Repository: entrylabs/entryjs Branch: develop Commit: 21cb7edaa9ec Files: 944 Total size: 50.3 MB Directory structure: gitextract_80_zfnjb/ ├── .babelrc ├── .eslintignore ├── .eslintrc ├── .github/ │ ├── pr-labeler.yml │ └── workflows/ │ ├── build-and-deploy.yml │ ├── pull-request-workflow.yml │ └── release.yml ├── .gitignore ├── .prettierrc ├── COPYING ├── Gruntfile.js ├── Jenkinsfile ├── LICENSE ├── NOTICE ├── README-en.md ├── README.md ├── contributing.md ├── example/ │ ├── example.ejs │ ├── example_mini.ejs │ └── example_webgl.ejs ├── extern/ │ ├── blockly/ │ │ ├── .ropeproject/ │ │ │ ├── config.py │ │ │ ├── globalnames │ │ │ ├── history │ │ │ └── objectdb │ │ ├── blockly_compressed.js │ │ ├── blockly_uncompressed.js │ │ ├── blocks/ │ │ │ ├── colour.js │ │ │ ├── lists.js │ │ │ ├── logic.js │ │ │ ├── loops.js │ │ │ ├── math.js │ │ │ ├── procedures.js │ │ │ ├── text.js │ │ │ └── variables.js │ │ ├── blocks_compressed.js │ │ ├── build.py │ │ ├── core/ │ │ │ ├── block.js │ │ │ ├── block_menu.js │ │ │ ├── block_svg.js │ │ │ ├── blockly.js │ │ │ ├── blocks.js │ │ │ ├── bubble.js │ │ │ ├── comment.js │ │ │ ├── connection-animation.js │ │ │ ├── connection.js │ │ │ ├── contextmenu.js │ │ │ ├── css.js │ │ │ ├── field.js │ │ │ ├── field_angle.js │ │ │ ├── field_checkbox.js │ │ │ ├── field_colour.js │ │ │ ├── field_dropdown.js │ │ │ ├── field_dropdowndynamic.js │ │ │ ├── field_icon.js │ │ │ ├── field_image.js │ │ │ ├── field_keydown_input.js │ │ │ ├── field_label.js │ │ │ ├── field_textinput.js │ │ │ ├── field_variable.js │ │ │ ├── flyout.js │ │ │ ├── generator.js │ │ │ ├── icon.js │ │ │ ├── inject.js │ │ │ ├── input.js │ │ │ ├── msg.js │ │ │ ├── mutator.js │ │ │ ├── names.js │ │ │ ├── procedures.js │ │ │ ├── realtime-client-utils.js │ │ │ ├── realtime.js │ │ │ ├── scrollbar.js │ │ │ ├── toolbox.js │ │ │ ├── tooltip.js │ │ │ ├── trashcan.js │ │ │ ├── utils.js │ │ │ ├── variables.js │ │ │ ├── warning.js │ │ │ ├── widgetdiv.js │ │ │ ├── workspace.js │ │ │ └── xml.js │ │ ├── dart_compressed.js │ │ ├── generators/ │ │ │ ├── dart/ │ │ │ │ ├── colour.js │ │ │ │ ├── lists.js │ │ │ │ ├── logic.js │ │ │ │ ├── loops.js │ │ │ │ ├── math.js │ │ │ │ ├── procedures.js │ │ │ │ ├── text.js │ │ │ │ └── variables.js │ │ │ ├── dart.js │ │ │ ├── javascript/ │ │ │ │ ├── colour.js │ │ │ │ ├── lists.js │ │ │ │ ├── logic.js │ │ │ │ ├── loops.js │ │ │ │ ├── math.js │ │ │ │ ├── procedures.js │ │ │ │ ├── text.js │ │ │ │ └── variables.js │ │ │ ├── javascript.js │ │ │ ├── python/ │ │ │ │ ├── colour.js │ │ │ │ ├── lists.js │ │ │ │ ├── logic.js │ │ │ │ ├── loops.js │ │ │ │ ├── math.js │ │ │ │ ├── procedures.js │ │ │ │ ├── text.js │ │ │ │ └── variables.js │ │ │ └── python.js │ │ ├── i18n/ │ │ │ ├── common.py │ │ │ ├── create_messages.py │ │ │ ├── dedup_json.py │ │ │ ├── js_to_json.py │ │ │ ├── json_to_js.py │ │ │ ├── status.py │ │ │ ├── tests.py │ │ │ └── xliff_to_json.py │ │ ├── javascript_compressed.js │ │ ├── media/ │ │ │ ├── click.ogg │ │ │ ├── delete.ogg │ │ │ ├── handclosed.cur │ │ │ └── handopen.cur │ │ ├── msg/ │ │ │ ├── js/ │ │ │ │ ├── ar.js │ │ │ │ ├── az-latn.js │ │ │ │ ├── az.js │ │ │ │ ├── be-tarask.js │ │ │ │ ├── br.js │ │ │ │ ├── ca.js │ │ │ │ ├── cs.js │ │ │ │ ├── da.js │ │ │ │ ├── de.js │ │ │ │ ├── el.js │ │ │ │ ├── en.js │ │ │ │ ├── en_us.js │ │ │ │ ├── es.js │ │ │ │ ├── fa.js │ │ │ │ ├── fi.js │ │ │ │ ├── fr.js │ │ │ │ ├── he.js │ │ │ │ ├── hi.js │ │ │ │ ├── hu.js │ │ │ │ ├── ia.js │ │ │ │ ├── id.js │ │ │ │ ├── is.js │ │ │ │ ├── it.js │ │ │ │ ├── ja.js │ │ │ │ ├── ko.js │ │ │ │ ├── lrc.js │ │ │ │ ├── ms.js │ │ │ │ ├── nb.js │ │ │ │ ├── nl.js │ │ │ │ ├── no.js │ │ │ │ ├── pl.js │ │ │ │ ├── pms.js │ │ │ │ ├── pt-br.js │ │ │ │ ├── pt.js │ │ │ │ ├── ro.js │ │ │ │ ├── ru.js │ │ │ │ ├── sq.js │ │ │ │ ├── sr.js │ │ │ │ ├── sv.js │ │ │ │ ├── th.js │ │ │ │ ├── tl.js │ │ │ │ ├── tr.js │ │ │ │ ├── uk.js │ │ │ │ ├── vi.js │ │ │ │ ├── zh-hans.js │ │ │ │ └── zh-hant.js │ │ │ ├── json/ │ │ │ │ ├── ar.json │ │ │ │ ├── az.json │ │ │ │ ├── be-tarask.json │ │ │ │ ├── br.json │ │ │ │ ├── ca.json │ │ │ │ ├── cs.json │ │ │ │ ├── da.json │ │ │ │ ├── de.json │ │ │ │ ├── el.json │ │ │ │ ├── en.json │ │ │ │ ├── es.json │ │ │ │ ├── fa.json │ │ │ │ ├── fi.json │ │ │ │ ├── fr.json │ │ │ │ ├── he.json │ │ │ │ ├── hi.json │ │ │ │ ├── hu.json │ │ │ │ ├── ia.json │ │ │ │ ├── id.json │ │ │ │ ├── is.json │ │ │ │ ├── it.json │ │ │ │ ├── ja.json │ │ │ │ ├── keys.json │ │ │ │ ├── ko.json │ │ │ │ ├── lrc.json │ │ │ │ ├── ms.json │ │ │ │ ├── nb.json │ │ │ │ ├── nl.json │ │ │ │ ├── pl.json │ │ │ │ ├── pms.json │ │ │ │ ├── pt-br.json │ │ │ │ ├── pt.json │ │ │ │ ├── qqq.json │ │ │ │ ├── ro.json │ │ │ │ ├── ru.json │ │ │ │ ├── sq.json │ │ │ │ ├── sr.json │ │ │ │ ├── sv.json │ │ │ │ ├── synonyms.json │ │ │ │ ├── th.json │ │ │ │ ├── tl.json │ │ │ │ ├── tr.json │ │ │ │ ├── uk.json │ │ │ │ ├── vi.json │ │ │ │ ├── zh-hans.json │ │ │ │ └── zh-hant.json │ │ │ └── messages.js │ │ ├── python_compressed.js │ │ └── tests/ │ │ ├── blockly_test.html │ │ ├── blockly_test.js │ │ ├── generator_test.js │ │ ├── generators/ │ │ │ ├── colour.xml │ │ │ ├── index.html │ │ │ ├── lists.xml │ │ │ ├── logic.xml │ │ │ ├── loops1.xml │ │ │ ├── loops2.xml │ │ │ ├── loops3.xml │ │ │ ├── math.xml │ │ │ ├── procedures.xml │ │ │ ├── text.xml │ │ │ ├── unittest.js │ │ │ ├── unittest_dart.js │ │ │ ├── unittest_javascript.js │ │ │ ├── unittest_python.js │ │ │ └── variables.xml │ │ ├── names_test.js │ │ └── playground.html │ ├── face-landmarker.worker.js │ ├── face-landmarker2.worker.js │ ├── gesture-recognition.worker.js │ ├── human/ │ │ ├── human.js │ │ └── models/ │ │ ├── blazeface.json │ │ ├── emotion.json │ │ ├── facemesh.json │ │ └── faceres.json │ ├── khaiii/ │ │ ├── cnv2hdn.lin │ │ ├── config.json │ │ ├── conv.2.fil │ │ ├── conv.3.fil │ │ ├── conv.4.fil │ │ ├── conv.5.fil │ │ ├── errpatch.len │ │ ├── errpatch.tri │ │ ├── errpatch.val │ │ ├── hdn2tag.lin │ │ ├── preanal.tri │ │ ├── preanal.val │ │ ├── restore.key │ │ ├── restore.one │ │ └── restore.val │ ├── lang/ │ │ ├── code.js │ │ ├── ebs.js │ │ ├── en.js │ │ ├── jp.js │ │ ├── ko.js │ │ └── vn.js │ ├── model/ │ │ ├── face_landmarker.task │ │ ├── gesture_recognizer.task │ │ ├── object_detector_lite.tflite │ │ └── pose_landmarker_lite.task │ ├── object-detector.worker.js │ ├── pose-landmarker.worker.js │ ├── tfjs-backend-wasm-simd.wasm │ ├── util/ │ │ ├── CanvasInput.js │ │ ├── CanvasInputOrg.js │ │ ├── DragDropTouch.js │ │ ├── filbert.js │ │ ├── handle.js │ │ ├── ndgmr.Collision.js │ │ ├── static.js │ │ └── static_mini.js │ ├── vision.worker.js │ ├── vision_bundle.js │ └── wasm/ │ ├── vision_wasm_internal.js │ ├── vision_wasm_internal.wasm │ ├── vision_wasm_nosimd_internal.js │ └── vision_wasm_nosimd_internal.wasm ├── images/ │ ├── cursor_eraser.cur │ ├── handclosed.cur │ ├── handopen.cur │ ├── media/ │ │ ├── FlashAudioPlugin.swf │ │ ├── click.ogg │ │ ├── delete.ogg │ │ ├── handclosed.cur │ │ └── handopen.cur │ └── sounds/ │ ├── click.ogg │ └── delete.ogg ├── jsconfig.json ├── karma.conf.js ├── package.json ├── scripts/ │ ├── build.sh │ ├── build_action.sh │ ├── deploy.sh │ └── deploy_action.sh ├── src/ │ ├── class/ │ │ ├── AILearning.js │ │ ├── AIUtilize.js │ │ ├── DataTable.js │ │ ├── Expansion.js │ │ ├── LiterallycanvasPainter.js │ │ ├── blockCountViewer.js │ │ ├── container.js │ │ ├── dialog.ts │ │ ├── doneProject.js │ │ ├── engine.js │ │ ├── entity.js │ │ ├── entryModuleLoader.ts │ │ ├── function.js │ │ ├── hardware/ │ │ │ ├── bluetoothServices/ │ │ │ │ ├── event-dispatcher.ts │ │ │ │ ├── index.ts │ │ │ │ ├── promise-queue.ts │ │ │ │ ├── service-helper.ts │ │ │ │ └── services/ │ │ │ │ ├── accelerometer.ts │ │ │ │ ├── button.ts │ │ │ │ ├── device-information.ts │ │ │ │ ├── dfu-control.ts │ │ │ │ ├── event.ts │ │ │ │ ├── io-pin.ts │ │ │ │ ├── led.ts │ │ │ │ ├── magnetometer.ts │ │ │ │ ├── temperature.ts │ │ │ │ └── uart.ts │ │ │ ├── externalProgramLauncher.ts │ │ │ ├── functions/ │ │ │ │ └── createHardwarePopup.ts │ │ │ ├── hardwareMonitor.ts │ │ │ ├── hardwareSocketMessageHandler.ts │ │ │ ├── webApiConnector.ts │ │ │ ├── webBluetoothConnector.ts │ │ │ ├── webSerialConnector.ts │ │ │ └── webUsbFlasher.ts │ │ ├── helper.js │ │ ├── hw.ts │ │ ├── hw_lite.ts │ │ ├── intro.ts │ │ ├── learning/ │ │ │ ├── Chart.js │ │ │ ├── Cluster.js │ │ │ ├── DecisionTree.js │ │ │ ├── ImageLearning.js │ │ │ ├── InputPopup.js │ │ │ ├── LearningBase.ts │ │ │ ├── LearningView.js │ │ │ ├── LogisticRegression.js │ │ │ ├── NumberClassification.js │ │ │ ├── Regression.js │ │ │ ├── SpeechClassification.js │ │ │ ├── Svm.js │ │ │ ├── TextLearning.js │ │ │ ├── Utils.ts │ │ │ └── bayes.ts │ │ ├── maxrect-packer/ │ │ │ ├── abstract_bin.ts │ │ │ ├── geom/ │ │ │ │ ├── ImageRect.ts │ │ │ │ └── Rectangle.ts │ │ │ ├── maxrects_bin.ts │ │ │ ├── maxrects_packer.ts │ │ │ └── oversized_element_bin.ts │ │ ├── object.js │ │ ├── painter.js │ │ ├── pdf.ts │ │ ├── pixi/ │ │ │ ├── atlas/ │ │ │ │ ├── AtlasCanvasViewer.ts │ │ │ │ ├── EntryTextureOption.ts │ │ │ │ ├── ISceneTextures.ts │ │ │ │ ├── PIXIAtlasHelper.ts │ │ │ │ ├── PIXIAtlasManager.ts │ │ │ │ ├── PIXIScaleAdaptor.ts │ │ │ │ ├── SceneBins.ts │ │ │ │ ├── SceneTextures.ts │ │ │ │ ├── loader/ │ │ │ │ │ ├── AtlasImageLoader.ts │ │ │ │ │ └── AtlasImageLoadingInfo.ts │ │ │ │ ├── model/ │ │ │ │ │ ├── IRawObject.ts │ │ │ │ │ └── IRawPicture.ts │ │ │ │ ├── structure/ │ │ │ │ │ ├── PrimitiveMap.ts │ │ │ │ │ └── PrimitiveSet.ts │ │ │ │ └── texture/ │ │ │ │ ├── AtlasBaseTexture.ts │ │ │ │ ├── AtlasTexture.ts │ │ │ │ ├── EntryBaseTexture.ts │ │ │ │ ├── EntryTexture.ts │ │ │ │ └── EntryTextureBase.ts │ │ │ ├── etc/ │ │ │ │ ├── PIXI-ndgmr.Collision.js │ │ │ │ ├── PIXIBrushAdaptor.ts │ │ │ │ ├── PIXICanvasInput.js │ │ │ │ ├── PIXIPaintAdaptor.ts │ │ │ │ └── PIXITempStore.ts │ │ │ ├── handle/ │ │ │ │ ├── PIXIHandle.js │ │ │ │ └── PIXIHandleEdge.js │ │ │ ├── helper/ │ │ │ │ ├── PIXIDragHelper.js │ │ │ │ └── PIXIHelper.ts │ │ │ ├── init/ │ │ │ │ ├── PIXIBaseAsset.ts │ │ │ │ ├── PIXIFontLoadHandler.ts │ │ │ │ └── PIXIGlobal.ts │ │ │ ├── mesh/ │ │ │ │ └── PIXIH3Plane.js │ │ │ ├── plugins/ │ │ │ │ ├── PIXIGraphicOverride.js │ │ │ │ ├── PIXIPixelPerfectInteractionPlugIn.js │ │ │ │ ├── PIXIShortPropPlugin.js │ │ │ │ ├── PIXISprite.ts │ │ │ │ ├── PIXITextMetricsPlugIn.js │ │ │ │ └── pixiGetChildAt.js │ │ │ ├── text/ │ │ │ │ ├── PIXIText.js │ │ │ │ └── PIXITextStyle.ts │ │ │ └── utils/ │ │ │ ├── AutoFit.ts │ │ │ ├── TimeoutTimer.ts │ │ │ └── logs.ts │ │ ├── playground.js │ │ ├── popup.js │ │ ├── popup_helper.ts │ │ ├── popup_list.js │ │ ├── project.js │ │ ├── property_panel.ts │ │ ├── reporter.js │ │ ├── scene.js │ │ ├── sound.ts │ │ ├── source/ │ │ │ └── DataTableSource.js │ │ ├── stage.js │ │ ├── stamp_entity.js │ │ ├── time_wait.js │ │ ├── toast.js │ │ ├── variable/ │ │ │ ├── answerVariable.js │ │ │ ├── index.js │ │ │ ├── listVariable.js │ │ │ ├── slideVariable.js │ │ │ ├── sttVariable.js │ │ │ ├── timerVariable.js │ │ │ └── variable.js │ │ └── variable_container.js │ ├── command/ │ │ ├── command.js │ │ ├── command_util.js │ │ ├── commander.js │ │ └── commands/ │ │ ├── block.js │ │ ├── comment.js │ │ ├── container.js │ │ ├── dataTable.js │ │ ├── engine.js │ │ ├── function.js │ │ ├── object.js │ │ ├── painter.js │ │ ├── playground.js │ │ ├── scene.js │ │ ├── textbox.js │ │ └── variableContainer.js │ ├── core/ │ │ ├── collection.js │ │ ├── db.js │ │ ├── dom.ts │ │ ├── event.js │ │ ├── model.js │ │ ├── modelClass.ts │ │ ├── observer.js │ │ ├── promiseManager.js │ │ ├── singleInstance.js │ │ └── svg.js │ ├── css/ │ │ ├── codemirror_theme.less │ │ ├── common.less │ │ ├── components/ │ │ │ ├── block.less │ │ │ ├── block_menu.less │ │ │ ├── board.less │ │ │ ├── console.less │ │ │ ├── container.less │ │ │ ├── context_menu.less │ │ │ ├── curtain.less │ │ │ ├── engine.less │ │ │ ├── extensions.less │ │ │ ├── function.less │ │ │ ├── global_svg.less │ │ │ ├── helper.less │ │ │ ├── hw_monitor.less │ │ │ ├── object.less │ │ │ ├── painter.less │ │ │ ├── pdf.less │ │ │ ├── playground.less │ │ │ ├── popup.less │ │ │ ├── property_panel.less │ │ │ ├── scene.less │ │ │ ├── stage.less │ │ │ ├── state_manager.less │ │ │ ├── table.less │ │ │ ├── target_checker.less │ │ │ ├── textcoding_helper.less │ │ │ ├── toast.less │ │ │ ├── tooltip.less │ │ │ ├── variable_container.less │ │ │ └── zoomController.less │ │ ├── entry.less │ │ ├── minimize.less │ │ ├── prefix.less │ │ └── static.less │ ├── entry.js │ ├── extensions/ │ │ ├── CloudVariable.js │ │ ├── dmet.js │ │ ├── dropper.js │ │ ├── extension.js │ │ └── target_checker.js │ ├── graphicEngine/ │ │ ├── EaselResManager.ts │ │ ├── FakePIXI.js │ │ ├── GEDragHelper.ts │ │ ├── GEHandle.js │ │ ├── GEHelper.ts │ │ └── IGEResManager.ts │ ├── log/ │ │ ├── activity.js │ │ ├── activityReporter.js │ │ ├── recorder.js │ │ ├── state.js │ │ └── state_manager.js │ ├── model/ │ │ ├── block_model.js │ │ ├── block_render_model.js │ │ ├── box_model.js │ │ ├── drag_instance.js │ │ └── thread_model.js │ ├── parser-no/ │ │ ├── block.js │ │ ├── js.js │ │ └── parser.js │ ├── playground/ │ │ ├── block.js │ │ ├── block_entry.js │ │ ├── block_entry_mini.js │ │ ├── block_menu.ts │ │ ├── block_menu_scroll.js │ │ ├── block_view.js │ │ ├── blocks/ │ │ │ ├── block_ai_learning.js │ │ │ ├── block_ai_learning_cluster.js │ │ │ ├── block_ai_learning_decisiontree.js │ │ │ ├── block_ai_learning_knn.js │ │ │ ├── block_ai_learning_logistic_regression.js │ │ │ ├── block_ai_learning_regression.js │ │ │ ├── block_ai_learning_svm.js │ │ │ ├── block_ai_utilize_audio.js │ │ │ ├── block_ai_utilize_face_landmarker.js │ │ │ ├── block_ai_utilize_gesture_recognition.js │ │ │ ├── block_ai_utilize_media_pipe.js │ │ │ ├── block_ai_utilize_object_detector.js │ │ │ ├── block_ai_utilize_pose_landmarker.js │ │ │ ├── block_ai_utilize_translate.js │ │ │ ├── block_ai_utilize_tts.js │ │ │ ├── block_ai_utilize_video.js │ │ │ ├── block_analysis.js │ │ │ ├── block_brush.js │ │ │ ├── block_calc.js │ │ │ ├── block_expansion_behaviorconduct_disaster.js │ │ │ ├── block_expansion_behaviorconduct_lifesafety.js │ │ │ ├── block_expansion_disasterAlert.js │ │ │ ├── block_expansion_emergencyActionGuidelines.js │ │ │ ├── block_expansion_festival.js │ │ │ ├── block_expansion_weather.js │ │ │ ├── block_flow.js │ │ │ ├── block_func.js │ │ │ ├── block_judgement.js │ │ │ ├── block_looks.js │ │ │ ├── block_moving.js │ │ │ ├── block_sound.js │ │ │ ├── block_start.js │ │ │ ├── block_text.js │ │ │ ├── block_variable.js │ │ │ ├── hardware/ │ │ │ │ ├── block_0uboard.js │ │ │ │ ├── block_CloverSEntry1.js │ │ │ │ ├── block_ITPLE_board.js │ │ │ │ ├── block_KKMOO.js │ │ │ │ ├── block_KRC.js │ │ │ │ ├── block_LineCoding.js │ │ │ │ ├── block_Lline.js │ │ │ │ ├── block_RichShield.js │ │ │ │ ├── block_abilix_Krypton0.js │ │ │ │ ├── block_aidrone.js │ │ │ │ ├── block_aidrone_tracking.js │ │ │ │ ├── block_aiot.js │ │ │ │ ├── block_aiservo.js │ │ │ │ ├── block_albert.js │ │ │ │ ├── block_albert_ai.js │ │ │ │ ├── block_altino.js │ │ │ │ ├── block_altino_lite.js │ │ │ │ ├── block_altino_neo.js │ │ │ │ ├── block_alux_connect.js │ │ │ │ ├── block_alux_nemo.js │ │ │ │ ├── block_alux_technic.js │ │ │ │ ├── block_ardublock.js │ │ │ │ ├── block_arduino.js │ │ │ │ ├── block_arduino_cake.js │ │ │ │ ├── block_arduino_ext.js │ │ │ │ ├── block_arduino_nano.js │ │ │ │ ├── block_armz.js │ │ │ │ ├── block_asomebot.js │ │ │ │ ├── block_asomekit.js │ │ │ │ ├── block_avatarbot.js │ │ │ │ ├── block_bingles.js │ │ │ │ ├── block_bitbrick.js │ │ │ │ ├── block_blacksmith.js │ │ │ │ ├── block_bridge.js │ │ │ │ ├── block_brown.js │ │ │ │ ├── block_byrobot_base.js │ │ │ │ ├── block_byrobot_controller_3_4.js │ │ │ │ ├── block_byrobot_controller_4.js │ │ │ │ ├── block_byrobot_drone_3_10.js │ │ │ │ ├── block_byrobot_drone_4.js │ │ │ │ ├── block_byrobot_drone_8.js │ │ │ │ ├── block_byrobot_dronefighter_controller.js │ │ │ │ ├── block_byrobot_dronefighter_drive.js │ │ │ │ ├── block_byrobot_dronefighter_flight.js │ │ │ │ ├── block_byrobot_petrone_v2_base.js │ │ │ │ ├── block_byrobot_petrone_v2_controller.js │ │ │ │ ├── block_byrobot_petrone_v2_drive.js │ │ │ │ ├── block_byrobot_petrone_v2_flight.js │ │ │ │ ├── block_c3coding_arduino.js │ │ │ │ ├── block_castarter_v2.js │ │ │ │ ├── block_cheese.js │ │ │ │ ├── block_choco.js │ │ │ │ ├── block_choco2.js │ │ │ │ ├── block_chocopi.js │ │ │ │ ├── block_coalaboard.js │ │ │ │ ├── block_cobl.js │ │ │ │ ├── block_coco.js │ │ │ │ ├── block_coconut.js │ │ │ │ ├── block_codeino.js │ │ │ │ ├── block_codestar.js │ │ │ │ ├── block_codewiz.js │ │ │ │ ├── block_coding_box.js │ │ │ │ ├── block_codingmachine.js │ │ │ │ ├── block_cp_moving.js │ │ │ │ ├── block_creamo.js │ │ │ │ ├── block_cremaker_3Dpen.js │ │ │ │ ├── block_cuboai.js │ │ │ │ ├── block_cue.js │ │ │ │ ├── block_dadublock.js │ │ │ │ ├── block_dalgona.js │ │ │ │ ├── block_dalgona_basic.js │ │ │ │ ├── block_dash.js │ │ │ │ ├── block_davinci.js │ │ │ │ ├── block_diaboard.js │ │ │ │ ├── block_dodaland.js │ │ │ │ ├── block_dplay.js │ │ │ │ ├── block_eduino.js │ │ │ │ ├── block_edumaker.js │ │ │ │ ├── block_elio.js │ │ │ │ ├── block_etboard.js │ │ │ │ ├── block_etkit.js │ │ │ │ ├── block_ev3.js │ │ │ │ ├── block_exmars_cube.js │ │ │ │ ├── block_firmtech2.js │ │ │ │ ├── block_freearduino.js │ │ │ │ ├── block_freelinker2.js │ │ │ │ ├── block_funboard.js │ │ │ │ ├── block_gbot.js │ │ │ │ ├── block_genirobot.js │ │ │ │ ├── block_hamster.js │ │ │ │ ├── block_hamster_s.js │ │ │ │ ├── block_handino.js │ │ │ │ ├── block_hasseam.js │ │ │ │ ├── block_hexaboard.js │ │ │ │ ├── block_hummingbird.js │ │ │ │ ├── block_hyact.js │ │ │ │ ├── block_iCOBOT.js │ │ │ │ ├── block_iboard.js │ │ │ │ ├── block_iotsmartfarm.js │ │ │ │ ├── block_jcboard.js │ │ │ │ ├── block_jdcode.js │ │ │ │ ├── block_jdkit.js │ │ │ │ ├── block_jikko.js │ │ │ │ ├── block_jikko_basic.js │ │ │ │ ├── block_jikko_lidoc.js │ │ │ │ ├── block_jikko_make.js │ │ │ │ ├── block_jinirobot_aibot.js │ │ │ │ ├── block_jinirobot_toybot.js │ │ │ │ ├── block_joystick.js │ │ │ │ ├── block_kaboino.js │ │ │ │ ├── block_kaduino.js │ │ │ │ ├── block_kamibot.js │ │ │ │ ├── block_kamibotPi.js │ │ │ │ ├── block_kingcoding.js │ │ │ │ ├── block_lecoboard.js │ │ │ │ ├── block_lecoboardAvr.js │ │ │ │ ├── block_lecoboardAvrBT.js │ │ │ │ ├── block_littlebits.js │ │ │ │ ├── block_magkinder.js │ │ │ │ ├── block_makermate.js │ │ │ │ ├── block_mechanicblock_controller.js │ │ │ │ ├── block_mechanicblock_uno.js │ │ │ │ ├── block_mechanicblock_uno_mini.js │ │ │ │ ├── block_mechanicblock_uno_s.js │ │ │ │ ├── block_mechatro.js │ │ │ │ ├── block_mechatronics_4d.js │ │ │ │ ├── block_memaker.js │ │ │ │ ├── block_microbit.js │ │ │ │ ├── block_microbit2.js │ │ │ │ ├── block_microbit_ext.js │ │ │ │ ├── block_mindpiggy.js │ │ │ │ ├── block_mkboard.js │ │ │ │ ├── block_modi.js │ │ │ │ ├── block_mrt.js │ │ │ │ ├── block_nemoino.js │ │ │ │ ├── block_neo.js │ │ │ │ ├── block_neo_cannon.js │ │ │ │ ├── block_neo_spider.js │ │ │ │ ├── block_neobot.js │ │ │ │ ├── block_neobot_game_theme.js │ │ │ │ ├── block_neobot_purple.js │ │ │ │ ├── block_neobot_robot_theme.js │ │ │ │ ├── block_neobot_sensor_theme.js │ │ │ │ ├── block_neobot_soco.js │ │ │ │ ├── block_neobot_thinkcar.js │ │ │ │ ├── block_orange.js │ │ │ │ ├── block_ozobot.js │ │ │ │ ├── block_palmkit.js │ │ │ │ ├── block_pingpong.js │ │ │ │ ├── block_pingpong_multi.js │ │ │ │ ├── block_playcode.js │ │ │ │ ├── block_plrun.js │ │ │ │ ├── block_robico.js │ │ │ │ ├── block_robodog.js │ │ │ │ ├── block_roboid.js │ │ │ │ ├── block_robolink_codrone_diy.js │ │ │ │ ├── block_robolink_codrone_edu.js │ │ │ │ ├── block_robolink_codrone_mini.js │ │ │ │ ├── block_robomation.js │ │ │ │ ├── block_roborobo_base.js │ │ │ │ ├── block_roborobo_cube.js │ │ │ │ ├── block_roborobo_robokit_rs.js │ │ │ │ ├── block_roborobo_roduino.js │ │ │ │ ├── block_roborobo_roe.js │ │ │ │ ├── block_roborobo_schoolkit.js │ │ │ │ ├── block_robotamicoding.js │ │ │ │ ├── block_robotis.js │ │ │ │ ├── block_robotisDream.js │ │ │ │ ├── block_robotisRB.js │ │ │ │ ├── block_robotisRBCar.js │ │ │ │ ├── block_robotisRBHumanoid.js │ │ │ │ ├── block_robotisRBKoala.js │ │ │ │ ├── block_robotisRBPracticalAssembly.js │ │ │ │ ├── block_robotori.js │ │ │ │ ├── block_robotry_parodule.js │ │ │ │ ├── block_robotry_robit_stage.js │ │ │ │ ├── block_rokoboard.js │ │ │ │ ├── block_runcoding.js │ │ │ │ ├── block_runcoding_display.js │ │ │ │ ├── block_sally.js │ │ │ │ ├── block_sciencecube.js │ │ │ │ ├── block_sensorboard.js │ │ │ │ ├── block_smartCodingHouse.js │ │ │ │ ├── block_smartboard.js │ │ │ │ ├── block_ssboard_nano.js │ │ │ │ ├── block_suno.js │ │ │ │ ├── block_talebot.js │ │ │ │ ├── block_telliot_Base.js │ │ │ │ ├── block_telliot_lite.js │ │ │ │ ├── block_thinkboard.js │ │ │ │ ├── block_timbo.js │ │ │ │ ├── block_truerobot.js │ │ │ │ ├── block_turtle.js │ │ │ │ ├── block_uglybot.js │ │ │ │ ├── block_uo_albert.js │ │ │ │ ├── block_wearable.js │ │ │ │ ├── block_whalesbot_eagle_1001.js │ │ │ │ ├── block_xbot.js │ │ │ │ ├── block_zerone.js │ │ │ │ ├── block_zumiMini.js │ │ │ │ └── index.js │ │ │ ├── hardwareLite/ │ │ │ │ ├── block_alux_connect_lite.js │ │ │ │ ├── block_alux_nemo_lite.js │ │ │ │ ├── block_alux_teachnic_normal_lite.js │ │ │ │ ├── block_alux_teachnic_power_lite.js │ │ │ │ ├── block_arduino_lite.js │ │ │ │ ├── block_choco_lite.js │ │ │ │ ├── block_cocodron_controller_Lite.js │ │ │ │ ├── block_codewiz_lite.js │ │ │ │ ├── block_hamster_lite.js │ │ │ │ ├── block_microbit2_lite.js │ │ │ │ ├── block_microbit2ble_lite.js │ │ │ │ ├── block_neo_cannon_lite.js │ │ │ │ ├── block_neo_lite.js │ │ │ │ ├── block_neo_spider_lite.js │ │ │ │ ├── block_neobot_purple_lite.js │ │ │ │ ├── block_neobot_soco_lite.js │ │ │ │ ├── block_neobot_thinkcar_lite.js │ │ │ │ ├── block_robolink_ZumiMini_lite.js │ │ │ │ ├── block_robotis_kkokdu_lite.js │ │ │ │ ├── block_robotis_koalabot_lite.js │ │ │ │ ├── block_robotis_rgee_lite.js │ │ │ │ ├── block_robotis_rla_lite.js │ │ │ │ ├── block_robotis_robotai_lite.js │ │ │ │ ├── block_sensorboard_lite.js │ │ │ │ ├── block_whalesbot_drone_lite.js │ │ │ │ ├── block_wizwing_controller_lite.js │ │ │ │ ├── index.js │ │ │ │ ├── metadata_alux_connect_lite.json │ │ │ │ ├── metadata_alux_nemo_lite.json │ │ │ │ ├── metadata_alux_teachnic_normal_lite.json │ │ │ │ ├── metadata_alux_teachnic_power_lite.json │ │ │ │ ├── metadata_arduino_lite.json │ │ │ │ ├── metadata_choco_lite.json │ │ │ │ ├── metadata_cocodron_controller_Lite.json │ │ │ │ ├── metadata_codewiz_lite.json │ │ │ │ ├── metadata_hamster_lite.json │ │ │ │ ├── metadata_microbit2_lite.json │ │ │ │ ├── metadata_microbit2ble_lite.json │ │ │ │ ├── metadata_neo_cannon_lite.json │ │ │ │ ├── metadata_neo_lite.json │ │ │ │ ├── metadata_neo_spider_lite.json │ │ │ │ ├── metadata_neobot_purple_lite.json │ │ │ │ ├── metadata_neobot_soco_lite.json │ │ │ │ ├── metadata_neobot_thinkcar_lite.json │ │ │ │ ├── metadata_robolink_ZumiMini_lite.json │ │ │ │ ├── metadata_robotis_kkokdu_lite.json │ │ │ │ ├── metadata_robotis_koalabot_lite.json │ │ │ │ ├── metadata_robotis_rgee_lite.json │ │ │ │ ├── metadata_robotis_rla_lite.json │ │ │ │ ├── metadata_robotis_robotai_lite.json │ │ │ │ ├── metadata_sensorboard_lite.json │ │ │ │ ├── metadata_whalesbot_drone_lite.json │ │ │ │ └── metadata_wizwing_controller_lite.json │ │ │ ├── index.js │ │ │ └── inputs/ │ │ │ └── keyboard.js │ │ ├── board.js │ │ ├── code.js │ │ ├── code_view.js │ │ ├── comment.js │ │ ├── connection_ripple.js │ │ ├── executors.js │ │ ├── executors2.js │ │ ├── extension/ │ │ │ ├── extension.js │ │ │ ├── guide.js │ │ │ └── side_tag.js │ │ ├── field/ │ │ │ ├── angle.js │ │ │ ├── block.js │ │ │ ├── color.js │ │ │ ├── dropdown.js │ │ │ ├── dropdownDynamic.js │ │ │ ├── dropdownExtra.js │ │ │ ├── field.js │ │ │ ├── image.js │ │ │ ├── indicator.js │ │ │ ├── keyboardInput.js │ │ │ ├── led.js │ │ │ ├── led2.js │ │ │ ├── lineBreak.js │ │ │ ├── musicScale.js │ │ │ ├── output.js │ │ │ ├── statement.js │ │ │ ├── text.js │ │ │ ├── textDynamic.js │ │ │ └── textInput.js │ │ ├── globalSvg.js │ │ ├── mutator.js │ │ ├── renderView.js │ │ ├── scope.js │ │ ├── scroll.js │ │ ├── skeleton/ │ │ │ ├── basic/ │ │ │ │ ├── basic.ts │ │ │ │ ├── basic_boolean_field.ts │ │ │ │ ├── basic_button.ts │ │ │ │ ├── basic_button_disabled.ts │ │ │ │ ├── basic_create.ts │ │ │ │ ├── basic_create_value.ts │ │ │ │ ├── basic_define.ts │ │ │ │ ├── basic_double_loop.ts │ │ │ │ ├── basic_event.ts │ │ │ │ ├── basic_loop.ts │ │ │ │ ├── basic_param.ts │ │ │ │ ├── basic_string_field.ts │ │ │ │ ├── basic_text.ts │ │ │ │ └── basic_text_light.ts │ │ │ ├── clickable_text.ts │ │ │ ├── comment.ts │ │ │ ├── index.ts │ │ │ └── pebble/ │ │ │ ├── pebble_basic.ts │ │ │ ├── pebble_event.ts │ │ │ └── pebble_loop.ts │ │ ├── skinner.js │ │ ├── thread.js │ │ ├── thread_view.js │ │ ├── toast.js │ │ ├── trashcan.js │ │ ├── vim.js │ │ ├── workspace.js │ │ └── zoom_controller.js │ ├── textcoding/ │ │ ├── ast/ │ │ │ ├── jsAstGenerator.js │ │ │ └── pyAstGenerator.js │ │ ├── data_processing/ │ │ │ ├── map.js │ │ │ └── queue.js │ │ ├── error/ │ │ │ └── textCodingError.js │ │ ├── hint/ │ │ │ └── python.js │ │ ├── parser/ │ │ │ └── core/ │ │ │ ├── block/ │ │ │ │ ├── blockToJs.js │ │ │ │ └── blockToPy.js │ │ │ └── text/ │ │ │ ├── jsToBlock.js │ │ │ └── pyToBlock.js │ │ ├── parser.js │ │ ├── static/ │ │ │ ├── codeMap.js │ │ │ └── keyboardCode.js │ │ └── util/ │ │ ├── console.js │ │ └── textCodingUtil.js │ ├── theme/ │ │ ├── old.js │ │ └── standard.js │ └── util/ │ ├── audioSocket.js │ ├── audioUtils.js │ ├── binPacking.js │ ├── block_driver.js │ ├── common.js │ ├── contextmenu.js │ ├── curtain.js │ ├── dataSource.ts │ ├── destroyer/ │ │ └── Destroyer.ts │ ├── domUtils.js │ ├── eventHandler.js │ ├── extrablockUtils.js │ ├── functions/ │ │ └── showConsoleBanner.ts │ ├── fuzzy.js │ ├── hardwareUtils.ts │ ├── htmlElementPatcher.js │ ├── init.js │ ├── loader.js │ ├── location.js │ ├── mediaPipeUtils.ts │ ├── modal.js │ ├── restrictor.js │ ├── scheduler.js │ ├── static.js │ ├── tooltip.js │ ├── tvCast.js │ ├── utils.js │ ├── virtualScroll.js │ ├── workers/ │ │ └── newmotion.worker.ts │ └── youtube.js ├── test/ │ ├── class/ │ │ └── container.spec.js │ ├── entry/ │ │ └── entry.js │ └── textcoding/ │ └── block.js ├── test_util/ │ └── helper.js ├── tsconfig.json ├── types/ │ ├── entry.d.ts │ ├── index.d.ts │ └── window.d.ts ├── webpack.config.js ├── webpack_config/ │ ├── common.js │ ├── dev.js │ ├── lint.js │ ├── prod.js │ └── serve.js └── weights/ ├── age_gender_model-shard1 ├── age_gender_model-weights_manifest.json ├── face_expression_model-shard1 ├── face_expression_model-weights_manifest.json ├── face_landmark_68_model-shard1 ├── face_landmark_68_model-weights_manifest.json ├── face_landmark_68_tiny_model-shard1 ├── face_landmark_68_tiny_model-weights_manifest.json ├── tiny_face_detector_model-shard1 └── tiny_face_detector_model-weights_manifest.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .babelrc ================================================ { "presets": ["@babel/preset-env"], "plugins": [ "@babel/plugin-transform-runtime", "@babel/plugin-transform-object-assign", "@babel/plugin-transform-modules-commonjs", "@babel/plugin-syntax-dynamic-import", "@babel/plugin-proposal-object-rest-spread", "@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-private-methods" ], "env": { "test": { "plugins": ["dynamic-import-node"] } } } ================================================ FILE: .eslintignore ================================================ src/playground/blocks/hardware/**/*.js extern test test_util ================================================ FILE: .eslintrc ================================================ { "parser": "@babel/eslint-parser", "plugins": ["prettier"], "extends": ["plugin:prettier/recommended"], "overrides": [ { "files": ["*.ts"], "parser": "@typescript-eslint/parser", "rules": { "no-unused-vars": "off", }, }, { "files": ["*.d.ts"], "parser": "@typescript-eslint/parser", "rules": { "no-unused-vars": "off", "no-var": "off", "no-useless-constructor": "off", }, }, ], "env": { "es6": true, "browser": true, "jquery": true, }, "parserOptions": { "requireConfigFile": false, "ecmaVersion": 2020, "sourceType": "module", "ecmaFeatures": { "jsx": true, }, }, "rules": { "prefer-const": "warn", "no-var": "warn", "eqeqeq": 0, "no-const-assign": "error", "no-new-object": "warn", "object-shorthand": "warn", "no-prototype-builtins": "warn", "no-array-constructor": "warn", "prefer-template": "warn", "no-useless-escape": "warn", "wrap-iife": ["warn", "inside"], "no-loop-func": "warn", "no-new-func": "warn", "prefer-rest-params": "warn", "prefer-arrow-callback": "warn", "template-curly-spacing": "warn", "no-param-reassign": ["warn", { "props": false }], "prefer-spread": "warn", "arrow-spacing": "warn", "arrow-body-style": ["warn", "as-needed"], "no-useless-constructor": "warn", "no-dupe-class-members": "warn", "no-duplicate-imports": "warn", "dot-notation": "warn", "no-undef": ["warn", { "typeof": true }], "one-var": ["warn", "never"], "no-multi-assign": "warn", "no-case-declarations": "warn", "no-nested-ternary": "warn", "no-unneeded-ternary": "warn", "brace-style": "warn", "space-before-blocks": [ "warn", { "functions": "always", "keywords": "always", "classes": "always" }, ], "space-infix-ops": "warn", "eol-last": ["warn", "always"], "no-whitespace-before-property": "warn", "padded-blocks": ["warn", "never"], "space-in-parens": ["warn", "never"], "array-bracket-spacing": ["warn", "never"], "object-curly-spacing": ["warn", "always"], "max-len": ["warn", { "code": 100 }], "comma-style": ["warn", "last"], "semi": ["warn"], "radix": "warn", "camelcase": ["warn", { "properties": "never" }], "new-cap": ["warn", { "capIsNewExceptionPattern": "^Entry." }], "curly": "warn", "keyword-spacing": "warn", }, "globals": { "$": true, "_": true, "arcon": true, "goog": true, "acorn": true, "createjs": true, "Entry": true, "filbert": true, "Blockly": true, "BigNumber": true, "Lang": true, "context": true, "popup": true, "WebFont": true, "CanvasInput": true, "EntryStatic": true, "EaselHandle": true, "ndgmr": true, "Ntry": true, "Snap": true, "mina": true, "Touch": true, "io": true, "LC": true, "ActiveXObject": true, "CodeMirror": true, "entrylms": true, "require": true, "module": true, "Symbol": true, "process": true, }, } ================================================ FILE: .github/pr-labeler.yml ================================================ feature: feature/* security: security/* issue: [issue/*, Issue/*] hotfix: hotfix/* ================================================ FILE: .github/workflows/build-and-deploy.yml ================================================ name: 'build-and-deploy' on: push: branches: - 'deploy/**' - master - develop-hw - develop2 - develop jobs: build-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Use Node.js 20.x uses: actions/setup-node@v4 env: NODE_OPTIONS: '--max-old-space-size=4096' TOOL_NODE_FLAGS: '--max-old-space-size=4096' with: node-version: 20 - uses: pnpm/action-setup@v3 name: Install pnpm with: version: 9 run_install: true - name: entry build env: NODE_OPTIONS: '--max-old-space-size=4096' TOOL_NODE_FLAGS: '--max-old-space-size=4096' run: pnpm prod - name: Define branch name id: target_branch shell: bash run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF##*/})" - uses: haya14busa/action-cond@v1 id: deploy_branch with: cond: ${{ steps.target_branch.outputs.branch == 'master' }} if_true: 'build' if_false: dist/${{ steps.target_branch.outputs.branch }} - name: Execute build.sh run: | sh ./scripts/build.sh - name: Execute deploy.sh run: | sh ./scripts/deploy.sh - name: Push Changes into build branch uses: ad-m/github-push-action@master with: github_token: ${{ secrets.GITHUB_TOKEN }} force: true directory: ./build branch: ${{ steps.deploy_branch.outputs.value }} ================================================ FILE: .github/workflows/pull-request-workflow.yml ================================================ name: PR Workflow on: pull_request: types: [opened, edited, synchronize] jobs: pr-labeler: runs-on: ubuntu-latest steps: - uses: TimonVS/pr-labeler-action@v3 with: configuration-path: .github/pr-labeler.yml # optional, .github/pr-labeler.yml is the default value env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} eslint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install pnpm uses: pnpm/action-setup@v3 with: version: 9 - run: pnpm install - uses: reviewdog/action-eslint@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} reporter: github-pr-review eslint_flags: '--ignore-pattern .eslintignore src/' ================================================ FILE: .github/workflows/release.yml ================================================ name: 'release' on: release: types: [created] jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install pnpm uses: pnpm/action-setup@v3 with: version: 9 - uses: actions/setup-node@v4 with: node-version: '20' cache: 'pnpm' - run: pnpm install - run: pnpm prod - uses: JS-DevTools/npm-publish@v3 with: token: ${{ secrets.NPM_TOKEN }} ================================================ FILE: .gitignore ================================================ # Logs logs *.log # Runtime data pids *.pid *.seed # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage reports # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directory # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git node_modules # external libraries extern/closure-library .DS_Store *.map .vscode/* .idea/ dist/ ================================================ FILE: .prettierrc ================================================ { "printWidth": 100, "tabWidth": 4, "singleQuote": true, "trailingComma": "es5", "bracketSpacing": true, "semi": true, "arrowParens": "always", "endOfLine": "auto" } ================================================ FILE: COPYING ================================================ Copyright 2015 Entry Labs Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: Gruntfile.js ================================================ module.exports = function(grunt) { 'use strict'; const ClosureCompiler = require('google-closure-compiler').compiler; grunt.initConfig({ concurrent: { tasks: ['watch'], options: { logConcurrentOutput: true, }, }, watch: { test: { files: ['test/**/*.js'], tasks: ['karma'], }, js: { files: ['src/**'], tasks: ['closureCompiler:targetName', 'karma', 'jshint', 'less'], }, }, less: { options: { compress: false, }, development: { files: { 'dist/entry.css': 'src/css/*.less', }, }, }, jshint: { all: ['src/**/*.js'], options: { jshintrc: true, ignores: ['src/blocks/*.js'], }, }, karma: { options: { frameworks: ['mocha', 'chai'], files: [ 'http://ajax.aspnetcdn.com/ajax/jshint/r07/jshint.js', 'test_util/*.js', 'extern/lang/ko.js', 'extern/blockly/blockly_compressed.js', 'extern/util/static.js', 'extern/util/filbert.js', 'extern/util/bignumber.min.js', 'node_modules/jquery/jquery.js', 'node_modules/createjs-easeljs/lib/easeljs-0.8.2.min.js', 'node_modules/createjs-soundjs/lib/soundjs-0.6.2.min.js', 'node_modules/createjs-preloadjs/lib/preloadjs-0.6.2.min.js', 'dist/entry.js', 'src/workspace/block_entry.js', ], }, unit: { configFile: 'karma.conf.js', files: [{ src: ['test/**/*.js'] }], }, }, closureCompiler: { options: { compilerFile: ClosureCompiler.COMPILER_PATH, checkModified: true, compilerOpts: { create_source_map: 'entry.js.map', compilation_level: 'SIMPLE_OPTIMIZATIONS', language_in: 'ECMASCRIPT5', language_out: 'ECMASCRIPT5', formatting: 'pretty_print', }, }, targetName: { src: ['src/entry.js', 'src/**/*.js', '!src/workspace/block_entry.js'], dest: 'dist/entry.js', }, dist: { options: { compilerOpts: { compilation_level: 'SIMPLE_OPTIMIZATIONS', language_in: 'ECMASCRIPT5', language_out: 'ECMASCRIPT5', }, }, expand: false, src: ['src/entry.js', 'src/**/*.js'], dest: 'dist/entry.min.js', ext: '.min.js', }, }, }); // Load NPM tasks grunt.loadNpmTasks('grunt-closure-tools'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-concurrent'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-karma'); grunt.loadNpmTasks('grunt-contrib-less'); grunt.option('force', true); // Default tasks. grunt.registerTask('default', ['closureCompiler', 'karma', 'jshint', 'less']); grunt.registerTask('development', [ 'watch', 'closureCompiler:targetName', 'karma', 'concurrent', ]); grunt.registerTask('test', ['karma']); grunt.registerTask('closure', ['closureCompiler']); grunt.registerTask('build', ['closureCompiler', 'less']); }; ================================================ FILE: Jenkinsfile ================================================ pipeline { agent none stages { stage('EntryJS Test') { when { beforeAgent true expression { return env.CHANGE_ID } } agent { docker { image 'node:8.11.3' } } steps { script { sh "npm prune" sh "npm install" sh "yarn test" } } post { always { junit 'reports/*.xml' } } } stage('SonarQube Analysis') { when { beforeAgent true expression { return env.CHANGE_ID } } agent { docker { image 'maven:3-alpine' } } steps { script { def scannerHome = tool "sonarqube-scanner"; withSonarQubeEnv("sonar") { sh "${scannerHome}/bin/sonar-scanner " + "-Dsonar.projectKey=entry.entryjs " + "-Dsonar.projectName=entryjs " + "-Dsonar.sourceEncoding=UTF-8 " + "-Dsonar.analysis.mode=preview " + "-Dsonar.github.repository=entrylabs/entryjs " + "-Dsonar.github.endpoint=https://api.github.com " + "-Dsonar.github.oauth=${GH_TOKEN} " + "-Dsonar.issuesReport.console.enable=true " + "-Dsonar.github.disableInlineComments=true " + "-Dsonar.github.pullRequest=${env.CHANGE_ID} " + "-Dsonar.sources=src " } } } } stage('SonarQube Scan') { when { beforeAgent true allOf { expression { BRANCH_NAME ==~ /(^master$)/ } not { changeRequest() } } } agent { docker { image 'maven:3-alpine' } } steps { script { def scannerHome = tool "sonarqube-scanner"; withSonarQubeEnv("sonar") { sh "${scannerHome}/bin/sonar-scanner " + "-Dsonar.projectKey=entry.entryjs " + "-Dsonar.projectName=entryjs " + "-Dsonar.sourceEncoding=UTF-8 " + "-Dsonar.sources=src " } } } } stage('EntryJS Deploy') { when { beforeAgent true allOf { expression { BRANCH_NAME ==~ /(^master$|^deploy\/.*$)/ } not { changeRequest() } } } agent { docker { image 'node:8.11.3' } } steps { script { sh '''npm prune npm install chmod +x ./scripts/build.sh chmod +x ./scripts/deploy.sh ./scripts/build.sh ./scripts/deploy.sh''' } } } } environment { GH_REPO = 'https://github.com/entrylabs/entryjs.git' GH_REF = 'github.com/entrylabs/entryjs.git' } } ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: NOTICE ================================================ EntryJS Copyright 2015 Entry Labs EntryJS project contains subcomponents with separate copyright notices and license terms. Your use of the source code for the these subcomponents is subject to the terms and conditions of the following licenses. ======================================================================= Blockly (https://github.com/google/blockly) ======================================================================= /** * @license * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://developers.google.com/blockly/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ ======================================================================= Collision-Detection-for-EaselJS (https://github.com/olsn/Collision-Detection-for-EaselJS) ======================================================================= Copyright (c) 2013 Olaf Horstmann 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. ======================================================================= CanvasInput (https://github.com/goldfire/CanvasInput) ======================================================================= /*! * CanvasInput v1.2.1 * http://goldfirestudios.com/blog/108/CanvasInput-HTML5-Canvas-Text-Input * * (c) 2013-2015, James Simpson of GoldFire Studios * goldfirestudios.com * * MIT License */ 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. ======================================================================= Context.js (https://github.com/jakiestfu/Context.js) ======================================================================= /* * Context.js * Copyright Jacob Kelley * MIT License * * Modified by Joshua Christman */ 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. ================================================ FILE: README-en.md ================================================ # entryjs entryjs is an HTML5-based block coding library developed by entry. If you access the [Entry](https://playentry.org) site, you can check the block coding environment using entryjs. ## get started entryjs uses several open source libraries to handle HTML Canvas, audio, and vector images. After these libraries are loaded in the web project, entryjs should be loaded. ### 3rd party library * [jQuery](http://jquery.com/download/) - 1.9.1 * [jquery-ui](https://github.com/jquery/jquery-ui) - 1.10.4 * [Underscore](https://github.com/jashkenas/underscore) - 1.8.3 * [CreateJS](http://createjs.com/downloads) * EaselJS - 0.8.0 * PreloadJS - 0.6.0 * SoundJS - 0.6.0 * [Lodash](https://lodash.com/docs/4.17.15) - 4.17.10 * [Velocity](https://github.com/julianshapiro/velocity) - ~1.2.3 * [CodeMirror](https://codemirror.net) - 5.12.0 * [Fuzzy](https://github.com/mattyork/fuzzy) - ~0.1.1 * [Literallycanvas](https://github.com/entrylabs/literallycanvas) - entry version * [EntryTool](https://github.com/entrylabs/entry-tool) - entry version All of these libraries are distributed as open source, You can download it yourself or install it using [npm](http://npmjs.org) or [bower](http://bower.io). ### JavaScript library ```html ``` ### entryjs stylesheet Basic styles related to block design are defined. ```html ``` ### Entry Initialization (Inject Options) Once you have loaded the necessary libraries and entryjs, you can inject the entryjs workspace using Javascript at a specific location in the current DOM. * Entry.init(domElement, initOptions); ```html
``` ```javascript var workspace = document.getElementById("workspace"); var initOptions = { type: 'workspace', libDir: '/lib', fonts: [{ name: '나눔고딕', family: 'Nanum Gothic', url: '/css/nanumgothic.css' }] }; Entry.init(workspace, initOptions); ``` * domElement : The DOM node into which the entry will be injected. * initOptions : Option value of entryjs workspace. ### initOptions All options except Workspace type and font information are optional and Boolean type. * Required - type: Workspace type. (workspace: creation environment, minimize: viewing environment) - libDir:Third-party library repository. Library location including entryjs. (default: '/lib') - fonts: Web font information * choice - projectsaveable: Whether the project can be saved (true) - objectaddable: Whether objects can be added (true) - objectEditable: Whether the object can be modified (true). Setting this value to false also sets objectAddable to false. - objectdeletable: Whether the object can be deleted (true) - soundeditable: Whether sound can be modified (true) - pictureeditable: Whether the shape can be modified (true) - sceneEditable: Whether the scene can be modified (true) - functionEnable: Whether the function is available (true) - messageEnable: signal available (true) - variableEnable: Whether the variable is available (true) - listEnable: list available (true) - isForLecture: Lecture project or not (false) - textCodingEnable: Whether entry python is available (true) - hardwareEnable: Hardware availability (true) * Web font information 정보 You can add one or more arrays of fonts to be used in the entry textbox and paint. ```javascript [{ name: 'Font name to display on screen', family: 'font-family name', url: 'Font definition file path' }] ``` ```javascript // 예시 [{ name: 'Nanum Gothic', family: 'Nanum Gothic', url: '/css/nanumgothic.css' }, { name: 'Nanum handwriting', family: 'Nanum Pen Script', url: '/css/nanumpenscript.css' }] ``` Free Korean web fonts can be downloaded from https://www.google.com/fonts/earlyaccess. ### Entry.playground.setBlockMenu(); Block menu reset ### Entry.loadProject(project); Load project. If the project argument is omitted, the default project is returned.. ### event. (Event description) * event listening ```javascript Entry.addEventListener(eventName, function); ``` - eventName: The name of the custom event you want to catch - function: Function to be executed when the corresponding custom event occurs * event dispatch ```javascript Entry.dispatchEvent(eventName,params); ``` - eventName: The name of the event you want to trigger - params: Parameters to be passed to the callback function listening for events * representative event - run - stop * user interaction - keyPressed - keyUpped - canvasClick - canvasClickCanceled - entityClick - entityClickCanceled - stageMouseMove - stageMouseOut * screen - windowResized ### Entry.Toast * Display notification messages at the bottom of the workspace - Entry.Toast.warning(title, message, auto-dospose); // caution - Entry.Toast.success(title, message, auto-dospose); // success - Entry.Toast.alert(title, message, auto-dospose); // warning ### Block shape definition and running script. ``` ${entryjs}/src/blocks/**/* ``` ### block shape definition Please refer to [EntryDocs - Write block specification](https://entrylabs.github.io/docs/guide/entryjs/2016-05-22-add_new_blocks.html). ### Project Schema ### save :You can save essential information in JSON format using the Entry function below. A saved project can be reloaded using Entry.loadProject(project) . ```javascript var project = Entry.exportProject(); ``` ### detailed schema ```javascript /** * MongoDB schema example. */ var ProjectSchema = new Schema({ speed: { // Execution frames per second type: Number, default: 60 }, objects: [ // object list { id: String, // Object ID. Unique. name: String, // The object (or textbox title) name. text: String, // text box content. (If objectType is textBox) order: Number, // TODO objectType: String, // object type. (sprite, textBox) scene: String, // Scene ID. Unique. active: { // whether the object is active type: Boolean, default: true }, lock: { // object lock type: Boolean, default: false }, rotateMethod: String, // rotation method (free, vertical, none) entity: { // entity information rotation: Number, // rotation direction: Number, // direction x: Number, // x coordinate y: Number, // y coordinate regX: Number, // horizontal center point regY: Number, // vertical center point scaleX: Number, // horizontal scale scaleY: Number, // vertical scale width: Number, // area height: Number, // height imageIndex: Number, // TODO visible: Boolean, // screen display colour: String, // text box font color font: String, // text box font bgColor: String, // text box background color textAlign: Number, // textbox alignment lineBreak: Boolean, // Whether text box line breaks underLine: Boolean, // text box strike: Boolean // text box underline }, script: String, // block script sprite: { // sprite information name: String, // sprite name pictures: [{ // shape list id: String, // Shape ID. Unique/ name: String, // shape name fileurl: String, // shape image dimension: { // shape size width: Number, height: Number, scaleX: Number, scaleY: Number }, scale: { // Magnification, reduction ratio (based on 100%) type: Number, default: 100 } }], sounds: [{ // list of sounds id: String, // Sound ID. Unique. name: String, // name fileurl: String, // Sound file URL duration: Number // play time. (in seconds) }] }, selectedPictureId: String, // ID of the currently active shape selectedSoundId: String // ID of currently active sound } ], variables: [ // project variable { name: String, // variable name variableType: String, // variable type. (General variable: variable, timer: timer, answer: answer, slide: slide, list: list) id: String, // variable ID. Unique. value: String, // variable value minValue: Number, // minimum maxValue: Number, // max value visible: Boolean, // visibility on canvas x: Number, // Converse position x coordinate y: Number, // canvas position y-coordinate width: Number, // width height: Number, // height isCloud: { // Shared variable or not type: Boolean, default: false }, object: { // If it is a local variable, the ID of the object it refers to type: String, default: null }, array: [{ // A list of values if the variable type is list data: String // value data }] } ], messages: [ // signal list { name: String, // signal name id: String // Signal ID. Unique. } ], functions: [ // function list { id: String, // function ID. Unique. block: String, // function block information content: String, // function execution information id: String, name: String }] } ], scenes: { // scene information type: [ // scene list { name: String, // scene name id: String // Scene ID. Unique. } ] }, }); ``` ### Sprite, Picture, Sound schema ### Sprites ```javascript var SpriteSchema = new Schema({ name: String, // sprite name pictures: [{ // shape list name: String, // shape name fileurl: String, // shape image dimension: { // shape size width: Number, height: Number } }], sounds: [{ // list of sounds name: String, // name fileurl: String, // Sound file URL duration: Number // play time. (in seconds) }] }) ``` #### Pictures ```javascript var PictureSchema = new Schema({ name: String, // shape name fileurl: String, // shape image dimension: { // shape size width: Number, height: Number } }) ``` #### Sounds ```javascript var SoundSchema = new Schema({ name: String, // name fileurl: String, // Sound file URL duration: Number // play time. (in seconds) }) ``` ## Copyright and License EntryJS Copyright (c) 2015 Entry Labs. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ # entryjs entryjs는 엔트리에서 개발한 HTML5 기반의 블록코딩 라이브러리 입니다. [엔트리](https://playentry.org) 사이트에 접속하시면 entryjs를 사용한 블록코딩 환경을 확인해 볼 수 있습니다. ## 시작하기 entryjs는 HTML Canvas와 오디오, 벡터 이미지등을 다루기 위해 몇가지 오픈소스 라이브러리들을 사용합니다. 이 라이브러리들이 웹프로젝트에 먼저 로딩된 후에 entryjs를 로딩하여야 합니다. ### 써드파티 라이브러리 - [jQuery](http://jquery.com/download/) - 1.9.1 - [jquery-ui](https://github.com/jquery/jquery-ui) - 1.10.4 - [Underscore](https://github.com/jashkenas/underscore) - 1.8.3 - [CreateJS](http://createjs.com/downloads) - EaselJS - 0.8.0 - PreloadJS - 0.6.0 - SoundJS - 0.6.0 - [Lodash](https://lodash.com/docs/4.17.15) - 4.17.10 - [Velocity](https://github.com/julianshapiro/velocity) - ~1.2.3 - [CodeMirror](https://codemirror.net) - 5.12.0 - [Fuzzy](https://github.com/mattyork/fuzzy) - ~0.1.1 - [Literallycanvas](https://github.com/entrylabs/literallycanvas) - entry version - [EntryTool](https://github.com/entrylabs/entry-tool) - entry version 위 라이브러리들은 모두 오픈소스로 배포되며, 직접 다운로드 받거나 [npm](http://npmjs.org), [bower](http://bower.io)등을 이용해 설치할 수 있습니다. ### 자바스크립트 라이브러리 ```html ``` ### entryjs 스타일시트 블록 디자인과 관련된 기본적인 스타일들이 정의되어 있습니다. ```html ``` ### 엔트리 초기화 (Inject Options) 필요한 라이브러리와 entryjs를 로딩하였으면 현재 DOM의 특정 위치에 Javascript를 이용해 entryjs workspace를 주입할 수 있습니다. - Entry.init(domElement, initOptions); ```html
``` ```javascript var workspace = document.getElementById('workspace'); var initOptions = { type: 'workspace', libDir: '/lib', fonts: [ { name: '나눔고딕', family: 'Nanum Gothic', url: '/css/nanumgothic.css', }, ], }; Entry.init(workspace, initOptions); ``` - domElement : Entry가 Inject될 DOM 노드. - initOptions : entryjs workspace의 옵션값. ### initOptions Workspace 타입과 폰트정보를 제외한 모든 옵션은 선택사항이며 Boolean 타입입니다. - 필수항목 - type: 워크스페이스 타입. (workspace: 만들기 환경, minimize: 구경하기 환경) - libDir: 써드파티 라이브러리 저장소. entryjs를 포함한 Library 위치. (기본값: '/lib') - fonts: 웹폰트 정보 - 선택항목 - projectsaveable: 프로젝트 저장가능 여부 (true) - objectaddable: 오브젝트 추가가능 여부 (true) - objectEditable: 오브젝트 수정가능 여부 (true). 이값을 false로 세팅하면 objectAddable도 false가 된다. - objectdeletable: 오브젝트 삭제가능 여부 (true) - soundeditable: 소리 수정가능 여부 (true) - pictureeditable: 모양 수정가능 여부 (true) - sceneEditable: 장면 수정가능 여부 (true) - functionEnable: 함수 사용가능 여부 (true) - messageEnable: 신호 사용가능 여부 (true) - variableEnable: 변수 사용가능 여부 (true) - listEnable: 리스트 사용가능 여부 (true) - isForLecture: 강의용 프로젝트 여부 (false) - textCodingEnable: 엔트리 파이선 사용가능 여부 (true) - hardwareEnable: 하드웨어 사용가능 여부 (true) - 웹폰트 정보 엔트리 글상자와 그림판에서 사용할 폰트들을 하나 이상 배열로 추가할 수 있습니다. ```javascript [ { name: '화면에 표시할 폰트 이름', family: 'font-family 이름', url: '폰트 정의파일 경로', }, ]; ``` ```javascript // 예시 [ { name: '나눔고딕', family: 'Nanum Gothic', url: '/css/nanumgothic.css', }, { name: '나눔필기체', family: 'Nanum Pen Script', url: '/css/nanumpenscript.css', }, ]; ``` 무료 한글 웹폰트는 https://www.google.com/fonts/earlyaccess 에서 다운로드 하실 수 있습니다. ### Entry.playground.setBlockMenu(); 블록메뉴 초기화 ### Entry.loadProject(project); 프로젝트 불러오기. project 인자를 생략할 경우 기본 프로젝트를 리턴합니다. ### 이벤트. (Event description) - event listening ```javascript Entry.addEventListener(eventName, function); ``` - eventName: 캐치하고 싶은 커스텀 이벤트의 이름 - function: 해당 커스텀 이벤트가 발생했을 경우 실행 될 함수 * event dispatch ```javascript Entry.dispatchEvent(eventName, params); ``` - eventName: 발생 시키고 싶은 이벤트의 이름 - params: 이벤트를 리스닝 하고 있는 콜백함수에 넘겨줄 파라미터 * 대표적인 이벤트 - run - stop * 유저 인터랙션 - keyPressed - keyUpped - canvasClick - canvasClickCanceled - entityClick - entityClickCanceled - stageMouseMove - stageMouseOut * 화면 - windowResized ### Entry.Toast - 워크스페이스 하단에 알림 메시지 표시 * Entry.Toast.warning(title, message, auto-dospose); // 주의 * Entry.Toast.success(title, message, auto-dospose); // 성공 * Entry.Toast.alert(title, message, auto-dospose); // 경고 ### 블록 모양 정의와 실행 스크립트. ``` ${entryjs}/src/blocks/**/* ``` ### 블록 모양 정의 [EntryDocs - 블록 명세 작성](https://entrylabs.github.io/docs/guide/entryjs/2016-05-22-add_new_blocks.html) 을 참고해주세요. ### 프로젝트 (Project Schema) ### 저장 : 아래의 Entry 함수를 이용해 필수정보들을 JSON형태로 저장할 수 있습니다. 저장된 프로젝트는 Entry.loadProject(project) 를 이용해 다시 로드할 수 있습니다. ```javascript var project = Entry.exportProject(); ``` ### 상세 스키마 ```javascript /** * MongoDB 스키마 예제. */ var ProjectSchema = new Schema({ speed: { // 초당 실행 프레임수 type: Number, default: 60 }, objects: [ // 오브젝트 목록 { id: String, // 오브젝트 ID. Unique. name: String, // 오브젝트(또는 글상자 제목) 이름. text: String, // 글상자 내용. (objectType이 textBox일 경우) order: Number, // TODO objectType: String, // 오브젝트 유형. (sprite, textBox) scene: String, // 장면 ID. Unique. active: { // 오브젝트 활성화 여부 type: Boolean, default: true }, lock: { // 오브젝트 잠금 여부 type: Boolean, default: false }, rotateMethod: String, // 회전방식. (free, vertical, none) entity: { // 엔티티 정보 rotation: Number, // 회전 direction: Number, // 방향 x: Number, // x 좌표 y: Number, // y 좌표 regX: Number, // 가로 중심점 regY: Number, // 세로 중심점 scaleX: Number, // 가로 배율 scaleY: Number, // 세로 배율 width: Number, // 넓이 height: Number, // 높이 imageIndex: Number, // TODO visible: Boolean, // 화면표시 여부 colour: String, // 글상자 폰트색깔 font: String, // 글상자 폰트 bgColor: String, // 글상자 배경색깔 textAlign: Number, // 글상자 정렬 lineBreak: Boolean, // 글상자 줄바꿈 여부 underLine: Boolean, // 글상자 strike: Boolean // 글상자 밑줄 }, script: String, // 블록 스크립트 sprite: { // 스프라이트 정보 name: String, // 스프라이트 이름 pictures: [{ // 모양 목록 id: String, // 모양 ID. Unique/ name: String, // 모양 이름 fileurl: String, // 모양 이미지 dimension: { // 모양 크기 width: Number, height: Number, scaleX: Number, scaleY: Number }, scale: { // 확대, 축소 비율(100% 기준) type: Number, default: 100 } }], sounds: [{ // 소리 목록 id: String, // 소리 ID. Unique. name: String, // 이름 fileurl: String, // 사운드 파일 URL duration: Number // 재생시간. (초단위) }] }, selectedPictureId: String, // 현재 활성화된 모양의 ID selectedSoundId: String // 현재 활성화된 소리의 ID } ], variables: [ // 프로젝트 변수 { name: String, // 변수명 variableType: String, // 변수형. (일반변수: variable, 타이머: timer, 대답: answer, 슬라이드: slide, 리스트: list) id: String, // 변수ID. Unique. value: String, // 변수 값 minValue: Number, // 최소값 maxValue: Number, // 최대값 visible: Boolean, // 캔버스에 표시여부 x: Number, // 컨버스 위치 x좌표 y: Number, // 캔버스 위치 y좌표 width: Number, // 넓이 height: Number, // 높이 isCloud: { // 공유 변수 여부 type: Boolean, default: false }, object: { // 지역변수일 경우 참조하는 오브젝트 ID type: String, default: null }, array: [{ // 변수형이 list일 경우 값 목록 data: String // 값 데이터 }] } ], messages: [ // 신호 목록 { name: String, // 신호명 id: String // 신호 ID. Unique. } ], functions: [ // 함수 목록 { id: String, // 함수 ID. Unique. block: String, // 함수 블록 정보 content: String, // 함수 실행 정보 id: String, name: String }] } ], scenes: { // 장면 정보 type: [ // 장면 목록 { name: String, // 장면 이름 id: String // 장면 ID. Unique. } ] }, }); ``` ### Sprite, Picture, Sound schema ### 스프라이트 ```javascript var SpriteSchema = new Schema({ name: String, // 스프라이트 이름 pictures: [ { // 모양 목록 name: String, // 모양 이름 fileurl: String, // 모양 이미지 dimension: { // 모양 크기 width: Number, height: Number, }, }, ], sounds: [ { // 소리 목록 name: String, // 이름 fileurl: String, // 사운드 파일 URL duration: Number, // 재생시간. (초단위) }, ], }); ``` #### 모양 ```javascript var PictureSchema = new Schema({ name: String, // 모양 이름 fileurl: String, // 모양 이미지 dimension: { // 모양 크기 width: Number, height: Number, }, }); ``` #### 소리 ```javascript var SoundSchema = new Schema({ name: String, // 이름 fileurl: String, // 사운드 파일 URL duration: Number, // 재생시간. (초단위) }); ``` ## Copyright and License EntryJS Copyright (c) 2015 Entry Labs. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: contributing.md ================================================ #### 업체PR 가이드 하드웨어 업체에서는 entryjs 레포지토리에서 Pull Request를 보내실때 devleop-hw브랜치로 보내주시기 바랍니다. 기타 다른브랜치에 PR보내시면 Reject사유가 될수 있습니다. ================================================ FILE: example/example.ejs ================================================ <%= htmlWebpackPlugin.options.title %> <% for (var css in htmlWebpackPlugin.files.css) { %> <% } %>
<% for (var chunk in htmlWebpackPlugin.files.js) { %> <% } %> ================================================ FILE: example/example_mini.ejs ================================================ <%= htmlWebpackPlugin.options.title %> <% for (var css in htmlWebpackPlugin.files.css) { %> <% } %>
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %> <% } %> ================================================ FILE: example/example_webgl.ejs ================================================ <%= htmlWebpackPlugin.options.title %> <% for (var css in htmlWebpackPlugin.files.css) { %> <% } %>
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %> <% } %> ================================================ FILE: extern/blockly/.ropeproject/config.py ================================================ # The default ``config.py`` def set_prefs(prefs): """This function is called before opening the project""" # Specify which files and folders to ignore in the project. # Changes to ignored resources are not added to the history and # VCSs. Also they are not returned in `Project.get_files()`. # Note that ``?`` and ``*`` match all characters but slashes. # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' # '.svn': matches 'pkg/.svn' and all of its children # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', '.hg', '.svn', '_svn', '.git'] # Specifies which files should be considered python files. It is # useful when you have scripts inside your project. Only files # ending with ``.py`` are considered to be python files by # default. #prefs['python_files'] = ['*.py'] # Custom source folders: By default rope searches the project # for finding source folders (folders that should be searched # for finding modules). You can add paths to that list. Note # that rope guesses project source folders correctly most of the # time; use this if you have any problems. # The folders should be relative to project root and use '/' for # separating folders regardless of the platform rope is running on. # 'src/my_source_folder' for instance. #prefs.add('source_folders', 'src') # You can extend python path for looking up modules #prefs.add('python_path', '~/python/') # Should rope save object information or not. prefs['save_objectdb'] = True prefs['compress_objectdb'] = False # If `True`, rope analyzes each module when it is being saved. prefs['automatic_soa'] = True # The depth of calls to follow in static object analysis prefs['soa_followed_calls'] = 0 # If `False` when running modules or unit tests "dynamic object # analysis" is turned off. This makes them much faster. prefs['perform_doa'] = True # Rope can check the validity of its object DB when running. prefs['validate_objectdb'] = True # How many undos to hold? prefs['max_history_items'] = 32 # Shows whether to save history across sessions. prefs['save_history'] = True prefs['compress_history'] = False # Set the number spaces used for indenting. According to # :PEP:`8`, it is best to use 4 spaces. Since most of rope's # unit-tests use 4 spaces it is more reliable, too. prefs['indent_size'] = 4 # Builtin and c-extension modules that are allowed to be imported # and inspected by rope. prefs['extension_modules'] = [] # Add all standard c-extensions to extension_modules list. prefs['import_dynload_stdmods'] = True # If `True` modules with syntax errors are considered to be empty. # The default value is `False`; When `False` syntax errors raise # `rope.base.exceptions.ModuleSyntaxError` exception. prefs['ignore_syntax_errors'] = False # If `True`, rope ignores unresolvable imports. Otherwise, they # appear in the importing namespace. prefs['ignore_bad_imports'] = False def project_opened(project): """This function is called after opening the project""" # Do whatever you like here! ================================================ FILE: extern/blockly/.ropeproject/globalnames ================================================ }qUbuild]q(UGen_compressedqUHEADERqU search_pathsqU import_pathqUcalcdepsqUGen_uncompressedqU Gen_langfilesq es. ================================================ FILE: extern/blockly/.ropeproject/history ================================================ ]q(]q]qe. ================================================ FILE: extern/blockly/.ropeproject/objectdb ================================================ }q. ================================================ FILE: extern/blockly/blockly_compressed.js ================================================ // Do not edit this file; automatically generated by build.py. "use strict"; var COMPILED=!0,goog=goog||{};goog.global=this;goog.isDef=function(a){return void 0!==a};goog.exportPath_=function(a,b,c){a=a.split(".");c=c||goog.global;a[0]in c||!c.execScript||c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)!a.length&&goog.isDef(b)?c[d]=b:c=c[d]?c[d]:c[d]={}}; goog.define=function(a,b){var c=b;COMPILED||(goog.global.CLOSURE_UNCOMPILED_DEFINES&&Object.prototype.hasOwnProperty.call(goog.global.CLOSURE_UNCOMPILED_DEFINES,a)?c=goog.global.CLOSURE_UNCOMPILED_DEFINES[a]:goog.global.CLOSURE_DEFINES&&Object.prototype.hasOwnProperty.call(goog.global.CLOSURE_DEFINES,a)&&(c=goog.global.CLOSURE_DEFINES[a]));goog.exportPath_(a,c)};goog.DEBUG=!0;goog.LOCALE="en";goog.TRUSTED_SITE=!0;goog.STRICT_MODE_COMPATIBLE=!1;goog.DISALLOW_TEST_ONLY_CODE=COMPILED&&!goog.DEBUG; goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING=!1;goog.provide=function(a){if(goog.isInModuleLoader_())throw Error("goog.provide can not be used within a goog.module.");if(!COMPILED&&goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');goog.constructNamespace_(a)};goog.constructNamespace_=function(a,b){if(!COMPILED){delete goog.implicitNamespaces_[a];for(var c=a;(c=c.substring(0,c.lastIndexOf(".")))&&!goog.getObjectByName(c);)goog.implicitNamespaces_[c]=!0}goog.exportPath_(a,b)}; goog.VALID_MODULE_RE_=/^[a-zA-Z_$][a-zA-Z0-9._$]*$/;goog.module=function(a){if(!goog.isString(a)||!a||-1==a.search(goog.VALID_MODULE_RE_))throw Error("Invalid module identifier");if(!goog.isInModuleLoader_())throw Error("Module "+a+" has been loaded incorrectly.");if(goog.moduleLoaderState_.moduleName)throw Error("goog.module may only be called once per module.");goog.moduleLoaderState_.moduleName=a;if(!COMPILED){if(goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');delete goog.implicitNamespaces_[a]}}; goog.module.get=function(a){return goog.module.getInternal_(a)};goog.module.getInternal_=function(a){if(!COMPILED)return goog.isProvided_(a)?a in goog.loadedModules_?goog.loadedModules_[a]:goog.getObjectByName(a):null};goog.moduleLoaderState_=null;goog.isInModuleLoader_=function(){return null!=goog.moduleLoaderState_}; goog.module.declareLegacyNamespace=function(){if(!COMPILED&&!goog.isInModuleLoader_())throw Error("goog.module.declareLegacyNamespace must be called from within a goog.module");if(!COMPILED&&!goog.moduleLoaderState_.moduleName)throw Error("goog.module must be called prior to goog.module.declareLegacyNamespace.");goog.moduleLoaderState_.declareLegacyNamespace=!0}; goog.setTestOnly=function(a){if(goog.DISALLOW_TEST_ONLY_CODE)throw a=a||"",Error("Importing test-only code into non-debug environment"+(a?": "+a:"."));};goog.forwardDeclare=function(a){};COMPILED||(goog.isProvided_=function(a){return a in goog.loadedModules_||!goog.implicitNamespaces_[a]&&goog.isDefAndNotNull(goog.getObjectByName(a))},goog.implicitNamespaces_={"goog.module":!0}); goog.getObjectByName=function(a,b){for(var c=a.split("."),d=b||goog.global,e;e=c.shift();)if(goog.isDefAndNotNull(d[e]))d=d[e];else return null;return d};goog.globalize=function(a,b){var c=b||goog.global,d;for(d in a)c[d]=a[d]}; goog.addDependency=function(a,b,c,d){if(goog.DEPENDENCIES_ENABLED){var e;a=a.replace(/\\/g,"/");var f=goog.dependencies_;d&&"boolean"!==typeof d||(d=d?{module:"goog"}:{});for(var g=0;e=b[g];g++)f.nameToPath[e]=a,f.loadFlags[a]=d;for(d=0;b=c[d];d++)a in f.requires||(f.requires[a]={}),f.requires[a][b]=!0}};goog.ENABLE_DEBUG_LOADER=!0;goog.logToConsole_=function(a){goog.global.console&&goog.global.console.error(a)}; goog.require=function(a){if(!COMPILED){goog.ENABLE_DEBUG_LOADER&&goog.IS_OLD_IE_&&goog.maybeProcessDeferredDep_(a);if(goog.isProvided_(a))return goog.isInModuleLoader_()?goog.module.getInternal_(a):null;if(goog.ENABLE_DEBUG_LOADER){var b=goog.getPathFromDeps_(a);if(b)return goog.writeScripts_(b),null}a="goog.require could not find: "+a;goog.logToConsole_(a);throw Error(a);}};goog.basePath="";goog.nullFunction=function(){}; goog.abstractMethod=function(){throw Error("unimplemented abstract method");};goog.addSingletonGetter=function(a){a.getInstance=function(){if(a.instance_)return a.instance_;goog.DEBUG&&(goog.instantiatedSingletons_[goog.instantiatedSingletons_.length]=a);return a.instance_=new a}};goog.instantiatedSingletons_=[];goog.LOAD_MODULE_USING_EVAL=!0;goog.SEAL_MODULE_EXPORTS=goog.DEBUG;goog.loadedModules_={};goog.DEPENDENCIES_ENABLED=!COMPILED&&goog.ENABLE_DEBUG_LOADER;goog.TRANSPILE="detect"; goog.TRANSPILER="transpile.js"; goog.DEPENDENCIES_ENABLED&&(goog.dependencies_={loadFlags:{},nameToPath:{},requires:{},visited:{},written:{},deferred:{}},goog.inHtmlDocument_=function(){var a=goog.global.document;return null!=a&&"write"in a},goog.findBasePath_=function(){if(goog.isDef(goog.global.CLOSURE_BASE_PATH))goog.basePath=goog.global.CLOSURE_BASE_PATH;else if(goog.inHtmlDocument_())for(var a=goog.global.document.getElementsByTagName("SCRIPT"),b=a.length-1;0<=b;--b){var c=a[b].src,d=c.lastIndexOf("?"),d=-1==d?c.length:d;if("base.js"== c.substr(d-7,7)){goog.basePath=c.substr(0,d-7);break}}},goog.importScript_=function(a,b){(goog.global.CLOSURE_IMPORT_SCRIPT||goog.writeScriptTag_)(a,b)&&(goog.dependencies_.written[a]=!0)},goog.IS_OLD_IE_=!(goog.global.atob||!goog.global.document||!goog.global.document.all),goog.importProcessedScript_=function(a,b,c){goog.importScript_("",'goog.retrieveAndExec_("'+a+'", '+b+", "+c+");")},goog.queuedModules_=[],goog.wrapModule_=function(a,b){return goog.LOAD_MODULE_USING_EVAL&&goog.isDef(goog.global.JSON)? "goog.loadModule("+goog.global.JSON.stringify(b+"\n//# sourceURL="+a+"\n")+");":'goog.loadModule(function(exports) {"use strict";'+b+"\n;return exports});\n//# sourceURL="+a+"\n"},goog.loadQueuedModules_=function(){var a=goog.queuedModules_.length;if(0\x3c/script>')},goog.appendScriptSrcNode_=function(a){var b=goog.global.document,c=b.createElement("script");c.type="text/javascript";c.src=a;c.defer=!1;c.async=!1;b.head.appendChild(c)},goog.writeScriptTag_=function(a,b){if(goog.inHtmlDocument_()){var c= goog.global.document;if(!goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING&&"complete"==c.readyState){if(/\bdeps.js$/.test(a))return!1;throw Error('Cannot write "'+a+'" after document load');}if(void 0===b)if(goog.IS_OLD_IE_){var d=" onreadystatechange='goog.onScriptLoad_(this, "+ ++goog.lastNonModuleScriptIndex_+")' ";c.write(''); // Load fresh Closure Library. document.write(''); document.write(''); ================================================ FILE: extern/blockly/blocks/colour.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Colour blocks for Blockly. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Blocks.colour'); goog.require('Blockly.Blocks'); Blockly.Blocks['colour_picker'] = { // Colour picker. init: function() { this.setHelpUrl(Blockly.Msg.COLOUR_PICKER_HELPURL); this.setColour(20); this.appendDummyInput() .appendField(new Blockly.FieldColour('#ff0000'), 'COLOUR'); this.setOutput(true, 'Colour'); this.setTooltip(Blockly.Msg.COLOUR_PICKER_TOOLTIP); } }; Blockly.Blocks['colour_random'] = { // Random colour. init: function() { this.setHelpUrl(Blockly.Msg.COLOUR_RANDOM_HELPURL); this.setColour(20); this.appendDummyInput() .appendField(Blockly.Msg.COLOUR_RANDOM_TITLE); this.setOutput(true, 'Colour'); this.setTooltip(Blockly.Msg.COLOUR_RANDOM_TOOLTIP); } }; Blockly.Blocks['colour_rgb'] = { // Compose a colour from RGB components. init: function() { this.setHelpUrl(Blockly.Msg.COLOUR_RGB_HELPURL); this.setColour(20); this.appendValueInput('RED') .setCheck('Number') .setAlign(Blockly.ALIGN_RIGHT) .appendField(Blockly.Msg.COLOUR_RGB_TITLE) .appendField(Blockly.Msg.COLOUR_RGB_RED); this.appendValueInput('GREEN') .setCheck('Number') .setAlign(Blockly.ALIGN_RIGHT) .appendField(Blockly.Msg.COLOUR_RGB_GREEN); this.appendValueInput('BLUE') .setCheck('Number') .setAlign(Blockly.ALIGN_RIGHT) .appendField(Blockly.Msg.COLOUR_RGB_BLUE); this.setOutput(true, 'Colour'); this.setTooltip(Blockly.Msg.COLOUR_RGB_TOOLTIP); } }; Blockly.Blocks['colour_blend'] = { // Blend two colours together. init: function() { this.setHelpUrl(Blockly.Msg.COLOUR_BLEND_HELPURL); this.setColour(20); this.appendValueInput('COLOUR1') .setCheck('Colour') .setAlign(Blockly.ALIGN_RIGHT) .appendField(Blockly.Msg.COLOUR_BLEND_TITLE) .appendField(Blockly.Msg.COLOUR_BLEND_COLOUR1); this.appendValueInput('COLOUR2') .setCheck('Colour') .setAlign(Blockly.ALIGN_RIGHT) .appendField(Blockly.Msg.COLOUR_BLEND_COLOUR2); this.appendValueInput('RATIO') .setCheck('Number') .setAlign(Blockly.ALIGN_RIGHT) .appendField(Blockly.Msg.COLOUR_BLEND_RATIO); this.setOutput(true, 'Colour'); this.setTooltip(Blockly.Msg.COLOUR_BLEND_TOOLTIP); } }; ================================================ FILE: extern/blockly/blocks/lists.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview List blocks for Blockly. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Blocks.lists'); goog.require('Blockly.Blocks'); Blockly.Blocks['lists_create_empty'] = { // Create an empty list. init: function() { this.setHelpUrl(Blockly.Msg.LISTS_CREATE_EMPTY_HELPURL); this.setColour(260); this.setOutput(true, 'Array'); this.appendDummyInput() .appendField(Blockly.Msg.LISTS_CREATE_EMPTY_TITLE); this.setTooltip(Blockly.Msg.LISTS_CREATE_EMPTY_TOOLTIP); } }; Blockly.Blocks['lists_create_with'] = { // Create a list with any number of elements of any type. init: function() { this.setColour(260); this.appendValueInput('ADD0') .appendField(Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH); this.appendValueInput('ADD1'); this.appendValueInput('ADD2'); this.setOutput(true, 'Array'); this.setMutator(new Blockly.Mutator(['lists_create_with_item'])); this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_TOOLTIP); this.itemCount_ = 3; }, mutationToDom: function(workspace) { var container = document.createElement('mutation'); container.setAttribute('items', this.itemCount_); return container; }, domToMutation: function(container) { for (var x = 0; x < this.itemCount_; x++) { this.removeInput('ADD' + x); } this.itemCount_ = parseInt(container.getAttribute('items'), 10); for (var x = 0; x < this.itemCount_; x++) { var input = this.appendValueInput('ADD' + x); if (x == 0) { input.appendField(Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH); } } if (this.itemCount_ == 0) { this.appendDummyInput('EMPTY') .appendField(Blockly.Msg.LISTS_CREATE_EMPTY_TITLE); } }, decompose: function(workspace) { var containerBlock = Blockly.Block.obtain(workspace, 'lists_create_with_container'); containerBlock.initSvg(); var connection = containerBlock.getInput('STACK').connection; for (var x = 0; x < this.itemCount_; x++) { var itemBlock = Blockly.Block.obtain(workspace, 'lists_create_with_item'); itemBlock.initSvg(); connection.connect(itemBlock.previousConnection); connection = itemBlock.nextConnection; } return containerBlock; }, compose: function(containerBlock) { // Disconnect all input blocks and remove all inputs. if (this.itemCount_ == 0) { this.removeInput('EMPTY'); } else { for (var x = this.itemCount_ - 1; x >= 0; x--) { this.removeInput('ADD' + x); } } this.itemCount_ = 0; // Rebuild the block's inputs. var itemBlock = containerBlock.getInputTargetBlock('STACK'); while (itemBlock) { var input = this.appendValueInput('ADD' + this.itemCount_); if (this.itemCount_ == 0) { input.appendField(Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH); } // Reconnect any child blocks. if (itemBlock.valueConnection_) { input.connection.connect(itemBlock.valueConnection_); } this.itemCount_++; itemBlock = itemBlock.nextConnection && itemBlock.nextConnection.targetBlock(); } if (this.itemCount_ == 0) { this.appendDummyInput('EMPTY') .appendField(Blockly.Msg.LISTS_CREATE_EMPTY_TITLE); } }, saveConnections: function(containerBlock) { // Store a pointer to any connected child blocks. var itemBlock = containerBlock.getInputTargetBlock('STACK'); var x = 0; while (itemBlock) { var input = this.getInput('ADD' + x); itemBlock.valueConnection_ = input && input.connection.targetConnection; x++; itemBlock = itemBlock.nextConnection && itemBlock.nextConnection.targetBlock(); } } }; Blockly.Blocks['lists_create_with_container'] = { // Container. init: function() { this.setColour(260); this.appendDummyInput() .appendField(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TITLE_ADD); this.appendStatementInput('STACK'); this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TOOLTIP); this.contextMenu = false; } }; Blockly.Blocks['lists_create_with_item'] = { // Add items. init: function() { this.setColour(260); this.appendDummyInput() .appendField(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TITLE); this.setPreviousStatement(true); this.setNextStatement(true); this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TOOLTIP); this.contextMenu = false; } }; Blockly.Blocks['lists_repeat'] = { // Create a list with one element repeated. init: function() { this.setHelpUrl(Blockly.Msg.LISTS_REPEAT_HELPURL); this.setColour(260); this.setOutput(true, 'Array'); this.interpolateMsg(Blockly.Msg.LISTS_REPEAT_TITLE, ['ITEM', null, Blockly.ALIGN_RIGHT], ['NUM', 'Number', Blockly.ALIGN_RIGHT], Blockly.ALIGN_RIGHT); this.setTooltip(Blockly.Msg.LISTS_REPEAT_TOOLTIP); } }; Blockly.Blocks['lists_length'] = { // List length. init: function() { this.setHelpUrl(Blockly.Msg.LISTS_LENGTH_HELPURL); this.setColour(260); this.interpolateMsg(Blockly.Msg.LISTS_LENGTH_TITLE, ['VALUE', ['Array', 'String'], Blockly.ALIGN_RIGHT], Blockly.ALIGN_RIGHT); this.setOutput(true, 'Number'); this.setTooltip(Blockly.Msg.LISTS_LENGTH_TOOLTIP); } }; Blockly.Blocks['lists_isEmpty'] = { // Is the list empty? init: function() { this.setHelpUrl(Blockly.Msg.LISTS_IS_EMPTY_HELPURL); this.setColour(260); this.interpolateMsg(Blockly.Msg.LISTS_IS_EMPTY_TITLE, ['VALUE', ['Array', 'String'], Blockly.ALIGN_RIGHT], Blockly.ALIGN_RIGHT) this.setInputsInline(true); this.setOutput(true, 'Boolean'); this.setTooltip(Blockly.Msg.LISTS_TOOLTIP); } }; Blockly.Blocks['lists_indexOf'] = { // Find an item in the list. init: function() { var OPERATORS = [[Blockly.Msg.LISTS_INDEX_OF_FIRST, 'FIRST'], [Blockly.Msg.LISTS_INDEX_OF_LAST, 'LAST']]; this.setHelpUrl(Blockly.Msg.LISTS_INDEX_OF_HELPURL); this.setColour(260); this.setOutput(true, 'Number'); this.appendValueInput('VALUE') .setCheck('Array') .appendField(Blockly.Msg.LISTS_INDEX_OF_INPUT_IN_LIST); this.appendValueInput('FIND') .appendField(new Blockly.FieldDropdown(OPERATORS), 'END'); this.setInputsInline(true); this.setTooltip(Blockly.Msg.LISTS_INDEX_OF_TOOLTIP); } }; Blockly.Blocks['lists_getIndex'] = { // Get element at index. init: function() { var MODE = [[Blockly.Msg.LISTS_GET_INDEX_GET, 'GET'], [Blockly.Msg.LISTS_GET_INDEX_GET_REMOVE, 'GET_REMOVE'], [Blockly.Msg.LISTS_GET_INDEX_REMOVE, 'REMOVE']]; this.WHERE_OPTIONS = [[Blockly.Msg.LISTS_GET_INDEX_FROM_START, 'FROM_START'], [Blockly.Msg.LISTS_GET_INDEX_FROM_END, 'FROM_END'], [Blockly.Msg.LISTS_GET_INDEX_FIRST, 'FIRST'], [Blockly.Msg.LISTS_GET_INDEX_LAST, 'LAST'], [Blockly.Msg.LISTS_GET_INDEX_RANDOM, 'RANDOM']]; this.setHelpUrl(Blockly.Msg.LISTS_GET_INDEX_HELPURL); this.setColour(260); var modeMenu = new Blockly.FieldDropdown(MODE, function(value) { var isStatement = (value == 'REMOVE'); this.sourceBlock_.updateStatement(isStatement); }); this.appendValueInput('VALUE') .setCheck('Array') .appendField(Blockly.Msg.LISTS_GET_INDEX_INPUT_IN_LIST); this.appendDummyInput() .appendField(modeMenu, 'MODE') .appendField('', 'SPACE'); this.appendDummyInput('AT'); if (Blockly.Msg.LISTS_GET_INDEX_TAIL) { this.appendDummyInput('TAIL') .appendField(Blockly.Msg.LISTS_GET_INDEX_TAIL); } this.setInputsInline(true); this.setOutput(true); this.updateAt(true); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { var combo = thisBlock.getFieldValue('MODE') + '_' + thisBlock.getFieldValue('WHERE'); return Blockly.Msg['LISTS_GET_INDEX_TOOLTIP_' + combo]; }); }, mutationToDom: function() { // Save whether the block is a statement or a value. // Save whether there is an 'AT' input. var container = document.createElement('mutation'); var isStatement = !this.outputConnection; container.setAttribute('statement', isStatement); var isAt = this.getInput('AT').type == Blockly.INPUT_VALUE; container.setAttribute('at', isAt); return container; }, domToMutation: function(xmlElement) { // Restore the block shape. // Note: Until January 2013 this block did not have mutations, // so 'statement' defaults to false and 'at' defaults to true. var isStatement = (xmlElement.getAttribute('statement') == 'true'); this.updateStatement(isStatement); var isAt = (xmlElement.getAttribute('at') != 'false'); this.updateAt(isAt); }, updateStatement: function(newStatement) { // Switch between a value block and a statement block. var oldStatement = !this.outputConnection; if (newStatement != oldStatement) { this.unplug(true, true); if (newStatement) { this.setOutput(false); this.setPreviousStatement(true); this.setNextStatement(true); } else { this.setPreviousStatement(false); this.setNextStatement(false); this.setOutput(true); } } }, updateAt: function(isAt) { // Create or delete an input for the numeric index. // Destroy old 'AT' and 'ORDINAL' inputs. this.removeInput('AT'); this.removeInput('ORDINAL', true); // Create either a value 'AT' input or a dummy input. if (isAt) { this.appendValueInput('AT').setCheck('Number'); if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) { this.appendDummyInput('ORDINAL') .appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX); } } else { this.appendDummyInput('AT'); } var menu = new Blockly.FieldDropdown(this.WHERE_OPTIONS, function(value) { var newAt = (value == 'FROM_START') || (value == 'FROM_END'); // The 'isAt' variable is available due to this function being a closure. if (newAt != isAt) { var block = this.sourceBlock_; block.updateAt(newAt); // This menu has been destroyed and replaced. Update the replacement. block.setFieldValue(value, 'WHERE'); return null; } return undefined; }); this.getInput('AT').appendField(menu, 'WHERE'); if (Blockly.Msg.LISTS_GET_INDEX_TAIL) { this.moveInputBefore('TAIL', null); } } }; Blockly.Blocks['lists_setIndex'] = { // Set element at index. init: function() { var MODE = [[Blockly.Msg.LISTS_SET_INDEX_SET, 'SET'], [Blockly.Msg.LISTS_SET_INDEX_INSERT, 'INSERT']]; this.WHERE_OPTIONS = [[Blockly.Msg.LISTS_GET_INDEX_FROM_START, 'FROM_START'], [Blockly.Msg.LISTS_GET_INDEX_FROM_END, 'FROM_END'], [Blockly.Msg.LISTS_GET_INDEX_FIRST, 'FIRST'], [Blockly.Msg.LISTS_GET_INDEX_LAST, 'LAST'], [Blockly.Msg.LISTS_GET_INDEX_RANDOM, 'RANDOM']]; this.setHelpUrl(Blockly.Msg.LISTS_SET_INDEX_HELPURL); this.setColour(260); this.appendValueInput('LIST') .setCheck('Array') .appendField(Blockly.Msg.LISTS_SET_INDEX_INPUT_IN_LIST); this.appendDummyInput() .appendField(new Blockly.FieldDropdown(MODE), 'MODE') .appendField('', 'SPACE'); this.appendDummyInput('AT'); this.appendValueInput('TO') .appendField(Blockly.Msg.LISTS_SET_INDEX_INPUT_TO); this.setInputsInline(true); this.setPreviousStatement(true); this.setNextStatement(true); this.setTooltip(Blockly.Msg.LISTS_SET_INDEX_TOOLTIP); this.updateAt(true); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { var combo = thisBlock.getFieldValue('MODE') + '_' + thisBlock.getFieldValue('WHERE'); return Blockly.Msg['LISTS_SET_INDEX_TOOLTIP_' + combo]; }); }, mutationToDom: function() { // Save whether there is an 'AT' input. var container = document.createElement('mutation'); var isAt = this.getInput('AT').type == Blockly.INPUT_VALUE; container.setAttribute('at', isAt); return container; }, domToMutation: function(xmlElement) { // Restore the block shape. // Note: Until January 2013 this block did not have mutations, // so 'at' defaults to true. var isAt = (xmlElement.getAttribute('at') != 'false'); this.updateAt(isAt); }, updateAt: function(isAt) { // Create or delete an input for the numeric index. // Destroy old 'AT' and 'ORDINAL' input. this.removeInput('AT'); this.removeInput('ORDINAL', true); // Create either a value 'AT' input or a dummy input. if (isAt) { this.appendValueInput('AT').setCheck('Number'); if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) { this.appendDummyInput('ORDINAL') .appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX); } } else { this.appendDummyInput('AT'); } var menu = new Blockly.FieldDropdown(this.WHERE_OPTIONS, function(value) { var newAt = (value == 'FROM_START') || (value == 'FROM_END'); // The 'isAt' variable is available due to this function being a closure. if (newAt != isAt) { var block = this.sourceBlock_; block.updateAt(newAt); // This menu has been destroyed and replaced. Update the replacement. block.setFieldValue(value, 'WHERE'); return null; } return undefined; }); this.moveInputBefore('AT', 'TO'); if (this.getInput('ORDINAL')) { this.moveInputBefore('ORDINAL', 'TO'); } this.getInput('AT').appendField(menu, 'WHERE'); } }; Blockly.Blocks['lists_getSublist'] = { // Get sublist. init: function() { this.WHERE_OPTIONS_1 = [[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_START, 'FROM_START'], [Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_END, 'FROM_END'], [Blockly.Msg.LISTS_GET_SUBLIST_START_FIRST, 'FIRST']]; this.WHERE_OPTIONS_2 = [[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_START, 'FROM_START'], [Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_END, 'FROM_END'], [Blockly.Msg.LISTS_GET_SUBLIST_END_LAST, 'LAST']]; this.setHelpUrl(Blockly.Msg.LISTS_GET_SUBLIST_HELPURL); this.setColour(260); this.appendValueInput('LIST') .setCheck('Array') .appendField(Blockly.Msg.LISTS_GET_SUBLIST_INPUT_IN_LIST); this.appendDummyInput('AT1'); this.appendDummyInput('AT2'); if (Blockly.Msg.LISTS_GET_SUBLIST_TAIL) { this.appendDummyInput('TAIL') .appendField(Blockly.Msg.LISTS_GET_SUBLIST_TAIL); } this.setInputsInline(true); this.setOutput(true, 'Array'); this.updateAt(1, true); this.updateAt(2, true); this.setTooltip(Blockly.Msg.LISTS_GET_SUBLIST_TOOLTIP); }, mutationToDom: function() { // Save whether there are 'AT' inputs. var container = document.createElement('mutation'); var isAt1 = this.getInput('AT1').type == Blockly.INPUT_VALUE; container.setAttribute('at1', isAt1); var isAt2 = this.getInput('AT2').type == Blockly.INPUT_VALUE; container.setAttribute('at2', isAt2); return container; }, domToMutation: function(xmlElement) { // Restore the block shape. var isAt1 = (xmlElement.getAttribute('at1') == 'true'); var isAt2 = (xmlElement.getAttribute('at2') == 'true'); this.updateAt(1, isAt1); this.updateAt(2, isAt2); }, updateAt: function(n, isAt) { // Create or delete an input for the numeric index. // Destroy old 'AT' and 'ORDINAL' inputs. this.removeInput('AT' + n); this.removeInput('ORDINAL' + n, true); // Create either a value 'AT' input or a dummy input. if (isAt) { this.appendValueInput('AT' + n).setCheck('Number'); if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) { this.appendDummyInput('ORDINAL' + n) .appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX); } } else { this.appendDummyInput('AT' + n); } var menu = new Blockly.FieldDropdown(this['WHERE_OPTIONS_' + n], function(value) { var newAt = (value == 'FROM_START') || (value == 'FROM_END'); // The 'isAt' variable is available due to this function being a closure. if (newAt != isAt) { var block = this.sourceBlock_; block.updateAt(n, newAt); // This menu has been destroyed and replaced. Update the replacement. block.setFieldValue(value, 'WHERE' + n); return null; } return undefined; }); this.getInput('AT' + n) .appendField(menu, 'WHERE' + n); if (n == 1) { this.moveInputBefore('AT1', 'AT2'); if (this.getInput('ORDINAL1')) { this.moveInputBefore('ORDINAL1', 'AT2'); } } if (Blockly.Msg.LISTS_GET_SUBLIST_TAIL) { this.moveInputBefore('TAIL', null); } } }; ================================================ FILE: extern/blockly/blocks/logic.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Logic blocks for Blockly. * @author q.neutron@gmail.com (Quynh Neutron) */ 'use strict'; goog.provide('Blockly.Blocks.logic'); goog.require('Blockly.Blocks'); Blockly.Blocks['controls_if'] = { // If/elseif/else condition. init: function() { this.setHelpUrl(Blockly.Msg.CONTROLS_IF_HELPURL); this.setColour(210); this.appendValueInput('IF0') .setCheck('Boolean') .appendField(Blockly.Msg.CONTROLS_IF_MSG_IF); this.appendStatementInput('DO0') .appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN); this.setPreviousStatement(true); this.setNextStatement(true); this.setMutator(new Blockly.Mutator(['controls_if_elseif', 'controls_if_else'])); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { if (!thisBlock.elseifCount_ && !thisBlock.elseCount_) { return Blockly.Msg.CONTROLS_IF_TOOLTIP_1; } else if (!thisBlock.elseifCount_ && thisBlock.elseCount_) { return Blockly.Msg.CONTROLS_IF_TOOLTIP_2; } else if (thisBlock.elseifCount_ && !thisBlock.elseCount_) { return Blockly.Msg.CONTROLS_IF_TOOLTIP_3; } else if (thisBlock.elseifCount_ && thisBlock.elseCount_) { return Blockly.Msg.CONTROLS_IF_TOOLTIP_4; } return ''; }); this.elseifCount_ = 0; this.elseCount_ = 0; }, mutationToDom: function() { if (!this.elseifCount_ && !this.elseCount_) { return null; } var container = document.createElement('mutation'); if (this.elseifCount_) { container.setAttribute('elseif', this.elseifCount_); } if (this.elseCount_) { container.setAttribute('else', 1); } return container; }, domToMutation: function(xmlElement) { this.elseifCount_ = parseInt(xmlElement.getAttribute('elseif'), 10); this.elseCount_ = parseInt(xmlElement.getAttribute('else'), 10); for (var x = 1; x <= this.elseifCount_; x++) { this.appendValueInput('IF' + x) .setCheck('Boolean') .appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF); this.appendStatementInput('DO' + x) .appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN); } if (this.elseCount_) { this.appendStatementInput('ELSE') .appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE); } }, decompose: function(workspace) { var containerBlock = Blockly.Block.obtain(workspace, 'controls_if_if'); containerBlock.initSvg(); var connection = containerBlock.getInput('STACK').connection; for (var x = 1; x <= this.elseifCount_; x++) { var elseifBlock = Blockly.Block.obtain(workspace, 'controls_if_elseif'); elseifBlock.initSvg(); connection.connect(elseifBlock.previousConnection); connection = elseifBlock.nextConnection; } if (this.elseCount_) { var elseBlock = Blockly.Block.obtain(workspace, 'controls_if_else'); elseBlock.initSvg(); connection.connect(elseBlock.previousConnection); } return containerBlock; }, compose: function(containerBlock) { // Disconnect the else input blocks and remove the inputs. if (this.elseCount_) { this.removeInput('ELSE'); } this.elseCount_ = 0; // Disconnect all the elseif input blocks and remove the inputs. for (var x = this.elseifCount_; x > 0; x--) { this.removeInput('IF' + x); this.removeInput('DO' + x); } this.elseifCount_ = 0; // Rebuild the block's optional inputs. var clauseBlock = containerBlock.getInputTargetBlock('STACK'); while (clauseBlock) { switch (clauseBlock.type) { case 'controls_if_elseif': this.elseifCount_++; var ifInput = this.appendValueInput('IF' + this.elseifCount_) .setCheck('Boolean') .appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF); var doInput = this.appendStatementInput('DO' + this.elseifCount_); doInput.appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN); // Reconnect any child blocks. if (clauseBlock.valueConnection_) { ifInput.connection.connect(clauseBlock.valueConnection_); } if (clauseBlock.statementConnection_) { doInput.connection.connect(clauseBlock.statementConnection_); } break; case 'controls_if_else': this.elseCount_++; var elseInput = this.appendStatementInput('ELSE'); elseInput.appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE); // Reconnect any child blocks. if (clauseBlock.statementConnection_) { elseInput.connection.connect(clauseBlock.statementConnection_); } break; default: throw 'Unknown block type.'; } clauseBlock = clauseBlock.nextConnection && clauseBlock.nextConnection.targetBlock(); } }, saveConnections: function(containerBlock) { // Store a pointer to any connected child blocks. var clauseBlock = containerBlock.getInputTargetBlock('STACK'); var x = 1; while (clauseBlock) { switch (clauseBlock.type) { case 'controls_if_elseif': var inputIf = this.getInput('IF' + x); var inputDo = this.getInput('DO' + x); clauseBlock.valueConnection_ = inputIf && inputIf.connection.targetConnection; clauseBlock.statementConnection_ = inputDo && inputDo.connection.targetConnection; x++; break; case 'controls_if_else': var inputDo = this.getInput('ELSE'); clauseBlock.statementConnection_ = inputDo && inputDo.connection.targetConnection; break; default: throw 'Unknown block type.'; } clauseBlock = clauseBlock.nextConnection && clauseBlock.nextConnection.targetBlock(); } } }; Blockly.Blocks['controls_if_if'] = { // If condition. init: function() { this.setColour(210); this.appendDummyInput() .appendField(Blockly.Msg.CONTROLS_IF_IF_TITLE_IF); this.appendStatementInput('STACK'); this.setTooltip(Blockly.Msg.CONTROLS_IF_IF_TOOLTIP); this.contextMenu = false; } }; Blockly.Blocks['controls_if_elseif'] = { // Else-If condition. init: function() { this.setColour(210); this.appendDummyInput() .appendField(Blockly.Msg.CONTROLS_IF_ELSEIF_TITLE_ELSEIF); this.setPreviousStatement(true); this.setNextStatement(true); this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSEIF_TOOLTIP); this.contextMenu = false; } }; Blockly.Blocks['controls_if_else'] = { // Else condition. init: function() { this.setColour(210); this.appendDummyInput() .appendField(Blockly.Msg.CONTROLS_IF_ELSE_TITLE_ELSE); this.setPreviousStatement(true); this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSE_TOOLTIP); this.contextMenu = false; } }; Blockly.Blocks['logic_compare'] = { // Comparison operator. init: function() { var OPERATORS = Blockly.RTL ? [ ['=', 'EQ'], ['\u2260', 'NEQ'], ['>', 'LT'], ['\u2265', 'LTE'], ['<', 'GT'], ['\u2264', 'GTE'] ] : [ ['=', 'EQ'], ['\u2260', 'NEQ'], ['<', 'LT'], ['\u2264', 'LTE'], ['>', 'GT'], ['\u2265', 'GTE'] ]; this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL); this.setColour(210); this.setOutput(true, 'Boolean'); this.appendValueInput('A'); this.appendValueInput('B') .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP'); this.setInputsInline(true); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { var op = thisBlock.getFieldValue('OP'); var TOOLTIPS = { EQ: Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ, NEQ: Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ, LT: Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT, LTE: Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE, GT: Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT, GTE: Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE }; return TOOLTIPS[op]; }); } }; Blockly.Blocks['logic_operation'] = { // Logical operations: 'and', 'or'. init: function() { var OPERATORS = [[Blockly.Msg.LOGIC_OPERATION_AND, 'AND'], [Blockly.Msg.LOGIC_OPERATION_OR, 'OR']]; this.setHelpUrl(Blockly.Msg.LOGIC_OPERATION_HELPURL); this.setColour(210); this.setOutput(true, 'Boolean'); this.appendValueInput('A') .setCheck('Boolean'); this.appendValueInput('B') .setCheck('Boolean') .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP'); this.setInputsInline(true); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { var op = thisBlock.getFieldValue('OP'); var TOOLTIPS = { AND: Blockly.Msg.LOGIC_OPERATION_TOOLTIP_AND, OR: Blockly.Msg.LOGIC_OPERATION_TOOLTIP_OR }; return TOOLTIPS[op]; }); } }; Blockly.Blocks['logic_negate'] = { // Negation. init: function() { this.setHelpUrl(Blockly.Msg.LOGIC_NEGATE_HELPURL); this.setColour(210); this.setOutput(true, 'Boolean'); this.interpolateMsg(Blockly.Msg.LOGIC_NEGATE_TITLE, ['BOOL', 'Boolean', Blockly.ALIGN_RIGHT], Blockly.ALIGN_RIGHT); this.setTooltip(Blockly.Msg.LOGIC_NEGATE_TOOLTIP); } }; Blockly.Blocks['logic_boolean'] = { // Boolean data type: true and false. init: function() { var BOOLEANS = [[Blockly.Msg.LOGIC_BOOLEAN_TRUE, 'TRUE'], [Blockly.Msg.LOGIC_BOOLEAN_FALSE, 'FALSE']]; this.setHelpUrl(Blockly.Msg.LOGIC_BOOLEAN_HELPURL); this.setColour(210); this.setOutput(true, 'Boolean'); this.appendDummyInput() .appendField(new Blockly.FieldDropdown(BOOLEANS), 'BOOL'); this.setTooltip(Blockly.Msg.LOGIC_BOOLEAN_TOOLTIP); } }; Blockly.Blocks['logic_null'] = { // Null data type. init: function() { this.setHelpUrl(Blockly.Msg.LOGIC_NULL_HELPURL); this.setColour(210); this.setOutput(true); this.appendDummyInput() .appendField(Blockly.Msg.LOGIC_NULL); this.setTooltip(Blockly.Msg.LOGIC_NULL_TOOLTIP); } }; Blockly.Blocks['logic_ternary'] = { // Ternary operator. init: function() { this.setHelpUrl(Blockly.Msg.LOGIC_TERNARY_HELPURL); this.setColour(210); this.appendValueInput('IF') .setCheck('Boolean') .appendField(Blockly.Msg.LOGIC_TERNARY_CONDITION); this.appendValueInput('THEN') .appendField(Blockly.Msg.LOGIC_TERNARY_IF_TRUE); this.appendValueInput('ELSE') .appendField(Blockly.Msg.LOGIC_TERNARY_IF_FALSE); this.setOutput(true); this.setTooltip(Blockly.Msg.LOGIC_TERNARY_TOOLTIP); } }; ================================================ FILE: extern/blockly/blocks/loops.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Loop blocks for Blockly. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Blocks.loops'); goog.require('Blockly.Blocks'); Blockly.Blocks['controls_repeat'] = { // Repeat n times (internal number). init: function() { this.setHelpUrl(Blockly.Msg.CONTROLS_REPEAT_HELPURL); this.setColour(120); this.appendDummyInput() .appendField(Blockly.Msg.CONTROLS_REPEAT_TITLE_REPEAT) .appendField(new Blockly.FieldTextInput('10', Blockly.FieldTextInput.nonnegativeIntegerValidator), 'TIMES') .appendField(Blockly.Msg.CONTROLS_REPEAT_TITLE_TIMES); this.appendStatementInput('DO') .appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO); this.setPreviousStatement(true); this.setNextStatement(true); this.setTooltip(Blockly.Msg.CONTROLS_REPEAT_TOOLTIP); } }; Blockly.Blocks['controls_repeat_ext'] = { // Repeat n times (external number). init: function() { this.setHelpUrl(Blockly.Msg.CONTROLS_REPEAT_HELPURL); this.setColour(120); this.interpolateMsg(Blockly.Msg.CONTROLS_REPEAT_TITLE, ['TIMES', 'Number', Blockly.ALIGN_RIGHT], Blockly.ALIGN_RIGHT); this.appendStatementInput('DO') .appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO); this.setPreviousStatement(true); this.setNextStatement(true); this.setInputsInline(true); this.setTooltip(Blockly.Msg.CONTROLS_REPEAT_TOOLTIP); } }; Blockly.Blocks['controls_whileUntil'] = { // Do while/until loop. init: function() { var OPERATORS = [[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_WHILE, 'WHILE'], [Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_UNTIL, 'UNTIL']]; this.setHelpUrl(Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL); this.setColour(120); this.appendValueInput('BOOL') .setCheck('Boolean') .appendField(new Blockly.FieldDropdown(OPERATORS), 'MODE'); this.appendStatementInput('DO') .appendField(Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO); this.setPreviousStatement(true); this.setNextStatement(true); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { var op = thisBlock.getFieldValue('MODE'); var TOOLTIPS = { WHILE: Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_WHILE, UNTIL: Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL }; return TOOLTIPS[op]; }); } }; Blockly.Blocks['controls_for'] = { // For loop. init: function() { this.setHelpUrl(Blockly.Msg.CONTROLS_FOR_HELPURL); this.setColour(120); this.appendDummyInput() .appendField(Blockly.Msg.CONTROLS_FOR_INPUT_WITH) .appendField(new Blockly.FieldVariable(null), 'VAR'); this.interpolateMsg(Blockly.Msg.CONTROLS_FOR_INPUT_FROM_TO_BY, ['FROM', 'Number', Blockly.ALIGN_RIGHT], ['TO', 'Number', Blockly.ALIGN_RIGHT], ['BY', 'Number', Blockly.ALIGN_RIGHT], Blockly.ALIGN_RIGHT); this.appendStatementInput('DO') .appendField(Blockly.Msg.CONTROLS_FOR_INPUT_DO); this.setPreviousStatement(true); this.setNextStatement(true); this.setInputsInline(true); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { return Blockly.Msg.CONTROLS_FOR_TOOLTIP.replace('%1', thisBlock.getFieldValue('VAR')); }); }, getVars: function() { return [this.getFieldValue('VAR')]; }, renameVar: function(oldName, newName) { if (Blockly.Names.equals(oldName, this.getFieldValue('VAR'))) { this.setFieldValue(newName, 'VAR'); } }, customContextMenu: function(options) { var option = {enabled: true}; var name = this.getFieldValue('VAR'); option.text = Blockly.Msg.VARIABLES_SET_CREATE_GET.replace('%1', name); var xmlField = goog.dom.createDom('field', null, name); xmlField.setAttribute('name', 'VAR'); var xmlBlock = goog.dom.createDom('block', null, xmlField); xmlBlock.setAttribute('type', 'variables_get'); option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock); options.push(option); } }; Blockly.Blocks['controls_forEach'] = { // For each loop. init: function() { this.setHelpUrl(Blockly.Msg.CONTROLS_FOREACH_HELPURL); this.setColour(120); this.appendValueInput('LIST') .setCheck('Array') .appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_ITEM) .appendField(new Blockly.FieldVariable(null), 'VAR') .appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_INLIST); if (Blockly.Msg.CONTROLS_FOREACH_INPUT_INLIST_TAIL) { this.appendDummyInput() .appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_INLIST_TAIL); this.setInputsInline(true); } this.appendStatementInput('DO') .appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_DO); this.setPreviousStatement(true); this.setNextStatement(true); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { return Blockly.Msg.CONTROLS_FOREACH_TOOLTIP.replace('%1', thisBlock.getFieldValue('VAR')); }); }, getVars: function() { return [this.getFieldValue('VAR')]; }, renameVar: function(oldName, newName) { if (Blockly.Names.equals(oldName, this.getFieldValue('VAR'))) { this.setFieldValue(newName, 'VAR'); } }, customContextMenu: Blockly.Blocks['controls_for'].customContextMenu }; Blockly.Blocks['controls_flow_statements'] = { // Flow statements: continue, break. init: function() { var OPERATORS = [[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK, 'BREAK'], [Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE, 'CONTINUE']]; this.setHelpUrl(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_HELPURL); this.setColour(120); this.appendDummyInput() .appendField(new Blockly.FieldDropdown(OPERATORS), 'FLOW'); this.setPreviousStatement(true); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { var op = thisBlock.getFieldValue('FLOW'); var TOOLTIPS = { BREAK: Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK, CONTINUE: Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE }; return thisBlock.TOOLTIPS[op]; }); }, onchange: function() { if (!this.workspace) { // Block has been deleted. return; } var legal = false; // Is the block nested in a control statement? var block = this; do { if (block.type == 'controls_repeat' || block.type == 'controls_repeat_ext' || block.type == 'controls_forEach' || block.type == 'controls_for' || block.type == 'controls_whileUntil') { legal = true; break; } block = block.getSurroundParent(); } while (block); if (legal) { this.setWarningText(null); } else { this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING); } } }; ================================================ FILE: extern/blockly/blocks/math.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Math blocks for Blockly. * @author q.neutron@gmail.com (Quynh Neutron) */ 'use strict'; goog.provide('Blockly.Blocks.math'); goog.require('Blockly.Blocks'); Blockly.Blocks['math_number'] = { // Numeric value. init: function() { this.setHelpUrl(Blockly.Msg.MATH_NUMBER_HELPURL); this.setColour(230); this.appendDummyInput() .appendField(new Blockly.FieldTextInput('0', Blockly.FieldTextInput.numberValidator), 'NUM'); this.setOutput(true, 'Number'); this.setTooltip(Blockly.Msg.MATH_NUMBER_TOOLTIP); } }; Blockly.Blocks['math_arithmetic'] = { // Basic arithmetic operator. init: function() { var OPERATORS = [[Blockly.Msg.MATH_ADDITION_SYMBOL, 'ADD'], [Blockly.Msg.MATH_SUBTRACTION_SYMBOL, 'MINUS'], [Blockly.Msg.MATH_MULTIPLICATION_SYMBOL, 'MULTIPLY'], [Blockly.Msg.MATH_DIVISION_SYMBOL, 'DIVIDE'], [Blockly.Msg.MATH_POWER_SYMBOL, 'POWER']]; this.setHelpUrl(Blockly.Msg.MATH_ARITHMETIC_HELPURL); this.setColour(230); this.setOutput(true, 'Number'); this.appendValueInput('A') .setCheck('Number'); this.appendValueInput('B') .setCheck('Number') .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP'); this.setInputsInline(true); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { var mode = thisBlock.getFieldValue('OP'); var TOOLTIPS = { ADD: Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD, MINUS: Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS, MULTIPLY: Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY, DIVIDE: Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE, POWER: Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER }; return TOOLTIPS[mode]; }); } }; Blockly.Blocks['math_single'] = { // Advanced math operators with single operand. init: function() { var OPERATORS = [[Blockly.Msg.MATH_SINGLE_OP_ROOT, 'ROOT'], [Blockly.Msg.MATH_SINGLE_OP_ABSOLUTE, 'ABS'], ['-', 'NEG'], ['ln', 'LN'], ['log10', 'LOG10'], ['e^', 'EXP'], ['10^', 'POW10']]; this.setHelpUrl(Blockly.Msg.MATH_SINGLE_HELPURL); this.setColour(230); this.setOutput(true, 'Number'); this.interpolateMsg('%1 %2', ['OP', new Blockly.FieldDropdown(OPERATORS)], ['NUM', 'Number', Blockly.ALIGN_RIGHT], Blockly.ALIGN_RIGHT); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { var mode = thisBlock.getFieldValue('OP'); var TOOLTIPS = { ROOT: Blockly.Msg.MATH_SINGLE_TOOLTIP_ROOT, ABS: Blockly.Msg.MATH_SINGLE_TOOLTIP_ABS, NEG: Blockly.Msg.MATH_SINGLE_TOOLTIP_NEG, LN: Blockly.Msg.MATH_SINGLE_TOOLTIP_LN, LOG10: Blockly.Msg.MATH_SINGLE_TOOLTIP_LOG10, EXP: Blockly.Msg.MATH_SINGLE_TOOLTIP_EXP, POW10: Blockly.Msg.MATH_SINGLE_TOOLTIP_POW10 }; return TOOLTIPS[mode]; }); } }; Blockly.Blocks['math_trig'] = { // Trigonometry operators. init: function() { var OPERATORS = [[Blockly.Msg.MATH_TRIG_SIN, 'SIN'], [Blockly.Msg.MATH_TRIG_COS, 'COS'], [Blockly.Msg.MATH_TRIG_TAN, 'TAN'], [Blockly.Msg.MATH_TRIG_ASIN, 'ASIN'], [Blockly.Msg.MATH_TRIG_ACOS, 'ACOS'], [Blockly.Msg.MATH_TRIG_ATAN, 'ATAN']]; this.setHelpUrl(Blockly.Msg.MATH_TRIG_HELPURL); this.setColour(230); this.setOutput(true, 'Number'); this.appendValueInput('NUM') .setCheck('Number') .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP'); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { var mode = thisBlock.getFieldValue('OP'); var TOOLTIPS = { SIN: Blockly.Msg.MATH_TRIG_TOOLTIP_SIN, COS: Blockly.Msg.MATH_TRIG_TOOLTIP_COS, TAN: Blockly.Msg.MATH_TRIG_TOOLTIP_TAN, ASIN: Blockly.Msg.MATH_TRIG_TOOLTIP_ASIN, ACOS: Blockly.Msg.MATH_TRIG_TOOLTIP_ACOS, ATAN: Blockly.Msg.MATH_TRIG_TOOLTIP_ATAN }; return TOOLTIPS[mode]; }); } }; Blockly.Blocks['math_constant'] = { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. init: function() { var CONSTANTS = [['\u03c0', 'PI'], ['e', 'E'], ['\u03c6', 'GOLDEN_RATIO'], ['sqrt(2)', 'SQRT2'], ['sqrt(\u00bd)', 'SQRT1_2'], ['\u221e', 'INFINITY']]; this.setHelpUrl(Blockly.Msg.MATH_CONSTANT_HELPURL); this.setColour(230); this.setOutput(true, 'Number'); this.appendDummyInput() .appendField(new Blockly.FieldDropdown(CONSTANTS), 'CONSTANT'); this.setTooltip(Blockly.Msg.MATH_CONSTANT_TOOLTIP); } }; Blockly.Blocks['math_number_property'] = { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. init: function() { var PROPERTIES = [[Blockly.Msg.MATH_IS_EVEN, 'EVEN'], [Blockly.Msg.MATH_IS_ODD, 'ODD'], [Blockly.Msg.MATH_IS_PRIME, 'PRIME'], [Blockly.Msg.MATH_IS_WHOLE, 'WHOLE'], [Blockly.Msg.MATH_IS_POSITIVE, 'POSITIVE'], [Blockly.Msg.MATH_IS_NEGATIVE, 'NEGATIVE'], [Blockly.Msg.MATH_IS_DIVISIBLE_BY, 'DIVISIBLE_BY']]; this.setColour(230); this.appendValueInput('NUMBER_TO_CHECK') .setCheck('Number'); var dropdown = new Blockly.FieldDropdown(PROPERTIES, function(option) { var divisorInput = (option == 'DIVISIBLE_BY'); this.sourceBlock_.updateShape(divisorInput); }); this.appendDummyInput() .appendField(dropdown, 'PROPERTY'); this.setInputsInline(true); this.setOutput(true, 'Boolean'); this.setTooltip(Blockly.Msg.MATH_IS_TOOLTIP); }, mutationToDom: function() { // Save whether the 'divisorInput' should be true of false (present or not). var container = document.createElement('mutation'); var divisorInput = (this.getFieldValue('PROPERTY') == 'DIVISIBLE_BY'); container.setAttribute('divisor_input', divisorInput); return container; }, domToMutation: function(xmlElement) { // Restore the 'divisorInput'. var divisorInput = (xmlElement.getAttribute('divisor_input') == 'true'); this.updateShape(divisorInput); }, updateShape: function(divisorInput) { // Add or remove a Value Input. var inputExists = this.getInput('DIVISOR'); if (divisorInput) { if (!inputExists) { this.appendValueInput('DIVISOR') .setCheck('Number'); } } else if (inputExists) { this.removeInput('DIVISOR'); } } }; Blockly.Blocks['math_change'] = { // Add to a variable in place. init: function() { this.setHelpUrl(Blockly.Msg.MATH_CHANGE_HELPURL); this.setColour(230); this.interpolateMsg( // TODO: Combine these messages instead of using concatenation. Blockly.Msg.MATH_CHANGE_TITLE_CHANGE + ' %1 ' + Blockly.Msg.MATH_CHANGE_INPUT_BY + ' %2', ['VAR', new Blockly.FieldVariable(Blockly.Msg.MATH_CHANGE_TITLE_ITEM)], ['DELTA', 'Number', Blockly.ALIGN_RIGHT], Blockly.ALIGN_RIGHT); this.setPreviousStatement(true); this.setNextStatement(true); // Assign 'this' to a variable for use in the tooltip closure below. var thisBlock = this; this.setTooltip(function() { return Blockly.Msg.MATH_CHANGE_TOOLTIP.replace('%1', thisBlock.getFieldValue('VAR')); }); }, getVars: function() { return [this.getFieldValue('VAR')]; }, renameVar: function(oldName, newName) { if (Blockly.Names.equals(oldName, this.getFieldValue('VAR'))) { this.setFieldValue(newName, 'VAR'); } } }; Blockly.Blocks['math_round'] = { // Rounding functions. init: function() { var OPERATORS = [[Blockly.Msg.MATH_ROUND_OPERATOR_ROUND, 'ROUND'], [Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDUP, 'ROUNDUP'], [Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDDOWN, 'ROUNDDOWN']]; this.setHelpUrl(Blockly.Msg.MATH_ROUND_HELPURL); this.setColour(230); this.setOutput(true, 'Number'); this.appendValueInput('NUM') .setCheck('Number') .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP'); this.setTooltip(Blockly.Msg.MATH_ROUND_TOOLTIP); } }; Blockly.Blocks['math_on_list'] = { // Evaluate a list of numbers to return sum, average, min, max, etc. // Some functions also work on text (min, max, mode, median). init: function() { var OPERATORS = [[Blockly.Msg.MATH_ONLIST_OPERATOR_SUM, 'SUM'], [Blockly.Msg.MATH_ONLIST_OPERATOR_MIN, 'MIN'], [Blockly.Msg.MATH_ONLIST_OPERATOR_MAX, 'MAX'], [Blockly.Msg.MATH_ONLIST_OPERATOR_AVERAGE, 'AVERAGE'], [Blockly.Msg.MATH_ONLIST_OPERATOR_MEDIAN, 'MEDIAN'], [Blockly.Msg.MATH_ONLIST_OPERATOR_MODE, 'MODE'], [Blockly.Msg.MATH_ONLIST_OPERATOR_STD_DEV, 'STD_DEV'], [Blockly.Msg.MATH_ONLIST_OPERATOR_RANDOM, 'RANDOM']]; // Assign 'this' to a variable for use in the closure below. var thisBlock = this; this.setHelpUrl(Blockly.Msg.MATH_ONLIST_HELPURL); this.setColour(230); this.setOutput(true, 'Number'); var dropdown = new Blockly.FieldDropdown(OPERATORS, function(newOp) { if (newOp == 'MODE') { thisBlock.outputConnection.setCheck('Array'); } else { thisBlock.outputConnection.setCheck('Number'); } }); this.appendValueInput('LIST') .setCheck('Array') .appendField(dropdown, 'OP'); this.setTooltip(function() { var mode = thisBlock.getFieldValue('OP'); var TOOLTIPS = { SUM: Blockly.Msg.MATH_ONLIST_TOOLTIP_SUM, MIN: Blockly.Msg.MATH_ONLIST_TOOLTIP_MIN, MAX: Blockly.Msg.MATH_ONLIST_TOOLTIP_MAX, AVERAGE: Blockly.Msg.MATH_ONLIST_TOOLTIP_AVERAGE, MEDIAN: Blockly.Msg.MATH_ONLIST_TOOLTIP_MEDIAN, MODE: Blockly.Msg.MATH_ONLIST_TOOLTIP_MODE, STD_DEV: Blockly.Msg.MATH_ONLIST_TOOLTIP_STD_DEV, RANDOM: Blockly.Msg.MATH_ONLIST_TOOLTIP_RANDOM }; return TOOLTIPS[mode]; }); } }; Blockly.Blocks['math_modulo'] = { // Remainder of a division. init: function() { this.setHelpUrl(Blockly.Msg.MATH_MODULO_HELPURL); this.setColour(230); this.setOutput(true, 'Number'); this.interpolateMsg(Blockly.Msg.MATH_MODULO_TITLE, ['DIVIDEND', 'Number', Blockly.ALIGN_RIGHT], ['DIVISOR', 'Number', Blockly.ALIGN_RIGHT], Blockly.ALIGN_RIGHT); this.setInputsInline(true); this.setTooltip(Blockly.Msg.MATH_MODULO_TOOLTIP); } }; Blockly.Blocks['math_constrain'] = { // Constrain a number between two limits. init: function() { this.setHelpUrl(Blockly.Msg.MATH_CONSTRAIN_HELPURL); this.setColour(230); this.setOutput(true, 'Number'); this.interpolateMsg(Blockly.Msg.MATH_CONSTRAIN_TITLE, ['VALUE', 'Number', Blockly.ALIGN_RIGHT], ['LOW', 'Number', Blockly.ALIGN_RIGHT], ['HIGH', 'Number', Blockly.ALIGN_RIGHT], Blockly.ALIGN_RIGHT) this.setInputsInline(true); this.setTooltip(Blockly.Msg.MATH_CONSTRAIN_TOOLTIP); } }; Blockly.Blocks['math_random_int'] = { // Random integer between [X] and [Y]. init: function() { this.setHelpUrl(Blockly.Msg.MATH_RANDOM_INT_HELPURL); this.setColour(230); this.setOutput(true, 'Number'); this.interpolateMsg(Blockly.Msg.MATH_RANDOM_INT_TITLE, ['FROM', 'Number', Blockly.ALIGN_RIGHT], ['TO', 'Number', Blockly.ALIGN_RIGHT], Blockly.ALIGN_RIGHT); this.setInputsInline(true); this.setTooltip(Blockly.Msg.MATH_RANDOM_INT_TOOLTIP); } }; Blockly.Blocks['math_random_float'] = { // Random fraction between 0 and 1. init: function() { this.setHelpUrl(Blockly.Msg.MATH_RANDOM_FLOAT_HELPURL); this.setColour(230); this.setOutput(true, 'Number'); this.appendDummyInput() .appendField(Blockly.Msg.MATH_RANDOM_FLOAT_TITLE_RANDOM); this.setTooltip(Blockly.Msg.MATH_RANDOM_FLOAT_TOOLTIP); } }; ================================================ FILE: extern/blockly/blocks/procedures.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Procedure blocks for Blockly. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Blocks.procedures'); goog.require('Blockly.Blocks'); Blockly.Blocks['procedures_defnoreturn'] = { // Define a procedure with no return value. init: function() { this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL); this.setColour(290); var name = Blockly.Procedures.findLegalName( Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE, this); this.appendDummyInput() .appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE) .appendField(new Blockly.FieldTextInput(name, Blockly.Procedures.rename), 'NAME') .appendField('', 'PARAMS'); this.appendStatementInput('STACK') .appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO); this.setMutator(new Blockly.Mutator(['procedures_mutatorarg'])); this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP); this.arguments_ = []; }, updateParams_: function() { // Check for duplicated arguments. var badArg = false; var hash = {}; for (var x = 0; x < this.arguments_.length; x++) { if (hash['arg_' + this.arguments_[x].toLowerCase()]) { badArg = true; break; } hash['arg_' + this.arguments_[x].toLowerCase()] = true; } if (badArg) { this.setWarningText(Blockly.Msg.PROCEDURES_DEF_DUPLICATE_WARNING); } else { this.setWarningText(null); } // Merge the arguments into a human-readable list. var paramString = ''; if (this.arguments_.length) { paramString = Blockly.Msg.PROCEDURES_BEFORE_PARAMS + ' ' + this.arguments_.join(', '); } this.setFieldValue(paramString, 'PARAMS'); }, mutationToDom: function() { var container = document.createElement('mutation'); for (var x = 0; x < this.arguments_.length; x++) { var parameter = document.createElement('arg'); parameter.setAttribute('name', this.arguments_[x]); container.appendChild(parameter); } return container; }, domToMutation: function(xmlElement) { this.arguments_ = []; for (var x = 0, childNode; childNode = xmlElement.childNodes[x]; x++) { if (childNode.nodeName.toLowerCase() == 'arg') { this.arguments_.push(childNode.getAttribute('name')); } } this.updateParams_(); }, decompose: function(workspace) { var containerBlock = Blockly.Block.obtain(workspace, 'procedures_mutatorcontainer'); containerBlock.initSvg(); var connection = containerBlock.getInput('STACK').connection; for (var x = 0; x < this.arguments_.length; x++) { var paramBlock = Blockly.Block.obtain(workspace, 'procedures_mutatorarg'); paramBlock.initSvg(); paramBlock.setFieldValue(this.arguments_[x], 'NAME'); // Store the old location. paramBlock.oldLocation = x; connection.connect(paramBlock.previousConnection); connection = paramBlock.nextConnection; } // Initialize procedure's callers with blank IDs. Blockly.Procedures.mutateCallers(this.getFieldValue('NAME'), this.workspace, this.arguments_, null); return containerBlock; }, compose: function(containerBlock) { this.arguments_ = []; this.paramIds_ = []; var paramBlock = containerBlock.getInputTargetBlock('STACK'); while (paramBlock) { this.arguments_.push(paramBlock.getFieldValue('NAME')); this.paramIds_.push(paramBlock.id); paramBlock = paramBlock.nextConnection && paramBlock.nextConnection.targetBlock(); } this.updateParams_(); Blockly.Procedures.mutateCallers(this.getFieldValue('NAME'), this.workspace, this.arguments_, this.paramIds_); }, dispose: function() { // Dispose of any callers. var name = this.getFieldValue('NAME'); Blockly.Procedures.disposeCallers(name, this.workspace); // Call parent's destructor. Blockly.Block.prototype.dispose.apply(this, arguments); }, getProcedureDef: function() { // Return the name of the defined procedure, // a list of all its arguments, // and that it DOES NOT have a return value. return [this.getFieldValue('NAME'), this.arguments_, false]; }, getVars: function() { return this.arguments_; }, renameVar: function(oldName, newName) { var change = false; for (var x = 0; x < this.arguments_.length; x++) { if (Blockly.Names.equals(oldName, this.arguments_[x])) { this.arguments_[x] = newName; change = true; } } if (change) { this.updateParams_(); // Update the mutator's variables if the mutator is open. if (this.mutator.isVisible_()) { var blocks = this.mutator.workspace_.getAllBlocks(); for (var x = 0, block; block = blocks[x]; x++) { if (block.type == 'procedures_mutatorarg' && Blockly.Names.equals(oldName, block.getFieldValue('NAME'))) { block.setFieldValue(newName, 'NAME'); } } } } }, customContextMenu: function(options) { // Add option to create caller. var option = {enabled: true}; var name = this.getFieldValue('NAME'); option.text = Blockly.Msg.PROCEDURES_CREATE_DO.replace('%1', name); var xmlMutation = goog.dom.createDom('mutation'); xmlMutation.setAttribute('name', name); for (var x = 0; x < this.arguments_.length; x++) { var xmlArg = goog.dom.createDom('arg'); xmlArg.setAttribute('name', this.arguments_[x]); xmlMutation.appendChild(xmlArg); } var xmlBlock = goog.dom.createDom('block', null, xmlMutation); xmlBlock.setAttribute('type', this.callType_); option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock); options.push(option); // Add options to create getters for each parameter. for (var x = 0; x < this.arguments_.length; x++) { var option = {enabled: true}; var name = this.arguments_[x]; option.text = Blockly.Msg.VARIABLES_SET_CREATE_GET.replace('%1', name); var xmlField = goog.dom.createDom('field', null, name); xmlField.setAttribute('name', 'VAR'); var xmlBlock = goog.dom.createDom('block', null, xmlField); xmlBlock.setAttribute('type', 'variables_get'); option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock); options.push(option); } }, callType_: 'procedures_callnoreturn' }; Blockly.Blocks['procedures_defreturn'] = { // Define a procedure with a return value. init: function() { this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFRETURN_HELPURL); this.setColour(290); var name = Blockly.Procedures.findLegalName( Blockly.Msg.PROCEDURES_DEFRETURN_PROCEDURE, this); this.appendDummyInput() .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_TITLE) .appendField(new Blockly.FieldTextInput(name, Blockly.Procedures.rename), 'NAME') .appendField('', 'PARAMS'); this.appendStatementInput('STACK') .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_DO); this.appendValueInput('RETURN') .setAlign(Blockly.ALIGN_RIGHT) .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN); this.setMutator(new Blockly.Mutator(['procedures_mutatorarg'])); this.setTooltip(Blockly.Msg.PROCEDURES_DEFRETURN_TOOLTIP); this.arguments_ = []; }, updateParams_: Blockly.Blocks['procedures_defnoreturn'].updateParams_, mutationToDom: Blockly.Blocks['procedures_defnoreturn'].mutationToDom, domToMutation: Blockly.Blocks['procedures_defnoreturn'].domToMutation, decompose: Blockly.Blocks['procedures_defnoreturn'].decompose, compose: Blockly.Blocks['procedures_defnoreturn'].compose, dispose: Blockly.Blocks['procedures_defnoreturn'].dispose, getProcedureDef: function() { // Return the name of the defined procedure, // a list of all its arguments, // and that it DOES have a return value. return [this.getFieldValue('NAME'), this.arguments_, true]; }, getVars: Blockly.Blocks['procedures_defnoreturn'].getVars, renameVar: Blockly.Blocks['procedures_defnoreturn'].renameVar, customContextMenu: Blockly.Blocks['procedures_defnoreturn'].customContextMenu, callType_: 'procedures_callreturn' }; Blockly.Blocks['procedures_mutatorcontainer'] = { // Procedure container (for mutator dialog). init: function() { this.setColour(290); this.appendDummyInput() .appendField(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TITLE); this.appendStatementInput('STACK'); this.setTooltip(''); this.contextMenu = false; } }; Blockly.Blocks['procedures_mutatorarg'] = { // Procedure argument (for mutator dialog). init: function() { this.setColour(290); this.appendDummyInput() .appendField(Blockly.Msg.PROCEDURES_MUTATORARG_TITLE) .appendField(new Blockly.FieldTextInput('x', this.validator), 'NAME'); this.setPreviousStatement(true); this.setNextStatement(true); this.setTooltip(''); this.contextMenu = false; }, validator: function(newVar) { // Merge runs of whitespace. Strip leading and trailing whitespace. // Beyond this, all names are legal. newVar = newVar.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, ''); return newVar || null; } }; Blockly.Blocks['procedures_callnoreturn'] = { // Call a procedure with no return value. init: function() { this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL); this.setColour(290); this.appendDummyInput() .appendField(Blockly.Msg.PROCEDURES_CALLNORETURN_CALL) .appendField('', 'NAME'); this.setPreviousStatement(true); this.setNextStatement(true); this.setTooltip(Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP); this.arguments_ = []; this.quarkConnections_ = null; this.quarkArguments_ = null; }, getProcedureCall: function() { return this.getFieldValue('NAME'); }, renameProcedure: function(oldName, newName) { if (Blockly.Names.equals(oldName, this.getFieldValue('NAME'))) { this.setFieldValue(newName, 'NAME'); this.setTooltip( (this.outputConnection ? Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP : Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP) .replace('%1', newName)); } }, setProcedureParameters: function(paramNames, paramIds) { // Data structures for parameters on each call block: // this.arguments = ['x', 'y'] // Existing param names. // paramNames = ['x', 'y', 'z'] // New param names. // paramIds = ['piua', 'f8b_', 'oi.o'] // IDs of params (consistent for each parameter through the life of a // mutator, regardless of param renaming). // this.quarkConnections_ {piua: null, f8b_: Blockly.Connection} // Look-up of paramIds to connections plugged into the call block. // this.quarkArguments_ = ['piua', 'f8b_'] // Existing param IDs. // Note that quarkConnections_ may include IDs that no longer exist, but // which might reappear if a param is reattached in the mutator. if (!paramIds) { // Reset the quarks (a mutator is about to open). this.quarkConnections_ = {}; this.quarkArguments_ = null; return; } if (paramIds.length != paramNames.length) { throw 'Error: paramNames and paramIds must be the same length.'; } if (!this.quarkArguments_) { // Initialize tracking for this block. this.quarkConnections_ = {}; if (paramNames.join('\n') == this.arguments_.join('\n')) { // No change to the parameters, allow quarkConnections_ to be // populated with the existing connections. this.quarkArguments_ = paramIds; } else { this.quarkArguments_ = []; } } // Switch off rendering while the block is rebuilt. var savedRendered = this.rendered; this.rendered = false; // Update the quarkConnections_ with existing connections. for (var x = this.arguments_.length - 1; x >= 0; x--) { var input = this.getInput('ARG' + x); if (input) { var connection = input.connection.targetConnection; this.quarkConnections_[this.quarkArguments_[x]] = connection; // Disconnect all argument blocks and remove all inputs. this.removeInput('ARG' + x); } } // Rebuild the block's arguments. this.arguments_ = [].concat(paramNames); this.quarkArguments_ = paramIds; for (var x = 0; x < this.arguments_.length; x++) { var input = this.appendValueInput('ARG' + x) .setAlign(Blockly.ALIGN_RIGHT) .appendField(this.arguments_[x]); if (this.quarkArguments_) { // Reconnect any child blocks. var quarkName = this.quarkArguments_[x]; if (quarkName in this.quarkConnections_) { var connection = this.quarkConnections_[quarkName]; if (!connection || connection.targetConnection || connection.sourceBlock_.workspace != this.workspace) { // Block no longer exists or has been attached elsewhere. delete this.quarkConnections_[quarkName]; } else { input.connection.connect(connection); } } } } // Restore rendering and show the changes. this.rendered = savedRendered; if (this.rendered) { this.render(); } }, mutationToDom: function() { // Save the name and arguments (none of which are editable). var container = document.createElement('mutation'); container.setAttribute('name', this.getFieldValue('NAME')); for (var x = 0; x < this.arguments_.length; x++) { var parameter = document.createElement('arg'); parameter.setAttribute('name', this.arguments_[x]); container.appendChild(parameter); } return container; }, domToMutation: function(xmlElement) { // Restore the name and parameters. var name = xmlElement.getAttribute('name'); this.setFieldValue(name, 'NAME'); this.setTooltip( (this.outputConnection ? Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP : Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP).replace('%1', name)); var def = Blockly.Procedures.getDefinition(name, this.workspace); if (def && def.mutator.isVisible()) { // Initialize caller with the mutator's IDs. this.setProcedureParameters(def.arguments_, def.paramIds_); } else { this.arguments_ = []; for (var x = 0, childNode; childNode = xmlElement.childNodes[x]; x++) { if (childNode.nodeName.toLowerCase() == 'arg') { this.arguments_.push(childNode.getAttribute('name')); } } // For the second argument (paramIds) use the arguments list as a dummy // list. this.setProcedureParameters(this.arguments_, this.arguments_); } }, renameVar: function(oldName, newName) { for (var x = 0; x < this.arguments_.length; x++) { if (Blockly.Names.equals(oldName, this.arguments_[x])) { this.arguments_[x] = newName; this.getInput('ARG' + x).fieldRow[0].setText(newName); } } }, customContextMenu: function(options) { // Add option to find caller. var option = {enabled: true}; option.text = Blockly.Msg.PROCEDURES_HIGHLIGHT_DEF; var name = this.getFieldValue('NAME'); var workspace = this.workspace; option.callback = function() { var def = Blockly.Procedures.getDefinition(name, workspace); def && def.select(); }; options.push(option); } }; Blockly.Blocks['procedures_callreturn'] = { // Call a procedure with a return value. init: function() { this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL); this.setColour(290); this.appendDummyInput() .appendField(Blockly.Msg.PROCEDURES_CALLRETURN_CALL) .appendField('', 'NAME'); this.setOutput(true); this.setTooltip(Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP); this.arguments_ = []; this.quarkConnections_ = null; this.quarkArguments_ = null; }, getProcedureCall: Blockly.Blocks['procedures_callnoreturn'].getProcedureCall, renameProcedure: Blockly.Blocks['procedures_callnoreturn'].renameProcedure, setProcedureParameters: Blockly.Blocks['procedures_callnoreturn'].setProcedureParameters, mutationToDom: Blockly.Blocks['procedures_callnoreturn'].mutationToDom, domToMutation: Blockly.Blocks['procedures_callnoreturn'].domToMutation, renameVar: Blockly.Blocks['procedures_callnoreturn'].renameVar, customContextMenu: Blockly.Blocks['procedures_callnoreturn'].customContextMenu }; Blockly.Blocks['procedures_ifreturn'] = { // Conditionally return value from a procedure. init: function() { this.setHelpUrl('http://c2.com/cgi/wiki?GuardClause'); this.setColour(290); this.appendValueInput('CONDITION') .setCheck('Boolean') .appendField(Blockly.Msg.CONTROLS_IF_MSG_IF); this.appendValueInput('VALUE') .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN); this.setInputsInline(true); this.setPreviousStatement(true); this.setNextStatement(true); this.setTooltip(Blockly.Msg.PROCEDURES_IFRETURN_TOOLTIP); this.hasReturnValue_ = true; }, mutationToDom: function() { // Save whether this block has a return value. var container = document.createElement('mutation'); container.setAttribute('value', Number(this.hasReturnValue_)); return container; }, domToMutation: function(xmlElement) { // Restore whether this block has a return value. var value = xmlElement.getAttribute('value'); this.hasReturnValue_ = (value == 1); if (!this.hasReturnValue_) { this.removeInput('VALUE'); this.appendDummyInput('VALUE') .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN); } }, onchange: function() { if (!this.workspace) { // Block has been deleted. return; } var legal = false; // Is the block nested in a procedure? var block = this; do { if (block.type == 'procedures_defnoreturn' || block.type == 'procedures_defreturn') { legal = true; break; } block = block.getSurroundParent(); } while (block); if (legal) { // If needed, toggle whether this block has a return value. if (block.type == 'procedures_defnoreturn' && this.hasReturnValue_) { this.removeInput('VALUE'); this.appendDummyInput('VALUE') .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN); this.hasReturnValue_ = false; } else if (block.type == 'procedures_defreturn' && !this.hasReturnValue_) { this.removeInput('VALUE'); this.appendValueInput('VALUE') .appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN); this.hasReturnValue_ = true; } this.setWarningText(null); } else { this.setWarningText(Blockly.Msg.PROCEDURES_IFRETURN_WARNING); } } }; ================================================ FILE: extern/blockly/blocks/text.js ================================================ ================================================ FILE: extern/blockly/blocks/variables.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Variable blocks for Blockly. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Blocks.variables'); goog.require('Blockly.Blocks'); Blockly.Blocks['variables_get'] = { // Variable getter. init: function() { this.setHelpUrl(Blockly.Msg.VARIABLES_GET_HELPURL); this.setColour(330); this.appendDummyInput() .appendField(Blockly.Msg.VARIABLES_GET_TITLE) .appendField(new Blockly.FieldVariable( Blockly.Msg.VARIABLES_GET_ITEM), 'VAR') .appendField(Blockly.Msg.VARIABLES_GET_TAIL); this.setOutput(true); this.setTooltip(Blockly.Msg.VARIABLES_GET_TOOLTIP); this.contextMenuMsg_ = Blockly.Msg.VARIABLES_GET_CREATE_SET; this.contextMenuType_ = 'variables_set'; }, getVars: function() { return [this.getFieldValue('VAR')]; }, renameVar: function(oldName, newName) { if (Blockly.Names.equals(oldName, this.getFieldValue('VAR'))) { this.setFieldValue(newName, 'VAR'); } }, customContextMenu: function(options) { var option = {enabled: true}; var name = this.getFieldValue('VAR'); option.text = this.contextMenuMsg_.replace('%1', name); var xmlField = goog.dom.createDom('field', null, name); xmlField.setAttribute('name', 'VAR'); var xmlBlock = goog.dom.createDom('block', null, xmlField); xmlBlock.setAttribute('type', this.contextMenuType_); option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock); options.push(option); } }; Blockly.Blocks['variables_set'] = { // Variable setter. init: function() { this.setHelpUrl(Blockly.Msg.VARIABLES_SET_HELPURL); this.setColour(330); this.interpolateMsg( // TODO: Combine these messages instead of using concatenation. Blockly.Msg.VARIABLES_SET_TITLE + ' %1 ' + Blockly.Msg.VARIABLES_SET_TAIL + ' %2', ['VAR', new Blockly.FieldVariable(Blockly.Msg.VARIABLES_SET_ITEM)], ['VALUE', null, Blockly.ALIGN_RIGHT], Blockly.ALIGN_RIGHT); this.setPreviousStatement(true); this.setNextStatement(true); this.setTooltip(Blockly.Msg.VARIABLES_SET_TOOLTIP); this.contextMenuMsg_ = Blockly.Msg.VARIABLES_SET_CREATE_GET; this.contextMenuType_ = 'variables_get'; }, getVars: function() { return [this.getFieldValue('VAR')]; }, renameVar: function(oldName, newName) { if (Blockly.Names.equals(oldName, this.getFieldValue('VAR'))) { this.setFieldValue(newName, 'VAR'); } }, customContextMenu: Blockly.Blocks['variables_get'].customContextMenu }; ================================================ FILE: extern/blockly/blocks_compressed.js ================================================ // Do not edit this file; automatically generated by build.py. "use strict"; // Copyright 2012 Google Inc. Apache License 2.0 Blockly.Blocks.colour={};Blockly.Blocks.colour_picker={init:function(){this.setHelpUrl(Blockly.Msg.COLOUR_PICKER_HELPURL);this.setColour(20);this.appendDummyInput().appendField(new Blockly.FieldColour("#ff0000"),"COLOUR");this.setOutput(!0,"Colour");this.setTooltip(Blockly.Msg.COLOUR_PICKER_TOOLTIP)}}; Blockly.Blocks.colour_random={init:function(){this.setHelpUrl(Blockly.Msg.COLOUR_RANDOM_HELPURL);this.setColour(20);this.appendDummyInput().appendField(Blockly.Msg.COLOUR_RANDOM_TITLE);this.setOutput(!0,"Colour");this.setTooltip(Blockly.Msg.COLOUR_RANDOM_TOOLTIP)}}; Blockly.Blocks.colour_rgb={init:function(){this.setHelpUrl(Blockly.Msg.COLOUR_RGB_HELPURL);this.setColour(20);this.appendValueInput("RED").setCheck("Number").setAlign(Blockly.ALIGN_RIGHT).appendField(Blockly.Msg.COLOUR_RGB_TITLE).appendField(Blockly.Msg.COLOUR_RGB_RED);this.appendValueInput("GREEN").setCheck("Number").setAlign(Blockly.ALIGN_RIGHT).appendField(Blockly.Msg.COLOUR_RGB_GREEN);this.appendValueInput("BLUE").setCheck("Number").setAlign(Blockly.ALIGN_RIGHT).appendField(Blockly.Msg.COLOUR_RGB_BLUE); this.setOutput(!0,"Colour");this.setTooltip(Blockly.Msg.COLOUR_RGB_TOOLTIP)}}; Blockly.Blocks.colour_blend={init:function(){this.setHelpUrl(Blockly.Msg.COLOUR_BLEND_HELPURL);this.setColour(20);this.appendValueInput("COLOUR1").setCheck("Colour").setAlign(Blockly.ALIGN_RIGHT).appendField(Blockly.Msg.COLOUR_BLEND_TITLE).appendField(Blockly.Msg.COLOUR_BLEND_COLOUR1);this.appendValueInput("COLOUR2").setCheck("Colour").setAlign(Blockly.ALIGN_RIGHT).appendField(Blockly.Msg.COLOUR_BLEND_COLOUR2);this.appendValueInput("RATIO").setCheck("Number").setAlign(Blockly.ALIGN_RIGHT).appendField(Blockly.Msg.COLOUR_BLEND_RATIO);this.setOutput(!0, "Colour");this.setTooltip(Blockly.Msg.COLOUR_BLEND_TOOLTIP)}};Blockly.Blocks.lists={};Blockly.Blocks.lists_create_empty={init:function(){this.setHelpUrl(Blockly.Msg.LISTS_CREATE_EMPTY_HELPURL);this.setColour(260);this.setOutput(!0,"Array");this.appendDummyInput().appendField(Blockly.Msg.LISTS_CREATE_EMPTY_TITLE);this.setTooltip(Blockly.Msg.LISTS_CREATE_EMPTY_TOOLTIP)}}; Blockly.Blocks.lists_create_with={init:function(){this.setColour(260);this.appendValueInput("ADD0").appendField(Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH);this.appendValueInput("ADD1");this.appendValueInput("ADD2");this.setOutput(!0,"Array");this.setMutator(new Blockly.Mutator(["lists_create_with_item"]));this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_TOOLTIP);this.itemCount_=3},mutationToDom:function(a){a=document.createElement("mutation");a.setAttribute("items",this.itemCount_);return a},domToMutation:function(a){for(var b= 0;b","LT"],["\u2265","LTE"],["<","GT"],["\u2264","GTE"]]:[["=","EQ"],["\u2260","NEQ"],["<","LT"],["\u2264","LTE"],[">","GT"],["\u2265","GTE"]];this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL);this.setColour(210);this.setOutput(!0,"Boolean");this.appendValueInput("A");this.appendValueInput("B").appendField(new Blockly.FieldDropdown(a),"OP");this.setInputsInline(!0);var b=this;this.setTooltip(function(){var a= b.getFieldValue("OP");return{EQ:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ,NEQ:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ,LT:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT,LTE:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE,GT:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT,GTE:Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE}[a]})}}; Blockly.Blocks.logic_operation={init:function(){var a=[[Blockly.Msg.LOGIC_OPERATION_AND,"AND"],[Blockly.Msg.LOGIC_OPERATION_OR,"OR"]];this.setHelpUrl(Blockly.Msg.LOGIC_OPERATION_HELPURL);this.setColour(210);this.setOutput(!0,"Boolean");this.appendValueInput("A").setCheck("Boolean");this.appendValueInput("B").setCheck("Boolean").appendField(new Blockly.FieldDropdown(a),"OP");this.setInputsInline(!0);var b=this;this.setTooltip(function(){var a=b.getFieldValue("OP");return{AND:Blockly.Msg.LOGIC_OPERATION_TOOLTIP_AND, OR:Blockly.Msg.LOGIC_OPERATION_TOOLTIP_OR}[a]})}};Blockly.Blocks.logic_negate={init:function(){this.setHelpUrl(Blockly.Msg.LOGIC_NEGATE_HELPURL);this.setColour(210);this.setOutput(!0,"Boolean");this.interpolateMsg(Blockly.Msg.LOGIC_NEGATE_TITLE,["BOOL","Boolean",Blockly.ALIGN_RIGHT],Blockly.ALIGN_RIGHT);this.setTooltip(Blockly.Msg.LOGIC_NEGATE_TOOLTIP)}}; Blockly.Blocks.logic_boolean={init:function(){var a=[[Blockly.Msg.LOGIC_BOOLEAN_TRUE,"TRUE"],[Blockly.Msg.LOGIC_BOOLEAN_FALSE,"FALSE"]];this.setHelpUrl(Blockly.Msg.LOGIC_BOOLEAN_HELPURL);this.setColour(210);this.setOutput(!0,"Boolean");this.appendDummyInput().appendField(new Blockly.FieldDropdown(a),"BOOL");this.setTooltip(Blockly.Msg.LOGIC_BOOLEAN_TOOLTIP)}}; Blockly.Blocks.logic_null={init:function(){this.setHelpUrl(Blockly.Msg.LOGIC_NULL_HELPURL);this.setColour(210);this.setOutput(!0);this.appendDummyInput().appendField(Blockly.Msg.LOGIC_NULL);this.setTooltip(Blockly.Msg.LOGIC_NULL_TOOLTIP)}}; Blockly.Blocks.logic_ternary={init:function(){this.setHelpUrl(Blockly.Msg.LOGIC_TERNARY_HELPURL);this.setColour(210);this.appendValueInput("IF").setCheck("Boolean").appendField(Blockly.Msg.LOGIC_TERNARY_CONDITION);this.appendValueInput("THEN").appendField(Blockly.Msg.LOGIC_TERNARY_IF_TRUE);this.appendValueInput("ELSE").appendField(Blockly.Msg.LOGIC_TERNARY_IF_FALSE);this.setOutput(!0);this.setTooltip(Blockly.Msg.LOGIC_TERNARY_TOOLTIP)}};Blockly.Blocks.loops={}; Blockly.Blocks.controls_repeat={init:function(){this.setHelpUrl(Blockly.Msg.CONTROLS_REPEAT_HELPURL);this.setColour(120);this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_REPEAT_TITLE_REPEAT).appendField(new Blockly.FieldTextInput("10",Blockly.FieldTextInput.nonnegativeIntegerValidator),"TIMES").appendField(Blockly.Msg.CONTROLS_REPEAT_TITLE_TIMES);this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO);this.setPreviousStatement(!0);this.setNextStatement(!0);this.setTooltip(Blockly.Msg.CONTROLS_REPEAT_TOOLTIP)}}; Blockly.Blocks.controls_repeat_ext={init:function(){this.setHelpUrl(Blockly.Msg.CONTROLS_REPEAT_HELPURL);this.setColour(120);this.interpolateMsg(Blockly.Msg.CONTROLS_REPEAT_TITLE,["TIMES","Number",Blockly.ALIGN_RIGHT],Blockly.ALIGN_RIGHT);this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO);this.setPreviousStatement(!0);this.setNextStatement(!0);this.setInputsInline(!0);this.setTooltip(Blockly.Msg.CONTROLS_REPEAT_TOOLTIP)}}; Blockly.Blocks.controls_whileUntil={init:function(){var a=[[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_WHILE,"WHILE"],[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_UNTIL,"UNTIL"]];this.setHelpUrl(Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL);this.setColour(120);this.appendValueInput("BOOL").setCheck("Boolean").appendField(new Blockly.FieldDropdown(a),"MODE");this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO);this.setPreviousStatement(!0);this.setNextStatement(!0);var b=this; this.setTooltip(function(){var a=b.getFieldValue("MODE");return{WHILE:Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_WHILE,UNTIL:Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL}[a]})}}; Blockly.Blocks.controls_for={init:function(){this.setHelpUrl(Blockly.Msg.CONTROLS_FOR_HELPURL);this.setColour(120);this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_FOR_INPUT_WITH).appendField(new Blockly.FieldVariable(null),"VAR");this.interpolateMsg(Blockly.Msg.CONTROLS_FOR_INPUT_FROM_TO_BY,["FROM","Number",Blockly.ALIGN_RIGHT],["TO","Number",Blockly.ALIGN_RIGHT],["BY","Number",Blockly.ALIGN_RIGHT],Blockly.ALIGN_RIGHT);this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_FOR_INPUT_DO); this.setPreviousStatement(!0);this.setNextStatement(!0);this.setInputsInline(!0);var a=this;this.setTooltip(function(){return Blockly.Msg.CONTROLS_FOR_TOOLTIP.replace("%1",a.getFieldValue("VAR"))})},getVars:function(){return[this.getFieldValue("VAR")]},renameVar:function(a,b){Blockly.Names.equals(a,this.getFieldValue("VAR"))&&this.setFieldValue(b,"VAR")},customContextMenu:function(a){var b={enabled:!0},c=this.getFieldValue("VAR");b.text=Blockly.Msg.VARIABLES_SET_CREATE_GET.replace("%1",c);c=goog.dom.createDom("field", null,c);c.setAttribute("name","VAR");c=goog.dom.createDom("block",null,c);c.setAttribute("type","variables_get");b.callback=Blockly.ContextMenu.callbackFactory(this,c);a.push(b)}}; Blockly.Blocks.controls_forEach={init:function(){this.setHelpUrl(Blockly.Msg.CONTROLS_FOREACH_HELPURL);this.setColour(120);this.appendValueInput("LIST").setCheck("Array").appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_ITEM).appendField(new Blockly.FieldVariable(null),"VAR").appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_INLIST);Blockly.Msg.CONTROLS_FOREACH_INPUT_INLIST_TAIL&&(this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_INLIST_TAIL),this.setInputsInline(!0));this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_DO); this.setPreviousStatement(!0);this.setNextStatement(!0);var a=this;this.setTooltip(function(){return Blockly.Msg.CONTROLS_FOREACH_TOOLTIP.replace("%1",a.getFieldValue("VAR"))})},getVars:function(){return[this.getFieldValue("VAR")]},renameVar:function(a,b){Blockly.Names.equals(a,this.getFieldValue("VAR"))&&this.setFieldValue(b,"VAR")},customContextMenu:Blockly.Blocks.controls_for.customContextMenu}; Blockly.Blocks.controls_flow_statements={init:function(){var a=[[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK,"BREAK"],[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE,"CONTINUE"]];this.setHelpUrl(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_HELPURL);this.setColour(120);this.appendDummyInput().appendField(new Blockly.FieldDropdown(a),"FLOW");this.setPreviousStatement(!0);var b=this;this.setTooltip(function(){var a=b.getFieldValue("FLOW");return b.TOOLTIPS[a]})},onchange:function(){if(this.workspace){var a= !1,b=this;do{if("controls_repeat"==b.type||"controls_repeat_ext"==b.type||"controls_forEach"==b.type||"controls_for"==b.type||"controls_whileUntil"==b.type){a=!0;break}b=b.getSurroundParent()}while(b);a?this.setWarningText(null):this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING)}}};Blockly.Blocks.math={};Blockly.Blocks.math_number={init:function(){this.setHelpUrl(Blockly.Msg.MATH_NUMBER_HELPURL);this.setColour(230);this.appendDummyInput().appendField(new Blockly.FieldTextInput("0",Blockly.FieldTextInput.numberValidator),"NUM");this.setOutput(!0,"Number");this.setTooltip(Blockly.Msg.MATH_NUMBER_TOOLTIP)}}; Blockly.Blocks.math_arithmetic={init:function(){var a=[[Blockly.Msg.MATH_ADDITION_SYMBOL,"ADD"],[Blockly.Msg.MATH_SUBTRACTION_SYMBOL,"MINUS"],[Blockly.Msg.MATH_MULTIPLICATION_SYMBOL,"MULTIPLY"],[Blockly.Msg.MATH_DIVISION_SYMBOL,"DIVIDE"],[Blockly.Msg.MATH_POWER_SYMBOL,"POWER"]];this.setHelpUrl(Blockly.Msg.MATH_ARITHMETIC_HELPURL);this.setColour(230);this.setOutput(!0,"Number");this.appendValueInput("A").setCheck("Number");this.appendValueInput("B").setCheck("Number").appendField(new Blockly.FieldDropdown(a), "OP");this.setInputsInline(!0);var b=this;this.setTooltip(function(){var a=b.getFieldValue("OP");return{ADD:Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD,MINUS:Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS,MULTIPLY:Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY,DIVIDE:Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE,POWER:Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER}[a]})}}; Blockly.Blocks.math_single={init:function(){var a=[[Blockly.Msg.MATH_SINGLE_OP_ROOT,"ROOT"],[Blockly.Msg.MATH_SINGLE_OP_ABSOLUTE,"ABS"],["-","NEG"],["ln","LN"],["log10","LOG10"],["e^","EXP"],["10^","POW10"]];this.setHelpUrl(Blockly.Msg.MATH_SINGLE_HELPURL);this.setColour(230);this.setOutput(!0,"Number");this.interpolateMsg("%1 %2",["OP",new Blockly.FieldDropdown(a)],["NUM","Number",Blockly.ALIGN_RIGHT],Blockly.ALIGN_RIGHT);var b=this;this.setTooltip(function(){var a=b.getFieldValue("OP");return{ROOT:Blockly.Msg.MATH_SINGLE_TOOLTIP_ROOT, ABS:Blockly.Msg.MATH_SINGLE_TOOLTIP_ABS,NEG:Blockly.Msg.MATH_SINGLE_TOOLTIP_NEG,LN:Blockly.Msg.MATH_SINGLE_TOOLTIP_LN,LOG10:Blockly.Msg.MATH_SINGLE_TOOLTIP_LOG10,EXP:Blockly.Msg.MATH_SINGLE_TOOLTIP_EXP,POW10:Blockly.Msg.MATH_SINGLE_TOOLTIP_POW10}[a]})}}; Blockly.Blocks.math_trig={init:function(){var a=[[Blockly.Msg.MATH_TRIG_SIN,"SIN"],[Blockly.Msg.MATH_TRIG_COS,"COS"],[Blockly.Msg.MATH_TRIG_TAN,"TAN"],[Blockly.Msg.MATH_TRIG_ASIN,"ASIN"],[Blockly.Msg.MATH_TRIG_ACOS,"ACOS"],[Blockly.Msg.MATH_TRIG_ATAN,"ATAN"]];this.setHelpUrl(Blockly.Msg.MATH_TRIG_HELPURL);this.setColour(230);this.setOutput(!0,"Number");this.appendValueInput("NUM").setCheck("Number").appendField(new Blockly.FieldDropdown(a),"OP");var b=this;this.setTooltip(function(){var a=b.getFieldValue("OP"); return{SIN:Blockly.Msg.MATH_TRIG_TOOLTIP_SIN,COS:Blockly.Msg.MATH_TRIG_TOOLTIP_COS,TAN:Blockly.Msg.MATH_TRIG_TOOLTIP_TAN,ASIN:Blockly.Msg.MATH_TRIG_TOOLTIP_ASIN,ACOS:Blockly.Msg.MATH_TRIG_TOOLTIP_ACOS,ATAN:Blockly.Msg.MATH_TRIG_TOOLTIP_ATAN}[a]})}}; Blockly.Blocks.math_constant={init:function(){this.setHelpUrl(Blockly.Msg.MATH_CONSTANT_HELPURL);this.setColour(230);this.setOutput(!0,"Number");this.appendDummyInput().appendField(new Blockly.FieldDropdown([["\u03c0","PI"],["e","E"],["\u03c6","GOLDEN_RATIO"],["sqrt(2)","SQRT2"],["sqrt(\u00bd)","SQRT1_2"],["\u221e","INFINITY"]]),"CONSTANT");this.setTooltip(Blockly.Msg.MATH_CONSTANT_TOOLTIP)}}; Blockly.Blocks.math_number_property={init:function(){var a=[[Blockly.Msg.MATH_IS_EVEN,"EVEN"],[Blockly.Msg.MATH_IS_ODD,"ODD"],[Blockly.Msg.MATH_IS_PRIME,"PRIME"],[Blockly.Msg.MATH_IS_WHOLE,"WHOLE"],[Blockly.Msg.MATH_IS_POSITIVE,"POSITIVE"],[Blockly.Msg.MATH_IS_NEGATIVE,"NEGATIVE"],[Blockly.Msg.MATH_IS_DIVISIBLE_BY,"DIVISIBLE_BY"]];this.setColour(230);this.appendValueInput("NUMBER_TO_CHECK").setCheck("Number");a=new Blockly.FieldDropdown(a,function(a){this.sourceBlock_.updateShape("DIVISIBLE_BY"== a)});this.appendDummyInput().appendField(a,"PROPERTY");this.setInputsInline(!0);this.setOutput(!0,"Boolean");this.setTooltip(Blockly.Msg.MATH_IS_TOOLTIP)},mutationToDom:function(){var a=document.createElement("mutation"),b="DIVISIBLE_BY"==this.getFieldValue("PROPERTY");a.setAttribute("divisor_input",b);return a},domToMutation:function(a){a="true"==a.getAttribute("divisor_input");this.updateShape(a)},updateShape:function(a){var b=this.getInput("DIVISOR");a?b||this.appendValueInput("DIVISOR").setCheck("Number"): b&&this.removeInput("DIVISOR")}}; Blockly.Blocks.math_change={init:function(){this.setHelpUrl(Blockly.Msg.MATH_CHANGE_HELPURL);this.setColour(230);this.interpolateMsg(Blockly.Msg.MATH_CHANGE_TITLE_CHANGE+" %1 "+Blockly.Msg.MATH_CHANGE_INPUT_BY+" %2",["VAR",new Blockly.FieldVariable(Blockly.Msg.MATH_CHANGE_TITLE_ITEM)],["DELTA","Number",Blockly.ALIGN_RIGHT],Blockly.ALIGN_RIGHT);this.setPreviousStatement(!0);this.setNextStatement(!0);var a=this;this.setTooltip(function(){return Blockly.Msg.MATH_CHANGE_TOOLTIP.replace("%1",a.getFieldValue("VAR"))})}, getVars:function(){return[this.getFieldValue("VAR")]},renameVar:function(a,b){Blockly.Names.equals(a,this.getFieldValue("VAR"))&&this.setFieldValue(b,"VAR")}}; Blockly.Blocks.math_round={init:function(){var a=[[Blockly.Msg.MATH_ROUND_OPERATOR_ROUND,"ROUND"],[Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDUP,"ROUNDUP"],[Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDDOWN,"ROUNDDOWN"]];this.setHelpUrl(Blockly.Msg.MATH_ROUND_HELPURL);this.setColour(230);this.setOutput(!0,"Number");this.appendValueInput("NUM").setCheck("Number").appendField(new Blockly.FieldDropdown(a),"OP");this.setTooltip(Blockly.Msg.MATH_ROUND_TOOLTIP)}}; Blockly.Blocks.math_on_list={init:function(){var a=[[Blockly.Msg.MATH_ONLIST_OPERATOR_SUM,"SUM"],[Blockly.Msg.MATH_ONLIST_OPERATOR_MIN,"MIN"],[Blockly.Msg.MATH_ONLIST_OPERATOR_MAX,"MAX"],[Blockly.Msg.MATH_ONLIST_OPERATOR_AVERAGE,"AVERAGE"],[Blockly.Msg.MATH_ONLIST_OPERATOR_MEDIAN,"MEDIAN"],[Blockly.Msg.MATH_ONLIST_OPERATOR_MODE,"MODE"],[Blockly.Msg.MATH_ONLIST_OPERATOR_STD_DEV,"STD_DEV"],[Blockly.Msg.MATH_ONLIST_OPERATOR_RANDOM,"RANDOM"]],b=this;this.setHelpUrl(Blockly.Msg.MATH_ONLIST_HELPURL);this.setColour(230); this.setOutput(!0,"Number");a=new Blockly.FieldDropdown(a,function(a){"MODE"==a?b.outputConnection.setCheck("Array"):b.outputConnection.setCheck("Number")});this.appendValueInput("LIST").setCheck("Array").appendField(a,"OP");this.setTooltip(function(){var a=b.getFieldValue("OP");return{SUM:Blockly.Msg.MATH_ONLIST_TOOLTIP_SUM,MIN:Blockly.Msg.MATH_ONLIST_TOOLTIP_MIN,MAX:Blockly.Msg.MATH_ONLIST_TOOLTIP_MAX,AVERAGE:Blockly.Msg.MATH_ONLIST_TOOLTIP_AVERAGE,MEDIAN:Blockly.Msg.MATH_ONLIST_TOOLTIP_MEDIAN, MODE:Blockly.Msg.MATH_ONLIST_TOOLTIP_MODE,STD_DEV:Blockly.Msg.MATH_ONLIST_TOOLTIP_STD_DEV,RANDOM:Blockly.Msg.MATH_ONLIST_TOOLTIP_RANDOM}[a]})}};Blockly.Blocks.math_modulo={init:function(){this.setHelpUrl(Blockly.Msg.MATH_MODULO_HELPURL);this.setColour(230);this.setOutput(!0,"Number");this.interpolateMsg(Blockly.Msg.MATH_MODULO_TITLE,["DIVIDEND","Number",Blockly.ALIGN_RIGHT],["DIVISOR","Number",Blockly.ALIGN_RIGHT],Blockly.ALIGN_RIGHT);this.setInputsInline(!0);this.setTooltip(Blockly.Msg.MATH_MODULO_TOOLTIP)}}; Blockly.Blocks.math_constrain={init:function(){this.setHelpUrl(Blockly.Msg.MATH_CONSTRAIN_HELPURL);this.setColour(230);this.setOutput(!0,"Number");this.interpolateMsg(Blockly.Msg.MATH_CONSTRAIN_TITLE,["VALUE","Number",Blockly.ALIGN_RIGHT],["LOW","Number",Blockly.ALIGN_RIGHT],["HIGH","Number",Blockly.ALIGN_RIGHT],Blockly.ALIGN_RIGHT);this.setInputsInline(!0);this.setTooltip(Blockly.Msg.MATH_CONSTRAIN_TOOLTIP)}}; Blockly.Blocks.math_random_int={init:function(){this.setHelpUrl(Blockly.Msg.MATH_RANDOM_INT_HELPURL);this.setColour(230);this.setOutput(!0,"Number");this.interpolateMsg(Blockly.Msg.MATH_RANDOM_INT_TITLE,["FROM","Number",Blockly.ALIGN_RIGHT],["TO","Number",Blockly.ALIGN_RIGHT],Blockly.ALIGN_RIGHT);this.setInputsInline(!0);this.setTooltip(Blockly.Msg.MATH_RANDOM_INT_TOOLTIP)}}; Blockly.Blocks.math_random_float={init:function(){this.setHelpUrl(Blockly.Msg.MATH_RANDOM_FLOAT_HELPURL);this.setColour(230);this.setOutput(!0,"Number");this.appendDummyInput().appendField(Blockly.Msg.MATH_RANDOM_FLOAT_TITLE_RANDOM);this.setTooltip(Blockly.Msg.MATH_RANDOM_FLOAT_TOOLTIP)}};Blockly.Blocks.procedures={}; Blockly.Blocks.procedures_defnoreturn={init:function(){this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);this.setColour(290);var a=Blockly.Procedures.findLegalName(Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE,this);this.appendDummyInput().appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE).appendField(new Blockly.FieldTextInput(a,Blockly.Procedures.rename),"NAME").appendField("","PARAMS");this.appendStatementInput("STACK").appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO);this.setMutator(new Blockly.Mutator(["procedures_mutatorarg"])); this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);this.arguments_=[]},updateParams_:function(){for(var a=!1,b={},c=0;c.js for every language defined in msg/js/.json. import errno, glob, httplib, json, os, re, subprocess, sys, threading, urllib def import_path(fullpath): """Import a file with full path specification. Allows one to import from any directory, something __import__ does not do. Args: fullpath: Path and filename of import. Returns: An imported module. """ path, filename = os.path.split(fullpath) filename, ext = os.path.splitext(filename) sys.path.append(path) module = __import__(filename) reload(module) # Might be out of date del sys.path[-1] return module HEADER = ('// Do not edit this file; automatically generated by build.py.\n' '"use strict";\n') class Gen_uncompressed(threading.Thread): """Generate a JavaScript file that loads Blockly's raw files. Runs in a separate thread. """ def __init__(self, search_paths): threading.Thread.__init__(self) self.search_paths = search_paths def run(self): target_filename = 'blockly_uncompressed.js' f = open(target_filename, 'w') f.write(HEADER) f.write(""" window.BLOCKLY_DIR = (function() { // Find name of current directory. var scripts = document.getElementsByTagName('script'); var re = new RegExp('(.+)[\/]blockly_uncompressed\.js$'); for (var x = 0, script; script = scripts[x]; x++) { var match = re.exec(script.src); if (match) { return match[1]; } } alert('Could not detect Blockly\\'s directory name.'); return ''; })(); window.BLOCKLY_BOOT = function() { // Execute after Closure has loaded. if (!window.goog) { alert('Error: Closure not found. Read this:\\n' + 'http://code.google.com/p/blockly/wiki/Closure\\n'); } // Build map of all dependencies (used and unused). var dir = window.BLOCKLY_DIR.match(/[^\\/]+$/)[0]; """) add_dependency = [] base_path = calcdeps.FindClosureBasePath(self.search_paths) for dep in calcdeps.BuildDependenciesFromFiles(self.search_paths): add_dependency.append(calcdeps.GetDepsLine(dep, base_path)) add_dependency = '\n'.join(add_dependency) # Find the Blockly directory name and replace it with a JS variable. # This allows blockly_uncompressed.js to be compiled on one computer and be # used on another, even if the directory name differs. m = re.search('[\\/]([^\\/]+)[\\/]core[\\/]blockly.js', add_dependency) add_dependency = re.sub('([\\/])' + re.escape(m.group(1)) + '([\\/]core[\\/])', '\\1" + dir + "\\2', add_dependency) f.write(add_dependency + '\n') provides = [] for dep in calcdeps.BuildDependenciesFromFiles(self.search_paths): if not dep.filename.startswith(os.pardir + os.sep): # '../' provides.extend(dep.provides) provides.sort() f.write('\n') f.write('// Load Blockly.\n') for provide in provides: f.write('goog.require(\'%s\');\n' % provide) f.write(""" delete window.BLOCKLY_DIR; delete window.BLOCKLY_BOOT; }; // Delete any existing Closure (e.g. Soy's nogoog_shim). document.write(''); // Load fresh Closure Library. document.write(''); document.write(''); """) f.close() print('SUCCESS: ' + target_filename) class Gen_compressed(threading.Thread): """Generate a JavaScript file that contains all of Blockly's core and all required parts of Closure, compiled together. Uses the Closure Compiler's online API. Runs in a separate thread. """ def __init__(self, search_paths): threading.Thread.__init__(self) self.search_paths = search_paths def run(self): self.gen_core() self.gen_blocks() self.gen_generator('javascript') self.gen_generator('python') self.gen_generator('dart') def gen_core(self): target_filename = 'blockly_compressed.js' # Define the parameters for the POST request. params = [ ('compilation_level', 'SIMPLE_OPTIMIZATIONS'), ('use_closure_library', 'true'), ('output_format', 'json'), ('output_info', 'compiled_code'), ('output_info', 'warnings'), ('output_info', 'errors'), ('output_info', 'statistics'), ('language', 'ECMASCRIPT5'), ] # Read in all the source files. filenames = calcdeps.CalculateDependencies(self.search_paths, [os.path.join('core', 'blockly.js')]) for filename in filenames: # Filter out the Closure files (the compiler will add them). if filename.startswith(os.pardir + os.sep): # '../' continue f = open(filename) params.append(('js_code', ''.join(f.readlines()))) f.close() self.do_compile(params, target_filename, filenames, '') def gen_blocks(self): target_filename = 'blocks_compressed.js' # Define the parameters for the POST request. params = [ ('compilation_level', 'SIMPLE_OPTIMIZATIONS'), ('output_format', 'json'), ('output_info', 'compiled_code'), ('output_info', 'warnings'), ('output_info', 'errors'), ('output_info', 'statistics'), ('language', 'ECMASCRIPT5'), ] # Read in all the source files. # Add Blockly.Blocks to be compatible with the compiler. params.append(('js_code', "goog.provide('Blockly.Blocks');")) filenames = glob.glob(os.path.join('blocks', '*.js')) for filename in filenames: f = open(filename) params.append(('js_code', ''.join(f.readlines()))) f.close() # Remove Blockly.Blocks to be compatible with Blockly. remove = "var Blockly={Blocks:{}};" self.do_compile(params, target_filename, filenames, remove) def gen_generator(self, language): target_filename = language + '_compressed.js' # Define the parameters for the POST request. params = [ ('compilation_level', 'SIMPLE_OPTIMIZATIONS'), ('output_format', 'json'), ('output_info', 'compiled_code'), ('output_info', 'warnings'), ('output_info', 'errors'), ('output_info', 'statistics'), ('language', 'ECMASCRIPT5'), ] # Read in all the source files. # Add Blockly.Generator to be compatible with the compiler. params.append(('js_code', "goog.provide('Blockly.Generator');")) filenames = glob.glob( os.path.join('generators', language, '*.js')) filenames.insert(0, os.path.join('generators', language + '.js')) for filename in filenames: f = open(filename) params.append(('js_code', ''.join(f.readlines()))) f.close() filenames.insert(0, '[goog.provide]') # Remove Blockly.Generator to be compatible with Blockly. remove = "var Blockly={Generator:{}};" self.do_compile(params, target_filename, filenames, remove) def do_compile(self, params, target_filename, filenames, remove): # Send the request to Google. headers = { "Content-type": "application/x-www-form-urlencoded" } conn = httplib.HTTPConnection('closure-compiler.appspot.com') conn.request('POST', '/compile', urllib.urlencode(params), headers) response = conn.getresponse() json_str = response.read() conn.close() # Parse the JSON response. json_data = json.loads(json_str) def file_lookup(name): if not name.startswith('Input_'): return '???' n = int(name[6:]) return filenames[n] if json_data.has_key('serverErrors'): errors = json_data['serverErrors'] for error in errors: print 'SERVER ERROR: %s' % target_filename print error['error'] elif json_data.has_key('errors'): errors = json_data['errors'] for error in errors: print('FATAL ERROR') print(error['error']) print('%s at line %d:' % ( file_lookup(error['file']), error['lineno'])) print(error['line']) print((' ' * error['charno']) + '^') sys.exit(1) else: if json_data.has_key('warnings'): warnings = json_data['warnings'] for warning in warnings: print('WARNING') print(warning['warning']) print('%s at line %d:' % ( file_lookup(warning['file']), warning['lineno'])) print(warning['line']) print((' ' * warning['charno']) + '^') print() if not json_data.has_key('compiledCode'): print('FATAL ERROR: Compiler did not return compiledCode.') sys.exit(1) code = HEADER + '\n' + json_data['compiledCode'] code = code.replace(remove, '') # Trim down Google's Apache licences. LICENSE = re.compile("""/\\* [\w ]+ (Copyright \\d+ Google Inc.) https://blockly.googlecode.com/ Licensed under the Apache License, Version 2.0 \(the "License"\); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. \\*/""") code = re.sub(LICENSE, r"\n// \1 Apache License 2.0", code) stats = json_data['statistics'] original_b = stats['originalSize'] compressed_b = stats['compressedSize'] if original_b > 0 and compressed_b > 0: f = open(target_filename, 'w') f.write(code) f.close() original_kb = int(original_b / 1024 + 0.5) compressed_kb = int(compressed_b / 1024 + 0.5) ratio = int(float(compressed_b) / float(original_b) * 100 + 0.5) print('SUCCESS: ' + target_filename) print('Size changed from %d KB to %d KB (%d%%).' % ( original_kb, compressed_kb, ratio)) else: print 'UNKNOWN ERROR' class Gen_langfiles(threading.Thread): """Generate JavaScript file for each natural language supported. Runs in a separate thread. """ def __init__(self): threading.Thread.__init__(self) def _rebuild(self, srcs, dests): # Determine whether any of the files in srcs is newer than any in dests. try: return (max(os.path.getmtime(src) for src in srcs) > min(os.path.getmtime(dest) for dest in dests)) except OSError, e: # Was a file not found? if e.errno == errno.ENOENT: # If it was a source file, we can't proceed. if e.filename in srcs: print('Source file missing: ' + e.filename) sys.exit(1) else: # If a destination file was missing, rebuild. return True else: print('Error checking file creation times: ' + e) def run(self): # The files msg/json/{en,qqq,synonyms}.json depend on msg/messages.js. if self._rebuild([os.path.join('msg', 'messages.js')], [os.path.join('msg', 'json', f) for f in ['en.json', 'qqq.json', 'synonyms.json']]): try: subprocess.check_call([ os.path.join('i18n', 'js_to_json.py'), '--input_file', 'msg/messages.js', '--output_dir', 'msg/json/', '--quiet']) except (subprocess.CalledProcessError, OSError), e: # Documentation for subprocess.check_call says that CalledProcessError # will be raised on failure, but I found that OSError is also possible. print('Error running i18n/js_to_json.py: ', e) sys.exit(1) # Checking whether it is necessary to rebuild the js files would be a lot of # work since we would have to compare each .json file with each # .js file. Rebuilding is easy and cheap, so just go ahead and do it. try: # Use create_messages.py to create .js files from .json files. cmd = [ os.path.join('i18n', 'create_messages.py'), '--source_lang_file', os.path.join('msg', 'json', 'en.json'), '--source_synonym_file', os.path.join('msg', 'json', 'synonyms.json'), '--key_file', os.path.join('msg', 'json', 'keys.json'), '--output_dir', os.path.join('msg', 'js'), '--quiet'] json_files = glob.glob(os.path.join('msg', 'json', '*.json')) json_files = [file for file in json_files if not (file.endswith(('keys.json', 'synonyms.json', 'qqq.json')))] cmd.extend(json_files) subprocess.check_call(cmd) except (subprocess.CalledProcessError, OSError), e: print('Error running i18n/create_messages.py: ', e) sys.exit(1) # Output list of .js files created. for f in json_files: # This assumes the path to the current directory does not contain 'json'. f = f.replace('json', 'js') if os.path.isfile(f): print('SUCCESS: ' + f) else: print('FAILED to create ' + f) if __name__ == '__main__': try: # os.chdir(os.path.join('extern','blockly')); # calcdeps = import_path(os.path.join(os.path.pardir, os.path.pardir, 'lib', # 'closure-library', 'closure', 'bin', 'calcdeps.py')) calcdeps = import_path(os.path.join(os.path.pardir, 'closure-library', 'closure', 'bin', 'calcdeps.py')) print calcdeps except ImportError: print("""Error: Closure not found. Read this: http://code.google.com/p/blockly/wiki/Closure""") sys.exit(1) search_paths = calcdeps.ExpandDirectories( ['core', os.path.join(os.path.pardir, 'closure-library')]) # ['core', os.path.join(os.path.pardir, os.path.pardir, 'lib', 'closure-library')]) # Run both tasks in parallel threads. # Uncompressed is limited by processor speed. # Compressed is limited by network and server speed. Gen_uncompressed(search_paths).start() Gen_compressed(search_paths).start() # This is run locally in a separate thread. Gen_langfiles().start() ================================================ FILE: extern/blockly/core/block.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview The class representing one block. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Block'); goog.require('Blockly.BlockSvg'); goog.require('Blockly.Blocks'); goog.require('Blockly.Comment'); goog.require('Blockly.Connection'); goog.require('Blockly.ContextMenu'); goog.require('Blockly.Input'); goog.require('Blockly.Msg'); goog.require('Blockly.Mutator'); goog.require('Blockly.Warning'); goog.require('Blockly.Workspace'); goog.require('Blockly.Xml'); goog.require('goog.asserts'); goog.require('goog.string'); goog.require('goog.Timer'); goog.require('goog.array'); /** * Unique ID counter for created blocks. * @private */ Blockly.uidCounter_ = 0; /** * Get the Blockly.uidCounter_ * @returns {number} */ Blockly.getUidCounter = function() { return Blockly.uidCounter_; } /** * Set the Blockly.uidCounter_ * @param {number} val The value to set the counter to. */ Blockly.setUidCounter = function(val) { Blockly.uidCounter_ = val; } /** * Class for one block. * @constructor */ Blockly.Block = function() { // We assert this here because there may be users of the previous form of // this constructor, which took arguments. goog.asserts.assert(arguments.length == 0, 'Please use Blockly.Block.obtain.'); }; /** * Obtain a newly created block. * @param {!Blockly.Workspace} workspace The block's workspace. * @param {?string} prototypeName Name of the language object containing * type-specific functions for this block. * @return {!Blockly.Block} The created block */ Blockly.Block.obtain = function(workspace, prototypeName) { if (Blockly.Realtime.isEnabled()) { return Blockly.Realtime.obtainBlock(workspace, prototypeName); } else { var newBlock = new Blockly.Block(); newBlock.initialize(workspace, prototypeName); return newBlock; } }; /** * Initialization for one block. * @param {!Blockly.Workspace} workspace The new block's workspace. * @param {?string} prototypeName Name of the language object containing * type-specific functions for this block. */ Blockly.Block.prototype.initialize = function(workspace, prototypeName) { this.id = ++Blockly.uidCounter_; workspace.addTopBlock(this); this.fill(workspace, prototypeName); // Bind an onchange function, if it exists. if (goog.isFunction(this.onchange)) { Blockly.bindEvent_(workspace.getCanvas(), 'blocklyWorkspaceChange', this, this.onchange); } }; /** * Fill a block with initial values. * @param {!Blockly.Workspace} workspace The workspace to use. * @param {string} prototypeName The typename of the block. */ Blockly.Block.prototype.fill = function(workspace, prototypeName) { this.outputConnection = null; this.nextConnection = null; this.previousConnection = null; this.inputList = []; this.inputsInline = false; this.rendered = false; this.disabled = false; this.tooltip = ''; this.contextMenu = true; this.parentBlock_ = null; this.childBlocks_ = []; this.deletable_ = true; this.movable_ = true; this.addable_ = true; this.editable_ = true; this.collapsed_ = false; this.workspace = workspace; this.isInFlyout = workspace.isFlyout; // Copy the type-specific functions and data from the prototype. if (prototypeName) { this.type = prototypeName; var prototype = Blockly.Blocks[prototypeName]; goog.asserts.assertObject(prototype, 'Error: "%s" is an unknown language block.', prototypeName); goog.mixin(this, prototype); } // Call an initialization function, if it exists. if (goog.isFunction(this.init)) { this.init(); } if (goog.isFunction(this.whenAdd)) { if (this.workspace == Blockly.mainWorkspace) this.whenAdd(); } }; /** * Get an existing block. * @param {string} id The block's id. * @param {!Blockly.Workspace} workspace The block's workspace. * @return {Blockly.Block} The found block, or null if not found. */ Blockly.Block.getById = function(id, workspace) { if (Blockly.Realtime.isEnabled()) { return Blockly.Realtime.getBlockById(id); } else { return workspace.getBlockById(id); } }; /** * Pointer to SVG representation of the block. * @type {Blockly.BlockSvg} * @private */ Blockly.Block.prototype.svg_ = null; /** * Block's mutator icon (if any). * @type {Blockly.Mutator} */ Blockly.Block.prototype.mutator = null; /** * Block's comment icon (if any). * @type {Blockly.Comment} */ Blockly.Block.prototype.comment = null; /** * Block's warning icon (if any). * @type {Blockly.Warning} */ Blockly.Block.prototype.warning = null; /** * Returns a list of mutator, comment, and warning icons. * @return {!Array} List of icons. */ Blockly.Block.prototype.getIcons = function() { var icons = []; if (this.mutator) { icons.push(this.mutator); } if (this.comment) { icons.push(this.comment); } if (this.warning) { icons.push(this.warning); } return icons; }; /** * Create and initialize the SVG representation of the block. */ Blockly.Block.prototype.initSvg = function() { this.svg_ = new Blockly.BlockSvg(this); this.svg_.init(); if (!Blockly.readOnly) { if (this.mouseDownWrapper_) Blockly.unbindEvent_(this.mouseDownWrapper_); this.mouseDownWrapper_ = Blockly.bindEvent_(this.svg_.getRootElement(), 'mousedown', this, this.onMouseDown_); if(this.type === "function_general") { if (this.dblClickWrapper_) Blockly.unbindEvent_(this.dblClickWrapper_); this.dblClickWrapper_ = Blockly.bindEvent_(this.svg_.getRootElement(), 'dblclick', this, this.onDblClick_); } } if (Blockly.enableBlockAnimation) { Blockly.bindEvent_(this.svg_.svgGroup_, 'mouseover', this.svg_, this.svg_.toggleOnPattern); Blockly.bindEvent_(this.svg_.svgGroup_, 'mouseout', this.svg_, this.svg_.toggleOffPattern); } this.workspace.getCanvas().appendChild(this.svg_.getRootElement()); }; /** * Return the root node of the SVG or null if none exists. * @return {Element} The root SVG node (probably a group). */ Blockly.Block.prototype.getSvgRoot = function() { return this.svg_ && this.svg_.getRootElement(); }; /** * Is the mouse dragging a block? * 0 - No drag operation. * 1 - Still inside the sticky DRAG_RADIUS. * 2 - Freely draggable. * @private */ Blockly.Block.dragMode_ = 0; /** * Wrapper function called when a mouseUp occurs during a drag operation. * @type {Array.} * @private */ Blockly.Block.onMouseUpWrapper_ = null; /** * Wrapper function called when a mouseMove occurs during a drag operation. * @type {Array.} * @private */ Blockly.Block.onMouseMoveWrapper_ = null; /** * Stop binding to the global mouseup and mousemove events. * @private */ Blockly.Block.terminateDrag_ = function() { if (Blockly.Block.onMouseUpWrapper_) { Blockly.unbindEvent_(Blockly.Block.onMouseUpWrapper_); Blockly.Block.onMouseUpWrapper_ = null; } if (Blockly.Block.onMouseMoveWrapper_) { Blockly.unbindEvent_(Blockly.Block.onMouseMoveWrapper_); Blockly.Block.onMouseMoveWrapper_ = null; } var selected = Blockly.selected; if (Blockly.Block.dragMode_ == 2) { // Terminate a drag operation. if (selected) { // Update the connection locations. var xy = selected.getRelativeToSurfaceXY(); var dx = xy.x - selected.startDragX; var dy = xy.y - selected.startDragY; selected.moveConnections_(dx, dy); delete selected.draggedBubbles_; selected.setDragging_(false); selected.render(); goog.Timer.callOnce( selected.bumpNeighbours_, Blockly.BUMP_DELAY, selected); // Fire an event to allow scrollbars to resize. Blockly.fireUiEvent(window, 'resize'); } } if (selected) { selected.workspace.fireChangeEvent(); } Blockly.Block.dragMode_ = 0; }; /** * Select this block. Highlight it visually. */ Blockly.Block.prototype.select = function() { goog.asserts.assertObject(this.svg_, 'Block is not rendered.'); if (Blockly.selected) { // Unselect any previously selected block. Blockly.selected.unselect(); } Blockly.selected = this; this.svg_.addSelect(); Blockly.fireUiEvent(this.workspace.getCanvas(), 'blocklySelectChange'); }; /** * Activate this block. Highlight it visually. */ Blockly.Block.prototype.activate = function() { goog.asserts.assertObject(this.svg_, 'Block is not rendered.'); if (Blockly.selected) { // Unselect any previously selected block. Blockly.selected.unselect(); } Blockly.selected = this; this.svg_.addActive(); Blockly.fireUiEvent(this.workspace.getCanvas(), 'blocklySelectChange'); }; /** * Unselect this block. Remove its highlighting. */ Blockly.Block.prototype.unselect = function() { goog.asserts.assertObject(this.svg_, 'Block is not rendered.'); Blockly.selected = null; this.svg_.removeSelect(); Blockly.fireUiEvent(this.workspace.getCanvas(), 'blocklySelectChange'); }; /** * Dispose of this block. * @param {boolean} healStack If true, then try to heal any gap by connecting * the next statement with the previous statement. Otherwise, dispose of * all children of this block. * @param {boolean} animate If true, show a disposal animation and sound. * @param {boolean} dontRemoveFromWorkspace If true, don't remove this block * from the workspace's list of top blocks. */ Blockly.Block.prototype.dispose = function(healStack, animate, dontRemoveFromWorkspace) { // Switch off rerendering. //this.isEditing = true; if (goog.isFunction(this.whenRemove)) { if (this.workspace == Blockly.mainWorkspace && this.isDrag) { this.whenRemove(Blockly.Xml.blockToDom_(this)); } } this.rendered = false; this.unplug(healStack); if (animate && this.svg_) { this.svg_.disposeUiEffect(); } // This block is now at the top of the workspace. // Remove this block from the workspace's list of top-most blocks. if (this.workspace && !dontRemoveFromWorkspace) { this.workspace.removeTopBlock(this); this.workspace = null; } // Just deleting this block from the DOM would result in a memory leak as // well as corruption of the connection database. Therefore we must // methodically step through the blocks and carefully disassemble them. if (Blockly.selected == this) { Blockly.selected = null; // If there's a drag in-progress, unlink the mouse events. Blockly.terminateDrag_(); } // First, dispose of all my children. for (var x = this.childBlocks_.length - 1; x >= 0; x--) { this.childBlocks_[x].dispose(false); } // Then dispose of myself. var icons = this.getIcons(); for (var x = 0; x < icons.length; x++) { icons[x].dispose(); } // Dispose of all inputs and their fields. for (var x = 0, input; input = this.inputList[x]; x++) { input.dispose(); } this.inputList = []; // Dispose of any remaining connections (next/previous/output). var connections = this.getConnections_(true); for (var x = 0; x < connections.length; x++) { var connection = connections[x]; if (connection.targetConnection) { connection.disconnect(); } connections[x].dispose(); } // Dispose of the SVG and break circular references. if (this.svg_) { this.svg_.dispose(); this.svg_ = null; } // Remove from Realtime set of blocks. if (Blockly.Realtime.isEnabled() && !Blockly.Realtime.withinSync) { Blockly.Realtime.removeBlock(this); } }; /** * Unplug this block from its superior block. If this block is a statement, * optionally reconnect the block underneath with the block on top. * @param {boolean} healStack Disconnect child statement and reconnect stack. * @param {boolean} bump Move the unplugged block sideways a short distance. */ Blockly.Block.prototype.unplug = function(healStack, bump) { bump = bump && !!this.getParent(); if (this.outputConnection) { if (this.outputConnection.targetConnection) { // Disconnect from any superior block. this.setParent(null); } } else { var previousTarget = null; if (this.previousConnection && this.previousConnection.targetConnection) { // Remember the connection that any next statements need to connect to. previousTarget = this.previousConnection.targetConnection; // Detach this block from the parent's tree. this.setParent(null); } if (healStack && this.nextConnection && this.nextConnection.targetConnection) { // Disconnect the next statement. var nextTarget = this.nextConnection.targetConnection; var nextBlock = this.nextConnection.targetBlock(); nextBlock.setParent(null); if (previousTarget) { // Attach the next statement to the previous statement. previousTarget.connect(nextTarget); } } } if (bump) { // Bump the block sideways. var dx = Blockly.SNAP_RADIUS * (Blockly.RTL ? -1 : 1); var dy = Blockly.SNAP_RADIUS * 2; this.moveBy(dx, dy); } }; /** * Return the coordinates of the top-left corner of this block relative to the * drawing surface's origin (0,0). * @return {!Object} Object with .x and .y properties. */ Blockly.Block.prototype.getRelativeToSurfaceXY = function() { var x = 0; var y = 0; if (this.svg_) { var element = this.svg_.getRootElement(); do { // Loop through this block and every parent. var xy = Blockly.getRelativeXY_(element); x += xy.x; y += xy.y; element = element.parentNode; } while (element && element != this.workspace.getCanvas()); } return {x: x, y: y}; }; /** * Move a block by a relative offset. * @param {number} dx Horizontal offset. * @param {number} dy Vertical offset. */ Blockly.Block.prototype.moveBy = function(dx, dy) { var xy = this.getRelativeToSurfaceXY(); this.svg_.getRootElement().setAttribute('transform', 'translate(' + (xy.x + dx) + ', ' + (xy.y + dy) + ')'); this.moveConnections_(dx, dy); if (Blockly.Realtime.isEnabled() && !Blockly.Realtime.withinSync) { Blockly.Realtime.blockChanged(this); } }; /** * Returns a bounding box describing the dimensions of this block. * @return {!Object} Object with height and width properties. */ Blockly.Block.prototype.getHeightWidth = function() { try { var bBox = this.getSvgRoot().getBBox(); var height = bBox.height; } catch (e) { // Firefox has trouble with hidden elements (Bug 528969). return {height: 0, width: 0}; } if (Blockly.BROKEN_CONTROL_POINTS) { /* HACK: WebKit bug 67298 causes control points to be included in the reported bounding box. The render functions (below) add two 5px spacer control points that we need to subtract. */ height -= 10; if (this.nextConnection) { // Bottom control point partially masked by lower tab. height += 4; } if (!this.nextConnection && !this.outputConnection && this.previousConnection) { height += 4; } } // Subtract one from the height due to the shadow. height -= 1; return {height: height, width: bBox.width}; }; Blockly.Block.prototype.onDblClick_ = function(e) { if (Entry.Func.isEdit) return; var funcs = Entry.variableContainer.functions_; if(funcs && funcs.length !== 0) Entry.Func.edit(funcs[this.hashId]); }; /** * Handle a mouse-down on an SVG block. * @param {!Event} e Mouse down event. * @private */ Blockly.Block.prototype.onMouseDown_ = function(e) { if (Entry.documentMousedown) Entry.documentMousedown.notify(e); if (this.isInFlyout) { this.select(); return; } // Update Blockly's knowledge of its own location. Blockly.svgResize(); Blockly.terminateDrag_(); this.select(); Blockly.hideChaff(); if (Blockly.isRightButton(e)) { // Right-click. if (this.isInBlockMenu && Blockly.Block.dragMode_ == 0) { if (this.stalkerBlock) this.stalkerBlock.dispose(); this.dispose(); return; } this.isDrag = true; if (Blockly.ContextMenu) { this.showContextMenu_(Blockly.mouseToSvg(e)); } } else if (Blockly.isMiddleButton(e)) { // middle-click. if (this.isInBlockMenu && Blockly.Block.dragMode_ == 0) { if (this.stalkerBlock) this.stalkerBlock.dispose(); this.dispose(); return; } } else if (!this.isMovable()) { // Allow unmovable blocks to be selected and context menued, but not // dragged. Let this event bubble up to document, so the workspace may be // dragged instead. return; } else { // Left-click if (typeof(Entry) == "object") { Entry.dispatchEvent("entryBlocklyChanged"); } this.isDrag = false; Blockly.removeAllRanges(); Blockly.setCursorHand_(true); // Look up the current translation and record it. var xy = this.getRelativeToSurfaceXY(); this.startDragX = xy.x; this.startDragY = xy.y; // Record the current mouse position. this.startDragMouseX = e.clientX; this.startDragMouseY = e.clientY; Blockly.Block.dragMode_ = 1; Blockly.Block.onMouseUpWrapper_ = Blockly.bindEvent_(document, 'mouseup', this, this.onMouseUp_); Blockly.Block.onMouseMoveWrapper_ = Blockly.bindEvent_(document, 'mousemove', this, this.onMouseMove_); // Build a list of bubbles that need to be moved and where they started. this.draggedBubbles_ = []; var descendants = this.getDescendants(); for (var x = 0, descendant; descendant = descendants[x]; x++) { var icons = descendant.getIcons(); for (var y = 0; y < icons.length; y++) { var data = icons[y].getIconLocation(); data.bubble = icons[y]; this.draggedBubbles_.push(data); } } } // This event has been handled. No need to bubble up to the document. e.stopPropagation(); }; /** * Handle a mouse-up anywhere in the SVG pane. Is only registered when a * block is clicked. We can't use mouseUp on the block since a fast-moving * cursor can briefly escape the block before it catches up. * @param {!Event} e Mouse up event. * @private */ Blockly.Block.prototype.onMouseUp_ = function(e) { if (this.isInBlockMenu) { this.isInBlockMenu = false; var selected = Blockly.selected; if (selected && selected.willBeDeleted) { this.stalkerBlock.dispose(false, false); selected.dispose(false, true); Blockly.terminateDrag_(); return; } else { this.stalkerBlock.dispose(false, false); delete selected.willBeDeleted; } this.stalkerBlock = null; } if (!this.isDrag && typeof(Entry) == "object") { //fire instant event //Entry.fireInstantEvent(this.id); }; Blockly.terminateDrag_(); if (Blockly.selected && Blockly.highlightedConnection_) { // Connect two blocks together. Blockly.localConnection_.connect(Blockly.highlightedConnection_); if (this.svg_) { // Trigger a connection animation. // Determine which connection is inferior (lower in the source stack). var inferiorConnection; if (Blockly.localConnection_.isSuperior()) { inferiorConnection = Blockly.highlightedConnection_; } else { inferiorConnection = Blockly.localConnection_; } inferiorConnection.sourceBlock_.svg_.connectionUiEffect(); } if (this.workspace.trashcan && this.workspace.trashcan.isOpen) { // Don't throw an object in the trash can if it just got connected. this.workspace.trashcan.close(); } if (typeof(Entry) == "object" && this.getParent() === this.isDisconnected) { Entry.dispatchEvent("cancelLastCommand"); } } else if (this.workspace.trashcan && this.workspace.trashcan.isOpen) { var trashcan = this.workspace.trashcan; goog.Timer.callOnce(trashcan.close, 100, trashcan); Blockly.selected.dispose(false, true); // Dropping a block on the trash can will usually cause the workspace to // resize to contain the newly positioned block. Force a second resize now // that the block has been deleted. Blockly.fireUiEvent(window, 'resize'); } else if (this.isDisconnected) { } else { if (typeof(Entry) == "object") { Entry.dispatchEvent("cancelLastCommand"); } } if (typeof(Entry) == "object") Entry.dispatchEvent("entryBlocklyMouseUp"); if (Blockly.highlightedConnection_) { Blockly.highlightedConnection_.unhighlight(); Blockly.highlightedConnection_ = null; } }; /** * Load the block's help page in a new window. * @private */ Blockly.Block.prototype.showHelp_ = function() { var url = goog.isFunction(this.helpUrl) ? this.helpUrl() : this.helpUrl; if (url) { window.open(url); } }; /** * Duplicate this block and its children. * @return {!Blockly.Block} The duplicate. * @private */ Blockly.Block.prototype.duplicate_ = function() { // Create a duplicate via XML. var xmlBlock = Blockly.Xml.blockToDom_(this); if (typeof(Entry) === "object") { xmlBlock = Entry.changeXmlHashId(xmlBlock); } else if (typeof(Ntry) === "object") { xmlBlock = Ntry.changeXmlHashId(xmlBlock); } // Blockly.Xml.deleteNext(xmlBlock); var newBlock = Blockly.Xml.domToBlock( /** @type {!Blockly.Workspace} */ (this.workspace), xmlBlock); // Move the duplicate next to the old block. var xy = this.getRelativeToSurfaceXY(); if (Blockly.RTL) { xy.x -= Blockly.SNAP_RADIUS; } else { xy.x += Blockly.SNAP_RADIUS; } xy.y += Blockly.SNAP_RADIUS * 2; newBlock.moveBy(xy.x, xy.y); return newBlock; }; /** * Show the context menu for this block. * @param {!Object} xy Coordinates of mouse click, contains x and y properties. * @private */ Blockly.Block.prototype.showContextMenu_ = function(xy) { if (Blockly.readOnly || !this.contextMenu) { return; } // Save the current block in a variable for use in closures. var block = this; var options = []; if (this.isDeletable() && !block.isInFlyout) { // Option to duplicate this block. var duplicateOption = { text: Lang.Blocks.Duplication_option, enabled: true, callback: function() { block.duplicate_(); if (typeof(Entry) == "object") { Entry.dispatchEvent("entryBlocklyChanged"); } } }; if (this.getDescendants().length > this.workspace.remainingCapacity()) { duplicateOption.enabled = false; } options.push(duplicateOption); var copyOption = { text: Lang.Blocks.CONTEXT_COPY_option, enabled: true, callback: function() { Blockly.copy_(Blockly.selected); } }; if (this.getDescendants().length > this.workspace.remainingCapacity()) { copyOption.enabled = false; } options.push(copyOption); // Option to delete this block. // Count the number of blocks that are nested in this block. var descendantCount = this.getDescendants().length; if (block.nextConnection && block.nextConnection.targetConnection) { // Blocks in the current stack would survive this block's deletion. descendantCount -= this.nextConnection.targetBlock(). getDescendants().length; } var deleteOption = { text: descendantCount == 1 ? Lang.Blocks.Delete_Blocks : Lang.Blocks.Delete_Blocks.replace('%1', descendantCount), enabled: true, callback: function() { block.dispose(true, true); if (typeof(Entry) == "object") { Entry.dispatchEvent("entryBlocklyChanged"); } } }; options.push(deleteOption); } // Allow the block to add or modify options. if (this.customContextMenu && !block.isInFlyout) { this.customContextMenu(options); } Blockly.ContextMenu.show(xy, options); }; /** * Returns all connections originating from this block. * @param {boolean} all If true, return all connections even hidden ones. * Otherwise return those that are visible. * @return {!Array.} Array of connections. * @private */ Blockly.Block.prototype.getConnections_ = function(all) { var myConnections = []; if (all || this.rendered) { if (this.outputConnection) { myConnections.push(this.outputConnection); } if (this.nextConnection) { myConnections.push(this.nextConnection); } if (this.previousConnection) { myConnections.push(this.previousConnection); } if (all || !this.collapsed_) { for (var x = 0, input; input = this.inputList[x]; x++) { if (input.connection) { myConnections.push(input.connection); } } } } return myConnections; }; /** * Move the connections for this block and all blocks attached under it. * Also update any attached bubbles. * @param {number} dx Horizontal offset from current location. * @param {number} dy Vertical offset from current location. * @private */ Blockly.Block.prototype.moveConnections_ = function(dx, dy) { if (!this.rendered) { // Rendering is required to lay out the blocks. // This is probably an invisible block attached to a collapsed block. return; } var myConnections = this.getConnections_(false); for (var x = 0; x < myConnections.length; x++) { myConnections[x].moveBy(dx, dy); } var icons = this.getIcons(); for (var x = 0; x < icons.length; x++) { icons[x].computeIconLocation(); } // Recurse through all blocks attached under this one. for (var x = 0; x < this.childBlocks_.length; x++) { this.childBlocks_[x].moveConnections_(dx, dy); } }; /** * Recursively adds or removes the dragging class to this node and its children. * @param {boolean} adding True if adding, false if removing. * @private */ Blockly.Block.prototype.setDragging_ = function(adding) { if (adding) { this.svg_.addDragging(); } else { this.svg_.removeDragging(); } // Recurse through all blocks attached under this one. for (var x = 0; x < this.childBlocks_.length; x++) { this.childBlocks_[x].setDragging_(adding); } }; /** * Drag this block to follow the mouse. * @param {!Event} e Mouse move event. * @private */ Blockly.Block.prototype.onMouseMove_ = function(e) { Blockly.scrollBarOff = false; this.isDrag = true; if (this.stalkerBlock) { this.stalkerBlock.isDrag = true; this.stalkerBlock.g = true; } this.isEditing = true; if (e.type == 'mousemove' && e.clientX <= 1 && e.clientY == 0 && e.button == 0) { /* HACK: Safari Mobile 6.0 and Chrome for Android 18.0 fire rogue mousemove events on certain touch actions. Ignore events with these signatures. This may result in a one-pixel blind spot in other browsers, but this shouldn't be noticable. */ e.stopPropagation(); return; } Blockly.removeAllRanges(); var dx = e.clientX - this.startDragMouseX; var dy = e.clientY - this.startDragMouseY; if (Blockly.Block.dragMode_ == 1) { // Still dragging within the sticky DRAG_RADIUS. var dr = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); if (dr > Blockly.DRAG_RADIUS) { // Switch to unrestricted dragging. Blockly.Block.dragMode_ = 2; // Push this block to the very top of the stack. this.isDisconnected = this.getParent(); this.setParent(null); this.setDragging_(true); } } if (Blockly.Block.dragMode_ == 2) { // Unrestricted dragging. var x = this.startDragX + dx; var y = this.startDragY + dy; this.svg_.getRootElement().setAttribute('transform', 'translate(' + x + ', ' + y + ')'); if (this.stalkerBlock) { this.willBeDeleted = true; var sx = this.stalkerBlock.startDragX + dx; var sy = this.stalkerBlock.startDragY + dy; if (200 - sx < this.svg_.blockInlineWidth_ / 2) this.willBeDeleted = false; this.stalkerBlock.svg_.getRootElement().setAttribute('transform', 'translate(' + sx + ', ' + sy + ')'); } // Drag all the nested bubbles. for (var i = 0; i < this.draggedBubbles_.length; i++) { var commentData = this.draggedBubbles_[i]; commentData.bubble.setIconLocation(commentData.x + dx, commentData.y + dy); } // Check to see if any of this block's connections are within range of // another block's connection. var myConnections = this.getConnections_(false); var closestConnection = null; var localConnection = null; var radiusConnection = Blockly.SNAP_RADIUS_ENTRY; //var radiusConnection = Blockly.SNAP_RADIUS; for (var i = 0; i < myConnections.length; i++) { var myConnection = myConnections[i]; var neighbour = myConnection.closest(radiusConnection, dx, dy); if (neighbour.connection) { closestConnection = neighbour.connection; localConnection = myConnection; radiusConnection = neighbour.radius; } } // Remove connection highlighting if needed. if (Blockly.highlightedConnection_ && Blockly.highlightedConnection_ != closestConnection) { Blockly.highlightedConnection_.unhighlight(); Blockly.highlightedConnection_ = null; Blockly.localConnection_ = null; } // Add connection highlighting if needed. if (closestConnection && closestConnection != Blockly.highlightedConnection_) { closestConnection.highlight(); Blockly.highlightedConnection_ = closestConnection; Blockly.localConnection_ = localConnection; } // Flip the trash can lid if needed. if (this.workspace.trashcan && this.isDeletable()) { this.workspace.trashcan.onMouseMove(e); } } delete this.isEditing; // This event has been handled. No need to bubble up to the document. e.stopPropagation(); }; /** * Bump unconnected blocks out of alignment. Two blocks which aren't actually * connected should not coincidentally line up on screen. * @private */ Blockly.Block.prototype.bumpNeighbours_ = function() { if (Blockly.Block.dragMode_ != 0) { // Don't bump blocks during a drag. return; } var rootBlock = this.getRootBlock(); if (rootBlock.isInFlyout) { // Don't move blocks around in a flyout. return; } // Loop though every connection on this block. var myConnections = this.getConnections_(false); for (var x = 0; x < myConnections.length; x++) { var connection = myConnections[x]; // Spider down from this block bumping all sub-blocks. if (connection.targetConnection && connection.isSuperior()) { connection.targetBlock().bumpNeighbours_(); } var neighbours = connection.neighbours_(Blockly.SNAP_RADIUS); for (var y = 0; y < neighbours.length; y++) { var otherConnection = neighbours[y]; // If both connections are connected, that's probably fine. But if // either one of them is unconnected, then there could be confusion. if (!connection.targetConnection || !otherConnection.targetConnection) { // Only bump blocks if they are from different tree structures. if (otherConnection.sourceBlock_.getRootBlock() != rootBlock) { // Always bump the inferior block. if (connection.isSuperior()) { otherConnection.bumpAwayFrom_(connection); } else { connection.bumpAwayFrom_(otherConnection); } } } } } }; /** * Return the parent block or null if this block is at the top level. * @return {Blockly.Block} The block that holds the current block. */ Blockly.Block.prototype.getParent = function() { // Look at the DOM to see if we are nested in another block. return this.parentBlock_; }; /** * Return the parent block that surrounds the current block, or null if this * block has no surrounding block. A parent block might just be the previous * statement, whereas the surrounding block is an if statement, while loop, etc. * @return {Blockly.Block} The block that surrounds the current block. */ Blockly.Block.prototype.getSurroundParent = function() { var block = this; while (true) { do { var prevBlock = block; block = block.getParent(); if (!block) { // Ran off the top. return null; } } while (block.nextConnection && block.nextConnection.targetBlock() == prevBlock); // This block is an enclosing parent, not just a statement in a stack. return block; } }; /** * Return the top-most block in this block's tree. * This will return itself if this block is at the top level. * @return {!Blockly.Block} The root block. */ Blockly.Block.prototype.getRootBlock = function() { var rootBlock; var block = this; do { rootBlock = block; block = rootBlock.parentBlock_; } while (block); return rootBlock; }; /** * Find all the blocks that are directly nested inside this one. * Includes value and block inputs, as well as any following statement. * Excludes any connection on an output tab or any preceding statement. * @return {!Array.} Array of blocks. */ Blockly.Block.prototype.getChildren = function() { return this.childBlocks_; }; /** * Set parent of this block to be a new block or null. * @param {Blockly.Block} newParent New parent block. */ Blockly.Block.prototype.setParent = function(newParent) { if (this.parentBlock_) { // Remove this block from the old parent's child list. var children = this.parentBlock_.childBlocks_; for (var child, x = 0; child = children[x]; x++) { if (child == this) { children.splice(x, 1); break; } } // Move this block up the DOM. Keep track of x/y translations. var xy = this.getRelativeToSurfaceXY(); this.workspace.getCanvas().appendChild(this.getSvgRoot()); this.svg_.getRootElement().setAttribute('transform', 'translate(' + xy.x + ', ' + xy.y + ')'); // Disconnect from superior blocks. this.parentBlock_ = null; if (this.previousConnection && this.previousConnection.targetConnection) { this.previousConnection.disconnect(); } if (this.outputConnection && this.outputConnection.targetConnection) { this.outputConnection.disconnect(); } // This block hasn't actually moved on-screen, so there's no need to update // its connection locations. } else { // Remove this block from the workspace's list of top-most blocks. // Note that during realtime sync we sometimes create child blocks that are // not top level so we check first before removing. if (goog.array.contains(this.workspace.getTopBlocks(false), this)) { this.workspace.removeTopBlock(this); } } this.parentBlock_ = newParent; if (newParent) { // Add this block to the new parent's child list. newParent.childBlocks_.push(this); var oldXY = this.getRelativeToSurfaceXY(); if (newParent.svg_ && this.svg_) { newParent.svg_.getRootElement().insertBefore(this.svg_.getRootElement(), newParent.svg_.svgPath_); } var newXY = this.getRelativeToSurfaceXY(); // Move the connections to match the child's new position. this.moveConnections_(newXY.x - oldXY.x, newXY.y - oldXY.y); } else { this.workspace.addTopBlock(this); } }; /** * Find all the blocks that are directly or indirectly nested inside this one. * Includes this block in the list. * Includes value and block inputs, as well as any following statements. * Excludes any connection on an output tab or any preceding statements. * @return {!Array.} Flattened array of blocks. */ Blockly.Block.prototype.getDescendants = function() { var blocks = [this]; for (var child, x = 0; child = this.childBlocks_[x]; x++) { blocks = blocks.concat(child.getDescendants()); } return blocks; }; /** * Get whether this block is deletable or not. * @return {boolean} True if deletable. */ Blockly.Block.prototype.isDeletable = function() { return this.deletable_ && !Blockly.readOnly; }; /** * Set whether this block is deletable or not. * @param {boolean} deletable True if deletable. */ Blockly.Block.prototype.setDeletable = function(deletable) { this.deletable_ = deletable; this.svg_ && this.svg_.updateMovable(); }; /** * Get whether this block is movable or not. * @return {boolean} True if movable. */ Blockly.Block.prototype.isMovable = function() { return this.movable_ && !Blockly.readOnly; }; /** * Set whether this block is movable or not. * @param {boolean} movable True if movable. */ Blockly.Block.prototype.setMovable = function(movable) { this.movable_ = movable; }; /** * Set whether this block is addable or not. * @param {boolean} addable True if addable. */ Blockly.Block.prototype.setAddable = function(addable) { this.addable_ = addable; }; /** * Get whether this block is addable or not. * @return {boolean} True if addable. */ Blockly.Block.prototype.isAddable = function() { return this.addable_ && !Blockly.readOnly; }; /** * Get whether this block is editable or not. * @return {boolean} True if editable. */ Blockly.Block.prototype.isEditable = function() { return this.editable_ && !Blockly.readOnly; }; /** * Set whether this block is editable or not. * @param {boolean} editable True if editable. */ Blockly.Block.prototype.setEditable = function(editable) { this.editable_ = editable; for (var x = 0, input; input = this.inputList[x]; x++) { for (var y = 0, field; field = input.fieldRow[y]; y++) { field.updateEditable(); } } var icons = this.getIcons(); for (var x = 0; x < icons.length; x++) { icons[x].updateEditable(); } }; /** * Set the URL of this block's help page. * @param {string|Function} url URL string for block help, or function that * returns a URL. Null for no help. */ Blockly.Block.prototype.setHelpUrl = function(url) { this.helpUrl = url; }; /** * Get the colour of a block. * @return {number} HSV hue value. */ Blockly.Block.prototype.getColour = function() { return this.colourHue_; }; /** * Change the colour of a block. * @param {number} colourHue HSV hue value. */ Blockly.Block.prototype.setColour = function(colourHue) { this.colourHue_ = colourHue; if (this.svg_) { this.svg_.updateColour(); } var icons = this.getIcons(); for (var x = 0; x < icons.length; x++) { icons[x].updateColour(); } if (this.rendered) { // Bump every dropdown to change its colour. for (var x = 0, input; input = this.inputList[x]; x++) { for (var y = 0, field; field = input.fieldRow[y]; y++) { field.setText(null); } } this.render(); } }; /** * Returns the named field from a block. * @param {string} name The name of the field. * @return {Blockly.Field} Named field, or null if field does not exist. * @private */ Blockly.Block.prototype.getField_ = function(name) { for (var x = 0, input; input = this.inputList[x]; x++) { for (var y = 0, field; field = input.fieldRow[y]; y++) { if (field.name === name) { return field; } } } return null; }; /** * Returns the language-neutral value from the field of a block. * @param {string} name The name of the field. * @return {?string} Value from the field or null if field does not exist. */ Blockly.Block.prototype.getFieldValue = function(name) { var field = this.getField_(name); if (field) { return field.getValue(); } return null; }; /** * Returns the language-neutral value from the field of a block. * @param {string} name The name of the field. * @return {?string} Value from the field or null if field does not exist. * @deprecated December 2013 */ Blockly.Block.prototype.getTitleValue = function(name) { console.log('Deprecated call to getTitleValue, use getFieldValue instead.'); return this.getFieldValue(name); }; /** * Change the field value for a block (e.g. 'CHOOSE' or 'REMOVE'). * @param {string} newValue Value to be the new field. * @param {string} name The name of the field. */ Blockly.Block.prototype.setFieldValue = function(newValue, name) { var field = this.getField_(name); goog.asserts.assertObject(field, 'Field "%s" not found.', name); field.setValue(newValue); }; /** * Change the field value for a block (e.g. 'CHOOSE' or 'REMOVE'). * @param {string} newValue Value to be the new field. * @param {string} name The name of the field. * @deprecated December 2013 */ Blockly.Block.prototype.setTitleValue = function(newValue, name) { console.log('Deprecated call to setTitleValue, use setFieldValue instead.'); this.setFieldValue(newValue, name); }; /** * Change the tooltip text for a block. * @param {string|!Element} newTip Text for tooltip or a parent element to * link to for its tooltip. */ Blockly.Block.prototype.setTooltip = function(newTip) { this.tooltip = newTip; }; /** * Set whether this block can chain onto the bottom of another block. * @param {boolean} newBoolean True if there can be a previous statement. * @param {string|Array.|null} opt_check Statement type or list of * statement types. Null or undefined if any type could be connected. */ Blockly.Block.prototype.setPreviousStatement = function(newBoolean, opt_check) { if (this.previousConnection) { goog.asserts.assert(!this.previousConnection.targetConnection, 'Must disconnect previous statement before removing connection.'); this.previousConnection.dispose(); this.previousConnection = null; } if (newBoolean) { goog.asserts.assert(!this.outputConnection, 'Remove output connection prior to adding previous connection.'); if (opt_check === undefined) { opt_check = null; } this.previousConnection = new Blockly.Connection(this, Blockly.PREVIOUS_STATEMENT); this.previousConnection.setCheck(opt_check); } if (this.rendered) { this.render(); this.bumpNeighbours_(); } }; /** * Set whether another block can chain onto the bottom of this block. * @param {boolean} newBoolean True if there can be a next statement. * @param {string|Array.|null} opt_check Statement type or list of * statement types. Null or undefined if any type could be connected. */ Blockly.Block.prototype.setNextStatement = function(newBoolean, opt_check) { if (this.nextConnection) { goog.asserts.assert(!this.nextConnection.targetConnection, 'Must disconnect next statement before removing connection.'); this.nextConnection.dispose(); this.nextConnection = null; } if (newBoolean) { if (opt_check === undefined) { opt_check = null; } this.nextConnection = new Blockly.Connection(this, Blockly.NEXT_STATEMENT); this.nextConnection.setCheck(opt_check); } if (this.rendered) { this.render(); this.bumpNeighbours_(); } }; /** * Set whether this block returns a value. * @param {boolean} newBoolean True if there is an output. * @param {string|Array.|null} opt_check Returned type or list of * returned types. Null or undefined if any type could be returned * (e.g. variable get). */ Blockly.Block.prototype.setOutput = function(newBoolean, opt_check) { if (this.outputConnection) { goog.asserts.assert(!this.outputConnection.targetConnection, 'Must disconnect output value before removing connection.'); this.outputConnection.dispose(); this.outputConnection = null; } if (newBoolean) { goog.asserts.assert(!this.previousConnection, 'Remove previous connection prior to adding output connection.'); if (opt_check === undefined) { opt_check = null; } this.outputConnection = new Blockly.Connection(this, Blockly.OUTPUT_VALUE); this.outputConnection.setCheck(opt_check); } if (this.rendered) { this.render(); this.bumpNeighbours_(); } }; /** * Change the output type on a block. * @param {string|Array.|null} check Returned type or list of * returned types. Null or undefined if any type could be returned * (e.g. variable get). It is fine if this is the same as the old type. * @throws {goog.asserts.AssertionError} if the block did not already have an * output. */ Blockly.Block.prototype.changeOutput = function(check) { goog.asserts.assert(this.outputConnection, 'Only use changeOutput() on blocks that already have an output.'); this.outputConnection.setCheck(check); }; /** * Set whether value inputs are arranged horizontally or vertically. * @param {boolean} newBoolean True if inputs are horizontal. */ Blockly.Block.prototype.setInputsInline = function(newBoolean) { this.inputsInline = newBoolean; if (this.rendered) { this.render(); this.bumpNeighbours_(); this.workspace.fireChangeEvent(); } }; /** * Set whether the block is disabled or not. * @param {boolean} disabled True if disabled. */ Blockly.Block.prototype.setDisabled = function(disabled) { if (this.disabled == disabled) { return; } this.disabled = disabled; this.svg_.updateDisabled(); this.workspace.fireChangeEvent(); }; /** * Get whether the block is disabled or not due to parents. * The block's own disabled property is not considered. * @return {boolean} True if disabled. */ Blockly.Block.prototype.getInheritedDisabled = function() { var block = this; while (true) { block = block.getSurroundParent(); if (!block) { // Ran off the top. return false; } else if (block.disabled) { return true; } } }; /** * Get whether the block is collapsed or not. * @return {boolean} True if collapsed. */ Blockly.Block.prototype.isCollapsed = function() { return this.collapsed_; }; /** * Set whether the block is collapsed or not. * @param {boolean} collapsed True if collapsed. */ Blockly.Block.prototype.setCollapsed = function(collapsed) { if (this.collapsed_ == collapsed) { return; } this.collapsed_ = collapsed; var renderList = []; // Show/hide the inputs. for (var x = 0, input; input = this.inputList[x]; x++) { renderList = renderList.concat(input.setVisible(!collapsed)); } var COLLAPSED_INPUT_NAME = '_TEMP_COLLAPSED_INPUT'; if (collapsed) { var icons = this.getIcons(); for (var x = 0; x < icons.length; x++) { icons[x].setVisible(false); } var text = this.toString(Blockly.COLLAPSE_CHARS); this.appendDummyInput(COLLAPSED_INPUT_NAME).appendField(text); } else { this.removeInput(COLLAPSED_INPUT_NAME) } if (!renderList.length) { // No child blocks, just render this block. renderList[0] = this; } if (this.rendered) { for (var x = 0, block; block = renderList[x]; x++) { block.render(); } this.bumpNeighbours_(); } }; /** * Create a human-readable text representation of this block and any children. * @param {?number} opt_maxLength Truncate the string to this length. * @return {string} Text of block. */ Blockly.Block.prototype.toString = function(opt_maxLength) { var text = []; for (var x = 0, input; input = this.inputList[x]; x++) { for (var y = 0, field; field = input.fieldRow[y]; y++) { text.push(field.getText()); } if (input.connection) { var child = input.connection.targetBlock(); if (child) { text.push(child.toString()); } else { text.push('?'); } } } text = goog.string.trim(text.join(' ')) || '???'; if (opt_maxLength) { // TODO: Improve truncation so that text from this block is given priority. // TODO: Handle FieldImage better. text = goog.string.truncate(text, opt_maxLength); } return text; } /** * Shortcut for appending a value input row. * @param {string} name Language-neutral identifier which may used to find this * input again. Should be unique to this block. * @return {!Blockly.Input} The input object created. */ Blockly.Block.prototype.appendValueInput = function(name) { return this.appendInput_(Blockly.INPUT_VALUE, name); }; /** * Shortcut for appending a statement input row. * @param {string} name Language-neutral identifier which may used to find this * input again. Should be unique to this block. * @return {!Blockly.Input} The input object created. */ Blockly.Block.prototype.appendStatementInput = function(name) { return this.appendInput_(Blockly.NEXT_STATEMENT, name); }; /** * Shortcut for appending a dummy input row. * @param {string} opt_name Language-neutral identifier which may used to find * this input again. Should be unique to this block. * @return {!Blockly.Input} The input object created. */ Blockly.Block.prototype.appendDummyInput = function(opt_name) { return this.appendInput_(Blockly.DUMMY_INPUT, opt_name || ''); }; /** * Interpolate a message string, creating fields and inputs. * @param {string} msg The message string to parse. %1, %2, etc. are symbols * for value inputs or for Fields, such as an instance of * Blockly.FieldDropdown, which would be placed as a field in either the * following value input or a dummy input. The newline character forces * the creation of an unnamed dummy input if any fields need placement. * Note that '%10' would be interpreted as a reference to the tenth * argument. To show the first argument followed by a zero, use '%1 0'. * (Spaces around tokens are stripped.) To display a percentage sign * followed by a number (e.g., "%123"), put that text in a * Blockly.FieldLabel (as described below). * @param {!Array.|Blockly.Field>|number} var_args * A series of tuples that each specify the value inputs to create. Each * tuple has at least two elements. The first is its name; the second is * its type, which can be any of: * - A string (such as 'Number'), denoting the one type allowed in the * corresponding socket. * - An array of strings (such as ['Number', 'List']), denoting the * different types allowed in the corresponding socket. * - null, denoting that any type is allowed in the corresponding socket. * - Blockly.Field, in which case that field instance, such as an * instance of Blockly.FieldDropdown, appears (instead of a socket). * If the type is any of the first three options (which are legal arguments * to setCheck()), there should be a third element in the tuple, giving its * alignment. * The final parameter is not a tuple, but just an alignment for any * trailing dummy inputs. This last parameter is mandatory; there may be * any number of tuples (though the number of tuples must match the symbols * in msg). */ Blockly.Block.prototype.interpolateMsg = function(msg, var_args) { /** * Add a field to this input. * @this !Blockly.input * @param {Blockly.Field|Array.} field * This is either a Field or a tuple of a name and a Field. */ function addFieldToInput(field) { if (field instanceof Blockly.Field) { this.appendField(field); } else { goog.asserts.assert(field instanceof Array); this.appendField(field[1], field[0]); } } // Validate the msg at the start and the dummy alignment at the end, // and remove the latter. goog.asserts.assertString(msg); var dummyAlign = arguments[arguments.length - 1]; goog.asserts.assert( dummyAlign === Blockly.ALIGN_LEFT || dummyAlign === Blockly.ALIGN_CENTRE || dummyAlign === Blockly.ALIGN_RIGHT, 'Illegal final argument "%d" is not an alignment.', dummyAlign); arguments.length = arguments.length - 1; var tokens = msg.split(this.interpolateMsg.SPLIT_REGEX_); var fields = []; for (var i = 0; i < tokens.length; i += 2) { var text = goog.string.trim(tokens[i]); var input = undefined; if (text) { fields.push(new Blockly.FieldLabel(text)); } var symbol = tokens[i + 1]; if (symbol && symbol.charAt(0) == '%') { // Numeric field. var number = parseInt(symbol.substring(1), 10); var tuple = arguments[number]; goog.asserts.assertArray(tuple, 'Message symbol "%s" is out of range.', symbol); goog.asserts.assertArray(tuple, 'Argument "%s" is not a tuple.', symbol); if (tuple[1] instanceof Blockly.Field) { fields.push([tuple[0], tuple[1]]); } else { input = this.appendValueInput(tuple[0]) .setCheck(tuple[1]) .setAlign(tuple[2]); } arguments[number] = null; // Inputs may not be reused. } else if (symbol == '\n' && fields.length) { // Create a dummy input. input = this.appendDummyInput(); } // If we just added an input, hang any pending fields on it. if (input && fields.length) { fields.forEach(addFieldToInput, input); fields = []; } } // If any fields remain, create a trailing dummy input. if (fields.length) { var input = this.appendDummyInput() .setAlign(dummyAlign); fields.forEach(addFieldToInput, input); } // Verify that all inputs were used. for (var i = 1; i < arguments.length - 1; i++) { goog.asserts.assert(arguments[i] === null, 'Input "%%s" not used in message: "%s"', i, msg); } // Make the inputs inline unless there is only one input and // no text follows it. this.setInputsInline(!msg.match(this.interpolateMsg.INLINE_REGEX_)); }; Blockly.Block.prototype.interpolateMsg.SPLIT_REGEX_ = /(%\d+|\n)/; Blockly.Block.prototype.interpolateMsg.INLINE_REGEX_ = /%1\s*$/; /** * Add a value input, statement input or local variable to this block. * @param {number} type Either Blockly.INPUT_VALUE or Blockly.NEXT_STATEMENT or * Blockly.DUMMY_INPUT. * @param {string} name Language-neutral identifier which may used to find this * input again. Should be unique to this block. * @return {!Blockly.Input} The input object created. * @private */ Blockly.Block.prototype.appendInput_ = function(type, name) { var connection = null; if (type == Blockly.INPUT_VALUE || type == Blockly.NEXT_STATEMENT) { connection = new Blockly.Connection(this, type); } var input = new Blockly.Input(type, name, this, connection); // Append input to list. this.inputList.push(input); if (this.rendered) { this.render(); // Adding an input will cause the block to change shape. this.bumpNeighbours_(); } return input; }; /** * Move a named input to a different location on this block. * @param {string} name The name of the input to move. * @param {?string} refName Name of input that should be after the moved input, * or null to be the input at the end. */ Blockly.Block.prototype.moveInputBefore = function(name, refName) { if (name == refName) { return; } // Find both inputs. var inputIndex = -1; var refIndex = refName ? -1 : this.inputList.length; for (var x = 0, input; input = this.inputList[x]; x++) { if (input.name == name) { inputIndex = x; if (refIndex != -1) { break; } } else if (refName && input.name == refName) { refIndex = x; if (inputIndex != -1) { break; } } } goog.asserts.assert(inputIndex != -1, 'Named input "%s" not found.', name); goog.asserts.assert(refIndex != -1, 'Reference input "%s" not found.', refName); this.moveNumberedInputBefore(inputIndex, refIndex); }; /** * Move a numbered input to a different location on this block. * @param {number} inputIndex Index of the input to move. * @param {number} refIndex Index of input that should be after the moved input. */ Blockly.Block.prototype.moveNumberedInputBefore = function( inputIndex, refIndex) { // Validate arguments. goog.asserts.assert(inputIndex != refIndex, 'Can\'t move input to itself.'); goog.asserts.assert(inputIndex < this.inputList.length, 'Input index ' + inputIndex + ' out of bounds.') goog.asserts.assert(refIndex <= this.inputList.length, 'Reference input ' + refIndex + ' out of bounds.') // Remove input. var input = this.inputList[inputIndex]; this.inputList.splice(inputIndex, 1); if (inputIndex < refIndex) { refIndex--; } // Reinsert input. this.inputList.splice(refIndex, 0, input); if (this.rendered) { this.render(); // Moving an input will cause the block to change shape. this.bumpNeighbours_(); } }; /** * Remove an input from this block. * @param {string} name The name of the input. * @param {boolean} opt_quiet True to prevent error if input is not present. * @throws {goog.asserts.AssertionError} if the input is not present and * opt_quiet is not true. */ Blockly.Block.prototype.removeInput = function(name, opt_quiet) { for (var x = 0, input; input = this.inputList[x]; x++) { if (input.name == name) { if (input.connection && input.connection.targetConnection) { // Disconnect any attached block. input.connection.targetBlock().setParent(null); } input.dispose(); this.inputList.splice(x, 1); if (this.rendered) { this.render(); // Removing an input will cause the block to change shape. this.bumpNeighbours_(); } return; } } if (!opt_quiet) { goog.asserts.fail('Input "%s" not found.', name); } }; /** * Fetches the named input object. * @param {string} name The name of the input. * @return {Object} The input object, or null of the input does not exist. */ Blockly.Block.prototype.getInput = function(name) { for (var x = 0, input; input = this.inputList[x]; x++) { if (input.name == name) { return input; } } // This input does not exist. return null; }; /** * Fetches the block attached to the named input. * @param {string} name The name of the input. * @return {Blockly.Block} The attached value block, or null if the input is * either disconnected or if the input does not exist. */ Blockly.Block.prototype.getInputTargetBlock = function(name) { var input = this.getInput(name); return input && input.connection && input.connection.targetBlock(); }; /** * Give this block a mutator dialog. * @param {Blockly.Mutator} mutator A mutator dialog instance or null to remove. */ Blockly.Block.prototype.setMutator = function(mutator) { if (this.mutator && this.mutator !== mutator) { this.mutator.dispose(); } if (mutator) { mutator.block_ = this; this.mutator = mutator; if (this.svg_) { mutator.createIcon(); } } }; /** * Returns the comment on this block (or '' if none). * @return {string} Block's comment. */ Blockly.Block.prototype.getCommentText = function() { if (this.comment) { var comment = this.comment.getText(); // Trim off trailing whitespace. return comment.replace(/\s+$/, '').replace(/ +\n/g, '\n'); } return ''; }; /** * Set this block's comment text. * @param {?string} text The text, or null to delete. */ Blockly.Block.prototype.setCommentText = function(text) { var changedState = false; if (goog.isString(text)) { if (!this.comment) { this.comment = new Blockly.Comment(this); changedState = true; } this.comment.setText(/** @type {string} */ (text)); } else { if (this.comment) { this.comment.dispose(); changedState = true; } } if (this.rendered) { this.render(); if (changedState) { // Adding or removing a comment icon will cause the block to change shape. this.bumpNeighbours_(); } } }; /** * Set this block's warning text. * @param {?string} text The text, or null to delete. */ Blockly.Block.prototype.setWarningText = function(text) { if (this.isInFlyout) { text = null; } var changedState = false; if (goog.isString(text)) { if (!this.warning) { this.warning = new Blockly.Warning(this); changedState = true; } this.warning.setText(/** @type {string} */ (text)); } else { if (this.warning) { this.warning.dispose(); changedState = true; } } if (changedState && this.rendered) { this.render(); // Adding or removing a warning icon will cause the block to change shape. this.bumpNeighbours_(); } }; /** * Render the block. * Lays out and reflows a block based on its contents and settings. */ Blockly.Block.prototype.render = function() { goog.asserts.assertObject(this.svg_, 'Uninitialized block cannot be rendered. Call block.initSvg()'); this.svg_.render(); if (Blockly.Realtime.isEnabled() && !Blockly.Realtime.withinSync) { Blockly.Realtime.blockChanged(this); } }; /** * Set stalker block. Stalker block is only for BlockMenu block. * It provide graphical effect when adding blocks on block menu. * @param {Blockly.Block} targetBlock */ Blockly.Block.prototype.setStalkerBlock = function(targetBlock) { if (!this.isInBlockMenu) return; this.stalkerBlock = targetBlock; }; ================================================ FILE: extern/blockly/core/block_menu.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Object representing a UI block menu. * @author kyumin92@gmail.com */ 'use strict'; goog.provide('Blockly.BlockMenu'); goog.require('Blockly.Workspace'); /** * Class for UI Block Menu * @param {!Element} element HTML div for block menu. * @constructor */ Blockly.BlockMenu = function(element) { /** * List of background buttons that lurk behind each block to catch clicks * landing in the blocks' lakes and bays. * @type {!Array.} * @private */ this.buttons_ = []; /** * List of split line. */ this.splitters_ = []; /** * List of buttons. */ this.buttons_ = []; /** * List of event listeners. * @type {!Array.} * @private */ this.listeners_ = []; this.isViewOnly = false; this.isCenterAlign = false; this.targetWorkspace = Blockly.mainWorkspace; this.bannedClass = []; this.view_ = element; this.menuView_ = Blockly.createSvgElement('svg', { 'xmlns': 'http://www.w3.org/2000/svg', 'xmlns:html': 'http://www.w3.org/1999/xhtml', 'xmlns:xlink': 'http://www.w3.org/1999/xlink', 'version': '1.1', 'class': 'blocklySvg' }, this.view_); var blockMenu = this; this.workspace_ = new Blockly.Workspace( function() {return blockMenu.getMetrics_();}, function(ratio) {return blockMenu.setMetrics_(ratio);}); this.menuView_.appendChild(this.workspace_.createDom()); this.scrollbar_ = new Blockly.Scrollbar(this.workspace_, false, false); this.onResizeWrapper_ = Blockly.bindEvent_(window, goog.events.EventType.RESIZE, this, this.syncViewSize_); Blockly.bindEvent_(window, 'resize', this, this.updateSplitters); var width = Blockly.BlockMenu.BTN_WIDTH; var height = Blockly.BlockMenu.BTN_HEIGHT; var round = Blockly.BlockMenu.BTN_ROUND; var paths = []; paths.push('m ' + round + ',0'); paths.push('h', width - 2 * round); paths.push('a', round + ',' + round + ' 0, 0,1 ' + round + ',' + round); paths.push('v', height - 2 * round); paths.push('a', round + ',' + round + ' 0, 0,1 -' + round + ',' + round); paths.push('h', - width + 2 * round); paths.push('a', round + ',' + round + ' 0, 0,1 -' + round + ',-' + round); paths.push('v', - height + 2 * round); paths.push('a', round + ',' + round + ' 0, 0,1 ' + round + ',-' + round); paths.push('z'); this.btnPath = paths.join(' '); }; Blockly.BlockMenu.BTN_HEIGHT = 30; Blockly.BlockMenu.BTN_WIDTH = 140; Blockly.BlockMenu.BTN_ROUND = 6; Blockly.BlockMenu.BTN_FONT_SIZE = '9pt'; /** * how and populate the blockmenu. * @param {!Array|string} xmlList List of blocks to show. * Variables and procedures have a custom set of blocks. */ Blockly.BlockMenu.prototype.show = function(xmlList) { this.hide(); var margin = 0; this.menuView_.style.display = 'block'; // Create the blocks to be shown in this blockMenu. var blocks = []; var gaps = []; if (xmlList == Blockly.Variables.NAME_TYPE) { // Special category for variables. Blockly.Variables.blockMenuCategory(blocks, gaps, margin, /** @type {!Blockly.Workspace} */ (this.workspace_)); } else if (xmlList == Blockly.Procedures.NAME_TYPE) { // Special category for procedures. Blockly.Procedures.blockMenuCategory(blocks, gaps, margin, /** @type {!Blockly.Workspace} */ (this.workspace_)); } else { for (var i = 0, xml; xml = xmlList[i]; i++) { if (xml.tagName && xml.tagName.toUpperCase() == 'BLOCK') { var block = Blockly.Xml.domToBlock( /** @type {!Blockly.Workspace} */ (this.workspace_), xml); block.isInFlyout = true; blocks.push(block); gaps.push(margin); } else if (xml.tagName && xml.tagName.toUpperCase() == 'SPLITTER') { blocks.push('splitter'); gaps.push(0); } else if (xml.tagName && xml.tagName.toUpperCase() == 'BTN') { blocks.push(xml); gaps.push(margin); } } } // Lay out the blocks vertically. var cursorY = 10; for (var i = 0, block; block = blocks[i]; i++) { if (block == 'splitter') { var previousBlock = blocks[i - 1]; var y = previousBlock.outputConnection ? cursorY : cursorY + 5; var splitter = this.createSplitter(64, y, this.view_.style.width.substr(0,3)); this.workspace_.svgBlockCanvas_.appendChild(splitter); this.splitters_.push(splitter); cursorY += 10; continue; } else if (block.tagName && block.tagName.toUpperCase() == 'BTN') { var height = Number(block.getAttribute('height')); var button = Blockly.createSvgElement('g', { 'transform': 'translate(' + (10) + ', ' + cursorY + ')', 'class': 'blocklyBlockMenuBtn' }, null); if (height) { var image = Blockly.createSvgElement('image', {'x': 0, 'y': 0, 'width': block.getAttribute('width') + 'px', 'height': height + 'px' }, button); image.setAttributeNS("http://www.w3.org/1999/xlink", 'xlink:href', block.getAttribute('src')); var highlightImage = Blockly.createSvgElement('image', {'x': 0, 'y': 0, 'width': block.getAttribute('width') + 'px', 'height': height + 'px', 'class': 'blocklyBlockMenuBtnHighlight' }, button); highlightImage.setAttributeNS("http://www.w3.org/1999/xlink", 'xlink:href', block.getAttribute('highlightSrc')); cursorY += height + 15; } else { var text = block.getAttribute('text'); var width = Blockly.BlockMenu.BTN_WIDTH; var height = Blockly.BlockMenu.BTN_HEIGHT; Blockly.createSvgElement('path', { 'transform': 'translate(1,1)', 'd': this.btnPath, 'fill': '#aaa' }, button); Blockly.createSvgElement('path', { 'd': this.btnPath, 'fill': '#eee', 'class': 'blocklyBlockMenuBtnPath' }, button); var textElement = Blockly.createSvgElement('text', { 'x': width/2 + 'px', 'y': (height/2 + 4) + 'px', 'font-family': 'ng', 'font-size': Blockly.BlockMenu.BTN_FONT_SIZE, 'text-anchor': 'middle' }, button); var textNode = document.createTextNode(eval(text)); textElement.appendChild(textNode); cursorY += height + 13; } var onclickFunc = block.getAttribute('onclick'); if (onclickFunc && !this.isViewOnly) { button.onclick = (function (func){ return function () {eval(func)}; })(onclickFunc); } this.workspace_.svgBlockCanvas_.appendChild(button); this.buttons_.push(button); continue; } else { var allBlocks = block.getDescendants(); for (var j = 0, child; child = allBlocks[j]; j++) { // Mark blocks as being inside a blockMenu. This is used to detect and // prevent the closure of the blockMenu if the user right-clicks on such a // block. child.isInFlyout = true; // There is no good way to handle comment bubbles inside the blockMenu. // Blocks shouldn't come with predefined comments, but someone will // try this, I'm sure. Kill the comment. Blockly.Comment && child.setCommentText(null); } block.render(); var root = block.getSvgRoot(); var blockHW = block.getHeightWidth(); var x = 10; if (this.isCenterAlign) { x = 200 - blockHW.width/2; } else if (block.outputConnection) { x += blockHW.height/2; var bType = block.type; if (bType == 'get_variable' || bType == 'get_canvas_input_value' || bType == 'value_of_index_from_list' || bType == 'length_of_list') { cursorY += 12; } if (block.outputConnection.check_[0].toUpperCase() == "PARAM") { x += 9; cursorY += 4; } } else if (!block.previousConnection && block.nextConnection){ x += 10; cursorY += 10; } else { cursorY += 7; } block.moveBy(x, cursorY); if (!block.previousConnection && !block.nextConnection){ cursorY += 10; } cursorY += blockHW.height + gaps[i]; if (block.isAddable() && !this.isViewOnly) { this.listeners_.push(Blockly.bindEvent_(root, 'mousedown', null, this.blockMouseDown_(block))); } } } this.width_ = 0; //if (block && block.svg_ && block.svg_.svgGroup_) //console.log(block.svg_.svgGroup_); this.reflow(); //this.filterForCapacity_(); // Fire a resize event to update the blockMenu's scrollbar. Blockly.fireUiEvent(window, 'resize'); this.reflowWrapper_ = Blockly.bindEvent_(this.workspace_.getCanvas(), 'blocklyWorkspaceChange', this, this.reflow); this.workspace_.fireChangeEvent(); return cursorY; }; Blockly.BlockMenu.prototype.banClass = function(className) { var index = this.bannedClass.indexOf(className); if (index < 0) this.bannedClass.push(className); } Blockly.BlockMenu.prototype.unbanClass = function(className) { var index = this.bannedClass.indexOf(className); if (index > -1) this.bannedClass.splice(index, 1); } Blockly.BlockMenu.prototype.checkBanClass = function(blockInfo) { var isNotFor = blockInfo.isNotFor; for (var i in this.bannedClass) { if (isNotFor && isNotFor.indexOf(this.bannedClass[i]) > -1) return true; } return false; } /** * Show category and populate the blockmenu. * @param {object} categoryObject to show. */ Blockly.BlockMenu.prototype.showCategory = function(categoryObject) { this.hide(); var margin = 0; this.menuView_.style.display = 'block'; var objectType = Entry.playground.object.objectType; // Create the blocks to be shown in this blockMenu. var blocks = []; var blockNames = categoryObject.blocks; var gaps = []; var blockClass = ""; for (var i in blockNames) { var blockInfo = EntryStatic.blockInfo[blockNames[i]]; if (this.checkBanClass(blockInfo)) continue; if (blockClass && blockClass != blockInfo.class) { blocks.push('splitter'); gaps.push(0); } var xmlText = blockInfo.xml; if (blockInfo.xmls) var xmls = blockInfo.xmls; else var xmls = [blockInfo.xml]; for (var j in xmls) { xmlText = xmls[j]; var xml = jQuery.parseXML(xmlText).childNodes[0]; if (xml.tagName && xml.tagName.toUpperCase() == 'BTN') { blocks.push(xml); } else { var block = Blockly.Xml.domToBlock( /** @type {!Blockly.Workspace} */ (this.workspace_), xml); block.isInFlyout = true; blocks.push(block); } gaps.push(margin); } blockClass = blockInfo.class; } // Lay out the blocks vertically. var cursorY = 10; for (var i = 0, block; block = blocks[i]; i++) { if (block == 'splitter') { var previousBlock = blocks[i - 1]; var y = previousBlock.outputConnection ? cursorY : cursorY + 5; var splitter = this.createSplitter(64, y, this.view_.style.width.substr(0,3)); this.workspace_.svgBlockCanvas_.appendChild(splitter); this.splitters_.push(splitter); cursorY += 10; continue; } else if (block.tagName && block.tagName.toUpperCase() == 'BTN') { var height = Number(block.getAttribute('height')); var button = Blockly.createSvgElement('g', { 'transform': 'translate(' + (10) + ', ' + cursorY + ')', 'class': 'blocklyBlockMenuBtn' }, null); if (height) { var image = Blockly.createSvgElement('image', {'x': 0, 'y': 0, 'width': block.getAttribute('width') + 'px', 'height': height + 'px' }, button); image.setAttributeNS("http://www.w3.org/1999/xlink", 'xlink:href', block.getAttribute('src')); var highlightImage = Blockly.createSvgElement('image', {'x': 0, 'y': 0, 'width': block.getAttribute('width') + 'px', 'height': height + 'px', 'class': 'blocklyBlockMenuBtnHighlight' }, button); highlightImage.setAttributeNS("http://www.w3.org/1999/xlink", 'xlink:href', block.getAttribute('highlightSrc')); cursorY += height + 10; } else { var text = block.getAttribute('text'); var width = Blockly.BlockMenu.BTN_WIDTH; var height = Blockly.BlockMenu.BTN_HEIGHT; Blockly.createSvgElement('path', { 'transform': 'translate(1,1)', 'd': this.btnPath, 'fill': '#aaa' }, button); Blockly.createSvgElement('path', { 'd': this.btnPath, 'fill': '#eee', 'class': 'blocklyBlockMenuBtnPath' }, button); var textElement = Blockly.createSvgElement('text', { 'x': width/2 + 'px', 'y': (height/2 + 4) + 'px', 'font-family': 'ng', 'font-size': Blockly.BlockMenu.BTN_FONT_SIZE, 'text-anchor': 'middle' }, button); var textNode = document.createTextNode(eval(text)); textElement.appendChild(textNode); cursorY += height + 13; } var onclickFunc = block.getAttribute('onclick'); if (onclickFunc) { button.onclick = (function (func){ return function () {eval(func)}; })(onclickFunc); } this.workspace_.svgBlockCanvas_.appendChild(button); this.buttons_.push(button); continue; } else { var allBlocks = block.getDescendants(); for (var j = 0, child; child = allBlocks[j]; j++) { // Mark blocks as being inside a blockMenu. This is used to detect and // prevent the closure of the blockMenu if the user right-clicks on such a // block. child.isInFlyout = true; // There is no good way to handle comment bubbles inside the blockMenu. // Blocks shouldn't come with predefined comments, but someone will // try this, I'm sure. Kill the comment. Blockly.Comment && child.setCommentText(null); } block.render(); var root = block.getSvgRoot(); var blockHW = block.getHeightWidth(); var x = 10; if (this.isCenterAlign) { x = 200 - blockHW.width/2; } else if (block.outputConnection) { x += blockHW.height/2; var bType = block.type; if (bType == 'get_variable' || bType == 'get_canvas_input_value' || bType == 'value_of_index_from_list' || bType == 'length_of_list') { cursorY += 12; } if (block.outputConnection.check_[0].toUpperCase() == "PARAM") { x += 9; cursorY += 4; } } else if (!block.previousConnection && block.nextConnection){ x += 10; cursorY += 10; } else { cursorY += 7; } block.moveBy(x, cursorY); if (!block.previousConnection && !block.nextConnection){ cursorY += 10; } cursorY += blockHW.height + gaps[i]; if (block.isAddable() && !this.isViewOnly) { this.listeners_.push(Blockly.bindEvent_(root, 'mousedown', null, this.blockMouseDown_(block))); } } } this.width_ = 0; //if (block && block.svg_ && block.svg_.svgGroup_) //console.log(block.svg_.svgGroup_); this.reflow(); //this.filterForCapacity_(); // Fire a resize event to update the blockMenu's scrollbar. Blockly.fireUiEvent(window, 'resize'); this.reflowWrapper_ = Blockly.bindEvent_(this.workspace_.getCanvas(), 'blocklyWorkspaceChange', this, this.reflow); this.workspace_.fireChangeEvent(); return cursorY; }; /** * Hide and empty the blockMenu. */ Blockly.BlockMenu.prototype.hide = function() { // Delete all the event listeners. for (var x = 0, listen; listen = this.listeners_[x]; x++) { Blockly.unbindEvent_(listen); } this.listeners_.splice(0); if (this.reflowWrapper_) { Blockly.unbindEvent_(this.reflowWrapper_); this.reflowWrapper_ = null; } // Delete all the blocks. var blocks = this.workspace_.getTopBlocks(false); for (var x = 0, block; block = blocks[x]; x++) { if (block.workspace == this.workspace_) { block.dispose(false, false); } } for (var i in this.splitters_) { goog.dom.removeNode(this.splitters_[i]); } this.splitters_ = []; for (var i in this.buttons_) { goog.dom.removeNode(this.buttons_[i]); } this.buttons_ = []; // Delete all the background buttons. //for (var x = 0, rect; rect = this.buttons_[x]; x++) { //goog.dom.removeNode(rect); //} //this.buttons_.splice(0); }; /** * Hide and empty the blockMenu. */ Blockly.BlockMenu.prototype.hide = function() { // Delete all the event listeners. for (var x = 0, listen; listen = this.listeners_[x]; x++) { Blockly.unbindEvent_(listen); } this.listeners_.splice(0); if (this.reflowWrapper_) { Blockly.unbindEvent_(this.reflowWrapper_); this.reflowWrapper_ = null; } // Delete all the blocks. var blocks = this.workspace_.getTopBlocks(false); for (var x = 0, block; block = blocks[x]; x++) { if (block.workspace == this.workspace_) { block.dispose(false, false); } } for (var i in this.splitters_) { goog.dom.removeNode(this.splitters_[i]); } this.splitters_ = []; for (var i in this.buttons_) { goog.dom.removeNode(this.buttons_[i]); } this.buttons_ = []; // Delete all the background buttons. //for (var x = 0, rect; rect = this.buttons_[x]; x++) { //goog.dom.removeNode(rect); //} //this.buttons_.splice(0); }; /** */ Blockly.BlockMenu.prototype.createSplitter = function(x, y, width) { var width = Number(width) - 119; var svgGroup = Blockly.createSvgElement('g', { 'transform': 'translate(' + (x-34) + ', ' + y + ')' }, null); Blockly.createSvgElement('path', {'stroke': '#b5b5b5', 'transform': 'translate(0, 1)', 'd': 'M0 0 l' + width + ' 0'}, svgGroup); return svgGroup; }; Blockly.BlockMenu.prototype.updateSplitters = function() { var width = Number(this.view_.style.width.substr(0,3)) - 119 + 64; for (var i in this.splitters_) { var splitter = this.splitters_[i]; splitter.childNodes[0].setAttribute('d', 'M0 0 l' + width + ' 0'); } } /** * Handle a mouse-down on an SVG block in a non-closing blockMenu. * @param {!Blockly.Block} originBlock The blockMenu block to copy. * @return {!Function} Function to call when block is clicked. * @private */ Blockly.BlockMenu.prototype.blockMouseDown_ = function(block) { var blockMenu = this; return function(e) { Blockly.terminateDrag_(); Blockly.hideChaff(); if (Blockly.isRightButton(e)) { // Right-click. if (Blockly.ContextMenu) { block.showContextMenu_(Blockly.mouseToSvg(e)); } } else { // Left-click (or middle click) Blockly.removeAllRanges(); Blockly.setCursorHand_(true); // Record the current mouse position. Blockly.BlockMenu.startDownEvent_ = e; Blockly.BlockMenu.startBlock_ = block; Blockly.BlockMenu.startblockMenu_ = blockMenu; Blockly.BlockMenu.onMouseUpWrapper_ = Blockly.bindEvent_(document, 'mouseup', this, Blockly.terminateDrag_); Blockly.BlockMenu.onMouseMoveWrapper_ = Blockly.bindEvent_(document, 'mousemove', this, blockMenu.onMouseMove_); } // This event has been handled. No need to bubble up to the document. e.stopPropagation(); }; }; /** * Mouse button is down on a block in a non-closing blockMenu. Create the block * if the mouse moves beyond a small radius. This allows one to play with * fields without instantiating blocks that instantly self-destruct. * @param {!Event} e Mouse move event. * @private */ Blockly.BlockMenu.prototype.onMouseMove_ = function(e) { if (e.type == 'mousemove' && e.clientX <= 1 && e.clientY == 0 && e.button == 0) { /* HACK: Safari Mobile 6.0 and Chrome for Android 18.0 fire rogue mousemove events on certain touch actions. Ignore events with these signatures. This may result in a one-pixel blind spot in other browsers, but this shouldn't be noticable. */ e.stopPropagation(); return; } Blockly.removeAllRanges(); var dx = e.clientX - Blockly.BlockMenu.startDownEvent_.clientX; var dy = e.clientY - Blockly.BlockMenu.startDownEvent_.clientY; // Still dragging within the sticky DRAG_RADIUS. var dr = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); if (dr > Blockly.DRAG_RADIUS) { // Create the block. Blockly.BlockMenu.startblockMenu_.createBlockFunc_(Blockly.BlockMenu.startBlock_) (Blockly.BlockMenu.startDownEvent_); } }; /** * Create a copy of this block on the workspace. * @param {!Blockly.Block} originBlock The blockMenu block to copy. * @return {!Function} Function to call when block is clicked. * @private */ Blockly.BlockMenu.prototype.createBlockFunc_ = function(originBlock) { var blockMenu = this; return function(e) { Blockly.scrollBarOff = true; if (Blockly.isRightButton(e)) { // Right-click. Don't create a block, let the context menu show. return; } if (originBlock.disabled) { // Beyond capacity. return; } // Create the new block by cloning the block in the blockMenu (via XML). if (typeof(Entry) == "object") { Entry.dispatchEvent("entryBlocklyChanged"); } var xml = Blockly.Xml.blockToDom_(originBlock); var block = Blockly.Xml.domToBlock(blockMenu.workspace_, xml); block.isInBlockMenu = true; // Place it in the same spot as the blockMenu copy. var svgRootOld = originBlock.getSvgRoot(); if (!svgRootOld) { throw 'originBlock is not rendered.'; } var xyOld = Blockly.getSvgXY_(svgRootOld); var svgRootNew = block.getSvgRoot(); if (!svgRootNew) { throw 'block is not rendered.'; } var xyNew = Blockly.getSvgXY_(svgRootNew); block.setDragging_(true); block.svg_.addSelect(); block.moveBy(xyOld.x - xyNew.x, xyOld.y - xyNew.y); block.startDragX = xyOld.x - xyNew.x; block.startDragY = xyOld.y - xyNew.y; var workspaceBlock = Blockly.Xml.domToBlock(blockMenu.targetWorkspace, xml); var svgRootNewWorkspace = workspaceBlock.getSvgRoot(); if (!svgRootNewWorkspace) { throw 'block is not rendered.'; } var xyNewWorkspace = Blockly.getSvgXY_(svgRootNewWorkspace); var workspace = Blockly.mainWorkspace; var borderWidth = $(workspace.svgGroup_.parentNode.parentNode).css('border-width'); borderWidth = borderWidth.substring(0, borderWidth.length-2); var blockMenuWorkspace = $(workspace.blockMenu.view_).position(); var playgroundBlockly = $(workspace.svgGroup_.parentNode.parentNode).eq(0).position(); var stalkerX = xyOld.x - xyNewWorkspace.x - playgroundBlockly.left + blockMenuWorkspace.left; var stalkerY = xyOld.y - xyNewWorkspace.y + blockMenuWorkspace.top - playgroundBlockly.top - borderWidth; workspaceBlock.moveBy(stalkerX, stalkerY); // Start a dragging operation on the new block. workspaceBlock.isInBlockMenu = true; workspaceBlock.setStalkerBlock(block); block.setStalkerBlock(workspaceBlock); workspaceBlock.onMouseDown_(e); }; }; /** * Compute width of flyout. Position button under each block. */ Blockly.BlockMenu.prototype.reflow = function() { var blockMenuWidth = 0; var margin = this.CORNER_RADIUS; var blocks = this.workspace_.getTopBlocks(false); for (var x = 0, block; block = blocks[x]; x++) { var root = block.getSvgRoot(); var blockHW = block.getHeightWidth(); blockMenuWidth = Math.max(blockMenuWidth, blockHW.width); } this.blockMenuWidth = blockMenuWidth; blockMenuWidth += margin + Blockly.BlockSvg.TAB_WIDTH + margin / 2 + Blockly.Scrollbar.scrollbarThickness; if (this.width_ != blockMenuWidth) { for (var x = 0, block; block = blocks[x]; x++) { var blockHW = block.getHeightWidth(); var blockXY = block.getRelativeToSurfaceXY(); if (Blockly.RTL) { // With the blockMenuWidth known, right-align the blocks. var dx = blockMenuWidth - margin - Blockly.BlockSvg.TAB_WIDTH - blockXY.x; block.moveBy(dx, 0); blockXY.x += dx; } //if (block.blockMenuRect_) { //block.blockMenuRect_.setAttribute('width', blockHW.width); //block.blockMenuRect_.setAttribute('height', blockHW.height); //block.blockMenuRect_.setAttribute('x', //Blockly.RTL ? blockXY.x - blockHW.width : blockXY.x); //block.blockMenuRect_.setAttribute('y', blockXY.y); //} } // Record the width for .getMetrics_ and .position_. this.width_ = blockMenuWidth; // Fire a resize event to update the blockMenu's scrollbar. Blockly.fireUiEvent(window, 'resize'); } }; /** * return metrices for workspace * @private */ Blockly.BlockMenu.prototype.getMetrics_ = function() { var rect = this.view_.getBoundingClientRect(); try { var optionBox = this.workspace_.getCanvas().getBBox(); } catch (e) { // Firefox has trouble with hidden elements (Bug 528969). var optionBox = {height: 0, y: 0}; } var metrics = { viewHeight: rect.height, viewWidth: rect.width, contentHeight: optionBox.height + optionBox.y, viewTop: -this.workspace_.scrollY, contentTop: 0, absoluteTop: 0, absoluteLeft: 0 }; return metrics; }; /** * Sets the Y translation of the flyout to match the scrollbars. * @param {!Object} yRatio Contains a y property which is a float * between 0 and 1 specifying the degree of scrolling. * @private */ Blockly.BlockMenu.prototype.setMetrics_ = function(yRatio) { var metrics = this.getMetrics_(); // This is a fix to an apparent race condition. if (!metrics) { return; } if (goog.isNumber(yRatio.y)) { this.workspace_.scrollY = -metrics.contentHeight * yRatio.y - metrics.contentTop; } var y = this.workspace_.scrollY + metrics.absoluteTop; this.workspace_.getCanvas().setAttribute('transform', 'translate(0,' + y + ')'); }; /** * Stop binding to the global mouseup and mousemove events. * @private */ Blockly.BlockMenu.terminateDrag_ = function() { if (Blockly.BlockMenu.onMouseUpWrapper_) { Blockly.unbindEvent_(Blockly.BlockMenu.onMouseUpWrapper_); Blockly.BlockMenu.onMouseUpWrapper_ = null; } if (Blockly.BlockMenu.onMouseMoveWrapper_) { Blockly.unbindEvent_(Blockly.BlockMenu.onMouseMoveWrapper_); Blockly.BlockMenu.onMouseMoveWrapper_ = null; } Blockly.BlockMenu.startDownEvent_ = null; Blockly.BlockMenu.startBlock_ = null; Blockly.BlockMenu.startFlyout_ = null; }; /** * Update view when window resizing * @private */ Blockly.BlockMenu.prototype.syncViewSize_ = function() { var rect = this.view_.getBoundingClientRect(); this.menuView_.style.width = rect.width + 'px'; this.menuView_.style.height = rect.height + 'px'; this.scrollbar_.resize(); }; ================================================ FILE: extern/blockly/core/block_svg.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Methods for graphically rendering a block as SVG. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.BlockSvg'); goog.require('goog.userAgent'); /** * Class for a block's SVG representation. * @param {!Blockly.Block} block The underlying block object. * @constructor */ Blockly.BlockSvg = function(block) { this.block_ = block; // Create core elements for the block. this.svgGroup_ = Blockly.createSvgElement('g', {}, null); this.svgGroup_.block = this.block_; this.svgPathDark_ = Blockly.createSvgElement('path', {'class': 'blocklyPathDark', 'transform': 'translate(0, 1)'}, this.svgGroup_); this.svgPath_ = Blockly.createSvgElement('path', {'class': 'blocklyPath'}, this.svgGroup_); if (Blockly.enableBlockAnimation) { this.svgPathPatternA_ = Blockly.createSvgElement('path', { 'id': 'blocklyPathPattern1', 'class': 'blocklyPathPattern'}, this.svgGroup_); this.svgPathPatternB_ = Blockly.createSvgElement('path', { 'id': 'blocklyPathPattern2', 'class': 'blocklyPathPattern'}, this.svgGroup_); this.svgPathPatternC_ = Blockly.createSvgElement('path', { 'id': 'blocklyPathPattern3', 'class': 'blocklyPathPattern'}, this.svgGroup_); this.svgPathPatternD_ = Blockly.createSvgElement('path', { 'id': 'blocklyPathPattern4', 'class': 'blocklyPathPattern'}, this.svgGroup_); } if (this.block_.outputConnection) this.svgPathLight_ = Blockly.createSvgElement('path', {'class': 'blocklyPathLight'}, this.svgGroup_); this.svgPath_.tooltip = this.block_; Blockly.Tooltip && Blockly.Tooltip.bindMouseEvents(this.svgPath_); this.updateMovable(); }; /** * Constant for identifying rows that are to be rendered inline. * Don't collide with Blockly.INPUT_VALUE and friends. * @const */ Blockly.BlockSvg.INLINE = -1; /** * Initialize the SVG representation with any block attributes which have * already been defined. */ Blockly.BlockSvg.prototype.init = function() { var block = this.block_; this.updateColour(); for (var x = 0, input; input = block.inputList[x]; x++) { input.init(); } if (block.mutator) { block.mutator.createIcon(); } }; /** * Add or remove the UI indicating if this block is movable or not. */ Blockly.BlockSvg.prototype.updateMovable = function() { if (this.block_.isMovable()) { Blockly.addClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable'); } else { Blockly.removeClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklyDraggable'); } }; Blockly.BlockSvg.prototype.toggleOnPattern = function(e) { Blockly.addClass_(this.svgGroup_.parentNode, 'disablePattern'); Blockly.addClass_(/** @type {!Element} */ (this.svgGroup_), 'togglePattern'); }; Blockly.BlockSvg.prototype.toggleOffPattern = function(e) { Blockly.removeClass_(this.svgGroup_.parentNode, 'disablePattern'); Blockly.removeClass_(/** @type {!Element} */ (this.svgGroup_), 'togglePattern'); }; /** * Get the root SVG element. * @return {!Element} The root SVG element. */ Blockly.BlockSvg.prototype.getRootElement = function() { return this.svgGroup_; }; // UI constants for rendering blocks. /** * Horizontal space between elements. * @const */ Blockly.BlockSvg.SEP_SPACE_X = 4; /** * Vertical space between elements. * @const */ Blockly.BlockSvg.SEP_SPACE_Y = 10; /** * Vertical padding around inline elements. * @const */ Blockly.BlockSvg.INLINE_PADDING_Y = 2; /** * Minimum height of a block. * @const */ Blockly.BlockSvg.MIN_BLOCK_Y = 30; /** * Minimum height of a block. * @const */ Blockly.BlockSvg.MIN_INLINE_BLOCK_Y = 20; /** * Height of horizontal puzzle tab. * @const */ Blockly.BlockSvg.TAB_HEIGHT = 20; /** * Width of horizontal puzzle tab. * @const */ Blockly.BlockSvg.TAB_WIDTH = 8; /** * Width of vertical tab (inc left margin). * @const */ Blockly.BlockSvg.NOTCH_WIDTH = 16; /** * Rounded corner radius. * @const */ Blockly.BlockSvg.CORNER_RADIUS = 0; /** * Minimum height of field rows. * @const */ Blockly.BlockSvg.FIELD_HEIGHT = 0; /** * Distance from shape edge to intersect with a curved corner at 45 degrees. * Applies to highlighting on around the inside of a curve. * @const */ Blockly.BlockSvg.DISTANCE_45_INSIDE = (1 - Math.SQRT1_2) * (Blockly.BlockSvg.CORNER_RADIUS - 1) + 1; /** * Distance from shape edge to intersect with a curved corner at 45 degrees. * Applies to highlighting on around the outside of a curve. * @const */ Blockly.BlockSvg.DISTANCE_45_OUTSIDE = (1 - Math.SQRT1_2) * (Blockly.BlockSvg.CORNER_RADIUS + 1) - 1; /** * SVG path for drawing next/previous notch from left to right. * @const */ //Blockly.BlockSvg.NOTCH_PATH_LEFT = 'l 6,4 3,0 6,-4'; Blockly.BlockSvg.NOTCH_PATH_LEFT = 'l 8,8 8,-8'; /** * SVG path for drawing next/previous notch from left to right with * highlighting. * @const */ Blockly.BlockSvg.NOTCH_PATH_LEFT_HIGHLIGHT = 'l 6.5,4 2,0 6.5,-4'; /** * SVG path for drawing next/previous notch from right to left. * @const */ //Blockly.BlockSvg.NOTCH_PATH_RIGHT = 'l -6,4 -3,0 -6,-4'; Blockly.BlockSvg.NOTCH_PATH_RIGHT = 'l -8,8 -8,-8'; /** * SVG path for drawing jagged teeth at the end of collapsed blocks. * @const */ Blockly.BlockSvg.JAGGED_TEETH = 'l 8,0 0,4 8,4 -16,8 8,4'; /** * SVG path for drawing jagged teeth at the end of collapsed blocks. * @const */ Blockly.BlockSvg.JAGGED_TEETH_HEIGHT = 20; /** * SVG path for drawing a horizontal puzzle tab from top to bottom. * @const */ Blockly.BlockSvg.TAB_PATH_DOWN = 'v 5 c 0,10 -' + Blockly.BlockSvg.TAB_WIDTH + ',-8 -' + Blockly.BlockSvg.TAB_WIDTH + ',7.5 s ' + Blockly.BlockSvg.TAB_WIDTH + ',-2.5 ' + Blockly.BlockSvg.TAB_WIDTH + ',7.5'; /** * SVG path for drawing a horizontal puzzle tab from top to bottom with * highlighting from the upper-right. * @const */ Blockly.BlockSvg.TAB_PATH_DOWN_HIGHLIGHT_RTL = 'v 6.5 m -' + (Blockly.BlockSvg.TAB_WIDTH * 0.98) + ',2.5 q -' + (Blockly.BlockSvg.TAB_WIDTH * .05) + ',10 ' + (Blockly.BlockSvg.TAB_WIDTH * .27) + ',10 m ' + (Blockly.BlockSvg.TAB_WIDTH * .71) + ',-2.5 v 1.5'; /** * SVG start point for drawing the top-left corner. * @const */ Blockly.BlockSvg.TOP_LEFT_CORNER_START = 'm 0,' + Blockly.BlockSvg.CORNER_RADIUS; /** * SVG start point for drawing the top-left corner's highlight in RTL. * @const */ Blockly.BlockSvg.TOP_LEFT_CORNER_START_HIGHLIGHT_RTL = 'm ' + Blockly.BlockSvg.DISTANCE_45_INSIDE + ',' + Blockly.BlockSvg.DISTANCE_45_INSIDE; /** * SVG start point for drawing the top-left corner's highlight in LTR. * @const */ Blockly.BlockSvg.TOP_LEFT_CORNER_START_HIGHLIGHT_LTR = 'm 1,' + (Blockly.BlockSvg.CORNER_RADIUS - 1); /** * SVG path for drawing the rounded top-left corner. * @const */ Blockly.BlockSvg.TOP_LEFT_CORNER = 'A ' + Blockly.BlockSvg.CORNER_RADIUS + ',' + Blockly.BlockSvg.CORNER_RADIUS + ' 0 0,1 ' + Blockly.BlockSvg.CORNER_RADIUS + ',0'; /** * SVG path for drawing the highlight on the rounded top-left corner. * @const */ Blockly.BlockSvg.TOP_LEFT_CORNER_HIGHLIGHT = 'A ' + (Blockly.BlockSvg.CORNER_RADIUS - 1) + ',' + (Blockly.BlockSvg.CORNER_RADIUS - 1) + ' 0 0,1 ' + Blockly.BlockSvg.CORNER_RADIUS + ',1'; /** * SVG path for drawing the top-left corner of a statement input. * Includes the top notch, a horizontal space, and the rounded inside corner. * @const */ Blockly.BlockSvg.INNER_TOP_LEFT_CORNER = Blockly.BlockSvg.NOTCH_PATH_RIGHT + ' h -0.6 h' + (Blockly.BlockSvg.CORNER_RADIUS) + ' a ' + Blockly.BlockSvg.CORNER_RADIUS + ',' + Blockly.BlockSvg.CORNER_RADIUS + ' 0 0,0 -' + Blockly.BlockSvg.CORNER_RADIUS + ',' + Blockly.BlockSvg.CORNER_RADIUS; /** * SVG path for drawing the bottom-left corner of a statement input. * Includes the rounded inside corner. * @const */ Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER = 'a ' + Blockly.BlockSvg.CORNER_RADIUS + ',' + Blockly.BlockSvg.CORNER_RADIUS + ' 0 0,0 ' + Blockly.BlockSvg.CORNER_RADIUS + ',' + Blockly.BlockSvg.CORNER_RADIUS; /** * SVG path for drawing highlight on the top-left corner of a statement * input in RTL. * @const */ Blockly.BlockSvg.INNER_TOP_LEFT_CORNER_HIGHLIGHT_RTL = 'a ' + (Blockly.BlockSvg.CORNER_RADIUS + 1) + ',' + (Blockly.BlockSvg.CORNER_RADIUS + 1) + ' 0 0,0 ' + (-Blockly.BlockSvg.DISTANCE_45_OUTSIDE - 1) + ',' + (Blockly.BlockSvg.CORNER_RADIUS - Blockly.BlockSvg.DISTANCE_45_OUTSIDE); /** * SVG path for drawing highlight on the bottom-left corner of a statement * input in RTL. * @const */ Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_RTL = 'a ' + (Blockly.BlockSvg.CORNER_RADIUS + 1) + ',' + (Blockly.BlockSvg.CORNER_RADIUS + 1) + ' 0 0,0 ' + (Blockly.BlockSvg.CORNER_RADIUS + 1) + ',' + (Blockly.BlockSvg.CORNER_RADIUS + 1); /** * SVG path for drawing highlight on the bottom-left corner of a statement * input in LTR. * @const */ Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER_HIGHLIGHT_LTR = 'a ' + (Blockly.BlockSvg.CORNER_RADIUS + 1) + ',' + (Blockly.BlockSvg.CORNER_RADIUS + 1) + ' 0 0,0 ' + (Blockly.BlockSvg.CORNER_RADIUS - Blockly.BlockSvg.DISTANCE_45_OUTSIDE) + ',' + (Blockly.BlockSvg.DISTANCE_45_OUTSIDE + 1); /** * Dispose of this SVG block. */ Blockly.BlockSvg.prototype.dispose = function() { goog.dom.removeNode(this.svgGroup_); // Sever JavaScript to DOM connections. this.svgGroup_ = null; this.svgPath_ = null; if (Blockly.enableBlockAnimation) { this.svgPathPatternA_ = null; this.svgPathPatternB_ = null; this.svgPathPatternC_ = null; this.svgPathPatternD_ = null; } this.svgPathLight_ = null; this.svgPathDark_ = null; // Break circular references. this.block_ = null; }; /** * Play some UI effects (sound, animation) when disposing of a block. */ Blockly.BlockSvg.prototype.disposeUiEffect = function() { Blockly.playAudio('delete'); var xy = Blockly.getSvgXY_(/** @type {!Element} */ (this.svgGroup_)); // Deeply clone the current block. var clone = this.svgGroup_.cloneNode(true); clone.translateX_ = xy.x; clone.translateY_ = xy.y; clone.setAttribute('transform', 'translate(' + clone.translateX_ + ',' + clone.translateY_ + ')'); Blockly.svg.appendChild(clone); clone.bBox_ = clone.getBBox(); // Start the animation. clone.startDate_ = new Date(); Blockly.BlockSvg.disposeUiStep_(clone); }; /** * Animate a cloned block and eventually dispose of it. * @param {!Element} clone SVG element to animate and dispose of. * @private */ Blockly.BlockSvg.disposeUiStep_ = function(clone) { var textNodes = clone.getElementsByTagName('text'); if (textNodes) { for (var i=0; i 1) { goog.dom.removeNode(clone); } else { var x = clone.translateX_ + (Blockly.RTL ? -1 : 1) * clone.bBox_.width / 2 * percent; var y = clone.translateY_ + clone.bBox_.height * percent; var translate = x + ', ' + y; var scale = 1 - percent; clone.setAttribute('transform', 'translate(' + translate + ')' + ' scale(' + scale + ')'); var closure = function() { Blockly.BlockSvg.disposeUiStep_(clone); }; window.setTimeout(closure, 10); } }; /** * Play some UI effects (sound, ripple) after a connection has been established. */ Blockly.BlockSvg.prototype.connectionUiEffect = function() { Blockly.playAudio('click'); // Determine the absolute coordinates of the inferior block. var xy = Blockly.getSvgXY_(/** @type {!Element} */ (this.svgGroup_)); // Offset the coordinates based on the two connection types. if (this.block_.outputConnection) { xy.x += Blockly.RTL ? 3 : -3; xy.y += 13; } else if (this.block_.previousConnection) { xy.x += Blockly.RTL ? -23 : 23; xy.y += 3; } var ripple = Blockly.createSvgElement('circle', {'cx': xy.x, 'cy': xy.y, 'r': 0, 'fill': 'none', 'stroke': '#888', 'stroke-width': 10}, Blockly.svg); // Start the animation. ripple.startDate_ = new Date(); Blockly.BlockSvg.connectionUiStep_(ripple); }; /** * Expand a ripple around a connection. * @param {!Element} ripple Element to animate. * @private */ Blockly.BlockSvg.connectionUiStep_ = function(ripple) { var ms = (new Date()) - ripple.startDate_; var percent = ms / 150; if (percent > 1) { goog.dom.removeNode(ripple); } else { ripple.setAttribute('r', percent * 25); ripple.style.opacity = 1 - percent; var closure = function() { Blockly.BlockSvg.connectionUiStep_(ripple); }; window.setTimeout(closure, 10); } }; /** * Change the colour of a block. */ Blockly.BlockSvg.prototype.updateColour = function() { if (this.block_.disabled) { // Disabled blocks don't have colour. return; } var hexColour = Blockly.makeColour(this.block_.getColour()); var rgb = goog.color.hexToRgb(hexColour); var rgbLight = goog.color.darken(rgb, 0.1); var rgbDark = goog.color.darken(rgb, 0.3); if (this.block_.outputConnection) this.svgPathLight_.setAttribute('stroke', goog.color.rgbArrayToHex(rgbLight)); if (this.block_.outputConnection) if (this.block_.parentBlock_) this.svgPathDark_.setAttribute('opacity', 0); else this.svgPathDark_.removeAttribute('opacity'); this.svgPathDark_.setAttribute('fill', goog.color.rgbArrayToHex(rgbDark)); this.svgPath_.setAttribute('fill', hexColour); if (Blockly.enableBlockAnimation) { this.svgPathPatternA_.setAttribute('fill', 'url(#blockPattern1)'); Blockly.createSvgElement('animate', { 'attributeName': 'opacity', 'values': '0;0.2;0;0', 'repeatCount': 'indefinite', 'begin': '0', 'dur': '1.4s' }, this.svgPathPatternA_); this.svgPathPatternB_.setAttribute('fill', 'url(#blockPattern2)'); Blockly.createSvgElement('animate', { 'attributeName': 'opacity', 'values': '0;0.2;0;0', 'repeatCount': 'indefinite', 'begin': '0.33', 'dur': '1.4s' }, this.svgPathPatternB_); this.svgPathPatternC_.setAttribute('fill', 'url(#blockPattern3)'); Blockly.createSvgElement('animate', { 'attributeName': 'opacity', 'values': '0;0.2;0;0', 'repeatCount': 'indefinite', 'begin': '0.67', 'dur': '1.4s' }, this.svgPathPatternC_); this.svgPathPatternD_.setAttribute('fill', 'url(#blockPattern4)'); } Blockly.createSvgElement('animate', { 'attributeName': 'opacity', 'values': '0;0.2;0;0', 'repeatCount': 'indefinite', 'begin': '1', 'dur': '1.4s' }, this.svgPathPatternD_); }; /** * Enable or disable a block. */ Blockly.BlockSvg.prototype.updateDisabled = function() { if (this.block_.disabled || this.block_.getInheritedDisabled()) { Blockly.addClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled'); this.svgPath_.setAttribute('fill', 'gray'); } else { Blockly.removeClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled'); this.updateColour(); } var children = this.block_.getChildren(); for (var x = 0, child; child = children[x]; x++) { child.svg_.updateDisabled(); } }; /** * Select this block. Highlight it visually. */ Blockly.BlockSvg.prototype.addSelect = function() { Blockly.addClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklySelected'); // Move the selected block to the top of the stack. if (this.block_.isInBlockMenu) return; this.svgGroup_.parentNode.appendChild(this.svgGroup_); }; /** * Unselect this block. Remove its highlighting. */ Blockly.BlockSvg.prototype.removeSelect = function() { Blockly.removeClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklySelected'); Blockly.removeClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklyActivated'); }; /** * Activate this block. Highlight it visually. */ Blockly.BlockSvg.prototype.addActive = function() { Blockly.addClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklyActivated'); // Move the selected block to the top of the stack. this.svgGroup_.parentNode.appendChild(this.svgGroup_); }; /** * Activate this block. Remove its highlighting. */ Blockly.BlockSvg.prototype.removeActive = function() { Blockly.removeClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklyActivated'); }; /** * Adds the dragging class to this block. * Also disables the highlights/shadows to improve performance. */ Blockly.BlockSvg.prototype.addDragging = function() { Blockly.addClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklyDragging'); }; /** * Removes the dragging class from this block. */ Blockly.BlockSvg.prototype.removeDragging = function() { Blockly.removeClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklyDragging'); }; /** * Render the block. * Lays out and reflows a block based on its contents and settings. */ Blockly.BlockSvg.prototype.render = function() { this.block_.rendered = true; var cursorX = Blockly.BlockSvg.SEP_SPACE_X; // Move the icons into position. var icons = this.block_.getIcons(); for (var x = 0; x < icons.length; x++) { cursorX = icons[x].renderIcon(cursorX); } cursorX += Blockly.RTL ? Blockly.BlockSvg.SEP_SPACE_X : -Blockly.BlockSvg.SEP_SPACE_X; // If there are no icons, cursorX will be 0, otherwise it will be the // width that the first label needs to move over by. var inputRows = this.renderCompute_(cursorX); this.renderDraw_(cursorX, inputRows); // Render all blocks above this one (propagate a reflow). var parentBlock = this.block_.getParent(); if (parentBlock) { parentBlock.render(); } else { // Top-most block. Fire an event to allow scrollbars to resize. //Blockly.fireUiEvent(window, 'resize'); // Remove. It's too heavy. } }; /** * Render a list of fields starting at the specified location. * @param {!Array.} fieldList List of fields. * @param {number} cursorX X-coordinate to start the fields. * @param {number} cursorY Y-coordinate to start the fields. * @param {number} rowHeight row height. * @return {number} X-coordinate of the end of the field row (plus a gap). * @private */ Blockly.BlockSvg.prototype.renderFields_ = function(fieldList, cursorX, cursorY, rowHeight) { for (var t = 0, field; field = fieldList[t]; t++) { // Get the dimensions of the field. if (field.isTextInput && fieldList.length ==1) cursorX -= 4; var fieldSize = field.getSize(); var fieldWidth = fieldSize.width; var fieldY = cursorY + (rowHeight - fieldSize.height)/ 2; field.getRootElement().setAttribute('transform', 'translate(' + cursorX + ', ' + fieldY + ')'); if (fieldWidth) { cursorX += fieldWidth + Blockly.BlockSvg.SEP_SPACE_X; } if (field.isTextInput && fieldList.length ==1) cursorX += 4; } return Blockly.RTL ? -cursorX : cursorX; }; /** * Computes the height and widths for each row and field. * @param {number} iconWidth Offset of first row due to icons. * @return {!Array.>} 2D array of objects, each containing * position information. * @private */ Blockly.BlockSvg.prototype.renderCompute_ = function(iconWidth) { var inputList = this.block_.inputList; var inputRows = []; inputRows.rightEdge = iconWidth + Blockly.BlockSvg.SEP_SPACE_X * 2; if (this.block_.previousConnection || this.block_.nextConnection) { inputRows.rightEdge = Math.max(inputRows.rightEdge, Blockly.BlockSvg.NOTCH_WIDTH + Blockly.BlockSvg.SEP_SPACE_X); } var fieldValueWidth = 0; // Width of longest external value field. var fieldStatementWidth = 0; // Width of longest statement field. var hasValue = false; var hasStatement = false; var hasDummy = false; var lastType = undefined; var isInline = this.block_.inputsInline && !this.block_.isCollapsed(); for (var i = 0, input; input = inputList[i]; i++) { if (!input.isVisible()) { continue; } var row; if (!isInline || !lastType || lastType == Blockly.NEXT_STATEMENT || input.type == Blockly.NEXT_STATEMENT) { // Create new row. lastType = input.type; row = []; if (isInline && input.type != Blockly.NEXT_STATEMENT) { row.type = Blockly.BlockSvg.INLINE; } else { row.type = input.type; } row.height = 0; inputRows.push(row); } else { row = inputRows[inputRows.length - 1]; } row.push(input); // Compute minimum input size. if (input.sourceBlock_.outputConnection) input.renderHeight = Blockly.BlockSvg.MIN_INLINE_BLOCK_Y; else input.renderHeight = Blockly.BlockSvg.MIN_BLOCK_Y; // The width is currently only needed for inline value inputs. if (isInline && input.type == Blockly.INPUT_VALUE) { input.renderWidth = Blockly.BlockSvg.TAB_WIDTH + Blockly.BlockSvg.SEP_SPACE_X; } else { input.renderWidth = 0; } // Expand input size if there is a connection. if (input.connection && input.connection.targetConnection) { var linkedBlock = input.connection.targetBlock(); var bBox = linkedBlock.getHeightWidth(); input.renderHeight = Blockly.BlockSvg.MIN_INLINE_BLOCK_Y; input.renderHeight = Math.max(input.renderHeight, bBox.height); input.renderWidth = Math.max(input.renderWidth, bBox.width); } row.height = Math.max(row.height, input.renderHeight); input.fieldWidth = 0; if (inputRows.length == 1) { // The first row gets shifted to accommodate any icons. input.fieldWidth += Blockly.RTL ? -iconWidth : iconWidth; } for (var j = 0, field; field = input.fieldRow[j]; j++) { if (j == 0 && field instanceof Blockly.FieldIcon) continue; if (j != 0) { input.fieldWidth += Blockly.BlockSvg.SEP_SPACE_X; } // Get the dimensions of the field. var fieldSize = field.getSize(); input.fieldWidth += fieldSize.width; row.height = Math.max(row.height, fieldSize.height); } if (row.type != Blockly.BlockSvg.INLINE) { if (row.type == Blockly.NEXT_STATEMENT) { hasStatement = true; fieldStatementWidth = Math.max(fieldStatementWidth, input.fieldWidth); } else { if (row.type == Blockly.INPUT_VALUE) { hasValue = true; } else if (row.type == Blockly.DUMMY_INPUT) { hasDummy = true; } fieldValueWidth = Math.max(fieldValueWidth, input.fieldWidth); } } } // Make inline rows a bit thicker in order to enclose the values. for (var y = 0, row; row = inputRows[y]; y++) { row.thicker = false; if (row.type == Blockly.BlockSvg.INLINE) { for (var z = 0, input; input = row[z]; z++) { if (input.type == Blockly.INPUT_VALUE) { if (this.block_.outputConnection) { row.height += 2 * Blockly.BlockSvg.INLINE_PADDING_Y; if (this.block_.outputConnection.check_[0].toUpperCase() == "PARAM") row.height = Blockly.BlockSvg.MIN_BLOCK_Y - 6; } row.thicker = true; break; } } } this.height = row.height+10; } // Compute the statement edge. // This is the width of a block where statements are nested. inputRows.statementEdge = 2 * Blockly.BlockSvg.SEP_SPACE_X + fieldStatementWidth; // Compute the preferred right edge. Inline blocks may extend beyond. // This is the width of the block where external inputs connect. if (hasStatement) { inputRows.rightEdge = Math.max(inputRows.rightEdge, inputRows.statementEdge + Blockly.BlockSvg.NOTCH_WIDTH); } if (hasValue) { inputRows.rightEdge = Math.max(inputRows.rightEdge, fieldValueWidth + Blockly.BlockSvg.SEP_SPACE_X * 2 + Blockly.BlockSvg.TAB_WIDTH); } else if (hasDummy) { inputRows.rightEdge = Math.max(inputRows.rightEdge, fieldValueWidth + Blockly.BlockSvg.SEP_SPACE_X * 2); } inputRows.hasValue = hasValue; inputRows.hasStatement = hasStatement; inputRows.hasDummy = hasDummy; return inputRows; }; /** * Draw the path of the block. * Move the fields to the correct locations. * @param {number} iconWidth Offset of first row due to icons. * @param {!Array.>} inputRows 2D array of objects, each * containing position information. * @private */ Blockly.BlockSvg.prototype.renderDraw_ = function(iconWidth, inputRows) { // Should the top and bottom left corners be rounded or square? if (this.block_.outputConnection) { this.squareTopLeftCorner_ = true; this.squareBottomLeftCorner_ = true; this.squareTopLeftCorner_ = false; this.squareBottomLeftCorner_ = false; // If this block is in the middle of a stack, square the corners. if (this.block_.previousConnection) { var prevBlock = this.block_.previousConnection.targetBlock(); if (prevBlock && prevBlock.nextConnection && prevBlock.nextConnection.targetConnection == this.block_.previousConnection) { this.squareTopLeftCorner_ = true; } } if (this.block_.nextConnection) { var nextBlock = this.block_.nextConnection.targetBlock(); if (nextBlock && nextBlock.previousConnection && nextBlock.previousConnection.targetConnection == this.block_.nextConnection) { this.squareBottomLeftCorner_ = true; } } } // Fetch the block's coordinates on the surface for use in anchoring // the connections. var connectionsXY = this.block_.getRelativeToSurfaceXY(); // Assemble the block's path. var steps = []; var inlineSteps = []; // The highlighting applies to edges facing the upper-left corner. // Since highlighting is a two-pixel wide border, it would normally overhang // the edge of the block by a pixel. So undersize all measurements by a pixel. this.renderDrawTop_(steps, connectionsXY, inputRows); var cursorY = this.renderDrawRight_(steps, inlineSteps, connectionsXY, inputRows, iconWidth); this.renderDrawBottom_(steps, connectionsXY, cursorY); this.renderDrawLeft_(steps, connectionsXY, cursorY, inputRows); var pathString = steps.join(' ') + '\n' + inlineSteps.join(' '); this.svgPath_.setAttribute('d', pathString); if (Blockly.enableBlockAnimation) { this.svgPathPatternA_.setAttribute('d', pathString); this.svgPathPatternB_.setAttribute('d', pathString); this.svgPathPatternC_.setAttribute('d', pathString); this.svgPathPatternD_.setAttribute('d', pathString); } this.svgPathDark_.setAttribute('d', pathString); if (this.block_.outputConnection) this.svgPathLight_.setAttribute('d', pathString); var block = this.block_; if (block.previousConnection && !block.nextConnection && !block.outputConnection && !block.dummySpace ) { block.dummySpace = true; var rect = Blockly.createSvgElement('rect', {'class':'BlockSpaceDummy', 'height': '9', 'width':'10', 'y':(this.height - 10), 'opacity': '0'}, block.svg_.svgGroup_); } }; /** * Render the top edge of the block. * @param {!Array.} steps Path of block outline. * @param {!Object} connectionsXY Location of block. * @param {!Array.>} inputRows 2D array of objects, each * containing position information. * @private */ Blockly.BlockSvg.prototype.renderDrawTop_ = function(steps, connectionsXY, inputRows) { // Position the cursor at the top-left starting point. //if (this.squareTopLeftCorner_) { var rightEdge = inputRows.rightEdge; if (true) { steps.push('m 0,0'); } else { steps.push(Blockly.BlockSvg.TOP_LEFT_CORNER_START); // Top-left rounded corner. steps.push(Blockly.BlockSvg.TOP_LEFT_CORNER); } if (Blockly.BROKEN_CONTROL_POINTS) { /* HACK: WebKit bug 67298 causes control points to be included in the reported bounding box. Add 5px control point to the top of the path. */ steps.push('c 0,4 0,-4 0,0'); } var firstRow = inputRows[0][0].fieldRow; // Top edge. if (this.block_.previousConnection) { steps.push('H', 0); steps.push(Blockly.BlockSvg.NOTCH_PATH_LEFT); // Create previous block connection. var connectionX = connectionsXY.x + Blockly.BlockSvg.NOTCH_WIDTH; var connectionY = connectionsXY.y; this.block_.previousConnection.moveTo(connectionX, connectionY); // This connection will be tightened when the parent renders. } else if (firstRow[0] instanceof Blockly.FieldIcon) { steps.push('m', '0,-5'); steps.push('a', '19.5,19.5 0, 0,1 16,0'); steps.push('c', '10,5 15,5 20,5'); } //steps.push('H', rightEdge); }; /** * Render the right edge of the block. * @param {!Array.} steps Path of block outline. * @param {!Array.} inlineSteps Inline block outlines. * @param {!Object} connectionsXY Location of block. * @param {!Array.>} inputRows 2D array of objects, each * containing position information. * @param {number} iconWidth Offset of first row due to icons. * @return {number} Height of block. * @private */ Blockly.BlockSvg.prototype.renderDrawRight_ = function(steps, inlineSteps, connectionsXY, inputRows, iconWidth) { var cursorX; var cursorY = 0; var connectionX, connectionY; var blockWidth; for (var y = 0, row; row = inputRows[y]; y++) { cursorX = Blockly.BlockSvg.SEP_SPACE_X; if (y == 0) { cursorX += Blockly.RTL ? -iconWidth : iconWidth; } if (y == 0 && this.block_.outputConnection) { if (row[0].type == Blockly.INPUT_VALUE) cursorX -= row.height/2 + 2; else if (this.block_.outputConnection.check_[0].toUpperCase() == "PARAM") cursorX -= 8; else cursorX -= row.height/2 - 5; } else if (y != 0) { cursorX += 33; cursorY -=2; } else if (inputRows[0][0].fieldRow[0] instanceof Blockly.FieldIcon) { cursorX -= 13; } else if (!this.block_.previousConnection && !this.block_.nextConnection) { cursorX -= 0; } else { cursorX += 14; }; if (this.block_.isCollapsed()) { // Jagged right edge. var input = row[0]; var fieldX = cursorX; var fieldY = cursorY + Blockly.BlockSvg.FIELD_HEIGHT; this.renderFields_(input.fieldRow, fieldX, fieldY, row.height); steps.push(Blockly.BlockSvg.JAGGED_TEETH); var remainder = row.height - Blockly.BlockSvg.JAGGED_TEETH_HEIGHT; steps.push('v', remainder); } else if (row.type == Blockly.BlockSvg.INLINE) { // Inline inputs. for (var x = 0, input; input = row[x]; x++) { var fieldX = cursorX; var fieldY = cursorY + Blockly.BlockSvg.FIELD_HEIGHT; // TODO: Align inline field rows (left/right/centre). cursorX = this.renderFields_(input.fieldRow, fieldX, fieldY, row.height); if (input.type != Blockly.DUMMY_INPUT) { cursorX += input.renderWidth + Blockly.BlockSvg.SEP_SPACE_X; } if (input.type == Blockly.INPUT_VALUE) { var r = input.renderHeight/2; var l = input.renderWidth; var param = 0; l += 1; var inputType = input.connection.check_ ? input.connection.check_[0] : "null"; var inlineCursorY = cursorY + (row.height - 2*r)/2; if (inputType.toUpperCase() == "BOOLEAN") { inlineSteps.push('M', (cursorX - Blockly.BlockSvg.SEP_SPACE_X - r) + ',' + (inlineCursorY + 0.5)); inlineSteps.push('h', -l + 2*r); inlineSteps.push('l', '-' + r + ',' + r + ' ' + r + ',' + r); inlineSteps.push('h', l - 2*r); inlineSteps.push('l', r + ',-' + r + ' -' + r + ',-' + r); inlineSteps.push('z'); } else if (inputType.toUpperCase() == "PARAM") { inlineCursorY += 1; if (this.block_.outputConnection) { cursorX -= input.renderWidth + Blockly.BlockSvg.SEP_SPACE_X; param = input.renderWidth + Blockly.BlockSvg.SEP_SPACE_X + 9; } else { param = 8; inlineSteps.push('M', (cursorX - Blockly.BlockSvg.SEP_SPACE_X - 6) + ',' + (3)); inlineSteps.push('h', -l + 9); inlineSteps.push('l', '-2,2 0,3 3,0 1,1 0,11 -1,1 -3,0 0,4 2,2'); inlineSteps.push('h', l - 9); inlineSteps.push('l', '2,-2 0,-3 3,0 1,-1 0,-13 -1,-1 -3,0 0,-2 -2,-2'); inlineSteps.push('z'); } } else { inlineSteps.push('M', (cursorX - Blockly.BlockSvg.SEP_SPACE_X - r) + ',' +( inlineCursorY + 0.5)); inlineSteps.push('h', -l + 2*r); inlineSteps.push('a', r + ',' + r + ' 0 1,0 0,' + 2*r); inlineSteps.push('h', l - 2*r); inlineSteps.push('a', r + ',' + r + ' 0 1,0 0,-' + 2*r); inlineSteps.push('z'); } // Create inline input connection. connectionX = connectionsXY.x + cursorX - Blockly.BlockSvg.SEP_SPACE_X -Blockly.BlockSvg.TAB_WIDTH-input.renderWidth +7.5+ r + param; connectionY = connectionsXY.y + inlineCursorY; input.connection.moveTo(connectionX, connectionY); if (input.connection.targetConnection) { input.connection.tighten_(); } } } cursorX = Math.max(cursorX, inputRows.rightEdge); blockWidth = cursorX; if (this.block_.outputConnection) { this.blockInlineWidth_ = cursorX; var r = row.height/2; this.r_ = r; var lastRow = row[row.length-1].fieldRow; if (lastRow[lastRow.length-1] instanceof Blockly.FieldLabel) cursorX += 1; cursorX += 2; if (this.block_.outputConnection.check_[0].toUpperCase() == "PARAM") { steps.push('H', cursorX); steps.push('l', '-3,0 2,2 0,3 3,0 1,1 0,12 -1,1 -3,0 0,3 -2,2 3,0'); } else if (this.block_.outputConnection.check_[0].toUpperCase() == "BOOLEAN") { steps.push('H', cursorX - r); steps.push('l', r + ',' + r + ' -' + r + ',' + r); } else { steps.push('H', cursorX - r - 4); steps.push('a', r + ',' + r + ' 0 1,1 0,' + 2*r); } } else { if (y==0) this.blockInlineWidth_ = cursorX; if (this.blockInlineWidth_) cursorX = this.blockInlineWidth_; var lastRow = row[row.length-1].fieldRow; if (!(lastRow[lastRow.length-1] instanceof Blockly.FieldIcon)) cursorX += 8; var r = row.height/2; steps.push('H', cursorX - r - 1); steps.push('a', r + ',' + r + ' 0 0,1 0,' + 2*r); } } else if (row.type == Blockly.INPUT_VALUE) { // External input. var input = row[0]; var fieldX = cursorX; var fieldY = cursorY + Blockly.BlockSvg.FIELD_HEIGHT; if (input.align != Blockly.ALIGN_LEFT) { var fieldRightX = inputRows.rightEdge - input.fieldWidth - Blockly.BlockSvg.TAB_WIDTH - 2 * Blockly.BlockSvg.SEP_SPACE_X; if (input.align == Blockly.ALIGN_RIGHT) { fieldX += fieldRightX; } else if (input.align == Blockly.ALIGN_CENTRE) { fieldX += (fieldRightX + fieldX) / 2; } } this.renderFields_(input.fieldRow, fieldX, fieldY, row.height); steps.push(Blockly.BlockSvg.TAB_PATH_DOWN); steps.push('v', row.height - Blockly.BlockSvg.TAB_HEIGHT); // Create external input connection. connectionX = connectionsXY.x + (Blockly.RTL ? -inputRows.rightEdge - 1 : inputRows.rightEdge + 1); connectionY = connectionsXY.y + cursorY + 1; input.connection.moveTo(connectionX, connectionY); if (input.connection.targetConnection) { input.connection.tighten_(); } } else if (row.type == Blockly.DUMMY_INPUT) { // External naked field. var input = row[0]; var fieldX = cursorX; var fieldY = cursorY + Blockly.BlockSvg.FIELD_HEIGHT; if (input.align != Blockly.ALIGN_LEFT) { var fieldRightX = inputRows.rightEdge - input.fieldWidth - 2 * Blockly.BlockSvg.SEP_SPACE_X; if (inputRows.hasValue) { fieldRightX -= Blockly.BlockSvg.TAB_WIDTH; } if (input.align == Blockly.ALIGN_RIGHT) { fieldX += fieldRightX; } else if (input.align == Blockly.ALIGN_CENTRE) { fieldX += (fieldRightX + fieldX) / 2; } } this.renderFields_(input.fieldRow, fieldX, fieldY, row.height); steps.push('v', row.height); } else if (row.type == Blockly.NEXT_STATEMENT) { // Nested statement. var input = row[0]; if (y == 0) { // If the first input is a statement stack, add a small row on top. steps.push('v', Blockly.BlockSvg.SEP_SPACE_Y); cursorY += Blockly.BlockSvg.SEP_SPACE_Y; } var fieldX = cursorX; var fieldY = cursorY + Blockly.BlockSvg.FIELD_HEIGHT; if (input.align != Blockly.ALIGN_LEFT) { var fieldRightX = inputRows.statementEdge - input.fieldWidth - 2 * Blockly.BlockSvg.SEP_SPACE_X; if (input.align == Blockly.ALIGN_RIGHT) { fieldX += fieldRightX; } else if (input.align == Blockly.ALIGN_CENTRE) { fieldX += (fieldRightX + fieldX) / 2; } } this.renderFields_(input.fieldRow, fieldX, fieldY, row.height); cursorX = inputRows.statementEdge + Blockly.BlockSvg.NOTCH_WIDTH; var r = row.height/2; steps.push('H', cursorX + 6); steps.push(Blockly.BlockSvg.INNER_TOP_LEFT_CORNER); steps.push('v', row.height- 4.5); steps.push(Blockly.BlockSvg.INNER_BOTTOM_LEFT_CORNER); steps.push('H', 14); steps.push(Blockly.BlockSvg.NOTCH_PATH_LEFT); if (this.blockInlineWidth_) steps.push('H', this.blockInlineWidth_ -12); else steps.push('H', blockWidth); // Create statement connection. connectionX = connectionsXY.x + (Blockly.RTL ? -cursorX : cursorX) + 6; connectionY = connectionsXY.y + cursorY + 3; if (y != 0) connectionY -= 0; cursorY -= 0; input.connection.moveTo(connectionX, connectionY); if (input.connection.targetConnection) { input.connection.tighten_(); } if (y == inputRows.length - 1 || inputRows[y + 1].type == Blockly.NEXT_STATEMENT) { // If the final input is a statement stack, add a small row underneath. // Consecutive statement stacks are also separated by a small divider. steps.push('a', 8 + ',' + 8 + ' 0 0,1 0,' + 2*8); cursorY += Blockly.BlockSvg.SEP_SPACE_Y + 3; } } cursorY += row.height; } if (!inputRows.length) { cursorY = Blockly.BlockSvg.MIN_BLOCK_Y; steps.push('V', cursorY); } return cursorY; }; /** * Render the bottom edge of the block. * @param {!Array.} steps Path of block outline. * @param {!Object} connectionsXY Location of block. * @param {number} cursorY Height of block. * @private */ Blockly.BlockSvg.prototype.renderDrawBottom_ = function(steps, connectionsXY, cursorY) { if (this.block_.nextConnection) { steps.push('l', '0,-0.5'); steps.push('H', Blockly.BlockSvg.NOTCH_WIDTH + ' ' + Blockly.BlockSvg.NOTCH_PATH_RIGHT); steps.push('l', '0,0.5'); // Create next block connection. var connectionX; connectionX = connectionsXY.x + Blockly.BlockSvg.NOTCH_WIDTH; var connectionY = connectionsXY.y + cursorY + 1; this.block_.nextConnection.moveTo(connectionX, connectionY); if (this.block_.nextConnection.targetConnection) { this.block_.nextConnection.tighten_(); } } if (Blockly.BROKEN_CONTROL_POINTS) { /* HACK: WebKit bug 67298 causes control points to be included in the reported bounding box. Add 5px control point to the bottom of the path. */ steps.push('c 0,4 0,-4 0,0'); } // Should the bottom-left corner be rounded or square? //if (this.squareBottomLeftCorner_) { if (true) { steps.push('H 0'); } else { steps.push('H', Blockly.BlockSvg.CORNER_RADIUS); steps.push('a', Blockly.BlockSvg.CORNER_RADIUS + ',' + Blockly.BlockSvg.CORNER_RADIUS + ' 0 0,1 -' + Blockly.BlockSvg.CORNER_RADIUS + ',-' + Blockly.BlockSvg.CORNER_RADIUS); } }; /** * Render the left edge of the block. * @param {!Array.} steps Path of block outline. * @param {!Object} connectionsXY Location of block. * @param {number} cursorY Height of block. * @private */ Blockly.BlockSvg.prototype.renderDrawLeft_ = function(steps, connectionsXY, cursorY, inputRows) { if (this.block_.outputConnection) { // Create output connection. this.block_.outputConnection.moveTo(connectionsXY.x, connectionsXY.y); // This connection will be tightened when the parent renders. var r = this.r_; if (this.block_.outputConnection.check_[0].toUpperCase() == "PARAM") { steps.push('l', '-18,0 -2,-2 0,-3 3,0 1,-1 0,-12 -1,-1 -3,0 0,-3 2,-2 18,0'); } else if (r && this.block_.outputConnection.check_[0].toUpperCase() == "BOOLEAN") { steps.push('l', '-' + r + ',-' + r + ' ' + r + ',-' + r); } else if (r) { steps.push('a', r + ',' + r + ' 0 1,1 0,-' + 2*r); } } var firstRow = inputRows[0][0].fieldRow; if (firstRow[0] instanceof Blockly.FieldIcon) { steps.push('a', '19.5,19.5 0, 0,1 0,-35'); steps.push('z'); } else steps.push('z'); }; ================================================ FILE: extern/blockly/core/blockly.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Core JavaScript library for Blockly. * @author fraser@google.com (Neil Fraser) */ 'use strict'; // Top level object for Blockly. goog.provide('Blockly'); // Blockly core dependencies. goog.require('Blockly.Block'); goog.require('Blockly.BlockMenu'); goog.require('Blockly.FieldIcon'); goog.require('Blockly.Connection'); goog.require('Blockly.FieldAngle'); goog.require('Blockly.FieldCheckbox'); goog.require('Blockly.FieldColour'); goog.require('Blockly.FieldDropdown'); goog.require('Blockly.FieldDropdownDynamic'); goog.require('Blockly.FieldImage'); goog.require('Blockly.FieldIcon'); goog.require('Blockly.FieldTextInput'); goog.require('Blockly.FieldKeydownInput'); goog.require('Blockly.FieldVariable'); goog.require('Blockly.Generator'); goog.require('Blockly.Msg'); goog.require('Blockly.Procedures'); goog.require('Blockly.Realtime'); goog.require('Blockly.Toolbox'); goog.require('Blockly.WidgetDiv'); goog.require('Blockly.Workspace'); goog.require('Blockly.inject'); goog.require('Blockly.utils'); // Closure dependencies. goog.require('goog.dom'); goog.require('goog.color'); goog.require('goog.events'); goog.require('goog.string'); goog.require('goog.ui.ColorPicker'); goog.require('goog.ui.tree.TreeControl'); goog.require('goog.userAgent'); /** * Path to Blockly's directory. Can be relative, absolute, or remote. * Used for loading additional resources. */ Blockly.pathToBlockly = './'; /** * Required name space for SVG elements. * @const */ Blockly.SVG_NS = 'http://www.w3.org/2000/svg'; /** * Required name space for HTML elements. * @const */ Blockly.HTML_NS = 'http://www.w3.org/1999/xhtml'; /** * The richness of block colours, regardless of the hue. * Must be in the range of 0 (inclusive) to 1 (exclusive). */ Blockly.HSV_SATURATION = 0.45; /** goog.require('Blockly.FieldKeydownInput'); * The intensity of block colours, regardless of the hue. * Must be in the range of 0 (inclusive) to 1 (exclusive). */ Blockly.HSV_VALUE = 0.65; /** * Convert a hue (HSV model) into an RGB hex triplet. * @param {number} hue Hue on a colour wheel (0-360). * @return {string} RGB code, e.g. '#5ba65b'. */ Blockly.makeColour = function(colorCode) { if (typeof(colorCode) == "number") return goog.color.hsvToHex(colorCode, Blockly.HSV_SATURATION, Blockly.HSV_VALUE * 256); else return colorCode; }; /** * ENUM for a right-facing value input. E.g. 'test' or 'return'. * @const */ Blockly.INPUT_VALUE = 1; /** * ENUM for a left-facing value output. E.g. 'call random'. * @const */ Blockly.OUTPUT_VALUE = 2; /** * ENUM for a down-facing block stack. E.g. 'then-do' or 'else-do'. * @const */ Blockly.NEXT_STATEMENT = 3; /** * ENUM for an up-facing block stack. E.g. 'close screen'. * @const */ Blockly.PREVIOUS_STATEMENT = 4; /** * ENUM for an dummy input. Used to add field(s) with no input. * @const */ Blockly.DUMMY_INPUT = 5; /** * ENUM for left alignment. * @const */ Blockly.ALIGN_LEFT = -1; /** * ENUM for centre alignment. * @const */ Blockly.ALIGN_CENTRE = 0; /** * ENUM for right alignment. * @const */ Blockly.ALIGN_RIGHT = 1; Blockly.enableBlockAnimation = !(goog.userAgent.SAFARI && !window.chrome); /** * Lookup table for determining the opposite type of a connection. * @const */ Blockly.OPPOSITE_TYPE = []; Blockly.OPPOSITE_TYPE[Blockly.INPUT_VALUE] = Blockly.OUTPUT_VALUE; Blockly.OPPOSITE_TYPE[Blockly.OUTPUT_VALUE] = Blockly.INPUT_VALUE; Blockly.OPPOSITE_TYPE[Blockly.NEXT_STATEMENT] = Blockly.PREVIOUS_STATEMENT; Blockly.OPPOSITE_TYPE[Blockly.PREVIOUS_STATEMENT] = Blockly.NEXT_STATEMENT; /** * Database of pre-loaded sounds. * @private * @const */ Blockly.SOUNDS_ = Object.create(null); /** * Currently activated block. * @type {Blockly.Block} */ Blockly.activated = null; /** * Currently selected block. * @type {Blockly.Block} */ Blockly.selected = null; /** * Is Blockly in a read-only, non-editable mode? * Note that this property may only be set before init is called. * It can't be used to dynamically toggle editability on and off. */ Blockly.readOnly = false; /** * Currently highlighted connection (during a drag). * @type {Blockly.Connection} * @private */ Blockly.highlightedConnection_ = null; /** * Connection on dragged block that matches the highlighted connection. * @type {Blockly.Connection} * @private */ Blockly.localConnection_ = null; /** * Number of pixels the mouse must move before a drag starts. * @const */ Blockly.DRAG_RADIUS = 5; /** * Maximum misalignment between connections for them to snap together. * @const */ Blockly.SNAP_RADIUS = 15; /** * Maximum misalignment between connections for them to snap together for Entry workspace. * @const */ Blockly.SNAP_RADIUS_ENTRY = 25; /** * Delay in ms between trigger and bumping unconnected block out of alignment. * @const */ Blockly.BUMP_DELAY = 250; /** * Number of characters to truncate a collapsed block to. * @const */ Blockly.COLLAPSE_CHARS = 30; /** * Length limit of blockly text input view. * @const */ Blockly.TEXT_INPUT_MAX_LENGTH = 20; Blockly.primitiveTypes = ['NUMBER', 'TRUE', 'FALSE', 'TEXT', 'FUNCTION_PARAM_BOOLEAN', 'FUNCTION_PARAM_STRING', 'TRUE_UN']; /** * The main workspace (defined by inject.js). * @type {Blockly.Workspace} */ Blockly.mainWorkspace = null; /** * Contents of the local clipboard. * @type {Element} * @private */ Blockly.clipboard_ = null; Blockly.textLengthCache = {}; /** * Returns the dimensions of the current SVG image. * @return {!Object} Contains width and height properties. */ Blockly.svgSize = function() { return {width: Blockly.svg.cachedWidth_, height: Blockly.svg.cachedHeight_}; }; /** * Size the SVG image to completely fill its container. Record both * the height/width and the absolute position of the SVG image. */ Blockly.svgResize = function() { var svg = Blockly.svg; var div = svg.parentNode; var width = div.offsetWidth-3; var height = div.offsetHeight; if (svg.cachedWidth_ != width) { svg.setAttribute('width', width + 'px'); svg.cachedWidth_ = width; } if (svg.cachedHeight_ != height) { svg.setAttribute('height', height + 'px'); svg.cachedHeight_ = height; } // Update the scrollbars (if they exist). if (Blockly.mainWorkspace.scrollbar) { Blockly.mainWorkspace.scrollbar.resize(); } }; /** * Handle a mouse-down on SVG drawing surface. * @param {!Event} e Mouse down event. * @private */ Blockly.onMouseDown_ = function(e) { Blockly.svgResize(); Blockly.terminateDrag_(); // In case mouse-up event was lost. //Blockly.hideChaff(); var isTargetSvg = e.target && e.target.nodeName && e.target.nodeName.toLowerCase() == 'svg'; if (!Blockly.readOnly && Blockly.selected && isTargetSvg) { // Clicking on the document clears the selection. Blockly.selected.unselect(); } if (Blockly.isRightButton(e)) { // Right-click. if (Blockly.ContextMenu) { Blockly.showContextMenu_(Blockly.mouseToSvg(e)); } } else if ((Blockly.readOnly || isTargetSvg) && Blockly.mainWorkspace.scrollbar) { // If the workspace is editable, only allow dragging when gripping empty // space. Otherwise, allow dragging when gripping anywhere. Blockly.mainWorkspace.dragMode = true; // Record the current mouse position. Blockly.mainWorkspace.startDragMouseX = e.clientX; Blockly.mainWorkspace.startDragMouseY = e.clientY; Blockly.mainWorkspace.startDragMetrics = Blockly.mainWorkspace.getMetrics(); Blockly.mainWorkspace.startScrollX = Blockly.mainWorkspace.scrollX; Blockly.mainWorkspace.startScrollY = Blockly.mainWorkspace.scrollY; } }; /** * Handle a mouse-up on SVG drawing surface. * @param {!Event} e Mouse up event. * @private */ Blockly.onMouseUp_ = function(e) { Blockly.setCursorHand_(false); Blockly.mainWorkspace.dragMode = false; }; /** * Handle a mouse-move on SVG surface. * @param {!Event} e Mouse move event. * @private */ Blockly.onMouseMove_ = function(e) { var hScroll = Blockly.mainWorkspace.scrollbar.hScroll; var vScroll = Blockly.mainWorkspace.scrollbar.vScroll; hScroll.svgGroup_.setAttribute('opacity', '1'); vScroll.svgGroup_.setAttribute('opacity', '1'); if (Blockly.mainWorkspace.dragMode) { Blockly.removeAllRanges(); var dx = e.clientX - Blockly.mainWorkspace.startDragMouseX; var dy = e.clientY - Blockly.mainWorkspace.startDragMouseY; var metrics = Blockly.mainWorkspace.startDragMetrics; var x = Blockly.mainWorkspace.startScrollX + dx; var y = Blockly.mainWorkspace.startScrollY + dy; x = Math.min(x, -metrics.contentLeft); y = Math.min(y, -metrics.contentTop); x = Math.max(x, metrics.viewWidth - metrics.contentLeft - metrics.contentWidth); y = Math.max(y, metrics.viewHeight - metrics.contentTop - metrics.contentHeight); // Move the scrollbars and the page will scroll automatically. Blockly.mainWorkspace.scrollbar.set(-x - metrics.contentLeft, -y - metrics.contentTop); } }; /** * Handle a mouse-wheel on SVG drawing surface. * @param {!Event} e Mouse move event. * @private */ Blockly.onMouseWheel_ = function (e) { e.preventDefault(); Blockly.removeAllRanges(); Blockly.hideChaff(); var dx = e.wheelDeltaX || -e.deltaX; var dy = e.wheelDeltaY || -e.deltaY; var metrics = Blockly.mainWorkspace.getMetrics(); Blockly.mainWorkspace.startScrollX = Blockly.mainWorkspace.scrollX; Blockly.mainWorkspace.startScrollY = Blockly.mainWorkspace.scrollY; var x = Blockly.mainWorkspace.startScrollX + dx; var y = Blockly.mainWorkspace.startScrollY + dy; x = Math.min(x, -metrics.contentLeft); y = Math.min(y, -metrics.contentTop); x = Math.max(x, metrics.viewWidth - metrics.contentLeft - metrics.contentWidth); y = Math.max(y, metrics.viewHeight - metrics.contentTop - metrics.contentHeight); // Move the scrollbars and the page will scroll automatically. Blockly.mainWorkspace.scrollbar.set(-x - metrics.contentLeft, -y - metrics.contentTop); } /** * Handle a mouse-wheel on flyout SVG drawing surface. * @param {!Event} e Mouse move event. * @private */ Blockly.onMouseWheelFlyout_ = function (e) { e.stopPropagation(); e.preventDefault(); Blockly.removeAllRanges(); var scroll = this.scrollbar_; var dy = e.wheelDeltaY || -e.deltaY; var metrics = this.getMetrics_(); scroll.startScrollY = parseFloat(this.scrollbar_.svgKnob_.getAttribute('y')); var y = parseFloat(-scroll.startScrollY) + dy; y = Math.min(y, -metrics.contentTop); y = Math.max(y, metrics.viewHeight - metrics.contentTop - metrics.contentHeight); scroll.svgKnob_.setAttribute(this.horizontal_ ? 'x' : 'y', scroll.constrainKnob_(-y- metrics.contentTop)); scroll.onScroll_(); } /** * Handle a key-down on SVG drawing surface. * @param {!Event} e Key down event. * @private */ Blockly.onKeyDown_ = function(e) { var block = Blockly.selected; if (Blockly.isTargetInput_(e)) { // When focused on an HTML text input widget, don't trap any keys. return; } // TODO: Add keyboard support for cursoring around the context menu. if (e.keyCode == 27) { // Pressing esc closes the context menu. //Blockly.hideChaff(); } else if (e.keyCode == 8 || e.keyCode == 46) { // Delete or backspace. try { if (block && block.isDeletable() && !block.isInFlyout) { Blockly.hideChaff(); var blockType = block.type.toUpperCase(); if (!(Blockly.primitiveTypes.indexOf(blockType) > -1 && block.getParent())) block.dispose(true, true); if (typeof(Entry) == "object") Entry.dispatchEvent("entryBlocklyChanged"); } } finally { // Stop the browser from going back to the previous page. // Use a finally so that any error in delete code above doesn't disappear // from the console when the page rolls back. e.preventDefault(); } } else if (e.altKey || e.ctrlKey || e.metaKey) { //target is Blockly mainWorkspace if (block && block.isDeletable() && (block.workspace == Blockly.mainWorkspace)) { Blockly.hideChaff(); if (e.keyCode == 67) { // 'c' for copy. Blockly.copy_(block); } else if (e.keyCode == 88) { // 'x' for cut. Blockly.copy_(block); block.dispose(true, true); } } //target is Entry.Func workspace if (typeof(Entry) == 'object' && Entry.Func && Entry.Func.workspace && block && block.isDeletable() && (block.workspace == Entry.Func.workspace)) { Blockly.hideChaff(); if (e.keyCode == 67) { // 'c' for copy. Blockly.copy_(block); } else if (e.keyCode == 88) { // 'x' for cut. Blockly.copy_(block); block.dispose(true, true); } } if (e.keyCode == 86) { // 'v' for paste. if (Blockly.clipboard_) { if (!Entry || !Entry.Func || !Entry.Func.workspace || !Entry.Func.workspace.visible ) { Blockly.mainWorkspace.paste(Blockly.clipboard_); } else { var xmlBlock = Blockly.clipboard_; xmlBlock.setAttribute('isForFunc', 'true'); Entry.Func.workspace.paste(xmlBlock); } } } } }; /** * Stop binding to the global mouseup and mousemove events. * @private */ Blockly.terminateDrag_ = function() { Blockly.Block.terminateDrag_(); Blockly.Flyout.terminateDrag_(); if (Blockly.mainWorkspace.blockMenu) Blockly.BlockMenu.terminateDrag_(); }; /** * Copy a block onto the local clipboard. * @param {!Blockly.Block} block Block to be copied. * @private */ Blockly.copy_ = function(block) { var xmlBlock = Blockly.Xml.blockToDom_(block); //Blockly.Xml.deleteNext(xmlBlock); // Encode start position in XML. var xy = block.getRelativeToSurfaceXY(); xmlBlock.setAttribute('x', Blockly.RTL ? -xy.x : xy.x); xmlBlock.setAttribute('y', xy.y); Blockly.clipboard_ = xmlBlock; }; /** * Show the context menu for the workspace. * @param {!Object} xy Coordinates of mouse click, contains x and y properties. * @private */ Blockly.showContextMenu_ = function(xy) { if (Blockly.readOnly) { return; } var options = []; if (Blockly.collapse) { var hasCollapsedBlocks = false; var hasExpandedBlocks = false; var topBlocks = Blockly.mainWorkspace.getTopBlocks(false); for (var i = 0; i < topBlocks.length; i++) { if (topBlocks[i].isCollapsed()) { hasCollapsedBlocks = true; } else { hasExpandedBlocks = true; } } // Option to collapse top blocks. var collapseOption = {enabled: hasExpandedBlocks}; collapseOption.text = Blockly.Msg.COLLAPSE_ALL; collapseOption.callback = function() { for (var i = 0; i < topBlocks.length; i++) { topBlocks[i].setCollapsed(true); } }; options.push(collapseOption); // Option to expand top blocks. var expandOption = {enabled: hasCollapsedBlocks}; expandOption.text = Blockly.Msg.EXPAND_ALL; expandOption.callback = function() { for (var i = 0; i < topBlocks.length; i++) { topBlocks[i].setCollapsed(false); } }; options.push(expandOption); } var pasteOption = { text: Lang.Blocks.Paste_blocks, enabled: true, callback: function() { var xmlBlock = Blockly.clipboard_; if (typeof(Entry) === "object" && Entry && Entry.Func && Entry.Func.workspace && Entry.Func.workspace.visible) { xmlBlock.setAttribute('isForFunc', 'true'); Entry.Func.workspace.paste(xmlBlock); } else if (typeof(Ntry) === "object" && Ntry && Ntry.Func && Ntry.Func.workspace && Ntry.Func.workspace.visible) { xmlBlock.setAttribute('isForFunc', 'true'); //Ntry.Func.workspace.paste(xmlBlock); } else { Blockly.mainWorkspace.paste(Blockly.clipboard_); } if (typeof(Entry) == "object") { Entry.dispatchEvent("entryBlocklyChanged"); } /* if (typeof(Ntry) == "object") { Ntry.dispatchEvent("ntryBlocklyChanged"); } */ } } var clearOption = { text: Lang.Blocks.Clear_all_blocks, enabled: true, callback: function() { var total; if (typeof(Entry) === "object" && Entry && Entry.Func && Entry.Func.workspace && Entry.Func.workspace.visible) { total = Entry.Func.workspace.getAllBlocks(); } else if (typeof(Ntry) === "object" && Ntry && Ntry.Func && Ntry.Func.workspace && Ntry.Func.workspace.visible) { //total = Ntry.Func.workspace.getAllBlocks(); } else { total = Blockly.mainWorkspace.getAllBlocks(); } for (var i = total.length-1; i >= 0; i--) { if (total[i].deletable_) total[i].dispose(); } if (typeof(Entry) == "object") { Entry.dispatchEvent("entryBlocklyChanged"); } /* if (typeof(Ntry) == "object") { Ntry.dispatchEvent("ntryBlocklyChanged"); } */ } } if (!Blockly.clipboard_) { pasteOption.enabled = false; } var cleanUpOption = { text: '코드 정리하기', enabled: true, callback: function() { Blockly.mainWorkspace.organizeBlocks(); if (typeof(Entry) == "object") Entry.dispatchEvent("entryBlocklyChanged"); if (typeof(Ntry) == "object") Entry.dispatchEvent("ntryBlocklyChanged"); } } options.push(pasteOption); options.push(cleanUpOption); options.push(clearOption); // Option to get help. /* var helpOption = {enabled: false}; helpOption.text = Blockly.Msg.HELP; helpOption.callback = function() {}; options.push(helpOption); */ Blockly.ContextMenu.show(xy, options); }; /** * Cancel the native context menu, unless the focus is on an HTML input widget. * @param {!Event} e Mouse down event. * @private */ Blockly.onContextMenu_ = function(e) { if (!Blockly.isTargetInput_(e) && Blockly.ContextMenu) { // When focused on an HTML text input widget, don't cancel the context menu. e.preventDefault(); } }; /** * Close tooltips, context menus, dropdown selections, etc. * @param {boolean=} opt_allowToolbox If true, don't close the toolbox. */ Blockly.hideChaff = function(opt_allowToolbox) { Blockly.Tooltip && Blockly.Tooltip.hide(); Blockly.ContextMenu && Blockly.ContextMenu.hide(); Blockly.FieldDropdown && Blockly.FieldDropdown.hide(); Blockly.FieldKeydownInput && Blockly.FieldKeydownInput.hide(); Blockly.WidgetDiv.hide(); if (!opt_allowToolbox && Blockly.Toolbox.flyout_ && Blockly.Toolbox.flyout_.autoClose) { Blockly.Toolbox.clearSelection(); } }; /** * Deselect any selections on the webpage. * Chrome will select text outside the SVG when double-clicking. * Deselect this text, so that it doesn't mess up any subsequent drag. */ Blockly.removeAllRanges = function() { if (window.getSelection) { // W3 var sel = window.getSelection(); if (sel && sel.removeAllRanges) { sel.removeAllRanges(); window.setTimeout(function() { window.getSelection().removeAllRanges(); }, 0); } } }; /** * Is this event targeting a text input widget? * @param {!Event} e An event. * @return {boolean} True if text input. * @private */ Blockly.isTargetInput_ = function(e) { return e.target.type == 'textarea' || e.target.type == 'text'; }; /** * Load an audio file. Cache it, ready for instantaneous playing. * @param {!Array.} filenames List of file types in decreasing order of * preference (i.e. increasing size). E.g. ['media/go.mp3', 'media/go.wav'] * Filenames include path from Blockly's root. File extensions matter. * @param {string} name Name of sound. * @private */ Blockly.loadAudio_ = function(filenames, name) { if (!window['Audio'] || !filenames.length) { // No browser support for Audio. return; } for (var i = 0; i < filenames.length; i++) { var filename = filenames[i]; var path = Blockly.pathToBlockly + filename; var id = filename.match(/\/([^.]+)./)[1]; createjs.Sound.registerSound(path, id, 4); break; } //var sound; //var audioTest = new window['Audio'](); //for (var i = 0; i < filenames.length; i++) { //var filename = filenames[i]; //var ext = filename.match(/\.(\w+)$/); //if (ext && audioTest.canPlayType('audio/' + ext[1])) { //// Found an audio format we can play. //sound = new window['Audio'](Blockly.pathToBlockly + filename); //break; //} //} //// To force the browser to load the sound, play it, but at nearly zero volume. //if (sound && sound.play) { //sound.volume = 0.01; //sound.play(); //Blockly.SOUNDS_[name] = sound; //} // To force the browser to load the sound, play it, but at nearly zero volume. //if (sound && sound.play) { //sound.volume = 0.01; //sound.play(); //Blockly.SOUNDS_[name] = sound; //} }; /** * Play an audio file at specified value. If volume is not specified, * use full volume (1). * @param {string} name Name of sound. * @param {?number} opt_volume Volume of sound (0-1). */ Blockly.playAudio = function(name, opt_volume) { createjs.Sound.play(name); //var sound = Blockly.SOUNDS_[name]; //if (sound) { //var mySound; //var ie9 = goog.userAgent.DOCUMENT_MODE && //goog.userAgent.DOCUMENT_MODE === 9; //if (ie9 || goog.userAgent.IPAD || goog.userAgent.ANDROID) { //// Creating a new audio node causes lag in IE9, Android and iPad. Android //// and IE9 refetch the file from the server, iPad uses a singleton audio //// node which must be deleted and recreated for each new audio tag. //mySound = sound; //} else { //mySound = sound.cloneNode(); //} //mySound.volume = (opt_volume === undefined ? 1 : opt_volume); //mySound.play(); //} }; /** * Set the mouse cursor to be either a closed hand or the default. * @param {boolean} closed True for closed hand. * @private */ Blockly.setCursorHand_ = function(closed) { if (Blockly.readOnly) { return; } /* Hotspot coordinates are baked into the CUR file, but they are still required due to a Chrome bug. http://code.google.com/p/chromium/issues/detail?id=1446 */ var cursor = ''; if (closed) { cursor = 'url(' + Blockly.pathToBlockly + 'media/handclosed.cur) 7 3, auto'; } if (Blockly.selected) { Blockly.selected.getSvgRoot().style.cursor = cursor; } // Set cursor on the SVG surface as well as block so that rapid movements // don't result in cursor changing to an arrow momentarily. Blockly.svg.style.cursor = cursor; }; /** * Return an object with all the metrics required to size scrollbars for the * main workspace. The following properties are computed: * .viewHeight: Height of the visible rectangle, * .viewWidth: Width of the visible rectangle, * .contentHeight: Height of the contents, * .contentWidth: Width of the content, * .viewTop: Offset of top edge of visible rectangle from parent, * .viewLeft: Offset of left edge of visible rectangle from parent, * .contentTop: Offset of the top-most content from the y=0 coordinate, * .contentLeft: Offset of the left-most content from the x=0 coordinate. * .absoluteTop: Top-edge of view. * .absoluteLeft: Left-edge of view. * @return {Object} Contains size and position metrics of main workspace. * @private */ Blockly.getMainWorkspaceMetrics_ = function() { var svgSize = Blockly.svgSize(); svgSize.width -= Blockly.Toolbox.width; // Zero if no Toolbox. var viewWidth = svgSize.width - Blockly.Scrollbar.scrollbarThickness; var viewHeight = svgSize.height - Blockly.Scrollbar.scrollbarThickness; try { var blockBox = Blockly.mainWorkspace.getCanvas().getBBox(); } catch (e) { // Firefox has trouble with hidden elements (Bug 528969). return null; } if (Blockly.mainWorkspace.scrollbar) { // Add a border around the content that is at least half a screenful wide. // Ensure border is wide enough that blocks can scroll over entire screen. var leftEdge = Math.min(blockBox.x - viewWidth / 2, blockBox.x + blockBox.width - viewWidth); var rightEdge = Math.max(blockBox.x + blockBox.width + viewWidth / 2, blockBox.x + viewWidth); var topEdge = Math.min(blockBox.y - viewHeight / 2, blockBox.y + blockBox.height - viewHeight); var bottomEdge = Math.max(blockBox.y + blockBox.height + viewHeight / 2, blockBox.y + viewHeight); } else { var leftEdge = blockBox.x; var rightEdge = leftEdge + blockBox.width; var topEdge = blockBox.y; var bottomEdge = topEdge + blockBox.height; } var absoluteLeft = Blockly.RTL ? 0 : Blockly.Toolbox.width; var metrics = { viewHeight: svgSize.height, viewWidth: svgSize.width, contentHeight: bottomEdge - topEdge, contentWidth: rightEdge - leftEdge, viewTop: -Blockly.mainWorkspace.scrollY, viewLeft: -Blockly.mainWorkspace.scrollX, contentTop: topEdge, contentLeft: leftEdge, absoluteTop: 0, absoluteLeft: absoluteLeft }; return metrics; }; Blockly.getGenralWorkspaceMetricsFunc_ = function(workspace) { return function() { var svgSize = Blockly.svgSize(); svgSize.width -= Blockly.Toolbox.width; // Zero if no Toolbox. var viewWidth = svgSize.width - Blockly.Scrollbar.scrollbarThickness; var viewHeight = svgSize.height - Blockly.Scrollbar.scrollbarThickness; try { var blockBox = workspace.getCanvas().getBBox(); } catch (e) { // Firefox has trouble with hidden elements (Bug 528969). return null; } if (workspace.scrollbar) { // Add a border around the content that is at least half a screenful wide. // Ensure border is wide enough that blocks can scroll over entire screen. var leftEdge = Math.min(blockBox.x - viewWidth / 2, blockBox.x + blockBox.width - viewWidth); var rightEdge = Math.max(blockBox.x + blockBox.width + viewWidth / 2, blockBox.x + viewWidth); var topEdge = Math.min(blockBox.y - viewHeight / 2, blockBox.y + blockBox.height - viewHeight); var bottomEdge = Math.max(blockBox.y + blockBox.height + viewHeight / 2, blockBox.y + viewHeight); } else { var leftEdge = blockBox.x; var rightEdge = leftEdge + blockBox.width; var topEdge = blockBox.y; var bottomEdge = topEdge + blockBox.height; } var absoluteLeft = Blockly.RTL ? 0 : Blockly.Toolbox.width; var metrics = { viewHeight: svgSize.height, viewWidth: svgSize.width, contentHeight: bottomEdge - topEdge, contentWidth: rightEdge - leftEdge, viewTop: -workspace.scrollY, viewLeft: -workspace.scrollX, contentTop: topEdge, contentLeft: leftEdge, absoluteTop: 0, absoluteLeft: absoluteLeft }; return metrics; } }; /** * Sets the X/Y translations of the main workspace to match the scrollbars. * @param {!Object} xyRatio Contains an x and/or y property which is a float * between 0 and 1 specifying the degree of scrolling. * @private */ Blockly.setMainWorkspaceMetrics_ = function(xyRatio) { if (!Blockly.mainWorkspace.scrollbar) { throw 'Attempt to set main workspace scroll without scrollbars.'; } var metrics = Blockly.getMainWorkspaceMetrics_(); if (goog.isNumber(xyRatio.x)) { Blockly.mainWorkspace.scrollX = -metrics.contentWidth * xyRatio.x - metrics.contentLeft; } if (goog.isNumber(xyRatio.y)) { Blockly.mainWorkspace.scrollY = -metrics.contentHeight * xyRatio.y - metrics.contentTop; } var translation = 'translate(' + (Blockly.mainWorkspace.scrollX + metrics.absoluteLeft) + ',' + (Blockly.mainWorkspace.scrollY + metrics.absoluteTop) + ')'; Blockly.mainWorkspace.getCanvas().setAttribute('transform', translation); Blockly.mainWorkspace.getBubbleCanvas().setAttribute('transform', translation); }; Blockly.setGeneralWorkspaceMetricsFunc_ = function(workspace) { return function(xyRatio) { if (!workspace.scrollbar) { throw 'Attempt to set main workspace scroll without scrollbars.'; } var metrics = Blockly.getGenralWorkspaceMetricsFunc_(workspace)(); if (goog.isNumber(xyRatio.x)) { workspace.scrollX = -metrics.contentWidth * xyRatio.x - metrics.contentLeft; } if (goog.isNumber(xyRatio.y)) { workspace.scrollY = -metrics.contentHeight * xyRatio.y - metrics.contentTop; } var translation = 'translate(' + (workspace.scrollX + metrics.absoluteLeft) + ',' + (workspace.scrollY + metrics.absoluteTop) + ')'; workspace.getCanvas().setAttribute('transform', translation); workspace.getBubbleCanvas().setAttribute('transform', translation); } }; /** * When something in Blockly's workspace changes, call a function. * @param {!Function} func Function to call. * @return {!Array.} Opaque data that can be passed to * removeChangeListener. */ Blockly.addChangeListener = function(func) { return Blockly.bindEvent_(Blockly.mainWorkspace.getCanvas(), 'blocklyWorkspaceChange', null, func); }; /** * Stop listening for Blockly's workspace changes. * @param {!Array.} bindData Opaque data from addChangeListener. */ Blockly.removeChangeListener = function(bindData) { Blockly.unbindEvent_(bindData); }; /** * Returns the main workspace. * @return {!Blockly.Workspace} The main workspace. */ Blockly.getMainWorkspace = function() { return Blockly.mainWorkspace; }; // Export symbols that would otherwise be renamed by Closure compiler. window['Blockly'] = Blockly; Blockly['getMainWorkspace'] = Blockly.getMainWorkspace; Blockly['addChangeListener'] = Blockly.addChangeListener; Blockly['removeChangeListener'] = Blockly.removeChangeListener; ================================================ FILE: extern/blockly/core/blocks.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2013 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Core JavaScript library for Blockly. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.require('goog.asserts'); /** * Name space for the Blocks singleton. * Blocks gets populated in the blocks files, possibly through calls to * Blocks.addTemplate(). */ goog.provide('Blockly.Blocks'); /** * Create a block template and add it as a field to Blockly.Blocks with the * name details.blockName. * @param {!Object} details Details about the block that should be created. * The following fields are used: * - blockName {string} The name of the block, which should be unique. * - colour {number} The hue value of the colour to use for the block. * (Blockly.HSV_SATURATION and Blockly.HSV_VALUE are used for saturation * and value, respectively.) * - output {?string|Array.} Output type. If undefined, there are * assumed to be no outputs. Otherwise, this is interpreted the same way * as arguments to Blockly.Block.setCheck(): * - null: Any type can be produced. * - String: Only the specified type (e.g., 'Number') can be produced. * - Array.: Any of the specified types can be produced. * - message {string} A message suitable for passing as a first argument to * Blockly.Block.interpolateMsg(). Specifically, it should consist of * text to be displayed on the block, optionally interspersed with * references to inputs (one-based indices into the args array) or fields, * such as '%1' for the first element of args. The creation of dummy * inputs can be forced with a newline (\n). * - args {Array.} One or more descriptions of value inputs. * TODO: Add Fields and statement stacks. * Each object in the array can have the following fields: * - name {string} The name of the input. * - type {?number} One of Blockly.INPUT_VALUE, Blockly.NEXT_STATEMENT, or * ??. If not provided, it is assumed to be Blockly.INPUT_VALUE. * - check {?string|Array.} Input type. See description of the * output field above. * - align {?number} One of Blockly.ALIGN_LEFT, Blockly.ALIGN_CENTRE, or * Blockly.ALIGN_RIGHT (the default value, if not explicitly provided). * - inline {?boolean}: Whether inputs should be inline (true) or external * (false). If not explicitly specified, inputs will be inline if message * references, and ends with, a single value input. * - previousStatement {?boolean} Whether there should be a statement * connector on the top of the block. If not specified, the default * value will be !output. * - nextStatement {?boolean} Whether there should be a statement * connector on the bottom of the block. If not specified, the default * value will be !output. * - tooltip {?string|Function} Tooltip text or a function on this block * that returns a tooltip string. * - helpUrl {?string|Function} The help URL, or a function on this block * that returns the help URL. * - switchable {?boolean} Whether the block should be switchable between * an expression and statement. Specifically, if true, the block will * begin as an expression (having an output). There will be a context * menu option 'Remove output'. If selected, the output will disappear, * and previous and next statement connectors will appear. The context * menu option 'Remove output' will be replaced by 'Add Output'. If * selected, the output will reappear and the statement connectors will * disappear. * - mutationToDomFunc {Function} TODO desc. * - domToMutationFunc {Function} TODO desc. * - customContextMenuFunc {Function} TODO desc. * Additional fields will be ignored. */ Blockly.Blocks.addTemplate = function(details) { // Validate inputs. TODO: Add more. goog.asserts.assert(details.blockName); goog.asserts.assert(Blockly.Blocks[details.blockName], 'Blockly.Blocks already has a field named ', details.blockName); goog.asserts.assert(details.message); goog.asserts.assert(details.colour && typeof details.colour == 'number' && details.colour >= 0 && details.colour < 360, 'details.colour must be a number from 0 to 360 (exclusive)'); if (details.output != 'undefined') { goog.asserts.assert(!details.previousStatement, 'When details.output is defined, ' + 'details.previousStatement must not be true.'); goog.asserts.assert(!details.nextStatement, 'When details.output is defined, ' + 'details.nextStatement must not be true.'); } // Build up template. var block = {}; block.init = function() { var thisBlock = this; // Set basic properties of block. this.setColour(details.colour); this.setHelpUrl(details.helpUrl); if (typeof details.tooltip == 'string') { this.setTooltip(details.tooltip); } else if (typeof details.tooltip == 'function') { this.setTooltip(function() { return details.tooltip(thisBlock); }); } // Set output and previous/next connections. if (details.output != 'undefined') { this.setOutput(true, details.output); } else { this.setPreviousStatement( typeof details.previousStatement == 'undefined' ? true : details.previousStatement); this.setNextStatement( typeof details.nextStatement == 'undefined' ? true : details.nextStatement); } // Build up arguments in the format expected by interpolateMsg. var interpArgs = []; interpArgs.push(details.text); if (details.args) { details.args.forEach(function(arg) { goog.asserts.assert(arg.name); goog.asserts.assert(arg.check != 'undefined'); if (arg.type == 'undefined' || arg.type == Blockly.INPUT_VALUE) { interpArgs.push([arg.name, arg.check, typeof arg.align == 'undefined' ? Blockly.ALIGN_RIGHT : arg.align]); } else { // TODO: Write code for other input types. goog.asserts.fail('addTemplate() can only handle value inputs.'); } }); } // Neil, how would you recommend specifying the final dummy alignment? // Should it be a top-level field in details? interpArgs.push(Blockly.ALIGN_RIGHT); if (details.inline) { this.setInlineInputs(details.inline); } Blockly.Block.prototype.interpolateMsg.apply(this, interpArgs); }; // Create mutationToDom if needed. if (details.switchable) { block.mutationToDom = function() { var container = details.mutationToDomFunc ? details.mutatationToDomFunc() : document.createElement('mutation'); container.setAttribute('is_statement', this['isStatement'] || false); return container; }; } else { block.mutationToDom = details.mutationToDomFunc; } // TODO: Add domToMutation and customContextMenu. // Add new block to Blockly.Blocks. Blockly.Blocks[details.blockName] = block; }; ================================================ FILE: extern/blockly/core/bubble.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Object representing a UI bubble. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Bubble'); goog.require('Blockly.Workspace'); /** * Class for UI bubble. * @param {!Blockly.Workspace} workspace The workspace on which to draw the * bubble. * @param {!Element} content SVG content for the bubble. * @param {Element} shape SVG element to avoid eclipsing. * @param {number} anchorX Absolute horizontal position of bubbles anchor point. * @param {number} anchorY Absolute vertical position of bubbles anchor point. * @param {?number} bubbleWidth Width of bubble, or null if not resizable. * @param {?number} bubbleHeight Height of bubble, or null if not resizable. * @constructor */ Blockly.Bubble = function(workspace, content, shape, anchorX, anchorY, bubbleWidth, bubbleHeight) { var angle = Blockly.Bubble.ARROW_ANGLE; if (Blockly.RTL) { angle = -angle; } this.arrow_radians_ = angle / 360 * Math.PI * 2; this.workspace_ = workspace; this.content_ = content; this.shape_ = shape; var canvas = workspace.getBubbleCanvas(); canvas.appendChild(this.createDom_(content, !!(bubbleWidth && bubbleHeight))); this.setAnchorLocation(anchorX, anchorY); if (!bubbleWidth || !bubbleHeight) { var bBox = /** @type {SVGLocatable} */ (this.content_).getBBox(); bubbleWidth = bBox.width + 2 * Blockly.Bubble.BORDER_WIDTH; bubbleHeight = bBox.height + 2 * Blockly.Bubble.BORDER_WIDTH; } this.setBubbleSize(bubbleWidth, bubbleHeight); // Render the bubble. this.positionBubble_(); this.renderArrow_(); this.rendered_ = true; if (!Blockly.readOnly) { Blockly.bindEvent_(this.bubbleBack_, 'mousedown', this, this.bubbleMouseDown_); if (this.resizeGroup_) { Blockly.bindEvent_(this.resizeGroup_, 'mousedown', this, this.resizeMouseDown_); } } }; /** * Width of the border around the bubble. */ Blockly.Bubble.BORDER_WIDTH = 6; /** * Determines the thickness of the base of the arrow in relation to the size * of the bubble. Higher numbers result in thinner arrows. */ Blockly.Bubble.ARROW_THICKNESS = 10; /** * The number of degrees that the arrow bends counter-clockwise. */ Blockly.Bubble.ARROW_ANGLE = 20; /** * The sharpness of the arrow's bend. Higher numbers result in smoother arrows. */ Blockly.Bubble.ARROW_BEND = 4; /** * Distance between arrow point and anchor point. */ Blockly.Bubble.ANCHOR_RADIUS = 8; /** * Wrapper function called when a mouseUp occurs during a drag operation. * @type {Array.} * @private */ Blockly.Bubble.onMouseUpWrapper_ = null; /** * Wrapper function called when a mouseMove occurs during a drag operation. * @type {Array.} * @private */ Blockly.Bubble.onMouseMoveWrapper_ = null; /** * Stop binding to the global mouseup and mousemove events. * @private */ Blockly.Bubble.unbindDragEvents_ = function() { if (Blockly.Bubble.onMouseUpWrapper_) { Blockly.unbindEvent_(Blockly.Bubble.onMouseUpWrapper_); Blockly.Bubble.onMouseUpWrapper_ = null; } if (Blockly.Bubble.onMouseMoveWrapper_) { Blockly.unbindEvent_(Blockly.Bubble.onMouseMoveWrapper_); Blockly.Bubble.onMouseMoveWrapper_ = null; } }; /** * Flag to stop incremental rendering during construction. * @private */ Blockly.Bubble.prototype.rendered_ = false; /** * Absolute X coordinate of anchor point. * @private */ Blockly.Bubble.prototype.anchorX_ = 0; /** * Absolute Y coordinate of anchor point. * @private */ Blockly.Bubble.prototype.anchorY_ = 0; /** * Relative X coordinate of bubble with respect to the anchor's centre. * In RTL mode the initial value is negated. * @private */ Blockly.Bubble.prototype.relativeLeft_ = 0; /** * Relative Y coordinate of bubble with respect to the anchor's centre. * @private */ Blockly.Bubble.prototype.relativeTop_ = 0; /** * Width of bubble. * @private */ Blockly.Bubble.prototype.width_ = 0; /** * Height of bubble. * @private */ Blockly.Bubble.prototype.height_ = 0; /** * Automatically position and reposition the bubble. * @private */ Blockly.Bubble.prototype.autoLayout_ = true; /** * Create the bubble's DOM. * @param {!Element} content SVG content for the bubble. * @param {boolean} hasResize Add diagonal resize gripper if true. * @return {!Element} The bubble's SVG group. * @private */ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { /* Create the bubble. Here's the markup that will be generated: [...content goes here...] */ this.bubbleGroup_ = Blockly.createSvgElement('g', {}, null); var bubbleEmboss = Blockly.createSvgElement('g', {'filter': 'url(#blocklyEmboss)'}, this.bubbleGroup_); this.bubbleArrow_ = Blockly.createSvgElement('path', {}, bubbleEmboss); this.bubbleBack_ = Blockly.createSvgElement('rect', {'class': 'blocklyDraggable', 'x': 0, 'y': 0, 'rx': Blockly.Bubble.BORDER_WIDTH, 'ry': Blockly.Bubble.BORDER_WIDTH}, bubbleEmboss); if (hasResize) { this.resizeGroup_ = Blockly.createSvgElement('g', {'class': Blockly.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE'}, this.bubbleGroup_); var resizeSize = 2 * Blockly.Bubble.BORDER_WIDTH; Blockly.createSvgElement('polygon', {'points': '0,x x,x x,0'.replace(/x/g, resizeSize.toString())}, this.resizeGroup_); Blockly.createSvgElement('line', {'class': 'blocklyResizeLine', 'x1': resizeSize / 3, 'y1': resizeSize - 1, 'x2': resizeSize - 1, 'y2': resizeSize / 3}, this.resizeGroup_); Blockly.createSvgElement('line', {'class': 'blocklyResizeLine', 'x1': resizeSize * 2 / 3, 'y1': resizeSize - 1, 'x2': resizeSize - 1, 'y2': resizeSize * 2 / 3}, this.resizeGroup_); } else { this.resizeGroup_ = null; } this.bubbleGroup_.appendChild(content); return this.bubbleGroup_; }; /** * Handle a mouse-down on bubble's border. * @param {!Event} e Mouse down event. * @private */ Blockly.Bubble.prototype.bubbleMouseDown_ = function(e) { this.promote_(); Blockly.Bubble.unbindDragEvents_(); if (Blockly.isRightButton(e)) { // Right-click. return; } else if (Blockly.isTargetInput_(e)) { // When focused on an HTML text input widget, don't trap any events. return; } // Left-click (or middle click) Blockly.setCursorHand_(true); // Record the starting offset between the current location and the mouse. if (Blockly.RTL) { this.dragDeltaX = this.relativeLeft_ + e.clientX; } else { this.dragDeltaX = this.relativeLeft_ - e.clientX; } this.dragDeltaY = this.relativeTop_ - e.clientY; Blockly.Bubble.onMouseUpWrapper_ = Blockly.bindEvent_(document, 'mouseup', this, Blockly.Bubble.unbindDragEvents_); Blockly.Bubble.onMouseMoveWrapper_ = Blockly.bindEvent_(document, 'mousemove', this, this.bubbleMouseMove_); Blockly.hideChaff(); // This event has been handled. No need to bubble up to the document. e.stopPropagation(); }; /** * Drag this bubble to follow the mouse. * @param {!Event} e Mouse move event. * @private */ Blockly.Bubble.prototype.bubbleMouseMove_ = function(e) { this.autoLayout_ = false; if (Blockly.RTL) { this.relativeLeft_ = this.dragDeltaX - e.clientX; } else { this.relativeLeft_ = this.dragDeltaX + e.clientX; } this.relativeTop_ = this.dragDeltaY + e.clientY; this.positionBubble_(); this.renderArrow_(); }; /** * Handle a mouse-down on bubble's resize corner. * @param {!Event} e Mouse down event. * @private */ Blockly.Bubble.prototype.resizeMouseDown_ = function(e) { this.promote_(); Blockly.Bubble.unbindDragEvents_(); if (Blockly.isRightButton(e)) { // Right-click. return; } // Left-click (or middle click) Blockly.setCursorHand_(true); // Record the starting offset between the current location and the mouse. if (Blockly.RTL) { this.resizeDeltaWidth = this.width_ + e.clientX; } else { this.resizeDeltaWidth = this.width_ - e.clientX; } this.resizeDeltaHeight = this.height_ - e.clientY; Blockly.Bubble.onMouseUpWrapper_ = Blockly.bindEvent_(document, 'mouseup', this, Blockly.Bubble.unbindDragEvents_); Blockly.Bubble.onMouseMoveWrapper_ = Blockly.bindEvent_(document, 'mousemove', this, this.resizeMouseMove_); Blockly.hideChaff(); // This event has been handled. No need to bubble up to the document. e.stopPropagation(); }; /** * Resize this bubble to follow the mouse. * @param {!Event} e Mouse move event. * @private */ Blockly.Bubble.prototype.resizeMouseMove_ = function(e) { this.autoLayout_ = false; var w = this.resizeDeltaWidth; var h = this.resizeDeltaHeight + e.clientY; if (Blockly.RTL) { // RTL drags the bottom-left corner. w -= e.clientX; } else { // LTR drags the bottom-right corner. w += e.clientX; } this.setBubbleSize(w, h); if (Blockly.RTL) { // RTL requires the bubble to move its left edge. this.positionBubble_(); } }; /** * Register a function as a callback event for when the bubble is resized. * @param {Object} thisObject The value of 'this' in the callback. * @param {!Function} callback The function to call on resize. */ Blockly.Bubble.prototype.registerResizeEvent = function(thisObject, callback) { Blockly.bindEvent_(this.bubbleGroup_, 'resize', thisObject, callback); }; /** * Move this bubble to the top of the stack. * @private */ Blockly.Bubble.prototype.promote_ = function() { var svgGroup = this.bubbleGroup_.parentNode; svgGroup.appendChild(this.bubbleGroup_); }; /** * Notification that the anchor has moved. * Update the arrow and bubble accordingly. * @param {number} x Absolute horizontal location. * @param {number} y Absolute vertical location. */ Blockly.Bubble.prototype.setAnchorLocation = function(x, y) { this.anchorX_ = x; this.anchorY_ = y; if (this.rendered_) { this.positionBubble_(); } }; /** * Position the bubble so that it does not fall offscreen. * @private */ Blockly.Bubble.prototype.layoutBubble_ = function() { // Compute the preferred bubble location. var relativeLeft = -this.width_ / 4; var relativeTop = -this.height_ - Blockly.BlockSvg.MIN_BLOCK_Y; // Prevent the bubble from being offscreen. if (this.workspace_.scrollbar) { // Fetch the workspace's metrics, if they exist. var metrics = this.workspace_.getMetrics(); if (this.anchorX_ + relativeLeft < Blockly.BlockSvg.SEP_SPACE_X + metrics.viewLeft) { // Slide the bubble right until it is onscreen. relativeLeft = Blockly.BlockSvg.SEP_SPACE_X + metrics.viewLeft - this.anchorX_; } else if (metrics.viewLeft + metrics.viewWidth < this.anchorX_ + relativeLeft + this.width_ + Blockly.BlockSvg.SEP_SPACE_X + Blockly.Scrollbar.scrollbarThickness) { // Slide the bubble left until it is onscreen. relativeLeft = metrics.viewLeft + metrics.viewWidth - this.anchorX_ - this.width_ - Blockly.BlockSvg.SEP_SPACE_X - Blockly.Scrollbar.scrollbarThickness; } if (this.anchorY_ + relativeTop < Blockly.BlockSvg.SEP_SPACE_Y + metrics.viewTop) { // Slide the bubble below the block. var bBox = /** @type {SVGLocatable} */ (this.shape_).getBBox(); relativeTop = bBox.height; } } this.relativeLeft_ = relativeLeft; this.relativeTop_ = relativeTop; }; /** * Move the bubble to a location relative to the anchor's centre. * @private */ Blockly.Bubble.prototype.positionBubble_ = function() { var left; if (Blockly.RTL) { left = this.anchorX_ - this.relativeLeft_ - this.width_; } else { left = this.anchorX_ + this.relativeLeft_; } var top = this.relativeTop_ + this.anchorY_; this.bubbleGroup_.setAttribute('transform', 'translate(' + left + ', ' + top + ')'); }; /** * Get the dimensions of this bubble. * @return {!Object} Object with width and height properties. */ Blockly.Bubble.prototype.getBubbleSize = function() { return {width: this.width_, height: this.height_}; }; /** * Size this bubble. * @param {number} width Width of the bubble. * @param {number} height Height of the bubble. */ Blockly.Bubble.prototype.setBubbleSize = function(width, height) { var doubleBorderWidth = 2 * Blockly.Bubble.BORDER_WIDTH; // Minimum size of a bubble. width = Math.max(width, doubleBorderWidth + 45); height = Math.max(height, doubleBorderWidth + Blockly.BlockSvg.FIELD_HEIGHT); this.width_ = width; this.height_ = height; this.bubbleBack_.setAttribute('width', width); this.bubbleBack_.setAttribute('height', height); if (this.resizeGroup_) { if (Blockly.RTL) { // Mirror the resize group. var resizeSize = 2 * Blockly.Bubble.BORDER_WIDTH; this.resizeGroup_.setAttribute('transform', 'translate(' + resizeSize + ', ' + (height - doubleBorderWidth) + ') scale(-1 1)'); } else { this.resizeGroup_.setAttribute('transform', 'translate(' + (width - doubleBorderWidth) + ', ' + (height - doubleBorderWidth) + ')'); } } if (this.rendered_) { if (this.autoLayout_) { this.layoutBubble_(); } this.positionBubble_(); this.renderArrow_(); } // Fire an event to allow the contents to resize. Blockly.fireUiEvent(this.bubbleGroup_, 'resize'); }; /** * Draw the arrow between the bubble and the origin. * @private */ Blockly.Bubble.prototype.renderArrow_ = function() { var steps = []; // Find the relative coordinates of the center of the bubble. var relBubbleX = this.width_ / 2; var relBubbleY = this.height_ / 2; // Find the relative coordinates of the center of the anchor. var relAnchorX = -this.relativeLeft_; var relAnchorY = -this.relativeTop_; if (relBubbleX == relAnchorX && relBubbleY == relAnchorY) { // Null case. Bubble is directly on top of the anchor. // Short circuit this rather than wade through divide by zeros. steps.push('M ' + relBubbleX + ',' + relBubbleY); } else { // Compute the angle of the arrow's line. var rise = relAnchorY - relBubbleY; var run = relAnchorX - relBubbleX; if (Blockly.RTL) { run *= -1; } var hypotenuse = Math.sqrt(rise * rise + run * run); var angle = Math.acos(run / hypotenuse); if (rise < 0) { angle = 2 * Math.PI - angle; } // Compute a line perpendicular to the arrow. var rightAngle = angle + Math.PI / 2; if (rightAngle > Math.PI * 2) { rightAngle -= Math.PI * 2; } var rightRise = Math.sin(rightAngle); var rightRun = Math.cos(rightAngle); // Calculate the thickness of the base of the arrow. var bubbleSize = this.getBubbleSize(); var thickness = (bubbleSize.width + bubbleSize.height) / Blockly.Bubble.ARROW_THICKNESS; thickness = Math.min(thickness, bubbleSize.width, bubbleSize.height) / 2; // Back the tip of the arrow off of the anchor. var backoffRatio = 1 - Blockly.Bubble.ANCHOR_RADIUS / hypotenuse; relAnchorX = relBubbleX + backoffRatio * run; relAnchorY = relBubbleY + backoffRatio * rise; // Coordinates for the base of the arrow. var baseX1 = relBubbleX + thickness * rightRun; var baseY1 = relBubbleY + thickness * rightRise; var baseX2 = relBubbleX - thickness * rightRun; var baseY2 = relBubbleY - thickness * rightRise; // Distortion to curve the arrow. var swirlAngle = angle + this.arrow_radians_; if (swirlAngle > Math.PI * 2) { swirlAngle -= Math.PI * 2; } var swirlRise = Math.sin(swirlAngle) * hypotenuse / Blockly.Bubble.ARROW_BEND; var swirlRun = Math.cos(swirlAngle) * hypotenuse / Blockly.Bubble.ARROW_BEND; steps.push('M' + baseX1 + ',' + baseY1); steps.push('C' + (baseX1 + swirlRun) + ',' + (baseY1 + swirlRise) + ' ' + relAnchorX + ',' + relAnchorY + ' ' + relAnchorX + ',' + relAnchorY); steps.push('C' + relAnchorX + ',' + relAnchorY + ' ' + (baseX2 + swirlRun) + ',' + (baseY2 + swirlRise) + ' ' + baseX2 + ',' + baseY2); } steps.push('z'); this.bubbleArrow_.setAttribute('d', steps.join(' ')); }; /** * Change the colour of a bubble. * @param {string} hexColour Hex code of colour. */ Blockly.Bubble.prototype.setColour = function(hexColour) { this.bubbleBack_.setAttribute('fill', hexColour); this.bubbleArrow_.setAttribute('fill', hexColour); }; /** * Dispose of this bubble. */ Blockly.Bubble.prototype.dispose = function() { Blockly.Bubble.unbindDragEvents_(); // Dispose of and unlink the bubble. goog.dom.removeNode(this.bubbleGroup_); this.bubbleGroup_ = null; this.workspace_ = null; this.content_ = null; this.shape_ = null; }; ================================================ FILE: extern/blockly/core/comment.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Object representing a code comment. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Comment'); goog.require('Blockly.Bubble'); goog.require('Blockly.Icon'); /** * Class for a comment. * @param {!Blockly.Block} block The block associated with this comment. * @extends {Blockly.Icon} * @constructor */ Blockly.Comment = function(block) { Blockly.Comment.superClass_.constructor.call(this, block); this.createIcon_(); }; goog.inherits(Blockly.Comment, Blockly.Icon); /** * Comment text (if bubble is not visible). * @private */ Blockly.Comment.prototype.text_ = ''; /** * Width of bubble. * @private */ Blockly.Comment.prototype.width_ = 160; /** * Height of bubble. * @private */ Blockly.Comment.prototype.height_ = 80; /** * Create the icon on the block. * @private */ Blockly.Comment.prototype.createIcon_ = function() { Blockly.Icon.prototype.createIcon_.call(this); /* Here's the markup that will be generated: ? */ var iconShield = Blockly.createSvgElement('circle', {'class': 'blocklyIconShield', 'r': Blockly.Icon.RADIUS, 'cx': Blockly.Icon.RADIUS, 'cy': Blockly.Icon.RADIUS}, this.iconGroup_); this.iconMark_ = Blockly.createSvgElement('text', {'class': 'blocklyIconMark', 'x': Blockly.Icon.RADIUS, 'y': 2 * Blockly.Icon.RADIUS - 3}, this.iconGroup_); this.iconMark_.appendChild(document.createTextNode('?')); }; /** * Create the editor for the comment's bubble. * @return {!Element} The top-level node of the editor. * @private */ Blockly.Comment.prototype.createEditor_ = function() { /* Create the editor. Here's the markup that will be generated: */ this.foreignObject_ = Blockly.createSvgElement('foreignObject', {'x': Blockly.Bubble.BORDER_WIDTH, 'y': Blockly.Bubble.BORDER_WIDTH}, null); var body = document.createElementNS(Blockly.HTML_NS, 'body'); body.setAttribute('xmlns', Blockly.HTML_NS); body.className = 'blocklyMinimalBody'; this.textarea_ = document.createElementNS(Blockly.HTML_NS, 'textarea'); this.textarea_.className = 'blocklyCommentTextarea'; this.textarea_.setAttribute('dir', Blockly.RTL ? 'RTL' : 'LTR'); this.updateEditable(); body.appendChild(this.textarea_); this.foreignObject_.appendChild(body); Blockly.bindEvent_(this.textarea_, 'mouseup', this, this.textareaFocus_); return this.foreignObject_; }; /** * Add or remove editability of the textarea. * @override */ Blockly.Comment.prototype.updateEditable = function() { if (this.textarea_) { if (!this.block_.isEditable()) { this.textarea_.setAttribute('disabled', 'disabled'); this.textarea_.setAttribute('readonly', 'readonly'); } else { this.textarea_.removeAttribute('disabled'); this.textarea_.removeAttribute('readonly'); } } // Allow the icon to update. Blockly.Icon.prototype.updateEditable.call(this); }; /** * Callback function triggered when the bubble has resized. * Resize the text area accordingly. * @private */ Blockly.Comment.prototype.resizeBubble_ = function() { var size = this.bubble_.getBubbleSize(); var doubleBorderWidth = 2 * Blockly.Bubble.BORDER_WIDTH; this.foreignObject_.setAttribute('width', size.width - doubleBorderWidth); this.foreignObject_.setAttribute('height', size.height - doubleBorderWidth); this.textarea_.style.width = (size.width - doubleBorderWidth - 4) + 'px'; this.textarea_.style.height = (size.height - doubleBorderWidth - 4) + 'px'; }; /** * Show or hide the comment bubble. * @param {boolean} visible True if the bubble should be visible. */ Blockly.Comment.prototype.setVisible = function(visible) { if (visible == this.isVisible()) { // No change. return; } // Save the bubble stats before the visibility switch. var text = this.getText(); var size = this.getBubbleSize(); if (visible) { // Create the bubble. this.bubble_ = new Blockly.Bubble( /** @type {!Blockly.Workspace} */ (this.block_.workspace), this.createEditor_(), this.block_.svg_.svgGroup_, this.iconX_, this.iconY_, this.width_, this.height_); this.bubble_.registerResizeEvent(this, this.resizeBubble_); this.updateColour(); this.text_ = null; } else { // Dispose of the bubble. this.bubble_.dispose(); this.bubble_ = null; this.textarea_ = null; this.foreignObject_ = null; } // Restore the bubble stats after the visibility switch. this.setText(text); this.setBubbleSize(size.width, size.height); }; /** * Bring the comment to the top of the stack when clicked on. * @param {!Event} e Mouse up event. * @private */ Blockly.Comment.prototype.textareaFocus_ = function(e) { // Ideally this would be hooked to the focus event for the comment. // However doing so in Firefox swallows the cursor for unknown reasons. // So this is hooked to mouseup instead. No big deal. this.bubble_.promote_(); // Since the act of moving this node within the DOM causes a loss of focus, // we need to reapply the focus. this.textarea_.focus(); }; /** * Get the dimensions of this comment's bubble. * @return {!Object} Object with width and height properties. */ Blockly.Comment.prototype.getBubbleSize = function() { if (this.isVisible()) { return this.bubble_.getBubbleSize(); } else { return {width: this.width_, height: this.height_}; } }; /** * Size this comment's bubble. * @param {number} width Width of the bubble. * @param {number} height Height of the bubble. */ Blockly.Comment.prototype.setBubbleSize = function(width, height) { if (this.isVisible()) { this.bubble_.setBubbleSize(width, height); } else { this.width_ = width; this.height_ = height; } }; /** * Returns this comment's text. * @return {string} Comment text. */ Blockly.Comment.prototype.getText = function() { return this.isVisible() ? this.textarea_.value : this.text_; }; /** * Set this comment's text. * @param {string} text Comment text. */ Blockly.Comment.prototype.setText = function(text) { if (this.isVisible()) { this.textarea_.value = text; } else { this.text_ = text; } }; /** * Dispose of this comment. */ Blockly.Comment.prototype.dispose = function() { this.block_.comment = null; Blockly.Icon.prototype.dispose.call(this); }; ================================================ FILE: extern/blockly/core/connection-animation.js ================================================ 'use strict'; goog.provide('Blockly.ConnectionAnimation'); goog.require('Blockly.Connection'); goog.require('goog.Timer'); /** * Class for a connection animation between blocks. * @param {!Blockly.Block} source The block establishing this connection. * @param {number} type The type of the connection. * @constructor */ Blockly.ConnectionAnimation = function() { }; /** * URL of the connection image * @type {string} * @private */ Blockly.ConnectionAnimation.prototype.IMG_URL_ = 'media/ani.png'; /** * Width connection image * @type {number} * @private */ Blockly.ConnectionAnimation.prototype.IMG_WIDTH_ = 23; /** * Height of the connection image * @type {number} * @private */ Blockly.ConnectionAnimation.prototype.IMG_HEIGHT_ = 23; /** * The SVG group containing the connection animation * @type {Element} * @private */ Blockly.ConnectionAnimation.prototype.svgGroup_ = null; /** * The SVG group containing the connection animation * @type {Element} * @private */ Blockly.ConnectionAnimation.prototype.svgBody_ = null; /** * Current scale of the img. * @type {number} * @private */ Blockly.ConnectionAnimation.prototype.scale_ = 0; /** * Current scale of the img. * @type {number} * @private */ Blockly.ConnectionAnimation.prototype.current_x_ = 0; /** * Current scale of the img. * @type {number} * @private */ Blockly.ConnectionAnimation.prototype.current_y_ = 0; /** * Target scale of the img. * @type {number} * @private */ Blockly.ConnectionAnimation.prototype.target_scale_ = 0.95; /** * Create the animation img elements. * @return {!Element} The anmimation SVG group */ Blockly.ConnectionAnimation.prototype.createDom = function() { this.svgGroup_ = Blockly.createSvgElement('g', {}, null); this.svgBody_ = Blockly.createSvgElement('image', {'width': this.IMG_WIDTH_, 'height': this.IMG_HEIGHT_}, this.svgGroup_); this.svgBody_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', Blockly.pathToBlockly + this.IMG_URL_); this.svgBody_.setAttribute('transform', 'scale(' + this.scale_ + ')'); return this.svgGroup_; }; /** * Initialize the animation image. */ Blockly.ConnectionAnimation.prototype.init = function() { this.hide_(); }; /** * Initialize the animation image. */ Blockly.ConnectionAnimation.prototype.hide_ = function () { if (this.scale_ <= 0) return; this.scale_ -= 0.1; this.svgBody_.setAttribute('transform', 'scale(' + this.scale_ + ')'); goog.Timer.callOnce(this.hide_, 5, this); }; /** * Initialize the animation image. */ Blockly.ConnectionAnimation.prototype.show_ = function (sourceBlock, connection) { if ( sourceBlock ) { var svg = sourceBlock.svg_.getRootElement(); this.bbox = svg.getBBox(); var xy = Blockly.getSvgXY_(svg); this.blockHeight = sourceBlock.svg_.height + 15; this.current_x_ = xy.x; this.current_y_ = xy.y; } if (connection) this.connection_ = connection; if (this.connection_ != this.connection_.sourceBlock_.outputConnection && this.connection_ != this.connection_.sourceBlock_.previousConnection && this.connection_ != this.connection_.sourceBlock_.nextConnection) this.svgGroup_.setAttribute('transform', 'translate(' + (this.current_x_ + Blockly.BlockSvg.NOTCH_WIDTH) + ',' + (this.current_y_ + this.blockHeight) + ')'); else this.svgGroup_.setAttribute('transform', 'translate(' + (this.current_x_) + ',' + (this.current_y_ + this.bbox.height) + ')'); if (this.scale_ >= 1) { this.svgBody_.setAttribute('transform', //'translate(' + (1 - this.target_scale_) * this.current_x_+12 + ','+ (1 - this.target_scale_) + this.current_y_+12 + ') ' + 'scale(' + this.target_scale_ + ')' ); return; } this.scale_ += 0.02; this.svgBody_.setAttribute('transform', //'translate(' + (1 - this.scale_) * this.current_x_ + 12 + ','+ (1 - this.scale_) + this.current_y_ + 12 + ') ' + 'scale(' + this.scale_ + ')' ); goog.Timer.callOnce(this.show_, 5, this); }; ================================================ FILE: extern/blockly/core/connection.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Components for creating connections between blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Connection'); goog.provide('Blockly.ConnectionDB'); goog.require('Blockly.Workspace'); /** * Class for a connection between blocks. * @param {!Blockly.Block} source The block establishing this connection. * @param {number} type The type of the connection. * @constructor */ Blockly.Connection = function(source, type) { this.sourceBlock_ = source; this.targetConnection = null; this.type = type; this.x_ = 0; this.y_ = 0; this.inDB_ = false; // Shortcut for the databases for this connection's workspace. this.dbList_ = this.sourceBlock_.workspace.connectionDBList; }; /** * Sever all links to this connection (not including from the source object). */ Blockly.Connection.prototype.dispose = function() { if (this.targetConnection) { throw 'Disconnect connection before disposing of it.'; } if (this.inDB_) { this.dbList_[this.type].removeConnection_(this); } this.inDB_ = false; if (Blockly.highlightedConnection_ == this) { Blockly.highlightedConnection_ = null; } if (Blockly.localConnection_ == this) { Blockly.localConnection_ = null; } }; /** * Does the connection belong to a superior block (higher in the source stack)? * @return {boolean} True if connection faces down or right. */ Blockly.Connection.prototype.isSuperior = function() { return this.type == Blockly.INPUT_VALUE || this.type == Blockly.NEXT_STATEMENT; }; /** * Connect this connection to another connection. * @param {!Blockly.Connection} otherConnection Connection to connect to. */ Blockly.Connection.prototype.connect = function(otherConnection) { if (this.sourceBlock_ == otherConnection.sourceBlock_) { throw 'Attempted to connect a block to itself.'; } if (this.sourceBlock_.workspace !== otherConnection.sourceBlock_.workspace) { throw 'Blocks are on different workspaces.'; } if (Blockly.OPPOSITE_TYPE[this.type] != otherConnection.type) { throw 'Attempt to connect incompatible types.'; } if (this.type == Blockly.INPUT_VALUE || this.type == Blockly.OUTPUT_VALUE) { if (this.targetConnection) { // Can't make a value connection if male block is already connected. throw 'Source connection already connected (value).'; } else if (otherConnection.targetConnection) { // Statement blocks may be inserted into the middle of a stack. // If female block is already connected, disconnect and bump the male. var orphanBlock = otherConnection.targetBlock(); orphanBlock.setParent(null); if (!orphanBlock.outputConnection) { throw 'Orphan block does not have an output connection.'; } // Attempt to reattach the orphan at the end of the newly inserted // block. Since this block may be a row, walk down to the end. var newBlock = this.sourceBlock_; var connection; while (connection = Blockly.Connection.singleConnection_( /** @type {!Blockly.Block} */ (newBlock), orphanBlock)) { // '=' is intentional in line above. if (connection.targetBlock()) { newBlock = connection.targetBlock(); } else { connection.connect(orphanBlock.outputConnection); orphanBlock = null; break; } } if (orphanBlock) { // Unable to reattach orphan. Bump it off to the side. var blockType = orphanBlock.type.toUpperCase(); if (Blockly.primitiveTypes.indexOf(blockType) > -1) orphanBlock.dispose(true, false); else { window.setTimeout(function() { orphanBlock.outputConnection.bumpAwayFrom_(otherConnection); }, Blockly.BUMP_DELAY); } //render whole workspace in order to prevent too much space error if (!newBlock.previousConnection && !newBlock.nextConnection) { window.setTimeout(function() { Blockly.mainWorkspace.render(); }, 0); } } } } else { if (this.targetConnection) { throw 'Source connection already connected (block).'; } else if (otherConnection.targetConnection) { // Statement blocks may be inserted into the middle of a stack. if (this.type != Blockly.PREVIOUS_STATEMENT) { throw 'Can only do a mid-stack connection with the top of a block.'; } // Split the stack. var orphanBlock = otherConnection.targetBlock(); orphanBlock.setParent(null); if (!orphanBlock.previousConnection) { throw 'Orphan block does not have a previous connection.'; } // Attempt to reattach the orphan at the bottom of the newly inserted // block. Since this block may be a stack, walk down to the end. var newBlock = this.sourceBlock_; while (newBlock.nextConnection) { if (newBlock.nextConnection.targetConnection) { newBlock = newBlock.nextConnection.targetBlock(); } else { newBlock.nextConnection.connect(orphanBlock.previousConnection); orphanBlock = null; break; } } if (orphanBlock) { // Unable to reattach orphan. Bump it off to the side. window.setTimeout(function() { orphanBlock.previousConnection.bumpAwayFrom_(otherConnection); }, Blockly.BUMP_DELAY); } } } // Determine which block is superior (higher in the source stack). var parentBlock, childBlock; if (this.isSuperior()) { // Superior block. parentBlock = this.sourceBlock_; childBlock = otherConnection.sourceBlock_; } else { // Inferior block. parentBlock = otherConnection.sourceBlock_; childBlock = this.sourceBlock_; } // Establish the connections. this.targetConnection = otherConnection; otherConnection.targetConnection = this; // Demote the inferior block so that one is a child of the superior one. childBlock.setParent(parentBlock); if (parentBlock.rendered) { parentBlock.svg_.updateDisabled(); } if (childBlock.rendered) { childBlock.svg_.updateDisabled(); } if (parentBlock.rendered && childBlock.rendered) { if (this.type == Blockly.NEXT_STATEMENT || this.type == Blockly.PREVIOUS_STATEMENT) { // Child block may need to square off its corners if it is in a stack. // Rendering a child will render its parent. childBlock.render(); } else { // Child block does not change shape. Rendering the parent node will // move its connected children into position. parentBlock.render(); } } }; /** * Does the given block have one and only one connection point that will accept * the orphaned block? * @param {!Blockly.Block} block The superior block. * @param {!Blockly.Block} orphanBlock The inferior block. * @return {Blockly.Connection} The suitable connection point on 'block', * or null. * @private */ Blockly.Connection.singleConnection_ = function(block, orphanBlock) { var connection = false; for (var x = 0; x < block.inputList.length; x++) { var thisConnection = block.inputList[x].connection; if (thisConnection && thisConnection.type == Blockly.INPUT_VALUE && orphanBlock.outputConnection.checkType_(thisConnection)) { if (connection) { return null; // More than one connection. } connection = thisConnection; } } return connection; }; /** * Disconnect this connection. */ Blockly.Connection.prototype.disconnect = function() { var otherConnection = this.targetConnection; if (!otherConnection) { throw 'Source connection not connected.'; } else if (otherConnection.targetConnection != this) { throw 'Target connection not connected to source connection.'; } otherConnection.targetConnection = null; this.targetConnection = null; var sourceBlock = this.sourceBlock_; if (!sourceBlock.isInFlyout && sourceBlock.isEditing && //sourceBlock == Blockly.selected && sourceBlock.outputConnection instanceof Blockly.Connection) { if (otherConnection.sourceBlock_.outputConnection && otherConnection.sourceBlock_.outputConnection.check_[0].toUpperCase() == "PARAM" && otherConnection.check_[0].toUpperCase() != "PARAM") { var xml = Blockly.Xml.blockToDom_(sourceBlock); var newblock = Blockly.Xml.domToBlock(sourceBlock.workspace, xml); otherConnection.connect(newblock.outputConnection); } else if (otherConnection.check_ && otherConnection.check_.indexOf('Number') > -1) { var xml = Blockly.Xml.textToDom('' + '10' + ''); var newblock = Blockly.Xml.domToBlock(sourceBlock.workspace, xml.childNodes[0]); otherConnection.connect(newblock.outputConnection); } else if (otherConnection.check_ && otherConnection.check_.indexOf('String') > -1) { var xml = Blockly.Xml.textToDom('' + '문자' + ''); var newblock = Blockly.Xml.domToBlock(sourceBlock.workspace, xml.childNodes[0]); otherConnection.connect(newblock.outputConnection); } else if (otherConnection.check_ && otherConnection.check_.indexOf('Boolean') > -1) { var xml = Blockly.Xml.textToDom('' + ''); var newblock = Blockly.Xml.domToBlock(sourceBlock.workspace, xml.childNodes[0]); otherConnection.connect(newblock.outputConnection); } sourceBlock.isDrag = false; otherConnection.sourceBlock_.isDrag = false; } // Rerender the parent so that it may reflow. var parentBlock, childBlock; if (this.isSuperior()) { // Superior block. parentBlock = this.sourceBlock_; childBlock = otherConnection.sourceBlock_; } else { // Inferior block. parentBlock = otherConnection.sourceBlock_; childBlock = this.sourceBlock_; } if (parentBlock.rendered) { parentBlock.render(); } if (childBlock.rendered) { childBlock.svg_.updateDisabled(); childBlock.render(); } }; /** * Returns the block that this connection connects to. * @return {Blockly.Block} The connected block or null if none is connected. */ Blockly.Connection.prototype.targetBlock = function() { if (this.targetConnection) { return this.targetConnection.sourceBlock_; } return null; }; /** * Move the block(s) belonging to the connection to a point where they don't * visually interfere with the specified connection. * @param {!Blockly.Connection} staticConnection The connection to move away * from. * @private */ Blockly.Connection.prototype.bumpAwayFrom_ = function(staticConnection) { if (Blockly.Block.dragMode_ != 0) { // Don't move blocks around while the user is doing the same. return; } // Move the root block. var rootBlock = this.sourceBlock_.getRootBlock(); if (rootBlock.isInFlyout) { // Don't move blocks around in a flyout. return; } var reverse = false; if (!rootBlock.isMovable()) { // Can't bump an uneditable block away. // Check to see if the other block is movable. rootBlock = staticConnection.sourceBlock_.getRootBlock(); if (!rootBlock.isMovable()) { return; } // Swap the connections and move the 'static' connection instead. staticConnection = this; reverse = true; } // Raise it to the top for extra visibility. var rootSvg = rootBlock.getSvgRoot(); rootSvg.parentNode.appendChild(rootSvg); var dx = (staticConnection.x_ + Blockly.SNAP_RADIUS) - this.x_; var dy = (staticConnection.y_ + Blockly.SNAP_RADIUS * 2) - this.y_; if (reverse) { // When reversing a bump due to an uneditable block, bump up. dy = -dy; } if (Blockly.RTL) { dx = -dx; } rootBlock.moveBy(dx, dy); }; /** * Change the connection's coordinates. * @param {number} x New absolute x coordinate. * @param {number} y New absolute y coordinate. */ Blockly.Connection.prototype.moveTo = function(x, y) { // Remove it from its old location in the database (if already present) if (this.inDB_) { this.dbList_[this.type].removeConnection_(this); } this.x_ = x; this.y_ = y; // Insert it into its new location in the database. this.dbList_[this.type].addConnection_(this); }; /** * Change the connection's coordinates. * @param {number} dx Change to x coordinate. * @param {number} dy Change to y coordinate. */ Blockly.Connection.prototype.moveBy = function(dx, dy) { this.moveTo(this.x_ + dx, this.y_ + dy); }; /** * Add highlighting around this connection. */ Blockly.Connection.prototype.highlight = function() { var steps; var xy = this.sourceBlock_.getRelativeToSurfaceXY(); var x = this.x_ - xy.x; var y = this.y_ - xy.y; if (this.type == Blockly.INPUT_VALUE || this.type == Blockly.OUTPUT_VALUE) { var inputType = this.check_ ? this.check_[0] : "null"; if (inputType.toUpperCase() == "PARAM") { var targetChecker = this.sourceBlock_.outputConnection; if (targetChecker) { steps = 'M -20,-2 l 2,2 0,3 4,0 0,12 -4,0 0,3 -2,2'; } else steps = 'M -20,3 l -2,2 0,3 4,0 0,12 -4,0 0,3 2,2'; } else if (inputType.toUpperCase() == "BOOLEAN") { var targetChecker = this.targetConnection && this.targetConnection.sourceBlock_; if (targetChecker) { var targetSvg = this.targetConnection.sourceBlock_.svg_. svgPathLight_.getAttribute('d').split('z')[0]; steps = targetSvg + 'z'; } else steps = 'M 16,0 h -20 l -11,11 11,11.5 h 20' + 'l 11,-11 -11,-11 z'; } else { var targetChecker = this.targetConnection && this.targetConnection.sourceBlock_; if (targetChecker) { var targetSvg = this.targetConnection.sourceBlock_.svg_. svgPathLight_.getAttribute('d').split('z')[0]; steps = targetSvg + 'z'; } else steps = 'M 10,0 h -10 a 12,9.9 0 0,0 0,19.5 h 10' + 'a 11,9.9 0 0,0 0,-19.5 z'; } Blockly.Connection.highlightedPath_ = Blockly.createSvgElement('path', {'class': 'blocklyHighlightedConnectionPathInline', 'd': steps, transform: 'translate(' + x + ', ' + y + ')'}, this.sourceBlock_.getSvgRoot()); } else { if (Blockly.RTL) { steps = 'm 20,0 h -5 l -6,4 -3,0 -6,-4 h -5'; } else { steps = 'm -15,0 l 7,8 7,-8'; } Blockly.Connection.highlightedPath_ = Blockly.createSvgElement('path', {'class': 'blocklyHighlightedConnectionPath', 'd': steps, transform: 'translate(' + x + ', ' + y + ')'}, this.sourceBlock_.getSvgRoot()); } }; /** * Remove the highlighting around this connection. */ Blockly.Connection.prototype.unhighlight = function() { goog.dom.removeNode(Blockly.Connection.highlightedPath_); delete Blockly.Connection.highlightedPath_; }; /** * Move the blocks on either side of this connection right next to each other. * @private */ Blockly.Connection.prototype.tighten_ = function() { var dx = Math.round(this.targetConnection.x_ - this.x_); var dy = Math.round(this.targetConnection.y_ - this.y_); if (dx != 0 || dy != 0) { var block = this.targetBlock(); var svgRoot = block.getSvgRoot(); if (!svgRoot) { throw 'block is not rendered.'; } var xy = Blockly.getRelativeXY_(svgRoot); block.getSvgRoot().setAttribute('transform', 'translate(' + (xy.x - dx) + ', ' + (xy.y - dy) + ')'); block.moveConnections_(-dx, -dy); } }; /** * Find the closest compatible connection to this connection. * @param {number} maxLimit The maximum radius to another connection. * @param {number} dx Horizontal offset between this connection's location * in the database and the current location (as a result of dragging). * @param {number} dy Vertical offset between this connection's location * in the database and the current location (as a result of dragging). * @return {!Object} Contains two properties: 'connection' which is either * another connection or null, and 'radius' which is the distance. */ Blockly.Connection.prototype.closest = function(maxLimit, dx, dy) { if (this.targetConnection) { // Don't offer to connect to a connection that's already connected. return {connection: null, radius: maxLimit}; } // Determine the opposite type of connection. var oppositeType = Blockly.OPPOSITE_TYPE[this.type]; var db = this.dbList_[oppositeType]; // Since this connection is probably being dragged, add the delta. var currentX = this.x_ + dx; var currentY = this.y_ + dy; // Binary search to find the closest y location. var pointerMin = 0; var pointerMax = db.length - 2; var pointerMid = pointerMax; while (pointerMin < pointerMid) { if (db[pointerMid].y_ < currentY) { pointerMin = pointerMid; } else { pointerMax = pointerMid; } pointerMid = Math.floor((pointerMin + pointerMax) / 2); } // Walk forward and back on the y axis looking for the closest x,y point. pointerMin = pointerMid; pointerMax = pointerMid; var closestConnection = null; var sourceBlock = this.sourceBlock_; var thisConnection = this; if (db.length) { while (pointerMin >= 0 && checkConnection_(pointerMin)) { pointerMin--; } do { pointerMax++; } while (pointerMax < db.length && checkConnection_(pointerMax)); } /** * Computes if the current connection is within the allowed radius of another * connection. * This function is a closure and has access to outside variables. * @param {number} yIndex The other connection's index in the database. * @return {boolean} True if the search needs to continue: either the current * connection's vertical distance from the other connection is less than * the allowed radius, or if the connection is not compatible. */ function checkConnection_(yIndex) { var connection = db[yIndex]; if (connection.type == Blockly.OUTPUT_VALUE || connection.type == Blockly.PREVIOUS_STATEMENT) { // Don't offer to connect an already connected left (male) value plug to // an available right (female) value plug. Don't offer to connect the // bottom of a statement block to one that's already connected. if (connection.targetConnection) { return true; } } // Offering to connect the top of a statement block to an already connected // connection is ok, we'll just insert it into the stack. // Offering to connect the left (male) of a value block to an already // connected value pair is ok, we'll splice it in. // Do type checking. if (!thisConnection.checkType_(connection)) { return true; } // Don't let blocks try to connect to themselves or ones they nest. var targetSourceBlock = connection.sourceBlock_; do { if (sourceBlock == targetSourceBlock) { return true; } targetSourceBlock = targetSourceBlock.getParent(); } while (targetSourceBlock); var dx = currentX - db[yIndex].x_; var dy = currentY - db[yIndex].y_; var r = Math.sqrt(dx * dx + dy * dy); if (r <= maxLimit) { closestConnection = db[yIndex]; maxLimit = r; } return dy < maxLimit; } return {connection: closestConnection, radius: maxLimit}; }; /** * Is this connection compatible with another connection with respect to the * value type system. E.g. square_root("Hello") is not compatible. * @param {!Blockly.Connection} otherConnection Connection to compare against. * @return {boolean} True if the connections share a type. * @private */ Blockly.Connection.prototype.checkType_ = function(otherConnection) { if (this.sourceBlock_.isInFlyout || otherConnection.sourceBlock_.isInFlyout) return false; if (!this.check_ || !otherConnection.check_) { // One or both sides are promiscuous enough that anything will fit. return true; } // Find any intersection in the check lists. for (var x = 0; x < this.check_.length; x++) { if (otherConnection.check_.indexOf(this.check_[x]) != -1) { return true; } } // No intersection. return false; }; /** * Change a connection's compatibility. * @param {*} check Compatible value type or list of value types. * Null if all types are compatible. * @return {!Blockly.Connection} The connection being modified * (to allow chaining). */ Blockly.Connection.prototype.setCheck = function(check) { if (check) { // Ensure that check is in an array. if (!(check instanceof Array)) { check = [check]; } this.check_ = check; // The new value type may not be compatible with the existing connection. if (this.targetConnection && !this.checkType_(this.targetConnection)) { if (this.isSuperior()) { this.targetBlock().setParent(null); } else { this.sourceBlock_.setParent(null); } // Bump away. this.sourceBlock_.bumpNeighbours_(); } } else { this.check_ = null; } return this; }; /** * Find all nearby compatible connections to this connection. * Type checking does not apply, since this function is used for bumping. * @param {number} maxLimit The maximum radius to another connection. * @return {!Array.} List of connections. * @private */ Blockly.Connection.prototype.neighbours_ = function(maxLimit) { // Determine the opposite type of connection. var oppositeType = Blockly.OPPOSITE_TYPE[this.type]; var db = this.dbList_[oppositeType]; var currentX = this.x_; var currentY = this.y_; // Binary search to find the closest y location. var pointerMin = 0; var pointerMax = db.length - 2; var pointerMid = pointerMax; while (pointerMin < pointerMid) { if (db[pointerMid].y_ < currentY) { pointerMin = pointerMid; } else { pointerMax = pointerMid; } pointerMid = Math.floor((pointerMin + pointerMax) / 2); } // Walk forward and back on the y axis looking for the closest x,y point. pointerMin = pointerMid; pointerMax = pointerMid; var neighbours = []; var sourceBlock = this.sourceBlock_; if (db.length) { while (pointerMin >= 0 && checkConnection_(pointerMin)) { pointerMin--; } do { pointerMax++; } while (pointerMax < db.length && checkConnection_(pointerMax)); } /** * Computes if the current connection is within the allowed radius of another * connection. * This function is a closure and has access to outside variables. * @param {number} yIndex The other connection's index in the database. * @return {boolean} True if the current connection's vertical distance from * the other connection is less than the allowed radius. */ function checkConnection_(yIndex) { var dx = currentX - db[yIndex].x_; var dy = currentY - db[yIndex].y_; var r = Math.sqrt(dx * dx + dy * dy); if (r <= maxLimit) { neighbours.push(db[yIndex]); } return dy < maxLimit; } return neighbours; }; /** * Hide this connection, as well as all down-stream connections on any block * attached to this connection. This happens when a block is collapsed. * Also hides down-stream comments. */ Blockly.Connection.prototype.hideAll = function() { if (this.inDB_) { this.dbList_[this.type].removeConnection_(this); } if (this.targetConnection) { var blocks = this.targetBlock().getDescendants(); for (var b = 0; b < blocks.length; b++) { var block = blocks[b]; // Hide all connections of all children. var connections = block.getConnections_(true); for (var c = 0; c < connections.length; c++) { var connection = connections[c]; if (connection.inDB_) { this.dbList_[connection.type].removeConnection_(connection); } } // Close all bubbles of all children. var icons = block.getIcons(); for (var x = 0; x < icons.length; x++) { icons[x].setVisible(false); } } } }; /** * Unhide this connection, as well as all down-stream connections on any block * attached to this connection. This happens when a block is expanded. * Also unhides down-stream comments. * @return {!Array.} List of blocks to render. */ Blockly.Connection.prototype.unhideAll = function() { if (!this.inDB_) { this.dbList_[this.type].addConnection_(this); } // All blocks that need unhiding must be unhidden before any rendering takes // place, since rendering requires knowing the dimensions of lower blocks. // Also, since rendering a block renders all its parents, we only need to // render the leaf nodes. var renderList = []; if (this.type != Blockly.INPUT_VALUE && this.type != Blockly.NEXT_STATEMENT) { // Only spider down. return renderList; } var block = this.targetBlock(); if (block) { var connections; if (block.isCollapsed()) { // This block should only be partially revealed since it is collapsed. connections = []; block.outputConnection && connections.push(block.outputConnection); block.nextConnection && connections.push(block.nextConnection); block.previousConnection && connections.push(block.previousConnection); } else { // Show all connections of this block. connections = block.getConnections_(true); } for (var c = 0; c < connections.length; c++) { renderList = renderList.concat(connections[c].unhideAll()); } if (renderList.length == 0) { // Leaf block. renderList[0] = block; } } return renderList; }; /** * Database of connections. * Connections are stored in order of their vertical component. This way * connections in an area may be looked up quickly using a binary search. * @constructor */ Blockly.ConnectionDB = function() { }; Blockly.ConnectionDB.prototype = new Array(); /** * Don't inherit the constructor from Array. * @type {!Function} */ Blockly.ConnectionDB.constructor = Blockly.ConnectionDB; /** * Add a connection to the database. Must not already exist in DB. * @param {!Blockly.Connection} connection The connection to be added. * @private */ Blockly.ConnectionDB.prototype.addConnection_ = function(connection) { if (connection.inDB_) { throw 'Connection already in database.'; } // Insert connection using binary search. var pointerMin = 0; var pointerMax = this.length; while (pointerMin < pointerMax) { var pointerMid = Math.floor((pointerMin + pointerMax) / 2); if (this[pointerMid].y_ < connection.y_) { pointerMin = pointerMid + 1; } else if (this[pointerMid].y_ > connection.y_) { pointerMax = pointerMid; } else { pointerMin = pointerMid; break; } } this.splice(pointerMin, 0, connection); connection.inDB_ = true; }; /** * Remove a connection from the database. Must already exist in DB. * @param {!Blockly.Connection} connection The connection to be removed. * @private */ Blockly.ConnectionDB.prototype.removeConnection_ = function(connection) { if (!connection.inDB_) { throw 'Connection not in database.'; } connection.inDB_ = false; // Find the connection using a binary search. var pointerMin = 0; var pointerMax = this.length - 2; var pointerMid = pointerMax; while (pointerMin < pointerMid) { if (this[pointerMid].y_ < connection.y_) { pointerMin = pointerMid; } else { pointerMax = pointerMid; } pointerMid = Math.floor((pointerMin + pointerMax) / 2); } // Walk forward and back on the y axis looking for the connection. // When found, splice it out of the array. pointerMin = pointerMid; pointerMax = pointerMid; while (pointerMin >= 0 && this[pointerMin].y_ == connection.y_) { if (this[pointerMin] == connection) { this.splice(pointerMin, 1); return; } pointerMin--; } do { if (this[pointerMax] == connection) { this.splice(pointerMax, 1); return; } pointerMax++; } while (pointerMax < this.length && this[pointerMax].y_ == connection.y_); throw 'Unable to find connection in connectionDB.'; }; /** * Initialize a set of connection DBs for a specified workspace. * @param {!Blockly.Workspace} workspace The workspace this DB is for. */ Blockly.ConnectionDB.init = function(workspace) { // Create four databases, one for each connection type. var dbList = []; dbList[Blockly.INPUT_VALUE] = new Blockly.ConnectionDB(); dbList[Blockly.OUTPUT_VALUE] = new Blockly.ConnectionDB(); dbList[Blockly.NEXT_STATEMENT] = new Blockly.ConnectionDB(); dbList[Blockly.PREVIOUS_STATEMENT] = new Blockly.ConnectionDB(); workspace.connectionDBList = dbList; }; ================================================ FILE: extern/blockly/core/contextmenu.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Functionality for the right-click context menus. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.ContextMenu'); /** * Horizontal padding on either side of each option. */ Blockly.ContextMenu.X_PADDING = 20; /** * Vertical height of each option. */ Blockly.ContextMenu.Y_HEIGHT = 20; /** * Is a context menu currently showing? */ Blockly.ContextMenu.visible = false; /** * Creates the context menu's DOM. Only needs to be called once. * @return {!SVGGElement} The context menu's SVG group. */ Blockly.ContextMenu.createDom = function() { /* */ var svgGroup = /** @type {!SVGGElement} */ ( Blockly.createSvgElement('g', {'class': 'blocklyHidden'}, null)); Blockly.ContextMenu.svgGroup = svgGroup; Blockly.ContextMenu.svgShadow = Blockly.createSvgElement('rect', {'class': 'blocklyContextMenuShadow', 'x': 2, 'y': -2}, svgGroup); Blockly.ContextMenu.svgBackground = Blockly.createSvgElement('rect', {'class': 'blocklyContextMenuBackground', 'y': -4}, svgGroup); Blockly.ContextMenu.svgOptions = Blockly.createSvgElement('g', {'class': 'blocklyContextMenuOptions'}, svgGroup); Blockly.contextMenu = svgGroup; return svgGroup; }; /** * Construct the menu based on the list of options and show the menu. * @param {!Object} xy Coordinates of anchor point, contains x and y properties. * @param {!Array.} options Array of menu options. */ Blockly.ContextMenu.show = function(xy, options) { if (!options.length) { Blockly.ContextMenu.hide(); return; } /* Here's what one option object looks like: {text: 'Make It So', enabled: true, callback: Blockly.MakeItSo} */ // Erase all existing options. goog.dom.removeChildren(Blockly.ContextMenu.svgOptions); /* Here's the SVG we want for each option: Make It So */ // The menu must be made visible early since otherwise BBox and // getComputedTextLength will return 0. Blockly.ContextMenu.svgGroup.style.display = 'block'; var maxWidth = 0; var resizeList = [Blockly.ContextMenu.svgBackground, Blockly.ContextMenu.svgShadow]; for (var x = 0, option; option = options[x]; x++) { var gElement = Blockly.ContextMenu.optionToDom(option.text); var rectElement = /** @type {SVGRectElement} */ (gElement.firstChild); var textElement = /** @type {SVGTextElement} */ (gElement.lastChild); Blockly.ContextMenu.svgOptions.appendChild(gElement); gElement.setAttribute('transform', 'translate(0, ' + (x * Blockly.ContextMenu.Y_HEIGHT) + ')'); resizeList.push(rectElement); Blockly.bindEvent_(gElement, 'mousedown', null, Blockly.noEvent); if (option.enabled) { Blockly.bindEvent_(gElement, 'mouseup', null, option.callback); Blockly.bindEvent_(gElement, 'mouseup', null, Blockly.ContextMenu.hide); } else { gElement.setAttribute('class', 'blocklyMenuDivDisabled'); } // Compute the length of the longest text length. maxWidth = Math.max(maxWidth, textElement.getComputedTextLength()); } // Run a second pass to resize all options to the required width. maxWidth += Blockly.ContextMenu.X_PADDING * 2; for (var x = 0; x < resizeList.length; x++) { resizeList[x].setAttribute('width', maxWidth); } if (Blockly.RTL) { // Right-align the text. for (var x = 0, gElement; gElement = Blockly.ContextMenu.svgOptions.childNodes[x]; x++) { var textElement = gElement.lastChild; textElement.setAttribute('text-anchor', 'end'); textElement.setAttribute('x', maxWidth - Blockly.ContextMenu.X_PADDING); } } Blockly.ContextMenu.svgBackground.setAttribute('height', options.length * Blockly.ContextMenu.Y_HEIGHT + 8); Blockly.ContextMenu.svgShadow.setAttribute('height', options.length * Blockly.ContextMenu.Y_HEIGHT + 10); // Convert the mouse coordinates into SVG coordinates. var anchorX = xy.x; var anchorY = xy.y; // Measure the menu's size and position it so that it does not go off-screen. var bBox = Blockly.ContextMenu.svgGroup.getBBox(); var svgSize = Blockly.svgSize(); if (anchorY + bBox.height > svgSize.height) { // Falling off the bottom of the screen; flip the menu up. anchorY -= bBox.height - 10; } if (Blockly.RTL) { if (anchorX - bBox.width <= 0) { anchorX++; } else { // Falling off the left edge in RTL mode; flip menu to right. anchorX -= bBox.width; } } else { if (anchorX + bBox.width > svgSize.width) { // Falling off the right edge in LTR mode; flip the menu to left. anchorX -= bBox.width; } else { anchorX++; } } Blockly.ContextMenu.svgGroup.setAttribute('transform', 'translate(' + anchorX + ', ' + anchorY + ')'); Blockly.ContextMenu.visible = true; }; /** * Create the DOM nodes for a menu option. * @param {string} text The option's text. * @return {!Element} node containing the menu option. */ Blockly.ContextMenu.optionToDom = function(text) { /* Here's the SVG we create: Make It So */ var gElement = Blockly.createSvgElement('g', {'class': 'blocklyMenuDiv'}, null); var rectElement = Blockly.createSvgElement('rect', {'height': Blockly.ContextMenu.Y_HEIGHT}, gElement); var textElement = Blockly.createSvgElement('text', {'class': 'blocklyMenuText', 'x': Blockly.ContextMenu.X_PADDING, 'y': 15}, gElement); var textNode = document.createTextNode(text); textElement.appendChild(textNode); return gElement; }; /** * Hide the context menu. */ Blockly.ContextMenu.hide = function() { if (Blockly.ContextMenu.visible) { Blockly.ContextMenu.svgGroup.style.display = 'none'; Blockly.ContextMenu.visible = false; } }; /** * Create a callback function that creates and configures a block, * then places the new block next to the original. * @param {!Blockly.Block} block Original block. * @param {!Element} xml XML representation of new block. * @return {!Function} Function that creates a block. */ Blockly.ContextMenu.callbackFactory = function(block, xml) { return function() { var newBlock = Blockly.Xml.domToBlock(block.workspace, xml); // Move the new block next to the old block. var xy = block.getRelativeToSurfaceXY(); if (Blockly.RTL) { xy.x -= Blockly.SNAP_RADIUS; } else { xy.x += Blockly.SNAP_RADIUS; } xy.y += Blockly.SNAP_RADIUS * 2; newBlock.moveBy(xy.x, xy.y); newBlock.select(); }; }; ================================================ FILE: extern/blockly/core/css.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2013 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Inject Blockly's CSS synchronously. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Css'); goog.require('goog.cssom'); /** * Inject the CSS into the DOM. This is preferable over using a regular CSS * file since: * a) It loads synchronously and doesn't force a redraw later. * b) It speeds up loading by not blocking on a separate HTTP transfer. * c) The CSS content may be made dynamic depending on init options. */ Blockly.Css.inject = function() { var text = Blockly.Css.CONTENT.join('\n'); // Strip off any trailing slash (either Unix or Windows). //var path = Blockly.pathToBlockly.replace(/[\\\/]$/, '') + Blockly.mediaFilePath; //text = text.replace(/<<>>/g, path); text = text.replace(/<<>>/g, Blockly.mediaFilePath); goog.cssom.addCssText(text); }; /** * Array making up the CSS content for Blockly. */ Blockly.Css.CONTENT = [ '.blocklySvg {', ' background-color: transparent;', ' position: absolute;', ' cursor: move', '}', '.blocklyWidgetDiv {', ' position: absolute;', ' display: none;', ' z-index: 999;', '}', '.blocklyDraggable {', ' /* Hotspot coordinates are baked into the CUR file, but they are still', ' required in the CSS due to a Chrome bug.', ' http://code.google.com/p/chromium/issues/detail?id=1446 */', ' cursor: url(<<>>/media/handopen.cur) 8 5, auto;', '}', '.blocklyResizeSE {', ' fill: #aaa;', ' cursor: se-resize;', '}', '.blocklyResizeSW {', ' fill: #aaa;', ' cursor: sw-resize;', '}', '.blocklyResizeLine {', ' stroke-width: 1;', ' stroke: #888;', '}', '.blocklyPathPattern {', ' opacity: 0;', ' display: none;', '}', '.togglePattern>.blocklyPathPattern {', ' display: block;', '}', '.disablePattern>.blocklyPathPattern {', ' opacity: 0;', ' display: none !important;', '}', '.blocklyHighlightedConnectionPathInline {', ' stroke-width: 2px;', //' stroke: #1D55B4;', //' fill: #1D55B4;', ' stroke: white;', ' stroke-opacity: 1;', ' fill: white;', ' fill-opacity: 0.5;', '}', '.blocklyHighlightedConnectionPath {', ' stroke-width: 2px;', ' stroke: #3a3737;', ' fill: none;', '}', '.blocklyPathLight {', ' fill: none;', ' stroke-width: 0.5;', ' stroke-linecap: square;', '}', '.blocklySelected>.blocklyPath {', ' stroke-width: 3px;', ' stroke: #798EB1;', '}', '.blocklyActivated>.blocklyPath {', ' stroke-width: 2px;', ' stroke: #FF3939;', '}', '.blocklyActivated>.blocklyPathLight {', ' display: none;', '}', '.blocklySelected>.blocklyPathLight {', ' display: none;', '}', '.blocklyDragging>.blocklyPath,', '.blocklyDragging>.blocklyPathLight {', ' fill-opacity: 0.8;', ' stroke-opacity: 0.8;', '}', '.blocklyDragging>.blocklyPathDark {', ' display: none;', '}', '.blocklyDisabled>.blocklyPath {', ' fill-opacity: 0.50;', ' stroke-opacity: 0.50;', '}', '.blocklyDisabled>.blocklyPathLight,', '.blocklyDisabled>.blocklyPathDark {', ' display: none;', '}', '.blocklyText {', ' cursor: default;', ' font-family: ng;', ' font-size: 9pt;', ' fill: #fff;', '}', '.blocklyEditableText>.blocklyText {', ' fill: #000;', '}', '.blocklyNonEditableText>text {', ' pointer-events: none;', '}', '.blocklyNonEditableText>rect,', '.blocklyEditableText>rect {', ' fill: #fff;', ' fill-opacity: 0;', '}', '.blocklyNonEditableField>rect,', '.blocklyEditableField>rect {', ' fill: #fff;', ' fill-opacity: 0.4;', '}', '.blocklyNonEditableField>text,', '.blocklyEditableField>text {', ' fill: #000;', '}', '.blocklyNonEditableText>text,', '.blocklyEditableText>text {', ' fill: #000;', '}', '.blocklyEditableText:hover>rect {', ' stroke-width: 2;', ' stroke: #fff;', '}', '/*', ' * Don\'t allow users to select text. It gets annoying when trying to', ' * drag a block and selected text moves instead.', ' */', '.blocklySvg text {', ' -moz-user-select: none;', ' -webkit-user-select: none;', ' user-select: none;', ' cursor: inherit;', '}', '', '.blocklyHidden {', ' display: none;', '}', '.blocklyFieldDropdown:not(.blocklyHidden) {', ' display: block;', '}', '.blocklyTooltipBackground {', ' fill: #ffffc7;', ' stroke-width: 1px;', ' stroke: #d8d8d8;', '}', '.blocklyTooltipShadow,', '.blocklyContextMenuShadow,', '.blocklyDropdownMenuShadow {', ' fill: #bbb;', ' filter: url(#blocklyShadowFilter);', '}', '.blocklyTooltipText {', ' font-family: sans-serif;', ' font-size: 9pt;', ' fill: #000;', '}', '', '.blocklyIconShield {', ' cursor: default;', ' fill: #00c;', ' stroke-width: 1px;', ' stroke: #ccc;', '}', '.blocklyIconGroup:hover>.blocklyIconShield {', ' fill: #00f;', ' stroke: #fff;', '}', '.blocklyIconGroup:hover>.blocklyIconMark {', ' fill: #fff;', '}', '.blocklyIconMark {', ' cursor: default !important;', ' font-family: sans-serif;', ' font-size: 9pt;', ' font-weight: bold;', ' fill: #ccc;', ' text-anchor: middle;', '}', '.blocklyWarningBody {', '}', '.blocklyMinimalBody {', ' margin: 0;', ' padding: 0;', '}', '.blocklyCommentTextarea {', ' margin: 0;', ' padding: 2px;', ' border: 0;', ' resize: none;', ' background-color: #ffc;', '}', '.blocklyHtmlInput {', ' font-family: ng;', ' font-size: 9pt;', ' border: none;', ' outline: none;', ' line-height: normal;', ' width: 100%;', '}', '.blocklyContextMenuBackground,', '.blocklyMutatorBackground {', ' fill: #fff;', ' stroke-width: 1;', ' stroke: #ddd;', '}', '.blocklyContextMenuOptions>.blocklyMenuDiv,', '.blocklyContextMenuOptions>.blocklyMenuDivDisabled,', '.blocklyDropdownMenuOptions>.blocklyMenuDiv {', ' fill: #fff;', '}', '.blocklyDropdownMenuOptions>.blocklyMenuDiv {', ' cursor: default;', '}', '.blocklyContextMenuOptions>.blocklyMenuDiv:hover>rect,', '.blocklyDropdownMenuOptions>.blocklyMenuDiv:hover>rect {', ' fill: #57e;', '}', '.blocklyMenuSelected>rect {', ' fill: #57e;', '}', '.blocklyMenuText {', ' cursor: default !important;', ' font-family: ng;', ' font-size: 9pt; /* All context menu sizes are based on pixels. */', ' fill: #000;', '}', '.blocklyContextMenuOptions>.blocklyMenuDiv:hover>.blocklyMenuText,', '.blocklyDropdownMenuOptions>.blocklyMenuDiv:hover>.blocklyMenuText {', ' fill: #fff;', '}', '.blocklyMenuSelected>.blocklyMenuText {', ' fill: #fff;', '}', '.blocklyMenuDivDisabled>.blocklyMenuText {', ' fill: #ccc;', '}', '.blocklyFlyoutBackground {', ' fill: #ddd;', ' fill-opacity: 0.8;', '}', '.blocklyColourBackground {', ' fill: #666;', '}', '.blocklyScrollbarBackground {', ' opacity: 0', '}', '.blocklyScrollbarKnob {', ' fill: #000;', ' opacity: 0.35', '}', '.blocklyScrollbarBackground:hover+.blocklyScrollbarKnob,', '.blocklyScrollbarKnob:hover {', ' fill: #000;', ' opacity: 0.6', '}', '.blocklyInvalidInput {', ' background: #faa;', '}', '.blocklyAngleCircle {', ' stroke: #444;', ' stroke-width: 1;', ' fill: #ddd;', ' fill-opacity: 0.8;', '}', '.blocklyAngleMarks {', ' stroke: #444;', ' stroke-width: 1;', '}', '.blocklyAngleGauge {', ' fill: #f88;', ' fill-opacity: 0.8; ', '}', '.blocklyAngleLine {', ' stroke: #f00;', ' stroke-width: 2;', ' stroke-linecap: round;', '}', '', '/* Category tree in Toolbox. */', '.blocklyToolboxDiv {', ' background-color: #ddd;', ' display: none;', ' overflow-x: visible;', ' overflow-y: auto;', ' position: absolute;', '}', '.blocklyTreeRoot {', ' padding: 4px 0;', '}', '.blocklyTreeRoot:focus {', ' outline: none;', '}', '.blocklyTreeRow {', ' line-height: 22px;', ' height: 22px;', ' padding-right: 1em;', ' white-space: nowrap;', '}', '.blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow {', ' padding-right: 0;', ' padding-left: 1em !important;', '}', '.blocklyTreeRow:hover {', ' background-color: #e4e4e4;', '}', '.blocklyTreeIcon {', ' height: 16px;', ' width: 16px;', ' vertical-align: middle;', ' background-image: url(<<>>/media/tree.png);', '}', '.blocklyTreeIconClosedLtr {', ' background-position: -32px -1px;', '}', '.blocklyTreeIconClosedRtl {', ' background-position: 0px -1px;', '}', '.blocklyTreeIconOpen {', ' background-position: -16px -1px;', '}', '.blocklyTreeIconNone {', ' background-position: -48px -1px;', '}', '.blocklyTreeSelected>.blocklyTreeIconClosedLtr {', ' background-position: -32px -17px;', '}', '.blocklyTreeSelected>.blocklyTreeIconClosedRtl {', ' background-position: 0px -17px;', '}', '.blocklyTreeSelected>.blocklyTreeIconOpen {', ' background-position: -16px -17px;', '}', '.blocklyTreeSelected>.blocklyTreeIconNone {', ' background-position: -48px -17px;', '}', '.blocklyTreeLabel {', ' cursor: default;', ' font-family: sans-serif;', ' font-size: 16px;', ' padding: 0 3px;', ' vertical-align: middle;', '}', '.blocklyTreeSelected {', ' background-color: #57e !important;', '}', '.blocklyTreeSelected .blocklyTreeLabel {', ' color: #fff;', '}', '.blocklyBlockMenuBtn {', ' cursor: pointer', '}', '.blocklyBlockMenuBtnHighlight {', ' opacity: 0', '}', '.blocklyBlockMenuBtnHighlight:hover {', ' opacity: 1', '}', '.blocklyBlockMenuBtnPath {', ' fill: #eee', '}', '.blocklyBlockMenuBtnPath:hover {', ' fill: #f4f4f4', '}', '', '/*', ' * Copyright 2007 The Closure Library Authors. All Rights Reserved.', ' *', ' * Use of this source code is governed by the Apache License, Version 2.0.', ' * See the COPYING file for details.', ' */', '', '/* Author: pupius@google.com (Daniel Pupius) */', '', '/*', ' Styles to make the colorpicker look like the old gmail color picker', ' NOTE: without CSS scoping this will override styles defined in palette.css', '*/', '.goog-palette {', ' outline: none;', ' cursor: default;', '}', '', '.goog-palette-table {', ' border: 1px solid #666;', ' border-collapse: collapse;', '}', '', '.goog-palette-cell {', ' height: 13px;', ' width: 15px;', ' margin: 0;', ' border: 0;', ' text-align: center;', ' vertical-align: middle;', ' border-right: 1px solid #666;', ' font-size: 1px;', '}', '', '.goog-palette-colorswatch {', ' position: relative;', ' height: 13px;', ' width: 15px;', ' border: 1px solid #666;', '}', '', '.goog-palette-cell-hover .goog-palette-colorswatch {', ' border: 1px solid #FFF;', '}', '', '.goog-palette-cell-selected .goog-palette-colorswatch {', ' border: 1px solid #000;', ' color: #fff;', '}', '', '.entryFunctionButton {', ' stroke: #555;', ' stroke-width: 3;', ' fill: transparent;', ' cursor: pointer;', '}', '', '.entryFunctionButton:hover {', ' stroke: black;', '}', '', '.entryFunctionButtonText {', ' font-family: ng !important;', ' font-size: 13 !important;', ' text-anchor: middle;', ' fill: black;', ' cursor: pointer !important;', '}', '' ]; ================================================ FILE: extern/blockly/core/field.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Input field. Used for editable titles, variables, etc. * This is an abstract class that defines the UI on the block. Actual * instances would be Blockly.FieldTextInput, Blockly.FieldDropdown, etc. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Field'); // TODO(scr): Fix circular dependencies // goog.require('Blockly.Block'); goog.require('Blockly.BlockSvg'); goog.require('goog.asserts'); /** * Class for an editable field. * @param {string} text The initial content of the field. * @constructor */ Blockly.Field = function(text) { this.sourceBlock_ = null; // Build the DOM. this.fieldGroup_ = Blockly.createSvgElement('g', {}, null); this.borderRect_ = Blockly.createSvgElement('rect', {'rx': 0, 'ry': 0, 'x': -Blockly.BlockSvg.SEP_SPACE_X / 3 , 'y': 0, 'height': 16}, this.fieldGroup_); if (this instanceof Blockly.FieldTextInput) { this.borderRect_.setAttribute('x', -Blockly.BlockSvg.SEP_SPACE_X / 2); this.borderRect_.setAttribute('y', '-2'); } this.textElement_ = Blockly.createSvgElement('text', {'class': 'blocklyText', 'y': 11}, this.fieldGroup_); this.size_ = {height: 14, width: 0}; this.setText(text); this.visible_ = true; }; /** * Clone this Field. This must be implemented by all classes derived from * Field. Since this class should not be instantiated, calling this method * throws an exception. * @throws {goog.assert.AssertionError} */ Blockly.Field.prototype.clone = function() { goog.asserts.fail('There should never be an instance of Field, ' + 'only its derived classes.'); }; /** * Non-breaking space. */ Blockly.Field.NBSP = '\u00A0'; /** * Editable fields are saved by the XML renderer, non-editable fields are not. */ Blockly.Field.prototype.EDITABLE = true; /** * Install this field on a block. * @param {!Blockly.Block} block The block containing this field. */ Blockly.Field.prototype.init = function(block) { if (this.sourceBlock_) { throw 'Field has already been initialized once.'; } this.sourceBlock_ = block; this.updateEditable(); block.getSvgRoot().appendChild(this.fieldGroup_); this.mouseUpWrapper_ = Blockly.bindEvent_(this.fieldGroup_, 'mouseup', this, this.onMouseUp_); // Bump to set the colours for dropdown arrows. this.setText(null); }; /** * Dispose of all DOM objects belonging to this editable field. */ Blockly.Field.prototype.dispose = function() { if (this.mouseUpWrapper_) { Blockly.unbindEvent_(this.mouseUpWrapper_); this.mouseUpWrapper_ = null; } this.sourceBlock_ = null; goog.dom.removeNode(this.fieldGroup_); this.fieldGroup_ = null; this.textElement_ = null; this.borderRect_ = null; }; /** * Add or remove the UI indicating if this field is editable or not. */ Blockly.Field.prototype.updateEditable = function() { if (!this.EDITABLE) { return; } if (this.sourceBlock_.isEditable()) { if (this.arrow_ || this.symbol_) Blockly.addClass_(/** @type {!Element} */ (this.fieldGroup_), 'blocklyEditableField'); else Blockly.addClass_(/** @type {!Element} */ (this.fieldGroup_), 'blocklyEditableText'); Blockly.removeClass_(/** @type {!Element} */ (this.fieldGroup_), 'blocklyNoNEditableText'); this.fieldGroup_.style.cursor = this.CURSOR; } else { Blockly.addClass_(/** @type {!Element} */ (this.fieldGroup_), 'blocklyNonEditableText'); Blockly.removeClass_(/** @type {!Element} */ (this.fieldGroup_), 'blocklyEditableText'); this.fieldGroup_.style.cursor = ''; } }; /** * Gets whether this editable field is visible or not. * @return {boolean} True if visible. */ Blockly.Field.prototype.isVisible = function() { return this.visible_; }; /** * Sets whether this editable field is visible or not. * @param {boolean} visible True if visible. */ Blockly.Field.prototype.setVisible = function(visible) { this.visible_ = visible; this.getRootElement().style.display = visible ? 'block' : 'none'; }; /** * Gets the group element for this editable field. * Used for measuring the size and for positioning. * @return {!Element} The group element. */ Blockly.Field.prototype.getRootElement = function() { return /** @type {!Element} */ (this.fieldGroup_); }; /** * Draws the border with the correct width. * Saves the computed width in a property. * @private */ Blockly.Field.prototype.render_ = function() { var width = this.textElement_.getComputedTextLength(); if (this.borderRect_) { this.borderRect_.setAttribute('width', width + Blockly.BlockSvg.SEP_SPACE_X); } this.size_.width = width; }; /** * Returns the height and width of the field. * @return {!Object} Height and width. */ Blockly.Field.prototype.getSize = function() { if (!this.size_.width) { this.render_(); } return this.size_; }; /** * Get the text from this field. * @return {string} Current text. */ Blockly.Field.prototype.getText = function() { return this.text_; }; /** * Set the text in this field. Trigger a rerender of the source block. * @param {?string} text New text. * @param {?boolean} isTrim Trim shown text. */ Blockly.Field.prototype.setText = function(text, isTrim) { if (text === null || text === this.text_) { // No change if null. return; } this.text_ = text; // Empty the text element. goog.dom.removeChildren(/** @type {!Element} */ (this.textElement_)); // Replace whitespace with non-breaking spaces so the text doesn't collapse. text = text.replace(/\s/g, Blockly.Field.NBSP); if (!text) { // Prevent the field from disappearing if empty. text = Blockly.Field.NBSP; } if (isTrim && (text.length > Blockly.TEXT_INPUT_MAX_LENGTH)) text = text.substr(0, Blockly.TEXT_INPUT_MAX_LENGTH - 1) + '...'; var textNode = document.createTextNode(text); this.textElement_.appendChild(textNode); // Cached width is obsolete. Clear it. this.size_.width = 0; if (this.sourceBlock_ && this.sourceBlock_.rendered) { this.sourceBlock_.render(); this.sourceBlock_.bumpNeighbours_(); this.sourceBlock_.workspace.fireChangeEvent(); } }; /** * By default there is no difference between the human-readable text and * the language-neutral values. Subclasses (such as dropdown) may define this. * @return {string} Current text. */ Blockly.Field.prototype.getValue = function() { return this.getText(); }; /** * By default there is no difference between the human-readable text and * the language-neutral values. Subclasses (such as dropdown) may define this. * @param {string} text New text. */ Blockly.Field.prototype.setValue = function(text) { this.setText(text); }; /** * Handle a mouse up event on an editable field. * @param {!Event} e Mouse up event. * @private */ Blockly.Field.prototype.onMouseUp_ = function(e) { if (Blockly.isRightButton(e)) { // Right-click. return; } else if (Blockly.Block.dragMode_ == 2) { // Drag operation is concluding. Don't open the editor. return; } else if (this.sourceBlock_.isEditable()) { // Non-abstract sub-classes must define a showEditor_ method. this.sourceBlock_.isDrag = true; this.showEditor_(); } }; /** * Change the tooltip text for this field. * @param {string|!Element} newTip Text for tooltip or a parent element to * link to for its tooltip. */ Blockly.Field.prototype.setTooltip = function(newTip) { // Non-abstract sub-classes may wish to implement this. See FieldLabel. }; ================================================ FILE: extern/blockly/core/field_angle.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2013 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Angle input field. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.FieldAngle'); goog.require('Blockly.FieldTextInput'); /** * Class for an editable angle field. * @param {string} text The initial content of the field. * @param {Function} opt_changeHandler An optional function that is called * to validate any constraints on what the user entered. Takes the new * text as an argument and returns the accepted text or null to abort * the change. * @extends {Blockly.Field} * @constructor */ Blockly.FieldAngle = function(text, opt_changeHandler) { var changeHandler; if (opt_changeHandler) { // Wrap the user's change handler together with the angle validator. var thisObj = this; changeHandler = function(value) { value = Blockly.FieldAngle.angleValidator.call(thisObj, value); if (value !== null) { opt_changeHandler.call(thisObj, value); } return value; }; } else { changeHandler = Blockly.FieldAngle.angleValidator; } // Add degree symbol: "360°" (LTR) or "°360" (RTL) this.symbol_ = Blockly.createSvgElement('tspan', {}, null); this.symbol_.appendChild(document.createTextNode('\u00B0')); Blockly.FieldAngle.superClass_.constructor.call(this, text, changeHandler); this.borderRect_.setAttribute('x', -Blockly.BlockSvg.SEP_SPACE_X/2); }; goog.inherits(Blockly.FieldAngle, Blockly.FieldTextInput); /** * Clone this FieldAngle. * @return {!Blockly.FieldAngle} The result of calling the constructor again * with the current values of the arguments used during construction. */ Blockly.FieldAngle.prototype.clone = function() { return new Blockly.FieldAngle(this.getText(), this.changeHandler_); }; /** * Round angles to the nearest 15 degrees when using mouse. * Set to 0 to disable rounding. */ Blockly.FieldAngle.ROUND = 15; /** * Half the width of protractor image. */ Blockly.FieldAngle.HALF = 100 / 2; /** * Radius of protractor circle. Slightly smaller than protractor size since * otherwise SVG crops off half the border at the edges. */ Blockly.FieldAngle.RADIUS = Blockly.FieldAngle.HALF - 1; /** * Clean up this FieldAngle, as well as the inherited FieldTextInput. * @return {!Function} Closure to call on destruction of the WidgetDiv. * @private */ Blockly.FieldAngle.prototype.dispose_ = function() { var thisField = this; return function() { Blockly.FieldAngle.superClass_.dispose_.call(thisField)(); thisField.gauge_ = null; if (thisField.clickWrapper_) { Blockly.unbindEvent_(thisField.clickWrapper_); } if (thisField.moveWrapper1_) { Blockly.unbindEvent_(thisField.moveWrapper1_); } if (thisField.moveWrapper2_) { Blockly.unbindEvent_(thisField.moveWrapper2_); } }; }; /** * Show the inline free-text editor on top of the text. * @private */ Blockly.FieldAngle.prototype.showEditor_ = function() { Blockly.FieldAngle.superClass_.showEditor_.call(this); var div = Blockly.WidgetDiv.DIV; if (!div.firstChild) { // Mobile interface uses window.prompt. return; } // Build the SVG DOM. var svg = Blockly.createSvgElement('svg', { 'xmlns': 'http://www.w3.org/2000/svg', 'xmlns:html': 'http://www.w3.org/1999/xhtml', 'xmlns:xlink': 'http://www.w3.org/1999/xlink', 'version': '1.1', 'height': (Blockly.FieldAngle.HALF * 2) + 'px', 'width': (Blockly.FieldAngle.HALF * 2) + 'px' }, div); var circle = Blockly.createSvgElement('circle', { 'cx': Blockly.FieldAngle.HALF, 'cy': Blockly.FieldAngle.HALF, 'r': Blockly.FieldAngle.RADIUS, 'class': 'blocklyAngleCircle' }, svg); this.gauge_ = Blockly.createSvgElement('path', {'class': 'blocklyAngleGauge'}, svg); this.line_ = Blockly.createSvgElement('line', {'x1': Blockly.FieldAngle.HALF, 'y1': Blockly.FieldAngle.HALF, 'class': 'blocklyAngleLine'}, svg); // Draw markers around the edge. for (var a = 0; a < 360; a += 15) { Blockly.createSvgElement('line', { 'x1': Blockly.FieldAngle.HALF + Blockly.FieldAngle.RADIUS, 'y1': Blockly.FieldAngle.HALF, 'x2': Blockly.FieldAngle.HALF + Blockly.FieldAngle.RADIUS - (a % 45 == 0 ? 10 : 5), 'y2': Blockly.FieldAngle.HALF, 'class': 'blocklyAngleMarks', 'transform': 'rotate(' + a + ', ' + Blockly.FieldAngle.HALF + ', ' + Blockly.FieldAngle.HALF + ')' }, svg); } svg.style.marginLeft = '-35px'; this.clickWrapper_ = Blockly.bindEvent_(svg, 'click', this, Blockly.WidgetDiv.hide); this.moveWrapper1_ = Blockly.bindEvent_(circle, 'mousemove', this, this.onMouseMove); this.moveWrapper2_ = Blockly.bindEvent_(this.gauge_, 'mousemove', this, this.onMouseMove); this.updateGraph(); }; /** * Set the angle to match the mouse's position. * @param {!Event} e Mouse move event. */ Blockly.FieldAngle.prototype.onMouseMove = function(e) { var bBox = this.gauge_.ownerSVGElement.getBoundingClientRect(); var dx = e.clientX - bBox.left - Blockly.FieldAngle.HALF; var dy = e.clientY - bBox.top - Blockly.FieldAngle.HALF; var angle = Math.atan(-dy / dx); if (isNaN(angle)) { // This shouldn't happen, but let's not let this error propogate further. return; } angle = angle / Math.PI * 180; angle = 90 - angle; // 0: East, 90: North, 180: West, 270: South. if (dx < 0) { angle += 180; } else if (dy > 0) { angle += 360; } if (Blockly.FieldAngle.ROUND) { angle = Math.round(angle / Blockly.FieldAngle.ROUND) * Blockly.FieldAngle.ROUND; } if (angle >= 360) { // Rounding may have rounded up to 360. angle -= 360; } angle = String(angle); Blockly.FieldTextInput.htmlInput_.value = angle; this.setText(angle); }; /** * Insert a degree symbol. * @param {?string} text New text. */ Blockly.FieldAngle.prototype.setText = function(text) { Blockly.FieldAngle.superClass_.setText.call(this, text); this.updateGraph(); // Insert degree symbol. if (Blockly.RTL) { this.textElement_.insertBefore(this.symbol_, this.textElement_.firstChild); } else { this.textElement_.appendChild(this.symbol_); } // Cached width is obsolete. Clear it. this.size_.width = 0; }; /** * Ensure that only an angle may be entered. * @param {string} text The user's text. * @return {?string} A string representing a valid angle, or null if invalid. */ Blockly.FieldAngle.prototype.updateGraph = function() { if (this.gauge_) { var angleRadians = Number(this.getText()) / 180 * Math.PI; if (isNaN(angleRadians)) { this.gauge_.setAttribute('d', 'M ' + Blockly.FieldAngle.HALF + ', ' + Blockly.FieldAngle.HALF); this.line_.setAttribute('x2', Blockly.FieldAngle.HALF); this.line_.setAttribute('y2', Blockly.FieldAngle.HALF); } else { var x = Blockly.FieldAngle.HALF + Math.sin(angleRadians) * Blockly.FieldAngle.RADIUS; var y = Blockly.FieldAngle.HALF + Math.cos(angleRadians) * -Blockly.FieldAngle.RADIUS; var largeFlag = (angleRadians > Math.PI) ? 1 : 0; this.gauge_.setAttribute('d', 'M ' + Blockly.FieldAngle.HALF + ', ' + Blockly.FieldAngle.HALF + ' v -' + Blockly.FieldAngle.RADIUS + ' A ' + Blockly.FieldAngle.RADIUS + ',' + Blockly.FieldAngle.RADIUS + ' 0 ' + largeFlag + ' 1 ' + x + ',' + y + ' z'); this.line_.setAttribute('x2', x); this.line_.setAttribute('y2', y); } } }; /** * Ensure that only an angle may be entered. * @param {string} text The user's text. * @return {?string} A string representing a valid angle, or null if invalid. */ Blockly.FieldAngle.angleValidator = function(text) { var n = Blockly.FieldTextInput.numberValidator(text); if (n !== null) { //n = n % 360; //if (n < 0) { //n += 360; //} n = String(n); } return n; }; ================================================ FILE: extern/blockly/core/field_checkbox.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Checkbox field. Checked or not checked. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.FieldCheckbox'); goog.require('Blockly.Field'); /** * Class for a checkbox field. * @param {string} state The initial state of the field ('TRUE' or 'FALSE'). * @param {Function} opt_changeHandler A function that is executed when a new * option is selected. Its sole argument is the new checkbox state. If * it returns a value, this becomes the new checkbox state, unless the * value is null, in which case the change is aborted. * @extends {Blockly.Field} * @constructor */ Blockly.FieldCheckbox = function(state, opt_changeHandler) { Blockly.FieldCheckbox.superClass_.constructor.call(this, ''); this.changeHandler_ = opt_changeHandler; // The checkbox doesn't use the inherited text element. // Instead it uses a custom checkmark element that is either visible or not. this.checkElement_ = Blockly.createSvgElement('text', {'class': 'blocklyText', 'x': -3}, this.fieldGroup_); var textNode = document.createTextNode('\u2713'); this.checkElement_.appendChild(textNode); // Set the initial state. this.setValue(state); }; goog.inherits(Blockly.FieldCheckbox, Blockly.Field); /** * Clone this FieldCheckbox. * @return {!Blockly.FieldCheckbox} The result of calling the constructor again * with the current values of the arguments used during construction. */ Blockly.FieldCheckbox.prototype.clone = function() { return new Blockly.FieldCheckbox(this.getValue(), this.changeHandler_); }; /** * Mouse cursor style when over the hotspot that initiates editability. */ Blockly.FieldCheckbox.prototype.CURSOR = 'default'; /** * Return 'TRUE' if the checkbox is checked, 'FALSE' otherwise. * @return {string} Current state. */ Blockly.FieldCheckbox.prototype.getValue = function() { return String(this.state_).toUpperCase(); }; /** * Set the checkbox to be checked if strBool is 'TRUE', unchecks otherwise. * @param {string} strBool New state. */ Blockly.FieldCheckbox.prototype.setValue = function(strBool) { var newState = (strBool == 'TRUE'); if (this.state_ !== newState) { this.state_ = newState; this.checkElement_.style.display = newState ? 'block' : 'none'; if (this.sourceBlock_ && this.sourceBlock_.rendered) { this.sourceBlock_.workspace.fireChangeEvent(); } } }; /** * Toggle the state of the checkbox. * @private */ Blockly.FieldCheckbox.prototype.showEditor_ = function() { var newState = !this.state_; if (this.changeHandler_) { // Call any change handler, and allow it to override. var override = this.changeHandler_(newState); if (override !== undefined) { newState = override; } } if (newState !== null) { this.setValue(String(newState).toUpperCase()); } }; ================================================ FILE: extern/blockly/core/field_colour.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Colour input field. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.FieldColour'); goog.require('Blockly.Field'); goog.require('goog.ui.ColorPicker'); /** * Class for a colour input field. * @param {string} colour The initial colour in '#rrggbb' format. * @param {Function} opt_changeHandler A function that is executed when a new * colour is selected. Its sole argument is the new colour value. Its * return value becomes the selected colour, unless it is undefined, in * which case the new colour stands, or it is null, in which case the change * is aborted. * @extends {Blockly.Field} * @constructor */ Blockly.FieldColour = function(colour, opt_changeHandler) { Blockly.FieldColour.superClass_.constructor.call(this, '\u00A0\u00A0\u00A0'); this.changeHandler_ = opt_changeHandler; this.borderRect_.style.fillOpacity = 1; // Set the initial state. this.setValue(colour); }; goog.inherits(Blockly.FieldColour, Blockly.Field); /** * Clone this FieldColour. * @return {!Blockly.FieldColour} The result of calling the constructor again * with the current values of the arguments used during construction. */ Blockly.FieldColour.prototype.clone = function() { return new Blockly.FieldColour(this.getValue(), this.changeHandler_); }; /** * Mouse cursor style when over the hotspot that initiates the editor. */ Blockly.FieldColour.prototype.CURSOR = 'default'; /** * Dispose of all DOM objects belonging to this editable field. */ Blockly.FieldColour.prototype.dispose = function() { Blockly.WidgetDiv.hideIfField(this); Blockly.FieldColour.superClass_.dispose.call(this); }; /** * Return the current colour. * @return {string} Current colour in '#rrggbb' format. */ Blockly.FieldColour.prototype.getValue = function() { return this.colour_; }; /** * Set the colour. * @param {string} colour The new colour in '#rrggbb' format. */ Blockly.FieldColour.prototype.setValue = function(colour) { this.colour_ = colour; this.borderRect_.style.fill = colour; if (this.sourceBlock_ && this.sourceBlock_.rendered) { this.sourceBlock_.workspace.fireChangeEvent(); } }; /** * An array of colour strings for the palette. * See bottom of this page for the default: * http://docs.closure-library.googlecode.com/git/closure_goog_ui_colorpicker.js.source.html * @type {!Array.} */ Blockly.FieldColour.COLOURS = goog.ui.ColorPicker.SIMPLE_GRID_COLORS; /** * Number of columns in the palette. */ Blockly.FieldColour.COLUMNS = 7; /** * Create a palette under the colour field. * @private */ Blockly.FieldColour.prototype.showEditor_ = function() { Blockly.WidgetDiv.show(this, Blockly.FieldColour.dispose_); var div = Blockly.WidgetDiv.DIV; // Create the palette using Closure. var picker = new goog.ui.ColorPicker(); picker.setSize(Blockly.FieldColour.COLUMNS); picker.setColors(Blockly.FieldColour.COLOURS); picker.render(div); picker.setSelectedColor(this.getValue()); // Position the palette to line up with the field. var xy = Blockly.getAbsoluteXY_(/** @type {!Element} */ (this.borderRect_)); var borderBBox = this.borderRect_.getBBox(); if (Blockly.RTL) { xy.x += borderBBox.width; } xy.y += borderBBox.height - 1; if (Blockly.RTL) { xy.x -= div.offsetWidth; } div.style.left = xy.x + 'px'; div.style.top = xy.y + 'px'; // Configure event handler. var thisObj = this; Blockly.FieldColour.changeEventKey_ = goog.events.listen(picker, goog.ui.ColorPicker.EventType.CHANGE, function(event) { var colour = event.target.getSelectedColor() || '#000000'; Blockly.WidgetDiv.hide(); if (thisObj.changeHandler_) { // Call any change handler, and allow it to override. var override = thisObj.changeHandler_(colour); if (override !== undefined) { colour = override; } } if (colour !== null) { if (typeof(Entry) == "object" && thisObj.getValue() != colour) { Entry.dispatchEvent("entryBlocklyChanged"); } thisObj.setValue(colour); } }); }; /** * Hide the colour palette. * @private */ Blockly.FieldColour.dispose_ = function() { if (Blockly.FieldColour.changeEventKey_) { goog.events.unlistenByKey(Blockly.FieldColour.changeEventKey_); } }; ================================================ FILE: extern/blockly/core/field_dropdown.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Dropdown input field. Used for editable titles and variables. * In the interests of a consistent UI, the toolbox shares some functions and * properties with the context menu. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.FieldDropdown'); goog.require('Blockly.Field'); /** * Class for an editable dropdown field. * @param {(!Array.|!Function)} menuGenerator An array of options * for a dropdown list, or a function which generates these options. * @param {Function} opt_changeHandler A function that is executed when a new * option is selected, with the newly selected value as its sole argument. * If it returns a value, that value (which must be one of the options) will * become selected in place of the newly selected option, unless the return * value is null, in which case the change is aborted. * @param {?Boolean} arrowOption If arrowOption is true or null, arrow will be * shown. If arrowOption is false, arrow will not be shown. * @extends {Blockly.Field} * @constructor */ Blockly.FieldDropdown = function(menuGenerator, opt_changeHandler, arrowOption, arrowColor) { this.menuGenerator_ = menuGenerator; this.changeHandler_ = opt_changeHandler; this.trimOptions_(); var firstTuple = this.getOptions_()[0]; this.value_ = firstTuple[1]; // Add dropdown arrow: "option ▾" (LTR) or "▾ אופציה" (RTL) this.arrow_ = Blockly.createSvgElement('tspan', {}, null); if (arrowColor) this.arrowColor_ = arrowColor; if (arrowOption != false) { this.arrow_.appendChild(document.createTextNode( Blockly.RTL ? '\u25BE ' : ' \u25BE')); } // Call parent's constructor. Blockly.FieldDropdown.superClass_.constructor.call(this, firstTuple[0]); }; goog.inherits(Blockly.FieldDropdown, Blockly.Field); /** * Clone this FieldDropdown. * @return {!Blockly.FieldDropdown} The result of calling the constructor again * with the current values of the arguments used during construction. */ Blockly.FieldDropdown.prototype.clone = function() { return new Blockly.FieldDropdown(this.menuGenerator_, this.changeHandler_); }; /** * Create the dropdown field's elements. Only needs to be called once. * @return {!Element} The field's SVG group. */ Blockly.FieldDropdown.createDom = function() { var url_up = Blockly.mediaFilePath + 'media/scroll_up.png'; var url_down = Blockly.mediaFilePath + 'media/scroll_down.png'; Blockly.FieldDropdown.currentPosition = 0; var svg = Blockly.createSvgElement('svg', { 'xmlns': 'http://www.w3.org/2000/svg', 'version': '1.1', 'height' : '200' }, null); Blockly.FieldDropdown.svgWrapper_ = svg; var svgGroup = Blockly.createSvgElement('g', {'class': 'blocklyHidden blocklyFieldDropdown'}, svg); Blockly.FieldDropdown.svgGroup_ = svgGroup; Blockly.FieldDropdown.svgShadow_ = Blockly.createSvgElement('rect', {'class': 'blocklyDropdownMenuShadow', 'x': 0, 'y': 1}, svgGroup); Blockly.FieldDropdown.svgBackground_ = Blockly.createSvgElement('rect', {'x': -2, 'y': -1, 'filter': 'url(#blocklyEmboss)'}, svgGroup); Blockly.FieldDropdown.svgOptions_ = Blockly.createSvgElement('g', {'class': 'blocklyDropdownMenuOptions'}, svgGroup); Blockly.FieldDropdown.scrollbarWrapper_ = Blockly.createSvgElement('g', {'class': 'blocklyDropdownScollWrapper blocklyHidden'}, svg); Blockly.FieldDropdown.scrollbarUpWrapper_ = Blockly.createSvgElement('g', {'transform':'translate(0 0)','cursor':'pointer'}, Blockly.FieldDropdown.scrollbarWrapper_); Blockly.createSvgElement('rect', {'width':'15','height':'40','fill':'none','stroke':'none'}, Blockly.FieldDropdown.scrollbarUpWrapper_); var upperImg = Blockly.createSvgElement('image', {'width':'10','height':'40', 'x':'5','opacity':'0.5'}, Blockly.FieldDropdown.scrollbarUpWrapper_); upperImg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', url_up); Blockly.FieldDropdown.scrollbarDownWrapper_ = Blockly.createSvgElement('g', {'transform':'translate(0 160)', 'cursor':'pointer'}, Blockly.FieldDropdown.scrollbarWrapper_); Blockly.createSvgElement('rect', {'width':'15','height':'40','fill':'none','stroke':'none'}, Blockly.FieldDropdown.scrollbarDownWrapper_); var upperImg = Blockly.createSvgElement('image', {'width':'10','height':'40', 'x':'5','opacity':'0.5'}, Blockly.FieldDropdown.scrollbarDownWrapper_); upperImg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', url_down);; return svg; }; /** * handle mouse over event */ Blockly.FieldDropdown.moveUp = function(e) { var current = Blockly.FieldDropdown.currentPosition if (current == 0) return; else Blockly.FieldDropdown.currentPosition--; Blockly.FieldDropdown.moveScroll(Blockly.FieldDropdown.currentPosition); Blockly.FieldDropdown.timer = window.setTimeout(function(){ Blockly.FieldDropdown.moveUp(); },100); }; Blockly.FieldDropdown.mouseLeave = function(e) { if (Blockly.FieldDropdown.timer) { window.clearInterval(Blockly.FieldDropdown.timer); Blockly.FieldDropdown.timer = null; } }; /** * handle mouse over event */ Blockly.FieldDropdown.moveDown = function(e) { if (this.getOptions_) Blockly.FieldDropdown.optionLength = this.getOptions_().length; var current = Blockly.FieldDropdown.currentPosition if (current + 10 == Blockly.FieldDropdown.optionLength) return; else Blockly.FieldDropdown.currentPosition++; Blockly.FieldDropdown.moveScroll(Blockly.FieldDropdown.currentPosition); Blockly.FieldDropdown.timer = window.setTimeout(function(){ Blockly.FieldDropdown.moveDown(); },100); }; /** * handle mouse wheel event */ Blockly.FieldDropdown.onMouseWheel = function(e) { e.stopPropagation(); e.preventDefault(); Blockly.removeAllRanges(); var svgScroll = Blockly.FieldDropdown.scrollbar_; var svgScrollWrapper = Blockly.FieldDropdown.scrollbarWrapper_; var options = this.getOptions_(); if (options.length <= 10) { Blockly.addClass_(svgScrollWrapper, 'blocklyHidden'); return; } else { var dy = e.wheelDeltaY || -e.deltaY; Blockly.removeClass_(svgScrollWrapper, 'blocklyHidden'); var current = Blockly.FieldDropdown.currentPosition if (current == 0 && dy > 0) return; if (current == (options.length - 10) && dy < 0) return; if (dy < 0) Blockly.FieldDropdown.currentPosition++; else Blockly.FieldDropdown.currentPosition--; Blockly.FieldDropdown.moveScroll(Blockly.FieldDropdown.currentPosition); } }; /** * translate svgGroup and scrollbar by currentposition */ Blockly.FieldDropdown.moveScroll = function(position) { var svgGroup = Blockly.FieldDropdown.svgGroup_; svgGroup.setAttribute('transform', 'translate(0 '+ (position * -20)+')'); }; /** * Close the dropdown and dispose of all UI. */ Blockly.FieldDropdown.prototype.dispose = function() { if (Blockly.FieldDropdown.openDropdown_ == this) { Blockly.FieldDropdown.hide(); } // Call parent's destructor. Blockly.Field.prototype.dispose.call(this); }; /** * Corner radius of the dropdown background. */ Blockly.FieldDropdown.CORNER_RADIUS = 2; /** * Mouse cursor style when over the hotspot that initiates the editor. */ Blockly.FieldDropdown.prototype.CURSOR = 'default'; /** * Which block is the dropdown attached to? * @type {Blockly.FieldDropdown} * @private */ Blockly.FieldDropdown.openDropdown_ = null; /** * Create a dropdown menu under the text. * @private */ Blockly.FieldDropdown.prototype.showEditor_ = function() { if (Blockly.FieldDropdown.workspace !== this.sourceBlock_.workspace) { goog.dom.removeChildren(/** @type {!Element} */ (Blockly.FieldDropdown.svgWrapper_)); var svg = Blockly.FieldDropdown.createDom(); this.sourceBlock_.workspace.svgGroup_.appendChild(svg); Blockly.FieldDropdown.workspace = this.sourceBlock_.workspace } var svgWrapper = Blockly.FieldDropdown.svgWrapper_; var svgGroup = Blockly.FieldDropdown.svgGroup_; var svgOptions = Blockly.FieldDropdown.svgOptions_; var svgBackground = Blockly.FieldDropdown.svgBackground_; var svgShadow = Blockly.FieldDropdown.svgShadow_; // Erase all existing options. goog.dom.removeChildren(svgOptions); // The menu must be made visible early since otherwise BBox and // getComputedTextLength will return 0. Blockly.removeClass_(svgGroup, 'blocklyHidden'); Blockly.FieldDropdown.openDropdown_ = this; function callbackFactory(value) { return function(e) { if (this.changeHandler_) { // Call any change handler, and allow it to override. var override = this.changeHandler_(value); if (override !== undefined) { value = override; } } if (value !== null) { if (typeof(Entry) == "object" && this.getValue() != value) { Entry.dispatchEvent("entryBlocklyChanged"); } this.setValue(value); } // This mouse click has been handled, don't bubble up to document. e.stopPropagation(); }; } var maxWidth = 0; var resizeList = []; var checkElement = null; var options = this.getOptions_(); for (var x = 0; x < options.length; x++) { var text = options[x][0]; // Human-readable text. var value = options[x][1]; // Language-neutral value. var gElement = Blockly.ContextMenu.optionToDom(text); var rectElement = /** @type {SVGRectElement} */ (gElement.firstChild); var textElement = /** @type {SVGTextElement} */ (gElement.lastChild); svgOptions.appendChild(gElement); // Add a checkmark next to the current item. if (!checkElement && value == this.value_) { checkElement = Blockly.createSvgElement('text', {'class': 'blocklyMenuText', 'y': 15}, null); // Insert the checkmark between the rect and text, thus preserving the // ability to reference them as firstChild and lastChild respectively. gElement.insertBefore(checkElement, textElement); checkElement.appendChild(document.createTextNode('\u2713')); } gElement.setAttribute('transform', 'translate(0, ' + (x * Blockly.ContextMenu.Y_HEIGHT) + ')'); resizeList.push(rectElement); Blockly.bindEvent_(gElement, 'mousedown', null, Blockly.noEvent); Blockly.bindEvent_(gElement, 'mouseup', this, callbackFactory(value)); Blockly.bindEvent_(gElement, 'mouseup', null, Blockly.FieldDropdown.hide); // Compute the length of the longest text length. maxWidth = Math.max(maxWidth, textElement.getComputedTextLength()); } // Run a second pass to resize all options to the required width. maxWidth += Blockly.ContextMenu.X_PADDING * 2; for (var x = 0; x < resizeList.length; x++) { resizeList[x].setAttribute('width', maxWidth); } if (Blockly.RTL) { // Right-align the text. for (var x = 0, gElement; gElement = svgOptions.childNodes[x]; x++) { var textElement = gElement.lastChild; textElement.setAttribute('text-anchor', 'end'); textElement.setAttribute('x', maxWidth - Blockly.ContextMenu.X_PADDING); } } if (checkElement) { if (Blockly.RTL) { // Research indicates that RTL checkmarks are supposed to be drawn the // same in the same direction as LTR checkmarks. It's only the alignment // that needs to change. checkElement.setAttribute('text-anchor', 'end'); checkElement.setAttribute('x', maxWidth - 5); } else { checkElement.setAttribute('x', 5); } } var width = maxWidth + Blockly.FieldDropdown.CORNER_RADIUS * 2; var height = options.length * Blockly.ContextMenu.Y_HEIGHT + Blockly.FieldDropdown.CORNER_RADIUS + 1; svgShadow.setAttribute('width', width); svgShadow.setAttribute('height', height); svgBackground.setAttribute('width', width); svgBackground.setAttribute('height', height); var hexColour = Blockly.makeColour(this.sourceBlock_.getColour()); svgBackground.setAttribute('fill', hexColour); // Position the dropdown to line up with the field. var xy = Blockly.getSvgXY_(/** @type {!Element} */ (this.borderRect_)); var borderBBox = this.borderRect_.getBBox(); var x; if (Blockly.RTL) { x = xy.x - maxWidth + Blockly.ContextMenu.X_PADDING + borderBBox.width - Blockly.BlockSvg.SEP_SPACE_X / 2; } else { x = xy.x - Blockly.ContextMenu.X_PADDING + Blockly.BlockSvg.SEP_SPACE_X / 2; } var scrollWrapper = Blockly.FieldDropdown.scrollbarWrapper_; if (options.length <= 10) { Blockly.addClass_(scrollWrapper, 'blocklyHidden'); } else { var hw = svgOptions.getBBox(); Blockly.removeClass_(scrollWrapper, 'blocklyHidden'); scrollWrapper.setAttribute('transform', 'translate('+ (Number(hw.width)-15) + ' 0)'); } Blockly.FieldDropdown.wheelEvent_ = Blockly.bindEvent_( svgGroup, 'wheel', this, Blockly.FieldDropdown.onMouseWheel); Blockly.FieldDropdown.moveUpEvent_ = Blockly.bindEvent_(Blockly.FieldDropdown.scrollbarUpWrapper_,'mouseover', this, Blockly.FieldDropdown.moveUp); Blockly.FieldDropdown.moveUpLeaveEvent_ = Blockly.bindEvent_(Blockly.FieldDropdown.scrollbarUpWrapper_,'mouseleave', this, Blockly.FieldDropdown.mouseLeave); Blockly.FieldDropdown.moveDownEvent_ = Blockly.bindEvent_(Blockly.FieldDropdown.scrollbarDownWrapper_,'mouseover', this, Blockly.FieldDropdown.moveDown); Blockly.FieldDropdown.moveDownLeaveEvent_ = Blockly.bindEvent_(Blockly.FieldDropdown.scrollbarDownWrapper_,'mouseleave', this, Blockly.FieldDropdown.mouseLeave); svgWrapper.setAttribute('x', x); svgWrapper.setAttribute('y', xy.y + borderBBox.height); }; /** * Factor out common words in statically defined options. * Create prefix and/or suffix labels. * @private */ Blockly.FieldDropdown.prototype.trimOptions_ = function() { this.prefixField = null; this.suffixField = null; var options = this.menuGenerator_; if (!goog.isArray(options) || options.length < 2) { return; } var strings = options.map(function(t) {return t[0];}); var shortest = Blockly.shortestStringLength(strings); var prefixLength = Blockly.commonWordPrefix(strings, shortest); var suffixLength = Blockly.commonWordSuffix(strings, shortest); if (!prefixLength && !suffixLength) { return; } if (shortest <= prefixLength + suffixLength) { // One or more strings will entirely vanish if we proceed. Abort. return; } if (prefixLength) { this.prefixField = strings[0].substring(0, prefixLength - 1); } if (suffixLength) { this.suffixField = strings[0].substr(1 - suffixLength); } // Remove the prefix and suffix from the options. var newOptions = []; for (var x = 0; x < options.length; x++) { var text = options[x][0]; var value = options[x][1]; text = text.substring(prefixLength, text.length - suffixLength); newOptions[x] = [text, value]; } this.menuGenerator_ = newOptions; }; /** * Return a list of the options for this dropdown. * @return {!Array.>} Array of option tuples: * (human-readable text, language-neutral name). * @private */ Blockly.FieldDropdown.prototype.getOptions_ = function() { if (goog.isFunction(this.menuGenerator_)) { return this.menuGenerator_.call(this); } return /** @type {!Array.>} */ (this.menuGenerator_); }; /** * Get the language-neutral value from this dropdown menu. * @return {string} Current text. */ Blockly.FieldDropdown.prototype.getValue = function() { return this.value_; }; /** * Set the language-neutral value for this dropdown menu. * @param {string} newValue New value to set. */ Blockly.FieldDropdown.prototype.setValue = function(newValue) { this.value_ = newValue; // Look up and display the human-readable text. var options = this.getOptions_(); for (var x = 0; x < options.length; x++) { // Options are tuples of human-readable text and language-neutral values. if (options[x][1] == newValue) { this.setText(options[x][0]); return; } } // Value not found. Add it, maybe it will become valid once set // (like variable names). this.setText(newValue); }; /** * Set the text in this field. Trigger a rerender of the source block. * @param {?string} text New text. */ Blockly.FieldDropdown.prototype.setText = function(text) { if (this.sourceBlock_) { // Update arrow's colour. if (this.arrowColor_) this.arrow_.style.fill = this.arrowColor_; else this.arrow_.style.fill = Blockly.makeColour(this.sourceBlock_.getColour()); } if (text === null) { // No change if null. return; } this.text_ = text; // Empty the text element. goog.dom.removeChildren(/** @type {!Element} */ (this.textElement_)); // Replace whitespace with non-breaking spaces so the text doesn't collapse. text = text.replace(/\s/g, Blockly.Field.NBSP); if (!text) { // Prevent the field from disappearing if empty. text = Blockly.Field.NBSP; } var textNode = document.createTextNode(text); this.textElement_.appendChild(textNode); // Insert dropdown arrow. if (Blockly.RTL) { this.textElement_.insertBefore(this.arrow_, this.textElement_.firstChild); } else { this.textElement_.appendChild(this.arrow_); } // Cached width is obsolete. Clear it. this.size_.width = 0; if (this.sourceBlock_ && this.sourceBlock_.rendered) { this.sourceBlock_.render(); this.sourceBlock_.bumpNeighbours_(); this.sourceBlock_.workspace.fireChangeEvent(); } }; /** * Hide the dropdown menu. */ Blockly.FieldDropdown.hide = function() { var svgGroup = Blockly.FieldDropdown.svgGroup_; var svgScrollWrapper = Blockly.FieldDropdown.scrollbarWrapper_; if (svgGroup) { Blockly.addClass_(svgGroup, 'blocklyHidden'); svgGroup.removeAttribute('transform'); } if (svgScrollWrapper) { Blockly.addClass_(svgScrollWrapper, 'blocklyHidden'); svgScrollWrapper.removeAttribute('transform'); } if (Blockly.FieldDropdown.wheelEvent_) Blockly.unbindEvent_(Blockly.FieldDropdown.wheelEvent_); if (Blockly.FieldDropdown.moveUpEvent_) Blockly.unbindEvent_(Blockly.FieldDropdown.moveUpEvent_); if (Blockly.FieldDropdown.moveDownEvent_) Blockly.unbindEvent_(Blockly.FieldDropdown.moveDownEvent_); if (Blockly.FieldDropdown.moveUpLeaveEvent_) Blockly.unbindEvent_(Blockly.FieldDropdown.moveUpLeaveEvent_); if (Blockly.FieldDropdown.moveDownLaeveEvent_) Blockly.unbindEvent_(Blockly.FieldDropdown.moveDownLeaveEvent_); Blockly.FieldDropdown.currentPosition = 0; Blockly.FieldDropdown.openDropdown_ = null; }; ================================================ FILE: extern/blockly/core/field_dropdowndynamic.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Dropdown input field. Used for editable titles and variables. * In the interests of a consistent UI, the toolbox shares some functions and * properties with the context menu. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.FieldDropdownDynamic'); goog.require('Blockly.Field'); /** * Class for an editable dropdown field. * @param {(!Array.|!Function)} menuGenerator An array of options * for a dropdown list, or a function which generates these options. * @param {Function} opt_changeHandler A function that is executed when a new * option is selected, with the newly selected value as its sole argument. * If it returns a value, that value (which must be one of the options) will * become selected in place of the newly selected option, unless the return * value is null, in which case the change is aborted. * @param {?Boolean} arrowOption If arrowOption is true or null, arrow will be * shown. If arrowOption is false, arrow will not be shown. * @extends {Blockly.Field} * @constructor */ Blockly.FieldDropdownDynamic = function(menuInfo, opt_changeHandler, arrowOption, arrowColor) { //document.addEventListener("cust", this.updateMenu_, false); //this.menuGenerator_ = menuGenerator; if (typeof menuInfo == "function") this.menuFunc_ = menuInfo else this.menuName_ = menuInfo; this.menuGenerator = this.getOptions_(); this.changeHandler_ = opt_changeHandler; this.trimOptions_(); var firstTuple = this.getOptions_()[0]; this.value_ = firstTuple[1]; // Add dropdown arrow: "option ▾" (LTR) or "▾ אופציה" (RTL) this.arrow_ = Blockly.createSvgElement('tspan', {}, null); if (arrowColor) this.arrowColor_ = arrowColor; if (arrowOption != false) { this.arrow_.appendChild(document.createTextNode( Blockly.RTL ? '\u25BE ' : ' \u25BE')); } // Call parent's constructor. Blockly.FieldDropdownDynamic.superClass_.constructor.call(this, firstTuple[0]); }; goog.inherits(Blockly.FieldDropdownDynamic, Blockly.Field); /* Blockly.FieldDropdownDynamic.prototype.updateMenu_ = function(e) { console.log("updated!"); this.menuGenerator_ = [['gamja','tiggem'], ['da','naggeoya'], ['grigo', 'igeotto']]; return true; }; */ /** * Clone this FieldDropdownDynamic. * @return {!Blockly.FieldDropdownDynamic} The result of calling the constructor again * with the current values of the arguments used during construction. */ Blockly.FieldDropdownDynamic.prototype.clone = function() { return new Blockly.FieldDropdownDynamic(this.menuGenerator_, this.changeHandler_); }; /** * Create the dropdown field's elements. Only needs to be called once. * @return {!Element} The field's SVG group. */ Blockly.FieldDropdownDynamic.createDom = function() { /* */ var svgGroup = Blockly.createSvgElement('g', {'class': 'blocklyHidden blocklyFieldDropdown'}, null); Blockly.FieldDropdownDynamic.svgGroup_ = svgGroup; Blockly.FieldDropdownDynamic.svgShadow_ = Blockly.createSvgElement('rect', {'class': 'blocklyDropdownMenuShadow', 'x': 0, 'y': 1}, svgGroup); Blockly.FieldDropdownDynamic.svgBackground_ = Blockly.createSvgElement('rect', {'x': -2, 'y': -1, 'filter': 'url(#blocklyEmboss)'}, svgGroup); Blockly.FieldDropdownDynamic.svgOptions_ = Blockly.createSvgElement('g', {'class': 'blocklyDropdownMenuOptions'}, svgGroup); return svgGroup; }; /** * Close the dropdown and dispose of all UI. */ Blockly.FieldDropdownDynamic.prototype.dispose = function() { if (Blockly.FieldDropdownDynamic.openDropdown_ == this) { Blockly.FieldDropdown.hide(); } // Call parent's destructor. Blockly.Field.prototype.dispose.call(this); }; /** * Corner radius of the dropdown background. */ Blockly.FieldDropdownDynamic.CORNER_RADIUS = 2; /** * Mouse cursor style when over the hotspot that initiates the editor. */ Blockly.FieldDropdownDynamic.prototype.CURSOR = 'default'; /** * Which block is the dropdown attached to? * @type {Blockly.FieldDropdownDynamic} * @private */ Blockly.FieldDropdownDynamic.openDropdown_ = null; /** * Create a dropdown menu under the text. * @private */ Blockly.FieldDropdownDynamic.prototype.showEditor_ = function() { if (Blockly.FieldDropdown.workspace !== this.sourceBlock_.workspace) { goog.dom.removeChildren(/** @type {!Element} */ (Blockly.FieldDropdown.svgWrapper_)); var svg = Blockly.FieldDropdown.createDom(); this.sourceBlock_.workspace.svgGroup_.appendChild(svg); Blockly.FieldDropdown.workspace = this.sourceBlock_.workspace } var svgWrapper = Blockly.FieldDropdown.svgWrapper_; var svgGroup = Blockly.FieldDropdown.svgGroup_; var svgOptions = Blockly.FieldDropdown.svgOptions_; var svgBackground = Blockly.FieldDropdown.svgBackground_; var svgShadow = Blockly.FieldDropdown.svgShadow_; // Erase all existing options. goog.dom.removeChildren(svgOptions); // The menu must be made visible early since otherwise BBox and // getComputedTextLength will return 0. Blockly.removeClass_(svgGroup, 'blocklyHidden'); Blockly.FieldDropdownDynamic.openDropdown_ = this; function callbackFactory(value) { return function(e) { if (this.changeHandler_) { // Call any change handler, and allow it to override. var override = this.changeHandler_(value); if (override !== undefined) { value = override; } } if (value !== null) { if (typeof(Entry) == "object" && this.getValue() != value) { Entry.dispatchEvent("entryBlocklyChanged"); } this.setValue(value); } // This mouse click has been handled, don't bubble up to document. e.stopPropagation(); }; } var maxWidth = 0; var resizeList = []; var checkElement = null; var options = this.getOptions_(); for (var x = 0; x < options.length; x++) { var text = options[x][0]; // Human-readable text. var value = options[x][1]; // Language-neutral value. var gElement = Blockly.ContextMenu.optionToDom(text); var rectElement = /** @type {SVGRectElement} */ (gElement.firstChild); var textElement = /** @type {SVGTextElement} */ (gElement.lastChild); svgOptions.appendChild(gElement); // Add a checkmark next to the current item. if (!checkElement && value == this.value_) { checkElement = Blockly.createSvgElement('text', {'class': 'blocklyMenuText', 'y': 15}, null); // Insert the checkmark between the rect and text, thus preserving the // ability to reference them as firstChild and lastChild respectively. gElement.insertBefore(checkElement, textElement); checkElement.appendChild(document.createTextNode('\u2713')); } gElement.setAttribute('transform', 'translate(0, ' + (x * Blockly.ContextMenu.Y_HEIGHT) + ')'); resizeList.push(rectElement); Blockly.bindEvent_(gElement, 'mousedown', null, Blockly.noEvent); Blockly.bindEvent_(gElement, 'mouseup', this, callbackFactory(value)); Blockly.bindEvent_(gElement, 'mouseup', null, Blockly.FieldDropdown.hide); // Compute the length of the longest text length. maxWidth = Math.max(maxWidth, textElement.getComputedTextLength()); } // Run a second pass to resize all options to the required width. maxWidth += Blockly.ContextMenu.X_PADDING * 2; for (var x = 0; x < resizeList.length; x++) { resizeList[x].setAttribute('width', maxWidth); } if (Blockly.RTL) { // Right-align the text. for (var x = 0, gElement; gElement = svgOptions.childNodes[x]; x++) { var textElement = gElement.lastChild; textElement.setAttribute('text-anchor', 'end'); textElement.setAttribute('x', maxWidth - Blockly.ContextMenu.X_PADDING); } } if (checkElement) { if (Blockly.RTL) { // Research indicates that RTL checkmarks are supposed to be drawn the // same in the same direction as LTR checkmarks. It's only the alignment // that needs to change. checkElement.setAttribute('text-anchor', 'end'); checkElement.setAttribute('x', maxWidth - 5); } else { checkElement.setAttribute('x', 5); } } var width = maxWidth + Blockly.FieldDropdownDynamic.CORNER_RADIUS * 2; var height = options.length * Blockly.ContextMenu.Y_HEIGHT + Blockly.FieldDropdownDynamic.CORNER_RADIUS + 1; svgShadow.setAttribute('width', width); svgShadow.setAttribute('height', height); svgBackground.setAttribute('width', width); svgBackground.setAttribute('height', height); var hexColour = Blockly.makeColour(this.sourceBlock_.getColour()); svgBackground.setAttribute('fill', hexColour); // Position the dropdown to line up with the field. var xy = Blockly.getSvgXY_(/** @type {!Element} */ (this.borderRect_)); var borderBBox = this.borderRect_.getBBox(); var x; if (Blockly.RTL) { x = xy.x - maxWidth + Blockly.ContextMenu.X_PADDING + borderBBox.width - Blockly.BlockSvg.SEP_SPACE_X / 2; } else { x = xy.x - Blockly.ContextMenu.X_PADDING + Blockly.BlockSvg.SEP_SPACE_X / 2; } var scrollWrapper = Blockly.FieldDropdown.scrollbarWrapper_ if (options.length <= 10) { Blockly.addClass_(scrollWrapper, 'blocklyHidden'); } else { var hw = svgOptions.getBBox(); Blockly.removeClass_(scrollWrapper, 'blocklyHidden'); scrollWrapper.setAttribute('transform', 'translate('+ (Number(hw.width)-15) + ' 0)'); } Blockly.FieldDropdown.wheelEvent_ = Blockly.bindEvent_( svgGroup, 'wheel', this, Blockly.FieldDropdown.onMouseWheel); Blockly.FieldDropdown.moveUpEvent_ = Blockly.bindEvent_(Blockly.FieldDropdown.scrollbarUpWrapper_,'mouseover', this, Blockly.FieldDropdown.moveUp); Blockly.FieldDropdown.moveUpLeaveEvent_ = Blockly.bindEvent_(Blockly.FieldDropdown.scrollbarUpWrapper_,'mouseleave', this, Blockly.FieldDropdown.mouseLeave); Blockly.FieldDropdown.moveDownEvent_ = Blockly.bindEvent_(Blockly.FieldDropdown.scrollbarDownWrapper_,'mouseover', this, Blockly.FieldDropdown.moveDown); Blockly.FieldDropdown.moveDownLeaveEvent_ = Blockly.bindEvent_(Blockly.FieldDropdown.scrollbarDownWrapper_,'mouseleave', this, Blockly.FieldDropdown.mouseLeave); svgWrapper.setAttribute('x', x); svgWrapper.setAttribute('y', xy.y + borderBBox.height); }; /** * Factor out common words in statically defined options. * Create prefix and/or suffix labels. * @private */ Blockly.FieldDropdownDynamic.prototype.trimOptions_ = function() { return; //ignore trim feature this.prefixField = null; this.suffixField = null; var options = this.menuGenerator_; if (!goog.isArray(options) || options.length < 2) { return; } var strings = options.map(function(t) {return t[0];}); var shortest = Blockly.shortestStringLength(strings); var prefixLength = Blockly.commonWordPrefix(strings, shortest); var suffixLength = Blockly.commonWordSuffix(strings, shortest); if (!prefixLength && !suffixLength) { return; } if (shortest <= prefixLength + suffixLength) { // One or more strings will entirely vanish if we proceed. Abort. return; } if (prefixLength) { this.prefixField = strings[0].substring(0, prefixLength - 1); } if (suffixLength) { this.suffixField = strings[0].substr(1 - suffixLength); } // Remove the prefix and suffix from the options. var newOptions = []; for (var x = 0; x < options.length; x++) { var text = options[x][0]; var value = options[x][1]; text = text.substring(prefixLength, text.length - suffixLength); newOptions[x] = [text, value]; } this.menuGenerator_ = newOptions; }; /** * Return a list of the options for this dropdown. * @return {!Array.>} Array of option tuples: * (human-readable text, language-neutral name). * @private */ Blockly.FieldDropdownDynamic.prototype.getOptions_ = function() { if (typeof(Entry.container) == "object") { if (this.menuName_) return Entry.container.getDropdownList(this.menuName_); else { return this.menuFunc_.call(this); } } else { return [[Lang.Blocks.no_target, 'null']]; } return /** @type {!Array.>} */ (this.menuGenerator_); }; /** * Get the language-neutral value from this dropdown menu. * @return {string} Current text. */ Blockly.FieldDropdownDynamic.prototype.getValue = function() { return this.value_; }; /** * Set the language-neutral value for this dropdown menu. * @param {string} newValue New value to set. */ Blockly.FieldDropdownDynamic.prototype.setValue = function(newValue) { this.value_ = newValue; // Look up and display the human-readable text. var options = this.getOptions_(); for (var x = 0; x < options.length; x++) { // Options are tuples of human-readable text and language-neutral values. if (options[x][1] == newValue) { this.setText(options[x][0]); return; } } // Value not found. Add it, maybe it will become valid once set // (like variable names). this.setText('대상없음'); }; /** * Set the text in this field. Trigger a rerender of the source block. * @param {?string} text New text. */ Blockly.FieldDropdownDynamic.prototype.setText = function(text) { if (this.sourceBlock_) { // Update arrow's colour. if (this.arrowColor_) this.arrow_.style.fill = this.arrowColor_; else this.arrow_.style.fill = Blockly.makeColour(this.sourceBlock_.getColour()); } if (!text || text === null) { // No change if null. return; } this.text_ = text; // Empty the text element. goog.dom.removeChildren(/** @type {!Element} */ (this.textElement_)); // Replace whitespace with non-breaking spaces so the text doesn't collapse. text = text.replace(/\s/g, Blockly.Field.NBSP); if (!text) { // Prevent the field from disappearing if empty. text = Blockly.Field.NBSP; } var textNode = document.createTextNode(text); this.textElement_.appendChild(textNode); // Insert dropdown arrow. if (Blockly.RTL) { this.textElement_.insertBefore(this.arrow_, this.textElement_.firstChild); } else { this.textElement_.appendChild(this.arrow_); } // Cached width is obsolete. Clear it. this.size_.width = 0; if (this.sourceBlock_ && this.sourceBlock_.rendered) { this.sourceBlock_.render(); this.sourceBlock_.bumpNeighbours_(); this.sourceBlock_.workspace.fireChangeEvent(); } }; /** * Hide the dropdown menu. */ Blockly.FieldDropdownDynamic.hide = function() { //this function should not be called but in order to prevent unexpected error, //remain this function Blockly.FieldDropdown.hide(); }; ================================================ FILE: extern/blockly/core/field_icon.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Image field. Used for titles, labels, etc. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.FieldIcon'); goog.require('Blockly.Field'); goog.require('goog.userAgent'); /** * Class for an image. * @param {string} src The URL of the image. * @param {?string} opt_alt Optional alt text for when block is collapsed. * @param {?string} type type of icon. * @extends {Blockly.Field} * @constructor */ Blockly.FieldIcon = function(src, opt_alt, type) { this.sourceBlock_ = null; this.type = type ? type : "endOrigin"; if (this.type == "end") { // Ensure height and width are numbers. Strings are bad at math. var height = 24; var width = 24; this.height_ = Number(height); this.width_ = Number(width); this.iconSize = 0.7; } else if ( this.type == "endOrigin" ) { var height = 24; var width = 24; this.height_ = Number(height); this.width_ = Number(width); } else if ( this.type == "start" ) { var height = 34; var width = 34; this.height_ = Number(height); this.width_ = Number(width); } this.size_ = {height: this.height_, width: this.width_}; this.text_ = opt_alt || ''; // Build the DOM. var offsetY = 0; if (this.type == "end") { this.fieldGroup_ = Blockly.createSvgElement('g', {}, null); this.circleElement_ = Blockly.createSvgElement('circle', {'cx': this.width_/2, 'cy': this.height_/2, 'r': this.width_/2, 'y': offsetY}, this.fieldGroup_); this.imageElement_ = Blockly.createSvgElement('image', {'height': this.height_*this.iconSize + 'px', 'width': this.width_*this.iconSize + 'px', 'x': this.width_ * (1 - this.iconSize) / 2, 'y': this.height_ * (1 - this.iconSize) / 2}, this.fieldGroup_); this.setValue(src); } else if ( this.type == "endOrigin" ) { this.fieldGroup_ = Blockly.createSvgElement('g', {}, null); this.imageElement_ = Blockly.createSvgElement('image', {'height': this.height_ + 'px', 'width': this.width_ + 'px', 'x': 0, 'y': 0}, this.fieldGroup_); this.setValue(src); } else if ( this.type == "start" ) { this.fieldGroup_ = Blockly.createSvgElement('g', {}, null); this.imageElement_ = Blockly.createSvgElement('image', {'height': this.height_ + 'px', 'width': this.width_ + 'px', 'x': 0, 'y': -2}, this.fieldGroup_); this.setValue(src); } if (goog.userAgent.GECKO) { // Due to a Firefox bug which eats mouse events on image elements, // a transparent rectangle needs to be placed on top of the image. this.rectElement_ = Blockly.createSvgElement('rect', {'height': this.height_ + 'px', 'width': this.width_ + 'px', 'y': offsetY, 'fill-opacity': 0}, this.fieldGroup_); } }; goog.inherits(Blockly.FieldIcon, Blockly.Field); /** * Clone this FieldIcon. * @return {!Blockly.FieldIcon} The result of calling the constructor again * with the current values of the arguments used during construction. */ Blockly.FieldIcon.prototype.clone = function() { return new Blockly.FieldIcon(this.getSrc(), this.width_, this.height_, this.getText()); }; /** * Rectangular mask used by Firefox. * @type {Element} * @private */ Blockly.FieldIcon.prototype.rectElement_ = null; /** * Editable fields are saved by the XML renderer, non-editable fields are not. */ Blockly.FieldIcon.prototype.EDITABLE = false; /** * Install this text on a block. * @param {!Blockly.Block} block The block containing this text. */ Blockly.FieldIcon.prototype.init = function(block) { if (this.sourceBlock_) { throw 'Image has already been initialized once.'; } this.sourceBlock_ = block; block.getSvgRoot().appendChild(this.fieldGroup_); // Configure the field to be transparent with respect to tooltips. if (!this.type || this.type == "end") { var topElement = this.rectElement_ || this.imageElement_; topElement.tooltip = this.sourceBlock_; var rgb = goog.color.hexToRgb(block.getColour()); var c = goog.color.darken(rgb, 0.2); c = goog.color.rgbToHex(c[0], c[1], c[2]); this.circleElement_.style.fill = c; } else if ( this.type == "endOrigin" ) { var topElement = this.imageElement_; topElement.tooltip = this.sourceBlock_; } else if ( this.type == "start" ) { var topElement = this.imageElement_; topElement.tooltip = this.sourceBlock_; } Blockly.Tooltip && Blockly.Tooltip.bindMouseEvents(topElement); }; /** * Dispose of all DOM objects belonging to this text. */ Blockly.FieldIcon.prototype.dispose = function() { goog.dom.removeNode(this.fieldGroup_); this.fieldGroup_ = null; this.imageElement_ = null; this.rectElement_ = null; }; /** * Change the tooltip text for this field. * @param {string|!Element} newTip Text for tooltip or a parent element to * link to for its tooltip. */ Blockly.FieldIcon.prototype.setTooltip = function(newTip) { var topElement = this.rectElement_ || this.imageElement_; topElement.tooltip = newTip; }; /** * Get the source URL of this image. * @return {string} Current text. * @override */ Blockly.FieldIcon.prototype.getValue = function() { return this.src_; }; /** * Set the source URL of this image. * @param {?string} src New source. * @override */ Blockly.FieldIcon.prototype.setValue = function(src) { if (src === null) { // No change if null. return; } this.src_ = src; this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', goog.isString(src) ? src : ''); }; /** * Set the alt text of this image. * @param {?string} alt New alt text. * @override */ Blockly.FieldIcon.prototype.setText = function(alt) { if (alt === null) { // No change if null. return; } this.text_ = alt; }; ================================================ FILE: extern/blockly/core/field_image.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Image field. Used for titles, labels, etc. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.FieldImage'); goog.require('Blockly.Field'); goog.require('goog.userAgent'); /** * Class for an image. * @param {string} src The URL of the image. * @param {number} width Width of the image. * @param {number} height Height of the image. * @param {?string} opt_alt Optional alt text for when block is collapsed. * @extends {Blockly.Field} * @constructor */ Blockly.FieldImage = function(src, width, height, opt_alt) { this.sourceBlock_ = null; // Ensure height and width are numbers. Strings are bad at math. this.height_ = Number(height); this.width_ = Number(width); this.size_ = {height: this.height_ + 10, width: this.width_}; this.text_ = opt_alt || ''; // Build the DOM. var offsetY = 6 - Blockly.BlockSvg.FIELD_HEIGHT; this.fieldGroup_ = Blockly.createSvgElement('g', {}, null); this.imageElement_ = Blockly.createSvgElement('image', {'height': this.height_ + 'px', 'width': this.width_ + 'px', 'y': offsetY}, this.fieldGroup_); this.setValue(src); if (goog.userAgent.GECKO) { // Due to a Firefox bug which eats mouse events on image elements, // a transparent rectangle needs to be placed on top of the image. this.rectElement_ = Blockly.createSvgElement('rect', {'height': this.height_ + 'px', 'width': this.width_ + 'px', 'y': offsetY, 'fill-opacity': 0}, this.fieldGroup_); } }; goog.inherits(Blockly.FieldImage, Blockly.Field); /** * Clone this FieldImage. * @return {!Blockly.FieldImage} The result of calling the constructor again * with the current values of the arguments used during construction. */ Blockly.FieldImage.prototype.clone = function() { return new Blockly.FieldImage(this.getSrc(), this.width_, this.height_, this.getText()); }; /** * Rectangular mask used by Firefox. * @type {Element} * @private */ Blockly.FieldImage.prototype.rectElement_ = null; /** * Editable fields are saved by the XML renderer, non-editable fields are not. */ Blockly.FieldImage.prototype.EDITABLE = false; /** * Install this text on a block. * @param {!Blockly.Block} block The block containing this text. */ Blockly.FieldImage.prototype.init = function(block) { if (this.sourceBlock_) { throw 'Image has already been initialized once.'; } this.sourceBlock_ = block; block.getSvgRoot().appendChild(this.fieldGroup_); // Configure the field to be transparent with respect to tooltips. var topElement = this.rectElement_ || this.imageElement_; topElement.tooltip = this.sourceBlock_; Blockly.Tooltip && Blockly.Tooltip.bindMouseEvents(topElement); }; /** * Dispose of all DOM objects belonging to this text. */ Blockly.FieldImage.prototype.dispose = function() { goog.dom.removeNode(this.fieldGroup_); this.fieldGroup_ = null; this.imageElement_ = null; this.rectElement_ = null; }; /** * Change the tooltip text for this field. * @param {string|!Element} newTip Text for tooltip or a parent element to * link to for its tooltip. */ Blockly.FieldImage.prototype.setTooltip = function(newTip) { var topElement = this.rectElement_ || this.imageElement_; topElement.tooltip = newTip; }; /** * Get the source URL of this image. * @return {string} Current text. * @override */ Blockly.FieldImage.prototype.getValue = function() { return this.src_; }; /** * Set the source URL of this image. * @param {?string} src New source. * @override */ Blockly.FieldImage.prototype.setValue = function(src) { if (src === null) { // No change if null. return; } this.src_ = src; this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', goog.isString(src) ? src : ''); }; /** * Set the alt text of this image. * @param {?string} alt New alt text. * @override */ Blockly.FieldImage.prototype.setText = function(alt) { if (alt === null) { // No change if null. return; } this.text_ = alt; }; ================================================ FILE: extern/blockly/core/field_keydown_input.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Text input field. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.FieldKeydownInput'); goog.require('Blockly.Field'); goog.require('Blockly.Msg'); goog.require('goog.asserts'); goog.require('goog.userAgent'); /** * Class for an editable text field. * @param {string} text The initial content of the field. * @param {Function} opt_changeHandler An optional function that is called * to validate any constraints on what the user entered. Takes the new * text as an argument and returns either the accepted text, a replacement * text, or null to abort the change. * @extends {Blockly.Field} * @constructor */ Blockly.FieldKeydownInput = function(value) { this.arrow_ = Blockly.createSvgElement('tspan', {}, null); var keyMap = Entry.getKeyCodeMap(); this.value_ = value; Blockly.FieldKeydownInput.superClass_.constructor.call(this, keyMap[value]); }; goog.inherits(Blockly.FieldKeydownInput, Blockly.Field); var fkip = Blockly.FieldKeydownInput.prototype; /** * Clone this FieldKeydownInput. * @return {!Blockly.FieldTextInput} The result of calling the constructor again * with the current values of the arguments used during construction. */ fkip.clone = function() { return new Blockly.FieldKeydownInput(this.getText(), this.changeHandler_); }; /** * Create the dropdown field's elements. Only needs to be called once. * @return {!Element} The field's SVG group. */ Blockly.FieldKeydownInput.createDom = function() { var url = Blockly.mediaFilePath + 'media/keyboard_workspace.png'; var svgGroup = Blockly.createSvgElement('g', {'class': 'blocklyHelperDiv blocklyHidden'}, null); var helpImg = Blockly.createSvgElement('image', {'class': 'blocklyHelperImg', 'width': '249', 'height': '106' }, svgGroup); helpImg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', url); Blockly.FieldKeydownInput.helperSvgGroup_ = svgGroup; return svgGroup; }; /** * Mouse cursor style when over the hotspot that initiates the editor. */ fkip.CURSOR = 'pointer'; /** * Dispose of all DOM objects belonging to this editable field. */ fkip.dispose = function() { Blockly.WidgetDiv.hideIfField(this); Blockly.FieldTextInput.superClass_.dispose.call(this); }; /** * Set the text in this field. * @param {?string} keycode New text. * @override */ fkip.setText = function(text) { if (text === null) return; if (!text) Blockly.Field.prototype.setText.call(this, ' '); else Blockly.Field.prototype.setText.call(this, text); }; /** * Show the inline free-text editor on top of the text. * @private */ fkip.showEditor_ = function() { Blockly.WidgetDiv.show(this, this.dispose_()); var div = Blockly.WidgetDiv.DIV; // Create the input. var htmlInput = goog.dom.createDom('input', 'blocklyHtmlInput'); Blockly.FieldTextInput.htmlInput_ = htmlInput; div.appendChild(htmlInput); htmlInput.value = htmlInput.defaultValue = this.text_; htmlInput.oldValue_ = null; this.resizeEditor_(); htmlInput.focus(); htmlInput.select(); // Bind to keyup -- trap Enter and Esc; resize after every keystroke. htmlInput.onKeyUpWrapper_ = Blockly.bindEvent_(htmlInput, 'keyup', this, this.onHtmlInputChange_); // Bind to keyPress -- repeatedly resize when holding down a key. //htmlInput.onKeyPressWrapper_ = //Blockly.bindEvent_(htmlInput, 'keypress', this, this.onHtmlInputChange_); htmlInput.onBlurWrapper_ = Blockly.bindEvent_(htmlInput, 'blur', this, Blockly.WidgetDiv.hide); htmlInput.onBlurWrapper_ = Blockly.bindEvent_(htmlInput, 'blur', this, Blockly.FieldKeydownInput.hide); var workspaceSvg = this.sourceBlock_.workspace.getCanvas(); var helperSvgGroup = Blockly.FieldKeydownInput.helperSvgGroup_; Blockly.removeClass_(helperSvgGroup, 'blocklyHidden'); var xy = Blockly.getSvgXY_(/** @type {!Element} */ (this.borderRect_)); var borderBBox = this.borderRect_.getBBox(); helperSvgGroup.setAttribute('transform', 'translate(' + (xy.x - 15 + borderBBox.width/2) + ', ' + (xy.y + 19) + ')'); }; /** * Handle a change to the editor. * @param {!Event} e Keyboard event. * @private */ fkip.onHtmlInputChange_ = function(e) { var htmlInput = Blockly.FieldTextInput.htmlInput_; htmlInput.value = ''; var c = e.keyCode; if ((c>=65 && c<=90) || (c>=37 && c<=40) || (c>=48 && c<=57) || c == 32 || c == 13) { Blockly.WidgetDiv.hide(); Blockly.FieldKeydownInput.hide(); this.setValue(c); } }; /** * Close the editor, save the results, and dispose of the editable * text field's elements. * @return {!Function} Closure to call on destruction of the WidgetDiv. * @private */ fkip.dispose_ = function() { var thisField = this; return function() { var htmlInput = Blockly.FieldTextInput.htmlInput_; var text; // Save the edit (if it validates). text = htmlInput.value; // thisField.setText(text); thisField.sourceBlock_.render(); Blockly.unbindEvent_(htmlInput.onKeyUpWrapper_); //Blockly.unbindEvent_(htmlInput.onKeyPressWrapper_); Blockly.FieldTextInput.htmlInput_ = null; }; }; /** * Hide the dropdown menu. */ Blockly.FieldKeydownInput.hide = function() { var helperSvgGroup = Blockly.FieldKeydownInput.helperSvgGroup_; if (helperSvgGroup) { Blockly.addClass_(helperSvgGroup, 'blocklyHidden'); } }; /** * Set the language-neutral value for this dropdown menu. * @param {string} value New value to set. */ fkip.setValue = function(value) { this.value_ = value; var keyMap = Entry.getKeyCodeMap(); var text = keyMap[value]; if (text) { this.setText(String(text)); return; } else { this.setText(Lang.Blocks.no_target); return; } }; /** * Get the language-neutral value from this dropdown menu. * @return {string} Current text. */ fkip.getValue = function() { return String(this.value_); }; /** * Resize the editor and the underlying block to fit the text. * @private */ fkip.resizeEditor_ = function() { var div = Blockly.WidgetDiv.DIV; var bBox = this.fieldGroup_.getBBox(); div.style.width = bBox.width + 'px'; var xy = Blockly.getAbsoluteXY_(/** @type {!Element} */ (this.borderRect_), this.sourceBlock_.workspace.svgGroup_.parentNode); // In RTL mode block fields and LTR input fields the left edge moves, // whereas the right edge is fixed. Reposition the editor. if (Blockly.RTL) { var borderBBox = this.borderRect_.getBBox(); xy.x += borderBBox.width; xy.x -= div.offsetWidth; } // Shift by a few pixels to line up exactly. xy.y += 1; if (goog.userAgent.WEBKIT) { xy.y -= 3; } div.style.left = xy.x + 'px'; div.style.top = xy.y + 'px'; }; ================================================ FILE: extern/blockly/core/field_label.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Non-editable text field. Used for titles, labels, etc. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.FieldLabel'); goog.require('Blockly.Field'); goog.require('Blockly.Tooltip'); /** * Class for a non-editable field. * @param {string} text The initial content of the field. * @param {string} color Color code of the field. * @extends {Blockly.Field} * @constructor */ Blockly.FieldLabel = function(text, color) { this.sourceBlock_ = null; // Build the DOM. if (goog.isString(color)) this.textElement_ = Blockly.createSvgElement('text', {'class': 'blocklyText', 'style': 'fill:' + color, 'y': 12}, null); else this.textElement_ = Blockly.createSvgElement('text', {'class': 'blocklyText', 'y': 12}, null); this.size_ = {height: 14, width: 0}; this.setText(text); }; goog.inherits(Blockly.FieldLabel, Blockly.Field); /** * Clone this FieldLabel. * @return {!Blockly.FieldLabel} The result of calling the constructor again * with the current values of the arguments used during construction. */ Blockly.FieldLabel.prototype.clone = function() { return new Blockly.FieldLabel(this.getText()); }; /** * Editable fields are saved by the XML renderer, non-editable fields are not. */ Blockly.FieldLabel.prototype.EDITABLE = false; /** * Install this text on a block. * @param {!Blockly.Block} block The block containing this text. */ Blockly.FieldLabel.prototype.init = function(block) { if (this.sourceBlock_) { throw 'Text has already been initialized once.'; } this.sourceBlock_ = block; block.getSvgRoot().appendChild(this.textElement_); // Configure the field to be transparent with respect to tooltips. this.textElement_.tooltip = this.sourceBlock_; Blockly.Tooltip && Blockly.Tooltip.bindMouseEvents(this.textElement_); }; /** * Dispose of all DOM objects belonging to this text. */ Blockly.FieldLabel.prototype.dispose = function() { goog.dom.removeNode(this.textElement_); this.textElement_ = null; }; /** * Gets the group element for this field. * Used for measuring the size and for positioning. * @return {!Element} The group element. */ Blockly.FieldLabel.prototype.getRootElement = function() { return /** @type {!Element} */ (this.textElement_); }; /** * Change the tooltip text for this field. * @param {string|!Element} newTip Text for tooltip or a parent element to * link to for its tooltip. */ Blockly.FieldLabel.prototype.setTooltip = function(newTip) { this.textElement_.tooltip = newTip; }; ================================================ FILE: extern/blockly/core/field_textinput.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Text input field. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.FieldTextInput'); goog.require('Blockly.Field'); goog.require('Blockly.Msg'); goog.require('goog.asserts'); goog.require('goog.userAgent'); /** * Class for an editable text field. * @param {string} text The initial content of the field. * @param {Function} opt_changeHandler An optional function that is called * to validate any constraints on what the user entered. Takes the new * text as an argument and returns either the accepted text, a replacement * text, or null to abort the change. * @extends {Blockly.Field} * @constructor */ Blockly.FieldTextInput = function(text, opt_changeHandler) { Blockly.FieldTextInput.superClass_.constructor.call(this, text); this.changeHandler_ = opt_changeHandler; this.isTextInput = true; }; goog.inherits(Blockly.FieldTextInput, Blockly.Field); /** * Clone this FieldTextInput. * @return {!Blockly.FieldTextInput} The result of calling the constructor again * with the current values of the arguments used during construction. */ Blockly.FieldTextInput.prototype.clone = function() { return new Blockly.FieldTextInput(this.getText(), this.changeHandler_); }; /** * Mouse cursor style when over the hotspot that initiates the editor. */ Blockly.FieldTextInput.prototype.CURSOR = 'text'; /** * Dispose of all DOM objects belonging to this editable field. */ Blockly.FieldTextInput.prototype.dispose = function() { Blockly.WidgetDiv.hideIfField(this); Blockly.FieldTextInput.superClass_.dispose.call(this); }; /** * Set the text in this field. * @param {?string} text New text. * @override */ Blockly.FieldTextInput.prototype.setText = function(text) { if (text === null) { // No change if null. return; } if (this.changeHandler_) { var validated = this.changeHandler_(text); // If the new text is invalid, validation returns null. // In this case we still want to display the illegal result. if (validated !== null && validated !== undefined) { text = validated; } } Blockly.Field.prototype.setText.call(this, text, true); }; /** * Show the inline free-text editor on top of the text. * @private */ Blockly.FieldTextInput.prototype.showEditor_ = function() { if (goog.userAgent.MOBILE) { // Mobile browsers have issues with in-line textareas (focus & keyboards). var newValue = window.prompt(Blockly.Msg.CHANGE_VALUE_TITLE, this.text_); if (this.changeHandler_) { var override = this.changeHandler_(newValue); if (override !== undefined) { newValue = override; } } if (newValue !== null) { this.setText(newValue); } return; } Blockly.WidgetDiv.show(this, this.dispose_()); var div = Blockly.WidgetDiv.DIV; // Create the input. var htmlInput = goog.dom.createDom('input', 'blocklyHtmlInput'); Blockly.FieldTextInput.htmlInput_ = htmlInput; div.appendChild(htmlInput); htmlInput.value = htmlInput.defaultValue = this.text_; htmlInput.oldValue_ = null; this.validate_(); this.resizeEditor_(); htmlInput.focus(); htmlInput.select(); // Bind to keyup -- trap Enter and Esc; resize after every keystroke. htmlInput.onKeyUpWrapper_ = Blockly.bindEvent_(htmlInput, 'keyup', this, this.onHtmlInputChange_); // Bind to keyPress -- repeatedly resize when holding down a key. htmlInput.onKeyPressWrapper_ = Blockly.bindEvent_(htmlInput, 'keypress', this, this.onHtmlInputChange_); htmlInput.onBlurWrapper_ = Blockly.bindEvent_(htmlInput, 'blur', this, Blockly.WidgetDiv.hide); var workspaceSvg = this.sourceBlock_.workspace.getCanvas(); htmlInput.onWorkspaceChangeWrapper_ = Blockly.bindEvent_(workspaceSvg, 'blocklyWorkspaceChange', this, this.resizeEditor_); }; /** * Handle a change to the editor. * @param {!Event} e Keyboard event. * @private */ Blockly.FieldTextInput.prototype.onHtmlInputChange_ = function(e) { var htmlInput = Blockly.FieldTextInput.htmlInput_; if (e.keyCode == 13) { // Enter Blockly.WidgetDiv.hide(); } else if (e.keyCode == 27) { // Esc this.setText(htmlInput.defaultValue); Blockly.WidgetDiv.hide(); } else { // Update source block. var text = htmlInput.value; if (text !== htmlInput.oldValue_) { htmlInput.oldValue_ = text; this.setText(text); this.validate_(); } else if (goog.userAgent.WEBKIT) { // Cursor key. Render the source block to show the caret moving. // Chrome only (version 26, OS X). this.sourceBlock_.render(); } } }; /** * Check to see if the contents of the editor validates. * Style the editor accordingly. * @private */ Blockly.FieldTextInput.prototype.validate_ = function() { var valid = true; goog.asserts.assertObject(Blockly.FieldTextInput.htmlInput_); var htmlInput = /** @type {!Element} */ (Blockly.FieldTextInput.htmlInput_); if (this.changeHandler_) { valid = this.changeHandler_(htmlInput.value); } if (valid === null) { Blockly.addClass_(htmlInput, 'blocklyInvalidInput'); } else { Blockly.removeClass_(htmlInput, 'blocklyInvalidInput'); } }; /** * Resize the editor and the underlying block to fit the text. * @private */ Blockly.FieldTextInput.prototype.resizeEditor_ = function() { var div = Blockly.WidgetDiv.DIV; var bBox = this.fieldGroup_.getBBox(); div.style.width = bBox.width + 'px'; var xy = Blockly.getAbsoluteXY_(/** @type {!Element} */ (this.borderRect_), this.sourceBlock_.workspace.svgGroup_.parentNode); // In RTL mode block fields and LTR input fields the left edge moves, // whereas the right edge is fixed. Reposition the editor. if (Blockly.RTL) { var borderBBox = this.borderRect_.getBBox(); xy.x += borderBBox.width; xy.x -= div.offsetWidth; } // Shift by a few pixels to line up exactly. xy.y += 1; if (goog.userAgent.WEBKIT) { xy.y -= 3; } div.style.left = xy.x + 'px'; div.style.top = xy.y + 'px'; }; /** * Close the editor, save the results, and dispose of the editable * text field's elements. * @return {!Function} Closure to call on destruction of the WidgetDiv. * @private */ Blockly.FieldTextInput.prototype.dispose_ = function() { var thisField = this; return function() { var htmlInput = Blockly.FieldTextInput.htmlInput_; var text; // Save the edit (if it validates). text = htmlInput.value; if (thisField.changeHandler_) { text = thisField.changeHandler_(text); if (text === null) { // Invalid edit. text = htmlInput.defaultValue; } } thisField.setText(text); thisField.sourceBlock_.render(); Blockly.unbindEvent_(htmlInput.onKeyUpWrapper_); Blockly.unbindEvent_(htmlInput.onKeyPressWrapper_); Blockly.unbindEvent_(htmlInput.onWorkspaceChangeWrapper_); Blockly.FieldTextInput.htmlInput_ = null; }; }; /** * Ensure that only a number may be entered. * @param {string} text The user's text. * @return {?string} A string representing a valid number, or null if invalid. */ Blockly.FieldTextInput.numberValidator = function(text) { // TODO: Handle cases like 'ten', '1.203,14', etc. // 'O' is sometimes mistaken for '0' by inexperienced users. text = text.replace(/O/ig, '0'); // Strip out thousands separators. text = text.replace(/,/g, ''); var n = parseFloat(text || 0); return isNaN(n) ? null : String(n); }; /** * Ensure that only a nonnegative integer may be entered. * @param {string} text The user's text. * @return {?string} A string representing a valid int, or null if invalid. */ Blockly.FieldTextInput.nonnegativeIntegerValidator = function(text) { var n = Blockly.FieldTextInput.numberValidator(text); if (n) { n = String(Math.max(0, Math.floor(n))); } return n; }; ================================================ FILE: extern/blockly/core/field_variable.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Variable input field. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.FieldVariable'); goog.require('Blockly.FieldDropdown'); goog.require('Blockly.Msg'); goog.require('Blockly.Variables'); /** * Class for a variable's dropdown field. * @param {!string} varname The default name for the variable. If null, * a unique variable name will be generated. * @param {Function} opt_changeHandler A function that is executed when a new * option is selected. Its sole argument is the new option value. Its * return value is ignored. * @extends {Blockly.FieldDropdown} * @constructor */ Blockly.FieldVariable = function(varname, opt_changeHandler) { var changeHandler; if (opt_changeHandler) { // Wrap the user's change handler together with the variable rename handler. var thisObj = this; changeHandler = function(value) { var retVal = Blockly.FieldVariable.dropdownChange.call(thisObj, value); var newVal; if (retVal === undefined) { newVal = value; // Existing variable selected. } else if (retVal === null) { newVal = thisObj.getValue(); // Abort, no change. } else { newVal = retVal; // Variable name entered. } opt_changeHandler.call(thisObj, newVal); return retVal; }; } else { changeHandler = Blockly.FieldVariable.dropdownChange; } Blockly.FieldVariable.superClass_.constructor.call(this, Blockly.FieldVariable.dropdownCreate, changeHandler); if (varname) { this.setValue(varname); } else { this.setValue(Blockly.Variables.generateUniqueName()); } }; goog.inherits(Blockly.FieldVariable, Blockly.FieldDropdown); /** * Clone this FieldVariable. * @return {!Blockly.FieldVariable} The result of calling the constructor again * with the current values of the arguments used during construction. */ Blockly.FieldVariable.prototype.clone = function() { return new Blockly.FieldVariable(this.getValue(), this.changeHandler_); }; /** * Get the variable's name (use a variableDB to convert into a real name). * Unline a regular dropdown, variables are literal and have no neutral value. * @return {string} Current text. */ Blockly.FieldVariable.prototype.getValue = function() { return this.getText(); }; /** * Set the variable name. * @param {string} text New text. */ Blockly.FieldVariable.prototype.setValue = function(text) { this.value_ = text; this.setText(text); }; /** * Return a sorted list of variable names for variable dropdown menus. * Include a special option at the end for creating a new variable name. * @return {!Array.} Array of variable names. * @this {!Blockly.FieldVariable} */ Blockly.FieldVariable.dropdownCreate = function() { var variableList = Blockly.Variables.allVariables(); // Ensure that the currently selected variable is an option. var name = this.getText(); if (name && variableList.indexOf(name) == -1) { variableList.push(name); } variableList.sort(goog.string.caseInsensitiveCompare); variableList.push(Blockly.Msg.RENAME_VARIABLE); variableList.push(Blockly.Msg.NEW_VARIABLE); // Variables are not language-specific, use the name as both the user-facing // text and the internal representation. var options = []; for (var x = 0; x < variableList.length; x++) { options[x] = [variableList[x], variableList[x]]; } return options; }; /** * Event handler for a change in variable name. * Special case the 'New variable...' and 'Rename variable...' options. * In both of these special cases, prompt the user for a new name. * @param {string} text The selected dropdown menu option. * @return {null|undefined|string} An acceptable new variable name, or null if * change is to be either aborted (cancel button) or has been already * handled (rename), or undefined if an existing variable was chosen. * @this {!Blockly.FieldVariable} */ Blockly.FieldVariable.dropdownChange = function(text) { function promptName(promptText, defaultText) { Blockly.hideChaff(); var newVar = window.prompt(promptText, defaultText); // Merge runs of whitespace. Strip leading and trailing whitespace. // Beyond this, all names are legal. return newVar && newVar.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, ''); } if (text == Blockly.Msg.RENAME_VARIABLE) { var oldVar = this.getText(); text = promptName(Blockly.Msg.RENAME_VARIABLE_TITLE.replace('%1', oldVar), oldVar); if (text) { Blockly.Variables.renameVariable(oldVar, text); } return null; } else if (text == Blockly.Msg.NEW_VARIABLE) { text = promptName(Blockly.Msg.NEW_VARIABLE_TITLE, ''); // Since variables are case-insensitive, ensure that if the new variable // matches with an existing variable, the new case prevails throughout. if (text) { Blockly.Variables.renameVariable(text, text); return text; } return null; } return undefined; }; ================================================ FILE: extern/blockly/core/flyout.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Flyout tray containing blocks which may be created. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Flyout'); goog.require('Blockly.Block'); goog.require('Blockly.Comment'); /** * Class for a flyout. * @constructor */ Blockly.Flyout = function() { /** * @type {!Blockly.Workspace} * @private */ var flyout = this; this.workspace_ = new Blockly.Workspace( function() {return flyout.getMetrics_();}, function(ratio) {return flyout.setMetrics_(ratio);}); this.workspace_.isFlyout = true; /** * Opaque data that can be passed to removeChangeListener. * @type {Array.} * @private */ this.changeWrapper_ = null; /** * @type {number} * @private */ this.width_ = 0; /** * @type {number} * @private */ this.height_ = 0; /** * List of background buttons that lurk behind each block to catch clicks * landing in the blocks' lakes and bays. * @type {!Array.} * @private */ this.buttons_ = []; /** * List of event listeners. * @type {!Array.} * @private */ this.listeners_ = []; }; /** * Does the flyout automatically close when a block is created? * @type {boolean} */ Blockly.Flyout.prototype.autoClose = true; /** * Corner radius of the flyout background. * @type {number} * @const */ Blockly.Flyout.prototype.CORNER_RADIUS = 8; /** * Wrapper function called when a resize occurs. * @type {Array.} * @private */ Blockly.Flyout.prototype.onResizeWrapper_ = null; /** * Creates the flyout's DOM. Only needs to be called once. * @return {!Element} The flyout's SVG group. */ Blockly.Flyout.prototype.createDom = function() { /* */ this.svgGroup_ = Blockly.createSvgElement('g', {}, null); this.svgBackground_ = Blockly.createSvgElement('path', {'class': 'blocklyFlyoutBackground'}, this.svgGroup_); this.svgGroup_.appendChild(this.workspace_.createDom()); return this.svgGroup_; }; /** * Dispose of this flyout. * Unlink from all DOM elements to prevent memory leaks. */ Blockly.Flyout.prototype.dispose = function() { this.hide(); if (this.onResizeWrapper_) { Blockly.unbindEvent_(this.onResizeWrapper_); this.onResizeWrapper_ = null; } if (this.changeWrapper_) { Blockly.unbindEvent_(this.changeWrapper_); this.changeWrapper_ = null; } if (this.scrollbar_) { this.scrollbar_.dispose(); this.scrollbar_ = null; } this.workspace_ = null; if (this.svgGroup_) { goog.dom.removeNode(this.svgGroup_); this.svgGroup_ = null; } this.svgBackground_ = null; this.targetWorkspace_ = null; }; /** * Return an object with all the metrics required to size scrollbars for the * flyout. The following properties are computed: * .viewHeight: Height of the visible rectangle, * .viewWidth: Width of the visible rectangle, * .contentHeight: Height of the contents, * .viewTop: Offset of top edge of visible rectangle from parent, * .contentTop: Offset of the top-most content from the y=0 coordinate, * .absoluteTop: Top-edge of view. * .absoluteLeft: Left-edge of view. * @return {Object} Contains size and position metrics of the flyout. * @private */ Blockly.Flyout.prototype.getMetrics_ = function() { if (!this.isVisible()) { // Flyout is hidden. return null; } var viewHeight = this.height_ - 2 * this.CORNER_RADIUS; var viewWidth = this.width_; try { var optionBox = this.workspace_.getCanvas().getBBox(); } catch (e) { // Firefox has trouble with hidden elements (Bug 528969). var optionBox = {height: 0, y: 0}; } return { viewHeight: viewHeight, viewWidth: viewWidth, contentHeight: optionBox.height + optionBox.y, viewTop: -this.workspace_.scrollY, contentTop: 0, absoluteTop: this.CORNER_RADIUS, absoluteLeft: 0 }; }; /** * Sets the Y translation of the flyout to match the scrollbars. * @param {!Object} yRatio Contains a y property which is a float * between 0 and 1 specifying the degree of scrolling. * @private */ Blockly.Flyout.prototype.setMetrics_ = function(yRatio) { var metrics = this.getMetrics_(); // This is a fix to an apparent race condition. if (!metrics) { return; } if (goog.isNumber(yRatio.y)) { this.workspace_.scrollY = -metrics.contentHeight * yRatio.y - metrics.contentTop; } var y = this.workspace_.scrollY + metrics.absoluteTop; this.workspace_.getCanvas().setAttribute('transform', 'translate(0,' + y + ')'); }; /** * Initializes the flyout. * @param {!Blockly.Workspace} workspace The workspace in which to create new * blocks. * @param {boolean} withScrollbar True if a scrollbar should be displayed. */ Blockly.Flyout.prototype.init = function(workspace, withScrollbar) { this.targetWorkspace_ = workspace; // Add scrollbars. var flyout = this; if (withScrollbar) { this.scrollbar_ = new Blockly.Scrollbar(flyout.workspace_, false, false); } this.hide(); // If the document resizes, reposition the flyout. this.onResizeWrapper_ = Blockly.bindEvent_(window, goog.events.EventType.RESIZE, this, this.position_); this.position_(); this.changeWrapper_ = Blockly.bindEvent_(this.targetWorkspace_.getCanvas(), 'blocklyWorkspaceChange', this, this.filterForCapacity_); }; /** * Move the toolbox to the edge of the workspace. * @private */ Blockly.Flyout.prototype.position_ = function() { if (!this.isVisible()) { return; } var metrics = this.targetWorkspace_.getMetrics(); if (!metrics) { // Hidden components will return null. return; } var edgeWidth = this.width_ - this.CORNER_RADIUS; if (Blockly.RTL) { edgeWidth *= -1; } // var path = ['M ' + (Blockly.RTL ? this.width_ : 0) + ',0']; // path.push('h', edgeWidth); // path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, // Blockly.RTL ? 0 : 1, // Blockly.RTL ? -this.CORNER_RADIUS : this.CORNER_RADIUS, // this.CORNER_RADIUS); // path.push('v', Math.max(0, metrics.viewHeight - this.CORNER_RADIUS * 2)); // path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, // Blockly.RTL ? 0 : 1, // Blockly.RTL ? this.CORNER_RADIUS : -this.CORNER_RADIUS, // this.CORNER_RADIUS); // path.push('h', -edgeWidth); // path.push('z'); var path = ['M ' + (Blockly.RTL ? this.width_ : 0) + ',0']; path.push('h', edgeWidth); path.push('v', Math.max(0, metrics.viewHeight)); path.push('h', -edgeWidth); path.push('z'); this.svgBackground_.setAttribute('d', path.join(' ')); var x = metrics.absoluteLeft; if (Blockly.RTL) { x += metrics.viewWidth; x -= this.width_; } this.svgGroup_.setAttribute('transform', 'translate(' + x + ',' + metrics.absoluteTop + ')'); // Record the height for Blockly.Flyout.getMetrics_. this.height_ = metrics.viewHeight; // Update the scrollbar (if one exists). if (this.scrollbar_) { this.scrollbar_.resize(); } }; /** * Is the flyout visible? * @return {boolean} True if visible. */ Blockly.Flyout.prototype.isVisible = function() { return this.svgGroup_.style.display == 'block'; }; /** * Hide and empty the flyout. */ Blockly.Flyout.prototype.hide = function() { if (!this.isVisible()) { return; } this.svgGroup_.style.display = 'none'; // Delete all the event listeners. for (var x = 0, listen; listen = this.listeners_[x]; x++) { Blockly.unbindEvent_(listen); } this.listeners_.splice(0); if (this.reflowWrapper_) { Blockly.unbindEvent_(this.reflowWrapper_); this.reflowWrapper_ = null; } }; /** * Show and populate the flyout. * @param {!Array|string} xmlList List of blocks to show. * Variables and procedures have a custom set of blocks. */ Blockly.Flyout.prototype.show = function(xmlList) { this.hide(); var blocks = this.workspace_.getTopBlocks(false); for (var x = 0, block; block = blocks[x]; x++) { if (block.workspace == this.workspace_) { block.dispose(false, false); } } // Delete all the blocks. // Delete all the background buttons. for (var x = 0, rect; rect = this.buttons_[x]; x++) { goog.dom.removeNode(rect); } this.buttons_.splice(0); var margin = this.CORNER_RADIUS; this.svgGroup_.style.display = 'block'; // Create the blocks to be shown in this flyout. var blocks = []; var gaps = []; if (xmlList == Blockly.Variables.NAME_TYPE) { // Special category for variables. Blockly.Variables.flyoutCategory(blocks, gaps, margin, /** @type {!Blockly.Workspace} */ (this.workspace_)); } else if (xmlList == Blockly.Procedures.NAME_TYPE) { // Special category for procedures. Blockly.Procedures.flyoutCategory(blocks, gaps, margin, /** @type {!Blockly.Workspace} */ (this.workspace_)); } else { for (var i = 0, xml; xml = xmlList[i]; i++) { if (xml.tagName && xml.tagName.toUpperCase() == 'BLOCK') { var block = Blockly.Xml.domToBlock( /** @type {!Blockly.Workspace} */ (this.workspace_), xml); blocks.push(block); gaps.push(margin); } } } // Lay out the blocks vertically. var cursorY = margin; for (var i = 0, block; block = blocks[i]; i++) { var allBlocks = block.getDescendants(); for (var j = 0, child; child = allBlocks[j]; j++) { // Mark blocks as being inside a flyout. This is used to detect and // prevent the closure of the flyout if the user right-clicks on such a // block. child.isInFlyout = true; // There is no good way to handle comment bubbles inside the flyout. // Blocks shouldn't come with predefined comments, but someone will // try this, I'm sure. Kill the comment. Blockly.Comment && child.setCommentText(null); } block.render(); var root = block.getSvgRoot(); var blockHW = block.getHeightWidth(); var x = Blockly.RTL ? 0 : margin + Blockly.BlockSvg.TAB_WIDTH * 0.5; if (block.outputConnection) x += blockHW.height/2; else if (!block.previousConnection && block.nextConnection) x += 10; block.moveBy(x, cursorY); cursorY += blockHW.height + gaps[i]; // Create an invisible rectangle under the block to act as a button. Just // using the block as a button is poor, since blocks have holes in them. var rect = Blockly.createSvgElement('rect', {'fill-opacity': 0}, null); // Add the rectangles under the blocks, so that the blocks' tooltips work. this.workspace_.getCanvas().insertBefore(rect, block.getSvgRoot()); block.flyoutRect_ = rect; this.buttons_[i] = rect; if (this.autoClose && block.isAddable()) { this.listeners_.push(Blockly.bindEvent_(root, 'mousedown', null, this.createBlockFunc_(block))); } else if (block.isAddable()) { this.listeners_.push(Blockly.bindEvent_(root, 'mousedown', null, this.blockMouseDown_(block))); } this.listeners_.push(Blockly.bindEvent_(root, 'mouseover', block.svg_, block.svg_.addSelect)); this.listeners_.push(Blockly.bindEvent_(root, 'mouseout', block.svg_, block.svg_.removeSelect)); this.listeners_.push(Blockly.bindEvent_(rect, 'mousedown', null, this.createBlockFunc_(block))); this.listeners_.push(Blockly.bindEvent_(rect, 'mouseover', block.svg_, block.svg_.addSelect)); this.listeners_.push(Blockly.bindEvent_(rect, 'mouseout', block.svg_, block.svg_.removeSelect)); } this.width_ = 0; this.reflow(); this.filterForCapacity_(); // Fire a resize event to update the flyout's scrollbar. Blockly.fireUiEvent(window, 'resize'); this.reflowWrapper_ = Blockly.bindEvent_(this.workspace_.getCanvas(), 'blocklyWorkspaceChange', this, this.reflow); this.workspace_.fireChangeEvent(); }; /** * Compute width of flyout. Position button under each block. * For RTL: Lay out the blocks right-aligned. */ Blockly.Flyout.prototype.reflow = function() { var flyoutWidth = 0; var margin = this.CORNER_RADIUS; var blocks = this.workspace_.getTopBlocks(false); for (var x = 0, block; block = blocks[x]; x++) { var root = block.getSvgRoot(); var blockHW = block.getHeightWidth(); flyoutWidth = Math.max(flyoutWidth, blockHW.width); } flyoutWidth += margin + Blockly.BlockSvg.TAB_WIDTH + margin / 2 + Blockly.Scrollbar.scrollbarThickness; if (this.width_ != flyoutWidth) { for (var x = 0, block; block = blocks[x]; x++) { var blockHW = block.getHeightWidth(); var blockXY = block.getRelativeToSurfaceXY(); if (Blockly.RTL) { // With the flyoutWidth known, right-align the blocks. var dx = flyoutWidth - margin - Blockly.BlockSvg.TAB_WIDTH - blockXY.x; block.moveBy(dx, 0); blockXY.x += dx; } if (block.flyoutRect_) { block.flyoutRect_.setAttribute('width', blockHW.width); block.flyoutRect_.setAttribute('height', blockHW.height); block.flyoutRect_.setAttribute('x', Blockly.RTL ? blockXY.x - blockHW.width : blockXY.x); block.flyoutRect_.setAttribute('y', blockXY.y); } } // Record the width for .getMetrics_ and .position_. this.width_ = flyoutWidth; // Fire a resize event to update the flyout's scrollbar. Blockly.fireUiEvent(window, 'resize'); } }; /** * Move a block to a specific location on the drawing surface. * @param {number} dx Horizontal location. * @param {number} dy Vertical location. */ Blockly.Block.prototype.moveTo = function(x, y) { var oldXY = this.getRelativeToSurfaceXY(); this.svg_.getRootElement().setAttribute('transform', 'translate(' + x + ', ' + y + ')'); this.moveConnections_(x - oldXY.x, y - oldXY.y); }; /** * Handle a mouse-down on an SVG block in a non-closing flyout. * @param {!Blockly.Block} originBlock The flyout block to copy. * @return {!Function} Function to call when block is clicked. * @private */ Blockly.Flyout.prototype.blockMouseDown_ = function(block) { var flyout = this; return function(e) { Blockly.terminateDrag_(); Blockly.hideChaff(); if (Blockly.isRightButton(e)) { // Right-click. if (Blockly.ContextMenu) { block.showContextMenu_(Blockly.mouseToSvg(e)); } } else { // Left-click (or middle click) Blockly.removeAllRanges(); Blockly.setCursorHand_(true); // Record the current mouse position. Blockly.Flyout.startDownEvent_ = e; Blockly.Flyout.startBlock_ = block; Blockly.Flyout.startFlyout_ = flyout; Blockly.Flyout.onMouseUpWrapper_ = Blockly.bindEvent_(document, 'mouseup', this, Blockly.terminateDrag_); Blockly.Flyout.onMouseMoveWrapper_ = Blockly.bindEvent_(document, 'mousemove', this, flyout.onMouseMove_); } // This event has been handled. No need to bubble up to the document. e.stopPropagation(); }; }; /** * Mouse button is down on a block in a non-closing flyout. Create the block * if the mouse moves beyond a small radius. This allows one to play with * fields without instantiating blocks that instantly self-destruct. * @param {!Event} e Mouse move event. * @private */ Blockly.Flyout.prototype.onMouseMove_ = function(e) { if (e.type == 'mousemove' && e.clientX <= 1 && e.clientY == 0 && e.button == 0) { /* HACK: Safari Mobile 6.0 and Chrome for Android 18.0 fire rogue mousemove events on certain touch actions. Ignore events with these signatures. This may result in a one-pixel blind spot in other browsers, but this shouldn't be noticable. */ e.stopPropagation(); return; } Blockly.removeAllRanges(); var dx = e.clientX - Blockly.Flyout.startDownEvent_.clientX; var dy = e.clientY - Blockly.Flyout.startDownEvent_.clientY; // Still dragging within the sticky DRAG_RADIUS. var dr = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); if (dr > Blockly.DRAG_RADIUS) { // Create the block. Blockly.Flyout.startFlyout_.createBlockFunc_(Blockly.Flyout.startBlock_) (Blockly.Flyout.startDownEvent_); } }; /** * Create a copy of this block on the workspace. * @param {!Blockly.Block} originBlock The flyout block to copy. * @return {!Function} Function to call when block is clicked. * @private */ Blockly.Flyout.prototype.createBlockFunc_ = function(originBlock) { var flyout = this; return function(e) { if (Blockly.isRightButton(e)) { // Right-click. Don't create a block, let the context menu show. return; } if (originBlock.disabled) { // Beyond capacity. return; } // Create the new block by cloning the block in the flyout (via XML). if (typeof(Entry) == "object") { Entry.dispatchEvent("entryBlocklyChanged"); } var xml = Blockly.Xml.blockToDom_(originBlock); var block = Blockly.Xml.domToBlock(flyout.targetWorkspace_, xml); // Place it in the same spot as the flyout copy. var svgRootOld = originBlock.getSvgRoot(); if (!svgRootOld) { throw 'originBlock is not rendered.'; } var xyOld = Blockly.getSvgXY_(svgRootOld); var svgRootNew = block.getSvgRoot(); if (!svgRootNew) { throw 'block is not rendered.'; } var xyNew = Blockly.getSvgXY_(svgRootNew); block.moveBy(xyOld.x - xyNew.x, xyOld.y - xyNew.y); if (flyout.autoClose) { flyout.hide(); } else { flyout.filterForCapacity_(); } // Start a dragging operation on the new block. block.onMouseDown_(e); }; }; /** * Filter the blocks on the flyout to disable the ones that are above the * capacity limit. * @private */ Blockly.Flyout.prototype.filterForCapacity_ = function() { var remainingCapacity = this.targetWorkspace_.remainingCapacity(); var blocks = this.workspace_.getTopBlocks(false); for (var i = 0, block; block = blocks[i]; i++) { var allBlocks = block.getDescendants(); var disabled = allBlocks.length > remainingCapacity; block.setDisabled(disabled); } }; /** * Stop binding to the global mouseup and mousemove events. * @private */ Blockly.Flyout.terminateDrag_ = function() { if (Blockly.Flyout.onMouseUpWrapper_) { Blockly.unbindEvent_(Blockly.Flyout.onMouseUpWrapper_); Blockly.Flyout.onMouseUpWrapper_ = null; } if (Blockly.Flyout.onMouseMoveWrapper_) { Blockly.unbindEvent_(Blockly.Flyout.onMouseMoveWrapper_); Blockly.Flyout.onMouseMoveWrapper_ = null; } Blockly.Flyout.startDownEvent_ = null; Blockly.Flyout.startBlock_ = null; Blockly.Flyout.startFlyout_ = null; }; ================================================ FILE: extern/blockly/core/generator.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Utility functions for generating executable code from * Blockly code. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Generator'); goog.require('Blockly.Block'); /** * Class for a code generator that translates the blocks into a language. * @param {string} name Language name of this generator. * @constructor */ Blockly.Generator = function(name) { this.name_ = name; this.RESERVED_WORDS_ = ''; }; /** * Category to separate generated function names from variables and procedures. */ Blockly.Generator.NAME_TYPE = 'generated_function'; /** * Generate code for all blocks in the workspace to the specified language. * @return {string} Generated code. */ Blockly.Generator.prototype.workspaceToCode = function() { var code = []; this.init(); var blocks = Blockly.mainWorkspace.getTopBlocks(true); for (var x = 0, block; block = blocks[x]; x++) { var line = this.blockToCode(block); if (line instanceof Array) { // Value blocks return tuples of code and operator order. // Top-level blocks don't care about operator order. line = line[0]; } if (line) { if (block.outputConnection && this.scrubNakedValue) { // This block is a naked value. Ask the language's code generator if // it wants to append a semicolon, or something. line = this.scrubNakedValue(line); } code.push(line); } } code = code.join('\n'); // Blank line between each section. code = this.finish(code); // Final scrubbing of whitespace. code = code.replace(/^\s+\n/, ''); code = code.replace(/\n\s+$/, '\n'); code = code.replace(/[ \t]+\n/g, '\n'); return code; }; /** * Generate code for all blocks in the tutorial workspace only attached to 'when_start' to the specified language. * @return {string} Generated code. */ Blockly.Generator.prototype.tutorialWorkspaceToCode = function() { var code = []; this.init(); var blocks = Blockly.mainWorkspace.getTopBlocks(true); var targetBlocks = []; for (var i=0; i */ this.iconGroup_ = Blockly.createSvgElement('g', {}, null); this.block_.getSvgRoot().appendChild(this.iconGroup_); Blockly.bindEvent_(this.iconGroup_, 'mouseup', this, this.iconClick_); this.updateEditable(); }; /** * Dispose of this icon. */ Blockly.Icon.prototype.dispose = function() { // Dispose of and unlink the icon. goog.dom.removeNode(this.iconGroup_); this.iconGroup_ = null; // Dispose of and unlink the bubble. this.setVisible(false); this.block_ = null; }; /** * Add or remove the UI indicating if this icon may be clicked or not. */ Blockly.Icon.prototype.updateEditable = function() { if (!this.block_.isInFlyout) { Blockly.addClass_(/** @type {!Element} */ (this.iconGroup_), 'blocklyIconGroup'); } else { Blockly.removeClass_(/** @type {!Element} */ (this.iconGroup_), 'blocklyIconGroup'); } }; /** * Is the associated bubble visible? * @return {boolean} True if the bubble is visible. */ Blockly.Icon.prototype.isVisible = function() { return !!this.bubble_; }; /** * Clicking on the icon toggles if the bubble is visible. * @param {!Event} e Mouse click event. * @private */ Blockly.Icon.prototype.iconClick_ = function(e) { if (!this.block_.isInFlyout) { this.setVisible(!this.isVisible()); } }; /** * Change the colour of the associated bubble to match its block. */ Blockly.Icon.prototype.updateColour = function() { if (this.isVisible()) { var hexColour = Blockly.makeColour(this.block_.getColour()); this.bubble_.setColour(hexColour); } }; /** * Render the icon. * @param {number} cursorX Horizontal offset at which to position the icon. * @return {number} Horizontal offset for next item to draw. */ Blockly.Icon.prototype.renderIcon = function(cursorX) { if (this.block_.isCollapsed()) { this.iconGroup_.setAttribute('display', 'none'); return cursorX; } this.iconGroup_.setAttribute('display', 'block'); var TOP_MARGIN = 5; var diameter = 2 * Blockly.Icon.RADIUS; if (Blockly.RTL) { cursorX -= diameter; } this.iconGroup_.setAttribute('transform', 'translate(' + cursorX + ', ' + TOP_MARGIN + ')'); this.computeIconLocation(); if (Blockly.RTL) { cursorX -= Blockly.BlockSvg.SEP_SPACE_X; } else { cursorX += diameter + Blockly.BlockSvg.SEP_SPACE_X; } return cursorX; }; /** * Notification that the icon has moved. Update the arrow accordingly. * @param {number} x Absolute horizontal location. * @param {number} y Absolute vertical location. */ Blockly.Icon.prototype.setIconLocation = function(x, y) { this.iconX_ = x; this.iconY_ = y; if (this.isVisible()) { this.bubble_.setAnchorLocation(x, y); } }; /** * Notification that the icon has moved, but we don't really know where. * Recompute the icon's location from scratch. */ Blockly.Icon.prototype.computeIconLocation = function() { // Find coordinates for the centre of the icon and update the arrow. var blockXY = this.block_.getRelativeToSurfaceXY(); var iconXY = Blockly.getRelativeXY_(this.iconGroup_); var newX = blockXY.x + iconXY.x + Blockly.Icon.RADIUS; var newY = blockXY.y + iconXY.y + Blockly.Icon.RADIUS; if (newX !== this.iconX_ || newY !== this.iconY_) { this.setIconLocation(newX, newY); } }; /** * Returns the center of the block's icon relative to the surface. * @return {!Object} Object with x and y properties. */ Blockly.Icon.prototype.getIconLocation = function() { return {x: this.iconX_, y: this.iconY_}; }; ================================================ FILE: extern/blockly/core/inject.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Functions for injecting Blockly into a web page. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.inject'); goog.require('Blockly.Css'); goog.require('goog.dom'); /** * Initialize the SVG document with various handlers. * @param {!Element} container Containing element. * @param {Object} opt_options Optional dictionary of options. */ Blockly.inject = function(container, opt_options) { // Verify that the container is in document. if (!goog.dom.contains(document, container)) { throw 'Error: container is not in current document.'; } if (opt_options) { // TODO(scr): don't mix this in to global variables. goog.mixin(Blockly, Blockly.parseOptions_(opt_options)); } Blockly.createDom_(container); Blockly.init_(); }; /** * Configure Blockly to behave according to a set of options. * @param {!Object} options Dictionary of options. * @return {Object} Parsed options. * @private */ Blockly.parseOptions_ = function(options) { var readOnly = !!options['readOnly']; if (readOnly) { var hasCategories = false; var hasTrashcan = false; var hasCollapse = false; var tree = null; } else { var tree = options['toolbox']; if (tree) { if (typeof tree != 'string' && typeof XSLTProcessor == 'undefined') { // In this case the tree will not have been properly built by the // browser. The HTML will be contained in the element, but it will // not have the proper DOM structure since the browser doesn't support // XSLTProcessor (XML -> HTML). This is the case in IE 9+. tree = tree.outerHTML; } if (typeof tree == 'string') { tree = Blockly.Xml.textToDom(tree); } //var hasCategories = !!tree.getElementsByTagName('category').length; var hasCategories = false; try { hasCategories = !!tree.getElementsByTagName('category').length; } catch (err) { hasCategories = false; } } else { tree = null; var hasCategories = false; } var hasTrashcan = options['trashcan']; if (hasTrashcan === undefined) { hasTrashcan = hasCategories; } var hasBlockMenu = options['blockmenu']; if (!hasBlockMenu instanceof HTMLElement) { hasBlockMenu = false; } var hasCollapse = options['collapse']; if (hasCollapse === undefined) { hasCollapse = hasCategories; } } var hasScrollbars = options['scrollbars']; if (hasScrollbars === undefined) { hasScrollbars = true; } return { RTL: !!options['rtl'], collapse: hasCollapse, readOnly: readOnly, maxBlocks: options['maxBlocks'] || Infinity, pathToBlockly: options['path'] || './', hasCategories: hasCategories, hasScrollbars: hasScrollbars, hasTrashcan: hasTrashcan, hasBlockMenu: hasBlockMenu, languageTree: tree, mediaFilePath: options['mediaFilePath'] || './', }; }; /** * Create the SVG image. * @param {!Element} container Containing element. * @private */ Blockly.createDom_ = function(container) { // Sadly browsers (Chrome vs Firefox) are currently inconsistent in laying // out content in RTL mode. Therefore Blockly forces the use of LTR, // then manually positions content in RTL as needed. container.setAttribute('dir', 'LTR'); // Closure can be trusted to create HTML widgets with the proper direction. goog.ui.Component.setDefaultRightToLeft(Blockly.RTL); // Load CSS. Blockly.Css.inject(); // Build the SVG DOM. /* ... */ var svg = Blockly.createSvgElement( 'svg', { xmlns: 'http://www.w3.org/2000/svg', 'xmlns:html': 'http://www.w3.org/1999/xhtml', 'xmlns:xlink': 'http://www.w3.org/1999/xlink', version: '1.1', class: 'blocklySvg', }, null ); /* ... filters go here ... */ var defs = Blockly.createSvgElement('defs', {}, svg); var filter, feSpecularLighting, feMerge, pattern, blockPattern, blockImg; /* */ filter = Blockly.createSvgElement('filter', { id: 'blocklyEmboss' }, defs); Blockly.createSvgElement( 'feGaussianBlur', { in: 'SourceAlpha', stdDeviation: 1, result: 'blur' }, filter ); feSpecularLighting = Blockly.createSvgElement( 'feSpecularLighting', { in: 'blur', surfaceScale: 1, specularConstant: 0.5, specularExponent: 10, 'lighting-color': 'white', result: 'specOut', }, filter ); Blockly.createSvgElement('fePointLight', { x: -5000, y: -10000, z: 20000 }, feSpecularLighting); Blockly.createSvgElement( 'feComposite', { in: 'specOut', in2: 'SourceAlpha', operator: 'in', result: 'specOut', }, filter ); Blockly.createSvgElement( 'feComposite', { in: 'SourceGraphic', in2: 'specOut', operator: 'arithmetic', k1: 0, k2: 1, k3: 1, k4: 0, }, filter ); /* */ filter = Blockly.createSvgElement('filter', { id: 'blocklyTrashcanShadowFilter' }, defs); Blockly.createSvgElement( 'feGaussianBlur', { in: 'SourceAlpha', stdDeviation: 2, result: 'blur' }, filter ); Blockly.createSvgElement( 'feOffset', { in: 'blur', dx: 1, dy: 1, result: 'offsetBlur' }, filter ); feMerge = Blockly.createSvgElement('feMerge', {}, filter); Blockly.createSvgElement('feMergeNode', { in: 'offsetBlur' }, feMerge); Blockly.createSvgElement('feMergeNode', { in: 'SourceGraphic' }, feMerge); /* */ filter = Blockly.createSvgElement('filter', { id: 'blocklyShadowFilter' }, defs); Blockly.createSvgElement('feGaussianBlur', { stdDeviation: 2 }, filter); /* */ pattern = Blockly.createSvgElement( 'pattern', { id: 'blocklyDisabledPattern', patternUnits: 'userSpaceOnUse', width: 10, height: 10, }, defs ); Blockly.createSvgElement('rect', { width: 10, height: 10, fill: '#aaa' }, pattern); Blockly.createSvgElement('path', { d: 'M 0 0 L 10 10 M 10 0 L 0 10', stroke: '#cc0' }, pattern); for (var i = 1; i < 5; i++) { blockPattern = Blockly.createSvgElement( 'pattern', { id: 'blockPattern' + i, patternUnits: 'userSpaceOnUse', width: 125, height: 33, x: 0, y: 0, }, defs ); blockImg = Blockly.createSvgElement( 'image', { width: 125, height: 33, x: 0, y: 0, }, blockPattern ); blockImg.setAttributeNS( 'http://www.w3.org/1999/xlink', 'xlink:href', Blockly.mediaFilePath + 'block_pattern_' + i + '.png' ); } Blockly.mainWorkspace = new Blockly.Workspace( Blockly.getMainWorkspaceMetrics_, Blockly.setMainWorkspaceMetrics_ ); svg.appendChild(Blockly.mainWorkspace.createDom()); Blockly.mainWorkspace.maxBlocks = Blockly.maxBlocks; if (!Blockly.readOnly) { // Determine if there needs to be a category tree, or a simple list of // blocks. This cannot be changed later, since the UI is very different. if (Blockly.hasCategories) { Blockly.Toolbox.createDom(svg, container); } else { if (Blockly.hasBlockMenu) { var blockMenu = new Blockly.BlockMenu(Blockly.hasBlockMenu); Blockly.mainWorkspace.blockMenu = blockMenu; Blockly.bindEvent_( blockMenu.menuView_, 'wheel', blockMenu, Blockly.onMouseWheelFlyout_ ); //Blockly.bindEvent_(blockMenu.workspace_.svgGroup_, 'wheel', blockMenu, Blockly.onMouseWheelFlyout_); } /** * @type {!Blockly.Flyout} * @private */ Blockly.mainWorkspace.flyout_ = new Blockly.Flyout(); var flyout = Blockly.mainWorkspace.flyout_; var flyoutSvg = flyout.createDom(); flyout.init(Blockly.mainWorkspace, true); Blockly.bindEvent_(flyoutSvg, 'wheel', flyout, Blockly.onMouseWheelFlyout_); flyout.autoClose = false; // Insert the flyout behind the workspace so that blocks appear on top. goog.dom.insertSiblingAfter(flyoutSvg, Blockly.mainWorkspace.svgGroup_); var workspaceChanged = function() { /* * prevent unintended block moving by scrolls */ //if (Blockly.Block.dragMode_ == 0) { //var metrics = Blockly.mainWorkspace.getMetrics(); //if (metrics.contentTop < 0 || //metrics.contentTop + metrics.contentHeight > //metrics.viewHeight + metrics.viewTop || //metrics.contentLeft < (Blockly.RTL ? metrics.viewLeft : 0) || //metrics.contentLeft + metrics.contentWidth > //metrics.viewWidth + (Blockly.RTL ? 2 : 1) * metrics.viewLeft) { //// One or more blocks is out of bounds. Bump them back in. //var MARGIN = 25; //var blocks = Blockly.mainWorkspace.getTopBlocks(false); //for (var b = 0, block; block = blocks[b]; b++) { //var blockXY = block.getRelativeToSurfaceXY(); //var blockHW = block.getHeightWidth(); //// Bump any block that's above the top back inside. //var overflow = metrics.viewTop + MARGIN - blockHW.height - //blockXY.y; //if (overflow > 0) { //block.moveBy(0, overflow); //} //// Bump any block that's below the bottom back inside. //var overflow = metrics.viewTop + metrics.viewHeight - MARGIN - //blockXY.y; //if (overflow < 0) { //block.moveBy(0, overflow); //} //// Bump any block that's off the left back inside. //var overflow = MARGIN + metrics.viewLeft - blockXY.x - //(Blockly.RTL ? 0 : blockHW.width); //if (overflow > 0) { //block.moveBy(overflow, 0); //} //// Bump any block that's off the right back inside. //var overflow = metrics.viewLeft + metrics.viewWidth - MARGIN - //blockXY.x + (Blockly.RTL ? blockHW.width : 0); //if (overflow < 0) { //block.moveBy(overflow, 0); //} //// Delete any block that's sitting on top of the flyout. //if (typeof(Entry) == "object" && block.isDeletable() && (Blockly.RTL ? //blockXY.x - 2 * metrics.viewLeft - metrics.viewWidth : //-blockXY.x) > + Blockly.mainWorkspace.scrollX) { ////block.dispose(false, true); //} //if (typeof(Entry) != "object" && block.isDeletable() && (Blockly.RTL ? //blockXY.x - 2 * metrics.viewLeft - metrics.viewWidth : //-blockXY.x) > + Blockly.mainWorkspace.scrollX - 150) { ////block.dispose(false, true); //} //} //} //} }; Blockly.addChangeListener(workspaceChanged); } } Blockly.Tooltip && svg.appendChild(Blockly.Tooltip.createDom()); if (!Blockly.readOnly && Blockly.FieldDropdown) { Blockly.fieldDropdownDom = Blockly.FieldDropdown.createDom(); svg.appendChild(Blockly.fieldDropdownDom); } if (!Blockly.readOnly && Blockly.FieldKeydownInput) { Blockly.fieldKeydownDom = Blockly.FieldKeydownInput.createDom(); svg.appendChild(Blockly.fieldKeydownDom); } if (Blockly.ContextMenu && Blockly.ContextMenu) { svg.appendChild(Blockly.ContextMenu.createDom()); } // The SVG is now fully assembled. Add it to the container. container.appendChild(svg); Blockly.bindEvent_(svg, 'mousedown', this, Blockly.hideChaff); //if (typeof(Entry) == "object") //Blockly.bindEvent_(svg, 'mousedown', this, Entry.stopInstantRun); Blockly.bindEvent_(svg, 'wheel', this, Blockly.onMouseWheel_); Blockly.svg = svg; Blockly.svgResize(); // Create an HTML container for popup overlays (e.g. editor widgets). Blockly.WidgetDiv.DIV = goog.dom.createDom('div', 'blocklyWidgetDiv'); document.body.appendChild(Blockly.WidgetDiv.DIV); }; /** * Initialize Blockly with various handlers. * @private */ Blockly.init_ = function() { if (goog.userAgent.WEBKIT) { /* HACK: WebKit bug 67298 causes control points to be included in the reported bounding box. Detect if this browser suffers from this bug by drawing a shape that is 50px high, and has a control point that sticks up by 5px. If the getBBox function returns a height of 55px instead of 50px, then this browser has broken control points. */ var path = Blockly.createSvgElement( 'path', { d: 'm 0,0 c 0,-5 0,-5 0,0 H 50 V 50 z' }, Blockly.svg ); if (path.getBBox().height > 50) { // Chrome (v28) and Opera (v15) report 55, Safari (v6.0.5) reports 53.75. Blockly.BROKEN_CONTROL_POINTS = true; } Blockly.svg.removeChild(path); } // Bind events for scrolling the workspace. // Most of these events should be bound to the SVG's surface. // However, 'mouseup' has to be on the whole document so that a block dragged // out of bounds and released will know that it has been released. // Also, 'keydown' has to be on the whole document since the browser doesn't // understand a concept of focus on the SVG image. Blockly.bindEvent_(Blockly.svg, 'mousedown', null, Blockly.onMouseDown_); Blockly.bindEvent_(Blockly.svg, 'mousemove', null, Blockly.onMouseMove_); Blockly.bindEvent_(Blockly.svg, 'contextmenu', null, Blockly.onContextMenu_); if (!Blockly.documentEventsBound_) { // Only bind the window/document events once. // Destroying and reinjecting Blockly should not bind again. Blockly.bindEvent_(window, 'resize', document, Blockly.svgResize); Blockly.bindEvent_(document, 'mouseup', null, Blockly.onMouseUp_); Blockly.bindEvent_(document, 'keydown', null, Blockly.onKeyDown_); // Some iPad versions don't fire resize after portrait to landscape change. if (goog.userAgent.IPAD) { Blockly.bindEvent_( window, 'orientationchange', document, function() { Blockly.fireUiEvent(window, 'resize'); }, false ); } Blockly.documentEventsBound_ = true; } if (Blockly.languageTree) { if (Blockly.hasCategories) { Blockly.Toolbox.init(); } else { // Build a fixed flyout with the root blocks. Blockly.mainWorkspace.flyout_.init(Blockly.mainWorkspace, true); Blockly.mainWorkspace.flyout_.show(Blockly.languageTree.childNodes); // Translate the workspace sideways to avoid the fixed flyout. Blockly.mainWorkspace.scrollX = Blockly.mainWorkspace.flyout_.width_; var translation = 'translate(' + Blockly.mainWorkspace.scrollX + ', 0)'; Blockly.mainWorkspace.getCanvas().setAttribute('transform', translation); Blockly.mainWorkspace.getBubbleCanvas().setAttribute('transform', translation); } } if (Blockly.hasScrollbars) { Blockly.mainWorkspace.scrollbar = new Blockly.ScrollbarPair(Blockly.mainWorkspace); Blockly.mainWorkspace.scrollbar.resize(); } //Blockly.mainWorkspace.addConnectionAnimation(); Blockly.mainWorkspace.addTrashcan(); // Load the sounds. /* Blockly.loadAudio_( ['media/click.mp3', 'media/click.wav', 'media/click.ogg'], 'click'); Blockly.loadAudio_( ['media/delete.mp3', 'media/delete.ogg', 'media/delete.wav'], 'delete'); */ }; ================================================ FILE: extern/blockly/core/input.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Object representing an input (value, statement, or dummy). * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Input'); // TODO(scr): Fix circular dependencies // goog.require('Blockly.Block'); goog.require('Blockly.Connection'); goog.require('Blockly.FieldLabel'); goog.require('goog.asserts'); /** * Class for an input with an optional field. * @param {number} type The type of the input. * @param {string} name Language-neutral identifier which may used to find this * input again. * @param {!Blockly.Block} block The block containing this input. * @param {Blockly.Connection} connection Optional connection for this input. * @constructor */ Blockly.Input = function(type, name, block, connection) { this.type = type; this.name = name; this.sourceBlock_ = block; this.connection = connection; this.fieldRow = []; this.align = Blockly.ALIGN_LEFT; this.visible_ = true; }; /** * Add an item to the end of the input's field row. * @param {string|!Blockly.Field} field Something to add as a field. * @param {string} opt_name Language-neutral identifier which may used to find * this field again. Should be unique to the host block. * @return {!Blockly.Input} The input being append to (to allow chaining). */ Blockly.Input.prototype.appendField = function(field, opt_name) { // Empty string, Null or undefined generates no field, unless field is named. if (!field && !opt_name) { return this; } // Generate a FieldLabel when given a plain text field. if (goog.isString(field)) { field = new Blockly.FieldLabel(/** @type {string} */ (field), opt_name); } if (this.sourceBlock_.svg_) { field.init(this.sourceBlock_); } field.name = opt_name; if (field.prefixField) { // Add any prefix. this.appendField(field.prefixField); } // Add the field to the field row. this.fieldRow.push(field); if (field.suffixField) { // Add any suffix. this.appendField(field.suffixField); } if (this.sourceBlock_.rendered) { this.sourceBlock_.render(); // Adding a field will cause the block to change shape. this.sourceBlock_.bumpNeighbours_(); } return this; }; /** * Add an item to the end of the input's field row. * @param {*} field Something to add as a field. * @param {string} opt_name Language-neutral identifier which may used to find * this field again. Should be unique to the host block. * @return {!Blockly.Input} The input being append to (to allow chaining). * @deprecated December 2013 */ Blockly.Input.prototype.appendTitle = function(field, opt_name) { console.log('Deprecated call to appendTitle, use appendField instead.'); return this.appendField(field, opt_name); }; /** * Remove a field from this input. * @param {string} name The name of the field. * @throws {goog.asserts.AssertionError} if the field is not present. */ Blockly.Input.prototype.removeField = function(name) { for (var i = 0, field; field = this.fieldRow[i]; i++) { if (field.name === name) { field.dispose(); this.fieldRow.splice(i, 1); if (this.sourceBlock_.rendered) { this.sourceBlock_.render(); // Removing a field will cause the block to change shape. this.sourceBlock_.bumpNeighbours_(); } return; } } goog.asserts.fail('Field "%s" not found.', name); }; /** * Gets whether this input is visible or not. * @return {boolean} True if visible. */ Blockly.Input.prototype.isVisible = function() { return this.visible_; }; /** * Sets whether this input is visible or not. * @param {boolean} visible True if visible. * @return {!Array.} List of blocks to render. */ Blockly.Input.prototype.setVisible = function(visible) { var renderList = []; if (this.visible_ == visible) { return renderList; } this.visible_ = visible; var display = visible ? 'block' : 'none'; for (var y = 0, field; field = this.fieldRow[y]; y++) { field.setVisible(visible); } if (this.connection) { // Has a connection. if (visible) { renderList = this.connection.unhideAll(); } else { renderList = this.connection.hideAll(); } var child = this.connection.targetBlock(); if (child) { child.svg_.getRootElement().style.display = display; if (!visible) { child.rendered = false; } } } return renderList; }; /** * Change a connection's compatibility. * @param {string|Array.|null} check Compatible value type or * list of value types. Null if all types are compatible. * @return {!Blockly.Input} The input being modified (to allow chaining). */ Blockly.Input.prototype.setCheck = function(check) { if (!this.connection) { throw 'This input does not have a connection.'; } this.connection.setCheck(check); return this; }; /** * Change the alignment of the connection's field(s). * @param {number} align One of Blockly.ALIGN_LEFT, ALIGN_CENTRE, ALIGN_RIGHT. * In RTL mode directions are reversed, and ALIGN_RIGHT aligns to the left. * @return {!Blockly.Input} The input being modified (to allow chaining). */ Blockly.Input.prototype.setAlign = function(align) { this.align = align; if (this.sourceBlock_.rendered) { this.sourceBlock_.render(); } return this; }; /** * Initialize the fields on this input. */ Blockly.Input.prototype.init = function() { for (var x = 0; x < this.fieldRow.length; x++) { this.fieldRow[x].init(this.sourceBlock_); } }; /** * Sever all links to this input. */ Blockly.Input.prototype.dispose = function() { for (var i = 0, field; field = this.fieldRow[i]; i++) { field.dispose(); } if (this.connection) { this.connection.dispose(); } this.sourceBlock_ = null; }; ================================================ FILE: extern/blockly/core/msg.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2013 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Core JavaScript library for Blockly. * @author scr@google.com (Sheridan Rawlins) */ 'use strict'; /** * Name space for the Msg singleton. * Msg gets populated in the message files. */ goog.provide('Blockly.Msg'); ================================================ FILE: extern/blockly/core/mutator.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Object representing a mutator dialog. A mutator allows the * user to change the shape of a block using a nested blocks editor. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Mutator'); goog.require('Blockly.Bubble'); goog.require('Blockly.Icon'); /** * Class for a mutator dialog. * @param {!Array.} quarkNames List of names of sub-blocks for flyout. * @extends {Blockly.Icon} * @constructor */ Blockly.Mutator = function(quarkNames) { Blockly.Mutator.superClass_.constructor.call(this, null); this.quarkXml_ = []; // Convert the list of names into a list of XML objects for the flyout. for (var x = 0; x < quarkNames.length; x++) { var element = goog.dom.createDom('block', {'type': quarkNames[x]}); this.quarkXml_[x] = element; } }; goog.inherits(Blockly.Mutator, Blockly.Icon); /** * Width of workspace. * @private */ Blockly.Mutator.prototype.workspaceWidth_ = 0; /** * Height of workspace. * @private */ Blockly.Mutator.prototype.workspaceHeight_ = 0; /** * Create the icon on the block. */ Blockly.Mutator.prototype.createIcon = function() { Blockly.Icon.prototype.createIcon_.call(this); /* Here's the markup that will be generated: */ var quantum = Blockly.Icon.RADIUS / 2; var iconShield = Blockly.createSvgElement('rect', {'class': 'blocklyIconShield', 'width': 4 * quantum, 'height': 4 * quantum, 'rx': quantum, 'ry': quantum}, this.iconGroup_); this.iconMark_ = Blockly.createSvgElement('text', {'class': 'blocklyIconMark', 'x': Blockly.Icon.RADIUS, 'y': 2 * Blockly.Icon.RADIUS - 4}, this.iconGroup_); this.iconMark_.appendChild(document.createTextNode('\u2605')); }; /** * Clicking on the icon toggles if the mutator bubble is visible. * Disable if block is uneditable. * @param {!Event} e Mouse click event. * @private * @override */ Blockly.Mutator.prototype.iconClick_ = function(e) { if (this.block_.isEditable()) { Blockly.Icon.prototype.iconClick_.call(this, e); } }; /** * Create the editor for the mutator's bubble. * @return {!Element} The top-level node of the editor. * @private */ Blockly.Mutator.prototype.createEditor_ = function() { /* Create the editor. Here's the markup that will be generated: [Flyout] [Workspace] */ this.svgDialog_ = Blockly.createSvgElement('svg', {'x': Blockly.Bubble.BORDER_WIDTH, 'y': Blockly.Bubble.BORDER_WIDTH}, null); this.svgBackground_ = Blockly.createSvgElement('rect', {'class': 'blocklyMutatorBackground', 'height': '100%', 'width': '100%'}, this.svgDialog_); var mutator = this; this.workspace_ = new Blockly.Workspace( function() {return mutator.getFlyoutMetrics_();}, null); this.flyout_ = new Blockly.Flyout(); this.flyout_.autoClose = false; this.svgDialog_.appendChild(this.flyout_.createDom()); this.svgDialog_.appendChild(this.workspace_.createDom()); return this.svgDialog_; }; /** * Add or remove the UI indicating if this icon may be clicked or not. */ Blockly.Mutator.prototype.updateEditable = function() { if (this.block_.isEditable()) { // Default behaviour for an icon. Blockly.Icon.prototype.updateEditable.call(this); } else { // Close any mutator bubble. Icon is not clickable. this.setVisible(false); Blockly.removeClass_(/** @type {!Element} */ (this.iconGroup_), 'blocklyIconGroup'); } }; /** * Callback function triggered when the bubble has resized. * Resize the workspace accordingly. * @private */ Blockly.Mutator.prototype.resizeBubble_ = function() { var doubleBorderWidth = 2 * Blockly.Bubble.BORDER_WIDTH; var workspaceSize = this.workspace_.getCanvas().getBBox(); var flyoutMetrics = this.flyout_.getMetrics_(); var width; if (Blockly.RTL) { width = -workspaceSize.x; } else { width = workspaceSize.width + workspaceSize.x; } var height = Math.max(workspaceSize.height + doubleBorderWidth * 3, flyoutMetrics.contentHeight + 20); width += doubleBorderWidth * 3; // Only resize if the size difference is significant. Eliminates shuddering. if (Math.abs(this.workspaceWidth_ - width) > doubleBorderWidth || Math.abs(this.workspaceHeight_ - height) > doubleBorderWidth) { // Record some layout information for getFlyoutMetrics_. this.workspaceWidth_ = width; this.workspaceHeight_ = height; // Resize the bubble. this.bubble_.setBubbleSize(width + doubleBorderWidth, height + doubleBorderWidth); this.svgDialog_.setAttribute('width', this.workspaceWidth_); this.svgDialog_.setAttribute('height', this.workspaceHeight_); } if (Blockly.RTL) { // Scroll the workspace to always left-align. var translation = 'translate(' + this.workspaceWidth_ + ',0)'; this.workspace_.getCanvas().setAttribute('transform', translation); } }; /** * Show or hide the mutator bubble. * @param {boolean} visible True if the bubble should be visible. */ Blockly.Mutator.prototype.setVisible = function(visible) { if (visible == this.isVisible()) { // No change. return; } if (visible) { // Create the bubble. this.bubble_ = new Blockly.Bubble(this.block_.workspace, this.createEditor_(), this.block_.svg_.svgGroup_, this.iconX_, this.iconY_, null, null); var thisObj = this; this.flyout_.init(this.workspace_, false); this.flyout_.show(this.quarkXml_); this.rootBlock_ = this.block_.decompose(this.workspace_); var blocks = this.rootBlock_.getDescendants(); for (var i = 0, child; child = blocks[i]; i++) { child.render(); } // The root block should not be dragable or deletable. this.rootBlock_.setMovable(false); this.rootBlock_.setDeletable(false); var margin = this.flyout_.CORNER_RADIUS * 2; var x = this.flyout_.width_ + margin; if (Blockly.RTL) { x = -x; } this.rootBlock_.moveBy(x, margin); // Save the initial connections, then listen for further changes. if (this.block_.saveConnections) { this.block_.saveConnections(this.rootBlock_); this.sourceListener_ = Blockly.bindEvent_( this.block_.workspace.getCanvas(), 'blocklyWorkspaceChange', this.block_, function() {thisObj.block_.saveConnections(thisObj.rootBlock_)}); } this.resizeBubble_(); // When the mutator's workspace changes, update the source block. Blockly.bindEvent_(this.workspace_.getCanvas(), 'blocklyWorkspaceChange', this.block_, function() {thisObj.workspaceChanged_();}); this.updateColour(); } else { // Dispose of the bubble. this.svgDialog_ = null; this.svgBackground_ = null; this.flyout_.dispose(); this.flyout_ = null; this.workspace_.dispose(); this.workspace_ = null; this.rootBlock_ = null; this.bubble_.dispose(); this.bubble_ = null; this.workspaceWidth_ = 0; this.workspaceHeight_ = 0; if (this.sourceListener_) { Blockly.unbindEvent_(this.sourceListener_); this.sourceListener_ = null; } } }; /** * Update the source block when the mutator's blocks are changed. * Delete or bump any block that's out of bounds. * Fired whenever a change is made to the mutator's workspace. * @private */ Blockly.Mutator.prototype.workspaceChanged_ = function() { if (Blockly.Block.dragMode_ == 0) { var blocks = this.workspace_.getTopBlocks(false); var MARGIN = 20; for (var b = 0, block; block = blocks[b]; b++) { var blockXY = block.getRelativeToSurfaceXY(); var blockHW = block.getHeightWidth(); if (Blockly.RTL ? blockXY.x > -this.flyout_.width_ + MARGIN : blockXY.x < this.flyout_.width_ - MARGIN) { // Delete any block that's sitting on top of the flyout. block.dispose(false, true); } else if (blockXY.y + blockHW.height < MARGIN) { // Bump any block that's above the top back inside. block.moveBy(0, MARGIN - blockHW.height - blockXY.y); } } } // When the mutator's workspace changes, update the source block. if (this.rootBlock_.workspace == this.workspace_) { // Switch off rendering while the source block is rebuilt. var savedRendered = this.block_.rendered; this.block_.rendered = false; // Allow the source block to rebuild itself. this.block_.compose(this.rootBlock_); // Restore rendering and show the changes. this.block_.rendered = savedRendered; if (this.block_.rendered) { this.block_.render(); } this.resizeBubble_(); // The source block may have changed, notify its workspace. this.block_.workspace.fireChangeEvent(); } }; /** * Return an object with all the metrics required to size scrollbars for the * mutator flyout. The following properties are computed: * .viewHeight: Height of the visible rectangle, * .absoluteTop: Top-edge of view. * .absoluteLeft: Left-edge of view. * @return {!Object} Contains size and position metrics of mutator dialog's * workspace. * @private */ Blockly.Mutator.prototype.getFlyoutMetrics_ = function() { var left = 0; if (Blockly.RTL) { left += this.workspaceWidth_; } return { viewHeight: this.workspaceHeight_, viewWidth: 0, // This seem wrong, but results in correct RTL layout. absoluteTop: 0, absoluteLeft: left }; }; /** * Dispose of this mutator. */ Blockly.Mutator.prototype.dispose = function() { this.block_.mutator = null; Blockly.Icon.prototype.dispose.call(this); }; ================================================ FILE: extern/blockly/core/names.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Utility functions for handling variables and procedure names. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Names'); /** * Class for a database of entity names (variables, functions, etc). * @param {string} reservedWords A comma-separated string of words that are * illegal for use as names in a language (e.g. 'new,if,this,...'). * @constructor */ Blockly.Names = function(reservedWords) { this.reservedDict_ = Object.create(null); if (reservedWords) { var splitWords = reservedWords.split(','); for (var x = 0; x < splitWords.length; x++) { this.reservedDict_[splitWords[x]] = true; } } this.reset(); }; /** * When JavaScript (or most other languages) is generated, variable 'foo' and * procedure 'foo' would collide. However, Blockly has no such problems since * variable get 'foo' and procedure call 'foo' are unambiguous. * Therefore, Blockly keeps a separate type name to disambiguate. * getName('foo', 'variable') -> 'foo' * getName('foo', 'procedure') -> 'foo2' */ /** * Empty the database and start from scratch. The reserved words are kept. */ Blockly.Names.prototype.reset = function() { this.db_ = Object.create(null); this.dbReverse_ = Object.create(null); }; /** * Convert a Blockly entity name to a legal exportable entity name. * @param {string} name The Blockly entity name (no constraints). * @param {string} type The type of entity in Blockly * ('VARIABLE', 'PROCEDURE', 'BUILTIN', etc...). * @return {string} An entity name legal for the exported language. */ Blockly.Names.prototype.getName = function(name, type) { var normalized = name.toLowerCase() + '_' + type; if (normalized in this.db_) { return this.db_[normalized]; } var safeName = this.getDistinctName(name, type); this.db_[normalized] = safeName; return safeName; }; /** * Convert a Blockly entity name to a legal exportable entity name. * Ensure that this is a new name not overlapping any previously defined name. * Also check against list of reserved words for the current language and * ensure name doesn't collide. * @param {string} name The Blockly entity name (no constraints). * @param {string} type The type of entity in Blockly * ('VARIABLE', 'PROCEDURE', 'BUILTIN', etc...). * @return {string} An entity name legal for the exported language. */ Blockly.Names.prototype.getDistinctName = function(name, type) { var safeName = this.safeName_(name); var i = ''; while (this.dbReverse_[safeName + i] || (safeName + i) in this.reservedDict_) { // Collision with existing name. Create a unique name. i = i ? i + 1 : 2; } safeName += i; this.dbReverse_[safeName] = true; return safeName; }; /** * Given a proposed entity name, generate a name that conforms to the * [_A-Za-z][_A-Za-z0-9]* format that most languages consider legal for * variables. * @param {string} name Potentially illegal entity name. * @return {string} Safe entity name. * @private */ Blockly.Names.prototype.safeName_ = function(name) { if (!name) { name = 'unnamed'; } else { // Unfortunately names in non-latin characters will look like // _E9_9F_B3_E4_B9_90 which is pretty meaningless. name = encodeURI(name.replace(/ /g, '_')).replace(/[^\w]/g, '_'); // Most languages don't allow names with leading numbers. if ('0123456789'.indexOf(name[0]) != -1) { name = 'my_' + name; } } return name; }; /** * Do the given two entity names refer to the same entity? * Blockly names are case-insensitive. * @param {string} name1 First name. * @param {string} name2 Second name. * @return {boolean} True if names are the same. */ Blockly.Names.equals = function(name1, name2) { return name1.toLowerCase() == name2.toLowerCase(); }; ================================================ FILE: extern/blockly/core/procedures.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Utility functions for handling procedures. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Procedures'); // TODO(scr): Fix circular dependencies // goog.require('Blockly.Block'); goog.require('Blockly.FieldVariable'); goog.require('Blockly.Names'); goog.require('Blockly.Workspace'); /** * Category to separate procedure names from variables and generated functions. */ Blockly.Procedures.NAME_TYPE = 'PROCEDURE'; /** * Find all user-created procedure definitions. * @return {!Array.>} Pair of arrays, the * first contains procedures without return variables, the second with. * Each procedure is defined by a three-element list of name, parameter * list, and return value boolean. */ Blockly.Procedures.allProcedures = function() { var blocks = Blockly.mainWorkspace.getAllBlocks(); var proceduresReturn = []; var proceduresNoReturn = []; for (var x = 0; x < blocks.length; x++) { var func = blocks[x].getProcedureDef; if (func) { var tuple = func.call(blocks[x]); if (tuple) { if (tuple[2]) { proceduresReturn.push(tuple); } else { proceduresNoReturn.push(tuple); } } } } proceduresNoReturn.sort(Blockly.Procedures.procTupleComparator_); proceduresReturn.sort(Blockly.Procedures.procTupleComparator_); return [proceduresNoReturn, proceduresReturn]; }; /** * Comparison function for case-insensitive sorting of the first element of * a tuple. * @param {!Array} ta First tuple. * @param {!Array} tb Second tuple. * @return {number} -1, 0, or 1 to signify greater than, equality, or less than. * @private */ Blockly.Procedures.procTupleComparator_ = function(ta, tb) { var a = ta[0].toLowerCase(); var b = tb[0].toLowerCase(); if (a > b) { return 1; } if (a < b) { return -1; } return 0; }; /** * Ensure two identically-named procedures don't exist. * @param {string} name Proposed procedure name. * @param {!Blockly.Block} block Block to disambiguate. * @return {string} Non-colliding name. */ Blockly.Procedures.findLegalName = function(name, block) { if (block.isInFlyout) { // Flyouts can have multiple procedures called 'procedure'. return name; } while (!Blockly.Procedures.isLegalName(name, block.workspace, block)) { // Collision with another procedure. var r = name.match(/^(.*?)(\d+)$/); if (!r) { name += '2'; } else { name = r[1] + (parseInt(r[2], 10) + 1); } } return name; }; /** * Does this procedure have a legal name? Illegal names include names of * procedures already defined. * @param {string} name The questionable name. * @param {!Blockly.Workspace} workspace The workspace to scan for collisions. * @param {Blockly.Block} opt_exclude Optional block to exclude from * comparisons (one doesn't want to collide with oneself). * @return {boolean} True if the name is legal. */ Blockly.Procedures.isLegalName = function(name, workspace, opt_exclude) { var blocks = workspace.getAllBlocks(); // Iterate through every block and check the name. for (var x = 0; x < blocks.length; x++) { if (blocks[x] == opt_exclude) { continue; } var func = blocks[x].getProcedureDef; if (func) { var procName = func.call(blocks[x]); if (Blockly.Names.equals(procName[0], name)) { return false; } } } return true; }; /** * Rename a procedure. Called by the editable field. * @param {string} text The proposed new name. * @return {string} The accepted name. * @this {!Blockly.FieldVariable} */ Blockly.Procedures.rename = function(text) { // Strip leading and trailing whitespace. Beyond this, all names are legal. text = text.replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''); // Ensure two identically-named procedures don't exist. text = Blockly.Procedures.findLegalName(text, this.sourceBlock_); // Rename any callers. var blocks = this.sourceBlock_.workspace.getAllBlocks(); for (var x = 0; x < blocks.length; x++) { var func = blocks[x].renameProcedure; if (func) { func.call(blocks[x], this.text_, text); } } return text; }; /** * Construct the blocks required by the flyout for the procedure category. * @param {!Array.} blocks List of blocks to show. * @param {!Array.} gaps List of widths between blocks. * @param {number} margin Standard margin width for calculating gaps. * @param {!Blockly.Workspace} workspace The flyout's workspace. */ Blockly.Procedures.flyoutCategory = function(blocks, gaps, margin, workspace) { if (Blockly.Blocks['procedures_defnoreturn']) { var block = Blockly.Block.obtain(workspace, 'procedures_defnoreturn'); block.initSvg(); blocks.push(block); gaps.push(margin * 2); } if (Blockly.Blocks['procedures_defreturn']) { var block = Blockly.Block.obtain(workspace, 'procedures_defreturn'); block.initSvg(); blocks.push(block); gaps.push(margin * 2); } if (Blockly.Blocks['procedures_ifreturn']) { var block = Blockly.Block.obtain(workspace, 'procedures_ifreturn'); block.initSvg(); blocks.push(block); gaps.push(margin * 2); } if (gaps.length) { // Add slightly larger gap between system blocks and user calls. gaps[gaps.length - 1] = margin * 3; } function populateProcedures(procedureList, templateName) { for (var x = 0; x < procedureList.length; x++) { var block = Blockly.Block.obtain(workspace, templateName); block.setFieldValue(procedureList[x][0], 'NAME'); var tempIds = []; for (var t = 0; t < procedureList[x][1].length; t++) { tempIds[t] = 'ARG' + t; } block.setProcedureParameters(procedureList[x][1], tempIds); block.initSvg(); blocks.push(block); gaps.push(margin * 2); } } var tuple = Blockly.Procedures.allProcedures(); populateProcedures(tuple[0], 'procedures_callnoreturn'); populateProcedures(tuple[1], 'procedures_callreturn'); }; /** * Find all the callers of a named procedure. * @param {string} name Name of procedure. * @param {!Blockly.Workspace} workspace The workspace to find callers in. * @return {!Array.} Array of caller blocks. */ Blockly.Procedures.getCallers = function(name, workspace) { var callers = []; var blocks = workspace.getAllBlocks(); // Iterate through every block and check the name. for (var x = 0; x < blocks.length; x++) { var func = blocks[x].getProcedureCall; if (func) { var procName = func.call(blocks[x]); // Procedure name may be null if the block is only half-built. if (procName && Blockly.Names.equals(procName, name)) { callers.push(blocks[x]); } } } return callers; }; /** * When a procedure definition is disposed of, find and dispose of all its * callers. * @param {string} name Name of deleted procedure definition. * @param {!Blockly.Workspace} workspace The workspace to delete callers from. */ Blockly.Procedures.disposeCallers = function(name, workspace) { var callers = Blockly.Procedures.getCallers(name, workspace); for (var x = 0; x < callers.length; x++) { callers[x].dispose(true, false); } }; /** * When a procedure definition changes its parameters, find and edit all its * callers. * @param {string} name Name of edited procedure definition. * @param {!Blockly.Workspace} workspace The workspace to delete callers from. * @param {!Array.} paramNames Array of new parameter names. * @param {!Array.} paramIds Array of unique parameter IDs. */ Blockly.Procedures.mutateCallers = function(name, workspace, paramNames, paramIds) { var callers = Blockly.Procedures.getCallers(name, workspace); for (var x = 0; x < callers.length; x++) { callers[x].setProcedureParameters(paramNames, paramIds); } }; /** * Find the definition block for the named procedure. * @param {string} name Name of procedure. * @param {!Blockly.Workspace} workspace The workspace to search. * @return {Blockly.Block} The procedure definition block, or null not found. */ Blockly.Procedures.getDefinition = function(name, workspace) { var blocks = workspace.getAllBlocks(); for (var x = 0; x < blocks.length; x++) { var func = blocks[x].getProcedureDef; if (func) { var tuple = func.call(blocks[x]); if (tuple && Blockly.Names.equals(tuple[0], name)) { return blocks[x]; } } } return null; }; ================================================ FILE: extern/blockly/core/realtime-client-utils.js ================================================ /** * @license * Copyright 2013 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict'; /** * @fileoverview Common utility functionality for Google Drive Realtime API, * including authorization and file loading. This functionality should serve * mostly as a well-documented example, though is usable in its own right. * * You can find this code as part of the Google Drive Realtime API Quickstart at * https://developers.google.com/drive/realtime/realtime-quickstart and also as * part of the Google Drive Realtime Playground code at * https://github.com/googledrive/realtime-playground/blob/master/js/realtime-client-utils.js */ /** * Realtime client utilities namespace. */ var rtclient = rtclient || {}; /** * OAuth 2.0 scope for installing Drive Apps. * @const */ rtclient.INSTALL_SCOPE = 'https://www.googleapis.com/auth/drive.install'; /** * OAuth 2.0 scope for opening and creating files. * @const */ rtclient.FILE_SCOPE = 'https://www.googleapis.com/auth/drive.file'; /** * OAuth 2.0 scope for accessing the user's ID. * @const */ rtclient.OPENID_SCOPE = 'openid'; /** * MIME type for newly created Realtime files. * @const */ rtclient.REALTIME_MIMETYPE = 'application/vnd.google-apps.drive-sdk'; /** * Parses the hash parameters to this page and returns them as an object. * @return {!Object} Parameter object. */ rtclient.getParams = function() { var params = {}; var hashFragment = window.location.hash; if (hashFragment) { // split up the query string and store in an object var paramStrs = hashFragment.slice(1).split('&'); for (var i = 0; i < paramStrs.length; i++) { var paramStr = paramStrs[i].split('='); params[paramStr[0]] = unescape(paramStr[1]); } } // Opening from Drive will encode the state in a query search parameter var searchFragment = window.location.search; if (searchFragment) { // split up the query string and store in an object var paramStrs2 = searchFragment.slice(1).split("&"); for (var j = 0; j < paramStrs2.length; j++) { var paramStr2 = paramStrs2[j].split("="); params[paramStr2[0]] = unescape(paramStr2[1]); } } console.log(params); return params; }; /** * Instance of the query parameters. */ rtclient.params = rtclient.getParams(); /** * Fetches an option from options or a default value, logging an error if * neither is available. * @param {!Object} options Containing options. * @param {string} key Option key. * @param {*} defaultValue Default option value (optional). * @return {*} Option value. */ rtclient.getOption = function(options, key, defaultValue) { if (options.hasOwnProperty(key)) { return options[key]; } console.error(key + ' should be present in the options.'); return defaultValue; }; /** * Creates a new Authorizer from the options. * @constructor * @param {!Object} options For authorizer. Two keys are required as mandatory, * these are: * * 1. "clientId", the Client ID from the console * 2. "authButtonElementId", the is of the dom element to use for * authorizing. */ rtclient.Authorizer = function(options) { this.clientId = rtclient.getOption(options, 'clientId'); // Get the user ID if it's available in the state query parameter. this.userId = rtclient.params['userId']; this.authButton = document.getElementById(rtclient.getOption(options, 'authButtonElementId')); }; /** * Start the authorization process. * @param {Function} onAuthComplete To call once authorization has completed. */ rtclient.Authorizer.prototype.start = function(onAuthComplete) { var _this = this; gapi.load('auth:client,drive-realtime,drive-share', function() { _this.authorize(onAuthComplete); }); }; /** * Reauthorize the client with no callback (used for authorization failure). * @param {Function} onAuthComplete To call once authorization has completed. */ rtclient.Authorizer.prototype.authorize = function(onAuthComplete) { var clientId = this.clientId; var userId = this.userId; var _this = this; var handleAuthResult = function(authResult) { if (authResult && !authResult.error) { _this.authButton.disabled = true; _this.fetchUserId(onAuthComplete); } else { _this.authButton.disabled = false; _this.authButton.onclick = authorizeWithPopup; } }; var authorizeWithPopup = function() { gapi.auth.authorize({ client_id: clientId, scope: [ rtclient.INSTALL_SCOPE, rtclient.FILE_SCOPE, rtclient.OPENID_SCOPE ], user_id: userId, immediate: false }, handleAuthResult); }; // Try with no popups first. gapi.auth.authorize({ client_id: clientId, scope: [ rtclient.INSTALL_SCOPE, rtclient.FILE_SCOPE, rtclient.OPENID_SCOPE ], user_id: userId, immediate: true }, handleAuthResult); }; /** * Fetch the user ID using the UserInfo API and save it locally. * @param {Function} callback The callback to call after user ID has been * fetched. */ rtclient.Authorizer.prototype.fetchUserId = function(callback) { var _this = this; gapi.client.load('oauth2', 'v2', function() { gapi.client.oauth2.userinfo.get().execute(function(resp) { if (resp.id) { _this.userId = resp.id; } if (callback) { callback(); } }); }); }; /** * Creates a new Realtime file. * @param {string} title Title of the newly created file. * @param {string} mimeType The MIME type of the new file. * @param {Function} callback The callback to call after creation. */ rtclient.createRealtimeFile = function(title, mimeType, callback) { gapi.client.load('drive', 'v2', function() { gapi.client.drive.files.insert({ 'resource': { mimeType: mimeType, title: title } }).execute(callback); }); }; /** * Fetches the metadata for a Realtime file. * @param {string} fileId The file to load metadata for. * @param {Function} callback The callback to be called on completion, * with signature: * * function onGetFileMetadata(file) {} * * where the file parameter is a Google Drive API file resource instance. */ rtclient.getFileMetadata = function(fileId, callback) { gapi.client.load('drive', 'v2', function() { gapi.client.drive.files.get({ 'fileId' : fileId }).execute(callback); }); }; /** * Parses the state parameter passed from the Drive user interface after * Open With operations. * @param {string} stateParam The state query parameter as a JSON string. * @return {Object} The state query parameter as an object or null if * parsing failed. */ rtclient.parseState = function(stateParam) { try { var stateObj = JSON.parse(stateParam); return stateObj; } catch (e) { return null; } }; /** * Handles authorizing, parsing query parameters, loading and creating Realtime * documents. * @constructor * @param {!Object} options Options for loader. Four keys are required as * mandatory, these are: * * 1. "clientId", the Client ID from the console * 2. "initializeModel", the callback to call when the file is loaded. * 3. "onFileLoaded", the callback to call when the model is first created. * * and one key is optional: * * 1. "defaultTitle", the title of newly created Realtime files. */ rtclient.RealtimeLoader = function(options) { // Initialize configuration variables. this.onFileLoaded = rtclient.getOption(options, 'onFileLoaded'); this.newFileMimeType = rtclient.getOption(options, 'newFileMimeType', rtclient.REALTIME_MIMETYPE); this.initializeModel = rtclient.getOption(options, 'initializeModel'); this.registerTypes = rtclient.getOption(options, 'registerTypes', function() {}); this.afterAuth = rtclient.getOption(options, 'afterAuth', function() {}); // This tells us if need to we automatically create a file after auth. this.autoCreate = rtclient.getOption(options, 'autoCreate', false); this.defaultTitle = rtclient.getOption(options, 'defaultTitle', 'New Realtime File'); this.afterCreate = rtclient.getOption(options, 'afterCreate', function() {}); this.authorizer = new rtclient.Authorizer(options); }; /** * Redirects the browser back to the current page with an appropriate file ID. * @param {Array.} fileIds The IDs of the files to open. * @param {string} userId The ID of the user. */ rtclient.RealtimeLoader.prototype.redirectTo = function(fileIds, userId) { var params = []; if (fileIds) { params.push('fileIds=' + fileIds.join(',')); } if (userId) { params.push('userId=' + userId); } // Naive URL construction. var newUrl = params.length == 0 ? window.location.pathname : (window.location.pathname + '#' + params.join('&')); // Using HTML URL re-write if available. if (window.history && window.history.replaceState) { window.history.replaceState('Google Drive Realtime API Playground', 'Google Drive Realtime API Playground', newUrl); } else { window.location.href = newUrl; } // We are still here that means the page didn't reload. rtclient.params = rtclient.getParams(); for (var index in fileIds) { gapi.drive.realtime.load(fileIds[index], this.onFileLoaded, this.initializeModel, this.handleErrors); } }; /** * Starts the loader by authorizing. */ rtclient.RealtimeLoader.prototype.start = function() { // Bind to local context to make them suitable for callbacks. var _this = this; this.authorizer.start(function() { if (_this.registerTypes) { _this.registerTypes(); } if (_this.afterAuth) { _this.afterAuth(); } _this.load(); }); }; /** * Handles errors thrown by the Realtime API. * @param {!Error} e Error. */ rtclient.RealtimeLoader.prototype.handleErrors = function(e) { if (e.type == gapi.drive.realtime.ErrorType.TOKEN_REFRESH_REQUIRED) { this.authorizer.authorize(); } else if (e.type == gapi.drive.realtime.ErrorType.CLIENT_ERROR) { alert('An Error happened: ' + e.message); window.location.href = '/'; } else if (e.type == gapi.drive.realtime.ErrorType.NOT_FOUND) { alert('The file was not found. It does not exist or you do not have ' + 'read access to the file.'); window.location.href = '/'; } }; /** * Loads or creates a Realtime file depending on the fileId and state query * parameters. */ rtclient.RealtimeLoader.prototype.load = function() { var fileIds = rtclient.params['fileIds']; if (fileIds) { fileIds = fileIds.split(','); } var userId = this.authorizer.userId; var state = rtclient.params['state']; // Creating the error callback. var authorizer = this.authorizer; // We have file IDs in the query parameters, so we will use them to load a // file. if (fileIds) { for (var index in fileIds) { gapi.drive.realtime.load(fileIds[index], this.onFileLoaded, this.initializeModel, this.handleErrors); } return; } // We have a state parameter being redirected from the Drive UI. // We will parse it and redirect to the fileId contained. else if (state) { var stateObj = rtclient.parseState(state); // If opening a file from Drive. if (stateObj.action == 'open') { fileIds = stateObj.ids; userId = stateObj.userId; this.redirectTo(fileIds, userId); return; } } if (this.autoCreate) { this.createNewFileAndRedirect(); } }; /** * Creates a new file and redirects to the URL to load it. */ rtclient.RealtimeLoader.prototype.createNewFileAndRedirect = function() { // No fileId or state have been passed. We create a new Realtime file and // redirect to it. var _this = this; rtclient.createRealtimeFile(this.defaultTitle, this.newFileMimeType, function(file) { if (file.id) { if (_this.afterCreate) { _this.afterCreate(file.id); } _this.redirectTo([file.id], _this.authorizer.userId); } else { // File failed to be created, log why and do not attempt to redirect. console.error('Error creating file.'); console.error(file); } }); }; ================================================ FILE: extern/blockly/core/realtime.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2014 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * This file contains functions used by any Blockly app that wants to provide * realtime collaboration functionality. * * Note that it depends on the existence of particularly named UI elements. * * TODO: Inject the UI element names */ /** * @fileoverview Common support code for Blockly apps using realtime * collaboration. * Note that to use this you must set up a project via the Google Developers * Console. Instructions on how to do that can be found in the Blockly wiki page * at https://code.google.com/p/blockly/wiki/RealtimeCollaboration * Once you do that you can set the clientId in * Blockly.Realtime.realtimeOptions_ * @author markf@google.com (Mark Friedman) */ 'use strict'; goog.provide('Blockly.Realtime'); goog.require('goog.array'); /** * Is realtime collaboration enabled? * @type {boolean} * @private */ Blockly.Realtime.enabled_ = false; /** * The Realtime model of this doc. * @type {gapi.drive.realtime.Model} * @private */ Blockly.Realtime.model_ = null; /** * The function used to initialize the UI after realtime is initialized. * @type {Function} * @private */ Blockly.Realtime.initUi_ = null; /** * A map from block id to blocks. * @type {gapi.drive.realtime.CollaborativeMap} * @private */ Blockly.Realtime.blocksMap_ = null; /** * Are currently syncing from another instance of this realtime doc. * @type {boolean} */ Blockly.Realtime.withinSync = false; /** * The current instance of the realtime loader client * @type {rtclient.RealtimeLoader} * @private */ Blockly.Realtime.realtimeLoader_ = null; /** * Returns whether realtime collaboration is enabled. * @returns {boolean} */ Blockly.Realtime.isEnabled = function() { return Blockly.Realtime.enabled_; }; /** * This function is called the first time that the Realtime model is created * for a file. This function should be used to initialize any values of the * model. * @param model {gapi.drive.realtime.Model} model The Realtime root model * object. */ Blockly.Realtime.initializeModel_ = function(model) { Blockly.Realtime.model_ = model; var blocksMap = model.createMap(); model.getRoot().set('blocks', blocksMap); var topBlocks = model.createList(); model.getRoot().set('topBlocks', topBlocks); var string = model.createString(Blockly.Msg.CHAT); model.getRoot().set('text', string); }; /** * Delete a block from the realtime blocks map. * @param {!Blockly.Block} block The block to remove. */ Blockly.Realtime.removeBlock = function(block) { Blockly.Realtime.blocksMap_.delete(block.id.toString()); }; /** * Add to the list of top-level blocks. * @param {!Blockly.Block} block The block to add. */ Blockly.Realtime.addTopBlock = function(block) { if (Blockly.Realtime.topBlocks_.indexOf(block) == -1) { Blockly.Realtime.topBlocks_.push(block); } }; /** * Delete a block from the list of top-level blocks. * @param {!Blockly.Block} block The block to remove. */ Blockly.Realtime.removeTopBlock = function(block) { Blockly.Realtime.topBlocks_.removeValue(block); }; /** * Obtain a newly created block known by the Realtime API. * @param {!Blockly.Workspace} workspace The workspace to put the block in. * @param {string} prototypeName The name of the prototype for the block * @return {!Blockly.Block} */ Blockly.Realtime.obtainBlock = function(workspace, prototypeName) { var newBlock = Blockly.Realtime.model_.create(Blockly.Block, workspace, prototypeName); return newBlock; }; /** * Get an existing block by id. * @param {string} id The block's id. * @return {Blockly.Block} The found block. */ Blockly.Realtime.getBlockById = function(id) { return Blockly.Realtime.blocksMap_.get(id); }; /** * Event handler to call when a block is changed. * @param {gapi.drive.realtime.ObjectChangedEvent} evt The event that occurred. * @private */ Blockly.Realtime.onObjectChange_ = function(evt) { var events = evt.events; var eventCount = evt.events.length; for (var i = 0; i < eventCount; i++) { var event = events[i]; if (!event.isLocal) { if (event.type == 'value_changed') { if (event.property == 'xmlDom') { var block = event.target; Blockly.Realtime.doWithinSync_(function(){ Blockly.Realtime.placeBlockOnWorkspace_(block, false); Blockly.Realtime.moveBlock_(block); }); } else if (event.property == 'relativeX' || event.property == 'relativeY') { var block2 = event.target; Blockly.Realtime.doWithinSync_(function () { if (!block2.svg_) { // If this is a move of a newly disconnected (i.e newly top level) // block it will not have any svg (because it has been disposed of // by it's parent), so we need to handle that here. Blockly.Realtime.placeBlockOnWorkspace_(block2, false); } Blockly.Realtime.moveBlock_(block2); }); } } } } }; /** * Event handler to call when there is a change to the realtime blocks map. * @param {gapi.drive.realtime.ValueChangedEvent} evt The event that occurred. * @private */ Blockly.Realtime.onBlocksMapChange_ = function(evt) { console.log('Blocks Map event:'); console.log(' id: ' + evt.property); if (!evt.isLocal) { var block = evt.newValue; if (block) { Blockly.Realtime.placeBlockOnWorkspace_(block, !(evt.oldValue)); } else { block = evt.oldValue; Blockly.Realtime.deleteBlock(block); } } }; /** * A convenient wrapper around code that synchronizes the local model being * edited with changes from another non-local model. * @param {!Function} thunk A thunk of code to call. * @private */ Blockly.Realtime.doWithinSync_ = function(thunk) { if (Blockly.Realtime.withinSync) { thunk(); } else { try { Blockly.Realtime.withinSync = true; thunk(); } finally { Blockly.Realtime.withinSync = false; } } }; /** * Places a block to be synced on this docs main workspace. The block might * already exist on this doc, in which case it is updated and/or moved. * @param {!Blockly.Block} block The block. * @param {boolean} addToTop Whether to add the block to the workspace/s list of * top-level blocks. * @private */ Blockly.Realtime.placeBlockOnWorkspace_ = function(block, addToTop) { Blockly.Realtime.doWithinSync_(function() { var blockDom = Blockly.Xml.textToDom(block.xmlDom).firstChild; var newBlock = Blockly.Xml.domToBlock(Blockly.mainWorkspace, blockDom, true); // TODO: The following is for debugging. It should never actually happen. if (!newBlock) { return; } // Since Blockly.Xml.blockDomToBlock() purposely won't add blocks to // workspace.topBlocks_ we sometimes need to do it explicitly here. if (addToTop) { newBlock.workspace.addTopBlock(newBlock); } if (addToTop || goog.array.contains(Blockly.Realtime.topBlocks_, newBlock)) { Blockly.Realtime.moveBlock_(newBlock); } }); }; /** * Move a block * @param {Blockly.Block} block The block to move. * @private */ Blockly.Realtime.moveBlock_ = function(block) { if (!isNaN(block.relativeX) && !isNaN(block.relativeY)) { var width = Blockly.svgSize().width; var curPos = block.getRelativeToSurfaceXY(); var dx = block.relativeX - curPos.x; var dy = block.relativeY - curPos.y; block.moveBy(Blockly.RTL ? width - dx : dx, dy); } }; /** * Delete a block. * @param {!Blockly.Block} block The block to delete. * @private */ Blockly.Realtime.deleteBlock = function(block) { Blockly.Realtime.doWithinSync_(function() { block.dispose(true, true, true); }); }; /** * Load all the blocks from the realtime model's blocks map and place them * appropriately on the main Blockly workspace. * @private */ Blockly.Realtime.loadBlocks_ = function() { var blocks = Blockly.Realtime.blocksMap_.values(); for (var i = 0; i < blocks.length; i++) { var block = blocks[i]; // Since we now have blocks with already existing ids, we have to make sure // that new blocks don't get any of the existing ids. var blockIdNum = parseInt(block.id, 10); if (blockIdNum > Blockly.getUidCounter()) { Blockly.setUidCounter(blockIdNum + 1); } } var topBlocks = Blockly.Realtime.topBlocks_; for (var j = 0; j < topBlocks.length; j++) { var topBlock = topBlocks.get(j); Blockly.Realtime.placeBlockOnWorkspace_(topBlock, true); } }; /** * Cause a changed block to update the realtime model, and therefore to be * synced with other apps editing this same doc. * @param {!Blockly.Block} block The block that changed. */ Blockly.Realtime.blockChanged = function(block) { if (block.workspace == Blockly.mainWorkspace) { var rootBlock = block.getRootBlock(); var xy = rootBlock.getRelativeToSurfaceXY(); var changed = false; var xml = Blockly.Xml.blockToDom_(rootBlock); xml.setAttribute('id', rootBlock.id); var topXml = goog.dom.createDom('xml'); topXml.appendChild(xml); var newXml = Blockly.Xml.domToText(topXml); if (newXml != rootBlock.xmlDom) { changed = true; rootBlock.xmlDom = newXml; } if (rootBlock.relativeX != xy.x || rootBlock.relativeY != xy.y){ rootBlock.relativeX = xy.x; rootBlock.relativeY = xy.y; changed = true; } if (changed) { var blockId = rootBlock.id.toString(); Blockly.Realtime.blocksMap_.set(blockId, rootBlock); } } }; /** * This function is called when the Realtime file has been loaded. It should * be used to initialize any user interface components and event handlers * depending on the Realtime model. In this case, create a text control binder * and bind it to our string model that we created in initializeModel. * @param {!gapi.drive.realtime.Document} doc The Realtime document. * @private */ Blockly.Realtime.onFileLoaded_ = function(doc) { Blockly.Realtime.model_ = doc.getModel(); Blockly.Realtime.blocksMap_ = Blockly.Realtime.model_.getRoot().get('blocks'); Blockly.Realtime.topBlocks_ = Blockly.Realtime.model_.getRoot().get('topBlocks'); Blockly.Realtime.model_.getRoot().addEventListener( gapi.drive.realtime.EventType.OBJECT_CHANGED, Blockly.Realtime.onObjectChange_); Blockly.Realtime.blocksMap_.addEventListener( gapi.drive.realtime.EventType.VALUE_CHANGED, Blockly.Realtime.onBlocksMapChange_); var string = Blockly.Realtime.model_.getRoot().get('text'); // Keeping one box updated with a String binder. var textArea1 = document.getElementById('chatbox'); gapi.drive.realtime.databinding.bindString(string, textArea1); // Enabling UI Elements. textArea1.disabled = false; Blockly.Realtime.initUi_(); Blockly.Realtime.loadBlocks_(); // Add logic for undo button. // TODO: Uncomment this when undo/redo are fixed. /* var undoButton = document.getElementById('undoButton'); var redoButton = document.getElementById('redoButton'); undoButton.onclick = function(e) { Blockly.Realtime.model_.undo(); }; redoButton.onclick = function(e) { Blockly.Realtime.model_.redo(); }; // Add event handler for UndoRedoStateChanged events. var onUndoRedoStateChanged = function(e) { undoButton.disabled = !e.canUndo; redoButton.disabled = !e.canRedo; }; Blockly.Realtime.model_.addEventListener( gapi.drive.realtime.EventType.UNDO_REDO_STATE_CHANGED, onUndoRedoStateChanged); */ }; /** * Register the Blockly types and attributes that are reflected in the realtime * model. * @private */ Blockly.Realtime.registerTypes_ = function() { var custom = gapi.drive.realtime.custom; custom.registerType(Blockly.Block, 'Block'); Blockly.Block.prototype.id = custom.collaborativeField('id'); Blockly.Block.prototype.type = custom.collaborativeField('type'); Blockly.Block.prototype.xmlDom = custom.collaborativeField('xmlDom'); Blockly.Block.prototype.relativeX = custom.collaborativeField('relativeX'); Blockly.Block.prototype.relativeY = custom.collaborativeField('relativeY'); custom.setInitializer(Blockly.Block, Blockly.Block.prototype.initialize); }; Blockly.Realtime.REAUTH_INTERVAL_IN_MILLISECONDS_ = 30 * 60 * 1000; /** * What to do after Realtime authorization. * @private */ Blockly.Realtime.afterAuth_ = function() { // This is a workaround for the fact that the code in realtime-client-utils.js // doesn't deal with auth timeouts correctly. So we explicitly reauthorize at // regular intervals. window.setTimeout( function() { Blockly.Realtime.realtimeLoader_.authorizer.authorize( Blockly.Realtime.afterAuth_); }, Blockly.Realtime.REAUTH_INTERVAL_IN_MILLISECONDS_); }; /** * Add "Anyone with the link" permissions to the file. * @param {string} fileId the file id */ Blockly.Realtime.afterCreate_ = function(fileId) { var resource = { 'type': 'anyone', 'role': 'writer', 'value': 'default', 'withLink': true }; var request = gapi.client.drive.permissions.insert({ 'fileId': fileId, 'resource': resource }); request.execute(function(resp) { // If we have an error try to just set the permission for all users // of the domain. if (resp.error) { Blockly.Realtime.getUserDomain(fileId, function(domain) { var resource = { 'type': 'domain', 'role': 'writer', 'value': domain, 'withLink': true }; request = gapi.client.drive.permissions.insert({ 'fileId': fileId, 'resource': resource }); request.execute(function(resp) { }); }); } }); }; /** * Get the domain (if it exists) associated with a realtime file. The callback * will be called with the domain, if it exists. * @param fileId {string} the id of the file * @param callback {function(string)} a function to call back with the domain */ Blockly.Realtime.getUserDomain = function (fileId, callback) { /** * Note that there may be a more direct way to get the domain by, for example, * using the Google profile API but this way we don't need any additional * APIs or scopes. But if it turns out that the permissions API stops * providing the domain this might have to change. */ var request = gapi.client.drive.permissions.list({ 'fileId': fileId }); request.execute(function(resp) { for (var i = 0; i < resp.items.length; i++) { var item = resp.items[i]; if (item.role == 'owner') { callback(item.domain); return; } } }); }; /** * Options for the Realtime loader. */ Blockly.Realtime.realtimeOptions_ = { /** * Client ID from the console. */ // clientId: 'INSERT YOUR CLIENT ID HERE', clientId: '922110111899.apps.googleusercontent.com', /** * The ID of the button to click to authorize. Must be a DOM element ID. */ authButtonElementId: 'authorizeButton', /** * Function to be called when a Realtime model is first created. */ initializeModel: Blockly.Realtime.initializeModel_, /** * Autocreate files right after auth automatically. */ autoCreate: true, /** * The name of newly created Drive files. */ defaultTitle: 'New Realtime Blockly File', /** * The MIME type of newly created Drive Files. By default the application * specific MIME type will be used: * application/vnd.google-apps.drive-sdk. */ newFileMimeType: null, // Using default. /** * Function to be called every time a Realtime file is loaded. */ onFileLoaded: Blockly.Realtime.onFileLoaded_, /** * Function to be called to initialize custom Collaborative Objects types. */ registerTypes: Blockly.Realtime.registerTypes_, /** * Function to be called after authorization and before loading files. */ afterAuth: Blockly.Realtime.afterAuth_, /** * Function to be called after file creation, if autoCreate is true. */ afterCreate: Blockly.Realtime.afterCreate_ }; /** * Start the Realtime loader with the options. */ Blockly.Realtime.startRealtime = function (uiInitialize) { Blockly.Realtime.enabled_ = true; Blockly.Realtime.initUi_ = uiInitialize; Blockly.Realtime.realtimeLoader_ = new rtclient.RealtimeLoader(Blockly.Realtime.realtimeOptions_); Blockly.Realtime.realtimeLoader_.start(); }; ================================================ FILE: extern/blockly/core/scrollbar.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Library for creating scrollbars. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Scrollbar'); goog.provide('Blockly.ScrollbarPair'); goog.require('goog.userAgent'); /** * Class for a pair of scrollbars. Horizontal and vertical. * @param {!Blockly.Workspace} workspace Workspace to bind the scrollbars to. * @constructor */ Blockly.ScrollbarPair = function(workspace) { this.workspace_ = workspace; this.oldHostMetrics_ = null; this.hScroll = new Blockly.Scrollbar(workspace, true, true); this.vScroll = new Blockly.Scrollbar(workspace, false, true); }; /** * Dispose of this pair of scrollbars. * Unlink from all DOM elements to prevent memory leaks. */ Blockly.ScrollbarPair.prototype.dispose = function() { Blockly.unbindEvent_(this.onResizeWrapper_); this.onResizeWrapper_ = null; this.workspace_ = null; this.oldHostMetrics_ = null; this.hScroll.dispose(); this.hScroll = null; this.vScroll.dispose(); this.vScroll = null; }; /** * Recalculate both of the scrollbars' locations and lengths. * Also reposition the corner rectangle. */ Blockly.ScrollbarPair.prototype.resize = function() { // Look up the host metrics once, and use for both scrollbars. if (Blockly.scrollBarOff) return; var hostMetrics = this.workspace_.getMetrics(); if (!hostMetrics) { // Host element is likely not visible. return; } // Only change the scrollbars if there has been a change in metrics. var resizeH = false; var resizeV = false; if (!this.oldHostMetrics_ || this.oldHostMetrics_.viewWidth != hostMetrics.viewWidth || this.oldHostMetrics_.viewHeight != hostMetrics.viewHeight || this.oldHostMetrics_.absoluteTop != hostMetrics.absoluteTop || this.oldHostMetrics_.absoluteLeft != hostMetrics.absoluteLeft) { // The window has been resized or repositioned. resizeH = true; resizeV = true; } else { // Has the content been resized or moved? if (!this.oldHostMetrics_ || this.oldHostMetrics_.contentWidth != hostMetrics.contentWidth || this.oldHostMetrics_.viewLeft != hostMetrics.viewLeft || this.oldHostMetrics_.contentLeft != hostMetrics.contentLeft) { resizeH = true; } if (!this.oldHostMetrics_ || this.oldHostMetrics_.contentHeight != hostMetrics.contentHeight || this.oldHostMetrics_.viewTop != hostMetrics.viewTop || this.oldHostMetrics_.contentTop != hostMetrics.contentTop) { resizeV = true; } } if (resizeH) { this.hScroll.resize(hostMetrics); } if (resizeV) { this.vScroll.resize(hostMetrics); } // Cache the current metrics to potentially short-cut the next resize event. this.oldHostMetrics_ = hostMetrics; }; /** * Set the sliders of both scrollbars to be at a certain position. * @param {number} x Horizontal scroll value. * @param {number} y Vertical scroll value. */ Blockly.ScrollbarPair.prototype.set = function(x, y) { /* HACK: Two scrollbars are about to have their sliders moved. Moving a scrollbar will normally result in its onScroll function being called. That function will update the contents. At issue is what happens when two scrollbars are moved. Calling onScroll twice may result in two rerenderings of the content and increase jerkiness during dragging. In the case of native scrollbars (currently used only by Firefox), onScroll is called as an event, which means two separate renderings of the content are performed. However in the case of SVG scrollbars (currently used by all other browsers), onScroll is called as a function and the browser only rerenders the contents once at the end of the thread. */ if (Blockly.Scrollbar === Blockly.ScrollbarNative) { // Native scrollbar mode. // Set both scrollbars and suppress their two separate onScroll events. this.hScroll.set(x, false); this.vScroll.set(y, false); // Redraw the surface once with the new settings for both scrollbars. var xyRatio = {}; xyRatio.x = (this.hScroll.outerDiv_.scrollLeft / this.hScroll.innerImg_.offsetWidth) || 0; xyRatio.y = (this.vScroll.outerDiv_.scrollTop / this.vScroll.innerImg_.offsetHeight) || 0; this.workspace_.setMetrics(xyRatio); } else { // SVG scrollbars. // Set both scrollbars and allow each to call a separate onScroll execution. this.hScroll.set(x, true); this.vScroll.set(y, true); } }; // -------------------------------------------------------------------- /** * Common properties and methods for ScrollbarNative and ScrollbarSvg. * Prevents the compiler from choosing incompatible names for properties on * each. * @interface */ Blockly.ScrollbarInterface = function() {}; /** * Dispose of this scrollbar. */ Blockly.ScrollbarInterface.prototype.dispose = function() {}; /** * Recalculate the scrollbar's location and its length. */ Blockly.ScrollbarInterface.prototype.resize = function() {}; /** * Is the scrollbar visible. * @return {boolean} True if visible. */ Blockly.ScrollbarInterface.prototype.isVisible = function() {}; /** * Set whether the scrollbar is visible. * @param {boolean} visible True if visible. */ Blockly.ScrollbarInterface.prototype.setVisible = function(visible) {}; /** * Set the scrollbar slider's position. * @param {number} value The distance from the top/left end of the bar. * @param {boolean} fireEvents True if onScroll events should be fired. */ Blockly.ScrollbarInterface.prototype.set = function(value, fireEvents) {}; // -------------------------------------------------------------------- /** * Class for a native widget scrollbar nested in a foreignObject element. * This technique offers a scrollbar that looks and behaves like the system's * scrollbars. However it isn't well supported at the moment. * @param {!Blockly.Workspace} workspace Workspace to bind the scrollbar to. * @param {?boolean} horizontal True if horizontal, false if vertical. * Null is used to create a test scrollbar to measure thickness. * @param {boolean=} opt_pair True if the scrollbar is part of a * horizontal/vertical pair. * @constructor * @implements {Blockly.ScrollbarInterface} */ Blockly.ScrollbarNative = function(workspace, horizontal, opt_pair) { this.workspace_ = workspace; this.pair_ = opt_pair || false; this.horizontal_ = horizontal; this.createDom_(); if (horizontal === null) { // Just return a bare-bones scrollbar DOM for thickness testing. return; } if (!Blockly.Scrollbar.scrollbarThickness) { // The first time a scrollbar is created, we need to measure the thickness. Blockly.ScrollbarNative.measureScrollbarThickness_(workspace); } if (horizontal) { this.foreignObject_.setAttribute('height', Blockly.Scrollbar.scrollbarThickness); this.outerDiv_.style.height = Blockly.Scrollbar.scrollbarThickness + 'px'; this.outerDiv_.style.overflowX = 'scroll'; this.outerDiv_.style.overflowY = 'hidden'; this.innerImg_.style.height = '1px'; } else { this.foreignObject_.setAttribute('width', Blockly.Scrollbar.scrollbarThickness); this.outerDiv_.style.width = Blockly.Scrollbar.scrollbarThickness + 'px'; this.outerDiv_.style.overflowX = 'hidden'; this.outerDiv_.style.overflowY = 'scroll'; this.innerImg_.style.width = '1px'; } var scrollbar = this; this.onScrollWrapper_ = Blockly.bindEvent_(this.outerDiv_, 'scroll', scrollbar, function() {scrollbar.onScroll_();}); Blockly.bindEvent_(this.foreignObject_, 'mousedown', null, function(e) {Blockly.hideChaff(true); Blockly.noEvent(e);}); }; /** * Dispose of this scrollbar. * Unlink from all DOM elements to prevent memory leaks. */ Blockly.ScrollbarNative.prototype.dispose = function() { Blockly.unbindEvent_(this.onResizeWrapper_); this.onResizeWrapper_ = null; Blockly.unbindEvent_(this.onScrollWrapper_); this.onScrollWrapper_ = null; goog.dom.removeNode(this.foreignObject_); this.foreignObject_ = null; this.workspace_ = null; this.outerDiv_ = null; this.innerImg_ = null; }; /** * Recalculate the scrollbar's location and its length. * @param {Object=} opt_metrics A data structure of from the describing all the * required dimensions. If not provided, it will be fetched from the host * object. */ Blockly.ScrollbarNative.prototype.resize = function(opt_metrics) { // Determine the location, height and width of the host element. var hostMetrics = opt_metrics; if (!hostMetrics) { hostMetrics = this.workspace_.getMetrics(); if (!hostMetrics) { // Host element is likely not visible. return; } } /* hostMetrics is an object with the following properties. * .viewHeight: Height of the visible rectangle, * .viewWidth: Width of the visible rectangle, * .contentHeight: Height of the contents, * .contentWidth: Width of the content, * .viewTop: Offset of top edge of visible rectangle from parent, * .viewLeft: Offset of left edge of visible rectangle from parent, * .contentTop: Offset of the top-most content from the y=0 coordinate, * .contentLeft: Offset of the left-most content from the x=0 coordinate, * .absoluteTop: Top-edge of view. * .absoluteLeft: Left-edge of view. */ if (this.horizontal_) { var outerLength = hostMetrics.viewWidth; if (this.pair_) { // Shorten the scrollbar to make room for the corner square. outerLength -= Blockly.Scrollbar.scrollbarThickness; } else { // Only show the scrollbar if needed. // Ideally this would also apply to scrollbar pairs, but that's a bigger // headache (due to interactions with the corner square). this.setVisible(outerLength < hostMetrics.contentWidth); } this.ratio_ = outerLength / hostMetrics.viewWidth; var innerLength = this.ratio_ * hostMetrics.contentWidth; var innerOffset = (hostMetrics.viewLeft - hostMetrics.contentLeft) * this.ratio_; this.outerDiv_.style.width = outerLength + 'px'; this.innerImg_.style.width = innerLength + 'px'; this.xCoordinate = hostMetrics.absoluteLeft; if (this.pair_ && Blockly.RTL) { this.xCoordinate += Blockly.Scrollbar.scrollbarThickness; } this.yCoordinate = hostMetrics.absoluteTop + hostMetrics.viewHeight - Blockly.Scrollbar.scrollbarThickness; this.foreignObject_.setAttribute('x', this.xCoordinate); this.foreignObject_.setAttribute('y', this.yCoordinate); this.foreignObject_.setAttribute('width', Math.max(0, outerLength)); this.outerDiv_.scrollLeft = Math.round(innerOffset); } else { var outerLength = hostMetrics.viewHeight; if (this.pair_) { // Shorten the scrollbar to make room for the corner square. outerLength -= Blockly.Scrollbar.scrollbarThickness; } else { // Only show the scrollbar if needed. this.setVisible(outerLength < hostMetrics.contentHeight); } this.ratio_ = outerLength / hostMetrics.viewHeight; var innerLength = this.ratio_ * hostMetrics.contentHeight; var innerOffset = (hostMetrics.viewTop - hostMetrics.contentTop) * this.ratio_; this.outerDiv_.style.height = outerLength + 'px'; this.innerImg_.style.height = innerLength + 'px'; this.xCoordinate = hostMetrics.absoluteLeft; if (!Blockly.RTL) { this.xCoordinate += hostMetrics.viewWidth - Blockly.Scrollbar.scrollbarThickness; } this.yCoordinate = hostMetrics.absoluteTop; this.foreignObject_.setAttribute('x', this.xCoordinate); this.foreignObject_.setAttribute('y', this.yCoordinate); this.foreignObject_.setAttribute('height', Math.max(0, outerLength)); this.outerDiv_.scrollTop = Math.round(innerOffset); } }; /** * Create all the DOM elements required for a scrollbar. * The resulting widget is not sized. * @private */ Blockly.ScrollbarNative.prototype.createDom_ = function() { /* Create the following DOM:
*/ this.foreignObject_ = Blockly.createSvgElement('foreignObject', {}, null); var body = document.createElementNS(Blockly.HTML_NS, 'body'); body.setAttribute('xmlns', Blockly.HTML_NS); body.setAttribute('class', 'blocklyMinimalBody'); var outer = document.createElementNS(Blockly.HTML_NS, 'div'); this.outerDiv_ = outer; var inner = document.createElementNS(Blockly.HTML_NS, 'img'); inner.setAttribute('src', Blockly.pathToBlockly + 'media/1x1.gif'); this.innerImg_ = inner; outer.appendChild(inner); body.appendChild(outer); this.foreignObject_.appendChild(body); Blockly.Scrollbar.insertAfter_(this.foreignObject_, this.workspace_.getBubbleCanvas()); }; /** * Is the scrollbar visible. Non-paired scrollbars disappear when they aren't * needed. * @return {boolean} True if visible. */ Blockly.ScrollbarNative.prototype.isVisible = function() { return this.foreignObject_.style.display != 'none'; }; /** * Set whether the scrollbar is visible. * Only applies to non-paired scrollbars. * @param {boolean} visible True if visible. */ Blockly.ScrollbarNative.prototype.setVisible = function(visible) { if (visible == this.isVisible()) { return; } // Ideally this would also apply to scrollbar pairs, but that's a bigger // headache (due to interactions with the corner square). if (this.pair_) { throw 'Unable to toggle visibility of paired scrollbars.'; } if (visible) { this.foreignObject_.style.display = 'block'; /* HACK: For some reason Firefox requires the metrics to be recalculated after displaying the scrollbar. Even though the metrics are identical and calculating these metrics has no side effects. Failure to do so results in a scrollbar that's crushed to 0 in an off-scale range. */ this.workspace_.getMetrics(); } else { // Hide the scrollbar. this.workspace_.setMetrics({x: 0, y: 0}); this.foreignObject_.style.display = 'none'; } }; /** * Called when scrollbar is dragged. * @private */ Blockly.ScrollbarNative.prototype.onScroll_ = function() { var xyRatio = {}; if (this.horizontal_) { xyRatio.x = (this.outerDiv_.scrollLeft / this.innerImg_.offsetWidth) || 0; } else { xyRatio.y = (this.outerDiv_.scrollTop / this.innerImg_.offsetHeight) || 0; } this.workspace_.setMetrics(xyRatio); }; /** * Set the scrollbar slider's position. * @param {number} value The distance from the top/left end of the bar. * @param {boolean} fireEvents True if onScroll events should be fired. */ Blockly.ScrollbarNative.prototype.set = function(value, fireEvents) { // If the scrollbar is part of a pair, it is slightly shorter than the view // and the value needs to be scaled accordingly. if (!fireEvents && this.onScrollWrapper_) { // Temporarily suppress the onscroll event handler. var scrollFunc = Blockly.unbindEvent_(this.onScrollWrapper_); } // Move the scrollbar slider. if (this.horizontal_) { this.outerDiv_.scrollLeft = value * this.ratio_; } else { this.outerDiv_.scrollTop = value * this.ratio_; } if (scrollFunc) { // Re-enable the onscroll event handler. var scrollbar = this; this.onScrollWrapper_ = Blockly.bindEvent_(this.outerDiv_, 'scroll', scrollbar, scrollFunc); } }; /** * Mutilate this scrollbar to measure the thickness of an HTML scrollbar. * @param {!Blockly.Workspace} workspace Workspace to bind the scrollbar to. * @private */ Blockly.ScrollbarNative.measureScrollbarThickness_ = function(workspace) { var testBar = new Blockly.ScrollbarNative(workspace, null, false); testBar.outerDiv_.style.width = '100px'; testBar.outerDiv_.style.height = '100px'; testBar.innerImg_.style.width = '100%'; testBar.innerImg_.style.height = '200px'; // Trivia: failure to set a height and width results in Firefox returning // a scrollbar width of -85 instead of 15. testBar.foreignObject_.setAttribute('width', 1); testBar.foreignObject_.setAttribute('height', 1); // Measure the width of the inner-most div. testBar.outerDiv_.style.overflowY = 'scroll'; var w1 = testBar.innerImg_.offsetWidth; // Turn off scrollbars and remeasure. testBar.outerDiv_.style.overflowY = 'hidden'; var w2 = testBar.innerImg_.offsetWidth; // Dispose of the test scrollbar. goog.dom.removeNode(testBar.foreignObject_); var thickness = w2 - w1; if (thickness <= 0) { // Chrome for OS X 10.7 (Lion) floats scrollbars over the content, meaning // that there is no way to measure the thickness. Pick a default. thickness = 15; } Blockly.Scrollbar.scrollbarThickness = thickness; }; // -------------------------------------------------------------------- /** * Class for a pure SVG scrollbar. * This technique offers a scrollbar that is guaranteed to work, but may not * look or behave like the system's scrollbars. * @param {!Blockly.Workspace} workspace Workspace to bind the scrollbar to. * @param {boolean} horizontal True if horizontal, false if vertical. * @param {boolean} opt_pair True if the scrollbar is part of a horiz/vert pair. * @constructor * @implements {Blockly.ScrollbarInterface} */ Blockly.ScrollbarSvg = function(workspace, horizontal, opt_pair) { this.workspace_ = workspace; this.pair_ = opt_pair || false; this.horizontal_ = horizontal; this.createDom_(); if (horizontal) { this.svgBackground_.setAttribute('height', Blockly.Scrollbar.scrollbarThickness); this.svgKnob_.setAttribute('height', Blockly.Scrollbar.scrollbarThickness - 6); this.svgKnob_.setAttribute('y', 3); } else { this.svgBackground_.setAttribute('width', Blockly.Scrollbar.scrollbarThickness); this.svgKnob_.setAttribute('width', Blockly.Scrollbar.scrollbarThickness - 6); this.svgKnob_.setAttribute('x', 6); } var scrollbar = this; var pElement = this.workspace_.svgGroup_.parentElement || this.workspace_.svgGroup_.parentNode; //Blockly.bindEvent_(pElement, 'mouseenter', scrollbar, function(e){ //scrollbar.svgGroup_.setAttribute('opacity', '1'); //}); //Blockly.bindEvent_(pElement, 'mouseout', scrollbar, function(e) { //var result = Blockly.isChild(pElement, e.toElement); //if ( !(result || e.toElement == pElement)) { //scrollbar.svgGroup_.setAttribute('opacity', '0'); //} else //return; //}); this.onMouseDownBarWrapper_ = Blockly.bindEvent_(this.svgBackground_, 'mousedown', scrollbar, scrollbar.onMouseDownBar_); this.onMouseDownKnobWrapper_ = Blockly.bindEvent_(this.svgKnob_, 'mousedown', scrollbar, scrollbar.onMouseDownKnob_); }; /** * set UI effect of this scrollbar. */ Blockly.ScrollbarSvg.prototype.uiEffectInc_ = function(e) { var pElement = this.workspace_.svgGroup_.parentElement; var scrollbar = this.svgGroup_; scrollbar.setAttribute('opacity', '1'); //var timerFunc= window.setInterval(function(){ //var currentOpacity = scrollbar.getAttribute('opacity'); //if (currentOpacity >= 1) { //scrollbar.setAttribute('opacity', '1'); //clearInterval(timerFunc); //} else { //currentOpacity = Number(currentOpacity) + 0.05; //scrollbar.setAttribute('opacity', currentOpacity); //} //}, 20); }; /** * set UI effect of this scrollbar. */ Blockly.ScrollbarSvg.prototype.uiEffectDec_ = function(e) { return; var pElement = this.workspace_.svgGroup_.parentElement; var result = Entry.isChild(pElement, e.toElement); var scrollbar = this.svgGroup_; if ( !(result || e.toElement == pElement)) { scrollbar.setAttribute('opacity', '0'); } else return; }; /** * Dispose of this scrollbar. * Unlink from all DOM elements to prevent memory leaks. */ Blockly.ScrollbarSvg.prototype.dispose = function() { this.onMouseUpKnob_(); if (this.onResizeWrapper_) { Blockly.unbindEvent_(this.onResizeWrapper_); this.onResizeWrapper_ = null; } Blockly.unbindEvent_(this.onMouseDownBarWrapper_); this.onMouseDownBarWrapper_ = null; Blockly.unbindEvent_(this.onMouseDownKnobWrapper_); this.onMouseDownKnobWrapper_ = null; goog.dom.removeNode(this.svgGroup_); this.svgGroup_ = null; this.svgBackground_ = null; this.svgKnob_ = null; this.workspace_ = null; }; /** * Recalculate the scrollbar's location and its length. * @param {Object=} opt_metrics A data structure of from the describing all the * required dimensions. If not provided, it will be fetched from the host * object. */ Blockly.ScrollbarSvg.prototype.resize = function(opt_metrics) { // Determine the location, height and width of the host element. var hostMetrics = opt_metrics; if (!hostMetrics) { hostMetrics = this.workspace_.getMetrics(); if (!hostMetrics) { // Host element is likely not visible. return; } } /* hostMetrics is an object with the following properties. * .viewHeight: Height of the visible rectangle, * .viewWidth: Width of the visible rectangle, * .contentHeight: Height of the contents, * .contentWidth: Width of the content, * .viewTop: Offset of top edge of visible rectangle from parent, * .viewLeft: Offset of left edge of visible rectangle from parent, * .contentTop: Offset of the top-most content from the y=0 coordinate, * .contentLeft: Offset of the left-most content from the x=0 coordinate, * .absoluteTop: Top-edge of view. * .absoluteLeft: Left-edge of view. */ if (this.horizontal_) { var outerLength = hostMetrics.viewWidth; if (this.pair_) { // Shorten the scrollbar to make room for the corner square. outerLength -= Blockly.Scrollbar.scrollbarThickness; } else { // Only show the scrollbar if needed. // Ideally this would also apply to scrollbar pairs, but that's a bigger // headache (due to interactions with the corner square). this.setVisible(outerLength < hostMetrics.contentHeight); } this.ratio_ = outerLength / hostMetrics.contentWidth; if (this.ratio_ === -Infinity || this.ratio_ === Infinity || isNaN(this.ratio_)) { this.ratio_ = 0; } var innerLength = hostMetrics.viewWidth * this.ratio_; var innerOffset = (hostMetrics.viewLeft - hostMetrics.contentLeft) * this.ratio_; this.svgKnob_.setAttribute('width', Math.max(0, innerLength)); this.xCoordinate = hostMetrics.absoluteLeft; if (this.pair_ && Blockly.RTL) { this.xCoordinate += hostMetrics.absoluteLeft + Blockly.Scrollbar.scrollbarThickness; } this.yCoordinate = hostMetrics.absoluteTop + hostMetrics.viewHeight - Blockly.Scrollbar.scrollbarThickness; this.svgGroup_.setAttribute('transform', 'translate(' + this.xCoordinate + ', ' + this.yCoordinate + ')'); this.svgBackground_.setAttribute('width', Math.max(0, outerLength)); this.svgKnob_.setAttribute('x', this.constrainKnob_(innerOffset)); } else { var outerLength = hostMetrics.viewHeight; if (this.pair_) { // Shorten the scrollbar to make room for the corner square. outerLength -= Blockly.Scrollbar.scrollbarThickness; } else { // Only show the scrollbar if needed. this.setVisible(outerLength < hostMetrics.contentHeight); } this.ratio_ = outerLength / hostMetrics.contentHeight; if (this.ratio_ === -Infinity || this.ratio_ === Infinity || isNaN(this.ratio_)) { this.ratio_ = 0; } var innerLength = hostMetrics.viewHeight * this.ratio_; var innerOffset = (hostMetrics.viewTop - hostMetrics.contentTop) * this.ratio_; this.svgKnob_.setAttribute('height', Math.max(0, innerLength)); this.xCoordinate = hostMetrics.absoluteLeft; if (!Blockly.RTL) { this.xCoordinate += hostMetrics.viewWidth - Blockly.Scrollbar.scrollbarThickness; } this.yCoordinate = hostMetrics.absoluteTop; this.svgGroup_.setAttribute('transform', 'translate(' + this.xCoordinate + ', ' + this.yCoordinate + ')'); this.svgBackground_.setAttribute('height', Math.max(0, outerLength)); this.svgKnob_.setAttribute('y', this.constrainKnob_(innerOffset)); } // Resizing may have caused some scrolling. //this.onScroll_(); }; /** * Create all the DOM elements required for a scrollbar. * The resulting widget is not sized. * @private */ Blockly.ScrollbarSvg.prototype.createDom_ = function() { /* Create the following DOM: */ this.svgGroup_ = Blockly.createSvgElement('g', {}, null); this.svgBackground_ = Blockly.createSvgElement('rect', {'class': 'blocklyScrollbarBackground'}, this.svgGroup_); var radius = Math.floor((Blockly.Scrollbar.scrollbarThickness - 6) / 2); this.svgKnob_ = Blockly.createSvgElement('rect', {'class': 'blocklyScrollbarKnob', 'rx': radius, 'ry': radius}, this.svgGroup_); Blockly.Scrollbar.insertAfter_(this.svgGroup_, this.workspace_.getBubbleCanvas()); }; /** * Is the scrollbar visible. Non-paired scrollbars disappear when they aren't * needed. * @return {boolean} True if visible. */ Blockly.ScrollbarSvg.prototype.isVisible = function() { return this.svgGroup_.getAttribute('display') != 'none'; }; /** * Set whether the scrollbar is visible. * Only applies to non-paired scrollbars. * @param {boolean} visible True if visible. */ Blockly.ScrollbarSvg.prototype.setVisible = function(visible) { if (visible == this.isVisible()) { return; } // Ideally this would also apply to scrollbar pairs, but that's a bigger // headache (due to interactions with the corner square). if (this.pair_) { throw 'Unable to toggle visibility of paired scrollbars.'; } if (visible) { this.svgGroup_.setAttribute('display', 'block'); } else { // Hide the scrollbar. this.workspace_.setMetrics({x: 0, y: 0}); this.svgGroup_.setAttribute('display', 'none'); } }; /** * Scroll by one pageful. * Called when scrollbar background is clicked. * @param {!Event} e Mouse down event. * @private */ Blockly.ScrollbarSvg.prototype.onMouseDownBar_ = function(e) { Blockly.hideChaff(true); if (Blockly.isRightButton(e)) { // Right-click. // Scrollbars have no context menu. e.stopPropagation(); return; } var mouseXY = Blockly.mouseToSvg(e); var mouseLocation = this.horizontal_ ? mouseXY.x : mouseXY.y; var knobXY = Blockly.getSvgXY_(this.svgKnob_); var knobStart = this.horizontal_ ? knobXY.x : knobXY.y; var knobLength = parseFloat( this.svgKnob_.getAttribute(this.horizontal_ ? 'width' : 'height')); var knobValue = parseFloat( this.svgKnob_.getAttribute(this.horizontal_ ? 'x' : 'y')); var pageLength = knobLength * 0.95; if (mouseLocation <= knobStart) { // Decrease the scrollbar's value by a page. knobValue -= pageLength; } else if (mouseLocation >= knobStart + knobLength) { // Increase the scrollbar's value by a page. knobValue += pageLength; } this.svgKnob_.setAttribute(this.horizontal_ ? 'x' : 'y', this.constrainKnob_(knobValue)); this.onScroll_(); e.stopPropagation(); }; /** * Start a dragging operation. * Called when scrollbar knob is clicked. * @param {!Event} e Mouse down event. * @private */ Blockly.ScrollbarSvg.prototype.onMouseDownKnob_ = function(e) { Blockly.hideChaff(true); this.onMouseUpKnob_(); if (Blockly.isRightButton(e)) { // Right-click. // Scrollbars have no context menu. e.stopPropagation(); return; } // Look up the current translation and record it. this.startDragKnob = parseFloat( this.svgKnob_.getAttribute(this.horizontal_ ? 'x' : 'y')); // Record the current mouse position. this.startDragMouse = this.horizontal_ ? e.clientX : e.clientY; Blockly.ScrollbarSvg.onMouseUpWrapper_ = Blockly.bindEvent_(document, 'mouseup', this, this.onMouseUpKnob_); Blockly.ScrollbarSvg.onMouseMoveWrapper_ = Blockly.bindEvent_(document, 'mousemove', this, this.onMouseMoveKnob_); e.stopPropagation(); }; /** * Drag the scrollbar's knob. * @param {!Event} e Mouse up event. * @private */ Blockly.ScrollbarSvg.prototype.onMouseMoveKnob_ = function(e) { var currentMouse = this.horizontal_ ? e.clientX : e.clientY; var mouseDelta = currentMouse - this.startDragMouse; var knobValue = this.startDragKnob + mouseDelta; // Position the bar. this.svgKnob_.setAttribute(this.horizontal_ ? 'x' : 'y', this.constrainKnob_(knobValue)); this.onScroll_(); }; /** * Stop binding to the global mouseup and mousemove events. * @private */ Blockly.ScrollbarSvg.prototype.onMouseUpKnob_ = function() { if (Blockly.ScrollbarSvg.onMouseUpWrapper_) { Blockly.unbindEvent_(Blockly.ScrollbarSvg.onMouseUpWrapper_); Blockly.ScrollbarSvg.onMouseUpWrapper_ = null; } if (Blockly.ScrollbarSvg.onMouseMoveWrapper_) { Blockly.unbindEvent_(Blockly.ScrollbarSvg.onMouseMoveWrapper_); Blockly.ScrollbarSvg.onMouseMoveWrapper_ = null; } }; /** * Constrain the knob's position within the minimum (0) and maximum * (length of scrollbar) values allowed for the scrollbar. * @param {number} value Value that is potentially out of bounds. * @return {number} Constrained value. * @private */ Blockly.ScrollbarSvg.prototype.constrainKnob_ = function(value) { if (value <= 0 || isNaN(value)) { value = 0; } else { var axis = this.horizontal_ ? 'width' : 'height'; var barLength = parseFloat(this.svgBackground_.getAttribute(axis)); var knobLength = parseFloat(this.svgKnob_.getAttribute(axis)); value = Math.min(value, barLength - knobLength); } return value; }; /** * Called when scrollbar is moved. * @private */ Blockly.ScrollbarSvg.prototype.onScroll_ = function() { var knobValue = parseFloat( this.svgKnob_.getAttribute(this.horizontal_ ? 'x' : 'y')); var barLength = parseFloat( this.svgBackground_.getAttribute(this.horizontal_ ? 'width' : 'height')); var ratio = knobValue / barLength; if (isNaN(ratio)) { ratio = 0; } var xyRatio = {}; if (this.horizontal_) { xyRatio.x = ratio; } else { xyRatio.y = ratio; } this.workspace_.setMetrics(xyRatio); Blockly.hideChaff(true); }; /** * Set the scrollbar slider's position. * @param {number} value The distance from the top/left end of the bar. * @param {boolean} fireEvents True if onScroll events should be fired. */ Blockly.ScrollbarSvg.prototype.set = function(value, fireEvents) { // Move the scrollbar slider. this.svgKnob_.setAttribute(this.horizontal_ ? 'x' : 'y', value * this.ratio_); if (fireEvents) { this.onScroll_(); } }; // -------------------------------------------------------------------- /** * Choose between the native and the SVG implementations. The native one is * preferred, provided that the browser supports it. * To test, see: tests/native_scrollbar_test.html * Known good user agents: * Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0.2) * Gecko/20100101 Firefox/10.0.2 * Mozilla/5.0 (Ubuntu; X11; Linux x86_64; rv:9.0.1) * Gecko/20100101 Firefox/9.0.1 */ //if (goog.userAgent.GECKO && //(goog.userAgent.MAC || goog.userAgent.LINUX)) { /** * Class for a scrollbar. */ Blockly.Scrollbar = Blockly.ScrollbarSvg; /** * Width of vertical scrollbar or height of horizontal scrollbar. */ Blockly.Scrollbar.scrollbarThickness = 15; /** * Insert a node after a reference node. * Contrast with node.insertBefore function. * @param {!Element} newNode New element to insert. * @param {!Element} refNode Existing element to precede new node. * @private */ Blockly.Scrollbar.insertAfter_ = function(newNode, refNode) { var siblingNode = refNode.nextSibling; var parentNode = refNode.parentNode; if (!parentNode) { throw 'Reference node has no parent.'; } if (siblingNode) { parentNode.insertBefore(newNode, siblingNode); } else { parentNode.appendChild(newNode); } }; ================================================ FILE: extern/blockly/core/toolbox.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Toolbox from whence to create blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Toolbox'); goog.require('Blockly.Flyout'); goog.require('goog.events.BrowserFeature'); goog.require('goog.style'); goog.require('goog.ui.tree.TreeControl'); goog.require('goog.ui.tree.TreeNode'); /** * Width of the toolbox. * @type {number} */ Blockly.Toolbox.width = 0; /** * The SVG group currently selected. * @type {SVGGElement} * @private */ Blockly.Toolbox.selectedOption_ = null; /** * Configuration constants for Closure's tree UI. * @type {Object.} * @const * @private */ Blockly.Toolbox.CONFIG_ = { indentWidth: 19, cssRoot: 'blocklyTreeRoot', cssHideRoot: 'blocklyHidden', cssItem: '', cssTreeRow: 'blocklyTreeRow', cssItemLabel: 'blocklyTreeLabel', cssTreeIcon: 'blocklyTreeIcon', cssExpandedFolderIcon: 'blocklyTreeIconOpen', cssFileIcon: 'blocklyTreeIconNone', cssSelectedRow: 'blocklyTreeSelected' }; /** * Creates the toolbox's DOM. Only needs to be called once. * @param {!Element} svg The top-level SVG element. * @param {!Element} container The SVG's HTML parent element. */ Blockly.Toolbox.createDom = function(svg, container) { // Create an HTML container for the Toolbox menu. Blockly.Toolbox.HtmlDiv = goog.dom.createDom('div', 'blocklyToolboxDiv'); Blockly.Toolbox.HtmlDiv.setAttribute('dir', Blockly.RTL ? 'RTL' : 'LTR'); container.appendChild(Blockly.Toolbox.HtmlDiv); /** * @type {!Blockly.Flyout} * @private */ Blockly.Toolbox.flyout_ = new Blockly.Flyout(); //Blockly.Toolbox.flyout_.hide = function() {}; svg.appendChild(Blockly.Toolbox.flyout_.createDom()); // Clicking on toolbar closes popups. Blockly.bindEvent_(Blockly.Toolbox.HtmlDiv, 'mousedown', null, function(e) { if (Blockly.isRightButton(e) || e.target == Blockly.Toolbox.HtmlDiv) { // Close flyout. Blockly.hideChaff(false); } else { // Just close popups. Blockly.hideChaff(true); } }); }; /** * Initializes the toolbox. */ Blockly.Toolbox.init = function() { Blockly.Toolbox.CONFIG_['cleardotPath'] = Blockly.pathToBlockly + 'media/1x1.gif'; Blockly.Toolbox.CONFIG_['cssCollapsedFolderIcon'] = 'blocklyTreeIconClosed' + (Blockly.RTL ? 'Rtl' : 'Ltr'); var tree = new Blockly.Toolbox.TreeControl('root', Blockly.Toolbox.CONFIG_); Blockly.Toolbox.tree_ = tree; tree.setShowRootNode(false); tree.setShowLines(false); tree.setShowExpandIcons(false); tree.setSelectedItem(null); Blockly.Toolbox.HtmlDiv.style.display = 'block'; Blockly.Toolbox.flyout_.init(Blockly.mainWorkspace, true); Blockly.Toolbox.populate_(); tree.render(Blockly.Toolbox.HtmlDiv); // If the document resizes, reposition the toolbox. goog.events.listen(window, goog.events.EventType.RESIZE, Blockly.Toolbox.position_); Blockly.Toolbox.position_(); }; /** * Move the toolbox to the edge. * @private */ Blockly.Toolbox.position_ = function() { var treeDiv = Blockly.Toolbox.HtmlDiv; var svgBox = goog.style.getBorderBox(Blockly.svg); var svgSize = Blockly.svgSize(); if (Blockly.RTL) { var xy = Blockly.convertCoordinates(0, 0, false); treeDiv.style.left = (xy.x + svgSize.width - treeDiv.offsetWidth) + 'px'; } else { treeDiv.style.marginLeft = svgBox.left; } treeDiv.style.height = (svgSize.height + 1) + 'px'; Blockly.Toolbox.width = treeDiv.offsetWidth; if (!Blockly.RTL) { // For some reason the LTR toolbox now reports as 1px too wide. Blockly.Toolbox.width -= 1; } }; /** * Fill the toolbox with categories and blocks. * @private */ Blockly.Toolbox.populate_ = function() { var rootOut = Blockly.Toolbox.tree_; rootOut.blocks = []; function syncTrees(treeIn, treeOut) { for (var i = 0, childIn; childIn = treeIn.childNodes[i]; i++) { if (!childIn.tagName) { // Skip over text. continue; } var name = childIn.tagName.toUpperCase(); if (name == 'CATEGORY') { var childOut = rootOut.createNode(childIn.getAttribute('name')); childOut.blocks = []; treeOut.add(childOut); var custom = childIn.getAttribute('custom'); if (custom) { // Variables and procedures have special categories that are dynamic. childOut.blocks = custom; } else { syncTrees(childIn, childOut); } } else if (name == 'BLOCK') { treeOut.blocks.push(childIn); } } } syncTrees(Blockly.languageTree, Blockly.Toolbox.tree_); if (rootOut.blocks.length) { throw 'Toolbox cannot have both blocks and categories in the root level.'; } // Fire a resize event since the toolbox may have changed width and height. Blockly.fireUiEvent(window, 'resize'); }; /** * Unhighlight any previously specified option. */ Blockly.Toolbox.clearSelection = function() { Blockly.Toolbox.tree_.setSelectedItem(null); }; // Extending Closure's Tree UI. /** * Extention of a TreeControl object that uses a custom tree node. * @param {string} html The HTML content of the node label. * @param {Object=} opt_config The configuration for the tree. See * goog.ui.tree.TreeControl.DefaultConfig. If not specified, a default config * will be used. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper. * @constructor * @extends {goog.ui.tree.TreeControl} */ Blockly.Toolbox.TreeControl = function(html, opt_config, opt_domHelper) { goog.ui.tree.TreeControl.call(this, html, opt_config, opt_domHelper); }; goog.inherits(Blockly.Toolbox.TreeControl, goog.ui.tree.TreeControl); /** * Adds touch handling to TreeControl. * @override */ Blockly.Toolbox.TreeControl.prototype.enterDocument = function() { Blockly.Toolbox.TreeControl.superClass_.enterDocument.call(this); // Add touch handler. if (goog.events.BrowserFeature.TOUCH_ENABLED) { var el = this.getElement(); Blockly.bindEvent_(el, goog.events.EventType.TOUCHSTART, this, this.handleTouchEvent_); } }; /** * Handles touch events. * @param {!goog.events.BrowserEvent} e The browser event. * @private */ Blockly.Toolbox.TreeControl.prototype.handleTouchEvent_ = function(e) { e.preventDefault(); var node = this.getNodeFromEvent_(e); if (node && e.type === goog.events.EventType.TOUCHSTART) { // Fire asynchronously since onMouseDown takes long enough that the browser // would fire the default mouse event before this method returns. window.setTimeout(function() { node.onMouseDown(e); // Same behavior for click and touch. }, 1); } }; /** * Creates a new tree node using a custom tree node. * @param {string} html The html content of the node label. * @return {goog.ui.tree.TreeNode} The new item. * @override */ Blockly.Toolbox.TreeControl.prototype.createNode = function(html) { return new Blockly.Toolbox.TreeNode(html || '', this.getConfig(), this.getDomHelper()); }; /** * Display/hide the flyout when an item is selected. * @param {goog.ui.tree.BaseNode} node The item to select. * @override */ Blockly.Toolbox.TreeControl.prototype.setSelectedItem = function(node) { if (this.selectedItem_ == node) { return; } goog.ui.tree.TreeControl.prototype.setSelectedItem.call(this, node); if (node && node.blocks && node.blocks.length) { Blockly.Toolbox.flyout_.show(node.blocks); } else { // Hide the flyout. Blockly.Toolbox.flyout_.hide(); } }; /** * An single node in the tree, customized for Blockly's UI. * @param {string} html The html content of the node label. * @param {Object=} opt_config The configuration for the tree. See * goog.ui.tree.TreeControl.DefaultConfig. If not specified, a default config * will be used. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper. * @constructor * @extends {goog.ui.tree.TreeNode} */ Blockly.Toolbox.TreeNode = function(html, opt_config, opt_domHelper) { goog.ui.tree.TreeNode.call(this, html, opt_config, opt_domHelper); var resize = function() { Blockly.fireUiEvent(window, 'resize'); }; // Fire a resize event since the toolbox may have changed width. goog.events.listen(Blockly.Toolbox.tree_, goog.ui.tree.BaseNode.EventType.EXPAND, resize); goog.events.listen(Blockly.Toolbox.tree_, goog.ui.tree.BaseNode.EventType.COLLAPSE, resize); }; goog.inherits(Blockly.Toolbox.TreeNode, goog.ui.tree.TreeNode); /** * Do not show the +/- icon. * @return {string} The source for the icon. * @override */ Blockly.Toolbox.TreeNode.prototype.getExpandIconHtml = function() { return ''; }; /** * Supress population of the +/- icon. * @return {null} Null. * @protected * @override */ Blockly.Toolbox.TreeNode.prototype.getExpandIconElement = function() { return null; }; /** * Expand or collapse the node on mouse click. * @param {!goog.events.BrowserEvent} e The browser event. * @override */ Blockly.Toolbox.TreeNode.prototype.onMouseDown = function(e) { // Expand icon. if (this.hasChildren() && this.isUserCollapsible_) { this.toggle(); this.select(); } else if (this.isSelected()) { this.getTree().setSelectedItem(null); } else { this.select(); } this.updateRow(); }; /** * Supress the inherited double-click behaviour. * @param {!goog.events.BrowserEvent} e The browser event. * @override * @private */ Blockly.Toolbox.TreeNode.prototype.onDoubleClick_ = function(e) { // NOP. }; ================================================ FILE: extern/blockly/core/tooltip.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Library to create tooltips for Blockly. * First, call Blockly.Tooltip.init() after onload. * Second, set the 'tooltip' property on any SVG element that needs a tooltip. * If the tooltip is a string, then that message will be displayed. * If the tooltip is an SVG element, then that object's tooltip will be used. * Third, call Blockly.Tooltip.bindMouseEvents(e) passing the SVG element. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Tooltip'); /** * Is a tooltip currently showing? */ Blockly.Tooltip.visible = false; /** * PID of suspended thread to clear tooltip on mouse out. * @private */ Blockly.Tooltip.mouseOutPid_ = 0; /** * PID of suspended thread to show the tooltip. * @private */ Blockly.Tooltip.showPid_ = 0; /** * Last observed location of the mouse pointer (freezes when tooltip appears). * @private */ Blockly.Tooltip.lastXY_ = {x: 0, y: 0}; /** * Current element being pointed at. * @private */ Blockly.Tooltip.element_ = null; /** * Once a tooltip has opened for an element, that element is 'poisoned' and * cannot respawn a tooltip until the pointer moves over a different element. * @private */ Blockly.Tooltip.poisonedElement_ = null; /** * Tooltip's SVG group element. * @type {Element} * @private */ Blockly.Tooltip.svgGroup_ = null; /** * Tooltip's SVG text element. * @type {SVGTextElement} * @private */ Blockly.Tooltip.svgText_ = null; /** * Tooltip's SVG background rectangle. * @type {Element} * @private */ Blockly.Tooltip.svgBackground_ = null; /** * Tooltip's SVG shadow rectangle. * @type {Element} * @private */ Blockly.Tooltip.svgShadow_ = null; /** * Horizontal offset between mouse cursor and tooltip. */ Blockly.Tooltip.OFFSET_X = 0; /** * Vertical offset between mouse cursor and tooltip. */ Blockly.Tooltip.OFFSET_Y = 10; /** * Radius mouse can move before killing tooltip. */ Blockly.Tooltip.RADIUS_OK = 10; /** * Delay before tooltip appears. */ Blockly.Tooltip.HOVER_MS = 1000; /** * Horizontal padding between text and background. */ Blockly.Tooltip.MARGINS = 5; /** * Create the tooltip elements. Only needs to be called once. * @return {!SVGGElement} The tooltip's SVG group. */ Blockly.Tooltip.createDom = function() { /* */ var svgGroup = /** @type {!SVGGElement} */ ( Blockly.createSvgElement('g', {'class': 'blocklyHidden'}, null)); Blockly.Tooltip.svgGroup_ = svgGroup; Blockly.Tooltip.svgShadow_ = /** @type {!SVGRectElement} */ ( Blockly.createSvgElement( 'rect', {'class': 'blocklyTooltipShadow', 'x': 2, 'y': 2}, svgGroup)); Blockly.Tooltip.svgBackground_ = /** @type {!SVGRectElement} */ ( Blockly.createSvgElement( 'rect', {'class': 'blocklyTooltipBackground'}, svgGroup)); Blockly.Tooltip.svgText_ = /** @type {!SVGTextElement} */ ( Blockly.createSvgElement( 'text', {'class': 'blocklyTooltipText'}, svgGroup)); return svgGroup; }; /** * Binds the required mouse events onto an SVG element. * @param {!Element} element SVG element onto which tooltip is to be bound. */ Blockly.Tooltip.bindMouseEvents = function(element) { Blockly.bindEvent_(element, 'mouseover', null, Blockly.Tooltip.onMouseOver_); Blockly.bindEvent_(element, 'mouseout', null, Blockly.Tooltip.onMouseOut_); Blockly.bindEvent_(element, 'mousemove', null, Blockly.Tooltip.onMouseMove_); }; /** * Hide the tooltip if the mouse is over a different object. * Initialize the tooltip to potentially appear for this object. * @param {!Event} e Mouse event. * @private */ Blockly.Tooltip.onMouseOver_ = function(e) { // If the tooltip is an object, treat it as a pointer to the next object in // the chain to look at. Terminate when a string or function is found. var element = e.target; while (!goog.isString(element.tooltip) && !goog.isFunction(element.tooltip)) { element = element.tooltip; } if (Blockly.Tooltip.element_ != element) { Blockly.Tooltip.hide(); Blockly.Tooltip.poisonedElement_ = null; Blockly.Tooltip.element_ = element; } // Forget about any immediately preceeding mouseOut event. window.clearTimeout(Blockly.Tooltip.mouseOutPid_); }; /** * Hide the tooltip if the mouse leaves the object and enters the workspace. * @param {!Event} e Mouse event. * @private */ Blockly.Tooltip.onMouseOut_ = function(e) { // Moving from one element to another (overlapping or with no gap) generates // a mouseOut followed instantly by a mouseOver. Fork off the mouseOut // event and kill it if a mouseOver is received immediately. // This way the task only fully executes if mousing into the void. Blockly.Tooltip.mouseOutPid_ = window.setTimeout(function() { Blockly.Tooltip.element_ = null; Blockly.Tooltip.poisonedElement_ = null; Blockly.Tooltip.hide(); }, 1); window.clearTimeout(Blockly.Tooltip.showPid_); }; /** * When hovering over an element, schedule a tooltip to be shown. If a tooltip * is already visible, hide it if the mouse strays out of a certain radius. * @param {!Event} e Mouse event. * @private */ Blockly.Tooltip.onMouseMove_ = function(e) { if (!Blockly.Tooltip.element_ || !Blockly.Tooltip.element_.tooltip) { // No tooltip here to show. return; } else if ((Blockly.ContextMenu && Blockly.ContextMenu.visible) || Blockly.Block.dragMode_ != 0) { // Don't display a tooltip when a context menu is active, or during a drag. return; } if (Blockly.Tooltip.visible) { // Compute the distance between the mouse position when the tooltip was // shown and the current mouse position. Pythagorean theorem. var mouseXY = Blockly.mouseToSvg(e); var dx = Blockly.Tooltip.lastXY_.x - mouseXY.x; var dy = Blockly.Tooltip.lastXY_.y - mouseXY.y; var dr = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); if (dr > Blockly.Tooltip.RADIUS_OK) { Blockly.Tooltip.hide(); } } else if (Blockly.Tooltip.poisonedElement_ != Blockly.Tooltip.element_) { // The mouse moved, clear any previously scheduled tooltip. window.clearTimeout(Blockly.Tooltip.showPid_); // Maybe this time the mouse will stay put. Schedule showing of tooltip. Blockly.Tooltip.lastXY_ = Blockly.mouseToSvg(e); Blockly.Tooltip.showPid_ = window.setTimeout(Blockly.Tooltip.show_, Blockly.Tooltip.HOVER_MS); } }; /** * Hide the tooltip. */ Blockly.Tooltip.hide = function() { if (Blockly.Tooltip.visible) { Blockly.Tooltip.visible = false; if (Blockly.Tooltip.svgGroup_) { Blockly.Tooltip.svgGroup_.style.display = 'none'; } } window.clearTimeout(Blockly.Tooltip.showPid_); }; /** * Create the tooltip and show it. * @private */ Blockly.Tooltip.show_ = function() { Blockly.Tooltip.poisonedElement_ = Blockly.Tooltip.element_; if (!Blockly.Tooltip.svgGroup_) { return; } // Erase all existing text. goog.dom.removeChildren( /** @type {!Element} */ (Blockly.Tooltip.svgText_)); // Create new text, line by line. var tip = Blockly.Tooltip.element_.tooltip; if (goog.isFunction(tip)) { tip = tip(); } var lines = tip.split('\n'); for (var i = 0; i < lines.length; i++) { var tspanElement = Blockly.createSvgElement('tspan', {'dy': '1em', 'x': Blockly.Tooltip.MARGINS}, Blockly.Tooltip.svgText_); var textNode = document.createTextNode(lines[i]); tspanElement.appendChild(textNode); } // Display the tooltip. Blockly.Tooltip.visible = true; Blockly.Tooltip.svgGroup_.style.display = 'block'; // Resize the background and shadow to fit. var bBox = Blockly.Tooltip.svgText_.getBBox(); var width = 2 * Blockly.Tooltip.MARGINS + bBox.width; var height = bBox.height; Blockly.Tooltip.svgBackground_.setAttribute('width', width); Blockly.Tooltip.svgBackground_.setAttribute('height', height); Blockly.Tooltip.svgShadow_.setAttribute('width', width); Blockly.Tooltip.svgShadow_.setAttribute('height', height); if (Blockly.RTL) { // Right-align the paragraph. // This cannot be done until the tooltip is rendered on screen. var maxWidth = bBox.width; for (var x = 0, textElement; textElement = Blockly.Tooltip.svgText_.childNodes[x]; x++) { textElement.setAttribute('text-anchor', 'end'); textElement.setAttribute('x', maxWidth + Blockly.Tooltip.MARGINS); } } // Move the tooltip to just below the cursor. var anchorX = Blockly.Tooltip.lastXY_.x; if (Blockly.RTL) { anchorX -= Blockly.Tooltip.OFFSET_X + width; } else { anchorX += Blockly.Tooltip.OFFSET_X; } var anchorY = Blockly.Tooltip.lastXY_.y + Blockly.Tooltip.OFFSET_Y; var svgSize = Blockly.svgSize(); if (anchorY + bBox.height > svgSize.height) { // Falling off the bottom of the screen; shift the tooltip up. anchorY -= bBox.height + 2 * Blockly.Tooltip.OFFSET_Y; } if (Blockly.RTL) { // Prevent falling off left edge in RTL mode. anchorX = Math.max(Blockly.Tooltip.MARGINS, anchorX); } else { if (anchorX + bBox.width > svgSize.width - 2 * Blockly.Tooltip.MARGINS) { // Falling off the right edge of the screen; // clamp the tooltip on the edge. anchorX = svgSize.width - bBox.width - 2 * Blockly.Tooltip.MARGINS; } } Blockly.Tooltip.svgGroup_.setAttribute('transform', 'translate(' + anchorX + ',' + anchorY + ')'); }; ================================================ FILE: extern/blockly/core/trashcan.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Object representing a trash can icon. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Trashcan'); goog.require('goog.Timer'); /** * Class for a trash can. * @param {!Blockly.Workspace} workspace The workspace to sit in. * @constructor */ Blockly.Trashcan = function(workspace) { this.workspace_ = workspace; }; /** * URL of the trashcan image (minus lid). * @type {string} * @private */ Blockly.Trashcan.prototype.BODY_URL_ = '/media/trashbody.png'; /** * URL of the lid image. * @type {string} * @private */ Blockly.Trashcan.prototype.LID_URL_ = '/media/trashlid.png'; /** * Width of both the trash can and lid images. * @type {number} * @private */ Blockly.Trashcan.prototype.WIDTH_ = 57; /** * Height of the trashcan image (minus lid). * @type {number} * @private */ Blockly.Trashcan.prototype.BODY_HEIGHT_ = 55; /** * Height of the lid image. * @type {number} * @private */ Blockly.Trashcan.prototype.LID_HEIGHT_ = 18; /** * Distance between trashcan and bottom edge of workspace. * @type {number} * @private */ Blockly.Trashcan.prototype.MARGIN_BOTTOM_ = 55; /** * Distance between trashcan and right edge of workspace. * @type {number} * @private */ Blockly.Trashcan.prototype.MARGIN_SIDE_ = 55; /** * Current open/close state of the lid. * @type {boolean} */ Blockly.Trashcan.prototype.isOpen = false; /** * The SVG group containing the trash can. * @type {Element} * @private */ Blockly.Trashcan.prototype.svgGroup_ = null; /** * The SVG image element of the trash can body. * @type {Element} * @private */ Blockly.Trashcan.prototype.svgBody_ = null; /** * The SVG image element of the trash can lid. * @type {Element} * @private */ Blockly.Trashcan.prototype.svgLid_ = null; /** * Task ID of opening/closing animation. * @type {number} * @private */ Blockly.Trashcan.prototype.lidTask_ = 0; /** * Current angle of the lid. * @type {number} * @private */ Blockly.Trashcan.prototype.lidAngle_ = 0; /** * Left coordinate of the trash can. * @type {number} * @private */ Blockly.Trashcan.prototype.left_ = 0; /** * Top coordinate of the trash can. * @type {number} * @private */ Blockly.Trashcan.prototype.top_ = 0; /** * Create the trash can elements. * @return {!Element} The trash can's SVG group. */ Blockly.Trashcan.prototype.createDom = function() { /* */ this.svgGroup_ = Blockly.createSvgElement('g', {'filter': 'url(#blocklyTrashcanShadowFilter)'}, null); Blockly.bindEvent_(this.svgGroup_, 'mousedown', this, function(e) { if (Blockly.isRightButton(e)) { console.log('hi'); document.getElementById('entryBlockly').style.background = 'white'; } }); this.svgBody_ = Blockly.createSvgElement('image', {'width': this.WIDTH_, 'height': this.BODY_HEIGHT_}, this.svgGroup_); this.svgBody_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', Blockly.mediaFilePath + this.BODY_URL_); this.svgBody_.setAttribute('y', this.LID_HEIGHT_); this.svgLid_ = Blockly.createSvgElement('image', {'width': this.WIDTH_, 'height': this.LID_HEIGHT_}, this.svgGroup_); this.svgLid_.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', Blockly.mediaFilePath + this.LID_URL_); return this.svgGroup_; }; /** * Initialize the trash can. */ Blockly.Trashcan.prototype.init = function() { this.setOpen_(false); this.position_(); // If the document resizes, reposition the trash can. Blockly.bindEvent_(window, 'resize', this, this.position_); }; /** * Dispose of this trash can. * Unlink from all DOM elements to prevent memory leaks. */ Blockly.Trashcan.prototype.dispose = function() { if (this.svgGroup_) { goog.dom.removeNode(this.svgGroup_); this.svgGroup_ = null; } this.svgBody_ = null; this.svgLid_ = null; this.workspace_ = null; goog.Timer.clear(this.lidTask_); }; /** * Move the trash can to the bottom-right corner. * @private */ Blockly.Trashcan.prototype.position_ = function() { var metrics = this.workspace_.getMetrics(); if (!metrics) { // There are no metrics available (workspace is probably not visible). return; } if (Blockly.RTL) { this.left_ = this.MARGIN_SIDE_; } else { this.left_ = metrics.viewWidth + metrics.absoluteLeft - this.WIDTH_ - this.MARGIN_SIDE_; } this.top_ = metrics.viewHeight + metrics.absoluteTop - (this.BODY_HEIGHT_ + this.LID_HEIGHT_) - this.MARGIN_BOTTOM_; this.svgGroup_.setAttribute('transform', 'translate(' + this.left_ + ',' + this.top_ + ')'); }; /** * Determines if the mouse is currently over the trash can. * Opens/closes the lid and sets the isOpen flag. * @param {!Event} e Mouse move event. */ Blockly.Trashcan.prototype.onMouseMove = function(e) { /* An alternative approach would be to use onMouseOver and onMouseOut events. However the selected block will be between the mouse and the trash can, thus these events won't fire. Another approach is to use HTML5's drag & drop API, but it's widely hated. Instead, we'll just have the block's drag_ function call us. */ if (!this.svgGroup_) { return; } var mouseXY = Blockly.mouseToSvg(e); var trashXY = Blockly.getSvgXY_(this.svgGroup_); var over = (mouseXY.x + 25 > trashXY.x) && (mouseXY.x < trashXY.x + this.WIDTH_ + 25 ) && (mouseXY.y + 25 > trashXY.y) && (mouseXY.y < trashXY.y + this.BODY_HEIGHT_ + this.LID_HEIGHT_ + 25 ); // For bonus points we might want to match the trapezoidal outline. if (this.isOpen != over) { this.setOpen_(over); } }; /** * Flip the lid open or shut. * @param {boolean} state True if open. * @private */ Blockly.Trashcan.prototype.setOpen_ = function(state) { if (this.isOpen == state) { return; } goog.Timer.clear(this.lidTask_); this.isOpen = state; this.animateLid_(); }; /** * Rotate the lid open or closed by one step. Then wait and recurse. * @private */ Blockly.Trashcan.prototype.animateLid_ = function() { this.lidAngle_ += this.isOpen ? 10 : -10; this.lidAngle_ = Math.max(0, this.lidAngle_); this.svgLid_.setAttribute('transform', 'rotate(' + (Blockly.RTL ? -this.lidAngle_ : this.lidAngle_) + ', ' + (Blockly.RTL ? 4 : this.WIDTH_ - 4) + ', ' + (this.LID_HEIGHT_ - 2) + ')'); if (this.isOpen ? (this.lidAngle_ < 45) : (this.lidAngle_ > 0)) { this.lidTask_ = goog.Timer.callOnce(this.animateLid_, 5, this); } }; /** * Flip the lid shut. * Called externally after a drag. */ Blockly.Trashcan.prototype.close = function() { this.setOpen_(false); }; ================================================ FILE: extern/blockly/core/utils.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Utility methods. * These methods are not specific to Blockly, and could be factored out if * a JavaScript framework such as Closure were used. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.utils'); /** * Add a CSS class to a element. * Similar to Closure's goog.dom.classes.add, except it handles SVG elements. * @param {!Element} element DOM element to add class to. * @param {string} className Name of class to add. * @private */ Blockly.addClass_ = function(element, className) { var classes = element.getAttribute('class') || ''; if ((' ' + classes + ' ').indexOf(' ' + className + ' ') == -1) { if (classes) { classes += ' '; } element.setAttribute('class', classes + className); } }; /** * Remove a CSS class from a element. * Similar to Closure's goog.dom.classes.remove, except it handles SVG elements. * @param {!Element} element DOM element to remove class from. * @param {string} className Name of class to remove. * @private */ Blockly.removeClass_ = function(element, className) { var classes = element.getAttribute('class'); if ((' ' + classes + ' ').indexOf(' ' + className + ' ') != -1) { var classList = classes.split(/\s+/); for (var i = 0; i < classList.length; i++) { if (!classList[i] || classList[i] == className) { classList.splice(i, 1); i--; } } if (classList.length) { element.setAttribute('class', classList.join(' ')); } else { element.removeAttribute('class'); } } }; /** * Bind an event to a function call. * @param {!Element} element Element upon which to listen. * @param {string} name Event name to listen to (e.g. 'mousedown'). * @param {Object} thisObject The value of 'this' in the function. * @param {!Function} func Function to call when event is triggered. * @return {!Array.} Opaque data that can be passed to unbindEvent_. * @private */ Blockly.bindEvent_ = function(element, name, thisObject, func) { var bindData = []; var wrapFunc; if (!element.addEventListener) { throw 'Element is not a DOM node with addEventListener.'; } wrapFunc = function(e) { func.apply(thisObject, arguments); }; element.addEventListener(name, wrapFunc, false); bindData.push([element, name, wrapFunc]); // Add equivalent touch event. if (name in Blockly.bindEvent_.TOUCH_MAP) { wrapFunc = function(e) { // Punt on multitouch events. if (e.changedTouches.length == 1) { // Map the touch event's properties to the event. var touchPoint = e.changedTouches[0]; e.clientX = touchPoint.clientX; e.clientY = touchPoint.clientY; } func.apply(thisObject, arguments); // Stop the browser from scrolling/zooming the page if (Entry && Entry.type == 'phone') { var scroll = $(window).scrollTop(); var element = $(Entry.playground.blocklyView_); var position = element.offset(); if (e.clientY > position.top - scroll && e.clientY < position.top - scroll + element.height() && e.clientX > position.left && e.clientX < position.left + element.width()) e.preventDefault(); } else { e.preventDefault(); } }; element.addEventListener(Blockly.bindEvent_.TOUCH_MAP[name], wrapFunc, false); bindData.push([element, Blockly.bindEvent_.TOUCH_MAP[name], wrapFunc]); } return bindData; }; /** * The TOUCH_MAP lookup dictionary specifies additional touch events to fire, * in conjunction with mouse events. * @type {Object} */ Blockly.bindEvent_.TOUCH_MAP = {}; if ('ontouchstart' in document.documentElement) { Blockly.bindEvent_.TOUCH_MAP = { mousedown: 'touchstart', mousemove: 'touchmove', mouseup: 'touchend' }; } /** * Unbind one or more events event from a function call. * @param {!Array.} bindData Opaque data from bindEvent_. This list is * emptied during the course of calling this function. * @return {!Function} The function call. * @private */ Blockly.unbindEvent_ = function(bindData) { while (bindData.length) { var bindDatum = bindData.pop(); var element = bindDatum[0]; var name = bindDatum[1]; var func = bindDatum[2]; element.removeEventListener(name, func, false); } return func; }; /** * Fire a synthetic event. * @param {!Element} element The event's target element. * @param {string} eventName Name of event (e.g. 'click'). */ Blockly.fireUiEvent = function(element, eventName) { var doc = document; if (doc.createEvent) { // W3 var evt = doc.createEvent('UIEvents'); evt.initEvent(eventName, true, true); // event type, bubbling, cancelable element.dispatchEvent(evt); } else if (doc.createEventObject) { // MSIE var evt = doc.createEventObject(); element.fireEvent('on' + eventName, evt); } else { throw 'FireEvent: No event creation mechanism.'; } }; /** * Don't do anything for this event, just halt propagation. * @param {!Event} e An event. */ Blockly.noEvent = function(e) { // This event has been handled. No need to bubble up to the document. e.preventDefault(); e.stopPropagation(); }; /** * Return the coordinates of the top-left corner of this element relative to * its parent. * @param {!Element} element Element to find the coordinates of. * @return {!Object} Object with .x and .y properties. * @private */ Blockly.getRelativeXY_ = function(element) { var xy = {x: 0, y: 0}; // First, check for x and y attributes. var x = element.getAttribute('x'); if (x) { xy.x = parseInt(x, 10); } var y = element.getAttribute('y'); if (y) { xy.y = parseInt(y, 10); } // Second, check for transform="translate(...)" attribute. var transform = element.getAttribute('transform'); // Note that Firefox and IE (9,10) return 'translate(12)' instead of // 'translate(12, 0)'. // Note that IE (9,10) returns 'translate(16 8)' instead of // 'translate(16, 8)'. var r = transform && transform.match(/translate\(\s*([-\d.]+)([ ,]\s*([-\d.]+)\s*\))?/); if (r) { xy.x += parseInt(r[1], 10); if (r[3]) { xy.y += parseInt(r[3], 10); } } return xy; }; /** * Return the absolute coordinates of the top-left corner of this element. * The origin (0,0) is the top-left corner of the Blockly svg. * @param {!Element} element Element to find the coordinates of. * @return {!Object} Object with .x and .y properties. * @private */ Blockly.getSvgXY_ = function(element, workspace) { var x = 0; var y = 0; if (Blockly.mainWorkspace.blockMenu) { do { // Loop through this block and every parent. var xy = Blockly.getRelativeXY_(element); x += xy.x; y += xy.y; element = element.parentNode; } while (element && (element.tagName.toUpperCase() != 'SVG')); } else { do { // Loop through this block and every parent. var xy = Blockly.getRelativeXY_(element); x += xy.x; y += xy.y; element = element.parentNode; } while (element && (element != Blockly.svg)); } return {x: x, y: y}; }; /** * Return the absolute coordinates of the top-left corner of this element. * The origin (0,0) is the top-left corner of the page body. * @param {!Element} element Element to find the coordinates of. * @return {!Object} Object with .x and .y properties. * @private */ Blockly.getAbsoluteXY_ = function(element, svg) { var xy = Blockly.getSvgXY_(element); return Blockly.convertCoordinates(xy.x, xy.y, false, svg); }; /** * Helper method for creating SVG elements. * @param {string} name Element's tag name. * @param {!Object} attrs Dictionary of attribute names and values. * @param {Element=} opt_parent Optional parent on which to append the element. * @return {!SVGElement} Newly created SVG element. */ Blockly.createSvgElement = function(name, attrs, opt_parent) { var e = /** @type {!SVGElement} */ ( document.createElementNS(Blockly.SVG_NS, name)); for (var key in attrs) { e.setAttribute(key, attrs[key]); } // IE defines a unique attribute "runtimeStyle", it is NOT applied to // elements created with createElementNS. However, Closure checks for IE // and assumes the presence of the attribute and crashes. if (document.body.runtimeStyle) { // Indicates presence of IE-only attr. e.runtimeStyle = e.currentStyle = e.style; } if (opt_parent) { opt_parent.appendChild(e); } return e; }; /** * Is this event a right-click? * @param {!Event} e Mouse event. * @return {boolean} True if right-click. */ Blockly.isRightButton = function(e) { // Control-clicking in WebKit on Mac OS X fails to change button to 2. return e.button == 2 || e.ctrlKey; }; /** * Is this event a middle-click? * @param {!Event} e Mouse event. * @return {boolean} True if middle-click. */ Blockly.isMiddleButton = function(e) { return e.button == 1; }; /** * Convert between HTML coordinates and SVG coordinates. * @param {number} x X input coordinate. * @param {number} y Y input coordinate. * @param {boolean} toSvg True to convert to SVG coordinates. * False to convert to mouse/HTML coordinates. * @param {?Object} svg Origin SVG. * @return {!Object} Object with x and y properties in output coordinates. */ Blockly.convertCoordinates = function(x, y, toSvg, svg) { if (toSvg) { x -= window.scrollX || window.pageXOffset; y -= window.scrollY || window.pageYOffset; } var svg = svg ? svg : Blockly.svg; var svgPoint = svg.createSVGPoint(); svgPoint.x = x; svgPoint.y = y; var matrix = svg.getScreenCTM(); if (toSvg) { matrix = matrix.inverse(); } var xy = svgPoint.matrixTransform(matrix); if (!toSvg) { xy.x += window.scrollX || window.pageXOffset; xy.y += window.scrollY || window.pageYOffset; } return xy; }; /** * Return the converted coordinates of the given mouse event. * The origin (0,0) is the top-left corner of the Blockly svg. * @param {!Event} e Mouse event. * @return {!Object} Object with .x and .y properties. */ Blockly.mouseToSvg = function(e) { var scrollX = window.scrollX || window.pageXOffset; var scrollY = window.scrollY || window.pageYOffset; return Blockly.convertCoordinates(e.clientX + scrollX, e.clientY + scrollY, true); }; /** * Given an array of strings, return the length of the shortest one. * @param {!Array.} array Array of strings. * @return {number} Length of shortest string. */ Blockly.shortestStringLength = function(array) { if (!array.length) { return 0; } var len = array[0].length; for (var i = 1; i < array.length; i++) { len = Math.min(len, array[i].length); } return len; }; /** * Given an array of strings, return the length of the common prefix. * Words may not be split. Any space after a word is included in the length. * @param {!Array.} array Array of strings. * @param {?number} opt_shortest Length of shortest string. * @return {number} Length of common prefix. */ Blockly.commonWordPrefix = function(array, opt_shortest) { if (!array.length) { return 0; } else if (array.length == 1) { return array[0].length; } var wordPrefix = 0; var max = opt_shortest || Blockly.shortestStringLength(array); for (var len = 0; len < max; len++) { var letter = array[0][len]; for (var i = 1; i < array.length; i++) { if (letter != array[i][len]) { return wordPrefix; } } if (letter == ' ') { wordPrefix = len + 1; } } for (var i = 1; i < array.length; i++) { var letter = array[i][len]; if (letter && letter != ' ') { return wordPrefix; } } return max; }; /** * Given an array of strings, return the length of the common suffix. * Words may not be split. Any space after a word is included in the length. * @param {!Array.} array Array of strings. * @param {?number} opt_shortest Length of shortest string. * @return {number} Length of common suffix. */ Blockly.commonWordSuffix = function(array, opt_shortest) { if (!array.length) { return 0; } else if (array.length == 1) { return array[0].length; } var wordPrefix = 0; var max = opt_shortest || Blockly.shortestStringLength(array); for (var len = 0; len < max; len++) { var letter = array[0].substr(-len - 1, 1); for (var i = 1; i < array.length; i++) { if (letter != array[i].substr(-len - 1, 1)) { return wordPrefix; } } if (letter == ' ') { wordPrefix = len + 1; } } for (var i = 1; i < array.length; i++) { var letter = array[i].charAt(array[i].length - len - 1); if (letter && letter != ' ') { return wordPrefix; } } return max; }; /** * Is the given string a number (includes negative and decimals). * @param {string} str Input string. * @return {boolean} True if number, false otherwise. */ Blockly.isNumber = function(str) { return !!str.match(/^\s*-?\d+(\.\d+)?\s*$/); }; Blockly.getComputedTextLength = function(textElement) { var textContent = textElement.innerHTML; var length = Blockly.textLengthCache[textContent]; if (length) return length; else { length = textElement.getComputedTextLength(); Blockly.textLengthCache[textContent] = length; return length; } }; Blockly.isChild = function(parent, child) { if (child != null) { while (child.parentNode) { if ( (child = child.parentNode) == parent) return true; } } return false; } ================================================ FILE: extern/blockly/core/variables.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Utility functions for handling variables and procedure names. * Note that variables and procedures share the same name space, meaning that * one can't have a variable and a procedure of the same name. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Variables'); // TODO(scr): Fix circular dependencies // goog.require('Blockly.Block'); goog.require('Blockly.Toolbox'); goog.require('Blockly.Workspace'); /** * Category to separate variable names from procedures and generated functions. */ Blockly.Variables.NAME_TYPE = 'VARIABLE'; /** * Find all user-created variables. * @param {Blockly.Block=} opt_block Optional root block. * @return {!Array.} Array of variable names. */ Blockly.Variables.allVariables = function(opt_block) { var blocks; if (opt_block) { blocks = opt_block.getDescendants(); } else { blocks = Blockly.mainWorkspace.getAllBlocks(); } var variableHash = Object.create(null); // Iterate through every block and add each variable to the hash. for (var x = 0; x < blocks.length; x++) { var func = blocks[x].getVars; if (func) { var blockVariables = func.call(blocks[x]); for (var y = 0; y < blockVariables.length; y++) { var varName = blockVariables[y]; // Variable name may be null if the block is only half-built. if (varName) { variableHash[varName.toLowerCase()] = varName; } } } } // Flatten the hash into a list. var variableList = []; for (var name in variableHash) { variableList.push(variableHash[name]); } return variableList; }; /** * Find all instances of the specified variable and rename them. * @param {string} oldName Variable to rename. * @param {string} newName New variable name. */ Blockly.Variables.renameVariable = function(oldName, newName) { var blocks = Blockly.mainWorkspace.getAllBlocks(); // Iterate through every block. for (var x = 0; x < blocks.length; x++) { var func = blocks[x].renameVar; if (func) { func.call(blocks[x], oldName, newName); } } }; /** * Construct the blocks required by the flyout for the variable category. * @param {!Array.} blocks List of blocks to show. * @param {!Array.} gaps List of widths between blocks. * @param {number} margin Standard margin width for calculating gaps. * @param {!Blockly.Workspace} workspace The flyout's workspace. */ Blockly.Variables.flyoutCategory = function(blocks, gaps, margin, workspace) { var variableList = Blockly.Variables.allVariables(); variableList.sort(goog.string.caseInsensitiveCompare); // In addition to the user's variables, we also want to display the default // variable name at the top. We also don't want this duplicated if the // user has created a variable of the same name. variableList.unshift(null); var defaultVariable = undefined; for (var i = 0; i < variableList.length; i++) { if (variableList[i] === defaultVariable) { continue; } var getBlock = Blockly.Blocks['variables_get'] ? Blockly.Block.obtain(workspace, 'variables_get') : null; getBlock && getBlock.initSvg(); var setBlock = Blockly.Blocks['variables_set'] ? Blockly.Block.obtain(workspace, 'variables_set') : null; setBlock && setBlock.initSvg(); if (variableList[i] === null) { defaultVariable = (getBlock || setBlock).getVars()[0]; } else { getBlock && getBlock.setFieldValue(variableList[i], 'VAR'); setBlock && setBlock.setFieldValue(variableList[i], 'VAR'); } setBlock && blocks.push(setBlock); getBlock && blocks.push(getBlock); if (getBlock && setBlock) { gaps.push(margin, margin * 3); } else { gaps.push(margin * 2); } } }; /** * Return a new variable name that is not yet being used. This will try to * generate single letter variable names in the range 'i' to 'z' to start with. * If no unique name is located it will try 'i1' to 'z1', then 'i2' to 'z2' etc. * @return {string} New variable name. */ Blockly.Variables.generateUniqueName = function() { var variableList = Blockly.Variables.allVariables(); var newName = ''; if (variableList.length) { variableList.sort(goog.string.caseInsensitiveCompare); var nameSuffix = 0, potName = 'i', i = 0, inUse = false; while (!newName) { i = 0; inUse = false; while (i < variableList.length && !inUse) { if (variableList[i].toLowerCase() == potName) { // This potential name is already used. inUse = true; } i++; } if (inUse) { // Try the next potential name. if (potName[0] === 'z') { // Reached the end of the character sequence so back to 'a' but with // a new suffix. nameSuffix++; potName = 'a'; } else { potName = String.fromCharCode(potName.charCodeAt(0) + 1); if (potName[0] == 'l') { // Avoid using variable 'l' because of ambiguity with '1'. potName = String.fromCharCode(potName.charCodeAt(0) + 1); } } if (nameSuffix > 0) { potName += nameSuffix; } } else { // We can use the current potential name. newName = potName; } } } else { newName = 'i'; } return newName; }; ================================================ FILE: extern/blockly/core/warning.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Object representing a warning. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Warning'); goog.require('Blockly.Bubble'); goog.require('Blockly.Icon'); /** * Class for a warning. * @param {!Blockly.Block} block The block associated with this warning. * @extends {Blockly.Icon} * @constructor */ Blockly.Warning = function(block) { Blockly.Warning.superClass_.constructor.call(this, block); this.createIcon_(); }; goog.inherits(Blockly.Warning, Blockly.Icon); /** * Warning text (if bubble is not visible). * @private */ Blockly.Warning.prototype.text_ = ''; /** * Create the icon on the block. * @private */ Blockly.Warning.prototype.createIcon_ = function() { Blockly.Icon.prototype.createIcon_.call(this); /* Here's the markup that will be generated: ! */ var iconShield = Blockly.createSvgElement('path', {'class': 'blocklyIconShield', 'd': 'M 2,15 Q -1,15 0.5,12 L 6.5,1.7 Q 8,-1 9.5,1.7 L 15.5,12 ' + 'Q 17,15 14,15 z'}, this.iconGroup_); this.iconMark_ = Blockly.createSvgElement('text', {'class': 'blocklyIconMark', 'x': Blockly.Icon.RADIUS, 'y': 2 * Blockly.Icon.RADIUS - 3}, this.iconGroup_); this.iconMark_.appendChild(document.createTextNode('!')); }; /** * Create the text for the warning's bubble. * @param {string} text The text to display. * @return {!SVGTextElement} The top-level node of the text. * @private */ Blockly.Warning.prototype.textToDom_ = function(text) { var paragraph = /** @type {!SVGTextElement} */ ( Blockly.createSvgElement( 'text', {'class': 'blocklyText', 'y': Blockly.Bubble.BORDER_WIDTH}, null)); var lines = text.split('\n'); for (var i = 0; i < lines.length; i++) { var tspanElement = Blockly.createSvgElement('tspan', {'dy': '1em', 'x': Blockly.Bubble.BORDER_WIDTH}, paragraph); var textNode = document.createTextNode(lines[i]); tspanElement.appendChild(textNode); } return paragraph; }; /** * Show or hide the warning bubble. * @param {boolean} visible True if the bubble should be visible. */ Blockly.Warning.prototype.setVisible = function(visible) { if (visible == this.isVisible()) { // No change. return; } if (visible) { // Create the bubble. var paragraph = this.textToDom_(this.text_); this.bubble_ = new Blockly.Bubble( /** @type {!Blockly.Workspace} */ (this.block_.workspace), paragraph, this.block_.svg_.svgGroup_, this.iconX_, this.iconY_, null, null); if (Blockly.RTL) { // Right-align the paragraph. // This cannot be done until the bubble is rendered on screen. var maxWidth = paragraph.getBBox().width; for (var x = 0, textElement; textElement = paragraph.childNodes[x]; x++) { textElement.setAttribute('text-anchor', 'end'); textElement.setAttribute('x', maxWidth + Blockly.Bubble.BORDER_WIDTH); } } this.updateColour(); // Bump the warning into the right location. var size = this.bubble_.getBubbleSize(); this.bubble_.setBubbleSize(size.width, size.height); } else { // Dispose of the bubble. this.bubble_.dispose(); this.bubble_ = null; this.body_ = null; this.foreignObject_ = null; } }; /** * Bring the warning to the top of the stack when clicked on. * @param {!Event} e Mouse up event. * @private */ Blockly.Warning.prototype.bodyFocus_ = function(e) { this.bubble_.promote_(); }; /** * Set this warning's text. * @param {string} text Warning text. */ Blockly.Warning.prototype.setText = function(text) { this.text_ = text; if (this.isVisible()) { this.setVisible(false); this.setVisible(true); } }; /** * Dispose of this warning. */ Blockly.Warning.prototype.dispose = function() { this.block_.warning = null; Blockly.Icon.prototype.dispose.call(this); }; ================================================ FILE: extern/blockly/core/widgetdiv.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2013 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview A div that floats on top of Blockly. This singleton contains * temporary HTML UI widgets that the user is currently interacting with. * E.g. text input areas, colour pickers. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.WidgetDiv'); goog.require('Blockly.Css'); goog.require('goog.dom'); /** * The HTML container. Set once by inject.js's Blockly.createDom_. * @type Element */ Blockly.WidgetDiv.DIV = null; /** * The field currently using this container. * @private * @type Blockly.Field */ Blockly.WidgetDiv.field_ = null; /** * Optional cleanup function set by whichever field uses the widget. * @private * @type Function */ Blockly.WidgetDiv.dispose_ = null; /** * Initialize and display the widget div. Close the old one if needed. * @param {!Blockly.Field} newField The field that will be using this container. * @param {Function} dispose Optional cleanup function to be run when the widget * is closed. */ Blockly.WidgetDiv.show = function(newField, dispose) { if (typeof(Entry) == "object") Entry.dispatchEvent("entryBlocklyChanged"); Blockly.WidgetDiv.hide(); Blockly.WidgetDiv.field_ = newField; Blockly.WidgetDiv.dispose_ = dispose; Blockly.WidgetDiv.initialValue = Blockly.WidgetDiv.field_.text_; Blockly.WidgetDiv.DIV.style.display = 'block'; }; /** * Destroy the widget and hide the div. */ Blockly.WidgetDiv.hide = function() { if (Blockly.WidgetDiv.field_) { if (typeof(Entry) == "object" && Blockly.WidgetDiv.initialValue != Blockly.WidgetDiv.field_.text_) { Entry.dispatchEvent("cancelLastCommand"); } Blockly.WidgetDiv.DIV.style.display = 'none'; Blockly.WidgetDiv.dispose_ && Blockly.WidgetDiv.dispose_(); Blockly.WidgetDiv.field_ = null; Blockly.WidgetDiv.dispose_ = null; goog.dom.removeChildren(Blockly.WidgetDiv.DIV); } }; /** * Destroy the widget and hide the div if it is being used by the specified * field. * @param {!Blockly.Field} oldField The field that was using this container. */ Blockly.WidgetDiv.hideIfField = function(oldField) { if (Blockly.WidgetDiv.field_ == oldField) { Blockly.WidgetDiv.hide(); } }; ================================================ FILE: extern/blockly/core/workspace.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Object representing a workspace. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Workspace'); // TODO(scr): Fix circular dependencies // goog.require('Blockly.Block'); goog.require('Blockly.ScrollbarPair'); goog.require('Blockly.Trashcan'); goog.require('Blockly.Xml'); /** * Class for a workspace. * @param {Function} getMetrics A function that returns size/scrolling metrics. * @param {Function} setMetrics A function that sets size/scrolling metrics. * @constructor */ Blockly.Workspace = function(getMetrics, setMetrics) { if (!getMetrics) { this.getMetrics = Blockly.getGenralWorkspaceMetricsFunc_(this); this.setMetrics = Blockly.setGeneralWorkspaceMetricsFunc_(this); } else { this.getMetrics = getMetrics; this.setMetrics = setMetrics; } /** @type {boolean} */ this.isFlyout = false; /** * @type {!Array.} * @private */ this.topBlocks_ = []; /** @type {number} */ this.maxBlocks = Infinity; Blockly.ConnectionDB.init(this); }; /** * Angle away from the horizontal to sweep for blocks. Order of execution is * generally top to bottom, but a small angle changes the scan to give a bit of * a left to right bias (reversed in RTL). Units are in degrees. * See: http://tvtropes.org/pmwiki/pmwiki.php/Main/DiagonalBilling. */ Blockly.Workspace.SCAN_ANGLE = 3; /** * Can this workspace be dragged around (true) or is it fixed (false)? * @type {boolean} */ Blockly.Workspace.prototype.dragMode = false; /** * Current horizontal scrolling offset. * @type {number} */ Blockly.Workspace.prototype.scrollX = 0; /** * Current vertical scrolling offset. * @type {number} */ Blockly.Workspace.prototype.scrollY = 0; /** * The workspace's trashcan (if any). * @type {Blockly.Trashcan} */ Blockly.Workspace.prototype.trashcan = null; /** * PID of upcoming firing of a change event. Used to fire only one event * after multiple changes. * @type {?number} * @private */ Blockly.Workspace.prototype.fireChangeEventPid_ = null; /** * This workspace's scrollbars, if they exist. * @type {Blockly.ScrollbarPair} */ Blockly.Workspace.prototype.scrollbar = null; /** * Create the trash can elements. * @return {!Element} The workspace's SVG group. */ Blockly.Workspace.prototype.createDom = function() { /* [Trashcan may go here] */ this.svgGroup_ = Blockly.createSvgElement('g', {}, null); this.svgBlockCanvas_ = Blockly.createSvgElement('g', {}, this.svgGroup_); this.svgBubbleCanvas_ = Blockly.createSvgElement('g', {}, this.svgGroup_); this.fireChangeEvent(); return this.svgGroup_; }; /** * Dispose of this workspace. * Unlink from all DOM elements to prevent memory leaks. */ Blockly.Workspace.prototype.dispose = function() { if (this.svgGroup_) { goog.dom.removeNode(this.svgGroup_); this.svgGroup_ = null; } this.svgBlockCanvas_ = null; this.svgBubbleCanvas_ = null; if (this.trashcan) { this.trashcan.dispose(); this.trashcan = null; } }; /** * Add a trashcan. */ Blockly.Workspace.prototype.addTrashcan = function() { if (Blockly.hasTrashcan && !Blockly.readOnly) { this.trashcan = new Blockly.Trashcan(this); var svgTrashcan = this.trashcan.createDom(); this.svgGroup_.insertBefore(svgTrashcan, this.svgBlockCanvas_); this.trashcan.init(); } }; /** * Add a connection animation. */ Blockly.Workspace.prototype.addConnectionAnimation = function() { this.connectionAnimation = new Blockly.ConnectionAnimation(); var svgConnectionAnimation = this.connectionAnimation.createDom(); this.svgGroup_.insertBefore(svgConnectionAnimation, this.svgBlockCanvas_); this.connectionAnimation.init(); }; /** * Get the SVG element that forms the drawing surface. * @return {!Element} SVG element. */ Blockly.Workspace.prototype.getCanvas = function() { return this.svgBlockCanvas_; }; /** * Get the SVG element that forms the bubble surface. * @return {!SVGGElement} SVG element. */ Blockly.Workspace.prototype.getBubbleCanvas = function() { return this.svgBubbleCanvas_; }; /** * Add a block to the list of top blocks. * @param {!Blockly.Block} block Block to remove. */ Blockly.Workspace.prototype.addTopBlock = function(block) { this.topBlocks_.push(block); if (Blockly.Realtime.isEnabled() && this == Blockly.mainWorkspace) { Blockly.Realtime.addTopBlock(block); } this.fireChangeEvent(); }; /** * Remove a block from the list of top blocks. * @param {!Blockly.Block} block Block to remove. */ Blockly.Workspace.prototype.removeTopBlock = function(block) { var found = false; for (var child, x = 0; child = this.topBlocks_[x]; x++) { if (child == block) { this.topBlocks_.splice(x, 1); found = true; break; } } if (!found) { throw 'Block not present in workspace\'s list of top-most blocks.'; } if (Blockly.Realtime.isEnabled() && this == Blockly.mainWorkspace) { Blockly.Realtime.removeTopBlock(block); } this.fireChangeEvent(); }; /** * Finds the top-level blocks and returns them. Blocks are optionally sorted * by position; top to bottom (with slight LTR or RTL bias). * @param {boolean} ordered Sort the list if true. * @return {!Array.} The top-level block objects. */ Blockly.Workspace.prototype.getTopBlocks = function(ordered) { // Copy the topBlocks_ list. var blocks = [].concat(this.topBlocks_); if (ordered && blocks.length > 1) { var offset = Math.sin(Blockly.Workspace.SCAN_ANGLE / 180 * Math.PI); if (Blockly.LTR) { offset *= -1; } blocks.sort(function(a, b) { var aXY = a.getRelativeToSurfaceXY(); var bXY = b.getRelativeToSurfaceXY(); return (aXY.y + offset * aXY.x) - (bXY.y + offset * bXY.x); }); } return blocks; }; /** * Find all blocks in workspace. No particular order. * @return {!Array.} Array of blocks. */ Blockly.Workspace.prototype.getAllBlocks = function() { var blocks = this.getTopBlocks(false); for (var x = 0; x < blocks.length; x++) { blocks = blocks.concat(blocks[x].getChildren()); } return blocks; }; /** * Dispose of all blocks in workspace. */ Blockly.Workspace.prototype.clear = function() { Blockly.hideChaff(); while (this.topBlocks_.length) { this.topBlocks_[0].dispose(); } }; /** * Render all blocks in workspace. */ Blockly.Workspace.prototype.render = function() { var renderList = this.getAllBlocks(); for (var x = 0, block; block = renderList[x]; x++) { if (!block.getChildren().length) { block.render(); } } }; /** * Finds the block with the specified ID in this workspace. * @param {string} id ID of block to find. * @return {Blockly.Block} The matching block, or null if not found. */ Blockly.Workspace.prototype.getBlockById = function(id) { // If this O(n) function fails to scale well, maintain a hash table of IDs. var blocks = this.getAllBlocks(); for (var x = 0, block; block = blocks[x]; x++) { if (block.id == id) { return block; } } return null; }; /** * Finds the block with the specified previous ID in this workspace. * @param {string} previous id ID of block to find. * @return {Blockly.Block} The matching block, or null if not found. */ Blockly.Workspace.prototype.getBlockByPreviousId = function(previousId) { // If this O(n) function fails to scale well, maintain a hash table of IDs. var blocks = this.getAllBlocks(); for (var x = 0, block; block = blocks[x]; x++) { if (block.previousId == previousId) { return block; } } return null; }; Blockly.Workspace.prototype.getBlockByIdWithDeactivate = function(id) { // If this O(n) function fails to scale well, maintain a hash table of IDs. var blocks = this.getAllBlocks(); for (var x = 0, block; block = blocks[x]; x++) { block.svg_.removeActive(); if (block.id == id) { return block; } } return null; }; Blockly.Workspace.prototype.setAllBlockDisable = function() { // If this O(n) function fails to scale well, maintain a hash table of IDs. var blocks = this.getAllBlocks(); for (var x = 0, block; block = blocks[x]; x++) { block.setDisabled(true); } return null; }; Blockly.Workspace.prototype.setAllBlockAble = function() { // If this O(n) function fails to scale well, maintain a hash table of IDs. var blocks = this.getAllBlocks(); for (var x = 0, block; block = blocks[x]; x++) { block.setDisabled(false); } return null; }; /** * Turn the visual trace functionality on or off. * @param {boolean} armed True if the trace should be on. */ Blockly.Workspace.prototype.traceOn = function(armed) { this.traceOn_ = armed; if (this.traceWrapper_) { Blockly.unbindEvent_(this.traceWrapper_); this.traceWrapper_ = null; } if (armed) { this.traceWrapper_ = Blockly.bindEvent_(this.svgBlockCanvas_, 'blocklySelectChange', this, function() {this.traceOn_ = false}); } }; /** * Activate a block in the workspace. * @param {?string} id ID of block to find. */ Blockly.Workspace.prototype.activateBlock = function(id) { this.traceOn(true); var block = null; if (id) { block = this.getBlockById(id); if (!block) { return; } } // Temporary turn off the listener for selection changes, so that we don't // trip the monitor for detecting user activity. this.traceOn(false); // Select the current block. if (block) { block.activate(); } else if (Blockly.selected) { Blockly.selected.unselect(); } this.traceOn(true); }; /** * Activate a block in the workspace. * @param {?string} id ID of block to find. */ Blockly.Workspace.prototype.activatePreviousBlock = function(id) { this.traceOn(true); var block = null; if (id) { block = this.getBlockByPreviousId(id); if (!block) { return; } } // Temporary turn off the listener for selection changes, so that we don't // trip the monitor for detecting user activity. this.traceOn(false); // Select the current block. if (block) { block.activate(); } else if (Blockly.selected) { Blockly.selected.unselect(); } this.traceOn(true); }; /** * Highlight a block in the workspace. * @param {?string} id ID of block to find. */ Blockly.Workspace.prototype.highlightBlock = function(id) { if (!this.traceOn_) { return; } var block = null; if (id) { block = this.getBlockById(id); if (!block) { return; } } // Temporary turn off the listener for selection changes, so that we don't // trip the monitor for detecting user activity. this.traceOn(false); // Select the current block. if (block) { block.select(); } else if (Blockly.selected) { Blockly.selected.unselect(); } // Restore the monitor for user activity. this.traceOn(true); }; /** * Fire a change event for this workspace. Changes include new block, dropdown * edits, mutations, connections, etc. Groups of simultaneous changes (e.g. * a tree of blocks being deleted) are merged into one event. * Applications may hook workspace changes by listening for * 'blocklyWorkspaceChange' on Blockly.mainWorkspace.getCanvas(). */ Blockly.Workspace.prototype.fireChangeEvent = function() { if (this.fireChangeEventPid_) { window.clearTimeout(this.fireChangeEventPid_); } var canvas = this.svgBlockCanvas_; if (canvas) { this.fireChangeEventPid_ = window.setTimeout(function() { Blockly.fireUiEvent(canvas, 'blocklyWorkspaceChange'); }, 0); } }; /** * Paste the provided block onto the workspace. * @param {!Element} xmlBlock XML block element. */ Blockly.Workspace.prototype.paste = function(xmlBlock) { if (xmlBlock.getElementsByTagName('block').length >= this.remainingCapacity()) { return; } if (typeof(Entry) === "object") { xmlBlock = Entry.changeXmlHashId(xmlBlock); } else if (typeof(Ntry) === "object") { xmlBlock = Ntry.changeXmlHashId(xmlBlock); } var block = Blockly.Xml.domToBlock(this, xmlBlock); // Move the duplicate to original position. var blockX = parseInt(xmlBlock.getAttribute('x'), 10); var blockY = parseInt(xmlBlock.getAttribute('y'), 10); if (!isNaN(blockX) && !isNaN(blockY)) { if (Blockly.RTL) { blockX = -blockX; } // // Offset block until not clobbering another block. do { var collide = false; var allBlocks = this.getAllBlocks(); for (var x = 0, otherBlock; otherBlock = allBlocks[x]; x++) { var otherXY = otherBlock.getRelativeToSurfaceXY(); if (Math.abs(blockX - otherXY.x) <= 1 && Math.abs(blockY - otherXY.y) <= 1) { if (Blockly.RTL) { blockX -= Blockly.SNAP_RADIUS; } else { blockX += Blockly.SNAP_RADIUS; } blockY += Blockly.SNAP_RADIUS * 2; collide = true; } } } while (collide); block.moveBy(blockX, blockY); } block.select(); if (xmlBlock.getAttribute('isForFunc')) { Entry.Func.positionBlock_(block); xmlBlock.removeAttribute('isForFunc'); } }; /** * The number of blocks that may be added to the workspace before reaching * the maxBlocks. * @return {number} Number of blocks left. */ Blockly.Workspace.prototype.remainingCapacity = function() { if (this.maxBlocks == Infinity) { return Infinity; } return this.maxBlocks - this.getAllBlocks().length; }; Blockly.Workspace.prototype.organizeBlocks = function() { var metrics = this.getMetrics(); if (!metrics) return; var verticalGap = 20; var targetLeftPosition; if (Blockly.hasBlockMenu) targetLeftPosition = Math.round(metrics.viewLeft + 35); else { var flyoutWidth = Blockly.mainWorkspace.flyout_.svgGroup_.getBBox().width; targetLeftPosition = Math.round(metrics.viewLeft + 30 + flyoutWidth); } var acculmulatedTop = 0; var columWidth = 0; var limitTopPosition = metrics.viewTop + metrics.viewHeight - 30; var topBlocks = this.getTopBlocks(); for (var i in topBlocks) { var block = topBlocks[i]; var heightWidth = block.getHeightWidth(); var targetTopPosition = acculmulatedTop + metrics.viewTop + verticalGap; if (targetTopPosition > limitTopPosition) { targetLeftPosition = targetLeftPosition + columWidth + 10; columWidth = 0; acculmulatedTop = 0; } columWidth = Math.max(columWidth, heightWidth.width); targetTopPosition = acculmulatedTop + metrics.viewTop + verticalGap; topBlocks[i].svg_.getRootElement().setAttribute('transform', 'translate(' + targetLeftPosition + ',' + targetTopPosition + ')'); acculmulatedTop = acculmulatedTop + heightWidth.height + verticalGap; } var xmls = Blockly.Xml.workspaceToDom(this); this.clear(); Blockly.Xml.domToWorkspace(this, xmls); }; // Export symbols that would otherwise be renamed by Closure compiler. Blockly.Workspace.prototype['clear'] = Blockly.Workspace.prototype.clear; ================================================ FILE: extern/blockly/core/xml.js ================================================ /** * @license * Visual Blocks Editor * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview XML reader and writer. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Xml'); // TODO(scr): Fix circular dependencies // goog.require('Blockly.Block'); /** * Encode a block tree as XML. * @param {!Object} workspace The SVG workspace. * @return {!Element} XML document. */ Blockly.Xml.workspaceToDom = function(workspace) { var width = Blockly.svgSize().width; var xml = goog.dom.createDom('xml'); var blocks = workspace.getTopBlocks(true); for (var i = 0, block; block = blocks[i]; i++) { var element = Blockly.Xml.blockToDom_(block); var xy = block.getRelativeToSurfaceXY(); element.setAttribute('x', Blockly.RTL ? width - xy.x : xy.x); element.setAttribute('y', xy.y); xml.appendChild(element); } return xml; }; /** * Encode a block subtree as XML. * @param {!Blockly.Block} block The root block to encode. * @return {!Element} Tree of XML elements. * @private */ Blockly.Xml.blockToDom_ = function(block) { var element = goog.dom.createDom('block'); element.setAttribute('type', block.type); if (block.outputConnection) element.setAttribute('class', "output " + block.type); else element.setAttribute('class', "inline " + block.type); element.setAttribute('id', block.id); if (block.mutationToDom) { // Custom data for an advanced block. var mutation = block.mutationToDom(); if (mutation) { element.appendChild(mutation); } } function fieldToDom(field) { if (field.name && field.EDITABLE) { var container = goog.dom.createDom('field', null, field.getValue()); container.setAttribute('name', field.name); element.appendChild(container); } } for (var x = 0, input; input = block.inputList[x]; x++) { for (var y = 0, field; field = input.fieldRow[y]; y++) { fieldToDom(field); } } if (block.comment) { var commentElement = goog.dom.createDom('comment', null, block.comment.getText()); commentElement.setAttribute('pinned', block.comment.isVisible()); var hw = block.comment.getBubbleSize(); commentElement.setAttribute('h', hw.height); commentElement.setAttribute('w', hw.width); element.appendChild(commentElement); } var hasValues = false; for (var i = 0, input; input = block.inputList[i]; i++) { var container; var empty = true; if (input.type == Blockly.DUMMY_INPUT) { continue; } else { var childBlock = input.connection.targetBlock(); if (input.type == Blockly.INPUT_VALUE) { container = goog.dom.createDom('value'); hasValues = true; } else if (input.type == Blockly.NEXT_STATEMENT) { container = goog.dom.createDom('statement'); } if (childBlock) { container.appendChild(Blockly.Xml.blockToDom_(childBlock)); empty = false; } } container.setAttribute('name', input.name); if (!empty) { element.appendChild(container); } } if (hasValues) { element.setAttribute('inline', block.inputsInline); } if (block.isCollapsed()) { element.setAttribute('collapsed', true); } if (block.disabled) { element.setAttribute('disabled', true); } if (!block.isDeletable()) { element.setAttribute('deletable', false); } if (!block.isMovable()) { element.setAttribute('movable', false); } if (!block.isAddable()) { element.setAttribute('addable', false); } if (!block.isEditable()) { element.setAttribute('editable', false); } if (block.nextConnection) { var nextBlock = block.nextConnection.targetBlock(); if (nextBlock) { var container = goog.dom.createDom('next', null, Blockly.Xml.blockToDom_(nextBlock)); element.appendChild(container); } } return element; }; /** * Converts a DOM structure into plain text. * Currently the text format is fairly ugly: all one line with no whitespace. * @param {!Element} dom A tree of XML elements. * @return {string} Text representation. */ Blockly.Xml.domToText = function(dom) { var oSerializer = new XMLSerializer(); return oSerializer.serializeToString(dom); }; /** * Converts a DOM structure into properly indented text. * @param {!Element} dom A tree of XML elements. * @return {string} Text representation. */ Blockly.Xml.domToPrettyText = function(dom) { // This function is not guaranteed to be correct for all XML. // But it handles the XML that Blockly generates. var blob = Blockly.Xml.domToText(dom); // Place every open and close tag on its own line. var lines = blob.split('<'); // Indent every line. var indent = ''; for (var x = 1; x < lines.length; x++) { var line = lines[x]; if (line[0] == '/') { indent = indent.substring(2); } lines[x] = indent + '<' + line; if (line[0] != '/' && line.slice(-2) != '/>') { indent += ' '; } } // Pull simple tags back together. // E.g. var text = lines.join('\n'); text = text.replace(/(<(\w+)\b[^>]*>[^\n]*)\n *<\/\2>/g, '$1'); // Trim leading blank line. return text.replace(/^\n/, ''); }; /** * Converts plain text into a DOM structure. * Throws an error if XML doesn't parse. * @param {string} text Text representation. * @return {!Element} A tree of XML elements. */ Blockly.Xml.textToDom = function(text) { var oParser = new DOMParser(); var dom = oParser.parseFromString(text, 'text/xml'); // The DOM should have one and only one top-level node, an XML tag. if (!dom || !dom.firstChild || dom.firstChild.nodeName.toLowerCase() != 'xml' || dom.firstChild !== dom.lastChild) { // Whatever we got back from the parser is not XML. throw 'Blockly.Xml.textToDom did not obtain a valid XML tree.'; } return dom.firstChild; }; /** * Decode an XML DOM and create blocks on the workspace. * @param {!Blockly.Workspace} workspace The SVG workspace. * @param {!Element} xml XML DOM. */ Blockly.Xml.domToWorkspace = function(workspace, xml) { var width = Blockly.svgSize().width; for (var x = 0, xmlChild; xmlChild = xml.childNodes[x]; x++) { if (xmlChild.nodeName.toLowerCase() == 'block') { var block = Blockly.Xml.domToBlock(workspace, xmlChild); var blockX = parseInt(xmlChild.getAttribute('x'), 10); var blockY = parseInt(xmlChild.getAttribute('y'), 10); if (!isNaN(blockX) && !isNaN(blockY)) { block.moveBy(Blockly.RTL ? width - blockX : blockX, blockY); } } } Blockly.svgResize(); }; /** * Decode an XML block tag and create a block (and possibly sub blocks) on the * workspace. * @param {!Blockly.Workspace} workspace The workspace. * @param {!Element} xmlBlock XML block element. * @param {boolean=} opt_reuseBlock Optional arg indicating whether to * reinitialize an existing block. * @return {!Blockly.Block} The root block created. * @private */ Blockly.Xml.domToBlock = function(workspace, xmlBlock, opt_reuseBlock) { var block = null; var prototypeName = xmlBlock.getAttribute('type'); if (!prototypeName) { throw 'Block type unspecified: \n' + xmlBlock.outerHTML; } var id = xmlBlock.getAttribute('id'); if (opt_reuseBlock && id) { block = Blockly.Block.getById(id, workspace); // TODO: The following is for debugging. It should never actually happen. if (!block) { throw 'Couldn\'t get Block with id: ' + id; } var parentBlock = block.getParent(); // If we've already filled this block then we will dispose of it and then // re-fill it. if (block.workspace) { block.dispose(true, false, true); } block.fill(workspace, prototypeName); block.parent_ = parentBlock; } else { block = Blockly.Block.obtain(workspace, prototypeName); // if (id) { // block.id = parseInt(id, 10); // } } block.previousId = xmlBlock.getAttribute('id'); if (!block.svg_) { block.initSvg(); } var inline = xmlBlock.getAttribute('inline'); if (inline) { block.setInputsInline(inline == 'true'); } var disabled = xmlBlock.getAttribute('disabled'); if (disabled) { block.setDisabled(disabled == 'true'); } var deletable = xmlBlock.getAttribute('deletable'); if (deletable) { block.setDeletable(deletable == 'true'); } var movable = xmlBlock.getAttribute('movable'); if (movable) { block.setMovable(movable == 'true'); } var addable = xmlBlock.getAttribute('addable'); if (addable) { block.setAddable(addable == 'true'); } var editable = xmlBlock.getAttribute('editable'); if (editable) { block.setEditable(editable == 'true'); } var blockChild = null; for (var x = 0, xmlChild; xmlChild = xmlBlock.childNodes[x]; x++) { if (xmlChild.nodeType == 3 && xmlChild.data.match(/^\s*$/)) { // Extra whitespace between tags does not concern us. continue; } var input; // Find the first 'real' grandchild node (that isn't whitespace). var firstRealGrandchild = null; for (var y = 0, grandchildNode; grandchildNode = xmlChild.childNodes[y]; y++) { if (grandchildNode.nodeType != 3 || !grandchildNode.data.match(/^\s*$/)) { firstRealGrandchild = grandchildNode; } } var name = xmlChild.getAttribute('name'); switch (xmlChild.nodeName.toLowerCase()) { case 'mutation': // Custom data for an advanced block. if (block.domToMutation) { block.domToMutation(xmlChild); } break; case 'comment': block.setCommentText(xmlChild.textContent); var visible = xmlChild.getAttribute('pinned'); if (visible) { block.comment.setVisible(visible == 'true'); } var bubbleW = parseInt(xmlChild.getAttribute('w'), 10); var bubbleH = parseInt(xmlChild.getAttribute('h'), 10); if (!isNaN(bubbleW) && !isNaN(bubbleH)) { block.comment.setBubbleSize(bubbleW, bubbleH); } break; case 'title': // Titles were renamed to field in December 2013. // Fall through. case 'field': block.setFieldValue(xmlChild.textContent, name); break; case 'value': case 'statement': input = block.getInput(name); if (!input) { throw 'Input ' + name + ' does not exist in block ' + prototypeName; } if (firstRealGrandchild && firstRealGrandchild.nodeName.toLowerCase() == 'block') { blockChild = Blockly.Xml.domToBlock(workspace, firstRealGrandchild, opt_reuseBlock); if (blockChild.outputConnection) { input.connection.connect(blockChild.outputConnection); } else if (blockChild.previousConnection) { input.connection.connect(blockChild.previousConnection); } else { throw 'Child block does not have output or previous statement.'; } } break; case 'next': if (firstRealGrandchild && firstRealGrandchild.nodeName.toLowerCase() == 'block') { if (!block.nextConnection) { throw 'Next statement does not exist.'; } else if (block.nextConnection.targetConnection) { // This could happen if there is more than one XML 'next' tag. throw 'Next statement is already connected.'; } blockChild = Blockly.Xml.domToBlock(workspace, firstRealGrandchild, opt_reuseBlock); if (!blockChild.previousConnection) { throw 'Next block does not have previous statement.'; } block.nextConnection.connect(blockChild.previousConnection); } break; default: // Unknown tag; ignore. Same principle as HTML parsers. } } var next = block.nextConnection && block.nextConnection.targetBlock(); if (next) { // Next block in a stack needs to square off its corners. // Rendering a child will render its parent. next.render(); } else { block.render(); } var collapsed = xmlBlock.getAttribute('collapsed'); if (collapsed) { block.setCollapsed(collapsed == 'true'); } return block; }; /** * Remove any 'next' block (statements in a stack). * @param {!Element} xmlBlock XML block element. */ Blockly.Xml.deleteNext = function(xmlBlock) { for (var x = 0, child; child = xmlBlock.childNodes[x]; x++) { if (child.nodeName.toLowerCase() == 'next') { xmlBlock.removeChild(child); break; } } }; // Export symbols that would otherwise be renamed by Closure compiler. Blockly['Xml'] = Blockly.Xml; Blockly.Xml['domToText'] = Blockly.Xml.domToText; Blockly.Xml['domToWorkspace'] = Blockly.Xml.domToWorkspace; Blockly.Xml['textToDom'] = Blockly.Xml.textToDom; Blockly.Xml['workspaceToDom'] = Blockly.Xml.workspaceToDom; ================================================ FILE: extern/blockly/dart_compressed.js ================================================ // Do not edit this file; automatically generated by build.py. "use strict"; // Copyright 2014 Google Inc. Apache License 2.0 Blockly.Dart=new Blockly.Generator("Dart");Blockly.Dart.addReservedWords("assert,break,case,catch,class,const,continue,default,do,else,enum,extends,false,final,finally,for,if,in,is,new,null,rethrow,return,super,switch,this,throw,true,try,var,void,while,with,print,identityHashCode,identical,BidirectionalIterator,Comparable,double,Function,int,Invocation,Iterable,Iterator,List,Map,Match,num,Pattern,RegExp,Set,StackTrace,String,StringSink,Type,bool,DateTime,Deprecated,Duration,Expando,Null,Object,RuneIterator,Runes,Stopwatch,StringBuffer,Symbol,Uri,Comparator,AbstractClassInstantiationError,ArgumentError,AssertionError,CastError,ConcurrentModificationError,CyclicInitializationError,Error,Exception,FallThroughError,FormatException,IntegerDivisionByZeroException,NoSuchMethodError,NullThrownError,OutOfMemoryError,RangeError,StackOverflowError,StateError,TypeError,UnimplementedError,UnsupportedError"); Blockly.Dart.ORDER_ATOMIC=0;Blockly.Dart.ORDER_UNARY_POSTFIX=1;Blockly.Dart.ORDER_UNARY_PREFIX=2;Blockly.Dart.ORDER_MULTIPLICATIVE=3;Blockly.Dart.ORDER_ADDITIVE=4;Blockly.Dart.ORDER_SHIFT=5;Blockly.Dart.ORDER_BITWISE_AND=6;Blockly.Dart.ORDER_BITWISE_XOR=7;Blockly.Dart.ORDER_BITWISE_OR=8;Blockly.Dart.ORDER_RELATIONAL=9;Blockly.Dart.ORDER_EQUALITY=10;Blockly.Dart.ORDER_LOGICAL_AND=11;Blockly.Dart.ORDER_LOGICAL_OR=12;Blockly.Dart.ORDER_CONDITIONAL=13;Blockly.Dart.ORDER_CASCADE=14; Blockly.Dart.ORDER_ASSIGNMENT=15;Blockly.Dart.ORDER_NONE=99;Blockly.Dart.INFINITE_LOOP_TRAP=null; Blockly.Dart.init=function(){Blockly.Dart.definitions_=Object.create(null);Blockly.Dart.functionNames_=Object.create(null);if(Blockly.Variables){Blockly.Dart.variableDB_?Blockly.Dart.variableDB_.reset():Blockly.Dart.variableDB_=new Blockly.Names(Blockly.Dart.RESERVED_WORDS_);for(var a=[],b=Blockly.Variables.allVariables(),c=0;c",GTE:">="}[a.getFieldValue("OP")],c="=="==b||"!="==b?Blockly.Dart.ORDER_EQUALITY:Blockly.Dart.ORDER_RELATIONAL,d=Blockly.Dart.valueToCode(a,"A",c)||"0";a=Blockly.Dart.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]}; Blockly.Dart.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"&&":"||",c="&&"==b?Blockly.Dart.ORDER_LOGICAL_AND:Blockly.Dart.ORDER_LOGICAL_OR,d=Blockly.Dart.valueToCode(a,"A",c);a=Blockly.Dart.valueToCode(a,"B",c);if(d||a){var e="&&"==b?"true":"false";d||(d=e);a||(a=e)}else a=d="false";return[d+" "+b+" "+a,c]};Blockly.Dart.logic_negate=function(a){var b=Blockly.Dart.ORDER_UNARY_PREFIX;return["!"+(Blockly.Dart.valueToCode(a,"BOOL",b)||"true"),b]}; Blockly.Dart.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"true":"false",Blockly.Dart.ORDER_ATOMIC]};Blockly.Dart.logic_null=function(a){return["null",Blockly.Dart.ORDER_ATOMIC]};Blockly.Dart.logic_ternary=function(a){var b=Blockly.Dart.valueToCode(a,"IF",Blockly.Dart.ORDER_CONDITIONAL)||"false",c=Blockly.Dart.valueToCode(a,"THEN",Blockly.Dart.ORDER_CONDITIONAL)||"null";a=Blockly.Dart.valueToCode(a,"ELSE",Blockly.Dart.ORDER_CONDITIONAL)||"null";return[b+" ? "+c+" : "+a,Blockly.Dart.ORDER_CONDITIONAL]};Blockly.Dart.loops={};Blockly.Dart.controls_repeat=function(a){var b=Number(a.getFieldValue("TIMES")),c=Blockly.Dart.statementToCode(a,"DO");Blockly.Dart.INFINITE_LOOP_TRAP&&(c=Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+c);a=Blockly.Dart.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE);return"for (int "+a+" = 0; "+a+" < "+b+"; "+a+"++) {\n"+c+"}\n"}; Blockly.Dart.controls_repeat_ext=function(a){var b=Blockly.Dart.valueToCode(a,"TIMES",Blockly.Dart.ORDER_ASSIGNMENT)||"0",c=Blockly.Dart.statementToCode(a,"DO");Blockly.Dart.INFINITE_LOOP_TRAP&&(c=Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+c);a="";var d=Blockly.Dart.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE),e=b;b.match(/^\w+$/)||Blockly.isNumber(b)||(e=Blockly.Dart.variableDB_.getDistinctName("repeat_end",Blockly.Variables.NAME_TYPE),a+="var "+e+" = "+b+";\n"); return a+("for (int "+d+" = 0; "+d+" < "+e+"; "+d+"++) {\n"+c+"}\n")};Blockly.Dart.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.Dart.valueToCode(a,"BOOL",b?Blockly.Dart.ORDER_UNARY_PREFIX:Blockly.Dart.ORDER_NONE)||"false",d=Blockly.Dart.statementToCode(a,"DO");Blockly.Dart.INFINITE_LOOP_TRAP&&(d=Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+d);b&&(c="!"+c);return"while ("+c+") {\n"+d+"}\n"}; Blockly.Dart.controls_for=function(a){var b=Blockly.Dart.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Dart.valueToCode(a,"FROM",Blockly.Dart.ORDER_ASSIGNMENT)||"0",d=Blockly.Dart.valueToCode(a,"TO",Blockly.Dart.ORDER_ASSIGNMENT)||"0",e=Blockly.Dart.valueToCode(a,"BY",Blockly.Dart.ORDER_ASSIGNMENT)||"1",f=Blockly.Dart.statementToCode(a,"DO");Blockly.Dart.INFINITE_LOOP_TRAP&&(f=Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+f);if(Blockly.isNumber(c)&& Blockly.isNumber(d)&&Blockly.isNumber(e)){var g=parseFloat(c)<=parseFloat(d);a="for ("+b+" = "+c+"; "+b+(g?" <= ":" >= ")+d+"; "+b;b=Math.abs(parseFloat(e));a=(1==b?a+(g?"++":"--"):a+((g?" += ":" -= ")+b))+(") {\n"+f+"}\n")}else a="",g=c,c.match(/^\w+$/)||Blockly.isNumber(c)||(g=Blockly.Dart.variableDB_.getDistinctName(b+"_start",Blockly.Variables.NAME_TYPE),a+="var "+g+" = "+c+";\n"),c=d,d.match(/^\w+$/)||Blockly.isNumber(d)||(c=Blockly.Dart.variableDB_.getDistinctName(b+"_end",Blockly.Variables.NAME_TYPE), a+="var "+c+" = "+d+";\n"),d=Blockly.Dart.variableDB_.getDistinctName(b+"_inc",Blockly.Variables.NAME_TYPE),a+="num "+d+" = ",a=Blockly.isNumber(e)?a+(Math.abs(e)+";\n"):a+("("+e+").abs();\n"),a=a+("if ("+g+" > "+c+") {\n")+(" "+d+" = -"+d+";\n"),a+="}\n",a+="for ("+b+" = "+g+";\n "+d+" >= 0 ? "+b+" <= "+c+" : "+b+" >= "+c+";\n "+b+" += "+d+") {\n"+f+"}\n";return a}; Blockly.Dart.controls_forEach=function(a){var b=Blockly.Dart.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Dart.valueToCode(a,"LIST",Blockly.Dart.ORDER_ASSIGNMENT)||"[]",d=Blockly.Dart.statementToCode(a,"DO");Blockly.Dart.INFINITE_LOOP_TRAP&&(d=Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+d);return"for (var "+b+" in "+c+") {\n"+d+"}\n"}; Blockly.Dart.controls_flow_statements=function(a){switch(a.getFieldValue("FLOW")){case "BREAK":return"break;\n";case "CONTINUE":return"continue;\n"}throw"Unknown flow statement.";};Blockly.Dart.math={};Blockly.Dart.addReservedWords("Math");Blockly.Dart.math_number=function(a){a=window.parseFloat(a.getFieldValue("NUM"));return[a,0>a?Blockly.Dart.ORDER_UNARY_PREFIX:Blockly.Dart.ORDER_ATOMIC]}; Blockly.Dart.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.Dart.ORDER_ADDITIVE],MINUS:[" - ",Blockly.Dart.ORDER_ADDITIVE],MULTIPLY:[" * ",Blockly.Dart.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",Blockly.Dart.ORDER_MULTIPLICATIVE],POWER:[null,Blockly.Dart.ORDER_NONE]}[a.getFieldValue("OP")],c=b[0],b=b[1],d=Blockly.Dart.valueToCode(a,"A",b)||"0";a=Blockly.Dart.valueToCode(a,"B",b)||"0";return c?[d+c+a,b]:(Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;",["Math.pow("+d+", "+a+ ")",Blockly.Dart.ORDER_UNARY_POSTFIX])}; Blockly.Dart.math_single=function(a){var b=a.getFieldValue("OP"),c;if("NEG"==b)return a=Blockly.Dart.valueToCode(a,"NUM",Blockly.Dart.ORDER_UNARY_PREFIX)||"0","-"==a[0]&&(a=" "+a),["-"+a,Blockly.Dart.ORDER_UNARY_PREFIX];Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";a="ABS"==b||"ROUND"==b.substring(0,5)?Blockly.Dart.valueToCode(a,"NUM",Blockly.Dart.ORDER_UNARY_POSTFIX)||"0":"SIN"==b||"COS"==b||"TAN"==b?Blockly.Dart.valueToCode(a,"NUM",Blockly.Dart.ORDER_MULTIPLICATIVE)|| "0":Blockly.Dart.valueToCode(a,"NUM",Blockly.Dart.ORDER_NONE)||"0";switch(b){case "ABS":c=a+".abs()";break;case "ROOT":c="Math.sqrt("+a+")";break;case "LN":c="Math.log("+a+")";break;case "EXP":c="Math.exp("+a+")";break;case "POW10":c="Math.pow(10,"+a+")";break;case "ROUND":c=a+".round()";break;case "ROUNDUP":c=a+".ceil()";break;case "ROUNDDOWN":c=a+".floor()";break;case "SIN":c="Math.sin("+a+" / 180 * Math.PI)";break;case "COS":c="Math.cos("+a+" / 180 * Math.PI)";break;case "TAN":c="Math.tan("+a+ " / 180 * Math.PI)"}if(c)return[c,Blockly.Dart.ORDER_UNARY_POSTFIX];switch(b){case "LOG10":c="Math.log("+a+") / Math.log(10)";break;case "ASIN":c="Math.asin("+a+") / Math.PI * 180";break;case "ACOS":c="Math.acos("+a+") / Math.PI * 180";break;case "ATAN":c="Math.atan("+a+") / Math.PI * 180";break;default:throw"Unknown math operator: "+b;}return[c,Blockly.Dart.ORDER_MULTIPLICATIVE]}; Blockly.Dart.math_constant=function(a){var b={PI:["Math.PI",Blockly.Dart.ORDER_UNARY_POSTFIX],E:["Math.E",Blockly.Dart.ORDER_UNARY_POSTFIX],GOLDEN_RATIO:["(1 + Math.sqrt(5)) / 2",Blockly.Dart.ORDER_MULTIPLICATIVE],SQRT2:["Math.SQRT2",Blockly.Dart.ORDER_UNARY_POSTFIX],SQRT1_2:["Math.SQRT1_2",Blockly.Dart.ORDER_UNARY_POSTFIX],INFINITY:["double.INFINITY",Blockly.Dart.ORDER_ATOMIC]};a=a.getFieldValue("CONSTANT");"INFINITY"!=a&&(Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;"); return b[a]}; Blockly.Dart.math_number_property=function(a){var b=Blockly.Dart.valueToCode(a,"NUMBER_TO_CHECK",Blockly.Dart.ORDER_MULTIPLICATIVE);if(!b)return["false",Blockly.Python.ORDER_ATOMIC];var c=a.getFieldValue("PROPERTY"),d;if("PRIME"==c)return Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;",[Blockly.Dart.provideFunction_("math_isPrime",["bool "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(n) {"," // https://en.wikipedia.org/wiki/Primality_test#Naive_methods"," if (n == 2 || n == 3) {"," return true;", " }"," // False if n is null, negative, is 1, or not whole."," // And false if n is divisible by 2 or 3."," if (n == null || n <= 1 || n % 1 != 0 || n % 2 == 0 || n % 3 == 0) {"," return false;"," }"," // Check all the numbers of form 6k +/- 1, up to sqrt(n)."," for (var x = 6; x <= Math.sqrt(n) + 1; x += 6) {"," if (n % (x - 1) == 0 || n % (x + 1) == 0) {"," return false;"," }"," }"," return true;","}"])+"("+b+")",Blockly.Dart.ORDER_UNARY_POSTFIX];switch(c){case "EVEN":d=b+ " % 2 == 0";break;case "ODD":d=b+" % 2 == 1";break;case "WHOLE":d=b+" % 1 == 0";break;case "POSITIVE":d=b+" > 0";break;case "NEGATIVE":d=b+" < 0";break;case "DIVISIBLE_BY":a=Blockly.Dart.valueToCode(a,"DIVISOR",Blockly.Dart.ORDER_MULTIPLICATIVE);if(!a)return["false",Blockly.Python.ORDER_ATOMIC];d=b+" % "+a+" == 0"}return[d,Blockly.Dart.ORDER_EQUALITY]}; Blockly.Dart.math_change=function(a){var b=Blockly.Dart.valueToCode(a,"DELTA",Blockly.Dart.ORDER_ADDITIVE)||"0";a=Blockly.Dart.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE);return a+" = ("+a+" is num ? "+a+" : 0) + "+b+";\n"};Blockly.Dart.math_round=Blockly.Dart.math_single;Blockly.Dart.math_trig=Blockly.Dart.math_single; Blockly.Dart.math_on_list=function(a){var b=a.getFieldValue("OP");a=Blockly.Dart.valueToCode(a,"LIST",Blockly.Dart.ORDER_NONE)||"[]";switch(b){case "SUM":b=Blockly.Dart.provideFunction_("math_sum",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," num sumVal = 0;"," myList.forEach((num entry) {sumVal += entry;});"," return sumVal;","}"]);b=b+"("+a+")";break;case "MIN":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";b=Blockly.Dart.provideFunction_("math_min", ["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," if (myList.isEmpty) return null;"," num minVal = myList[0];"," myList.forEach((num entry) {minVal = Math.min(minVal, entry);});"," return minVal;","}"]);b=b+"("+a+")";break;case "MAX":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";b=Blockly.Dart.provideFunction_("math_max",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," if (myList.isEmpty) return null;"," num maxVal = myList[0];", " myList.forEach((num entry) {maxVal = Math.max(maxVal, entry);});"," return maxVal;","}"]);b=b+"("+a+")";break;case "AVERAGE":b=Blockly.Dart.provideFunction_("math_average",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," // First filter list for numbers only."," List localList = new List.from(myList);"," localList.removeMatching((a) => a is! num);"," if (localList.isEmpty) return null;"," num sumVal = 0;"," localList.forEach((num entry) {sumVal += entry;});"," return sumVal / localList.length;", "}"]);b=b+"("+a+")";break;case "MEDIAN":b=Blockly.Dart.provideFunction_("math_median",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," // First filter list for numbers only, then sort, then return middle value"," // or the average of two middle values if list has an even number of elements."," List localList = new List.from(myList);"," localList.removeMatching((a) => a is! num);"," if (localList.isEmpty) return null;"," localList.sort((a, b) => (a - b));"," int index = localList.length ~/ 2;", " if (localList.length % 2 == 1) {"," return localList[index];"," } else {"," return (localList[index - 1] + localList[index]) / 2;"," }","}"]);b=b+"("+a+")";break;case "MODE":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";b=Blockly.Dart.provideFunction_("math_modes",["List "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List values) {"," List modes = [];"," List counts = [];"," int maxCount = 0;"," for (int i = 0; i < values.length; i++) {"," var value = values[i];", " bool found = false;"," int thisCount;"," for (int j = 0; j < counts.length; j++) {"," if (counts[j][0] == value) {"," thisCount = ++counts[j][1];"," found = true;"," break;"," }"," }"," if (!found) {"," counts.add([value, 1]);"," thisCount = 1;"," }"," maxCount = Math.max(thisCount, maxCount);"," }"," for (int j = 0; j < counts.length; j++) {"," if (counts[j][1] == maxCount) {"," modes.add(counts[j][0]);"," }"," }"," return modes;", "}"]);b=b+"("+a+")";break;case "STD_DEV":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";b=Blockly.Dart.provideFunction_("math_standard_deviation",["num "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," // First filter list for numbers only."," List numbers = new List.from(myList);"," numbers.removeMatching((a) => a is! num);"," if (numbers.isEmpty) return null;"," num n = numbers.length;"," num sum = 0;"," numbers.forEach((x) => sum += x);"," num mean = sum / n;", " num sumSquare = 0;"," numbers.forEach((x) => sumSquare += Math.pow(x - mean, 2));"," return Math.sqrt(sumSquare / n);","}"]);b=b+"("+a+")";break;case "RANDOM":Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";b=Blockly.Dart.provideFunction_("math_random_item",["dynamic "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(List myList) {"," int x = new Math.Random().nextInt(myList.length);"," return myList[x];","}"]);b=b+"("+a+")";break;default:throw"Unknown operator: "+b;}return[b, Blockly.Dart.ORDER_UNARY_POSTFIX]};Blockly.Dart.math_modulo=function(a){var b=Blockly.Dart.valueToCode(a,"DIVIDEND",Blockly.Dart.ORDER_MULTIPLICATIVE)||"0";a=Blockly.Dart.valueToCode(a,"DIVISOR",Blockly.Dart.ORDER_MULTIPLICATIVE)||"0";return[b+" % "+a,Blockly.Dart.ORDER_MULTIPLICATIVE]}; Blockly.Dart.math_constrain=function(a){Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";var b=Blockly.Dart.valueToCode(a,"VALUE",Blockly.Dart.ORDER_NONE)||"0",c=Blockly.Dart.valueToCode(a,"LOW",Blockly.Dart.ORDER_NONE)||"0";a=Blockly.Dart.valueToCode(a,"HIGH",Blockly.Dart.ORDER_NONE)||"double.INFINITY";return["Math.min(Math.max("+b+", "+c+"), "+a+")",Blockly.Dart.ORDER_UNARY_POSTFIX]}; Blockly.Dart.math_random_int=function(a){Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";var b=Blockly.Dart.valueToCode(a,"FROM",Blockly.Dart.ORDER_NONE)||"0";a=Blockly.Dart.valueToCode(a,"TO",Blockly.Dart.ORDER_NONE)||"0";return[Blockly.Dart.provideFunction_("math_random_int",["int "+Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_+"(num a, num b) {"," if (a > b) {"," // Swap a and b to ensure a is smaller."," num c = a;"," a = b;"," b = c;"," }"," return new Math.Random().nextInt(b - a + 1) + a;", "}"])+"("+b+", "+a+")",Blockly.Dart.ORDER_UNARY_POSTFIX]};Blockly.Dart.math_random_float=function(a){Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;";return["new Math.Random().nextDouble()",Blockly.Dart.ORDER_UNARY_POSTFIX]};Blockly.Dart.procedures={}; Blockly.Dart.procedures_defreturn=function(a){var b=Blockly.Dart.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE),c=Blockly.Dart.statementToCode(a,"STACK");Blockly.Dart.INFINITE_LOOP_TRAP&&(c=Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+c);var d=Blockly.Dart.valueToCode(a,"RETURN",Blockly.Dart.ORDER_NONE)||"";d&&(d=" return "+d+";\n");for(var e=d?"dynamic":"void",f=[],g=0;g list = str.split(exp);"," final title = new StringBuffer();"," for (String part in list) {"," if (part.length > 0) {", " title.write(part[0].toUpperCase());"," if (part.length > 0) {"," title.write(part.substring(1).toLowerCase());"," }"," }"," }"," return title.toString();","}"]),a=Blockly.Dart.valueToCode(a,"TEXT",Blockly.Dart.ORDER_NONE)||"''",a=b+"("+a+")");return[a,Blockly.Dart.ORDER_UNARY_POSTFIX]}; Blockly.Dart.text_trim=function(a){var b={LEFT:".replaceFirst(new RegExp(r'^\\s+'), '')",RIGHT:".replaceFirst(new RegExp(r'\\s+$'), '')",BOTH:".trim()"}[a.getFieldValue("MODE")];return[(Blockly.Dart.valueToCode(a,"TEXT",Blockly.Dart.ORDER_UNARY_POSTFIX)||"''")+b,Blockly.Dart.ORDER_UNARY_POSTFIX]};Blockly.Dart.text_print=function(a){return"print("+(Blockly.Dart.valueToCode(a,"TEXT",Blockly.Dart.ORDER_NONE)||"''")+");\n"}; Blockly.Dart.text_prompt=function(a){Blockly.Dart.definitions_.import_dart_html="import 'dart:html' as Html;";var b="Html.window.prompt("+Blockly.Dart.quote_(a.getFieldValue("TEXT"))+", '')";"NUMBER"==a.getFieldValue("TYPE")&&(Blockly.Dart.definitions_.import_dart_math="import 'dart:math' as Math;",b="Math.parseDouble("+b+")");return[b,Blockly.Dart.ORDER_UNARY_POSTFIX]};Blockly.Dart.variables={};Blockly.Dart.variables_get=function(a){return[Blockly.Dart.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),Blockly.Dart.ORDER_ATOMIC]};Blockly.Dart.variables_set=function(a){var b=Blockly.Dart.valueToCode(a,"VALUE",Blockly.Dart.ORDER_ASSIGNMENT)||"0";return Blockly.Dart.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE)+" = "+b+";\n"}; ================================================ FILE: extern/blockly/generators/dart/colour.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2014 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Dart for colour blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Dart.colour'); goog.require('Blockly.Dart'); Blockly.Dart.addReservedWords('Math'); Blockly.Dart['colour_picker'] = function(block) { // Colour picker. var code = '\'' + block.getFieldValue('COLOUR') + '\''; return [code, Blockly.Dart.ORDER_ATOMIC]; }; Blockly.Dart['colour_random'] = function(block) { // Generate a random colour. Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var functionName = Blockly.Dart.provideFunction_( 'colour_random', [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '() {', ' String hex = \'0123456789abcdef\';', ' var rnd = new Math.Random();', ' return \'#${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}\'', ' \'${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}\'', ' \'${hex[rnd.nextInt(16)]}${hex[rnd.nextInt(16)]}\';', '}']); var code = functionName + '()'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['colour_rgb'] = function(block) { // Compose a colour from RGB components expressed as percentages. var red = Blockly.Dart.valueToCode(block, 'RED', Blockly.Dart.ORDER_NONE) || 0; var green = Blockly.Dart.valueToCode(block, 'GREEN', Blockly.Dart.ORDER_NONE) || 0; var blue = Blockly.Dart.valueToCode(block, 'BLUE', Blockly.Dart.ORDER_NONE) || 0; Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var functionName = Blockly.Dart.provideFunction_( 'colour_rgb', [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(num r, num g, num b) {', ' num rn = (Math.max(Math.min(r, 1), 0) * 255).round();', ' String rs = rn.toInt().toRadixString(16);', ' rs = \'0$rs\';', ' rs = rs.substring(rs.length - 2);', ' num gn = (Math.max(Math.min(g, 1), 0) * 255).round();', ' String gs = gn.toInt().toRadixString(16);', ' gs = \'0$gs\';', ' gs = gs.substring(gs.length - 2);', ' num bn = (Math.max(Math.min(b, 1), 0) * 255).round();', ' String bs = bn.toInt().toRadixString(16);', ' bs = \'0$bs\';', ' bs = bs.substring(bs.length - 2);', ' return \'#$rs$gs$bs\';', '}']); var code = functionName + '(' + red + ', ' + green + ', ' + blue + ')'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['colour_blend'] = function(block) { // Blend two colours together. var c1 = Blockly.Dart.valueToCode(block, 'COLOUR1', Blockly.Dart.ORDER_NONE) || '\'#000000\''; var c2 = Blockly.Dart.valueToCode(block, 'COLOUR2', Blockly.Dart.ORDER_NONE) || '\'#000000\''; var ratio = Blockly.Dart.valueToCode(block, 'RATIO', Blockly.Dart.ORDER_NONE) || 0.5; Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var functionName = Blockly.Dart.provideFunction_( 'colour_blend', [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(String c1, String c2, num ratio) {', ' ratio = Math.max(Math.min(ratio, 1), 0);', ' int r1 = int.parse(\'0x${c1.substring(1, 3)}\');', ' int g1 = int.parse(\'0x${c1.substring(3, 5)}\');', ' int b1 = int.parse(\'0x${c1.substring(5, 7)}\');', ' int r2 = int.parse(\'0x${c2.substring(1, 3)}\');', ' int g2 = int.parse(\'0x${c2.substring(3, 5)}\');', ' int b2 = int.parse(\'0x${c2.substring(5, 7)}\');', ' num rn = (r1 * (1 - ratio) + r2 * ratio).round();', ' String rs = rn.toInt().toRadixString(16);', ' num gn = (g1 * (1 - ratio) + g2 * ratio).round();', ' String gs = gn.toInt().toRadixString(16);', ' num bn = (b1 * (1 - ratio) + b2 * ratio).round();', ' String bs = bn.toInt().toRadixString(16);', ' rs = \'0$rs\';', ' rs = rs.substring(rs.length - 2);', ' gs = \'0$gs\';', ' gs = gs.substring(gs.length - 2);', ' bs = \'0$bs\';', ' bs = bs.substring(bs.length - 2);', ' return \'#$rs$gs$bs\';', '}']); var code = functionName + '(' + c1 + ', ' + c2 + ', ' + ratio + ')'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; ================================================ FILE: extern/blockly/generators/dart/lists.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2014 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Dart for list blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Dart.lists'); goog.require('Blockly.Dart'); Blockly.Dart.addReservedWords('Math'); Blockly.Dart['lists_create_empty'] = function(block) { // Create an empty list. return ['[]', Blockly.Dart.ORDER_ATOMIC]; }; Blockly.Dart['lists_create_with'] = function(block) { // Create a list with any number of elements of any type. var code = new Array(block.itemCount_); for (var n = 0; n < block.itemCount_; n++) { code[n] = Blockly.Dart.valueToCode(block, 'ADD' + n, Blockly.Dart.ORDER_NONE) || 'null'; } code = '[' + code.join(', ') + ']'; return [code, Blockly.Dart.ORDER_ATOMIC]; }; Blockly.Dart['lists_repeat'] = function(block) { // Create a list with one element repeated. var argument0 = Blockly.Dart.valueToCode(block, 'ITEM', Blockly.Dart.ORDER_NONE) || 'null'; var argument1 = Blockly.Dart.valueToCode(block, 'NUM', Blockly.Dart.ORDER_NONE) || '0'; var code = 'new List.filled(' + argument1 + ', ' + argument0 + ')'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['lists_length'] = function(block) { // List length. var argument0 = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]'; return [argument0 + '.length', Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['lists_isEmpty'] = function(block) { // Is the list empty? var argument0 = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]'; return [argument0 + '.isEmpty', Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['lists_indexOf'] = function(block) { // Find an item in the list. var operator = block.getFieldValue('END') == 'FIRST' ? 'indexOf' : 'lastIndexOf'; var argument0 = Blockly.Dart.valueToCode(block, 'FIND', Blockly.Dart.ORDER_NONE) || '\'\''; var argument1 = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]'; var code = argument1 + '.' + operator + '(' + argument0 + ') + 1'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['lists_getIndex'] = function(block) { // Get element at index. // Note: Until January 2013 this block did not have MODE or WHERE inputs. var mode = block.getFieldValue('MODE') || 'GET'; var where = block.getFieldValue('WHERE') || 'FROM_START'; var at = Blockly.Dart.valueToCode(block, 'AT', Blockly.Dart.ORDER_UNARY_PREFIX) || '1'; var list = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]'; if (where == 'FIRST') { if (mode == 'GET') { var code = list + '.first'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } else if (mode == 'GET_REMOVE') { var code = list + '.removeAt(0)'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } else if (mode == 'REMOVE') { return list + '.removeAt(0);\n'; } } else if (where == 'LAST') { if (mode == 'GET') { var code = list + '.last'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } else if (mode == 'GET_REMOVE') { var code = list + '.removeLast()'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } else if (mode == 'REMOVE') { return list + '.removeLast();\n'; } } else if (where == 'FROM_START') { // Blockly uses one-based indicies. if (Blockly.isNumber(at)) { // If the index is a naked number, decrement it right now. at = parseInt(at, 10) - 1; } else { // If the index is dynamic, decrement it in code. at += ' - 1'; } if (mode == 'GET') { var code = list + '[' + at + ']'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } else if (mode == 'GET_REMOVE') { var code = list + '.removeAt(' + at + ')'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } else if (mode == 'REMOVE') { return list + '.removeAt(' + at + ');\n'; } } else if (where == 'FROM_END') { if (mode == 'GET') { var functionName = Blockly.Dart.provideFunction_( 'lists_get_from_end', [ 'dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(List myList, num x) {', ' x = myList.length - x;', ' return myList.removeAt(x);', '}']); code = functionName + '(' + list + ', ' + at + ')'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } else if (mode == 'GET_REMOVE' || mode == 'REMOVE') { var functionName = Blockly.Dart.provideFunction_( 'lists_remove_from_end', [ 'dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(List myList, num x) {', ' x = myList.length - x;', ' return myList.removeAt(x);', '}']); code = functionName + '(' + list + ', ' + at + ')'; if (mode == 'GET_REMOVE') { return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } else if (mode == 'REMOVE') { return code + ';\n'; } } } else if (where == 'RANDOM') { Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var functionName = Blockly.Dart.provideFunction_( 'lists_get_random_item', [ 'dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(List myList, bool remove) {', ' int x = new Math.Random().nextInt(myList.length);', ' if (remove) {', ' return myList.removeAt(x);', ' } else {', ' return myList[x];', ' }', '}']); code = functionName + '(' + list + ', ' + (mode != 'GET') + ')'; if (mode == 'GET' || mode == 'GET_REMOVE') { return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } else if (mode == 'REMOVE') { return code + ';\n'; } } throw 'Unhandled combination (lists_getIndex).'; }; Blockly.Dart['lists_setIndex'] = function(block) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. var list = Blockly.Dart.valueToCode(block, 'LIST', Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]'; var mode = block.getFieldValue('MODE') || 'GET'; var where = block.getFieldValue('WHERE') || 'FROM_START'; var at = Blockly.Dart.valueToCode(block, 'AT', Blockly.Dart.ORDER_ADDITIVE) || '1'; var value = Blockly.Dart.valueToCode(block, 'TO', Blockly.Dart.ORDER_ASSIGNMENT) || 'null'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. function cacheList() { if (list.match(/^\w+$/)) { return ''; } var listVar = Blockly.Dart.variableDB_.getDistinctName( 'tmp_list', Blockly.Variables.NAME_TYPE); var code = 'List ' + listVar + ' = ' + list + ';\n'; list = listVar; return code; } if (where == 'FIRST') { if (mode == 'SET') { return list + '[0] = ' + value + ';\n'; } else if (mode == 'INSERT') { return list + '.insert(0, ' + value + ');\n'; } } else if (where == 'LAST') { if (mode == 'SET') { var code = cacheList(); code += list + '[' + list + '.length - 1] = ' + value + ';\n'; return code; } else if (mode == 'INSERT') { return list + '.add(' + value + ');\n'; } } else if (where == 'FROM_START') { // Blockly uses one-based indicies. if (Blockly.isNumber(at)) { // If the index is a naked number, decrement it right now. at = parseInt(at, 10) - 1; } else { // If the index is dynamic, decrement it in code. at += ' - 1'; } if (mode == 'SET') { return list + '[' + at + '] = ' + value + ';\n'; } else if (mode == 'INSERT') { return list + '.insert(' + at + ', ' + value + ');\n'; } } else if (where == 'FROM_END') { var code = cacheList(); if (mode == 'SET') { code += list + '[' + list + '.length - ' + at + '] = ' + value + ';\n'; return code; } else if (mode == 'INSERT') { code += list + '.insert(' + list + '.length - ' + at + ', ' + value + ');\n'; return code; } } else if (where == 'RANDOM') { Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var code = cacheList(); var xVar = Blockly.Dart.variableDB_.getDistinctName( 'tmp_x', Blockly.Variables.NAME_TYPE); code += 'int ' + xVar + ' = new Math.Random().nextInt(' + list + '.length);'; if (mode == 'SET') { code += list + '[' + xVar + '] = ' + value + ';\n'; return code; } else if (mode == 'INSERT') { code += list + '.insert(' + xVar + ', ' + value + ');\n'; return code; } } throw 'Unhandled combination (lists_setIndex).'; }; Blockly.Dart['lists_getSublist'] = function(block) { // Get sublist. var list = Blockly.Dart.valueToCode(block, 'LIST', Blockly.Dart.ORDER_UNARY_POSTFIX) || '[]'; var where1 = block.getFieldValue('WHERE1'); var where2 = block.getFieldValue('WHERE2'); var at1 = Blockly.Dart.valueToCode(block, 'AT1', Blockly.Dart.ORDER_NONE) || '1'; var at2 = Blockly.Dart.valueToCode(block, 'AT2', Blockly.Dart.ORDER_NONE) || '1'; if ((where1 == 'FIRST' || where1 == 'FROM_START' && Blockly.isNumber(at1)) && (where2 == 'LAST' || where2 == 'FROM_START' && Blockly.isNumber(at2))) { // Simple case that can be done inline. at1 = where1 == 'FIRST' ? 0 : parseInt(at1, 10) - 1; if (where2 == 'LAST') { code = list + '.sublist(' + at1 + ')'; } else { at2 = parseInt(at2, 10); code = list + '.sublist(' + at1 + ', ' + at2 + ')'; } } else { var functionName = Blockly.Dart.provideFunction_( 'lists_get_sublist', [ 'List ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(list, where1, at1, where2, at2) {', ' int getAt(where, at) {', ' if (where == \'FROM_START\') {', ' at--;', ' } else if (where == \'FROM_END\') {', ' at = list.length - at;', ' } else if (where == \'FIRST\') {', ' at = 0;', ' } else if (where == \'LAST\') {', ' at = list.length - 1;', ' } else {', ' throw \'Unhandled option (lists_getSublist).\';', ' }', ' return at;', ' }', ' at1 = getAt(where1, at1);', ' at2 = getAt(where2, at2) + 1;', ' return list.sublist(at1, at2);', '}']); var code = functionName + '(' + list + ', \'' + where1 + '\', ' + at1 + ', \'' + where2 + '\', ' + at2 + ')'; } return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; ================================================ FILE: extern/blockly/generators/dart/logic.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2014 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Dart for logic blocks. * @author q.neutron@gmail.com (Quynh Neutron) */ 'use strict'; goog.provide('Blockly.Dart.logic'); goog.require('Blockly.Dart'); Blockly.Dart['controls_if'] = function(block) { // If/elseif/else condition. var n = 0; var argument = Blockly.Dart.valueToCode(block, 'IF' + n, Blockly.Dart.ORDER_NONE) || 'false'; var branch = Blockly.Dart.statementToCode(block, 'DO' + n); var code = 'if (' + argument + ') {\n' + branch + '}'; for (n = 1; n <= block.elseifCount_; n++) { argument = Blockly.Dart.valueToCode(block, 'IF' + n, Blockly.Dart.ORDER_NONE) || 'false'; branch = Blockly.Dart.statementToCode(block, 'DO' + n); code += ' else if (' + argument + ') {\n' + branch + '}'; } if (block.elseCount_) { branch = Blockly.Dart.statementToCode(block, 'ELSE'); code += ' else {\n' + branch + '}'; } return code + '\n'; }; Blockly.Dart['logic_compare'] = function(block) { // Comparison operator. var OPERATORS = { EQ: '==', NEQ: '!=', LT: '<', LTE: '<=', GT: '>', GTE: '>=' }; var operator = OPERATORS[block.getFieldValue('OP')]; var order = (operator == '==' || operator == '!=') ? Blockly.Dart.ORDER_EQUALITY : Blockly.Dart.ORDER_RELATIONAL; var argument0 = Blockly.Dart.valueToCode(block, 'A', order) || '0'; var argument1 = Blockly.Dart.valueToCode(block, 'B', order) || '0'; var code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; }; Blockly.Dart['logic_operation'] = function(block) { // Operations 'and', 'or'. var operator = (block.getFieldValue('OP') == 'AND') ? '&&' : '||'; var order = (operator == '&&') ? Blockly.Dart.ORDER_LOGICAL_AND : Blockly.Dart.ORDER_LOGICAL_OR; var argument0 = Blockly.Dart.valueToCode(block, 'A', order); var argument1 = Blockly.Dart.valueToCode(block, 'B', order); if (!argument0 && !argument1) { // If there are no arguments, then the return value is false. argument0 = 'false'; argument1 = 'false'; } else { // Single missing arguments have no effect on the return value. var defaultArgument = (operator == '&&') ? 'true' : 'false'; if (!argument0) { argument0 = defaultArgument; } if (!argument1) { argument1 = defaultArgument; } } var code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; }; Blockly.Dart['logic_negate'] = function(block) { // Negation. var order = Blockly.Dart.ORDER_UNARY_PREFIX; var argument0 = Blockly.Dart.valueToCode(block, 'BOOL', order) || 'true'; var code = '!' + argument0; return [code, order]; }; Blockly.Dart['logic_boolean'] = function(block) { // Boolean values true and false. var code = (block.getFieldValue('BOOL') == 'TRUE') ? 'true' : 'false'; return [code, Blockly.Dart.ORDER_ATOMIC]; }; Blockly.Dart['logic_null'] = function(block) { // Null data type. return ['null', Blockly.Dart.ORDER_ATOMIC]; }; Blockly.Dart['logic_ternary'] = function(block) { // Ternary operator. var value_if = Blockly.Dart.valueToCode(block, 'IF', Blockly.Dart.ORDER_CONDITIONAL) || 'false'; var value_then = Blockly.Dart.valueToCode(block, 'THEN', Blockly.Dart.ORDER_CONDITIONAL) || 'null'; var value_else = Blockly.Dart.valueToCode(block, 'ELSE', Blockly.Dart.ORDER_CONDITIONAL) || 'null'; var code = value_if + ' ? ' + value_then + ' : ' + value_else return [code, Blockly.Dart.ORDER_CONDITIONAL]; }; ================================================ FILE: extern/blockly/generators/dart/loops.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2014 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Dart for loop blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Dart.loops'); goog.require('Blockly.Dart'); Blockly.Dart['controls_repeat'] = function(block) { // Repeat n times (internal number). var repeats = Number(block.getFieldValue('TIMES')); var branch = Blockly.Dart.statementToCode(block, 'DO'); if (Blockly.Dart.INFINITE_LOOP_TRAP) { branch = Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } var loopVar = Blockly.Dart.variableDB_.getDistinctName( 'count', Blockly.Variables.NAME_TYPE); var code = 'for (int ' + loopVar + ' = 0; ' + loopVar + ' < ' + repeats + '; ' + loopVar + '++) {\n' + branch + '}\n'; return code; }; Blockly.Dart['controls_repeat_ext'] = function(block) { // Repeat n times (external number). var repeats = Blockly.Dart.valueToCode(block, 'TIMES', Blockly.Dart.ORDER_ASSIGNMENT) || '0'; var branch = Blockly.Dart.statementToCode(block, 'DO'); if (Blockly.Dart.INFINITE_LOOP_TRAP) { branch = Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } var code = ''; var loopVar = Blockly.Dart.variableDB_.getDistinctName( 'count', Blockly.Variables.NAME_TYPE); var endVar = repeats; if (!repeats.match(/^\w+$/) && !Blockly.isNumber(repeats)) { var endVar = Blockly.Dart.variableDB_.getDistinctName( 'repeat_end', Blockly.Variables.NAME_TYPE); code += 'var ' + endVar + ' = ' + repeats + ';\n'; } code += 'for (int ' + loopVar + ' = 0; ' + loopVar + ' < ' + endVar + '; ' + loopVar + '++) {\n' + branch + '}\n'; return code; }; Blockly.Dart['controls_whileUntil'] = function(block) { // Do while/until loop. var until = block.getFieldValue('MODE') == 'UNTIL'; var argument0 = Blockly.Dart.valueToCode(block, 'BOOL', until ? Blockly.Dart.ORDER_UNARY_PREFIX : Blockly.Dart.ORDER_NONE) || 'false'; var branch = Blockly.Dart.statementToCode(block, 'DO'); if (Blockly.Dart.INFINITE_LOOP_TRAP) { branch = Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } if (until) { argument0 = '!' + argument0; } return 'while (' + argument0 + ') {\n' + branch + '}\n'; }; Blockly.Dart['controls_for'] = function(block) { // For loop. var variable0 = Blockly.Dart.variableDB_.getName( block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); var argument0 = Blockly.Dart.valueToCode(block, 'FROM', Blockly.Dart.ORDER_ASSIGNMENT) || '0'; var argument1 = Blockly.Dart.valueToCode(block, 'TO', Blockly.Dart.ORDER_ASSIGNMENT) || '0'; var increment = Blockly.Dart.valueToCode(block, 'BY', Blockly.Dart.ORDER_ASSIGNMENT) || '1'; var branch = Blockly.Dart.statementToCode(block, 'DO'); if (Blockly.Dart.INFINITE_LOOP_TRAP) { branch = Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } var code; if (Blockly.isNumber(argument0) && Blockly.isNumber(argument1) && Blockly.isNumber(increment)) { // All arguments are simple numbers. var up = parseFloat(argument0) <= parseFloat(argument1); code = 'for (' + variable0 + ' = ' + argument0 + '; ' + variable0 + (up ? ' <= ' : ' >= ') + argument1 + '; ' + variable0; var step = Math.abs(parseFloat(increment)); if (step == 1) { code += up ? '++' : '--'; } else { code += (up ? ' += ' : ' -= ') + step; } code += ') {\n' + branch + '}\n'; } else { code = ''; // Cache non-trivial values to variables to prevent repeated look-ups. var startVar = argument0; if (!argument0.match(/^\w+$/) && !Blockly.isNumber(argument0)) { var startVar = Blockly.Dart.variableDB_.getDistinctName( variable0 + '_start', Blockly.Variables.NAME_TYPE); code += 'var ' + startVar + ' = ' + argument0 + ';\n'; } var endVar = argument1; if (!argument1.match(/^\w+$/) && !Blockly.isNumber(argument1)) { var endVar = Blockly.Dart.variableDB_.getDistinctName( variable0 + '_end', Blockly.Variables.NAME_TYPE); code += 'var ' + endVar + ' = ' + argument1 + ';\n'; } // Determine loop direction at start, in case one of the bounds // changes during loop execution. var incVar = Blockly.Dart.variableDB_.getDistinctName( variable0 + '_inc', Blockly.Variables.NAME_TYPE); code += 'num ' + incVar + ' = '; if (Blockly.isNumber(increment)) { code += Math.abs(increment) + ';\n'; } else { code += '(' + increment + ').abs();\n'; } code += 'if (' + startVar + ' > ' + endVar + ') {\n'; code += ' ' + incVar + ' = -' + incVar +';\n'; code += '}\n'; code += 'for (' + variable0 + ' = ' + startVar + ';\n' + ' ' + incVar + ' >= 0 ? ' + variable0 + ' <= ' + endVar + ' : ' + variable0 + ' >= ' + endVar + ';\n' + ' ' + variable0 + ' += ' + incVar + ') {\n' + branch + '}\n'; } return code; }; Blockly.Dart['controls_forEach'] = function(block) { // For each loop. var variable0 = Blockly.Dart.variableDB_.getName( block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); var argument0 = Blockly.Dart.valueToCode(block, 'LIST', Blockly.Dart.ORDER_ASSIGNMENT) || '[]'; var branch = Blockly.Dart.statementToCode(block, 'DO'); if (Blockly.Dart.INFINITE_LOOP_TRAP) { branch = Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } var code = 'for (var ' + variable0 + ' in ' + argument0 + ') {\n' + branch + '}\n'; return code; }; Blockly.Dart['controls_flow_statements'] = function(block) { // Flow statements: continue, break. switch (block.getFieldValue('FLOW')) { case 'BREAK': return 'break;\n'; case 'CONTINUE': return 'continue;\n'; } throw 'Unknown flow statement.'; }; ================================================ FILE: extern/blockly/generators/dart/math.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2014 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Dart for math blocks. * @author q.neutron@gmail.com (Quynh Neutron) */ 'use strict'; goog.provide('Blockly.Dart.math'); goog.require('Blockly.Dart'); Blockly.Dart.addReservedWords('Math'); Blockly.Dart['math_number'] = function(block) { // Numeric value. var code = window.parseFloat(block.getFieldValue('NUM')); // -4.abs() returns -4 in Dart due to strange order of operation choices. // -4 is actually an operator and a number. Reflect this in the order. var order = code < 0 ? Blockly.Dart.ORDER_UNARY_PREFIX : Blockly.Dart.ORDER_ATOMIC; return [code, order]; }; Blockly.Dart['math_arithmetic'] = function(block) { // Basic arithmetic operators, and power. var OPERATORS = { ADD: [' + ', Blockly.Dart.ORDER_ADDITIVE], MINUS: [' - ', Blockly.Dart.ORDER_ADDITIVE], MULTIPLY: [' * ', Blockly.Dart.ORDER_MULTIPLICATIVE], DIVIDE: [' / ', Blockly.Dart.ORDER_MULTIPLICATIVE], POWER: [null, Blockly.Dart.ORDER_NONE] // Handle power separately. }; var tuple = OPERATORS[block.getFieldValue('OP')]; var operator = tuple[0]; var order = tuple[1]; var argument0 = Blockly.Dart.valueToCode(block, 'A', order) || '0'; var argument1 = Blockly.Dart.valueToCode(block, 'B', order) || '0'; var code; // Power in Dart requires a special case since it has no operator. if (!operator) { Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; code = 'Math.pow(' + argument0 + ', ' + argument1 + ')'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } code = argument0 + operator + argument1; return [code, order]; }; Blockly.Dart['math_single'] = function(block) { // Math operators with single operand. var operator = block.getFieldValue('OP'); var code; var arg; if (operator == 'NEG') { // Negation is a special case given its different operator precedence. arg = Blockly.Dart.valueToCode(block, 'NUM', Blockly.Dart.ORDER_UNARY_PREFIX) || '0'; if (arg[0] == '-') { // --3 is not legal in Dart. arg = ' ' + arg; } code = '-' + arg; return [code, Blockly.Dart.ORDER_UNARY_PREFIX]; } Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; if (operator == 'ABS' || operator.substring(0, 5) == 'ROUND') { arg = Blockly.Dart.valueToCode(block, 'NUM', Blockly.Dart.ORDER_UNARY_POSTFIX) || '0'; } else if (operator == 'SIN' || operator == 'COS' || operator == 'TAN') { arg = Blockly.Dart.valueToCode(block, 'NUM', Blockly.Dart.ORDER_MULTIPLICATIVE) || '0'; } else { arg = Blockly.Dart.valueToCode(block, 'NUM', Blockly.Dart.ORDER_NONE) || '0'; } // First, handle cases which generate values that don't need parentheses // wrapping the code. switch (operator) { case 'ABS': code = arg + '.abs()'; break; case 'ROOT': code = 'Math.sqrt(' + arg + ')'; break; case 'LN': code = 'Math.log(' + arg + ')'; break; case 'EXP': code = 'Math.exp(' + arg + ')'; break; case 'POW10': code = 'Math.pow(10,' + arg + ')'; break; case 'ROUND': code = arg + '.round()'; break; case 'ROUNDUP': code = arg + '.ceil()'; break; case 'ROUNDDOWN': code = arg + '.floor()'; break; case 'SIN': code = 'Math.sin(' + arg + ' / 180 * Math.PI)'; break; case 'COS': code = 'Math.cos(' + arg + ' / 180 * Math.PI)'; break; case 'TAN': code = 'Math.tan(' + arg + ' / 180 * Math.PI)'; break; } if (code) { return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } // Second, handle cases which generate values that may need parentheses // wrapping the code. switch (operator) { case 'LOG10': code = 'Math.log(' + arg + ') / Math.log(10)'; break; case 'ASIN': code = 'Math.asin(' + arg + ') / Math.PI * 180'; break; case 'ACOS': code = 'Math.acos(' + arg + ') / Math.PI * 180'; break; case 'ATAN': code = 'Math.atan(' + arg + ') / Math.PI * 180'; break; default: throw 'Unknown math operator: ' + operator; } return [code, Blockly.Dart.ORDER_MULTIPLICATIVE]; }; Blockly.Dart['math_constant'] = function(block) { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. var CONSTANTS = { PI: ['Math.PI', Blockly.Dart.ORDER_UNARY_POSTFIX], E: ['Math.E', Blockly.Dart.ORDER_UNARY_POSTFIX], GOLDEN_RATIO: ['(1 + Math.sqrt(5)) / 2', Blockly.Dart.ORDER_MULTIPLICATIVE], SQRT2: ['Math.SQRT2', Blockly.Dart.ORDER_UNARY_POSTFIX], SQRT1_2: ['Math.SQRT1_2', Blockly.Dart.ORDER_UNARY_POSTFIX], INFINITY: ['double.INFINITY', Blockly.Dart.ORDER_ATOMIC] }; var constant = block.getFieldValue('CONSTANT'); if (constant != 'INFINITY') { Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; } return CONSTANTS[constant]; }; Blockly.Dart['math_number_property'] = function(block) { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. var number_to_check = Blockly.Dart.valueToCode(block, 'NUMBER_TO_CHECK', Blockly.Dart.ORDER_MULTIPLICATIVE); if (!number_to_check) { return ['false', Blockly.Python.ORDER_ATOMIC]; } var dropdown_property = block.getFieldValue('PROPERTY'); var code; if (dropdown_property == 'PRIME') { // Prime is a special case as it is not a one-liner test. Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var functionName = Blockly.Dart.provideFunction_( 'math_isPrime', [ 'bool ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(n) {', ' // https://en.wikipedia.org/wiki/Primality_test#Naive_methods', ' if (n == 2 || n == 3) {', ' return true;', ' }', ' // False if n is null, negative, is 1, or not whole.', ' // And false if n is divisible by 2 or 3.', ' if (n == null || n <= 1 || n % 1 != 0 || n % 2 == 0 ||' + ' n % 3 == 0) {', ' return false;', ' }', ' // Check all the numbers of form 6k +/- 1, up to sqrt(n).', ' for (var x = 6; x <= Math.sqrt(n) + 1; x += 6) {', ' if (n % (x - 1) == 0 || n % (x + 1) == 0) {', ' return false;', ' }', ' }', ' return true;', '}']); code = functionName + '(' + number_to_check + ')'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } switch (dropdown_property) { case 'EVEN': code = number_to_check + ' % 2 == 0'; break; case 'ODD': code = number_to_check + ' % 2 == 1'; break; case 'WHOLE': code = number_to_check + ' % 1 == 0'; break; case 'POSITIVE': code = number_to_check + ' > 0'; break; case 'NEGATIVE': code = number_to_check + ' < 0'; break; case 'DIVISIBLE_BY': var divisor = Blockly.Dart.valueToCode(block, 'DIVISOR', Blockly.Dart.ORDER_MULTIPLICATIVE); if (!divisor) { return ['false', Blockly.Python.ORDER_ATOMIC]; } code = number_to_check + ' % ' + divisor + ' == 0'; break; } return [code, Blockly.Dart.ORDER_EQUALITY]; }; Blockly.Dart['math_change'] = function(block) { // Add to a variable in place. var argument0 = Blockly.Dart.valueToCode(block, 'DELTA', Blockly.Dart.ORDER_ADDITIVE) || '0'; var varName = Blockly.Dart.variableDB_.getName(block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); return varName + ' = (' + varName + ' is num ? ' + varName + ' : 0) + ' + argument0 + ';\n'; }; // Rounding functions have a single operand. Blockly.Dart['math_round'] = Blockly.Dart['math_single']; // Trigonometry functions have a single operand. Blockly.Dart['math_trig'] = Blockly.Dart['math_single']; Blockly.Dart['math_on_list'] = function(block) { // Math functions for lists. var func = block.getFieldValue('OP'); var list = Blockly.Dart.valueToCode(block, 'LIST', Blockly.Dart.ORDER_NONE) || '[]'; var code; switch (func) { case 'SUM': var functionName = Blockly.Dart.provideFunction_( 'math_sum', [ 'num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(List myList) {', ' num sumVal = 0;', ' myList.forEach((num entry) {sumVal += entry;});', ' return sumVal;', '}']); code = functionName + '(' + list + ')'; break; case 'MIN': Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var functionName = Blockly.Dart.provideFunction_( 'math_min', [ 'num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(List myList) {', ' if (myList.isEmpty) return null;', ' num minVal = myList[0];', ' myList.forEach((num entry) ' + '{minVal = Math.min(minVal, entry);});', ' return minVal;', '}']); code = functionName + '(' + list + ')'; break; case 'MAX': Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var functionName = Blockly.Dart.provideFunction_( 'math_max', [ 'num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(List myList) {', ' if (myList.isEmpty) return null;', ' num maxVal = myList[0];', ' myList.forEach((num entry) ' + '{maxVal = Math.max(maxVal, entry);});', ' return maxVal;', '}']); code = functionName + '(' + list + ')'; break; case 'AVERAGE': // This operation exclude null and values that are not int or float: // math_mean([null,null,"aString",1,9]) == 5.0. var functionName = Blockly.Dart.provideFunction_( 'math_average', [ 'num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(List myList) {', ' // First filter list for numbers only.', ' List localList = new List.from(myList);', ' localList.removeMatching((a) => a is! num);', ' if (localList.isEmpty) return null;', ' num sumVal = 0;', ' localList.forEach((num entry) {sumVal += entry;});', ' return sumVal / localList.length;', '}']); code = functionName + '(' + list + ')'; break; case 'MEDIAN': var functionName = Blockly.Dart.provideFunction_( 'math_median', [ 'num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(List myList) {', ' // First filter list for numbers only, then sort, ' + 'then return middle value', ' // or the average of two middle values if list has an ' + 'even number of elements.', ' List localList = new List.from(myList);', ' localList.removeMatching((a) => a is! num);', ' if (localList.isEmpty) return null;', ' localList.sort((a, b) => (a - b));', ' int index = localList.length ~/ 2;', ' if (localList.length % 2 == 1) {', ' return localList[index];', ' } else {', ' return (localList[index - 1] + localList[index]) / 2;', ' }', '}']); code = functionName + '(' + list + ')'; break; case 'MODE': Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1]. var functionName = Blockly.Dart.provideFunction_( 'math_modes', [ 'List ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(List values) {', ' List modes = [];', ' List counts = [];', ' int maxCount = 0;', ' for (int i = 0; i < values.length; i++) {', ' var value = values[i];', ' bool found = false;', ' int thisCount;', ' for (int j = 0; j < counts.length; j++) {', ' if (counts[j][0] == value) {', ' thisCount = ++counts[j][1];', ' found = true;', ' break;', ' }', ' }', ' if (!found) {', ' counts.add([value, 1]);', ' thisCount = 1;', ' }', ' maxCount = Math.max(thisCount, maxCount);', ' }', ' for (int j = 0; j < counts.length; j++) {', ' if (counts[j][1] == maxCount) {', ' modes.add(counts[j][0]);', ' }', ' }', ' return modes;', '}']); code = functionName + '(' + list + ')'; break; case 'STD_DEV': Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var functionName = Blockly.Dart.provideFunction_( 'math_standard_deviation', [ 'num ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(List myList) {', ' // First filter list for numbers only.', ' List numbers = new List.from(myList);', ' numbers.removeMatching((a) => a is! num);', ' if (numbers.isEmpty) return null;', ' num n = numbers.length;', ' num sum = 0;', ' numbers.forEach((x) => sum += x);', ' num mean = sum / n;', ' num sumSquare = 0;', ' numbers.forEach((x) => sumSquare += ' + 'Math.pow(x - mean, 2));', ' return Math.sqrt(sumSquare / n);', '}']); code = functionName + '(' + list + ')'; break; case 'RANDOM': Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var functionName = Blockly.Dart.provideFunction_( 'math_random_item', [ 'dynamic ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(List myList) {', ' int x = new Math.Random().nextInt(myList.length);', ' return myList[x];', '}']); code = functionName + '(' + list + ')'; break; default: throw 'Unknown operator: ' + func; } return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['math_modulo'] = function(block) { // Remainder computation. var argument0 = Blockly.Dart.valueToCode(block, 'DIVIDEND', Blockly.Dart.ORDER_MULTIPLICATIVE) || '0'; var argument1 = Blockly.Dart.valueToCode(block, 'DIVISOR', Blockly.Dart.ORDER_MULTIPLICATIVE) || '0'; var code = argument0 + ' % ' + argument1; return [code, Blockly.Dart.ORDER_MULTIPLICATIVE]; }; Blockly.Dart['math_constrain'] = function(block) { // Constrain a number between two limits. Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var argument0 = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_NONE) || '0'; var argument1 = Blockly.Dart.valueToCode(block, 'LOW', Blockly.Dart.ORDER_NONE) || '0'; var argument2 = Blockly.Dart.valueToCode(block, 'HIGH', Blockly.Dart.ORDER_NONE) || 'double.INFINITY'; var code = 'Math.min(Math.max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['math_random_int'] = function(block) { // Random integer between [X] and [Y]. Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var argument0 = Blockly.Dart.valueToCode(block, 'FROM', Blockly.Dart.ORDER_NONE) || '0'; var argument1 = Blockly.Dart.valueToCode(block, 'TO', Blockly.Dart.ORDER_NONE) || '0'; var functionName = Blockly.Dart.provideFunction_( 'math_random_int', [ 'int ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(num a, num b) {', ' if (a > b) {', ' // Swap a and b to ensure a is smaller.', ' num c = a;', ' a = b;', ' b = c;', ' }', ' return new Math.Random().nextInt(b - a + 1) + a;', '}']); var code = functionName + '(' + argument0 + ', ' + argument1 + ')'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['math_random_float'] = function(block) { // Random fraction between 0 and 1. Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; return ['new Math.Random().nextDouble()', Blockly.Dart.ORDER_UNARY_POSTFIX]; }; ================================================ FILE: extern/blockly/generators/dart/procedures.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2014 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Dart for procedure blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Dart.procedures'); goog.require('Blockly.Dart'); Blockly.Dart['procedures_defreturn'] = function(block) { // Define a procedure with a return value. var funcName = Blockly.Dart.variableDB_.getName(block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.Dart.statementToCode(block, 'STACK'); if (Blockly.Dart.INFINITE_LOOP_TRAP) { branch = Blockly.Dart.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } var returnValue = Blockly.Dart.valueToCode(block, 'RETURN', Blockly.Dart.ORDER_NONE) || ''; if (returnValue) { returnValue = ' return ' + returnValue + ';\n'; } var returnType = returnValue ? 'dynamic' : 'void'; var args = []; for (var x = 0; x < block.arguments_.length; x++) { args[x] = Blockly.Dart.variableDB_.getName(block.arguments_[x], Blockly.Variables.NAME_TYPE); } var code = returnType + ' ' + funcName + '(' + args.join(', ') + ') {\n' + branch + returnValue + '}'; code = Blockly.Dart.scrub_(block, code); Blockly.Dart.definitions_[funcName] = code; return null; }; // Defining a procedure without a return value uses the same generator as // a procedure with a return value. Blockly.Dart['procedures_defnoreturn'] = Blockly.Dart['procedures_defreturn']; Blockly.Dart['procedures_callreturn'] = function(block) { // Call a procedure with a return value. var funcName = Blockly.Dart.variableDB_.getName(block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var args = []; for (var x = 0; x < block.arguments_.length; x++) { args[x] = Blockly.Dart.valueToCode(block, 'ARG' + x, Blockly.Dart.ORDER_NONE) || 'null'; } var code = funcName + '(' + args.join(', ') + ')'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. var funcName = Blockly.Dart.variableDB_.getName(block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var args = []; for (var x = 0; x < block.arguments_.length; x++) { args[x] = Blockly.Dart.valueToCode(block, 'ARG' + x, Blockly.Dart.ORDER_NONE) || 'null'; } var code = funcName + '(' + args.join(', ') + ');\n'; return code; }; Blockly.Dart['procedures_ifreturn'] = function(block) { // Conditionally return value from a procedure. var condition = Blockly.Dart.valueToCode(block, 'CONDITION', Blockly.Dart.ORDER_NONE) || 'false'; var code = 'if (' + condition + ') {\n'; if (block.hasReturnValue_) { var value = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_NONE) || 'null'; code += ' return ' + value + ';\n'; } else { code += ' return;\n'; } code += '}\n'; return code; }; ================================================ FILE: extern/blockly/generators/dart/text.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2014 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Dart for text blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Dart.text'); goog.require('Blockly.Dart'); Blockly.Dart.addReservedWords('Html,Math'); Blockly.Dart['text'] = function(block) { // Text value. var code = Blockly.Dart.quote_(block.getFieldValue('TEXT')); return [code, Blockly.Dart.ORDER_ATOMIC]; }; Blockly.Dart['text_join'] = function(block) { // Create a string made up of any number of elements of any type. var code; if (block.itemCount_ == 0) { return ['\'\'', Blockly.Dart.ORDER_ATOMIC]; } else if (block.itemCount_ == 1) { var argument0 = Blockly.Dart.valueToCode(block, 'ADD0', Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\''; code = argument0 + '.toString()'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } else { code = new Array(block.itemCount_); for (var n = 0; n < block.itemCount_; n++) { code[n] = Blockly.Dart.valueToCode(block, 'ADD' + n, Blockly.Dart.ORDER_NONE) || '\'\''; } code = '[' + code.join(',') + '].join()'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } }; Blockly.Dart['text_append'] = function(block) { // Append to a variable in place. var varName = Blockly.Dart.variableDB_.getName(block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); var argument0 = Blockly.Dart.valueToCode(block, 'TEXT', Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\''; return varName + ' = [' + varName + ', ' + argument0 + '].join();\n'; }; Blockly.Dart['text_length'] = function(block) { // String length. var argument0 = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\''; return [argument0 + '.length', Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['text_isEmpty'] = function(block) { // Is the string null? var argument0 = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\''; return [argument0 + '.isEmpty', Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['text_indexOf'] = function(block) { // Search the text for a substring. var operator = block.getFieldValue('END') == 'FIRST' ? 'indexOf' : 'lastIndexOf'; var argument0 = Blockly.Dart.valueToCode(block, 'FIND', Blockly.Dart.ORDER_NONE) || '\'\''; var argument1 = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\''; var code = argument1 + '.' + operator + '(' + argument0 + ') + 1'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['text_charAt'] = function(block) { // Get letter at index. // Note: Until January 2013 this block did not have the WHERE input. var where = block.getFieldValue('WHERE') || 'FROM_START'; var at = Blockly.Dart.valueToCode(block, 'AT', Blockly.Dart.ORDER_NONE) || '1'; var text = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\''; switch (where) { case 'FIRST': var code = text + '[0]'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; case 'FROM_START': // Blockly uses one-based indicies. if (at.match(/^-?\d+$/)) { // If the index is a naked number, decrement it right now. at = parseInt(at, 10) - 1; } else { // If the index is dynamic, decrement it in code. at += ' - 1'; } var code = text + '[' + at + ']'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; case 'LAST': at = 1; // Fall through. case 'FROM_END': var functionName = Blockly.Dart.provideFunction_( 'text_get_from_end', [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(String text, num x) {', ' return text[text.length - x];', '}']); code = functionName + '(' + text + ', ' + at + ')'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; case 'RANDOM': Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; var functionName = Blockly.Dart.provideFunction_( 'text_random_letter', [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(String text) {', ' int x = new Math.Random().nextInt(text.length);', ' return text[x];', '}']); code = functionName + '(' + text + ')'; return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; } throw 'Unhandled option (text_charAt).'; }; Blockly.Dart['text_getSubstring'] = function(block) { // Get substring. var text = Blockly.Dart.valueToCode(block, 'STRING', Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\''; var where1 = block.getFieldValue('WHERE1'); var where2 = block.getFieldValue('WHERE2'); var at1 = Blockly.Dart.valueToCode(block, 'AT1', Blockly.Dart.ORDER_NONE) || '1'; var at2 = Blockly.Dart.valueToCode(block, 'AT2', Blockly.Dart.ORDER_NONE) || '1'; if (where1 == 'FIRST' && where2 == 'LAST') { var code = text; } else { var functionName = Blockly.Dart.provideFunction_( 'text_get_substring', [ 'function ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(text, where1, at1, where2, at2) {', ' function getAt(where, at) {', ' if (where == \'FROM_START\') {', ' at--;', ' } else if (where == \'FROM_END\') {', ' at = text.length - at;', ' } else if (where == \'FIRST\') {', ' at = 0;', ' } else if (where == \'LAST\') {', ' at = text.length - 1;', ' } else {', ' throw \'Unhandled option (text_getSubstring).\';', ' }', ' return at;', ' }', ' at1 = getAt(where1, at1);', ' at2 = getAt(where2, at2) + 1;', ' return text.substring(at1, at2);', '}']); var code = functionName + '(' + text + ', \'' + where1 + '\', ' + at1 + ', \'' + where2 + '\', ' + at2 + ')'; } return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['text_changeCase'] = function(block) { // Change capitalization. var OPERATORS = { UPPERCASE: '.toUpperCase()', LOWERCASE: '.toLowerCase()', TITLECASE: null }; var operator = OPERATORS[block.getFieldValue('CASE')]; var code; if (operator) { // Upper and lower case are functions built into Dart. var argument0 = Blockly.Dart.valueToCode(block, 'TEXT', Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\''; code = argument0 + operator; } else { // Title case is not a native Dart function. Define one. var functionName = Blockly.Dart.provideFunction_( 'text_toTitleCase', [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(String str) {', ' RegExp exp = new RegExp(r\'\\b\');', ' List list = str.split(exp);', ' final title = new StringBuffer();', ' for (String part in list) {', ' if (part.length > 0) {', ' title.write(part[0].toUpperCase());', ' if (part.length > 0) {', ' title.write(part.substring(1).toLowerCase());', ' }', ' }', ' }', ' return title.toString();', '}']); var argument0 = Blockly.Dart.valueToCode(block, 'TEXT', Blockly.Dart.ORDER_NONE) || '\'\''; code = functionName + '(' + argument0 + ')'; } return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['text_trim'] = function(block) { // Trim spaces. var OPERATORS = { LEFT: '.replaceFirst(new RegExp(r\'^\\s+\'), \'\')', RIGHT: '.replaceFirst(new RegExp(r\'\\s+$\'), \'\')', BOTH: '.trim()' }; var operator = OPERATORS[block.getFieldValue('MODE')]; var argument0 = Blockly.Dart.valueToCode(block, 'TEXT', Blockly.Dart.ORDER_UNARY_POSTFIX) || '\'\''; return [argument0 + operator, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; Blockly.Dart['text_print'] = function(block) { // Print statement. var argument0 = Blockly.Dart.valueToCode(block, 'TEXT', Blockly.Dart.ORDER_NONE) || '\'\''; return 'print(' + argument0 + ');\n'; }; Blockly.Dart['text_prompt'] = function(block) { // Prompt function. Blockly.Dart.definitions_['import_dart_html'] = 'import \'dart:html\' as Html;'; var msg = Blockly.Dart.quote_(block.getFieldValue('TEXT')); var code = 'Html.window.prompt(' + msg + ', \'\')'; var toNumber = block.getFieldValue('TYPE') == 'NUMBER'; if (toNumber) { Blockly.Dart.definitions_['import_dart_math'] = 'import \'dart:math\' as Math;'; code = 'Math.parseDouble(' + code + ')'; } return [code, Blockly.Dart.ORDER_UNARY_POSTFIX]; }; ================================================ FILE: extern/blockly/generators/dart/variables.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2014 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Dart for variable blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Dart.variables'); goog.require('Blockly.Dart'); Blockly.Dart['variables_get'] = function(block) { // Variable getter. var code = Blockly.Dart.variableDB_.getName(block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); return [code, Blockly.Dart.ORDER_ATOMIC]; }; Blockly.Dart['variables_set'] = function(block) { // Variable setter. var argument0 = Blockly.Dart.valueToCode(block, 'VALUE', Blockly.Dart.ORDER_ASSIGNMENT) || '0'; var varName = Blockly.Dart.variableDB_.getName(block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); return varName + ' = ' + argument0 + ';\n'; }; ================================================ FILE: extern/blockly/generators/dart.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2014 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Helper functions for generating Dart for blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Dart'); goog.require('Blockly.Generator'); Blockly.Dart = new Blockly.Generator('Dart'); /** * List of illegal variable names. * This is not intended to be a security feature. Blockly is 100% client-side, * so bypassing this list is trivial. This is intended to prevent users from * accidentally clobbering a built-in object or function. * @private */ Blockly.Dart.addReservedWords( // https://www.dartlang.org/docs/spec/latest/dart-language-specification.pdf // Section 16.1.1 'assert,break,case,catch,class,const,continue,default,do,else,enum,extends,false,final,finally,for,if,in,is,new,null,rethrow,return,super,switch,this,throw,true,try,var,void,while,with,' + // https://api.dartlang.org/dart_core.html 'print,identityHashCode,identical,BidirectionalIterator,Comparable,double,Function,int,Invocation,Iterable,Iterator,List,Map,Match,num,Pattern,RegExp,Set,StackTrace,String,StringSink,Type,bool,DateTime,Deprecated,Duration,Expando,Null,Object,RuneIterator,Runes,Stopwatch,StringBuffer,Symbol,Uri,Comparator,AbstractClassInstantiationError,ArgumentError,AssertionError,CastError,ConcurrentModificationError,CyclicInitializationError,Error,Exception,FallThroughError,FormatException,IntegerDivisionByZeroException,NoSuchMethodError,NullThrownError,OutOfMemoryError,RangeError,StackOverflowError,StateError,TypeError,UnimplementedError,UnsupportedError'); /** * Order of operation ENUMs. * https://www.dartlang.org/docs/dart-up-and-running/ch02.html#operator_table */ Blockly.Dart.ORDER_ATOMIC = 0; // 0 "" ... Blockly.Dart.ORDER_UNARY_POSTFIX = 1; // expr++ expr-- () [] . Blockly.Dart.ORDER_UNARY_PREFIX = 2; // -expr !expr ~expr ++expr --expr Blockly.Dart.ORDER_MULTIPLICATIVE = 3; // * / % ~/ Blockly.Dart.ORDER_ADDITIVE = 4; // + - Blockly.Dart.ORDER_SHIFT = 5; // << >> Blockly.Dart.ORDER_BITWISE_AND = 6; // & Blockly.Dart.ORDER_BITWISE_XOR = 7; // ^ Blockly.Dart.ORDER_BITWISE_OR = 8; // | Blockly.Dart.ORDER_RELATIONAL = 9; // >= > <= < as is is! Blockly.Dart.ORDER_EQUALITY = 10; // == != Blockly.Dart.ORDER_LOGICAL_AND = 11; // && Blockly.Dart.ORDER_LOGICAL_OR = 12; // || Blockly.Dart.ORDER_CONDITIONAL = 13; // expr ? expr : expr Blockly.Dart.ORDER_CASCADE = 14; // .. Blockly.Dart.ORDER_ASSIGNMENT = 15; // = *= /= ~/= %= += -= <<= >>= &= ^= |= Blockly.Dart.ORDER_NONE = 99; // (...) /** * Arbitrary code to inject into locations that risk causing infinite loops. * Any instances of '%1' will be replaced by the block ID that failed. * E.g. ' checkTimeout(%1);\n' * @type ?string */ Blockly.Dart.INFINITE_LOOP_TRAP = null; /** * Initialise the database of variable names. */ Blockly.Dart.init = function() { // Create a dictionary of definitions to be printed before the code. Blockly.Dart.definitions_ = Object.create(null); // Create a dictionary mapping desired function names in definitions_ // to actual function names (to avoid collisions with user functions). Blockly.Dart.functionNames_ = Object.create(null); if (Blockly.Variables) { if (!Blockly.Dart.variableDB_) { Blockly.Dart.variableDB_ = new Blockly.Names(Blockly.Dart.RESERVED_WORDS_); } else { Blockly.Dart.variableDB_.reset(); } var defvars = []; var variables = Blockly.Variables.allVariables(); for (var x = 0; x < variables.length; x++) { defvars[x] = 'var ' + Blockly.Dart.variableDB_.getName(variables[x], Blockly.Variables.NAME_TYPE) + ';'; } Blockly.Dart.definitions_['variables'] = defvars.join('\n'); } }; /** * Prepend the generated code with the variable definitions. * @param {string} code Generated code. * @return {string} Completed code. */ Blockly.Dart.finish = function(code) { // Indent every line. code = ' ' + code.replace(/\n/g, '\n '); code = code.replace(/\n\s+$/, '\n'); code = 'main() {\n' + code + '}'; // Convert the definitions dictionary into a list. var imports = []; var definitions = []; for (var name in Blockly.Dart.definitions_) { var def = Blockly.Dart.definitions_[name]; if (def.match(/^import\s/)) { imports.push(def); } else { definitions.push(def); } } var allDefs = imports.join('\n') + '\n\n' + definitions.join('\n\n'); return allDefs.replace(/\n\n+/g, '\n\n').replace(/\n*$/, '\n\n\n') + code; }; /** * Naked values are top-level blocks with outputs that aren't plugged into * anything. A trailing semicolon is needed to make this legal. * @param {string} line Line of generated code. * @return {string} Legal line of code. */ Blockly.Dart.scrubNakedValue = function(line) { return line + ';\n'; }; /** * Encode a string as a properly escaped Dart string, complete with quotes. * @param {string} string Text to encode. * @return {string} Dart string. * @private */ Blockly.Dart.quote_ = function(string) { // TODO: This is a quick hack. Replace with goog.string.quote string = string.replace(/\\/g, '\\\\') .replace(/\n/g, '\\\n') .replace(/\$/g, '\\$') .replace(/'/g, '\\\''); return '\'' + string + '\''; }; /** * Common tasks for generating Dart from blocks. * Handles comments for the specified block and any connected value blocks. * Calls any statements following this block. * @param {!Blockly.Block} block The current block. * @param {string} code The Dart code created for this block. * @return {string} Dart code with comments and subsequent blocks added. * @this {Blockly.CodeGenerator} * @private */ Blockly.Dart.scrub_ = function(block, code) { if (code === null) { // Block has handled code generation itself. return ''; } var commentCode = ''; // Only collect comments for blocks that aren't inline. if (!block.outputConnection || !block.outputConnection.targetConnection) { // Collect comment for this block. var comment = block.getCommentText(); if (comment) { commentCode += this.prefixLines(comment, '// ') + '\n'; } // Collect comments for all value arguments. // Don't collect comments for nested statements. for (var x = 0; x < block.inputList.length; x++) { if (block.inputList[x].type == Blockly.INPUT_VALUE) { var childBlock = block.inputList[x].connection.targetBlock(); if (childBlock) { var comment = this.allNestedComments(childBlock); if (comment) { commentCode += this.prefixLines(comment, '// '); } } } } } var nextBlock = block.nextConnection && block.nextConnection.targetBlock(); var nextCode = this.blockToCode(nextBlock); return commentCode + code + nextCode; }; ================================================ FILE: extern/blockly/generators/javascript/colour.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating JavaScript for colour blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.JavaScript.colour'); goog.require('Blockly.JavaScript'); Blockly.JavaScript['colour_picker'] = function(block) { // Colour picker. var code = '\'' + block.getFieldValue('COLOUR') + '\''; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; Blockly.JavaScript['colour_random'] = function(block) { // Generate a random colour. var functionName = Blockly.JavaScript.provideFunction_( 'colour_random', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '() {', ' var num = Math.floor(Math.random() * Math.pow(2, 24));', ' return \'#\' + (\'00000\' + num.toString(16)).substr(-6);', '}']); var code = functionName + '()'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; Blockly.JavaScript['colour_rgb'] = function(block) { // Compose a colour from RGB components expressed as percentages. var red = Blockly.JavaScript.valueToCode(block, 'RED', Blockly.JavaScript.ORDER_COMMA) || 0; var green = Blockly.JavaScript.valueToCode(block, 'GREEN', Blockly.JavaScript.ORDER_COMMA) || 0; var blue = Blockly.JavaScript.valueToCode(block, 'BLUE', Blockly.JavaScript.ORDER_COMMA) || 0; var functionName = Blockly.JavaScript.provideFunction_( 'colour_rgb', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(r, g, b) {', ' r = Math.max(Math.min(Number(r), 100), 0) * 2.55;', ' g = Math.max(Math.min(Number(g), 100), 0) * 2.55;', ' b = Math.max(Math.min(Number(b), 100), 0) * 2.55;', ' r = (\'0\' + (Math.round(r) || 0).toString(16)).slice(-2);', ' g = (\'0\' + (Math.round(g) || 0).toString(16)).slice(-2);', ' b = (\'0\' + (Math.round(b) || 0).toString(16)).slice(-2);', ' return \'#\' + r + g + b;', '}']); var code = functionName + '(' + red + ', ' + green + ', ' + blue + ')'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; Blockly.JavaScript['colour_blend'] = function(block) { // Blend two colours together. var c1 = Blockly.JavaScript.valueToCode(block, 'COLOUR1', Blockly.JavaScript.ORDER_COMMA) || '\'#000000\''; var c2 = Blockly.JavaScript.valueToCode(block, 'COLOUR2', Blockly.JavaScript.ORDER_COMMA) || '\'#000000\''; var ratio = Blockly.JavaScript.valueToCode(block, 'RATIO', Blockly.JavaScript.ORDER_COMMA) || 0.5; var functionName = Blockly.JavaScript.provideFunction_( 'colour_blend', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(c1, c2, ratio) {', ' ratio = Math.max(Math.min(Number(ratio), 1), 0);', ' var r1 = parseInt(c1.substring(1, 3), 16);', ' var g1 = parseInt(c1.substring(3, 5), 16);', ' var b1 = parseInt(c1.substring(5, 7), 16);', ' var r2 = parseInt(c2.substring(1, 3), 16);', ' var g2 = parseInt(c2.substring(3, 5), 16);', ' var b2 = parseInt(c2.substring(5, 7), 16);', ' var r = Math.round(r1 * (1 - ratio) + r2 * ratio);', ' var g = Math.round(g1 * (1 - ratio) + g2 * ratio);', ' var b = Math.round(b1 * (1 - ratio) + b2 * ratio);', ' r = (\'0\' + (r || 0).toString(16)).slice(-2);', ' g = (\'0\' + (g || 0).toString(16)).slice(-2);', ' b = (\'0\' + (b || 0).toString(16)).slice(-2);', ' return \'#\' + r + g + b;', '}']); var code = functionName + '(' + c1 + ', ' + c2 + ', ' + ratio + ')'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; ================================================ FILE: extern/blockly/generators/javascript/lists.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating JavaScript for list blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.JavaScript.lists'); goog.require('Blockly.JavaScript'); Blockly.JavaScript['lists_create_empty'] = function(block) { // Create an empty list. return ['[]', Blockly.JavaScript.ORDER_ATOMIC]; }; Blockly.JavaScript['lists_create_with'] = function(block) { // Create a list with any number of elements of any type. var code = new Array(block.itemCount_); for (var n = 0; n < block.itemCount_; n++) { code[n] = Blockly.JavaScript.valueToCode(block, 'ADD' + n, Blockly.JavaScript.ORDER_COMMA) || 'null'; } code = '[' + code.join(', ') + ']'; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; Blockly.JavaScript['lists_repeat'] = function(block) { // Create a list with one element repeated. var functionName = Blockly.JavaScript.provideFunction_( 'lists_repeat', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(value, n) {', ' var array = [];', ' for (var i = 0; i < n; i++) {', ' array[i] = value;', ' }', ' return array;', '}']); var argument0 = Blockly.JavaScript.valueToCode(block, 'ITEM', Blockly.JavaScript.ORDER_COMMA) || 'null'; var argument1 = Blockly.JavaScript.valueToCode(block, 'NUM', Blockly.JavaScript.ORDER_COMMA) || '0'; var code = functionName + '(' + argument0 + ', ' + argument1 + ')'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; Blockly.JavaScript['lists_length'] = function(block) { // List length. var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_FUNCTION_CALL) || '[]'; return [argument0 + '.length', Blockly.JavaScript.ORDER_MEMBER]; }; Blockly.JavaScript['lists_isEmpty'] = function(block) { // Is the list empty? var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_MEMBER) || '[]'; return ['!' + argument0 + '.length', Blockly.JavaScript.ORDER_LOGICAL_NOT]; }; Blockly.JavaScript['lists_indexOf'] = function(block) { // Find an item in the list. var operator = block.getFieldValue('END') == 'FIRST' ? 'indexOf' : 'lastIndexOf'; var argument0 = Blockly.JavaScript.valueToCode(block, 'FIND', Blockly.JavaScript.ORDER_NONE) || '\'\''; var argument1 = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_MEMBER) || '[]'; var code = argument1 + '.' + operator + '(' + argument0 + ') + 1'; return [code, Blockly.JavaScript.ORDER_MEMBER]; }; Blockly.JavaScript['lists_getIndex'] = function(block) { // Get element at index. // Note: Until January 2013 this block did not have MODE or WHERE inputs. var mode = block.getFieldValue('MODE') || 'GET'; var where = block.getFieldValue('WHERE') || 'FROM_START'; var at = Blockly.JavaScript.valueToCode(block, 'AT', Blockly.JavaScript.ORDER_UNARY_NEGATION) || '1'; var list = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_MEMBER) || '[]'; if (where == 'FIRST') { if (mode == 'GET') { var code = list + '[0]'; return [code, Blockly.JavaScript.ORDER_MEMBER]; } else if (mode == 'GET_REMOVE') { var code = list + '.shift()'; return [code, Blockly.JavaScript.ORDER_MEMBER]; } else if (mode == 'REMOVE') { return list + '.shift();\n'; } } else if (where == 'LAST') { if (mode == 'GET') { var code = list + '.slice(-1)[0]'; return [code, Blockly.JavaScript.ORDER_MEMBER]; } else if (mode == 'GET_REMOVE') { var code = list + '.pop()'; return [code, Blockly.JavaScript.ORDER_MEMBER]; } else if (mode == 'REMOVE') { return list + '.pop();\n'; } } else if (where == 'FROM_START') { // Blockly uses one-based indicies. if (Blockly.isNumber(at)) { // If the index is a naked number, decrement it right now. at = parseFloat(at) - 1; } else { // If the index is dynamic, decrement it in code. at += ' - 1'; } if (mode == 'GET') { var code = list + '[' + at + ']'; return [code, Blockly.JavaScript.ORDER_MEMBER]; } else if (mode == 'GET_REMOVE') { var code = list + '.splice(' + at + ', 1)[0]'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return list + '.splice(' + at + ', 1);\n'; } } else if (where == 'FROM_END') { if (mode == 'GET') { var code = list + '.slice(-' + at + ')[0]'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; } else if (mode == 'GET_REMOVE' || mode == 'REMOVE') { var functionName = Blockly.JavaScript.provideFunction_( 'lists_remove_from_end', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(list, x) {', ' x = list.length - x;', ' return list.splice(x, 1)[0];', '}']); code = functionName + '(' + list + ', ' + at + ')'; if (mode == 'GET_REMOVE') { return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return code + ';\n'; } } } else if (where == 'RANDOM') { var functionName = Blockly.JavaScript.provideFunction_( 'lists_get_random_item', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(list, remove) {', ' var x = Math.floor(Math.random() * list.length);', ' if (remove) {', ' return list.splice(x, 1)[0];', ' } else {', ' return list[x];', ' }', '}']); code = functionName + '(' + list + ', ' + (mode != 'GET') + ')'; if (mode == 'GET' || mode == 'GET_REMOVE') { return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return code + ';\n'; } } throw 'Unhandled combination (lists_getIndex).'; }; Blockly.JavaScript['lists_setIndex'] = function(block) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. var list = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_MEMBER) || '[]'; var mode = block.getFieldValue('MODE') || 'GET'; var where = block.getFieldValue('WHERE') || 'FROM_START'; var at = Blockly.JavaScript.valueToCode(block, 'AT', Blockly.JavaScript.ORDER_NONE) || '1'; var value = Blockly.JavaScript.valueToCode(block, 'TO', Blockly.JavaScript.ORDER_ASSIGNMENT) || 'null'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. function cacheList() { if (list.match(/^\w+$/)) { return ''; } var listVar = Blockly.JavaScript.variableDB_.getDistinctName( 'tmp_list', Blockly.Variables.NAME_TYPE); var code = 'var ' + listVar + ' = ' + list + ';\n'; list = listVar; return code; } if (where == 'FIRST') { if (mode == 'SET') { return list + '[0] = ' + value + ';\n'; } else if (mode == 'INSERT') { return list + '.unshift(' + value + ');\n'; } } else if (where == 'LAST') { if (mode == 'SET') { var code = cacheList(); code += list + '[' + list + '.length - 1] = ' + value + ';\n'; return code; } else if (mode == 'INSERT') { return list + '.push(' + value + ');\n'; } } else if (where == 'FROM_START') { // Blockly uses one-based indicies. if (Blockly.isNumber(at)) { // If the index is a naked number, decrement it right now. at = parseFloat(at) - 1; } else { // If the index is dynamic, decrement it in code. at += ' - 1'; } if (mode == 'SET') { return list + '[' + at + '] = ' + value + ';\n'; } else if (mode == 'INSERT') { return list + '.splice(' + at + ', 0, ' + value + ');\n'; } } else if (where == 'FROM_END') { var code = cacheList(); if (mode == 'SET') { code += list + '[' + list + '.length - ' + at + '] = ' + value + ';\n'; return code; } else if (mode == 'INSERT') { code += list + '.splice(' + list + '.length - ' + at + ', 0, ' + value + ');\n'; return code; } } else if (where == 'RANDOM') { var code = cacheList(); var xVar = Blockly.JavaScript.variableDB_.getDistinctName( 'tmp_x', Blockly.Variables.NAME_TYPE); code += 'var ' + xVar + ' = Math.floor(Math.random() * ' + list + '.length);\n'; if (mode == 'SET') { code += list + '[' + xVar + '] = ' + value + ';\n'; return code; } else if (mode == 'INSERT') { code += list + '.splice(' + xVar + ', 0, ' + value + ');\n'; return code; } } throw 'Unhandled combination (lists_setIndex).'; }; Blockly.JavaScript['lists_getSublist'] = function(block) { // Get sublist. var list = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_MEMBER) || '[]'; var where1 = block.getFieldValue('WHERE1'); var where2 = block.getFieldValue('WHERE2'); var at1 = Blockly.JavaScript.valueToCode(block, 'AT1', Blockly.JavaScript.ORDER_NONE) || '1'; var at2 = Blockly.JavaScript.valueToCode(block, 'AT2', Blockly.JavaScript.ORDER_NONE) || '1'; if (where1 == 'FIRST' && where2 == 'LAST') { var code = list + '.concat()'; } else { var functionName = Blockly.JavaScript.provideFunction_( 'lists_get_sublist', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(list, where1, at1, where2, at2) {', ' function getAt(where, at) {', ' if (where == \'FROM_START\') {', ' at--;', ' } else if (where == \'FROM_END\') {', ' at = list.length - at;', ' } else if (where == \'FIRST\') {', ' at = 0;', ' } else if (where == \'LAST\') {', ' at = list.length - 1;', ' } else {', ' throw \'Unhandled option (lists_getSublist).\';', ' }', ' return at;', ' }', ' at1 = getAt(where1, at1);', ' at2 = getAt(where2, at2) + 1;', ' return list.slice(at1, at2);', '}']); var code = functionName + '(' + list + ', \'' + where1 + '\', ' + at1 + ', \'' + where2 + '\', ' + at2 + ')'; } return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; ================================================ FILE: extern/blockly/generators/javascript/logic.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating JavaScript for logic blocks. * @author q.neutron@gmail.com (Quynh Neutron) */ 'use strict'; goog.provide('Blockly.JavaScript.logic'); goog.require('Blockly.JavaScript'); Blockly.JavaScript['controls_if'] = function(block) { // If/elseif/else condition. var n = 0; var argument = Blockly.JavaScript.valueToCode(block, 'IF' + n, Blockly.JavaScript.ORDER_NONE) || 'false'; var branch = Blockly.JavaScript.statementToCode(block, 'DO' + n); var code = 'if (' + argument + ') {\n' + branch + '}'; for (n = 1; n <= block.elseifCount_; n++) { argument = Blockly.JavaScript.valueToCode(block, 'IF' + n, Blockly.JavaScript.ORDER_NONE) || 'false'; branch = Blockly.JavaScript.statementToCode(block, 'DO' + n); code += ' else if (' + argument + ') {\n' + branch + '}'; } if (block.elseCount_) { branch = Blockly.JavaScript.statementToCode(block, 'ELSE'); code += ' else {\n' + branch + '}'; } return code + '\n'; }; Blockly.JavaScript['logic_compare'] = function(block) { // Comparison operator. var OPERATORS = { EQ: '==', NEQ: '!=', LT: '<', LTE: '<=', GT: '>', GTE: '>=' }; var operator = OPERATORS[block.getFieldValue('OP')]; var order = (operator == '==' || operator == '!=') ? Blockly.JavaScript.ORDER_EQUALITY : Blockly.JavaScript.ORDER_RELATIONAL; var argument0 = Blockly.JavaScript.valueToCode(block, 'A', order) || '0'; var argument1 = Blockly.JavaScript.valueToCode(block, 'B', order) || '0'; var code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; }; Blockly.JavaScript['logic_operation'] = function(block) { // Operations 'and', 'or'. var operator = (block.getFieldValue('OP') == 'AND') ? '&&' : '||'; var order = (operator == '&&') ? Blockly.JavaScript.ORDER_LOGICAL_AND : Blockly.JavaScript.ORDER_LOGICAL_OR; var argument0 = Blockly.JavaScript.valueToCode(block, 'A', order); var argument1 = Blockly.JavaScript.valueToCode(block, 'B', order); if (!argument0 && !argument1) { // If there are no arguments, then the return value is false. argument0 = 'false'; argument1 = 'false'; } else { // Single missing arguments have no effect on the return value. var defaultArgument = (operator == '&&') ? 'true' : 'false'; if (!argument0) { argument0 = defaultArgument; } if (!argument1) { argument1 = defaultArgument; } } var code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; }; Blockly.JavaScript['logic_negate'] = function(block) { // Negation. var order = Blockly.JavaScript.ORDER_LOGICAL_NOT; var argument0 = Blockly.JavaScript.valueToCode(block, 'BOOL', order) || 'true'; var code = '!' + argument0; return [code, order]; }; Blockly.JavaScript['logic_boolean'] = function(block) { // Boolean values true and false. var code = (block.getFieldValue('BOOL') == 'TRUE') ? 'true' : 'false'; return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; Blockly.JavaScript['logic_null'] = function(block) { // Null data type. return ['null', Blockly.JavaScript.ORDER_ATOMIC]; }; Blockly.JavaScript['logic_ternary'] = function(block) { // Ternary operator. var value_if = Blockly.JavaScript.valueToCode(block, 'IF', Blockly.JavaScript.ORDER_CONDITIONAL) || 'false'; var value_then = Blockly.JavaScript.valueToCode(block, 'THEN', Blockly.JavaScript.ORDER_CONDITIONAL) || 'null'; var value_else = Blockly.JavaScript.valueToCode(block, 'ELSE', Blockly.JavaScript.ORDER_CONDITIONAL) || 'null'; var code = value_if + ' ? ' + value_then + ' : ' + value_else return [code, Blockly.JavaScript.ORDER_CONDITIONAL]; }; ================================================ FILE: extern/blockly/generators/javascript/loops.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating JavaScript for loop blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.JavaScript.loops'); goog.require('Blockly.JavaScript'); Blockly.JavaScript['controls_repeat'] = function(block) { // Repeat n times (internal number). var repeats = Number(block.getFieldValue('TIMES')); var branch = Blockly.JavaScript.statementToCode(block, 'DO'); if (Blockly.JavaScript.INFINITE_LOOP_TRAP) { branch = Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } var loopVar = Blockly.JavaScript.variableDB_.getDistinctName( 'count', Blockly.Variables.NAME_TYPE); var code = 'for (var ' + loopVar + ' = 0; ' + loopVar + ' < ' + repeats + '; ' + loopVar + '++) {\n' + branch + '}\n'; return code; }; Blockly.JavaScript['controls_repeat_ext'] = function(block) { // Repeat n times (external number). var repeats = Blockly.JavaScript.valueToCode(block, 'TIMES', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0'; var branch = Blockly.JavaScript.statementToCode(block, 'DO'); if (Blockly.JavaScript.INFINITE_LOOP_TRAP) { branch = Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } var code = ''; var loopVar = Blockly.JavaScript.variableDB_.getDistinctName( 'count', Blockly.Variables.NAME_TYPE); var endVar = repeats; if (!repeats.match(/^\w+$/) && !Blockly.isNumber(repeats)) { var endVar = Blockly.JavaScript.variableDB_.getDistinctName( 'repeat_end', Blockly.Variables.NAME_TYPE); code += 'var ' + endVar + ' = ' + repeats + ';\n'; } code += 'for (var ' + loopVar + ' = 0; ' + loopVar + ' < ' + endVar + '; ' + loopVar + '++) {\n' + branch + '}\n'; return code; }; Blockly.JavaScript['controls_whileUntil'] = function(block) { // Do while/until loop. var until = block.getFieldValue('MODE') == 'UNTIL'; var argument0 = Blockly.JavaScript.valueToCode(block, 'BOOL', until ? Blockly.JavaScript.ORDER_LOGICAL_NOT : Blockly.JavaScript.ORDER_NONE) || 'false'; var branch = Blockly.JavaScript.statementToCode(block, 'DO'); if (Blockly.JavaScript.INFINITE_LOOP_TRAP) { branch = Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } if (until) { argument0 = '!' + argument0; } return 'while (' + argument0 + ') {\n' + branch + '}\n'; }; Blockly.JavaScript['controls_for'] = function(block) { // For loop. var variable0 = Blockly.JavaScript.variableDB_.getName( block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); var argument0 = Blockly.JavaScript.valueToCode(block, 'FROM', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0'; var argument1 = Blockly.JavaScript.valueToCode(block, 'TO', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0'; var increment = Blockly.JavaScript.valueToCode(block, 'BY', Blockly.JavaScript.ORDER_ASSIGNMENT) || '1'; var branch = Blockly.JavaScript.statementToCode(block, 'DO'); if (Blockly.JavaScript.INFINITE_LOOP_TRAP) { branch = Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } var code; if (Blockly.isNumber(argument0) && Blockly.isNumber(argument1) && Blockly.isNumber(increment)) { // All arguments are simple numbers. var up = parseFloat(argument0) <= parseFloat(argument1); code = 'for (' + variable0 + ' = ' + argument0 + '; ' + variable0 + (up ? ' <= ' : ' >= ') + argument1 + '; ' + variable0; var step = Math.abs(parseFloat(increment)); if (step == 1) { code += up ? '++' : '--'; } else { code += (up ? ' += ' : ' -= ') + step; } code += ') {\n' + branch + '}\n'; } else { code = ''; // Cache non-trivial values to variables to prevent repeated look-ups. var startVar = argument0; if (!argument0.match(/^\w+$/) && !Blockly.isNumber(argument0)) { var startVar = Blockly.JavaScript.variableDB_.getDistinctName( variable0 + '_start', Blockly.Variables.NAME_TYPE); code += 'var ' + startVar + ' = ' + argument0 + ';\n'; } var endVar = argument1; if (!argument1.match(/^\w+$/) && !Blockly.isNumber(argument1)) { var endVar = Blockly.JavaScript.variableDB_.getDistinctName( variable0 + '_end', Blockly.Variables.NAME_TYPE); code += 'var ' + endVar + ' = ' + argument1 + ';\n'; } // Determine loop direction at start, in case one of the bounds // changes during loop execution. var incVar = Blockly.JavaScript.variableDB_.getDistinctName( variable0 + '_inc', Blockly.Variables.NAME_TYPE); code += 'var ' + incVar + ' = '; if (Blockly.isNumber(increment)) { code += Math.abs(increment) + ';\n'; } else { code += 'Math.abs(' + increment + ');\n'; } code += 'if (' + startVar + ' > ' + endVar + ') {\n'; code += ' ' + incVar + ' = -' + incVar +';\n'; code += '}\n'; code += 'for (' + variable0 + ' = ' + startVar + ';\n' + ' ' + incVar + ' >= 0 ? ' + variable0 + ' <= ' + endVar + ' : ' + variable0 + ' >= ' + endVar + ';\n' + ' ' + variable0 + ' += ' + incVar + ') {\n' + branch + '}\n'; } return code; }; Blockly.JavaScript['controls_forEach'] = function(block) { // For each loop. var variable0 = Blockly.JavaScript.variableDB_.getName( block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); var argument0 = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_ASSIGNMENT) || '[]'; var branch = Blockly.JavaScript.statementToCode(block, 'DO'); if (Blockly.JavaScript.INFINITE_LOOP_TRAP) { branch = Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } var indexVar = Blockly.JavaScript.variableDB_.getDistinctName( variable0 + '_index', Blockly.Variables.NAME_TYPE); branch = ' ' + variable0 + ' = ' + argument0 + '[' + indexVar + '];\n' + branch; var code = 'for (var ' + indexVar + ' in ' + argument0 + ') {\n' + branch + '}\n'; return code; }; Blockly.JavaScript['controls_flow_statements'] = function(block) { // Flow statements: continue, break. switch (block.getFieldValue('FLOW')) { case 'BREAK': return 'break;\n'; case 'CONTINUE': return 'continue;\n'; } throw 'Unknown flow statement.'; }; ================================================ FILE: extern/blockly/generators/javascript/math.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating JavaScript for math blocks. * @author q.neutron@gmail.com (Quynh Neutron) */ 'use strict'; goog.provide('Blockly.JavaScript.math'); goog.require('Blockly.JavaScript'); Blockly.JavaScript['math_number'] = function(block) { // Numeric value. var code = parseFloat(block.getFieldValue('NUM')); return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; Blockly.JavaScript['math_arithmetic'] = function(block) { // Basic arithmetic operators, and power. var OPERATORS = { ADD: [' + ', Blockly.JavaScript.ORDER_ADDITION], MINUS: [' - ', Blockly.JavaScript.ORDER_SUBTRACTION], MULTIPLY: [' * ', Blockly.JavaScript.ORDER_MULTIPLICATION], DIVIDE: [' / ', Blockly.JavaScript.ORDER_DIVISION], POWER: [null, Blockly.JavaScript.ORDER_COMMA] // Handle power separately. }; var tuple = OPERATORS[block.getFieldValue('OP')]; var operator = tuple[0]; var order = tuple[1]; var argument0 = Blockly.JavaScript.valueToCode(block, 'A', order) || '0'; var argument1 = Blockly.JavaScript.valueToCode(block, 'B', order) || '0'; var code; // Power in JavaScript requires a special case since it has no operator. if (!operator) { code = 'Math.pow(' + argument0 + ', ' + argument1 + ')'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; } code = argument0 + operator + argument1; return [code, order]; }; Blockly.JavaScript['math_single'] = function(block) { // Math operators with single operand. var operator = block.getFieldValue('OP'); var code; var arg; if (operator == 'NEG') { // Negation is a special case given its different operator precedence. arg = Blockly.JavaScript.valueToCode(block, 'NUM', Blockly.JavaScript.ORDER_UNARY_NEGATION) || '0'; if (arg[0] == '-') { // --3 is not legal in JS. arg = ' ' + arg; } code = '-' + arg; return [code, Blockly.JavaScript.ORDER_UNARY_NEGATION]; } if (operator == 'SIN' || operator == 'COS' || operator == 'TAN') { arg = Blockly.JavaScript.valueToCode(block, 'NUM', Blockly.JavaScript.ORDER_DIVISION) || '0'; } else { arg = Blockly.JavaScript.valueToCode(block, 'NUM', Blockly.JavaScript.ORDER_NONE) || '0'; } // First, handle cases which generate values that don't need parentheses // wrapping the code. switch (operator) { case 'ABS': code = 'Math.abs(' + arg + ')'; break; case 'ROOT': code = 'Math.sqrt(' + arg + ')'; break; case 'LN': code = 'Math.log(' + arg + ')'; break; case 'EXP': code = 'Math.exp(' + arg + ')'; break; case 'POW10': code = 'Math.pow(10,' + arg + ')'; break; case 'ROUND': code = 'Math.round(' + arg + ')'; break; case 'ROUNDUP': code = 'Math.ceil(' + arg + ')'; break; case 'ROUNDDOWN': code = 'Math.floor(' + arg + ')'; break; case 'SIN': code = 'Math.sin(' + arg + ' / 180 * Math.PI)'; break; case 'COS': code = 'Math.cos(' + arg + ' / 180 * Math.PI)'; break; case 'TAN': code = 'Math.tan(' + arg + ' / 180 * Math.PI)'; break; } if (code) { return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; } // Second, handle cases which generate values that may need parentheses // wrapping the code. switch (operator) { case 'LOG10': code = 'Math.log(' + arg + ') / Math.log(10)'; break; case 'ASIN': code = 'Math.asin(' + arg + ') / Math.PI * 180'; break; case 'ACOS': code = 'Math.acos(' + arg + ') / Math.PI * 180'; break; case 'ATAN': code = 'Math.atan(' + arg + ') / Math.PI * 180'; break; default: throw 'Unknown math operator: ' + operator; } return [code, Blockly.JavaScript.ORDER_DIVISION]; }; Blockly.JavaScript['math_constant'] = function(block) { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. var CONSTANTS = { PI: ['Math.PI', Blockly.JavaScript.ORDER_MEMBER], E: ['Math.E', Blockly.JavaScript.ORDER_MEMBER], GOLDEN_RATIO: ['(1 + Math.sqrt(5)) / 2', Blockly.JavaScript.ORDER_DIVISION], SQRT2: ['Math.SQRT2', Blockly.JavaScript.ORDER_MEMBER], SQRT1_2: ['Math.SQRT1_2', Blockly.JavaScript.ORDER_MEMBER], INFINITY: ['Infinity', Blockly.JavaScript.ORDER_ATOMIC] }; return CONSTANTS[block.getFieldValue('CONSTANT')]; }; Blockly.JavaScript['math_number_property'] = function(block) { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. var number_to_check = Blockly.JavaScript.valueToCode(block, 'NUMBER_TO_CHECK', Blockly.JavaScript.ORDER_MODULUS) || '0'; var dropdown_property = block.getFieldValue('PROPERTY'); var code; if (dropdown_property == 'PRIME') { // Prime is a special case as it is not a one-liner test. var functionName = Blockly.JavaScript.provideFunction_( 'math_isPrime', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(n) {', ' // https://en.wikipedia.org/wiki/Primality_test#Naive_methods', ' if (n == 2 || n == 3) {', ' return true;', ' }', ' // False if n is NaN, negative, is 1, or not whole.', ' // And false if n is divisible by 2 or 3.', ' if (isNaN(n) || n <= 1 || n % 1 != 0 || n % 2 == 0 ||' + ' n % 3 == 0) {', ' return false;', ' }', ' // Check all the numbers of form 6k +/- 1, up to sqrt(n).', ' for (var x = 6; x <= Math.sqrt(n) + 1; x += 6) {', ' if (n % (x - 1) == 0 || n % (x + 1) == 0) {', ' return false;', ' }', ' }', ' return true;', '}']); code = functionName + '(' + number_to_check + ')'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; } switch (dropdown_property) { case 'EVEN': code = number_to_check + ' % 2 == 0'; break; case 'ODD': code = number_to_check + ' % 2 == 1'; break; case 'WHOLE': code = number_to_check + ' % 1 == 0'; break; case 'POSITIVE': code = number_to_check + ' > 0'; break; case 'NEGATIVE': code = number_to_check + ' < 0'; break; case 'DIVISIBLE_BY': var divisor = Blockly.JavaScript.valueToCode(block, 'DIVISOR', Blockly.JavaScript.ORDER_MODULUS) || '0'; code = number_to_check + ' % ' + divisor + ' == 0'; break; } return [code, Blockly.JavaScript.ORDER_EQUALITY]; }; Blockly.JavaScript['math_change'] = function(block) { // Add to a variable in place. var argument0 = Blockly.JavaScript.valueToCode(block, 'DELTA', Blockly.JavaScript.ORDER_ADDITION) || '0'; var varName = Blockly.JavaScript.variableDB_.getName( block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); return varName + ' = (typeof ' + varName + ' == \'number\' ? ' + varName + ' : 0) + ' + argument0 + ';\n'; }; // Rounding functions have a single operand. Blockly.JavaScript['math_round'] = Blockly.JavaScript['math_single']; // Trigonometry functions have a single operand. Blockly.JavaScript['math_trig'] = Blockly.JavaScript['math_single']; Blockly.JavaScript['math_on_list'] = function(block) { // Math functions for lists. var func = block.getFieldValue('OP'); var list, code; switch (func) { case 'SUM': list = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_MEMBER) || '[]'; code = list + '.reduce(function(x, y) {return x + y;})'; break; case 'MIN': list = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_COMMA) || '[]'; code = 'Math.min.apply(null, ' + list + ')'; break; case 'MAX': list = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_COMMA) || '[]'; code = 'Math.max.apply(null, ' + list + ')'; break; case 'AVERAGE': // math_median([null,null,1,3]) == 2.0. var functionName = Blockly.JavaScript.provideFunction_( 'math_mean', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(myList) {', ' return myList.reduce(function(x, y) {return x + y;}) / ' + 'myList.length;', '}']); list = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_NONE) || '[]'; code = functionName + '(' + list + ')'; break; case 'MEDIAN': // math_median([null,null,1,3]) == 2.0. var functionName = Blockly.JavaScript.provideFunction_( 'math_median', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(myList) {', ' var localList = myList.filter(function (x) ' + '{return typeof x == \'number\';});', ' if (!localList.length) return null;', ' localList.sort(function(a, b) {return b - a;});', ' if (localList.length % 2 == 0) {', ' return (localList[localList.length / 2 - 1] + ' + 'localList[localList.length / 2]) / 2;', ' } else {', ' return localList[(localList.length - 1) / 2];', ' }', '}']); list = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_NONE) || '[]'; code = functionName + '(' + list + ')'; break; case 'MODE': // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1]. var functionName = Blockly.JavaScript.provideFunction_( 'math_modes', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(values) {', ' var modes = [];', ' var counts = [];', ' var maxCount = 0;', ' for (var i = 0; i < values.length; i++) {', ' var value = values[i];', ' var found = false;', ' var thisCount;', ' for (var j = 0; j < counts.length; j++) {', ' if (counts[j][0] === value) {', ' thisCount = ++counts[j][1];', ' found = true;', ' break;', ' }', ' }', ' if (!found) {', ' counts.push([value, 1]);', ' thisCount = 1;', ' }', ' maxCount = Math.max(thisCount, maxCount);', ' }', ' for (var j = 0; j < counts.length; j++) {', ' if (counts[j][1] == maxCount) {', ' modes.push(counts[j][0]);', ' }', ' }', ' return modes;', '}']); list = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_NONE) || '[]'; code = functionName + '(' + list + ')'; break; case 'STD_DEV': var functionName = Blockly.JavaScript.provideFunction_( 'math_standard_deviation', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(numbers) {', ' var n = numbers.length;', ' if (!n) return null;', ' var mean = numbers.reduce(function(x, y) {return x + y;}) / n;', ' var variance = 0;', ' for (var j = 0; j < n; j++) {', ' variance += Math.pow(numbers[j] - mean, 2);', ' }', ' variance = variance / n;', ' return Math.sqrt(variance);', '}']); list = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_NONE) || '[]'; code = functionName + '(' + list + ')'; break; case 'RANDOM': var functionName = Blockly.JavaScript.provideFunction_( 'math_random_list', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(list) {', ' var x = Math.floor(Math.random() * list.length);', ' return list[x];', '}']); list = Blockly.JavaScript.valueToCode(block, 'LIST', Blockly.JavaScript.ORDER_NONE) || '[]'; code = functionName + '(' + list + ')'; break; default: throw 'Unknown operator: ' + func; } return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; Blockly.JavaScript['math_modulo'] = function(block) { // Remainder computation. var argument0 = Blockly.JavaScript.valueToCode(block, 'DIVIDEND', Blockly.JavaScript.ORDER_MODULUS) || '0'; var argument1 = Blockly.JavaScript.valueToCode(block, 'DIVISOR', Blockly.JavaScript.ORDER_MODULUS) || '0'; var code = argument0 + ' % ' + argument1; return [code, Blockly.JavaScript.ORDER_MODULUS]; }; Blockly.JavaScript['math_constrain'] = function(block) { // Constrain a number between two limits. var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_COMMA) || '0'; var argument1 = Blockly.JavaScript.valueToCode(block, 'LOW', Blockly.JavaScript.ORDER_COMMA) || '0'; var argument2 = Blockly.JavaScript.valueToCode(block, 'HIGH', Blockly.JavaScript.ORDER_COMMA) || 'Infinity'; var code = 'Math.min(Math.max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; Blockly.JavaScript['math_random_int'] = function(block) { // Random integer between [X] and [Y]. var argument0 = Blockly.JavaScript.valueToCode(block, 'FROM', Blockly.JavaScript.ORDER_COMMA) || '0'; var argument1 = Blockly.JavaScript.valueToCode(block, 'TO', Blockly.JavaScript.ORDER_COMMA) || '0'; var functionName = Blockly.JavaScript.provideFunction_( 'math_random_int', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(a, b) {', ' if (a > b) {', ' // Swap a and b to ensure a is smaller.', ' var c = a;', ' a = b;', ' b = c;', ' }', ' return Math.floor(Math.random() * (b - a + 1) + a);', '}']); var code = functionName + '(' + argument0 + ', ' + argument1 + ')'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; Blockly.JavaScript['math_random_float'] = function(block) { // Random fraction between 0 and 1. return ['Math.random()', Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; ================================================ FILE: extern/blockly/generators/javascript/procedures.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating JavaScript for procedure blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.JavaScript.procedures'); goog.require('Blockly.JavaScript'); Blockly.JavaScript['procedures_defreturn'] = function(block) { // Define a procedure with a return value. var funcName = Blockly.JavaScript.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.JavaScript.statementToCode(block, 'STACK'); if (Blockly.JavaScript.INFINITE_LOOP_TRAP) { branch = Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } var returnValue = Blockly.JavaScript.valueToCode(block, 'RETURN', Blockly.JavaScript.ORDER_NONE) || ''; if (returnValue) { returnValue = ' return ' + returnValue + ';\n'; } var args = []; for (var x = 0; x < block.arguments_.length; x++) { args[x] = Blockly.JavaScript.variableDB_.getName(block.arguments_[x], Blockly.Variables.NAME_TYPE); } var code = 'function ' + funcName + '(' + args.join(', ') + ') {\n' + branch + returnValue + '}'; code = Blockly.JavaScript.scrub_(block, code); Blockly.JavaScript.definitions_[funcName] = code; return null; }; // Defining a procedure without a return value uses the same generator as // a procedure with a return value. Blockly.JavaScript['procedures_defnoreturn'] = Blockly.JavaScript['procedures_defreturn']; Blockly.JavaScript['procedures_callreturn'] = function(block) { // Call a procedure with a return value. var funcName = Blockly.JavaScript.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var args = []; for (var x = 0; x < block.arguments_.length; x++) { args[x] = Blockly.JavaScript.valueToCode(block, 'ARG' + x, Blockly.JavaScript.ORDER_COMMA) || 'null'; } var code = funcName + '(' + args.join(', ') + ')'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; Blockly.JavaScript['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. var funcName = Blockly.JavaScript.variableDB_.getName( block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var args = []; for (var x = 0; x < block.arguments_.length; x++) { args[x] = Blockly.JavaScript.valueToCode(block, 'ARG' + x, Blockly.JavaScript.ORDER_COMMA) || 'null'; } var code = funcName + '(' + args.join(', ') + ');\n'; return code; }; Blockly.JavaScript['procedures_ifreturn'] = function(block) { // Conditionally return value from a procedure. var condition = Blockly.JavaScript.valueToCode(block, 'CONDITION', Blockly.JavaScript.ORDER_NONE) || 'false'; var code = 'if (' + condition + ') {\n'; if (block.hasReturnValue_) { var value = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_NONE) || 'null'; code += ' return ' + value + ';\n'; } else { code += ' return;\n'; } code += '}\n'; return code; }; ================================================ FILE: extern/blockly/generators/javascript/text.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating JavaScript for text blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.JavaScript.text'); goog.require('Blockly.JavaScript'); Blockly.JavaScript['text'] = function(block) { // Text value. var code = Blockly.JavaScript.quote_(block.getFieldValue('TEXT')); return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; Blockly.JavaScript['text_join'] = function(block) { // Create a string made up of any number of elements of any type. var code; if (block.itemCount_ == 0) { return ['\'\'', Blockly.JavaScript.ORDER_ATOMIC]; } else if (block.itemCount_ == 1) { var argument0 = Blockly.JavaScript.valueToCode(block, 'ADD0', Blockly.JavaScript.ORDER_NONE) || '\'\''; code = 'String(' + argument0 + ')'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; } else if (block.itemCount_ == 2) { var argument0 = Blockly.JavaScript.valueToCode(block, 'ADD0', Blockly.JavaScript.ORDER_NONE) || '\'\''; var argument1 = Blockly.JavaScript.valueToCode(block, 'ADD1', Blockly.JavaScript.ORDER_NONE) || '\'\''; code = 'String(' + argument0 + ') + String(' + argument1 + ')'; return [code, Blockly.JavaScript.ORDER_ADDITION]; } else { code = new Array(block.itemCount_); for (var n = 0; n < block.itemCount_; n++) { code[n] = Blockly.JavaScript.valueToCode(block, 'ADD' + n, Blockly.JavaScript.ORDER_COMMA) || '\'\''; } code = '[' + code.join(',') + '].join(\'\')'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; } }; Blockly.JavaScript['text_append'] = function(block) { // Append to a variable in place. var varName = Blockly.JavaScript.variableDB_.getName( block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); var argument0 = Blockly.JavaScript.valueToCode(block, 'TEXT', Blockly.JavaScript.ORDER_NONE) || '\'\''; return varName + ' = String(' + varName + ') + String(' + argument0 + ');\n'; }; Blockly.JavaScript['text_length'] = function(block) { // String length. var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_FUNCTION_CALL) || '\'\''; return [argument0 + '.length', Blockly.JavaScript.ORDER_MEMBER]; }; Blockly.JavaScript['text_isEmpty'] = function(block) { // Is the string null? var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_MEMBER) || '\'\''; return ['!' + argument0, Blockly.JavaScript.ORDER_LOGICAL_NOT]; }; Blockly.JavaScript['text_indexOf'] = function(block) { // Search the text for a substring. var operator = block.getFieldValue('END') == 'FIRST' ? 'indexOf' : 'lastIndexOf'; var argument0 = Blockly.JavaScript.valueToCode(block, 'FIND', Blockly.JavaScript.ORDER_NONE) || '\'\''; var argument1 = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_MEMBER) || '\'\''; var code = argument1 + '.' + operator + '(' + argument0 + ') + 1'; return [code, Blockly.JavaScript.ORDER_MEMBER]; }; Blockly.JavaScript['text_charAt'] = function(block) { // Get letter at index. // Note: Until January 2013 this block did not have the WHERE input. var where = block.getFieldValue('WHERE') || 'FROM_START'; var at = Blockly.JavaScript.valueToCode(block, 'AT', Blockly.JavaScript.ORDER_UNARY_NEGATION) || '1'; var text = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_MEMBER) || '\'\''; switch (where) { case 'FIRST': var code = text + '.charAt(0)'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; case 'LAST': var code = text + '.slice(-1)'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; case 'FROM_START': // Blockly uses one-based indicies. if (Blockly.isNumber(at)) { // If the index is a naked number, decrement it right now. at = parseFloat(at) - 1; } else { // If the index is dynamic, decrement it in code. at += ' - 1'; } var code = text + '.charAt(' + at + ')'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; case 'FROM_END': var code = text + '.slice(-' + at + ').charAt(0)'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; case 'RANDOM': var functionName = Blockly.JavaScript.provideFunction_( 'text_random_letter', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(text) {', ' var x = Math.floor(Math.random() * text.length);', ' return text[x];', '}']); code = functionName + '(' + text + ')'; return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; } throw 'Unhandled option (text_charAt).'; }; Blockly.JavaScript['text_getSubstring'] = function(block) { // Get substring. var text = Blockly.JavaScript.valueToCode(block, 'STRING', Blockly.JavaScript.ORDER_MEMBER) || '\'\''; var where1 = block.getFieldValue('WHERE1'); var where2 = block.getFieldValue('WHERE2'); var at1 = Blockly.JavaScript.valueToCode(block, 'AT1', Blockly.JavaScript.ORDER_NONE) || '1'; var at2 = Blockly.JavaScript.valueToCode(block, 'AT2', Blockly.JavaScript.ORDER_NONE) || '1'; if (where1 == 'FIRST' && where2 == 'LAST') { var code = text; } else { var functionName = Blockly.JavaScript.provideFunction_( 'text_get_substring', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(text, where1, at1, where2, at2) {', ' function getAt(where, at) {', ' if (where == \'FROM_START\') {', ' at--;', ' } else if (where == \'FROM_END\') {', ' at = text.length - at;', ' } else if (where == \'FIRST\') {', ' at = 0;', ' } else if (where == \'LAST\') {', ' at = text.length - 1;', ' } else {', ' throw \'Unhandled option (text_getSubstring).\';', ' }', ' return at;', ' }', ' at1 = getAt(where1, at1);', ' at2 = getAt(where2, at2) + 1;', ' return text.slice(at1, at2);', '}']); var code = functionName + '(' + text + ', \'' + where1 + '\', ' + at1 + ', \'' + where2 + '\', ' + at2 + ')'; } return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; Blockly.JavaScript['text_changeCase'] = function(block) { // Change capitalization. var OPERATORS = { UPPERCASE: '.toUpperCase()', LOWERCASE: '.toLowerCase()', TITLECASE: null }; var operator = OPERATORS[block.getFieldValue('CASE')]; var code; if (operator) { // Upper and lower case are functions built into JavaScript. var argument0 = Blockly.JavaScript.valueToCode(block, 'TEXT', Blockly.JavaScript.ORDER_MEMBER) || '\'\''; code = argument0 + operator; } else { // Title case is not a native JavaScript function. Define one. var functionName = Blockly.JavaScript.provideFunction_( 'text_toTitleCase', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(str) {', ' return str.replace(/\\S+/g,', ' function(txt) {return txt[0].toUpperCase() + ' + 'txt.substring(1).toLowerCase();});', '}']); var argument0 = Blockly.JavaScript.valueToCode(block, 'TEXT', Blockly.JavaScript.ORDER_NONE) || '\'\''; code = functionName + '(' + argument0 + ')'; } return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; Blockly.JavaScript['text_trim'] = function(block) { // Trim spaces. var OPERATORS = { LEFT: '.trimLeft()', RIGHT: '.trimRight()', BOTH: '.trim()' }; var operator = OPERATORS[block.getFieldValue('MODE')]; var argument0 = Blockly.JavaScript.valueToCode(block, 'TEXT', Blockly.JavaScript.ORDER_MEMBER) || '\'\''; return [argument0 + operator, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; Blockly.JavaScript['text_print'] = function(block) { // Print statement. var argument0 = Blockly.JavaScript.valueToCode(block, 'TEXT', Blockly.JavaScript.ORDER_NONE) || '\'\''; return 'window.alert(' + argument0 + ');\n'; }; Blockly.JavaScript['text_prompt'] = function(block) { // Prompt function. var msg = Blockly.JavaScript.quote_(block.getFieldValue('TEXT')); var code = 'window.prompt(' + msg + ')'; var toNumber = block.getFieldValue('TYPE') == 'NUMBER'; if (toNumber) { code = 'parseFloat(' + code + ')'; } return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL]; }; ================================================ FILE: extern/blockly/generators/javascript/variables.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating JavaScript for variable blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.JavaScript.variables'); goog.require('Blockly.JavaScript'); Blockly.JavaScript['variables_get'] = function(block) { // Variable getter. var code = Blockly.JavaScript.variableDB_.getName(block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); return [code, Blockly.JavaScript.ORDER_ATOMIC]; }; Blockly.JavaScript['variables_set'] = function(block) { // Variable setter. var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE', Blockly.JavaScript.ORDER_ASSIGNMENT) || '0'; var varName = Blockly.JavaScript.variableDB_.getName( block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); return varName + ' = ' + argument0 + ';\n'; }; ================================================ FILE: extern/blockly/generators/javascript.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Helper functions for generating JavaScript for blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.JavaScript'); goog.require('Blockly.Generator'); Blockly.JavaScript = new Blockly.Generator('JavaScript'); /** * List of illegal variable names. * This is not intended to be a security feature. Blockly is 100% client-side, * so bypassing this list is trivial. This is intended to prevent users from * accidentally clobbering a built-in object or function. * @private */ Blockly.JavaScript.addReservedWords( 'Blockly,' + // In case JS is evaled in the current window. // https://developer.mozilla.org/en/JavaScript/Reference/Reserved_Words 'break,case,catch,continue,debugger,default,delete,do,else,finally,for,function,if,in,instanceof,new,return,switch,this,throw,try,typeof,var,void,while,with,' + 'class,enum,export,extends,import,super,implements,interface,let,package,private,protected,public,static,yield,' + 'const,null,true,false,' + // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects 'Array,ArrayBuffer,Boolean,Date,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Error,eval,EvalError,Float32Array,Float64Array,Function,Infinity,Int16Array,Int32Array,Int8Array,isFinite,isNaN,Iterator,JSON,Math,NaN,Number,Object,parseFloat,parseInt,RangeError,ReferenceError,RegExp,StopIteration,String,SyntaxError,TypeError,Uint16Array,Uint32Array,Uint8Array,Uint8ClampedArray,undefined,uneval,URIError,' + // https://developer.mozilla.org/en/DOM/window 'applicationCache,closed,Components,content,_content,controllers,crypto,defaultStatus,dialogArguments,directories,document,frameElement,frames,fullScreen,globalStorage,history,innerHeight,innerWidth,length,location,locationbar,localStorage,menubar,messageManager,mozAnimationStartTime,mozInnerScreenX,mozInnerScreenY,mozPaintCount,name,navigator,opener,outerHeight,outerWidth,pageXOffset,pageYOffset,parent,performance,personalbar,pkcs11,returnValue,screen,screenX,screenY,scrollbars,scrollMaxX,scrollMaxY,scrollX,scrollY,self,sessionStorage,sidebar,status,statusbar,toolbar,top,URL,window,' + 'addEventListener,alert,atob,back,blur,btoa,captureEvents,clearImmediate,clearInterval,clearTimeout,close,confirm,disableExternalCapture,dispatchEvent,dump,enableExternalCapture,escape,find,focus,forward,GeckoActiveXObject,getAttention,getAttentionWithCycleCount,getComputedStyle,getSelection,home,matchMedia,maximize,minimize,moveBy,moveTo,mozRequestAnimationFrame,open,openDialog,postMessage,print,prompt,QueryInterface,releaseEvents,removeEventListener,resizeBy,resizeTo,restore,routeEvent,scroll,scrollBy,scrollByLines,scrollByPages,scrollTo,setCursor,setImmediate,setInterval,setResizable,setTimeout,showModalDialog,sizeToContent,stop,unescape,updateCommands,XPCNativeWrapper,XPCSafeJSObjectWrapper,' + 'onabort,onbeforeunload,onblur,onchange,onclick,onclose,oncontextmenu,ondevicemotion,ondeviceorientation,ondragdrop,onerror,onfocus,onhashchange,onkeydown,onkeypress,onkeyup,onload,onmousedown,onmousemove,onmouseout,onmouseover,onmouseup,onmozbeforepaint,onpaint,onpopstate,onreset,onresize,onscroll,onselect,onsubmit,onunload,onpageshow,onpagehide,' + 'Image,Option,Worker,' + // https://developer.mozilla.org/en/Gecko_DOM_Reference 'Event,Range,File,FileReader,Blob,BlobBuilder,' + 'Attr,CDATASection,CharacterData,Comment,console,DocumentFragment,DocumentType,DomConfiguration,DOMError,DOMErrorHandler,DOMException,DOMImplementation,DOMImplementationList,DOMImplementationRegistry,DOMImplementationSource,DOMLocator,DOMObject,DOMString,DOMStringList,DOMTimeStamp,DOMUserData,Entity,EntityReference,MediaQueryList,MediaQueryListListener,NameList,NamedNodeMap,Node,NodeFilter,NodeIterator,NodeList,Notation,Plugin,PluginArray,ProcessingInstruction,SharedWorker,Text,TimeRanges,Treewalker,TypeInfo,UserDataHandler,Worker,WorkerGlobalScope,' + 'HTMLDocument,HTMLElement,HTMLAnchorElement,HTMLAppletElement,HTMLAudioElement,HTMLAreaElement,HTMLBaseElement,HTMLBaseFontElement,HTMLBodyElement,HTMLBRElement,HTMLButtonElement,HTMLCanvasElement,HTMLDirectoryElement,HTMLDivElement,HTMLDListElement,HTMLEmbedElement,HTMLFieldSetElement,HTMLFontElement,HTMLFormElement,HTMLFrameElement,HTMLFrameSetElement,HTMLHeadElement,HTMLHeadingElement,HTMLHtmlElement,HTMLHRElement,HTMLIFrameElement,HTMLImageElement,HTMLInputElement,HTMLKeygenElement,HTMLLabelElement,HTMLLIElement,HTMLLinkElement,HTMLMapElement,HTMLMenuElement,HTMLMetaElement,HTMLModElement,HTMLObjectElement,HTMLOListElement,HTMLOptGroupElement,HTMLOptionElement,HTMLOutputElement,HTMLParagraphElement,HTMLParamElement,HTMLPreElement,HTMLQuoteElement,HTMLScriptElement,HTMLSelectElement,HTMLSourceElement,HTMLSpanElement,HTMLStyleElement,HTMLTableElement,HTMLTableCaptionElement,HTMLTableCellElement,HTMLTableDataCellElement,HTMLTableHeaderCellElement,HTMLTableColElement,HTMLTableRowElement,HTMLTableSectionElement,HTMLTextAreaElement,HTMLTimeElement,HTMLTitleElement,HTMLTrackElement,HTMLUListElement,HTMLUnknownElement,HTMLVideoElement,' + 'HTMLCanvasElement,CanvasRenderingContext2D,CanvasGradient,CanvasPattern,TextMetrics,ImageData,CanvasPixelArray,HTMLAudioElement,HTMLVideoElement,NotifyAudioAvailableEvent,HTMLCollection,HTMLAllCollection,HTMLFormControlsCollection,HTMLOptionsCollection,HTMLPropertiesCollection,DOMTokenList,DOMSettableTokenList,DOMStringMap,RadioNodeList,' + 'SVGDocument,SVGElement,SVGAElement,SVGAltGlyphElement,SVGAltGlyphDefElement,SVGAltGlyphItemElement,SVGAnimationElement,SVGAnimateElement,SVGAnimateColorElement,SVGAnimateMotionElement,SVGAnimateTransformElement,SVGSetElement,SVGCircleElement,SVGClipPathElement,SVGColorProfileElement,SVGCursorElement,SVGDefsElement,SVGDescElement,SVGEllipseElement,SVGFilterElement,SVGFilterPrimitiveStandardAttributes,SVGFEBlendElement,SVGFEColorMatrixElement,SVGFEComponentTransferElement,SVGFECompositeElement,SVGFEConvolveMatrixElement,SVGFEDiffuseLightingElement,SVGFEDisplacementMapElement,SVGFEDistantLightElement,SVGFEFloodElement,SVGFEGaussianBlurElement,SVGFEImageElement,SVGFEMergeElement,SVGFEMergeNodeElement,SVGFEMorphologyElement,SVGFEOffsetElement,SVGFEPointLightElement,SVGFESpecularLightingElement,SVGFESpotLightElement,SVGFETileElement,SVGFETurbulenceElement,SVGComponentTransferFunctionElement,SVGFEFuncRElement,SVGFEFuncGElement,SVGFEFuncBElement,SVGFEFuncAElement,SVGFontElement,SVGFontFaceElement,SVGFontFaceFormatElement,SVGFontFaceNameElement,SVGFontFaceSrcElement,SVGFontFaceUriElement,SVGForeignObjectElement,SVGGElement,SVGGlyphElement,SVGGlyphRefElement,SVGGradientElement,SVGLinearGradientElement,SVGRadialGradientElement,SVGHKernElement,SVGImageElement,SVGLineElement,SVGMarkerElement,SVGMaskElement,SVGMetadataElement,SVGMissingGlyphElement,SVGMPathElement,SVGPathElement,SVGPatternElement,SVGPolylineElement,SVGPolygonElement,SVGRectElement,SVGScriptElement,SVGStopElement,SVGStyleElement,SVGSVGElement,SVGSwitchElement,SVGSymbolElement,SVGTextElement,SVGTextPathElement,SVGTitleElement,SVGTRefElement,SVGTSpanElement,SVGUseElement,SVGViewElement,SVGVKernElement,' + 'SVGAngle,SVGColor,SVGICCColor,SVGElementInstance,SVGElementInstanceList,SVGLength,SVGLengthList,SVGMatrix,SVGNumber,SVGNumberList,SVGPaint,SVGPoint,SVGPointList,SVGPreserveAspectRatio,SVGRect,SVGStringList,SVGTransform,SVGTransformList,' + 'SVGAnimatedAngle,SVGAnimatedBoolean,SVGAnimatedEnumeration,SVGAnimatedInteger,SVGAnimatedLength,SVGAnimatedLengthList,SVGAnimatedNumber,SVGAnimatedNumberList,SVGAnimatedPreserveAspectRatio,SVGAnimatedRect,SVGAnimatedString,SVGAnimatedTransformList,' + 'SVGPathSegList,SVGPathSeg,SVGPathSegArcAbs,SVGPathSegArcRel,SVGPathSegClosePath,SVGPathSegCurvetoCubicAbs,SVGPathSegCurvetoCubicRel,SVGPathSegCurvetoCubicSmoothAbs,SVGPathSegCurvetoCubicSmoothRel,SVGPathSegCurvetoQuadraticAbs,SVGPathSegCurvetoQuadraticRel,SVGPathSegCurvetoQuadraticSmoothAbs,SVGPathSegCurvetoQuadraticSmoothRel,SVGPathSegLinetoAbs,SVGPathSegLinetoHorizontalAbs,SVGPathSegLinetoHorizontalRel,SVGPathSegLinetoRel,SVGPathSegLinetoVerticalAbs,SVGPathSegLinetoVerticalRel,SVGPathSegMovetoAbs,SVGPathSegMovetoRel,ElementTimeControl,TimeEvent,SVGAnimatedPathData,' + 'SVGAnimatedPoints,SVGColorProfileRule,SVGCSSRule,SVGExternalResourcesRequired,SVGFitToViewBox,SVGLangSpace,SVGLocatable,SVGRenderingIntent,SVGStylable,SVGTests,SVGTextContentElement,SVGTextPositioningElement,SVGTransformable,SVGUnitTypes,SVGURIReference,SVGViewSpec,SVGZoomAndPan'); /** * Order of operation ENUMs. * https://developer.mozilla.org/en/JavaScript/Reference/Operators/Operator_Precedence */ Blockly.JavaScript.ORDER_ATOMIC = 0; // 0 "" ... Blockly.JavaScript.ORDER_MEMBER = 1; // . [] Blockly.JavaScript.ORDER_NEW = 1; // new Blockly.JavaScript.ORDER_FUNCTION_CALL = 2; // () Blockly.JavaScript.ORDER_INCREMENT = 3; // ++ Blockly.JavaScript.ORDER_DECREMENT = 3; // -- Blockly.JavaScript.ORDER_LOGICAL_NOT = 4; // ! Blockly.JavaScript.ORDER_BITWISE_NOT = 4; // ~ Blockly.JavaScript.ORDER_UNARY_PLUS = 4; // + Blockly.JavaScript.ORDER_UNARY_NEGATION = 4; // - Blockly.JavaScript.ORDER_TYPEOF = 4; // typeof Blockly.JavaScript.ORDER_VOID = 4; // void Blockly.JavaScript.ORDER_DELETE = 4; // delete Blockly.JavaScript.ORDER_MULTIPLICATION = 5; // * Blockly.JavaScript.ORDER_DIVISION = 5; // / Blockly.JavaScript.ORDER_MODULUS = 5; // % Blockly.JavaScript.ORDER_ADDITION = 6; // + Blockly.JavaScript.ORDER_SUBTRACTION = 6; // - Blockly.JavaScript.ORDER_BITWISE_SHIFT = 7; // << >> >>> Blockly.JavaScript.ORDER_RELATIONAL = 8; // < <= > >= Blockly.JavaScript.ORDER_IN = 8; // in Blockly.JavaScript.ORDER_INSTANCEOF = 8; // instanceof Blockly.JavaScript.ORDER_EQUALITY = 9; // == != === !== Blockly.JavaScript.ORDER_BITWISE_AND = 10; // & Blockly.JavaScript.ORDER_BITWISE_XOR = 11; // ^ Blockly.JavaScript.ORDER_BITWISE_OR = 12; // | Blockly.JavaScript.ORDER_LOGICAL_AND = 13; // && Blockly.JavaScript.ORDER_LOGICAL_OR = 14; // || Blockly.JavaScript.ORDER_CONDITIONAL = 15; // ?: Blockly.JavaScript.ORDER_ASSIGNMENT = 16; // = += -= *= /= %= <<= >>= ... Blockly.JavaScript.ORDER_COMMA = 17; // , Blockly.JavaScript.ORDER_NONE = 99; // (...) /** * Arbitrary code to inject into locations that risk causing infinite loops. * Any instances of '%1' will be replaced by the block ID that failed. * E.g. ' checkTimeout(%1);\n' * @type ?string */ Blockly.JavaScript.INFINITE_LOOP_TRAP = null; /** * Initialise the database of variable names. */ Blockly.JavaScript.init = function() { // Create a dictionary of definitions to be printed before the code. Blockly.JavaScript.definitions_ = Object.create(null); // Create a dictionary mapping desired function names in definitions_ // to actual function names (to avoid collisions with user functions). Blockly.JavaScript.functionNames_ = Object.create(null); if (Blockly.Variables) { if (!Blockly.JavaScript.variableDB_) { Blockly.JavaScript.variableDB_ = new Blockly.Names(Blockly.JavaScript.RESERVED_WORDS_); } else { Blockly.JavaScript.variableDB_.reset(); } var defvars = []; var variables = Blockly.Variables.allVariables(); for (var x = 0; x < variables.length; x++) { defvars[x] = 'var ' + Blockly.JavaScript.variableDB_.getName(variables[x], Blockly.Variables.NAME_TYPE) + ';'; } Blockly.JavaScript.definitions_['variables'] = defvars.join('\n'); } }; /** * Prepend the generated code with the variable definitions. * @param {string} code Generated code. * @return {string} Completed code. */ Blockly.JavaScript.finish = function(code) { // Convert the definitions dictionary into a list. var definitions = []; for (var name in Blockly.JavaScript.definitions_) { definitions.push(Blockly.JavaScript.definitions_[name]); } return definitions.join('\n\n') + '\n\n\n' + code; }; /** * Naked values are top-level blocks with outputs that aren't plugged into * anything. A trailing semicolon is needed to make this legal. * @param {string} line Line of generated code. * @return {string} Legal line of code. */ Blockly.JavaScript.scrubNakedValue = function(line) { return line + ';\n'; }; /** * Encode a string as a properly escaped JavaScript string, complete with * quotes. * @param {string} string Text to encode. * @return {string} JavaScript string. * @private */ Blockly.JavaScript.quote_ = function(string) { // TODO: This is a quick hack. Replace with goog.string.quote string = string.replace(/\\/g, '\\\\') .replace(/\n/g, '\\\n') .replace(/'/g, '\\\''); return '\'' + string + '\''; }; /** * Common tasks for generating JavaScript from blocks. * Handles comments for the specified block and any connected value blocks. * Calls any statements following this block. * @param {!Blockly.Block} block The current block. * @param {string} code The JavaScript code created for this block. * @return {string} JavaScript code with comments and subsequent blocks added. * @this {Blockly.CodeGenerator} * @private */ Blockly.JavaScript.scrub_ = function(block, code) { if (code === null) { // Block has handled code generation itself. return ''; } var commentCode = ''; // Only collect comments for blocks that aren't inline. if (!block.outputConnection || !block.outputConnection.targetConnection) { // Collect comment for this block. var comment = block.getCommentText(); if (comment) { commentCode += this.prefixLines(comment, '// ') + '\n'; } // Collect comments for all value arguments. // Don't collect comments for nested statements. for (var x = 0; x < block.inputList.length; x++) { if (block.inputList[x].type == Blockly.INPUT_VALUE) { var childBlock = block.inputList[x].connection.targetBlock(); if (childBlock) { var comment = this.allNestedComments(childBlock); if (comment) { commentCode += this.prefixLines(comment, '// '); } } } } } var nextBlock = block.nextConnection && block.nextConnection.targetBlock(); var nextCode = this.blockToCode(nextBlock); return commentCode + code + nextCode; }; ================================================ FILE: extern/blockly/generators/python/colour.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Python for colour blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Python.colour'); goog.require('Blockly.Python'); Blockly.Python['colour_picker'] = function(block) { // Colour picker. var code = '\'' + block.getFieldValue('COLOUR') + '\''; return [code, Blockly.Python.ORDER_ATOMIC]; }; Blockly.Python['colour_random'] = function(block) { // Generate a random colour. Blockly.Python.definitions_['import_random'] = 'import random'; var code = '\'#%06x\' % random.randint(0, 2**24 - 1)'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; }; Blockly.Python['colour_rgb'] = function(block) { // Compose a colour from RGB components expressed as percentages. var functionName = Blockly.Python.provideFunction_( 'colour_rgb', [ 'def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(r, g, b):', ' r = round(min(100, max(0, r)) * 2.55)', ' g = round(min(100, max(0, g)) * 2.55)', ' b = round(min(100, max(0, b)) * 2.55)', ' return \'#%02x%02x%02x\' % (r, g, b)']); var r = Blockly.Python.valueToCode(block, 'RED', Blockly.Python.ORDER_NONE) || 0; var g = Blockly.Python.valueToCode(block, 'GREEN', Blockly.Python.ORDER_NONE) || 0; var b = Blockly.Python.valueToCode(block, 'BLUE', Blockly.Python.ORDER_NONE) || 0; var code = functionName + '(' + r + ', ' + g + ', ' + b + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; }; Blockly.Python['colour_blend'] = function(block) { // Blend two colours together. var functionName = Blockly.Python.provideFunction_( 'colour_blend', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(colour1, colour2, ratio):', ' r1, r2 = int(colour1[1:3], 16), int(colour2[1:3], 16)', ' g1, g2 = int(colour1[3:5], 16), int(colour2[3:5], 16)', ' b1, b2 = int(colour1[5:7], 16), int(colour2[5:7], 16)', ' ratio = min(1, max(0, ratio))', ' r = round(r1 * (1 - ratio) + r2 * ratio)', ' g = round(g1 * (1 - ratio) + g2 * ratio)', ' b = round(b1 * (1 - ratio) + b2 * ratio)', ' return \'#%02x%02x%02x\' % (r, g, b)']); var colour1 = Blockly.Python.valueToCode(block, 'COLOUR1', Blockly.Python.ORDER_NONE) || '\'#000000\''; var colour2 = Blockly.Python.valueToCode(block, 'COLOUR2', Blockly.Python.ORDER_NONE) || '\'#000000\''; var ratio = Blockly.Python.valueToCode(block, 'RATIO', Blockly.Python.ORDER_NONE) || 0; var code = functionName + '(' + colour1 + ', ' + colour2 + ', ' + ratio + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; }; ================================================ FILE: extern/blockly/generators/python/lists.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Python for list blocks. * @author q.neutron@gmail.com (Quynh Neutron) */ 'use strict'; goog.provide('Blockly.Python.lists'); goog.require('Blockly.Python'); Blockly.Python['lists_create_empty'] = function(block) { // Create an empty list. return ['[]', Blockly.Python.ORDER_ATOMIC]; }; Blockly.Python['lists_create_with'] = function(block) { // Create a list with any number of elements of any type. var code = new Array(block.itemCount_); for (var n = 0; n < block.itemCount_; n++) { code[n] = Blockly.Python.valueToCode(block, 'ADD' + n, Blockly.Python.ORDER_NONE) || 'None'; } code = '[' + code.join(', ') + ']'; return [code, Blockly.Python.ORDER_ATOMIC]; }; Blockly.Python['lists_repeat'] = function(block) { // Create a list with one element repeated. var argument0 = Blockly.Python.valueToCode(block, 'ITEM', Blockly.Python.ORDER_NONE) || 'None'; var argument1 = Blockly.Python.valueToCode(block, 'NUM', Blockly.Python.ORDER_MULTIPLICATIVE) || '0'; var code = '[' + argument0 + '] * ' + argument1; return [code, Blockly.Python.ORDER_MULTIPLICATIVE]; }; Blockly.Python['lists_length'] = function(block) { // List length. var argument0 = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_NONE) || '[]'; return ['len(' + argument0 + ')', Blockly.Python.ORDER_FUNCTION_CALL]; }; Blockly.Python['lists_isEmpty'] = function(block) { // Is the list empty? var argument0 = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_NONE) || '[]'; var code = 'not len(' + argument0 + ')'; return [code, Blockly.Python.ORDER_LOGICAL_NOT]; }; Blockly.Python['lists_indexOf'] = function(block) { // Find an item in the list. var argument0 = Blockly.Python.valueToCode(block, 'FIND', Blockly.Python.ORDER_NONE) || '[]'; var argument1 = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_MEMBER) || '\'\''; var code; if (block.getFieldValue('END') == 'FIRST') { var functionName = Blockly.Python.provideFunction_( 'first_index', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList, elem):', ' try: theIndex = myList.index(elem) + 1', ' except: theIndex = 0', ' return theIndex']); code = functionName + '(' + argument1 + ', ' + argument0 + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else { var functionName = Blockly.Python.provideFunction_( 'last_index', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList, elem):', ' try: theIndex = len(myList) - myList[::-1].index(elem)', ' except: theIndex = 0', ' return theIndex']); code = functionName + '(' + argument1 + ', ' + argument0 + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } }; Blockly.Python['lists_getIndex'] = function(block) { // Get element at index. // Note: Until January 2013 this block did not have MODE or WHERE inputs. var mode = block.getFieldValue('MODE') || 'GET'; var where = block.getFieldValue('WHERE') || 'FROM_START'; var at = Blockly.Python.valueToCode(block, 'AT', Blockly.Python.ORDER_UNARY_SIGN) || '1'; var list = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_MEMBER) || '[]'; if (where == 'FIRST') { if (mode == 'GET') { var code = list + '[0]'; return [code, Blockly.Python.ORDER_MEMBER]; } else { var code = list + '.pop(0)'; if (mode == 'GET_REMOVE') { return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return code + '\n'; } } } else if (where == 'LAST') { if (mode == 'GET') { var code = list + '[-1]'; return [code, Blockly.Python.ORDER_MEMBER]; } else { var code = list + '.pop()'; if (mode == 'GET_REMOVE') { return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return code + '\n'; } } } else if (where == 'FROM_START') { // Blockly uses one-based indicies. if (Blockly.isNumber(at)) { // If the index is a naked number, decrement it right now. at = parseInt(at, 10) - 1; } else { // If the index is dynamic, decrement it in code. at = 'int(' + at + ' - 1)'; } if (mode == 'GET') { var code = list + '[' + at + ']'; return [code, Blockly.Python.ORDER_MEMBER]; } else { var code = list + '.pop(' + at + ')'; if (mode == 'GET_REMOVE') { return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return code + '\n'; } } } else if (where == 'FROM_END') { if (mode == 'GET') { var code = list + '[-' + at + ']'; return [code, Blockly.Python.ORDER_MEMBER]; } else { var code = list + '.pop(-' + at + ')'; if (mode == 'GET_REMOVE') { return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return code + '\n'; } } } else if (where == 'RANDOM') { Blockly.Python.definitions_['import_random'] = 'import random'; if (mode == 'GET') { code = 'random.choice(' + list + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else { var functionName = Blockly.Python.provideFunction_( 'lists_remove_random_item', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):', ' x = int(random.random() * len(myList))', ' return myList.pop(x)']); code = functionName + '(' + list + ')'; if (mode == 'GET_REMOVE') { return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else if (mode == 'REMOVE') { return code + '\n'; } } } throw 'Unhandled combination (lists_getIndex).'; }; Blockly.Python['lists_setIndex'] = function(block) { // Set element at index. // Note: Until February 2013 this block did not have MODE or WHERE inputs. var list = Blockly.Python.valueToCode(block, 'LIST', Blockly.Python.ORDER_MEMBER) || '[]'; var mode = block.getFieldValue('MODE') || 'GET'; var where = block.getFieldValue('WHERE') || 'FROM_START'; var at = Blockly.Python.valueToCode(block, 'AT', Blockly.Python.ORDER_NONE) || '1'; var value = Blockly.Python.valueToCode(block, 'TO', Blockly.Python.ORDER_NONE) || 'None'; // Cache non-trivial values to variables to prevent repeated look-ups. // Closure, which accesses and modifies 'list'. function cacheList() { if (list.match(/^\w+$/)) { return ''; } var listVar = Blockly.Python.variableDB_.getDistinctName( 'tmp_list', Blockly.Variables.NAME_TYPE); var code = listVar + ' = ' + list + '\n'; list = listVar; return code; } if (where == 'FIRST') { if (mode == 'SET') { return list + '[0] = ' + value + '\n'; } else if (mode == 'INSERT') { return list + '.insert(0, ' + value + ')\n'; } } else if (where == 'LAST') { if (mode == 'SET') { return list + '[-1] = ' + value + '\n'; } else if (mode == 'INSERT') { return list + '.append(' + value + ')\n'; } } else if (where == 'FROM_START') { // Blockly uses one-based indicies. if (Blockly.isNumber(at)) { // If the index is a naked number, decrement it right now. at = parseInt(at, 10) - 1; } else { // If the index is dynamic, decrement it in code. at = 'int(' + at + ' - 1)'; } if (mode == 'SET') { return list + '[' + at + '] = ' + value + '\n'; } else if (mode == 'INSERT') { return list + '.insert(' + at + ', ' + value + ')\n'; } } else if (where == 'FROM_END') { if (mode == 'SET') { return list + '[-' + at + '] = ' + value + '\n'; } else if (mode == 'INSERT') { return list + '.insert(-' + at + ', ' + value + ')\n'; } } else if (where == 'RANDOM') { Blockly.Python.definitions_['import_random'] = 'import random'; var code = cacheList(); var xVar = Blockly.Python.variableDB_.getDistinctName( 'tmp_x', Blockly.Variables.NAME_TYPE); code += xVar + ' = int(random.random() * len(' + list + '))\n'; if (mode == 'SET') { code += list + '[' + xVar + '] = ' + value + '\n'; return code; } else if (mode == 'INSERT') { code += list + '.insert(' + xVar + ', ' + value + ')\n'; return code; } } throw 'Unhandled combination (lists_setIndex).'; }; Blockly.Python['lists_getSublist'] = function(block) { // Get sublist. var list = Blockly.Python.valueToCode(block, 'LIST', Blockly.Python.ORDER_MEMBER) || '[]'; var where1 = block.getFieldValue('WHERE1'); var where2 = block.getFieldValue('WHERE2'); var at1 = Blockly.Python.valueToCode(block, 'AT1', Blockly.Python.ORDER_ADDITIVE) || '1'; var at2 = Blockly.Python.valueToCode(block, 'AT2', Blockly.Python.ORDER_ADDITIVE) || '1'; if (where1 == 'FIRST' || (where1 == 'FROM_START' && at1 == '1')) { at1 = ''; } else if (where1 == 'FROM_START') { // Blockly uses one-based indicies. if (Blockly.isNumber(at1)) { // If the index is a naked number, decrement it right now. at1 = parseInt(at1, 10) - 1; } else { // If the index is dynamic, decrement it in code. at1 = 'int(' + at1 + ' - 1)'; } } else if (where1 == 'FROM_END') { if (Blockly.isNumber(at1)) { at1 = -parseInt(at1, 10); } else { at1 = '-int(' + at1 + ')'; } } if (where2 == 'LAST' || (where2 == 'FROM_END' && at2 == '1')) { at2 = ''; } else if (where1 == 'FROM_START') { if (Blockly.isNumber(at2)) { at2 = parseInt(at2, 10); } else { at2 = 'int(' + at2 + ')'; } } else if (where1 == 'FROM_END') { if (Blockly.isNumber(at2)) { // If the index is a naked number, increment it right now. // Add special case for -0. at2 = 1 - parseInt(at2, 10); if (at2 == 0) { at2 = ''; } } else { // If the index is dynamic, increment it in code. Blockly.Python.definitions_['import_sys'] = 'import sys'; at2 = 'int(1 - ' + at2 + ') or sys.maxsize'; } } var code = list + '[' + at1 + ' : ' + at2 + ']'; return [code, Blockly.Python.ORDER_MEMBER]; }; ================================================ FILE: extern/blockly/generators/python/logic.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Python for logic blocks. * @author q.neutron@gmail.com (Quynh Neutron) */ 'use strict'; goog.provide('Blockly.Python.logic'); goog.require('Blockly.Python'); Blockly.Python['controls_if'] = function(block) { // If/elseif/else condition. var n = 0; var argument = Blockly.Python.valueToCode(block, 'IF' + n, Blockly.Python.ORDER_NONE) || 'False'; var branch = Blockly.Python.statementToCode(block, 'DO' + n) || ' pass\n'; var code = 'if ' + argument + ':\n' + branch; for (n = 1; n <= block.elseifCount_; n++) { argument = Blockly.Python.valueToCode(block, 'IF' + n, Blockly.Python.ORDER_NONE) || 'False'; branch = Blockly.Python.statementToCode(block, 'DO' + n) || ' pass\n'; code += 'elif ' + argument + ':\n' + branch; } if (block.elseCount_) { branch = Blockly.Python.statementToCode(block, 'ELSE') || ' pass\n'; code += 'else:\n' + branch; } return code; }; Blockly.Python['logic_compare'] = function(block) { // Comparison operator. var OPERATORS = { EQ: '==', NEQ: '!=', LT: '<', LTE: '<=', GT: '>', GTE: '>=' }; var operator = OPERATORS[block.getFieldValue('OP')]; var order = Blockly.Python.ORDER_RELATIONAL; var argument0 = Blockly.Python.valueToCode(block, 'A', order) || '0'; var argument1 = Blockly.Python.valueToCode(block, 'B', order) || '0'; var code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; }; Blockly.Python['logic_operation'] = function(block) { // Operations 'and', 'or'. var operator = (block.getFieldValue('OP') == 'AND') ? 'and' : 'or'; var order = (operator == 'and') ? Blockly.Python.ORDER_LOGICAL_AND : Blockly.Python.ORDER_LOGICAL_OR; var argument0 = Blockly.Python.valueToCode(block, 'A', order); var argument1 = Blockly.Python.valueToCode(block, 'B', order); if (!argument0 && !argument1) { // If there are no arguments, then the return value is false. argument0 = 'False'; argument1 = 'False'; } else { // Single missing arguments have no effect on the return value. var defaultArgument = (operator == 'and') ? 'True' : 'False'; if (!argument0) { argument0 = defaultArgument; } if (!argument1) { argument1 = defaultArgument; } } var code = argument0 + ' ' + operator + ' ' + argument1; return [code, order]; }; Blockly.Python['logic_negate'] = function(block) { // Negation. var argument0 = Blockly.Python.valueToCode(block, 'BOOL', Blockly.Python.ORDER_LOGICAL_NOT) || 'True'; var code = 'not ' + argument0; return [code, Blockly.Python.ORDER_LOGICAL_NOT]; }; Blockly.Python['logic_boolean'] = function(block) { // Boolean values true and false. var code = (block.getFieldValue('BOOL') == 'TRUE') ? 'True' : 'False'; return [code, Blockly.Python.ORDER_ATOMIC]; }; Blockly.Python['logic_null'] = function(block) { // Null data type. return ['None', Blockly.Python.ORDER_ATOMIC]; }; Blockly.Python['logic_ternary'] = function(block) { // Ternary operator. var value_if = Blockly.Python.valueToCode(block, 'IF', Blockly.Python.ORDER_CONDITIONAL) || 'False'; var value_then = Blockly.Python.valueToCode(block, 'THEN', Blockly.Python.ORDER_CONDITIONAL) || 'None'; var value_else = Blockly.Python.valueToCode(block, 'ELSE', Blockly.Python.ORDER_CONDITIONAL) || 'None'; var code = value_then + ' if ' + value_if + ' else ' + value_else return [code, Blockly.Python.ORDER_CONDITIONAL]; }; ================================================ FILE: extern/blockly/generators/python/loops.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Python for loop blocks. * @author q.neutron@gmail.com (Quynh Neutron) */ 'use strict'; goog.provide('Blockly.Python.loops'); goog.require('Blockly.Python'); Blockly.Python['controls_repeat'] = function(block) { // Repeat n times (internal number). var repeats = parseInt(block.getFieldValue('TIMES'), 10); var branch = Blockly.Python.statementToCode(block, 'DO') || ' pass\n'; if (Blockly.Python.INFINITE_LOOP_TRAP) { branch = Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } var loopVar = Blockly.Python.variableDB_.getDistinctName( 'count', Blockly.Variables.NAME_TYPE); var code = 'for ' + loopVar + ' in range(' + repeats + '):\n' + branch; return code; }; Blockly.Python['controls_repeat_ext'] = function(block) { // Repeat n times (external number). var repeats = Blockly.Python.valueToCode(block, 'TIMES', Blockly.Python.ORDER_NONE) || '0'; if (Blockly.isNumber(repeats)) { repeats = parseInt(repeats, 10); } else { repeats = 'int(' + repeats + ')'; } var branch = Blockly.Python.statementToCode(block, 'DO') || ' pass\n'; if (Blockly.Python.INFINITE_LOOP_TRAP) { branch = Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g, '\'' + block.id + '\'') + branch; } var loopVar = Blockly.Python.variableDB_.getDistinctName( 'count', Blockly.Variables.NAME_TYPE); var code = 'for ' + loopVar + ' in range(' + repeats + '):\n' + branch; return code; }; Blockly.Python['controls_whileUntil'] = function(block) { // Do while/until loop. var until = block.getFieldValue('MODE') == 'UNTIL'; var argument0 = Blockly.Python.valueToCode(block, 'BOOL', until ? Blockly.Python.ORDER_LOGICAL_NOT : Blockly.Python.ORDER_NONE) || 'False'; var branch = Blockly.Python.statementToCode(block, 'DO') || ' pass\n'; if (Blockly.Python.INFINITE_LOOP_TRAP) { branch = Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g, '"' + block.id + '"') + branch; } if (until) { argument0 = 'not ' + argument0; } return 'while ' + argument0 + ':\n' + branch; }; Blockly.Python['controls_for'] = function(block) { // For loop. var variable0 = Blockly.Python.variableDB_.getName( block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); var argument0 = Blockly.Python.valueToCode(block, 'FROM', Blockly.Python.ORDER_NONE) || '0'; var argument1 = Blockly.Python.valueToCode(block, 'TO', Blockly.Python.ORDER_NONE) || '0'; var increment = Blockly.Python.valueToCode(block, 'BY', Blockly.Python.ORDER_NONE) || '1'; var branch = Blockly.Python.statementToCode(block, 'DO') || ' pass\n'; if (Blockly.Python.INFINITE_LOOP_TRAP) { branch = Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g, '"' + block.id + '"') + branch; } var code = ''; var range; // Helper functions. var defineUpRange = function() { return Blockly.Python.provideFunction_( 'upRange', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(start, stop, step):', ' while start <= stop:', ' yield start', ' start += abs(step)']); }; var defineDownRange = function() { return Blockly.Python.provideFunction_( 'downRange', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(start, stop, step):', ' while start >= stop:', ' yield start', ' start -= abs(step)']); }; // Arguments are legal Python code (numbers or strings returned by scrub()). var generateUpDownRange = function(start, end, inc) { return '(' + start + ' <= ' + end + ') and ' + defineUpRange() + '(' + start + ', ' + end + ', ' + inc + ') or ' + defineDownRange() + '(' + start + ', ' + end + ', ' + inc + ')'; }; if (Blockly.isNumber(argument0) && Blockly.isNumber(argument1) && Blockly.isNumber(increment)) { // All parameters are simple numbers. argument0 = parseFloat(argument0); argument1 = parseFloat(argument1); increment = Math.abs(parseFloat(increment)); if (argument0 % 1 === 0 && argument1 % 1 === 0 && increment % 1 === 0) { // All parameters are integers. if (argument0 <= argument1) { // Count up. argument1++; if (argument0 == 0 && increment == 1) { // If starting index is 0, omit it. range = argument1; } else { range = argument0 + ', ' + argument1; } // If increment isn't 1, it must be explicit. if (increment != 1) { range += ', ' + increment; } } else { // Count down. argument1--; range = argument0 + ', ' + argument1 + ', -' + increment; } range = 'range(' + range + ')'; } else { // At least one of the parameters is not an integer. if (argument0 < argument1) { range = defineUpRange(); } else { range = defineDownRange(); } range += '(' + argument0 + ', ' + argument1 + ', ' + increment + ')'; } } else { // Cache non-trivial values to variables to prevent repeated look-ups. var scrub = function(arg, suffix) { if (Blockly.isNumber(arg)) { // Simple number. arg = parseFloat(arg); } else if (arg.match(/^\w+$/)) { // Variable. arg = 'float(' + arg + ')'; } else { // It's complicated. var varName = Blockly.Python.variableDB_.getDistinctName( variable0 + suffix, Blockly.Variables.NAME_TYPE); code += varName + ' = float(' + arg + ')\n'; arg = varName; } return arg; }; var startVar = scrub(argument0, '_start'); var endVar = scrub(argument1, '_end'); var incVar = scrub(increment, '_inc'); if (typeof startVar == 'number' && typeof endVar == 'number') { if (startVar < endVar) { range = defineUpRange(startVar, endVar, increment); } else { range = defineDownRange(startVar, endVar, increment); } } else { // We cannot determine direction statically. range = generateUpDownRange(startVar, endVar, increment); } } code += 'for ' + variable0 + ' in ' + range + ':\n' + branch; return code; }; Blockly.Python['controls_forEach'] = function(block) { // For each loop. var variable0 = Blockly.Python.variableDB_.getName( block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); var argument0 = Blockly.Python.valueToCode(block, 'LIST', Blockly.Python.ORDER_RELATIONAL) || '[]'; var branch = Blockly.Python.statementToCode(block, 'DO') || ' pass\n'; if (Blockly.Python.INFINITE_LOOP_TRAP) { branch = Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g, '"' + block.id + '"') + branch; } var code = 'for ' + variable0 + ' in ' + argument0 + ':\n' + branch; return code; }; Blockly.Python['controls_flow_statements'] = function(block) { // Flow statements: continue, break. switch (block.getFieldValue('FLOW')) { case 'BREAK': return 'break\n'; case 'CONTINUE': return 'continue\n'; } throw 'Unknown flow statement.'; }; ================================================ FILE: extern/blockly/generators/python/math.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Python for math blocks. * @author q.neutron@gmail.com (Quynh Neutron) */ 'use strict'; goog.provide('Blockly.Python.math'); goog.require('Blockly.Python'); // If any new block imports any library, add that library name here. Blockly.Python.addReservedWords('math,random'); Blockly.Python['math_number'] = function(block) { // Numeric value. var code = parseFloat(block.getFieldValue('NUM')); var order = code < 0 ? Blockly.Python.ORDER_UNARY_SIGN : Blockly.Python.ORDER_ATOMIC; return [code, order]; }; Blockly.Python['math_arithmetic'] = function(block) { // Basic arithmetic operators, and power. var OPERATORS = { ADD: [' + ', Blockly.Python.ORDER_ADDITIVE], MINUS: [' - ', Blockly.Python.ORDER_ADDITIVE], MULTIPLY: [' * ', Blockly.Python.ORDER_MULTIPLICATIVE], DIVIDE: [' / ', Blockly.Python.ORDER_MULTIPLICATIVE], POWER: [' ** ', Blockly.Python.ORDER_EXPONENTIATION] }; var tuple = OPERATORS[block.getFieldValue('OP')]; var operator = tuple[0]; var order = tuple[1]; var argument0 = Blockly.Python.valueToCode(block, 'A', order) || '0'; var argument1 = Blockly.Python.valueToCode(block, 'B', order) || '0'; var code = argument0 + operator + argument1; return [code, order]; // In case of 'DIVIDE', division between integers returns different results // in Python 2 and 3. However, is not an issue since Blockly does not // guarantee identical results in all languages. To do otherwise would // require every operator to be wrapped in a function call. This would kill // legibility of the generated code. See: // http://code.google.com/p/blockly/wiki/Language }; Blockly.Python['math_single'] = function(block) { // Math operators with single operand. var operator = block.getFieldValue('OP'); var code; var arg; if (operator == 'NEG') { // Negation is a special case given its different operator precedence. var code = Blockly.Python.valueToCode(block, 'NUM', Blockly.Python.ORDER_UNARY_SIGN) || '0'; return ['-' + code, Blockly.Python.ORDER_UNARY_SIGN]; } Blockly.Python.definitions_['import_math'] = 'import math'; if (operator == 'SIN' || operator == 'COS' || operator == 'TAN') { arg = Blockly.Python.valueToCode(block, 'NUM', Blockly.Python.ORDER_MULTIPLICATIVE) || '0'; } else { arg = Blockly.Python.valueToCode(block, 'NUM', Blockly.Python.ORDER_NONE) || '0'; } // First, handle cases which generate values that don't need parentheses // wrapping the code. switch (operator) { case 'ABS': code = 'math.fabs(' + arg + ')'; break; case 'ROOT': code = 'math.sqrt(' + arg + ')'; break; case 'LN': code = 'math.log(' + arg + ')'; break; case 'LOG10': code = 'math.log10(' + arg + ')'; break; case 'EXP': code = 'math.exp(' + arg + ')'; break; case 'POW10': code = 'math.pow(10,' + arg + ')'; break; case 'ROUND': code = 'round(' + arg + ')'; break; case 'ROUNDUP': code = 'math.ceil(' + arg + ')'; break; case 'ROUNDDOWN': code = 'math.floor(' + arg + ')'; break; case 'SIN': code = 'math.sin(' + arg + ' / 180.0 * math.pi)'; break; case 'COS': code = 'math.cos(' + arg + ' / 180.0 * math.pi)'; break; case 'TAN': code = 'math.tan(' + arg + ' / 180.0 * math.pi)'; break; } if (code) { return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } // Second, handle cases which generate values that may need parentheses // wrapping the code. switch (operator) { case 'ASIN': code = 'math.asin(' + arg + ') / math.pi * 180'; break; case 'ACOS': code = 'math.acos(' + arg + ') / math.pi * 180'; break; case 'ATAN': code = 'math.atan(' + arg + ') / math.pi * 180'; break; default: throw 'Unknown math operator: ' + operator; } return [code, Blockly.Python.ORDER_MULTIPLICATIVE]; }; Blockly.Python['math_constant'] = function(block) { // Constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY. var CONSTANTS = { PI: ['math.pi', Blockly.Python.ORDER_MEMBER], E: ['math.e', Blockly.Python.ORDER_MEMBER], GOLDEN_RATIO: ['(1 + math.sqrt(5)) / 2', Blockly.Python.ORDER_MULTIPLICATIVE], SQRT2: ['math.sqrt(2)', Blockly.Python.ORDER_MEMBER], SQRT1_2: ['math.sqrt(1.0 / 2)', Blockly.Python.ORDER_MEMBER], INFINITY: ['float(\'inf\')', Blockly.Python.ORDER_ATOMIC] }; var constant = block.getFieldValue('CONSTANT'); if (constant != 'INFINITY') { Blockly.Python.definitions_['import_math'] = 'import math'; } return CONSTANTS[constant]; }; Blockly.Python['math_number_property'] = function(block) { // Check if a number is even, odd, prime, whole, positive, or negative // or if it is divisible by certain number. Returns true or false. var number_to_check = Blockly.Python.valueToCode(block, 'NUMBER_TO_CHECK', Blockly.Python.ORDER_MULTIPLICATIVE) || '0'; var dropdown_property = block.getFieldValue('PROPERTY'); var code; if (dropdown_property == 'PRIME') { Blockly.Python.definitions_['import_math'] = 'import math'; var functionName = Blockly.Python.provideFunction_( 'math_isPrime', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(n):', ' # https://en.wikipedia.org/wiki/Primality_test#Naive_methods', ' # If n is not a number but a string, try parsing it.', ' if type(n) not in (int, float, long):', ' try:', ' n = float(n)', ' except:', ' return False', ' if n == 2 or n == 3:', ' return True', ' # False if n is negative, is 1, or not whole,' + ' or if n is divisible by 2 or 3.', ' if n <= 1 or n % 1 != 0 or n % 2 == 0 or n % 3 == 0:', ' return False', ' # Check all the numbers of form 6k +/- 1, up to sqrt(n).', ' for x in range(6, int(math.sqrt(n)) + 2, 6):', ' if n % (x - 1) == 0 or n % (x + 1) == 0:', ' return False', ' return True']); code = functionName + '(' + number_to_check + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } switch (dropdown_property) { case 'EVEN': code = number_to_check + ' % 2 == 0'; break; case 'ODD': code = number_to_check + ' % 2 == 1'; break; case 'WHOLE': code = number_to_check + ' % 1 == 0'; break; case 'POSITIVE': code = number_to_check + ' > 0'; break; case 'NEGATIVE': code = number_to_check + ' < 0'; break; case 'DIVISIBLE_BY': var divisor = Blockly.Python.valueToCode(block, 'DIVISOR', Blockly.Python.ORDER_MULTIPLICATIVE); // If 'divisor' is some code that evals to 0, Python will raise an error. if (!divisor || divisor == '0') { return ['False', Blockly.Python.ORDER_ATOMIC]; } code = number_to_check + ' % ' + divisor + ' == 0'; break; } return [code, Blockly.Python.ORDER_RELATIONAL]; }; Blockly.Python['math_change'] = function(block) { // Add to a variable in place. var argument0 = Blockly.Python.valueToCode(block, 'DELTA', Blockly.Python.ORDER_ADDITIVE) || '0'; var varName = Blockly.Python.variableDB_.getName(block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); return varName + ' = (' + varName + ' if type(' + varName + ') in (int, float, long) else 0) + ' + argument0 + '\n'; }; // Rounding functions have a single operand. Blockly.Python['math_round'] = Blockly.Python['math_single']; // Trigonometry functions have a single operand. Blockly.Python['math_trig'] = Blockly.Python['math_single']; Blockly.Python['math_on_list'] = function(block) { // Math functions for lists. var func = block.getFieldValue('OP'); var list = Blockly.Python.valueToCode(block, 'LIST', Blockly.Python.ORDER_NONE) || '[]'; var code; switch (func) { case 'SUM': code = 'sum(' + list + ')'; break; case 'MIN': code = 'min(' + list + ')'; break; case 'MAX': code = 'max(' + list + ')'; break; case 'AVERAGE': var functionName = Blockly.Python.provideFunction_( 'math_mean', // This operation excludes null and values that are not int or float:', // math_mean([null, null, "aString", 1, 9]) == 5.0.', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):', ' localList = [e for e in myList if type(e) in (int, float, long)]', ' if not localList: return', ' return float(sum(localList)) / len(localList)']); code = functionName + '(' + list + ')'; break; case 'MEDIAN': var functionName = Blockly.Python.provideFunction_( 'math_median', // This operation excludes null values: // math_median([null, null, 1, 3]) == 2.0. ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(myList):', ' localList = sorted([e for e in myList ' + 'if type(e) in (int, float, long)])', ' if not localList: return', ' if len(localList) % 2 == 0:', ' return (localList[len(localList) / 2 - 1] + ' + 'localList[len(localList) / 2]) / 2.0', ' else:', ' return localList[(len(localList) - 1) / 2]']); code = functionName + '(' + list + ')'; break; case 'MODE': var functionName = Blockly.Python.provideFunction_( 'math_modes', // As a list of numbers can contain more than one mode, // the returned result is provided as an array. // Mode of [3, 'x', 'x', 1, 1, 2, '3'] -> ['x', 1]. ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(some_list):', ' modes = []', ' # Using a lists of [item, count] to keep count rather than dict', ' # to avoid "unhashable" errors when the counted item is ' + 'itself a list or dict.', ' counts = []', ' maxCount = 1', ' for item in some_list:', ' found = False', ' for count in counts:', ' if count[0] == item:', ' count[1] += 1', ' maxCount = max(maxCount, count[1])', ' found = True', ' if not found:', ' counts.append([item, 1])', ' for counted_item, item_count in counts:', ' if item_count == maxCount:', ' modes.append(counted_item)', ' return modes']); code = functionName + '(' + list + ')'; break; case 'STD_DEV': Blockly.Python.definitions_['import_math'] = 'import math'; var functionName = Blockly.Python.provideFunction_( 'math_standard_deviation', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(numbers):', ' n = len(numbers)', ' if n == 0: return', ' mean = float(sum(numbers)) / n', ' variance = sum((x - mean) ** 2 for x in numbers) / n', ' return math.sqrt(variance)']); code = functionName + '(' + list + ')'; break; case 'RANDOM': Blockly.Python.definitions_['import_random'] = 'import random'; code = 'random.choice(' + list + ')'; break; default: throw 'Unknown operator: ' + func; } return [code, Blockly.Python.ORDER_FUNCTION_CALL]; }; Blockly.Python['math_modulo'] = function(block) { // Remainder computation. var argument0 = Blockly.Python.valueToCode(block, 'DIVIDEND', Blockly.Python.ORDER_MULTIPLICATIVE) || '0'; var argument1 = Blockly.Python.valueToCode(block, 'DIVISOR', Blockly.Python.ORDER_MULTIPLICATIVE) || '0'; var code = argument0 + ' % ' + argument1; return [code, Blockly.Python.ORDER_MULTIPLICATIVE]; }; Blockly.Python['math_constrain'] = function(block) { // Constrain a number between two limits. var argument0 = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_NONE) || '0'; var argument1 = Blockly.Python.valueToCode(block, 'LOW', Blockly.Python.ORDER_NONE) || '0'; var argument2 = Blockly.Python.valueToCode(block, 'HIGH', Blockly.Python.ORDER_NONE) || 'float(\'inf\')'; var code = 'min(max(' + argument0 + ', ' + argument1 + '), ' + argument2 + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; }; Blockly.Python['math_random_int'] = function(block) { // Random integer between [X] and [Y]. Blockly.Python.definitions_['import_random'] = 'import random'; var argument0 = Blockly.Python.valueToCode(block, 'FROM', Blockly.Python.ORDER_NONE) || '0'; var argument1 = Blockly.Python.valueToCode(block, 'TO', Blockly.Python.ORDER_NONE) || '0'; var code = 'random.randint(' + argument0 + ', ' + argument1 + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; }; Blockly.Python['math_random_float'] = function(block) { // Random fraction between 0 and 1. Blockly.Python.definitions_['import_random'] = 'import random'; return ['random.random()', Blockly.Python.ORDER_FUNCTION_CALL]; }; ================================================ FILE: extern/blockly/generators/python/procedures.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Python for procedure blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Python.procedures'); goog.require('Blockly.Python'); Blockly.Python['procedures_defreturn'] = function(block) { // Define a procedure with a return value. // First, add a 'global' statement for every variable that is assigned. var globals = Blockly.Variables.allVariables(block); for (var i = globals.length - 1; i >= 0; i--) { var varName = globals[i]; if (block.arguments_.indexOf(varName) == -1) { globals[i] = Blockly.Python.variableDB_.getName(varName, Blockly.Variables.NAME_TYPE); } else { // This variable is actually a parameter name. Do not include it in // the list of globals, thus allowing it be of local scope. globals.splice(i, 1); } } globals = globals.length ? ' global ' + globals.join(', ') + '\n' : ''; var funcName = Blockly.Python.variableDB_.getName(block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var branch = Blockly.Python.statementToCode(block, 'STACK'); if (Blockly.Python.INFINITE_LOOP_TRAP) { branch = Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g, '"' + block.id + '"') + branch; } var returnValue = Blockly.Python.valueToCode(block, 'RETURN', Blockly.Python.ORDER_NONE) || ''; if (returnValue) { returnValue = ' return ' + returnValue + '\n'; } else if (!branch) { branch = ' pass'; } var args = []; for (var x = 0; x < block.arguments_.length; x++) { args[x] = Blockly.Python.variableDB_.getName(block.arguments_[x], Blockly.Variables.NAME_TYPE); } var code = 'def ' + funcName + '(' + args.join(', ') + '):\n' + globals + branch + returnValue; code = Blockly.Python.scrub_(block, code); Blockly.Python.definitions_[funcName] = code; return null; }; // Defining a procedure without a return value uses the same generator as // a procedure with a return value. Blockly.Python['procedures_defnoreturn'] = Blockly.Python['procedures_defreturn']; Blockly.Python['procedures_callreturn'] = function(block) { // Call a procedure with a return value. var funcName = Blockly.Python.variableDB_.getName(block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var args = []; for (var x = 0; x < block.arguments_.length; x++) { args[x] = Blockly.Python.valueToCode(block, 'ARG' + x, Blockly.Python.ORDER_NONE) || 'None'; } var code = funcName + '(' + args.join(', ') + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; }; Blockly.Python['procedures_callnoreturn'] = function(block) { // Call a procedure with no return value. var funcName = Blockly.Python.variableDB_.getName(block.getFieldValue('NAME'), Blockly.Procedures.NAME_TYPE); var args = []; for (var x = 0; x < block.arguments_.length; x++) { args[x] = Blockly.Python.valueToCode(block, 'ARG' + x, Blockly.Python.ORDER_NONE) || 'None'; } var code = funcName + '(' + args.join(', ') + ')\n'; return code; }; Blockly.Python['procedures_ifreturn'] = function(block) { // Conditionally return value from a procedure. var condition = Blockly.Python.valueToCode(block, 'CONDITION', Blockly.Python.ORDER_NONE) || 'False'; var code = 'if ' + condition + ':\n'; if (block.hasReturnValue_) { var value = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_NONE) || 'None'; code += ' return ' + value + '\n'; } else { code += ' return\n'; } return code; }; ================================================ FILE: extern/blockly/generators/python/text.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Python for text blocks. * @author q.neutron@gmail.com (Quynh Neutron) */ 'use strict'; goog.provide('Blockly.Python.text'); goog.require('Blockly.Python'); Blockly.Python['text'] = function(block) { // Text value. var code = Blockly.Python.quote_(block.getFieldValue('TEXT')); return [code, Blockly.Python.ORDER_ATOMIC]; }; Blockly.Python['text_join'] = function(block) { // Create a string made up of any number of elements of any type. //Should we allow joining by '-' or ',' or any other characters? var code; if (block.itemCount_ == 0) { return ['\'\'', Blockly.Python.ORDER_ATOMIC]; } else if (block.itemCount_ == 1) { var argument0 = Blockly.Python.valueToCode(block, 'ADD0', Blockly.Python.ORDER_NONE) || '\'\''; code = 'str(' + argument0 + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } else if (block.itemCount_ == 2) { var argument0 = Blockly.Python.valueToCode(block, 'ADD0', Blockly.Python.ORDER_NONE) || '\'\''; var argument1 = Blockly.Python.valueToCode(block, 'ADD1', Blockly.Python.ORDER_NONE) || '\'\''; var code = 'str(' + argument0 + ') + str(' + argument1 + ')'; return [code, Blockly.Python.ORDER_UNARY_SIGN]; } else { var code = []; for (var n = 0; n < block.itemCount_; n++) { code[n] = Blockly.Python.valueToCode(block, 'ADD' + n, Blockly.Python.ORDER_NONE) || '\'\''; } var tempVar = Blockly.Python.variableDB_.getDistinctName('temp_value', Blockly.Variables.NAME_TYPE); code = '\'\'.join([str(' + tempVar + ') for ' + tempVar + ' in [' + code.join(', ') + ']])'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } }; Blockly.Python['text_append'] = function(block) { // Append to a variable in place. var varName = Blockly.Python.variableDB_.getName(block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); var argument0 = Blockly.Python.valueToCode(block, 'TEXT', Blockly.Python.ORDER_NONE) || '\'\''; return varName + ' = str(' + varName + ') + str(' + argument0 + ')\n'; }; Blockly.Python['text_length'] = function(block) { // String length. var argument0 = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_NONE) || '\'\''; return ['len(' + argument0 + ')', Blockly.Python.ORDER_FUNCTION_CALL]; }; Blockly.Python['text_isEmpty'] = function(block) { // Is the string null? var argument0 = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_NONE) || '\'\''; var code = 'not len(' + argument0 + ')'; return [code, Blockly.Python.ORDER_LOGICAL_NOT]; }; Blockly.Python['text_indexOf'] = function(block) { // Search the text for a substring. // Should we allow for non-case sensitive??? var operator = block.getFieldValue('END') == 'FIRST' ? 'find' : 'rfind'; var argument0 = Blockly.Python.valueToCode(block, 'FIND', Blockly.Python.ORDER_NONE) || '\'\''; var argument1 = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_MEMBER) || '\'\''; var code = argument1 + '.' + operator + '(' + argument0 + ') + 1'; return [code, Blockly.Python.ORDER_MEMBER]; }; Blockly.Python['text_charAt'] = function(block) { // Get letter at index. // Note: Until January 2013 this block did not have the WHERE input. var where = block.getFieldValue('WHERE') || 'FROM_START'; var at = Blockly.Python.valueToCode(block, 'AT', Blockly.Python.ORDER_UNARY_SIGN) || '1'; var text = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_MEMBER) || '\'\''; switch (where) { case 'FIRST': var code = text + '[0]'; return [code, Blockly.Python.ORDER_MEMBER]; case 'LAST': var code = text + '[-1]'; return [code, Blockly.Python.ORDER_MEMBER]; case 'FROM_START': // Blockly uses one-based indicies. if (Blockly.isNumber(at)) { // If the index is a naked number, decrement it right now. at = parseInt(at, 10) - 1; } else { // If the index is dynamic, decrement it in code. at = 'int(' + at + ' - 1)'; } var code = text + '[' + at + ']'; return [code, Blockly.Python.ORDER_MEMBER]; case 'FROM_END': var code = text + '[-' + at + ']'; return [code, Blockly.Python.ORDER_MEMBER]; case 'RANDOM': Blockly.Python.definitions_['import_random'] = 'import random'; var functionName = Blockly.Python.provideFunction_( 'text_random_letter', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(text):', ' x = int(random.random() * len(text))', ' return text[x];']); code = functionName + '(' + text + ')'; return [code, Blockly.Python.ORDER_FUNCTION_CALL]; } throw 'Unhandled option (text_charAt).'; }; Blockly.Python['text_getSubstring'] = function(block) { // Get substring. var text = Blockly.Python.valueToCode(block, 'STRING', Blockly.Python.ORDER_MEMBER) || '\'\''; var where1 = block.getFieldValue('WHERE1'); var where2 = block.getFieldValue('WHERE2'); var at1 = Blockly.Python.valueToCode(block, 'AT1', Blockly.Python.ORDER_ADDITIVE) || '1'; var at2 = Blockly.Python.valueToCode(block, 'AT2', Blockly.Python.ORDER_ADDITIVE) || '1'; if (where1 == 'FIRST' || (where1 == 'FROM_START' && at1 == '1')) { at1 = ''; } else if (where1 == 'FROM_START') { // Blockly uses one-based indicies. if (Blockly.isNumber(at1)) { // If the index is a naked number, decrement it right now. at1 = parseInt(at1, 10) - 1; } else { // If the index is dynamic, decrement it in code. at1 = 'int(' + at1 + ' - 1)'; } } else if (where1 == 'FROM_END') { if (Blockly.isNumber(at1)) { at1 = -parseInt(at1, 10); } else { at1 = '-int(' + at1 + ')'; } } if (where2 == 'LAST' || (where2 == 'FROM_END' && at2 == '1')) { at2 = ''; } else if (where1 == 'FROM_START') { if (Blockly.isNumber(at2)) { at2 = parseInt(at2, 10); } else { at2 = 'int(' + at2 + ')'; } } else if (where1 == 'FROM_END') { if (Blockly.isNumber(at2)) { // If the index is a naked number, increment it right now. at2 = 1 - parseInt(at2, 10); if (at2 == 0) { at2 = ''; } } else { // If the index is dynamic, increment it in code. // Add special case for -0. Blockly.Python.definitions_['import_sys'] = 'import sys'; at2 = 'int(1 - ' + at2 + ') or sys.maxsize'; } } var code = text + '[' + at1 + ' : ' + at2 + ']'; return [code, Blockly.Python.ORDER_MEMBER]; }; Blockly.Python['text_changeCase'] = function(block) { // Change capitalization. var OPERATORS = { UPPERCASE: '.upper()', LOWERCASE: '.lower()', TITLECASE: '.title()' }; var operator = OPERATORS[block.getFieldValue('CASE')]; var argument0 = Blockly.Python.valueToCode(block, 'TEXT', Blockly.Python.ORDER_MEMBER) || '\'\''; var code = argument0 + operator; return [code, Blockly.Python.ORDER_MEMBER]; }; Blockly.Python['text_trim'] = function(block) { // Trim spaces. var OPERATORS = { LEFT: '.lstrip()', RIGHT: '.rstrip()', BOTH: '.strip()' }; var operator = OPERATORS[block.getFieldValue('MODE')]; var argument0 = Blockly.Python.valueToCode(block, 'TEXT', Blockly.Python.ORDER_MEMBER) || '\'\''; var code = argument0 + operator; return [code, Blockly.Python.ORDER_MEMBER]; }; Blockly.Python['text_print'] = function(block) { // Print statement. var argument0 = Blockly.Python.valueToCode(block, 'TEXT', Blockly.Python.ORDER_NONE) || '\'\''; return 'print(' + argument0 + ')\n'; }; Blockly.Python['text_prompt'] = function(block) { // Prompt function. var functionName = Blockly.Python.provideFunction_( 'text_prompt', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(msg):', ' try:', ' return raw_input(msg)', ' except NameError:', ' return input(msg)']); var msg = Blockly.Python.quote_(block.getFieldValue('TEXT')); var code = functionName + '(' + msg + ')'; var toNumber = block.getFieldValue('TYPE') == 'NUMBER'; if (toNumber) { code = 'float(' + code + ')'; } return [code, Blockly.Python.ORDER_FUNCTION_CALL]; }; ================================================ FILE: extern/blockly/generators/python/variables.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Python for variable blocks. * @author q.neutron@gmail.com (Quynh Neutron) */ 'use strict'; goog.provide('Blockly.Python.variables'); goog.require('Blockly.Python'); Blockly.Python['variables_get'] = function(block) { // Variable getter. var code = Blockly.Python.variableDB_.getName(block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); return [code, Blockly.Python.ORDER_ATOMIC]; }; Blockly.Python['variables_set'] = function(block) { // Variable setter. var argument0 = Blockly.Python.valueToCode(block, 'VALUE', Blockly.Python.ORDER_NONE) || '0'; var varName = Blockly.Python.variableDB_.getName(block.getFieldValue('VAR'), Blockly.Variables.NAME_TYPE); return varName + ' = ' + argument0 + '\n'; }; ================================================ FILE: extern/blockly/generators/python.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Helper functions for generating Python for blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; goog.provide('Blockly.Python'); goog.require('Blockly.Generator'); Blockly.Python = new Blockly.Generator('Python'); /** * List of illegal variable names. * This is not intended to be a security feature. Blockly is 100% client-side, * so bypassing this list is trivial. This is intended to prevent users from * accidentally clobbering a built-in object or function. * @private */ Blockly.Python.addReservedWords( // import keyword // print ','.join(keyword.kwlist) // http://docs.python.org/reference/lexical_analysis.html#keywords 'and,as,assert,break,class,continue,def,del,elif,else,except,exec,finally,for,from,global,if,import,in,is,lambda,not,or,pass,print,raise,return,try,while,with,yield,' + //http://docs.python.org/library/constants.html 'True,False,None,NotImplemented,Ellipsis,__debug__,quit,exit,copyright,license,credits,' + // http://docs.python.org/library/functions.html 'abs,divmod,input,open,staticmethod,all,enumerate,int,ord,str,any,eval,isinstance,pow,sum,basestring,execfile,issubclass,print,super,bin,file,iter,property,tuple,bool,filter,len,range,type,bytearray,float,list,raw_input,unichr,callable,format,locals,reduce,unicode,chr,frozenset,long,reload,vars,classmethod,getattr,map,repr,xrange,cmp,globals,max,reversed,zip,compile,hasattr,memoryview,round,__import__,complex,hash,min,set,apply,delattr,help,next,setattr,buffer,dict,hex,object,slice,coerce,dir,id,oct,sorted,intern'); /** * Order of operation ENUMs. * http://docs.python.org/reference/expressions.html#summary */ Blockly.Python.ORDER_ATOMIC = 0; // 0 "" ... Blockly.Python.ORDER_COLLECTION = 1; // tuples, lists, dictionaries Blockly.Python.ORDER_STRING_CONVERSION = 1; // `expression...` Blockly.Python.ORDER_MEMBER = 2; // . [] Blockly.Python.ORDER_FUNCTION_CALL = 2; // () Blockly.Python.ORDER_EXPONENTIATION = 3; // ** Blockly.Python.ORDER_UNARY_SIGN = 4; // + - Blockly.Python.ORDER_BITWISE_NOT = 4; // ~ Blockly.Python.ORDER_MULTIPLICATIVE = 5; // * / // % Blockly.Python.ORDER_ADDITIVE = 6; // + - Blockly.Python.ORDER_BITWISE_SHIFT = 7; // << >> Blockly.Python.ORDER_BITWISE_AND = 8; // & Blockly.Python.ORDER_BITWISE_XOR = 9; // ^ Blockly.Python.ORDER_BITWISE_OR = 10; // | Blockly.Python.ORDER_RELATIONAL = 11; // in, not in, is, is not, // <, <=, >, >=, <>, !=, == Blockly.Python.ORDER_LOGICAL_NOT = 12; // not Blockly.Python.ORDER_LOGICAL_AND = 13; // and Blockly.Python.ORDER_LOGICAL_OR = 14; // or Blockly.Python.ORDER_CONDITIONAL = 15; // if else Blockly.Python.ORDER_LAMBDA = 16; // lambda Blockly.Python.ORDER_NONE = 99; // (...) /** * Arbitrary code to inject into locations that risk causing infinite loops. * Any instances of '%1' will be replaced by the block ID that failed. * E.g. ' checkTimeout(%1)\n' * @type ?string */ Blockly.Python.INFINITE_LOOP_TRAP = null; /** * Initialise the database of variable names. */ Blockly.Python.init = function() { // Create a dictionary of definitions to be printed before the code. Blockly.Python.definitions_ = Object.create(null); // Create a dictionary mapping desired function names in definitions_ // to actual function names (to avoid collisions with user functions). Blockly.Python.functionNames_ = Object.create(null); if (Blockly.Variables) { if (!Blockly.Python.variableDB_) { Blockly.Python.variableDB_ = new Blockly.Names(Blockly.Python.RESERVED_WORDS_); } else { Blockly.Python.variableDB_.reset(); } var defvars = []; var variables = Blockly.Variables.allVariables(); for (var x = 0; x < variables.length; x++) { defvars[x] = Blockly.Python.variableDB_.getName(variables[x], Blockly.Variables.NAME_TYPE) + ' = None'; } Blockly.Python.definitions_['variables'] = defvars.join('\n'); } }; /** * Prepend the generated code with the variable definitions. * @param {string} code Generated code. * @return {string} Completed code. */ Blockly.Python.finish = function(code) { // Convert the definitions dictionary into a list. var imports = []; var definitions = []; for (var name in Blockly.Python.definitions_) { var def = Blockly.Python.definitions_[name]; if (def.match(/^(from\s+\S+\s+)?import\s+\S+/)) { imports.push(def); } else { definitions.push(def); } } var allDefs = imports.join('\n') + '\n\n' + definitions.join('\n\n'); return allDefs.replace(/\n\n+/g, '\n\n').replace(/\n*$/, '\n\n\n') + code; }; /** * Naked values are top-level blocks with outputs that aren't plugged into * anything. * @param {string} line Line of generated code. * @return {string} Legal line of code. */ Blockly.Python.scrubNakedValue = function(line) { return line + '\n'; }; /** * Encode a string as a properly escaped Python string, complete with quotes. * @param {string} string Text to encode. * @return {string} Python string. * @private */ Blockly.Python.quote_ = function(string) { // TODO: This is a quick hack. Replace with goog.string.quote string = string.replace(/\\/g, '\\\\') .replace(/\n/g, '\\\n') .replace(/\%/g, '\\%') .replace(/'/g, '\\\''); return '\'' + string + '\''; }; /** * Common tasks for generating Python from blocks. * Handles comments for the specified block and any connected value blocks. * Calls any statements following this block. * @param {!Blockly.Block} block The current block. * @param {string} code The Python code created for this block. * @return {string} Python code with comments and subsequent blocks added. * @this {Blockly.CodeGenerator} * @private */ Blockly.Python.scrub_ = function(block, code) { if (code === null) { // Block has handled code generation itself. return ''; } var commentCode = ''; // Only collect comments for blocks that aren't inline. if (!block.outputConnection || !block.outputConnection.targetConnection) { // Collect comment for this block. var comment = block.getCommentText(); if (comment) { commentCode += this.prefixLines(comment, '# ') + '\n'; } // Collect comments for all value arguments. // Don't collect comments for nested statements. for (var x = 0; x < block.inputList.length; x++) { if (block.inputList[x].type == Blockly.INPUT_VALUE) { var childBlock = block.inputList[x].connection.targetBlock(); if (childBlock) { var comment = this.allNestedComments(childBlock); if (comment) { commentCode += this.prefixLines(comment, '# '); } } } } } var nextBlock = block.nextConnection && block.nextConnection.targetBlock(); var nextCode = this.blockToCode(nextBlock); return commentCode + code + nextCode; }; ================================================ FILE: extern/blockly/i18n/common.py ================================================ #!/usr/bin/python # Code shared by translation conversion scripts. # # Copyright 2013 Google Inc. # https://blockly.googlecode.com/ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import codecs import json import os from datetime import datetime class InputError(Exception): """Exception raised for errors in the input. Attributes: location -- where error occurred msg -- explanation of the error """ def __init__(self, location, msg): Exception.__init__(self, '{0}: {1}'.format(location, msg)) self.location = location self.msg = msg def read_json_file(filename): """Read a JSON file as UTF-8 into a dictionary, discarding @metadata. Args: filename: The filename, which must end ".json". Returns: The dictionary. Raises: InputError: The filename did not end with ".json" or an error occurred while opening or reading the file. """ if not filename.endswith('.json'): raise InputError(filename, 'filenames must end with ".json"') try: # Read in file. with codecs.open(filename, 'r', 'utf-8') as infile: defs = json.load(infile) if '@metadata' in defs: del defs['@metadata'] return defs except ValueError, e: print('Error reading ' + filename) raise InputError(file, str(e)) def _create_qqq_file(output_dir): """Creates a qqq.json file with message documentation for translatewiki.net. The file consists of key-value pairs, where the keys are message ids and the values are descriptions for the translators of the messages. What documentation exists for the format can be found at: http://translatewiki.net/wiki/Translating:Localisation_for_developers#Message_documentation The file should be closed by _close_qqq_file(). Parameters: output_dir: The output directory. Returns: A pointer to a file to which a left brace and newline have been written. Raises: IOError: An error occurred while opening or writing the file. """ qqq_file_name = os.path.join(os.curdir, output_dir, 'qqq.json') qqq_file = codecs.open(qqq_file_name, 'w', 'utf-8') print 'Created file: ' + qqq_file_name qqq_file.write('{\n') return qqq_file def _close_qqq_file(qqq_file): """Closes a qqq.json file created and opened by _create_qqq_file(). This writes the final newlines and right brace. Args: qqq_file: A file created by _create_qqq_file(). Raises: IOError: An error occurred while writing to or closing the file. """ qqq_file.write('\n}\n') qqq_file.close() def _create_lang_file(author, lang, output_dir): """Creates a .json file for translatewiki.net. The file consists of metadata, followed by key-value pairs, where the keys are message ids and the values are the messages in the language specified by the corresponding command-line argument. The file should be closed by _close_lang_file(). Args: author: Name and email address of contact for translators. lang: ISO 639-1 source language code. output_dir: Relative directory for output files. Returns: A pointer to a file to which the metadata has been written. Raises: IOError: An error occurred while opening or writing the file. """ lang_file_name = os.path.join(os.curdir, output_dir, lang + '.json') lang_file = codecs.open(lang_file_name, 'w', 'utf-8') print 'Created file: ' + lang_file_name # string.format doesn't like printing braces, so break up our writes. lang_file.write('{\n "@metadata": {') lang_file.write(""" "author": "{0}", "lastupdated": "{1}", "locale": "{2}", "messagedocumentation" : "qqq" """.format(author, str(datetime.now()), lang)) lang_file.write(' },\n') return lang_file def _close_lang_file(lang_file): """Closes a .json file created with _create_lang_file(). This also writes the terminating left brace and newline. Args: lang_file: A file opened with _create_lang_file(). Raises: IOError: An error occurred while writing to or closing the file. """ lang_file.write('\n}\n') lang_file.close() def _create_key_file(output_dir): """Creates a keys.json file mapping Closure keys to Blockly keys. Args: output_dir: Relative directory for output files. Raises: IOError: An error occurred while creating the file. """ key_file_name = os.path.join(os.curdir, output_dir, 'keys.json') key_file = open(key_file_name, 'w') key_file.write('{\n') print 'Created file: ' + key_file_name return key_file def _close_key_file(key_file): """Closes a key file created and opened with _create_key_file(). Args: key_file: A file created by _create_key_file(). Raises: IOError: An error occurred while writing to or closing the file. """ key_file.write('\n}\n') key_file.close() def write_files(author, lang, output_dir, units, write_key_file): """Writes the output files for the given units. There are three possible output files: * lang_file: JSON file mapping meanings (e.g., Maze.turnLeft) to the English text. The base name of the language file is specified by the "lang" command-line argument. * key_file: JSON file mapping meanings to Soy-generated keys (long hash codes). This is only output if the parameter write_key_file is True. * qqq_file: JSON file mapping meanings to descriptions. Args: author: Name and email address of contact for translators. lang: ISO 639-1 source language code. output_dir: Relative directory for output files. units: A list of dictionaries with entries for 'meaning', 'source', 'description', and 'keys' (the last only if write_key_file is true), in the order desired in the output files. write_key_file: Whether to output a keys.json file. Raises: IOError: An error occurs opening, writing to, or closing a file. KeyError: An expected key is missing from units. """ lang_file = _create_lang_file(author, lang, output_dir) qqq_file = _create_qqq_file(output_dir) if write_key_file: key_file = _create_key_file(output_dir) first_entry = True for unit in units: if not first_entry: lang_file.write(',\n') if write_key_file: key_file.write(',\n') qqq_file.write(',\n') lang_file.write(u' "{0}": "{1}"'.format( unit['meaning'], unit['source'].replace('"', "'"))) if write_key_file: key_file.write('"{0}": "{1}"'.format(unit['meaning'], unit['key'])) qqq_file.write(u' "{0}": "{1}"'.format( unit['meaning'], unit['description'].replace('"', "'").replace( '{lb}', '{').replace('{rb}', '}'))) first_entry = False _close_lang_file(lang_file) if write_key_file: _close_key_file(key_file) _close_qqq_file(qqq_file) def insert_breaks(s, min_length, max_length): """Inserts line breaks to try to get line lengths within the given range. This tries to minimize raggedness and to break lines at punctuation (periods and commas). It never splits words or numbers. Multiple spaces may be converted into single spaces. Args: s: The string to split. min_length: The requested minimum number of characters per line. max_length: The requested minimum number of characters per line. Returns: A copy of the original string with zero or more line breaks inserted. """ newline = '\\n' if len(s) < min_length: return s # Try splitting by sentences. This assumes sentences end with periods. sentences = s.split('.') # Remove empty sentences. sentences = [sen for sen in sentences if sen] # If all sentences are at least min_length and at most max_length, # then return one per line. if not [sen for sen in sentences if len(sen) > max_length or len(sen) < min_length]: return newline.join([sen.strip() + '.' for sen in sentences]) # Otherwise, divide into words, and use a greedy algorithm for the first # line, and try to get later lines as close as possible in length. words = [word for word in s.split(' ') if word] line1 = '' while (len(line1) + 1 + len(words[0]) < max_length and # Preferentially split on periods and commas. (not ((line1.endswith('. ') or line1.endswith(', ')) and len(line1) > min_length))): line1 += words.pop(0) + ' ' # If it all fits on one line, return that line. if not words: return line1 ideal_length = len(line1) output = line1 line = '' while words: line += words.pop(0) + ' ' if words: potential_len = len(line) + len(words[0]) if (potential_len > max_length or potential_len - ideal_length > ideal_length - len(line) or (line.endswith('. ') and len(line) > min_length)): output += newline + line line = '' output += newline + line return output ================================================ FILE: extern/blockly/i18n/create_messages.py ================================================ #!/usr/bin/python # Generate .js files defining Blockly core and language messages. # # Copyright 2013 Google Inc. # https://blockly.googlecode.com/ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import argparse import codecs import os import re import sys from common import read_json_file _NEWLINE_PATTERN = re.compile('[\n\r]') def main(): """Generate .js files defining Blockly core and language messages.""" # Process command-line arguments. parser = argparse.ArgumentParser(description='Convert JSON files to JS.') parser.add_argument('--source_lang', default='en', help='ISO 639-1 source language code') parser.add_argument('--source_lang_file', default=os.path.join('json', 'en.json'), help='Path to .json file for source language') parser.add_argument('--source_synonym_file', default=os.path.join('json', 'synonyms.json'), help='Path to .json file with synonym definitions') parser.add_argument('--output_dir', default='js/', help='relative directory for output files') parser.add_argument('--key_file', default='keys.json', help='relative path to input keys file') parser.add_argument('--min_length', default=30, help='minimum line length (not counting last line)') parser.add_argument('--max_length', default=50, help='maximum line length (not guaranteed)') parser.add_argument('--quiet', action='store_true', default=False, help='do not write anything to standard output') parser.add_argument('files', nargs='+', help='input files') args = parser.parse_args() if not args.output_dir.endswith(os.path.sep): args.output_dir += os.path.sep # Read in source language .json file, which provides any values missing # in target languages' .json files. source_defs = read_json_file(os.path.join(os.curdir, args.source_lang_file)) # Make sure the source file doesn't contain a newline or carriage return. for key, value in source_defs.items(): if _NEWLINE_PATTERN.search(value): print('ERROR: definition of {0} in {1} contained a newline character.'. format(key, args.source_lang_file)) sys.exit(1) sorted_keys = source_defs.keys() sorted_keys.sort() # Read in synonyms file, which must be output in every language. synonym_defs = read_json_file(os.path.join( os.curdir, args.source_synonym_file)) synonym_text = '\n'.join(['Blockly.Msg.{0} = Blockly.Msg.{1};'.format( key, synonym_defs[key]) for key in synonym_defs]) # Create each output file. for arg_file in args.files: (_, filename) = os.path.split(arg_file) target_lang = filename[:filename.index('.')] if target_lang not in ('qqq', 'keys', 'synonyms'): target_defs = read_json_file(os.path.join(os.curdir, arg_file)) # If there's a '\n' or '\r', remove it and print a warning. for key, value in target_defs.items(): if _NEWLINE_PATTERN.search(value): print('WARNING: definition of {0} in {1} contained ' 'a newline character.'. format(key, arg_file)) target_defs[key] = _NEWLINE_PATTERN.sub(' ', value) # Output file. outname = os.path.join(os.curdir, args.output_dir, target_lang + '.js') with codecs.open(outname, 'w', 'utf-8') as outfile: outfile.write( """// This file was automatically generated. Do not modify. 'use strict'; goog.provide('Blockly.Msg.{0}'); goog.require('Blockly.Msg'); """.format(target_lang)) # For each key in the source language file, output the target value # if present; otherwise, output the source language value with a # warning comment. for key in sorted_keys: if key in target_defs: value = target_defs[key] comment = '' del target_defs[key] else: value = source_defs[key] comment = ' // untranslated' value = value.replace('"', '\\"') outfile.write(u'Blockly.Msg.{0} = "{1}";{2}\n'.format( key, value, comment)) # Announce any keys defined only for target language. if target_defs: extra_keys = [key for key in target_defs if key not in synonym_defs] synonym_keys = [key for key in target_defs if key in synonym_defs] if not args.quiet: if extra_keys: print('These extra keys appeared in {0}: {1}'.format( filename, ', '.join(extra_keys))) if synonym_keys: print('These synonym keys appeared in {0}: {1}'.format( filename, ', '.join(synonym_keys))) outfile.write(synonym_text) if not args.quiet: print('Created {0}.'.format(outname)) if __name__ == '__main__': main() ================================================ FILE: extern/blockly/i18n/dedup_json.py ================================================ #!/usr/bin/python # Consolidates duplicate key-value pairs in a JSON file. # If the same key is used with different values, no warning is given, # and there is no guarantee about which key-value pair will be output. # There is also no guarantee as to the order of the key-value pairs # output. # # Copyright 2013 Google Inc. # https://blockly.googlecode.com/ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import argparse import codecs import json from common import InputError def main(): """Parses arguments and iterates over files. Raises: IOError: An I/O error occurred with an input or output file. InputError: Input JSON could not be parsed. """ # Set up argument parser. parser = argparse.ArgumentParser( description='Removes duplicate key-value pairs from JSON files.') parser.add_argument('--suffix', default='', help='optional suffix for output files; ' 'if empty, files will be changed in place') parser.add_argument('files', nargs='+', help='input files') args = parser.parse_args() # Iterate over files. for filename in args.files: # Read in json using Python libraries. This eliminates duplicates. print('Processing ' + filename + '...') try: with codecs.open(filename, 'r', 'utf-8') as infile: j = json.load(infile) except ValueError, e: print('Error reading ' + filename) raise InputError(file, str(e)) # Built up output strings as an array to make output of delimiters easier. output = [] for key in j: if key != '@metadata': output.append('\t"' + key + '": "' + j[key].replace('\n', '\\n') + '"') # Output results. with codecs.open(filename + args.suffix, 'w', 'utf-8') as outfile: outfile.write('{\n') outfile.write(',\n'.join(output)) outfile.write('\n}\n') if __name__ == '__main__': main() ================================================ FILE: extern/blockly/i18n/js_to_json.py ================================================ #!/usr/bin/python # Gives the translation status of the specified apps and languages. # # Copyright 2013 Google Inc. # https://blockly.googlecode.com/ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Extracts messages from .js files into .json files for translation. Specifically, lines with the following formats are extracted: /// Here is a description of the following message. Blockly.SOME_KEY = 'Some value'; Adjacent "///" lines are concatenated. There are two output files, each of which is proper JSON. For each key, the file en.json would get an entry of the form: "Blockly.SOME_KEY", "Some value", The file qqq.json would get: "Blockly.SOME_KEY", "Here is a description of the following message.", Commas would of course be omitted for the final entry of each value. @author Ellen Spertus (ellen.spertus@gmail.com) """ import argparse import codecs import json import os import re from common import write_files _INPUT_DEF_PATTERN = re.compile("""Blockly.Msg.(\w*)\s*=\s*'([^']*)';?$""") _INPUT_SYN_PATTERN = re.compile( """Blockly.Msg.(\w*)\s*=\s*Blockly.Msg.(\w*);""") def main(): # Set up argument parser. parser = argparse.ArgumentParser(description='Create translation files.') parser.add_argument( '--author', default='Ellen Spertus ', help='name and email address of contact for translators') parser.add_argument('--lang', default='en', help='ISO 639-1 source language code') parser.add_argument('--output_dir', default='json', help='relative directory for output files') parser.add_argument('--input_file', default='messages.js', help='input file') parser.add_argument('--quiet', action='store_true', default=False, help='only display warnings, not routine info') args = parser.parse_args() if (not args.output_dir.endswith(os.path.sep)): args.output_dir += os.path.sep # Read and parse input file. results = [] synonyms = {} description = '' infile = codecs.open(args.input_file, 'r', 'utf-8') for line in infile: if line.startswith('///'): if description: description = description + ' ' + line[3:].strip() else: description = line[3:].strip() else: match = _INPUT_DEF_PATTERN.match(line) if match: result = {} result['meaning'] = match.group(1) result['source'] = match.group(2) if not description: print('Warning: No description for ' + result['meaning']) result['description'] = description description = '' results.append(result) else: match = _INPUT_SYN_PATTERN.match(line) if match: if description: print('Warning: Description preceding definition of synonym {0}.'. format(match.group(1))) description = '' synonyms[match.group(1)] = match.group(2) infile.close() # Create .json, keys.json, and qqq.json. write_files(args.author, args.lang, args.output_dir, results, False) # Create synonyms.json. synonym_file_name = os.path.join(os.curdir, args.output_dir, 'synonyms.json') with open(synonym_file_name, 'w') as outfile: json.dump(synonyms, outfile) if not args.quiet: print("Wrote {0} synonym pairs to {1}.".format( len(synonyms), synonym_file_name)) if __name__ == '__main__': main() ================================================ FILE: extern/blockly/i18n/json_to_js.py ================================================ #!/usr/bin/python # Converts .json files into .js files for use within Blockly apps. # # Copyright 2013 Google Inc. # https://blockly.googlecode.com/ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import argparse import codecs # for codecs.open(..., 'utf-8') import json # for json.load() import os # for os.path() import subprocess # for subprocess.check_call() from common import InputError from common import insert_breaks from common import read_json_file # Store parsed command-line arguments in global variable. args = None def _create_xlf(target_lang): """Creates a .xlf file for Soy. Args: target_lang: The ISO 639 language code for the target language. This is used in the name of the file and in the metadata. Returns: A pointer to a file to which the metadata has been written. Raises: IOError: An error occurred while opening or writing the file. """ filename = os.path.join(os.curdir, args.output_dir, target_lang + '.xlf') out_file = codecs.open(filename, 'w', 'utf-8') out_file.write(""" """.format(args.source_lang, target_lang)) return out_file def _close_xlf(xlf_file): """Closes a .xlf file created with create_xlf(). This includes writing the terminating XML. Args: xlf_file: A pointer to a file created by _create_xlf(). Raises: IOError: An error occurred while writing to or closing the file. """ xlf_file.write(""" """) xlf_file.close() def _process_file(path_to_json, target_lang, key_dict): """Creates an .xlf file corresponding to the specified .json input file. The name of the input file must be target_lang followed by '.json'. The name of the output file will be target_lang followed by '.js'. Args: path_to_json: Path to the directory of xx.json files. target_lang: A IETF language code (RFC 4646), such as 'es' or 'pt-br'. key_dict: Dictionary mapping Blockly keys (e.g., Maze.turnLeft) to Closure keys (hash numbers). Raises: IOError: An I/O error occurred with an input or output file. InputError: Input JSON could not be parsed. KeyError: Key found in input file but not in key file. """ keyfile = os.path.join(path_to_json, target_lang + '.json') j = read_json_file(keyfile) out_file = _create_xlf(target_lang) for key in j: if key != '@metadata': try: identifier = key_dict[key] except KeyError, e: print('Key "%s" is in %s but not in %s' % (key, keyfile, args.key_file)) raise e target = j.get(key) # Only insert line breaks for tooltips. if key.lower().find('tooltip') != -1: target = insert_breaks( j.get(key), args.min_length, args.max_length) out_file.write(u""" {1} """.format(identifier, target)) _close_xlf(out_file) def main(): """Parses arguments and iterates over files.""" # Set up argument parser. parser = argparse.ArgumentParser(description='Convert JSON files to JS.') parser.add_argument('--source_lang', default='en', help='ISO 639-1 source language code') parser.add_argument('--output_dir', default='generated', help='relative directory for output files') parser.add_argument('--key_file', default='json' + os.path.sep + 'keys.json', help='relative path to input keys file') parser.add_argument('--template', default='template.soy') parser.add_argument('--min_length', default=30, help='minimum line length (not counting last line)') parser.add_argument('--max_length', default=50, help='maximum line length (not guaranteed)') parser.add_argument('--path_to_jar', default='..' + os.path.sep + 'apps' + os.path.sep + '_soy', help='relative path from working directory to ' 'SoyToJsSrcCompiler.jar') parser.add_argument('files', nargs='+', help='input files') # Initialize global variables. global args args = parser.parse_args() # Make sure output_dir ends with slash. if (not args.output_dir.endswith(os.path.sep)): args.output_dir += os.path.sep # Read in keys.json, mapping descriptions (e.g., Maze.turnLeft) to # Closure keys (long hash numbers). key_file = open(args.key_file) key_dict = json.load(key_file) key_file.close() # Process each input file. print('Creating .xlf files...') processed_langs = [] for arg_file in args.files: (path_to_json, filename) = os.path.split(arg_file) if not filename.endswith('.json'): raise InputError(filename, 'filenames must end with ".json"') target_lang = filename[:filename.index('.')] if not target_lang in ('qqq', 'keys'): processed_langs.append(target_lang) _process_file(path_to_json, target_lang, key_dict) # Output command line for Closure compiler. if processed_langs: print('Creating .js files...') processed_lang_list = ','.join(processed_langs) subprocess.check_call([ 'java', '-jar', os.path.join(args.path_to_jar, 'SoyToJsSrcCompiler.jar'), '--locales', processed_lang_list, '--messageFilePathFormat', args.output_dir + '{LOCALE}.xlf', '--outputPathFormat', args.output_dir + '{LOCALE}.js', '--srcs', args.template]) if len(processed_langs) == 1: print('Created ' + processed_lang_list + '.js in ' + args.output_dir) else: print('Created {' + processed_lang_list + '}.js in ' + args.output_dir) command = ['rm'] command.extend(map(lambda s: args.output_dir + s + '.xlf', processed_langs)) subprocess.check_call(command) print('Removed .xlf files.') if __name__ == '__main__': main() ================================================ FILE: extern/blockly/i18n/status.py ================================================ #!/usr/bin/python # Gives the translation status of the specified apps and languages. # # Copyright 2013 Google Inc. # https://blockly.googlecode.com/ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Produce a table showing the translation status of each app by language. @author Ellen Spertus (ellen.spertus@gmail.com) """ import argparse import os from common import read_json_file # Bogus language name representing all messages defined. TOTAL = 'qqq' # List of key prefixes, which are app names, except for 'Apps', which # has common messages. It is included here for convenience. APPS = ['Apps', 'Code', 'Graph', 'Maze', 'Plane', 'Puzzle', 'Turtle'] def get_prefix(s): """Gets the portion of a string before the first period. Args: s: A string. Returns: The portion of the string before the first period, or the entire string if it does not contain a period. """ return s.split('.')[0] def get_prefix_count(prefix, arr): """Counts how many strings in the array start with the prefix. Args: prefix: The prefix string. arr: An array of strings. Returns: The number of strings in arr starting with prefix. """ # This code was chosen for its elegance not its efficiency. return len([elt for elt in arr if elt.startswith(prefix)]) def output_as_html(messages, apps, verbose): """Outputs the given prefix counts and percentages as HTML. Specifically, a sortable HTML table is produced, where the app names are column headers, and one language is output per row. Entries are color-coded based on the percent completeness. Args: messages: A dictionary of dictionaries, where the outer keys are language codes used by translatewiki (generally, ISO 639 language codes) or the string TOTAL, used to indicate the total set of messages. The inner dictionary makes message keys to values in that language. apps: Apps to consider. verbose: Whether to list missing keys. """ def generate_language_url(lang): return 'https://translatewiki.net/wiki/Special:SupportedLanguages#' + lang def generate_number_as_percent(num, total, tag): percent = num * 100 / total if percent == 100: color = 'green' elif percent >= 90: color = 'orange' elif percent >= 60: color = 'black' else: color = 'gray' s = '{1} ({2}%)'.format(color, num, percent) if verbose and percent < 100: return '{1}'.format(tag, s) else: return s print('Blockly app translation status') print("") print('') print('') for lang in messages: if lang != TOTAL: print(''.format( lang, generate_language_url(lang))) for app in apps: print '' print('') print('
Language' + ''.join(apps) + '
{0}' print(generate_number_as_percent( get_prefix_count(app, messages[lang]), get_prefix_count(app, messages[TOTAL]), (lang + app))) print '
ALL') print(''.join([str(get_prefix_count(app, TOTAL)) for app in apps])) print('
') if verbose: for lang in messages: if lang != TOTAL: for app in apps: if (get_prefix_count(app, messages[lang]) < get_prefix_count(app, messages[TOTAL])): print('
{1} ({0})'. format(lang, app, generate_language_url(lang))) print(' missing: ') print(', '.join( [key for key in messages[TOTAL] if key.startswith(app) and key not in messages[lang]])) print('

') print('') def output_as_text(messages, apps, verbose): """Outputs the given prefix counts and percentages as text. Args: messages: A dictionary of dictionaries, where the outer keys are language codes used by translatewiki (generally, ISO 639 language codes) or the string TOTAL, used to indicate the total set of messages. The inner dictionary makes message keys to values in that language. apps: Apps to consider. verbose: Whether to list missing keys. """ def generate_number_as_percent(num, total): return '{0} ({1}%)'.format(num, num * 100 / total) MAX_WIDTH = len('999 (100%)') + 1 FIELD_STRING = '{0: <' + str(MAX_WIDTH) + '}' print(FIELD_STRING.format('Language') + ''.join( [FIELD_STRING.format(app) for app in apps])) print(('-' * (MAX_WIDTH - 1) + ' ') * (len(apps) + 1)) for lang in messages: if lang != TOTAL: print(FIELD_STRING.format(lang) + ''.join([FIELD_STRING.format(generate_number_as_percent( get_prefix_count(app, messages[lang]), get_prefix_count(app, messages[TOTAL]))) for app in apps])) print(FIELD_STRING.format(TOTAL) + ''.join( [FIELD_STRING.format(get_prefix_count(app, messages[TOTAL])) for app in apps])) if verbose: for lang in messages: if lang != TOTAL: for app in apps: missing = [key for key in messages[TOTAL] if key.startswith(app) and key not in messages[lang]] print('{0} {1}: Missing: {2}'.format( app.upper(), lang, (', '.join(missing) if missing else 'none'))) def output_as_csv(messages, apps): """Outputs the given prefix counts and percentages as CSV. Args: messages: A dictionary of dictionaries, where the outer keys are language codes used by translatewiki (generally, ISO 639 language codes) or the string TOTAL, used to indicate the total set of messages. The inner dictionary makes message keys to values in that language. apps: Apps to consider. """ # Header row. print('Language, ' + ', ,'.join(apps)) # Total row. # Put at top, rather than bottom, so it can be frozen. print('TOTAL, ' + ', '.join( [str(get_prefix_count(app, messages[TOTAL])) + ', ' for app in apps])) # One line per language. for lang in messages: if lang != TOTAL: print(lang + ', ' + ', '.join( [str(get_prefix_count(app, messages[lang])) + ', ' + str((get_prefix_count(app, messages[lang]) * 1.0 / get_prefix_count(app, messages[TOTAL]))) for app in apps])) def main(): """Processes input files and outputs results in specified format. """ # Argument parsing. parser = argparse.ArgumentParser( description='Display translation status by app and language.') parser.add_argument('--key_file', default='json' + os.path.sep + 'keys.json', help='file with complete list of keys.') parser.add_argument('--output', default='text', choices=['text', 'html', 'csv'], help='output format') parser.add_argument('--verbose', action='store_true', default=False, help='whether to indicate which messages were translated ' '(only used in text and html output modes)') parser.add_argument('--app', default=None, choices=APPS, help='if set, only consider the specified app (prefix).') parser.add_argument('lang_files', nargs='+', help='names of JSON files to examine') args = parser.parse_args() apps = [args.app] if args.app else APPS # Read in JSON files. messages = {} # A dictionary of dictionaries. messages[TOTAL] = read_json_file(args.key_file) for lang_file in args.lang_files: prefix = get_prefix(os.path.split(lang_file)[1]) # Skip non-language files. if prefix not in ['qqq', 'keys']: messages[prefix] = read_json_file(lang_file) # Output results. if args.output == 'text': output_as_text(messages, apps, args.verbose) elif args.output == 'html': output_as_html(messages, apps, args.verbose) elif args.output == 'csv': output_as_csv(messages, apps) else: print('No output?!') if __name__ == '__main__': main() ================================================ FILE: extern/blockly/i18n/tests.py ================================================ #!/usr/bin/python # -*- coding: utf-8 -*- # Tests of i18n scripts. # # Copyright 2013 Google Inc. # https://blockly.googlecode.com/ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import common import re import unittest class TestSequenceFunctions(unittest.TestCase): def test_insert_breaks(self): spaces = re.compile(r'\s+|\\n') def contains_all_chars(orig, result): return re.sub(spaces, '', orig) == re.sub(spaces, '', result) sentences = [u'Quay Pegman qua bên trái hoặc bên phải 90 độ.', u'Foo bar baz this is english that is okay bye.', u'If there is a path in the specified direction, \nthen ' + u'do some actions.', u'If there is a path in the specified direction, then do ' + u'the first block of actions. Otherwise, do the second ' + u'block of actions.'] for sentence in sentences: output = common.insert_breaks(sentence, 30, 50) self.assert_(contains_all_chars(sentence, output), u'Mismatch between:\n{0}\n{1}'.format( re.sub(spaces, '', sentence), re.sub(spaces, '', output))) if __name__ == '__main__': unittest.main() ================================================ FILE: extern/blockly/i18n/xliff_to_json.py ================================================ #!/usr/bin/python # Converts .xlf files into .json files for use at http://translatewiki.net. # # Copyright 2013 Google Inc. # https://blockly.googlecode.com/ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import argparse import os import re import subprocess import sys from xml.dom import minidom from common import InputError from common import write_files # Global variables args = None # parsed command-line arguments def _parse_trans_unit(trans_unit): """Converts a trans-unit XML node into a more convenient dictionary format. Args: trans_unit: An XML representation of a .xlf translation unit. Returns: A dictionary with useful information about the translation unit. The returned dictionary is guaranteed to have an entry for 'key' and may have entries for 'source', 'target', 'description', and 'meaning' if present in the argument. Raises: InputError: A required field was not present. """ def get_value(tag_name): elts = trans_unit.getElementsByTagName(tag_name) if not elts: return None elif len(elts) == 1: return ''.join([child.toxml() for child in elts[0].childNodes]) else: raise InputError('', 'Unable to extract ' + tag_name) result = {} key = trans_unit.getAttribute('id') if not key: raise InputError('', 'id attribute not found') result['key'] = key # Get source and target, if present. try: result['source'] = get_value('source') result['target'] = get_value('target') except InputError, e: raise InputError(key, e.msg) # Get notes, using the from value as key and the data as value. notes = trans_unit.getElementsByTagName('note') for note in notes: from_value = note.getAttribute('from') if from_value and len(note.childNodes) == 1: result[from_value] = note.childNodes[0].data else: raise InputError(key, 'Unable to extract ' + from_value) return result def _process_file(filename): """Builds list of translation units from input file. Each translation unit in the input file includes: - an id (opaquely generated by Soy) - the Blockly name for the message - the text in the source language (generally English) - a description for the translator The Soy and Blockly ids are joined with a hyphen and serve as the keys in both output files. The value is the corresponding text (in the .json file) or the description (in the qqq.json file). Args: filename: The name of an .xlf file produced by Closure. Raises: IOError: An I/O error occurred with an input or output file. InputError: The input file could not be parsed or lacked required fields. Returns: A list of dictionaries produced by parse_trans_unit(). """ try: results = [] # list of dictionaries (return value) names = [] # list of names of encountered keys (local variable) try: parsed_xml = minidom.parse(filename) except IOError: # Don't get caught by below handler raise except Exception, e: print raise InputError(filename, str(e)) # Make sure needed fields are present and non-empty. for trans_unit in parsed_xml.getElementsByTagName('trans-unit'): unit = _parse_trans_unit(trans_unit) for key in ['description', 'meaning', 'source']: if not key in unit or not unit[key]: raise InputError(filename + ':' + unit['key'], key + ' not found') if unit['description'].lower() == 'ibid': if unit['meaning'] not in names: # If the term has not already been described, the use of 'ibid' # is an error. raise InputError( filename, 'First encountered definition of: ' + unit['meaning'] + ' has definition: ' + unit['description'] + '. This error can occur if the definition was not' + ' provided on the first appearance of the message' + ' or if the source (English-language) messages differ.') else: # If term has already been described, 'ibid' was used correctly, # and we output nothing. pass else: if unit['meaning'] in names: raise InputError(filename, 'Second definition of: ' + unit['meaning']) names.append(unit['meaning']) results.append(unit) return results except IOError, e: print 'Error with file {0}: {1}'.format(filename, e.strerror) sys.exit(1) def sort_units(units, templates): """Sorts the translation units by their definition order in the template. Args: units: A list of dictionaries produced by parse_trans_unit() that have a non-empty value for the key 'meaning'. templates: A string containing the Soy templates in which each of the units' meanings is defined. Returns: A new list of translation units, sorted by the order in which their meaning is defined in the templates. Raises: InputError: If a meaning definition cannot be found in the templates. """ def key_function(unit): match = re.search( '\\smeaning\\s*=\\s*"{0}"\\s'.format(unit['meaning']), templates) if match: return match.start() else: raise InputError(args.templates, 'msg definition for meaning not found: ' + unit['meaning']) return sorted(units, key=key_function) def main(): """Parses arguments and processes the specified file. Raises: IOError: An I/O error occurred with an input or output file. InputError: Input files lacked required fields. """ # Set up argument parser. parser = argparse.ArgumentParser(description='Create translation files.') parser.add_argument( '--author', default='Ellen Spertus ', help='name and email address of contact for translators') parser.add_argument('--lang', default='en', help='ISO 639-1 source language code') parser.add_argument('--output_dir', default='json', help='relative directory for output files') parser.add_argument('--xlf', help='file containing xlf definitions') parser.add_argument('--templates', default=['template.soy'], nargs='+', help='relative path to Soy templates, comma or space ' 'separated (used for ordering messages)') global args args = parser.parse_args() # Make sure output_dir ends with slash. if (not args.output_dir.endswith(os.path.sep)): args.output_dir += os.path.sep # Process the input file, and sort the entries. units = _process_file(args.xlf) files = [] for arg in args.templates: for filename in arg.split(','): filename = filename.strip(); if filename: with open(filename) as myfile: files.append(' '.join(line.strip() for line in myfile)) sorted_units = sort_units(units, ' '.join(files)) # Write the output files. write_files(args.author, args.lang, args.output_dir, sorted_units, True) # Delete the input .xlf file. command = ['rm', args.xlf] subprocess.check_call(command) print('Removed ' + args.xlf) if __name__ == '__main__': main() ================================================ FILE: extern/blockly/javascript_compressed.js ================================================ // Do not edit this file; automatically generated by build.py. "use strict"; // Copyright 2012 Google Inc. Apache License 2.0 Blockly.JavaScript=new Blockly.Generator("JavaScript");Blockly.JavaScript.addReservedWords("Blockly,break,case,catch,continue,debugger,default,delete,do,else,finally,for,function,if,in,instanceof,new,return,switch,this,throw,try,typeof,var,void,while,with,class,enum,export,extends,import,super,implements,interface,let,package,private,protected,public,static,yield,const,null,true,false,Array,ArrayBuffer,Boolean,Date,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Error,eval,EvalError,Float32Array,Float64Array,Function,Infinity,Int16Array,Int32Array,Int8Array,isFinite,isNaN,Iterator,JSON,Math,NaN,Number,Object,parseFloat,parseInt,RangeError,ReferenceError,RegExp,StopIteration,String,SyntaxError,TypeError,Uint16Array,Uint32Array,Uint8Array,Uint8ClampedArray,undefined,uneval,URIError,applicationCache,closed,Components,content,_content,controllers,crypto,defaultStatus,dialogArguments,directories,document,frameElement,frames,fullScreen,globalStorage,history,innerHeight,innerWidth,length,location,locationbar,localStorage,menubar,messageManager,mozAnimationStartTime,mozInnerScreenX,mozInnerScreenY,mozPaintCount,name,navigator,opener,outerHeight,outerWidth,pageXOffset,pageYOffset,parent,performance,personalbar,pkcs11,returnValue,screen,screenX,screenY,scrollbars,scrollMaxX,scrollMaxY,scrollX,scrollY,self,sessionStorage,sidebar,status,statusbar,toolbar,top,URL,window,addEventListener,alert,atob,back,blur,btoa,captureEvents,clearImmediate,clearInterval,clearTimeout,close,confirm,disableExternalCapture,dispatchEvent,dump,enableExternalCapture,escape,find,focus,forward,GeckoActiveXObject,getAttention,getAttentionWithCycleCount,getComputedStyle,getSelection,home,matchMedia,maximize,minimize,moveBy,moveTo,mozRequestAnimationFrame,open,openDialog,postMessage,print,prompt,QueryInterface,releaseEvents,removeEventListener,resizeBy,resizeTo,restore,routeEvent,scroll,scrollBy,scrollByLines,scrollByPages,scrollTo,setCursor,setImmediate,setInterval,setResizable,setTimeout,showModalDialog,sizeToContent,stop,unescape,updateCommands,XPCNativeWrapper,XPCSafeJSObjectWrapper,onabort,onbeforeunload,onblur,onchange,onclick,onclose,oncontextmenu,ondevicemotion,ondeviceorientation,ondragdrop,onerror,onfocus,onhashchange,onkeydown,onkeypress,onkeyup,onload,onmousedown,onmousemove,onmouseout,onmouseover,onmouseup,onmozbeforepaint,onpaint,onpopstate,onreset,onresize,onscroll,onselect,onsubmit,onunload,onpageshow,onpagehide,Image,Option,Worker,Event,Range,File,FileReader,Blob,BlobBuilder,Attr,CDATASection,CharacterData,Comment,console,DocumentFragment,DocumentType,DomConfiguration,DOMError,DOMErrorHandler,DOMException,DOMImplementation,DOMImplementationList,DOMImplementationRegistry,DOMImplementationSource,DOMLocator,DOMObject,DOMString,DOMStringList,DOMTimeStamp,DOMUserData,Entity,EntityReference,MediaQueryList,MediaQueryListListener,NameList,NamedNodeMap,Node,NodeFilter,NodeIterator,NodeList,Notation,Plugin,PluginArray,ProcessingInstruction,SharedWorker,Text,TimeRanges,Treewalker,TypeInfo,UserDataHandler,Worker,WorkerGlobalScope,HTMLDocument,HTMLElement,HTMLAnchorElement,HTMLAppletElement,HTMLAudioElement,HTMLAreaElement,HTMLBaseElement,HTMLBaseFontElement,HTMLBodyElement,HTMLBRElement,HTMLButtonElement,HTMLCanvasElement,HTMLDirectoryElement,HTMLDivElement,HTMLDListElement,HTMLEmbedElement,HTMLFieldSetElement,HTMLFontElement,HTMLFormElement,HTMLFrameElement,HTMLFrameSetElement,HTMLHeadElement,HTMLHeadingElement,HTMLHtmlElement,HTMLHRElement,HTMLIFrameElement,HTMLImageElement,HTMLInputElement,HTMLKeygenElement,HTMLLabelElement,HTMLLIElement,HTMLLinkElement,HTMLMapElement,HTMLMenuElement,HTMLMetaElement,HTMLModElement,HTMLObjectElement,HTMLOListElement,HTMLOptGroupElement,HTMLOptionElement,HTMLOutputElement,HTMLParagraphElement,HTMLParamElement,HTMLPreElement,HTMLQuoteElement,HTMLScriptElement,HTMLSelectElement,HTMLSourceElement,HTMLSpanElement,HTMLStyleElement,HTMLTableElement,HTMLTableCaptionElement,HTMLTableCellElement,HTMLTableDataCellElement,HTMLTableHeaderCellElement,HTMLTableColElement,HTMLTableRowElement,HTMLTableSectionElement,HTMLTextAreaElement,HTMLTimeElement,HTMLTitleElement,HTMLTrackElement,HTMLUListElement,HTMLUnknownElement,HTMLVideoElement,HTMLCanvasElement,CanvasRenderingContext2D,CanvasGradient,CanvasPattern,TextMetrics,ImageData,CanvasPixelArray,HTMLAudioElement,HTMLVideoElement,NotifyAudioAvailableEvent,HTMLCollection,HTMLAllCollection,HTMLFormControlsCollection,HTMLOptionsCollection,HTMLPropertiesCollection,DOMTokenList,DOMSettableTokenList,DOMStringMap,RadioNodeList,SVGDocument,SVGElement,SVGAElement,SVGAltGlyphElement,SVGAltGlyphDefElement,SVGAltGlyphItemElement,SVGAnimationElement,SVGAnimateElement,SVGAnimateColorElement,SVGAnimateMotionElement,SVGAnimateTransformElement,SVGSetElement,SVGCircleElement,SVGClipPathElement,SVGColorProfileElement,SVGCursorElement,SVGDefsElement,SVGDescElement,SVGEllipseElement,SVGFilterElement,SVGFilterPrimitiveStandardAttributes,SVGFEBlendElement,SVGFEColorMatrixElement,SVGFEComponentTransferElement,SVGFECompositeElement,SVGFEConvolveMatrixElement,SVGFEDiffuseLightingElement,SVGFEDisplacementMapElement,SVGFEDistantLightElement,SVGFEFloodElement,SVGFEGaussianBlurElement,SVGFEImageElement,SVGFEMergeElement,SVGFEMergeNodeElement,SVGFEMorphologyElement,SVGFEOffsetElement,SVGFEPointLightElement,SVGFESpecularLightingElement,SVGFESpotLightElement,SVGFETileElement,SVGFETurbulenceElement,SVGComponentTransferFunctionElement,SVGFEFuncRElement,SVGFEFuncGElement,SVGFEFuncBElement,SVGFEFuncAElement,SVGFontElement,SVGFontFaceElement,SVGFontFaceFormatElement,SVGFontFaceNameElement,SVGFontFaceSrcElement,SVGFontFaceUriElement,SVGForeignObjectElement,SVGGElement,SVGGlyphElement,SVGGlyphRefElement,SVGGradientElement,SVGLinearGradientElement,SVGRadialGradientElement,SVGHKernElement,SVGImageElement,SVGLineElement,SVGMarkerElement,SVGMaskElement,SVGMetadataElement,SVGMissingGlyphElement,SVGMPathElement,SVGPathElement,SVGPatternElement,SVGPolylineElement,SVGPolygonElement,SVGRectElement,SVGScriptElement,SVGStopElement,SVGStyleElement,SVGSVGElement,SVGSwitchElement,SVGSymbolElement,SVGTextElement,SVGTextPathElement,SVGTitleElement,SVGTRefElement,SVGTSpanElement,SVGUseElement,SVGViewElement,SVGVKernElement,SVGAngle,SVGColor,SVGICCColor,SVGElementInstance,SVGElementInstanceList,SVGLength,SVGLengthList,SVGMatrix,SVGNumber,SVGNumberList,SVGPaint,SVGPoint,SVGPointList,SVGPreserveAspectRatio,SVGRect,SVGStringList,SVGTransform,SVGTransformList,SVGAnimatedAngle,SVGAnimatedBoolean,SVGAnimatedEnumeration,SVGAnimatedInteger,SVGAnimatedLength,SVGAnimatedLengthList,SVGAnimatedNumber,SVGAnimatedNumberList,SVGAnimatedPreserveAspectRatio,SVGAnimatedRect,SVGAnimatedString,SVGAnimatedTransformList,SVGPathSegList,SVGPathSeg,SVGPathSegArcAbs,SVGPathSegArcRel,SVGPathSegClosePath,SVGPathSegCurvetoCubicAbs,SVGPathSegCurvetoCubicRel,SVGPathSegCurvetoCubicSmoothAbs,SVGPathSegCurvetoCubicSmoothRel,SVGPathSegCurvetoQuadraticAbs,SVGPathSegCurvetoQuadraticRel,SVGPathSegCurvetoQuadraticSmoothAbs,SVGPathSegCurvetoQuadraticSmoothRel,SVGPathSegLinetoAbs,SVGPathSegLinetoHorizontalAbs,SVGPathSegLinetoHorizontalRel,SVGPathSegLinetoRel,SVGPathSegLinetoVerticalAbs,SVGPathSegLinetoVerticalRel,SVGPathSegMovetoAbs,SVGPathSegMovetoRel,ElementTimeControl,TimeEvent,SVGAnimatedPathData,SVGAnimatedPoints,SVGColorProfileRule,SVGCSSRule,SVGExternalResourcesRequired,SVGFitToViewBox,SVGLangSpace,SVGLocatable,SVGRenderingIntent,SVGStylable,SVGTests,SVGTextContentElement,SVGTextPositioningElement,SVGTransformable,SVGUnitTypes,SVGURIReference,SVGViewSpec,SVGZoomAndPan"); Blockly.JavaScript.ORDER_ATOMIC=0;Blockly.JavaScript.ORDER_MEMBER=1;Blockly.JavaScript.ORDER_NEW=1;Blockly.JavaScript.ORDER_FUNCTION_CALL=2;Blockly.JavaScript.ORDER_INCREMENT=3;Blockly.JavaScript.ORDER_DECREMENT=3;Blockly.JavaScript.ORDER_LOGICAL_NOT=4;Blockly.JavaScript.ORDER_BITWISE_NOT=4;Blockly.JavaScript.ORDER_UNARY_PLUS=4;Blockly.JavaScript.ORDER_UNARY_NEGATION=4;Blockly.JavaScript.ORDER_TYPEOF=4;Blockly.JavaScript.ORDER_VOID=4;Blockly.JavaScript.ORDER_DELETE=4; Blockly.JavaScript.ORDER_MULTIPLICATION=5;Blockly.JavaScript.ORDER_DIVISION=5;Blockly.JavaScript.ORDER_MODULUS=5;Blockly.JavaScript.ORDER_ADDITION=6;Blockly.JavaScript.ORDER_SUBTRACTION=6;Blockly.JavaScript.ORDER_BITWISE_SHIFT=7;Blockly.JavaScript.ORDER_RELATIONAL=8;Blockly.JavaScript.ORDER_IN=8;Blockly.JavaScript.ORDER_INSTANCEOF=8;Blockly.JavaScript.ORDER_EQUALITY=9;Blockly.JavaScript.ORDER_BITWISE_AND=10;Blockly.JavaScript.ORDER_BITWISE_XOR=11;Blockly.JavaScript.ORDER_BITWISE_OR=12; Blockly.JavaScript.ORDER_LOGICAL_AND=13;Blockly.JavaScript.ORDER_LOGICAL_OR=14;Blockly.JavaScript.ORDER_CONDITIONAL=15;Blockly.JavaScript.ORDER_ASSIGNMENT=16;Blockly.JavaScript.ORDER_COMMA=17;Blockly.JavaScript.ORDER_NONE=99;Blockly.JavaScript.INFINITE_LOOP_TRAP=null; Blockly.JavaScript.init=function(){Blockly.JavaScript.definitions_=Object.create(null);Blockly.JavaScript.functionNames_=Object.create(null);if(Blockly.Variables){Blockly.JavaScript.variableDB_?Blockly.JavaScript.variableDB_.reset():Blockly.JavaScript.variableDB_=new Blockly.Names(Blockly.JavaScript.RESERVED_WORDS_);for(var a=[],b=Blockly.Variables.allVariables(),c=0;c",GTE:">="}[a.getFieldValue("OP")],c="=="==b||"!="==b?Blockly.JavaScript.ORDER_EQUALITY:Blockly.JavaScript.ORDER_RELATIONAL,d=Blockly.JavaScript.valueToCode(a,"A",c)||"0";a=Blockly.JavaScript.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]}; Blockly.JavaScript.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"&&":"||",c="&&"==b?Blockly.JavaScript.ORDER_LOGICAL_AND:Blockly.JavaScript.ORDER_LOGICAL_OR,d=Blockly.JavaScript.valueToCode(a,"A",c);a=Blockly.JavaScript.valueToCode(a,"B",c);if(d||a){var e="&&"==b?"true":"false";d||(d=e);a||(a=e)}else a=d="false";return[d+" "+b+" "+a,c]}; Blockly.JavaScript.logic_negate=function(a){var b=Blockly.JavaScript.ORDER_LOGICAL_NOT;return["!"+(Blockly.JavaScript.valueToCode(a,"BOOL",b)||"true"),b]};Blockly.JavaScript.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"true":"false",Blockly.JavaScript.ORDER_ATOMIC]};Blockly.JavaScript.logic_null=function(a){return["null",Blockly.JavaScript.ORDER_ATOMIC]}; Blockly.JavaScript.logic_ternary=function(a){var b=Blockly.JavaScript.valueToCode(a,"IF",Blockly.JavaScript.ORDER_CONDITIONAL)||"false",c=Blockly.JavaScript.valueToCode(a,"THEN",Blockly.JavaScript.ORDER_CONDITIONAL)||"null";a=Blockly.JavaScript.valueToCode(a,"ELSE",Blockly.JavaScript.ORDER_CONDITIONAL)||"null";return[b+" ? "+c+" : "+a,Blockly.JavaScript.ORDER_CONDITIONAL]};Blockly.JavaScript.loops={};Blockly.JavaScript.controls_repeat=function(a){var b=Number(a.getFieldValue("TIMES")),c=Blockly.JavaScript.statementToCode(a,"DO");Blockly.JavaScript.INFINITE_LOOP_TRAP&&(c=Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+c);a=Blockly.JavaScript.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE);return"for (var "+a+" = 0; "+a+" < "+b+"; "+a+"++) {\n"+c+"}\n"}; Blockly.JavaScript.controls_repeat_ext=function(a){var b=Blockly.JavaScript.valueToCode(a,"TIMES",Blockly.JavaScript.ORDER_ASSIGNMENT)||"0",c=Blockly.JavaScript.statementToCode(a,"DO");Blockly.JavaScript.INFINITE_LOOP_TRAP&&(c=Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+c);a="";var d=Blockly.JavaScript.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE),e=b;b.match(/^\w+$/)||Blockly.isNumber(b)||(e=Blockly.JavaScript.variableDB_.getDistinctName("repeat_end",Blockly.Variables.NAME_TYPE), a+="var "+e+" = "+b+";\n");return a+("for (var "+d+" = 0; "+d+" < "+e+"; "+d+"++) {\n"+c+"}\n")}; Blockly.JavaScript.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.JavaScript.valueToCode(a,"BOOL",b?Blockly.JavaScript.ORDER_LOGICAL_NOT:Blockly.JavaScript.ORDER_NONE)||"false",d=Blockly.JavaScript.statementToCode(a,"DO");Blockly.JavaScript.INFINITE_LOOP_TRAP&&(d=Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+d);b&&(c="!"+c);return"while ("+c+") {\n"+d+"}\n"}; Blockly.JavaScript.controls_for=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.JavaScript.valueToCode(a,"FROM",Blockly.JavaScript.ORDER_ASSIGNMENT)||"0",d=Blockly.JavaScript.valueToCode(a,"TO",Blockly.JavaScript.ORDER_ASSIGNMENT)||"0",e=Blockly.JavaScript.valueToCode(a,"BY",Blockly.JavaScript.ORDER_ASSIGNMENT)||"1",f=Blockly.JavaScript.statementToCode(a,"DO");Blockly.JavaScript.INFINITE_LOOP_TRAP&&(f=Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, "'"+a.id+"'")+f);if(Blockly.isNumber(c)&&Blockly.isNumber(d)&&Blockly.isNumber(e)){var g=parseFloat(c)<=parseFloat(d);a="for ("+b+" = "+c+"; "+b+(g?" <= ":" >= ")+d+"; "+b;b=Math.abs(parseFloat(e));a=(1==b?a+(g?"++":"--"):a+((g?" += ":" -= ")+b))+(") {\n"+f+"}\n")}else a="",g=c,c.match(/^\w+$/)||Blockly.isNumber(c)||(g=Blockly.JavaScript.variableDB_.getDistinctName(b+"_start",Blockly.Variables.NAME_TYPE),a+="var "+g+" = "+c+";\n"),c=d,d.match(/^\w+$/)||Blockly.isNumber(d)||(c=Blockly.JavaScript.variableDB_.getDistinctName(b+ "_end",Blockly.Variables.NAME_TYPE),a+="var "+c+" = "+d+";\n"),d=Blockly.JavaScript.variableDB_.getDistinctName(b+"_inc",Blockly.Variables.NAME_TYPE),a+="var "+d+" = ",a=Blockly.isNumber(e)?a+(Math.abs(e)+";\n"):a+("Math.abs("+e+");\n"),a=a+("if ("+g+" > "+c+") {\n")+(" "+d+" = -"+d+";\n"),a+="}\n",a+="for ("+b+" = "+g+";\n "+d+" >= 0 ? "+b+" <= "+c+" : "+b+" >= "+c+";\n "+b+" += "+d+") {\n"+f+"}\n";return a}; Blockly.JavaScript.controls_forEach=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_ASSIGNMENT)||"[]",d=Blockly.JavaScript.statementToCode(a,"DO");Blockly.JavaScript.INFINITE_LOOP_TRAP&&(d=Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+d);a=Blockly.JavaScript.variableDB_.getDistinctName(b+"_index",Blockly.Variables.NAME_TYPE);return"for (var "+a+" in "+ c+") {\n"+(" "+b+" = "+c+"["+a+"];\n"+d)+"}\n"};Blockly.JavaScript.controls_flow_statements=function(a){switch(a.getFieldValue("FLOW")){case "BREAK":return"break;\n";case "CONTINUE":return"continue;\n"}throw"Unknown flow statement.";};Blockly.JavaScript.math={};Blockly.JavaScript.math_number=function(a){return[parseFloat(a.getFieldValue("NUM")),Blockly.JavaScript.ORDER_ATOMIC]}; Blockly.JavaScript.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.JavaScript.ORDER_ADDITION],MINUS:[" - ",Blockly.JavaScript.ORDER_SUBTRACTION],MULTIPLY:[" * ",Blockly.JavaScript.ORDER_MULTIPLICATION],DIVIDE:[" / ",Blockly.JavaScript.ORDER_DIVISION],POWER:[null,Blockly.JavaScript.ORDER_COMMA]}[a.getFieldValue("OP")],c=b[0],b=b[1],d=Blockly.JavaScript.valueToCode(a,"A",b)||"0";a=Blockly.JavaScript.valueToCode(a,"B",b)||"0";return c?[d+c+a,b]:["Math.pow("+d+", "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; Blockly.JavaScript.math_single=function(a){var b=a.getFieldValue("OP"),c;if("NEG"==b)return a=Blockly.JavaScript.valueToCode(a,"NUM",Blockly.JavaScript.ORDER_UNARY_NEGATION)||"0","-"==a[0]&&(a=" "+a),["-"+a,Blockly.JavaScript.ORDER_UNARY_NEGATION];a="SIN"==b||"COS"==b||"TAN"==b?Blockly.JavaScript.valueToCode(a,"NUM",Blockly.JavaScript.ORDER_DIVISION)||"0":Blockly.JavaScript.valueToCode(a,"NUM",Blockly.JavaScript.ORDER_NONE)||"0";switch(b){case "ABS":c="Math.abs("+a+")";break;case "ROOT":c="Math.sqrt("+ a+")";break;case "LN":c="Math.log("+a+")";break;case "EXP":c="Math.exp("+a+")";break;case "POW10":c="Math.pow(10,"+a+")";break;case "ROUND":c="Math.round("+a+")";break;case "ROUNDUP":c="Math.ceil("+a+")";break;case "ROUNDDOWN":c="Math.floor("+a+")";break;case "SIN":c="Math.sin("+a+" / 180 * Math.PI)";break;case "COS":c="Math.cos("+a+" / 180 * Math.PI)";break;case "TAN":c="Math.tan("+a+" / 180 * Math.PI)"}if(c)return[c,Blockly.JavaScript.ORDER_FUNCTION_CALL];switch(b){case "LOG10":c="Math.log("+a+ ") / Math.log(10)";break;case "ASIN":c="Math.asin("+a+") / Math.PI * 180";break;case "ACOS":c="Math.acos("+a+") / Math.PI * 180";break;case "ATAN":c="Math.atan("+a+") / Math.PI * 180";break;default:throw"Unknown math operator: "+b;}return[c,Blockly.JavaScript.ORDER_DIVISION]}; Blockly.JavaScript.math_constant=function(a){return{PI:["Math.PI",Blockly.JavaScript.ORDER_MEMBER],E:["Math.E",Blockly.JavaScript.ORDER_MEMBER],GOLDEN_RATIO:["(1 + Math.sqrt(5)) / 2",Blockly.JavaScript.ORDER_DIVISION],SQRT2:["Math.SQRT2",Blockly.JavaScript.ORDER_MEMBER],SQRT1_2:["Math.SQRT1_2",Blockly.JavaScript.ORDER_MEMBER],INFINITY:["Infinity",Blockly.JavaScript.ORDER_ATOMIC]}[a.getFieldValue("CONSTANT")]}; Blockly.JavaScript.math_number_property=function(a){var b=Blockly.JavaScript.valueToCode(a,"NUMBER_TO_CHECK",Blockly.JavaScript.ORDER_MODULUS)||"0",c=a.getFieldValue("PROPERTY"),d;if("PRIME"==c)return[Blockly.JavaScript.provideFunction_("math_isPrime",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(n) {"," // https://en.wikipedia.org/wiki/Primality_test#Naive_methods"," if (n == 2 || n == 3) {"," return true;"," }"," // False if n is NaN, negative, is 1, or not whole."," // And false if n is divisible by 2 or 3.", " if (isNaN(n) || n <= 1 || n % 1 != 0 || n % 2 == 0 || n % 3 == 0) {"," return false;"," }"," // Check all the numbers of form 6k +/- 1, up to sqrt(n)."," for (var x = 6; x <= Math.sqrt(n) + 1; x += 6) {"," if (n % (x - 1) == 0 || n % (x + 1) == 0) {"," return false;"," }"," }"," return true;","}"])+"("+b+")",Blockly.JavaScript.ORDER_FUNCTION_CALL];switch(c){case "EVEN":d=b+" % 2 == 0";break;case "ODD":d=b+" % 2 == 1";break;case "WHOLE":d=b+" % 1 == 0";break;case "POSITIVE":d= b+" > 0";break;case "NEGATIVE":d=b+" < 0";break;case "DIVISIBLE_BY":a=Blockly.JavaScript.valueToCode(a,"DIVISOR",Blockly.JavaScript.ORDER_MODULUS)||"0",d=b+" % "+a+" == 0"}return[d,Blockly.JavaScript.ORDER_EQUALITY]};Blockly.JavaScript.math_change=function(a){var b=Blockly.JavaScript.valueToCode(a,"DELTA",Blockly.JavaScript.ORDER_ADDITION)||"0";a=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE);return a+" = (typeof "+a+" == 'number' ? "+a+" : 0) + "+b+";\n"}; Blockly.JavaScript.math_round=Blockly.JavaScript.math_single;Blockly.JavaScript.math_trig=Blockly.JavaScript.math_single; Blockly.JavaScript.math_on_list=function(a){var b=a.getFieldValue("OP");switch(b){case "SUM":a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_MEMBER)||"[]";a+=".reduce(function(x, y) {return x + y;})";break;case "MIN":a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_COMMA)||"[]";a="Math.min.apply(null, "+a+")";break;case "MAX":a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_COMMA)||"[]";a="Math.max.apply(null, "+a+")";break;case "AVERAGE":b=Blockly.JavaScript.provideFunction_("math_mean", ["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(myList) {"," return myList.reduce(function(x, y) {return x + y;}) / myList.length;","}"]);a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_NONE)||"[]";a=b+"("+a+")";break;case "MEDIAN":b=Blockly.JavaScript.provideFunction_("math_median",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(myList) {"," var localList = myList.filter(function (x) {return typeof x == 'number';});"," if (!localList.length) return null;", " localList.sort(function(a, b) {return b - a;});"," if (localList.length % 2 == 0) {"," return (localList[localList.length / 2 - 1] + localList[localList.length / 2]) / 2;"," } else {"," return localList[(localList.length - 1) / 2];"," }","}"]);a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_NONE)||"[]";a=b+"("+a+")";break;case "MODE":b=Blockly.JavaScript.provideFunction_("math_modes",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(values) {"," var modes = [];", " var counts = [];"," var maxCount = 0;"," for (var i = 0; i < values.length; i++) {"," var value = values[i];"," var found = false;"," var thisCount;"," for (var j = 0; j < counts.length; j++) {"," if (counts[j][0] === value) {"," thisCount = ++counts[j][1];"," found = true;"," break;"," }"," }"," if (!found) {"," counts.push([value, 1]);"," thisCount = 1;"," }"," maxCount = Math.max(thisCount, maxCount);"," }"," for (var j = 0; j < counts.length; j++) {", " if (counts[j][1] == maxCount) {"," modes.push(counts[j][0]);"," }"," }"," return modes;","}"]);a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_NONE)||"[]";a=b+"("+a+")";break;case "STD_DEV":b=Blockly.JavaScript.provideFunction_("math_standard_deviation",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(numbers) {"," var n = numbers.length;"," if (!n) return null;"," var mean = numbers.reduce(function(x, y) {return x + y;}) / n;"," var variance = 0;", " for (var j = 0; j < n; j++) {"," variance += Math.pow(numbers[j] - mean, 2);"," }"," variance = variance / n;"," return Math.sqrt(variance);","}"]);a=Blockly.JavaScript.valueToCode(a,"LIST",Blockly.JavaScript.ORDER_NONE)||"[]";a=b+"("+a+")";break;case "RANDOM":b=Blockly.JavaScript.provideFunction_("math_random_list",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(list) {"," var x = Math.floor(Math.random() * list.length);"," return list[x];","}"]);a=Blockly.JavaScript.valueToCode(a, "LIST",Blockly.JavaScript.ORDER_NONE)||"[]";a=b+"("+a+")";break;default:throw"Unknown operator: "+b;}return[a,Blockly.JavaScript.ORDER_FUNCTION_CALL]};Blockly.JavaScript.math_modulo=function(a){var b=Blockly.JavaScript.valueToCode(a,"DIVIDEND",Blockly.JavaScript.ORDER_MODULUS)||"0";a=Blockly.JavaScript.valueToCode(a,"DIVISOR",Blockly.JavaScript.ORDER_MODULUS)||"0";return[b+" % "+a,Blockly.JavaScript.ORDER_MODULUS]}; Blockly.JavaScript.math_constrain=function(a){var b=Blockly.JavaScript.valueToCode(a,"VALUE",Blockly.JavaScript.ORDER_COMMA)||"0",c=Blockly.JavaScript.valueToCode(a,"LOW",Blockly.JavaScript.ORDER_COMMA)||"0";a=Blockly.JavaScript.valueToCode(a,"HIGH",Blockly.JavaScript.ORDER_COMMA)||"Infinity";return["Math.min(Math.max("+b+", "+c+"), "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]}; Blockly.JavaScript.math_random_int=function(a){var b=Blockly.JavaScript.valueToCode(a,"FROM",Blockly.JavaScript.ORDER_COMMA)||"0";a=Blockly.JavaScript.valueToCode(a,"TO",Blockly.JavaScript.ORDER_COMMA)||"0";return[Blockly.JavaScript.provideFunction_("math_random_int",["function "+Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_+"(a, b) {"," if (a > b) {"," // Swap a and b to ensure a is smaller."," var c = a;"," a = b;"," b = c;"," }"," return Math.floor(Math.random() * (b - a + 1) + a);", "}"])+"("+b+", "+a+")",Blockly.JavaScript.ORDER_FUNCTION_CALL]};Blockly.JavaScript.math_random_float=function(a){return["Math.random()",Blockly.JavaScript.ORDER_FUNCTION_CALL]};Blockly.JavaScript.procedures={}; Blockly.JavaScript.procedures_defreturn=function(a){var b=Blockly.JavaScript.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE),c=Blockly.JavaScript.statementToCode(a,"STACK");Blockly.JavaScript.INFINITE_LOOP_TRAP&&(c=Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+c);var d=Blockly.JavaScript.valueToCode(a,"RETURN",Blockly.JavaScript.ORDER_NONE)||"";d&&(d=" return "+d+";\n");for(var e=[],f=0;f", "lastupdated": "2014-09-01 18:13:57.039117", "locale": "en", "messagedocumentation" : "qqq" }, "VARIABLES_DEFAULT_NAME": "item", "DUPLICATE_BLOCK": "Duplicate", "ADD_COMMENT": "Add Comment", "REMOVE_COMMENT": "Remove Comment", "EXTERNAL_INPUTS": "External Inputs", "INLINE_INPUTS": "Inline Inputs", "DELETE_BLOCK": "Delete Block", "DELETE_X_BLOCKS": "Delete %1 Blocks", "COLLAPSE_BLOCK": "Collapse Block", "COLLAPSE_ALL": "Collapse Blocks", "EXPAND_BLOCK": "Expand Block", "EXPAND_ALL": "Expand Blocks", "DISABLE_BLOCK": "Disable Block", "ENABLE_BLOCK": "Enable Block", "HELP": "Help", "CHAT": "Chat with your collaborator by typing in this box!", "CHANGE_VALUE_TITLE": "Change value:", "NEW_VARIABLE": "New variable...", "NEW_VARIABLE_TITLE": "New variable name:", "RENAME_VARIABLE": "Rename variable...", "RENAME_VARIABLE_TITLE": "Rename all '%1' variables to:", "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Choose a colour from the palette.", "COLOUR_RANDOM_HELPURL": "http://randomcolour.com", "COLOUR_RANDOM_TITLE": "random colour", "COLOUR_RANDOM_TOOLTIP": "Choose a colour at random.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "colour with", "COLOUR_RGB_RED": "red", "COLOUR_RGB_GREEN": "green", "COLOUR_RGB_BLUE": "blue", "COLOUR_RGB_TOOLTIP": "Create a colour with the specified amount of red, green, and blue. All values must be between 0 and 100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "blend", "COLOUR_BLEND_COLOUR1": "colour 1", "COLOUR_BLEND_COLOUR2": "colour 2", "COLOUR_BLEND_RATIO": "ratio", "COLOUR_BLEND_TOOLTIP": "Blends two colours together with a given ratio (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "repeat %1 times", "CONTROLS_REPEAT_TITLE_REPEAT": "repeat", "CONTROLS_REPEAT_TITLE_TIMES": "times", "CONTROLS_REPEAT_INPUT_DO": "do", "CONTROLS_REPEAT_TOOLTIP": "Do some statements several times.", "CONTROLS_WHILEUNTIL_HELPURL": "https://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "repeat while", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "repeat until", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "While a value is true, then do some statements.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "While a value is false, then do some statements.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Have the variable %1 take on the values from the start number to the end number, counting by the specified interval, and do the specified blocks.", "CONTROLS_FOR_INPUT_WITH": "count with", "CONTROLS_FOR_INPUT_FROM_TO_BY": "from %1 to %2 by %3", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each for each block", "CONTROLS_FOREACH_INPUT_ITEM": "for each item", "CONTROLS_FOREACH_INPUT_INLIST": "in list", "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "", "CONTROLS_FOREACH_TOOLTIP": "For each item in a list, set the variable '%1' to the item, and then do some statements.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "break out of loop", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "continue with next iteration of loop", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Break out of the containing loop.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Skip the rest of this loop, and continue with the next iteration.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Warning: This block may only be used within a loop.", "CONTROLS_IF_HELPURL": "https://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "If a value is true, then do some statements.", "CONTROLS_IF_TOOLTIP_2": "If a value is true, then do the first block of statements. Otherwise, do the second block of statements.", "CONTROLS_IF_TOOLTIP_3": "If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements.", "CONTROLS_IF_TOOLTIP_4": "If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements. If none of the values are true, do the last block of statements.", "CONTROLS_IF_MSG_IF": "if", "CONTROLS_IF_MSG_ELSEIF": "else if", "CONTROLS_IF_MSG_ELSE": "else", "CONTROLS_IF_IF_TOOLTIP": "Add, remove, or reorder sections to reconfigure this if block.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Add a condition to the if block.", "CONTROLS_IF_ELSE_TOOLTIP": "Add a final, catch-all condition to the if block.", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "Return true if both inputs equal each other.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Return true if both inputs are not equal to each other.", "LOGIC_COMPARE_TOOLTIP_LT": "Return true if the first input is smaller than the second input.", "LOGIC_COMPARE_TOOLTIP_LTE": "Return true if the first input is smaller than or equal to the second input.", "LOGIC_COMPARE_TOOLTIP_GT": "Return true if the first input is greater than the second input.", "LOGIC_COMPARE_TOOLTIP_GTE": "Return true if the first input is greater than or equal to the second input.", "LOGIC_OPERATION_HELPURL": "https://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Return true if both inputs are true.", "LOGIC_OPERATION_AND": "and", "LOGIC_OPERATION_TOOLTIP_OR": "Return true if at least one of the inputs is true.", "LOGIC_OPERATION_OR": "or", "LOGIC_NEGATE_HELPURL": "https://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "not %1", "LOGIC_NEGATE_TOOLTIP": "Returns true if the input is false. Returns false if the input is true.", "LOGIC_BOOLEAN_HELPURL": "https://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "true", "LOGIC_BOOLEAN_FALSE": "false", "LOGIC_BOOLEAN_TOOLTIP": "Returns either true or false.", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "null", "LOGIC_NULL_TOOLTIP": "Returns null.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "if true", "LOGIC_TERNARY_IF_FALSE": "if false", "LOGIC_TERNARY_TOOLTIP": "Check the condition in 'test'. If the condition is true, returns the 'if true' value; otherwise returns the 'if false' value.", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "A number.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "×", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "asin", "MATH_TRIG_ACOS": "acos", "MATH_TRIG_ATAN": "atan", "MATH_ARITHMETIC_HELPURL": "https://en.wikipedia.org/wiki/Arithmetic", "MATH_ARITHMETIC_TOOLTIP_ADD": "Return the sum of the two numbers.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Return the difference of the two numbers.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Return the product of the two numbers.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Return the quotient of the two numbers.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Return the first number raised to the power of the second number.", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "square root", "MATH_SINGLE_TOOLTIP_ROOT": "Return the square root of a number.", "MATH_SINGLE_OP_ABSOLUTE": "absolute", "MATH_SINGLE_TOOLTIP_ABS": "Return the absolute value of a number.", "MATH_SINGLE_TOOLTIP_NEG": "Return the negation of a number.", "MATH_SINGLE_TOOLTIP_LN": "Return the natural logarithm of a number.", "MATH_SINGLE_TOOLTIP_LOG10": "Return the base 10 logarithm of a number.", "MATH_SINGLE_TOOLTIP_EXP": "Return e to the power of a number.", "MATH_SINGLE_TOOLTIP_POW10": "Return 10 to the power of a number.", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "Return the sine of a degree (not radian).", "MATH_TRIG_TOOLTIP_COS": "Return the cosine of a degree (not radian).", "MATH_TRIG_TOOLTIP_TAN": "Return the tangent of a degree (not radian).", "MATH_TRIG_TOOLTIP_ASIN": "Return the arcsine of a number.", "MATH_TRIG_TOOLTIP_ACOS": "Return the arccosine of a number.", "MATH_TRIG_TOOLTIP_ATAN": "Return the arctangent of a number.", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "Return one of the common constants: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (infinity).", "MATH_IS_EVEN": "is even", "MATH_IS_ODD": "is odd", "MATH_IS_PRIME": "is prime", "MATH_IS_WHOLE": "is whole", "MATH_IS_POSITIVE": "is positive", "MATH_IS_NEGATIVE": "is negative", "MATH_IS_DIVISIBLE_BY": "is divisible by", "MATH_IS_TOOLTIP": "Check if a number is an even, odd, prime, whole, positive, negative, or if it is divisible by certain number. Returns true or false.", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "change", "MATH_CHANGE_INPUT_BY": "by", "MATH_CHANGE_TOOLTIP": "Add a number to variable '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Round a number up or down.", "MATH_ROUND_OPERATOR_ROUND": "round", "MATH_ROUND_OPERATOR_ROUNDUP": "round up", "MATH_ROUND_OPERATOR_ROUNDDOWN": "round down", "MATH_ONLIST_HELPURL": "", "MATH_ONLIST_OPERATOR_SUM": "sum of list", "MATH_ONLIST_TOOLTIP_SUM": "Return the sum of all the numbers in the list.", "MATH_ONLIST_OPERATOR_MIN": "min of list", "MATH_ONLIST_TOOLTIP_MIN": "Return the smallest number in the list.", "MATH_ONLIST_OPERATOR_MAX": "max of list", "MATH_ONLIST_TOOLTIP_MAX": "Return the largest number in the list.", "MATH_ONLIST_OPERATOR_AVERAGE": "average of list", "MATH_ONLIST_TOOLTIP_AVERAGE": "Return the average (arithmetic mean) of the numeric values in the list.", "MATH_ONLIST_OPERATOR_MEDIAN": "median of list", "MATH_ONLIST_TOOLTIP_MEDIAN": "Return the median number in the list.", "MATH_ONLIST_OPERATOR_MODE": "modes of list", "MATH_ONLIST_TOOLTIP_MODE": "Return a list of the most common item(s) in the list.", "MATH_ONLIST_OPERATOR_STD_DEV": "standard deviation of list", "MATH_ONLIST_TOOLTIP_STD_DEV": "Return the standard deviation of the list.", "MATH_ONLIST_OPERATOR_RANDOM": "random item of list", "MATH_ONLIST_TOOLTIP_RANDOM": "Return a random element from the list.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "remainder of %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Return the remainder from dividing the two numbers.", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "constrain %1 low %2 high %3", "MATH_CONSTRAIN_TOOLTIP": "Constrain a number to be between the specified limits (inclusive).", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "random integer from %1 to %2", "MATH_RANDOM_INT_TOOLTIP": "Return a random integer between the two specified limits, inclusive.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "random fraction", "MATH_RANDOM_FLOAT_TOOLTIP": "Return a random fraction between 0.0 (inclusive) and 1.0 (exclusive).", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "A letter, word, or line of text.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "create text with", "TEXT_JOIN_TOOLTIP": "Create a piece of text by joining together any number of items.", "TEXT_CREATE_JOIN_TITLE_JOIN": "join", "TEXT_CREATE_JOIN_TOOLTIP": "Add, remove, or reorder sections to reconfigure this text block.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Add an item to the text.", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "to", "TEXT_APPEND_APPENDTEXT": "append text", "TEXT_APPEND_TOOLTIP": "Append some text to variable '%1'.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "length of %1", "TEXT_LENGTH_TOOLTIP": "Returns the number of letters (including spaces) in the provided text.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 is empty", "TEXT_ISEMPTY_TOOLTIP": "Returns true if the provided text is empty.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Returns the index of the first/last occurrence of first text in the second text. Returns 0 if text is not found.", "TEXT_INDEXOF_INPUT_INTEXT": "in text", "TEXT_INDEXOF_OPERATOR_FIRST": "find first occurrence of text", "TEXT_INDEXOF_OPERATOR_LAST": "find last occurrence of text", "TEXT_INDEXOF_TAIL": "", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "in text", "TEXT_CHARAT_FROM_START": "get letter #", "TEXT_CHARAT_FROM_END": "get letter # from end", "TEXT_CHARAT_FIRST": "get first letter", "TEXT_CHARAT_LAST": "get last letter", "TEXT_CHARAT_RANDOM": "get random letter", "TEXT_CHARAT_TAIL": "", "TEXT_CHARAT_TOOLTIP": "Returns the letter at the specified position.", "TEXT_GET_SUBSTRING_TOOLTIP": "Returns a specified portion of the text.", "TEXT_GET_SUBSTRING_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "in text", "TEXT_GET_SUBSTRING_START_FROM_START": "get substring from letter #", "TEXT_GET_SUBSTRING_START_FROM_END": "get substring from letter # from end", "TEXT_GET_SUBSTRING_START_FIRST": "get substring from first letter", "TEXT_GET_SUBSTRING_END_FROM_START": "to letter #", "TEXT_GET_SUBSTRING_END_FROM_END": "to letter # from end", "TEXT_GET_SUBSTRING_END_LAST": "to last letter", "TEXT_GET_SUBSTRING_TAIL": "", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Return a copy of the text in a different case.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "to UPPER CASE", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "to lower case", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "to Title Case", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Return a copy of the text with spaces removed from one or both ends.", "TEXT_TRIM_OPERATOR_BOTH": "trim spaces from both sides of", "TEXT_TRIM_OPERATOR_LEFT": "trim spaces from left side of", "TEXT_TRIM_OPERATOR_RIGHT": "trim spaces from right side of", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "print %1", "TEXT_PRINT_TOOLTIP": "Print the specified text, number or other value.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "prompt for text with message", "TEXT_PROMPT_TYPE_NUMBER": "prompt for number with message", "TEXT_PROMPT_TOOLTIP_NUMBER": "Prompt for user for a number.", "TEXT_PROMPT_TOOLTIP_TEXT": "Prompt for user for some text.", "LISTS_CREATE_EMPTY_HELPURL": "https://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "create empty list", "LISTS_CREATE_EMPTY_TOOLTIP": "Returns a list, of length 0, containing no data records", "LISTS_CREATE_WITH_TOOLTIP": "Create a list with any number of items.", "LISTS_CREATE_WITH_INPUT_WITH": "create list with", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "list", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Add, remove, or reorder sections to reconfigure this list block.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Add an item to the list.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "Creates a list consisting of the given value repeated the specified number of times.", "LISTS_REPEAT_TITLE": "create list with item %1 repeated %2 times", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "length of %1", "LISTS_LENGTH_TOOLTIP": "Returns the length of a list.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 is empty", "LISTS_TOOLTIP": "Returns true if the list is empty.", "LISTS_INLIST": "in list", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "find first occurrence of item", "LISTS_INDEX_OF_LAST": "find last occurrence of item", "LISTS_INDEX_OF_TOOLTIP": "Returns the index of the first/last occurrence of the item in the list. Returns 0 if text is not found.", "LISTS_GET_INDEX_GET": "get", "LISTS_GET_INDEX_GET_REMOVE": "get and remove", "LISTS_GET_INDEX_REMOVE": "remove", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# from end", "LISTS_GET_INDEX_FIRST": "first", "LISTS_GET_INDEX_LAST": "last", "LISTS_GET_INDEX_RANDOM": "random", "LISTS_GET_INDEX_TAIL": "", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Returns the item at the specified position in a list. #1 is the first item.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Returns the item at the specified position in a list. #1 is the last item.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Returns the first item in a list.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Returns the last item in a list.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Returns a random item in a list.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Removes and returns the item at the specified position in a list. #1 is the first item.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Removes and returns the item at the specified position in a list. #1 is the last item.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Removes and returns the first item in a list.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Removes and returns the last item in a list.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Removes and returns a random item in a list.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Removes the item at the specified position in a list. #1 is the first item.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Removes the item at the specified position in a list. #1 is the last item.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Removes the first item in a list.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Removes the last item in a list.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Removes a random item in a list.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "set", "LISTS_SET_INDEX_INSERT": "insert at", "LISTS_SET_INDEX_INPUT_TO": "as", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Sets the item at the specified position in a list. #1 is the first item.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Sets the item at the specified position in a list. #1 is the last item.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Sets the first item in a list.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Sets the last item in a list.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Sets a random item in a list.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Inserts the item at the specified position in a list. #1 is the first item.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Inserts the item at the specified position in a list. #1 is the last item.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Inserts the item at the start of a list.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Append the item to the end of a list.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Inserts the item randomly in a list.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "get sub-list from #", "LISTS_GET_SUBLIST_START_FROM_END": "get sub-list from # from end", "LISTS_GET_SUBLIST_START_FIRST": "get sub-list from first", "LISTS_GET_SUBLIST_END_FROM_START": "to #", "LISTS_GET_SUBLIST_END_FROM_END": "to # from end", "LISTS_GET_SUBLIST_END_LAST": "to last", "LISTS_GET_SUBLIST_TAIL": "", "LISTS_GET_SUBLIST_TOOLTIP": "Creates a copy of the specified portion of a list.", "ORDINAL_NUMBER_SUFFIX": "", "VARIABLES_GET_HELPURL": "https://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TITLE": "", "VARIABLES_GET_TAIL": "", "VARIABLES_GET_TOOLTIP": "Returns the value of this variable.", "VARIABLES_GET_CREATE_SET": "Create 'set %1'", "VARIABLES_SET_HELPURL": "https://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "set", "VARIABLES_SET_TAIL": "to", "VARIABLES_SET_TOOLTIP": "Sets this variable to be equal to the input.", "VARIABLES_SET_CREATE_GET": "Create 'get %1'", "PROCEDURES_DEFNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFNORETURN_TITLE": "to", "PROCEDURES_DEFNORETURN_PROCEDURE": "do something", "PROCEDURES_BEFORE_PARAMS": "with:", "PROCEDURES_DEFNORETURN_DO": "", "PROCEDURES_DEFNORETURN_TOOLTIP": "Creates a function with no output.", "PROCEDURES_DEFRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFRETURN_RETURN": "return", "PROCEDURES_DEFRETURN_TOOLTIP": "Creates a function with an output.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Warning: This function has duplicate parameters.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_CALL": "", "PROCEDURES_CALLNORETURN_TOOLTIP": "Run the user-defined function '%1'.", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Run the user-defined function '%1' and use its output.", "PROCEDURES_MUTATORCONTAINER_TITLE": "inputs", "PROCEDURES_MUTATORARG_TITLE": "input name:", "PROCEDURES_HIGHLIGHT_DEF": "Highlight function definition", "PROCEDURES_CREATE_DO": "Create '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "If a value is true, then return a second value.", "PROCEDURES_IFRETURN_WARNING": "Warning: This block may be used only within a function definition.", "CONTEXT_BLOCK_COPY": "Copy", "CONTEXT_BLOCK_PASTE": "Paste" } ================================================ FILE: extern/blockly/msg/json/es.json ================================================ { "@metadata": { "authors": [ "Fitoschido", "VegaDark", "WeSiToS" ] }, "VARIABLES_DEFAULT_NAME": "elemento", "DUPLICATE_BLOCK": "Duplicar", "ADD_COMMENT": "Añadir comentario", "REMOVE_COMMENT": "Eliminar comentario", "EXTERNAL_INPUTS": "Entradas externas", "INLINE_INPUTS": "Entradas en línea", "DELETE_BLOCK": "Eliminar bloque", "DELETE_X_BLOCKS": "Eliminar %1 bloques", "COLLAPSE_BLOCK": "Contraer bloque", "COLLAPSE_ALL": "Contraer bloques", "EXPAND_BLOCK": "Expandir bloque", "EXPAND_ALL": "Expandir bloques", "DISABLE_BLOCK": "Desactivr bloque", "ENABLE_BLOCK": "Activar bloque", "HELP": "Ayuda", "CHANGE_VALUE_TITLE": "Cambiar el valor:", "NEW_VARIABLE": "Variable nueva…", "NEW_VARIABLE_TITLE": "Nombre de variable nueva:", "RENAME_VARIABLE": "Renombrar la variable…", "RENAME_VARIABLE_TITLE": "Renombrar todas las variables «%1» a:", "COLOUR_PICKER_HELPURL": "https://es.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Elige un color de la paleta.", "COLOUR_RANDOM_TITLE": "color aleatorio", "COLOUR_RANDOM_TOOLTIP": "Elige un color al azar.", "COLOUR_RGB_TITLE": "color con", "COLOUR_RGB_RED": "rojo", "COLOUR_RGB_GREEN": "verde", "COLOUR_RGB_BLUE": "azul", "COLOUR_RGB_TOOLTIP": "Crea un color con cantidades específicas de rojo, verde y azul. Todos los valores deben encontrarse entre 0 y 100.", "COLOUR_BLEND_TITLE": "combinar", "COLOUR_BLEND_COLOUR1": "color 1", "COLOUR_BLEND_COLOUR2": "color 2", "COLOUR_BLEND_RATIO": "razón", "COLOUR_BLEND_TOOLTIP": "Combina dos colores con una proporción determinada (0,0–1,0).", "CONTROLS_REPEAT_HELPURL": "https://es.wikipedia.org/wiki/Bucle_for", "CONTROLS_REPEAT_TITLE": "repetir %1 veces", "CONTROLS_REPEAT_TITLE_REPEAT": "repetir", "CONTROLS_REPEAT_TITLE_TIMES": "veces", "CONTROLS_REPEAT_INPUT_DO": "haz", "CONTROLS_REPEAT_TOOLTIP": "Hacer algunas declaraciones varias veces.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "repetir mientras", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "repetir hasta", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Mientras que un valor es verdadero, entonces hacer algunas declaraciones.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Mientras que un valor es falso, entonces hacer algunas declaraciones.", "CONTROLS_FOR_TOOLTIP": "Tiene la variable %1 que toma los valores desde el número de inicio hasta el número final, contando por el intervalo especificado, y hacer los bloques especificados.", "CONTROLS_FOR_INPUT_WITH": "contar con", "CONTROLS_FOR_INPUT_FROM_TO_BY": "de %1 a %2 por %3", "CONTROLS_FOREACH_INPUT_ITEM": "para cada elemento", "CONTROLS_FOREACH_INPUT_INLIST": "en la lista", "CONTROLS_FOREACH_TOOLTIP": "Para cada elemento en una lista, establece la variable '%1' en el elemento y luego hacer algunas declaraciones.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "romper el bucle", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "continuar con la siguiente iteración del bucle", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Rompe el que contiene el bucle.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Saltar el resto de este bucle, y continuar con la siguiente iteración.", "CONTROLS_FLOW_STATEMENTS_WARNING": "ADVERTENCIA: Este bloque puede usarse sólo dentro de un bucle.", "CONTROLS_IF_TOOLTIP_1": "Si un valor es verdadero, entonces hacer algunas declaraciones.", "CONTROLS_IF_TOOLTIP_2": "Si un valor es verdadero, entonces hacer el primer bloque de declaraciones. De lo contrario, hacer el segundo bloque de declaraciones.", "CONTROLS_IF_TOOLTIP_3": "Si el primer valor es verdadero, entonces hacer el primer bloque de declaraciones. De lo contrario, si el segundo valor es verdadero, hacer el segundo bloque de declaraciones.", "CONTROLS_IF_TOOLTIP_4": "Si el primer valor es verdadero, entonces hacer el primer bloque de declaraciones. De lo contrario, si el segundo valor es verdadero, hacer el segundo bloque de declaraciones. Si ninguno de los valores son verdaderos, hacer el último bloque de declaraciones.", "CONTROLS_IF_MSG_IF": "si", "CONTROLS_IF_MSG_ELSEIF": "o si", "CONTROLS_IF_MSG_ELSE": "sino", "CONTROLS_IF_IF_TOOLTIP": "Agregar, eliminar o reordenar las secciones para reconfigurar este bloque.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Agregar una condición a este bloque.", "CONTROLS_IF_ELSE_TOOLTIP": "Agregar una condición general final a este bloque.", "LOGIC_COMPARE_HELPURL": "https://es.wikipedia.org/wiki/Desigualdad_matemática", "LOGIC_COMPARE_TOOLTIP_EQ": "Devolver verdadero si ambas entradas igualan unas a otras.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Devolver verdadero si ambas entradas no son iguales entre sí.", "LOGIC_COMPARE_TOOLTIP_LT": "Devolver verdadero si la primera entrada es menor que la segunda entrada.", "LOGIC_COMPARE_TOOLTIP_LTE": "Devolver verdadero si la primera entrada es menor que o igual a la segunda entrada.", "LOGIC_COMPARE_TOOLTIP_GT": "Devolver verdadero si la primera entrada es mayor que la segunda entrada.", "LOGIC_COMPARE_TOOLTIP_GTE": "Devolver verdadero si la primera entrada es mayor o igual a la segunda entrada.", "LOGIC_OPERATION_TOOLTIP_AND": "Devolver verdadero si ambas entradas son verdaderas.", "LOGIC_OPERATION_AND": "y", "LOGIC_OPERATION_TOOLTIP_OR": "Devolver verdadero si al menos una de las entradas es verdadera.", "LOGIC_OPERATION_OR": "o", "LOGIC_NEGATE_TITLE": "no %1", "LOGIC_NEGATE_TOOLTIP": "Devolver verdadero si la entrada es falsa. Devolver falso si la entrada es verdadera.", "LOGIC_BOOLEAN_TRUE": "verdadero", "LOGIC_BOOLEAN_FALSE": "falso", "LOGIC_BOOLEAN_TOOLTIP": "Devuelve «verdadero» o «falso».", "LOGIC_NULL": "nulo", "LOGIC_NULL_TOOLTIP": "Devuelve «nulo».", "LOGIC_TERNARY_CONDITION": "prueba", "LOGIC_TERNARY_IF_TRUE": "si es verdadero", "LOGIC_TERNARY_IF_FALSE": "si es falso", "LOGIC_TERNARY_TOOLTIP": "Comprobar la condición en \"probar\". Si la condición es verdadera, devolver el valor \"si es cierto\"; de lo contrario, devolver el valor \"si es falso\".", "MATH_NUMBER_HELPURL": "https://es.wikipedia.org/wiki/Número", "MATH_NUMBER_TOOLTIP": "Un número.", "MATH_ARITHMETIC_HELPURL": "https://es.wikipedia.org/wiki/Aritmética", "MATH_ARITHMETIC_TOOLTIP_ADD": "Devuelve la suma de ambos numeros.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Devuelve la diferencia de ambos números.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Devuelve el producto de ambos números.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Devuelve el cociente de ambos números.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Devuelve el primer número elevado a la potencia del segundo.", "MATH_SINGLE_HELPURL": "https://es.wikipedia.org/wiki/Ra%C3%ADz_cuadrada", "MATH_SINGLE_OP_ROOT": "raíz cuadrada", "MATH_SINGLE_TOOLTIP_ROOT": "Devuelve la raíz cuadrada de un número.", "MATH_SINGLE_OP_ABSOLUTE": "absoluto", "MATH_SINGLE_TOOLTIP_ABS": "Devuelve el valor absoluto de un número.", "MATH_SINGLE_TOOLTIP_NEG": "Devolver la negación de un número.", "MATH_SINGLE_TOOLTIP_LN": "Devuelve el logaritmo natural de un número.", "MATH_SINGLE_TOOLTIP_LOG10": "Devuelve el logaritmo base 10 de un número.", "MATH_SINGLE_TOOLTIP_EXP": "Devuelve e a la potencia de un número.", "MATH_SINGLE_TOOLTIP_POW10": "Devuelve 10 a la potencia de un número.", "MATH_TRIG_HELPURL": "https://es.wikipedia.org/wiki/Función_trigonométrica", "MATH_TRIG_TOOLTIP_SIN": "Devolver el seno de un grado (no radián).", "MATH_TRIG_TOOLTIP_COS": "Devolver el coseno de un grado (no radián).", "MATH_TRIG_TOOLTIP_TAN": "Devolver la tangente de un grado (no radián).", "MATH_TRIG_TOOLTIP_ASIN": "Devolver el arcoseno de un número.", "MATH_TRIG_TOOLTIP_ACOS": "Devolver el arcocoseno de un número.", "MATH_TRIG_TOOLTIP_ATAN": "Devolver el arcotangente de un número.", "MATH_CONSTANT_HELPURL": "https://es.wikipedia.org/wiki/Anexo:Constantes_matemáticas", "MATH_CONSTANT_TOOLTIP": "Devolver una de las constantes comunes: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), o ∞ (infinito).", "MATH_IS_EVEN": "es par", "MATH_IS_ODD": "es impar", "MATH_IS_PRIME": "es primo", "MATH_IS_WHOLE": "es entero", "MATH_IS_POSITIVE": "es positivo", "MATH_IS_NEGATIVE": "es negativo", "MATH_IS_DIVISIBLE_BY": "es divisible por", "MATH_IS_TOOLTIP": "Comprobar si un número es par, impar, primo, entero, positivo, negativo, o si es divisible por un número determinado. Devuelve verdadero o falso.", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "cambiar", "MATH_CHANGE_INPUT_BY": "por", "MATH_CHANGE_TOOLTIP": "Añadir un número a la variable «%1».", "MATH_ROUND_HELPURL": "https://es.wikipedia.org/wiki/Redondeo", "MATH_ROUND_TOOLTIP": "Redondear un número hacia arriba o hacia abajo.", "MATH_ROUND_OPERATOR_ROUND": "redondear", "MATH_ROUND_OPERATOR_ROUNDUP": "redondear más", "MATH_ROUND_OPERATOR_ROUNDDOWN": "redondear menos", "MATH_ONLIST_OPERATOR_SUM": "suma de la lista", "MATH_ONLIST_TOOLTIP_SUM": "Devolver la suma de todos los números en la lista.", "MATH_ONLIST_OPERATOR_MIN": "min de la lista", "MATH_ONLIST_TOOLTIP_MIN": "Devolver el número más pequeño en la lista.", "MATH_ONLIST_OPERATOR_MAX": "max de la lista", "MATH_ONLIST_TOOLTIP_MAX": "Devolver el número más grande en la lista.", "MATH_ONLIST_OPERATOR_AVERAGE": "promedio de la lista", "MATH_ONLIST_TOOLTIP_AVERAGE": "Devolver el promedio (media aritmética) de los valores numéricos en la lista.", "MATH_ONLIST_OPERATOR_MEDIAN": "mediana de lista", "MATH_ONLIST_TOOLTIP_MEDIAN": "Devolver la mediana en la lista.", "MATH_ONLIST_OPERATOR_MODE": "modos de la lista", "MATH_ONLIST_TOOLTIP_MODE": "Devolver una lista de los elementos más comunes en la lista.", "MATH_ONLIST_OPERATOR_STD_DEV": "desviación estándar de la lista", "MATH_ONLIST_TOOLTIP_STD_DEV": "Devolver la desviación estándar de la lista.", "MATH_ONLIST_OPERATOR_RANDOM": "elemento aleatorio de la lista", "MATH_ONLIST_TOOLTIP_RANDOM": "Devolver un elemento aleatorio de la lista.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "resultado de %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Devolver el resultado al dividir los dos números.", "MATH_CONSTRAIN_TITLE": "limitar %1 bajo %2 alto %3", "MATH_CONSTRAIN_TOOLTIP": "Limitar un número entre los límites especificados (inclusive).", "MATH_RANDOM_INT_HELPURL": "https://es.wikipedia.org/wiki/Generador_de_números_aleatorios", "MATH_RANDOM_INT_TITLE": "entero aleatorio de %1 a %2", "MATH_RANDOM_INT_TOOLTIP": "Devolver un entero aleatorio entre los dos límites especificados, inclusive.", "MATH_RANDOM_FLOAT_HELPURL": "https://es.wikipedia.org/wiki/Generador_de_números_aleatorios", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "fracción aleatoria", "MATH_RANDOM_FLOAT_TOOLTIP": "Devolver una fracción aleatoria entre 0,0 (ambos inclusive) y 1.0 (exclusivo).", "TEXT_TEXT_HELPURL": "https://es.wikipedia.org/wiki/Cadena_de_caracteres", "TEXT_TEXT_TOOLTIP": "Una letra, palabra o línea de texto.", "TEXT_JOIN_TITLE_CREATEWITH": "crear texto con", "TEXT_JOIN_TOOLTIP": "Crear un fragmento de texto al unir cualquier número de elementos.", "TEXT_CREATE_JOIN_TITLE_JOIN": "unir", "TEXT_CREATE_JOIN_TOOLTIP": "Agregar, eliminar o reordenar las secciones para reconfigurar este bloque de texto.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Agregar un elemento al texto.", "TEXT_APPEND_TO": "a", "TEXT_APPEND_APPENDTEXT": "añadir texto", "TEXT_APPEND_TOOLTIP": "Añadir texto a la variable '%1'.", "TEXT_LENGTH_TITLE": "longitud de %1", "TEXT_LENGTH_TOOLTIP": "Devuelve el número de letras (incluyendo espacios) en el texto proporcionado.", "TEXT_ISEMPTY_TITLE": "%1 está vacío", "TEXT_ISEMPTY_TOOLTIP": "Devuelve verdadero si el texto proporcionado está vacío.", "TEXT_INDEXOF_TOOLTIP": "Devuelve el índice de la primera/última aparición del primer texto en el segundo texto. Devuelve 0 si el texto no se encuentra.", "TEXT_INDEXOF_INPUT_INTEXT": "en el texto", "TEXT_INDEXOF_OPERATOR_FIRST": "encontrar la primera aparición del texto", "TEXT_INDEXOF_OPERATOR_LAST": "encontrar la última aparición del texto", "TEXT_CHARAT_INPUT_INTEXT": "en el texto", "TEXT_CHARAT_FROM_START": "obtener la letra #", "TEXT_CHARAT_FROM_END": "obtener la letra # del final", "TEXT_CHARAT_FIRST": "obtener la primera letra", "TEXT_CHARAT_LAST": "obtener la última letra", "TEXT_CHARAT_RANDOM": "obtener letra aleatoria", "TEXT_CHARAT_TOOLTIP": "Devuelve la letra a la posición especificada.", "TEXT_GET_SUBSTRING_TOOLTIP": "Devuelve una porción determinada del texto.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "en el texto", "TEXT_GET_SUBSTRING_START_FROM_START": "obtener subcadena de la letra #", "TEXT_GET_SUBSTRING_START_FROM_END": "obtener subcadena de la letra # del final", "TEXT_GET_SUBSTRING_START_FIRST": "obtener subcadena de la primera letra", "TEXT_GET_SUBSTRING_END_FROM_START": "a la letra #", "TEXT_GET_SUBSTRING_END_FROM_END": "a la letra # del final", "TEXT_GET_SUBSTRING_END_LAST": "a la última letra", "TEXT_CHANGECASE_TOOLTIP": "Devuelve una copia del texto en un caso diferente.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "a mayúsculas", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "a minúsculas", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "a mayúsculas cada palabra", "TEXT_TRIM_TOOLTIP": "Devuelve una copia del texto con espacios retirados de uno o ambos extremos.", "TEXT_TRIM_OPERATOR_BOTH": "quitar espacios de ambos lados de", "TEXT_TRIM_OPERATOR_LEFT": "quitar espacios al inicio de", "TEXT_TRIM_OPERATOR_RIGHT": "quitar espacios al final de", "TEXT_PRINT_TITLE": "imprimir %1", "TEXT_PRINT_TOOLTIP": "Imprimir el texto especificado, número u otro valor.", "TEXT_PROMPT_TYPE_TEXT": "solicitar el texto con el mensaje", "TEXT_PROMPT_TYPE_NUMBER": "solicitar el número con el mensaje", "TEXT_PROMPT_TOOLTIP_NUMBER": "Solicitar al usuario por un número.", "TEXT_PROMPT_TOOLTIP_TEXT": "Solicitar al usuario por un texto.", "LISTS_CREATE_EMPTY_TITLE": "crear lista vacía", "LISTS_CREATE_EMPTY_TOOLTIP": "Devuelve una lista, de longitud de 0, que no contenga ningún registro de datos", "LISTS_CREATE_WITH_TOOLTIP": "Crear una lista con cualquier número de elementos.", "LISTS_CREATE_WITH_INPUT_WITH": "crear lista con", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "lista", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Agregar, eliminar o reorganizar las secciones para reconfigurar esta lista de bloques.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Agregar un elemento a la lista.", "LISTS_REPEAT_TOOLTIP": "Crea una lista que consta de un valor dado repetido el número de veces especificado.", "LISTS_REPEAT_TITLE": "crear lista con el elemento %1 repetido %2 veces", "LISTS_LENGTH_TITLE": "longitud de %1", "LISTS_LENGTH_TOOLTIP": "Devuelve la longitud de una lista.", "LISTS_IS_EMPTY_TITLE": "%1 está vacío", "LISTS_TOOLTIP": "Devuelve verdadero si la lista está vacía.", "LISTS_INLIST": "en la lista", "LISTS_INDEX_OF_FIRST": "encontrar la primera aparición del elemento", "LISTS_INDEX_OF_LAST": "encontrar la última aparición del elemento", "LISTS_INDEX_OF_TOOLTIP": "Devuelve el índice de la primera/última aparición del elemento en la lista. Devuelve 0 si el texto no se encuentra.", "LISTS_GET_INDEX_GET": "obtener", "LISTS_GET_INDEX_GET_REMOVE": "obtener y retirar", "LISTS_GET_INDEX_REMOVE": "eliminar", "LISTS_GET_INDEX_FROM_END": "# del final", "LISTS_GET_INDEX_FIRST": "primero", "LISTS_GET_INDEX_LAST": "último", "LISTS_GET_INDEX_RANDOM": "aleatorio", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Devuelve el elemento a la posición especificada en la lista. #1 es el primer elemento.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Devuelve el elemento a la posición especificada en la lista. #1 es el último elemento.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Devuelve el primer elemento de una lista.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Devuelve el último elemento de una lista.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Devuelve un elemento aleatorio en una lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Elimina y devuelve el elemento a la posición especificada en la lista. #1 es el primer elemento.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Elimina y devuelve el elemento a la posición especificada en la lista. #1 es el último elemento.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Elimina y devuelve el primer elemento de una lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Elimina y devuelve el último elemento de una lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Elimina y devuelve un elemento aleatorio en una lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Elimina el elemento a la posición especificada en la lista. #1 es el primer elemento.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Elimina el elemento a la posición especificada en la lista. #1 es el último elemento.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Elimina el primer elemento de una lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Elimina el último elemento de una lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Elimina un elemento aleatorio en una lista.", "LISTS_SET_INDEX_SET": "establece", "LISTS_SET_INDEX_INSERT": "inserta en", "LISTS_SET_INDEX_INPUT_TO": "como", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Establece el elemento a la posición especificada en una lista. #1 es el primer elemento.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Establece el elemento a la posición especificada en una lista. #1 es el último elemento.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Establece el primer elemento de una lista.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Establece el último elemento de una lista.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Establece un elemento aleatorio en una lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Inserta el elemento a la posición especificada en la lista. #1 es el primer elemento.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Inserta el elemento a la posición especificada en la lista. #1 es el último elemento.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Inserta el elemento al inicio de una lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Añade el elemento al final de una lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Inserta el elemento aleatoriamente en una lista.", "LISTS_GET_SUBLIST_START_FROM_START": "obtener sub-lista de #", "LISTS_GET_SUBLIST_START_FROM_END": "obtener sub-lista de # del final", "LISTS_GET_SUBLIST_START_FIRST": "obtener sub-lista del primero", "LISTS_GET_SUBLIST_END_FROM_START": "a #", "LISTS_GET_SUBLIST_END_FROM_END": "a # del final", "LISTS_GET_SUBLIST_END_LAST": "a la última", "LISTS_GET_SUBLIST_TOOLTIP": "Crea una copia de la parte especificada de una lista.", "VARIABLES_GET_TOOLTIP": "Devuelve el valor de esta variable.", "VARIABLES_GET_CREATE_SET": "Crear 'set %1'", "VARIABLES_SET_TITLE": "establece", "VARIABLES_SET_TAIL": "a", "VARIABLES_SET_TOOLTIP": "Establece esta variable para que sea igual a la entrada.", "VARIABLES_SET_CREATE_GET": "Crear 'obtener %1'", "PROCEDURES_DEFNORETURN_TITLE": "a", "PROCEDURES_DEFNORETURN_PROCEDURE": "hacer algo", "PROCEDURES_BEFORE_PARAMS": "con:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Crea una función sin salida.", "PROCEDURES_DEFRETURN_RETURN": "devuelve", "PROCEDURES_DEFRETURN_TOOLTIP": "Crea una función con una salida.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Advertencia: Esta función tiene parámetros duplicados.", "PROCEDURES_CALLNORETURN_HELPURL": "https://es.wikipedia.org/wiki/Subrutina", "PROCEDURES_CALLNORETURN_TOOLTIP": "Ejecuta la función definida por el usuario '%1'.", "PROCEDURES_CALLRETURN_HELPURL": "https://es.wikipedia.org/wiki/Subrutina", "PROCEDURES_CALLRETURN_TOOLTIP": "Ejecuta la función definida por el usuario '%1' y usar su salida.", "PROCEDURES_MUTATORCONTAINER_TITLE": "entradas", "PROCEDURES_MUTATORARG_TITLE": "nombre de entrada:", "PROCEDURES_HIGHLIGHT_DEF": "Destacar definición de la función", "PROCEDURES_CREATE_DO": "Crear '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Si el valor es verdadero, entonces devuelve un segundo valor.", "PROCEDURES_IFRETURN_WARNING": "Advertencia: Este bloque solo puede ser utilizado dentro de la definición de una función." } ================================================ FILE: extern/blockly/msg/json/fa.json ================================================ { "@metadata": { "authors": [ "Ebraminio", "Reza1615" ] }, "VARIABLES_DEFAULT_NAME": "مورد", "DUPLICATE_BLOCK": "تکراری", "ADD_COMMENT": "افزودن نظر", "REMOVE_COMMENT": "حذف نظر", "EXTERNAL_INPUTS": "ورودی‌های خارجی", "INLINE_INPUTS": "ورودی‌های درون خطی", "DELETE_BLOCK": "حذف بلوک", "DELETE_X_BLOCKS": "حذف بلوک‌های %1", "COLLAPSE_BLOCK": "فروپاشی بلوک", "COLLAPSE_ALL": "فروپاشی بلوک‌ها", "EXPAND_BLOCK": "گسترش بلوک", "EXPAND_ALL": "گسترش بلوک‌ها", "DISABLE_BLOCK": "غیرفعال‌سازی بلوک", "ENABLE_BLOCK": "فعال‌سازی بلوک", "HELP": "راهنما", "CHANGE_VALUE_TITLE": "تغییر مقدار:", "NEW_VARIABLE": "متغیر جدید...", "NEW_VARIABLE_TITLE": "نام متغیر جدید:", "RENAME_VARIABLE": "تغییر نام متغیر...", "RENAME_VARIABLE_TITLE": "تغییر نام همهٔ متغیرهای «%1» به:", "COLOUR_PICKER_HELPURL": "https://fa.wikipedia.org/wiki/%D8%B1%D9%86%DA%AF", "COLOUR_PICKER_TOOLTIP": "انتخاب یک رنگ از تخته‌رنگ.", "COLOUR_RANDOM_TITLE": "رنگ تصادفی", "COLOUR_RANDOM_TOOLTIP": "انتخاب یک رنگ به شکل تصادفی.", "COLOUR_RGB_TITLE": "رنگ با", "COLOUR_RGB_RED": "قرمز", "COLOUR_RGB_GREEN": "سبز", "COLOUR_RGB_BLUE": "آبی", "COLOUR_RGB_TOOLTIP": "ساخت یک رنگ با مقدار مشخص‌شده‌ای از قرمز، سبز و آبی. همهٔ مقادیر باید بین ۰ تا ۱۰۰ باشند.", "COLOUR_BLEND_TITLE": "مخلوط", "COLOUR_BLEND_COLOUR1": "رنگ ۱", "COLOUR_BLEND_COLOUR2": "رنگ ۲", "COLOUR_BLEND_RATIO": "نسبت", "COLOUR_BLEND_TOOLTIP": "دو رنگ را با نسبت مشخص‌شده مخلوط می‌کند (۰٫۰ - ۱٫۰)", "CONTROLS_REPEAT_HELPURL": "https://fa.wikipedia.org/wiki/%D8%AD%D9%84%D9%82%D9%87_%D9%81%D9%88%D8%B1", "CONTROLS_REPEAT_TITLE": "%1 بار تکرار", "CONTROLS_REPEAT_TITLE_REPEAT": "تکرار", "CONTROLS_REPEAT_TITLE_TIMES": "بار", "CONTROLS_REPEAT_INPUT_DO": "انحام", "CONTROLS_REPEAT_TOOLTIP": "انجام چند عبارت چندین بار.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "تکرار در حالی که", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "تکرار تا زمانی که", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "تا زمانی که یک مقدار صحیح است، چند عبارت را انجام بده.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "تا زمانی که یک مقدار ناصحیح است، چند عبارت را انجام بده.", "CONTROLS_FOR_TOOLTIP": "متغیر %1 را در مقادیر شروع‌شده از عدد انتهای به عدد انتهایی را دارد، با فواصل مشخص‌شده می‌شمارد و این بلوک مشخص‌شده را انجام می‌دهد.", "CONTROLS_FOR_INPUT_WITH": "با تعداد", "CONTROLS_FOR_INPUT_FROM_TO_BY": "از %1 به %2 با گام‌های %3", "CONTROLS_FOREACH_INPUT_ITEM": "برای هر مورد", "CONTROLS_FOREACH_INPUT_INLIST": "در فهرست", "CONTROLS_FOREACH_TOOLTIP": "برای هر مورد در این فهرست، تنظیم متغیر «%1» به مورد و انجام تعدادی عبارت.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "شکستن حلقه", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "ادامه با تکرار بعدی حلقه", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "شکستن حلقهٔ شامل.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "پریدن از بقیهٔ حلقه و ادامه با تکرار بعدی.", "CONTROLS_FLOW_STATEMENTS_WARNING": "اخطار: این بلوک ممکن است فقط داخل یک حلقه استفاده شود.", "CONTROLS_IF_TOOLTIP_1": "اگر یک مقدار صحیح است، سپس چند عبارت را انجام بده.", "CONTROLS_IF_TOOLTIP_2": "اگر یک مقدار صحیح است، اول بلوک اول عبارات را انجام بده. در غیر این صورت بلوک دوم عبارات انجام بده.", "CONTROLS_IF_TOOLTIP_3": "اگر مقدار اول صحیح بود، از آن بلوک اول عبارات را انجام بده. در غیر این صورت، اگر مقدار دوم صحیح است، بلوک دوم عبارات را انجام بده.", "CONTROLS_IF_TOOLTIP_4": "اگر مقدار اول درست است، بلوک اول عبارات را انجام بده. در غیر این صورت، اگر مقدار دوم درست باشد بلوک دوم عبارات را انجام بده. اگر هیچ از مقادیر درست نبود، آخرین بلوک عبارات را انجام بده.", "CONTROLS_IF_MSG_IF": "اگر", "CONTROLS_IF_MSG_ELSEIF": "اگر آنگاه", "CONTROLS_IF_MSG_ELSE": "آنگاه", "CONTROLS_IF_IF_TOOLTIP": "اضافه، حذف یا ترتیب‌سازی قسمت‌ها برای تنظیم مجدد این بلوک اگر مسدود است.", "CONTROLS_IF_ELSEIF_TOOLTIP": "افزودن یک شرط به بلوک اگر.", "CONTROLS_IF_ELSE_TOOLTIP": "اضافه‌کردن نهایی، گرفتن همهٔ شرایط به بلوک اگر.", "LOGIC_COMPARE_HELPURL": "https://fa.wikipedia.org/wiki/%D9%86%D8%A7%D8%A8%D8%B1%D8%A7%D8%A8%D8%B1%DB%8C", "LOGIC_COMPARE_TOOLTIP_EQ": "بازگشت صحیح اگر هر دو ورودی با یکدیگر برابر باشد.", "LOGIC_COMPARE_TOOLTIP_NEQ": "برگرداندن صحیح اگر هر دو ورودی با یکدیگر برابر نباشند.", "LOGIC_COMPARE_TOOLTIP_LT": "بازگرداندن صحیح اگر ورودی اول کوچکتر از ورودی دوم باشد.", "LOGIC_COMPARE_TOOLTIP_LTE": "بازگرداندن صحیح اگر ورودی اول کوچکتر یا مساوی با ورودی دوم باشد.", "LOGIC_COMPARE_TOOLTIP_GT": "بازگرداندن صحیح اگر ورودی اول بزرگتر از ورودی دوم باشد.", "LOGIC_COMPARE_TOOLTIP_GTE": "بازگرداندن صحیح اگر ورودی اول بزرگتر یا مساوی یا ورودی دوم باشد.", "LOGIC_OPERATION_TOOLTIP_AND": "بازگرداندن صحیح اگر هر دو ورودی صحیح باشد.", "LOGIC_OPERATION_AND": "و", "LOGIC_OPERATION_TOOLTIP_OR": "بازگرداندن صحیح اگر یکی از دو ورودی صحیح باشد.", "LOGIC_OPERATION_OR": "یا", "LOGIC_NEGATE_TITLE": "نه %1", "LOGIC_NEGATE_TOOLTIP": "صجیج باز می‌گرداند اگر ورودی نا صحیح باشند. ناصحیح بازمی‌گرداند اگر ورودی صحیح باشد.", "LOGIC_BOOLEAN_TRUE": "صحیح", "LOGIC_BOOLEAN_FALSE": "ناصحیح", "LOGIC_BOOLEAN_TOOLTIP": "بازگرداندن یکی از صحیح یا ناصحیح.", "LOGIC_NULL": "تهی", "LOGIC_NULL_TOOLTIP": "تهی بازمی‌گرداند.", "LOGIC_TERNARY_CONDITION": "آزمایش", "LOGIC_TERNARY_IF_TRUE": "اگر صحیح", "LOGIC_TERNARY_IF_FALSE": "اگر ناصحیح", "LOGIC_TERNARY_TOOLTIP": "بررسی وضعیت در «آزمایش». اگر وضعیت صحیح باشد، مقدار «اگر صحیح» را بر می‌گرداند در غیر اینصورت مقدار «اگر ناصحیح» را.", "MATH_NUMBER_HELPURL": "https://fa.wikipedia.org/wiki/%D8%B9%D8%AF%D8%AF", "MATH_NUMBER_TOOLTIP": "یک عدد.", "MATH_ARITHMETIC_HELPURL": "https://fa.wikipedia.org/wiki/%D8%AD%D8%B3%D8%A7%D8%A8", "MATH_ARITHMETIC_TOOLTIP_ADD": "بازگرداندن مقدار جمع دو عدد.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "بازگرداندن تفاوت دو عدد.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "بازگرداندن حاصلضرب دو عدد.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "بازگرداندن باقی‌ماندهٔ دو عدد.", "MATH_ARITHMETIC_TOOLTIP_POWER": "بازگرداندن اولین عددی که از توان عدد دوم حاصل شده باشد.", "MATH_SINGLE_HELPURL": "https://fa.wikipedia.org/wiki/%D8%B1%DB%8C%D8%B4%D9%87_%D8%AF%D9%88%D9%85", "MATH_SINGLE_OP_ROOT": "ریشهٔ دوم", "MATH_SINGLE_TOOLTIP_ROOT": "ریشهٔ دوم یک عدد را باز می‌گرداند.", "MATH_SINGLE_OP_ABSOLUTE": "مطلق", "MATH_SINGLE_TOOLTIP_ABS": "قدر مطلق یک عدد را بازمی‌گرداند.", "MATH_SINGLE_TOOLTIP_NEG": "منفی‌شدهٔ یک عدد را باز می‌گرداند.", "MATH_SINGLE_TOOLTIP_LN": "لوگاریتم طبیعی یک عدد را باز می‌گرداند.", "MATH_SINGLE_TOOLTIP_LOG10": "بازگرداندن لگاریتم بر پایهٔ ۱۰ یک عدد.", "MATH_SINGLE_TOOLTIP_EXP": "بازگرداندن توان e یک عدد.", "MATH_SINGLE_TOOLTIP_POW10": "بازگرداندن توان ۱۰ یک عدد.", "MATH_TRIG_HELPURL": "https://fa.wikipedia.org/wiki/%D8%AA%D8%A7%D8%A8%D8%B9%E2%80%8C%D9%87%D8%A7%DB%8C_%D9%85%D8%AB%D9%84%D8%AB%D8%A7%D8%AA%DB%8C", "MATH_TRIG_TOOLTIP_SIN": "بازگرداندن سینوس درجه (نه رادیان).", "MATH_TRIG_TOOLTIP_COS": "بازگرداندن کسینوس درجه (نه رادیان).", "MATH_TRIG_TOOLTIP_TAN": "بازگرداندن تانژانت یک درجه (نه رادیان).", "MATH_TRIG_TOOLTIP_ASIN": "بازگرداندن آرک‌سینوس درجه (نه رادیان).", "MATH_TRIG_TOOLTIP_ACOS": "بازگرداندن آرک‌کسینوس درجه (نه رادیان).", "MATH_TRIG_TOOLTIP_ATAN": "بازگرداندن آرک‌تانژانت درجه (نه رادیان).", "MATH_CONSTANT_HELPURL": "https://fa.wikipedia.org/wiki/%D8%AB%D8%A7%D8%A8%D8%AA_%D8%B1%DB%8C%D8%A7%D8%B6%DB%8C", "MATH_CONSTANT_TOOLTIP": "یکی از مقادیر مشترک را برمی‌گرداند: π (۳٫۱۴۱…)، e (۲٫۷۱۸...)، φ (۱٫۶۱۸)، sqrt(۲) (۱٫۴۱۴)، sqrt(۱/۲) (۰٫۷۰۷...) و یا ∞ (بی‌نهایت).", "MATH_IS_EVEN": "زوج است", "MATH_IS_ODD": "فرد است", "MATH_IS_PRIME": "عدد اول است", "MATH_IS_WHOLE": "کامل است", "MATH_IS_POSITIVE": "مثبت است", "MATH_IS_NEGATIVE": "منفی است", "MATH_IS_DIVISIBLE_BY": "تقسیم شده بر", "MATH_IS_TOOLTIP": "بررسی می‌کند که آیا یک عدد زوج، فرد، اول، کامل، مثبت، منفی یا بخش‌پذیر عدد خاصی باشد را بررسی می‌کند. درست یا نادرست باز می‌گرداند.", "MATH_CHANGE_HELPURL": "https://fa.wikipedia.org/wiki/%D8%A7%D8%B5%D8%B7%D9%84%D8%A7%D8%AD_%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%E2%80%8C%D9%86%D9%88%DB%8C%D8%B3%DB%8C#.D8.A7.D9.81.D8.B2.D8.A7.DB.8C.D8.B4_.D8.B4.D9.85.D8.A7.D8.B1.D9.86.D8.AF.D9.87", "MATH_CHANGE_TITLE_CHANGE": "تغییر", "MATH_CHANGE_INPUT_BY": "با", "MATH_CHANGE_TOOLTIP": "افزودن یک عدد به متغیر '%1'.", "MATH_ROUND_HELPURL": "https://fa.wikipedia.org/wiki/%D8%B1%D9%88%DB%8C%D9%87_%28%D8%B9%D9%84%D9%88%D9%85_%D8%B1%D8%A7%DB%8C%D8%A7%D9%86%D9%87%29", "MATH_ROUND_TOOLTIP": "گردکردن یک عدد به بالا یا پایین.", "MATH_ROUND_OPERATOR_ROUND": "گردکردن", "MATH_ROUND_OPERATOR_ROUNDUP": "گرد به بالا", "MATH_ROUND_OPERATOR_ROUNDDOWN": "گرد به پایین", "MATH_ONLIST_OPERATOR_SUM": "جمع فهرست", "MATH_ONLIST_TOOLTIP_SUM": "جمع همهٔ عددهای فهرست را باز می‌گرداند.", "MATH_ONLIST_OPERATOR_MIN": "کوچکترین فهرست", "MATH_ONLIST_TOOLTIP_MIN": "کوچک‌ترین عدد در فهرست را باز می‌گرداند.", "MATH_ONLIST_OPERATOR_MAX": "بزرگ‌ترین فهرست", "MATH_ONLIST_TOOLTIP_MAX": "بزرگ‌ترین عدد در فهرست را باز می‌گرداند.", "MATH_ONLIST_OPERATOR_AVERAGE": "میانگین فهرست", "MATH_ONLIST_TOOLTIP_AVERAGE": "میانگین (میانگین ریاضی) مقادیر عددی فهرست را بر می‌گرداند.", "MATH_ONLIST_OPERATOR_MEDIAN": "میانهٔ فهرست", "MATH_ONLIST_TOOLTIP_MEDIAN": "میانهٔ عدد در فهرست را بر می‌گرداند.", "MATH_ONLIST_OPERATOR_MODE": "مد فهرست", "MATH_ONLIST_TOOLTIP_MODE": "شایع‌ترین قلم(های) در فهرست را بر می‌گرداند.", "MATH_ONLIST_OPERATOR_STD_DEV": "انحراف معیار فهرست", "MATH_ONLIST_TOOLTIP_STD_DEV": "انحراف معیار فهرست را بر می‌گرداند.", "MATH_ONLIST_OPERATOR_RANDOM": "مورد تصادفی از فهرست", "MATH_ONLIST_TOOLTIP_RANDOM": "موردی تصادفی از فهرست را بر می‌گرداند.", "MATH_MODULO_HELPURL": "https://fa.wikipedia.org/wiki/%D8%B9%D9%85%D9%84%DB%8C%D8%A7%D8%AA_%D9%BE%DB%8C%D9%85%D8%A7%D9%86%D9%87", "MATH_MODULO_TITLE": "باقی‌ماندهٔ %1 + %2", "MATH_MODULO_TOOLTIP": "باقی‌ماندهٔ تقسیم دو عدد را بر می‌گرداند.", "MATH_CONSTRAIN_TITLE": "محدودکردن %1 پایین %2 بالا %3", "MATH_CONSTRAIN_TOOLTIP": "محدودکردن یک عدد بین محدودیت‌های مشخص‌شده (بسته).", "MATH_RANDOM_INT_HELPURL": "https://fa.wikipedia.org/wiki/%D8%AA%D9%88%D9%84%DB%8C%D8%AF_%D8%A7%D8%B9%D8%AF%D8%A7%D8%AF_%D8%AA%D8%B5%D8%A7%D8%AF%D9%81%DB%8C", "MATH_RANDOM_INT_TITLE": "عدد صحیح تصادفی بین %1 تا %2", "MATH_RANDOM_INT_TOOLTIP": "یک عدد تصادفی بین دو مقدار مشخص‌شده به صورت بسته باز می‌گرداند.", "MATH_RANDOM_FLOAT_HELPURL": "https://fa.wikipedia.org/wiki/%D8%AA%D9%88%D9%84%DB%8C%D8%AF_%D8%A7%D8%B9%D8%AF%D8%A7%D8%AF_%D8%AA%D8%B5%D8%A7%D8%AF%D9%81%DB%8C", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "کسر تصادفی", "MATH_RANDOM_FLOAT_TOOLTIP": "بازگرداندن کسری تصادفی بین ۰٫۰ (بسته) تا ۱٫۰ (باز).", "TEXT_TEXT_HELPURL": "https://fa.wikipedia.org/wiki/%D8%B1%D8%B4%D8%AA%D9%87_%28%D8%B9%D9%84%D9%88%D9%85_%D8%B1%D8%A7%DB%8C%D8%A7%D9%86%D9%87%29", "TEXT_TEXT_TOOLTIP": "یک حرف، کلمه یا خطی از متن.", "TEXT_JOIN_TITLE_CREATEWITH": "ایجاد متن با", "TEXT_JOIN_TOOLTIP": "یک تکه‌ای از متن را با چسپاندن همهٔ تعداد از موارد ایجاد می‌کند.", "TEXT_CREATE_JOIN_TITLE_JOIN": "عضویت", "TEXT_CREATE_JOIN_TOOLTIP": "اضافه‌کردن، حذف یا مرتب‌سازی بحش‌ها برای تنظیم مجدد این بلوک متنی.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "افزودن یک مورد به متن.", "TEXT_APPEND_TO": "به", "TEXT_APPEND_APPENDTEXT": "الحاق متن", "TEXT_APPEND_TOOLTIP": "الحاق متنی به متغیر «%1».", "TEXT_LENGTH_TITLE": "طول %1", "TEXT_LENGTH_TOOLTIP": "بازگرداندن عددی از حروف (شامل فاصله‌ها) در متن فراهم‌شده.", "TEXT_ISEMPTY_TITLE": "%1 خالی است", "TEXT_ISEMPTY_TOOLTIP": "اضافه‌کردن صحیح اگر متن فراهم‌شده خالی است.", "TEXT_INDEXOF_TOOLTIP": "شاخصی از اولین آخرین رخ‌داد متن اول در متن دوم بر می‌گرداند. اگر متن یافت نشد ۰ باز می‌گرداند.", "TEXT_INDEXOF_INPUT_INTEXT": "در متن", "TEXT_INDEXOF_OPERATOR_FIRST": "اولین رخداد متن را بیاب", "TEXT_INDEXOF_OPERATOR_LAST": "آخرین رخداد متن را بیاب", "TEXT_CHARAT_INPUT_INTEXT": "در متن", "TEXT_CHARAT_FROM_START": "گرفتن حرف #", "TEXT_CHARAT_FROM_END": "گرفتن حرف # از آخر", "TEXT_CHARAT_FIRST": "گرفتن اولین حرف", "TEXT_CHARAT_LAST": "گرفتن آخرین حرف", "TEXT_CHARAT_RANDOM": "گرفتن حرف تصادفی", "TEXT_CHARAT_TOOLTIP": "حرفی در موقعیت مشخص‌شده بر می‌گرداند.", "TEXT_GET_SUBSTRING_TOOLTIP": "قسمت مشخصی‌شده‌ای از متن را بر می‌گرداند.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "در متن", "TEXT_GET_SUBSTRING_START_FROM_START": "گرفتن زیرمتن از حرف #", "TEXT_GET_SUBSTRING_START_FROM_END": "گرفتن زیرمتن از حرف # به انتها", "TEXT_GET_SUBSTRING_START_FIRST": "گرفتن زیرمتن از اولین حرف", "TEXT_GET_SUBSTRING_END_FROM_START": "به حرف #", "TEXT_GET_SUBSTRING_END_FROM_END": "به حرف # از انتها", "TEXT_GET_SUBSTRING_END_LAST": "به آخرین حرف", "TEXT_CHANGECASE_TOOLTIP": "بازگرداندن کپی متن در حالتی متفاوت.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "به حروف بزرگ", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "به حروف کوچک", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "به حروف بزرگ عنوان", "TEXT_TRIM_TOOLTIP": "کپی از متن با فاصله‌های حذف‌شده از یک یا هر دو پایان باز می‌گرداند.", "TEXT_TRIM_OPERATOR_BOTH": "تراشیدن فاصله‌ها از هر دو طرف", "TEXT_TRIM_OPERATOR_LEFT": "تراشیدن فاصله‌ها از طرف چپ", "TEXT_TRIM_OPERATOR_RIGHT": "تراشیدن فاصله‌ها از طرف چپ", "TEXT_PRINT_TITLE": "چاپ %1", "TEXT_PRINT_TOOLTIP": "چاپ متن، عدد یا هر مقدار دیگر مشخص‌شده.", "TEXT_PROMPT_TYPE_TEXT": "اعلان برای متن با پیام", "TEXT_PROMPT_TYPE_NUMBER": "اعلان برای عدد با پیام", "TEXT_PROMPT_TOOLTIP_NUMBER": "اعلان برای کاربر با یک عدد.", "TEXT_PROMPT_TOOLTIP_TEXT": "اعلان برای کاربر برای یک متن.", "LISTS_CREATE_EMPTY_TITLE": "ایجاد فهرست خالی", "LISTS_CREATE_EMPTY_TOOLTIP": "فهرستی با طول صفر شامل هیچ رکورد داده‌ای بر می‌گرداند.", "LISTS_CREATE_WITH_TOOLTIP": "فهرستی از هر عددی از موارد می‌سازد.", "LISTS_CREATE_WITH_INPUT_WITH": "ایجاد فهرست با", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "فهرست", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "اضافه‌کردن، حذف‌کردن یا ترتیب‌سازی مجدد بخش‌ها این بلوک فهرستی.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "اضافه‌کردن یک مورد به فهرست.", "LISTS_REPEAT_TOOLTIP": "فهرستی شامل مقادیر داده‌شدهٔ تکرار شده عدد مشخص‌شده می‌سازد.", "LISTS_REPEAT_TITLE": "فهرستی با %1 تکرارشده به اندازهٔ %2 می‌سازد", "LISTS_LENGTH_TITLE": "طول %1", "LISTS_LENGTH_TOOLTIP": "طول یک فهرست را برمی‌گرداند.", "LISTS_IS_EMPTY_TITLE": "%1 خالی است", "LISTS_TOOLTIP": "اگر فهرست خالی است مقدار صجیج بر می‌گرداند.", "LISTS_INLIST": "در فهرست", "LISTS_INDEX_OF_FIRST": "یافتن اولین رخ‌داد مورد", "LISTS_INDEX_OF_LAST": "یافتن آخرین رخ‌داد مورد", "LISTS_INDEX_OF_TOOLTIP": "شاخصی از اولین/آخرین رخ‌داد مورد در فهرست را بر می‌گرداند. ۰ بر می‌گرداند اگر متن موجود نبود.", "LISTS_GET_INDEX_GET": "گرفتن", "LISTS_GET_INDEX_GET_REMOVE": "گرفتن و حذف‌کردن", "LISTS_GET_INDEX_REMOVE": "حذف‌کردن", "LISTS_GET_INDEX_FROM_END": "# از انتها", "LISTS_GET_INDEX_FIRST": "اولین", "LISTS_GET_INDEX_LAST": "آخرین", "LISTS_GET_INDEX_RANDOM": "تصادفی", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "موردی در محل مشخص‌شده بر می‌گرداند. #1 اولین مورد است.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "موردی در محل مشخص در فهرست بر می‌گرداند. #1 آخرین مورد است.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "اولین مورد یک فهرست را بر می‌گرداند.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "آخرین مورد در یک فهرست را بر می‌گرداند.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "یک مورد تصادفی در یک فهرست بر می‌گرداند.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "مورد در محل مشخص‌شده در فهرست را حذف و بر می‌گرداند. #1 اولین مورد است.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "مورد در محل مشخص‌شده در فهرست را حذف و بر می‌گرداند. #1 آخرین مورد است.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "اولین مورد مشخص‌شده در فهرست را حذف و بر می‌گرداند.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "آخرین مورد مشخص‌شده در فهرست را حذف و بر می‌گرداند.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "مورد تصادفی‌ای را در فهرست حذف و بر می‌گرداند.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "مورد مشخص‌شده در موقعیت مشخص در یک فهرست را حذف و بر می‌گرداند. #1 اولین مورد است.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "مورد مشخص‌شده در موقعیت مشخص در یک فهرست را حذف و بر می‌گرداند. #1 آخرین مورد است.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "اولین مورد را در یک فهرست حذف می‌کند.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "آخرین مورد را در یک فهرست حذف می‌کند.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "یک مورد تصادفی را یک فهرست حذف می‌کند.", "LISTS_SET_INDEX_SET": "مجموعه", "LISTS_SET_INDEX_INSERT": "درج در", "LISTS_SET_INDEX_INPUT_TO": "به‌عنوان", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "مورد مشخص‌شده در یک فهرست را قرار می‌دهد. #1 اولین مورد است.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "مورد مشخص‌شده در یک فهرست را قرار می‌دهد. #1 آخرین مورد است.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "اولین مورد در یک فهرست را تعیین می‌کند.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "آخرین مورد در یک فهرست را تعیین می‌کند.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "یک مورد تصادفی در یک فهرست را تعیین می‌کند.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "موردی در موقعیت مشخص‌شده در یک فهرست اضافه می‌کند. #1 اولین مورد است.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "موردی در موقعیت مشخص‌شده در یک فهرست اضافه می‌کند. #1 آخرین مورد است.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "موردی به ته فهرست اضافه می‌کند.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "موردی به ته فهرست الحاق می‌کند.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "مورد را به صورت تصادفی در یک فهرست می‌افزاید.", "LISTS_GET_SUBLIST_START_FROM_START": "گرفتن زیرمجموعه‌ای از #", "LISTS_GET_SUBLIST_START_FROM_END": "گرفتن زیرمجموعه‌ای از # از انتها", "LISTS_GET_SUBLIST_START_FIRST": "گرفتن زیرمجموعه‌ای از ابتدا", "LISTS_GET_SUBLIST_END_FROM_START": "به #", "LISTS_GET_SUBLIST_END_FROM_END": "به # از انتها", "LISTS_GET_SUBLIST_END_LAST": "به آخرین", "LISTS_GET_SUBLIST_TOOLTIP": "کپی از قسمت مشخص‌شدهٔ لیست درست می‌کند.", "VARIABLES_GET_TOOLTIP": "مقدار این متغیر را بر می‌گرداند.", "VARIABLES_GET_CREATE_SET": "درست‌کردن «تنظیم %1»", "VARIABLES_SET_TITLE": "مجموعه", "VARIABLES_SET_TAIL": "به", "VARIABLES_SET_TOOLTIP": "متغیر برابر با خروجی را مشخص می‌کند.", "VARIABLES_SET_CREATE_GET": "درست‌کردن «گرفتن %1»", "PROCEDURES_DEFNORETURN_TITLE": "به", "PROCEDURES_DEFNORETURN_PROCEDURE": "انجام چیزی", "PROCEDURES_BEFORE_PARAMS": "با:", "PROCEDURES_DEFNORETURN_TOOLTIP": "تابعی می‌سازد بدون هیچ خروجی.", "PROCEDURES_DEFRETURN_RETURN": "بازگشت", "PROCEDURES_DEFRETURN_TOOLTIP": "تابعی با یک خروجی می‌سازد.", "PROCEDURES_DEF_DUPLICATE_WARNING": "اخطار: این تابعی پارامتر تکراری دارد.", "PROCEDURES_CALLNORETURN_HELPURL": "https://fa.wikipedia.org/wiki/%D8%B1%D9%88%DB%8C%D9%87_%28%D8%B9%D9%84%D9%88%D9%85_%D8%B1%D8%A7%DB%8C%D8%A7%D9%86%D9%87%29", "PROCEDURES_CALLNORETURN_TOOLTIP": "اجرای تابع تعریف‌شده توسط کاربر «%1».", "PROCEDURES_CALLRETURN_HELPURL": "https://fa.wikipedia.org/wiki/%D8%B1%D9%88%DB%8C%D9%87_%28%D8%B9%D9%84%D9%88%D9%85_%D8%B1%D8%A7%DB%8C%D8%A7%D9%86%D9%87%29", "PROCEDURES_CALLRETURN_TOOLTIP": "اجرای تابع تعریف‌شده توسط کاربر «%1» و استفاده از خروجی آن.", "PROCEDURES_MUTATORCONTAINER_TITLE": "ورودی‌ها", "PROCEDURES_MUTATORARG_TITLE": "نام ورودی:", "PROCEDURES_HIGHLIGHT_DEF": "برجسته‌سازی تعریف تابع", "PROCEDURES_CREATE_DO": "ساختن «%1»", "PROCEDURES_IFRETURN_TOOLTIP": "اگر یک مقدار صحیح است، مقدار دوم را برگردان.", "PROCEDURES_IFRETURN_WARNING": "اخطار: این بلوک احتمالاً فقط داخل یک تابع استفاده می‌شود." } ================================================ FILE: extern/blockly/msg/json/fi.json ================================================ { "@metadata": { "authors": [ "Nike", "Silvonen", "Espertus" ] }, "VARIABLES_DEFAULT_NAME": "kohde", "DUPLICATE_BLOCK": "Kopioi", "ADD_COMMENT": "Lisää kommentti", "REMOVE_COMMENT": "Poista kommentti", "EXTERNAL_INPUTS": "Ulkoiset syötteet", "INLINE_INPUTS": "Tuo syötteet", "DELETE_BLOCK": "Poista lohko", "DELETE_X_BLOCKS": "Poista %1 lohkoa", "COLLAPSE_BLOCK": "Sulje lohko", "COLLAPSE_ALL": "Sulje lohkot", "EXPAND_BLOCK": "Laajenna lohko", "EXPAND_ALL": "Laajenna lohkot", "DISABLE_BLOCK": "Passivoi lohko", "ENABLE_BLOCK": "Aktivoi lohko", "HELP": "Apua", "CHANGE_VALUE_TITLE": "Muuta arvoa:", "NEW_VARIABLE": "Uusi muuttuja...", "NEW_VARIABLE_TITLE": "Uuden muuttujan nimi:", "RENAME_VARIABLE": "Nimeä uudelleen muuttuja...", "RENAME_VARIABLE_TITLE": "Nimeä uudelleen kaikki '%1' muuttujaa:", "COLOUR_PICKER_HELPURL": "https://fi.wikipedia.org/wiki/V%C3%A4ri", "COLOUR_PICKER_TOOLTIP": "Valitse väri paletista.", "COLOUR_RANDOM_TITLE": "satunnainen väri", "COLOUR_RANDOM_TOOLTIP": "Valitse väri sattumanvaraisesti.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "väri, jossa on", "COLOUR_RGB_RED": "punainen", "COLOUR_RGB_GREEN": "vihreä", "COLOUR_RGB_BLUE": "sininen", "COLOUR_RGB_TOOLTIP": "Luo väri, jossa on tietty määrä punaista, vihreää ja sinistä. Kaikkien arvojen tulee olla välillä 0 - 100.", "COLOUR_BLEND_TITLE": "sekoitus", "COLOUR_BLEND_COLOUR1": "väri 1", "COLOUR_BLEND_COLOUR2": "väri 2", "COLOUR_BLEND_RATIO": "suhde", "COLOUR_BLEND_TOOLTIP": "Sekoittaa kaksi väriä keskenään annetussa suhteessa (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "toista %1 kertaa", "CONTROLS_REPEAT_TITLE_REPEAT": "toista", "CONTROLS_REPEAT_TITLE_TIMES": "kertaa", "CONTROLS_REPEAT_INPUT_DO": "tee", "CONTROLS_REPEAT_TOOLTIP": "Suorita joukko lausekkeita useampi kertaa.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "toista niin kauan kuin", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "toista kunnes", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Niin kauan kuin arvo on tosi, suorita joukko lausekkeita.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Niin kauan kuin arvo on epätosi, suorita joukko lausekkeita.", "CONTROLS_FOR_TOOLTIP": "Aseta muuttujaan %1 arvot alkuarvosta loppuarvoon annetun askeleen välein ja suorita joka askeleella annettu koodilohko.", "CONTROLS_FOR_INPUT_WITH": "laske", "CONTROLS_FOR_INPUT_FROM_TO_BY": "Väli %1-%2 %3:n välein", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each", "CONTROLS_FOREACH_INPUT_ITEM": "kullekin kohteelle", "CONTROLS_FOREACH_INPUT_INLIST": "listassa", "CONTROLS_FOREACH_TOOLTIP": "Aseta muuttujan %1 arvoksi kukin listan kohde vuorollaan ja suorita joukko lausekkeita.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "poistu silmukasta", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "jatka silmukan seuraavaan toistoon", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Poistu sisemmästä silmukasta.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Ohita loput tästä silmukasta ja siirry seuraavaan toistoon.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Varoitus: Tätä lohkoa voi käyttää vain silmukan sisällä.", "CONTROLS_IF_TOOLTIP_1": "Jos arvo on tosi, suorita lauseke.", "CONTROLS_IF_TOOLTIP_2": "Jos arvo on tosi, suorita ensimmäinen lohko lausekkeita. Muuten suorita toinen lohko lausekkeita.", "CONTROLS_IF_TOOLTIP_3": "Jos ensimmäinen arvo on tosi, suorita ensimmäinen lohko lausekkeita. Muuten, jos toinen arvo on tosi, suorita toinen lohko lausekkeita.", "CONTROLS_IF_TOOLTIP_4": "Jos ensimmäinen arvo on tosi, suorita ensimmäinen lohko lausekkeita. Muuten, jos toinen arvo on tosi, suorita toinen lohko lausekkeita. Jos mikään arvoista ei ole tosi, suorita viimeinen lohko lausekkeita.", "CONTROLS_IF_MSG_IF": "jos", "CONTROLS_IF_MSG_ELSEIF": "muuten jos", "CONTROLS_IF_MSG_ELSE": "muuten", "CONTROLS_IF_IF_TOOLTIP": "Lisää, poista tai järjestele osioita tässä \"jos\" lohkossa.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Lisää ehto \"jos\" lohkoon.", "CONTROLS_IF_ELSE_TOOLTIP": "Lisää lopullinen \"muuten\" lohko \"jos\" lohkoon.", "LOGIC_COMPARE_HELPURL": "https://fi.wikipedia.org/wiki/Ep%C3%A4yht%C3%A4l%C3%B6", "LOGIC_COMPARE_TOOLTIP_EQ": "Palauta tosi, jos syötteet ovat keskenään samat.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Palauttaa tosi, jos syötteet eivät ole keskenään samoja.", "LOGIC_COMPARE_TOOLTIP_LT": "Palauttaa tosi, jos ensimmäinen syöte on pienempi, kuin toinen.", "LOGIC_COMPARE_TOOLTIP_LTE": "Palauttaa tosi, jos ensimmäinen syöte on pienempi tai yhtä suuri, kuin toinen.", "LOGIC_COMPARE_TOOLTIP_GT": "Palauttaa tosi, jos ensimmäinen syöte on suurempi, kuin toinen.", "LOGIC_COMPARE_TOOLTIP_GTE": "Palauttaa tosi, jos ensimmäinen syöte on suurempi tai yhtä suuri, kuin toinen.", "LOGIC_OPERATION_TOOLTIP_AND": "Palauttaa tosi, jos kummatkin syötteet ovat tosia.", "LOGIC_OPERATION_AND": "ja", "LOGIC_OPERATION_TOOLTIP_OR": "Palauttaa tosi, jos ainakin yksi syötteistä on tosi.", "LOGIC_OPERATION_OR": "tai", "LOGIC_NEGATE_TITLE": "ei %1", "LOGIC_NEGATE_TOOLTIP": "Palauttaa tosi, jos syöte on epätosi. Palauttaa epätosi, jos syöte on tosi.", "LOGIC_BOOLEAN_TRUE": "tosi", "LOGIC_BOOLEAN_FALSE": "epätosi", "LOGIC_BOOLEAN_TOOLTIP": "Palauttaa joko tosi tai epätosi.", "LOGIC_NULL": "ei mitään", "LOGIC_NULL_TOOLTIP": "Palauttaa \"ei mitään\"-arvon.", "LOGIC_TERNARY_CONDITION": "ehto", "LOGIC_TERNARY_IF_TRUE": "jos tosi", "LOGIC_TERNARY_IF_FALSE": "jos epätosi", "LOGIC_TERNARY_TOOLTIP": "Tarkistaa testin ehdon. Jos ehto on tosi, palauttaa \"jos tosi\" arvon, muuten palauttaa \"jos epätosi\" arvon.", "MATH_NUMBER_HELPURL": "https://fi.wikipedia.org/wiki/Luku", "MATH_NUMBER_TOOLTIP": "Luku.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "⋅", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "asin", "MATH_TRIG_ACOS": "acos", "MATH_TRIG_ATAN": "atan", "MATH_ARITHMETIC_HELPURL": "http://fi.wikipedia.org/wiki/Aritmetiikka", "MATH_ARITHMETIC_TOOLTIP_ADD": "Palauttaa kahden luvun summan.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Palauttaa kahden luvun erotuksen.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Palauttaa kertolaskun tulon.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Palauttaa jakolaskun osamäärän.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Palauttaa ensimmäisen luvun korotettuna toisen luvun potenssiin.", "MATH_SINGLE_HELPURL": "https://fi.wikipedia.org/wiki/Neli%C3%B6juuri", "MATH_SINGLE_OP_ROOT": "neliöjuuri", "MATH_SINGLE_TOOLTIP_ROOT": "Palauttaa luvun neliöjuuren.", "MATH_SINGLE_OP_ABSOLUTE": "itseisarvo", "MATH_SINGLE_TOOLTIP_ABS": "Palauttaa luvun itseisarvon.", "MATH_SINGLE_TOOLTIP_NEG": "Palauttaa numeron vastaluvun.", "MATH_SINGLE_TOOLTIP_LN": "Palauttaa luvun luonnollisen logaritmin.", "MATH_SINGLE_TOOLTIP_LOG10": "Palauttaa luvun kymmenkantaisen logaritmin.", "MATH_SINGLE_TOOLTIP_EXP": "Palauttaa e potenssiin luku.", "MATH_SINGLE_TOOLTIP_POW10": "Palauttaa 10 potenssiin luku.", "MATH_TRIG_HELPURL": "https://fi.wikipedia.org/wiki/Trigonometrinen_funktio", "MATH_TRIG_TOOLTIP_SIN": "Palauttaa asteluvun (ei radiaanin) sinin.", "MATH_TRIG_TOOLTIP_COS": "Palauttaa asteluvun (ei radiaanin) kosinin.", "MATH_TRIG_TOOLTIP_TAN": "Palauttaa asteluvun (ei radiaanin) tangentin.", "MATH_TRIG_TOOLTIP_ASIN": "Palauttaa luvun arkussinin.", "MATH_TRIG_TOOLTIP_ACOS": "Palauttaa luvun arkuskosinin.", "MATH_TRIG_TOOLTIP_ATAN": "Palauttaa luvun arkustangentin.", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "Palauttaa jonkin seuraavista vakioista: π (3.141…), e (2.718…), φ (1.618…), neliöjuuri(2) (1.414…), neliöjuuri(½) (0.707…), or ∞ (ääretön).", "MATH_IS_EVEN": "on parillinen", "MATH_IS_ODD": "on pariton", "MATH_IS_PRIME": "on alkuluku", "MATH_IS_WHOLE": "on kokonaisluku", "MATH_IS_POSITIVE": "on positiivinen", "MATH_IS_NEGATIVE": "on negatiivinen", "MATH_IS_DIVISIBLE_BY": "on jaollinen luvulla", "MATH_IS_TOOLTIP": "Tarkistaa onko numero parillinen, pariton, alkuluku, kokonaisluku, positiivinen, negatiivinen, tai jos se on jaollinen toisella luvulla. Palauttaa tosi tai epätosi.", "MATH_CHANGE_HELPURL": "https://fi.wikipedia.org/wiki/Yhteenlasku", "MATH_CHANGE_TITLE_CHANGE": "muuta", "MATH_CHANGE_INPUT_BY": "arvolla", "MATH_CHANGE_TOOLTIP": "Lisää arvo muuttujaan '%1'.", "MATH_ROUND_HELPURL": "https://fi.wikipedia.org/wiki/Py%C3%B6rist%C3%A4minen", "MATH_ROUND_TOOLTIP": "Pyöristää luvun ylös- tai alaspäin.", "MATH_ROUND_OPERATOR_ROUND": "pyöristä", "MATH_ROUND_OPERATOR_ROUNDUP": "pyöristä ylöspäin", "MATH_ROUND_OPERATOR_ROUNDDOWN": "pyöristä alaspäin", "MATH_ONLIST_OPERATOR_SUM": "summa luvuista", "MATH_ONLIST_TOOLTIP_SUM": "Palauttaa kaikkien annettujen lukujen summan.", "MATH_ONLIST_OPERATOR_MIN": "pienin luvuista", "MATH_ONLIST_TOOLTIP_MIN": "Palauttaa pienimmän annetuista luvuista.", "MATH_ONLIST_OPERATOR_MAX": "suurin luvuista", "MATH_ONLIST_TOOLTIP_MAX": "Palauttaa suurimman annetuista luvuista.", "MATH_ONLIST_OPERATOR_AVERAGE": "keskiarvo luvuista", "MATH_ONLIST_TOOLTIP_AVERAGE": "Palauttaa aritmeettisen keskiarvon annetuista luvuista.", "MATH_ONLIST_OPERATOR_MEDIAN": "keskiluku luvuista", "MATH_ONLIST_TOOLTIP_MEDIAN": "Palauttaa annettujen lukujen keskiluvun.", "MATH_ONLIST_OPERATOR_MODE": "tyyppiarvo luvuista", "MATH_ONLIST_TOOLTIP_MODE": "Palauttaa luettelon yleisimmistä luvuista annetussa listassa.", "MATH_ONLIST_OPERATOR_STD_DEV": "keskihajonta luvuista", "MATH_ONLIST_TOOLTIP_STD_DEV": "Palauttaa annettujen lukujen keskihajonnan.", "MATH_ONLIST_OPERATOR_RANDOM": "satunnainen valinta luvuista", "MATH_ONLIST_TOOLTIP_RANDOM": "Palauttaa satunnaisesti valitun luvun annetuista luvuista.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "%1 ÷ %2 jakojäännös", "MATH_MODULO_TOOLTIP": "Palauttaa jakolaskun jakojäännöksen.", "MATH_CONSTRAIN_TITLE": "rajoita %1 vähintään %2 enintään %3", "MATH_CONSTRAIN_TOOLTIP": "Rajoittaa arvon annetulle suljetulle välille.", "MATH_RANDOM_INT_HELPURL": "https://fi.wikipedia.org/wiki/Satunnaisluku", "MATH_RANDOM_INT_TITLE": "Palauttaa satunnaisen kokonaisluvun väliltä %1-%2", "MATH_RANDOM_INT_TOOLTIP": "Palauttaa satunnaisen kokonaisluvun kahden annetun arvon suljetulta väliltä.", "MATH_RANDOM_FLOAT_HELPURL": "https://fi.wikipedia.org/wiki/Satunnaisluku", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "satunnainen murtoluku", "MATH_RANDOM_FLOAT_TOOLTIP": "Palauttaa satunnaisen luvun oikealta puoliavoimesta välistä [0.0, 1.0).", "TEXT_TEXT_HELPURL": "https://fi.wikipedia.org/wiki/Merkkijono", "TEXT_TEXT_TOOLTIP": "Kirjain, sana tai rivi tekstiä.", "TEXT_JOIN_TITLE_CREATEWITH": "luo teksti", "TEXT_JOIN_TOOLTIP": "Luo merkkijonon liittämällä yhteen minkä tahansa määrän kohteita.", "TEXT_CREATE_JOIN_TITLE_JOIN": "liitä", "TEXT_CREATE_JOIN_TOOLTIP": "Lisää, poista tai uudelleen järjestä osioita tässä lohkossa.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Lisää kohteen tekstiin.", "TEXT_APPEND_TO": "muuttujaan", "TEXT_APPEND_APPENDTEXT": "lisää teksti", "TEXT_APPEND_TOOLTIP": "Lisää tekstiä muuttujaan '%1'.", "TEXT_LENGTH_TITLE": "%1:n pituus", "TEXT_LENGTH_TOOLTIP": "Palauttaa annetussa tekstissä olevien merkkien määrän (välilyönnit mukaan lukien).", "TEXT_ISEMPTY_TITLE": "%1 on tyhjä", "TEXT_ISEMPTY_TOOLTIP": "Palauttaa tosi, jos annettu teksti on tyhjä.", "TEXT_INDEXOF_TOOLTIP": "Palauttaa ensin annetun tekstin ensimmäisen/viimeisen esiintymän osoitteen toisessa tekstissä. Palauttaa osoitteen 0 jos tekstiä ei löytynyt.", "TEXT_INDEXOF_INPUT_INTEXT": "tekstistä", "TEXT_INDEXOF_OPERATOR_FIRST": "etsi ensimmäinen esiintymä merkkijonolle", "TEXT_INDEXOF_OPERATOR_LAST": "etsi viimeinen esiintymä merkkijonolle", "TEXT_CHARAT_INPUT_INTEXT": "tekstistä", "TEXT_CHARAT_FROM_START": "Hae kirjain nro", "TEXT_CHARAT_FROM_END": "Hae kirjain nro (lopusta laskien)", "TEXT_CHARAT_FIRST": "hae ensimmäinen kirjain", "TEXT_CHARAT_LAST": "hae viimeinen kirjain", "TEXT_CHARAT_RANDOM": "hae satunnainen kirjain", "TEXT_CHARAT_TOOLTIP": "Palauttaa annetussa kohdassa olevan kirjaimen.", "TEXT_GET_SUBSTRING_TOOLTIP": "Palauttaa määrätyn osan tekstistä.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "merkkijonosta", "TEXT_GET_SUBSTRING_START_FROM_START": "hae osa alkaen kirjaimesta nro", "TEXT_GET_SUBSTRING_START_FROM_END": "hae osa alkaen kirjaimesta nro (lopusta laskien)", "TEXT_GET_SUBSTRING_START_FIRST": "hae osa alkaen ensimmäisestä kirjaimesta", "TEXT_GET_SUBSTRING_END_FROM_START": "kirjaimeen nro", "TEXT_GET_SUBSTRING_END_FROM_END": "kirjaimeen nro (lopusta laskien)", "TEXT_GET_SUBSTRING_END_LAST": "viimeiseen kirjaimeen", "TEXT_CHANGECASE_TOOLTIP": "Palauttaa kopion tekstistä eri kirjainkoossa.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "isot kirjaimet", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "pienet kirjaimet", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "isot alkukirjaimet", "TEXT_TRIM_TOOLTIP": "Palauttaa kopion tekstistä siten, että välilyönnit on poistettu yhdestä tai molemmista päistä.", "TEXT_TRIM_OPERATOR_BOTH": "poistaa välilyönnit kummaltakin puolelta", "TEXT_TRIM_OPERATOR_LEFT": "poistaa välilyönnit vasemmalta puolelta", "TEXT_TRIM_OPERATOR_RIGHT": "poistaa välilyönnit oikealta puolelta", "TEXT_PRINT_TITLE": "tulosta %1", "TEXT_PRINT_TOOLTIP": "Tulostaa annetun tekstin, numeron tia muun arvon.", "TEXT_PROMPT_TYPE_TEXT": "käyttäen annettua viestiä, kehottaa syöttämään tekstiä", "TEXT_PROMPT_TYPE_NUMBER": "käyttäen annettua viestiä, kehottaa syöttämään numeron", "TEXT_PROMPT_TOOLTIP_NUMBER": "Kehottaa käyttäjää syöttämään numeron.", "TEXT_PROMPT_TOOLTIP_TEXT": "Kehottaa käyttäjää syöttämään tekstiä.", "LISTS_CREATE_EMPTY_TITLE": "Luo tyhjä lista", "LISTS_CREATE_EMPTY_TOOLTIP": "Palauta tyhjä lista, pituus 0", "LISTS_CREATE_WITH_TOOLTIP": "Luo lista, jossa on mikä tahansa määrä kohteita.", "LISTS_CREATE_WITH_INPUT_WITH": "luo lista", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "lista", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Listää, poista tai järjestele uudestaan osioita tässä lohkossa.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Lisää kohde listaan.", "LISTS_REPEAT_TOOLTIP": "Luo listan, jossa annettu arvo toistuu määrätyn monta kertaa.", "LISTS_REPEAT_TITLE": "luo lista, jossa kohde %1 toistuu %2 kertaa", "LISTS_LENGTH_TITLE": "%1:n pituus", "LISTS_LENGTH_TOOLTIP": "Palauttaa listan pituuden.", "LISTS_IS_EMPTY_TITLE": "%1 on tyhjä", "LISTS_TOOLTIP": "Palauttaa tosi, jos lista on tyhjä.", "LISTS_INLIST": "listassa", "LISTS_INDEX_OF_FIRST": "etsi ensimmäinen esiintymä kohteelle", "LISTS_INDEX_OF_LAST": "etsi viimeinen esiintymä kohteelle", "LISTS_INDEX_OF_TOOLTIP": "Palauttaa kohteen ensimmäisen/viimeisen esiintymän kohdan. Palauttaa 0 jos tekstiä ei löydy.", "LISTS_GET_INDEX_GET": "hae", "LISTS_GET_INDEX_GET_REMOVE": "hae ja poista", "LISTS_GET_INDEX_REMOVE": "poista", "LISTS_GET_INDEX_FROM_START": "nro", "LISTS_GET_INDEX_FROM_END": "nro (lopusta laskien)", "LISTS_GET_INDEX_FIRST": "ensimmäinen", "LISTS_GET_INDEX_LAST": "viimeinen", "LISTS_GET_INDEX_RANDOM": "satunnainen", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Palauta kohde annetusta kohdasta listaa. Numero 1 tarkoittaa listan ensimmäistä kohdetta.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Palauta kohde annetusta kohdasta listaa. Numero 1 tarkoittaa listan viimeistä kohdetta.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Palauta ensimmäinen kohde listalta.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Palauttaa listan viimeisen kohteen.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Palauttaa satunnaisen kohteen listalta.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Poistaa ja palauttaa kohteen annetusta kohden listaa. Nro 1 on ensimmäinen kohde.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Poistaa ja palauttaa kohteen annetusta kohden listaa. Nro 1 on ensimmäinen kohde.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Poistaa ja palauttaa ensimmäisen kohteen listalta.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Poistaa ja palauttaa viimeisen kohteen listalta.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Poistaa ja palauttaa satunnaisen kohteen listalta.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Poistaa kohteen listalta annetusta kohtaa. Nro 1 on ensimmäinen kohde.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Poistaa kohteen listalta annetusta kohtaa. Nro 1 on viimeinen kohde.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Poistaa ensimmäisen kohteen listalta.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Poistaa viimeisen kohteen listalta.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Poistaa satunnaisen kohteen listalta.", "LISTS_SET_INDEX_SET": "aseta", "LISTS_SET_INDEX_INSERT": "lisää kohtaan", "LISTS_SET_INDEX_INPUT_TO": "kohteeksi", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Asettaa kohteen määrättyyn kohtaa listassa. Nro 1 on listan alku.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Asettaa listan määrätyssä kohtaa olevan kohteen. Nro 1 on listan loppu.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Asettaa listan ensimmäisen kohteen.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Asettaa listan viimeisen kohteen.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Asettaa satunnaisen kohteen listassa.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Lisää kohteen listan annettuun kohtaan. Nro 1 on listan kärki.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Lisää kohteen annettuun kohtaan listaa. Nro 1 on listan häntä.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Lisää kohteen listan kärkeen.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Lisää kohteen listan loppuun.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Lisää kohteen satunnaiseen kohtaan listassa.", "LISTS_GET_SUBLIST_START_FROM_START": "hae osalista alkaen kohdasta", "LISTS_GET_SUBLIST_START_FROM_END": "hae osalista alkaen kohdasta (lopusta laskien)", "LISTS_GET_SUBLIST_START_FIRST": "hae osalista alkaen alusta", "LISTS_GET_SUBLIST_END_FROM_START": "päättyen kohtaan", "LISTS_GET_SUBLIST_END_FROM_END": "päättyen kohtaan (lopusta laskien)", "LISTS_GET_SUBLIST_END_LAST": "viimeinen", "LISTS_GET_SUBLIST_TOOLTIP": "Luo kopio määrätystä kohden listaa.", "VARIABLES_GET_TOOLTIP": "Palauttaa muuttujan arvon.", "VARIABLES_GET_CREATE_SET": "Luo 'aseta %1'", "VARIABLES_SET_TITLE": "aseta", "VARIABLES_SET_TAIL": "arvoksi", "VARIABLES_SET_TOOLTIP": "Asettaa muutujan arvoksi annetun syötteen.", "VARIABLES_SET_CREATE_GET": "Luo 'hae %1'", "PROCEDURES_DEFNORETURN_TITLE": "tehdäksesi", "PROCEDURES_DEFNORETURN_PROCEDURE": "tee jotain", "PROCEDURES_BEFORE_PARAMS": "parametrit:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Luo funktio, jolla ei ole tuotosta.", "PROCEDURES_DEFRETURN_RETURN": "palauta", "PROCEDURES_DEFRETURN_TOOLTIP": "Luo funktio, jolla ei ole tuotosta.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Varoitus: tällä funktiolla on sama parametri useamman kerran.", "PROCEDURES_CALLNORETURN_HELPURL": "https://fi.wikipedia.org/wiki/Aliohjelma", "PROCEDURES_CALLNORETURN_TOOLTIP": "Suorittaa käyttäjän määrittelemä funktio '%1'.", "PROCEDURES_CALLRETURN_HELPURL": "https://fi.wikipedia.org/wiki/Aliohjelma", "PROCEDURES_CALLRETURN_TOOLTIP": "Suorittaa käyttäjän määrittelemän funktion '%1' ja käyttää sen tuotosta.", "PROCEDURES_MUTATORCONTAINER_TITLE": "syötteet", "PROCEDURES_MUTATORARG_TITLE": "syötteen nimi:", "PROCEDURES_HIGHLIGHT_DEF": "Korosta funktion määritelmä", "PROCEDURES_CREATE_DO": "Luo '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Jos arvo on tosi, palauta toinen arvo.", "PROCEDURES_IFRETURN_WARNING": "Varoitus: tätä lohkoa voi käyttää vain funktion määrityksessä." } ================================================ FILE: extern/blockly/msg/json/fr.json ================================================ { "@metadata": { "authors": [ "Espertus", "Gomoko" ] }, "VARIABLES_DEFAULT_NAME": "élément", "DUPLICATE_BLOCK": "Dupliquer", "ADD_COMMENT": "Ajouter un commentaire", "REMOVE_COMMENT": "Supprimer un commentaire", "EXTERNAL_INPUTS": "Entrées externes", "INLINE_INPUTS": "Entrées en ligne", "DELETE_BLOCK": "Supprimer le bloc", "DELETE_X_BLOCKS": "Supprimer %1 blocs", "COLLAPSE_BLOCK": "Réduire le bloc", "COLLAPSE_ALL": "Réduire les blocs", "EXPAND_BLOCK": "Développer le bloc", "EXPAND_ALL": "Développer les blocs", "DISABLE_BLOCK": "Désactiver le bloc", "ENABLE_BLOCK": "Activer le bloc", "HELP": "Aide", "CHANGE_VALUE_TITLE": "Modifier la valeur :", "NEW_VARIABLE": "Nouvelle variable…", "NEW_VARIABLE_TITLE": "Nom de la nouvelle variable :", "RENAME_VARIABLE": "Renommer la variable…", "RENAME_VARIABLE_TITLE": "Renommer toutes les variables '%1' en :", "COLOUR_PICKER_HELPURL": "https://fr.wikipedia.org/wiki/Couleur", "COLOUR_PICKER_TOOLTIP": "Choisir une couleur dans la palette", "COLOUR_RANDOM_TITLE": "couleur aléatoire", "COLOUR_RANDOM_TOOLTIP": "Choisir une couleur au hasard.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "colorer avec", "COLOUR_RGB_RED": "rouge", "COLOUR_RGB_GREEN": "vert", "COLOUR_RGB_BLUE": "bleu", "COLOUR_RGB_TOOLTIP": "Créer une couleur avec la quantité spécifiée de rouge, vert et bleu. Toutes les valeurs doivent être entre 0 et 100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "mélanger", "COLOUR_BLEND_COLOUR1": "couleur 1", "COLOUR_BLEND_COLOUR2": "couleur 2", "COLOUR_BLEND_RATIO": "ratio", "COLOUR_BLEND_TOOLTIP": "Mélange deux couleurs ensemble avec un ratio donné (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "répéter %1 fois", "CONTROLS_REPEAT_TITLE_REPEAT": "répéter", "CONTROLS_REPEAT_TITLE_TIMES": "fois", "CONTROLS_REPEAT_INPUT_DO": "faire", "CONTROLS_REPEAT_TOOLTIP": "Exécuter certains ordres plusieurs fois.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "répéter tant que", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "répéter jusqu’à", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Tant qu’une valeur est vraie, alors exécuter certains ordres.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Tant qu’une valeur est fausse, alors exécuter certains ordres.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Faire en sorte que la variable %1 prenne les valeurs depuis le numéro de début jusqu’au numéro de fin, en s’incrémentant de l’intervalle spécifié, et exécuter les ordres spécifiés.", "CONTROLS_FOR_INPUT_WITH": "compter avec", "CONTROLS_FOR_INPUT_FROM_TO_BY": "de %1 à %2 par %3", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each pour chaque bloc", "CONTROLS_FOREACH_INPUT_ITEM": "pour chaque élément", "CONTROLS_FOREACH_INPUT_INLIST": "dans la liste", "CONTROLS_FOREACH_TOOLTIP": "Pour chaque élément dans une liste, donner la valeur de l’élément à la variable '%1', puis exécuter certains ordres.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "sortir de la boucle", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "continuer avec la prochaine itération de la boucle", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Sortir de la boucle englobante.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Sauter le reste de cette boucle, et poursuivre avec l’itération suivante.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Attention : Ce bloc ne devrait être utilisé que dans une boucle.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "Si une valeur est vraie, alors exécuter certains ordres.", "CONTROLS_IF_TOOLTIP_2": "Si une valeur est vraie, alors exécuter le premier bloc d’ordres. Sinon, exécuter le second bloc d’ordres.", "CONTROLS_IF_TOOLTIP_3": "Si la première valeur est vraie, alors exécuter le premier bloc d’ordres. Sinon, si la seconde valeur est vraie, exécuter le second bloc d’ordres.", "CONTROLS_IF_TOOLTIP_4": "Si la première valeur est vraie, alors exécuter le premier bloc d’ordres. Sinon, si la seconde valeur est vraie, exécuter le second bloc d’ordres. Si aucune des valeurs n’est vraie, exécuter le dernier bloc d’ordres.", "CONTROLS_IF_MSG_IF": "si", "CONTROLS_IF_MSG_ELSEIF": "sinon si", "CONTROLS_IF_MSG_ELSE": "sinon", "CONTROLS_IF_IF_TOOLTIP": "Ajouter, supprimer ou réordonner les sections pour reconfigurer ce bloc si.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Ajouter une condition au bloc si.", "CONTROLS_IF_ELSE_TOOLTIP": "Ajouter une condition finale fourre-tout au bloc si.", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "Renvoyer vrai si les deux entrées sont égales.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Renvoyer vrai si les deux entrées ne sont pas égales.", "LOGIC_COMPARE_TOOLTIP_LT": "Renvoyer vrai si la première entrée est plus petite que la seconde.", "LOGIC_COMPARE_TOOLTIP_LTE": "Renvoyer vrai si la première entrée est plus petite ou égale à la seconde.", "LOGIC_COMPARE_TOOLTIP_GT": "Renvoyer vrai si la première entrée est plus grande que la seconde.", "LOGIC_COMPARE_TOOLTIP_GTE": "Renvoyer vrai si la première entrée est plus grande ou égale à la seconde.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Renvoyer vrai si les deux entrées sont vraies.", "LOGIC_OPERATION_AND": "et", "LOGIC_OPERATION_TOOLTIP_OR": "Renvoyer vrai si au moins une des entrées est vraie.", "LOGIC_OPERATION_OR": "ou", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "pas %1", "LOGIC_NEGATE_TOOLTIP": "Renvoie vrai si l’entrée est fausse. Renvoie faux si l’entrée est vraie.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "vrai", "LOGIC_BOOLEAN_FALSE": "faux", "LOGIC_BOOLEAN_TOOLTIP": "Renvoie soit vrai soit faux.", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "nul", "LOGIC_NULL_TOOLTIP": "Renvoie nul.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "si vrai", "LOGIC_TERNARY_IF_FALSE": "si faux", "LOGIC_TERNARY_TOOLTIP": "Vérifier la condition dans 'test'. Si elle est vraie, renvoie la valeur 'si vrai' ; sinon renvoie la valeur 'si faux'.", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "Un nombre.", "MATH_ARITHMETIC_HELPURL": "https://en.wikipedia.org/wiki/Arithmetic", "MATH_ARITHMETIC_TOOLTIP_ADD": "Renvoie la somme des deux nombres.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Renvoie la différence des deux nombres.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Renvoie le produit des deux nombres.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Renvoie le quotient des deux nombres.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Renvoie le premier nombre élevé à la puissance du second.", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "racine carrée", "MATH_SINGLE_TOOLTIP_ROOT": "Renvoie la racine carrée d’un nombre.", "MATH_SINGLE_OP_ABSOLUTE": "absolu", "MATH_SINGLE_TOOLTIP_ABS": "Renvoie la valeur absolue d’un nombre.", "MATH_SINGLE_TOOLTIP_NEG": "Renvoie l’opposé d’un nombre", "MATH_SINGLE_TOOLTIP_LN": "Renvoie le logarithme naturel d’un nombre.", "MATH_SINGLE_TOOLTIP_LOG10": "Renvoie le logarithme base 10 d’un nombre.", "MATH_SINGLE_TOOLTIP_EXP": "Renvoie e à la puissance d’un nombre.", "MATH_SINGLE_TOOLTIP_POW10": "Renvoie 10 à la puissance d’un nombre.", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "Renvoie le sinus d’un angle en degrés (pas en radians).", "MATH_TRIG_TOOLTIP_COS": "Renvoie le cosinus d’un angle en degrés (pas en radians).", "MATH_TRIG_TOOLTIP_TAN": "Renvoie la tangente d’un angle en degrés (pas en radians).", "MATH_TRIG_TOOLTIP_ASIN": "Renvoie l’arcsinus d’un nombre.", "MATH_TRIG_TOOLTIP_ACOS": "Renvoie l’arccosinus d’un nombre.", "MATH_TRIG_TOOLTIP_ATAN": "Renvoie l’arctangente d’un nombre.", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "Renvoie une des constantes courantes : π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), ou ∞ (infini).", "MATH_IS_EVEN": "est pair", "MATH_IS_ODD": "est impair", "MATH_IS_PRIME": "est premier", "MATH_IS_WHOLE": "est entier", "MATH_IS_POSITIVE": "est positif", "MATH_IS_NEGATIVE": "est négatif", "MATH_IS_DIVISIBLE_BY": "est divisible par", "MATH_IS_TOOLTIP": "Vérifier si un nombre est pair, impair, premier, entier, positif, négatif, ou s’il est divisible par un certain nombre. Renvoie vrai ou faux.", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "incrémenter", "MATH_CHANGE_INPUT_BY": "de", "MATH_CHANGE_TOOLTIP": "Ajouter un nombre à la variable '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Arrondir un nombre au-dessus ou au-dessous.", "MATH_ROUND_OPERATOR_ROUND": "arrondir", "MATH_ROUND_OPERATOR_ROUNDUP": "arrondir au supérieur", "MATH_ROUND_OPERATOR_ROUNDDOWN": "arrondir à l’inférieur", "MATH_ONLIST_OPERATOR_SUM": "somme de la liste", "MATH_ONLIST_TOOLTIP_SUM": "Renvoyer la somme de tous les nombres dans la liste.", "MATH_ONLIST_OPERATOR_MIN": "minimum de la liste", "MATH_ONLIST_TOOLTIP_MIN": "Renvoyer le plus petit nombre dans la liste.", "MATH_ONLIST_OPERATOR_MAX": "maximum de la liste", "MATH_ONLIST_TOOLTIP_MAX": "Renvoyer le plus grand nombre dans la liste.", "MATH_ONLIST_OPERATOR_AVERAGE": "moyenne de la liste", "MATH_ONLIST_TOOLTIP_AVERAGE": "Renvoyer la moyenne (arithmétique) des valeurs numériques dans la liste.", "MATH_ONLIST_OPERATOR_MEDIAN": "médiane de la liste", "MATH_ONLIST_TOOLTIP_MEDIAN": "Renvoyer le nombre médian dans la liste.", "MATH_ONLIST_OPERATOR_MODE": "majoritaires de la liste", "MATH_ONLIST_TOOLTIP_MODE": "Renvoyer une liste des élément(s) le(s) plus courant(s) dans la liste.", "MATH_ONLIST_OPERATOR_STD_DEV": "écart-type de la liste", "MATH_ONLIST_TOOLTIP_STD_DEV": "Renvoyer l’écart-type de la liste.", "MATH_ONLIST_OPERATOR_RANDOM": "élément aléatoire de la liste", "MATH_ONLIST_TOOLTIP_RANDOM": "Renvoyer un élément dans la liste au hasard.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "reste de %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Renvoyer le reste de la division des deux nombres.", "MATH_CONSTRAIN_TITLE": "contraindre %1 entre %2 et %3", "MATH_CONSTRAIN_TOOLTIP": "Contraindre un nombre à être entre les limites spécifiées (incluses).", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "entier aléatoire entre %1 et %2", "MATH_RANDOM_INT_TOOLTIP": "Renvoyer un entier aléatoire entre les deux limites spécifiées, incluses.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "fraction aléatoire", "MATH_RANDOM_FLOAT_TOOLTIP": "Renvoyer une fraction aléatoire entre 0.0 (inclus) et 1.0 (exclus).", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "Une lettre, un mot ou une ligne de texte.", "TEXT_JOIN_TITLE_CREATEWITH": "créer le texte avec", "TEXT_JOIN_TOOLTIP": "Créer un morceau de texte en agrégeant un nombre quelconque d’éléments.", "TEXT_CREATE_JOIN_TITLE_JOIN": "joindre", "TEXT_CREATE_JOIN_TOOLTIP": "Ajouter, supprimer, ou réordonner des sections pour reconfigurer ce bloc de texte.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Ajouter un élément au texte.", "TEXT_APPEND_TO": "à", "TEXT_APPEND_APPENDTEXT": "ajouter le texte", "TEXT_APPEND_TOOLTIP": "Ajouter du texte à la variable '%1'.", "TEXT_LENGTH_TITLE": "longueur de %1", "TEXT_LENGTH_TOOLTIP": "Renvoie le nombre de lettres (espaces compris) dans le texte fourni.", "TEXT_ISEMPTY_TITLE": "%1 est vide", "TEXT_ISEMPTY_TOOLTIP": "Renvoie vrai si le texte fourni est vide.", "TEXT_INDEXOF_TOOLTIP": "Renvoie l’index de la première/dernière occurrence de la première chaîne dans la seconde. Renvoie 0 si la chaîne n’est pas trouvée.", "TEXT_INDEXOF_INPUT_INTEXT": "dans le texte", "TEXT_INDEXOF_OPERATOR_FIRST": "trouver la première occurrence de la chaîne", "TEXT_INDEXOF_OPERATOR_LAST": "trouver la dernière occurrence de la chaîne", "TEXT_CHARAT_INPUT_INTEXT": "dans le texte", "TEXT_CHARAT_FROM_START": "obtenir la lettre #", "TEXT_CHARAT_FROM_END": "obtenir la lettre # depuis la fin", "TEXT_CHARAT_FIRST": "obtenir la première lettre", "TEXT_CHARAT_LAST": "obtenir la dernière lettre", "TEXT_CHARAT_RANDOM": "obtenir une lettre au hasard", "TEXT_CHARAT_TOOLTIP": "Renvoie la lettre à la position indiquée.", "TEXT_GET_SUBSTRING_TOOLTIP": "Renvoie une partie indiquée du texte.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "dans le texte", "TEXT_GET_SUBSTRING_START_FROM_START": "obtenir la sous-chaîne depuis la lettre #", "TEXT_GET_SUBSTRING_START_FROM_END": "obtenir la sous-chaîne depuis la lettre # depuis la fin", "TEXT_GET_SUBSTRING_START_FIRST": "obtenir la sous-chaîne depuis la première lettre", "TEXT_GET_SUBSTRING_END_FROM_START": "jusqu’à la lettre #", "TEXT_GET_SUBSTRING_END_FROM_END": "jusqu’à la lettre # depuis la fin", "TEXT_GET_SUBSTRING_END_LAST": "jusqu’à la dernière lettre", "TEXT_CHANGECASE_TOOLTIP": "Renvoyer une copie du texte dans une autre casse.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "en MAJUSCULES", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "en minuscules", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "en Majuscule Au Début De Chaque Mot", "TEXT_TRIM_TOOLTIP": "Renvoyer une copie du texte avec les espaces supprimés d’un bout ou des deux.", "TEXT_TRIM_OPERATOR_BOTH": "supprimer les espaces des deux côtés", "TEXT_TRIM_OPERATOR_LEFT": "supprimer les espaces du côté gauche", "TEXT_TRIM_OPERATOR_RIGHT": "supprimer les espaces du côté droit", "TEXT_PRINT_TITLE": "afficher %1", "TEXT_PRINT_TOOLTIP": "Afficher le texte, le nombre ou une autre valeur spécifié.", "TEXT_PROMPT_TYPE_TEXT": "invite pour un texte avec un message", "TEXT_PROMPT_TYPE_NUMBER": "invite pour un nombre avec un message", "TEXT_PROMPT_TOOLTIP_NUMBER": "Demander un nombre à l’utilisateur.", "TEXT_PROMPT_TOOLTIP_TEXT": "Demander un texte à l’utilisateur.", "LISTS_CREATE_EMPTY_TITLE": "créer une liste vide", "LISTS_CREATE_EMPTY_TOOLTIP": "Renvoyer une liste, de longueur 0, ne contenant aucun enregistrement", "LISTS_CREATE_WITH_TOOLTIP": "Créer une liste avec un nombre quelconque d’éléments.", "LISTS_CREATE_WITH_INPUT_WITH": "créer une liste avec", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "liste", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Ajouter, supprimer, ou réordonner les sections pour reconfigurer ce bloc de liste.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Ajouter un élément à la liste.", "LISTS_REPEAT_TOOLTIP": "Crée une liste consistant en la valeur fournie répétée le nombre de fois indiqué.", "LISTS_REPEAT_TITLE": "créer une liste avec l’élément %1 répété %2 fois", "LISTS_LENGTH_TITLE": "longueur de %1", "LISTS_LENGTH_TOOLTIP": "Renvoie la longueur d’une liste.", "LISTS_IS_EMPTY_TITLE": "%1 est vide", "LISTS_TOOLTIP": "Renvoie vrai si la liste est vide.", "LISTS_INLIST": "dans la liste", "LISTS_INDEX_OF_FIRST": "trouver la première occurrence de l’élément", "LISTS_INDEX_OF_LAST": "trouver la dernière occurrence de l’élément", "LISTS_INDEX_OF_TOOLTIP": "Renvoie l’index de la première/dernière occurrence de l’élément dans la liste. Renvoie 0 si le texte n’est pas trouvé.", "LISTS_GET_INDEX_GET": "obtenir", "LISTS_GET_INDEX_GET_REMOVE": "obtenir et supprimer", "LISTS_GET_INDEX_REMOVE": "supprimer", "LISTS_GET_INDEX_FROM_END": "# depuis la fin", "LISTS_GET_INDEX_FIRST": "premier", "LISTS_GET_INDEX_LAST": "dernier", "LISTS_GET_INDEX_RANDOM": "aléatoire", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Renvoie l’élément à la position indiquée dans une liste. #1 est le premier élément.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Renvoie l’élément à la position indiquée dans une liste. #1 est le dernier élément.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Renvoie le premier élément dans une liste.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Renvoie le dernier élément dans une liste.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Renvoie un élément au hasard dans une liste.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Supprime et renvoie l’élément à la position indiquée dans une liste. #1 est le premier élément.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Supprime et renvoie l’élément à la position indiquée dans une liste. #1 est le dernier élément.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Supprime et renvoie le premier élément dans une liste.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Supprime et renvoie le dernier élément dans une liste.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Supprime et renvoie un élément au hasard dans une liste.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Supprime l’élément à la position indiquée dans une liste. #1 est le premier élément.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Supprime l’élément à la position indiquée dans une liste. #1 est le dernier élément.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Supprime le premier élément dans une liste.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Supprime le dernier élément dans une liste.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Supprime un élément au hasard dans une liste.", "LISTS_SET_INDEX_SET": "mettre", "LISTS_SET_INDEX_INSERT": "insérer en", "LISTS_SET_INDEX_INPUT_TO": "comme", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Fixe l’élément à la position indiquée dans une liste. #1 est le premier élément.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Fixe l’élément à la position indiquée dans une liste. #1 est le dernier élément.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Fixe le premier élément dans une liste.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Fixe le dernier élément dans une liste.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Fixe un élément au hasard dans une liste.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Insère l’élément à la position indiquée dans une liste. #1 est le premier élément.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Insère l’élément à la position indiquée dans une liste. #1 est le dernier élément.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Insère l’élément au début d’une liste.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Ajouter l’élément à la fin d’une liste.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Insère l’élément au hasard dans une liste.", "LISTS_GET_SUBLIST_START_FROM_START": "obtenir la sous-liste depuis #", "LISTS_GET_SUBLIST_START_FROM_END": "obtenir la sous-liste depuis # depuis la fin", "LISTS_GET_SUBLIST_START_FIRST": "obtenir la sous-liste depuis le début", "LISTS_GET_SUBLIST_END_FROM_START": "jusqu’à #", "LISTS_GET_SUBLIST_END_FROM_END": "jusqu’à # depuis la fin", "LISTS_GET_SUBLIST_END_LAST": "jusqu’à la fin", "LISTS_GET_SUBLIST_TOOLTIP": "Crée une copie de la partie spécifiée d’une liste.", "VARIABLES_GET_TOOLTIP": "Renvoie la valeur de cette variable.", "VARIABLES_GET_CREATE_SET": "Créer 'fixer %1'", "VARIABLES_SET_TITLE": "fixer", "VARIABLES_SET_TAIL": "à", "VARIABLES_SET_TOOLTIP": "Fixe cette variable pour qu’elle soit égale à la valeur de l’entrée.", "VARIABLES_SET_CREATE_GET": "Créer 'obtenir %1'", "PROCEDURES_DEFNORETURN_TITLE": "à", "PROCEDURES_DEFNORETURN_PROCEDURE": "faire quelque chose", "PROCEDURES_BEFORE_PARAMS": "avec :", "PROCEDURES_DEFNORETURN_TOOLTIP": "Crée une fonction sans sortie.", "PROCEDURES_DEFRETURN_RETURN": "retour", "PROCEDURES_DEFRETURN_TOOLTIP": "Crée une fonction avec une sortie.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Attention : Cette fonction a des paramètres dupliqués.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_TOOLTIP": "Exécuter la fonction '%1' définie par l’utilisateur.", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Exécuter la fonction '%1' définie par l’utilisateur et utiliser son résultat.", "PROCEDURES_MUTATORCONTAINER_TITLE": "entrées", "PROCEDURES_MUTATORARG_TITLE": "nom de l’entrée :", "PROCEDURES_HIGHLIGHT_DEF": "Surligner la définition de la fonction", "PROCEDURES_CREATE_DO": "Créer '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Si une valeur est vraie, alors renvoyer une seconde valeur.", "PROCEDURES_IFRETURN_WARNING": "Attention : Ce bloc pourrait n’être utilisé que dans une définition de fonction." } ================================================ FILE: extern/blockly/msg/json/he.json ================================================ { "@metadata": { "authors": [ "Dorongol", "YaronSh", "Amire80", "Inkbug" ] }, "VARIABLES_DEFAULT_NAME": "פריט", "DUPLICATE_BLOCK": "שכפל", "ADD_COMMENT": "הוסף תגובה", "REMOVE_COMMENT": "הסר הערה", "EXTERNAL_INPUTS": "קלטים חיצוניים", "INLINE_INPUTS": "קלטים פנימיים", "DELETE_BLOCK": "מחק קטע קוד", "DELETE_X_BLOCKS": "מחק %1 קטעי קוד", "COLLAPSE_BLOCK": "צמצם קטע קוד", "COLLAPSE_ALL": "צמצם קטעי קוד", "EXPAND_BLOCK": "הרחב קטע קוד", "EXPAND_ALL": "הרחב קטעי קוד", "DISABLE_BLOCK": "נטרל קטע קוד", "ENABLE_BLOCK": "הפעל קטע קוד", "HELP": "עזרה", "CHANGE_VALUE_TITLE": "שנה ערך:", "NEW_VARIABLE": "משתנה חדש...", "NEW_VARIABLE_TITLE": "שם המשתנה החדש:", "RENAME_VARIABLE": "שנה את שם המשתנה...", "RENAME_VARIABLE_TITLE": "שנה את שם כל '%1' המשתנים ל:", "COLOUR_PICKER_HELPURL": "http://he.wikipedia.org/wiki/%D7%A6%D7%91%D7%A2", "COLOUR_PICKER_TOOLTIP": "בחר צבע מן הצבעים.", "COLOUR_RANDOM_TITLE": "צבע אקראי", "COLOUR_RANDOM_TOOLTIP": "בחר צבא אקראי.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "צבע עם", "COLOUR_RGB_RED": "אדום", "COLOUR_RGB_GREEN": "ירוק", "COLOUR_RGB_BLUE": "כחול", "COLOUR_RGB_TOOLTIP": "צור צבע עם הסכום המצוין של אדום, ירוק וכחול. כל הערכים חייבים להיות בין 0 ל100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "ערבב", "COLOUR_BLEND_COLOUR1": "צבע 1", "COLOUR_BLEND_COLOUR2": "צבע 2", "COLOUR_BLEND_RATIO": "יחס", "COLOUR_BLEND_TOOLTIP": "מערבב שני צבעים יחד עם יחס נתון(0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "http://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "חזור על הפעולה %1 פעמים", "CONTROLS_REPEAT_TITLE_REPEAT": "חזור", "CONTROLS_REPEAT_TITLE_TIMES": "פעמים", "CONTROLS_REPEAT_INPUT_DO": "תעשה", "CONTROLS_REPEAT_TOOLTIP": "תעשה כמה פעולות מספר פעמים.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "חזור כל עוד", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "חזור עד ש...", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "בזמן שהערך שווה לשגוי, תעשה מספר חישובים.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "בזמן שהערך שווה לשגוי, תעשה מספר חישובים.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Have the variable %1 take on the values from the start number to the end number, counting by the specified interval, and do the specified blocks.", "CONTROLS_FOR_INPUT_WITH": "תספור עם", "CONTROLS_FOR_INPUT_FROM_TO_BY": "מ- %1 ל- %2 עד- %3", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each", "CONTROLS_FOREACH_INPUT_ITEM": "לכל פריט", "CONTROLS_FOREACH_INPUT_INLIST": "ברשימה", "CONTROLS_FOREACH_TOOLTIP": "הגדר את המשתנה '%1' לכל פריט ברשימה, ולאחר מכן בצע כמה חישובים.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "צא מהלולאה", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "המשך עם האיטרציה הבאה של הלולאה", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "צא אל מחוץ ללולאה הכוללת.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "דלג על שאר הלולאה והמשך עם האיטרציה הבאה.", "CONTROLS_FLOW_STATEMENTS_WARNING": "אזהרה: בלוק זה עשוי לשמש רק בתוך לולאה.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "אם ערך נכון, בצע מספר חישובים.", "CONTROLS_IF_TOOLTIP_2": "אם הערך נכון, אז תבצע את הבלוק הראשון של הצהרות. אחרת, בצע את הבלוק השני של הצהרות.", "CONTROLS_IF_TOOLTIP_3": "אם הערך הראשון שווה לנכון, אז בצע את הבלוק הראשון של הצהרות. אחרת, אם הערך השני נכון, בצע את הבלוק השני של הצהרות.", "CONTROLS_IF_TOOLTIP_4": "אם הערך הראשון נכון, אז תבצע את הבלוק הראשון של הצהרות. אחרת, אם הערך השני נכון, בצע את הבלוק השני של הצהרות. אם אף אחד מהם לא נכון, בצע את הבלוק האחרון של הצהרות.", "CONTROLS_IF_MSG_IF": "אם", "CONTROLS_IF_MSG_ELSEIF": "אחרת אם", "CONTROLS_IF_MSG_ELSE": "אחרת", "CONTROLS_IF_IF_TOOLTIP": "תוסיף, תמחק, או תסדר מחדש כדי להגדיר מחדש את הבלוק If.", "CONTROLS_IF_ELSEIF_TOOLTIP": "תוסיף תנאי לבלוק If.", "CONTROLS_IF_ELSE_TOOLTIP": "לסיום, כל התנאים תקפים לגבי בלוק If.", "LOGIC_COMPARE_HELPURL": "http://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "תחזיר נכון אם שני הקלטים שווים אחד לשני.", "LOGIC_COMPARE_TOOLTIP_NEQ": "תחזיר אמת אם שני הקלטים אינם שווים זה לזה.", "LOGIC_COMPARE_TOOLTIP_LT": "תחזיר אמת (true) אם הקלט הראשון הוא קטן יותר מאשר הקלט השני.", "LOGIC_COMPARE_TOOLTIP_LTE": "תחזיר אמת אם הקלט הראשון הוא קטן יותר או שווה לקלט השני.", "LOGIC_COMPARE_TOOLTIP_GT": "תחזיר נכון אם הקלט הראשון גדול יותר מהקלט השני.", "LOGIC_COMPARE_TOOLTIP_GTE": "תחזיר נכון אם הקלט הראשון גדול יותר או שווה לכניסה השנייה.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "תחזיר נכון אם שני הקלטים נכונים.", "LOGIC_OPERATION_AND": "ו", "LOGIC_OPERATION_TOOLTIP_OR": "תחזיר נכון אם מתקיים לפחות אחד מהקלטים נכונים.", "LOGIC_OPERATION_OR": "או", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "לא %1", "LOGIC_NEGATE_TOOLTIP": "Returns true if the input is false. Returns false if the input is true.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "נכון", "LOGIC_BOOLEAN_FALSE": "שגוי", "LOGIC_BOOLEAN_TOOLTIP": "תחזיר אם נכון או אם שגוי.", "LOGIC_NULL_HELPURL": "http://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "null", "LOGIC_NULL_TOOLTIP": "תחזיר ריק.", "LOGIC_TERNARY_HELPURL": "http://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "בדיקה", "LOGIC_TERNARY_IF_TRUE": "אם נכון", "LOGIC_TERNARY_IF_FALSE": "אם שגוי", "LOGIC_TERNARY_TOOLTIP": "בדוק את התנאי ב'מבחן'. אם התנאי נכון, תחזיר את הערך 'אם נכון'; אחרת תחזיר את הערך 'אם שגוי'.", "MATH_NUMBER_HELPURL": "http://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "מספר.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "×", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "asin", "MATH_TRIG_ACOS": "acos", "MATH_TRIG_ATAN": "atan", "MATH_ARITHMETIC_HELPURL": "http://he.wikipedia.org/wiki/%D7%90%D7%A8%D7%99%D7%AA%D7%9E%D7%98%D7%99%D7%A7%D7%94", "MATH_ARITHMETIC_TOOLTIP_ADD": "תחזיר את סכום שני המספרים.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Return the difference of the two numbers.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Return the product of the two numbers.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Return the quotient of the two numbers.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Return the first number raised to the power of the second number.", "MATH_SINGLE_HELPURL": "http://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "square root", "MATH_SINGLE_TOOLTIP_ROOT": "Return the square root of a number.", "MATH_SINGLE_OP_ABSOLUTE": "ערך מוחלט", "MATH_SINGLE_TOOLTIP_ABS": "Return the absolute value of a number.", "MATH_SINGLE_TOOLTIP_NEG": "Return the negation of a number.", "MATH_SINGLE_TOOLTIP_LN": "Return the natural logarithm of a number.", "MATH_SINGLE_TOOLTIP_LOG10": "Return the base 10 logarithm of a number.", "MATH_SINGLE_TOOLTIP_EXP": "Return e to the power of a number.", "MATH_SINGLE_TOOLTIP_POW10": "Return 10 to the power of a number.", "MATH_TRIG_HELPURL": "http://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "Return the sine of a degree (not radian).", "MATH_TRIG_TOOLTIP_COS": "Return the cosine of a degree (not radian).", "MATH_TRIG_TOOLTIP_TAN": "Return the tangent of a degree (not radian).", "MATH_TRIG_TOOLTIP_ASIN": "Return the arcsine of a number.", "MATH_TRIG_TOOLTIP_ACOS": "Return the arccosine of a number.", "MATH_TRIG_TOOLTIP_ATAN": "Return the arctangent of a number.", "MATH_CONSTANT_HELPURL": "http://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "Return one of the common constants: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (infinity).", "MATH_IS_EVEN": "זוגי", "MATH_IS_ODD": "אי-זוגי", "MATH_IS_PRIME": "ראשוני", "MATH_IS_WHOLE": "שלם", "MATH_IS_POSITIVE": "חיובי", "MATH_IS_NEGATIVE": "שלילי", "MATH_IS_DIVISIBLE_BY": "מתחלק ב", "MATH_IS_TOOLTIP": "Check if a number is an even, odd, prime, whole, positive, negative, or if it is divisible by certain number. Returns true or false.", "MATH_CHANGE_HELPURL": "http://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "שנה", "MATH_CHANGE_INPUT_BY": "by", "MATH_CHANGE_TOOLTIP": "הוסף מספר למשתנה '%1'.", "MATH_ROUND_HELPURL": "http://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Round a number up or down.", "MATH_ROUND_OPERATOR_ROUND": "עיגול", "MATH_ROUND_OPERATOR_ROUNDUP": "עיגול למעלה", "MATH_ROUND_OPERATOR_ROUNDDOWN": "עיגול למטה", "MATH_ONLIST_OPERATOR_SUM": "סכום של רשימה", "MATH_ONLIST_TOOLTIP_SUM": "Return the sum of all the numbers in the list.", "MATH_ONLIST_OPERATOR_MIN": "מינימום של רשימה", "MATH_ONLIST_TOOLTIP_MIN": "תחזיר את המספר הקטן ביותר ברשימה.", "MATH_ONLIST_OPERATOR_MAX": "מקסימום של רשימה", "MATH_ONLIST_TOOLTIP_MAX": "תחזיר את המספר הגדול ביותר ברשימה.", "MATH_ONLIST_OPERATOR_AVERAGE": "ממוצע של רשימה", "MATH_ONLIST_TOOLTIP_AVERAGE": "Return the average (arithmetic mean) of the numeric values in the list.", "MATH_ONLIST_OPERATOR_MEDIAN": "median of list", "MATH_ONLIST_TOOLTIP_MEDIAN": "תחזיר את המספר החיצוני ביותר ברשימה.", "MATH_ONLIST_OPERATOR_MODE": "modes of list", "MATH_ONLIST_TOOLTIP_MODE": "Return a list of the most common item(s) in the list.", "MATH_ONLIST_OPERATOR_STD_DEV": "standard deviation of list", "MATH_ONLIST_TOOLTIP_STD_DEV": "Return the standard deviation of the list.", "MATH_ONLIST_OPERATOR_RANDOM": "פריט אקראי מרשימה", "MATH_ONLIST_TOOLTIP_RANDOM": "תחזיר רכיב אקראי מרשימה.", "MATH_MODULO_HELPURL": "http://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "שארית החילוק %1 ÷ %2", "MATH_MODULO_TOOLTIP": "החזרת השארית מחלוקת שני המספרים.", "MATH_CONSTRAIN_HELPURL": "http://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "constrain %1 low %2 high %3", "MATH_CONSTRAIN_TOOLTIP": "Constrain a number to be between the specified limits (inclusive).", "MATH_RANDOM_INT_HELPURL": "http://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "random integer from %1 to %2", "MATH_RANDOM_INT_TOOLTIP": "Return a random integer between the two specified limits, inclusive.", "MATH_RANDOM_FLOAT_HELPURL": "http://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "random fraction", "MATH_RANDOM_FLOAT_TOOLTIP": "Return a random fraction between 0.0 (inclusive) and 1.0 (exclusive).", "TEXT_TEXT_HELPURL": "http://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "A letter, word, or line of text.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "create text with", "TEXT_JOIN_TOOLTIP": "Create a piece of text by joining together any number of items.", "TEXT_CREATE_JOIN_TITLE_JOIN": "join", "TEXT_CREATE_JOIN_TOOLTIP": "Add, remove, or reorder sections to reconfigure this text block.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Add an item to the text.", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "to", "TEXT_APPEND_APPENDTEXT": "append text", "TEXT_APPEND_TOOLTIP": "Append some text to variable '%1'.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "length of %1", "TEXT_LENGTH_TOOLTIP": "Returns the number of letters (including spaces) in the provided text.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 is empty", "TEXT_ISEMPTY_TOOLTIP": "Returns true if the provided text is empty.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Returns the index of the first/last occurrence of first text in the second text. Returns 0 if text is not found.", "TEXT_INDEXOF_INPUT_INTEXT": "in text", "TEXT_INDEXOF_OPERATOR_FIRST": "find first occurrence of text", "TEXT_INDEXOF_OPERATOR_LAST": "find last occurrence of text", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "in text", "TEXT_CHARAT_FROM_START": "get letter #", "TEXT_CHARAT_FROM_END": "get letter # from end", "TEXT_CHARAT_FIRST": "get first letter", "TEXT_CHARAT_LAST": "get last letter", "TEXT_CHARAT_RANDOM": "get random letter", "TEXT_CHARAT_TOOLTIP": "Returns the letter at the specified position.", "TEXT_GET_SUBSTRING_TOOLTIP": "Returns a specified portion of the text.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "in text", "TEXT_GET_SUBSTRING_START_FROM_START": "get substring from letter #", "TEXT_GET_SUBSTRING_START_FROM_END": "get substring from letter # from end", "TEXT_GET_SUBSTRING_START_FIRST": "get substring from first letter", "TEXT_GET_SUBSTRING_END_FROM_START": "to letter #", "TEXT_GET_SUBSTRING_END_FROM_END": "to letter # from end", "TEXT_GET_SUBSTRING_END_LAST": "to last letter", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Return a copy of the text in a different case.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "to UPPER CASE", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "to lower case", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "to Title Case", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Return a copy of the text with spaces removed from one or both ends.", "TEXT_TRIM_OPERATOR_BOTH": "למחוק רווחים משני הקצוות", "TEXT_TRIM_OPERATOR_LEFT": "למחוק רווחים מימין", "TEXT_TRIM_OPERATOR_RIGHT": "למחוק רווחים משמאל", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "print %1", "TEXT_PRINT_TOOLTIP": "Print the specified text, number or other value.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "prompt for text with message", "TEXT_PROMPT_TYPE_NUMBER": "prompt for number with message", "TEXT_PROMPT_TOOLTIP_NUMBER": "Prompt for user for a number.", "TEXT_PROMPT_TOOLTIP_TEXT": "Prompt for user for some text.", "LISTS_CREATE_EMPTY_HELPURL": "http://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "צור רשימה ריקה", "LISTS_CREATE_EMPTY_TOOLTIP": "החזר רשימה,באורך 0, המכילה רשומות נתונים", "LISTS_CREATE_WITH_TOOLTIP": "צור רשימה עם כל מספר של פריטים.", "LISTS_CREATE_WITH_INPUT_WITH": "צור רשימה עם", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "רשימה", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "תוסיף, תמחק, או תסדר מחדש כדי להגדיר מחדש את הבלוק If.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "הוסף פריט לרשימה.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "יוצר רשימה המורכבת מהערך נתון חוזר מספר פעמים שצוין.", "LISTS_REPEAT_TITLE": "ליצור רשימה עם הפריט %1 %2 פעמים", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "אורכו של %1", "LISTS_LENGTH_TOOLTIP": "מחזירה את האורך של רשימה.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 הוא ריק", "LISTS_TOOLTIP": "מחזיר אמת אם הרשימה ריקה.", "LISTS_INLIST": "ברשימה", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "מחזירה את המיקום הראשון של פריט ברשימה", "LISTS_INDEX_OF_LAST": "מחזירה את המיקום האחרון של פריט ברשימה", "LISTS_INDEX_OF_TOOLTIP": "מחזירה את האינדקס של המופע ראשון/אחרון של הפריט ברשימה. מחזירה 0 אם טקסט אינו נמצא.", "LISTS_GET_INDEX_GET": "לקבל", "LISTS_GET_INDEX_GET_REMOVE": "קבל ומחק", "LISTS_GET_INDEX_REMOVE": "הסרה", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# מהסוף", "LISTS_GET_INDEX_FIRST": "ראשון", "LISTS_GET_INDEX_LAST": "אחרון", "LISTS_GET_INDEX_RANDOM": "אקראי", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "מחזיר פריט במיקום שצוין ברשימה. #1 הוא הפריט הראשון.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "מחזיר פריט במיקום שצוין ברשימה. #1 הוא הפריט האחרון.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "מחזיר את הפריט הראשון ברשימה.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "מחזיר את הפריט האחרון ברשימה.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "מחזיר פריט אקראי מהרשימה.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "מסיר ומחזיר את הפריט במיקום שצוין ברשימה. #1 הוא הפריט הראשון.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "מסיר ומחזיר את הפריט במיקום שצוין ברשימה. #1 הוא הפריט האחרון.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "מסיר ומחזיר את הפריט הראשון ברשימה.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "מסיר ומחזיר את הפריט האחרון ברשימה.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "מחק והחזר פריט אקראי מהרשימה.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "מחזיר פריט במיקום שצוין ברשימה. #1 הוא הפריט הראשון.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "מחזיר פריט במיקום שצוין ברשימה. #1 הוא הפריט האחרון.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "הסר את הפריט הראשון ברשימה.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "הסר את הפריט הראשון ברשימה.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "הסר פריט אקראי ברשימה.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "הגדר", "LISTS_SET_INDEX_INSERT": "הכנס ב", "LISTS_SET_INDEX_INPUT_TO": "כמו", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "מגדיר את הפריט במיקום שצוין ברשימה. #1 הוא הפריט הראשון.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "מגדיר את הפריט במיקום שצוין ברשימה. #1 הוא הפריט האחרון.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "מגדיר את הפריט הראשון ברשימה.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "מגדיר את הפריט האחרון ברשימה.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "מגדיר פריט אקראי ברשימה.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "מכניס את הפריט במיקום שצוין ברשימה. #1 הוא הפריט הראשון.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "מכניס את הפריט במיקום שצוין ברשימה. #1 הוא הפריט האחרון.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "מכניס את הפריט בתחילת רשימה.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "מוסיף את הפריט בסוף רשימה.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "הוסף פריט באופן אקראי ברשימה.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "מחזירה חלק מהרשימה החל מ-#", "LISTS_GET_SUBLIST_START_FROM_END": "מחזירה חלק מהרשימה החל מ-# עד הסוף", "LISTS_GET_SUBLIST_START_FIRST": "get sub-list from first", "LISTS_GET_SUBLIST_END_FROM_START": "ל #", "LISTS_GET_SUBLIST_END_FROM_END": "ל # מהסוף", "LISTS_GET_SUBLIST_END_LAST": "לאחרון", "LISTS_GET_SUBLIST_TOOLTIP": "יוצרת עותק של חלק מסוים מהרשימה.", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TOOLTIP": "Returns the value of this variable.", "VARIABLES_GET_CREATE_SET": "Create 'set %1'", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "set", "VARIABLES_SET_TAIL": "to", "VARIABLES_SET_TOOLTIP": "Sets this variable to be equal to the input.", "VARIABLES_SET_CREATE_GET": "Create 'get %1'", "PROCEDURES_DEFNORETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFNORETURN_TITLE": "to", "PROCEDURES_DEFNORETURN_PROCEDURE": "do something", "PROCEDURES_BEFORE_PARAMS": "with:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Creates a function with no output.", "PROCEDURES_DEFRETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFRETURN_RETURN": "return", "PROCEDURES_DEFRETURN_TOOLTIP": "Creates a function with an output.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Warning: This function has duplicate parameters.", "PROCEDURES_CALLNORETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_TOOLTIP": "Run the user-defined function '%1'.", "PROCEDURES_CALLRETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Run the user-defined function '%1' and use its output.", "PROCEDURES_MUTATORCONTAINER_TITLE": "מקורות קלט", "PROCEDURES_MUTATORARG_TITLE": "שם הקלט:", "PROCEDURES_HIGHLIGHT_DEF": "Highlight function definition", "PROCEDURES_CREATE_DO": "Create '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "If a value is true, then return a second value.", "PROCEDURES_IFRETURN_WARNING": "Warning: This block may be used only within a function definition." } ================================================ FILE: extern/blockly/msg/json/hi.json ================================================ { "@metadata": { "authors": [ "Bl707" ] }, "VARIABLES_DEFAULT_NAME": "आइटम", "DUPLICATE_BLOCK": "कॉपी करें", "ADD_COMMENT": "टिप्पणी छोड़ें", "REMOVE_COMMENT": "टिप्पणी हटायें", "EXTERNAL_INPUTS": "बाहरी इनपुट", "INLINE_INPUTS": "इनलाइन इनपुट", "DELETE_BLOCK": "ब्लॉक हटाएँ", "DELETE_X_BLOCKS": "%1 ब्लॉक हटाएँ", "COLLAPSE_BLOCK": "ब्लॉक को संक्षिप्त करें", "COLLAPSE_ALL": "ब्लॉक संक्षिप्त करें", "EXPAND_BLOCK": "ब्लॉक का विस्तार करें", "EXPAND_ALL": "ब्लॉक विस्तार करें", "DISABLE_BLOCK": "ब्लॉक को अक्षम करें", "ENABLE_BLOCK": "ब्लॉक को सक्षम करें", "HELP": "सहायता", "CHANGE_VALUE_TITLE": "मान परिवर्तित करें:", "NEW_VARIABLE": "नया चर...", "NEW_VARIABLE_TITLE": "नए चर का नाम:", "RENAME_VARIABLE": "चर का नाम बदलें...", "RENAME_VARIABLE_TITLE": "सभी '%1' चरों के नाम बदलें:", "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "पैलेट से एक रंग चुनें।", "COLOUR_RANDOM_TITLE": "रैन्डम रंग", "COLOUR_RANDOM_TOOLTIP": "रैन्डम्ली एक रंग चयन करें।", "COLOUR_RGB_TITLE": "इसके साथ रंग करें", "COLOUR_RGB_RED": "लाल", "COLOUR_RGB_GREEN": "हरा", "COLOUR_RGB_BLUE": "नीला", "COLOUR_BLEND_TITLE": "मिश्रण करें", "COLOUR_BLEND_COLOUR1": "रंग 1", "COLOUR_BLEND_COLOUR2": "रंग 2", "COLOUR_BLEND_RATIO": "अनुपात", "COLOUR_BLEND_TOOLTIP": "दिए गए अनुपात (0.0 - 1.0) के साथ दो रंगों का मिश्रण करता है।", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "%1 बार दोहराएँ", "CONTROLS_REPEAT_TITLE_REPEAT": "दोहराएँ", "CONTROLS_REPEAT_TITLE_TIMES": "इतनी बार", "CONTROLS_REPEAT_INPUT_DO": "डू", "CONTROLS_REPEAT_TOOLTIP": "कुछ स्टेट्मन्ट कई बार चलाएँ।", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "दोहराएँ जब कि", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "दोहराएँ जब तक", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "जब तक मान ट्रू है, तब तक कुछ स्टेट्मेंट्स चलाएँ।", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "जब तक मान फॉल्स है, तब तक कुछ स्टेट्मेंट्स चलाएँ।", "CONTROLS_FOR_INPUT_WITH": "काउंट करें", "CONTROLS_FOREACH_INPUT_ITEM": "प्रत्येक आइटम के लिए", "CONTROLS_FOREACH_INPUT_INLIST": "सूची में", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "लूप से बाहर निकलें", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "लूप का अगला आईटरेशन जारी रखें", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "भीतरी लूप से बाहर निकलें।", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "बाकी बचे लूप को छोड़ें, और अगला आईटरेशन जारी रखें।", "CONTROLS_FLOW_STATEMENTS_WARNING": "सावधान: ये ब्लॉक केवल लूप के अंदर इस्तेमाल किया जा सकता है।", "CONTROLS_IF_TOOLTIP_1": "यदी मान ट्रू है, तो कुछ स्टेट्मेंट्स चलाएँ।", "CONTROLS_IF_MSG_IF": "इफ", "CONTROLS_IF_MSG_ELSEIF": "एल्स इफ", "CONTROLS_IF_MSG_ELSE": "एल्स", "CONTROLS_IF_ELSEIF_TOOLTIP": "यदि ब्लॉक मे एक शर्त जोड़ें।", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "ट्रू रिटर्न करें यदि दोनो इनपुट इक दूसरे के बराबर हों।", "LOGIC_COMPARE_TOOLTIP_NEQ": "ट्रू रिटर्न करें यदि दोनो इनपुट इक दूसरे के बराबर नहीं हों।", "LOGIC_COMPARE_TOOLTIP_LT": "ट्रू रिटर्न करें यदि पहला इनपुट दूसरे इनपुट से छोटा हो।", "LOGIC_COMPARE_TOOLTIP_LTE": "ट्रू रिटर्न करें यदि पहला इनपुट दूसरे इनपुट से छोटा हो या बराबर हो।", "LOGIC_COMPARE_TOOLTIP_GT": "ट्रू रिटर्न करें यदि पहला इनपुट दूसरे इनपुट से बड़ा हो।", "LOGIC_COMPARE_TOOLTIP_GTE": "ट्रू रिटर्न करें यदि पहला इनपुट दूसरे इनपुट से बड़ा हो या बराबर हो।", "LOGIC_OPERATION_TOOLTIP_AND": "ट्रू रिटर्न करें यदि दोनो इनपुट ट्रू हों।", "LOGIC_OPERATION_AND": "AND (तथा)", "LOGIC_OPERATION_TOOLTIP_OR": "ट्रू रिटर्न करें यदि दोनो मे से इक इनपुट ट्रू हो।", "LOGIC_OPERATION_OR": "OR (अथवा)", "LOGIC_NEGATE_TITLE": "NOT (पूरक) %1", "LOGIC_NEGATE_TOOLTIP": "ट्रू रिटर्न करता है यदि इनपुट फॉल्स है। फॉल्स रिटर्न करता है यदि इनपुट ट्रू है।", "LOGIC_BOOLEAN_TRUE": "ट्रू", "LOGIC_BOOLEAN_FALSE": "फॉल्स", "LOGIC_BOOLEAN_TOOLTIP": "ट्रू या फॉल्स रिटर्न करता है।", "LOGIC_NULL": "NULL (अमान्य)", "LOGIC_NULL_TOOLTIP": "null (अमान्य) रिटर्न करता है।", "LOGIC_TERNARY_CONDITION": "टेस्ट", "LOGIC_TERNARY_IF_TRUE": "यदि ट्रू है", "LOGIC_TERNARY_IF_FALSE": "यदि फॉल्स है", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "एक संख्या।", "MATH_ARITHMETIC_HELPURL": "https://en.wikipedia.org/wiki/Arithmetic", "MATH_ARITHMETIC_TOOLTIP_ADD": "दो संख्याओं का योग रिटर्न करें।", "MATH_ARITHMETIC_TOOLTIP_MINUS": "दो संख्याओं का अंतर रिटर्न करें।", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "दो संख्याओं का गुणन रिटर्न करें।", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "दो संख्याओं का भागफल रिटर्न करें।", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "वर्गमूल", "MATH_SINGLE_TOOLTIP_ROOT": "संख्या का वर्गमूल रिटर्न करें।", "MATH_SINGLE_OP_ABSOLUTE": "परम", "MATH_SINGLE_TOOLTIP_ABS": "संख्या का परम मान रिटर्न करें।", "MATH_SINGLE_TOOLTIP_NEG": "संख्या का निषेध मान रिटर्न करें।", "MATH_SINGLE_TOOLTIP_LN": "संख्या का प्राकृतिक लघुगणक रिटर्न करें।", "MATH_SINGLE_TOOLTIP_LOG10": "संख्या का मूल 10 लघुगणक रिटर्न करें।", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "डिग्री का साइन रिटर्न करें (रेडियन नही)", "MATH_TRIG_TOOLTIP_COS": "डिग्री का कोसाइन रिटर्न करें (रेडियन नही)", "MATH_TRIG_TOOLTIP_TAN": "डिग्री का टैन्जन्ट रिटर्न करें (रेडियन नही)", "MATH_TRIG_TOOLTIP_ASIN": "संख्या का आर्कसाइन रिटर्न करें।", "MATH_TRIG_TOOLTIP_ACOS": "संख्या का आर्ककोसाइन रिटर्न करें।", "MATH_TRIG_TOOLTIP_ATAN": "संख्या का आर्कटैन्जन्ट रिटर्न करें।", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_IS_EVEN": "सम है", "MATH_IS_ODD": "विषम है", "MATH_IS_PRIME": "अभाज्य है", "MATH_IS_WHOLE": "पूर्णांक है", "MATH_IS_POSITIVE": "धनात्मक है", "MATH_IS_NEGATIVE": "ऋणात्मक है", "MATH_IS_DIVISIBLE_BY": "इसके द्वारा विभाज्य है", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "बदलें", "MATH_CHANGE_TOOLTIP": "संख्या को चर '%1' से जोड़ें।", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "संख्या को बड़ा या घटा के पूर्णांक बनाएँ।", "MATH_ROUND_OPERATOR_ROUND": "पूर्णांक बनाएँ", "MATH_ROUND_OPERATOR_ROUNDUP": "बड़ा के पूर्णांक बनाएँ", "MATH_ROUND_OPERATOR_ROUNDDOWN": "घटा के पूर्णांक बनाएँ", "MATH_ONLIST_OPERATOR_SUM": "सूची का योग", "MATH_ONLIST_TOOLTIP_SUM": "सूची की सभी संख्याओं का योग रिटर्न करें।", "MATH_ONLIST_OPERATOR_MIN": "सूची मे न्यूनतम", "MATH_ONLIST_TOOLTIP_MIN": "सूची मे सबसे छोटी संख्या रिटर्न करें।", "MATH_ONLIST_OPERATOR_MAX": "सूची मे अधिकतम", "MATH_ONLIST_TOOLTIP_MAX": "सूची मे सबसे बड़ी संख्या रिटर्न करें।", "MATH_ONLIST_OPERATOR_AVERAGE": "सूची का औसत मान", "MATH_ONLIST_OPERATOR_MEDIAN": "सूची की माध्यिका", "MATH_ONLIST_TOOLTIP_MEDIAN": "सूची की माध्यिका संख्या रिटर्न करें।", "MATH_ONLIST_OPERATOR_MODE": "सूची का मोड", "MATH_ONLIST_TOOLTIP_MODE": "सूची मे सबसे आम आइटम(s) की सूची रिटर्न करें।", "MATH_ONLIST_OPERATOR_STD_DEV": "सूची का मानक विचलन", "MATH_ONLIST_TOOLTIP_STD_DEV": "सूची का मानक विचलन रिटर्न करें।", "MATH_ONLIST_OPERATOR_RANDOM": "सूची का रैन्डम आइटम", "MATH_ONLIST_TOOLTIP_RANDOM": "सूची से एक रैन्डम आइटम रिटर्न करें।", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "%1 ÷ %2 का शेषफल", "MATH_MODULO_TOOLTIP": "दो संख्याओं के भाग का शेषफल रिटर्न करें।", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "%1 से % 2 तक रैन्डम पूर्णांक", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "रैन्डम अंश", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "एक अक्षर, शब्द, या टेक्स्ट की पंक्ति।", "TEXT_JOIN_TITLE_CREATEWITH": "इसके साथ टेक्स्ट बनाएँ", "TEXT_CREATE_JOIN_TITLE_JOIN": "जोड़", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "सूची मे एक आइटम जोड़ें।", "TEXT_APPEND_TO": "इस", "TEXT_APPEND_APPENDTEXT": "से जोड़ें ये टेक्स्ट", "TEXT_APPEND_TOOLTIP": "कुछ टेक्स्ट इस चर '%1' से जोड़ें।", "TEXT_LENGTH_TITLE": "%1 की लंबाई", "TEXT_LENGTH_TOOLTIP": "दिए गये टेक्स्ट मे अक्षरों की संख्या रिटर्न करता है (खाली स्थान मिला के)।", "TEXT_ISEMPTY_TITLE": "%1 खाली है", "TEXT_ISEMPTY_TOOLTIP": "ट्रू रिटर्न करता है यदि दिया गया टेक्स्ट खाली है।", "TEXT_INDEXOF_INPUT_INTEXT": "इस टेक्स्ट मे", "TEXT_INDEXOF_OPERATOR_FIRST": "टेक्स्ट पहली बार जहाँ आया है उसे ढूढ़े", "TEXT_INDEXOF_OPERATOR_LAST": "टेक्स्ट आखरी बार जहाँ आया है उसे ढूढ़े", "TEXT_CHARAT_INPUT_INTEXT": "इस टेक्स्ट मे", "TEXT_CHARAT_FROM_START": "अक्षर # पाएँ", "TEXT_CHARAT_FROM_END": "आखिर से अक्षर # पाएँ", "TEXT_CHARAT_FIRST": "पहला अक्षर पाएँ", "TEXT_CHARAT_LAST": "आखरी अक्षर पाएँ", "TEXT_CHARAT_RANDOM": "रैन्डम अक्षर पाएँ", "TEXT_CHARAT_TOOLTIP": "बताई गयी जगह से अक्षर रिटर्न करता है", "TEXT_GET_SUBSTRING_TOOLTIP": "टेक्स्ट का बताया गया अंश रिटर्न करता है", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "इस टेक्स्ट मे", "TEXT_GET_SUBSTRING_START_FROM_START": "अक्षर # से सबस्ट्रिंग पाएँ", "TEXT_GET_SUBSTRING_START_FROM_END": "आखरी अक्षर # से सबस्ट्रिंग पाएँ", "TEXT_GET_SUBSTRING_START_FIRST": "पहले अक्षर से सबस्ट्रिंग पाएँ", "TEXT_GET_SUBSTRING_END_FROM_START": "यहाँ तक अक्षर #", "TEXT_GET_SUBSTRING_END_FROM_END": "आखिर से यहाँ तक अक्षर #", "TEXT_GET_SUBSTRING_END_LAST": "यहाँ तक आखरी अक्षर", "TEXT_CHANGECASE_TOOLTIP": "टेक्स्ट की कॉपी भिन्न केस (अक्षर से संबंधित) मे रिटर्न करें।", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "बड़े अक्षर मे", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "छोटे अक्षर मे", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "टाइटल केस मे", "TEXT_TRIM_OPERATOR_BOTH": "रिक्त स्थान को इस टेक्स्ट के दोनों तरफ से निकालें", "TEXT_TRIM_OPERATOR_LEFT": "रिक्त स्थान को इस टेक्स्ट के बायें तरफ से निकालें", "TEXT_TRIM_OPERATOR_RIGHT": "रिक्त स्थान को इस टेक्स्ट के दाईं तरफ से निकालें", "TEXT_PRINT_TITLE": "प्रिंट करें %1", "TEXT_PRINT_TOOLTIP": "दिया गया टेक्स्ट प्रिंट करें, संख्या या अन्य मान।", "TEXT_PROMPT_TYPE_TEXT": "सूचना के साथ टेक्स्ट के लिए प्रॉम्प्ट करें", "TEXT_PROMPT_TYPE_NUMBER": "सूचना के साथ संख्या के लिए प्रॉम्प्ट करें", "TEXT_PROMPT_TOOLTIP_NUMBER": "यूज़र से संख्या के लिए प्रॉम्प्ट करें।", "TEXT_PROMPT_TOOLTIP_TEXT": "यूज़र से कुछ टेक्स्ट के लिए प्रॉम्प्ट करें।", "LISTS_CREATE_EMPTY_TITLE": "खाली सूची बनाएँ", "LISTS_CREATE_WITH_TOOLTIP": "कितने भी आइटम वाली एक सूची बनाएँ।", "LISTS_CREATE_WITH_INPUT_WITH": "इसके सूची बनाएँ", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "सूची", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "सूची मे एक आइटम जोड़ें।", "LISTS_LENGTH_TITLE": "%1 की लंबाई", "LISTS_LENGTH_TOOLTIP": "सूची की लंबाई रिटर्न करता है।", "LISTS_IS_EMPTY_TITLE": "%1 खाली है", "LISTS_TOOLTIP": "यदि सूची खाली है तो ट्रू रिटर्न करता है।", "LISTS_INLIST": "सूची में", "LISTS_INDEX_OF_FIRST": "आइटम पहली बार जहाँ आया है उसे ढूढ़े", "LISTS_INDEX_OF_LAST": "आइटम आखरी बार जहाँ आया है उसे ढूढ़े", "LISTS_GET_INDEX_REMOVE": "निकालें", "LISTS_GET_INDEX_FROM_END": "अंत से #", "LISTS_GET_INDEX_FIRST": "पहला", "LISTS_GET_INDEX_LAST": "आखिरी", "LISTS_GET_INDEX_RANDOM": "रैन्डम", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "सूची का पहला आइटम रिटर्न करता है।", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "सूची का आखरी आइटम रिटर्न करता है।", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "सूची से रैन्डम आइटम रिटर्न करता है।", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "सूची का पहला आइटम निकालता है और रिटर्न करता है।", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "सूची का आखरी आइटम निकालता है और रिटर्न करता है।", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "सूची से रैन्डम आइटम निकालता है और रिटर्न करता है।", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "सूची का पहला आइटम निकालता है।", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "सूची का आखरी आइटम निकालता है।", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "सूची से रैन्डम आइटम निकालता है।", "LISTS_SET_INDEX_SET": "सैट करें", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "सूची मे बताए गये स्थान में आइटम सैट करता है। #1 पहला आइटम है।", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "सूची मे बताए गये स्थान में आइटम सैट करता है। #1 आखरी आइटम है।", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "सूची में पहला आइटम सैट करता है।", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "सूची में आखरी आइटम सैट करता है।", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "सूची में रैन्डम आइटम सैट करता है।", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "सूची मे बताए गये स्थान में आइटम इनसर्ट करता है। #1 पहला आइटम है।", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "सूची मे बताए गये स्थान में आइटम इनसर्ट करता है। #1 आखरी आइटम है।", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "आइटम को सूची के शुरू में इनसर्ट करता है।", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "आइटम को सूची के अंत में जोड़ता है।", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "आइटम को सूची में रैन्डम्ली इनसर्ट करता है।", "LISTS_GET_SUBLIST_TOOLTIP": "सूची के बताए गये भाग की कॉपी बनता है।", "VARIABLES_GET_TOOLTIP": "इस चर का मान रिटर्न करता है।", "VARIABLES_GET_CREATE_SET": "सेट '%1' बनाएँ", "VARIABLES_SET_TITLE": "सेट करें", "VARIABLES_SET_TAIL": "को", "VARIABLES_SET_TOOLTIP": "इस चर को इनपुट के बराबर सेट करता है।", "PROCEDURES_DEFNORETURN_PROCEDURE": "कुछ करें", "PROCEDURES_BEFORE_PARAMS": ": के साथ", "PROCEDURES_DEFNORETURN_TOOLTIP": "बिना आउटपुट वाला एक फ़ंक्शन बनाता है।", "PROCEDURES_DEFRETURN_RETURN": "रिटर्न", "PROCEDURES_DEFRETURN_TOOLTIP": "आउटपुट वाला एक फ़ंक्शन बनाता है।", "PROCEDURES_DEF_DUPLICATE_WARNING": "सावधान: इस फ़ंक्शन मे डुप्लिकेट पैरामीटर हैं।", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_TOOLTIP": "यूज़र द्वारा वर्णन किया गया फ़ंक्शन '%1' चलाएँ।", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "यूज़र द्वारा वर्णन किया गया फ़ंक्शन '%1' चलाएँ और उसका आउटपुट इस्तेमाल करें।", "PROCEDURES_MUTATORCONTAINER_TITLE": "इनपुट", "PROCEDURES_MUTATORARG_TITLE": "इनपुट का नाम:", "PROCEDURES_HIGHLIGHT_DEF": "फ़ंक्शन परिभाषा को हाइलाइट करें", "PROCEDURES_CREATE_DO": "'%1' बनाएँ", "PROCEDURES_IFRETURN_TOOLTIP": "यदि एक मान ट्रू है तो, दूसरा मान रिटर्न करें।", "PROCEDURES_IFRETURN_WARNING": "सावधान: ये ब्लॉक फ़ंक्शन परिभाषा के अंदर ही इस्तेमाल किया जा सकता।" } ================================================ FILE: extern/blockly/msg/json/hu.json ================================================ { "@metadata": { "authors": [ "Espertus", "Takács Viktor László" ] }, "VARIABLES_DEFAULT_NAME": "változó", "DUPLICATE_BLOCK": "Másolat", "ADD_COMMENT": "Megjegyzés hozzáadása", "REMOVE_COMMENT": "Megjegyzés tölése", "EXTERNAL_INPUTS": "Külső kapcsolatok", "INLINE_INPUTS": "Belső kapcsolatok", "DELETE_BLOCK": "Töröl", "DELETE_X_BLOCKS": "%1 blokk törlése", "COLLAPSE_BLOCK": "Összezár", "COLLAPSE_ALL": "Összezár", "EXPAND_BLOCK": "Kibont", "EXPAND_ALL": "Kinyit", "DISABLE_BLOCK": "Letilt", "ENABLE_BLOCK": "Engedélyez", "HELP": "Sugó", "CHANGE_VALUE_TITLE": "Érték módosítása:", "NEW_VARIABLE": "Új...", "NEW_VARIABLE_TITLE": "Az új változó neve:", "RENAME_VARIABLE": "Átnevezés...", "RENAME_VARIABLE_TITLE": "\"%1\" változó átnevezése:", "COLOUR_PICKER_HELPURL": "https://hu.wikipedia.org/wiki/Szín", "COLOUR_PICKER_TOOLTIP": "Válassz színt a palettáról.", "COLOUR_RANDOM_TITLE": "Véletlen szín", "COLOUR_RANDOM_TOOLTIP": "Véletlenszerűen kiválasztott szín.", "COLOUR_RGB_TITLE": "Szín", "COLOUR_RGB_RED": "vörös", "COLOUR_RGB_GREEN": "zöld", "COLOUR_RGB_BLUE": "kék", "COLOUR_RGB_TOOLTIP": "Szín előállítása a megadott vörös, zöld, és kék értékekkel. Minden értéknek 0 és 100 közé kell esnie.", "COLOUR_BLEND_TITLE": "Színkeverés", "COLOUR_BLEND_COLOUR1": "", "COLOUR_BLEND_COLOUR2": "+", "COLOUR_BLEND_RATIO": "arány:", "COLOUR_BLEND_TOOLTIP": "Két színt kever össze a megadott arányban (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://hu.wikipedia.org/wiki/Ciklus_(programoz%C3%A1s)#Sz.C3.A1ml.C3.A1l.C3.B3s_.28FOR.29_ciklus", "CONTROLS_REPEAT_TITLE": "Ismételd %1 alkalommal", "CONTROLS_REPEAT_TITLE_REPEAT": "Ismételd", "CONTROLS_REPEAT_TITLE_TIMES": "alkalommal", "CONTROLS_REPEAT_INPUT_DO": "", "CONTROLS_REPEAT_TOOLTIP": "Megadott kódrészlet ismételt végrehajtása.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "ismételd amíg igazː", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "amíg nem", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Amíg a feltétel igaz, végrehajtja az utasításokat.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Amíg a feltétel hamis, végrehajtja az utasításokat.", "CONTROLS_FOR_TOOLTIP": "Véges lépésszámú ciklus. A \"%1\" változó értékét számolja ki a kezdőérték és a végérték között. Minden lépésben végrehajtódnak az utasítások.", "CONTROLS_FOR_INPUT_WITH": "Számold ki", "CONTROLS_FOR_INPUT_FROM_TO_BY": "értékét %1 és %2 között, lépésköz: %3", "CONTROLS_FOREACH_HELPURL": "https://hu.wikipedia.org/wiki/Ciklus_(programoz%C3%A1s)#Iter.C3.A1l.C3.B3_ciklus", "CONTROLS_FOREACH_INPUT_ITEM": "Minden", "CONTROLS_FOREACH_INPUT_INLIST": "elemre a", "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "listában", "CONTROLS_FOREACH_TOOLTIP": "A lista elemszámának megfelelő lépésszámú ciklus. A \"%1\" változó minden lépésben megkapja a lista adott elemének értékét. Minden lépésben végrehajtódnak az utasítások.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "befejezi az ismétlést", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "folytatja a következővel", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Megszakítja végtelen ciklust.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Megszakítja az aktuális futást és folytatja elölről.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Figyelem: Ez a blokk, csak egy ciklusban használható.", "CONTROLS_IF_TOOLTIP_1": "Ha a kifejezés igaz, akkor végrehajtjuk az utasításokat.", "CONTROLS_IF_TOOLTIP_2": "Ha a kifejezés igaz, akkor végrehajtjuk az első utasítás blokkot. Különben a második utasítás blokk kerül végrehajtásra.", "CONTROLS_IF_TOOLTIP_3": "Ha az első kifejezés igaz, akkor végrehajtjuk az első utasítás blokkot. Ha a második kifejezés igaz, akkor végrehajtjuk a második utasítás blokkot.", "CONTROLS_IF_TOOLTIP_4": "Ha az első kifejezés igaz, akkor végrehajtjuk az első utasítás blokkot. Ha a második kifejezés igaz, akkor végrehajtjuk a második utasítás blokkot. Amennyiben egyik kifejezés sem igaz, akkor az utolsó utasítás blokk kerül végrehajtásra.", "CONTROLS_IF_MSG_IF": "Ha", "CONTROLS_IF_MSG_ELSEIF": "ha", "CONTROLS_IF_MSG_ELSE": "különben", "CONTROLS_IF_IF_TOOLTIP": "A feltételes elágazás (ha) blokk testreszabásához bővítsd, töröld vagy rendezd át a részeit.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Újabb feltételes elágazás.", "CONTROLS_IF_ELSE_TOOLTIP": "Végső, 'egyébként' feltételt ad a 'ha' blokkhoz.", "LOGIC_COMPARE_HELPURL": "https://hu.wikipedia.org/wiki/Egyenl%C5%91tlens%C3%A9g", "LOGIC_COMPARE_TOOLTIP_EQ": "Igaz, ha a kifejezés két oldala egyenlő.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Igaz, ha a kifejezés két oldala nem egyenlő..", "LOGIC_COMPARE_TOOLTIP_LT": "Igaz, ha a bal oldali kifejezés kisebb, mint a jobb oldali.", "LOGIC_COMPARE_TOOLTIP_LTE": "Igaz, ha a bal oldali kifejezés kisebb vagy egyenlő, mint a jobb oldali.", "LOGIC_COMPARE_TOOLTIP_GT": "Igaz, ha a bal oldali kifejezés nagyobb, mint a jobb oldali.", "LOGIC_COMPARE_TOOLTIP_GTE": "Igaz, ha a bal oldali kifejezés nagyobb vagy egyenlő, mint a jobb oldali.", "LOGIC_OPERATION_TOOLTIP_AND": "Igaz, ha mindkét kifejezés igaz.", "LOGIC_OPERATION_AND": "és", "LOGIC_OPERATION_TOOLTIP_OR": "Igaz, ha bármelyik kifejezés igaz.", "LOGIC_OPERATION_OR": "vagy", "LOGIC_NEGATE_TITLE": "nem %1", "LOGIC_NEGATE_TOOLTIP": "Igaz, ha a kifejezés hamis. Hamis, ha a kifejezés igaz.", "LOGIC_BOOLEAN_TRUE": "igaz", "LOGIC_BOOLEAN_FALSE": "hamis", "LOGIC_BOOLEAN_TOOLTIP": "Igaz, vagy Hamis érték", "LOGIC_NULL": "null", "LOGIC_NULL_TOOLTIP": "null érték.", "LOGIC_TERNARY_CONDITION": "kifejezés:", "LOGIC_TERNARY_IF_TRUE": "érték, ha igaz:", "LOGIC_TERNARY_IF_FALSE": "érték, ha hamis:", "LOGIC_TERNARY_TOOLTIP": "Kiértékeli a kifejezést. Ha a kifejezés igaz visszatér az \"érték, ha igaz\" értékkel, különben az \"érték, ha hamis\" értékkel.", "MATH_NUMBER_HELPURL": "https://hu.wikipedia.org/wiki/Sz%C3%A1m", "MATH_NUMBER_TOOLTIP": "Egy szám.", "MATH_ARITHMETIC_HELPURL": "https://hu.wikipedia.org/wiki/Matematikai_m%C5%B1velet", "MATH_ARITHMETIC_TOOLTIP_ADD": "Két szám összege.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Két szám különbsége.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Két szám szorzata.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Két szám hányadosa.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Az első számnak a második számmal megyegyező hatványa.", "MATH_SINGLE_HELPURL": "https://hu.wikipedia.org/wiki/Gy%C3%B6kvon%C3%A1s", "MATH_SINGLE_OP_ROOT": "négyzetgyök", "MATH_SINGLE_TOOLTIP_ROOT": "A szám négyzetgyöke.", "MATH_SINGLE_OP_ABSOLUTE": "abszolútérték", "MATH_SINGLE_TOOLTIP_ABS": "A szám abszolútértéke.", "MATH_SINGLE_TOOLTIP_NEG": "A szám -1 szerese.", "MATH_SINGLE_TOOLTIP_LN": "A szám természetes alapú logaritmusa.", "MATH_SINGLE_TOOLTIP_LOG10": "A szám 10-es alapú logaritmusa.", "MATH_SINGLE_TOOLTIP_EXP": "Az e megadott számú hatványa.", "MATH_SINGLE_TOOLTIP_POW10": "A 10 megadott számú hatványa.", "MATH_TRIG_HELPURL": "https://hu.wikipedia.org/wiki/Sz%C3%B6gf%C3%BCggv%C3%A9nyek", "MATH_TRIG_TOOLTIP_SIN": "A fokban megadott szög szinusz értéke.", "MATH_TRIG_TOOLTIP_COS": "A fokban megadott szög koszinusz értéke.", "MATH_TRIG_TOOLTIP_TAN": "A fokban megadott szög tangens értéke.", "MATH_TRIG_TOOLTIP_ASIN": "A fokban megadott szög arkusz szinusz értéke.", "MATH_TRIG_TOOLTIP_ACOS": "A fokban megadott szög arkusz koszinusz értéke.", "MATH_TRIG_TOOLTIP_ATAN": "A fokban megadott szög arkusz tangens értéke.", "MATH_CONSTANT_HELPURL": "https://hu.wikipedia.org/wiki/Matematikai_konstans", "MATH_CONSTANT_TOOLTIP": "Ismert matematikai konstans: π (3.141…), e (2.718…), φ (1.618…), gyök(2) (1.414…), gyök(½) (0.707…), vagy ∞ (végtelen).", "MATH_IS_EVEN": "páros szám?", "MATH_IS_ODD": "páratlan szám?", "MATH_IS_PRIME": "prímszám?", "MATH_IS_WHOLE": "egész szám?", "MATH_IS_POSITIVE": "pozitív szám?", "MATH_IS_NEGATIVE": "negatív szám?", "MATH_IS_DIVISIBLE_BY": "osztható ezzel?ː", "MATH_IS_TOOLTIP": "Megadja a számról, hogy páros, páratlan, prím, egész, pozitív vagy negatív szám, illetve osztható-e a másodikkal. Igaz, vagy Hamis értéket ad eredményül.", "MATH_CHANGE_HELPURL": "https://hu.wikipedia.org/wiki/JavaScript#Aritmetikai_oper.C3.A1torok", "MATH_CHANGE_TITLE_CHANGE": "Növeld", "MATH_CHANGE_INPUT_BY": "értékét, (növekmény)ː", "MATH_CHANGE_TOOLTIP": "A(z) \"%1\" változó értékének növelése.", "MATH_ROUND_HELPURL": "https://hu.wikipedia.org/wiki/Eg%C3%A9szr%C3%A9sz#Kerek.C3.ADt.C3.A9s", "MATH_ROUND_TOOLTIP": "Kerekítés a következő, vagy megelőző egész számra.", "MATH_ROUND_OPERATOR_ROUND": "Kerekítés", "MATH_ROUND_OPERATOR_ROUNDUP": "Kerekítés fel", "MATH_ROUND_OPERATOR_ROUNDDOWN": "Kerekítés le", "MATH_ONLIST_OPERATOR_SUM": "lista összege", "MATH_ONLIST_TOOLTIP_SUM": "A lista elemeinek összegét adja eredményül.", "MATH_ONLIST_OPERATOR_MIN": "lista minimuma", "MATH_ONLIST_TOOLTIP_MIN": "A lista elemeinek minimumát adja eredményül.", "MATH_ONLIST_OPERATOR_MAX": "lista maximuma", "MATH_ONLIST_TOOLTIP_MAX": "A lista elemeinek maximumát adja eredményül.", "MATH_ONLIST_OPERATOR_AVERAGE": "lista átlaga", "MATH_ONLIST_TOOLTIP_AVERAGE": "A lista elemeinek átlagát adja eredményül.", "MATH_ONLIST_OPERATOR_MEDIAN": "lista mediánja", "MATH_ONLIST_TOOLTIP_MEDIAN": "A lista elemeinek mediánját adja eredményül.", "MATH_ONLIST_OPERATOR_MODE": "lista módusza", "MATH_ONLIST_TOOLTIP_MODE": "A lista elemeinek móduszát adja eredményül.", "MATH_ONLIST_OPERATOR_STD_DEV": "lista szórása", "MATH_ONLIST_TOOLTIP_STD_DEV": "A lista elemeinek szórását adja eredményül.", "MATH_ONLIST_OPERATOR_RANDOM": "lista véletlen eleme", "MATH_ONLIST_TOOLTIP_RANDOM": "A lista egy véletlen elemét adja eredményül.", "MATH_MODULO_HELPURL": "https://hu.wikipedia.org/wiki/Eg%C3%A9szr%C3%A9sz#Als.C3.B3_eg.C3.A9szr.C3.A9sz", "MATH_MODULO_TITLE": "maradék %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Az egész osztás maradékát adja eredméynül.", "MATH_CONSTRAIN_TITLE": "korlátozd %1 -t %2 és %3 közé", "MATH_CONSTRAIN_TOOLTIP": "Egy változó értékének korlátozása a megadott zárt intervallumra.", "MATH_RANDOM_INT_HELPURL": "https://hu.wikipedia.org/wiki/V%C3%A9letlen", "MATH_RANDOM_INT_TITLE": "véletlen egész szám %1 között %2", "MATH_RANDOM_INT_TOOLTIP": "Véletlen egész szám a megadott zárt intervallumon belül.", "MATH_RANDOM_FLOAT_HELPURL": "https://hu.wikipedia.org/wiki/V%C3%A9letlen", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "véletlen tört", "MATH_RANDOM_FLOAT_TOOLTIP": "Véletlen tört érték 0.0 és 1.0 között.", "TEXT_TEXT_HELPURL": "https://hu.wikipedia.org/wiki/String", "TEXT_TEXT_TOOLTIP": "Egy betű, szó vagy szöveg egy sora.", "TEXT_JOIN_TITLE_CREATEWITH": "összefűz", "TEXT_JOIN_TOOLTIP": "Tetszőleges számú szövegrészletet fűz össze egybefüggő szöveggé.", "TEXT_CREATE_JOIN_TITLE_JOIN": "összefűz", "TEXT_CREATE_JOIN_TOOLTIP": "Összefűzéssel, törléssel vagy rendezéssel kapcsolato sblokkok szöveg szerkesztéséhez.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Elem hozzáfűzése a szöveghez.", "TEXT_APPEND_TO": "A", "TEXT_APPEND_APPENDTEXT": "szövegéhez fűzd hozzá", "TEXT_APPEND_TOOLTIP": "Szöveget fűz a \"%1\" változó értékéhez.", "TEXT_LENGTH_TITLE": "hossz %1", "TEXT_LENGTH_TOOLTIP": "A megadott szöveg karaktereinek számát adja eredményül (beleértve a szóközöket).", "TEXT_ISEMPTY_TITLE": "%1 üres sztring?", "TEXT_ISEMPTY_TOOLTIP": "Igaz, ha a vizsgált sztring üres.", "TEXT_INDEXOF_TOOLTIP": "A keresett szöveg első vagy utolsó előfordulásával tér vissza. 0 esetén a szövegrészlet nem található.", "TEXT_INDEXOF_INPUT_INTEXT": "A(z)", "TEXT_INDEXOF_OPERATOR_FIRST": "szövegben első előfordulásának indexe", "TEXT_INDEXOF_OPERATOR_LAST": "szövegben utolsó előfordulásának indexe", "TEXT_INDEXOF_TAIL": "szövegnek", "TEXT_CHARAT_INPUT_INTEXT": "A", "TEXT_CHARAT_FROM_START": "szövegnek az elejétől számított", "TEXT_CHARAT_FROM_END": "szövegnek a végétől számított", "TEXT_CHARAT_FIRST": "szövegnek az első", "TEXT_CHARAT_LAST": "szövegnek az utolsó", "TEXT_CHARAT_RANDOM": "szövegnek tetszőleges", "TEXT_CHARAT_TAIL": "karaktere", "TEXT_CHARAT_TOOLTIP": "A szöveg egy megadott karakterét adja eredményül.", "TEXT_GET_SUBSTRING_TOOLTIP": "A megadott szövegrészletet adja eredményül.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "a", "TEXT_GET_SUBSTRING_START_FROM_START": "szövegben válaszd ki a(z)", "TEXT_GET_SUBSTRING_START_FROM_END": "szövegben válaszd ki a hátulról a(z)", "TEXT_GET_SUBSTRING_START_FIRST": "szövegben válaszd ki az első", "TEXT_GET_SUBSTRING_END_FROM_START": "betűtől a(z)", "TEXT_GET_SUBSTRING_END_FROM_END": "betűtől a hátulról számított", "TEXT_GET_SUBSTRING_END_LAST": "betűtől az utolsó", "TEXT_GET_SUBSTRING_TAIL": "betűig tartó betűsort", "TEXT_CHANGECASE_TOOLTIP": "Return a copy of the text in a different case.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "NAGYBETŰS", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "kisbetűs", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "Címként Formázott", "TEXT_TRIM_TOOLTIP": "Levágja a megadott szöveg végeiről a szóközöket.", "TEXT_TRIM_OPERATOR_BOTH": "a végekről", "TEXT_TRIM_OPERATOR_LEFT": "az elejéről", "TEXT_TRIM_OPERATOR_RIGHT": "a végéről", "TEXT_PRINT_TITLE": "Üzenet %1", "TEXT_PRINT_TOOLTIP": "Megejelníti a megadott kaakterláncot üzenetként a képernyőn.", "TEXT_PROMPT_TYPE_TEXT": "Kérj be szöveget", "TEXT_PROMPT_TYPE_NUMBER": "Kérj be számot", "TEXT_PROMPT_TOOLTIP_NUMBER": "Számot kér be a felhasználótól.", "TEXT_PROMPT_TOOLTIP_TEXT": "Szöveget kér be a felhasználótól.", "LISTS_CREATE_EMPTY_TITLE": "üres lista", "LISTS_CREATE_EMPTY_TOOLTIP": "Elemeket nem tartalmazó üres listát ad eredményül", "LISTS_CREATE_WITH_TOOLTIP": "Listát készít a megadott elemekből.", "LISTS_CREATE_WITH_INPUT_WITH": "Lista készítés, elemek:", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "lista", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Add, remove, or reorder sections to reconfigure this list block.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Elem hozzáadása listához.", "LISTS_REPEAT_TOOLTIP": "A megadtott elem felhasználásával n elemű listát készít", "LISTS_REPEAT_TITLE": "Lista készítése %1 elemet %2 alkalommal hozzáadva", "LISTS_LENGTH_TITLE": "%1 lista hossza", "LISTS_LENGTH_TOOLTIP": "A lista elemszámát adja eredményül.", "LISTS_IS_EMPTY_TITLE": "%1 üres lista?", "LISTS_TOOLTIP": "Az eredmény igaz, ha a lista nem tartalmaz elemeket.", "LISTS_INLIST": "A(z)", "LISTS_INDEX_OF_FIRST": "listában első előfordulásaː", "LISTS_INDEX_OF_LAST": "listában utolsó előfordulásaː", "LISTS_INDEX_OF_TOOLTIP": "A megadtott elem eslő vagy utolsó előfordulásával tér vissza. 0 esetén nincs ilyen eleme a listának.", "LISTS_GET_INDEX_GET": "listából értéke", "LISTS_GET_INDEX_GET_REMOVE": "listából kivétele", "LISTS_GET_INDEX_REMOVE": "listából törlése", "LISTS_GET_INDEX_FROM_START": "az elejétől számított", "LISTS_GET_INDEX_FROM_END": "a végétől számított", "LISTS_GET_INDEX_FIRST": "az első", "LISTS_GET_INDEX_LAST": "az utolsó", "LISTS_GET_INDEX_RANDOM": "bármely", "LISTS_GET_INDEX_TAIL": "elemnek", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "A lista megadott sorszámú elemét adja eredményül. 1 az első elemet jelenti.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "A lista megadott sorszámú elemét adja eredményül. 1 az utolsó elemet jelenti.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "A lista első elemét adja eredményül.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "A lista utolsó elemét adja eredményül.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "A lista véletlenszerűen választott elemét adja eredményül.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "A megadott sorszámú elem kivétele a listából 1 az első elemet jelenti.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "A megadott sorszámú elem kivétele a listából 1 az utolsó elemet jelenti.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Az első elem kivétele a listából.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Az utolsó elem kivétele a listából.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Véletlenszerűen választott elem kivétele a listából.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "A megadott sorszámú elem törlése a listából 1 az első elemet jelenti.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "A megadott sorszámú elem törlése a listából 1 az utolsó elemet jelenti.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Az első elem törlése a listából.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Az utolsó elem törlése a listából.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Véletlenszerűen választott elem törlése a listából.", "LISTS_SET_INDEX_SET": "listába állítsd be", "LISTS_SET_INDEX_INSERT": "listába szúrd be", "LISTS_SET_INDEX_INPUT_TO": "elemkéntː", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "A megadott sorszámú elem cseréje a listában. 1 az első elemet jelenti.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "A megadott sorszámú elem cseréje a listában. 1 az utolsó elemet jelenti.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Az első elem cseréje a listában.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Az utolsó elem cseréje a listában.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Véletlenszerűen választott elem cseréje a listában.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Beszúrás a megadott sorszámú elem elé a listában. 1 az első elemet jelenti.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Beszúrás a megadott sorszámú elem elé a listában. 1 az utolsó elemet jelenti.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Beszúrás a lista elejére.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Beszúrás a lista végére.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Beszúrás véletlenszerűen választott elem elé a listában.", "LISTS_GET_SUBLIST_START_FROM_START": "részlistája az elejétől számított", "LISTS_GET_SUBLIST_START_FROM_END": "részlistája a végétől számított", "LISTS_GET_SUBLIST_START_FIRST": "részlistája az első", "LISTS_GET_SUBLIST_END_FROM_START": "és az elejétől számított", "LISTS_GET_SUBLIST_END_FROM_END": "és a végétől számított", "LISTS_GET_SUBLIST_END_LAST": "és az utolsó", "LISTS_GET_SUBLIST_TAIL": "elem között", "LISTS_GET_SUBLIST_TOOLTIP": "A lista adott részéről másolat.", "ORDINAL_NUMBER_SUFFIX": ".", "VARIABLES_GET_TITLE": "", "VARIABLES_GET_TAIL": "", "VARIABLES_GET_TOOLTIP": "A változó értékét adja eredményül.", "VARIABLES_GET_CREATE_SET": "Create \"set %1\"", "VARIABLES_SET_TITLE": "", "VARIABLES_SET_TAIL": "", "VARIABLES_SET_TOOLTIP": "A változónak adhatunk értéket.", "VARIABLES_SET_CREATE_GET": "Create \"get %1\"", "PROCEDURES_DEFNORETURN_TITLE": "Eljárás", "PROCEDURES_DEFNORETURN_PROCEDURE": "név", "PROCEDURES_BEFORE_PARAMS": "paraméterlistaː", "PROCEDURES_DEFNORETURN_DO": "", "PROCEDURES_DEFNORETURN_TOOLTIP": "Eljárás (nem ad vissza eredményt).", "PROCEDURES_DEFRETURN_RETURN": "eredménye", "PROCEDURES_DEFRETURN_TOOLTIP": "Függvény eredménnyel.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Figyelem: Az eljárásban azonos elnevezésű paramétert adtál meg.", "PROCEDURES_CALLNORETURN_HELPURL": "https://hu.wikipedia.org/wiki/F%C3%BCggv%C3%A9ny_(programoz%C3%A1s)", "PROCEDURES_CALLNORETURN_CALL": "", "PROCEDURES_CALLNORETURN_TOOLTIP": "Végrehajtja az eljárást.", "PROCEDURES_CALLRETURN_HELPURL": "https://hu.wikipedia.org/wiki/F%C3%BCggv%C3%A9ny_(programoz%C3%A1s)", "PROCEDURES_CALLRETURN_TOOLTIP": "Meghívja a függvényt.", "PROCEDURES_MUTATORCONTAINER_TITLE": "paraméterek", "PROCEDURES_MUTATORARG_TITLE": "változó:", "PROCEDURES_HIGHLIGHT_DEF": "Eljárás kiemelése", "PROCEDURES_CREATE_DO": "Create \"do %1\"", "PROCEDURES_IFRETURN_TOOLTIP": "Ha az érték igaz, akkor visszatér a függvény értékével.", "PROCEDURES_IFRETURN_WARNING": "Figyelem: Ez a blokk csak eljáráson belül használható." } ================================================ FILE: extern/blockly/msg/json/ia.json ================================================ { "@metadata": { "authors": [ "McDutchie" ] }, "VARIABLES_DEFAULT_NAME": "cosa", "DUPLICATE_BLOCK": "Duplicar", "ADD_COMMENT": "Adder commento", "REMOVE_COMMENT": "Remover commento", "EXTERNAL_INPUTS": "Entrata externe", "INLINE_INPUTS": "Entrata interne", "DELETE_BLOCK": "Deler bloco", "DELETE_X_BLOCKS": "Deler %1 blocos", "COLLAPSE_BLOCK": "Plicar bloco", "COLLAPSE_ALL": "Plicar blocos", "EXPAND_BLOCK": "Displicar bloco", "EXPAND_ALL": "Displicar blocos", "DISABLE_BLOCK": "Disactivar bloco", "ENABLE_BLOCK": "Activar bloco", "HELP": "Adjuta", "CHANGE_VALUE_TITLE": "Cambiar valor:", "NEW_VARIABLE": "Nove variabile...", "NEW_VARIABLE_TITLE": "Nomine del nove variabile:", "RENAME_VARIABLE": "Renominar variabile...", "RENAME_VARIABLE_TITLE": "Renominar tote le variabiles '%1' a:", "COLOUR_PICKER_HELPURL": "https://ia.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Elige un color del paletta.", "COLOUR_RANDOM_TITLE": "color aleatori", "COLOUR_RANDOM_TOOLTIP": "Eliger un color al hasardo.", "COLOUR_RGB_TITLE": "colorar con", "COLOUR_RGB_RED": "rubie", "COLOUR_RGB_GREEN": "verde", "COLOUR_RGB_BLUE": "blau", "COLOUR_RGB_TOOLTIP": "Crear un color con le quantitate specificate de rubie, verde e blau. Tote le valores debe esser inter 0 e 100.", "COLOUR_BLEND_TITLE": "miscer", "COLOUR_BLEND_COLOUR1": "color 1", "COLOUR_BLEND_COLOUR2": "color 2", "COLOUR_BLEND_RATIO": "ration", "COLOUR_BLEND_TOOLTIP": "Misce duo colores con un ration specificate (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "repeter %1 vices", "CONTROLS_REPEAT_TITLE_REPEAT": "repeter", "CONTROLS_REPEAT_TITLE_TIMES": "vices", "CONTROLS_REPEAT_INPUT_DO": "face", "CONTROLS_REPEAT_TOOLTIP": "Exequer certe instructiones plure vices.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "repeter durante que", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "repeter usque a", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Durante que un valor es ver, exequer certe instructiones.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Durante que un valor es false, exequer certe instructiones.", "CONTROLS_FOR_TOOLTIP": "Mitter in le variabile %1 le valores ab le numero initial usque al numero final, con passos secundo le intervallo specificate, e exequer le blocos specificate.", "CONTROLS_FOR_INPUT_WITH": "contar con", "CONTROLS_FOR_INPUT_FROM_TO_BY": "de %1 a %2 per %3", "CONTROLS_FOREACH_INPUT_ITEM": "pro cata elemento", "CONTROLS_FOREACH_INPUT_INLIST": "in lista", "CONTROLS_FOREACH_TOOLTIP": "Pro cata elemento in un lista, mitter lo in le variabile '%1' e exequer certe instructiones.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "escappar del bucla", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "continuar con le proxime iteration del bucla", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Escappar del bucla continente.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Saltar le resto de iste bucla e continuar con le proxime iteration.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Attention: Iste bloco pote solmente esser usate in un bucla.", "CONTROLS_IF_TOOLTIP_1": "Si un valor es ver, exequer certe instructiones.", "CONTROLS_IF_TOOLTIP_2": "Si un valor es ver, exequer le prime bloco de instructiones. Si non, exequer le secunde bloco de instructiones.", "CONTROLS_IF_TOOLTIP_3": "Si le prime valor es ver, exequer le prime bloco de instructiones. Si non, si le secunde valor es ver, exequer le secunde bloco de instructiones.", "CONTROLS_IF_TOOLTIP_4": "Si le prime valor es ver, exequer le prime bloco de instructiones. Si non, si le secunde valor es ver, exequer le secunde bloco de instructiones. Si necun del valores es ver, exequer le ultime bloco de instructiones.", "CONTROLS_IF_MSG_IF": "si", "CONTROLS_IF_MSG_ELSEIF": "si non si", "CONTROLS_IF_MSG_ELSE": "si non", "CONTROLS_IF_IF_TOOLTIP": "Adder, remover o reordinar sectiones pro reconfigurar iste bloco \"si\".", "CONTROLS_IF_ELSEIF_TOOLTIP": "Adder un condition al bloco \"si\".", "CONTROLS_IF_ELSE_TOOLTIP": "Adder un condition final de reserva al bloco \"si\".", "LOGIC_COMPARE_TOOLTIP_EQ": "Retornar ver si le duo entratas es equal.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Retornar ver si le duo entratas non es equal.", "LOGIC_COMPARE_TOOLTIP_LT": "Retornar ver si le prime entrata es minor que le secunde.", "LOGIC_COMPARE_TOOLTIP_LTE": "Retornar ver si le prime entrata es minor que o equal al secunde.", "LOGIC_COMPARE_TOOLTIP_GT": "Retornar ver si le prime entrata es major que le secunde.", "LOGIC_COMPARE_TOOLTIP_GTE": "Retornar ver si le prime entrata es major que o equal al secunde.", "LOGIC_OPERATION_TOOLTIP_AND": "Retornar ver si ambe entratas es ver.", "LOGIC_OPERATION_AND": "e", "LOGIC_OPERATION_TOOLTIP_OR": "Retornar ver si al minus un del entratas es ver.", "LOGIC_OPERATION_OR": "o", "LOGIC_NEGATE_TITLE": "non %1", "LOGIC_NEGATE_TOOLTIP": "Retornar ver si le entrata es false. Retornar false si le entrata es ver.", "LOGIC_BOOLEAN_TRUE": "ver", "LOGIC_BOOLEAN_FALSE": "false", "LOGIC_BOOLEAN_TOOLTIP": "Retorna o ver o false.", "LOGIC_NULL": "nulle", "LOGIC_NULL_TOOLTIP": "Retorna nulle.", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "si ver", "LOGIC_TERNARY_IF_FALSE": "si false", "LOGIC_TERNARY_TOOLTIP": "Verificar le condition in 'test'. Si le condition es ver, retorna le valor de 'si ver'; si non, retorna le valor de 'si false'.", "MATH_NUMBER_HELPURL": "https://ia.wikipedia.org/wiki/Numero", "MATH_NUMBER_TOOLTIP": "Un numero.", "MATH_ARITHMETIC_HELPURL": "https://ia.wikipedia.org/wiki/Arithmetica", "MATH_ARITHMETIC_TOOLTIP_ADD": "Retornar le summa del duo numeros.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Retornar le differentia del duo numeros.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Retornar le producto del duo numeros.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Retornar le quotiente del duo numeros.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Retornar le prime numero elevate al potentia del secunde numero.", "MATH_SINGLE_HELPURL": "https://ia.wikipedia.org/wiki/Radice_quadrate", "MATH_SINGLE_OP_ROOT": "radice quadrate", "MATH_SINGLE_TOOLTIP_ROOT": "Retornar le radice quadrate de un numero.", "MATH_SINGLE_OP_ABSOLUTE": "absolute", "MATH_SINGLE_TOOLTIP_ABS": "Retornar le valor absolute de un numero.", "MATH_SINGLE_TOOLTIP_NEG": "Retornar le negation de un numero.", "MATH_SINGLE_TOOLTIP_LN": "Retornar le logarithmo natural de un numero.", "MATH_SINGLE_TOOLTIP_LOG10": "Retornar le logarithmo in base 10 del numero.", "MATH_SINGLE_TOOLTIP_EXP": "Retornar e elevate al potentia del numero.", "MATH_SINGLE_TOOLTIP_POW10": "Retornar 10 elevate al potentia de un numero." } ================================================ FILE: extern/blockly/msg/json/id.json ================================================ { "@metadata": [], "VARIABLES_DEFAULT_NAME": "item", "DUPLICATE_BLOCK": "Duplikat", "ADD_COMMENT": "Tambahkan sebuah comment", "REMOVE_COMMENT": "Hapus komentar", "EXTERNAL_INPUTS": "Input-input eksternal", "INLINE_INPUTS": "Input inline", "DELETE_BLOCK": "Hapus blok", "DELETE_X_BLOCKS": "Hapus %1 blok", "COLLAPSE_BLOCK": "Tutup blok", "COLLAPSE_ALL": "Tutup blok", "EXPAND_BLOCK": "Kembangkan blok", "EXPAND_ALL": "Kembangkan blok-blok", "DISABLE_BLOCK": "Nonaktifkan blok", "ENABLE_BLOCK": "Aktifkan blok", "HELP": "Tolong", "CHANGE_VALUE_TITLE": "Ubah nilai:", "NEW_VARIABLE": "Pembolehubah baru...", "NEW_VARIABLE_TITLE": "Nama pembolehubah baru:", "RENAME_VARIABLE": "namai ulang variabel...", "RENAME_VARIABLE_TITLE": "Ubah nama semua variabel '%1' menjadi:", "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Pilih warna dari daftar warna.", "COLOUR_RANDOM_TITLE": "Warna acak", "COLOUR_RANDOM_TOOLTIP": "Pilih warna secara acak.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "Dengan warna", "COLOUR_RGB_RED": "merah", "COLOUR_RGB_GREEN": "hijau", "COLOUR_RGB_BLUE": "biru", "COLOUR_RGB_TOOLTIP": "Buatlah warna dengan jumlah yang ditentukan dari merah, hijau dan biru. Semua nilai harus antarai 0 sampai 100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "Tertutup", "COLOUR_BLEND_COLOUR1": "Warna 1", "COLOUR_BLEND_COLOUR2": "Warna 2", "COLOUR_BLEND_RATIO": "rasio", "COLOUR_BLEND_TOOLTIP": "mencampur dua warna secara bersamaan dengan perbandingan (0.0-1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "ulangi %1 kali", "CONTROLS_REPEAT_TITLE_REPEAT": "ulangi", "CONTROLS_REPEAT_TITLE_TIMES": "kali", "CONTROLS_REPEAT_INPUT_DO": "kerjakan", "CONTROLS_REPEAT_TOOLTIP": "Lakukan beberapa perintah beberapa kali.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "Ulangi jika", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "Ulangi sampai", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Jika sementara nilai benar (true), maka lakukan beberapa perintah.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Jika sementara nilai tidak benar (false), maka lakukan beberapa perintah.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Menggunakan variabel %1 dengan mengambil nilai dari batas awal hingga ke batas akhir, dengan interval tertentu, dan mengerjakan block tertentu.", "CONTROLS_FOR_INPUT_WITH": "Cacah dengan", "CONTROLS_FOR_INPUT_FROM_TO_BY": "dari %1 ke %2 dengan step / penambahan %3", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each for each block", "CONTROLS_FOREACH_INPUT_ITEM": "untuk setiap item", "CONTROLS_FOREACH_INPUT_INLIST": "di dalam list", "CONTROLS_FOREACH_TOOLTIP": "Untuk tiap-tiap item di dalam list, tetapkan variabel '%1' ke dalam item, selanjutnya kerjakan beberapa statement.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "Keluar dari perulangan", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "Lanjutkan dengan langkah penggulangan berikutnya", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Keluar sementara dari perulanggan.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Abaikan sisa dari loop ini, dan lanjutkan dengan iterasi berikutnya.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Peringatan: Blok ini hanya dapat digunakan dalam loop.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "jika nilainya benar maka kerjakan perintah berikutnya.", "CONTROLS_IF_TOOLTIP_2": "jika nilainya benar, maka kerjakan blok perintah yang pertama. Jika tidak, kerjakan blok perintah yang kedua.", "CONTROLS_IF_TOOLTIP_3": "Jika nilai pertama adalah benar (true), maka lakukan perintah-perintah yang berada didalam blok pertama. Jika nilai kedua adalah benar (true), maka lakukan perintah-perintah yang berada didalam blok kedua.", "CONTROLS_IF_TOOLTIP_4": "Jika blok pertama adalah benar (true), maka lakukan perintah-perintah yang berada didalam blok pertama. Atau jika blok kedua adalah benar (true), maka lakukan perintah-perintah yang berada didalam blok kedua.", "CONTROLS_IF_MSG_IF": "Jika", "CONTROLS_IF_MSG_ELSEIF": "else if", "CONTROLS_IF_MSG_ELSE": "else", "CONTROLS_IF_IF_TOOLTIP": "Menambahkan, menghapus, atau menyusun kembali bagian untuk mengkonfigurasi blok IF ini.", "CONTROLS_IF_ELSEIF_TOOLTIP": "tambahkan prasyarat ke dalam blok IF.", "CONTROLS_IF_ELSE_TOOLTIP": "Terakhir, tambahkan tangkap-semua kondisi kedalam blok jika (if).", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "Mengembalikan betul jika input kedua-duanya sama dengan satu sama lain.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Mengembalikan nilai benar (true) jika kedua input tidak sama satu dengan yang lain.", "LOGIC_COMPARE_TOOLTIP_LT": "Mengembalikan nilai benar (true) jika input yang pertama lebih kecil dari input yang kedua.", "LOGIC_COMPARE_TOOLTIP_LTE": "Mengembalikan nilai benar (true) jika input yang pertama lebih kecil atau sama dengan input yang kedua .", "LOGIC_COMPARE_TOOLTIP_GT": "Mengembalikan nilai benar (true) jika input yang pertama lebih besar dari input yang kedua.", "LOGIC_COMPARE_TOOLTIP_GTE": "Mengembalikan nilai benar (true) jika input yang pertama lebih besar dari atau sama dengan input yang kedua.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Kembalikan betul jika kedua-dua input adalah betul.", "LOGIC_OPERATION_AND": "dan", "LOGIC_OPERATION_TOOLTIP_OR": "Mengembalikan nilai benar (true) jika setidaknya salah satu masukan nilainya benar (true).", "LOGIC_OPERATION_OR": "atau", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "bukan (not) %1", "LOGIC_NEGATE_TOOLTIP": "Mengembalikan nilai benar (true) jika input false. Mengembalikan nilai salah (false) jika input true.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "Benar", "LOGIC_BOOLEAN_FALSE": "Salah", "LOGIC_BOOLEAN_TOOLTIP": "Mengembalikan betul (true) atau salah (false).", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "null", "LOGIC_NULL_TOOLTIP": "mengembalikan kosong.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "jika benar (true)", "LOGIC_TERNARY_IF_FALSE": "jika tidak benar (false)", "LOGIC_TERNARY_TOOLTIP": "Periksa kondisi di \"test\". Jika kondisi benar (true), mengembalikan nilai \"jika benar\" ; Jik sebaliknya akan mengembalikan nilai \"jika salah\".", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "Suatu angka.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "×", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "asin", "MATH_TRIG_ACOS": "acos", "MATH_TRIG_ATAN": "atan", "MATH_ARITHMETIC_HELPURL": "https://id.wikipedia.org/wiki/Aritmetika", "MATH_ARITHMETIC_TOOLTIP_ADD": "Kembalikan jumlah dari kedua angka.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Kembalikan selisih dari kedua angka.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Kembalikan perkalian dari kedua angka.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Kembalikan hasil bagi dari kedua angka.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Kembalikan angka pertama pangkat angka kedua.", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "akar", "MATH_SINGLE_TOOLTIP_ROOT": "Kembalikan akar dari angka.", "MATH_SINGLE_OP_ABSOLUTE": "mutlak", "MATH_SINGLE_TOOLTIP_ABS": "Kembalikan nilai absolut angka.", "MATH_SINGLE_TOOLTIP_NEG": "Kembalikan penyangkalan terhadap angka.", "MATH_SINGLE_TOOLTIP_LN": "Kembalikan logaritma natural dari angka.", "MATH_SINGLE_TOOLTIP_LOG10": "Kembalikan dasar logaritma 10 dari angka.", "MATH_SINGLE_TOOLTIP_EXP": "Kembalikan 10 pangkat angka.", "MATH_SINGLE_TOOLTIP_POW10": "Kembalikan 10 pangkat angka.", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "Kembalikan sinus dari derajat (bukan radian).", "MATH_TRIG_TOOLTIP_COS": "Kembalikan cos dari derajat (bukan radian).", "MATH_TRIG_TOOLTIP_TAN": "Kembalikan tangen dari derajat (tidak radian).", "MATH_TRIG_TOOLTIP_ASIN": "Kembalikan asin dari angka.", "MATH_TRIG_TOOLTIP_ACOS": "Kembalikan acosine dari angka.", "MATH_TRIG_TOOLTIP_ATAN": "Kembalikan atan dari angka.", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "Kembalikan salah satu konstant: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), atau ∞ (infinity).", "MATH_IS_EVEN": "adalah bilangan genap", "MATH_IS_ODD": "adalah bilangan ganjil", "MATH_IS_PRIME": "adalah bilangan pokok", "MATH_IS_WHOLE": "adalah bilangan bulat", "MATH_IS_POSITIVE": "adalah bilangan positif", "MATH_IS_NEGATIVE": "adalah bilangan negatif", "MATH_IS_DIVISIBLE_BY": "dibagi oleh", "MATH_IS_TOOLTIP": "Periksa apakah angka adalah bilangan genap, bilangan pokok, bilangan bulat, bilangan positif, bilangan negatif, atau apakan bisa dibagi oleh angka tertentu. Mengembalikan benar (true) atau salah (false).", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "ubah", "MATH_CHANGE_INPUT_BY": "oleh", "MATH_CHANGE_TOOLTIP": "Tambahkan angka kedalam variabel '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Bulatkan suatu bilangan naik atau turun.", "MATH_ROUND_OPERATOR_ROUND": "membulatkan", "MATH_ROUND_OPERATOR_ROUNDUP": "mengumpulkan", "MATH_ROUND_OPERATOR_ROUNDDOWN": "membulatkan kebawah", "MATH_ONLIST_OPERATOR_SUM": "jumlah dari list (daftar)", "MATH_ONLIST_TOOLTIP_SUM": "Kembalikan jumlah dari seluruh bilangan dari list.", "MATH_ONLIST_OPERATOR_MIN": "minimum dari list (daftar)", "MATH_ONLIST_TOOLTIP_MIN": "Kembalikan angka terkecil dari list.", "MATH_ONLIST_OPERATOR_MAX": "maximum dari list (daftar)", "MATH_ONLIST_TOOLTIP_MAX": "Kembalikan angka terbesar dari list.", "MATH_ONLIST_OPERATOR_AVERAGE": "rata-rata dari list (daftar)", "MATH_ONLIST_TOOLTIP_AVERAGE": "Kembalikan rata-rata (mean aritmetik) dari nilai numerik dari list (daftar).", "MATH_ONLIST_OPERATOR_MEDIAN": "median dari list (daftar)", "MATH_ONLIST_TOOLTIP_MEDIAN": "Kembalikan median dari list.", "MATH_ONLIST_OPERATOR_MODE": "mode-mode dari list (daftar)", "MATH_ONLIST_TOOLTIP_MODE": "Kembalikan list berisi item-item yang paling umum dari dalam list.", "MATH_ONLIST_OPERATOR_STD_DEV": "deviasi standar dari list (daftar)", "MATH_ONLIST_TOOLTIP_STD_DEV": "Kembalikan standard deviasi dari list.", "MATH_ONLIST_OPERATOR_RANDOM": "item acak dari list (daftar)", "MATH_ONLIST_TOOLTIP_RANDOM": "Kembalikan element acak dari list.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "sisa %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Kembalikan sisa dari pembagian ke dua angka.", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "Batasi %1 rendah %2 tinggi %3", "MATH_CONSTRAIN_TOOLTIP": "Batasi angka antara batas yang ditentukan (inklusif).", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "acak bulat dari %1 sampai %2", "MATH_RANDOM_INT_TOOLTIP": "Mengembalikan bilangan acak antara dua batas yang ditentukan, inklusif.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "Nilai pecahan acak", "MATH_RANDOM_FLOAT_TOOLTIP": "Mengembalikan nilai acak pecahan antara 0.0 (inklusif) dan 1.0 (ekslusif).", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "Huruf, kata atau baris teks.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "Buat teks dengan", "TEXT_JOIN_TOOLTIP": "Buat teks dengan cara gabungkan sejumlah item.", "TEXT_CREATE_JOIN_TITLE_JOIN": "join", "TEXT_CREATE_JOIN_TOOLTIP": "Tambah, ambil, atau susun ulang teks blok.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Tambahkan suatu item ke dalam teks.", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "untuk", "TEXT_APPEND_APPENDTEXT": "tambahkan teks", "TEXT_APPEND_TOOLTIP": "Tambahkan beberapa teks ke variabel '%1'.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "panjang dari %1", "TEXT_LENGTH_TOOLTIP": "Kembalikan sejumlah huruf (termasuk spasi) dari teks yang disediakan.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 kosong", "TEXT_ISEMPTY_TOOLTIP": "Kembalikan benar (true) jika teks yang disediakan kosong.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Kembalikan indeks pertama dan terakhir dari kejadian pertama/terakhir dari teks pertama dalam teks kedua. Kembalikan 0 jika teks tidak ditemukan.", "TEXT_INDEXOF_INPUT_INTEXT": "dalam teks", "TEXT_INDEXOF_OPERATOR_FIRST": "temukan kejadian pertama dalam teks", "TEXT_INDEXOF_OPERATOR_LAST": "temukan kejadian terakhir dalam teks", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "dalam teks", "TEXT_CHARAT_FROM_START": "ambil huruf ke #", "TEXT_CHARAT_FROM_END": "ambil huruf nomor # dari belakang", "TEXT_CHARAT_FIRST": "ambil huruf pertama", "TEXT_CHARAT_LAST": "ambil huruf terakhir", "TEXT_CHARAT_RANDOM": "ambil huruf secara acak", "TEXT_CHARAT_TOOLTIP": "Kembalikan karakter dari posisi tertentu.", "TEXT_GET_SUBSTRING_TOOLTIP": "Mengembalikan spesifik bagian dari teks.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "in teks", "TEXT_GET_SUBSTRING_START_FROM_START": "ambil bagian teks (substring) dari huruf no #", "TEXT_GET_SUBSTRING_START_FROM_END": "ambil bagian teks (substring) dari huruf ke # dari terakhir", "TEXT_GET_SUBSTRING_START_FIRST": "ambil bagian teks (substring) dari huruf pertama", "TEXT_GET_SUBSTRING_END_FROM_START": "pada huruf #", "TEXT_GET_SUBSTRING_END_FROM_END": "pada huruf nomer # dari terakhir", "TEXT_GET_SUBSTRING_END_LAST": "pada huruf terakhir", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Kembalikan kopi dari text dengan kapitalisasi yang berbeda.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "menjadi huruf kapital", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "menjadi huruf kecil", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "menjadi huruf pertama kapital", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Kembali salinan teks dengan spasi dihapus dari satu atau kedua ujungnya.", "TEXT_TRIM_OPERATOR_BOTH": "pangkas ruang dari kedua belah sisi", "TEXT_TRIM_OPERATOR_LEFT": "pangkas ruang dari sisi kiri", "TEXT_TRIM_OPERATOR_RIGHT": "pangkas ruang dari sisi kanan", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "cetak %1", "TEXT_PRINT_TOOLTIP": "Cetak teks yant ditentukan, angka atau ninlai lainnya.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "meminta teks dengan pesan", "TEXT_PROMPT_TYPE_NUMBER": "Meminta angka dengan pesan", "TEXT_PROMPT_TOOLTIP_NUMBER": "Meminta pengguna untuk memberi sebuah angka.", "TEXT_PROMPT_TOOLTIP_TEXT": "Meminta pengguna untuk memberi beberapa teks.", "LISTS_CREATE_EMPTY_HELPURL": "https://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "buat list kosong", "LISTS_CREATE_EMPTY_TOOLTIP": "Mengembalikan daftar, dengan panjang 0, tidak berisi data", "LISTS_CREATE_WITH_TOOLTIP": "Buat sebuah daftar (list) dengan sejumlah item.", "LISTS_CREATE_WITH_INPUT_WITH": "buat daftar (list) dengan", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "list", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Tambahkan, hapus, atau susun ulang bagian untuk mengkonfigurasi blok LIST (daftar) ini.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Tambahkan sebuah item ke daftar (list).", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "Ciptakan daftar yang terdiri dari nilai yang diberikan diulang jumlah waktu yang ditentukan.", "LISTS_REPEAT_TITLE": "membuat daftar dengan item %1 diulang %2 kali", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "panjang dari %1", "LISTS_LENGTH_TOOLTIP": "Mengembalikan panjang daftar.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 kosong", "LISTS_TOOLTIP": "Mengembalikan nilai benar (true) jika list kosong.", "LISTS_INLIST": "dalam daftar", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "cari kejadian pertama item", "LISTS_INDEX_OF_LAST": "Cari kejadian terakhir item", "LISTS_INDEX_OF_TOOLTIP": "Mengembalikan indeks dari kejadian pertama/terakhir item dalam daftar. Menghasilkan 0 jika teks tidak ditemukan.", "LISTS_GET_INDEX_GET": "dapatkan", "LISTS_GET_INDEX_GET_REMOVE": "dapatkan dan hapus", "LISTS_GET_INDEX_REMOVE": "Hapus", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# dari akhir", "LISTS_GET_INDEX_FIRST": "pertama", "LISTS_GET_INDEX_LAST": "terakhir", "LISTS_GET_INDEX_RANDOM": "acak", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Sisipkan item ke dalam posisi yang telah ditentukan didalam list (daftar). Item pertama adalah item terakhir (yg paling akhir).", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Sisipkan item ke dalam posisi yang telah ditentukan didalam list (daftar). Item pertama adalah item yang terakhir.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Kembalikan item pertama dalam daftar (list).", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Mengembalikan item pertama dalam list (daftar).", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Mengembalikan item acak dalam list (daftar).", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Menghilangkan dan mengembalikan barang di posisi tertentu dalam list (daftar). #1 adalah item pertama.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Menghilangkan dan mengembalikan barang di posisi tertentu dalam list (daftar). #1 adalah item terakhir.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Menghilangkan dan mengembalikan item pertama dalam list (daftar).", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Menghilangkan dan mengembalikan item terakhir dalam list (daftar).", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Menghilangkan dan mengembalikan barang dengan acak dalam list (daftar).", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Menghapus item dengan posisi tertentu dalam daftar. Item pertama adalah item yang terakhir.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Menghapus item dengan posisi tertentu dalam daftar. Item pertama adalah item yang terakhir.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Menghapus item pertama dalam daftar.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Menghapus item terakhir dalam daftar.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Menghapus sebuah item secara acak dalam list.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "tetapkan", "LISTS_SET_INDEX_INSERT": "sisipkan di", "LISTS_SET_INDEX_INPUT_TO": "sebagai", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Tetapkan item ke dalam posisi yang telah ditentukan di dalam list. #1 adalah item yang pertama.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Tetapkan item ke dalam posisi yang telah ditentukan di dalam list. #1 adalah item yang terakhir.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Tetapkan item pertama di dalam list.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Menetapkan item terakhir dalam list.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Tetapkan secara acak sebuah item dalam list.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Sisipkan item ke dalam posisi yang telah ditentukan di dalam list. #1 adalah item yang pertama.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Sisipkan item ke dalam posisi yang telah ditentukan di dalam list. #1 adalah item yang terakhir.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Sisipkan item di bagian awal dari list.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Tambahkan item ke bagian akhir list.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Sisipkan item secara acak ke dalam list.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "Dapatkan bagian daftar dari #", "LISTS_GET_SUBLIST_START_FROM_END": "Dapatkan bagian list nomor # dari akhir", "LISTS_GET_SUBLIST_START_FIRST": "Dapatkan bagian pertama dari list", "LISTS_GET_SUBLIST_END_FROM_START": "ke #", "LISTS_GET_SUBLIST_END_FROM_END": "ke # dari akhir", "LISTS_GET_SUBLIST_END_LAST": "ke yang paling akhir", "LISTS_GET_SUBLIST_TOOLTIP": "Membuat salinan dari bagian tertentu dari list.", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TOOLTIP": "Mengembalikan nilai variabel ini.", "VARIABLES_GET_CREATE_SET": "Membuat 'tetapkan %1'", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "tetapkan", "VARIABLES_SET_TAIL": "untuk", "VARIABLES_SET_TOOLTIP": "tetapkan variabel ini dengan input yang sama.", "VARIABLES_SET_CREATE_GET": "Membuat 'dapatkan %1'", "PROCEDURES_DEFNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFNORETURN_TITLE": "untuk", "PROCEDURES_DEFNORETURN_PROCEDURE": "buat sesuatu", "PROCEDURES_BEFORE_PARAMS": "dengan:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Menciptakan sebuah fungsi dengan tiada output.", "PROCEDURES_DEFRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFRETURN_RETURN": "kembali", "PROCEDURES_DEFRETURN_TOOLTIP": "Menciptakan sebuah fungsi dengan satu output.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Peringatan: Fungsi ini memiliki parameter duplikat.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_TOOLTIP": "Menjalankan fungsi '%1' yang ditetapkan pengguna.", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Menjalankan fungsi '%1' yang ditetapkan pengguna dan menggunakan outputnya.", "PROCEDURES_MUTATORCONTAINER_TITLE": "input", "PROCEDURES_MUTATORARG_TITLE": "masukan Nama:", "PROCEDURES_HIGHLIGHT_DEF": "Sorot definisi fungsi", "PROCEDURES_CREATE_DO": "Buat '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Jika nilai yang benar, kemudian kembalikan nilai kedua.", "PROCEDURES_IFRETURN_WARNING": "Peringatan: Blok ini dapat digunakan hanya dalam definisi fungsi." } ================================================ FILE: extern/blockly/msg/json/is.json ================================================ { "@metadata": { "authors": [ "Jonbg" ] }, "VARIABLES_DEFAULT_NAME": "atriði", "DUPLICATE_BLOCK": "Afrita", "ADD_COMMENT": "Skrifa skýringu", "REMOVE_COMMENT": "Fjarlægja skýringu", "EXTERNAL_INPUTS": "Ytri inntök", "INLINE_INPUTS": "Innri inntök", "DELETE_BLOCK": "Eyða kubbi", "DELETE_X_BLOCKS": "Eyða %1 kubbum", "COLLAPSE_BLOCK": "Loka kubbi", "COLLAPSE_ALL": "Loka kubbum", "EXPAND_BLOCK": "Opna kubb", "EXPAND_ALL": "Opna kubba", "DISABLE_BLOCK": "Óvirkja kubb", "ENABLE_BLOCK": "Virkja kubb", "HELP": "Hjálp", "CHANGE_VALUE_TITLE": "Breyta gildi:", "NEW_VARIABLE": "Ný breyta...", "NEW_VARIABLE_TITLE": "Heiti nýrrar breytu:", "RENAME_VARIABLE": "Endurnefna breytu...", "RENAME_VARIABLE_TITLE": "Endurnefna allar '%1' breyturnar:", "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Velja lit úr litakorti.", "COLOUR_RANDOM_TITLE": "einhver litur", "COLOUR_RANDOM_TOOLTIP": "Velja einhvern lit af handahófi.", "COLOUR_RGB_TITLE": "litur", "COLOUR_RGB_RED": "rautt", "COLOUR_RGB_GREEN": "grænt", "COLOUR_RGB_BLUE": "blátt", "COLOUR_RGB_TOOLTIP": "Búa til lit úr tilteknu magni af rauðu, grænu og bláu. Allar tölurnar verða að vera á bilinu 0 til 100.", "COLOUR_BLEND_TITLE": "blöndun", "COLOUR_BLEND_COLOUR1": "litur 1", "COLOUR_BLEND_COLOUR2": "litur 2", "COLOUR_BLEND_RATIO": "hlutfall", "COLOUR_BLEND_TOOLTIP": "Blandar tveimur litum í gefnu hlutfalli (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "endurtaka %1 sinnum", "CONTROLS_REPEAT_TITLE_REPEAT": "endurtaka", "CONTROLS_REPEAT_TITLE_TIMES": "sinnum", "CONTROLS_REPEAT_INPUT_DO": "gera", "CONTROLS_REPEAT_TOOLTIP": "Gera eitthvað aftur og aftur.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "endurtaka á meðan", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "endurtaka þar til", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Endurtaka eitthvað á meðan gildi er satt.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Endurtaka eitthvað á meðan gildi er ósatt.", "CONTROLS_FOR_TOOLTIP": "Láta breytuna %1 taka inn gildi frá fyrstu tölu til síðustu tölu hlaupandi á bilinu og endurtaka kubbana fyrir hverja tölu.", "CONTROLS_FOR_INPUT_WITH": "telja með", "CONTROLS_FOR_INPUT_FROM_TO_BY": "frá %1 til %2 um %3", "CONTROLS_FOREACH_INPUT_ITEM": "fyrir hvert", "CONTROLS_FOREACH_INPUT_INLIST": "í lista", "CONTROLS_FOREACH_TOOLTIP": "Fyrir hvert atriði í lista er breyta '%1' stillt á atriðið og skipanir gerðar.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "fara út úr lykkju", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "fara beint í næstu umferð lykkjunnar", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Fara út úr umlykjandi lykkju.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Sleppa afganginum af lykkjunni og fara beint í næstu umferð hennar.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Aðvörun: Þennan kubb má aðeins nota innan lykkju.", "CONTROLS_IF_TOOLTIP_1": "Ef gildi er satt skal gera einhverjar skipanir.", "CONTROLS_IF_TOOLTIP_2": "Ef gildi er satt skal gera skipanir í fyrri kubbnum. Annars skal gera skipanir í seinni kubbnum.", "CONTROLS_IF_TOOLTIP_3": "Ef fyrra gildið er satt skal gera skipanir í fyrri kubbnum. Annars, ef seinna gildið er satt, þá skal gera skipanir í seinni kubbnum.", "CONTROLS_IF_TOOLTIP_4": "Ef fyrra gildið er satt skal gera skipanir í fyrri kubbnum. Annars, ef seinna gildið er satt, skal gera skipanir í seinni kubbnum. Ef hvorugt gildið er satt, skal gera skipanir í síðasta kubbnum.", "CONTROLS_IF_MSG_IF": "ef", "CONTROLS_IF_MSG_ELSEIF": "annars ef", "CONTROLS_IF_MSG_ELSE": "annars", "CONTROLS_IF_IF_TOOLTIP": "Bæta við, fjarlægja eða umraða til að breyta skipan þessa EF kubbs.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Bæta skilyrði við EF kubbinn.", "CONTROLS_IF_ELSE_TOOLTIP": "Bæta við hluta EF kubbs sem grípur öll tilfelli sem uppfylla ekki hin skilyrðin.", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "Skila sönnu ef inntökin eru jöfn.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Skila sönnu ef inntökin eru ekki jöfn.", "LOGIC_COMPARE_TOOLTIP_LT": "Skila sönnu ef fyrra inntakið er minna en seinna inntakið.", "LOGIC_COMPARE_TOOLTIP_LTE": "Skila sönnu ef fyrra inntakið er minna en eða jafnt og seinna inntakið.", "LOGIC_COMPARE_TOOLTIP_GT": "Skila sönnu ef fyrra inntakið er stærra en seinna inntakið.", "LOGIC_COMPARE_TOOLTIP_GTE": "Skila sönnu ef fyrra inntakið er stærra en eða jafnt og seinna inntakið.", "LOGIC_OPERATION_TOOLTIP_AND": "Skila sönnu ef bæði inntökin eru sönn.", "LOGIC_OPERATION_AND": "og", "LOGIC_OPERATION_TOOLTIP_OR": "Skila sönnu ef að minnsta kosti eitt inntak er satt.", "LOGIC_OPERATION_OR": "eða", "LOGIC_NEGATE_TITLE": "ekki %1", "LOGIC_NEGATE_TOOLTIP": "Skilar sönnu ef inntakið er ósatt. Skilar ósönnu ef inntakið er satt.", "LOGIC_BOOLEAN_TRUE": "satt", "LOGIC_BOOLEAN_FALSE": "ósatt", "LOGIC_BOOLEAN_TOOLTIP": "Skilar annað hvort sönnu eða ósönnu.", "LOGIC_NULL": "tómagildi", "LOGIC_NULL_TOOLTIP": "Skilar tómagildi.", "LOGIC_TERNARY_CONDITION": "prófun", "LOGIC_TERNARY_IF_TRUE": "ef satt", "LOGIC_TERNARY_IF_FALSE": "ef ósatt", "LOGIC_TERNARY_TOOLTIP": "Kanna skilyrðið í 'prófun'. Skilar 'ef satt' gildinu ef skilyrðið er satt, en skilar annars 'ef ósatt' gildinu.", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "Tala.", "MATH_ARITHMETIC_HELPURL": "https://en.wikipedia.org/wiki/Arithmetic", "MATH_ARITHMETIC_TOOLTIP_ADD": "Skila summu talnanna tveggja.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Skila mismun talnanna.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Skila margfeldi talnanna.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Skila deilingu talnanna.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Skila fyrri tölunni í veldinu seinni talan.", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "kvaðratrót", "MATH_SINGLE_TOOLTIP_ROOT": "Skila kvaðratrót tölu.", "MATH_SINGLE_OP_ABSOLUTE": "algildi", "MATH_SINGLE_TOOLTIP_ABS": "Skila algildi tölu.", "MATH_SINGLE_TOOLTIP_NEG": "Skila neitun tölu (tölunni með öfugu formerki).", "MATH_SINGLE_TOOLTIP_LN": "Skila náttúrlegum lógaritma tölu.", "MATH_SINGLE_TOOLTIP_LOG10": "Skila tugalógaritma tölu.", "MATH_SINGLE_TOOLTIP_EXP": "Skila e í veldi tölu.", "MATH_SINGLE_TOOLTIP_POW10": "Skila 10 í veldi tölu.", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "Skila sínusi horns gefnu í gráðum.", "MATH_TRIG_TOOLTIP_COS": "Skila kósínusi horns gefnu í gráðum.", "MATH_TRIG_TOOLTIP_TAN": "Skila tangensi horns gefnu í gráðum.", "MATH_TRIG_TOOLTIP_ASIN": "Skilar arkarsínusi tölu.", "MATH_TRIG_TOOLTIP_ACOS": "Skilar arkarkósínusi tölu.", "MATH_TRIG_TOOLTIP_ATAN": "Skilar arkartangensi tölu.", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "Skila algengum fasta: π (3.141…), e (2.718…), φ (1.618…), kvrót(2) (1.414…), kvrót(½) (0.707…) eða ∞ (óendanleika).", "MATH_IS_EVEN": "er\\u00A0jöfn tala", "MATH_IS_ODD": "er oddatala", "MATH_IS_PRIME": "er prímtala", "MATH_IS_WHOLE": "er heiltala", "MATH_IS_POSITIVE": "er jákvæð", "MATH_IS_NEGATIVE": "er neikvæð", "MATH_IS_DIVISIBLE_BY": "er\\u00A0deilanleg með", "MATH_IS_TOOLTIP": "Kanna hvort tala sé jöfn tala, oddatala, jákvæð, neikvæð eða deilanleg með tiltekinni tölu. Skilar sönnu eða ósönnu.", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "breyta", "MATH_CHANGE_INPUT_BY": "um", "MATH_CHANGE_TOOLTIP": "Bæta tölu við breytu '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Námunda tölu upp eða niður.", "MATH_ROUND_OPERATOR_ROUND": "námunda", "MATH_ROUND_OPERATOR_ROUNDUP": "námunda upp", "MATH_ROUND_OPERATOR_ROUNDDOWN": "námunda niður", "MATH_ONLIST_OPERATOR_SUM": "summa lista", "MATH_ONLIST_TOOLTIP_SUM": "Skila summu allra talna í listanum.", "MATH_ONLIST_OPERATOR_MIN": "minnst í lista", "MATH_ONLIST_TOOLTIP_MIN": "Skila minnstu tölu í listanum.", "MATH_ONLIST_OPERATOR_MAX": "stærst í lista", "MATH_ONLIST_TOOLTIP_MAX": "Skila stærstu tölu í listanum.", "MATH_ONLIST_OPERATOR_AVERAGE": "meðaltal lista", "MATH_ONLIST_TOOLTIP_AVERAGE": "Skila meðaltali talna í listanum.", "MATH_ONLIST_OPERATOR_MEDIAN": "miðgildi lista", "MATH_ONLIST_TOOLTIP_MEDIAN": "Skila miðgildi listans.", "MATH_ONLIST_OPERATOR_MODE": "tíðast í lista", "MATH_ONLIST_TOOLTIP_MODE": "Skila lista yfir tíðustu gildin í listanum.", "MATH_ONLIST_OPERATOR_STD_DEV": "staðalfrávik lista", "MATH_ONLIST_TOOLTIP_STD_DEV": "Skila staðalfráviki lista.", "MATH_ONLIST_OPERATOR_RANDOM": "eitthvað úr lista", "MATH_ONLIST_TOOLTIP_RANDOM": "Skila einhverju atriði úr listanum.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "afgangur af %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Skila afgangi deilingar með tölunum.", "MATH_CONSTRAIN_TITLE": "þröngva %1 lægst %2 hæst %3", "MATH_CONSTRAIN_TOOLTIP": "Þröngva tölu til að vera innan hinna tilgreindu marka (að báðum meðtöldum).", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "slembitala frá %1 til %2", "MATH_RANDOM_INT_TOOLTIP": "Skila heiltölu sem valin er af handahófi og er innan tilgreindra marka, að báðum meðtöldum.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "slembibrot", "MATH_RANDOM_FLOAT_TOOLTIP": "Skila broti sem er valið af handahófi úr tölum á bilinu frá og með 0.0 til (en ekki með) 1.0.", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "Stafur, orð eða textalína.", "TEXT_JOIN_TITLE_CREATEWITH": "búa til texta með", "TEXT_JOIN_TOOLTIP": "Búa til texta með því að tengja saman einhvern fjölda atriða.", "TEXT_CREATE_JOIN_TITLE_JOIN": "tengja", "TEXT_CREATE_JOIN_TOOLTIP": "Bæta við, fjarlægja eða umraða hlutum til að breyta skipan þessa textakubbs.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Bæta atriði við textann.", "TEXT_APPEND_TO": "við", "TEXT_APPEND_APPENDTEXT": "bæta texta", "TEXT_APPEND_TOOLTIP": "Bæta texta við breytuna '%1'.", "TEXT_LENGTH_TITLE": "lengd %1", "TEXT_LENGTH_TOOLTIP": "Skilar fjölda stafa (með bilum) í gefna textanum.", "TEXT_ISEMPTY_TITLE": "%1 er tómur", "TEXT_ISEMPTY_TOOLTIP": "Skilar sönnu ef gefni textinn er tómur.", "TEXT_INDEXOF_TOOLTIP": "Finnur fyrsta/síðasta tilfelli fyrri textans í seinni textanum og skilar sæti hans. Skilar 0 ef textinn finnst ekki.", "TEXT_INDEXOF_INPUT_INTEXT": "í texta", "TEXT_INDEXOF_OPERATOR_FIRST": "finna fyrsta tilfelli texta", "TEXT_INDEXOF_OPERATOR_LAST": "finna síðasta tilfelli texta", "TEXT_CHARAT_INPUT_INTEXT": "í texta", "TEXT_CHARAT_FROM_START": "sækja staf #", "TEXT_CHARAT_FROM_END": "sækja staf # frá enda", "TEXT_CHARAT_FIRST": "sækja fyrsta staf", "TEXT_CHARAT_LAST": "sækja síðasta staf", "TEXT_CHARAT_RANDOM": "sækja einhvern staf", "TEXT_CHARAT_TOOLTIP": "Skila staf á tilteknum stað.", "TEXT_GET_SUBSTRING_TOOLTIP": "Skilar tilteknum hluta textans.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "í texta", "TEXT_GET_SUBSTRING_START_FROM_START": "sækja textabút frá staf #", "TEXT_GET_SUBSTRING_START_FROM_END": "sækja textabút frá staf # frá enda", "TEXT_GET_SUBSTRING_START_FIRST": "sækja textabút frá fyrsta staf", "TEXT_GET_SUBSTRING_END_FROM_START": "að staf #", "TEXT_GET_SUBSTRING_END_FROM_END": "að staf # frá enda", "TEXT_GET_SUBSTRING_END_LAST": "að síðasta staf", "TEXT_CHANGECASE_TOOLTIP": "Skila afriti af textanum með annarri stafastöðu.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "í HÁSTAFI", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "í lágstafi", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "í Upphafstafi", "TEXT_TRIM_TOOLTIP": "Skila afriti af textanum þar sem möguleg bil við báða enda hafa verið fjarlægð.", "TEXT_TRIM_OPERATOR_BOTH": "eyða bilum af báðum endum", "TEXT_TRIM_OPERATOR_LEFT": "eyða bilum af vinstri enda", "TEXT_TRIM_OPERATOR_RIGHT": "eyða bilum af hægri enda", "TEXT_PRINT_TITLE": "prenta %1", "TEXT_PRINT_TOOLTIP": "Prenta tiltekinn texta, tölu eða annað gildi.", "TEXT_PROMPT_TYPE_TEXT": "biðja um texta með skilaboðum", "TEXT_PROMPT_TYPE_NUMBER": "biðja um tölu með skilaboðum", "TEXT_PROMPT_TOOLTIP_NUMBER": "Biðja notandann um tölu.", "TEXT_PROMPT_TOOLTIP_TEXT": "Biðja notandann um texta.", "LISTS_CREATE_EMPTY_TITLE": "búa til tóman lista", "LISTS_CREATE_EMPTY_TOOLTIP": "Skilar lista með lengdina 0 án gagna", "LISTS_CREATE_WITH_TOOLTIP": "Búa til lista með einhverjum fjölda atriða.", "LISTS_CREATE_WITH_INPUT_WITH": "búa til lista með", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "listi", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Bæta við, fjarlægja eða umraða hlutum til að breyta skipan þessa listakubbs.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Bæta atriði við listann.", "LISTS_REPEAT_TOOLTIP": "Býr til lista sem inniheldur tiltekna gildið endurtekið tiltekið oft.", "LISTS_REPEAT_TITLE": "búa til lista með atriði %1 endurtekið %2 sinnum", "LISTS_LENGTH_TITLE": "lengd %1", "LISTS_LENGTH_TOOLTIP": "Skilar lengd lista.", "LISTS_IS_EMPTY_TITLE": "%1 er tómur", "LISTS_TOOLTIP": "Skilar sönnu ef listinn er tómur.", "LISTS_INLIST": "í lista", "LISTS_INDEX_OF_FIRST": "finna fyrsta tilfelli atriðis", "LISTS_INDEX_OF_LAST": "finna síðasta tilfelli atriðis", "LISTS_INDEX_OF_TOOLTIP": "Finnur hvar atriðið kemur fyrir fyrst/síðast í listanum og skilar sæti þess. Skilar 0 ef textinn finnst ekki.", "LISTS_GET_INDEX_GET": "sækja", "LISTS_GET_INDEX_GET_REMOVE": "sækja og fjarlægja", "LISTS_GET_INDEX_REMOVE": "fjarlægja", "LISTS_GET_INDEX_FROM_END": "# frá enda", "LISTS_GET_INDEX_FIRST": "fyrsta", "LISTS_GET_INDEX_LAST": "síðasta", "LISTS_GET_INDEX_RANDOM": "eitthvert", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Skilar atriðinu í hinum tiltekna stað í lista. #1 er fyrsta atriðið.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Skilar atriðinu á hinum tiltekna stað í lista. #1 er síðasta atriðið.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Skilar fyrsta atriði í lista.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Skilar síðasta atriði í lista.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Skilar einhverju atriði úr lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Fjarlægir og skilar atriðinu á hinum tiltekna stað í lista. #1 er fyrsta atriðið.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Fjarlægir og skilar atriðinu á hinum tiltekna stað í lista. #1 er síðasta atriðið.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Fjarlægir og skilar fyrsta atriðinu í lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Fjarlægir og skilar síðasta atriðinu í lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Fjarlægir og skilar einhverju atriði úr lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Fjarlægir atriðið á hinum tiltekna stað í lista. #1 er fyrsta atriðið.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Fjarlægir atriðið á hinum tiltekna stað í lista. #1 er síðasta atriðið.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Fjarlægir fyrsta atriðið í lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Fjarlægir síðasta atriðið í lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Fjarlægir eitthvert atriði úr lista.", "LISTS_SET_INDEX_SET": "setja í", "LISTS_SET_INDEX_INSERT": "bæta við", "LISTS_SET_INDEX_INPUT_TO": "sem", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Setur atriðið í tiltekna sætið í listanum. #1 er fyrsta atriðið.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Setur atriðið í tiltekna sætið í listanum. #1 er síðasta atriðið.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Setur atriðið í fyrsta sæti lista.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Setur atriðið í síðasta sæti lista.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Setur atriðið í eitthvert sæti lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Bætir atriðinu í listann á tilteknum stað. #1 er fyrsta atriðið.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Bætir atriðinu í listann á tilteknum stað. #1 er síðasta atriðið.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Bætir atriðinu fremst í listann.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Bætir atriðinu aftan við listann.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Bætir atriðinu einhversstaðar við listann.", "LISTS_GET_SUBLIST_START_FROM_START": "sækja undirlista frá #", "LISTS_GET_SUBLIST_START_FROM_END": "sækja undirlista frá # frá enda", "LISTS_GET_SUBLIST_START_FIRST": "sækja undirlista frá fyrsta", "LISTS_GET_SUBLIST_END_FROM_START": "til #", "LISTS_GET_SUBLIST_END_FROM_END": "til # frá enda", "LISTS_GET_SUBLIST_END_LAST": "til síðasta", "LISTS_GET_SUBLIST_TOOLTIP": "Býr til afrit af tilteknum hluta lista.", "VARIABLES_GET_TOOLTIP": "Skilar gildi þessarar breytu.", "VARIABLES_GET_CREATE_SET": "Búa til 'stilla %1'", "VARIABLES_SET_TITLE": "stilla", "VARIABLES_SET_TAIL": "á", "VARIABLES_SET_TOOLTIP": "Stillir þessa breytu á innihald inntaksins.", "VARIABLES_SET_CREATE_GET": "Búa til 'sækja %1'", "PROCEDURES_DEFNORETURN_TITLE": "til að", "PROCEDURES_DEFNORETURN_PROCEDURE": "gera eitthvað", "PROCEDURES_BEFORE_PARAMS": "með:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Býr til fall sem skilar engu.", "PROCEDURES_DEFRETURN_RETURN": "skila", "PROCEDURES_DEFRETURN_TOOLTIP": "Býr til fall sem skilar úttaki.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Aðvörun: Þetta fall er með tvítekna stika.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_TOOLTIP": "Keyra heimatilbúna fallið '%1'.", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Keyra heimatilbúna fallið '%1' og nota úttak þess.", "PROCEDURES_MUTATORCONTAINER_TITLE": "inntök", "PROCEDURES_MUTATORARG_TITLE": "heiti inntaks:", "PROCEDURES_HIGHLIGHT_DEF": "Sýna skilgreiningu falls", "PROCEDURES_CREATE_DO": "Búa til '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Ef gildi er satt, skal skila öðru gildi.", "PROCEDURES_IFRETURN_WARNING": "Aðvörun: Þennan kubb má aðeins nota í skilgreiningu falls." } ================================================ FILE: extern/blockly/msg/json/it.json ================================================ { "@metadata": { "authors": [ "Beta16", "Espertus", "Nerimic" ] }, "VARIABLES_DEFAULT_NAME": "elemento", "DUPLICATE_BLOCK": "Duplica", "ADD_COMMENT": "Aggiungi commento", "REMOVE_COMMENT": "Rimuovi commento", "EXTERNAL_INPUTS": "Ingressi esterni", "INLINE_INPUTS": "Ingressi in linea", "DELETE_BLOCK": "Cancella blocco", "DELETE_X_BLOCKS": "Cancella %1 blocchi", "COLLAPSE_BLOCK": "Comprimi blocco", "COLLAPSE_ALL": "Comprimi blocchi", "EXPAND_BLOCK": "Espandi blocco", "EXPAND_ALL": "Espandi blocchi", "DISABLE_BLOCK": "Disattiva blocco", "ENABLE_BLOCK": "Attiva blocco", "HELP": "Aiuto", "CHANGE_VALUE_TITLE": "Modifica valore:", "NEW_VARIABLE": "Nuova variabile...", "NEW_VARIABLE_TITLE": "Nome della nuova variabile:", "RENAME_VARIABLE": "Rinomina variabile...", "RENAME_VARIABLE_TITLE": "Rinomina tutte le variabili '%1' in:", "COLOUR_PICKER_HELPURL": "https://it.wikipedia.org/wiki/Colore", "COLOUR_PICKER_TOOLTIP": "Scegli un colore dalla tavolozza.", "COLOUR_RANDOM_TITLE": "colore casuale", "COLOUR_RANDOM_TOOLTIP": "Scegli un colore a caso.", "COLOUR_RGB_TITLE": "colora con", "COLOUR_RGB_RED": "rosso", "COLOUR_RGB_GREEN": "verde", "COLOUR_RGB_BLUE": "blu", "COLOUR_RGB_TOOLTIP": "Crea un colore con la quantità specificata di rosso, verde e blu. Tutti i valori devono essere compresi tra 0 e 100.", "COLOUR_BLEND_TITLE": "miscela", "COLOUR_BLEND_COLOUR1": "colore 1", "COLOUR_BLEND_COLOUR2": "colore 2", "COLOUR_BLEND_RATIO": "rapporto", "COLOUR_BLEND_TOOLTIP": "Mescola due colori insieme con un determinato rapporto (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://it.wikipedia.org/wiki/Ciclo_for", "CONTROLS_REPEAT_TITLE": "ripeti %1 volte", "CONTROLS_REPEAT_TITLE_REPEAT": "ripeti", "CONTROLS_REPEAT_TITLE_TIMES": "volte", "CONTROLS_REPEAT_INPUT_DO": "fai", "CONTROLS_REPEAT_TOOLTIP": "Esegue alcune istruzione diverse volte.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "ripeti mentre", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "ripeti fino a che", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Finché un valore è vero, esegue alcune istruzioni.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Finché un valore è falso, esegue alcune istruzioni.", "CONTROLS_FOR_TOOLTIP": "Fa sì che la variabile %1 prenda tutti i valori a partire dal numero di partenza fino a quello di arrivo, con passo pari all'intervallo specificato, ed esegue il blocco indicato.", "CONTROLS_FOR_INPUT_WITH": "conta con", "CONTROLS_FOR_INPUT_FROM_TO_BY": "da %1 a %2 per %3", "CONTROLS_FOREACH_INPUT_ITEM": "per ogni elemento", "CONTROLS_FOREACH_INPUT_INLIST": "nella lista", "CONTROLS_FOREACH_TOOLTIP": "Per ogni elemento in una lista, imposta la variabile '%1' pari all'elemento e quindi esegue alcune istruzioni.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "esce dal ciclo", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "prosegui con la successiva iterazione del ciclo", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Esce dal ciclo.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Salta il resto di questo ciclo e prosegue con la successiva iterazione.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Attenzioneː Questo blocco può essere usato solo in un ciclo.", "CONTROLS_IF_TOOLTIP_1": "Se un valore è vero allora esegue alcune istruzioni.", "CONTROLS_IF_TOOLTIP_2": "Se un valore è vero allora esegue il primo blocco di istruzioni. Altrimenti esegue il secondo blocco di istruzioni.", "CONTROLS_IF_TOOLTIP_3": "Se il primo valore è vero allora esegue un primo blocco di istruzioni. Altrimenti, se il secondo valore è vero, esegue un secondo blocco di istruzioni.", "CONTROLS_IF_TOOLTIP_4": "Se il primo valore è vero allora esegue un primo blocco di istruzioni. Altrimenti, se il secondo valore è vero, esegue un secondo blocco di istruzioni. Se nessuno dei valori è vero esegue l'ultimo blocco di istruzioni.", "CONTROLS_IF_MSG_IF": "se", "CONTROLS_IF_MSG_ELSEIF": "altrimenti se", "CONTROLS_IF_MSG_ELSE": "altrimenti", "CONTROLS_IF_IF_TOOLTIP": "Aggiungi, elimina o riordina le sezioni per riconfigurare questo blocco se.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Aggiungi una condizione al blocco se.", "CONTROLS_IF_ELSE_TOOLTIP": "Aggiungi una condizione finale pigliatutto al blocco se.", "LOGIC_COMPARE_HELPURL": "https://it.wikipedia.org/wiki/Disuguaglianza", "LOGIC_COMPARE_TOOLTIP_EQ": "Restituisce vero se gli input sono uno uguale all'altro.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Restituisce vero se gli input non sono uno uguale all'altro.", "LOGIC_COMPARE_TOOLTIP_LT": "Restituisce vero se il primo input è minore del secondo.", "LOGIC_COMPARE_TOOLTIP_LTE": "Restituisce vero se il primo input è minore o uguale al secondo.", "LOGIC_COMPARE_TOOLTIP_GT": "Restituisce vero se il primo input è maggiore o uguale al secondo.", "LOGIC_COMPARE_TOOLTIP_GTE": "Restituisce uguale se il primo input è maggiore o uguale al secondo input.", "LOGIC_OPERATION_TOOLTIP_AND": "Restituisce vero se entrambi gli input sono veri.", "LOGIC_OPERATION_AND": "e", "LOGIC_OPERATION_TOOLTIP_OR": "Restituisce vero se almeno uno degli input è vero.", "LOGIC_OPERATION_OR": "o", "LOGIC_NEGATE_TITLE": "non %1", "LOGIC_NEGATE_TOOLTIP": "Restituisce vero se l'input è falso. Restituisce falso se l'input è vero.", "LOGIC_BOOLEAN_TRUE": "vero", "LOGIC_BOOLEAN_FALSE": "falso", "LOGIC_BOOLEAN_TOOLTIP": "Restituisce vero o falso.", "LOGIC_NULL": "nullo", "LOGIC_NULL_TOOLTIP": "Restituisce valore nullo.", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "se vero", "LOGIC_TERNARY_IF_FALSE": "se falso", "LOGIC_TERNARY_TOOLTIP": "Verifica la condizione in 'test'. Se questa è vera restituisce il valore 'se vero' altrimenti restituisce il valore 'se falso'.", "MATH_NUMBER_HELPURL": "https://it.wikipedia.org/wiki/Numero", "MATH_NUMBER_TOOLTIP": "Un numero.", "MATH_ARITHMETIC_HELPURL": "https://it.wikipedia.org/wiki/Aritmetica", "MATH_ARITHMETIC_TOOLTIP_ADD": "Restituisce la somma dei due numeri.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Restituisce la differenza dei due numeri.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Restituisce il prodotto dei due numeri.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Restituisce il quoziente dei due numeri.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Restituisce il primo numero elevato alla potenza del secondo numero.", "MATH_SINGLE_HELPURL": "https://it.wikipedia.org/wiki/Radice_quadrata", "MATH_SINGLE_OP_ROOT": "radice quadrata", "MATH_SINGLE_TOOLTIP_ROOT": "Restituisce la radice quadrata del numero.", "MATH_SINGLE_OP_ABSOLUTE": "assoluto", "MATH_SINGLE_TOOLTIP_ABS": "Restituisce il valore assoluto del numero.", "MATH_SINGLE_TOOLTIP_NEG": "Restituisce l'opposto del numero.", "MATH_SINGLE_TOOLTIP_LN": "Restituisce il logaritmo naturale del numero.", "MATH_SINGLE_TOOLTIP_LOG10": "Restituisce il logaritmo in base 10 del numero.", "MATH_SINGLE_TOOLTIP_EXP": "Restituisce e elevato alla potenza del numero.", "MATH_SINGLE_TOOLTIP_POW10": "Restituisce 10 elevato alla potenza del numero.", "MATH_TRIG_HELPURL": "https://it.wikipedia.org/wiki/Funzione_trigonometrica", "MATH_TRIG_TOOLTIP_SIN": "Restituisce il seno di un angolo espresso in gradi (non radianti).", "MATH_TRIG_TOOLTIP_COS": "Restituisce il coseno di un angolo espresso in gradi (non radianti).", "MATH_TRIG_TOOLTIP_TAN": "Restituisce la tangente di un angolo espresso in gradi (non radianti).", "MATH_TRIG_TOOLTIP_ASIN": "Restituisce l'arco-seno di un numero.", "MATH_TRIG_TOOLTIP_ACOS": "Restituisce l'arco-coseno di un numero.", "MATH_TRIG_TOOLTIP_ATAN": "Restituisce l'arco-tangente di un numero.", "MATH_CONSTANT_HELPURL": "https://it.wikipedia.org/wiki/Costante_matematica", "MATH_CONSTANT_TOOLTIP": "Restituisce una delle costanti comuniː π (3.141…), e (2.718…), φ (1.618…), radq(2) (1.414…), radq(½) (0.707…) o ∞ (infinito).", "MATH_IS_EVEN": "è pari", "MATH_IS_ODD": "è dispari", "MATH_IS_PRIME": "è primo", "MATH_IS_WHOLE": "è intero", "MATH_IS_POSITIVE": "è positivo", "MATH_IS_NEGATIVE": "è negativo", "MATH_IS_DIVISIBLE_BY": "è divisibile per", "MATH_IS_TOOLTIP": "Verifica se un numero è pari, dispari, primo, intero, positivo, negativo o se è divisibile per un certo numero. Restituisce vero o falso.", "MATH_CHANGE_HELPURL": "https://it.wikipedia.org/wiki/Addizione", "MATH_CHANGE_TITLE_CHANGE": "cambia", "MATH_CHANGE_INPUT_BY": "di", "MATH_CHANGE_TOOLTIP": "Aggiunge un numero alla variabile '%1'.", "MATH_ROUND_HELPURL": "https://it.wikipedia.org/wiki/Arrotondamento", "MATH_ROUND_TOOLTIP": "Arrotonda un numero verso l'alto o verso il basso.", "MATH_ROUND_OPERATOR_ROUND": "arrotonda", "MATH_ROUND_OPERATOR_ROUNDUP": "arrotonda verso l'alto", "MATH_ROUND_OPERATOR_ROUNDDOWN": "arrotonda verso il basso", "MATH_ONLIST_OPERATOR_SUM": "somma la lista", "MATH_ONLIST_TOOLTIP_SUM": "Restituisce la somma si tutti i numeri nella lista.", "MATH_ONLIST_OPERATOR_MIN": "minimo della lista", "MATH_ONLIST_TOOLTIP_MIN": "Restituisce il più piccolo numero della lista.", "MATH_ONLIST_OPERATOR_MAX": "massimo della lista", "MATH_ONLIST_TOOLTIP_MAX": "Restituisce il più grande numero della lista.", "MATH_ONLIST_OPERATOR_AVERAGE": "media della lista", "MATH_ONLIST_TOOLTIP_AVERAGE": "Restituisce la media (media aritmetica) dei valori numerici nella lista.", "MATH_ONLIST_OPERATOR_MEDIAN": "mediana della lista", "MATH_ONLIST_TOOLTIP_MEDIAN": "Restituisce il valore mediano della lista.", "MATH_ONLIST_OPERATOR_MODE": "mode della lista", "MATH_ONLIST_TOOLTIP_MODE": "Restituisce una lista degli elementi più frequenti nella lista.", "MATH_ONLIST_OPERATOR_STD_DEV": "deviazione standard della lista", "MATH_ONLIST_TOOLTIP_STD_DEV": "Restituisce la deviazione standard della lista.", "MATH_ONLIST_OPERATOR_RANDOM": "elemento casuale della lista", "MATH_ONLIST_TOOLTIP_RANDOM": "Restituisce un elemento casuale della lista.", "MATH_MODULO_HELPURL": "https://it.wikipedia.org/wiki/Resto", "MATH_MODULO_TITLE": "resto di %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Restituisce il resto della divisione di due numeri.", "MATH_CONSTRAIN_TITLE": "costringi %1 da %2 a %3", "MATH_CONSTRAIN_TOOLTIP": "Costringe un numero all'interno dei limiti indicati (compresi).", "MATH_RANDOM_INT_HELPURL": "https://it.wikipedia.org/wiki/Numeri_pseudo-casuali", "MATH_RANDOM_INT_TITLE": "intero casuale da %1 a %2", "MATH_RANDOM_INT_TOOLTIP": "Restituisce un numero intero casuale compreso tra i due limiti indicati (inclusi).", "MATH_RANDOM_FLOAT_HELPURL": "https://it.wikipedia.org/wiki/Numeri_pseudo-casuali", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "frazione casuale", "MATH_RANDOM_FLOAT_TOOLTIP": "Restituisce una frazione compresa fra 0.0 (incluso) e 1.0 (escluso).", "TEXT_TEXT_HELPURL": "https://it.wikipedia.org/wiki/Stringa_(informatica)", "TEXT_TEXT_TOOLTIP": "Una lettera, una parola o una linea di testo.", "TEXT_JOIN_TITLE_CREATEWITH": "crea testo con", "TEXT_JOIN_TOOLTIP": "Crea un blocco di testo unendo un certo numero di elementi.", "TEXT_CREATE_JOIN_TITLE_JOIN": "unisci", "TEXT_CREATE_JOIN_TOOLTIP": "Aggiungi, rimuovi o riordina le sezioni per riconfigurare questo blocco testo.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Aggiungi un elemento al testo.", "TEXT_APPEND_TO": "a", "TEXT_APPEND_APPENDTEXT": "aggiungi il testo", "TEXT_APPEND_TOOLTIP": "Aggiunge del testo alla variabile '%1'.", "TEXT_LENGTH_TITLE": "lunghezza di %1", "TEXT_LENGTH_TOOLTIP": "Restituisce il numero di lettere (inclusi gli spazi) nel testo fornito.", "TEXT_ISEMPTY_TITLE": "%1 è vuoto", "TEXT_ISEMPTY_TOOLTIP": "Restituisce vero se il testo fornito è vuoto.", "TEXT_INDEXOF_TOOLTIP": "Restituisce l'indice della prima occorrenza del primo testo all'interno del secondo testo. Restituisce 0 se il testo non viene trovato.", "TEXT_INDEXOF_INPUT_INTEXT": "nel testo", "TEXT_INDEXOF_OPERATOR_FIRST": "trova la prima occorrenza del testo", "TEXT_INDEXOF_OPERATOR_LAST": "trova l'ultima occorrenza del testo", "TEXT_CHARAT_INPUT_INTEXT": "nel testo", "TEXT_CHARAT_FROM_START": "prendi la lettera #", "TEXT_CHARAT_FROM_END": "prendi la lettera # dalla fine", "TEXT_CHARAT_FIRST": "prendi la prima lettera", "TEXT_CHARAT_LAST": "prendi l'ultima lettera", "TEXT_CHARAT_RANDOM": "prendi lettera casuale", "TEXT_CHARAT_TOOLTIP": "Restituisce la lettera nella posizione indicata.", "TEXT_GET_SUBSTRING_TOOLTIP": "Restituisce la porzione di testo indicata.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "nel testo", "TEXT_GET_SUBSTRING_START_FROM_START": "prendi sotto-stringa dalla lettera #", "TEXT_GET_SUBSTRING_START_FROM_END": "prendi sotto-stringa dalla lettera # dalla fine", "TEXT_GET_SUBSTRING_START_FIRST": "prendi sotto-stringa dalla prima lettera", "TEXT_GET_SUBSTRING_END_FROM_START": "alla lettera #", "TEXT_GET_SUBSTRING_END_FROM_END": "alla lettera # dalla fine", "TEXT_GET_SUBSTRING_END_LAST": "all'ultima lettera", "TEXT_CHANGECASE_TOOLTIP": "Restituisce una copia del testo in un diverso formato maiuscole/minuscole.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "in MAIUSCOLO", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "in minuscolo", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "con Iniziali Maiuscole", "TEXT_TRIM_TOOLTIP": "Restituisce una copia del testo con gli spazi rimossi ad uno o entrambe le estremità.", "TEXT_TRIM_OPERATOR_BOTH": "rimuovi spazi da entrambi gli estremi", "TEXT_TRIM_OPERATOR_LEFT": "rimuovi spazi a sinistra", "TEXT_TRIM_OPERATOR_RIGHT": "rimuovi spazi a destra", "TEXT_PRINT_TITLE": "scrivi %1", "TEXT_PRINT_TOOLTIP": "Scrive il testo, numero o altro valore indicato.", "TEXT_PROMPT_TYPE_TEXT": "richiedi testo con messaggio", "TEXT_PROMPT_TYPE_NUMBER": "richiedi numero con messaggio", "TEXT_PROMPT_TOOLTIP_NUMBER": "Richiedi un numero all'utente.", "TEXT_PROMPT_TOOLTIP_TEXT": "Richiede del testo da parte dell'utente.", "LISTS_CREATE_EMPTY_TITLE": "crea lista vuota", "LISTS_CREATE_EMPTY_TOOLTIP": "Restituisce una lista, di lunghezza 0, contenente nessun record di dati", "LISTS_CREATE_WITH_TOOLTIP": "Crea una lista con un certo numero di elementi.", "LISTS_CREATE_WITH_INPUT_WITH": "crea lista con", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "lista", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Aggiungi, rimuovi o riordina le sezioni per riconfigurare il blocco lista.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Aggiunge un elemento alla lista.", "LISTS_REPEAT_TOOLTIP": "Crea una lista costituita dal valore indicato ripetuto per il numero di volte specificato.", "LISTS_REPEAT_TITLE": "crea una lista con l'elemento %1 ripetuto %2 volte", "LISTS_LENGTH_TITLE": "lunghezza di %1", "LISTS_LENGTH_TOOLTIP": "Restituisce la lunghezza della lista", "LISTS_IS_EMPTY_TITLE": "%1 è vuota", "LISTS_TOOLTIP": "Restituisce vero se la lista è vuota.", "LISTS_INLIST": "nella lista", "LISTS_INDEX_OF_FIRST": "trova la prima occorrenza dell'elemento", "LISTS_INDEX_OF_LAST": "trova l'ultima occorrenza dell'elemento", "LISTS_INDEX_OF_TOOLTIP": "Restituisce l'indice della prima/ultima occorrenza dell'elemento nella lista. Restituisce 0 se il testo non viene trovato.", "LISTS_GET_INDEX_GET": "prendi", "LISTS_GET_INDEX_GET_REMOVE": "prendi e rimuovi", "LISTS_GET_INDEX_REMOVE": "rimuovi", "LISTS_GET_INDEX_FROM_END": "# dalla fine", "LISTS_GET_INDEX_FIRST": "primo", "LISTS_GET_INDEX_LAST": "ultimo", "LISTS_GET_INDEX_RANDOM": "casuale", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Restituisce l'elemento nella posizione indicata della lista. 1 corrisponde al primo elemento della lista.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Restituisce l'elemento nella posizione indicata della lista. 1 corrisponde all'ultimo elemento.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Restituisce il primo elemento in una lista.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Restituisce l'ultimo elemento in una lista.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Restituisce un elemento casuale in una lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Rimuove e restituisce l'elemento nella posizione indicata in una lista. 1 corrisponde al primo elemento.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Rimuove e restituisce l'elemento nella posizione indicata in una lista. 1 corrisponde all'ultimo elemento.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Rimuove e restituisce il primo elemento in una lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Restituisce e rimuove l'ultimo elemento in una lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Restituisce e rimuove un elemento casuale in una lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Rimuove l'elemento nella posizione indicata in una lista. 1 corrisponde al primo elemento.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Rimuove l'elemento nella posizione indicata in una lista. 1 corrisponde all'ultimo elemento.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Rimuove il primo elemento in una lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Rimuove l'ultimo elemento in una lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Rimuove un elemento casuale in una lista.", "LISTS_SET_INDEX_SET": "imposta", "LISTS_SET_INDEX_INSERT": "inserisci in", "LISTS_SET_INDEX_INPUT_TO": "come", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Imposta l'elemento nella posizione indicata di una lista. 1 corrisponde al primo elemento.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Imposta l'elemento nella posizione indicata di una lista. 1 corrisponde all'ultimo elemento.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Imposta il primo elemento in una lista.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Imposta l'ultimo elemento in una lista.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Imposta un elemento casuale in una lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Inserisci un elemento nella posizione indicata in una lista. #1 corrisponde al primo elemento.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Inserisci l'elemento nella posizione indicata in una lista. #1 corrisponde all'ultimo elemento.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Inserisci l'elemento all'inizio della lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Aggiungi un elemento alla fine di una lista", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Inserisce l'elemento casualmente in una lista.", "LISTS_GET_SUBLIST_START_FROM_START": "prendi sotto-lista da #", "LISTS_GET_SUBLIST_START_FROM_END": "prendi sotto-lista da # dalla fine", "LISTS_GET_SUBLIST_START_FIRST": "prendi sotto-lista dall'inizio", "LISTS_GET_SUBLIST_END_FROM_START": "fino a #", "LISTS_GET_SUBLIST_END_FROM_END": "da # dalla fine", "LISTS_GET_SUBLIST_END_LAST": "dagli ultimi", "LISTS_GET_SUBLIST_TOOLTIP": "Crea una copia della porzione specificata di una lista.", "VARIABLES_GET_TOOLTIP": "Restituisce il valore di una variabile.", "VARIABLES_GET_CREATE_SET": "Crea 'imposta %1'", "VARIABLES_SET_TITLE": "imposta", "VARIABLES_SET_TAIL": "a", "VARIABLES_SET_TOOLTIP": "Imposta questa variabile ad essere pari all'input.", "VARIABLES_SET_CREATE_GET": "Crea 'prendi %1'", "PROCEDURES_DEFNORETURN_TITLE": "per", "PROCEDURES_DEFNORETURN_PROCEDURE": "fai qualcosa", "PROCEDURES_BEFORE_PARAMS": "conː", "PROCEDURES_DEFNORETURN_TOOLTIP": "Crea una funzione senza output.", "PROCEDURES_DEFRETURN_RETURN": "ritorna", "PROCEDURES_DEFRETURN_TOOLTIP": "Crea una funzione con un output.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Attenzioneː Questa funzione ha parametri duplicati.", "PROCEDURES_CALLNORETURN_HELPURL": "https://it.wikipedia.org/wiki/Funzione_(informatica)", "PROCEDURES_CALLNORETURN_TOOLTIP": "Esegue la funzione definita dall'utente '%1'.", "PROCEDURES_CALLRETURN_HELPURL": "https://it.wikipedia.org/wiki/Funzione_(informatica)", "PROCEDURES_CALLRETURN_TOOLTIP": "Esegue la funzione definita dall'utente '%1' ed usa il suo output.", "PROCEDURES_MUTATORCONTAINER_TITLE": "input", "PROCEDURES_MUTATORARG_TITLE": "nome inputː", "PROCEDURES_HIGHLIGHT_DEF": "Evidenzia definizione di funzione", "PROCEDURES_CREATE_DO": "Crea '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Se un valore è vero allora restituisce un secondo valore.", "PROCEDURES_IFRETURN_WARNING": "Attenzioneː Questo blocco può essere usato solo all'interno di una definizione di funzione." } ================================================ FILE: extern/blockly/msg/json/ja.json ================================================ { "@metadata": { "authors": [ "Shirayuki", "Oda" ] }, "VARIABLES_DEFAULT_NAME": "項目", "DUPLICATE_BLOCK": "複製", "ADD_COMMENT": "コメントを追加", "REMOVE_COMMENT": "コメントを削除します。", "EXTERNAL_INPUTS": "外部入力", "INLINE_INPUTS": "インライン入力", "DELETE_BLOCK": "ブロックを消す", "DELETE_X_BLOCKS": "%1 個のブロックを消す", "COLLAPSE_BLOCK": "ブロックを折りたたむ", "COLLAPSE_ALL": "ブロックを折りたたむ", "EXPAND_BLOCK": "ブロックを展開します。", "EXPAND_ALL": "ブロックを展開します。", "DISABLE_BLOCK": "ブロックを無効にします。", "ENABLE_BLOCK": "ブロックを有効にします。", "HELP": "ヘルプ", "CHANGE_VALUE_TITLE": "値を変更します。", "NEW_VARIABLE": "新しい変数", "NEW_VARIABLE_TITLE": "新しい変数の、名前", "RENAME_VARIABLE": "変数の名前を変更.", "RENAME_VARIABLE_TITLE": "%1の変数すべてを名前変更します。", "COLOUR_PICKER_HELPURL": "https://ja.wikipedia.org/wiki/色", "COLOUR_PICKER_TOOLTIP": "パレットから色を選んでください。", "COLOUR_RANDOM_TITLE": "ランダムな色", "COLOUR_RANDOM_TOOLTIP": "ランダムな色を選択します。", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "カラーと", "COLOUR_RGB_RED": "赤", "COLOUR_RGB_GREEN": "緑", "COLOUR_RGB_BLUE": "青", "COLOUR_RGB_TOOLTIP": "赤、緑、および青の指定された量で色を作成します。すべての値は 0 ~ 100 の間でなければなりません。", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "ブレンド", "COLOUR_BLEND_COLOUR1": "色 1", "COLOUR_BLEND_COLOUR2": "色 2", "COLOUR_BLEND_RATIO": "割合", "COLOUR_BLEND_TOOLTIP": "ブレンド2 つの色を指定された比率に混ぜる」 (0.0 ~ 1.0)。", "CONTROLS_REPEAT_HELPURL": "https://ja.wikipedia.org/wiki/for文", "CONTROLS_REPEAT_TITLE": "%1 回、繰り返します", "CONTROLS_REPEAT_TITLE_REPEAT": "繰り返し", "CONTROLS_REPEAT_TITLE_TIMES": "回", "CONTROLS_REPEAT_INPUT_DO": "してください", "CONTROLS_REPEAT_TOOLTIP": "いくつかのステートメントを数回行います。", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "つつその間、繰り返す4", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "までを繰り返します", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "値は true のあいだ、いくつかのステートメントを行います。", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "値は false のあいだ、いくつかのステートメントを行います。", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "変数 %1は、指定した間隔ごとのカウントを開始番号から 終了番号まで、値をとり、指定したブロックを行う必要があります。", "CONTROLS_FOR_INPUT_WITH": "で、カウントします。", "CONTROLS_FOR_INPUT_FROM_TO_BY": "%1 から%2、 %3 で", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each", "CONTROLS_FOREACH_INPUT_ITEM": "各項目の", "CONTROLS_FOREACH_INPUT_INLIST": "リストで", "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "", "CONTROLS_FOREACH_TOOLTIP": "リストの各項目に対して変数 '%1' のアイテムに設定し、いくつかのステートメントをしてください。", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "ループから抜け出す", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "ループの次の反復処理を続行します。", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "含むループから抜け出します。", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "このループの残りの部分をスキップし、次のイテレーションに進みます。", "CONTROLS_FLOW_STATEMENTS_WARNING": "注意: このブロックは、ループ内でのみ使用します。", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "値が true の場合はその後ステートメントを行をいくつかします。", "CONTROLS_IF_TOOLTIP_2": "値が true 場合は、ステートメントの最初のブロックを行います。それ以外の場合は、ステートメントの 2 番目のブロックを行います。", "CONTROLS_IF_TOOLTIP_3": "最初の値が true 場合は、ステートメントの最初のブロックを行います。それ以外の場合は、2 番目の値が true の場合、ステートメントの 2 番目のブロックをします。", "CONTROLS_IF_TOOLTIP_4": "最初の値が true 場合は、ステートメントの最初のブロックを行います。2 番目の値が true の場合は、ステートメントの 2 番目のブロックを行います。それ以外の場合は最後のブロックのステートメントを行います。", "CONTROLS_IF_MSG_IF": "もし", "CONTROLS_IF_MSG_ELSEIF": "他でもし", "CONTROLS_IF_MSG_ELSE": "他", "CONTROLS_IF_IF_TOOLTIP": "追加、削除、またはセクションを順序変更して、ブロックをこれを再構成します。", "CONTROLS_IF_ELSEIF_TOOLTIP": "場合に条件にブロック追加。", "CONTROLS_IF_ELSE_TOOLTIP": "Ifブロックに、すべてをキャッチする条件を追加。", "LOGIC_COMPARE_HELPURL": "https://ja.wikipedia.org/wiki/不等式", "LOGIC_COMPARE_TOOLTIP_EQ": "もし両方がお互いに等しく入力した場合は true を返します。", "LOGIC_COMPARE_TOOLTIP_NEQ": "両方の入力が互いに等しくない場合に true を返します。", "LOGIC_COMPARE_TOOLTIP_LT": "最初の入力が 2 番目の入力よりも小さいい場合は true を返します。", "LOGIC_COMPARE_TOOLTIP_LTE": "もし、最初の入力が二つ目入力より少ないか、おなじであったらTRUEをかえしてください", "LOGIC_COMPARE_TOOLTIP_GT": "最初の入力が 2 番目の入力よりも大きい場合は true を返します。", "LOGIC_COMPARE_TOOLTIP_GTE": "もし入力がふたつめの入よりも大きかったらtrueをり返します。", "LOGIC_OPERATION_HELPURL": "https://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "両方の入力がおんなじ場わいわtrue を返します。", "LOGIC_OPERATION_AND": "そして", "LOGIC_OPERATION_TOOLTIP_OR": "最低少なくとも 1 つの入力が true の場合は true を返します。", "LOGIC_OPERATION_OR": "または", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "%1 ではないです。", "LOGIC_NEGATE_TOOLTIP": "入力が false の場合は、true を返します。入力が true の場合は false を返します。", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "true", "LOGIC_BOOLEAN_FALSE": "false", "LOGIC_BOOLEAN_TOOLTIP": "True または false を返します。", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "null", "LOGIC_NULL_TOOLTIP": "Null を返します。", "LOGIC_TERNARY_HELPURL": "https://ja.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "テスト", "LOGIC_TERNARY_IF_TRUE": "true の場合", "LOGIC_TERNARY_IF_FALSE": "false の場合", "LOGIC_TERNARY_TOOLTIP": "'テスト' の条件をチェックします。条件が true の場合、'true' の値を返します。それ以外の場合 'false' のを返します。", "MATH_NUMBER_HELPURL": "https://ja.wikipedia.org/wiki/数", "MATH_NUMBER_TOOLTIP": "数です。", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "×", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "asin", "MATH_TRIG_ACOS": "acos", "MATH_TRIG_ATAN": "atan", "MATH_ARITHMETIC_HELPURL": "https://ja.wikipedia.org/wiki/算術", "MATH_ARITHMETIC_TOOLTIP_ADD": "2 つの数の合計を返します。", "MATH_ARITHMETIC_TOOLTIP_MINUS": "2 つの数の差を返します。", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "2 つの数の積を返します。", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "2 つの数の商を返します。", "MATH_ARITHMETIC_TOOLTIP_POWER": "最初の数を2 番目の値で累乗した結果を返します。", "MATH_SINGLE_HELPURL": "https://ja.wikipedia.org/wiki/平方根", "MATH_SINGLE_OP_ROOT": "平方根", "MATH_SINGLE_TOOLTIP_ROOT": "平方根を返す", "MATH_SINGLE_OP_ABSOLUTE": "絶対値", "MATH_SINGLE_TOOLTIP_ABS": "絶対値を返す", "MATH_SINGLE_TOOLTIP_NEG": "負の数を返す", "MATH_SINGLE_TOOLTIP_LN": "数値の自然対数をかえしてください", "MATH_SINGLE_TOOLTIP_LOG10": "log 10 を返す。", "MATH_SINGLE_TOOLTIP_EXP": "数値の e 粂を返す", "MATH_SINGLE_TOOLTIP_POW10": "10の x 乗", "MATH_TRIG_HELPURL": "https://ja.wikipedia.org/wiki/三角関数", "MATH_TRIG_TOOLTIP_SIN": "番号のsineの次数を返す", "MATH_TRIG_TOOLTIP_COS": "番号のcosineの次数を返す", "MATH_TRIG_TOOLTIP_TAN": "番号のtangentの次数を返す", "MATH_TRIG_TOOLTIP_ASIN": "番号のarcsine を返すます", "MATH_TRIG_TOOLTIP_ACOS": "arccosine の値を返す", "MATH_TRIG_TOOLTIP_ATAN": "番号のarctangent を返すます", "MATH_CONSTANT_HELPURL": "https://ja.wikipedia.org/wiki/数学定数", "MATH_CONSTANT_TOOLTIP": "いずれかの共通の定数のを返す: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (無限).", "MATH_IS_EVEN": "わ偶数", "MATH_IS_ODD": "奇数です。", "MATH_IS_PRIME": "素数です", "MATH_IS_WHOLE": "は整数", "MATH_IS_POSITIVE": "正の値", "MATH_IS_NEGATIVE": "負の値", "MATH_IS_DIVISIBLE_BY": "割り切れる", "MATH_IS_TOOLTIP": "数字が、偶数、奇数、素数、整数、正数、負数、またはそれが特定の数で割り切れる場合かどうかを確認してください。どの制限が一つでも本当でしたら true をかえしてください、そうでない場合わ falseを返してください。", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "変更", "MATH_CHANGE_INPUT_BY": "に", "MATH_CHANGE_TOOLTIP": "'%1' をたします。", "MATH_ROUND_HELPURL": "https://ja.wikipedia.org/wiki/端数処理", "MATH_ROUND_TOOLTIP": "数値を切り上げるか切り捨てる", "MATH_ROUND_OPERATOR_ROUND": "概数", "MATH_ROUND_OPERATOR_ROUNDUP": "数値を切り上げ", "MATH_ROUND_OPERATOR_ROUNDDOWN": "端数を切り捨てる", "MATH_ONLIST_HELPURL": "", "MATH_ONLIST_OPERATOR_SUM": "リストの合計", "MATH_ONLIST_TOOLTIP_SUM": "全部リストの数をたして返す", "MATH_ONLIST_OPERATOR_MIN": "リストの最小の数", "MATH_ONLIST_TOOLTIP_MIN": "リストの最小数を返します。", "MATH_ONLIST_OPERATOR_MAX": "リストの最大値", "MATH_ONLIST_TOOLTIP_MAX": "リストの最大数を返します。", "MATH_ONLIST_OPERATOR_AVERAGE": "リストの平均", "MATH_ONLIST_TOOLTIP_AVERAGE": "リストの数値の平均 (算術平均) を返します。", "MATH_ONLIST_OPERATOR_MEDIAN": "リストの中央値", "MATH_ONLIST_TOOLTIP_MEDIAN": "リストの中央値の数を返します。", "MATH_ONLIST_OPERATOR_MODE": "一覧モード", "MATH_ONLIST_TOOLTIP_MODE": "リストで最も一般的な項目のリストを返します。", "MATH_ONLIST_OPERATOR_STD_DEV": "リストの標準偏差", "MATH_ONLIST_TOOLTIP_STD_DEV": "リウトの標準偏差をかえす", "MATH_ONLIST_OPERATOR_RANDOM": "リストのランダム アイテム", "MATH_ONLIST_TOOLTIP_RANDOM": "リストからランダムに要素を返します。", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "残りの %1 ÷ %2", "MATH_MODULO_TOOLTIP": "2 つの数値を除算した残りを返します。", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "制限%1下リミット%2上限リミット%3", "MATH_CONSTRAIN_TOOLTIP": "値を、上限 x と下限 y のあいだに制限んする(上限と下限が、x と y とに同じ場合わ、上限の値は x, 下限の値はy)。", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "%1 から %2 への無作為の整数", "MATH_RANDOM_INT_TOOLTIP": "指定した下限の間、無作為なランダムな整数を返します。", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "ランダムな分数", "MATH_RANDOM_FLOAT_TOOLTIP": "ランダムな分数を返すー0.0 (包括) の間のと 1.0 (排他的な)。", "TEXT_TEXT_HELPURL": "https://ja.wikipedia.org/wiki/文字列", "TEXT_TEXT_TOOLTIP": "文字、単語、または行のテキスト。", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "テキストを作成します。", "TEXT_JOIN_TOOLTIP": "任意の数の項目一部を一緒に接合してテキストの作成します。", "TEXT_CREATE_JOIN_TITLE_JOIN": "結合", "TEXT_CREATE_JOIN_TOOLTIP": "追加、削除、またはセクションを順序変更して、ブロックを再構成します。", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "テキスト をアイテム追加します。", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "宛先", "TEXT_APPEND_APPENDTEXT": "テキストを追加します。", "TEXT_APPEND_TOOLTIP": "変数 '%1' にいくつかのテキストを追加します。", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "%1 の長さ", "TEXT_LENGTH_TOOLTIP": "指定されたテキストの文字 (スペースを含む) の数を返します。", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 が空", "TEXT_ISEMPTY_TOOLTIP": "指定されたテキストが空の場合は、true を返します。", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "最初のテキストの二番目のてきすとの、最初と最後の、出現したインデックスをかえします。テキストが見つからない場合は 0 を返します。", "TEXT_INDEXOF_INPUT_INTEXT": "テキストで", "TEXT_INDEXOF_OPERATOR_FIRST": "テキストの最初の出現箇所を検索します。", "TEXT_INDEXOF_OPERATOR_LAST": "テキストの最後に見つかったを検索します。", "TEXT_INDEXOF_TAIL": "", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "テキストで", "TEXT_CHARAT_FROM_START": "文字# を取得", "TEXT_CHARAT_FROM_END": "一番最後の言葉、キャラクターを所得", "TEXT_CHARAT_FIRST": "最初の文字を得る", "TEXT_CHARAT_LAST": "最後の文字を得る", "TEXT_CHARAT_RANDOM": "ランダムな文字を得る", "TEXT_CHARAT_TAIL": "", "TEXT_CHARAT_TOOLTIP": "指定された位置に文字を返します。", "TEXT_GET_SUBSTRING_TOOLTIP": "テキストの指定部分を返します。", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "テキストで", "TEXT_GET_SUBSTRING_START_FROM_START": "文字列からの部分文字列を取得 #", "TEXT_GET_SUBSTRING_START_FROM_END": "部分文字列を取得する #端から得る", "TEXT_GET_SUBSTRING_START_FIRST": "部分文字列を取得する。", "TEXT_GET_SUBSTRING_END_FROM_START": "# の文字", "TEXT_GET_SUBSTRING_END_FROM_END": "文字列の# 終わりからの#", "TEXT_GET_SUBSTRING_END_LAST": "最後のの文字", "TEXT_GET_SUBSTRING_TAIL": "", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "別のケースに、テキストのコピーを返します。", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "大文字に変換する", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "小文字に", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "タイトル ケースに", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "スペースを 1 つまたは両方の端から削除したのち、テキストのコピーを返します。", "TEXT_TRIM_OPERATOR_BOTH": "両端のスペースを取り除く", "TEXT_TRIM_OPERATOR_LEFT": "左端のスペースを取り除く", "TEXT_TRIM_OPERATOR_RIGHT": "右端のスペースを取り除く", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "%1 を印刷します。", "TEXT_PRINT_TOOLTIP": "指定したテキスト、番号または他の値を印刷します。", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "メッセージをプロンプトしてにテキストを求める", "TEXT_PROMPT_TYPE_NUMBER": "メッセージを送って番号の入力を求める", "TEXT_PROMPT_TOOLTIP_NUMBER": "ユーザーにプロンプトして数字のインプットを求めます", "TEXT_PROMPT_TOOLTIP_TEXT": "いくつかのテキストを、ユーザーに入力するようにプロンプト。", "LISTS_CREATE_EMPTY_HELPURL": "https://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "空のリストを作成します。", "LISTS_CREATE_EMPTY_TOOLTIP": "長さゼロ、データ レコード空のリストを返します", "LISTS_CREATE_WITH_TOOLTIP": "アイテム数かぎりないのリストを作成します。", "LISTS_CREATE_WITH_INPUT_WITH": "これを使ってリストを作成します。", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "リスト", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "追加、削除、またはセクションを順序変更して、ブロックを再構成します。", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "リストにアイテムを追加します。", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "指定された値をなんどか繰り返してリストを作ります。", "LISTS_REPEAT_TITLE": "アイテム %1 と一緒にリストを作成し %2 回繰り", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": " %1の長さ", "LISTS_LENGTH_TOOLTIP": "リストの長さを返します。", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 が空", "LISTS_TOOLTIP": "リストが空の場合は、true を返します。", "LISTS_INLIST": "リストで", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "最初に見つかった項目を検索します。", "LISTS_INDEX_OF_LAST": "最後に見つかったアイテムを見つける", "LISTS_INDEX_OF_TOOLTIP": "リスト項目の最初/最後に出現するインデックス位置を返します。テキストが見つからない場合は 0 を返します。", "LISTS_GET_INDEX_GET": "取得", "LISTS_GET_INDEX_GET_REMOVE": "取得と削除", "LISTS_GET_INDEX_REMOVE": "削除", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "終しまいから #", "LISTS_GET_INDEX_FIRST": "最初", "LISTS_GET_INDEX_LAST": "最後", "LISTS_GET_INDEX_RANDOM": "ランダム", "LISTS_GET_INDEX_TAIL": "", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "リスト内の指定位置にある項目を返します。# 1 は、最初の項目です。", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "リスト内の指定位置にある項目を返します。# 1 は、最後の項目です。", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "リストの最初の項目を返信します。", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "リストの最後の項目を返します。", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "ランダム アイテム リストを返します。", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "リスト内の指定位置にある項目を削除し、返します。# 1 は、最後の項目です。", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "リスト内の指定位置にある項目を削除し、返します。# 1 は、最後の項目です。", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "リスト内の最初の項目を削除したあと返します。", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "リスト内の最後の項目を削除したあと返します。", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "リストのランダムなアイテムを削除し、返します。", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "リスト内の指定位置にある項目を返します。# 1 は、最初の項目です。", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "リスト内の指定位置にある項目を削除します。# 1 は、最後の項目です。", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "リスト内の最初の項目を削除します。", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "リスト内の最後の項目を削除します。", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "リスト内にある任意のアイテムを削除します。", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "セット", "LISTS_SET_INDEX_INSERT": "挿入します。", "LISTS_SET_INDEX_INPUT_TO": "として", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "リスト内の指定された位置に項目を設定します。# 1 は、最初の項目です。", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "リスト内の指定された位置に項目を設定します。# 1 は、最後の項目です。", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "リスト内に最初の項目を設定します。", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "リスト内の最後の項目を設定します。", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "リスト内にランダムなアイテムを設定します。", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "リスト内の指定位置に項目を挿入します。# 1 は、最初の項目です。", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "リスト内の指定位置に項目を挿入します。# 1 は、最後の項目です。", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "リストの先頭に項目を挿入します。", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "リストの末尾に項目を追加します。", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "リストに項目をランダムに挿入します。", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "# からサブディレクトリのリストを取得します。", "LISTS_GET_SUBLIST_START_FROM_END": "端から #のサブリストを取得します。", "LISTS_GET_SUBLIST_START_FIRST": "最初からサブリストを取得する。", "LISTS_GET_SUBLIST_END_FROM_START": "#へ", "LISTS_GET_SUBLIST_END_FROM_END": "最後から#へ", "LISTS_GET_SUBLIST_END_LAST": "最後へ", "LISTS_GET_SUBLIST_TAIL": "", "LISTS_GET_SUBLIST_TOOLTIP": "リストの指定された部分のコピーを作成してくださ。", "ORDINAL_NUMBER_SUFFIX": "", "VARIABLES_GET_HELPURL": "https://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TITLE": "", "VARIABLES_GET_TAIL": "", "VARIABLES_GET_TOOLTIP": "この変数の値を返します。", "VARIABLES_GET_CREATE_SET": "'セット%1を作成します。", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "セット", "VARIABLES_SET_TAIL": "宛先", "VARIABLES_SET_TOOLTIP": "この入力を変数と等しくなるように設定します。", "VARIABLES_SET_CREATE_GET": "'%1 を取得' を作成します。", "PROCEDURES_DEFNORETURN_HELPURL": "https://ja.wikipedia.org/wiki/サブルーチン", "PROCEDURES_DEFNORETURN_TITLE": "宛先", "PROCEDURES_DEFNORETURN_PROCEDURE": "何かしてください", "PROCEDURES_BEFORE_PARAMS": "で。", "PROCEDURES_DEFNORETURN_DO": "", "PROCEDURES_DEFNORETURN_TOOLTIP": "出力なしで関数を作成します。", "PROCEDURES_DEFRETURN_HELPURL": "https://ja.wikipedia.org/wiki/サブルーチン", "PROCEDURES_DEFRETURN_RETURN": "返す", "PROCEDURES_DEFRETURN_TOOLTIP": "出力を持つ関数を作成します。", "PROCEDURES_DEF_DUPLICATE_WARNING": "警告: この関数は、重複するパラメーターがあります。", "PROCEDURES_CALLNORETURN_HELPURL": "https://ja.wikipedia.org/wiki/サブルーチン", "PROCEDURES_CALLNORETURN_CALL": "", "PROCEDURES_CALLNORETURN_TOOLTIP": "ユーザー定義関数 '%1' を実行します。", "PROCEDURES_CALLRETURN_HELPURL": "https://ja.wikipedia.org/wiki/サブルーチン", "PROCEDURES_CALLRETURN_TOOLTIP": "ユーザー定義関数 '%1' を実行し、その出力を使用します。", "PROCEDURES_MUTATORCONTAINER_TITLE": "入力", "PROCEDURES_MUTATORARG_TITLE": "入力名:", "PROCEDURES_HIGHLIGHT_DEF": "関数の内容を強調表示します。", "PROCEDURES_CREATE_DO": "%1をつくる", "PROCEDURES_IFRETURN_TOOLTIP": "1番目値が true の場合、2 番目の値を返します。", "PROCEDURES_IFRETURN_WARNING": "警告: このブロックは、関数定義内でのみ使用できます。" } ================================================ FILE: extern/blockly/msg/json/keys.json ================================================ { ================================================ FILE: extern/blockly/msg/json/ko.json ================================================ { "@metadata": { "authors": [ "Hym411", "아라" ] }, "VARIABLES_DEFAULT_NAME": "항목", "DUPLICATE_BLOCK": "블록 복사 & 붙여넣기", "ADD_COMMENT": "덧글 추가", "REMOVE_COMMENT": "내용 제거", "EXTERNAL_INPUTS": "외부 입력", "INLINE_INPUTS": "내부 입력", "DELETE_BLOCK": "블록 삭제", "DELETE_X_BLOCKS": "블록 삭제", "COLLAPSE_BLOCK": "블록 축소", "COLLAPSE_ALL": "블록 축소", "EXPAND_BLOCK": "블록 확장", "EXPAND_ALL": "블록 확장", "DISABLE_BLOCK": "블록 비활성화", "ENABLE_BLOCK": "블록 활성화", "HELP": "도움말", "CHANGE_VALUE_TITLE": "값 변경:", "NEW_VARIABLE": "새 변수", "NEW_VARIABLE_TITLE": "새 변수 이름:", "RENAME_VARIABLE": "변수 이름 바꾸기:", "RENAME_VARIABLE_TITLE": "'%1' 변수 이름을 바꾸기:", "COLOUR_PICKER_HELPURL": "https://ko.wikipedia.org/wiki/색", "COLOUR_PICKER_TOOLTIP": "팔레트에서 색을 고릅니다", "COLOUR_RANDOM_TITLE": "임의 색상", "COLOUR_RANDOM_TOOLTIP": "무작위로 색을 고릅니다.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "RGB 색", "COLOUR_RGB_RED": "빨강", "COLOUR_RGB_GREEN": "초록", "COLOUR_RGB_BLUE": "파랑", "COLOUR_RGB_TOOLTIP": "빨강,파랑,초록의 값을 이용하여 색을 만드십시오. 모든 값은 0과 100 사이에 있어야 합니다.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "혼합", "COLOUR_BLEND_COLOUR1": "색 1", "COLOUR_BLEND_COLOUR2": "색 2", "COLOUR_BLEND_RATIO": "비율", "COLOUR_BLEND_TOOLTIP": "두 색을 주어진 비율로 혼합 (0.0 - 1.0)", "CONTROLS_REPEAT_HELPURL": "https://ko.wikipedia.org/wiki/For_루프", "CONTROLS_REPEAT_TITLE": "%1회 반복", "CONTROLS_REPEAT_TITLE_REPEAT": "반복", "CONTROLS_REPEAT_TITLE_TIMES": "회", "CONTROLS_REPEAT_INPUT_DO": "하기", "CONTROLS_REPEAT_TOOLTIP": "여러 번 반복해 명령들을 실행합니다.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "동안 반복", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "다음까지 반복", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "값이 참일 때, 몇가지 선언을 합니다.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "값이 거짓일 때, 몇가지 선언을 합니다.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "변수 %1 의 값을 변경하면서 반복 실행합니다. 변수에 저장되는 값은, 첫번째 수부터 두번째 수까지, 일정 값씩 늘어납니다.", "CONTROLS_FOR_INPUT_WITH": "으로 계산", "CONTROLS_FOR_INPUT_FROM_TO_BY": "%1에서 %3을 이용하여 %2로", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each", "CONTROLS_FOREACH_INPUT_ITEM": "각 항목에 대해", "CONTROLS_FOREACH_INPUT_INLIST": "목록으로", "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "", "CONTROLS_FOREACH_TOOLTIP": "리스트 안에 들어있는 각 아이템들을, 순서대로 변수 '%1' 에 한 번씩 저장시키고, 그 때 마다 명령을 실행합니다.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "반복 중단", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "다음 반복", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "현재 반복 실행 블록을, 빠져나갑니다.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "나머지 반복 부분을 더이상 실행하지 않고, 다음 반복을 수행합니다.", "CONTROLS_FLOW_STATEMENTS_WARNING": "경고 : 이 블록은 반복 실행 블록 안에서만 사용됩니다.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "조건식의 계산 결과가 참이면, 명령을 실행합니다.", "CONTROLS_IF_TOOLTIP_2": "조건식의 계산 결과가 참이면, 첫번째 블록의 명령을 실행하고, 그렇지 않으면 두번째 블록의 명령을 실행합니다.", "CONTROLS_IF_TOOLTIP_3": "첫번째 조건식의 계산 결과가 참이면, 첫번째 블록의 명령을 실행하고, 두번째 조건식의 계산 결과가 참이면, 두번째 블록의 명령을 실행합니다.", "CONTROLS_IF_TOOLTIP_4": "첫번째 조건식의 계산 결과가 참이면, 첫번째 블록의 명령을 실행하고, 두번째 조건식의 계산 결과가 참이면, 두번째 블록의 명령을 실행하고, ... , 어떤 조건식의 계산 결과도 참이 아니면, 마지막 블록의 명령을 실행합니다.", "CONTROLS_IF_MSG_IF": "만약에", "CONTROLS_IF_MSG_ELSEIF": "다른 경우", "CONTROLS_IF_MSG_ELSE": "아니라면", "CONTROLS_IF_IF_TOOLTIP": "\"만약\" 블록의 내용을 추가, 삭제, 재구성 합니다.", "CONTROLS_IF_ELSEIF_TOOLTIP": "\"만약\" 블록에 조건 검사를 추가합니다.", "CONTROLS_IF_ELSE_TOOLTIP": "\"만약\" 블록의 마지막에, 모든 검사 결과가 거짓인 경우 실행할 부분을 추가합니다.", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "두 값이 같으면, 참(true) 값을 돌려줍니다.", "LOGIC_COMPARE_TOOLTIP_NEQ": "두 값이 서로 다르면, 참(true) 값을 돌려줍니다.", "LOGIC_COMPARE_TOOLTIP_LT": "첫 번째 값이 두 번째 값보다 작으면, 참(true) 값을 돌려줍니다.", "LOGIC_COMPARE_TOOLTIP_LTE": "첫 번째 값이 두 번째 값보다 작거나 같으면, 참(true) 값을 돌려줍니다.", "LOGIC_COMPARE_TOOLTIP_GT": "첫 번째 값이 두 번째 값보다 크면, 참(true) 값을 돌려줍니다.", "LOGIC_COMPARE_TOOLTIP_GTE": "첫 번째 값이 두 번째 값보다 크거나 같으면, 참(true) 값을 돌려줍니다.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "두 값이 모두 참(true) 값이면, 참 값을 돌려줍니다.", "LOGIC_OPERATION_AND": "그리고", "LOGIC_OPERATION_TOOLTIP_OR": "적어도 하나의 값이 참일 경우 참을 반환합니다.", "LOGIC_OPERATION_OR": "또는", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "%1 의 반대", "LOGIC_NEGATE_TOOLTIP": "입력값이 거짓이라면 참을 반환합니다. 참이라면 거짓을 반환합니다.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "참", "LOGIC_BOOLEAN_FALSE": "거짓", "LOGIC_BOOLEAN_TOOLTIP": "참 혹은 거짓 모두 반환합니다.", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "빈 값", "LOGIC_NULL_TOOLTIP": "빈 값을 반환합니다.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "테스트", "LOGIC_TERNARY_IF_TRUE": "만약 참이라면", "LOGIC_TERNARY_IF_FALSE": "만약 거짓이라면", "LOGIC_TERNARY_TOOLTIP": "'검사' 를 진행해, 결과가 참(true)이면 '참이면' 부분의 값을 돌려줍니다. ; 결과가 참이 아니면, '거짓이면' 부분의 값을 돌려줍니다.", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "수", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "x", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "asin", "MATH_TRIG_ACOS": "acos", "MATH_TRIG_ATAN": "atan", "MATH_ARITHMETIC_HELPURL": "https://en.wikipedia.org/wiki/Arithmetic", "MATH_ARITHMETIC_TOOLTIP_ADD": "두 수의 합을 반환합니다.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "두 수간의 차이를 반환합니다.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "두 수의 곱을 반환합니다.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "두 수의 나눈 결과를 반환합니다.", "MATH_ARITHMETIC_TOOLTIP_POWER": "첫 번째 수를 두 번째 수 만큼, 거듭제곱 한 결괏값을 돌려줍니다.", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "제곱근", "MATH_SINGLE_TOOLTIP_ROOT": "숫자의 제곱근을 반환합니다.", "MATH_SINGLE_OP_ABSOLUTE": "절대값", "MATH_SINGLE_TOOLTIP_ABS": "어떤 수의 절대값(absolute)을 계산한 결과를, 정수값으로 돌려줍니다.", "MATH_SINGLE_TOOLTIP_NEG": "음(-)/양(+), 부호를 반대로 하여 값을 돌려줍니다.", "MATH_SINGLE_TOOLTIP_LN": "어떤 수의, 자연로그(natural logarithm) 값을 돌려줍니다.(밑 e, 예시 log e x)", "MATH_SINGLE_TOOLTIP_LOG10": "어떤 수의, 기본로그(logarithm) 값을 돌려줍니다.(밑 10, 예시 log 10 x)", "MATH_SINGLE_TOOLTIP_EXP": "e 의, 거듭제곱(power) 값을 돌려줍니다.", "MATH_SINGLE_TOOLTIP_POW10": "10 의, 거듭제곱(power) 값을 돌려줍니다.", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "어떤 각도(degree, radian 아님)의, sin(sine) 값을 계산해 돌려줍니다.", "MATH_TRIG_TOOLTIP_COS": "어떤 각도(degree, radian 아님)의, cos(cosine) 값을 계산해 돌려줍니다.", "MATH_TRIG_TOOLTIP_TAN": "어떤 각도(degree, radian 아님)의, tan(tangent) 값을 계산해 돌려줍니다.", "MATH_TRIG_TOOLTIP_ASIN": "어떤 수에 대한, asin(arcsine) 값을 돌려줍니다.", "MATH_TRIG_TOOLTIP_ACOS": "어떤 수에 대한, acos(arccosine) 값을 돌려줍니다.", "MATH_TRIG_TOOLTIP_ATAN": "어떤 수에 대한, atan(arctangent) 값을 돌려줍니다.", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "일반적인 상수 값들 중 하나를 돌려줍니다. : π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (infinity).", "MATH_IS_EVEN": "가 짝수(even) 이면", "MATH_IS_ODD": "가 홀수(odd) 이면", "MATH_IS_PRIME": "가 소수(prime) 이면", "MATH_IS_WHOLE": "가 정수이면", "MATH_IS_POSITIVE": "가 양(+)수 이면", "MATH_IS_NEGATIVE": "가 음(-)수 이면", "MATH_IS_DIVISIBLE_BY": "가 다음 수로 나누어 떨어지면 :", "MATH_IS_TOOLTIP": "어떤 수가 짝 수, 홀 수, 소 수, 정 수, 양 수, 음 수, 나누어 떨어지는 수 인지 검사해 결괏값을 돌려줍니다. 참(true) 또는 거짓(false) 값을 돌려줌.", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "값 변경", "MATH_CHANGE_INPUT_BY": "만큼", "MATH_CHANGE_TOOLTIP": "변수 '%1' 에 저장되어있는 값에, 어떤 수를 더해, 변수에 다시 저장합니다.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "어떤 수를 반올림/올림/버림한 결과를, 정수값으로 돌려줍니다.", "MATH_ROUND_OPERATOR_ROUND": "반올림", "MATH_ROUND_OPERATOR_ROUNDUP": "올림", "MATH_ROUND_OPERATOR_ROUNDDOWN": "버림", "MATH_ONLIST_HELPURL": "", "MATH_ONLIST_OPERATOR_SUM": "합", "MATH_ONLIST_TOOLTIP_SUM": "리스트에 들어있는 수(값)들을, 모두 합(sum) 한, 총합(sum)을 돌려줍니다.", "MATH_ONLIST_OPERATOR_MIN": "최소값", "MATH_ONLIST_TOOLTIP_MIN": "리스트에 들어있는 수(값) 들 중, 가장 작은(min) 수(값)를 돌려줍니다.", "MATH_ONLIST_OPERATOR_MAX": "최대값", "MATH_ONLIST_TOOLTIP_MAX": "리스트에 들어있는 수(값) 들 중, 가장 큰(max) 수(값)를 돌려줍니다.", "MATH_ONLIST_OPERATOR_AVERAGE": "평균값", "MATH_ONLIST_TOOLTIP_AVERAGE": "리스트에 들어있는 수(값)들에 대해, 산술 평균(arithmetic mean) 한 값을 돌려줍니다.", "MATH_ONLIST_OPERATOR_MEDIAN": "중간값", "MATH_ONLIST_TOOLTIP_MEDIAN": "리스트에 들어있는 수(값) 들 중, 중간(median) 수(값)를 돌려줍니다.", "MATH_ONLIST_OPERATOR_MODE": "가장 여러 개 있는 값", "MATH_ONLIST_TOOLTIP_MODE": "리스트에 들어있는 아이템들 중에서, 가장 여러 번 들어있는 아이템들을 리스트로 만들어 돌려줍니다. (최빈값, modes)", "MATH_ONLIST_OPERATOR_STD_DEV": "표준 편차", "MATH_ONLIST_TOOLTIP_STD_DEV": "리스트에 들어있는 수(값)들에 대해, 표준 편차(standard deviation) 를 구해 돌려줍니다.", "MATH_ONLIST_OPERATOR_RANDOM": "랜덤 아이템", "MATH_ONLIST_TOOLTIP_RANDOM": "리스트에 들어있는 아이템들 중에서, 랜덤(random)으로 아이템을 돌려줍니다.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "%1 를 %2 로 나눈 나머지", "MATH_MODULO_TOOLTIP": "첫 번째 수를 두 번째 수로 나눈, 나머지 값을 돌려줍니다.", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "%1 의 값을, 최소 %2 최대 %3 으로 조정", "MATH_CONSTRAIN_TOOLTIP": "어떤 수를, 특정 범위의 값이 되도록 강제로 조정합니다.", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "랜덤정수(%1\u003C= n \u003C=%2)", "MATH_RANDOM_INT_TOOLTIP": "주어진 범위에서, 랜덤 정수값을 돌려줍니다.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "랜덤 실수(0.0\u003C= f \u003C1.0)", "MATH_RANDOM_FLOAT_TOOLTIP": "랜덤 실수 값(0.0\u003C= f \u003C1.0)을 돌려줍니다.", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "문자, 단어, 문장.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "텍스트 만들기", "TEXT_JOIN_TOOLTIP": "여러 개의 아이템들을 연결해(묶어), 새로운 문장을 만듭니다.", "TEXT_CREATE_JOIN_TITLE_JOIN": "가입", "TEXT_CREATE_JOIN_TOOLTIP": "이 문장 블록의 구성을 추가, 삭제, 재구성 합니다.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "문장을 만들 조각 아이템", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "다음", "TEXT_APPEND_APPENDTEXT": "내용 덧붙이기", "TEXT_APPEND_TOOLTIP": "'%1' 의 마지막에 문장을 덧붙입니다.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "다음 문장의 문자 개수 %1", "TEXT_LENGTH_TOOLTIP": "입력된 문장의, 문자 개수를 돌려줍니다.(공백문자 포함)", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1이 비어있습니다", "TEXT_ISEMPTY_TOOLTIP": "입력된 문장이, 빈 문장(\"\")이면 참(true) 값을 돌려줍니다.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "어떤 문장이 가장 처음 나타난 위치 또는, 가장 마지막으로 나타난 위치를 찾아 돌려줍니다. 찾는 문장이 없는 경우는 0 값을 돌려줌.", "TEXT_INDEXOF_INPUT_INTEXT": "문장", "TEXT_INDEXOF_OPERATOR_FIRST": "에서 다음 문장이 처음으로 나타난 위치 찾기 :", "TEXT_INDEXOF_OPERATOR_LAST": "에서 다음 문장이 마지막으로 나타난 위치 찾기 :", "TEXT_INDEXOF_TAIL": "", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "문장", "TEXT_CHARAT_FROM_START": "에서, 앞에서부터 # 번째 위치의 문자 얻기", "TEXT_CHARAT_FROM_END": "에서, 마지막부터 # 번째 위치의 문자 얻기", "TEXT_CHARAT_FIRST": "에서, 첫 번째 문자 얻기", "TEXT_CHARAT_LAST": "에서, 마지막 문자 얻기", "TEXT_CHARAT_RANDOM": "에서, 랜덤하게 한 문자 얻기", "TEXT_CHARAT_TAIL": "", "TEXT_CHARAT_TOOLTIP": "특정 번째 위치에서, 문자를 얻어내 돌려줍니다.", "TEXT_GET_SUBSTRING_TOOLTIP": "문장 중 일부를 얻어내 돌려줍니다.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "문장", "TEXT_GET_SUBSTRING_START_FROM_START": "에서, 처음부터 # 번째 문자부터 얻어냄", "TEXT_GET_SUBSTRING_START_FROM_END": "에서, 마지막에서 # 번째부터 얻어냄", "TEXT_GET_SUBSTRING_START_FIRST": "에서, 처음부터 얻어냄", "TEXT_GET_SUBSTRING_END_FROM_START": "# 번째 문자까지", "TEXT_GET_SUBSTRING_END_FROM_END": "끝에서부터 # 번째 문자까지", "TEXT_GET_SUBSTRING_END_LAST": "마지막 문자까지", "TEXT_GET_SUBSTRING_TAIL": "", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "영문 대소문자 형태를 변경해 돌려줍니다.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "대문자로", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "소문자로", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "첫 문자만 대문자로", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "문장의 왼쪽/오른쪽/양쪽에서 스페이스 문자를 제거해 돌려줍니다.", "TEXT_TRIM_OPERATOR_BOTH": "다음 문장에서 양쪽(왼쪽+오른쪽) 공백문자(space) 제거 :", "TEXT_TRIM_OPERATOR_LEFT": "다음 문장에서 왼쪽 공백문자(space) 제거 :", "TEXT_TRIM_OPERATOR_RIGHT": "다음 문장에서 오른쪽 공백문자(space) 제거 :", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "다음 내용 출력 %1", "TEXT_PRINT_TOOLTIP": "원하는 문장, 수, 값 등을 출력합니다.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "다음 안내 멘트를 활용해 문장 입력", "TEXT_PROMPT_TYPE_NUMBER": "다음 안내 멘트를 활용해 수 입력", "TEXT_PROMPT_TOOLTIP_NUMBER": "수 입력 받음.", "TEXT_PROMPT_TOOLTIP_TEXT": "문장 입력 받음.", "LISTS_CREATE_EMPTY_HELPURL": "https://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "빈 리스트 생성", "LISTS_CREATE_EMPTY_TOOLTIP": "아이템이 없는, 빈 리스트를 만들어 돌려줍니다.", "LISTS_CREATE_WITH_TOOLTIP": "원하는 아이템 갯수로 리스트를 생성합니다.", "LISTS_CREATE_WITH_INPUT_WITH": "리스트 만들기", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "리스트", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "리스트 블록의 내용을 추가, 삭제, 재구성 합니다.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "아이템을 리스트에 추가합니다.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "원하는 값을, 원하는 갯수 만큼 넣어, 새로운 리스트를 생성합니다.", "LISTS_REPEAT_TITLE": "%1 을 %2 번 넣어, 리스트 생성", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "%1의 길이", "LISTS_LENGTH_TOOLTIP": "리스트에 포함되어있는, 아이템 갯수를 돌려줍니다.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1이 비어있습니다", "LISTS_TOOLTIP": "목록이 비었을 때 참을 반환합니다.", "LISTS_INLIST": "리스트", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "처음으로 나타난 위치", "LISTS_INDEX_OF_LAST": "마지막으로 나타난 위치", "LISTS_INDEX_OF_TOOLTIP": "아이템이 나타난, 처음 또는 마지막 위치를 찾아 돌려줍니다. 아이템이 없으면 0 돌려줌.", "LISTS_GET_INDEX_GET": "아이템 가져오기", "LISTS_GET_INDEX_GET_REMOVE": "잘라 내기", "LISTS_GET_INDEX_REMOVE": "삭제", "LISTS_GET_INDEX_FROM_START": "첫번째 위치부터, # 번째", "LISTS_GET_INDEX_FROM_END": "마지막 번째 위치부터, # 번째", "LISTS_GET_INDEX_FIRST": "첫번째", "LISTS_GET_INDEX_LAST": "마지막", "LISTS_GET_INDEX_RANDOM": "임의로", "LISTS_GET_INDEX_TAIL": "", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "특정 위치의 아이템을 찾아 돌려줍니다. #1 은 첫번째 아이템.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "특정 위치의 아이템을 찾아 돌려줍니다. #1 은 마지막 아이템.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "첫 번째 아이템을 찾아 돌려줍니다.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "마지막 아이템을 찾아 돌려줍니다.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "리스트의 아이템들 중, 랜덤으로 선택해 돌려줍니다.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "특정 위치의 아이템을 찾아내 돌려주고, 그 아이템을 리스트에서 삭제합니다. #1 는 첫번째 아이템.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "특정 위치의 아이템을 찾아내 돌려주고, 그 아이템을 리스트에서 삭제합니다. #1 는 마지막 아이템.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "첫 번째 아이템을 찾아내 돌려주고, 그 아이템을 리스트에서 삭제합니다.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "마지막 아이템을 찾아내 돌려주고, 그 아이템을 리스트에서 삭제합니다.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "랜덤 위치의 아이템을 찾아내 돌려주고,그 아이템을 리스트에서 삭제합니다.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "특정 위치의 아이템을 찾아내 삭제합니다. #1 는 첫번째 아이템.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "특정 위치의 아이템을 찾아내 삭제합니다. #1 는 마지막 아이템.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "리스트에서 첫 번째 아이템을 삭제합니다.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "리스트에서 마지막 아이템을 찾아 삭제합니다.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "리스트에서 랜덤하게 아이템을 삭제합니다.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "에서 설정", "LISTS_SET_INDEX_INSERT": "에서 원하는 위치에 삽입", "LISTS_SET_INDEX_INPUT_TO": "에", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "특정 번째 위치의 아이템으로 설정합니다. #1 는 첫번째 아이템.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "특정 번째 위치의 아이템으로 설정합니다. #1 는 마지막 아이템.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "첫 번째 위치의 아이템으로 설정합니다.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "마지막 아이템으로 설정합니다.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "랜덤 위치의 아이템으로 설정합니다.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "아이템을 리스트의 특정 위치에 삽입합니다. 첫번째 아이템은 #1.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "아이템을 리스트의 특정 위치에 삽입합니다. 마지막 아이템은 #1.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "아이템을 리스트의 첫번째 위치에 삽입합니다.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "리스트의 마지막에 아이템을 추가합니다.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "리스트의 랜덤 위치에 아이템을 삽입합니다.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "처음 # 번째 위치부터, 서브 리스트 추출", "LISTS_GET_SUBLIST_START_FROM_END": "마지막부터 # 번째 위치부터, 서브 리스트 추출", "LISTS_GET_SUBLIST_START_FIRST": "첫 번째 위치부터, 서브 리스트 추출", "LISTS_GET_SUBLIST_END_FROM_START": "앞에서부터 # 번째로", "LISTS_GET_SUBLIST_END_FROM_END": "끝에서부터 # 번째로", "LISTS_GET_SUBLIST_END_LAST": "마지막으로", "LISTS_GET_SUBLIST_TAIL": "", "LISTS_GET_SUBLIST_TOOLTIP": "특정 부분을 복사해 새로운 리스트로 생성합니다.", "ORDINAL_NUMBER_SUFFIX": "", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TITLE": "", "VARIABLES_GET_TAIL": "", "VARIABLES_GET_TOOLTIP": "변수에 저장 되어있는 값을 돌려줍니다.", "VARIABLES_GET_CREATE_SET": "'집합 %1' 생성", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "값 변경:", "VARIABLES_SET_TAIL": "를 다음 값으로 변경", "VARIABLES_SET_TOOLTIP": "변수의 값을 입력한 값으로 변경해 줍니다.", "VARIABLES_SET_CREATE_GET": "'%1 값 읽기' 블록 생성", "PROCEDURES_DEFNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFNORETURN_TITLE": "함수", "PROCEDURES_DEFNORETURN_PROCEDURE": "함수 이름", "PROCEDURES_BEFORE_PARAMS": "사용:", "PROCEDURES_DEFNORETURN_DO": "", "PROCEDURES_DEFNORETURN_TOOLTIP": "실행 후, 결과 값을 돌려주지 않는 함수를 만듭니다.", "PROCEDURES_DEFRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFRETURN_RETURN": "다음을 돌려줌", "PROCEDURES_DEFRETURN_TOOLTIP": "실행 후, 결과 값을 돌려주는 함수를 만듭니다.", "PROCEDURES_DEF_DUPLICATE_WARNING": "경고: 이 함수에는, 같은 이름을 사용하는 매개 변수들이 있습니다.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_CALL": "", "PROCEDURES_CALLNORETURN_TOOLTIP": "미리 정의해 둔 '%1' 함수를 실행합니다.", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "미리 정의해 둔 '%1' 함수를 실행하고, 함수를 실행한 결과 값을 돌려줍니다.", "PROCEDURES_MUTATORCONTAINER_TITLE": "매개 변수들", "PROCEDURES_MUTATORARG_TITLE": "매개 변수:", "PROCEDURES_HIGHLIGHT_DEF": "함수 정의 찾기", "PROCEDURES_CREATE_DO": "'%1' 생성", "PROCEDURES_IFRETURN_TOOLTIP": "값이 참이라면, 두번째 값을 반환합니다.", "PROCEDURES_IFRETURN_WARNING": "경고: 이 블록은, 함수 정의 블록 안에서만 사용할 수 있습니다.", "CONTEXT_BLOCK_COPY": "블록 복사", "CONTEXT_BLOCK_PASTE": "붙여넣기" } ================================================ FILE: extern/blockly/msg/json/lrc.json ================================================ { "@metadata": { "authors": [ "Mogoeilor" ] }, "DUPLICATE_BLOCK": "کپی کردن", "ADD_COMMENT": "نظرتونه اضاف بکید", "REMOVE_COMMENT": "نظر جا وه جا کو", "EXTERNAL_INPUTS": "داده یا وه دری", "INLINE_INPUTS": "داده یا مئنجا", "HELP": "هومياری", "CHANGE_VALUE_TITLE": "ارزشت آلشت کو:", "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "یه رن د رنگ دو انتخاو بکید", "COLOUR_RANDOM_TITLE": "رن بختکی", "COLOUR_RANDOM_TOOLTIP": "یه رنگ بختکی انتخاو بکید", "COLOUR_RGB_TITLE": "رن وا", "COLOUR_RGB_RED": "سور", "COLOUR_RGB_GREEN": "سوز", "COLOUR_RGB_BLUE": "آوی", "COLOUR_BLEND_TITLE": "شیوسته", "COLOUR_BLEND_COLOUR1": "رن 1", "COLOUR_BLEND_COLOUR2": "رن 2", "COLOUR_BLEND_RATIO": "نسوت", "COLOUR_BLEND_TOOLTIP": "هر کوم د رنگیانه وا نسوت دائه بیه به شیون(0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "%1 تکرار کو چن بار", "CONTROLS_REPEAT_TITLE_REPEAT": "د نو انجوم دئن", "CONTROLS_REPEAT_TITLE_TIMES": "وختیا", "CONTROLS_REPEAT_INPUT_DO": "انجوم بئه", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "تا تکرار کو", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "تا تکرار کو", "CONTROLS_FOR_INPUT_WITH": "اشماردن وا", "CONTROLS_FOREACH_INPUT_ITEM": "سی هر قلم", "CONTROLS_FOREACH_INPUT_INLIST": "د نوم گه", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "حلقه نه خراو کو", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "حلقه شومل بیه نه خراو کو", "CONTROLS_IF_MSG_IF": "ار", "CONTROLS_IF_MSG_ELSEIF": "هنی ار", "CONTROLS_IF_MSG_ELSE": "هنی", "LOGIC_OPERATION_AND": "و", "LOGIC_OPERATION_OR": "یا", "LOGIC_NEGATE_TITLE": "نه %1", "LOGIC_BOOLEAN_TRUE": "راست و دوروست", "LOGIC_BOOLEAN_FALSE": "غلط", "LOGIC_BOOLEAN_TOOLTIP": "هم غلط و هم راس ورگن", "LOGIC_NULL": "خمثی", "LOGIC_TERNARY_CONDITION": "آزماشت کردن", "LOGIC_TERNARY_IF_TRUE": "ار درس بی", "LOGIC_TERNARY_IF_FALSE": "ار غلط بی", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "یه شماره.", "MATH_ARITHMETIC_HELPURL": "https://en.wikipedia.org/wiki/Arithmetic", "MATH_ARITHMETIC_TOOLTIP_ADD": "وه انازه دو گل شماره ورگن.", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "چارسوک ریشه", "MATH_SINGLE_OP_ABSOLUTE": "تموم و کمال", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_IS_EVEN": "همیشه هیئش", "MATH_IS_ODD": "تهنائه", "MATH_IS_WHOLE": "همشه", "MATH_IS_POSITIVE": "مثبته", "MATH_IS_NEGATIVE": "منفیه", "MATH_IS_DIVISIBLE_BY": "یه وا بهر بیه", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "آلشت بكيد", "MATH_CHANGE_INPUT_BY": "وا", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_OPERATOR_ROUND": "گرد کردن", "MATH_ROUND_OPERATOR_ROUNDUP": "وه رو گرد کردن", "MATH_ROUND_OPERATOR_ROUNDDOWN": "وه هار گرد کردن", "MATH_ONLIST_OPERATOR_AVERAGE": "مینجاگه نوم گه", "MATH_ONLIST_OPERATOR_MEDIAN": "مینجا نوم گه", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_JOIN_TITLE_CREATEWITH": "راس کردن متن وا", "TEXT_CREATE_JOIN_TITLE_JOIN": "پیوسن", "TEXT_APPEND_TO": "سی", "TEXT_ISEMPTY_TITLE": "%1 حالیه", "TEXT_INDEXOF_INPUT_INTEXT": "د متن", "TEXT_CHARAT_INPUT_INTEXT": "د متن", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "د متن", "TEXT_GET_SUBSTRING_END_FROM_START": "سی واج#", "TEXT_GET_SUBSTRING_END_FROM_END": "سی واج# تا آخر", "TEXT_GET_SUBSTRING_END_LAST": "سی آخرین واج", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "سی حرف گپ", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "سی واج کؤچک", "LISTS_CREATE_EMPTY_TITLE": "یه گل نوم گه حالی راس بکیت", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "نوم گه", "LISTS_IS_EMPTY_TITLE": "%1 حالیه", "LISTS_INLIST": "د نوم گه", "LISTS_GET_INDEX_GET": "گرتن", "LISTS_GET_INDEX_GET_REMOVE": "گرتن و جاوه جا بیئن", "LISTS_GET_INDEX_REMOVE": "ؤرداشتن", "LISTS_GET_INDEX_FROM_END": "# تا آخر", "LISTS_GET_INDEX_FIRST": "اولی", "LISTS_GET_INDEX_LAST": "آخر", "LISTS_GET_INDEX_RANDOM": "بختكی", "LISTS_SET_INDEX_INSERT": "بنه د", "LISTS_SET_INDEX_INPUT_TO": "چی", "LISTS_GET_SUBLIST_END_FROM_START": "سی#", "LISTS_GET_SUBLIST_END_LAST": "سی آخر", "VARIABLES_SET_TAIL": "سی", "PROCEDURES_DEFNORETURN_TITLE": "سی", "PROCEDURES_BEFORE_PARAMS": "وا:", "PROCEDURES_DEFRETURN_RETURN": "ورگنیئن", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_MUTATORCONTAINER_TITLE": "داده یا", "PROCEDURES_MUTATORARG_TITLE": "نوم داده:", "PROCEDURES_CREATE_DO": "راس کردن%1" } ================================================ FILE: extern/blockly/msg/json/ms.json ================================================ { "@metadata": { "authors": [ "Anakmalaysia", "Espertus" ] }, "VARIABLES_DEFAULT_NAME": "Perkara", "DUPLICATE_BLOCK": "Pendua", "ADD_COMMENT": "Berikan Komen", "REMOVE_COMMENT": "Padamkan Komen", "EXTERNAL_INPUTS": "Input Luaran", "INLINE_INPUTS": "Input Sebaris", "DELETE_BLOCK": "Hapuskan Blok", "DELETE_X_BLOCKS": "Hapuskan %1 Blok", "COLLAPSE_BLOCK": "Lipat Blok", "COLLAPSE_ALL": "Lipat Blok²", "EXPAND_BLOCK": "Buka Blok", "EXPAND_ALL": "Buka Blok²", "DISABLE_BLOCK": "Matikan Blok", "ENABLE_BLOCK": "Hidupkan Blok", "HELP": "Bantuan", "CHANGE_VALUE_TITLE": "Ubah nilai:", "NEW_VARIABLE": "Pembolehubah baru...", "NEW_VARIABLE_TITLE": "Nama pembolehubah baru:", "RENAME_VARIABLE": "Tukar nama pembolehubah...", "RENAME_VARIABLE_TITLE": "Tukar nama semua pembolehubah '%1' kepada:", "COLOUR_PICKER_HELPURL": "https://ms.wikipedia.org/wiki/Warna", "COLOUR_PICKER_TOOLTIP": "Pilih satu warna daripada palet.", "COLOUR_RANDOM_TITLE": "warna rawak", "COLOUR_RANDOM_TOOLTIP": "Pilih satu warna secara rawak.", "COLOUR_RGB_TITLE": "warnakan", "COLOUR_RGB_RED": "merah", "COLOUR_RGB_GREEN": "hijau", "COLOUR_RGB_BLUE": "biru", "COLOUR_RGB_TOOLTIP": "Peroleh satu warna dengan menentukan amaun campuran merah, hijau dan biru. Kesemua nilai haruslah antara 0 hingga 100.", "COLOUR_BLEND_TITLE": "adun", "COLOUR_BLEND_COLOUR1": "warna 1", "COLOUR_BLEND_COLOUR2": "warna 2", "COLOUR_BLEND_RATIO": "nisbah", "COLOUR_BLEND_TOOLTIP": "Campurkan dua warna sekali pada nisbah yang ditentukan (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "ulang %1 kali", "CONTROLS_REPEAT_TITLE_REPEAT": "ulang", "CONTROLS_REPEAT_TITLE_TIMES": "kali", "CONTROLS_REPEAT_INPUT_DO": "lakukan", "CONTROLS_REPEAT_TOOLTIP": "Lakukan perintah berulang kali.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "ulangi apabila", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "ulangi sehingga", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Lakukan beberapa perintah apabila nilainya benar (true).", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Lakukan beberapa perintah apabila nilainya palsu (false).", "CONTROLS_FOR_TOOLTIP": "Gunakan pembolehubah %1 pada nilai-nilai dari nombor pangkal hingga nombor hujung, mengira mengikut selang yang ditentukan, dan lakukan blok-blok yang tertentu.", "CONTROLS_FOR_INPUT_WITH": "kira dengan", "CONTROLS_FOR_INPUT_FROM_TO_BY": "dari %1 hingga %2 selang %3", "CONTROLS_FOREACH_INPUT_ITEM": "untuk setiap perkara", "CONTROLS_FOREACH_INPUT_INLIST": "dalam senarai", "CONTROLS_FOREACH_TOOLTIP": "Untuk setiap perkara dalam senarai, tetapkan pembolehubah '%1' pada perkara, kemudian lakukan beberapa perintah.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "Keluar daripada gelung lingkaran", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "Teruskan dengan pengulangan seterusnya gelung", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Pecahkan kandungan lingkaran.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Langkau seluruh gelung ini, dan teruskan dengan lelaran seterusnya.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Amaran: Blok ini hanya boleh digunakan dalam satu lingkaran.", "CONTROLS_IF_TOOLTIP_1": "Jika nilai yang benar, lakukan beberapa penyata.", "CONTROLS_IF_TOOLTIP_2": "Jika suatu nilai benar, lakukan penyata blok pertama. Jika tidak, bina penyata blok kedua.", "CONTROLS_IF_TOOLTIP_3": "Jika nilai yang pertama adalah benar, lakukan penyata pertama blok. Sebaliknya, jika nilai kedua adalah benar, lakukan penyata blok kedua.", "CONTROLS_IF_TOOLTIP_4": "Jika nilai yang pertama adalah benar, lakukan penyata blok pertama. Sebaliknya, jika nilai kedua adalah benar, lakukan penyata blok kedua. Jika tiada nilai adalah benar, lakukan penyata blok terakhir.", "CONTROLS_IF_MSG_IF": "jika", "CONTROLS_IF_MSG_ELSEIF": "lain jika", "CONTROLS_IF_MSG_ELSE": "lain", "CONTROLS_IF_IF_TOOLTIP": "Tambah, alih keluar, atau susun semula bahagian-bahagian untuk menyusun semula blok jika.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Tambah satu syarat kepada blok jika.", "CONTROLS_IF_ELSE_TOOLTIP": "Tambah yang terakhir, alihkan semua keadaan ke blok jika.", "LOGIC_COMPARE_HELPURL": "https://id.wikipedia.org/wiki/Pertidaksamaan", "LOGIC_COMPARE_TOOLTIP_EQ": "Kembali benar jika kedua-dua input benar antara satu sama lain.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Taip balik benar jika kedua-dua input tidak sama.", "LOGIC_COMPARE_TOOLTIP_LT": "Kembali benar jika input pertama adalah lebih kecil daripada input kedua.", "LOGIC_COMPARE_TOOLTIP_LTE": "Kembali benar jika input pertama adalah lebih kecil daripada atau sama dengan input kedua.", "LOGIC_COMPARE_TOOLTIP_GT": "Kembali benar jika input pertama adalah lebih besar daripada input kedua.", "LOGIC_COMPARE_TOOLTIP_GTE": "Kembali benar jika input pertama adalah lebih besar daripada atau sama dengan input kedua.", "LOGIC_OPERATION_TOOLTIP_AND": "Return true if both inputs are true.", "LOGIC_OPERATION_AND": "dan", "LOGIC_OPERATION_TOOLTIP_OR": "Return true if at least one of the inputs is true.", "LOGIC_OPERATION_OR": "atau", "LOGIC_NEGATE_TITLE": "bukan %1", "LOGIC_NEGATE_TOOLTIP": "'Benar' akan dibalas jika inputnya salah. 'Salah' akan dibalas jika inputnya benar.", "LOGIC_BOOLEAN_TRUE": "benar", "LOGIC_BOOLEAN_FALSE": "palsu", "LOGIC_BOOLEAN_TOOLTIP": "Kembalikan samada benar atau palsu.", "LOGIC_NULL": "null", "LOGIC_NULL_TOOLTIP": "Returns null.", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "Jika benar", "LOGIC_TERNARY_IF_FALSE": "Jika palsu", "LOGIC_TERNARY_TOOLTIP": "Check the condition in 'test'. If the condition is true, returns the 'if true' value; otherwise returns the 'if false' value.", "MATH_NUMBER_HELPURL": "https://ms.wikipedia.org/wiki/Nombor", "MATH_NUMBER_TOOLTIP": "Suatu nombor.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "×", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "asin", "MATH_TRIG_ACOS": "acos", "MATH_TRIG_ATAN": "atan", "MATH_ARITHMETIC_HELPURL": "https://ms.wikipedia.org/wiki/Aritmetik", "MATH_ARITHMETIC_TOOLTIP_ADD": "Return the sum of the two numbers.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Taip balik hasil tolak dua nombor tersebut.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Taip balik hasil darab dua nombor tersebut.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Taip balik hasil bahagi dua nombor tersebut.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Return the first number raised to the power of the second number.", "MATH_SINGLE_HELPURL": "https://ms.wikipedia.org/wiki/Punca_kuasa_dua", "MATH_SINGLE_OP_ROOT": "Punca kuasa dua", "MATH_SINGLE_TOOLTIP_ROOT": "Kembalikan punca kuasa nombor.", "MATH_SINGLE_OP_ABSOLUTE": "mutlak", "MATH_SINGLE_TOOLTIP_ABS": "Kembalikan nilai mutlak suatu nombor.", "MATH_SINGLE_TOOLTIP_NEG": "Kembalikan nombor yang songsang.", "MATH_SINGLE_TOOLTIP_LN": "Kembali dalam logaritma nombor asli.", "MATH_SINGLE_TOOLTIP_LOG10": "Kembali logarithm 10 asas nombor.", "MATH_SINGLE_TOOLTIP_EXP": "Kembalikan e kepada kuasa nombor.", "MATH_SINGLE_TOOLTIP_POW10": "Kembalikan 10 kepada kuasa nombor.", "MATH_TRIG_HELPURL": "https://ms.wikipedia.org/wiki/Fungsi_trigonometri", "MATH_TRIG_TOOLTIP_SIN": "Kembalikan darjah sine (bukan radian).", "MATH_TRIG_TOOLTIP_COS": "Kembalikan darjah kosinus (bukan radian).", "MATH_TRIG_TOOLTIP_TAN": "Kembalikan darjah tangen (bukan radian).", "MATH_TRIG_TOOLTIP_ASIN": "Kembalikan arcsince beberapa nombor.", "MATH_TRIG_TOOLTIP_ACOS": "Kembali arccosine beberapa nombor.", "MATH_TRIG_TOOLTIP_ATAN": "Kembalikan beberapa nombor arctangent.", "MATH_CONSTANT_HELPURL": "https://ms.wikipedia.org/wiki/Pemalar_matematik", "MATH_CONSTANT_TOOLTIP": "Return one of the common constants: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (infinity).", "MATH_IS_EVEN": "Adalah genap", "MATH_IS_ODD": "aneh", "MATH_IS_PRIME": "is prime", "MATH_IS_WHOLE": "is whole", "MATH_IS_POSITIVE": "adalah positif", "MATH_IS_NEGATIVE": "negatif", "MATH_IS_DIVISIBLE_BY": "Boleh dibahagikan dengan", "MATH_IS_TOOLTIP": "Check if a number is an even, odd, prime, whole, positive, negative, or if it is divisible by certain number. Returns true or false.", "MATH_CHANGE_HELPURL": "https://id.wikipedia.org/wiki/Perjumlahan", "MATH_CHANGE_TITLE_CHANGE": "perubahan", "MATH_CHANGE_INPUT_BY": "oleh", "MATH_CHANGE_TOOLTIP": "Tambah nombor kepada pembolehubah '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Bulat nombor yang naik atau turun.", "MATH_ROUND_OPERATOR_ROUND": "pusingan", "MATH_ROUND_OPERATOR_ROUNDUP": "pusingan ke atas", "MATH_ROUND_OPERATOR_ROUNDDOWN": "Pusingan ke bawah", "MATH_ONLIST_OPERATOR_SUM": "Jumlah senarai", "MATH_ONLIST_TOOLTIP_SUM": "Kembalikan jumlah semua nombor dalam senarai.", "MATH_ONLIST_OPERATOR_MIN": "min dalam senarai", "MATH_ONLIST_TOOLTIP_MIN": "Kembalikan nombor terkecil dalam senarai.", "MATH_ONLIST_OPERATOR_MAX": "Max senarai", "MATH_ONLIST_TOOLTIP_MAX": "Pulangkan jumlah terbesar dalam senarai.", "MATH_ONLIST_OPERATOR_AVERAGE": "purata daripada senarai", "MATH_ONLIST_TOOLTIP_AVERAGE": "Kembalikan purata (min aritmetik) nilai-nilai angka di dalam senarai.", "MATH_ONLIST_OPERATOR_MEDIAN": "Median senarai", "MATH_ONLIST_TOOLTIP_MEDIAN": "Kembalikan nombor median dalam senarai.", "MATH_ONLIST_OPERATOR_MODE": "jenis senarai", "MATH_ONLIST_TOOLTIP_MODE": "Kembali senarai item yang paling biasa dalam senarai.", "MATH_ONLIST_OPERATOR_STD_DEV": "sisihan piawai bagi senarai", "MATH_ONLIST_TOOLTIP_STD_DEV": "Kembali dengan sisihan piawai daripada senarai.", "MATH_ONLIST_OPERATOR_RANDOM": "Item rawak daripada senarai", "MATH_ONLIST_TOOLTIP_RANDOM": "Kembalikan elemen rawak daripada senarai.", "MATH_MODULO_HELPURL": "https://id.wikipedia.org/wiki/Operasi_modulus", "MATH_MODULO_TITLE": "remainder of %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Taip balik baki yang didapat daripada pembahagian dua nombor tersebut.", "MATH_CONSTRAIN_TITLE": "constrain %1 low %2 high %3", "MATH_CONSTRAIN_TOOLTIP": "Constrain a number to be between the specified limits (inclusive).", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "integer rawak dari %1ke %2", "MATH_RANDOM_INT_TOOLTIP": "Kembalikan integer rawak diantara dua had yang ditentukan, inklusif.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "pecahan rawak", "MATH_RANDOM_FLOAT_TOOLTIP": "Kembali sebahagian kecil rawak antara 0.0 (inklusif) dan 1.0 (eksklusif).", "TEXT_TEXT_HELPURL": "https://ms.wikipedia.org/wiki/Rentetan", "TEXT_TEXT_TOOLTIP": "Huruf, perkataan, atau baris teks.", "TEXT_JOIN_TITLE_CREATEWITH": "hasilkan teks dengan", "TEXT_JOIN_TOOLTIP": "Hasilkan sebahagian teks dengan menghubungkan apa jua nombor item.", "TEXT_CREATE_JOIN_TITLE_JOIN": "Sertai", "TEXT_CREATE_JOIN_TOOLTIP": "Add, remove, or reorder sections to reconfigure this text block.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Add an item to the text.", "TEXT_APPEND_TO": "Untuk", "TEXT_APPEND_APPENDTEXT": "append text", "TEXT_APPEND_TOOLTIP": "Append some text to variable '%1'.", "TEXT_LENGTH_TITLE": "panjang %1", "TEXT_LENGTH_TOOLTIP": "Kembalikan jumlah huruf (termasuk ruang) dalam teks yang disediakan.", "TEXT_ISEMPTY_TITLE": "%1 adalah kosong", "TEXT_ISEMPTY_TOOLTIP": "Kembalikan benar jika teks yang disediakan adalah kosong.", "TEXT_INDEXOF_TOOLTIP": "Kembalikan Indeks kejadian pertama/terakhir dari teks pertama ke dalam teks kedua. Kembalikan 0 Jika teks tidak ditemui.", "TEXT_INDEXOF_INPUT_INTEXT": "dalam teks", "TEXT_INDEXOF_OPERATOR_FIRST": "mencari kejadian pertama teks", "TEXT_INDEXOF_OPERATOR_LAST": "mencari kejadian terakhir teks", "TEXT_CHARAT_INPUT_INTEXT": "Dalam teks", "TEXT_CHARAT_FROM_START": "get letter #", "TEXT_CHARAT_FROM_END": "get letter # from end", "TEXT_CHARAT_FIRST": "get first letter", "TEXT_CHARAT_LAST": "Dapatkan abjad terakhir", "TEXT_CHARAT_RANDOM": "Dapatkan abjad rawak", "TEXT_CHARAT_TOOLTIP": "Returns the letter at the specified position.", "TEXT_GET_SUBSTRING_TOOLTIP": "Returns a specified portion of the text.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "dalam teks", "TEXT_GET_SUBSTRING_START_FROM_START": "get substring from letter #", "TEXT_GET_SUBSTRING_START_FROM_END": "get substring from letter # from end", "TEXT_GET_SUBSTRING_START_FIRST": "get substring from first letter", "TEXT_GET_SUBSTRING_END_FROM_START": "to letter #", "TEXT_GET_SUBSTRING_END_FROM_END": "to letter # from end", "TEXT_GET_SUBSTRING_END_LAST": "untuk huruf terakhir", "TEXT_CHANGECASE_TOOLTIP": "Return a copy of the text in a different case.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "Kepada HURUF BESAR", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "Kepada huruf kecil", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "to Title Case", "TEXT_TRIM_TOOLTIP": "Kembali salinan teks dengan ruang yang dikeluarkan daripada satu atau hujung kedua belah.", "TEXT_TRIM_OPERATOR_BOTH": "mengurangkan kawasan dari kedua-dua belah", "TEXT_TRIM_OPERATOR_LEFT": "mengurangkan ruang dari sebelah kiri", "TEXT_TRIM_OPERATOR_RIGHT": "mengurangkan kawasan dari sisi kanan", "TEXT_PRINT_TITLE": "cetak %1", "TEXT_PRINT_TOOLTIP": "Cetak teks yang ditentukan, nombor atau nilai lain.", "TEXT_PROMPT_TYPE_TEXT": "Prom untuk teks dengan mesej", "TEXT_PROMPT_TYPE_NUMBER": "Prom untuk nombor dengan mesej", "TEXT_PROMPT_TOOLTIP_NUMBER": "Peringatan kepada pengguna untuk nombor.", "TEXT_PROMPT_TOOLTIP_TEXT": "Peringatkan pengguna untuk sebahagian teks.", "LISTS_CREATE_EMPTY_TITLE": "Wujudkan senarai kosong", "LISTS_CREATE_EMPTY_TOOLTIP": "Kembalikan senarai panjang 0, yang tidak mengandungi rekod data", "LISTS_CREATE_WITH_TOOLTIP": "Wujudkan senarai dengan apa jua nombor item.", "LISTS_CREATE_WITH_INPUT_WITH": "wujudkan senarai dengan", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "senarai", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Tambah, alih keluar, atau susun semula bahagian-bahagian untuk menyusun semula senarai blok.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Tambah item ke dalam senarai.", "LISTS_REPEAT_TOOLTIP": "Wujudkan senarai yang terdiri daripada nilai berulang mengikut nombor yang ditentukan.", "LISTS_REPEAT_TITLE": "wujudkan senarai dengan item %1 diulangi %2 kali", "LISTS_LENGTH_TITLE": "panjang %1", "LISTS_LENGTH_TOOLTIP": "Kembalikan panjang senarai", "LISTS_IS_EMPTY_TITLE": "%1 adalah kosong", "LISTS_TOOLTIP": "Kembalikan benar jika senarai kosong.", "LISTS_INLIST": "dalam senarai", "LISTS_INDEX_OF_FIRST": "cari pertama item kejadian", "LISTS_INDEX_OF_LAST": "cari kejadian akhir item", "LISTS_INDEX_OF_TOOLTIP": "Kembalikan indeks kejadian pertama/terakhir item dalam senarai. Kembalikan 0 jika teks tidak ditemui.", "LISTS_GET_INDEX_GET": "dapatkan", "LISTS_GET_INDEX_GET_REMOVE": "dapat dan alihkan", "LISTS_GET_INDEX_REMOVE": "alihkan", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# dari akhir", "LISTS_GET_INDEX_FIRST": "pertama", "LISTS_GET_INDEX_LAST": "terakhir", "LISTS_GET_INDEX_RANDOM": "rawak", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Kembalikan item dalam kedudukan yang ditetapkan dalam senarai. #1 ialah item terakhir.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Kembalikan item dalam kedudukan yang ditetapkan dalam senarai. #1 ialah item terakhir.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Kembalikan item pertama dalam senarai.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Kembalikan item pertama dalam senarai.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Kembalikan item rawak dalam senarai.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Alihkan dan kembalikan item mengikut spesifikasi posisi dalam senarai. #1 ialah item pertama.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Alihkan dan kembalikan item mengikut spesifikasi posisi dalam senarai. #1 ialah item terakhir.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Alihkan dan kembalikan item pertama dalam senarai.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Alihkan dan kembalikan item terakhir dalam senarai.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Alihkan dan kembalikan item rawak dalam senarai.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Alihkan item pada posisi mengikut spesifikasi dalam senarai. #1 ialah item pertama.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Alihkan item mengikut spesifikasi posisi dalam senarai. #1 ialah item terakhir.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Alihkan item pertama dalam senarai.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Alihkan item terakhir dalam senarai.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Alihkan item rawak dalam senarai.", "LISTS_SET_INDEX_SET": "set", "LISTS_SET_INDEX_INSERT": "masukkan pada", "LISTS_SET_INDEX_INPUT_TO": "sebagai", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Masukkan item pada posisi yang ditentukan dalam senarai. #1 ialah item terakhir.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Masukkan item pada posisi yang ditentukan dalam senarai. #1 ialah item terakhir.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Set item pertama dalam senarai.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Set item terakhir dalam senarai.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Set item rawak dalam senarai.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Masukkan item pada posisi yand ditentukan dalam senarai. #1 ialah item terakhir.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Masukkan item pada posisi yang ditentukan dalam senarai. #1 ialah item terakhir.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Selit item pada permulaan senarai.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Tambahkan item dalam senarai akhir.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Selit item secara rawak di dalam senarai.", "LISTS_GET_SUBLIST_START_FROM_START": "dapatkan sub-senarai daripada #", "LISTS_GET_SUBLIST_START_FROM_END": "dapatkan sub-senarai daripada # daripada terakhir", "LISTS_GET_SUBLIST_START_FIRST": "dapatkan sub-senarai daripada pertama", "LISTS_GET_SUBLIST_END_FROM_START": "ke #", "LISTS_GET_SUBLIST_END_FROM_END": "ke # dari akhir", "LISTS_GET_SUBLIST_END_LAST": "ke akhir", "LISTS_GET_SUBLIST_TOOLTIP": "Wujudkan salinan bahagian yang ditentukan dari senarai.", "VARIABLES_GET_TOOLTIP": "Kembalikan nilai pemboleh ubah ini.", "VARIABLES_GET_CREATE_SET": "Hasilkan 'set %1'", "VARIABLES_SET_TITLE": "set", "VARIABLES_SET_TAIL": "ke", "VARIABLES_SET_TOOLTIP": "Set pembolehubah ini supaya sama dengan input.", "VARIABLES_SET_CREATE_GET": "Hasilkan 'set %1'", "PROCEDURES_DEFNORETURN_TITLE": "Untuk", "PROCEDURES_DEFNORETURN_PROCEDURE": "Buat sesuatu", "PROCEDURES_BEFORE_PARAMS": "dengan:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Menghasilkan suatu fungsi tanpa output.", "PROCEDURES_DEFRETURN_RETURN": "kembali", "PROCEDURES_DEFRETURN_TOOLTIP": "Mencipta satu fungsi dengan pengeluaran.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Amaran: Fungsi ini mempunyai parameter yang berganda.", "PROCEDURES_CALLNORETURN_HELPURL": "https://ms.wikipedia.org/wiki/Fungsi", "PROCEDURES_CALLNORETURN_TOOLTIP": "Run the user-defined function '%1'.", "PROCEDURES_CALLRETURN_HELPURL": "https://ms.wikipedia.org/wiki/Fungsi", "PROCEDURES_CALLRETURN_TOOLTIP": "Run the user-defined function '%1' and use its output.", "PROCEDURES_MUTATORCONTAINER_TITLE": "Input-input", "PROCEDURES_MUTATORARG_TITLE": "Nama input:", "PROCEDURES_HIGHLIGHT_DEF": "Serlahkan definisi fungsi", "PROCEDURES_CREATE_DO": "Hasilkan '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "If a value is true, then return a second value.", "PROCEDURES_IFRETURN_WARNING": "Amaran: Blok ini hanya boleh digunakan dalam fungsi definisi." } ================================================ FILE: extern/blockly/msg/json/nb.json ================================================ { "@metadata": [], "VARIABLES_DEFAULT_NAME": "element", "DUPLICATE_BLOCK": "duplikat", "ADD_COMMENT": "Legg til kommentar", "REMOVE_COMMENT": "Fjern kommentar", "EXTERNAL_INPUTS": "Eksterne kilder", "INLINE_INPUTS": "Interne kilder", "DELETE_BLOCK": "Slett blokk", "DELETE_X_BLOCKS": "Slett %1 blokk(er)", "COLLAPSE_BLOCK": "Skjul blokk", "COLLAPSE_ALL": "Skjul blokker", "EXPAND_BLOCK": "Utvid blokk", "EXPAND_ALL": "Utvid blokker", "DISABLE_BLOCK": "Deaktiver blokk", "ENABLE_BLOCK": "Aktiver blokk", "HELP": "Hjelp", "CHANGE_VALUE_TITLE": "Bytt verdi:", "NEW_VARIABLE": "Ny variabel...", "NEW_VARIABLE_TITLE": "Nytt variabelnavn:", "RENAME_VARIABLE": "Gi nytt navn til variabel...", "RENAME_VARIABLE_TITLE": "Endre navnet til alle '%1' variabler til:", "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Velg en farge fra paletten.", "COLOUR_RANDOM_TITLE": "tilfeldig farge", "COLOUR_RANDOM_TOOLTIP": "Velg en tilfeldig farge.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "farge med", "COLOUR_RGB_RED": "rød", "COLOUR_RGB_GREEN": "grønn", "COLOUR_RGB_BLUE": "blå", "COLOUR_RGB_TOOLTIP": "Lag en farge med angitt verdi av rød, grønn og blå. Alle verdier må være mellom 0 og 100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "blande", "COLOUR_BLEND_COLOUR1": "farge 1", "COLOUR_BLEND_COLOUR2": "farge 2", "COLOUR_BLEND_RATIO": "forhold", "COLOUR_BLEND_TOOLTIP": "Blander to farger sammen med et gitt forhold (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "gjenta %1 ganger", "CONTROLS_REPEAT_TITLE_REPEAT": "gjenta", "CONTROLS_REPEAT_TITLE_TIMES": "ganger", "CONTROLS_REPEAT_INPUT_DO": "gjør", "CONTROLS_REPEAT_TOOLTIP": "Gjenta noen instruksjoner flere ganger.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "gjenta mens", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "gjenta til", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Så lenge et utsagn stemmer, utfør noen instruksjoner.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Så lenge et utsagn ikke stemmer, gjør noen instruksjoner.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Ha variabel %1 ta verdiene fra start nummer til slutt nummer, telle med spesifisert intervall og lag de spesifiserte blokkene.", "CONTROLS_FOR_INPUT_WITH": "tell med", "CONTROLS_FOR_INPUT_FROM_TO_BY": "fra %1 til %2 med %3", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each for each block", "CONTROLS_FOREACH_INPUT_ITEM": "for hvert element", "CONTROLS_FOREACH_INPUT_INLIST": "i listen", "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "", "CONTROLS_FOREACH_TOOLTIP": "For hvert element i en liste, angi variabelen '%1' til elementet, og deretter lag noen setninger.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "bryt ut av løkken", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "fortsett med neste gjentakelse av løkken", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Bryt ut av den gjeldende løkken.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Hopp over resten av denne løkken og fortsett med neste gjentakelse.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Advarsel: Denne blokken kan kun brukes innenfor en løkke.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "Hvis dette er sant, så gjør følgende.", "CONTROLS_IF_TOOLTIP_2": "Hvis dette er sant, så utfør den første blokken av instruksjoner. Hvis ikke, utfør den andre blokken.", "CONTROLS_IF_TOOLTIP_3": "Hvis det første stemmer, så utfør den første blokken av instruksjoner. Ellers, hvis det andre stemmer, utfør den andre blokken av instruksjoner.", "CONTROLS_IF_TOOLTIP_4": "Hvis den første verdien er sann, så utfør den første blokken med setninger. Ellers, hvis den andre verdien er sann, så utfør den andre blokken med setninger. Hvis ingen av verdiene er sanne, så utfør den siste blokken med setninger.", "CONTROLS_IF_MSG_IF": "hvis", "CONTROLS_IF_MSG_ELSEIF": "ellers hvis", "CONTROLS_IF_MSG_ELSE": "ellers", "CONTROLS_IF_IF_TOOLTIP": "Legg til, fjern eller flytt seksjoner i denne hvis-blokken.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Legg til en betingelse til hvis blokken.", "CONTROLS_IF_ELSE_TOOLTIP": "Legg til hva som skal skje hvis de andre ikke slår til.", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "Returnerer sann hvis begge inputene er like hverandre.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Returnerer sant hvis begge argumentene er ulike hverandre.", "LOGIC_COMPARE_TOOLTIP_LT": "Returnerer sant hvis det første argumentet er mindre enn det andre argumentet.", "LOGIC_COMPARE_TOOLTIP_LTE": "Returnerer sant hvis det første argumentet er mindre enn eller likt det andre argumentet.", "LOGIC_COMPARE_TOOLTIP_GT": "Returnerer sant hvis det første argumentet er større enn den andre argumentet.", "LOGIC_COMPARE_TOOLTIP_GTE": "Returnerer sant hvis det første argumentet er større enn eller likt det andre argumentet.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Returnerer sant hvis begge argumentene er sanne.", "LOGIC_OPERATION_AND": "og", "LOGIC_OPERATION_TOOLTIP_OR": "Returnerer sant hvis minst ett av argumentene er sant.", "LOGIC_OPERATION_OR": "eller", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "ikke %1", "LOGIC_NEGATE_TOOLTIP": "Returnerer sant hvis argumentet er usant. Returnerer usant hvis argumentet er sant.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "sann", "LOGIC_BOOLEAN_FALSE": "usann", "LOGIC_BOOLEAN_TOOLTIP": "Returnerer enten sann eller usann.", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "null", "LOGIC_NULL_TOOLTIP": "Returnerer null.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "hvis sant", "LOGIC_TERNARY_IF_FALSE": "hvis usant", "LOGIC_TERNARY_TOOLTIP": "Sjekk betingelsen i 'test'. Hvis betingelsen er sann, da returneres 'hvis sant' verdien. Hvis ikke returneres 'hvis usant' verdien.", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "Et tall.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "x", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "asin", "MATH_TRIG_ACOS": "acos", "MATH_TRIG_ATAN": "atan", "MATH_ARITHMETIC_HELPURL": "https://no.wikipedia.org/wiki/Aritmetikk", "MATH_ARITHMETIC_TOOLTIP_ADD": "Returnerer summen av to tall.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Returner differansen mellom to tall.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Returner produktet av to tall.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Returner kvotienten av to tall.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Returner det første tallet opphøyd i den andre tallet.", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "kvadratrot", "MATH_SINGLE_TOOLTIP_ROOT": "Returner kvadratroten av et tall.", "MATH_SINGLE_OP_ABSOLUTE": "absoluttverdi", "MATH_SINGLE_TOOLTIP_ABS": "Returner absoluttverdien av et tall.", "MATH_SINGLE_TOOLTIP_NEG": "Returner det negative tallet.", "MATH_SINGLE_TOOLTIP_LN": "Returner den naturlige logaritmen til et tall.", "MATH_SINGLE_TOOLTIP_LOG10": "Returner base-10 logaritmen til et tall.", "MATH_SINGLE_TOOLTIP_EXP": "Returner e opphøyd i et tall.", "MATH_SINGLE_TOOLTIP_POW10": "Returner 10 opphøyd i et tall.", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "Returner sinus av en vinkel (ikke radian).", "MATH_TRIG_TOOLTIP_COS": "Returner cosinus av en vinkel (ikke radian).", "MATH_TRIG_TOOLTIP_TAN": "Returner tangenten av en vinkel (ikke radian).", "MATH_TRIG_TOOLTIP_ASIN": "Returner arcsinus til et tall.", "MATH_TRIG_TOOLTIP_ACOS": "Returner arccosinus til et tall.", "MATH_TRIG_TOOLTIP_ATAN": "Returner arctangens til et tall.", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "Returner en av felleskonstantene π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), eller ∞ (uendelig).", "MATH_IS_EVEN": "er et partall", "MATH_IS_ODD": "er et oddetall", "MATH_IS_PRIME": "er et primtall", "MATH_IS_WHOLE": "er et heltall", "MATH_IS_POSITIVE": "er positivt", "MATH_IS_NEGATIVE": "er negativer negativt", "MATH_IS_DIVISIBLE_BY": "er delelig med", "MATH_IS_TOOLTIP": "Sjekk om et tall er et partall, oddetall, primtall, heltall, positivt, negativt, eller om det er delelig med et annet tall. Returnerer sant eller usant.", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "endre", "MATH_CHANGE_INPUT_BY": "ved", "MATH_CHANGE_TOOLTIP": "Addere et tall til variabelen '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Avrund et tall ned eller opp.", "MATH_ROUND_OPERATOR_ROUND": "avrunding", "MATH_ROUND_OPERATOR_ROUNDUP": "rund opp", "MATH_ROUND_OPERATOR_ROUNDDOWN": "rund ned", "MATH_ONLIST_HELPURL": "", "MATH_ONLIST_OPERATOR_SUM": "summen av listen", "MATH_ONLIST_TOOLTIP_SUM": "Returner summen av alle tallene i listen.", "MATH_ONLIST_OPERATOR_MIN": "minimum av listen", "MATH_ONLIST_TOOLTIP_MIN": "Returner det minste tallet i listen.", "MATH_ONLIST_OPERATOR_MAX": "maksimum av liste", "MATH_ONLIST_TOOLTIP_MAX": "Returner det største tallet i listen.", "MATH_ONLIST_OPERATOR_AVERAGE": "gjennomsnittet av listen", "MATH_ONLIST_TOOLTIP_AVERAGE": "Returner det aritmetiske gjennomsnittet av tallene i listen.", "MATH_ONLIST_OPERATOR_MEDIAN": "medianen til listen", "MATH_ONLIST_TOOLTIP_MEDIAN": "Returner listens median.", "MATH_ONLIST_OPERATOR_MODE": "Listens typetall", "MATH_ONLIST_TOOLTIP_MODE": "Returner en liste av de vanligste elementene i listen.", "MATH_ONLIST_OPERATOR_STD_DEV": "standardavviket til listen", "MATH_ONLIST_TOOLTIP_STD_DEV": "Returner listens standardavvik.", "MATH_ONLIST_OPERATOR_RANDOM": "tilfeldig element i listen", "MATH_ONLIST_TOOLTIP_RANDOM": "Returner et tilfeldig element fra listen.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "resten av %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Returner resten fra delingen av to tall.", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "begrense %1 lav %2 høy %3", "MATH_CONSTRAIN_TOOLTIP": "Begrens et tall til å være mellom de angitte grenseverdiene (inklusiv).", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "Et tilfeldig heltall mellom %1 og %2", "MATH_RANDOM_INT_TOOLTIP": "Returner et tilfeldig tall mellom de to spesifiserte grensene, inkludert de to.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "tilfeldig flyttall", "MATH_RANDOM_FLOAT_TOOLTIP": "Returner et tilfeldig flyttall mellom 0.0 (inkludert) og 1.0 (ikke inkludert).", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "En bokstav, ett ord eller en linje med tekst.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "lage tekst med", "TEXT_JOIN_TOOLTIP": "Opprett en tekst ved å sette sammen et antall elementer.", "TEXT_CREATE_JOIN_TITLE_JOIN": "føy sammen", "TEXT_CREATE_JOIN_TOOLTIP": "Legg til, fjern eller forandre rekkefølgen for å forandre på denne tekstblokken.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Legg til et element til teksten.", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "til", "TEXT_APPEND_APPENDTEXT": "tilføy tekst", "TEXT_APPEND_TOOLTIP": "Tilføy tekst til variabelen '%1'.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "lengden av %1", "TEXT_LENGTH_TOOLTIP": "Returnerer antall bokstaver (inkludert mellomrom) i den angitte teksten.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 er tom", "TEXT_ISEMPTY_TOOLTIP": "Returnerer sann hvis den angitte teksten er tom.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Returnerer posisjonen for første/siste forekomsten av den første tekst i den andre teksten. Returnerer 0 hvis teksten ikke blir funnet.", "TEXT_INDEXOF_INPUT_INTEXT": "i tekst", "TEXT_INDEXOF_OPERATOR_FIRST": "finn første forekomst av tekst", "TEXT_INDEXOF_OPERATOR_LAST": "finn siste forekomst av tekst", "TEXT_INDEXOF_TAIL": "", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "i tekst", "TEXT_CHARAT_FROM_START": "hent bokstav #", "TEXT_CHARAT_FROM_END": "hent bokstav # fra slutten", "TEXT_CHARAT_FIRST": "hent første bokstav", "TEXT_CHARAT_LAST": "hent den siste bokstaven", "TEXT_CHARAT_RANDOM": "hent en tilfeldig bokstav", "TEXT_CHARAT_TAIL": "", "TEXT_CHARAT_TOOLTIP": "Returnerer bokstaven på angitt plassering.", "TEXT_GET_SUBSTRING_TOOLTIP": "Returnerer den angitte delen av teksten.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "i tekst", "TEXT_GET_SUBSTRING_START_FROM_START": "hent delstreng fra bokstav #", "TEXT_GET_SUBSTRING_START_FROM_END": "hent delstreng fra bokstav # fra slutten", "TEXT_GET_SUBSTRING_START_FIRST": "hent delstreng fra første bokstav", "TEXT_GET_SUBSTRING_END_FROM_START": "til bokstav #", "TEXT_GET_SUBSTRING_END_FROM_END": "til bokstav # fra slutten", "TEXT_GET_SUBSTRING_END_LAST": "til siste bokstav", "TEXT_GET_SUBSTRING_TAIL": "", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Returnerer en kopi av teksten der store og små bokstaver er byttet om.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "til STORE BOKSTAVER", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "til små bokstaver", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "til store forbokstaver", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Returner en kopi av teksten med mellomrom fjernet fra en eller begge sidene.", "TEXT_TRIM_OPERATOR_BOTH": "fjern mellomrom fra begge sider", "TEXT_TRIM_OPERATOR_LEFT": "fjern mellomrom fra venstre side", "TEXT_TRIM_OPERATOR_RIGHT": "fjern mellomrom fra høyre side", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "skriv ut %1", "TEXT_PRINT_TOOLTIP": "Skriv ut angitt tekst, tall eller annet innhold.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "spør om tekst med en melding", "TEXT_PROMPT_TYPE_NUMBER": "spør om et tall med en melding", "TEXT_PROMPT_TOOLTIP_NUMBER": "Be brukeren om et tall.", "TEXT_PROMPT_TOOLTIP_TEXT": "Spør brukeren om tekst.", "LISTS_CREATE_EMPTY_HELPURL": "https://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "opprett en tom liste", "LISTS_CREATE_EMPTY_TOOLTIP": "Returnerer en tom liste, altså med lengde 0", "LISTS_CREATE_WITH_TOOLTIP": "Lag en liste med et vilkårlig antall elementer.", "LISTS_CREATE_WITH_INPUT_WITH": "lag en liste med", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "liste", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Legg til, fjern eller endre rekkefølgen for å endre på denne delen av listen.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Tilføy et element til listen.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "Lager en liste hvor den gitte verdien gjentas et antall ganger.", "LISTS_REPEAT_TITLE": "Lag en liste hvor elementet %1 forekommer %2 ganger", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "lengden på %1", "LISTS_LENGTH_TOOLTIP": "Returnerer lengden til en liste.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 er tom", "LISTS_TOOLTIP": "Returnerer sann hvis listen er tom.", "LISTS_INLIST": "i listen", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "finn første forekomst av elementet", "LISTS_INDEX_OF_LAST": "finn siste forekomst av elementet", "LISTS_INDEX_OF_TOOLTIP": "Returnerer posisjonen til den første/siste forekomsten av elementet i en liste. Returnerer 0 hvis ikke funnet.", "LISTS_GET_INDEX_GET": "hent", "LISTS_GET_INDEX_GET_REMOVE": "hent og fjern", "LISTS_GET_INDEX_REMOVE": "fjern", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# fra slutten", "LISTS_GET_INDEX_FIRST": "først", "LISTS_GET_INDEX_LAST": "siste", "LISTS_GET_INDEX_RANDOM": "tilfeldig", "LISTS_GET_INDEX_TAIL": "", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Returner elementet på den angitte posisjonen i en liste. #1 er det første elementet.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Returner elementet på den angitte posisjonen i en liste. #1 er det siste elementet.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Returnerer det første elementet i en liste.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Returnerer det siste elementet i en liste.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Returnerer et tilfeldig element i en liste.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Fjerner og returnerer elementet ved en gitt posisjon i en liste. #1 er det første elementet.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Fjerner og returnerer elementet ved en gitt posisjon i en liste. #1 er det siste elementet.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Fjerner og returnerer det første elementet i en liste.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Fjerner og returnerer det siste elementet i en liste.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Fjerner og returnerer et tilfeldig element i en liste.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Fjerner et element ved en gitt posisjon i en liste. #1 er det første elementet.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Fjerner et element ved en gitt posisjon i en liste. #1 er det siste elementet.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Fjerner det første elementet i en liste.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Fjerner det siste elementet i en liste.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Fjerner et tilfeldig element i en liste.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "sett", "LISTS_SET_INDEX_INSERT": "sett inn ved", "LISTS_SET_INDEX_INPUT_TO": "som", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Setter inn elementet ved den angitte posisjonen i en liste. #1 er det første elementet.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Setter inn elementet ved den angitte posisjonen i en liste. #1 er det siste elementet.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Angir det første elementet i en liste.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Angir det siste elementet i en liste.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Angir et tilfeldig element i en liste.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Setter inn elementet ved den angitte posisjonen i en liste. #1 er det første elementet.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Setter inn elementet ved den angitte posisjonen i en liste. #1 er det siste elementet.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Setter inn elementet i starten av en liste.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Tilføy elementet til slutten av en liste.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Setter inn elementet ved en tilfeldig posisjon i en liste.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "Hent del-listen fra #", "LISTS_GET_SUBLIST_START_FROM_END": "Hent de siste # elementene", "LISTS_GET_SUBLIST_START_FIRST": "Hent en del av listen", "LISTS_GET_SUBLIST_END_FROM_START": "til #", "LISTS_GET_SUBLIST_END_FROM_END": "til # fra slutten", "LISTS_GET_SUBLIST_END_LAST": "til siste", "LISTS_GET_SUBLIST_TAIL": "", "LISTS_GET_SUBLIST_TOOLTIP": "Kopiérer en ønsket del av en liste.", "ORDINAL_NUMBER_SUFFIX": "", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TITLE": "", "VARIABLES_GET_TAIL": "", "VARIABLES_GET_TOOLTIP": "Returnerer verdien av denne variabelen.", "VARIABLES_GET_CREATE_SET": "Opprett 'sett %1'", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "sett", "VARIABLES_SET_TAIL": "til", "VARIABLES_SET_TOOLTIP": "Setter verdien av denne variablen lik parameteren.", "VARIABLES_SET_CREATE_GET": "Opprett 'hent %1'", "PROCEDURES_DEFNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFNORETURN_TITLE": "til", "PROCEDURES_DEFNORETURN_PROCEDURE": "gjør noe", "PROCEDURES_BEFORE_PARAMS": "med:", "PROCEDURES_DEFNORETURN_DO": "", "PROCEDURES_DEFNORETURN_TOOLTIP": "Opprett en funksjon som ikke har noe resultat.", "PROCEDURES_DEFRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFRETURN_RETURN": "returner", "PROCEDURES_DEFRETURN_TOOLTIP": "Oppretter en funksjon som har et resultat.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Advarsel: Denne funksjonen har duplikate parametere.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_CALL": "", "PROCEDURES_CALLNORETURN_TOOLTIP": "Kjør den brukerdefinerte funksjonen '%1'.", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Kjør den brukerdefinerte funksjonen'%1' og bruk resultatet av den.", "PROCEDURES_MUTATORCONTAINER_TITLE": "parametere", "PROCEDURES_MUTATORARG_TITLE": "Navn på parameter:", "PROCEDURES_HIGHLIGHT_DEF": "Marker funksjonsdefinisjonen", "PROCEDURES_CREATE_DO": "Opprett '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Hvis en verdi er sann, returner da en annen verdi.", "PROCEDURES_IFRETURN_WARNING": "Advarsel: Denne blokken kan bare benyttes innenfor en funksjonsdefinisjon." } ================================================ FILE: extern/blockly/msg/json/nl.json ================================================ { "@metadata": { "authors": [ "Siebrand" ] }, "VARIABLES_DEFAULT_NAME": "item", "DUPLICATE_BLOCK": "Duplicaat", "ADD_COMMENT": "Reactie toevoegen", "REMOVE_COMMENT": "Opmerking verwijderen", "EXTERNAL_INPUTS": "Externe invoer", "INLINE_INPUTS": "Inline invoer", "DELETE_BLOCK": "Blok verwijderen", "DELETE_X_BLOCKS": "%1 blokken verwijderen", "COLLAPSE_BLOCK": "Blok inklappen", "COLLAPSE_ALL": "Blokken inklappen", "EXPAND_BLOCK": "Blok uitvouwen", "EXPAND_ALL": "Blokken uitvouwen", "DISABLE_BLOCK": "Blok uitschakelen", "ENABLE_BLOCK": "Blok inschakelen", "HELP": "Hulp", "CHANGE_VALUE_TITLE": "Waarde wijzigen:", "NEW_VARIABLE": "Nieuwe variabele...", "NEW_VARIABLE_TITLE": "Nieuwe variabelenaam:", "RENAME_VARIABLE": "Variabele hernoemen...", "RENAME_VARIABLE_TITLE": "Alle variabelen \"%1\" hernoemen naar:", "COLOUR_PICKER_HELPURL": "https://nl.wikipedia.org/wiki/Kleur", "COLOUR_PICKER_TOOLTIP": "Kies een kleur in het palet.", "COLOUR_RANDOM_TITLE": "willekeurige kleur", "COLOUR_RANDOM_TOOLTIP": "Kies een willekeurige kleur.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "kleuren met", "COLOUR_RGB_RED": "rood", "COLOUR_RGB_GREEN": "groen", "COLOUR_RGB_BLUE": "blauw", "COLOUR_RGB_TOOLTIP": "Maak een kleur met de opgegeven hoeveelheid rood, groen en blauw. Alle waarden moeten tussen 0 en 100 liggen.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "mengen", "COLOUR_BLEND_COLOUR1": "kleur 1", "COLOUR_BLEND_COLOUR2": "kleur 2", "COLOUR_BLEND_RATIO": "verhouding", "COLOUR_BLEND_TOOLTIP": "Mengt twee kleuren samen met een bepaalde verhouding (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://nl.wikipedia.org/wiki/Repetitie_(informatica)#For_en_Foreach", "CONTROLS_REPEAT_TITLE": "%1 keer herhalen", "CONTROLS_REPEAT_TITLE_REPEAT": "herhalen", "CONTROLS_REPEAT_TITLE_TIMES": "keer", "CONTROLS_REPEAT_INPUT_DO": "voer uit", "CONTROLS_REPEAT_TOOLTIP": "Voer een aantal opdrachten meerdere keren uit.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "herhalen zolang", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "herhalen totdat", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Terwijl een waarde waar is de volgende opdrachten uitvoeren.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Terwijl een waarde onwaar is de volgende opdrachten uitvoeren.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Laat de variabele %1 de waarden aannemen van het beginnummer tot het laatste nummer, tellende met het opgegeven interval, en met uitvoering van de opgegeven blokken.", "CONTROLS_FOR_INPUT_WITH": "rekenen met", "CONTROLS_FOR_INPUT_FROM_TO_BY": "van %1 tot %2 in stappen van %3", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each for each block", "CONTROLS_FOREACH_INPUT_ITEM": "voor ieder item", "CONTROLS_FOREACH_INPUT_INLIST": "in lijst", "CONTROLS_FOREACH_TOOLTIP": "Voor ieder item in een lijst, stel de variabele \"%1\" in op het item en voer daarna opdrachten uit.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "uit lus breken", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "doorgaan met de volgende iteratie van de lus", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "uit de bovenliggende lus breken", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "De rest van deze lus overslaan en doorgaan met de volgende herhaling.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Waarschuwing: dit blok mag alleen gebruikt worden in een lus.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "Als een waarde waar is, voer dan opdrachten uit.", "CONTROLS_IF_TOOLTIP_2": "Als een waarde waar is, voert dan het eerste blok met opdrachten uit. Voer andere het tweede blok met opdrachten uit.", "CONTROLS_IF_TOOLTIP_3": "Als de eerste waarde waar is, voer dan het eerste blok met opdrachten uit. Voer anders, als de tweede waarde waar is, het tweede blok met opdrachten uit.", "CONTROLS_IF_TOOLTIP_4": "Als de eerste waarde \"waar\" is, voer dan het eerste blok uit. Voer anders wanneer de tweede waarde \"waar\" is, het tweede blok uit. Als geen van beide waarden waar zijn, voer dan het laatste blok uit.", "CONTROLS_IF_MSG_IF": "als", "CONTROLS_IF_MSG_ELSEIF": "anders als", "CONTROLS_IF_MSG_ELSE": "anders", "CONTROLS_IF_IF_TOOLTIP": "Voeg stukken toe, verwijder of verander de volgorde om dit \"als\"-blok te wijzigen.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Voeg een voorwaarde toe aan het als-blok.", "CONTROLS_IF_ELSE_TOOLTIP": "Voeg een laatste, vang-alles conditie toe aan het als-statement.", "LOGIC_COMPARE_HELPURL": "https://nl.wikipedia.org/wiki/Ongelijkheid", "LOGIC_COMPARE_TOOLTIP_EQ": "Geeft \"waar\", als beide waarden gelijk aan elkaar zijn.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Geeft \"waar\" terug als de waarden niet gelijk zijn aan elkaar.", "LOGIC_COMPARE_TOOLTIP_LT": "Geeft \"waar\" als de eerste invoer kleiner is dan de tweede invoer.", "LOGIC_COMPARE_TOOLTIP_LTE": "Geeft \"waar\" terug als de eerste invoer kleiner of gelijk is aan de tweede invoer.", "LOGIC_COMPARE_TOOLTIP_GT": "Geeft \"waar\" terug als de eerste invoer meer is dan de tweede invoer.", "LOGIC_COMPARE_TOOLTIP_GTE": "Geeft \"waar\" terug als de eerste invoer groter is of gelijk aan de tweede invoer.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Geeft waar als beide waarden waar zijn.", "LOGIC_OPERATION_AND": "en", "LOGIC_OPERATION_TOOLTIP_OR": "Geeft \"waar\" terug als in ieder geval één van de waarden waar is.", "LOGIC_OPERATION_OR": "of", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "niet %1", "LOGIC_NEGATE_TOOLTIP": "Geeft \"waar\" terug als de invoer \"onwaar\" is. Geeft \"onwaar\" als de invoer \"waar\" is.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "waar", "LOGIC_BOOLEAN_FALSE": "onwaar", "LOGIC_BOOLEAN_TOOLTIP": "Geeft \"waar\" of \"onwaar\" terug.", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "niets", "LOGIC_NULL_TOOLTIP": "Geeft niets terug.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "als waar", "LOGIC_TERNARY_IF_FALSE": "als onwaar", "LOGIC_TERNARY_TOOLTIP": "Test de voorwaarde in \"test\". Als de voorwaarde \"waar\" is, geef de waarde van \"als waar\" terug; geef anders de waarde van \"als onwaar\" terug.", "MATH_NUMBER_HELPURL": "https://nl.wikipedia.org/wiki/Getal_%28wiskunde%29", "MATH_NUMBER_TOOLTIP": "Een getal.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "×", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "asin", "MATH_TRIG_ACOS": "acos", "MATH_TRIG_ATAN": "arctan", "MATH_ARITHMETIC_HELPURL": "https://nl.wikipedia.org/wiki/Rekenen", "MATH_ARITHMETIC_TOOLTIP_ADD": "Geeft de som van 2 getallen.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Geeft het verschil van de twee getallen.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Geeft het product terug van de twee getallen.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Geeft de gedeelde waarde van twee getallen.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Geeft het eerste getal tot de macht van het tweede getal.", "MATH_SINGLE_HELPURL": "https://nl.wikipedia.org/wiki/Vierkantswortel", "MATH_SINGLE_OP_ROOT": "wortel", "MATH_SINGLE_TOOLTIP_ROOT": "Geeft de wortel van een getal.", "MATH_SINGLE_OP_ABSOLUTE": "absoluut", "MATH_SINGLE_TOOLTIP_ABS": "Geeft de absolute waarde van een getal.", "MATH_SINGLE_TOOLTIP_NEG": "Geeft de negatief van een getal.", "MATH_SINGLE_TOOLTIP_LN": "Geeft het natuurlijk logaritme van een getal.", "MATH_SINGLE_TOOLTIP_LOG10": "Geeft het logaritme basis 10 van een getal.", "MATH_SINGLE_TOOLTIP_EXP": "Geeft e tot de macht van een getal.", "MATH_SINGLE_TOOLTIP_POW10": "Geeft 10 tot de macht van een getal.", "MATH_TRIG_HELPURL": "https://nl.wikipedia.org/wiki/Goniometrische_functie", "MATH_TRIG_TOOLTIP_SIN": "Geeft de sinus van een graad (geen radialen).", "MATH_TRIG_TOOLTIP_COS": "Geeft de cosinus van een graad (geen radialen).", "MATH_TRIG_TOOLTIP_TAN": "Geeft de tangens van een graad (geen radialen).", "MATH_TRIG_TOOLTIP_ASIN": "Geeft de arcsinus van een getal.", "MATH_TRIG_TOOLTIP_ACOS": "Geeft de arccosinus van een getal.", "MATH_TRIG_TOOLTIP_ATAN": "Geeft de arctangens van een getal.", "MATH_CONSTANT_HELPURL": "https://nl.wikipedia.org/wiki/Wiskundige_constante", "MATH_CONSTANT_TOOLTIP": "Geeft een van de vaak voorkomende constante waardes: π (3.141…), e (2.718…), φ (1.618…), √2 (1.414…), √½ (0.707…), of ∞ (oneindig).", "MATH_IS_EVEN": "is even", "MATH_IS_ODD": "is oneven", "MATH_IS_PRIME": "is priemgetal", "MATH_IS_WHOLE": "is geheel getal", "MATH_IS_POSITIVE": "is positief", "MATH_IS_NEGATIVE": "is negatief", "MATH_IS_DIVISIBLE_BY": "is deelbaar door", "MATH_IS_TOOLTIP": "Test of een getal even, oneven, een priemgetal, geheel, positief of negatief is, of deelbaar is door een bepaald getal. Geeft \"waar\" of \"onwaar\".", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "wijzigen", "MATH_CHANGE_INPUT_BY": "met", "MATH_CHANGE_TOOLTIP": "Voegt een getal toe aan variabele \"%1\".", "MATH_ROUND_HELPURL": "https://nl.wikipedia.org/wiki/Afronden", "MATH_ROUND_TOOLTIP": "Rondt een getal af omhoog of naar beneden.", "MATH_ROUND_OPERATOR_ROUND": "afronden", "MATH_ROUND_OPERATOR_ROUNDUP": "omhoog afronden", "MATH_ROUND_OPERATOR_ROUNDDOWN": "naar beneden afronden", "MATH_ONLIST_OPERATOR_SUM": "som van lijst", "MATH_ONLIST_TOOLTIP_SUM": "Geeft de som van alle getallen in de lijst.", "MATH_ONLIST_OPERATOR_MIN": "laagste uit lijst", "MATH_ONLIST_TOOLTIP_MIN": "Geeft het kleinste getal uit een lijst.", "MATH_ONLIST_OPERATOR_MAX": "hoogste uit lijst", "MATH_ONLIST_TOOLTIP_MAX": "Geeft het grootste getal in een lijst.", "MATH_ONLIST_OPERATOR_AVERAGE": "gemiddelde van lijst", "MATH_ONLIST_TOOLTIP_AVERAGE": "Geeft het gemiddelde terug van de numerieke waardes in een lijst.", "MATH_ONLIST_OPERATOR_MEDIAN": "mediaan van lijst", "MATH_ONLIST_TOOLTIP_MEDIAN": "Geeft de mediaan in de lijst.", "MATH_ONLIST_OPERATOR_MODE": "modi van lijst", "MATH_ONLIST_TOOLTIP_MODE": "Geeft een lijst van de meest voorkomende onderdelen in de lijst.", "MATH_ONLIST_OPERATOR_STD_DEV": "standaarddeviatie van lijst", "MATH_ONLIST_TOOLTIP_STD_DEV": "Geeft de standaardafwijking van de lijst.", "MATH_ONLIST_OPERATOR_RANDOM": "willekeurige item van lijst", "MATH_ONLIST_TOOLTIP_RANDOM": "Geeft een willekeurig item uit de lijst terug.", "MATH_MODULO_HELPURL": "https://nl.wikipedia.org/wiki/Modulair_rekenen", "MATH_MODULO_TITLE": "restgetal van %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Geeft het restgetal van het resultaat van de deling van de twee getallen.", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "beperk %1 van minimaal %2 tot maximaal %3", "MATH_CONSTRAIN_TOOLTIP": "Beperk een getal tussen de twee opgegeven limieten (inclusief).", "MATH_RANDOM_INT_HELPURL": "https://nl.wikipedia.org/wiki/Toevalsgenerator", "MATH_RANDOM_INT_TITLE": "willekeurig getal van %1 tot %2", "MATH_RANDOM_INT_TOOLTIP": "Geeft een willekeurig getal tussen de 2 opgegeven limieten in, inclusief.", "MATH_RANDOM_FLOAT_HELPURL": "https://nl.wikipedia.org/wiki/Toevalsgenerator", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "willekeurige fractie", "MATH_RANDOM_FLOAT_TOOLTIP": "Geeft een willekeurige fractie tussen 0.0 (inclusief) en 1.0 (exclusief).", "TEXT_TEXT_HELPURL": "https://nl.wikipedia.org/wiki/String_%28informatica%29", "TEXT_TEXT_TOOLTIP": "Een letter, woord of een regel tekst.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "maak tekst met", "TEXT_JOIN_TOOLTIP": "Maakt een stuk tekst door één of meer items samen te voegen.", "TEXT_CREATE_JOIN_TITLE_JOIN": "samenvoegen", "TEXT_CREATE_JOIN_TOOLTIP": "Toevoegen, verwijderen of volgorde veranderen van secties om dit tekstblok opnieuw in te stellen.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Voegt een item aan de tekst toe.", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "voeg toe aan", "TEXT_APPEND_APPENDTEXT": "tekst", "TEXT_APPEND_TOOLTIP": "Voeg tekst toe aan de variabele \"%1\".", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "lengte van %1", "TEXT_LENGTH_TOOLTIP": "Geeft het aantal tekens terug (inclusief spaties) in de opgegeven tekst.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 is leeg", "TEXT_ISEMPTY_TOOLTIP": "Geeft \"waar\" terug, als de opgegeven tekst leeg is.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Geeft de index terug van de eerste/laatste aanwezigheid van de eerste tekst in de tweede tekst. Geeft 0 terug als de tekst niet gevonden is.", "TEXT_INDEXOF_INPUT_INTEXT": "in tekst", "TEXT_INDEXOF_OPERATOR_FIRST": "zoek eerste voorkomen van tekst", "TEXT_INDEXOF_OPERATOR_LAST": "zoek het laatste voorkomen van tekst", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "in tekst", "TEXT_CHARAT_FROM_START": "haal letter # op", "TEXT_CHARAT_FROM_END": "haal letter # op vanaf einde", "TEXT_CHARAT_FIRST": "haal eerste letter op", "TEXT_CHARAT_LAST": "haal laatste letter op", "TEXT_CHARAT_RANDOM": "haal willekeurige letter op", "TEXT_CHARAT_TOOLTIP": "Geeft de letter op de opgegeven positie terug.", "TEXT_GET_SUBSTRING_TOOLTIP": "Geeft het opgegeven onderdeel van de tekst terug.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "in tekst", "TEXT_GET_SUBSTRING_START_FROM_START": "haal subtekst op vanaf letter #", "TEXT_GET_SUBSTRING_START_FROM_END": "haal subtekst op vanaf letter # vanaf einde", "TEXT_GET_SUBSTRING_START_FIRST": "haal subtekst op van eerste letter", "TEXT_GET_SUBSTRING_END_FROM_START": "naar letter #", "TEXT_GET_SUBSTRING_END_FROM_END": "van letter # tot einde", "TEXT_GET_SUBSTRING_END_LAST": "naar laatste letter", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Geef een kopie van de tekst met veranderde hoofdletters terug.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "naar HOOFDLETTERS", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "naar kleine letters", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "naar Hoofdletter Per Woord", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Geeft een kopie van de tekst met verwijderde spaties van één of beide kanten.", "TEXT_TRIM_OPERATOR_BOTH": "spaties van beide kanten afhalen", "TEXT_TRIM_OPERATOR_LEFT": "spaties van de linkerkant verwijderen", "TEXT_TRIM_OPERATOR_RIGHT": "spaties van de rechterkant verwijderen", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "tekst weergeven: %1", "TEXT_PRINT_TOOLTIP": "Drukt de opgegeven tekst, getal of een andere waarde af.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "vraagt om invoer met bericht", "TEXT_PROMPT_TYPE_NUMBER": "vraagt de gebruiker om een getal met de tekst", "TEXT_PROMPT_TOOLTIP_NUMBER": "Vraagt de gebruiker om een getal in te voeren.", "TEXT_PROMPT_TOOLTIP_TEXT": "Vraagt de gebruiker om invoer.", "LISTS_CREATE_EMPTY_HELPURL": "https://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "maak een lege lijst", "LISTS_CREATE_EMPTY_TOOLTIP": "Geeft een lijst terug met lengte 0, zonder items", "LISTS_CREATE_WITH_TOOLTIP": "Maak een lijst met een willekeurig aantal items.", "LISTS_CREATE_WITH_INPUT_WITH": "maak een lijst met", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "lijst", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Voeg stukken toe, verwijder ze of verander de volgorde om dit lijstblok aan te passen.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Voeg iets toe aan de lijst.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "Maakt een lijst die bestaat uit de opgegeven waarde, het opgegeven aantal keer herhaald.", "LISTS_REPEAT_TITLE": "Maak lijst met item %1, %2 keer herhaald", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "lengte van %1", "LISTS_LENGTH_TOOLTIP": "Geeft de lengte van een lijst terug.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 is leeg", "LISTS_TOOLTIP": "Geeft waar terug als de lijst leeg is.", "LISTS_INLIST": "in lijst", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "zoek eerste voorkomen van item", "LISTS_INDEX_OF_LAST": "zoek laatste voorkomen van item", "LISTS_INDEX_OF_TOOLTIP": "Geeft de index van het eerste of laatste voorkomen van een item in de lijst terug. Geeft 0 terug als de tekst niet is gevonden.", "LISTS_GET_INDEX_GET": "haal op", "LISTS_GET_INDEX_GET_REMOVE": "haal op en verwijder", "LISTS_GET_INDEX_REMOVE": "verwijder", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# van einde", "LISTS_GET_INDEX_FIRST": "eerste", "LISTS_GET_INDEX_LAST": "laatste", "LISTS_GET_INDEX_RANDOM": "willekeurig", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Geeft het item op de opgegeven positie in een lijst. Item 1 is het eerste item.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Geeft het item op de opgegeven positie in een lijst terug. Item 1 is het laatste item.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Geeft het eerste item in een lijst terug.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Geeft het laatste item in een lijst terug.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Geeft een willekeurig item uit een lijst.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Geeft het item op de opgegeven positie in een lijst terug en verwijdert het. Item 1 is het eerste item.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Verwijdert en geeft het item op de opgegeven positie in de lijst. Item 1 is het laatste item.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Geeft het laatste item in een lijst terug en verwijdert het.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Geeft het laatste item uit een lijst terug en verwijdert het.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Geeft een willekeurig item in een lijst terug en verwijdert het.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Verwijdert het item op de opgegeven positie in een lijst. Item 1 is het eerste item.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Verwijdert een item op de opgegeven positie in een lijst. Item 1 is het laatste item.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Verwijdert het eerste item in een lijst.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Verwijdert het laatste item uit een lijst.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Verwijdert een willekeurig item uit een lijst.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "stel in", "LISTS_SET_INDEX_INSERT": "tussenvoegen op", "LISTS_SET_INDEX_INPUT_TO": "als", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Stelt het item op de opgegeven positie in de lijst in. Item 1 is het eerste item.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Stelt het item op een opgegeven positie in de lijst in. Item 1 is het laatste item.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Stelt het eerste item in een lijst in.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Stelt het laatste item van een lijst in.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Stelt een willekeurig item uit de lijst in.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Voegt het item op een opgegeven positie in een lijst in. Item 1 is het eerste item.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Voegt het item op de opgegeven positie toe aan een lijst in. Item 1 is het laatste item.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Voegt het item toe aan het begin van de lijst.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Voeg het item aan het einde van een lijst toe.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Voegt het item op een willekeurige positie in de lijst in.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "haal sublijst op vanaf positie", "LISTS_GET_SUBLIST_START_FROM_END": "haal sublijst op van positie vanaf einde", "LISTS_GET_SUBLIST_START_FIRST": "haal sublijst op vanaf eerste", "LISTS_GET_SUBLIST_END_FROM_START": "naar item", "LISTS_GET_SUBLIST_END_FROM_END": "naar # vanaf einde", "LISTS_GET_SUBLIST_END_LAST": "naar laatste", "LISTS_GET_SUBLIST_TOOLTIP": "Maakt een kopie van het opgegeven deel van de lijst.", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TOOLTIP": "Geeft de waarde van deze variabele.", "VARIABLES_GET_CREATE_SET": "Maak \"verander %1\"", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "stel in", "VARIABLES_SET_TAIL": "naar", "VARIABLES_SET_TOOLTIP": "Verandert de waarde van de variabele naar de waarde van de invoer.", "VARIABLES_SET_CREATE_GET": "Maak 'opvragen van %1'", "PROCEDURES_DEFNORETURN_HELPURL": "https://nl.wikipedia.org/wiki/Subprogramma", "PROCEDURES_DEFNORETURN_TITLE": "om", "PROCEDURES_DEFNORETURN_PROCEDURE": "doe iets", "PROCEDURES_BEFORE_PARAMS": "met:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Maakt een functie zonder uitvoer.", "PROCEDURES_DEFRETURN_HELPURL": "https://nl.wikipedia.org/wiki/Subprogramma", "PROCEDURES_DEFRETURN_RETURN": "uitvoeren", "PROCEDURES_DEFRETURN_TOOLTIP": "Maakt een functie met een uitvoer.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Waarschuwing: deze functie heeft parameters met dezelfde naam.", "PROCEDURES_CALLNORETURN_HELPURL": "https://nl.wikipedia.org/wiki/Subprogramma", "PROCEDURES_CALLNORETURN_TOOLTIP": "Voer de door de gebruiker gedefinieerde functie \"%1\" uit.", "PROCEDURES_CALLRETURN_HELPURL": "https://nl.wikipedia.org/wiki/Subprogramma", "PROCEDURES_CALLRETURN_TOOLTIP": "Voer de door de gebruiker gedefinieerde functie \"%1\" uit en gebruik de uitvoer.", "PROCEDURES_MUTATORCONTAINER_TITLE": "ingangen", "PROCEDURES_MUTATORARG_TITLE": "invoernaam:", "PROCEDURES_HIGHLIGHT_DEF": "Accentueer functiedefinitie", "PROCEDURES_CREATE_DO": "Maak \"%1\"", "PROCEDURES_IFRETURN_TOOLTIP": "Als de eerste waarde \"waar\" is, geef dan de tweede waarde terug.", "PROCEDURES_IFRETURN_WARNING": "Waarschuwing: dit blok mag alleen gebruikt worden binnen de definitie van een functie." } ================================================ FILE: extern/blockly/msg/json/pl.json ================================================ { "@metadata": [], "VARIABLES_DEFAULT_NAME": "element", "DUPLICATE_BLOCK": "Powiel", "ADD_COMMENT": "Dodaj komentarz", "REMOVE_COMMENT": "Usuń Komentarz", "EXTERNAL_INPUTS": "Zewnętrzne wejścia", "INLINE_INPUTS": "Webdowane wejscia", "DELETE_BLOCK": "Usuń blok", "DELETE_X_BLOCKS": "Usunąć %1 bloki", "COLLAPSE_BLOCK": "Zwiń blok", "COLLAPSE_ALL": "Zwiń bloki", "EXPAND_BLOCK": "Rozwiń blok", "EXPAND_ALL": "Rozwiń bloki", "DISABLE_BLOCK": "Wyłącz blok", "ENABLE_BLOCK": "Włącz blok", "HELP": "Pomoc", "CHANGE_VALUE_TITLE": "Zmień wartość:", "NEW_VARIABLE": "Nowa zmienna...", "NEW_VARIABLE_TITLE": "Nowa nazwa zmiennej:", "RENAME_VARIABLE": "Zmień nazwę zmiennej...", "RENAME_VARIABLE_TITLE": "Zmień nazwy wszystkich '%1' zmiennych na:", "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Wybierz kolor z palety.", "COLOUR_RANDOM_TITLE": "losowy kolor", "COLOUR_RANDOM_TOOLTIP": "Wybierz kolor w sposób losowy.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "kolor z", "COLOUR_RGB_RED": "czerwony", "COLOUR_RGB_GREEN": "zielony", "COLOUR_RGB_BLUE": "niebieski", "COLOUR_RGB_TOOLTIP": "Połącz czerwony, zielony i niebieski w odpowiednich proporcjach, tak aby powstał nowy kolor. Zawartość każdego z nich określa liczba z przedziału od 0 do 100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "mieszanka", "COLOUR_BLEND_COLOUR1": "kolor 1", "COLOUR_BLEND_COLOUR2": "kolor 2", "COLOUR_BLEND_RATIO": "proporcja", "COLOUR_BLEND_TOOLTIP": "Miesza dwa kolory w danej proporcji (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "powtórz %1 razy", "CONTROLS_REPEAT_TITLE_REPEAT": "powtórz", "CONTROLS_REPEAT_TITLE_TIMES": "razy", "CONTROLS_REPEAT_INPUT_DO": "wykonaj", "CONTROLS_REPEAT_TOOLTIP": "Wykonaj niektóre instrukcje kilka razy.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "powtarzaj dopóki", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "powtarzaj aż", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Gdy wartość jest prawdziwa, wykonaj kilka instrukcji.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Gdy wartość jest nieprawdziwa, wykonaj kilka instrukcji.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Czy zmienna %1 przyjmuje wartości od numeru startowego do numeru końcowego, licząc przez określony interwał, i wykonuje określone bloki.", "CONTROLS_FOR_INPUT_WITH": "liczyć z", "CONTROLS_FOR_INPUT_FROM_TO_BY": "od %1 do %2 co %3 (wartość kroku)", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each", "CONTROLS_FOREACH_INPUT_ITEM": "dla każdego elementu", "CONTROLS_FOREACH_INPUT_INLIST": "na liście", "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "", "CONTROLS_FOREACH_TOOLTIP": "Dla każdego elementu z listy przyporządkuj zmienną '%1', a następnie wykonaj kilka instrukcji.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "wyjść z pętli", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "Przejdź do kolejnej iteracji pętli", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Wyjść z zawierającej pętli.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Pomiń resztę pętli i kontynuuj w kolejnej iteracji.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Ostrzeżenie: Ten blok może być użyty tylko w pętli.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "Jeśli wartość jest prawdziwa, to wykonaj kilka instrukcji.", "CONTROLS_IF_TOOLTIP_2": "Jeśli wartość jest prawdą, to wykonaj pierwszy blok instrukcji. W przeciwnym razie, wykonaj drugi blok instrukcji.", "CONTROLS_IF_TOOLTIP_3": "Jeśli pierwsza wartość jest prawdą, to wykonaj pierwszy blok instrukcji. W przeciwnym razie, jeśli druga wartość jest prawdą, to wykonaj drugi blok instrukcji.", "CONTROLS_IF_TOOLTIP_4": "Jeśli pierwsza wartość jest prawdziwa, wykonaj pierwszy blok instrukcji. W przeciwnym razie jeśli druga wartość jest prawdziwa, wykonaj drugi blok instrukcji. Jeżeli żadna z wartości nie jest prawdziwa, wykonaj ostatni blok instrukcji.", "CONTROLS_IF_MSG_IF": "jeśli", "CONTROLS_IF_MSG_ELSEIF": "w przeciwnym razie jeśli", "CONTROLS_IF_MSG_ELSE": "w przeciwnym razie", "CONTROLS_IF_IF_TOOLTIP": "Dodać, usunąć lub zmienić kolejność sekcji żeby zrekonfigurować blok if.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Dodać warunek do bloku if.", "CONTROLS_IF_ELSE_TOOLTIP": "Dodać warunek końcowy, warunek złap wszystkie do bloku if.", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "Zwraca \"prawda\", jeśli obie dane wejściowe są sobie równe.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Zwraca \"prawda\", jeśli obie dane wejściowe nie są sobie równe.", "LOGIC_COMPARE_TOOLTIP_LT": "Zwraca \"prawda\" jeśli pierwsza dana wejściowa jest większa od drugiej.", "LOGIC_COMPARE_TOOLTIP_LTE": "Zwraca \"prawda\", jeśli pierwsza dana wejściowa jest większa lub równa drugiej danej wejściowej.", "LOGIC_COMPARE_TOOLTIP_GT": "Zwraca \"prawda\" jeśli pierwszy dany element jest większy od drugiego.", "LOGIC_COMPARE_TOOLTIP_GTE": "Zwraca \"prawda\", jeśli pierwsza dana wejściowa jest większa niż lub równa drugiej danej wejściowej.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Zwraca \"prawda\" jeśli oba dane elementy mają wartość \"prawda\".", "LOGIC_OPERATION_AND": "i", "LOGIC_OPERATION_TOOLTIP_OR": "Zwraca \"prawda\" jeśli co najmniej jeden dany element ma wartość \"prawda\".", "LOGIC_OPERATION_OR": "lub", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "nie %1", "LOGIC_NEGATE_TOOLTIP": "Zwraca \"prawda\", jeśli dane wejściowe są fałszywe. Zwraca \"fałsz\", jeśli dana wejściowa jest prawdziwa.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "prawda", "LOGIC_BOOLEAN_FALSE": "fałsz", "LOGIC_BOOLEAN_TOOLTIP": "Zwraca 'prawda' lub 'fałsz'.", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "nic", "LOGIC_NULL_TOOLTIP": "Zwraca zero.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "jeśli prawda", "LOGIC_TERNARY_IF_FALSE": "jeśli fałsz", "LOGIC_TERNARY_TOOLTIP": "Sprawdz warunek w 'test'. Jesli warunek jest prawdziwy, to zwroci 'if true'; jesli nie jest prawdziwy to zwroci 'if false'.", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "Liczba.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "/", "MATH_MULTIPLICATION_SYMBOL": "×", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "arc sin", "MATH_TRIG_ACOS": "arc cos", "MATH_TRIG_ATAN": "arc tan", "MATH_ARITHMETIC_HELPURL": "https://pl.wikipedia.org/wiki/Arytmetyka", "MATH_ARITHMETIC_TOOLTIP_ADD": "Zwroci sume dwoch numerow.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Zwroci roznicy miedzy dwoch numerow.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Zwróć iloczyn dwóch liczb.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Zwróć iloraz dwóch liczb.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Zwróć pierwszą liczbę podniesioną do potęgi drugiej liczby.", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "pierwiastek kwadratowy", "MATH_SINGLE_TOOLTIP_ROOT": "Zwróć pierwiastek kwadratowy danej liczby.", "MATH_SINGLE_OP_ABSOLUTE": "wartość bezwzględna", "MATH_SINGLE_TOOLTIP_ABS": "Zwróć wartość bezwzględną danej liczby.", "MATH_SINGLE_TOOLTIP_NEG": "Zwróć negację danej liczby.", "MATH_SINGLE_TOOLTIP_LN": "Zwróć logarytm naturalny danej liczby.", "MATH_SINGLE_TOOLTIP_LOG10": "Zwróć logarytm dziesiętny danej liczby.", "MATH_SINGLE_TOOLTIP_EXP": "Zwraca e do potęgi danej liczby.", "MATH_SINGLE_TOOLTIP_POW10": "Zwróć 10 do potęgi danej liczby.", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "Zwraca wartość sinusa o stopniu (nie radian).", "MATH_TRIG_TOOLTIP_COS": "Zwraca wartość cosinusa o stopniu (nie radian).", "MATH_TRIG_TOOLTIP_TAN": "Zwróć tangens o stopniu (nie radian).", "MATH_TRIG_TOOLTIP_ASIN": "Zwróć arcus sinus danej liczby.", "MATH_TRIG_TOOLTIP_ACOS": "Zwróć arcus cosinus danej liczby.", "MATH_TRIG_TOOLTIP_ATAN": "Zwróć arcus tangens danej liczby.", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "Zwróć jedną wspólną stałą: π (3.141), e (2.718...), φ (1.618...), sqrt(2) (1.414...), sqrt(½) (0.707...) lub ∞ (nieskończoność).", "MATH_IS_EVEN": "jest parzysta", "MATH_IS_ODD": "jest nieparzysta", "MATH_IS_PRIME": "jest liczbą pierwszą", "MATH_IS_WHOLE": "jest liczbą całkowitą", "MATH_IS_POSITIVE": "jest dodatnia", "MATH_IS_NEGATIVE": "jest ujemna", "MATH_IS_DIVISIBLE_BY": "jest podzielna przez", "MATH_IS_TOOLTIP": "Sprawdź, czy liczba jest parzysta, nieparzysta, pierwsza, całkowita, dodatnia, ujemna, lub jeśli jest podzielna przez konkretną liczbę. Zwraca wartość \"prawda\" lub \"fałsz\".", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "zmien", "MATH_CHANGE_INPUT_BY": "o", "MATH_CHANGE_TOOLTIP": "Dodaj liczbę do zmiennej '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Zaokrąglić w górę lub w dół.", "MATH_ROUND_OPERATOR_ROUND": "zaokrąglić", "MATH_ROUND_OPERATOR_ROUNDUP": "zaokrąglić w górę", "MATH_ROUND_OPERATOR_ROUNDDOWN": "zaokrąglić w dół", "MATH_ONLIST_HELPURL": "", "MATH_ONLIST_OPERATOR_SUM": "suma z listy", "MATH_ONLIST_TOOLTIP_SUM": "Zwraca sume wszystkich liczb z listy.", "MATH_ONLIST_OPERATOR_MIN": "minimalna wartość z listy", "MATH_ONLIST_TOOLTIP_MIN": "Zwraca najnizszy numer w liscie.", "MATH_ONLIST_OPERATOR_MAX": "maksymalna wartość z listy", "MATH_ONLIST_TOOLTIP_MAX": "Zwraca najwyzszy numer w liscie.", "MATH_ONLIST_OPERATOR_AVERAGE": "średnia z listy", "MATH_ONLIST_TOOLTIP_AVERAGE": "Zwróć średnią (średnią arytmetyczną) wartości liczbowych z listy.", "MATH_ONLIST_OPERATOR_MEDIAN": "mediana z listy", "MATH_ONLIST_TOOLTIP_MEDIAN": "Zwróć medianę liczby na liście.", "MATH_ONLIST_OPERATOR_MODE": "dominanty listy", "MATH_ONLIST_TOOLTIP_MODE": "Zwróć listę najczęściej występujących elementów na liście.", "MATH_ONLIST_OPERATOR_STD_DEV": "odchylenie standardowe z listy", "MATH_ONLIST_TOOLTIP_STD_DEV": "Zwróć odchylenie standardowe listy.", "MATH_ONLIST_OPERATOR_RANDOM": "losowy element z listy", "MATH_ONLIST_TOOLTIP_RANDOM": "Zwróć losowy element z listy.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "reszta z dzielenia %1 przez %2", "MATH_MODULO_TOOLTIP": "Zwraca resztę z dzielenia dwóch liczb przez siebie.", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "zaokrągl %1 w dół %2 w górę %3", "MATH_CONSTRAIN_TOOLTIP": "Zaokrągl liczbę, aby była w określonych granicach (włącznie).", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "losowa liczba całkowita od %1 do %2", "MATH_RANDOM_INT_TOOLTIP": "Zwróć losową liczbę całkowitą w ramach dwóch określonych granic, włącznie.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "losowy ułamek", "MATH_RANDOM_FLOAT_TOOLTIP": "Zwróć losowy ułamek między 0.0 (włącznie), a 1.0 (wyłącznie).", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "Litera, wyraz lub linia tekstu.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "utwórz tekst z", "TEXT_JOIN_TOOLTIP": "Utwórz fragment tekstu, łącząc ze sobą dowolną liczbę tekstów.", "TEXT_CREATE_JOIN_TITLE_JOIN": "połącz", "TEXT_CREATE_JOIN_TOOLTIP": "Dodaj, usuń lub zmień kolejność sekcji, aby zmodyfikować blok tekstowy.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Dodaj element do tekstu.", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "do", "TEXT_APPEND_APPENDTEXT": "dołącz tekst", "TEXT_APPEND_TOOLTIP": "Dołącz tekst do zmiennej '%1'.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "długość %1", "TEXT_LENGTH_TOOLTIP": "Zwraca liczbę liter (łącznie ze spacjami) w podanym tekście.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 jest pusty", "TEXT_ISEMPTY_TOOLTIP": "Zwraca prawda (true), jeśli podany tekst jest pusty.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Zwraca indeks pierwszego/ostatniego wystąpienia pierwszego tekstu w drugim tekście. Zwraca wartość 0, jeśli tekst nie został znaleziony.", "TEXT_INDEXOF_INPUT_INTEXT": "w tekście", "TEXT_INDEXOF_OPERATOR_FIRST": "znajdź pierwsze wystąpienie tekstu", "TEXT_INDEXOF_OPERATOR_LAST": "znajdź ostatnie wystąpienie tekstu", "TEXT_INDEXOF_TAIL": "", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "z tekstu", "TEXT_CHARAT_FROM_START": "pobierz literę #", "TEXT_CHARAT_FROM_END": "pobierz literę # od końca", "TEXT_CHARAT_FIRST": "pobierz pierwszą literę", "TEXT_CHARAT_LAST": "pobierz ostatnią literę", "TEXT_CHARAT_RANDOM": "pobierz losową literę", "TEXT_CHARAT_TAIL": "", "TEXT_CHARAT_TOOLTIP": "Zwraca literę na określonej pozycji.", "TEXT_GET_SUBSTRING_TOOLTIP": "Zwraca określoną część tekstu.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "w tekście", "TEXT_GET_SUBSTRING_START_FROM_START": "pobierz podsłowo od litery #", "TEXT_GET_SUBSTRING_START_FROM_END": "pobierz podsłowo od litery # od końca", "TEXT_GET_SUBSTRING_START_FIRST": "pobierz podsłowo od pierwszej litery", "TEXT_GET_SUBSTRING_END_FROM_START": "do litery #", "TEXT_GET_SUBSTRING_END_FROM_END": "do litery # od końca", "TEXT_GET_SUBSTRING_END_LAST": "do ostatniej litery", "TEXT_GET_SUBSTRING_TAIL": "", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Zwraca kopię tekstu z inną wielkością liter.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "zmień na WIELKIE LITERY", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "zmień na małe litery", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "zmień na od Wielkich Liter", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Zwróć kopię tekstu z usuniętymi spacjami z jednego lub z obu końców tekstu.", "TEXT_TRIM_OPERATOR_BOTH": "usuń spacje po obu stronach tekstu", "TEXT_TRIM_OPERATOR_LEFT": "usuń spacje z lewej strony tekstu", "TEXT_TRIM_OPERATOR_RIGHT": "usuń spacje z prawej strony tekstu", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "wydrukuj %1", "TEXT_PRINT_TOOLTIP": "Drukuj określony tekst, liczbę lub coś innego.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "poproś o tekst z tą wiadomością", "TEXT_PROMPT_TYPE_NUMBER": "poproś o liczbę z tą wiadomością", "TEXT_PROMPT_TOOLTIP_NUMBER": "Zapytaj użytkownika o liczbę.", "TEXT_PROMPT_TOOLTIP_TEXT": "Zapytaj użytkownika o jakiś tekst.", "LISTS_CREATE_EMPTY_HELPURL": "https://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "utwórz pustą listę", "LISTS_CREATE_EMPTY_TOOLTIP": "Zwraca listę, o długości 0, nie zawierającą rekordów z danymi", "LISTS_CREATE_WITH_TOOLTIP": "Utwórz listę z dowolną ilością elementów.", "LISTS_CREATE_WITH_INPUT_WITH": "Tworzenie listy z", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "lista", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Dodać, usunąć lub zmienić kolejność sekcji żeby zrekonfigurować blok tej listy.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Dodaj element do listy.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "Tworzy listę składającą się z podanej wartości powtórzonej odpowiednią liczbę razy.", "LISTS_REPEAT_TITLE": "stwórz listę, powtarzając element %1 %2 razy", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "długość %1", "LISTS_LENGTH_TOOLTIP": "Zwraca długość listy.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 jest pusty", "LISTS_TOOLTIP": "Zwraca \"prawda\" jeśli lista jest pusta.", "LISTS_INLIST": "na liście", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "znaleźć pierwsze wystąpienie elementu", "LISTS_INDEX_OF_LAST": "znajduje ostatanie wystąpienie elementu", "LISTS_INDEX_OF_TOOLTIP": "Zwraca indeks pierwszego/ostatniego wystąpienia elementu na liście. Zwraca wartość 0, jeśli tekst nie zostanie znaleziony.", "LISTS_GET_INDEX_GET": "pobierz", "LISTS_GET_INDEX_GET_REMOVE": "Pobierz i usuń", "LISTS_GET_INDEX_REMOVE": "usuń", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# od końca", "LISTS_GET_INDEX_FIRST": "pierwszy", "LISTS_GET_INDEX_LAST": "ostatni", "LISTS_GET_INDEX_RANDOM": "losowy", "LISTS_GET_INDEX_TAIL": "", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Zwraca element z konkretnej pozycji na liście. #1 to pierwszy element.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Zwraca element z określonej pozycji na liście. #1 to ostatni element.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Zwraca pierwszy element z listy.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Zwraca ostatni element z listy.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Zwraca losowy element z listy.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Usuwa i zwraca element z określonej pozycji na liście. #1 to pierwszy element.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Usuwa i zwraca element z określonej pozycji na liście. #1 to ostatni element.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Usuwa i zwraca pierwszy element z listy.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Usuwa i zwraca ostatni element z listy.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Usuwa i zwraca losowy element z listy.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Usuwa element z określonej pozycji na liście. #1 to pierwszy element.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Usuwa element z określonej pozycji na liście. #1 to ostatni element.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Usuwa pierwszy element z listy.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Usuwa ostatni element z listy.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Usuwa losowy element z listy.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "ustaw", "LISTS_SET_INDEX_INSERT": "wstaw w", "LISTS_SET_INDEX_INPUT_TO": "jako", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Wstawia element w odpowiednie miejsce na liście. #1 to pierwszy element.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Wstawia element w odpowiednie miejsce na liście. #1 to ostatni element.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Wstawia pierwszy element na liście.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Wstawia ostatni element na liście.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Wstawia losowy element na liście.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Wstawia element w odpowiednim miejscu na liście. #1 to pierwszy element.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Wstawia element w odpowiednim miejscu na liście. #1 to ostatni element.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Wstawia element na początku listy.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Wstaw element na koniec listy.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Wstawia element w losowym miejscu na liście.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "Pobierz listę podrzędną z #", "LISTS_GET_SUBLIST_START_FROM_END": "Pobierz listę podrzędną z # od końca", "LISTS_GET_SUBLIST_START_FIRST": "Pobierz listę podrzędną z pierwszego", "LISTS_GET_SUBLIST_END_FROM_START": "do #", "LISTS_GET_SUBLIST_END_FROM_END": "do # od końca", "LISTS_GET_SUBLIST_END_LAST": "do ostatniego", "LISTS_GET_SUBLIST_TAIL": "", "LISTS_GET_SUBLIST_TOOLTIP": "Tworzy kopię z określoną część listy.", "ORDINAL_NUMBER_SUFFIX": "", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TITLE": "", "VARIABLES_GET_TAIL": "", "VARIABLES_GET_TOOLTIP": "Zwraca wartość tej zmiennej.", "VARIABLES_GET_CREATE_SET": "Utwórz blok 'ustaw %1'", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "przypisz", "VARIABLES_SET_TAIL": "wartość", "VARIABLES_SET_TOOLTIP": "Nadaj tej zmiennej wartość.", "VARIABLES_SET_CREATE_GET": "Utwórz blok 'pobierz %1'", "PROCEDURES_DEFNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFNORETURN_TITLE": "do", "PROCEDURES_DEFNORETURN_PROCEDURE": "zrób coś", "PROCEDURES_BEFORE_PARAMS": "z:", "PROCEDURES_DEFNORETURN_DO": "", "PROCEDURES_DEFNORETURN_TOOLTIP": "Tworzy funkcję bez wyniku.", "PROCEDURES_DEFRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFRETURN_RETURN": "zwróć", "PROCEDURES_DEFRETURN_TOOLTIP": "Tworzy funkcję z wynikiem.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Ostrzeżenie: Ta funkcja ma powtórzone parametry.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_CALL": "", "PROCEDURES_CALLNORETURN_TOOLTIP": "Uruchom funkcję zdefiniowaną przez użytkownika '%1'.", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Uruchom funkcję zdefiniowaną przez użytkownika '%1' i skorzystaj z jej wyniku.", "PROCEDURES_MUTATORCONTAINER_TITLE": "wejścia", "PROCEDURES_MUTATORARG_TITLE": "nazwa wejścia:", "PROCEDURES_HIGHLIGHT_DEF": "Podświetl definicję funkcji", "PROCEDURES_CREATE_DO": "Stwórz '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Jeśli wartość jest prawdziwa, zwróć drugą wartość.", "PROCEDURES_IFRETURN_WARNING": "Ostrzeżenie: Ten blok może być używany tylko w definicji funkcji." } ================================================ FILE: extern/blockly/msg/json/pms.json ================================================ { "@metadata": { "authors": [ "Borichèt" ] }, "VARIABLES_DEFAULT_NAME": "element", "DUPLICATE_BLOCK": "Dupliché", "ADD_COMMENT": "Gionté un coment", "REMOVE_COMMENT": "Scancelé un coment", "EXTERNAL_INPUTS": "Imission esterne", "INLINE_INPUTS": "Imission an linia", "DELETE_BLOCK": "Scancelé ël blòch", "DELETE_X_BLOCKS": "Scancelé %1 blòch", "COLLAPSE_BLOCK": "Arduve ël blòch", "COLLAPSE_ALL": "Arduve ij blòch", "EXPAND_BLOCK": "Dësvlupé ël blòch", "EXPAND_ALL": "Dësvlupé ij blòch", "DISABLE_BLOCK": "Disativé ël blòch", "ENABLE_BLOCK": "Ativé ël blòch", "HELP": "Agiut", "CHANGE_VALUE_TITLE": "Modifiché ël valor:", "NEW_VARIABLE": "Neuva variàbil...", "NEW_VARIABLE_TITLE": "Nòm ëd la neuva variàbil:", "RENAME_VARIABLE": "Arnomé la variàbil...", "RENAME_VARIABLE_TITLE": "Arnomé tute le variàbij '%1' 'me:", "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Serne un color ant la taulòssa.", "COLOUR_RANDOM_TITLE": "color a asar", "COLOUR_RANDOM_TOOLTIP": "Serne un color a asar.", "COLOUR_RGB_TITLE": "coloré con", "COLOUR_RGB_RED": "ross", "COLOUR_RGB_GREEN": "verd", "COLOUR_RGB_BLUE": "bleu", "COLOUR_RGB_TOOLTIP": "Creé un color con la quantità spessificà ëd ross, verd e bleu. Tuti ij valor a devo esse antra 0 e 100.", "COLOUR_BLEND_TITLE": "mës-cé", "COLOUR_BLEND_COLOUR1": "color 1", "COLOUR_BLEND_COLOUR2": "color 2", "COLOUR_BLEND_RATIO": "rapòrt", "COLOUR_BLEND_TOOLTIP": "A mës-cia doi color ansema con un rapòrt dàit (0,0 - 1,0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "arpete %1 vire", "CONTROLS_REPEAT_TITLE_REPEAT": "arpete", "CONTROLS_REPEAT_TITLE_TIMES": "vire", "CONTROLS_REPEAT_INPUT_DO": "fé", "CONTROLS_REPEAT_TOOLTIP": "Eseguì chèiche anstrussion vàire vire.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "arpete antramentre che", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "arpete fin-a a", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Cand un valor a l'é ver, eseguì chèiche anstrussion.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Cand un valor a l'é fàuss, eseguì chèiche anstrussion.", "CONTROLS_FOR_TOOLTIP": "Fé an manera che la variàbil %1 a pija ij valor dal nùmer inissial fin-a al nùmer final, an contand për l'antërval ëspessificà, e eseguì ij bloch ëspessificà.", "CONTROLS_FOR_INPUT_WITH": "conté con", "CONTROLS_FOR_INPUT_FROM_TO_BY": "da %1 a %2 për %3", "CONTROLS_FOREACH_INPUT_ITEM": "për minca element", "CONTROLS_FOREACH_INPUT_INLIST": "ant la lista", "CONTROLS_FOREACH_TOOLTIP": "Për minca element an na lista, dé ël valor ëd l'element a la variàbil '%1', peui eseguì chèiche anstrussion.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "seurte da la liassa", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "continué con l'iterassion sucessiva dla liassa", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Seurte da la liassa anglobanta.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Sauté ël rest ëd sa liassa, e continué con l'iterassion apress.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Atension: Ës blòch a peul mach esse dovrà andrinta a na liassa.", "CONTROLS_IF_TOOLTIP_1": "Si un valor a l'é ver, antlora eseguì chèiche anstrussion.", "CONTROLS_IF_TOOLTIP_2": "Si un valor a l'é ver, antlora eseguì ël prim blòch d'anstrussion. Dësnò, eseguì ël second blòch d'anstrussion.", "CONTROLS_IF_TOOLTIP_3": "Si ël prim valor a l'é ver, antlora fé andé ël prim blòch d'anstrussion. Dësnò, si ël second valor a l'é ver, fé andé ël second blòch d'anstrussion.", "CONTROLS_IF_TOOLTIP_4": "Si ël prim valor a l'é ver, antlora fé andé ël prim blòch d'anstrussion. Dësnò, si ël second valor a l'é ver, fé andé ël second blòcj d'anstrussion. Si gnun dij valor a l'é ver, fé andé l'ùltim blòch d'anstrussion.", "CONTROLS_IF_MSG_IF": "si", "CONTROLS_IF_MSG_ELSEIF": "dësnò si", "CONTROLS_IF_MSG_ELSE": "dësnò", "CONTROLS_IF_IF_TOOLTIP": "Gionté, gavé o riordiné le session për cinfiguré torna ës blòch si.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Gionté na condission al blòch si.", "CONTROLS_IF_ELSE_TOOLTIP": "Gionté na condission final ch'a cheuj tut al blòch si.", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "Rësponde ver si le doe imission a son uguaj.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Rësponde ver si le doe imission a son nen uguaj.", "LOGIC_COMPARE_TOOLTIP_LT": "Rësponde ver si la prima imission a l'é pi cita dla sconda.", "LOGIC_COMPARE_TOOLTIP_LTE": "Rësponde ver si la prima imission a l'é pi cita o ugual a la sconda.", "LOGIC_COMPARE_TOOLTIP_GT": "Rësponde ver si la prima imission a l'é pi granda che la sconda.", "LOGIC_COMPARE_TOOLTIP_GTE": "Rësponde ver si la prima imission a l'é pi granda o ugual a la sconda.", "LOGIC_OPERATION_TOOLTIP_AND": "Rësponde ver se tute doe j'imission a son vere.", "LOGIC_OPERATION_AND": "e", "LOGIC_OPERATION_TOOLTIP_OR": "Rësponde ver se almanch un-a d'imission a l'é vera.", "LOGIC_OPERATION_OR": "o", "LOGIC_NEGATE_TITLE": "nen %1", "LOGIC_NEGATE_TOOLTIP": "A rëspond ver se l'imission a l'é fàussa. A rëspond fàuss se l'imission a l'é vera.", "LOGIC_BOOLEAN_TRUE": "ver", "LOGIC_BOOLEAN_FALSE": "fàuss", "LOGIC_BOOLEAN_TOOLTIP": "A rëspond ver o fàuss.", "LOGIC_NULL": "gnente", "LOGIC_NULL_TOOLTIP": "A rëspond gnente.", "LOGIC_TERNARY_CONDITION": "preuva", "LOGIC_TERNARY_IF_TRUE": "se ver", "LOGIC_TERNARY_IF_FALSE": "se fàuss", "LOGIC_TERNARY_TOOLTIP": "Controlé la condission an 'preuva'. Se la condission a l'é vera, a rëspond con ël valor 'se ver'; dësnò a rëspond con ël valor 'se fàuss'.", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "Un nùmer.", "MATH_ARITHMETIC_HELPURL": "https://en.wikipedia.org/wiki/Arithmetic", "MATH_ARITHMETIC_TOOLTIP_ADD": "A smon la soma ëd doi nùmer.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "A smon la diferensa dij doi nùmer.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "A smon ël prodot dij doi nùmer.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "A smon ël cossient dij doi nùmer.", "MATH_ARITHMETIC_TOOLTIP_POWER": "A smon ël prim nùmer alvà a la potensa dël second.", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "rèis quadra", "MATH_SINGLE_TOOLTIP_ROOT": "A smon la rèis quadra d'un nùmer.", "MATH_SINGLE_OP_ABSOLUTE": "assolù", "MATH_SINGLE_TOOLTIP_ABS": "A smon ël valor assolù d'un nùmer.", "MATH_SINGLE_TOOLTIP_NEG": "A smon l'opòst d'un nùmer.", "MATH_SINGLE_TOOLTIP_LN": "A smon ël logaritm natural d'un nùmer.", "MATH_SINGLE_TOOLTIP_LOG10": "A smon ël logaritm an base 10 d'un nùmer.", "MATH_SINGLE_TOOLTIP_EXP": "A smon e a la potensa d'un nùmer.", "MATH_SINGLE_TOOLTIP_POW10": "A smon 10 a la potensa d'un nùmer.", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "A smon ël sen ëd n'àngol an gré (pa an radiant).", "MATH_TRIG_TOOLTIP_COS": "A smon ël cosen ëd n'àngol an gré (pa an radiant).", "MATH_TRIG_TOOLTIP_TAN": "A smon la tangenta ëd n'àngol an gré (pa an radiant).", "MATH_TRIG_TOOLTIP_ASIN": "A smon l'arch-sen d'un nùmer.", "MATH_TRIG_TOOLTIP_ACOS": "A smon l'arch-cosen d'un nùmer.", "MATH_TRIG_TOOLTIP_ATAN": "A smon l'arch-tangenta d'un nùmer.", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "A smon un-a dle costante comun-e π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…) o ∞ (infinì).", "MATH_IS_EVEN": "a l'é cobi", "MATH_IS_ODD": "a l'é dëscobi", "MATH_IS_PRIME": "a l'é prim", "MATH_IS_WHOLE": "a l'é antregh", "MATH_IS_POSITIVE": "a l'é positiv", "MATH_IS_NEGATIVE": "a l'é negativ", "MATH_IS_DIVISIBLE_BY": "a l'é divisìbil për", "MATH_IS_TOOLTIP": "A contròla si un nùmer a l'é cobi, dëscobi, prim, antreghm positiv, negativ, o s'a l'é divisìbil për un nùmer dàit. A rëspond ver o fàuss.", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "ancrementé", "MATH_CHANGE_INPUT_BY": "për", "MATH_CHANGE_TOOLTIP": "Gionté un nùmer a la variàbil '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "A arionda un nùmer për difet o ecess.", "MATH_ROUND_OPERATOR_ROUND": "ariondé", "MATH_ROUND_OPERATOR_ROUNDUP": "ariondé për ecess", "MATH_ROUND_OPERATOR_ROUNDDOWN": "ariondé për difet", "MATH_ONLIST_OPERATOR_SUM": "soma dla lista", "MATH_ONLIST_TOOLTIP_SUM": "A smon la soma ëd tuti ij nùmer ant la lista.", "MATH_ONLIST_OPERATOR_MIN": "mìnim ëd la lista", "MATH_ONLIST_TOOLTIP_MIN": "A smon ël pi cit nùmer ëd la lista.", "MATH_ONLIST_OPERATOR_MAX": "màssim ëd la lista", "MATH_ONLIST_TOOLTIP_MAX": "A smon ël pi gròss nùmer ëd la lista.", "MATH_ONLIST_OPERATOR_AVERAGE": "media dla lista", "MATH_ONLIST_TOOLTIP_AVERAGE": "A smon la media (aritmética) dij valor numérich ant la lista.", "MATH_ONLIST_OPERATOR_MEDIAN": "mesan-a dla lista", "MATH_ONLIST_TOOLTIP_MEDIAN": "A smon ël nùmer mesan ëd la lista.", "MATH_ONLIST_OPERATOR_MODE": "mòde dla lista", "MATH_ONLIST_TOOLTIP_MODE": "A smon na lista dj'element pi frequent ëd la lista.", "MATH_ONLIST_OPERATOR_STD_DEV": "deviassion ëstàndard ëd la lista", "MATH_ONLIST_TOOLTIP_STD_DEV": "A smon la deviassion ëstàndard ëd la lista.", "MATH_ONLIST_OPERATOR_RANDOM": "element a l'ancàpit ëd la lista", "MATH_ONLIST_TOOLTIP_RANDOM": "A smon n'element a l'ancàpit da la lista.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "resta ëd %1:%2", "MATH_MODULO_TOOLTIP": "A smon la resta ëd la division dij doi nùmer.", "MATH_CONSTRAIN_TITLE": "limité %1 antra %2 e %3", "MATH_CONSTRAIN_TOOLTIP": "Limité un nùmer a esse antra le limitassion ëspessificà (comprèise).", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "antregh aleatòri antra %1 e %2", "MATH_RANDOM_INT_TOOLTIP": "A smon n'antregh aleatòri antra ij doi lìmit ëspessificà, comprèis.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "frassion aleatòria", "MATH_RANDOM_FLOAT_TOOLTIP": "A smon na frassion aleatòria antra 0,0 (comprèis) e 1,0 (esclus).", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "Na litra, na paròla o na linia ëd test.", "TEXT_JOIN_TITLE_CREATEWITH": "creé ël test con", "TEXT_JOIN_TOOLTIP": "Creé un tòch ëd test an gionzend un nùmer qualsëssìa d'element.", "TEXT_CREATE_JOIN_TITLE_JOIN": "gionze", "TEXT_CREATE_JOIN_TOOLTIP": "Gionté, gavé o riordiné le session për configuré torna ës blòch ëd test.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Gionté n'element al test.", "TEXT_APPEND_TO": "a", "TEXT_APPEND_APPENDTEXT": "taché ël test", "TEXT_APPEND_TOOLTIP": "Taché dël test a la variàbil '%1'.", "TEXT_LENGTH_TITLE": "longheur ëd %1", "TEXT_LENGTH_TOOLTIP": "A smon ël nùmer ëd litre (spassi comprèis) ant ël test fornì.", "TEXT_ISEMPTY_TITLE": "%1 a l'é veuid", "TEXT_ISEMPTY_TOOLTIP": "A smon ver se ël test fornì a l'é veuid.", "TEXT_INDEXOF_TOOLTIP": "A smon l'ìndes dla prima/ùltima ocorensa dël prim test ant ël second test. A smon 0 se ël test a l'é nen trovà.", "TEXT_INDEXOF_INPUT_INTEXT": "ant ël test", "TEXT_INDEXOF_OPERATOR_FIRST": "trové la prima ocorensa dël test", "TEXT_INDEXOF_OPERATOR_LAST": "trové l'ùltima ocorensa dël test", "TEXT_CHARAT_INPUT_INTEXT": "ant ël test", "TEXT_CHARAT_FROM_START": "oten-e la litra #", "TEXT_CHARAT_FROM_END": "oten-e la litra # da la fin", "TEXT_CHARAT_FIRST": "oten-e la prima litra", "TEXT_CHARAT_LAST": "oten-e l'ùltima litra", "TEXT_CHARAT_RANDOM": "oten-e na litra a l'ancàpit", "TEXT_CHARAT_TOOLTIP": "A smon la litra ant la posission ëspessificà.", "TEXT_GET_SUBSTRING_TOOLTIP": "A smon un tòch ëspessificà dël test.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "ant ël test", "TEXT_GET_SUBSTRING_START_FROM_START": "oten-e la sota-stringa da la litra #", "TEXT_GET_SUBSTRING_START_FROM_END": "oten-e la sota-stringa da la litra # da la fin", "TEXT_GET_SUBSTRING_START_FIRST": "oten-e la sota-stringa da la prima litra", "TEXT_GET_SUBSTRING_END_FROM_START": "fin-a a la litra #", "TEXT_GET_SUBSTRING_END_FROM_END": "fin-a a la litra # da la fin", "TEXT_GET_SUBSTRING_END_LAST": "fin-a a l'ùltima litra", "TEXT_CHANGECASE_TOOLTIP": "A smon na còpia dël test ant un caràter diferent.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "an MAJÙSCOL", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "an minùscul", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "an Majùscol A L'Ancamin Ëd Minca Paròla", "TEXT_TRIM_TOOLTIP": "A smon na còpia dël test con jë spassi gavà da n'estremità o da tute doe.", "TEXT_TRIM_OPERATOR_BOTH": "gavé jë spassi da le doe bande ëd", "TEXT_TRIM_OPERATOR_LEFT": "gavé jë spassi da la banda snistra ëd", "TEXT_TRIM_OPERATOR_RIGHT": "gavé jë spassi da la banda drita ëd", "TEXT_PRINT_TITLE": "smon-e %1", "TEXT_PRINT_TOOLTIP": "Smon-e ël test, ël nùmer o n'àutr valor ëspessificà.", "TEXT_PROMPT_TYPE_TEXT": "anvit për un test con un mëssagi", "TEXT_PROMPT_TYPE_NUMBER": "anvit për un nùmer con un mëssagi", "TEXT_PROMPT_TOOLTIP_NUMBER": "Ciamé un nùmer a l'utent.", "TEXT_PROMPT_TOOLTIP_TEXT": "Ciamé un test a l'utent.", "LISTS_CREATE_EMPTY_TITLE": "creé na lista veuida", "LISTS_CREATE_EMPTY_TOOLTIP": "Smon-e na lista, ëd longheur 0, ch'a conten gnun-a argistrassion", "LISTS_CREATE_WITH_TOOLTIP": "Creé na lista con un nùmer qualsëssìa d'element.", "LISTS_CREATE_WITH_INPUT_WITH": "creé na lista con", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "lista", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Gionté, gavé o riordiné le session për configuré torna cost blòch ëd lista.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Gionté n'element a la lista.", "LISTS_REPEAT_TOOLTIP": "A crea na lista ch'a consist dël valor dàit arpetù ël nùmer ëspessificà ëd vire.", "LISTS_REPEAT_TITLE": "creé na lista con l'element %1 arpetù %2 vire", "LISTS_LENGTH_TITLE": "longheur ëd %1", "LISTS_LENGTH_TOOLTIP": "A smon la longheur ¨d na lista.", "LISTS_IS_EMPTY_TITLE": "%1 a l'é veuid", "LISTS_TOOLTIP": "A smon ver se la lista a l'é veuida.", "LISTS_INLIST": "ant la lista", "LISTS_INDEX_OF_FIRST": "trové la prima ocorensa dl'element", "LISTS_INDEX_OF_LAST": "trové l'ùltima ocorensa dl'element", "LISTS_INDEX_OF_TOOLTIP": "A smon l'ìndes ëd la prima/ùltima ocorensa dl'element ant la lista. A smon 0 se ël test a l'é nen trovà.", "LISTS_GET_INDEX_GET": "oten-e", "LISTS_GET_INDEX_GET_REMOVE": "oten-e e eliminé", "LISTS_GET_INDEX_REMOVE": "eliminé", "LISTS_GET_INDEX_FROM_END": "# da la fin", "LISTS_GET_INDEX_FIRST": "prim", "LISTS_GET_INDEX_LAST": "ùltim", "LISTS_GET_INDEX_RANDOM": "a l'ancàpit", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "A smon l'element a la posission ëspessificà an na lista. #1 a l'é ël prim element.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "A smon l'element a la posission ëspessificà an na lista. #1 a l'é l'ùltim element.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "A smon ël prim element an na lista.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "A smon l'ùltim element an na lista.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "A smon n'element a l'ancàpit an na lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "A gava e a smon l'element a la posission ëspessificà an na lista. #1 a l'é 'l prim element.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "A gava e a smon l'element a la posission ëspessificà an na lista. #1 a l'é l'ùltim element.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "A gava e a smon ël prim element an na lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "A gava e a smon l'ùltim element an na lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "A gava e a smon n'element a l'ancàpit an na lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "A gava l'element a la posission ëspessificà an na lista. #1 a l'é ël prim element.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "A gava l'element a la posission ëspessificà an na lista. #1 a l'é l'ùltim element.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "A gava ël prim element an na lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "A gava l'ùltim element an na lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "A gava n'element a l'ancàpit da na lista.", "LISTS_SET_INDEX_SET": "buté", "LISTS_SET_INDEX_INSERT": "anserì an", "LISTS_SET_INDEX_INPUT_TO": "tanme", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "A fissa l'element a la posission ëspessificà an na lista. #1 a l'é ël prim element.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "A fissa l'element a la posission ëspessificà an na lista. #1 a l'é l'ùltim element.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "A fissa ël prim element an na lista.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "A fissa l'ùltim element an na lista.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "A fissa n'element a l'ancàpit an na lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "A anseriss l'element a la posission ëspessificà an na lista. #1 a l'é ël prim element.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "A anseriss l'element a la posission ëspessificà an na lista. #1 a l'é l'ùltim element.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "A anseriss l'element al prinsipi ëd na lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Gionté l'element a la fin ëd na lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "A anseriss l'element a l'ancàpit an na lista.", "LISTS_GET_SUBLIST_START_FROM_START": "oten-e la sot-lista da #", "LISTS_GET_SUBLIST_START_FROM_END": "oten-e la sot-lista da # da la fin", "LISTS_GET_SUBLIST_START_FIRST": "oten-e la sot-lista dal prim", "LISTS_GET_SUBLIST_END_FROM_START": "fin-a a #", "LISTS_GET_SUBLIST_END_FROM_END": "fin-a a # da la fin", "LISTS_GET_SUBLIST_END_LAST": "fin-a a l'ùltim", "LISTS_GET_SUBLIST_TOOLTIP": "A crea na còpia dël tòch ëspessificà ëd na lista.", "VARIABLES_GET_TOOLTIP": "A smon ël valor ëd sa variàbil.", "VARIABLES_GET_CREATE_SET": "Creé 'fissé %1'", "VARIABLES_SET_TITLE": "fissé", "VARIABLES_SET_TAIL": "a", "VARIABLES_SET_TOOLTIP": "Fissé costa variàbil ugual al valor d'imission.", "VARIABLES_SET_CREATE_GET": "Creé 'oten-e %1'", "PROCEDURES_DEFNORETURN_TITLE": "a", "PROCEDURES_DEFNORETURN_PROCEDURE": "fé cheicòs", "PROCEDURES_BEFORE_PARAMS": "con:", "PROCEDURES_DEFNORETURN_TOOLTIP": "A crea na fonsion sensa surtìa.", "PROCEDURES_DEFRETURN_RETURN": "artorn", "PROCEDURES_DEFRETURN_TOOLTIP": "A crea na fonsion con na surtìa.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Atension: Costa fonsion a l'ha dij paràmeter duplicà.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_TOOLTIP": "Eseguì la fonsion '%1' definìa da l'utent.", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Eseguì la fonsion '%1' definìa da l'utent e dovré sò arzultà.", "PROCEDURES_MUTATORCONTAINER_TITLE": "imission", "PROCEDURES_MUTATORARG_TITLE": "nòm ëd l'imission:", "PROCEDURES_HIGHLIGHT_DEF": "Sot-ligné la definission dla fonsion", "PROCEDURES_CREATE_DO": "Creé '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Se un valor a l'é ver, antlora smon-e un second valor.", "PROCEDURES_IFRETURN_WARNING": "Atension: Ës blòch a podria esse dovrà mach an na definission ëd fonsion." } ================================================ FILE: extern/blockly/msg/json/pt-br.json ================================================ { "@metadata": { "authors": [ "Espertus", "Prilopes", "Mordecaista" ] }, "VARIABLES_DEFAULT_NAME": "item", "DUPLICATE_BLOCK": "Duplicar", "ADD_COMMENT": "Adicionar Comentário", "REMOVE_COMMENT": "Remover Comentário", "EXTERNAL_INPUTS": "Entrada externa", "INLINE_INPUTS": "Entradas Internas", "DELETE_BLOCK": "Remover Bloco", "DELETE_X_BLOCKS": "Remover %1 Blocos", "COLLAPSE_BLOCK": "Recolher Bloco", "COLLAPSE_ALL": "Recolher Blocos", "EXPAND_BLOCK": "Expandir Bloco", "EXPAND_ALL": "Expandir Blocos", "DISABLE_BLOCK": "Desabilitar Bloco", "ENABLE_BLOCK": "Habilitar Bloco", "HELP": "Ajuda", "CHANGE_VALUE_TITLE": "Mudar valor:", "NEW_VARIABLE": "Nova variável...", "NEW_VARIABLE_TITLE": "Nome da nova variável:", "RENAME_VARIABLE": "Renomear variável...", "RENAME_VARIABLE_TITLE": "Renomear todas as variáveis '%1' para:", "COLOUR_PICKER_HELPURL": "https://pt.wikipedia.org/wiki/Cor", "COLOUR_PICKER_TOOLTIP": "Escolher uma cor da palheta de cores.", "COLOUR_RANDOM_TITLE": "cor aleatória", "COLOUR_RANDOM_TOOLTIP": "Escolher cor de forma aleatória.", "COLOUR_RGB_TITLE": "colorir com", "COLOUR_RGB_RED": "vermelho", "COLOUR_RGB_GREEN": "verde", "COLOUR_RGB_BLUE": "azul", "COLOUR_RGB_TOOLTIP": "Cria uma cor de acordo com a quantidade especificada de vermelho, verde e azul. Todos os valores devem estar entre 0 e 100.", "COLOUR_BLEND_TITLE": "misturar", "COLOUR_BLEND_COLOUR1": "cor 1", "COLOUR_BLEND_COLOUR2": "cor 2", "COLOUR_BLEND_RATIO": "proporção", "COLOUR_BLEND_TOOLTIP": "Mistura duas cores dada uma proporção (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://pt.wikipedia.org/wiki/Estrutura_de_repeti%C3%A7%C3%A3o#Repeti.C3.A7.C3.A3o_com_vari.C3.A1vel_de_controle", "CONTROLS_REPEAT_TITLE": "Repita %1 vezes", "CONTROLS_REPEAT_TITLE_REPEAT": "repita", "CONTROLS_REPEAT_TITLE_TIMES": "vezes", "CONTROLS_REPEAT_INPUT_DO": "faça", "CONTROLS_REPEAT_TOOLTIP": "Faça algumas instruções várias vezes.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "repita enquanto", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "repita até", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Enquanto um valor for verdadeiro, então faça algumas instruções.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Enquanto um valor é falso, então faça algumas instruções.", "CONTROLS_FOR_TOOLTIP": "Faz com que a variável %1 assuma os valores do número inicial ao número final, contando de acordo com o intervalo especificado, e executa os blocos especificados.", "CONTROLS_FOR_INPUT_WITH": "contar com", "CONTROLS_FOR_INPUT_FROM_TO_BY": "de %1 até %2 por %3", "CONTROLS_FOREACH_INPUT_ITEM": "para cada item", "CONTROLS_FOREACH_INPUT_INLIST": "na lista", "CONTROLS_FOREACH_TOOLTIP": "Para cada item em uma lista, atribui o item à variável \"%1\", e então realiza algumas instruções.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "encerra o laço", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "continua com a próxima iteração do laço", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Encerra o laço.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Ignora o resto deste laço, e continua com a próxima iteração.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Atenção: Este bloco só pode ser usado dentro de um laço.", "CONTROLS_IF_TOOLTIP_1": "Se um valor é verdadeiro, então realize algumas instruções.", "CONTROLS_IF_TOOLTIP_2": "Se um valor é verdadeiro, então realize o primeiro bloco de instruções. Senão, realize o segundo bloco de instruções.", "CONTROLS_IF_TOOLTIP_3": "Se o primeiro valor é verdadeiro, então realize o primeiro bloco de instruções. Senão, se o segundo valor é verdadeiro, realize o segundo bloco de instruções.", "CONTROLS_IF_TOOLTIP_4": "Se o primeiro valor é verdadeiro, então realize o primeiro bloco de instruções. Senão, se o segundo valor é verdadeiro, realize o segundo bloco de instruções. Se nenhum dos blocos for verdadeiro, realize o último bloco de instruções.", "CONTROLS_IF_MSG_IF": "se", "CONTROLS_IF_MSG_ELSEIF": "senão se", "CONTROLS_IF_MSG_ELSE": "senão", "CONTROLS_IF_IF_TOOLTIP": "Acrescente, remova ou reordene seções para reconfigurar este bloco.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Acrescente uma condição para o bloco se.", "CONTROLS_IF_ELSE_TOOLTIP": "Acrescente uma condição final para o bloco se.", "LOGIC_COMPARE_HELPURL": "https://pt.wikipedia.org/wiki/Inequa%C3%A7%C3%A3o", "LOGIC_COMPARE_TOOLTIP_EQ": "Retorna verdadeiro se ambas as entradas forem iguais.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Retorna verdadeiro se ambas as entradas forem diferentes.", "LOGIC_COMPARE_TOOLTIP_LT": "Retorna verdadeiro se a primeira entrada for menor que a segunda entrada.", "LOGIC_COMPARE_TOOLTIP_LTE": "Retorna verdadeiro se a primeira entrada for menor ou igual à segunda entrada.", "LOGIC_COMPARE_TOOLTIP_GT": "Retorna verdadeiro se a primeira entrada for maior que a segunda entrada.", "LOGIC_COMPARE_TOOLTIP_GTE": "Retorna verdadeiro se a primeira entrada for maior ou igual à segunda entrada.", "LOGIC_OPERATION_TOOLTIP_AND": "Retorna verdadeiro se ambas as entradas forem verdadeiras.", "LOGIC_OPERATION_AND": "e", "LOGIC_OPERATION_TOOLTIP_OR": "Retorna verdadeiro se uma das estradas for verdadeira.", "LOGIC_OPERATION_OR": "ou", "LOGIC_NEGATE_TITLE": "não %1", "LOGIC_NEGATE_TOOLTIP": "Retorna verdadeiro se a entrada for falsa. Retorna falsa se a entrada for verdadeira.", "LOGIC_BOOLEAN_TRUE": "verdadeiro", "LOGIC_BOOLEAN_FALSE": "falso", "LOGIC_BOOLEAN_TOOLTIP": "Retorna verdadeiro ou falso.", "LOGIC_NULL": "nulo", "LOGIC_NULL_TOOLTIP": "Retorna nulo.", "LOGIC_TERNARY_CONDITION": "teste", "LOGIC_TERNARY_IF_TRUE": "se verdadeiro", "LOGIC_TERNARY_IF_FALSE": "se falso", "LOGIC_TERNARY_TOOLTIP": "Avalia a condição em \"teste\". Se a condição for verdadeira retorna o valor \"se verdadeiro\", senão retorna o valor \"se falso\".", "MATH_NUMBER_HELPURL": "https://pt.wikipedia.org/wiki/N%C3%BAmero", "MATH_NUMBER_TOOLTIP": "Um número.", "MATH_ARITHMETIC_HELPURL": "https://pt.wikipedia.org/wiki/Aritm%C3%A9tica", "MATH_ARITHMETIC_TOOLTIP_ADD": "Retorna a soma dos dois números.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Retorna a diferença entre os dois números.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Retorna o produto dos dois números.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Retorna o quociente da divisão dos dois números.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Retorna o primeiro número elevado à potência do segundo número.", "MATH_SINGLE_HELPURL": "https://pt.wikipedia.org/wiki/Raiz_quadrada", "MATH_SINGLE_OP_ROOT": "raiz quadrada", "MATH_SINGLE_TOOLTIP_ROOT": "Retorna a raiz quadrada de um número.", "MATH_SINGLE_OP_ABSOLUTE": "absoluto", "MATH_SINGLE_TOOLTIP_ABS": "Retorna o valor absoluto de um número.", "MATH_SINGLE_TOOLTIP_NEG": "Retorna o oposto de um número.", "MATH_SINGLE_TOOLTIP_LN": "Retorna o logaritmo natural de um número.", "MATH_SINGLE_TOOLTIP_LOG10": "Retorna o logaritmo em base 10 de um número.", "MATH_SINGLE_TOOLTIP_EXP": "Retorna o número e elevado à potência de um número.", "MATH_SINGLE_TOOLTIP_POW10": "Retorna 10 elevado à potência de um número.", "MATH_TRIG_HELPURL": "https://pt.wikipedia.org/wiki/Fun%C3%A7%C3%A3o_trigonom%C3%A9trica", "MATH_TRIG_TOOLTIP_SIN": "Retorna o seno de um grau (não radiano).", "MATH_TRIG_TOOLTIP_COS": "Retorna o cosseno de um grau (não radiano).", "MATH_TRIG_TOOLTIP_TAN": "Retorna a tangente de um grau (não radiano).", "MATH_TRIG_TOOLTIP_ASIN": "Retorna o arco seno de um número.", "MATH_TRIG_TOOLTIP_ACOS": "Retorna o arco cosseno de um número.", "MATH_TRIG_TOOLTIP_ATAN": "Retorna o arco tangente de um número.", "MATH_CONSTANT_HELPURL": "https://pt.wikipedia.org/wiki/Anexo:Lista_de_constantes_matem%C3%A1ticas", "MATH_CONSTANT_TOOLTIP": "Retorna uma das constantes comuns: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), ou ∞ (infinito).", "MATH_IS_EVEN": "é par", "MATH_IS_ODD": "é ímpar", "MATH_IS_PRIME": "é primo", "MATH_IS_WHOLE": "é inteiro", "MATH_IS_POSITIVE": "é positivo", "MATH_IS_NEGATIVE": "é negativo", "MATH_IS_DIVISIBLE_BY": "é divisível por", "MATH_IS_TOOLTIP": "Verifica se um número é par, ímpar, inteiro, positivo, negativo, ou se é divisível por outro número. Retorna verdadeiro ou falso.", "MATH_CHANGE_HELPURL": "https://pt.wikipedia.org/wiki/Adi%C3%A7%C3%A3o", "MATH_CHANGE_TITLE_CHANGE": "alterar", "MATH_CHANGE_INPUT_BY": "por", "MATH_CHANGE_TOOLTIP": "Soma um número à variável \"%1\".", "MATH_ROUND_HELPURL": "https://pt.wikipedia.org/wiki/Arredondamento", "MATH_ROUND_TOOLTIP": "Arredonda um número para cima ou para baixo.", "MATH_ROUND_OPERATOR_ROUND": "arredonda", "MATH_ROUND_OPERATOR_ROUNDUP": "arredonda para cima", "MATH_ROUND_OPERATOR_ROUNDDOWN": "arredonda para baixo", "MATH_ONLIST_OPERATOR_SUM": "soma de uma lista", "MATH_ONLIST_TOOLTIP_SUM": "Retorna a soma de todos os números na lista.", "MATH_ONLIST_OPERATOR_MIN": "menor da lista", "MATH_ONLIST_TOOLTIP_MIN": "Retorna o menor número da lista.", "MATH_ONLIST_OPERATOR_MAX": "maior da lista", "MATH_ONLIST_TOOLTIP_MAX": "Retorna o maior número da lista.", "MATH_ONLIST_OPERATOR_AVERAGE": "média da lista", "MATH_ONLIST_TOOLTIP_AVERAGE": "Retorna a média aritmética dos números da lista.", "MATH_ONLIST_OPERATOR_MEDIAN": "mediana da lista", "MATH_ONLIST_TOOLTIP_MEDIAN": "Retorna a mediana dos números da lista.", "MATH_ONLIST_OPERATOR_MODE": "moda da lista", "MATH_ONLIST_TOOLTIP_MODE": "Retorna uma lista do(s) item(ns) mais comum(ns) da lista.", "MATH_ONLIST_OPERATOR_STD_DEV": "desvio padrão da lista", "MATH_ONLIST_TOOLTIP_STD_DEV": "Retorna o desvio padrão dos números da lista.", "MATH_ONLIST_OPERATOR_RANDOM": "item aleatório da lista", "MATH_ONLIST_TOOLTIP_RANDOM": "Retorna um elemento aleatório da lista.", "MATH_MODULO_HELPURL": "https://pt.wikipedia.org/wiki/Opera%C3%A7%C3%A3o_m%C3%B3dulo", "MATH_MODULO_TITLE": "resto da divisão de %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Retorna o resto da divisão de dois números.", "MATH_CONSTRAIN_TITLE": "restringe %1 inferior %2 superior %3", "MATH_CONSTRAIN_TOOLTIP": "Restringe um número entre os limites especificados (inclusivo).", "MATH_RANDOM_INT_HELPURL": "https://pt.wikipedia.org/wiki/Gerador_de_n%C3%BAmeros_pseudoaleat%C3%B3rios", "MATH_RANDOM_INT_TITLE": "inteiro aleatório entre %1 e %2", "MATH_RANDOM_INT_TOOLTIP": "Retorna um número inteiro entre os dois limites informados, inclusivo.", "MATH_RANDOM_FLOAT_HELPURL": "https://pt.wikipedia.org/wiki/Gerador_de_n%C3%BAmeros_pseudoaleat%C3%B3rios", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "fração aleatória", "MATH_RANDOM_FLOAT_TOOLTIP": "Retorna uma fração aleatória entre 0.0 (inclusivo) e 1.0 (exclusivo).", "TEXT_TEXT_HELPURL": "https://pt.wikipedia.org/wiki/Cadeia_de_caracteres", "TEXT_TEXT_TOOLTIP": "Uma letra, palavra ou linha de texto.", "TEXT_JOIN_TITLE_CREATEWITH": "criar texto com", "TEXT_JOIN_TOOLTIP": "Criar um pedaço de texto juntando qualquer número de itens.", "TEXT_CREATE_JOIN_TITLE_JOIN": "unir", "TEXT_CREATE_JOIN_TOOLTIP": "Acrescenta, remove ou reordena seções para reconfigurar este bloco de texto.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Acrescentar um item ao texto.", "TEXT_APPEND_TO": "para", "TEXT_APPEND_APPENDTEXT": "acrescentar texto", "TEXT_APPEND_TOOLTIP": "Acrescentar um pedaço de texto à variável \"%1\".", "TEXT_LENGTH_TITLE": "tamanho de %1", "TEXT_LENGTH_TOOLTIP": "Retorna o número de letras (incluindo espaços) no texto fornecido.", "TEXT_ISEMPTY_TITLE": "%1 é vazio", "TEXT_ISEMPTY_TOOLTIP": "Retorna verdadeiro se o texto fornecido for vazio.", "TEXT_INDEXOF_TOOLTIP": "Retorna a posição da primeira/última ocorrência do primeiro texto no segundo texto. Retorna 0 se o texto não for encontrado.", "TEXT_INDEXOF_INPUT_INTEXT": "no texto", "TEXT_INDEXOF_OPERATOR_FIRST": "primeira ocorrência do texto", "TEXT_INDEXOF_OPERATOR_LAST": "última ocorrência do texto", "TEXT_CHARAT_INPUT_INTEXT": "no texto", "TEXT_CHARAT_FROM_START": "obter letra nº", "TEXT_CHARAT_FROM_END": "obter letra nº a partir do final", "TEXT_CHARAT_FIRST": "obter primeira letra", "TEXT_CHARAT_LAST": "obter última letra", "TEXT_CHARAT_RANDOM": "obter letra aleatória", "TEXT_CHARAT_TOOLTIP": "Retorna a letra na posição especificada.", "TEXT_GET_SUBSTRING_TOOLTIP": "Retorna o trecho de texto especificado.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "no texto", "TEXT_GET_SUBSTRING_START_FROM_START": "obter trecho de letra nº", "TEXT_GET_SUBSTRING_START_FROM_END": "obter trecho de letra nº a partir do final", "TEXT_GET_SUBSTRING_START_FIRST": "obter trecho de primeira letra", "TEXT_GET_SUBSTRING_END_FROM_START": "até letra nº", "TEXT_GET_SUBSTRING_END_FROM_END": "até letra nº a partir do final", "TEXT_GET_SUBSTRING_END_LAST": "até última letra", "TEXT_CHANGECASE_TOOLTIP": "Retorna uma cópia do texto em um formato diferente.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "para MAIÚSCULAS", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "para minúsculas", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "para Nomes Próprios", "TEXT_TRIM_TOOLTIP": "Retorna uma cópia do texto com os espaços removidos de uma ou ambas extremidades.", "TEXT_TRIM_OPERATOR_BOTH": "remover espaços de ambos os lados de", "TEXT_TRIM_OPERATOR_LEFT": "remover espaços à esquerda de", "TEXT_TRIM_OPERATOR_RIGHT": "remover espaços à direita de", "TEXT_PRINT_TITLE": "imprime %1", "TEXT_PRINT_TOOLTIP": "Imprime o texto, número ou valor especificado.", "TEXT_PROMPT_TYPE_TEXT": "Pede um texto com uma mensagem", "TEXT_PROMPT_TYPE_NUMBER": "Pede um número com uma mensagem", "TEXT_PROMPT_TOOLTIP_NUMBER": "Pede ao usuário um número.", "TEXT_PROMPT_TOOLTIP_TEXT": "Pede ao usuário um texto.", "LISTS_CREATE_EMPTY_TITLE": "criar lista vazia", "LISTS_CREATE_EMPTY_TOOLTIP": "Retorna uma lista, de tamanho 0, contendo nenhum registro", "LISTS_CREATE_WITH_TOOLTIP": "Cria uma lista com a quantidade de itens informada.", "LISTS_CREATE_WITH_INPUT_WITH": "criar lista com", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "lista", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Acrescenta, remove ou reordena seções para reconfigurar este bloco de lista.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Acrescenta um item à lista.", "LISTS_REPEAT_TOOLTIP": "Cria uma lista consistindo no valor informado repetido o número de vezes especificado.", "LISTS_REPEAT_TITLE": "criar lista com item %1 repetido %2 vezes", "LISTS_LENGTH_TITLE": "tamanho de %1", "LISTS_LENGTH_TOOLTIP": "Retorna o tamanho de uma lista.", "LISTS_IS_EMPTY_TITLE": "%1 é vazia", "LISTS_TOOLTIP": "Retona verdadeiro se a lista estiver vazia.", "LISTS_INLIST": "na lista", "LISTS_INDEX_OF_FIRST": "encontre a primeira ocorrência do item", "LISTS_INDEX_OF_LAST": "encontre a última ocorrência do item", "LISTS_INDEX_OF_TOOLTIP": "Retorna a posição da primeira/última ocorrência do item na lista. Retorna 0 se o texto não for encontrado.", "LISTS_GET_INDEX_GET": "obter", "LISTS_GET_INDEX_GET_REMOVE": "obter e remover", "LISTS_GET_INDEX_REMOVE": "remover", "LISTS_GET_INDEX_FROM_START": "nº", "LISTS_GET_INDEX_FROM_END": "nº a partir do final", "LISTS_GET_INDEX_FIRST": "primeiro", "LISTS_GET_INDEX_LAST": "último", "LISTS_GET_INDEX_RANDOM": "aleatório", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Retorna o item da lista na posição especificada. #1 é o primeiro item.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Retorna o item da lista na posição especificada. #1 é o último item.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Retorna o primeiro item em uma lista.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Retorna o último item em uma lista.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Retorna um item aleatório de uma lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Remove e retorna o item na posição especificada em uma lista. #1 é o primeiro item.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Remove e retorna o item na posição especificada em uma lista. #1 é o último item.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Remove e retorna o primeiro item de uma lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Remove e retorna o último item de uma lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Remove e retorna um item aleatório de uma lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Remove o item na posição especificada em uma lista. #1 é o primeiro item.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Remove o item na posição especificada em uma lista. #1 é o último item.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Remove o primeiro item de uma lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Remove o último item de uma lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Remove um item aleatório de uma lista.", "LISTS_SET_INDEX_SET": "definir", "LISTS_SET_INDEX_INSERT": "inserir em", "LISTS_SET_INDEX_INPUT_TO": "como", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Define o item da posição especificada de uma lista. #1 é o primeiro item.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Define o item da posição especificada de uma lista. #1 é o último item.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Define o primeiro item de uma lista.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Define o último item de uma lista.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Define um item aleatório de uma lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Insere o item na posição especificada em uma lista. #1 é o primeiro item.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Insere o item na posição especificada em uma lista. #1 é o último item.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Insere o item no início de uma lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Insere o item no final de uma lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Insere o item em uma posição qualquer de uma lista.", "LISTS_GET_SUBLIST_START_FROM_START": "obtém sublista de nº", "LISTS_GET_SUBLIST_START_FROM_END": "obtém sublista de nº a partir do final", "LISTS_GET_SUBLIST_START_FIRST": "obtém sublista a partir do primeiro", "LISTS_GET_SUBLIST_END_FROM_START": "até nº", "LISTS_GET_SUBLIST_END_FROM_END": "até nº a partir do final", "LISTS_GET_SUBLIST_END_LAST": "até último", "LISTS_GET_SUBLIST_TOOLTIP": "Cria uma cópia da porção especificada de uma lista.", "VARIABLES_GET_TOOLTIP": "Retorna o valor desta variável.", "VARIABLES_GET_CREATE_SET": "Criar \"definir %1\"", "VARIABLES_SET_TITLE": "definir", "VARIABLES_SET_TAIL": "para", "VARIABLES_SET_TOOLTIP": "Define esta variável para o valor da entrada.", "VARIABLES_SET_CREATE_GET": "Criar \"obter %1\"", "PROCEDURES_DEFNORETURN_TITLE": "para", "PROCEDURES_DEFNORETURN_PROCEDURE": "faça algo", "PROCEDURES_BEFORE_PARAMS": "com:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Cria uma função que não tem retorno.", "PROCEDURES_DEFRETURN_RETURN": "retorna", "PROCEDURES_DEFRETURN_TOOLTIP": "Cria uma função que possui um valor de retorno.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Atenção: Esta função tem parâmetros duplicados.", "PROCEDURES_CALLNORETURN_HELPURL": "https://pt.wikipedia.org/wiki/Sub-rotina", "PROCEDURES_CALLNORETURN_TOOLTIP": "Executa a função definida pelo usuário \"%1\".", "PROCEDURES_CALLRETURN_HELPURL": "https://pt.wikipedia.org/wiki/Sub-rotina", "PROCEDURES_CALLRETURN_TOOLTIP": "Executa a função definida pelo usuário \"%1\" e usa seu retorno.", "PROCEDURES_MUTATORCONTAINER_TITLE": "entradas", "PROCEDURES_MUTATORARG_TITLE": "nome da entrada:", "PROCEDURES_HIGHLIGHT_DEF": "Destacar definição da função", "PROCEDURES_CREATE_DO": "Criar \"%1\"", "PROCEDURES_IFRETURN_TOOLTIP": "Se um valor é verdadeiro, então retorna um valor.", "PROCEDURES_IFRETURN_WARNING": "Atenção: Este bloco só pode ser utilizado dentro da definição de uma função." } ================================================ FILE: extern/blockly/msg/json/pt.json ================================================ { "@metadata": [], "VARIABLES_DEFAULT_NAME": "item", "DUPLICATE_BLOCK": "Duplicar", "ADD_COMMENT": "Adicionar Comentário", "REMOVE_COMMENT": "Remover Comentário", "EXTERNAL_INPUTS": "Entradas externas", "INLINE_INPUTS": "Entradas Internas", "DELETE_BLOCK": "Remover Bloco", "DELETE_X_BLOCKS": "Remover %1 Blocos", "COLLAPSE_BLOCK": "Colapsar Bloco", "COLLAPSE_ALL": "Recolher Blocos", "EXPAND_BLOCK": "Expandir Bloco", "EXPAND_ALL": "Expandir Blocos", "DISABLE_BLOCK": "Desabilitar Bloco", "ENABLE_BLOCK": "Habilitar Bloco", "HELP": "Ajuda", "CHANGE_VALUE_TITLE": "Alterar valor:", "NEW_VARIABLE": "Nova variável...", "NEW_VARIABLE_TITLE": "Nome da nova variável:", "RENAME_VARIABLE": "Renomear variável...", "RENAME_VARIABLE_TITLE": "Renomear todas as variáveis '%1' para:", "COLOUR_PICKER_HELPURL": "http://pt.wikipedia.org/wiki/Cor", "COLOUR_PICKER_TOOLTIP": "Escolhe uma cor da paleta de cores.", "COLOUR_RANDOM_TITLE": "cor aleatória", "COLOUR_RANDOM_TOOLTIP": "Escolher cor de forma aleatória.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "pinte com", "COLOUR_RGB_RED": "vermelho", "COLOUR_RGB_GREEN": "verde", "COLOUR_RGB_BLUE": "azul", "COLOUR_RGB_TOOLTIP": "Cria uma cor de acordo com a quantidade especificada de vermelho, verde e azul. Todos os valores devem estar entre 0 e 100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "misturar", "COLOUR_BLEND_COLOUR1": "cor 1", "COLOUR_BLEND_COLOUR2": "cor 2", "COLOUR_BLEND_RATIO": "proporção", "COLOUR_BLEND_TOOLTIP": "Mistura duas cores dada uma proporção (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "http://pt.wikipedia.org/wiki/Estrutura_de_repeti%C3%A7%C3%A3o#Repeti.C3.A7.C3.A3o_com_vari.C3.A1vel_de_controle", "CONTROLS_REPEAT_TITLE": "repita %1 vez", "CONTROLS_REPEAT_TITLE_REPEAT": "repita", "CONTROLS_REPEAT_TITLE_TIMES": "vezes", "CONTROLS_REPEAT_INPUT_DO": "faça", "CONTROLS_REPEAT_TOOLTIP": "Faça algumas instruções várias vezes.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "repita enquanto", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "repita até", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Enquanto um valor for verdadeiro, então faça algumas instruções.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Enquanto um valor for falso, então faça algumas instruções.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Faz com que a variável %1 assuma os valores desde o número inicial até ao número final, contando de acordo com o intervalo especificado e executa os blocos especificados.", "CONTROLS_FOR_INPUT_WITH": "contar com", "CONTROLS_FOR_INPUT_FROM_TO_BY": "de %1 até %2 de %3 em %3", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Ciclos#para_cada", "CONTROLS_FOREACH_INPUT_ITEM": "para cada item", "CONTROLS_FOREACH_INPUT_INLIST": "na lista", "CONTROLS_FOREACH_TOOLTIP": "Para cada item numa lista, define a variável \"%1\" para o item e então faz algumas instruções.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "sair do ciclo", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "continuar com a próxima iteração do ciclo", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Sair do ciclo que está contido.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Ignora o resto deste ciclo e continua na próxima iteração.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Atenção: Este bloco só pode ser usado dentro de um ciclo.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "Se um valor é verdadeiro, então realize alguns passos.", "CONTROLS_IF_TOOLTIP_2": "Se um valor é verdadeiro, então realize o primeiro bloco de instruções. Senão, realize o segundo bloco de instruções", "CONTROLS_IF_TOOLTIP_3": "Se o primeiro valor é verdadeiro, então realize o primeiro bloco de instruções. Senão, se o segundo valor é verdadeiro, realize o segundo bloco de instruções.", "CONTROLS_IF_TOOLTIP_4": "Se o primeiro valor é verdadeiro, então realize o primeiro bloco de instruções. Senão, se o segundo valor é verdadeiro, realize o segundo bloco de instruções. Se nenhum dos blocos for verdadeiro, realize o último bloco de instruções.", "CONTROLS_IF_MSG_IF": "se", "CONTROLS_IF_MSG_ELSEIF": "senão se", "CONTROLS_IF_MSG_ELSE": "senão", "CONTROLS_IF_IF_TOOLTIP": "Acrescente, remova ou reordene secções para reconfigurar este bloco se.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Acrescente uma condição ao bloco se.", "CONTROLS_IF_ELSE_TOOLTIP": "Acrescente uma condição de excepação final para o bloco se.", "LOGIC_COMPARE_HELPURL": "http://pt.wikipedia.org/wiki/Inequa%C3%A7%C3%A3o", "LOGIC_COMPARE_TOOLTIP_EQ": "Retorna verdadeiro se ambas as entradas forem iguais entre si.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Retorna verdadeiro se ambas as entradas forem diferentes entre si.", "LOGIC_COMPARE_TOOLTIP_LT": "Retorna verdadeiro se a primeira entrada for menor que a segunda entrada.", "LOGIC_COMPARE_TOOLTIP_LTE": "Retorna verdadeiro se a primeira entrada for menor ou igual à segunda entrada.", "LOGIC_COMPARE_TOOLTIP_GT": "Retorna verdadeiro se a primeira entrada for maior que a segunda entrada.", "LOGIC_COMPARE_TOOLTIP_GTE": "Retorna verdadeiro se a primeira entrada for maior ou igual à segunda entrada.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Retorna verdadeiro se ambas as entradas forem verdadeiras.", "LOGIC_OPERATION_AND": "e", "LOGIC_OPERATION_TOOLTIP_OR": "Retorna verdadeiro se pelo menos uma das estradas for verdadeira.", "LOGIC_OPERATION_OR": "ou", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "não %1", "LOGIC_NEGATE_TOOLTIP": "Retorna verdadeiro se a entrada for falsa. Retorna falso se a entrada for verdadeira.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "verdadeiro", "LOGIC_BOOLEAN_FALSE": "falso", "LOGIC_BOOLEAN_TOOLTIP": "Retorna verdadeiro ou falso.", "LOGIC_NULL_HELPURL": "http://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "nulo", "LOGIC_NULL_TOOLTIP": "Retorna nulo.", "LOGIC_TERNARY_HELPURL": "http://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "teste", "LOGIC_TERNARY_IF_TRUE": "se verdadeiro", "LOGIC_TERNARY_IF_FALSE": "se falso", "LOGIC_TERNARY_TOOLTIP": "Avalia a condição em \"teste\". Se a condição for verdadeira retorna o valor \"se verdadeiro\", senão retorna o valor \"se falso\".", "MATH_NUMBER_HELPURL": "http://pt.wikipedia.org/wiki/N%C3%BAmero", "MATH_NUMBER_TOOLTIP": "Um número.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "×", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "asin", "MATH_TRIG_ACOS": "acos", "MATH_TRIG_ATAN": "atan", "MATH_ARITHMETIC_HELPURL": "http://pt.wikipedia.org/wiki/Aritm%C3%A9tica", "MATH_ARITHMETIC_TOOLTIP_ADD": "Retorna a soma de dois números.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Retorna a diferença de dois números.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Retorna o produto de dois números.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Retorna o quociente da divisão de dois números.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Retorna o primeiro número elevado à potência do segundo número.", "MATH_SINGLE_HELPURL": "http://pt.wikipedia.org/wiki/Raiz_quadrada", "MATH_SINGLE_OP_ROOT": "raíz quadrada", "MATH_SINGLE_TOOLTIP_ROOT": "Retorna a raiz quadrada de um número.", "MATH_SINGLE_OP_ABSOLUTE": "absoluto", "MATH_SINGLE_TOOLTIP_ABS": "Retorna o valor absoluto de um número.", "MATH_SINGLE_TOOLTIP_NEG": "Retorna o oposto de um número.", "MATH_SINGLE_TOOLTIP_LN": "Retorna o logarítmo natural de um número.", "MATH_SINGLE_TOOLTIP_LOG10": "Retorna o logarítmo em base 10 de um número.", "MATH_SINGLE_TOOLTIP_EXP": "Retorna o número e elevado à potência de um número.", "MATH_SINGLE_TOOLTIP_POW10": "Retorna 10 elevado à potência de um número.", "MATH_TRIG_HELPURL": "http://pt.wikipedia.org/wiki/Fun%C3%A7%C3%A3o_trigonom%C3%A9trica", "MATH_TRIG_TOOLTIP_SIN": "Retorna o seno de um grau (não radiano).", "MATH_TRIG_TOOLTIP_COS": "Retorna o cosseno de um grau (não radiano).", "MATH_TRIG_TOOLTIP_TAN": "Retorna a tangente de um grau (não radiano).", "MATH_TRIG_TOOLTIP_ASIN": "Retorna o arco seno de um número.", "MATH_TRIG_TOOLTIP_ACOS": "Retorna o arco cosseno de um número.", "MATH_TRIG_TOOLTIP_ATAN": "Retorna o arco tangente de um número.", "MATH_CONSTANT_HELPURL": "http://pt.wikipedia.org/wiki/Anexo:Lista_de_constantes_matem%C3%A1ticas", "MATH_CONSTANT_TOOLTIP": "Retorna uma das constantes comuns: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), ou ∞ (infinito).", "MATH_IS_EVEN": "é par", "MATH_IS_ODD": "é impar", "MATH_IS_PRIME": "é primo", "MATH_IS_WHOLE": "é inteiro", "MATH_IS_POSITIVE": "é positivo", "MATH_IS_NEGATIVE": "é negativo", "MATH_IS_DIVISIBLE_BY": "é divisível por", "MATH_IS_TOOLTIP": "Verifica se um número é par, impar, primo, inteiro, positivo, negativo, ou se é divisível por outro número. Retorna verdadeiro ou falso.", "MATH_CHANGE_HELPURL": "http://pt.wikipedia.org/wiki/Adi%C3%A7%C3%A3o", "MATH_CHANGE_TITLE_CHANGE": "alterar", "MATH_CHANGE_INPUT_BY": "por", "MATH_CHANGE_TOOLTIP": "Soma um número à variável \"%1\".", "MATH_ROUND_HELPURL": "http://pt.wikipedia.org/wiki/Arredondamento", "MATH_ROUND_TOOLTIP": "Arredonda um número para cima ou para baixo.", "MATH_ROUND_OPERATOR_ROUND": "arredonda", "MATH_ROUND_OPERATOR_ROUNDUP": "arredonda para cima", "MATH_ROUND_OPERATOR_ROUNDDOWN": "arredonda para baixo", "MATH_ONLIST_OPERATOR_SUM": "soma da lista", "MATH_ONLIST_TOOLTIP_SUM": "Retorna a soma de todos os números da lista.", "MATH_ONLIST_OPERATOR_MIN": "menor de uma lista", "MATH_ONLIST_TOOLTIP_MIN": "Retorna o menor número da lista.", "MATH_ONLIST_OPERATOR_MAX": "maior de uma lista", "MATH_ONLIST_TOOLTIP_MAX": "Retorna o maior número da lista.", "MATH_ONLIST_OPERATOR_AVERAGE": "média de uma lista", "MATH_ONLIST_TOOLTIP_AVERAGE": "Retorna a média aritmética dos valores números da lista.", "MATH_ONLIST_OPERATOR_MEDIAN": "mediana de uma lista", "MATH_ONLIST_TOOLTIP_MEDIAN": "Retorna a mediana da lista.", "MATH_ONLIST_OPERATOR_MODE": "moda de uma lista", "MATH_ONLIST_TOOLTIP_MODE": "Retorna a lista de item(ns) mais comum(ns) da lista.", "MATH_ONLIST_OPERATOR_STD_DEV": "desvio padrão de uma lista", "MATH_ONLIST_TOOLTIP_STD_DEV": "Retorna o desvio padrão dos números da lista.", "MATH_ONLIST_OPERATOR_RANDOM": "item aleatório de uma lista", "MATH_ONLIST_TOOLTIP_RANDOM": "Retorna um elemento aleatório da lista.", "MATH_MODULO_HELPURL": "http://pt.wikipedia.org/wiki/Opera%C3%A7%C3%A3o_m%C3%B3dulo", "MATH_MODULO_TITLE": "resto da divisão de %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Retorna o resto da divisão de dois números.", "MATH_CONSTRAIN_HELPURL": "http://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "restringe %1 inferior %2 superior %3", "MATH_CONSTRAIN_TOOLTIP": "Restringe um número entre os limites especificados (inclusive).", "MATH_RANDOM_INT_HELPURL": "http://pt.wikipedia.org/wiki/N%C3%BAmero_aleat%C3%B3rio", "MATH_RANDOM_INT_TITLE": "inteiro aleatório entre %1 e %2", "MATH_RANDOM_INT_TOOLTIP": "Retorna um número inteiro entre os dois limites especificados, inclusive.", "MATH_RANDOM_FLOAT_HELPURL": "http://pt.wikipedia.org/wiki/N%C3%BAmero_aleat%C3%B3rio", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "fração aleatória", "MATH_RANDOM_FLOAT_TOOLTIP": "Insere uma fração aleatória entre 0.0 (inclusive) e 1.0 (exclusive).", "TEXT_TEXT_HELPURL": "http://pt.wikipedia.org/wiki/Cadeia_de_caracteres", "TEXT_TEXT_TOOLTIP": "Uma letra, palavra ou linha de texto.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "criar texto com", "TEXT_JOIN_TOOLTIP": "Criar um pedaço de texto juntando qualquer número de itens.", "TEXT_CREATE_JOIN_TITLE_JOIN": "unir", "TEXT_CREATE_JOIN_TOOLTIP": "Acrescenta, remove ou reordena seções para reconfigurar este bloco de texto.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Acrescentar um item ao texto.", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "para", "TEXT_APPEND_APPENDTEXT": "acrescentar texto", "TEXT_APPEND_TOOLTIP": "Acrescentar um pedaço de texto à variável \"%1\".", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "tamanho de %1", "TEXT_LENGTH_TOOLTIP": "Devolve o número de letras (incluindo espaços) do texto fornecido.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 está vazio", "TEXT_ISEMPTY_TOOLTIP": "Retorna verdadeiro se o texto fornecido estiver vazio.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Retorna a posição da primeira/última ocorrência do primeiro texto no segundo texto. Retorna 0 se o texto não for encontrado.", "TEXT_INDEXOF_INPUT_INTEXT": "no texto", "TEXT_INDEXOF_OPERATOR_FIRST": "primeira ocorrência do texto", "TEXT_INDEXOF_OPERATOR_LAST": "última ocorrência do texto", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "no texto", "TEXT_CHARAT_FROM_START": "obter letra nº", "TEXT_CHARAT_FROM_END": "obter letra nº a partir do final", "TEXT_CHARAT_FIRST": "obter primeira letra", "TEXT_CHARAT_LAST": "obter última letra", "TEXT_CHARAT_RANDOM": "obter letra aleatória", "TEXT_CHARAT_TOOLTIP": "Retorna a letra na posição especificada.", "TEXT_GET_SUBSTRING_TOOLTIP": "Retorna a parte especificada do texto.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "no texto", "TEXT_GET_SUBSTRING_START_FROM_START": "obter subsequência de tamanho #", "TEXT_GET_SUBSTRING_START_FROM_END": "obter subsequência de tamanho # a partir do final", "TEXT_GET_SUBSTRING_START_FIRST": "obter subsequência a partir da primeira letra", "TEXT_GET_SUBSTRING_END_FROM_START": "até letra nº", "TEXT_GET_SUBSTRING_END_FROM_END": "até letra nº a partir do final", "TEXT_GET_SUBSTRING_END_LAST": "até última letra", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Retorna uma cópia do texto em formato diferente.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "para MAIÚSCULAS", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "para minúsculas", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "para Iniciais Maiúsculas", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Retorna uma cópia do texto com os espaços removidos de uma ou ambas as extremidades.", "TEXT_TRIM_OPERATOR_BOTH": "remover espaços de ambos os lados", "TEXT_TRIM_OPERATOR_LEFT": "remover espaços à esquerda", "TEXT_TRIM_OPERATOR_RIGHT": "remover espaços à direita", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "imprime %1", "TEXT_PRINT_TOOLTIP": "Imprime o texto, número ou outro valor especificado.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "Pede um texto com a mensagem", "TEXT_PROMPT_TYPE_NUMBER": "pede um número com a mensagem", "TEXT_PROMPT_TOOLTIP_NUMBER": "Pede ao utilizador um número.", "TEXT_PROMPT_TOOLTIP_TEXT": "Pede ao utilizador um texto.", "LISTS_CREATE_EMPTY_HELPURL": "http://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "criar lista vazia", "LISTS_CREATE_EMPTY_TOOLTIP": "Retorna uma lista, de tamanho 0, contendo nenhum registo", "LISTS_CREATE_WITH_TOOLTIP": "Cria uma lista com qualquer número de itens.", "LISTS_CREATE_WITH_INPUT_WITH": "criar lista com", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "lista", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Acrescente, remova ou reordene as seções para reconfigurar este bloco lista.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Acrescenta um item à lista.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "Cria uma lista constituída por um dado valor repetido o número de vezes especificado.", "LISTS_REPEAT_TITLE": "criar lista com o item %1 repetido %2 vezes", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "tamanho de %1", "LISTS_LENGTH_TOOLTIP": "Retorna o tamanho de uma lista.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 está vazia", "LISTS_TOOLTIP": "Retona verdadeiro se a lista estiver vazia.", "LISTS_INLIST": "na lista", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "encontre a primeira ocorrência do item", "LISTS_INDEX_OF_LAST": "encontre a última ocorrência do item", "LISTS_INDEX_OF_TOOLTIP": "Retorna a posição da primeira/última ocorrência do item na lista. Retorna 0 se o texto não for encontrado.", "LISTS_GET_INDEX_GET": "obter", "LISTS_GET_INDEX_GET_REMOVE": "obter e remover", "LISTS_GET_INDEX_REMOVE": "remover", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# a partir do final", "LISTS_GET_INDEX_FIRST": "primeiro", "LISTS_GET_INDEX_LAST": "último", "LISTS_GET_INDEX_RANDOM": "aleatório", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Retorna o item na posição especificada da lista . #1 é o primeiro item.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Retorna o item da lista na posição especificada. #1 é o último item.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Retorna o primeiro item de uma lista.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Retorna o último item de uma lista.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Retorna um item aleatório de uma lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Remove e retorna o item na posição especificada de uma lista. #1 é o primeiro item.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Remove e retorna o item na posição especificada de uma lista. #1 é o último item.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Remove e retorna o primeiro item de uma lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Remove e retorna o último item de uma lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Remove e retorna um item aleatório de uma lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Remove o item de uma posição especifica da lista. #1 é o primeiro item.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Remove o item na posição especificada de uma lista. #1 é o ultimo item.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Remove o primeiro item de uma lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Remove o último item de uma lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Remove um item aleatório de uma lista.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "definir", "LISTS_SET_INDEX_INSERT": "inserir em", "LISTS_SET_INDEX_INPUT_TO": "como", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Define o item na posição especificada de uma lista. #1 é o primeiro item.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Define o item na posição especificada de uma lista. #1 é o último item.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Define o primeiro item de uma lista.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Define o último item de uma lista.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Define um item aleatório de uma lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Insere o item numa posição especificada numa lista. #1 é o primeiro item.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Insere o item numa posição especificada de uma lista. #1 é o último item.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Insere o item no início da lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Insere o item no final da lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Insere o item numa posição aleatória de uma lista.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "obtem sublista de #", "LISTS_GET_SUBLIST_START_FROM_END": "obtem sublista de # a partir do final", "LISTS_GET_SUBLIST_START_FIRST": "obtem sublista da primeira lista", "LISTS_GET_SUBLIST_END_FROM_START": "até #", "LISTS_GET_SUBLIST_END_FROM_END": "até #, a partir do final", "LISTS_GET_SUBLIST_END_LAST": "para o último", "LISTS_GET_SUBLIST_TOOLTIP": "Cria uma cópia da porção especificada de uma lista.", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TOOLTIP": "Retorna o valor desta variável.", "VARIABLES_GET_CREATE_SET": "Criar \"definir %1\"", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "definir", "VARIABLES_SET_TAIL": "para", "VARIABLES_SET_TOOLTIP": "Define esta variável para o valor inserido.", "VARIABLES_SET_CREATE_GET": "Criar \"obter %1\"", "PROCEDURES_DEFNORETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFNORETURN_TITLE": "para", "PROCEDURES_DEFNORETURN_PROCEDURE": "faz algo", "PROCEDURES_BEFORE_PARAMS": "com:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Cria uma função que não tem retorno.", "PROCEDURES_DEFRETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFRETURN_RETURN": "retorna", "PROCEDURES_DEFRETURN_TOOLTIP": "Cria uma função que possui um valor de retorno.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Atenção: Esta função tem parâmetros duplicados.", "PROCEDURES_CALLNORETURN_HELPURL": "http://pt.wikipedia.org/wiki/Sub-rotina", "PROCEDURES_CALLNORETURN_TOOLTIP": "Executa a função \"%1\".", "PROCEDURES_CALLRETURN_HELPURL": "http://pt.wikipedia.org/wiki/Sub-rotina", "PROCEDURES_CALLRETURN_TOOLTIP": "Executa a função \"%1\" e usa o seu retorno.", "PROCEDURES_MUTATORCONTAINER_TITLE": "entradas", "PROCEDURES_MUTATORARG_TITLE": "nome da entrada:", "PROCEDURES_HIGHLIGHT_DEF": "Destacar definição da função", "PROCEDURES_CREATE_DO": "Criar \"%1\"", "PROCEDURES_IFRETURN_TOOLTIP": "se o valor é verdadeiro, então retorna um segundo valor.", "PROCEDURES_IFRETURN_WARNING": "Atenção: Este bloco só pode ser utilizado dentro da definição de uma função." } ================================================ FILE: extern/blockly/msg/json/qqq.json ================================================ { "VARIABLES_DEFAULT_NAME": "default name - A simple, general default name for a variable, preferably short. For more context, see [[Translating:Blockly#infrequent_message_types]].", "DUPLICATE_BLOCK": "context menu - Make a copy of the selected block (and any blocks it contains).", "ADD_COMMENT": "context menu - Add a descriptive comment to the selected block.", "REMOVE_COMMENT": "context menu - Remove the descriptive comment from the selected block.", "EXTERNAL_INPUTS": "context menu - Change from 'external' to 'inline' mode for displaying blocks used as inputs to the selected block. See [[Translating:Blockly#context_menus]].", "INLINE_INPUTS": "context menu - Change from 'internal' to 'external' mode for displaying blocks used as inputs to the selected block. See [[Translating:Blockly#context_menus]].", "DELETE_BLOCK": "context menu - Permanently delete the selected block.", "DELETE_X_BLOCKS": "context menu - Permanently delete the %1 selected blocks.\n\nParameters:\n* %1 - an integer greater than 1.", "COLLAPSE_BLOCK": "context menu - Make the appearance of the selected block smaller by hiding some information about it.", "COLLAPSE_ALL": "context menu - Make the appearance of the selected blocks smaller by hiding some information about it. Use the same terminology as in the previous message.", "EXPAND_BLOCK": "context menu - Restore the appearance of the selected block by showing information about it that was hidden (collapsed) earlier.", "EXPAND_ALL": "context menu - Restore the appearance of the selected block by showing information about it that was hidden (collapsed) earlier. Use the same terminology as in the previous message.", "DISABLE_BLOCK": "context menu - Make the selected block have no effect (unless reenabled).", "ENABLE_BLOCK": "context menu - Make the selected block have effect (after having been disabled earlier).", "HELP": "context menu - Provide helpful information about the selected block.\n{{Identical|Help}}", "CHAT": "collaboration instruction - Tell the user that they can talk with other users.", "CHANGE_VALUE_TITLE": "prompt - This message is only seen in the Opera browser. With most browsers, users can edit numeric values in blocks by just clicking and typing. Opera does not allows this, so we have to open a new window and prompt users with this message to chanage a value.", "NEW_VARIABLE": "dropdown choice - When the user clicks on a variable block, this is one of the dropdown menu choices. It is used to define a new variable. See [https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu].", "NEW_VARIABLE_TITLE": "prompt - Prompts the user to enter the name for a new variable. See [https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu].", "RENAME_VARIABLE": "dropdown choice - When the user clicks on a variable block, this is one of the dropdown menu choices. It is used to rename the current variable. See [https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu].", "RENAME_VARIABLE_TITLE": "prompt - Prompts the user to enter the new name for the selected variable. See [https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu].\n\nParameters:\n* %1 - the name of the variable to be renamed.", "COLOUR_PICKER_HELPURL": "url - Information about colour.", "COLOUR_PICKER_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Colour#Picking_a_colour_from_a_palette https://code.google.com/p/blockly/wiki/Colour#Picking_a_colour_from_a_palette].", "COLOUR_RANDOM_HELPURL": "url - A link that displays a random colour each time you visit it.", "COLOUR_RANDOM_TITLE": "block text - Title of block that generates a colour at random.", "COLOUR_RANDOM_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Colour#Generating_a_random_colour https://code.google.com/p/blockly/wiki/Colour#Generating_a_random_colour].", "COLOUR_RGB_HELPURL": "url - A link for color codes with percentages (0-100%) for each component, instead of the more common 0-255, which may be more difficult for beginners.", "COLOUR_RGB_TITLE": "block text - Title of block for [https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components].", "COLOUR_RGB_RED": "block input text - The amount of red (from 0 to 100) to use when [https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components].\n{{Identical|Red}}", "COLOUR_RGB_GREEN": "block input text - The amount of green (from 0 to 100) to use when [https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components].", "COLOUR_RGB_BLUE": "block input text - The amount of blue (from 0 to 100) to use when [https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components].\n{{Identical|Blue}}", "COLOUR_RGB_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components].", "COLOUR_BLEND_HELPURL": "url - A useful link that displays blending of two colors.", "COLOUR_BLEND_TITLE": "block text - A verb for blending two shades of paint.", "COLOUR_BLEND_COLOUR1": "block input text - The first of two colours to [https://code.google.com/p/blockly/wiki/Colour#Blending_colours blend].", "COLOUR_BLEND_COLOUR2": "block input text - The second of two colours to [https://code.google.com/p/blockly/wiki/Colour#Blending_colours blend].", "COLOUR_BLEND_RATIO": "block input text - The proportion of the [https://code.google.com/p/blockly/wiki/Colour#Blending_colours blend] containing the first color; the remaining proportion is of the second colour. For example, if the first colour is red and the second color blue, a ratio of 1 would yield pure red, a ratio of .5 would yield purple (equal amounts of red and blue), and a ratio of 0 would yield pure blue.", "COLOUR_BLEND_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Colour#Blending_colours https://code.google.com/p/blockly/wiki/Colour#Blending_colours].", "CONTROLS_REPEAT_HELPURL": "url - Describes 'repeat loops' in computer programs; consider using the translation of the page [https://en.wikipedia.org/wiki/Control_flow http://en.wikipedia.org/wiki/Control_flow].", "CONTROLS_REPEAT_TITLE": "block input text - Title of [https://code.google.com/p/blockly/wiki/Loops#repeat repeat block].\n\nParameters:\n* %1 - the number of times the body of the loop should be repeated.", "CONTROLS_REPEAT_TITLE_REPEAT": "block text - Text preceding the number of repetitions in a [https://code.google.com/p/blockly/wiki/Loops#repeat repeat block]. (This is redundant with the previous message but is needed to support older code.)", "CONTROLS_REPEAT_TITLE_TIMES": "block text - Text following the number of times a [https://code.google.com/p/blockly/wiki/Loops#repeat repeat loop] should be repeated. (This is redundant but is needed to support older code.)", "CONTROLS_REPEAT_INPUT_DO": "block text - Preceding the blocks in the body of the loop. See [https://code.google.com/p/blockly/wiki/Loops https://code.google.com/p/blockly/wiki/Loops].", "CONTROLS_REPEAT_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Loops#repeat https://code.google.com/p/blockly/wiki/Loops#repeat].", "CONTROLS_WHILEUNTIL_HELPURL": "url - Describes 'while loops' in computer programs; consider using the translation of [https://en.wikipedia.org/wiki/While_loop https://en.wikipedia.org/wiki/While_loop], if present, or [https://en.wikipedia.org/wiki/Control_flow https://en.wikipedia.org/wiki/Control_flow].", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "dropdown - Specifies that a loop should [https://code.google.com/p/blockly/wiki/Loops#Repeat_while repeat while] the following condition is true.", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "dropdown - Specifies that a loop should [https://code.google.com/p/blockly/wiki/Loops#Repeat_until repeat until] the following condition becomes true.", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "tooltip - See [https://code.google.com/p/blockly/wiki/Loops#repeat_while Loops#repeat_while https://code.google.com/p/blockly/wiki/Loops#repeat_while Loops#repeat_while].", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "tooltip - See [https://code.google.com/p/blockly/wiki/Loops#repeat_until https://code.google.com/p/blockly/wiki/Loops#repeat_until].", "CONTROLS_FOR_HELPURL": "url - Describes 'for loops' in computer programs. Consider using your language's translation of [https://en.wikipedia.org/wiki/For_loop https://en.wikipedia.org/wiki/For_loop], if present.", "CONTROLS_FOR_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Loops#count_with https://code.google.com/p/blockly/wiki/Loops#count_with].\n\nParameters:\n* %1 - the name of the loop variable.", "CONTROLS_FOR_INPUT_WITH": "block title - Title of [https://code.google.com/p/blockly/wiki/Loops#count_with count with] blocks. [[File:Blockly-count-with.png]]", "CONTROLS_FOR_INPUT_FROM_TO_BY": "block text - Starting with a (usually lower) number in a range (%1), ending with a (usually higher) number in a range (%2), and counting the iterations by a number of steps (%3). As in [https://code.google.com/p/blockly/wiki/Loops#count_with https://code.google.com/p/blockly/wiki/Loops#count_with]. [[File:Blockly-count-with.png]]", "CONTROLS_FOREACH_HELPURL": "url - Describes 'for-each loops' in computer programs. Consider using your language's translation of [https://en.wikipedia.org/wiki/Foreach https://en.wikipedia.org/wiki/Foreach] if present.", "CONTROLS_FOREACH_INPUT_ITEM": "block text - Title of [https://code.google.com/p/blockly/wiki/Loops#for_each for each block].", "CONTROLS_FOREACH_INPUT_INLIST": "block text - Preceding the list that should be iterated over in a [https://code.google.com/p/blockly/wiki/Loops#for_each for each loop].", "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "block text - Following the list that should be iterated over in a [https://code.google.com/p/blockly/wiki/Loops#for_each for each loop]. This is empty in most, but not all, languages.", "CONTROLS_FOREACH_TOOLTIP": "block text - Description of [https://code.google.com/p/blockly/wiki/Loops#for_each for each blocks].\n\nParameters:\n* %1 - the name of the loop variable.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "url - Describes control flow in computer programs. Consider using your language's translation of [https://en.wikipedia.org/wiki/Control_flow https://en.wikipedia.org/wiki/Control_flow], if it exists.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "dropdown - The current loop should be exited. See [https://code.google.com/p/blockly/wiki/Loops#break https://code.google.com/p/blockly/wiki/Loops#break].", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "dropdown - The current iteration of the loop should be ended and the next should begin. See [https://code.google.com/p/blockly/wiki/Loops#continue_with_next_iteration https://code.google.com/p/blockly/wiki/Loops#continue_with_next_iteration].", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "tooltip - See [https://code.google.com/p/blockly/wiki/Loops#break_out_of_loop https://code.google.com/p/blockly/wiki/Loops#break_out_of_loop].", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "tooltip - See [https://code.google.com/p/blockly/wiki/Loops#continue_with_next_iteration https://code.google.com/p/blockly/wiki/Loops#continue_with_next_iteration].", "CONTROLS_FLOW_STATEMENTS_WARNING": "warning - The user has tried placing a block outside of a loop (for each, while, repeat, etc.), but this type of block may only be used within a loop. See [https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks].", "CONTROLS_IF_HELPURL": "url - Describes conditional statements (if-then-else) in computer programs. Consider using your language's translation of [https://en.wikipedia.org/wiki/If_else https://en.wikipedia.org/wiki/If_else], if present.", "CONTROLS_IF_TOOLTIP_1": "tooltip - Describes [https://code.google.com/p/blockly/wiki/IfElse#If_blocks 'if' blocks]. Consider using your language's translation of [https://en.wikipedia.org/wiki/If_statement https://en.wikipedia.org/wiki/If_statement], if present.", "CONTROLS_IF_TOOLTIP_2": "tooltip - Describes [https://code.google.com/p/blockly/wiki/IfElse#If-Else_blocks if-else blocks]. Consider using your language's translation of [https://en.wikipedia.org/wiki/If_statement https://en.wikipedia.org/wiki/If_statement], if present.", "CONTROLS_IF_TOOLTIP_3": "tooltip - Describes [https://code.google.com/p/blockly/wiki/IfElse#If-Else-If_blocks if-else-if blocks]. Consider using your language's translation of [https://en.wikipedia.org/wiki/If_statement https://en.wikipedia.org/wiki/If_statement], if present.", "CONTROLS_IF_TOOLTIP_4": "tooltip - Describes [https://code.google.com/p/blockly/wiki/IfElse#If-Else-If-Else_blocks if-else-if-else blocks]. Consider using your language's translation of [https://en.wikipedia.org/wiki/If_statement https://en.wikipedia.org/wiki/If_statement], if present.", "CONTROLS_IF_MSG_IF": "block text - See [https://code.google.com/p/blockly/wiki/IfElse https://code.google.com/p/blockly/wiki/IfElse]. It is recommended, but not essential, that this have text in common with the translation of 'else if'", "CONTROLS_IF_MSG_ELSEIF": "block text - See [https://code.google.com/p/blockly/wiki/IfElse https://code.google.com/p/blockly/wiki/IfElse]. The English words 'otherwise if' would probably be clearer than 'else if', but the latter is used because it is traditional and shorter.", "CONTROLS_IF_MSG_ELSE": "block text - See [https://code.google.com/p/blockly/wiki/IfElse https://code.google.com/p/blockly/wiki/IfElse]. The English word 'otherwise' would probably be superior to 'else', but the latter is used because it is traditional and shorter.", "CONTROLS_IF_IF_TOOLTIP": "tooltip - Describes [https://code.google.com/p/blockly/wiki/IfElse#Block_Modification if block modification].", "CONTROLS_IF_ELSEIF_TOOLTIP": "tooltip - Describes the 'else if' subblock during [https://code.google.com/p/blockly/wiki/IfElse#Block_Modification if block modification].", "CONTROLS_IF_ELSE_TOOLTIP": "tooltip - Describes the 'else' subblock during [https://code.google.com/p/blockly/wiki/IfElse#Block_Modification if block modification].", "LOGIC_COMPARE_HELPURL": "url - Information about comparisons.", "LOGIC_COMPARE_TOOLTIP_EQ": "tooltip - Describes the equals (=) block.", "LOGIC_COMPARE_TOOLTIP_NEQ": "tooltip - Describes the equals (\u0026ne;) block.", "LOGIC_COMPARE_TOOLTIP_LT": "tooltip - Describes the equals (\u0026lt;) block.", "LOGIC_COMPARE_TOOLTIP_LTE": "tooltip - Describes the equals (\u0026le;) block.", "LOGIC_COMPARE_TOOLTIP_GT": "tooltip - Describes the equals (\u0026gt;) block.", "LOGIC_COMPARE_TOOLTIP_GTE": "tooltip - Describes the equals (\u0026ge;) block.", "LOGIC_OPERATION_HELPURL": "url - Information about the Boolean conjunction ('and') and disjunction ('or') operators. Consider using the translation of [https://en.wikipedia.org/wiki/Boolean_logic https://en.wikipedia.org/wiki/Boolean_logic], if it exists in your language.", "LOGIC_OPERATION_TOOLTIP_AND": "tooltip - See [https://en.wikipedia.org/wiki/Logical_conjunction https://en.wikipedia.org/wiki/Logical_conjunction].", "LOGIC_OPERATION_AND": "block text - See [https://en.wikipedia.org/wiki/Logical_conjunction https://en.wikipedia.org/wiki/Logical_conjunction].", "LOGIC_OPERATION_TOOLTIP_OR": "block text - See [https://en.wikipedia.org/wiki/Disjunction https://en.wikipedia.org/wiki/Disjunction].", "LOGIC_OPERATION_OR": "block text - See [https://en.wikipedia.org/wiki/Disjunction https://en.wikipedia.org/wiki/Disjunction].", "LOGIC_NEGATE_HELPURL": "url - Information about logical negation. The translation of [https://en.wikipedia.org/wiki/Logical_negation https://en.wikipedia.org/wiki/Logical_negation] is recommended if it exists in the target language.", "LOGIC_NEGATE_TITLE": "block text - This is a unary operator that returns ''false'' when the input is ''true'', and ''true'' when the input is ''false''. \n\nParameters:\n* %1 - the input (which should be either the value 'true' or 'false')", "LOGIC_NEGATE_TOOLTIP": "tooltip - See [https://en.wikipedia.org/wiki/Logical_negation https://en.wikipedia.org/wiki/Logical_negation].", "LOGIC_BOOLEAN_HELPURL": "url - Information about the logic values ''true'' and ''false''. Consider using the translation of [https://en.wikipedia.org/wiki/Truth_value https://en.wikipedia.org/wiki/Truth_value] if it exists in your language.", "LOGIC_BOOLEAN_TRUE": "block text - The word for the [https://en.wikipedia.org/wiki/Truth_value logical value] ''true''.", "LOGIC_BOOLEAN_FALSE": "block text - The word for the [https://en.wikipedia.org/wiki/Truth_value logical value] ''false''.", "LOGIC_BOOLEAN_TOOLTIP": "tooltip - Indicates that the block returns either of the two possible [https://en.wikipedia.org/wiki/Truth_value logical values].", "LOGIC_NULL_HELPURL": "url - Provide a link to the translation of [https://en.wikipedia.org/wiki/Nullable_type https://en.wikipedia.org/wiki/Nullable_type], if it exists in your language; otherwise, do not worry about translating this advanced concept.", "LOGIC_NULL": "block text - In computer languages, ''null'' is a special value that indicates that no value has been set. You may use your language's word for 'nothing' or 'invalid'.", "LOGIC_NULL_TOOLTIP": "tooltip - This should use the word from the previous message.", "LOGIC_TERNARY_HELPURL": "url - Describes the programming language operator known as the ''ternary'' or ''conditional'' operator. It is recommended that you use the translation of [https://en.wikipedia.org/wiki/%3F: https://en.wikipedia.org/wiki/%3F:] if it exists.", "LOGIC_TERNARY_CONDITION": "block input text - Label for the input whose value determines which of the other two inputs is returned. In some programming languages, this is called a ''''predicate''''.", "LOGIC_TERNARY_IF_TRUE": "block input text - Indicates that the following input should be returned (used as output) if the test input is true. Remember to try to keep block text terse (short).", "LOGIC_TERNARY_IF_FALSE": "block input text - Indicates that the following input should be returned (used as output) if the test input is false.", "LOGIC_TERNARY_TOOLTIP": "tooltip - See [https://en.wikipedia.org/wiki/%3F: https://en.wikipedia.org/wiki/%3F:].", "MATH_NUMBER_HELPURL": "url - Information about (real) numbers.", "MATH_NUMBER_TOOLTIP": "tooltip - Any positive or negative number, not necessarily an integer.", "MATH_ADDITION_SYMBOL": "math - The symbol for the binary operation addition.", "MATH_SUBTRACTION_SYMBOL": "math - The symbol for the binary operation indicating that the right operand should be subtracted from the left operand.", "MATH_DIVISION_SYMBOL": "math - The binary operation indicating that the left operand should be divided by the right operand.", "MATH_MULTIPLICATION_SYMBOL": "math - The symbol for the binary operation multiplication.", "MATH_POWER_SYMBOL": "math - The symbol for the binary operation exponentiation. Specifically, if the value of the left operand is L and the value of the right operand (the exponent) is R, multiply L by itself R times. (Fractional and negative exponents are also legal.)", "MATH_TRIG_SIN": "math - The short name of the trigonometric function [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent sine].", "MATH_TRIG_COS": "math - The short name of the trigonometric function [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent cosine].", "MATH_TRIG_TAN": "math - The short name of the trigonometric function [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent tangent].", "MATH_TRIG_ASIN": "math - The short name of the ''inverse of'' the trigonometric function [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent sine].", "MATH_TRIG_ACOS": "math - The short name of the ''inverse of'' the trigonometric function [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent cosine].", "MATH_TRIG_ATAN": "math - The short name of the ''inverse of'' the trigonometric function [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent tangent].", "MATH_ARITHMETIC_HELPURL": "url - Information about addition, subtraction, multiplication, division, and exponentiation.", "MATH_ARITHMETIC_TOOLTIP_ADD": "tooltip - See [https://en.wikipedia.org/wiki/Addition https://en.wikipedia.org/wiki/Addition].", "MATH_ARITHMETIC_TOOLTIP_MINUS": "tooltip - See [https://en.wikipedia.org/wiki/Subtraction https://en.wikipedia.org/wiki/Subtraction].", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "tooltip - See [https://en.wikipedia.org/wiki/Multiplication https://en.wikipedia.org/wiki/Multiplication].", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "tooltip - See [https://en.wikipedia.org/wiki/Division_(mathematics) https://en.wikipedia.org/wiki/Division_(mathematics)].", "MATH_ARITHMETIC_TOOLTIP_POWER": "tooltip - See [https://en.wikipedia.org/wiki/Exponentiation https://en.wikipedia.org/wiki/Exponentiation].", "MATH_SINGLE_HELPURL": "url - Information about the square root operation.", "MATH_SINGLE_OP_ROOT": "dropdown - This computes the positive [https://en.wikipedia.org/wiki/Square_root square root] of its input. For example, the square root of 16 is 4.", "MATH_SINGLE_TOOLTIP_ROOT": "tooltip - Please use the same term as in the previous message.", "MATH_SINGLE_OP_ABSOLUTE": "dropdown - This leaves positive numeric inputs changed and inverts negative inputs. For example, the absolute value of 5 is 5; the absolute value of -5 is also 5. For more information, see [https://en.wikipedia.org/wiki/Absolute_value https://en.wikipedia.org/wiki/Absolute_value].", "MATH_SINGLE_TOOLTIP_ABS": "tooltip - Please use the same term as in the previous message.", "MATH_SINGLE_TOOLTIP_NEG": "tooltip - Calculates '''0-n''', where '''n''' is the single numeric input.", "MATH_SINGLE_TOOLTIP_LN": "tooltip - Calculates the [https://en.wikipedia.org/wiki/Natural_logarithm|natural logarithm] of its single numeric input.", "MATH_SINGLE_TOOLTIP_LOG10": "tooltip - Calculates the [https://en.wikipedia.org/wiki/Common_logarithm common logarithm] of its single numeric input.", "MATH_SINGLE_TOOLTIP_EXP": "tooltip - Multiplies [https://en.wikipedia.org/wiki/E_%28mathematical_constant%29 e] by itself n times, where n is the single numeric input.", "MATH_SINGLE_TOOLTIP_POW10": "tooltip - Multiplies 10 by itself n times, where n is the single numeric input.", "MATH_TRIG_HELPURL": "url - Information about the trigonometric functions sine, cosine, tangent, and their inverses (ideally using degrees, not radians).", "MATH_TRIG_TOOLTIP_SIN": "tooltip - Return the [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent sine] of an [https://en.wikipedia.org/wiki/Degree_(angle) angle in degrees], not radians.", "MATH_TRIG_TOOLTIP_COS": "tooltip - Return the [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent cosine] of an [https://en.wikipedia.org/wiki/Degree_(angle) angle in degrees], not radians.", "MATH_TRIG_TOOLTIP_TAN": "tooltip - Return the [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent tangent] of an [https://en.wikipedia.org/wiki/Degree_(angle) angle in degrees], not radians.", "MATH_TRIG_TOOLTIP_ASIN": "tooltip - The [https://en.wikipedia.org/wiki/Inverse_trigonometric_functions inverse] of the [https://en.wikipedia.org/wiki/Cosine#Sine.2C_cosine_and_tangent sine function], using [https://en.wikipedia.org/wiki/Degree_(angle) degrees], not radians.", "MATH_TRIG_TOOLTIP_ACOS": "tooltip - The [https://en.wikipedia.org/wiki/Inverse_trigonometric_functions inverse] of the [https://en.wikipedia.org/wiki/Cosine#Sine.2C_cosine_and_tangent cosine] function, using [https://en.wikipedia.org/wiki/Degree_(angle) degrees], not radians.", "MATH_TRIG_TOOLTIP_ATAN": "tooltip - The [https://en.wikipedia.org/wiki/Inverse_trigonometric_functions inverse] of the [https://en.wikipedia.org/wiki/Cosine#Sine.2C_cosine_and_tangent tangent] function, using [https://en.wikipedia.org/wiki/Degree_(angle) degrees], not radians.", "MATH_CONSTANT_HELPURL": "url - Information about the mathematical constants \u0026pi;, e, the golden ratio (\u0026phi;), \u0026radic; 2, \u0026radic; 1/2, and infinity (\u0026infin;).", "MATH_CONSTANT_TOOLTIP": "tooltip - Provides the specified [https://en.wikipedia.org/wiki/Mathematical_constant mathematical constant].", "MATH_IS_EVEN": "dropdown - A number is '''even''' if it is a multiple of 2. For example, 4 is even (yielding true), but 3 is not (false).", "MATH_IS_ODD": "dropdown - A number is '''odd''' if it is not a multiple of 2. For example, 3 is odd (yielding true), but 4 is not (false). The opposite of 'odd' is 'even'.", "MATH_IS_PRIME": "dropdown - A number is [https://en.wikipedia.org/wiki/Prime prime] if it cannot be evenly divided by any positive integers except for 1 and itself. For example, 5 is prime, but 6 is not because 2 \u0026times; 3 = 6.", "MATH_IS_WHOLE": "dropdown - A number is '''whole''' if it is an [https://en.wikipedia.org/wiki/Integer integer]. For example, 5 is whole, but 5.1 is not.", "MATH_IS_POSITIVE": "dropdown - A number is '''positive''' if it is greater than 0. (0 is neither negative nor positive.)", "MATH_IS_NEGATIVE": "dropdown - A number is '''negative''' if it is less than 0. (0 is neither negative nor positive.)", "MATH_IS_DIVISIBLE_BY": "dropdown - A number x is divisible by y if y goes into x evenly. For example, 10 is divisible by 5, but 10 is not divisible by 3.", "MATH_IS_TOOLTIP": "tooltip - This block lets the user specify via a dropdown menu whether to check if the numeric input is even, odd, prime, whole, positive, negative, or divisible by a given value.", "MATH_CHANGE_HELPURL": "url - Information about incrementing (increasing the value of) a variable. For other languages, just use the translation of the Wikipedia page about addition ([https://en.wikipedia.org/wiki/Addition https://en.wikipedia.org/wiki/Addition]).", "MATH_CHANGE_TITLE_CHANGE": "- As in: '''change''' [the value of variable] ''item by'' 1 (e.g., if the variable named 'item' had the value 5, change it to 6).", "MATH_CHANGE_INPUT_BY": "- As in: ''change'' [the value of variable] ''item'' '''by''' 1 (e.g., if the variable named 'item' had the value 5, change it to 6).", "MATH_CHANGE_TOOLTIP": "tooltip - This updates the value of the variable by adding to it the following numeric input.\n\nParameters:\n* %1 - the name of the variable whose value should be increased.", "MATH_ROUND_HELPURL": "url - Information about how numbers are rounded to the nearest integer", "MATH_ROUND_TOOLTIP": "tooltip - See [https://en.wikipedia.org/wiki/Rounding https://en.wikipedia.org/wiki/Rounding].", "MATH_ROUND_OPERATOR_ROUND": "dropdown - This rounds its input to the nearest whole number. For example, 3.4 is rounded to 3.", "MATH_ROUND_OPERATOR_ROUNDUP": "dropdown - This rounds its input up to the nearest whole number. For example, if the input was 2.2, the result would be 3.", "MATH_ROUND_OPERATOR_ROUNDDOWN": "dropdown - This rounds its input down to the nearest whole number. For example, if the input was 3.8, the result would be 3.", "MATH_ONLIST_HELPURL": "url - Information about applying a function to a list of numbers. (We were unable to find such information in English. Feel free to skip this and any other URLs that are difficult.)", "MATH_ONLIST_OPERATOR_SUM": "dropdown - This computes the sum of the numeric elements in the list. For example, the sum of the list {1, 4} is 5.", "MATH_ONLIST_TOOLTIP_SUM": "tooltip - Please use the same term for 'sum' as in the previous message.", "MATH_ONLIST_OPERATOR_MIN": "dropdown - This finds the smallest (minimum) number in a list. For example, the smallest number in the list [-5, 0, 3] is -5.", "MATH_ONLIST_TOOLTIP_MIN": "tooltip - Please use the same term for 'min' or 'minimum' as in the previous message.", "MATH_ONLIST_OPERATOR_MAX": "dropdown - This finds the largest (maximum) number in a list. For example, the largest number in the list [-5, 0, 3] is 3.", "MATH_ONLIST_TOOLTIP_MAX": "tooltip", "MATH_ONLIST_OPERATOR_AVERAGE": "dropdown - This adds up all of the numbers in a list and divides the sum by the number of elements in the list. For example, the [https://en.wikipedia.org/wiki/Arithmetic_mean average] of the list [1, 2, 3, 4] is 2.5 (10/4).", "MATH_ONLIST_TOOLTIP_AVERAGE": "tooltip - See [https://en.wikipedia.org/wiki/Arithmetic_mean https://en.wikipedia.org/wiki/Arithmetic_mean] for more informatin.", "MATH_ONLIST_OPERATOR_MEDIAN": "dropdown - This finds the [https://en.wikipedia.org/wiki/Median median] of the numeric values in a list. For example, the median of the list {1, 2, 7, 12, 13} is 7.", "MATH_ONLIST_TOOLTIP_MEDIAN": "tooltip - See [https://en.wikipedia.org/wiki/Median median https://en.wikipedia.org/wiki/Median median] for more information.", "MATH_ONLIST_OPERATOR_MODE": "dropdown - This finds the most common numbers ([https://en.wikipedia.org/wiki/Mode_(statistics) modes]) in a list. For example, the modes of the list {1, 3, 9, 3, 9} are {3, 9}.", "MATH_ONLIST_TOOLTIP_MODE": "tooltip - See [https://en.wikipedia.org/wiki/Mode_(statistics) https://en.wikipedia.org/wiki/Mode_(statistics)] for more information.", "MATH_ONLIST_OPERATOR_STD_DEV": "dropdown - This finds the [https://en.wikipedia.org/wiki/Standard_deviation standard deviation] of the numeric values in a list.", "MATH_ONLIST_TOOLTIP_STD_DEV": "tooltip - See [https://en.wikipedia.org/wiki/Standard_deviation https://en.wikipedia.org/wiki/Standard_deviation] for more information.", "MATH_ONLIST_OPERATOR_RANDOM": "dropdown - This choose an element at random from a list. Each element is chosen with equal probability.", "MATH_ONLIST_TOOLTIP_RANDOM": "tooltip - Please use same term for 'random' as in previous entry.", "MATH_MODULO_HELPURL": "url - information about the modulo (remainder) operation.", "MATH_MODULO_TITLE": "block text - Title of block providing the remainder when dividing the first numerical input by the second. For example, the remainder of 10 divided by 3 is 1.\n\nParameters:\n* %1 - the dividend (10, in our example)\n* %2 - the divisor (3 in our example).", "MATH_MODULO_TOOLTIP": "tooltip - For example, the remainder of 10 divided by 3 is 1.", "MATH_CONSTRAIN_HELPURL": "url - Information about constraining a numeric value to be in a specific range. (The English URL is not ideal. Recall that translating URLs is the lowest priority.)", "MATH_CONSTRAIN_TITLE": "block text - The title of the block that '''constrain'''s (forces) a number to be in a given range. For example, if the number 150 is constrained to be between 5 and 100, the result will be 100. \n\nParameters:\n* %1 - the value to constrain (e.g., 150)\n* %2 - the minimum value (e.g., 5)\n* %3 - the maximum value (e.g., 100).", "MATH_CONSTRAIN_TOOLTIP": "tooltip - This compares a number ''x'' to a low value ''L'' and a high value ''H''. If ''x'' is less then ''L'', the result is ''L''. If ''x'' is greater than ''H'', the result is ''H''. Otherwise, the result is ''x''.", "MATH_RANDOM_INT_HELPURL": "url - Information about how computers generate random numbers.", "MATH_RANDOM_INT_TITLE": "block text - The title of the block that generates a random integer (whole number) in the specified range. For example, if the range is from 5 to 7, this returns 5, 6, or 7 with equal likelihood. %1 is a placeholder for the lower number, %2 is the placeholder for the larger number.", "MATH_RANDOM_INT_TOOLTIP": "tooltip - Return a random integer between two values specified as inputs. For example, if one input was 7 and another 9, any of the numbers 7, 8, or 9 could be produced.", "MATH_RANDOM_FLOAT_HELPURL": "url - Information about how computers generate random numbers (specifically, numbers in the range from 0 to just below 1).", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "block text - The title of the block that generates a random number greater than or equal to 0 and less than 1.", "MATH_RANDOM_FLOAT_TOOLTIP": "tooltip - Return a random fraction between 0 and 1. The value may be equal to 0 but must be less than 1.", "TEXT_TEXT_HELPURL": "url - Information about how computers represent text (sometimes referred to as ''string''s).", "TEXT_TEXT_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Text#Introduction https://code.google.com/p/blockly/wiki/Text#Introduction].", "TEXT_JOIN_HELPURL": "url - Information on concatenating/appending pieces of text.", "TEXT_JOIN_TITLE_CREATEWITH": "block text - See [https://code.google.com/p/blockly/wiki/Text#Text_creation https://code.google.com/p/blockly/wiki/Text#Text_creation].", "TEXT_JOIN_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Text#Text_creation create text with] for more information.", "TEXT_CREATE_JOIN_TITLE_JOIN": "block text - This is shown when the programmer wants to change the number of pieces of text being joined together. See [https://code.google.com/p/blockly/wiki/Text#Text_creation https://code.google.com/p/blockly/wiki/Text#Text_creation], specifically the last picture in the 'Text creation' section.", "TEXT_CREATE_JOIN_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Text#Text_creation https://code.google.com/p/blockly/wiki/Text#Text_creation], specifically the last picture in the 'Text creation' section.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "block text - See [https://code.google.com/p/blockly/wiki/Text#Text_creation https://code.google.com/p/blockly/wiki/Text#Text_creation], specifically the last picture in the 'Text creation' section.", "TEXT_APPEND_HELPURL": "url - This and the other text-related URLs are going to be hard to translate. As always, it is okay to leave untranslated or paste in the English-language URL. For these URLs, you might also consider a general URL about how computers represent text (such as the translation of [https://en.wikipedia.org/wiki/String_(computer_science) this Wikipedia page]).", "TEXT_APPEND_TO": "block input text - Message preceding the name of a variable to which text should be appended. [[File:blockly-append-text.png]]", "TEXT_APPEND_APPENDTEXT": "block input text - Message following the variable and preceding the piece of text that should be appended, as shown below. [[File:blockly-append-text.png]]", "TEXT_APPEND_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Text#Text_modification https://code.google.com/p/blockly/wiki/Text#Text_modification] for more information.\n\nParameters:\n* %1 - the name of the variable to which text should be appended", "TEXT_LENGTH_HELPURL": "url - Information about text on computers (usually referred to as 'strings').", "TEXT_LENGTH_TITLE": "block text - See [https://code.google.com/p/blockly/wiki/Text#Text_length https://code.google.com/p/blockly/wiki/Text#Text_length]. \n\nParameters:\n* %1 - the piece of text to take the length of", "TEXT_LENGTH_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Text#Text_length https://code.google.com/p/blockly/wiki/Text#Text_length].", "TEXT_ISEMPTY_HELPURL": "url - Information about empty pieces of text on computers (usually referred to as 'empty strings').", "TEXT_ISEMPTY_TITLE": "block text - See [https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text]. \n\nParameters:\n* %1 - the piece of text to test for emptiness", "TEXT_ISEMPTY_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text].", "TEXT_INDEXOF_HELPURL": "url - Information about finding a character in a piece of text.", "TEXT_INDEXOF_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Text#Finding_text https://code.google.com/p/blockly/wiki/Text#Finding_text].", "TEXT_INDEXOF_INPUT_INTEXT": "block text - Title of blocks allowing users to find text. See [https://code.google.com/p/blockly/wiki/Text#Finding_text https://code.google.com/p/blockly/wiki/Text#Finding_text]. [[File:Blockly-find-text.png]].", "TEXT_INDEXOF_OPERATOR_FIRST": "dropdown - See [https://code.google.com/p/blockly/wiki/Text#Finding_text https://code.google.com/p/blockly/wiki/Text#Finding_text]. [[File:Blockly-find-text.png]].", "TEXT_INDEXOF_OPERATOR_LAST": "dropdown - See [https://code.google.com/p/blockly/wiki/Text#Finding_text https://code.google.com/p/blockly/wiki/Text#Finding_text]. This would replace 'find first occurrence of text' below. (For more information on how common text is factored out of dropdown menus, see [https://translatewiki.net/wiki/Translating:Blockly#Drop-Down_Menus https://translatewiki.net/wiki/Translating:Blockly#Drop-Down_Menus)].) [[File:Blockly-find-text.png]].", "TEXT_INDEXOF_TAIL": "block text - Optional text to follow the rightmost block in a [https://code.google.com/p/blockly/wiki/Text#Finding_text https://code.google.com/p/blockly/wiki/Text#Finding_text in text ... find block] (after the 'a' in the below picture). This will be the empty string in most languages. [[File:Blockly-find-text.png]].", "TEXT_CHARAT_HELPURL": "url - Information about extracting characters (letters, number, symbols, etc.) from text.", "TEXT_CHARAT_INPUT_INTEXT": "block text - Appears before the piece of text from which a letter (or number, punctuation character, etc.) should be extracted, as shown below. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. [[File:Blockly-text-get.png]]", "TEXT_CHARAT_FROM_START": "dropdown - Indicates that the letter (or number, punctuation character, etc.) with the specified index should be obtained from the preceding piece of text. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. [[File:Blockly-text-get.png]]", "TEXT_CHARAT_FROM_END": "block text - Indicates that the letter (or number, punctuation character, etc.) with the specified index from the end of a given piece of text should be obtained. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. [[File:Blockly-text-get.png]]", "TEXT_CHARAT_FIRST": "block text - Indicates that the first letter of the following piece of text should be retrieved. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. [[File:Blockly-text-get.png]]", "TEXT_CHARAT_LAST": "block text - Indicates that the last letter (or number, punctuation mark, etc.) of the following piece of text should be retrieved. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. [[File:Blockly-text-get.png]]", "TEXT_CHARAT_RANDOM": "block text - Indicates that any letter (or number, punctuation mark, etc.) in the following piece of text should be randomly selected. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. [[File:Blockly-text-get.png]]", "TEXT_CHARAT_TAIL": "block text - Text that goes after the rightmost block/dropdown when getting a single letter from a piece of text, as in [https://blockly-demo.appspot.com/static/apps/code/index.html#3m23km these blocks] or shown below. For most languages, this will be blank. [[File:Blockly-text-get.png]]", "TEXT_CHARAT_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. [[File:Blockly-text-get.png]]", "TEXT_GET_SUBSTRING_TOOLTIP": "See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text].", "TEXT_GET_SUBSTRING_HELPURL": "url - Information about extracting characters from text. Reminder: urls are the lowest priority translations. Feel free to skip.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "block text - Precedes a piece of text from which a portion should be extracted. [[File:Blockly-get-substring.png]]", "TEXT_GET_SUBSTRING_START_FROM_START": "dropdown - Indicates that the following number specifies the position (relative to the start position) of the beginning of the region of text that should be obtained from the preceding piece of text. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. [[File:Blockly-get-substring.png]]", "TEXT_GET_SUBSTRING_START_FROM_END": "dropdown - Indicates that the following number specifies the position (relative to the end position) of the beginning of the region of text that should be obtained from the preceding piece of text. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. Note: If {{msg-Blockly|ORDINAL_NUMBER_SUFFIX}} is defined, it will automatically appear ''after'' this and any other [https://translatewiki.net/wiki/Translating:Blockly#Ordinal_numbers ordinal numbers] on this block. [[File:Blockly-get-substring.png]]", "TEXT_GET_SUBSTRING_START_FIRST": "block text - Indicates that a region starting with the first letter of the preceding piece of text should be extracted. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. [[File:Blockly-get-substring.png]]", "TEXT_GET_SUBSTRING_END_FROM_START": "dropdown - Indicates that the following number specifies the position (relative to the start position) of the end of the region of text that should be obtained from the preceding piece of text. See [ https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. [[File:Blockly-get-substring.png]]", "TEXT_GET_SUBSTRING_END_FROM_END": "dropdown - Indicates that the following number specifies the position (relative to the end position) of the end of the region of text that should be obtained from the preceding piece of text. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. [[File:Blockly-get-substring.png]]", "TEXT_GET_SUBSTRING_END_LAST": "block text - Indicates that a region ending with the last letter of the preceding piece of text should be extracted. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. [[File:Blockly-get-substring.png]]", "TEXT_GET_SUBSTRING_TAIL": "block text - Text that should go after the rightmost block/dropdown when [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text extracting a region of text]. In most languages, this will be the empty string. [[File:Blockly-get-substring.png]]", "TEXT_CHANGECASE_HELPURL": "url - Information about the case of letters (upper-case and lower-case).", "TEXT_CHANGECASE_TOOLTIP": "tooltip - Describes a block to adjust the case of letters. For more information on this block, see [https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case].", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "block text - Indicates that all of the letters in the following piece of text should be capitalized. If your language does not use case, you may indicate that this is not applicable to your language. For more information on this block, see [https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case].", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "block text - Indicates that all of the letters in the following piece of text should be converted to lower-case. If your language does not use case, you may indicate that this is not applicable to your language. For more information on this block, see [https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case].", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "block text - Indicates that the first letter of each of the following words should be capitalized and the rest converted to lower-case. If your language does not use case, you may indicate that this is not applicable to your language. For more information on this block, see [https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case].", "TEXT_TRIM_HELPURL": "url - Information about trimming (removing) text off the beginning and ends of pieces of text.", "TEXT_TRIM_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces].", "TEXT_TRIM_OPERATOR_BOTH": "dropdown - Removes spaces from the beginning and end of a piece of text. See [https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces]. Note that neither this nor the other options modify the original piece of text (that follows); the block just returns a version of the text without the specified spaces.", "TEXT_TRIM_OPERATOR_LEFT": "dropdown - Removes spaces from the beginning of a piece of text. See [https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces]. Note that in right-to-left scripts, this will remove spaces from the right side.", "TEXT_TRIM_OPERATOR_RIGHT": "dropdown - Removes spaces from the end of a piece of text. See [https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces]. Note that in right-to-left scripts, this will remove spaces from the left side.", "TEXT_PRINT_HELPURL": "url - Information about displaying text on computers.", "TEXT_PRINT_TITLE": "block text - Display the input on the screen. See [https://code.google.com/p/blockly/wiki/Text#Printing_text https://code.google.com/p/blockly/wiki/Text#Printing_text]. \n\nParameters:\n* %1 - the value to print", "TEXT_PRINT_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Text#Printing_text https://code.google.com/p/blockly/wiki/Text#Printing_text].", "TEXT_PROMPT_HELPURL": "url - Information about getting text from users.", "TEXT_PROMPT_TYPE_TEXT": "dropdown - Specifies that a piece of text should be requested from the user with the following message. See [https://code.google.com/p/blockly/wiki/Text#Printing_text https://code.google.com/p/blockly/wiki/Text#Printing_text].", "TEXT_PROMPT_TYPE_NUMBER": "dropdown - Specifies that a number should be requested from the user with the following message. See [https://code.google.com/p/blockly/wiki/Text#Printing_text https://code.google.com/p/blockly/wiki/Text#Printing_text].", "TEXT_PROMPT_TOOLTIP_NUMBER": "dropdown - Precedes the message with which the user should be prompted for a number. See [https://code.google.com/p/blockly/wiki/Text#Printing_text https://code.google.com/p/blockly/wiki/Text#Printing_text].", "TEXT_PROMPT_TOOLTIP_TEXT": "dropdown - Precedes the message with which the user should be prompted for some text. See [https://code.google.com/p/blockly/wiki/Text#Printing_text https://code.google.com/p/blockly/wiki/Text#Printing_text].", "LISTS_CREATE_EMPTY_HELPURL": "url - Information on empty lists.", "LISTS_CREATE_EMPTY_TITLE": "block text - See [https://code.google.com/p/blockly/wiki/Lists#create_empty_list https://code.google.com/p/blockly/wiki/Lists#create_empty_list].", "LISTS_CREATE_EMPTY_TOOLTIP": "block text - See [https://code.google.com/p/blockly/wiki/Lists#create_empty_list https://code.google.com/p/blockly/wiki/Lists#create_empty_list].", "LISTS_CREATE_WITH_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#create_list_with https://code.google.com/p/blockly/wiki/Lists#create_list_with].", "LISTS_CREATE_WITH_INPUT_WITH": "block text - See [https://code.google.com/p/blockly/wiki/Lists#create_list_with https://code.google.com/p/blockly/wiki/Lists#create_list_with].", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "block text - This appears in a sub-block when [https://code.google.com/p/blockly/wiki/Lists#changing_number_of_inputs changing the number of inputs in a ''''create list with'''' block].", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#changing_number_of_inputs https://code.google.com/p/blockly/wiki/Lists#changing_number_of_inputs].", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#changing_number_of_inputs https://code.google.com/p/blockly/wiki/Lists#changing_number_of_inputs].", "LISTS_REPEAT_HELPURL": "url - Information about [https://code.google.com/p/blockly/wiki/Lists#create_list_with creating a list with multiple copies of a single item].", "LISTS_REPEAT_TOOLTIP": "url - See [https://code.google.com/p/blockly/wiki/Lists#create_list_with creating a list with multiple copies of a single item].", "LISTS_REPEAT_TITLE": "block text - See [https://code.google.com/p/blockly/wiki/Lists#create_list_with https://code.google.com/p/blockly/wiki/Lists#create_list_with]. \n\nParameters:\n* %1 - the item (text) to be repeated\n* %2 - the number of times to repeat it", "LISTS_LENGTH_HELPURL": "url - Information about how the length of a list is computed (i.e., by the total number of elements, not the number of different elements).", "LISTS_LENGTH_TITLE": "block text - See [https://code.google.com/p/blockly/wiki/Lists#length_of https://code.google.com/p/blockly/wiki/Lists#length_of]. \n\nParameters:\n* %1 - the list whose length is desired", "LISTS_LENGTH_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#length_of https://code.google.com/p/blockly/wiki/Lists#length_of Blockly:Lists:length of].", "LISTS_IS_EMPTY_HELPURL": "url - See [https://code.google.com/p/blockly/wiki/Lists#is_empty https://code.google.com/p/blockly/wiki/Lists#is_empty].", "LISTS_IS_EMPTY_TITLE": "block text - See [https://code.google.com/p/blockly/wiki/Lists#is_empty https://code.google.com/p/blockly/wiki/Lists#is_empty]. \n\nParameters:\n* %1 - the list to test", "LISTS_TOOLTIP": "block tooltip - See [https://code.google.com/p/blockly/wiki/Lists#is_empty https://code.google.com/p/blockly/wiki/Lists#is_empty].", "LISTS_INLIST": "block text - Title of blocks operating on [https://code.google.com/p/blockly/wiki/Lists lists].", "LISTS_INDEX_OF_HELPURL": "url - See [https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List].", "LISTS_INDEX_OF_FIRST": "dropdown - See [https://code.google.com/p/blockly/wiki/Lists#Finding_Items_in_a_List Lists#Finding_Items_in_a_List]. [[File:Blockly-list-find.png]]", "LISTS_INDEX_OF_LAST": "dropdown - See [https://code.google.com/p/blockly/wiki/Lists#Finding_Items_in_a_List https://code.google.com/p/blockly/wiki/Lists#Finding_Items_in_a_List]. [[File:Blockly-list-find.png]]", "LISTS_INDEX_OF_TOOLTIP": "dropdown - See [https://code.google.com/p/blockly/wiki/Lists#Finding_Items_in_a_List https://code.google.com/p/blockly/wiki/Lists#Finding_Items_in_a_List]. [[File:Blockly-list-find.png]]", "LISTS_GET_INDEX_GET": "dropdown - Indicates that the user wishes to [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item get an item from a list] without removing it from the list.", "LISTS_GET_INDEX_GET_REMOVE": "dropdown - Indicates that the user wishes to [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item get and remove an item from a list], as opposed to merely getting it without modifying the list.", "LISTS_GET_INDEX_REMOVE": "dropdown - Indicates that the user wishes to [https://code.google.com/p/blockly/wiki/Lists#Removing_an_item remove an item from a list].", "LISTS_GET_INDEX_FROM_START": "dropdown - Indicates that an index relative to the front of the list should be used to [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item get and/or remove an item from a list]. Note: If {{msg-Blockly|ORDINAL_NUMBER_SUFFIX}} is defined, it will automatically appear ''after'' this number (and any other ordinal numbers on this block). See [[Translating:Blockly#Ordinal_numbers]] for more information on ordinal numbers in Blockly. [[File:Blockly-list-get-item.png]]", "LISTS_GET_INDEX_FROM_END": "dropdown - Indicates that an index relative to the end of the list should be used to [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item access an item in a list]. [[File:Blockly-list-get-item.png]]", "LISTS_GET_INDEX_FIRST": "dropdown - Indicates that the '''first''' item should be [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item accessed in a list]. [[File:Blockly-list-get-item.png]]", "LISTS_GET_INDEX_LAST": "dropdown - Indicates that the '''last''' item should be [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item accessed in a list]. [[File:Blockly-list-get-item.png]]", "LISTS_GET_INDEX_RANDOM": "dropdown - Indicates that a '''random''' item should be [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item accessed in a list]. [[File:Blockly-list-get-item.png]]", "LISTS_GET_INDEX_TAIL": "block text - Text that should go after the rightmost block/dropdown when [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item accessing an item from a list]. In most languages, this will be the empty string. [[File:Blockly-list-get-item.png]]", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for more information.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for more information.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for more information.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for more information.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for more information.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for '# from start'.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for '# from end'.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for 'first'.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for 'last'.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for 'random'.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for '# from start'.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for '# from end'.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for 'first'.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for 'last'.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for 'random'.", "LISTS_SET_INDEX_HELPURL": "url - Information about putting items in lists.", "LISTS_SET_INDEX_SET": "block text - [https://code.google.com/p/blockly/wiki/Lists#in_list_..._set Replaces an item in a list]. [[File:Blockly-in-list-set-insert.png]]", "LISTS_SET_INDEX_INSERT": "block text - [https://code.google.com/p/blockly/wiki/Lists#in_list_..._insert_at Inserts an item into a list]. [[File:Blockly-in-list-set-insert.png]]", "LISTS_SET_INDEX_INPUT_TO": "block text - The word(s) after the position in the list and before the item to be set/inserted. [[File:Blockly-in-list-set-insert.png]]", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the 'get' block, the idea is the same for the 'set' block).", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the 'get' block, the idea is the same for the 'set' block).", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the 'get' block, the idea is the same for the 'set' block).", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the 'get' block, the idea is the same for the 'set' block).", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the 'get' block, the idea is the same for the 'set' block).", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the 'get' block, the idea is the same for the 'insert' block).", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the 'get' block, the idea is the same for the 'insert' block).", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the 'get' block, the idea is the same for the 'insert' block).", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the 'get' block, the idea is the same for the 'insert' block).", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the 'get' block, the idea is the same for the 'insert' block).", "LISTS_GET_SUBLIST_HELPURL": "url - Information describing extracting a sublist from an existing list.", "LISTS_GET_SUBLIST_START_FROM_START": "dropdown - Indicates that an index relative to the front of the list should be used to specify the beginning of the range from which to [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist get a sublist]. [[File:Blockly-get-sublist.png]] Note: If {{msg-Blockly|ORDINAL_NUMBER_SUFFIX}} is defined, it will automatically appear ''after'' this number (and any other ordinal numbers on this block). See [[Translating:Blockly#Ordinal_numbers]] for more information on ordinal numbers in Blockly.", "LISTS_GET_SUBLIST_START_FROM_END": "dropdown - Indicates that an index relative to the end of the list should be used to specify the beginning of the range from which to [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist get a sublist].", "LISTS_GET_SUBLIST_START_FIRST": "dropdown - Indicates that the [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist sublist to extract] should begin with the list's first item.", "LISTS_GET_SUBLIST_END_FROM_START": "dropdown - Indicates that an index relative to the front of the list should be used to specify the end of the range from which to [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist get a sublist]. [[File:Blockly-get-sublist.png]]", "LISTS_GET_SUBLIST_END_FROM_END": "dropdown - Indicates that an index relative to the end of the list should be used to specify the end of the range from which to [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist get a sublist]. [[File:Blockly-get-sublist.png]]", "LISTS_GET_SUBLIST_END_LAST": "dropdown - Indicates that the '''last''' item in the given list should be [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist the end of the selected sublist]. [[File:Blockly-get-sublist.png]]", "LISTS_GET_SUBLIST_TAIL": "block text - This appears in the rightmost position ('tail') of the sublist block, as described at [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist]. In English and most other languages, this is the empty string. [[File:Blockly-get-sublist.png]]", "LISTS_GET_SUBLIST_TOOLTIP": "tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist] for more information. [[File:Blockly-get-sublist.png]]", "ORDINAL_NUMBER_SUFFIX": "grammar - Text that follows an ordinal number (a number that indicates position relative to other numbers). In most languages, such text appears before the number, so this should be blank. An exception is Hungarian. See [[Translating:Blockly#Ordinal_numbers]] for more information.", "VARIABLES_GET_HELPURL": "url - Information about ''variables'' in computer programming. Consider using your language's translation of [https://en.wikipedia.org/wiki/Variable_(computer_science) https://en.wikipedia.org/wiki/Variable_(computer_science)], if it exists.", "VARIABLES_GET_TITLE": "block text - This precedes the name of a variable when getting its values. In most (all?) languages, it should be the empty string. If unsure, ask yourself if any word should go before 'x' in the expression 'x + 1'.", "VARIABLES_GET_TAIL": "block text - This follows the name of a variable. In most (all?) languages, it should be the empty string. If unsure, ask yourself if any word should go after 'x' in the expression 'x + 1'.", "VARIABLES_GET_TOOLTIP": "tooltip - This gets the value of the named variable without modifying it.", "VARIABLES_GET_CREATE_SET": "context menu - Selecting this creates a block to set (change) the value of this variable. \n\nParameters:\n* %1 - the name of the variable.", "VARIABLES_SET_HELPURL": "url - Information about ''variables'' in computer programming. Consider using your language's translation of [https://en.wikipedia.org/wiki/Variable_(computer_science) https://en.wikipedia.org/wiki/Variable_(computer_science)], if it exists.", "VARIABLES_SET_TITLE": "block text - The imperative or infinitive form of the verb 'set', as in: '''set''' [the value of] x to 7.", "VARIABLES_SET_TAIL": "block text - The word that goes after the name of the variable and before its new value in: set [the value of] x '''to''' 7.", "VARIABLES_SET_TOOLTIP": "tooltip - This initializes or changes the value of the named variable.", "VARIABLES_SET_CREATE_GET": "context menu - Selecting this creates a block to get (change) the value of this variable.\n\nParameters:\n* %1 - the name of the variable.", "PROCEDURES_DEFNORETURN_HELPURL": "url - Information about defining [https://en.wikipedia.org/wiki/Procedure_(computer_science) functions] that do not have return values.", "PROCEDURES_DEFNORETURN_TITLE": "block text - This precedes the name of the procedure when defining it. See [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#c84aoc this sample procedure definition].", "PROCEDURES_DEFNORETURN_PROCEDURE": "default name - This acts as a placeholder for the name of a function on a function definition block, as shown on [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#w7cfju this block]. The user will replace it with the function's name.", "PROCEDURES_BEFORE_PARAMS": "block text - This precedes the list of parameters to a function. See [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#6ot5y5 this sample function with parameters].", "PROCEDURES_DEFNORETURN_DO": "block text - This appears next to the function's 'body', the blocks that should be run when the function is called, as shown in [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#c84aoc this sample procedure definition].", "PROCEDURES_DEFNORETURN_TOOLTIP": "tooltip", "PROCEDURES_DEFRETURN_HELPURL": "url - Information about defining [https://en.wikipedia.org/wiki/Procedure_(computer_science) functions] that have return values.", "PROCEDURES_DEFRETURN_RETURN": "block text - This imperative or infinite verb precedes the value that is used as the return value (output) of this function. See [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#6ot5y5 this sample function that returns a value].", "PROCEDURES_DEFRETURN_TOOLTIP": "tooltip", "PROCEDURES_DEF_DUPLICATE_WARNING": "alert - The user has created a function with two parameters that have the same name. Every parameter must have a different name.", "PROCEDURES_CALLNORETURN_HELPURL": "url - Information about calling [https://en.wikipedia.org/wiki/Procedure_(computer_science) functions] that do not return values.", "PROCEDURES_CALLNORETURN_CALL": "block text - In most (if not all) languages, this will be the empty string. It precedes the name of the function that should be run. See, for example, the 'draw square' block in [https://blockly-demo.appspot.com/static/apps/turtle/index.html#ztz96g].", "PROCEDURES_CALLNORETURN_TOOLTIP": "tooltip - This block causes the body (blocks inside) of the named function definition to be run.", "PROCEDURES_CALLRETURN_HELPURL": "url - Information about calling [https://en.wikipedia.org/wiki/Procedure_(computer_science) functions] that return values.", "PROCEDURES_CALLRETURN_TOOLTIP": "tooltip - This block causes the body (blocks inside) of the named function definition to be run.\n\nParameters:\n* %1 - the name of the function.", "PROCEDURES_MUTATORCONTAINER_TITLE": "block text - This text appears on a block in a window that appears when the user clicks on the plus sign or star on a function definition block. It refers to the set of parameters (referred to by the simpler term 'inputs') to the function. See [[Translating:Blockly#function_definitions]].", "PROCEDURES_MUTATORARG_TITLE": "block text - This text appears on a block in a window that appears when the user clicks on the plus sign or star on a function definition block]. It appears on the block for adding an individual parameter (referred to by the simpler term 'inputs') to the function. See [[Translating:Blockly#function_definitions]].", "PROCEDURES_HIGHLIGHT_DEF": "context menu - This appears on the context menu for function calls. Selecting it causes the corresponding function definition to be highlighted (as shown at [[Translating:Blockly#context_menus]].", "PROCEDURES_CREATE_DO": "context menu - This appears on the context menu for function definitions. Selecting it creates a block to call the function. \n\nParameters:\n* %1 - the name of the function.", "PROCEDURES_IFRETURN_TOOLTIP": "tooltip - If the first value is true, this causes the second value to be returned immediately from the enclosing function.", "PROCEDURES_IFRETURN_WARNING": "warning - This appears if the user tries to use this block outside of a function definition.", "CONTEXT_BLOCK_COPY": "Context Menu Copy", "CONTEXT_BLOCK_PASTE": "Context Menu Paste" } ================================================ FILE: extern/blockly/msg/json/ro.json ================================================ { "@metadata": [], "VARIABLES_DEFAULT_NAME": "element", "DUPLICATE_BLOCK": "Duplicati", "ADD_COMMENT": "Adaugă un comentariu", "REMOVE_COMMENT": "Elimină comentariu", "EXTERNAL_INPUTS": "Intrări Externe", "INLINE_INPUTS": "Intrari de Linie", "DELETE_BLOCK": "Șterge Bloc", "DELETE_X_BLOCKS": "Ștergeți %1 Blocuri", "COLLAPSE_BLOCK": "Restrange blocul", "COLLAPSE_ALL": "Restrange blocurile", "EXPAND_BLOCK": "Extinde bloc", "EXPAND_ALL": "Extinde blocuri", "DISABLE_BLOCK": "Dezactivaţi bloc", "ENABLE_BLOCK": "Permite bloc", "HELP": "Ajutor", "CHANGE_VALUE_TITLE": "Schimbaţi valoarea:", "NEW_VARIABLE": "Variabilă nouă...", "NEW_VARIABLE_TITLE": "Noul nume de variabilă:", "RENAME_VARIABLE": "Redenumirea variabilei...", "RENAME_VARIABLE_TITLE": "Redenumeşte toate variabilele '%1' în:", "COLOUR_PICKER_HELPURL": "https://ro.wikipedia.org/wiki/Culoare", "COLOUR_PICKER_TOOLTIP": "Alege o culoare din paleta de culori.", "COLOUR_RANDOM_TITLE": "culoare aleatorie", "COLOUR_RANDOM_TOOLTIP": "Alege o culoare la întâmplare.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "colorează cu", "COLOUR_RGB_RED": "roşu", "COLOUR_RGB_GREEN": "verde", "COLOUR_RGB_BLUE": "albastru", "COLOUR_RGB_TOOLTIP": "Creează o culoare cu suma specificată de roşu, verde şi albastru. Toate valorile trebuie să fie între 0 şi 100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "amestec", "COLOUR_BLEND_COLOUR1": "culoare 1", "COLOUR_BLEND_COLOUR2": "culoare 2", "COLOUR_BLEND_RATIO": "Raport", "COLOUR_BLEND_TOOLTIP": "Amestecă două culori cu un raport dat (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "repetă de %1 ori", "CONTROLS_REPEAT_TITLE_REPEAT": "repetă", "CONTROLS_REPEAT_TITLE_TIMES": "ori", "CONTROLS_REPEAT_INPUT_DO": "fă", "CONTROLS_REPEAT_TOOLTIP": "Face unele afirmaţii de mai multe ori.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "repetă în timp ce", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "Repetaţi până când", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "În timp ce o valoare este adevărat, atunci face unele declaraţii.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "În timp ce o valoare este adevărat, atunci face unele declaraţii.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Cu variablia %1 ia o valoare din numărul început la numărul final, numara in intervalul specificat, apoi face blocurile specificate.", "CONTROLS_FOR_INPUT_WITH": "numără cu", "CONTROLS_FOR_INPUT_FROM_TO_BY": "de la %1 la %2 prin %3", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each for each block", "CONTROLS_FOREACH_INPUT_ITEM": "pentru fiecare element", "CONTROLS_FOREACH_INPUT_INLIST": "în listă", "CONTROLS_FOREACH_TOOLTIP": "Pentru fiecare element din listă, setaţi variabila '%1' ca valoarea elementului, şi apoi faceţi unele declaraţii.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "ieşi din bucla", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "continuă cu următoarea iterație a buclei", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Ieși din bucla care conţine.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Sari peste restul aceastei bucle, şi continuă cu urmatoarea iteratie.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Avertisment: Acest bloc pote fi utilizat numai în interiorul unei bucle.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "Dacă o valoare este adevărată, atunci fa unele declaraţii.", "CONTROLS_IF_TOOLTIP_2": "Dacă o valoare este adevărat, atunci face primul bloc de declaraţii. Altfel, face al doilea bloc de declaraţii.", "CONTROLS_IF_TOOLTIP_3": "Dacă prima valoare este adevărat, atunci face primul bloc de declaraţii. Altfel, dacă a doua valoare este adevărat, face al doilea bloc de declaraţii.", "CONTROLS_IF_TOOLTIP_4": "Dacă prima valoare este adevărat, atunci face primul bloc de declaraţii. Altfel, dacă a doua valoare este adevărat, face al doilea bloc de declaraţii. În cazul în care niciuna din valorilor nu este adevărat, face ultimul bloc de declaraţii.", "CONTROLS_IF_MSG_IF": "dacă", "CONTROLS_IF_MSG_ELSEIF": "altfel dacă", "CONTROLS_IF_MSG_ELSE": "altfel", "CONTROLS_IF_IF_TOOLTIP": "Adaugă, elimină sau reordonează secţiuni pentru a reconfigura acest bloc if.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Adăugaţi o condiţie in blocul if.", "CONTROLS_IF_ELSE_TOOLTIP": "Adauga o stare finala, cuprinde toata conditia din blocul if.", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "Returnează adevărat dacă ambele intrări sunt egale.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Returnează adevărat daca cele două intrări nu sunt egale.", "LOGIC_COMPARE_TOOLTIP_LT": "Returnează adevărat dacă prima intrare este mai mică decât a doua intrare.", "LOGIC_COMPARE_TOOLTIP_LTE": "Returnează adevărat dacă prima intrare este mai mică sau egală cu a doua intrare.", "LOGIC_COMPARE_TOOLTIP_GT": "Returnează adevărat dacă prima intrare este mai mare decât a doua intrare.", "LOGIC_COMPARE_TOOLTIP_GTE": "Returnează adevărat dacă prima intrare este mai mare sau egală cu a doua intrare.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Returnează adevărat daca ambele intrări sunt adevărate.", "LOGIC_OPERATION_AND": "şi", "LOGIC_OPERATION_TOOLTIP_OR": "Returnează adevărat dacă cel puţin una din intrări este adevărată.", "LOGIC_OPERATION_OR": "sau", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "non %1", "LOGIC_NEGATE_TOOLTIP": "Returnează adevărat dacă intrarea este falsă. Returnează fals dacă intrarea este adevărată.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "adevărat", "LOGIC_BOOLEAN_FALSE": "fals", "LOGIC_BOOLEAN_TOOLTIP": "Returnează adevărat sau fals.", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "nul", "LOGIC_NULL_TOOLTIP": "returnează nul.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "dacă este adevărat", "LOGIC_TERNARY_IF_FALSE": "dacă este fals", "LOGIC_TERNARY_TOOLTIP": "Verifică condiţia din \"test\". Dacă condiţia este adevărată, returnează valoarea \"în cazul în care adevărat\"; în caz contrar întoarce valoarea \"în cazul în care e fals\".", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "Un număr.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "×", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tg", "MATH_TRIG_ASIN": "arcsin", "MATH_TRIG_ACOS": "arccos", "MATH_TRIG_ATAN": "arctg", "MATH_ARITHMETIC_HELPURL": "https://ro.wikipedia.org/wiki/Aritmetic%C4%83", "MATH_ARITHMETIC_TOOLTIP_ADD": "Returnează suma a două numere.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Returneaza diferenţa dintre cele două numere.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Returnează produsul celor două numere.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Returnează câtul celor două numere.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Returneaza numărul rezultat prin ridicarea primului număr la puterea celui de-al doilea.", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "rădăcina pătrată", "MATH_SINGLE_TOOLTIP_ROOT": "Returnează rădăcina pătrată a unui număr.", "MATH_SINGLE_OP_ABSOLUTE": "absolută", "MATH_SINGLE_TOOLTIP_ABS": "Returnează valoarea absolută a unui număr.", "MATH_SINGLE_TOOLTIP_NEG": "Returnează negaţia unui număr.", "MATH_SINGLE_TOOLTIP_LN": "Întoarce logaritmul natural al unui număr.", "MATH_SINGLE_TOOLTIP_LOG10": "Returnează logaritmul în baza 10 a unui număr.", "MATH_SINGLE_TOOLTIP_EXP": "Returnează e la puterea unui număr.", "MATH_SINGLE_TOOLTIP_POW10": "Returnează 10 la puterea unui număr.", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "Întoarce cosinusul unui grad (nu radianul).", "MATH_TRIG_TOOLTIP_COS": "Întoarce cosinusul unui grad (nu radianul).", "MATH_TRIG_TOOLTIP_TAN": "Întoarce tangenta unui grad (nu radianul).", "MATH_TRIG_TOOLTIP_ASIN": "Returnează arcsinusul unui număr.", "MATH_TRIG_TOOLTIP_ACOS": "Returnează arccosinusul unui număr.", "MATH_TRIG_TOOLTIP_ATAN": "Returnează arctangenta unui număr.", "MATH_CONSTANT_HELPURL": "https://ro.wikipedia.org/wiki/Constant%C4%83_matematic%C4%83", "MATH_CONSTANT_TOOLTIP": "Întoarcă una din constantele comune: π (3.141...), e (2.718...), φ (1,618...), sqrt(2) (1.414...), sqrt(½) (0.707...) sau ∞ (infinitate).", "MATH_IS_EVEN": "este par", "MATH_IS_ODD": "este impar", "MATH_IS_PRIME": "este prim", "MATH_IS_WHOLE": "este întreg", "MATH_IS_POSITIVE": "este pozitiv", "MATH_IS_NEGATIVE": "este negativ", "MATH_IS_DIVISIBLE_BY": "este divizibil cu", "MATH_IS_TOOLTIP": "Verifică dacă un număr este un par, impar, prim, întreg, pozitiv, negativ, sau dacă este divizibil cu un anumit număr. Returnează true sau false.", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "schimbă", "MATH_CHANGE_INPUT_BY": "de", "MATH_CHANGE_TOOLTIP": "Adaugă un număr variabilei '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Rotunjirea unui număr în sus sau în jos.", "MATH_ROUND_OPERATOR_ROUND": "rotund", "MATH_ROUND_OPERATOR_ROUNDUP": "rotunjește în sus", "MATH_ROUND_OPERATOR_ROUNDDOWN": "rotunjit", "MATH_ONLIST_OPERATOR_SUM": "suma listei", "MATH_ONLIST_TOOLTIP_SUM": "Returnează suma tuturor numerelor din lista.", "MATH_ONLIST_OPERATOR_MIN": "minimul listei", "MATH_ONLIST_TOOLTIP_MIN": "Returnează cel mai mic număr din listă.", "MATH_ONLIST_OPERATOR_MAX": "maximul listei", "MATH_ONLIST_TOOLTIP_MAX": "Întoarce cel mai mare număr din listă.", "MATH_ONLIST_OPERATOR_AVERAGE": "media listei", "MATH_ONLIST_TOOLTIP_AVERAGE": "Întoarce media (aritmetică) a valorilor numerice în listă.", "MATH_ONLIST_OPERATOR_MEDIAN": "media listei", "MATH_ONLIST_TOOLTIP_MEDIAN": "Întoarce numărul median în listă.", "MATH_ONLIST_OPERATOR_MODE": "moduri de listă", "MATH_ONLIST_TOOLTIP_MODE": "Returnează o listă cu cel(e) mai frecvent(e) element(e) din listă.", "MATH_ONLIST_OPERATOR_STD_DEV": "deviația standard a listei", "MATH_ONLIST_TOOLTIP_STD_DEV": "Întoarce deviația standard a listei.", "MATH_ONLIST_OPERATOR_RANDOM": "element aleatoriu din lista", "MATH_ONLIST_TOOLTIP_RANDOM": "Returnează un element aleatoriu din listă.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "restul la %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Întoarce restul din împărţirea celor două numere.", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "constrânge %1 redus %2 ridicat %3", "MATH_CONSTRAIN_TOOLTIP": "Constrânge un număr să fie între limitele specificate (inclusiv).", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "un număr întreg aleator de la %1 la %2", "MATH_RANDOM_INT_TOOLTIP": "Returnează un număr întreg aleator aflat între cele două limite specificate, inclusiv.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "fracții aleatorii", "MATH_RANDOM_FLOAT_TOOLTIP": "Returnează o fracţie aleatoare între 0.0 (inclusiv) si 1.0 (exclusiv).", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "O literă, cuvânt sau linie de text.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "crează text cu", "TEXT_JOIN_TOOLTIP": "Creaţi o bucată de text prin unirea oricărui număr de elemente.", "TEXT_CREATE_JOIN_TITLE_JOIN": "alăturaţi-vă", "TEXT_CREATE_JOIN_TOOLTIP": "Adaugă, elimină sau reordonează secțiuni ca să reconfigureze blocul text.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Adaugă un element în text.", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "la", "TEXT_APPEND_APPENDTEXT": "Adăugaţi text", "TEXT_APPEND_TOOLTIP": "Adăugaţi text la variabila '%1'.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "lungime de %1", "TEXT_LENGTH_TOOLTIP": "Returnează numărul de litere (inclusiv spaţiile) în textul furnizat.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 este gol", "TEXT_ISEMPTY_TOOLTIP": "Returnează adevărat dacă textul furnizat este gol.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Returnează indicele primei/ultimei apariţii din primul text în al doilea text. Returnează 0 dacă textul nu este găsit.", "TEXT_INDEXOF_INPUT_INTEXT": "în text", "TEXT_INDEXOF_OPERATOR_FIRST": "găseşte prima apariţie a textului", "TEXT_INDEXOF_OPERATOR_LAST": "găseşte ultima apariţie a textului", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "în text", "TEXT_CHARAT_FROM_START": "obtine litera #", "TEXT_CHARAT_FROM_END": "obţine litera # de la sfârșit", "TEXT_CHARAT_FIRST": "obţine prima litera", "TEXT_CHARAT_LAST": "obţine o litera oarecare", "TEXT_CHARAT_RANDOM": "obtine o litera oarecare", "TEXT_CHARAT_TOOLTIP": "Returnează litera la poziția specificată.", "TEXT_GET_SUBSTRING_TOOLTIP": "Returnează o anumită parte din text.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "în text", "TEXT_GET_SUBSTRING_START_FROM_START": "obține subșir de la litera #", "TEXT_GET_SUBSTRING_START_FROM_END": "obține un subșir de la litera # de la sfârșit", "TEXT_GET_SUBSTRING_START_FIRST": "obţine un subșir de la prima literă", "TEXT_GET_SUBSTRING_END_FROM_START": "la litera #", "TEXT_GET_SUBSTRING_END_FROM_END": "la litera # de la sfarsit", "TEXT_GET_SUBSTRING_END_LAST": "la ultima literă", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Întoarce o copie a textului într-un caz diferit.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "la MAJUSCULE", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "la litere mici", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "către Titlul de caz", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Returnează o copie a textului fără spațiile de la unul sau ambele capete.", "TEXT_TRIM_OPERATOR_BOTH": "taie spațiile de pe ambele părți", "TEXT_TRIM_OPERATOR_LEFT": "tăiaţi spațiile din partea stângă", "TEXT_TRIM_OPERATOR_RIGHT": "taie spațiile din partea dreaptă", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "imprimare %1", "TEXT_PRINT_TOOLTIP": "Afișează textul specificat, numărul sau altă valoare.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "solicită pentru text cu mesaj", "TEXT_PROMPT_TYPE_NUMBER": "solicită pentru număr cu mesaj", "TEXT_PROMPT_TOOLTIP_NUMBER": "Solicită utilizatorul pentru un număr.", "TEXT_PROMPT_TOOLTIP_TEXT": "Solicită utilizatorul pentru text.", "LISTS_CREATE_EMPTY_HELPURL": "https://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "creează listă goală", "LISTS_CREATE_EMPTY_TOOLTIP": "Returnează o listă, de lungime 0, care nu conţine înregistrări de date", "LISTS_CREATE_WITH_TOOLTIP": "Creaţi o listă cu orice număr de elemente.", "LISTS_CREATE_WITH_INPUT_WITH": "creează listă cu", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "listă", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Adaugă, elimină sau reordonează secţiuni ca să reconfiguraţi aceste blocuri de listă.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Adăugaţi un element la listă.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "Creează o listă alcătuită dintr-o anumită valoare repetată de numărul specificat de ori.", "LISTS_REPEAT_TITLE": "creaza lista cu %1 elemente repetate de %2 ori", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "lungime de %1", "LISTS_LENGTH_TOOLTIP": "Returnează lungimea unei liste.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 este gol", "LISTS_TOOLTIP": "Returnează adevărat dacă lista este goală.", "LISTS_INLIST": "în listă", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "Găseşte prima apariţie a elementului", "LISTS_INDEX_OF_LAST": "găseşte ultima apariţie a elementului", "LISTS_INDEX_OF_TOOLTIP": "Returneaza indexul de la prima/ultima aparitie a elementuli din lista. Returneaza 0 daca textul nu este gasit.", "LISTS_GET_INDEX_GET": "obţine", "LISTS_GET_INDEX_GET_REMOVE": "obţine şi elimină", "LISTS_GET_INDEX_REMOVE": "elimină", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# de la sfârșit", "LISTS_GET_INDEX_FIRST": "primul", "LISTS_GET_INDEX_LAST": "ultimul", "LISTS_GET_INDEX_RANDOM": "aleator", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Returneaza elementul la poziţia specificată într-o listă. #1 este primul element.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Returneaza elementul la poziţia specificată într-o listă. #1 este ultimul element.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Returnează primul element dintr-o listă.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Returnează ultimul element într-o listă.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Returneaza un element aleatoriu într-o listă.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Elimină şi returneaza elementul la poziţia specificată într-o listă. #1 este primul element.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Elimină şi returneaza elementul la poziţia specificată într-o listă. #1 este ultimul element.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Elimină şi returnează primul element într-o listă.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Elimină şi returnează ultimul element într-o listă.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Elimină şi returnează un element aleatoriu într-o listă.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Elimină elementul la poziţia specificată într-o listă. #1 este primul element.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Elimină elementul la poziţia specificată într-o listă. #1 este ultimul element.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Elimină primul element într-o listă.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Elimină ultimul element într-o listă.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Elimină un element aleatoriu într-o listă.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "seteaza", "LISTS_SET_INDEX_INSERT": "introduceţi la", "LISTS_SET_INDEX_INPUT_TO": "ca", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Setează elementul la poziţia specificată într-o listă. #1 este primul element.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Setează elementul la poziţia specificată într-o listă. #1 este ultimul element.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Setează primul element într-o listă.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Setează ultimul element într-o listă.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Setează un element aleator într-o listă.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Inserează elementul la poziţia specificată într-o listă. #1 este primul element.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Inserează elementul la poziţia specificată într-o listă. #1 este ultimul element.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Inserează elementul la începutul unei liste.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Adăugă elementul la sfârşitul unei liste.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Inserează elementul aleatoriu într-o listă.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "obţine sub-lista de la #", "LISTS_GET_SUBLIST_START_FROM_END": "obţine sub-lista de la # de la sfârşitul", "LISTS_GET_SUBLIST_START_FIRST": "obţine sub-lista de la primul", "LISTS_GET_SUBLIST_END_FROM_START": "la #", "LISTS_GET_SUBLIST_END_FROM_END": "la # de la sfarsit", "LISTS_GET_SUBLIST_END_LAST": "la ultima", "LISTS_GET_SUBLIST_TOOLTIP": "Creează o copie a porţiunii specificate dintr-o listă.", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TOOLTIP": "Returnează valoarea acestei variabile.", "VARIABLES_GET_CREATE_SET": "Crează 'set %1'", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "seteaza", "VARIABLES_SET_TAIL": "la", "VARIABLES_SET_TOOLTIP": "Setează această variabilă sa fie egală la intrare.", "VARIABLES_SET_CREATE_GET": "Crează 'get %1'", "PROCEDURES_DEFNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFNORETURN_TITLE": "la", "PROCEDURES_DEFNORETURN_PROCEDURE": "fă ceva", "PROCEDURES_BEFORE_PARAMS": "cu:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Crează o funcţie cu nici o ieşire.", "PROCEDURES_DEFRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFRETURN_RETURN": "returnează", "PROCEDURES_DEFRETURN_TOOLTIP": "Creează o funcţie cu o ieşire.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Atenţie: Această funcţie are parametri duplicaţi.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_TOOLTIP": "Executați funcția '%1 'definită de utilizator.", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Executați funcția '%1 'definită de utilizator şi folosiţi producţia sa.", "PROCEDURES_MUTATORCONTAINER_TITLE": "intrări", "PROCEDURES_MUTATORARG_TITLE": "nume de intrare:", "PROCEDURES_HIGHLIGHT_DEF": "Evidenţiază definiţia funcţiei", "PROCEDURES_CREATE_DO": "Creaţi '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Dacă o valoare este adevărată, atunci returnează valoarea a doua.", "PROCEDURES_IFRETURN_WARNING": "Avertisment: Acest bloc poate fi utilizat numai în definiţia unei funcţii." } ================================================ FILE: extern/blockly/msg/json/ru.json ================================================ { "@metadata": { "authors": [ "Espertus", "MS", "Okras" ] }, "VARIABLES_DEFAULT_NAME": "элемент", "DUPLICATE_BLOCK": "Скопировать", "ADD_COMMENT": "Добавить комментарий", "REMOVE_COMMENT": "Удалить комментарий", "EXTERNAL_INPUTS": "Вставки снаружи", "INLINE_INPUTS": "Вставки внутри", "DELETE_BLOCK": "Удалить блок", "DELETE_X_BLOCKS": "Удалить %1 блоков", "COLLAPSE_BLOCK": "Свернуть блок", "COLLAPSE_ALL": "Свернуть блоки", "EXPAND_BLOCK": "Развернуть блок", "EXPAND_ALL": "Развернуть блоки", "DISABLE_BLOCK": "Отключить блок", "ENABLE_BLOCK": "Включить блок", "HELP": "Справка", "CHANGE_VALUE_TITLE": "Измените значение:", "NEW_VARIABLE": "Новая переменная…", "NEW_VARIABLE_TITLE": "Имя новой переменной:", "RENAME_VARIABLE": "Переименовать переменную…", "RENAME_VARIABLE_TITLE": "Переименовать все переменные '%1' в:", "COLOUR_PICKER_HELPURL": "https://ru.wikipedia.org/wiki/Цвет", "COLOUR_PICKER_TOOLTIP": "Выберите цвет из палитры.", "COLOUR_RANDOM_TITLE": "случайный цвет", "COLOUR_RANDOM_TOOLTIP": "Выбирает цвет случайным образом.", "COLOUR_RGB_TITLE": "цвет из", "COLOUR_RGB_RED": "красного", "COLOUR_RGB_GREEN": "зелёного", "COLOUR_RGB_BLUE": "синего", "COLOUR_RGB_TOOLTIP": "Создаёт цвет с указанной пропорцией красного, зеленого и синего. Все значения должны быть между 0 и 100.", "COLOUR_BLEND_TITLE": "смешать", "COLOUR_BLEND_COLOUR1": "цвет 1", "COLOUR_BLEND_COLOUR2": "цвет 2", "COLOUR_BLEND_RATIO": "доля цвета 1", "COLOUR_BLEND_TOOLTIP": "Смешивает два цвета в заданном соотношении (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://ru.wikipedia.org/wiki/Цикл_(программирование)", "CONTROLS_REPEAT_TITLE": "повторить %1 раз", "CONTROLS_REPEAT_TITLE_REPEAT": "повторить", "CONTROLS_REPEAT_TITLE_TIMES": "раз", "CONTROLS_REPEAT_INPUT_DO": "выполнить", "CONTROLS_REPEAT_TOOLTIP": "Выполняет команды несколько раз.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "повторять, пока", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "повторять, пока не", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Пока значение истинно, выполняет команды.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Пока значение ложно, выполняет команды", "CONTROLS_FOR_TOOLTIP": "Присваивает переменной %1 значения от начального до конечного с заданным шагом и выполняет указанные команды.", "CONTROLS_FOR_INPUT_WITH": "цикл по", "CONTROLS_FOR_INPUT_FROM_TO_BY": "от %1 до %2 с шагом %3", "CONTROLS_FOREACH_INPUT_ITEM": "для каждого элемента", "CONTROLS_FOREACH_INPUT_INLIST": "в списке", "CONTROLS_FOREACH_TOOLTIP": "Для каждого элемента в списке, присваивает переменной '%1' значение элемента и выполняет указанные команды.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "выйти из цикла", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "перейти к следующему шагу цикла", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Прерывает этот цикл.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Пропускает остаток цикла и переходит к следующему шагу.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Предупреждение: этот блок может использоваться только внутри цикла.", "CONTROLS_IF_TOOLTIP_1": "Если условие истинно, выполняет команды.", "CONTROLS_IF_TOOLTIP_2": "Если условие истинно, выполняет первый блок команд. Иначе выполняется второй блок команд.", "CONTROLS_IF_TOOLTIP_3": "Если первое условие истинно, то выполняет первый блок команд. Иначе, если второе условие истинно, выполняет второй блок команд.", "CONTROLS_IF_TOOLTIP_4": "Если первое условие истинно, то выполняет первый блок команд. В противном случае, если второе условие истинно, выполняет второй блок команд. Если ни одно из условий не истинно, выполняет последний блок команд.", "CONTROLS_IF_MSG_IF": "если", "CONTROLS_IF_MSG_ELSEIF": "иначе если", "CONTROLS_IF_MSG_ELSE": "иначе", "CONTROLS_IF_IF_TOOLTIP": "Добавьте, удалите, переставьте фрагменты для переделки блока \"если\".", "CONTROLS_IF_ELSEIF_TOOLTIP": "Добавляет условие к блоку \"если\"", "CONTROLS_IF_ELSE_TOOLTIP": "Добавить заключительный подблок для случая, когда все условия ложны.", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "Возвращает значение истина, если вставки равны.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Возвращает значение истина, если вставки не равны.", "LOGIC_COMPARE_TOOLTIP_LT": "Возвращает значение истина, если первая вставка меньше второй.", "LOGIC_COMPARE_TOOLTIP_LTE": "Возвращает значение истина, если первая вставка меньше или равна второй.", "LOGIC_COMPARE_TOOLTIP_GT": "Возвращает значение истина, если первая вставка больше второй.", "LOGIC_COMPARE_TOOLTIP_GTE": "Возвращает значение истина, если первая вставка больше или равна второй.", "LOGIC_OPERATION_TOOLTIP_AND": "Возвращает значение истина, если обе вставки истинны.", "LOGIC_OPERATION_AND": "и", "LOGIC_OPERATION_TOOLTIP_OR": "Возвращает значение истина, если хотя бы одна из вставок истинна.", "LOGIC_OPERATION_OR": "или", "LOGIC_NEGATE_TITLE": "не %1", "LOGIC_NEGATE_TOOLTIP": "Возвращает значение истина, если вставка ложна. Возвращает значение ложь, если вставка истинна.", "LOGIC_BOOLEAN_TRUE": "истина", "LOGIC_BOOLEAN_FALSE": "ложь", "LOGIC_BOOLEAN_TOOLTIP": "Возвращает значение истина или ложь.", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "ничто", "LOGIC_NULL_TOOLTIP": "Возвращает ничто.", "LOGIC_TERNARY_HELPURL": "https://ru.wikipedia.org/wiki/Тернарная_условная_операция", "LOGIC_TERNARY_CONDITION": "выбрать по", "LOGIC_TERNARY_IF_TRUE": "если истина", "LOGIC_TERNARY_IF_FALSE": "если ложь", "LOGIC_TERNARY_TOOLTIP": "Проверяет условие выбора. Если условие истинно, возвращает первое значение, в противном случае возвращает второе значение.", "MATH_NUMBER_HELPURL": "https://ru.wikipedia.org/wiki/Число", "MATH_NUMBER_TOOLTIP": "Число.", "MATH_ARITHMETIC_HELPURL": "https://ru.wikipedia.org/wiki/Арифметика", "MATH_ARITHMETIC_TOOLTIP_ADD": "Возвращает сумму двух чисел.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Возвращает разность двух чисел.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Возвращает произведение двух чисел.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Возвращает частное от деления первого числа на второе.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Возвращает первое число, возведённое в степень второго числа.", "MATH_SINGLE_HELPURL": "https://ru.wikipedia.org/wiki/Квадратный_корень", "MATH_SINGLE_OP_ROOT": "квадратный корень", "MATH_SINGLE_TOOLTIP_ROOT": "Возвращает квадратный корень числа.", "MATH_SINGLE_OP_ABSOLUTE": "модуль", "MATH_SINGLE_TOOLTIP_ABS": "Возвращает модуль числа", "MATH_SINGLE_TOOLTIP_NEG": "Возвращает противоположное число.", "MATH_SINGLE_TOOLTIP_LN": "Возвращает натуральный логарифм числа.", "MATH_SINGLE_TOOLTIP_LOG10": "Возвращает десятичный логарифм числа.", "MATH_SINGLE_TOOLTIP_EXP": "Возвращает е в указанной степени.", "MATH_SINGLE_TOOLTIP_POW10": "Возвращает 10 в указанной степени.", "MATH_TRIG_HELPURL": "https://ru.wikipedia.org/wiki/Тригонометрические_функции", "MATH_TRIG_TOOLTIP_SIN": "Возвращает синус угла в градусах.", "MATH_TRIG_TOOLTIP_COS": "Возвращает косинус угла в градусах.", "MATH_TRIG_TOOLTIP_TAN": "Возвращает тангенс угла в градусах.", "MATH_TRIG_TOOLTIP_ASIN": "Возвращает арксинус (в градусах).", "MATH_TRIG_TOOLTIP_ACOS": "Возвращает арккосинус (в градусах).", "MATH_TRIG_TOOLTIP_ATAN": "Возвращает арктангенс (в градусах)", "MATH_CONSTANT_HELPURL": "https://ru.wikipedia.org/wiki/Математическая_константа", "MATH_CONSTANT_TOOLTIP": "Возвращает одну из распространённых констант: π (3.141...), e (2.718...), φ (1.618...), sqrt(2) (1.414...), sqrt(½) (0.707...) или ∞ (бесконечность).", "MATH_IS_EVEN": "чётное", "MATH_IS_ODD": "нечётное", "MATH_IS_PRIME": "простое", "MATH_IS_WHOLE": "целое", "MATH_IS_POSITIVE": "положительное", "MATH_IS_NEGATIVE": "отрицательное", "MATH_IS_DIVISIBLE_BY": "делится на", "MATH_IS_TOOLTIP": "Проверяет, является ли число чётным, нечётным, простым, целым, положительным, отрицательным или оно кратно определённому числу. Возвращает значение истина или ложь.", "MATH_CHANGE_HELPURL": "https://ru.wikipedia.org/wiki/%D0%98%D0%B4%D0%B8%D0%BE%D0%BC%D0%B0_%28%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%29#.D0.98.D0.BD.D0.BA.D1.80.D0.B5.D0.BC.D0.B5.D0.BD.D1.82", "MATH_CHANGE_TITLE_CHANGE": "увеличить", "MATH_CHANGE_INPUT_BY": "на", "MATH_CHANGE_TOOLTIP": "Добавляет число к переменной '%1'.", "MATH_ROUND_HELPURL": "https://ru.wikipedia.org/wiki/Округление", "MATH_ROUND_TOOLTIP": "Округляет число до большего или меньшего.", "MATH_ROUND_OPERATOR_ROUND": "округлить", "MATH_ROUND_OPERATOR_ROUNDUP": "округлить к большему", "MATH_ROUND_OPERATOR_ROUNDDOWN": "округлить к меньшему", "MATH_ONLIST_OPERATOR_SUM": "сумма списка", "MATH_ONLIST_TOOLTIP_SUM": "Возвращает сумму всех чисел в списке.", "MATH_ONLIST_OPERATOR_MIN": "наименьшее в списке", "MATH_ONLIST_TOOLTIP_MIN": "Возвращает наименьшее число списка.", "MATH_ONLIST_OPERATOR_MAX": "наибольшее в списке", "MATH_ONLIST_TOOLTIP_MAX": "Возвращает наибольшее число списка.", "MATH_ONLIST_OPERATOR_AVERAGE": "среднее арифметическое списка", "MATH_ONLIST_TOOLTIP_AVERAGE": "Возвращает среднее арифметическое списка.", "MATH_ONLIST_OPERATOR_MEDIAN": "медиана списка", "MATH_ONLIST_TOOLTIP_MEDIAN": "Возвращает медиану списка.", "MATH_ONLIST_OPERATOR_MODE": "моды списка", "MATH_ONLIST_TOOLTIP_MODE": "Возвращает список наиболее часто встречающихся элементов списка.", "MATH_ONLIST_OPERATOR_STD_DEV": "стандартное отклонение списка", "MATH_ONLIST_TOOLTIP_STD_DEV": "Возвращает стандартное отклонение списка.", "MATH_ONLIST_OPERATOR_RANDOM": "случайный элемент списка", "MATH_ONLIST_TOOLTIP_RANDOM": "Возвращает случайный элемент списка.", "MATH_MODULO_HELPURL": "https://ru.wikipedia.org/wiki/Деление_с_остатком", "MATH_MODULO_TITLE": "остаток от %1 : %2", "MATH_MODULO_TOOLTIP": "Возвращает остаток от деления двух чисел.", "MATH_CONSTRAIN_TITLE": "ограничить %1 снизу %2 сверху %3", "MATH_CONSTRAIN_TOOLTIP": "Ограничивает число нижней и верхней границами (включительно).", "MATH_RANDOM_INT_HELPURL": "https://ru.wikipedia.org/wiki/Генератор_псевдослучайных_чисел", "MATH_RANDOM_INT_TITLE": "случайное целое число от %1 для %2", "MATH_RANDOM_INT_TOOLTIP": "Возвращает случайное число между двумя заданными пределами (включая и их).", "MATH_RANDOM_FLOAT_HELPURL": "https://ru.wikipedia.org/wiki/Генератор_псевдослучайных_чисел", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "случайное число от 0 (включительно) до 1", "MATH_RANDOM_FLOAT_TOOLTIP": "Возвращает случайное число от 0.0 (включительно) до 1.0.", "TEXT_TEXT_HELPURL": "https://ru.wikipedia.org/wiki/Строковый_тип", "TEXT_TEXT_TOOLTIP": "Буква, слово или строка текста.", "TEXT_JOIN_TITLE_CREATEWITH": "создать текст из", "TEXT_JOIN_TOOLTIP": "Создаёт фрагмент текста, объединяя любое число элементов", "TEXT_CREATE_JOIN_TITLE_JOIN": "соединить", "TEXT_CREATE_JOIN_TOOLTIP": "Добавьте, удалите, переставьте фрагменты для переделки текстового блока.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Добавить элемент к тексту.", "TEXT_APPEND_TO": "к", "TEXT_APPEND_APPENDTEXT": "добавить текст", "TEXT_APPEND_TOOLTIP": "Добавить текст к переменной «%1».", "TEXT_LENGTH_TITLE": "длина %1", "TEXT_LENGTH_TOOLTIP": "Возвращает число символов (включая пробелы) в заданном тексте.", "TEXT_ISEMPTY_TITLE": "%1 пуст", "TEXT_ISEMPTY_TOOLTIP": "Возвращает значение истина, если предоставленный текст пуст.", "TEXT_INDEXOF_TOOLTIP": "Возвращает номер позиции первого/последнего вхождения первого текста во втором. Возвращает 0, если текст не найден.", "TEXT_INDEXOF_INPUT_INTEXT": "в тексте", "TEXT_INDEXOF_OPERATOR_FIRST": "найти первое вхождение текста", "TEXT_INDEXOF_OPERATOR_LAST": "найти последнее вхождение текста", "TEXT_CHARAT_INPUT_INTEXT": "в тексте", "TEXT_CHARAT_FROM_START": "взять букву №", "TEXT_CHARAT_FROM_END": "взять букву № с конца", "TEXT_CHARAT_FIRST": "взять первую букву", "TEXT_CHARAT_LAST": "взять последнюю букву", "TEXT_CHARAT_RANDOM": "взять случайную букву", "TEXT_CHARAT_TOOLTIP": "Возвращает букву в указанной позиции.", "TEXT_GET_SUBSTRING_TOOLTIP": "Возвращает указанную часть текста.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "в тексте", "TEXT_GET_SUBSTRING_START_FROM_START": "взять подстроку с буквы №", "TEXT_GET_SUBSTRING_START_FROM_END": "взять подстроку с буквы № с конца", "TEXT_GET_SUBSTRING_START_FIRST": "взять подстроку с первой буквы", "TEXT_GET_SUBSTRING_END_FROM_START": "по букву №", "TEXT_GET_SUBSTRING_END_FROM_END": "по букву № с конца", "TEXT_GET_SUBSTRING_END_LAST": "по последнюю букву", "TEXT_CHANGECASE_TOOLTIP": "Возвращает копию текста с ЗАГЛАВНЫМИ или строчными буквами.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "в ЗАГЛАВНЫЕ БУКВЫ", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "в строчные буквы", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "в Заглавные Начальные Буквы", "TEXT_TRIM_TOOLTIP": "Возвращает копию текста с пробелами, удалеными с одного или обоих концов.", "TEXT_TRIM_OPERATOR_BOTH": "обрезать пробелы с двух сторон", "TEXT_TRIM_OPERATOR_LEFT": "обрезать пробелы слева", "TEXT_TRIM_OPERATOR_RIGHT": "обрезать пробелы справа", "TEXT_PRINT_TITLE": "напечатать %1", "TEXT_PRINT_TOOLTIP": "Печатает текст, число или другой объект.", "TEXT_PROMPT_TYPE_TEXT": "запросить текст с подсказкой", "TEXT_PROMPT_TYPE_NUMBER": "запросить число с подсказкой", "TEXT_PROMPT_TOOLTIP_NUMBER": "Запросить у пользователя число.", "TEXT_PROMPT_TOOLTIP_TEXT": "Запросить у пользователя текст.", "LISTS_CREATE_EMPTY_TITLE": "создать пустой список", "LISTS_CREATE_EMPTY_TOOLTIP": "Возвращает список длины 0, не содержащий данных", "LISTS_CREATE_WITH_TOOLTIP": "Создаёт список с любым числом элементов.", "LISTS_CREATE_WITH_INPUT_WITH": "создать список из", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "список", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Добавьте, удалите, переставьте элементы для переделки блока списка.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Добавляет элемент к списку.", "LISTS_REPEAT_TOOLTIP": "Создаёт список, состоящий из заданного числа копий элемента.", "LISTS_REPEAT_TITLE": "создать список из элемента %1, повторяющегося %2 раз", "LISTS_LENGTH_TITLE": "длина %1", "LISTS_LENGTH_TOOLTIP": "Возвращает длину списка.", "LISTS_IS_EMPTY_TITLE": "%1 пуст", "LISTS_TOOLTIP": "Возвращает значение истина, если список пуст.", "LISTS_INLIST": "в списке", "LISTS_INDEX_OF_FIRST": "найти первое вхождение элемента", "LISTS_INDEX_OF_LAST": "найти последнее вхождение элемента", "LISTS_INDEX_OF_TOOLTIP": "Возвращает номер позиции первого/последнего вхождения элемента в списке. Возвращает 0, если текст не найден.", "LISTS_GET_INDEX_GET": "взять", "LISTS_GET_INDEX_GET_REMOVE": "взять и удалить", "LISTS_GET_INDEX_REMOVE": "удалить", "LISTS_GET_INDEX_FROM_END": "№ с конца", "LISTS_GET_INDEX_FIRST": "первый", "LISTS_GET_INDEX_LAST": "последний", "LISTS_GET_INDEX_RANDOM": "произвольный", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Возвращает элемент в указанной позиции списка (№1 - первый элемент).", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Возвращает элемент в указанной позиции списка (№1 - последний элемент).", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Возвращает первый элемент списка.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Возвращает последний элемент списка.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Возвращает случайный элемент списка.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Удаляет и возвращает элемент в указанной позиции списка (№1 - первый элемент).", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Удаляет и возвращает элемент в указанной позиции списка (№1 - последний элемент).", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Удаляет и возвращает первый элемент списка.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Удаляет и возвращает последний элемент списка.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Удаляет и возвращает случайный элемент списка.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Удаляет элемент в указанной позиции списка (№1 - первый элемент).", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Удаляет элемент в указанной позиции списка (№1 - последний элемент).", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Удаляет первый элемент списка.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Удаляет последний элемент списка.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Удаляет случайный элемент списка.", "LISTS_SET_INDEX_SET": "присвоить", "LISTS_SET_INDEX_INSERT": "вставить в", "LISTS_SET_INDEX_INPUT_TO": "=", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Присваивает значение элементу в указанной позиции списка (№1 - первый элемент).", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Присваивает значение элементу в указанной позиции списка (№1 - последний элемент).", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Присваивает значение первому элементу списка.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Присваивает значение последнему элементу списка.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Присваивает значение случайному элементу списка.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Вставляет элемент в указанной позиции списка (№1 - первый элемент).", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Вставляет элемент в указанной позиции списка (№1 - последний элемент).", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Вставляет элемент в начало списка.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Добавляет элемент в конец списка.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Вставляет элемент в случайное место в списке.", "LISTS_GET_SUBLIST_START_FROM_START": "взять подсписок с №", "LISTS_GET_SUBLIST_START_FROM_END": "взять подсписок с № с конца", "LISTS_GET_SUBLIST_START_FIRST": "взять подсписок с первого", "LISTS_GET_SUBLIST_END_FROM_START": "по №", "LISTS_GET_SUBLIST_END_FROM_END": "по № с конца", "LISTS_GET_SUBLIST_END_LAST": "по последний", "LISTS_GET_SUBLIST_TOOLTIP": "Создаёт копию указанной части списка.", "VARIABLES_GET_TOOLTIP": "Возвращает значение этой переменной.", "VARIABLES_GET_CREATE_SET": "Создать блок \"присвоить\" для %1", "VARIABLES_SET_TITLE": "присвоить", "VARIABLES_SET_TAIL": "=", "VARIABLES_SET_TOOLTIP": "Присваивает переменной значение вставки.", "VARIABLES_SET_CREATE_GET": "Создать вставку %1", "PROCEDURES_DEFNORETURN_TITLE": "чтобы", "PROCEDURES_DEFNORETURN_PROCEDURE": "выполнить что-то", "PROCEDURES_BEFORE_PARAMS": "с:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Создаёт процедуру, не возвращающую значение.", "PROCEDURES_DEFRETURN_RETURN": "вернуть", "PROCEDURES_DEFRETURN_TOOLTIP": "Создаёт процедуру, возвращающую значение.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Предупреждение: эта функция имеет повторяющиеся параметры.", "PROCEDURES_CALLNORETURN_HELPURL": "https://ru.wikipedia.org/wiki/Функция_%28программирование%29", "PROCEDURES_CALLNORETURN_TOOLTIP": "Исполняет определённую пользователем процедуру '%1'.", "PROCEDURES_CALLRETURN_HELPURL": "https://ru.wikipedia.org/wiki/Функция_%28программирование%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Исполняет определённую пользователем процедуру '%1' и возвращает вычисленное значение.", "PROCEDURES_MUTATORCONTAINER_TITLE": "параметры", "PROCEDURES_MUTATORARG_TITLE": "имя параметра:", "PROCEDURES_HIGHLIGHT_DEF": "Выделить определение процедуры", "PROCEDURES_CREATE_DO": "Создать вызов '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Если первое значение истинно, возвращает второе значение.", "PROCEDURES_IFRETURN_WARNING": "Предупреждение: Этот блок может использоваться только внутри определения функции." } ================================================ FILE: extern/blockly/msg/json/sq.json ================================================ { "@metadata": [], "VARIABLES_DEFAULT_NAME": "send", "DUPLICATE_BLOCK": "Kopjo", "ADD_COMMENT": "Vendos nje Koment", "REMOVE_COMMENT": "Fshij komentin", "EXTERNAL_INPUTS": "Hyrjet e jashtme", "INLINE_INPUTS": "Hyrjet e brendshme", "DELETE_BLOCK": "Fshij bllokun", "DELETE_X_BLOCKS": "Fshij %1 blloqe", "COLLAPSE_BLOCK": "Mbyll bllokun", "COLLAPSE_ALL": "Mbyll blloqet", "EXPAND_BLOCK": "Zmadho bllokun", "EXPAND_ALL": "Zmadho blloqet", "DISABLE_BLOCK": "Çaktivizo bllokun", "ENABLE_BLOCK": "Aktivizo bllokun", "HELP": "Ndihmë", "CHANGE_VALUE_TITLE": "Ndrysho Vlerat:", "NEW_VARIABLE": "Identifikatorë i ri...", "NEW_VARIABLE_TITLE": "Emri i identifikatorit të ri:", "RENAME_VARIABLE": "Ndrysho emrin variables...", "RENAME_VARIABLE_TITLE": "Ndrysho emrin e te gjitha '%1' variablave ne :", "COLOUR_PICKER_HELPURL": "http://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Zgjidh nje ngjyre nga nje game ngjyrash.", "COLOUR_RANDOM_TITLE": "ngjyre e rastesishme", "COLOUR_RANDOM_TOOLTIP": "Zgjidhni një ngjyrë në mënyrë të rastësishme.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "ngjyre me", "COLOUR_RGB_RED": "e kuqe", "COLOUR_RGB_GREEN": "jeshile", "COLOUR_RGB_BLUE": "blu", "COLOUR_RGB_TOOLTIP": "Krijo një ngjyrë me shumën e specifikuar te te kuqes, te gjelbëres, dhe bluse. Te gjitha vlerat duhet te jene mes 0 dhe 100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "Përzierje", "COLOUR_BLEND_COLOUR1": "Ngjyra 1", "COLOUR_BLEND_COLOUR2": "Ngjyra 2", "COLOUR_BLEND_RATIO": "Perpjesetim", "COLOUR_BLEND_TOOLTIP": "Perzien dy ngjyra së bashku me një raport të dhënë (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "http://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "përsërit %1 herë", "CONTROLS_REPEAT_TITLE_REPEAT": "përsërit", "CONTROLS_REPEAT_TITLE_TIMES": "herë", "CONTROLS_REPEAT_INPUT_DO": "ekzekuto", "CONTROLS_REPEAT_TOOLTIP": "Ekzekuto disa fjali disa herë.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "përsërit përderisa", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "përsërit derisa", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Përderisa një vlerë është e saktë, atëherë ekzekuto disa fjali.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Përderisa një vlerë është e pasaktë, atëherë ekzekuto disa fjali.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Bëje identifikuesin %1 që ta ketë vlerat prej numrit të fillimit deri tek numri i fundit, duke numëruar nga intervali i specifikuar, dhe ti bëj blloqet e specifikuara.", "CONTROLS_FOR_INPUT_WITH": "numero me", "CONTROLS_FOR_INPUT_FROM_TO_BY": "nga '%1' ne '%2' me nga '%3'", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each", "CONTROLS_FOREACH_INPUT_ITEM": "per cdo produkt", "CONTROLS_FOREACH_INPUT_INLIST": "ne liste", "CONTROLS_FOREACH_TOOLTIP": "Per cdo produkt ne nje \"liste\" \"vendos\" ndryshoren '%1' produktit, dhe pastaj bej disa deklarata.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "dil nga nje faze perseritese", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "vazhdo me elementin tjeter te nje faze perseritese", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Ndahu nga unaza.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Kapërce pjesën e mbetur të unazës, dhe vazhdo me ripërsëritjen tjetër.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Paralajmërim: Ky bllok mund të përdoret vetëm brenda unazës.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "Nëse një vlerë është e saktë, atëherë ekzekuto disa fjali.", "CONTROLS_IF_TOOLTIP_2": "Nëse një vlerë është e saktë, atëherë ekzekuto bllokun e parë të fjalive. Përndryshe, ekzekuto bllokun e dytë të fjalive.", "CONTROLS_IF_TOOLTIP_3": "Nëse vlera e parë është e saktë, atëherë ekzekuto bllokun e parë të fjalive. Përndryshe, nëse vlera e dytë është e saktë, ekzekuto bllokun e dytë të fjalive.", "CONTROLS_IF_TOOLTIP_4": "Nëse vlera e parë është e saktë, atëherë ekzekuto bllokun e parë të fjalive. Përndryshe, nëse vlera e dytë është e saktë, ekzekuto bllokun e dytë të fjalive. Nëse asnjëra nga vlerat nuk është e saktë, ekzekuto bllokun e fundit të fjalive.", "CONTROLS_IF_MSG_IF": "nëse", "CONTROLS_IF_MSG_ELSEIF": "përndryshe nëse", "CONTROLS_IF_MSG_ELSE": "përndryshe", "CONTROLS_IF_IF_TOOLTIP": "Shto, fshij, ose rirregullo sektoret për ta rikonfiguruar këte bllok nëse.", "CONTROLS_IF_ELSEIF_TOOLTIP": "\"Vendos\" \"kushtein\"tek \"pjesa\" \"if\"", "CONTROLS_IF_ELSE_TOOLTIP": "Shto një përfundues, që i mbërrin të gjitha kushtet në bllokun nëse.", "LOGIC_COMPARE_HELPURL": "http://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "Ktheje të saktë nëse të dy hyrjet janë të barabarta me njëra-tjetrën.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Ktheje të saktë nëse të dy hyrjet nuk janë të barabarta me njëra-tjetrën.", "LOGIC_COMPARE_TOOLTIP_LT": "Ktheje të saktë nëse hyrja e parë është më e vogël se hyrja e dytë.", "LOGIC_COMPARE_TOOLTIP_LTE": "Ktheje të saktë nëse hyrja e parë është më e vogël ose e barabartë me hyrjen e dytë.", "LOGIC_COMPARE_TOOLTIP_GT": "Ktheje të saktë nëse hyrja e parë është më e madhe se hyrja e dytë.", "LOGIC_COMPARE_TOOLTIP_GTE": "Ktheje të saktë nëse hyrja e parë është më e madhe ose e barabartë me hyrjen e dytë.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Kthehet të saktë nëse të dy hyrjet janë të sakta.", "LOGIC_OPERATION_AND": "dhe", "LOGIC_OPERATION_TOOLTIP_OR": "Kthehet e saktë nëse së paku njëra nga hyrjet është e saktë.", "LOGIC_OPERATION_OR": "ose", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "jo %1", "LOGIC_NEGATE_TOOLTIP": "Kthehet e saktë nëse hyrja është e pasaktë. Kthehet e pasaktë nëse hyrja është e saktë.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "e saktë", "LOGIC_BOOLEAN_FALSE": "e pasaktë", "LOGIC_BOOLEAN_TOOLTIP": "Kthehet ose të saktë ose të pasaktë.", "LOGIC_NULL_HELPURL": "http://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "pavlerë", "LOGIC_NULL_TOOLTIP": "Kthehet e pavlerë.", "LOGIC_TERNARY_HELPURL": "http://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "nëse e saktë", "LOGIC_TERNARY_IF_FALSE": "nëse e pasaktë", "LOGIC_TERNARY_TOOLTIP": "Kontrollo kushtin në 'test'. Nëse kushti është i saktë, kthen vlerën 'nëse e saktë'; përndryshe kthen vlerën 'nëse e pasaktë'.", "MATH_NUMBER_HELPURL": "http://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "Një numër.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "x", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "asinus", "MATH_TRIG_ACOS": "acosinus", "MATH_TRIG_ATAN": "atangjentë", "MATH_ARITHMETIC_HELPURL": "http://sq.wikipedia.org/wiki/Aritmetika", "MATH_ARITHMETIC_TOOLTIP_ADD": "Kthen shumën e dy numrave.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Kthen ndryshimin e dy numrave.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Kthen produktin e dy numrave.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Kthen herësin e dy numrave.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Kthen numrin e parë të ngritur në fuqinë e numrit të dytë.", "MATH_SINGLE_HELPURL": "http://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "rrënja katrore", "MATH_SINGLE_TOOLTIP_ROOT": "Kthen rrënjën katrore të një numri.", "MATH_SINGLE_OP_ABSOLUTE": "absolut", "MATH_SINGLE_TOOLTIP_ABS": "Kthen vlerën absolute të një numri.", "MATH_SINGLE_TOOLTIP_NEG": "Kthe negacionin e një numri.", "MATH_SINGLE_TOOLTIP_LN": "Kthen logaritmën natyrale të një numri.", "MATH_SINGLE_TOOLTIP_LOG10": "Kthen 10 logaritmet bazë të një numri.", "MATH_SINGLE_TOOLTIP_EXP": "Kthen e në fuqinë e një numri.", "MATH_SINGLE_TOOLTIP_POW10": "Kthen 10 në fuqinë e një numri.", "MATH_TRIG_HELPURL": "http://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "Kthe kosinusin e nje kendi (jo ne radiant).", "MATH_TRIG_TOOLTIP_COS": "Kthe kosinusin e nje grade (jo ne radiant).", "MATH_TRIG_TOOLTIP_TAN": "Kthe tangentin e nje kendi (jo radiant).", "MATH_TRIG_TOOLTIP_ASIN": "Rikthe sin-1 e nje numeri.", "MATH_TRIG_TOOLTIP_ACOS": "Rikthe cos-1 e nje numeri.", "MATH_TRIG_TOOLTIP_ATAN": "Kthe tg-1 e nje numeri.", "MATH_CONSTANT_HELPURL": "http://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "Kthen një nga konstantet e përbashkëta: : π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (infiniti).", "MATH_IS_EVEN": "është çift", "MATH_IS_ODD": "është tek", "MATH_IS_PRIME": "është prim", "MATH_IS_WHOLE": "është i plotë", "MATH_IS_POSITIVE": "është pozitiv", "MATH_IS_NEGATIVE": "është negativ", "MATH_IS_DIVISIBLE_BY": "është i pjestueshme me", "MATH_IS_TOOLTIP": "Kontrollo nëse një numër është çift, tek, prim, i plotë, pozitiv, negativ, ose nëse është i pjestueshëm me një numër të caktuar. Kthehet e saktë ose e pasaktë.", "MATH_CHANGE_HELPURL": "http://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "ndrysho", "MATH_CHANGE_INPUT_BY": "nga", "MATH_CHANGE_TOOLTIP": "Shto një numër në ndryshoren '%1'.", "MATH_ROUND_HELPURL": "http://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Rrumbullakësimi i numrit të lartë ose të ulët.", "MATH_ROUND_OPERATOR_ROUND": "rrumbullakësimi", "MATH_ROUND_OPERATOR_ROUNDUP": "rrumbullakësimi i lartë", "MATH_ROUND_OPERATOR_ROUNDDOWN": "rrumbullakësimi i ulët", "MATH_ONLIST_OPERATOR_SUM": "mbledhja e listës", "MATH_ONLIST_TOOLTIP_SUM": "Kthe shumën e të gjithë numrave të listës.", "MATH_ONLIST_OPERATOR_MIN": "numri më i ulët i listës", "MATH_ONLIST_TOOLTIP_MIN": "Kthe numrin me të vogël të listës.", "MATH_ONLIST_OPERATOR_MAX": "numri më i madh i listës", "MATH_ONLIST_TOOLTIP_MAX": "Kthe numrin më të madh të listës.", "MATH_ONLIST_OPERATOR_AVERAGE": "mesatarja e listës", "MATH_ONLIST_TOOLTIP_AVERAGE": "Kthen mesatarën (kuptimi aritmetik) i vlerave numerike të listës.", "MATH_ONLIST_OPERATOR_MEDIAN": "mediana e listës", "MATH_ONLIST_TOOLTIP_MEDIAN": "Kthe numrin median të listës.", "MATH_ONLIST_OPERATOR_MODE": "modat e listës", "MATH_ONLIST_TOOLTIP_MODE": "Kthe listën e sendit(eve) më të zakonshme të listës.", "MATH_ONLIST_OPERATOR_STD_DEV": "devijimi standard i listës", "MATH_ONLIST_TOOLTIP_STD_DEV": "Kthe devijimin standard të listës.", "MATH_ONLIST_OPERATOR_RANDOM": "send i rastësishëm i listës", "MATH_ONLIST_TOOLTIP_RANDOM": "Kthe një element të rastësishëm nga lista.", "MATH_MODULO_HELPURL": "http://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "mbetësi i %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Kthen mbetësin nga pjestimi i dy numrave.", "MATH_CONSTRAIN_HELPURL": "http://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "detyro %1 e ulët %2 e lartë %3", "MATH_CONSTRAIN_TOOLTIP": "Vëni një numër që të jetë në mes të kufive të specifikuara(përfshirëse).", "MATH_RANDOM_INT_HELPURL": "http://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "numër i plotë i rastësishëm nga %1 deri në %2", "MATH_RANDOM_INT_TOOLTIP": "Kthe një numër të plotë të rastësishëm të dy kufijve të specifikuar, të përfshirë.", "MATH_RANDOM_FLOAT_HELPURL": "http://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "fraksioni i rastësishëm", "MATH_RANDOM_FLOAT_TOOLTIP": "Kthe fraksionin e rastësishëm në mes të 0.0 (përfshirëse) dhe 1.0 (jopërfshirëse).", "TEXT_TEXT_HELPURL": "http://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "Nje shkronje, fjale, ose rresht teksti.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "krijo tekst me", "TEXT_JOIN_TOOLTIP": "Krijo nje pjese te tekstit duke bashkuar se bashku disa sende", "TEXT_CREATE_JOIN_TITLE_JOIN": "bashkangjit", "TEXT_CREATE_JOIN_TOOLTIP": "Shto, fshij, ose rirregullo sektoret për ta rikonfiguruar këtë bllok teksti.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Shto nje gje ne tekst", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "ne", "TEXT_APPEND_APPENDTEXT": "shto tekst", "TEXT_APPEND_TOOLTIP": "shto tekst tek varibla '%1'.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "gjatesi %1", "TEXT_LENGTH_TOOLTIP": "Pergjigjet me nje numer shkronjash (duke perfshire hapesire) ne tekstin e dhene.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 eshte bosh", "TEXT_ISEMPTY_TOOLTIP": "Kthehet e vertete neqoftese teksti i dhene eshte bosh.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Pergjigjet me indeksin e pare/fundit te rastisjes se tekstit te pare ne tekstin e dyte. Pergjigjet me 0 ne qofte se teksti nuk u gjet.", "TEXT_INDEXOF_INPUT_INTEXT": "ne tekst", "TEXT_INDEXOF_OPERATOR_FIRST": "gjej rastisjen e pare te tekstit", "TEXT_INDEXOF_OPERATOR_LAST": "gjej rastisjen e fundit te tekstit", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "ne tekst", "TEXT_CHARAT_FROM_START": "merr shkronjen #", "TEXT_CHARAT_FROM_END": "merr shkronjen # nga fundi", "TEXT_CHARAT_FIRST": "merr shkronjen e pare", "TEXT_CHARAT_LAST": "merr shkronjen e fundit", "TEXT_CHARAT_RANDOM": "merr nje shkronje te rastesishme", "TEXT_CHARAT_TOOLTIP": "Kthe nje shkronje nga nje pozicion i caktuar.", "TEXT_GET_SUBSTRING_TOOLTIP": "Pergjigjet me nje pjese te caktuar teksti.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "ne tekst", "TEXT_GET_SUBSTRING_START_FROM_START": "Merr nenvargun nga shkronja #", "TEXT_GET_SUBSTRING_START_FROM_END": "merr nenvargun nga shkronja # nga fundi", "TEXT_GET_SUBSTRING_START_FIRST": "merr vlerat qe vazhdojne me shkronjen e pare", "TEXT_GET_SUBSTRING_END_FROM_START": "ne shkronjen #", "TEXT_GET_SUBSTRING_END_FROM_END": "ne shkronjen # nga fundi", "TEXT_GET_SUBSTRING_END_LAST": "tek shkronja e fundit", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Kthe nje kopje te tekstit ne nje rast te ndryshem.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "me shkronja te medha shtypi", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "me shkronja te vogla shtypi", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "Fillimi me shkronje te madhe shtypi", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Pergjigju me nje kopje te tekstit me hapesira te fshira nga njera ane ose te dyja anet.", "TEXT_TRIM_OPERATOR_BOTH": "prit hapesirat nga te dyja anet", "TEXT_TRIM_OPERATOR_LEFT": "prit hapesirat nga ana e majte", "TEXT_TRIM_OPERATOR_RIGHT": "prit hapesirat nga ana e djathte", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "printo %1", "TEXT_PRINT_TOOLTIP": "Printo tekstin e caktuar, numer ose vlere tjeter.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "kerko tekst me njoftim", "TEXT_PROMPT_TYPE_NUMBER": "kerko nje numer me njoftim", "TEXT_PROMPT_TOOLTIP_NUMBER": "Kerkoji perdoruesit nje numer.", "TEXT_PROMPT_TOOLTIP_TEXT": "Kerkoji perdoruesit ca tekst.", "LISTS_CREATE_EMPTY_HELPURL": "http://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "krijo një listë të zbrazët", "LISTS_CREATE_EMPTY_TOOLTIP": "Kthen një listë, te gjatësisë 0, duke mos përmbajtur asnjë regjistrim të të dhënave", "LISTS_CREATE_WITH_TOOLTIP": "Krijo një listë me ndonjë numbër të sendeve.", "LISTS_CREATE_WITH_INPUT_WITH": "krijo listë me", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "listë", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Shto, fshij, ose rirregullo sektoret për ta rikonfiguruar këtë bllok të listës.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Shto një send në listë.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "Krijon në listë qe përmban vlerën e dhënë të përsëritur aq herë sa numri i specifikuar.", "LISTS_REPEAT_TITLE": "krijo listën me sendin %1 të përsëritur %2 herë", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "gjatësia e %1", "LISTS_LENGTH_TOOLTIP": "Kthen gjatësinë e listës.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 është e zbraztë", "LISTS_TOOLTIP": "Kthehet i saktë nëse lista është e zbraztë.", "LISTS_INLIST": "në listë", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "gjen ndodhjen e parë të sendit", "LISTS_INDEX_OF_LAST": "gjen ndodhjen e fundit të sendit", "LISTS_INDEX_OF_TOOLTIP": "Kthen indeksin e ndodhjes së parë/fudit të sendit në listë. Kthen 0 nëse teksti nuk është gjetur.", "LISTS_GET_INDEX_GET": "merr", "LISTS_GET_INDEX_GET_REMOVE": "merr dhe fshij", "LISTS_GET_INDEX_REMOVE": "largo", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# nga fundi", "LISTS_GET_INDEX_FIRST": "i parë", "LISTS_GET_INDEX_LAST": "i fundit", "LISTS_GET_INDEX_RANDOM": "i rastësishëm", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Kthen një send në pozicionin e specifikuar në listë. #1 është sendi i parë.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Kthen një send në pozicionin e specifikuar në listë. #1 është sendi i fundit.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Rikthen tek artikulli i par në list.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Kthen artikullin e fundit në list.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Kthen një send të rastësishëm në listë.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Fshin dhe kthen sendin në pozicionin e specifikuar në listë. #1 është sendi i parë.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Fshin dhe kthen sendin në pozicionin e specifikuar në listë. #1 është sendi i fundit.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Fshin dhe kthen sendin e parë në listë.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Fshin dhe kthen sendin e fundit në listë.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Fshin dhe kthen një send të rastësishëm në listë.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Fshin sendin në pozicionin e specifikuar në listë. #1 është sendi i parë.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Fshin sendin në pozicionin e specifikuar në listë. #1 është sendi i fundit.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Fshin sendin e parë në listë.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Fshin sendin e fundit në listë.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Kthen një send të rastësishëm në listë.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "vendos", "LISTS_SET_INDEX_INSERT": "fut në", "LISTS_SET_INDEX_INPUT_TO": "sikurse", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Vendos sendin në pozicionin e specifikuar në listë. #1 është sendi i parë.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Vendos sendin ne pozicionin e specifikuar në listë. #1 është sendi i fundit.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Vendos sendin e parë në listë.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Vendos sendin e fundit në listë.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Vendos një send të rastësishëm në listë.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Fut sendin në pozicionin e specifikuar të listës. #1 është sendi i parë.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Fut sendin në pozicionin e specifikuar të listës. #1 është sendi i fundit.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Fut sendin në fillim të listës.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Bashkangjit sendin në fund të listës.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Fut sendin rastësisht në listë.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "merr nën-listën nga #", "LISTS_GET_SUBLIST_START_FROM_END": "merr nën listën nga # nga fundi", "LISTS_GET_SUBLIST_START_FIRST": "merr nën-listën nga i pari", "LISTS_GET_SUBLIST_END_FROM_START": "tek #", "LISTS_GET_SUBLIST_END_FROM_END": "tek # nga fundi", "LISTS_GET_SUBLIST_END_LAST": "tek i fundit", "LISTS_GET_SUBLIST_TOOLTIP": "Krijon në kopje të pjesës së specifikuar të listës.", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TOOLTIP": "Pergjigjet me nje vlere te kesaj variable.", "VARIABLES_GET_CREATE_SET": "Krijo 'vendos %1", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "vendos", "VARIABLES_SET_TAIL": "ne", "VARIABLES_SET_TOOLTIP": "Vendos kete variable te jete e barabarte me te dhenat ne hyrje.", "VARIABLES_SET_CREATE_GET": "Krijo 'merr %1", "PROCEDURES_DEFNORETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFNORETURN_TITLE": "te", "PROCEDURES_DEFNORETURN_PROCEDURE": "bëj diqka", "PROCEDURES_BEFORE_PARAMS": "me:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Krijon një funksion pa dalje.", "PROCEDURES_DEFRETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFRETURN_RETURN": "rikthe", "PROCEDURES_DEFRETURN_TOOLTIP": "Krijon një funksion me një dalje.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Paralajmërim: Ky funksion ka parametra të dyfishuar.", "PROCEDURES_CALLNORETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_TOOLTIP": "Lësho funksionin e definuar nga përdoruesi '%1'.", "PROCEDURES_CALLRETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Lëho funksionin e definuar nga përdoruesi '%1' dhe përdor daljen e tij.", "PROCEDURES_MUTATORCONTAINER_TITLE": "Informacioni i futur", "PROCEDURES_MUTATORARG_TITLE": "Fut emrin:", "PROCEDURES_HIGHLIGHT_DEF": "Thekso definicionin e funksionit", "PROCEDURES_CREATE_DO": "Krijo '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Nëse një vlerë është e saktë, atëherë kthe një vlerë të dytë.", "PROCEDURES_IFRETURN_WARNING": "Paralajmërim: Ky bllok mund të përdoret vetëm brenda definicionit të funksionit." } ================================================ FILE: extern/blockly/msg/json/sr.json ================================================ { "@metadata": [], "VARIABLES_DEFAULT_NAME": "ставка", "DUPLICATE_BLOCK": "Дуплирај", "ADD_COMMENT": "Додај Коментар", "REMOVE_COMMENT": "Уклонити коментар", "EXTERNAL_INPUTS": "Спољашњи Уноси", "INLINE_INPUTS": "Линијски Уноси", "DELETE_BLOCK": "Избриши Блок", "DELETE_X_BLOCKS": "Избриши %1 Блокова", "COLLAPSE_BLOCK": "Скупи Блок", "COLLAPSE_ALL": "Скупи Блокове", "EXPAND_BLOCK": "Прошири Блок", "EXPAND_ALL": "Прошири Блокове", "DISABLE_BLOCK": "Онеспособи Блок", "ENABLE_BLOCK": "Оспособи Блок", "HELP": "Помоћ", "CHANGE_VALUE_TITLE": "Промени вредност:", "NEW_VARIABLE": "Нова промењјива...", "NEW_VARIABLE_TITLE": "Име нове промењиве:", "RENAME_VARIABLE": "Преименовати варијаблу...", "RENAME_VARIABLE_TITLE": "Преименовати све '%1' варијабле у:", "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Изаберите боју са палете.", "COLOUR_RANDOM_TITLE": "насумична боја", "COLOUR_RANDOM_TOOLTIP": "Изаберите боју насумице.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "обоји са", "COLOUR_RGB_RED": "црвена", "COLOUR_RGB_GREEN": "зелена", "COLOUR_RGB_BLUE": "плава", "COLOUR_RGB_TOOLTIP": "Креирај боју са одређеном количином црвене,зелене, и плаве. Све вредности морају бити између 0 и 100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "Помешати", "COLOUR_BLEND_COLOUR1": "Боја 1", "COLOUR_BLEND_COLOUR2": "Боја 2", "COLOUR_BLEND_RATIO": "Коефициент", "COLOUR_BLEND_TOOLTIP": "Помешати две боје заједно са датим односом (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "поновите %1 пута", "CONTROLS_REPEAT_TITLE_REPEAT": "поновите", "CONTROLS_REPEAT_TITLE_TIMES": "пута", "CONTROLS_REPEAT_INPUT_DO": "урадите", "CONTROLS_REPEAT_TOOLTIP": "Одрадити неке наредбе неколико пута.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "понављати док", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "понављати до", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Док је вредност тачна, онда извршите неке наредбе.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Док вредност није тачна, онда извршити неке наредбе.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Имај промењиву %1 узми вредности од почетног броја до задњег броја, бројећи по одређеном интервалу, и изврши одређене блокове.", "CONTROLS_FOR_INPUT_WITH": "преброј са", "CONTROLS_FOR_INPUT_FROM_TO_BY": "од %1 до %2 од %3", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each", "CONTROLS_FOREACH_INPUT_ITEM": "за сваку ставку", "CONTROLS_FOREACH_INPUT_INLIST": "у листи", "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "", "CONTROLS_FOREACH_TOOLTIP": "За сваку ставку унутар листе, подеси промењиву '%1' по ставци, и онда начини неке изјаве-наредбе.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "Изађите из петље", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "настави са следећом итерацијом петље", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Напусти садржај петље.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Прескочи остатак ове петље, и настави са следећом итерацијом(понављанјем).", "CONTROLS_FLOW_STATEMENTS_WARNING": "Упозорење: Овај блок може да се употреби само унутар петље.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "ако је вредност тачна, онда изврши неке наредбе-изјаве.", "CONTROLS_IF_TOOLTIP_2": "ако је вредност тачна, онда изврши први блок наредби, У супротном, изврши други блок наредби.", "CONTROLS_IF_TOOLTIP_3": "Ако је прва вредност тачна, онда изврши први блок наредби, у супротном, ако је друга вредност тачна , изврши други блок наредби.", "CONTROLS_IF_TOOLTIP_4": "Ако је прва вредност тачна, онда изврши први блок наредби, у супротном, ако је друга вредност тачна , изврши други блок наредби. Ако ни једна од вредности није тачна, изврши последнји блок наредби.", "CONTROLS_IF_MSG_IF": "ако", "CONTROLS_IF_MSG_ELSEIF": "друго ако", "CONTROLS_IF_MSG_ELSE": "друго (у другом случају)", "CONTROLS_IF_IF_TOOLTIP": "Додај, уклони, или преуреди делове како бих реконфигурисали овај иф блок.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Додај услов иф блоку.", "CONTROLS_IF_ELSE_TOOLTIP": "Додај коначни, catch-all (ухвати све) услове иф блока.", "LOGIC_COMPARE_HELPURL": "https://sr.wikipedia.org/wiki/Неједнакост", "LOGIC_COMPARE_TOOLTIP_EQ": "враћа вредност тачно ако су оба уноса једнака један другом.", "LOGIC_COMPARE_TOOLTIP_NEQ": "враћа за вредност тачно ако су оба уноса различита.", "LOGIC_COMPARE_TOOLTIP_LT": "Враћа за вредност тачно ако је први унос мањи од другог уноса.", "LOGIC_COMPARE_TOOLTIP_LTE": "враћа за вредност тачно ако је први унос мањи или једнак другом уносу.", "LOGIC_COMPARE_TOOLTIP_GT": "Враћа за вредност тачно ако је први унос већи од другог уноса.", "LOGIC_COMPARE_TOOLTIP_GTE": "враћа за вредност тачно ако је први унос већи или једнак другом уносу.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Враћа за вредност тачно ако су оба уноса тачна.", "LOGIC_OPERATION_AND": "И", "LOGIC_OPERATION_TOOLTIP_OR": "враћа за вредност тачно ако је бар један од уноса тачан.", "LOGIC_OPERATION_OR": "или", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "није %1", "LOGIC_NEGATE_TOOLTIP": "Враћа за вредност тачно ако је унос нетачан. Враћа за вредност нетачно ако је унос тачан.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "тачно", "LOGIC_BOOLEAN_FALSE": "нетачно", "LOGIC_BOOLEAN_TOOLTIP": "враћа вредност или тачно или нетачно.", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "НИШТА", "LOGIC_NULL_TOOLTIP": "Враћа нулу.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "тест", "LOGIC_TERNARY_IF_TRUE": "ако је тачно", "LOGIC_TERNARY_IF_FALSE": "ако је нетачно", "LOGIC_TERNARY_TOOLTIP": "Провери услов у 'test'. Ако је услов тачан, тада враћа 'if true' вредност; у другом случају враћа 'if false' вредност.", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "Неки број.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "×", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "син", "MATH_TRIG_COS": "цос", "MATH_TRIG_TAN": "тан", "MATH_TRIG_ASIN": "арц син", "MATH_TRIG_ACOS": "арц цос", "MATH_TRIG_ATAN": "арц тан", "MATH_ARITHMETIC_HELPURL": "https://en.wikipedia.org/wiki/Arithmetic", "MATH_ARITHMETIC_TOOLTIP_ADD": "Вратите збир два броја.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Вратите разлику два броја.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Вратите производ два броја.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Вратите количник два броја.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Вратите први број подигнут на власт другог броја.", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "квадратни корен", "MATH_SINGLE_TOOLTIP_ROOT": "Вратити квадратни корен броја.", "MATH_SINGLE_OP_ABSOLUTE": "апсолутан", "MATH_SINGLE_TOOLTIP_ABS": "Вратите апсолутну вредност броја.", "MATH_SINGLE_TOOLTIP_NEG": "Враћа негативну вредност броја.", "MATH_SINGLE_TOOLTIP_LN": "Вратити природни логаритам броја.", "MATH_SINGLE_TOOLTIP_LOG10": "Враћа логаритам са базом 10 броја.", "MATH_SINGLE_TOOLTIP_EXP": "вратити е на власти броја.", "MATH_SINGLE_TOOLTIP_POW10": "Враћа 10-ти степен броја.", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "Вратите синус степена (не радијан).", "MATH_TRIG_TOOLTIP_COS": "Вратите косинус степена (не радијан).", "MATH_TRIG_TOOLTIP_TAN": "Вратите тангенс степена (не радијан).", "MATH_TRIG_TOOLTIP_ASIN": "Вратите аркус броја.", "MATH_TRIG_TOOLTIP_ACOS": "Вратити аркус косинуса броја.", "MATH_TRIG_TOOLTIP_ATAN": "Вратите аркус тангенс броја.", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "врати једну од заједничких константи: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), или ∞ (infinity).", "MATH_IS_EVEN": "је једнако", "MATH_IS_ODD": "је непарно", "MATH_IS_PRIME": "је прост", "MATH_IS_WHOLE": "цео је", "MATH_IS_POSITIVE": "је позитивно", "MATH_IS_NEGATIVE": "је негативно", "MATH_IS_DIVISIBLE_BY": "Је дељиво са", "MATH_IS_TOOLTIP": "Провјерава да ли је број паран, непаран, прост, цио, позитиван, негативан, или да ли је делјив са одређеним бројем. Враћа тачно или нетачно.", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "промени", "MATH_CHANGE_INPUT_BY": "по, за, од", "MATH_CHANGE_TOOLTIP": "додај број промењивој '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Заокружити број изнад или испод.", "MATH_ROUND_OPERATOR_ROUND": "Заокружити", "MATH_ROUND_OPERATOR_ROUNDUP": "Заокружити изнад", "MATH_ROUND_OPERATOR_ROUNDDOWN": "Заокружити испод", "MATH_ONLIST_HELPURL": "", "MATH_ONLIST_OPERATOR_SUM": "збир листе", "MATH_ONLIST_TOOLTIP_SUM": "Враћа суму свих бројева са листе.", "MATH_ONLIST_OPERATOR_MIN": "минимални са листе", "MATH_ONLIST_TOOLTIP_MIN": "Враћа најманји број са листе.", "MATH_ONLIST_OPERATOR_MAX": "Максимални са листе", "MATH_ONLIST_TOOLTIP_MAX": "Враћа највећи број са листе.", "MATH_ONLIST_OPERATOR_AVERAGE": "просечни са листе", "MATH_ONLIST_TOOLTIP_AVERAGE": "Враћа просјечну (аритметичку средину) нумеричких вредности са листе.", "MATH_ONLIST_OPERATOR_MEDIAN": "са средине листе", "MATH_ONLIST_TOOLTIP_MEDIAN": "Враћа среднји број са листе.", "MATH_ONLIST_OPERATOR_MODE": "облици листе", "MATH_ONLIST_TOOLTIP_MODE": "Враћа најчешћу ставку(е) са листе.", "MATH_ONLIST_OPERATOR_STD_DEV": "стандардна девиација листе", "MATH_ONLIST_TOOLTIP_STD_DEV": "Враћа стандардну девијацију листе.", "MATH_ONLIST_OPERATOR_RANDOM": "Насумична ставка са листе", "MATH_ONLIST_TOOLTIP_RANDOM": "Враћа насумично одабрани елемент са листе.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "подсетник од %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Вратити подсетник од дељења два броја.", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "Ограничи %1 ниско %2 високо %3", "MATH_CONSTRAIN_TOOLTIP": "Ограничити број да буде између одређених ограниченја (закључно).", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "сличајно одабрани цијели број од %1 до %2", "MATH_RANDOM_INT_TOOLTIP": "Враћа случајно одабрани цели број између две одређене границе, уклјучиво.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "Насумична функција", "MATH_RANDOM_FLOAT_TOOLTIP": "Враћа насумучно одабран дио између 0.0 (уклјучиво) и 1.0 (исклјучиво).", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "Слово, реч, линија текста.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "написати текст са", "TEXT_JOIN_TOOLTIP": "Направити дио текста спајајући различите ставке.", "TEXT_CREATE_JOIN_TITLE_JOIN": "придружити се", "TEXT_CREATE_JOIN_TOOLTIP": "Додај, уклони, или другачије поредај одјелке како би изнова поставили овај текст блок.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Додати ставку у текст.", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "како би", "TEXT_APPEND_APPENDTEXT": "закачити текст", "TEXT_APPEND_TOOLTIP": "додати неки текст варијабли '%1.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "дужина %1", "TEXT_LENGTH_TOOLTIP": "Враћа број слова (уклјучујући размаке) у датом тексту.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 је празно", "TEXT_ISEMPTY_TOOLTIP": "Враћа тачно ако је доставлјени текст празан.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Враћа однос првог/заднјег појавлјиванја текста у другом тексту. Врађа 0 ако текст није пронађен.", "TEXT_INDEXOF_INPUT_INTEXT": "у тексту", "TEXT_INDEXOF_OPERATOR_FIRST": "нађи прво појавлјиванје текста", "TEXT_INDEXOF_OPERATOR_LAST": "нађи заднје појавлјиванје текста", "TEXT_INDEXOF_TAIL": "", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "у тексту", "TEXT_CHARAT_FROM_START": "добити слово #", "TEXT_CHARAT_FROM_END": "добити сливо # са краја", "TEXT_CHARAT_FIRST": "добити прво слово", "TEXT_CHARAT_LAST": "Узми заднје слово", "TEXT_CHARAT_RANDOM": "насумично одабери слово", "TEXT_CHARAT_TAIL": "", "TEXT_CHARAT_TOOLTIP": "Враћа слово на одређену позицију.", "TEXT_GET_SUBSTRING_TOOLTIP": "Враћа одређен дио текста.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "у тексту", "TEXT_GET_SUBSTRING_START_FROM_START": "узмите низ од слова #", "TEXT_GET_SUBSTRING_START_FROM_END": "узмите низ од слова # од краја", "TEXT_GET_SUBSTRING_START_FIRST": "узмите низ од првог слова", "TEXT_GET_SUBSTRING_END_FROM_START": "слову #", "TEXT_GET_SUBSTRING_END_FROM_END": "слову # са краја", "TEXT_GET_SUBSTRING_END_LAST": "заднјем слову", "TEXT_GET_SUBSTRING_TAIL": "", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Враћа копију текста у другачијем случају.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "великим словима", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "малим словима", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "свака реч починје великим словом", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Враћа копију текста са уклонјеним простором са једног од два краја.", "TEXT_TRIM_OPERATOR_BOTH": "скратити простор са обе стране", "TEXT_TRIM_OPERATOR_LEFT": "скратити простор са леве стране", "TEXT_TRIM_OPERATOR_RIGHT": "скратити простор са десне стране", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_PRINT_TITLE": "принатати %1", "TEXT_PRINT_TOOLTIP": "Принтати одређени текст, број друге вредности.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "тражити текст са поруком", "TEXT_PROMPT_TYPE_NUMBER": "тражити број са поруком", "TEXT_PROMPT_TOOLTIP_NUMBER": "Питај корисника за број.", "TEXT_PROMPT_TOOLTIP_TEXT": "Питај корисника да ти да нешто текста.", "LISTS_CREATE_EMPTY_HELPURL": "https://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "креирај празну листу", "LISTS_CREATE_EMPTY_TOOLTIP": "враћа листу, дужине 0, не садржавајући евиденцију података", "LISTS_CREATE_WITH_TOOLTIP": "Креирај листу са било којим бројем ставки.", "LISTS_CREATE_WITH_INPUT_WITH": "креирај листу са", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "листа", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Додајте, избришите, или преуредите делове како би се реорганизовали овај блок листе.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Додај ставку листи.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "Прави листу која се састоји од задане вредности коју понавлјамо одређени број шута.", "LISTS_REPEAT_TITLE": "Направити листу са ставком %1 која се понавлја %2 пута", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "дужина од %1", "LISTS_LENGTH_TOOLTIP": "Враћа дужину листе.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 је празан", "LISTS_TOOLTIP": "Враћа вредност тачно ако је листа празна.", "LISTS_INLIST": "у листи", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "наћи прво појавлјиванје ставке", "LISTS_INDEX_OF_LAST": "наћи последнје појавлјиванје ставке", "LISTS_INDEX_OF_TOOLTIP": "Враћа однос првог/последнјег појавлјиванја ставке у листи. Враћа 0 ако се текст не наће.", "LISTS_GET_INDEX_GET": "узми", "LISTS_GET_INDEX_GET_REMOVE": "узми и уклони", "LISTS_GET_INDEX_REMOVE": "уклони", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# од краја", "LISTS_GET_INDEX_FIRST": "први", "LISTS_GET_INDEX_LAST": "последњи", "LISTS_GET_INDEX_RANDOM": "насумичан", "LISTS_GET_INDEX_TAIL": "", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Враћа ставку на одређену позицију на листи. #1 је прва ставка.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Враћа ставку на одређену позицију на листи. #1 је последња ставка.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Враћа прву ставку на листи.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Враћа последњу ставку у листи.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Враћа ставку из листе случајним одабиром.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Укланја и враћа ставку са одређене позиције са листе.#1 је прва ставка.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Укланја и враћа ставку са одређене позиције са листе.#1 је последнја ставка.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Укланја и враћа прву ставку са листе.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Укланја и враћа последнју ставку са листе.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Укланја и враћа насумићно одабрану ставку са листе.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Укланја ставку са одређене позиције на листи.#1 је прва ставка.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Укланја ставку са одређене позиције на листи.#1 је последнја ставка.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Уклања прву ставку на листи.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Уклања последнју ставку са листе.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Уклања насумичну ставку на листи.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "поставити", "LISTS_SET_INDEX_INSERT": "Убацити у", "LISTS_SET_INDEX_INPUT_TO": "као", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Убацује ставку на одређену позицију на листи.#1 је прва ставка.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Убацује ставку на одређену позицију на листи.#1 је последња ставка.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "подешава прву ставку у листи.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Убацује последњу ставку у листи.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Убацује-Подешава насумичну ставку на листи.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Убацује ставку на одређену позицију на листи.#1 је прва ставка.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Убацује ставку на одређену позицију на листи.#1 је последнја ставка.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Убацује ставку на почетак листе.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Вратити ставку на крај листе.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Убацује ставку на насумићно место на листи.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "узми под листу од #", "LISTS_GET_SUBLIST_START_FROM_END": "узми под-листу од # од краја", "LISTS_GET_SUBLIST_START_FIRST": "узмите под-листу од прве-ог", "LISTS_GET_SUBLIST_END_FROM_START": "до #", "LISTS_GET_SUBLIST_END_FROM_END": "до # од краја", "LISTS_GET_SUBLIST_END_LAST": "до последњег", "LISTS_GET_SUBLIST_TAIL": "", "LISTS_GET_SUBLIST_TOOLTIP": "Прави копију одређеног дела листе.", "ORDINAL_NUMBER_SUFFIX": "", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TITLE": "", "VARIABLES_GET_TAIL": "", "VARIABLES_GET_TOOLTIP": "Враћа вриједност варијабле.", "VARIABLES_GET_CREATE_SET": "Направити сет %1", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "поставити", "VARIABLES_SET_TAIL": "како би", "VARIABLES_SET_TOOLTIP": "Чини да варијабла буде једнака уносу.", "VARIABLES_SET_CREATE_GET": "Креирај добити %1", "PROCEDURES_DEFNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFNORETURN_TITLE": "како би", "PROCEDURES_DEFNORETURN_PROCEDURE": "урадити нешто", "PROCEDURES_BEFORE_PARAMS": "са:", "PROCEDURES_DEFNORETURN_DO": "", "PROCEDURES_DEFNORETURN_TOOLTIP": "Прави функцију без избациванја излазне вредности.", "PROCEDURES_DEFRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFRETURN_RETURN": "Вратити", "PROCEDURES_DEFRETURN_TOOLTIP": "Прави функцију са избациванјем излазне вредности.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Упозоренје: ова функција има дупле параметре.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_CALL": "", "PROCEDURES_CALLNORETURN_TOOLTIP": "Извршити функцију '%1' коју корисник дефинира.", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Извршити функцију '%1' коју корисник дефинира и користи резултат.", "PROCEDURES_MUTATORCONTAINER_TITLE": "улазне вредности", "PROCEDURES_MUTATORARG_TITLE": "Назив улазне вредности:", "PROCEDURES_HIGHLIGHT_DEF": "Истакнути дефиницију функције", "PROCEDURES_CREATE_DO": "Израчунати '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Ако је вредност тачна, врати другу вредност.", "PROCEDURES_IFRETURN_WARNING": "Упозоренје: овај се блок може користити једино ако постоји дефиниција функције." } ================================================ FILE: extern/blockly/msg/json/sv.json ================================================ { "@metadata": { "authors": [ "Jopparn", "WikiPhoenix" ] }, "VARIABLES_DEFAULT_NAME": "föremål", "DUPLICATE_BLOCK": "Duplicera", "ADD_COMMENT": "Lägg till kommentar", "REMOVE_COMMENT": "Radera kommentar", "EXTERNAL_INPUTS": "Externa inmatningar", "INLINE_INPUTS": "radinmatning", "DELETE_BLOCK": "Radera block", "DELETE_X_BLOCKS": "Radera %1 block", "COLLAPSE_BLOCK": "Fäll ihop block", "COLLAPSE_ALL": "Fäll ihop block", "EXPAND_BLOCK": "Expandera block", "EXPAND_ALL": "Expandera block", "DISABLE_BLOCK": "Inaktivera block", "ENABLE_BLOCK": "Aktivera block", "HELP": "Hjälp", "CHANGE_VALUE_TITLE": "Ändra värde:", "NEW_VARIABLE": "Ny variabel...", "NEW_VARIABLE_TITLE": "Nytt variabelnamn:", "RENAME_VARIABLE": "Byt namn på variabel...", "RENAME_VARIABLE_TITLE": "Byt namn på alla variablerna '%1' till:", "COLOUR_PICKER_HELPURL": "https://sv.wikipedia.org/wiki/Färg", "COLOUR_PICKER_TOOLTIP": "Välj en färg från paletten.", "COLOUR_RANDOM_TITLE": "slumpfärg", "COLOUR_RANDOM_TOOLTIP": "Välj en slumpartad färg.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "färg med", "COLOUR_RGB_RED": "röd", "COLOUR_RGB_GREEN": "grön", "COLOUR_RGB_BLUE": "blå", "COLOUR_RGB_TOOLTIP": "Skapa en färg med det angivna mängden röd, grön och blå. Alla värden måste vara mellan 0 och 100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "blanda", "COLOUR_BLEND_COLOUR1": "färg 1", "COLOUR_BLEND_COLOUR2": "färg 2", "COLOUR_BLEND_RATIO": "förhållande", "COLOUR_BLEND_TOOLTIP": "Blandar ihop två färger med ett bestämt förhållande (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "upprepa %1 gånger", "CONTROLS_REPEAT_TITLE_REPEAT": "upprepa", "CONTROLS_REPEAT_TITLE_TIMES": "gånger", "CONTROLS_REPEAT_INPUT_DO": "utför", "CONTROLS_REPEAT_TOOLTIP": "Utför några kommandon flera gånger.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "upprepa medan", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "upprepa tills", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Medan ett värde är sant, utför några kommandon.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Medan ett värde är falskt, utför några kommandon.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Låt variabeln %1 ta värden från starttalet till sluttalet, beräknat med det angivna intervallet, och utför de angivna blocken.", "CONTROLS_FOR_INPUT_WITH": "räkna med", "CONTROLS_FOR_INPUT_FROM_TO_BY": "från %1 till %2 med %3", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each för \"varje\"-block", "CONTROLS_FOREACH_INPUT_ITEM": "för varje föremål", "CONTROLS_FOREACH_INPUT_INLIST": "i listan", "CONTROLS_FOREACH_TOOLTIP": "För varje objekt i en lista, ange variabeln '%1' till objektet, och utför sedan några kommandon.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "bryt ut ur upprepning", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "fortsätta med nästa upprepning av loop", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Bryta ut ur den innehållande upprepningen.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Hoppa över resten av denna upprepning och fortsätt med nästa upprepning.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Varning: Detta block kan endast användas i en upprepning.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "Om ett värde är sant, utför några kommandon.", "CONTROLS_IF_TOOLTIP_2": "Om värdet är sant, utför det första kommandoblocket. Annars utför det andra kommandoblocket.", "CONTROLS_IF_TOOLTIP_3": "Om det första värdet är sant, utför det första kommandoblocket. Annars, om det andra värdet är sant, utför det andra kommandoblocket.", "CONTROLS_IF_TOOLTIP_4": "Om det första värdet är sant, utför det första kommandoblocket. Annars, om det andra värdet är sant, utför det andra kommandoblocket. Om ingen av värdena är sanna, utför det sista kommandoblocket.", "CONTROLS_IF_MSG_IF": "om", "CONTROLS_IF_MSG_ELSEIF": "annars om", "CONTROLS_IF_MSG_ELSE": "annars", "CONTROLS_IF_IF_TOOLTIP": "Lägg till, ta bort eller ändra ordningen för sektioner för att omkonfigurera blocket \"om\".", "CONTROLS_IF_ELSEIF_TOOLTIP": "Lägg till ett villkor blocket \"om\".", "CONTROLS_IF_ELSE_TOOLTIP": "Lägg till ett sista villkor som täcker alla alternativ som är kvar för \"if\"-blocket.", "LOGIC_COMPARE_HELPURL": "https://sv.wikipedia.org/wiki/Olikhet", "LOGIC_COMPARE_TOOLTIP_EQ": "Ger tillbaka sant om båda värdena är lika med varandra.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Ger tillbaka sant om båda värdena inte är lika med varandra.", "LOGIC_COMPARE_TOOLTIP_LT": "Ger tillbaka sant om den första värdet är mindre än det andra.", "LOGIC_COMPARE_TOOLTIP_LTE": "Ger tillbaka sant om den första värdet är mindre än eller lika med det andra.", "LOGIC_COMPARE_TOOLTIP_GT": "Ger tillbaka sant om den första värdet är större än det andra.", "LOGIC_COMPARE_TOOLTIP_GTE": "Ger tillbaka sant om den första värdet är större än eller lika med det andra.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Ger tillbaka sant om båda värdena är sanna.", "LOGIC_OPERATION_AND": "och", "LOGIC_OPERATION_TOOLTIP_OR": "Ger tillbaka sant om minst ett av värdena är sant.", "LOGIC_OPERATION_OR": "eller", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "inte %1", "LOGIC_NEGATE_TOOLTIP": "Ger tillbaka sant om inmatningen är falsk. Ger tillbaka falskt och inmatningen är sann.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "sant", "LOGIC_BOOLEAN_FALSE": "falskt", "LOGIC_BOOLEAN_TOOLTIP": "Returnerar antingen sant eller falskt.", "LOGIC_NULL_HELPURL": "https://sv.wikipedia.org/wiki/Null", "LOGIC_NULL": "null", "LOGIC_NULL_TOOLTIP": "Returnerar null.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "om sant", "LOGIC_TERNARY_IF_FALSE": "om falskt", "LOGIC_TERNARY_TOOLTIP": "Kontrollera villkoret i \"test\". Om villkoret är sant, ge tillbaka \"om sant\"-värdet; annars ge tillbaka \"om falskt\"-värdet.", "MATH_NUMBER_HELPURL": "https://sv.wikipedia.org/wiki/Tal", "MATH_NUMBER_TOOLTIP": "Ett tal.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "×", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "arcsin", "MATH_TRIG_ACOS": "arccos", "MATH_TRIG_ATAN": "arctan", "MATH_ARITHMETIC_HELPURL": "https://sv.wikipedia.org/wiki/Aritmetik", "MATH_ARITHMETIC_TOOLTIP_ADD": "Returnerar summan av de två talen.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Returnerar differensen mellan de två talen.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Returnerar produkten av de två talen.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Returnerar kvoten av de två talen.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Ger tillbaka det första talet upphöjt till det andra talet.", "MATH_SINGLE_HELPURL": "https://sv.wikipedia.org/wiki/Kvadratrot", "MATH_SINGLE_OP_ROOT": "kvadratrot", "MATH_SINGLE_TOOLTIP_ROOT": "Returnerar kvadratroten av ett tal.", "MATH_SINGLE_OP_ABSOLUTE": "absolut", "MATH_SINGLE_TOOLTIP_ABS": "Returnerar absolutvärdet av ett tal.", "MATH_SINGLE_TOOLTIP_NEG": "Returnerar negationen av ett tal.", "MATH_SINGLE_TOOLTIP_LN": "Returnera den naturliga logaritmen av ett tal.", "MATH_SINGLE_TOOLTIP_LOG10": "Returnerar logaritmen för bas 10 av ett tal.", "MATH_SINGLE_TOOLTIP_EXP": "Ger tillbaka e upphöjt i ett tal.", "MATH_SINGLE_TOOLTIP_POW10": "Ger tillbaka 10 upphöjt i ett tal.", "MATH_TRIG_HELPURL": "https://sv.wikipedia.org/wiki/Trigonometrisk_funktion", "MATH_TRIG_TOOLTIP_SIN": "Ger tillbaka sinus för en grad (inte radian).", "MATH_TRIG_TOOLTIP_COS": "Ger tillbaka cosinus för en grad (inte radian).", "MATH_TRIG_TOOLTIP_TAN": "Ger tillbaka tangens för en grad (inte radian).", "MATH_TRIG_TOOLTIP_ASIN": "Ger tillbaka arcus sinus (arcsin) för ett tal.", "MATH_TRIG_TOOLTIP_ACOS": "Ger tillbaka arcus cosinus (arccos) för ett tal.", "MATH_TRIG_TOOLTIP_ATAN": "Ger tillbaka arcus tangens (arctan) av ett tal.", "MATH_CONSTANT_HELPURL": "https://sv.wikipedia.org/wiki/Matematisk_konstant", "MATH_CONSTANT_TOOLTIP": "Returnerar en av de vanliga konstanterna: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…) eller ∞ (oändligt).", "MATH_IS_EVEN": "är jämnt", "MATH_IS_ODD": "är ojämnt", "MATH_IS_PRIME": "är ett primtal", "MATH_IS_WHOLE": "är helt", "MATH_IS_POSITIVE": "är positivt", "MATH_IS_NEGATIVE": "är negativt", "MATH_IS_DIVISIBLE_BY": "är delbart med", "MATH_IS_TOOLTIP": "Kontrollera om ett tal är jämnt, ojämnt, helt, positivt, negativt eller det är delbart med ett bestämt tal. Returnerar med sant eller falskt.", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "ändra", "MATH_CHANGE_INPUT_BY": "med", "MATH_CHANGE_TOOLTIP": "Lägg till ett tal till variabeln '%1'.", "MATH_ROUND_HELPURL": "https://sv.wikipedia.org/wiki/Avrundning", "MATH_ROUND_TOOLTIP": "Avrunda ett tal uppåt eller nedåt.", "MATH_ROUND_OPERATOR_ROUND": "avrunda", "MATH_ROUND_OPERATOR_ROUNDUP": "avrunda uppåt", "MATH_ROUND_OPERATOR_ROUNDDOWN": "avrunda nedåt", "MATH_ONLIST_OPERATOR_SUM": "summan av listan", "MATH_ONLIST_TOOLTIP_SUM": "Ger tillbaka summan av alla talen i listan.", "MATH_ONLIST_OPERATOR_MIN": "minsta talet i listan", "MATH_ONLIST_TOOLTIP_MIN": "Ger tillbaka det minsta talet i listan.", "MATH_ONLIST_OPERATOR_MAX": "högsta talet i listan", "MATH_ONLIST_TOOLTIP_MAX": "Ger tillbaka det största talet i listan.", "MATH_ONLIST_OPERATOR_AVERAGE": "medelvärdet av listan", "MATH_ONLIST_TOOLTIP_AVERAGE": "Ger tillbaka medelvärdet (aritmetiskt) av de numeriska värdena i listan.", "MATH_ONLIST_OPERATOR_MEDIAN": "medianen av listan", "MATH_ONLIST_TOOLTIP_MEDIAN": "Returnerar medianen av talen i listan.", "MATH_ONLIST_OPERATOR_MODE": "typvärdet i listan", "MATH_ONLIST_TOOLTIP_MODE": "Ger tillbaka en lista med de(t) vanligaste objekte(t/n) i listan.", "MATH_ONLIST_OPERATOR_STD_DEV": "standardavvikelsen i listan", "MATH_ONLIST_TOOLTIP_STD_DEV": "Ger tillbaka standardavvikelsen i listan.", "MATH_ONLIST_OPERATOR_RANDOM": "slumpmässigt objekt i listan", "MATH_ONLIST_TOOLTIP_RANDOM": "Returnerar ett slumpmässigt element från listan.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "resten av %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Returnerar kvoten från divisionen av de två talen.", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "begränsa %1 till mellan %2 och %3", "MATH_CONSTRAIN_TOOLTIP": "Begränsa ett tal till att mellan de angivna gränsvärden (inklusive).", "MATH_RANDOM_INT_HELPURL": "https://sv.wikipedia.org/wiki/Slumptalsgenerator", "MATH_RANDOM_INT_TITLE": "slumpartat heltal från %1 till %2", "MATH_RANDOM_INT_TOOLTIP": "Ger tillbaka ett slumpat heltal mellan två värden (inklusive).", "MATH_RANDOM_FLOAT_HELPURL": "https://sv.wikipedia.org/wiki/Slumptalsgenerator", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "slumpat decimaltal", "MATH_RANDOM_FLOAT_TOOLTIP": "Ger tillbaka ett slumpat decimaltal mellan 0.0 (inkluderat) och 1.0 (exkluderat).", "TEXT_TEXT_HELPURL": "https://sv.wikipedia.org/wiki/Str%C3%A4ng_%28data%29", "TEXT_TEXT_TOOLTIP": "En bokstav, ord eller textrad.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "skapa text med", "TEXT_JOIN_TOOLTIP": "Skapa en textbit genom att sammanfoga ett valfritt antal föremål.", "TEXT_CREATE_JOIN_TITLE_JOIN": "sammanfoga", "TEXT_CREATE_JOIN_TOOLTIP": "Lägg till, ta bort eller ändra ordningen för sektioner för att omkonfigurera detta textblock.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Lägg till ett föremål till texten.", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "till", "TEXT_APPEND_APPENDTEXT": "lägg till text", "TEXT_APPEND_TOOLTIP": "Lägg till lite text till variabeln '%1'.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "längden på %1", "TEXT_LENGTH_TOOLTIP": "Ger tillbaka antalet bokstäver (inklusive mellanslag) i den angivna texten.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 är tom", "TEXT_ISEMPTY_TOOLTIP": "Returnerar sant om den angivna texten är tom.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Ger tillbaka indexet för den första/sista förekomsten av första texten i den andra texten. Ger tillbaka 0 om texten inte hittas.", "TEXT_INDEXOF_INPUT_INTEXT": "i texten", "TEXT_INDEXOF_OPERATOR_FIRST": "hitta första förekomsten av texten", "TEXT_INDEXOF_OPERATOR_LAST": "hitta sista förekomsten av texten", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "i texten", "TEXT_CHARAT_FROM_START": "hämta bokstaven #", "TEXT_CHARAT_FROM_END": "hämta bokstaven # från slutet", "TEXT_CHARAT_FIRST": "hämta första bokstaven", "TEXT_CHARAT_LAST": "hämta sista bokstaven", "TEXT_CHARAT_RANDOM": "hämta slumpad bokstav", "TEXT_CHARAT_TOOLTIP": "Ger tillbaka bokstaven på den specificerade positionen.", "TEXT_GET_SUBSTRING_TOOLTIP": "Ger tillbaka en viss del av texten.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "i texten", "TEXT_GET_SUBSTRING_START_FROM_START": "få textdel från bokstav #", "TEXT_GET_SUBSTRING_START_FROM_END": "få textdel från bokstav # från slutet", "TEXT_GET_SUBSTRING_START_FIRST": "få textdel från första bokstaven", "TEXT_GET_SUBSTRING_END_FROM_START": "till bokstav #", "TEXT_GET_SUBSTRING_END_FROM_END": "till bokstav # från slutet", "TEXT_GET_SUBSTRING_END_LAST": "till sista bokstaven", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Returnerar en kopia av texten i ett annat skiftläge.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "till VERSALER", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "till gemener", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "till Versala Initialer", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Returnerar en kopia av texten med borttagna mellanrum från en eller båda ändar.", "TEXT_TRIM_OPERATOR_BOTH": "ta bort mellanrum från båda sidorna av", "TEXT_TRIM_OPERATOR_LEFT": "ta bort mellanrum från vänstra sidan av", "TEXT_TRIM_OPERATOR_RIGHT": "ta bort mellanrum från högra sidan av", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "skriv %1", "TEXT_PRINT_TOOLTIP": "Skriv den angivna texten, talet eller annat värde.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "fråga efter text med meddelande", "TEXT_PROMPT_TYPE_NUMBER": "fråga efter ett tal med meddelande", "TEXT_PROMPT_TOOLTIP_NUMBER": "Fråga användaren efter ett tal.", "TEXT_PROMPT_TOOLTIP_TEXT": "Fråga användaren efter lite text.", "LISTS_CREATE_EMPTY_HELPURL": "https://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "skapa tom lista", "LISTS_CREATE_EMPTY_TOOLTIP": "Ger tillbaka en lista utan någon data, alltså med längden 0", "LISTS_CREATE_WITH_TOOLTIP": "Skapa en lista med valfritt antal föremål.", "LISTS_CREATE_WITH_INPUT_WITH": "skapa lista med", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "lista", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Lägg till, ta bort eller ändra ordningen på objekten för att göra om det här \"list\"-blocket.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Lägg till ett föremål till listan.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "Skapar en lista som innehåller ett valt värde upprepat ett bestämt antalet gånger.", "LISTS_REPEAT_TITLE": "skapa lista med föremålet %1 upprepat %2 gånger", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "längden på %1", "LISTS_LENGTH_TOOLTIP": "Returnerar längden på en lista.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 är tom", "LISTS_TOOLTIP": "Returnerar sant om listan är tom.", "LISTS_INLIST": "i listan", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "hitta första förekomsten av objektet", "LISTS_INDEX_OF_LAST": "hitta sista förekomsten av objektet", "LISTS_INDEX_OF_TOOLTIP": "Ger tillbaka den första/sista förekomsten av objektet i listan. Ger tillbaka 0 om texten inte hittas.", "LISTS_GET_INDEX_GET": "hämta", "LISTS_GET_INDEX_GET_REMOVE": "hämta och ta bort", "LISTS_GET_INDEX_REMOVE": "ta bort", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# från slutet", "LISTS_GET_INDEX_FIRST": "första", "LISTS_GET_INDEX_LAST": "sista", "LISTS_GET_INDEX_RANDOM": "slumpad", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Ger tillbaka objektet på den efterfrågade positionen i en lista. #1 är det första objektet.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Ger tillbaka objektet på den efterfrågade positionen i en lista. #1 är det sista objektet.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Returnerar det första objektet i en lista.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Returnerar det sista objektet i en lista.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Returnerar ett slumpmässigt objekt i en lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Tar bort och återställer objektet på den specificerade positionen i en lista. #1 är det första objektet.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Tar bort och återställer objektet på den specificerade positionen i en lista. #1 är det sista objektet.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Tar bort och återställer det första objektet i en lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Tar bort och återställer det sista objektet i en lista.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Tar bort och återställer ett slumpmässigt objekt i en lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Tar bort objektet på den specificerade positionen i en lista. #1 är det första objektet.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Tar bort objektet på den efterfrågade positionen i en lista. #1 är det sista objektet.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Tar bort det första objektet i en lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Tar bort det sista objektet i en lista.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Tar bort en slumpmässig post i en lista.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "ange", "LISTS_SET_INDEX_INSERT": "Sätt in vid", "LISTS_SET_INDEX_INPUT_TO": "som", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Sätter in objektet vid en specificerad position i en lista. #1 är det första objektet.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Sätter in objektet vid en specificerad position i en lista. #1 är det sista objektet.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Anger det första objektet i en lista.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Anger det sista elementet i en lista.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Sätter in ett slumpat objekt i en lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Sätter in objektet vid en specificerad position i en lista. #1 är det första objektet.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "sätter in objektet vid en specificerad position i en lista. #1 är det sista objektet.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "sätter in objektet i början av en lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Lägg till objektet i slutet av en lista.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "sätter in objektet på en slumpad position i en lista.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "få underlista från #", "LISTS_GET_SUBLIST_START_FROM_END": "få underlista från # från slutet", "LISTS_GET_SUBLIST_START_FIRST": "få underlista från första", "LISTS_GET_SUBLIST_END_FROM_START": "till #", "LISTS_GET_SUBLIST_END_FROM_END": "till # från slutet", "LISTS_GET_SUBLIST_END_LAST": "till sista", "LISTS_GET_SUBLIST_TOOLTIP": "Skapar en kopia av den specificerade delen av en lista.", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TOOLTIP": "Returnerar värdet av denna variabel.", "VARIABLES_GET_CREATE_SET": "Skapa \"välj %1\"", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "välj", "VARIABLES_SET_TAIL": "till", "VARIABLES_SET_TOOLTIP": "Gör så att den här variabeln blir lika med inputen.", "VARIABLES_SET_CREATE_GET": "Skapa 'hämta %1'", "PROCEDURES_DEFNORETURN_HELPURL": "https://sv.wikipedia.org/wiki/Funktion_%28programmering%29", "PROCEDURES_DEFNORETURN_TITLE": "för att", "PROCEDURES_DEFNORETURN_PROCEDURE": "göra något", "PROCEDURES_BEFORE_PARAMS": "med:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Skapar en funktion utan output.", "PROCEDURES_DEFRETURN_HELPURL": "https://sv.wikipedia.org/wiki/Funktion_%28programmering%29", "PROCEDURES_DEFRETURN_RETURN": "returnera", "PROCEDURES_DEFRETURN_TOOLTIP": "Skapar en funktion med output.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Varning: Denna funktion har dubbla parametrar.", "PROCEDURES_CALLNORETURN_HELPURL": "https://sv.wikipedia.org/wiki/Funktion_%28programmering%29", "PROCEDURES_CALLNORETURN_TOOLTIP": "Kör den användardefinierade funktionen \"%1\".", "PROCEDURES_CALLRETURN_HELPURL": "https://sv.wikipedia.org/wiki/Funktion_%28programmering%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Kör den användardefinierade funktionen \"%1\" och använd resultatet av den.", "PROCEDURES_MUTATORCONTAINER_TITLE": "inmatningar", "PROCEDURES_MUTATORARG_TITLE": "inmatningsnamn:", "PROCEDURES_HIGHLIGHT_DEF": "Markera funktionsdefinition", "PROCEDURES_CREATE_DO": "Skapa '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "Om ett värde är sant returneras ett andra värde.", "PROCEDURES_IFRETURN_WARNING": "Varning: Detta block får användas endast i en funktionsdefinition." } ================================================ FILE: extern/blockly/msg/json/synonyms.json ================================================ {"PROCEDURES_DEFRETURN_TITLE": "PROCEDURES_DEFNORETURN_TITLE", "LISTS_GET_SUBLIST_INPUT_IN_LIST": "LISTS_INLIST", "LISTS_SET_INDEX_INPUT_IN_LIST": "LISTS_INLIST", "PROCEDURES_DEFRETURN_PROCEDURE": "PROCEDURES_DEFNORETURN_PROCEDURE", "VARIABLES_SET_ITEM": "VARIABLES_DEFAULT_NAME", "LISTS_CREATE_WITH_ITEM_TITLE": "VARIABLES_DEFAULT_NAME", "CONTROLS_IF_ELSE_TITLE_ELSE": "CONTROLS_IF_MSG_ELSE", "VARIABLES_GET_ITEM": "VARIABLES_DEFAULT_NAME", "PROCEDURES_DEFRETURN_DO": "PROCEDURES_DEFNORETURN_DO", "LISTS_GET_INDEX_HELPURL": "LISTS_INDEX_OF_HELPURL", "TEXT_CREATE_JOIN_ITEM_TITLE_ITEM": "VARIABLES_DEFAULT_NAME", "CONTROLS_IF_MSG_THEN": "CONTROLS_REPEAT_INPUT_DO", "LISTS_INDEX_OF_INPUT_IN_LIST": "LISTS_INLIST", "PROCEDURES_CALLRETURN_CALL": "PROCEDURES_CALLNORETURN_CALL", "LISTS_GET_INDEX_INPUT_IN_LIST": "LISTS_INLIST", "CONTROLS_IF_ELSEIF_TITLE_ELSEIF": "CONTROLS_IF_MSG_ELSEIF", "CONTROLS_FOREACH_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO", "CONTROLS_IF_IF_TITLE_IF": "CONTROLS_IF_MSG_IF", "CONTROLS_WHILEUNTIL_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO", "CONTROLS_FOR_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO", "TEXT_APPEND_VARIABLE": "VARIABLES_DEFAULT_NAME", "MATH_CHANGE_TITLE_ITEM": "VARIABLES_DEFAULT_NAME"} ================================================ FILE: extern/blockly/msg/json/th.json ================================================ { "@metadata": { "authors": [ "Azpirin" ] }, "VARIABLES_DEFAULT_NAME": "รายการ", "DUPLICATE_BLOCK": "สร้างซ้ำ", "ADD_COMMENT": "ใส่คำอธิบาย", "REMOVE_COMMENT": "เอาคำอธิบายออก", "EXTERNAL_INPUTS": "อินพุตภายนอก", "INLINE_INPUTS": "อินพุตแบบอินไลน์", "DELETE_BLOCK": "ลบบล็อก", "DELETE_X_BLOCKS": "ลบ %1 บล็อก", "COLLAPSE_BLOCK": "ย่อบล็อก", "COLLAPSE_ALL": "ย่อบล็อก", "EXPAND_BLOCK": "ขยายบล็อก", "EXPAND_ALL": "ขยายบล็อก", "DISABLE_BLOCK": "ปิดการทำงานของบล็อกนี้", "ENABLE_BLOCK": "เปิดการทำงานของบล็อกนี้", "HELP": "ช่วยเหลือ", "CHANGE_VALUE_TITLE": "เปลี่ยนค่า:", "NEW_VARIABLE": "สร้างตัวแปรใหม่", "NEW_VARIABLE_TITLE": "ชื่อตัวแปร:", "RENAME_VARIABLE": "เปลี่ยนชื่อตัวแปร...", "RENAME_VARIABLE_TITLE": "เปลี่ยนชื่อ \"%1\" เป็น:", "COLOUR_PICKER_HELPURL": "https://th.wikipedia.org/wiki/สี", "COLOUR_PICKER_TOOLTIP": "เลือกสีจากจานสี", "COLOUR_RANDOM_TITLE": "สุ่มสี", "COLOUR_RANDOM_TOOLTIP": "เลือกสีแบบสุ่ม", "COLOUR_RGB_TITLE": "สีที่ประกอบด้วย", "COLOUR_RGB_RED": "ค่าสีแดง", "COLOUR_RGB_GREEN": "ค่าสีเขียว", "COLOUR_RGB_BLUE": "ค่าสีน้ำเงิน", "COLOUR_RGB_TOOLTIP": "สร้างสีด้วยการกำหนดค่าของสีแดง เขียว และน้ำเงิน โดยต้องเป็นค่าระหว่าง 0 จนถึง 100", "COLOUR_BLEND_TITLE": "ผสม", "COLOUR_BLEND_COLOUR1": "สีที่ 1", "COLOUR_BLEND_COLOUR2": "สีที่ 2", "COLOUR_BLEND_RATIO": "อัตราส่วน", "COLOUR_BLEND_TOOLTIP": "ผสมสีทั้งสองเข้าด้วยกันด้วยอัตราส่วน (0.0 - 1.0)", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "ทำซ้ำ %1 ครั้ง", "CONTROLS_REPEAT_TITLE_REPEAT": "ทำซ้ำ", "CONTROLS_REPEAT_TITLE_TIMES": "ครั้ง", "CONTROLS_REPEAT_INPUT_DO": "ทำ:", "CONTROLS_REPEAT_TOOLTIP": "ทำซ้ำคำสั่งตามจำนวนครั้งที่กำหนด", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "ทำซ้ำ ตราบใดที่", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "ทำซ้ำ จนกว่าจะ", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "ถ้าเงื่อนไขเป็นจริง ก็จะทำตามคำสั่งที่กำหนด", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "ถ้าเงื่อนไขเป็นเท็จ ก็จะทำตามคำสั่งที่กำหนด", "CONTROLS_FOR_TOOLTIP": "ตัวแปร \"%1\" จะมีค่าตั้งแต่จำนวนเริ่มต้น ไปจนถึงจำนวนสิ้นสุด โดยมีการเปลี่ยนแปลงตามจำนวนที่กำหนด", "CONTROLS_FOR_INPUT_WITH": "นับ", "CONTROLS_FOR_INPUT_FROM_TO_BY": "จาก %1 จนถึง %2 เปลี่ยนค่าทีละ %3", "CONTROLS_FOREACH_INPUT_ITEM": "วนซ้ำทุกรายการ", "CONTROLS_FOREACH_INPUT_INLIST": "ในรายการ", "CONTROLS_FOREACH_TOOLTIP": "ทำซ้ำทุกรายการ กำหนดค่าตัวแปร \"%1\" ตามรายการ และทำตามคำสั่งที่กำหนดไว้", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "ออกจากการวนซ้ำ", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "เริ่มการวนซ้ำรอบต่อไป", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "ออกจากการวนซ้ำที่มีอยู่", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "ข้ามสิ่งที่เหลืออยู่ และไปเริ่มวนซ้ำรอบต่อไปทันที", "CONTROLS_FLOW_STATEMENTS_WARNING": "ระวัง: บล็อกชนิดนี้สามารถใช้งานได้เมื่ออยู่ภายในการวนซ้ำเท่านั้น", "CONTROLS_IF_TOOLTIP_1": "ว่าเงื่อนไขเป็นจริง ก็จะ \"ทำ\" ตามที่กำหนด", "CONTROLS_IF_TOOLTIP_2": "ถ้าเงื่อนไขเป็นจริง ก็จะ \"ทำ\" ตามที่กำหนด แต่ถ้าเงื่อนไขเป็นเท็จก็จะทำ \"นอกเหนือจากนี้\"", "CONTROLS_IF_TOOLTIP_3": "ถ้าเงื่อนไขแรกเป็นจริง ก็จะทำตามคำสั่งในบล็อกแรก แต่ถ้าไม่ก็จะไปตรวจเงื่อนไขที่สอง ถ้าเงื่อนไขที่สองเป็นจริง ก็จะทำตามเงื่อนไขในบล็อกที่สองนี้", "CONTROLS_IF_TOOLTIP_4": "ถ้าเงื่อนไขแรกเป็นจริง ก็จะทำคำสั่งในบล็อกแรก จากนั้นจะข้ามคำสั่งในบล็อกที่เหลือ แต่ถ้าเงื่อนไขแรกเป็นเท็จ ก็จะทำการตรวจเงื่อนไขที่สอง ถ้าเงื่อนไขที่สองเป็นจริง ก็จะทำตามคำสั่งในบล็อกที่สอง จากนั้นจะข้ามคำสั่งในบล็อกที่เหลือ แต่ถ้าทั้งเงื่อนไขแรกและเงื่อนไขที่สองเป็นเท็จทั้งหมด ก็จะมาทำบล็อกที่สาม", "CONTROLS_IF_MSG_IF": "ถ้า", "CONTROLS_IF_MSG_ELSEIF": "นอกเหนือจากนี้ ถ้า", "CONTROLS_IF_MSG_ELSE": "นอกเหนือจากนี้", "CONTROLS_IF_IF_TOOLTIP": "เพิ่ม ลบ หรือจัดเรียงบล็อก \"ถ้า\" นี้ใหม่", "CONTROLS_IF_ELSEIF_TOOLTIP": "กำหนดเงื่อนไขของบล็อก \"ถ้า\"", "CONTROLS_IF_ELSE_TOOLTIP": "เพิ่มสิ่งสุดท้าย ที่จะตรวจจับความเป็นไปได้ทั้งหมดของบล็อก \"ถ้า\"", "LOGIC_COMPARE_HELPURL": "https://th.wikipedia.org/wiki/อสมการ", "LOGIC_COMPARE_TOOLTIP_EQ": "คืนค่าเป็น \"จริง\" ถ้าค่าที่ใส่ทั้งสองค่านั้นเท่ากัน", "LOGIC_COMPARE_TOOLTIP_NEQ": "คืนค่าเป็น \"จริง\" ถ้าค่าที่ใส่ทั้งสองค่านั้นไม่เท่ากัน", "LOGIC_COMPARE_TOOLTIP_LT": "คืนค่าเป็น \"จริง\" ถ้าค่าแรกน้อยกว่าค่าที่สอง", "LOGIC_COMPARE_TOOLTIP_LTE": "คืนค่าเป็น \"จริง\" ถ้าค่าแรกน้อยกว่าหรือเท่ากับค่าที่สอง", "LOGIC_COMPARE_TOOLTIP_GT": "คืนค่าเป็น \"จริง\" ถ้าค่าแรกมากกว่าค่าที่สอง", "LOGIC_COMPARE_TOOLTIP_GTE": "คืนค่าเป็น \"จริง\" ถ้าค่าแรกมากกว่าหรือเท่ากับค่าที่สอง", "LOGIC_OPERATION_TOOLTIP_AND": "คืนค่าเป็น \"จริง\" ถ้าค่าทั้งสองค่าเป็นจริง", "LOGIC_OPERATION_AND": "และ", "LOGIC_OPERATION_TOOLTIP_OR": "คืนค่าเป็น \"จริง\" ถ้ามีอย่างน้อยหนึ่งค่าที่เป็นจริง", "LOGIC_OPERATION_OR": "หรือ", "LOGIC_NEGATE_TITLE": "ไม่ %1", "LOGIC_NEGATE_TOOLTIP": "คืนค่าเป็น \"จริง\" ถ้าค่าที่ใส่เป็นเท็จ\nคืนค่าเป็น \"เท็จ\" ถ้าค่าที่ใส่เป็นจริง", "LOGIC_BOOLEAN_TRUE": "จริง", "LOGIC_BOOLEAN_FALSE": "เท็จ", "LOGIC_BOOLEAN_TOOLTIP": "คืนค่าเป็นจริงหรือเท็จ", "LOGIC_NULL": "ไม่กำหนด", "LOGIC_NULL_TOOLTIP": "คืนค่า \"ไม่กำหนด\"", "LOGIC_TERNARY_CONDITION": "ทดสอบ", "LOGIC_TERNARY_IF_TRUE": "ถ้า เป็นจริง", "LOGIC_TERNARY_IF_FALSE": "ถ้า เป็นเท็จ", "LOGIC_TERNARY_TOOLTIP": "ตรวจสอบเงื่อนไขใน \"ทดสอบ\" ถ้าเงื่อนไขเป็นจริง จะคืนค่า \"ถ้า เป็นจริง\" ถ้าเงื่อนไขเป็นเท็จ จะคืนค่า \"ถ้า เป็นเท็จ\"", "MATH_NUMBER_HELPURL": "https://th.wikipedia.org/wiki/จำนวน", "MATH_NUMBER_TOOLTIP": "จำนวน", "MATH_ARITHMETIC_HELPURL": "https://th.wikipedia.org/wiki/เลขคณิต", "MATH_ARITHMETIC_TOOLTIP_ADD": "คืนค่าผลรวมของตัวเลขทั้งสองจำนวน", "MATH_ARITHMETIC_TOOLTIP_MINUS": "คืนค่าผลต่างของตัวเลขทั้งสองจำนวน", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "คืนค่าผลคูณของตัวเลขทั้งสองจำนวน", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "คืนค่าผลหารของตัวเลขทั้งสองจำนวน", "MATH_ARITHMETIC_TOOLTIP_POWER": "คืนค่าผลการยกกำลัง โดยตัวเลขแรกเป็นฐาน และตัวเลขที่สองเป็นเลขชี้กำลัง", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "รากที่สอง", "MATH_SINGLE_TOOLTIP_ROOT": "คืนค่ารากที่สองของตัวเลข", "MATH_SINGLE_OP_ABSOLUTE": "ค่าสัมบูรณ์", "MATH_SINGLE_TOOLTIP_ABS": "คืนค่าค่าสัมบูรณ์ของตัวเลข", "MATH_SINGLE_TOOLTIP_NEG": "คืนค่าติดลบของตัวเลข", "MATH_SINGLE_TOOLTIP_LN": "คืนค่าลอการิทึมธรรมชาติของตัวเลข", "MATH_SINGLE_TOOLTIP_LOG10": "คืนค่าลอการิทึมฐานสิบของตัวเลข", "MATH_SINGLE_TOOLTIP_EXP": "คืนค่า e ยกกำลังด้วยตัวเลข", "MATH_SINGLE_TOOLTIP_POW10": "คืนค่า 10 ยกกำลังด้วยตัวเลข", "MATH_TRIG_HELPURL": "https://th.wikipedia.org/wiki/ฟังก์ชันตรีโกณมิติ", "MATH_TRIG_TOOLTIP_SIN": "คืนค่า sine ขององศา (ไม่ใช่เรเดียน)", "MATH_TRIG_TOOLTIP_COS": "คืนค่า cosine ขององศา (ไม่ใช่เรเดียน)", "MATH_TRIG_TOOLTIP_TAN": "คืนค่า tangent ขององศา (ไม่ใช่เรเดียน)", "MATH_TRIG_TOOLTIP_ASIN": "คืนค่า arcsine ของตัวเลข", "MATH_TRIG_TOOLTIP_ACOS": "คืนค่า arccosine ของตัวเลข", "MATH_TRIG_TOOLTIP_ATAN": "คืนค่า arctangent ของตัวเลข", "MATH_CONSTANT_HELPURL": "https://th.wikipedia.org/wiki/ค่าคงตัวทางคณิตศาสตร์", "MATH_CONSTANT_TOOLTIP": "คืนค่าคงตัวทางคณิตศาสตร์ที่พบบ่อยๆ เช่น π (3.141…), e (2.718…), φ (1.618…), รากที่สอง (1.414…), รากที่ ½ (0.707…), ∞ (อนันต์)", "MATH_IS_EVEN": "เป็นจำนวนคู่", "MATH_IS_ODD": "เป็นจำนวนคี่", "MATH_IS_PRIME": "เป็นจำนวนเฉพาะ", "MATH_IS_WHOLE": "เป็นเลขจำนวนเต็ม", "MATH_IS_POSITIVE": "เป็นเลขบวก", "MATH_IS_NEGATIVE": "เป็นเลขติดลบ", "MATH_IS_DIVISIBLE_BY": "หารลงตัว", "MATH_IS_TOOLTIP": "ตรวจว่าตัวเลขเป็นจำนวนคู่ จำนวนคี่ จำนวนเฉพาะ จำนวนเต็ม เลขบวก เลขติดลบ หรือหารด้วยเลขที่กำหนดลงตัวหรือไม่ คืนค่าเป็นจริงหรือเท็จ", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "เปลี่ยนค่า", "MATH_CHANGE_INPUT_BY": "เป็น", "MATH_CHANGE_TOOLTIP": "เพิ่มค่าของตัวแปร \"%1\"", "MATH_ROUND_HELPURL": "https://th.wikipedia.org/wiki/การปัดเศษ", "MATH_ROUND_TOOLTIP": "ปัดเศษของตัวเลขขึ้นหรือลง", "MATH_ROUND_OPERATOR_ROUND": "ปัดเศษ", "MATH_ROUND_OPERATOR_ROUNDUP": "ปัดเศษขึ้น", "MATH_ROUND_OPERATOR_ROUNDDOWN": "ปัดเศษลง", "MATH_ONLIST_OPERATOR_SUM": "ผลรวมของรายการ", "MATH_ONLIST_TOOLTIP_SUM": "คืนค่าผลรวมของตัวเลขทั้งหมดในรายการ", "MATH_ONLIST_OPERATOR_MIN": "น้อยที่สุดในรายการ", "MATH_ONLIST_TOOLTIP_MIN": "คืนค่าตัวเลขที่น้อยที่สุดในรายการ", "MATH_ONLIST_OPERATOR_MAX": "มากที่สุดในรายการ", "MATH_ONLIST_TOOLTIP_MAX": "คืนค่าตัวเลขที่มากที่สุดในรายการ", "MATH_ONLIST_OPERATOR_AVERAGE": "ค่าเฉลี่ยของรายการ", "MATH_ONLIST_TOOLTIP_AVERAGE": "คืนค่าเฉลี่ยของรายการ", "MATH_ONLIST_OPERATOR_MEDIAN": "ค่ามัธยฐานของรายการ", "MATH_ONLIST_TOOLTIP_MEDIAN": "คืนค่ามัธยฐานของรายการ", "MATH_ONLIST_OPERATOR_MODE": "ฐานนิยมของรายการ", "MATH_ONLIST_TOOLTIP_MODE": "คืนค่าฐานนิยมของรายการ", "MATH_ONLIST_OPERATOR_STD_DEV": "ส่วนเบี่ยงเบนมาตรฐานของรายการ", "MATH_ONLIST_TOOLTIP_STD_DEV": "คืนค่าส่วนเบี่ยงเบนมาตรฐานของรายการ", "MATH_ONLIST_OPERATOR_RANDOM": "สุ่มรายการ", "MATH_ONLIST_TOOLTIP_RANDOM": "สุ่มคืนค่าสิ่งที่อยู่ในรายการ", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "เศษของ %1 ÷ %2", "MATH_MODULO_TOOLTIP": "คืนค่าเศษที่ได้จากการหารของตัวเลขทั้งสองจำนวน", "MATH_CONSTRAIN_TITLE": "จำกัดค่า %1 ต่ำสุด %2 สูงสุด %3", "MATH_CONSTRAIN_TOOLTIP": "จำกัดค่าของตัวเลขให้อยู่ในช่วงที่กำหนด", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "สุ่มเลขจำนวนเต็มตั้งแต่ %1 จนถึง %2", "MATH_RANDOM_INT_TOOLTIP": "สุ่มเลขจำนวนเต็มจากช่วงที่กำหนด", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "สุ่มเลขเศษส่วน", "MATH_RANDOM_FLOAT_TOOLTIP": "สุ่มเลขเศษส่วน ตั้งแต่ 0.0 แต่ไม่เกิน 1.0", "TEXT_TEXT_HELPURL": "https://th.wikipedia.org/wiki/สายอักขระ", "TEXT_TEXT_TOOLTIP": "ตัวหนังสือ คำ หรือข้อความ", "TEXT_JOIN_TITLE_CREATEWITH": "สร้างข้อความด้วย", "TEXT_JOIN_TOOLTIP": "สร้างข้อความด้วยการรวมจำนวนของรายการเข้าด้วยกัน", "TEXT_CREATE_JOIN_TITLE_JOIN": "รวม", "TEXT_CREATE_JOIN_TOOLTIP": "เพิ่ม ลบ หรือจัดเรียงบล็อกข้อความนี้ใหม่", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "เพิ่มรายการเข้าไปในข้อความ", "TEXT_APPEND_TO": "นำเอา", "TEXT_APPEND_APPENDTEXT": "ต่อด้วยข้อความ", "TEXT_APPEND_TOOLTIP": "ต่อข้อความให้ตัวแปร \"%1\"", "TEXT_LENGTH_TITLE": "ความยาวของ %1", "TEXT_LENGTH_TOOLTIP": "คืนค่าความยาวของข้อความ (รวมช่องว่าง)", "TEXT_ISEMPTY_TITLE": "%1 ว่าง", "TEXT_ISEMPTY_TOOLTIP": "คืนค่าจริง ถ้าข้อความยังว่าง", "TEXT_INDEXOF_TOOLTIP": "คืนค่าตำแหน่งที่พบข้อความแรกอยู่ในข้อความที่สอง คืนค่า 0 ถ้าหาไม่พบ", "TEXT_INDEXOF_INPUT_INTEXT": "ในข้อความ", "TEXT_INDEXOF_OPERATOR_FIRST": "หาข้อความแรกที่พบ", "TEXT_INDEXOF_OPERATOR_LAST": "หาข้อความสุดท้ายที่พบ", "TEXT_CHARAT_INPUT_INTEXT": "ในข้อความ", "TEXT_CHARAT_FROM_START": "ดึง ตัวอักษรตัวที่", "TEXT_CHARAT_FROM_END": "ดึง ตัวอักษรตัวที่ # จากท้าย", "TEXT_CHARAT_FIRST": "ดึง ตัวอักษรตัวแรก", "TEXT_CHARAT_LAST": "ดึง ตัวอักษรตัวสุดท้าย", "TEXT_CHARAT_RANDOM": "ถึงตัวอักษรแบบสุ่ม", "TEXT_CHARAT_TOOLTIP": "คืนค่าตัวอักษรจากตำแหน่งที่ระบุ", "TEXT_GET_SUBSTRING_TOOLTIP": "คืนค่าบางส่วนของข้อความ", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "ในข้อความ", "TEXT_GET_SUBSTRING_START_FROM_START": "แยกข้อความย่อยตั้งแต่ ตัวอักษรที่", "TEXT_GET_SUBSTRING_START_FROM_END": "แยกข้อความย่อยตั้งแต่ ตัวอักษรที่ # จากท้าย", "TEXT_GET_SUBSTRING_START_FIRST": "แยกข้อความย่อยตั้งแต่ ตัวอักษรแรก", "TEXT_GET_SUBSTRING_END_FROM_START": "จนถึง ตัวอักษรที่", "TEXT_GET_SUBSTRING_END_FROM_END": "จนถึง ตัวอักษรที่ # จากท้าย", "TEXT_GET_SUBSTRING_END_LAST": "จนถึง ตัวอักษรสุดท้าย", "TEXT_CHANGECASE_TOOLTIP": "คืนค่าสำเนาของข้อความในกรณีต่างๆ", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "เปลี่ยนเป็น ตัวพิมพ์ใหญ่", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "เปลี่ยนเป็น ตัวพิมพ์เล็ก", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "เปลี่ยนเป็น ตัวอักษรแรกเป็นตัวพิมพ์ใหญ่", "TEXT_TRIM_TOOLTIP": "คืนค่าสำเนาของข้อความที่ลบเอาช่องว่างหน้าและหลังข้อความออกแล้ว", "TEXT_TRIM_OPERATOR_BOTH": "ลบช่องว่างทั้งสองข้างของ", "TEXT_TRIM_OPERATOR_LEFT": "ลบช่องว่างด้านหน้าของ", "TEXT_TRIM_OPERATOR_RIGHT": "ลบช่องว่างข้างท้ายของ", "TEXT_PRINT_TITLE": "พิมพ์ %1", "TEXT_PRINT_TOOLTIP": "พิมพ์ข้อความ ตัวเลข หรือค่าอื่นๆ", "TEXT_PROMPT_TYPE_TEXT": "แสดงหน้าต่างข้อความ", "TEXT_PROMPT_TYPE_NUMBER": "แสดงหน้าต่างตัวเลข", "TEXT_PROMPT_TOOLTIP_NUMBER": "แสดงหน้าต่างให้ผู้ใช้ใส่ตัวเลข", "TEXT_PROMPT_TOOLTIP_TEXT": "แสดงหน้าต่างให้ผู้ใช้ใส่ข้อความ", "LISTS_CREATE_EMPTY_TITLE": "สร้างรายการเปล่า", "LISTS_CREATE_EMPTY_TOOLTIP": "สร้างรายการเปล่า (ความยาวเป็น 0) ยังไม่มีข้อมูลใดๆ อยู่", "LISTS_CREATE_WITH_TOOLTIP": "สร้างรายการพร้อมด้วยไอเท็ม", "LISTS_CREATE_WITH_INPUT_WITH": "สร้างข้อความด้วย", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "รายการ", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "เพิ่ม ลบ หรือจัดเรียงบล็อกรายการนี้ใหม่", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "เพิ่มไอเท็มเข้าไปในรายการ", "LISTS_REPEAT_TOOLTIP": "สร้างรายการที่ประกอบด้วยค่าตามที่ระบุในจำนวนตามที่ต้องการ", "LISTS_REPEAT_TITLE": "สร้างรายการที่มีไอเท็ม %1 จำนวน %2", "LISTS_LENGTH_TITLE": "ความยาวของ %1", "LISTS_LENGTH_TOOLTIP": "ส่งคืนค่าความยาวของรายการ", "LISTS_IS_EMPTY_TITLE": "%1 ว่างเปล่า", "LISTS_TOOLTIP": "คืนค่าเป็นจริง ถ้ารายการยังว่างเปล่า", "LISTS_INLIST": "ในรายการ", "LISTS_INDEX_OF_FIRST": "หาอันแรกที่พบ", "LISTS_INDEX_OF_LAST": "หาอันสุดท้ายที่พบ", "LISTS_INDEX_OF_TOOLTIP": "คืนค่าตำแหน่งของไอเท็มอันแรก/สุดท้ายที่พบในรายการ คืนค่า 0 ถ้าหาไม่พบ", "LISTS_GET_INDEX_GET": "เรียกดู", "LISTS_GET_INDEX_GET_REMOVE": "เรียกดูและเอาออก", "LISTS_GET_INDEX_REMOVE": "เอาออก", "LISTS_GET_INDEX_FROM_END": "# จากท้าย", "LISTS_GET_INDEX_FIRST": "แรกสุด", "LISTS_GET_INDEX_LAST": "ท้ายสุด", "LISTS_GET_INDEX_RANDOM": "สุ่ม", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "คืนค่าเป็นไอเท็มตามตำแหน่งที่ระบุ #1 คือไอเท็มอันแรกสุด", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "คืนค่าเป็นไอเท็มตามตำแหน่งที่ระบุ #1 คือไอเท็มอันท้ายสุด", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "คืนค่าไอเท็มอันแรกในรายการ", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "คืนค่าไอเท็มอันสุดท้ายในรายการ", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "คืนค่าไอเท็มแบบสุ่มจากรายการ", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "เอาออก และคืนค่าไอเท็มในตำแหน่งที่ระบุจากรายการ #1 คือไอเท็มอันแรก", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "เอาออก และคืนค่าไอเท็มในตำแหน่งที่ระบุจากรายการ #1 คือไอเท็มอันสุดท้าย", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "เอาออก และคืนค่าไอเท็มอันแรกในรายการ", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "เอาออก และคืนค่าไอเท็มอันสุดท้ายในรายการ", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "เอาออก และคืนค่าไอเท็มแบบสุ่มจากรายการ", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "คืนค่าเป็นไอเท็มตามตำแหน่งที่ระบุ #1 คือไอเท็มอันแรกสุด", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "คืนค่าเป็นไอเท็มตามตำแหน่งที่ระบุ #1 คือไอเท็มอันท้ายสุด", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "เอาไอเท็มแรกสุดในรายการออก", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "เอาไอเท็มอันท้ายสุดในรายการออก", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "เอาไอเท็มแบบสุ่มจากรายการออก", "LISTS_SET_INDEX_SET": "กำหนด", "LISTS_SET_INDEX_INSERT": "แทรกที่", "LISTS_SET_INDEX_INPUT_TO": "เป็น", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "กำหนดไอเท็มในตำแหน่งที่ระบุในรายการ #1 คือไอเท็มอันแรกสุด", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "กำหนดไอเท็มในตำแหน่งที่ระบุในรายการ #1 คือไอเท็มอันท้ายสุด", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "กำหนดไอเท็มอันแรกในรายการ", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "กำหนดไอเท็มอันสุดท้ายในรายการ", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "กำหนดไอเท็มแบบสุ่มในรายการ", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "แทรกไอเท็มเข้าไปในตำแหน่งที่กำหนด #1 คือไอเท็มอันแรก", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "แทรกไอเท็มเข้าไปในตำแหน่งที่กำหนด #1 คือไอเท็มอันสุดท้าย", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "แทรกไอเท็มเข้าไปเป็นอันแรกสุดของรายการ", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "เพิ่มไอเท็มเข้าไปท้ายสุดของรายการ", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "เพิ่มไอเท็มเข้าไปในรายการแบบสุ่ม", "LISTS_GET_SUBLIST_START_FROM_START": "ดึงรายการย่อยจาก #", "LISTS_GET_SUBLIST_START_FROM_END": "ดึงรายการย่อยจาก # จากท้ายสุด", "LISTS_GET_SUBLIST_START_FIRST": "ดึงรายการย่อยทั้งแต่แรกสุด", "LISTS_GET_SUBLIST_END_FROM_START": "จนถึง #", "LISTS_GET_SUBLIST_END_FROM_END": "ถึง # จากท้ายสุด", "LISTS_GET_SUBLIST_END_LAST": "ถึง ท้ายสุด", "LISTS_GET_SUBLIST_TOOLTIP": "สร้างสำเนารายการในช่วงที่กำหนด", "VARIABLES_GET_TOOLTIP": "คืนค่าของตัวแปรนี้", "VARIABLES_GET_CREATE_SET": "สร้าง \"กำหนด %1\"", "VARIABLES_SET_TITLE": "กำหนด", "VARIABLES_SET_TAIL": "จนถึง", "VARIABLES_SET_TOOLTIP": "กำหนดให้ตัวแปรนี้เท่ากับการป้อนข้อมูล", "VARIABLES_SET_CREATE_GET": "สร้าง \"get %1\"", "PROCEDURES_DEFNORETURN_TITLE": "ถึง", "PROCEDURES_DEFNORETURN_PROCEDURE": "ทำอะไรบางอย่าง", "PROCEDURES_BEFORE_PARAMS": "ด้วย:", "PROCEDURES_DEFNORETURN_TOOLTIP": "สร้างฟังก์ชันที่ไม่มีผลลัพธ์", "PROCEDURES_DEFRETURN_RETURN": "คืนค่า", "PROCEDURES_DEFRETURN_TOOLTIP": "สร้างฟังก์ชันที่มีผลลัพธ์", "PROCEDURES_DEF_DUPLICATE_WARNING": "ระวัง: ฟังก์ชันนี้มีพารามิเตอร์ที่มีชื่อซ้ำกัน", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_(computer_science)", "PROCEDURES_CALLNORETURN_TOOLTIP": "เรียกใช้ฟังก์ชันที่สร้างโดยผู้ใช้ \"%1\"", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_(computer_science)", "PROCEDURES_CALLRETURN_TOOLTIP": "เรียกใช้ฟังก์ชันที่สร้างโดยผู้ใช้ \"%1\" และใช้ผลลัพธ์ของมัน", "PROCEDURES_MUTATORCONTAINER_TITLE": "นำเข้า", "PROCEDURES_MUTATORARG_TITLE": "ชื่อนำเข้า:", "PROCEDURES_HIGHLIGHT_DEF": "เน้นฟังก์ชันนิยาม", "PROCEDURES_CREATE_DO": "สร้าง \"%1\"", "PROCEDURES_IFRETURN_TOOLTIP": "ถ้ามีค่าเป็นจริง ให้คืนค่าที่สอง", "PROCEDURES_IFRETURN_WARNING": "ระวัง: บล็อกนี้ใช้เฉพาะในการสร้างฟังก์ชันเท่านั้น" } ================================================ FILE: extern/blockly/msg/json/tl.json ================================================ { "@metadata": [], "VARIABLES_DEFAULT_NAME": "item", "DUPLICATE_BLOCK": "Kaparehas", "ADD_COMMENT": "Dagdag komento", "REMOVE_COMMENT": "Remove Comment", "EXTERNAL_INPUTS": "Panlabas na Inputs", "INLINE_INPUTS": "Inline na Inputs", "DELETE_BLOCK": "burahin ang bloke", "DELETE_X_BLOCKS": "burahin %1 ng bloke", "COLLAPSE_BLOCK": "bloke", "COLLAPSE_ALL": "bloke", "EXPAND_BLOCK": "Palawakin ang Block", "EXPAND_ALL": "Palawakin ang Blocks", "DISABLE_BLOCK": "Ipangwalang bisa ang Block", "ENABLE_BLOCK": "Bigyan ng bisa ang Block", "HELP": "Tulong", "CHANGE_VALUE_TITLE": "pagbago ng value:", "NEW_VARIABLE": "New variable...", "NEW_VARIABLE_TITLE": "New variable name:", "RENAME_VARIABLE": "Rename variable...", "RENAME_VARIABLE_TITLE": "Rename all '%1' variables to:", "COLOUR_PICKER_HELPURL": "http://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "pagpili ng kulay sa paleta.", "COLOUR_RANDOM_TITLE": "iba ibang kulay", "COLOUR_RANDOM_TOOLTIP": "pagpili ng iba't ibang kulay.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "kulayan ng", "COLOUR_RGB_RED": "pula", "COLOUR_RGB_GREEN": "berde", "COLOUR_RGB_BLUE": "asul", "COLOUR_RGB_TOOLTIP": "gumawa ng kulay ng may espisipikong dami ng kulay pula, berde, at asul. lahat ng halaga ay dapat sa pagitan ng 0 at 100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "halo", "COLOUR_BLEND_COLOUR1": "kulay 1", "COLOUR_BLEND_COLOUR2": "kulay 2", "COLOUR_BLEND_RATIO": "proporsyon", "COLOUR_BLEND_TOOLTIP": "Paghalo ng dalawang kulay kasama ng ibinigay na proporsyon (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "http://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "ulitin %1 beses", "CONTROLS_REPEAT_TITLE_REPEAT": "ulitin", "CONTROLS_REPEAT_TITLE_TIMES": "beses", "CONTROLS_REPEAT_INPUT_DO": "gawin", "CONTROLS_REPEAT_TOOLTIP": "gumawa ng ilang pangungusap ng ilang ulit.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "ulitin habang", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "ulitin hanggang", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Habang ang value ay true, gagawin ang ibang statements.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Habang ang value ay false, gagawin ang ibang statements.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Magkaroon ng mga variable na %1 na tanggalin ng mga halaga mula sa simulang numero hanggang sa dulong numero, at bilangin sa pamamagitan ng tinukoy na agwat, at gawin ang mga tinukoy na mga blocks.", "CONTROLS_FOR_INPUT_WITH": "bilangin", "CONTROLS_FOR_INPUT_FROM_TO_BY": "mula %1 hanggang %2 ng %3", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each", "CONTROLS_FOREACH_INPUT_ITEM": "sa bawat bagay", "CONTROLS_FOREACH_INPUT_INLIST": "sa listahan", "CONTROLS_FOREACH_TOOLTIP": "Para sa bawat item sa isang list, i-set ang variable ng '% 1' sa mga item, at pagkatapos ay gumawa ng ilang mga statements.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "putulin ang paulit ulit", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "Magpatuloy sa susunod na pag-ulit ng loop", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Hatiin ang nilalaman ng loop.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Laktawan ang natitirang bahagi ng loop, at magpatuloy sa susunod na pag-ulit.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Babala: Ang block ito ay maaari lamang magamit sa loob ng loop.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "kung ang value ay true, gagawin ang do statements.", "CONTROLS_IF_TOOLTIP_2": "Kung ang value ay true, gagawin ang unang block ng do statements. Kung hindi, gagawin ang pangalawang block ng statement.", "CONTROLS_IF_TOOLTIP_3": "Kung ang unang value ay true, gagawin ang first block ng statement. Kung hindi, kung ang second value ay true, gagawin ang second block ng statement.", "CONTROLS_IF_TOOLTIP_4": "Kung ang first value ay true, gagawin ang first block ng statement. Kung hindi true ang second value, gagawin ang second block ng statement. Kung wala sa mga values ay true, gagawin ang last block ng statements.", "CONTROLS_IF_MSG_IF": "kung", "CONTROLS_IF_MSG_ELSEIF": "else if", "CONTROLS_IF_MSG_ELSE": "else", "CONTROLS_IF_IF_TOOLTIP": "Mag Add, remove o kaya mag reorder ng sections para maayos ang if block.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Mag dagdag ng condition sa if block.", "CONTROLS_IF_ELSE_TOOLTIP": "Mag Add ng final, kunin lahat ng condition sa if block.", "LOGIC_COMPARE_HELPURL": "http://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "Nag babalik ng true kung ang pinasok ay parehong magkatumbas.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Return true if both inputs are not equal to each other.", "LOGIC_COMPARE_TOOLTIP_LT": "Nag babalik ng true kung ang unang pinasok ay maliit kaysa sa pangalawang pinasok.", "LOGIC_COMPARE_TOOLTIP_LTE": "Nag babalik ng true kung ang unang pinasok ay maliit sa o katumbas sa pangalawang pinasok.", "LOGIC_COMPARE_TOOLTIP_GT": "Nagbabalik ng true kung ang unang pinasok ay mas malaki kaysa pangalawang pinasok.", "LOGIC_COMPARE_TOOLTIP_GTE": "Nag babalik ng true kung ang unang pinasok ay mas malaki or katumbas ng pangalawang pinasok.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Return true if both inputs are true.", "LOGIC_OPERATION_AND": "at", "LOGIC_OPERATION_TOOLTIP_OR": "Return true if at least one of the inputs is true.", "LOGIC_OPERATION_OR": "o", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "not %1", "LOGIC_NEGATE_TOOLTIP": "Returns true if the input is false. Returns false if the input is true.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "tama", "LOGIC_BOOLEAN_FALSE": "mali", "LOGIC_BOOLEAN_TOOLTIP": "Nag babalik ng true or false.", "LOGIC_NULL_HELPURL": "http://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "blangko", "LOGIC_NULL_TOOLTIP": "Returns null.", "LOGIC_TERNARY_HELPURL": "http://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "kung tama", "LOGIC_TERNARY_IF_FALSE": "kung mali", "LOGIC_TERNARY_TOOLTIP": "Check the condition in 'test'. If the condition is true, returns the 'if true' value; otherwise returns the 'if false' value.", "MATH_NUMBER_HELPURL": "http://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "A number.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "-", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "×", "MATH_POWER_SYMBOL": "^", "MATH_TRIG_SIN": "sin", "MATH_TRIG_COS": "cos", "MATH_TRIG_TAN": "tan", "MATH_TRIG_ASIN": "asin", "MATH_TRIG_ACOS": "acos", "MATH_TRIG_ATAN": "atan", "MATH_ARITHMETIC_HELPURL": "http://en.wikipedia.org/wiki/Arithmetic", "MATH_ARITHMETIC_TOOLTIP_ADD": "Return the sum of the two numbers.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Return the difference of the two numbers.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Return the product of the two numbers.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Return the quotient of the two numbers.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Return the first number raised to the power of the second number.", "MATH_SINGLE_HELPURL": "http://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "square root", "MATH_SINGLE_TOOLTIP_ROOT": "Return the square root of a number.", "MATH_SINGLE_OP_ABSOLUTE": "absolute", "MATH_SINGLE_TOOLTIP_ABS": "Return the absolute value of a number.", "MATH_SINGLE_TOOLTIP_NEG": "Return the negation of a number.", "MATH_SINGLE_TOOLTIP_LN": "Return the natural logarithm of a number.", "MATH_SINGLE_TOOLTIP_LOG10": "Return the base 10 logarithm of a number.", "MATH_SINGLE_TOOLTIP_EXP": "Return e to the power of a number.", "MATH_SINGLE_TOOLTIP_POW10": "Return 10 to the power of a number.", "MATH_TRIG_HELPURL": "http://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "Return the sine of a degree (not radian).", "MATH_TRIG_TOOLTIP_COS": "Return the cosine of a degree (not radian).", "MATH_TRIG_TOOLTIP_TAN": "Return the tangent of a degree (not radian).", "MATH_TRIG_TOOLTIP_ASIN": "Return the arcsine of a number.", "MATH_TRIG_TOOLTIP_ACOS": "Return the arccosine of a number.", "MATH_TRIG_TOOLTIP_ATAN": "Return the arctangent of a number.", "MATH_CONSTANT_HELPURL": "http://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "Return one of the common constants: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (infinity).", "MATH_IS_EVEN": "is even", "MATH_IS_ODD": "is odd", "MATH_IS_PRIME": "is prime", "MATH_IS_WHOLE": "is whole", "MATH_IS_POSITIVE": "ay positibo", "MATH_IS_NEGATIVE": "ay negatibo", "MATH_IS_DIVISIBLE_BY": "is divisible by", "MATH_IS_TOOLTIP": "Check if a number is an even, odd, prime, whole, positive, negative, or if it is divisible by certain number. Returns true or false.", "MATH_CHANGE_HELPURL": "http://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "baguhin", "MATH_CHANGE_INPUT_BY": "by", "MATH_CHANGE_TOOLTIP": "Add a number to variable '%1'.", "MATH_ROUND_HELPURL": "http://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Round a number up or down.", "MATH_ROUND_OPERATOR_ROUND": "round", "MATH_ROUND_OPERATOR_ROUNDUP": "round up", "MATH_ROUND_OPERATOR_ROUNDDOWN": "round down", "MATH_ONLIST_OPERATOR_SUM": "sum of list", "MATH_ONLIST_TOOLTIP_SUM": "Return the sum of all the numbers in the list.", "MATH_ONLIST_OPERATOR_MIN": "min of list", "MATH_ONLIST_TOOLTIP_MIN": "Return the smallest number in the list.", "MATH_ONLIST_OPERATOR_MAX": "max of list", "MATH_ONLIST_TOOLTIP_MAX": "Return the largest number in the list.", "MATH_ONLIST_OPERATOR_AVERAGE": "average of list", "MATH_ONLIST_TOOLTIP_AVERAGE": "Return the average (arithmetic mean) of the numeric values in the list.", "MATH_ONLIST_OPERATOR_MEDIAN": "median of list", "MATH_ONLIST_TOOLTIP_MEDIAN": "Return the median number in the list.", "MATH_ONLIST_OPERATOR_MODE": "modes of list", "MATH_ONLIST_TOOLTIP_MODE": "Return a list of the most common item(s) in the list.", "MATH_ONLIST_OPERATOR_STD_DEV": "standard deviation of list", "MATH_ONLIST_TOOLTIP_STD_DEV": "Return the standard deviation of the list.", "MATH_ONLIST_OPERATOR_RANDOM": "random item of list", "MATH_ONLIST_TOOLTIP_RANDOM": "Return a random element from the list.", "MATH_MODULO_HELPURL": "http://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "remainder of %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Return the remainder from dividing the two numbers.", "MATH_CONSTRAIN_HELPURL": "http://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "constrain %1 low %2 high %3", "MATH_CONSTRAIN_TOOLTIP": "Constrain a number to be between the specified limits (inclusive).", "MATH_RANDOM_INT_HELPURL": "http://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "random integer from %1 to %2", "MATH_RANDOM_INT_TOOLTIP": "Return a random integer between the two specified limits, inclusive.", "MATH_RANDOM_FLOAT_HELPURL": "http://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "random fraction", "MATH_RANDOM_FLOAT_TOOLTIP": "Return a random fraction between 0.0 (inclusive) and 1.0 (exclusive).", "TEXT_TEXT_HELPURL": "http://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "A letter, word, or line of text.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "create text with", "TEXT_JOIN_TOOLTIP": "Create a piece of text by joining together any number of items.", "TEXT_CREATE_JOIN_TITLE_JOIN": "join", "TEXT_CREATE_JOIN_TOOLTIP": "Add, remove, or reorder sections to reconfigure this text block.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Add an item to the text.", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "to", "TEXT_APPEND_APPENDTEXT": "append text", "TEXT_APPEND_TOOLTIP": "Append some text to variable '%1'.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "length of %1", "TEXT_LENGTH_TOOLTIP": "Returns the number of letters (including spaces) in the provided text.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 is empty", "TEXT_ISEMPTY_TOOLTIP": "Returns true if the provided text is empty.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Returns the index of the first/last occurrence of first text in the second text. Returns 0 if text is not found.", "TEXT_INDEXOF_INPUT_INTEXT": "in text", "TEXT_INDEXOF_OPERATOR_FIRST": "find first occurrence of text", "TEXT_INDEXOF_OPERATOR_LAST": "find last occurrence of text", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "in text", "TEXT_CHARAT_FROM_START": "get letter #", "TEXT_CHARAT_FROM_END": "get letter # from end", "TEXT_CHARAT_FIRST": "get first letter", "TEXT_CHARAT_LAST": "get last letter", "TEXT_CHARAT_RANDOM": "get random letter", "TEXT_CHARAT_TOOLTIP": "Returns the letter at the specified position.", "TEXT_GET_SUBSTRING_TOOLTIP": "Returns a specified portion of the text.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "in text", "TEXT_GET_SUBSTRING_START_FROM_START": "get substring from letter #", "TEXT_GET_SUBSTRING_START_FROM_END": "get substring from letter # from end", "TEXT_GET_SUBSTRING_START_FIRST": "get substring from first letter", "TEXT_GET_SUBSTRING_END_FROM_START": "to letter #", "TEXT_GET_SUBSTRING_END_FROM_END": "to letter # from end", "TEXT_GET_SUBSTRING_END_LAST": "to last letter", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Return a copy of the text in a different case.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "to UPPER CASE", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "to lower case", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "to Title Case", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Return a copy of the text with spaces removed from one or both ends.", "TEXT_TRIM_OPERATOR_BOTH": "trim spaces from both sides", "TEXT_TRIM_OPERATOR_LEFT": "trim spaces from left side", "TEXT_TRIM_OPERATOR_RIGHT": "trim spaces from right side", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "print %1", "TEXT_PRINT_TOOLTIP": "Print the specified text, number or other value.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "prompt for text with message", "TEXT_PROMPT_TYPE_NUMBER": "prompt for number with message", "TEXT_PROMPT_TOOLTIP_NUMBER": "Prompt for user for a number.", "TEXT_PROMPT_TOOLTIP_TEXT": "Prompt for user for some text.", "LISTS_CREATE_EMPTY_HELPURL": "http://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "Gumawa ng walang laman na list", "LISTS_CREATE_EMPTY_TOOLTIP": "Ibabalik ang list, na may haba na 0, nag lalaman ng walang data records", "LISTS_CREATE_WITH_TOOLTIP": "Gumawa ng list na may kahit anong number ng items.", "LISTS_CREATE_WITH_INPUT_WITH": "gumawa ng list kasama", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "list", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Magdagdag, mag tanggal or mag ayos ng sections para muling maayos ang listahan ng block.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Mag dagdag ng item sa list.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#paggawa_ng_list_kasama", "LISTS_REPEAT_TOOLTIP": "Pag gawa ng list na binubuo ng binigay na value at inulit na tinuloy na bilang ng beses.", "LISTS_REPEAT_TITLE": "pag gawa ng list kasama ng item %1 inuulit %2 beses", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#haba_ng", "LISTS_LENGTH_TITLE": "haba ng %1", "LISTS_LENGTH_TOOLTIP": "Pag balik ng haba ng list.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#ay_walang_laman", "LISTS_IS_EMPTY_TITLE": "%1 ay walang laman", "LISTS_TOOLTIP": "Nagbabalik ng true kung ang list ay walang laman.", "LISTS_INLIST": "sa list", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Pagkuha_ng_Items_mula_sa_List", "LISTS_INDEX_OF_FIRST": "Hanapin ang unang pangyayari ng item", "LISTS_INDEX_OF_LAST": "hanapin ang huling pangyayari ng item", "LISTS_INDEX_OF_TOOLTIP": "Pagbalik ng index ng una/huli pangyayari ng item sa list. Pagbalik ng 0 kung ang item ay hindi makita.", "LISTS_GET_INDEX_GET": "kunin", "LISTS_GET_INDEX_GET_REMOVE": "kunin at tanggalin", "LISTS_GET_INDEX_REMOVE": "tanggalin", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# mula katapusan", "LISTS_GET_INDEX_FIRST": "Una", "LISTS_GET_INDEX_LAST": "huli", "LISTS_GET_INDEX_RANDOM": "nang hindi pinipili", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Ibalik ang item sa itinakdang posisyon sa list. #1 ay ang unang item.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Ibalik ang item sa tinakdang posisyon sa list. #1 ay ang huling item.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Ibalik ang unang item sa list.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Ibalik ang huling item sa list.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Nag babalik ng hindi pinipiling item sa list.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Nag tatanggal at nag babalik ng mga items sa tinukoy na posisyon sa list. #1 ang unang item.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Nag tatanggal at nag babalik ng items sa tinukoy na posisyon sa list. #1 ay ang huling item.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Nag tatanggal at nag babalik ng mga unang item sa list.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Nag tatanggal at nag babalik ng huling item sa list.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Nag tatanggal at nag babalik ng mga hindi pinipiling item sa list.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Nag tatanggal ng item sa tinukoy na posisyon sa list. #1 ay ang unang item.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Nag tatanggal ng item sa tinukoy na posisyon sa list. #1 ay ang huling item.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Nag tatanggal ng unang item sa list.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Nag tatanggal ng huling item sa list.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Nag tatanggal ng item mula sa walang pinipiling list.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#sa_list_..._set", "LISTS_SET_INDEX_SET": "set", "LISTS_SET_INDEX_INSERT": "isingit sa", "LISTS_SET_INDEX_INPUT_TO": "gaya ng", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Pag set ng item sa tinukoy na position sa isang list. #1 ay ang unang item.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Pag set ng item sa tinukoy na posisyon sa isang list. #1 ay ang huling item.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Pag set ng unang item sa isang list.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Pag set sa huling item sa isang list.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Pag set ng walang pinipiling item sa isang list.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Nag singit ng item sa tinukoy na posistion sa list. #1 ay ang unang item.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Nag singit ng item sa tinukoy na posisyon sa list. #1 ay ang huling item.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Nag singit ng item sa simula ng list.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Idagdag ang item sa huli ng isang list.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Isingit ang item ng walang pinipili sa isang list.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Pagkuha_ng_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "pag kuha ng sub-list mula #", "LISTS_GET_SUBLIST_START_FROM_END": "pag kuha ng sub-list mula sa # mula huli", "LISTS_GET_SUBLIST_START_FIRST": "pag kuha ng sub-list mula sa una", "LISTS_GET_SUBLIST_END_FROM_START": "mula #", "LISTS_GET_SUBLIST_END_FROM_END": "mula # hanggang huli", "LISTS_GET_SUBLIST_END_LAST": "hanggang huli", "LISTS_GET_SUBLIST_TOOLTIP": "Gumagawa ng kopya ng tinukoy na bahagi ng list.", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TOOLTIP": "Returns the value of this variable.", "VARIABLES_GET_CREATE_SET": "Create 'set %1'", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "set", "VARIABLES_SET_TAIL": "to", "VARIABLES_SET_TOOLTIP": "Sets this variable to be equal to the input.", "VARIABLES_SET_CREATE_GET": "Create 'get %1'", "PROCEDURES_DEFNORETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFNORETURN_TITLE": "to", "PROCEDURES_DEFNORETURN_PROCEDURE": "do something", "PROCEDURES_BEFORE_PARAMS": "with:", "PROCEDURES_DEFNORETURN_TOOLTIP": "Creates a function with no output.", "PROCEDURES_DEFRETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFRETURN_RETURN": "return", "PROCEDURES_DEFRETURN_TOOLTIP": "Creates a function with an output.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Warning: This function has duplicate parameters.", "PROCEDURES_CALLNORETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_TOOLTIP": "Run the user-defined function '%1'.", "PROCEDURES_CALLRETURN_HELPURL": "http://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Run the user-defined function '%1' and use its output.", "PROCEDURES_MUTATORCONTAINER_TITLE": "inputs", "PROCEDURES_MUTATORARG_TITLE": "input name:", "PROCEDURES_HIGHLIGHT_DEF": "Highlight function definition", "PROCEDURES_CREATE_DO": "Create '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "If a value is true, then return a second value.", "PROCEDURES_IFRETURN_WARNING": "Warning: This block may be used only within a function definition." } ================================================ FILE: extern/blockly/msg/json/tr.json ================================================ { "@metadata": [], "VARIABLES_DEFAULT_NAME": "öge", "DUPLICATE_BLOCK": "çoğalt", "ADD_COMMENT": "Yorum Ekle", "REMOVE_COMMENT": "Yorumları sil", "EXTERNAL_INPUTS": "Harici Girişler", "INLINE_INPUTS": "Satır içi girdi", "DELETE_BLOCK": "Bloğu Sil", "DELETE_X_BLOCKS": "%1 Bloğu Sil", "COLLAPSE_BLOCK": "Blok'u Daralt", "COLLAPSE_ALL": "Blokları Daralt", "EXPAND_BLOCK": "Bloğu Genişlet", "EXPAND_ALL": "Blokları Genişlet", "DISABLE_BLOCK": "Bloğu Devre Dışı Bırak", "ENABLE_BLOCK": "Bloğu Etkinleştir", "HELP": "Yardım", "CHANGE_VALUE_TITLE": "Değeri değiştir:", "NEW_VARIABLE": "Yeni değişken...", "NEW_VARIABLE_TITLE": "Yeni değişken ismi :", "RENAME_VARIABLE": "Değişkeni yeniden adlandır...", "RENAME_VARIABLE_TITLE": "Tüm '%1' değişkenlerini yeniden isimlendir:", "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "Paletten bir renk seçin.", "COLOUR_RANDOM_TITLE": "rastgele renk", "COLOUR_RANDOM_TOOLTIP": "Rastgele bir renk seçin.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "renk değerleri", "COLOUR_RGB_RED": "kırmızı", "COLOUR_RGB_GREEN": "yeşil", "COLOUR_RGB_BLUE": "mavi", "COLOUR_RGB_TOOLTIP": "Kırmızı, yeşil ve mavinin belirtilen miktarıyla bir renk oluşturun. Tüm değerler 0 ile 100 arasında olmalıdır.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "karıştır", "COLOUR_BLEND_COLOUR1": "renk 1", "COLOUR_BLEND_COLOUR2": "renk 2", "COLOUR_BLEND_RATIO": "oran", "COLOUR_BLEND_TOOLTIP": "Verilen bir orana bağlı olarak iki rengi karıştırır. (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop Döngü", "CONTROLS_REPEAT_TITLE": "%1 kez tekrarla", "CONTROLS_REPEAT_TITLE_REPEAT": "tekrarla", "CONTROLS_REPEAT_TITLE_TIMES": "kez", "CONTROLS_REPEAT_INPUT_DO": "yap", "CONTROLS_REPEAT_TOOLTIP": "Bazı işlemleri birkaç kez yap.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "tekrar ederken", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "kadar tekrarla", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Bir değer true ise, o zaman bazı ifadeleri yap.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Bir değer false ise, o zaman bazı ifadeleri yap.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "%1 değişkenini başlangıç numarasından bitiş numarasına kadar tanımlı farkla değerler verirken tanımlı blokları yap.", "CONTROLS_FOR_INPUT_WITH": "ile sayılır", "CONTROLS_FOR_INPUT_FROM_TO_BY": "%1 den %2 ye, her adımda %3 değişim", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each", "CONTROLS_FOREACH_INPUT_ITEM": "her öğe için", "CONTROLS_FOREACH_INPUT_INLIST": "listede", "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "", "CONTROLS_FOREACH_TOOLTIP": "Bir listedeki her öğe için '%1' değişkenini maddeye atayın ve bundan sonra bazı açıklamalar yapın.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "döngüden çık", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "döngünün sonraki adımından devam et", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "İçeren döngüden çık.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Bu döngünün geri kalanını atlayın ve sonraki adım ile devam edin.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Uyarı: Bu blok sadece bir döngü içinde kullanılabilir.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "Eğer değişken true , yani gerçekleşmiş ise , ardından gelen işlemi yerine getir .", "CONTROLS_IF_TOOLTIP_2": "Eğer değişken true, yani gerçekleşiyor ise ilk blok'taki işlemleri yerine getir, Aksi halde ikinci blok'taki işlemleri yerine getir.", "CONTROLS_IF_TOOLTIP_3": "Eğer ilk değişken true, yani koşul gerçekleşmiş ise ilk blok içerisindeki işlem(ler)i gerçekleştir. Eğer ikinci değişken true ise, ikinci bloktaki işlem(ler)i gerçekleştir .", "CONTROLS_IF_TOOLTIP_4": "Eğer ilk değer true, yani olumlu ise, ilk blok'taki işlem(ler)i gerçekleştir. İlk değer true değil ama ikinci değer true ise, ikinci bloktaki işlem(ler)i gerçekleştir. Eğer değerlerin hiçbiri true değil ise son blok'taki işlem(ler)i gerçekleştir.", "CONTROLS_IF_MSG_IF": "eğer", "CONTROLS_IF_MSG_ELSEIF": "değilse eğer", "CONTROLS_IF_MSG_ELSE": "değilse", "CONTROLS_IF_IF_TOOLTIP": "If bloğuna ekle, kaldır veya yeniden düzenleme yap.", "CONTROLS_IF_ELSEIF_TOOLTIP": "If bloğuna bir koşul ekleyin.", "CONTROLS_IF_ELSE_TOOLTIP": "If bloğuna kalan durumları \"yakalayan\" bir son ekle.", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics) eşitsizlik işlemi", "LOGIC_COMPARE_TOOLTIP_EQ": "Girilen iki değer birbirine eşitse \"True\" değerini verir.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Girilen iki değerde birbirine eşit değilse \"True\" değerini verir.", "LOGIC_COMPARE_TOOLTIP_LT": "Girilen ilk değer ikinci değerden küçükse \"True\" değerini verir.", "LOGIC_COMPARE_TOOLTIP_LTE": "Girilen ilk değer ikinci değerden küçük veya eşitse \"True\" değerini verir.", "LOGIC_COMPARE_TOOLTIP_GT": "Girilen ilk değer ikinci değerden daha büyükse \"True\" değerini verir.", "LOGIC_COMPARE_TOOLTIP_GTE": "Girilen ilk değer ikinci değerden büyük veya eşitse \"True\" değerini verir.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Girilen iki değerde doğruysa \"True\" değerini verir.", "LOGIC_OPERATION_AND": "ve", "LOGIC_OPERATION_TOOLTIP_OR": "Girilen iki değerden en az biri doğruysa \"True\" değerini verir.", "LOGIC_OPERATION_OR": "veya", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "%1 değil", "LOGIC_NEGATE_TOOLTIP": "Girilen değer yanlışsa \"True\" değerini verir.Girilen değer doğruysa \"False\" değerini verir.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False olumlu_olumsuz", "LOGIC_BOOLEAN_TRUE": "Olumlu", "LOGIC_BOOLEAN_FALSE": "false = Olumsuz", "LOGIC_BOOLEAN_TOOLTIP": "Ya 'True' yada 'False' değerini verir.", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "sıfır", "LOGIC_NULL_TOOLTIP": "sıfır verir.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "test", "LOGIC_TERNARY_IF_TRUE": "doğru ise", "LOGIC_TERNARY_IF_FALSE": "yanlış ise", "LOGIC_TERNARY_TOOLTIP": "'test'deki şartı test eder. Eğer şart doğru ise 'doğru' değeri döndürür, aksi halde 'yanlış' değeri döndürür.", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "Bir sayı.", "MATH_ADDITION_SYMBOL": "+", "MATH_SUBTRACTION_SYMBOL": "tire", "MATH_DIVISION_SYMBOL": "÷", "MATH_MULTIPLICATION_SYMBOL": "x", "MATH_POWER_SYMBOL": "üst alma", "MATH_TRIG_SIN": "Sinüs", "MATH_TRIG_COS": "kosünüs", "MATH_TRIG_TAN": "tanjant", "MATH_TRIG_ASIN": "asinüs", "MATH_TRIG_ACOS": "akosünüs", "MATH_TRIG_ATAN": "atanjant", "MATH_ARITHMETIC_HELPURL": "https://tr.wikipedia.org/wiki/Aritmetik", "MATH_ARITHMETIC_TOOLTIP_ADD": "İki rakamın toplamını döndür.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "İki sayını farkını döndür.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "İki sayının çarpımını döndür.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "İki sayının bölümünü döndür.", "MATH_ARITHMETIC_TOOLTIP_POWER": "İlk sayinin ikincinin kuvvetine yükseltilmişini döndür.", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root Kare kök", "MATH_SINGLE_OP_ROOT": "Kare kök", "MATH_SINGLE_TOOLTIP_ROOT": "Bir sayının karekökü nü döndür .", "MATH_SINGLE_OP_ABSOLUTE": "Kesin", "MATH_SINGLE_TOOLTIP_ABS": "Bir sayının tam değerini döndür .", "MATH_SINGLE_TOOLTIP_NEG": "Bir sayıyı geçersiz olarak döndür .", "MATH_SINGLE_TOOLTIP_LN": "Bir sayının doğal logaritmasını döndür .", "MATH_SINGLE_TOOLTIP_LOG10": "Bir sayının 10 temelinde logaritmasını döndür .", "MATH_SINGLE_TOOLTIP_EXP": "Bir sayının e ' inci kuvvetini döndür .", "MATH_SINGLE_TOOLTIP_POW10": "Bir sayının 10. kuvvetini döndür .", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions Trigonometrik fonksiyonlar", "MATH_TRIG_TOOLTIP_SIN": "Bir açının sinüsünü döndür(radyan olarak değil).", "MATH_TRIG_TOOLTIP_COS": "Bir açının kosinüsünü döndür(radyan olarak değil).", "MATH_TRIG_TOOLTIP_TAN": "Bir açının tanjantını döndür(radyan olarak değil).", "MATH_TRIG_TOOLTIP_ASIN": "Bir sayının ters sinüsünü döndür .", "MATH_TRIG_TOOLTIP_ACOS": "Bir sayının ters kosunusunu döndür .", "MATH_TRIG_TOOLTIP_ATAN": "Bir sayının ters tanjantını döndür .", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "Yaygın sabitlerden birini döndür:π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (sonsuz).", "MATH_IS_EVEN": "çift", "MATH_IS_ODD": "tek", "MATH_IS_PRIME": "asal", "MATH_IS_WHOLE": "Bütün olduğunu", "MATH_IS_POSITIVE": "pozitif", "MATH_IS_NEGATIVE": "negatif", "MATH_IS_DIVISIBLE_BY": "bölünebilir", "MATH_IS_TOOLTIP": "Bir sayinin çift mi tek mi , tam mı, asal mı , pozitif mi, negatif mi, veya tam bir sayıyla bölünebilirliğini kontrol et.'True' veya 'False' değerini döndür.", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "Değiştirmek", "MATH_CHANGE_INPUT_BY": "ile", "MATH_CHANGE_TOOLTIP": "'%1' değişkenine bir sayı ekle.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding Yuvarlama", "MATH_ROUND_TOOLTIP": "Bir sayı yı yukarı yada aşağı yuvarla .", "MATH_ROUND_OPERATOR_ROUND": "Yuvarla", "MATH_ROUND_OPERATOR_ROUNDUP": "yukarı yuvarla", "MATH_ROUND_OPERATOR_ROUNDDOWN": "aşağı yuvarla", "MATH_ONLIST_HELPURL": "", "MATH_ONLIST_OPERATOR_SUM": "Listenin toplamı", "MATH_ONLIST_TOOLTIP_SUM": "Listede ki tüm sayıların toplamını döndür.", "MATH_ONLIST_OPERATOR_MIN": "Listenin en küçüğü", "MATH_ONLIST_TOOLTIP_MIN": "Listenin en küçüğünü döndür.", "MATH_ONLIST_OPERATOR_MAX": "en büyük sayı", "MATH_ONLIST_TOOLTIP_MAX": "Listenin en büyüğünü döndür.", "MATH_ONLIST_OPERATOR_AVERAGE": "listenin ortalaması", "MATH_ONLIST_TOOLTIP_AVERAGE": "Listedeki sayısal değerlerin ortalamasını (aritmetik anlamda) döndür.", "MATH_ONLIST_OPERATOR_MEDIAN": "Listenin medyanı", "MATH_ONLIST_TOOLTIP_MEDIAN": "Listenin medyanını döndür.", "MATH_ONLIST_OPERATOR_MODE": "Listenin modları", "MATH_ONLIST_TOOLTIP_MODE": "Listede ki en yaygın öğe veya öğelerinin listesini döndür.", "MATH_ONLIST_OPERATOR_STD_DEV": "Listenin standart sapması", "MATH_ONLIST_TOOLTIP_STD_DEV": "Listenin standart sapmasını döndür.", "MATH_ONLIST_OPERATOR_RANDOM": "Listenin rastgele öğesi", "MATH_ONLIST_TOOLTIP_RANDOM": "Listeden rastgele bir element döndür.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "%1 ÷ %2 nin kalanı", "MATH_MODULO_TOOLTIP": "İki sayının bölümünden kalanı döndür.", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "%1 i en düşük %2 en yüksek %3 ile sınırla", "MATH_CONSTRAIN_TOOLTIP": "Bir sayıyı belirli iki sayı arasında sınırlandır(dahil).", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation Rast gele sayı üretme", "MATH_RANDOM_INT_TITLE": "%1 ile %2 arasında rastgele tam sayı üret", "MATH_RANDOM_INT_TOOLTIP": "Herhangi iki sayı arasında , sayılar dahil olmak üzere , rastgele bir tam sayı döndür.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation Rastgele sayı yaratma", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "Rast gele kesirli sayı , yada parça", "MATH_RANDOM_FLOAT_TOOLTIP": "0.0(dahil) ve 1.0 (hariç) sayıları arasında bir sayı döndür .", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "Metnin bir harfi,kelimesi veya satırı.", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "ile metin oluştur", "TEXT_JOIN_TOOLTIP": "Herhangi bir sayıda ki öğeleri bir araya getirerek metnin bir parçasını oluştur.", "TEXT_CREATE_JOIN_TITLE_JOIN": "Katıl", "TEXT_CREATE_JOIN_TOOLTIP": "Bu metin bloğunu düzenlemek için bölüm ekle,sil veya yeniden görevlendir.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Metine bir öğe ekle.", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "e", "TEXT_APPEND_APPENDTEXT": "Metin Ekle", "TEXT_APPEND_TOOLTIP": "Değişken '%1' e bazı metinler ekleyin.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification Yazı değişimi", "TEXT_LENGTH_TITLE": "%1 in uzunluğu", "TEXT_LENGTH_TOOLTIP": "Yazı içerisinde verilen harflerin ( harf arasındaki boşluklar dahil) sayısını verir .", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 boş", "TEXT_ISEMPTY_TOOLTIP": "Verilen metin boşsa true(doğru) değerini verir.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "İlk metnin ikinci metnin içindeki ilk ve son varoluşlarının indeksini döndürür.Metin bulunamadıysa 0 döndürür.", "TEXT_INDEXOF_INPUT_INTEXT": "metinde", "TEXT_INDEXOF_OPERATOR_FIRST": "Metnin ilk varolduğu yeri bul", "TEXT_INDEXOF_OPERATOR_LAST": "Metnin son varolduğu yeri bul", "TEXT_INDEXOF_TAIL": "", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "metinde", "TEXT_CHARAT_FROM_START": "# harfini al", "TEXT_CHARAT_FROM_END": "# dan sona harfleri al", "TEXT_CHARAT_FIRST": "İlk harfini al", "TEXT_CHARAT_LAST": "son harfi al", "TEXT_CHARAT_RANDOM": "Rastgele bir harf al", "TEXT_CHARAT_TAIL": "", "TEXT_CHARAT_TOOLTIP": "Belirli pozisyonda ki bir harfi döndürür.", "TEXT_GET_SUBSTRING_TOOLTIP": "Metinin belirli bir kısmını döndürür.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "metinde", "TEXT_GET_SUBSTRING_START_FROM_START": "n inci harften alt-string alma", "TEXT_GET_SUBSTRING_START_FROM_END": "n inci harften sona kadar alt-string alma", "TEXT_GET_SUBSTRING_START_FIRST": "ilk harften başlayarak alt-string alma", "TEXT_GET_SUBSTRING_END_FROM_START": "# harfe", "TEXT_GET_SUBSTRING_END_FROM_END": "Sondan # harfe", "TEXT_GET_SUBSTRING_END_LAST": "son harfe", "TEXT_GET_SUBSTRING_TAIL": "", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "Metnin bir kopyasını farklı bir harf durumunda (HEPSİ BÜYÜK - hepsi küçük) getirir.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "büyük harf", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "küçük harf", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "Baş Harfler Büyük", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "Metnin bir veya her iki sondan da boşlukları silinmiş şekilde kopyasını verir.", "TEXT_TRIM_OPERATOR_BOTH": "İki tarafdan da boşlukları düzenle", "TEXT_TRIM_OPERATOR_LEFT": "Soldan boşlukları düzenle", "TEXT_TRIM_OPERATOR_RIGHT": "Sağdan boşlukları düzenle", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text Yazıyı yazdırmak", "TEXT_PRINT_TITLE": "%1 ' i Yaz", "TEXT_PRINT_TOOLTIP": "Belirli bir metni,sayıyı veya başka bir değeri yaz.", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user Kullanıcıdan veri almak", "TEXT_PROMPT_TYPE_TEXT": "Kullanıcıdan yazım al , istek mesajıyla", "TEXT_PROMPT_TYPE_NUMBER": "Kullanıcıdan sayı al , istek mesajı göstererek", "TEXT_PROMPT_TOOLTIP_NUMBER": "Kullanıcıdan sayı al .", "TEXT_PROMPT_TOOLTIP_TEXT": "Kullanıcıdan Yazım al .", "LISTS_CREATE_EMPTY_HELPURL": "https://en.wikipedia.org/wiki/Linked_list#Empty_lists Boş Listeler", "LISTS_CREATE_EMPTY_TITLE": "Boş liste oluştur", "LISTS_CREATE_EMPTY_TOOLTIP": "Veri kaydı içermeyen uzunluğu 0 olan bir listeyi verir", "LISTS_CREATE_WITH_TOOLTIP": "Herhangi sayıda nesne içeren bir liste oluştur.", "LISTS_CREATE_WITH_INPUT_WITH": "İle liste oluşturma", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "liste", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Bu liste bloğunu yeniden yapılandırmak için bölüm ekle,kaldır veya yeniden çağır.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Listeye bir nesne ekle.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with İle liste yaratma", "LISTS_REPEAT_TOOLTIP": "Verilen bir değerin , belirli bir sayıda tekrarlanmasından oluşan bir liste yaratır .", "LISTS_REPEAT_TITLE": "%1 nesnenin %2 kez tekrarlandığı bir liste yarat", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of Uzunluk Listeleri", "LISTS_LENGTH_TITLE": "%1'in uzunluğu", "LISTS_LENGTH_TOOLTIP": "Bir listenin uzunluğunu verir.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty Boş Listeler", "LISTS_IS_EMPTY_TITLE": "%1 boş", "LISTS_TOOLTIP": "Eğer liste boş ise true döndürür .", "LISTS_INLIST": "Listede", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List Bir listeden öğe almak", "LISTS_INDEX_OF_FIRST": "Öğenin ilk varolduğu yeri bul", "LISTS_INDEX_OF_LAST": "Öğenin son varolduğu yeri bul", "LISTS_INDEX_OF_TOOLTIP": "Öğenin listede , ilk ve son görüldüğü dizinleri döndürür . Öğe bulunmassa , 0 döndürür .", "LISTS_GET_INDEX_GET": "Al", "LISTS_GET_INDEX_GET_REMOVE": "al ve kaldır", "LISTS_GET_INDEX_REMOVE": "kaldır", "LISTS_GET_INDEX_FROM_START": "# Kare", "LISTS_GET_INDEX_FROM_END": "# sonundan", "LISTS_GET_INDEX_FIRST": "ilk", "LISTS_GET_INDEX_LAST": "son", "LISTS_GET_INDEX_RANDOM": "rastgele", "LISTS_GET_INDEX_TAIL": "", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Listede belirli pozisyondaki bir öğeyi verir.#1 ilk öğedir.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Listede belirli pozisyondaki bir öğeyi verir.#1 son öğedir.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Listedeki ilk öğeyi verir.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Listedeki son öğeyi verir.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Listedeki rastgele bir öğeyi verir.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Kaldırır ve listede belirtilen konumdaki bir öğeyi döndürür. #1 son öğedir.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Kaldırır ve listede belirtilen konumdaki bir ögeyi döndürür. #1 son ögedir.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Kaldırır ve listedeki ilk öğeyi döndürür.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Kaldırır ve listedeki son öğeyi döndürür.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Kaldırır ve listedeki rastgele bir öğeyi verir.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Bir liste içerisinde , tanımlanan pozisyonda ki öğeyi kaldırır.#1 ilk öğedir.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Liste içerisinde , tanımlanan pozisyondaki bir öğeyi kaldırır . #1 son öğe dir .", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Listedeki ilk nesneyi kaldırır.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Listedeki son nesneyi kaldırır.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Listedeki rastgele bir nesneyi kaldırır.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set Listeler#Liste içi ...gurubu", "LISTS_SET_INDEX_SET": "yerleştir", "LISTS_SET_INDEX_INSERT": "e yerleştir", "LISTS_SET_INDEX_INPUT_TO": "olarak", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Bir öğeyi belirtilen yere göre listeye yerleştirir . #1 ilk öğedir .", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Bir öğeyi belirtilen yere göre listeye yerleştirir . #1 son öğedir .", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Bir listenin ilk öğesini yerleştirir .", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Bir listedeki son öğeyi yerleştirir .", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Listeye rast gele bir öğe yerleştirir .", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Bir öğeyi belirtilen pozisyona göre listeye yerleştirir . #1 ilk öğedir .", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Bir öğeyi , belirtilen yer pozisyonuna göre , listeye yerleştirir . #1 son öğedir .", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Nesneyi listenin başlangıcına ekler.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Öğeyi listenin sonuna ekle .", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Bir öğeyi listeye rast gele ekler .", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist alt liste", "LISTS_GET_SUBLIST_START_FROM_START": "# dan alt liste al", "LISTS_GET_SUBLIST_START_FROM_END": "# işaretinden sonra gelen ifadeye göre alt liste al , # sondan", "LISTS_GET_SUBLIST_START_FIRST": "ilk öğeden alt liste al", "LISTS_GET_SUBLIST_END_FROM_START": "#'a", "LISTS_GET_SUBLIST_END_FROM_END": "Sondan #'a kadar", "LISTS_GET_SUBLIST_END_LAST": "Sona kadar", "LISTS_GET_SUBLIST_TAIL": "", "LISTS_GET_SUBLIST_TOOLTIP": "Listenin belirli bir kısmının kopyasını yaratır.", "ORDINAL_NUMBER_SUFFIX": "", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TITLE": "", "VARIABLES_GET_TAIL": "", "VARIABLES_GET_TOOLTIP": "Bu değişkenin değerini verir.", "VARIABLES_GET_CREATE_SET": "'set %1' oluştur", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "Atamak", "VARIABLES_SET_TAIL": "e", "VARIABLES_SET_TOOLTIP": "Bu değişkeni girilen değere eşitler.", "VARIABLES_SET_CREATE_GET": "'get %1' oluştur", "PROCEDURES_DEFNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFNORETURN_TITLE": "e", "PROCEDURES_DEFNORETURN_PROCEDURE": "birşey yap", "PROCEDURES_BEFORE_PARAMS": "ile :", "PROCEDURES_DEFNORETURN_DO": "", "PROCEDURES_DEFNORETURN_TOOLTIP": "Çıktı vermeyen bir fonksiyon yaratır .", "PROCEDURES_DEFRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_DEFRETURN_RETURN": "Geri dön", "PROCEDURES_DEFRETURN_TOOLTIP": "Çıktı veren bir fonksiyon oluşturur.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Uyarı: Bu fonksiyon yinelenen parametreler vardır.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29 prosedür_%28bilgisayar_bilimi%29", "PROCEDURES_CALLNORETURN_CALL": "", "PROCEDURES_CALLNORETURN_TOOLTIP": "Kullanıcı tanımlı fonksiyonu çalıştır '%1' .", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "Kullanıcı tanımlı fonksiyonu çalıştır '%1' ve çıktısını kullan .", "PROCEDURES_MUTATORCONTAINER_TITLE": "girdiler", "PROCEDURES_MUTATORARG_TITLE": "girdi adı:", "PROCEDURES_HIGHLIGHT_DEF": "Fonksiyon tanımı vurgulamak", "PROCEDURES_CREATE_DO": "'%1' oluştur", "PROCEDURES_IFRETURN_TOOLTIP": "Eğer değer doğruysa, ikinci değere geri dön.", "PROCEDURES_IFRETURN_WARNING": "Uyarı: Bu blok yalnızca bir fonksiyon tanımı içinde kullanılır." } ================================================ FILE: extern/blockly/msg/json/uk.json ================================================ { "@metadata": { "authors": [ "Andriykopanytsia" ] }, "VARIABLES_DEFAULT_NAME": "елемент", "DUPLICATE_BLOCK": "Дублікат", "ADD_COMMENT": "Додати коментар", "REMOVE_COMMENT": "Видалити коментар", "EXTERNAL_INPUTS": "Зовнішні входи", "INLINE_INPUTS": "Вбудовані входи", "DELETE_BLOCK": "Видалити блок", "DELETE_X_BLOCKS": "Видалити %1 блоків", "COLLAPSE_BLOCK": "Згорнути блок", "COLLAPSE_ALL": "Згорнути блоки", "EXPAND_BLOCK": "Розгорнути блок", "EXPAND_ALL": "Розгорнути блоки", "DISABLE_BLOCK": "Вимкнути блок", "ENABLE_BLOCK": "Увімкнути блок", "HELP": "Довідка", "CHANGE_VALUE_TITLE": "Змінити значення:", "NEW_VARIABLE": "Нова змінна...", "NEW_VARIABLE_TITLE": "Нове ім'я змінної:", "RENAME_VARIABLE": "Перейменувати змінну...", "RENAME_VARIABLE_TITLE": "Перейменувати усі змінні \"%1\" до:", "COLOUR_PICKER_HELPURL": "https://uk.wikipedia.org/wiki/Колір", "COLOUR_PICKER_TOOLTIP": "Вибрати колір з палітри.", "COLOUR_RANDOM_TITLE": "випадковий колір", "COLOUR_RANDOM_TOOLTIP": "Вибрати колір навмання.", "COLOUR_RGB_HELPURL": "http://www.december.com/html/spec/colorper.html", "COLOUR_RGB_TITLE": "колір з", "COLOUR_RGB_RED": "червоний", "COLOUR_RGB_GREEN": "зелений", "COLOUR_RGB_BLUE": "синій", "COLOUR_RGB_TOOLTIP": "Створити колір з указаного червоного, зеленого та синього. Усі значення мають бути від 0 до 100.", "COLOUR_BLEND_HELPURL": "http://meyerweb.com/eric/tools/color-blend/", "COLOUR_BLEND_TITLE": "суміш", "COLOUR_BLEND_COLOUR1": "колір 1", "COLOUR_BLEND_COLOUR2": "колір 2", "COLOUR_BLEND_RATIO": "співвідношення", "COLOUR_BLEND_TOOLTIP": "Змішує дві барви разом з даним співвідношенням (0.0 - 1.0).", "CONTROLS_REPEAT_HELPURL": "http://en.Wikipedia.org/Wiki/For_loop", "CONTROLS_REPEAT_TITLE": "повторити %1 разів", "CONTROLS_REPEAT_TITLE_REPEAT": "повторити", "CONTROLS_REPEAT_TITLE_TIMES": "разів", "CONTROLS_REPEAT_INPUT_DO": "зробити", "CONTROLS_REPEAT_TOOLTIP": "Зробити деякі заяви кілька разів.", "CONTROLS_WHILEUNTIL_HELPURL": "http://code.google.com/p/blockly/wiki/Repeat", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "повторювати поки", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "повторювати доки", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Поки значення true, зробити деякі заяви.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Поки значення false, зробити деякі заяви.", "CONTROLS_FOR_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#count_with", "CONTROLS_FOR_TOOLTIP": "Наявна змінна %1 приймає значення від початкового значення до кінцевого значення, враховуючи заданий інтервал, і зробіть вказані блоки.", "CONTROLS_FOR_INPUT_WITH": "рахувати з", "CONTROLS_FOR_INPUT_FROM_TO_BY": "від %1 до %2 через %3", "CONTROLS_FOREACH_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#for_each for each block", "CONTROLS_FOREACH_INPUT_ITEM": "для кожного елемента", "CONTROLS_FOREACH_INPUT_INLIST": "у списку", "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "блок тексту", "CONTROLS_FOREACH_TOOLTIP": "Для кожного елемента в списку задайте змінну '%1' для елемента, а потім зробіть деякі заяви.", "CONTROLS_FLOW_STATEMENTS_HELPURL": "https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "перервати цикл", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "продовжити з наступної ітерації циклу", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Вирватися з циклічних оточень.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Пропустити залишок цього циклу і перейти до виконання наступної ітерації.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Попередження: цей блок може бути використаний тільки в межах циклу.", "CONTROLS_IF_HELPURL": "http://code.google.com/p/blockly/wiki/If_Then", "CONTROLS_IF_TOOLTIP_1": "Якщо значення true, зробити деякі заяви.", "CONTROLS_IF_TOOLTIP_2": "Якщо значення істина, то виконується перший блок операторів. В іншому випадку виконується другий блок операторів.", "CONTROLS_IF_TOOLTIP_3": "Якщо перше значення істина, то виконується перший блок операторів. В іншому випадку, якщо друге значення істина, то виконується другий блок операторів.", "CONTROLS_IF_TOOLTIP_4": "Якщо перше значення істина, то виконується перший блок операторів. В іншому випадку, якщо друге значення істина, то виконується другий блок операторів. Якщо жодне із значень не є істинним, то виконується останній блок операторів.", "CONTROLS_IF_MSG_IF": "якщо", "CONTROLS_IF_MSG_ELSEIF": "Інакше якщо", "CONTROLS_IF_MSG_ELSE": "інакше", "CONTROLS_IF_IF_TOOLTIP": "Додати, видалити або змінити порядок розділів переналаштувати це, якщо блокується.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Додати умову до якщо блокувати.", "CONTROLS_IF_ELSE_TOOLTIP": "Додати остаточну, всеосяжну умова до блоку якщо.", "LOGIC_COMPARE_HELPURL": "https://uk.wikipedia.org/wiki/Нерівність", "LOGIC_COMPARE_TOOLTIP_EQ": "Повертає true, якщо обидва входи рівні один одному.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Повертає true, якщо обидва входи не дорівнюють один одному.", "LOGIC_COMPARE_TOOLTIP_LT": "Повертає true, якщо перше вхідне значення менше, ніж другий вхід.", "LOGIC_COMPARE_TOOLTIP_LTE": "Повертає true, якщо перше вхідне значення менше або дорівнює другому входу.", "LOGIC_COMPARE_TOOLTIP_GT": "Повертає true, якщо перше вхідне значення більше, ніж другий вхід.", "LOGIC_COMPARE_TOOLTIP_GTE": "Повертає true, якщо перше вхідне значення більше або дорівнює другому входу.", "LOGIC_OPERATION_HELPURL": "http://code.google.com/p/blockly/wiki/And_Or", "LOGIC_OPERATION_TOOLTIP_AND": "Повертає true, якщо обидва входи істинні.", "LOGIC_OPERATION_AND": "та", "LOGIC_OPERATION_TOOLTIP_OR": "Повертає true, якщо принаймні один з входів true.", "LOGIC_OPERATION_OR": "або", "LOGIC_NEGATE_HELPURL": "http://code.google.com/p/blockly/wiki/Not", "LOGIC_NEGATE_TITLE": "не %1", "LOGIC_NEGATE_TOOLTIP": "Повертає істина, якщо вхідне значення хибність. Повертає хибність, якщо вхідна значення істина.", "LOGIC_BOOLEAN_HELPURL": "http://code.google.com/p/blockly/wiki/True_False", "LOGIC_BOOLEAN_TRUE": "істина", "LOGIC_BOOLEAN_FALSE": "хибність", "LOGIC_BOOLEAN_TOOLTIP": "Повертає значення ІСТИНА або ХИБНІСТЬ.", "LOGIC_NULL_HELPURL": "https://en.wikipedia.org/wiki/Nullable_type", "LOGIC_NULL": "нічого", "LOGIC_NULL_TOOLTIP": "Повертає null.", "LOGIC_TERNARY_HELPURL": "https://en.wikipedia.org/wiki/%3F:", "LOGIC_TERNARY_CONDITION": "тест", "LOGIC_TERNARY_IF_TRUE": "якщо істина", "LOGIC_TERNARY_IF_FALSE": "Якщо хибність", "LOGIC_TERNARY_TOOLTIP": "Перевірте умову в 'test'. Якщо умова істинна, то повертає значення типу 'якщо істина'; в іншому випадку повертає значення 'якщо хибність'.", "MATH_NUMBER_HELPURL": "https://uk.wikipedia.org/wiki/Число", "MATH_NUMBER_TOOLTIP": "Число.", "MATH_ARITHMETIC_HELPURL": "https://uk.wikipedia.org/wiki/Арифметика", "MATH_ARITHMETIC_TOOLTIP_ADD": "Повертає суму двох чисел.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Повертає різницю двох чисел.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Повертає добуток двох чисел.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Повертає частку двох чисел.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Повертає перше число, піднесене до степеня другого числа.", "MATH_SINGLE_HELPURL": "https://uk.wikipedia.org/wiki/Квадратний_корінь", "MATH_SINGLE_OP_ROOT": "квадратний корінь", "MATH_SINGLE_TOOLTIP_ROOT": "Повертає квадратний корінь числа.", "MATH_SINGLE_OP_ABSOLUTE": "модуль", "MATH_SINGLE_TOOLTIP_ABS": "Повертає модуль числа.", "MATH_SINGLE_TOOLTIP_NEG": "Повертає протилежне число.", "MATH_SINGLE_TOOLTIP_LN": "Повертає натуральний логарифм числа.", "MATH_SINGLE_TOOLTIP_LOG10": "Повертає десятковий логарифм числа.", "MATH_SINGLE_TOOLTIP_EXP": "Повертає e у степені.", "MATH_SINGLE_TOOLTIP_POW10": "Повертає 10 у степені.", "MATH_TRIG_HELPURL": "https://uk.wikipedia.org/wiki/Тригонометричні_функції", "MATH_TRIG_TOOLTIP_SIN": "Повертає синус кута у градусах (не у радіанах).", "MATH_TRIG_TOOLTIP_COS": "Повертає косинус кута у градусах (не у радіанах).", "MATH_TRIG_TOOLTIP_TAN": "Повертає тангенс кута у градусах (не у радіанах).", "MATH_TRIG_TOOLTIP_ASIN": "Повертає арксинус числа.", "MATH_TRIG_TOOLTIP_ACOS": "Повертає арккосинус числа.", "MATH_TRIG_TOOLTIP_ATAN": "Повертає арктангенс числа.", "MATH_CONSTANT_HELPURL": "https://uk.wikipedia.org/wiki/Математична_константа", "MATH_CONSTANT_TOOLTIP": "Повертає одну з поширених констант: π (3.141...), e (2.718...), φ (1,618...), sqrt(2) (1.414...), sqrt(½) (0.707...) або ∞ (безмежність).", "MATH_IS_EVEN": "парне", "MATH_IS_ODD": "непарне", "MATH_IS_PRIME": "просте", "MATH_IS_WHOLE": "ціле", "MATH_IS_POSITIVE": "додатне", "MATH_IS_NEGATIVE": "від'ємне", "MATH_IS_DIVISIBLE_BY": "ділиться на", "MATH_IS_TOOLTIP": "Перевіряє, чи число парне, непарне, просте, ціле, додатне, від'ємне або чи воно ділиться на певне число без остачі. Повертає істина або хибність.", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "змінити", "MATH_CHANGE_INPUT_BY": "від", "MATH_CHANGE_TOOLTIP": "Додати число змінній '%1'.", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Округлення числа у більшу або меншу сторону.", "MATH_ROUND_OPERATOR_ROUND": "округлити", "MATH_ROUND_OPERATOR_ROUNDUP": "округлити у більшу сторону", "MATH_ROUND_OPERATOR_ROUNDDOWN": "округлити у меншу сторону", "MATH_ONLIST_HELPURL": "http://www.mapleprimes.com/questions/100441-Applying-Function-To-List-Of-Numbers", "MATH_ONLIST_OPERATOR_SUM": "сума списку", "MATH_ONLIST_TOOLTIP_SUM": "Повертає суму всіх чисел у списку.", "MATH_ONLIST_OPERATOR_MIN": "мінімум списку", "MATH_ONLIST_TOOLTIP_MIN": "Повертає найменше число у списку.", "MATH_ONLIST_OPERATOR_MAX": "максимум списку", "MATH_ONLIST_TOOLTIP_MAX": "Повертає найбільше число у списку.", "MATH_ONLIST_OPERATOR_AVERAGE": "середнє списку", "MATH_ONLIST_TOOLTIP_AVERAGE": "Повертає середнє (арифметичне) числових значень у списку.", "MATH_ONLIST_OPERATOR_MEDIAN": "медіана списку", "MATH_ONLIST_TOOLTIP_MEDIAN": "Повертає медіану списку.", "MATH_ONLIST_OPERATOR_MODE": "моди списку", "MATH_ONLIST_TOOLTIP_MODE": "Повертає перелік найпоширеніших елементів у списку.", "MATH_ONLIST_OPERATOR_STD_DEV": "стандартне відхилення списку", "MATH_ONLIST_TOOLTIP_STD_DEV": "Повертає стандартне відхилення списку.", "MATH_ONLIST_OPERATOR_RANDOM": "випадковий елемент списку", "MATH_ONLIST_TOOLTIP_RANDOM": "Повертає випадковий елемент зі списку.", "MATH_MODULO_HELPURL": "https://uk.wikipedia.org/wiki/Ділення_з_остачею", "MATH_MODULO_TITLE": "остача від %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Повертає остачу від ділення двох чисел.", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "обмежити %1 від %2 до %3", "MATH_CONSTRAIN_TOOLTIP": "Обмежує число вказаними межами (включно).", "MATH_RANDOM_INT_HELPURL": "https://uk.wikipedia.org/wiki/Генерація_випадкових_чисел", "MATH_RANDOM_INT_TITLE": "випадкове ціле число від %1 до %2", "MATH_RANDOM_INT_TOOLTIP": "Повертає випадкове ціле число між двома заданими межами включно.", "MATH_RANDOM_FLOAT_HELPURL": "https://uk.wikipedia.org/wiki/Генерація_випадкових_чисел", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "випадковий дріб", "MATH_RANDOM_FLOAT_TOOLTIP": "Повертає випадковий дріб від 0,0 (включно) та 1.0 (не включно).", "TEXT_TEXT_HELPURL": "https://uk.wikipedia.org/wiki/Рядок_(програмування)", "TEXT_TEXT_TOOLTIP": "Символ, слово або рядок тексту.", "TEXT_JOIN_HELPURL": "http://www.chemie.fu-berlin.de/chemnet/use/info/make/make_8.html", "TEXT_JOIN_TITLE_CREATEWITH": "створити текст з", "TEXT_JOIN_TOOLTIP": "Створити фрагмент тексту шляхом приєднання будь-якого числа елементів.", "TEXT_CREATE_JOIN_TITLE_JOIN": "приєднати", "TEXT_CREATE_JOIN_TOOLTIP": "Додати, видалити або змінити порядок розділів для переналаштування блокування тексту.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "Додати елемент до тексту.", "TEXT_APPEND_HELPURL": "http://www.liv.ac.uk/HPC/HTMLF90Course/HTMLF90CourseNotesnode91.html", "TEXT_APPEND_TO": "до", "TEXT_APPEND_APPENDTEXT": "додати текст", "TEXT_APPEND_TOOLTIP": "Додати який-небудь текст змінній '%1'.", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "довжина %1", "TEXT_LENGTH_TOOLTIP": "Повертає число символів (включаючи пробіли) у даному тексті.", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1 є порожнім", "TEXT_ISEMPTY_TOOLTIP": "Повертає true, якщо вказаний текст порожній.", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "Повертає індекс першого/останнього входження першого тексту у другому. Повертає 0, якщо текст не знайдений.", "TEXT_INDEXOF_INPUT_INTEXT": "у тексті", "TEXT_INDEXOF_OPERATOR_FIRST": "знайти перше входження тексту", "TEXT_INDEXOF_OPERATOR_LAST": "знайти останнє входження тексту", "TEXT_INDEXOF_TAIL": ".", "TEXT_CHARAT_HELPURL": "http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Farsubex.htm", "TEXT_CHARAT_INPUT_INTEXT": "у тексті", "TEXT_CHARAT_FROM_START": "отримати символ", "TEXT_CHARAT_FROM_END": "отримати символ # з кінця", "TEXT_CHARAT_FIRST": "отримати перший символ", "TEXT_CHARAT_LAST": "отримати останній символ", "TEXT_CHARAT_RANDOM": "отримати випадковий символ", "TEXT_CHARAT_TAIL": "-ий.", "TEXT_CHARAT_TOOLTIP": "Повертає символ у зазначеній позиції.", "TEXT_GET_SUBSTRING_TOOLTIP": "Повертає заданий фрагмент тексту.", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "у тексті", "TEXT_GET_SUBSTRING_START_FROM_START": "отримати підрядок від символу", "TEXT_GET_SUBSTRING_START_FROM_END": "отримати підрядок від символу # з кінця", "TEXT_GET_SUBSTRING_START_FIRST": "отримати підрядок від першого символу", "TEXT_GET_SUBSTRING_END_FROM_START": "до символу #", "TEXT_GET_SUBSTRING_END_FROM_END": "до символу з кінця", "TEXT_GET_SUBSTRING_END_LAST": "до останнього символу", "TEXT_GET_SUBSTRING_TAIL": "-ого.", "TEXT_CHANGECASE_HELPURL": "http://www.liv.ac.uk/HPC/HTMLF90Course/HTMLF90CourseNotesnode91.html", "TEXT_CHANGECASE_TOOLTIP": "Повернути копію тексту в іншому випадку.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "до ВЕРХНЬОГО регістру", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "до нижнього регістру", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "Великі Перші Букви", "TEXT_TRIM_HELPURL": "http://www.liv.ac.uk/HPC/HTMLF90Course/HTMLF90CourseNotesnode91.html", "TEXT_TRIM_TOOLTIP": "Повертає копію тексту з пробілами вилученими від одного або обох кінців.", "TEXT_TRIM_OPERATOR_BOTH": "викидати крайні пробіли з обох сторін", "TEXT_TRIM_OPERATOR_LEFT": "вилучати пробіли з лівого боку", "TEXT_TRIM_OPERATOR_RIGHT": "вилучати пробіли з правого боку", "TEXT_PRINT_HELPURL": "http://www.liv.ac.uk/HPC/HTMLF90Course/HTMLF90CourseNotesnode91.html", "TEXT_PRINT_TITLE": "друк %1", "TEXT_PRINT_TOOLTIP": "Надрукувати заданий текст, числа або інші символи.", "TEXT_PROMPT_HELPURL": "http://www.liv.ac.uk/HPC/HTMLF90Course/HTMLF90CourseNotesnode92.html", "TEXT_PROMPT_TYPE_TEXT": "запит на текст з повідомлення", "TEXT_PROMPT_TYPE_NUMBER": "запит на число з повідомлення", "TEXT_PROMPT_TOOLTIP_NUMBER": "Запитувати у користувача число.", "TEXT_PROMPT_TOOLTIP_TEXT": "Запитувати у користувача деякий текст.", "LISTS_CREATE_EMPTY_HELPURL": "https://uk.wikipedia.org/wiki/Зв%27язаний_список", "LISTS_CREATE_EMPTY_TITLE": "створити порожній список", "LISTS_CREATE_EMPTY_TOOLTIP": "Повертає список, довжиною 0, що не містить записів даних", "LISTS_CREATE_WITH_TOOLTIP": "Створює список з будь-якою кількістю елементів.", "LISTS_CREATE_WITH_INPUT_WITH": "створює список з", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "список", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Додати, видалити або змінити порядок розділів для переналаштування блокування списку.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Додати елемент до списку.", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "Створює список, що складається з заданого значення повтореного певну кількість разів.", "LISTS_REPEAT_TITLE": "створити список з елемента %1 повтореного %2 разів", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "довжина %1", "LISTS_LENGTH_TOOLTIP": "Повертає довжину списку.", "LISTS_IS_EMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#is_empty", "LISTS_IS_EMPTY_TITLE": "%1 є порожнім", "LISTS_TOOLTIP": "Повертає істина, якщо список порожній.", "LISTS_INLIST": "у списку", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "знайти перше входження елемента", "LISTS_INDEX_OF_LAST": "знайти останнє входження елемента", "LISTS_INDEX_OF_TOOLTIP": "Повертає індекс першого/останнього входження першого елементу у списку. Повертає 0, якщо текст не знайдений.", "LISTS_GET_INDEX_GET": "отримати", "LISTS_GET_INDEX_GET_REMOVE": "отримати і видалити", "LISTS_GET_INDEX_REMOVE": "вилучити", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "# з кінця", "LISTS_GET_INDEX_FIRST": "перший", "LISTS_GET_INDEX_LAST": "останній", "LISTS_GET_INDEX_RANDOM": "випадковий", "LISTS_GET_INDEX_TAIL": "-ий.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Повертає елемент у заданій позицію у списку. #1 - це перший пункт.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Повертає елемент у заданій позиції у списку. #1 - це останній пункт.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Повертає перший елемент у списку.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Повертає останній елемент списку.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Повертає випадковий елемент у списку.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Видаляє і повертає елемент у заданій позиції у списку. #1 - це перший пункт.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Видаляє і повертає елемент у заданій позиції у списку. #1 - це останній пункт.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Видаляє і повертає перший елемент у списку.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Видаляє і повертає останній елемент списку.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Видаляє і повертає випадковий елемент у список.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Вилучає елемент у вказаній позиції списку. #1 - це перший пункт.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Вилучає елемент у вказаній позиції списку. #1 - це останній пункт.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Видаляє перший елемент у списку.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Видаляє останній елемент списку.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Видаляє випадковий елемент у списку.", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "встановити", "LISTS_SET_INDEX_INSERT": "вставити в", "LISTS_SET_INDEX_INPUT_TO": "як", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Задає елемент у вказаній позиції списку. #1 - це перший пункт.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Задає елемент у вказаній позиції списку. #1 - це останній пункт.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Задає перший елемент у списку.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Задає останній елемент списку.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Задає випадковий елемент у списку.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Вставка елемента у вказану позицію списку. #1 є першим пунктом.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Вставляє елемент у вказану позицію списку. #1 - це останній пункт.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Вставляє елемент на початок списку.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Додає елемент до кінця списку.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Випадковим чином вставляє елемент у списку.", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "отримати вкладений список з #", "LISTS_GET_SUBLIST_START_FROM_END": "отримати вкладений список від # з кінця", "LISTS_GET_SUBLIST_START_FIRST": "отримати вкладений список з першого", "LISTS_GET_SUBLIST_END_FROM_START": "до #", "LISTS_GET_SUBLIST_END_FROM_END": "до # з кінця", "LISTS_GET_SUBLIST_END_LAST": "до останнього", "LISTS_GET_SUBLIST_TAIL": "символу.", "LISTS_GET_SUBLIST_TOOLTIP": "Створює копію вказаної частини списку.", "ORDINAL_NUMBER_SUFFIX": "-ий.", "VARIABLES_GET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Get", "VARIABLES_GET_TITLE": "значення", "VARIABLES_GET_TAIL": "значення", "VARIABLES_GET_TOOLTIP": "Повертає значення цієї змінної.", "VARIABLES_GET_CREATE_SET": "Створити 'set %1'", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "встановити", "VARIABLES_SET_TAIL": "до", "VARIABLES_SET_TOOLTIP": "Задає цю змінну рівною вводу.", "VARIABLES_SET_CREATE_GET": "Створити 'get %1'", "PROCEDURES_DEFNORETURN_HELPURL": "https://uk.wikipedia.org/wiki/Підпрограма", "PROCEDURES_DEFNORETURN_TITLE": "до", "PROCEDURES_DEFNORETURN_PROCEDURE": "щось зробити", "PROCEDURES_BEFORE_PARAMS": "з:", "PROCEDURES_DEFNORETURN_DO": "блок тексту", "PROCEDURES_DEFNORETURN_TOOLTIP": "Створює функцію без виводу.", "PROCEDURES_DEFRETURN_HELPURL": "https://uk.wikipedia.org/wiki/Підпрограма", "PROCEDURES_DEFRETURN_RETURN": "повернути", "PROCEDURES_DEFRETURN_TOOLTIP": "Створює функцію з виводу.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Увага: ця функція має дубльовані параметри.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_CALL": "блок тексту", "PROCEDURES_CALLNORETURN_TOOLTIP": "Запустити користувацьку функцію \"%1\".", "PROCEDURES_CALLRETURN_HELPURL": "https://uk.wikipedia.org/wiki/Підпрограма", "PROCEDURES_CALLRETURN_TOOLTIP": "Запустити користувацьку функцію \"%1\" і використовувати її вивід.", "PROCEDURES_MUTATORCONTAINER_TITLE": "вхід", "PROCEDURES_MUTATORARG_TITLE": "ім'я входу:", "PROCEDURES_HIGHLIGHT_DEF": "Визначення функції підсвітки", "PROCEDURES_CREATE_DO": "Створити \"%1\"", "PROCEDURES_IFRETURN_TOOLTIP": "Якщо значення true, то повернути друге значення.", "PROCEDURES_IFRETURN_WARNING": "Попередження: Цей блок може використовуватися лише в межах визначення функції." } ================================================ FILE: extern/blockly/msg/json/vi.json ================================================ { "@metadata": { "authors": [ "Baonguyen21022003", "Espertus", "Qneutron" ] }, "VARIABLES_DEFAULT_NAME": "vật", "DUPLICATE_BLOCK": "Tạo Bản Sao", "ADD_COMMENT": "Thêm Chú Giải", "REMOVE_COMMENT": "Xóa Chú Giải", "EXTERNAL_INPUTS": "Chỗ Gắn Bên Ngoài", "INLINE_INPUTS": "Chỗ Gắn Cùng Dòng", "DELETE_BLOCK": "Xóa Mảnh Này", "DELETE_X_BLOCKS": "Xóa %1 Mảnh", "COLLAPSE_BLOCK": "Thu Nhỏ Mảnh", "COLLAPSE_ALL": "Thu Nhỏ Mọi Mảnh", "EXPAND_BLOCK": "Mở Lớn Mảnh", "EXPAND_ALL": "Mở Lớn Mọi Mảnh", "DISABLE_BLOCK": "Ngưng Tác Dụng", "ENABLE_BLOCK": "Phục Hồi Tác Dụng", "HELP": "Trợ Giúp", "CHANGE_VALUE_TITLE": "Thay giá trị thành:", "NEW_VARIABLE": "Biến mới...", "NEW_VARIABLE_TITLE": "Tên của biến mới:", "RENAME_VARIABLE": "Thay tên biến...", "RENAME_VARIABLE_TITLE": "Thay tên tất cả \"%1\" biến này thành:", "COLOUR_PICKER_HELPURL": "https://vi.wikipedia.org/wiki/M%C3%A0u_s%E1%BA%AFc", "COLOUR_PICKER_TOOLTIP": "Chọn một màu từ bảng màu.", "COLOUR_RANDOM_TITLE": "màu bất kỳ", "COLOUR_RANDOM_TOOLTIP": "chọn một màu bất kỳ.", "COLOUR_RGB_TITLE": "Tạo màu từ", "COLOUR_RGB_RED": "màu đỏ", "COLOUR_RGB_GREEN": "màu xanh lá cây", "COLOUR_RGB_BLUE": "màu xanh dương", "COLOUR_RGB_TOOLTIP": "Tạo màu từ ba màu: đỏ, xanh lá cây, xanh dương với số lượng cụ thể. Mỗi số phải có giá trị từ 0 đến 100.", "COLOUR_BLEND_TITLE": "pha", "COLOUR_BLEND_COLOUR1": "màu 1", "COLOUR_BLEND_COLOUR2": "màu 2", "COLOUR_BLEND_RATIO": "tỉ lệ", "COLOUR_BLEND_TOOLTIP": "Pha hai màu với nhau theo tỉ lệ (0 - 100).", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "lặp lại %1 lần", "CONTROLS_REPEAT_TITLE_REPEAT": "lặp lại", "CONTROLS_REPEAT_TITLE_TIMES": "lần", "CONTROLS_REPEAT_INPUT_DO": "thực hiện", "CONTROLS_REPEAT_TOOLTIP": "Thực hiện các lệnh vài lần.", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "lặp lại trong khi", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "lặp lại cho đến khi", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "Miễn là điều kiện còn đúng, thì thực hiện các lệnh.", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "Miễn là điều kiện còn sai, thì thực hiện các lệnh. Khi điều kiện đúng thì ngưng.", "CONTROLS_FOR_TOOLTIP": "Đếm từ số đầu đến số cuối. Khi đến mỗi số, gán số vào biến \"%1\" rồi thực hiện các lệnh.", "CONTROLS_FOR_INPUT_WITH": "đếm theo", "CONTROLS_FOR_INPUT_FROM_TO_BY": "từ %1 đến %2 mỗi lần thêm %3", "CONTROLS_FOREACH_INPUT_ITEM": "với mỗi thành phần", "CONTROLS_FOREACH_INPUT_INLIST": "trong danh sách", "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "", "CONTROLS_FOREACH_TOOLTIP": "Trong một danh sách, lấy từng thành phần, gán vào biến \"%1\", rồi thực hiện một số lệnh.", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "thoát", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "sang lần lặp tiếp theo", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "Thoát khỏi vòng lặp hiện tại.", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "Bỏ qua phần còn lại trong vòng lặp này, và sang lần lặp tiếp theo.", "CONTROLS_FLOW_STATEMENTS_WARNING": "Chú ý: Mảnh này chỉ có thế dùng trong các vòng lặp.", "CONTROLS_IF_TOOLTIP_1": "Nếu điều kiện đúng, thực hiện các lệnh.", "CONTROLS_IF_TOOLTIP_2": "Nếu điều kiện đúng, thực hiện các lệnh đầu. Nếu sai, thực hiện các lệnh sau.", "CONTROLS_IF_TOOLTIP_3": "Nếu điều kiện đúng, thực hiện các lệnh đầu. Nếu không, nếu điều kiện thứ hai đúng, thực hiện các lệnh thứ hai.", "CONTROLS_IF_TOOLTIP_4": "Nếu điều kiện đúng, thực hiện các lệnh đầu. Nếu không, nếu điều kiện thứ hai đúng, thực hiện các lệnh thứ hai. Nếu không điều kiện nào đúng, thực hiện các lệnh cuối cùng.", "CONTROLS_IF_MSG_IF": "nếu", "CONTROLS_IF_MSG_ELSEIF": "nếu không nếu", "CONTROLS_IF_MSG_ELSE": "nếu không", "CONTROLS_IF_IF_TOOLTIP": "Thêm, bỏ, hoặc đổi thứ tự các mảnh con để tạo cấu trúc mới cho mảnh nếu.", "CONTROLS_IF_ELSEIF_TOOLTIP": "Thêm một điều kiện vào mảnh nếu.", "CONTROLS_IF_ELSE_TOOLTIP": "Cuối cùng, khi không điều kiện nào đúng.", "LOGIC_COMPARE_HELPURL": "https://vi.wikipedia.org/wiki/B%E1%BA%A5t_%C4%91%E1%BA%B3ng_th%E1%BB%A9c", "LOGIC_COMPARE_TOOLTIP_EQ": "Hoàn trả giá trị \"đúng\" (true) nếu giá trị hai đầu vào bằng nhau.", "LOGIC_COMPARE_TOOLTIP_NEQ": "Hoàn trả giá trị \"đúng\" (true) nếu giá trị hai đầu vào không bằng nhau.", "LOGIC_COMPARE_TOOLTIP_LT": "Hoàn trả giá trị \"đúng\" (true) nếu đầu vào thứ nhất nhỏ hơn đầu vào thứ hai.", "LOGIC_COMPARE_TOOLTIP_LTE": "Hoàn trả giá trị \"đúng\" (true) nếu đầu vào thứ nhất nhỏ hơn hoặc bằng đầu vào thứ hai.", "LOGIC_COMPARE_TOOLTIP_GT": "Hoàn trả giá trị \"đúng\" (true) nếu đầu vào thứ nhất lớn hơn đầu vào thứ hai.", "LOGIC_COMPARE_TOOLTIP_GTE": "Hoàn trả giá trị \"đúng\" (true) nếu đầu vào thứ nhất lớn hơn hoặc bằng đầu vào thứ hai.", "LOGIC_OPERATION_TOOLTIP_AND": "Hoàn trả \"đúng\" (true) nếu cả hai đầu vào đều đúng.", "LOGIC_OPERATION_AND": "và", "LOGIC_OPERATION_TOOLTIP_OR": "Hoàn trả \"đúng\" (true) nếu ít nhất một trong hai đầu vào đúng.", "LOGIC_OPERATION_OR": "hoặc", "LOGIC_NEGATE_TITLE": "không %1", "LOGIC_NEGATE_TOOLTIP": "Hoàn trả \"đúng\" (true) nếu đầu vào sai. Hoàn trả \"sai\" (false) nếu đầu vào đúng.", "LOGIC_BOOLEAN_TRUE": "đúng", "LOGIC_BOOLEAN_FALSE": "sai", "LOGIC_BOOLEAN_TOOLTIP": "Hoàn trả \"đúng\" hoặc \"sai\".", "LOGIC_NULL": "trống không", "LOGIC_NULL_TOOLTIP": "Hoàn trả trống không.", "LOGIC_TERNARY_CONDITION": "kiểm tra", "LOGIC_TERNARY_IF_TRUE": "nếu đúng", "LOGIC_TERNARY_IF_FALSE": "nếu sai", "LOGIC_TERNARY_TOOLTIP": "Kiểm tra điều kiện. Nếu điều kiện đúng, hoàn trả giá trị từ mệnh đề \"nếu đúng\" nếu không đúng, hoàn trả giá trị từ mệnh đề \"nếu sai\".", "MATH_NUMBER_HELPURL": "https://vi.wikipedia.org/wiki/S%E1%BB%91", "MATH_NUMBER_TOOLTIP": "Một con số.", "MATH_ARITHMETIC_HELPURL": "https://vi.wikipedia.org/wiki/S%E1%BB%91_h%E1%BB%8Dc", "MATH_ARITHMETIC_TOOLTIP_ADD": "Hoàn trả tổng của hai con số.", "MATH_ARITHMETIC_TOOLTIP_MINUS": "Hoàn trả hiệu của hai con số.", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "Hoàn trả tích của hai con số.", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "Hoàn trả thương của hai con số.", "MATH_ARITHMETIC_TOOLTIP_POWER": "Hoàn trả số lũy thừa với số thứ nhất là cơ số và số thứ hai là số mũ.", "MATH_SINGLE_HELPURL": "https://vi.wikipedia.org/wiki/C%C4%83n_b%E1%BA%ADc_hai", "MATH_SINGLE_OP_ROOT": "căn bật hai", "MATH_SINGLE_TOOLTIP_ROOT": "Hoàn trả căn bật hai của số đầu vào.", "MATH_SINGLE_OP_ABSOLUTE": "giá trị tuyệt đối", "MATH_SINGLE_TOOLTIP_ABS": "Hoàn trả giá trị tuyệt đối của số đầu vào.", "MATH_SINGLE_TOOLTIP_NEG": "Đổi dấu của số đầu vào: âm thành dương và dương thành âm, và hoàn trả số mới.", "MATH_SINGLE_TOOLTIP_LN": "Hoàn trả lôgarit tự nhiên của số đầu vào.", "MATH_SINGLE_TOOLTIP_LOG10": "Hoàn trả lôgarit cơ số 10 của số đầu vào.", "MATH_SINGLE_TOOLTIP_EXP": "Hoàn trả lũy thừa của số e với số mũ đầu vào.", "MATH_SINGLE_TOOLTIP_POW10": "Hoàn trả lũy thừa của số 10 với số mũ đầu vào.", "MATH_TRIG_HELPURL": "https://vi.wikipedia.org/wiki/H%C3%A0m_l%C6%B0%E1%BB%A3ng_gi%C3%A1c", "MATH_TRIG_TOOLTIP_SIN": "Hoàn trả Sin của một góc (theo độ).", "MATH_TRIG_TOOLTIP_COS": "Hoàn trả Cos của một góc (theo độ).", "MATH_TRIG_TOOLTIP_TAN": "Hoàn trả Tang của một góc (theo độ).", "MATH_TRIG_TOOLTIP_ASIN": "Hoàn trả Arcsin của một góc (theo độ).", "MATH_TRIG_TOOLTIP_ACOS": "Hoàn trả Arccos của một góc (theo độ).", "MATH_TRIG_TOOLTIP_ATAN": "Hoàn trả Arctang của một góc (theo độ).", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "Hoàn trả các đẳng số thường gặp: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (vô cực).", "MATH_IS_EVEN": "chẵn", "MATH_IS_ODD": "lẻ", "MATH_IS_PRIME": "là số nguyên tố", "MATH_IS_WHOLE": "là số nguyên", "MATH_IS_POSITIVE": "là số dương", "MATH_IS_NEGATIVE": "là số âm", "MATH_IS_DIVISIBLE_BY": "chia hết cho", "MATH_IS_TOOLTIP": "Kiểm tra con số xem nó có phải là số chẵn, lẻ, nguyên tố, nguyên, dương, âm, hay xem nó có chia hết cho số đầu vào hay không. Hoàn trả đúng hay sai.", "MATH_CHANGE_HELPURL": "https://vi.wikipedia.org/wiki/Ph%C3%A9p_c%E1%BB%99ng", "MATH_CHANGE_TITLE_CHANGE": "cộng vào", "MATH_CHANGE_INPUT_BY": "giá trị", "MATH_CHANGE_TOOLTIP": "Cộng số đầu vào vào biến \"%1\".", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "Làm tròn lên hoặc tròn xuống số đầu vào.", "MATH_ROUND_OPERATOR_ROUND": "làm tròn", "MATH_ROUND_OPERATOR_ROUNDUP": "làm tròn lên", "MATH_ROUND_OPERATOR_ROUNDDOWN": "làm tròn xuống", "MATH_ONLIST_HELPURL": "", "MATH_ONLIST_OPERATOR_SUM": "tổng của một danh sách", "MATH_ONLIST_TOOLTIP_SUM": "Hoàn trả tổng số của tất cả các số trong danh sách.", "MATH_ONLIST_OPERATOR_MIN": "số nhỏ nhất của một danh sách", "MATH_ONLIST_TOOLTIP_MIN": "Hoàn trả số nhỏ nhất trong tất cả các số trong danh sách.", "MATH_ONLIST_OPERATOR_MAX": "số lớn nhât của một danh sách", "MATH_ONLIST_TOOLTIP_MAX": "Hoàn trả số lớn nhất trong tất cả các số trong danh sách.", "MATH_ONLIST_OPERATOR_AVERAGE": "giá trị trung bình của một danh sách", "MATH_ONLIST_TOOLTIP_AVERAGE": "Hoàn trả giá trị trung bình từ của danh sách số.", "MATH_ONLIST_OPERATOR_MEDIAN": "số trung vị của một danh sách", "MATH_ONLIST_TOOLTIP_MEDIAN": "Hoàn trả số trung vị của danh sách số.", "MATH_ONLIST_OPERATOR_MODE": "các mode của một danh sách", "MATH_ONLIST_TOOLTIP_MODE": "Hoàn trả các số có mặt nhiều nhất trong danh sách.", "MATH_ONLIST_OPERATOR_STD_DEV": "độ lệch chuẩn của một danh sách", "MATH_ONLIST_TOOLTIP_STD_DEV": "Hoàn trả độ lệch chuẩn của danh sách số.", "MATH_ONLIST_OPERATOR_RANDOM": "một số bất kỳ của một danh sách", "MATH_ONLIST_TOOLTIP_RANDOM": "Hoàn trả một số bất kỳ từ các số trong danh sách.", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "số dư của %1 ÷ %2", "MATH_MODULO_TOOLTIP": "Chia số thứ nhất cho số thứ hai rồi hoàn trả số dư từ.", "MATH_CONSTRAIN_TITLE": "giới hạn %1 không dưới %2 không hơn %3", "MATH_CONSTRAIN_TOOLTIP": "Giới hạn số đầu vào để không dưới số thứ nhất và không hơn số thứ hai.", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "Một số nguyên bất kỳ từ %1 đến %2", "MATH_RANDOM_INT_TOOLTIP": "Hoàn trả một số nguyên bất kỳ lớn hơn hoặc bằng số đầu và nhỏ hơn hoặc bằng số sau.", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "phân số bất kỳ", "MATH_RANDOM_FLOAT_TOOLTIP": "Hoàn trả một phân số bất kỳ không nhỏ hơn 0.0 và không lớn hơn 1.0.", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/string _(computer_science)", "TEXT_TEXT_TOOLTIP": "Một ký tự, một từ, hay một dòng.", "TEXT_JOIN_HELPURL": "", "TEXT_JOIN_TITLE_CREATEWITH": "tạo văn bản từ", "TEXT_JOIN_TOOLTIP": "Tạo một văn bản từ các thành phần.", "TEXT_CREATE_JOIN_TITLE_JOIN": "kết nối", "TEXT_CREATE_JOIN_TOOLTIP": "Thêm, bỏ, hoặc sắp xếp lại các thành phần để tạo dựng mảnh văn bản này.", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "thêm vật mới vào văn bản.", "TEXT_APPEND_TO": "ở cuối", "TEXT_APPEND_APPENDTEXT": "thêm văn bản", "TEXT_APPEND_TOOLTIP": "Thêm một mảng văn bản vào biến \"%1\".", "TEXT_LENGTH_TITLE": "độ dài của %1", "TEXT_LENGTH_TOOLTIP": "Hoàn trả số lượng ký tự (kể cả khoảng trắng) trong văn bản đầu vào.", "TEXT_ISEMPTY_TITLE": "%1 trống không", "TEXT_ISEMPTY_TOOLTIP": "Hoàn trả “đúng nếu văn bản không có ký tự nào.", "TEXT_INDEXOF_TOOLTIP": "Hoàn trả vị trí xuất hiện đầu/cuối của văn bản thứ nhất trong văn bản thứ hai. Nếu không tìm thấy thì hoàn trả số 0.", "TEXT_INDEXOF_INPUT_INTEXT": "trong văn bản", "TEXT_INDEXOF_OPERATOR_FIRST": "tìm sự có mặt đầu tiên của", "TEXT_INDEXOF_OPERATOR_LAST": "tìm sự có mặt cuối cùng của", "TEXT_CHARAT_INPUT_INTEXT": "trong văn bản", "TEXT_CHARAT_FROM_START": "lấy ký tự thứ", "TEXT_CHARAT_FROM_END": "lấy từ phía cuối, ký tự thứ", "TEXT_CHARAT_FIRST": "lấy ký tự đầu tiên", "TEXT_CHARAT_LAST": "lấy ký tự cuối cùng", "TEXT_CHARAT_RANDOM": "lấy ký tự bất kỳ", "TEXT_CHARAT_TAIL": "", "TEXT_CHARAT_TOOLTIP": "Hoàn trả ký tự ở vị trí đặt ra.", "TEXT_GET_SUBSTRING_TOOLTIP": "Hoàn trả một mảng ký tự ấn định từ trong văn bản.", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "trong văn bản", "TEXT_GET_SUBSTRING_START_FROM_START": "lấy từ ký tự thứ", "TEXT_GET_SUBSTRING_START_FROM_END": "lấy từ phía cuối, ký tự thứ", "TEXT_GET_SUBSTRING_START_FIRST": "lấy từ ký tự đầu tiên", "TEXT_GET_SUBSTRING_END_FROM_START": "đến ký tự thứ", "TEXT_GET_SUBSTRING_END_FROM_END": "đến từ phía cuối, ký tự thứ", "TEXT_GET_SUBSTRING_END_LAST": "đến ký tự cuối cùng", "TEXT_GET_SUBSTRING_TAIL": "", "TEXT_CHANGECASE_TOOLTIP": "Hoàn trả văn bản sau khi chuyển đổi chữ in hoa hay thường.", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "thành CHỮ IN HOA", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "thành chữ thường", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "thành Chữ In Đầu Mỗi Từ", "TEXT_TRIM_TOOLTIP": "Hoàn trả bản sao của văn bản sau khi xóa khoảng trắng từ một hoặc hai bên.", "TEXT_TRIM_OPERATOR_BOTH": "cắt các không gian từ cả hai mặt của", "TEXT_TRIM_OPERATOR_LEFT": "cắt các không gian từ bên trái của", "TEXT_TRIM_OPERATOR_RIGHT": "cắt các không gian từ bên phải của", "TEXT_PRINT_TITLE": "in lên màng hình %1", "TEXT_PRINT_TOOLTIP": "In ra màng hình một văn bản, con số, hay một giá trị đầu vào khác.", "TEXT_PROMPT_TYPE_TEXT": "Xin người dùng nhập vào văn bản với dòng hướng dẫn", "TEXT_PROMPT_TYPE_NUMBER": "Xin người dùng nhập vào con số với dòng hướng dẫn", "TEXT_PROMPT_TOOLTIP_NUMBER": "Xin người dùng nhập vào một con số.", "TEXT_PROMPT_TOOLTIP_TEXT": "Xin người dùng nhập vào một văn bản.", "LISTS_CREATE_EMPTY_TITLE": "tạo danh sách trống", "LISTS_CREATE_EMPTY_TOOLTIP": "Hoàn trả một danh sách, với độ dài 0, không có thành tố nào cả", "LISTS_CREATE_WITH_TOOLTIP": "Tạo một danh sách bao gồm nhiều vậts, với một số lượng bất kỳ.", "LISTS_CREATE_WITH_INPUT_WITH": "tạo danh sách gồm", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "danh sách", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "Thêm, bỏ, hoặc sắp xếp lại các thành phần để tạo dựng mảnh danh sách này.", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "Thêm vật vào danh sách.", "LISTS_REPEAT_TOOLTIP": "Tạo danh sách gồm một số lượng vật nhất định với mỗi vật đều giống nhau.", "LISTS_REPEAT_TITLE": "tạo danh sách gồm một vật %1 lặp lại %2 lần", "LISTS_LENGTH_TITLE": "độ dài của %1", "LISTS_LENGTH_TOOLTIP": "Hoàn trả độ dài của một danh sách.", "LISTS_IS_EMPTY_TITLE": "%1 trống rỗng", "LISTS_TOOLTIP": "Hoàn trả “đúng\" nếu danh sách không có thành tử nào.", "LISTS_INLIST": "trong dánh sách", "LISTS_INDEX_OF_FIRST": "tìm sự có mặt đầu tiên của vật", "LISTS_INDEX_OF_LAST": "tìm sự có mặt cuối cùng của vật", "LISTS_INDEX_OF_TOOLTIP": "Hoàn trả vị trí xuất hiện đầu/cuối của vật trong danh sách. Nếu không tìm thấy thì hoàn trả số 0.", "LISTS_GET_INDEX_GET": "lấy thành tố", "LISTS_GET_INDEX_GET_REMOVE": "lấy và xóa thành tố", "LISTS_GET_INDEX_REMOVE": "xóa thành tố", "LISTS_GET_INDEX_FROM_START": "thứ", "LISTS_GET_INDEX_FROM_END": "(đếm từ cuối) thứ", "LISTS_GET_INDEX_FIRST": "đầu tiên", "LISTS_GET_INDEX_LAST": "cuối cùng", "LISTS_GET_INDEX_RANDOM": "bất kỳ", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "Hoàn trả thành tố trong danh sách ở vị trí ấn định. Số 1 là thành tố đầu tiên.", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "Hoàn trả thành tố trong danh sách ở vị trí ấn định. Số 1 là thành tố cuối cùng.", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "Hoàn trả thành tố đầu tiên trong danh sách.", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "Hoàn trả thành tố cuối cùng trong danh sách.", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "Hoàn trả một thành tố bất kỳ trong danh sách.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "Hoàn trả và xóa thành tố trong danh sách ở vị trí ấn định. Số 1 là thành tố đầu tiên.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "Hoàn trả và xóa thành tố trong danh sách ở vị trí ấn định. Số 1 là thành tố cuối cùng.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "Hoàn trả và xóa thành tố đầu tiên trong danh sách.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "Hoàn trả và xóa thành tố cuối cùng trong danh sách.", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "Hoàn trả và xóa mộtthành tố bất kỳ trong danh sách.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "Xóa thành tố trong danh sách ở vị trí ấn định. Số 1 là thành tố đầu tiên.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "Xóa thành tố trong danh sách ở vị trí ấn định. Số 1 là thành tố cuối cùng.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "Xóa thành tố đầu tiên trong danh sách.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "Xóa thành tố cuối cùng trong danh sách.", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "Xóa thành tố bất kỳ trong danh sách.", "LISTS_SET_INDEX_SET": "đặt thành tố", "LISTS_SET_INDEX_INSERT": "gắn chèn vào vị trí", "LISTS_SET_INDEX_INPUT_TO": "giá trị", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "Đặt giá trị của thành tố ở vị trí ấn định trong một danh sách. #1 là thành tố đầu tiên.", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "Đặt giá trị của thành tố trong một danh sách ở vị trí ấn định từ phía cuối. #1 là thành tố cuối cùng.", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "Đặt giá trị của thành tố đầu tiên trong danh sách.", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "Đặt giá trị của thành tố cuối cùng trong danh sách.", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "Đặt giá trị của thành tố ngẫu nhiên trong danh sách.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "Gắn chèn vật vào danh sách theo vị trí ấn định. #1 là thành tố đầu tiên.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "Gắn chèn vật vào danh sách theo vị trí ấn định từ phía cuối. #1 là thành tố cuối cùng.", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "Gắn chèn vật vào đầu danh sách.", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "Gắn thêm vật vào cuối danh sách.", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "Gắn chèn vật vào danh sách ở vị trí ngẫu nhiên.", "LISTS_GET_SUBLIST_START_FROM_START": "lấy một danh sách con từ thứ", "LISTS_GET_SUBLIST_START_FROM_END": "lấy một danh sách con từ (đếm từ cuối) thứ", "LISTS_GET_SUBLIST_START_FIRST": "lấy một danh sách con từ đầu tiên", "LISTS_GET_SUBLIST_END_FROM_START": "đến thứ", "LISTS_GET_SUBLIST_END_FROM_END": "đến (đếm từ cuối) thứ", "LISTS_GET_SUBLIST_END_LAST": "đến cuối cùng", "LISTS_GET_SUBLIST_TOOLTIP": "Lấy một mảng của danh sách này để tạo danh sách con.", "VARIABLES_GET_TITLE": "", "VARIABLES_GET_TAIL": "", "VARIABLES_GET_TOOLTIP": "Hoàn trả giá trị của.", "VARIABLES_GET_CREATE_SET": "Tạo mảnh \"đặt vào %1\"", "VARIABLES_SET_TITLE": "cho", "VARIABLES_SET_TAIL": "bằng", "VARIABLES_SET_TOOLTIP": "Đặt giá trị của biến này thành...", "VARIABLES_SET_CREATE_GET": "Tạo mảnh \"lấy %1\"", "PROCEDURES_DEFNORETURN_TITLE": "", "PROCEDURES_DEFNORETURN_PROCEDURE": "thủ tục", "PROCEDURES_BEFORE_PARAMS": "với:", "PROCEDURES_DEFNORETURN_DO": "", "PROCEDURES_DEFNORETURN_TOOLTIP": "Một thủ tục không có giá trị hoàn trả.", "PROCEDURES_DEFRETURN_RETURN": "hoàn trả", "PROCEDURES_DEFRETURN_TOOLTIP": "Một thủ tục có giá trị hoàn trả.", "PROCEDURES_DEF_DUPLICATE_WARNING": "Chú ý: Thủ tục này có lặp lại tên các tham số.", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/procedure _ %28computer_science% 29", "PROCEDURES_CALLNORETURN_CALL": "thực hiện", "PROCEDURES_CALLNORETURN_TOOLTIP": "Chạy một thủ tục không có giá trị hoàn trả.", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/procedure _ %28computer_science% 29", "PROCEDURES_CALLRETURN_TOOLTIP": "Chạy một thủ tục có giá trị hoàn trả.", "PROCEDURES_MUTATORCONTAINER_TITLE": "các tham số", "PROCEDURES_MUTATORARG_TITLE": "biến:", "PROCEDURES_HIGHLIGHT_DEF": "Làm nổi bật thủ tục", "PROCEDURES_CREATE_DO": "Tạo mảnh \"thực hiện %1\"", "PROCEDURES_IFRETURN_TOOLTIP": "Khi điều kiện đúng thì hoàn trả một giá trị.", "PROCEDURES_IFRETURN_WARNING": "Chú ý: Mảnh này chỉ có thể dùng trong một thủ tục." } ================================================ FILE: extern/blockly/msg/json/zh-hans.json ================================================ { "@metadata": { "authors": [ "Espertus", "Liuxinyu970226", "Luotiancheng", "Qiyue2001", "Xiaomingyan", "Yfdyh000" ] }, "VARIABLES_DEFAULT_NAME": "项", "DUPLICATE_BLOCK": "复制", "ADD_COMMENT": "添加注释", "REMOVE_COMMENT": "删除注释", "EXTERNAL_INPUTS": "外部输入", "INLINE_INPUTS": "单行输入", "DELETE_BLOCK": "删除块", "DELETE_X_BLOCKS": "删除 %1 块", "COLLAPSE_BLOCK": "折叠块", "COLLAPSE_ALL": "折叠块", "EXPAND_BLOCK": "展开块", "EXPAND_ALL": "展开块", "DISABLE_BLOCK": "禁用块", "ENABLE_BLOCK": "启用块", "HELP": "帮助", "CHANGE_VALUE_TITLE": "更改值:", "NEW_VARIABLE": "新变量...", "NEW_VARIABLE_TITLE": "新变量的名称:", "RENAME_VARIABLE": "重命名变量...", "RENAME_VARIABLE_TITLE": "将所有“%1”变量重命名为:", "COLOUR_PICKER_HELPURL": "https://zh.wikipedia.org/wiki/颜色", "COLOUR_PICKER_TOOLTIP": "从调色板中选择一种颜色。", "COLOUR_RANDOM_TITLE": "随机颜色", "COLOUR_RANDOM_TOOLTIP": "随机选择一种颜色。", "COLOUR_RGB_TITLE": "颜色", "COLOUR_RGB_RED": "红色", "COLOUR_RGB_GREEN": "绿色", "COLOUR_RGB_BLUE": "蓝色", "COLOUR_RGB_TOOLTIP": "通过指定红色、绿色和蓝色的量创建一种颜色。所有的值必须介于0和100之间。", "COLOUR_BLEND_TITLE": "混合", "COLOUR_BLEND_COLOUR1": "颜色1", "COLOUR_BLEND_COLOUR2": "颜色2", "COLOUR_BLEND_RATIO": "比例", "COLOUR_BLEND_TOOLTIP": "用一个给定的比率(0.0-1.0)混合两种颜色。", "CONTROLS_REPEAT_HELPURL": "https://zh.wikipedia.org/wiki/For回圈", "CONTROLS_REPEAT_TITLE": "重复 %1 次", "CONTROLS_REPEAT_TITLE_REPEAT": "重复", "CONTROLS_REPEAT_TITLE_TIMES": "次", "CONTROLS_REPEAT_INPUT_DO": "执行", "CONTROLS_REPEAT_TOOLTIP": "多次执行一些语句。", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "重复当", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "重复直到", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "只要值为真,执行一些语句。", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "只要值为假,执行一些语句。", "CONTROLS_FOR_TOOLTIP": "从起始数到结尾数中取出变量“%1”的值,按指定的时间间隔,执行指定的块。", "CONTROLS_FOR_INPUT_WITH": "使用", "CONTROLS_FOR_INPUT_FROM_TO_BY": "从范围 %1 到 %2 每隔 %3", "CONTROLS_FOREACH_INPUT_ITEM": "为每个项目", "CONTROLS_FOREACH_INPUT_INLIST": "在列表中", "CONTROLS_FOREACH_TOOLTIP": "遍历每个列表中的项目,将变量“%1”设定到该项中,然后执行某些语句。", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "中断循环", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "继续下一次循环", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "中断包含它的循环。", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "跳过这个循环的剩余部分,并继续下一次迭代。", "CONTROLS_FLOW_STATEMENTS_WARNING": "警告:此块仅可用于在一个循环内。", "CONTROLS_IF_TOOLTIP_1": "如果值为真,执行一些语句。", "CONTROLS_IF_TOOLTIP_2": "如果值为真,则执行语句的第一块;否则,则执行语句的第二块。", "CONTROLS_IF_TOOLTIP_3": "如果第一个值为真,则执行语句的第一个块;否则,如果第二个值为真,则执行语句的第二块。", "CONTROLS_IF_TOOLTIP_4": "如果第一个值为真,则执行语句的第一块;否则,如果第二个值为真,则执行语句的第二块;如果没有值为真,则执行语句的最后一块。", "CONTROLS_IF_MSG_IF": "如果", "CONTROLS_IF_MSG_ELSEIF": "否则如果", "CONTROLS_IF_MSG_ELSE": "否则", "CONTROLS_IF_IF_TOOLTIP": "增加、删除或重新排列各节来重新配置“if”块。", "CONTROLS_IF_ELSEIF_TOOLTIP": "在if语句块中增加一个条件。", "CONTROLS_IF_ELSE_TOOLTIP": "添加一个最终的,包括所有情况的节到if块中。", "LOGIC_COMPARE_HELPURL": "https://zh.wikipedia.org/wiki/不等", "LOGIC_COMPARE_TOOLTIP_EQ": "如果两个输入结果相等,则返回真。", "LOGIC_COMPARE_TOOLTIP_NEQ": "如果两个输入结果不相等,则返回真。", "LOGIC_COMPARE_TOOLTIP_LT": "如果第一个输入结果比第二个小,则返回真。", "LOGIC_COMPARE_TOOLTIP_LTE": "如果第一个输入结果小于或等于第二个输入结果,则返回真。", "LOGIC_COMPARE_TOOLTIP_GT": "如果第一个输入结果比第二个大,则返回真。", "LOGIC_COMPARE_TOOLTIP_GTE": "如果第一个输入结果大于或等于第二个输入结果,则返回真。", "LOGIC_OPERATION_TOOLTIP_AND": "如果两个输入结果都为真,则返回真。", "LOGIC_OPERATION_AND": "和", "LOGIC_OPERATION_TOOLTIP_OR": "如果至少有一个输入结果为真,则返回真。", "LOGIC_OPERATION_OR": "或", "LOGIC_NEGATE_TITLE": "并非%1", "LOGIC_NEGATE_TOOLTIP": "如果输入结果为假,则返回真;如果输入结果为真,则返回假。", "LOGIC_BOOLEAN_TRUE": "真", "LOGIC_BOOLEAN_FALSE": "错", "LOGIC_BOOLEAN_TOOLTIP": "同时返回真或假。", "LOGIC_NULL": "空", "LOGIC_NULL_TOOLTIP": "返回空值。", "LOGIC_TERNARY_HELPURL": "https://zh.wikipedia.org/wiki/条件运算符", "LOGIC_TERNARY_CONDITION": "测试", "LOGIC_TERNARY_IF_TRUE": "如果为真", "LOGIC_TERNARY_IF_FALSE": "如果为假", "LOGIC_TERNARY_TOOLTIP": "检查“test”中的条件。如果条件为真,则返回“if true”的值,否则,则返回“if false”的值。", "MATH_NUMBER_HELPURL": "https://zh.wikipedia.org/wiki/数字", "MATH_NUMBER_TOOLTIP": "一个数字。", "MATH_ARITHMETIC_HELPURL": "https://zh.wikipedia.org/wiki/算术", "MATH_ARITHMETIC_TOOLTIP_ADD": "返回两个数字的和。", "MATH_ARITHMETIC_TOOLTIP_MINUS": "返回两个数字的区别。", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "返回两个数字的乘积。", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "返回两个数字的商。", "MATH_ARITHMETIC_TOOLTIP_POWER": "返回第一个数的第二个数次幂。", "MATH_SINGLE_HELPURL": "https://zh.wikipedia.org/wiki/平方根", "MATH_SINGLE_OP_ROOT": "平方根", "MATH_SINGLE_TOOLTIP_ROOT": "返回数的平方根。", "MATH_SINGLE_OP_ABSOLUTE": "绝对", "MATH_SINGLE_TOOLTIP_ABS": "返回一个数的绝对值。", "MATH_SINGLE_TOOLTIP_NEG": "返回数的逻辑非。", "MATH_SINGLE_TOOLTIP_LN": "返回一个数的自然对数。", "MATH_SINGLE_TOOLTIP_LOG10": "返回数字的对数。", "MATH_SINGLE_TOOLTIP_EXP": "返回数的e次幂。", "MATH_SINGLE_TOOLTIP_POW10": "返回数的10次幂。", "MATH_TRIG_HELPURL": "https://zh.wikipedia.org/wiki/三角函数", "MATH_TRIG_TOOLTIP_SIN": "返回指定角度的正弦值(非弧度)。", "MATH_TRIG_TOOLTIP_COS": "返回指定角度的余弦值(非弧度)。", "MATH_TRIG_TOOLTIP_TAN": "返回指定角度的正切值(非弧度)。", "MATH_TRIG_TOOLTIP_ASIN": "返回一个数的反正弦值。", "MATH_TRIG_TOOLTIP_ACOS": "返回一个数的反余弦值。", "MATH_TRIG_TOOLTIP_ATAN": "返回指定角度的反正切值。", "MATH_CONSTANT_HELPURL": "https://zh.wikipedia.org/wiki/数学常数", "MATH_CONSTANT_TOOLTIP": "返回一个常见常量:π (3.141......),e (2.718...)、φ (1.618...)、 sqrt(2) (1.414......)、sqrt(½) (0.707......)或 ∞(无穷大)。", "MATH_IS_EVEN": "是偶数", "MATH_IS_ODD": "是奇数", "MATH_IS_PRIME": "是质数", "MATH_IS_WHOLE": "为整数", "MATH_IS_POSITIVE": "是正值", "MATH_IS_NEGATIVE": "为负", "MATH_IS_DIVISIBLE_BY": "可被整除", "MATH_IS_TOOLTIP": "如果数字是偶数、奇数、非负整数、正数、负数或如果它可被某数字整除,则返回真或假。", "MATH_CHANGE_HELPURL": "https://zh.wikipedia.org/wiki/%E5%8A%A0%E6%B3%95", "MATH_CHANGE_TITLE_CHANGE": "更改", "MATH_CHANGE_INPUT_BY": "由", "MATH_CHANGE_TOOLTIP": "将一个数添加到变量“%1”。", "MATH_ROUND_HELPURL": "https://zh.wikipedia.org/wiki/四舍五入", "MATH_ROUND_TOOLTIP": "数字向上或向下舍入。", "MATH_ROUND_OPERATOR_ROUND": "向下舍入", "MATH_ROUND_OPERATOR_ROUNDUP": "向上舍入", "MATH_ROUND_OPERATOR_ROUNDDOWN": "向下舍入", "MATH_ONLIST_OPERATOR_SUM": "列表中的数的总和", "MATH_ONLIST_TOOLTIP_SUM": "返回列表中的所有数字的和。", "MATH_ONLIST_OPERATOR_MIN": "列表中的最小值", "MATH_ONLIST_TOOLTIP_MIN": "返回列表中最小数。", "MATH_ONLIST_OPERATOR_MAX": "列表中的最大值", "MATH_ONLIST_TOOLTIP_MAX": "返回列表中最大数。", "MATH_ONLIST_OPERATOR_AVERAGE": "列表中的平均数", "MATH_ONLIST_TOOLTIP_AVERAGE": "返回列表中的数值的平均值。", "MATH_ONLIST_OPERATOR_MEDIAN": "列表中位数", "MATH_ONLIST_TOOLTIP_MEDIAN": "返回列表中的中位数。", "MATH_ONLIST_OPERATOR_MODE": "列表模式", "MATH_ONLIST_TOOLTIP_MODE": "返回列表中的最常见的项的列表。", "MATH_ONLIST_OPERATOR_STD_DEV": "列表中的标准差", "MATH_ONLIST_TOOLTIP_STD_DEV": "返回列表的标准偏差。", "MATH_ONLIST_OPERATOR_RANDOM": "列表的随机项", "MATH_ONLIST_TOOLTIP_RANDOM": "从列表中返回一个随机的元素。", "MATH_MODULO_HELPURL": "https://zh.wikipedia.org/wiki/%E6%A8%A1%E9%99%A4", "MATH_MODULO_TITLE": "取余数自 %1 ÷ %2", "MATH_MODULO_TOOLTIP": "返回这两个数字相除后的余数。", "MATH_CONSTRAIN_HELPURL": "https://en.wikipedia.org/wiki/Clamping_%28graphics%29", "MATH_CONSTRAIN_TITLE": "限制数字 %1 介于 (低) %2 到 (高) %3", "MATH_CONSTRAIN_TOOLTIP": "限制数字介于两个指定的数字之间", "MATH_RANDOM_INT_HELPURL": "https://zh.wikipedia.org/wiki/随机数发生器", "MATH_RANDOM_INT_TITLE": "从 %1 到 %2 之间的随机整数", "MATH_RANDOM_INT_TOOLTIP": "返回两个指定的范围(含)之间的随机整数。", "MATH_RANDOM_FLOAT_HELPURL": "https://zh.wikipedia.org/wiki/随机数发生器", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "随机分数", "MATH_RANDOM_FLOAT_TOOLTIP": "返回介于(包含)0.0到1.0之间的随机数。", "TEXT_TEXT_HELPURL": "https://zh.wikipedia.org/wiki/字符串", "TEXT_TEXT_TOOLTIP": "一个字母、单词或一行文本。", "TEXT_JOIN_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_creation", "TEXT_JOIN_TITLE_CREATEWITH": "建立字串使用", "TEXT_JOIN_TOOLTIP": "通过串起任意数量的项以建立一段文字。", "TEXT_CREATE_JOIN_TITLE_JOIN": "加入", "TEXT_CREATE_JOIN_TOOLTIP": "添加、删除或重新排列各节来重新配置这个文本块。", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "将一个项添加到文本中。", "TEXT_APPEND_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_APPEND_TO": "在", "TEXT_APPEND_APPENDTEXT": "追加文本", "TEXT_APPEND_TOOLTIP": "将一些文本追加到变量“%1”。", "TEXT_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Text_modification", "TEXT_LENGTH_TITLE": "%1的长度", "TEXT_LENGTH_TOOLTIP": "返回文本的字符数(包括空格)。", "TEXT_ISEMPTY_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text", "TEXT_ISEMPTY_TITLE": "%1是空的", "TEXT_ISEMPTY_TOOLTIP": "如果提供的文本为空,则返回真。", "TEXT_INDEXOF_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Finding_text", "TEXT_INDEXOF_TOOLTIP": "返回在第二个字串中的第一/最后一个匹配项的索引值。如果未找到则返回 0。", "TEXT_INDEXOF_INPUT_INTEXT": "自文本", "TEXT_INDEXOF_OPERATOR_FIRST": "寻找第一个出现的文本", "TEXT_INDEXOF_OPERATOR_LAST": "寻找最后一个出现的文本", "TEXT_INDEXOF_TAIL": "空白", "TEXT_CHARAT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Extracting_text", "TEXT_CHARAT_INPUT_INTEXT": "于文本中", "TEXT_CHARAT_FROM_START": "获得字符#", "TEXT_CHARAT_FROM_END": "获得倒数第#个字符", "TEXT_CHARAT_FIRST": "获得第一个字符", "TEXT_CHARAT_LAST": "获得最后一个字符", "TEXT_CHARAT_RANDOM": "获取随机的字母", "TEXT_CHARAT_TAIL": "空白", "TEXT_CHARAT_TOOLTIP": "返回位于指定位置的字母。", "TEXT_GET_SUBSTRING_TOOLTIP": "返回指定的部分文本。", "TEXT_GET_SUBSTRING_HELPURL": "http://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "自文本", "TEXT_GET_SUBSTRING_START_FROM_START": "取得一段字串自#", "TEXT_GET_SUBSTRING_START_FROM_END": "取得一段字串自#到末尾", "TEXT_GET_SUBSTRING_START_FIRST": "取得一段字串自第一个字符", "TEXT_GET_SUBSTRING_END_FROM_START": "到字符#", "TEXT_GET_SUBSTRING_END_FROM_END": "到倒数第#个字符", "TEXT_GET_SUBSTRING_END_LAST": "到最后一个字符", "TEXT_GET_SUBSTRING_TAIL": "空白", "TEXT_CHANGECASE_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case", "TEXT_CHANGECASE_TOOLTIP": "使用不同的大小写复制这段文字。", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "为大写", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "为小写", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "为首字母大写", "TEXT_TRIM_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces", "TEXT_TRIM_TOOLTIP": "复制这段文字的同时删除两端多余的空格。", "TEXT_TRIM_OPERATOR_BOTH": "消除两侧空格", "TEXT_TRIM_OPERATOR_LEFT": "消除左侧空格", "TEXT_TRIM_OPERATOR_RIGHT": "消除右侧空格", "TEXT_PRINT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Printing_text", "TEXT_PRINT_TITLE": "打印%1", "TEXT_PRINT_TOOLTIP": "打印指定的文字、数字或其他值。", "TEXT_PROMPT_HELPURL": "https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user", "TEXT_PROMPT_TYPE_TEXT": "输入数字并显示提示消息", "TEXT_PROMPT_TYPE_NUMBER": "输入数字并显示提示消息", "TEXT_PROMPT_TOOLTIP_NUMBER": "提示用户输入数字。", "TEXT_PROMPT_TOOLTIP_TEXT": "提示用户输入一些文本。", "LISTS_CREATE_EMPTY_HELPURL": "https://en.wikipedia.org/wiki/Linked_list#Empty_lists", "LISTS_CREATE_EMPTY_TITLE": "创建空列表", "LISTS_CREATE_EMPTY_TOOLTIP": "返回一个列表,长度为 0,不包含任何数据记录", "LISTS_CREATE_WITH_TOOLTIP": "建立一个具有任意数量项目的列表。", "LISTS_CREATE_WITH_INPUT_WITH": "建立字串使用", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "列表", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "增加、删除或重新排列各部分以此重新配置这个列表块。", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "将一个项添加到列表中。", "LISTS_REPEAT_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#create_list_with", "LISTS_REPEAT_TOOLTIP": "建立包含指定重复次数的值的列表。", "LISTS_REPEAT_TITLE": "建立列表使用项 %1 重复 %2 次", "LISTS_LENGTH_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#length_of", "LISTS_LENGTH_TITLE": "%1的长度", "LISTS_LENGTH_TOOLTIP": "返回列表的长度。", "LISTS_IS_EMPTY_TITLE": "%1是空的", "LISTS_TOOLTIP": "如果改列表为空,则返回真。", "LISTS_INLIST": "在列表中", "LISTS_INDEX_OF_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List", "LISTS_INDEX_OF_FIRST": "找出第一个项出现", "LISTS_INDEX_OF_LAST": "找出最后一个项出现", "LISTS_INDEX_OF_TOOLTIP": "返回在列表中的第一/最后一个匹配项的索引值。如果未找到则返回 0。", "LISTS_GET_INDEX_GET": "获得", "LISTS_GET_INDEX_GET_REMOVE": "取出并移除", "LISTS_GET_INDEX_REMOVE": "移除", "LISTS_GET_INDEX_FROM_START": "#", "LISTS_GET_INDEX_FROM_END": "倒数第#", "LISTS_GET_INDEX_FIRST": "第一", "LISTS_GET_INDEX_LAST": "最后", "LISTS_GET_INDEX_RANDOM": "随机", "LISTS_GET_INDEX_TAIL": "空白", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "返回在列表中的指定位置的项。#1是第一个项目。", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "返回在列表中的指定位置的项。#1是最后一项。", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "返回列表中的第一个项目。", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "返回列表中的最后一项。", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "随机返回列表中的一个项目。", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "移除并返回列表中的指定位置的项。#1 是第一项。", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "移除并返回列表中的指定位置的项。#1 是最后一项。", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "移除并返回列表中的第一个项目。", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "移除并返回列表中的最后一个项目。", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "移除并返回列表中的一个随机项目中。", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "移除在列表中的指定位置的项。#1 是第一项。", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "删除在列表中的指定位置的项。#1是最后一项。", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "移除列表中的第一项", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "移除列表中的最后一项", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "删除列表中的一个随机的项。", "LISTS_SET_INDEX_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#in_list_..._set", "LISTS_SET_INDEX_SET": "设置", "LISTS_SET_INDEX_INSERT": "插入在", "LISTS_SET_INDEX_INPUT_TO": "为", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "设置在列表中指定位置的项。#1是第一项。", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "设置在列表中指定位置的项。#1是最后一项。", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "设置列表中的第一个项目。", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "设置列表中的最后一项。", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "设置列表中一个随机的项目。", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "插入在列表中指定位置的项。#1是第一项。", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "插入在列表中的指定位置的项。#1是最后一项。", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "在列表的起始处添加该项。", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "将该项追加到列表的末尾。", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "在列表中随机插入项。", "LISTS_GET_SUBLIST_HELPURL": "https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist", "LISTS_GET_SUBLIST_START_FROM_START": "从#取得子列表", "LISTS_GET_SUBLIST_START_FROM_END": "从倒数#取得子列表", "LISTS_GET_SUBLIST_START_FIRST": "从头获得子列表", "LISTS_GET_SUBLIST_END_FROM_START": "到#", "LISTS_GET_SUBLIST_END_FROM_END": "到倒数第#", "LISTS_GET_SUBLIST_END_LAST": "到最后", "LISTS_GET_SUBLIST_TAIL": "空白", "LISTS_GET_SUBLIST_TOOLTIP": "复制列表中指定的部分。", "ORDINAL_NUMBER_SUFFIX": "空白", "VARIABLES_GET_TITLE": "空白", "VARIABLES_GET_TAIL": "空白", "VARIABLES_GET_TOOLTIP": "返回此变量的值。", "VARIABLES_GET_CREATE_SET": "创建“设定%1”", "VARIABLES_SET_HELPURL": "http://code.google.com/p/blockly/wiki/Variables#Set", "VARIABLES_SET_TITLE": "赋值", "VARIABLES_SET_TAIL": "到", "VARIABLES_SET_TOOLTIP": "设置此变量,以使它和输入值相等。", "VARIABLES_SET_CREATE_GET": "创建“获得%1”", "PROCEDURES_DEFNORETURN_HELPURL": "https://zh.wikipedia.org/wiki/子程序", "PROCEDURES_DEFNORETURN_TITLE": "至", "PROCEDURES_DEFNORETURN_PROCEDURE": "做点什么", "PROCEDURES_BEFORE_PARAMS": "与:", "PROCEDURES_DEFNORETURN_DO": "空白", "PROCEDURES_DEFNORETURN_TOOLTIP": "创建一个不带输出值的函数。", "PROCEDURES_DEFRETURN_HELPURL": "https://zh.wikipedia.org/wiki/子程序", "PROCEDURES_DEFRETURN_RETURN": "返回", "PROCEDURES_DEFRETURN_TOOLTIP": "创建一个有输出值的函数。", "PROCEDURES_DEF_DUPLICATE_WARNING": "警告: 此函数具有重复参数。", "PROCEDURES_CALLNORETURN_HELPURL": "https://zh.wikipedia.org/wiki/子程序", "PROCEDURES_CALLNORETURN_CALL": "空白", "PROCEDURES_CALLNORETURN_TOOLTIP": "运行用户定义的函数“%1”。", "PROCEDURES_CALLRETURN_HELPURL": "https://zh.wikipedia.org/wiki/子程序", "PROCEDURES_CALLRETURN_TOOLTIP": "运行用户定义的函数“%1”,并使用它的输出值。", "PROCEDURES_MUTATORCONTAINER_TITLE": "參數", "PROCEDURES_MUTATORARG_TITLE": "输入名称:", "PROCEDURES_HIGHLIGHT_DEF": "突出显示函数定义", "PROCEDURES_CREATE_DO": "创建“%1”", "PROCEDURES_IFRETURN_TOOLTIP": "如果值为真,则返回第二个值。", "PROCEDURES_IFRETURN_WARNING": "警告: 仅在定义函数内可使用此块。" } ================================================ FILE: extern/blockly/msg/json/zh-hant.json ================================================ { "@metadata": { "authors": [ "Gasolin" ] }, "VARIABLES_DEFAULT_NAME": "變量", "DUPLICATE_BLOCK": "複製", "ADD_COMMENT": "加入註解", "REMOVE_COMMENT": "移除註解", "EXTERNAL_INPUTS": "多行輸入", "INLINE_INPUTS": "單行輸入", "DELETE_BLOCK": "刪除積木", "DELETE_X_BLOCKS": "刪除 %1 塊積木", "COLLAPSE_BLOCK": "收合積木", "COLLAPSE_ALL": "收合積木", "EXPAND_BLOCK": "展開積木", "EXPAND_ALL": "展開積木", "DISABLE_BLOCK": "停用積木", "ENABLE_BLOCK": "啟用積木", "HELP": "說明", "CHANGE_VALUE_TITLE": "修改值:", "NEW_VARIABLE": "新變量...", "NEW_VARIABLE_TITLE": "新變量名稱:", "RENAME_VARIABLE": "重新命名變量...", "RENAME_VARIABLE_TITLE": "將所有 \"%1\" 變量重新命名為:", "COLOUR_PICKER_HELPURL": "https://en.wikipedia.org/wiki/Color", "COLOUR_PICKER_TOOLTIP": "從調色板中選擇一種顏色。", "COLOUR_RANDOM_TITLE": "隨機顏色", "COLOUR_RANDOM_TOOLTIP": "隨機選擇一種顏色。", "COLOUR_RGB_TITLE": "顏色", "COLOUR_RGB_RED": "紅", "COLOUR_RGB_GREEN": "綠", "COLOUR_RGB_BLUE": "藍", "COLOUR_RGB_TOOLTIP": "透過指定紅、綠、 藍色的值來建立一種顏色。所有的值必須介於 0 和 100 之間。", "COLOUR_BLEND_TITLE": "混合", "COLOUR_BLEND_COLOUR1": "顏色 1", "COLOUR_BLEND_COLOUR2": "顏色 2", "COLOUR_BLEND_RATIO": "比例", "COLOUR_BLEND_TOOLTIP": "透過一個比率 (0.0-1.0)來混合兩種顏色。", "CONTROLS_REPEAT_HELPURL": "https://en.wikipedia.org/wiki/For_loop", "CONTROLS_REPEAT_TITLE": "重複 %1 次", "CONTROLS_REPEAT_TITLE_REPEAT": "重複", "CONTROLS_REPEAT_TITLE_TIMES": "次數", "CONTROLS_REPEAT_INPUT_DO": "執行", "CONTROLS_REPEAT_TOOLTIP": "多次執行一些語句", "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "重複 當", "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "重複 直到", "CONTROLS_WHILEUNTIL_TOOLTIP_WHILE": "當值為真時,執行一些語句", "CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL": "當值為否時,執行一些語句", "CONTROLS_FOR_TOOLTIP": "從起始數到結尾數中取出變數 %1 的值,按指定的時間間隔,執行指定的積木。", "CONTROLS_FOR_INPUT_WITH": "使用", "CONTROLS_FOR_INPUT_FROM_TO_BY": "從範圍 %1 到 %2 每隔 %3", "CONTROLS_FOREACH_INPUT_ITEM": "取出每個", "CONTROLS_FOREACH_INPUT_INLIST": "自列表", "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "", "CONTROLS_FOREACH_TOOLTIP": "遍歷每個列表中的項目,將變量 '%1' 設定到該項目中,然後執行某些語句", "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "停止 迴圈", "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "繼續下一個 迴圈", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK": "離開當前的 迴圈", "CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE": "跳過這個迴圈的其餘步驟,並繼續下一次的迴圈運算。", "CONTROLS_FLOW_STATEMENTS_WARNING": "警告: 此積木僅可用於迴圈內。", "CONTROLS_IF_TOOLTIP_1": "當值為真時,執行一些語句", "CONTROLS_IF_TOOLTIP_2": "當值為真時,執行第一個語句,否則則執行第二個語句", "CONTROLS_IF_TOOLTIP_3": "如果第一個值為真,則執行第一個語句。否則當第二個值為真時,則執行第二個語句", "CONTROLS_IF_TOOLTIP_4": "如果第一個值為真,則執行第一個語句。否則當第二個值為真時,則執行第二個語句。如果前幾個敘述都不為真,則執行最後一個語句", "CONTROLS_IF_MSG_IF": "如果", "CONTROLS_IF_MSG_ELSEIF": "否則如果", "CONTROLS_IF_MSG_ELSE": "否則", "CONTROLS_IF_IF_TOOLTIP": "添加、 刪除或重新排列各區塊來此重新配置這個'如果'積木。", "CONTROLS_IF_ELSEIF_TOOLTIP": "將條件添加到'如果'積木。", "CONTROLS_IF_ELSE_TOOLTIP": "加入一個最終,所有條件下都都執行的區塊到'如果'積木中", "LOGIC_COMPARE_HELPURL": "https://en.wikipedia.org/wiki/Inequality_(mathematics)", "LOGIC_COMPARE_TOOLTIP_EQ": "如果這兩個輸入區塊內容相等,返回 真。", "LOGIC_COMPARE_TOOLTIP_NEQ": "如果這兩個輸入區塊內容不相等,返回 真。", "LOGIC_COMPARE_TOOLTIP_LT": "如果第一個輸入小於第二個輸入,返回 真。", "LOGIC_COMPARE_TOOLTIP_LTE": "如果第一個輸入是小於或等於第二個輸入,返回 真。", "LOGIC_COMPARE_TOOLTIP_GT": "如果第一個輸入大於第二個輸入,返回 真。", "LOGIC_COMPARE_TOOLTIP_GTE": "如果第一個輸入大於或等於第二個輸入,返回 真。", "LOGIC_OPERATION_TOOLTIP_AND": "如果這兩個輸入值都為 真,則返回 真。", "LOGIC_OPERATION_AND": "且", "LOGIC_OPERATION_TOOLTIP_OR": "如果至少一個輸入的值為 真,返回 真。", "LOGIC_OPERATION_OR": "或", "LOGIC_NEGATE_TITLE": "非 %1", "LOGIC_NEGATE_TOOLTIP": "如果輸入的值是 否,則返回 真。如果輸入的值是 真 返回 否。", "LOGIC_BOOLEAN_TRUE": "真", "LOGIC_BOOLEAN_FALSE": "否", "LOGIC_BOOLEAN_TOOLTIP": "返回 真 或 否。", "LOGIC_NULL": "空", "LOGIC_NULL_TOOLTIP": "返回 空。", "LOGIC_TERNARY_CONDITION": "測試", "LOGIC_TERNARY_IF_TRUE": "如果為真", "LOGIC_TERNARY_IF_FALSE": "如果為非", "LOGIC_TERNARY_TOOLTIP": "檢查 'test' 中的條件。如果條件為 真,將返回 '如果為 真' 值 ;否則,返回 '如果為 否' 的值。", "MATH_NUMBER_HELPURL": "https://en.wikipedia.org/wiki/Number", "MATH_NUMBER_TOOLTIP": "一個數字。", "MATH_ARITHMETIC_HELPURL": "https://en.wikipedia.org/wiki/Arithmetic", "MATH_ARITHMETIC_TOOLTIP_ADD": "返回兩個數字的總和。", "MATH_ARITHMETIC_TOOLTIP_MINUS": "返回兩個數字的差。", "MATH_ARITHMETIC_TOOLTIP_MULTIPLY": "返回兩個數字的乘積。", "MATH_ARITHMETIC_TOOLTIP_DIVIDE": "返回兩個數字的商。", "MATH_ARITHMETIC_TOOLTIP_POWER": "返回第二個數字的指數的第一個數字。", "MATH_SINGLE_HELPURL": "https://en.wikipedia.org/wiki/Square_root", "MATH_SINGLE_OP_ROOT": "開根號", "MATH_SINGLE_TOOLTIP_ROOT": "返回指定數字的平方根。", "MATH_SINGLE_OP_ABSOLUTE": "絕對值", "MATH_SINGLE_TOOLTIP_ABS": "返回指定數字的絕對值。", "MATH_SINGLE_TOOLTIP_NEG": "返回指定數字的 negation。", "MATH_SINGLE_TOOLTIP_LN": "返回指定數字的自然對數。", "MATH_SINGLE_TOOLTIP_LOG10": "返回指定數字的對數。", "MATH_SINGLE_TOOLTIP_EXP": "返回指定數字指數的 e", "MATH_SINGLE_TOOLTIP_POW10": "返回指定數字指數的10的冪次。", "MATH_TRIG_HELPURL": "https://en.wikipedia.org/wiki/Trigonometric_functions", "MATH_TRIG_TOOLTIP_SIN": "返回指定角度的正弦值(非弧度)。", "MATH_TRIG_TOOLTIP_COS": "返回指定角度的餘弦值(非弧度)。", "MATH_TRIG_TOOLTIP_TAN": "返回指定角度的正切值(非弧度)。", "MATH_TRIG_TOOLTIP_ASIN": "返回指定角度的反正弦值(非弧度)。", "MATH_TRIG_TOOLTIP_ACOS": "返回指定角度的反餘弦值(非弧度)。", "MATH_TRIG_TOOLTIP_ATAN": "返回指定角度的反正切值。", "MATH_CONSTANT_HELPURL": "https://en.wikipedia.org/wiki/Mathematical_constant", "MATH_CONSTANT_TOOLTIP": "返回一個的常見常量: π (3.141......),e (2.718...)、 φ (1.618...)、 開方(2) (1.414......)、 開方(½) (0.707......) 或 ∞ (無窮大)。", "MATH_IS_EVEN": "是偶數", "MATH_IS_ODD": "是奇數", "MATH_IS_PRIME": "是質數", "MATH_IS_WHOLE": "是非負整數", "MATH_IS_POSITIVE": "是正值", "MATH_IS_NEGATIVE": "是負值", "MATH_IS_DIVISIBLE_BY": "可被整除", "MATH_IS_TOOLTIP": "如果數字是偶數,奇數,非負整數,正數、 負數或如果它是可被某數字整除,則返回 真 或 否。", "MATH_CHANGE_HELPURL": "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter", "MATH_CHANGE_TITLE_CHANGE": "修改", "MATH_CHANGE_INPUT_BY": "自", "MATH_CHANGE_TOOLTIP": "將數字添加到變量 '%1'。", "MATH_ROUND_HELPURL": "https://en.wikipedia.org/wiki/Rounding", "MATH_ROUND_TOOLTIP": "將數字向上或向下舍入。", "MATH_ROUND_OPERATOR_ROUND": "四捨五入", "MATH_ROUND_OPERATOR_ROUNDUP": "無條件進位", "MATH_ROUND_OPERATOR_ROUNDDOWN": "無條件捨去", "MATH_ONLIST_OPERATOR_SUM": "總和 自列表", "MATH_ONLIST_TOOLTIP_SUM": "返回列表中的所有數字的總和。", "MATH_ONLIST_OPERATOR_MIN": "最小值 自列表", "MATH_ONLIST_TOOLTIP_MIN": "返回列表中的最小數字。", "MATH_ONLIST_OPERATOR_MAX": "最大值 自列表", "MATH_ONLIST_TOOLTIP_MAX": "返回列表中的最大數字。", "MATH_ONLIST_OPERATOR_AVERAGE": "平均值 自列表", "MATH_ONLIST_TOOLTIP_AVERAGE": "返回列表中數值的平均值 (算術平均值)。", "MATH_ONLIST_OPERATOR_MEDIAN": "中位數 自列表", "MATH_ONLIST_TOOLTIP_MEDIAN": "返回列表中數值的中位數。", "MATH_ONLIST_OPERATOR_MODE": "比較眾數 自列表", "MATH_ONLIST_TOOLTIP_MODE": "返回一個列表中的最常見項目的列表。", "MATH_ONLIST_OPERATOR_STD_DEV": "標準差 自列表", "MATH_ONLIST_TOOLTIP_STD_DEV": "返回列表中數字的標準差。", "MATH_ONLIST_OPERATOR_RANDOM": "隨機抽取 自列表", "MATH_ONLIST_TOOLTIP_RANDOM": "從列表中返回一個隨機的項目。", "MATH_MODULO_HELPURL": "https://en.wikipedia.org/wiki/Modulo_operation", "MATH_MODULO_TITLE": "取餘數自 %1 ÷ %2", "MATH_MODULO_TOOLTIP": "回傳兩個數字相除的餘數", "MATH_CONSTRAIN_TITLE": "限制數字 %1 介於 (低) %2 到 (高) %3", "MATH_CONSTRAIN_TOOLTIP": "限制數字介於兩個指定的數字之間", "MATH_RANDOM_INT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_INT_TITLE": "取隨機整數介於 (低) %1 到 %2", "MATH_RANDOM_INT_TOOLTIP": "回傳限制的數字區間內的隨機數字", "MATH_RANDOM_FLOAT_HELPURL": "https://en.wikipedia.org/wiki/Random_number_generation", "MATH_RANDOM_FLOAT_TITLE_RANDOM": "取隨機分數", "MATH_RANDOM_FLOAT_TOOLTIP": "返回介於 (包含) 0.0 到 1.0 之間的隨機數。", "TEXT_TEXT_HELPURL": "https://en.wikipedia.org/wiki/String_(computer_science)", "TEXT_TEXT_TOOLTIP": "字元、 單詞或一行文字。", "TEXT_JOIN_TITLE_CREATEWITH": "建立字串使用", "TEXT_JOIN_TOOLTIP": "通過串起任意數量的項目來建立一段文字。", "TEXT_CREATE_JOIN_TITLE_JOIN": "加入", "TEXT_CREATE_JOIN_TOOLTIP": "添加、 刪除或重新排列各區塊來此重新配置這個文字積木。", "TEXT_CREATE_JOIN_ITEM_TOOLTIP": "將一個項目加入到字串中。", "TEXT_APPEND_TO": "在", "TEXT_APPEND_APPENDTEXT": "後加入文字", "TEXT_APPEND_TOOLTIP": "將一些文字追加到變量 '%1'。", "TEXT_LENGTH_TITLE": "長度 %1", "TEXT_LENGTH_TOOLTIP": "返回這串文字的字元數(含空格) 。", "TEXT_ISEMPTY_TITLE": "%1 為空", "TEXT_ISEMPTY_TOOLTIP": "如果提供的字串為空,則返回 真。", "TEXT_INDEXOF_TOOLTIP": "返回在第二個字串中的第一個/最後一個匹配項目的索引值。如果未找到則返回 0。", "TEXT_INDEXOF_INPUT_INTEXT": "在字串", "TEXT_INDEXOF_OPERATOR_FIRST": "尋找 第一個 出現的字串", "TEXT_INDEXOF_OPERATOR_LAST": "尋找 最後一個 出現的字串", "TEXT_CHARAT_INPUT_INTEXT": "的字元在字串", "TEXT_CHARAT_FROM_START": "取得 字元 #", "TEXT_CHARAT_FROM_END": "取得 倒數第 # 個字元", "TEXT_CHARAT_FIRST": "取第一個字元", "TEXT_CHARAT_LAST": "取最後一個字元", "TEXT_CHARAT_RANDOM": "取隨機一個字元", "TEXT_CHARAT_TAIL": "", "TEXT_CHARAT_TOOLTIP": "返回位於指定位置的字元。", "TEXT_GET_SUBSTRING_TOOLTIP": "返回指定的部分文字。", "TEXT_GET_SUBSTRING_INPUT_IN_TEXT": "自字串", "TEXT_GET_SUBSTRING_START_FROM_START": "取得一段字串自 #", "TEXT_GET_SUBSTRING_START_FROM_END": "取得一段字串自 #", "TEXT_GET_SUBSTRING_START_FIRST": "取得一段字串 自 第一個字元", "TEXT_GET_SUBSTRING_END_FROM_START": "到 字元 #", "TEXT_GET_SUBSTRING_END_FROM_END": "到 倒數第 # 個字元", "TEXT_GET_SUBSTRING_END_LAST": "到 最後一個字元", "TEXT_CHANGECASE_TOOLTIP": "使用不同的大小寫複製這段文字。", "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "轉成 大寫", "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "轉成 小寫", "TEXT_CHANGECASE_OPERATOR_TITLECASE": "轉成 首字母大寫", "TEXT_TRIM_TOOLTIP": "複製這段文字的同時刪除兩端多餘的空格。", "TEXT_TRIM_OPERATOR_BOTH": "從 兩側 消除空格", "TEXT_TRIM_OPERATOR_LEFT": "從 左側 消除空格", "TEXT_TRIM_OPERATOR_RIGHT": "從 右側 消除空格", "TEXT_PRINT_TITLE": "印出 %1", "TEXT_PRINT_TOOLTIP": "印出指定的文字、 數字或其他值。", "TEXT_PROMPT_TYPE_TEXT": "輸入 文字 並顯示提示訊息", "TEXT_PROMPT_TYPE_NUMBER": "輸入 數字 並顯示提示訊息", "TEXT_PROMPT_TOOLTIP_NUMBER": "輸入數字", "TEXT_PROMPT_TOOLTIP_TEXT": "輸入文字", "LISTS_CREATE_EMPTY_TITLE": "建立空列表", "LISTS_CREATE_EMPTY_TOOLTIP": "返回一個長度為 0 的列表,不包含任何資料記錄", "LISTS_CREATE_WITH_TOOLTIP": "建立一個具備任意數量項目的列表。", "LISTS_CREATE_WITH_INPUT_WITH": "使用這些值建立列表", "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "加入", "LISTS_CREATE_WITH_CONTAINER_TOOLTIP": "添加、 刪除或重新排列各區塊來此重新配置這個 列表 積木。", "LISTS_CREATE_WITH_ITEM_TOOLTIP": "將一個項目加入到列表中。", "LISTS_REPEAT_TOOLTIP": "建立包含指定重複次數的 值 的列表。", "LISTS_REPEAT_TITLE": "建立列表使用項目 %1 重複 %2 次數", "LISTS_LENGTH_TITLE": "長度 %1", "LISTS_LENGTH_TOOLTIP": "返回列表的長度。", "LISTS_IS_EMPTY_TITLE": "%1 值為空", "LISTS_TOOLTIP": "如果該列表為空,則返回 真。", "LISTS_INLIST": "自列表", "LISTS_INDEX_OF_FIRST": "找出 第一個 項目出現", "LISTS_INDEX_OF_LAST": "找出 最後一個 項目出現", "LISTS_INDEX_OF_TOOLTIP": "返回在列表中的第一個/最後一個匹配項目的索引值。如果未找到則返回 0。", "LISTS_GET_INDEX_GET": "取值", "LISTS_GET_INDEX_GET_REMOVE": "取出並移除", "LISTS_GET_INDEX_REMOVE": "移除", "LISTS_GET_INDEX_FROM_END": "倒數第#筆", "LISTS_GET_INDEX_FIRST": "第一筆", "LISTS_GET_INDEX_LAST": "最後一筆", "LISTS_GET_INDEX_RANDOM": "隨機", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_START": "返回在列表中的指定位置的項目。#1 是第一個項目。", "LISTS_GET_INDEX_TOOLTIP_GET_FROM_END": "返回在列表中的指定位置的項目。#1 是最後一個項目。", "LISTS_GET_INDEX_TOOLTIP_GET_FIRST": "返回列表中的第一個項目", "LISTS_GET_INDEX_TOOLTIP_GET_LAST": "返回列表中的最後一個項目", "LISTS_GET_INDEX_TOOLTIP_GET_RANDOM": "返回列表中隨機的一個項目", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START": "移除並返回列表中的指定位置的項目。#1 是第一個項目。", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END": "移除並返回列表中的指定位置的項目。#1 是最後一個項目。", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST": "移除並返回列表中的第一個項目", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST": "移除並返回列表中的最後一個項目", "LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM": "移除並返回列表中的隨機一個項目", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START": "移除在列表中的指定位置的項目。#1 是第一個項目。", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END": "移除在列表中的指定位置的項目。#1 是最後一個項目。", "LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST": "移除列表中的第一個項目", "LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST": "移除列表中的最後一個項目", "LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM": "移除列表中隨機的一個項目", "LISTS_SET_INDEX_SET": "設定", "LISTS_SET_INDEX_INSERT": "插入到", "LISTS_SET_INDEX_INPUT_TO": "為", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_START": "設定在列表中的指定位置的項目。#1 是第一個項目。", "LISTS_SET_INDEX_TOOLTIP_SET_FROM_END": "設定在列表中的指定位置的項目。#1 是最後一個項目。", "LISTS_SET_INDEX_TOOLTIP_SET_FIRST": "設定列表中的第一個項目", "LISTS_SET_INDEX_TOOLTIP_SET_LAST": "設定列表中的最後一個項目", "LISTS_SET_INDEX_TOOLTIP_SET_RANDOM": "設定列表中隨機的一個項目", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START": "插入在列表中的指定位置的項目。#1 是第一個項目。", "LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END": "插入在列表中的指定位置的項目。#1 是最後一個項目。", "LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST": "在列表的起始處添加一個項目。", "LISTS_SET_INDEX_TOOLTIP_INSERT_LAST": "在列表的尾端加入一個項目", "LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM": "在列表中隨機插入項目", "LISTS_GET_SUBLIST_START_FROM_START": "從 # 取得子列表", "LISTS_GET_SUBLIST_START_FROM_END": "從倒數 # 取得子列表", "LISTS_GET_SUBLIST_START_FIRST": "從 頭 取得子列表", "LISTS_GET_SUBLIST_END_FROM_START": "到 #", "LISTS_GET_SUBLIST_END_FROM_END": "到 倒數 # 位", "LISTS_GET_SUBLIST_END_LAST": "到 最後", "LISTS_GET_SUBLIST_TOOLTIP": "複製列表中指定的部分。", "VARIABLES_GET_TITLE": "", "VARIABLES_GET_TAIL": "", "VARIABLES_GET_TOOLTIP": "返回此變量的值。", "VARIABLES_GET_CREATE_SET": "創立 '設定 %1'", "VARIABLES_SET_TITLE": "賦值", "VARIABLES_SET_TAIL": "到", "VARIABLES_SET_TOOLTIP": "設定此變量,好和輸入值相等。", "VARIABLES_SET_CREATE_GET": "建立 '取得 %1'", "PROCEDURES_DEFNORETURN_TITLE": "到", "PROCEDURES_DEFNORETURN_PROCEDURE": "流程", "PROCEDURES_BEFORE_PARAMS": "與:", "PROCEDURES_DEFNORETURN_TOOLTIP": "創建一個無回傳值的函數。", "PROCEDURES_DEFRETURN_RETURN": "回傳", "PROCEDURES_DEFRETURN_TOOLTIP": "創建一個有回傳值的函數。", "PROCEDURES_DEF_DUPLICATE_WARNING": "警告: 此函數中有重複的參數。", "PROCEDURES_CALLNORETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLNORETURN_CALL": "呼叫", "PROCEDURES_CALLNORETURN_TOOLTIP": "執行使用者定義的函數 '%1'。", "PROCEDURES_CALLRETURN_HELPURL": "https://en.wikipedia.org/wiki/Procedure_%28computer_science%29", "PROCEDURES_CALLRETURN_TOOLTIP": "執行使用者定義的函數 '%1' 並使用它的回傳值", "PROCEDURES_MUTATORCONTAINER_TITLE": "參數", "PROCEDURES_MUTATORARG_TITLE": "變量:", "PROCEDURES_HIGHLIGHT_DEF": "高亮顯示函式定義", "PROCEDURES_CREATE_DO": "建立 '%1'", "PROCEDURES_IFRETURN_TOOLTIP": "如果值為 真,則返回第二個值。", "PROCEDURES_IFRETURN_WARNING": "警告: 此積木僅可在定義函式時使用。" } ================================================ FILE: extern/blockly/msg/messages.js ================================================ /** * @license * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview English strings. * @author fraser@google.com (Neil Fraser) * * After modifying this file, either run "build.py" from the parent directory, * or run (from this directory): * ../i18n/js_to_json.py * to regenerate json/{en,qqq,synonyms}.json. * * To convert all of the json files to .js files, run: * ../i18n/create_messages.py json/*.json */ 'use strict'; goog.provide('Blockly.Msg.en'); goog.require('Blockly.Msg'); /** * Due to the frequency of long strings, the 80-column wrap rule need not apply * to message files. */ /** * Tip: Generate URLs for read-only blocks by creating the blocks in the Code app, * then evaluating this in the console: * 'http://blockly-demo.appspot.com/static/apps/code/readonly.html?lang=en&xml=' + encodeURIComponent(Blockly.Xml.domToText(Blockly.Xml.workspaceToDom(Blockly.mainWorkspace)).slice(5, -6)) */ /// default name - A simple, general default name for a variable, preferably short. /// For more context, see /// [[Translating:Blockly#infrequent_message_types]]. Blockly.Msg.VARIABLES_DEFAULT_NAME = 'item'; // Context menus. /// context menu - Make a copy of the selected block (and any blocks it contains). Blockly.Msg.DUPLICATE_BLOCK = 'Duplicate'; /// context menu - Add a descriptive comment to the selected block. Blockly.Msg.ADD_COMMENT = 'Add Comment'; /// context menu - Remove the descriptive comment from the selected block. Blockly.Msg.REMOVE_COMMENT = 'Remove Comment'; /// context menu - Change from 'external' to 'inline' mode for displaying blocks used as inputs to the selected block. See [[Translating:Blockly#context_menus]]. Blockly.Msg.EXTERNAL_INPUTS = 'External Inputs'; /// context menu - Change from 'internal' to 'external' mode for displaying blocks used as inputs to the selected block. See [[Translating:Blockly#context_menus]]. Blockly.Msg.INLINE_INPUTS = 'Inline Inputs'; /// context menu - Permanently delete the selected block. Blockly.Msg.DELETE_BLOCK = 'Delete Block'; /// context menu - Permanently delete the %1 selected blocks.\n\nParameters:\n* %1 - an integer greater than 1. Blockly.Msg.DELETE_X_BLOCKS = 'Delete %1 Blocks'; /// context menu - Make the appearance of the selected block smaller by hiding some information about it. Blockly.Msg.COLLAPSE_BLOCK = 'Collapse Block'; /// context menu - Make the appearance of the selected blocks smaller by hiding some information about it. Use the same terminology as in the previous message. Blockly.Msg.COLLAPSE_ALL = 'Collapse Blocks'; /// context menu - Restore the appearance of the selected block by showing information about it that was hidden (collapsed) earlier. Blockly.Msg.EXPAND_BLOCK = 'Expand Block'; /// context menu - Restore the appearance of the selected block by showing information about it that was hidden (collapsed) earlier. Use the same terminology as in the previous message. Blockly.Msg.EXPAND_ALL = 'Expand Blocks'; /// context menu - Make the selected block have no effect (unless reenabled). Blockly.Msg.DISABLE_BLOCK = 'Disable Block'; /// context menu - Make the selected block have effect (after having been disabled earlier). Blockly.Msg.ENABLE_BLOCK = 'Enable Block'; /// context menu - Provide helpful information about the selected block.\n{{Identical|Help}} Blockly.Msg.HELP = 'Help'; // Realtime collaboration. /// collaboration instruction - Tell the user that they can talk with other users. Blockly.Msg.CHAT = 'Chat with your collaborator by typing in this box!'; // Variable renaming. /// prompt - This message is only seen in the Opera browser. With most browsers, users can edit numeric values in blocks by just clicking and typing. Opera does not allows this, so we have to open a new window and prompt users with this message to chanage a value. Blockly.Msg.CHANGE_VALUE_TITLE = 'Change value:'; /// dropdown choice - When the user clicks on a variable block, this is one of the dropdown menu choices. It is used to define a new variable. See [https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu]. Blockly.Msg.NEW_VARIABLE = 'New variable...'; /// prompt - Prompts the user to enter the name for a new variable. See [https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu]. Blockly.Msg.NEW_VARIABLE_TITLE = 'New variable name:'; /// dropdown choice - When the user clicks on a variable block, this is one of the dropdown menu choices. It is used to rename the current variable. See [https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu]. Blockly.Msg.RENAME_VARIABLE = 'Rename variable...'; /// prompt - Prompts the user to enter the new name for the selected variable. See [https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu https://code.google.com/p/blockly/wiki/Variables#Dropdown_menu].\n\nParameters:\n* %1 - the name of the variable to be renamed. Blockly.Msg.RENAME_VARIABLE_TITLE = 'Rename all "%1" variables to:'; // Colour Blocks. /// url - Information about colour. Blockly.Msg.COLOUR_PICKER_HELPURL = 'https://en.wikipedia.org/wiki/Color'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Colour#Picking_a_colour_from_a_palette https://code.google.com/p/blockly/wiki/Colour#Picking_a_colour_from_a_palette]. Blockly.Msg.COLOUR_PICKER_TOOLTIP = 'Choose a colour from the palette.'; /// url - A link that displays a random colour each time you visit it. Blockly.Msg.COLOUR_RANDOM_HELPURL = 'http://randomcolour.com'; /// block text - Title of block that generates a colour at random. Blockly.Msg.COLOUR_RANDOM_TITLE = 'random colour'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Colour#Generating_a_random_colour https://code.google.com/p/blockly/wiki/Colour#Generating_a_random_colour]. Blockly.Msg.COLOUR_RANDOM_TOOLTIP = 'Choose a colour at random.'; /// url - A link for color codes with percentages (0-100%) for each component, instead of the more common 0-255, which may be more difficult for beginners. Blockly.Msg.COLOUR_RGB_HELPURL = 'http://www.december.com/html/spec/colorper.html'; /// block text - Title of block for [https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components]. Blockly.Msg.COLOUR_RGB_TITLE = 'colour with'; /// block input text - The amount of red (from 0 to 100) to use when [https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components].\n{{Identical|Red}} Blockly.Msg.COLOUR_RGB_RED = 'red'; /// block input text - The amount of green (from 0 to 100) to use when [https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components]. Blockly.Msg.COLOUR_RGB_GREEN = 'green'; /// block input text - The amount of blue (from 0 to 100) to use when [https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components].\n{{Identical|Blue}} Blockly.Msg.COLOUR_RGB_BLUE = 'blue'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components https://code.google.com/p/blockly/wiki/Colour#Creating_a_colour_from_red,_green,_and_blue_components]. Blockly.Msg.COLOUR_RGB_TOOLTIP = 'Create a colour with the specified amount of red, green, and blue. All values must be between 0 and 100.'; /// url - A useful link that displays blending of two colors. Blockly.Msg.COLOUR_BLEND_HELPURL = 'http://meyerweb.com/eric/tools/color-blend/'; /// block text - A verb for blending two shades of paint. Blockly.Msg.COLOUR_BLEND_TITLE = 'blend'; /// block input text - The first of two colours to [https://code.google.com/p/blockly/wiki/Colour#Blending_colours blend]. Blockly.Msg.COLOUR_BLEND_COLOUR1 = 'colour 1'; /// block input text - The second of two colours to [https://code.google.com/p/blockly/wiki/Colour#Blending_colours blend]. Blockly.Msg.COLOUR_BLEND_COLOUR2 = 'colour 2'; /// block input text - The proportion of the [https://code.google.com/p/blockly/wiki/Colour#Blending_colours blend] containing the first color; the remaining proportion is of the second colour. For example, if the first colour is red and the second color blue, a ratio of 1 would yield pure red, a ratio of .5 would yield purple (equal amounts of red and blue), and a ratio of 0 would yield pure blue. Blockly.Msg.COLOUR_BLEND_RATIO = 'ratio'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Colour#Blending_colours https://code.google.com/p/blockly/wiki/Colour#Blending_colours]. Blockly.Msg.COLOUR_BLEND_TOOLTIP = 'Blends two colours together with a given ratio (0.0 - 1.0).'; // Loop Blocks. /// url - Describes 'repeat loops' in computer programs; consider using the translation of the page [https://en.wikipedia.org/wiki/Control_flow http://en.wikipedia.org/wiki/Control_flow]. Blockly.Msg.CONTROLS_REPEAT_HELPURL = 'https://en.wikipedia.org/wiki/For_loop'; /// block input text - Title of [https://code.google.com/p/blockly/wiki/Loops#repeat repeat block].\n\nParameters:\n* %1 - the number of times the body of the loop should be repeated. Blockly.Msg.CONTROLS_REPEAT_TITLE = 'repeat %1 times'; /// block text - Text preceding the number of repetitions in a [https://code.google.com/p/blockly/wiki/Loops#repeat repeat block]. /// (This is redundant with the previous message but is needed to support older code.) Blockly.Msg.CONTROLS_REPEAT_TITLE_REPEAT = 'repeat'; /// block text - Text following the number of times a [https://code.google.com/p/blockly/wiki/Loops#repeat repeat loop] should be repeated. /// (This is redundant but is needed to support older code.) Blockly.Msg.CONTROLS_REPEAT_TITLE_TIMES = 'times'; /// block text - Preceding the blocks in the body of the loop. See [https://code.google.com/p/blockly/wiki/Loops https://code.google.com/p/blockly/wiki/Loops]. Blockly.Msg.CONTROLS_REPEAT_INPUT_DO = 'do'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Loops#repeat https://code.google.com/p/blockly/wiki/Loops#repeat]. Blockly.Msg.CONTROLS_REPEAT_TOOLTIP = 'Do some statements several times.'; /// url - Describes 'while loops' in computer programs; consider using the translation of [https://en.wikipedia.org/wiki/While_loop https://en.wikipedia.org/wiki/While_loop], if present, or [https://en.wikipedia.org/wiki/Control_flow https://en.wikipedia.org/wiki/Control_flow]. Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL = 'https://code.google.com/p/blockly/wiki/Repeat'; Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO = Blockly.Msg.CONTROLS_REPEAT_INPUT_DO; /// dropdown - Specifies that a loop should [https://code.google.com/p/blockly/wiki/Loops#Repeat_while repeat while] the following condition is true. Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_WHILE = 'repeat while'; /// dropdown - Specifies that a loop should [https://code.google.com/p/blockly/wiki/Loops#Repeat_until repeat until] the following condition becomes true. Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_UNTIL = 'repeat until'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Loops#repeat_while Loops#repeat_while https://code.google.com/p/blockly/wiki/Loops#repeat_while Loops#repeat_while]. Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_WHILE = 'While a value is true, then do some statements.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Loops#repeat_until https://code.google.com/p/blockly/wiki/Loops#repeat_until]. Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL = 'While a value is false, then do some statements.'; /// url - Describes 'for loops' in computer programs. Consider using your language's translation of [https://en.wikipedia.org/wiki/For_loop https://en.wikipedia.org/wiki/For_loop], if present. Blockly.Msg.CONTROLS_FOR_HELPURL = 'https://code.google.com/p/blockly/wiki/Loops#count_with'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Loops#count_with https://code.google.com/p/blockly/wiki/Loops#count_with].\n\nParameters:\n* %1 - the name of the loop variable. Blockly.Msg.CONTROLS_FOR_TOOLTIP = 'Have the variable %1 take on the values from the start number to the end number, counting by the specified interval, and do the specified blocks.'; /// block title - Title of [https://code.google.com/p/blockly/wiki/Loops#count_with count with] blocks. /// [[File:Blockly-count-with.png]] Blockly.Msg.CONTROLS_FOR_INPUT_WITH = 'count with'; /// block text - Starting with a (usually lower) number in a range (%1), /// ending with a (usually higher) number in a range (%2), and counting the /// iterations by a number of steps (%3). As in /// [https://code.google.com/p/blockly/wiki/Loops#count_with /// https://code.google.com/p/blockly/wiki/Loops#count_with]. /// [[File:Blockly-count-with.png]] Blockly.Msg.CONTROLS_FOR_INPUT_FROM_TO_BY = 'from %1 to %2 by %3'; Blockly.Msg.CONTROLS_FOR_INPUT_DO = Blockly.Msg.CONTROLS_REPEAT_INPUT_DO; /// url - Describes 'for-each loops' in computer programs. Consider using your language's translation of [https://en.wikipedia.org/wiki/Foreach https://en.wikipedia.org/wiki/Foreach] if present. Blockly.Msg.CONTROLS_FOREACH_HELPURL = 'https://code.google.com/p/blockly/wiki/Loops#for_each for each block'; /// block text - Title of [https://code.google.com/p/blockly/wiki/Loops#for_each for each block]. Blockly.Msg.CONTROLS_FOREACH_INPUT_ITEM = 'for each item'; /// block text - Preceding the list that should be iterated over in a [https://code.google.com/p/blockly/wiki/Loops#for_each for each loop]. Blockly.Msg.CONTROLS_FOREACH_INPUT_INLIST = 'in list'; /// block text - Following the list that should be iterated over in a [https://code.google.com/p/blockly/wiki/Loops#for_each for each loop]. This is empty in most, but not all, languages. Blockly.Msg.CONTROLS_FOREACH_INPUT_INLIST_TAIL = ''; Blockly.Msg.CONTROLS_FOREACH_INPUT_DO = Blockly.Msg.CONTROLS_REPEAT_INPUT_DO; /// block text - Description of [https://code.google.com/p/blockly/wiki/Loops#for_each for each blocks].\n\nParameters:\n* %1 - the name of the loop variable. Blockly.Msg.CONTROLS_FOREACH_TOOLTIP = 'For each item in a list, set the variable "%1" to the item, and then do some statements.'; /// url - Describes control flow in computer programs. Consider using your language's translation of [https://en.wikipedia.org/wiki/Control_flow https://en.wikipedia.org/wiki/Control_flow], if it exists. Blockly.Msg.CONTROLS_FLOW_STATEMENTS_HELPURL = 'https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks'; /// dropdown - The current loop should be exited. See [https://code.google.com/p/blockly/wiki/Loops#break https://code.google.com/p/blockly/wiki/Loops#break]. Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK = 'break out of loop'; /// dropdown - The current iteration of the loop should be ended and the next should begin. See [https://code.google.com/p/blockly/wiki/Loops#continue_with_next_iteration https://code.google.com/p/blockly/wiki/Loops#continue_with_next_iteration]. Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE = 'continue with next iteration of loop'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Loops#break_out_of_loop https://code.google.com/p/blockly/wiki/Loops#break_out_of_loop]. Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK = 'Break out of the containing loop.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Loops#continue_with_next_iteration https://code.google.com/p/blockly/wiki/Loops#continue_with_next_iteration]. Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE = 'Skip the rest of this loop, and continue with the next iteration.'; /// warning - The user has tried placing a block outside of a loop (for each, while, repeat, etc.), but this type of block may only be used within a loop. See [https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks https://code.google.com/p/blockly/wiki/Loops#Loop_Termination_Blocks]. Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING = 'Warning: This block may only be used within a loop.'; // Logic Blocks. /// url - Describes conditional statements (if-then-else) in computer programs. Consider using your language's translation of [https://en.wikipedia.org/wiki/If_else https://en.wikipedia.org/wiki/If_else], if present. Blockly.Msg.CONTROLS_IF_HELPURL = 'https://code.google.com/p/blockly/wiki/If_Then'; /// tooltip - Describes [https://code.google.com/p/blockly/wiki/IfElse#If_blocks 'if' blocks]. Consider using your language's translation of [https://en.wikipedia.org/wiki/If_statement https://en.wikipedia.org/wiki/If_statement], if present. Blockly.Msg.CONTROLS_IF_TOOLTIP_1 = 'If a value is true, then do some statements.'; /// tooltip - Describes [https://code.google.com/p/blockly/wiki/IfElse#If-Else_blocks if-else blocks]. Consider using your language's translation of [https://en.wikipedia.org/wiki/If_statement https://en.wikipedia.org/wiki/If_statement], if present. Blockly.Msg.CONTROLS_IF_TOOLTIP_2 = 'If a value is true, then do the first block of statements. Otherwise, do the second block of statements.'; /// tooltip - Describes [https://code.google.com/p/blockly/wiki/IfElse#If-Else-If_blocks if-else-if blocks]. Consider using your language's translation of [https://en.wikipedia.org/wiki/If_statement https://en.wikipedia.org/wiki/If_statement], if present. Blockly.Msg.CONTROLS_IF_TOOLTIP_3 = 'If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements.'; /// tooltip - Describes [https://code.google.com/p/blockly/wiki/IfElse#If-Else-If-Else_blocks if-else-if-else blocks]. Consider using your language's translation of [https://en.wikipedia.org/wiki/If_statement https://en.wikipedia.org/wiki/If_statement], if present. Blockly.Msg.CONTROLS_IF_TOOLTIP_4 = 'If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements. If none of the values are true, do the last block of statements.'; /// block text - See [https://code.google.com/p/blockly/wiki/IfElse https://code.google.com/p/blockly/wiki/IfElse]. /// It is recommended, but not essential, that this have text in common with the translation of 'else if' Blockly.Msg.CONTROLS_IF_MSG_IF = 'if'; /// block text - See [https://code.google.com/p/blockly/wiki/IfElse https://code.google.com/p/blockly/wiki/IfElse]. The English words "otherwise if" would probably be clearer than "else if", but the latter is used because it is traditional and shorter. Blockly.Msg.CONTROLS_IF_MSG_ELSEIF = 'else if'; /// block text - See [https://code.google.com/p/blockly/wiki/IfElse https://code.google.com/p/blockly/wiki/IfElse]. The English word "otherwise" would probably be superior to "else", but the latter is used because it is traditional and shorter. Blockly.Msg.CONTROLS_IF_MSG_ELSE = 'else'; Blockly.Msg.CONTROLS_IF_MSG_THEN = Blockly.Msg.CONTROLS_REPEAT_INPUT_DO; Blockly.Msg.CONTROLS_IF_IF_TITLE_IF = Blockly.Msg.CONTROLS_IF_MSG_IF; /// tooltip - Describes [https://code.google.com/p/blockly/wiki/IfElse#Block_Modification if block modification]. Blockly.Msg.CONTROLS_IF_IF_TOOLTIP = 'Add, remove, or reorder sections to reconfigure this if block.'; Blockly.Msg.CONTROLS_IF_ELSEIF_TITLE_ELSEIF = Blockly.Msg.CONTROLS_IF_MSG_ELSEIF; /// tooltip - Describes the 'else if' subblock during [https://code.google.com/p/blockly/wiki/IfElse#Block_Modification if block modification]. Blockly.Msg.CONTROLS_IF_ELSEIF_TOOLTIP = 'Add a condition to the if block.'; Blockly.Msg.CONTROLS_IF_ELSE_TITLE_ELSE = Blockly.Msg.CONTROLS_IF_MSG_ELSE; /// tooltip - Describes the 'else' subblock during [https://code.google.com/p/blockly/wiki/IfElse#Block_Modification if block modification]. Blockly.Msg.CONTROLS_IF_ELSE_TOOLTIP = 'Add a final, catch-all condition to the if block.'; /// url - Information about comparisons. Blockly.Msg.LOGIC_COMPARE_HELPURL = 'https://en.wikipedia.org/wiki/Inequality_(mathematics)'; /// tooltip - Describes the equals (=) block. Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ = 'Return true if both inputs equal each other.'; /// tooltip - Describes the equals (\u0026ne;) block. Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ = 'Return true if both inputs are not equal to each other.'; /// tooltip - Describes the equals (\u0026lt;) block. Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT = 'Return true if the first input is smaller than the second input.'; /// tooltip - Describes the equals (\u0026le;) block. Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE = 'Return true if the first input is smaller than or equal to the second input.'; /// tooltip - Describes the equals (\u0026gt;) block. Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT = 'Return true if the first input is greater than the second input.'; /// tooltip - Describes the equals (\u0026ge;) block. Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE = 'Return true if the first input is greater than or equal to the second input.'; /// url - Information about the Boolean conjunction ("and") and disjunction ("or") operators. Consider using the translation of [https://en.wikipedia.org/wiki/Boolean_logic https://en.wikipedia.org/wiki/Boolean_logic], if it exists in your language. Blockly.Msg.LOGIC_OPERATION_HELPURL = 'https://code.google.com/p/blockly/wiki/And_Or'; /// tooltip - See [https://en.wikipedia.org/wiki/Logical_conjunction https://en.wikipedia.org/wiki/Logical_conjunction]. Blockly.Msg.LOGIC_OPERATION_TOOLTIP_AND = 'Return true if both inputs are true.'; /// block text - See [https://en.wikipedia.org/wiki/Logical_conjunction https://en.wikipedia.org/wiki/Logical_conjunction]. Blockly.Msg.LOGIC_OPERATION_AND = 'and'; /// block text - See [https://en.wikipedia.org/wiki/Disjunction https://en.wikipedia.org/wiki/Disjunction]. Blockly.Msg.LOGIC_OPERATION_TOOLTIP_OR = 'Return true if at least one of the inputs is true.'; /// block text - See [https://en.wikipedia.org/wiki/Disjunction https://en.wikipedia.org/wiki/Disjunction]. Blockly.Msg.LOGIC_OPERATION_OR = 'or'; /// url - Information about logical negation. The translation of [https://en.wikipedia.org/wiki/Logical_negation https://en.wikipedia.org/wiki/Logical_negation] is recommended if it exists in the target language. Blockly.Msg.LOGIC_NEGATE_HELPURL = 'https://code.google.com/p/blockly/wiki/Not'; /// block text - This is a unary operator that returns ''false'' when the input is ''true'', and ''true'' when the input is ''false''. /// \n\nParameters:\n* %1 - the input (which should be either the value "true" or "false") Blockly.Msg.LOGIC_NEGATE_TITLE = 'not %1'; /// tooltip - See [https://en.wikipedia.org/wiki/Logical_negation https://en.wikipedia.org/wiki/Logical_negation]. Blockly.Msg.LOGIC_NEGATE_TOOLTIP = 'Returns true if the input is false. Returns false if the input is true.'; /// url - Information about the logic values ''true'' and ''false''. Consider using the translation of [https://en.wikipedia.org/wiki/Truth_value https://en.wikipedia.org/wiki/Truth_value] if it exists in your language. Blockly.Msg.LOGIC_BOOLEAN_HELPURL = 'https://code.google.com/p/blockly/wiki/True_False'; /// block text - The word for the [https://en.wikipedia.org/wiki/Truth_value logical value] ''true''. Blockly.Msg.LOGIC_BOOLEAN_TRUE = 'true'; /// block text - The word for the [https://en.wikipedia.org/wiki/Truth_value logical value] ''false''. Blockly.Msg.LOGIC_BOOLEAN_FALSE = 'false'; /// tooltip - Indicates that the block returns either of the two possible [https://en.wikipedia.org/wiki/Truth_value logical values]. Blockly.Msg.LOGIC_BOOLEAN_TOOLTIP = 'Returns either true or false.'; /// url - Provide a link to the translation of [https://en.wikipedia.org/wiki/Nullable_type https://en.wikipedia.org/wiki/Nullable_type], if it exists in your language; otherwise, do not worry about translating this advanced concept. Blockly.Msg.LOGIC_NULL_HELPURL = 'https://en.wikipedia.org/wiki/Nullable_type'; /// block text - In computer languages, ''null'' is a special value that indicates that no value has been set. You may use your language's word for "nothing" or "invalid". Blockly.Msg.LOGIC_NULL = 'null'; /// tooltip - This should use the word from the previous message. Blockly.Msg.LOGIC_NULL_TOOLTIP = 'Returns null.'; /// url - Describes the programming language operator known as the ''ternary'' or ''conditional'' operator. It is recommended that you use the translation of [https://en.wikipedia.org/wiki/%3F: https://en.wikipedia.org/wiki/%3F:] if it exists. Blockly.Msg.LOGIC_TERNARY_HELPURL = 'https://en.wikipedia.org/wiki/%3F:'; /// block input text - Label for the input whose value determines which of the other two inputs is returned. In some programming languages, this is called a ''''predicate''''. Blockly.Msg.LOGIC_TERNARY_CONDITION = 'test'; /// block input text - Indicates that the following input should be returned (used as output) if the test input is true. Remember to try to keep block text terse (short). Blockly.Msg.LOGIC_TERNARY_IF_TRUE = 'if true'; /// block input text - Indicates that the following input should be returned (used as output) if the test input is false. Blockly.Msg.LOGIC_TERNARY_IF_FALSE = 'if false'; /// tooltip - See [https://en.wikipedia.org/wiki/%3F: https://en.wikipedia.org/wiki/%3F:]. Blockly.Msg.LOGIC_TERNARY_TOOLTIP = 'Check the condition in "test". If the condition is true, returns the "if true" value; otherwise returns the "if false" value.'; // Math Blocks. /// url - Information about (real) numbers. Blockly.Msg.MATH_NUMBER_HELPURL = 'https://en.wikipedia.org/wiki/Number'; /// tooltip - Any positive or negative number, not necessarily an integer. Blockly.Msg.MATH_NUMBER_TOOLTIP = 'A number.'; /// math - The symbol for the binary operation addition. Blockly.Msg.MATH_ADDITION_SYMBOL = '+'; /// math - The symbol for the binary operation indicating that the right operand should be /// subtracted from the left operand. Blockly.Msg.MATH_SUBTRACTION_SYMBOL = '-'; /// math - The binary operation indicating that the left operand should be divided by /// the right operand. Blockly.Msg.MATH_DIVISION_SYMBOL = '÷'; /// math - The symbol for the binary operation multiplication. Blockly.Msg.MATH_MULTIPLICATION_SYMBOL = '×'; /// math - The symbol for the binary operation exponentiation. Specifically, if the /// value of the left operand is L and the value of the right operand (the exponent) is /// R, multiply L by itself R times. (Fractional and negative exponents are also legal.) Blockly.Msg.MATH_POWER_SYMBOL = '^'; /// math - The short name of the trigonometric function /// [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent sine]. Blockly.Msg.MATH_TRIG_SIN = 'sin'; /// math - The short name of the trigonometric function /// [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent cosine]. Blockly.Msg.MATH_TRIG_COS = 'cos'; /// math - The short name of the trigonometric function /// [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent tangent]. Blockly.Msg.MATH_TRIG_TAN = 'tan'; /// math - The short name of the ''inverse of'' the trigonometric function /// [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent sine]. Blockly.Msg.MATH_TRIG_ASIN = 'asin'; /// math - The short name of the ''inverse of'' the trigonometric function /// [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent cosine]. Blockly.Msg.MATH_TRIG_ACOS = 'acos'; /// math - The short name of the ''inverse of'' the trigonometric function /// [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent tangent]. Blockly.Msg.MATH_TRIG_ATAN = 'atan'; /// url - Information about addition, subtraction, multiplication, division, and exponentiation. Blockly.Msg.MATH_ARITHMETIC_HELPURL = 'https://en.wikipedia.org/wiki/Arithmetic'; /// tooltip - See [https://en.wikipedia.org/wiki/Addition https://en.wikipedia.org/wiki/Addition]. Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD = 'Return the sum of the two numbers.'; /// tooltip - See [https://en.wikipedia.org/wiki/Subtraction https://en.wikipedia.org/wiki/Subtraction]. Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS = 'Return the difference of the two numbers.'; /// tooltip - See [https://en.wikipedia.org/wiki/Multiplication https://en.wikipedia.org/wiki/Multiplication]. Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY = 'Return the product of the two numbers.'; /// tooltip - See [https://en.wikipedia.org/wiki/Division_(mathematics) https://en.wikipedia.org/wiki/Division_(mathematics)]. Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE = 'Return the quotient of the two numbers.'; /// tooltip - See [https://en.wikipedia.org/wiki/Exponentiation https://en.wikipedia.org/wiki/Exponentiation]. Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER = 'Return the first number raised to the power of the second number.'; /// url - Information about the square root operation. Blockly.Msg.MATH_SINGLE_HELPURL = 'https://en.wikipedia.org/wiki/Square_root'; /// dropdown - This computes the positive [https://en.wikipedia.org/wiki/Square_root square root] of its input. For example, the square root of 16 is 4. Blockly.Msg.MATH_SINGLE_OP_ROOT = 'square root'; /// tooltip - Please use the same term as in the previous message. Blockly.Msg.MATH_SINGLE_TOOLTIP_ROOT = 'Return the square root of a number.'; /// dropdown - This leaves positive numeric inputs changed and inverts negative inputs. For example, the absolute value of 5 is 5; the absolute value of -5 is also 5. For more information, see [https://en.wikipedia.org/wiki/Absolute_value https://en.wikipedia.org/wiki/Absolute_value]. Blockly.Msg.MATH_SINGLE_OP_ABSOLUTE = 'absolute'; /// tooltip - Please use the same term as in the previous message. Blockly.Msg.MATH_SINGLE_TOOLTIP_ABS = 'Return the absolute value of a number.'; /// tooltip - Calculates '''0-n''', where '''n''' is the single numeric input. Blockly.Msg.MATH_SINGLE_TOOLTIP_NEG = 'Return the negation of a number.'; /// tooltip - Calculates the [https://en.wikipedia.org/wiki/Natural_logarithm|natural logarithm] of its single numeric input. Blockly.Msg.MATH_SINGLE_TOOLTIP_LN = 'Return the natural logarithm of a number.'; /// tooltip - Calculates the [https://en.wikipedia.org/wiki/Common_logarithm common logarithm] of its single numeric input. Blockly.Msg.MATH_SINGLE_TOOLTIP_LOG10 = 'Return the base 10 logarithm of a number.'; /// tooltip - Multiplies [https://en.wikipedia.org/wiki/E_%28mathematical_constant%29 e] by itself n times, where n is the single numeric input. Blockly.Msg.MATH_SINGLE_TOOLTIP_EXP = 'Return e to the power of a number.'; /// tooltip - Multiplies 10 by itself n times, where n is the single numeric input. Blockly.Msg.MATH_SINGLE_TOOLTIP_POW10 = 'Return 10 to the power of a number.'; /// url - Information about the trigonometric functions sine, cosine, tangent, and their inverses (ideally using degrees, not radians). Blockly.Msg.MATH_TRIG_HELPURL = 'https://en.wikipedia.org/wiki/Trigonometric_functions'; /// tooltip - Return the [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent sine] of an [https://en.wikipedia.org/wiki/Degree_(angle) angle in degrees], not radians. Blockly.Msg.MATH_TRIG_TOOLTIP_SIN = 'Return the sine of a degree (not radian).'; /// tooltip - Return the [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent cosine] of an [https://en.wikipedia.org/wiki/Degree_(angle) angle in degrees], not radians. Blockly.Msg.MATH_TRIG_TOOLTIP_COS = 'Return the cosine of a degree (not radian).'; /// tooltip - Return the [https://en.wikipedia.org/wiki/Trigonometric_functions#Sine.2C_cosine_and_tangent tangent] of an [https://en.wikipedia.org/wiki/Degree_(angle) angle in degrees], not radians. Blockly.Msg.MATH_TRIG_TOOLTIP_TAN = 'Return the tangent of a degree (not radian).'; /// tooltip - The [https://en.wikipedia.org/wiki/Inverse_trigonometric_functions inverse] of the [https://en.wikipedia.org/wiki/Cosine#Sine.2C_cosine_and_tangent sine function], using [https://en.wikipedia.org/wiki/Degree_(angle) degrees], not radians. Blockly.Msg.MATH_TRIG_TOOLTIP_ASIN = 'Return the arcsine of a number.'; /// tooltip - The [https://en.wikipedia.org/wiki/Inverse_trigonometric_functions inverse] of the [https://en.wikipedia.org/wiki/Cosine#Sine.2C_cosine_and_tangent cosine] function, using [https://en.wikipedia.org/wiki/Degree_(angle) degrees], not radians. Blockly.Msg.MATH_TRIG_TOOLTIP_ACOS = 'Return the arccosine of a number.'; /// tooltip - The [https://en.wikipedia.org/wiki/Inverse_trigonometric_functions inverse] of the [https://en.wikipedia.org/wiki/Cosine#Sine.2C_cosine_and_tangent tangent] function, using [https://en.wikipedia.org/wiki/Degree_(angle) degrees], not radians. Blockly.Msg.MATH_TRIG_TOOLTIP_ATAN = 'Return the arctangent of a number.'; /// url - Information about the mathematical constants \u0026pi;, e, the golden ratio (\u0026phi;), \u0026radic; 2, \u0026radic; 1/2, and infinity (\u0026infin;). Blockly.Msg.MATH_CONSTANT_HELPURL = 'https://en.wikipedia.org/wiki/Mathematical_constant'; /// tooltip - Provides the specified [https://en.wikipedia.org/wiki/Mathematical_constant mathematical constant]. Blockly.Msg.MATH_CONSTANT_TOOLTIP = 'Return one of the common constants: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (infinity).'; /// dropdown - A number is '''even''' if it is a multiple of 2. For example, 4 is even (yielding true), but 3 is not (false). Blockly.Msg.MATH_IS_EVEN = 'is even'; /// dropdown - A number is '''odd''' if it is not a multiple of 2. For example, 3 is odd (yielding true), but 4 is not (false). The opposite of "odd" is "even". Blockly.Msg.MATH_IS_ODD = 'is odd'; /// dropdown - A number is [https://en.wikipedia.org/wiki/Prime prime] if it cannot be evenly divided by any positive integers except for 1 and itself. For example, 5 is prime, but 6 is not because 2 \u0026times; 3 = 6. Blockly.Msg.MATH_IS_PRIME = 'is prime'; /// dropdown - A number is '''whole''' if it is an [https://en.wikipedia.org/wiki/Integer integer]. For example, 5 is whole, but 5.1 is not. Blockly.Msg.MATH_IS_WHOLE = 'is whole'; /// dropdown - A number is '''positive''' if it is greater than 0. (0 is neither negative nor positive.) Blockly.Msg.MATH_IS_POSITIVE = 'is positive'; /// dropdown - A number is '''negative''' if it is less than 0. (0 is neither negative nor positive.) Blockly.Msg.MATH_IS_NEGATIVE = 'is negative'; /// dropdown - A number x is divisible by y if y goes into x evenly. For example, 10 is divisible by 5, but 10 is not divisible by 3. Blockly.Msg.MATH_IS_DIVISIBLE_BY = 'is divisible by'; /// tooltip - This block lets the user specify via a dropdown menu whether to check if the numeric input is even, odd, prime, whole, positive, negative, or divisible by a given value. Blockly.Msg.MATH_IS_TOOLTIP = 'Check if a number is an even, odd, prime, whole, positive, negative, or if it is divisible by certain number. Returns true or false.'; /// url - Information about incrementing (increasing the value of) a variable. /// For other languages, just use the translation of the Wikipedia page about /// addition ([https://en.wikipedia.org/wiki/Addition https://en.wikipedia.org/wiki/Addition]). Blockly.Msg.MATH_CHANGE_HELPURL = 'https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter'; /// - As in: '''change''' [the value of variable] ''item by'' 1 (e.g., if the variable named 'item' had the value 5, change it to 6). Blockly.Msg.MATH_CHANGE_TITLE_CHANGE = 'change'; Blockly.Msg.MATH_CHANGE_TITLE_ITEM = Blockly.Msg.VARIABLES_DEFAULT_NAME; /// - As in: ''change'' [the value of variable] ''item'' '''by''' 1 (e.g., if the variable named 'item' had the value 5, change it to 6). Blockly.Msg.MATH_CHANGE_INPUT_BY = 'by'; /// tooltip - This updates the value of the variable by adding to it the following numeric input.\n\nParameters:\n* %1 - the name of the variable whose value should be increased. Blockly.Msg.MATH_CHANGE_TOOLTIP = 'Add a number to variable "%1".'; /// url - Information about how numbers are rounded to the nearest integer Blockly.Msg.MATH_ROUND_HELPURL = 'https://en.wikipedia.org/wiki/Rounding'; /// tooltip - See [https://en.wikipedia.org/wiki/Rounding https://en.wikipedia.org/wiki/Rounding]. Blockly.Msg.MATH_ROUND_TOOLTIP = 'Round a number up or down.'; /// dropdown - This rounds its input to the nearest whole number. For example, 3.4 is rounded to 3. Blockly.Msg.MATH_ROUND_OPERATOR_ROUND = 'round'; /// dropdown - This rounds its input up to the nearest whole number. For example, if the input was 2.2, the result would be 3. Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDUP = 'round up'; /// dropdown - This rounds its input down to the nearest whole number. For example, if the input was 3.8, the result would be 3. Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDDOWN = 'round down'; /// url - Information about applying a function to a list of numbers. (We were unable to find such information in English. Feel free to skip this and any other URLs that are difficult.) Blockly.Msg.MATH_ONLIST_HELPURL = ''; /// dropdown - This computes the sum of the numeric elements in the list. For example, the sum of the list {1, 4} is 5. Blockly.Msg.MATH_ONLIST_OPERATOR_SUM = 'sum of list'; /// tooltip - Please use the same term for "sum" as in the previous message. Blockly.Msg.MATH_ONLIST_TOOLTIP_SUM = 'Return the sum of all the numbers in the list.'; /// dropdown - This finds the smallest (minimum) number in a list. For example, the smallest number in the list [-5, 0, 3] is -5. Blockly.Msg.MATH_ONLIST_OPERATOR_MIN = 'min of list'; /// tooltip - Please use the same term for "min" or "minimum" as in the previous message. Blockly.Msg.MATH_ONLIST_TOOLTIP_MIN = 'Return the smallest number in the list.'; /// dropdown - This finds the largest (maximum) number in a list. For example, the largest number in the list [-5, 0, 3] is 3. Blockly.Msg.MATH_ONLIST_OPERATOR_MAX = 'max of list'; /// tooltip Blockly.Msg.MATH_ONLIST_TOOLTIP_MAX = 'Return the largest number in the list.'; /// dropdown - This adds up all of the numbers in a list and divides the sum by the number of elements in the list. For example, the [https://en.wikipedia.org/wiki/Arithmetic_mean average] of the list [1, 2, 3, 4] is 2.5 (10/4). Blockly.Msg.MATH_ONLIST_OPERATOR_AVERAGE = 'average of list'; /// tooltip - See [https://en.wikipedia.org/wiki/Arithmetic_mean https://en.wikipedia.org/wiki/Arithmetic_mean] for more informatin. Blockly.Msg.MATH_ONLIST_TOOLTIP_AVERAGE = 'Return the average (arithmetic mean) of the numeric values in the list.'; /// dropdown - This finds the [https://en.wikipedia.org/wiki/Median median] of the numeric values in a list. For example, the median of the list {1, 2, 7, 12, 13} is 7. Blockly.Msg.MATH_ONLIST_OPERATOR_MEDIAN = 'median of list'; /// tooltip - See [https://en.wikipedia.org/wiki/Median median https://en.wikipedia.org/wiki/Median median] for more information. Blockly.Msg.MATH_ONLIST_TOOLTIP_MEDIAN = 'Return the median number in the list.'; /// dropdown - This finds the most common numbers ([https://en.wikipedia.org/wiki/Mode_(statistics) modes]) in a list. For example, the modes of the list {1, 3, 9, 3, 9} are {3, 9}. Blockly.Msg.MATH_ONLIST_OPERATOR_MODE = 'modes of list'; /// tooltip - See [https://en.wikipedia.org/wiki/Mode_(statistics) https://en.wikipedia.org/wiki/Mode_(statistics)] for more information. Blockly.Msg.MATH_ONLIST_TOOLTIP_MODE = 'Return a list of the most common item(s) in the list.'; /// dropdown - This finds the [https://en.wikipedia.org/wiki/Standard_deviation standard deviation] of the numeric values in a list. Blockly.Msg.MATH_ONLIST_OPERATOR_STD_DEV = 'standard deviation of list'; /// tooltip - See [https://en.wikipedia.org/wiki/Standard_deviation https://en.wikipedia.org/wiki/Standard_deviation] for more information. Blockly.Msg.MATH_ONLIST_TOOLTIP_STD_DEV = 'Return the standard deviation of the list.'; /// dropdown - This choose an element at random from a list. Each element is chosen with equal probability. Blockly.Msg.MATH_ONLIST_OPERATOR_RANDOM = 'random item of list'; /// tooltip - Please use same term for 'random' as in previous entry. Blockly.Msg.MATH_ONLIST_TOOLTIP_RANDOM = 'Return a random element from the list.'; /// url - information about the modulo (remainder) operation. Blockly.Msg.MATH_MODULO_HELPURL = 'https://en.wikipedia.org/wiki/Modulo_operation'; /// block text - Title of block providing the remainder when dividing the first numerical input by the second. For example, the remainder of 10 divided by 3 is 1.\n\nParameters:\n* %1 - the dividend (10, in our example)\n* %2 - the divisor (3 in our example). Blockly.Msg.MATH_MODULO_TITLE = 'remainder of %1 ÷ %2'; /// tooltip - For example, the remainder of 10 divided by 3 is 1. Blockly.Msg.MATH_MODULO_TOOLTIP = 'Return the remainder from dividing the two numbers.'; /// url - Information about constraining a numeric value to be in a specific range. (The English URL is not ideal. Recall that translating URLs is the lowest priority.) Blockly.Msg.MATH_CONSTRAIN_HELPURL = 'https://en.wikipedia.org/wiki/Clamping_%28graphics%29'; /// block text - The title of the block that '''constrain'''s (forces) a number to be in a given range. ///For example, if the number 150 is constrained to be between 5 and 100, the result will be 100. ///\n\nParameters:\n* %1 - the value to constrain (e.g., 150)\n* %2 - the minimum value (e.g., 5)\n* %3 - the maximum value (e.g., 100). Blockly.Msg.MATH_CONSTRAIN_TITLE = 'constrain %1 low %2 high %3'; /// tooltip - This compares a number ''x'' to a low value ''L'' and a high value ''H''. If ''x'' is less then ''L'', the result is ''L''. If ''x'' is greater than ''H'', the result is ''H''. Otherwise, the result is ''x''. Blockly.Msg.MATH_CONSTRAIN_TOOLTIP = 'Constrain a number to be between the specified limits (inclusive).'; /// url - Information about how computers generate random numbers. Blockly.Msg.MATH_RANDOM_INT_HELPURL = 'https://en.wikipedia.org/wiki/Random_number_generation'; /// block text - The title of the block that generates a random integer (whole number) in the specified range. For example, if the range is from 5 to 7, this returns 5, 6, or 7 with equal likelihood. %1 is a placeholder for the lower number, %2 is the placeholder for the larger number. Blockly.Msg.MATH_RANDOM_INT_TITLE = 'random integer from %1 to %2'; /// tooltip - Return a random integer between two values specified as inputs. For example, if one input was 7 and another 9, any of the numbers 7, 8, or 9 could be produced. Blockly.Msg.MATH_RANDOM_INT_TOOLTIP = 'Return a random integer between the two specified limits, inclusive.'; /// url - Information about how computers generate random numbers (specifically, numbers in the range from 0 to just below 1). Blockly.Msg.MATH_RANDOM_FLOAT_HELPURL = 'https://en.wikipedia.org/wiki/Random_number_generation'; /// block text - The title of the block that generates a random number greater than or equal to 0 and less than 1. Blockly.Msg.MATH_RANDOM_FLOAT_TITLE_RANDOM = 'random fraction'; /// tooltip - Return a random fraction between 0 and 1. The value may be equal to 0 but must be less than 1. Blockly.Msg.MATH_RANDOM_FLOAT_TOOLTIP = 'Return a random fraction between 0.0 (inclusive) and 1.0 (exclusive).'; // Text Blocks. /// url - Information about how computers represent text (sometimes referred to as ''string''s). Blockly.Msg.TEXT_TEXT_HELPURL = 'https://en.wikipedia.org/wiki/String_(computer_science)'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Text#Introduction https://code.google.com/p/blockly/wiki/Text#Introduction]. Blockly.Msg.TEXT_TEXT_TOOLTIP = 'A letter, word, or line of text.'; /// url - Information on concatenating/appending pieces of text. Blockly.Msg.TEXT_JOIN_HELPURL = 'https://code.google.com/p/blockly/wiki/Text#Text_creation'; /// block text - See [https://code.google.com/p/blockly/wiki/Text#Text_creation https://code.google.com/p/blockly/wiki/Text#Text_creation]. Blockly.Msg.TEXT_JOIN_TITLE_CREATEWITH = 'create text with'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Text#Text_creation create text with] for more information. Blockly.Msg.TEXT_JOIN_TOOLTIP = 'Create a piece of text by joining together any number of items.'; /// block text - This is shown when the programmer wants to change the number of pieces of text being joined together. See [https://code.google.com/p/blockly/wiki/Text#Text_creation https://code.google.com/p/blockly/wiki/Text#Text_creation], specifically the last picture in the 'Text creation' section. Blockly.Msg.TEXT_CREATE_JOIN_TITLE_JOIN = 'join'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Text#Text_creation https://code.google.com/p/blockly/wiki/Text#Text_creation], specifically the last picture in the 'Text creation' section. Blockly.Msg.TEXT_CREATE_JOIN_TOOLTIP = 'Add, remove, or reorder sections to reconfigure this text block.'; Blockly.Msg.TEXT_CREATE_JOIN_ITEM_TITLE_ITEM = Blockly.Msg.VARIABLES_DEFAULT_NAME; /// block text - See [https://code.google.com/p/blockly/wiki/Text#Text_creation https://code.google.com/p/blockly/wiki/Text#Text_creation], specifically the last picture in the 'Text creation' section. Blockly.Msg.TEXT_CREATE_JOIN_ITEM_TOOLTIP = 'Add an item to the text.'; /// url - This and the other text-related URLs are going to be hard to translate. As always, it is okay to leave untranslated or paste in the English-language URL. For these URLs, you might also consider a general URL about how computers represent text (such as the translation of [https://en.wikipedia.org/wiki/String_(computer_science) this Wikipedia page]). Blockly.Msg.TEXT_APPEND_HELPURL = 'https://code.google.com/p/blockly/wiki/Text#Text_modification'; /// block input text - Message preceding the name of a variable to which text should be appended. /// [[File:blockly-append-text.png]] Blockly.Msg.TEXT_APPEND_TO = 'to'; /// block input text - Message following the variable and preceding the piece of text that should /// be appended, as shown below. /// [[File:blockly-append-text.png]] Blockly.Msg.TEXT_APPEND_APPENDTEXT = 'append text'; Blockly.Msg.TEXT_APPEND_VARIABLE = Blockly.Msg.VARIABLES_DEFAULT_NAME; /// tooltip - See [https://code.google.com/p/blockly/wiki/Text#Text_modification https://code.google.com/p/blockly/wiki/Text#Text_modification] for more information.\n\nParameters:\n* %1 - the name of the variable to which text should be appended Blockly.Msg.TEXT_APPEND_TOOLTIP = 'Append some text to variable "%1".'; /// url - Information about text on computers (usually referred to as 'strings'). Blockly.Msg.TEXT_LENGTH_HELPURL = 'https://code.google.com/p/blockly/wiki/Text#Text_modification'; /// block text - See [https://code.google.com/p/blockly/wiki/Text#Text_length https://code.google.com/p/blockly/wiki/Text#Text_length]. /// \n\nParameters:\n* %1 - the piece of text to take the length of Blockly.Msg.TEXT_LENGTH_TITLE = 'length of %1'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Text#Text_length https://code.google.com/p/blockly/wiki/Text#Text_length]. Blockly.Msg.TEXT_LENGTH_TOOLTIP = 'Returns the number of letters (including spaces) in the provided text.'; /// url - Information about empty pieces of text on computers (usually referred to as 'empty strings'). Blockly.Msg.TEXT_ISEMPTY_HELPURL = 'https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text'; /// block text - See [https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text]. /// \n\nParameters:\n* %1 - the piece of text to test for emptiness Blockly.Msg.TEXT_ISEMPTY_TITLE = '%1 is empty'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text https://code.google.com/p/blockly/wiki/Text#Checking_for_empty_text]. Blockly.Msg.TEXT_ISEMPTY_TOOLTIP = 'Returns true if the provided text is empty.'; /// url - Information about finding a character in a piece of text. Blockly.Msg.TEXT_INDEXOF_HELPURL = 'https://code.google.com/p/blockly/wiki/Text#Finding_text'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Text#Finding_text https://code.google.com/p/blockly/wiki/Text#Finding_text]. Blockly.Msg.TEXT_INDEXOF_TOOLTIP = 'Returns the index of the first/last occurrence of first text in the second text. Returns 0 if text is not found.'; /// block text - Title of blocks allowing users to find text. See /// [https://code.google.com/p/blockly/wiki/Text#Finding_text /// https://code.google.com/p/blockly/wiki/Text#Finding_text]. /// [[File:Blockly-find-text.png]]. Blockly.Msg.TEXT_INDEXOF_INPUT_INTEXT = 'in text'; /// dropdown - See [https://code.google.com/p/blockly/wiki/Text#Finding_text /// https://code.google.com/p/blockly/wiki/Text#Finding_text]. /// [[File:Blockly-find-text.png]]. Blockly.Msg.TEXT_INDEXOF_OPERATOR_FIRST = 'find first occurrence of text'; /// dropdown - See [https://code.google.com/p/blockly/wiki/Text#Finding_text /// https://code.google.com/p/blockly/wiki/Text#Finding_text]. This would /// replace "find first occurrence of text" below. (For more information on /// how common text is factored out of dropdown menus, see /// [https://translatewiki.net/wiki/Translating:Blockly#Drop-Down_Menus /// https://translatewiki.net/wiki/Translating:Blockly#Drop-Down_Menus)].) /// [[File:Blockly-find-text.png]]. Blockly.Msg.TEXT_INDEXOF_OPERATOR_LAST = 'find last occurrence of text'; /// block text - Optional text to follow the rightmost block in a /// [https://code.google.com/p/blockly/wiki/Text#Finding_text /// https://code.google.com/p/blockly/wiki/Text#Finding_text in text ... find block] /// (after the "a" in the below picture). This will be the empty string in most languages. /// [[File:Blockly-find-text.png]]. Blockly.Msg.TEXT_INDEXOF_TAIL = ''; /// url - Information about extracting characters (letters, number, symbols, etc.) from text. Blockly.Msg.TEXT_CHARAT_HELPURL = 'https://code.google.com/p/blockly/wiki/Text#Extracting_text'; /// block text - Appears before the piece of text from which a letter (or number, /// punctuation character, etc.) should be extracted, as shown below. See /// [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. /// [[File:Blockly-text-get.png]] Blockly.Msg.TEXT_CHARAT_INPUT_INTEXT = 'in text'; /// dropdown - Indicates that the letter (or number, punctuation character, etc.) with the /// specified index should be obtained from the preceding piece of text. See /// [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. /// [[File:Blockly-text-get.png]] Blockly.Msg.TEXT_CHARAT_FROM_START = 'get letter #'; /// block text - Indicates that the letter (or number, punctuation character, etc.) with the /// specified index from the end of a given piece of text should be obtained. See /// [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. /// [[File:Blockly-text-get.png]] Blockly.Msg.TEXT_CHARAT_FROM_END = 'get letter # from end'; /// block text - Indicates that the first letter of the following piece of text should be /// retrieved. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. /// [[File:Blockly-text-get.png]] Blockly.Msg.TEXT_CHARAT_FIRST = 'get first letter'; /// block text - Indicates that the last letter (or number, punctuation mark, etc.) of the /// following piece of text should be retrieved. See /// [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. /// [[File:Blockly-text-get.png]] Blockly.Msg.TEXT_CHARAT_LAST = 'get last letter'; /// block text - Indicates that any letter (or number, punctuation mark, etc.) in the /// following piece of text should be randomly selected. See /// [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. /// [[File:Blockly-text-get.png]] Blockly.Msg.TEXT_CHARAT_RANDOM = 'get random letter'; /// block text - Text that goes after the rightmost block/dropdown when getting a single letter from /// a piece of text, as in [https://blockly-demo.appspot.com/static/apps/code/index.html#3m23km these /// blocks] or shown below. For most languages, this will be blank. /// [[File:Blockly-text-get.png]] Blockly.Msg.TEXT_CHARAT_TAIL = ''; /// tooltip - See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_single_character]. /// [[File:Blockly-text-get.png]] Blockly.Msg.TEXT_CHARAT_TOOLTIP = 'Returns the letter at the specified position.'; /// See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. Blockly.Msg.TEXT_GET_SUBSTRING_TOOLTIP = 'Returns a specified portion of the text.'; /// url - Information about extracting characters from text. Reminder: urls are the /// lowest priority translations. Feel free to skip. Blockly.Msg.TEXT_GET_SUBSTRING_HELPURL = 'https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text'; /// block text - Precedes a piece of text from which a portion should be extracted. /// [[File:Blockly-get-substring.png]] Blockly.Msg.TEXT_GET_SUBSTRING_INPUT_IN_TEXT = 'in text'; /// dropdown - Indicates that the following number specifies the position (relative to the start /// position) of the beginning of the region of text that should be obtained from the preceding /// piece of text. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. /// [[File:Blockly-get-substring.png]] Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_START = 'get substring from letter #'; /// dropdown - Indicates that the following number specifies the position (relative to the end /// position) of the beginning of the region of text that should be obtained from the preceding /// piece of text. See [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. /// Note: If {{msg-Blockly|ORDINAL_NUMBER_SUFFIX}} is defined, it will /// automatically appear ''after'' this and any other /// [https://translatewiki.net/wiki/Translating:Blockly#Ordinal_numbers ordinal numbers] /// on this block. /// [[File:Blockly-get-substring.png]] Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_END = 'get substring from letter # from end'; /// block text - Indicates that a region starting with the first letter of the preceding piece /// of text should be extracted. See /// [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. /// [[File:Blockly-get-substring.png]] Blockly.Msg.TEXT_GET_SUBSTRING_START_FIRST = 'get substring from first letter'; /// dropdown - Indicates that the following number specifies the position (relative to /// the start position) of the end of the region of text that should be obtained from the /// preceding piece of text. See [ /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. /// [[File:Blockly-get-substring.png]] Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_START = 'to letter #'; /// dropdown - Indicates that the following number specifies the position (relative to the /// end position) of the end of the region of text that should be obtained from the preceding /// piece of text. See /// [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. /// [[File:Blockly-get-substring.png]] Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_END = 'to letter # from end'; /// block text - Indicates that a region ending with the last letter of the preceding piece /// of text should be extracted. See /// [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text /// https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text]. /// [[File:Blockly-get-substring.png]] Blockly.Msg.TEXT_GET_SUBSTRING_END_LAST = 'to last letter'; /// block text - Text that should go after the rightmost block/dropdown when /// [https://code.google.com/p/blockly/wiki/Text#Extracting_a_region_of_text /// extracting a region of text]. In most languages, this will be the empty string. /// [[File:Blockly-get-substring.png]] Blockly.Msg.TEXT_GET_SUBSTRING_TAIL = ''; /// url - Information about the case of letters (upper-case and lower-case). Blockly.Msg.TEXT_CHANGECASE_HELPURL = 'https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case' /// tooltip - Describes a block to adjust the case of letters. For more information on this block, /// see [https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case /// https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case]. Blockly.Msg.TEXT_CHANGECASE_TOOLTIP = 'Return a copy of the text in a different case.'; /// block text - Indicates that all of the letters in the following piece of text should be /// capitalized. If your language does not use case, you may indicate that this is not /// applicable to your language. For more information on this block, see /// [https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case /// https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case]. Blockly.Msg.TEXT_CHANGECASE_OPERATOR_UPPERCASE = 'to UPPER CASE'; /// block text - Indicates that all of the letters in the following piece of text should be converted to lower-case. If your language does not use case, you may indicate that this is not applicable to your language. For more information on this block, see [https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case]. Blockly.Msg.TEXT_CHANGECASE_OPERATOR_LOWERCASE = 'to lower case'; /// block text - Indicates that the first letter of each of the following words should be capitalized and the rest converted to lower-case. If your language does not use case, you may indicate that this is not applicable to your language. For more information on this block, see [https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case https://code.google.com/p/blockly/wiki/Text#Adjusting_text_case]. Blockly.Msg.TEXT_CHANGECASE_OPERATOR_TITLECASE = 'to Title Case'; /// url - Information about trimming (removing) text off the beginning and ends of pieces of text. Blockly.Msg.TEXT_TRIM_HELPURL = 'https://code.google.com/p/blockly/wiki/Text#Trimming_%28removing%29_spaces'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces /// https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces]. Blockly.Msg.TEXT_TRIM_TOOLTIP = 'Return a copy of the text with spaces removed from one or both ends.'; /// dropdown - Removes spaces from the beginning and end of a piece of text. See /// [https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces /// https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces]. Note that neither /// this nor the other options modify the original piece of text (that follows); /// the block just returns a version of the text without the specified spaces. Blockly.Msg.TEXT_TRIM_OPERATOR_BOTH = 'trim spaces from both sides of'; /// dropdown - Removes spaces from the beginning of a piece of text. See /// [https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces /// https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces]. /// Note that in right-to-left scripts, this will remove spaces from the right side. Blockly.Msg.TEXT_TRIM_OPERATOR_LEFT = 'trim spaces from left side of'; /// dropdown - Removes spaces from the end of a piece of text. See /// [https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces /// https://code.google.com/p/blockly/wiki/Text#Trimming_(removing)_spaces]. /// Note that in right-to-left scripts, this will remove spaces from the left side. Blockly.Msg.TEXT_TRIM_OPERATOR_RIGHT = 'trim spaces from right side of'; /// url - Information about displaying text on computers. Blockly.Msg.TEXT_PRINT_HELPURL = 'https://code.google.com/p/blockly/wiki/Text#Printing_text'; /// block text - Display the input on the screen. See /// [https://code.google.com/p/blockly/wiki/Text#Printing_text /// https://code.google.com/p/blockly/wiki/Text#Printing_text]. /// \n\nParameters:\n* %1 - the value to print Blockly.Msg.TEXT_PRINT_TITLE = 'print %1'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Text#Printing_text /// https://code.google.com/p/blockly/wiki/Text#Printing_text]. Blockly.Msg.TEXT_PRINT_TOOLTIP = 'Print the specified text, number or other value.'; /// url - Information about getting text from users. Blockly.Msg.TEXT_PROMPT_HELPURL = 'https://code.google.com/p/blockly/wiki/Text#Getting_input_from_the_user'; /// dropdown - Specifies that a piece of text should be requested from the user with /// the following message. See [https://code.google.com/p/blockly/wiki/Text#Printing_text /// https://code.google.com/p/blockly/wiki/Text#Printing_text]. Blockly.Msg.TEXT_PROMPT_TYPE_TEXT = 'prompt for text with message'; /// dropdown - Specifies that a number should be requested from the user with the /// following message. See [https://code.google.com/p/blockly/wiki/Text#Printing_text /// https://code.google.com/p/blockly/wiki/Text#Printing_text]. Blockly.Msg.TEXT_PROMPT_TYPE_NUMBER = 'prompt for number with message'; /// dropdown - Precedes the message with which the user should be prompted for /// a number. See [https://code.google.com/p/blockly/wiki/Text#Printing_text /// https://code.google.com/p/blockly/wiki/Text#Printing_text]. Blockly.Msg.TEXT_PROMPT_TOOLTIP_NUMBER = 'Prompt for user for a number.'; /// dropdown - Precedes the message with which the user should be prompted for some text. /// See [https://code.google.com/p/blockly/wiki/Text#Printing_text /// https://code.google.com/p/blockly/wiki/Text#Printing_text]. Blockly.Msg.TEXT_PROMPT_TOOLTIP_TEXT = 'Prompt for user for some text.'; // Lists Blocks. /// url - Information on empty lists. Blockly.Msg.LISTS_CREATE_EMPTY_HELPURL = 'https://en.wikipedia.org/wiki/Linked_list#Empty_lists'; /// block text - See [https://code.google.com/p/blockly/wiki/Lists#create_empty_list https://code.google.com/p/blockly/wiki/Lists#create_empty_list]. Blockly.Msg.LISTS_CREATE_EMPTY_TITLE = 'create empty list'; /// block text - See [https://code.google.com/p/blockly/wiki/Lists#create_empty_list https://code.google.com/p/blockly/wiki/Lists#create_empty_list]. Blockly.Msg.LISTS_CREATE_EMPTY_TOOLTIP = 'Returns a list, of length 0, containing no data records'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#create_list_with https://code.google.com/p/blockly/wiki/Lists#create_list_with]. Blockly.Msg.LISTS_CREATE_WITH_TOOLTIP = 'Create a list with any number of items.'; /// block text - See [https://code.google.com/p/blockly/wiki/Lists#create_list_with https://code.google.com/p/blockly/wiki/Lists#create_list_with]. Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH = 'create list with'; /// block text - This appears in a sub-block when [https://code.google.com/p/blockly/wiki/Lists#changing_number_of_inputs changing the number of inputs in a ''''create list with'''' block]. Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TITLE_ADD = 'list'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#changing_number_of_inputs https://code.google.com/p/blockly/wiki/Lists#changing_number_of_inputs]. Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TOOLTIP = 'Add, remove, or reorder sections to reconfigure this list block.'; Blockly.Msg.LISTS_CREATE_WITH_ITEM_TITLE = Blockly.Msg.VARIABLES_DEFAULT_NAME; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#changing_number_of_inputs https://code.google.com/p/blockly/wiki/Lists#changing_number_of_inputs]. Blockly.Msg.LISTS_CREATE_WITH_ITEM_TOOLTIP = 'Add an item to the list.'; /// url - Information about [https://code.google.com/p/blockly/wiki/Lists#create_list_with creating a list with multiple copies of a single item]. Blockly.Msg.LISTS_REPEAT_HELPURL = 'https://code.google.com/p/blockly/wiki/Lists#create_list_with'; /// url - See [https://code.google.com/p/blockly/wiki/Lists#create_list_with creating a list with multiple copies of a single item]. Blockly.Msg.LISTS_REPEAT_TOOLTIP = 'Creates a list consisting of the given value repeated the specified number of times.'; /// block text - See [https://code.google.com/p/blockly/wiki/Lists#create_list_with /// https://code.google.com/p/blockly/wiki/Lists#create_list_with]. ///\n\nParameters:\n* %1 - the item (text) to be repeated\n* %2 - the number of times to repeat it Blockly.Msg.LISTS_REPEAT_TITLE = 'create list with item %1 repeated %2 times'; /// url - Information about how the length of a list is computed (i.e., by the total number of elements, not the number of different elements). Blockly.Msg.LISTS_LENGTH_HELPURL = 'https://code.google.com/p/blockly/wiki/Lists#length_of'; /// block text - See [https://code.google.com/p/blockly/wiki/Lists#length_of https://code.google.com/p/blockly/wiki/Lists#length_of]. /// \n\nParameters:\n* %1 - the list whose length is desired Blockly.Msg.LISTS_LENGTH_TITLE = 'length of %1'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#length_of https://code.google.com/p/blockly/wiki/Lists#length_of Blockly:Lists:length of]. Blockly.Msg.LISTS_LENGTH_TOOLTIP = 'Returns the length of a list.'; /// url - See [https://code.google.com/p/blockly/wiki/Lists#is_empty https://code.google.com/p/blockly/wiki/Lists#is_empty]. Blockly.Msg.LISTS_IS_EMPTY_HELPURL = 'https://code.google.com/p/blockly/wiki/Lists#is_empty'; /// block text - See [https://code.google.com/p/blockly/wiki/Lists#is_empty /// https://code.google.com/p/blockly/wiki/Lists#is_empty]. /// \n\nParameters:\n* %1 - the list to test Blockly.Msg.LISTS_IS_EMPTY_TITLE = '%1 is empty'; /// block tooltip - See [https://code.google.com/p/blockly/wiki/Lists#is_empty /// https://code.google.com/p/blockly/wiki/Lists#is_empty]. Blockly.Msg.LISTS_TOOLTIP = 'Returns true if the list is empty.'; /// block text - Title of blocks operating on [https://code.google.com/p/blockly/wiki/Lists lists]. Blockly.Msg.LISTS_INLIST = 'in list'; /// url - See [https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List /// https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List]. Blockly.Msg.LISTS_INDEX_OF_HELPURL = 'https://code.google.com/p/blockly/wiki/Lists#Getting_Items_from_a_List'; Blockly.Msg.LISTS_INDEX_OF_INPUT_IN_LIST = Blockly.Msg.LISTS_INLIST; /// dropdown - See [https://code.google.com/p/blockly/wiki/Lists#Finding_Items_in_a_List /// Lists#Finding_Items_in_a_List]. /// [[File:Blockly-list-find.png]] Blockly.Msg.LISTS_INDEX_OF_FIRST = 'find first occurrence of item'; /// dropdown - See [https://code.google.com/p/blockly/wiki/Lists#Finding_Items_in_a_List /// https://code.google.com/p/blockly/wiki/Lists#Finding_Items_in_a_List]. /// [[File:Blockly-list-find.png]] Blockly.Msg.LISTS_INDEX_OF_LAST = 'find last occurrence of item'; /// dropdown - See [https://code.google.com/p/blockly/wiki/Lists#Finding_Items_in_a_List /// https://code.google.com/p/blockly/wiki/Lists#Finding_Items_in_a_List]. /// [[File:Blockly-list-find.png]] Blockly.Msg.LISTS_INDEX_OF_TOOLTIP = 'Returns the index of the first/last occurrence of the item in the list. Returns 0 if text is not found.'; Blockly.Msg.LISTS_GET_INDEX_HELPURL = Blockly.Msg.LISTS_INDEX_OF_HELPURL; /// dropdown - Indicates that the user wishes to /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item /// get an item from a list] without removing it from the list. Blockly.Msg.LISTS_GET_INDEX_GET = 'get'; /// dropdown - Indicates that the user wishes to /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item /// get and remove an item from a list], as opposed to merely getting /// it without modifying the list. Blockly.Msg.LISTS_GET_INDEX_GET_REMOVE = 'get and remove'; /// dropdown - Indicates that the user wishes to /// [https://code.google.com/p/blockly/wiki/Lists#Removing_an_item /// remove an item from a list]. Blockly.Msg.LISTS_GET_INDEX_REMOVE = 'remove'; /// dropdown - Indicates that an index relative to the front of the list should be used to /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item get and/or remove /// an item from a list]. Note: If {{msg-Blockly|ORDINAL_NUMBER_SUFFIX}} is defined, it will /// automatically appear ''after'' this number (and any other ordinal numbers on this block). /// See [[Translating:Blockly#Ordinal_numbers]] for more information on ordinal numbers in Blockly. /// [[File:Blockly-list-get-item.png]] Blockly.Msg.LISTS_GET_INDEX_FROM_START = '#'; /// dropdown - Indicates that an index relative to the end of the list should be used /// to [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item access an item in a list]. /// [[File:Blockly-list-get-item.png]] Blockly.Msg.LISTS_GET_INDEX_FROM_END = '# from end'; /// dropdown - Indicates that the '''first''' item should be /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item accessed in a list]. /// [[File:Blockly-list-get-item.png]] Blockly.Msg.LISTS_GET_INDEX_FIRST = 'first'; /// dropdown - Indicates that the '''last''' item should be /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item accessed in a list]. /// [[File:Blockly-list-get-item.png]] Blockly.Msg.LISTS_GET_INDEX_LAST = 'last'; /// dropdown - Indicates that a '''random''' item should be /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item accessed in a list]. /// [[File:Blockly-list-get-item.png]] Blockly.Msg.LISTS_GET_INDEX_RANDOM = 'random'; /// block text - Text that should go after the rightmost block/dropdown when /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item /// accessing an item from a list]. In most languages, this will be the empty string. /// [[File:Blockly-list-get-item.png]] Blockly.Msg.LISTS_GET_INDEX_TAIL = ''; Blockly.Msg.LISTS_GET_INDEX_INPUT_IN_LIST = Blockly.Msg.LISTS_INLIST; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item /// https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for more information. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FROM_START = 'Returns the item at the specified position in a list. #1 is the first item.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item /// https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for more information. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FROM_END = 'Returns the item at the specified position in a list. #1 is the last item.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item /// https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for more information. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FIRST = 'Returns the first item in a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item /// https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for more information. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_LAST = 'Returns the last item in a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item /// https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for more information. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_RANDOM = 'Returns a random item in a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] /// (for remove and return) and /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for '# from start'. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_START = 'Removes and returns the item at the specified position in a list. #1 is the first item.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for '# from end'. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM_END = 'Removes and returns the item at the specified position in a list. #1 is the last item.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for 'first'. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST = 'Removes and returns the first item in a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for 'last'. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST = 'Removes and returns the last item in a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for 'random'. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM = 'Removes and returns a random item in a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for '# from start'. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_START = 'Removes the item at the specified position in a list. #1 is the first item.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for '# from end'. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM_END = 'Removes the item at the specified position in a list. #1 is the last item.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for 'first'. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST = 'Removes the first item in a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for 'last'. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST = 'Removes the last item in a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_and_removing_an_item] (for remove and return) and [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item] for 'random'. Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM = 'Removes a random item in a list.'; /// url - Information about putting items in lists. Blockly.Msg.LISTS_SET_INDEX_HELPURL = 'https://code.google.com/p/blockly/wiki/Lists#in_list_..._set'; Blockly.Msg.LISTS_SET_INDEX_INPUT_IN_LIST = Blockly.Msg.LISTS_INLIST; /// block text - [https://code.google.com/p/blockly/wiki/Lists#in_list_..._set /// Replaces an item in a list]. /// [[File:Blockly-in-list-set-insert.png]] Blockly.Msg.LISTS_SET_INDEX_SET = 'set'; /// block text - [https://code.google.com/p/blockly/wiki/Lists#in_list_..._insert_at /// Inserts an item into a list]. /// [[File:Blockly-in-list-set-insert.png]] Blockly.Msg.LISTS_SET_INDEX_INSERT = 'insert at'; /// block text - The word(s) after the position in the list and before the item to be set/inserted. /// [[File:Blockly-in-list-set-insert.png]] Blockly.Msg.LISTS_SET_INDEX_INPUT_TO = 'as'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the "get" block, the idea is the same for the "set" block). Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FROM_START = 'Sets the item at the specified position in a list. #1 is the first item.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the "get" block, the idea is the same for the "set" block). Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FROM_END = 'Sets the item at the specified position in a list. #1 is the last item.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the "get" block, the idea is the same for the "set" block). Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FIRST = 'Sets the first item in a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the "get" block, the idea is the same for the "set" block). Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_LAST = 'Sets the last item in a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the "get" block, the idea is the same for the "set" block). Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_RANDOM = 'Sets a random item in a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the "get" block, the idea is the same for the "insert" block). Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_START = 'Inserts the item at the specified position in a list. #1 is the first item.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the "get" block, the idea is the same for the "insert" block). Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FROM_END = 'Inserts the item at the specified position in a list. #1 is the last item.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the "get" block, the idea is the same for the "insert" block). Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST = 'Inserts the item at the start of a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the "get" block, the idea is the same for the "insert" block). Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_LAST = 'Append the item to the end of a list.'; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_single_item} (even though the page describes the "get" block, the idea is the same for the "insert" block). Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM = 'Inserts the item randomly in a list.'; /// url - Information describing extracting a sublist from an existing list. Blockly.Msg.LISTS_GET_SUBLIST_HELPURL = 'https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist'; Blockly.Msg.LISTS_GET_SUBLIST_INPUT_IN_LIST = Blockly.Msg.LISTS_INLIST; /// dropdown - Indicates that an index relative to the front of the list should be used /// to specify the beginning of the range from which to /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist get a sublist]. /// [[File:Blockly-get-sublist.png]] /// Note: If {{msg-Blockly|ORDINAL_NUMBER_SUFFIX}} is defined, it will /// automatically appear ''after'' this number (and any other ordinal numbers on this block). /// See [[Translating:Blockly#Ordinal_numbers]] for more information on ordinal numbers in Blockly. Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_START = 'get sub-list from #'; /// dropdown - Indicates that an index relative to the end of the list should be used /// to specify the beginning of the range from which to /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist get a sublist]. Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_END = 'get sub-list from # from end'; /// dropdown - Indicates that the /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist sublist to extract] /// should begin with the list's first item. Blockly.Msg.LISTS_GET_SUBLIST_START_FIRST = 'get sub-list from first'; /// dropdown - Indicates that an index relative to the front of the list should be /// used to specify the end of the range from which to /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist get a sublist]. /// [[File:Blockly-get-sublist.png]] Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_START = 'to #'; /// dropdown - Indicates that an index relative to the end of the list should be /// used to specify the end of the range from which to /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist get a sublist]. /// [[File:Blockly-get-sublist.png]] Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_END = 'to # from end'; /// dropdown - Indicates that the '''last''' item in the given list should be /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist the end /// of the selected sublist]. /// [[File:Blockly-get-sublist.png]] Blockly.Msg.LISTS_GET_SUBLIST_END_LAST = 'to last'; /// block text - This appears in the rightmost position ("tail") of the /// sublist block, as described at /// [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist /// https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist]. /// In English and most other languages, this is the empty string. /// [[File:Blockly-get-sublist.png]] Blockly.Msg.LISTS_GET_SUBLIST_TAIL = ''; /// tooltip - See [https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist /// https://code.google.com/p/blockly/wiki/Lists#Getting_a_sublist] for more information. /// [[File:Blockly-get-sublist.png]] Blockly.Msg.LISTS_GET_SUBLIST_TOOLTIP = 'Creates a copy of the specified portion of a list.'; /// grammar - Text that follows an ordinal number (a number that indicates /// position relative to other numbers). In most languages, such text appears /// before the number, so this should be blank. An exception is Hungarian. /// See [[Translating:Blockly#Ordinal_numbers]] for more information. Blockly.Msg.ORDINAL_NUMBER_SUFFIX = ''; // Variables Blocks. /// url - Information about ''variables'' in computer programming. Consider using your language's translation of [https://en.wikipedia.org/wiki/Variable_(computer_science) https://en.wikipedia.org/wiki/Variable_(computer_science)], if it exists. Blockly.Msg.VARIABLES_GET_HELPURL = 'https://code.google.com/p/blockly/wiki/Variables#Get'; /// block text - This precedes the name of a variable when getting its values. In most (all?) languages, it should be the empty string. If unsure, ask yourself if any word should go before "x" in the expression "x + 1". Blockly.Msg.VARIABLES_GET_TITLE = ''; Blockly.Msg.VARIABLES_GET_ITEM = Blockly.Msg.VARIABLES_DEFAULT_NAME; /// block text - This follows the name of a variable. In most (all?) languages, it should be the empty string. If unsure, ask yourself if any word should go after "x" in the expression "x + 1". Blockly.Msg.VARIABLES_GET_TAIL = ''; /// tooltip - This gets the value of the named variable without modifying it. Blockly.Msg.VARIABLES_GET_TOOLTIP = 'Returns the value of this variable.'; /// context menu - Selecting this creates a block to set (change) the value of this variable. /// \n\nParameters:\n* %1 - the name of the variable. Blockly.Msg.VARIABLES_GET_CREATE_SET = 'Create "set %1"'; /// url - Information about ''variables'' in computer programming. Consider using your language's translation of [https://en.wikipedia.org/wiki/Variable_(computer_science) https://en.wikipedia.org/wiki/Variable_(computer_science)], if it exists. Blockly.Msg.VARIABLES_SET_HELPURL = 'https://code.google.com/p/blockly/wiki/Variables#Set'; /// block text - The imperative or infinitive form of the verb "set", as in: '''set''' [the value of] x to 7. Blockly.Msg.VARIABLES_SET_TITLE = 'set'; Blockly.Msg.VARIABLES_SET_ITEM = Blockly.Msg.VARIABLES_DEFAULT_NAME; /// block text - The word that goes after the name of the variable and before its new /// value in: set [the value of] x '''to''' 7. Blockly.Msg.VARIABLES_SET_TAIL = 'to'; /// tooltip - This initializes or changes the value of the named variable. Blockly.Msg.VARIABLES_SET_TOOLTIP = 'Sets this variable to be equal to the input.'; /// context menu - Selecting this creates a block to get (change) the value of /// this variable.\n\nParameters:\n* %1 - the name of the variable. Blockly.Msg.VARIABLES_SET_CREATE_GET = 'Create "get %1"'; // Procedures Blocks. /// url - Information about defining [https://en.wikipedia.org/wiki/Procedure_(computer_science) functions] that do not have return values. Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL = 'https://en.wikipedia.org/wiki/Procedure_%28computer_science%29'; /// block text - This precedes the name of the procedure when defining it. See /// [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#c84aoc this sample /// procedure definition]. Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE = 'to'; /// default name - This acts as a placeholder for the name of a function on a /// function definition block, as shown on /// [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#w7cfju this block]. /// The user will replace it with the function's name. Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE = 'do something'; /// block text - This precedes the list of parameters to a function. See /// [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#6ot5y5 this sample /// function with parameters]. Blockly.Msg.PROCEDURES_BEFORE_PARAMS = 'with:'; /// block text - This appears next to the function's "body", the blocks that should be /// run when the function is called, as shown in /// [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#c84aoc this sample /// procedure definition]. Blockly.Msg.PROCEDURES_DEFNORETURN_DO = ''; /// tooltip Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP = 'Creates a function with no output.'; /// url - Information about defining [https://en.wikipedia.org/wiki/Procedure_(computer_science) functions] that have return values. Blockly.Msg.PROCEDURES_DEFRETURN_HELPURL = 'https://en.wikipedia.org/wiki/Procedure_%28computer_science%29'; Blockly.Msg.PROCEDURES_DEFRETURN_TITLE = Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE; Blockly.Msg.PROCEDURES_DEFRETURN_PROCEDURE = Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE; Blockly.Msg.PROCEDURES_DEFRETURN_DO = Blockly.Msg.PROCEDURES_DEFNORETURN_DO; /// block text - This imperative or infinite verb precedes the value that is used as the return value /// (output) of this function. See /// [https://blockly-demo.appspot.com/static/apps/code/index.html?lang=en#6ot5y5 this sample /// function that returns a value]. Blockly.Msg.PROCEDURES_DEFRETURN_RETURN = 'return'; /// tooltip Blockly.Msg.PROCEDURES_DEFRETURN_TOOLTIP = 'Creates a function with an output.'; /// alert - The user has created a function with two parameters that have the same name. Every parameter must have a different name. Blockly.Msg.PROCEDURES_DEF_DUPLICATE_WARNING = 'Warning: This function has duplicate parameters.'; /// url - Information about calling [https://en.wikipedia.org/wiki/Procedure_(computer_science) functions] that do not return values. Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL = 'https://en.wikipedia.org/wiki/Procedure_%28computer_science%29'; /// block text - In most (if not all) languages, this will be the empty string. /// It precedes the name of the function that should be run. See, for example, /// the "draw square" block in [https://blockly-demo.appspot.com/static/apps/turtle/index.html#ztz96g]. Blockly.Msg.PROCEDURES_CALLNORETURN_CALL = ''; /// tooltip - This block causes the body (blocks inside) of the named function definition to be run. Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP = 'Run the user-defined function "%1".'; /// url - Information about calling [https://en.wikipedia.org/wiki/Procedure_(computer_science) functions] that return values. Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL = 'https://en.wikipedia.org/wiki/Procedure_%28computer_science%29'; Blockly.Msg.PROCEDURES_CALLRETURN_CALL = Blockly.Msg.PROCEDURES_CALLNORETURN_CALL; /// tooltip - This block causes the body (blocks inside) of the named function definition to be run.\n\nParameters:\n* %1 - the name of the function. Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP = 'Run the user-defined function "%1" and use its output.'; /// block text - This text appears on a block in a window that appears when the user clicks /// on the plus sign or star on a function definition block. It refers to the set of parameters /// (referred to by the simpler term "inputs") to the function. See /// [[Translating:Blockly#function_definitions]]. Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TITLE = 'inputs'; /// block text - This text appears on a block in a window that appears when the user clicks /// on the plus sign or star on a function definition block]. It appears on the block for /// adding an individual parameter (referred to by the simpler term "inputs") to the function. /// See [[Translating:Blockly#function_definitions]]. Blockly.Msg.PROCEDURES_MUTATORARG_TITLE = 'input name:'; /// context menu - This appears on the context menu for function calls. Selecting /// it causes the corresponding function definition to be highlighted (as shown at /// [[Translating:Blockly#context_menus]]. Blockly.Msg.PROCEDURES_HIGHLIGHT_DEF = 'Highlight function definition'; /// context menu - This appears on the context menu for function definitions. /// Selecting it creates a block to call the function. \n\nParameters:\n* %1 - the name of the function. Blockly.Msg.PROCEDURES_CREATE_DO = 'Create "%1"'; /// tooltip - If the first value is true, this causes the second value to be returned /// immediately from the enclosing function. Blockly.Msg.PROCEDURES_IFRETURN_TOOLTIP = 'If a value is true, then return a second value.'; /// warning - This appears if the user tries to use this block outside of a function definition. Blockly.Msg.PROCEDURES_IFRETURN_WARNING = 'Warning: This block may be used only within a function definition.'; /// Context Menu Copy Blockly.Msg.CONTEXT_BLOCK_COPY = 'Copy'; /// Context Menu Paste Blockly.Msg.CONTEXT_BLOCK_PASTE = 'Paste'; ================================================ FILE: extern/blockly/python_compressed.js ================================================ // Do not edit this file; automatically generated by build.py. "use strict"; // Copyright 2012 Google Inc. Apache License 2.0 Blockly.Python=new Blockly.Generator("Python");Blockly.Python.addReservedWords("and,as,assert,break,class,continue,def,del,elif,else,except,exec,finally,for,from,global,if,import,in,is,lambda,not,or,pass,print,raise,return,try,while,with,yield,True,False,None,NotImplemented,Ellipsis,__debug__,quit,exit,copyright,license,credits,abs,divmod,input,open,staticmethod,all,enumerate,int,ord,str,any,eval,isinstance,pow,sum,basestring,execfile,issubclass,print,super,bin,file,iter,property,tuple,bool,filter,len,range,type,bytearray,float,list,raw_input,unichr,callable,format,locals,reduce,unicode,chr,frozenset,long,reload,vars,classmethod,getattr,map,repr,xrange,cmp,globals,max,reversed,zip,compile,hasattr,memoryview,round,__import__,complex,hash,min,set,apply,delattr,help,next,setattr,buffer,dict,hex,object,slice,coerce,dir,id,oct,sorted,intern"); Blockly.Python.ORDER_ATOMIC=0;Blockly.Python.ORDER_COLLECTION=1;Blockly.Python.ORDER_STRING_CONVERSION=1;Blockly.Python.ORDER_MEMBER=2;Blockly.Python.ORDER_FUNCTION_CALL=2;Blockly.Python.ORDER_EXPONENTIATION=3;Blockly.Python.ORDER_UNARY_SIGN=4;Blockly.Python.ORDER_BITWISE_NOT=4;Blockly.Python.ORDER_MULTIPLICATIVE=5;Blockly.Python.ORDER_ADDITIVE=6;Blockly.Python.ORDER_BITWISE_SHIFT=7;Blockly.Python.ORDER_BITWISE_AND=8;Blockly.Python.ORDER_BITWISE_XOR=9;Blockly.Python.ORDER_BITWISE_OR=10; Blockly.Python.ORDER_RELATIONAL=11;Blockly.Python.ORDER_LOGICAL_NOT=12;Blockly.Python.ORDER_LOGICAL_AND=13;Blockly.Python.ORDER_LOGICAL_OR=14;Blockly.Python.ORDER_CONDITIONAL=15;Blockly.Python.ORDER_LAMBDA=16;Blockly.Python.ORDER_NONE=99;Blockly.Python.INFINITE_LOOP_TRAP=null; Blockly.Python.init=function(){Blockly.Python.definitions_=Object.create(null);Blockly.Python.functionNames_=Object.create(null);if(Blockly.Variables){Blockly.Python.variableDB_?Blockly.Python.variableDB_.reset():Blockly.Python.variableDB_=new Blockly.Names(Blockly.Python.RESERVED_WORDS_);for(var a=[],b=Blockly.Variables.allVariables(),c=0;c",GTE:">="}[a.getFieldValue("OP")],c=Blockly.Python.ORDER_RELATIONAL,d=Blockly.Python.valueToCode(a,"A",c)||"0";a=Blockly.Python.valueToCode(a,"B",c)||"0";return[d+" "+b+" "+a,c]}; Blockly.Python.logic_operation=function(a){var b="AND"==a.getFieldValue("OP")?"and":"or",c="and"==b?Blockly.Python.ORDER_LOGICAL_AND:Blockly.Python.ORDER_LOGICAL_OR,d=Blockly.Python.valueToCode(a,"A",c);a=Blockly.Python.valueToCode(a,"B",c);if(d||a){var e="and"==b?"True":"False";d||(d=e);a||(a=e)}else a=d="False";return[d+" "+b+" "+a,c]};Blockly.Python.logic_negate=function(a){return["not "+(Blockly.Python.valueToCode(a,"BOOL",Blockly.Python.ORDER_LOGICAL_NOT)||"True"),Blockly.Python.ORDER_LOGICAL_NOT]}; Blockly.Python.logic_boolean=function(a){return["TRUE"==a.getFieldValue("BOOL")?"True":"False",Blockly.Python.ORDER_ATOMIC]};Blockly.Python.logic_null=function(a){return["None",Blockly.Python.ORDER_ATOMIC]}; Blockly.Python.logic_ternary=function(a){var b=Blockly.Python.valueToCode(a,"IF",Blockly.Python.ORDER_CONDITIONAL)||"False",c=Blockly.Python.valueToCode(a,"THEN",Blockly.Python.ORDER_CONDITIONAL)||"None";a=Blockly.Python.valueToCode(a,"ELSE",Blockly.Python.ORDER_CONDITIONAL)||"None";return[c+" if "+b+" else "+a,Blockly.Python.ORDER_CONDITIONAL]};Blockly.Python.loops={};Blockly.Python.controls_repeat=function(a){var b=parseInt(a.getFieldValue("TIMES"),10),c=Blockly.Python.statementToCode(a,"DO")||" pass\n";Blockly.Python.INFINITE_LOOP_TRAP&&(c=Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+c);return"for "+Blockly.Python.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE)+" in range("+b+"):\n"+c}; Blockly.Python.controls_repeat_ext=function(a){var b=Blockly.Python.valueToCode(a,"TIMES",Blockly.Python.ORDER_NONE)||"0",b=Blockly.isNumber(b)?parseInt(b,10):"int("+b+")",c=Blockly.Python.statementToCode(a,"DO")||" pass\n";Blockly.Python.INFINITE_LOOP_TRAP&&(c=Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g,"'"+a.id+"'")+c);return"for "+Blockly.Python.variableDB_.getDistinctName("count",Blockly.Variables.NAME_TYPE)+" in range("+b+"):\n"+c}; Blockly.Python.controls_whileUntil=function(a){var b="UNTIL"==a.getFieldValue("MODE"),c=Blockly.Python.valueToCode(a,"BOOL",b?Blockly.Python.ORDER_LOGICAL_NOT:Blockly.Python.ORDER_NONE)||"False",d=Blockly.Python.statementToCode(a,"DO")||" pass\n";Blockly.Python.INFINITE_LOOP_TRAP&&(d=Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g,'"'+a.id+'"')+d);b&&(c="not "+c);return"while "+c+":\n"+d}; Blockly.Python.controls_for=function(a){var b=Blockly.Python.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE),c=Blockly.Python.valueToCode(a,"FROM",Blockly.Python.ORDER_NONE)||"0",d=Blockly.Python.valueToCode(a,"TO",Blockly.Python.ORDER_NONE)||"0",e=Blockly.Python.valueToCode(a,"BY",Blockly.Python.ORDER_NONE)||"1",g=Blockly.Python.statementToCode(a,"DO")||" pass\n";Blockly.Python.INFINITE_LOOP_TRAP&&(g=Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g,'"'+a.id+'"')+g);var f= "",h=function(){return Blockly.Python.provideFunction_("upRange",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(start, stop, step):"," while start <= stop:"," yield start"," start += abs(step)"])},k=function(){return Blockly.Python.provideFunction_("downRange",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(start, stop, step):"," while start >= stop:"," yield start"," start -= abs(step)"])};a=function(a,b,c){return"("+a+" <= "+b+") and "+h()+"("+a+", "+b+", "+c+") or "+k()+ "("+a+", "+b+", "+c+")"};if(Blockly.isNumber(c)&&Blockly.isNumber(d)&&Blockly.isNumber(e))c=parseFloat(c),d=parseFloat(d),e=Math.abs(parseFloat(e)),0===c%1&&0===d%1&&0===e%1?(c<=d?(d++,a=0==c&&1==e?d:c+", "+d,1!=e&&(a+=", "+e)):(d--,a=c+", "+d+", -"+e),a="range("+a+")"):(a=ca?Blockly.Python.ORDER_UNARY_SIGN:Blockly.Python.ORDER_ATOMIC]}; Blockly.Python.math_arithmetic=function(a){var b={ADD:[" + ",Blockly.Python.ORDER_ADDITIVE],MINUS:[" - ",Blockly.Python.ORDER_ADDITIVE],MULTIPLY:[" * ",Blockly.Python.ORDER_MULTIPLICATIVE],DIVIDE:[" / ",Blockly.Python.ORDER_MULTIPLICATIVE],POWER:[" ** ",Blockly.Python.ORDER_EXPONENTIATION]}[a.getFieldValue("OP")],c=b[0],b=b[1],d=Blockly.Python.valueToCode(a,"A",b)||"0";a=Blockly.Python.valueToCode(a,"B",b)||"0";return[d+c+a,b]}; Blockly.Python.math_single=function(a){var b=a.getFieldValue("OP"),c;if("NEG"==b)return c=Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_UNARY_SIGN)||"0",["-"+c,Blockly.Python.ORDER_UNARY_SIGN];Blockly.Python.definitions_.import_math="import math";a="SIN"==b||"COS"==b||"TAN"==b?Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_MULTIPLICATIVE)||"0":Blockly.Python.valueToCode(a,"NUM",Blockly.Python.ORDER_NONE)||"0";switch(b){case "ABS":c="math.fabs("+a+")";break;case "ROOT":c="math.sqrt("+ a+")";break;case "LN":c="math.log("+a+")";break;case "LOG10":c="math.log10("+a+")";break;case "EXP":c="math.exp("+a+")";break;case "POW10":c="math.pow(10,"+a+")";break;case "ROUND":c="round("+a+")";break;case "ROUNDUP":c="math.ceil("+a+")";break;case "ROUNDDOWN":c="math.floor("+a+")";break;case "SIN":c="math.sin("+a+" / 180.0 * math.pi)";break;case "COS":c="math.cos("+a+" / 180.0 * math.pi)";break;case "TAN":c="math.tan("+a+" / 180.0 * math.pi)"}if(c)return[c,Blockly.Python.ORDER_FUNCTION_CALL];switch(b){case "ASIN":c= "math.asin("+a+") / math.pi * 180";break;case "ACOS":c="math.acos("+a+") / math.pi * 180";break;case "ATAN":c="math.atan("+a+") / math.pi * 180";break;default:throw"Unknown math operator: "+b;}return[c,Blockly.Python.ORDER_MULTIPLICATIVE]}; Blockly.Python.math_constant=function(a){var b={PI:["math.pi",Blockly.Python.ORDER_MEMBER],E:["math.e",Blockly.Python.ORDER_MEMBER],GOLDEN_RATIO:["(1 + math.sqrt(5)) / 2",Blockly.Python.ORDER_MULTIPLICATIVE],SQRT2:["math.sqrt(2)",Blockly.Python.ORDER_MEMBER],SQRT1_2:["math.sqrt(1.0 / 2)",Blockly.Python.ORDER_MEMBER],INFINITY:["float('inf')",Blockly.Python.ORDER_ATOMIC]};a=a.getFieldValue("CONSTANT");"INFINITY"!=a&&(Blockly.Python.definitions_.import_math="import math");return b[a]}; Blockly.Python.math_number_property=function(a){var b=Blockly.Python.valueToCode(a,"NUMBER_TO_CHECK",Blockly.Python.ORDER_MULTIPLICATIVE)||"0",c=a.getFieldValue("PROPERTY"),d;if("PRIME"==c)return Blockly.Python.definitions_.import_math="import math",[Blockly.Python.provideFunction_("math_isPrime",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(n):"," # https://en.wikipedia.org/wiki/Primality_test#Naive_methods"," # If n is not a number but a string, try parsing it."," if type(n) not in (int, float, long):", " try:"," n = float(n)"," except:"," return False"," if n == 2 or n == 3:"," return True"," # False if n is negative, is 1, or not whole, or if n is divisible by 2 or 3."," if n <= 1 or n % 1 != 0 or n % 2 == 0 or n % 3 == 0:"," return False"," # Check all the numbers of form 6k +/- 1, up to sqrt(n)."," for x in range(6, int(math.sqrt(n)) + 2, 6):"," if n % (x - 1) == 0 or n % (x + 1) == 0:"," return False"," return True"])+"("+b+")",Blockly.Python.ORDER_FUNCTION_CALL]; switch(c){case "EVEN":d=b+" % 2 == 0";break;case "ODD":d=b+" % 2 == 1";break;case "WHOLE":d=b+" % 1 == 0";break;case "POSITIVE":d=b+" > 0";break;case "NEGATIVE":d=b+" < 0";break;case "DIVISIBLE_BY":a=Blockly.Python.valueToCode(a,"DIVISOR",Blockly.Python.ORDER_MULTIPLICATIVE);if(!a||"0"==a)return["False",Blockly.Python.ORDER_ATOMIC];d=b+" % "+a+" == 0"}return[d,Blockly.Python.ORDER_RELATIONAL]}; Blockly.Python.math_change=function(a){var b=Blockly.Python.valueToCode(a,"DELTA",Blockly.Python.ORDER_ADDITIVE)||"0";a=Blockly.Python.variableDB_.getName(a.getFieldValue("VAR"),Blockly.Variables.NAME_TYPE);return a+" = ("+a+" if type("+a+") in (int, float, long) else 0) + "+b+"\n"};Blockly.Python.math_round=Blockly.Python.math_single;Blockly.Python.math_trig=Blockly.Python.math_single; Blockly.Python.math_on_list=function(a){var b=a.getFieldValue("OP");a=Blockly.Python.valueToCode(a,"LIST",Blockly.Python.ORDER_NONE)||"[]";switch(b){case "SUM":b="sum("+a+")";break;case "MIN":b="min("+a+")";break;case "MAX":b="max("+a+")";break;case "AVERAGE":b=Blockly.Python.provideFunction_("math_mean",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(myList):"," localList = [e for e in myList if type(e) in (int, float, long)]"," if not localList: return"," return float(sum(localList)) / len(localList)"]); b=b+"("+a+")";break;case "MEDIAN":b=Blockly.Python.provideFunction_("math_median",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(myList):"," localList = sorted([e for e in myList if type(e) in (int, float, long)])"," if not localList: return"," if len(localList) % 2 == 0:"," return (localList[len(localList) / 2 - 1] + localList[len(localList) / 2]) / 2.0"," else:"," return localList[(len(localList) - 1) / 2]"]);b=b+"("+a+")";break;case "MODE":b=Blockly.Python.provideFunction_("math_modes", ["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(some_list):"," modes = []"," # Using a lists of [item, count] to keep count rather than dict",' # to avoid "unhashable" errors when the counted item is itself a list or dict.'," counts = []"," maxCount = 1"," for item in some_list:"," found = False"," for count in counts:"," if count[0] == item:"," count[1] += 1"," maxCount = max(maxCount, count[1])"," found = True"," if not found:"," counts.append([item, 1])", " for counted_item, item_count in counts:"," if item_count == maxCount:"," modes.append(counted_item)"," return modes"]);b=b+"("+a+")";break;case "STD_DEV":Blockly.Python.definitions_.import_math="import math";b=Blockly.Python.provideFunction_("math_standard_deviation",["def "+Blockly.Python.FUNCTION_NAME_PLACEHOLDER_+"(numbers):"," n = len(numbers)"," if n == 0: return"," mean = float(sum(numbers)) / n"," variance = sum((x - mean) ** 2 for x in numbers) / n"," return math.sqrt(variance)"]); b=b+"("+a+")";break;case "RANDOM":Blockly.Python.definitions_.import_random="import random";b="random.choice("+a+")";break;default:throw"Unknown operator: "+b;}return[b,Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.math_modulo=function(a){var b=Blockly.Python.valueToCode(a,"DIVIDEND",Blockly.Python.ORDER_MULTIPLICATIVE)||"0";a=Blockly.Python.valueToCode(a,"DIVISOR",Blockly.Python.ORDER_MULTIPLICATIVE)||"0";return[b+" % "+a,Blockly.Python.ORDER_MULTIPLICATIVE]}; Blockly.Python.math_constrain=function(a){var b=Blockly.Python.valueToCode(a,"VALUE",Blockly.Python.ORDER_NONE)||"0",c=Blockly.Python.valueToCode(a,"LOW",Blockly.Python.ORDER_NONE)||"0";a=Blockly.Python.valueToCode(a,"HIGH",Blockly.Python.ORDER_NONE)||"float('inf')";return["min(max("+b+", "+c+"), "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]}; Blockly.Python.math_random_int=function(a){Blockly.Python.definitions_.import_random="import random";var b=Blockly.Python.valueToCode(a,"FROM",Blockly.Python.ORDER_NONE)||"0";a=Blockly.Python.valueToCode(a,"TO",Blockly.Python.ORDER_NONE)||"0";return["random.randint("+b+", "+a+")",Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.math_random_float=function(a){Blockly.Python.definitions_.import_random="import random";return["random.random()",Blockly.Python.ORDER_FUNCTION_CALL]};Blockly.Python.procedures={}; Blockly.Python.procedures_defreturn=function(a){for(var b=Blockly.Variables.allVariables(a),c=b.length-1;0<=c;c--){var d=b[c];-1==a.arguments_.indexOf(d)?b[c]=Blockly.Python.variableDB_.getName(d,Blockly.Variables.NAME_TYPE):b.splice(c,1)}b=b.length?" global "+b.join(", ")+"\n":"";c=Blockly.Python.variableDB_.getName(a.getFieldValue("NAME"),Blockly.Procedures.NAME_TYPE);d=Blockly.Python.statementToCode(a,"STACK");Blockly.Python.INFINITE_LOOP_TRAP&&(d=Blockly.Python.INFINITE_LOOP_TRAP.replace(/%1/g,'"'+ a.id+'"')+d);var e=Blockly.Python.valueToCode(a,"RETURN",Blockly.Python.ORDER_NONE)||"";e?e=" return "+e+"\n":d||(d=" pass");for(var g=[],f=0;f Unit tests for Blockly ================================================ FILE: extern/blockly/tests/blockly_test.js ================================================ /** * Visual Blocks Editor * * Copyright 2011 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict'; function verify_DB_(msg, expected, db) { var equal = (expected.length == db.length); if (equal) { for (var x = 0; x < expected.length; x++) { if (expected[x] != db[x]) { equal = false; break; } } } if (equal) { assertTrue(msg, true); } else { assertEquals(msg, expected, db); } } function test_DB_addConnection() { var db = new Blockly.ConnectionDB(); var o2 = {y_: 2}; db.addConnection_(o2); verify_DB_('Adding connection #2', [o2], db); var o4 = {y_: 4}; db.addConnection_(o4); verify_DB_('Adding connection #4', [o2, o4], db); var o1 = {y_: 1}; db.addConnection_(o1); verify_DB_('Adding connection #1', [o1, o2, o4], db); var o3a = {y_: 3}; db.addConnection_(o3a); verify_DB_('Adding connection #3a', [o1, o2, o3a, o4], db); var o3b = {y_: 3}; db.addConnection_(o3b); verify_DB_('Adding connection #3b', [o1, o2, o3b, o3a, o4], db); } function test_DB_removeConnection() { var db = new Blockly.ConnectionDB(); var o1 = {y_: 1}; var o2 = {y_: 2}; var o3a = {y_: 3}; var o3b = {y_: 3}; var o3c = {y_: 3}; var o4 = {y_: 4}; db.addConnection_(o1); db.addConnection_(o2); db.addConnection_(o3c); db.addConnection_(o3b); db.addConnection_(o3a); db.addConnection_(o4); verify_DB_('Adding connections 1-4', [o1, o2, o3a, o3b, o3c, o4], db); db.removeConnection_(o2); verify_DB_('Removing connection #2', [o1, o3a, o3b, o3c, o4], db); db.removeConnection_(o4); verify_DB_('Removing connection #4', [o1, o3a, o3b, o3c], db); db.removeConnection_(o1); verify_DB_('Removing connection #1', [o3a, o3b, o3c], db); db.removeConnection_(o3a); verify_DB_('Removing connection #3a', [o3b, o3c], db); db.removeConnection_(o3c); verify_DB_('Removing connection #3c', [o3b], db); db.removeConnection_(o3b); verify_DB_('Removing connection #3b', [], db); } function test_addClass() { var p = document.createElement('p'); Blockly.addClass_(p, 'one'); assertEquals('Adding "one"', 'one', p.className); Blockly.addClass_(p, 'one'); assertEquals('Adding duplicate "one"', 'one', p.className); Blockly.addClass_(p, 'two'); assertEquals('Adding "two"', 'one two', p.className); Blockly.addClass_(p, 'two'); assertEquals('Adding duplicate "two"', 'one two', p.className); Blockly.addClass_(p, 'three'); assertEquals('Adding "three"', 'one two three', p.className); } function test_removeClass() { var p = document.createElement('p'); p.className = ' one three two three '; Blockly.removeClass_(p, 'two'); assertEquals('Removing "two"', 'one three three', p.className); Blockly.removeClass_(p, 'four'); assertEquals('Removing "four"', 'one three three', p.className); Blockly.removeClass_(p, 'three'); assertEquals('Removing "three"', 'one', p.className); Blockly.removeClass_(p, 'ne'); assertEquals('Removing "ne"', 'one', p.className); Blockly.removeClass_(p, 'one'); assertEquals('Removing "one"', '', p.className); Blockly.removeClass_(p, 'zero'); assertEquals('Removing "zero"', '', p.className); } function test_shortestStringLength() { var len = Blockly.shortestStringLength('one,two,three,four,five'.split(',')); assertEquals('Length of "one"', 3, len); len = Blockly.shortestStringLength('one,two,three,four,five,'.split(',')); assertEquals('Length of ""', 0, len); len = Blockly.shortestStringLength(['Hello World']); assertEquals('List of one', 11, len); len = Blockly.shortestStringLength([]); assertEquals('Empty list', 0, len); } function test_commonWordPrefix() { var len = Blockly.commonWordPrefix('one,two,three,four,five'.split(',')); assertEquals('No prefix', 0, len); len = Blockly.commonWordPrefix('Xone,Xtwo,Xthree,Xfour,Xfive'.split(',')); assertEquals('No word prefix', 0, len); len = Blockly.commonWordPrefix('abc de,abc de,abc de,abc de'.split(',')); assertEquals('Full equality', 6, len); len = Blockly.commonWordPrefix('abc deX,abc deY'.split(',')); assertEquals('One word prefix', 4, len); len = Blockly.commonWordPrefix('abc de,abc deY'.split(',')); assertEquals('Overflow no', 4, len); len = Blockly.commonWordPrefix('abc de,abc de Y'.split(',')); assertEquals('Overflow yes', 6, len); len = Blockly.commonWordPrefix(['Hello World']); assertEquals('List of one', 11, len); len = Blockly.commonWordPrefix([]); assertEquals('Empty list', 0, len); len = Blockly.commonWordPrefix('turn left,turn right'.split(',')); assertEquals('No prefix due to &nbsp;', 0, len); len = Blockly.commonWordPrefix('turn\u00A0left,turn\u00A0right'.split(',')); assertEquals('No prefix due to \\u00A0', 0, len); } function test_commonWordSuffix() { var len = Blockly.commonWordSuffix('one,two,three,four,five'.split(',')); assertEquals('No prefix', 0, len); len = Blockly.commonWordSuffix('oneX,twoX,threeX,fourX,fiveX'.split(',')); assertEquals('No word prefix', 0, len); len = Blockly.commonWordSuffix('abc de,abc de,abc de,abc de'.split(',')); assertEquals('Full equality', 6, len); len = Blockly.commonWordSuffix('Xabc de,Yabc de'.split(',')); assertEquals('One word prefix', 3, len); len = Blockly.commonWordSuffix('abc de,Yabc de'.split(',')); assertEquals('Overflow no', 3, len); len = Blockly.commonWordSuffix('abc de,Y abc de'.split(',')); assertEquals('Overflow yes', 6, len); len = Blockly.commonWordSuffix(['Hello World']); assertEquals('List of one', 11, len); len = Blockly.commonWordSuffix([]); assertEquals('Empty list', 0, len); } ================================================ FILE: extern/blockly/tests/generator_test.js ================================================ /** * Blockly Tests * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict'; function test_prefix() { var generator = new Blockly.Generator('INTERCAL'); assertEquals('Prefix nothing.', '', generator.prefixLines('', '')); assertEquals('Prefix a word.', '@Hello', generator.prefixLines('Hello', '@')); assertEquals('Prefix one line.', '12Hello\n', generator.prefixLines('Hello\n', '12')); assertEquals('Prefix two lines.', '***Hello\n***World\n', generator.prefixLines('Hello\nWorld\n', '***')); } ================================================ FILE: extern/blockly/tests/generators/colour.xml ================================================ test rgb from rgb 100 40 0 #ff6600 test colour picker static colour #ff6600 #ff6600 test blend blend #ff0000 100 40 0 0.4 #ff2900 test colour random 100 item test name item 7 test name FIRST item # i 2 7 test name TRUE NEQ 0 FIRST abcdefABDEF0123456789 FROM_START item i ================================================ FILE: extern/blockly/tests/generators/index.html ================================================ Blockly Generator Test

Blockly Generator Test

Generate:

================================================ FILE: extern/blockly/tests/generators/lists.xml ================================================ test create test create empty test create items TRUE love TRUE love test create repeated Eject 3 Eject Eject Eject test empty not empty FALSE 0 empty TRUE test length zero length 0 one length cat 1 three length cat TRUE 3 test find find first FIRST Alice Eve Bob Eve Eve 2 find last LAST Alice Eve Bob Eve Eve 4 find none FIRST Alice Bob Carol Dave Eve 0 test get list Kirk Spock McCoy get first GET FIRST list Kirk get last GET LAST list McCoy get random TRUE POSITIVE FIRST list GET RANDOM list get # GET FROM_START list 2 Spock get #-end GET FROM_END list 3 Kirk test get remove list Kirk Spock McCoy getremove first GET_REMOVE FIRST list Kirk getremove first list list Spock McCoy list Kirk Spock McCoy getremove last GET_REMOVE LAST list McCoy getremove last list list Kirk Spock list Kirk Spock McCoy getremove random TRUE EQ FIRST list GET_REMOVE RANDOM list 0 getremove random list list 2 list Kirk Spock McCoy getremove # GET_REMOVE FROM_START list 2 Spock getremove # list list Kirk McCoy list Kirk Spock McCoy getremove #-end GET_REMOVE FROM_END list 3 Kirk getremove #-end list list Spock McCoy test remove list Kirk Spock McCoy REMOVE FIRST list remove first list list Spock McCoy list Kirk Spock McCoy REMOVE LAST list remove last list list Kirk Spock list Kirk Spock McCoy REMOVE RANDOM list remove random list list 2 list Kirk Spock McCoy REMOVE FROM_START list 2 remove # list list Kirk McCoy list Kirk Spock McCoy REMOVE FROM_END list 3 remove #-end list list Spock McCoy test set x Picard Riker Crusher SET FIRST x Jean-Luc set first list x Jean-Luc Riker Crusher x Picard Riker Crusher SET LAST x Beverly set last list x Picard Riker Beverly x Picard Riker Crusher SET RANDOM x Data set random list x 3 x Picard Riker Crusher SET FROM_START x 3 Pulaski set # list x Picard Riker Pulaski x Picard Riker Crusher SET FROM_END x 1 Pulaski set #-end list x Picard Riker Pulaski test insert x Picard Riker Crusher INSERT FIRST x Data insert first list x Data Picard Riker Crusher x Picard Riker Crusher INSERT LAST x Data insert last list x Picard Riker Crusher Data x Picard Riker Crusher INSERT RANDOM x Data insert random list x 4 x Picard Riker Crusher INSERT FROM_START x 3 Data insert # list x Picard Riker Data Crusher x Picard Riker Crusher INSERT FROM_END x 1 Data insert #-end list x Picard Riker Data Crusher test sublist list Columbia Challenger Discovery Atlantis Endeavour sublist # start FROM_START FROM_START list 2 3 Challenger Discovery sublist # end FROM_END FROM_END list 3 2 Discovery Atlantis sublist first-last FIRST LAST list list ================================================ FILE: extern/blockly/tests/generators/logic.xml ================================================ True TRUE TRUE False FALSE FALSE Not true TRUE FALSE Not false FALSE TRUE test if FALSE if false ok FALSE TRUE ok TRUE if true TRUE ok ok FALSE FALSE if/else false ok TRUE if/else false TRUE ok ok FALSE TRUE ok TRUE if/else true if/else true TRUE ok ok FALSE FALSE elseif 1 TRUE ok TRUE TRUE elseif 2 elseif 3 elseif 4 TRUE ok test equalities Equal yes TRUE EQ 2 2 Equal no FALSE EQ 3 4 Not equal yes TRUE NEQ 5 6 Not equal no FALSE EQ 3 4 Smaller yes TRUE LT 5 6 Smaller no FALSE LT 7 7 Greater yes TRUE GT 9 8 Greater no FALSE GT 10 10 Smaller-equal yes TRUE LTE 11 11 Smaller-equal no FALSE LTE 13 12 Greater-equal yes TRUE GTE 14 14 Greater-equal no FALSE GTE 15 16 test or Or true/true TRUE OR TRUE TRUE Or false/true TRUE OR FALSE TRUE Or true/false TRUE OR TRUE FALSE Or false/false FALSE OR FALSE FALSE test and And true/true TRUE AND TRUE TRUE And false/true FALSE AND FALSE TRUE And true/false FALSE AND TRUE FALSE And false/false FALSE AND FALSE FALSE test ternary if true TRUE 42 99 42 if true FALSE 42 99 99 ================================================ FILE: extern/blockly/tests/generators/loops1.xml ================================================ test foreach log x a b c log x for loop log abc test while WHILE FALSE while 0 UNTIL TRUE until 0 count 1 WHILE NEQ count 10 count 1 while 10 count 10 count 1 UNTIL EQ count 10 count 1 until 10 count 10 test repeat count 0 10 count 1 repeat 10 count 10 ================================================ FILE: extern/blockly/tests/generators/loops2.xml ================================================ test count by log x 1 8 2 log x count up ints log 1357 log x 8 1 2 log x count down ints log 8642 loglist x 1 8 1.5 INSERT LAST loglist x count with floats loglist 1 2.5 4 5.5 7 loglist x ADD 1 0 ADD 8 0 MINUS 1 2 INSERT LAST loglist x count up non-trivial ints loglist 1 2 3 4 5 6 7 8 loglist x ADD 8 0 ADD 1 0 2 INSERT LAST loglist x count down non-trivial ints loglist 8 6 4 2 loglist x ADD 5 0.5 ADD 1 0 ADD 1 0 INSERT LAST loglist x count with floats loglist 5.5 4.5 3.5 2.5 1.5 test count log x 1 8 log x count up log 12345678 log x 8 1 log x count down log 87654321 loglist x ADD 1 0 ADD 4 0 INSERT LAST loglist x count up non-trivial loglist 1 2 3 4 loglist x ADD 3 1 ADD 1 0 INSERT LAST loglist x count down non-trivial loglist 4 3 2 1 ================================================ FILE: extern/blockly/tests/generators/loops3.xml ================================================ test break count 1 WHILE NEQ count 10 EQ count 5 BREAK count 1 while break count 5 count 1 UNTIL EQ count 10 EQ count 5 BREAK count 1 until break count 5 log x 1 8 EQ x 5 BREAK log x count break log 1234 log x a b c d EQ x c BREAK log x for break log ab test continue log count 0 WHILE NEQ count 8 count 1 EQ count 5 CONTINUE log count while continue log 1234678 log count 0 UNTIL EQ count 8 count 1 EQ count 5 CONTINUE log count until continue log 1234678 log x 1 8 EQ x 5 CONTINUE log x count continue log 1234678 log x a b c d EQ x c CONTINUE log x for continue log abd ================================================ FILE: extern/blockly/tests/generators/math.xml ================================================ test operations on single sqrt ROOT 25 5 abs ABS -25 25 negate NEG -25 25 ln LN 1 0 log10 LOG10 100 2 exp EXP 2 7.38905609893065 power10 POW10 2 100 test arithmetic add ADD 1 2 3 subtract MINUS 1 2 -1 multiply MULTIPLY 4 2.5 10 divide DIVIDE 8.2 -5 -1.64 power POWER 10 4 10000 test trig sin SIN 90 1 cos COS 180 -1 tan TAN 0 0 asin ASIN -1 -90 acos ACOS 1 0 atan ATAN 1 45 test constant const pi ROUNDDOWN MULTIPLY PI 1000 3141 const e ROUNDDOWN MULTIPLY E 1000 2718 const golden ROUNDDOWN MULTIPLY GOLDEN_RATIO 1000 1618 const sqrt 2 ROUNDDOWN MULTIPLY SQRT2 1000 1414 const sqrt 0.5 ROUNDDOWN MULTIPLY SQRT1_2 1000 707 const infinity TRUE LT 9999 INFINITY test number properties even TRUE EVEN 42 odd FALSE ODD 42.1 prime 5 TRUE PRIME 5 prime 25 FALSE PRIME 25 prime negative FALSE PRIME -31.1 whole FALSE WHOLE PI positive TRUE POSITIVE INFINITY negative TRUE NEGATIVE -42 divisible TRUE DIVISIBLE_BY 42 2 test round round ROUND 42.42 42 round up ROUNDUP -42.42 -42 round down ROUNDDOWN 42.42 42 test change varToChange 100 varToChange 42 change varToChange 142 assert list equal equal TRUE NEQ a b equal FALSE x 1 a NEQ GET FROM_START x a GET FROM_START x b equal FALSE BREAK equal list equality a b equal test operations on list sum SUM 3 4 5 12 min MIN 3 4 5 3 max MAX 3 4 5 5 average AVERAGE 3 4 5 4 median MEDIAN 3 4 5 1 3.5 modes TRUE MODE 3 4 3 3 standard dev STD_DEV 3 3 3 0 random TRUE GT FIRST RANDOM 3 4 5 3 4 5 0 test mod mod 42 5 2 test constraint constraint 100 0 42 42 test random integer rand 5 10 randRange TRUE AND GTE rand 5 LTE rand 10 randInteger TRUE WHOLE rand test random fraction rand randFloat TRUE AND GTE rand 0 LTE rand 1 ================================================ FILE: extern/blockly/tests/generators/procedures.xml ================================================ test recurse 3 -1-2-1-3-1-2-1- test procedure 8 2 procedure with global proc z 4 proc w FALSE FALSE procedure no return TRUE proc w proc w FALSE TRUE procedure return FALSE proc w procedure 1 proc z DIVIDE proc x proc y procedure 2 proc x proc w TRUE test function function with arguments 2 3 -1 function with side effect func z side effect func a unchanged func c global function with global 2 3global function with scope func a unchanged function return TRUE TRUE function no return FALSE FALSE function 1 func z side effect MINUS func x func y function 2 func a 1 func a func c function 3 func a TRUE FALSE recurse GT n 0 text MINUS n 1 n MINUS n 1 text - text ================================================ FILE: extern/blockly/tests/generators/text.xml ================================================ test length length Google 6 length 0 test empty not empty FALSE Google empty TRUE test create text single text Hello Hello double text K 9 K9 triple text 1 2 3 123 test append item item Miserable item Failure append text item MiserableFailure item 12 item 34 append number item 1234 test substring text 123456789 substring # start FROM_START FROM_START text 2 3 23 substring # end FROM_END FROM_END text 3 2 78 substring first-last FIRST LAST text text test find first find FIRST Banana an 2 last find LAST Banana an 4 no find FIRST Banana Peel 0 test letter letter # FROM_START Blockly 3 o letter # from end FROM_END Blockly 3 k first letter FIRST Blockly B last letter LAST Blockly y random letter TRUE POSITIVE FIRST Blockly RANDOM Blockly test case uppercase UPPERCASE Hello World HELLO WORLD lowercase LOWERCASE Hello World hello world titlecase TITLECASE heLLo WorlD Hello World test trim trim both BOTH abc def abc def trim left LEFT abc def abc def trim right RIGHT abc def abc def ================================================ FILE: extern/blockly/tests/generators/unittest.js ================================================ /** * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Unit test blocks for Blockly. * @author fraser@google.com (Neil Fraser) */ 'use strict'; Blockly.Blocks['unittest_main'] = { // Container for unit tests. init: function() { this.setColour(65); this.appendDummyInput() .appendField('run tests'); this.appendStatementInput('DO'); this.setTooltip('Executes the enclosed unit tests,\n' + 'then prints a summary.'); }, getVars: function() { return ['unittestResults']; } }; Blockly.Blocks['unittest_assertequals'] = { // Asserts that a value equals another value. init: function() { this.setColour(65); this.setPreviousStatement(true); this.setNextStatement(true); this.appendDummyInput() .appendField(new Blockly.FieldTextInput('test name'), 'MESSAGE'); this.appendValueInput('ACTUAL', null) .appendField('actual'); this.appendValueInput('EXPECTED', null) .appendField('expected'); this.setTooltip('Tests that "actual == expected".'); }, getVars: function() { return ['unittestResults']; } }; Blockly.Blocks['unittest_assertvalue'] = { // Asserts that a value is true, false, or null. init: function() { this.setColour(65); this.setPreviousStatement(true); this.setNextStatement(true); this.appendDummyInput() .appendField(new Blockly.FieldTextInput('test name'), 'MESSAGE'); this.appendValueInput('ACTUAL', Boolean) .appendField('assert') .appendField(new Blockly.FieldDropdown( [['true', 'TRUE'], ['false', 'FALSE'], ['null', 'NULL']]), 'EXPECTED'); this.setTooltip('Tests that the value is true, false, or null.'); }, getVars: function() { return ['unittestResults']; } }; Blockly.Blocks['unittest_fail'] = { // Always assert an error. init: function() { this.setColour(65); this.setPreviousStatement(true); this.setNextStatement(true); this.appendDummyInput() .appendField(new Blockly.FieldTextInput('test name'), 'MESSAGE') .appendField('fail'); this.setTooltip('Records an error.'); }, getVars: function() { return ['unittestResults']; } }; ================================================ FILE: extern/blockly/tests/generators/unittest_dart.js ================================================ /** * Visual Blocks Language * * Copyright 2014 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Dart for unit test blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; Blockly.Dart['unittest_main'] = function(block) { // Container for unit tests. var resultsVar = Blockly.Dart.variableDB_.getName('unittestResults', Blockly.Variables.NAME_TYPE); var functionName = Blockly.Dart.provideFunction_( 'unittest_report', [ 'String ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '() {', ' // Create test report.', ' List report = [];', ' StringBuffer summary = new StringBuffer();', ' int fails = 0;', ' for (int x = 0; x < ' + resultsVar + '.length; x++) {', ' if (' + resultsVar + '[x][0]) {', ' summary.write(".");', ' } else {', ' summary.write("F");', ' fails++;', ' report.add("");', ' report.add("FAIL: ${' + resultsVar + '[x][2]}");', ' report.add(' + resultsVar + '[x][1]);', ' }', ' }', ' report.insert(0, summary.toString());', ' report.add("");', ' report.add("Ran ${' + resultsVar + '.length} tests.");', ' report.add("");', ' if (fails != 0) {', ' report.add("FAILED (failures=$fails)");', ' } else {', ' report.add("OK");', ' }', ' return report.join("\\n");', '}']); // Setup global to hold test results. var code = resultsVar + ' = [];\n'; // Run tests (unindented). code += Blockly.Dart.statementToCode(block, 'DO') .replace(/^ /, '').replace(/\n /g, '\n'); var reportVar = Blockly.Dart.variableDB_.getDistinctName( 'report', Blockly.Variables.NAME_TYPE); code += 'String ' + reportVar + ' = ' + functionName + '();\n'; // Destroy results. code += resultsVar + ' = null;\n'; // Print the report to the console (that's where errors will go anyway). code += 'print(' + reportVar + ');\n'; return code; }; Blockly.Dart['unittest_main'].defineAssert_ = function() { var resultsVar = Blockly.Dart.variableDB_.getName('unittestResults', Blockly.Variables.NAME_TYPE); var functionName = Blockly.Dart.provideFunction_( 'unittest_assertequals', [ 'void ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(dynamic actual, dynamic expected, String message) {', ' // Asserts that a value equals another value.', ' if (' + resultsVar + ' == null) {', ' throw "Orphaned assert: ${message}";', ' }', ' bool equals(a, b) {', ' if (a == b) {', ' return true;', ' } else if (a is List && b is List) {', ' if (a.length != b.length) {', ' return false;', ' }', ' for (num i = 0; i < a.length; i++) {', ' if (!equals(a[i], b[i])) {', ' return false;', ' }', ' }', ' return true;', ' }', ' return false;', ' }', ' if (equals(actual, expected)) {', ' ' + resultsVar + '.add([true, "OK", message]);', ' } else {', ' ' + resultsVar + '.add([false, ' + '"Expected: $expected\\nActual: $actual", message]);', ' }', '}']); return functionName; }; Blockly.Dart['unittest_assertequals'] = function(block) { // Asserts that a value equals another value. var message = Blockly.Dart.quote_(block.getFieldValue('MESSAGE')); var actual = Blockly.Dart.valueToCode(block, 'ACTUAL', Blockly.Dart.ORDER_NONE) || 'null'; var expected = Blockly.Dart.valueToCode(block, 'EXPECTED', Blockly.Dart.ORDER_NONE) || 'null'; return Blockly.Dart['unittest_main'].defineAssert_() + '(' + actual + ', ' + expected + ', ' + message + ');\n'; }; Blockly.Dart['unittest_assertvalue'] = function(block) { // Asserts that a value is true, false, or null. var message = Blockly.Dart.quote_(block.getFieldValue('MESSAGE')); var actual = Blockly.Dart.valueToCode(block, 'ACTUAL', Blockly.Dart.ORDER_NONE) || 'null'; var expected = block.getFieldValue('EXPECTED'); if (expected == 'TRUE') { expected = 'true'; } else if (expected == 'FALSE') { expected = 'false'; } else if (expected == 'NULL') { expected = 'null'; } return Blockly.Dart['unittest_main'].defineAssert_() + '(' + actual + ', ' + expected + ', ' + message + ');\n'; }; Blockly.Dart['unittest_fail'] = function(block) { // Always assert an error. var resultsVar = Blockly.Dart.variableDB_.getName('unittestResults', Blockly.Variables.NAME_TYPE); var message = Blockly.Dart.quote_(block.getFieldValue('MESSAGE')); var functionName = Blockly.Dart.provideFunction_( 'unittest_fail', [ 'void ' + Blockly.Dart.FUNCTION_NAME_PLACEHOLDER_ + '(String message) {', ' // Always assert an error.', ' if (' + resultsVar + ' == null) {', ' throw "Orphaned assert fail: ${message}";', ' }', ' ' + resultsVar + '.add([false, "Fail.", message]);', '}']); return functionName + '(' + message + ');\n'; }; ================================================ FILE: extern/blockly/tests/generators/unittest_javascript.js ================================================ /** * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating JavaScript for unit test blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; Blockly.JavaScript['unittest_main'] = function(block) { // Container for unit tests. var resultsVar = Blockly.JavaScript.variableDB_.getName('unittestResults', Blockly.Variables.NAME_TYPE); var functionName = Blockly.JavaScript.provideFunction_( 'unittest_report', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '() {', ' // Create test report.', ' var report = [];', ' var summary = [];', ' var fails = 0;', ' for (var x = 0; x < ' + resultsVar + '.length; x++) {', ' if (' + resultsVar + '[x][0]) {', ' summary.push(".");', ' } else {', ' summary.push("F");', ' fails++;', ' report.push("");', ' report.push("FAIL: " + ' + resultsVar + '[x][2]);', ' report.push(' + resultsVar + '[x][1]);', ' }', ' }', ' report.unshift(summary.join(""));', ' report.push("");', ' report.push("Number of tests run: " + ' + resultsVar + '.length);', ' report.push("");', ' if (fails) {', ' report.push("FAILED (failures=" + fails + ")");', ' } else {', ' report.push("OK");', ' }', ' return report.join("\\n");', '}']); // Setup global to hold test results. var code = resultsVar + ' = [];\n'; // Run tests (unindented). code += Blockly.JavaScript.statementToCode(block, 'DO') .replace(/^ /, '').replace(/\n /g, '\n'); var reportVar = Blockly.JavaScript.variableDB_.getDistinctName( 'report', Blockly.Variables.NAME_TYPE); code += 'var ' + reportVar + ' = ' + functionName + '();\n'; // Destroy results. code += resultsVar + ' = null;\n'; // Send the report to the console (that's where errors will go anyway). code += 'console.log(' + reportVar + ');\n'; return code; }; Blockly.JavaScript['unittest_main'].defineAssert_ = function(block) { var resultsVar = Blockly.JavaScript.variableDB_.getName('unittestResults', Blockly.Variables.NAME_TYPE); var functionName = Blockly.JavaScript.provideFunction_( 'assertEquals', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(actual, expected, message) {', ' // Asserts that a value equals another value.', ' if (!' + resultsVar + ') {', ' throw "Orphaned assert: " + message;', ' }', ' function equals(a, b) {', ' if (a === b) {', ' return true;', ' } else if (a instanceof Array && b instanceof Array) {', ' if (a.length != b.length) {', ' return false;', ' }', ' for (var i = 0; i < a.length; i++) {', ' if (!equals(a[i], b[i])) {', ' return false;', ' }', ' }', ' return true;', ' }', ' return false;', ' }', ' if (equals(actual, expected)) {', ' ' + resultsVar + '.push([true, "OK", message]);', ' } else {', ' ' + resultsVar + '.push([false, ' + '"Expected: " + expected + "\\nActual: " + actual, message]);', ' }', '}']); return functionName; }; Blockly.JavaScript['unittest_assertequals'] = function(block) { // Asserts that a value equals another value. var message = Blockly.JavaScript.quote_(block.getFieldValue('MESSAGE')); var actual = Blockly.JavaScript.valueToCode(block, 'ACTUAL', Blockly.JavaScript.ORDER_COMMA) || 'null'; var expected = Blockly.JavaScript.valueToCode(block, 'EXPECTED', Blockly.JavaScript.ORDER_COMMA) || 'null'; return Blockly.JavaScript['unittest_main'].defineAssert_() + '(' + actual + ', ' + expected + ', ' + message + ');\n'; }; Blockly.JavaScript['unittest_assertvalue'] = function(block) { // Asserts that a value is true, false, or null. var message = Blockly.JavaScript.quote_(block.getFieldValue('MESSAGE')); var actual = Blockly.JavaScript.valueToCode(block, 'ACTUAL', Blockly.JavaScript.ORDER_COMMA) || 'null'; var expected = block.getFieldValue('EXPECTED'); if (expected == 'TRUE') { expected = 'true'; } else if (expected == 'FALSE') { expected = 'false'; } else if (expected == 'NULL') { expected = 'null'; } return Blockly.JavaScript['unittest_main'].defineAssert_() + '(' + actual + ', ' + expected + ', ' + message + ');\n'; }; Blockly.JavaScript['unittest_fail'] = function(block) { // Always assert an error. var resultsVar = Blockly.JavaScript.variableDB_.getName('unittestResults', Blockly.Variables.NAME_TYPE); var message = Blockly.JavaScript.quote_(block.getFieldValue('MESSAGE')); var functionName = Blockly.JavaScript.provideFunction_( 'unittest_fail', [ 'function ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + '(message) {', ' // Always assert an error.', ' if (!' + resultsVar + ') {', ' throw "Orphaned assert fail: " + message;', ' }', ' ' + resultsVar + '.push([false, "Fail.", message]);', '}']); return functionName + '(' + message + ');\n'; }; ================================================ FILE: extern/blockly/tests/generators/unittest_python.js ================================================ /** * Visual Blocks Language * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Generating Python for unit test blocks. * @author fraser@google.com (Neil Fraser) */ 'use strict'; Blockly.Python['unittest_main'] = function(block) { // Container for unit tests. var resultsVar = Blockly.Python.variableDB_.getName('unittestResults', Blockly.Variables.NAME_TYPE); var functionName = Blockly.Python.provideFunction_( 'unittest_report', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '():', ' # Create test report.', ' report = []', ' summary = []', ' fails = 0', ' for (success, log, message) in ' + resultsVar + ':', ' if success:', ' summary.append(".")', ' else:', ' summary.append("F")', ' fails += 1', ' report.append("")', ' report.append("FAIL: " + message)', ' report.append(log)', ' report.insert(0, "".join(summary))', ' report.append("")', ' report.append("Number of tests run: %d" % len(' + resultsVar + '))', ' report.append("")', ' if fails:', ' report.append("FAILED (failures=%d)" % fails)', ' else:', ' report.append("OK")', ' return "\\n".join(report)']); // Setup global to hold test results. var code = resultsVar + ' = []\n'; // Run tests (unindented). code += Blockly.Python.statementToCode(block, 'DO') .replace(/^ /, '').replace(/\n /g, '\n'); var reportVar = Blockly.Python.variableDB_.getDistinctName( 'report', Blockly.Variables.NAME_TYPE); code += reportVar + ' = ' + functionName + '()\n'; // Destroy results. code += resultsVar + ' = None\n'; // Print the report. code += 'print(' + reportVar + ')\n'; return code; }; Blockly.Python['unittest_main'].defineAssert_ = function() { var resultsVar = Blockly.Python.variableDB_.getName('unittestResults', Blockly.Variables.NAME_TYPE); var functionName = Blockly.Python.provideFunction_( 'assertEquals', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(actual, expected, message):', ' # Asserts that a value equals another value.', ' if ' + resultsVar + ' == None:', ' raise Exception("Orphaned assert equals: " + message)', ' if actual == expected:', ' ' + resultsVar + '.append((True, "OK", message))', ' else:', ' ' + resultsVar + '.append((False, ' + '"Expected: %s\\nActual: %s" % (expected, actual), message))']); return functionName; }; Blockly.Python['unittest_assertequals'] = function(block) { // Asserts that a value equals another value. var message = Blockly.Python.quote_(block.getFieldValue('MESSAGE')); var actual = Blockly.Python.valueToCode(block, 'ACTUAL', Blockly.Python.ORDER_NONE) || 'None'; var expected = Blockly.Python.valueToCode(block, 'EXPECTED', Blockly.Python.ORDER_NONE) || 'None'; return Blockly.Python['unittest_main'].defineAssert_() + '(' + actual + ', ' + expected + ', ' + message + ')\n'; }; Blockly.Python['unittest_assertvalue'] = function(block) { // Asserts that a value is true, false, or null. var message = Blockly.Python.quote_(block.getFieldValue('MESSAGE')); var actual = Blockly.Python.valueToCode(block, 'ACTUAL', Blockly.Python.ORDER_NONE) || 'None'; var expected = block.getFieldValue('EXPECTED'); if (expected == 'TRUE') { expected = 'True'; } else if (expected == 'FALSE') { expected = 'False'; } else if (expected == 'NULL') { expected = 'None'; } return Blockly.Python['unittest_main'].defineAssert_() + '(' + actual + ', ' + expected + ', ' + message + ')\n'; }; Blockly.Python['unittest_fail'] = function(block) { // Always assert an error. var resultsVar = Blockly.Python.variableDB_.getName('unittestResults', Blockly.Variables.NAME_TYPE); var message = Blockly.Python.quote_(block.getFieldValue('MESSAGE')); var functionName = Blockly.Python.provideFunction_( 'fail', ['def ' + Blockly.Python.FUNCTION_NAME_PLACEHOLDER_ + '(message):', ' # Always assert an error.', ' if ' + resultsVar + ' == None:', ' raise Exception("Orphaned assert equals: " + message)', ' ' + resultsVar + '.append((False, "Fail.", message))']); return functionName + '(' + message + ')\n'; }; ================================================ FILE: extern/blockly/tests/generators/variables.xml ================================================ item 123 variable item 123 if 123 reserved variable if 123 ================================================ FILE: extern/blockly/tests/names_test.js ================================================ /** * Blockly Tests * * Copyright 2012 Google Inc. * https://blockly.googlecode.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict'; function test_safeName() { var varDB = new Blockly.Names('window,door'); assertEquals('SafeName empty.', 'unnamed', varDB.safeName_('')); assertEquals('SafeName ok.', 'foobar', varDB.safeName_('foobar')); assertEquals('SafeName number start.', 'my_9lives', varDB.safeName_('9lives')); assertEquals('SafeName number end.', 'lives9', varDB.safeName_('lives9')); assertEquals('SafeName special chars.', '____', varDB.safeName_('!@#$')); assertEquals('SafeName reserved.', 'door', varDB.safeName_('door')); } function test_getName() { var varDB = new Blockly.Names('window,door'); assertEquals('Name add #1.', 'Foo_bar', varDB.getName('Foo.bar', 'var')); assertEquals('Name get #1.', 'Foo_bar', varDB.getName('Foo.bar', 'var')); assertEquals('Name add #2.', 'Foo_bar2', varDB.getName('Foo bar', 'var')); assertEquals('Name get #2.', 'Foo_bar2', varDB.getName('foo BAR', 'var')); assertEquals('Name add #3.', 'door2', varDB.getName('door', 'var')); assertEquals('Name add #4.', 'Foo_bar3', varDB.getName('Foo.bar', 'proc')); assertEquals('Name get #1b.', 'Foo_bar', varDB.getName('Foo.bar', 'var')); assertEquals('Name get #4.', 'Foo_bar3', varDB.getName('Foo.bar', 'proc')); } function test_getDistinctName() { var varDB = new Blockly.Names('window,door'); assertEquals('Name distinct #1.', 'Foo_bar', varDB.getDistinctName('Foo.bar', 'var')); assertEquals('Name distinct #2.', 'Foo_bar2', varDB.getDistinctName('Foo.bar', 'var')); assertEquals('Name distinct #3.', 'Foo_bar3', varDB.getDistinctName('Foo.bar', 'proc')); varDB.reset(); assertEquals('Name distinct #4.', 'Foo_bar', varDB.getDistinctName('Foo.bar', 'var')); } function test_nameEquals() { assertTrue('Name equals #1.', Blockly.Names.equals('Foo.bar', 'Foo.bar')); assertFalse('Name equals #2.', Blockly.Names.equals('Foo.bar', 'Foo_bar')); assertTrue('Name equals #3.', Blockly.Names.equals('Foo.bar', 'FOO.BAR')); } ================================================ FILE: extern/blockly/tests/playground.html ================================================ Blockly Playground

Blockly Playground

Show - Hide

 
   


Stress test with an

================================================ FILE: extern/face-landmarker.worker.js ================================================ self.importScripts(`${self.location.pathname}/../human/human.js`); const config = { backend: 'humangl', modelBasePath: './human/models/', cacheModels: true, validateModels: true, wasmPlatformFetch: false, debug: false, async: true, warmup: 'full', cacheSensitivity: 0.7, skipAllowed: false, deallocate: false, flags: {}, softwareKernels: false, face: { enabled: true, detector: { modelPath: 'blazeface.json', rotation: false, maxDetected: 4, minConfidence: 0.2, return: true, }, mesh: { enabled: true, modelPath: 'facemesh.json', keepInvalid: false, }, attention: { enabled: false, modelPath: 'facemesh-attention.json', }, iris: { enabled: false, modelPath: 'iris.json', }, emotion: { enabled: true, minConfidence: 0.1, skipFrames: 99, skipTime: 1500, modelPath: 'emotion.json', }, description: { enabled: true, modelPath: 'faceres.json', skipFrames: 99, skipTime: 3000, minConfidence: 0.1, }, antispoof: { enabled: false, skipFrames: 99, skipTime: 4000, modelPath: 'antispoof.json', }, liveness: { enabled: false, skipFrames: 99, skipTime: 4000, modelPath: 'liveness.json', }, }, filter: { enabled: false }, object: { enabled: false }, gesture: { enabled: false }, hand: { enabled: false }, body: { enabled: false }, segmentation: { enabled: false }, }; const drawOption = { alpha: 1, color: '#ffffff', drawPoints: true, drawPolygons: true, drawAttention: false, drawBoxes: false, drawGaze: false, drawGestures: false, drawLabels: false, }; let flipState; let isRun = false; let isFirstIdle = false; self.onmessage = async ({ data }) => { if (data.action === 'face_landmarker_init') { initializeFaceLandmarker(data); } else if (data.action === 'face_landmarker_restart') { isRun = true; self.postMessage({ action: 'run_start_face_landmarker' }); } else if (data.action === 'face_landmarker_change_option') { changeFaceLandmarkerOption(data.option); } else if (data.action === 'face_landmarker') { flipState = data.flipState; predictFaceLandmarker(data.imageBitmap); } else if (data.action === 'clear_face_landmarker') { clearPredictFaceLandmarker(); } }; let human; let faceLang; let offCanvas; let workerContext; let drawingUtils; let faceLandmarker; let isPrevFaceLandmarker = false; let countDetectedFace = 0; let isDrawDetectedFaceLandmarker = false; const initializeFaceLandmarker = async (data) => { const { canvas, option, isSafari, lang } = data; faceLang = lang.face; isDrawDetectedFaceLandmarker = option.isDrawDetectedFaceLandmarker; offCanvas = canvas; workerContext = canvas.getContext('2d'); workerContext.font = '20px Arial'; if (isSafari) { config.backend = 'wasm'; } if (!human) human = new Human.default(config); await human.load(); // optional as models would be loaded on-demand first time they are required await human.warmup(); // optional as model warmup is performed on-demand first time its executed isRun = true; self.postMessage({ action: 'run_start_face_landmarker' }); self.postMessage({ action: 'next_face_landmarker' }); }; const changeFaceLandmarkerOption = (option) => { isDrawDetectedFaceLandmarker = option.isDrawDetectedFaceLandmarker; }; const contextFlip = (context, axis) => { if (flipState === 0) { context.scale(-1, 1); return { x: -axis[0] * 640, y: axis[1] * 360 - 20, }; } else if (flipState === 1) { context.scale(1, 1); return { x: axis[0] * 640, y: axis[1] * 360 - 20, }; } else if (flipState === 2) { context.scale(-1, -1); return { x: -axis[0] * 640, y: -axis[1] * 360 + 20, }; } else if (flipState === 3) { context.scale(1, -1); return { x: axis[0] * 640, y: -axis[1] * 360 + 20, }; } }; let lastDetect; const predictFaceLandmarker = async (imageBitmap) => { try { if (!workerContext || !human) { return; } if (!isFirstIdle && human.state === 'idle') { isFirstIdle = true; } if (!isRun || !isFirstIdle) { return; } lastDetect = human.detect(imageBitmap); const results = await lastDetect; workerContext.save(); workerContext.clearRect(0, 0, 640, 360); const { face } = results; self.postMessage({ action: 'face_landmarker_data', faceLandmarkerResult: { face }, }); if (face.length) { if (!isPrevFaceLandmarker) { isPrevFaceLandmarker = true; self.postMessage({ action: 'start_face_landmarker' }); } if (face.length !== countDetectedFace) { countDetectedFace = face.length; self.postMessage({ action: 'count_detected_face_landmarker', count: countDetectedFace, }); } if (!isDrawDetectedFaceLandmarker) { return; } face.forEach((item, i) => { const { meshRaw } = item; const mark297 = meshRaw[297]; const { x, y } = contextFlip(workerContext, mark297); workerContext.fillStyle = '#FF0000'; workerContext.fillText(`${i + 1}-${faceLang}`, x, y); contextFlip(workerContext, mark297); }); await human.draw.face(offCanvas, face, drawOption); } else if (isPrevFaceLandmarker) { isPrevFaceLandmarker = false; countDetectedFace = 0; self.postMessage({ action: 'stop_face_landmarker' }); } } catch (e) { console.error(e); } finally { workerContext.restore(); requestAnimationFrame(() => { self.postMessage({ action: 'next_face_landmarker' }); }); } }; const clearPredictFaceLandmarker = async () => { isRun = false; await lastDetect; requestAnimationFrame(() => { self.postMessage({ action: 'run_stop_face_landmarker' }); isPrevFaceLandmarker = false; countDetectedFace = 0; workerContext.clearRect(0, 0, 640, 360); }); }; ================================================ FILE: extern/face-landmarker2.worker.js ================================================ self.importScripts(`${self.location.pathname}/../vision_bundle.js`); self.onmessage = async ({ data }) => { if (data.action === 'face_landmarker_init') { initializeFaceLandmarker(data); } else if (data.action === 'face_landmarker_change_option') { changeFaceLandmarkerOption(data.option); } else if (data.action === 'face_landmarker') { predictFaceLandmarker(data.imageBitmap); } else if (data.action === 'clear_face_landmarker') { clearPredictFaceLandmarker(); } }; let workerContext; let drawingUtils; let faceLandmarker; let isPrevFaceLandmarker = false; let countDetectedFace = 0; let isDrawDetectedFaceLandmarker = false; const initializeFaceLandmarker = async (data) => { const { canvas, option } = data; isDrawDetectedFaceLandmarker = option.isDrawDetectedFaceLandmarker; workerContext = canvas.getContext('2d'); workerContext.font = '20px Arial'; drawingUtils = new DrawingUtils(workerContext); const vision = await FilesetResolver.forVisionTasks(`${self.location.pathname}/../wasm`); faceLandmarker = await FaceLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: `${self.location.pathname}/../model/face_landmarker.task`, delegate: 'GPU', }, runningMode: 'VIDEO', numFaces: 4, }); self.postMessage({ action: 'next_face_landmarker' }); }; const changeFaceLandmarkerOption = (option) => { isDrawDetectedFaceLandmarker = option.isDrawDetectedFaceLandmarker; }; const predictFaceLandmarker = async (imageBitmap) => { try { if (!workerContext || !faceLandmarker) { return; } const results = await faceLandmarker.detectForVideo(imageBitmap, Date.now()); workerContext.save(); workerContext.clearRect(0, 0, 640, 360); const { faceLandmarks } = results; self.postMessage({ action: 'face_landmarker_data', faceLandmarkerResult: results, }); if (faceLandmarks.length) { if (!isPrevFaceLandmarker) { isPrevFaceLandmarker = true; self.postMessage({ action: 'start_face_landmarker' }); } if (faceLandmarks.length !== countDetectedFace) { countDetectedFace = faceLandmarks.length; self.postMessage({ action: 'count_detected_face_landmarker', count: countDetectedFace, }); } if (!isDrawDetectedFaceLandmarker) { return; } faceLandmarks.forEach((landmark, i) => { drawingUtils.drawConnectors(landmark, FaceLandmarker.FACE_LANDMARKS_TESSELATION, { color: '#C0C0C070', lineWidth: 1, }); drawingUtils.drawConnectors(landmark, FaceLandmarker.FACE_LANDMARKS_RIGHT_EYE, { color: '#FF3030', }); drawingUtils.drawConnectors(landmark, FaceLandmarker.FACE_LANDMARKS_RIGHT_EYEBROW, { color: '#FF3030', }); drawingUtils.drawConnectors(landmark, FaceLandmarker.FACE_LANDMARKS_LEFT_EYE, { color: '#30FF30', }); drawingUtils.drawConnectors(landmark, FaceLandmarker.FACE_LANDMARKS_LEFT_EYEBROW, { color: '#30FF30', }); drawingUtils.drawConnectors(landmark, FaceLandmarker.FACE_LANDMARKS_FACE_OVAL, { color: '#E0E0E0', }); drawingUtils.drawConnectors(landmark, FaceLandmarker.FACE_LANDMARKS_LIPS, { color: '#E0E0E0', }); drawingUtils.drawConnectors(landmark, FaceLandmarker.FACE_LANDMARKS_RIGHT_IRIS, { color: '#FF3030', }); drawingUtils.drawConnectors(landmark, FaceLandmarker.FACE_LANDMARKS_LEFT_IRIS, { color: '#30FF30', }); }); } else if (isPrevFaceLandmarker) { isPrevFaceLandmarker = false; countDetectedFace = 0; self.postMessage({ action: 'stop_face_landmarker' }); } } catch (e) { console.error(e); } finally { workerContext.restore(); requestAnimationFrame(() => { self.postMessage({ action: 'next_face_landmarker' }); }); } }; const clearPredictFaceLandmarker = () => { console.log('clearPredictFaceLandmarker'); isPrevFaceLandmarker = false; workerContext.clearRect(0, 0, 640, 360); }; ================================================ FILE: extern/gesture-recognition.worker.js ================================================ self.importScripts(`${self.location.pathname}/../vision_bundle.js`); let flipState; let isRun = false; self.onmessage = async ({ data }) => { if (data.action === 'gesture_recognizer_init') { initializeGesture(data); } else if (data.action === 'gesture_recognizer_restart') { isRun = true; } else if (data.action === 'gesture_recognizer_change_option') { changeGestureOption(data.option); } else if (data.action === 'gesture_recognizer') { flipState = data.flipState || 0; predictGesture(data.imageBitmap); } else if (data.action === 'clear_gesture_recognizer') { clearPredictGesture(); } }; let leftHand; let rightHand; let workerContext; let drawingUtils; let gestureRecognizer; let isPrevHandDetected = false; let countDetectedHand = 0; let isDrawDetectedHand = false; const initializeGesture = async (data) => { const { canvas, lang, option } = data; isRun = true; leftHand = lang.leftHand; rightHand = lang.rightHand; isDrawDetectedHand = option.isDrawDetectedHand; workerContext = canvas.getContext('2d'); workerContext.font = '20px Arial'; drawingUtils = new DrawingUtils(workerContext); const vision = await FilesetResolver.forVisionTasks(`${self.location.pathname}/../wasm`); gestureRecognizer = await GestureRecognizer.createFromOptions(vision, { baseOptions: { modelAssetPath: `${self.location.pathname}/../model/gesture_recognizer.task`, delegate: 'GPU', }, runningMode: 'VIDEO', numHands: 2, }); self.postMessage({ action: 'next_gesture_recognizer' }); }; const changeGestureOption = (option) => { isDrawDetectedHand = option.isDrawDetectedHand; }; const YX = (a) => { return Math.max(1, Math.min(10, 10 * (1 - (a - -0.15) / 0.25) + (1 - (0.1 - a) / 0.25))); }; const contextFlip = (context, axis) => { if (flipState === 0) { context.scale(-1, 1); return { x: -axis.x * 640, y: axis.y * 360 - 20, }; } else if (flipState === 1) { context.scale(1, 1); return { x: axis.x * 640, y: axis.y * 360 - 20, }; } else if (flipState === 2) { context.scale(-1, -1); return { x: -axis.x * 640, y: -axis.y * 360 + 20, }; } else if (flipState === 3) { context.scale(1, -1); return { x: axis.x * 640, y: -axis.y * 360 + 20, }; } }; const predictGesture = (imageBitmap) => { try { if (!workerContext || !gestureRecognizer || !isRun) { return; } const results = gestureRecognizer.recognizeForVideo(imageBitmap, Date.now()); workerContext.save(); workerContext.clearRect(0, 0, 640, 360); const { landmarks, handednesses } = results; self.postMessage({ action: 'gesture_recognizer_data', gestureRecognizerResult: results, }); if (landmarks.length) { if (!isPrevHandDetected) { isPrevHandDetected = true; self.postMessage({ action: 'start_gesture_recognizer' }); } if (landmarks.length !== countDetectedHand) { countDetectedHand = landmarks.length; self.postMessage({ action: 'count_detected_hand_gesture_recognizer', count: countDetectedHand, }); } if (!isDrawDetectedHand) { return; } landmarks.forEach((landmark, i) => { let connectColor; let landmarkColor; const [handedness] = handednesses[i]; const mark12 = landmark[12]; const { x, y } = contextFlip(workerContext, mark12); if (handedness.categoryName === 'Left') { workerContext.fillStyle = '#FF0000'; workerContext.fillText(`${i + 1}-${rightHand}`, x, y); connectColor = '#FF0000'; landmarkColor = '#00FF00'; } else { workerContext.fillStyle = '#00FF00'; workerContext.fillText(`${i + 1}-${leftHand}`, x, y); connectColor = '#00FF00'; landmarkColor = '#FF0000'; } contextFlip(workerContext, mark12); drawingUtils.drawConnectors(landmark, GestureRecognizer.HAND_CONNECTIONS, { color: connectColor, lineWidth: 4, }); drawingUtils.drawLandmarks(landmark, { color: connectColor, lineWidth: 4, fillColor: landmarkColor, radius: (e) => { return YX(e.from?.z || 0); }, }); }); } else if (isPrevHandDetected) { isPrevHandDetected = false; countDetectedHand = 0; self.postMessage({ action: 'stop_gesture_recognizer' }); } } catch (e) { console.error(e); } finally { workerContext.restore(); requestAnimationFrame(() => { self.postMessage({ action: 'next_gesture_recognizer' }); }); } }; const clearPredictGesture = () => { console.log('clearPredictGesture'); isRun = false; isPrevHandDetected = false; countDetectedHand = 0; workerContext.clearRect(0, 0, 640, 360); }; ================================================ FILE: extern/human/human.js ================================================ /* Human homepage: author: ' */ "use strict";var Human=(()=>{var sc=Object.defineProperty;var MI=Object.getOwnPropertyDescriptor;var $I=Object.getOwnPropertyNames;var _I=Object.prototype.hasOwnProperty;var PI=(e,t,a)=>t in e?sc(e,t,{enumerable:!0,configurable:!0,writable:!0,value:a}):e[t]=a;var Cs=(e=>typeof require!="undefined"?require:typeof Proxy!="undefined"?new Proxy(e,{get:(t,a)=>(typeof require!="undefined"?require:t)[a]}):e)(function(e){if(typeof require!="undefined")return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')});var hr=(e,t)=>{for(var a in t)sc(e,a,{get:t[a],enumerable:!0})},FI=(e,t,a,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of $I(t))!_I.call(e,r)&&r!==a&&sc(e,r,{get:()=>t[r],enumerable:!(n=MI(t,r))||n.enumerable});return e};var OI=e=>FI(sc({},"__esModule",{value:!0}),e);var ue=(e,t,a)=>(PI(e,typeof t!="symbol"?t+"":t,a),a),O5=(e,t,a)=>{if(!t.has(e))throw TypeError("Cannot "+a)};var Ga=(e,t,a)=>(O5(e,t,"read from private field"),a?a.call(e):t.get(e)),Gn=(e,t,a)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,a)},fr=(e,t,a,n)=>(O5(e,t,"write to private field"),n?n.call(e,a):t.set(e,a),a);var w0e={};hr(w0e,{Env:()=>Ap,Human:()=>A5,default:()=>A5,defaults:()=>Io,draw:()=>s0,empty:()=>or,env:()=>ne,match:()=>$0,models:()=>x5});var Ue={};hr(Ue,{Abs:()=>wl,Acos:()=>kl,Acosh:()=>Il,AdadeltaOptimizer:()=>Th,AdagradOptimizer:()=>Ch,AdamOptimizer:()=>Nh,AdamaxOptimizer:()=>Eh,Add:()=>ts,AddN:()=>Ks,All:()=>Zs,Any:()=>Ys,ArgMax:()=>Js,ArgMin:()=>kd,Asin:()=>Sl,Asinh:()=>Tl,Atan:()=>Cl,Atan2:()=>El,Atanh:()=>Nl,AvgPool:()=>Qs,AvgPool3D:()=>Hc,AvgPool3DGrad:()=>G1,AvgPoolGrad:()=>U1,BackendWasm:()=>I8,BatchMatMul:()=>ei,BatchToSpaceND:()=>Rl,Bincount:()=>Id,BroadcastArgs:()=>jc,BroadcastTo:()=>TS,Cast:()=>ti,Ceil:()=>ai,ClipByValue:()=>as,Complex:()=>Sd,ComplexAbs:()=>qc,Concat:()=>Ml,Conv2D:()=>ni,Conv2DBackpropFilter:()=>Xc,Conv2DBackpropInput:()=>ri,Conv3D:()=>Kc,Conv3DBackpropFilterV2:()=>H1,Conv3DBackpropInputV2:()=>Zc,Cos:()=>si,Cosh:()=>ii,CropAndResize:()=>ui,Cumprod:()=>oi,Cumsum:()=>li,DataStorage:()=>vd,DenseBincount:()=>Td,DepthToSpace:()=>di,DepthwiseConv2dNative:()=>pi,DepthwiseConv2dNativeBackpropFilter:()=>Yc,DepthwiseConv2dNativeBackpropInput:()=>Jc,Diag:()=>Qc,Dilation2D:()=>eh,Dilation2DBackpropFilter:()=>Gm,Dilation2DBackpropInput:()=>Um,ENV:()=>W1,Einsum:()=>Cd,Elu:()=>hi,EluGrad:()=>j1,Environment:()=>mA,Equal:()=>fi,Erf:()=>$l,Exp:()=>mi,ExpandDims:()=>_l,Expm1:()=>Pl,FFT:()=>Nd,Fill:()=>Fl,FlipLeftRight:()=>gi,Floor:()=>xi,FloorDiv:()=>Ai,FromPixels:()=>rd,FusedBatchNorm:()=>yi,FusedConv2D:()=>qr,FusedDepthwiseConv2D:()=>Xr,GPGPUContext:()=>il,GatherNd:()=>bi,GatherV2:()=>Ol,GraphModel:()=>op,Greater:()=>vi,GreaterEqual:()=>wi,IFFT:()=>Ed,Identity:()=>ki,Imag:()=>Rd,IsFinite:()=>Dl,IsInf:()=>zl,IsNan:()=>Ii,KernelBackend:()=>bl,LRN:()=>ah,LRNGrad:()=>q1,LeakyRelu:()=>Si,Less:()=>Ti,LessEqual:()=>Ci,LinSpace:()=>th,Log:()=>Ni,Log1p:()=>Ll,LogSoftmax:()=>CS,LogicalAnd:()=>Ei,LogicalNot:()=>Ri,LogicalOr:()=>Bl,LogicalXor:()=>xA,LowerBound:()=>NS,MathBackendCPU:()=>$h,MathBackendWebGL:()=>fu,Max:()=>Mi,MaxPool:()=>_i,MaxPool3D:()=>nh,MaxPool3DGrad:()=>K1,MaxPoolGrad:()=>X1,MaxPoolWithArgmax:()=>rh,Maximum:()=>$i,Mean:()=>Pi,Min:()=>Fi,Minimum:()=>Oi,MirrorPad:()=>Di,Mod:()=>Wl,MomentumOptimizer:()=>Rh,Multinomial:()=>sh,Multiply:()=>zi,Neg:()=>Vl,NonMaxSuppressionV3:()=>Bi,NonMaxSuppressionV4:()=>Ul,NonMaxSuppressionV5:()=>Wi,NotEqual:()=>Li,OP_SCOPE_SUFFIX:()=>e2,OneHot:()=>Vi,OnesLike:()=>Gl,Optimizer:()=>is,OptimizerConstructors:()=>Or,Pack:()=>Hl,PadV2:()=>Ui,Pool:()=>ES,Pow:()=>Gi,Prelu:()=>Hi,Prod:()=>ji,RMSPropOptimizer:()=>Mh,RaggedGather:()=>ih,RaggedRange:()=>oh,RaggedTensorToTensor:()=>lh,Range:()=>jl,Rank:()=>qm,Real:()=>Md,RealDiv:()=>ci,Reciprocal:()=>qi,Reduction:()=>ya,Relu:()=>Xi,Relu6:()=>Yi,Reshape:()=>ql,ResizeBilinear:()=>Zi,ResizeBilinearGrad:()=>Y1,ResizeNearestNeighbor:()=>Ki,ResizeNearestNeighborGrad:()=>Z1,Reverse:()=>Ji,RotateWithOffset:()=>mo,Round:()=>Xl,Rsqrt:()=>Qi,SGDOptimizer:()=>ip,ScatterNd:()=>eo,SearchSorted:()=>$d,Select:()=>Kl,Selu:()=>_d,Sigmoid:()=>ao,Sign:()=>Pd,Sin:()=>to,Sinh:()=>Yl,Slice:()=>Zl,Softmax:()=>so,Softplus:()=>Fd,SpaceToBatchND:()=>Jl,SparseFillEmptyRows:()=>Od,SparseReshape:()=>eu,SparseSegmentMean:()=>Dd,SparseSegmentSum:()=>zd,SparseToDense:()=>Ld,SplitV:()=>Ql,Sqrt:()=>no,Square:()=>Bd,SquaredDifference:()=>io,Step:()=>fo,StridedSlice:()=>oo,StringNGrams:()=>tu,StringSplit:()=>Wd,StringToHashBucketFast:()=>Vd,Sub:()=>lo,Sum:()=>ro,Tan:()=>uo,Tanh:()=>po,Tensor:()=>pt,TensorBuffer:()=>jt,Tile:()=>ns,TopK:()=>co,Transform:()=>ho,Transpose:()=>Ar,Unique:()=>uh,Unpack:()=>au,UnsortedSegmentSum:()=>dh,UpperBound:()=>RS,Variable:()=>od,WebGPUBackend:()=>Vh,ZerosLike:()=>nu,_FusedMatMul:()=>jr,abs:()=>qa,acos:()=>oy,acosh:()=>ly,add:()=>be,addN:()=>ch,all:()=>uy,any:()=>dy,argMax:()=>ar,argMin:()=>py,asin:()=>cy,asinh:()=>hy,atan:()=>fy,atan2:()=>my,atanh:()=>gy,avgPool:()=>b2,avgPool3d:()=>by,backend:()=>tr,backend_util:()=>T,basicLSTMCell:()=>vy,batchNorm:()=>Qd,batchNorm2d:()=>wy,batchNorm3d:()=>ky,batchNorm4d:()=>Iy,batchToSpaceND:()=>v2,bincount:()=>w2,booleanMaskAsync:()=>a4,broadcastArgs:()=>Sy,broadcastTo:()=>sl,broadcast_util:()=>xo,browser:()=>wr,buffer:()=>Me,cast:()=>He,ceil:()=>Ty,clipByValue:()=>Cy,clone:()=>wa,complex:()=>br,concat:()=>at,concat1d:()=>Ny,concat2d:()=>ru,concat3d:()=>Ey,concat4d:()=>Ry,conv1d:()=>My,conv2d:()=>ep,conv2dTranspose:()=>_y,conv3d:()=>Py,conv3dTranspose:()=>Fy,copyRegisteredKernels:()=>FS,cos:()=>Oy,cosh:()=>Dy,cosineWindow:()=>vh,cumprod:()=>zy,cumsum:()=>Ly,customGrad:()=>Qn,denseBincount:()=>By,deprecationWarn:()=>l2,depthToSpace:()=>Wy,depthwiseConv2d:()=>hh,deregisterOp:()=>yP,device_util:()=>jd,diag:()=>Vy,dilation2d:()=>Uy,disableDeprecationWarnings:()=>uC,dispose:()=>Y,disposeVariables:()=>dC,div:()=>me,divNoNan:()=>Gy,dot:()=>Hy,dropout:()=>o4,einsum:()=>jy,elu:()=>I2,enableDebugMode:()=>lC,enableProdMode:()=>o2,enclosingPowerOfTwo:()=>J2,engine:()=>kt,env:()=>W,equal:()=>k2,erf:()=>qy,euclideanNorm:()=>Zy,exp:()=>Zr,expandDims:()=>Gt,expm1:()=>Yy,eye:()=>T2,fft:()=>yh,fill:()=>nr,findBackend:()=>u2,findBackendFactory:()=>mC,floor:()=>C2,floorDiv:()=>Yd,forceHalfFloat:()=>G6,fused:()=>Q2,gather:()=>N2,gatherND:()=>i4,gather_util:()=>c2,getBackend:()=>ia,getGradient:()=>Hm,getKernel:()=>Sc,getKernelsForBackend:()=>Zn,getThreadsCount:()=>Ene,gpgpu_util:()=>w6,grad:()=>UE,grads:()=>GE,greater:()=>np,greaterEqual:()=>E2,ifft:()=>hd,imag:()=>Zd,image:()=>ge,inTopKAsync:()=>l4,io:()=>jn,irfft:()=>X2,isFinite:()=>Jy,isInf:()=>Qy,isNaN:()=>eb,keep:()=>On,kernel_impls:()=>Tn,leakyRelu:()=>R2,less:()=>tb,lessEqual:()=>fh,linalg:()=>g4,linspace:()=>ab,loadGraphModel:()=>r3,loadGraphModelSync:()=>kF,localResponseNormalization:()=>nb,log:()=>cl,log1p:()=>M2,logSigmoid:()=>sb,logSoftmax:()=>ib,logSumExp:()=>_2,logicalAnd:()=>pd,logicalNot:()=>P2,logicalOr:()=>F2,logicalXor:()=>ob,losses:()=>x4,lowerBound:()=>lb,matMul:()=>st,math:()=>UA,max:()=>pa,maxPool:()=>O2,maxPool3d:()=>ub,maxPoolWithArgmax:()=>db,maximum:()=>D2,mean:()=>cd,memory:()=>pC,meshgrid:()=>pb,min:()=>Kr,minimum:()=>z2,mirrorPad:()=>cb,mod:()=>su,moments:()=>hb,movingAverage:()=>n4,mul:()=>ae,multiRNNCell:()=>fb,multinomial:()=>mb,neg:()=>Xn,nextFrame:()=>b4,norm:()=>ap,notEqual:()=>L2,oneHot:()=>Nc,ones:()=>Wr,onesLike:()=>gb,op:()=>D,outerProduct:()=>xb,pad:()=>rr,pad1d:()=>Ab,pad2d:()=>yb,pad3d:()=>bb,pad4d:()=>vb,pool:()=>wb,pow:()=>pl,prelu:()=>W2,print:()=>r2,prod:()=>kb,profile:()=>cC,raggedGather:()=>Ib,raggedRange:()=>Sb,raggedTensorToTensor:()=>Tb,rand:()=>Cb,randomGamma:()=>Nb,randomNormal:()=>G2,randomStandardNormal:()=>Eb,randomUniform:()=>H2,range:()=>hl,ready:()=>Kd,real:()=>dl,reciprocal:()=>Rb,registerBackend:()=>go,registerGradient:()=>$S,registerKernel:()=>mn,registerOp:()=>AP,relu:()=>rp,relu6:()=>j2,removeBackend:()=>fC,reshape:()=>J,reverse:()=>Yr,reverse1d:()=>Mb,reverse2d:()=>$b,reverse3d:()=>_b,reverse4d:()=>Pb,rfft:()=>bh,round:()=>q2,rsqrt:()=>Fb,scalar:()=>Fe,scatterND:()=>r4,scatter_util:()=>h2,searchSorted:()=>gh,selu:()=>Ob,separableConv2d:()=>Db,serialization:()=>ay,setBackend:()=>Xd,setPlatform:()=>gC,setThreadsCount:()=>Nne,setWasmPath:()=>Cne,setWasmPaths:()=>Wh,setWebGLContext:()=>Fh,setdiff1dAsync:()=>zb,shared:()=>_h,sigmoid:()=>Da,sign:()=>Lb,signal:()=>m4,sin:()=>Bb,sinh:()=>Wb,slice:()=>Pe,slice1d:()=>Vb,slice2d:()=>Ub,slice3d:()=>sp,slice4d:()=>xh,slice_util:()=>It,softmax:()=>Ah,softplus:()=>$2,spaceToBatchND:()=>B2,sparse:()=>A4,sparseToDense:()=>s4,spectral:()=>f4,split:()=>ka,sqrt:()=>Jn,square:()=>In,squaredDifference:()=>K2,squeeze:()=>_e,stack:()=>sa,step:()=>Z2,stridedSlice:()=>Gb,string:()=>y4,sub:()=>fe,sum:()=>tt,sumOutType:()=>Hd,tan:()=>Hb,tanh:()=>Rc,tensor:()=>Be,tensor1d:()=>Ht,tensor2d:()=>Kn,tensor3d:()=>p2,tensor4d:()=>jb,tensor5d:()=>qb,tensor6d:()=>Xb,tensor_util:()=>vA,test_util:()=>ry,tidy:()=>$e,tile:()=>Gr,time:()=>hC,topk:()=>Kb,train:()=>m_,transpose:()=>Ws,truncatedNormal:()=>Zb,unique:()=>Yb,unregisterGradient:()=>PS,unregisterKernel:()=>_S,unsortedSegmentSum:()=>Jb,unstack:()=>Ta,upcastType:()=>ca,upperBound:()=>Qb,util:()=>v,valueAndGrad:()=>HE,valueAndGrads:()=>jE,variable:()=>e4,variableGrads:()=>rb,version:()=>xp,version_converter:()=>SF,version_core:()=>A2,version_cpu:()=>$O,version_wasm:()=>Rne,version_webgl:()=>AG,webgl:()=>yG,webgl_util:()=>j7,webgpu_util:()=>C8,where:()=>Vs,whereAsync:()=>Y2,zeros:()=>fn,zerosLike:()=>Ka});var DI=Object.create,z1=Object.defineProperty,zI=Object.getOwnPropertyDescriptor,LI=Object.getOwnPropertyNames,BI=Object.getPrototypeOf,WI=Object.prototype.hasOwnProperty,aA=(e=>typeof Cs!="undefined"?Cs:typeof Proxy!="undefined"?new Proxy(e,{get:(t,a)=>(typeof Cs!="undefined"?Cs:t)[a]}):e)(function(e){if(typeof Cs!="undefined")return Cs.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')}),qt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Xe=(e,t)=>{for(var a in t)z1(e,a,{get:t[a],enumerable:!0})},VI=(e,t,a,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of LI(t))!WI.call(e,r)&&r!==a&&z1(e,r,{get:()=>t[r],enumerable:!(n=zI(t,r))||n.enumerable});return e},yl=(e,t,a)=>(a=e!=null?DI(BI(e)):{},VI(t||!e||!e.__esModule?z1(a,"default",{value:e,enumerable:!0}):a,e)),UI=qt((e,t)=>{t.exports=n;var a=null;try{a=new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([0,97,115,109,1,0,0,0,1,13,2,96,0,1,127,96,4,127,127,127,127,1,127,3,7,6,0,1,1,1,1,1,6,6,1,127,1,65,0,11,7,50,6,3,109,117,108,0,1,5,100,105,118,95,115,0,2,5,100,105,118,95,117,0,3,5,114,101,109,95,115,0,4,5,114,101,109,95,117,0,5,8,103,101,116,95,104,105,103,104,0,0,10,191,1,6,4,0,35,0,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,126,34,4,66,32,135,167,36,0,32,4,167,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,127,34,4,66,32,135,167,36,0,32,4,167,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,128,34,4,66,32,135,167,36,0,32,4,167,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,129,34,4,66,32,135,167,36,0,32,4,167,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,130,34,4,66,32,135,167,36,0,32,4,167,11])),{}).exports}catch(I){}function n(I,N,O){this.low=I|0,this.high=N|0,this.unsigned=!!O}n.prototype.__isLong__,Object.defineProperty(n.prototype,"__isLong__",{value:!0});function r(I){return(I&&I.__isLong__)===!0}n.isLong=r;var s={},i={};function o(I,N){var O,L,B;return N?(I>>>=0,(B=0<=I&&I<256)&&(L=i[I],L)?L:(O=u(I,(I|0)<0?-1:0,!0),B&&(i[I]=O),O)):(I|=0,(B=-128<=I&&I<128)&&(L=s[I],L)?L:(O=u(I,I<0?-1:0,!1),B&&(s[I]=O),O))}n.fromInt=o;function l(I,N){if(isNaN(I))return N?b:y;if(N){if(I<0)return b;if(I>=g)return _}else{if(I<=-x)return $;if(I+1>=x)return E}return I<0?l(-I,N).neg():u(I%m|0,I/m|0,N)}n.fromNumber=l;function u(I,N,O){return new n(I,N,O)}n.fromBits=u;var p=Math.pow;function c(I,N,O){if(I.length===0)throw Error("empty string");if(I==="NaN"||I==="Infinity"||I==="+Infinity"||I==="-Infinity")return y;if(typeof N=="number"?(O=N,N=!1):N=!!N,O=O||10,O<2||360)throw Error("interior hyphen");if(L===0)return c(I.substring(1),N,O).neg();for(var B=l(p(O,8)),G=y,j=0;j>>0:this.low},M.toNumber=function(){return this.unsigned?(this.high>>>0)*m+(this.low>>>0):this.high*m+(this.low>>>0)},M.toString=function(I){if(I=I||10,I<2||36>>0,V=H.toString(I);if(G=U,G.isZero())return V+j;for(;V.length<6;)V="0"+V;j=""+V+j}},M.getHighBits=function(){return this.high},M.getHighBitsUnsigned=function(){return this.high>>>0},M.getLowBits=function(){return this.low},M.getLowBitsUnsigned=function(){return this.low>>>0},M.getNumBitsAbs=function(){if(this.isNegative())return this.eq($)?64:this.neg().getNumBitsAbs();for(var I=this.high!=0?this.high:this.low,N=31;N>0&&(I&1<=0},M.isOdd=function(){return(this.low&1)===1},M.isEven=function(){return(this.low&1)===0},M.equals=function(I){return r(I)||(I=d(I)),this.unsigned!==I.unsigned&&this.high>>>31===1&&I.high>>>31===1?!1:this.high===I.high&&this.low===I.low},M.eq=M.equals,M.notEquals=function(I){return!this.eq(I)},M.neq=M.notEquals,M.ne=M.notEquals,M.lessThan=function(I){return this.comp(I)<0},M.lt=M.lessThan,M.lessThanOrEqual=function(I){return this.comp(I)<=0},M.lte=M.lessThanOrEqual,M.le=M.lessThanOrEqual,M.greaterThan=function(I){return this.comp(I)>0},M.gt=M.greaterThan,M.greaterThanOrEqual=function(I){return this.comp(I)>=0},M.gte=M.greaterThanOrEqual,M.ge=M.greaterThanOrEqual,M.compare=function(I){if(r(I)||(I=d(I)),this.eq(I))return 0;var N=this.isNegative(),O=I.isNegative();return N&&!O?-1:!N&&O?1:this.unsigned?I.high>>>0>this.high>>>0||I.high===this.high&&I.low>>>0>this.low>>>0?-1:1:this.sub(I).isNegative()?-1:1},M.comp=M.compare,M.negate=function(){return!this.unsigned&&this.eq($)?$:this.not().add(w)},M.neg=M.negate,M.add=function(I){r(I)||(I=d(I));var N=this.high>>>16,O=this.high&65535,L=this.low>>>16,B=this.low&65535,G=I.high>>>16,j=I.high&65535,U=I.low>>>16,H=I.low&65535,V=0,Q=0,Z=0,re=0;return re+=B+H,Z+=re>>>16,re&=65535,Z+=L+U,Q+=Z>>>16,Z&=65535,Q+=O+j,V+=Q>>>16,Q&=65535,V+=N+G,V&=65535,u(Z<<16|re,V<<16|Q,this.unsigned)},M.subtract=function(I){return r(I)||(I=d(I)),this.add(I.neg())},M.sub=M.subtract,M.multiply=function(I){if(this.isZero())return y;if(r(I)||(I=d(I)),a){var N=a.mul(this.low,this.high,I.low,I.high);return u(N,a.get_high(),this.unsigned)}if(I.isZero())return y;if(this.eq($))return I.isOdd()?$:y;if(I.eq($))return this.isOdd()?$:y;if(this.isNegative())return I.isNegative()?this.neg().mul(I.neg()):this.neg().mul(I).neg();if(I.isNegative())return this.mul(I.neg()).neg();if(this.lt(A)&&I.lt(A))return l(this.toNumber()*I.toNumber(),this.unsigned);var O=this.high>>>16,L=this.high&65535,B=this.low>>>16,G=this.low&65535,j=I.high>>>16,U=I.high&65535,H=I.low>>>16,V=I.low&65535,Q=0,Z=0,re=0,ee=0;return ee+=G*V,re+=ee>>>16,ee&=65535,re+=B*V,Z+=re>>>16,re&=65535,re+=G*H,Z+=re>>>16,re&=65535,Z+=L*V,Q+=Z>>>16,Z&=65535,Z+=B*H,Q+=Z>>>16,Z&=65535,Z+=G*U,Q+=Z>>>16,Z&=65535,Q+=O*V+L*H+B*U+G*j,Q&=65535,u(re<<16|ee,Q<<16|Z,this.unsigned)},M.mul=M.multiply,M.divide=function(I){if(r(I)||(I=d(I)),I.isZero())throw Error("division by zero");if(a){if(!this.unsigned&&this.high===-2147483648&&I.low===-1&&I.high===-1)return this;var N=(this.unsigned?a.div_u:a.div_s)(this.low,this.high,I.low,I.high);return u(N,a.get_high(),this.unsigned)}if(this.isZero())return this.unsigned?b:y;var O,L,B;if(this.unsigned){if(I.unsigned||(I=I.toUnsigned()),I.gt(this))return b;if(I.gt(this.shru(1)))return S;B=b}else{if(this.eq($)){if(I.eq(w)||I.eq(C))return $;if(I.eq($))return w;var G=this.shr(1);return O=G.div(I).shl(1),O.eq(y)?I.isNegative()?w:C:(L=this.sub(I.mul(O)),B=O.add(L.div(I)),B)}else if(I.eq($))return this.unsigned?b:y;if(this.isNegative())return I.isNegative()?this.neg().div(I.neg()):this.neg().div(I).neg();if(I.isNegative())return this.div(I.neg()).neg();B=y}for(L=this;L.gte(I);){O=Math.max(1,Math.floor(L.toNumber()/I.toNumber()));for(var j=Math.ceil(Math.log(O)/Math.LN2),U=j<=48?1:p(2,j-48),H=l(O),V=H.mul(I);V.isNegative()||V.gt(L);)O-=U,H=l(O,this.unsigned),V=H.mul(I);H.isZero()&&(H=w),B=B.add(H),L=L.sub(V)}return B},M.div=M.divide,M.modulo=function(I){if(r(I)||(I=d(I)),a){var N=(this.unsigned?a.rem_u:a.rem_s)(this.low,this.high,I.low,I.high);return u(N,a.get_high(),this.unsigned)}return this.sub(this.div(I).mul(I))},M.mod=M.modulo,M.rem=M.modulo,M.not=function(){return u(~this.low,~this.high,this.unsigned)},M.and=function(I){return r(I)||(I=d(I)),u(this.low&I.low,this.high&I.high,this.unsigned)},M.or=function(I){return r(I)||(I=d(I)),u(this.low|I.low,this.high|I.high,this.unsigned)},M.xor=function(I){return r(I)||(I=d(I)),u(this.low^I.low,this.high^I.high,this.unsigned)},M.shiftLeft=function(I){return r(I)&&(I=I.toInt()),(I&=63)===0?this:I<32?u(this.low<>>32-I,this.unsigned):u(0,this.low<>>I|this.high<<32-I,this.high>>I,this.unsigned):u(this.high>>I-32,this.high>=0?0:-1,this.unsigned)},M.shr=M.shiftRight,M.shiftRightUnsigned=function(I){if(r(I)&&(I=I.toInt()),I&=63,I===0)return this;var N=this.high;if(I<32){var O=this.low;return u(O>>>I|N<<32-I,N>>>I,this.unsigned)}else return I===32?u(N,0,this.unsigned):u(N>>>I-32,0,this.unsigned)},M.shru=M.shiftRightUnsigned,M.shr_u=M.shiftRightUnsigned,M.toSigned=function(){return this.unsigned?u(this.low,this.high,!1):this},M.toUnsigned=function(){return this.unsigned?this:u(this.low,this.high,!0)},M.toBytes=function(I){return I?this.toBytesLE():this.toBytesBE()},M.toBytesLE=function(){var I=this.high,N=this.low;return[N&255,N>>>8&255,N>>>16&255,N>>>24,I&255,I>>>8&255,I>>>16&255,I>>>24]},M.toBytesBE=function(){var I=this.high,N=this.low;return[I>>>24,I>>>16&255,I>>>8&255,I&255,N>>>24,N>>>16&255,N>>>8&255,N&255]},n.fromBytes=function(I,N,O){return O?n.fromBytesLE(I,N):n.fromBytesBE(I,N)},n.fromBytesLE=function(I,N){return new n(I[0]|I[1]<<8|I[2]<<16|I[3]<<24,I[4]|I[5]<<8|I[6]<<16|I[7]<<24,N)},n.fromBytesBE=function(I,N){return new n(I[4]<<24|I[5]<<16|I[6]<<8|I[7],I[0]<<24|I[1]<<16|I[2]<<8|I[3],N)}}),GI=qt(()=>{}),HI=qt(()=>{}),jI=qt((e,t)=>{(function(a,n,r){function s(u){var p=this,c=l();p.next=function(){var d=2091639*p.s0+p.c*23283064365386963e-26;return p.s0=p.s1,p.s1=p.s2,p.s2=d-(p.c=d|0)},p.c=1,p.s0=c(" "),p.s1=c(" "),p.s2=c(" "),p.s0-=c(u),p.s0<0&&(p.s0+=1),p.s1-=c(u),p.s1<0&&(p.s1+=1),p.s2-=c(u),p.s2<0&&(p.s2+=1),c=null}function i(u,p){return p.c=u.c,p.s0=u.s0,p.s1=u.s1,p.s2=u.s2,p}function o(u,p){var c=new s(u),d=p&&p.state,h=c.next;return h.int32=function(){return c.next()*4294967296|0},h.double=function(){return h()+(h()*2097152|0)*11102230246251565e-32},h.quick=h,d&&(typeof d=="object"&&i(d,c),h.state=function(){return i(c,{})}),h}function l(){var u=4022871197,p=function(c){c=String(c);for(var d=0;d>>0,h-=u,h*=u,u=h>>>0,h-=u,u+=h*4294967296}return(u>>>0)*23283064365386963e-26};return p}n&&n.exports?n.exports=o:r&&r.amd?r(function(){return o}):this.alea=o})(e,typeof t=="object"&&t,typeof define=="function"&&define)}),qI=qt((e,t)=>{(function(a,n,r){function s(l){var u=this,p="";u.x=0,u.y=0,u.z=0,u.w=0,u.next=function(){var d=u.x^u.x<<11;return u.x=u.y,u.y=u.z,u.z=u.w,u.w^=u.w>>>19^d^d>>>8},l===(l|0)?u.x=l:p+=l;for(var c=0;c>>0)/4294967296};return d.double=function(){do var h=p.next()>>>11,f=(p.next()>>>0)/4294967296,m=(h+f)/(1<<21);while(m===0);return m},d.int32=p.next,d.quick=d,c&&(typeof c=="object"&&i(c,p),d.state=function(){return i(p,{})}),d}n&&n.exports?n.exports=o:r&&r.amd?r(function(){return o}):this.xor128=o})(e,typeof t=="object"&&t,typeof define=="function"&&define)}),XI=qt((e,t)=>{(function(a,n,r){function s(l){var u=this,p="";u.next=function(){var d=u.x^u.x>>>2;return u.x=u.y,u.y=u.z,u.z=u.w,u.w=u.v,(u.d=u.d+362437|0)+(u.v=u.v^u.v<<4^(d^d<<1))|0},u.x=0,u.y=0,u.z=0,u.w=0,u.v=0,l===(l|0)?u.x=l:p+=l;for(var c=0;c>>4),u.next()}function i(l,u){return u.x=l.x,u.y=l.y,u.z=l.z,u.w=l.w,u.v=l.v,u.d=l.d,u}function o(l,u){var p=new s(l),c=u&&u.state,d=function(){return(p.next()>>>0)/4294967296};return d.double=function(){do var h=p.next()>>>11,f=(p.next()>>>0)/4294967296,m=(h+f)/(1<<21);while(m===0);return m},d.int32=p.next,d.quick=d,c&&(typeof c=="object"&&i(c,p),d.state=function(){return i(p,{})}),d}n&&n.exports?n.exports=o:r&&r.amd?r(function(){return o}):this.xorwow=o})(e,typeof t=="object"&&t,typeof define=="function"&&define)}),KI=qt((e,t)=>{(function(a,n,r){function s(l){var u=this;u.next=function(){var c=u.x,d=u.i,h,f,m;return h=c[d],h^=h>>>7,f=h^h<<24,h=c[d+1&7],f^=h^h>>>10,h=c[d+3&7],f^=h^h>>>3,h=c[d+4&7],f^=h^h<<7,h=c[d+7&7],h=h^h<<13,f^=h^h<<9,c[d]=f,u.i=d+1&7,f};function p(c,d){var h,f,m=[];if(d===(d|0))f=m[0]=d;else for(d=""+d,h=0;h0;--h)c.next()}p(u,l)}function i(l,u){return u.x=l.x.slice(),u.i=l.i,u}function o(l,u){l==null&&(l=+new Date);var p=new s(l),c=u&&u.state,d=function(){return(p.next()>>>0)/4294967296};return d.double=function(){do var h=p.next()>>>11,f=(p.next()>>>0)/4294967296,m=(h+f)/(1<<21);while(m===0);return m},d.int32=p.next,d.quick=d,c&&(c.x&&i(c,p),d.state=function(){return i(p,{})}),d}n&&n.exports?n.exports=o:r&&r.amd?r(function(){return o}):this.xorshift7=o})(e,typeof t=="object"&&t,typeof define=="function"&&define)}),ZI=qt((e,t)=>{(function(a,n,r){function s(l){var u=this;u.next=function(){var c=u.w,d=u.X,h=u.i,f,m;return u.w=c=c+1640531527|0,m=d[h+34&127],f=d[h=h+1&127],m^=m<<13,f^=f<<17,m^=m>>>15,f^=f>>>12,m=d[h]=m^f,u.i=h,m+(c^c>>>16)|0};function p(c,d){var h,f,m,g,x,A=[],y=128;for(d===(d|0)?(f=d,d=null):(d=d+"\0",f=0,y=Math.max(y,d.length)),m=0,g=-32;g>>15,f^=f<<4,f^=f>>>13,g>=0&&(x=x+1640531527|0,h=A[g&127]^=f+x,m=h==0?m+1:0);for(m>=128&&(A[(d&&d.length||0)&127]=-1),m=127,g=4*128;g>0;--g)f=A[m+34&127],h=A[m=m+1&127],f^=f<<13,h^=h<<17,f^=f>>>15,h^=h>>>12,A[m]=f^h;c.w=x,c.X=A,c.i=m}p(u,l)}function i(l,u){return u.i=l.i,u.w=l.w,u.X=l.X.slice(),u}function o(l,u){l==null&&(l=+new Date);var p=new s(l),c=u&&u.state,d=function(){return(p.next()>>>0)/4294967296};return d.double=function(){do var h=p.next()>>>11,f=(p.next()>>>0)/4294967296,m=(h+f)/(1<<21);while(m===0);return m},d.int32=p.next,d.quick=d,c&&(c.X&&i(c,p),d.state=function(){return i(p,{})}),d}n&&n.exports?n.exports=o:r&&r.amd?r(function(){return o}):this.xor4096=o})(e,typeof t=="object"&&t,typeof define=="function"&&define)}),YI=qt((e,t)=>{(function(a,n,r){function s(l){var u=this,p="";u.next=function(){var d=u.b,h=u.c,f=u.d,m=u.a;return d=d<<25^d>>>7^h,h=h-f|0,f=f<<24^f>>>8^m,m=m-d|0,u.b=d=d<<20^d>>>12^h,u.c=h=h-f|0,u.d=f<<16^h>>>16^m,u.a=m-d|0},u.a=0,u.b=0,u.c=-1640531527,u.d=1367130551,l===Math.floor(l)?(u.a=l/4294967296|0,u.b=l|0):p+=l;for(var c=0;c>>0)/4294967296};return d.double=function(){do var h=p.next()>>>11,f=(p.next()>>>0)/4294967296,m=(h+f)/(1<<21);while(m===0);return m},d.int32=p.next,d.quick=d,c&&(typeof c=="object"&&i(c,p),d.state=function(){return i(p,{})}),d}n&&n.exports?n.exports=o:r&&r.amd?r(function(){return o}):this.tychei=o})(e,typeof t=="object"&&t,typeof define=="function"&&define)}),JI=qt(()=>{}),QI=qt((e,t)=>{(function(a,n,r){var s=256,i=6,o=52,l="random",u=r.pow(s,i),p=r.pow(2,o),c=p*2,d=s-1,h;function f(w,S,C){var E=[];S=S==!0?{entropy:!0}:S||{};var _=A(x(S.entropy?[w,b(n)]:w==null?y():w,3),E),$=new m(E),M=function(){for(var I=$.g(i),N=u,O=0;I=c;)I/=2,N/=2,O>>>=1;return(I+O)/N};return M.int32=function(){return $.g(4)|0},M.quick=function(){return $.g(4)/4294967296},M.double=M,A(b($.S),n),(S.pass||C||function(I,N,O,L){return L&&(L.S&&g(L,$),I.state=function(){return g($,{})}),O?(r[l]=I,N):I})(M,_,"global"in S?S.global:this==r,S.state)}function m(w){var S,C=w.length,E=this,_=0,$=E.i=E.j=0,M=E.S=[];for(C||(w=[C++]);_{var a=jI(),n=qI(),r=XI(),s=KI(),i=ZI(),o=YI(),l=QI();l.alea=a,l.xor128=n,l.xorwow=r,l.xorshift7=s,l.xor4096=i,l.tychei=o,t.exports=l}),wc=qt(()=>{}),rA=qt(()=>{}),eS=qt(()=>{}),tS=qt(()=>{}),aS=qt(()=>{}),nS=qt((e,t)=>{var a=(()=>{var n=typeof document!="undefined"&&document.currentScript?document.currentScript.src:void 0;return typeof __filename!="undefined"&&(n=n||__filename),function(r){r=r||{};function s(){return oe.buffer!=je&&dt(oe.buffer),ht}function i(){return oe.buffer!=je&&dt(oe.buffer),Va}function o(){return oe.buffer!=je&&dt(oe.buffer),Ft}function l(){return oe.buffer!=je&&dt(oe.buffer),aa}function u(){return oe.buffer!=je&&dt(oe.buffer),$a}function p(){return oe.buffer!=je&&dt(oe.buffer),on}function c(){return oe.buffer!=je&&dt(oe.buffer),_a}var d=typeof r!="undefined"?r:{},h,f;d.ready=new Promise(function(F,q){h=F,f=q});var m;typeof process!="undefined"&&process.listeners&&(m={uncaughtException:process.listeners("uncaughtException"),unhandledRejection:process.listeners("unhandledRejection")});var g=Object.assign({},d),x=[],A="./this.program",y=(F,q)=>{throw q},b=typeof window=="object",w=typeof importScripts=="function",S=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string",C=d.ENVIRONMENT_IS_PTHREAD||!1,E="";function _(F){return d.locateFile?d.locateFile(F,E):E+F}var $,M,I,N;function O(F){F instanceof Ss||H("exiting due to exception: "+F)}if(S){w?E=wc().dirname(E)+"/":E=__dirname+"/";var L,B;typeof aA=="function"&&(L=rA(),B=wc()),$=(q,se)=>(q=B.normalize(q),L.readFileSync(q,se?void 0:"utf8")),I=q=>{var se=$(q,!0);return se.buffer||(se=new Uint8Array(se)),se},M=(q,se,pe)=>{q=B.normalize(q),L.readFile(q,function(Te,Je){Te?pe(Te):se(Je.buffer)})},process.argv.length>1&&(A=process.argv[1].replace(/\\/g,"/")),x=process.argv.slice(2),process.on("uncaughtException",function(q){if(!(q instanceof Ss))throw q}),process.on("unhandledRejection",function(q){throw q}),y=(q,se)=>{if(bn())throw process.exitCode=q,se;O(se),process.exit(q)},d.inspect=function(){return"[Emscripten Module object]"};let F;try{F=eS()}catch(q){throw console.error('The "worker_threads" module is not supported in this node.js build - perhaps a newer version is needed?'),q}global.Worker=F.Worker}else(b||w)&&(w?E=self.location.href:typeof document!="undefined"&&document.currentScript&&(E=document.currentScript.src),typeof n!="undefined"&&n&&(E=n),E.indexOf("blob:")!==0?E=E.substr(0,E.replace(/[?#].*/,"").lastIndexOf("/")+1):E="",S||($=F=>{var q=new XMLHttpRequest;return q.open("GET",F,!1),q.send(null),q.responseText},w&&(I=F=>{var q=new XMLHttpRequest;return q.open("GET",F,!1),q.responseType="arraybuffer",q.send(null),new Uint8Array(q.response)}),M=(F,q,se)=>{var pe=new XMLHttpRequest;pe.open("GET",F,!0),pe.responseType="arraybuffer",pe.onload=()=>{if(pe.status==200||pe.status==0&&pe.response){q(pe.response);return}se()},pe.onerror=se,pe.send(null)}),N=F=>document.title=F);S&&typeof performance=="undefined"&&(global.performance=tS().performance);var G=console.log.bind(console),j=console.warn.bind(console);S&&(G=F=>L.writeSync(1,F+` `),j=F=>L.writeSync(2,F+` `));var U=d.print||G,H=d.printErr||j;Object.assign(d,g),g=null,d.arguments&&(x=d.arguments),d.thisProgram&&(A=d.thisProgram),d.quit&&(y=d.quit);var V=4,Q=Atomics.load,Z=Atomics.store,re=Atomics.compareExchange,ee;d.wasmBinary&&(ee=d.wasmBinary);var he=d.noExitRuntime||!0;typeof WebAssembly!="object"&&Uo("no native wasm support detected");var oe,Ae,we=!1,Re;function Ge(F,q){F||Uo(q)}var Ke=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):void 0;function nt(F,q,se){for(var pe=q+se,Te=q;F[Te]&&!(Te>=pe);)++Te;if(Te-q>16&&F.buffer&&Ke)return Ke.decode(F.buffer instanceof SharedArrayBuffer?F.slice(q,Te):F.subarray(q,Te));for(var Je="";q>10,56320|un&1023)}}return Je}function ut(F,q){return F?nt(i(),F,q):""}function et(F,q,se,pe){if(!(pe>0))return 0;for(var Te=se,Je=se+pe-1,Oe=0;Oe=55296&&We<=57343){var Dt=F.charCodeAt(++Oe);We=65536+((We&1023)<<10)|Dt&1023}if(We<=127){if(se>=Je)break;q[se++]=We}else if(We<=2047){if(se+1>=Je)break;q[se++]=192|We>>6,q[se++]=128|We&63}else if(We<=65535){if(se+2>=Je)break;q[se++]=224|We>>12,q[se++]=128|We>>6&63,q[se++]=128|We&63}else{if(se+3>=Je)break;q[se++]=240|We>>18,q[se++]=128|We>>12&63,q[se++]=128|We>>6&63,q[se++]=128|We&63}}return q[se]=0,se-Te}function rt(F,q,se){return et(F,i(),q,se)}var je,ht,Va,Ft,sn,aa,$a,on,_a;C&&(je=d.buffer);function dt(F){je=F,d.HEAP8=ht=new Int8Array(F),d.HEAP16=Ft=new Int16Array(F),d.HEAP32=aa=new Int32Array(F),d.HEAPU8=Va=new Uint8Array(F),d.HEAPU16=sn=new Uint16Array(F),d.HEAPU32=$a=new Uint32Array(F),d.HEAPF32=on=new Float32Array(F),d.HEAPF64=_a=new Float64Array(F)}var Pa=d.INITIAL_MEMORY||16777216;if(C)oe=d.wasmMemory,je=d.buffer;else if(d.wasmMemory)oe=d.wasmMemory;else if(oe=new WebAssembly.Memory({initial:Pa/65536,maximum:32768,shared:!0}),!(oe.buffer instanceof SharedArrayBuffer))throw H("requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag"),S&&console.log("(on node you may need: --experimental-wasm-threads --experimental-wasm-bulk-memory and also use a recent version)"),Error("bad memory");oe&&(je=oe.buffer),Pa=je.byteLength,dt(je);var Ua,ur=[],Bo=[],Un=[],$u=!1;function bn(){return he}function Wo(){if(d.preRun)for(typeof d.preRun=="function"&&(d.preRun=[d.preRun]);d.preRun.length;)U0(d.preRun.shift());Ou(ur)}function Xt(){$u=!0,!C&&Ou(Bo)}function _p(){if(!C){if(d.postRun)for(typeof d.postRun=="function"&&(d.postRun=[d.postRun]);d.postRun.length;)y5(d.postRun.shift());Ou(Un)}}function U0(F){ur.unshift(F)}function G0(F){Bo.unshift(F)}function y5(F){Un.unshift(F)}var _r=0,Vo=null,dr=null;function b5(F){_r++,d.monitorRunDependencies&&d.monitorRunDependencies(_r)}function v5(F){if(_r--,d.monitorRunDependencies&&d.monitorRunDependencies(_r),_r==0&&(Vo!==null&&(clearInterval(Vo),Vo=null),dr)){var q=dr;dr=null,q()}}function Uo(F){C?postMessage({cmd:"onAbort",arg:F}):d.onAbort&&d.onAbort(F),F="Aborted("+F+")",H(F),we=!0,Re=1,F+=". Build with -sASSERTIONS for more info.";var q=new WebAssembly.RuntimeError(F);throw f(q),q}var H0="data:application/octet-stream;base64,";function Pp(F){return F.startsWith(H0)}function _u(F){return F.startsWith("file://")}var xa;xa="tfjs-backend-wasm-threaded-simd.wasm",Pp(xa)||(xa=_(xa));function Fp(F){try{if(F==xa&&ee)return new Uint8Array(ee);if(I)return I(F);throw"both async and sync fetching of the wasm failed"}catch(q){Uo(q)}}function j0(){if(!ee&&(b||w)){if(typeof fetch=="function"&&!_u(xa))return fetch(xa,{credentials:"same-origin"}).then(function(F){if(!F.ok)throw"failed to load wasm binary file at '"+xa+"'";return F.arrayBuffer()}).catch(function(){return Fp(xa)});if(M)return new Promise(function(F,q){M(xa,function(se){F(new Uint8Array(se))},q)})}return Promise.resolve().then(function(){return Fp(xa)})}function q0(){var F={env:qp,wasi_snapshot_preview1:qp};function q(Oe,We){var Dt=Oe.exports;if(d.asm=Dt,nf(d.asm._emscripten_tls_init),Ua=d.asm.__indirect_function_table,G0(d.asm.__wasm_call_ctors),Ae=We,!C){var un=Le.unusedWorkers.length;Le.unusedWorkers.forEach(function(cr){Le.loadWasmModuleToWorker(cr,function(){--un||v5("wasm-instantiate")})})}}C||b5("wasm-instantiate");function se(Oe){q(Oe.instance,Oe.module)}function pe(Oe){return j0().then(function(We){return WebAssembly.instantiate(We,F)}).then(function(We){return We}).then(Oe,function(We){H("failed to asynchronously prepare wasm: "+We),Uo(We)})}function Te(){return!ee&&typeof WebAssembly.instantiateStreaming=="function"&&!Pp(xa)&&!_u(xa)&&!S&&typeof fetch=="function"?fetch(xa,{credentials:"same-origin"}).then(function(Oe){var We=WebAssembly.instantiateStreaming(Oe,F);return We.then(se,function(Dt){return H("wasm streaming compile failed: "+Dt),H("falling back to ArrayBuffer instantiation"),pe(se)})}):pe(se)}if(d.instantiateWasm)try{var Je=d.instantiateWasm(F,q);return Je}catch(Oe){H("Module.instantiateWasm callback failed with error: "+Oe),f(Oe)}return Te().catch(f),{}}var X0,w5,K0={};function Ss(F){this.name="ExitStatus",this.message="Program terminated with exit("+F+")",this.status=F}function Z0(F){var q=Le.pthreads[F];delete Le.pthreads[F],q.terminate(),Nm(F),Le.runningWorkers.splice(Le.runningWorkers.indexOf(q),1),q.pthread_ptr=0}function Y0(F){var q=Le.pthreads[F];q.postMessage({cmd:"cancel"})}function Pu(F){var q=Le.pthreads[F];Ge(q),Le.returnWorkerToPool(q)}function Op(F){var q=Le.getNewWorker();if(!q)return 6;Le.runningWorkers.push(q),Le.pthreads[F.pthread_ptr]=q,q.pthread_ptr=F.pthread_ptr;var se={cmd:"run",start_routine:F.startRoutine,arg:F.arg,pthread_ptr:F.pthread_ptr};return q.runPthread=()=>{se.time=performance.now(),q.postMessage(se,F.transferList)},q.loaded&&(q.runPthread(),delete q.runPthread),0}var Dp={varargs:void 0,get:function(){Dp.varargs+=4;var F=l()[Dp.varargs-4>>2];return F},getStr:function(F){var q=ut(F);return q}};function Fu(F){if(C)return Pr(1,1,F);Re=F,bn()||(Le.terminateAllThreads(),d.onExit&&d.onExit(F),we=!0),y(F,new Ss(F))}function k5(F,q){if(Re=F,!q&&C)throw Lp(F),"unwind";Fu(F)}var zp=k5;function J0(F){if(F instanceof Ss||F=="unwind")return Re;y(1,F)}var Le={unusedWorkers:[],runningWorkers:[],tlsInitFunctions:[],pthreads:{},init:function(){C?Le.initWorker():Le.initMainThread()},initMainThread:function(){for(var F=8;F--;)Le.allocateUnusedWorker()},initWorker:function(){he=!1},setExitStatus:function(F){Re=F},terminateAllThreads:function(){for(var F of Object.values(Le.pthreads))Le.returnWorkerToPool(F);for(var F of Le.unusedWorkers)F.terminate();Le.unusedWorkers=[]},returnWorkerToPool:function(F){var q=F.pthread_ptr;delete Le.pthreads[q],Le.unusedWorkers.push(F),Le.runningWorkers.splice(Le.runningWorkers.indexOf(F),1),F.pthread_ptr=0,Nm(q)},receiveObjectTransfer:function(F){},threadInitTLS:function(){Le.tlsInitFunctions.forEach(F=>F())},loadWasmModuleToWorker:function(F,q){F.onmessage=se=>{var pe=se.data,Te=pe.cmd;if(F.pthread_ptr&&(Le.currentProxiedOperationCallerThread=F.pthread_ptr),pe.targetThread&&pe.targetThread!=Qp()){var Je=Le.pthreads[pe.targetThread];Je?Je.postMessage(pe,pe.transferList):H('Internal error! Worker sent a message "'+Te+'" to target pthread '+pe.targetThread+", but that thread no longer exists!"),Le.currentProxiedOperationCallerThread=void 0;return}Te==="processProxyingQueue"?Du(pe.queue):Te==="spawnThread"?Op(pe):Te==="cleanupThread"?Pu(pe.thread):Te==="killThread"?Z0(pe.thread):Te==="cancelThread"?Y0(pe.thread):Te==="loaded"?(F.loaded=!0,q&&q(F),F.runPthread&&(F.runPthread(),delete F.runPthread)):Te==="print"?U("Thread "+pe.threadId+": "+pe.text):Te==="printErr"?H("Thread "+pe.threadId+": "+pe.text):Te==="alert"?alert("Thread "+pe.threadId+": "+pe.text):pe.target==="setimmediate"?F.postMessage(pe):Te==="onAbort"?d.onAbort&&d.onAbort(pe.arg):Te&&H("worker sent an unknown command "+Te),Le.currentProxiedOperationCallerThread=void 0},F.onerror=se=>{var pe="worker sent an error!";throw H(pe+" "+se.filename+":"+se.lineno+": "+se.message),se},S&&(F.on("message",function(se){F.onmessage({data:se})}),F.on("error",function(se){F.onerror(se)}),F.on("detachedExit",function(){})),F.postMessage({cmd:"load",urlOrBlob:d.mainScriptUrlOrBlob||n,wasmMemory:oe,wasmModule:Ae})},allocateUnusedWorker:function(){var F=_("tfjs-backend-wasm-threaded-simd.worker.js");Le.unusedWorkers.push(new Worker(F))},getNewWorker:function(){return Le.unusedWorkers.length==0&&(Le.allocateUnusedWorker(),Le.loadWasmModuleToWorker(Le.unusedWorkers[0])),Le.unusedWorkers.pop()}};d.PThread=Le;function Ou(F){for(;F.length>0;)F.shift()(d)}function Q0(F){var q=Em(),se=F();return ec(q),se}function I5(F){return F}function S5(F){var q=/\b_Z[\w\d_]+/g;return F.replace(q,function(se){var pe=se;return se===pe?se:pe+" ["+se+"]"})}function ef(){var F=Qp(),q=l()[F+44>>2],se=l()[F+48>>2],pe=q-se;$5(q,pe),ec(q)}d.establishStackSpace=ef;function Lp(F){if(C)return Pr(2,0,F);try{zp(F)}catch(q){J0(q)}}var Go=[];function tf(F){var q=Go[F];return q||(F>=Go.length&&(Go.length=F+1),Go[F]=q=Ua.get(F)),q}function af(F,q){var se=tf(F)(q);bn()?Le.setExitStatus(se):M5(se)}d.invokeEntryPoint=af;function T5(){var F=new Error;if(!F.stack){try{throw new Error}catch(q){F=q}if(!F.stack)return"(no stack trace available)"}return F.stack.toString()}function nf(F){Le.tlsInitFunctions.push(F)}function rf(F,q){s().set(F,q)}function sf(F){N5(F,!w,1,!b),Le.threadInitTLS()}function of(F){C?postMessage({cmd:"cleanupThread",thread:F}):Pu(F)}function Bp(F,q,se,pe){return C?Pr(3,1,F,q,se,pe):Wp(F,q,se,pe)}function Wp(F,q,se,pe){if(typeof SharedArrayBuffer=="undefined")return H("Current environment does not support SharedArrayBuffer, pthreads are not available!"),6;var Te=[],Je=0;if(C&&(Te.length===0||Je))return Bp(F,q,se,pe);if(Je)return Je;var Oe={startRoutine:se,pthread_ptr:F,arg:pe,transferList:Te};return C?(Oe.cmd="spawnThread",postMessage(Oe,Te),0):Op(Oe)}function lf(){return 2097152}var uf=!0;function df(){return uf}function Du(F){Atomics.store(l(),F>>2,1),Qp()&&R5(F),Atomics.compareExchange(l(),F>>2,1,0)}d.executeNotifiedProxyingQueue=Du;function pf(F,q,se,pe){if(F==q)setTimeout(()=>Du(pe));else if(C)postMessage({targetThread:F,cmd:"processProxyingQueue",queue:pe});else{var Te=Le.pthreads[F];if(!Te)return;Te.postMessage({cmd:"processProxyingQueue",queue:pe})}return 1}function cf(F,q,se){return-1}function hf(){Uo("")}function Ts(F){Ts.shown||(Ts.shown={}),Ts.shown[F]||(Ts.shown[F]=1,S&&(F="warning: "+F),H(F))}function ff(){S||w||Ts("Blocking on the main thread is very dangerous, see https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread")}function mf(){return Date.now()}function Vp(){return 2147483648}function gf(){return Vp()}var Ho;S?Ho=()=>{var F=process.hrtime();return F[0]*1e3+F[1]/1e6}:C?Ho=()=>performance.now()-d.__performance_now_clock_drift:Ho=()=>performance.now();function xf(F,q,se){i().copyWithin(F,q,q+se)}function Af(){return S?aS().cpus().length:navigator.hardwareConcurrency}function Pr(F,q){var se=arguments.length-2,pe=arguments;return Q0(()=>{for(var Te=se,Je=tc(Te*8),Oe=Je>>3,We=0;We>3,Te=0;Te>>16),dt(oe.buffer),1}catch(q){}}function vf(F){var q=i().length;if(F=F>>>0,F<=q)return!1;var se=Vp();if(F>se)return!1;let pe=(Dt,un)=>Dt+(un-Dt%un)%un;for(var Te=1;Te<=4;Te*=2){var Je=q*(1+.2/Te);Je=Math.min(Je,F+100663296);var Oe=Math.min(se,pe(Math.max(F,Je),65536)),We=bf(Oe);if(We)return!0}return!1}function wf(){throw"unwind"}function Up(F){return C?Pr(4,1,F):52}function Gp(F,q,se,pe,Te){return C?Pr(5,1,F,q,se,pe,Te):70}var kf=[null,[],[]];function If(F,q){var se=kf[F];q===0||q===10?((F===1?U:H)(nt(se,0)),se.length=0):se.push(q)}function Hp(F,q,se,pe){if(C)return Pr(6,1,F,q,se,pe);for(var Te=0,Je=0;Je>2],We=u()[q+4>>2];q+=8;for(var Dt=0;Dt>2]=Te,0}function jp(F){var q=d["_"+F];return q}function Sf(F,q,se,pe,Te){var Je={string:dn=>{var Ko=0;if(dn!=null&&dn!==0){var F5=(dn.length<<2)+1;Ko=tc(F5),rt(dn,Ko,F5)}return Ko},array:dn=>{var Ko=tc(dn.length);return rf(dn,Ko),Ko}};function Oe(dn){return q==="string"?ut(dn):q==="boolean"?Boolean(dn):dn}var We=jp(F),Dt=[],un=0;if(pe)for(var cr=0;crOe==="number"||Oe==="boolean"),Je=q!=="string";return Je&&Te&&!pe?jp(F):function(){return Sf(F,q,se,arguments,pe)}}Le.init();var Cf=[null,Fu,Lp,Bp,Up,Gp,Hp],qp={__emscripten_init_main_thread_js:sf,__emscripten_thread_cleanup:of,__pthread_create_js:Wp,_emscripten_default_pthread_stack_size:lf,_emscripten_get_now_is_monotonic:df,_emscripten_notify_task_queue:pf,_emscripten_set_offscreencanvas_size:cf,abort:hf,emscripten_check_blocking_allowed:ff,emscripten_date_now:mf,emscripten_get_heap_max:gf,emscripten_get_now:Ho,emscripten_memcpy_big:xf,emscripten_num_logical_cores:Af,emscripten_receive_on_main_thread_js:yf,emscripten_resize_heap:vf,emscripten_unwind_to_js_event_loop:wf,exit:zp,fd_close:Up,fd_seek:Gp,fd_write:Hp,memory:oe||d.wasmMemory},C5=q0(),Nf=d.___wasm_call_ctors=function(){return(Nf=d.___wasm_call_ctors=d.asm.__wasm_call_ctors).apply(null,arguments)},Ef=d._init=function(){return(Ef=d._init=d.asm.init).apply(null,arguments)},Rf=d._init_with_threads_count=function(){return(Rf=d._init_with_threads_count=d.asm.init_with_threads_count).apply(null,arguments)},Mf=d._get_threads_count=function(){return(Mf=d._get_threads_count=d.asm.get_threads_count).apply(null,arguments)},$f=d._register_tensor=function(){return($f=d._register_tensor=d.asm.register_tensor).apply(null,arguments)},_f=d._dispose_data=function(){return(_f=d._dispose_data=d.asm.dispose_data).apply(null,arguments)},Pf=d._dispose=function(){return(Pf=d._dispose=d.asm.dispose).apply(null,arguments)},Ff=d._Abs=function(){return(Ff=d._Abs=d.asm.Abs).apply(null,arguments)},Of=d._Add=function(){return(Of=d._Add=d.asm.Add).apply(null,arguments)},Df=d._AddN=function(){return(Df=d._AddN=d.asm.AddN).apply(null,arguments)},zf=d._All=function(){return(zf=d._All=d.asm.All).apply(null,arguments)},Lf=d._Any=function(){return(Lf=d._Any=d.asm.Any).apply(null,arguments)},Bf=d._ArgMax=function(){return(Bf=d._ArgMax=d.asm.ArgMax).apply(null,arguments)},Wf=d._AvgPool=function(){return(Wf=d._AvgPool=d.asm.AvgPool).apply(null,arguments)},Vf=d._BatchMatMul=function(){return(Vf=d._BatchMatMul=d.asm.BatchMatMul).apply(null,arguments)},Uf=d._Ceil=function(){return(Uf=d._Ceil=d.asm.Ceil).apply(null,arguments)},Gf=d._ClipByValue=function(){return(Gf=d._ClipByValue=d.asm.ClipByValue).apply(null,arguments)},Hf=d._Conv2D=function(){return(Hf=d._Conv2D=d.asm.Conv2D).apply(null,arguments)},jf=d._Conv2DBackpropInput=function(){return(jf=d._Conv2DBackpropInput=d.asm.Conv2DBackpropInput).apply(null,arguments)},qf=d._Cos=function(){return(qf=d._Cos=d.asm.Cos).apply(null,arguments)},Xf=d._Cosh=function(){return(Xf=d._Cosh=d.asm.Cosh).apply(null,arguments)},Kf=d._CropAndResize=function(){return(Kf=d._CropAndResize=d.asm.CropAndResize).apply(null,arguments)},Zf=d._Cumprod=function(){return(Zf=d._Cumprod=d.asm.Cumprod).apply(null,arguments)},Yf=d._Cumsum=function(){return(Yf=d._Cumsum=d.asm.Cumsum).apply(null,arguments)},Jf=d._DepthToSpace=function(){return(Jf=d._DepthToSpace=d.asm.DepthToSpace).apply(null,arguments)},Qf=d._DepthwiseConv2dNative=function(){return(Qf=d._DepthwiseConv2dNative=d.asm.DepthwiseConv2dNative).apply(null,arguments)},em=d._Elu=function(){return(em=d._Elu=d.asm.Elu).apply(null,arguments)},tm=d._Equal=function(){return(tm=d._Equal=d.asm.Equal).apply(null,arguments)},am=d._Exp=function(){return(am=d._Exp=d.asm.Exp).apply(null,arguments)},nm=d._FlipLeftRight=function(){return(nm=d._FlipLeftRight=d.asm.FlipLeftRight).apply(null,arguments)},rm=d._Floor=function(){return(rm=d._Floor=d.asm.Floor).apply(null,arguments)},sm=d._FloorDiv=function(){return(sm=d._FloorDiv=d.asm.FloorDiv).apply(null,arguments)},im=d._FusedBatchNorm=function(){return(im=d._FusedBatchNorm=d.asm.FusedBatchNorm).apply(null,arguments)},om=d._FusedConv2D=function(){return(om=d._FusedConv2D=d.asm.FusedConv2D).apply(null,arguments)},lm=d._FusedDepthwiseConv2D=function(){return(lm=d._FusedDepthwiseConv2D=d.asm.FusedDepthwiseConv2D).apply(null,arguments)},um=d._Gather=function(){return(um=d._Gather=d.asm.Gather).apply(null,arguments)},dm=d._GatherNd=function(){return(dm=d._GatherNd=d.asm.GatherNd).apply(null,arguments)},pm=d._Greater=function(){return(pm=d._Greater=d.asm.Greater).apply(null,arguments)},cm=d._GreaterEqual=function(){return(cm=d._GreaterEqual=d.asm.GreaterEqual).apply(null,arguments)},hm=d._IsNan=function(){return(hm=d._IsNan=d.asm.IsNan).apply(null,arguments)},fm=d._LeakyRelu=function(){return(fm=d._LeakyRelu=d.asm.LeakyRelu).apply(null,arguments)},mm=d._Less=function(){return(mm=d._Less=d.asm.Less).apply(null,arguments)},gm=d._LessEqual=function(){return(gm=d._LessEqual=d.asm.LessEqual).apply(null,arguments)},xm=d._Log=function(){return(xm=d._Log=d.asm.Log).apply(null,arguments)},Am=d._LogicalAnd=function(){return(Am=d._LogicalAnd=d.asm.LogicalAnd).apply(null,arguments)},ym=d._LogicalNot=function(){return(ym=d._LogicalNot=d.asm.LogicalNot).apply(null,arguments)},bm=d._LogicalOr=function(){return(bm=d._LogicalOr=d.asm.LogicalOr).apply(null,arguments)},vm=d._LogicalXor=function(){return(vm=d._LogicalXor=d.asm.LogicalXor).apply(null,arguments)},wm=d._Max=function(){return(wm=d._Max=d.asm.Max).apply(null,arguments)},km=d._MaxPool=function(){return(km=d._MaxPool=d.asm.MaxPool).apply(null,arguments)},Xp=d._Maximum=function(){return(Xp=d._Maximum=d.asm.Maximum).apply(null,arguments)},Kp=d._Mean=function(){return(Kp=d._Mean=d.asm.Mean).apply(null,arguments)},Lu=d._Min=function(){return(Lu=d._Min=d.asm.Min).apply(null,arguments)},Im=d._Minimum=function(){return(Im=d._Minimum=d.asm.Minimum).apply(null,arguments)},Sm=d._MirrorPad=function(){return(Sm=d._MirrorPad=d.asm.MirrorPad).apply(null,arguments)},jo=d._Multiply=function(){return(jo=d._Multiply=d.asm.Multiply).apply(null,arguments)},Zp=d._Neg=function(){return(Zp=d._Neg=d.asm.Neg).apply(null,arguments)},qo=d._NonMaxSuppressionV3=function(){return(qo=d._NonMaxSuppressionV3=d.asm.NonMaxSuppressionV3).apply(null,arguments)},Xo=d._NonMaxSuppressionV4=function(){return(Xo=d._NonMaxSuppressionV4=d.asm.NonMaxSuppressionV4).apply(null,arguments)},Tm=d._NonMaxSuppressionV5=function(){return(Tm=d._NonMaxSuppressionV5=d.asm.NonMaxSuppressionV5).apply(null,arguments)},X=d._NotEqual=function(){return(X=d._NotEqual=d.asm.NotEqual).apply(null,arguments)},ie=d._OneHot=function(){return(ie=d._OneHot=d.asm.OneHot).apply(null,arguments)},ke=d._PadV2=function(){return(ke=d._PadV2=d.asm.PadV2).apply(null,arguments)},Ye=d._Pow=function(){return(Ye=d._Pow=d.asm.Pow).apply(null,arguments)},yt=d._Prelu=function(){return(yt=d._Prelu=d.asm.Prelu).apply(null,arguments)},bt=d._Prod=function(){return(bt=d._Prod=d.asm.Prod).apply(null,arguments)},Ze=d._RealDiv=function(){return(Ze=d._RealDiv=d.asm.RealDiv).apply(null,arguments)},qe=d._Reciprocal=function(){return(qe=d._Reciprocal=d.asm.Reciprocal).apply(null,arguments)},Ot=d._Relu=function(){return(Ot=d._Relu=d.asm.Relu).apply(null,arguments)},ln=d._Relu6=function(){return(ln=d._Relu6=d.asm.Relu6).apply(null,arguments)},pr=d._ResizeBilinear=function(){return(pr=d._ResizeBilinear=d.asm.ResizeBilinear).apply(null,arguments)},Yp=d._ResizeNearestNeighbor=function(){return(Yp=d._ResizeNearestNeighbor=d.asm.ResizeNearestNeighbor).apply(null,arguments)},Bu=d._Reverse=function(){return(Bu=d._Reverse=d.asm.Reverse).apply(null,arguments)},Cm=d._RotateWithOffset=function(){return(Cm=d._RotateWithOffset=d.asm.RotateWithOffset).apply(null,arguments)},Fa=d._Round=function(){return(Fa=d._Round=d.asm.Round).apply(null,arguments)},Fr=d._Rsqrt=function(){return(Fr=d._Rsqrt=d.asm.Rsqrt).apply(null,arguments)},Jp=d._ScatterNd=function(){return(Jp=d._ScatterNd=d.asm.ScatterNd).apply(null,arguments)},Jk=d._SelectV2=function(){return(Jk=d._SelectV2=d.asm.SelectV2).apply(null,arguments)},Qk=d._Sigmoid=function(){return(Qk=d._Sigmoid=d.asm.Sigmoid).apply(null,arguments)},eI=d._Sin=function(){return(eI=d._Sin=d.asm.Sin).apply(null,arguments)},tI=d._Softmax=function(){return(tI=d._Softmax=d.asm.Softmax).apply(null,arguments)},aI=d._SparseFillEmptyRows=function(){return(aI=d._SparseFillEmptyRows=d.asm.SparseFillEmptyRows).apply(null,arguments)},nI=d._SparseReshape=function(){return(nI=d._SparseReshape=d.asm.SparseReshape).apply(null,arguments)},rI=d._SparseSegmentReduction=function(){return(rI=d._SparseSegmentReduction=d.asm.SparseSegmentReduction).apply(null,arguments)},sI=d._Sqrt=function(){return(sI=d._Sqrt=d.asm.Sqrt).apply(null,arguments)},iI=d._Square=function(){return(iI=d._Square=d.asm.Square).apply(null,arguments)},oI=d._SquaredDifference=function(){return(oI=d._SquaredDifference=d.asm.SquaredDifference).apply(null,arguments)},lI=d._Step=function(){return(lI=d._Step=d.asm.Step).apply(null,arguments)},uI=d._StridedSlice=function(){return(uI=d._StridedSlice=d.asm.StridedSlice).apply(null,arguments)},dI=d._Sub=function(){return(dI=d._Sub=d.asm.Sub).apply(null,arguments)},pI=d._Sum=function(){return(pI=d._Sum=d.asm.Sum).apply(null,arguments)},cI=d._Tan=function(){return(cI=d._Tan=d.asm.Tan).apply(null,arguments)},hI=d._Tanh=function(){return(hI=d._Tanh=d.asm.Tanh).apply(null,arguments)},fI=d._Tile=function(){return(fI=d._Tile=d.asm.Tile).apply(null,arguments)},mI=d._TopK=function(){return(mI=d._TopK=d.asm.TopK).apply(null,arguments)},gI=d._Transform=function(){return(gI=d._Transform=d.asm.Transform).apply(null,arguments)},xI=d._Transpose=function(){return(xI=d._Transpose=d.asm.Transpose).apply(null,arguments)},AI=d.__FusedMatMul=function(){return(AI=d.__FusedMatMul=d.asm._FusedMatMul).apply(null,arguments)},yI=d._malloc=function(){return(yI=d._malloc=d.asm.malloc).apply(null,arguments)},bI=d._free=function(){return(bI=d._free=d.asm.free).apply(null,arguments)},vI=d.__emscripten_tls_init=function(){return(vI=d.__emscripten_tls_init=d.asm._emscripten_tls_init).apply(null,arguments)},Qp=d._pthread_self=function(){return(Qp=d._pthread_self=d.asm.pthread_self).apply(null,arguments)},wI=d.___errno_location=function(){return(wI=d.___errno_location=d.asm.__errno_location).apply(null,arguments)},N5=d.__emscripten_thread_init=function(){return(N5=d.__emscripten_thread_init=d.asm._emscripten_thread_init).apply(null,arguments)},kI=d.__emscripten_thread_crashed=function(){return(kI=d.__emscripten_thread_crashed=d.asm._emscripten_thread_crashed).apply(null,arguments)},II=d._emscripten_main_thread_process_queued_calls=function(){return(II=d._emscripten_main_thread_process_queued_calls=d.asm.emscripten_main_thread_process_queued_calls).apply(null,arguments)},SI=d._emscripten_main_browser_thread_id=function(){return(SI=d._emscripten_main_browser_thread_id=d.asm.emscripten_main_browser_thread_id).apply(null,arguments)},E5=d._emscripten_run_in_main_runtime_thread_js=function(){return(E5=d._emscripten_run_in_main_runtime_thread_js=d.asm.emscripten_run_in_main_runtime_thread_js).apply(null,arguments)},TI=d._emscripten_dispatch_to_thread_=function(){return(TI=d._emscripten_dispatch_to_thread_=d.asm.emscripten_dispatch_to_thread_).apply(null,arguments)},R5=d.__emscripten_proxy_execute_task_queue=function(){return(R5=d.__emscripten_proxy_execute_task_queue=d.asm._emscripten_proxy_execute_task_queue).apply(null,arguments)},Nm=d.__emscripten_thread_free_data=function(){return(Nm=d.__emscripten_thread_free_data=d.asm._emscripten_thread_free_data).apply(null,arguments)},M5=d.__emscripten_thread_exit=function(){return(M5=d.__emscripten_thread_exit=d.asm._emscripten_thread_exit).apply(null,arguments)},$5=d._emscripten_stack_set_limits=function(){return($5=d._emscripten_stack_set_limits=d.asm.emscripten_stack_set_limits).apply(null,arguments)},Em=d.stackSave=function(){return(Em=d.stackSave=d.asm.stackSave).apply(null,arguments)},ec=d.stackRestore=function(){return(ec=d.stackRestore=d.asm.stackRestore).apply(null,arguments)},tc=d.stackAlloc=function(){return(tc=d.stackAlloc=d.asm.stackAlloc).apply(null,arguments)},CI=d.dynCall_iijjiiii=function(){return(CI=d.dynCall_iijjiiii=d.asm.dynCall_iijjiiii).apply(null,arguments)},NI=d.dynCall_jiji=function(){return(NI=d.dynCall_jiji=d.asm.dynCall_jiji).apply(null,arguments)};d.keepRuntimeAlive=bn,d.wasmMemory=oe,d.cwrap=Tf,d.ExitStatus=Ss,d.PThread=Le;var ac;dr=function F(){ac||_5(),ac||(dr=F)};function _5(F){if(F=F||x,_r>0)return;if(C){h(d),Xt(),postMessage({cmd:"loaded"});return}if(Wo(),_r>0)return;function q(){ac||(ac=!0,d.calledRun=!0,!we&&(Xt(),h(d),d.onRuntimeInitialized&&d.onRuntimeInitialized(),_p()))}d.setStatus?(d.setStatus("Running..."),setTimeout(function(){setTimeout(function(){d.setStatus("")},1),q()},1)):q()}if(d.preInit)for(typeof d.preInit=="function"&&(d.preInit=[d.preInit]);d.preInit.length>0;)d.preInit.pop()();_5();var nc;m&&(nc={uncaughtException:process.listeners("uncaughtException").filter(function(F){return!m.uncaughtException.indexOf(F)>-1}),unhandledRejection:process.listeners("unhandledRejection").filter(function(F){return!m.unhandledRejection.indexOf(F)>-1})});var rc;if(typeof WasmBackendModule!="undefined")rc=WasmBackendModule;else if(typeof r!="undefined")rc=r;else throw new Error("Could not find wasm module in post.js");if(nc){var EI=rc._dispose;rc._dispose=function(){EI(),nc.uncaughtException.forEach(function(F){process.removeListener("uncaughtException",F)}),nc.unhandledRejection.forEach(function(F){process.removeListener("unhandledRejection",F)})}}return r.ready}})();typeof e=="object"&&typeof t=="object"?t.exports=a:typeof define=="function"&&define.amd?define([],function(){return a}):typeof e=="object"&&(e.WasmBackendModuleThreadedSimd=a)}),rS=qt((e,t)=>{t.exports.wasmWorkerContents=`"use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",data=>onmessage({data:data}));var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:function(f){(0,eval)(fs.readFileSync(f,"utf8"))},postMessage:function(msg){parentPort.postMessage(msg)},performance:global.performance||{now:function(){return Date.now()}}})}var initializedJS=false;var pendingNotifiedProxyingQueues=[];function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+" ");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var instance=new WebAssembly.Instance(Module["wasmModule"],info);receiveInstance(instance);Module["wasmModule"]=null;return instance.exports};self.onunhandledrejection=e=>{throw e.reason??e};self.onmessage=e=>{try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob=="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}WasmBackendModuleThreadedSimd(Module).then(function(instance){Module=instance})}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;Module["__emscripten_thread_init"](e.data.pthread_ptr,0,0,1);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){pendingNotifiedProxyingQueues.forEach(queue=>{Module["executeNotifiedProxyingQueue"](queue)});pendingNotifiedProxyingQueues=[];initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){if(ex instanceof Module["ExitStatus"]){if(Module["keepRuntimeAlive"]()){}else{Module["__emscripten_thread_exit"](ex.status)}}else{throw ex}}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processProxyingQueue"){if(initializedJS){Module["executeNotifiedProxyingQueue"](e.data.queue)}else{pendingNotifiedProxyingQueues.push(e.data.queue)}}else if(e.data.cmd){err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}};`}),sS=qt((e,t)=>{var a=(()=>{var n=typeof document!="undefined"&&document.currentScript?document.currentScript.src:void 0;return typeof __filename!="undefined"&&(n=n||__filename),function(r){r=r||{};var s=typeof r!="undefined"?r:{},i,o;s.ready=new Promise(function(X,ie){i=X,o=ie});var l;typeof process!="undefined"&&process.listeners&&(l={uncaughtException:process.listeners("uncaughtException"),unhandledRejection:process.listeners("unhandledRejection")});var u=Object.assign({},s),p=[],c="./this.program",d=(X,ie)=>{throw ie},h=typeof window=="object",f=typeof importScripts=="function",m=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string",g="";function x(X){return s.locateFile?s.locateFile(X,g):g+X}var A,y,b,w;function S(X){X instanceof Vo||$("exiting due to exception: "+X)}if(m){f?g=wc().dirname(g)+"/":g=__dirname+"/";var C,E;typeof aA=="function"&&(C=rA(),E=wc()),A=(X,ie)=>(X=E.normalize(X),C.readFileSync(X,ie?void 0:"utf8")),b=X=>{var ie=A(X,!0);return ie.buffer||(ie=new Uint8Array(ie)),ie},y=(X,ie,ke)=>{X=E.normalize(X),C.readFile(X,function(Ye,yt){Ye?ke(Ye):ie(yt.buffer)})},process.argv.length>1&&(c=process.argv[1].replace(/\\/g,"/")),p=process.argv.slice(2),process.on("uncaughtException",function(X){if(!(X instanceof Vo))throw X}),process.on("unhandledRejection",function(X){throw X}),d=(X,ie)=>{if(Va())throw process.exitCode=X,ie;S(ie),process.exit(X)},s.inspect=function(){return"[Emscripten Module object]"}}else(h||f)&&(f?g=self.location.href:typeof document!="undefined"&&document.currentScript&&(g=document.currentScript.src),n&&(g=n),g.indexOf("blob:")!==0?g=g.substr(0,g.replace(/[?#].*/,"").lastIndexOf("/")+1):g="",A=X=>{var ie=new XMLHttpRequest;return ie.open("GET",X,!1),ie.send(null),ie.responseText},f&&(b=X=>{var ie=new XMLHttpRequest;return ie.open("GET",X,!1),ie.responseType="arraybuffer",ie.send(null),new Uint8Array(ie.response)}),y=(X,ie,ke)=>{var Ye=new XMLHttpRequest;Ye.open("GET",X,!0),Ye.responseType="arraybuffer",Ye.onload=()=>{if(Ye.status==200||Ye.status==0&&Ye.response){ie(Ye.response);return}ke()},Ye.onerror=ke,Ye.send(null)},w=X=>document.title=X);var _=s.print||console.log.bind(console),$=s.printErr||console.warn.bind(console);Object.assign(s,u),u=null,s.arguments&&(p=s.arguments),s.thisProgram&&(c=s.thisProgram),s.quit&&(d=s.quit);var M=4,I;s.wasmBinary&&(I=s.wasmBinary);var N=s.noExitRuntime||!0;typeof WebAssembly!="object"&&Un("no native wasm support detected");var O,L=!1,B;function G(X,ie){X||Un(ie)}var j=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):void 0;function U(X,ie,ke){for(var Ye=ie+ke,yt=ie;X[yt]&&!(yt>=Ye);)++yt;if(yt-ie>16&&X.buffer&&j)return j.decode(X.subarray(ie,yt));for(var bt="";ie>10,56320|ln&1023)}}return bt}function H(X,ie){return X?U(ee,X,ie):""}function V(X,ie,ke,Ye){if(!(Ye>0))return 0;for(var yt=ke,bt=ke+Ye-1,Ze=0;Ze=55296&&qe<=57343){var Ot=X.charCodeAt(++Ze);qe=65536+((qe&1023)<<10)|Ot&1023}if(qe<=127){if(ke>=bt)break;ie[ke++]=qe}else if(qe<=2047){if(ke+1>=bt)break;ie[ke++]=192|qe>>6,ie[ke++]=128|qe&63}else if(qe<=65535){if(ke+2>=bt)break;ie[ke++]=224|qe>>12,ie[ke++]=128|qe>>6&63,ie[ke++]=128|qe&63}else{if(ke+3>=bt)break;ie[ke++]=240|qe>>18,ie[ke++]=128|qe>>12&63,ie[ke++]=128|qe>>6&63,ie[ke++]=128|qe&63}}return ie[ke]=0,ke-yt}function Q(X,ie,ke){return V(X,ee,ie,ke)}var Z,re,ee,he,oe,Ae,we,Re,Ge;function Ke(X){Z=X,s.HEAP8=re=new Int8Array(X),s.HEAP16=he=new Int16Array(X),s.HEAP32=Ae=new Int32Array(X),s.HEAPU8=ee=new Uint8Array(X),s.HEAPU16=oe=new Uint16Array(X),s.HEAPU32=we=new Uint32Array(X),s.HEAPF32=Re=new Float32Array(X),s.HEAPF64=Ge=new Float64Array(X)}var nt=s.INITIAL_MEMORY||16777216,ut,et=[],rt=[],je=[],ht=!1;function Va(){return N}function Ft(){if(s.preRun)for(typeof s.preRun=="function"&&(s.preRun=[s.preRun]);s.preRun.length;)$a(s.preRun.shift());dr(et)}function sn(){ht=!0,dr(rt)}function aa(){if(s.postRun)for(typeof s.postRun=="function"&&(s.postRun=[s.postRun]);s.postRun.length;)_a(s.postRun.shift());dr(je)}function $a(X){et.unshift(X)}function on(X){rt.unshift(X)}function _a(X){je.unshift(X)}var dt=0,Pa=null,Ua=null;function ur(X){dt++,s.monitorRunDependencies&&s.monitorRunDependencies(dt)}function Bo(X){if(dt--,s.monitorRunDependencies&&s.monitorRunDependencies(dt),dt==0&&(Pa!==null&&(clearInterval(Pa),Pa=null),Ua)){var ie=Ua;Ua=null,ie()}}function Un(X){s.onAbort&&s.onAbort(X),X="Aborted("+X+")",$(X),L=!0,B=1,X+=". Build with -sASSERTIONS for more info.";var ie=new WebAssembly.RuntimeError(X);throw o(ie),ie}var $u="data:application/octet-stream;base64,";function bn(X){return X.startsWith($u)}function Wo(X){return X.startsWith("file://")}var Xt;Xt="tfjs-backend-wasm.wasm",bn(Xt)||(Xt=x(Xt));function _p(X){try{if(X==Xt&&I)return new Uint8Array(I);if(b)return b(X);throw"both async and sync fetching of the wasm failed"}catch(ie){Un(ie)}}function U0(){if(!I&&(h||f)){if(typeof fetch=="function"&&!Wo(Xt))return fetch(Xt,{credentials:"same-origin"}).then(function(X){if(!X.ok)throw"failed to load wasm binary file at '"+Xt+"'";return X.arrayBuffer()}).catch(function(){return _p(Xt)});if(y)return new Promise(function(X,ie){y(Xt,function(ke){X(new Uint8Array(ke))},ie)})}return Promise.resolve().then(function(){return _p(Xt)})}function G0(){var X={env:Fu,wasi_snapshot_preview1:Fu};function ie(Ze,qe){var Ot=Ze.exports;s.asm=Ot,O=s.asm.memory,Ke(O.buffer),ut=s.asm.__indirect_function_table,on(s.asm.__wasm_call_ctors),Bo("wasm-instantiate")}ur("wasm-instantiate");function ke(Ze){ie(Ze.instance)}function Ye(Ze){return U0().then(function(qe){return WebAssembly.instantiate(qe,X)}).then(function(qe){return qe}).then(Ze,function(qe){$("failed to asynchronously prepare wasm: "+qe),Un(qe)})}function yt(){return!I&&typeof WebAssembly.instantiateStreaming=="function"&&!bn(Xt)&&!Wo(Xt)&&!m&&typeof fetch=="function"?fetch(Xt,{credentials:"same-origin"}).then(function(Ze){var qe=WebAssembly.instantiateStreaming(Ze,X);return qe.then(ke,function(Ot){return $("wasm streaming compile failed: "+Ot),$("falling back to ArrayBuffer instantiation"),Ye(ke)})}):Ye(ke)}if(s.instantiateWasm)try{var bt=s.instantiateWasm(X,ie);return bt}catch(Ze){$("Module.instantiateWasm callback failed with error: "+Ze),o(Ze)}return yt().catch(o),{}}var y5,_r;function Vo(X){this.name="ExitStatus",this.message="Program terminated with exit("+X+")",this.status=X}function dr(X){for(;X.length>0;)X.shift()(s)}function b5(X){return X}function v5(X){var ie=/\b_Z[\w\d_]+/g;return X.replace(ie,function(ke){var Ye=ke;return ke===Ye?ke:Ye+" ["+ke+"]"})}function Uo(){var X=new Error;if(!X.stack){try{throw new Error}catch(ie){X=ie}if(!X.stack)return"(no stack trace available)"}return X.stack.toString()}function H0(X,ie){re.set(X,ie)}function Pp(){Un("")}function _u(){return 2147483648}function xa(){return _u()}function Fp(X,ie,ke){ee.copyWithin(X,ie,ie+ke)}function j0(X){try{return O.grow(X-Z.byteLength+65535>>>16),Ke(O.buffer),1}catch(ie){}}function q0(X){var ie=ee.length;X=X>>>0;var ke=_u();if(X>ke)return!1;let Ye=(Ot,ln)=>Ot+(ln-Ot%ln)%ln;for(var yt=1;yt<=4;yt*=2){var bt=ie*(1+.2/yt);bt=Math.min(bt,X+100663296);var Ze=Math.min(ke,Ye(Math.max(X,bt),65536)),qe=j0(Ze);if(qe)return!0}return!1}var X0={varargs:void 0,get:function(){X0.varargs+=4;var X=Ae[X0.varargs-4>>2];return X},getStr:function(X){var ie=H(X);return ie}};function w5(X){return 52}function K0(X,ie,ke,Ye,yt){return 70}var Ss=[null,[],[]];function Z0(X,ie){var ke=Ss[X];ie===0||ie===10?((X===1?_:$)(U(ke,0)),ke.length=0):ke.push(ie)}function Y0(X,ie,ke,Ye){for(var yt=0,bt=0;bt>2],qe=we[ie+4>>2];ie+=8;for(var Ot=0;Ot>2]=yt,0}function Pu(X){var ie=s["_"+X];return ie}function Op(X,ie,ke,Ye,yt){var bt={string:Fa=>{var Fr=0;if(Fa!=null&&Fa!==0){var Jp=(Fa.length<<2)+1;Fr=Lu(Jp),Q(Fa,Fr,Jp)}return Fr},array:Fa=>{var Fr=Lu(Fa.length);return H0(Fa,Fr),Fr}};function Ze(Fa){return ie==="string"?H(Fa):ie==="boolean"?Boolean(Fa):Fa}var qe=Pu(X),Ot=[],ln=0;if(Ye)for(var pr=0;prZe==="number"||Ze==="boolean"),bt=ie!=="string";return bt&&yt&&!Ye?Pu(X):function(){return Op(X,ie,ke,arguments,Ye)}}var Fu={abort:Pp,emscripten_get_heap_max:xa,emscripten_memcpy_big:Fp,emscripten_resize_heap:q0,fd_close:w5,fd_seek:K0,fd_write:Y0},k5=G0(),zp=s.___wasm_call_ctors=function(){return(zp=s.___wasm_call_ctors=s.asm.__wasm_call_ctors).apply(null,arguments)},J0=s._init=function(){return(J0=s._init=s.asm.init).apply(null,arguments)},Le=s._init_with_threads_count=function(){return(Le=s._init_with_threads_count=s.asm.init_with_threads_count).apply(null,arguments)},Ou=s._get_threads_count=function(){return(Ou=s._get_threads_count=s.asm.get_threads_count).apply(null,arguments)},Q0=s._register_tensor=function(){return(Q0=s._register_tensor=s.asm.register_tensor).apply(null,arguments)},I5=s._dispose_data=function(){return(I5=s._dispose_data=s.asm.dispose_data).apply(null,arguments)},S5=s._dispose=function(){return(S5=s._dispose=s.asm.dispose).apply(null,arguments)},ef=s._Abs=function(){return(ef=s._Abs=s.asm.Abs).apply(null,arguments)},Lp=s._Add=function(){return(Lp=s._Add=s.asm.Add).apply(null,arguments)},Go=s._AddN=function(){return(Go=s._AddN=s.asm.AddN).apply(null,arguments)},tf=s._All=function(){return(tf=s._All=s.asm.All).apply(null,arguments)},af=s._Any=function(){return(af=s._Any=s.asm.Any).apply(null,arguments)},T5=s._ArgMax=function(){return(T5=s._ArgMax=s.asm.ArgMax).apply(null,arguments)},nf=s._AvgPool=function(){return(nf=s._AvgPool=s.asm.AvgPool).apply(null,arguments)},rf=s._BatchMatMul=function(){return(rf=s._BatchMatMul=s.asm.BatchMatMul).apply(null,arguments)},sf=s._Ceil=function(){return(sf=s._Ceil=s.asm.Ceil).apply(null,arguments)},of=s._ClipByValue=function(){return(of=s._ClipByValue=s.asm.ClipByValue).apply(null,arguments)},Bp=s._Conv2D=function(){return(Bp=s._Conv2D=s.asm.Conv2D).apply(null,arguments)},Wp=s._Conv2DBackpropInput=function(){return(Wp=s._Conv2DBackpropInput=s.asm.Conv2DBackpropInput).apply(null,arguments)},lf=s._Cos=function(){return(lf=s._Cos=s.asm.Cos).apply(null,arguments)},uf=s._Cosh=function(){return(uf=s._Cosh=s.asm.Cosh).apply(null,arguments)},df=s._CropAndResize=function(){return(df=s._CropAndResize=s.asm.CropAndResize).apply(null,arguments)},Du=s._Cumprod=function(){return(Du=s._Cumprod=s.asm.Cumprod).apply(null,arguments)},pf=s._Cumsum=function(){return(pf=s._Cumsum=s.asm.Cumsum).apply(null,arguments)},cf=s._DepthToSpace=function(){return(cf=s._DepthToSpace=s.asm.DepthToSpace).apply(null,arguments)},hf=s._DepthwiseConv2dNative=function(){return(hf=s._DepthwiseConv2dNative=s.asm.DepthwiseConv2dNative).apply(null,arguments)},Ts=s._Elu=function(){return(Ts=s._Elu=s.asm.Elu).apply(null,arguments)},ff=s._Equal=function(){return(ff=s._Equal=s.asm.Equal).apply(null,arguments)},mf=s._Exp=function(){return(mf=s._Exp=s.asm.Exp).apply(null,arguments)},Vp=s._FlipLeftRight=function(){return(Vp=s._FlipLeftRight=s.asm.FlipLeftRight).apply(null,arguments)},gf=s._Floor=function(){return(gf=s._Floor=s.asm.Floor).apply(null,arguments)},Ho=s._FloorDiv=function(){return(Ho=s._FloorDiv=s.asm.FloorDiv).apply(null,arguments)},xf=s._FusedBatchNorm=function(){return(xf=s._FusedBatchNorm=s.asm.FusedBatchNorm).apply(null,arguments)},Af=s._FusedConv2D=function(){return(Af=s._FusedConv2D=s.asm.FusedConv2D).apply(null,arguments)},Pr=s._FusedDepthwiseConv2D=function(){return(Pr=s._FusedDepthwiseConv2D=s.asm.FusedDepthwiseConv2D).apply(null,arguments)},zu=s._Gather=function(){return(zu=s._Gather=s.asm.Gather).apply(null,arguments)},yf=s._GatherNd=function(){return(yf=s._GatherNd=s.asm.GatherNd).apply(null,arguments)},bf=s._Greater=function(){return(bf=s._Greater=s.asm.Greater).apply(null,arguments)},vf=s._GreaterEqual=function(){return(vf=s._GreaterEqual=s.asm.GreaterEqual).apply(null,arguments)},wf=s._IsNan=function(){return(wf=s._IsNan=s.asm.IsNan).apply(null,arguments)},Up=s._LeakyRelu=function(){return(Up=s._LeakyRelu=s.asm.LeakyRelu).apply(null,arguments)},Gp=s._Less=function(){return(Gp=s._Less=s.asm.Less).apply(null,arguments)},kf=s._LessEqual=function(){return(kf=s._LessEqual=s.asm.LessEqual).apply(null,arguments)},If=s._Log=function(){return(If=s._Log=s.asm.Log).apply(null,arguments)},Hp=s._LogicalAnd=function(){return(Hp=s._LogicalAnd=s.asm.LogicalAnd).apply(null,arguments)},jp=s._LogicalNot=function(){return(jp=s._LogicalNot=s.asm.LogicalNot).apply(null,arguments)},Sf=s._LogicalOr=function(){return(Sf=s._LogicalOr=s.asm.LogicalOr).apply(null,arguments)},Tf=s._LogicalXor=function(){return(Tf=s._LogicalXor=s.asm.LogicalXor).apply(null,arguments)},Cf=s._Max=function(){return(Cf=s._Max=s.asm.Max).apply(null,arguments)},qp=s._MaxPool=function(){return(qp=s._MaxPool=s.asm.MaxPool).apply(null,arguments)},C5=s._Maximum=function(){return(C5=s._Maximum=s.asm.Maximum).apply(null,arguments)},Nf=s._Mean=function(){return(Nf=s._Mean=s.asm.Mean).apply(null,arguments)},Ef=s._Min=function(){return(Ef=s._Min=s.asm.Min).apply(null,arguments)},Rf=s._Minimum=function(){return(Rf=s._Minimum=s.asm.Minimum).apply(null,arguments)},Mf=s._MirrorPad=function(){return(Mf=s._MirrorPad=s.asm.MirrorPad).apply(null,arguments)},$f=s._Multiply=function(){return($f=s._Multiply=s.asm.Multiply).apply(null,arguments)},_f=s._Neg=function(){return(_f=s._Neg=s.asm.Neg).apply(null,arguments)},Pf=s._NonMaxSuppressionV3=function(){return(Pf=s._NonMaxSuppressionV3=s.asm.NonMaxSuppressionV3).apply(null,arguments)},Ff=s._NonMaxSuppressionV4=function(){return(Ff=s._NonMaxSuppressionV4=s.asm.NonMaxSuppressionV4).apply(null,arguments)},Of=s._NonMaxSuppressionV5=function(){return(Of=s._NonMaxSuppressionV5=s.asm.NonMaxSuppressionV5).apply(null,arguments)},Df=s._NotEqual=function(){return(Df=s._NotEqual=s.asm.NotEqual).apply(null,arguments)},zf=s._OneHot=function(){return(zf=s._OneHot=s.asm.OneHot).apply(null,arguments)},Lf=s._PadV2=function(){return(Lf=s._PadV2=s.asm.PadV2).apply(null,arguments)},Bf=s._Pow=function(){return(Bf=s._Pow=s.asm.Pow).apply(null,arguments)},Wf=s._Prelu=function(){return(Wf=s._Prelu=s.asm.Prelu).apply(null,arguments)},Vf=s._Prod=function(){return(Vf=s._Prod=s.asm.Prod).apply(null,arguments)},Uf=s._RealDiv=function(){return(Uf=s._RealDiv=s.asm.RealDiv).apply(null,arguments)},Gf=s._Reciprocal=function(){return(Gf=s._Reciprocal=s.asm.Reciprocal).apply(null,arguments)},Hf=s._Relu=function(){return(Hf=s._Relu=s.asm.Relu).apply(null,arguments)},jf=s._Relu6=function(){return(jf=s._Relu6=s.asm.Relu6).apply(null,arguments)},qf=s._ResizeBilinear=function(){return(qf=s._ResizeBilinear=s.asm.ResizeBilinear).apply(null,arguments)},Xf=s._ResizeNearestNeighbor=function(){return(Xf=s._ResizeNearestNeighbor=s.asm.ResizeNearestNeighbor).apply(null,arguments)},Kf=s._Reverse=function(){return(Kf=s._Reverse=s.asm.Reverse).apply(null,arguments)},Zf=s._RotateWithOffset=function(){return(Zf=s._RotateWithOffset=s.asm.RotateWithOffset).apply(null,arguments)},Yf=s._Round=function(){return(Yf=s._Round=s.asm.Round).apply(null,arguments)},Jf=s._Rsqrt=function(){return(Jf=s._Rsqrt=s.asm.Rsqrt).apply(null,arguments)},Qf=s._ScatterNd=function(){return(Qf=s._ScatterNd=s.asm.ScatterNd).apply(null,arguments)},em=s._SelectV2=function(){return(em=s._SelectV2=s.asm.SelectV2).apply(null,arguments)},tm=s._Sigmoid=function(){return(tm=s._Sigmoid=s.asm.Sigmoid).apply(null,arguments)},am=s._Sin=function(){return(am=s._Sin=s.asm.Sin).apply(null,arguments)},nm=s._Softmax=function(){return(nm=s._Softmax=s.asm.Softmax).apply(null,arguments)},rm=s._SparseFillEmptyRows=function(){return(rm=s._SparseFillEmptyRows=s.asm.SparseFillEmptyRows).apply(null,arguments)},sm=s._SparseReshape=function(){return(sm=s._SparseReshape=s.asm.SparseReshape).apply(null,arguments)},im=s._SparseSegmentReduction=function(){return(im=s._SparseSegmentReduction=s.asm.SparseSegmentReduction).apply(null,arguments)},om=s._Sqrt=function(){return(om=s._Sqrt=s.asm.Sqrt).apply(null,arguments)},lm=s._Square=function(){return(lm=s._Square=s.asm.Square).apply(null,arguments)},um=s._SquaredDifference=function(){return(um=s._SquaredDifference=s.asm.SquaredDifference).apply(null,arguments)},dm=s._Step=function(){return(dm=s._Step=s.asm.Step).apply(null,arguments)},pm=s._StridedSlice=function(){return(pm=s._StridedSlice=s.asm.StridedSlice).apply(null,arguments)},cm=s._Sub=function(){return(cm=s._Sub=s.asm.Sub).apply(null,arguments)},hm=s._Sum=function(){return(hm=s._Sum=s.asm.Sum).apply(null,arguments)},fm=s._Tan=function(){return(fm=s._Tan=s.asm.Tan).apply(null,arguments)},mm=s._Tanh=function(){return(mm=s._Tanh=s.asm.Tanh).apply(null,arguments)},gm=s._Tile=function(){return(gm=s._Tile=s.asm.Tile).apply(null,arguments)},xm=s._TopK=function(){return(xm=s._TopK=s.asm.TopK).apply(null,arguments)},Am=s._Transform=function(){return(Am=s._Transform=s.asm.Transform).apply(null,arguments)},ym=s._Transpose=function(){return(ym=s._Transpose=s.asm.Transpose).apply(null,arguments)},bm=s.__FusedMatMul=function(){return(bm=s.__FusedMatMul=s.asm._FusedMatMul).apply(null,arguments)},vm=s._malloc=function(){return(vm=s._malloc=s.asm.malloc).apply(null,arguments)},wm=s._free=function(){return(wm=s._free=s.asm.free).apply(null,arguments)},km=s.___errno_location=function(){return(km=s.___errno_location=s.asm.__errno_location).apply(null,arguments)},Xp=s.stackSave=function(){return(Xp=s.stackSave=s.asm.stackSave).apply(null,arguments)},Kp=s.stackRestore=function(){return(Kp=s.stackRestore=s.asm.stackRestore).apply(null,arguments)},Lu=s.stackAlloc=function(){return(Lu=s.stackAlloc=s.asm.stackAlloc).apply(null,arguments)},Im=s.dynCall_iijjiiii=function(){return(Im=s.dynCall_iijjiiii=s.asm.dynCall_iijjiiii).apply(null,arguments)},Sm=s.dynCall_jiji=function(){return(Sm=s.dynCall_jiji=s.asm.dynCall_jiji).apply(null,arguments)};s.cwrap=Dp;var jo;Ua=function X(){jo||Zp(),jo||(Ua=X)};function Zp(X){if(X=X||p,dt>0||(Ft(),dt>0))return;function ie(){jo||(jo=!0,s.calledRun=!0,!L&&(sn(),i(s),s.onRuntimeInitialized&&s.onRuntimeInitialized(),aa()))}s.setStatus?(s.setStatus("Running..."),setTimeout(function(){setTimeout(function(){s.setStatus("")},1),ie()},1)):ie()}if(s.preInit)for(typeof s.preInit=="function"&&(s.preInit=[s.preInit]);s.preInit.length>0;)s.preInit.pop()();Zp();var qo;l&&(qo={uncaughtException:process.listeners("uncaughtException").filter(function(X){return!l.uncaughtException.indexOf(X)>-1}),unhandledRejection:process.listeners("unhandledRejection").filter(function(X){return!l.unhandledRejection.indexOf(X)>-1})});var Xo;if(typeof r!="undefined")Xo=r;else if(typeof WasmBackendModuleThreadedSimd!="undefined")Xo=WasmBackendModuleThreadedSimd;else throw new Error("Could not find wasm module in post.js");if(qo){var Tm=Xo._dispose;Xo._dispose=function(){Tm(),qo.uncaughtException.forEach(function(X){process.removeListener("uncaughtException",X)}),qo.unhandledRejection.forEach(function(X){process.removeListener("unhandledRejection",X)})}}return r.ready}})();typeof e=="object"&&typeof t=="object"?t.exports=a:typeof define=="function"&&define.amd?define([],function(){return a}):typeof e=="object"&&(e.WasmBackendModule=a)}),vd=class{constructor(e,t){this.backend=e,this.dataMover=t,this.data=new WeakMap,this.dataIdsCount=0}get(e){return this.data.has(e)||this.dataMover.moveData(this.backend,e),this.data.get(e)}set(e,t){this.dataIdsCount++,this.data.set(e,t)}has(e){return this.data.has(e)}delete(e){return this.dataIdsCount--,this.data.delete(e)}numDataIds(){return this.dataIdsCount}},bl=class{refCount(e){return Ha("refCount")}incRef(e){return Ha("incRef")}timerAvailable(){return!0}time(e){return Ha("time")}read(e){return Ha("read")}readSync(e){return Ha("readSync")}readToGPU(e,t){return Ha("readToGPU")}numDataIds(){return Ha("numDataIds")}disposeData(e,t){return Ha("disposeData")}write(e,t,a){return Ha("write")}move(e,t,a,n,r){return Ha("move")}createTensorFromTexture(e,t,a){return Ha("createTensorFromTexture")}memory(){return Ha("memory")}floatPrecision(){return Ha("floatPrecision")}epsilon(){return this.floatPrecision()===32?1e-7:1e-4}dispose(){return Ha("dispose")}};function Ha(e){throw new Error(`'${e}' not yet implemented or not found in the registry. This kernel may not be supported by the tfjs backend you have chosen`)}function sA(e){let t=e.length,a=0;for(;t>0;)a=Math.random()*t|0,t--,kc(e,t,a)}function iS(e,t){if(e.length!==t.length)throw new Error(`Array sizes must match to be shuffled together First array length was ${e.length}Second array length was ${t.length}`);let a=e.length,n=0;for(;a>0;)n=Math.random()*a|0,a--,kc(e,a,n),kc(t,a,n)}function nd(e,t,a){return Math.max(e,Math.min(t,a))}function oS(e){return e%2===0?e:e+1}function kc(e,t,a){let n=e[t];e[t]=e[a],e[a]=n}function lS(e){let t=0;for(let a=0;aa+` Shapes ${e} and ${t} must match`)}function Xs(e){P(e!=null,()=>"The input to the tensor constructor must be a non-null value.")}function zs(e,t=[],a=!1){if(t==null&&(t=[]),Array.isArray(e)||da(e)&&!a)for(let n=0;n0,a,n){return new Promise((r,s)=>{let i=0,o=()=>{if(e()){r();return}i++;let l=t(i);if(a!=null&&i>=a){s();return}n!=null?n(o,l):setTimeout(o,l)};o()})}function gS(e,t){let a=1,n=-1;for(let s=0;s=0)a*=e[s];else if(e[s]===-1){if(n!==-1)throw Error(`Shapes can only have 1 implicit size. Found -1 at dim ${n} and dim ${s}`);n=s}else if(e[s]<0)throw Error(`Shapes can not be < 0. Found ${e[s]} at dim ${s}`);if(n===-1){if(t>0&&t!==a)throw Error(`Size(${t}) must match the product of shape ${e}`);return e}if(a===0)throw Error(`Cannot infer the missing size in [${e}] when there are 0 elements`);if(t%a!==0)throw Error(`The implicit shape can't be a fractional number. Got ${t} / ${a}`);let r=e.slice();return r[n]=t/a,r}function wd(e,t){let a=t.length;return e=e==null?t.map((n,r)=>r):[].concat(e),P(e.every(n=>n>=-a&&n`All values in axis param must be in range [-${a}, ${a}) but got axis ${e}`),P(e.every(n=>ol(n)),()=>`All values in axis param must be integers but got axis ${e}`),e.map(n=>n<0?a+n:n)}function iA(e,t){let a=[],n=[],r=t!=null&&Array.isArray(t)&&t.length===0,s=t==null||r?null:wd(t,e).sort(),i=0;for(let o=0;oo)&&e[o]===1&&(a.push(e[o]),n.push(o)),s[i]<=o&&i++}e[o]!==1&&(a.push(e[o]),n.push(o))}return{newShape:a,keptDims:n}}function oA(e,t){let a=null;if(e==null||e==="float32")a=new Float32Array(t);else if(e==="int32")a=new Int32Array(t);else if(e==="bool")a=new Uint8Array(t);else throw new Error(`Unknown data type ${e}`);return a}function lA(e,t){let a=null;if(e==null||e==="float32")a=new Float32Array(t);else if(e==="int32")a=new Int32Array(t);else if(e==="bool")a=new Uint8Array(t);else if(e==="string")a=new Array(t);else throw new Error(`Unknown data type ${e}`);return a}function uA(e,t){for(let a=0;at+=a.length),t}function Lr(e){return typeof e=="string"||e instanceof String}function cA(e){return typeof e=="boolean"}function hA(e){return typeof e=="number"}function Uc(e){return Array.isArray(e)?Uc(e[0]):e instanceof Float32Array?"float32":e instanceof Int32Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray?"int32":hA(e)?"float32":Lr(e)?"string":cA(e)?"bool":"float32"}function Hr(e){return!!(e&&e.constructor&&e.call&&e.apply)}function Ic(e,t){for(let a=t;a=0;--n)a[n]=a[n+1]*e[n+1];return a}function fA(e,t,a,n=!1){let r=new Array;if(t.length===1){let s=t[0]*(n?2:1);for(let i=0;il*u)*(n?2:1);for(let l=0;lr*s)*(a?2:1);if(n===0)return[];if(n!==t.length)throw new Error(`[${e}] does not match the input size ${t.length}${a?" for a complex tensor":""}.`);return fA(0,e,t,a)}function L1(e,t){let a=Gc(e,t);for(let n=0;nn*r,1);if(t==null||t==="float32")return al(e,new Float32Array(a));if(t==="int32")return al(e,new Int32Array(a));if(t==="bool")return al(e,new Uint8Array(a));throw new Error(`Unknown data type ${t}`)}function Ja(e){e.forEach(t=>{P(Number.isInteger(t)&&t>=0,()=>`Tensor must have a shape comprised of positive integers but got shape [${e}].`)})}function yS(e,t,a){if(t===0)return 0;if(t===1)return e[0];let n=e[e.length-1];for(let r=0;r{let[a,n]=t.split(":");this.urlFlags[a]=kS(a,n)})}};function vS(e){let t={};return e.replace(/[?&]([^=?&]+)(?:=([^&]*))?/g,(a,...n)=>(wS(t,n[0],n[1]),n.join("="))),t}function wS(e,t,a){e[decodeURIComponent(t)]=decodeURIComponent(a||"")}function kS(e,t){if(t=t.toLowerCase(),t==="true"||t==="false")return t==="true";if(`${+t}`===t)return+t;throw new Error(`Could not parse value flag value ${t} for flag ${e}.`)}function W(){return W1}var W1=null;function IS(e){W1=e}var Mm;function gA(){if(Mm==null){let e;if(typeof window!="undefined")e=window;else if(typeof global!="undefined")e=global;else if(typeof process!="undefined")e=process;else if(typeof self!="undefined")e=self;else throw new Error("Could not find a global object");Mm=e}return Mm}function SS(){let e=gA();return e._tfGlobals==null&&(e._tfGlobals=new Map),e._tfGlobals}function V1(e,t){let a=SS();if(a.has(e))return a.get(e);{let n=t();return a.set(e,n),a.get(e)}}var wl="Abs",kl="Acos",Il="Acosh",ts="Add",Ks="AddN",Zs="All",Ys="Any",Js="ArgMax",kd="ArgMin",Sl="Asin",Tl="Asinh",Cl="Atan",Nl="Atanh",El="Atan2",Qs="AvgPool",U1="AvgPoolGrad",Hc="AvgPool3D",G1="AvgPool3DGrad",ei="BatchMatMul",Rl="BatchToSpaceND",Id="Bincount",TS="BroadcastTo",jc="BroadcastArgs",ti="Cast",ai="Ceil",as="ClipByValue",Sd="Complex",qc="ComplexAbs",Ml="Concat",ni="Conv2D",Xc="Conv2DBackpropFilter",ri="Conv2DBackpropInput",Kc="Conv3D",H1="Conv3DBackpropFilterV2",Zc="Conv3DBackpropInputV2",si="Cos",ii="Cosh",oi="Cumprod",li="Cumsum",ui="CropAndResize",Td="DenseBincount",di="DepthToSpace",pi="DepthwiseConv2dNative",Yc="DepthwiseConv2dNativeBackpropFilter",Jc="DepthwiseConv2dNativeBackpropInput",Qc="Diag",eh="Dilation2D",Um="Dilation2DBackpropInput",Gm="Dilation2DBackpropFilter",ci="RealDiv",Cd="Einsum",hi="Elu",j1="EluGrad",$l="Erf",fi="Equal",mi="Exp",_l="ExpandDims",Pl="Expm1",Nd="FFT",Fl="Fill",gi="FlipLeftRight",xi="Floor",Ai="FloorDiv",yi="FusedBatchNorm",Ol="GatherV2",bi="GatherNd",vi="Greater",wi="GreaterEqual",ki="Identity",Ed="IFFT",Rd="Imag",Dl="IsFinite",zl="IsInf",Ii="IsNan",Si="LeakyRelu",Ti="Less",Ci="LessEqual",th="LinSpace",Ni="Log",Ll="Log1p",Ei="LogicalAnd",Ri="LogicalNot",Bl="LogicalOr",xA="LogicalXor",CS="LogSoftmax",NS="LowerBound",ah="LRN",q1="LRNGrad",Mi="Max",$i="Maximum",_i="MaxPool",X1="MaxPoolGrad",nh="MaxPool3D",K1="MaxPool3DGrad",rh="MaxPoolWithArgmax",Pi="Mean",Fi="Min",Oi="Minimum",Di="MirrorPad",Wl="Mod",sh="Multinomial",zi="Multiply",Vl="Neg",Li="NotEqual",Bi="NonMaxSuppressionV3",Ul="NonMaxSuppressionV4",Wi="NonMaxSuppressionV5",Gl="OnesLike",Vi="OneHot",Hl="Pack",Ui="PadV2",ES="Pool",Gi="Pow",Hi="Prelu",ji="Prod",ih="RaggedGather",oh="RaggedRange",lh="RaggedTensorToTensor",jl="Range",Md="Real",qi="Reciprocal",Xi="Relu",ql="Reshape",Ki="ResizeNearestNeighbor",Z1="ResizeNearestNeighborGrad",Zi="ResizeBilinear",Y1="ResizeBilinearGrad",Yi="Relu6",Ji="Reverse",Xl="Round",Qi="Rsqrt",eo="ScatterNd",$d="SearchSorted",Kl="Select",_d="Selu",Zl="Slice",to="Sin",Yl="Sinh",Pd="Sign",ao="Sigmoid",Fd="Softplus",no="Sqrt",ro="Sum",Jl="SpaceToBatchND",Ql="SplitV",so="Softmax",Od="SparseFillEmptyRows",eu="SparseReshape",Dd="SparseSegmentMean",zd="SparseSegmentSum",Ld="SparseToDense",io="SquaredDifference",Bd="Square",oo="StridedSlice",tu="StringNGrams",Wd="StringSplit",Vd="StringToHashBucketFast",lo="Sub",uo="Tan",po="Tanh",ns="Tile",co="TopK",ho="Transform",Ar="Transpose",uh="Unique",au="Unpack",dh="UnsortedSegmentSum",RS="UpperBound",nu="ZerosLike",fo="Step",rd="FromPixels",mo="RotateWithOffset",jr="_FusedMatMul",qr="FusedConv2D",Xr="FusedDepthwiseConv2D";function zr(...e){W().getBool("IS_TEST")||W().getBool("PROD")||console.warn(...e)}function MS(...e){W().getBool("IS_TEST")||W().getBool("PROD")||console.log(...e)}var ll=V1("kernelRegistry",()=>new Map),sd=V1("gradRegistry",()=>new Map);function Sc(e,t){let a=J1(e,t);return ll.get(a)}function Hm(e){return sd.get(e)}function Zn(e){let t=ll.entries(),a=[];for(;;){let{done:n,value:r}=t.next();if(n)break;let[s,i]=r,[o]=s.split("_");o===e&&a.push(i)}return a}function mn(e){let{kernelName:t,backendName:a}=e,n=J1(t,a);ll.has(n)&&zr(`The kernel '${t}' for backend '${a}' is already registered`),ll.set(n,e)}function $S(e){let{kernelName:t}=e;sd.has(t)&&W().getBool("DEBUG")&&zr(`Overriding the gradient for '${t}'`),sd.set(t,e)}function _S(e,t){let a=J1(e,t);if(!ll.has(a))throw new Error(`The kernel '${e}' for backend '${t}' is not registered`);ll.delete(a)}function PS(e){if(!sd.has(e))throw new Error(`The gradient '${e}' for backend is not registered`);sd.delete(e)}function FS(e,t){Zn(e).forEach(a=>{let n=Object.assign({},a,{backendName:t});mn(n)})}function J1(e,t){return`${t}_${e}`}var v={};Xe(v,{arraysEqual:()=>es,assert:()=>P,assertNonNegativeIntegerDimensions:()=>Ja,assertNonNull:()=>Xs,assertShapesMatch:()=>Sa,bytesFromStringArray:()=>pA,bytesPerElement:()=>Vm,checkConversionForErrors:()=>uA,clamp:()=>nd,computeStrides:()=>vl,createScalarValue:()=>WS,createShuffledIndices:()=>fS,decodeString:()=>Tc,distSquared:()=>dS,encodeString:()=>Gd,fetch:()=>US,fingerPrint64:()=>BS,flatten:()=>zs,getArrayFromDType:()=>lA,getTypedArrayFromDType:()=>oA,hasEncodingLoss:()=>xS,hexToLong:()=>Ud,indexToLoc:()=>bS,inferDtype:()=>Uc,inferFromImplicitShape:()=>gS,isBoolean:()=>cA,isFunction:()=>Hr,isInt:()=>ol,isNumber:()=>hA,isPromise:()=>B1,isScalarShape:()=>pS,isString:()=>Lr,isTypedArray:()=>da,isValidDtype:()=>dA,locToIndex:()=>yS,makeOnesTypedArray:()=>L1,makeZerosNestedTypedArray:()=>AS,makeZerosTypedArray:()=>Gc,nearestDivisor:()=>Ic,nearestLargerEven:()=>oS,now:()=>id,parseAxisParam:()=>wd,randUniform:()=>uS,repeatedTry:()=>mS,rightPad:()=>Qu,shuffle:()=>sA,shuffleCombo:()=>iS,sizeFromShape:()=>At,sizeToSquarishShape:()=>hS,squeezeShape:()=>iA,sum:()=>lS,swap:()=>kc,tanh:()=>cS,toNestedArray:()=>al,toTypedArray:()=>ph});var z5=yl(UI()),$s=z5.default||z5;function Ud(e){return $s.fromString(e,!0,16)}var AA=Ud("c3a5c85c97cb3127"),Rs=Ud("b492b66fbe98f273"),Aa=Ud("9ae16a3b2f90404f");function jm(e){return e.xor(e.shru(47))}function yA(e,t,a){let n=e.slice(t,t+a);return $s.fromBytes(Array.from(n),!0,!0)}function ft(e,t){return yA(e,t,8)}function L5(e,t){return yA(e,t,4)}function Kt(e,t){return t===0?e:e.shru(t).or(e.shl(64-t))}function Ur(e,t,a=Ud("9ddfea08eb382d69")){let n=e.xor(t).mul(a);n=n.xor(n.shru(47));let r=t.xor(n).mul(a);return r=r.xor(r.shru(47)),r=r.mul(a),r}function OS(e,t,a,n,r,s){r=r.add(e),s=Kt(s.add(r).add(n),21);let i=r;return r=r.add(t),r=r.add(a),s=s.add(Kt(r,44)),[r.add(n),s.add(i)]}function ic(e,t,a,n){return OS(ft(e,t),ft(e,t+8),ft(e,t+16),ft(e,t+24),a,n)}function DS(e,t=e.length){if(t>=8){let a=Aa.add(t*2),n=ft(e,0).add(Aa),r=ft(e,t-8),s=Kt(r,37).mul(a).add(n),i=Kt(n,25).add(r).mul(a);return Ur(s,i,a)}if(t>=4){let a=Aa.add(t*2),n=L5(e,0);return Ur(n.shl(3).add(t),L5(e,t-4),a)}if(t>0){let a=e[0],n=e[t>>1],r=e[t-1],s=a+(n<<8),i=t+(r<<2);return jm(Aa.mul(s).xor(AA.mul(i))).mul(Aa)}return Aa}function zS(e,t=e.length){let a=Aa.add(t*2),n=ft(e,0).mul(Rs),r=ft(e,8),s=ft(e,t-8).mul(a),i=ft(e,t-16).mul(Aa);return Ur(Kt(n.add(r),43).add(Kt(s,30)).add(i),n.add(Kt(r.add(Aa),18)).add(s),a)}function LS(e,t=e.length){let a=Aa.add(t*2),n=ft(e,0).mul(Aa),r=ft(e,8),s=ft(e,t-8).mul(a),i=ft(e,t-16).mul(Aa),o=Kt(n.add(r),43).add(Kt(s,30)).add(i),l=Ur(o,n.add(Kt(r.add(Aa),18)).add(s),a),u=ft(e,16).mul(a),p=ft(e,24),c=o.add(ft(e,t-32)).mul(a),d=l.add(ft(e,t-24)).mul(a);return Ur(Kt(u.add(p),43).add(Kt(c,30)).add(d),u.add(Kt(p.add(n),18)).add(c),a)}function BS(e,t=e.length){let a=$s.fromNumber(81,!0);if(t<=32)return t<=16?DS(e,t):zS(e,t);if(t<=64)return LS(e,t);let n=a,r=a.mul(Rs).add(113),s=jm(r.mul(Aa).add(113)).mul(Aa),i=[$s.UZERO,$s.UZERO],o=[$s.UZERO,$s.UZERO];n=n.mul(Aa).add(ft(e,0));let l=0,u=(t-1>>6)*64,p=u+(t-1&63)-63;do n=Kt(n.add(r).add(i[0]).add(ft(e,l+8)),37).mul(Rs),r=Kt(r.add(i[1]).add(ft(e,l+48)),42).mul(Rs),n=n.xor(o[1]),r=r.add(i[0]).add(ft(e,l+40)),s=Kt(s.add(o[0]),33).mul(Rs),i=ic(e,l,i[1].mul(Rs),n.add(o[0])),o=ic(e,l+32,s.add(o[1]),r.add(ft(e,l+16))),[s,n]=[n,s],l+=64;while(l!==u);let c=Rs.add(s.and(255).shl(1));return l=p,o[0]=o[0].add(t-1&63),i[0]=i[0].add(o[0]),o[0]=o[0].add(i[0]),n=Kt(n.add(r).add(i[0]).add(ft(e,l+8)),37).mul(c),r=Kt(r.add(i[1]).add(ft(e,l+48)),42).mul(c),n=n.xor(o[1].mul(9)),r=r.add(i[0].mul(9).add(ft(e,l+40))),s=Kt(s.add(o[0]),33).mul(c),i=ic(e,l,i[1].mul(c),n.add(o[0])),o=ic(e,l+32,s.add(o[1]),r.add(ft(e,l+16))),[s,n]=[n,s],Ur(Ur(i[0],o[0],c).add(jm(r).mul(AA)).add(s),Ur(i[1],o[1],c).add(n),c)}function WS(e,t){return t==="string"?Gd(e):ph([e],t)}function VS(e,t){return e instanceof Float32Array&&t==="float32"||e instanceof Int32Array&&t==="int32"||e instanceof Uint8Array&&t==="bool"}function ph(e,t){if(t==="string")throw new Error("Cannot convert a string[] to a TypedArray");if(Array.isArray(e)&&(e=zs(e)),W().getBool("DEBUG")&&uA(e,t),VS(e,t))return e;if(t==null||t==="float32"||t==="complex64")return new Float32Array(e);if(t==="int32")return new Int32Array(e);if(t==="bool"){let a=new Uint8Array(e.length);for(let n=0;n{n=a()},s,i=id();if(this.backendTimer.timerAvailable())s=this.backendTimer.time(r);else{r();for(let o of n)o.dataSync();s=Promise.resolve({kernelMs:id()-i})}if(W().getBool("CHECK_COMPUTATION_FOR_ERRORS"))for(let o=0;o{HS(u,l.dtype,e)})}return{kernelName:e,outputs:n,inputs:t,timeMs:s.then(o=>o.kernelMs),extraInfo:s.then(o=>o.getExtraProfileInfo!=null?o.getExtraProfileInfo():"")}}logKernelProfile(e){let{kernelName:t,outputs:a,timeMs:n,inputs:r,extraInfo:s}=e;a.forEach(i=>{Promise.all([i.data(),n,s]).then(o=>{this.logger.logKernelProfile(t,i,o[0],o[1],r,o[2])})})}};function HS(e,t,a){if(t!=="float32")return!1;for(let n=0;n0?f:""} `}}console.log(`%c${o} %c${i} %c${l}D ${p} %c${u} %c${c} %c${s}`,"font-weight:bold","color:red","color:blue","color: orange","color: green","color: steelblue")}};function qS(e,t,a){let n={},r={};for(let l=0;ln[m.id]=!0),h=!0,r[u.id]=!0;break}if(h)break}}let s={};s[a.id]=!0;let i={};for(let l=e.length-1;l>=0;l--){let u=e[l],p=u.inputs;for(let c=0;c=0;r--){let s=t[r],i=[];if(s.outputs.forEach(l=>{let u=e[l.id];u!=null?i.push(u):i.push(null)}),s.gradient==null)throw new Error(`Cannot compute gradient: gradient function not found for ${s.kernelName}.`);let o=s.gradient(i);for(let l in s.inputs){if(!(l in o))throw new Error(`Cannot backprop through input ${l}. Available gradients found: ${Object.keys(o)}.`);let u=a(()=>o[l]());if(u.dtype!=="float32")throw new Error(`Error in gradient for op ${s.kernelName}. The gradient of input ${l} must have 'float32' dtype, but has '${u.dtype}'`);let p=s.inputs[l];if(!es(u.shape,p.shape))throw new Error(`Error in gradient for op ${s.kernelName}. The gradient of input '${l}' has shape '${u.shape}', which does not match the shape of the input '${p.shape}'`);if(e[p.id]==null)e[p.id]=u;else{let c=e[p.id];e[p.id]=n(c,u),c.dispose()}}}}var B5=20,Wu=3,$m=7;function KS(e,t,a,n){let r=vl(t),s=ZS(e,t,a,r),i=t.length,o=hc(e,t,a,r,s),l=["Tensor"];return n&&(l.push(` dtype: ${a}`),l.push(` rank: ${i}`),l.push(` shape: [${t}]`),l.push(" values:")),l.push(o.map(u=>" "+u).join(` `)),l.join(` `)}function ZS(e,t,a,n){let r=At(t),s=n[n.length-1],i=new Array(s).fill(0),o=t.length,l=a==="complex64"?Gu(e):e;if(o>1)for(let u=0;uB5){let m=Wu*i,g=Array.from(e.slice(0,m)),x=Array.from(e.slice((o-Wu)*i,o*i));return a==="complex64"&&(g=Gu(g),x=Gu(x)),["["+g.map((A,y)=>Uu(A,r[y],a)).join(", ")+", ..., "+x.map((A,y)=>Uu(A,r[o-Wu+y],a)).join(", ")+"]"]}return["["+(a==="complex64"?Gu(e):Array.from(e)).map((m,g)=>Uu(m,r[g],a)).join(", ")+"]"]}let u=t.slice(1),p=n.slice(1),c=n[0]*i,d=[];if(o>B5){for(let m=0;m`Length of values '${n}' does not match the size inferred by the shape '${this.size}'.`)}if(t==="complex64")throw new Error("complex64 dtype TensorBuffers are not supported. Please create a TensorBuffer for the real and imaginary parts separately and call tf.complex(real, imag).");this.values=a||lA(t,this.size),this.strides=vl(e)}set(e,...t){t.length===0&&(t=[0]),P(t.length===this.rank,()=>`The number of provided coordinates (${t.length}) must match the rank (${this.rank})`);let a=this.locToIndex(t);this.values[a]=e}get(...e){e.length===0&&(e=[0]);let t=0;for(let n of e){if(n<0||n>=this.shape[t]){let r=`Requested out of range element at ${e}. Buffer shape=${this.shape}`;throw new Error(r)}t++}let a=e[e.length-1];for(let n=0;nTc(a))}catch(a){throw new Error("Failed to decode the string bytes into utf-8. To get the original bytes, call tensor.bytes().")}}return e}dataToGPU(e){return this.throwIfDisposed(),Fn().readToGPU(this.dataId,e)}dataSync(){this.throwIfDisposed();let e=Fn().readSync(this.dataId);if(this.dtype==="string")try{return e.map(t=>Tc(t))}catch(t){throw new Error("Failed to decode the string bytes into utf-8. To get the original bytes, call tensor.bytes().")}return e}async bytes(){this.throwIfDisposed();let e=await Fn().read(this.dataId);return this.dtype==="string"?e:new Uint8Array(e.buffer)}dispose(){this.isDisposed||(Fn().disposeTensor(this),this.isDisposedInternal=!0)}get isDisposed(){return this.isDisposedInternal}throwIfDisposed(){if(this.isDisposed)throw new Error("Tensor is disposed.")}print(e=!1){return Qo.print(this,e)}clone(){return this.throwIfDisposed(),Qo.clone(this)}toString(e=!1){let t=this.dataSync();return KS(t,this.shape,this.dtype,e)}cast(e){return this.throwIfDisposed(),Qo.cast(this,e)}variable(e=!0,t,a){return this.throwIfDisposed(),Fn().makeVariable(this,e,t,a)}};Object.defineProperty(pt,Symbol.hasInstance,{value:e=>!!e&&e.data!=null&&e.dataSync!=null&&e.throwIfDisposed!=null});function tT(){return V1("Tensor",()=>pt)}tT();var od=class extends pt{constructor(e,t,a,n){super(e.shape,e.dtype,e.dataId,n),this.trainable=t,this.name=a}assign(e){if(e.dtype!==this.dtype)throw new Error(`dtype of the new value (${e.dtype}) and previous value (${this.dtype}) must match`);if(!es(e.shape,this.shape))throw new Error(`shape of the new value (${e.shape}) and previous value (${this.shape}) must match`);Fn().disposeTensor(this),this.dataId=e.dataId,Fn().incRef(this,null)}dispose(){Fn().disposeVariable(this),this.isDisposedInternal=!0}};Object.defineProperty(od,Symbol.hasInstance,{value:e=>e instanceof pt&&e.assign!=null&&e.assign instanceof Function});var vA={};Xe(vA,{assertTypesMatch:()=>wA,getTensorsInContainer:()=>Q1,isTensorInList:()=>nT,makeTypesMatch:()=>St});var qm;(function(e){e.R0="R0",e.R1="R1",e.R2="R2",e.R3="R3",e.R4="R4",e.R5="R5",e.R6="R6"})(qm||(qm={}));var Xm;(function(e){e.float32="float32",e.int32="int32",e.bool="int32",e.complex64="complex64"})(Xm||(Xm={}));var Km;(function(e){e.float32="float32",e.int32="int32",e.bool="bool",e.complex64="complex64"})(Km||(Km={}));var Zm;(function(e){e.float32="float32",e.int32="float32",e.bool="float32",e.complex64="complex64"})(Zm||(Zm={}));var Ym;(function(e){e.float32="complex64",e.int32="complex64",e.bool="complex64",e.complex64="complex64"})(Ym||(Ym={}));var aT={float32:Zm,int32:Xm,bool:Km,complex64:Ym};function ca(e,t){if(e==="string"||t==="string"){if(e==="string"&&t==="string")return"string";throw new Error(`Can not upcast ${e} with ${t}`)}return aT[e][t]}function Hd(e){return ca(e,"int32")}function St(e,t){if(e.dtype===t.dtype)return[e,t];let a=ca(e.dtype,t.dtype);return[e.cast(a),t.cast(a)]}function wA(e,t){P(e.dtype===t.dtype,()=>`The dtypes of the first(${e.dtype}) and second(${t.dtype}) input must match`)}function nT(e,t){return t.some(a=>a.id===e.id)}function Q1(e){let t=[];return kA(e,t,new Set),t}function kA(e,t,a){if(e==null)return;if(e instanceof pt){t.push(e);return}if(!rT(e))return;let n=e;for(let r in n){let s=n[r];a.has(s)||(a.add(s),kA(s,t,a))}}function rT(e){return Array.isArray(e)||typeof e=="object"}function _m(e){return e.kernelName!=null}var W5=class{constructor(){this.registeredVariables={},this.nextTapeNodeId=0,this.numBytes=0,this.numTensors=0,this.numStringTensors=0,this.numDataBuffers=0,this.gradientDepth=0,this.kernelDepth=0,this.scopeStack=[],this.numDataMovesStack=[],this.nextScopeId=0,this.tensorInfo=new WeakMap,this.profiling=!1,this.activeProfile={newBytes:0,newTensors:0,peakBytes:0,kernels:[],result:null,get kernelNames(){return Array.from(new Set(this.kernels.map(e=>e.name)))}}}dispose(){for(let e in this.registeredVariables)this.registeredVariables[e].dispose()}},ld=class{constructor(e){this.ENV=e,this.registry={},this.registryFactory={},this.pendingBackendInitId=0,this.state=new W5}async ready(){if(this.pendingBackendInit!=null)return this.pendingBackendInit.then(()=>{});if(this.backendInstance!=null)return;let e=this.getSortedBackends();for(let t=0;t{e.setupFunc!=null&&e.setupFunc(this.backendInstance)})}disposeRegisteredKernels(e){Zn(e).forEach(t=>{t.disposeFunc!=null&&t.disposeFunc(this.registry[e])})}initializeBackend(e){let t=this.registryFactory[e];if(t==null)throw new Error(`Cannot initialize backend ${e}, no registration found.`);try{let a=t.factory();if(a&&!(a instanceof bl)&&typeof a.then=="function"){let n=++this.pendingBackendInitId,r=a.then(s=>n(nthis.registryFactory[t].priority-this.registryFactory[e].priority)}initializeBackendsAndReturnBest(){let e=this.getSortedBackends();for(let t=0;tthis.startScope(a),()=>this.endScope(n),()=>(n=t(),n instanceof Promise&&console.error("Cannot return a Promise inside of tidy."),n))}scopedRun(e,t,a){e();try{let n=a();return t(),n}catch(n){throw t(),n}}nextTensorId(){return ld.nextTensorId++}nextVariableId(){return ld.nextVariableId++}clone(e){let t=z.runKernel(ki,{x:e}),a={x:e},n=s=>({x:()=>{let i="float32",o={x:s},l={dtype:i};return z.runKernel(ti,o,l)}}),r=[];return this.addTapeNode(this.state.activeScope.name,a,[t],n,r,{}),t}runKernel(e,t,a){if(this.backendName==null&&this.backend,Sc(e,this.backendName)==null)throw new Error(`Kernel '${e}' not registered for backend '${this.backendName}'`);return this.runKernelFunc({kernelName:e,inputs:t,attrs:a})}shouldCheckForMemLeaks(){return this.ENV.getBool("IS_TEST")}checkKernelForMemLeak(e,t,a){let n=this.backend.numDataIds(),r=0;a.forEach(o=>{r+=o.dtype==="complex64"?3:1});let s=this.state.numDataMovesStack[this.state.numDataMovesStack.length-1],i=n-t-r-s;if(i>0)throw new Error(`Backend '${this.backendName}' has an internal memory leak (${i} data ids) after running '${e}'`)}runKernelFunc(e){let t,a=[],n=this.isTapeOn(),r=this.state.numBytes,s=this.state.numTensors;this.shouldCheckForMemLeaks()&&this.state.numDataMovesStack.push(0);let i;this.backendName==null&&this.backend;let o,l=_m(e)?e.kernelName:this.state.activeScope!=null?this.state.activeScope.name:"";if(_m(e)){let{kernelName:h,inputs:f,attrs:m}=e;this.backendName==null&&this.backend;let g=Sc(h,this.backendName);P(g!=null,()=>`Cannot find registered kernel '${h}' for backend '${this.backendName}'`),i=()=>{let x=this.backend.numDataIds();o=g.kernelFunc({inputs:f,attrs:m,backend:this.backend});let A=Array.isArray(o)?o:[o];this.shouldCheckForMemLeaks()&&this.checkKernelForMemLeak(h,x,A);let y=A.map(b=>b.rank!=null?b:this.makeTensorFromTensorInfo(b));if(n){let b=this.getTensorsForGradient(h,f,y);a=this.saveTensorsForBackwardMode(b)}return y}}else{let{forwardFunc:h}=e,f=m=>{!n||(a=m.map(g=>this.keep(this.clone(g))))};i=()=>{let m=this.backend.numDataIds();o=this.tidy(()=>h(this.backend,f));let g=Array.isArray(o)?o:[o];return this.shouldCheckForMemLeaks()&&this.checkKernelForMemLeak(l,m,g),g}}let{inputs:u,attrs:p}=e,c=_m(e)?null:e.backwardsFunc,d;return this.scopedRun(()=>this.state.kernelDepth++,()=>this.state.kernelDepth--,()=>{!this.ENV.getBool("DEBUG")&&!this.state.profiling?t=i():(d=this.profiler.profileKernel(l,u,()=>i()),this.ENV.getBool("DEBUG")&&this.profiler.logKernelProfile(d),t=d.outputs)}),n&&this.addTapeNode(l,u,t,c,a,p),this.state.profiling&&this.state.activeProfile.kernels.push({name:l,bytesAdded:this.state.numBytes-r,totalBytesSnapshot:this.state.numBytes,tensorsAdded:this.state.numTensors-s,totalTensorsSnapshot:this.state.numTensors,inputShapes:Object.keys(u).map(h=>u[h]!=null?u[h].shape:null),outputShapes:t.map(h=>h.shape),kernelTimeMs:d.timeMs,extraInfo:d.extraInfo}),Array.isArray(o)?t:t[0]}saveTensorsForBackwardMode(e){return e.map(t=>this.keep(this.clone(t)))}getTensorsForGradient(e,t,a){let n=Hm(e);if(n!=null){let r=n.inputsToSave||[],s=n.outputsToSave||[],i;n.saveAllInputs?(P(Array.isArray(t),()=>"saveAllInputs is true, expected inputs to be an array."),i=Object.keys(t).map(l=>t[l])):i=r.map(l=>t[l]);let o=a.filter((l,u)=>s[u]);return i.concat(o)}return[]}makeTensor(e,t,a,n){if(e==null)throw new Error("Values passed to engine.makeTensor() are null");a=a||"float32",n=n||this.backend;let r=e;a==="string"&&Lr(e[0])&&(r=e.map(o=>Gd(o)));let s=n.write(r,t,a),i=new pt(t,a,s,this.nextTensorId());if(this.trackTensor(i,n),a==="string"){let o=this.state.tensorInfo.get(s),l=pA(r);this.state.numBytes+=l-o.bytes,o.bytes=l}return i}makeTensorFromDataId(e,t,a,n){a=a||"float32";let r={dataId:e,shape:t,dtype:a};return this.makeTensorFromTensorInfo(r,n)}makeTensorFromTensorInfo(e,t){let{dataId:a,shape:n,dtype:r}=e,s=new pt(n,r,a,this.nextTensorId());return this.trackTensor(s,t),s}makeVariable(e,t=!0,a,n){a=a||this.nextVariableId().toString(),n!=null&&n!==e.dtype&&(e=e.cast(n));let r=new od(e,t,a,this.nextTensorId());if(this.state.registeredVariables[r.name]!=null)throw new Error(`Variable with name ${r.name} was already registered`);return this.state.registeredVariables[r.name]=r,this.incRef(r,this.backend),r}trackTensor(e,t){this.state.numTensors++,e.dtype==="string"&&this.state.numStringTensors++;let a=0;e.dtype!=="complex64"&&e.dtype!=="string"&&(a=e.size*Vm(e.dtype)),this.state.numBytes+=a,this.state.tensorInfo.has(e.dataId)||(this.state.numDataBuffers++,this.state.tensorInfo.set(e.dataId,{backend:t||this.backend,dtype:e.dtype,shape:e.shape,bytes:a})),e instanceof od||this.track(e)}incRef(e,t){this.trackTensor(e,t),this.backend.incRef(e.dataId)}removeDataId(e,t){this.state.tensorInfo.has(e)&&this.state.tensorInfo.get(e).backend===t&&(this.state.tensorInfo.delete(e),this.state.numDataBuffers--)}disposeTensor(e){if(!this.state.tensorInfo.has(e.dataId))return;let t=this.state.tensorInfo.get(e.dataId);if(this.state.numTensors--,e.dtype==="string"&&(this.state.numStringTensors--,this.state.numBytes-=t.bytes),e.dtype!=="complex64"&&e.dtype!=="string"){let a=e.size*Vm(e.dtype);this.state.numBytes-=a}t.backend.disposeData(e.dataId)&&this.removeDataId(e.dataId,t.backend)}disposeVariables(){for(let e in this.state.registeredVariables){let t=this.state.registeredVariables[e];this.disposeVariable(t)}}disposeVariable(e){this.disposeTensor(e),this.state.registeredVariables[e.name]!=null&&delete this.state.registeredVariables[e.name]}memory(){let e=this.backend.memory();return e.numTensors=this.state.numTensors,e.numDataBuffers=this.state.numDataBuffers,e.numBytes=this.state.numBytes,this.state.numStringTensors>0&&(e.unreliable=!0,e.reasons==null&&(e.reasons=[]),e.reasons.push("Memory usage by string tensors is approximate (2 bytes per character)")),e}async profile(e){this.state.profiling=!0;let t=this.state.numBytes,a=this.state.numTensors;this.state.activeProfile.kernels=[],this.state.activeProfile.result=await e(),this.state.profiling=!1,this.state.activeProfile.peakBytes=Math.max(...this.state.activeProfile.kernels.map(n=>n.totalBytesSnapshot)),this.state.activeProfile.newBytes=this.state.numBytes-t,this.state.activeProfile.newTensors=this.state.numTensors-a;for(let n of this.state.activeProfile.kernels)n.kernelTimeMs=await n.kernelTimeMs,n.extraInfo=await n.extraInfo;return this.state.activeProfile}isTapeOn(){return this.state.gradientDepth>0&&this.state.kernelDepth===0}addTapeNode(e,t,a,n,r,s){let i={id:this.state.nextTapeNodeId++,kernelName:e,inputs:t,outputs:a,saved:r},o=Hm(e);o!=null&&(n=o.gradFunc),n!=null&&(i.gradient=l=>(l=l.map((u,p)=>{if(u==null){let c=a[p],d=Gc(c.size,c.dtype);return this.makeTensor(d,c.shape,c.dtype)}return u}),n(l.length>1?l:l[0],r,s))),this.state.activeTape.push(i)}keep(e){return e.kept=!0,e}startTape(){this.state.gradientDepth===0&&(this.state.activeTape=[]),this.state.gradientDepth++}endTape(){this.state.gradientDepth--}startScope(e){let t={track:[],name:"unnamed scope",id:this.state.nextScopeId++};e&&(t.name=e),this.state.scopeStack.push(t),this.state.activeScope=t}endScope(e){let t=Q1(e),a=new Set(t.map(r=>r.id));for(let r=0;r{!r.kept&&r.scopeId===n.id&&this.track(r)})}gradients(e,t,a,n=!1){if(P(t.length>0,()=>"gradients() received an empty list of xs."),a!=null&&a.dtype!=="float32")throw new Error(`dy must have 'float32' dtype, but has '${a.dtype}'`);let r=this.scopedRun(()=>this.startTape(),()=>this.endTape(),()=>this.tidy("forward",e));P(r instanceof pt,()=>"The result y returned by f() must be a tensor.");let s=qS(this.state.activeTape,t,r);if(!n&&s.length===0&&t.length>0)throw new Error("Cannot compute gradient of y=f(x) with respect to x. Make sure that the f you passed encloses all operations that lead from x to y.");return this.tidy("backward",()=>{let i={};i[r.id]=a==null?sT(r.shape):a,XS(i,s,l=>this.tidy(l),iT);let o=t.map(l=>i[l.id]);return this.state.gradientDepth===0&&(this.state.activeTape.forEach(l=>{for(let u of l.saved)u.dispose()}),this.state.activeTape=null),{value:r,grads:o}})}customGrad(e){return P(Hr(e),()=>"The f passed in customGrad(f) must be a function."),(...t)=>{P(t.every(i=>i instanceof pt),()=>"The args passed in customGrad(f)(x1, x2,...) must all be tensors");let a,n={};t.forEach((i,o)=>{n[o]=i});let r=(i,o)=>(a=e(...t,o),P(a.value instanceof pt,()=>"The function f passed in customGrad(f) must return an object where `obj.value` is a tensor"),P(Hr(a.gradFunc),()=>"The function f passed in customGrad(f) must return an object where `obj.gradFunc` is a function."),a.value),s=(i,o)=>{let l=a.gradFunc(i,o),u=Array.isArray(l)?l:[l];P(u.length===t.length,()=>"The function f passed in customGrad(f) must return an object where `obj.gradFunc` is a function that returns the same number of tensors as inputs passed to f(...)."),P(u.every(c=>c instanceof pt),()=>"The function f passed in customGrad(f) must return an object where `obj.gradFunc` is a function that returns a list of only tensors.");let p={};return u.forEach((c,d)=>{p[d]=()=>c}),p};return this.runKernelFunc({forwardFunc:r,backwardsFunc:s,inputs:n})}}readSync(e){return this.state.tensorInfo.get(e).backend.readSync(e)}read(e){return this.state.tensorInfo.get(e).backend.read(e)}readToGPU(e,t){return this.state.tensorInfo.get(e).backend.readToGPU(e,t)}async time(e){let t=id(),a=await this.backend.time(e);return a.wallMs=id()-t,a}track(e){return this.state.activeScope!=null&&(e.scopeId=this.state.activeScope.id,this.state.activeScope.track.push(e)),e}get registeredVariables(){return this.state.registeredVariables}reset(){this.pendingBackendInitId++,this.state.dispose(),this.ENV.reset(),this.state=new W5;for(let e in this.registry)this.disposeRegisteredKernels(e),this.registry[e].dispose(),delete this.registry[e];this.backendName=null,this.backendInstance=null,this.pendingBackendInit=null}};ld.nextTensorId=0;ld.nextVariableId=0;function sT(e){let t=L1(At(e),"float32");return z.makeTensor(t,e,"float32")}function IA(){let e=gA();if(e._tfengine==null){let t=new mA(e);e._tfengine=new ld(t)}return IS(e._tfengine.ENV),JS(()=>e._tfengine),e._tfengine}var z=IA();function iT(e,t){let a={a:e,b:t};return z.runKernel(ts,a)}var jd={};Xe(jd,{isBrowser:()=>SA,isMobile:()=>uT,mockIsMobile:()=>lT});function oT(){return typeof navigator!="undefined"&&navigator!=null}var Jm;function lT(e){Jm=e}function uT(e){if(Jm!==void 0)return Jm;if(e||oT()){if(e||(e=navigator),e.product==="ReactNative")return!0;let t=e.userAgent||e.vendor||(typeof window!="undefined"?window.opera:"");if(!t){let a=e;return a.userAgentData&&a.userAgentData.mobile}return/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(t)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(t.substr(0,4))}return!1}function SA(){return typeof window!="undefined"&&window.document!=null||typeof WorkerGlobalScope!="undefined"}var hn=W();hn.registerFlag("DEBUG",()=>!1,e=>{e&&console.warn("Debugging mode is ON. The output of every math call will be downloaded to CPU and checked for NaNs. This significantly impacts performance.")});hn.registerFlag("IS_BROWSER",()=>SA());hn.registerFlag("IS_NODE",()=>typeof process!="undefined"&&typeof process.versions!="undefined"&&typeof process.versions.node!="undefined");hn.registerFlag("IS_CHROME",()=>typeof navigator!="undefined"&&navigator!=null&&navigator.userAgent!=null&&/Chrome/.test(navigator.userAgent)&&/Google Inc/.test(navigator.vendor));hn.registerFlag("PROD",()=>!1);hn.registerFlag("TENSORLIKE_CHECK_SHAPE_CONSISTENCY",()=>hn.getBool("DEBUG"));hn.registerFlag("DEPRECATION_WARNINGS_ENABLED",()=>!0);hn.registerFlag("IS_TEST",()=>!1);hn.registerFlag("CHECK_COMPUTATION_FOR_ERRORS",()=>!0);hn.registerFlag("WRAP_TO_IMAGEBITMAP",()=>!1);hn.registerFlag("CANVAS2D_WILL_READ_FREQUENTLY_FOR_GPU",()=>!1);hn.registerFlag("USE_SETTIMEOUTCUSTOM",()=>!1);function Yn(e,t){let a=e;if(da(e))return t==="string"?[]:[e.length];if(typeof e=="object"&&"texture"in e){let r=e.channels||"RGBA";return[e.height,e.width*r.length]}if(!Array.isArray(e))return[];let n=[];for(;Array.isArray(a)||da(a)&&t!=="string";)n.push(a.length),a=a[0];return Array.isArray(e)&&W().getBool("TENSORLIKE_CHECK_SHAPE_CONSISTENCY")&&TA(e,n,[]),n}function TA(e,t,a){if(a=a||[],!Array.isArray(e)&&!da(e)){P(t.length===0,()=>`Element arr[${a.join("][")}] is a primitive, but should be an array/TypedArray of ${t[0]} elements`);return}P(t.length>0,()=>`Element arr[${a.join("][")}] should be a primitive, but is an array of ${e.length} elements`),P(e.length===t[0],()=>`Element arr[${a.join("][")}] should have ${t[0]} elements, but has ${e.length} elements`);let n=t.slice(1);for(let r=0;r=0&&(r=n),V5(n,r,t,a),e==null||!da(e)&&!Array.isArray(e)&&typeof e!="number"&&typeof e!="boolean"&&typeof e!="string"){let o=e==null?"null":e.constructor.name;throw new Error(`Argument '${t}' passed to '${a}' must be a Tensor or TensorLike, but got '${o}'`)}let s=Yn(e,r);!da(e)&&!Array.isArray(e)&&(e=[e]);let i=r!=="string"?ph(e,r):zs(e,[],!0);return z.makeTensor(i,s,r)}function ud(e,t,a,n="numeric"){if(!Array.isArray(e))throw new Error(`Argument ${t} passed to ${a} must be a \`Tensor[]\` or \`TensorLike[]\``);return e.map((r,s)=>R(r,`${t}[${s}]`,a,n))}var e2="__op";function D(e){let t=Object.keys(e);if(t.length!==1)throw new Error(`Please provide an object with a single key (operation name) mapping to a function. Got an object with ${t.length} keys.`);let a=t[0],n=e[a];a.endsWith("_")&&(a=a.substring(0,a.length-1)),a=a+e2;let r=(...s)=>{z.startScope(a);try{let i=n(...s);return B1(i)&&console.error("Cannot return a Promise inside of tidy."),z.endScope(i),i}catch(i){throw z.endScope(null),i}};return Object.defineProperty(r,"name",{value:a,configurable:!0}),r}function dT(e,t){let a=R(e,"real","complex"),n=R(t,"imag","complex");Sa(a.shape,n.shape,`real and imag shapes, ${a.shape} and ${n.shape}, must match in call to tf.complex().`);let r={real:a,imag:n};return z.runKernel(Sd,r)}var br=D({complex_:dT});function rs(e,t,a,n){if(n==null&&(n=Uc(e)),n==="complex64")throw new Error("Cannot construct a complex64 tensor directly. Please use tf.complex(real, imag).");if(typeof e=="object"&&"texture"in e){if(n!=="float32"&&n!=="int32")throw new Error(`Creating tensor from texture only supports 'float32'|'int32' dtype, while the dtype is ${n}.`);return e.channels=e.channels||"RGBA",z.backend.createTensorFromTexture(e,t||a,n)}if(!da(e)&&!Array.isArray(e)&&typeof e!="number"&&typeof e!="boolean"&&typeof e!="string")throw new Error("values passed to tensor(values) must be a number/boolean/string or an array of numbers/booleans/strings, or a TypedArray");if(t!=null){Ja(t);let r=At(t),s=At(a);P(r===s,()=>`Based on the provided shape, [${t}], the tensor should have ${r} values but has ${s}`);for(let i=0;i`Error creating a new Tensor. Inferred shape (${a}) does not match the provided shape (${t}). `)}}return!da(e)&&!Array.isArray(e)&&(e=[e]),t=t||a,e=n!=="string"?ph(e,n):zs(e,[],!0),z.makeTensor(e,t,n)}function Be(e,t,a){let n=Yn(e,a);return rs(e,t,n,a)}var Qm={float32:4,float16:2,int32:4,uint16:2,uint8:1,bool:1,complex64:8},Cc=4;async function pT(e,t){let a=[],n=[],r=Array.isArray(e)?e.map(i=>i.name):Object.keys(e);for(let i=0;i{let d=await l.bytes(),h=d.reduce((g,x)=>g+x.length,0)+Cc*d.length,f=new Uint8Array(h),m=0;for(let g=0;g{if(t+=s.byteLength,a.push(s.byteLength===s.buffer.byteLength?s:new s.constructor(s)),!(s instanceof Float32Array||s instanceof Int32Array||s instanceof Uint8Array))throw new Error(`Unsupported TypedArray subtype: ${s.constructor.name}`)});let n=new Uint8Array(t),r=0;return a.forEach(s=>{n.set(new Uint8Array(s.buffer),r),r+=s.byteLength}),n.buffer}var t2=typeof Buffer!="undefined"&&(typeof Blob=="undefined"||typeof atob=="undefined"||typeof btoa=="undefined");function U5(e){return t2?Buffer.byteLength(e):new Blob([e]).size}function hT(e){if(t2)return Buffer.from(e).toString("base64");let t=new Uint8Array(e),a="";for(let n=0,r=t.length;n{t+=r.byteLength});let a=new Uint8Array(t),n=0;return e.forEach(r=>{a.set(new Uint8Array(r),n),n+=r.byteLength}),a.buffer}function G5(e){let t="/";for(e=e.trim();e.endsWith(t);)e=e.slice(0,e.length-1);let a=e.split(t);return a[a.length-1]}function NA(e,t){let a={modelTopology:e.modelTopology,format:e.format,generatedBy:e.generatedBy,convertedBy:e.convertedBy,weightsManifest:t};return e.signature!=null&&(a.signature=e.signature),e.userDefinedMetadata!=null&&(a.userDefinedMetadata=e.userDefinedMetadata),e.modelInitializer!=null&&(a.modelInitializer=e.modelInitializer),e.initializerSignature!=null&&(a.initializerSignature=e.initializerSignature),e.trainingConfig!=null&&(a.trainingConfig=e.trainingConfig),a}function EA(e,t,a){let n={modelTopology:e.modelTopology,format:e.format,generatedBy:e.generatedBy,convertedBy:e.convertedBy};if(e.trainingConfig!=null&&(n.trainingConfig=e.trainingConfig),e.weightsManifest!=null){if(!t)throw new Error("modelJSON has weightsManifest but weightSpecs is null");if(!a)throw new Error("modelJSON has weightsManifest but weightData is null");n.weightSpecs=t,n.weightData=a}return e.signature!=null&&(n.signature=e.signature),e.userDefinedMetadata!=null&&(n.userDefinedMetadata=e.userDefinedMetadata),e.modelInitializer!=null&&(n.modelInitializer=e.modelInitializer),e.initializerSignature!=null&&(n.initializerSignature=e.initializerSignature),n}async function n2(e,t){let a,n;return e.weightsManifest!=null&&([a,n]=await t(e.weightsManifest)),EA(e,a,n)}function qd(e){if(e.modelTopology instanceof ArrayBuffer)throw new Error("Expected JSON model topology, received ArrayBuffer.");return{dateSaved:new Date,modelTopologyType:"JSON",modelTopologyBytes:e.modelTopology==null?0:U5(JSON.stringify(e.modelTopology)),weightSpecsBytes:e.weightSpecs==null?0:U5(JSON.stringify(e.weightSpecs)),weightDataBytes:e.weightData==null?0:e.weightData.byteLength}}function RA(e){let t=[];for(let a of e)t.push(...a.weights);return t}function mT(){let e=a=>{let n=a<<13,r=0;for(;(n&8388608)===0;)r-=8388608,n<<=1;return n&=-8388609,r+=947912704,n|r},t=new Uint32Array(2048);t[0]=0;for(let a=1;a<1024;a++)t[a]=e(a);for(let a=1024;a<2048;a++)t[a]=939524096+(a-1024<<13);return t}function gT(){let e=new Uint32Array(64);e[0]=0,e[31]=1199570944,e[32]=2147483648,e[63]=3347054592;for(let t=1;t<31;t++)e[t]=t<<23;for(let t=33;t<63;t++)e[t]=2147483648+(t-32<<23);return e}function xT(){let e=new Uint32Array(64);for(let t=0;t<64;t++)e[t]=1024;return e[0]=e[32]=0,e}function AT(){let e=mT(),t=gT(),a=xT();return n=>{let r=new ArrayBuffer(4*n.length),s=new Uint32Array(r);for(let i=0;i>10]+(o&1023)]+t[o>>10];s[i]=l}return new Float32Array(r)}}var Rt=class{constructor(){this.saveRouters=[],this.loadRouters=[]}static getInstance(){return Rt.instance==null&&(Rt.instance=new Rt),Rt.instance}static registerSaveRouter(e){Rt.getInstance().saveRouters.push(e)}static registerLoadRouter(e){Rt.getInstance().loadRouters.push(e)}static getSaveHandlers(e){return Rt.getHandlers(e,"save")}static getLoadHandlers(e,t){return Rt.getHandlers(e,"load",t)}static getHandlers(e,t,a){let n=[];return(t==="load"?Rt.getInstance().loadRouters:Rt.getInstance().saveRouters).forEach(r=>{let s=r(e,a);s!==null&&n.push(s)}),n}},yT=e=>Rt.registerSaveRouter(e),bT=e=>Rt.registerLoadRouter(e),vT=e=>Rt.getSaveHandlers(e),wT=(e,t)=>Rt.getLoadHandlers(e,t),e1="tensorflowjs",t1=1,Fs="models_store",Br="model_info_store";function MA(){if(!W().getBool("IS_BROWSER"))throw new Error("Failed to obtain IndexedDB factory because the current environmentis not a web browser.");let e=typeof window=="undefined"?self:window,t=e.indexedDB||e.mozIndexedDB||e.webkitIndexedDB||e.msIndexedDB||e.shimIndexedDB;if(t==null)throw new Error("The current browser does not appear to support IndexedDB.");return t}function a1(e){let t=e.result;t.createObjectStore(Fs,{keyPath:"modelPath"}),t.createObjectStore(Br,{keyPath:"modelPath"})}var Ls=class{constructor(e){if(this.indexedDB=MA(),e==null||!e)throw new Error("For IndexedDB, modelPath must not be null, undefined or empty.");this.modelPath=e}async save(e){if(e.modelTopology instanceof ArrayBuffer)throw new Error("BrowserLocalStorage.save() does not support saving model topology in binary formats yet.");return this.databaseAction(this.modelPath,e)}async load(){return this.databaseAction(this.modelPath)}databaseAction(e,t){return new Promise((a,n)=>{let r=this.indexedDB.open(e1,t1);r.onupgradeneeded=()=>a1(r),r.onsuccess=()=>{let s=r.result;if(t==null){let i=s.transaction(Fs,"readonly"),o=i.objectStore(Fs).get(this.modelPath);o.onsuccess=()=>{if(o.result==null)return s.close(),n(new Error(`Cannot find model with path '${this.modelPath}' in IndexedDB.`));a(o.result.modelArtifacts)},o.onerror=l=>(s.close(),n(o.error)),i.oncomplete=()=>s.close()}else{let i=qd(t),o=s.transaction(Br,"readwrite"),l=o.objectStore(Br),u=l.put({modelPath:this.modelPath,modelArtifactsInfo:i}),p;u.onsuccess=()=>{p=s.transaction(Fs,"readwrite");let c=p.objectStore(Fs).put({modelPath:this.modelPath,modelArtifacts:t,modelArtifactsInfo:i});c.onsuccess=()=>a({modelArtifactsInfo:i}),c.onerror=d=>{l=o.objectStore(Br);let h=l.delete(this.modelPath);h.onsuccess=()=>(s.close(),n(c.error)),h.onerror=f=>(s.close(),n(c.error))}},u.onerror=c=>(s.close(),n(u.error)),o.oncomplete=()=>{p==null?s.close():p.oncomplete=()=>s.close()}}},r.onerror=s=>n(r.error)})}};Ls.URL_SCHEME="indexeddb://";var $A=e=>W().getBool("IS_BROWSER")&&!Array.isArray(e)&&e.startsWith(Ls.URL_SCHEME)?kT(e.slice(Ls.URL_SCHEME.length)):null;Rt.registerSaveRouter($A);Rt.registerLoadRouter($A);function kT(e){return new Ls(e)}function IT(e){return e.startsWith(Ls.URL_SCHEME)?e.slice(Ls.URL_SCHEME.length):e}var ST=class{constructor(){this.indexedDB=MA()}async listModels(){return new Promise((e,t)=>{let a=this.indexedDB.open(e1,t1);a.onupgradeneeded=()=>a1(a),a.onsuccess=()=>{let n=a.result,r=n.transaction(Br,"readonly"),s=r.objectStore(Br).getAll();s.onsuccess=()=>{let i={};for(let o of s.result)i[o.modelPath]=o.modelArtifactsInfo;e(i)},s.onerror=i=>(n.close(),t(s.error)),r.oncomplete=()=>n.close()},a.onerror=n=>t(a.error)})}async removeModel(e){return e=IT(e),new Promise((t,a)=>{let n=this.indexedDB.open(e1,t1);n.onupgradeneeded=()=>a1(n),n.onsuccess=()=>{let r=n.result,s=r.transaction(Br,"readwrite"),i=s.objectStore(Br),o=i.get(e),l;o.onsuccess=()=>{if(o.result==null)return r.close(),a(new Error(`Cannot find model with path '${e}' in IndexedDB.`));{let u=i.delete(e),p=()=>{l=r.transaction(Fs,"readwrite");let c=l.objectStore(Fs).delete(e);c.onsuccess=()=>t(o.result.modelArtifactsInfo),c.onerror=d=>a(o.error)};u.onsuccess=p,u.onerror=c=>(p(),r.close(),a(o.error))}},o.onerror=u=>(r.close(),a(o.error)),s.oncomplete=()=>{l==null?r.close():l.oncomplete=()=>r.close()}},n.onerror=r=>a(n.error)})}},xr="/",el="tensorflowjs_models",_A="info",TT="model_topology",CT="weight_specs",NT="weight_data",ET="model_metadata";function PA(e){return{info:[el,e,_A].join(xr),topology:[el,e,TT].join(xr),weightSpecs:[el,e,CT].join(xr),weightData:[el,e,NT].join(xr),modelMetadata:[el,e,ET].join(xr)}}function FA(e){for(let t of Object.values(e))window.localStorage.removeItem(t)}function RT(e){let t=e.split(xr);if(t.length<3)throw new Error(`Invalid key format: ${e}`);return t.slice(1,t.length-1).join(xr)}function MT(e){return e.startsWith(Bs.URL_SCHEME)?e.slice(Bs.URL_SCHEME.length):e}var Bs=class{constructor(e){if(!W().getBool("IS_BROWSER")||typeof window=="undefined"||typeof window.localStorage=="undefined")throw new Error("The current environment does not support local storage.");if(this.LS=window.localStorage,e==null||!e)throw new Error("For local storage, modelPath must not be null, undefined or empty.");this.modelPath=e,this.keys=PA(this.modelPath)}async save(e){if(e.modelTopology instanceof ArrayBuffer)throw new Error("BrowserLocalStorage.save() does not support saving model topology in binary formats yet.");{let t=JSON.stringify(e.modelTopology),a=JSON.stringify(e.weightSpecs),n=qd(e);try{this.LS.setItem(this.keys.info,JSON.stringify(n)),this.LS.setItem(this.keys.topology,t),this.LS.setItem(this.keys.weightSpecs,a),this.LS.setItem(this.keys.weightData,hT(e.weightData));let r={format:e.format,generatedBy:e.generatedBy,convertedBy:e.convertedBy,signature:e.signature!=null?e.signature:void 0,userDefinedMetadata:e.userDefinedMetadata!=null?e.userDefinedMetadata:void 0,modelInitializer:e.modelInitializer!=null?e.modelInitializer:void 0,initializerSignature:e.initializerSignature!=null?e.initializerSignature:void 0,trainingConfig:e.trainingConfig!=null?e.trainingConfig:void 0};return this.LS.setItem(this.keys.modelMetadata,JSON.stringify(r)),{modelArtifactsInfo:n}}catch(r){throw FA(this.keys),new Error(`Failed to save model '${this.modelPath}' to local storage: size quota being exceeded is a possible cause of this failure: modelTopologyBytes=${n.modelTopologyBytes}, weightSpecsBytes=${n.weightSpecsBytes}, weightDataBytes=${n.weightDataBytes}.`)}}}async load(){let e=JSON.parse(this.LS.getItem(this.keys.info));if(e==null)throw new Error(`In local storage, there is no model with name '${this.modelPath}'`);if(e.modelTopologyType!=="JSON")throw new Error("BrowserLocalStorage does not support loading non-JSON model topology yet.");let t={},a=JSON.parse(this.LS.getItem(this.keys.topology));if(a==null)throw new Error(`In local storage, the topology of model '${this.modelPath}' is missing.`);t.modelTopology=a;let n=JSON.parse(this.LS.getItem(this.keys.weightSpecs));if(n==null)throw new Error(`In local storage, the weight specs of model '${this.modelPath}' are missing.`);t.weightSpecs=n;let r=this.LS.getItem(this.keys.modelMetadata);if(r!=null){let i=JSON.parse(r);t.format=i.format,t.generatedBy=i.generatedBy,t.convertedBy=i.convertedBy,i.signature!=null&&(t.signature=i.signature),i.userDefinedMetadata!=null&&(t.userDefinedMetadata=i.userDefinedMetadata),i.modelInitializer!=null&&(t.modelInitializer=i.modelInitializer),i.initializerSignature!=null&&(t.initializerSignature=i.initializerSignature),i.trainingConfig!=null&&(t.trainingConfig=i.trainingConfig)}let s=this.LS.getItem(this.keys.weightData);if(s==null)throw new Error(`In local storage, the binary weight values of model '${this.modelPath}' are missing.`);return t.weightData=fT(s),t}};Bs.URL_SCHEME="localstorage://";var OA=e=>W().getBool("IS_BROWSER")&&!Array.isArray(e)&&e.startsWith(Bs.URL_SCHEME)?$T(e.slice(Bs.URL_SCHEME.length)):null;Rt.registerSaveRouter(OA);Rt.registerLoadRouter(OA);function $T(e){return new Bs(e)}var _T=class{constructor(){P(W().getBool("IS_BROWSER"),()=>"Current environment is not a web browser"),P(typeof window=="undefined"||typeof window.localStorage!="undefined",()=>"Current browser does not appear to support localStorage"),this.LS=window.localStorage}async listModels(){let e={},t=el+xr,a=xr+_A;for(let n=0;n"scheme must not be undefined or null."),e.endsWith(nl)&&(e=e.slice(0,e.indexOf(nl))),P(e.length>0,()=>"scheme must not be an empty string.");let a=Oa.getInstance();P(a.managers[e]==null,()=>`A model store manager is already registered for scheme '${e}'.`),a.managers[e]=t}static getManager(e){let t=Oa.getInstance().managers[e];if(t==null)throw new Error(`Cannot find model manager for scheme '${e}'`);return t}static getSchemes(){return Object.keys(Oa.getInstance().managers)}};function fc(e){if(e.indexOf(nl)===-1)throw new Error(`The url string provided does not contain a scheme. Supported schemes are: ${Oa.getSchemes().join(",")}`);return{scheme:e.split(nl)[0],path:e.split(nl)[1]}}async function DA(e,t,a=!1){P(e!==t,()=>`Old path and new path are the same: '${e}'`);let n=Rt.getLoadHandlers(e);P(n.length>0,()=>`Copying failed because no load handler is found for source URL ${e}.`),P(n.length<2,()=>`Copying failed because more than one (${n.length}) load handlers for source URL ${e}.`);let r=n[0],s=Rt.getSaveHandlers(t);P(s.length>0,()=>`Copying failed because no save handler is found for destination URL ${t}.`),P(s.length<2,()=>`Copying failed because more than one (${n.length}) save handlers for destination URL ${t}.`);let i=s[0],o=fc(e).scheme,l=fc(e).path,u=o===fc(e).scheme,p=await r.load();a&&u&&await Oa.getManager(o).removeModel(l);let c=await i.save(p);return a&&!u&&await Oa.getManager(o).removeModel(l),c.modelArtifactsInfo}async function PT(){let e=Oa.getSchemes(),t={};for(let a of e){let n=await Oa.getManager(a).listModels();for(let r in n){let s=a+nl+r;t[s]=n[r]}}return t}async function FT(e){let t=fc(e);return Oa.getManager(t.scheme).removeModel(t.path)}async function OT(e,t){return DA(e,t,!1)}async function DT(e,t){return DA(e,t,!0)}var zT=class{constructor(){this.messageName="setTimeoutCustom",this.functionRefs=[],this.handledMessageCount=0,this.hasEventListener=!1}fetch(e,t){return fetch(e,t)}now(){return performance.now()}encode(e,t){if(t!=="utf-8"&&t!=="utf8")throw new Error(`Browser's encoder only supports utf-8, but got ${t}`);return this.textEncoder==null&&(this.textEncoder=new TextEncoder),this.textEncoder.encode(e)}decode(e,t){return new TextDecoder(t).decode(e)}setTimeoutCustom(e,t){if(typeof window=="undefined"||!W().getBool("USE_SETTIMEOUTCUSTOM")){setTimeout(e,t);return}this.functionRefs.push(e),setTimeout(()=>{window.postMessage({name:this.messageName,index:this.functionRefs.length-1},"*")},t),this.hasEventListener||(this.hasEventListener=!0,window.addEventListener("message",a=>{if(a.source===window&&a.data.name===this.messageName){a.stopPropagation();let n=this.functionRefs[a.data.index];n(),this.handledMessageCount++,this.handledMessageCount===this.functionRefs.length&&(this.functionRefs=[],this.handledMessageCount=0)}},!0))}};if(W().get("IS_BROWSER")){W().setPlatform("browser",new zT);try{Oa.registerManager(Bs.URL_SCHEME,new _T)}catch(e){}try{Oa.registerManager(Ls.URL_SCHEME,new ST)}catch(e){}}var LT={importFetch:()=>GI()},Pm,BT=class{constructor(){this.util=HI(),this.textEncoder=new this.util.TextEncoder}fetch(e,t){return W().global.fetch!=null?W().global.fetch(e,t):(Pm==null&&(Pm=LT.importFetch()),Pm(e,t))}now(){let e=process.hrtime();return e[0]*1e3+e[1]/1e6}encode(e,t){if(t!=="utf-8"&&t!=="utf8")throw new Error(`Node built-in encoder only supports utf-8, but got ${t}`);return this.textEncoder.encode(e)}decode(e,t){return e.length===0?"":new this.util.TextDecoder(t).decode(e)}};W().get("IS_NODE")&&!W().get("IS_BROWSER")&&W().setPlatform("node",new BT);function Me(e,t="float32",a){return t=t||"float32",Ja(e),new jt(e,t,a)}function WT(e,t){let a=R(e,"x","cast");if(!dA(t))throw new Error(`Failed to cast to unknown dtype ${t}`);if(t==="string"&&a.dtype!=="string"||t!=="string"&&a.dtype==="string")throw new Error("Only strings can be casted to strings");let n={x:a},r={dtype:t};return z.runKernel(ti,n,r)}var He=D({cast_:WT});function VT(e){let t={x:R(e,"x","clone","string_or_numeric")};return z.runKernel(ki,t)}var wa=D({clone_:VT});function r2(e,t=!1){console.log(e.toString(t))}IA();var UT={buffer:Me,cast:He,clone:wa,print:r2};QS(UT);var jn={};Xe(jn,{browserFiles:()=>ZT,browserHTTPRequest:()=>tC,concatenateArrayBuffers:()=>a2,copyModel:()=>OT,decodeWeights:()=>CA,encodeWeights:()=>pT,fromMemory:()=>nC,fromMemorySync:()=>VA,getLoadHandlers:()=>wT,getModelArtifactsForJSON:()=>n2,getModelArtifactsForJSONSync:()=>EA,getModelArtifactsInfoForJSON:()=>qd,getSaveHandlers:()=>vT,getWeightSpecs:()=>RA,http:()=>i2,isHTTPScheme:()=>n1,listModels:()=>PT,loadWeights:()=>YT,moveModel:()=>DT,registerLoadRouter:()=>bT,registerSaveRouter:()=>yT,removeModel:()=>FT,weightsLoaderFactory:()=>LA,withSaveHandler:()=>rC,withSaveHandlerSync:()=>sC});var GT="model",HT=".json",jT=".weights.bin";function H5(e){return new Promise(t=>setTimeout(t)).then(e)}var ul=class{constructor(e){if(!W().getBool("IS_BROWSER"))throw new Error("browserDownloads() cannot proceed because the current environment is not a browser.");e.startsWith(ul.URL_SCHEME)&&(e=e.slice(ul.URL_SCHEME.length)),(e==null||e.length===0)&&(e=GT),this.modelJsonFileName=e+HT,this.weightDataFileName=e+jT}async save(e){if(typeof document=="undefined")throw new Error("Browser downloads are not supported in this environment since `document` is not present");let t=window.URL.createObjectURL(new Blob([e.weightData],{type:"application/octet-stream"}));if(e.modelTopology instanceof ArrayBuffer)throw new Error("BrowserDownloads.save() does not support saving model topology in binary formats yet.");{let a=[{paths:["./"+this.weightDataFileName],weights:e.weightSpecs}],n=NA(e,a),r=window.URL.createObjectURL(new Blob([JSON.stringify(n)],{type:"application/json"})),s=this.modelJsonAnchor==null?document.createElement("a"):this.modelJsonAnchor;if(s.download=this.modelJsonFileName,s.href=r,await H5(()=>s.dispatchEvent(new MouseEvent("click"))),e.weightData!=null){let i=this.weightDataAnchor==null?document.createElement("a"):this.weightDataAnchor;i.download=this.weightDataFileName,i.href=t,await H5(()=>i.dispatchEvent(new MouseEvent("click")))}return{modelArtifactsInfo:qd(e)}}}};ul.URL_SCHEME="downloads://";var qT=class{constructor(e){if(e==null||e.length<1)throw new Error(`When calling browserFiles, at least 1 file is required, but received ${e}`);this.jsonFile=e[0],this.weightsFiles=e.slice(1)}async load(){return new Promise((e,t)=>{let a=new FileReader;a.onload=n=>{let r=JSON.parse(n.target.result),s=r.modelTopology;if(s==null){t(new Error(`modelTopology field is missing from file ${this.jsonFile.name}`));return}if(r.weightsManifest==null){t(new Error(`weightManifest field is missing from file ${this.jsonFile.name}`));return}if(this.weightsFiles.length===0){e({modelTopology:s});return}let i=n2(r,o=>this.loadWeights(o));e(i)},a.onerror=n=>t(`Failed to read model topology and weights manifest JSON from file '${this.jsonFile.name}'. BrowserFiles supports loading Keras-style tf.Model artifacts only.`),a.readAsText(this.jsonFile)})}loadWeights(e){let t=[],a=[];for(let s of e)t.push(...s.weights),a.push(...s.paths);let n=this.checkManifestAndWeightFiles(e),r=a.map(s=>this.loadWeightsFile(s,n[s]));return Promise.all(r).then(s=>[t,a2(s)])}loadWeightsFile(e,t){return new Promise((a,n)=>{let r=new FileReader;r.onload=s=>{let i=s.target.result;a(i)},r.onerror=s=>n(`Failed to weights data from file of path '${e}'.`),r.readAsArrayBuffer(t)})}checkManifestAndWeightFiles(e){let t=[],a=this.weightsFiles.map(r=>G5(r.name)),n={};for(let r of e)r.paths.forEach(s=>{let i=G5(s);if(t.indexOf(i)!==-1)throw new Error(`Duplicate file basename found in weights manifest: '${i}'`);if(t.push(i),a.indexOf(i)===-1)throw new Error(`Weight file with basename '${i}' is not provided.`);n[s]=this.weightsFiles[a.indexOf(i)]});if(t.length!==this.weightsFiles.length)throw new Error(`Mismatch in the number of files in weights manifest (${t.length}) and the number of weight files provided (${this.weightsFiles.length}).`);return n}},XT=e=>W().getBool("IS_BROWSER")&&!Array.isArray(e)&&e.startsWith(ul.URL_SCHEME)?KT(e.slice(ul.URL_SCHEME.length)):null;Rt.registerSaveRouter(XT);function KT(e="model"){return new ul(e)}function ZT(e){return new qT(e)}function j5(e,t,a,n){i(e),a=a==null?0:a,n=n==null?1:n,o(a,n);let r=0,s=l=>(l.then(u=>{let p=a+ ++r/e.length*(n-a);return t(p),u}),l);function i(l){P(l!=null&&Array.isArray(l)&&l.length>0,()=>"promises must be a none empty array")}function o(l,u){P(l>=0&&l<=1,()=>`Progress fraction must be in range [0, 1], but got startFraction ${l}`),P(u>=0&&u<=1,()=>`Progress fraction must be in range [0, 1], but got endFraction ${u}`),P(u>=l,()=>`startFraction must be no more than endFraction, but got startFraction ${l} and endFraction ${u}`)}return Promise.all(e.map(s))}async function zA(e,t){t==null&&(t={});let a=t.fetchFunc==null?W().platform.fetch:t.fetchFunc,n=e.map(u=>a(u,t.requestInit,{isBinary:!0})),r=0,s=.5,i=(t.onProgress==null?await Promise.all(n):await j5(n,t.onProgress,r,s)).map(u=>u.arrayBuffer()),o=.5,l=1;return t.onProgress==null?await Promise.all(i):await j5(i,t.onProgress,o,l)}async function YT(e,t="",a,n){return LA(r=>zA(r,{requestInit:n}))(e,t,a)}function LA(e){return async(t,a="",n)=>{let r=t.map(()=>!1),s={},i=n!=null?n.map(()=>!1):[],o=[];if(t.forEach((h,f)=>{let m=0;h.weights.forEach(g=>{let x="quantization"in g?g.quantization.dtype:g.dtype,A=Qm[x]*At(g.shape),y=()=>{r[f]=!0,s[f]==null&&(s[f]=[]),s[f].push({manifestEntry:g,groupOffset:m,sizeBytes:A})};n!=null?n.forEach((b,w)=>{b===g.name&&(y(),i[w]=!0)}):y(),o.push(g.name),m+=A})}),!i.every(h=>h)){let h=n.filter((f,m)=>!i[m]);throw new Error(`Could not find weights in manifest with names: ${h.join(", ")}. Manifest JSON has weights with names: ${o.join(", ")}.`)}let l=r.reduce((h,f,m)=>(f&&h.push(m),h),[]),u=[];l.forEach(h=>{t[h].paths.forEach(f=>{let m=a+(a.endsWith("/")?"":"/")+f;u.push(m)})});let p=await e(u),c={},d=0;return l.forEach(h=>{let f=t[h].paths.length,m=0;for(let y=0;y{let b=g.slice(y.groupOffset,y.groupOffset+y.sizeBytes),w=CA(b,[y.manifestEntry]);for(let S in w)c[S]=w[S]}),d+=f}),c}}var JT="application/octet-stream",QT="application/json",s2=class{constructor(e,t){if(this.DEFAULT_METHOD="POST",t==null&&(t={}),this.weightPathPrefix=t.weightPathPrefix,this.onProgress=t.onProgress,this.weightUrlConverter=t.weightUrlConverter,t.fetchFunc!=null?(P(typeof t.fetchFunc=="function",()=>"Must pass a function that matches the signature of `fetch` (see https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)"),this.fetch=t.fetchFunc):this.fetch=W().platform.fetch,P(e!=null&&e.length>0,()=>"URL path for http must not be null, undefined or empty."),Array.isArray(e)&&P(e.length===2,()=>`URL paths for http must have a length of 2, (actual length is ${e.length}).`),this.path=e,t.requestInit!=null&&t.requestInit.body!=null)throw new Error("requestInit is expected to have no pre-existing body, but has one.");this.requestInit=t.requestInit||{}}async save(e){if(e.modelTopology instanceof ArrayBuffer)throw new Error("BrowserHTTPRequest.save() does not support saving model topology in binary formats yet.");let t=Object.assign({method:this.DEFAULT_METHOD},this.requestInit);t.body=new FormData;let a=[{paths:["./model.weights.bin"],weights:e.weightSpecs}],n=NA(e,a);t.body.append("model.json",new Blob([JSON.stringify(n)],{type:QT}),"model.json"),e.weightData!=null&&t.body.append("model.weights.bin",new Blob([e.weightData],{type:JT}),"model.weights.bin");let r=await this.fetch(this.path,t);if(r.ok)return{modelArtifactsInfo:qd(e),responses:[r]};throw new Error(`BrowserHTTPRequest.save() failed due to HTTP response status ${r.status}.`)}async load(){let e=await this.fetch(this.path,this.requestInit);if(!e.ok)throw new Error(`Request to ${this.path} failed with status code ${e.status}. Please verify this URL points to the model JSON of the model to load.`);let t;try{t=await e.json()}catch(r){let s=`Failed to parse model JSON of response from ${this.path}.`;throw this.path.endsWith(".pb")?s+=" Your path contains a .pb file extension. Support for .pb models have been removed in TensorFlow.js 1.0 in favor of .json models. You can re-convert your Python TensorFlow model using the TensorFlow.js 1.0 conversion scripts or you can convert your.pb models with the 'pb2json'NPM script in the tensorflow/tfjs-converter repository.":s+=" Please make sure the server is serving valid JSON for this request.",new Error(s)}let a=t.modelTopology,n=t.weightsManifest;if(a==null&&n==null)throw new Error(`The JSON from HTTP path ${this.path} contains neither model topology or manifest for weights.`);return n2(t,r=>this.loadWeights(r))}async loadWeights(e){let t=Array.isArray(this.path)?this.path[1]:this.path,[a,n]=eC(t),r=this.weightPathPrefix||a,s=RA(e),i=[],o=[];for(let u of e)for(let p of u.paths)this.weightUrlConverter!=null?o.push(this.weightUrlConverter(p)):i.push(r+p+n);this.weightUrlConverter&&i.push(...await Promise.all(o));let l=await zA(i,{requestInit:this.requestInit,fetchFunc:this.fetch,onProgress:this.onProgress});return[s,a2(l)]}};s2.URL_SCHEME_REGEX=/^https?:\/\//;function eC(e){let t=e.lastIndexOf("/"),a=e.lastIndexOf("?"),n=e.substring(0,t),r=a>t?e.substring(a):"";return[n+"/",r]}function n1(e){return e.match(s2.URL_SCHEME_REGEX)!=null}var BA=(e,t)=>{if(typeof fetch=="undefined"&&(t==null||t.fetchFunc==null))return null;{let a=!0;if(Array.isArray(e)?a=e.every(n=>n1(n)):a=n1(e),a)return i2(e,t)}return null};Rt.registerSaveRouter(BA);Rt.registerLoadRouter(BA);function i2(e,t){return new s2(e,t)}function tC(e,t){return i2(e,t)}var Fm=class{constructor(e){this.modelArtifacts=e}load(){return this.modelArtifacts}},WA=class{constructor(e){this.saveHandler=e}save(e){return this.saveHandler(e)}},aC=class{constructor(e){e.load&&(this.load=()=>Promise.resolve(e.load())),e.save&&(this.save=t=>Promise.resolve(e.save(t)))}};function nC(e,t,a,n){let r=arguments;return new aC(VA(...r))}function VA(e,t,a,n){return arguments.length===1?e.modelTopology!=null||e.weightSpecs!=null?new Fm(e):(console.warn("Please call tf.io.fromMemory() with only one argument. The argument should be of type ModelArtifacts. The multi-argument signature of tf.io.fromMemory() has been deprecated and will be removed in a future release."),new Fm({modelTopology:e})):(console.warn("Please call tf.io.fromMemory() with only one argument. The argument should be of type ModelArtifacts. The multi-argument signature of tf.io.fromMemory() has been deprecated and will be removed in a future release."),new Fm({modelTopology:e,weightSpecs:t,weightData:a,trainingConfig:n}))}function rC(e){return new WA(e)}function sC(e){return new WA(e)}var UA={};Xe(UA,{confusionMatrix:()=>wC});function iC(e,t,a=!1,n=!1){let r=R(e,"a","matMul"),s=R(t,"b","matMul");[r,s]=St(r,s);let i={a:r,b:s},o={transposeA:a,transposeB:n};return z.runKernel(ei,i,o)}var st=D({matMul_:iC});function oC(e,t,a=1,n=0,r="int32"){if(t<2)throw new Error(`Error in oneHot: depth must be >=2, but it is ${t}`);let s={indices:R(e,"indices","oneHot","int32")},i={dtype:r,depth:t,onValue:a,offValue:n};return z.runKernel(Vi,s,i)}var Nc=D({oneHot_:oC});function o2(){W().set("PROD",!0)}function lC(){W().set("DEBUG",!0)}function uC(){W().set("DEPRECATION_WARNINGS_ENABLED",!1),console.warn("TensorFlow.js deprecation warnings have been disabled.")}function l2(e){W().getBool("DEPRECATION_WARNINGS_ENABLED")&&console.warn(e+" You can disable deprecation warnings with tf.disableDeprecationWarnings().")}eT(l2);function dC(){z.disposeVariables()}function kt(){return z}function pC(){return z.memory()}function cC(e){return z.profile(e)}function $e(e,t){return z.tidy(e,t)}function Y(e){Q1(e).forEach(t=>t.dispose())}function On(e){return z.keep(e)}function hC(e){return z.time(e)}function Xd(e){return z.setBackend(e)}function Kd(){return z.ready()}function ia(){return z.backendName}function fC(e){z.removeBackend(e)}function u2(e){return z.findBackend(e)}function mC(e){return z.findBackendFactory(e)}function go(e,t,a=1){return z.registerBackend(e,t,a)}function tr(){return z.backend}function gC(e,t){W().setPlatform(e,t)}function xC(e){let t={input:R(e,"input","imag")};return z.runKernel(Rd,t)}var Zd=D({imag_:xC});function AC(e){let t={x:R(e,"x","neg")};return z.runKernel(Vl,t)}var Xn=D({neg_:AC});function yC(e){let t={input:R(e,"input","real")};return z.runKernel(Md,t)}var dl=D({real_:yC});function bC(e,t,a){let n=R(e,"x","transpose");if(t==null&&(t=n.shape.map((i,o)=>o).reverse()),P(n.rank===t.length,()=>`Error in transpose: rank of input ${n.rank} must match length of perm ${t}.`),t.forEach(i=>{P(i>=0&&i`All entries in 'perm' must be between 0 and ${n.rank-1} but got ${t}`)}),n.rank<=1)return n.clone();let r={x:n},s={perm:t};return n.dtype==="complex64"?$e(()=>{let i=dl(n),o=Zd(n);return i=z.runKernel(Ar,{x:i},s),o=z.runKernel(Ar,{x:o},s),a&&(o=Xn(o)),br(i,o)}):z.runKernel(Ar,r,s)}var Ws=D({transpose_:bC});function vC(e,t,a){let n=R(e,"labels","confusionMatrix"),r=R(t,"predictions","confusionMatrix");P(a==null||a>0&&Number.isInteger(a),()=>`If provided, numClasses must be a positive integer, but got ${a}`),P(n.rank===1,()=>`Expected the rank of labels to be 1, but got ${n.rank}`),P(r.rank===1,()=>`Expected the rank of predictions to be 1, but got ${r.rank}`),P(n.shape[0]===r.shape[0],()=>`Mismatch in the number of examples: ${n.shape[0]} vs. ${r.shape[0]}. Labels and predictions should have the same number of elements.`),P(a>0&&Number.isInteger(a),()=>`numClasses is required to be a positive integer, but got ${a}`);let s=Nc(He(n,"int32"),a),i=Nc(He(r,"int32"),a),o=Ws(s),l=st(o,i);return He(l,"int32")}var wC=D({confusionMatrix_:vC}),xo={};Xe(xo,{assertAndGetBroadcastShape:()=>zt,getBroadcastDims:()=>GA,getReductionAxes:()=>d2});function GA(e,t){let a=e.length,n=[];for(let r=0;r1&&i===1&&n.unshift(s)}return n}function d2(e,t){let a=[];for(let n=0;n1)&&a.unshift(s)}return a}function zt(e,t){let a=[],n=Math.max(e.length,t.length);for(let r=0;rEC,fromPixelsAsync:()=>CC,toPixels:()=>NC});function p2(e,t,a){if(Xs(e),t!=null&&t.length!==3)throw new Error("tensor3d() requires shape to have three numbers");let n=Yn(e,a);if(n.length!==3&&n.length!==1)throw new Error("tensor3d() requires values to be number[][][] or flat/TypedArray");if(n.length===1&&t==null)throw new Error("tensor3d() requires shape to be provided when `values` are a flat array");return rs(e,t,n,a)}var Ns;function HA(e,t=3){if(t>4)throw new Error("Cannot construct Tensor with more than 4 channels from pixels.");if(e==null)throw new Error("pixels passed to tf.browser.fromPixels() can not be null");let a=!1,n=!1,r=!1,s=!1,i=!1,o=!1;if(e.data instanceof Uint8Array)a=!0;else if(typeof ImageData!="undefined"&&e instanceof ImageData)n=!0;else if(typeof HTMLVideoElement!="undefined"&&e instanceof HTMLVideoElement)r=!0;else if(typeof HTMLImageElement!="undefined"&&e instanceof HTMLImageElement)s=!0;else if(e.getContext!=null)i=!0;else if(typeof ImageBitmap!="undefined"&&e instanceof ImageBitmap)o=!0;else throw new Error(`pixels passed to tf.browser.fromPixels() must be either an HTMLVideoElement, HTMLImageElement, HTMLCanvasElement, ImageData in browser, or OffscreenCanvas, ImageData in webworker or {data: Uint32Array, width: number, height: number}, but was ${e.constructor.name}`);if(Sc(rd,z.backendName)!=null){let d={pixels:e},h={numChannels:t};return z.runKernel(rd,d,h)}let[l,u]=r?[e.videoWidth,e.videoHeight]:[e.width,e.height],p;if(i)p=e.getContext("2d").getImageData(0,0,l,u).data;else if(n||a)p=e.data;else if(s||r||o){if(Ns==null)if(typeof document=="undefined")if(typeof OffscreenCanvas!="undefined"&&typeof OffscreenCanvasRenderingContext2D!="undefined")Ns=new OffscreenCanvas(1,1).getContext("2d");else throw new Error("Cannot parse input in current context. Reason: OffscreenCanvas Context2D rendering is not supported.");else Ns=document.createElement("canvas").getContext("2d",{willReadFrequently:!0});Ns.canvas.width=l,Ns.canvas.height=u,Ns.drawImage(e,0,0,l,u),p=Ns.getImageData(0,0,l,u).data}let c;if(t===4)c=new Int32Array(p);else{let d=l*u;c=new Int32Array(d*t);for(let h=0;h4||s===2)throw new Error(`toPixels only supports depth of size 1, 3 or 4 but got ${s}`);if(a.dtype!=="float32"&&a.dtype!=="int32")throw new Error(`Unsupported type for toPixels: ${a.dtype}. Please use float32 or int32 tensors.`);let i=await a.data(),o=a.dtype==="float32"?255:1,l=new Uint8ClampedArray(r*n*4);for(let u=0;u1)throw new Error(`Tensor values for a float32 Tensor must be in the range [0 - 1] but encountered ${h}.`)}else if(a.dtype==="int32"&&(h<0||h>255))throw new Error(`Tensor values for a int32 Tensor must be in the range [0 - 255] but encountered ${h}.`);s===1?(p[0]=h*o,p[1]=h*o,p[2]=h*o):p[d]=h*o}let c=u*4;l[c+0]=Math.round(p[0]),l[c+1]=Math.round(p[1]),l[c+2]=Math.round(p[2]),l[c+3]=Math.round(p[3])}if(t!=null){t.width=r,t.height=n;let u=t.getContext("2d"),p=new ImageData(l,r,n);u.putImageData(p,0,0)}return a!==e&&a.dispose(),l}var EC=D({fromPixels_:HA}),c2={};Xe(c2,{prepareAndValidate:()=>jA});function jA(e,t){let a=e.shape.length,n=t.shape.length;if(a<1)throw new Error(`tf.gatherND() expects the input to be rank 1 or higher, but the rank was ${a}.`);if(n<1)throw new Error(`tf.gatherND() expects the indices to be rank 1 or higher, but the rank was ${n}.`);if(t.dtype!=="int32")throw new Error(`tf.gatherND() expects the indices to be int32 type, but the dtype was ${t.dtype}.`);if(t.shape[n-1]>a)throw new Error(`index innermost dimension length must be <= tensor rank; saw: ${t.shape[n-1]} vs. ${a}`);if(At(e.shape)===0)throw new Error(`Requested more than 0 entries, but input is empty. Input shape: ${e.shape}.`);let r=t.shape,s=r[r.length-1],i=1;for(let c=0;cc/u),1].slice(0,s);return[l,i,u,p]}var h2={};Xe(h2,{calculateShapes:()=>qA,validateInput:()=>m2,validateUpdateShape:()=>f2});function f2(e,t,a){let n=t.rank>1?t.shape[t.rank-1]:1,r=t.rank>1?t.rank-1:1,s=`Must have updates.shape = indices.shape[:batchDim] + shape[sliceDim:], got updates.shape: ${a.shape}, indices.shape: ${t.shape}, shape: ${e}, sliceDim: ${n}, and batchDim: ${r}.`;if(a.rank1?t.shape[n-1]:1,s=a.length,i=1;for(let c=r;cMC,computeFlatOffset:()=>OC,computeOutShape:()=>_C,getNormalizedAxes:()=>PC,isSliceContinous:()=>FC,maskToAxes:()=>$C,parseSliceParams:()=>DC,sliceInfo:()=>zC,startForAxis:()=>ey,startIndicesWithElidedDims:()=>YA,stopForAxis:()=>ty,stopIndicesWithElidedDims:()=>JA,stridesForAxis:()=>QA,stridesWithElidedDims:()=>XA});var r1=-2,RC=-1;function MC(e,t,a){let n=e.shape.length;P(n===t.length,()=>`Error in slice${n}D: Length of begin ${t} must match the rank of the array (${n}).`),P(n===a.length,()=>`Error in slice${n}D: Length of size ${a} must match the rank of the array (${n}).`);for(let r=0;r`Error in slice${n}D: begin[${r}] + size[${r}] (${t[r]+a[r]}) would overflow input.shape[${r}] (${e.shape[r]})`)}function $C(e){let t=[],a=0;for(;e>0;)e&1&&t.push(a),e/=2,a++;return t}function _C(e,t,a){let n=[];for(let r=0;r0){let h=t[0],f=a+1;p=YA(i,h,f,n,e),c=JA(o,h,f,r,e),d=XA(s,h,f,e)}else for(let h=0;h-1)s[o]=0;else{let l=KA(t,a,o),u=n[l];e&1<-1)s[o]=Number.MAX_SAFE_INTEGER;else{let l=KA(t,a,o),u=n[l];e&1<0?i=Number.MIN_SAFE_INTEGER:i=Number.MAX_SAFE_INTEGER);let l=n[r];return i<0&&(i+=l),i=nd(0,i,l-1),i}function ty(e,t,a,n,r,s){let i=t[r],o=a[r]||1;(e&1<0?i=Number.MAX_SAFE_INTEGER:i=Number.MIN_SAFE_INTEGER);let l=n[r];return i<0&&(i+=l),o>0?i=nd(0,i,l):i=nd(-1,i,l-1),i}function FC(e,t,a){let n=a.length;for(let r=0;r1){n=r;break}for(let r=n+1;r0||a[r]!==e[r])return!1;return!0}function OC(e,t){let a=e.length>0?e[e.length-1]:1;for(let n=0;n{P(i!==-1,()=>"slice() does not support negative begin indexing.")});let s;return a==null?s=new Array(r).fill(-1):typeof a=="number"?s=[a,...new Array(r-1).fill(-1)]:a.lengthi>=0?i:(P(i===-1,()=>`Negative size values should be exactly -1 but got ${i} for the slice() size at index ${o}.`),e.shape[o]-n[o])),[n,s]}function zC(e,t,a,n,r,s,i,o,l){let u;if(n==null?(u=new Array(t.length),u.fill(1)):u=n,i!=null&&(i&i-1)!==0)throw new Error("Multiple ellipses in slice is not allowed.");let p=!1,c={dims:u.length,numAddAxisAfterEllipsis:0,begin:t.slice(),end:a.slice(),strides:u.slice(),beginMask:r,endMask:s,ellipsisMask:i,newAxisMask:o,shrinkAxisMask:l};for(let A=0;A0?0:-1,d.strides[A]>0?b:b-1];if(y&&d.strides[A]<=0)throw Error("only stride 1 allowed on non-range indexing.");m=m&&d.strides[A]===1;let C=!!(d.beginMask&1<=b)throw Error(`slice index ${d.begin[A]} of dimension ${A} out of bounds.`)}else d.begin[A]=q5(d.begin[A],0,d.strides[A],b,w,S),d.end[A]=q5(d.end[A],1,d.strides[A],b,w,S);let $=d.strides[A]===1&&d.begin[A]===0&&d.end[A]===b;h=h&&$,f=f&&(A===0&&d.strides[A]===1||$)}else h=h&&d.strides[A]===1&&C,f=f&&(A===0&&d.strides[A]===1||C);let E,_=!1;if(d.beginValid&&d.endValid?(E=d.end[A]-d.begin[A],_=!0):y?(E=1,_=!0):C&&b>=0&&(d.strides[A]<0?E=-b:E=b,_=!0),_){let $;E===0||E<0!=d.strides[A]<0?$=0:$=Math.trunc(E/d.strides[A])+(E%d.strides[A]!==0?1:0),g.push($)}else g.push(-1)}for(let A=0;A=0?x.push(g[y]):y===r1&&x.push(1)}return{finalShapeSparse:x.filter((A,y)=>d.finalShapeGatherIndices[y]!==r1),finalShape:x,isIdentity:h,sliceDim0:f,isSimpleSlice:m,begin:d.begin,end:d.end,strides:d.strides}}function LC(e,t){t.beginMask=0,t.endMask=0,t.shrinkAxisMask=0;let a=0;t.beginValid=e.begin!=null,t.endValid=e.end!=null,t.begin=new Array(t.dims),t.end=new Array(t.dims),t.strides=new Array(t.dims),t.finalShapeGatherIndices=[],t.finalShapeGatherIndicesSparse=[],t.inputShapeGatherIndicesSparse=new Array(t.dims);for(let n=0;n0?s[t]:s[t+1&1];{let i=e<0?n+e:e;return is[1]?s[1]:i}}var ay={};Xe(ay,{Serializable:()=>ny,SerializationMap:()=>_s,registerClass:()=>ss});var ny=class{getClassName(){return this.constructor.className}static fromConfig(e,t){return new e(t)}},_s=class{constructor(){this.classNameMap={}}static getMap(){return _s.instance==null&&(_s.instance=new _s),_s.instance}static register(e){_s.getMap().classNameMap[e.className]=[e,e.fromConfig]}};function ss(e){P(e.className!=null,()=>"Class being registered does not have the static className property defined."),P(typeof e.className=="string",()=>"className is required to be a string, but got type "+typeof e.className),P(e.className.length>0,()=>"Class being registered has an empty-string as its className, which is disallowed."),_s.register(e)}var ry={};Xe(ry,{TEST_EPSILON_FLOAT16:()=>sy,createVideoElement:()=>qC,encodeStrings:()=>iy,expectArrayBuffersEqual:()=>jC,expectArraysClose:()=>WC,expectArraysEqual:()=>UC,expectNumbersClose:()=>GC,expectPromiseToFail:()=>VC,expectValuesInRange:()=>HC,play:()=>XC,testEpsilon:()=>g2});var BC=.001,sy=.1;function WC(e,t,a){return a==null&&(a=g2()),s1(e,t,(n,r)=>x2(n,r,a))}function g2(){return z.backend.floatPrecision()===32?BC:sy}function s1(e,t,a){let n=!0;if((da(e)||da(t))&&(n=!1),da(e)&&da(t)&&(n=!0),n){let i=e.constructor.name,o=t.constructor.name;if(i!==o)throw new Error(`Arrays are of different type. Actual: ${i}. Expected: ${o}`)}if(Array.isArray(e)&&Array.isArray(t)){let i=Yn(e),o=Yn(t);if(!es(i,o))throw new Error(`Arrays have different shapes. Actual: [${i}]. Expected: [${o}]`)}let r=da(e)?e:zs(e),s=da(t)?t:zs(t);if(r.length!==s.length)throw new Error(`Arrays have different lengths actual: ${r.length} vs expected: ${s.length}. Actual: ${r}. Expected: ${s}.`);for(let i=0;it.fail(),()=>t()),typeof expect!="undefined"&&expect().nothing()}function UC(e,t){let a=typeof t=="string"||typeof t=="number"||typeof t=="boolean"?[t]:t;return Lr(e)||Lr(e[0])||Lr(t)||Lr(t[0])?s1(e,a,(n,r)=>n==r):s1(e,t,(n,r)=>x2(n,r,0))}function GC(e,t,a){if(a==null&&(a=g2()),!x2(e,t,a))throw new Error(`Numbers differ: actual === ${e}, expected === ${t}`);typeof expect!="undefined"&&expect().nothing()}function x2(e,t,a){return!isFinite(e)&&!isFinite(t)?!0:!(isNaN(e)||isNaN(t)||Math.abs(e-t)>a)}function HC(e,t,a){for(let n=0;na)throw new Error(`Value out of range:${e[n]} low: ${t}, high: ${a}`)}function jC(e,t){let a=new Float32Array(e),n=new Float32Array(t);if(a.length!==n.length)throw new Error(`Expected ArrayBuffer to be of length ${n.length}, but it was ${a.length}`);for(let r=0;r{t.addEventListener("loadeddata",n=>a(t)),t.load()})}async function XC(e){await e.play(),"requestVideoFrameCallback"in e&&await new Promise(t=>{e.requestVideoFrameCallback(t)})}var A2="4.1.0";function KC(e,t){let a=R(e,"a","add"),n=R(t,"b","add");[a,n]=St(a,n);let r={a,b:n};return z.runKernel(ts,r)}var be=D({add_:KC});function ZC(e,t){let a=R(e,"a","floorDiv"),n=R(t,"b","floorDiv");[a,n]=St(a,n);let r={a,b:n};return z.runKernel(Ai,r)}var Yd=D({floorDiv_:ZC});function YC(e,t){let a=R(e,"a","div"),n=R(t,"b","div");if([a,n]=St(a,n),a.dtype==="int32"&&n.dtype==="int32")return Yd(a,n);let r={a,b:n},s={};return z.runKernel(ci,r,s)}var me=D({div_:YC});function JC(e,t){let a=R(e,"a","mul"),n=R(t,"b","mul");[a,n]=St(a,n);let r={a,b:n};return z.runKernel(zi,r)}var ae=D({mul_:JC});function QC(e){let t=R(e,"x","abs");if(t.dtype==="complex64"){let a={x:t};return z.runKernel(qc,a)}else{let a={x:t};return z.runKernel(wl,a)}}var qa=D({abs_:QC});function eN(e){let t={x:R(e,"x","acos")};return z.runKernel(kl,t)}var oy=D({acos_:eN});function tN(e){let t={x:R(e,"x","acosh")};return z.runKernel(Il,t)}var ly=D({acosh_:tN});function aN(e){P(Array.isArray(e),()=>"The argument passed to tf.addN() must be a list of tensors"),P(e.length>=1,()=>`Must pass at least one tensor to tf.addN(), but got ${e.length}`);let t=e.map((r,s)=>R(r,`tensors${s}`,"addN")),a=t[0];t.forEach(r=>{if(r.dtype!==a.dtype)throw new Error("All tensors passed to tf.addN() must have the same dtype")}),t.forEach(r=>{if(!es(r.shape,a.shape))throw new Error("All tensors passed to tf.addN() must have the same shape")});let n=t;return z.runKernel(Ks,n)}var ch=D({addN_:aN});function nN(e,t=null,a=!1){let n={x:R(e,"x","all","bool")},r={axis:t,keepDims:a};return z.runKernel(Zs,n,r)}var uy=D({all_:nN});function rN(e,t=null,a=!1){let n={x:R(e,"x","any","bool")},r={axis:t,keepDims:a};return z.runKernel(Ys,n,r)}var dy=D({any_:rN});function sN(e,t=0){let a={x:R(e,"x","argMax")},n={axis:t};return z.runKernel(Js,a,n)}var ar=D({argMax_:sN});function iN(e,t=0){let a={x:R(e,"x","argMin")},n={axis:t};return z.runKernel(kd,a,n)}var py=D({argMin_:iN});function oN(e){let t={x:R(e,"x","asin")};return z.runKernel(Sl,t)}var cy=D({asin_:oN});function lN(e){let t={x:R(e,"x","asinh")};return z.runKernel(Tl,t)}var hy=D({asinh_:lN});function uN(e){let t={x:R(e,"x","atan")};return z.runKernel(Cl,t)}var fy=D({atan_:uN});function dN(e,t){let a=R(e,"a","atan2"),n=R(t,"b","atan2");[a,n]=St(a,n);let r={a,b:n};return z.runKernel(El,r)}var my=D({atan2_:dN});function pN(e){let t={x:R(e,"x","atanh")};return z.runKernel(Nl,t)}var gy=D({atanh_:pN});function cN(e,t,a,n,r="NHWC",s){let i=e[3],o=[...t,i],l=yy(r);return Jd(e,o,a,s,n,null,null,l)}function xy(e,t,a,n,r,s,i="channelsLast"){let[o,l]=Ec(t),u;if(i==="channelsLast")u=[o,l,e[3],e[3]];else if(i==="channelsFirst")u=[o,l,e[1],e[1]];else throw new Error(`Unknown dataFormat ${i}`);return Jd(e,u,a,n,r,s,!1,i)}function hN(e,t,a,n,r,s,i="NDHWC"){let[o,l,u]=i1(t),p,c;if(i==="NDHWC")c="channelsLast",p=[o,l,u,e[4],e[4]];else if(i==="NCDHW")c="channelsFirst",p=[o,l,u,e[1],e[1]];else throw new Error(`Unknown dataFormat ${i}`);return Ay(e,p,a,n,r,!1,c,s)}function Jd(e,t,a,n,r,s,i=!1,o="channelsLast"){let[l,u,p,c]=[-1,-1,-1,-1];if(o==="channelsLast")[l,u,p,c]=e;else if(o==="channelsFirst")[l,c,u,p]=e;else throw new Error(`Unknown dataFormat ${o}`);let[d,h,,f]=t,[m,g]=Ec(a),[x,A]=Ec(n),y=rl(d,x),b=rl(h,A),{padInfo:w,outHeight:S,outWidth:C}=gN(r,u,p,m,g,y,b,s,o),E=i?f*c:f,_;return o==="channelsFirst"?_=[l,E,S,C]:o==="channelsLast"&&(_=[l,S,C,E]),{batchSize:l,dataFormat:o,inHeight:u,inWidth:p,inChannels:c,outHeight:S,outWidth:C,outChannels:E,padInfo:w,strideHeight:m,strideWidth:g,filterHeight:d,filterWidth:h,effectiveFilterHeight:y,effectiveFilterWidth:b,dilationHeight:x,dilationWidth:A,inShape:e,outShape:_,filterShape:t}}function Ay(e,t,a,n,r,s=!1,i="channelsLast",o){let[l,u,p,c,d]=[-1,-1,-1,-1,-1];if(i==="channelsLast")[l,u,p,c,d]=e;else if(i==="channelsFirst")[l,d,u,p,c]=e;else throw new Error(`Unknown dataFormat ${i}`);let[h,f,m,,g]=t,[x,A,y]=i1(a),[b,w,S]=i1(n),C=rl(h,b),E=rl(f,w),_=rl(m,S),{padInfo:$,outDepth:M,outHeight:I,outWidth:N}=xN(r,u,p,c,x,A,y,C,E,_,o),O=s?g*d:g,L;return i==="channelsFirst"?L=[l,O,M,I,N]:i==="channelsLast"&&(L=[l,M,I,N,O]),{batchSize:l,dataFormat:i,inDepth:u,inHeight:p,inWidth:c,inChannels:d,outDepth:M,outHeight:I,outWidth:N,outChannels:O,padInfo:$,strideDepth:x,strideHeight:A,strideWidth:y,filterDepth:h,filterHeight:f,filterWidth:m,effectiveFilterDepth:C,effectiveFilterHeight:E,effectiveFilterWidth:_,dilationDepth:b,dilationHeight:w,dilationWidth:S,inShape:e,outShape:L,filterShape:t}}function fN(e,t,a,n,r){n==null&&(n=y2(e,t,a));let s=e[0],i=e[1],o=Os((s-t+2*n)/a+1,r),l=Os((i-t+2*n)/a+1,r);return[o,l]}function mN(e,t,a,n,r,s){r==null&&(r=y2(e,t,n));let i=e[0],o=e[1],l=e[2],u=Os((i-t+2*r)/n+1,s),p=Os((o-t+2*r)/n+1,s),c=Os((l-t+2*r)/n+1,s);return[u,p,c,a]}function y2(e,t,a,n=1){let r=rl(t,n);return Math.floor((e[0]*(a-1)-a+r)/2)}function Ec(e){return typeof e=="number"?[e,e,e]:e.length===2?[e[0],e[1],1]:e}function i1(e){return typeof e=="number"?[e,e,e]:e}function rl(e,t){return t<=1?e:e+(e-1)*(t-1)}function gN(e,t,a,n,r,s,i,o,l){let u,p,c;if(typeof e=="number"){u={top:e,bottom:e,left:e,right:e,type:e===0?"VALID":"NUMBER"};let d=fN([t,a],s,n,e,o);p=d[0],c=d[1]}else if(e==="same"){p=Math.ceil(t/n),c=Math.ceil(a/r);let d=Math.max(0,(p-1)*n+s-t),h=Math.max(0,(c-1)*r+i-a),f=Math.floor(d/2),m=d-f,g=Math.floor(h/2),x=h-g;u={top:f,bottom:m,left:g,right:x,type:"SAME"}}else if(e==="valid")u={top:0,bottom:0,left:0,right:0,type:"VALID"},p=Math.ceil((t-s+1)/n),c=Math.ceil((a-i+1)/r);else if(typeof e=="object"){let d=l==="channelsLast"?e[1][0]:e[2][0],h=l==="channelsLast"?e[1][1]:e[2][1],f=l==="channelsLast"?e[2][0]:e[3][0],m=l==="channelsLast"?e[2][1]:e[3][1];u={top:d,bottom:h,left:f,right:m,type:d===0&&h===0&&f===0&&m===0?"VALID":"EXPLICIT"},p=Os((t-s+d+h)/n+1,o),c=Os((a-i+f+m)/r+1,o)}else throw Error(`Unknown padding parameter: ${e}`);return{padInfo:u,outHeight:p,outWidth:c}}function xN(e,t,a,n,r,s,i,o,l,u,p){let c,d,h,f;if(typeof e=="number"){c={top:e,bottom:e,left:e,right:e,front:e,back:e,type:e===0?"VALID":"NUMBER"};let m=mN([t,a,n,1],o,1,r,e,p);d=m[0],h=m[1],f=m[2]}else if(e==="same"){d=Math.ceil(t/r),h=Math.ceil(a/s),f=Math.ceil(n/i);let m=(d-1)*r+o-t,g=(h-1)*s+l-a,x=(f-1)*i+u-n,A=Math.floor(m/2),y=m-A,b=Math.floor(g/2),w=g-b,S=Math.floor(x/2),C=x-S;c={top:b,bottom:w,left:S,right:C,front:A,back:y,type:"SAME"}}else if(e==="valid")c={top:0,bottom:0,left:0,right:0,front:0,back:0,type:"VALID"},d=Math.ceil((t-o+1)/r),h=Math.ceil((a-l+1)/s),f=Math.ceil((n-u+1)/i);else throw Error(`Unknown padding parameter: ${e}`);return{padInfo:c,outDepth:d,outHeight:h,outWidth:f}}function Os(e,t){if(!t)return Math.trunc(e);switch(t){case"round":return Math.round(e);case"ceil":return Math.ceil(e);case"floor":return Math.floor(e);default:throw new Error(`Unknown roundingMode ${t}`)}}function dd(e){let[t,a,n]=Ec(e);return t===1&&a===1&&n===1}function kr(e,t){return dd(e)||dd(t)}function yy(e){if(e==="NHWC")return"channelsLast";if(e==="NCHW")return"channelsFirst";throw new Error(`Unknown dataFormat ${e}`)}function Sn(e,t,a){if(a!=null){if(typeof t=="string")throw Error(`Error in ${e}: pad must be an integer when using dimRoundingMode ${a} but got pad ${t}.`);if(typeof t=="number")P(ol(t),()=>`Error in ${e}: pad must be an integer when using dimRoundingMode ${a} but got pad ${t}.`);else if(typeof t=="object")t.forEach(n=>{n.forEach(r=>{P(ol(r),()=>`Error in ${e}: pad must be an integer when using dimRoundingMode ${a} but got pad ${r}.`)})});else throw Error(`Error in ${e}: Unknown padding parameter: ${t}`)}}function AN(e,t){let a={x:R(e,"x","reshape","string_or_numeric")},n={shape:t};return z.runKernel(ql,a,n)}var J=D({reshape_:AN});function yN(e,t,a,n,r){let s=R(e,"x","avgPool","float32"),i=1;P(kr(a,i),()=>`Error in avgPool: Either strides or dilations must be 1. Got strides ${a} and dilations '${i}'`);let o=s,l=!1;s.rank===3&&(l=!0,o=J(s,[1,s.shape[0],s.shape[1],s.shape[2]])),P(o.rank===4,()=>`Error in avgPool: x must be rank 4 but got rank ${o.rank}.`),Sn("avgPool",n,r);let u={x:o},p={filterSize:t,strides:a,pad:n,dimRoundingMode:r},c=z.runKernel(Qs,u,p);return c=He(c,s.dtype),l?J(c,[c.shape[1],c.shape[2],c.shape[3]]):c}var b2=D({avgPool_:yN});function bN(e,t,a,n,r,s="NDHWC"){let i=R(e,"x","avgPool3d","float32"),o=i,l=!1;i.rank===4&&(l=!0,o=J(i,[1,i.shape[0],i.shape[1],i.shape[2],i.shape[3]])),P(o.rank===5,()=>`Error in avgPool3d: x must be rank 5 but got rank ${o.rank}.`),P(s==="NDHWC",()=>`Error in avgPool3d: Only NDHWC is currently supported, but got dataFormat of ${s}`),Sn("avgPool3d",n,r);let u={x:o},p={filterSize:t,strides:a,pad:n,dimRoundingMode:r,dataFormat:s},c=z.runKernel(Hc,u,p);return c=He(c,o.dtype),l?J(c,[c.shape[1],c.shape[2],c.shape[3],c.shape[4]]):c}var by=D({avgPool3d_:bN});function vN(e,t=0){P(e.length>=1,()=>"Pass at least one tensor to concat");let a=ud(e,"tensors","concat","string_or_numeric");if(a[0].dtype==="complex64"&&a.forEach(s=>{if(s.dtype!=="complex64")throw new Error(`Cannot concatenate complex64 tensors with a tensor with dtype ${s.dtype}. `)}),a.length===1)return wa(a[0]);let n=a,r={axis:t};return z.runKernel(Ml,n,r)}var at=D({concat_:vN});function wN(e){let t={x:R(e,"x","sigmoid","float32")};return z.runKernel(ao,t)}var Da=D({sigmoid_:wN});function kN(e,t,a){let n=R(e,"x","slice","string_or_numeric");if(n.rank===0)throw new Error("Slicing scalar is not possible");let r={x:n},s={begin:t,size:a};return z.runKernel(Zl,r,s)}var Pe=D({slice_:kN});function IN(e){let t={x:R(e,"x","tanh","float32")};return z.runKernel(po,t)}var Rc=D({tanh_:IN});function SN(e,t,a,n,r,s){let i=R(e,"forgetBias","basicLSTMCell"),o=R(t,"lstmKernel","basicLSTMCell"),l=R(a,"lstmBias","basicLSTMCell"),u=R(n,"data","basicLSTMCell"),p=R(r,"c","basicLSTMCell"),c=R(s,"h","basicLSTMCell"),d=at([u,c],1),h=st(d,o),f=be(h,l),m=f.shape[0],g=f.shape[1]/4,x=[m,g],A=Pe(f,[0,0],x),y=Pe(f,[0,g],x),b=Pe(f,[0,g*2],x),w=Pe(f,[0,g*3],x),S=be(ae(Da(A),Rc(y)),ae(p,Da(be(i,b)))),C=ae(Rc(S),Da(w));return[S,C]}var vy=D({basicLSTMCell_:SN});function TN(e,t,a){let n=R(e,"x","batchToSpaceND"),r=t.reduce((o,l)=>o*l);P(n.rank>=1+t.length,()=>`input rank is ${n.rank} but should be > than blockShape.length ${t.length}`),P(a.length===t.length,()=>`crops.length is ${a.length} but should be equal to blockShape.length ${t.length}`),P(n.shape[0]%r===0,()=>`input tensor batch is ${n.shape[0]} but is not divisible by the product of the elements of blockShape ${t.join(" * ")} === ${r}`);let s={x:n},i={blockShape:t,crops:a};return z.runKernel(Rl,s,i)}var v2=D({batchToSpaceND_:TN});function CN(e){let t;return e.rank===0||e.rank===1?t=J(e,[1,1,1,e.size]):e.rank===2?t=J(e,[1,1,e.shape[0],e.shape[1]]):e.rank===3?t=J(e,[1,e.shape[0],e.shape[1],e.shape[2]]):t=e,t}function NN(e,t,a,n,r,s){s==null&&(s=.001);let i=R(e,"x","batchNorm"),o=R(t,"mean","batchNorm"),l=R(a,"variance","batchNorm"),u;r!=null&&(u=R(r,"scale","batchNorm"));let p;n!=null&&(p=R(n,"offset","batchNorm")),P(o.rank===l.rank,()=>"Batch normalization gradient requires mean and variance to have equal ranks."),P(p==null||o.rank===p.rank,()=>"Batch normalization gradient requires mean and offset to have equal ranks."),P(u==null||o.rank===u.rank,()=>"Batch normalization gradient requires mean and scale to have equal ranks.");let c={x:CN(i),scale:u,offset:p,mean:o,variance:l},d={varianceEpsilon:s},h=z.runKernel(yi,c,d);return J(h,i.shape)}var Qd=D({batchNorm_:NN});function EN(e,t,a,n,r,s){let i=R(e,"x","batchNorm"),o=R(t,"mean","batchNorm"),l=R(a,"variance","batchNorm"),u;r!=null&&(u=R(r,"scale","batchNorm"));let p;return n!=null&&(p=R(n,"offset","batchNorm")),P(i.rank===2,()=>`Error in batchNorm2D: x must be rank 2 but got rank ${i.rank}.`),P(o.rank===2||o.rank===1,()=>`Error in batchNorm2D: mean must be rank 2 or rank 1 but got rank ${o.rank}.`),P(l.rank===2||l.rank===1,()=>`Error in batchNorm2D: variance must be rank 2 or rank 1 but got rank ${l.rank}.`),u!=null&&P(u.rank===2||u.rank===1,()=>`Error in batchNorm2D: scale must be rank 2 or rank 1 but got rank ${u.rank}.`),p!=null&&P(p.rank===2||p.rank===1,()=>`Error in batchNorm2D: offset must be rank 2 or rank 1 but got rank ${p.rank}.`),Qd(i,o,l,p,u,s)}var wy=D({batchNorm2d_:EN});function RN(e,t,a,n,r,s){let i=R(e,"x","batchNorm"),o=R(t,"mean","batchNorm"),l=R(a,"variance","batchNorm"),u;r!=null&&(u=R(r,"scale","batchNorm"));let p;return n!=null&&(p=R(n,"offset","batchNorm")),P(i.rank===3,()=>`Error in batchNorm3D: x must be rank 3 but got rank ${i.rank}.`),P(o.rank===3||o.rank===1,()=>`Error in batchNorm3D: mean must be rank 3 or rank 1 but got rank ${o.rank}.`),P(l.rank===3||l.rank===1,()=>`Error in batchNorm3D: variance must be rank 3 or rank 1 but got rank ${l.rank}.`),u!=null&&P(u.rank===3||u.rank===1,()=>`Error in batchNorm3D: scale must be rank 3 or rank 1 but got rank ${u.rank}.`),p!=null&&P(p.rank===3||p.rank===1,()=>`Error in batchNorm3D: offset must be rank 3 or rank 1 but got rank ${p.rank}.`),Qd(i,o,l,p,u,s)}var ky=D({batchNorm3d_:RN});function MN(e,t,a,n,r,s){let i=R(e,"x","batchNorm"),o=R(t,"mean","batchNorm"),l=R(a,"variance","batchNorm"),u;r!=null&&(u=R(r,"scale","batchNorm"));let p;return n!=null&&(p=R(n,"offset","batchNorm")),P(i.rank===4,()=>`Error in batchNorm4D: x must be rank 4 but got rank ${i.rank}.`),P(o.rank===4||o.rank===1,()=>`Error in batchNorm4D: mean must be rank 4 or rank 1 but got rank ${o.rank}.`),P(l.rank===4||l.rank===1,()=>`Error in batchNorm4D: variance must be rank 4 or rank 1 but got rank ${l.rank}.`),u!=null&&P(u.rank===4||u.rank===1,()=>`Error in batchNorm4D: scale must be rank 4 or rank 1 but got rank ${u.rank}.`),p!=null&&P(p.rank===4||p.rank===1,()=>`Error in batchNorm4D: offset must be rank 4 or rank 1 but got rank ${p.rank}.`),Qd(i,o,l,p,u,s)}var Iy=D({batchNorm4d_:MN});function $N(e,t,a){let n=R(e,"x","bincount"),r=R(t,"weights","bincount");P(n.dtype==="int32",()=>`Error in bincount: input dtype must be int32, but got ${n.dtype}`),P(a>=0,()=>`size must be non-negative, but got ${a}.`),P(r.size===n.size||r.size===0,()=>`Error in bincount: weights must have the same size as input or0-length, but got input shape: ${n.shape}, weights shape: ${r.shape}.`);let s={x:n,weights:r},i={size:a};return z.runKernel(Id,s,i)}var w2=D({bincount_:$N});function _N(e,t){let a=R(e,"s0","broadcastArgs","int32"),n=R(t,"s1","broadcastArgs","int32");if(a.rank!==1)throw new Error(`broadcastArgs(): first input must be a vector (rank=1). Has rank ${a.rank}`);if(n.rank!==1)throw new Error(`broadcastArgs(): second input must be a vector (rank=1). Has rank ${n.rank}`);let r={s0:a,s1:n};return z.runKernel(jc,r)}var Sy=D({broadcastArgs_:_N});function PN(e,t){let a=R(e,"broadcastTo","x"),n=a.shape;if(Ja(t),t.lengtha.rank){let l=a.shape.slice();for(;l.length=0;l--)if(r[l]===t[l])s[l]=1;else if(a.shape[l]!==1)throw new Error(`broadcastTo(): [${n}] cannot be broadcast to [${t}].`);if(s.map((l,u)=>l>1?u:-1).filter(l=>l>=0).length===0)return wa(a);let i={x:a},o={reps:s};return z.runKernel(ns,i,o)}var sl=D({broadcastTo_:PN});function FN(e){let t={x:R(e,"x","ceil","float32")};return z.runKernel(ai,t)}var Ty=D({ceil_:FN});function nr(e,t,a){Ja(e);let n={shape:e,value:t,dtype:a};return z.runKernel(Fl,{},n)}function ON(e,t,a){let n=R(e,"x","clipByValue");if(P(t<=a,()=>`Error in clip: min (${t}) must be less than or equal to max (${a}).`),t===a)return nr(n.shape,t,n.dtype);let r={x:n},s={clipValueMin:t,clipValueMax:a};return z.runKernel(as,r,s)}var Cy=D({clipByValue_:ON});function DN(e){return at(e,0)}var Ny=D({concat1d_:DN});function zN(e,t){return at(e,t)}var ru=D({concat2d_:zN});function LN(e,t){return at(e,t)}var Ey=D({concat3d_:LN});function BN(e,t){return at(e,t)}var Ry=D({concat4d_:BN});function WN(e,t,a,n,r="NHWC",s=[1,1],i){let o=R(e,"x","conv2d","float32"),l=R(t,"filter","conv2d","float32"),u=o,p=!1;o.rank===3&&(p=!0,u=J(o,[1,o.shape[0],o.shape[1],o.shape[2]])),P(u.rank===4,()=>`Error in conv2d: input must be rank 4, but got rank ${u.rank}.`),P(l.rank===4,()=>`Error in conv2d: filter must be rank 4, but got rank ${l.rank}.`),Sn("conv2d",n,i);let c=r==="NHWC"?u.shape[3]:u.shape[1];P(c===l.shape[2],()=>`Error in conv2d: depth of input (${c}) must match input depth for filter ${l.shape[2]}.`),P(kr(a,s),()=>`Error in conv2D: Either strides or dilations must be 1. Got strides ${a} and dilations '${s}'`);let d={x:u,filter:l},h={strides:a,pad:n,dataFormat:r,dilations:s,dimRoundingMode:i},f=z.runKernel(ni,d,h);return p?J(f,[f.shape[1],f.shape[2],f.shape[3]]):f}var ep=D({conv2d_:WN});function VN(e,t,a,n,r="NWC",s=1,i){let o=R(e,"x","conv1d"),l=R(t,"filter","conv1d"),u=o,p=!1;o.rank===2&&(p=!0,u=J(o,[1,o.shape[0],o.shape[1]])),P(u.rank===3,()=>`Error in conv1d: input must be rank 3, but got rank ${u.rank}.`),P(l.rank===3,()=>`Error in conv1d: filter must be rank 3, but got rank ${l.rank}.`),Sn("conv1d",n,i),P(u.shape[2]===l.shape[1],()=>`Error in conv1d: depth of input (${u.shape[2]}) must match input depth for filter ${l.shape[1]}.`),P(kr(a,s),()=>`Error in conv1D: Either stride or dilation must be 1. Got stride ${a} and dilation '${s}'`),P(r==="NWC",()=>`Error in conv1d: got dataFormat of ${r} but only NWC is currently supported.`);let c=J(l,[1,l.shape[0],l.shape[1],l.shape[2]]),d=J(u,[u.shape[0],1,u.shape[1],u.shape[2]]),h=ep(d,c,[1,a],n,"NHWC",[1,s],i);return p?J(h,[h.shape[2],h.shape[3]]):J(h,[h.shape[0],h.shape[2],h.shape[3]])}var My=D({conv1d_:VN});function UN(e,t,a,n,r,s="NHWC",i){P(e.length===t.rank,()=>`Length of inShape (${e.length}) and rank of dy (${t.rank}) must match`);let o=e,l=t,u=!1;t.rank===3&&(u=!0,l=J(t,[1,t.shape[0],t.shape[1],t.shape[2]]),o=[1,e[0],e[1],e[2]]),P(o.length===4,()=>`Error in conv2dDerInput: inShape must be length 4, but got length ${o.length}.`),P(l.rank===4,()=>`Error in conv2dDerInput: dy must be rank 4, but got rank ${l.rank}`),P(a.rank===4,()=>`Error in conv2dDerInput: filter must be rank 4, but got rank ${a.rank}`);let p=s==="NHWC"?o[3]:o[1],c=s==="NHWC"?l.shape[3]:l.shape[1];P(p===a.shape[2],()=>`Error in conv2dDerInput: depth of input (${p}) must match input depth for filter ${a.shape[2]}.`),P(c===a.shape[3],()=>`Error in conv2dDerInput: depth of output (${c}) must match output depth for filter ${a.shape[3]}.`),Sn("conv2dDerInput",r,i);let d={dy:l,filter:a},h={strides:n,pad:r,dataFormat:s,dimRoundingMode:i,inputShape:o},f=z.runKernel(ri,d,h);return u?J(f,[f.shape[1],f.shape[2],f.shape[3]]):f}var $y=D({conv2DBackpropInput_:UN});function GN(e,t,a,n,r,s){let i=R(e,"x","conv2dTranspose"),o=R(t,"filter","conv2dTranspose");return $y(a,i,o,n,r,"NHWC",s)}var _y=D({conv2dTranspose_:GN});function HN(e,t,a,n,r="NDHWC",s=[1,1,1]){let i=R(e,"x","conv3d"),o=R(t,"filter","conv3d"),l=i,u=!1;i.rank===4&&(u=!0,l=J(i,[1,i.shape[0],i.shape[1],i.shape[2],i.shape[3]])),P(l.rank===5,()=>`Error in conv3d: input must be rank 5, but got rank ${l.rank}.`),P(o.rank===5,()=>`Error in conv3d: filter must be rank 5, but got rank ${o.rank}.`),P(l.shape[4]===o.shape[3],()=>`Error in conv3d: depth of input (${l.shape[4]}) must match input depth for filter ${o.shape[3]}.`),P(kr(a,s),()=>`Error in conv3D: Either strides or dilations must be 1. Got strides ${a} and dilations '${s}'`),P(r==="NDHWC",()=>`Error in conv3d: got dataFormat of ${r} but only NDHWC is currently supported.`);let p={x:l,filter:o},c={strides:a,pad:n,dataFormat:r,dilations:s},d=z.runKernel(Kc,p,c);return u?J(d,[d.shape[1],d.shape[2],d.shape[3],d.shape[4]]):d}var Py=D({conv3d_:HN});function jN(e,t,a,n,r){P(e.length===t.rank,()=>`Length of inShape (${e.length}) and rank of dy (${t.rank}) must match`);let s=e,i=t,o=!1;t.rank===4&&(o=!0,i=J(t,[1,t.shape[0],t.shape[1],t.shape[2],t.shape[3]]),s=[1,e[0],e[1],e[2],e[3]]);let l=s[4],u=i.shape[4];P(s.length===5,()=>`Error in conv3dDerInput: inShape must be length 5, but got length ${s.length}.`),P(i.rank===5,()=>`Error in conv3dDerInput: dy must be rank 5, but got rank ${i.rank}`),P(a.rank===5,()=>`Error in conv3dDerInput: filter must be rank 5, but got rank ${a.rank}`),P(l===a.shape[3],()=>`Error in conv3dDerInput: depth of input (${l}) must match input depth for filter ${a.shape[3]}.`),P(u===a.shape[4],()=>`Error in conv3dDerInput: depth of output (${u}) must match output depth for filter ${a.shape[4]}.`);let p={dy:i,filter:a},c={pad:r,strides:n,inputShape:s},d=z.runKernel(Zc,p,c);return o?J(d,[d.shape[1],d.shape[2],d.shape[3],d.shape[4]]):d}var qN=D({conv3DBackpropInput_:jN});function XN(e,t,a,n,r){let s=R(e,"x","conv3dTranspose"),i=R(t,"filter","conv3dTranspose");return qN(a,s,i,n,r)}var Fy=D({conv3dTranspose_:XN});function KN(e){let t={x:R(e,"x","cos","float32")};return z.runKernel(si,t)}var Oy=D({cos_:KN});function ZN(e){let t={x:R(e,"x","cosh","float32")};return z.runKernel(ii,t)}var Dy=D({cosh_:ZN});function YN(e,t=0,a=!1,n=!1){let r={x:R(e,"x","cumprod")},s={axis:t,exclusive:a,reverse:n};return z.runKernel(oi,r,s)}var zy=D({cumprod_:YN});function JN(e,t=0,a=!1,n=!1){let r={x:R(e,"x","cumsum")},s={axis:t,exclusive:a,reverse:n};return z.runKernel(li,r,s)}var Ly=D({cumsum_:JN});function QN(e,t,a,n=!1){let r=R(e,"x","denseBincount"),s=R(t,"weights","denseBincount");P(r.dtype==="int32",()=>`Error in denseBincount: input dtype must be int32, but got ${r.dtype}`),P(r.rank<=2,()=>`Error in denseBincount: input must be at most rank 2, but got rank ${r.rank}.`),P(a>=0,()=>`size must be non-negative, but got ${a}.`),P(s.size===r.size||s.size===0,()=>`Error in denseBincount: weights must have the same shape as x or 0-length, but got x shape: ${r.shape}, weights shape: ${s.shape}.`);let i={x:r,weights:s},o={size:a,binaryOutput:n};return z.runKernel(Td,i,o)}var By=D({denseBincount_:QN});function eE(e,t,a="NHWC"){let n=R(e,"x","depthToSpace","float32"),r=a==="NHWC"?n.shape[1]:n.shape[2],s=a==="NHWC"?n.shape[2]:n.shape[3],i=a==="NHWC"?n.shape[3]:n.shape[1];P(t>1,()=>`blockSize should be > 1 for depthToSpace, but was: ${t}`),P(r*t>=0,()=>`Negative dimension size caused by overflow when multiplying ${r} and ${t} for depthToSpace with input shape ${n.shape}`),P(s*t>=0,()=>`Negative dimension size caused by overflow when multiplying ${s} and ${t} for depthToSpace with input shape ${n.shape}`),P(i%(t*t)===0,()=>`Dimension size must be evenly divisible by ${t*t} but is ${i} for depthToSpace with input shape ${n.shape}`);let o={x:n},l={blockSize:t,dataFormat:a};return z.runKernel(di,o,l)}var Wy=D({depthToSpace_:eE});function tE(e,t,a,n,r="NHWC",s=[1,1],i){let o=R(e,"x","depthwiseConv2d","float32"),l=R(t,"filter","depthwiseConv2d","float32"),u=o,p=!1;o.rank===3&&(p=!0,u=J(o,[1,o.shape[0],o.shape[1],o.shape[2]])),P(u.rank===4,()=>`Error in depthwiseConv2d: input must be rank 4, but got rank ${u.rank}.`),P(l.rank===4,()=>`Error in depthwiseConv2d: filter must be rank 4, but got rank ${l.rank}.`);let c=r==="NHWC"?u.shape[3]:u.shape[1];P(c===l.shape[2],()=>`Error in depthwiseConv2d: number of input channels (${c}) must match the inChannels dimension in filter ${l.shape[2]}.`),Sn("depthwiseConv2d",n,i);let d={x:u,filter:l},h={strides:a,pad:n,dataFormat:r,dilations:s,dimRoundingMode:i},f=z.runKernel(pi,d,h);return p?J(f,[f.shape[1],f.shape[2],f.shape[3]]):f}var hh=D({depthwiseConv2d_:tE});function aE(e){let t={x:R(e,"x","diag")};return z.runKernel(Qc,t)}var Vy=D({diag_:aE});function nE(e,t,a,n,r=[1,1],s="NHWC"){let i=R(e,"x","dilation2d"),o=R(t,"filter","dilation2d");P(i.rank===3||i.rank===4,()=>`Error in dilation2d: input must be rank 3 or 4, but got rank ${i.rank}.`),P(o.rank===3,()=>`Error in dilation2d: filter must be rank 3, but got rank ${o.rank}.`),P(s==="NHWC",()=>`Error in dilation2d: Only NHWC is currently supported, but got dataFormat of ${s}`);let l=i,u=!1;i.rank===3&&(l=J(i,[1,i.shape[0],i.shape[1],i.shape[2]]),u=!0);let p={x:l,filter:o},c={strides:a,pad:n,dilations:r},d=z.runKernel(eh,p,c);return u?J(d,[d.shape[1],d.shape[2],d.shape[3]]):d}var Uy=D({dilation2d_:nE});function rE(e,t){let a=R(e,"a","equal","string_or_numeric"),n=R(t,"b","equal","string_or_numeric");[a,n]=St(a,n),zt(a.shape,n.shape);let r={a,b:n};return z.runKernel(fi,r)}var k2=D({equal_:rE});function sE(e,t,a){let n=R(t,"a","where"),r=R(a,"b","where"),s=R(e,"condition","where","bool"),i=zt(zt(s.shape,n.shape),r.shape),o=sl(s,i),l=sl(n,i),u=sl(r,i),p={condition:o,t:l,e:u};return z.runKernel(Kl,p)}var Vs=D({where_:sE});function iE(e){let t={x:R(e,"x","zerosLike")};return z.runKernel(nu,t)}var Ka=D({zerosLike_:iE});function oE(e,t){let a=R(e,"a","div"),n=R(t,"b","div");[a,n]=St(a,n);let r=me(a,n),s=Ka(r),i=k2(n,s);return Vs(i,s,r)}var Gy=D({divNoNan_:oE});function lE(e,t){let a=R(e,"t1","dot"),n=R(t,"t2","dot");P((a.rank===1||a.rank===2)&&(n.rank===1||n.rank===2),()=>`Error in dot: inputs must all be rank 1 or 2, but got ranks ${a.rank} and ${n.rank}.`);let r=a.rank===1?a.size:a.shape[1],s=n.rank===1?n.size:n.shape[0];if(P(r===s,()=>`Error in dot: inner dimensions of inputs must match, but got ${r} and ${s}.`),a.rank===1&&n.rank===1){let i=J(a,[1,-1]),o=J(n,[-1,1]),l=st(i,o);return J(l,[])}else if(a.rank===1&&n.rank===2){let i=J(a,[1,-1]),o=J(n,[n.shape[0],n.shape[1]]),l=st(i,o);return J(l,[l.size])}else if(a.rank===2&&n.rank===1){let i=J(n,[-1,1]),o=st(a,i);return J(o,[o.size])}else{let i=J(n,[n.shape[0],n.shape[1]]);return st(a,i)}}var Hy=D({dot_:lE});function uE(e,...t){let a=t.map((r,s)=>R(r,`tensors${s}`,"einsum")),n={equation:e};return z.runKernel(Cd,a,n)}var jy=D({einsum_:uE});function dE(e){let t={x:R(e,"x","elu","float32")};return z.runKernel(hi,t)}var I2=D({elu_:dE});function pE(e){let t=R(e,"x","erf");P(t.dtype==="int32"||t.dtype==="float32",()=>"Input dtype must be `int32` or `float32`."),t.dtype==="int32"&&(t=He(t,"float32"));let a={x:t};return z.runKernel($l,a)}var qy=D({erf_:pE});function S2(e,t){for(let a=0;ae[s]);return[a,r]}function tp(e,t){let a=t.map(n=>1);return Xy(e,a,t)}function hE(e,t,a){P(S2(t,a),()=>`${e} supports only inner-most axes for now. Got axes ${t} and rank-${a} input.`)}function fE(e,t){if(S2(e,t))return null;let a=[];for(let n=0;na.push(n)),a}function mE(e){return e.map((t,a)=>[a,t]).sort((t,a)=>t[1]-a[1]).map(t=>t[0])}function gE(e,t){let a=[];for(let n=t-e;n"Axis must be <= rank of the tensor");let n={input:a},r={dim:t};return z.runKernel(_l,n,r)}var Gt=D({expandDims_:TE});function CE(e){let t={x:R(e,"x","expm1")};return z.runKernel(Pl,t)}var Yy=D({expm1_:CE});function NE(e,t){let a=R(e,"x","tile","string_or_numeric");P(a.rank===t.length,()=>`Error in transpose: rank of input ${a.rank} must match length of reps ${t}.`);let n={x:a},r={reps:t};return z.runKernel(ns,n,r)}var Gr=D({tile_:NE});function EE(e,t,a,n="float32"){t==null&&(t=e);let r=Me([e,t],n),s=e<=t?e:t;for(let o=0;o`Error in localResponseNormalization: x must be rank 3 or 4 but got rank ${s.rank}.`),P(ol(t),()=>`Error in localResponseNormalization: depthRadius must be an integer but got depthRadius ${t}.`);let i=s,o=!1;s.rank===3&&(o=!0,i=J(s,[1,s.shape[0],s.shape[1],s.shape[2]]));let l={x:i},u={depthRadius:t,bias:a,alpha:n,beta:r},p=z.runKernel(ah,l,u);return o?J(p,[p.shape[1],p.shape[2],p.shape[3]]):p}var nb=D({localResponseNormalization_:BE});function WE(e){let t={x:R(e,"x","log","float32")};return z.runKernel(Ni,t)}var cl=D({log_:WE});function VE(e){let t={x:R(e,"x","log1p")};return z.runKernel(Ll,t)}var M2=D({log1p_:VE});function UE(e){return P(Hr(e),()=>"The f passed in grad(f) must be a function"),(t,a)=>{let n=R(t,"x","tf.grad","string_or_numeric"),r=a!=null?R(a,"dy","tf.grad"):null;return z.tidy(()=>{let{value:s,grads:i}=z.gradients(()=>e(n),[n],r);return r!=null&&Sa(s.shape,r.shape,"The shape of dy passed in grad(f)(x, dy) must match the shape returned by f(x)"),mh(i),i[0]})}}function GE(e){return P(Hr(e),()=>"The f passed in grads(f) must be a function"),(t,a)=>{P(Array.isArray(t),()=>"The args passed in grads(f)(args) must be an array of `Tensor`s or `TensorLike`s");let n=ud(t,"args","tf.grads","string_or_numeric"),r=a!=null?R(a,"dy","tf.grads"):null;return z.tidy(()=>{let{value:s,grads:i}=z.gradients(()=>e(...n),n,r);return r!=null&&Sa(s.shape,r.shape,"The shape of dy passed in grads(f)([x1,...], dy) must match the shape returned by f([x1,...])"),mh(i),i})}}function HE(e){return P(Hr(e),()=>"The f passed in valueAndGrad(f) must be a function"),(t,a)=>{P(t instanceof pt,()=>"The x passed in valueAndGrad(f)(x) must be a tensor"),P(a==null||a instanceof pt,()=>"The dy passed in valueAndGrad(f)(x, dy) must be a tensor");let{grads:n,value:r}=z.gradients(()=>e(t),[t],a);return mh(n),{grad:n[0],value:r}}}function jE(e){return P(Hr(e),()=>"The f passed in valueAndGrads(f) must be a function"),(t,a)=>{P(Array.isArray(t)&&t.every(r=>r instanceof pt),()=>"The args passed in valueAndGrads(f)(args) must be array of tensors"),P(a==null||a instanceof pt,()=>"The dy passed in valueAndGrads(f)(args, dy) must be a tensor");let n=z.gradients(()=>e(...t),t,a);return a!=null&&Sa(n.value.shape,a.shape,"The shape of dy passed in valueAndGrads(f)([x1,...], dy) must match the shape returned by f([x1,...])"),mh(n.grads),n}}function rb(e,t){P(Hr(e),()=>"The f passed in variableGrads(f) must be a function"),P(t==null||Array.isArray(t)&&t.every(u=>u instanceof od),()=>"The varList passed in variableGrads(f, varList) must be an array of variables");let a=t!=null;if(!a){t=[];for(let u in z.registeredVariables)t.push(z.registeredVariables[u])}let n=a?t.filter(u=>!u.trainable):null,r=t.length;t=t.filter(u=>u.trainable),P(t.length>0,()=>`variableGrads() expects at least one of the input variables to be trainable, but none of the ${r} variables is trainable.`);let s=!0,{value:i,grads:o}=z.gradients(e,t,null,s);P(o.some(u=>u!=null),()=>"Cannot find a connection between any variable and the result of the loss function y=f(x). Please make sure the operations that use variables are inside the function f passed to minimize()."),P(i.rank===0,()=>`The f passed in variableGrads(f) must return a scalar, but it returned a rank-${i.rank} tensor`);let l={};return t.forEach((u,p)=>{o[p]!=null&&(l[u.name]=o[p])}),n!=null&&n.forEach(u=>l[u.name]=null),{value:i,grads:l}}function Qn(e){return z.customGrad(e)}function mh(e){if(e.filter(t=>t==null).length>0)throw new Error(`Cannot compute gradient of y=f(x) with respect to x. Make sure that the f you passed encloses all operations that lead from x to y.`)}function qE(e){let t={x:R(e,"x","softplus")};return z.runKernel(Fd,t)}var $2=D({softplus_:qE});function XE(e){let t=R(e,"x","logSigmoid");return Qn(a=>({value:Xn($2(Xn(a))),gradFunc:n=>ae(n,Da(Xn(a)))}))(t)}var sb=D({logSigmoid_:XE});function KE(e,t){let a=R(e,"a","sub"),n=R(t,"b","sub");[a,n]=St(a,n);let r={a,b:n};return z.runKernel(lo,r)}var fe=D({sub_:KE});function ZE(e,t=-1){let a=R(e,"logits","logSoftmax");if(t===-1&&(t=a.rank-1),t!==a.rank-1)throw Error(`Log Softmax along a non-last dimension is not yet supported. Logits was rank ${a.rank} and axis was ${t}`);return Qn((n,r)=>{let s=pa(n,t,!0),i=fe(n,s),o=fe(He(i,"float32"),cl(tt(Zr(i),t,!0)));return r([o]),{value:o,gradFunc:(l,u)=>{let[p]=u,c=!0,d=Zr(p);return fe(l,ae(tt(l,t,c),d))}}})(a)}var ib=D({logSoftmax_:ZE});function YE(e,t=null,a=!1){let n=R(e,"x","logSumExp"),r=wd(t,n.shape),s=pa(n,r,!0),i=fe(n,s),o=Zr(i),l=tt(o,r),u=cl(l),p=be(J(s,u.shape),u);if(a){let c=tp(p.shape,r);return J(p,c)}return p}var _2=D({logSumExp_:YE});function JE(e,t){let a=R(e,"a","logicalAnd","bool"),n=R(t,"b","logicalAnd","bool");zt(a.shape,n.shape);let r={a,b:n};return z.runKernel(Ei,r)}var pd=D({logicalAnd_:JE});function QE(e){let t={x:R(e,"x","logicalNot","bool")};return z.runKernel(Ri,t)}var P2=D({logicalNot_:QE});function eR(e,t){let a=R(e,"a","logicalOr","bool"),n=R(t,"b","logicalOr","bool");zt(a.shape,n.shape);let r={a,b:n};return z.runKernel(Bl,r)}var F2=D({logicalOr_:eR});function tR(e,t){let a=R(e,"a","logicalXor","bool"),n=R(t,"b","logicalXor","bool");return zt(a.shape,n.shape),pd(F2(e,t),P2(pd(e,t)))}var ob=D({logicalXor_:tR}),oc=2147483648;function aR(e,t,a="left"){let n=R(e,"sortedSequence","searchSorted"),r=R(t,"values","searchSorted"),s=n.shape[n.shape.length-1],i=r.shape[r.shape.length-1],o=J(n,[-1,s]),l=J(r,[-1,i]);if(o.rank<2)throw new Error("Sorted input argument must be at least 2-dimensional");if(o.shape[0]!==l.shape[0])throw new Error("Leading dimension of 'sortedSequence' and 'values' must match.");if(At(l.shape)>=oc)throw new Error(`values tensor size must less than ${oc}`);if(o.shape[1]>=oc)throw new Error(`trailing dim_size must less than ${oc} for int32 output type, was ${o.shape[1]}`);let u={sortedSequence:o,values:l},p={side:a};return z.runKernel($d,u,p)}var gh=D({searchSorted_:aR});function lb(e,t){return gh(e,t,"left")}function nR(e,t,a,n,r){let s=R(e,"x","maxPool"),i=1,o=s,l=!1;s.rank===3&&(l=!0,o=J(s,[1,s.shape[0],s.shape[1],s.shape[2]])),P(o.rank===4,()=>`Error in maxPool: input must be rank 4 but got rank ${o.rank}.`),P(kr(a,i),()=>`Error in maxPool: Either strides or dilations must be 1. Got strides ${a} and dilations '${i}'`),Sn("maxPool",n,r);let u={x:o},p={filterSize:t,strides:a,pad:n,dimRoundingMode:r},c=z.runKernel(_i,u,p);return l?J(c,[c.shape[1],c.shape[2],c.shape[3]]):c}var O2=D({maxPool_:nR});function rR(e,t=[1,1,1],a,n,r,s="NDHWC"){let i=R(e,"x","maxPool3d"),o=i,l=!1;i.rank===4&&(l=!0,o=J(i,[1,i.shape[0],i.shape[1],i.shape[2],i.shape[3]])),P(o.rank===5,()=>`Error in maxPool3d: x must be rank 5 but got rank ${o.rank}.`),P(s==="NDHWC",()=>`Error in maxPool3d: Only NDHWC is currently supported, but got dataFormat of ${s}`),Sn("maxPool3d",n,r);let u={x:o},p={filterSize:t,strides:a,pad:n,dimRoundingMode:r,dataFormat:s},c=z.runKernel(nh,u,p);return l?J(c,[c.shape[1],c.shape[2],c.shape[3],c.shape[4]]):c}var ub=D({maxPool3d_:rR});function sR(e,t,a,n,r=!1){let s={x:R(e,"x","maxPoolWithArgmax")},i={filterSize:t,strides:a,pad:n,includeBatchInIndex:r},o=z.runKernel(rh,s,i);return{result:o[0],indexes:o[1]}}var db=D({maxPoolWithArgmax_:sR});function iR(e,t){let a=R(e,"a","maximum"),n=R(t,"b","maximum");[a,n]=St(a,n),a.dtype==="bool"&&(a=He(a,"int32"),n=He(n,"int32")),zt(a.shape,n.shape);let r={a,b:n};return z.runKernel($i,r)}var D2=D({maximum_:iR});function oR(e,t=null,a=!1){let n={x:R(e,"x","mean")},r={axis:t,keepDims:a};return z.runKernel(Pi,n,r)}var cd=D({mean_:oR});function fn(e,t="float32"){if(Ja(e),t==="complex64"){let n=fn(e,"float32"),r=fn(e,"float32");return br(n,r)}let a=Gc(At(e),t);return z.makeTensor(a,e,t)}function Wr(e,t="float32"){if(Ja(e),t==="complex64"){let n=Wr(e,"float32"),r=fn(e,"float32");return br(n,r)}let a=L1(At(e),t);return z.makeTensor(a,e,t)}function pb(e,t,{indexing:a="xy"}={}){if(a!=="xy"&&a!=="ij")throw new TypeError(`${a} is not a valid third argument to meshgrid`);if(e===void 0)return[];let n=R(e,"x","meshgrid",e instanceof pt?e.dtype:"float32");if(t===void 0)return[n];let r=R(t,"y","meshgrid",t instanceof pt?t.dtype:"float32"),s=At(n.shape),i=At(r.shape);return a==="xy"?(n=J(n,[1,-1]),r=J(r,[-1,1]),[st(Wr([i,1],n.dtype),n),st(r,Wr([1,s],r.dtype))]):(n=J(n,[-1,1]),r=J(r,[1,-1]),[st(n,Wr([1,i],n.dtype)),st(Wr([s,1],r.dtype),r)])}function lR(e,t){let a=R(e,"a","minimum"),n=R(t,"b","minimum");[a,n]=St(a,n),a.dtype==="bool"&&(a=He(a,"int32"),n=He(n,"int32")),zt(a.shape,n.shape);let r={a,b:n};return z.runKernel(Oi,r)}var z2=D({minimum_:lR});function uR(e,t,a){P(a==="reflect"||a==="symmetric",()=>`Invalid mode. Mode must be either reflect or symmetric. Got ${a}.`);let n=R(e,"x","mirrorPad");if(n.rank===0)throw new Error("mirrorPad(scalar) is not defined. Pass non-scalar to mirrorPad");P(t.length===n.rank,()=>`Padding doesn't match input. Must be ${n.rank}. Got ${t.length}.`);let r=a==="reflect"?1:0;for(let o=0;o"Invalid number of paddings. Must be length of 2 each."),P(t[o][0]>=0&&t[o][0]<=n.shape[o]-r&&t[o][1]>=0&&t[o][1]<=n.shape[o]-r,()=>`Padding in dimension ${o} cannot be greater than or equal to ${n.shape[o]-r} or less than 0 for input of shape ${n.shape}`);let s={paddings:t,mode:a},i={x:n};return z.runKernel(Di,i,s)}var cb=D({mirrorPad_:uR});function dR(e,t){let a=R(e,"a","mod"),n=R(t,"b","mod");[a,n]=St(a,n);let r={a,b:n};return z.runKernel(Wl,r)}var su=D({mod_:dR});function pR(e,t=null,a=!1){e=R(e,"x","moments");let n=wd(t,e.shape),r=cd(e,n,a),s=r.shape;a||(s=tp(r.shape,n));let i=In(fe(He(e,"float32"),J(r,s))),o=cd(i,n,a);return{mean:r,variance:o}}var hb=D({moments_:pR});function cR(e,t,a,n){let r=R(t,"data","multiRNNCell"),s=ud(a,"c","multiRNNCell"),i=ud(n,"h","multiRNNCell"),o=r,l=[];for(let c=0;c2)throw new Error(`Rank of probabilities must be 1 or 2, but is ${i}`);a=a||Math.random();let o={logits:i===1?J(r,[1,-1]):r},l={numSamples:t,seed:a,normalized:n},u=z.runKernel(sh,o,l);return i===1?J(u,[u.size]):u}var mb=D({multinomial_:hR});function fR(e,t){let a=R(e,"a","notEqual","string_or_numeric"),n=R(t,"b","notEqual","string_or_numeric");[a,n]=St(a,n),zt(a.shape,n.shape);let r={a,b:n};return z.runKernel(Li,r)}var L2=D({notEqual_:fR});function mR(e){let t={x:R(e,"x","onesLike")};return z.runKernel(Gl,t)}var gb=D({onesLike_:mR});function gR(e,t){let a=R(e,"v1","outerProduct"),n=R(t,"v2","outerProduct");P(a.rank===1&&n.rank===1,()=>`Error in outerProduct: inputs must be rank 1, but got ranks ${a.rank} and ${n.rank}.`);let r=J(a,[-1,1]),s=J(n,[1,-1]);return st(r,s)}var xb=D({outerProduct_:gR});function xR(e,t,a=0){let n=R(e,"x","pad");if(n.rank===0)throw new Error("pad(scalar) is not defined. Pass non-scalar to pad");let r={paddings:t,constantValue:a},s={x:n};return z.runKernel(Ui,s,r)}var rr=D({pad_:xR});function AR(e,t,a=0){return P(t.length===2,()=>"Invalid number of paddings. Must be length of 2."),rr(e,[t],a)}var Ab=D({pad1d_:AR});function yR(e,t,a=0){return P(t.length===2&&t[0].length===2&&t[1].length===2,()=>"Invalid number of paddings. Must be length of 2 each."),rr(e,t,a)}var yb=D({pad2d_:yR});function bR(e,t,a=0){return P(t.length===3&&t[0].length===2&&t[1].length===2&&t[2].length===2,()=>"Invalid number of paddings. Must be length of 2 each."),rr(e,t,a)}var bb=D({pad3d_:bR});function vR(e,t,a=0){return P(t.length===4&&t[0].length===2&&t[1].length===2&&t[2].length===2&&t[3].length===2,()=>"Invalid number of paddings. Must be length of 2 each."),rr(e,t,a)}var vb=D({pad4d_:vR});function wR(e,t,a){let n=R(e,"x","spaceToBatchND");P(n.rank>=1+t.length,()=>`input rank ${n.rank} should be > than [blockShape] ${t.length}`),P(a.length===t.length,()=>`paddings.shape[0] ${a.length} must be equal to [blockShape] ${t.length}`),P(n.shape.reduce((i,o,l)=>l>0&&l<=t.length?i&&(o+a[l-1][0]+a[l-1][1])%t[l-1]===0:i,!0),()=>`input spatial dimensions ${n.shape.slice(1)} with paddings ${a.toString()} must be divisible by blockShapes ${t.toString()}`);let r={x:n},s={blockShape:t,paddings:a};return z.runKernel(Jl,r,s)}var B2=D({spaceToBatchND_:wR});function kR(e,t,a,n,r,s,i){r==null&&(r=[1,1]),s==null&&(s=1),n===0&&(n="valid");let o=R(e,"x","maxPool"),l=o,u=!1;o.rank===3&&(u=!0,l=J(o,[1,o.shape[0],o.shape[1],o.shape[2]])),P(kr(s,r),()=>`Error in pool: Either strides or dilations must be 1. Got strides ${s} and dilations '${r}'`);let p=xy(l.shape,t,s,r,n),c=[p.dilationHeight,p.dilationWidth],d;n==="same"?d=SR([p.filterHeight,p.filterWidth],c):d=[[0,0],[0,0]];let h=c[0]===1&&c[1]===1,[f,m]=IR([p.inHeight,p.inWidth],c,d),g=h?n:"valid",x=h?l:B2(l,c,f),A=(a==="avg"?()=>b2(x,t,s,g,i):()=>O2(x,t,s,g,i))(),y=h?A:v2(A,c,m);return u?J(y,[y.shape[1],y.shape[2],y.shape[3]]):y}function IR(e,t,a){let n=a.map(p=>p[0]),r=a.map(p=>p[1]),s=e.concat(n,r),i=t.map((p,c)=>(p-s[c]%p)%p),o=r.map((p,c)=>p+i[c]),l=t.map((p,c)=>[n[c],o[c]]),u=t.map((p,c)=>[0,i[c]]);return[l,u]}function SR(e,t){let a=e.map((s,i)=>s+(s-1)*(t[i]-1)).map(s=>s-1),n=a.map(s=>Math.floor(s/2)),r=a.map((s,i)=>s-n[i]);return a.map((s,i)=>[n[i],r[i]])}var wb=D({pool_:kR});function TR(e,t){let a=R(e,"x","prelu"),n=R(t,"alpha","prelu"),r={x:a,alpha:n};return z.runKernel(Hi,r)}var W2=D({prelu_:TR});function CR(e,t=null,a=!1){let n=R(e,"x","prod");n.dtype==="bool"&&(n=He(n,"int32"));let r={x:n},s={axis:t,keepDims:a};return z.runKernel(ji,r,s)}var kb=D({prod_:CR});function NR(e,t,a,n){let r=e.map((p,c)=>R(p,`tensors${c}`,"raggedGather","int32")),s=R(t,"paramsDenseValues","raggedGather"),i=R(a,"indices","raggedGather","int32"),o={paramsNestedSplits:r,paramsDenseValues:s,indices:i},l={outputRaggedRank:n},u=z.runKernel(ih,o,l);return{outputNestedSplits:u.slice(0,u.length-1),outputDenseValues:u[u.length-1]}}var Ib=D({raggedGather_:NR});function ER(e,t,a){let n=R(e,"starts","raggedRange"),r=R(t,"limits","raggedRange",n.dtype),s=R(a,"deltas","raggedRange",n.dtype),i={starts:n,limits:r,deltas:s},o=z.runKernel(oh,i);return{rtNestedSplits:o[0],rtDenseValues:o[1]}}var Sb=D({raggedRange_:ER});function RR(e,t,a,n,r){let s=R(e,"shape","raggedTensorToTensor","int32"),i=R(t,"values","raggedTensorToTensor"),o=R(a,"defaultValue","raggedTensorToTensor",i.dtype),l=n.map((c,d)=>R(c,`tensors${d}`,"raggedTensorToTensor","int32")),u={shape:s,values:i,defaultValue:o,rowPartitionTensors:l},p={rowPartitionTypes:r};return z.runKernel(lh,u,p)}var Tb=D({raggedTensorToTensor_:RR});function MR(e,t,a){Ja(e);let n=At(e),r=null;if(a==null||a==="float32")r=new Float32Array(n);else if(a==="int32")r=new Int32Array(n);else if(a==="bool")r=new Uint8Array(n);else throw new Error(`Unknown data type ${a}`);for(let s=0;s=1||s===0);let i=Math.sqrt(-2*Math.log(s)/s);e=this.mean+this.stdDev*n*i,t=this.mean+this.stdDev*r*i,(!this.truncated||this.isValidTruncated(e))&&(a=!0)}return(!this.truncated||this.isValidTruncated(t))&&(this.nextVal=this.convertValue(t)),this.convertValue(e)}convertValue(e){return this.dtype==null||this.dtype==="float32"?e:Math.round(e)}isValidTruncated(e){return e<=this.upper&&e>=this.lower}},$R=class{constructor(e,t,a,n){this.alpha=e,this.beta=1/t,this.dtype=a;let r=n||Math.random();this.randu=V2.alea(r.toString()),this.randn=new U2(0,1,a,!1,this.randu()),e<1?this.d=e+2/3:this.d=e-1/3,this.c=1/Math.sqrt(9*this.d)}nextValue(){let e,t,a,n,r,s;for(;;){do n=this.randn.nextValue(),s=1+this.c*n;while(s<=0);if(s*=s*s,e=n*n,t=1-.331*e*e,a=.5*e+this.d*(1-s+Math.log(s)),r=this.randu(),rthis.dtype==null||this.dtype==="float32",this.min=e,this.range=t-e,this.dtype=a,n==null&&(n=Math.random()),typeof n=="number"&&(n=n.toString()),!this.canReturnFloat()&&this.range<=1)throw new Error(`The difference between ${e} - ${t} <= 1 and dtype is not float`);this.random=V2.alea(n)}convertValue(e){return this.canReturnFloat()?e:Math.round(e)}nextValue(){return this.convertValue(this.min+this.range*this.random())}};function PR(e,t,a=1,n="float32",r){if(Ja(e),a==null&&(a=1),n==null&&(n="float32"),n!=="float32"&&n!=="int32")throw new Error(`Unsupported data type ${n}`);let s=new $R(t,a,n,r),i=Me(e,n);for(let o=0;o`Error in reverse1D: x must be rank 1 but got rank ${t.rank}.`),Yr(t,0)}var Mb=D({reverse1d_:VR});function UR(e,t){let a=R(e,"x","reverse");return P(a.rank===2,()=>`Error in reverse2D: x must be rank 2 but got rank ${a.rank}.`),Yr(a,t)}var $b=D({reverse2d_:UR});function GR(e,t){let a=R(e,"x","reverse");return P(a.rank===3,()=>`Error in reverse3D: x must be rank 3 but got rank ${a.rank}.`),Yr(a,t)}var _b=D({reverse3d_:GR});function HR(e,t){let a=R(e,"x","reverse");return P(a.rank===4,()=>`Error in reverse4D: x must be rank 4 but got rank ${a.rank}.`),Yr(a,t)}var Pb=D({reverse4d_:HR});function jR(e){let t={x:R(e,"x","round")};return z.runKernel(Xl,t)}var q2=D({round_:jR});function qR(e){let t={x:R(e,"x","rsqrt","float32")};return z.runKernel(Qi,t)}var Fb=D({rsqrt_:qR});function XR(e){let t={x:R(e,"x","selu")};return z.runKernel(_d,t)}var Ob=D({selu_:XR});function KR(e,t,a,n,r,s=[1,1],i="NHWC"){let o=R(e,"x","separableConv2d"),l=R(t,"depthwiseFilter","separableConv2d"),u=R(a,"pointwiseFilter","separableConv2d"),p=o,c=!1;if(o.rank===3&&(c=!0,p=J(o,[1,o.shape[0],o.shape[1],o.shape[2]])),i==="NCHW")throw new Error("separableConv2d currently does not support dataFormat NCHW; only NHWC is supported");P(p.rank===4,()=>`Error in separableConv2d: input must be rank 4, but got rank ${p.rank}.`),P(l.rank===4,()=>`Error in separableConv2d: depthwise filter must be rank 4, but got rank ${l.rank}.`),P(u.rank===4,()=>`Error in separableConv2d: pointwise filter must be rank 4, but got rank ${l.rank}.`),P(u.shape[0]===1,()=>`Error in separableConv2d: the first dimension of pointwise filter must be 1, but got ${u.shape[0]}.`),P(u.shape[1]===1,()=>`Error in separableConv2d: the second dimension of pointwise filter must be 1, but got ${u.shape[1]}.`);let d=l.shape[2],h=l.shape[3];P(u.shape[2]===d*h,()=>`Error in separableConv2d: the third dimension of pointwise filter must be ${d*h}, but got ${u.shape[2]}.`);let f=hh(p,l,n,r,i,s),m=ep(f,u,1,"valid",i);return c?J(m,[m.shape[1],m.shape[2],m.shape[3]]):m}var Db=D({separableConv2d_:KR});async function ZR(e,t){let a=R(e,"x","setdiff1d"),n=R(t,"y","setdiff1d");P(a.dtype===n.dtype,()=>`x and y should have the same dtype, but got x (${a.dtype}) and y (${n.dtype}).`),P(a.rank===1,()=>`x should be 1D tensor, but got x (${a.shape}).`),P(n.rank===1,()=>`y should be 1D tensor, but got y (${n.shape}).`);let r=await a.data(),s=await n.data(),i=new Set(s),o=0;for(let p=0;p`slice1d expects a rank-1 tensor, but got a rank-${n.rank} tensor`),Pe(n,[t],[a])}var Vb=D({slice1d_:eM});function tM(e,t,a){let n=R(e,"x","slice2d");return P(n.rank===2,()=>`slice2d expects a rank-2 tensor, but got a rank-${n.rank} tensor`),Pe(n,t,a)}var Ub=D({slice2d_:tM});function aM(e,t,a){let n=R(e,"x","slice3d");return P(n.rank===3,()=>`slice3d expects a rank-3 tensor, but got a rank-${n.rank} tensor`),Pe(n,t,a)}var sp=D({slice3d_:aM});function nM(e,t,a){let n=R(e,"x","slice4d");return P(n.rank===4,()=>`slice4d expects a rank-4 tensor, but got a rank-${n.rank} tensor`),Pe(n,t,a)}var xh=D({slice4d_:nM});function rM(e,t=-1){let a=R(e,"logits","softmax","float32");if(t===-1&&(t=a.rank-1),t!==a.rank-1)throw Error(`Softmax along a non-last dimension is not yet supported. Logits was rank ${a.rank} and dim was ${t}`);let n={logits:a},r={dim:t};return z.runKernel(so,n,r)}var Ah=D({softmax_:rM});function sM(e){P(e.dtype==="complex64",()=>`The dtype for tf.spectral.fft() must be complex64 but got ${e.dtype}.`);let t={input:e};return z.runKernel(Nd,t)}var yh=D({fft_:sM});function iM(e){P(e.dtype==="complex64",()=>`The dtype for tf.spectral.ifft() must be complex64 but got ${e.dtype}.`);let t={input:e};return z.runKernel(Ed,t)}var hd=D({ifft_:iM});function oM(e){let t=e.shape[e.shape.length-1],a=e.size/t,n;if(t<=2){let r=J(e,[a,t]);n=hd(r)}else{let r=[a,2*(t-1)],s=J(dl(e),[a,t]),i=J(Zd(e),[a,t]),o=Yr(Pe(s,[0,1],[a,t-2]),1),l=ae(Yr(Pe(i,[0,1],[a,t-2]),1),Fe(-1)),u=at([s,o],1),p=at([i,l],1),c=J(br(u,p),[r[0],r[1]]);n=hd(c)}if(n=dl(n),e.rank===3&&e.shape[0]!==0){let r=n,s=e.shape[0];n=J(n,[s,n.shape[0]/s,n.shape[1]]),r.dispose()}return n}var X2=D({irfft_:oM});function lM(e,t,a=0){let n={x:R(e,"x","split")},r={numOrSizeSplits:t,axis:a};return z.runKernel(Ql,n,r)}var ka=D({split_:lM});function uM(e,t){P(e.dtype==="float32",()=>`The dtype for rfft() must be real value but got ${e.dtype}`);let a=e.shape[e.shape.length-1],n=e.size/a,r;if(t!=null&&t0),m=e.shape.map(g=>g);m[e.shape.length-1]=t,r=Pe(e,f,m),a=t}else if(t!=null&&t>a){let f=e.shape.map(m=>m);f[e.shape.length-1]=t-a,r=at([e,fn(f)],e.shape.length-1),a=t}else r=e;let s=Ka(r),i=J(br(r,s),[n,a]),o=yh(i),l=Math.floor(a/2)+1,u=dl(o),p=Zd(o),c=ka(u,[l,a-l],u.shape.length-1),d=ka(p,[l,a-l],p.shape.length-1),h=r.shape.slice();return h[r.shape.length-1]=l,J(br(c[0],d[0]),h)}var bh=D({rfft_:uM});function dM(e,t){let a=R(e,"a","squaredDifference"),n=R(t,"b","squaredDifference");[a,n]=St(a,n),zt(a.shape,n.shape);let r={a,b:n},s={};return z.runKernel(io,r,s)}var K2=D({squaredDifference_:dM});function pM(e,t){let a=R(e,"x","squeeze","string_or_numeric");return J(a,iA(a.shape,t).newShape)}var _e=D({squeeze_:pM});function cM(e,t=0){let a=ud(e,"tensors","stack","string_or_numeric");P(a.length>=1,()=>"Pass at least one tensor to tf.stack"),a.length>0&&P(t<=a[0].rank,()=>"Axis must be <= rank of the tensor");let n=a,r={axis:t};return z.runKernel(Hl,n,r)}var sa=D({stack_:cM});function hM(e,t=0){let a={x:R(e,"x","step")},n={alpha:t};return z.runKernel(fo,a,n)}var Z2=D({step_:hM});function fM(e,t,a,n,r=0,s=0,i=0,o=0,l=0){let u={x:R(e,"x","stridedSlice","string_or_numeric")},p={begin:t,end:a,strides:n,beginMask:r,endMask:s,ellipsisMask:i,newAxisMask:o,shrinkAxisMask:l};return z.runKernel(oo,u,p)}var Gb=D({stridedSlice_:fM});function mM(e){let t={x:R(e,"x","tan","float32")};return z.runKernel(uo,t)}var Hb=D({tan_:mM});function Ht(e,t){Xs(e);let a=Yn(e,t);if(a.length!==1)throw new Error("tensor1d() requires values to be a flat/TypedArray");return rs(e,null,a,t)}function Kn(e,t,a){if(Xs(e),t!=null&&t.length!==2)throw new Error("tensor2d() requires shape to have two numbers");let n=Yn(e,a);if(n.length!==2&&n.length!==1)throw new Error("tensor2d() requires values to be number[][] or flat/TypedArray");if(n.length===1&&t==null)throw new Error("tensor2d() requires shape to be provided when `values` are a flat/TypedArray");return rs(e,t,n,a)}function jb(e,t,a){if(Xs(e),t!=null&&t.length!==4)throw new Error("tensor4d() requires shape to have four numbers");let n=Yn(e,a);if(n.length!==4&&n.length!==1)throw new Error("tensor4d() requires values to be number[][][][] or flat/TypedArray");if(n.length===1&&t==null)throw new Error("tensor4d() requires shape to be provided when `values` are a flat array");return rs(e,t,n,a)}function qb(e,t,a){if(Xs(e),t!=null&&t.length!==5)throw new Error("tensor5d() requires shape to have five numbers");let n=Yn(e,a);if(n.length!==5&&n.length!==1)throw new Error("tensor5d() requires values to be number[][][][][] or flat/TypedArray");if(n.length===1&&t==null)throw new Error("tensor5d() requires shape to be provided when `values` are a flat array");return rs(e,t,n,a)}function Xb(e,t,a){if(Xs(e),t!=null&&t.length!==6)throw new Error("tensor6d() requires shape to have six numbers");let n=Yn(e,a);if(n.length!==6&&n.length!==1)throw new Error("tensor6d() requires values to be number[][][][][][] or flat/TypedArray");if(n.length===1&&t==null)throw new Error("tensor6d() requires shape to be provided when `values` are a flat array");return t=t||n,rs(e,t,n,a)}function gM(e,t=1,a=!0){let n=R(e,"x","topk");if(n.rank===0)throw new Error("topk() expects the input to be of rank 1 or higher");let r=n.shape[n.shape.length-1];if(t<0)throw new Error(`'k' passed to topk() must be >= 0 but got ${t}`);if(t>r)throw new Error(`'k' passed to topk() must be <= the last dimension (${r}) but got ${t}`);let s={x:n},i={k:t,sorted:a},[o,l]=z.runKernel(co,s,i);return{values:o,indices:l}}var Kb=D({topk_:gM});function xM(e,t=0,a=1,n,r){if(Ja(e),n!=null&&n==="bool")throw new Error("Unsupported data type $ { dtype }");let s=new U2(t,a,n,!0,r),i=Me(e,n);for(let o=0;o0,()=>"The input tensor must be at least 1D");let n={x:a},r={axis:t},[s,i]=z.runKernel(uh,n,r);return{values:s,indices:i}}var Yb=D({unique_:AM});function yM(e,t,a){let n=R(e,"x","unsortedSegmentSum"),r=R(t,"segmentIds","unsortedSegmentSum","int32");P(ol(a),()=>"numSegments must be of dtype int");let s={x:n,segmentIds:r},i={numSegments:a};return z.runKernel(dh,s,i)}var Jb=D({unsortedSegmentSum_:yM});function bM(e,t=0){let a=R(e,"x","unstack","string_or_numeric");P(t>=-a.shape.length&&t`Axis = ${t} is not in [-${a.shape.length}, ${a.shape.length})`);let n={value:a},r={axis:t};return z.runKernel(au,n,r)}var Ta=D({unstack_:bM});function Qb(e,t){return gh(e,t,"right")}function e4(e,t=!0,a,n){return z.makeVariable(e,t,a,n)}function t4(e,t){let a=[];for(let s=0;s0,()=>"mask cannot be scalar"),Sa(o.slice(s,s+i),r.shape,"mask's shape must match the first K dimensions of tensor's shape,");let l=1;for(let m=s;m"Shape mismatch in v and x");let l=Fe(1),u=fe(l,o),p=ae(fe(i,s),u);if(r){P(n!=null,()=>"When using zeroDebias: true, step is required.");let c=R(n,"step","movingAverage");p=me(p,fe(l,pl(o,c)))}return be(s,p)}var n4=D({movingAverage_:kM});function IM(e,t,a){Ja(a);let n=R(e,"indices","scatterND","int32"),r=R(t,"updates","scatterND");m2(r,n,a);let s={indices:n,updates:r},i={shape:a};return z.runKernel(eo,s,i)}var r4=D({scatterND_:IM});function SM(e,t,a,n){if(e.dtype!=="int32")throw new Error(`tf.sparseToDense() expects the indices to be int32 type, but the dtype was ${e.dtype}.`);if(e.rank>2)throw new Error(`sparseIndices should be a scalar, vector, or matrix, but got shape ${e.shape}.`);let r=e.rank>0?e.shape[0]:1,s=e.rank>1?e.shape[1]:1;if(a.length!==s)throw new Error(`outputShape has incorrect number of elements:, ${a.length}, should be: ${s}.`);let i=t.size;if(!(t.rank===0||t.rank===1&&i===r))throw new Error(`sparseValues has incorrect shape ${t.shape}, should be [] or [${r}]`);if(t.dtype!==n.dtype)throw new Error("sparseValues.dtype must match defaultValues.dtype")}function TM(e,t,a,n=0){Ja(a);let r=R(e,"sparseIndices","sparseToDense","int32"),s=R(t,"sparseValues","sparseToDense","string_or_numeric"),i=R(n,"defaultValue","sparseToDense",s.dtype);SM(r,s,a,i);let o={sparseIndices:r,sparseValues:s,defaultValue:i},l={outputShape:a};return z.runKernel(Ld,o,l)}var s4=D({sparseToDense_:TM});function CM(e,t){let a=R(t,"indices","gatherND","int32"),n={params:R(e,"x","gatherND","string_or_numeric"),indices:a};return z.runKernel(bi,n)}var i4=D({gatherND_:CM});function NM(e,t){if(t==null)return e.shape.slice();if(es(e.shape,t))return t;if(e.shape.length===t.length){let a=[];for(let n=0;n`x has to be a floating point tensor since it's going to be scaled, but got a ${r.dtype} tensor instead.`),P(t>=0&&t<1,()=>`rate must be a float in the range [0, 1), but got ${t}.`),t===0)return e instanceof pt?r.clone():r;let s=NM(r,a),i=1-t,o=me(C2(be(H2(s,0,1,"float32",n),i)),i);return ae(r,o)}var o4=D({dropout_:EM});function J2(e){return Math.floor(Math.pow(2,Math.ceil(Math.log(e)/Math.log(2))))}function vh(e,t,a){let n=1-e%2,r=new Float32Array(e);for(let s=0;s1,()=>`inTopK() expects the predictions to be of rank 2 or higher, but got ${n.rank}`),P(n.rank-1===r.rank,()=>`predictions rank should be 1 larger than targets rank, but got predictions rank ${n.rank} and targets rank ${r.rank}`),Sa(n.shape.slice(0,n.shape.length-1),r.shape,"predictions's shape should be align with the targets' shape, except the last dimension.");let s=n.shape[n.shape.length-1];P(a>0&&a<=s,()=>`'k' passed to inTopK() must be > 0 && <= the predictions last dimension (${s}), but got ${a}`);let i=await n.data(),o=await r.data(),[l,u]=[i.length/s,s],p=oA("bool",l);for(let c=0;cg.value-m.value),p[c]=0;for(let m=0;mPM,depthwiseConv2d:()=>BM,matMul:()=>VM});function MM(e,t,a,n,r,s="NHWC",i){let o=e;e.rank===3&&(o=J(e,[1,e.shape[0],e.shape[1],e.shape[2]]));let l=t;l.rank===3&&(l=J(t,[1,t.shape[0],t.shape[1],t.shape[2]])),P(o.rank===4,()=>`Error in conv2dDerFilter: input must be rank 4, but got shape ${o.shape}.`),P(l.rank===4,()=>`Error in conv2dDerFilter: dy must be rank 4, but got shape ${l.shape}.`),P(a.length===4,()=>`Error in conv2dDerFilter: filterShape must be length 4, but got ${a}.`);let u=s==="NHWC"?o.shape[3]:o.shape[1],p=s==="NHWC"?l.shape[3]:l.shape[1];P(u===a[2],()=>`Error in conv2dDerFilter: depth of input ${u}) must match input depth in filter (${a[2]}.`),P(p===a[3],()=>`Error in conv2dDerFilter: depth of dy (${p}) must match output depth for filter (${a[3]}).`),Sn("conv2dDerFilter",r,i);let c={x:o,dy:l},d={strides:n,pad:r,dataFormat:s,dimRoundingMode:i,filterShape:a};return z.runKernel(Xc,c,d)}var $M=D({conv2DBackpropFilter_:MM});function wh(e,t,a){if(a==null||a==="linear")return e;if(a==="relu")return ae(e,Z2(t));throw new Error(`Cannot compute gradient for fused activation ${a}.`)}function kh(e,t){let a=t,n=d2(e.shape,t.shape);return n.length>0&&(a=tt(a,n)),J(a,e.shape)}function Ih(e,t,a,n){if(t==="linear")return e;if(t==="relu")return rp(e);if(t==="elu")return I2(e);if(t==="relu6")return j2(e);if(t==="prelu")return W2(e,a);if(t==="leakyrelu")return R2(e,n);if(t==="sigmoid")return Da(e);throw new Error(`Unknown fused activation ${t}.`)}var Sh=(e,t)=>!(e>0)||t==="linear";function _M({x:e,filter:t,strides:a,pad:n,dataFormat:r="NHWC",dilations:s=[1,1],dimRoundingMode:i,bias:o,activation:l="linear",preluActivationWeights:u,leakyreluAlpha:p}){if(l=l||"linear",Sh(z.state.gradientDepth,l)===!1){P(r==="NHWC",()=>`Error in fused conv2d: got dataFormat of ${r} but only NHWC is currently supported for the case of gradient depth is 0 and the activation is not linear.`);let S=ep(e,t,a,n,r,s,i);return o!=null&&(S=be(S,o)),Ih(S,l,u,p)}let c=R(e,"x","conv2d","float32"),d=R(t,"filter","conv2d","float32"),h=c,f=!1;c.rank===3&&(f=!0,h=J(c,[1,c.shape[0],c.shape[1],c.shape[2]])),P(h.rank===4,()=>`Error in fused conv2d: input must be rank 4, but got rank ${h.rank}.`),P(d.rank===4,()=>`Error in fused conv2d: filter must be rank 4, but got rank ${d.rank}.`),Sn("fused conv2d",n,i);let m=r==="NHWC"?h.shape[3]:h.shape[1];P(d.shape[2]===m,()=>`Error in conv2d: depth of input (${m}) must match input depth for filter ${d.shape[2]}.`),P(kr(a,s),()=>`Error in conv2D: Either strides or dilations must be 1. Got strides ${a} and dilations '${s}'`);let g=Jd(h.shape,d.shape,a,s,n,i),x;o!=null&&(x=R(o,"bias","fused conv2d"),[x]=St(x,c),r==="NHWC"?zt(g.outShape,x.shape):(P(x.shape.length<=1,()=>`Error in fused conv2d: only supports scalar or 1-D Tensor bias for NCHW format but got the bias of rank-${x.shape.length}.`),P(x.shape.length===0||x.shape[0]===g.outChannels||x.shape[0]===1,()=>`Error in fused conv2d: bias shape (${x.shape}) is not compatible with the number of output channels (${g.outChannels})`)));let A;if(u!=null){let S=u.shape;if(P(S.length<=1||S.length===3,()=>`Error in fused conv2d: only supports scalar, 1-D Tensor or 3-D Tensor PReLU activation weights but got a tensor of rank-${S.length}.`),S.length===1)P(S[0]===1||S[0]===g.outChannels,()=>`Error in fused conv2d: PReLU activation weights (${S}) is not compatible with the number of output channels (${g.outChannels}).`);else if(S.length===3)try{zt(S,g.outShape)}catch(C){let E=`Error in fused conv2d: PReLU activation weights (${S}) is not compatible with the output shape of the conv2d (${g.outShape}).`;throw Error(E)}A=R(u,"prelu weights","fused conv2d")}let y=(S,C)=>{P(r==="NHWC",()=>`Error in gradient of fused conv2D: got dataFormat of ${r} but only NHWC is currently supported.`);let[E,_,$,M]=C,I=wh(S,$,l);P(dd(s),()=>`Error in gradient of fused conv2D: dilation rates greater than 1 are not yet supported in gradients. Got dilations '${s}'`);let N=$y(_.shape,I,E,a,n),O=$M(_,I,E.shape,a,n),L=[N,O];if(M!=null){let B=kh(M,I);L.push(B)}return L},b={x:h,filter:d,bias:x,preluActivationWeights:A},w={strides:a,pad:n,dataFormat:r,dilations:s,dimRoundingMode:i,activation:l,leakyreluAlpha:p};return o==null?Qn((S,C,E)=>{let _=z.runKernel(qr,b,w);return E([C,S,_]),f&&(_=J(_,[_.shape[1],_.shape[2],_.shape[3]])),{value:_,gradFunc:y}})(h,d):Qn((S,C,E,_)=>{let $=z.runKernel(qr,b,w);return _([C,S,$,E]),f&&($=J($,[$.shape[1],$.shape[2],$.shape[3]])),{value:$,gradFunc:y}})(h,d,x)}var PM=D({fusedConv2d_:_M});function FM(e,t,a,n,r,s=[1,1],i){let o=e;e.rank===3&&(o=J(e,[1,e.shape[0],e.shape[1],e.shape[2]]));let l=t;l.rank===3&&(l=J(t,[1,t.shape[0],t.shape[1],t.shape[2]]));let u={x:o,dy:l},p={strides:n,pad:r,dimRoundingMode:i,dilations:s,filterShape:a};return z.runKernel(Yc,u,p)}var OM=D({depthwiseConv2dNativeBackpropFilter_:FM});function DM(e,t,a,n,r,s=[1,1],i){let o=t,l=!1;t.rank===3&&(l=!0,o=J(t,[1,t.shape[0],t.shape[1],t.shape[2]]));let u={dy:o,filter:a},p={strides:n,pad:r,dimRoundingMode:i,dilations:s,inputShape:e},c=z.runKernel(Jc,u,p);return l?J(c,[c.shape[1],c.shape[2],c.shape[3]]):c}var zM=D({depthwiseConv2dNativeBackpropInput_:DM});function LM({x:e,filter:t,strides:a,pad:n,dataFormat:r="NHWC",dilations:s=[1,1],dimRoundingMode:i,bias:o,activation:l="linear",preluActivationWeights:u,leakyreluAlpha:p}){if(Sh(z.state.gradientDepth,l)===!1){let w=hh(e,t,a,n,r,s,i);return o!=null&&(w=be(w,o)),Ih(w,l,u,p)}let c=R(e,"x","depthwiseConv2d","float32"),d=R(t,"filter","depthwiseConv2d","float32"),h=c,f=!1;c.rank===3&&(f=!0,h=J(c,[1,c.shape[0],c.shape[1],c.shape[2]])),P(h.rank===4,()=>`Error in fused depthwiseConv2d: input must be rank 4, but got rank ${h.rank}.`),P(d.rank===4,()=>`Error in fused depthwiseConv2d: filter must be rank 4, but got rank ${d.rank}.`),P(h.shape[3]===d.shape[2],()=>`Error in fused depthwiseConv2d: number of input channels (${h.shape[3]}) must match the inChannels dimension in filter ${d.shape[2]}.`),s==null&&(s=[1,1]),P(kr(a,s),()=>`Error in fused depthwiseConv2d: Either strides or dilations must be 1. Got strides ${a} and dilations '${s}'`),Sn("fused depthwiseConv2d",n,i);let m=Jd(h.shape,d.shape,a,s,n,i,!0),g;o!=null&&(g=R(o,"bias","fused conv2d"),[g]=St(g,c),zt(m.outShape,g.shape));let x;u!=null&&(x=R(u,"prelu weights","fused depthwiseConv2d"));let A=(w,S)=>{P(dd(s),()=>`Error in gradient of fused depthwiseConv2d: dilation rates greater than 1 are not yet supported. Got dilations '${s}'`);let[C,E,_,$]=S,M=wh(w,_,l),I=zM(E.shape,M,C,a,n,s,i),N=OM(E,M,C.shape,a,n,s,i);if($!=null){let O=kh(g,M);return[I,N,O]}return[I,N]},y={x:h,filter:d,bias:g,preluActivationWeights:x},b={strides:a,pad:n,dataFormat:r,dilations:s,dimRoundingMode:i,activation:l,leakyreluAlpha:p};return o==null?Qn((w,S,C)=>{let E=z.runKernel(Xr,y,b);return C([S,w,E]),f&&(E=J(E,[E.shape[1],E.shape[2],E.shape[3]])),{value:E,gradFunc:A}})(h,d):Qn((w,S,C,E)=>{let _=z.runKernel(Xr,y,b);return E([S,w,_,C]),f&&(_=J(_,[_.shape[1],_.shape[2],_.shape[3]])),{value:_,gradFunc:A}})(h,d,g)}var BM=D({fusedDepthwiseConv2d_:LM});function WM({a:e,b:t,transposeA:a=!1,transposeB:n=!1,bias:r,activation:s="linear",preluActivationWeights:i,leakyreluAlpha:o=.2}){if(Sh(z.state.gradientDepth,s)===!1){let $=st(e,t,a,n);return r!=null&&($=be($,r)),Ih($,s,i,o)}let l=R(e,"a","fused matMul"),u=R(t,"b","fused matMul");[l,u]=St(l,u);let p=a?l.shape[l.rank-2]:l.shape[l.rank-1],c=n?u.shape[u.rank-1]:u.shape[u.rank-2],d=a?l.shape[l.rank-1]:l.shape[l.rank-2],h=n?u.shape[u.rank-2]:u.shape[u.rank-1],f=l.shape.slice(0,-2),m=u.shape.slice(0,-2),g=At(f),x=At(m);P(p===c,()=>`Error in fused matMul: inner shapes (${p}) and (${c}) of Tensors with shapes ${l.shape} and ${u.shape} and transposeA=${a} and transposeB=${n} must match.`);let A=zt(l.shape.slice(0,-2),u.shape.slice(0,-2)).concat([d,h]),y=a?J(l,[g,p,d]):J(l,[g,d,p]),b=n?J(u,[x,h,c]):J(u,[x,c,h]),w;r!=null&&(w=R(r,"bias","fused matMul"),[w]=St(w,l),zt(A,w.shape));let S;i!=null&&(S=R(i,"prelu weights","fused matMul"));let C=($,M)=>{let[I,N,O,L]=M,B=wh(J($,O.shape),O,s),G,j;if(!a&&!n?(G=st(B,N,!1,!0),j=st(I,B,!0,!1)):!a&&n?(G=st(B,N,!1,!1),j=st(B,I,!0,!1)):a&&!n?(G=st(N,B,!1,!0),j=st(I,B,!1,!1)):(G=st(N,B,!0,!0),j=st(B,I,!0,!0)),r!=null){let U=kh(L,B);return[G,j,U]}else return[G,j]},E={a:y,b,bias:w,preluActivationWeights:S},_={transposeA:a,transposeB:n,activation:s,leakyreluAlpha:o};return r==null?Qn(($,M,I)=>{let N=z.runKernel(jr,E,_);return I([$,M,N]),{value:J(N,A),gradFunc:C}})(y,b):Qn(($,M,I,N)=>{let O=z.runKernel(jr,E,_);return N([$,M,O,I]),{value:J(O,A),gradFunc:C}})(y,b,w)}var VM=D({fusedMatMul_:WM});function UM(e){return vh(e,.54,.46)}var GM=D({hammingWindow_:UM});function HM(e){return vh(e,.5,.5)}var u4=D({hannWindow_:HM});function jM(e,t,a,n=!1,r=0){let s=0,i=[];for(;s+t<=e.size;)i.push(Pe(e,s,t)),s+=a;if(n)for(;s`Error in cropAndResize: image must be rank 4,but got rank ${i.rank}.`),P(o.rank===2&&o.shape[1]===4,()=>`Error in cropAndResize: boxes must be have size [${u},4] but had shape ${o.shape}.`),P(l.rank===1&&l.shape[0]===u,()=>`Error in cropAndResize: boxInd must be have size [${u}] but had shape ${o.shape}.`),P(n.length===2,()=>`Error in cropAndResize: cropSize must be of length 2, but got length ${n.length}.`),P(n[0]>=1&&n[1]>=1,()=>`cropSize must be atleast [1,1], but was ${n}`),P(r==="bilinear"||r==="nearest",()=>`method must be bilinear or nearest, but was ${r}`);let p={image:i,boxes:o,boxInd:l},c={method:r,extrapolationValue:s,cropSize:n};return z.runKernel(ui,p,c)}var ZM=D({cropAndResize_:KM});function YM(e){let t=R(e,"image","flipLeftRight","float32");P(t.rank===4,()=>`Error in flipLeftRight: image must be rank 4,but got rank ${t.rank}.`);let a={image:t};return z.runKernel(gi,a,{})}var JM=D({flipLeftRight_:YM});function QM(e){let t=R(e,"image","grayscaleToRGB"),a=t.rank-1,n=t.shape[a];P(t.rank>=2,()=>`Error in grayscaleToRGB: images must be at least rank 2, but got rank ${t.rank}.`),P(n===1,()=>`Error in grayscaleToRGB: last dimension of a grayscale image should be size 1, but got size ${n}.`);let r=new Array(t.rank);return r.fill(1,0,a),r[a]=3,Gr(t,r)}var e$=D({grayscaleToRGB_:QM});function t$(e,t,a=0,n=.5){let r=R(e,"image","rotateWithOffset","float32");P(r.rank===4,()=>`Error in rotateWithOffset: image must be rank 4,but got rank ${r.rank}.`);let s={image:r},i={radians:t,fillValue:a,center:n};return z.runKernel(mo,s,i)}var a$=D({rotateWithOffset_:t$});function iu(e,t,a,n,r,s){n==null&&(n=.5),r==null&&(r=Number.NEGATIVE_INFINITY),s==null&&(s=0);let i=e.shape[0];return a=Math.min(a,i),P(0<=n&&n<=1,()=>`iouThreshold must be in [0, 1], but was '${n}'`),P(e.rank===2,()=>`boxes must be a 2D tensor, but was of rank '${e.rank}'`),P(e.shape[1]===4,()=>`boxes must have 4 columns, but 2nd dimension was ${e.shape[1]}`),P(t.rank===1,()=>"scores must be a 1D tensor"),P(t.shape[0]===i,()=>`scores has incompatible shape with boxes. Expected ${i}, but was ${t.shape[0]}`),P(0<=s&&s<=1,()=>`softNmsSigma must be in [0, 1], but was '${s}'`),{maxOutputSize:a,iouThreshold:n,scoreThreshold:r,softNmsSigma:s}}function n$(e,t,a,n=.5,r=Number.NEGATIVE_INFINITY){let s=R(e,"boxes","nonMaxSuppression","float32"),i=R(t,"scores","nonMaxSuppression","float32"),o=iu(s,i,a,n,r);a=o.maxOutputSize,n=o.iouThreshold,r=o.scoreThreshold;let l={maxOutputSize:a,iouThreshold:n,scoreThreshold:r};return z.runKernel(Bi,{boxes:s,scores:i},l)}var r$=D({nonMaxSuppression_:n$});function s$(e,t,a){let n=i$(e,t,a),r=n<0?-(n+1):n;e.splice(r,0,t)}function i$(e,t,a){return l$(e,t,a||o$)}function o$(e,t){return e>t?1:e>>1);let o=a(t,e[s]);o>0?n=s+1:(r=s,i=!o)}return i?n:-n-1}function p4(e,t,a,n,r){return e3(e,t,a,n,r,0)}function c4(e,t,a,n,r,s){return e3(e,t,a,n,r,0,!1,s,!0)}function h4(e,t,a,n,r,s){return e3(e,t,a,n,r,s,!0)}function e3(e,t,a,n,r,s,i=!1,o=!1,l=!1){let u=[];for(let g=0;gr&&u.push({score:t[g],boxIndex:g,suppressBeginIndex:0});u.sort(X5);let p=s>0?-.5/s:0,c=[],d=[];for(;c.length0;){let g=u.pop(),{score:x,boxIndex:A,suppressBeginIndex:y}=g;if(x=y;--w){let S=u$(e,A,c[w]);if(S>=n){b=!0;break}if(g.score=g.score*d$(n,p,S),g.score<=r)break}g.suppressBeginIndex=c.length,b||(g.score===x?(c.push(A),d.push(g.score)):g.score>r&&s$(u,g,X5))}let h=c.length,f=a-h;o&&f>0&&(c.push(...new Array(f).fill(0)),d.push(...new Array(f).fill(0)));let m={selectedIndices:c};return i&&(m.selectedScores=d),l&&(m.validOutputs=h),m}function u$(e,t,a){let n=e.subarray(t*4,t*4+4),r=e.subarray(a*4,a*4+4),s=Math.min(n[0],n[2]),i=Math.min(n[1],n[3]),o=Math.max(n[0],n[2]),l=Math.max(n[1],n[3]),u=Math.min(r[0],r[2]),p=Math.min(r[1],r[3]),c=Math.max(r[0],r[2]),d=Math.max(r[1],r[3]),h=(o-s)*(l-i),f=(c-u)*(d-p);if(h<=0||f<=0)return 0;let m=Math.max(s,u),g=Math.max(i,p),x=Math.min(o,c),A=Math.min(l,d),y=Math.max(x-m,0)*Math.max(A-g,0);return y/(h+f-y)}function d$(e,t,a){let n=Math.exp(t*a*a);return a<=e?n:0}function X5(e,t){return e.score-t.score||e.score===t.score&&t.boxIndex-e.boxIndex}async function p$(e,t,a,n=.5,r=Number.NEGATIVE_INFINITY){let s=R(e,"boxes","nonMaxSuppressionAsync"),i=R(t,"scores","nonMaxSuppressionAsync"),o=iu(s,i,a,n,r);a=o.maxOutputSize,n=o.iouThreshold,r=o.scoreThreshold;let l=await Promise.all([s.data(),i.data()]),u=l[0],p=l[1],{selectedIndices:c}=p4(u,p,a,n,r);return s!==e&&s.dispose(),i!==t&&i.dispose(),Ht(c,"int32")}var c$=p$;function h$(e,t,a,n=.5,r=Number.NEGATIVE_INFINITY,s=0){let i=R(e,"boxes","nonMaxSuppression"),o=R(t,"scores","nonMaxSuppression"),l=iu(i,o,a,n,r,s);a=l.maxOutputSize,n=l.iouThreshold,r=l.scoreThreshold,s=l.softNmsSigma;let u={boxes:i,scores:o},p={maxOutputSize:a,iouThreshold:n,scoreThreshold:r,softNmsSigma:s},c=z.runKernel(Wi,u,p);return{selectedIndices:c[0],selectedScores:c[1]}}var f$=D({nonMaxSuppressionWithScore_:h$});async function m$(e,t,a,n=.5,r=Number.NEGATIVE_INFINITY,s=0){let i=R(e,"boxes","nonMaxSuppressionAsync"),o=R(t,"scores","nonMaxSuppressionAsync"),l=iu(i,o,a,n,r,s);a=l.maxOutputSize,n=l.iouThreshold,r=l.scoreThreshold,s=l.softNmsSigma;let u=await Promise.all([i.data(),o.data()]),p=u[0],c=u[1],{selectedIndices:d,selectedScores:h}=h4(p,c,a,n,r,s);return i!==e&&i.dispose(),o!==t&&o.dispose(),{selectedIndices:Ht(d,"int32"),selectedScores:Ht(h)}}var g$=m$;function x$(e,t,a,n=.5,r=Number.NEGATIVE_INFINITY,s=!1){let i=R(e,"boxes","nonMaxSuppression"),o=R(t,"scores","nonMaxSuppression"),l=iu(i,o,a,n,r,null),u=l.maxOutputSize,p=l.iouThreshold,c=l.scoreThreshold,d={boxes:i,scores:o},h={maxOutputSize:u,iouThreshold:p,scoreThreshold:c,padToMaxOutputSize:s},f=z.runKernel(Ul,d,h);return{selectedIndices:f[0],validOutputs:f[1]}}var A$=D({nonMaxSuppressionPadded_:x$});async function y$(e,t,a,n=.5,r=Number.NEGATIVE_INFINITY,s=!1){let i=R(e,"boxes","nonMaxSuppressionAsync"),o=R(t,"scores","nonMaxSuppressionAsync"),l=iu(i,o,a,n,r,null),u=l.maxOutputSize,p=l.iouThreshold,c=l.scoreThreshold,[d,h]=await Promise.all([i.data(),o.data()]),{selectedIndices:f,validOutputs:m}=c4(d,h,u,p,c,s);return i!==e&&i.dispose(),o!==t&&o.dispose(),{selectedIndices:Ht(f,"int32"),validOutputs:Fe(m,"int32")}}var b$=y$;function v$(e,t,a=!1,n=!1){let r=R(e,"images","resizeBilinear");P(r.rank===3||r.rank===4,()=>`Error in resizeBilinear: x must be rank 3 or 4, but got rank ${r.rank}.`),P(t.length===2,()=>`Error in resizeBilinear: new shape must 2D, but got shape ${t}.`),P(n===!1||a===!1,()=>"Error in resizeBilinear: If halfPixelCenters is true, alignCorners must be false.");let s=r,i=!1;r.rank===3&&(i=!0,s=J(r,[1,r.shape[0],r.shape[1],r.shape[2]]));let[]=t,o={images:s},l={alignCorners:a,halfPixelCenters:n,size:t},u=z.runKernel(Zi,o,l);return i?J(u,[u.shape[1],u.shape[2],u.shape[3]]):u}var w$=D({resizeBilinear_:v$});function k$(e,t,a=!1,n=!1){let r=R(e,"images","resizeNearestNeighbor");P(r.rank===3||r.rank===4,()=>`Error in resizeNearestNeighbor: x must be rank 3 or 4, but got rank ${r.rank}.`),P(t.length===2,()=>`Error in resizeNearestNeighbor: new shape must 2D, but got shape ${t}.`),P(r.dtype==="float32"||r.dtype==="int32",()=>"`images` must have `int32` or `float32` as dtype"),P(n===!1||a===!1,()=>"Error in resizeNearestNeighbor: If halfPixelCenters is true, alignCorners must be false.");let s=r,i=!1;r.rank===3&&(i=!0,s=J(r,[1,r.shape[0],r.shape[1],r.shape[2]]));let[]=t,o={images:s},l={alignCorners:a,halfPixelCenters:n,size:t},u=z.runKernel(Ki,o,l);return i?J(u,[u.shape[1],u.shape[2],u.shape[3]]):u}var I$=D({resizeNearestNeighbor_:k$});function S$(e,t="binary",a=!1,n=.5){let r=R(e,"image","threshold"),s=.2989,i=.587,o=.114,l=r.shape[0]*r.shape[1],u=ae(Ht([n]),255),p,c,d,h;if(P(r.rank===3,()=>`Error in threshold: image must be rank 3,but got rank ${r.rank}.`),P(r.shape[2]===3||r.shape[2]===1,()=>`Error in threshold: image color channel must be equal to 3 or 1but got ${r.shape[2]}.`),P(r.dtype==="int32"||r.dtype==="float32",()=>`Error in dtype: image dtype must be int32 or float32,but got dtype ${r.dtype}.`),P(t==="otsu"||t==="binary",()=>`Method must be binary or otsu, but was ${t}`),r.shape[2]===3){[p,c,d]=ka(r,[1,1,1],-1);let m=ae(p,s),g=ae(c,i),x=ae(d,o);h=be(be(m,g),x)}else h=e;if(t==="otsu"){let m=w2(He(q2(h),"int32"),Be([]),256);u=T$(m,l)}let f=a?fh(h,u):np(h,u);return He(ae(f,255),"int32")}function T$(e,t){let a=Ht([-1]),n=Ht([0]),r=Ht([0]),s,i,o,l,u,p;for(let c=0;c`Error in transform: image must be rank 4,but got rank ${i.rank}.`),P(o.rank===2&&(o.shape[0]===i.shape[0]||o.shape[0]===1)&&o.shape[1]===8,()=>"Error in transform: Input transform should be batch x 8 or 1 x 8"),P(s==null||s.length===2,()=>`Error in transform: outputShape must be [height, width] or null, but got ${s}.`);let l={image:i,transforms:o},u={interpolation:a,fillMode:n,fillValue:r,outputShape:s};return z.runKernel(ho,l,u)}var E$=D({transform_:N$});function R$(e,t,a){P(t%1===0,()=>`bandPart(): numLower must be an integer, got ${t}.`),P(a%1===0,()=>`bandPart(): numUpper must be an integer, got ${a}.`);let n=R(e,"a","bandPart");P(n.rank>=2,()=>`bandPart(): Rank must be at least 2, got ${n.rank}.`);let r=n.shape,[s,i]=n.shape.slice(-2);if(!(t<=s))throw new Error(`bandPart(): numLower (${t}) must not be greater than the number of rows (${s}).`);if(!(a<=i))throw new Error(`bandPart(): numUpper (${a}) must not be greater than the number of columns (${i}).`);t<0&&(t=s),a<0&&(a=i);let o=J(hl(0,s,1,"int32"),[-1,1]),l=hl(0,i,1,"int32"),u=fe(o,l),p=pd(fh(u,Fe(+t,"int32")),E2(u,Fe(-a,"int32"))),c=fn([s,i],n.dtype);return J(sa(Ta(J(n,[-1,s,i])).map(d=>Vs(p,d,c))),r)}var M$=D({bandPart_:R$});function $$(e){let t;if(Array.isArray(e)){t=!1,P(e!=null&&e.length>0,()=>"Gram-Schmidt process: input must not be null, undefined, or empty");let r=e[0].shape[0];for(let s=1;s`Gram-Schmidt: Non-unique lengths found in the input vectors: (${e[s].shape[0]} vs. ${r})`)}else t=!0,e=ka(e,e.shape[0],0).map(r=>_e(r,[0]));P(e.length<=e[0].shape[0],()=>`Gram-Schmidt: Number of vectors (${e.length}) exceeds number of dimensions (${e[0].shape[0]}).`);let a=[],n=e;for(let r=0;r{let s=n[r];if(r>0)for(let i=0;i=2,()=>`qr() requires input tensor to have a rank >= 2, but got rank ${e.rank}`),e.rank===2)return K5(e,t);{let a=e.shape.slice(0,e.shape.length-2).reduce((l,u)=>l*u),n=Ta(J(e,[a,e.shape[e.shape.length-2],e.shape[e.shape.length-1]]),0),r=[],s=[];n.forEach(l=>{let[u,p]=K5(l,t);r.push(u),s.push(p)});let i=J(sa(r,0),e.shape),o=J(sa(s,0),e.shape);return[i,o]}}function K5(e,t=!1){return z.tidy(()=>{P(e.shape.length===2,()=>`qr2d() requires a 2D Tensor, but got a ${e.shape.length}D Tensor.`);let a=e.shape[0],n=e.shape[1],r=T2(a),s=wa(e),i=Kn([[1]],[1,1]),o=wa(i),l=a>=n?n:a;for(let u=0;u{let h=Pe(s,[u,u],[a-u,1]),f=ap(h),m=Pe(s,[u,u],[1,1]),g=Vs(np(m,0),Kn([[-1]]),Kn([[1]])),x=fe(m,ae(g,f)),A=me(h,x);A.shape[0]===1?o=wa(i):o=at([i,Pe(A,[1,0],[A.shape[0]-1,A.shape[1]])],0);let y=Xn(me(st(g,x),f)),b=Pe(s,[u,0],[a-u,n]),w=ae(y,o),S=Ws(o);if(u===0)s=fe(b,st(w,st(S,b)));else{let _=fe(b,st(w,st(S,b)));s=at([Pe(s,[0,0],[u,n]),_],0)}let C=Ws(w),E=Pe(r,[0,u],[a,r.shape[1]-u]);if(u===0)r=fe(E,st(st(E,o),C));else{let _=fe(E,st(st(E,o),C));r=at([Pe(r,[0,0],[a,u]),_],1)}return[o,s,r]}),Y([p,c,d])}return!t&&a>n&&(r=Pe(r,[0,0],[a,n]),s=Pe(s,[0,0],[n,n])),[r,s]})}var F$=D({qr_:P$}),ya;(function(e){e[e.NONE=0]="NONE",e[e.MEAN=1]="MEAN",e[e.SUM=2]="SUM",e[e.SUM_BY_NONZERO_WEIGHTS=3]="SUM_BY_NONZERO_WEIGHTS"})(ya||(ya={}));function O$(e,t,a=ya.SUM_BY_NONZERO_WEIGHTS){let n=R(e,"losses","computeWeightedLoss"),r=null;t!=null&&(r=R(t,"weights","computeWeightedLoss"));let s=r==null?n:ae(n,r);if(a===ya.NONE)return s;if(a===ya.SUM)return tt(s);if(a===ya.MEAN){if(r==null)return cd(s);{let i=n.size/r.size,o=me(tt(s),tt(r));return i>1?me(o,Fe(i)):o}}if(a===ya.SUM_BY_NONZERO_WEIGHTS){if(r==null)return me(tt(s),Fe(n.size));{let i=ae(r,Wr(n.shape)),o=He(tt(L2(i,Fe(0))),"float32");return me(tt(s),o)}}throw Error(`Unknown reduction: ${a}`)}var Ir=D({computeWeightedLoss_:O$});function D$(e,t,a,n=ya.SUM_BY_NONZERO_WEIGHTS){let r=R(e,"labels","absoluteDifference"),s=R(t,"predictions","absoluteDifference"),i=null;a!=null&&(i=R(a,"weights","absoluteDifference")),Sa(r.shape,s.shape,"Error in absoluteDifference: ");let o=qa(fe(r,s));return Ir(o,i,n)}var z$=D({absoluteDifference_:D$});function L$(e,t,a,n,r=ya.SUM_BY_NONZERO_WEIGHTS){let s=R(e,"labels","cosineDistance"),i=R(t,"predictions","cosineDistance"),o=null;n!=null&&(o=R(n,"weights","cosineDistance")),Sa(s.shape,i.shape,"Error in cosineDistance: ");let l=Fe(1),u=fe(l,tt(ae(s,i),a,!0));return Ir(u,o,r)}var B$=D({cosineDistance_:L$});function W$(e,t,a,n=ya.SUM_BY_NONZERO_WEIGHTS){let r=R(e,"labels","hingeLoss"),s=R(t,"predictions","hingeLoss"),i=null;a!=null&&(i=R(a,"weights","hingeLoss")),Sa(r.shape,s.shape,"Error in hingeLoss: ");let o=Fe(1);r=fe(ae(Fe(2),r),o);let l=rp(fe(o,ae(r,s)));return Ir(l,i,n)}var V$=D({hingeLoss_:W$});function U$(e,t,a,n=1,r=ya.SUM_BY_NONZERO_WEIGHTS){let s=R(e,"labels","huberLoss"),i=R(t,"predictions","huberLoss"),o=null;a!=null&&(o=R(a,"weights","huberLoss")),Sa(s.shape,i.shape,"Error in huberLoss: ");let l=Fe(n),u=qa(fe(i,s)),p=z2(u,l),c=fe(u,p),d=be(ae(Fe(.5),In(p)),ae(l,c));return Ir(d,o,r)}var G$=D({huberLoss_:U$});function H$(e,t,a,n=1e-7,r=ya.SUM_BY_NONZERO_WEIGHTS){let s=R(e,"labels","logLoss"),i=R(t,"predictions","logLoss"),o=null;a!=null&&(o=R(a,"weights","logLoss")),Sa(s.shape,i.shape,"Error in logLoss: ");let l=Fe(1),u=Fe(n),p=Xn(ae(s,cl(be(i,u)))),c=ae(fe(l,s),cl(be(fe(l,i),u))),d=fe(p,c);return Ir(d,o,r)}var j$=D({logLoss_:H$});function q$(e,t,a,n=ya.SUM_BY_NONZERO_WEIGHTS){let r=R(e,"labels","meanSquaredError"),s=R(t,"predictions","meanSquaredError"),i=null;a!=null&&(i=R(a,"weights","meanSquaredError")),Sa(r.shape,s.shape,"Error in meanSquaredError: ");let o=K2(r,s);return Ir(o,i,n)}var X$=D({meanSquaredError_:q$});function K$(e,t){let a=R(e,"labels","sigmoidCrossEntropyWithLogits"),n=R(t,"logits","sigmoidCrossEntropyWithLogits");Sa(a.shape,n.shape,"Error in sigmoidCrossEntropyWithLogits: ");let r=rp(n),s=ae(n,a),i=M2(Zr(Xn(qa(n))));return be(fe(r,s),i)}function Z$(e,t,a,n=0,r=ya.SUM_BY_NONZERO_WEIGHTS){let s=R(e,"multiClassLabels","sigmoidCrossEntropy"),i=R(t,"logits","sigmoidCrossEntropy"),o=null;if(a!=null&&(o=R(a,"weights","sigmoidCrossEntropy")),Sa(s.shape,i.shape,"Error in sigmoidCrossEntropy: "),n>0){let u=Fe(n),p=Fe(1),c=Fe(.5);s=be(ae(s,fe(p,u)),ae(c,u))}let l=K$(s,i);return Ir(l,o,r)}var Y$=D({sigmoidCrossEntropy_:Z$});function J$(e,t,a=-1){if(a===-1&&(a=t.rank-1),a!==t.rank-1)throw Error(`Softmax cross entropy along a non-last dimension is not yet supported. Labels / logits was rank ${t.rank} and dim was ${a}`);return Qn((n,r,s)=>{let i=_2(r,[a],!0),o=fe(He(r,"float32"),i);s([n,o]);let l=Xn(ae(o,n));return{value:tt(l,[a]),gradFunc:(u,p)=>{let[c,d]=p,h=tp(u.shape,[a]);return[ae(J(u,h),fe(He(c,"float32"),Zr(d))),ae(J(u,h),fe(Zr(d),He(c,"float32")))]}}})(e,t)}function Q$(e,t,a,n=0,r=ya.SUM_BY_NONZERO_WEIGHTS){let s=R(e,"onehotLabels","softmaxCrossEntropy"),i=R(t,"logits","softmaxCrossEntropy"),o=null;if(a!=null&&(o=R(a,"weights","softmaxCrossEntropy")),Sa(s.shape,i.shape,"Error in softmaxCrossEntropy: "),n>0){let u=Fe(n),p=Fe(1),c=Fe(s.shape[1]);s=be(ae(s,fe(p,u)),me(u,c))}let l=J$(s,i);return Ir(l,o,r)}var e_=D({softmaxCrossEntropy_:Q$});function t_(e,t,a,n){let r=R(e,"indices","sparseFillEmptyRows","int32"),s=R(t,"values","sparseFillEmptyRows"),i=R(a,"denseShape","sparseFillEmptyRows","int32"),o=R(n,"defaultValue","sparseFillEmptyRows",s.dtype);if(r.rank!==2)throw new Error(`Indices should be Tensor2D but received shape ${r.shape}`);if(s.rank!==1)throw new Error(`Values should be Tensor1D but received shape ${s.shape}`);if(i.rank!==1)throw new Error(`Dense shape should be Tensor1D but received shape ${i.shape}`);if(o.rank!==0)throw new Error(`Default value should be a scalar but received shape ${o.shape}`);let l={indices:r,values:s,denseShape:i,defaultValue:o},u=z.runKernel(Od,l);return{outputIndices:u[0],outputValues:u[1],emptyRowIndicator:u[2],reverseIndexMap:u[3]}}var a_=D({sparseFillEmptyRows_:t_});function n_(e,t,a){let n=R(e,"inputIndices","sparseReshape","int32"),r=R(t,"inputShape","sparseReshape","int32"),s=R(a,"newShape","sparseReshape","int32");if(n.rank!==2)throw new Error(`Input indices should be Tensor2D but received shape ${n.shape}`);if(r.rank!==1)throw new Error(`Input shape should be Tensor1D but received shape ${r.shape}`);if(s.rank!==1)throw new Error(`New shape should be Tensor1D but received shape ${s.shape}`);let i={inputIndices:n,inputShape:r,newShape:s},o=z.runKernel(eu,i);return{outputIndices:o[0],outputShape:o[1]}}var r_=D({sparseReshape_:n_});function s_(e,t,a){let n=R(e,"data","sparseSegmentMean"),r=R(t,"indices","sparseSegmentMean","int32"),s=R(a,"segmentIds","sparseSegmentMean","int32");if(n.rank<1)throw new Error("Data should be at least 1 dimensional but received scalar");if(r.rank!==1)throw new Error(`Indices should be Tensor1D but received shape ${r.shape}`);if(s.rank!==1)throw new Error(`Segment ids should be Tensor1D but received shape ${s.shape}`);let i={data:n,indices:r,segmentIds:s};return z.runKernel(Dd,i)}var i_=D({sparseSegmentMean_:s_});function o_(e,t,a){let n=R(e,"data","sparseSegmentSum"),r=R(t,"indices","sparseSegmentSum","int32"),s=R(a,"segmentIds","sparseSegmentSum","int32");if(n.rank<1)throw new Error("Data should be at least 1 dimensional but received scalar");if(r.rank!==1)throw new Error(`Indices should be Tensor1D but received shape ${r.shape}`);if(s.rank!==1)throw new Error(`Segment ids should be Tensor1D but received shape ${s.shape}`);let i={data:n,indices:r,segmentIds:s};return z.runKernel(zd,i)}var l_=D({sparseSegmentSum_:o_});function u_(e,t,a,n,r,s,i,o){let l=R(e,"data","stringNGrams","string");if(l.dtype!=="string")throw new Error("Data must be of datatype string");if(l.shape.length!==1)throw new Error(`Data must be a vector, saw: ${l.shape}`);let u=R(t,"dataSplits","stringNGrams");if(u.dtype!=="int32")throw new Error("Data splits must be of datatype int32");let p={separator:a,nGramWidths:n,leftPad:r,rightPad:s,padWidth:i,preserveShortSequences:o},c={data:l,dataSplits:u},d=z.runKernel(tu,c,p);return{nGrams:d[0],nGramsSplits:d[1]}}var d_=D({stringNGrams_:u_});function p_(e,t,a=!0){let n=R(e,"input","stringSplit","string"),r=R(t,"delimiter","stringSplit","string");if(n.rank!==1)throw new Error(`Input should be Tensor1D but received shape ${n.shape}`);if(r.rank!==0)throw new Error(`Delimiter should be a scalar but received shape ${r.shape}`);let s={skipEmpty:a},i={input:n,delimiter:r},o=z.runKernel(Wd,i,s);return{indices:o[0],values:o[1],shape:o[2]}}var c_=D({stringSplit_:p_});function h_(e,t){let a=R(e,"input","stringToHashBucketFast","string"),n={numBuckets:t};if(t<=0)throw new Error("Number of buckets must be at least 1");let r={input:a};return z.runKernel(Vd,r,n)}var f_=D({stringToHashBucketFast_:h_}),f4={fft:yh,ifft:hd,rfft:bh,irfft:X2},m4={hammingWindow:GM,hannWindow:u4,frame:d4,stft:XM},ge={flipLeftRight:JM,grayscaleToRGB:e$,resizeNearestNeighbor:I$,resizeBilinear:w$,rotateWithOffset:a$,cropAndResize:ZM,nonMaxSuppression:r$,nonMaxSuppressionAsync:c$,nonMaxSuppressionWithScore:f$,nonMaxSuppressionWithScoreAsync:g$,nonMaxSuppressionPadded:A$,nonMaxSuppressionPaddedAsync:b$,threshold:C$,transform:E$},g4={bandPart:M$,gramSchmidt:_$,qr:F$},x4={absoluteDifference:z$,computeWeightedLoss:Ir,cosineDistance:B$,hingeLoss:V$,huberLoss:G$,logLoss:j$,meanSquaredError:X$,sigmoidCrossEntropy:Y$,softmaxCrossEntropy:e_},A4={sparseFillEmptyRows:a_,sparseReshape:r_,sparseSegmentMean:i_,sparseSegmentSum:l_},y4={stringNGrams:d_,stringSplit:c_,stringToHashBucketFast:f_},is=class extends ny{minimize(e,t=!1,a){let{value:n,grads:r}=this.computeGradients(e,a);if(a!=null){let s=a.map(i=>({name:i.name,tensor:r[i.name]}));this.applyGradients(s)}else this.applyGradients(r);return Y(r),t?n:(n.dispose(),null)}get iterations(){return this.iterations_==null&&(this.iterations_=0),this.iterations_}incrementIterations(){this.iterations_=this.iterations+1}computeGradients(e,t){return rb(e,t)}dispose(){this.iterations_!=null&&Y(this.iterations_)}async saveIterations(){return this.iterations_==null&&(this.iterations_=0),{name:"iter",tensor:Fe(this.iterations_,"int32")}}async getWeights(){throw new Error("getWeights() is not implemented for this optimizer yet.")}async setWeights(e){throw new Error(`setWeights() is not implemented for this optimizer class ${this.getClassName()}`)}async extractIterations(e){return this.iterations_=(await e[0].tensor.data())[0],e.slice(1)}};Object.defineProperty(is,Symbol.hasInstance,{value:e=>e.minimize!=null&&e.computeGradients!=null&&e.applyGradients!=null});var Th=class extends is{constructor(e,t,a=null){super(),this.learningRate=e,this.rho=t,this.epsilon=a,this.accumulatedGrads=[],this.accumulatedUpdates=[],a==null&&(this.epsilon=z.backend.epsilon())}applyGradients(e){(Array.isArray(e)?e.map(t=>t.name):Object.keys(e)).forEach((t,a)=>{let n=z.registeredVariables[t],r=!1;this.accumulatedGrads[a]==null&&(this.accumulatedGrads[a]={originalName:`${t}/accum_grad`,variable:$e(()=>Ka(n).variable(r))}),this.accumulatedUpdates[a]==null&&(this.accumulatedUpdates[a]={originalName:`${t}/accum_var`,variable:$e(()=>Ka(n).variable(r))});let s=Array.isArray(e)?e[a].tensor:e[t];if(s==null)return;let i=this.accumulatedGrads[a].variable,o=this.accumulatedUpdates[a].variable;$e(()=>{let l=be(ae(i,this.rho),ae(In(s),1-this.rho)),u=ae(me(Jn(be(o,this.epsilon)),Jn(be(i,this.epsilon))),s),p=be(ae(o,this.rho),ae(In(u),1-this.rho));i.assign(l),o.assign(p);let c=be(ae(u,-this.learningRate),n);n.assign(c)})}),this.incrementIterations()}dispose(){this.accumulatedUpdates!=null&&(Y(this.accumulatedGrads.map(e=>e.variable)),Y(this.accumulatedUpdates.map(e=>e.variable)))}async getWeights(){let e=[...this.accumulatedGrads,...this.accumulatedUpdates];return[await this.saveIterations()].concat(e.map(t=>({name:t.originalName,tensor:t.variable})))}async setWeights(e){e=await this.extractIterations(e);let t=e.length/2,a=!1;this.accumulatedGrads=e.slice(0,t).map(n=>({originalName:n.name,variable:n.tensor.variable(a)})),this.accumulatedUpdates=e.slice(t,t*2).map(n=>({originalName:n.name,variable:n.tensor.variable(a)}))}getConfig(){return{learningRate:this.learningRate,rho:this.rho,epsilon:this.epsilon}}static fromConfig(e,t){return new e(t.learningRate,t.rho,t.epsilon)}};Th.className="Adadelta";ss(Th);var Ch=class extends is{constructor(e,t=.1){super(),this.learningRate=e,this.initialAccumulatorValue=t,this.accumulatedGrads=[]}applyGradients(e){(Array.isArray(e)?e.map(t=>t.name):Object.keys(e)).forEach((t,a)=>{let n=z.registeredVariables[t];this.accumulatedGrads[a]==null&&(this.accumulatedGrads[a]={originalName:`${t}/accumulator`,variable:$e(()=>nr(n.shape,this.initialAccumulatorValue).variable(!1))});let r=Array.isArray(e)?e[a].tensor:e[t];if(r==null)return;let s=this.accumulatedGrads[a].variable;$e(()=>{let i=be(s,In(r));s.assign(i);let o=be(ae(me(r,Jn(be(i,z.backend.epsilon()))),-this.learningRate),n);n.assign(o)})}),this.incrementIterations()}dispose(){this.accumulatedGrads!=null&&Y(this.accumulatedGrads.map(e=>e.variable))}async getWeights(){return[await this.saveIterations()].concat(this.accumulatedGrads.map(e=>({name:e.originalName,tensor:e.variable})))}async setWeights(e){e=await this.extractIterations(e);let t=!1;this.accumulatedGrads=e.map(a=>({originalName:a.name,variable:a.tensor.variable(t)}))}getConfig(){return{learningRate:this.learningRate,initialAccumulatorValue:this.initialAccumulatorValue}}static fromConfig(e,t){return new e(t.learningRate,t.initialAccumulatorValue)}};Ch.className="Adagrad";ss(Ch);var Nh=class extends is{constructor(e,t,a,n=null){super(),this.learningRate=e,this.beta1=t,this.beta2=a,this.epsilon=n,this.accumulatedFirstMoment=[],this.accumulatedSecondMoment=[],$e(()=>{this.accBeta1=Fe(t).variable(),this.accBeta2=Fe(a).variable()}),n==null&&(this.epsilon=z.backend.epsilon())}applyGradients(e){let t=Array.isArray(e)?e.map(a=>a.name):Object.keys(e);$e(()=>{let a=fe(1,this.accBeta1),n=fe(1,this.accBeta2);t.forEach((r,s)=>{let i=z.registeredVariables[r],o=!1;this.accumulatedFirstMoment[s]==null&&(this.accumulatedFirstMoment[s]={originalName:`${r}/m`,variable:$e(()=>Ka(i).variable(o))}),this.accumulatedSecondMoment[s]==null&&(this.accumulatedSecondMoment[s]={originalName:`${r}/v`,variable:$e(()=>Ka(i).variable(o))});let l=Array.isArray(e)?e[s].tensor:e[r];if(l==null)return;let u=this.accumulatedFirstMoment[s].variable,p=this.accumulatedSecondMoment[s].variable,c=be(ae(u,this.beta1),ae(l,1-this.beta1)),d=be(ae(p,this.beta2),ae(In(l),1-this.beta2)),h=me(c,a),f=me(d,n);u.assign(c),p.assign(d);let m=be(ae(me(h,be(Jn(f),this.epsilon)),-this.learningRate),i);i.assign(m)}),this.accBeta1.assign(ae(this.accBeta1,this.beta1)),this.accBeta2.assign(ae(this.accBeta2,this.beta2))}),this.incrementIterations()}dispose(){this.accBeta1.dispose(),this.accBeta2.dispose(),this.accumulatedFirstMoment!=null&&Y(this.accumulatedFirstMoment.map(e=>e.variable)),this.accumulatedSecondMoment!=null&&Y(this.accumulatedSecondMoment.map(e=>e.variable))}async getWeights(){let e=[...this.accumulatedFirstMoment,...this.accumulatedSecondMoment];return[await this.saveIterations()].concat(e.map(t=>({name:t.originalName,tensor:t.variable})))}async setWeights(e){e=await this.extractIterations(e),$e(()=>{this.accBeta1.assign(pl(this.beta1,this.iterations_+1)),this.accBeta2.assign(pl(this.beta2,this.iterations_+1))});let t=e.length/2,a=!1;this.accumulatedFirstMoment=e.slice(0,t).map(n=>({originalName:n.name,variable:n.tensor.variable(a)})),this.accumulatedSecondMoment=e.slice(t,t*2).map(n=>({originalName:n.name,variable:n.tensor.variable(a)}))}getConfig(){return{learningRate:this.learningRate,beta1:this.beta1,beta2:this.beta2,epsilon:this.epsilon}}static fromConfig(e,t){return new e(t.learningRate,t.beta1,t.beta2,t.epsilon)}};Nh.className="Adam";ss(Nh);var Eh=class extends is{constructor(e,t,a,n=null,r=0){super(),this.learningRate=e,this.beta1=t,this.beta2=a,this.epsilon=n,this.decay=r,this.accumulatedFirstMoment=[],this.accumulatedWeightedInfNorm=[],$e(()=>{this.iteration=Fe(0).variable(),this.accBeta1=Fe(t).variable()}),n==null&&(this.epsilon=z.backend.epsilon())}applyGradients(e){let t=Array.isArray(e)?e.map(a=>a.name):Object.keys(e);$e(()=>{let a=fe(1,this.accBeta1),n=me(-this.learningRate,be(ae(this.iteration,this.decay),1));t.forEach((r,s)=>{let i=z.registeredVariables[r],o=!1;this.accumulatedFirstMoment[s]==null&&(this.accumulatedFirstMoment[s]={originalName:`${r}/m`,variable:Ka(i).variable(o)}),this.accumulatedWeightedInfNorm[s]==null&&(this.accumulatedWeightedInfNorm[s]={originalName:`${r}/v`,variable:Ka(i).variable(o)});let l=Array.isArray(e)?e[s].tensor:e[r];if(l==null)return;let u=this.accumulatedFirstMoment[s].variable,p=this.accumulatedWeightedInfNorm[s].variable,c=be(ae(u,this.beta1),ae(l,1-this.beta1)),d=ae(p,this.beta2),h=qa(l),f=D2(d,h);u.assign(c),p.assign(f);let m=be(ae(me(n,a),me(c,be(f,this.epsilon))),i);i.assign(m)}),this.iteration.assign(be(this.iteration,1)),this.accBeta1.assign(ae(this.accBeta1,this.beta1))}),this.incrementIterations()}dispose(){this.accBeta1.dispose(),this.iteration.dispose(),this.accumulatedFirstMoment!=null&&Y(this.accumulatedFirstMoment.map(e=>e.variable)),this.accumulatedWeightedInfNorm!=null&&Y(this.accumulatedWeightedInfNorm.map(e=>e.variable))}async getWeights(){throw new Error("getWeights() is not implemented for Adamax yet.")}async setWeights(e){throw new Error("setWeights() is not implemented for Adamax yet.")}getConfig(){return{learningRate:this.learningRate,beta1:this.beta1,beta2:this.beta2,epsilon:this.epsilon,decay:this.decay}}static fromConfig(e,t){return new e(t.learningRate,t.beta1,t.beta2,t.epsilon,t.decay)}};Eh.className="Adamax";ss(Eh);var ip=class extends is{constructor(e){super(),this.learningRate=e,this.setLearningRate(e)}applyGradients(e){(Array.isArray(e)?e.map(t=>t.name):Object.keys(e)).forEach((t,a)=>{let n=Array.isArray(e)?e[a].tensor:e[t];if(n==null)return;let r=z.registeredVariables[t];$e(()=>{let s=be(ae(this.c,n),r);r.assign(s)})}),this.incrementIterations()}setLearningRate(e){this.learningRate=e,this.c!=null&&this.c.dispose(),this.c=On(Fe(-e))}dispose(){this.c.dispose()}async getWeights(){return[await this.saveIterations()]}async setWeights(e){if(e=await this.extractIterations(e),e.length!==0)throw new Error("SGD optimizer does not have settable weights.")}getConfig(){return{learningRate:this.learningRate}}static fromConfig(e,t){return new e(t.learningRate)}};ip.className="SGD";ss(ip);var Rh=class extends ip{constructor(e,t,a=!1){super(e),this.learningRate=e,this.momentum=t,this.useNesterov=a,this.accumulations=[],this.m=Fe(this.momentum)}applyGradients(e){(Array.isArray(e)?e.map(t=>t.name):Object.keys(e)).forEach((t,a)=>{let n=z.registeredVariables[t];this.accumulations[a]==null&&(this.accumulations[a]={originalName:`${t}/momentum`,variable:$e(()=>Ka(n).variable(!1))});let r=this.accumulations[a].variable,s=Array.isArray(e)?e[a].tensor:e[t];s!=null&&$e(()=>{let i,o=be(ae(this.m,r),s);this.useNesterov?i=be(ae(this.c,be(s,ae(o,this.m))),n):i=be(ae(this.c,o),n),r.assign(o),n.assign(i)})}),this.incrementIterations()}dispose(){this.m.dispose(),this.accumulations!=null&&Y(this.accumulations.map(e=>e.variable))}setMomentum(e){this.momentum=e}async getWeights(){return[await this.saveIterations()].concat(this.accumulations.map(e=>({name:e.originalName,tensor:e.variable})))}async setWeights(e){e=await this.extractIterations(e);let t=!1;this.accumulations=e.map(a=>({originalName:a.name,variable:a.tensor.variable(t)}))}getConfig(){return{learningRate:this.learningRate,momentum:this.momentum,useNesterov:this.useNesterov}}static fromConfig(e,t){return new e(t.learningRate,t.momentum,t.useNesterov)}};Rh.className="Momentum";ss(Rh);var Mh=class extends is{constructor(e,t=.9,a=0,n=null,r=!1){if(super(),this.learningRate=e,this.decay=t,this.momentum=a,this.epsilon=n,this.accumulatedMeanSquares=[],this.accumulatedMoments=[],this.accumulatedMeanGrads=[],this.centered=r,n==null&&(this.epsilon=z.backend.epsilon()),e==null)throw new Error("learningRate for RMSPropOptimizer must be defined.")}applyGradients(e){(Array.isArray(e)?e.map(t=>t.name):Object.keys(e)).forEach((t,a)=>{let n=z.registeredVariables[t],r=!1;this.accumulatedMeanSquares[a]==null&&(this.accumulatedMeanSquares[a]={originalName:`${t}/rms`,variable:$e(()=>Ka(n).variable(r))}),this.accumulatedMoments[a]==null&&(this.accumulatedMoments[a]={originalName:`${t}/momentum`,variable:$e(()=>Ka(n).variable(r))}),this.accumulatedMeanGrads[a]==null&&this.centered&&(this.accumulatedMeanGrads[a]={originalName:`${t}/mg`,variable:$e(()=>Ka(n).variable(r))});let s=Array.isArray(e)?e[a].tensor:e[t];if(s==null)return;let i=this.accumulatedMeanSquares[a].variable,o=this.accumulatedMoments[a].variable;$e(()=>{let l=be(ae(i,this.decay),ae(In(s),1-this.decay));if(this.centered){let u=this.accumulatedMeanGrads[a].variable,p=be(ae(u,this.decay),ae(s,1-this.decay)),c=me(ae(s,this.learningRate),Jn(fe(l,be(In(p),this.epsilon)))),d=be(ae(o,this.momentum),c);i.assign(l),u.assign(p),o.assign(d);let h=fe(n,d);n.assign(h)}else{let u=be(ae(i,this.decay),ae(In(s),1-this.decay)),p=be(ae(o,this.momentum),me(ae(s,this.learningRate),Jn(be(u,this.epsilon))));i.assign(u),o.assign(p);let c=fe(n,p);n.assign(c)}})}),this.incrementIterations()}dispose(){this.accumulatedMeanSquares!=null&&Y(this.accumulatedMeanSquares.map(e=>e.variable)),this.accumulatedMeanGrads!=null&&this.centered&&Y(this.accumulatedMeanGrads.map(e=>e.variable)),this.accumulatedMoments!=null&&Y(this.accumulatedMoments.map(e=>e.variable))}async getWeights(){let e=[...this.accumulatedMeanSquares,...this.accumulatedMoments];return this.centered&&e.push(...this.accumulatedMeanGrads),[await this.saveIterations()].concat(e.map(t=>({name:t.originalName,tensor:t.variable})))}async setWeights(e){e=await this.extractIterations(e);let t=this.centered?e.length/3:e.length/2,a=!1;this.accumulatedMeanSquares=e.slice(0,t).map(n=>({originalName:n.name,variable:n.tensor.variable(a)})),this.accumulatedMoments=e.slice(t,t*2).map(n=>({originalName:n.name,variable:n.tensor.variable(a)})),this.centered&&(this.accumulatedMeanGrads=e.slice(t*2,t*3).map(n=>({originalName:n.name,variable:n.tensor.variable(a)})))}getConfig(){return{learningRate:this.learningRate,decay:this.decay,momentum:this.momentum,epsilon:this.epsilon,centered:this.centered}}static fromConfig(e,t){return new e(t.learningRate,t.decay,t.momentum,t.epsilon,t.centered)}};Mh.className="RMSProp";ss(Mh);var Or=class{static sgd(e){return new ip(e)}static momentum(e,t,a=!1){return new Rh(e,t,a)}static rmsprop(e,t=.9,a=0,n=null,r=!1){return new Mh(e,t,a,n,r)}static adam(e=.001,t=.9,a=.999,n=null){return new Nh(e,t,a,n)}static adadelta(e=.001,t=.95,a=null){return new Th(e,t,a)}static adamax(e=.002,t=.9,a=.999,n=null,r=0){return new Eh(e,t,a,n,r)}static adagrad(e,t=.1){return new Ch(e,t)}},m_={sgd:Or.sgd,momentum:Or.momentum,adadelta:Or.adadelta,adagrad:Or.adagrad,rmsprop:Or.rmsprop,adamax:Or.adamax,adam:Or.adam},g_=(()=>typeof requestAnimationFrame!="undefined"?requestAnimationFrame:typeof setImmediate!="undefined"?setImmediate:e=>e())();function b4(){return new Promise(e=>g_(()=>e()))}var T={};Xe(T,{ERF_A1:()=>__,ERF_A2:()=>P_,ERF_A3:()=>F_,ERF_A4:()=>O_,ERF_A5:()=>D_,ERF_P:()=>$_,PARALLELIZE_THRESHOLD:()=>t3,RowPartitionType:()=>Hn,SELU_SCALE:()=>M_,SELU_SCALEALPHA:()=>R_,applyActivation:()=>Ih,assertAndGetBroadcastShape:()=>zt,assertAxesAreInnerMostDims:()=>hE,assertParamsConsistent:()=>x_,assignToTypedArray:()=>U_,axesAreInnerMostDims:()=>S2,calculateShapes:()=>qA,checkEinsumDimSizes:()=>K_,checkPadOnDimRoundingMode:()=>Sn,combineLocations:()=>Xy,combineRaggedTensorToTensorShapes:()=>y_,complexWithEvenIndex:()=>B_,complexWithOddIndex:()=>W_,computeConv2DInfo:()=>Jd,computeConv3DInfo:()=>Ay,computeDefaultPad:()=>y2,computeDilation2DInfo:()=>cN,computeOptimalWindowSize:()=>k_,computeOutAndReduceShapes:()=>cE,computeOutShape:()=>A_,computePool2DInfo:()=>xy,computePool3DInfo:()=>hN,convertConv2DDataFormat:()=>yy,decodeEinsumEquation:()=>q_,eitherStridesOrDilationsAreOne:()=>kr,expandShapeToKeepDim:()=>tp,exponent:()=>H_,exponents:()=>G_,fromStringArrayToUint8:()=>gP,fromUint8ToStringArray:()=>mP,getAxesPermutation:()=>fE,getBroadcastDims:()=>GA,getComplexWithIndex:()=>V_,getEinsumComputePath:()=>Z_,getEinsumPermutation:()=>X_,getFusedBiasGradient:()=>kh,getFusedDyActivation:()=>wh,getImageCenter:()=>I_,getInnerMostAxes:()=>gE,getPermuted:()=>T_,getRaggedRank:()=>v_,getReductionAxes:()=>d2,getReshaped:()=>S_,getReshapedPermuted:()=>C_,getRowPartitionTypesHelper:()=>b_,getSliceBeginCoords:()=>N_,getSliceSize:()=>E_,getSparseFillEmptyRowsIndicesDenseShapeMismatch:()=>eP,getSparseFillEmptyRowsNegativeIndexErrorMessage:()=>tP,getSparseFillEmptyRowsOutOfRangeIndexErrorMessage:()=>aP,getSparseReshapeEmptyTensorZeroOutputDimErrorMessage:()=>sP,getSparseReshapeInputOutputMismatchErrorMessage:()=>oP,getSparseReshapeInputOutputMultipleErrorMessage:()=>iP,getSparseReshapeMultipleNegativeOneOutputDimErrorMessage:()=>nP,getSparseReshapeNegativeOutputDimErrorMessage:()=>rP,getSparseSegmentReductionIndicesOutOfRangeErrorMessage:()=>pP,getSparseSegmentReductionNegativeSegmentIdsErrorMessage:()=>lP,getSparseSegmentReductionNonIncreasingSegmentIdsErrorMessage:()=>uP,getSparseSegmentReductionSegmentIdOutOfRangeErrorMessage:()=>dP,getUndoAxesPermutation:()=>mE,isIdentityPermutation:()=>Y_,log:()=>MS,mergeRealAndImagArrays:()=>z_,prepareAndValidate:()=>jA,prepareSplitSize:()=>Q_,segment_util:()=>v4,shouldFuse:()=>Sh,slice_util:()=>It,splitRealAndImagArrays:()=>L_,tupleValuesAreOne:()=>dd,upcastType:()=>ca,validateDefaultValueShape:()=>w_,validateInput:()=>m2,validateUpdateShape:()=>f2,warn:()=>zr});function x_(e,t){let a=e[0].length;e.forEach((r,s)=>{P(r.length===a,()=>`Error in concat${a}D: rank of tensors[${s}] must be the same as the rank of the rest (${a})`)}),P(t>=0&&t`Error in concat${a}D: axis must be between 0 and ${a-1}.`);let n=e[0];e.forEach((r,s)=>{for(let i=0;i`Error in concat${a}D: Shape of tensors[${s}] (${r}) does not match the shape of the rest (${n}) along the non-concatenated axis ${s}.`)})}function A_(e,t){let a=e[0].slice();for(let n=1;n=0)if(o>=0){if(o!==s)throw new Error(`rt input.shape and shape=${t} are incompatible: rt input.shape[${r+e}] = ${s} but shape[${r+e}] = ${o}`)}else n[i]=s}return n}function b_(e){let t={FIRST_DIM_SIZE:Hn.FIRST_DIM_SIZE,VALUE_ROWIDS:Hn.VALUE_ROWIDS,ROW_LENGTHS:Hn.ROW_LENGTHS,ROW_SPLITS:Hn.ROW_SPLITS,ROW_LIMITS:Hn.ROW_LIMITS,ROW_STARTS:Hn.ROW_STARTS},a=[];for(let n of e)if(n in t)a.push(t[n]);else break;return a}function v_(e){return e.length===0?0:e[0]===Hn.FIRST_DIM_SIZE?e.length-1:e.length}function w_(e,t){if(e==null||t==null)return;let a=e.length,n=t.length;if(a>=n)throw new Error(`defaultValue.shape=${e} and ragged tensor flatValues.shape=${t}, are incompatible: defaultValue.rank = ${a} must be less than ragged tensor input flatValues.rank = ${n})`);for(let r=0;r=0&&i>=0&&s!==1&&s!==i)throw new Error(`defaultValue.shape=${e}, and ragged tensor input flatValues.shape=${t} are incompatible: defaultValue.shape[${r-e.length}] = ${s} but ragged tensor input.flatValues.shape[${r-e.length}] = ${i}`)}}var t3=30;function k_(e){return e<=t3?e:Ic(e,Math.floor(Math.sqrt(e)))}function I_(e,t,a){let n=a*(typeof e=="number"?e:e[0]),r=t*(typeof e=="number"?e:e[1]);return[n,r]}function S_(e,t,a,n=!0){let r=[];if(n)r=r.concat(t.slice(0)),r.push(e[0]/a),r=r.concat(e.slice(1));else{r=r.concat(e[0]);let s=t.length;for(let i=0;i=t*2+1||i%2===1?s.push(i):r.push(i);n.push(...r),n.push(0),n.push(...s)}return n}function C_(e,t,a,n=!0){let r=[];n?r.push(e[0]/a):r.push(e[0]*a);for(let s=1;s/g,Z5=",",Y5="...";function q_(e,t){e=e.replace(/\s/g,"");let a=(e.length-e.replace(j_,"").length)/Om.length;if(a<1)throw new Error("Equations without an arrow are not supported.");if(a>1)throw new Error(`Equation must contain exactly one arrow ("${Om}").`);let[n,r]=e.split(Om);P(n.indexOf(Y5)===-1,()=>`The ellipsis notation ("${Y5}") is not supported yet.`);let s=n.split(Z5),i=s.length;if(t!==i)throw new Error(`Expected ${i} input tensors, received ${t}`);if(i>2)throw new Error("Support for more than 2 input tensors is not implemented yet.");let o=[];for(let d=0;df.indexOf(h)!==-1))throw new Error(`Output subscripts contain the label ${h} not present in the input subscripts.`);o.indexOf(h)===-1&&o.push(h)}for(let d=0;dr!==-1),{permutationIndices:a,expandDims:n}}function K_(e,t,a){let n=new Array(e);for(let r=0;r`Expected dimension ${n[t[r][i]]} at axis ${i} of input shaped ${JSON.stringify(s)}, but got dimension ${s[i]}`)}}function Z_(e,t){let a=e,n=[],r=0;e.length===0&&a.push(-1),r=e.length+1;for(let i=0;it===a)}function J_(e,t){let a=[];for(let n=0;n"Number of splits must evenly divide the axis."),n=new Array(t).fill(e.shape[a]/t);else{let r=t.reduce((i,o)=>(o===-1&&(i+=1),i),0);P(r<=1,()=>"There should be only one negative value in split array.");let s=t.indexOf(-1);if(s!==-1){let i=t.reduce((o,l)=>l>0?o+l:o);t[s]=e.shape[a]-i}P(e.shape[a]===t.reduce((i,o)=>i+o),()=>"The sum of sizes must match the size of the axis dimension."),n=t}return n}function eP(e){return`Received SparseTensor with denseShape[0] = 0 but indices.shape[0] = ${e}`}function tP(e,t){return`indices(${e}, 0) is invalid: ${t} < 0`}function aP(e,t,a){return`indices(${e}, 0) is invalid: ${t} >= ${a}`}function nP(e,t){return`only one output dimension may be -1, not both ${e} and ${t}`}function rP(e,t){return`size ${e} must be non-negative, not ${t}`}function sP(){return"reshape cannot infer the missing input size for an empty tensor unless all specified input sizes are non-zero"}function iP(e,t){let a=At(e),n=At(t);return`Input to reshape is a SparseTensor with ${a} dense values, but the requested shape requires a multiple of ${n}. inputShape=${e} outputShape= ${t}`}function oP(e,t){let a=At(e),n=At(t);return`Input to reshape is a tensor with ${a} dense values, but the requested shape has ${n}. inputShape=${e} outputShape=${t}`}function lP(){return"segment ids must be >= 0"}function uP(){return"segment ids are not increasing"}function dP(e,t){return`Segment id ${e} out of range [0, ${t}), possibly because segmentIds input is not sorted.`}function pP(e,t,a){return`Bad: indices[${e}] == ${t} out of range [0, ${a})`}var v4={};Xe(v4,{collectGatherOpShapeInfo:()=>fP,computeOutShape:()=>hP,segOpComputeOptimalWindowSize:()=>cP});function cP(e,t){let a=!1,n;for(e<=t3?(n=e,a=!0):n=Ic(e,Math.floor(Math.sqrt(e)));!a;)n>t||n===e?a=!0:n=Ic(e,n+1);return n}function hP(e,t,a){let n=[],r=e.length;for(let s=0;sr))throw new Error(`Expect batchDims in the range of [-${r}, ${r}], but got ${n}`);if(n<0&&(n+=r),n>s)throw new Error(`batchDims (${n}) must be less than rank(x) ( ${s}).`);if(aTc(t))}catch(t){throw new Error(`Failed to decode encoded string bytes into utf-8, error: ${t}`)}}function gP(e){return e.map(t=>Gd(t))}var Tn={};Xe(Tn,{nonMaxSuppressionV3Impl:()=>p4,nonMaxSuppressionV4Impl:()=>c4,nonMaxSuppressionV5Impl:()=>h4,whereImpl:()=>t4});var xP=W();xP.registerFlag("KEEP_INTERMEDIATE_TENSORS",()=>!1,e=>{e&&console.warn("Keep intermediate tensors is ON. This will print the values of all intermediate tensors during model inference. Not all models support this mode. For details, check e2e/benchmarks/ model_config.js. This significantly impacts performance.")});var wn;(function(e){e[e.DT_INVALID=0]="DT_INVALID",e[e.DT_FLOAT=1]="DT_FLOAT",e[e.DT_DOUBLE=2]="DT_DOUBLE",e[e.DT_INT32=3]="DT_INT32",e[e.DT_UINT8=4]="DT_UINT8",e[e.DT_INT16=5]="DT_INT16",e[e.DT_INT8=6]="DT_INT8",e[e.DT_STRING=7]="DT_STRING",e[e.DT_COMPLEX64=8]="DT_COMPLEX64",e[e.DT_INT64=9]="DT_INT64",e[e.DT_BOOL=10]="DT_BOOL",e[e.DT_QINT8=11]="DT_QINT8",e[e.DT_QUINT8=12]="DT_QUINT8",e[e.DT_QINT32=13]="DT_QINT32",e[e.DT_BFLOAT16=14]="DT_BFLOAT16",e[e.DT_QINT16=15]="DT_QINT16",e[e.DT_QUINT16=16]="DT_QUINT16",e[e.DT_UINT16=17]="DT_UINT16",e[e.DT_COMPLEX128=18]="DT_COMPLEX128",e[e.DT_HALF=19]="DT_HALF",e[e.DT_RESOURCE=20]="DT_RESOURCE",e[e.DT_VARIANT=21]="DT_VARIANT",e[e.DT_UINT32=22]="DT_UINT32",e[e.DT_UINT64=23]="DT_UINT64",e[e.DT_FLOAT_REF=101]="DT_FLOAT_REF",e[e.DT_DOUBLE_REF=102]="DT_DOUBLE_REF",e[e.DT_INT32_REF=103]="DT_INT32_REF",e[e.DT_UINT8_REF=104]="DT_UINT8_REF",e[e.DT_INT16_REF=105]="DT_INT16_REF",e[e.DT_INT8_REF=106]="DT_INT8_REF",e[e.DT_STRING_REF=107]="DT_STRING_REF",e[e.DT_COMPLEX64_REF=108]="DT_COMPLEX64_REF",e[e.DT_INT64_REF=109]="DT_INT64_REF",e[e.DT_BOOL_REF=110]="DT_BOOL_REF",e[e.DT_QINT8_REF=111]="DT_QINT8_REF",e[e.DT_QUINT8_REF=112]="DT_QUINT8_REF",e[e.DT_QINT32_REF=113]="DT_QINT32_REF",e[e.DT_BFLOAT16_REF=114]="DT_BFLOAT16_REF",e[e.DT_QINT16_REF=115]="DT_QINT16_REF",e[e.DT_QUINT16_REF=116]="DT_QUINT16_REF",e[e.DT_UINT16_REF=117]="DT_UINT16_REF",e[e.DT_COMPLEX128_REF=118]="DT_COMPLEX128_REF",e[e.DT_HALF_REF=119]="DT_HALF_REF",e[e.DT_RESOURCE_REF=120]="DT_RESOURCE_REF",e[e.DT_VARIANT_REF=121]="DT_VARIANT_REF",e[e.DT_UINT32_REF=122]="DT_UINT32_REF",e[e.DT_UINT64_REF=123]="DT_UINT64_REF"})(wn||(wn={}));var J5;(function(e){let t;(function(a){a[a.LEGACY=0]="LEGACY",a[a.V1=1]="V1",a[a.V2=2]="V2"})(t=e.CheckpointFormatVersion||(e.CheckpointFormatVersion={}))})(J5||(J5={}));var a3={};function AP(e,t){let a={tfOpName:e,category:"custom",inputs:[],attrs:[],customExecutor:t};a3[e]=a}function w4(e){return a3[e]}function yP(e){delete a3[e]}function k(e,t,a,n,r){let s=t.inputParams[e];if(s&&s.inputIndexStart!==void 0){let o=s.inputIndexStart,l=s.inputIndexEnd===0?void 0:s.inputIndexEnd===void 0?o+1:s.inputIndexEnd;if(s.type==="tensor")return ba(t.inputNames[s.inputIndexStart],a,n,r);if(s.type==="tensors")return t.inputNames.slice(o,l).map(c=>ba(c,a,n,r));let u=ba(t.inputNames.slice(o)[0],a,n,r),p=u.dataSync();return s.type==="number"?p[0]:v.toNestedArray(u.shape,p)}let i=t.attrParams[e];return i&&i.value}function ba(e,t,a,n){let[r,s]=ja(e);if(n!=null){let o=n.getHashTableHandleByName(r);if(o!=null)return o}let i=a.currentContextIds.find(o=>!!t[Mc(r,o)]);return i!==void 0?t[Mc(r,i)][s]:void 0}function bP(e,t,a){return t[Mc(e,a.currentContextId)]}function mr(e,t){let[a,n,r]=ja(e);return[Mc(a,t&&t.currentContextId),n,r]}function Mc(e,t){return t?`${e}-${t}`:e}function ja(e){let t=e.split(":");if(t.length===1)return[e,0,void 0];let a=t[0],n=t.length===3?t[1]:void 0,r=Number(t[t.length-1]);return[a,r,n]}function mc(e,t,a){let n=k("pad",e,t,a);if(n==="explicit"){n=k("explicitPaddings",e,t,a);let r=[[0,0],[0,0],[0,0],[0,0]];for(let s=0;s<4;s++)r[s][0]=n[s*2],r[s][1]=n[s*2+1];return r}return n}function gr(e){return e.kept?e:wa(e)}var k4={};Xe(k4,{json:()=>vP});var vP=[{tfOpName:"Add",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"AddV2",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"AddN",category:"arithmetic",inputs:[{start:0,end:0,name:"tensors",type:"tensors"}]},{tfOpName:"BiasAdd",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:!0}]},{tfOpName:"Sub",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"RealDiv",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Div",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"DivNoNan",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"FloorDiv",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Mul",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Maximum",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Minimum",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Pow",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"SquaredDifference",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Mod",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"FloorMod",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]}],I4={};Xe(I4,{json:()=>wP});var wP=[{tfOpName:"Abs",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Acos",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Asin",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Atan",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Atan2",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"y",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Ceil",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"ClipByValue",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"clipValueMin",type:"number"},{start:2,name:"clipValueMax",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Complex",category:"basic_math",inputs:[{start:0,name:"real",type:"tensor"},{start:1,name:"imag",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"ComplexAbs",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Cos",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Cosh",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Elu",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Exp",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Floor",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Log",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Imag",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0},{tfName:"Tout",name:"outputType",type:"dtype",notSupported:!0}]},{tfOpName:"Neg",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Real",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0},{tfName:"Tout",name:"outputType",type:"dtype",notSupported:!0}]},{tfOpName:"Prelu",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"alpha",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Relu",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Relu6",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Selu",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Sigmoid",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Sin",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Sinh",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Sqrt",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Rsqrt",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Square",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Tan",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Tanh",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Sign",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Round",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Expm1",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Log1p",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Reciprocal",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Softplus",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Asinh",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Acosh",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Atanh",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Erf",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Prod",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axes",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool",notSupported:!0},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"LeakyRelu",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"alpha",name:"alpha",type:"number",defaultValue:.2},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"IsNan",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]}],S4={};Xe(S4,{json:()=>kP});var kP=[{tfOpName:"EmptyTensorList",category:"control",inputs:[{start:0,name:"elementShape",type:"shape"},{start:1,name:"maxNumElements",type:"number"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"LoopCond",category:"control",inputs:[{start:0,name:"pred",type:"tensor"}]},{tfOpName:"Switch",category:"control",inputs:[{start:0,name:"data",type:"tensor"},{start:1,name:"pred",type:"tensor"}]},{tfOpName:"Merge",category:"control",inputs:[{start:0,end:0,name:"tensors",type:"tensors"}]},{tfOpName:"Enter",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0},{tfName:"frame_name",name:"frameName",type:"string"},{tfName:"is_constant",name:"isConstant",type:"bool"}]},{tfOpName:"Exit",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"NextIteration",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"TensorArrayV3",category:"control",inputs:[{start:0,name:"size",type:"number"}],attrs:[{tfName:"dtype",name:"dtype",type:"dtype"},{tfName:"element_shape",name:"elementShape",type:"shape"},{tfName:"dynamic_size",name:"dynamicSize",type:"bool"},{tfName:"clear_after_read",name:"clearAfterRead",type:"bool"},{tfName:"identical_element_shapes",name:"identicalElementShapes",type:"bool"},{tfName:"tensor_array_name",name:"name",type:"string"}]},{tfOpName:"TensorArrayWriteV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"index",type:"number"},{start:2,name:"tensor",type:"tensor"},{start:3,name:"flowIn",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"TensorArrayReadV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"index",type:"number"},{start:2,name:"flowIn",type:"number"}],attrs:[{tfName:"dtype",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"TensorArrayGatherV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"indices",type:"number[]"},{start:2,name:"flowIn",type:"number"}],attrs:[{tfName:"dtype",name:"dtype",type:"dtype"},{tfName:"element_shape",name:"elementShape",type:"shape"}]},{tfOpName:"TensorArrayScatterV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"indices",type:"number[]"},{start:2,name:"tensor",type:"tensor"},{start:3,name:"flowIn",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"TensorArrayConcatV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"flowIn",type:"number"}],attrs:[{tfName:"dtype",name:"dtype",type:"dtype"},{tfName:"element_shape_except0",name:"elementShapeExcept0",type:"shape",notSupported:!0}]},{tfOpName:"TensorArraySplitV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"tensor",type:"tensor"},{start:2,name:"lengths",type:"number[]"},{start:3,name:"flowIn",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"TensorArraySizeV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"flowIn",type:"number"}]},{tfOpName:"TensorArrayCloseV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"}]},{tfOpName:"StatelessIf",category:"control",inputs:[{start:0,name:"cond",type:"tensor"},{start:1,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"then_branch",name:"thenBranch",type:"func"},{tfName:"else_branch",name:"elseBranch",type:"func"}]},{tfOpName:"If",category:"control",inputs:[{start:0,name:"cond",type:"tensor"},{start:1,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"then_branch",name:"thenBranch",type:"func"},{tfName:"else_branch",name:"elseBranch",type:"func"}]},{tfOpName:"StatelessWhile",category:"control",inputs:[{start:0,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"cond",name:"cond",type:"func"},{tfName:"body",name:"body",type:"func"}]},{tfOpName:"While",category:"control",inputs:[{start:0,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"cond",name:"cond",type:"func"},{tfName:"body",name:"body",type:"func"}]},{tfOpName:"TensorListScatter",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"},{start:1,name:"indices",type:"number[]"},{start:2,name:"elementShape",type:"shape"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListScatterV2",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"},{start:1,name:"indices",type:"number[]"},{start:2,name:"elementShape",type:"shape"},{start:3,name:"numElements",type:"number"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListGather",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"indices",type:"number[]"},{start:2,name:"elementShape",type:"shape"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListGetItem",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"index",type:"number"},{start:2,name:"elementShape",type:"shape"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListSetItem",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"index",type:"number"},{start:2,name:"tensor",type:"tensor"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListReserve",category:"control",inputs:[{start:0,name:"elementShape",type:"shape"},{start:1,name:"numElements",type:"number"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListFromTensor",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"},{start:1,name:"elementShape",type:"shape"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListStack",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"elementShape",type:"shape"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"},{tfName:"num_elements",name:"numElements",type:"dtype"}]},{tfOpName:"TensorListSplit",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"},{start:1,name:"elementShape",type:"shape"},{start:2,name:"lengths",type:"number[]"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListConcat",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"}],attrs:[{tfName:"element_shape",name:"elementShape",type:"shape"},{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListConcatV2",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"}],attrs:[{tfName:"element_shape",name:"elementShape",type:"shape"},{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListPopBack",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"elementShape",type:"shape"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListPushBack",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"tensor",type:"tensor"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListLength",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"}]},{tfOpName:"TensorListResize",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"size",type:"number"}]}],T4={};Xe(T4,{json:()=>IP});var IP=[{tfOpName:"AvgPool",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:!0},{tfName:"ksize",name:"kernelSize",type:"number[]"},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"MaxPool",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:!0},{tfName:"ksize",name:"kernelSize",type:"number[]"},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[],notSupported:!0},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"MaxPoolWithArgmax",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"ksize",name:"kernelSize",type:"number[]"},{tfName:"include_batch_in_index",name:"includeBatchInIndex",type:"bool"},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"AvgPool3D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:!0},{tfName:"ksize",name:"kernelSize",type:"number[]"},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"MaxPool3D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:!0},{tfName:"ksize",name:"kernelSize",type:"number[]"},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Conv1D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"}],attrs:[{tfName:"stride",name:"stride",type:"number"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NWC"},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0},{tfName:"dilation",name:"dilation",type:"number",defaultValue:1}]},{tfOpName:"Conv2D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0},{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"useCudnnOnGpu",name:"useCudnnOnGpu",type:"bool"},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NHWC"},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[]},{tfName:"dilations",name:"dilations",type:"number[]"}]},{tfOpName:"_FusedConv2D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"},{start:2,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"num_args",name:"numArgs",type:"number"},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0},{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[]},{tfName:"use_cudnn_on_gpu",name:"useCudnnOnGpu",type:"bool",defaultValue:!0},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NHWC"},{tfName:"dilations",name:"dilations",type:"number[]",defaultValue:[1,1,1,1]},{tfName:"fused_ops",name:"fusedOps",type:"string[]",defaultValue:[]},{tfName:"epsilon",name:"epsilon",type:"number",defaultValue:1e-4},{tfName:"leakyrelu_alpha",name:"leakyreluAlpha",type:"number",defaultValue:.2}]},{tfOpName:"Conv2DBackpropInput",category:"convolution",inputs:[{start:2,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"},{start:0,name:"outputShape",type:"number[]"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:!0},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[]},{tfName:"dilations",name:"dilations",type:"number[]",notSupported:!0}]},{tfOpName:"DepthwiseConv2d",category:"convolution",inputs:[{start:0,name:"input",type:"tensor"},{start:1,name:"filter",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NHWC"},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[]},{tfName:"dilations",name:"dilations",type:"number[]"}]},{tfOpName:"DepthwiseConv2dNative",category:"convolution",inputs:[{start:0,name:"input",type:"tensor"},{start:1,name:"filter",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NHWC"},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[]},{tfName:"dilations",name:"dilations",type:"number[]"}]},{tfOpName:"FusedDepthwiseConv2dNative",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"},{start:2,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"num_args",name:"numArgs",type:"number"},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0},{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NHWC"},{tfName:"dilations",name:"dilations",type:"number[]",defaultValue:[1,1,1,1]},{tfName:"fused_ops",name:"fusedOps",type:"string[]",defaultValue:[]},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[]}]},{tfOpName:"Conv3D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NHWC"},{tfName:"dilations",name:"dilations",type:"number[]"}]},{tfOpName:"Dilation2D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"rates",name:"dilations",type:"number[]"},{tfName:"padding",name:"pad",type:"string"}]}],C4={};Xe(C4,{json:()=>SP});var SP=[{tfOpName:"Fill",category:"creation",inputs:[{start:0,name:"shape",type:"number[]"},{start:1,name:"value",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"LinSpace",category:"creation",inputs:[{start:0,name:"start",type:"number"},{start:1,name:"stop",type:"number"},{start:2,name:"num",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"OneHot",category:"creation",inputs:[{start:0,name:"indices",type:"tensor"},{start:1,name:"depth",type:"number"},{start:2,name:"onValue",type:"number",defaultValue:1},{start:3,name:"offValue",type:"number",defaultValue:0}],attrs:[{tfName:"axis",name:"axis",type:"number",notSupported:!0},{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"Ones",category:"creation",inputs:[{start:0,name:"shape",type:"number[]"}],attrs:[{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"OnesLike",category:"creation",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"dtype",name:"dtype",type:"dtype"}]},{tfOpName:"RandomStandardNormal",category:"creation",inputs:[{start:0,name:"shape",type:"number[]"}],attrs:[{tfName:"seed",name:"seed",type:"number",defaultValue:0},{tfName:"seed2",name:"seed2",type:"number",defaultValue:0,notSupported:!0},{tfName:"dtype",name:"dtype",type:"dtype"},{tfName:"T",name:"T",type:"number",notSupported:!0}]},{tfOpName:"RandomUniform",category:"creation",inputs:[{start:0,name:"shape",type:"number[]"}],attrs:[{tfName:"minval",name:"minval",type:"number",defaultValue:0},{tfName:"maxval",name:"maxval",type:"number",defaultValue:1},{tfName:"dtype",name:"dtype",type:"dtype"},{tfName:"seed",name:"seed",type:"number",defaultValue:0},{tfName:"seed2",name:"seed2",type:"number",defaultValue:0,notSupported:!0},{tfName:"T",name:"T",type:"number",notSupported:!0}]},{tfOpName:"Range",category:"creation",inputs:[{start:0,name:"start",type:"number"},{start:1,name:"stop",type:"number"},{start:2,name:"step",type:"number",defaultValue:0}],attrs:[{tfName:"Tidx",name:"dtype",type:"dtype"}]},{tfOpName:"TruncatedNormal",category:"creation",inputs:[{start:0,name:"shape",type:"number[]"}],attrs:[{tfName:"means",name:"mean",type:"number",defaultValue:0},{tfName:"stddev",name:"stdDev",type:"number",defaultValue:1},{tfName:"seed",name:"seed",type:"number"},{tfName:"seed2",name:"seed2",type:"number",defaultValue:0,notSupported:!0},{tfName:"dtype",name:"dtype",type:"dtype"},{tfName:"T",name:"T",type:"number",notSupported:!0}]},{tfOpName:"Zeros",category:"creation",inputs:[{start:0,name:"shape",type:"number[]"}],attrs:[{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"ZerosLike",category:"creation",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"Multinomial",category:"creation",inputs:[{start:0,name:"logits",type:"tensor"},{start:1,name:"numSamples",type:"number"}],attrs:[{tfName:"seed",name:"seed",type:"number"},{tfName:"seed2",name:"seed2",type:"number"},{tfName:"T",name:"dtype",type:"dtype"},{tfName:"output_dtype",name:"output_dtype",type:"dtype"}]}],N4={};Xe(N4,{json:()=>TP});var TP=[{tfOpName:"NonMaxSuppressionV2",category:"dynamic",inputs:[{start:0,name:"boxes",type:"tensor"},{start:1,name:"scores",type:"tensor"},{start:2,name:"maxOutputSize",type:"number"},{start:3,name:"iouThreshold",type:"number"}]},{tfOpName:"NonMaxSuppressionV3",category:"dynamic",inputs:[{start:0,name:"boxes",type:"tensor"},{start:1,name:"scores",type:"tensor"},{start:2,name:"maxOutputSize",type:"number"},{start:3,name:"iouThreshold",type:"number"},{start:4,name:"scoreThreshold",type:"number"}]},{tfOpName:"NonMaxSuppressionV4",category:"dynamic",inputs:[{start:0,name:"boxes",type:"tensor"},{start:1,name:"scores",type:"tensor"},{start:2,name:"maxOutputSize",type:"number"},{start:3,name:"iouThreshold",type:"number"},{start:4,name:"scoreThreshold",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0},{tfName:"T_threshold",name:"threshold",type:"dtype",notSupported:!0},{tfName:"pad_to_max_output_size",name:"padToMaxOutputSize",type:"bool"}]},{tfOpName:"NonMaxSuppressionV5",category:"dynamic",inputs:[{start:0,name:"boxes",type:"tensor"},{start:1,name:"scores",type:"tensor"},{start:2,name:"maxOutputSize",type:"number"},{start:3,name:"iouThreshold",type:"number"},{start:4,name:"scoreThreshold",type:"number"},{start:5,name:"softNmsSigma",type:"number"}]},{tfOpName:"Where",category:"dynamic",inputs:[{start:0,name:"condition",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"ListDiff",category:"dynamic",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"y",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]}],E4={};Xe(E4,{json:()=>CP});var CP=[{tfOpName:"LowerBound",category:"evaluation",inputs:[{start:0,name:"sortedSequence",type:"tensor"},{start:1,name:"values",type:"tensor"}]},{tfOpName:"TopKV2",category:"evaluation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"k",type:"number"}],attrs:[{tfName:"sorted",name:"sorted",type:"bool"}]},{tfOpName:"UpperBound",category:"evaluation",inputs:[{start:0,name:"sortedSequence",type:"tensor"},{start:1,name:"values",type:"tensor"}]},{tfOpName:"Unique",category:"evaluation",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"UniqueV2",category:"evaluation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number"}]}],R4={};Xe(R4,{json:()=>NP});var NP=[{tfOpName:"PlaceholderWithDefault",category:"graph",inputs:[{start:0,name:"default",type:"tensor"}],attrs:[{tfName:"shape",name:"shape",type:"shape"},{tfName:"dtype",name:"dtype",type:"dtype"}]},{tfOpName:"Placeholder",category:"graph",attrs:[{tfName:"shape",name:"shape",type:"shape"},{tfName:"dtype",name:"dtype",type:"dtype"}]},{tfOpName:"Const",category:"graph"},{tfOpName:"Identity",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"IdentityN",category:"graph",inputs:[{start:0,end:0,name:"x",type:"tensors"}]},{tfOpName:"Snapshot",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"Rank",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"Size",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"Shape",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"ShapeN",category:"graph",inputs:[{start:0,end:0,name:"x",type:"tensors"}]},{tfOpName:"Print",category:"graph",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"data",type:"tensors"}],attrs:[{tfName:"message",name:"message",type:"string"},{tfName:"first_n",name:"firstN",type:"number",notSupported:!0},{tfName:"summarize",name:"summarize",type:"number",defaultValue:3}]},{tfOpName:"NoOp",category:"graph",inputs:[]},{tfOpName:"StopGradient",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"FakeQuantWithMinMaxVars",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"min",name:"min",type:"number"},{tfName:"max",name:"max",type:"number"}]}],M4={};Xe(M4,{json:()=>EP});var EP=[{tfOpName:"HashTable",category:"hash_table",inputs:[],attrs:[{tfName:"shared_name",name:"sharedName",type:"string"},{tfName:"use_node_name_sharing",name:"useNodeNameSharing",type:"bool"},{tfName:"key_dtype",name:"keyDType",type:"dtype"},{tfName:"value_dtype",name:"valueDType",type:"dtype"}]},{tfOpName:"HashTableV2",category:"hash_table",inputs:[],attrs:[{tfName:"shared_name",name:"sharedName",type:"string"},{tfName:"use_node_name_sharing",name:"useNodeNameSharing",type:"bool"},{tfName:"key_dtype",name:"keyDType",type:"dtype"},{tfName:"value_dtype",name:"valueDType",type:"dtype"}]},{tfOpName:"LookupTableImport",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"},{start:1,name:"keys",type:"tensor"},{start:2,name:"values",type:"tensor"}],attrs:[{tfName:"Tin",name:"tIn",type:"dtype",notSupported:!0},{tfName:"Tout",name:"tOut",type:"dtype",notSupported:!0}]},{tfOpName:"LookupTableImportV2",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"},{start:1,name:"keys",type:"tensor"},{start:2,name:"values",type:"tensor"}],attrs:[{tfName:"Tin",name:"tIn",type:"dtype",notSupported:!0},{tfName:"Tout",name:"tOut",type:"dtype",notSupported:!0}]},{tfOpName:"LookupTableFind",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"},{start:1,name:"keys",type:"tensor"},{start:2,name:"defaultValue",type:"tensor"}],attrs:[{tfName:"Tin",name:"tIn",type:"dtype",notSupported:!0},{tfName:"Tout",name:"tOut",type:"dtype",notSupported:!0}]},{tfOpName:"LookupTableFindV2",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"},{start:1,name:"keys",type:"tensor"},{start:2,name:"defaultValue",type:"tensor"}],attrs:[{tfName:"Tin",name:"tIn",type:"dtype",notSupported:!0},{tfName:"Tout",name:"tOut",type:"dtype",notSupported:!0}]},{tfOpName:"LookupTableSize",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"}]},{tfOpName:"LookupTableSizeV2",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"}]},{tfOpName:"InitializeTable",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"},{start:1,name:"keys",type:"tensor"},{start:2,name:"values",type:"tensor"}]},{tfOpName:"InitializeTableV2",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"},{start:1,name:"keys",type:"tensor"},{start:2,name:"values",type:"tensor"}]}],$4={};Xe($4,{json:()=>RP});var RP=[{tfOpName:"ResizeBilinear",category:"image",inputs:[{start:0,name:"images",type:"tensor"},{start:1,name:"size",type:"number[]"}],attrs:[{tfName:"align_corners",name:"alignCorners",type:"bool"},{tfName:"half_pixel_centers",name:"halfPixelCenters",type:"bool"},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"ResizeNearestNeighbor",category:"image",inputs:[{start:0,name:"images",type:"tensor"},{start:1,name:"size",type:"number[]"}],attrs:[{tfName:"align_corners",name:"alignCorners",type:"bool"},{tfName:"half_pixel_centers",name:"halfPixelCenters",type:"bool"},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"CropAndResize",category:"image",inputs:[{start:0,name:"image",type:"tensor"},{start:1,name:"boxes",type:"tensor"},{start:2,name:"boxInd",type:"tensor"},{start:3,name:"cropSize",type:"number[]"}],attrs:[{tfName:"method",name:"method",type:"string"},{tfName:"extrapolation_value",name:"extrapolationValue",type:"number"}]},{tfOpName:"ImageProjectiveTransformV3",category:"image",inputs:[{start:0,name:"images",type:"tensor"},{start:1,name:"transforms",type:"tensor"},{start:2,name:"outputShape",type:"number[]"},{start:3,name:"fillValue",type:"number"}],attrs:[{tfName:"interpolation",name:"interpolation",type:"string"},{tfName:"fill_mode",name:"fillMode",type:"string"}]}],_4={};Xe(_4,{json:()=>MP});var MP=[{tfOpName:"Equal",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"NotEqual",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Greater",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"GreaterEqual",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Less",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"LessEqual",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"LogicalAnd",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"LogicalNot",category:"logical",inputs:[{start:0,name:"a",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"LogicalOr",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Select",category:"logical",inputs:[{start:0,name:"condition",type:"tensor"},{start:1,name:"a",type:"tensor"},{start:2,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"SelectV2",category:"logical",inputs:[{start:0,name:"condition",type:"tensor"},{start:1,name:"a",type:"tensor"},{start:2,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]}],P4={};Xe(P4,{json:()=>$P});var $P=[{tfOpName:"_FusedMatMul",category:"matrices",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"},{start:2,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"num_args",name:"numArgs",type:"number"},{tfName:"fused_ops",name:"fusedOps",type:"string[]",defaultValue:[]},{tfName:"epsilon",name:"epsilon",type:"number",defaultValue:1e-4},{tfName:"transpose_a",name:"transposeA",type:"bool",defaultValue:!1},{tfName:"transpose_b",name:"transposeB",type:"bool",defaultValue:!1},{tfName:"leakyrelu_alpha",name:"leakyreluAlpha",type:"number",defaultValue:.2},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"MatMul",category:"matrices",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"transpose_a",name:"transposeA",type:"bool",defaultValue:!1},{tfName:"transpose_b",name:"transposeB",type:"bool",defaultValue:!1},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"BatchMatMul",category:"matrices",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"adj_x",name:"transposeA",type:"bool",defaultValue:!1},{tfName:"adj_y",name:"transposeB",type:"bool",defaultValue:!1},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"BatchMatMulV2",category:"matrices",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"adj_x",name:"transposeA",type:"bool",defaultValue:!1},{tfName:"adj_y",name:"transposeB",type:"bool",defaultValue:!1},{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Transpose",category:"matrices",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"perm",type:"number[]"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"Einsum",category:"matrices",inputs:[{start:0,end:0,name:"tensors",type:"tensors"}],attrs:[{tfName:"equation",name:"equation",type:"string"},{tfName:"N",name:"n",type:"number",defaultValue:2},{tfName:"T",name:"dtype",type:"dtype"}]}],F4={};Xe(F4,{json:()=>_P});var _P=[{tfOpName:"EuclideanNorm",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool",defaultValue:!1}]},{tfOpName:"FusedBatchNorm",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"scale",type:"tensor"},{start:2,name:"offset",type:"tensor"},{start:3,name:"mean",type:"tensor"},{start:4,name:"variance",type:"tensor"}],attrs:[{tfName:"epsilon",name:"epsilon",type:"number",defaultValue:.001},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:!0}]},{tfOpName:"FusedBatchNormV2",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"scale",type:"tensor"},{start:2,name:"offset",type:"tensor"},{start:3,name:"mean",type:"tensor"},{start:4,name:"variance",type:"tensor"}],attrs:[{tfName:"epsilon",name:"epsilon",type:"number",defaultValue:.001},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:!0}]},{tfOpName:"FusedBatchNormV3",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"scale",type:"tensor"},{start:2,name:"offset",type:"tensor"},{start:3,name:"mean",type:"tensor"},{start:4,name:"variance",type:"tensor"}],attrs:[{tfName:"epsilon",name:"epsilon",type:"number",defaultValue:.001},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:!0}]},{tfOpName:"LRN",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"depth_radius",name:"radius",type:"number",defaultValue:5},{tfName:"bias",name:"bias",type:"number",defaultValue:1},{tfName:"alpha",name:"alpha",type:"number",defaultValue:1},{tfName:"beta",name:"beta",type:"number",defaultValue:.5}]},{tfOpName:"Softmax",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"LogSoftmax",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"SparseToDense",category:"normalization",inputs:[{start:0,name:"sparseIndices",type:"tensor"},{start:1,name:"outputShape",type:"number[]"},{start:2,name:"sparseValues",type:"tensor"},{start:3,name:"defaultValue",type:"tensor"}],attrs:[{tfName:"validate_indices",name:"validateIndices",type:"bool",defaultValue:!0,notSupported:!0}]}],O4={};Xe(O4,{json:()=>PP});var PP=[{tfOpName:"Bincount",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"size",type:"number"},{start:2,name:"weights",type:"tensor"}]},{tfOpName:"DenseBincount",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"size",type:"number"},{start:2,name:"weights",type:"tensor"}],attrs:[{tfName:"binary_output",name:"binaryOutput",type:"bool"}]},{tfOpName:"Max",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"Mean",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"Min",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"Sum",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"All",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"Any",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"ArgMax",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number"}]},{tfOpName:"ArgMin",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number"}]},{tfOpName:"Prod",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"Cumprod",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number"}],attrs:[{tfName:"exclusive",name:"exclusive",type:"bool"},{tfName:"reverse",name:"reverse",type:"bool"}]},{tfOpName:"Cumsum",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number"}],attrs:[{tfName:"exclusive",name:"exclusive",type:"bool"},{tfName:"reverse",name:"reverse",type:"bool"}]}],D4={};Xe(D4,{json:()=>FP});var FP=[{tfOpName:"ConcatV2",category:"slice_join",inputs:[{start:0,end:-1,name:"tensors",type:"tensors"},{start:-1,name:"axis",type:"number"}],attrs:[{tfName:"N",name:"n",type:"number",defaultValue:2}]},{tfOpName:"Concat",category:"slice_join",inputs:[{start:1,end:0,name:"tensors",type:"tensors"},{start:0,name:"axis",type:"number"}],attrs:[{tfName:"N",name:"n",type:"number",defaultValue:2}]},{tfOpName:"GatherV2",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"indices",type:"tensor"},{start:2,name:"axis",type:"number",defaultValue:0}],attrs:[{tfName:"batch_dims",name:"batchDims",type:"number",defaultValue:0}]},{tfOpName:"Gather",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"indices",type:"tensor"}],attrs:[{tfName:"validate_indices",name:"validateIndices",type:"bool",notSupported:!0}]},{tfOpName:"Reverse",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"dims",type:"bool[]"}]},{tfOpName:"ReverseV2",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}]},{tfOpName:"Slice",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"begin",type:"number[]"},{start:2,name:"size",type:"number[]"}]},{tfOpName:"StridedSlice",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"begin",type:"number[]"},{start:2,name:"end",type:"number[]"},{start:3,name:"strides",type:"number[]"}],attrs:[{tfName:"begin_mask",name:"beginMask",type:"number",defaultValue:0},{tfName:"end_mask",name:"endMask",type:"number",defaultValue:0},{tfName:"new_axis_mask",name:"newAxisMask",type:"number",defaultValue:0},{tfName:"ellipsis_mask",name:"ellipsisMask",type:"number",defaultValue:0},{tfName:"shrink_axis_mask",name:"shrinkAxisMask",type:"number",defaultValue:0}]},{tfOpName:"Pack",category:"slice_join",inputs:[{start:0,end:0,name:"tensors",type:"tensors"}],attrs:[{tfName:"axis",name:"axis",type:"number",defaultValue:0}]},{tfOpName:"Unpack",category:"slice_join",inputs:[{start:0,name:"tensor",type:"tensor"}],attrs:[{tfName:"axis",name:"axis",type:"number",defaultValue:0},{tfName:"num",name:"num",type:"number",defaultValue:0,notSupported:!0}]},{tfOpName:"Tile",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"reps",type:"number[]"}]},{tfOpName:"Split",category:"slice_join",inputs:[{start:0,name:"axis",type:"number",defaultValue:0},{start:1,name:"x",type:"tensor"}],attrs:[{tfName:"num_split",name:"numOrSizeSplits",type:"number",defaultValue:1}]},{tfOpName:"SplitV",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"numOrSizeSplits",type:"number[]"},{start:2,name:"axis",type:"number",defaultValue:0}]},{tfOpName:"ScatterNd",category:"slice_join",inputs:[{start:0,name:"indices",type:"tensor"},{start:1,name:"values",type:"tensor"},{start:2,name:"shape",type:"number[]"}]},{tfOpName:"GatherNd",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"indices",type:"tensor"}]},{tfOpName:"SparseToDense",category:"slice_join",inputs:[{start:0,name:"sparseIndices",type:"tensor"},{start:1,name:"outputShape",type:"number[]"},{start:2,name:"sparseValues",type:"tensor"},{start:3,name:"defaultValue",type:"tensor"}],attrs:[{tfName:"validate_indices",name:"validateIndices",type:"bool",defaultValue:!1,notSupported:!0}]}],z4={};Xe(z4,{json:()=>OP});var OP=[{tfOpName:"SparseFillEmptyRows",category:"sparse",inputs:[{start:0,name:"indices",type:"tensor"},{start:1,name:"values",type:"tensor"},{start:2,name:"denseShape",type:"tensor"},{start:3,name:"defaultValue",type:"tensor"}]},{tfOpName:"SparseReshape",category:"sparse",inputs:[{start:0,name:"inputIndices",type:"tensor"},{start:1,name:"inputShape",type:"tensor"},{start:2,name:"newShape",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:!0}]},{tfOpName:"SparseSegmentMean",category:"sparse",inputs:[{start:0,name:"data",type:"tensor"},{start:1,name:"indices",type:"tensor"},{start:2,name:"segmentIds",type:"tensor"}]},{tfOpName:"SparseSegmentSum",category:"sparse",inputs:[{start:0,name:"data",type:"tensor"},{start:1,name:"indices",type:"tensor"},{start:2,name:"segmentIds",type:"tensor"}]}],L4={};Xe(L4,{json:()=>DP});var DP=[{tfOpName:"FFT",category:"spectral",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"IFFT",category:"spectral",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"RFFT",category:"spectral",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"fft_length",type:"number",notSupported:!0}]},{tfOpName:"IRFFT",category:"spectral",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"fft_length",type:"number",notSupported:!0}]}],B4={};Xe(B4,{json:()=>zP});var zP=[{tfOpName:"StringNGrams",category:"string",inputs:[{start:0,name:"data",type:"tensor"},{start:1,name:"dataSplits",type:"tensor"}],attrs:[{tfName:"separator",name:"separator",type:"string"},{tfName:"ngram_widths",name:"nGramWidths",type:"number[]"},{tfName:"left_pad",name:"leftPad",type:"string"},{tfName:"right_pad",name:"rightPad",type:"string"},{tfName:"pad_width",name:"padWidth",type:"number"},{tfName:"preserve_short_sequences",name:"preserveShortSequences",type:"bool"}],outputs:["ngrams","ngrams_splits"]},{tfOpName:"StringSplit",category:"string",inputs:[{start:0,name:"input",type:"tensor"},{start:1,name:"delimiter",type:"tensor"}],attrs:[{tfName:"skip_empty",name:"skipEmpty",type:"bool"}],outputs:["indices","values","shape"]},{tfOpName:"StringToHashBucketFast",category:"string",inputs:[{start:0,name:"input",type:"tensor"}],attrs:[{tfName:"num_buckets",name:"numBuckets",type:"number"}]}],W4={};Xe(W4,{json:()=>LP});var LP=[{tfOpName:"Cast",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"SrcT",name:"sdtype",type:"dtype",notSupported:!0},{tfName:"DstT",name:"dtype",type:"dtype"}]},{tfOpName:"ExpandDims",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number"}]},{tfOpName:"MirrorPad",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"padding",type:"number[]"}],attrs:[{tfName:"mode",name:"mode",type:"string"}]},{tfOpName:"Pad",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"padding",type:"number[]"}],attrs:[{tfName:"constant_value",name:"constantValue",type:"number",defaultValue:0}]},{tfOpName:"PadV2",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"padding",type:"number[]"},{start:2,name:"constantValue",type:"number",defaultValue:0}]},{tfOpName:"Reshape",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"shape",type:"number[]"}]},{tfOpName:"Squeeze",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"axis",tfDeprecatedName:"squeeze_dims",name:"axis",type:"number[]"}]},{tfOpName:"SpaceToBatchND",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"blockShape",type:"number[]"},{start:2,name:"paddings",type:"number[]"}]},{tfOpName:"BatchToSpaceND",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"blockShape",type:"number[]"},{start:2,name:"crops",type:"number[]"}]},{tfOpName:"DepthToSpace",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"block_size",name:"blockSize",type:"number"},{tfName:"data_format",name:"dataFormat",type:"string"}]},{tfOpName:"BroadcastTo",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"shape",type:"number[]"}],attrs:[]},{tfOpName:"BroadcastArgs",category:"transformation",inputs:[{start:0,name:"s0",type:"tensor"},{start:1,name:"s1",type:"tensor"}],attrs:[]}],Q5=class{constructor(){let e=[k4,I4,S4,T4,C4,N4,E4,R4,M4,$4,_4,P4,F4,O4,D4,z4,L4,B4,W4],t=[].concat(...e.map(a=>a.json));this.opMappers=t.reduce((a,n)=>(a[n.tfOpName]=n,a),{})}static get Instance(){return this._instance||(this._instance=new this)}transformGraph(e,t={}){let a=e.node,n=[],r=[],s=[],i=a.reduce((f,m)=>(f[m.name]=this.mapNode(m),m.op.startsWith("Placeholder")?n.push(f[m.name]):m.op==="Const"?r.push(f[m.name]):(m.input==null||m.input.length===0)&&s.push(f[m.name]),f),{}),o=[],l=[],u={},p={};t!=null&&(u=this.mapSignatureEntries(t.inputs),p=this.mapSignatureEntries(t.outputs));let c=Object.keys(i);c.forEach(f=>{let m=i[f];m.inputNames.forEach((g,x)=>{let[A,,y]=mr(g),b=i[A];if(b.outputs!=null){let w=b.outputs.indexOf(y);if(w!==-1){let S=`${A}:${w}`;m.inputNames[x]=S}}m.inputs.push(b),b.children.push(m)})}),Object.keys(p).length===0?c.forEach(f=>{let m=i[f];m.children.length===0&&l.push(m)}):Object.keys(p).forEach(f=>{let[m]=mr(f),g=i[m];g!=null&&(g.signatureKey=p[f],l.push(g))}),Object.keys(u).length>0?Object.keys(u).forEach(f=>{let[m]=mr(f),g=i[m];g&&(g.signatureKey=u[f],o.push(g))}):o=n;let d={};e.library!=null&&e.library.function!=null&&(d=e.library.function.reduce((f,m)=>(f[m.signature.name]=this.mapFunction(m),f),{}));let h={nodes:i,inputs:o,outputs:l,weights:r,placeholders:n,signature:t,functions:d};return s.length>0&&(h.initNodes=s),h}mapSignatureEntries(e){return Object.keys(e||{}).reduce((t,a)=>(t[e[a].name]=a,t),{})}mapNode(e){let t=w4(e.op)||this.opMappers[e.op]||{};e.attr==null&&(e.attr={});let a={name:e.name,op:e.op,category:t.category,inputNames:(e.input||[]).map(n=>n.startsWith("^")?n.slice(1):n),inputs:[],children:[],inputParams:{},attrParams:{},rawAttrs:e.attr,outputs:t.outputs};return t.inputs!=null&&(a.inputParams=t.inputs.reduce((n,r)=>(n[r.name]={type:r.type,inputIndexStart:r.start,inputIndexEnd:r.end},n),{})),t.attrs!=null&&(a.attrParams=t.attrs.reduce((n,r)=>{let s=r.type,i;switch(r.type){case"string":i=o1(e.attr,r.tfName,r.defaultValue),i===void 0&&!!r.tfDeprecatedName&&(i=o1(e.attr,r.tfDeprecatedName,r.defaultValue));break;case"string[]":i=f1(e.attr,r.tfName,r.defaultValue),i===void 0&&!!r.tfDeprecatedName&&(i=f1(e.attr,r.tfDeprecatedName,r.defaultValue));break;case"number":i=u1(e.attr,r.tfName,r.defaultValue||0),i===void 0&&!!r.tfDeprecatedName&&(i=u1(e.attr,r.tfDeprecatedName,r.defaultValue));break;case"number[]":i=h1(e.attr,r.tfName,r.defaultValue),i===void 0&&!!r.tfDeprecatedName&&(i=h1(e.attr,r.tfDeprecatedName,r.defaultValue));break;case"bool":i=l1(e.attr,r.tfName,r.defaultValue),i===void 0&&!!r.tfDeprecatedName&&(i=l1(e.attr,r.tfDeprecatedName,r.defaultValue));break;case"bool[]":i=g1(e.attr,r.tfName,r.defaultValue),i===void 0&&!!r.tfDeprecatedName&&(i=g1(e.attr,r.tfDeprecatedName,r.defaultValue));break;case"shape":i=c1(e.attr,r.tfName,r.defaultValue),i===void 0&&!!r.tfDeprecatedName&&(i=c1(e.attr,r.tfDeprecatedName,r.defaultValue));break;case"shape[]":i=m1(e.attr,r.tfName,r.defaultValue),i===void 0&&!!r.tfDeprecatedName&&(i=m1(e.attr,r.tfDeprecatedName,r.defaultValue));break;case"dtype":i=d1(e.attr,r.tfName,r.defaultValue),i===void 0&&!!r.tfDeprecatedName&&(i=d1(e.attr,r.tfDeprecatedName,r.defaultValue));break;case"dtype[]":i=p1(e.attr,r.tfName,r.defaultValue),i===void 0&&!!r.tfDeprecatedName&&(i=p1(e.attr,r.tfDeprecatedName,r.defaultValue));break;case"func":i=ex(e.attr,r.tfName,r.defaultValue),i===void 0&&!!r.tfDeprecatedName&&(i=ex(e.attr,r.tfDeprecatedName,r.defaultValue));break;case"tensor":case"tensors":break;default:throw new Error(`Unsupported param type: ${r.type} for op: ${e.op}`)}return n[r.name]={value:i,type:s},n},{})),a}mapFunction(e){let t=e.nodeDef,a=[],n=[],r={};t!=null&&(r=t.reduce((u,p)=>(u[p.name]=this.mapNode(p),p.op==="Const"&&n.push(u[p.name]),u),{}));let s=[],i=[];e.signature.inputArg.forEach(u=>{let[p]=mr(u.name),c={name:p,op:"Placeholder",inputs:[],inputNames:[],category:"graph",inputParams:{},attrParams:{dtype:{value:n3(u.type),type:"dtype"}},children:[]};c.signatureKey=u.name,s.push(c),r[p]=c}),Object.keys(r).forEach(u=>{let p=r[u];p.inputNames.forEach((c,d)=>{let[h,,f]=mr(c),m=r[h];if(m.outputs!=null){let g=m.outputs.indexOf(f);if(g!==-1){let x=`${h}:${g}`;p.inputNames[d]=x}}p.inputs.push(m),m.children.push(p)})});let o=e.ret;e.signature.outputArg.forEach(u=>{let[p,c]=mr(o[u.name]),d=r[p];d!=null&&(d.defaultOutput=c,i.push(d))});let l=this.mapArgsToSignature(e);return{nodes:r,inputs:s,outputs:i,weights:n,placeholders:a,signature:l}}mapArgsToSignature(e){return{methodName:e.signature.name,inputs:e.signature.inputArg.reduce((t,a)=>(t[a.name]=this.mapArgToTensorInfo(a),t),{}),outputs:e.signature.outputArg.reduce((t,a)=>(t[a.name]=this.mapArgToTensorInfo(a,e.ret),t),{})}}mapArgToTensorInfo(e,t){let a=e.name;return t!=null&&(a=t[a]),{name:a,dtype:e.type}}};function BP(e){let t=W().global;if(typeof t.atob!="undefined")return t.atob(e);if(typeof Buffer!="undefined")return new Buffer(e,"base64").toString();throw new Error("Unable to decode base64 in this environment. Missing built-in atob() or Buffer()")}function V4(e,t){let a=Array.isArray(e)?String.fromCharCode.apply(null,e):BP(e);return t?a:a.toLowerCase()}function o1(e,t,a,n=!1){let r=e[t];return r!=null?V4(r.s,n):a}function l1(e,t,a){let n=e[t];return n?n.b:a}function u1(e,t,a){let n=e[t]||{},r=n.i!=null?n.i:n.f!=null?n.f:a;return typeof r=="number"?r:parseInt(r,10)}function n3(e){switch(typeof e=="string"&&(e=wn[e]),e){case wn.DT_FLOAT:case wn.DT_HALF:return"float32";case wn.DT_INT32:case wn.DT_INT64:case wn.DT_INT8:case wn.DT_UINT8:return"int32";case wn.DT_BOOL:return"bool";case wn.DT_DOUBLE:return"float32";case wn.DT_STRING:return"string";default:return null}}function ex(e,t,a){let n=e[t];return n&&n.func?n.func.name:a}function d1(e,t,a){let n=e[t];return n&&n.type?n3(n.type):a}function p1(e,t,a){let n=e[t];return n&&n.list&&n.list.type?n.list.type.map(r=>n3(r)):a}function U4(e){if(!e.unknownRank)return e.dim!=null?e.dim.map(t=>typeof t.size=="number"?t.size:parseInt(t.size,10)):[]}function c1(e,t,a){let n=e[t];return n&&n.shape?U4(n.shape):a}function h1(e,t,a){let n=e[t];return n?((n.list.f&&n.list.f.length?n.list.f:n.list.i)||[]).map(r=>typeof r=="number"?r:parseInt(r,10)):a}function f1(e,t,a,n=!1){let r=e[t];return r&&r.list&&r.list.s?r.list.s.map(s=>V4(s,n)):a}function m1(e,t,a){let n=e[t];return n&&n.list&&n.list.shape?n.list.shape.map(r=>U4(r)):a}function g1(e,t,a){let n=e[t];return n&&n.list&&n.list.b?n.list.b:a}var WP=class{constructor(e,t,a){this.node=e,this.tensorMap=t,this.context=a,this.inputs=[],this.attrs={},this.inputs=e.inputNames.map(n=>this.getInput(n)),e.rawAttrs!=null&&(this.attrs=Object.keys(e.rawAttrs).reduce((n,r)=>(n[r]=this.getAttr(r),n),{}))}getInput(e){return ba(e,this.tensorMap,this.context)}getAttr(e,t){let a=this.node.rawAttrs[e];if(a.tensor!=null)return ba(e,this.tensorMap,this.context);if(a.i!=null||a.f!=null)return u1(this.node.rawAttrs,e,t);if(a.s!=null)return o1(this.node.rawAttrs,e,t);if(a.b!=null)return l1(this.node.rawAttrs,e,t);if(a.shape!=null)return c1(this.node.rawAttrs,e,t);if(a.type!=null)return d1(this.node.rawAttrs,e,t);if(a.list!=null){if(a.list.i!=null||a.list.f!=null)return h1(this.node.rawAttrs,e,t);if(a.list.s!=null)return f1(this.node.rawAttrs,e,t);if(a.list.shape!=null)return m1(this.node.rawAttrs,e,t);if(a.list.b!=null)return g1(this.node.rawAttrs,e,t);if(a.list.type!=null)return p1(this.node.rawAttrs,e,t)}return t}},Zt={};Xe(Zt,{OP_SCOPE_SUFFIX:()=>e2,abs:()=>qa,acos:()=>oy,acosh:()=>ly,add:()=>be,addN:()=>ch,all:()=>uy,any:()=>dy,argMax:()=>ar,argMin:()=>py,asin:()=>cy,asinh:()=>hy,atan:()=>fy,atan2:()=>my,atanh:()=>gy,avgPool:()=>b2,avgPool3d:()=>by,basicLSTMCell:()=>vy,batchNorm:()=>Qd,batchNorm2d:()=>wy,batchNorm3d:()=>ky,batchNorm4d:()=>Iy,batchToSpaceND:()=>v2,bincount:()=>w2,booleanMaskAsync:()=>a4,broadcastArgs:()=>Sy,broadcastTo:()=>sl,buffer:()=>Me,cast:()=>He,ceil:()=>Ty,clipByValue:()=>Cy,clone:()=>wa,complex:()=>br,concat:()=>at,concat1d:()=>Ny,concat2d:()=>ru,concat3d:()=>Ey,concat4d:()=>Ry,conv1d:()=>My,conv2d:()=>ep,conv2dTranspose:()=>_y,conv3d:()=>Py,conv3dTranspose:()=>Fy,cos:()=>Oy,cosh:()=>Dy,cosineWindow:()=>vh,cumprod:()=>zy,cumsum:()=>Ly,denseBincount:()=>By,depthToSpace:()=>Wy,depthwiseConv2d:()=>hh,diag:()=>Vy,dilation2d:()=>Uy,div:()=>me,divNoNan:()=>Gy,dot:()=>Hy,dropout:()=>o4,einsum:()=>jy,elu:()=>I2,enclosingPowerOfTwo:()=>J2,equal:()=>k2,erf:()=>qy,euclideanNorm:()=>Zy,exp:()=>Zr,expandDims:()=>Gt,expm1:()=>Yy,eye:()=>T2,fft:()=>yh,fill:()=>nr,floor:()=>C2,floorDiv:()=>Yd,fused:()=>Q2,gather:()=>N2,gatherND:()=>i4,greater:()=>np,greaterEqual:()=>E2,ifft:()=>hd,imag:()=>Zd,image:()=>ge,inTopKAsync:()=>l4,irfft:()=>X2,isFinite:()=>Jy,isInf:()=>Qy,isNaN:()=>eb,leakyRelu:()=>R2,less:()=>tb,lessEqual:()=>fh,linalg:()=>g4,linspace:()=>ab,localResponseNormalization:()=>nb,log:()=>cl,log1p:()=>M2,logSigmoid:()=>sb,logSoftmax:()=>ib,logSumExp:()=>_2,logicalAnd:()=>pd,logicalNot:()=>P2,logicalOr:()=>F2,logicalXor:()=>ob,losses:()=>x4,lowerBound:()=>lb,matMul:()=>st,max:()=>pa,maxPool:()=>O2,maxPool3d:()=>ub,maxPoolWithArgmax:()=>db,maximum:()=>D2,mean:()=>cd,meshgrid:()=>pb,min:()=>Kr,minimum:()=>z2,mirrorPad:()=>cb,mod:()=>su,moments:()=>hb,movingAverage:()=>n4,mul:()=>ae,multiRNNCell:()=>fb,multinomial:()=>mb,neg:()=>Xn,norm:()=>ap,notEqual:()=>L2,oneHot:()=>Nc,ones:()=>Wr,onesLike:()=>gb,op:()=>D,outerProduct:()=>xb,pad:()=>rr,pad1d:()=>Ab,pad2d:()=>yb,pad3d:()=>bb,pad4d:()=>vb,pool:()=>wb,pow:()=>pl,prelu:()=>W2,print:()=>r2,prod:()=>kb,raggedGather:()=>Ib,raggedRange:()=>Sb,raggedTensorToTensor:()=>Tb,rand:()=>Cb,randomGamma:()=>Nb,randomNormal:()=>G2,randomStandardNormal:()=>Eb,randomUniform:()=>H2,range:()=>hl,real:()=>dl,reciprocal:()=>Rb,relu:()=>rp,relu6:()=>j2,reshape:()=>J,reverse:()=>Yr,reverse1d:()=>Mb,reverse2d:()=>$b,reverse3d:()=>_b,reverse4d:()=>Pb,rfft:()=>bh,round:()=>q2,rsqrt:()=>Fb,scalar:()=>Fe,scatterND:()=>r4,searchSorted:()=>gh,selu:()=>Ob,separableConv2d:()=>Db,setdiff1dAsync:()=>zb,sigmoid:()=>Da,sign:()=>Lb,signal:()=>m4,sin:()=>Bb,sinh:()=>Wb,slice:()=>Pe,slice1d:()=>Vb,slice2d:()=>Ub,slice3d:()=>sp,slice4d:()=>xh,softmax:()=>Ah,softplus:()=>$2,spaceToBatchND:()=>B2,sparse:()=>A4,sparseToDense:()=>s4,spectral:()=>f4,split:()=>ka,sqrt:()=>Jn,square:()=>In,squaredDifference:()=>K2,squeeze:()=>_e,stack:()=>sa,step:()=>Z2,stridedSlice:()=>Gb,string:()=>y4,sub:()=>fe,sum:()=>tt,tan:()=>Hb,tanh:()=>Rc,tensor:()=>Be,tensor1d:()=>Ht,tensor2d:()=>Kn,tensor3d:()=>p2,tensor4d:()=>jb,tensor5d:()=>qb,tensor6d:()=>Xb,tile:()=>Gr,topk:()=>Kb,transpose:()=>Ws,truncatedNormal:()=>Zb,unique:()=>Yb,unsortedSegmentSum:()=>Jb,unstack:()=>Ta,upperBound:()=>Qb,variable:()=>e4,where:()=>Vs,whereAsync:()=>Y2,zeros:()=>fn,zerosLike:()=>Ka});var VP=(e,t,a,n=Zt)=>{switch(e.op){case"BiasAdd":case"AddV2":case"Add":return[n.add(k("a",e,t,a),k("b",e,t,a))];case"AddN":return[n.addN(k("tensors",e,t,a))];case"FloorMod":case"Mod":return[n.mod(k("a",e,t,a),k("b",e,t,a))];case"Mul":return[n.mul(k("a",e,t,a),k("b",e,t,a))];case"RealDiv":case"Div":return[n.div(k("a",e,t,a),k("b",e,t,a))];case"DivNoNan":return[n.divNoNan(k("a",e,t,a),k("b",e,t,a))];case"FloorDiv":return[n.floorDiv(k("a",e,t,a),k("b",e,t,a))];case"Sub":return[n.sub(k("a",e,t,a),k("b",e,t,a))];case"Minimum":return[n.minimum(k("a",e,t,a),k("b",e,t,a))];case"Maximum":return[n.maximum(k("a",e,t,a),k("b",e,t,a))];case"Pow":return[n.pow(k("a",e,t,a),k("b",e,t,a))];case"SquaredDifference":return[n.squaredDifference(k("a",e,t,a),k("b",e,t,a))];default:throw TypeError(`Node type ${e.op} is not implemented`)}},UP=(e,t,a,n=Zt)=>{switch(e.op){case"Abs":case"ComplexAbs":return[n.abs(k("x",e,t,a))];case"Acos":return[n.acos(k("x",e,t,a))];case"Acosh":return[n.acosh(k("x",e,t,a))];case"Asin":return[n.asin(k("x",e,t,a))];case"Asinh":return[n.asinh(k("x",e,t,a))];case"Atan":return[n.atan(k("x",e,t,a))];case"Atan2":return[n.atan2(k("x",e,t,a),k("y",e,t,a))];case"Atanh":return[n.atanh(k("x",e,t,a))];case"Ceil":return[n.ceil(k("x",e,t,a))];case"Complex":return[n.complex(k("real",e,t,a),k("imag",e,t,a))];case"Cos":return[n.cos(k("x",e,t,a))];case"Cosh":return[n.cosh(k("x",e,t,a))];case"Elu":return[n.elu(k("x",e,t,a))];case"Erf":return[n.erf(k("x",e,t,a))];case"Exp":return[n.exp(k("x",e,t,a))];case"Expm1":return[n.expm1(k("x",e,t,a))];case"Floor":return[n.floor(k("x",e,t,a))];case"Log":return[n.log(k("x",e,t,a))];case"Log1p":return[n.log1p(k("x",e,t,a))];case"Imag":return[n.imag(k("x",e,t,a))];case"Neg":return[n.neg(k("x",e,t,a))];case"Reciprocal":return[n.reciprocal(k("x",e,t,a))];case"Real":return[n.real(k("x",e,t,a))];case"Relu":return[n.relu(k("x",e,t,a))];case"Round":return[n.round(k("x",e,t,a))];case"Selu":return[n.selu(k("x",e,t,a))];case"Sigmoid":return[n.sigmoid(k("x",e,t,a))];case"Sin":return[n.sin(k("x",e,t,a))];case"Sign":return[n.sign(k("x",e,t,a))];case"Sinh":return[n.sinh(k("x",e,t,a))];case"Softplus":return[n.softplus(k("x",e,t,a))];case"Sqrt":return[n.sqrt(k("x",e,t,a))];case"Square":return[n.square(k("x",e,t,a))];case"Tanh":return[n.tanh(k("x",e,t,a))];case"Tan":return[n.tan(k("x",e,t,a))];case"ClipByValue":return[n.clipByValue(k("x",e,t,a),k("clipValueMin",e,t,a),k("clipValueMax",e,t,a))];case"Relu6":return[n.relu6(k("x",e,t,a))];case"Rsqrt":return[n.rsqrt(ba(e.inputNames[0],t,a))];case"Prod":return[n.prod(k("x",e,t,a),k("axes",e,t,a))];case"LeakyRelu":return[n.leakyRelu(k("x",e,t,a),k("alpha",e,t,a))];case"Prelu":return[n.prelu(k("x",e,t,a),k("alpha",e,t,a))];case"IsNan":return[n.isNaN(ba(e.inputNames[0],t,a))];default:throw TypeError(`Node type ${e.op} is not implemented`)}};function kn(e,t,a=""){if(!(typeof e=="number"||typeof t=="number")){v.assert(e.length===t.length,()=>a+` Shapes ${e} and ${t} must match`);for(let n=0;na+` Shapes ${e} and ${t} must match`)}}}function tx(e){return!(typeof e=="number"||e.some(t=>t<0))}function Vu(e,t,a){let n=x1(e,a),r=!tx(n);if(r&&t.length===0)throw new Error(`Tried to calculate elements of an empty list with non-fully-defined elementShape: ${n}`);if(r&&t.forEach(s=>{n=x1(s.shape,n)}),!tx(n))throw new Error(`Non-fully-defined elementShape: ${n}`);return n}function x1(e,t){if(typeof e=="number")return t;if(typeof t=="number")return e;if(e.length!==t.length)throw new Error(`Incompatible ranks during merge: ${e} vs. ${t}`);let a=[];for(let n=0;n=0&&s>=0&&r!==s)throw new Error(`Incompatible shape during merge: ${e} vs. ${t}`);a[n]=r>=0?r:s}return a}var GP=class{constructor(e,t,a,n,r,s,i){this.name=e,this.dtype=t,this.maxSize=a,this.elementShape=n,this.identicalElementShapes=r,this.dynamicSize=s,this.clearAfterRead=i,this.tensors=[],this.closed_=!1,this.idTensor=Fe(0),On(this.idTensor)}get id(){return this.idTensor.id}get closed(){return this.closed_}clearAndClose(e){this.tensors.forEach(t=>{(e==null||!e.has(t.tensor.id))&&t.tensor.dispose()}),this.tensors=[],this.closed_=!0,this.idTensor.dispose()}size(){return this.tensors.length}read(e){if(this.closed_)throw new Error(`TensorArray ${this.name} has already been closed.`);if(e<0||e>=this.size())throw new Error(`Tried to read from index ${e}, but array size is: ${this.size()}`);let t=this.tensors[e];if(t.cleared)throw new Error(`TensorArray ${this.name}: Could not read index ${e} twice because it was cleared after a previous read (perhaps try setting clear_after_read = false?).`);return this.clearAfterRead&&(t.cleared=!0),t.read=!0,t.tensor}readMany(e){return e.map(t=>this.read(t))}write(e,t){if(this.closed_)throw new Error(`TensorArray ${this.name} has already been closed.`);if(e<0||!this.dynamicSize&&e>=this.maxSize)throw new Error(`Tried to write to index ${e}, but array is not resizeable and size is: ${this.maxSize}`);let a=this.tensors[e]||{};if(t.dtype!==this.dtype)throw new Error(`TensorArray ${this.name}: Could not write to TensorArray index ${e}, because the value dtype is ${t.dtype}, but TensorArray dtype is ${this.dtype}.`);if(this.size()===0&&(this.elementShape==null||this.elementShape.length===0)&&(this.elementShape=t.shape),kn(this.elementShape,t.shape,`TensorArray ${this.name}: Could not write to TensorArray index ${e}.`),a.read)throw new Error(`TensorArray ${this.name}: Could not write to TensorArray index ${e}, because it has already been read.`);if(a.written)throw new Error(`TensorArray ${this.name}: Could not write to TensorArray index ${e}, because it has already been written.`);a.tensor=t,On(t),a.written=!0,this.tensors[e]=a}writeMany(e,t){if(e.length!==t.length)throw new Error(`TensorArray ${this.name}: could not write multiple tensors,because the index size: ${e.length} is not the same as tensors size: ${t.length}.`);e.forEach((a,n)=>this.write(a,t[n]))}gather(e,t){if(!!t&&t!==this.dtype)throw new Error(`TensorArray dtype is ${this.dtype} but gather requested dtype ${t}`);if(e)e=e.slice(0,this.size());else{e=[];for(let n=0;n=this.maxSize)throw new Error(`Max index must be < array size (${a} vs. ${this.maxSize})`);this.writeMany(e,Ta(t,0))}split(e,t){if(t.dtype!==this.dtype)throw new Error(`TensorArray dtype is ${this.dtype} but tensor has dtype ${t.dtype}`);let a=0,n=e.map(o=>(a+=o,a));if(a!==t.shape[0])throw new Error(`Expected sum of lengths to be equal to tensor.shape[0], but sum of lengths is ${a}, and tensor's shape is: ${t.shape}`);if(!this.dynamicSize&&e.length!==this.maxSize)throw new Error(`TensorArray's size is not equal to the size of lengths (${this.maxSize} vs. ${e.length}), and the TensorArray is not marked as dynamically resizeable`);let r=a===0?0:t.size/a,s=[];$e(()=>{t=J(t,[1,a,r]);for(let o=0;o{if(a!==r.dtype)throw new Error(`Invalid data types; op elements ${a}, but list elements ${r.dtype}`);kn(t,r.shape,"TensorList shape mismatch: "),On(r)}),this.idTensor=Fe(0),this.maxNumElements=n,On(this.idTensor)}get id(){return this.idTensor.id}copy(){return new fl([...this.tensors],this.elementShape,this.elementDtype)}clearAndClose(e){this.tensors.forEach(t=>{(e==null||!e.has(t.id))&&t.dispose()}),this.tensors.length=0,this.idTensor.dispose()}size(){return this.tensors.length}stack(e,t,a=-1){if(t!==this.elementDtype)throw new Error(`Invalid data types; op elements ${t}, but list elements ${this.elementDtype}`);if(a!==-1&&this.tensors.length!==a)throw new Error(`Operation expected a list with ${a} elements but got a list with ${this.tensors.length} elements.`);kn(e,this.elementShape,"TensorList shape mismatch: ");let n=Vu(this.elementShape,this.tensors,e);return $e(()=>{let r=this.tensors.map(s=>J(s,n));return sa(r,0)})}popBack(e,t){if(t!==this.elementDtype)throw new Error(`Invalid data types; op elements ${t}, but list elements ${this.elementDtype}`);if(this.size()===0)throw new Error("Trying to pop from an empty list.");let a=Vu(this.elementShape,this.tensors,e),n=this.tensors.pop();return n.kept=!1,kn(n.shape,e,"TensorList shape mismatch: "),J(n,a)}pushBack(e){if(e.dtype!==this.elementDtype)throw new Error(`Invalid data types; op elements ${e.dtype}, but list elements ${this.elementDtype}`);if(kn(e.shape,this.elementShape,"TensorList shape mismatch: "),this.maxNumElements===this.size())throw new Error("Trying to push element into a full list.");On(e),this.tensors.push(e)}resize(e){if(e<0)throw new Error(`TensorListResize expects size to be non-negative. Got: ${e}`);if(this.maxNumElements!==-1&&e>this.maxNumElements)throw new Error(`TensorListResize input size ${e} is greater maxNumElement ${this.maxNumElements}.`);let t=new fl([],this.elementShape,this.elementDtype,this.maxNumElements);t.tensors.length=e;for(let a=0;athis.tensors.length)throw new Error(`Trying to access element ${e} in a list with ${this.tensors.length} elements.`);if(this.tensors[e]==null)throw new Error(`element at index ${e} is null.`);kn(this.tensors[e].shape,t,"TensorList shape mismatch: ");let n=Vu(this.elementShape,this.tensors,t);return J(this.tensors[e],n)}setItem(e,t){if(t.dtype!==this.elementDtype)throw new Error(`Invalid data types; op elements ${t.dtype}, but list elements ${this.elementDtype}`);if(e<0||this.maxNumElements!==-1&&e>=this.maxNumElements)throw new Error(`Trying to set element ${e} in a list with max ${this.maxNumElements} elements.`);kn(this.elementShape,t.shape,"TensorList shape mismatch: "),On(t),this.tensors[e]!=null&&(this.tensors[e].kept=!1),this.tensors[e]=t}gather(e,t,a){if(t!==this.elementDtype)throw new Error(`Invalid data types; op elements ${t}, but list elements ${this.elementDtype}`);kn(this.elementShape,a,"TensorList shape mismatch: "),e=e.slice(0,this.size());let n=Vu(this.elementShape,this.tensors,a);return e.length===0?Be([],[0].concat(n)):$e(()=>{let r=e.map(s=>J(this.tensors[s],n));return sa(r,0)})}concat(e,t){if(!!e&&e!==this.elementDtype)throw new Error(`TensorList dtype is ${this.elementDtype} but concat requested dtype ${e}`);kn(this.elementShape,t,"TensorList shape mismatch: ");let a=Vu(this.elementShape,this.tensors,t);return this.size()===0?Be([],[0].concat(a)):$e(()=>{let n=this.tensors.map(r=>J(r,a));return at(n,0)})}};function HP(e,t,a){let n=e.dtype;if(e.shape.length<1)throw new Error(`Tensor must be at least a vector, but saw shape: ${e.shape}`);if(e.dtype!==a)throw new Error(`Invalid data types; op elements ${e.dtype}, but list elements ${a}`);let r=e.shape.slice(1);kn(r,t,"TensorList shape mismatch: ");let s=Ta(e);return new fl(s,t,n)}function jP(e,t,a,n){return new fl([],e,t,n)}function qP(e,t,a,n){if(t.length!==e.shape[0])throw new Error(`Expected len(indices) == tensor.shape[0], but saw: ${t.length} vs. ${e.shape[0]}`);let r=Math.max(...t);if(n!=null&&n!==-1&&r>=n)throw new Error(`Max index must be < array size (${r} vs. ${n})`);let s=new fl([],a,e.dtype,n),i=Ta(e,0);return t.forEach((o,l)=>{s.setItem(o,i[l])}),s}function XP(e,t,a){let n=0,r=t.map(p=>(n+=p,n));if(n!==e.shape[0])throw new Error(`Expected sum of lengths to be equal to tensor.shape[0], but sum of lengths is ${n}, and tensor's shape is: ${e.shape}`);let s=e.shape.slice(1),i=x1(s,a),o=n===0?0:e.size/n,l=$e(()=>{let p=[];e=J(e,[1,n,o]);for(let c=0;c{switch(e.op){case"If":case"StatelessIf":{let n=k("thenBranch",e,t,a),r=k("elseBranch",e,t,a),s=k("cond",e,t,a),i=k("args",e,t,a);return(await s.data())[0]?a.functionMap[n].executeFunctionAsync(i,a.tensorArrayMap,a.tensorListMap):a.functionMap[r].executeFunctionAsync(i,a.tensorArrayMap,a.tensorListMap)}case"While":case"StatelessWhile":{let n=k("body",e,t,a),r=k("cond",e,t,a),s=k("args",e,t,a),i=await a.functionMap[r].executeFunctionAsync(s,a.tensorArrayMap,a.tensorListMap),o=s.map(p=>p.id),l=await i[0].data();i.forEach(p=>{!p.kept&&o.indexOf(p.id)===-1&&p.dispose()});let u=s;for(;l[0];){let p=u;u=await a.functionMap[n].executeFunctionAsync(u,a.tensorArrayMap,a.tensorListMap);let c=u.map(h=>h.id);p.forEach(h=>{!h.kept&&o.indexOf(h.id)===-1&&c.indexOf(h.id)===-1&&h.dispose()});let d=await a.functionMap[r].executeFunctionAsync(u,a.tensorArrayMap,a.tensorListMap);l=await d[0].data(),d.forEach(h=>{!h.kept&&o.indexOf(h.id)===-1&&c.indexOf(h.id)===-1&&h.dispose()})}return u}case"LoopCond":{let n=k("pred",e,t,a);return[gr(n)]}case"Switch":{let n=k("pred",e,t,a),r=k("data",e,t,a);return r.kept||(r=gr(r)),(await n.data())[0]?[void 0,r]:[r,void 0]}case"Merge":{let n=e.inputNames.find(r=>ba(r,t,a)!==void 0);if(n){let r=ba(n,t,a);return[gr(r)]}return}case"Enter":{let n=k("frameName",e,t,a),r=k("tensor",e,t,a);return a.enterFrame(n),[gr(r)]}case"Exit":{let n=k("tensor",e,t,a);return a.exitFrame(),[gr(n)]}case"NextIteration":{let n=k("tensor",e,t,a);return a.nextIteration(),[gr(n)]}case"TensorArrayV3":{let n=k("size",e,t,a),r=k("dtype",e,t,a),s=k("elementShape",e,t,a),i=k("dynamicSize",e,t,a),o=k("clearAfterRead",e,t,a),l=k("identicalElementShapes",e,t,a),u=k("name",e,t,a),p=new GP(u,r,n,s,l,i,o);return a.addTensorArray(p),[p.idTensor,Fe(1)]}case"TensorArrayWriteV3":{let n=k("tensorArrayId",e,t,a),r=k("index",e,t,a),s=k("tensor",e,t,a),i=a.getTensorArray(n.id);return i.write(r,s),[i.idTensor]}case"TensorArrayReadV3":{let n=k("tensorArrayId",e,t,a),r=k("index",e,t,a);return[a.getTensorArray(n.id).read(r)]}case"TensorArrayGatherV3":{let n=k("tensorArrayId",e,t,a),r=k("indices",e,t,a),s=k("dtype",e,t,a);return[a.getTensorArray(n.id).gather(r,s)]}case"TensorArrayScatterV3":{let n=k("tensorArrayId",e,t,a),r=k("indices",e,t,a),s=k("tensor",e,t,a),i=a.getTensorArray(n.id);return i.scatter(r,s),[i.idTensor]}case"TensorArrayConcatV3":{let n=k("tensorArrayId",e,t,a),r=a.getTensorArray(n.id),s=k("dtype",e,t,a);return[r.concat(s)]}case"TensorArraySplitV3":{let n=k("tensorArrayId",e,t,a),r=k("tensor",e,t,a),s=k("lengths",e,t,a),i=a.getTensorArray(n.id);return i.split(s,r),[i.idTensor]}case"TensorArraySizeV3":{let n=k("tensorArrayId",e,t,a),r=a.getTensorArray(n.id);return[Fe(r.size(),"int32")]}case"TensorArrayCloseV3":{let n=k("tensorArrayId",e,t,a),r=a.getTensorArray(n.id);return r.clearAndClose(),[r.idTensor]}case"TensorListSetItem":{let n=k("tensorListId",e,t,a),r=k("index",e,t,a),s=k("tensor",e,t,a),i=a.getTensorList(n.id);return i.setItem(r,s),[i.idTensor]}case"TensorListGetItem":{let n=k("tensorListId",e,t,a),r=k("index",e,t,a),s=k("elementShape",e,t,a),i=k("elementDType",e,t,a);return[a.getTensorList(n.id).getItem(r,s,i)]}case"TensorListScatterV2":case"TensorListScatter":{let n=k("indices",e,t,a),r=k("tensor",e,t,a),s=k("elementShape",e,t,a),i=k("numElements",e,t,a),o=qP(r,n,s,i);return a.addTensorList(o),[o.idTensor]}case"TensorListReserve":case"EmptyTensorList":{let n=k("elementShape",e,t,a),r=k("elementDType",e,t,a),s;e.op==="TensorListReserve"?s="numElements":s="maxNumElements";let i=k(s,e,t,a),o=e.op==="TensorListReserve"?-1:i,l=jP(n,r,i,o);return a.addTensorList(l),[l.idTensor]}case"TensorListGather":{let n=k("tensorListId",e,t,a),r=k("indices",e,t,a),s=k("elementShape",e,t,a),i=k("elementDType",e,t,a);return[a.getTensorList(n.id).gather(r,i,s)]}case"TensorListStack":{let n=k("tensorListId",e,t,a),r=k("elementShape",e,t,a),s=k("elementDType",e,t,a),i=k("numElements",e,t,a);return[a.getTensorList(n.id).stack(r,s,i)]}case"TensorListFromTensor":{let n=k("tensor",e,t,a),r=k("elementShape",e,t,a),s=k("elementDType",e,t,a),i=HP(n,r,s);return a.addTensorList(i),[i.idTensor]}case"TensorListConcat":case"TensorListConcatV2":{let n=k("tensorListId",e,t,a),r=a.getTensorList(n.id),s=k("dtype",e,t,a),i=k("elementShape",e,t,a);return[r.concat(s,i)]}case"TensorListPushBack":{let n=k("tensorListId",e,t,a),r=k("tensor",e,t,a),s=a.getTensorList(n.id);return s.pushBack(r),[s.idTensor]}case"TensorListPopBack":{let n=k("tensorListId",e,t,a),r=k("elementShape",e,t,a),s=k("elementDType",e,t,a);return[a.getTensorList(n.id).popBack(r,s)]}case"TensorListSplit":{let n=k("tensor",e,t,a),r=k("elementShape",e,t,a),s=k("lengths",e,t,a),i=XP(n,s,r);return a.addTensorList(i),[i.idTensor]}case"TensorListLength":{let n=k("tensorListId",e,t,a),r=a.getTensorList(n.id);return[Fe(r.size(),"int32")]}case"TensorListResize":{let n=k("tensorListId",e,t,a),r=k("size",e,t,a),s=a.getTensorList(n.id).resize(r);return a.addTensorList(s),[s.idTensor]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};function ax(e,t,a){let[n,r]=k("fusedOps",e,t,a),s=n==="biasadd",i=!s,o=r==="prelu",l=n==="fusedbatchnorm",u=k("numArgs",e,t,a);if(s){if(o&&u!==2)throw new Error("FusedConv2d and DepthwiseConv2d with BiasAdd and Prelu must have two extra arguments: bias and alpha.");if(!o&&s&&u!==1)throw new Error("FusedConv2d and DepthwiseConv2d with BiasAdd must have one extra argument: bias.")}if(l)throw new Error("FusedConv2d and DepthwiseConv2d with FusedBatchNorm is not supported");let p=k("strides",e,t,a),c=mc(e,t,a),d=k("dataFormat",e,t,a).toUpperCase(),h=k("dilations",e,t,a),[f,m]=k("args",e,t,a);i&&(m=f,f=void 0);let g=k("leakyreluAlpha",e,t,a);return{stride:p,pad:c,dataFormat:d,dilations:h,biasArg:f,preluArg:m,activationFunc:r,leakyreluAlpha:g}}var ZP=(e,t,a,n=Zt)=>{switch(e.op){case"Conv1D":{let r=k("stride",e,t,a),s=k("pad",e,t,a),i=k("dataFormat",e,t,a).toUpperCase(),o=k("dilation",e,t,a);return[n.conv1d(k("x",e,t,a),k("filter",e,t,a),r,s,i,o)]}case"Conv2D":{let r=k("strides",e,t,a),s=mc(e,t,a),i=k("dataFormat",e,t,a).toUpperCase(),o=k("dilations",e,t,a);return[n.conv2d(k("x",e,t,a),k("filter",e,t,a),[r[1],r[2]],s,i,[o[1],o[2]])]}case"_FusedConv2D":{let{stride:r,pad:s,dataFormat:i,dilations:o,biasArg:l,preluArg:u,activationFunc:p,leakyreluAlpha:c}=ax(e,t,a);return[n.fused.conv2d({x:k("x",e,t,a),filter:k("filter",e,t,a),strides:[r[1],r[2]],pad:s,dataFormat:i,dilations:[o[1],o[2]],bias:l,activation:p,preluActivationWeights:u,leakyreluAlpha:c})]}case"FusedDepthwiseConv2dNative":{let{stride:r,pad:s,dataFormat:i,dilations:o,biasArg:l,preluArg:u,activationFunc:p,leakyreluAlpha:c}=ax(e,t,a);return[n.fused.depthwiseConv2d({x:k("x",e,t,a),filter:k("filter",e,t,a),strides:[r[1],r[2]],pad:s,dataFormat:i,dilations:[o[1],o[2]],bias:l,activation:p,preluActivationWeights:u,leakyreluAlpha:c})]}case"Conv2DBackpropInput":case"Conv2dTranspose":{let r=k("outputShape",e,t,a),s=k("strides",e,t,a),i=mc(e,t,a);return[n.conv2dTranspose(k("x",e,t,a),k("filter",e,t,a),r,[s[1],s[2]],i)]}case"DepthwiseConv2dNative":case"DepthwiseConv2d":{let r=k("strides",e,t,a),s=mc(e,t,a),i=k("dilations",e,t,a),o=k("dataFormat",e,t,a).toUpperCase();return[n.depthwiseConv2d(k("input",e,t,a),k("filter",e,t,a),[r[1],r[2]],s,o,[i[1],i[2]])]}case"Conv3D":{let r=k("strides",e,t,a),s=k("pad",e,t,a),i=k("dataFormat",e,t,a).toUpperCase(),o=k("dilations",e,t,a);return[n.conv3d(k("x",e,t,a),k("filter",e,t,a),[r[1],r[2],r[3]],s,i,[o[1],o[2],o[3]])]}case"AvgPool":{let r=k("strides",e,t,a),s=k("pad",e,t,a),i=k("kernelSize",e,t,a);return[n.avgPool(k("x",e,t,a),[i[1],i[2]],[r[1],r[2]],s)]}case"MaxPool":{let r=k("strides",e,t,a),s=k("pad",e,t,a),i=k("kernelSize",e,t,a);return[n.maxPool(k("x",e,t,a),[i[1],i[2]],[r[1],r[2]],s)]}case"MaxPoolWithArgmax":{let r=k("strides",e,t,a),s=k("pad",e,t,a),i=k("kernelSize",e,t,a),o=k("includeBatchInIndex",e,t,a),{result:l,indexes:u}=n.maxPoolWithArgmax(k("x",e,t,a),[i[1],i[2]],[r[1],r[2]],s,o);return[l,u]}case"AvgPool3D":{let r=k("strides",e,t,a),s=k("pad",e,t,a),i=k("kernelSize",e,t,a);return[n.avgPool3d(k("x",e,t,a),[i[1],i[2],i[3]],[r[1],r[2],r[3]],s)]}case"MaxPool3D":{let r=k("strides",e,t,a),s=k("pad",e,t,a),i=k("kernelSize",e,t,a);return[n.maxPool3d(k("x",e,t,a),[i[1],i[2],i[3]],[r[1],r[2],r[3]],s)]}case"Dilation2D":{let r=k("strides",e,t,a),s=k("pad",e,t,a),i=k("dilations",e,t,a),o=r[1],l=r[2],u=i[1],p=i[2];return[n.dilation2d(k("x",e,t,a),k("filter",e,t,a),[o,l],s,[u,p],"NHWC")]}default:throw TypeError(`Node type ${e.op} is not implemented`)}},YP=(e,t,a,n=Zt)=>{switch(e.op){case"Fill":{let r=k("shape",e,t,a),s=k("dtype",e,t,a),i=k("value",e,t,a);return[n.fill(r,i,s)]}case"LinSpace":{let r=k("start",e,t,a),s=k("stop",e,t,a),i=k("num",e,t,a);return[n.linspace(r,s,i)]}case"Multinomial":{let r=k("logits",e,t,a),s=k("numSamples",e,t,a),i=k("seed",e,t,a);return[n.multinomial(r,s,i)]}case"OneHot":{let r=k("indices",e,t,a),s=k("depth",e,t,a),i=k("onValue",e,t,a),o=k("offValue",e,t,a),l=k("dtype",e,t,a);return[n.oneHot(r,s,i,o,l)]}case"Ones":return[n.ones(k("shape",e,t,a),k("dtype",e,t,a))];case"OnesLike":return[n.onesLike(k("x",e,t,a))];case"RandomStandardNormal":return[n.randomStandardNormal(k("shape",e,t,a),k("dtype",e,t,a),k("seed",e,t,a))];case"RandomUniform":return[n.randomUniform(k("shape",e,t,a),k("minval",e,t,a),k("maxval",e,t,a),k("dtype",e,t,a))];case"Range":{let r=k("start",e,t,a),s=k("stop",e,t,a),i=k("step",e,t,a);return[n.range(r,s,i,k("dtype",e,t,a))]}case"TruncatedNormal":{let r=k("shape",e,t,a),s=k("mean",e,t,a),i=k("stdDev",e,t,a),o=k("seed",e,t,a);return[n.truncatedNormal(r,s,i,k("dtype",e,t,a),o)]}case"Zeros":return[n.zeros(k("shape",e,t,a),k("dtype",e,t,a))];case"ZerosLike":return[n.zerosLike(k("x",e,t,a))];default:throw TypeError(`Node type ${e.op} is not implemented`)}};function Dm(e,t,a){let n=k("boxes",e,t,a),r=k("scores",e,t,a),s=k("maxOutputSize",e,t,a),i=k("iouThreshold",e,t,a),o=k("scoreThreshold",e,t,a),l=k("softNmsSigma",e,t,a);return{boxes:n,scores:r,maxOutputSize:s,iouThreshold:i,scoreThreshold:o,softNmsSigma:l}}var JP=async(e,t,a,n,r=Zt)=>{switch(e.op){case"NonMaxSuppressionV5":{let{boxes:s,scores:i,maxOutputSize:o,iouThreshold:l,scoreThreshold:u,softNmsSigma:p}=Dm(e,t,a),c=await r.image.nonMaxSuppressionWithScoreAsync(s,i,o,l,u,p);return[c.selectedIndices,c.selectedScores]}case"NonMaxSuppressionV4":{let{boxes:s,scores:i,maxOutputSize:o,iouThreshold:l,scoreThreshold:u}=Dm(e,t,a),p=k("padToMaxOutputSize",e,t,a),c=await r.image.nonMaxSuppressionPaddedAsync(s,i,o,l,u,p);return[c.selectedIndices,c.validOutputs]}case"NonMaxSuppressionV3":case"NonMaxSuppressionV2":{let{boxes:s,scores:i,maxOutputSize:o,iouThreshold:l,scoreThreshold:u}=Dm(e,t,a);return[await r.image.nonMaxSuppressionAsync(s,i,o,l,u)]}case"Where":{let s=r.cast(k("condition",e,t,a),"bool"),i=[await r.whereAsync(s)];return s.dispose(),i}case"ListDiff":return r.setdiff1dAsync(k("x",e,t,a),k("y",e,t,a));default:throw TypeError(`Node type ${e.op} is not implemented`)}},QP=(e,t,a,n=Zt)=>{switch(e.op){case"LowerBound":{let r=k("sortedSequence",e,t,a),s=k("values",e,t,a);return[n.lowerBound(r,s)]}case"TopKV2":{let r=k("x",e,t,a),s=k("k",e,t,a),i=k("sorted",e,t,a),o=n.topk(r,s,i);return[o.values,o.indices]}case"UpperBound":{let r=k("sortedSequence",e,t,a),s=k("values",e,t,a);return[n.upperBound(r,s)]}case"Unique":{let r=k("x",e,t,a),s=n.unique(r);return[s.values,s.indices]}case"UniqueV2":{let r=k("x",e,t,a),s=k("axis",e,t,a),i=n.unique(r,s);return[i.values,i.indices]}default:throw TypeError(`Node type ${e.op} is not implemented`)}},eF=(e,t,a,n=Zt)=>{switch(e.op){case"Const":return t[e.name];case"PlaceholderWithDefault":let r=k("default",e,t,a);return[ba(e.name,t,a)||r];case"Placeholder":return[ba(e.name,t,a)];case"Identity":case"StopGradient":case"FakeQuantWithMinMaxVars":{let p=k("x",e,t,a);return[gr(p)]}case"IdentityN":return k("x",e,t,a).map(p=>gr(p));case"Snapshot":let s=k("x",e,t,a);return[gr(s)];case"Shape":return[n.tensor1d(k("x",e,t,a).shape,"int32")];case"ShapeN":return k("x",e,t,a).map(p=>n.tensor1d(p.shape));case"Size":return[n.scalar(k("x",e,t,a).size,"int32")];case"Rank":return[n.scalar(k("x",e,t,a).rank,"int32")];case"NoOp":return[n.scalar(1)];case"Print":let i=k("x",e,t,a),o=k("data",e,t,a),l=k("message",e,t,a),u=k("summarize",e,t,a);console.warn("The graph has a tf.print() operation,usually used for debugging, which slows down performance."),console.log(l);for(let p=0;pe.dispose()),this.tensorMap.clear(),this.handle.dispose()}size(){return this.tensorMap.size}tensorSize(){return Fe(this.size(),"int32")}async import(e,t){this.checkKeyAndValueTensor(e,t);let a=await e.data();return this.tensorMap.forEach(n=>n.dispose()),this.tensorMap.clear(),$e(()=>{let n=Ta(t),r=a.length,s=n.length;v.assert(r===s,()=>`The number of elements doesn't match, keys has ${r} elements, the values has ${s} elements.`);for(let i=0;i{let n=[];for(let r=0;r{switch(e.op){case"HashTable":case"HashTableV2":{let r=n.getHashTableHandleByName(e.name);if(r!=null)return[r];{let s=k("keyDType",e,t,a),i=k("valueDType",e,t,a),o=new tF(s,i);return n.addHashTable(e.name,o),[o.handle]}}case"InitializeTable":case"InitializeTableV2":case"LookupTableImport":case"LookupTableImportV2":{let r=k("tableHandle",e,t,a,n),s=k("keys",e,t,a),i=k("values",e,t,a);return[await n.getHashTableById(r.id).import(s,i)]}case"LookupTableFind":case"LookupTableFindV2":{let r=k("tableHandle",e,t,a,n),s=k("keys",e,t,a),i=k("defaultValue",e,t,a);return[await n.getHashTableById(r.id).find(s,i)]}case"LookupTableSize":case"LookupTableSizeV2":{let r=k("tableHandle",e,t,a,n);return[n.getHashTableById(r.id).tensorSize()]}default:throw TypeError(`Node type ${e.op} is not implemented`)}},nF=(e,t,a,n=Zt)=>{switch(e.op){case"ResizeBilinear":{let r=k("images",e,t,a),s=k("size",e,t,a),i=k("alignCorners",e,t,a),o=k("halfPixelCenters",e,t,a);return[n.image.resizeBilinear(r,[s[0],s[1]],i,o)]}case"ResizeNearestNeighbor":{let r=k("images",e,t,a),s=k("size",e,t,a),i=k("alignCorners",e,t,a),o=k("halfPixelCenters",e,t,a);return[n.image.resizeNearestNeighbor(r,[s[0],s[1]],i,o)]}case"CropAndResize":{let r=k("image",e,t,a),s=k("boxes",e,t,a),i=k("boxInd",e,t,a),o=k("cropSize",e,t,a),l=k("method",e,t,a),u=k("extrapolationValue",e,t,a);return[n.image.cropAndResize(r,s,i,o,l,u)]}case"ImageProjectiveTransformV3":{let r=k("images",e,t,a),s=k("transforms",e,t,a),i=k("outputShape",e,t,a),o=k("fillValue",e,t,a),l=k("interpolation",e,t,a),u=k("fillMode",e,t,a);return[n.image.transform(r,s,l.toLowerCase(),u.toLowerCase(),o,i)]}default:throw TypeError(`Node type ${e.op} is not implemented`)}},rF=(e,t,a,n=Zt)=>{switch(e.op){case"Equal":return[n.equal(k("a",e,t,a),k("b",e,t,a))];case"NotEqual":return[n.notEqual(k("a",e,t,a),k("b",e,t,a))];case"Greater":return[n.greater(k("a",e,t,a),k("b",e,t,a))];case"GreaterEqual":return[n.greaterEqual(k("a",e,t,a),k("b",e,t,a))];case"Less":return[n.less(k("a",e,t,a),k("b",e,t,a))];case"LessEqual":return[n.lessEqual(k("a",e,t,a),k("b",e,t,a))];case"LogicalAnd":return[n.logicalAnd(k("a",e,t,a),k("b",e,t,a))];case"LogicalNot":return[n.logicalNot(k("a",e,t,a))];case"LogicalOr":return[n.logicalOr(k("a",e,t,a),k("b",e,t,a))];case"Select":case"SelectV2":return[n.where(k("condition",e,t,a),k("a",e,t,a),k("b",e,t,a))];default:throw TypeError(`Node type ${e.op} is not implemented`)}},sF=(e,t,a,n=Zt)=>{switch(e.op){case"BatchMatMul":case"BatchMatMulV2":case"MatMul":return[n.matMul(k("a",e,t,a),k("b",e,t,a),k("transposeA",e,t,a),k("transposeB",e,t,a))];case"Einsum":return[n.einsum(k("equation",e,t,a),...k("tensors",e,t,a))];case"Transpose":return[n.transpose(k("x",e,t,a),k("perm",e,t,a))];case"_FusedMatMul":let[r,s]=k("fusedOps",e,t,a),i=r==="biasadd",o=s==="prelu",l=k("numArgs",e,t,a),u=k("leakyreluAlpha",e,t,a);if(i){if(o&&l!==2)throw new Error("Fused MatMul with BiasAdd and Prelu must have two extra arguments: bias and alpha.");if(!o&&l!==1)throw new Error("Fused MatMul with BiasAdd must have one extra argument: bias.")}let[p,c]=k("args",e,t,a);return[n.fused.matMul({a:k("a",e,t,a),b:k("b",e,t,a),transposeA:k("transposeA",e,t,a),transposeB:k("transposeB",e,t,a),bias:p,activation:s,preluActivationWeights:c,leakyreluAlpha:u})];default:throw TypeError(`Node type ${e.op} is not implemented`)}},iF=(e,t,a,n=Zt)=>{switch(e.op){case"EuclideanNorm":return[n.euclideanNorm(k("x",e,t,a),k("axis",e,t,a),k("keepDims",e,t,a))];case"FusedBatchNorm":case"FusedBatchNormV2":return[n.batchNorm(k("x",e,t,a),k("mean",e,t,a),k("variance",e,t,a),k("offset",e,t,a),k("scale",e,t,a),k("epsilon",e,t,a))];case"FusedBatchNormV3":return[n.batchNorm(k("x",e,t,a),k("mean",e,t,a),k("variance",e,t,a),k("offset",e,t,a),k("scale",e,t,a),k("epsilon",e,t,a))];case"LRN":return[n.localResponseNormalization(k("x",e,t,a),k("radius",e,t,a),k("bias",e,t,a),k("alpha",e,t,a),k("beta",e,t,a))];case"Softmax":return[n.softmax(k("x",e,t,a))];case"LogSoftmax":return[n.logSoftmax(k("x",e,t,a))];case"SparseToDense":return[n.sparseToDense(k("sparseIndices",e,t,a),k("outputShape",e,t,a),k("sparseValues",e,t,a),k("defaultValue",e,t,a))];default:throw TypeError(`Node type ${e.op} is not implemented`)}},oF=(e,t,a,n=Zt)=>{switch(e.op){case"RaggedGather":{let{outputNestedSplits:r,outputDenseValues:s}=n.raggedGather(k("paramsNestedSplits",e,t,a),k("paramsDenseValues",e,t,a),k("indices",e,t,a),k("outputRaggedRank",e,t,a));return r.concat(s)}case"RaggedRange":{let{rtNestedSplits:r,rtDenseValues:s}=n.raggedRange(k("starts",e,t,a),k("limits",e,t,a),k("splits",e,t,a));return[r,s]}case"RaggedTensorToTensor":return[n.raggedTensorToTensor(k("shape",e,t,a),k("values",e,t,a),k("defaultValue",e,t,a),k("rowPartitionTensors",e,t,a),k("rowPartitionTypes",e,t,a))];default:throw TypeError(`Node type ${e.op} is not implemented`)}},lF=(e,t,a,n=Zt)=>{switch(e.op){case"Max":{let o=k("axis",e,t,a),l=k("keepDims",e,t,a);return[n.max(k("x",e,t,a),o,l)]}case"Mean":{let o=k("axis",e,t,a),l=k("keepDims",e,t,a);return[n.mean(k("x",e,t,a),o,l)]}case"Min":{let o=k("axis",e,t,a),l=k("keepDims",e,t,a);return[n.min(k("x",e,t,a),o,l)]}case"Sum":{let o=k("axis",e,t,a),l=k("keepDims",e,t,a);return[n.sum(k("x",e,t,a),o,l)]}case"All":{let o=k("axis",e,t,a),l=k("keepDims",e,t,a);return[n.all(k("x",e,t,a),o,l)]}case"Any":{let o=k("axis",e,t,a),l=k("keepDims",e,t,a);return[n.any(k("x",e,t,a),o,l)]}case"ArgMax":{let o=k("axis",e,t,a);return[n.argMax(k("x",e,t,a),o)]}case"ArgMin":{let o=k("axis",e,t,a);return[n.argMin(k("x",e,t,a),o)]}case"Prod":{let o=k("axis",e,t,a),l=k("keepDims",e,t,a);return[n.prod(k("x",e,t,a),o,l)]}case"Cumprod":{let o=k("axis",e,t,a),l=k("exclusive",e,t,a),u=k("reverse",e,t,a);return[n.cumprod(k("x",e,t,a),o,l,u)]}case"Cumsum":{let o=k("axis",e,t,a),l=k("exclusive",e,t,a),u=k("reverse",e,t,a);return[n.cumsum(k("x",e,t,a),o,l,u)]}case"Bincount":let r=k("x",e,t,a),s=k("weights",e,t,a),i=k("size",e,t,a);return[n.bincount(r,s,i)];case"DenseBincount":{let o=k("x",e,t,a),l=k("weights",e,t,a),u=k("size",e,t,a),p=k("binaryOutput",e,t,a);return[n.denseBincount(o,l,u,p)]}default:throw TypeError(`Node type ${e.op} is not implemented`)}},uF=(e,t,a,n=Zt)=>{switch(e.op){case"ConcatV2":case"Concat":{let r=k("n",e,t,a),s=k("axis",e,t,a),i=k("tensors",e,t,a);return i=i.slice(0,r),[n.concat(i,s)]}case"Gather":{let r=k("x",e,t,a),s=k("indices",e,t,a);return[n.gather(r,n.cast(s,"int32"),0)]}case"GatherV2":{let r=k("axis",e,t,a),s=k("batchDims",e,t,a),i=k("x",e,t,a),o=k("indices",e,t,a);return[n.gather(i,n.cast(o,"int32"),r,s)]}case"Reverse":{let r=k("dims",e,t,a),s=[];for(let o=0;o{let r=k("axis",e,t,a),s=k("tensors",e,t,a),i=s[0].shape,o=n.squeeze(s[0]).shape,l=s.map(u=>{let p=v.arraysEqual(u.shape,i);if(!p&&!v.arraysEqual(n.squeeze(u).shape,o))throw new Error("the input tensors shape does not match");return p?u:n.reshape(u,i)});return[n.stack(l,r)]});case"Unpack":{let r=k("axis",e,t,a),s=k("tensor",e,t,a);return n.unstack(s,r)}case"Tile":{let r=k("reps",e,t,a);return[n.tile(k("x",e,t,a),r)]}case"Split":case"SplitV":{let r=k("axis",e,t,a),s=k("numOrSizeSplits",e,t,a),i=k("x",e,t,a);return n.split(i,s,r)}case"ScatterNd":{let r=k("indices",e,t,a),s=k("values",e,t,a),i=k("shape",e,t,a);return[n.scatterND(r,s,i)]}case"GatherNd":{let r=k("x",e,t,a),s=k("indices",e,t,a);return[n.gatherND(r,s)]}case"SparseToDense":{let r=k("sparseIndices",e,t,a),s=k("outputShape",e,t,a),i=k("sparseValues",e,t,a),o=k("defaultValue",e,t,a);return[n.sparseToDense(r,i,s,i.dtype===o.dtype?o:n.cast(o,i.dtype))]}default:throw TypeError(`Node type ${e.op} is not implemented`)}},dF=(e,t,a,n=Zt)=>{switch(e.op){case"SparseFillEmptyRows":{let{outputIndices:r,outputValues:s,emptyRowIndicator:i,reverseIndexMap:o}=n.sparse.sparseFillEmptyRows(k("indices",e,t,a),k("values",e,t,a),k("denseShape",e,t,a),k("defaultValue",e,t,a));return[r,s,i,o]}case"SparseReshape":{let{outputIndices:r,outputShape:s}=n.sparse.sparseReshape(k("inputIndices",e,t,a),k("inputShape",e,t,a),k("newShape",e,t,a));return[r,s]}case"SparseSegmentMean":return[n.sparse.sparseSegmentMean(k("data",e,t,a),k("indices",e,t,a),k("segmentIds",e,t,a))];case"SparseSegmentSum":return[n.sparse.sparseSegmentSum(k("data",e,t,a),k("indices",e,t,a),k("segmentIds",e,t,a))];default:throw TypeError(`Node type ${e.op} is not implemented`)}},pF=(e,t,a,n=Zt)=>{switch(e.op){case"FFT":return[n.fft(k("x",e,t,a))];case"IFFT":return[n.ifft(k("x",e,t,a))];case"RFFT":return[n.rfft(k("x",e,t,a))];case"IRFFT":return[n.irfft(k("x",e,t,a))];default:throw TypeError(`Node type ${e.op} is not implemented`)}},cF=(e,t,a,n=Zt)=>{switch(e.op){case"StringNGrams":{let{nGrams:r,nGramsSplits:s}=n.string.stringNGrams(k("data",e,t,a),k("dataSplits",e,t,a),k("separator",e,t,a),k("nGramWidths",e,t,a),k("leftPad",e,t,a),k("rightPad",e,t,a),k("padWidth",e,t,a),k("preserveShortSequences",e,t,a));return[r,s]}case"StringSplit":{let{indices:r,values:s,shape:i}=n.string.stringSplit(k("input",e,t,a),k("delimiter",e,t,a),k("skipEmpty",e,t,a));return[r,s,i]}case"StringToHashBucketFast":return[n.string.stringToHashBucketFast(k("input",e,t,a),k("numBuckets",e,t,a))];default:throw TypeError(`Node type ${e.op} is not implemented`)}},hF=(e,t,a,n=Zt)=>{switch(e.op){case"Cast":return[n.cast(k("x",e,t,a),k("dtype",e,t,a))];case"ExpandDims":{let r=k("axis",e,t,a);return[n.expandDims(k("x",e,t,a),r)]}case"Squeeze":{let r=k("axis",e,t,a);return[n.squeeze(k("x",e,t,a),r)]}case"Reshape":return[n.reshape(k("x",e,t,a),k("shape",e,t,a))];case"MirrorPad":return[n.mirrorPad(k("x",e,t,a),k("padding",e,t,a),k("mode",e,t,a))];case"PadV2":case"Pad":return[n.pad(k("x",e,t,a),k("padding",e,t,a),k("constantValue",e,t,a))];case"SpaceToBatchND":{let r=k("blockShape",e,t,a),s=k("paddings",e,t,a);return[n.spaceToBatchND(k("x",e,t,a),r,s)]}case"BatchToSpaceND":{let r=k("blockShape",e,t,a),s=k("crops",e,t,a);return[n.batchToSpaceND(k("x",e,t,a),r,s)]}case"DepthToSpace":{let r=k("blockSize",e,t,a),s=k("dataFormat",e,t,a).toUpperCase();return[n.depthToSpace(k("x",e,t,a),r,s)]}case"BroadcastTo":return[n.broadcastTo(k("x",e,t,a),k("shape",e,t,a))];case"BroadcastArgs":return[n.broadcastArgs(k("s0",e,t,a),k("s1",e,t,a))];default:throw TypeError(`Node type ${e.op} is not implemented`)}};function nx(e,t,a,n,r=$e){let s=((i,o,l)=>{switch(i.category){case"arithmetic":return r(()=>VP(i,o,l));case"basic_math":return r(()=>UP(i,o,l));case"control":return KP(i,o,l);case"convolution":return r(()=>ZP(i,o,l));case"creation":return r(()=>YP(i,o,l));case"dynamic":return JP(i,o,l);case"evaluation":return r(()=>QP(i,o,l));case"image":return r(()=>nF(i,o,l));case"graph":return r(()=>eF(i,o,l));case"logical":return r(()=>rF(i,o,l));case"matrices":return r(()=>sF(i,o,l));case"normalization":return r(()=>iF(i,o,l));case"ragged":return r(()=>oF(i,o,l));case"reduction":return r(()=>lF(i,o,l));case"slice_join":return r(()=>uF(i,o,l));case"sparse":return r(()=>dF(i,o,l));case"spectral":return r(()=>pF(i,o,l));case"string":return r(()=>cF(i,o,l));case"transformation":return r(()=>hF(i,o,l));case"hash_table":return aF(i,o,l,n);case"custom":let u=w4(i.op);if(u&&u.customExecutor)return u.customExecutor(new WP(i,o,l));throw TypeError(`Custom op ${i.op} is not registered.`);default:throw TypeError(`Unknown op '${i.op}'. File an issue at https://github.com/tensorflow/tfjs/issues so we can add it, or register a custom execution with tf.registerOp()`)}})(e,t,a);return v.isPromise(s)?s.then(i=>[].concat(i)):[].concat(s)}var rx=class{constructor(e={},t={},a={},n={}){this.weightMap=e,this.tensorArrayMap=t,this.tensorListMap=a,this.functionMap=n,this.rootContext={id:0,frameName:"",iterationId:0},this.contexts=[this.rootContext],this.lastId=0,this.generateCurrentContextIds()}newFrame(e,t){return{id:e,frameName:t,iterationId:0}}set currentContext(e){this.contexts!==e&&(this.contexts=e,this.generateCurrentContextIds())}get currentContext(){return this.contexts}get currentContextId(){return this._currentContextIds[0]}get currentContextIds(){return this._currentContextIds}generateCurrentContextIds(){let e=[];for(let t=0;tt.id===0&&t.iterationId===0?"":`${t.frameName}-${t.iterationId}`).join("/"):""}enterFrame(e){this.contexts&&(this.lastId++,this.contexts=this.contexts.slice(),this.contexts.push(this.newFrame(this.lastId,e)),this._currentContextIds.unshift(this.contextIdforContexts(this.contexts)))}exitFrame(){if(this.contexts&&this.contexts.length>1)this.contexts=this.contexts.slice(),this.contexts.splice(-1),this.currentContextIds.shift();else throw new Error("Cannot exit frame, the context is empty")}nextIteration(){if(this.contexts&&this.contexts.length>0){this.contexts=this.contexts.slice(),this.lastId++;let e=Object.assign({},this.contexts[this.contexts.length-1]);e.iterationId+=1,e.id=this.lastId,this.contexts.splice(-1,1,e),this._currentContextIds.splice(0,1,this.contextIdforContexts(this.contexts))}else throw new Error("Cannot increase frame iteration, the context is empty")}getWeight(e){return this.weightMap[e]}addTensorArray(e){this.tensorArrayMap[e.id]=e}getTensorArray(e){return this.tensorArrayMap[e]}addTensorList(e){this.tensorListMap[e.id]=e}getTensorList(e){return this.tensorListMap[e]}dispose(e){for(let t in this.tensorArrayMap)this.tensorArrayMap[t].clearAndClose(e);for(let t in this.tensorListMap)this.tensorListMap[t].clearAndClose(e)}};function sx(e,t,a,n){let r=new Set,s=[],i=null,o=null,l=new Set,u=Object.keys(e).map(d=>ja(d)[0]),p=[];n!=null&&(p=n.map(d=>ja(d.name)[0]));let c=[...t];for(;c.length>0;){let d=c.pop();if((G4(d)||AF(d)||yF(d))&&i==null&&(i=d,o=i.children.map(h=>h.name).filter(h=>r.has(h))),r.add(d.name),a[d.name]==null&&u.indexOf(d.name)===-1&&p.indexOf(d.name)===-1){if(d.inputs.length===0){s.push(d.name);continue}d.inputs.forEach(h=>{l.has(h.name)||(l.add(h.name),c.push(h))})}}return{inputs:e,outputs:t,usedNodes:r,missingInputs:s,dynamicNode:i,syncInputs:o}}function fF(e,t,a){let{usedNodes:n,inputs:r}=a,s=[],i=Object.keys(r).map(p=>ja(p)[0]).map(p=>e.nodes[p]),o=e.initNodes;i.forEach(p=>{n.has(p.name)&&s.push(p)}),e.weights.forEach(p=>{n.has(p.name)&&s.push(p)}),o!=null&&o.forEach(p=>{n.has(p.name)&&s.push(p)});let l=new Set,u=[];for(;s.length>0;){let p=s.pop();l.add(p.name),t[p.name]||u.push(p),p.children.forEach(c=>{!l.has(c.name)&&n.has(c.name)&&c.inputs.every(d=>l.has(d.name))&&s.push(c)})}return u}var mF=["Switch","Merge","Enter","Exit","NextIteration","StatelessIf","StatelessWhile","if","While"],gF=["NonMaxSuppressionV2","NonMaxSuppressionV3","NonMaxSuppressionV5","Where"],xF=["HashTable","HashTableV2","LookupTableImport","LookupTableImportV2","LookupTableFind","LookupTableFindV2","LookupTableSize","LookupTableSizeV2"];function G4(e){return mF.indexOf(e.op)>=0}function AF(e){return gF.indexOf(e.op)>=0}function yF(e){return xF.indexOf(e.op)>=0}var A1=class{constructor(e,t){this.graph=e,this.parent=t,this.compiledMap=new Map,this._weightMap={},this.SEPERATOR=",",this._functions={},this._functionExecutorMap={},this.keepIntermediateTensors=!1,this._outputs=e.outputs,this._inputs=e.inputs,this._initNodes=e.initNodes,this._signature=e.signature,this._functions=e.functions,e.functions!=null&&Object.keys(e.functions).forEach(a=>{this._functionExecutorMap[a]=new A1(e.functions[a],this)})}get weightIds(){return this.parent?this.parent.weightIds:this._weightIds}get functionExecutorMap(){return this.parent?this.parent.functionExecutorMap:this._functionExecutorMap}get weightMap(){return this.parent?this.parent.weightMap:this._weightMap}set weightMap(e){let t=Object.keys(e).map(a=>e[a].map(n=>n.id));this._weightIds=[].concat(...t),this._weightMap=e}set resourceManager(e){this._resourceManager=e}get inputs(){return this._inputs.map(e=>({name:e.name,shape:e.attrParams.shape?e.attrParams.shape.value:void 0,dtype:e.attrParams.dtype?e.attrParams.dtype.value:void 0}))}get outputs(){return this._outputs.map(e=>({name:e.name,shape:e.attrParams.shape?e.attrParams.shape.value:void 0,dtype:e.attrParams.dtype?e.attrParams.dtype.value:void 0}))}get inputNodes(){return this._inputs.map(e=>e.signatureKey||e.name)}get outputNodes(){return this._outputs.map(e=>{let t=e.signatureKey||e.name;return e.defaultOutput?`${t}:${e.defaultOutput}`:t})}get functions(){return Object.keys(this._functions).reduce((e,t)=>(e[t]=this._functions[t].signature,e),{})}getCompilationKey(e,t){let a=e.map(r=>r.name).sort(),n=t.map(r=>r.name).sort();return a.join(this.SEPERATOR)+"--"+n.join(this.SEPERATOR)}compile(e,t){let a=sx(e,t,this.weightMap,this._initNodes),{missingInputs:n,dynamicNode:r,syncInputs:s}=a;if(r!=null)throw new Error(`This execution contains the node '${r.name}', which has the dynamic op '${r.op}'. Please use model.executeAsync() instead. Alternatively, to avoid the dynamic ops, specify the inputs [${s}]`);if(n.length>0){let i=t.map(l=>l.name),o=Object.keys(e);throw new Error(`Cannot compute the outputs [${i}] from the provided inputs [${o}]. Missing the following inputs: [${n}]`)}return fF(this.graph,this.weightMap,a)}cloneAndKeepTensor(e){if(e==null)return null;let t=e.clone();return On(t),t}cloneTensorList(e){return e?e.map(t=>this.cloneAndKeepTensor(t)):null}cloneTensorMap(e){return Object.fromEntries(Object.entries(e).map(([t,a])=>[t,this.cloneTensorList(a)]))}execute(e,t){this.disposeIntermediateTensors(),e=this.mapInputs(e);let a=Object.keys(e).sort();this.checkInputs(e),this.checkInputShapeAndType(e),t=this.mapOutputs(t),this.checkOutputs(t);let n=a.map(p=>this.graph.nodes[ja(p)[0]]),r=t.map(p=>ja(p)[0]),s=r.map(p=>this.graph.nodes[p]);s.length===0&&(s=this._outputs);let i=this.getCompilationKey(n,s),o=this.compiledMap.get(i);o==null&&(o=this.compile(e,s),this.compiledMap.set(i,o));try{this.keepIntermediateTensors=W().getBool("KEEP_INTERMEDIATE_TENSORS")}catch(p){this.keepIntermediateTensors=!1,console.warn(p.message)}let l={},u={};return $e(()=>{let p=new rx(this.weightMap,l,u,this.functionExecutorMap),c=Object.assign({},this.weightMap);this.keepIntermediateTensors&&(this.clonedTensorsMap=this.cloneTensorMap(this.weightMap)),Object.keys(e).forEach(f=>{let[m,g]=ja(f),x=[];x[g]=e[f],c[m]=x,this.keepIntermediateTensors&&(this.clonedTensorsMap[m]=this.cloneTensorList(x))});let d=this.getFrozenTensorIds(c),h={};for(let f=0;fba(f,c,p))})}getFrozenTensorIds(e){let t=[].concat.apply([],Object.keys(e).map(a=>e[a]).map(a=>a.map(n=>n.id)));return new Set(t)}checkTensorForDisposal(e,t,a,n,r,s,i){t.category==="control"||s.indexOf(e)!==-1||(a[e].forEach(o=>{o!=null&&(i[o.id]=(i[o.id]||0)+t.children.length)}),t.inputs.forEach(o=>{if(o.category!=="control"){let l=bP(o.name,a,n);l!=null&&l.forEach(u=>{if(u&&!u.kept&&!r.has(u.id)){let p=i[u.id];p===1?(u.dispose(),delete i[u.id]):p!=null&&i[u.id]--}})}}))}async executeAsync(e,t){return this._executeAsync(e,t)}disposeIntermediateTensors(){!this.clonedTensorsMap||(Object.values(this.clonedTensorsMap).forEach(e=>{for(let t of e)t&&!t.isDisposed&&t.dispose()}),this.clonedTensorsMap=null)}getIntermediateTensors(){return this.clonedTensorsMap}async _executeAsync(e,t,a=!1,n={},r={}){this.disposeIntermediateTensors(),a||(e=this.mapInputs(e),this.checkInputs(e),this.checkInputShapeAndType(e),t=this.mapOutputs(t),this.checkOutputs(t));try{this.keepIntermediateTensors=W().getBool("KEEP_INTERMEDIATE_TENSORS")}catch(c){this.keepIntermediateTensors=!1,console.warn(c.message)}let s=new rx(this.weightMap,n,r,this.functionExecutorMap);this.keepIntermediateTensors&&(this.clonedTensorsMap=this.cloneTensorMap(this.weightMap));let i=await this.executeWithControlFlow(e,s,t,a),o=t.map(c=>ba(c,i,s)),l=o.map(c=>c.id),u=Object.keys(e).map(c=>e[c].id),p=new Set([...l,...u,...this.weightIds]);return Object.values(i).forEach(c=>{c.forEach(d=>{d&&!d.isDisposed&&!p.has(d.id)&&d.dispose()})}),this.parent==null&&s.dispose(p),o}async executeFunctionAsync(e,t,a){let n=e.reduce((r,s,i)=>(r[this.inputs[i].name]=s,r),{});return this._executeAsync(n,this.outputNodes,!0,t,a)}async executeWithControlFlow(e,t,a,n){let r=Object.keys(e),s=r.map(A=>this.graph.nodes[ja(A)[0]]),i=a.map(A=>ja(A)[0]),o=i.map(A=>this.graph.nodes[A]);o.length===0&&(o=this._outputs);let{usedNodes:l,missingInputs:u,dynamicNode:p,syncInputs:c}=sx(e,o,this.weightMap,this._initNodes),d=[...s,...this.graph.weights,...this._initNodes||[]].map(A=>({node:A,contexts:t.currentContext})),h=Object.assign({},this.weightMap);Object.keys(e).forEach(A=>{let[y,b]=ja(A),w=[];w[b]=e[A],h[y]=w});let f={},m=this.getFrozenTensorIds(h),g={};for(;d.length>0;){let A=this.processStack(s,d,t,h,g,m,i,f,l);await Promise.all(A)}p==null&&!n&&console.warn("This model execution did not contain any nodes with control flow or dynamic output shapes. You can use model.execute() instead.");let x=o.filter(A=>!G4(A)&&!ba(A.name,h,t)).map(A=>A.name);if(x.length>0){let A="";throw p!=null&&(A=`Alternatively, to avoid the dynamic ops, use model.execute() and specify the inputs [${c}]`),new Error(`Cannot compute the outputs [${x}] from the provided inputs [${r}]. Consider providing the following inputs: [${u}]. ${A}`)}return h}processStack(e,t,a,n,r,s,i,o,l){let u=[];for(;t.length>0;){let p=t.pop();a.currentContext=p.contexts;let c="";if(p.node.op==="Enter"&&k("isConstant",p.node,n,a)&&([c]=mr(p.node.name,a)),n[p.node.name]==null){let d=nx(p.node,n,a,this._resourceManager);c||([c]=mr(p.node.name,a));let h=a.currentContext;v.isPromise(d)?u.push(d.then(f=>(n[c]=f,this.keepIntermediateTensors&&(this.clonedTensorsMap[c]=this.cloneTensorList(f)),a.currentContext=h,this.checkTensorForDisposal(c,p.node,n,a,s,i,o),this.processChildNodes(p.node,t,a,n,r,l),f))):(n[c]=d,this.keepIntermediateTensors&&(this.clonedTensorsMap[c]=this.cloneTensorList(d)),this.checkTensorForDisposal(c,p.node,n,a,s,i,o),this.processChildNodes(p.node,t,a,n,r,l))}else this.processChildNodes(p.node,t,a,n,r,l)}return u}processChildNodes(e,t,a,n,r,s){e.children.forEach(i=>{let[o]=mr(i.name,a);r[o]||!s.has(i.name)||(i.op==="Merge"?i.inputNames.some(l=>!!ba(l,n,a))&&(r[o]=!0,t.push({contexts:a.currentContext,node:i})):i.inputNames.every(l=>!!ba(l,n,a))&&(r[o]=!0,t.push({contexts:a.currentContext,node:i})))})}dispose(){Object.keys(this.weightMap).forEach(e=>this.weightMap[e].forEach(t=>t.dispose()))}checkInputShapeAndType(e){Object.keys(e).forEach(t=>{let a=e[t],[n]=ja(t),r=this.graph.nodes[n];if(r.attrParams.shape&&r.attrParams.shape.value){let s=r.attrParams.shape.value,i=s.length===a.shape.length&&a.shape.every((o,l)=>s[l]===-1||s[l]===o);v.assert(i,()=>`The shape of dict['${r.name}'] provided in model.execute(dict) must be [${s}], but was [${a.shape}]`)}r.attrParams.dtype&&r.attrParams.dtype.value&&v.assert(a.dtype===r.attrParams.dtype.value,()=>`The dtype of dict['${r.name}'] provided in model.execute(dict) must be ${r.attrParams.dtype.value}, but was ${a.dtype}`)})}mapInputs(e){var t,a;let n={};for(let r in e){let s=(a=(t=this._signature)===null||t===void 0?void 0:t.inputs)===null||a===void 0?void 0:a[r];s!=null?n[s.name]=e[r]:n[r]=e[r]}return n}checkInputs(e){let t=Object.keys(e).filter(a=>{let[n]=ja(a);return this.graph.nodes[n]==null});if(t.length>0)throw new Error(`The dict provided in model.execute(dict) has keys: [${t}] that are not part of graph`)}mapOutputs(e){return e.map(t=>{var a,n;let r=(n=(a=this._signature)===null||a===void 0?void 0:a.outputs)===null||n===void 0?void 0:n[t];return r!=null?r.name:t},{})}checkOutputs(e){e.forEach(t=>{let[a]=ja(t);if(!this.graph.nodes[a])throw new Error(`The output '${t}' is not found in the graph`)})}},bF=class{constructor(e={},t={}){this.hashTableNameToHandle=e,this.hashTableMap=t}addHashTable(e,t){this.hashTableNameToHandle[e]=t.handle,this.hashTableMap[t.id]=t}getHashTableHandleByName(e){return this.hashTableNameToHandle[e]}getHashTableById(e){return this.hashTableMap[e]}dispose(){for(let e in this.hashTableMap)this.hashTableMap[e].clearAndClose(),delete this.hashTableMap[e];for(let e in this.hashTableNameToHandle)this.hashTableNameToHandle[e].dispose(),delete this.hashTableNameToHandle[e]}},vF="?tfjs-format=file",wF="model.json",op=class{constructor(e,t={},a=jn){this.modelUrl=e,this.loadOptions=t,this.version="n/a",this.io=a,t==null&&(this.loadOptions={}),this.resourceManager=new bF}get modelVersion(){return this.version}get inputNodes(){return this.executor.inputNodes}get outputNodes(){return this.executor.outputNodes}get inputs(){return this.executor.inputs}get outputs(){return this.executor.outputs}get weights(){return this.executor.weightMap}get metadata(){return this.artifacts.userDefinedMetadata}get modelSignature(){return this.signature}get modelStructuredOutputKeys(){return this.structuredOutputKeys}findIOHandler(){let e=this.modelUrl;if(e.load!=null)this.handler=e;else if(this.loadOptions.requestInit!=null)this.handler=this.io.browserHTTPRequest(e,this.loadOptions);else{let t=this.io.getLoadHandlers(e,this.loadOptions);if(t.length===0)t.push(this.io.browserHTTPRequest(e,this.loadOptions));else if(t.length>1)throw new Error(`Found more than one (${t.length}) load handlers for URL '${[e]}'`);this.handler=t[0]}}load(){if(this.findIOHandler(),this.handler.load==null)throw new Error("Cannot proceed with model loading because the IOHandler provided does not have the `load` method implemented.");let e=this.handler.load();return v.isPromise(e)?e.then(t=>this.loadSync(t)):this.loadSync(e)}loadSync(e){this.artifacts=e;let t=this.artifacts.modelTopology,a=this.artifacts.signature;if(this.artifacts.userDefinedMetadata!=null){let r=this.artifacts.userDefinedMetadata;r.signature!=null&&(a=r.signature),r.structuredOutputKeys!=null&&(this.structuredOutputKeys=r.structuredOutputKeys)}this.signature=a,this.version=`${t.versions.producer}.${t.versions.minConsumer}`;let n=this.io.decodeWeights(this.artifacts.weightData,this.artifacts.weightSpecs);if(this.executor=new A1(Q5.Instance.transformGraph(t,this.signature)),this.executor.weightMap=this.convertTensorMapToTensorsMap(n),this.executor.resourceManager=this.resourceManager,e.modelInitializer!=null&&e.modelInitializer.node!=null){let r=Q5.Instance.transformGraph(e.modelInitializer);this.initializer=new A1(r),this.initializer.weightMap=this.executor.weightMap,this.initializer.resourceManager=this.resourceManager,this.initializerSignature=e.initializerSignature}return!0}async save(e,t){if(typeof e=="string"){let a=this.io.getSaveHandlers(e);if(a.length===0)throw new Error(`Cannot find any save handlers for URL '${e}'`);if(a.length>1)throw new Error(`Found more than one (${a.length}) save handlers for URL '${e}'`);e=a[0]}if(e.save==null)throw new Error("GraphModel.save() cannot proceed because the IOHandler provided does not have the `save` attribute defined.");return e.save(this.artifacts)}addStructuredOutputNames(e){if(this.structuredOutputKeys){let t=e instanceof pt?[e]:e,a={};return t.forEach((n,r)=>a[this.structuredOutputKeys[r]]=n),a}return e}predict(e,t){let a=this.execute(e,this.outputNodes);return this.addStructuredOutputNames(a)}async predictAsync(e,t){let a=await this.executeAsync(e,this.outputNodes);return this.addStructuredOutputNames(a)}normalizeInputs(e){var t;if(!(e instanceof pt)&&!Array.isArray(e)){let r=(t=this.signature)===null||t===void 0?void 0:t.inputs;if(r!=null)for(let s in r){let i=r[s];i.resourceId!=null&&(e[s]=this.resourceIdToCapturedInput[i.resourceId])}return e}e=Array.isArray(e)?e:[e];let a=Object.keys(this.resourceIdToCapturedInput).length;if(e.length+a!==this.inputNodes.length)throw new Error(`Input tensor count mismatch, the graph model has ${this.inputNodes.length-a} non-resource placeholders, while there are ${e.length} input tensors provided.`);let n=0;return this.inputNodes.reduce((r,s)=>{var i,o,l;let u=(l=(o=(i=this.signature)===null||i===void 0?void 0:i.inputs)===null||o===void 0?void 0:o[s])===null||l===void 0?void 0:l.resourceId;return u!=null?r[s]=this.resourceIdToCapturedInput[u]:r[s]=e[n++],r},{})}normalizeOutputs(e){return e=e||this.outputNodes,Array.isArray(e)?e:[e]}executeInitializerGraph(){return this.initializer==null?[]:this.initializerSignature==null?this.initializer.execute({},[]):this.initializer.execute({},Object.keys(this.initializerSignature.outputs))}async executeInitializerGraphAsync(){return this.initializer==null?[]:this.initializerSignature==null?this.initializer.executeAsync({},[]):this.initializer.executeAsync({},Object.keys(this.initializerSignature.outputs))}setResourceIdToCapturedInput(e){if(this.resourceIdToCapturedInput={},this.initializerSignature){let t=this.initializerSignature.outputs,a=Object.keys(t);for(let n=0;n1?a:a[0]}async executeAsync(e,t){this.resourceIdToCapturedInput==null&&this.setResourceIdToCapturedInput(await this.executeInitializerGraphAsync()),e=this.normalizeInputs(e),t=this.normalizeOutputs(t);let a=await this.executor.executeAsync(e,t);return a.length>1?a:a[0]}getIntermediateTensors(){return this.executor.getIntermediateTensors()}disposeIntermediateTensors(){this.executor.disposeIntermediateTensors()}convertTensorMapToTensorsMap(e){return Object.keys(e).reduce((t,a)=>(t[a]=[e[a]],t),{})}dispose(){this.executor.dispose(),this.initializer&&(this.initializer.dispose(),this.resourceIdToCapturedInput&&Y(this.resourceIdToCapturedInput)),this.resourceManager.dispose()}};async function r3(e,t={},a=jn){if(e==null)throw new Error("modelUrl in loadGraphModel() cannot be null. Please provide a url or an IOHandler that loads the model");t==null&&(t={}),t.fromTFHub&&typeof e=="string"&&(e=IF(e));let n=new op(e,t,a);return await n.load(),n}function kF(e){if(e==null)throw new Error("modelUrl in loadGraphModelSync() cannot be null. Please provide model artifacts or an IOHandler that loads the model");let t;if(e instanceof Array){let[n,r]=e;if(!n)throw new Error("modelJSON must be the first element of the array");if(!r||!(r instanceof ArrayBuffer))throw new Error("An ArrayBuffer of weights must be the second element of the array");if(!("modelTopology"in n))throw new Error("Model JSON is missing 'modelTopology'");if(!("weightsManifest"in n))throw new Error("Model JSON is missing 'weightsManifest'");let s=jn.getWeightSpecs(n.weightsManifest),i=jn.getModelArtifactsForJSONSync(n,s,r);t=jn.fromMemorySync(i)}else if("load"in e)t=e;else if("modelTopology"in e&&"weightSpecs"in e&&"weightData"in e)t=jn.fromMemorySync(e);else throw new Error("Unknown model format");let a=new op(t);return a.load(),a}function IF(e){return e.endsWith("/")||(e=e+"/"),`${e}${wF}${vF}`}var SF="4.1.0";function ye(e,t){Array.isArray(e)||(e=[e]),e.forEach(a=>{a!=null&&v.assert(a.dtype!=="complex64",()=>`${t} does not support complex64 tensors in the CPU backend.`)})}var TF=Tn.whereImpl,$h=class extends bl{constructor(){super(),this.blockSize=48,this.firstUse=!0,this.data=new vd(this,kt())}nextDataId(){return $h.nextDataId++}write(e,t,a){this.firstUse&&(this.firstUse=!1,W().get("IS_NODE")&&T.warn(` ============================ Hi, looks like you are running TensorFlow.js in Node.js. To speed things up dramatically, install our node backend, visit https://github.com/tensorflow/tfjs-node for more details. ============================`));let n={id:this.nextDataId()};return this.data.set(n,{values:e,dtype:a,refCount:1}),n}makeTensorInfo(e,t,a){let n;if(t==="string"&&a!=null&&a.length>0&&v.isString(a[0])){let r=a.map(s=>v.encodeString(s));n=this.write(r,e,t)}else n=this.write(a,e,t);return{dataId:n,shape:e,dtype:t}}refCount(e){return this.data.has(e)?this.data.get(e).refCount:0}incRef(e){let t=this.data.get(e);t.refCount++}decRef(e){if(this.data.has(e)){let t=this.data.get(e);t.refCount--}}move(e,t,a,n,r){this.data.set(e,{values:t,dtype:n,refCount:r})}numDataIds(){return this.data.numDataIds()}async read(e){return this.readSync(e)}readSync(e){let{dtype:t,complexTensorInfos:a}=this.data.get(e);if(t==="complex64"){let n=this.readSync(a.real.dataId),r=this.readSync(a.imag.dataId);return T.mergeRealAndImagArrays(n,r)}return this.data.get(e).values}bufferSync(e){let t=this.readSync(e.dataId);if(e.dtype==="string")try{let a=t.map(n=>v.decodeString(n));return Me(e.shape,e.dtype,a)}catch(a){throw new Error("Failed to decode encoded string bytes into utf-8")}return Me(e.shape,e.dtype,t)}makeOutput(e,t,a){return kt().makeTensorFromTensorInfo(this.makeTensorInfo(t,a,e),this)}disposeData(e,t=!1){if(this.data.has(e)){if(this.data.get(e).refCount--,!t&&this.data.get(e).refCount>0)return!1;let{complexTensorInfos:a}=this.data.get(e);a!=null&&(this.disposeData(a.real.dataId,!0),this.disposeData(a.imag.dataId,!0)),this.data.delete(e)}return!0}disposeIntermediateTensorInfo(e){this.disposeData(e.dataId)}async time(e){let t=v.now();return e(),{kernelMs:v.now()-t}}memory(){return{unreliable:!0,reasons:["The reported memory is an upper bound. Due to automatic garbage collection, the true allocated memory may be less."]}}where(e){ye([e],"where");let t=this.readSync(e.dataId);return TF(e.shape,t)}dispose(){}floatPrecision(){return 32}epsilon(){return super.epsilon()}};$h.nextDataId=0;var _h={};Xe(_h,{addImpl:()=>q4,bincountImpl:()=>i3,bincountReduceImpl:()=>X4,castImpl:()=>j4,ceilImpl:()=>K4,concatImpl:()=>o3,equalImpl:()=>Z4,expImpl:()=>J4,expm1Impl:()=>e7,floorImpl:()=>t7,gatherNdImpl:()=>a7,gatherV2Impl:()=>n7,greaterEqualImpl:()=>s7,greaterImpl:()=>r7,lessEqualImpl:()=>o7,lessImpl:()=>i7,linSpaceImpl:()=>l7,logImpl:()=>u7,maxImpl:()=>d7,maximumImpl:()=>p7,minimumImpl:()=>c7,multiplyImpl:()=>l3,negImpl:()=>h7,notEqualImpl:()=>f7,prodImpl:()=>m7,raggedGatherImpl:()=>g7,raggedRangeImpl:()=>x7,raggedTensorToTensorImpl:()=>A7,rangeImpl:()=>d3,rsqrtImpl:()=>y7,scatterImpl:()=>tl,sigmoidImpl:()=>bO,simpleAbsImpl:()=>H4,sliceImpl:()=>_c,sparseFillEmptyRowsImpl:()=>v7,sparseReshapeImpl:()=>w7,sparseSegmentReductionImpl:()=>p3,sqrtImpl:()=>kO,squaredDifferenceImpl:()=>k7,stridedSliceImpl:()=>I7,stringNGramsImpl:()=>c3,stringSplitImpl:()=>h3,stringToHashBucketFastImpl:()=>f3,subImpl:()=>S7,tileImpl:()=>T7,topKImpl:()=>N7,transposeImpl:()=>u3,uniqueImpl:()=>E7});function H4(e){let t=new Float32Array(e.length);for(let a=0;a{let{x:t}=e.inputs,a=e.backend;ye(t,"abs");let n=new Float32Array(v.sizeFromShape(t.shape)),r=a.data.get(t.dataId).values;return n=H4(r),a.makeOutput(n,t.shape,t.dtype)},NF={kernelName:wl,backendName:"cpu",kernelFunc:CF};function Lt(e){return(t,a,n,r,s)=>{let i=T.assertAndGetBroadcastShape(t,a),o=i.length,l=v.computeStrides(i),u=v.sizeFromShape(i),p=v.getTypedArrayFromDType(s,u),c=t.length,d=a.length,h=v.computeStrides(t),f=v.computeStrides(a),m=T.getBroadcastDims(t,i),g=T.getBroadcastDims(a,i);if(m.length+g.length===0)for(let x=0;xy[C]=0);let b=v.locToIndex(y,c,h),w=A.slice(-d);g.forEach(C=>w[C]=0);let S=v.locToIndex(w,d,f);p[x]=e(n[b],r[S])}return[p,i]}}function Xa(e){let{inputs:t,backend:a}=e,{real:n,imag:r}=t,s=a.data.get(n.dataId).values,i=a.data.get(r.dataId).values,o=a.makeTensorInfo(n.shape,"complex64"),l=a.data.get(o.dataId);return l.complexTensorInfos={real:a.makeTensorInfo(n.shape,"float32",s),imag:a.makeTensorInfo(r.shape,"float32",i)},o}var EF={kernelName:Sd,backendName:"cpu",kernelFunc:Xa};function $c(e,t,a="float32"){if(a==="complex64"){let r=$c(e,t,"float32"),s=$c(e,t,"float32");return Xa({inputs:{real:r,imag:s},backend:e})}let n=v.makeZerosTypedArray(v.sizeFromShape(t),a);return e.makeTensorInfo(t,a,n)}function er(e){let{inputs:t,backend:a}=e,{x:n}=t;return a.incRef(n.dataId),{dataId:n.dataId,shape:n.shape,dtype:n.dtype}}var RF={kernelName:ki,backendName:"cpu",kernelFunc:er};function Us(e){let{inputs:t,backend:a}=e,{input:n}=t,r=a.data.get(n.dataId).complexTensorInfos.real,s=a.data.get(r.dataId).values;return a.makeTensorInfo(r.shape,r.dtype,s)}var MF={kernelName:Md,backendName:"cpu",kernelFunc:Us};function j4(e,t,a,n){if(n==="int32"){let r=Int32Array.from(e);return[t,"int32",r]}if(n==="bool"){let r=v.toTypedArray([0],a),[s,i]=Lt((o,l)=>o!==l?1:0)(t,[],e,r,"bool");return[i,"bool",s]}throw new Error(`Error in Cast: failed to cast ${a} to ${n}`)}function Jr(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{dtype:s}=n;if(s==="complex64"){if(r.dtype==="complex64")return er({inputs:{x:r},backend:a});let p=$c(a,r.shape,r.dtype),c=Jr({inputs:{x:r},backend:a,attrs:{dtype:"float32"}}),d=Xa({inputs:{real:c,imag:p},backend:a});return a.disposeIntermediateTensorInfo(p),a.disposeIntermediateTensorInfo(c),d}if(r.dtype==="complex64"){let p=Us({inputs:{input:r},backend:a}),c=Jr({inputs:{x:p},backend:a,attrs:{dtype:s}});return a.disposeIntermediateTensorInfo(p),c}if(!v.hasEncodingLoss(r.dtype,s)){let p=er({inputs:{x:r},backend:a});return{dataId:p.dataId,shape:p.shape,dtype:s}}let i=a.data.get(r.dataId).values,[o,l,u]=j4(i,r.shape,r.dtype,s);return a.makeTensorInfo(o,l,u)}var $F={kernelName:ti,backendName:"cpu",kernelFunc:Jr};function Yt(e,t,a,n){return a==null?({inputs:r,backend:s})=>{let{a:i,b:o}=r,l=s;ye([i,o],e);let u=l.data.get(i.dataId).values,p=l.data.get(o.dataId).values,c=i.dtype==="string"?T.fromUint8ToStringArray(u):u,d=i.dtype==="string"?T.fromUint8ToStringArray(p):p,h=n||i.dtype,[f,m]=t(i.shape,o.shape,c,d,h);return l.makeTensorInfo(m,h,f)}:({inputs:r,backend:s})=>{let{a:i,b:o}=r,l=s;if(i.dtype==="complex64"||o.dtype==="complex64"){let u=Jr({inputs:{x:i},backend:l,attrs:{dtype:"complex64"}}),p=l.data.get(u.dataId),c=p.complexTensorInfos.real,d=p.complexTensorInfos.imag,h=l.data.get(c.dataId).values,f=l.data.get(d.dataId).values,m=Jr({inputs:{x:o},backend:l,attrs:{dtype:"complex64"}}),g=l.data.get(m.dataId),x=g.complexTensorInfos.real,A=g.complexTensorInfos.imag,y=l.data.get(x.dataId).values,b=l.data.get(A.dataId).values,[w,S,C]=a(i.shape,o.shape,h,f,y,b),E=l.makeTensorInfo(C,"float32",w),_=l.makeTensorInfo(C,"float32",S),$=Xa({inputs:{real:E,imag:_},backend:l});return l.disposeIntermediateTensorInfo(u),l.disposeIntermediateTensorInfo(m),l.disposeIntermediateTensorInfo(E),l.disposeIntermediateTensorInfo(_),$}else{let u=l.data.get(i.dataId).values,p=l.data.get(o.dataId).values,c=n||i.dtype,[d,h]=t(i.shape,o.shape,u,p,c);return l.makeTensorInfo(h,c,d)}}}function s3(e){return(t,a,n,r,s,i)=>{let o=T.assertAndGetBroadcastShape(t,a),l=v.sizeFromShape(o),u=o.length,p=v.computeStrides(o),c=v.getTypedArrayFromDType("float32",l),d=v.getTypedArrayFromDType("float32",l),h=T.getBroadcastDims(t,o),f=T.getBroadcastDims(a,o),m=T.mergeRealAndImagArrays(n,r),g=T.mergeRealAndImagArrays(s,i),x=t.length,A=v.computeStrides(t),y=a.length,b=v.computeStrides(a);if(h.length+f.length===0)for(let w=0;wC[I]=0);let E=v.locToIndex(C,x,A),_=S.slice(-y);f.forEach(I=>_[I]=0);let $=v.locToIndex(_,y,b),M=e(m[E*2],m[E*2+1],g[$*2],g[$*2+1]);c[w]=M.real,d[w]=M.imag}return[c,d,o]}}var q4=Lt((e,t)=>e+t),_F=s3((e,t,a,n)=>({real:e+a,imag:t+n})),ml=Yt(ts,q4,_F),PF={kernelName:ts,backendName:"cpu",kernelFunc:ml};function i3(e,t,a,n,r){let s=v.sizeFromShape(n),i=v.makeZerosTypedArray(r,a);for(let o=0;o=r||(s>0?i[l]+=t[o]:i[l]+=1)}return i}function X4(e,t,a,n=!1){let r=e.shape[0],s=e.shape[1],i=Me([r,a],t.dtype);for(let o=0;o=a||(n?i.set(1,o,u):t.size>0?i.set(i.get(o,u)+t.get(o,l),o,u):i.set(i.get(o,u)+1,o,u))}return i}function os(e){return(t,a,n)=>{let r=v.getTypedArrayFromDType(a,t.length);for(let s=0;s{let{x:i}=n;if(ye(i,e),i.dtype==="string"||a==="string")throw new Error("unaryKernelFunc does not support string input/output");let o=s,l=o.data.get(i.dataId).values,u=v.sizeFromShape(i.shape),p=a||i.dtype,c=v.getArrayFromDType(p,u);for(let d=0;d{let{x:i}=n;if(ye(i,e),i.dtype==="string"||a==="string")throw new Error("unaryKernelFunc does not support string input/output");let o=s,l=o.data.get(i.dataId).values,u=a||i.dtype,p=t(l,u,r);return o.makeTensorInfo(i.shape,u,p)}}var K4=os(e=>Math.ceil(e)),FF=ou(ai,K4),OF={kernelName:ai,backendName:"cpu",kernelFunc:FF};function o3(e,t,a,n){let r=v.getArrayFromDType(a,v.sizeFromShape(t));if(n&&a!=="string"){let s=0;e.forEach(i=>{let o=v.sizeFromShape(i.shape);r.set(i.vals,s),s+=o})}else{let s=0;e.forEach(i=>{let o=a==="string"?T.fromUint8ToStringArray(i.vals):i.vals,l=0;for(let u=0;ue===t?1:0),Y4=Yt(fi,Z4,null,"bool"),DF={kernelName:fi,backendName:"cpu",kernelFunc:Y4},J4=os(e=>Math.exp(e)),Q4=ou(mi,J4,"float32"),zF={kernelName:mi,backendName:"cpu",kernelFunc:Q4},e7=os(e=>Math.expm1(e)),LF=ou(Pl,e7),BF={kernelName:Pl,backendName:"cpu",kernelFunc:LF},t7=os(e=>Math.floor(e)),WF=ou(xi,t7),VF={kernelName:xi,backendName:"cpu",kernelFunc:WF};function a7(e,t,a,n,r,s,i,o,l){let u=Me([n,s],a);for(let p=0;p=l/s)throw new Error(`Invalid indices: ${c} does not index into ${o}`);for(let h=0;he>t?1:0),UF=Yt(vi,r7,null,"bool"),GF={kernelName:vi,backendName:"cpu",kernelFunc:UF},s7=Lt((e,t)=>e>=t?1:0),HF=Yt(wi,s7,null,"bool"),jF={kernelName:wi,backendName:"cpu",kernelFunc:HF},i7=Lt((e,t)=>ee<=t?1:0),KF=Yt(Ci,o7,null,"bool"),ZF={kernelName:Ci,backendName:"cpu",kernelFunc:KF};function l7(e,t,a){let n=(t-e)/(a-1),r=v.makeZerosTypedArray(a,"float32");r[0]=e;for(let s=1;sMath.log(e)),YF=ou(Ni,u7),JF={kernelName:Ni,backendName:"cpu",kernelFunc:YF};function d7(e,t,a,n){let r=v.getTypedArrayFromDType(n,v.sizeFromShape(a));for(let s=0;so)&&(o=u)}r[s]=o}return r}var p7=Lt((e,t)=>Math.max(e,t)),QF=Yt($i,p7),eO={kernelName:$i,backendName:"cpu",kernelFunc:QF},c7=Lt((e,t)=>Math.min(e,t)),tO=Yt(Oi,c7),aO={kernelName:Oi,backendName:"cpu",kernelFunc:tO},l3=Lt((e,t)=>e*t),nO=s3((e,t,a,n)=>({real:e*a-t*n,imag:e*n+t*a})),Ph=Yt(zi,l3,nO),rO={kernelName:zi,backendName:"cpu",kernelFunc:Ph};function h7(e,t,a){let n=v.createScalarValue(-1,a);return l3([],t,n,e,a)}function sO(e){let{inputs:t,backend:a}=e,{x:n}=t;ye(n,"neg");let r=a.data.get(n.dataId).values,[s,i]=h7(r,n.shape,n.dtype);return a.makeTensorInfo(i,n.dtype,s)}var iO={kernelName:Vl,backendName:"cpu",kernelFunc:sO},f7=Lt((e,t)=>e!==t?1:0),oO=Yt(Li,f7,null,"bool"),lO={kernelName:Li,backendName:"cpu",kernelFunc:oO};function u3(e,t,a,n,r){let s=t.length,i=v.sizeFromShape(t),o=v.computeStrides(t),l=v.computeStrides(r),u=v.getTypedArrayFromDType(a,v.sizeFromShape(r));for(let p=0;pa.disposeIntermediateTensorInfo(A)),a.makeTensorInfo(x,g,f)}var pO={kernelName:ji,backendName:"cpu",kernelFunc:dO};function cO(e,t,a){e.forEach((n,r)=>{if(n<0||n>=a){let s=v.indexToLoc(r,t.length,v.computeStrides(t)).join(",");throw new Error(`indices[${s}] = ${n} is not in [0, ${a})`)}})}function hO(e,t){for(let a=0;ar)throw new Error("Ragged splits must not point past values");for(let s=1;sn[s])throw new Error("Ragged splits must be sorted in ascending order")}}function fO(e,t,a,n){let r=[],s=0,i=t.length-1+a.length,o=new Array(i).fill(null).map(()=>[0]);hO(a,n);let l=1;for(let u=0;u=0){let m=o[f],g=m[m.length-1]-h[p];for(let x=p;xr[i]=s)}return t}function ix(e,t){let a=e.slice(0,t);for(;a.length1)throw new Error("starts must be a scalar or vector");if(r.length>1)throw new Error("limits must be a scalar or vector");if(i.length>1)throw new Error("deltas must be a scalar or vector");let o=t.length===0,l=r.length===0,u=i.length===0,p=[];o||p.push(t[0]),l||p.push(r[0]),u||p.push(i[0]);for(let g=1;g0&&Ax)b=0;else if(b=Math.ceil(Math.abs((A-x)/y)),b>ox)throw new Error(`Requires ((limit - start) / delta) <= ${ox}`);d[g+1]=d[g]+b}let h=d[c],f=v.getArrayFromDType(a,h),m=0;for(let g=0;ga&&(a=r)}return a}static getMaxWidthValueRowID(e){let t=e.length;if(t===0)return 0;let a=0,n=e[0],r=0;for(let s=1;s"Final length of result must be equal to firstDimension."),r}calculateOutputIndexRowSplit(e,t,a,n){let r=e.length,s=[];for(let i=0;i0&&s.length!==e[r-1])throw new Error("Invalid row split size.");return s}calculateOutputIndexValueRowID(e,t,a,n){let r=e.length,s=[];if(r===0)return[];let i=0,o=e[0];if(o>=t.length)throw new Error(`Got currentValueRowId=${o}, which is not less than ${t.length}`);let l=t[o];s.push(l);for(let u=1;u=0&&(++i,i=t.length)throw new Error(`Got nextValueRowId=${p} which is not less than ${t.length}`);l=t[p]}s.push(l)}if(s.length!==e.length)throw new Error("Invalid row ids.");return s}calculateOutputIndex(e,t,a,n){let r=this.getRowPartitionTensor(e),s=this.getRowPartitionTypeByDimension(e);switch(s){case vn.VALUE_ROWIDS:return this.calculateOutputIndexValueRowID(r,t,a,n);case vn.ROW_SPLITS:if(r.length-1>t.length)throw new Error(`Row partition size is greater than output size: ${r.length-1} > ${t.length}`);return this.calculateOutputIndexRowSplit(r,t,a,n);default:throw new Error(`Unsupported partition type: ${vn[s]}`)}}getFirstDimensionSize(){let e=this.rowPartitionValues[0];if(this.rowPartitionTypes.length===0)throw new Error("No row_partition_types given.");let t=this.rowPartitionTypes[0];switch(t){case vn.FIRST_DIM_SIZE:return e[0];case vn.VALUE_ROWIDS:throw new Error("Cannot handle VALUE_ROWIDS in first dimension.");case vn.ROW_SPLITS:return this.rowPartitionValuesShapes[0][0]-1;default:throw new Error(`Cannot handle type ${vn[t]}`)}}compute(){if(this.rowPartitionValues[0].length<=0)throw new Error("Invalid first partition input. Tensor requires at least one element.");let e=this.getFirstDimensionSize(),t=this.calculateOutputSize(e),a=new Array(this.raggedRank+1);a[a.length-1]=1;for(let s=a.length-2;s>=0;--s)a[s]=a[s+1]*t[s+1];let n=ux(t,!1),r=v.getArrayFromDType(this.valuesDType,v.sizeFromShape(n));if(a[0]*t[0]>0){let s=this.calculateFirstParentOutputIndex(e,a[0],t[0]);for(let i=1;i<=this.raggedRank;++i)s=this.calculateOutputIndex(i-1,s,a[i],t[i]);this.setOutput(this.raggedRank,s,r,n)}return[n,r]}setOutput(e,t,a,n){if(a.length===0)return;let r=this.values,s=a,i=n.slice();i=i.slice(e+1);let o=v.sizeFromShape(i),l=t.length,u=this.defaultValue;if(u.length!==o&&u.length!==1){let h=this.defaultValueShape;$e(()=>{let f=J(u,h);u=sl(f,i).dataSync()})}let p=0,c=0,d=0;for(let h=0;h<=l;++h){let f=h=l){let m=a.length;f=Math.floor(m/o)}if(f>d)if(this.defaultValue.length===1)s.subarray(d*o,f*o).fill(this.defaultValue[0]),d=f;else for(;f>d;){let m=s.slice(d*o);lx(m,u,o),++d}f<0?(p=h+1,c=d):(p=h,c=d,d=c+1)}}};function lx(e,t,a){for(let n=0;n= 0`);if(n<-1)throw new Error(`Dimension ${n} must be >= -1`);n=-1}a.push(n)}return a}function A7(e,t,a,n,r,s,i,o,l,u){return new y1(e,t,a,n,r,s,i,o,l,u).compute()}function d3(e,t,a,n){let r=e===t,s=e1;if(r||s||i)return v.makeZerosTypedArray(0,n);let o=Math.abs(Math.ceil((t-e)/a)),l=v.makeZerosTypedArray(o,n);t1/Math.sqrt(e)),AO=ou(Qi,y7),yO={kernelName:Qi,backendName:"cpu",kernelFunc:AO};function tl(e,t,a,n,r,s,i,o,l,u){let p=[n/r,r],c=e.values,d=t.values;if(n===0)return Me(a,t.dtype);let h=Me(p,t.dtype);typeof l=="string"||typeof l=="number"?h.values.fill(l):typeof l=="boolean"&&h.values.fill(+l);for(let f=0;f=n/r)throw new Error(`Invalid indices: ${m} does not index into ${a}`);for(let x=0;x1/(1+Math.exp(-e))),b7=ot(ao,e=>1/(1+Math.exp(-e))),vO={kernelName:ao,backendName:"cpu",kernelFunc:b7};function _c(e,t,a,n,r){let s=It.isSliceContinous(n,t,a),i=v.sizeFromShape(a),o=v.computeStrides(n);if(s){let c=It.computeFlatOffset(t,o);return r==="string"?e.slice(c,c+i):e.subarray(c,c+i)}let l=r==="string"?T.fromUint8ToStringArray(e):e,u=Me(n,r,l),p=Me(a,r);for(let c=0;cf+t[m]);p.set(u.get(...h),...d)}return r==="string"?T.fromStringArrayToUint8(p.values):p.values}function Gs(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{begin:s,size:i}=n;ye(r,"slice");let[o,l]=It.parseSliceParams(r,s,i);It.assertParamsValid(r,o,l);let u=a.data.get(r.dataId).values,p=_c(u,o,l,r.shape,r.dtype);return a.makeTensorInfo(l,r.dtype,p)}var wO={kernelName:Zl,backendName:"cpu",kernelFunc:Gs};function v7(e,t,a,n,r,s,i){let o=t[0],l=s[0],u=new Array(l),p=new Array(o),c=t[1];if(l===0){if(o!==0)throw new Error(T.getSparseFillEmptyRowsIndicesDenseShapeMismatch(o));let g=v.getArrayFromDType(a,0),x=v.getArrayFromDType(r,0);return[g,[0,c],x,u,p]}let d=!0,h=0,f=new Array(l).fill(0);for(let g=0;g=l)throw new Error(T.getSparseFillEmptyRowsOutOfRangeIndexErrorMessage(g,x,l));++f[x],d=d&&x>=h,h=x}let m=!0;for(let g=0;g0&&(f[g]+=f[g-1])}if(m&&d){let g=e,x=n;for(let A=0;A0){d[c-1]=1;for(let m=c-2;m>=0;--m)d[m]=d[m+1]*n[m+1]}let h=[];if(o>0){h[o-1]=1;for(let m=o-2;m>=0;--m)h[m]=h[m+1]*l[m+1]}let f=v.getArrayFromDType(a,i*o);for(let m=0;m0?r[o-1]+1:0;if(p<0)throw new Error(T.getSparseSegmentReductionNegativeSegmentIdsErrorMessage());let c=t.slice();c[0]=p;let d=c.reduce((A,y)=>A*y,1),h=v.getArrayFromDType(a,d);if(o===0)return p>0&&h.fill(i),[h,c];if(p<=0)throw new Error(T.getSparseSegmentReductionNegativeSegmentIdsErrorMessage());let f=0,m=1,g=0,x=r[f];for(;;){let A=0;if(m=A)throw new Error(T.getSparseSegmentReductionNonIncreasingSegmentIdsErrorMessage())}if(x<0||x>=p)throw new Error(T.getSparseSegmentReductionSegmentIdOutOfRangeErrorMessage(x,p));x>g&&h.fill(i,g*u,x*u);for(let y=f;y=l[0])throw new Error(T.getSparseSegmentReductionIndicesOutOfRangeErrorMessage(y,n[y],l[0]));for(let w=0;wo)break}return gMath.sqrt(e)),IO=ot(no,e=>Math.sqrt(e)),SO={kernelName:no,backendName:"cpu",kernelFunc:IO},k7=Lt((e,t)=>{let a=e-t;return a*a}),TO=Yt(io,k7),CO={kernelName:io,backendName:"cpu",kernelFunc:TO};function I7(e,t,a,n){let r=Me(e,t.dtype);for(let s=0;s0?0:i-o),d=0;d+=l*this.leftPad.length;for(let x=0;xx.forEach(A=>f[m++]=A);for(let x=0;x0){g(e[c+p-1]);for(let x=0;x0){let o=t[0];if(o!==0)throw new Error(`First split value must be 0, got ${o}`);for(let l=1;l=o;if(u=u&&t[l]<=a,!u)throw new Error(`Invalid split value ${t[l]}, must be in [${o}, ${a}]`);o=t[l]}if(o!==a)throw new Error(`Last split value must be data size. Expected ${a}, got ${o}`)}let r=n-1,s=v.getArrayFromDType("int32",n);if(a===0||n===0){let o=new Array(a);for(let l=0;l<=r;++l)s[l]=0;return[o,s]}s[0]=0;for(let o=1;o<=r;++o){let l=t[o]-t[o-1],u=0;this.nGramWidths.forEach(p=>{u+=this.getNumNGrams(l,p)}),this.preserveShort&&l>0&&u===0&&(u=1),s[o]=s[o-1]+u}let i=new Array(s[r]);for(let o=0;o{let c=t[o+1]-t[o],d=this.getNumNGrams(c,p);this.createNGrams(e,l,i,u,d,p),u+=d}),this.preserveShort&&u===s[o]){let p=t[o+1]-t[o];if(p===0)continue;let c=p+2*this.padWidth,d=1;this.createNGrams(e,l,i,u,d,c)}}return[i,s]}};function c3(e,t,a,n,r,s,i,o){return new NO(a,n,r,s,i,o).compute(e,t)}function EO(e,t,a,n){if(!e.length)return;if(t.length===0){for(let s=0;se-t),RO=s3((e,t,a,n)=>({real:e-a,imag:t-n})),m3=Yt(lo,S7,RO),MO={kernelName:lo,backendName:"cpu",kernelFunc:m3};function T7(e,t){let a=new Array(e.rank);for(let r=0;r{let a=t.value-e.value;return a===0?e.index-t.index:a};function C7(e,t,a=0,n=e.length-1){for(;n>a;){if(n-a>600){let o=n-a+1,l=t-a+1,u=Math.log(o),p=.5*Math.exp(2*u/3),c=.5*Math.sqrt(u*p*(o-p)/o)*Math.sign(l-o/2),d=Math.max(a,Math.floor(t-l*p/o+c)),h=Math.min(n,Math.floor(t+(o-l)*p/o+c));C7(e,t,d,h)}let r=e[t],s=a,i=n;for(v.swap(e,a,t),Hu(e[n],r)>0&&v.swap(e,a,n);s0;)i=i-1}Hu(e[a],r)===0?v.swap(e,a,i):(i=i+1,v.swap(e,i,n)),i<=t&&(a=i+1),t<=i&&(n=i-1)}}function N7(e,t,a,n,r){let s=t[t.length-1],[i,o]=[e.length/s,s],l=v.getTypedArrayFromDType(a,i*n),u=v.getTypedArrayFromDType("int32",i*n);for(let c=0;cf[y]={value:A,index:y}),n{for(let g=0;gnew $h,1);var R7=ot(hi,e=>e>=0?e:Math.exp(e)-1),_O={kernelName:hi,backendName:"cpu",kernelFunc:R7};function M7(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{alpha:s}=n;ye([r],"leakyRelu");let i=v.sizeFromShape(r.shape),o=a.data.get(r.dataId).values,l=v.getTypedArrayFromDType("float32",i);for(let u=0;ue<0?t*e:e);function $7(e){let{inputs:t,backend:a}=e,{x:n,alpha:r}=t;ye([n,r],"prelu");let s=a.data.get(n.dataId).values,i=a.data.get(r.dataId).values,[o,l]=FO(n.shape,r.shape,s,i,"float32");return a.makeTensorInfo(l,"float32",o)}var OO={kernelName:Hi,backendName:"cpu",kernelFunc:$7},_7=ot(Xi,e=>Math.max(0,e)),DO={kernelName:Xi,backendName:"cpu",kernelFunc:_7},P7=ot(Yi,e=>Math.min(Math.max(0,e),6)),zO={kernelName:Yi,backendName:"cpu",kernelFunc:P7};function Pc(e,t,a,n,r){if(a==="linear")return er({inputs:{x:t},backend:e});if(a==="relu")return _7({inputs:{x:t},backend:e});if(a==="elu")return R7({inputs:{x:t},backend:e});if(a==="relu6")return P7({inputs:{x:t},backend:e});if(a==="prelu")return $7({inputs:{x:t,alpha:n},backend:e});if(a==="leakyrelu")return M7({inputs:{x:t},backend:e,attrs:{alpha:r}});if(a==="sigmoid")return b7({inputs:{x:t},backend:e});throw new Error(`Activation ${a} has not been implemented for the CPU backend.`)}function mt(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{shape:s}=n,i=v.sizeFromShape(r.shape),o=v.inferFromImplicitShape(s,i),l=v.sizeFromShape(o);v.assert(i===l,()=>`The new shape (${o}) has ${l} elements and the old shape (${r.shape}) has ${i} elements. The new shape and old shape must have the same number of elements.`),a.incRef(r.dataId);let u=a.data.get(r.dataId);if(u.complexTensorInfos!=null){let p=u.complexTensorInfos.real,c=u.complexTensorInfos.imag;p.shape=o,c.shape=o}return{dataId:r.dataId,shape:o,dtype:r.dtype}}var LO={kernelName:ql,backendName:"cpu",kernelFunc:mt};function F7(e){let{inputs:t,backend:a,attrs:n}=e,{a:r,b:s}=t,{transposeA:i,transposeB:o}=n;ye([r,s],"matMul");let l=r.shape.length,u=s.shape.length,p=i?r.shape[l-2]:r.shape[l-1],c=o?s.shape[u-1]:s.shape[u-2],d=i?r.shape[l-1]:r.shape[l-2],h=o?s.shape[u-2]:s.shape[u-1],f=r.shape.slice(0,-2),m=s.shape.slice(0,-2),g=v.sizeFromShape(f),x=v.sizeFromShape(m),A=xo.assertAndGetBroadcastShape(r.shape.slice(0,-2),s.shape.slice(0,-2)).concat([d,h]);v.assert(p===c,()=>`Error in matMul: inner shapes (${p}) and (${c}) of Tensors with shapes ${r.shape} and ${s.shape} and transposeA=${i} and transposeB=${o} must match.`);let y=i?[g,p,d]:[g,d,p],b=o?[x,h,c]:[x,c,h],w=mt({inputs:{x:r},backend:a,attrs:{shape:y}}),S=mt({inputs:{x:s},backend:a,attrs:{shape:b}}),C=i?w.shape[1]:w.shape[2],E=i?w.shape[2]:w.shape[1],_=o?S.shape[1]:S.shape[2],$=Math.max(g,x),M=a.data.get(w.dataId).values,I=a.data.get(S.dataId).values,N=v.computeStrides(w.shape),O=v.computeStrides(S.shape),[L,B,G]=i?[N[0],1,N[1]]:[N[0],N[1],1],[j,U,H]=o?[1,O[1],O[0]]:[O[1],1,O[0]],V=E*_,Q=Me([$,E,_],w.dtype),Z=Q.values,re=a.blockSize;for(let ee=0;ee<$;ee++)for(let he=0;heMath.acos(e)),GO={kernelName:kl,backendName:"cpu",kernelFunc:UO},HO=ot(Il,e=>Math.acosh(e)),jO={kernelName:Il,backendName:"cpu",kernelFunc:HO};function qO(e){let{inputs:t,backend:a}=e,n=t;ye(t,"addN");let r=n.map(o=>a.data.get(o.dataId).values),s=Me(n[0].shape,n[0].dtype),i=s.values;for(let o=0;oA&&(A=w,y=b)}h[g]=y}return u.forEach(g=>a.disposeIntermediateTensorInfo(g)),a.makeTensorInfo(p,"int32",h)}var eD={kernelName:Js,backendName:"cpu",kernelFunc:QO};function tD(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s}=n;ye(r,"argMin");let i=v.parseAxisParam(s,r.shape),o=T.getAxesPermutation(i,r.shape.length),l=r,u=[];o!=null&&(l=La({inputs:{x:r},backend:a,attrs:{perm:o}}),u.push(l),i=T.getInnerMostAxes(i.length,l.shape.length)),i=[i[0]],T.assertAxesAreInnerMostDims("argMin",i,l.shape.length);let[p,c]=T.computeOutAndReduceShapes(l.shape,i),d=v.sizeFromShape(p),h=v.makeZerosTypedArray(d,"int32"),f=v.sizeFromShape(c),m=a.data.get(l.dataId).values;for(let g=0;ga.disposeIntermediateTensorInfo(g)),a.makeTensorInfo(p,"int32",h)}var aD={kernelName:kd,backendName:"cpu",kernelFunc:tD},nD=ot(Sl,e=>Math.asin(e)),rD={kernelName:Sl,backendName:"cpu",kernelFunc:nD},sD=ot(Tl,e=>Math.asinh(e)),iD={kernelName:Tl,backendName:"cpu",kernelFunc:sD},oD=ot(Cl,e=>Math.atan(e)),lD={kernelName:Cl,backendName:"cpu",kernelFunc:oD},uD=Lt((e,t)=>Math.atan2(e,t)),dD=Yt(El,uD),pD={kernelName:El,backendName:"cpu",kernelFunc:dD},cD=ot(Nl,e=>Math.atanh(e)),hD={kernelName:Nl,backendName:"cpu",kernelFunc:cD};function g3(e,t,a,n,r,s){let i=r.strideHeight,o=r.strideWidth,l=r.dilationHeight,u=r.dilationWidth,p=r.effectiveFilterHeight,c=r.effectiveFilterWidth,d=r.padInfo.top,h=r.padInfo.left,f=s==="max"?Number.NEGATIVE_INFINITY:Number.POSITIVE_INFINITY,m=Me(r.outShape,a),g=m.values,x=r.outShape[1]*r.outShape[2]*r.outShape[3],A=r.outShape[2]*r.outShape[3],y=r.outShape[3];for(let b=0;bG?G=ee:s==="avg"&&(j+=ee,U++)}if(isNaN(G))break}let H=I+N*y+C;g[H]=s==="avg"?j/U:G}}}return m}function O7(e,t,a,n,r=!1,s=!1){let i=Me(n.outShape,"int32"),o=n.strideHeight,l=n.strideWidth,u=n.dilationHeight,p=n.dilationWidth,c=n.effectiveFilterHeight,d=n.effectiveFilterWidth,h=n.padInfo.top,f=n.padInfo.left,m=Me(t,a,e);for(let g=0;g$&&($=B,r?M=s?((g*n.inHeight+I)*n.inWidth+O)*n.inChannels+x:(I*n.inWidth+O)*n.inChannels+x:M=N*d+L)}}i.set(M,g,A,S,x)}}return i}function D7(e,t,a,n,r,s){let i=r.strideDepth,o=r.strideHeight,l=r.strideWidth,u=r.dilationDepth,p=r.dilationHeight,c=r.dilationWidth,d=r.effectiveFilterDepth,h=r.effectiveFilterHeight,f=r.effectiveFilterWidth,m=r.padInfo.front,g=r.padInfo.top,x=r.padInfo.left,A=s==="max"?Number.NEGATIVE_INFINITY:Number.POSITIVE_INFINITY,y=Me(r.outShape,a),b=y.values,w=r.outShape[1]*r.outShape[2]*r.outShape[3]*r.outShape[4],S=r.outShape[2]*r.outShape[3]*r.outShape[4],C=r.outShape[3]*r.outShape[4],E=r.outShape[4];for(let _=0;_Ae?Ae=ht:s==="avg"&&(we+=ht,Re++),isNaN(Ae))break}if(isNaN(Ae))break}if(isNaN(Ae))break}let Ge=oe+I;b[Ge]=s==="avg"?we/Re:Ae}}}}return y}function fD(e,t){let a=Me(t.outShape,"int32"),n=t.strideDepth,r=t.strideHeight,s=t.strideWidth,i=t.dilationDepth,o=t.dilationHeight,l=t.dilationWidth,u=t.effectiveFilterDepth,p=t.effectiveFilterHeight,c=t.effectiveFilterWidth,d=t.padInfo.front,h=t.padInfo.top,f=t.padInfo.left;for(let m=0;m=N&&(N=V,O=B*p*c+j*p+H)}}}a.set(O,m,x,w,_,g)}}}return a}function mD(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t;ye(r,"avgPool");let{filterSize:s,strides:i,pad:o,dimRoundingMode:l}=n,u=1;v.assert(T.eitherStridesOrDilationsAreOne(i,u),()=>`Error in avgPool: Either strides or dilations must be 1. Got strides ${i} and dilations '${u}'`);let p=T.computePool2DInfo(r.shape,s,i,u,o,l),c;if(p.filterWidth===1&&p.filterHeight===1&&v.arraysEqual(p.inShape,p.outShape))c=er({inputs:{x:r},backend:a});else{let d=a.data.get(r.dataId).values,h=v.computeStrides(r.shape),f=g3(d,r.shape,r.dtype,h,p,"avg");c=a.makeTensorInfo(p.outShape,r.dtype,f.values)}return c}var gD={kernelName:Qs,backendName:"cpu",kernelFunc:mD};function xD(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{filterSize:s,strides:i,pad:o,dimRoundingMode:l,dataFormat:u}=n;ye(r,"avgPool3d");let p=T.computePool3DInfo(r.shape,s,i,1,o,l,u),c=a.data.get(r.dataId).values,d=D7(c,r.shape,r.dtype,v.computeStrides(r.shape),p,"avg");return a.makeTensorInfo(d.shape,"float32",d.values)}var AD={kernelName:Hc,backendName:"cpu",kernelFunc:xD};function yD(e){let{inputs:t,backend:a,attrs:n}=e,{dy:r,input:s}=t,{filterSize:i,strides:o,pad:l,dimRoundingMode:u}=n;ye([r,s],"avgPool3DGrad");let p=T.computePool3DInfo(s.shape,i,o,1,l,u),c=p.strideDepth,d=p.strideHeight,h=p.strideWidth,f=p.filterDepth,m=p.filterHeight,g=p.filterWidth,x=p.dilationDepth,A=p.dilationHeight,y=p.dilationWidth,b=p.effectiveFilterDepth,w=p.effectiveFilterHeight,S=p.effectiveFilterWidth,C=b-1-p.padInfo.front,E=S-1-p.padInfo.left,_=w-1-p.padInfo.top,$=Me(s.shape,"float32"),M=1/(f*m*g),I=a.bufferSync(r);for(let N=0;N=p.outDepth||Math.floor(Z)!==Z))for(let re=0;re=p.outHeight||Math.floor(ee)!==ee))for(let he=0;he=p.outWidth||Math.floor(oe)!==oe)continue;let Ae=I.get(N,Z,ee,oe,O);V+=Ae}}}$.set(V*M,N,L,B,G,O)}return a.makeTensorInfo($.shape,$.dtype,$.values)}var bD={kernelName:G1,backendName:"cpu",kernelFunc:yD};function vD(e){let{inputs:t,backend:a,attrs:n}=e,{dy:r,input:s}=t,i=s;ye([r,s],"avgPoolGrad");let{filterSize:o,strides:l,pad:u}=n,p=T.computePool2DInfo(i.shape,o,l,1,u),c=p.strideHeight,d=p.strideWidth,h=p.filterHeight,f=p.filterWidth,m=p.dilationHeight,g=p.dilationWidth,x=p.effectiveFilterHeight,A=p.effectiveFilterWidth,y=A-1-p.padInfo.left,b=x-1-p.padInfo.top,w=Me(i.shape,"float32"),S=1/(h*f),C=a.data.get(r.dataId).values,E=Me(r.shape,"float32",C);for(let _=0;_=p.outHeight||Math.floor(G)!==G))for(let j=0;j=p.outWidth||Math.floor(U)!==U)continue;let H=E.get(_,G,U,$);L+=H}}w.set(L*S,_,M,I,$)}return a.makeTensorInfo(w.shape,w.dtype,w.values)}var wD={kernelName:U1,backendName:"cpu",kernelFunc:vD};function kD(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,scale:s,offset:i,mean:o,variance:l}=t;v.assert(o.shape.length===l.shape.length,()=>"Batch normalization gradient requires mean and variance to have equal ranks."),v.assert(i==null||o.shape.length===i.shape.length,()=>"Batch normalization gradient requires mean and offset to have equal ranks."),v.assert(s==null||o.shape.length===s.shape.length,()=>"Batch normalization gradient requires mean and scale to have equal ranks."),ye([r,o,l,s,i],"batchNorm");let{varianceEpsilon:u}=n;u==null&&(u=.001);let p=a.data.get(r.dataId).values,c=a.data.get(o.dataId).values,d=a.data.get(l.dataId).values,h=s?a.data.get(s.dataId).values:new Float32Array([1]),f=i?a.data.get(i.dataId).values:new Float32Array([0]),m=new Float32Array(p.length),g=f.length,x=h.length,A=d.length,y=c.length,b=0,w=0,S=0,C=0;for(let E=0;E=g&&(b=0),w>=y&&(w=0),S>=x&&(S=0),C>=A&&(C=0);return a.makeTensorInfo(r.shape,r.dtype,m)}var ID={kernelName:yi,backendName:"cpu",kernelFunc:kD};function SD(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{blockShape:s,crops:i}=n;ye([r],"batchToSpaceND");let o=s.reduce((x,A)=>x*A),l=T.getReshaped(r.shape,s,o),u=T.getPermuted(l.length,s.length),p=T.getReshapedPermuted(r.shape,s,o),c=T.getSliceBeginCoords(i,s.length),d=T.getSliceSize(p,i,s.length),h=mt({inputs:{x:r},backend:a,attrs:{shape:l}}),f=La({inputs:{x:h},backend:a,attrs:{perm:u}}),m=mt({inputs:{x:f},backend:a,attrs:{shape:p}}),g=Gs({inputs:{x:m},backend:a,attrs:{begin:c,size:d}});return a.disposeIntermediateTensorInfo(h),a.disposeIntermediateTensorInfo(f),a.disposeIntermediateTensorInfo(m),g}var TD={kernelName:Rl,backendName:"cpu",kernelFunc:SD};function CD(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,weights:s}=t,{size:i}=n,o=a.data.get(r.dataId).values,l=a.data.get(s.dataId).values,u=i3(o,l,s.dtype,s.shape,i);return a.makeTensorInfo([i],s.dtype,u)}var ND={kernelName:Id,backendName:"cpu",kernelFunc:CD};function ED(e){let{inputs:t,backend:a}=e,{s0:n,s1:r}=t,s=a.data.get(n.dataId).values,i=a.data.get(r.dataId).values,o=T.assertAndGetBroadcastShape(Array.from(s),Array.from(i));return a.makeTensorInfo([o.length],"int32",Int32Array.from(o))}var RD={kernelName:jc,backendName:"cpu",kernelFunc:ED},MD=ot(as,(e,t)=>{let a=t;return e>a.clipValueMax?a.clipValueMax:e{let{x:t}=e.inputs,a=e.backend,n=new Float32Array(v.sizeFromShape(t.shape)),r=a.data.get(t.dataId),s=r.complexTensorInfos.real,i=r.complexTensorInfos.imag,o=a.data.get(s.dataId).values,l=a.data.get(i.dataId).values;for(let u=0;um.shape);T.assertParamsConsistent(i,s);let o=T.computeOutShape(t.map(m=>m.shape),s);if(v.sizeFromShape(o)===0)return a.makeTensorInfo(o,t[0].dtype,[]);let l=t.filter(m=>v.sizeFromShape(m.shape)>0);if(l.length===1)return er({inputs:{x:l[0]},backend:a});if(l[0].dtype==="complex64"){let m=l.map(b=>Us({inputs:{input:b},backend:a})),g=l.map(b=>gl({inputs:{input:b},backend:a})),x=xl({inputs:m,backend:a,attrs:{axis:s}}),A=xl({inputs:g,backend:a,attrs:{axis:s}}),y=Xa({inputs:{real:x,imag:A},backend:a});return m.forEach(b=>a.disposeIntermediateTensorInfo(b)),g.forEach(b=>a.disposeIntermediateTensorInfo(b)),a.disposeIntermediateTensorInfo(x),a.disposeIntermediateTensorInfo(A),y}let u=l.map(m=>{let g=[-1,v.sizeFromShape(m.shape.slice(s))];return mt({inputs:{x:m},backend:a,attrs:{shape:g}})}),p=u.map(m=>({vals:a.data.get(m.dataId).values,shape:m.shape}));o=T.computeOutShape(u.map(m=>m.shape),1);let c=u[0].shape[0]===1,d=o3(p,o,t[0].dtype,c),h=T.computeOutShape(l.map(m=>m.shape),s),f=a.makeTensorInfo(h,t[0].dtype,d);return u.forEach(m=>a.disposeIntermediateTensorInfo(m)),f}var OD={kernelName:Ml,backendName:"cpu",kernelFunc:xl};function z7(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,filter:s}=t,{strides:i,pad:o,dataFormat:l,dilations:u,dimRoundingMode:p}=n;ye([r,s],"conv2d");let c=T.convertConv2DDataFormat(l),d=T.computeConv2DInfo(r.shape,s.shape,i,u,o,p,!1,c),h=d.filterHeight,f=d.filterWidth,m=d.dilationHeight,g=d.dilationWidth,x=d.padInfo.left,A=d.padInfo.top,y=d.dataFormat==="channelsLast",b=new jt(d.outShape,r.dtype),w=v.computeStrides(r.shape),S=v.computeStrides(s.shape),C=w[0],E=y?w[1]:w[2],_=y?w[2]:1,$=y?1:w[1],M=b.strides[0],I=y?b.strides[1]:b.strides[2],N=y?b.strides[2]:1,O=y?1:b.strides[1],L=a.data.get(r.dataId).values,B=a.data.get(s.dataId).values,G=b.values;for(let j=0;j=d.inHeight)continue;let he=re*S[0],oe=U+ee*E;for(let Ae=0;Ae=d.inWidth)continue;let nt=he+Ge*S[1],ut=oe+Ke*_,et=nt;for(let rt=0;rt=u.inDepth)continue;let j=B*_[0],U=M+G*E[1];for(let H=0;H=u.inHeight)continue;let ee=j+Z*_[1],he=U+re*E[2];for(let oe=0;oe=u.inWidth)continue;let Ke=ee+Re*_[2],nt=he+Ge*u.inChannels,ut=Ke;for(let et=0;etMath.cos(e)),KD={kernelName:si,backendName:"cpu",kernelFunc:XD},ZD=ot(ii,e=>Math.cosh(e)),YD={kernelName:ii,backendName:"cpu",kernelFunc:ZD};function JD(e){let{inputs:t,backend:a,attrs:n}=e,{image:r,boxes:s,boxInd:i}=t,{cropSize:o,method:l,extrapolationValue:u}=n,[p,c,d,h]=r.shape,f=s.shape[0],[m,g]=o,x=Me([f,m,g,h],"float32"),A=a.data.get(s.dataId).values,y=a.data.get(i.dataId).values,b=a.data.get(r.dataId).values,w=v.computeStrides(r.shape),S=v.computeStrides(x.shape);for(let C=0;C=p)continue;let O=m>1?(M-_)*(c-1)/(m-1):0,L=g>1?(I-$)*(d-1)/(g-1):0;for(let B=0;B1?_*(c-1)+B*O:.5*(_+M)*(c-1);if(G<0||G>c-1){for(let j=0;j1?$*(d-1)+V*L:.5*($+I)*(d-1);if(Q<0||Q>d-1){for(let he=0;he1?$*(d-1)+j*L:.5*($+I)*(d-1);if(U<0||U>d-1){for(let Q=0;Qx+f-A-1:(x,A)=>x+A;for(let x=0;xx+f-A-1:(x,A)=>x+A;for(let x=0;x`Only NHWC dataFormat supported on CPU for depthToSpace. Got ${i}`);let o=r.shape[0],l=r.shape[1],u=r.shape[2],p=r.shape[3],c=l*s,d=u*s,h=p/(s*s),f=a.data.get(r.dataId).values,m=new Float32Array(o*c*d*h),g=0;for(let x=0;x`Error in depthwiseConv2d: Either strides or dilations must be 1. Got strides ${i} and dilations '${d}'`);let h=T.computeConv2DInfo(r.shape,s.shape,i,d,o,u,!0),{filterHeight:f,filterWidth:m,dilationHeight:g,dilationWidth:x,padInfo:A}=h,y=A.left,b=A.top,w=h.outChannels/h.inChannels,S=new jt(h.outShape,r.dtype),C=a.data.get(r.dataId).values,E=a.data.get(s.dataId).values,_=S.values;for(let $=0;$=h.inHeight)continue;let j=B*c[0],U=M+G*p[1];for(let H=0;H=h.inWidth)continue;let ee=j+Z*c[1],he=U+re*h.inChannels,oe=V,Ae=ee;for(let we=0;we{let{x:n,filter:r}=e,{strides:s,pad:i,dilations:o}=a,l=t,u=l.data.get(n.dataId).values,p=n.shape.length,c=l.data.get(r.dataId).values,d=r.shape.length,{batchSize:h,inHeight:f,inWidth:m,inChannels:g,outHeight:x,outWidth:A,padInfo:y,strideHeight:b,strideWidth:w,filterHeight:S,filterWidth:C,dilationHeight:E,dilationWidth:_,outShape:$}=T.computeDilation2DInfo(n.shape,r.shape,s,i,"NHWC",o),M=v.sizeFromShape($),I=$.length,N=v.getArrayFromDType(n.dtype,M);for(let O=0;O=0&&Z=0&&eeH&&(H=Ae)}}}let V=v.locToIndex([O,L,G,U],I,v.computeStrides($));N[V]=H}}}return{dataId:l.write(v.toTypedArray(N,n.dtype),$,n.dtype),shape:$,dtype:n.dtype}}},gz={kernelName:Gm,backendName:"cpu",kernelFunc:({inputs:e,backend:t,attrs:a})=>{let{x:n,filter:r,dy:s}=e,{strides:i,pad:o,dilations:l}=a,u=t,p=v.toNestedArray(n.shape,u.data.get(n.dataId).values),c=v.toNestedArray(r.shape,u.data.get(r.dataId).values),{batchSize:d,inHeight:h,inWidth:f,inChannels:m,outHeight:g,outWidth:x,padInfo:A,strideHeight:y,strideWidth:b,filterHeight:w,filterWidth:S,dilationHeight:C,dilationWidth:E,outShape:_}=T.computeDilation2DInfo(n.shape,r.shape,i,o,"NHWC",l);v.assert(s.rank===_.length,()=>`Error in ${Gm}, dy must have the same rank as output ${_.length}, but got ${s.rank}`);let $=v.toNestedArray(_,u.data.get(s.dataId).values),M=v.makeZerosNestedTypedArray(r.shape,r.dtype);for(let I=0;I=0&&Q=0&&rej&&(j=ee,U=V,H=Z)}}}M[U][H][G]+=$[I][N][L][G]}}}return{dataId:u.write(v.toTypedArray(M,n.dtype),r.shape,r.dtype),shape:r.shape,dtype:r.dtype}}},xz={kernelName:Um,backendName:"cpu",kernelFunc:({inputs:e,backend:t,attrs:a})=>{let{x:n,filter:r,dy:s}=e,{strides:i,pad:o,dilations:l}=a,u=t,p=v.toNestedArray(n.shape,u.data.get(n.dataId).values),c=v.toNestedArray(r.shape,u.data.get(r.dataId).values),{batchSize:d,inHeight:h,inWidth:f,inChannels:m,outHeight:g,outWidth:x,padInfo:A,strideHeight:y,strideWidth:b,filterHeight:w,filterWidth:S,dilationHeight:C,dilationWidth:E,outShape:_}=T.computeDilation2DInfo(n.shape,r.shape,i,o,"NHWC",l);v.assert(s.rank===_.length,()=>`Error in ${Um}, dy must have the same rank as output ${_.length}, but got ${s.rank}`);let $=v.toNestedArray(_,u.data.get(s.dataId).values),M=v.makeZerosNestedTypedArray(n.shape,n.dtype);for(let I=0;I=0&&Q=0&&rej&&(j=ee,U=Q,H=re)}}}M[I][U][H][G]+=$[I][N][L][G]}}}return{dataId:u.write(v.toTypedArray(M,n.dtype),n.shape,n.dtype),shape:n.shape,dtype:n.dtype}}};function lp(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,keepDims:i}=n;ye(r,"sum");let o;r.dtype==="bool"?o=Jr({inputs:{x:r},backend:a,attrs:{dtype:"int32"}}):o=er({inputs:{x:r},backend:a});let l=o.shape.length,u=v.parseAxisParam(s,o.shape),p=T.getAxesPermutation(u,l),c=u,d=o;p!=null&&(d=La({inputs:{x:o},backend:a,attrs:{perm:p}}),c=T.getInnerMostAxes(c.length,l)),T.assertAxesAreInnerMostDims("sum",c,d.shape.length);let[h,f]=T.computeOutAndReduceShapes(d.shape,c),m=T.upcastType(d.dtype,"int32"),g=$c(a,h,m),x=v.sizeFromShape(f),A=a.data.get(g.dataId).values,y=a.data.get(d.dataId).values;for(let b=0;b=0&&(d=lp({inputs:{x:d},backend:a,attrs:{axis:u[m]-(i.length-h),keepDims:!1}}),f.push(d)),h--)}for(let m of f)m!==d&&a.disposeIntermediateTensorInfo(m);return d}var bz={kernelName:Cd,backendName:"cpu",kernelFunc:yz};function vz(e){let{inputs:t,backend:a}=e,{dy:n,y:r}=t;ye([n,r],"eluGrad");let s=new Float32Array(v.sizeFromShape(r.shape)),i=a.data.get(r.dataId).values,o=a.data.get(n.dataId).values;for(let l=0;l=1?s[l]=o[l]:s[l]=o[l]*(u+1)}return a.makeTensorInfo(r.shape,"float32",s)}var wz={kernelName:j1,backendName:"cpu",kernelFunc:vz},kz=T.ERF_P,Iz=T.ERF_A1,Sz=T.ERF_A2,Tz=T.ERF_A3,Cz=T.ERF_A4,Nz=T.ERF_A5,Ez=ot($l,e=>{let t=Math.sign(e),a=Math.abs(e),n=1/(1+kz*a);return t*(1-((((Nz*n+Cz)*n+Tz)*n+Sz)*n+Iz)*n*Math.exp(-a*a))}),Rz={kernelName:$l,backendName:"cpu",kernelFunc:Ez};function Fc(e){let{inputs:t,backend:a,attrs:n}=e,{input:r}=t,{dim:s}=n,i=r.shape.length,o=r.shape.slice(),l=s;return s<0&&(v.assert(-(i+1)<=s,()=>`Axis must be in the interval [${-(i+1)}, ${i}]`),l=i+s+1),o.splice(l,0,1),mt({inputs:{x:r},backend:a,attrs:{shape:o}})}var Mz={kernelName:_l,backendName:"cpu",kernelFunc:Fc},$z=Lt((e,t)=>e/t),x3=Yt(ci,$z),b1={kernelName:ci,backendName:"cpu",kernelFunc:x3};function B7(e,t,a){let n=e.shape,r=n[0],s=n[1],i=a.data.get(e.dataId),o=i.complexTensorInfos.real,l=i.complexTensorInfos.imag,u=[r,s],p=v.sizeFromShape(u),c=v.getTypedArrayFromDType("float32",p),d=v.getTypedArrayFromDType("float32",p);for(let g=0;g{let{image:n}=e,r=a,s=v.getTypedArrayFromDType(n.dtype,v.sizeFromShape(n.shape)),[i,o,l,u]=n.shape,p=r.data.get(n.dataId).values;for(let c=0;c=0&&AMath.floor(e/t)),Vz=Yt(Ai,Wz,null,"int32"),Uz={kernelName:Ai,backendName:"cpu",kernelFunc:Vz};function Gz(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,filter:s,bias:i,preluActivationWeights:o}=t,{strides:l,pad:u,dataFormat:p,dilations:c,dimRoundingMode:d,activation:h,leakyreluAlpha:f}=n,m=z7({inputs:{x:r,filter:s},backend:a,attrs:{strides:l,pad:u,dataFormat:p,dilations:c,dimRoundingMode:d}});if(i){let g=m;if(p==="NCHW"&&i.shape.length===1&&i.shape[0]!==1){let x=mt({inputs:{x:i},backend:a,attrs:{shape:[i.shape[0],1,1]}});m=ml({inputs:{a:m,b:x},backend:a}),a.disposeIntermediateTensorInfo(x)}else m=ml({inputs:{a:m,b:i},backend:a});a.disposeIntermediateTensorInfo(g)}if(h){let g=m;if(p==="NCHW"&&h==="prelu"&&o.shape.length===1&&o.shape[0]!==1){let x=mt({inputs:{x:o},backend:a,attrs:{shape:[o.shape[0],1,1]}});m=Pc(a,m,h,x,f),a.disposeIntermediateTensorInfo(x)}else m=Pc(a,m,h,o,f);a.disposeIntermediateTensorInfo(g)}return m}var Hz={kernelName:qr,backendName:"cpu",kernelFunc:Gz};function jz(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,filter:s,bias:i,preluActivationWeights:o}=t,{strides:l,pad:u,dataFormat:p,dilations:c,dimRoundingMode:d,activation:h,leakyreluAlpha:f}=n,m=L7({inputs:{x:r,filter:s},backend:a,attrs:{strides:l,pad:u,dataFormat:p,dilations:c,dimRoundingMode:d}});if(i){let g=m;m=ml({inputs:{a:m,b:i},backend:a}),a.disposeIntermediateTensorInfo(g)}if(h){let g=m;m=Pc(a,m,h,o,f),a.disposeIntermediateTensorInfo(g)}return m}var qz={kernelName:Xr,backendName:"cpu",kernelFunc:jz};function Xz(e){let{inputs:t,backend:a}=e,{params:n,indices:r}=t,s=v.sizeFromShape(n.shape),i=r.shape,o=i[i.length-1],[l,u,p,c]=T.prepareAndValidate(n,r);if(u===0)return a.makeTensorInfo(l,n.dtype,[]);let d=a.data.get(r.dataId).values,h=a.bufferSync(n),f=a7(d,h,n.dtype,u,o,p,c,n.shape,s);return a.makeTensorInfo(l,n.dtype,f.values)}var Kz={kernelName:bi,backendName:"cpu",kernelFunc:Xz};function Zz(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,indices:s}=t,{axis:i,batchDims:o}=n;ye([r,s],"gatherV2");let l=v.parseAxisParam(i,r.shape)[0],u=a.data.get(s.dataId).values,p=r.shape[l];for(let b=0;b=0,()=>`GatherV2: the index value ${w} is not in [0, ${p-1}]`)}let c=o;o==null&&(c=0);let d=v.sizeFromShape(s.shape),h=T.segment_util.collectGatherOpShapeInfo(r,s,l,c),f=mt({inputs:{x:r},backend:a,attrs:{shape:[h.batchSize,h.outerSize,h.dimSize,h.sliceSize]}}),m=mt({inputs:{x:s},backend:a,attrs:{shape:[h.batchSize,d/h.batchSize]}}),g=[h.batchSize,h.outerSize,d/h.batchSize,h.sliceSize],x=a.bufferSync(m),A=a.bufferSync(f),y=n7(A,x,g);return a.disposeIntermediateTensorInfo(f),a.disposeIntermediateTensorInfo(m),a.makeTensorInfo(h.outputShape,y.dtype,y.values)}var Yz={kernelName:Ol,backendName:"cpu",kernelFunc:Zz};function Jz(e){let{inputs:t,backend:a}=e,{input:n}=t,r=v.sizeFromShape(n.shape),s=n.shape[n.shape.length-1],i=r/s,o=mt({inputs:{x:n},backend:a,attrs:{shape:[i,s]}}),l=B7(o,!0,a),u=mt({inputs:{x:l},backend:a,attrs:{shape:n.shape}});return a.disposeIntermediateTensorInfo(o),a.disposeIntermediateTensorInfo(l),u}var Qz={kernelName:Ed,backendName:"cpu",kernelFunc:Jz},eL=ot(Dl,e=>Number.isFinite(e)?1:0,"bool"),tL={kernelName:Dl,backendName:"cpu",kernelFunc:eL},aL=ot(zl,e=>Math.abs(e)===1/0?1:0,"bool"),nL={kernelName:zl,backendName:"cpu",kernelFunc:aL},rL=ot(Ii,e=>Number.isNaN(e)?1:0,"bool"),sL={kernelName:Ii,backendName:"cpu",kernelFunc:rL};function iL(e){let{backend:t,attrs:a}=e,{start:n,stop:r,num:s}=a,i=l7(n,r,s);return t.makeTensorInfo([i.length],"float32",i)}var oL={kernelName:th,backendName:"cpu",kernelFunc:iL},lL=ot(Ll,e=>Math.log1p(e)),uL={kernelName:Ll,backendName:"cpu",kernelFunc:lL},dL=Lt((e,t)=>e&&t),pL=Yt(Ei,dL,null,"bool"),cL={kernelName:Ei,backendName:"cpu",kernelFunc:pL},hL=ot(Ri,e=>e?0:1,"bool"),fL={kernelName:Ri,backendName:"cpu",kernelFunc:hL},mL=Lt((e,t)=>e||t),gL=Yt(Bl,mL,null,"bool"),xL={kernelName:Bl,backendName:"cpu",kernelFunc:gL};function AL(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{depthRadius:s,bias:i,alpha:o,beta:l}=n;ye(r,"LRN");let u=r.shape[3],p=u-1,c=a.data.get(r.dataId).values,d=v.sizeFromShape(r.shape),h=new Float32Array(d);function f(m){let g=m%u,x=m-g+Math.max(0,g-s),A=m-g+Math.min(g+s,p),y=0;for(;x<=A;x++){let b=c[x];y+=b*b}return y}for(let m=0;m`Error in maxPool: Either strides or dilations must be 1. Got strides ${i} and dilations '${u}'`);let p=T.computePool2DInfo(r.shape,s,i,u,o,l),c;if(p.filterWidth===1&&p.filterHeight===1&&v.arraysEqual(p.inShape,p.outShape))c=er({inputs:{x:r},backend:a});else{let d=a.data.get(r.dataId).values,h=v.computeStrides(r.shape),f=g3(d,r.shape,r.dtype,h,p,"max");c=a.makeTensorInfo(p.outShape,r.dtype,f.values)}return c}var IL={kernelName:_i,backendName:"cpu",kernelFunc:kL};function SL(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{filterSize:s,strides:i,pad:o,dimRoundingMode:l,dataFormat:u}=n;ye(r,"maxPool3d");let p=T.computePool3DInfo(r.shape,s,i,1,o,l,u),c=a.data.get(r.dataId).values,d=D7(c,r.shape,r.dtype,v.computeStrides(r.shape),p,"max");return a.makeTensorInfo(d.shape,"float32",d.values)}var TL={kernelName:nh,backendName:"cpu",kernelFunc:SL};function CL(e){let{inputs:t,backend:a,attrs:n}=e,{dy:r,input:s}=t,{filterSize:i,strides:o,pad:l,dimRoundingMode:u}=n;ye([r,s],"maxPool3DGrad");let p=T.computePool3DInfo(s.shape,i,o,1,l,u),c=a.bufferSync(s),d=fD(c,p),h=p.strideDepth,f=p.strideHeight,m=p.strideWidth,g=p.dilationDepth,x=p.dilationHeight,A=p.dilationWidth,y=p.effectiveFilterDepth,b=p.effectiveFilterHeight,w=p.effectiveFilterWidth,S=y-1-p.padInfo.front,C=w-1-p.padInfo.left,E=b-1-p.padInfo.top,_=Me(s.shape,"float32"),$=a.bufferSync(r);for(let M=0;M=p.outDepth||Math.floor(V)!==V))for(let Q=0;Q=p.outHeight||Math.floor(Z)!==Z))for(let re=0;re=p.outWidth||Math.floor(ee)!==ee)continue;let he=y*b*w-1-d.get(M,V,Z,ee,I),oe=H*b*w+Q*w+re,Ae=he===oe?1:0;if(Ae===0)continue;let we=$.get(M,V,Z,ee,I);U+=we*Ae}}}_.set(U,M,N,O,L,I)}return a.makeTensorInfo(_.shape,_.dtype,_.values)}var NL={kernelName:K1,backendName:"cpu",kernelFunc:CL};function EL(e){let{inputs:t,backend:a,attrs:n}=e,{dy:r,input:s,output:i}=t,o=s;ye([s,i],"maxPoolGrad");let{filterSize:l,strides:u,pad:p,dimRoundingMode:c}=n,d=T.computePool2DInfo(o.shape,l,u,1,p,c),h=a.data.get(o.dataId).values,f=Me(d.outShape,o.dtype,O7(h,o.shape,o.dtype,d).values),m=d.strideHeight,g=d.strideWidth,x=d.dilationHeight,A=d.dilationWidth,y=d.effectiveFilterHeight,b=d.effectiveFilterWidth,w=b-1-d.padInfo.left,S=y-1-d.padInfo.top,C=Me(o.shape,"float32"),E=a.data.get(r.dataId).values,_=Me(r.shape,"float32",E);for(let $=0;$=d.outHeight||Math.floor(j)!==j))for(let U=0;U=d.outWidth||Math.floor(H)!==H)continue;let V=y*b-1-f.get($,j,H,M),Q=G*b+U,Z=V===Q?1:0;if(Z===0)continue;let re=_.get($,j,H,M);B+=re*Z}}C.set(B,$,I,N,M)}return a.makeTensorInfo(C.shape,C.dtype,C.values)}var RL={kernelName:X1,backendName:"cpu",kernelFunc:EL};function ML(e,t,a,n,r){let s=v.computeStrides(t),i=g3(e,t,a,s,r,"max"),o=O7(e,t,a,r,!0,n);return[i.values,o.values]}var $L={kernelName:rh,backendName:"cpu",kernelFunc:({inputs:e,attrs:t,backend:a})=>{let{x:n}=e,{filterSize:r,strides:s,pad:i,includeBatchInIndex:o}=t,l=a;ye(n,"MaxPoolWithArgmax");let u=l.data.get(n.dataId).values,p=T.computePool2DInfo(n.shape,r,s,[1,1],i),[c,d]=ML(u,n.shape,n.dtype,o,p),h=l.write(c,p.outShape,n.dtype),f=l.write(d,p.outShape,n.dtype);return[{dataId:h,shape:p.outShape,dtype:n.dtype},{dataId:f,shape:p.outShape,dtype:"int32"}]}};function _L(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,keepDims:i}=n,o=v.parseAxisParam(s,r.shape),l=T.computeOutAndReduceShapes(r.shape,o)[1],u=v.sizeFromShape(l),p=[],c=a.makeTensorInfo([],"float32",new Float32Array([u]));p.push(c);let d=Jr({inputs:{x:r},backend:a,attrs:{dtype:"float32"}});p.push(d);let h=x3({inputs:{a:d,b:c},backend:a});p.push(h);let f=lp({inputs:{x:h},backend:a,attrs:{axis:s,keepDims:i}});return p.forEach(m=>a.disposeIntermediateTensorInfo(m)),f}var PL={kernelName:Pi,backendName:"cpu",kernelFunc:_L};function FL(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,keepDims:i}=n;ye(r,"min");let o=v.parseAxisParam(s,r.shape),l=o,u=T.getAxesPermutation(l,r.shape.length),p=r;u!=null&&(p=La({inputs:{x:r},backend:a,attrs:{perm:u}}),l=T.getInnerMostAxes(l.length,r.shape.length)),T.assertAxesAreInnerMostDims("min",l,p.shape.length);let[c,d]=T.computeOutAndReduceShapes(p.shape,l),h=v.sizeFromShape(d),f=v.makeZerosTypedArray(v.sizeFromShape(c),p.dtype),m=a.data.get(p.dataId).values;for(let x=0;xA[0]+r.shape[y]+A[1]),l=s.map(A=>A[0]),u=s.map((A,y)=>A[0]+r.shape[y]),p=i==="reflect"?0:1,c=a.data.get(r.dataId).values,d=r.shape.length,h=v.computeStrides(r.shape),f=v.sizeFromShape(o),m=o.length,g=v.computeStrides(o),x=v.getTypedArrayFromDType(r.dtype,f);for(let A=0;A=u[w]&&(y[w]=(u[w]-1)*2-y[w]+p);y=y.map((w,S)=>w-l[S]);let b=v.locToIndex(y,d,h);x[A]=c[b]}return{dataId:a.write(x,o,r.dtype),shape:o,dtype:r.dtype}}var zL={kernelName:Di,backendName:"cpu",kernelFunc:DL},LL=Lt((e,t)=>{let a=e%t;return e<0&&t<0||e>=0&&t>=0?a:(a+t)%t}),BL=Yt(Wl,LL),WL={kernelName:Wl,backendName:"cpu",kernelFunc:BL},VL=yl(nA());function V7(e){let{inputs:t,backend:a,attrs:n}=e,{logits:r}=t,{dim:s}=n,i=r.shape.length,o=s;if(o===-1&&(o=i-1),o!==i-1)throw Error(`Softmax along a non-last dimension is not yet supported. Logits was rank ${i} and dim was ${o}`);let l=v.parseAxisParam([o],r.shape),u=W7({inputs:{x:r},backend:a,attrs:{reductionIndices:l,keepDims:!1}}),p=T.expandShapeToKeepDim(u.shape,l),c=mt({inputs:{x:u},backend:a,attrs:{shape:p}}),d=m3({inputs:{a:r,b:c},backend:a}),h=Q4({inputs:{x:d},backend:a}),f=lp({inputs:{x:h},backend:a,attrs:{axis:l,keepDims:!1}}),m=mt({inputs:{x:f},backend:a,attrs:{shape:p}}),g=x3({inputs:{a:h,b:m},backend:a});return a.disposeIntermediateTensorInfo(u),a.disposeIntermediateTensorInfo(c),a.disposeIntermediateTensorInfo(d),a.disposeIntermediateTensorInfo(h),a.disposeIntermediateTensorInfo(f),a.disposeIntermediateTensorInfo(m),g}var UL={kernelName:so,backendName:"cpu",kernelFunc:V7};function GL(e){let{inputs:t,backend:a,attrs:n}=e,{logits:r}=t,{numSamples:s,seed:i,normalized:o}=n;ye(r,"multinomial");let l=o?r:V7({inputs:{logits:r},backend:a,attrs:{dim:-1}}),u=l.shape[0],p=l.shape[1],c=a.data.get(l.dataId).values,d=[u,s],h=v.makeZerosTypedArray(v.sizeFromShape(d),"int32");for(let f=0;f=0&&c[d]{v.assertShapesMatch(s,p.shape,"All tensors passed to stack must have matching shapes"),v.assert(i===p.dtype,()=>"All tensors passed to stack must have matching dtypes")});let o=[],l=t.map(p=>{let c=Fc({inputs:{input:p},backend:a,attrs:{dim:r}});return o.push(c),c}),u=xl({inputs:l,backend:a,attrs:{axis:r}});return o.forEach(p=>a.disposeIntermediateTensorInfo(p)),u}var sB={kernelName:Hl,backendName:"cpu",kernelFunc:G7};function iB(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{paddings:s,constantValue:i}=n;ye(r,"pad");let o=s.map((x,A)=>x[0]+r.shape[A]+x[1]),l=s.map(x=>x[0]),u=a.data.get(r.dataId).values,p=v.sizeFromShape(r.shape),c=r.shape.length,d=v.computeStrides(r.shape),h=v.sizeFromShape(o),f=o.length,m=v.computeStrides(o),g=v.getTypedArrayFromDType(r.dtype,h);i!==0&&g.fill(i);for(let x=0;xb+l[w]),y=v.locToIndex(A,f,m);g[y]=u[x]}return{dataId:a.write(g,o,r.dtype),shape:o,dtype:r.dtype}}var H7={kernelName:Ui,backendName:"cpu",kernelFunc:iB},oB=Lt((e,t)=>Math.pow(e,t)),lB=Yt(Gi,oB),uB={kernelName:Gi,backendName:"cpu",kernelFunc:lB};function dB(e){let{inputs:t,backend:a,attrs:n}=e,{paramsNestedSplits:r,paramsDenseValues:s,indices:i}=t,{outputRaggedRank:o}=n,l=r.map(x=>a.data.get(x.dataId).values),u=r.map(x=>x.shape),p=a.data.get(s.dataId).values,c=a.data.get(i.dataId).values,[d,h,f]=g7(l,u,p,s.shape,s.dtype,c,i.shape,o),m=d.map(x=>a.makeTensorInfo([x.length],"int32",x)),g=a.makeTensorInfo(f,s.dtype,h);return m.concat([g])}var pB={kernelName:ih,backendName:"cpu",kernelFunc:dB};function cB(e){let{inputs:t,backend:a}=e,{starts:n,limits:r,deltas:s}=t,i=a.data.get(n.dataId).values,o=a.data.get(r.dataId).values,l=a.data.get(s.dataId).values,[u,p]=x7(i,n.shape,n.dtype,o,r.shape,l,s.shape),c=a.makeTensorInfo([u.length],"int32",u),d=a.makeTensorInfo([p.length],n.dtype,p);return[c,d]}var hB={kernelName:oh,backendName:"cpu",kernelFunc:cB};function fB(e){let{inputs:t,backend:a,attrs:n}=e,{shape:r,values:s,defaultValue:i,rowPartitionTensors:o}=t,{rowPartitionTypes:l}=n,u=a.data.get(r.dataId).values,p=a.data.get(s.dataId).values,c=a.data.get(i.dataId).values,d=o.map(g=>a.data.get(g.dataId).values),h=o.map(g=>g.shape),[f,m]=A7(u,r.shape,p,s.shape,s.dtype,c,i.shape,d,h,l);return a.makeTensorInfo(f,s.dtype,m)}var mB={kernelName:lh,backendName:"cpu",kernelFunc:fB};function gB(e){let{backend:t,attrs:a}=e,{start:n,stop:r,dtype:s,step:i}=a,o=d3(n,r,i,s);return t.makeTensorInfo([o.length],s,o)}var xB={kernelName:jl,backendName:"cpu",kernelFunc:gB},AB=ot(qi,e=>1/e),yB={kernelName:qi,backendName:"cpu",kernelFunc:AB};function bB(e){let{inputs:t,backend:a,attrs:n}=e,{images:r}=t,{alignCorners:s,halfPixelCenters:i,size:o}=n;ye(r,"resizeBilinear");let l=v.computeStrides(r.shape),[u,p]=o,[c,d,h,f]=r.shape,m=a.data.get(r.dataId).values,g=new Float32Array(v.sizeFromShape([c,u,p,f])),x=[s&&u>1?d-1:d,s&&p>1?h-1:h],A=[s&&u>1?u-1:u,s&&p>1?p-1:p],y=0,b=x[0]/A[0],w=x[1]/A[1];for(let S=0;S1?u-1:u,i&&h>1?p-1:p],g=[i&&d>1?d-1:d,i&&h>1?h-1:h],x=m[0]/g[0],A=m[1]/g[1],y=a.data.get(s.dataId).values,b=0;for(let w=0;w1?d-1:d,s&&p>1?h-1:h],A=[s&&u>1?u-1:u,s&&p>1?p-1:p],y=x[0]/A[0],b=x[1]/A[1],w=0;for(let S=0;S1?p-1:p,i&&f>1?c-1:c],A=[i&&h>1?h-1:h,i&&f>1?f-1:f],y=x[0]/A[0],b=x[1]/A[1],w=1/y,S=1/b,C=Math.ceil(w)*2+2,E=Math.ceil(S)*2+2;for(let _=0;_=h)continue;let Z=$+Q*l[1],re=Q*y,ee=Math.min(p-1,i?Math.round(re):Math.floor(re));if(M===ee)for(let he=0;he=f)continue;let Ae=Z+oe*l[2],we=oe*b,Re=Math.min(c-1,i?Math.round(we):Math.floor(we));L===Re&&(H+=g[Ae+U])}}m[B+U]=H}}}}return a.makeTensorInfo(r.shape,r.dtype,m)}var CB={kernelName:Z1,backendName:"cpu",kernelFunc:TB};function NB(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{dims:s}=n;ye(r,"reverse");let i=r.shape.length,o=v.parseAxisParam(s,r.shape);if(i===0)return er({inputs:{x:r},backend:a});let l=new jt(r.shape,r.dtype),u=a.bufferSync(r);for(let p=0;pd[h]=r.shape[h]-1-d[h]),l.set(u.get(...d),...c)}return a.makeTensorInfo(l.shape,l.dtype,l.values)}var EB={kernelName:Ji,backendName:"cpu",kernelFunc:NB},RB={kernelName:mo,backendName:"cpu",kernelFunc:({inputs:e,attrs:t,backend:a})=>{let{image:n}=e,{radians:r,fillValue:s,center:i}=t,o=a,l=v.getTypedArrayFromDType(n.dtype,v.sizeFromShape(n.shape)),[u,p,c,d]=n.shape,[h,f]=T.getImageCenter(i,p,c),m=255,g=Math.sin(r),x=Math.cos(r),A=o.data.get(n.dataId).values;for(let y=0;y=0&&N=0&&O{let t=Math.floor(e);return e-t<.5?Math.floor(e):e-t>.5?Math.ceil(e):t%2===0?t:t+1}),$B={kernelName:Xl,backendName:"cpu",kernelFunc:MB};function _B(e){let{inputs:t,backend:a,attrs:n}=e,{indices:r,updates:s}=t,{shape:i}=n,{sliceRank:o,numUpdates:l,sliceSize:u,strides:p,outputSize:c}=T.calculateShapes(s,r,i),d=!0,h=a.bufferSync(r),f=a.bufferSync(s),m=tl(h,f,i,c,u,l,o,p,0,d);return a.makeTensorInfo(i,m.dtype,m.values)}var PB={kernelName:eo,backendName:"cpu",kernelFunc:_B};function FB(e,t){let a=0,n=e.length,r=0;for(;a1||r.shape.length===1?1:v.sizeFromShape(r.shape.slice(1));for(let f=0;fe>=0?UB*e:VB*(Math.exp(e)-1)),HB={kernelName:_d,backendName:"cpu",kernelFunc:GB},jB=ot(Pd,e=>e<0?-1:e>0?1:0),qB={kernelName:Pd,backendName:"cpu",kernelFunc:jB},XB=ot(to,e=>Math.sin(e)),KB={kernelName:to,backendName:"cpu",kernelFunc:XB},ZB=ot(Yl,e=>Math.sinh(e)),YB={kernelName:Yl,backendName:"cpu",kernelFunc:ZB},JB=11920928955078125e-23,dx=Math.log(JB)+2,QB=ot(Fd,e=>{let t=e>-dx,a=eNumber(g)))),a.makeTensorInfo([m.length],n.dtype,new Int32Array(m))]}var rW={kernelName:Od,backendName:"cpu",kernelFunc:nW};function sW(e){let{inputs:t,backend:a}=e,{inputIndices:n,inputShape:r,newShape:s}=t;if(n.shape.length!==2)throw new Error(`Input indices should be a matrix but received shape ${n.shape}`);if(r.shape.length!==1)throw new Error(`Input shape should be a vector but received shape ${r.shape}`);if(s.shape.length!==1)throw new Error(`Target shape should be a vector but received shape ${s.shape}`);let i=Array.from(a.data.get(r.dataId).values),o=a.data.get(n.dataId).values,l=Array.from(a.data.get(s.dataId).values),[u,p,c]=w7(o,n.shape,n.dtype,i,l);return[a.makeTensorInfo(p,n.dtype,u),a.makeTensorInfo([c.length],s.dtype,new Int32Array(c))]}var iW={kernelName:eu,backendName:"cpu",kernelFunc:sW};function oW(e){let{inputs:t,backend:a}=e,{data:n,indices:r,segmentIds:s}=t;if(n.shape.length<1)throw new Error("Data should be at least 1 dimensional but received scalar");if(r.shape.length!==1)throw new Error(`Indices should be a vector but received shape ${r.shape}`);if(s.shape.length!==1)throw new Error(`Segment ids should be a vector but received shape ${s.shape}`);if(r.shape[0]!==s.shape[0])throw new Error("segmentIds and indices should have same size.");let i=a.data.get(n.dataId).values,o=a.data.get(r.dataId).values,l=a.data.get(s.dataId).values,[u,p]=p3(i,n.shape,n.dtype,o,l,!0);return a.makeTensorInfo(p,n.dtype,u)}var lW={kernelName:Dd,backendName:"cpu",kernelFunc:oW};function uW(e){let{inputs:t,backend:a}=e,{data:n,indices:r,segmentIds:s}=t;if(n.shape.length<1)throw new Error("Data should be at least 1 dimensional but received scalar");if(r.shape.length!==1)throw new Error(`Indices should be a vector but received shape ${r.shape}`);if(s.shape.length!==1)throw new Error(`Segment ids should be a vector but received shape ${s.shape}`);if(r.shape[0]!==s.shape[0])throw new Error("segmentIds and indices should have same size.");let i=a.data.get(n.dataId).values,o=a.data.get(r.dataId).values,l=a.data.get(s.dataId).values,[u,p]=p3(i,n.shape,n.dtype,o,l);return a.makeTensorInfo(p,n.dtype,u)}var dW={kernelName:zd,backendName:"cpu",kernelFunc:uW};function pW(e){let{inputs:t,backend:a,attrs:n}=e,{sparseIndices:r,sparseValues:s,defaultValue:i}=t,{outputShape:o}=n,{sliceRank:l,numUpdates:u,sliceSize:p,strides:c,outputSize:d}=T.calculateShapes(s,r,o),h=!1,f=a.bufferSync(r),m;switch(s.dtype){case"bool":{let g=a.bufferSync(s),x=Boolean(a.data.get(i.dataId).values[0]);m=tl(f,g,o,d,p,u,l,c,x,h);break}case"float32":{let g=a.bufferSync(s),x=a.data.get(i.dataId).values[0];m=tl(f,g,o,d,p,u,l,c,x,h);break}case"int32":{let g=a.bufferSync(s),x=a.data.get(i.dataId).values[0];m=tl(f,g,o,d,p,u,l,c,x,h);break}case"string":{let g=a.bufferSync(s),x=v.decodeString(a.data.get(i.dataId).values[0]);m=tl(f,g,o,d,p,u,l,c,x,h);break}default:throw new Error(`Unsupported type ${s.dtype}`)}return a.makeTensorInfo(o,m.dtype,m.values)}var cW={kernelName:Ld,backendName:"cpu",kernelFunc:pW};function hW(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{numOrSizeSplits:s,axis:i}=n,o=v.parseAxisParam(i,r.shape)[0],l=T.prepareSplitSize(r,s,o),u=new Array(r.shape.length).fill(0),p=r.shape.slice();return l.map(c=>{let d=[...p];d[o]=c;let h=Gs({inputs:{x:r},backend:a,attrs:{begin:u,size:d}});return u[o]+=c,h})}var fW={kernelName:Ql,backendName:"cpu",kernelFunc:hW},mW={kernelName:Bd,backendName:"cpu",kernelFunc:({inputs:e,backend:t})=>{let{x:a}=e,n=t;ye(a,"square");let r=n.data.get(a.dataId).values,s=new Float32Array(r.length);for(let i=0;i{let a=t;return isNaN(e)?NaN:e>0?1:a.alpha}),xW={kernelName:fo,backendName:"cpu",kernelFunc:gW};function AW(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{begin:s,end:i,strides:o,beginMask:l,endMask:u,ellipsisMask:p,newAxisMask:c,shrinkAxisMask:d}=n;ye(r,"stridedSlice");let{finalShapeSparse:h,finalShape:f,isIdentity:m,sliceDim0:g,isSimpleSlice:x,begin:A,end:y,strides:b}=It.sliceInfo(r.shape,s,i,o,l,u,p,c,d),w;if(m)w=mt({inputs:{x:r},backend:a,attrs:{shape:f}});else if(g||x){v.assert(r.shape.length>=1,()=>`Input must have rank at least 1, got: ${r.shape.length}`);let S=It.computeOutShape(A,y,b),C=Gs({inputs:{x:r},backend:a,attrs:{begin:A,size:S}});w=mt({inputs:{x:C},backend:a,attrs:{shape:f}}),a.disposeIntermediateTensorInfo(C)}else{let S=a.bufferSync(r),C=I7(h,S,b,A);w=a.makeTensorInfo(f,C.dtype,C.values)}return w}var yW={kernelName:oo,backendName:"cpu",kernelFunc:AW};function bW(e){let{inputs:t,backend:a,attrs:n}=e,{separator:r,nGramWidths:s,leftPad:i,rightPad:o,padWidth:l,preserveShortSequences:u}=n,{data:p,dataSplits:c}=t,d=a.data.get(p.dataId).values,h=a.data.get(c.dataId).values,[f,m]=c3(d,h,r,s,i,o,l,u);return[a.makeTensorInfo([f.length],"string",f),a.makeTensorInfo(c.shape,"int32",m)]}var vW={kernelName:tu,backendName:"cpu",kernelFunc:bW};function wW(e){let{inputs:t,backend:a,attrs:n}=e,{skipEmpty:r}=n,{input:s,delimiter:i}=t;if(s.dtype!=="string")throw new Error("Input must be of datatype string");if(s.shape.length!==1)throw new Error(`Input must be a vector, got shape: ${s.shape}`);if(i.shape.length!==0)throw new Error(`Delimiter must be a scalar, got shape: ${i.shape}`);let o=a.data.get(s.dataId).values,l=a.data.get(i.dataId).values[0],[u,p,c]=h3(o,l,r),d=p.length;return[a.makeTensorInfo([d,2],"int32",u),a.makeTensorInfo([d],"string",p),a.makeTensorInfo([2],"int32",new Int32Array(c))]}var kW={kernelName:Wd,backendName:"cpu",kernelFunc:wW};function IW(e){let{inputs:t,backend:a,attrs:n}=e,{numBuckets:r}=n,{input:s}=t;if(s.dtype!=="string")throw new Error("Input must be of datatype string");if(r<=0)throw new Error("Number of buckets must be at least 1");let i=a.data.get(s.dataId).values,o=f3(i,r);return a.makeTensorInfo(s.shape,"int32",o)}var SW={kernelName:Vd,backendName:"cpu",kernelFunc:IW},TW=ot(uo,e=>Math.tan(e)),CW={kernelName:uo,backendName:"cpu",kernelFunc:TW},NW=ot(po,e=>Math.tanh(e)),EW={kernelName:po,backendName:"cpu",kernelFunc:NW};function RW(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{reps:s}=n;ye(r,"tile");let i=T7(a.bufferSync(r),s);return a.makeTensorInfo(i.shape,i.dtype,i.values)}var MW={kernelName:ns,backendName:"cpu",kernelFunc:RW};function $W(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{k:s,sorted:i}=n;ye(r,"topk");let o=a.data.get(r.dataId).values,[l,u]=N7(o,r.shape,r.dtype,s,i);return[a.makeTensorInfo(l.shape,l.dtype,l.values),a.makeTensorInfo(u.shape,u.dtype,u.values)]}var _W={kernelName:co,backendName:"cpu",kernelFunc:$W};function PW(e){let{inputs:t,attrs:a,backend:n}=e,{image:r,transforms:s}=t,{interpolation:i,fillMode:o,fillValue:l,outputShape:u}=a,[p,c,d,h]=r.shape,[f,m]=u!=null?u:[c,d],g=[p,f,m,h],x=v.computeStrides(r.shape),A=x[0],y=x[1],b=x[2],w=v.computeStrides(g),S=w[0],C=w[1],E=w[2],_=v.getTypedArrayFromDType(r.dtype,v.sizeFromShape(g));_.fill(l);let $=n.data.get(r.dataId).values,M=n.data.get(s.dataId).values;for(let I=0;It-1)if(t<=1)a=0;else{let n=2*t;a-=n*Math.trunc(a/n),a>=t&&(a=n-a-1)}return v.clamp(0,a,t-1)}function DW(e,t){let a=e;if(a<0)if(t<=1)a=0;else{let n=t-1;a+=t*(Math.trunc(-a/n)+1)}else if(a>t-1)if(t<=1)a=0;else{let n=t-1;a-=t*Math.trunc(a/n)}return v.clamp(0,a,t-1)}function zW(e,t){return e}function LW(e,t){return v.clamp(0,e,t-1)}function ju(e,t,a,n,r,s,i,o,l,u,p){let c=i*n+o*r+l*s+u;return 0<=o&&oa.disposeIntermediateTensorInfo(f)),h}var qW={kernelName:dh,backendName:"cpu",kernelFunc:jW},XW=[VO,NF,GO,jO,PF,XO,ZO,JO,eD,aD,rD,iD,lD,pD,hD,gD,AD,bD,wD,BO,ID,TD,ND,RD,$F,OF,$D,EF,PD,OD,DD,LD,WD,UD,HD,qD,KD,YD,QD,tz,nz,sz,oz,lz,dz,cz,fz,mz,gz,xz,bz,_O,wz,DF,Rz,zF,Mz,BF,Dz,zz,Bz,VF,Uz,Hz,qz,Kz,Yz,GF,jF,RF,Qz,FD,tL,nL,sL,PO,XF,ZF,oL,JF,uL,cL,fL,xL,yL,vL,wL,eO,IL,TL,NL,RL,$L,PL,OL,aO,zL,WL,HL,rO,iO,XL,YL,eB,lO,aB,rB,sB,H7,uB,OO,pO,pB,hB,mB,xB,MF,b1,yB,DO,zO,LO,vB,kB,SB,CB,EB,RB,$B,yO,PB,LB,WB,HB,vO,qB,KB,YB,wO,UL,eW,aW,rW,iW,lW,dW,cW,fW,SO,mW,CO,xW,yW,vW,kW,SW,MO,Az,CW,EW,MW,_W,FW,uO,UW,HW,qW,nB];for(let e of XW)mn(e);var j7={};Xe(j7,{assertNotComplex:()=>uu,bindCanvasToFramebuffer:()=>sV,bindColorTextureToFramebuffer:()=>xc,bindTextureToProgramUniformSampler:()=>o6,bindTextureUnit:()=>r6,bindVertexBufferToProgramAttribute:()=>w1,callAndCheck:()=>le,canBeRepresented:()=>q7,createFragmentShader:()=>Z7,createFramebuffer:()=>n6,createProgram:()=>Y7,createStaticIndexBuffer:()=>e6,createStaticVertexBuffer:()=>Q7,createTexture:()=>t6,createVertexShader:()=>K7,getBatchDim:()=>Hs,getExtensionOrThrow:()=>qu,getFramebufferErrorMessage:()=>l6,getMaxTexturesInShader:()=>c6,getNumChannels:()=>nV,getProgramUniformLocation:()=>i6,getProgramUniformLocationOrThrow:()=>s6,getRowsCols:()=>js,getShapeAs3D:()=>Ku,getTextureShapeFromLogicalShape:()=>d6,getWebGLDisjointQueryTimerVersion:()=>h6,getWebGLErrorMessage:()=>X7,getWebGLMaxTextureSize:()=>p6,hasExtension:()=>cn,isCapableOfRenderingToFloatTexture:()=>f6,isDownloadFloatTextureEnabled:()=>m6,isReshapeFree:()=>md,isWebGLFenceEnabled:()=>g6,isWebGLVersionEnabled:()=>I1,linkProgram:()=>J7,logShaderSourceAndInfoLog:()=>b3,resetMaxTextureSize:()=>iV,resetMaxTexturesInShader:()=>oV,unbindColorTextureFromFramebuffer:()=>k1,unbindTextureUnit:()=>rV,validateFramebuffer:()=>Xu,validateProgram:()=>gc,validateTextureSize:()=>a6});var Ps={},lc={alpha:!1,antialias:!1,premultipliedAlpha:!1,preserveDrawingBuffer:!1,depth:!1,stencil:!1,failIfMajorPerformanceCaveat:!0};function Fh(e,t){Ps[e]=t}function Dn(e,t){if(!(e in Ps)||t!=null){let n=ZW(e,t);if(n!==null)Ps[e]=n;else return console.log("Could not get context for WebGL version",e),null}let a=Ps[e];return a==null||a.isContextLost()?(delete Ps[e],Dn(e)):(a.disable(a.DEPTH_TEST),a.disable(a.STENCIL_TEST),a.disable(a.BLEND),a.disable(a.DITHER),a.disable(a.POLYGON_OFFSET_FILL),a.disable(a.SAMPLE_COVERAGE),a.enable(a.SCISSOR_TEST),a.enable(a.CULL_FACE),a.cullFace(a.BACK),Ps[e])}function KW(e){if(typeof OffscreenCanvas!="undefined"&&e===2)return new OffscreenCanvas(300,150);if(typeof document!="undefined")return document.createElement("canvas");throw new Error("Cannot create a canvas in this context")}function ZW(e,t){if(e!==1&&e!==2)throw new Error("Cannot get WebGL rendering context, WebGL is disabled.");let a=t==null?KW(e):t;return a.addEventListener("webglcontextlost",n=>{n.preventDefault(),delete Ps[e]},!1),W().getBool("SOFTWARE_WEBGL_ENABLED")&&(lc.failIfMajorPerformanceCaveat=!1),e===1?a.getContext("webgl",lc)||a.getContext("experimental-webgl",lc):a.getContext("webgl2",lc)}var fd;(function(e){e[e.DENSE=0]="DENSE",e[e.SHARED_BATCH=1]="SHARED_BATCH"})(fd||(fd={}));var pn;(function(e){e[e.RENDER=0]="RENDER",e[e.UPLOAD=1]="UPLOAD",e[e.PIXELS=2]="PIXELS",e[e.DOWNLOAD=3]="DOWNLOAD"})(pn||(pn={}));var na;(function(e){e[e.UNPACKED_FLOAT16=0]="UNPACKED_FLOAT16",e[e.UNPACKED_FLOAT32=1]="UNPACKED_FLOAT32",e[e.PACKED_4X1_UNSIGNED_BYTE=2]="PACKED_4X1_UNSIGNED_BYTE",e[e.PACKED_2X2_FLOAT32=3]="PACKED_2X2_FLOAT32",e[e.PACKED_2X2_FLOAT16=4]="PACKED_2X2_FLOAT16"})(na||(na={}));function up(e,t){return[t,e]}function YW(e,t){return e*t}function uc(e){let t=v.sizeFromShape(e),a=Math.ceil(t/4);return v.sizeToSquarishShape(a)}function lu(e,t){return[Math.max(1,Math.ceil(t/2)),Math.max(1,Math.ceil(e/2))]}function JW(e,t){let[a,n]=lu(e,t);return a*n*4}function y3(e,t){let a=e,n,r,s,i,o,l,u,p,c,d;return W().getNumber("WEBGL_VERSION")===2?(n=a.R32F,r=a.R16F,s=a.RGBA16F,i=a.RGBA32F,o=a.RED,u=4,p=1,c=a.HALF_FLOAT,d=a.FLOAT,l=a.RGBA8):(n=e.RGBA,r=e.RGBA,s=e.RGBA,i=a.RGBA,o=e.RGBA,u=4,p=4,c=t!=null?t.HALF_FLOAT_OES:null,d=e.FLOAT,l=e.RGBA),{internalFormatFloat:n,internalFormatHalfFloat:r,internalFormatPackedHalfFloat:s,internalFormatPackedFloat:i,textureFormatFloat:o,downloadTextureFormat:l,downloadUnpackNumChannels:u,defaultNumChannels:p,textureTypeHalfFloat:c,textureTypeFloat:d}}function le(e,t){let a=t();return W().getBool("DEBUG")&&QW(e),a}function QW(e){let t=e.getError();if(t!==e.NO_ERROR)throw new Error("WebGL Error: "+X7(e,t))}var eV=596e-10,tV=65504;function q7(e){return!!(W().getBool("WEBGL_RENDER_FLOAT32_ENABLED")||e===0||eVe.getExtension(t),'Extension "'+t+'" not supported on this browser.')}function K7(e,t){let a=Sr(e,()=>e.createShader(e.VERTEX_SHADER),"Unable to create vertex WebGLShader.");if(le(e,()=>e.shaderSource(a,t)),le(e,()=>e.compileShader(a)),e.getShaderParameter(a,e.COMPILE_STATUS)===!1)throw console.log(e.getShaderInfoLog(a)),new Error("Failed to compile vertex shader.");return a}function Z7(e,t){let a=Sr(e,()=>e.createShader(e.FRAGMENT_SHADER),"Unable to create fragment WebGLShader.");if(le(e,()=>e.shaderSource(a,t)),le(e,()=>e.compileShader(a)),W().get("ENGINE_COMPILE_ONLY"))return a;if(e.getShaderParameter(a,e.COMPILE_STATUS)===!1)throw b3(t,e.getShaderInfoLog(a)),new Error("Failed to compile fragment shader.");return a}var aV=/ERROR: [0-9]+:([0-9]+):/g;function b3(e,t){let a=aV.exec(t);if(a==null){console.log(`Couldn't parse line number in error: ${t}`),console.log(e);return}let n=+a[1],r=e.split(` `),s=r.length.toString().length+2,i=r.map((c,d)=>v.rightPad((d+1).toString(),s)+c),o=0;for(let c=0;ce.createProgram(),"Unable to create WebGLProgram.")}function J7(e,t){if(le(e,()=>e.linkProgram(t)),!W().get("ENGINE_COMPILE_ONLY")&&e.getProgramParameter(t,e.LINK_STATUS)===!1)throw console.log(e.getProgramInfoLog(t)),new Error("Failed to link vertex and fragment shaders.")}function gc(e,t){if(le(e,()=>e.validateProgram(t)),e.getProgramParameter(t,e.VALIDATE_STATUS)===!1)throw console.log(e.getProgramInfoLog(t)),new Error("Shader program validation failed.")}function Q7(e,t){let a=Sr(e,()=>e.createBuffer(),"Unable to create WebGLBuffer");return le(e,()=>e.bindBuffer(e.ARRAY_BUFFER,a)),le(e,()=>e.bufferData(e.ARRAY_BUFFER,t,e.STATIC_DRAW)),a}function e6(e,t){let a=Sr(e,()=>e.createBuffer(),"Unable to create WebGLBuffer");return le(e,()=>e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,a)),le(e,()=>e.bufferData(e.ELEMENT_ARRAY_BUFFER,t,e.STATIC_DRAW)),a}function nV(){return W().getNumber("WEBGL_VERSION")===2?1:4}function t6(e){return Sr(e,()=>e.createTexture(),"Unable to create WebGLTexture.")}function a6(e,t){let a=W().getNumber("WEBGL_MAX_TEXTURE_SIZE");if(e<=0||t<=0){let n=`[${e}x${t}]`;throw new Error("Requested texture size "+n+" is invalid.")}if(e>a||t>a){let n=`[${e}x${t}]`,r=`[${a}x${a}]`;throw new Error("Requested texture size "+n+" greater than WebGL maximum on this browser / GPU "+r+".")}}function n6(e){return Sr(e,()=>e.createFramebuffer(),"Unable to create WebGLFramebuffer.")}function w1(e,t,a,n,r,s,i){let o=e.getAttribLocation(t,a);return o===-1?!1:(le(e,()=>e.bindBuffer(e.ARRAY_BUFFER,n)),le(e,()=>e.vertexAttribPointer(o,r,e.FLOAT,!1,s,i)),le(e,()=>e.enableVertexAttribArray(o)),!0)}function r6(e,t,a){u6(e,a),le(e,()=>e.activeTexture(e.TEXTURE0+a)),le(e,()=>e.bindTexture(e.TEXTURE_2D,t))}function rV(e,t){u6(e,t),le(e,()=>e.activeTexture(e.TEXTURE0+t)),le(e,()=>e.bindTexture(e.TEXTURE_2D,null))}function s6(e,t,a){return Sr(e,()=>e.getUniformLocation(t,a),'uniform "'+a+'" not present in program.')}function i6(e,t,a){return e.getUniformLocation(t,a)}function o6(e,t,a,n){le(e,()=>r6(e,t,n)),le(e,()=>e.uniform1i(a,n))}function sV(e){le(e,()=>e.bindFramebuffer(e.FRAMEBUFFER,null)),le(e,()=>e.viewport(0,0,e.canvas.width,e.canvas.height)),le(e,()=>e.scissor(0,0,e.canvas.width,e.canvas.height))}function xc(e,t,a){le(e,()=>e.bindFramebuffer(e.FRAMEBUFFER,a)),le(e,()=>e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t,0))}function k1(e,t){le(e,()=>e.bindFramebuffer(e.FRAMEBUFFER,t)),le(e,()=>e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,null,0))}function Xu(e){let t=e.checkFramebufferStatus(e.FRAMEBUFFER);if(t!==e.FRAMEBUFFER_COMPLETE)throw new Error("Error binding framebuffer: "+l6(e,t))}function l6(e,t){switch(t){case e.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:return"FRAMEBUFFER_INCOMPLETE_ATTACHMENT";case e.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:return"FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";case e.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:return"FRAMEBUFFER_INCOMPLETE_DIMENSIONS";case e.FRAMEBUFFER_UNSUPPORTED:return"FRAMEBUFFER_UNSUPPORTED";default:return`unknown error ${t}`}}function Sr(e,t,a){let n=le(e,()=>t());if(n==null)throw new Error(a);return n}function u6(e,t){let a=e.MAX_COMBINED_TEXTURE_IMAGE_UNITS-1,n=t+e.TEXTURE0;if(na){let r=`[gl.TEXTURE0, gl.TEXTURE${a}]`;throw new Error(`textureUnit must be in ${r}.`)}}function Hs(e,t=2){return v.sizeFromShape(e.slice(0,e.length-t))}function js(e){if(e.length===0)throw Error("Cannot get rows and columns of an empty shape array.");return[e.length>1?e[e.length-2]:1,e[e.length-1]]}function Ku(e){let t=[1,1,1];return e.length===0||e.length===1&&e[0]===1||(t=[Hs(e),...js(e)]),t}function d6(e,t=!1){let a=W().getNumber("WEBGL_MAX_TEXTURE_SIZE"),n=W().getNumber("WEBGL_MAX_SIZE_FOR_NARROW_TEXTURE");n===1/0&&W().getBool("WEBGL_AUTO_SQUARIFY_NARROW_TEXTURE_SHAPE")&&(n=a/2),t&&(a=a*2,n=n*2,e=e.map((o,l)=>l>=e.length-2?v.nearestLargerEven(e[l]):e[l]),e.length===1&&(e=[2,e[0]])),e.length!==2&&(e=v.squeezeShape(e).newShape);let r=v.sizeFromShape(e),s=null;e.length<=1&&r<=a?s=[1,r]:e.length===2&&e[0]<=a&&e[1]<=a?s=e:e.length===3&&e[0]*e[1]<=a&&e[2]<=a?s=[e[0]*e[1],e[2]]:e.length===3&&e[0]<=a&&e[1]*e[2]<=a?s=[e[0],e[1]*e[2]]:e.length===4&&e[0]*e[1]*e[2]<=a&&e[3]<=a?s=[e[0]*e[1]*e[2],e[3]]:e.length===4&&e[0]<=a&&e[1]*e[2]*e[3]<=a&&(s=[e[0],e[1]*e[2]*e[3]]);let i=s!=null&&Math.max(...s)>n&&Math.min(...s)<=(t?2:1)&&Math.min(...s)>0;if(s==null||i)if(t){let o=Hs(e),l=2,u=2;e.length&&([l,u]=js(e)),r=o*(l/2)*(u/2),s=v.sizeToSquarishShape(r).map(p=>p*2)}else s=v.sizeToSquarishShape(r);return s}function dc(e){return e%2===0}function md(e,t){if(e=e.slice(-2),t=t.slice(-2),v.arraysEqual(e,t)||!e.length||!t.length||e[0]===0||e[1]===0||t[0]===0||t[1]===0)return!0;if(e.length!==t.length){let a=e.slice(-1)[0],n=t.slice(-1)[0];if(a===n||dc(a)&&dc(n)&&(e[0]===1||t[0]===1))return!0}return e[1]===t[1]&&dc(e[0])&&dc(t[0])}var Ac,yc;function p6(e){if(Ac==null){let t=Dn(e);Ac=t.getParameter(t.MAX_TEXTURE_SIZE)}return Ac}function iV(){Ac=null}function oV(){yc=null}function c6(e){if(yc==null){let t=Dn(e);yc=t.getParameter(t.MAX_TEXTURE_IMAGE_UNITS)}return Math.min(16,yc)}function h6(e){if(e===0)return 0;let t,a=Dn(e);return cn(a,"EXT_disjoint_timer_query_webgl2")&&e===2?t=2:cn(a,"EXT_disjoint_timer_query")?t=1:t=0,t}function cn(e,t){return e.getExtension(t)!=null}function I1(e){try{if(Dn(e)!=null)return!0}catch(t){return console.log("Error when getting WebGL context: ",t),!1}return!1}function f6(e){if(e===0)return!1;let t=Dn(e);if(e===1){if(!cn(t,"OES_texture_float"))return!1}else if(!cn(t,"EXT_color_buffer_float"))return!1;return S1(t)}function m6(e){if(e===0)return!1;let t=Dn(e);if(e===1){if(!cn(t,"OES_texture_float")||!cn(t,"WEBGL_color_buffer_float"))return!1}else{if(cn(t,"EXT_color_buffer_float"))return S1(t);let a="EXT_color_buffer_half_float";if(cn(t,a)){let n=t.getExtension(a);return lV(t,n)}return!1}return S1(t)}function S1(e){let t=y3(e),a=e.createTexture();e.bindTexture(e.TEXTURE_2D,a);let n=1,r=1;e.texImage2D(e.TEXTURE_2D,0,t.internalFormatFloat,n,r,0,t.textureFormatFloat,t.textureTypeFloat,null);let s=e.createFramebuffer();e.bindFramebuffer(e.FRAMEBUFFER,s),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,a,0);let i=e.checkFramebufferStatus(e.FRAMEBUFFER)===e.FRAMEBUFFER_COMPLETE;return e.bindTexture(e.TEXTURE_2D,null),e.bindFramebuffer(e.FRAMEBUFFER,null),e.deleteTexture(a),e.deleteFramebuffer(s),i}function lV(e,t){let a=y3(e,t),n=e.createTexture();e.bindTexture(e.TEXTURE_2D,n);let r=1,s=1;e.texImage2D(e.TEXTURE_2D,0,a.internalFormatHalfFloat,r,s,0,a.textureFormatFloat,a.textureTypeHalfFloat,null);let i=e.createFramebuffer();e.bindFramebuffer(e.FRAMEBUFFER,i),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,n,0);let o=e.checkFramebufferStatus(e.FRAMEBUFFER)===e.FRAMEBUFFER_COMPLETE;return e.bindTexture(e.TEXTURE_2D,null),e.bindFramebuffer(e.FRAMEBUFFER,null),e.deleteTexture(n),e.deleteFramebuffer(i),o}function g6(e){return e!==2?!1:Dn(e).fenceSync!=null}function uu(e,t){Array.isArray(e)||(e=[e]),e.forEach(a=>{a!=null&&v.assert(a.dtype!=="complex64",()=>`${t} does not support complex64 tensors in the WebGL backend.`)})}var ve=W();ve.registerFlag("HAS_WEBGL",()=>ve.getNumber("WEBGL_VERSION")>0);ve.registerFlag("WEBGL_VERSION",()=>I1(2)?2:I1(1)?1:0);ve.registerFlag("WEBGL_CHECK_NUMERICAL_PROBLEMS",()=>!1);ve.registerFlag("WEBGL_BUFFER_SUPPORTED",()=>ve.get("WEBGL_VERSION")===2);ve.registerFlag("WEBGL_CPU_FORWARD",()=>!0);ve.registerFlag("WEBGL_FORCE_F16_TEXTURES",()=>!1);ve.registerFlag("WEBGL_PACK",()=>ve.getBool("HAS_WEBGL"));ve.registerFlag("WEBGL_PACK_NORMALIZATION",()=>ve.getBool("WEBGL_PACK"));ve.registerFlag("WEBGL_PACK_CLIP",()=>ve.getBool("WEBGL_PACK"));ve.registerFlag("WEBGL_PACK_DEPTHWISECONV",()=>ve.getBool("WEBGL_PACK"));ve.registerFlag("WEBGL_PACK_BINARY_OPERATIONS",()=>ve.getBool("WEBGL_PACK"));ve.registerFlag("WEBGL_PACK_UNARY_OPERATIONS",()=>ve.getBool("WEBGL_PACK"));ve.registerFlag("WEBGL_PACK_ARRAY_OPERATIONS",()=>ve.getBool("WEBGL_PACK"));ve.registerFlag("WEBGL_PACK_IMAGE_OPERATIONS",()=>ve.getBool("WEBGL_PACK"));ve.registerFlag("WEBGL_PACK_REDUCE",()=>ve.getBool("WEBGL_PACK"));ve.registerFlag("WEBGL_LAZILY_UNPACK",()=>ve.getBool("WEBGL_PACK"));ve.registerFlag("WEBGL_CONV_IM2COL",()=>ve.getBool("WEBGL_PACK"));ve.registerFlag("WEBGL_MAX_TEXTURE_SIZE",()=>p6(ve.getNumber("WEBGL_VERSION")));ve.registerFlag("WEBGL_MAX_TEXTURES_IN_SHADER",()=>c6(ve.getNumber("WEBGL_VERSION")));ve.registerFlag("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION",()=>{let e=ve.getNumber("WEBGL_VERSION");return e===0?0:h6(e)});ve.registerFlag("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE",()=>ve.getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION")>0&&!jd.isMobile());ve.registerFlag("WEBGL_RENDER_FLOAT32_CAPABLE",()=>f6(ve.getNumber("WEBGL_VERSION")));ve.registerFlag("WEBGL_RENDER_FLOAT32_ENABLED",()=>ve.getBool("WEBGL_FORCE_F16_TEXTURES")?!1:ve.getBool("WEBGL_RENDER_FLOAT32_CAPABLE"));ve.registerFlag("WEBGL_DOWNLOAD_FLOAT_ENABLED",()=>m6(ve.getNumber("WEBGL_VERSION")));ve.registerFlag("WEBGL_FENCE_API_ENABLED",()=>g6(ve.getNumber("WEBGL_VERSION")));ve.registerFlag("WEBGL_SIZE_UPLOAD_UNIFORM",()=>ve.getBool("WEBGL_RENDER_FLOAT32_ENABLED")?4:0);ve.registerFlag("WEBGL_DELETE_TEXTURE_THRESHOLD",()=>-1,e=>{if(e<0&&e!==-1)throw new Error(`WEBGL_DELETE_TEXTURE_THRESHOLD must be -1 (indicating never delete) or at least 0, but got ${e}.`)});ve.registerFlag("WEBGL_FLUSH_THRESHOLD",()=>jd.isMobile()?1:-1,e=>{if(e<0&&e!==-1)throw new Error(`WEBGL_FLUSH_THRESHOLD must be -1 (indicating never manual flush) or at least 0, but got ${e}.`)});ve.registerFlag("CPU_HANDOFF_SIZE_THRESHOLD",()=>128);ve.registerFlag("WEBGL_USE_SHAPES_UNIFORMS",()=>!1);ve.registerFlag("TOPK_LAST_DIM_CPU_HANDOFF_SIZE_THRESHOLD",()=>1e5);ve.registerFlag("TOPK_K_CPU_HANDOFF_THRESHOLD",()=>128);ve.registerFlag("WEBGL_EXP_CONV",()=>!1);ve.registerFlag("SOFTWARE_WEBGL_ENABLED",()=>ve.getBool("IS_TEST"));ve.registerFlag("WEBGL_MAX_SIZE_FOR_NARROW_TEXTURE",()=>1/0);ve.registerFlag("WEBGL_AUTO_SQUARIFY_NARROW_TEXTURE_SHAPE",()=>!1);ve.registerFlag("WEBGL2_ISNAN_CUSTOM",()=>!1);ve.registerFlag("ENGINE_COMPILE_ONLY",()=>!1);function Ca(){let e,t,a,n,r,s,i,o,l,u;return W().getNumber("WEBGL_VERSION")===2?(e="#version 300 es",t="in",a="out",n="in",r="texture",s="outputColor",i="out vec4 outputColor;",o=W().getBool("WEBGL2_ISNAN_CUSTOM")?` bool isnan_custom(float val) { uint floatToUint = floatBitsToUint(val); return (floatToUint & 0x7fffffffu) > 0x7f800000u; } bvec4 isnan_custom(vec4 val) { return bvec4(isnan_custom(val.x), isnan_custom(val.y), isnan_custom(val.z), isnan_custom(val.w)); } #define isnan(value) isnan_custom(value) `:"",l="",u=` #define round(value) newRound(value) int newRound(float value) { return int(floor(value + 0.5)); } ivec4 newRound(vec4 value) { return ivec4(floor(value + vec4(0.5))); } `):(e="",t="attribute",a="varying",n="varying",r="texture2D",s="gl_FragColor",i="",o=` #define isnan(value) isnan_custom(value) bool isnan_custom(float val) { return (val > 0. || val < 1. || val == 0.) ? false : true; } bvec4 isnan_custom(vec4 val) { return bvec4(isnan(val.x), isnan(val.y), isnan(val.z), isnan(val.w)); } `,l=` uniform float INFINITY; bool isinf(float val) { return abs(val) == INFINITY; } bvec4 isinf(vec4 val) { return equal(abs(val), vec4(INFINITY)); } `,u=` int round(float value) { return int(floor(value + 0.5)); } ivec4 round(vec4 value) { return ivec4(floor(value + vec4(0.5))); } `),{version:e,attribute:t,varyingVs:a,varyingFs:n,texture2D:r,output:s,defineOutput:i,defineSpecialNaN:o,defineSpecialInf:l,defineRound:u}}function Ao(e,t,a="index"){let n=v.computeStrides(t);return n.map((r,s)=>{let i=`int ${e[s]} = ${a} / ${r}`,o=s===n.length-1?`int ${e[s+1]} = ${a} - ${e[s]} * ${r}`:`index -= ${e[s]} * ${r}`;return`${i}; ${o};`}).join("")}function Oh(e,t,a="index"){let n=v.computeStrides(t);return n.map((r,s)=>{let i=`int ${e[s]} = ${a} / outShapeStrides[${s}]`,o=s===n.length-1?`int ${e[s+1]} = ${a} - ${e[s]} * outShapeStrides[${s}]`:`index -= ${e[s]} * outShapeStrides[${s}]`;return`${i}; ${o};`}).join("")}function uV(e,t){let a=e.length,n=e.map(s=>`${t}[${s}]`),r=new Array(a-1);r[a-2]=n[a-1];for(let s=a-3;s>=0;--s)r[s]=`(${r[s+1]} * ${n[s+1]})`;return r}function dV(e,t,a="index"){let n=e.map((s,i)=>i),r=uV(n,t);return r.map((s,i)=>{let o=`int ${e[i]} = ${a} / ${r[i]}`,l=i===r.length-1?`int ${e[i+1]} = ${a} - ${e[i]} * ${r[i]}`:`index -= ${e[i]} * ${r[i]}`;return`${o}; ${l};`}).join("")}function v3(e){let t=v.computeStrides(e).map(a=>a.toString());return` int getFlatIndex(ivec3 coords) { return coords.x * ${t[0]} + coords.y * ${t[1]} + coords.z; } `}function w3(){return` int getFlatIndex(ivec3 coords) { return coords.x * outShapeStrides[0] + coords.y * outShapeStrides[1] + coords.z; } `}var x6=` const float FLOAT_MAX = 1.70141184e38; const float FLOAT_MIN = 1.17549435e-38; lowp vec4 encode_float(highp float v) { if (isnan(v)) { return vec4(255, 255, 255, 255); } highp float av = abs(v); if(av < FLOAT_MIN) { return vec4(0.0, 0.0, 0.0, 0.0); } else if(v > FLOAT_MAX) { return vec4(0.0, 0.0, 128.0, 127.0) / 255.0; } else if(v < -FLOAT_MAX) { return vec4(0.0, 0.0, 128.0, 255.0) / 255.0; } highp vec4 c = vec4(0,0,0,0); highp float e = floor(log2(av)); highp float m = exp2(fract(log2(av))) - 1.0; c[2] = floor(128.0 * m); m -= c[2] / 128.0; c[1] = floor(32768.0 * m); m -= c[1] / 32768.0; c[0] = floor(8388608.0 * m); highp float ebias = e + 127.0; c[3] = floor(ebias / 2.0); ebias -= c[3] * 2.0; c[2] += floor(ebias) * 128.0; c[3] += 128.0 * step(0.0, -v); return c / 255.0; } `,{getBroadcastDims:A6}=T;function pV(e,t,a){let n=[];if(e.forEach(d=>{let h=v.sizeFromShape(d.shapeInfo.logicalShape);if(d.shapeInfo.isUniform?n.push(`uniform float ${d.name}${h>1?`[${h}]`:""};`):(n.push(`uniform sampler2D ${d.name};`),n.push(`uniform int offset${d.name};`)),a.enableShapeUniforms){let{uniformShape:f}=k3(a.packedInputs,d.shapeInfo.logicalShape,d.shapeInfo.texShape);switch(f.length){case 1:n.push(`uniform int ${d.name}Shape;`);break;case 2:n.push(`uniform ivec2 ${d.name}Shape;`);break;case 3:n.push(`uniform ivec3 ${d.name}Shape;`);break;case 4:n.push(`uniform ivec4 ${d.name}Shape;`);break;default:break}n.push(`uniform ivec2 ${d.name}TexShape;`)}}),a.enableShapeUniforms){switch(t.logicalShape.length){case 1:n.push("uniform int outShape;");break;case 2:n.push("uniform ivec2 outShape;"),n.push("uniform int outShapeStrides;");break;case 3:n.push("uniform ivec3 outShape;"),n.push("uniform ivec2 outShapeStrides;");break;case 4:n.push("uniform ivec4 outShape;"),n.push("uniform ivec3 outShapeStrides;");break;default:break}n.push("uniform ivec2 outTexShape;")}a.customUniforms&&a.customUniforms.forEach(d=>{n.push(`uniform ${d.type} ${d.name}${d.arrayIndex?`[${d.arrayIndex}]`:""};`)});let r=n.join(` `),s=e.map(d=>cV(d,t,a.packedInputs,a.enableShapeUniforms)).join(` `),i=t.texShape,o=Ca(),l=mV(o),u,p,c=AV(o);return t.isPacked?(u=hV(t.logicalShape,i,a.enableShapeUniforms),p=xV(o)):(u=fV(t.logicalShape,i,a.enableShapeUniforms),p=gV(o)),a.packedInputs&&(c+=wV),[c,l,p,r,u,s,a.userCode].join(` `)}function du(e,t=!1){let a=e.shapeInfo.logicalShape;switch(a.length){case 0:return PV(e,t);case 1:return OV(e,t);case 2:return zV(e,t);case 3:return BV(e,t);case 4:return VV(e,t);case 5:return UV(e);case 6:return GV(e);default:throw new Error(`${a.length}-D input sampling is not yet supported`)}}function y6(e,t){switch(e.shapeInfo.logicalShape.length){case 0:return _V(e);case 1:return FV(e,t);case 2:return DV(e,t);case 3:return LV(e,t);default:return WV(e,t)}}function cV(e,t,a=!1,n){let r="";a?r+=y6(e,n):r+=du(e,n);let s=e.shapeInfo.logicalShape,i=t.logicalShape;return s.length<=i.length&&(a?r+=HV(e,t):r+=jV(e,t)),r}function hV(e,t,a){switch(e.length){case 0:return b6();case 1:return kV(e,t,a);case 2:return MV(e,t,a);case 3:return SV(e,t,a);default:return CV(e,t,a)}}function fV(e,t,a){switch(e.length){case 0:return b6();case 1:return IV(e,t,a);case 2:return $V(e,t,a);case 3:return TV(e,t,a);case 4:return NV(e,t,a);case 5:return EV(e,t);case 6:return RV(e,t);default:throw new Error(`${e.length}-D output sampling is not yet supported`)}}function mV(e){return` float sampleTexture(sampler2D textureSampler, vec2 uv) { return ${e.texture2D}(textureSampler, uv).r; } `}function gV(e){return` void setOutput(float val) { ${e.output} = vec4(val, 0, 0, 0); } `}function xV(e){return` void setOutput(vec4 val) { ${e.output} = val; } `}function AV(e){return`${e.version} precision highp float; precision highp int; precision highp sampler2D; ${e.varyingFs} vec2 resultUV; ${e.defineOutput} const vec2 halfCR = vec2(0.5, 0.5); struct ivec5 { int x; int y; int z; int w; int u; }; struct ivec6 { int x; int y; int z; int w; int u; int v; }; uniform float NAN; ${e.defineSpecialNaN} ${e.defineSpecialInf} ${e.defineRound} int imod(int x, int y) { return x - y * (x / y); } int idiv(int a, int b, float sign) { int res = a / b; int mod = imod(a, b); if (sign < 0. && mod != 0) { res -= 1; } return res; } //Based on the work of Dave Hoskins //https://www.shadertoy.com/view/4djSRW #define HASHSCALE1 443.8975 float random(float seed){ vec2 p = resultUV * seed; vec3 p3 = fract(vec3(p.xyx) * HASHSCALE1); p3 += dot(p3, p3.yzx + 19.19); return fract((p3.x + p3.y) * p3.z); } ${yV} ${bV} ${vV} `}var yV=` vec2 uvFromFlat(int texNumR, int texNumC, int index) { int texR = index / texNumC; int texC = index - texR * texNumC; return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR); } vec2 packedUVfrom1D(int texNumR, int texNumC, int index) { int texelIndex = index / 2; int texR = texelIndex / texNumC; int texC = texelIndex - texR * texNumC; return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR); } `,bV=` vec2 packedUVfrom2D(int texelsInLogicalRow, int texNumR, int texNumC, int row, int col) { int texelIndex = (row / 2) * texelsInLogicalRow + (col / 2); int texR = texelIndex / texNumC; int texC = texelIndex - texR * texNumC; return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR); } `,vV=` vec2 packedUVfrom3D(int texNumR, int texNumC, int texelsInBatch, int texelsInLogicalRow, int b, int row, int col) { int index = b * texelsInBatch + (row / 2) * texelsInLogicalRow + (col / 2); int texR = index / texNumC; int texC = index - texR * texNumC; return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR); } `,wV=` float getChannel(vec4 frag, vec2 innerDims) { vec2 modCoord = mod(innerDims, 2.); return modCoord.x == 0. ? (modCoord.y == 0. ? frag.r : frag.g) : (modCoord.y == 0. ? frag.b : frag.a); } float getChannel(vec4 frag, int dim) { float modCoord = mod(float(dim), 2.); return modCoord == 0. ? frag.r : frag.g; } `;function b6(){return` int getOutputCoords() { return 0; } `}function kV(e,t,a){let n=[Math.ceil(t[0]/2),Math.ceil(t[1]/2)];return n[0]===1?a?` int getOutputCoords() { return 2 * int(resultUV.x * ceil(float(outTexShape[1]) / 2.0)); } `:` int getOutputCoords() { return 2 * int(resultUV.x * ${n[1]}.0); } `:n[1]===1?a?` int getOutputCoords() { return 2 * int(resultUV.y * ceil(float(outTexShape[0]) / 2.0)); } `:` int getOutputCoords() { return 2 * int(resultUV.y * ${n[0]}.0); } `:a?` int getOutputCoords() { ivec2 packedTexShape = ivec2(ceil(float(outTexShape[0]) / 2.0), ceil(float(outTexShape[1]) / 2.0)); ivec2 resTexRC = ivec2(resultUV.yx * vec2(packedTexShape[0], packedTexShape[1])); return 2 * (resTexRC.x * packedTexShape[1] + resTexRC.y); } `:` int getOutputCoords() { ivec2 resTexRC = ivec2(resultUV.yx * vec2(${n[0]}, ${n[1]})); return 2 * (resTexRC.x * ${n[1]} + resTexRC.y); } `}function IV(e,t,a){return t[0]===1?a?` int getOutputCoords() { return int(resultUV.x * float(outTexShape[1])); } `:` int getOutputCoords() { return int(resultUV.x * ${t[1]}.0); } `:t[1]===1?a?` int getOutputCoords() { return int(resultUV.y * float(outTexShape[0])); } `:` int getOutputCoords() { return int(resultUV.y * ${t[0]}.0); } `:a?` int getOutputCoords() { ivec2 resTexRC = ivec2(resultUV.yx * vec2(outTexShape[0], outTexShape[1])); return resTexRC.x * outTexShape[1] + resTexRC.y; } `:` int getOutputCoords() { ivec2 resTexRC = ivec2(resultUV.yx * vec2(${t[0]}, ${t[1]})); return resTexRC.x * ${t[1]} + resTexRC.y; } `}function SV(e,t,a){if(a)return` ivec3 getOutputCoords() { ivec2 packedTexShape = ivec2(ceil(float(outTexShape[0]) / 2.0), ceil(float(outTexShape[1]) / 2.0)); int texelsInLogicalRow = int(ceil(float(outShape[2]) / 2.0)); int texelsInBatch = texelsInLogicalRow * int(ceil(float(outShape[1]) / 2.0)); ivec2 resTexRC = ivec2(resultUV.yx * vec2(packedTexShape[0], packedTexShape[1])); int index = resTexRC.x * packedTexShape[1] + resTexRC.y; int b = index / texelsInBatch; index -= b * texelsInBatch; int r = 2 * (index / texelsInLogicalRow); int c = imod(index, texelsInLogicalRow) * 2; return ivec3(b, r, c); } `;let n=[Math.ceil(t[0]/2),Math.ceil(t[1]/2)],r=Math.ceil(e[2]/2),s=r*Math.ceil(e[1]/2);return` ivec3 getOutputCoords() { ivec2 resTexRC = ivec2(resultUV.yx * vec2(${n[0]}, ${n[1]})); int index = resTexRC.x * ${n[1]} + resTexRC.y; int b = index / ${s}; index -= b * ${s}; int r = 2 * (index / ${r}); int c = imod(index, ${r}) * 2; return ivec3(b, r, c); } `}function TV(e,t,a){if(a)return` ivec3 getOutputCoords() { ivec2 resTexRC = ivec2(resultUV.yx * vec2(outTexShape[0], outTexShape[1])); int index = resTexRC.x * outTexShape[1] + resTexRC.y; ${Oh(["r","c","d"],e)} return ivec3(r, c, d); } `;let n=Ao(["r","c","d"],e);return` ivec3 getOutputCoords() { ivec2 resTexRC = ivec2(resultUV.yx * vec2(${t[0]}, ${t[1]})); int index = resTexRC.x * ${t[1]} + resTexRC.y; ${n} return ivec3(r, c, d); } `}function CV(e,t,a){if(a)return` ivec4 getOutputCoords() { ivec2 packedTexShape = ivec2(ceil(float(outTexShape[0]) / 2.0), ceil(float(outTexShape[1]) / 2.0)); ivec2 resTexRC = ivec2(resultUV.yx * vec2(packedTexShape[0], packedTexShape[1])); int index = resTexRC.x * packedTexShape[1] + resTexRC.y; int texelsInLogicalRow = int(ceil(float(outShape[3]) / 2.0)); int texelsInBatch = texelsInLogicalRow * int(ceil(float(outShape[2]) / 2.0)); int texelsInBatchN = texelsInBatch * outShape[1]; int b2 = index / texelsInBatchN; index -= b2 * texelsInBatchN; int b = index / texelsInBatch; index -= b * texelsInBatch; int r = 2 * (index / texelsInLogicalRow); int c = imod(index, texelsInLogicalRow) * 2; return ivec4(b2, b, r, c); } `;let n=[Math.ceil(t[0]/2),Math.ceil(t[1]/2)],r=Math.ceil(e[e.length-1]/2),s=r*Math.ceil(e[e.length-2]/2),i=s,o="",l="b, r, c";for(let u=2;u=1?p="coords = 0;":p=o.map(g=>`coords.${c[g+u]} = 0;`).join(` `);let d="";i<2&&s>0?d="coords":d=e.shapeInfo.logicalShape.map((g,x)=>`coords.${c[x+u]}`).join(", ");let h="return outputValue;",f=v.sizeFromShape(e.shapeInfo.logicalShape)===1,m=v.sizeFromShape(t.logicalShape)===1;if(s===1&&!f&&!m)h=` return vec4(outputValue.xy, outputValue.xy); `;else if(f&&!m)i===1?h=` return vec4(outputValue.x, outputValue.x, 0., 0.); `:h=` return vec4(outputValue.x); `;else if(o.length){let g=s-2,x=s-1;o.indexOf(g)>-1&&o.indexOf(x)>-1?h="return vec4(outputValue.x);":o.indexOf(g)>-1?h="return vec4(outputValue.x, outputValue.y, outputValue.x, outputValue.y);":o.indexOf(x)>-1&&(h="return vec4(outputValue.xx, outputValue.zz);")}return` vec4 ${r}() { ${l} coords = getOutputCoords(); ${p} vec4 outputValue = get${n}(${d}); ${h} } `}function jV(e,t){let a=e.name,n=a.charAt(0).toUpperCase()+a.slice(1),r="get"+n+"AtOutCoords",s=t.texShape,i=e.shapeInfo.texShape,o=e.shapeInfo.logicalShape.length,l=t.logicalShape.length;if(!e.shapeInfo.isUniform&&o===l&&e.shapeInfo.flatOffset==null&&v.arraysEqual(i,s))return` float ${r}() { return sampleTexture(${a}, resultUV); } `;let u=gt(l),p=A6(e.shapeInfo.logicalShape,t.logicalShape),c=l-o,d,h=["x","y","z","w","u","v"];o===0?d="":l<2&&p.length>=1?d="coords = 0;":d=p.map(m=>`coords.${h[m+c]} = 0;`).join(` `);let f="";return l<2&&o>0?f="coords":f=e.shapeInfo.logicalShape.map((m,g)=>`coords.${h[g+c]}`).join(", "),` float ${r}() { ${u} coords = getOutputCoords(); ${d} return get${n}(${f}); } `}function gt(e){if(e<=1)return"int";if(e===2)return"ivec2";if(e===3)return"ivec3";if(e===4)return"ivec4";if(e===5)return"ivec5";if(e===6)return"ivec6";throw Error(`GPU for rank ${e} is not yet supported`)}function k3(e,t,a){let{newShape:n,keptDims:r}=v.squeezeShape(t),s=t.length,i=e&&s===3&&t[0]===1,o=i?t.slice(1):n,l=!e&&s>1&&!v.arraysEqual(t,a)&&n.lengthe[a]).join(", ")}function qV(e,t,a,n){let r=a.map((p,c)=>{let d={logicalShape:p.shape,texShape:p.isUniform?null:p.texData.texShape,isUniform:p.isUniform,isPacked:p.isUniform?!1:p.texData.isPacked,flatOffset:null};return p.texData!=null&&p.texData.slice!=null&&p.texData.slice.flatOffset>0&&(d.flatOffset=p.texData.slice.flatOffset),{name:t.variableNames[c],shapeInfo:d}}),s=r.map(p=>p.shapeInfo),i={logicalShape:n.shape,texShape:n.texData.texShape,isUniform:!1,isPacked:n.texData.isPacked,flatOffset:null},o=pV(r,i,t),l=Z7(e.gl,o),u=e.createProgram(l);return W().get("ENGINE_COMPILE_ONLY")?{program:t,fragmentShader:l,source:o,webGLProgram:u,inShapeInfos:s,outShapeInfo:i,uniformLocations:null,customUniformLocations:null,infLoc:null,nanLoc:null,inShapesLocations:null,inTexShapesLocations:null,outShapeLocation:null,outShapeStridesLocation:null,outTexShapeLocation:null}:Object.assign({program:t,fragmentShader:l,source:o,webGLProgram:u,inShapeInfos:s,outShapeInfo:i},v6(e,t,u))}function v6(e,t,a){let n={},r={},s={},i=[],o,l,u,p=null,c=null;c=e.getUniformLocation(a,"NAN",!1),W().getNumber("WEBGL_VERSION")===1&&(p=e.getUniformLocation(a,"INFINITY",!1));let d=!1;for(let h=0;h{i[f]=e.getUniformLocation(a,h.name,d)}),{uniformLocations:n,customUniformLocations:i,infLoc:p,nanLoc:c,inShapesLocations:r,inTexShapesLocations:s,outShapeLocation:o,outShapeStridesLocation:u,outTexShapeLocation:l}}function cx(e,t){if(e.length!==t.length)throw Error(`Binary was compiled with ${e.length} inputs, but was executed with ${t.length} inputs`);e.forEach((a,n)=>{let r=a.logicalShape,s=t[n],i=s.shape;if(!v.arraysEqual(r,i))throw Error(`Binary was compiled with different shapes than the current args. Shapes ${r} and ${i} must match`);if(a.isUniform&&s.isUniform)return;let o=a.texShape,l=s.isUniform?null:s.texData.texShape;if(!v.arraysEqual(o,l))throw Error(`Binary was compiled with different texture shapes than the current args. Shape ${o} and ${l} must match`)})}function XV(e,t,a,n,r){t.program.enableShapeUniforms||(cx(t.inShapeInfos,a),cx([t.outShapeInfo],[n]));let s=n.texData.texture,i=n.texData.texShape;n.texData.isPacked?e.setOutputPackedMatrixTexture(s.texture,i[0],i[1]):e.setOutputMatrixTexture(s.texture,i[0],i[1]),e.setProgram(t.webGLProgram),W().getNumber("WEBGL_VERSION")===1&&t.infLoc!==null&&e.gl.uniform1f(t.infLoc,1/0),t.nanLoc!==null&&e.gl.uniform1f(t.nanLoc,NaN),a.forEach((l,u)=>{let p=t.program.variableNames[u],c=t.uniformLocations[p],d=t.uniformLocations[`offset${p}`],h=t.inShapesLocations[`${p}Shape`],f=t.inTexShapesLocations[`${p}TexShape`];if(h){let{uniformShape:m}=k3(t.program.packedInputs,l.shape,l.texData.texShape);switch(m.length){case 1:e.gl.uniform1iv(h,new Int32Array(m));break;case 2:e.gl.uniform2iv(h,new Int32Array(m));break;case 3:e.gl.uniform3iv(h,new Int32Array(m));break;case 4:e.gl.uniform4iv(h,new Int32Array(m));break;default:break}}if(f&&e.gl.uniform2i(f,l.texData.texShape[0],l.texData.texShape[1]),c!=null){if(l.isUniform){if(v.sizeFromShape(l.shape)<2)e.gl.uniform1f(c,l.uniformValues[0]);else{let m=l.uniformValues;m instanceof Float32Array||(m=new Float32Array(m)),e.gl.uniform1fv(c,m)}return}l.texData.slice!=null&&d!=null&&e.gl.uniform1i(d,l.texData.slice.flatOffset),e.setInputMatrixTexture(l.texData.texture.texture,c,u)}});let o=t.outShapeLocation;if(o)switch(n.shape.length){case 1:e.gl.uniform1iv(o,new Int32Array(n.shape));break;case 2:e.gl.uniform2iv(o,new Int32Array(n.shape));break;case 3:e.gl.uniform3iv(o,new Int32Array(n.shape));break;case 4:e.gl.uniform4iv(o,new Int32Array(n.shape));break;default:break}if(t.outShapeStridesLocation){let l=v.computeStrides(n.shape);switch(n.shape.length){case 2:e.gl.uniform1iv(t.outShapeStridesLocation,new Int32Array(l));break;case 3:e.gl.uniform2iv(t.outShapeStridesLocation,new Int32Array(l));break;case 4:e.gl.uniform3iv(t.outShapeStridesLocation,new Int32Array(l));break;default:break}}t.outTexShapeLocation&&e.gl.uniform2i(t.outTexShapeLocation,n.texData.texShape[0],n.texData.texShape[1]),t.program.customUniforms&&r&&t.program.customUniforms.forEach((l,u)=>{let p=t.customUniformLocations[u],c=r[u];if(l.type==="float")e.gl.uniform1fv(p,c);else if(l.type==="vec2")e.gl.uniform2fv(p,c);else if(l.type==="vec3")e.gl.uniform3fv(p,c);else if(l.type==="vec4")e.gl.uniform4fv(p,c);else if(l.type==="int")e.gl.uniform1iv(p,c);else if(l.type==="ivec2")e.gl.uniform2iv(p,c);else if(l.type==="ivec3")e.gl.uniform3iv(p,c);else if(l.type==="ivec4")e.gl.uniform4iv(p,c);else throw Error(`uniform type ${l.type} is not supported yet.`)}),e.executeProgram()}function KV(e,t,a){let n="";t.concat(a).forEach(i=>{let o=i.texData!=null&&i.texData.slice!=null&&i.texData.slice.flatOffset>0;if(e.enableShapeUniforms&&!i.isUniform){let l=i.texData.texShape,{useSqueezeShape:u,uniformShape:p,keptDims:c}=k3(e.packedInputs,i.shape,l),d="",h="",f="";if(p.length===1&&e.packedInputs){let w=[Math.ceil(l[0]/2),Math.ceil(l[1]/2)];d=`${w[0]>1}_${w[1]>1}`}else if(p.length===2&&!e.packedInputs)h=`${p[0]>1}_${p[1]>1}`;else if(p.length>2&&!e.packedInputs){let w=v.computeStrides(p);f=`${w[0]===l[1]}_${w[w.length-1]===l[1]}`}let m=i.shape.length,g=p.length===2&&v.arraysEqual(i.shape,l),x=v.sizeFromShape(i.shape)===1,A=T.getBroadcastDims(i.shape,a.shape),y=!e.packedInputs&&m===a.shape.length&&v.arraysEqual(l,a.texData.texShape),b=e.packedInputs||p.length>2?"":`${l[0]>1}_${l[1]>1}`;n+=`${m}_${y}_${u?c:""}_${p.length}_${x}_${A}_${g}_${d}_${h}_${f}_${b}_${o}`}else{let l=i.isUniform?"uniform":i.texData.texShape;n+=`${i.shape}_${l}_${o}`}});let r=e.userCode,s=e.constructor.name;return s+="_"+n+"_"+r+`${W().getNumber("WEBGL_VERSION")}`,s}function Na(e){return W().getBool("WEBGL_USE_SHAPES_UNIFORMS")&&e<=4}var ZV=class{constructor(e){this.variableNames=["A"],this.packedInputs=!1,this.packedOutput=!0,this.outPackingScheme=fd.DENSE,this.customUniforms=[{name:"texShape",type:"ivec2"}];let t=Ca();this.outputShape=e,this.enableShapeUniforms=Na(this.outputShape.length),this.userCode=` ivec3 outCoordsFromFlatIndex(int index) { ${this.enableShapeUniforms?Oh(["r","c","d"],e):Ao(["r","c","d"],e)} return ivec3(r, c, d); } void main() { ivec2 resTexRC = ivec2(resultUV.yx * vec2(texShape[0], texShape[1])); int index = 4 * (resTexRC.x * texShape[1] + resTexRC.y); vec4 result = vec4(0.); for (int i=0; i<4; i++) { int flatIndex = index + i; ivec3 rc = outCoordsFromFlatIndex(flatIndex); result[i] = getA(rc.x, rc.y, rc.z); } ${t.output} = result; } `}},YV=class{constructor(e){this.variableNames=["A"],this.packedInputs=!0,this.packedOutput=!0,this.outPackingScheme=fd.DENSE,this.customUniforms=[{name:"texShape",type:"ivec2"}];let t=Ca();this.outputShape=e,this.enableShapeUniforms=Na(this.outputShape.length),this.userCode=` ivec3 outCoordsFromFlatIndex(int index) { ${this.enableShapeUniforms?Oh(["r","c","d"],e):Ao(["r","c","d"],e)} return ivec3(r, c, d); } void main() { ivec2 resTexRC = ivec2(resultUV.yx * vec2(texShape[0], texShape[1])); int index = 4 * (resTexRC.x * texShape[1] + resTexRC.y); vec4 result = vec4(0.); for (int i=0; i<4; i++) { int flatIndex = index + i; ivec3 rc = outCoordsFromFlatIndex(flatIndex); result[i] = getChannel(getA(rc.x, rc.y, rc.z), vec2(rc.y, rc.z)); } ${t.output} = result; } `}},JV=class{constructor(e){this.variableNames=["A"],this.outTexUsage=pn.DOWNLOAD;let t=Ca();this.outputShape=e,this.userCode=` ${x6} void main() { float x = getAAtOutCoords(); ${t.output} = encode_float(x); } `}},QV=class{constructor(e){this.variableNames=["A"],this.packedInputs=!0,this.packedOutput=!1,this.outTexUsage=pn.DOWNLOAD;let t=Ca();this.outputShape=e,this.userCode=` ${x6} void main() { ivec3 coords = getOutputCoords(); float x = getChannel(getAAtOutCoords(), vec2(coords.y, coords.z)); ${t.output} = encode_float(x); } `}},eU={R:0,G:1,B:2,A:3},hx=class{constructor(e,t=!1,a="RGBA"){this.variableNames=["A"],this.customUniforms=[{name:"texShape",type:"ivec2"}];let n=Ca();this.outputShape=e,this.enableShapeUniforms=Na(this.outputShape.length);let r="result";t&&(r="floor(result * 255. + 0.5)");let s="";for(let i=0;iM6,createBufferFromOutputTexture:()=>P6,createFloat16MatrixTexture:()=>C6,createFloat16PackedMatrixTexture:()=>R6,createFloat32MatrixTexture:()=>T6,createIndexBuffer:()=>S6,createPackedMatrixTexture:()=>E6,createUnsignedBytesMatrixTexture:()=>N6,createVertexBuffer:()=>I6,createVertexShader:()=>k6,downloadByteEncodedFloatMatrixFromOutputTexture:()=>O6,downloadFloat32MatrixFromBuffer:()=>F6,downloadMatrixFromPackedOutputTexture:()=>z6,downloadPackedMatrixFromBuffer:()=>D6,getInternalFormatForFloat16MatrixTexture:()=>S3,getInternalFormatForFloat16PackedMatrixTexture:()=>N3,getInternalFormatForFloat32MatrixTexture:()=>I3,getInternalFormatForPackedMatrixTexture:()=>C3,getInternalFormatForUnsignedBytesMatrixTexture:()=>T3,uploadDenseMatrixToTexture:()=>$6,uploadPixelDataToTexture:()=>_6});function k6(e){let t=Ca(),a=`${t.version} precision highp float; ${t.attribute} vec3 clipSpacePos; ${t.attribute} vec2 uv; ${t.varyingVs} vec2 resultUV; void main() { gl_Position = vec4(clipSpacePos, 1); resultUV = uv; }`;return K7(e,a)}function I6(e){let t=new Float32Array([-1,1,0,0,1,-1,-1,0,0,0,1,1,0,1,1,1,-1,0,1,0]);return Q7(e,t)}function S6(e){let t=new Uint16Array([0,1,2,2,1,3]);return e6(e,t)}function dp(e,t,a,n,r,s){a6(t,a);let i=t6(e),o=e.TEXTURE_2D;return le(e,()=>e.bindTexture(o,i)),le(e,()=>e.texParameteri(o,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE)),le(e,()=>e.texParameteri(o,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE)),le(e,()=>e.texParameteri(o,e.TEXTURE_MIN_FILTER,e.NEAREST)),le(e,()=>e.texParameteri(o,e.TEXTURE_MAG_FILTER,e.NEAREST)),W().getNumber("WEBGL_VERSION")===1?le(e,()=>e.texImage2D(o,0,n,t,a,0,r,s,null)):le(e,()=>e.texStorage2D(o,1,n,t,a)),le(e,()=>e.bindTexture(e.TEXTURE_2D,null)),{texture:i,texShape:[a,t]}}function I3(e){return e.internalFormatFloat}function T6(e,t,a,n){let[r,s]=up(t,a);return dp(e,r,s,I3(n),n.textureFormatFloat,e.FLOAT)}function S3(e){return e.internalFormatHalfFloat}function C6(e,t,a,n){let[r,s]=up(t,a);return dp(e,r,s,S3(n),n.textureFormatFloat,n.textureTypeHalfFloat)}function T3(e){return e.downloadTextureFormat}function N6(e,t,a,n){let[r,s]=up(t,a);return dp(e,r,s,T3(n),e.RGBA,e.UNSIGNED_BYTE)}function C3(e){return e.internalFormatPackedFloat}function E6(e,t,a,n){let[r,s]=lu(t,a);return dp(e,r,s,C3(n),e.RGBA,e.FLOAT)}function N3(e){return e.internalFormatPackedHalfFloat}function R6(e,t,a,n){let[r,s]=lu(t,a);return dp(e,r,s,N3(n),e.RGBA,n.textureTypeHalfFloat)}function M6(e,t,a){return le(e,()=>e.bindBuffer(e.ARRAY_BUFFER,a)),w1(e,t,"clipSpacePos",a,3,20,0)&&w1(e,t,"uv",a,2,20,12)}function $6(e,t,a,n,r,s){le(e,()=>e.bindTexture(e.TEXTURE_2D,t));let i,o,l;r instanceof Uint8Array?(i=new Uint8Array(a*n*4),o=e.UNSIGNED_BYTE,l=e.RGBA):(i=new Float32Array(a*n*4),o=e.FLOAT,l=s.internalFormatPackedFloat),i.set(r),W().getNumber("WEBGL_VERSION")===2?le(e,()=>e.texSubImage2D(e.TEXTURE_2D,0,0,0,a,n,e.RGBA,o,i)):le(e,()=>e.texImage2D(e.TEXTURE_2D,0,l,a,n,0,e.RGBA,o,i)),le(e,()=>e.bindTexture(e.TEXTURE_2D,null))}function _6(e,t,a){le(e,()=>e.bindTexture(e.TEXTURE_2D,t)),a.data instanceof Uint8Array?W().getNumber("WEBGL_VERSION")===2?le(e,()=>e.texSubImage2D(e.TEXTURE_2D,0,0,0,a.width,a.height,e.RGBA,e.UNSIGNED_BYTE,a.data)):le(e,()=>e.texImage2D(e.TEXTURE_2D,0,e.RGBA,a.width,a.height,0,e.RGBA,e.UNSIGNED_BYTE,a.data)):W().getNumber("WEBGL_VERSION")===2?le(e,()=>e.texSubImage2D(e.TEXTURE_2D,0,0,0,e.RGBA,e.UNSIGNED_BYTE,a)):le(e,()=>e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,a)),le(e,()=>e.bindTexture(e.TEXTURE_2D,null))}function P6(e,t,a,n){let r=e.createBuffer();le(e,()=>e.bindBuffer(e.PIXEL_PACK_BUFFER,r));let s=4*4*t*a;return le(e,()=>e.bufferData(e.PIXEL_PACK_BUFFER,s,e.STREAM_READ)),le(e,()=>e.readPixels(0,0,a,t,e.RGBA,e.FLOAT,0)),le(e,()=>e.bindBuffer(e.PIXEL_PACK_BUFFER,null)),r}function F6(e,t,a){let n=e,r=new Float32Array(a);return n.bindBuffer(n.PIXEL_PACK_BUFFER,t),n.getBufferSubData(n.PIXEL_PACK_BUFFER,0,r),n.bindBuffer(n.PIXEL_PACK_BUFFER,null),r}function O6(e,t,a,n){let[r,s]=up(t,a),i=4,o=new Uint8Array(YW(t*a,i));return le(e,()=>e.readPixels(0,0,r,s,n.downloadTextureFormat,e.UNSIGNED_BYTE,o)),new Float32Array(o.buffer)}function D6(e,t,a,n,r,s,i,o){let l=e,u=new Float32Array(JW(s,i));return l.bindBuffer(l.PIXEL_PACK_BUFFER,t),l.getBufferSubData(l.PIXEL_PACK_BUFFER,0,u),l.bindBuffer(l.PIXEL_PACK_BUFFER,null),u}function z6(e,t,a){let n=new Float32Array(t*a*4);return le(e,()=>e.readPixels(0,0,a,t,e.RGBA,e.FLOAT,n)),n}var il=class{constructor(e){this.outputTexture=null,this.program=null,this.disposed=!1,this.itemsToPoll=[];let t=W().getNumber("WEBGL_VERSION");if(e!=null?(this.gl=e,Fh(t,e)):this.gl=Dn(t),e=this.gl,W().getNumber("WEBGL_VERSION")===2){let r=e;this.createVertexArray=()=>le(r,()=>r.createVertexArray()),this.bindVertexArray=s=>le(r,()=>r.bindVertexArray(s)),this.deleteVertexArray=s=>le(r,()=>r.deleteVertexArray(s)),this.getVertexArray=()=>le(r,()=>r.getParameter(r.VERTEX_ARRAY_BINDING))}else if(e!=null){let r=e.getExtension("OES_vertex_array_object");if(r==null)throw new Error("All WebGL1 implementations are expected to offer OES_vertex_array_object.");this.createVertexArray=()=>le(e,()=>r.createVertexArrayOES()),this.bindVertexArray=s=>le(e,()=>r.bindVertexArrayOES(s)),this.deleteVertexArray=s=>le(e,()=>r.deleteVertexArrayOES(s)),this.getVertexArray=()=>le(e,()=>e.getParameter(r.VERTEX_ARRAY_BINDING_OES))}let a="WEBGL_color_buffer_float",n="EXT_color_buffer_half_float";if(this.parallelCompilationExtension=this.gl.getExtension("KHR_parallel_shader_compile"),W().getNumber("WEBGL_VERSION")===1){let r="OES_texture_float",s="OES_texture_half_float";if(this.textureFloatExtension=qu(this.gl,r),cn(this.gl,s))this.textureHalfFloatExtension=qu(this.gl,s);else if(W().get("WEBGL_FORCE_F16_TEXTURES"))throw new Error("GL context does not support half float textures, yet the environment flag WEBGL_FORCE_F16_TEXTURES is set to true.");if(this.colorBufferFloatExtension=this.gl.getExtension(a),cn(this.gl,n))this.colorBufferHalfFloatExtension=qu(this.gl,n);else if(W().get("WEBGL_FORCE_F16_TEXTURES"))throw new Error("GL context does not support color renderable half floats, yet the environment flag WEBGL_FORCE_F16_TEXTURES is set to true.")}else if(a="EXT_color_buffer_float",cn(this.gl,a))this.colorBufferFloatExtension=this.gl.getExtension(a);else if(cn(this.gl,n))this.colorBufferHalfFloatExtension=this.gl.getExtension(n);else throw new Error("GL context does not support color renderable floats");this.vertexBuffer=I6(this.gl),this.indexBuffer=S6(this.gl),this.framebuffer=n6(this.gl),this.textureConfig=y3(this.gl,this.textureHalfFloatExtension)}get debug(){return W().getBool("DEBUG")}dispose(){if(this.disposed)return;this.program!=null&&console.warn("Disposing a GPGPUContext that still has a bound WebGLProgram. This is probably a resource leak, delete the program with GPGPUContext.deleteProgram before disposing."),this.outputTexture!=null&&console.warn("Disposing a GPGPUContext that still has a bound output matrix texture. This is probably a resource leak, delete the output matrix texture with GPGPUContext.deleteMatrixTexture before disposing.");let e=this.gl;le(e,()=>e.finish()),le(e,()=>e.bindFramebuffer(e.FRAMEBUFFER,null)),le(e,()=>e.deleteFramebuffer(this.framebuffer)),le(e,()=>e.bindBuffer(e.ARRAY_BUFFER,null)),le(e,()=>e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,null)),le(e,()=>e.deleteBuffer(this.indexBuffer)),this.disposed=!0}createFloat32MatrixTexture(e,t){return this.throwIfDisposed(),T6(this.gl,e,t,this.textureConfig)}createFloat16MatrixTexture(e,t){return this.throwIfDisposed(),C6(this.gl,e,t,this.textureConfig)}createUnsignedBytesMatrixTexture(e,t){return this.throwIfDisposed(),N6(this.gl,e,t,this.textureConfig)}uploadPixelDataToTexture(e,t){this.throwIfDisposed(),_6(this.gl,e,t)}uploadDenseMatrixToTexture(e,t,a,n){this.throwIfDisposed(),$6(this.gl,e,t,a,n,this.textureConfig)}createFloat16PackedMatrixTexture(e,t){return this.throwIfDisposed(),R6(this.gl,e,t,this.textureConfig)}createPackedMatrixTexture(e,t){return this.throwIfDisposed(),E6(this.gl,e,t,this.textureConfig)}deleteMatrixTexture(e){this.throwIfDisposed(),this.outputTexture===e&&(k1(this.gl,this.framebuffer),this.outputTexture=null),le(this.gl,()=>this.gl.deleteTexture(e))}downloadByteEncodedFloatMatrixFromOutputTexture(e,t,a){return this.downloadMatrixDriver(e,()=>O6(this.gl,t,a,this.textureConfig))}downloadPackedMatrixFromBuffer(e,t,a,n,r,s){return D6(this.gl,e,t,a,n,r,s,this.textureConfig)}downloadFloat32MatrixFromBuffer(e,t){return F6(this.gl,e,t)}createBufferFromTexture(e,t,a){this.bindTextureToFrameBuffer(e);let n=P6(this.gl,t,a,this.textureConfig);return this.unbindTextureToFrameBuffer(),n}createAndWaitForFence(){let e=this.createFence(this.gl);return this.pollFence(e)}createFence(e){let t,a;if(W().getBool("WEBGL_FENCE_API_ENABLED")){let n=e,r=n.fenceSync(n.SYNC_GPU_COMMANDS_COMPLETE,0);e.flush(),a=()=>{let s=n.clientWaitSync(r,0,0);return s===n.ALREADY_SIGNALED||s===n.CONDITION_SATISFIED},t=r}else W().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION")>0?(t=this.beginQuery(),this.endQuery(),a=()=>this.isQueryAvailable(t,W().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION"))):a=()=>!0;return{query:t,isFencePassed:a}}downloadMatrixFromPackedTexture(e,t,a){return this.downloadMatrixDriver(e,()=>z6(this.gl,t,a))}createProgram(e){this.throwIfDisposed();let t=this.gl;this.vertexShader==null&&(this.vertexShader=k6(t));let a=Y7(t);le(t,()=>t.attachShader(a,this.vertexShader)),le(t,()=>t.attachShader(a,e)),J7(t,a);let n;return n=Object.assign(a,{vao:this.createVertexArray()}),this.bindVertexArray(n.vao),le(t,()=>t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer)),console.assert(M6(t,n,this.vertexBuffer),"gpgpu_util.bindVertexProgramAttributeStreams not fully successful."),this.debug&&gc(t,n),this.setProgram(n),n}deleteProgram(e){this.throwIfDisposed(),e===this.program&&(this.program=null),e!=null&&(le(this.gl,()=>this.gl.deleteProgram(e)),this.deleteVertexArray(e.vao))}setProgram(e){this.throwIfDisposed(),this.program=e,this.program!=null&&(this.bindVertexArray(this.program.vao),this.debug&&gc(this.gl,this.program)),le(this.gl,()=>this.gl.useProgram(e))}getUniformLocation(e,t,a=!0){return this.throwIfDisposed(),a?s6(this.gl,e,t):i6(this.gl,e,t)}getAttributeLocation(e,t){return this.throwIfDisposed(),le(this.gl,()=>this.gl.getAttribLocation(e,t))}getUniformLocationNoThrow(e,t){return this.throwIfDisposed(),this.gl.getUniformLocation(e,t)}setInputMatrixTexture(e,t,a){this.throwIfDisposed(),this.throwIfNoProgram(),o6(this.gl,e,t,a)}setOutputMatrixTexture(e,t,a){this.setOutputMatrixTextureDriver(e,a,t)}setOutputPackedMatrixTexture(e,t,a){this.throwIfDisposed();let[n,r]=lu(t,a);this.setOutputMatrixTextureDriver(e,n,r)}setOutputMatrixWriteRegion(e,t,a,n){this.setOutputMatrixWriteRegionDriver(a,e,n,t)}setOutputPackedMatrixWriteRegion(e,t,a,n){throw new Error("setOutputPackedMatrixWriteRegion not implemented.")}debugValidate(){this.program!=null&&gc(this.gl,this.program),Xu(this.gl)}executeProgram(){this.throwIfDisposed(),this.throwIfNoProgram();let e=this.gl;if(this.debug){let t=this.getVertexArray();console.assert(t===this.program.vao,"VAO changed between setProgram and executeProgram!"),this.debugValidate()}le(e,()=>e.drawElements(e.TRIANGLES,6,e.UNSIGNED_SHORT,0))}blockUntilAllProgramsCompleted(){this.throwIfDisposed(),le(this.gl,()=>this.gl.finish())}getQueryTimerExtension(){return this.disjointQueryTimerExtension==null&&(this.disjointQueryTimerExtension=qu(this.gl,W().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION")===2?"EXT_disjoint_timer_query_webgl2":"EXT_disjoint_timer_query")),this.disjointQueryTimerExtension}getQueryTimerExtensionWebGL2(){return this.getQueryTimerExtension()}getQueryTimerExtensionWebGL1(){return this.getQueryTimerExtension()}beginQuery(){if(W().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION")===2){let a=this.gl,n=this.getQueryTimerExtensionWebGL2(),r=a.createQuery();return a.beginQuery(n.TIME_ELAPSED_EXT,r),r}let e=this.getQueryTimerExtensionWebGL1(),t=e.createQueryEXT();return e.beginQueryEXT(e.TIME_ELAPSED_EXT,t),t}endQuery(){if(W().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION")===2){let t=this.gl,a=this.getQueryTimerExtensionWebGL2();t.endQuery(a.TIME_ELAPSED_EXT);return}let e=this.getQueryTimerExtensionWebGL1();e.endQueryEXT(e.TIME_ELAPSED_EXT)}async waitForQueryAndGetTime(e){return await v.repeatedTry(()=>this.disposed||this.isQueryAvailable(e,W().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION"))),this.getQueryTime(e,W().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION"))}getQueryTime(e,t){if(t===0)return null;if(t===2){let a=this.gl;return a.getQueryParameter(e,a.QUERY_RESULT)/1e6}else{let a=this.getQueryTimerExtensionWebGL1();return a.getQueryObjectEXT(e,a.QUERY_RESULT_EXT)/1e6}}isQueryAvailable(e,t){if(t===0)return!0;if(t===2){let a=this.gl,n=this.getQueryTimerExtensionWebGL2(),r=a.getQueryParameter(e,a.QUERY_RESULT_AVAILABLE);return this.disjoint==null&&(this.disjoint=this.gl.getParameter(n.GPU_DISJOINT_EXT)),r&&!this.disjoint}else{let a=this.getQueryTimerExtensionWebGL1(),n=a.getQueryObjectEXT(e,a.QUERY_RESULT_AVAILABLE_EXT);return this.disjoint==null&&(this.disjoint=this.gl.getParameter(a.GPU_DISJOINT_EXT)),n&&!this.disjoint}}pollFence(e){return new Promise(t=>{this.addItemToPoll(()=>e.isFencePassed(),()=>t())})}pollItems(){let e=aU(this.itemsToPoll.map(t=>t.isDoneFn));for(let t=0;t<=e;++t){let{resolveFn:a}=this.itemsToPoll[t];a()}this.itemsToPoll=this.itemsToPoll.slice(e+1)}addItemToPoll(e,t){if(this.itemsToPoll.push({isDoneFn:e,resolveFn:t}),this.itemsToPoll.length>1)return;let a;"setTimeoutCustom"in W().platform&&(a=W().platform.setTimeoutCustom.bind(W().platform)),v.repeatedTry(()=>(this.pollItems(),this.itemsToPoll.length===0),()=>0,null,a)}bindTextureToFrameBuffer(e){this.throwIfDisposed(),xc(this.gl,e,this.framebuffer),this.debug&&Xu(this.gl)}unbindTextureToFrameBuffer(){this.outputTexture!=null?(xc(this.gl,this.outputTexture,this.framebuffer),this.debug&&Xu(this.gl)):k1(this.gl,this.framebuffer)}downloadMatrixDriver(e,t){this.bindTextureToFrameBuffer(e);let a=t();return this.unbindTextureToFrameBuffer(),a}setOutputMatrixTextureDriver(e,t,a){this.throwIfDisposed();let n=this.gl;xc(n,e,this.framebuffer),this.debug&&Xu(n),this.outputTexture=e,le(n,()=>n.viewport(0,0,t,a)),le(n,()=>n.scissor(0,0,t,a))}setOutputMatrixWriteRegionDriver(e,t,a,n){this.throwIfDisposed(),le(this.gl,()=>this.gl.scissor(e,t,a,n))}throwIfDisposed(){if(this.disposed)throw new Error("Attempted to use disposed GPGPUContext.")}throwIfNoProgram(){if(this.program==null)throw new Error("No GPU program is currently set.")}};function aU(e){let t=0;for(;t`${e}.${a}`)}function va(e,t){return t===1?[e]:V6(e,t)}function jU(e,t){if(e===1)return"rc";let a="";for(let n=0;n ${this.enableShapeUniforms?"outShape":this.outputShape[0]}`;let t="";for(let a=this.rank-2;a= ${this.enableShapeUniforms?`outShape[${a}]`:this.outputShape[a]}`,a= ${a}; bool rEdge = rp1 >= ${n}; `}getOutput(e){let t=this.getSourceCoordsArr(e);return this.rank===1?`getA(rc), (rc + 1 >= ${this.enableShapeUniforms?"outShape":this.outputShape[0]} ? 0. : getA(rc + 1)), 0, 0`:`getA(${t[0]}), cEdge ? 0. : getA(${t[1]}), rEdge ? 0. : getA(${t[2]}), rEdge || cEdge ? 0. : getA(${t[3]})`}},U6=class{constructor(e,t){this.variableNames=["A"],this.packedInputs=!0,this.packedOutput=!0,this.customUniforms=[{name:"inputShape",type:"ivec3"}],this.outputShape=e,this.enableShapeUniforms=Na(this.outputShape.length);let a="";for(let n=0;n<4;n++){let r="thisRC = rc;";n%2===1&&(r+="thisRC.z += 1;"),n>1&&(r+="thisRC.y += 1;"),a+=` ${r} ${n>0?"if(thisRC.y < rows && thisRC.z < cols){":""} int flatIndex = getFlatIndex(thisRC); ivec3 inputRC = inputCoordsFromReshapedOutCoords(flatIndex); vec2 inputRCInnerDims = vec2(float(inputRC.y),float(inputRC.z)); result[${n}] = getChannel(getA(inputRC.x, inputRC.y, inputRC.z), inputRCInnerDims); ${n>0?"}":""} `}this.userCode=` ${XU(t,this.enableShapeUniforms)} ${this.enableShapeUniforms?w3():v3(e)} void main() { ivec3 rc = getOutputCoords(); vec4 result = vec4(0.); ivec3 thisRC; int rows = ${this.enableShapeUniforms?"outShape[1]":e[1]}; int cols = ${this.enableShapeUniforms?"outShape[2]":e[2]}; ${a} setOutput(result); } `}};function XU(e,t){return` ivec3 inputCoordsFromReshapedOutCoords(int index) { ${t?dV(["r","c","d"],"inputShape"):Ao(["r","c","d"],e)} return ivec3(r, c, d); } `}var KU=class{constructor(e){this.gpgpu=e,this.numUsedTextures=0,this.numFreeTextures=0,this._numBytesAllocated=0,this._numBytesFree=0,this.freeTextures={},this.logEnabled=!1,this.usedTextures={}}acquireTexture(e,t,a){let n=mx(t,a),r=gx(e,n,a);r in this.freeTextures||(this.freeTextures[r]=[]),r in this.usedTextures||(this.usedTextures[r]=[]);let s=fx(e,n,this.gpgpu.gl,this.gpgpu.textureConfig,a);if(this.freeTextures[r].length>0){this.numFreeTextures--,this.numUsedTextures++,this._numBytesFree-=s,this.log();let o=this.freeTextures[r].shift();return this.usedTextures[r].push(o),o}let i;return n===na.PACKED_2X2_FLOAT32?i=this.gpgpu.createPackedMatrixTexture(e[0],e[1]):n===na.PACKED_2X2_FLOAT16?i=this.gpgpu.createFloat16PackedMatrixTexture(e[0],e[1]):n===na.UNPACKED_FLOAT32?i=this.gpgpu.createFloat32MatrixTexture(e[0],e[1]):n===na.UNPACKED_FLOAT16?i=this.gpgpu.createFloat16MatrixTexture(e[0],e[1]):n===na.PACKED_4X1_UNSIGNED_BYTE&&(i=this.gpgpu.createUnsignedBytesMatrixTexture(e[0],e[1])),this.usedTextures[r].push(i),this.numUsedTextures++,this._numBytesAllocated+=s,this.log(),i}releaseTexture(e,t,a,n){if(this.freeTextures==null)return;let r=mx(a,n),s=gx(t,r,n);s in this.freeTextures||(this.freeTextures[s]=[]);let i=fx(t,r,this.gpgpu.gl,this.gpgpu.textureConfig,n),o=W().get("WEBGL_DELETE_TEXTURE_THRESHOLD");o!==-1&&this._numBytesAllocated>o?(this.gpgpu.deleteMatrixTexture(e.texture),this._numBytesAllocated-=i):(this.freeTextures[s].push(e),this.numFreeTextures++,this._numBytesFree+=i),this.numUsedTextures--;let l=this.usedTextures[s],u=l.indexOf(e);if(u<0)throw new Error("Cannot release a texture that was never provided by this texture manager");l.splice(u,1),this.log()}log(){if(!this.logEnabled)return;let e=this.numFreeTextures+this.numUsedTextures;console.log("Free/Used",`${this.numFreeTextures} / ${this.numUsedTextures}`,`(${e})`);let t=this._numBytesFree/this._numBytesAllocated;console.log(`Bytes allocated: ${this._numBytesAllocated}`),console.log(`Bytes unused: ${this._numBytesFree} (${Math.round(100*t)}%)`)}get numBytesAllocated(){return this._numBytesAllocated}get numBytesFree(){return this._numBytesFree}getNumUsedTextures(){return this.numUsedTextures}getNumFreeTextures(){return this.numFreeTextures}dispose(){if(this.freeTextures!=null){for(let e in this.freeTextures)this.freeTextures[e].forEach(t=>{this.gpgpu.deleteMatrixTexture(t.texture)});for(let e in this.usedTextures)this.usedTextures[e].forEach(t=>{this.gpgpu.deleteMatrixTexture(t.texture)});this.freeTextures=null,this.usedTextures=null,this.numUsedTextures=0,this.numFreeTextures=0,this._numBytesAllocated=0,this._numBytesFree=0}}};function ZU(e,t){let a=e;if(t===a.R32F)return 4;if(t===a.R16F)return 2;if(t===a.RGBA32F||t===e.RGBA)return 16;if(t===a.RGBA16F)return 8;if(t===a.RGBA8)return 4;throw new Error(`Unknown internal format ${t}`)}function fx(e,t,a,n,r){let s=YU(t,n),i;if(r){let[l,u]=lu(e[0],e[1]);i=l*u}else{let[l,u]=up(e[0],e[1]);i=l*u}let o=ZU(a,s);return i*o}function YU(e,t){switch(e){case na.PACKED_2X2_FLOAT32:return C3(t);case na.PACKED_2X2_FLOAT16:return N3(t);case na.UNPACKED_FLOAT32:return I3(t);case na.UNPACKED_FLOAT16:return S3(t);case na.PACKED_4X1_UNSIGNED_BYTE:return T3(t);default:throw new Error(`Unknown physical texture type ${e}`)}}function JU(e){return W().getBool("WEBGL_RENDER_FLOAT32_ENABLED")?e?na.PACKED_2X2_FLOAT32:na.UNPACKED_FLOAT32:e?na.PACKED_2X2_FLOAT16:na.UNPACKED_FLOAT16}function mx(e,t){if(e===pn.UPLOAD)return na.PACKED_2X2_FLOAT32;if(e===pn.RENDER||e==null)return JU(t);if(e===pn.DOWNLOAD||e===pn.PIXELS)return na.PACKED_4X1_UNSIGNED_BYTE;throw new Error(`Unknown logical texture type ${e}`)}function gx(e,t,a){return`${e[0]}_${e[1]}_${t}_${a}`}var qn=class{constructor(e,t){this.variableNames=["A"],this.outputShape=e,this.enableShapeUniforms=Na(this.outputShape.length),this.userCode=` float unaryOperation(float x) { ${t} } void main() { float x = getAAtOutCoords(); float y = unaryOperation(x); setOutput(y); } `}},Cn="if (isnan(x)) return x;",QU="return x;",xx="return abs(x);",eG="return (x >= 0.0) ? x : (exp(x) - 1.0);",tG=Cn+` return (x < 0.0) ? 0.0 : x; `,aG=Cn+` return (x < 0.0) ? 0.0 : min(6.0, x); `,Dr="return x;",nG="return 1.0 / (1.0 + exp(-1.0 * x));",rG="return x;",sG=` vec4 result; result.r = (x.r >= 0.0) ? x.r : (exp(x.r) - 1.0); result.g = (x.g >= 0.0) ? x.g : (exp(x.g) - 1.0); result.b = (x.b >= 0.0) ? x.b : (exp(x.b) - 1.0); result.a = (x.a >= 0.0) ? x.a : (exp(x.a) - 1.0); return result; `,iG=` vec4 result = x * vec4(greaterThanEqual(x, vec4(0.0))); bvec4 isNaN = isnan(x); result.r = isNaN.r ? x.r : result.r; result.g = isNaN.g ? x.g : result.g; result.b = isNaN.b ? x.b : result.b; result.a = isNaN.a ? x.a : result.a; return result; `,oG=` vec4 result = min(x, vec4(6.)) * vec4(greaterThanEqual(x, vec4(0.0))); bvec4 isNaN = isnan(x); result.r = isNaN.r ? x.r : result.r; result.g = isNaN.g ? x.g : result.g; result.b = isNaN.b ? x.b : result.b; result.a = isNaN.a ? x.a : result.a; return result; `,lG="return 1.0 / (1.0 + exp(-1.0 * x));",Vr=class{constructor(e,t){this.variableNames=["A"],this.packedInputs=!0,this.packedOutput=!0,this.outputShape=e,this.enableShapeUniforms=Na(this.outputShape.length),this.userCode=` vec4 unaryOperation(vec4 x) { ${t} } void main() { vec4 x = getAAtOutCoords(); vec4 y = unaryOperation(x); setOutput(y); } `}},uG=class{constructor(e){this.variableNames=["A"],this.packedInputs=!0,this.packedOutput=!1,this.outputShape=e,this.enableShapeUniforms=Na(this.outputShape.length);let t=e.length,a=va("rc",t),n=gt(t),r=jU(t,a),s=a.slice(-2),i=t<=1?"rc":`vec2(${s.join(",")})`;this.userCode=` void main() { ${n} rc = getOutputCoords(); vec4 packedInput = getA(${r}); setOutput(getChannel(packedInput, ${i})); } `}},dG=Tn.whereImpl,pG=1e-7,cG=1e-4,zm={};function hG(e){return e in zm||(zm[e]={}),zm[e]}var fG=W().getNumber("CPU_HANDOFF_SIZE_THRESHOLD"),mG=600;function gG(){return W().global.screen==null?1024:W().global.screen.height*W().global.screen.width*window.devicePixelRatio*mG/1024/1024}var fu=class extends bl{constructor(e){if(super(),this.pendingRead=new WeakMap,this.pendingDisposal=new WeakSet,this.dataRefCount=new WeakMap,this.numBytesInGPU=0,this.uploadWaitMs=0,this.downloadWaitMs=0,this.lastGlFlushTime=0,this.warnedAboutMemory=!1,this.pendingDeletes=0,this.disposed=!1,!W().getBool("HAS_WEBGL"))throw new Error("WebGL is not supported on this device");let t;if(e!=null){if(e instanceof il)t=e;else{let a=Dn(W().getNumber("WEBGL_VERSION"),e);t=new il(a)}this.binaryCache={},this.gpgpuCreatedLocally=!1}else{let a=Dn(W().getNumber("WEBGL_VERSION"));t=new il(a),this.binaryCache=hG(W().getNumber("WEBGL_VERSION")),this.gpgpuCreatedLocally=!0}this.gpgpu=t,this.canvas=this.gpgpu.gl.canvas,this.textureManager=new KU(this.gpgpu),this.numMBBeforeWarning=gG(),this.texData=new vd(this,kt())}nextDataId(){return fu.nextDataId++}numDataIds(){return this.texData.numDataIds()-this.pendingDeletes}writeTexture(e,t,a,n,r,s){let i=this.makeTensorInfo(t,a),o=this.texData.get(i.dataId);o.isPacked=!1,o.texture={texture:e,texShape:[n,r]},o.texShape=[n,r];let l=Ku(t),u=new hx(l,!1,s),p=this.runWebGLProgram(u,[i],a,[[n,r]]);return p.shape=t,o.texture=null,this.disposeIntermediateTensorInfo(i),p.dataId}write(e,t,a){if((W().getBool("WEBGL_CHECK_NUMERICAL_PROBLEMS")||W().getBool("DEBUG"))&&this.checkNumericalProblems(e),a==="complex64"&&e!=null)throw new Error("Cannot write to a complex64 dtype. Please use tf.complex(real, imag).");let n={id:this.nextDataId()};return this.texData.set(n,{shape:t,dtype:a,values:e,usage:pn.UPLOAD,refCount:1}),n}refCount(e){return this.texData.has(e)?this.texData.get(e).refCount:0}incRef(e){let t=this.texData.get(e);t.refCount++}decRef(e){if(this.texData.has(e)){let t=this.texData.get(e);t.refCount--}}move(e,t,a,n,r){if(W().getBool("DEBUG")&&this.checkNumericalProblems(t),n==="complex64")throw new Error("Cannot write to a complex64 dtype. Please use tf.complex(real, imag).");this.texData.set(e,{shape:a,dtype:n,values:t,usage:pn.UPLOAD,refCount:r})}disposeIntermediateTensorInfo(e){this.disposeData(e.dataId)}readSync(e){let t=this.texData.get(e),{values:a,dtype:n,complexTensorInfos:r,slice:s,shape:i,isPacked:o}=t;if(s!=null){let c;o?c=new Vr(i,Dr):c=new qn(i,Dr);let d=this.runWebGLProgram(c,[{dataId:e,shape:i,dtype:n}],n),h=this.readSync(d.dataId);return this.disposeIntermediateTensorInfo(d),h}if(a!=null)return this.convertAndCacheOnCPU(e);if(n==="string")return a;let l=this.activeTimers!=null,u;l&&(u=v.now());let p;if(n==="complex64"){let c=this.readSync(r.real.dataId),d=this.readSync(r.imag.dataId);p=T.mergeRealAndImagArrays(c,d)}else p=this.getValuesFromTexture(e);return l&&(this.downloadWaitMs+=v.now()-u),this.convertAndCacheOnCPU(e,p)}async read(e){if(this.pendingRead.has(e)){let h=this.pendingRead.get(e);return new Promise(f=>h.push(f))}let t=this.texData.get(e),{values:a,shape:n,slice:r,dtype:s,complexTensorInfos:i,isPacked:o}=t;if(r!=null){let h;o?h=new Vr(n,Dr):h=new qn(n,Dr);let f=this.runWebGLProgram(h,[{dataId:e,shape:n,dtype:s}],s),m=this.read(f.dataId);return this.disposeIntermediateTensorInfo(f),m}if(a!=null)return this.convertAndCacheOnCPU(e);if(W().getBool("DEBUG")&&!W().getBool("WEBGL_DOWNLOAD_FLOAT_ENABLED")&&W().getNumber("WEBGL_VERSION")===2)throw new Error("tensor.data() with WEBGL_DOWNLOAD_FLOAT_ENABLED=false and WEBGL_VERSION=2 not yet supported.");let l=null,u;if(s!=="complex64"&&W().get("WEBGL_BUFFER_SUPPORTED")){u=this.decode(e);let h=this.texData.get(u.dataId);l=this.gpgpu.createBufferFromTexture(h.texture.texture,...uc(n))}this.pendingRead.set(e,[]),s!=="complex64"&&await this.gpgpu.createAndWaitForFence();let p;if(s==="complex64"){let h=await Promise.all([this.read(i.real.dataId),this.read(i.imag.dataId)]),f=h[0],m=h[1];p=T.mergeRealAndImagArrays(f,m)}else if(l==null)p=this.getValuesFromTexture(e);else{let h=v.sizeFromShape(n);p=this.gpgpu.downloadFloat32MatrixFromBuffer(l,h)}if(u!=null&&this.disposeIntermediateTensorInfo(u),l!=null){let h=this.gpgpu.gl;le(h,()=>h.deleteBuffer(l))}let c=this.convertAndCacheOnCPU(e,p),d=this.pendingRead.get(e);return this.pendingRead.delete(e),d.forEach(h=>h(c)),this.pendingDisposal.has(e)&&(this.pendingDisposal.delete(e),this.disposeData(e)&&kt().removeDataId(e,this),this.pendingDeletes--),c}readToGPU(e,t={}){let a=this.texData.get(e),{values:n,shape:r,slice:s,dtype:i,isPacked:o,texture:l}=a;if(i==="complex64")throw new Error("Does not support reading texture for complex64 dtype.");if(s!=null){let d;o?d=new Vr(r,Dr):d=new qn(r,Dr);let h=this.runWebGLProgram(d,[{dataId:e,shape:r,dtype:i}],i),f=this.readToGPU(h,t);return this.disposeIntermediateTensorInfo(h),f}if(l==null)throw n!=null?new Error("Data is not on GPU but on CPU."):new Error("There is no data on GPU or CPU.");let u=this.decode(e,t.customTexShape),p=kt().makeTensorFromTensorInfo(u),c=this.texData.get(u.dataId);return Object.assign({tensorRef:p},c.texture)}bufferSync(e){let t=this.readSync(e.dataId);if(e.dtype==="string")try{let a=t.map(n=>v.decodeString(n));return Me(e.shape,e.dtype,a)}catch(a){throw new Error("Failed to decode encoded string bytes into utf-8")}return Me(e.shape,e.dtype,t)}checkNumericalProblems(e){if(e!=null)for(let t=0;t0}time(e){let t=this.activeTimers,a=[],n=!1;this.programTimersStack==null?(this.programTimersStack=a,n=!0):this.activeTimers.push(a),this.activeTimers=a,e();let r=v.flatten(this.activeTimers.map(o=>o.query)).filter(o=>o!=null),s=v.flatten(this.activeTimers.map(o=>o.name)).filter(o=>o!=null);this.activeTimers=t,n&&(this.programTimersStack=null);let i={uploadWaitMs:this.uploadWaitMs,downloadWaitMs:this.downloadWaitMs,kernelMs:null,wallMs:null};return(async()=>{if(W().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE")>0){let o=await Promise.all(r);i.kernelMs=v.sum(o),i.getExtraProfileInfo=()=>o.map((l,u)=>({name:s[u],ms:l})).map(l=>`${l.name}: ${l.ms}`).join(", ")}else i.kernelMs={error:"WebGL query timers are not supported in this environment."};return this.uploadWaitMs=0,this.downloadWaitMs=0,i})()}memory(){return{unreliable:!1,numBytesInGPU:this.numBytesInGPU,numBytesInGPUAllocated:this.textureManager.numBytesAllocated,numBytesInGPUFree:this.textureManager.numBytesFree}}startTimer(){return W().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE")>0?this.gpgpu.beginQuery():{startMs:v.now(),endMs:null}}endTimer(e){return W().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE")>0?(this.gpgpu.endQuery(),e):(e.endMs=v.now(),e)}async getQueryTime(e){if(W().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE")>0)return this.gpgpu.waitForQueryAndGetTime(e);let t=e;return t.endMs-t.startMs}disposeData(e,t=!1){if(this.pendingDisposal.has(e))return!1;if(!this.texData.has(e))return!0;if(t?this.texData.get(e).refCount=0:this.texData.get(e).refCount--,!t&&this.texData.get(e).refCount>0)return!1;if(this.pendingRead.has(e))return this.pendingDisposal.add(e),this.pendingDeletes++,!1;this.releaseGPUData(e);let{complexTensorInfos:a}=this.texData.get(e);return a!=null&&(this.disposeData(a.real.dataId,t),this.disposeData(a.imag.dataId,t)),this.texData.delete(e),!0}releaseGPUData(e){let{texture:t,dtype:a,texShape:n,usage:r,isPacked:s,slice:i}=this.texData.get(e),o=i&&i.origDataId||e,l=this.dataRefCount.get(o);l>1?this.dataRefCount.set(o,l-1):(this.dataRefCount.delete(o),t!=null&&(this.numBytesInGPU-=this.computeBytes(n,a),this.textureManager.releaseTexture(t,n,r,s)));let u=this.texData.get(e);u.texture=null,u.texShape=null,u.isPacked=!1,u.slice=null}getTexture(e){return this.uploadToGPU(e),this.texData.get(e).texture.texture}getDataInfo(e){return this.texData.get(e)}shouldExecuteOnCPU(e,t=fG){return W().getBool("WEBGL_CPU_FORWARD")&&e.every(a=>this.texData.get(a.dataId).texture==null&&v.sizeFromShape(a.shape)0&&v.isString(a[0])){let r=a.map(s=>v.encodeString(s));n=this.write(r,e,t)}else n=this.write(a,e,t);return this.texData.get(n).usage=null,{dataId:n,shape:e,dtype:t}}makeOutput(e,t,a){return kt().makeTensorFromTensorInfo(this.makeTensorInfo(e,t,a),this)}unpackTensor(e){let t=new uG(e.shape);return this.runWebGLProgram(t,[e],e.dtype)}packTensor(e){let t=new qU(e.shape),a=!0;return this.runWebGLProgram(t,[e],e.dtype,null,a)}packedReshape(e,t){let a=[Hs(e.shape),...js(e.shape)],n={dtype:e.dtype,shape:a,dataId:e.dataId},r=[Hs(t),...js(t)],s=new U6(r,a),i=!0,o=[a],l=this.runWebGLProgram(s,[n],e.dtype,o,i);return{dataId:l.dataId,shape:t,dtype:l.dtype}}decode(e,t){let a=this.texData.get(e),{isPacked:n,shape:r,dtype:s}=a;if(t!=null){let c=v.sizeFromShape(r),d=t[0]*t[1]*4;v.assert(c<=d,()=>"customTexShape is too small. Row * Column * 4 should be equal or larger than the size of the tensor data.")}let i=Ku(r),o;n?o=new YV(i):o=new ZV(i);let l=!0,u=[t!=null?t:uc(i)],p=this.runWebGLProgram(o,[{shape:i,dtype:s,dataId:e}],s,u,l,t);return{dtype:s,shape:r,dataId:p.dataId}}runWebGLProgram(e,t,a,n,r=!1,s){let i=this.makeTensorInfo(e.outputShape,a),o=this.texData.get(i.dataId);if(e.packedOutput&&(o.isPacked=!0),e.outPackingScheme===fd.DENSE){let g=s!=null?s:uc(e.outputShape);o.texShape=g.map(x=>x*2)}if(e.outTexUsage!=null&&(o.usage=e.outTexUsage),v.sizeFromShape(i.shape)===0)return o.values=v.getTypedArrayFromDType(i.dtype,0),i;let l=[],u=t.map(g=>{if(g.dtype==="complex64")throw new Error("GPGPUProgram does not support complex64 input. For complex64 dtypes, please separate the program into real and imaginary parts.");let x=this.texData.get(g.dataId);if(x.texture==null){if(!e.packedInputs&&v.sizeFromShape(g.shape)<=W().getNumber("WEBGL_SIZE_UPLOAD_UNIFORM"))return{shape:g.shape,texData:null,isUniform:!0,uniformValues:x.values};e.packedInputs&&(x.isPacked=!0,x.shape=g.shape)}if(this.uploadToGPU(g.dataId),!!x.isPacked!=!!e.packedInputs)g=x.isPacked?this.unpackTensor(g):this.packTensor(g),l.push(g),x=this.texData.get(g.dataId);else if(x.isPacked&&!md(x.shape,g.shape)){let A=g,y=g.shape;g.shape=x.shape,g=this.packedReshape(g,y),l.push(g),x=this.texData.get(g.dataId),A.shape=y}return{shape:g.shape,texData:x,isUniform:!1}});this.uploadToGPU(i.dataId);let p={shape:i.shape,texData:o,isUniform:!1},c=KV(e,u,p),d=this.getAndSaveBinary(c,()=>qV(this.gpgpu,e,u,p)),h=this.activeTimers!=null,f;h&&(f=this.startTimer()),W().get("ENGINE_COMPILE_ONLY")||XV(this.gpgpu,d,u,p,n),l.forEach(g=>this.disposeIntermediateTensorInfo(g)),h&&(f=this.endTimer(f),this.activeTimers.push({name:e.constructor.name,query:this.getQueryTime(f)}));let m=W().get("WEBGL_FLUSH_THRESHOLD");if(m>0){let g=v.now();g-this.lastGlFlushTime>m&&(this.gpgpu.gl.flush(),this.lastGlFlushTime=g)}if(!W().getBool("WEBGL_LAZILY_UNPACK")&&o.isPacked&&r===!1){let g=this.unpackTensor(i);return this.disposeIntermediateTensorInfo(i),g}return i}compileAndRun(e,t,a,n,r=!1){return a=a||t[0].dtype,this.runWebGLProgram(e,t,a,n,r)}getAndSaveBinary(e,t){return e in this.binaryCache||(this.binaryCache[e]=t()),this.binaryCache[e]}getTextureManager(){return this.textureManager}dispose(){this.disposed||(W().getBool("IS_TEST")||Object.keys(this.binaryCache).forEach(e=>{this.gpgpu.deleteProgram(this.binaryCache[e].webGLProgram),delete this.binaryCache[e]}),this.textureManager.dispose(),this.canvas!=null&&typeof HTMLCanvasElement!="undefined"&&this.canvas instanceof HTMLCanvasElement?this.canvas.remove():this.canvas=null,this.gpgpuCreatedLocally&&(this.gpgpu.program=null,this.gpgpu.dispose()),this.disposed=!0)}floatPrecision(){return this.floatPrecisionValue==null&&(this.floatPrecisionValue=$e(()=>{if(!W().get("WEBGL_RENDER_FLOAT32_ENABLED")){let e=W().getBool("DEBUG");W().set("DEBUG",!1);let t=this.abs(Fe(1e-8)).dataSync()[0];if(W().set("DEBUG",e),t>0)return 32}return 16})),this.floatPrecisionValue}epsilon(){return this.floatPrecision()===32?pG:cG}uploadToGPU(e){let t=this.texData.get(e),{shape:a,dtype:n,values:r,texture:s,usage:i,isPacked:o}=t;if(s!=null)return;let l=this.activeTimers!=null,u;l&&(u=v.now());let p=t.texShape;if(p==null&&(p=d6(a,o),t.texShape=p),r!=null){let c=Ku(a),d,h=p[1],f=p[0],m=r instanceof Uint8Array||r instanceof Uint8ClampedArray;(o||!m)&&([h,f]=lu(p[0],p[1])),o?d=new tU(c,m):d=new hx(c,m);let g=m?[f,h]:p,x=this.makeTensorInfo(g,n),A=this.texData.get(x.dataId);m?A.usage=pn.PIXELS:A.usage=pn.UPLOAD,A.texShape=g,this.gpgpu.uploadDenseMatrixToTexture(this.getTexture(x.dataId),h,f,r);let y=[[f,h]],b=!0,w=this.runWebGLProgram(d,[x],n,y,b),S=this.texData.get(w.dataId);t.texShape=S.texShape,t.isPacked=S.isPacked,t.usage=S.usage,W().get("ENGINE_COMPILE_ONLY")?this.disposeData(w.dataId):(t.texture=S.texture,t.values=null,this.texData.delete(w.dataId)),this.disposeIntermediateTensorInfo(x),l&&(this.uploadWaitMs+=v.now()-u)}else{let c=this.acquireTexture(p,i,n,o);t.texture=c}}convertAndCacheOnCPU(e,t){let a=this.texData.get(e),{dtype:n}=a;return t!=null&&(a.values=xG(t,n)),a.values}acquireTexture(e,t,a,n){if(this.numBytesInGPU+=this.computeBytes(e,a),!this.warnedAboutMemory&&this.numBytesInGPU>this.numMBBeforeWarning*1024*1024){let r=(this.numBytesInGPU/1024/1024).toFixed(2);this.warnedAboutMemory=!0,console.warn(`High memory usage in GPU: ${r} MB, most likely due to a memory leak`)}return this.textureManager.acquireTexture(e,t,n)}computeBytes(e,t){return e[0]*e[1]*v.bytesPerElement(t)}checkCompileCompletion(){for(let[,e]of Object.entries(this.binaryCache))this.checkCompletion_(e)}async checkCompileCompletionAsync(){let e=[];if(this.gpgpu.parallelCompilationExtension){for(let[,t]of Object.entries(this.binaryCache))e.push(this.checkCompletionAsync_(t));return Promise.all(e)}else{for(let[,t]of Object.entries(this.binaryCache)){let a=new Promise(n=>{try{this.checkCompletion_(t),n(!0)}catch(r){throw r}});e.push(a)}return Promise.all(e)}}async checkCompletionAsync_(e){return this.gpgpu.gl.getProgramParameter(e.webGLProgram,this.gpgpu.parallelCompilationExtension.COMPLETION_STATUS_KHR)?this.checkCompletion_(e):(await b4(),this.checkCompletionAsync_(e))}checkCompletion_(e){if(this.gpgpu.gl.getProgramParameter(e.webGLProgram,this.gpgpu.gl.LINK_STATUS)===!1)throw console.log(this.gpgpu.gl.getProgramInfoLog(e.webGLProgram)),this.gpgpu.gl.getShaderParameter(e.fragmentShader,this.gpgpu.gl.COMPILE_STATUS)===!1?(b3(e.source,this.gpgpu.gl.getShaderInfoLog(e.fragmentShader)),new Error("Failed to compile fragment shader.")):new Error("Failed to link vertex and fragment shaders.");return!0}getUniformLocations(){for(let[,e]of Object.entries(this.binaryCache)){let{uniformLocations:t,customUniformLocations:a,infLoc:n,nanLoc:r,inShapesLocations:s,inTexShapesLocations:i,outShapeLocation:o,outShapeStridesLocation:l,outTexShapeLocation:u}=v6(this.gpgpu,e.program,e.webGLProgram);e.uniformLocations=t,e.customUniformLocations=a,e.infLoc=n,e.nanLoc=r,e.inShapesLocations=s,e.inTexShapesLocations=i,e.outShapeLocation=o,e.outShapeStridesLocation=l,e.outTexShapeLocation=u}}createTensorFromTexture(e,t,a){let{texture:n,height:r,width:s,channels:i}=e,o=kt().backend;if(!o.gpgpu.gl.isTexture(n))throw new Error("The texture is invalid. Also, please make sure the texture and the TFJS WebGL backend are using the same canvas. If you want to use your own custom canvas, you have to create and use the custom TFJS WebGL backend created from the canvas through 'new tf.MathBackendWebGL(customCanvas)'.");let l=o.writeTexture(n,t,a,r,s,i);return kt().makeTensorFromDataId(l,t,a,o)}};fu.nextDataId=0;function xG(e,t){if(t==="float32"||t==="complex64")return e;if(t==="int32"||t==="bool"){let a=t==="int32"?new Int32Array(e.length):new Uint8Array(e.length);for(let n=0;nnew fu,2);var yG={forceHalfFloat:G6},R3=` if (isnan(a)) return a; if (isnan(b)) return b; `,Al=class{constructor(e,t,a){this.variableNames=["A","B"],this.outputShape=T.assertAndGetBroadcastShape(t,a),this.enableShapeUniforms=Na(this.outputShape.length),this.userCode=` float binaryOperation(float a, float b) { ${e} } void main() { float a = getAAtOutCoords(); float b = getBAtOutCoords(); setOutput(binaryOperation(a, b)); } `}},pp=` result.r = isNaN.r ? NAN : result.r; result.g = isNaN.g ? NAN : result.g; result.b = isNaN.b ? NAN : result.b; result.a = isNaN.a ? NAN : result.a; `,cp=class{constructor(e,t,a,n=!1){this.variableNames=["A","B"],this.supportsBroadcasting=!0,this.packedInputs=!0,this.packedOutput=!0,this.outputShape=T.assertAndGetBroadcastShape(t,a);let r=this.outputShape.length;this.enableShapeUniforms=Na(r);let s="";if(n)if(r===0||v.sizeFromShape(this.outputShape)===1)s=` result.y = 0.; result.z = 0.; result.w = 0.; `;else if(s=` ${gt(r)} coords = getOutputCoords(); `,r===1)this.enableShapeUniforms?s+=` result.y = (coords + 1) >= outShape ? 0. : result.y; result.z = 0.; result.w = 0.; `:s+=` result.y = (coords + 1) >= ${this.outputShape[0]} ? 0. : result.y; result.z = 0.; result.w = 0.; `;else{let i=va("coords",r);this.enableShapeUniforms?s+=` bool nextRowOutOfBounds = (${i[r-2]} + 1) >= outShape[${r} - 2]; bool nextColOutOfBounds = (${i[r-1]} + 1) >= outShape[${r} - 1]; result.y = nextColOutOfBounds ? 0. : result.y; result.z = nextRowOutOfBounds ? 0. : result.z; result.w = nextColOutOfBounds || nextRowOutOfBounds ? 0. : result.w; `:s+=` bool nextRowOutOfBounds = (${i[r-2]} + 1) >= ${this.outputShape[r-2]}; bool nextColOutOfBounds = (${i[r-1]} + 1) >= ${this.outputShape[r-1]}; result.y = nextColOutOfBounds ? 0. : result.y; result.z = nextRowOutOfBounds ? 0. : result.z; result.w = nextColOutOfBounds || nextRowOutOfBounds ? 0. : result.w; `}this.userCode=` vec4 binaryOperation(vec4 a, vec4 b) { ${e} } void main() { vec4 a = getAAtOutCoords(); vec4 b = getBAtOutCoords(); vec4 result = binaryOperation(a, b); ${s} setOutput(result); } `}};function Za(e){let{inputs:t,backend:a}=e,{x:n}=t;return a.incRef(n.dataId),{dataId:n.dataId,shape:n.shape,dtype:n.dtype}}var bG={kernelName:ki,backendName:"webgl",kernelFunc:Za};function ls(e){let{inputs:t,backend:a}=e,{real:n,imag:r}=t,s=a.makeTensorInfo(n.shape,"complex64"),i=a.texData.get(s.dataId),o=Za({inputs:{x:n},backend:a}),l=Za({inputs:{x:r},backend:a});return i.complexTensorInfos={real:o,imag:l},s}var vG={kernelName:Sd,backendName:"webgl",kernelFunc:ls},H6="return (a < 0.) ? b * a : a;",j6=` vec4 aLessThanZero = vec4(lessThan(a, vec4(0.))); return (aLessThanZero * (b * a)) + ((vec4(1.0) - aLessThanZero) * a); `;function wG(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{alpha:s}=n,i=a.makeTensorInfo([],"float32",v.createScalarValue(s,"float32")),o=W().getBool("WEBGL_PACK_BINARY_OPERATIONS")?new cp(j6,r.shape,i.shape):new Al(H6,r.shape,i.shape),l=a.runWebGLProgram(o,[r,i],"float32");return a.disposeIntermediateTensorInfo(i),l}var kG={kernelName:Si,backendName:"webgl",kernelFunc:wG},q6="return (a < 0.) ? b * a : a;",X6=` vec4 aLessThanZero = vec4(lessThan(a, vec4(0.))); return (aLessThanZero * (b * a)) + ((vec4(1.0) - aLessThanZero) * a); `;function IG(e){let{inputs:t,backend:a}=e,{x:n,alpha:r}=t,s=W().getBool("WEBGL_PACK_BINARY_OPERATIONS")?new cp(X6,n.shape,r.shape):new Al(q6,n.shape,r.shape);return a.runWebGLProgram(s,[n,r],"float32")}var SG={kernelName:Hi,backendName:"webgl",kernelFunc:IG},mu="if (isnan(x)) return x;";function Qe({opSnippet:e,packedOpSnippet:t,cpuKernelImpl:a,dtype:n}){return({inputs:r,backend:s})=>{let{x:i}=r,o=s,l=n||i.dtype;if(o.shouldExecuteOnCPU([i])&&a!=null){let c=o.texData.get(i.dataId),d=a(c.values,l);return o.makeTensorInfo(i.shape,l,d)}let u=W().getBool("WEBGL_PACK_UNARY_OPERATIONS")&&t!=null,p;return u?p=new Vr(i.shape,t):p=new qn(i.shape,e),o.runWebGLProgram(p,[i],l)}}function oa({opSnippet:e,packedOpSnippet:t,checkOutOfBounds:a=!1,supportsComplex:n=!1,cpuKernelImpl:r,dtype:s}){return({inputs:i,backend:o})=>{let{a:l,b:u}=i,p=o;if(n&&l.dtype==="complex64"){let f=p.texData.get(l.dataId),m=p.texData.get(u.dataId),[g,x]=[[f.complexTensorInfos.real,m.complexTensorInfos.real],[f.complexTensorInfos.imag,m.complexTensorInfos.imag]].map(y=>{let[b,w]=y,S={dataId:b.dataId,dtype:b.dtype,shape:l.shape},C={dataId:w.dataId,dtype:w.dtype,shape:u.shape},E=new Al(e,l.shape,u.shape);return p.runWebGLProgram(E,[S,C],ca(b.dtype,w.dtype))}),A=ls({inputs:{real:g,imag:x},backend:p});return p.disposeIntermediateTensorInfo(g),p.disposeIntermediateTensorInfo(x),A}let c=s||ca(l.dtype,u.dtype);if((l.dtype==="string"||u.dtype==="string"||p.shouldExecuteOnCPU([l,u]))&&r!=null){let f=p.texData.get(l.dataId).values,m=p.texData.get(u.dataId).values,g=l.dtype==="string"?T.fromUint8ToStringArray(f):f,x=l.dtype==="string"?T.fromUint8ToStringArray(m):m,[A,y]=r(l.shape,u.shape,g,x,c),b=p.makeTensorInfo(y,c),w=p.texData.get(b.dataId);return w.values=A,b}let d=W().getBool("WEBGL_PACK_BINARY_OPERATIONS")&&t!=null,h;return d?h=new cp(t,l.shape,u.shape,a):h=new Al(e,l.shape,u.shape),p.runWebGLProgram(h,[l,u],c)}}function gd(e,t=!1){if(e==="linear")return t?rG:QU;if(e==="relu")return t?iG:tG;if(e==="elu")return t?sG:eG;if(e==="relu6")return t?oG:aG;if(e==="prelu")return t?X6:q6;if(e==="leakyrelu")return t?j6:H6;if(e==="sigmoid")return t?lG:nG;throw new Error(`Activation ${e} has not been implemented for the WebGL backend.`)}var K6=class{constructor(e,t,a,n=!1,r=!1,s=!1,i=null,o=!1,l=!1){this.variableNames=["matrixA","matrixB"],this.packedInputs=!0,this.packedOutput=!0,this.outputShape=a,this.enableShapeUniforms=Na(this.outputShape.length);let u=n?e[1]:e[2],p=Math.ceil(u/2),c=n?"i * 2, rc.y":"rc.y, i * 2",d=r?"rc.z, i * 2":"i * 2, rc.z",h=n?["a.xxyy","a.zzww"]:["a.xxzz","a.yyww"],f=r?["b.xzxz","b.ywyw"]:["b.xyxy","b.zwzw"],m="",g="";i&&(o?m=`vec4 activation(vec4 a) { vec4 b = getPreluActivationWeightsAtOutCoords(); ${i} }`:l?m=`vec4 activation(vec4 a) { vec4 b = getLeakyreluAlphaAtOutCoords(); ${i} }`:m=`vec4 activation(vec4 x) { ${i} }`,g="result = activation(result);");let x=s?"result += getBiasAtOutCoords();":"";s&&this.variableNames.push("bias"),o&&this.variableNames.push("preluActivationWeights"),l&&this.variableNames.push("leakyreluAlpha");let A="rc.x",y="rc.x";e[0]`The new shape (${l}) has ${u} elements and the old shape (${r.shape}) has ${o} elements. The new shape and old shape must have the same number of elements.`);let p=i.texData.get(r.dataId);return p.isPacked&&!md(r.shape,l)&&!(p.texture!==null&&md(p.shape,l))?CG(r,l,i):(i.incRef(r.dataId),{dataId:r.dataId,shape:l,dtype:r.dtype})}var NG={kernelName:ql,backendName:"webgl",kernelFunc:ce},vx=class{constructor(e,t){this.variableNames=["x"];let{windowSize:a,batchSize:n,inSize:r,outSize:s}=e;this.outputShape=[n,s];let i=Math.floor(a/4)*4,o=a%4,l="sumValue += dot(values, ones);";if(t!=null){let p=1/t;l=`sumValue += dot(values * ${v.isInt(p)?p.toPrecision(2):p}, ones);`}let u="";r%a>0&&(u=` if (inIdx < 0 || inIdx >= ${r}) { return 0.0; } `),this.userCode=` const vec4 ones = vec4(1.0, 1.0, 1.0, 1.0); float getValue(int batch, int inIdx) { ${u} return getX(batch, inIdx); } void main() { ivec2 coords = getOutputCoords(); int batch = coords[0]; int outIdx = coords[1]; int inOffset = outIdx * ${a}; float sumValue = 0.0; for (int i = 0; i < ${i}; i += 4) { int inIdx = inOffset + i; vec4 values = vec4( getValue(batch, inIdx), getValue(batch, inIdx + 1), getValue(batch, inIdx + 2), getValue(batch, inIdx + 3) ); ${l} } int inIdx = inOffset + ${i}; if (${o===1}) { vec4 values = vec4(getValue(batch, inIdx), 0.0, 0.0, 0.0); ${l} } else if (${o===2}) { vec4 values = vec4( getValue(batch, inIdx), getValue(batch, inIdx + 1), 0.0, 0.0); ${l} } else if (${o===3}) { vec4 values = vec4( getValue(batch, inIdx), getValue(batch, inIdx + 1), getValue(batch, inIdx + 2), 0.0); ${l} } setOutput(sumValue); } `}},EG=class{constructor(e,t){this.variableNames=["x"];let{windowSize:a,batchSize:n,inSize:r,outSize:s}=e;this.outputShape=[n,s];let i="0.0",o="";t==="prod"?i="1.0":t==="min"?(i="1.0 / 1e-20",o="min"):t==="max"&&(i="-1.0 / 1e-20",o="max");let l=`${t}(${t}(${t}(minMaxValue[0], minMaxValue[1]), minMaxValue[2]), minMaxValue[3])`;t==="sum"?l="sumValue":t==="prod"?l="prodValue":t==="all"?l="allValue":t==="any"&&(l="anyValue");let u=Math.floor(a/4)*4,p=a%4,c=` if (${t==="sum"}) { sumValue += dot(values, ones); } else if (${t==="prod"}) { vec2 tmp = vec2(values[0], values[1]) * vec2(values[2], values[3]); prodValue *= tmp[0] * tmp[1]; } else { minMaxValue = ${o}(values, minMaxValue); if (${t==="min"} || ${t==="max"}) { minMaxValue = ${o}(values, minMaxValue); bvec4 isNaN = isnan(values); if (isNaN.r || isNaN.g || isNaN.b || isNaN.a) { minMaxValue = vec4(NAN); } } } `,d="vec4";t==="all"?(i="1.0",c=` bool reducedAllValue = all(values); float floatedReducedAllValue = float(reducedAllValue); allValue = float(allValue >= 1.0 && floatedReducedAllValue >= 1.0); `,d="bvec4"):t==="any"&&(i="0.0",c=` bool reducedAnyValue = any(values); float floatedReducedAnyValue = float(reducedAnyValue); anyValue = float(anyValue >= 1.0 || floatedReducedAnyValue >= 1.0); `,d="bvec4");let h="";r%a>0&&(h=` if (inIdx < 0 || inIdx >= ${r}) { return initializationValue; } `),this.userCode=` const float initializationValue = ${i}; const vec4 ones = vec4(1.0, 1.0, 1.0, 1.0); float getValue(int batch, int inIdx) { ${h} return getX(batch, inIdx); } void main() { ivec2 coords = getOutputCoords(); int batch = coords[0]; int outIdx = coords[1]; int inOffset = outIdx * ${a}; vec4 minMaxValue = vec4(${i}); float prodValue = 1.0; float sumValue = 0.0; float allValue = 1.0; float anyValue = 0.0; for (int i = 0; i < ${u}; i += 4) { int inIdx = inOffset + i; ${d} values = ${d}( getValue(batch, inIdx), getValue(batch, inIdx + 1), getValue(batch, inIdx + 2), getValue(batch, inIdx + 3) ); ${c} } int inIdx = inOffset + ${u}; if (${p===1}) { ${d} values = ${d}( getValue(batch, inIdx), initializationValue, initializationValue, initializationValue ); ${c} } else if (${p===2}) { ${d} values = ${d}( getValue(batch, inIdx), getValue(batch, inIdx + 1), initializationValue, initializationValue ); ${c} } else if (${p===3}) { ${d} values = ${d}( getValue(batch, inIdx), getValue(batch, inIdx + 1), getValue(batch, inIdx + 2), initializationValue ); ${c} } setOutput(${l}); } `}};function RG(e){let t=[];for(;t.length===0||t[t.length-1].outSize!==1;){let a=t.length?t[t.length-1].outSize:e[1],n=T.computeOptimalWindowSize(a);t.push({inSize:a,windowSize:n,outSize:Math.ceil(a/n)})}return t}function bo(e,t,a,n){let r=RG(e.shape),s=e;for(let i=0;i6)throw Error(`Transpose for rank ${t} is not yet supported`);let a=["resRC.x","resRC.y","resRC.z","resRC.w","resRC.u","resRC.v"],n=new Array(t);for(let r=0;r6)throw Error(`Packed transpose for rank ${this.rank} is not yet supported.`);let n=gt(this.rank),r=V6("rc",this.rank),s=new Array(this.rank);for(let u=0;u`Error in matMul: inner shapes (${c}) and (${d}) of Tensors with shapes ${e.shape} and ${t.shape} and transposeA=${a} and transposeB=${n} must match.`);let b=a?[x,c,h]:[x,h,c],w=n?[A,f,d]:[A,d,f],S=ce({inputs:{x:e},backend:r,attrs:{shape:b}}),C=ce({inputs:{x:t},backend:r,attrs:{shape:w}}),E=[S,C],_=Math.max(x,A),$=a?S.shape[1]:S.shape[2],M=s!=null,I=i!=null,N=l==="leakyrelu",O=l!=null?gd(l,!0):null,L=M||I||N||O!=null,B;if((h===1||f===1)&&$>Z6&&L===!1){let j=S,U=C;a&&(j=Ia({inputs:{x:S},backend:r,attrs:{perm:[0,2,1]}}),E.push(j)),n&&(U=Ia({inputs:{x:C},backend:r,attrs:{perm:[0,2,1]}}),E.push(U));let H=f!==1,V=f===1,Q=j;H&&(Q=ce({inputs:{x:j},backend:r,attrs:{shape:[_,$,1]}}),E.push(Q));let Z=f===1?2:1,re=U;V&&(re=ce({inputs:{x:U},backend:r,attrs:{shape:[_,1,$]}}),E.push(re));let ee=M3({inputs:{a:Q,b:re},backend:r});B=zh({inputs:{x:ee},backend:r,attrs:{axis:Z,keepDims:!0}}),E.push(ee)}else{let j=ca(e.dtype,t.dtype),U=new K6(b,w,[_,h,f],a,n,M,O,I,N),H=[S,C];if(s!=null&&H.push(s),I&&H.push(i),N){let V=r.makeTensorInfo([],"float32",v.createScalarValue(o,"float32"));H.push(V),E.push(V)}B=r.runWebGLProgram(U,H,j)}let G=ce({inputs:{x:B},backend:r,attrs:{shape:y}});E.push(B);for(let j of E)r.disposeIntermediateTensorInfo(j);return G}function DG(e){let{inputs:t,backend:a,attrs:n}=e,{a:r,b:s,bias:i,preluActivationWeights:o}=t,{transposeA:l,transposeB:u,activation:p,leakyreluAlpha:c}=n;return Dc({a:r,b:s,transposeA:l,transposeB:u,backend:a,bias:i,preluActivationWeights:o,leakyreluAlpha:c,activation:p})}var zG={kernelName:jr,backendName:"webgl",kernelFunc:DG},wx="return abs(x);";function LG(e){let{inputs:t,backend:a}=e,{x:n}=t;if(a.shouldExecuteOnCPU([n])&&n.dtype!=="complex64"){let s=a.texData.get(n.dataId),i=B6(s.values);return a.makeTensorInfo(n.shape,n.dtype,i)}let r;return W().getBool("WEBGL_PACK_UNARY_OPERATIONS")?r=new Vr(n.shape,wx):r=new qn(n.shape,wx),a.runWebGLProgram(r,[n],n.dtype)}var BG={kernelName:wl,backendName:"webgl",kernelFunc:LG},WG=Cn+` if (abs(x) > 1.) { return NAN; } return acos(x); `,VG=Qe({opSnippet:WG}),UG={kernelName:kl,backendName:"webgl",kernelFunc:VG},GG=Cn+` if (x < 1.0) return NAN; return log(x + sqrt(x * x - 1.0));`,HG=Qe({opSnippet:GG}),jG={kernelName:Il,backendName:"webgl",kernelFunc:HG},kx="return a + b;",qG=oa({opSnippet:kx,packedOpSnippet:kx,supportsComplex:!0,cpuKernelImpl:nU}),XG={kernelName:ts,backendName:"webgl",kernelFunc:qG},KG=class{constructor(e,t){this.outputShape=[],this.outputShape=e,this.variableNames=t.map((r,s)=>`T${s}`);let a=[];this.variableNames.forEach(r=>{a.push(`float v${r} = get${r}AtOutCoords();`)});let n=this.variableNames.map(r=>`v${r}`).join(" + ");this.userCode=` void main() { ${a.join(` `)} float result = ${n}; setOutput(result); } `}},ZG=class{constructor(e,t){this.outputShape=[],this.packedInputs=!0,this.packedOutput=!0,this.outputShape=e,this.variableNames=t.map((r,s)=>`T${s}`);let a=[];this.variableNames.forEach(r=>{a.push(`vec4 v${r} = get${r}AtOutCoords();`)});let n=this.variableNames.map(r=>`v${r}`).join(" + ");this.userCode=` void main() { ${a.join(` `)} vec4 result = ${n}; setOutput(result); } `}};function bc(e){let{inputs:t,backend:a}=e,n=t;if(n.length===1)return Za({inputs:{x:n[0]},backend:a});if(n.length>W().get("WEBGL_MAX_TEXTURES_IN_SHADER")){let o=Math.floor(n.length/2),l=bc({inputs:n.slice(0,o),backend:a}),u=bc({inputs:n.slice(o),backend:a});return bc({inputs:[l,u],backend:a})}let r=n.map(o=>o.dtype).reduce((o,l)=>ca(o,l)),s=n.map(o=>o.shape),i=W().getBool("WEBGL_PACK")?new ZG(n[0].shape,s):new KG(n[0].shape,s);return a.runWebGLProgram(i,n,r)}var YG={kernelName:Ks,backendName:"webgl",kernelFunc:bc};function JG(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,keepDims:i}=n,o=r.shape.length,l=v.parseAxisParam(s,r.shape),u=l,p=T.getAxesPermutation(u,o),c=r;p!=null&&(c=Ia({inputs:{x:r},backend:a,attrs:{perm:p}}),u=T.getInnerMostAxes(u.length,o)),T.assertAxesAreInnerMostDims("all",u,o);let[d,h]=T.computeOutAndReduceShapes(c.shape,u),f=v.sizeFromShape(h),m=ce({inputs:{x:c},backend:a,attrs:{shape:[-1,f]}}),g=bo(m,m.dtype,"all",a),x;if(i){let A=T.expandShapeToKeepDim(d,l);x=ce({inputs:{x:g},backend:a,attrs:{shape:A}})}else x=ce({inputs:{x:g},backend:a,attrs:{shape:d}});return a.disposeIntermediateTensorInfo(m),a.disposeIntermediateTensorInfo(g),p!=null&&a.disposeIntermediateTensorInfo(c),x}var QG={kernelName:Zs,backendName:"webgl",kernelFunc:JG};function eH(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,keepDims:i}=n,o=r.shape.length,l=v.parseAxisParam(s,r.shape),u=l,p=T.getAxesPermutation(u,o),c=r;p!=null&&(c=Ia({inputs:{x:r},backend:a,attrs:{perm:p}}),u=T.getInnerMostAxes(u.length,o)),T.assertAxesAreInnerMostDims("any",u,o);let[d,h]=T.computeOutAndReduceShapes(c.shape,u),f=v.sizeFromShape(h),m=ce({inputs:{x:c},backend:a,attrs:{shape:[-1,f]}}),g=bo(m,m.dtype,"any",a),x;if(i){let A=T.expandShapeToKeepDim(d,l);x=ce({inputs:{x:g},backend:a,attrs:{shape:A}})}else x=ce({inputs:{x:g},backend:a,attrs:{shape:d}});return a.disposeIntermediateTensorInfo(m),a.disposeIntermediateTensorInfo(g),p!=null&&a.disposeIntermediateTensorInfo(c),x}var tH={kernelName:Ys,backendName:"webgl",kernelFunc:eH},aH=class{constructor(e,t,a){this.variableNames=["A"];let{windowSize:n,batchSize:r,outSize:s}=e;a||this.variableNames.push("bestIndicesA"),this.outputShape=[r,s];let i=t==="max"?">":"<",o=a?"inOffset + i;":"round(getBestIndicesA(batch, inOffset + i));";this.userCode=` void main() { ivec2 coords = getOutputCoords(); int batch = coords[0]; int outIdx = coords[1]; int inOffset = outIdx * ${n}; int bestIndex = inOffset; float bestValue = getA(batch, bestIndex); for (int i = 0; i < ${n}; i++) { int inIdx = ${o}; float candidate = getA(batch, inIdx); if (candidate ${i} bestValue) { bestValue = candidate; bestIndex = inIdx; } } setOutput(float(bestIndex)); } `}},nH=class{constructor(e,t,a,n){this.variableNames=["A"],this.packedInputs=!0,this.packedOutput=!0,v.assert(e.length>2,()=>`Packed arg${a.charAt(0).toUpperCase()+a.slice(1)} supports only inputs with rank above 2.`);let r=e[e.length-1],s=Math.ceil(r/t);this.outputShape=e.slice(0,-1),s>1&&this.outputShape.push(s),n||this.variableNames.push("bestIndicesA");let i=this.outputShape,o=i.length,l=gt(o),u=va("coords",o),p,c;if(s===1){c=o+1;let C=gt(c);p=` ${C} sourceLocR = ${C}(${u.join()}, 0); ++${u[o-1]}; ${C} sourceLocG = ${C}(${u.join()}, 0); ++${u[o-2]}; ${C} sourceLocA = ${C}(${u.join()}, 0); --${u[o-1]}; ${C} sourceLocB = ${C}(${u.join()}, 0); --${u[o-2]};`}else c=o,p=` ${l} sourceLocR = coords; ++${u[o-1]}; ${l} sourceLocG = coords; ++${u[o-2]}; ${l} sourceLocA = coords; --${u[o-1]}; ${l} sourceLocB = coords; --${u[o-2]};`;let d=["x","y","z","w","u","v"].slice(0,c),h="."+d[c-1],f=d.map(C=>"int "+C),m=va("sourceLocR",c-1).concat("inIdx.r"),g=va("sourceLocG",c-1).concat("inIdx.g"),x=va("sourceLocB",c-1).concat("inIdx.b"),A=va("sourceLocA",c-1).concat("inIdx.a"),y=a==="max"?"greaterThan":"lessThan",b=n?"":` inIdx = round(vec4(getBestIndicesAChannel(${m.join()}), getBestIndicesAChannel(${g.join()}), getBestIndicesAChannel(${x.join()}), getBestIndicesAChannel(${A.join()})));`,w=`vec4( getAChannel(${m.join()}), hasNextCol ? getAChannel(${g.join()}) : 0., hasNextRow ? getAChannel(${x.join()}) : 0., hasNextRow && hasNextCol ? getAChannel(${A.join()}) : 0.)`,S=n?"":` float getBestIndicesAChannel(${f.join()}) { return getChannel(getBestIndicesA(${d.join()}), vec2(${d.slice(-2).join()})); }`;this.userCode=` float getAChannel(${f.join()}) { return getChannel(getA(${d.join()}), vec2(${d.slice(-2).join()})); } ${S} void main() { ${l} coords = getOutputCoords(); bool hasNextCol = ${u[o-1]} < ${i[o-1]-1}; bool hasNextRow = ${u[o-2]} < ${i[o-2]-1}; ${p} ivec4 srcIdx = ivec4(sourceLocR${h}, sourceLocG${h}, sourceLocB${h}, sourceLocA${h}) * ${t}; ivec4 inIdx = srcIdx; vec4 bestIndex = vec4(inIdx); vec4 bestValue = ${w}; for (int i = 0; i < ${t}; i++) { inIdx = srcIdx; ${b} vec4 candidate = ${w}; bvec4 nan = isnan(candidate); bvec4 replace = bvec4( vec4(${y}(candidate, bestValue)) * (vec4(1.0) - vec4(nan))); bestValue = vec4(replace.x ? candidate.x : bestValue.x, replace.y ? candidate.y : bestValue.y, replace.z ? candidate.z : bestValue.z, replace.w ? candidate.w : bestValue.w); bestIndex = mix(bestIndex, vec4(inIdx), vec4(replace)); srcIdx++; } setOutput(bestIndex); } `}};function Y6(e,t,a,n=null){let r=t.shape[0],s=t.shape[1];n!=null&&(r=n.shape[0],s=n.shape[1]);let i=T.computeOptimalWindowSize(s),o={windowSize:i,inSize:s,batchSize:r,outSize:Math.ceil(s/i)},l=new aH(o,a,n==null),u=[t];n!=null&&u.push(n);let p=e.runWebGLProgram(l,u,"int32");if(p.shape[1]===1)return p;let c=Y6(e,t,a,p);return e.disposeIntermediateTensorInfo(p),c}function J6(e,t,a,n=null){let r=n!=null?n.shape:t.shape,s=r[r.length-1],i=T.computeOptimalWindowSize(s),o=new nH(r,i,a,n==null),l=n==null?[t]:[t,n],u=e.runWebGLProgram(o,l,"int32");if(u.shape.length===t.shape.length){let p=J6(e,t,a,u);return e.disposeIntermediateTensorInfo(u),p}return u}function Q6(e,t,a,n){let r=[a];if(T.assertAxesAreInnerMostDims("arg"+n.charAt(0).toUpperCase()+n.slice(1),r,t.shape.length),!W().getBool("WEBGL_PACK_REDUCE")||t.shape.length<=2){let s=[],i=e.texData.get(t.dataId),o=i!==null&&i.isPacked,l=t;o&&(l=e.unpackTensor(t),s.push(l));let[u,p]=T.computeOutAndReduceShapes(l.shape,r),c=v.sizeFromShape(p),d=ce({inputs:{x:l},backend:e,attrs:{shape:[-1,c]}});s.push(d);let h=Y6(e,d,n);s.push(h);let f=ce({inputs:{x:h},backend:e,attrs:{shape:u}});return s.forEach(m=>e.disposeIntermediateTensorInfo(m)),f}return J6(e,t,n)}function rH(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s}=n,i=v.parseAxisParam(s,r.shape),o=T.getAxesPermutation(i,r.shape.length),l=r,u=[];o!=null&&(l=Ia({inputs:{x:r},backend:a,attrs:{perm:o}}),u.push(l),i=T.getInnerMostAxes(i.length,l.shape.length)),T.assertAxesAreInnerMostDims("argMax",[i[0]],l.shape.length);let p=Q6(a,l,i[0],"max");return u.forEach(c=>a.disposeIntermediateTensorInfo(c)),p}var sH={kernelName:Js,backendName:"webgl",kernelFunc:rH};function iH(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s}=n,i=v.parseAxisParam(s,r.shape),o=T.getAxesPermutation(i,r.shape.length),l=r,u=[];o!=null&&(l=Ia({inputs:{x:r},backend:a,attrs:{perm:o}}),u.push(l),i=T.getInnerMostAxes(i.length,l.shape.length)),T.assertAxesAreInnerMostDims("argMin",[i[0]],l.shape.length);let p=Q6(a,l,i[0],"min");return u.forEach(c=>a.disposeIntermediateTensorInfo(c)),p}var oH={kernelName:kd,backendName:"webgl",kernelFunc:iH},lH=Cn+` if (abs(x) > 1.) { return NAN; } return asin(x); `,uH=Qe({opSnippet:lH}),dH={kernelName:Sl,backendName:"webgl",kernelFunc:uH},pH=Cn+"return log(x + sqrt(x * x + 1.0));",cH=Qe({opSnippet:pH}),hH={kernelName:Tl,backendName:"webgl",kernelFunc:cH},fH=Cn+` return atan(x); `,mH=Qe({opSnippet:fH}),gH={kernelName:Cl,backendName:"webgl",kernelFunc:mH},xH=R3+` return atan(a, b); `,AH=` vec4 result = atan(a, b); bvec4 isNaNA = isnan(a); bvec4 isNaNB = isnan(b); bvec4 isNaN = bvec4(isNaNA.x || isNaNB.x, isNaNA.y || isNaNB.y, isNaNA.z || isNaNB.z, isNaNA.w || isNaNB.w); `+pp+` return result; `,yH=oa({opSnippet:xH,packedOpSnippet:AH}),bH={kernelName:El,backendName:"webgl",kernelFunc:yH},vH=Cn+` if ((x < -1.0) || (x > 1.0)) return NAN; return (log(1.0 + x) - log(1.0 - x)) / 2.0;`,wH=Qe({opSnippet:vH}),kH={kernelName:Nl,backendName:"webgl",kernelFunc:wH},xd=class{constructor(e,t,a,n=!1,r=!1){if(this.variableNames=["x"],t==="avg"&&a)throw new Error("Cannot compute positions for average pool.");let s=e.filterWidth,i=e.strideHeight,o=e.strideWidth,l=e.dilationHeight,u=e.dilationWidth,p=e.effectiveFilterHeight,c=e.effectiveFilterWidth,d=e.padInfo.top,h=e.padInfo.left;this.outputShape=e.outShape;let f=t==="avg",m=`((batch * ${e.inHeight} + xR) * ${e.inWidth} + xC) * ${e.inChannels} + d`,g=`(xR * ${e.inWidth} + xC) * ${e.inChannels} + d`,x="0.0";if(f||(x="-1.0 / 1e-20"),a){let C=">=";this.userCode=` const ivec2 strides = ivec2(${i}, ${o}); const ivec2 pads = ivec2(${d}, ${h}); void main() { ivec4 coords = getOutputCoords(); int batch = coords[0]; int d = coords[3]; ivec2 xRCCorner = coords.yz * strides - pads; int xRCorner = xRCCorner.x; int xCCorner = xRCCorner.y; // max/min x(?, ?, d) to get y(yR, yC, d). // ? = to be determined float minMaxValue = 0.0; float minMaxValueFound = 0.0; int minMaxPosition = 0; float avgValue = 0.0; for (int wR = 0; wR < ${p}; wR += ${l}) { int xR = xRCorner + wR; if (xR < 0 || xR >= ${e.inHeight}) { continue; } for (int wC = 0; wC < ${c}; wC += ${u}) { int xC = xCCorner + wC; if (xC < 0 || xC >= ${e.inWidth}) { continue; } float value = getX(batch, xR, xC, d); // If a min / max value has already been found, use it. If not, // use the current value. float currMinMaxValue = mix( value, minMaxValue, minMaxValueFound); if (value ${C} currMinMaxValue) { minMaxValue = value; minMaxValueFound = 1.0; minMaxPosition = ${n?r?m:g:`wR * ${c} + wC`}; } } } setOutput(float(minMaxPosition)); } `;return}let A="max",y=`${t}(${t}(${t}(minMaxValue[0], minMaxValue[1]), minMaxValue[2]), minMaxValue[3])`;t==="avg"&&(y="avgValue / count");let b=Math.floor(s/4)*4,w=s%4,S=` if (${f}) { avgValue += dot(values, ones); } else { minMaxValue = ${A}(values, minMaxValue); } `;this.userCode=` const ivec2 strides = ivec2(${i}, ${o}); const ivec2 pads = ivec2(${d}, ${h}); const float initializationValue = ${x}; const vec4 ones = vec4(1.0, 1.0, 1.0, 1.0); float count = 0.0; float getValue(int batch, int xR, int xC, int d) { if (xC < 0 || xC >= ${e.inWidth}) { return initializationValue; } count += 1.0; return getX(batch, xR, xC, d); } void main() { ivec4 coords = getOutputCoords(); int batch = coords[0]; int d = coords[3]; ivec2 xRCCorner = coords.yz * strides - pads; int xRCorner = xRCCorner.x; int xCCorner = xRCCorner.y; // max/min x(?, ?, d) to get y(yR, yC, d). // ? = to be determined vec4 minMaxValue = vec4(${x}); float avgValue = 0.0; count = 0.0; for (int wR = 0; wR < ${p}; wR += ${l}) { int xR = xRCorner + wR; if (xR < 0 || xR >= ${e.inHeight}) { continue; } for (int wC = 0; wC < ${b}; wC += 4) { int xC = xCCorner + wC * ${u}; vec4 values = vec4( getValue(batch, xR, xC, d), getValue(batch, xR, xC + ${u}, d), getValue(batch, xR, xC + 2 * ${u}, d), getValue(batch, xR, xC + 3 * ${u}, d) ); ${S} } int xC = xCCorner + ${b}; if (${w===1}) { vec4 values = vec4( getValue(batch, xR, xC, d), initializationValue, initializationValue, initializationValue ); ${S} } else if (${w===2}) { vec4 values = vec4( getValue(batch, xR, xC, d), getValue(batch, xR, xC + ${u}, d), initializationValue, initializationValue ); ${S} } else if (${w===3}) { vec4 values = vec4( getValue(batch, xR, xC, d), getValue(batch, xR, xC + ${u}, d), getValue(batch, xR, xC + 2 * ${u}, d), initializationValue ); ${S} } } setOutput(${y}); } `}},$3=class{constructor(e,t,a,n=!1,r=!1){if(this.variableNames=["x"],t==="avg"&&a)throw new Error("Cannot compute positions for average pool.");let s=e.filterWidth,i=e.strideDepth,o=e.strideHeight,l=e.strideWidth,u=e.dilationDepth,p=e.dilationHeight,c=e.dilationWidth,d=e.effectiveFilterDepth,h=e.effectiveFilterHeight,f=e.effectiveFilterWidth,m=e.padInfo.front,g=e.padInfo.top,x=e.padInfo.left;this.outputShape=e.outShape;let A=t==="avg",y="0.0";if(A||(y="-1.0 / 1e-20"),a){let _=">=";this.userCode=` const ivec3 strides = ivec3(${i}, ${o}, ${l}); const ivec3 pads = ivec3(${m}, ${g}, ${x}); void main() { ivec5 coords = getOutputCoords(); int batch = coords.x; int ch = coords.u; ivec3 xCorner = ivec3(coords.y, coords.z, coords.w) * strides - pads; int xDCorner = xCorner.x; int xRCorner = xCorner.y; int xCCorner = xCorner.z; // max/min x(?, ?, ?, ch) to get y(yD, yR, yC, ch). // ? = to be determined float minMaxValue = 0.0; float minMaxValueFound = 0.0; int minMaxPosition = 0; for (int wD = 0; wD < ${d}; wD += ${u}) { int xD = xDCorner + wD; if (xD < 0 || xD >= ${e.inDepth}) { continue; } for (int wR = 0; wR < ${h}; wR += ${p}) { int xR = xRCorner + wR; if (xR < 0 || xR >= ${e.inHeight}) { continue; } for (int wC = 0; wC < ${f}; wC += ${c}) { int xC = xCCorner + wC; if (xC < 0 || xC >= ${e.inWidth}) { continue; } float value = getX(batch, xD, xR, xC, ch); // If a min / max value has already been found, use it. If not, // use the current value. float currMinMaxValue = mix( value, minMaxValue, minMaxValueFound); if (value ${_} currMinMaxValue) { minMaxValue = value; minMaxValueFound = 1.0; minMaxPosition = ${n?r?`(((batch * ${e.inDepth} + xD) * ${e.inHeight} + xR) * ${e.inWidth} + xC) * ${e.inChannels} + ch`:`((xD * ${e.inHeight} + xR) * ${e.inWidth} + xC) * ${e.inChannels} + ch`:`wD * ${h} * ${f} + wR * ${f} + wC`}; } } } } setOutput(float(minMaxPosition)); } `;return}let b="max",w=`${t}(${t}(${t}(minMaxValue[0], minMaxValue[1]), minMaxValue[2]), minMaxValue[3])`;t==="avg"&&(w="avgValue / count");let S=Math.floor(s/4)*4,C=s%4,E=` if (${A}) { avgValue += dot(values, ones); } else { minMaxValue = ${b}(values, minMaxValue); } `;this.userCode=` const ivec3 strides = ivec3(${i}, ${o}, ${l}); const ivec3 pads = ivec3(${m}, ${g}, ${x}); const float initializationValue = ${y}; const vec4 ones = vec4(1.0, 1.0, 1.0, 1.0); float count = 0.0; float getValue(int batch, int xD, int xR, int xC, int ch) { if (xC < 0 || xC >= ${e.inWidth}) { return initializationValue; } count += 1.0; return getX(batch, xD, xR, xC, ch); } void main() { ivec5 coords = getOutputCoords(); int batch = coords.x; int ch = coords.u; ivec3 xCorner = ivec3(coords.y, coords.z, coords.w) * strides - pads; int xDCorner = xCorner.x; int xRCorner = xCorner.y; int xCCorner = xCorner.z; // max/min x(?, ?, ?, d) to get y(yD, yR, yC, ch). // ? = to be determined vec4 minMaxValue = vec4(${y}); float avgValue = 0.0; count = 0.0; for (int wD = 0; wD < ${d}; wD += ${u}) { int xD = xDCorner + wD; if (xD < 0 || xD >= ${e.inDepth}) { continue; } for (int wR = 0; wR < ${h}; wR += ${p}) { int xR = xRCorner + wR; if (xR < 0 || xR >= ${e.inHeight}) { continue; } for (int wC = 0; wC < ${S}; wC += 4) { int xC = xCCorner + wC * ${c}; vec4 values = vec4( getValue(batch, xD, xR, xC, ch), getValue(batch, xD, xR, xC + ${c}, ch), getValue(batch, xD, xR, xC + 2 * ${c}, ch), getValue(batch, xD, xR, xC + 3 * ${c}, ch) ); ${E} } int xC = xCCorner + ${S}; if (${C===1}) { vec4 values = vec4( getValue(batch, xD, xR, xC, ch), initializationValue, initializationValue, initializationValue ); ${E} } else if (${C===2}) { vec4 values = vec4( getValue(batch, xD, xR, xC, ch), getValue(batch, xD, xR, xC + ${c}, ch), initializationValue, initializationValue ); ${E} } else if (${C===3}) { vec4 values = vec4( getValue(batch, xD, xR, xC, ch), getValue(batch, xD, xR, xC + ${c}, ch), getValue(batch, xD, xR, xC + 2 * ${c}, ch), initializationValue ); ${E} } } setOutput(${w}); } } `}};function IH(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t;uu(r,"avgPool");let{filterSize:s,strides:i,pad:o,dimRoundingMode:l}=n,u=1;v.assert(T.eitherStridesOrDilationsAreOne(i,u),()=>`Error in avgPool: Either strides or dilations must be 1. Got strides ${i} and dilations '${u}'`);let p=T.computePool2DInfo(r.shape,s,i,u,o,l);if(p.filterWidth===1&&p.filterHeight===1&&v.arraysEqual(p.inShape,p.outShape))return Za({inputs:{x:r},backend:a});let c=new xd(p,"avg",!1);return a.runWebGLProgram(c,[r],"float32")}var SH={kernelName:Qs,backendName:"webgl",kernelFunc:IH};function TH(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{filterSize:s,strides:i,pad:o,dimRoundingMode:l,dataFormat:u}=n,p=[1,1,1],c=T.computePool3DInfo(r.shape,s,i,p,o,l,u),d=new $3(c,"avg",!1);return a.runWebGLProgram(d,[r],"float32")}var CH={kernelName:Hc,backendName:"webgl",kernelFunc:TH},NH=class{constructor(e){this.variableNames=["dy"],this.outputShape=e.inShape;let t=e.filterHeight,a=e.filterWidth,n=e.strideHeight,r=e.strideWidth,s=e.dilationHeight,i=e.dilationWidth,o=e.effectiveFilterHeight,l=e.effectiveFilterWidth,u=o-1-e.padInfo.top,p=l-1-e.padInfo.left,c=1/(t*a);this.userCode=` const ivec2 pads = ivec2(${u}, ${p}); const float avgMultiplier = float(${c}); void main() { ivec4 coords = getOutputCoords(); int b = coords[0]; int d = coords[3]; ivec2 dyRCCorner = coords.yz - pads; int dyRCorner = dyRCCorner.x; int dyCCorner = dyRCCorner.y; // Convolve dy(?, ?, d) with pos mask(:, :, d) to get dx(xR, xC, d). // ? = to be determined. : = across all values in that axis. float dotProd = 0.0; for (int wR = 0; wR < ${o}; wR += ${s}) { float dyR = float(dyRCorner + wR) / ${n}.0; if (dyR < 0.0 || dyR >= ${e.outHeight}.0 || fract(dyR) > 0.0) { continue; } int idyR = int(dyR); for (int wC = 0; wC < ${l}; wC+= ${i}) { float dyC = float(dyCCorner + wC) / ${r}.0; if (dyC < 0.0 || dyC >= ${e.outWidth}.0 || fract(dyC) > 0.0) { continue; } int idyC = int(dyC); float dyValue = getDy(b, idyR, idyC, d); dotProd += dyValue * avgMultiplier; } } setOutput(dotProd); } `}},EH=class{constructor(e){this.variableNames=["dy"],this.outputShape=e.inShape;let t=e.filterDepth,a=e.filterHeight,n=e.filterWidth,r=e.strideDepth,s=e.strideHeight,i=e.strideWidth,o=e.dilationDepth,l=e.dilationHeight,u=e.dilationWidth,p=e.effectiveFilterDepth,c=e.effectiveFilterHeight,d=e.effectiveFilterWidth,h=p-1-e.padInfo.front,f=c-1-e.padInfo.top,m=d-1-e.padInfo.left,g=1/(t*a*n);this.userCode=` const ivec3 pads = ivec3(${h}, ${f}, ${m}); const float avgMultiplier = float(${g}); void main() { ivec5 coords = getOutputCoords(); int batch = coords.x; int ch = coords.u; ivec3 dyCorner = ivec3(coords.y, coords.z, coords.w) - pads; int dyDCorner = dyCorner.x; int dyRCorner = dyCorner.y; int dyCCorner = dyCorner.z; // Convolve dy(?, ?, ?, d) with pos mask(:, :, :, ch) to get // dx(xD, xR, xC, ch). // ? = to be determined. : = across all values in that axis. float dotProd = 0.0; for (int wD = 0; wD < ${p}; wD += ${o}) { float dyD = float(dyDCorner + wD) / ${r}.0; if (dyD < 0.0 || dyD >= ${e.outDepth}.0 || fract(dyD) > 0.0) { continue; } int idyD = int(dyD); for (int wR = 0; wR < ${c}; wR += ${l}) { float dyR = float(dyRCorner + wR) / ${s}.0; if (dyR < 0.0 || dyR >= ${e.outHeight}.0 || fract(dyR) > 0.0) { continue; } int idyR = int(dyR); for (int wC = 0; wC < ${d}; wC += ${u}) { float dyC = float(dyCCorner + wC) / ${i}.0; if (dyC < 0.0 || dyC >= ${e.outWidth}.0 || fract(dyC) > 0.0) { continue; } int idyC = int(dyC); float dyValue = getDy(batch, idyD, idyR, idyC, ch); dotProd += dyValue * avgMultiplier; } } } setOutput(dotProd); } `}};function RH(e){let{inputs:t,backend:a,attrs:n}=e,{dy:r,input:s}=t,i=s,{filterSize:o,strides:l,pad:u,dimRoundingMode:p}=n,c=[1,1,1],d=T.computePool3DInfo(i.shape,o,l,c,u,p),h=new EH(d);return a.runWebGLProgram(h,[r],i.dtype)}var MH={kernelName:G1,backendName:"webgl",kernelFunc:RH};function $H(e){let{inputs:t,backend:a,attrs:n}=e,{dy:r,input:s}=t,i=s;uu([r,s],"avgPoolGrad");let{filterSize:o,strides:l,pad:u}=n,p=T.computePool2DInfo(i.shape,o,l,1,u),c=new NH(p);return a.runWebGLProgram(c,[r],i.dtype)}var _H={kernelName:U1,backendName:"webgl",kernelFunc:$H};function PH(e){let{inputs:t,backend:a,attrs:n}=e,{a:r,b:s}=t,{transposeA:i,transposeB:o}=n;return Dc({a:r,b:s,transposeA:i,transposeB:o,backend:a})}var FH={kernelName:ei,backendName:"webgl",kernelFunc:PH},OH=class{constructor(e,t,a,n,r,s){this.outputShape=[],this.variableNames=["x","mean","variance"],T.assertAndGetBroadcastShape(e,t),T.assertAndGetBroadcastShape(e,a);let i="0.0";n!=null&&(T.assertAndGetBroadcastShape(e,n),this.variableNames.push("offset"),i="getOffsetAtOutCoords()");let o="1.0";r!=null&&(T.assertAndGetBroadcastShape(e,r),this.variableNames.push("scale"),o="getScaleAtOutCoords()"),this.outputShape=e,this.userCode=` void main() { float x = getXAtOutCoords(); float mean = getMeanAtOutCoords(); float variance = getVarianceAtOutCoords(); float offset = ${i}; float scale = ${o}; float inv = scale * inversesqrt(variance + float(${s})); setOutput(dot(vec3(x, -mean, offset), vec3(inv, inv, 1))); } `}},DH=class{constructor(e,t,a,n,r,s){this.packedInputs=!0,this.packedOutput=!0,this.variableNames=["x","mean","variance"],T.assertAndGetBroadcastShape(e,t),T.assertAndGetBroadcastShape(e,a);let i="vec4(0.0)";n!=null&&(T.assertAndGetBroadcastShape(e,n),this.variableNames.push("offset"),i="getOffsetAtOutCoords()");let o="vec4(1.0)";r!=null&&(T.assertAndGetBroadcastShape(e,r),this.variableNames.push("scale"),o="getScaleAtOutCoords()"),this.outputShape=e,this.userCode=` void main() { vec4 offset = ${i}; vec4 scale = ${o}; vec4 x = getXAtOutCoords(); vec4 mean = getMeanAtOutCoords(); vec4 variance = getVarianceAtOutCoords(); vec4 inv = scale * inversesqrt(variance + vec4(${s})); setOutput((x - mean) * inv + offset); } `}},zH=({inputs:e,backend:t,attrs:a})=>{let{x:n,mean:r,variance:s,offset:i,scale:o}=e;v.assert(r.shape.length===s.shape.length,()=>"Batch normalization gradient requires mean and variance to have equal ranks."),v.assert(i==null||r.shape.length===i.shape.length,()=>"Batch normalization gradient requires mean and offset to have equal ranks."),v.assert(o==null||r.shape.length===o.shape.length,()=>"Batch normalization gradient requires mean and scale to have equal ranks.");let{varianceEpsilon:l}=a;l==null&&(l=.001);let u=[n,r,s],p=null;i!=null&&(p=i.shape,u.push(i));let c=null;o!=null&&(c=o.shape,u.push(o));let d=W().getBool("WEBGL_PACK_NORMALIZATION")?new DH(n.shape,r.shape,s.shape,p,c,l):new OH(n.shape,r.shape,s.shape,p,c,l);return t.runWebGLProgram(d,u,u[0].dtype)},LH={kernelName:yi,backendName:"webgl",kernelFunc:zH},BH=class{constructor(e){this.variableNames=["source"],this.outputShape=e,this.rank=e.length;let t=gt(this.rank);this.customUniforms=[{name:"start",arrayIndex:this.rank,type:"int"}];let a=WH(this.rank),n,r=e.map((s,i)=>`sourceLoc.${T1[i]} = start[${i}] + coords.${T1[i]};`);n=` ${t} sourceLoc; ${t} coords = getOutputCoords(); ${r.join(` `)} `,this.userCode=` void main() { ${n} setOutput(getSource(${a})); } `}},T1=["x","y","z","w","u","v"];function WH(e){if(e===1)return"sourceLoc";if(e<=6)return T1.slice(0,e).map(t=>"sourceLoc."+t).join(",");throw Error(`Slicing for rank ${e} is not yet supported`)}var VH=class{constructor(e){this.variableNames=["source"],this.packedInputs=!0,this.packedOutput=!0,this.outputShape=e,this.rank=e.length,this.customUniforms=[{name:"start",arrayIndex:this.rank,type:"int"}];let t=gt(this.rank),a=va("coords",this.rank),n=va("sourceLoc",this.rank),r=this.rank===1?"sourceLoc":`vec2(${n.slice(-2).join()})`,s=`getChannel(getSource(${n.join()}), ${r})`,i=` result.x = ${s}; if (++${a[this.rank-1]} < ${e[this.rank-1]}) { ++${n[this.rank-1]}; result.y = ${s}; --${n[this.rank-1]}; } `,o=this.rank===1?"":` --${a[this.rank-1]}; if (++${a[this.rank-2]} < ${e[this.rank-2]}) { ++${n[this.rank-2]}; result.z = ${s}; if (++${a[this.rank-1]} < ${e[this.rank-1]}) { ++${n[this.rank-1]}; result.w = ${s}; } } `,l=this.rank<=4?`sourceLoc = coords + ${t}(${e.map((u,p)=>`start[${p}]`).join()});`:e.map((u,p)=>`${n[p]} = ${a[p]} + start[${p}];`).join(` `);this.userCode=` void main() { ${t} coords = getOutputCoords(); ${t} sourceLoc; ${l} vec4 result = vec4(0.); ${i} ${o} setOutput(result); } `}};function UH(e,t,a,n){let r=n.texData.get(e.dataId),s=n.makeTensorInfo(a,e.dtype),i=n.texData.get(s.dataId);Object.assign(i,r),i.refCount=1,i.shape=a,i.dtype=e.dtype;let o=It.computeFlatOffset(t,v.computeStrides(e.shape));r.slice&&(o+=r.slice.flatOffset),i.slice={flatOffset:o,origDataId:r.slice&&r.slice.origDataId||e.dataId};let l=n.dataRefCount.get(i.slice.origDataId)||1;return n.dataRefCount.set(i.slice.origDataId,l+1),s}function gu(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{begin:s,size:i}=n,[o,l]=It.parseSliceParams(r,s,i);if(It.assertParamsValid(r,o,l),v.sizeFromShape(l)===0)return a.makeTensorInfo(l,r.dtype,[]);if(a.shouldExecuteOnCPU([r])||r.dtype==="string"){let c=a.texData.get(r.dataId),d=PU(c.values,o,l,r.shape,r.dtype);return a.makeTensorInfo(l,r.dtype,d)}let{isPacked:u}=a.texData.get(r.dataId),p=It.isSliceContinous(r.shape,o,l);if(u||!p){let c=W().getBool("WEBGL_PACK_ARRAY_OPERATIONS")?new VH(l):new BH(l),d=[o];return a.runWebGLProgram(c,[r],r.dtype,d)}return a.uploadToGPU(r.dataId),UH(r,o,l,a)}var GH={kernelName:Zl,backendName:"webgl",kernelFunc:gu},HH=e=>{let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{blockShape:s,crops:i}=n;v.assert(r.shape.length<=4,()=>"batchToSpaceND for rank > 4 with a WebGL backend not implemented yet");let o=s.reduce((A,y)=>A*y),l=T.getReshaped(r.shape,s,o),u=T.getPermuted(l.length,s.length),p=T.getReshapedPermuted(r.shape,s,o),c=T.getSliceBeginCoords(i,s.length),d=T.getSliceSize(p,i,s.length),h=[],f=ce({inputs:{x:r},backend:a,attrs:{shape:l}}),m=Ia({inputs:{x:f},backend:a,attrs:{perm:u}}),g=ce({inputs:{x:m},backend:a,attrs:{shape:p}}),x=gu({inputs:{x:g},backend:a,attrs:{begin:c,size:d}});return h.push(f),h.push(m),h.push(g),h.forEach(A=>a.disposeIntermediateTensorInfo(A)),x},jH={kernelName:Rl,backendName:"webgl",kernelFunc:HH};function qH(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,weights:s}=t,{size:i}=n,o=a.readSync(r.dataId),l=a.readSync(s.dataId),u=L6(o,l,s.dtype,s.shape,i);return a.makeTensorInfo([i],s.dtype,u)}var XH={kernelName:Id,backendName:"webgl",kernelFunc:qH};function KH(e){let{inputs:t,backend:a}=e,{s0:n,s1:r}=t,s=a.readSync(n.dataId),i=a.readSync(r.dataId),o=T.assertAndGetBroadcastShape(Array.from(s),Array.from(i));return a.makeTensorInfo([o.length],"int32",Int32Array.from(o))}var ZH={kernelName:jc,backendName:"webgl",kernelFunc:KH},YH="return float(a != b);",ev=oa({opSnippet:YH,cpuKernelImpl:SU,dtype:"bool"}),JH={kernelName:Li,backendName:"webgl",kernelFunc:ev};function hp(e){let{inputs:t,backend:a}=e,{input:n}=t,r=a.texData.get(n.dataId);return Za({inputs:{x:r.complexTensorInfos.real},backend:a})}var QH={kernelName:Md,backendName:"webgl",kernelFunc:hp},ej="return float(int(x));";function tj(e,t){let a=new qn(e.shape,ej),n=t.runWebGLProgram(a,[e],"int32");return{dataId:n.dataId,shape:n.shape,dtype:n.dtype}}function C1(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{dtype:s}=n;if(s==="complex64"){if(r.dtype==="complex64")return Za({inputs:{x:r},backend:a});let i=fn(r.shape),o=C1({inputs:{x:r},backend:a,attrs:{dtype:"float32"}}),l=ls({inputs:{real:o,imag:i},backend:a});return i.dispose(),a.disposeIntermediateTensorInfo(o),l}if(r.dtype==="complex64"){let i=hp({inputs:{input:r},backend:a}),o=C1({inputs:{x:i},backend:a,attrs:{dtype:s}});return a.disposeIntermediateTensorInfo(i),o}if(!v.hasEncodingLoss(r.dtype,s)){let i=Za({inputs:{x:r},backend:a});return{dataId:i.dataId,shape:i.shape,dtype:s}}if(a.shouldExecuteOnCPU([r])){let i=a.texData.get(r.dataId).values,[o,l,u]=sU(i,r.shape,r.dtype,s);return a.makeTensorInfo(o,l,u)}if(s==="int32")return tj(r,a);if(s==="bool"){let i=a.makeTensorInfo([],"bool",v.getTypedArrayFromDType("bool",1)),o=ev({inputs:{a:r,b:i},backend:a});return a.disposeIntermediateTensorInfo(i),o}throw new Error(`Error in Cast: failed to cast ${r.dtype} to ${s}`)}var aj={kernelName:ti,backendName:"webgl",kernelFunc:C1},Ix="return ceil(x);",nj=Qe({opSnippet:Ix,packedOpSnippet:Ix,cpuKernelImpl:iU}),rj={kernelName:ai,backendName:"webgl",kernelFunc:nj},sj=class{constructor(e){this.variableNames=["A"],this.customUniforms=[{name:"minVal",type:"float"},{name:"maxVal",type:"float"}],this.outputShape=e,this.userCode=` void main() { float value = getAAtOutCoords(); if (isnan(value)) { setOutput(value); return; } setOutput(clamp(value, minVal, maxVal)); } `}},ij=class{constructor(e){this.variableNames=["A"],this.packedInputs=!0,this.packedOutput=!0,this.customUniforms=[{name:"minVal",type:"float"},{name:"maxVal",type:"float"}],this.outputShape=e,this.userCode=` void main() { vec4 value = getAAtOutCoords(); if (any(isnan(value))) { setOutput(value); return; } setOutput(clamp(value, vec4(minVal), vec4(maxVal))); } `}};function oj(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{clipValueMin:s,clipValueMax:i}=n,o;W().getBool("WEBGL_PACK_CLIP")?o=new ij(r.shape):o=new sj(r.shape);let l=[[s],[i]];return a.runWebGLProgram(o,[r],r.dtype,l)}var lj={kernelName:as,backendName:"webgl",kernelFunc:oj},uj=class{constructor(e){this.variableNames=["real","imag"],this.outputShape=e,this.userCode=` void main() { float re = abs(getRealAtOutCoords()); float im = abs(getImagAtOutCoords()); float mx = max(re, im); // sadly the length function in glsl is not underflow-safe // (at least not on Intel GPUs). So the safe solution is // to ensure underflow-safety in all cases. setOutput( mx == 0.0 ? 0.0 : mx * length(vec2(1, min(re, im)/mx)) ); } `}};function Sx(e,t){return{dataId:t.dataId,dtype:t.dtype,shape:e.shape}}function dj(e){let{inputs:t,backend:a}=e,{x:n}=t,r=a.texData.get(n.dataId),s=new uj(n.shape),i=[Sx(n,r.complexTensorInfos.real),Sx(n,r.complexTensorInfos.imag)];return a.runWebGLProgram(s,i,i[0].dtype)}var pj={kernelName:qc,backendName:"webgl",kernelFunc:dj},cj=class{constructor(e){this.outputShape=[],this.outputShape=T.computeOutShape(e,1),this.variableNames=e.map((s,i)=>`T${i}`);let t=new Array(e.length-1);t[0]=e[0][1];for(let s=1;s`T${m}`);let o=new Array(e.length-1);o[0]=e[0][t];for(let f=1;f= ${o[f-1]}) { return getChannel( getT${f}(${pc(i,l,m)}), vec2(${pc(u,l,m)})); }`}let d=o.length,h=o[o.length-1];c+=` return getChannel( getT${d}(${pc(i,l,h)}), vec2(${pc(u,l,h)}));`,this.userCode=` float getValue(${i.map(f=>"int "+f)}) { ${c} } void main() { ${r} coords = getOutputCoords(); vec4 result = vec4(getValue(${s}), 0., 0., 0.); ${s[n-1]} = ${s[n-1]} + 1; if (${s[n-1]} < ${a[n-1]}) { result.g = getValue(${s}); } ${s[n-2]} = ${s[n-2]} + 1; if (${s[n-2]} < ${a[n-2]}) { result.a = getValue(${s}); } ${s[n-1]} = ${s[n-1]} - 1; if (${s[n-2]} < ${a[n-2]} && ${s[n-1]} < ${a[n-1]}) { result.b = getValue(${s}); } setOutput(result); } `}};function pc(e,t,a){let n=e.indexOf(t);return e.map((r,s)=>s===n?`${r} - ${a}`:r).join()}function Lh(e){let{inputs:t,backend:a}=e,{input:n}=t,r=a.texData.get(n.dataId);return Za({inputs:{x:r.complexTensorInfos.imag},backend:a})}var fj={kernelName:Rd,backendName:"webgl",kernelFunc:Lh};function Zu(e,t,a){let n=e[0].dtype;if(n==="complex64"){let h=e.map(A=>hp({inputs:{input:A},backend:a})),f=e.map(A=>Lh({inputs:{input:A},backend:a})),m=Zu(h,t,a),g=Zu(f,t,a),x=ls({inputs:{real:m,imag:g},backend:a});return h.forEach(A=>a.disposeIntermediateTensorInfo(A)),f.forEach(A=>a.disposeIntermediateTensorInfo(A)),a.disposeIntermediateTensorInfo(m),a.disposeIntermediateTensorInfo(g),x}let r=a.shouldExecuteOnCPU(e);if(n==="string"&&(r=!0),r){let h=e.map(b=>{let w=[-1,v.sizeFromShape(b.shape.slice(t))];return ce({inputs:{x:b},backend:a,attrs:{shape:w}})}),f=h.map(b=>({vals:a.readSync(b.dataId),shape:b.shape})),m=T.computeOutShape(h.map(b=>b.shape),1),g=h[0].shape[0]===1,x=oU(f,m,n,g),A=T.computeOutShape(e.map(b=>b.shape),t),y=a.makeTensorInfo(A,n,x);return h.forEach(b=>a.disposeIntermediateTensorInfo(b)),y}let s=e.filter(h=>v.sizeFromShape(h.shape)>0),i=W().getBool("WEBGL_PACK_ARRAY_OPERATIONS")&&s[0].shape.length>1;if(s.length===1){let h=i?new qn(e[0].shape,Dr):new Vr(e[0].shape,Dr);return a.runWebGLProgram(h,e,n)}let o=W().getNumber("WEBGL_MAX_TEXTURES_IN_SHADER");if(s.length>o){let h=[];for(let m=0;mf.shape),t);return a.runWebGLProgram(h,s,n)}let{tensors2D:l,outShape:u}=mj(s,t,a),p=new cj(l.map(h=>h.shape)),c=a.runWebGLProgram(p,l,n);l.forEach(h=>a.disposeIntermediateTensorInfo(h));let d=ce({inputs:{x:c},attrs:{shape:u},backend:a});return a.disposeIntermediateTensorInfo(c),d}function mj(e,t,a){let n=T.computeOutShape(e.map(r=>r.shape),t);return{tensors2D:e.map(r=>ce({inputs:{x:r},attrs:{shape:[-1,v.sizeFromShape(r.shape.slice(t))]},backend:a})),outShape:n}}function tv(e){let{inputs:t,backend:a,attrs:n}=e,{axis:r}=n,s=v.parseAxisParam(r,t[0].shape)[0],i=t.map(u=>u.shape);T.assertParamsConsistent(i,s);let o=T.computeOutShape(t.map(u=>u.shape),s);if(v.sizeFromShape(o)===0)return a.makeTensorInfo(o,t[0].dtype,[]);let l=t.filter(u=>v.sizeFromShape(u.shape)>0);return l.length===1?Za({inputs:{x:l[0]},backend:a}):Zu(l,s,a)}var gj={kernelName:Ml,backendName:"webgl",kernelFunc:tv},av=class{constructor(e,t=!1,a=null,n=!1,r=!1){this.variableNames=["x","W"],this.outputShape=e.outShape;let s=e.padInfo.top,i=e.padInfo.left,o=e.strideHeight,l=e.strideWidth,u=e.dilationHeight,p=e.dilationWidth,c=e.filterHeight,d=e.filterWidth,h=Math.floor(e.inChannels/4)*4,f=e.inChannels%4,m=e.dataFormat==="channelsLast",g=m?1:2,x=m?2:3,A=m?3:1,y="",b="";a&&(n?y=`float activation(float a) { float b = getPreluActivationWeightsAtOutCoords(); ${a} }`:r?y=`float activation(float a) { float b = getLeakyreluAlphaAtOutCoords(); ${a} }`:y=` float activation(float x) { ${a} } `,b="result = activation(result);");let w=t?"result += getBiasAtOutCoords();":"";t&&this.variableNames.push("bias"),n&&this.variableNames.push("preluActivationWeights"),r&&this.variableNames.push("leakyreluAlpha"),this.userCode=` ${y} const ivec2 strides = ivec2(${o}, ${l}); const ivec2 pads = ivec2(${s}, ${i}); void main() { ivec4 coords = getOutputCoords(); int batch = coords[0]; int d2 = coords[${A}]; ivec2 xRCCorner = ivec2(coords[${g}], coords[${x}]) * strides - pads; int xRCorner = xRCCorner.x; int xCCorner = xRCCorner.y; // Convolve x(?, ?, d1) with w(:, :, d1, d2) to get y(yR, yC, d2). // ? = to be determined. : = across all values in that axis. float dotProd = 0.0; for (int wR = 0; wR < ${c}; wR++) { int xR = xRCorner + wR * ${u}; if (xR < 0 || xR >= ${e.inHeight}) { continue; } for (int wC = 0; wC < ${d}; wC++) { int xC = xCCorner + wC * ${p}; if (xC < 0 || xC >= ${e.inWidth}) { continue; } for (int d1 = 0; d1 < ${h}; d1 += 4) { vec4 wValues = vec4( getW(wR, wC, d1, d2), getW(wR, wC, d1 + 1, d2), getW(wR, wC, d1 + 2, d2), getW(wR, wC, d1 + 3, d2) ); if (${m}) { vec4 xValues = vec4( getX(batch, xR, xC, d1), getX(batch, xR, xC, d1 + 1), getX(batch, xR, xC, d1 + 2), getX(batch, xR, xC, d1 + 3) ); dotProd += dot(xValues, wValues); } else { vec4 xValues = vec4( getX(batch, d1, xR, xC), getX(batch, d1 + 1, xR, xC), getX(batch, d1 + 2, xR, xC), getX(batch, d1 + 3, xR, xC) ); dotProd += dot(xValues, wValues); } } if (${f===1}) { if (${m}) { dotProd += getX(batch, xR, xC, ${h}) * getW(wR, wC, ${h}, d2); } else { dotProd += getX(batch, ${h}, xR, xC) * getW(wR, wC, ${h}, d2); } } else if (${f===2}) { vec2 wValues = vec2( getW(wR, wC, ${h}, d2), getW(wR, wC, ${h} + 1, d2) ); if (${m}) { vec2 xValues = vec2( getX(batch, xR, xC, ${h}), getX(batch, xR, xC, ${h} + 1) ); dotProd += dot(xValues, wValues); } else { vec2 xValues = vec2( getX(batch, ${h}, xR, xC), getX(batch, ${h} + 1, xR, xC) ); dotProd += dot(xValues, wValues); } } else if (${f===3}) { vec3 wValues = vec3( getW(wR, wC, ${h}, d2), getW(wR, wC, ${h} + 1, d2), getW(wR, wC, ${h} + 2, d2) ); if (${m}) { vec3 xValues = vec3( getX(batch, xR, xC, ${h}), getX(batch, xR, xC, ${h} + 1), getX(batch, xR, xC, ${h} + 2) ); dotProd += dot(xValues, wValues); } else { vec3 xValues = vec3( getX(batch, ${h}, xR, xC), getX(batch, ${h} + 1, xR, xC), getX(batch, ${h} + 2, xR, xC) ); dotProd += dot(xValues, wValues); } } } } float result = dotProd; ${w} ${b} setOutput(result); } `}},xj=class{constructor(e){this.variableNames=["x","W"],this.outputShape=e.outShape;let t=e.padInfo.front,a=e.padInfo.top,n=e.padInfo.left,r=e.strideDepth,s=e.strideHeight,i=e.strideWidth,o=e.dilationDepth,l=e.dilationHeight,u=e.dilationWidth,p=e.filterDepth,c=e.filterHeight,d=e.filterWidth,h=Math.floor(e.inChannels/4)*4,f=e.inChannels%4;this.userCode=` const ivec3 strides = ivec3(${r}, ${s}, ${i}); const ivec3 pads = ivec3(${t}, ${a}, ${n}); void main() { ivec5 coords = getOutputCoords(); int batch = coords.x; int d2 = coords.u; ivec3 xFRCCorner = ivec3(coords.y, coords.z, coords.w) * strides - pads; int xFCorner = xFRCCorner.x; int xRCorner = xFRCCorner.y; int xCCorner = xFRCCorner.z; // Convolve x(?, ?, ?, d1) with w(:, :, :, d1, d2) to get // y(yF, yR, yC, d2). ? = to be determined. : = across all // values in that axis. float dotProd = 0.0; for (int wF = 0; wF < ${p}; wF++) { int xF = xFCorner + wF * ${o}; if (xF < 0 || xF >= ${e.inDepth}) { continue; } for (int wR = 0; wR < ${c}; wR++) { int xR = xRCorner + wR * ${l}; if (xR < 0 || xR >= ${e.inHeight}) { continue; } for (int wC = 0; wC < ${d}; wC++) { int xC = xCCorner + wC * ${u}; if (xC < 0 || xC >= ${e.inWidth}) { continue; } for (int d1 = 0; d1 < ${h}; d1 += 4) { vec4 xValues = vec4( getX(batch, xF, xR, xC, d1), getX(batch, xF, xR, xC, d1 + 1), getX(batch, xF, xR, xC, d1 + 2), getX(batch, xF, xR, xC, d1 + 3) ); vec4 wValues = vec4( getW(wF, wR, wC, d1, d2), getW(wF, wR, wC, d1 + 1, d2), getW(wF, wR, wC, d1 + 2, d2), getW(wF, wR, wC, d1 + 3, d2) ); dotProd += dot(xValues, wValues); } if (${f===1}) { dotProd += getX(batch, xF, xR, xC, ${h}) * getW(wF, wR, wC, ${h}, d2); } else if (${f===2}) { vec2 xValues = vec2( getX(batch, xF, xR, xC, ${h}), getX(batch, xF, xR, xC, ${h} + 1) ); vec2 wValues = vec2( getW(wF, wR, wC, ${h}, d2), getW(wF, wR, wC, ${h} + 1, d2) ); dotProd += dot(xValues, wValues); } else if (${f===3}) { vec3 xValues = vec3( getX(batch, xF, xR, xC, ${h}), getX(batch, xF, xR, xC, ${h} + 1), getX(batch, xF, xR, xC, ${h} + 2) ); vec3 wValues = vec3( getW(wF, wR, wC, ${h}, d2), getW(wF, wR, wC, ${h} + 1, d2), getW(wF, wR, wC, ${h} + 2, d2) ); dotProd += dot(xValues, wValues); } } } } setOutput(dotProd); } `}},nv=class{constructor(e,t=!1,a=null,n=!1,r=!1){this.variableNames=["x","W"],this.packedInputs=!0,this.packedOutput=!0,this.customUniforms=[{name:"pads",type:"ivec2"},{name:"strides",type:"ivec2"},{name:"dilations",type:"ivec2"},{name:"inDims",type:"ivec2"}],this.outputShape=e.outShape,this.enableShapeUniforms=Na(this.outputShape.length);let s=e.padInfo.left,i=e.strideWidth,o=e.dilationWidth,l=e.filterHeight,u=e.filterWidth,p=u,c=` int xR; int xC; int xCOffset; vec4 wTexel; vec4 previous; vec4 final;`;for(let m=0;m=0 && xR < inDims[0]) { `;for(let m=0;m<(p+1)/2;m++){let g=m*2;if(c+=` xC = xCCorner + ${g*o}; `,i===1){if(g= 0 && xCOffset < inDims[1] && xTexelC${g}Ready == 0) { xTexelC${g} = getX(batch, xR, xCOffset, d1); // Need to manually clear unused channels in case // we're reading from recycled texture. if (xCOffset + 1 >= inDims[1]) { xTexelC${g}.zw = vec2(0.0); } xTexelC${g}Ready = 1; } `,o===1&&g>0?c+=` xC${g} = vec4(xTexelC${g-2}.zw, xTexelC${g}.xy); `:c+=` xCOffset = xC + 1 - 2; if (xCOffset >= 0 && xCOffset < inDims[1]) { previous = getX(batch, xR, xCOffset, d1); // Need to manually clear unused channels in case // we're reading from recycled texture. if (xCOffset + 1 >= inDims[1]) { previous.zw = vec2(0.0); } xC${g} = vec4(previous.zw, xTexelC${g}.xy); } else { xC${g} = vec4(0.0, 0.0, xTexelC${g}.xy); } `):c+=` if (xC >= 0 && xC < inDims[1] && xTexelC${g}Ready == 0) { xTexelC${g} = getX(batch, xR, xC, d1); if (xC + 1 >= inDims[1]) { xTexelC${g}.zw = vec2(0.0); } xTexelC${g}Ready = 1; } xC${g} = xTexelC${g}; `,g+1= 0 && xCOffset < inDims[1] && xTexelC${g+1}Ready == 0) { xTexelC${g+1} = getX(batch, xR, xCOffset, d1); // Need to manually clear unused channels in case // we're reading from recycled texture. if (xCOffset + 1 >= inDims[1]) { xTexelC${g+1}.zw = vec2(0.0); } xTexelC${g+1}Ready = 1; } `,o>1?c+=` xCOffset -= 2; if (xCOffset >= 0 && xCOffset < inDims[1]) { previous = getX(batch, xR, xCOffset, d1); xC${g+1} = vec4(previous.zw, xTexelC${g+1}.xy); } else { xC${g+1} = vec4(0.0, 0.0, xTexelC${g+1}.xy); } `:c+=` xC${g+1} = vec4(xTexelC${g}.zw, xTexelC${g+1}.xy); `):x===1?c+=` xC${g+1} = xTexelC${g}; `:c+=` xCOffset = xC + ${x}; if (xCOffset >= 0 && xCOffset < inDims[1] && xTexelC${g+1}Ready == 0) { xTexelC${g+1} = getX(batch, xR, xCOffset, d1); if (xCOffset + 1 >= inDims[1]) { xTexelC${g+1}.zw = vec2(0.0); } xTexelC${g+1}Ready = 1; } xC${g+1} = xTexelC${g+1}; `}}else g= 0 && xCOffset < inDims[1] && xTexelC${g}Ready == 0) { xTexelC${g} = getX(batch, xR, xCOffset, d1); // Need to manually clear unused channels in case // we're reading from recycled texture. if (xCOffset + 1 >= inDims[1]) { xTexelC${g}.zw = vec2(0.0); } xTexelC${g}Ready = 1; } if(xC + 1 >= 0 && xC + 1 < inDims[1] && xTexelC${g+1}Ready == 0) { xTexelC${g+1} = getX(batch, xR, xC + 1, d1); // Need to manually clear unused channels in case // we're reading from recycled texture. if (xC + 2 >= inDims[1]) { xTexelC${g+1}.zw = vec2(0.0); } xTexelC${g+1}Ready = 1; } xC${g} = vec4(xTexelC${g}.zw, xTexelC${g+1}.zw); `,g+1= 0 && xCOffset < inDims[1]) { final = getX(batch, xR, xCOffset, d1); } xC${g+1} = vec4(xTexelC${g+1}.xy, final.xy); `)):(c+=` if(xC >= 0 && xC < inDims[1] && xTexelC${g}Ready == 0) { xTexelC${g} = getX(batch, xR, xC, d1); if (xC + 1 >= inDims[1]) { xTexelC${g}.zw = vec2(0.0); } xTexelC${g}Ready = 1; } xCOffset = xC + strides[1]; if(xCOffset >= 0 && xCOffset < inDims[1] && xTexelC${g+1}Ready == 0) { xTexelC${g+1} = getX(batch, xR, xCOffset, d1); if (xCOffset + 1 >= inDims[1]) { xTexelC${g+1}.zw = vec2(0.); } xTexelC${g+1}Ready = 1; } xC${g} = vec4( xTexelC${g}.xy, xTexelC${g+1}.xy); `,g+1= 0) { // Use custom imod instead mod. On Intel GPU, mod may generate // unexpected value. // https://github.com/tensorflow/tfjs/issues/5447 offsetX = imod(blockIndex, outWidth) * stride[1] - pad[1]; d1 = offsetX + dilation[1] * (imod(pos, itemsPerBlockRow) / inChannels); if(d1 < inputShape[${i}] && d1 >= 0) { ch = imod(pos, inChannels); if (${r}) { innerDims = vec2(d1, ch); result[${u*2+p}] = getChannel( getA(rc.x, d0, int(innerDims.x), int(innerDims.y)), innerDims); } else { innerDims = vec2(d0, d1); result[${u*2+p}] = getChannel( getA(rc.x, ch, int(innerDims.x), int(innerDims.y)), innerDims); } } } } `;this.userCode=` void main() { ivec3 rc = getOutputCoords(); vec4 result = vec4(0); int blockIndex, pos, offsetY, d0, offsetX, d1, ch; vec2 innerDims; ${l} ${n.output} = result; } `}};function zc(e,t){let a=e.length;return a>=3?t?[...e.slice(0,-3),e[a-3]*e[a-2],e[a-1]]:[...e.slice(0,-3),e[a-3],e[a-2]*e[a-1]]:!t&&a===1&&e[0]>1?[e[0],1]:null}function rv({x:e,filter:t,convInfo:a,backend:n,bias:r=null,preluActivationWeights:s=null,leakyreluAlpha:i=0,activation:o=null}){let l=e.shape,u=n.texData.get(e.dataId),p=a.inChannels,c=l[0]*l[1]*l[2],d=a.outChannels,h=a.dataFormat==="channelsLast",f=!1,m=!1,g,x=[];if(s!=null){let A=zc(s.shape,h);A!=null&&(s=ce({inputs:{x:s},backend:n,attrs:{shape:A}}),x.push(s))}if(r!=null){let A=zc(r.shape,h);A!=null&&(r=ce({inputs:{x:r},backend:n,attrs:{shape:A}}),x.push(r))}if(!((c===1||d===1)&&p>Z6)&&u.isPacked&&h&&u.texture!=null&&l[2]%2!==0&&v.arraysEqual(u.shape.slice(-3),l.slice(-3))){let A=l[0]*l[1]*(l[2]+1),y={dataId:e.dataId,shape:[1,A,a.inChannels],dtype:e.dtype},b=u.shape;u.shape=u.shape.slice(),u.shape[u.shape.length-2]++,v.assert(md(u.shape,y.shape),()=>`packed reshape ${u.shape} to ${y.shape} isn't free`);let w=ce({inputs:{x:t},backend:n,attrs:{shape:[1,a.inChannels,a.outChannels]}});x.push(w);let S=Dc({a:y,b:w,backend:n,transposeA:f,transposeB:m,bias:r,activation:o,preluActivationWeights:s,leakyreluAlpha:i}),C=n.texData.get(S.dataId);v.assert(C.isPacked,()=>"batchMatMul result is expected to be packed"),u.shape=b,C.shape=a.outShape,g=Za({inputs:{x:S},backend:n}),g.shape=a.outShape,x.push(S)}else{let A=a.outHeight*a.outWidth,y=ce({inputs:{x:e},backend:n,attrs:{shape:h?[a.batchSize,A,a.inChannels]:[a.batchSize,a.inChannels,A]}}),b=ce({inputs:{x:t},backend:n,attrs:{shape:[1,a.inChannels,a.outChannels]}}),w=Dc({a:h?y:b,b:h?b:y,transposeA:!h,transposeB:m,backend:n,bias:r,activation:o,preluActivationWeights:s,leakyreluAlpha:i});g=ce({inputs:{x:w},backend:n,attrs:{shape:a.outShape}}),x.push(y),x.push(b),x.push(w)}for(let A of x)n.disposeIntermediateTensorInfo(A);return g}function sv({x:e,filter:t,convInfo:a,backend:n,bias:r=null,preluActivationWeights:s=null,leakyreluAlpha:i=0,activation:o=null}){let{filterWidth:l,filterHeight:u,inChannels:p,outWidth:c,outHeight:d,dataFormat:h}=a,f=h==="channelsLast",m=l*u*p,g=d*c,x=[a.batchSize,m,g],A=!0,y=!1,b=[];if(s!=null){let j=zc(s.shape,f);j!=null&&(s=ce({inputs:{x:s},backend:n,attrs:{shape:j}}),b.push(s))}if(r!=null){let j=zc(r.shape,f);j!=null&&(r=ce({inputs:{x:r},backend:n,attrs:{shape:j}}),b.push(r))}let w=ce({inputs:{x:t},backend:n,attrs:{shape:[1,m,v.sizeFromShape(t.shape)/m]}});b.push(w);let S=new Aj(x,a),C=[e.shape,[a.padInfo.top,a.padInfo.left],[a.strideHeight,a.strideWidth],[a.dilationHeight,a.dilationWidth],[a.inChannels],[a.filterWidth*a.inChannels],[a.outWidth]],E=n.runWebGLProgram(S,[e],"float32",C),_=ce({inputs:{x:E},backend:n,attrs:{shape:x}});b.push(E),b.push(_);let $=r!=null,M=s!=null,I=o==="leakyrelu",N=o?gd(o,!0):null,O=new K6(f?_.shape:w.shape,f?w.shape:_.shape,f?[a.batchSize,g,a.outChannels]:[a.batchSize,a.outChannels,g],A,y,$,N,M,I),L=f?[_,w]:[w,_];if(r&&L.push(r),M&&L.push(s),I){let j=n.makeTensorInfo([],"float32",v.createScalarValue(i,"float32"));L.push(j),b.push(j)}let B=n.runWebGLProgram(O,L,"float32"),G=ce({inputs:{x:B},backend:n,attrs:{shape:a.outShape}});b.push(B);for(let j of b)n.disposeIntermediateTensorInfo(j);return G}function yj(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,filter:s}=t,{strides:i,pad:o,dataFormat:l,dilations:u,dimRoundingMode:p}=n,c=T.convertConv2DDataFormat(l),d=T.computeConv2DInfo(r.shape,s.shape,i,u,o,p,!1,c),h;if(d.filterHeight===1&&d.filterWidth===1&&d.dilationHeight===1&&d.dilationWidth===1&&d.strideHeight===1&&d.strideWidth===1&&(d.padInfo.type==="SAME"||d.padInfo.type==="VALID"))h=rv({x:r,filter:s,convInfo:d,backend:a});else if(d.strideWidth<=2&&c==="channelsLast"&&W().getBool("WEBGL_EXP_CONV")){let m=new nv(d),g=[[d.padInfo.top,d.padInfo.left],[d.strideHeight,d.strideWidth],[d.dilationHeight,d.dilationWidth],[d.inHeight,d.inWidth]];h=a.runWebGLProgram(m,[r,s],"float32",g)}else if(W().getBool("WEBGL_CONV_IM2COL"))h=sv({x:r,filter:s,convInfo:d,backend:a});else{let m=new av(d);h=a.runWebGLProgram(m,[r,s],"float32")}let f=ce({inputs:{x:h},backend:a,attrs:{shape:d.outShape}});return a.disposeIntermediateTensorInfo(h),f}var bj={kernelName:ni,backendName:"webgl",kernelFunc:yj},vj=class{constructor(e){this.variableNames=["x","dy"],this.outputShape=e.filterShape;let t=e.strideHeight,a=e.strideWidth,n=e.padInfo.top,r=e.padInfo.left,s=e.dataFormat==="channelsLast";this.userCode=` void main() { ivec4 coords = getOutputCoords(); int wR = coords.x; int wC = coords.y; int d1 = coords.z; int d2 = coords.w; // Convolve x(?, ?, d1) with dy(:, :, d2) to get dw(wR, wC, d1, d2). // ? = to be determined. : = across all values in that axis. float dotProd = 0.0; for (int b = 0; b < ${e.batchSize}; b++) { for (int yR = 0; yR < ${e.outHeight}; yR++) { int xR = wR + yR * ${t} - ${n}; if (xR < 0 || xR >= ${e.inHeight}) { continue; } for (int yC = 0; yC < ${e.outWidth}; yC++) { int xC = wC + yC * ${a} - ${r}; if (xC < 0 || xC >= ${e.inWidth}) { continue; } if (${s}) { float dyValue = getDy(b, yR, yC, d2); float xValue = getX(b, xR, xC, d1); dotProd += (xValue * dyValue); } else { float dyValue = getDy(b, d2, yR, yC); float xValue = getX(b, d1, xR, xC); dotProd += (xValue * dyValue); } } } } setOutput(dotProd); } `}},wj=class{constructor(e){this.variableNames=["dy","W"],this.outputShape=e.inShape;let t=e.filterHeight,a=e.filterWidth,n=e.strideHeight,r=e.strideWidth,s=e.dataFormat==="channelsLast",i=t-1-e.padInfo.top,o=a-1-e.padInfo.left,l=s?1:2,u=s?2:3,p=s?3:1;this.userCode=` const ivec2 pads = ivec2(${i}, ${o}); void main() { ivec4 coords = getOutputCoords(); int batch = coords[0]; int d1 = coords[${p}]; ivec2 dyCorner = ivec2(coords[${l}], coords[${u}]) - pads; int dyRCorner = dyCorner.x; int dyCCorner = dyCorner.y; // Convolve dy(?, ?, d2) with w(:, :, d1, d2) to compute dx(xR, xC, d1). // ? = to be determined. : = across all values in that axis. float dotProd = 0.0; for (int wR = 0; wR < ${t}; wR++) { float dyR = float(dyRCorner + wR) / ${n}.0; if (dyR < 0.0 || dyR >= ${e.outHeight}.0 || fract(dyR) > 0.0) { continue; } int idyR = int(dyR); int wRPerm = ${t} - 1 - wR; for (int wC = 0; wC < ${a}; wC++) { float dyC = float(dyCCorner + wC) / ${r}.0; if (dyC < 0.0 || dyC >= ${e.outWidth}.0 || fract(dyC) > 0.0) { continue; } int idyC = int(dyC); int wCPerm = ${a} - 1 - wC; for (int d2 = 0; d2 < ${e.outChannels}; d2++) { if (${s}) { float xValue = getDy(batch, idyR, idyC, d2); float wValue = getW(wRPerm, wCPerm, d1, d2); dotProd += xValue * wValue; } else { float xValue = getDy(batch, d2, idyR, idyC); float wValue = getW(wRPerm, wCPerm, d1, d2); dotProd += xValue * wValue; } } } } setOutput(dotProd); } `}},kj=class{constructor(e){this.variableNames=["x","dy"],this.outputShape=e.filterShape;let t=e.strideDepth,a=e.strideHeight,n=e.strideWidth,r=e.padInfo.front,s=e.padInfo.top,i=e.padInfo.left;this.userCode=` void main() { ivec5 coords = getOutputCoords(); int wF = coords.x; int wR = coords.y; int wC = coords.z; int d1 = coords.w; int d2 = coords.u; float dotProd = 0.0; for (int b = 0; b < ${e.batchSize}; b++) { for (int yF = 0; yF < ${e.outDepth}; yF++) { int xF = wF + yF * ${t} - ${r}; if (xF < 0 || xF >= ${e.inDepth}) { continue; } for (int yR = 0; yR < ${e.outHeight}; yR++) { int xR = wR + yR * ${a} - ${s}; if (xR < 0 || xR >= ${e.inHeight}) { continue; } for (int yC = 0; yC < ${e.outWidth}; yC++) { int xC = wC + yC * ${n} - ${i}; if (xC < 0 || xC >= ${e.inWidth}) { continue; } float dyValue = getDy(b, yF, yR, yC, d2); float xValue = getX(b, xF, xR, xC, d1); dotProd += (xValue * dyValue); } } } } setOutput(dotProd); } `}},Ij=class{constructor(e){this.variableNames=["dy","W"],this.outputShape=e.inShape;let t=e.filterDepth,a=e.filterHeight,n=e.filterWidth,r=e.strideDepth,s=e.strideHeight,i=e.strideWidth,o=t-1-e.padInfo.front,l=a-1-e.padInfo.top,u=n-1-e.padInfo.left;this.userCode=` const ivec3 pads = ivec3(${o}, ${l}, ${u}); void main() { ivec5 coords = getOutputCoords(); int batch = coords.x; int d1 = coords.u; ivec3 dyCorner = ivec3(coords.y, coords.z, coords.w) - pads; int dyFCorner = dyCorner.x; int dyRCorner = dyCorner.y; int dyCCorner = dyCorner.z; float dotProd = 0.0; for (int wF = 0; wF < ${t}; wF++) { float dyF = float(dyFCorner + wF) / ${r}.0; if (dyF < 0.0 || dyF >= ${e.outDepth}.0 || fract(dyF) > 0.0) { continue; } int idyF = int(dyF); int wFPerm = ${t} - 1 - wF; for (int wR = 0; wR < ${a}; wR++) { float dyR = float(dyRCorner + wR) / ${s}.0; if (dyR < 0.0 || dyR >= ${e.outHeight}.0 || fract(dyR) > 0.0) { continue; } int idyR = int(dyR); int wRPerm = ${a} - 1 - wR; for (int wC = 0; wC < ${n}; wC++) { float dyC = float(dyCCorner + wC) / ${i}.0; if (dyC < 0.0 || dyC >= ${e.outWidth}.0 || fract(dyC) > 0.0) { continue; } int idyC = int(dyC); int wCPerm = ${n} - 1 - wC; for (int d2 = 0; d2 < ${e.outChannels}; d2++) { float xValue = getDy(batch, idyF, idyR, idyC, d2); float wValue = getW(wFPerm, wRPerm, wCPerm, d1, d2); dotProd += xValue * wValue; } } } } setOutput(dotProd); } `}};function Sj(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,dy:s}=t,{strides:i,pad:o,dataFormat:l,dimRoundingMode:u,filterShape:p}=n,c=T.convertConv2DDataFormat(l),d=T.computeConv2DInfo(r.shape,p,i,1,o,u,!1,c),h=new vj(d);return a.runWebGLProgram(h,[r,s],"float32")}var Tj={kernelName:Xc,backendName:"webgl",kernelFunc:Sj};function Cj(e){let{inputs:t,backend:a,attrs:n}=e,{dy:r,filter:s}=t,{inputShape:i,strides:o,pad:l,dataFormat:u,dimRoundingMode:p}=n,c=T.convertConv2DDataFormat(u),d=T.computeConv2DInfo(i,s.shape,o,1,l,p,!1,c),h=new wj(d);return a.runWebGLProgram(h,[r,s],"float32")}var Nj={kernelName:ri,backendName:"webgl",kernelFunc:Cj};function Ej(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,filter:s}=t,{strides:i,pad:o,dilations:l}=n,u=T.computeConv3DInfo(r.shape,s.shape,i,l,o),p=new xj(u);return a.runWebGLProgram(p,[r,s],"float32")}var Rj={kernelName:Kc,backendName:"webgl",kernelFunc:Ej};function Mj(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,dy:s}=t,{strides:i,pad:o,filterShape:l}=n,u=T.computeConv3DInfo(r.shape,l,i,1,o),p=new kj(u);return a.runWebGLProgram(p,[r,s],"float32")}var $j={kernelName:H1,backendName:"webgl",kernelFunc:Mj};function _j(e){let{inputs:t,backend:a,attrs:n}=e,{dy:r,filter:s}=t,{pad:i,strides:o,inputShape:l}=n,u=T.computeConv3DInfo(l,s.shape,o,1,i),p=new Ij(u);return a.runWebGLProgram(p,[r,s],"float32")}var Pj={kernelName:Zc,backendName:"webgl",kernelFunc:_j},Fj=mu+` return cos(x); `,Oj=Qe({opSnippet:Fj}),Dj={kernelName:si,backendName:"webgl",kernelFunc:Oj},zj=` float e2x = exp(-x); return (e2x + 1.0 / e2x) / 2.0; `,Lj=Qe({opSnippet:zj}),Bj={kernelName:ii,backendName:"webgl",kernelFunc:Lj},Wj=class{constructor(e,t,a,n,r){this.variableNames=["Image","Boxes","BoxInd"],this.outputShape=[];let[s,i,o,l]=e,[u]=t,[p,c]=a;this.outputShape=[u,p,c,l];let d=n==="bilinear"?1:0,[h,f]=[`${i-1}.0`,`${o-1}.0`],[m,g,x]=p>1?[`${(i-1)/(p-1)}`,"(y2-y1) * height_ratio",`y1*${h} + float(y)*(height_scale)`]:["0.0","0.0",`0.5 * (y1+y2) * ${h}`],[A,y,b]=c>1?[`${(o-1)/(c-1)}`,"(x2-x1) * width_ratio",`x1*${f} + float(x)*(width_scale)`]:["0.0","0.0",`0.5 * (x1+x2) * ${f}`];this.userCode=` const float height_ratio = float(${m}); const float width_ratio = float(${A}); void main() { ivec4 coords = getOutputCoords(); int b = coords[0]; int y = coords[1]; int x = coords[2]; int d = coords[3]; // get box vals float y1 = getBoxes(b,0); float x1 = getBoxes(b,1); float y2 = getBoxes(b,2); float x2 = getBoxes(b,3); // get image in batch index int bInd = round(getBoxInd(b)); if(bInd < 0 || bInd >= ${s}) { return; } float height_scale = ${g}; float width_scale = ${y}; float in_y = ${x}; if( in_y < 0.0 || in_y > ${h} ) { setOutput(float(${r})); return; } float in_x = ${b}; if( in_x < 0.0 || in_x > ${f} ) { setOutput(float(${r})); return; } vec2 sourceFracIndexCR = vec2(in_x,in_y); if(${d} == 1) { // Compute the four integer indices. ivec2 sourceFloorCR = ivec2(sourceFracIndexCR); ivec2 sourceCeilCR = ivec2(ceil(sourceFracIndexCR)); float topLeft = getImage(b, sourceFloorCR.y, sourceFloorCR.x, d); float bottomLeft = getImage(b, sourceCeilCR.y, sourceFloorCR.x, d); float topRight = getImage(b, sourceFloorCR.y, sourceCeilCR.x, d); float bottomRight = getImage(b, sourceCeilCR.y, sourceCeilCR.x, d); vec2 fracCR = sourceFracIndexCR - vec2(sourceFloorCR); float top = topLeft + (topRight - topLeft) * fracCR.x; float bottom = bottomLeft + (bottomRight - bottomLeft) * fracCR.x; float newValue = top + (bottom - top) * fracCR.y; setOutput(newValue); } else { // Compute the coordinators of nearest neighbor point. ivec2 sourceNearestCR = ivec2(floor( sourceFracIndexCR + vec2(0.5,0.5))); float newValue = getImage(b, sourceNearestCR.y, sourceNearestCR.x, d); setOutput(newValue); } } `}},Vj=e=>{let{inputs:t,backend:a,attrs:n}=e,{image:r,boxes:s,boxInd:i}=t,{cropSize:o,method:l,extrapolationValue:u}=n,p=new Wj(r.shape,s.shape,o,l,u);return a.runWebGLProgram(p,[r,s,i],"float32")},Uj={kernelName:ui,backendName:"webgl",kernelFunc:Vj},Ad;(function(e){e.Prod="*",e.Sum="+"})(Ad||(Ad={}));var Tx=class{constructor(e,t,a,n){this.op=e,this.outputShape=t,this.variableNames=["x"],this.customUniforms=[{name:"index",type:"float"}];let r=this.outputShape.length,s=this.op===Ad.Prod?"1.0":"0.0",i=a?s:`getX(${Cx(r,"coords",this.op)})`,o=this.outputShape[this.outputShape.length-1],l="",u="";a?(l=n?`end != ${o-1}`:"end != 0",u=n?"end + 1":"end - 1"):(l=n?`end + pow2 < ${o}`:"end >= pow2",u=n?"end + pow2":"end - pow2"),this.userCode=` void main() { ${gt(r)} coords = getOutputCoords(); int end = ${Nx(r,"coords",this.op)}; float val = ${i}; int pow2 = int(pow(2.0, index)); if (${l}) { int idx = ${u}; ${Nx(r,"coords",this.op)} = idx; val ${this.op}= getX(${Cx(r,"coords",this.op)}); } setOutput(val); } `}};function Cx(e,t,a){if(e===1)return`${t}`;if(e===2)return`${t}.x, ${t}.y`;if(e===3)return`${t}.x, ${t}.y, ${t}.z`;if(e===4)return`${t}.x, ${t}.y, ${t}.z, ${t}.w`;throw new Error(`Cumulative ${a} for rank ${e} is not yet supported`)}function Nx(e,t,a){if(e===1)return`${t}`;if(e===2)return`${t}.y`;if(e===3)return`${t}.z`;if(e===4)return`${t}.w`;throw new Error(`Cumulative ${a} for rank ${e} is not yet supported`)}function iv(e,t,a,n,r,s){let i=t.shape.length,o=T.getAxesPermutation([n],i),l=t;o!=null&&(l=Ia({inputs:{x:t},backend:a,attrs:{perm:o}}));let u=T.getInnerMostAxes(1,i)[0];if(u!==i-1)throw new Error(`WebGL cumprod shader expects an inner-most axis=${t.shape.length-1} but got axis=${n}`);let p=l.shape[u],c=Za({inputs:{x:l},backend:a});for(let d=0;d<=Math.ceil(Math.log2(p))-1;d++){let h=new Tx(e,l.shape,!1,s),f=[[d]],m=c;c=a.runWebGLProgram(h,[c],c.dtype,f),a.disposeIntermediateTensorInfo(m)}if(r){let d=new Tx(e,l.shape,r,s),h=c;c=a.runWebGLProgram(d,[c],c.dtype),a.disposeIntermediateTensorInfo(h)}if(o!=null){let d=T.getUndoAxesPermutation(o),h=Ia({inputs:{x:c},backend:a,attrs:{perm:d}});return a.disposeIntermediateTensorInfo(c),a.disposeIntermediateTensorInfo(l),h}return c}function Gj(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,exclusive:i,reverse:o}=n;return iv(Ad.Prod,r,a,s,i,o)}var Hj={kernelName:oi,backendName:"webgl",kernelFunc:Gj};function jj(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,exclusive:i,reverse:o}=n;return iv(Ad.Sum,r,a,s,i,o)}var qj={kernelName:li,backendName:"webgl",kernelFunc:jj};function Xj(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,weights:s}=t,{size:i,binaryOutput:o}=n;if(r.shape.length===1){let l=a.readSync(r.dataId),u=a.readSync(s.dataId),p=L6(l,u,s.dtype,s.shape,i);return a.makeTensorInfo([i],s.dtype,p)}else if(r.shape.length===2){let l=a.bufferSync(r),u=a.bufferSync(s),p=rU(l,u,i,o);return a.makeTensorInfo(p.shape,s.dtype,p.values)}throw new Error(`Error in denseBincount: input must be at most rank 2, but got rank${r.shape.length}.`)}var Kj={kernelName:Td,backendName:"webgl",kernelFunc:Xj},Zj=class{constructor(e,t,a){this.variableNames=["x"],this.outputShape=[],this.outputShape=e,this.blockSize=t,this.dataFormat=a,this.userCode=` void main() { ivec4 coords = getOutputCoords(); int b = coords[0]; int h = ${this.getHeightCoordString()}; int w = ${this.getWidthCoordString()}; int d = ${this.getDepthCoordString()}; int in_h = h / ${t}; int offset_h = imod(h, ${t}); int in_w = w / ${t}; int offset_w = imod(w, ${t}); int offset_d = (offset_h * ${t} + offset_w) * ${this.getOutputDepthSize()}; int in_d = d + offset_d; float result = ${this.getInputSamplingString()}; setOutput(result); } `}getHeightCoordString(){return this.dataFormat==="NHWC"?"coords[1]":"coords[2]"}getWidthCoordString(){return this.dataFormat==="NHWC"?"coords[2]":"coords[3]"}getDepthCoordString(){return this.dataFormat==="NHWC"?"coords[3]":"coords[1]"}getOutputDepthSize(){return this.dataFormat==="NHWC"?this.outputShape[3]:this.outputShape[1]}getInputSamplingString(){return this.dataFormat==="NHWC"?"getX(b, in_h, in_w, in_d)":"getX(b, in_d, in_h, in_w)"}};function Yj(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{blockSize:s,dataFormat:i}=n,o=r.shape[0],l=i==="NHWC"?r.shape[1]:r.shape[2],u=i==="NHWC"?r.shape[2]:r.shape[3],p=i==="NHWC"?r.shape[3]:r.shape[1],c=l*s,d=u*s,h=p/(s*s),f=i==="NHWC"?[o,c,d,h]:[o,h,c,d],m=new Zj(f,s,i);return a.runWebGLProgram(m,[r],r.dtype)}var Jj={kernelName:di,backendName:"webgl",kernelFunc:Yj},ov=class{constructor(e,t=!1,a=null,n=!1,r=!1){this.variableNames=["x","W"],this.customUniforms=[{name:"pads",type:"ivec2"},{name:"strides",type:"ivec2"},{name:"dilations",type:"ivec2"},{name:"inDims",type:"ivec2"}],this.outputShape=e.outShape,this.enableShapeUniforms=Na(this.outputShape.length);let s=e.filterHeight,i=e.filterWidth,o=e.outChannels/e.inChannels,l="",u="";a&&(n?l=`float activation(float a) { float b = getPreluActivationWeightsAtOutCoords(); ${a} }`:r?l=`float activation(float a) { float b = getLeakyreluAlphaAtOutCoords(); ${a} }`:l=` float activation(float x) { ${a} } `,u="result = activation(result);");let p=t?"result += getBiasAtOutCoords();":"";t&&this.variableNames.push("bias"),n&&this.variableNames.push("preluActivationWeights"),r&&this.variableNames.push("leakyreluAlpha"),this.userCode=` ${l} void main() { ivec4 coords = getOutputCoords(); int batch = coords.x; ivec2 xRCCorner = coords.yz * strides - pads; int d2 = coords.w; int d1 = d2 / ${o}; int q = d2 - d1 * ${o}; int xRCorner = xRCCorner.x; int xCCorner = xRCCorner.y; // Convolve x(?, ?, d1) with w(:, :, d1, q) to get y(yR, yC, d2). // ? = to be determined. : = across all values in that axis. float dotProd = 0.0; // TO DO(dsmilkov): Flatten the two for loops and vec4 the operations. for (int wR = 0; wR < ${s}; wR++) { int xR = xRCorner + wR * dilations[0]; if (xR < 0 || xR >= inDims[0]) { continue; } for (int wC = 0; wC < ${i}; wC++) { int xC = xCCorner + wC * dilations[1]; if (xC < 0 || xC >= inDims[1]) { continue; } float xVal = getX(batch, xR, xC, d1); float wVal = getW(wR, wC, d1, q); dotProd += xVal * wVal; } } float result = dotProd; ${p} ${u} setOutput(result); } `}},lv=class{constructor(e,t=!1,a=null,n=!1,r=!1){this.variableNames=["x","W"],this.packedInputs=!0,this.packedOutput=!0,this.customUniforms=[{name:"pads",type:"ivec2"},{name:"strides",type:"ivec2"},{name:"dilations",type:"ivec2"},{name:"inDims",type:"ivec2"}],this.outputShape=e.outShape,this.enableShapeUniforms=Na(this.outputShape.length);let s=e.outChannels/e.inChannels,i=e.padInfo.left,o=e.strideWidth,l=e.dilationWidth,u=e.filterHeight,p=e.filterWidth,c=p,d=` int xR; int xC; int xCOffset; vec4 wTexel; vec4 previous; vec4 final;`;for(let g=0;g=0 && xR < inDims[0]) { `;for(let g=0;g<(c+1)/2;g++){let x=g*2;if(d+=` xC = xCCorner + ${x*l}; `,o===1){if(x= 0 && xCOffset < inDims[1] && xTexelC${x}Ready == 0) { xTexelC${x} = getX(batch, xR, xCOffset, d1); // Need to manually clear unused channels in case // we're reading from recycled texture. if (xCOffset + 1 >= inDims[1]) { xTexelC${x}.zw = vec2(0.0); } xTexelC${x}Ready = 1; } `,l===1&&x>0?d+=` xC${x} = vec4(xTexelC${x-2}.zw, xTexelC${x}.xy); `:d+=` xCOffset = xC + 1 - 2; if (xCOffset >= 0 && xCOffset < inDims[1]) { previous = getX(batch, xR, xCOffset, d1); // Need to manually clear unused channels in case // we're reading from recycled texture. if (xCOffset + 1 >= inDims[1]) { previous.zw = vec2(0.0); } xC${x} = vec4(previous.zw, xTexelC${x}.xy); } else { xC${x} = vec4(0.0, 0.0, xTexelC${x}.xy); } `):d+=` if (xC >= 0 && xC < inDims[1] && xTexelC${x}Ready == 0) { xTexelC${x} = getX(batch, xR, xC, d1); if (xC + 1 >= inDims[1]) { xTexelC${x}.zw = vec2(0.0); } xTexelC${x}Ready = 1; } xC${x} = xTexelC${x}; `,x+1= 0 && xCOffset < inDims[1] && xTexelC${x+1}Ready == 0) { xTexelC${x+1} = getX(batch, xR, xCOffset, d1); // Need to manually clear unused channels in case // we're reading from recycled texture. if (xCOffset + 1 >= inDims[1]) { xTexelC${x+1}.zw = vec2(0.0); } xTexelC${x+1}Ready = 1; } `,l>1?d+=` xCOffset -= 2; if (xCOffset >= 0 && xCOffset < inDims[1]) { previous = getX(batch, xR, xCOffset, d1); xC${x+1} = vec4(previous.zw, xTexelC${x+1}.xy); } else { xC${x+1} = vec4(0.0, 0.0, xTexelC${x+1}.xy); } `:d+=` xC${x+1} = vec4(xTexelC${x}.zw, xTexelC${x+1}.xy); `):A===1?d+=` xC${x+1} = xTexelC${x}; `:d+=` xCOffset = xC + ${A}; if (xCOffset >= 0 && xCOffset < inDims[1] && xTexelC${x+1}Ready == 0) { xTexelC${x+1} = getX(batch, xR, xCOffset, d1); if (xCOffset + 1 >= inDims[1]) { xTexelC${x+1}.zw = vec2(0.0); } xTexelC${x+1}Ready = 1; } xC${x+1} = xTexelC${x+1}; `}}else x= 0 && xCOffset < inDims[1] && xTexelC${x}Ready == 0) { xTexelC${x} = getX(batch, xR, xCOffset, d1); // Need to manually clear unused channels in case // we're reading from recycled texture. if (xCOffset + 1 >= inDims[1]) { xTexelC${x}.zw = vec2(0.0); } xTexelC${x}Ready = 1; } if(xC + 1 >= 0 && xC + 1 < inDims[1] && xTexelC${x+1}Ready == 0) { xTexelC${x+1} = getX(batch, xR, xC + 1, d1); // Need to manually clear unused channels in case // we're reading from recycled texture. if (xC + 2 >= inDims[1]) { xTexelC${x+1}.zw = vec2(0.0); } xTexelC${x+1}Ready = 1; } xC${x} = vec4(xTexelC${x}.zw, xTexelC${x+1}.zw); `,x+1= 0 && xCOffset < inDims[1]) { final = getX(batch, xR, xCOffset, d1); } xC${x+1} = vec4(xTexelC${x+1}.xy, final.xy); `)):(d+=` if(xC >= 0 && xC < inDims[1] && xTexelC${x}Ready == 0) { xTexelC${x} = getX(batch, xR, xC, d1); if (xC + 1 >= inDims[1]) { xTexelC${x}.zw = vec2(0.0); } xTexelC${x}Ready = 1; } xCOffset = xC + strides[1]; if(xCOffset >= 0 && xCOffset < inDims[1] && xTexelC${x+1}Ready == 0) { xTexelC${x+1} = getX(batch, xR, xCOffset, d1); if (xCOffset + 1 >= inDims[1]) { xTexelC${x+1}.zw = vec2(0.); } xTexelC${x+1}Ready = 1; } xC${x} = vec4( xTexelC${x}.xy, xTexelC${x+1}.xy); `,x+1`Error in depthwiseConv2d: Either strides or dilations must be 1. Got strides ${i} and dilations '${p}'`);let c=T.computeConv2DInfo(r.shape,s.shape,i,p,o,u,!0),d;W().getBool("WEBGL_PACK_DEPTHWISECONV")&&c.strideWidth<=2&&c.outChannels/c.inChannels===1?d=new lv(c):d=new ov(c);let h=[[c.padInfo.top,c.padInfo.left],[c.strideHeight,c.strideWidth],[c.dilationHeight,c.dilationWidth],[c.inHeight,c.inWidth]];return a.runWebGLProgram(d,[r,s],"float32",h)}var eq={kernelName:pi,backendName:"webgl",kernelFunc:Qj},tq=class{constructor(e){this.variableNames=["x","dy"],this.outputShape=e.filterShape;let t=e.strideHeight,a=e.strideWidth,n=e.padInfo.top,r=e.padInfo.left,s=e.outChannels/e.inChannels;this.userCode=` void main() { ivec4 coords = getOutputCoords(); int wR = coords.x; int wC = coords.y; int d1 = coords.z; int dm = coords.w; int d2 = d1 * ${s} + dm; float dotProd = 0.0; // TO DO: Vec4 over the batch size for (int b = 0; b < ${e.batchSize}; b++) { for (int yR = 0; yR < ${e.outHeight}; yR++) { int xR = wR + yR * ${t} - ${n}; if (xR < 0 || xR >= ${e.inHeight}) { continue; } for (int yC = 0; yC < ${e.outWidth}; yC++) { int xC = wC + yC * ${a} - ${r}; if (xC < 0 || xC >= ${e.inWidth}) { continue; } float dyValue = getDy(b, yR, yC, d2); float xValue = getX(b, xR, xC, d1); dotProd += (xValue * dyValue); } } } setOutput(dotProd); } `}},aq=class{constructor(e){this.variableNames=["dy","W"],this.outputShape=e.inShape;let t=e.filterHeight,a=e.filterWidth,n=e.strideHeight,r=e.strideWidth,s=t-1-e.padInfo.top,i=a-1-e.padInfo.left,o=e.outChannels/e.inChannels;this.userCode=` const ivec2 pads = ivec2(${s}, ${i}); void main() { ivec4 coords = getOutputCoords(); int batch = coords[0]; int d1 = coords[3]; ivec2 dyCorner = coords.yz - pads; int dyRCorner = dyCorner.x; int dyCCorner = dyCorner.y; float dotProd = 0.0; for (int wR = 0; wR < ${t}; wR++) { float dyR = float(dyRCorner + wR) / ${n}.0; if (dyR < 0.0 || dyR >= ${e.outHeight}.0 || fract(dyR) > 0.0) { continue; } int idyR = int(dyR); int wRPerm = ${t} - 1 - wR; for (int wC = 0; wC < ${a}; wC++) { float dyC = float(dyCCorner + wC) / ${r}.0; if (dyC < 0.0 || dyC >= ${e.outWidth}.0 || fract(dyC) > 0.0) { continue; } int idyC = int(dyC); int wCPerm = ${a} - 1 - wC; // TO DO: Vec4 over the channelMul for (int dm = 0; dm < ${o}; dm++) { int d2 = d1 * ${o} + dm; float xValue = getDy(batch, idyR, idyC, d2); float wValue = getW(wRPerm, wCPerm, d1, dm); dotProd += xValue * wValue; } } } setOutput(dotProd); } `}};function nq(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,dy:s}=t,{strides:i,dilations:o,pad:l,dimRoundingMode:u,filterShape:p}=n,c=T.computeConv2DInfo(r.shape,p,i,o,l,u,!0),d=new tq(c);return a.runWebGLProgram(d,[r,s],"float32")}var rq={kernelName:Yc,backendName:"webgl",kernelFunc:nq};function sq(e){let{inputs:t,backend:a,attrs:n}=e,{dy:r,filter:s}=t,{strides:i,dilations:o,pad:l,dimRoundingMode:u,inputShape:p}=n,c=T.computeConv2DInfo(p,s.shape,i,o,l,u,!0),d=new aq(c);return a.runWebGLProgram(d,[r,s],"float32")}var iq={kernelName:Jc,backendName:"webgl",kernelFunc:sq},oq=class{constructor(e){this.variableNames=["X"],this.outputShape=[e,e],this.userCode=` void main() { ivec2 coords = getOutputCoords(); float val = coords[0] == coords[1] ? getX(coords[0]) : 0.0; setOutput(val); } `}};function lq(e){let{inputs:t,backend:a}=e,{x:n}=t,r=[...n.shape,...n.shape],s=v.sizeFromShape(n.shape),i=ce({inputs:{x:n},backend:a,attrs:{shape:[s]}}),o=new oq(s),l=a.runWebGLProgram(o,[i],i.dtype),u=ce({inputs:{x:l},backend:a,attrs:{shape:r}});return a.disposeIntermediateTensorInfo(i),a.disposeIntermediateTensorInfo(l),u}var uq={kernelName:Qc,backendName:"webgl",kernelFunc:lq},dq=class{constructor(e){this.variableNames=["x","W"],this.outputShape=e.outShape;let{inHeight:t,inWidth:a,padInfo:n,strideHeight:r,strideWidth:s,filterHeight:i,filterWidth:o,dilationHeight:l,dilationWidth:u}=e,{top:p,left:c}=n;this.userCode=` const ivec2 strides = ivec2(${r}, ${s}); const ivec2 pads = ivec2(${p}, ${c}); const float neg_infinity = -3.4e38; void main() { ivec4 coords = getOutputCoords(); int batch = coords.x; int d1 = coords.w; ivec2 outTopLeftCorner = coords.yz * strides - pads; int hBeg = outTopLeftCorner.x; int wBeg = outTopLeftCorner.y; float curVal = neg_infinity; for (int h = 0; h < ${i}; h++) { int hIn = hBeg + h * ${l}; if (hIn >= 0 && hIn < ${t}) { for (int w = 0; w < ${o}; w++) { int wIn = wBeg + w * ${u}; if (wIn >= 0 && wIn < ${a}) { float xVal = getX(batch, hIn, wIn, d1); float wVal = getW(h, w, d1); float val = xVal + wVal; if (val > curVal) { curVal = val; } } } } } float result = curVal; setOutput(result); } `}};function pq(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,filter:s}=t,{strides:i,pad:o,dilations:l}=n,u=T.computeDilation2DInfo(r.shape,s.shape,i,o,"NHWC",l),p,c=new dq(u);p=a.runWebGLProgram(c,[r,s],"float32");let d=ce({inputs:{x:p},backend:a,attrs:{shape:u.outShape}});return a.disposeIntermediateTensorInfo(p),d}var cq={kernelName:eh,backendName:"webgl",kernelFunc:pq};function hq(e){let{inputs:t,backend:a,attrs:n}=e,{equation:r}=n,s=t,{allDims:i,summedDims:o,idDims:l}=T.decodeEinsumEquation(r,s.length);T.checkEinsumDimSizes(i.length,l,s);let{path:u,steps:p}=T.getEinsumComputePath(o,l),c=p.length,d=null,h=i.length,f=[];for(let m=0;m=0&&(d=zh({inputs:{x:d},backend:a,attrs:{axis:u[m]-(i.length-h),keepDims:!1}}),f.push(d)),h--)}for(let m of f)m!==d&&a.disposeIntermediateTensorInfo(m);return d}var fq={kernelName:Cd,backendName:"webgl",kernelFunc:hq},mq="return (x >= 0.0) ? x : (exp(x) - 1.0);",gq=` vec4 result; result.r = (x.r >= 0.0) ? x.r : (exp(x.r) - 1.0); result.g = (x.g >= 0.0) ? x.g : (exp(x.g) - 1.0); result.b = (x.b >= 0.0) ? x.b : (exp(x.b) - 1.0); result.a = (x.a >= 0.0) ? x.a : (exp(x.a) - 1.0); return result; `,xq=Qe({opSnippet:mq,packedOpSnippet:gq}),Aq={kernelName:hi,backendName:"webgl",kernelFunc:xq},yq="return (b >= 1.0) ? a : a * (b + 1.0);",bq=` vec4 bGTEZero = vec4(greaterThanEqual(b, vec4(0.))); return (bGTEZero * a) + ((vec4(1.0) - bGTEZero) * (a * (b + vec4(1.0)))); `,vq=e=>{let{inputs:t,backend:a}=e,{dy:n,y:r}=t,s=W().getBool("WEBGL_PACK_BINARY_OPERATIONS")?new cp(bq,n.shape,r.shape):new Al(yq,n.shape,r.shape);return a.runWebGLProgram(s,[n,r],n.dtype)},wq={kernelName:j1,backendName:"webgl",kernelFunc:vq},kq=` return vec4(equal(a, b)); `,Iq="return float(a == b);",Sq=oa({opSnippet:Iq,packedOpSnippet:kq,dtype:"bool",cpuKernelImpl:lU}),Tq={kernelName:fi,backendName:"webgl",kernelFunc:Sq},Cq=` // Error function is calculated approximately with elementary function. // See "Handbook of Mathematical Functions with Formulas, // Graphs, and Mathematical Tables", Abramowitz and Stegun. float p = ${T.ERF_P}; float a1 = ${T.ERF_A1}; float a2 = ${T.ERF_A2}; float a3 = ${T.ERF_A3}; float a4 = ${T.ERF_A4}; float a5 = ${T.ERF_A5}; float sign = sign(x); x = abs(x); float t = 1.0 / (1.0 + p * x); return sign * (1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*exp(-x*x)); `,Nq=Qe({opSnippet:Cq}),Eq={kernelName:$l,backendName:"webgl",kernelFunc:Nq},Rq=mu+` return exp(x); `,Mq=` vec4 result = exp(x); bvec4 isNaN = isnan(x); result.r = isNaN.r ? x.r : result.r; result.g = isNaN.g ? x.g : result.g; result.b = isNaN.b ? x.b : result.b; result.a = isNaN.a ? x.a : result.a; return result; `,uv=Qe({opSnippet:Rq,packedOpSnippet:Mq,cpuKernelImpl:uU,dtype:"float32"}),$q={kernelName:mi,backendName:"webgl",kernelFunc:uv};function N1(e){let{inputs:t,attrs:a,backend:n}=e,{dim:r}=a,{input:s}=t,i=s.shape.length,o=s.shape.slice(),l=r;return r<0&&(v.assert(-(i+1)<=r,()=>`Axis must be in the interval [${-(i+1)}, ${i}]`),l=i+r+1),o.splice(l,0,1),ce({inputs:{x:s},backend:n,attrs:{shape:o}})}var _q={kernelName:_l,backendName:"webgl",kernelFunc:N1},Ex="return exp(x) - 1.0;",Pq=Qe({opSnippet:Ex,packedOpSnippet:Ex,cpuKernelImpl:dU}),Fq={kernelName:Pl,backendName:"webgl",kernelFunc:Pq},Rx=class{constructor(e,t,a){this.variableNames=["real","imag"];let n=t[1];this.outputShape=t;let r=a?`2.0 * ${Math.PI}`:`-2.0 * ${Math.PI}`,s=a?`${n}.0`:"1.0",i;if(e==="real")i="return real * expR - imag * expI;";else if(e==="imag")i="return real * expI + imag * expR;";else throw new Error(`FFT component must be either "real" or "imag", got ${e}.`);this.userCode=` const float exponentMultiplier = ${r}; float unaryOpComplex(float real, float expR, float imag, float expI) { ${i} } float mulMatDFT(int batch, int index) { float indexRatio = float(index) / float(${n}); float exponentMultiplierTimesIndexRatio = exponentMultiplier * indexRatio; float result = 0.0; for (int i = 0; i < ${n}; i++) { // x = (-2|2 * PI / N) * index * i; float x = exponentMultiplierTimesIndexRatio * float(i); float expR = cos(x); float expI = sin(x); float real = getReal(batch, i); float imag = getImag(batch, i); result += unaryOpComplex(real, expR, imag, expI) / ${s}; } return result; } void main() { ivec2 coords = getOutputCoords(); setOutput(mulMatDFT(coords[0], coords[1])); } `}};function dv(e,t,a){let n=a.texData.get(e.dataId),r=v.sizeFromShape(e.shape),s=e.shape[e.shape.length-1],i=r/s,o=ce({inputs:{x:e},backend:a,attrs:{shape:[i,s]}}),l=o.shape,u=new Rx("real",l,t),p=new Rx("imag",l,t),c=[{dataId:n.complexTensorInfos.real.dataId,dtype:n.complexTensorInfos.real.dtype,shape:l},{dataId:n.complexTensorInfos.imag.dataId,dtype:n.complexTensorInfos.imag.dtype,shape:l}],d=a.runWebGLProgram(u,c,"float32"),h=a.runWebGLProgram(p,c,"float32"),f=ls({inputs:{real:d,imag:h},backend:a});a.disposeIntermediateTensorInfo(d),a.disposeIntermediateTensorInfo(h);let m=ce({inputs:{x:f},backend:a,attrs:{shape:e.shape}});return a.disposeIntermediateTensorInfo(o),a.disposeIntermediateTensorInfo(f),m}function Oq(e){let{inputs:t,backend:a}=e,{input:n}=t;return dv(n,!1,a)}var Dq={kernelName:Nd,backendName:"webgl",kernelFunc:Oq},zq=class{constructor(e,t){this.outputShape=[],this.customUniforms=[{name:"value",type:"float"}],this.variableNames=["x"],this.outputShape=e,this.userCode=` void main() { // Input can be obtained from uniform value. setOutput(value); } `}};function fp(e){let{backend:t,attrs:a}=e,{shape:n,value:r}=a,{dtype:s}=a;if(s=s||v.inferDtype(r),s==="string"){let i=v.getArrayFromDType(s,v.sizeFromShape(n));return i.fill(r),t.makeTensorInfo(n,s,i)}else{let i=new zq(n,r),o=[[r]];return t.runWebGLProgram(i,[],s,o)}}var Lq={kernelName:Fl,backendName:"webgl",kernelFunc:fp},Bq=class{constructor(e){this.variableNames=["Image"],this.outputShape=[];let t=e[2];this.outputShape=e,this.userCode=` void main() { ivec4 coords = getOutputCoords(); int x = coords[2]; int coordX = ${t} - x - 1; float outputValue; if(coordX >= 0 && coordX < ${t}) { outputValue = getImage(coords[0], coords[1], coordX, coords[3]); } else { outputValue = getImage(coords[0], coords[1], coords[2], coords[3]); } setOutput(outputValue); } `}},Wq={kernelName:gi,backendName:"webgl",kernelFunc:({inputs:e,backend:t})=>{let{image:a}=e,n=t,r=new Bq(a.shape);return n.runWebGLProgram(r,[a],a.dtype)}},Mx="return floor(x);",Vq=Qe({opSnippet:Mx,packedOpSnippet:Mx,cpuKernelImpl:pU}),Uq={kernelName:xi,backendName:"webgl",kernelFunc:Vq},Gq=` float s = sign(a) * sign(b); int ia = round(a); int ib = round(b); if (ib != 0) { // Windows (D3D) wants guaranteed non-zero int division at compile-time. return float(idiv(ia, ib, s)); } else { return NAN; } `,Hq=` ivec4 ia = round(a); ivec4 ib = round(b); bvec4 cond = notEqual(ib, ivec4(0)); ivec4 result = ivec4(0); vec4 s = sign(a) * sign(b); // Windows (D3D) wants guaranteed non-zero int division at compile-time. if (cond[0]) { result[0] = idiv(ia[0], ib[0], s[0]); } if (cond[1]) { result[1] = idiv(ia[1], ib[1], s[1]); } if (cond[2]) { result[2] = idiv(ia[2], ib[2], s[2]); } if (cond[3]) { result[3] = idiv(ia[3], ib[3], s[3]); } return vec4(result); `,jq=oa({opSnippet:Gq,packedOpSnippet:Hq,dtype:"int32"}),qq={kernelName:Ai,backendName:"webgl",kernelFunc:jq},Xq=class{constructor(e){this.variableNames=["A"];let t=Ca(),[a,n]=e;this.outputShape=e,this.userCode=` void main() { ivec3 coords = getOutputCoords(); int texR = coords[0]; int texC = coords[1]; int depth = coords[2]; vec2 uv = (vec2(texC, texR) + halfCR) / vec2(${n}.0, ${a}.0); vec4 values = ${t.texture2D}(A, uv); float value; if (depth == 0) { value = values.r; } else if (depth == 1) { value = values.g; } else if (depth == 2) { value = values.b; } else if (depth == 3) { value = values.a; } setOutput(floor(value * 255.0 + 0.5)); } `}},Kq=class{constructor(e){this.variableNames=["A"],this.packedInputs=!1,this.packedOutput=!0;let t=Ca(),[a,n]=e;this.outputShape=e,this.userCode=` void main() { ivec3 coords = getOutputCoords(); int texR = coords[0]; int texC = coords[1]; int depth = coords[2]; vec4 result = vec4(0.); for(int row=0; row<=1; row++) { for(int col=0; col<=1; col++) { texC = coords[1] + row; depth = coords[2] + col; vec2 uv = (vec2(texC, texR) + halfCR) / vec2(${n}.0, ${a}.0); vec4 values = ${t.texture2D}(A, uv); float value; if (depth == 0) { value = values.r; } else if (depth == 1) { value = values.g; } else if (depth == 2) { value = values.b; } else if (depth == 3) { value = values.a; } result[row * 2 + col] = floor(value * 255.0 + 0.5); } } ${t.output} = result; } `}},Zq={kernelName:rd,backendName:"webgl",kernelFunc:Yq},Zo,Lm=W().getBool("CANVAS2D_WILL_READ_FREQUENTLY_FOR_GPU");function Yq(e){let{inputs:t,backend:a,attrs:n}=e,{pixels:r}=t,{numChannels:s}=n,i=typeof HTMLVideoElement!="undefined"&&r instanceof HTMLVideoElement,o=typeof HTMLImageElement!="undefined"&&r instanceof HTMLImageElement,[l,u]=i?[r.videoWidth,r.videoHeight]:[r.width,r.height],p=[u,l],c=[u,l,s];if(o||i){let m=W().getBool("CANVAS2D_WILL_READ_FREQUENTLY_FOR_GPU");(Zo==null||m!==Lm)&&(Lm=m,Zo=document.createElement("canvas").getContext("2d",{willReadFrequently:Lm})),Zo.canvas.width=l,Zo.canvas.height=u,Zo.drawImage(r,0,0,l,u),r=Zo.canvas}let d=a.makeTensorInfo(p,"int32");a.texData.get(d.dataId).usage=pn.PIXELS,a.gpgpu.uploadPixelDataToTexture(a.getTexture(d.dataId),r);let h=W().getBool("WEBGL_PACK")?new Kq(c):new Xq(c),f=a.runWebGLProgram(h,[d],"int32");return a.disposeData(d.dataId),f}function Jq(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,filter:s,bias:i,preluActivationWeights:o}=t,{strides:l,pad:u,dataFormat:p,dilations:c,dimRoundingMode:d,activation:h,leakyreluAlpha:f}=n,m=T.convertConv2DDataFormat(p),g=T.computeConv2DInfo(r.shape,s.shape,l,c,u,d,!1,m),x,A=[],y=i!=null,b=o!=null,w=h==="leakyrelu",S=()=>{let E=[r,s],_=($,M)=>{if(M==="NCHW"&&$.shape.length===1&&$.shape[0]!==1){let I=ce({inputs:{x:$},backend:a,attrs:{shape:[$.shape[0],1,1]}});return A.push(I),I}return $};if(y&&E.push(_(i,p)),b&&E.push(_(o,p)),w){let $=a.makeTensorInfo([],"float32",v.createScalarValue(f,"float32"));E.push($),A.push($)}return E};if(g.filterHeight===1&&g.filterWidth===1&&g.dilationHeight===1&&g.dilationWidth===1&&g.strideHeight===1&&g.strideWidth===1&&(g.padInfo.type==="SAME"||g.padInfo.type==="VALID"))x=rv({x:r,filter:s,convInfo:g,backend:a,bias:i,activation:h,preluActivationWeights:o,leakyreluAlpha:f});else if(g.strideWidth<=2&&m==="channelsLast"&&W().getBool("WEBGL_EXP_CONV")){let E=h?gd(h,!0):null,_=new nv(g,y,E,b,w),$=[[g.padInfo.top,g.padInfo.left],[g.strideHeight,g.strideWidth],[g.dilationHeight,g.dilationWidth],[g.inHeight,g.inWidth]],M=S();x=a.runWebGLProgram(_,M,"float32",$)}else if(W().getBool("WEBGL_CONV_IM2COL"))x=sv({x:r,filter:s,convInfo:g,backend:a,bias:i,activation:h,preluActivationWeights:o,leakyreluAlpha:f});else{let E=h?gd(h,!1):null,_=new av(g,y,E,b,w),$=S();x=a.runWebGLProgram(_,$,"float32")}let C=ce({inputs:{x},backend:a,attrs:{shape:g.outShape}});return A.push(x),A.forEach(E=>a.disposeIntermediateTensorInfo(E)),C}var Qq={kernelName:qr,backendName:"webgl",kernelFunc:Jq};function eX(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,filter:s,bias:i,preluActivationWeights:o}=t,{strides:l,pad:u,dilations:p,dimRoundingMode:c,activation:d,leakyreluAlpha:h}=n,f=[],m=p;m==null&&(m=[1,1]),v.assert(T.eitherStridesOrDilationsAreOne(l,m),()=>`Error in depthwiseConv2d: Either strides or dilations must be 1. Got strides ${l} and dilations '${m}'`);let g=T.computeConv2DInfo(r.shape,s.shape,l,m,u,c,!0),x=W().getBool("WEBGL_PACK_DEPTHWISECONV")&&g.strideWidth<=2&&g.outChannels/g.inChannels===1,A=d?gd(d,x):null,y=[r,s],b=i!=null,w=o!=null,S=d==="leakyrelu";if(b&&y.push(i),w&&y.push(o),S){let $=a.makeTensorInfo([],"float32",v.createScalarValue(h,"float32"));y.push($),f.push($)}let C;x?C=new lv(g,b,A,w,S):C=new ov(g,b,A,w,S);let E=[[g.padInfo.top,g.padInfo.left],[g.strideHeight,g.strideWidth],[g.dilationHeight,g.dilationWidth],[g.inHeight,g.inWidth]],_=a.runWebGLProgram(C,y,"float32",E);return f.forEach($=>a.disposeIntermediateTensorInfo($)),_}var tX={kernelName:Xr,backendName:"webgl",kernelFunc:eX},aX=class{constructor(e,t,a,n){this.sliceDim=e,this.strides=t,this.paramsShape=n,this.variableNames=["x","indices"],this.outputShape=a;let r=gt(a.length),s=` int index;`;for(let i=0;i= ${this.paramsShape[i]}; flattenIndex += index * ${this.strides[i]};`;this.userCode=` void main() { ${r} coords = getOutputCoords(); int flattenIndex = 0; bool out_of_bounds = false; ${s} setOutput(out_of_bounds ? 0.0 : getX(flattenIndex, coords[1])); } `}};function nX(e){let{inputs:t,backend:a}=e,{params:n,indices:r}=t,s=r.shape,i=s[s.length-1],o=v.sizeFromShape(n.shape),[l,u,p,c]=T.prepareAndValidate(n,r),d=ce({inputs:{x:r},backend:a,attrs:{shape:[u,i]}}),h=ce({inputs:{x:n},backend:a,attrs:{shape:[v.sizeFromShape(n.shape)/p,p]}});if(a.shouldExecuteOnCPU([n,r])||n.dtype==="string"){let x=a.readSync(r.dataId),A=a.bufferSync(n),y=cU(x,A,n.dtype,u,i,p,c,n.shape,o);return a.makeTensorInfo(l,n.dtype,y.values)}let f=new aX(i,c,[u,p],n.shape),m=a.runWebGLProgram(f,[h,d],h.dtype),g=ce({inputs:{x:m},backend:a,attrs:{shape:l}});return a.disposeIntermediateTensorInfo(d),a.disposeIntermediateTensorInfo(h),a.disposeIntermediateTensorInfo(m),g}var rX={kernelName:bi,backendName:"webgl",kernelFunc:nX},sX=class{constructor(e,t){this.variableNames=["A","indices"],this.outputShape=t,this.rank=t.length;let a=gt(this.rank),n=iX(e,2);this.userCode=` void main() { ${a} resRC = getOutputCoords(); int index = int(getIndices(resRC.x, resRC.z)); float inBounds = (index >= 0) && (index < ${e[2]}) ? 1.0 : 0.0; setOutput(inBounds * getA(${n})); } `}};function iX(e,t){let a=["resRC.x","resRC.y","resRC.z","resRC.w"],n=[];for(let r=0;r=0,()=>`GatherV2: the index value ${w} is not in [0, ${y-1}]`)}}let u=T.segment_util.collectGatherOpShapeInfo(r,s,l,o),p=v.sizeFromShape(s.shape),c=[],d=ce({inputs:{x:r},backend:a,attrs:{shape:[u.batchSize,u.outerSize,u.dimSize,u.sliceSize]}}),h=ce({inputs:{x:s},backend:a,attrs:{shape:[u.batchSize,p/u.batchSize]}});c.push(d),c.push(h);let f=[u.batchSize,u.outerSize,p/u.batchSize,u.sliceSize];if(a.shouldExecuteOnCPU([r,s])||r.dtype==="string"){let A=a.bufferSync(h),y=a.bufferSync(d),b=hU(y,A,f);return c.forEach(w=>a.disposeIntermediateTensorInfo(w)),a.makeTensorInfo(u.outputShape,b.dtype,b.values)}let m=new sX(d.shape,f),g=a.runWebGLProgram(m,[d,h],d.dtype);c.push(g);let x=ce({inputs:{x:g},backend:a,attrs:{shape:u.outputShape}});return c.forEach(A=>a.disposeIntermediateTensorInfo(A)),x}var oX={kernelName:Ol,backendName:"webgl",kernelFunc:pv},lX="return float(a > b);",uX=` return vec4(greaterThan(a, b)); `,dX=oa({opSnippet:lX,packedOpSnippet:uX,cpuKernelImpl:fU,dtype:"bool"}),pX={kernelName:vi,backendName:"webgl",kernelFunc:dX},cX="return float(a >= b);",hX=` return vec4(greaterThanEqual(a, b)); `,fX=oa({opSnippet:cX,packedOpSnippet:hX,dtype:"bool",cpuKernelImpl:mU}),mX={kernelName:wi,backendName:"webgl",kernelFunc:fX};function gX(e){let{inputs:t,backend:a}=e,{input:n}=t;return dv(n,!0,a)}var xX={kernelName:Ed,backendName:"webgl",kernelFunc:gX},AX="return float(!isnan(x) && !isinf(x));",yX=Qe({opSnippet:AX,dtype:"bool"}),bX={kernelName:Dl,backendName:"webgl",kernelFunc:yX},vX="return float(isinf(x));",wX=Qe({opSnippet:vX,dtype:"bool"}),kX={kernelName:zl,backendName:"webgl",kernelFunc:wX},IX="return float(isnan(x));",SX=Qe({opSnippet:IX,dtype:"bool"}),TX={kernelName:Ii,backendName:"webgl",kernelFunc:SX},CX="return float(a < b);",NX=` return vec4(lessThan(a, b)); `,EX=oa({opSnippet:CX,packedOpSnippet:NX,cpuKernelImpl:gU,dtype:"bool"}),RX={kernelName:Ti,backendName:"webgl",kernelFunc:EX},MX="return float(a <= b);",$X=` return vec4(lessThanEqual(a, b)); `,_X=oa({opSnippet:MX,packedOpSnippet:$X,cpuKernelImpl:xU,dtype:"bool"}),PX={kernelName:Ci,backendName:"webgl",kernelFunc:_X};function FX(e){let{backend:t,attrs:a}=e,{start:n,stop:r,num:s}=a,i=AU(n,r,s);return t.makeTensorInfo([i.length],"float32",i)}var OX={kernelName:th,backendName:"webgl",kernelFunc:FX},DX=mu+` return x < 0.0 ? 0./0. : log(x); `,zX=` vec4 result = log(x); bvec4 isNaN = isnan(x); result.r = isNaN.r ? x.r : (x.r < 0.0 ? 0./0. : result.r); result.g = isNaN.g ? x.g : (x.g < 0.0 ? 0./0. : result.g); result.b = isNaN.b ? x.b : (x.b < 0.0 ? 0./0. : result.b); result.a = isNaN.a ? x.a : (x.a < 0.0 ? 0./0. : result.a); return result; `,LX=Qe({opSnippet:DX,packedOpSnippet:zX,cpuKernelImpl:yU}),BX={kernelName:Ni,backendName:"webgl",kernelFunc:LX},WX=mu+` return log(1.0 + x); `,VX=Qe({opSnippet:WX}),UX={kernelName:Ll,backendName:"webgl",kernelFunc:VX},GX="return float(a >= 1.0 && b >= 1.0);",HX=` return vec4( vec4(greaterThanEqual(a, vec4(1.0))) * vec4(greaterThanEqual(b, vec4(1.0)))); `,jX=oa({opSnippet:GX,packedOpSnippet:HX,dtype:"bool"}),qX={kernelName:Ei,backendName:"webgl",kernelFunc:jX},XX="return float(!(x >= 1.0));",KX=Qe({opSnippet:XX}),ZX={kernelName:Ri,backendName:"webgl",kernelFunc:KX},YX="return float(a >= 1.0 || b >= 1.0);",JX=` return min( vec4(greaterThanEqual(a, vec4(1.0))) + vec4(greaterThanEqual(b, vec4(1.0))), vec4(1.0)); `,QX=oa({opSnippet:YX,packedOpSnippet:JX,dtype:"bool"}),eK={kernelName:Bl,backendName:"webgl",kernelFunc:QX},tK=class{constructor(e,t,a,n,r){this.variableNames=["x"],this.outputShape=[];let s=t,i=e[3]-1;this.outputShape=e;let o,l=`float(${a}) + float(${n}) * sum`;r===.5?o=`inversesqrt(${l})`:r===1?o=`1.0/(${l})`:o=`exp(log(${l}) * float(-${r}));`,this.userCode=` void main() { ivec4 coords = getOutputCoords(); int b = coords[0]; int r = coords[1]; int c = coords[2]; int d = coords[3]; float x = getX(b, r, c, d); float sum = 0.0; for (int j = -${s}; j <= ${s}; j++) { int idx = d + j; if (idx >= 0 && idx <= ${i}) { float z = getX(b, r, c, idx); sum += z * z; } } float val = x * ${o}; setOutput(val); } `}},aK=class{constructor(e,t,a,n,r){this.variableNames=["x"],this.outputShape=[],this.packedInputs=!0,this.packedOutput=!0;let s=t,i=e[3]-1;this.outputShape=e;let o,l=`float(${a}) + float(${n}) * sum`;r===.5?o=`inversesqrt(${l})`:r===1?o=`1.0/(${l})`:o=`exp(log(${l}) * float(-${r}));`,this.userCode=` void main() { ivec4 coords = getOutputCoords(); int b = coords.x; int r = coords.y; int c = coords.z; int d = coords.w; bool hasNextCol = d < ${this.outputShape[3]}; bool hasNextRow = c < ${this.outputShape[2]}; vec4 sum = vec4(0.); vec4 xFragAtOutputCoords = getX(b, r, c, d); vec4 xAtOutputCoords = vec4( getChannel(xFragAtOutputCoords, vec2(c, d)), hasNextCol ? getChannel(xFragAtOutputCoords, vec2(c, d + 1)) : 0.0, hasNextRow ? getChannel(xFragAtOutputCoords , vec2(c + 1, d)) : 0.0, (hasNextRow && hasNextCol) ? getChannel(xFragAtOutputCoords, vec2(c + 1, d + 1)) : 0.0 ); int firstChannel = d - ${s}; vec2 cache = vec2(0.); if(firstChannel >= 0){ vec4 firstChannelFrag = getX(b, r, c, firstChannel); cache.x = getChannel(firstChannelFrag, vec2(c, firstChannel)); if(hasNextRow){ cache.y = getChannel(firstChannelFrag, vec2(c + 1, firstChannel)); } } ivec2 depth = ivec2(d, d + 1); for (int j = - ${s}; j <= ${s}; j++) { ivec2 idx = depth + j; bvec2 aboveLowerBound = greaterThanEqual(idx, ivec2(0)); bvec2 belowUpperBound = lessThanEqual(idx, ivec2(${i})); bool depthInRange = aboveLowerBound.x && belowUpperBound.x; bool depthPlusOneInRange = aboveLowerBound.y && belowUpperBound.y; if(depthInRange || depthPlusOneInRange){ vec4 z = vec4(0.); vec4 xFragAtCurrentDepth; z.xz = cache.xy; if(depthPlusOneInRange && hasNextCol){ xFragAtCurrentDepth = idx.y != d ? getX(b, r, c, idx.y) : xFragAtOutputCoords; z.y = getChannel(xFragAtCurrentDepth, vec2(c, idx.y)); if(hasNextRow){ z.w = getChannel(xFragAtCurrentDepth, vec2(c + 1, idx.y)); } } cache.xy = z.yw; sum += z * z; } } vec4 result = xAtOutputCoords * ${o}; setOutput(result); } `}},nK=e=>{let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{depthRadius:s,bias:i,alpha:o,beta:l}=n,u=W().getBool("WEBGL_PACK_NORMALIZATION")?new aK(r.shape,s,i,o,l):new tK(r.shape,s,i,o,l);return a.runWebGLProgram(u,[r],r.dtype)},rK={kernelName:ah,backendName:"webgl",kernelFunc:nK},sK=class{constructor(e,t,a,n,r){this.variableNames=["inputImage","outputImage","dy"],this.outputShape=[],this.outputShape=e,this.depth=e[3],this.depthRadius=t,this.bias=a,this.alpha=n,this.beta=r,this.userCode=` void main() { ivec4 coords = getOutputCoords(); int b = coords[0]; int r = coords[1]; int c = coords[2]; float result = 0.0; for (int d = 0; d < ${this.depth}; ++d) { int depthBegin = int(max(0.0, float(d - ${t}))); int depthEnd = int(min(float(${this.depth}), float(d + ${t} + 1))); const int MIN_DEPTH_BEGIN = 0; const int MAX_DEPTH_END = ${this.depth}; float norm = 0.0; for (int k = MIN_DEPTH_BEGIN; k < MAX_DEPTH_END; ++k) { if (k < depthBegin){ continue; } else if (k >= depthBegin && k < depthEnd) { norm += getInputImage(b, r, c, k) * getInputImage(b, r, c, k); } else { break; } } norm = float(${n}) * norm + float(${a}); for(int k = MIN_DEPTH_BEGIN; k < MAX_DEPTH_END; ++k){ if (k < depthBegin){ continue; } else if (k >= depthBegin && k < depthEnd){ float dyi = -2.0 * float(${n}) * float(${r}) * getInputImage(b ,r ,c, k) * getOutputImage(b, r, c, d) / norm; if (k == d) { dyi += pow(norm, -1.0 * ${r}); } if (k == coords[3]) { dyi *= getDy(b, r, c, d); result += dyi; } } else { break; } } } setOutput(result); } `}},iK=e=>{let{inputs:t,backend:a,attrs:n}=e,{x:r,y:s,dy:i}=t,{depthRadius:o,bias:l,alpha:u,beta:p}=n,c=new sK(r.shape,o,l,u,p);return a.runWebGLProgram(c,[r,s,i],r.dtype)},oK={kernelName:q1,backendName:"webgl",kernelFunc:iK};function lK(e,t,a,n){let r=v.sizeFromShape(t),s=v.sizeFromShape(e.shape)/r,i=ce({inputs:{x:e},attrs:{shape:[s,r]},backend:n}),o=bo(i,e.dtype,"max",n),l=ce({inputs:{x:o},attrs:{shape:a},backend:n});return n.disposeIntermediateTensorInfo(i),n.disposeIntermediateTensorInfo(o),l}function cv(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{reductionIndices:s,keepDims:i}=n,o=r.shape.length,l=v.parseAxisParam(s,r.shape),u=l,p=T.getAxesPermutation(u,o),c=p!=null,d=a.shouldExecuteOnCPU([r]),h=r;if(c){if(d){let A=a.texData.get(h.dataId).values,y=new Array(o);for(let S=0;S`Error in maxPool: Either strides or dilations must be 1. Got strides ${i} and dilations '${u}'`);let p=T.computePool2DInfo(r.shape,s,i,u,o,l);if(p.filterWidth===1&&p.filterHeight===1&&v.arraysEqual(p.inShape,p.outShape))return Za({inputs:{x:r},backend:a});let c=new xd(p,"max",!1);return a.runWebGLProgram(c,[r],r.dtype)}var mK={kernelName:_i,backendName:"webgl",kernelFunc:fK};function gK(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{filterSize:s,strides:i,pad:o,dataFormat:l,dimRoundingMode:u}=n,p=[1,1,1],c=T.computePool3DInfo(r.shape,s,i,p,o,u,l),d=new $3(c,"max",!1);return a.runWebGLProgram(d,[r],r.dtype)}var xK={kernelName:nh,backendName:"webgl",kernelFunc:gK},AK=class{constructor(e){this.variableNames=["dy","maxPos"],this.outputShape=e.inShape;let t=e.strideHeight,a=e.strideWidth,n=e.dilationHeight,r=e.effectiveFilterHeight,s=e.effectiveFilterWidth,i=r-1-e.padInfo.top,o=s-1-e.padInfo.left,l=r*s-1;this.userCode=` const ivec2 pads = ivec2(${i}, ${o}); void main() { ivec4 coords = getOutputCoords(); int b = coords[0]; int d = coords[3]; ivec2 dyRCCorner = coords.yz - pads; int dyRCorner = dyRCCorner.x; int dyCCorner = dyRCCorner.y; // Convolve dy(?, ?, d) with pos mask(:, :, d) to get dx(xR, xC, d). // ? = to be determined. : = across all values in that axis. float dotProd = 0.0; for (int wR = 0; wR < ${r}; wR += ${n}) { float dyR = float(dyRCorner + wR) / ${t}.0; if (dyR < 0.0 || dyR >= ${e.outHeight}.0 || fract(dyR) > 0.0) { continue; } int idyR = int(dyR); for (int wC = 0; wC < ${s}; wC++) { float dyC = float(dyCCorner + wC) / ${a}.0; if (dyC < 0.0 || dyC >= ${e.outWidth}.0 || fract(dyC) > 0.0) { continue; } int idyC = int(dyC); float dyValue = getDy(b, idyR, idyC, d); int maxPosValue = ${l} - int(getMaxPos(b, idyR, idyC, d)); // Get the current value, check it against the value from the // position matrix. int curPosValue = wR * ${s} + wC; float mask = float(maxPosValue == curPosValue ? 1.0 : 0.0); dotProd += dyValue * mask; } } setOutput(dotProd); } `}},yK=class{constructor(e){this.variableNames=["dy","maxPos"],this.outputShape=e.inShape;let t=e.strideDepth,a=e.strideHeight,n=e.strideWidth,r=e.dilationDepth,s=e.dilationHeight,i=e.dilationWidth,o=e.effectiveFilterDepth,l=e.effectiveFilterHeight,u=e.effectiveFilterWidth,p=o-1-e.padInfo.front,c=l-1-e.padInfo.top,d=u-1-e.padInfo.left,h=o*l*u-1;this.userCode=` const ivec3 pads = ivec3(${p}, ${c}, ${d}); void main() { ivec5 coords = getOutputCoords(); int batch = coords.x; int ch = coords.u; ivec3 dyCorner = ivec3(coords.y, coords.z, coords.w) - pads; int dyDCorner = dyCorner.x; int dyRCorner = dyCorner.y; int dyCCorner = dyCorner.z; // Convolve dy(?, ?, ?, ch) with pos mask(:, :, :, d) to get // dx(xD, xR, xC, ch). // ? = to be determined. : = across all values in that axis. float dotProd = 0.0; for (int wD = 0; wD < ${o}; wD += ${r}) { float dyD = float(dyDCorner + wD) / ${t}.0; if (dyD < 0.0 || dyD >= ${e.outDepth}.0 || fract(dyD) > 0.0) { continue; } int idyD = int(dyD); for (int wR = 0; wR < ${l}; wR += ${s}) { float dyR = float(dyRCorner + wR) / ${a}.0; if (dyR < 0.0 || dyR >= ${e.outHeight}.0 || fract(dyR) > 0.0) { continue; } int idyR = int(dyR); for (int wC = 0; wC < ${u}; wC += ${i}) { float dyC = float(dyCCorner + wC) / ${n}.0; if (dyC < 0.0 || dyC >= ${e.outWidth}.0 || fract(dyC) > 0.0) { continue; } int idyC = int(dyC); float dyValue = getDy(batch, idyD, idyR, idyC, ch); int maxPosValue = ${h} - int(getMaxPos(batch, idyD, idyR, idyC, ch)); // Get the current value, check it against the value from the // position matrix. int curPosValue = wD * ${l} * ${u} + wR * ${u} + wC; float mask = float(maxPosValue == curPosValue ? 1.0 : 0.0); dotProd += dyValue * mask; } } } setOutput(dotProd); } `}};function bK(e){let{inputs:t,backend:a,attrs:n}=e,{dy:r,input:s}=t,i=s,{filterSize:o,strides:l,pad:u,dimRoundingMode:p}=n,c=[1,1,1],d=T.computePool3DInfo(i.shape,o,l,c,u,p),h=new $3(d,"max",!0),f=a.runWebGLProgram(h,[i],i.dtype),m=new yK(d),g=a.runWebGLProgram(m,[r,f],i.dtype);return a.disposeIntermediateTensorInfo(f),g}var vK={kernelName:K1,backendName:"webgl",kernelFunc:bK};function wK(e){let{inputs:t,backend:a,attrs:n}=e,{dy:r,input:s,output:i}=t,o=s;uu([s,i],"maxPoolGrad");let{filterSize:l,strides:u,pad:p,dimRoundingMode:c}=n,d=T.computePool2DInfo(o.shape,l,u,1,p,c),h=!0,f=new xd(d,"max",h),m=a.runWebGLProgram(f,[o],o.dtype),g=new AK(d),x=a.runWebGLProgram(g,[r,m],o.dtype);return a.disposeIntermediateTensorInfo(m),x}var kK={kernelName:X1,backendName:"webgl",kernelFunc:wK};function IK(e,t,a,n){let r=new xd(a,"max",!1),s=n.runWebGLProgram(r,[e],"float32");r=new xd(a,"max",!0,!0,t);let i=n.runWebGLProgram(r,[e],"float32");return[s,i]}var SK={kernelName:rh,backendName:"webgl",kernelFunc:({inputs:e,attrs:t,backend:a})=>{let{x:n}=e,{filterSize:r,strides:s,pad:i,includeBatchInIndex:o}=t,l=a;v.assert(n.shape.length===4,()=>`Error in maxPool: input must be rank 4 but got rank ${n.shape.length}.`);let u=[1,1];v.assert(T.eitherStridesOrDilationsAreOne(s,u),()=>`Error in maxPool: Either strides or dilations must be 1. Got strides ${s} and dilations '${u}'`);let p=T.computePool2DInfo(n.shape,r,s,u,i),[c,d]=IK(n,o,p,l);return[c,d]}};function TK(e,t,a,n){let r=v.sizeFromShape(t),s=v.sizeFromShape(e.shape)/r,i=ce({inputs:{x:e},attrs:{shape:[s,r]},backend:n}),o=bo(i,"float32","mean",n),l=ce({inputs:{x:o},attrs:{shape:a},backend:n});return n.disposeIntermediateTensorInfo(i),n.disposeIntermediateTensorInfo(o),l}var CK={kernelName:Pi,backendName:"webgl",kernelFunc:({inputs:e,attrs:t,backend:a})=>{let{x:n}=e,{keepDims:r,axis:s}=t,i=a,o=n.shape.length,l=v.parseAxisParam(s,n.shape),u=l,p=T.getAxesPermutation(u,o),c=p!=null,d=i.shouldExecuteOnCPU([n]),h=[],f=n;if(c){if(d){let y=i.texData.get(f.dataId).values,b=new Array(o);for(let C=0;Cu[0]+e[p]+u[1]);let n=e.length,r=gt(n),s=t.map(u=>u[0]).join(","),i=t.map((u,p)=>u[0]+e[p]).join(","),o=["coords[0]","coords[1]","coords[2]","coords[3]"].slice(0,n),l=a==="reflect"?0:1;if(n===1){this.userCode=` int start = ${s}; int end = ${i}; void main() { int outC = getOutputCoords(); if (outC < start) { outC = start * 2 - outC - ${l}; } else if(outC >= end) { outC = (end - 1) * 2 - outC + ${l}; } setOutput(getX(outC - start)); } `;return}this.userCode=` ${r} start = ${r}(${s}); ${r} end = ${r}(${i}); void main() { ${r} outC = getOutputCoords(); for (int i = 0; i < ${n}; i++) { if (outC[i] < start[i]) { outC[i] = start[i] * 2 - outC[i] - ${l}; } else if(outC[i] >= end[i]) { outC[i] = (end[i] - 1) * 2 - outC[i] + ${l}; } } ${r} coords = outC - start; setOutput(getX(${o})); } `}},FK=class{constructor(e,t,a){this.variableNames=["x"],this.packedInputs=!0,this.packedOutput=!0,this.outputShape=t.map((h,f)=>h[0]+e[f]+h[1]);let n=e.length,r=gt(n),s=t.map(h=>h[0]).join(","),i=t.map((h,f)=>h[0]+e[f]).join(","),o=va("rc",n),l=va("source",n),u=`${o[n-1]} < ${this.outputShape[n-1]}`,p=n===1?"source":`vec2(${l.slice(-2).join()})`,c=a==="reflect"?0:1,d="";if(n===1){let h=` ${r} source = rc; if (source < start) { source = start * 2 - source - ${c}; } else if (source >= end) { source = (end - 1) * 2 - source + ${c}; } source -= start; `;d=` ${r} rc = outputLoc; ${h} result[0] = getChannel(getX(${l.join()}), ${p}); ${o[n-1]} += 1; if(${u}) { ${h} result[1] = getChannel(getX(${l.join()}), ${p}); } `}else{let h=` ${r} source = rc; ${r} lt = ${r}(lessThan(source, start)); ${r} gte = ${r}(greaterThanEqual(source, end)); ${r} orig = 1 - (lt + gte); source = orig * source + lt * (start * 2 - source - ${c}) + gte * ((end - 1) * 2 - source + ${c}); source -= start; `;d=` ${r} rc = outputLoc; ${h} result[0] = getChannel(getX(${l.join()}), ${p}); ${o[n-1]} += 1; if(${u}) { ${h} result[1] = getChannel(getX(${l.join()}), ${p}); } rc = outputLoc; ${o[n-2]} += 1; if(${o[n-2]} < ${this.outputShape[n-2]}) { ${h} result[2] = getChannel(getX(${l.join()}), ${p}); ${o[n-1]} += 1; if(${u}) { ${h} result[3] = getChannel(getX(${l.join()}), ${p}); } } `}this.userCode=` const ${r} start = ${r}(${s}); const ${r} end = ${r}(${i}); void main() { ${r} outputLoc = getOutputCoords(); vec4 result = vec4(0.); ${d} setOutput(result); } `}},OK=({inputs:e,backend:t,attrs:a})=>{let{x:n}=e,{paddings:r,mode:s}=a,i=W().getBool("WEBGL_PACK_ARRAY_OPERATIONS")?new FK(n.shape,r,s):new PK(n.shape,r,s);return t.runWebGLProgram(i,[n],n.dtype)},DK={kernelName:Di,backendName:"webgl",kernelFunc:OK},zK=`if (b == 0.0) return NAN; return mod(a, b);`,LK=` vec4 result = mod(a, b); bvec4 isNaN = equal(b, vec4(0.0)); `+pp+` return result; `,BK=oa({opSnippet:zK,packedOpSnippet:LK}),WK={kernelName:Wl,backendName:"webgl",kernelFunc:BK},VK=class{constructor(e,t,a){this.variableNames=["probs"],this.customUniforms=[{name:"seed",type:"float"}],this.outputShape=[e,a],this.userCode=` void main() { ivec2 coords = getOutputCoords(); int batch = coords[0]; float r = random(seed); float cdf = 0.0; for (int i = 0; i < ${t-1}; i++) { cdf += getProbs(batch, i); if (r < cdf) { setOutput(float(i)); return; } } // If no other event happened, last event happened. setOutput(float(${t-1})); } `}},UK=` if (a == b) { return 1.0; }; return a / b;`,GK=` // vec4 one = vec4(equal(a, b)); // return one + (vec4(1.0) - one) * a / b; vec4 result = a / b; if(a.x == b.x) { result.x = 1.; } if(a.y == b.y) { result.y = 1.; } if(a.z == b.z) { result.z = 1.; } if(a.w == b.w) { result.w = 1.; } return result; `,hv=oa({opSnippet:UK,packedOpSnippet:GK,checkOutOfBounds:!0}),HK={kernelName:ci,backendName:"webgl",kernelFunc:hv},$x="return a - b;",fv=oa({opSnippet:$x,packedOpSnippet:$x,supportsComplex:!0,cpuKernelImpl:VU}),jK={kernelName:lo,backendName:"webgl",kernelFunc:fv};function mv(e){let{inputs:t,backend:a,attrs:n}=e,{logits:r}=t,{dim:s}=n,i=v.parseAxisParam([s],r.shape),o=cv({inputs:{x:r},backend:a,attrs:{reductionIndices:i,keepDims:!1}}),l=T.expandShapeToKeepDim(o.shape,i),u=ce({inputs:{x:o},backend:a,attrs:{shape:l}}),p=fv({inputs:{a:r,b:u},backend:a}),c=uv({inputs:{x:p},backend:a}),d=zh({inputs:{x:c},backend:a,attrs:{axis:i,keepDims:!1}}),h=ce({inputs:{x:d},backend:a,attrs:{shape:l}}),f=hv({inputs:{a:c,b:h},backend:a});return a.disposeIntermediateTensorInfo(o),a.disposeIntermediateTensorInfo(u),a.disposeIntermediateTensorInfo(p),a.disposeIntermediateTensorInfo(c),a.disposeIntermediateTensorInfo(d),a.disposeIntermediateTensorInfo(h),f}var qK={kernelName:so,backendName:"webgl",kernelFunc:mv};function XK(e){let{inputs:t,backend:a,attrs:n}=e,{logits:r}=t,{numSamples:s,seed:i,normalized:o}=n,l=o?r:mv({inputs:{logits:r},backend:a,attrs:{dim:r.shape.length-1}}),u=l.shape[0],p=l.shape[1],c=new VK(u,p,s),d=[[i]],h=a.runWebGLProgram(c,[l],"int32",d);return o||a.disposeIntermediateTensorInfo(l),h}var KK={kernelName:sh,backendName:"webgl",kernelFunc:XK},ZK=Cn+` return -x; `,YK=` vec4 result = -x; bvec4 isNaN = isnan(x); result.r = isNaN.r ? x.r : result.r; result.g = isNaN.g ? x.g : result.g; result.b = isNaN.b ? x.b : result.b; result.a = isNaN.a ? x.a : result.a; return result; `;function JK(e){let{inputs:t,backend:a}=e,{x:n}=t;if(a.shouldExecuteOnCPU([n])){let s=a.texData.get(n.dataId),[i,o]=IU(s.values,n.shape,n.dtype);return a.makeTensorInfo(o,n.dtype,i)}let r;return W().getBool("WEBGL_PACK_UNARY_OPERATIONS")?r=new Vr(n.shape,YK):r=new qn(n.shape,ZK),a.runWebGLProgram(r,[n],n.dtype)}var QK={kernelName:Vl,backendName:"webgl",kernelFunc:JK},eZ=Tn.nonMaxSuppressionV3Impl;function tZ(e){T.warn("tf.nonMaxSuppression() in webgl locks the UI thread. Call tf.nonMaxSuppressionAsync() instead");let{inputs:t,backend:a,attrs:n}=e,{boxes:r,scores:s}=t,{maxOutputSize:i,iouThreshold:o,scoreThreshold:l}=n,u=a.readSync(r.dataId),p=a.readSync(s.dataId),{selectedIndices:c}=eZ(u,p,i,o,l);return a.makeTensorInfo([c.length],"int32",new Int32Array(c))}var aZ={kernelName:Bi,backendName:"webgl",kernelFunc:tZ},nZ=Tn.nonMaxSuppressionV4Impl;function rZ(e){T.warn("tf.nonMaxSuppression() in webgl locks the UI thread. Call tf.nonMaxSuppressionAsync() instead");let{inputs:t,backend:a,attrs:n}=e,{boxes:r,scores:s}=t,{maxOutputSize:i,iouThreshold:o,scoreThreshold:l,padToMaxOutputSize:u}=n,p=a.readSync(r.dataId),c=a.readSync(s.dataId),{selectedIndices:d,validOutputs:h}=nZ(p,c,i,o,l,u);return[a.makeTensorInfo([d.length],"int32",new Int32Array(d)),a.makeTensorInfo([],"int32",new Int32Array([h]))]}var sZ={kernelName:Ul,backendName:"webgl",kernelFunc:rZ},iZ=Tn.nonMaxSuppressionV5Impl;function oZ(e){T.warn("tf.nonMaxSuppression() in webgl locks the UI thread. Call tf.nonMaxSuppressionAsync() instead");let{inputs:t,backend:a,attrs:n}=e,{boxes:r,scores:s}=t,{maxOutputSize:i,iouThreshold:o,scoreThreshold:l,softNmsSigma:u}=n,p=a.readSync(r.dataId),c=a.readSync(s.dataId),d=i,h=o,f=l,m=u,{selectedIndices:g,selectedScores:x}=iZ(p,c,d,h,f,m);return[a.makeTensorInfo([g.length],"int32",new Int32Array(g)),a.makeTensorInfo([x.length],"float32",new Float32Array(x))]}var lZ={kernelName:Wi,backendName:"webgl",kernelFunc:oZ},uZ=class{constructor(e,t,a,n){this.variableNames=["indices"],this.outputShape=[e,t],this.userCode=` void main() { ivec2 coords = getOutputCoords(); int index = round(getIndices(coords.x)); setOutput(mix(float(${n}), float(${a}), float(index == coords.y))); } `}},dZ=e=>{let{inputs:t,backend:a,attrs:n}=e,{indices:r}=t,{dtype:s,depth:i,onValue:o,offValue:l}=n,u=v.sizeFromShape(r.shape),p=new uZ(u,i,o,l),c=ce({inputs:{x:r},backend:a,attrs:{shape:[u]}}),d=a.runWebGLProgram(p,[c],s);a.disposeIntermediateTensorInfo(c);let h=[...r.shape,i],f=ce({inputs:{x:d},backend:a,attrs:{shape:h}});return a.disposeIntermediateTensorInfo(d),f},pZ={kernelName:Vi,backendName:"webgl",kernelFunc:dZ};function Lc(e){let{inputs:t,backend:a}=e,{x:n}=t;if(n.dtype==="complex64"){let r=hp({inputs:{input:n},backend:a}),s=Lc({inputs:{x:r},backend:a}),i=Lh({inputs:{input:n},backend:a}),o=Lc({inputs:{x:i},backend:a}),l=ls({inputs:{real:s,imag:o},backend:a});return a.disposeIntermediateTensorInfo(r),a.disposeIntermediateTensorInfo(s),a.disposeIntermediateTensorInfo(i),a.disposeIntermediateTensorInfo(o),l}else return fp({attrs:{shape:n.shape,dtype:n.dtype,value:n.dtype==="string"?"":0},backend:a})}var cZ={kernelName:nu,backendName:"webgl",kernelFunc:Lc};function gv(e){let{inputs:t,backend:a}=e,{x:n}=t;if(n.dtype==="string")throw new Error("onesLike is not supported under string dtype");if(n.dtype==="complex64"){let r=hp({inputs:{input:n},backend:a}),s=gv({inputs:{x:r},backend:a}),i=Lh({inputs:{input:n},backend:a}),o=Lc({inputs:{x:i},backend:a}),l=ls({inputs:{real:s,imag:o},backend:a});return a.disposeIntermediateTensorInfo(r),a.disposeIntermediateTensorInfo(s),a.disposeIntermediateTensorInfo(i),a.disposeIntermediateTensorInfo(o),l}else return fp({attrs:{shape:n.shape,dtype:n.dtype,value:1},backend:a})}var hZ={kernelName:Gl,backendName:"webgl",kernelFunc:gv};function fZ(e){let{inputs:t,backend:a,attrs:n}=e,{axis:r}=n;if(t.length===1)return N1({inputs:{input:t[0]},backend:a,attrs:{dim:r}});let s=t[0].shape,i=t[0].dtype;t.forEach(p=>{v.assertShapesMatch(s,p.shape,"All tensors passed to stack must have matching shapes"),v.assert(i===p.dtype,()=>"All tensors passed to stack must have matching dtypes")});let o=[],l=t.map(p=>{let c=N1({inputs:{input:p},backend:a,attrs:{dim:r}});return o.push(c),c}),u=tv({inputs:l,backend:a,attrs:{axis:r}});return o.forEach(p=>a.disposeIntermediateTensorInfo(p)),u}var mZ={kernelName:Hl,backendName:"webgl",kernelFunc:fZ},gZ=class{constructor(e,t,a){this.variableNames=["x"],this.customUniforms=[{name:"value",type:"float"}],this.outputShape=t.map((l,u)=>l[0]+e[u]+l[1]);let n=e.length,r=gt(n),s=t.map(l=>l[0]).join(","),i=t.map((l,u)=>l[0]+e[u]).join(","),o=["coords[0]","coords[1]","coords[2]","coords[3]"].slice(0,n);if(n===1){this.userCode=` int start = ${s}; int end = ${i}; void main() { int outC = getOutputCoords(); if (outC < start || outC >= end) { setOutput(value); } else { setOutput(getX(outC - start)); } } `;return}this.userCode=` ${r} start = ${r}(${s}); ${r} end = ${r}(${i}); void main() { ${r} outC = getOutputCoords(); if (any(lessThan(outC, start)) || any(greaterThanEqual(outC, end))) { setOutput(value); } else { ${r} coords = outC - start; setOutput(getX(${o})); } } `}},xZ=class{constructor(e,t,a){this.variableNames=["x"],this.packedInputs=!0,this.packedOutput=!0,this.customUniforms=[{name:"value",type:"float"}],this.outputShape=t.map((f,m)=>f[0]+e[m]+f[1]);let n=e.length,r=gt(n),s=t.map(f=>f[0]).join(","),i=t.map((f,m)=>f[0]+e[m]).join(","),o=va("rc",n),l=va("source",n),u=`${o[n-1]} < ${this.outputShape[n-1]}`,p=n===1?"source":`vec2(${l.slice(-2).join()})`,c=[`${r} rc = outputLoc;`,`${o[n-1]} += 1; if(${u}) { `,n===1?"":`} rc = outputLoc; ${o[n-2]} += 1; if(${o[n-2]} < ${this.outputShape[n-2]}) {`,n===1?"":` ${o[n-1]} += 1; if(${u}) {`],d=n===1?"rc < start || rc >= end":"any(lessThan(rc, start)) || any(greaterThanEqual(rc, end))",h="";for(let f=0,m=n===1?2:4;f{let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{paddings:s,constantValue:i}=n;if(v.sizeFromShape(r.shape)===0){let u=s.map((p,c)=>p[0]+r.shape[c]+p[1]);return fp({backend:a,attrs:{shape:u,value:i,dtype:r.dtype}})}let o=W().getBool("WEBGL_PACK_ARRAY_OPERATIONS")?new xZ(r.shape,s,i):new gZ(r.shape,s,i),l=[[i]];return a.runWebGLProgram(o,[r],r.dtype,l)},AZ={kernelName:Ui,backendName:"webgl",kernelFunc:xv},yZ=` if(a < 0.0 && floor(b) < b){ return NAN; } if (b == 0.0) { return 1.0; } return (round(mod(b, 2.0)) != 1) ? pow(abs(a), b) : sign(a) * pow(abs(a), b); `,bZ=` // isModRound1 has 1 for components with round(mod(b, 2.0)) == 1, 0 otherwise. vec4 isModRound1 = vec4(equal(round(mod(b, 2.0)), ivec4(1))); vec4 multiplier = sign(a) * isModRound1 + (vec4(1.0) - isModRound1); vec4 result = multiplier * pow(abs(a), b); // Ensure that a^0 = 1, including 0^0 = 1 as this correspond to TF and JS bvec4 isExpZero = equal(b, vec4(0.0)); result.r = isExpZero.r ? 1.0 : result.r; result.g = isExpZero.g ? 1.0 : result.g; result.b = isExpZero.b ? 1.0 : result.b; result.a = isExpZero.a ? 1.0 : result.a; bvec4 isNaN1 = lessThan(a, vec4(0.0)); bvec4 isNaN2 = lessThan(floor(b), b); bvec4 isNaN = bvec4(isNaN1.x && isNaN2.x, isNaN1.y && isNaN2.y, isNaN1.z && isNaN2.z, isNaN1.w && isNaN2.w); `+pp+` return result; `,vZ=oa({opSnippet:yZ,packedOpSnippet:bZ}),wZ={kernelName:Gi,backendName:"webgl",kernelFunc:vZ};function kZ(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,keepDims:i}=n,o=r.shape.length,l=[],u=v.parseAxisParam(s,r.shape),p=u,c=T.getAxesPermutation(p,o),d=r;c!=null&&(d=Ia({inputs:{x:r},backend:a,attrs:{perm:c}}),p=T.getInnerMostAxes(p.length,o),l.push(d)),T.assertAxesAreInnerMostDims("prod",p,o);let h;if(a.shouldExecuteOnCPU([d])){let f=a.texData.get(d.dataId).values,{outVals:m,outShape:g,outDtype:x}=TU(d.shape,d.dtype,f,p);h=a.makeTensorInfo(g,x,m)}else{let[f,m]=T.computeOutAndReduceShapes(d.shape,p),g=v.sizeFromShape(m),x=ce({inputs:{x:d},backend:a,attrs:{shape:[-1,g]}}),A=Hd(r.dtype),y=bo(x,A,"prod",a);h=ce({inputs:{x:y},backend:a,attrs:{shape:f}}),l.push(x),l.push(y)}if(i){l.push(h);let f=T.expandShapeToKeepDim(h.shape,u);h=ce({inputs:{x:h},backend:a,attrs:{shape:f}})}return l.forEach(f=>a.disposeIntermediateTensorInfo(f)),h}var IZ={kernelName:ji,backendName:"webgl",kernelFunc:kZ};function SZ(e){let{inputs:t,backend:a,attrs:n}=e,{paramsNestedSplits:r,paramsDenseValues:s,indices:i}=t,{outputRaggedRank:o}=n,l=r.map(x=>a.readSync(x.dataId)),u=r.map(x=>x.shape),p=a.readSync(s.dataId),c=a.readSync(i.dataId),[d,h,f]=CU(l,u,p,s.shape,s.dtype,c,i.shape,o),m=d.map(x=>a.makeTensorInfo([x.length],"int32",x)),g=a.makeTensorInfo(f,s.dtype,h);return m.concat([g])}var TZ={kernelName:ih,backendName:"webgl",kernelFunc:SZ};function CZ(e){let{inputs:t,backend:a}=e,{starts:n,limits:r,deltas:s}=t,i=a.readSync(n.dataId),o=a.readSync(r.dataId),l=a.readSync(s.dataId),[u,p]=NU(i,n.shape,n.dtype,o,r.shape,l,s.shape),c=a.makeTensorInfo([u.length],"int32",u),d=a.makeTensorInfo([p.length],n.dtype,p);return[c,d]}var NZ={kernelName:oh,backendName:"webgl",kernelFunc:CZ};function EZ(e){let{inputs:t,backend:a,attrs:n}=e,{shape:r,values:s,defaultValue:i,rowPartitionTensors:o}=t,{rowPartitionTypes:l}=n,u=a.readSync(r.dataId),p=a.readSync(s.dataId),c=a.readSync(i.dataId),d=o.map(g=>a.readSync(g.dataId)),h=o.map(g=>g.shape),[f,m]=EU(u,r.shape,p,s.shape,s.dtype,c,i.shape,d,h,l);return a.makeTensorInfo(f,s.dtype,m)}var RZ={kernelName:lh,backendName:"webgl",kernelFunc:EZ},Av=e=>{let{backend:t,attrs:a}=e,{start:n,stop:r,step:s,dtype:i}=a,o=RU(n,r,s,i);return t.makeTensorInfo([o.length],i,o)},MZ={kernelName:jl,backendName:"webgl",kernelFunc:Av},$Z="return 1.0 / x;",_Z=Qe({opSnippet:$Z}),PZ={kernelName:qi,backendName:"webgl",kernelFunc:_Z},FZ=Cn+` return (x < 0.0) ? 0.0 : x; `,OZ=` vec4 result = x * vec4(greaterThanEqual(x, vec4(0.0))); bvec4 isNaN = isnan(x); result.r = isNaN.r ? x.r : result.r; result.g = isNaN.g ? x.g : result.g; result.b = isNaN.b ? x.b : result.b; result.a = isNaN.a ? x.a : result.a; return result; `,DZ=Qe({opSnippet:FZ,packedOpSnippet:OZ}),zZ={kernelName:Xi,backendName:"webgl",kernelFunc:DZ},LZ=Cn+` return (x < 0.0) ? 0.0 : min(6.0, x); `,BZ=` vec4 result = min(x, vec4(6.)) * vec4(greaterThanEqual(x, vec4(0.0))); bvec4 isNaN = isnan(x); result.r = isNaN.r ? x.r : result.r; result.g = isNaN.g ? x.g : result.g; result.b = isNaN.b ? x.b : result.b; result.a = isNaN.a ? x.a : result.a; return result; `,WZ=Qe({opSnippet:LZ,packedOpSnippet:BZ}),VZ={kernelName:Yi,backendName:"webgl",kernelFunc:WZ},UZ=class{constructor(e,t,a,n,r){this.variableNames=["A"],this.outputShape=[];let[s,i,o,l]=e;this.outputShape=[s,t,a,l];let u=[n&&t>1?i-1:i,n&&a>1?o-1:o],p=[n&&t>1?t-1:t,n&&a>1?a-1:a],c;r?c="(vec2(yRC) + vec2(0.5)) * effectiveInputOverOutputRatioRC - vec2(0.5)":c="vec2(yRC) * effectiveInputOverOutputRatioRC",this.userCode=` const vec2 effectiveInputOverOutputRatioRC = vec2( ${u[0]/p[0]}, ${u[1]/p[1]}); const vec2 inputShapeRC = vec2(${i}.0, ${o}.0); void main() { ivec4 coords = getOutputCoords(); int b = coords[0]; int d = coords[3]; ivec2 yRC = coords.yz; // Fractional source index. vec2 sourceFracIndexRC = ${c}; // Compute the four integer indices. ivec2 sourceFloorRC = ivec2(max(sourceFracIndexRC, vec2(0.0))); ivec2 sourceCeilRC = ivec2( min(inputShapeRC - 1.0, ceil(sourceFracIndexRC))); float topLeft = getA(b, sourceFloorRC.x, sourceFloorRC.y, d); float bottomLeft = getA(b, sourceCeilRC.x, sourceFloorRC.y, d); float topRight = getA(b, sourceFloorRC.x, sourceCeilRC.y, d); float bottomRight = getA(b, sourceCeilRC.x, sourceCeilRC.y, d); vec2 fracRC = sourceFracIndexRC - vec2(sourceFloorRC); float top = topLeft + (topRight - topLeft) * fracRC.y; float bottom = bottomLeft + (bottomRight - bottomLeft) * fracRC.y; float newValue = top + (bottom - top) * fracRC.x; setOutput(newValue); } `}},GZ=class{constructor(e,t,a,n,r){this.variableNames=["A"],this.packedInputs=!0,this.packedOutput=!0,this.outputShape=[];let[s,i,o,l]=e;this.outputShape=[s,t,a,l];let u=[n&&t>1?i-1:i,n&&a>1?o-1:o],p=[n&&t>1?t-1:t,n&&a>1?a-1:a],c;r?c="(vec3(yRC) + vec3(0.5)) * effectiveInputOverOutputRatioRC - vec3(0.5)":c="vec3(yRC) * effectiveInputOverOutputRatioRC",this.userCode=` const vec3 effectiveInputOverOutputRatioRC = vec3( ${u[0]/p[0]}, ${u[1]/p[1]}, ${u[1]/p[1]}); const vec3 inputShapeRC = vec3(${i}.0, ${o}.0, ${o}.0); float getAValue(int b, int r, int c, int d) { return getChannel(getA(b, r, c, d), vec2(c, d)); } void main() { ivec4 coords = getOutputCoords(); int b = coords[0]; int d = coords[3]; // Calculate values for next column in yRC.z. ivec3 yRC = coords.yzz + ivec3(0, 0, 1); // Fractional source index. vec3 sourceFracIndexRC = ${c}; // Compute the four integer indices. ivec3 sourceFloorRC = ivec3(max(sourceFracIndexRC, vec3(0.0))); ivec3 sourceCeilRC = ivec3( min(inputShapeRC - 1.0, ceil(sourceFracIndexRC))); // Should we calculate next column and row elements in 2x2 packed cell. bool hasNextCol = d < ${l-1}; bool hasNextRow = coords.z < ${a-1}; // In parallel, construct four corners for all four components in // packed 2x2 cell. vec4 topLeft = vec4( getAValue(b, sourceFloorRC.x, sourceFloorRC.y, d), hasNextCol ? getAValue(b, sourceFloorRC.x, sourceFloorRC.y, d + 1) : 0.0, hasNextRow ? getAValue(b, sourceFloorRC.x, sourceFloorRC.z, d) : 0.0, (hasNextRow && hasNextCol) ? getAValue(b, sourceFloorRC.x, sourceFloorRC.z, d + 1) : 0.0); vec4 bottomLeft = vec4( getAValue(b, sourceCeilRC.x, sourceFloorRC.y, d), hasNextCol ? getAValue(b, sourceCeilRC.x, sourceFloorRC.y, d + 1) : 0.0, hasNextRow ? getAValue(b, sourceCeilRC.x, sourceFloorRC.z, d) : 0.0, (hasNextRow && hasNextCol) ? getAValue(b, sourceCeilRC.x, sourceFloorRC.z, d + 1) : 0.0); vec4 topRight = vec4( getAValue(b, sourceFloorRC.x, sourceCeilRC.y, d), hasNextCol ? getAValue(b, sourceFloorRC.x, sourceCeilRC.y, d + 1) : 0.0, hasNextRow ? getAValue(b, sourceFloorRC.x, sourceCeilRC.z, d) : 0.0, (hasNextRow && hasNextCol) ? getAValue(b, sourceFloorRC.x, sourceCeilRC.z, d + 1) : 0.0); vec4 bottomRight = vec4( getAValue(b, sourceCeilRC.x, sourceCeilRC.y, d), hasNextCol ? getAValue(b, sourceCeilRC.x, sourceCeilRC.y, d + 1) : 0.0, hasNextRow ? getAValue(b, sourceCeilRC.x, sourceCeilRC.z, d) : 0.0, (hasNextRow && hasNextCol) ? getAValue(b, sourceCeilRC.x, sourceCeilRC.z, d + 1) : 0.0); vec3 fracRC = sourceFracIndexRC - vec3(sourceFloorRC); vec4 top = mix(topLeft, topRight, fracRC.yyzz); vec4 bottom = mix(bottomLeft, bottomRight, fracRC.yyzz); vec4 newValue = mix(top, bottom, fracRC.x); setOutput(newValue); } `}};function HZ(e){let{inputs:t,backend:a,attrs:n}=e,{images:r}=t,{alignCorners:s,halfPixelCenters:i,size:o}=n,[l,u]=o,p=W().getBool("WEBGL_PACK_IMAGE_OPERATIONS")?new GZ(r.shape,l,u,s,i):new UZ(r.shape,l,u,s,i);return a.runWebGLProgram(p,[r],"float32")}var jZ={kernelName:Zi,backendName:"webgl",kernelFunc:HZ},qZ=class{constructor(e,t,a){this.variableNames=["dy"],this.outputShape=[],this.outputShape=t;let[,n,r]=t,[,s,i]=e,o=[a&&s>1?n-1:n,a&&i>1?r-1:r],l=[a&&s>1?s-1:s,a&&i>1?i-1:i],u=o[0]/l[0],p=o[1]/l[1],c=1/u,d=1/p,h=Math.ceil(c)*2+2,f=Math.ceil(d)*2+2;this.userCode=` void main() { ivec4 coords = getOutputCoords(); int b = coords[0]; int d = coords[3]; int r = coords[1]; int c = coords[2]; float accumulator = 0.0; const float heightScale = float(${u}); const float widthScale = float(${p}); const float invHeightScale = float(${c}); const float invWidthScale = float(${d}); const int winHeight = int(${h}); const int winWidth = int(${f}); // Compute bounds for where in dy we will look float startRLerp = floor(float(r) * invHeightScale); int startDyR = int(startRLerp - float(winHeight / 2)); float startCLerp = floor(float(c) * invWidthScale); int startDyC = int(startCLerp - float(winWidth / 2)); // Loop over dy for (int dyROffset = 0; dyROffset < winHeight; dyROffset++) { int dyR = dyROffset + startDyR; // Guard against the window exceeding the bounds of dy if (dyR < 0 || dyR >= ${s}) { continue; } for (int dyCOffset = 0; dyCOffset < winWidth; dyCOffset++) { int dyC = dyCOffset + startDyC; // Guard against the window exceeding the bounds of dy if (dyC < 0 || dyC >= ${i}) { continue; } float dxR = float(dyR) * heightScale; int topDxRIndex = int(floor(dxR)); int bottomDxRIndex = int(min(ceil(dxR), ${n-1}.0)); float dxRLerp = dxR - float(topDxRIndex); float inverseDxRLerp = 1.0 - dxRLerp; float dxC = float(dyC) * widthScale; int leftDxCIndex = int(floor(dxC)); int rightDxCIndex = int(min(ceil(dxC), ${r-1}.0)); float dxCLerp = dxC - float(leftDxCIndex); float inverseDxCLerp = 1.0 - dxCLerp; if (r == topDxRIndex && c == leftDxCIndex) { // topLeft accumulator += getDy(b, dyR, dyC, d) * inverseDxRLerp * inverseDxCLerp; } if (r == topDxRIndex && c == rightDxCIndex) { // topRight accumulator += getDy(b, dyR, dyC, d) * inverseDxRLerp * dxCLerp; } if (r == bottomDxRIndex && c == leftDxCIndex) { // bottomLeft accumulator += getDy(b, dyR, dyC, d) * dxRLerp * inverseDxCLerp; } if (r == bottomDxRIndex && c == rightDxCIndex) { // bottomRight accumulator += getDy(b, dyR, dyC, d) * dxRLerp * dxCLerp; } } } // End loop over dy setOutput(accumulator); } `}};function XZ(e){let{inputs:t,backend:a,attrs:n}=e,{images:r,dy:s}=t,{alignCorners:i}=n,o=new qZ(s.shape,r.shape,i);return a.runWebGLProgram(o,[s],s.dtype)}var KZ={kernelName:Y1,backendName:"webgl",kernelFunc:XZ},ZZ=class{constructor(e,t,a,n,r){this.variableNames=["A"],this.outputShape=[];let[s,i,o,l]=e;this.outputShape=[s,t,a,l];let u=[n&&t>1?i-1:i,n&&a>1?o-1:o],p=[n&&t>1?t-1:t,n&&a>1?a-1:a],c=n?"0.5":"0.0",d;r?d="max((vec2(yRC) + vec2(0.5)) * effectiveInputOverOutputRatioRC, vec2(0.0))":d="vec2(yRC) * effectiveInputOverOutputRatioRC",this.userCode=` const vec2 effectiveInputOverOutputRatioRC = vec2( ${u[0]/p[0]}, ${u[1]/p[1]}); const vec2 inputShapeRC = vec2(${i}.0, ${o}.0); void main() { ivec4 coords = getOutputCoords(); int b = coords[0]; int d = coords[3]; ivec2 yRC = coords.yz; // Fractional source index. vec2 sourceFracIndexRC = ${d}; // Compute the coordinators of nearest neighbor point. ivec2 sourceNearestRC = ivec2( min(inputShapeRC - 1.0, floor(sourceFracIndexRC + ${c}))); float newValue = getA(b, sourceNearestRC.x, sourceNearestRC.y, d); setOutput(newValue); } `}},YZ=class{constructor(e,t,a,n,r){this.variableNames=["A"],this.packedInputs=!0,this.packedOutput=!0,this.outputShape=[];let[s,i,o,l]=e;this.outputShape=[s,t,a,l];let u=[n&&t>1?i-1:i,n&&a>1?o-1:o],p=[n&&t>1?t-1:t,n&&a>1?a-1:a],c=n?"0.5":"0.0",d;r?d="max((vec3(yRC) + vec3(0.5)) * effectiveInputOverOutputRatioRC, vec3(0.0))":d="vec3(yRC) * effectiveInputOverOutputRatioRC",this.userCode=` const vec3 effectiveInputOverOutputRatioRC = vec3( ${u[0]/p[0]}, ${u[1]/p[1]}, ${u[1]/p[1]}); const vec3 inputShapeRC = vec3(${i}.0, ${o}.0, ${o}.0); float getAValue(int b, int r, int c, int d) { return getChannel(getA(b, r, c, d), vec2(c, d)); } void main() { ivec4 coords = getOutputCoords(); int b = coords[0]; int d = coords[3]; // Calculate values for next column in yRC.z. ivec3 yRC = coords.yzz + ivec3(0, 0, 1); // Fractional source index. vec3 sourceFracIndexRC = ${d}; // Compute the coordinators of nearest neighbor point. ivec3 sourceNearestRC = ivec3( min(inputShapeRC - 1.0, floor(sourceFracIndexRC + ${c}))); // Should we calculate next column and row elements in 2x2 packed cell. bool hasNextCol = d < ${l-1}; bool hasNextRow = coords.z < ${a-1}; vec4 newValue = vec4( getAValue(b, sourceNearestRC.x, sourceNearestRC.y, d), hasNextCol ? getAValue(b, sourceNearestRC.x, sourceNearestRC.y, d + 1) : 0.0, hasNextRow ? getAValue(b, sourceNearestRC.x, sourceNearestRC.z, d) : 0.0, (hasNextRow && hasNextCol) ? getAValue(b, sourceNearestRC.x, sourceNearestRC.z, d + 1) : 0.0); setOutput(newValue); } `}};function JZ(e){let{inputs:t,backend:a,attrs:n}=e,{images:r}=t,{alignCorners:s,halfPixelCenters:i,size:o}=n,[l,u]=o,p=W().getBool("WEBGL_PACK_IMAGE_OPERATIONS")?new YZ(r.shape,l,u,s,i):new ZZ(r.shape,l,u,s,i);return a.runWebGLProgram(p,[r],r.dtype)}var QZ={kernelName:Ki,backendName:"webgl",kernelFunc:JZ},eY=class{constructor(e,t,a){this.variableNames=["dy"],this.outputShape=[],this.outputShape=t;let[,n,r]=t,[,s,i]=e,o=[a&&s>1?n-1:n,a&&i>1?r-1:r],l=[a&&s>1?s-1:s,a&&i>1?i-1:i],u=o[0]/l[0],p=o[1]/l[1],c=1/u,d=1/p,h=Math.ceil(c)*2+2,f=Math.ceil(d)*2+2;this.userCode=` void main() { ivec4 coords = getOutputCoords(); int b = coords[0]; int d = coords[3]; int r = coords[1]; int c = coords[2]; float accumulator = 0.0; const float heightScale = float(${u}); const float widthScale = float(${p}); const float invHeightScale = float(${c}); const float invWidthScale = float(${d}); const int winHeight = int(${h}); const int winWidth = int(${f}); // Compute bounds for where in dy we will look float startRLerp = floor(float(r) * invHeightScale); int startDyR = int(floor(startRLerp - float(winHeight / 2))); float startCLerp = floor(float(c) * invWidthScale); int startDyC = int(floor(startCLerp - float(winWidth / 2))); // Loop over dy for (int dyROffset = 0; dyROffset < winHeight; dyROffset++) { int dyR = dyROffset + startDyR; // Guard against the window exceeding the bounds of dy if (dyR < 0 || dyR >= ${s}) { continue; } for (int dyCOffset = 0; dyCOffset < winWidth; dyCOffset++) { int dyC = dyCOffset + startDyC; // Guard against the window exceeding the bounds of dy if (dyC < 0 || dyC >= ${i}) { continue; } float sourceFracRow = float(${o[0]}) * (float(dyR) / float(${l[0]})); float sourceFracCol = float(${o[1]}) * (float(dyC) / float(${l[1]})); int sourceNearestRow = int(min( float(int(${n}) - 1), ${a} ? float(round(sourceFracRow)) : float(floor(sourceFracRow)))); int sourceNearestCol = int(min( float(int(${r}) - 1), ${a} ? float(round(sourceFracCol)) : float(floor(sourceFracCol)))); if (r == sourceNearestRow && c == sourceNearestCol) { accumulator += getDy(b, dyR, dyC, d); } } } // End loop over dy setOutput(accumulator); } `}};function tY(e){let{inputs:t,backend:a,attrs:n}=e,{images:r,dy:s}=t,{alignCorners:i}=n,o=new eY(s.shape,r.shape,i);return a.runWebGLProgram(o,[s],s.dtype)}var aY={kernelName:Z1,backendName:"webgl",kernelFunc:tY},nY=class{constructor(e,t){this.variableNames=["x"];let a=e.length;if(a>4)throw new Error(`WebGL backend: Reverse of rank-${a} tensor is not yet supported`);if(this.outputShape=e,a===1){this.userCode=` void main() { int coord = getOutputCoords(); setOutput(getX(${e[0]} - coord - 1)); } `;return}let n=i=>t.indexOf(i)!==-1&&e[i]!==1?`${e[i]} - coords[${i}] - 1`:`coords[${i}]`,r=e.map((i,o)=>n(o)).join(","),s=gt(a);this.userCode=` void main() { ${s} coords = getOutputCoords(); setOutput(getX(${r})); } `}},rY=class{constructor(e,t){this.variableNames=["x"],this.packedInputs=!0,this.packedOutput=!0;let a=e.length;if(a>4)throw new Error(`WebGL backend: Reverse of rank-${a} tensor is not yet supported`);this.outputShape=e;let n=va("rc",a),r=`${n[a-1]} + 1 < ${this.outputShape[a-1]}`,s=`${n[a-2]} + 1 < ${this.outputShape[a-2]}`,i=gt(a);a===1?this.userCode=` void main(){ int rc = getOutputCoords(); vec4 result = vec4(0.); result.r = getChannel(getX(${e[0]} - rc - 1), ${e[0]} - rc - 1); if(${r}){ result.g = getChannel(getX(${e[0]} - (rc + 1) - 1), ${e[0]} - (rc + 1) - 1); } setOutput(result); } `:this.userCode=` void main() { ${i} rc = getOutputCoords(); vec4 result = vec4(0.); result.r = ${o(n.slice())}; if(${r}){ result.g = ${l(n.slice())}; } if(${s}) { result.b = ${u(n.slice())}; if(${r}) { result.a = ${p(n.slice())}; } } setOutput(result); } `;function o(h){return c(h)}function l(h){return h[a-1]="("+h[a-1]+" + 1)",c(h)}function u(h){return h[a-2]="("+h[a-2]+" + 1)",c(h)}function p(h){return h[a-1]="("+h[a-1]+" + 1)",h[a-2]="("+h[a-2]+" + 1)",c(h)}function c(h){let f=e.map((x,A)=>d(A,h)),m=f.join(","),g=f.slice(-2).join(",");return`getChannel(getX(${m}), vec2(${g}))`}function d(h,f){return t.indexOf(h)!==-1&&e[h]!==1?`${e[h]} - ${f[h]} - 1`:`${f[h]}`}}};function sY(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{dims:s}=n,i=r.shape.length,o=v.parseAxisParam(s,r.shape);if(i===0)return Za({inputs:{x:r},backend:a});let l=W().getBool("WEBGL_PACK_ARRAY_OPERATIONS")?new rY(r.shape,o):new nY(r.shape,o);return a.runWebGLProgram(l,[r],r.dtype)}var iY={kernelName:Ji,backendName:"webgl",kernelFunc:sY},oY=class{constructor(e,t){this.variableNames=["Image"],this.outputShape=[],this.customUniforms=[{name:"params",type:"vec4"}];let a=e[1],n=e[2];this.outputShape=e;let r="";typeof t=="number"?r=`float outputValue = ${t.toFixed(2)};`:r=` vec3 fill = vec3(${t.join(",")}); float outputValue = fill[coords[3]];`,this.userCode=` void main() { ivec4 coords = getOutputCoords(); int x = coords[2]; int y = coords[1]; float coordXFloat = (float(x) - params[0]) * params[3] - (float(y) - params[1]) * params[2]; float coordYFloat = (float(x) - params[0]) * params[2] + (float(y) - params[1]) * params[3]; int coordX = int(round(coordXFloat + params[0])); int coordY = int(round(coordYFloat + params[1])); ${r} if(coordX >= 0 && coordX < ${n} && coordY >= 0 && coordY < ${a}) { outputValue = getImage(coords[0], coordY, coordX, coords[3]); } setOutput(outputValue); } `}},lY={kernelName:mo,backendName:"webgl",kernelFunc:({inputs:e,attrs:t,backend:a})=>{let{image:n}=e,{radians:r,fillValue:s,center:i}=t,o=a,l=new oY(n.shape,s),[u,p]=T.getImageCenter(i,n.shape[1],n.shape[2]),c=[[u,p,Math.sin(r),Math.cos(r)]];return o.runWebGLProgram(l,[n],n.dtype,c)}},uY=` // OpenGL ES does not support round function. // The algorithm is based on banker's rounding. float base = floor(x); if ((x - base) < 0.5) { return floor(x); } else if ((x - base) > 0.5) { return ceil(x); } else { if (mod(base, 2.0) == 0.0) { return base; } else { return base + 1.0; } } `,dY=Qe({opSnippet:uY}),pY={kernelName:Xl,backendName:"webgl",kernelFunc:dY},cY="return inversesqrt(x);",hY=Qe({opSnippet:cY,cpuKernelImpl:MU}),fY={kernelName:Qi,backendName:"webgl",kernelFunc:hY},yv=class{constructor(e,t,a,n,r,s,i=!0){this.variableNames=["updates","indices","defaultValue"],this.outputShape=s;let o=gt(r.length),l=gt(s.length),u="";a===1?u="i":a===2&&(u="i, j");let p=`getIndices(${u})`,c="";n===1?c="i":n===2&&(c="i, coords[1]");let d=`getUpdates(${c})`,h=t>1?"strides[j]":"strides";this.userCode=` ${o} strides = ${o}(${r}); void main() { ${l} coords = getOutputCoords(); float sum = 0.0; bool found = false; for (int i = 0; i < ${e}; i++) { int flattenedIndex = 0; for (int j = 0; j < ${t}; j++) { int index = round(${p}); flattenedIndex += index * ${h}; } if (flattenedIndex == coords[0]) { sum += ${d}; found = true; } } setOutput(mix(getDefaultValue(), sum, float(found))); } `}};function mY(e){let{inputs:t,backend:a,attrs:n}=e,{indices:r,updates:s}=t,{shape:i}=n,{sliceRank:o,numUpdates:l,sliceSize:u,strides:p,outputSize:c}=T.calculateShapes(s,r,i),d=[c/u,u];if(c===0)return a.makeTensorInfo(i,r.dtype);let h=ce({inputs:{x:r},backend:a,attrs:{shape:[l,o]}}),f=ce({inputs:{x:s},backend:a,attrs:{shape:[l,u]}}),m=a.makeTensorInfo([],"float32",new Float32Array([0])),g=new yv(l,o,h.shape.length,f.shape.length,p,d),x=a.runWebGLProgram(g,[f,h,m],f.dtype),A=ce({inputs:{x},backend:a,attrs:{shape:i}});return a.disposeIntermediateTensorInfo(h),a.disposeIntermediateTensorInfo(f),a.disposeIntermediateTensorInfo(x),a.disposeIntermediateTensorInfo(m),A}var gY={kernelName:eo,backendName:"webgl",kernelFunc:mY},xY=class{constructor(e,t,a,n){this.variableNames=["sortedSequence","values"],this.customUniforms=[{name:"numInputs",type:"int"}],this.outputShape=[e,a];let r="while (left < right) {",s=`for (int i = 0; i < ${Math.ceil(Math.log2(t+1))}; ++i) { if (left >= right) break;`,i=W().getNumber("WEBGL_VERSION")===2?r:s,o=n==="left"?"<":"<=";this.userCode=` int findBound(int batch, float value) { int left = 0; int right = numInputs; int mid; ${i} mid = (left + right) / 2; if (getSortedSequence(batch, mid) ${o} value) { left = mid + 1; } else { right = mid; } } return right; } void main() { ivec2 coords = getOutputCoords(); int batch = coords[0]; int valueIndex = coords[1]; float value = getValues(batch, valueIndex); setOutput(float(findBound(batch, value))); } `}};function AY(e){let{inputs:t,backend:a,attrs:n}=e,{sortedSequence:r,values:s}=t,{side:i}=n,o=new xY(r.shape[0],r.shape[1],s.shape[1],i),l=[[r.shape[1]]];return a.runWebGLProgram(o,[r,s],"int32",l)}var yY={kernelName:$d,backendName:"webgl",kernelFunc:AY},bY=class{constructor(e,t,a){this.variableNames=["c","a","b"],this.outputShape=t;let n,r;if(a>4)throw Error(`Where for rank ${a} is not yet supported`);if(a===1)r="resRC",n="resRC";else{let i=["resRC.x","resRC.y","resRC.z","resRC.w"],o=[],l=[];for(let u=0;u= 1.0) { setOutput(getA(${r})); } else { setOutput(getB(${r})); } } `}};function vY(e){let{inputs:t,backend:a}=e,{condition:n,t:r,e:s}=t,i=new bY(n.shape.length,r.shape,r.shape.length);return a.runWebGLProgram(i,[n,r,s],ca(r.dtype,s.dtype))}var wY={kernelName:Kl,backendName:"webgl",kernelFunc:vY},kY=` // Stable and Attracting Fixed Point (0, 1) for Normalized Weights. // see: https://arxiv.org/abs/1706.02515 float scaleAlpha = ${T.SELU_SCALEALPHA}; float scale = ${T.SELU_SCALE}; return (x >= 0.0) ? scale * x : scaleAlpha * (exp(x) - 1.0); `,IY=Qe({opSnippet:kY}),SY={kernelName:_d,backendName:"webgl",kernelFunc:IY},TY=mu+` return 1.0 / (1.0 + exp(-1.0 * x)); `,CY=` vec4 result = 1.0 / (1.0 + exp(-1.0 * x)); bvec4 isNaN = isnan(x); result.r = isNaN.r ? x.r : result.r; result.g = isNaN.g ? x.g : result.g; result.b = isNaN.b ? x.b : result.b; result.a = isNaN.a ? x.a : result.a; return result; `,NY=Qe({opSnippet:TY,packedOpSnippet:CY,cpuKernelImpl:_U}),EY={kernelName:ao,backendName:"webgl",kernelFunc:NY},RY=` if (isnan(x)) { return 0.0; } return sign(x); `,MY=Qe({opSnippet:RY}),$Y={kernelName:Pd,backendName:"webgl",kernelFunc:MY},_Y=mu+` return sin(x); `,PY=Qe({opSnippet:_Y}),FY={kernelName:to,backendName:"webgl",kernelFunc:PY},OY=` float e2x = exp(x); return (e2x - 1.0 / e2x) / 2.0; `,DY=Qe({opSnippet:OY}),zY={kernelName:Yl,backendName:"webgl",kernelFunc:DY},LY=` float epsilon = 1.1920928955078125e-7; float threshold = log(epsilon) + 2.0; bool too_large = x > -threshold; bool too_small = x < threshold; float result; float exp_x = exp(x); if (too_large){ result = x; } else if (too_small){ result = exp_x; } else{ result = log(exp_x + 1.0); } return result; `,BY=Qe({opSnippet:LY}),WY={kernelName:Fd,backendName:"webgl",kernelFunc:BY},VY=e=>{let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{blockShape:s,paddings:i}=n;v.assert(r.shape.length<=4,()=>"spaceToBatchND for rank > 4 with a WebGL backend not implemented yet");let o=s.reduce((x,A)=>x*A),l=[[0,0]];l.push(...i);for(let x=1+s.length;xa.disposeIntermediateTensorInfo(x)),g},UY={kernelName:Jl,backendName:"webgl",kernelFunc:VY};function GY(e){let{inputs:t,backend:a}=e,{indices:n,values:r,denseShape:s,defaultValue:i}=t;if(s.shape.length!==1)throw new Error(`Dense shape must be a vector, saw: ${s.shape}`);if(n.shape.length!==2)throw new Error(`Indices must be a matrix, saw: ${n.shape}`);if(r.shape.length!==1)throw new Error(`Values must be a vector, saw: ${r.shape}`);if(i.shape.length!==0)throw new Error(`Default value must be a scalar, saw: ${i.shape}`);let o=a.readSync(n.dataId),l=a.readSync(r.dataId),u=a.readSync(s.dataId),p=a.readSync(i.dataId)[0],[c,d,h,f,m]=FU(o,n.shape,n.dtype,l,r.dtype,u,p);return[a.makeTensorInfo(d,n.dtype,c),a.makeTensorInfo([d[0]],r.dtype,h),a.makeTensorInfo([f.length],"bool",new Uint8Array(f.map(g=>Number(g)))),a.makeTensorInfo([m.length],n.dtype,new Int32Array(m))]}var HY={kernelName:Od,backendName:"webgl",kernelFunc:GY};function jY(e){let{inputs:t,backend:a}=e,{inputIndices:n,inputShape:r,newShape:s}=t;if(n.shape.length!==2)throw new Error(`Input indices should be a matrix but received shape ${n.shape}`);if(r.shape.length!==1)throw new Error(`Input shape should be a vector but received shape ${r.shape}`);if(s.shape.length!==1)throw new Error(`Target shape should be a vector but received shape ${s.shape}`);let i=Array.from(a.readSync(r.dataId)),o=a.readSync(n.dataId),l=Array.from(a.readSync(s.dataId)),[u,p,c]=OU(o,n.shape,n.dtype,i,l);return[a.makeTensorInfo(p,n.dtype,u),a.makeTensorInfo([c.length],s.dtype,new Int32Array(c))]}var qY={kernelName:eu,backendName:"webgl",kernelFunc:jY};function XY(e){let{inputs:t,backend:a}=e,{data:n,indices:r,segmentIds:s}=t;if(n.shape.length<1)throw new Error("Data should be at least 1 dimensional but received scalar");if(r.shape.length!==1)throw new Error(`Indices should be a vector but received shape ${r.shape}`);if(s.shape.length!==1)throw new Error(`Segment ids should be a vector but received shape ${s.shape}`);let i=a.readSync(n.dataId),o=a.readSync(r.dataId),l=a.readSync(s.dataId),[u,p]=W6(i,n.shape,n.dtype,o,l,!0);return a.makeTensorInfo(p,n.dtype,u)}var KY={kernelName:Dd,backendName:"webgl",kernelFunc:XY};function ZY(e){let{inputs:t,backend:a}=e,{data:n,indices:r,segmentIds:s}=t;if(n.shape.length<1)throw new Error("Data should be at least 1 dimensional but received scalar");if(r.shape.length!==1)throw new Error(`Indices should be a vector but received shape ${r.shape}`);if(s.shape.length!==1)throw new Error(`Segment ids should be a vector but received shape ${s.shape}`);let i=a.readSync(n.dataId),o=a.readSync(r.dataId),l=a.readSync(s.dataId),[u,p]=W6(i,n.shape,n.dtype,o,l);return a.makeTensorInfo(p,n.dtype,u)}var YY={kernelName:zd,backendName:"webgl",kernelFunc:ZY};function JY(e){let{inputs:t,backend:a,attrs:n}=e,{sparseIndices:r,sparseValues:s,defaultValue:i}=t,{outputShape:o}=n,{sliceRank:l,numUpdates:u,sliceSize:p,strides:c,outputSize:d}=T.calculateShapes(s,r,o),h=!1;if(s.dtype==="string"){let x=a.bufferSync(r),A=a.bufferSync(s),y=v.decodeString(a.readSync(i.dataId)[0]),b=$U(x,A,o,d,p,u,l,c,y,h);return a.makeTensorInfo(o,b.dtype,b.values)}let f=new yv(u,l,r.shape.length,s.shape.length,c,[d,1],h),m=a.runWebGLProgram(f,[s,r,i],s.dtype),g=ce({inputs:{x:m},backend:a,attrs:{shape:o}});return a.disposeIntermediateTensorInfo(m),g}var QY={kernelName:Ld,backendName:"webgl",kernelFunc:JY};function eJ(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{numOrSizeSplits:s,axis:i}=n,o=v.parseAxisParam(i,r.shape)[0],l=T.prepareSplitSize(r,s,o),u=r.shape.length,p=new Array(u).fill(0),c=r.shape.slice();return l.map(d=>{let h=[...c];h[o]=d;let f=gu({inputs:{x:r},backend:a,attrs:{begin:p,size:h}});return p[o]+=d,f})}var tJ={kernelName:Ql,backendName:"webgl",kernelFunc:eJ},_x="return sqrt(x);",aJ=Qe({opSnippet:_x,packedOpSnippet:_x,cpuKernelImpl:DU}),nJ={kernelName:no,backendName:"webgl",kernelFunc:aJ},rJ="return x * x;",sJ=Qe({opSnippet:rJ}),iJ={kernelName:Bd,backendName:"webgl",kernelFunc:sJ},Px="return (a - b) * (a - b);",oJ=oa({opSnippet:Px,packedOpSnippet:Px}),lJ={kernelName:io,backendName:"webgl",kernelFunc:oJ};function uJ({inputs:e,attrs:t,backend:a}){let{x:n}=e,r=Cn+` return x > 0.0 ? 1.0 : float(${t.alpha}); `,s=new qn(n.shape,r);return a.runWebGLProgram(s,[n],n.dtype)}var dJ={kernelName:fo,backendName:"webgl",kernelFunc:uJ},pJ=class{constructor(e,t,a){this.variableNames=["x"],this.outputShape=a;let n=a.length,r=gt(a.length),s=gt(a.length),i="";if(n===1)i="coords * strides + begin";else{let o=0;i=a.map((l,u)=>(o++,a.length===1?`coords * strides[${u}] + begin[${u}]`:`coords[${o-1}] * strides[${u}] + begin[${u}]`)).join(",")}this.userCode=` ${r} begin = ${r}(${e}); ${r} strides = ${r}(${t}); void main() { ${s} coords = getOutputCoords(); setOutput(getX(${i})); } `}};function cJ(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{begin:s,end:i,strides:o,beginMask:l,endMask:u,ellipsisMask:p,newAxisMask:c,shrinkAxisMask:d}=n,{finalShapeSparse:h,finalShape:f,isIdentity:m,sliceDim0:g,isSimpleSlice:x,begin:A,end:y,strides:b}=It.sliceInfo(r.shape,s,i,o,l,u,p,c,d),w;if(m)w=ce({inputs:{x:r},backend:a,attrs:{shape:f}});else if(g||x){v.assert(r.shape.length>=1,()=>`Input must have rank at least 1, got: ${r.shape.length}`);let C=It.computeOutShape(A,y,b),E=gu({inputs:{x:r},backend:a,attrs:{begin:A,size:C}});w=ce({inputs:{x:E},backend:a,attrs:{shape:f}}),a.disposeIntermediateTensorInfo(E)}else if(a.shouldExecuteOnCPU([r])){let C=a.readSync(r.dataId),E=Me(r.shape,r.dtype,C),_=zU(h,E,b,A);w=a.makeTensorInfo(f,r.dtype,_.values)}else{let C=new pJ(A,b,h);w=a.runWebGLProgram(C,[r],r.dtype)}let S=ce({inputs:{x:w},backend:a,attrs:{shape:f}});return a.disposeIntermediateTensorInfo(w),S}var hJ={kernelName:oo,backendName:"webgl",kernelFunc:cJ};function fJ(e){let{inputs:t,backend:a,attrs:n}=e,{separator:r,nGramWidths:s,leftPad:i,rightPad:o,padWidth:l,preserveShortSequences:u}=n,{data:p,dataSplits:c}=t,d=a.readSync(p.dataId),h=a.readSync(c.dataId),[f,m]=LU(d,h,r,s,i,o,l,u);return[a.makeTensorInfo([f.length],"string",f),a.makeTensorInfo(c.shape,"int32",m)]}var mJ={kernelName:tu,backendName:"webgl",kernelFunc:fJ};function gJ(e){let{inputs:t,backend:a,attrs:n}=e,{skipEmpty:r}=n,{input:s,delimiter:i}=t;if(s.dtype!=="string")throw new Error("Input must be of datatype string");if(s.shape.length!==1)throw new Error(`Input must be a vector, got shape: ${s.shape}`);if(i.shape.length!==0)throw new Error(`Delimiter must be a scalar, got shape: ${i.shape}`);let o=a.readSync(s.dataId),l=a.readSync(i.dataId)[0],[u,p,c]=BU(o,l,r),d=p.length;return[a.makeTensorInfo([d,2],"int32",u),a.makeTensorInfo([d],"string",p),a.makeTensorInfo([2],"int32",new Int32Array(c))]}var xJ={kernelName:Wd,backendName:"webgl",kernelFunc:gJ};function AJ(e){let{inputs:t,backend:a,attrs:n}=e,{numBuckets:r}=n,{input:s}=t;if(s.dtype!=="string")throw new Error("Input must be of datatype string");if(r<=0)throw new Error("Number of buckets must be at least 1");let i=a.readSync(s.dataId),o=WU(i,r);return a.makeTensorInfo(s.shape,"int32",o)}var yJ={kernelName:Vd,backendName:"webgl",kernelFunc:AJ},bJ="return tan(x);",vJ=Qe({opSnippet:bJ}),wJ={kernelName:uo,backendName:"webgl",kernelFunc:vJ},kJ=` float e2x = exp(-2.0 * abs(x)); return sign(x) * (1.0 - e2x) / (1.0 + e2x); `,IJ=Qe({opSnippet:kJ}),SJ={kernelName:po,backendName:"webgl",kernelFunc:IJ},TJ=class{constructor(e,t){this.variableNames=["A"];let a=new Array(e.length);for(let s=0;s5)throw Error(`Tile for rank ${t} is not yet supported`);if(t===1)return`imod(resRC, ${e[0]})`;let a=["resRC.x","resRC.y","resRC.z","resRC.w","resRC.u"],n=[];for(let r=0;r5){let o=a.readSync(r.dataId),l=r.dtype==="string"?o.map(c=>v.decodeString(c)):o,u=Me(r.shape,r.dtype,l),p=UU(u,s);return a.makeTensorInfo(p.shape,p.dtype,p.values)}let i=new TJ(r.shape,s);return a.runWebGLProgram(i,[r],r.dtype)}var NJ={kernelName:ns,backendName:"webgl",kernelFunc:bv},EJ=class{constructor(e){this.variableNames=["x","indices"],this.customUniforms=[{name:"n",type:"int"},{name:"firstPass",type:"int"},{name:"negativeInf",type:"float"},{name:"dir",type:"int"},{name:"inc",type:"int"}],this.outputShape=e,this.userCode=` void main() { ivec2 coords = getOutputCoords(); int batch = coords[0]; int elemIdx = coords[1]; // We compare elements pair-wise within a group of size 2 * inc. // The comparing rule for each group alternates between ascending // and descending. Within each group, we compare each pair at // positions i and i+inc. To decide whether an element at position i // is x0 or x1, we mod it by 2 * inc, if the result is smaller than // inc, it is in the first half of the group, we denote it as x0, // otherwise we denote it as x1. // For example, as shown in the Bitonic top K paper referenced above, // Figure5(a) shows that element[1] is in the // second half of the group when group size is 2, but it is in the // first half of the group when group size is 4. bool isFirstInPair = imod(elemIdx, 2 * inc) < inc; int i = isFirstInPair ? elemIdx : elemIdx - inc; int i0 = firstPass == 1 ? i : int(getIndices(batch, i)); int i1 = firstPass == 1 ? i + inc : int(getIndices(batch, i + inc)); float x0 = i0 < n ? getX(batch, i0) : negativeInf; float x1 = i1 < n ? getX(batch, i1) : negativeInf; // Denotes which direction indices are in (ascending or descending). bool reverse = imod(elemIdx, 2 * dir) >= dir; bool isGreater = x0 > x1 || (x0 == x1 && i1 > i0); if (reverse == isGreater) { // Elements in opposite order of direction int iTemp = i0; i0 = i1; i1 = iTemp; } if (isFirstInPair) { setOutput(float(i0)); } else { setOutput(float(i1)); } } `}},RJ=class{constructor(e){this.variableNames=["x","indices"],this.customUniforms=[{name:"n",type:"int"},{name:"firstPass",type:"int"},{name:"k",type:"int"}],this.outputShape=e,this.userCode=` void main() { // Takes max of indices (0, k), (1, k + 1), (2, k + 2) ... ivec2 coords = getOutputCoords(); int batch = coords[0]; int elemIdx = coords[1]; // The output size is half of the previous size. // If the previous sequence is | | | | _ _ _ _ | | | | _ _ _ _ (k=4), // we only need to output the indices at positions |, the indices at // positions _ can be thrown away, see Figure5(b) After Phase 2 // (Merge phase) in the Bitonic Top K paper referenced above. // For example, the paper shows we only need to output the orange bars. // The output sequence should look like this | | | | | | | |. // Because the sequence is halved, to map the output index back // to the previous sequence to find the corresponding value, // we need to double the index. When we double the index, // we basically interpolate a position, so 2i looks like // | _ | _ | _ | _ | _ | _ | _. We move the | to the first k position // of each 2k positions by - elemIdx % k. E.g. for output at // index 4,5,6,7, we want to get the corresponding element at // original index 8,9,10,11, for output at index 8,9,10,11, // we want to get the corresponding element at original index // 16,17,18,19, so on and so forth. int i = elemIdx < k ? elemIdx : (elemIdx * 2 - imod(elemIdx, k)); int i0 = firstPass == 1 ? i : int(getIndices(batch, i)); int i1 = firstPass == 1 ? i + k : int(getIndices(batch, i + k)); float x0 = getX(batch, i0); float x1 = i1 < n ? getX(batch, i1) : x0; setOutput(x0 >= x1 ? float(i0) : float(i1)); } `}};function Es(e,t){t!==null&&e.disposeIntermediateTensorInfo(t)}function Fx(e){let t=1;for(;tl){let _=a.readSync(r.dataId),[$,M]=GU(_,u,r.dtype,s,i);return[a.makeTensorInfo($.shape,$.dtype,$.values),a.makeTensorInfo(M.shape,M.dtype,M.values)]}if(s===0)return u[u.length-1]=0,[a.makeTensorInfo(u,r.dtype,[]),a.makeTensorInfo(u,"int32",[])];if(p===1)return[r,fp({attrs:{shape:u,dtype:"int32",value:0},backend:a})];let c=a.texData.get(r.dataId),d=c!==null&&c.isPacked,h=d?a.unpackTensor(r):r,f=v.sizeFromShape(u)/p,m=ce({inputs:{x:h},attrs:{shape:[f,p]},backend:a});d&&Es(a,h);let g=Fx(s),x=Fx(p),A=null,y=()=>A===null?[m,m]:[m,A],b=(_,$,M)=>{let I=y(),N=new EJ(M),O=[[p],[A===null?1:0],[Number.NEGATIVE_INFINITY],[_],[$]],L=A;A=a.runWebGLProgram(N,I,"int32",O),Es(a,L)};for(let _=1;_=1;M/=2)b($,M,[f,x])}for(let _=x;_>g;_/=2){let $=y(),M=new RJ([f,_/2]),I=[[p],[A===null?1:0],[g]],N=A;A=a.runWebGLProgram(M,$,"int32",I),Es(a,N);let O=g/2,L=O*2;for(let B=O;B>=1;B/=2)b(L,B,A.shape)}let w=A;A=gu({inputs:{x:A},backend:a,attrs:{begin:0,size:[f,s]}}),Es(a,w);let S=pv({inputs:{x:m,indices:A},backend:a,attrs:{axis:1,batchDims:1}});Es(a,m);let C=u.slice(0,-1);C.push(s),w=A,A=ce({inputs:{x:A},attrs:{shape:C},backend:a}),Es(a,w);let E=S;return S=ce({inputs:{x:S},attrs:{shape:C},backend:a}),Es(a,E),[S,A]}var $J={kernelName:co,backendName:"webgl",kernelFunc:MJ},_J=class{constructor(e,t,a,n,r,s){this.variableNames=["Image","Transforms"],this.outputShape=s;let i=a==="nearest"?1:2,o;switch(n){case"constant":o=1;break;case"reflect":o=2;break;case"wrap":o=3;break;case"nearest":o=4;break;default:o=1;break}this.userCode=` float mapCoord(float outCoord, float len) { float inCoord = outCoord; if(${o} == 2) { if (inCoord < 0.0) { if (len <= 1.0) { inCoord = 0.0; } else { float sz2 = 2.0 * len; if (inCoord < sz2) { inCoord = sz2 * float(int(float(-inCoord / sz2))) + inCoord; } inCoord = inCoord < -len ? inCoord + sz2 : -inCoord - 1.0; } } else if (inCoord > len - 1.0) { if (len <= 1.0) { inCoord = 0.0; } else { float sz2 = 2.0 * len; inCoord -= sz2 * float(int(float(inCoord / sz2))); if (inCoord >= len) { inCoord = sz2 - inCoord - 1.0; } } } return clamp(inCoord, 0.0, len - 1.0); } else if (${o} == 3) { if (inCoord < 0.0) { if (len <= 1.0) { inCoord = 0.0; } else { float sz = len - 1.0; inCoord += len * (float(int(float(-inCoord / sz))) + 1.0); } } else if (inCoord > len - 1.0) { if (len <= 1.0) { inCoord = 0.0; } else { float sz = len - 1.0; inCoord -= len * float(int(float(inCoord / sz))); } } return clamp(inCoord, 0.0, len - 1.0); } else if (${o} == 4) { return clamp(outCoord, 0.0, len - 1.0); } else { return outCoord; } } float readWithFillValue(int batch, int coordY, int coordX, int channel) { float outputValue; if (0 <= coordY && coordY < ${e} && 0 <= coordX && coordX < ${t}) { outputValue = getImage(batch, coordY, coordX, channel); } else { outputValue = float(${r}); } return outputValue; } void main() { ivec4 coords = getOutputCoords(); float outputValue; int batch = coords[0]; int x = coords[2]; int y = coords[1]; int channel = coords[3]; float xf = float(x); float yf = float(y); float a1 = getTransforms(batch, 0); float a2 = getTransforms(batch, 1); float a3 = getTransforms(batch, 2); float b1 = getTransforms(batch, 3); float b2 = getTransforms(batch, 4); float b3 = getTransforms(batch, 5); float c1 = getTransforms(batch, 6); float c2 = getTransforms(batch, 7); float projection = c1 * xf + c2 * yf + 1.0; if (projection == 0.0) { outputValue = float(${r}); } else { float inX = (a1 * xf + a2 * yf + a3) / projection; float inY = (b1 * xf + b2 * yf + b3) / projection; float mapX = mapCoord(inX, float(${t})); float mapY = mapCoord(inY, float(${e})); if (${i} == 1) { int coordY = int(round(mapY)); int coordX = int(round(mapX)); outputValue = readWithFillValue(batch, coordY, coordX, channel); } else { float yFloor = floor(mapY); float xFloor = floor(mapX); float yCeil = yFloor + 1.0; float xCeil = xFloor + 1.0; float valueYFloor = (xCeil - mapX) * readWithFillValue(batch, int(yFloor), int(xFloor), channel) + (mapX - xFloor) * readWithFillValue(batch, int(yFloor), int(xCeil), channel); float valueYCeil = (xCeil - mapX) * readWithFillValue(batch, int(yCeil), int(xFloor), channel) + (mapX - xFloor) * readWithFillValue(batch, int(yCeil), int(xCeil), channel); outputValue = (yCeil - mapY) * valueYFloor + (mapY - yFloor) * valueYCeil; } } setOutput(outputValue); } `}};function PJ(e){let{inputs:t,backend:a,attrs:n}=e,{image:r,transforms:s}=t,{interpolation:i,fillMode:o,fillValue:l,outputShape:u}=n,[p,c,d,h]=r.shape,[f,m]=u!=null?u:[c,d],g=[p,f,m,h],x=new _J(c,d,i,o,l,g);return a.runWebGLProgram(x,[r,s],"float32")}var FJ={kernelName:ho,backendName:"webgl",kernelFunc:PJ};function OJ(e){let{inputs:t,attrs:a,backend:n}=e,{axis:r}=a,{x:s}=t;uu(s,"unique"),console.warn("WARNING: ","UI might be locked temporarily as data is being downloaded");let i=n.readSync(s.dataId),{outputValues:o,outputShape:l,indices:u}=HU(i,r,s.shape,s.dtype);return[n.makeTensorInfo(l,s.dtype,o),n.makeTensorInfo([u.length],"int32",u)]}var DJ={kernelName:uh,backendName:"webgl",kernelFunc:OJ};function zJ(e){let{inputs:t,backend:a,attrs:n}=e,{value:r}=t,{axis:s}=n;s<0&&(s+=r.shape.length);let i=r,o=i.shape.length,l=r.shape[s],u=new Array(o-1),p=0;for(let m=0;ma.disposeIntermediateTensorInfo(m)),f}var LJ={kernelName:au,backendName:"webgl",kernelFunc:zJ},BJ=class{constructor(e,t){this.variableNames=["x","segmentIds"];let a=e.windowSize,n=e.batchSize,r=e.inSize,s=e.numSegments,i=s*Math.ceil(r/a);this.outputShape=[n,i];let o="0.0",l="sumValue",u=Math.floor(a/4)*4,p=a%4,c=` sumValue += dot(values, segFilter); `,d="";r%a>0&&(d=` if (inIdx < 0 || inIdx >= ${r}) { return initializationValue; } `);let h="";r%a>0&&(h=` if (inIdx < 0 || inIdx >= ${r}) { return -1.0; } `),this.userCode=` const float initializationValue = ${o}; float getValue(int batch, int inIdx) { ${d} return getX(batch, inIdx); } float getSegmentIdAtIndex(int inIdx) { ${h} return getSegmentIds(inIdx); } void main() { ivec2 coords = getOutputCoords(); int batch = coords[0]; int outIdx = coords[1]; int inOffset = int(floor(float(outIdx) / float( ${s})) * float(${a})); int currentSeg = int(mod(float(outIdx), float(${s}))); float sumValue = 0.0; for (int i = 0; i < ${u}; i += 4) { int inIdx = inOffset + i; vec4 values = vec4( getValue(batch, inIdx), getValue(batch, inIdx + 1), getValue(batch, inIdx + 2), getValue(batch, inIdx + 3) ); vec4 segFilter = vec4( int(getSegmentIdAtIndex(inIdx)) == currentSeg ? 1 : 0, int(getSegmentIdAtIndex(inIdx + 1)) == currentSeg ? 1 : 0, int(getSegmentIdAtIndex(inIdx + 2)) == currentSeg ? 1 : 0, int(getSegmentIdAtIndex(inIdx + 3)) == currentSeg ? 1 : 0 ); ${c} } int inIdx = inOffset + ${u}; if (${p===1}) { vec4 values = vec4( getValue(batch, inIdx), initializationValue, initializationValue, initializationValue ); int inIdxSeg = int(getSegmentIdAtIndex(inIdx)); vec4 segFilter = vec4( int(getSegmentIdAtIndex(inIdx)) == currentSeg ? 1 : 0, 0, 0, 0 ); ${c} } else if (${p===2}) { vec4 values = vec4( getValue(batch, inIdx), getValue(batch, inIdx + 1), initializationValue, initializationValue ); vec4 segFilter = vec4( int(getSegmentIdAtIndex(inIdx)) == currentSeg ? 1 : 0, int(getSegmentIdAtIndex(inIdx + 1)) == currentSeg ? 1 : 0, 0, 0 ); ${c} } else if (${p===3}) { vec4 values = vec4( getValue(batch, inIdx), getValue(batch, inIdx + 1), getValue(batch, inIdx + 2), initializationValue ); vec4 segFilter = vec4( int(getSegmentIdAtIndex(inIdx)) == currentSeg ? 1 : 0, int(getSegmentIdAtIndex(inIdx + 1)) == currentSeg ? 1 : 0, int(getSegmentIdAtIndex(inIdx + 2)) == currentSeg ? 1 : 0, 0 ); ${c} } setOutput(${l}); } `}};function WJ(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,segmentIds:s}=t,{numSegments:i}=n,o=r.shape.length,l=[],u=0,p=T.getAxesPermutation([u],o),c=r;p!=null&&(c=Ia({inputs:{x:r},backend:a,attrs:{perm:p}}),l.push(c),u=T.getInnerMostAxes(1,o)[0]);let d=T.segment_util.computeOutShape(c.shape,u,i),h=v.sizeFromShape([c.shape[u]]),f=ce({inputs:{x:c},backend:a,attrs:{shape:[-1,h]}});l.push(f);let m=Hd(r.dtype),g=(b,w,S,C,E)=>{let _=b.shape[0],$=b.shape[1],M=T.segment_util.segOpComputeOptimalWindowSize($,E),I={windowSize:M,inSize:$,batchSize:_,numSegments:E},N=new BJ(I,w),O=a.compileAndRun(N,[b,S],C);if(l.push(O),O.shape[1]===E)return O;let L=Av({backend:a,attrs:{start:0,stop:E,step:1,dtype:"float32"}}),B=bv({inputs:{x:L},backend:a,attrs:{reps:[$/M]}});return l.push(L),l.push(B),g(O,w,B,C,E)},x=g(f,"unsortedSegmentSum",s,m,i),A=ce({inputs:{x},backend:a,attrs:{shape:d}}),y=A;if(p!=null){l.push(A);let b=T.getUndoAxesPermutation(p);y=Ia({inputs:{x:y},backend:a,attrs:{perm:b}})}return l.forEach(b=>a.disposeIntermediateTensorInfo(b)),y}var VJ={kernelName:dh,backendName:"webgl",kernelFunc:WJ},UJ=[zG,BG,UG,jG,XG,YG,QG,tH,sH,oH,dH,hH,gH,bH,kH,SH,CH,MH,_H,FH,LH,jH,XH,ZH,aj,rj,lj,vG,pj,gj,bj,Tj,Nj,Rj,$j,Pj,Dj,Bj,Uj,Hj,qj,Kj,Jj,eq,rq,iq,uq,cq,fq,Aq,wq,Tq,Eq,$q,_q,Fq,Dq,Lq,Wq,Uq,qq,Zq,Qq,tX,rX,oX,pX,mX,bG,xX,fj,bX,kX,TX,kG,RX,PX,OX,BX,UX,qX,ZX,eK,rK,oK,uK,hK,mK,xK,vK,kK,SK,CK,EK,_K,DK,WK,KK,TG,QK,aZ,sZ,lZ,JH,pZ,hZ,mZ,AZ,wZ,SG,IZ,TZ,NZ,RZ,MZ,QH,HK,PZ,zZ,VZ,NG,jZ,KZ,QZ,aY,iY,lY,pY,fY,gY,yY,wY,SY,EY,$Y,FY,zY,GH,qK,WY,UY,HY,qY,KY,YY,QY,tJ,nJ,iJ,lJ,dJ,hJ,mJ,xJ,yJ,jK,FG,wJ,SJ,NJ,$J,FJ,OG,DJ,LJ,VJ,cZ];for(let e of UJ)mn(e);var Tt;(function(e){e[e.float32=0]="float32",e[e.int32=1]="int32",e[e.bool=2]="bool",e[e.string=3]="string",e[e.complex64=4]="complex64"})(Tt||(Tt={}));var yd;(function(e){e[e.linear=0]="linear",e[e.relu=1]="relu",e[e.relu6=2]="relu6",e[e.prelu=3]="prelu",e[e.leakyrelu=4]="leakyrelu",e[e.sigmoid=5]="sigmoid",e[e.elu=6]="elu"})(yd||(yd={}));var vv;function GJ(e){vv=e.wasm.cwrap(jr,null,["number","array","number","number","array","number","number","number","number","number","number","number","number"])}function HJ(e){let{inputs:t,backend:a,attrs:n}=e,{a:r,b:s,bias:i,preluActivationWeights:o}=t;if(r.dtype!=="float32"||s.dtype!=="float32")throw new Error("_FusedMatMul for non non-float32 tensors not yet supported.");let{transposeA:l,transposeB:u,activation:p,leakyreluAlpha:c}=n,d=a.dataIdMap.get(r.dataId).id,h=a.dataIdMap.get(s.dataId).id,f=0;if(i!=null){let E=a.dataIdMap.get(i.dataId);if(E.shape.length!==1)throw new Error(`_FusedMatMul only supports rank-1 bias but got rank ${E.shape.length}.`);f=E.id}let m=o==null?0:a.dataIdMap.get(o.dataId).id,g=yd[p];if(g==null)throw new Error(`${p} activation not yet supported for FusedConv2D in the wasm backend.`);let x=l?r.shape[2]:r.shape[1],A=u?s.shape[1]:s.shape[2],y=xo.assertAndGetBroadcastShape(r.shape.slice(0,-2),s.shape.slice(0,-2)),b=a.makeOutput([...y,x,A],r.dtype),w=a.dataIdMap.get(b.dataId).id,S=new Uint8Array(new Int32Array(r.shape).buffer),C=new Uint8Array(new Int32Array(s.shape).buffer);return vv(d,S,r.shape.length,h,C,s.shape.length,l,u,g,f,m,c||0,w),b}var jJ={kernelName:jr,backendName:"wasm",setupFunc:GJ,kernelFunc:HJ};function Bt(e,t){let a;function n(s){a=s.wasm.cwrap(e,null,["number","number","number"])}function r(s){let{backend:i,inputs:{x:o}}=s,l=i.dataIdMap.get(o.dataId).id,u=i.makeOutput(o.shape,t||o.dtype),p=i.dataIdMap.get(u.dataId).id;return v.sizeFromShape(u.shape)===0||a(l,Tt[o.dtype],p),u}return{kernelName:e,backendName:"wasm",setupFunc:n,kernelFunc:r}}var qJ=Bt(wl);function la(e,t,a){let n;function r(i){n=i.wasm.cwrap(e,null,["number","array","number","number","array","number","number","number"])}function s(i){let{backend:o,inputs:l}=i,{a:u,b:p}=l,c=o.dataIdMap.get(u.dataId).id,d=o.dataIdMap.get(p.dataId).id,h=a!=null?a:u.dtype,f=T.assertAndGetBroadcastShape(u.shape,p.shape),m=o.makeOutput(f,h);if(v.sizeFromShape(f)===0)return m;let g=new Uint8Array(new Int32Array(u.shape).buffer),x=new Uint8Array(new Int32Array(p.shape).buffer),A=o.dataIdMap.get(m.dataId).id;return n(c,g,u.shape.length,d,x,p.shape.length,Tt[u.dtype],A),m}return{kernelName:e,backendName:"wasm",setupFunc:r,kernelFunc:s}}var XJ=!0,KJ=la(ts,XJ),wv;function ZJ(e){wv=e.wasm.cwrap(Ks,null,["array","number","number","number"])}function YJ(e){let{inputs:t,backend:a}=e,n=a.makeOutput(t[0].shape,t[0].dtype);if(v.sizeFromShape(n.shape)===0)return n;let r=t.map(o=>a.dataIdMap.get(o.dataId).id),s=new Uint8Array(new Int32Array(r).buffer),i=a.dataIdMap.get(n.dataId).id;return wv(s,r.length,Tt[n.dtype],i),n}var JJ={kernelName:Ks,backendName:"wasm",setupFunc:ZJ,kernelFunc:YJ};function Bh(e){let{inputs:{x:t},backend:a}=e;if(t.dtype==="string")return Be(a.readSync(t.dataId),t.shape,t.dtype);let n=a.makeOutput(t.shape,t.dtype),r=a.typedArrayFromHeap(t);return a.typedArrayFromHeap(n).set(r),n}var QJ={kernelName:ki,backendName:"wasm",kernelFunc:Bh},kv;function eQ(e){kv=e.wasm.cwrap(Ar,null,["number","array","number","number","number","array","number"])}function Qr(e){let{inputs:t,backend:a,attrs:n}=e,[r,s]=aQ(t.x.shape,n.perm),i=!0;for(let f=0;f=r&&(s===-1||n[s]>n[i])&&(s=i);n[s]=r}return[a,n]}var nQ={kernelName:Ar,backendName:"wasm",kernelFunc:Qr,setupFunc:eQ};function us(e,t,a){let n=e.shape,r=e.shape.length,s=v.parseAxisParam(t,n),i=s,o=T.getAxesPermutation(i,r),l=null,u=!1;if(o!=null){let p=new Array(r);for(let d=0;d`new shape: ${i}, old shape: ${n.shape}. New shape and old shape must have the same number of elements.`),e.backend.incRef(n.dataId),{dataId:n.dataId,shape:i,dtype:n.dtype}}var gQ={kernelName:ql,backendName:"wasm",kernelFunc:za},Nv;function xQ(e){Nv=e.wasm.cwrap(ei,null,["number","array","number","number","array","number","number","number","number"])}function AQ(e){let{inputs:t,backend:a,attrs:n}=e,{a:r,b:s}=t,{transposeA:i,transposeB:o}=n;if(r.dtype!=="float32"||s.dtype!=="float32")throw new Error("BatchMatMul for non non-float32 tensors not yet supported.");let l=r.shape.length,u=s.shape.length,p=i?r.shape[l-2]:r.shape[l-1],c=o?s.shape[u-1]:s.shape[u-2],d=i?r.shape[l-1]:r.shape[l-2],h=o?s.shape[u-2]:s.shape[u-1],f=r.shape.slice(0,-2),m=s.shape.slice(0,-2),g=v.sizeFromShape(f),x=v.sizeFromShape(m),A=xo.assertAndGetBroadcastShape(r.shape.slice(0,-2),s.shape.slice(0,-2)).concat([d,h]);v.assert(p===c,()=>`Error in matMul: inner shapes (${p}) and (${c}) of Tensors with shapes ${r.shape} and ${s.shape} and transposeA=${i} and transposeB=${o} must match.`);let y=i?[g,p,d]:[g,d,p],b=o?[x,h,c]:[x,c,h],w=za({inputs:{x:r},backend:a,attrs:{shape:y}}),S=za({inputs:{x:s},backend:a,attrs:{shape:b}}),C=a.dataIdMap.get(w.dataId).id,E=a.dataIdMap.get(S.dataId).id,_=i?w.shape[2]:w.shape[1],$=o?S.shape[1]:S.shape[2],M=Math.max(g,x),I=a.makeOutput([M,_,$],w.dtype),N=a.dataIdMap.get(I.dataId).id,O=new Uint8Array(new Int32Array(w.shape).buffer),L=new Uint8Array(new Int32Array(S.shape).buffer);return Nv(C,O,w.shape.length,E,L,S.shape.length,i,o,N),a.disposeData(w.dataId),a.disposeData(S.dataId),I.shape=A,I}var yQ={kernelName:ei,backendName:"wasm",setupFunc:xQ,kernelFunc:AQ};function qs(e){let{inputs:{x:t},attrs:{begin:a,size:n},backend:r}=e,[s,i]=It.parseSliceParams(t,a,n),o=It.isSliceContinous(t.shape,s,i),l=r.readSync(t.dataId),u=r.makeOutput(i,t.dtype),p=v.computeStrides(t.shape),c=r.dataIdMap.get(u.dataId);if(o){let f=It.computeFlatOffset(s,p);return t.dtype==="string"?c.stringBytes=l.slice(f,f+v.sizeFromShape(i)):r.typedArrayFromHeap(u).set(l.subarray(f,f+v.sizeFromShape(i))),u}if(t.dtype==="string"){let f=_c(l,s,i,t.shape,t.dtype);return c.stringBytes=f,u}let d=r.typedArrayFromHeap(u),h=t.shape.length;if(h===2)bQ(l,p[0],d,s,i);else if(h===3)vQ(l,p[0],p[1],d,s,i);else if(h===4)wQ(l,p[0],p[1],p[2],d,s,i);else{let f=_c(l,s,i,t.shape,t.dtype);d.set(f)}return u}function bQ(e,t,a,n,r){let s=0,i=n[0],o=n[1],l=i+r[0];for(let u=i;ux*A),l=T.getReshaped(r.shape,s,o),u=T.getPermuted(l.length,s.length),p=T.getReshapedPermuted(r.shape,s,o),c=T.getSliceBeginCoords(i,s.length),d=T.getSliceSize(p,i,s.length),h=za({inputs:{x:r},backend:a,attrs:{shape:l}}),f=Qr({inputs:{x:h},backend:a,attrs:{perm:u}}),m=za({inputs:{x:f},backend:a,attrs:{shape:p}}),g=qs({inputs:{x:m},backend:a,attrs:{begin:c,size:d}});return a.disposeData(h.dataId),a.disposeData(f.dataId),a.disposeData(h.dataId),g}var SQ={kernelName:Rl,backendName:"wasm",kernelFunc:IQ};function xu(e){let{inputs:{x:t},attrs:{dtype:a},backend:n}=e,r=n.makeOutput(t.shape,a),s=n.typedArrayFromHeap(t);return n.typedArrayFromHeap(r).set(s),r}var TQ={kernelName:ti,backendName:"wasm",kernelFunc:xu},CQ=Bt(ai),Ev;function NQ(e){Ev=e.wasm.cwrap(as,null,["number","number","number","number"])}function EQ(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{clipValueMin:s,clipValueMax:i}=n,o=a.dataIdMap.get(r.dataId).id,l=a.makeOutput(r.shape,r.dtype),u=a.dataIdMap.get(l.dataId).id;return Ev(o,s,i,u),l}var RQ={kernelName:as,backendName:"wasm",setupFunc:NQ,kernelFunc:EQ};function Rv(e){let{inputs:t,backend:a}=e,n=v.parseAxisParam(e.attrs.axis,t[0].shape)[0],r=t.map(h=>h.shape);T.assertParamsConsistent(r,n);let s=T.computeOutShape(t.map(h=>h.shape),n),i=t.filter(h=>v.sizeFromShape(h.shape)>0);if(i.length===1)return Bh({inputs:{x:i[0]},backend:a});let o=a.makeOutput(s,t[0].dtype);if(v.sizeFromShape(s)===0)return o;if(i[0].dtype==="string"){let h=i.map(y=>{let b=[-1,v.sizeFromShape(y.shape.slice(n))];return za({inputs:{x:y},backend:a,attrs:{shape:b}})}),f=h.map(y=>({vals:a.readSync(y.dataId),shape:y.shape}));s=T.computeOutShape(h.map(y=>y.shape),1);let m=h[0].shape[0]===1,g=o3(f,s,t[0].dtype,m),x=T.computeOutShape(i.map(y=>y.shape),n);o.shape=x;let A=a.dataIdMap.get(o.dataId);return A.stringBytes=T.fromStringArrayToUint8(g),h.forEach(y=>a.disposeData(y.dataId)),o}let l=v.sizeFromShape(i[0].shape.slice(0,n)),u=0,p=i.map(h=>{let f=v.sizeFromShape(h.shape.slice(n));return u+=f,f}),c=i.map(h=>a.typedArrayFromHeap(h)),d=a.typedArrayFromHeap(o);for(let h=0;h`cumprod does not support ${r.dtype} tensors in the WASM backend`);let u=T.getAxesPermutation([s],l),p=r;u!==null&&(p=Qr({inputs:{x:r},attrs:{perm:u},backend:a}));let c=T.getInnerMostAxes(1,l)[0];T.assertAxesAreInnerMostDims("cumprod",[c],l);let d=a.makeOutput(p.shape,p.dtype),h=p.shape[c],f=a.dataIdMap.get(p.dataId).id,m=a.dataIdMap.get(d.dataId).id;Pv(f,i?1:0,o?1:0,h,m,Tt[r.dtype]);let g=d;if(u!==null){let x=T.getUndoAxesPermutation(u);g=Qr({inputs:{x:d},attrs:{perm:x},backend:a}),a.disposeData(p.dataId),a.disposeData(d.dataId)}return g}var HQ={kernelName:oi,backendName:"wasm",setupFunc:UQ,kernelFunc:GQ},Fv;function jQ(e){Fv=e.wasm.cwrap(li,null,["number","number","number","number","number","number"])}function qQ(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,exclusive:i,reverse:o}=n,l=r.shape.length;v.assert(r.dtype==="float32"||r.dtype==="int32",()=>`cumsum does not support ${r.dtype} tensors in the WASM backend`);let u=T.getAxesPermutation([s],l),p=r;u!==null&&(p=Qr({inputs:{x:r},attrs:{perm:u},backend:a}));let c=T.getInnerMostAxes(1,l)[0];T.assertAxesAreInnerMostDims("cumsum",[c],l);let d=a.makeOutput(p.shape,p.dtype),h=p.shape[c],f=a.dataIdMap.get(p.dataId).id,m=a.dataIdMap.get(d.dataId).id;Fv(f,i?1:0,o?1:0,h,m,Tt[r.dtype]);let g=d;if(u!==null){let x=T.getUndoAxesPermutation(u);g=Qr({inputs:{x:d},attrs:{perm:x},backend:a}),a.disposeData(p.dataId),a.disposeData(d.dataId)}return g}var XQ={kernelName:li,backendName:"wasm",setupFunc:jQ,kernelFunc:qQ},Ov;function KQ(e){Ov=e.wasm.cwrap(di,null,["number","number","number","array","number","array","array","number","number"])}function ZQ(e){let{backend:t,inputs:a,attrs:n}=e,{x:r}=a,{blockSize:s,dataFormat:i}=n,o=r.shape[0],l=i==="NHWC"?r.shape[1]:r.shape[2],u=i==="NHWC"?r.shape[2]:r.shape[3],p=i==="NHWC"?r.shape[3]:r.shape[1],c=l*s,d=u*s,h=p/(s*s),f=i==="NHWC"?[o,c,d,h]:[o,h,c,d],m=t.makeOutput(f,"float32"),g=t.dataIdMap.get(r.dataId).id,x=new Uint8Array(new Int32Array(v.computeStrides(r.shape)).buffer),A=new Uint8Array(new Int32Array(f).buffer),y=new Uint8Array(new Int32Array(v.computeStrides(f)).buffer),b=t.dataIdMap.get(m.dataId).id;return Ov(g,s,i==="NHWC"?1:0,x,r.shape.length-1,A,y,f.length,b),m}var YQ={kernelName:di,backendName:"wasm",setupFunc:KQ,kernelFunc:ZQ},Dv;function JQ(e){Dv=e.wasm.cwrap(pi,null,["number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number"])}function QQ(e){let{inputs:t,attrs:a,backend:n}=e,{x:r,filter:s}=t,i=n.dataIdMap.get(r.dataId).id,o=n.dataIdMap.get(s.dataId).id,{strides:l,dilations:u,pad:p,dimRoundingMode:c}=a,d=u==null?[1,1]:u,h=T.computeConv2DInfo(r.shape,s.shape,l,d,p,c,!0),f=h.filterHeight,m=h.filterWidth,g=h.padInfo.top,x=h.padInfo.right,A=h.padInfo.bottom,y=h.padInfo.left,b=h.dilationHeight,w=h.dilationWidth,S=h.strideHeight,C=h.strideWidth,E=h.inChannels,_=h.outChannels,$=h.padInfo.type==="SAME"?1:0;if(h.dataFormat!=="channelsLast")throw new Error(`wasm backend DepthwiseConv2dNative does not support dataFormat:'${h.dataFormat}'. Please use 'channelsLast'.`);let M=n.makeOutput(h.outShape,"float32"),I=n.dataIdMap.get(M.dataId).id;return Dv(i,r.shape[0],r.shape[1],r.shape[2],o,f,m,g,x,A,y,$,b,w,S,C,E,_,I),M}var eee={kernelName:pi,backendName:"wasm",setupFunc:JQ,kernelFunc:QQ},tee=Bt(hi),aee=!1,nee=la(fi,aee,"bool"),ree=Bt(mi,"float32");function R1(e){let{inputs:t,attrs:a,backend:n}=e,{input:r}=t,{dim:s}=a,i=r.shape.length,o=r.shape.slice(),l=s;return s<0&&(v.assert(-(i+1)<=s,()=>`Axis must be in the interval [${-(i+1)}, ${i}]`),l=i+s+1),o.splice(l,0,1),za({inputs:{x:r},backend:n,attrs:{shape:o}})}var see={kernelName:_l,backendName:"wasm",kernelFunc:R1};function zv(e){let{attrs:{shape:t,value:a,dtype:n},backend:r}=e,s=r.makeOutput(t,n);return r.typedArrayFromHeap(s).fill(a),s}var iee={kernelName:Fl,backendName:"wasm",kernelFunc:zv},Lv;function oee(e){Lv=e.wasm.cwrap(gi,null,["number","number","number","number","number","number"])}function lee(e){let{inputs:t,backend:a}=e,{image:n}=t,r=a.makeOutput(n.shape,n.dtype),s=a.dataIdMap.get(n.dataId).id,i=a.dataIdMap.get(r.dataId).id,[o,l,u,p]=n.shape;return Lv(s,o,l,u,p,i),r}var uee={kernelName:gi,backendName:"wasm",kernelFunc:lee,setupFunc:oee},dee=Bt(xi),pee=!1,cee=la(Ai,pee),Bv;function hee(e){Bv=e.wasm.cwrap(yi,null,["number","number","number","number","number","number","number"])}function fee(e){let{backend:t,inputs:a,attrs:n}=e,{varianceEpsilon:r}=n,{x:s,mean:i,variance:o,offset:l,scale:u}=a,p=t.dataIdMap.get(s.dataId).id,c=t.dataIdMap.get(i.dataId).id,d=t.dataIdMap.get(o.dataId).id,h=l!=null?t.dataIdMap.get(l.dataId).id:0,f=u!=null?t.dataIdMap.get(u.dataId).id:0,m=t.makeOutput(s.shape,s.dtype);if(v.sizeFromShape(s.shape)===0)return m;let g=t.dataIdMap.get(m.dataId).id;return Bv(p,c,d,h,f,r,g),m}var mee={kernelName:yi,backendName:"wasm",setupFunc:hee,kernelFunc:fee},Wv;function gee(e){Wv=e.wasm.cwrap(qr,null,["number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number"])}function xee(e){let{inputs:t,attrs:a,backend:n}=e,{x:r,filter:s,bias:i,preluActivationWeights:o}=t,{strides:l,pad:u,dilations:p,dataFormat:c,dimRoundingMode:d,activation:h,leakyreluAlpha:f}=a,m=T.computeConv2DInfo(r.shape,s.shape,l,p,u,d),g=yd[h];if(g==null)throw new Error(`${h} activation not yet supported for FusedConv2D in the wasm backend.`);let x=n.dataIdMap.get(r.dataId).id,A=n.dataIdMap.get(s.dataId).id,y=m.outChannels,b=0;if(i!=null){let Z=n.dataIdMap.get(i.dataId);if(Z.shape.length!==1)throw new Error(`FusedConv2D only supports rank-1 bias but got rank ${Z.shape.length}.`);if(Z.shape[0]!==y)throw new Error(`FusedConv2D bias shape (${Z.shape}) does not match the number of output channels (${y})`);b=Z.id}let w=m.filterHeight,S=m.filterWidth,C=m.padInfo.top,E=m.padInfo.right,_=m.padInfo.bottom,$=m.padInfo.left,M=m.dilationHeight,I=m.dilationWidth,N=m.strideHeight,O=m.strideWidth,L=m.inChannels,B=m.padInfo.type==="SAME"?1:0,G=m.batchSize,j=m.inHeight,U=m.inWidth;if(c!=="NHWC")throw new Error(`wasm backend FusedConv2D does not support dataFormat:'${c}'. Please use 'NHWC'.`);let H=n.makeOutput(m.outShape,"float32"),V=n.dataIdMap.get(H.dataId).id,Q=o==null?0:n.dataIdMap.get(o.dataId).id;return Wv(x,G,j,U,A,w,S,b,C,E,_,$,B,M,I,N,O,L,y,g,Q,f||0,V),H}var Aee={kernelName:qr,backendName:"wasm",setupFunc:gee,kernelFunc:xee},Vv;function yee(e){Vv=e.wasm.cwrap(Xr,null,["number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number"])}function bee(e){let{inputs:t,attrs:a,backend:n}=e,{x:r,filter:s,bias:i,preluActivationWeights:o}=t,{strides:l,pad:u,dilations:p,dataFormat:c,dimRoundingMode:d,activation:h,leakyreluAlpha:f}=a,m=T.computeConv2DInfo(r.shape,s.shape,l,p,u,d,!0),g=yd[h];if(g==null)throw new Error(`${h} activation not yet supported for FusedDepthwiseConv2D in the wasm backend.`);let x=n.dataIdMap.get(r.dataId).id,A=n.dataIdMap.get(s.dataId).id,y=m.outChannels,b=0;if(i!=null){let Z=n.dataIdMap.get(i.dataId);if(Z.shape.length!==1)throw new Error(`FusedDepthwiseConv2D only supports rank-1 bias but got rank ${Z.shape.length}.`);if(Z.shape[0]!==y)throw new Error(`FusedDepthwiseConv2D bias shape (${Z.shape}) does not match the number of output channels (${y})`);b=Z.id}let w=m.filterHeight,S=m.filterWidth,C=m.padInfo.top,E=m.padInfo.right,_=m.padInfo.bottom,$=m.padInfo.left,M=m.dilationHeight,I=m.dilationWidth,N=m.strideHeight,O=m.strideWidth,L=m.inChannels,B=m.padInfo.type==="SAME"?1:0,G=m.batchSize,j=m.inHeight,U=m.inWidth;if(c!=="NHWC")throw new Error(`wasm backend FusedDepthwiseConv2D does not support dataFormat:'${c}'. Please use 'NHWC'.`);let H=n.makeOutput(m.outShape,"float32"),V=n.dataIdMap.get(H.dataId).id,Q=o==null?0:n.dataIdMap.get(o.dataId).id;return Vv(x,G,j,U,A,w,S,b,C,E,_,$,B,M,I,N,O,L,y,g,Q,f||0,V),H}var vee={kernelName:Xr,backendName:"wasm",setupFunc:yee,kernelFunc:bee},Uv;function wee(e){Uv=e.wasm.cwrap(bi,null,["number","number","number","number","number","number","array","number"])}function kee(e){let{backend:t,inputs:a}=e,{params:n,indices:r}=a,[s,i,o,l]=c2.prepareAndValidate(n,r),u=t.makeOutput(s,n.dtype);if(i===0)return u;let p=r.shape,c=p[p.length-1],d=t.dataIdMap.get(n.dataId).id,h=t.dataIdMap.get(r.dataId).id,f=new Uint8Array(new Int32Array(l).buffer),m=t.dataIdMap.get(u.dataId).id;return Uv(d,Tt[n.dtype],h,i,c,o,f,m),u}var Iee={kernelName:bi,backendName:"wasm",setupFunc:wee,kernelFunc:kee},Gv;function See(e){Gv=e.wasm.cwrap("Gather",null,["number","number","array","number","number","number","array","number"])}function Tee(e){let{backend:t,inputs:a,attrs:n}=e,{x:r,indices:s}=a,{axis:i,batchDims:o}=n,l=v.parseAxisParam(i,r.shape)[0],u=t.readSync(s.dataId),p=r.shape[l];for(let C=0;C=0,()=>`GatherV2: the index value ${E} is not in [0, ${p-1}]`)}let c=T.segment_util.collectGatherOpShapeInfo(r,s,l,o),d=za({inputs:{x:r},attrs:{shape:[c.batchSize,c.outerSize,c.dimSize,c.sliceSize]},backend:t}),h=v.sizeFromShape(s.shape),f=za({inputs:{x:s},attrs:{shape:[c.batchSize,h/c.batchSize]},backend:t}),m=[c.batchSize,c.outerSize,h/c.batchSize,c.sliceSize],g=t.makeOutput(m,r.dtype);if(v.sizeFromShape(r.shape)===0)return g;let x=d.shape.length-1,A=t.dataIdMap.get(d.dataId).id,y=t.dataIdMap.get(f.dataId).id,b=t.dataIdMap.get(g.dataId).id,w=new Uint8Array(new Int32Array(v.computeStrides(d.shape)).buffer),S=new Uint8Array(new Int32Array(v.computeStrides(m)).buffer);return Gv(A,Tt[r.dtype],w,x,y,c.batchSize,S,b),t.disposeData(d.dataId),t.disposeData(f.dataId),g.shape=c.outputShape,g}var Cee={kernelName:Ol,backendName:"wasm",setupFunc:See,kernelFunc:Tee},Nee=!1,Eee=la(vi,Nee,"bool"),Ree=!1,Mee=la(wi,Ree,"bool"),$ee=Bt(Ii,"bool"),Hv;function _ee(e){Hv=e.wasm.cwrap(Si,null,["number","number","number","number"])}function Pee(e){let{inputs:{x:t},attrs:{alpha:a},backend:n}=e,r=n.dataIdMap.get(t.dataId).id,s=n.makeOutput(t.shape,"float32");if(v.sizeFromShape(t.shape)!==0){let i=n.dataIdMap.get(s.dataId).id;Hv(r,Tt[t.dtype],a,i)}return s}var Fee={kernelName:Si,backendName:"wasm",setupFunc:_ee,kernelFunc:Pee},Oee=!1,Dee=la(Ti,Oee,"bool"),zee=!1,Lee=la(Ci,zee,"bool"),Bee=Bt(Ni),Wee=!1,Vee=la(Ei,Wee,"bool"),Uee=Bt(Ri),Gee=!1,Hee=la(Bl,Gee,"bool"),jee=!1,qee=la(xA,jee,"bool"),jv;function Xee(e){jv=e.wasm.cwrap(Mi,null,["number","number","number","number"])}function Kee(e){let{backend:t,inputs:a,attrs:n}=e,{reductionIndices:r,keepDims:s}=n,{x:i}=a,o=t.dataIdMap.get(i.dataId).id,l=i,{transposed:u,axes:p,originalAxes:c,inputWasTransposed:d}=us(i,r,t);if(d){let A=t.dataIdMap.get(u.dataId).id;l=u,o=A}let h=l.shape.length;T.assertAxesAreInnerMostDims("max",p,h);let[f,m]=T.computeOutAndReduceShapes(l.shape,p),g=v.sizeFromShape(m),x=t.makeOutput(f,i.dtype);if(v.sizeFromShape(l.shape)!==0){let A=t.dataIdMap.get(x.dataId).id;jv(o,Tt[i.dtype],g,A)}if(d&&t.disposeData(u.dataId),s){let A=T.expandShapeToKeepDim(x.shape,c);x.shape=A}return x}var Zee={kernelName:Mi,backendName:"wasm",setupFunc:Xee,kernelFunc:Kee},Yee=!1,Jee=la($i,Yee),qv;function Qee(e){qv=e.wasm.cwrap(_i,null,["number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number","number"])}function ete(e){let{inputs:t,attrs:a,backend:n}=e,r=t.x,s=n.dataIdMap.get(r.dataId).id;v.assert(r.dtype==="float32",()=>`Error in MaxPool: only float32 input is supported. Got ${r.dtype}.`);let{filterSize:i,strides:o,pad:l,dimRoundingMode:u}=a,p=T.computePool2DInfo(r.shape,i,o,1,l,u),c=p.filterHeight,d=p.filterWidth,h=p.padInfo.top,f=p.padInfo.right,m=p.padInfo.bottom,g=p.padInfo.left,x=p.dilationHeight,A=p.dilationWidth,y=p.strideHeight,b=p.strideWidth,w=p.inChannels,S=p.outChannels;if(p.dataFormat!=="channelsLast")throw new Error(`wasm backend does not support dataFormat:'${p.dataFormat}'. Please use 'channelsLast'.`);let C=n.makeOutput(p.outShape,"float32"),E=n.dataIdMap.get(C.dataId).id;return qv(s,r.shape[0],r.shape[1],r.shape[2],c,d,h,f,m,g,x,A,y,b,w,S,E),C}var tte={kernelName:_i,backendName:"wasm",setupFunc:Qee,kernelFunc:ete},Xv;function ate(e){Xv=e.wasm.cwrap(Pi,null,["number, number, number"])}function nte(e){let{backend:t,inputs:a,attrs:n}=e,{axis:r,keepDims:s}=n,{x:i}=a,o=t.dataIdMap.get(i.dataId).id,l=o,u=i,{transposed:p,axes:c,originalAxes:d,inputWasTransposed:h}=us(i,r,t),f=c;if(h){let b=t.dataIdMap.get(p.dataId).id;b!==o&&(u=p,l=b,f=T.getInnerMostAxes(f.length,u.shape.length))}T.assertAxesAreInnerMostDims("mean",f,u.shape.length);let[m,g]=T.computeOutAndReduceShapes(u.shape,f),x=v.sizeFromShape(g),A=u;u.dtype!=="float32"&&(A=xu({backend:t,inputs:{x:u},attrs:{dtype:"float32"}}),l=t.dataIdMap.get(A.dataId).id);let y=t.makeOutput(m,"float32");if(v.sizeFromShape(u.shape)!==0){let b=t.dataIdMap.get(y.dataId).id;Xv(l,x,b)}if(h&&t.disposeData(p.dataId),s){let b=T.expandShapeToKeepDim(y.shape,d);y.shape=b}return u.dtype!=="float32"&&t.disposeData(A.dataId),y}var rte={kernelName:Pi,backendName:"wasm",setupFunc:ate,kernelFunc:nte},Kv;function ste(e){Kv=e.wasm.cwrap(Fi,null,["number","number","number","number"])}function ite(e){let{backend:t,inputs:a,attrs:n}=e,{axis:r,keepDims:s}=n,{x:i}=a,o=t.dataIdMap.get(i.dataId).id,l=o,u=i,{transposed:p,axes:c,originalAxes:d,inputWasTransposed:h}=us(i,r,t);if(h){let y=t.dataIdMap.get(p.dataId).id;y!==o&&(u=p,l=y)}let f=u.shape.length;T.assertAxesAreInnerMostDims("min",c,f);let[m,g]=T.computeOutAndReduceShapes(u.shape,c),x=v.sizeFromShape(g),A=t.makeOutput(m,u.dtype);if(v.sizeFromShape(u.shape)!==0){let y=t.dataIdMap.get(A.dataId).id;Kv(l,Tt[i.dtype],x,y)}if(h&&t.disposeData(p.dataId),s){let y=T.expandShapeToKeepDim(A.shape,d);A.shape=y}return A}var ote={kernelName:Fi,backendName:"wasm",setupFunc:ste,kernelFunc:ite},lte=!1,ute=la(Oi,lte),M1;(function(e){e[e.reflect=0]="reflect",e[e.symmetric=1]="symmetric"})(M1||(M1={}));var Zv;function dte(e){Zv=e.wasm.cwrap(Di,null,["number","array","number","number","array","array","number","number"])}function pte(e){let{inputs:{x:t},backend:a,attrs:{paddings:n,mode:r}}=e,s=n.map((f,m)=>f[0]+t.shape[m]+f[1]),i=a.dataIdMap.get(t.dataId).id,o=a.makeOutput(s,t.dtype),l=a.dataIdMap.get(o.dataId).id,u=new Uint8Array(new Int32Array(t.shape).buffer),p=n.map(f=>f[0]),c=n.map(f=>f[1]),d=new Uint8Array(new Int32Array(p).buffer),h=new Uint8Array(new Int32Array(c).buffer);return Zv(i,u,t.shape.length,Tt[t.dtype],d,h,M1[r],l),o}var cte={kernelName:Di,backendName:"wasm",kernelFunc:pte,setupFunc:dte},hte=!0,fte=la(zi,hte),mte=Bt(Vl);function _3(e,t){let a=new Int32Array(e.wasm.HEAPU8.buffer,t,4),n=a[0],r=a[1],s=a[2],i=a[3];return e.wasm._free(t),{pSelectedIndices:n,selectedSize:r,pSelectedScores:s,pValidOutputs:i}}var Yv;function gte(e){Yv=e.wasm.cwrap(Bi,"number",["number","number","number","number","number"])}function xte(e){let{backend:t,inputs:a,attrs:n}=e,{iouThreshold:r,maxOutputSize:s,scoreThreshold:i}=n,{boxes:o,scores:l}=a,u=t.dataIdMap.get(o.dataId).id,p=t.dataIdMap.get(l.dataId).id,c=Yv(u,p,s,r,i),{pSelectedIndices:d,selectedSize:h,pSelectedScores:f,pValidOutputs:m}=_3(t,c);return t.wasm._free(f),t.wasm._free(m),t.makeOutput([h],"int32",d)}var Ate={kernelName:Bi,backendName:"wasm",setupFunc:gte,kernelFunc:xte},Jv;function yte(e){Jv=e.wasm.cwrap(Ul,"number",["number","number","number","number","number","bool"])}function bte(e){let{backend:t,inputs:a,attrs:n}=e,{iouThreshold:r,maxOutputSize:s,scoreThreshold:i,padToMaxOutputSize:o}=n,{boxes:l,scores:u}=a,p=t.dataIdMap.get(l.dataId).id,c=t.dataIdMap.get(u.dataId).id,d=Jv(p,c,s,r,i,o),{pSelectedIndices:h,selectedSize:f,pSelectedScores:m,pValidOutputs:g}=_3(t,d);t.wasm._free(m);let x=t.makeOutput([f],"int32",h),A=t.makeOutput([],"int32",g);return[x,A]}var vte={kernelName:Ul,backendName:"wasm",setupFunc:yte,kernelFunc:bte},Qv;function wte(e){Qv=e.wasm.cwrap(Wi,"number",["number","number","number","number","number","number"])}function kte(e){let{backend:t,inputs:a,attrs:n}=e,{iouThreshold:r,maxOutputSize:s,scoreThreshold:i,softNmsSigma:o}=n,{boxes:l,scores:u}=a,p=t.dataIdMap.get(l.dataId).id,c=t.dataIdMap.get(u.dataId).id,d=Qv(p,c,s,r,i,o),{pSelectedIndices:h,selectedSize:f,pSelectedScores:m,pValidOutputs:g}=_3(t,d);t.wasm._free(g);let x=t.makeOutput([f],"int32",h),A=t.makeOutput([f],"float32",m);return[x,A]}var Ite={kernelName:Wi,backendName:"wasm",setupFunc:wte,kernelFunc:kte},Ste=!1,Tte=la(Li,Ste,"bool"),e8;function Cte(e){e8=e.wasm.cwrap(Vi,null,["number","number","number","number","number"])}function Nte(e){let{inputs:t,backend:a,attrs:n}=e,{indices:r}=t,{dtype:s,depth:i,onValue:o,offValue:l}=n,u=a.makeOutput([...r.shape,i],s),p=a.dataIdMap.get(u.dataId).id,c=a.dataIdMap.get(r.dataId).id;return e8(c,i,o,l,p),u}var Ete={kernelName:Vi,backendName:"wasm",setupFunc:Cte,kernelFunc:Nte};function Rte(e){let{inputs:{x:t},backend:a}=e,n=a.makeOutput(t.shape,t.dtype);return a.typedArrayFromHeap(n).fill(1),n}var Mte={kernelName:Gl,backendName:"wasm",kernelFunc:Rte};function $te(e){let{inputs:t,backend:a,attrs:n}=e,{axis:r}=n;if(t.length===1)return R1({inputs:{input:t[0]},backend:a,attrs:{dim:r}});let s=t[0].shape,i=t[0].dtype;t.forEach(p=>{v.assertShapesMatch(s,p.shape,"All tensors passed to stack must have matching shapes"),v.assert(i===p.dtype,()=>"All tensors passed to stack must have matching dtypes")});let o=[],l=t.map(p=>{let c=R1({inputs:{input:p},backend:a,attrs:{dim:r}});return o.push(c),c}),u=Rv({inputs:l,backend:a,attrs:{axis:r}});return o.forEach(p=>a.disposeData(p.dataId)),u}var _te={kernelName:Hl,backendName:"wasm",kernelFunc:$te},t8;function Pte(e){t8=e.wasm.cwrap(Ui,null,["number","array","number","number","array","array","number","number"])}function Fte(e){let{inputs:{x:t},backend:a,attrs:{paddings:n,constantValue:r}}=e,s=n.map((f,m)=>f[0]+t.shape[m]+f[1]);if(v.sizeFromShape(t.shape)===0)return zv({backend:a,attrs:{shape:s,value:r,dtype:t.dtype}});let i=a.dataIdMap.get(t.dataId).id,o=a.makeOutput(s,t.dtype),l=a.dataIdMap.get(o.dataId).id,u=new Uint8Array(new Int32Array(t.shape).buffer),p=n.map(f=>f[0]),c=n.map(f=>f[1]),d=new Uint8Array(new Int32Array(p).buffer),h=new Uint8Array(new Int32Array(c).buffer);return t8(i,u,t.shape.length,Tt[t.dtype],d,h,r,l),o}var a8={kernelName:Ui,backendName:"wasm",kernelFunc:Fte,setupFunc:Pte},Ote=!1,Dte=la(Gi,Ote),n8;function zte(e){n8=e.wasm.cwrap(Hi,null,["number","number","number"])}function Lte(e){let{inputs:t,backend:a}=e,{x:n,alpha:r}=t,s=a.dataIdMap.get(n.dataId).id,i=a.dataIdMap.get(r.dataId).id,o=s,l=n,u=l;l.dtype!=="float32"&&(u=xu({backend:a,inputs:{x:n},attrs:{dtype:"float32"}}),o=a.dataIdMap.get(u.dataId).id);let p=a.makeOutput(n.shape,"float32"),c=a.dataIdMap.get(p.dataId).id;return n8(o,i,c),l.dtype!=="float32"&&a.disposeData(u.dataId),p}var Bte={kernelName:Hi,backendName:"wasm",setupFunc:zte,kernelFunc:Lte},r8;function Wte(e){r8=e.wasm.cwrap(ji,null,["number","number","number","number"])}function Vte(e){let{backend:t,inputs:a,attrs:n}=e,{axis:r,keepDims:s}=n,{x:i}=a,o=t.dataIdMap.get(i.dataId).id,l=o,u=i,{transposed:p,axes:c,originalAxes:d,inputWasTransposed:h}=us(i,r,t),f=c;if(h){let y=t.dataIdMap.get(p.dataId).id;y!==o&&(u=p,l=y,f=T.getInnerMostAxes(f.length,u.shape.length))}T.assertAxesAreInnerMostDims("prod",f,u.shape.length);let[m,g]=T.computeOutAndReduceShapes(u.shape,f),x=v.sizeFromShape(g),A=t.makeOutput(m,u.dtype);if(v.sizeFromShape(u.shape)!==0){let y=t.dataIdMap.get(A.dataId).id;r8(l,x,Tt[A.dtype],y)}if(h&&t.disposeData(p.dataId),s){let y=T.expandShapeToKeepDim(A.shape,d);A.shape=y}return A}var Ute={kernelName:ji,backendName:"wasm",setupFunc:Wte,kernelFunc:Vte},Gte=e=>{let{backend:t,attrs:a}=e,{start:n,stop:r,step:s,dtype:i}=a,o=d3(n,r,s,i),l=t.makeOutput([o.length],i);return t.typedArrayFromHeap(l).set(o),l},Hte={kernelName:jl,backendName:"wasm",kernelFunc:Gte},jte=!0,qte=la(ci,jte),Xte=Bt(qi),Kte=Bt(Xi),Zte=Bt(Yi),s8;function Yte(e){s8=e.wasm.cwrap(Zi,null,["number","number","number","number","number","number","number","number","number","number"])}function Jte(e){let{backend:t,inputs:a,attrs:n}=e,{images:r}=a,{alignCorners:s,halfPixelCenters:i,size:o}=n,[l,u]=o,[p,c,d,h]=r.shape,f=[p,l,u,h],m=t.dataIdMap.get(r.dataId),g;m.dtype!=="float32"&&(g=xu({backend:t,inputs:{x:r},attrs:{dtype:"float32"}}),m=t.dataIdMap.get(g.dataId));let x=m.id,A=t.makeOutput(f,"float32");if(v.sizeFromShape(r.shape)===0)return A;let y=t.dataIdMap.get(A.dataId).id;return s8(x,p,c,d,h,l,u,s?1:0,i?1:0,y),g!=null&&t.disposeData(g.dataId),A}var Qte={kernelName:Zi,backendName:"wasm",setupFunc:Yte,kernelFunc:Jte},i8;function eae(e){i8=e.wasm.cwrap(Ki,null,["number","number","number","number","number","number","number","number","number","number"])}function tae(e){let{backend:t,inputs:a,attrs:n}=e,{images:r}=a,{alignCorners:s,halfPixelCenters:i,size:o}=n,[l,u]=o,[p,c,d,h]=r.shape,f=[p,l,u,h],m=t.makeOutput(f,"float32");if(v.sizeFromShape(r.shape)===0)return m;let g=t.dataIdMap.get(r.dataId),x;g.dtype!=="float32"&&(x=xu({backend:t,inputs:{x:r},attrs:{dtype:"float32"}}),g=t.dataIdMap.get(x.dataId));let A=g.id,y=t.dataIdMap.get(m.dataId).id;return i8(A,p,c,d,h,l,u,s?1:0,i?1:0,y),x!=null&&t.disposeData(x.dataId),m}var aae={kernelName:Ki,backendName:"wasm",setupFunc:eae,kernelFunc:tae},o8;function nae(e){o8=e.wasm.cwrap(Ji,null,["number","array","number","array","number","number"])}function rae(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{dims:s}=n,i=v.parseAxisParam(s,r.shape);if(r.shape.length===0)return Bh({inputs:{x:r},backend:a});let o=a.makeOutput(r.shape,r.dtype),l=a.dataIdMap.get(r.dataId).id,u=a.dataIdMap.get(o.dataId).id,p=new Uint8Array(new Int32Array(i).buffer),c=new Uint8Array(new Int32Array(r.shape).buffer);o8(l,p,i.length,c,r.shape.length,u);let d=za({inputs:{x:o},attrs:{shape:r.shape},backend:a});return a.disposeData(o.dataId),d}var sae={kernelName:Ji,backendName:"wasm",kernelFunc:rae,setupFunc:nae},l8;function iae(e){l8=e.wasm.cwrap(mo,null,["number","number","number","number","number","number","number","number","array","number","number"])}function oae(e){let{inputs:t,backend:a,attrs:n}=e,{image:r}=t,{radians:s,fillValue:i,center:o}=n,l=a.makeOutput(r.shape,r.dtype),u=a.dataIdMap.get(r.dataId).id,p=a.dataIdMap.get(l.dataId).id,[c,d,h,f]=r.shape,[m,g]=T.getImageCenter(o,d,h),x=i===0,A=255,y=typeof i=="number"?[i,i,i,x?0:A]:[...i,A],b=new Uint8Array(new Int32Array(y).buffer);return l8(u,c,d,h,f,s,m,g,b,y.length,p),l}var lae={kernelName:mo,backendName:"wasm",kernelFunc:oae,setupFunc:iae},uae=Bt(Xl),dae=Bt(Qi),u8;function pae(e){u8=e.wasm.cwrap(eo,null,["number","number","number","number","number","number","array","number","number"])}function cae(e){let{backend:t,inputs:a,attrs:n}=e,{indices:r,updates:s}=a,{shape:i}=n,o=t.makeOutput(i,s.dtype);if(v.sizeFromShape(i)===0)return o;let{sliceRank:l,numUpdates:u,sliceSize:p,strides:c,outputSize:d}=h2.calculateShapes(s,r,i),h=t.dataIdMap.get(r.dataId).id,f=t.dataIdMap.get(s.dataId).id,m=new Uint8Array(new Int32Array(c).buffer),g=t.dataIdMap.get(o.dataId).id;return u8(h,f,Tt[s.dtype],l,u,p,m,d,g),o}var hae={kernelName:eo,backendName:"wasm",setupFunc:pae,kernelFunc:cae},d8;function fae(e){d8=e.wasm.cwrap("SelectV2",null,["number","number","number","number","number"])}function mae(e){let{inputs:t,backend:a}=e,{condition:n,t:r,e:s}=t,i=a.dataIdMap.get(n.dataId).id,o=a.dataIdMap.get(r.dataId).id,l=a.dataIdMap.get(s.dataId).id,u=a.makeOutput(r.shape,r.dtype),p=a.dataIdMap.get(u.dataId).id,c=n.shape.length,d=r.shape.length,h=c===0||c>1||d===1?1:v.sizeFromShape(r.shape.slice(1));return d8(i,o,l,h,p),u}var gae={kernelName:Kl,backendName:"wasm",kernelFunc:mae,setupFunc:fae},p8;function xae(e){p8=e.wasm.cwrap(ao,null,["number","number"])}function Aae(e){let{backend:t,inputs:{x:a}}=e,n=t.dataIdMap.get(a.dataId).id,r=t.makeOutput(a.shape,a.dtype),s=t.dataIdMap.get(r.dataId).id;return v.sizeFromShape(r.shape)===0||p8(n,s),r}var yae={kernelName:"Sigmoid",backendName:"wasm",setupFunc:xae,kernelFunc:Aae},bae=Bt(to),c8;function vae(e){c8=e.wasm.cwrap(so,null,["number","number","number","number"])}function wae(e){let{backend:t,inputs:{logits:a},attrs:{dim:n}}=e,r=t.dataIdMap.get(a.dataId).id,s=t.makeOutput(a.shape,a.dtype),i=t.dataIdMap.get(s.dataId).id,o=a.shape[n],l=v.sizeFromShape(a.shape)/o;return v.sizeFromShape(s.shape)===0||c8(r,i,o,l),s}var kae={kernelName:so,backendName:"wasm",setupFunc:vae,kernelFunc:wae};function Iae(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{blockShape:s,paddings:i}=n,o=v.sizeFromShape(s),l=[[0,0]];l.push(...i);for(let g=1+s.length;g0?l+1:0;if(u<0)throw new Error(T.getSparseSegmentReductionNegativeSegmentIdsErrorMessage());let p=r.shape.slice();p[0]=u;let c=a.dataIdMap.get(r.dataId).id,d=a.dataIdMap.get(s.dataId).id,h=a.dataIdMap.get(i.dataId).id,f=a.makeOutput(p,r.dtype),m=a.dataIdMap.get(f.dataId).id,g=a.makeOutput([4],"int32"),x=a.dataIdMap.get(g.dataId).id;m8(c,Tt[r.dtype],r.shape[0],d,h,m,x,t,0);let A=a.readSync(g.dataId),y;switch(A[0]){case 0:{y=T.getSparseSegmentReductionNegativeSegmentIdsErrorMessage();break}case 1:{y=T.getSparseSegmentReductionNonIncreasingSegmentIdsErrorMessage();break}case 2:y=T.getSparseSegmentReductionSegmentIdOutOfRangeErrorMessage(A[1],A[2]);break;case 3:y=T.getSparseSegmentReductionIndicesOutOfRangeErrorMessage(A[1],A[2],A[3]);break;default:y=""}if(a.disposeData(g.dataId),y)throw a.disposeData(f.dataId),new Error(y);return f}function $ae(e){return x8(e,!0)}var _ae={kernelName:Dd,backendName:"wasm",setupFunc:g8,kernelFunc:$ae};function Pae(e){return x8(e,!1)}var Fae={kernelName:zd,backendName:"wasm",setupFunc:g8,kernelFunc:Pae};function Oae(e){let{inputs:t,attrs:a,backend:n}=e,{x:r}=t,{numOrSizeSplits:s,axis:i}=a,o=v.parseAxisParam(i,r.shape)[0],l=T.prepareSplitSize(r,s,o),u=new Array(r.shape.length).fill(0),p=r.shape.slice();return l.map(c=>{let d=[...p];d[o]=c;let h=qs({inputs:{x:r},attrs:{begin:u,size:d},backend:n});return u[o]+=c,h})}var Dae={kernelName:Ql,backendName:"wasm",kernelFunc:Oae},zae=Bt(no),Lae=Bt(Bd),Bae=!0,Wae=la(io,Bae),A8;function Vae(e){A8=e.wasm.cwrap(fo,null,["number","number","number","number"])}function Uae(e){let{backend:t,inputs:a,attrs:n}=e,{alpha:r}=n,{x:s}=a,i=t.dataIdMap.get(s.dataId).id,o=t.makeOutput(s.shape,s.dtype),l=t.dataIdMap.get(o.dataId).id;return A8(i,r,Tt[s.dtype],l),o}var Gae={kernelName:fo,backendName:"wasm",setupFunc:Vae,kernelFunc:Uae},y8;function Hae(e){y8=e.wasm.cwrap(oo,null,["number","array","number","array","array","array","array","array","number","number"])}function jae(e){let{backend:t,inputs:a,attrs:n}=e,{x:r}=a,{begin:s,end:i,strides:o,beginMask:l,endMask:u,ellipsisMask:p,newAxisMask:c,shrinkAxisMask:d}=n,{finalShapeSparse:h,finalShape:f,isIdentity:m,sliceDim0:g,isSimpleSlice:x,begin:A,end:y,strides:b}=It.sliceInfo(r.shape,s,i,o,l,u,p,c,d),w;if(m)w=za({inputs:{x:r},backend:t,attrs:{shape:f}});else if(g||x){v.assert(r.shape.length>=1,()=>`Input must have rank at least 1, got: ${r.shape.length}`);let S=It.computeOutShape(A,y,b),C=qs({inputs:{x:r},backend:t,attrs:{begin:A,size:S}});w=za({inputs:{x:C},backend:t,attrs:{shape:f}}),t.disposeData(C.dataId)}else{let S=t.makeOutput(h,"float32"),C=t.dataIdMap.get(r.dataId).id,E=new Uint8Array(new Int32Array(v.computeStrides(r.shape)).buffer),_=new Uint8Array(new Int32Array(A).buffer),$=new Uint8Array(new Int32Array(y).buffer),M=new Uint8Array(new Int32Array(b).buffer),I=new Uint8Array(new Int32Array(h).buffer),N=new Uint8Array(new Int32Array(v.computeStrides(h)).buffer),O=t.dataIdMap.get(S.dataId).id;y8(C,E,r.shape.length,_,$,M,I,N,h.length,O),w=za({inputs:{x:S},backend:t,attrs:{shape:f}}),t.disposeData(S.dataId)}return w}var qae={kernelName:oo,backendName:"wasm",setupFunc:Hae,kernelFunc:jae};function Xae(e){let{backend:t,inputs:a,attrs:n}=e,{data:r,dataSplits:s}=a,{separator:i,nGramWidths:o,leftPad:l,rightPad:u,padWidth:p,preserveShortSequences:c}=n,d=t.readSync(r.dataId),h=t.readSync(s.dataId),[f,m]=c3(d,h,i,o,l,u,p,c),g=t.makeOutput([f.length],"string"),x=t.dataIdMap.get(g.dataId);x.stringBytes=f;let A=t.makeOutput(s.shape,"int32");return t.typedArrayFromHeap(A).set(m),[g,A]}var Kae={kernelName:tu,backendName:"wasm",kernelFunc:Xae};function Zae(e){let{backend:t,inputs:a,attrs:n}=e,{input:r,delimiter:s}=a,{skipEmpty:i}=n,o=t.readSync(r.dataId),l=t.readSync(s.dataId),[u,p,c]=h3(o,l[0],i),d=p.length,h=t.makeOutput([d,2],"int32");t.typedArrayFromHeap(h).set(u);let f=t.makeOutput([d],"string"),m=t.dataIdMap.get(f.dataId);m.stringBytes=p;let g=t.makeOutput([2],"int32");return t.typedArrayFromHeap(g).set(c),[h,f,g]}var Yae={kernelName:Wd,backendName:"wasm",kernelFunc:Zae};function Jae(e){let{backend:t,inputs:a,attrs:n}=e,{input:r}=a,{numBuckets:s}=n,i=t.readSync(r.dataId),o=f3(i,s),l=t.makeOutput(r.shape,"int32");return t.typedArrayFromHeap(l).set(o),l}var Qae={kernelName:Vd,backendName:"wasm",kernelFunc:Jae},ene=!0,tne=la(lo,ene),b8;function ane(e){b8=e.wasm.cwrap(ro,null,["number","number","number","number"])}function nne(e){let{backend:t,inputs:a,attrs:n}=e,{axis:r,keepDims:s}=n,{x:i}=a,o=t.dataIdMap.get(i.dataId).id,l=o,u=i,{transposed:p,axes:c,originalAxes:d,inputWasTransposed:h}=us(i,r,t),f=c;if(h){let y=t.dataIdMap.get(p.dataId).id;y!==o&&(u=p,l=y,f=T.getInnerMostAxes(f.length,u.shape.length))}T.assertAxesAreInnerMostDims("sum",f,u.shape.length);let[m,g]=T.computeOutAndReduceShapes(u.shape,f),x=v.sizeFromShape(g),A=t.makeOutput(m,u.dtype);if(v.sizeFromShape(u.shape)!==0){let y=t.dataIdMap.get(A.dataId).id;b8(l,x,Tt[A.dtype],y)}if(h&&t.disposeData(p.dataId),s){let y=T.expandShapeToKeepDim(A.shape,d);A.shape=y}return A}var rne={kernelName:ro,backendName:"wasm",setupFunc:ane,kernelFunc:nne},sne=Bt(uo),ine=Bt(po),v8;function one(e){v8=e.wasm.cwrap(ns,null,["number","array","number","array","number","number"])}function lne(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,s=a.dataIdMap.get(r.dataId).id,{reps:i}=n,o=new Array(r.shape.length);for(let d=0;d{let{x:n}=e,{k:r,sorted:s}=a,i=t.dataIdMap.get(n.dataId).id,o=new Uint8Array(new Int32Array(n.shape).buffer),l=n.shape.slice();l[l.length-1]=r;let u=t.makeOutput(l,n.dtype),p=t.dataIdMap.get(u.dataId).id,c=t.makeOutput(l,"int32"),d=t.dataIdMap.get(c.dataId).id;return w8(i,o,n.shape.length,Tt[n.dtype],r,s,p,d),[u,c]},cne={kernelName:co,backendName:"wasm",setupFunc:dne,kernelFunc:pne},k8;function hne(e){k8=e.wasm.cwrap(ho,null,["number","number","bool","number","number","number","number","number","number","array","number","array","number","number","number","number","number"])}function fne(e){let{backend:t,inputs:a,attrs:n}=e,{image:r,transforms:s}=a,{interpolation:i,fillMode:o,fillValue:l,outputShape:u}=n,[p,c,d,h]=r.shape,[f,m]=u!=null?u:[c,d],g=[p,f,m,h],x=new Uint8Array(new Int32Array(v.computeStrides(r.shape)).buffer),A=new Uint8Array(new Int32Array(v.computeStrides(g)).buffer),y=t.makeOutput(g,r.dtype),b=t.dataIdMap.get(y.dataId).id,w=t.dataIdMap.get(r.dataId).id,S=t.dataIdMap.get(s.dataId).id,C=i==="nearest"?1:2,E;switch(o){case"constant":E=1;break;case"reflect":E=2;break;case"wrap":E=3;break;case"nearest":E=4;break;default:E=1;break}return k8(w,S,s.shape[0]>1,p,f,m,h,d,c,x,r.shape.length-1,A,g.length-1,C,E,l,b),y}var mne={kernelName:ho,backendName:"wasm",setupFunc:hne,kernelFunc:fne};function gne(e){let{inputs:t,backend:a,attrs:n}=e,{value:r}=t,{axis:s}=n;s<0&&(s+=r.shape.length);let i=r.shape[s],o=r.shape.length,l=new Array(o-1),u=0;for(let h=0;h({dataId:h,dtype:f,shape:l}))}var xne={kernelName:au,backendName:"wasm",kernelFunc:gne};function Ane(e){let{inputs:{x:t},backend:a}=e,n=a.makeOutput(t.shape,t.dtype);return a.typedArrayFromHeap(n).fill(0),n}var yne={kernelName:nu,backendName:"wasm",kernelFunc:Ane},bne=[jJ,qJ,KJ,JJ,iQ,uQ,cQ,mQ,yQ,SQ,TQ,CQ,RQ,MQ,PQ,DQ,zQ,LQ,VQ,HQ,XQ,YQ,eee,tee,nee,ree,see,iee,uee,dee,cee,mee,Aee,vee,Iee,Cee,Eee,Mee,QJ,$ee,Fee,Dee,Lee,Bee,Vee,Uee,Hee,qee,Zee,Jee,tte,rte,ote,ute,cte,fte,mte,Ate,vte,Ite,Tte,Ete,Mte,_te,a8,Dte,Bte,Ute,Hte,qte,Xte,Kte,Zte,gQ,Qte,aae,sae,lae,uae,dae,hae,gae,yae,bae,kQ,kae,Sae,Nae,Mae,_ae,Fae,Dae,zae,Lae,Wae,Gae,qae,Kae,Yae,Qae,tne,rne,sne,ine,une,cne,mne,nQ,xne,yne];for(let e of bne)mn(e);var $1=W();$1.registerFlag("WASM_HAS_SIMD_SUPPORT",async()=>{try{return WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,10,9,1,7,0,65,0,253,15,26,11]))}catch(e){return!1}});$1.registerFlag("WASM_HAS_MULTITHREAD_SUPPORT",async()=>{if($1.get("IS_NODE"))return!1;try{return new MessageChannel().port1.postMessage(new SharedArrayBuffer(1)),WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,5,4,1,3,1,1,10,11,1,9,0,65,0,254,16,2,0,26,11]))}catch(e){return!1}});var Ox=yl(nS()),vne=yl(rS()),Dx=yl(sS()),zx=Ox.default||Ox,wne=Dx.default||Dx,I8=class extends bl{constructor(e){super(),this.wasm=e,this.dataIdNextNumber=1,this.wasm.tfjs.initWithThreadsCount(S8),_1=this.wasm.tfjs.getThreadsCount(),this.dataIdMap=new vd(this,kt())}write(e,t,a){let n={id:this.dataIdNextNumber++};return this.move(n,e,t,a,1),n}numDataIds(){return this.dataIdMap.numDataIds()}async time(e){let t=v.now();return e(),{kernelMs:v.now()-t}}move(e,t,a,n,r){let s=this.dataIdNextNumber++;if(n==="string"){let u=t;this.dataIdMap.set(e,{id:s,stringBytes:u,shape:a,dtype:n,memoryOffset:null,refCount:r});return}let i=v.sizeFromShape(a),o=i*v.bytesPerElement(n),l=this.wasm._malloc(o);this.dataIdMap.set(e,{id:s,memoryOffset:l,shape:a,dtype:n,refCount:r}),this.wasm.tfjs.registerTensor(s,i,l),t!=null&&this.wasm.HEAPU8.set(new Uint8Array(t.buffer,t.byteOffset,o),l)}async read(e){return this.readSync(e)}readSync(e,t,a){let{memoryOffset:n,dtype:r,shape:s,stringBytes:i}=this.dataIdMap.get(e);if(r==="string")return(t==null||t===0)&&(a==null||a>=i.length)?i:i.slice(t,a);t=t||0,a=a||v.sizeFromShape(s);let o=v.bytesPerElement(r),l=this.wasm.HEAPU8.slice(n+t*o,n+a*o);return Sne(l.buffer,r)}disposeData(e,t=!1){if(this.dataIdMap.has(e)){let a=this.dataIdMap.get(e);if(a.refCount--,!t&&a.refCount>0)return!1;this.wasm._free(a.memoryOffset),this.wasm.tfjs.disposeData(a.id),this.dataIdMap.delete(e)}return!0}refCount(e){return this.dataIdMap.has(e)?this.dataIdMap.get(e).refCount:0}incRef(e){let t=this.dataIdMap.get(e);t!=null&&t.refCount++}floatPrecision(){return 32}getMemoryOffset(e){return this.dataIdMap.get(e).memoryOffset}dispose(){this.wasm.tfjs.dispose(),"PThread"in this.wasm&&this.wasm.PThread.terminateAllThreads(),this.wasm=null}memory(){return{unreliable:!1}}makeOutput(e,t,a){let n;if(a==null)n=this.write(null,e,t);else{let r=this.dataIdNextNumber++;n={id:r},this.dataIdMap.set(n,{id:r,memoryOffset:a,shape:e,dtype:t,refCount:1});let s=v.sizeFromShape(e);this.wasm.tfjs.registerTensor(r,s,a)}return{dataId:n,shape:e,dtype:t}}typedArrayFromHeap({shape:e,dtype:t,dataId:a}){let n=this.wasm.HEAPU8.buffer,{memoryOffset:r}=this.dataIdMap.get(a),s=v.sizeFromShape(e);switch(t){case"float32":return new Float32Array(n,r,s);case"int32":return new Int32Array(n,r,s);case"bool":return new Uint8Array(n,r,s);default:throw new Error(`Unknown dtype ${t}`)}}};function kne(e){return(t,a)=>(v.fetch(e,{credentials:"same-origin"}).then(n=>{n.ok||t.env.a(`failed to load wasm binary file at '${e}'`),n.arrayBuffer().then(r=>{WebAssembly.instantiate(r,t).then(s=>{a(s.instance,s.module)})})}),{})}function Lx(e,t,a){if(Bc!=null)return Bc;let n="tfjs-backend-wasm.wasm";return e&&t?n="tfjs-backend-wasm-threaded-simd.wasm":e&&(n="tfjs-backend-wasm-simd.wasm"),ed!=null&&ed[n]!=null?ed[n]:a+n}async function Ine(){let[e,t]=await Promise.all([W().getAsync("WASM_HAS_SIMD_SUPPORT"),W().getAsync("WASM_HAS_MULTITHREAD_SUPPORT")]);return new Promise((a,n)=>{let r={};r.locateFile=(o,l)=>{if(o.endsWith(".worker.js")){let u=vne.wasmWorkerContents.replace(/\n/g,"\\n"),p=new Blob([u],{type:"application/javascript"});return URL.createObjectURL(p)}return o.endsWith(".wasm")?Lx(e,t,Yu!=null?Yu:l):l+o},P3&&(r.instantiateWasm=kne(Lx(e,t,Yu!=null?Yu:"")));let s=!1;r.onAbort=()=>{s||td||(td=!0,n({message:"Make sure the server can serve the `.wasm` file relative to the bundled js file. For more details see https://github.com/tensorflow/tfjs/blob/master/tfjs-backend-wasm/README.md#using-bundlers"}))};let i;t&&e&&Bc==null?(r.mainScriptUrlOrBlob=new Blob(["var WasmBackendModuleThreadedSimd = "+zx.toString()],{type:"text/javascript"}),i=zx(r)):i=wne(r),i.then(o=>{s=!0,td=!1;let l=null;o.tfjs={init:o.cwrap("init",null,[]),initWithThreadsCount:o.cwrap("init_with_threads_count",null,["number"]),getThreadsCount:o.cwrap("get_threads_count","number",[]),registerTensor:o.cwrap("register_tensor",null,["number","number","number"]),disposeData:o.cwrap("dispose_data",l,["number"]),dispose:o.cwrap("dispose",l,[])},a({wasm:o})}).catch(n)})}function Sne(e,t){switch(t){case"float32":return new Float32Array(e);case"int32":return new Int32Array(e);case"bool":return new Uint8Array(e);default:throw new Error(`Unknown dtype ${t}`)}}var Tne=["tfjs-backend-wasm.wasm","tfjs-backend-wasm-simd.wasm","tfjs-backend-wasm-threaded-simd.wasm"],Bc=null,Yu=null,ed={},td=!1,P3=!1;function Cne(e,t=!1){if(l2("setWasmPath has been deprecated in favor of setWasmPaths and will be removed in a future release."),td)throw new Error("The WASM backend was already initialized. Make sure you call `setWasmPath()` before you call `tf.setBackend()` or `tf.ready()`");Bc=e,P3=t}function Wh(e,t=!1){if(td)throw new Error("The WASM backend was already initialized. Make sure you call `setWasmPaths()` before you call `tf.setBackend()` or `tf.ready()`");if(typeof e=="string")Yu=e;else{ed=e;let a=Tne.filter(n=>ed[n]==null);if(a.length>0)throw new Error(`There were no entries found for the following binaries: ${a.join(",")}. Please either call setWasmPaths with a map providing a path for each binary, or with a string indicating the directory where all the binaries can be found.`)}P3=t}var S8=-1,_1=-1;function Nne(e){S8=e}function Ene(){if(_1===-1)throw new Error("WASM backend not initialized.");return _1}var Rne="4.1.0",Mne=2;go("wasm",async()=>{let{wasm:e}=await Ine();return new I8(e)},Mne);var zn=W();zn.registerFlag("WEBGPU_DEFERRED_SUBMIT_BATCH_SIZE",()=>15);zn.registerFlag("WEBGPU_CPU_FORWARD",()=>!0);zn.registerFlag("WEBGPU_MATMUL_PROGRAM_TYPE",()=>-1);zn.registerFlag("WEBGPU_USE_NAIVE_CONV2D_TRANSPOSE",()=>!1);zn.registerFlag("WEBGPU_USE_LOW_POWER_GPU",()=>!1);zn.registerFlag("WEBGPU_CPU_HANDOFF_SIZE_THRESHOLD",()=>1e3);zn.registerFlag("WEBGPU_USE_PROFILE_TOOL",()=>!1);zn.registerFlag("WEBGPU_IMPORT_EXTERNAL_TEXTURE",()=>!0);zn.registerFlag("WEBGPU_USE_NAIVE_CONV2D_DEBUG",()=>!1);zn.registerFlag("WEBGPU_THRESHOLD_TO_INCREASE_WORKGROUPS_FOR_MATMUL",()=>0);zn.registerFlag("WEBGPU_CONV_SEPARATE_IM2COL_SHADER",()=>!1);var $ne=class{constructor(e){e&&(this.vendor=e.vendor,this.architecture=e.architecture,this.intelGPUGeneration=this.getIntelGPUGeneration())}getIntelGPUGeneration(){if(this.isIntel()){if(this.architecture.startsWith("gen"))return Number(this.architecture.match(/\d+/));if(this.architecture.startsWith("xe"))return 12}return 0}isIntel(){return this.vendor==="intel"}},_ne=class{constructor(e){this.device=e,this.numUsedBuffers=0,this.numFreeBuffers=0,this.freeBuffers=new Map,this.usedBuffers=new Map,this.numBytesUsed=0,this.numBytesAllocated=0}acquireUploadBuffer(e,t){return this.acquireBuffer(e,t,!0)}acquireBuffer(e,t,a=!1){let n=Bx(e,t);if(this.freeBuffers.has(n)||this.freeBuffers.set(n,[]),this.usedBuffers.has(n)||this.usedBuffers.set(n,[]),this.numBytesUsed+=e,this.numUsedBuffers++,this.freeBuffers.get(n).length>0){this.numFreeBuffers--;let s=this.freeBuffers.get(n).shift();return this.usedBuffers.get(n).push(s),s}this.numBytesAllocated+=e;let r=this.device.createBuffer({size:e,usage:t,mappedAtCreation:a});return this.usedBuffers.get(n).push(r),r}releaseBuffer(e,t,a){if(this.freeBuffers.size===0)return;let n=Bx(t,a);this.freeBuffers.has(n)||this.freeBuffers.set(n,[]),this.freeBuffers.get(n).push(e),this.numFreeBuffers++,this.numUsedBuffers--;let r=this.usedBuffers.get(n),s=r.indexOf(e);if(s<0)throw new Error("Cannot release a buffer that was never provided by this buffer manager");r.splice(s,1),this.numBytesUsed-=t}releaseUploadBuffer(e,t,a){e.mapAsync(GPUMapMode.WRITE).then(()=>{this.releaseBuffer(e,t,a)},n=>{})}getNumUsedBuffers(){return this.numUsedBuffers}getNumFreeBuffers(){return this.numFreeBuffers}dispose(){this.freeBuffers.forEach((e,t)=>{e.forEach(a=>{a.destroy()})}),this.usedBuffers.forEach((e,t)=>{e.forEach(a=>{a.destroy()})}),this.freeBuffers=new Map,this.usedBuffers=new Map,this.numUsedBuffers=0,this.numFreeBuffers=0,this.numBytesUsed=0,this.numBytesAllocated=0}};function Bx(e,t){return`${e}_${t}`}var Pne=class{constructor(e){this.device=e,this.numUsedTextures=0,this.numFreeTextures=0,this.freeTextures=new Map,this.usedTextures=new Map,this.numBytesUsed=0,this.numBytesAllocated=0}acquireTexture(e,t,a,n){let r=Vx(a),s=e*t*r,i=Wx(e,t,a,n);if(this.freeTextures.has(i)||this.freeTextures.set(i,[]),this.usedTextures.has(i)||this.usedTextures.set(i,[]),this.numBytesUsed+=s,this.numUsedTextures++,this.freeTextures.get(i).length>0){this.numFreeTextures--;let l=this.freeTextures.get(i).shift();return this.usedTextures.get(i).push(l),l}this.numBytesAllocated+=s;let o=this.device.createTexture({size:[e,t],format:a,usage:n});return this.usedTextures.get(i).push(o),o}releaseTexture(e,t,a,n,r){if(this.freeTextures.size===0)return;let s=Wx(t,a,n,r);this.freeTextures.has(s)||this.freeTextures.set(s,[]),this.freeTextures.get(s).push(e),this.numFreeTextures++,this.numUsedTextures--;let i=this.usedTextures.get(s),o=i.indexOf(e);if(o<0)throw new Error("Cannot release a texture that was never provided by this texture manager");i.splice(o,1);let l=Vx(n),u=t*a*l;this.numBytesUsed-=u}getNumUsedTextures(){return this.numUsedTextures}getNumFreeTextures(){return this.numFreeTextures}dispose(){this.freeTextures.forEach((e,t)=>{e.forEach(a=>{a.destroy()})}),this.usedTextures.forEach((e,t)=>{e.forEach(a=>{a.destroy()})}),this.freeTextures=new Map,this.usedTextures=new Map,this.numUsedTextures=0,this.numFreeTextures=0,this.numBytesUsed=0,this.numBytesAllocated=0}};function Wx(e,t,a,n){return`${e}_${t}_${a}_${n}`}function Vx(e){if(e==="rgba8unorm")return 16;throw new Error(`${e} is not supported!`)}function Fne(e,t){if(Math.max(...e)>3)throw new Error("Cannot symbolically compute strides for rank > 4 tensor.");let a=e.length,n=e.map(s=>`${t}[${s}]`),r=new Array(a-1);r[a-2]=n[a-1];for(let s=a-3;s>=0;--s)r[s]=`(${r[s+1]} * ${n[s+1]})`;return r}var One=(e,t,a,n)=>{let r={dtype:n.dtype,shape:n.shape},s=zne(a,r,t),i=e.createShaderModule({code:s,label:t.constructor.name});return e.createComputePipeline({compute:{module:i,entryPoint:"_start"},label:t.constructor.name,layout:"auto"})};function ra(e){if(e<=1)return"i32";if(e===2)return"vec2";if(e===3)return"vec3";if(e===4)return"vec4";if(e===5)return"vec5";if(e===6)return"vec6";throw Error(`GPU for rank ${e} is not yet supported`)}function yr(e){if(e===0)return"x";if(e===1)return"y";if(e===2)return"z";if(e===3)return"w";if(e===4)return"u";if(e===5)return"v";throw Error(`Index ${e} is not yet supported`)}function Ce(...e){let t;switch(e.length){case 0:t=` fn main() `;break;case 1:t=` fn main(${e[0]} : i32) `;break;default:throw Error("Unreachable")}return t}function Ux(e){let t;return t=` ${Dne()} fn _start(@builtin(local_invocation_id) LocalId : vec3, @builtin(global_invocation_id) GlobalId : vec3, @builtin(local_invocation_index) LocalIndex: u32, @builtin(workgroup_id) WorkgroupId : vec3, @builtin(num_workgroups) NumWorkgroups : vec3) { localId = LocalId; localIndex = LocalIndex; globalId = GlobalId; numWorkgroups = NumWorkgroups; workgroupId = WorkgroupId; ${e?"main(getGlobalIndex());":"main();"}; } `,t}function Dne(){return` @compute @workgroup_size(workgroupSizeX, workgroupSizeY, workgroupSizeZ) `}function zne(e,t,a){let n=[],r=a.workgroupSize[0]*a.workgroupSize[1]*a.workgroupSize[2];if(n.push(` const workgroupSizeX = ${a.workgroupSize[0]}u; const workgroupSizeY = ${a.workgroupSize[1]}u; const workgroupSizeZ = ${a.workgroupSize[2]}u; var localId: vec3; var localIndex: u32; var globalId: vec3; var numWorkgroups: vec3; var workgroupId: vec3; // Only used when the y/z dimension of workgroup size is 1. fn getGlobalIndex() -> i32 { ${T8(a)?" return i32(globalId.x);":` return i32((workgroupId.z * numWorkgroups.x * numWorkgroups.y + workgroupId.y * numWorkgroups.x + workgroupId.x) * ${r} + localIndex); `} } `),a.isFromPixels){n.push(` struct Uniform { size : i32, numChannels : i32, outShapeStrides : vec2, }; @group(0) @binding(0) var result: array<${ad(t.dtype,a.isVec4)}>; @group(0) @binding(2) var uniforms: Uniform; `);let h=jx(a);return[Gx,n.join(` `),Hx(t.shape),a.getUserCode(),Ux(h)].join(` `)}let s="struct Uniforms { NAN : f32, INFINITY : f32, ";a.variableNames.forEach((h,f)=>{let m=ra(e[f].shape.length);s+=`${h.charAt(0).toLowerCase()+h.slice(1)}Shape : ${m}, `});let i=ra(t.shape.length);s+=`outShape : ${i}, `;let o=t.shape.length-1,l=ra(o);s+=` outShapeStrides: ${l}, `,a.size&&(s+="size : i32, "),a.uniforms&&(s+=a.uniforms),s+="};",s=qne(s),n.push(s),a.atomic?n.push(` @group(0) @binding(0) var result: array>; `):n.push(` @group(0) @binding(0) var result: array<${ad(t.dtype,a.isVec4)}>; `),a.variableNames.forEach((h,f)=>{n.push(` @group(0) @binding(${1+f}) var ${h}: array<${a.variableTypes?a.variableTypes[f]:ad(e[f].dtype,a.isVec4)}>; `)}),s!==""&&n.push(` @group(0) @binding(${1+a.variableNames.length}) var uniforms: Uniforms; `);let u=Gne(t.shape,a.dispatchLayout),p=[Gx+Bne,n.join(` `),Hx(t.shape),u,Hne(t.shape.length)];a.atomic||p.push(jne(t.shape,t.dtype,a.isVec4));let c=e.map((h,f)=>Une(h,t.shape,a.variableTypes?a.variableTypes[f]==="vec4":a.isVec4,a.dispatchLayout.x.length===t.shape.length)).join(` `);p.push(c),p.push(a.getUserCode());let d=jx(a);return p.push(Ux(d)),p.join(` `)}function Lne(e,t,a,n){let r=e.shaderKey;if(e.isFromPixels)return r;let s=a.map(p=>p.dtype).concat(n.dtype),i=a.map(p=>T.getBroadcastDims(p.shape,n.shape)),o=a.map(p=>v.arraysEqual(p.shape,n.shape)).join("_"),l=i.map(p=>p.join("_")).join(";"),u=T8(e)?"flatDispatch":"";return r+="_"+(e.workgroupSize?e.workgroupSize.join(","):"")+t.map(p=>p.length).join(",")+s.join(",")+e.variableNames.join(",")+l+o+u,r}var Gx=` struct vec5 {x: i32, y: i32, z: i32, w: i32, u: i32}; struct vec6 {x: i32, y: i32, z: i32, w: i32, u: i32, v: i32}; // Checks whether coordinates lie within the bounds of the shape. fn coordsInBounds2D(coord : vec2, shape : vec2) -> bool { return all(coord >= vec2(0)) && all(coord < shape); } fn coordsInBounds3D(coord : vec3, shape : vec3) -> bool { return all(coord >= vec3(0)) && all(coord < shape); } fn coordsInBounds4D(coord : vec4, shape : vec4) -> bool { return all(coord >= vec4(0)) && all(coord < shape); } fn getIndexFromCoords1D(coord : i32, shape : i32) -> i32 { return coord; } fn getIndexFromCoords2D(coords : vec2, shape : vec2) -> i32 { return dot(coords, vec2(shape.y, 1)); } fn getIndexFromCoords3D(coords : vec3, shape : vec3) -> i32 { return dot(coords, vec3(shape.y * shape.z, shape.z, 1)); } fn getIndexFromCoords4D(coords : vec4, shape : vec4) -> i32 { return dot(coords, vec4( shape.y * shape.z * shape.w, shape.z * shape.w, shape.w, 1)); } fn getIndexFromCoords5D(coords : vec5, shape : vec5) -> i32 { let shapeStrides: vec5 = vec5(shape.y * shape.z * shape.w * shape.u, shape.z * shape.w * shape.u, shape.w * shape.u, shape.u, 1); return coords.x*shapeStrides.x + coords.y*shapeStrides.y + coords.z*shapeStrides.z + coords.w*shapeStrides.w + coords.u*shapeStrides.u; } fn getIndexFromCoords6D(coords : vec6, shape : vec6) -> i32 { let shapeStrides: vec6 = vec6(shape.y * shape.z * shape.w * shape.u * shape.v, shape.z * shape.w * shape.u * shape.v, shape.w * shape.u * shape.v, shape.u * shape.v, shape.v, 1); return coords.x*shapeStrides.x + coords.y*shapeStrides.y + coords.z*shapeStrides.z + coords.w*shapeStrides.w + coords.u*shapeStrides.u + coords.v*shapeStrides.v; } fn idiv(a: i32, b: i32, sign: f32) -> i32 { var res: i32 = a / b; let modulo: i32 = a % b; if (sign < 0. && modulo != 0) { res = res - 1; } return res; } // NaN defination in IEEE 754-1985 is : // - sign = either 0 or 1. // - biased exponent = all 1 bits. // - fraction = anything except all 0 bits (since all 0 bits represents infinity). // https://en.wikipedia.org/wiki/IEEE_754-1985#Representation_of_non-numbers fn isnan(val: f32) -> bool { let floatToUint: u32 = bitcast(val); return (floatToUint & 0x7fffffffu) > 0x7f800000u; } fn isnanVec4(val : vec4) -> vec4 { return vec4(isnan(val[0]), isnan(val[1]), isnan(val[2]), isnan(val[3])); } `,Bne=` fn isinf(val: f32) -> bool { return abs(val) == uniforms.INFINITY; } `;function Hx(e){let t=e.length;if(t<=1)return"fn getCoordsFromIndex(index : i32) -> i32 { return index; }";let a=v.computeStrides(e),n=ra(t),r=[];for(let i=0;i vec2 { let d0 = index / uniforms.outShapeStrides; let d1 = index - d0 * uniforms.outShapeStrides; return vec2(d0, d1); }`;let s;return s="var index2 = index;"+a.map((i,o)=>{let l=`let ${r[o]} = index2 / uniforms.outShapeStrides.${yr(o)}`,u=o===a.length-1?`let ${r[o+1]} = index2 - ${r[o]} * uniforms.outShapeStrides.${yr(o)}`:`index2 = index2 - ${r[o]} * uniforms.outShapeStrides.${yr(o)}`;return`${l}; ${u};`}).join(""),` fn getCoordsFromIndex(index : i32) -> ${n} { ${s} return ${n}(${r.join(",")}); } `}function Wne(e,t){let a=e.name,n=e.shape.length,r=ra(n),s="get"+a.charAt(0).toUpperCase()+a.slice(1),i=["d0","d1","d2","d3","d4","d5"].slice(0,n),o=i.map(p=>`${p} : i32`).join(", ");if(n<1)return t?` fn ${s}() -> vec4 { return vec4(${a}[0]); } `:` fn ${s}() ->f32 { return f32(${a}[0]); } `;let l=`uniforms.${a.charAt(0).toLowerCase()+a.slice(1)}Shape`,u=`${n}D`;return n===0&&(u="1D"),t?` fn ${s}(${o}) -> vec4 { return vec4(${a}[getIndexFromCoords${u}(${r}(${i.join(",")}), ${l}) / 4]); } `:` fn ${s}(${o}) -> f32 { return f32(${a}[getIndexFromCoords${u}(${r}(${i.join(",")}), ${l})]); } `}function Vne(e,t,a,n){let r=e.name,s=r.charAt(0).toUpperCase()+r.slice(1),i="get"+s+"ByOutput",o=e.shape.length,l=t.length,u=ra(l);if(v.arraysEqual(e.shape,t)&&n)return a?` fn ${i}Index(globalIndex : i32) -> vec4 { return vec4(${r}[globalIndex]); } fn ${i}Coords(coords : ${u}) -> vec4 { return vec4(${r}[${l>1?"getOutputIndexFromCoords(coords)":"coords"} / 4]); } `:` fn ${i}Index(globalIndex : i32) -> f32 { return f32(${r}[globalIndex]); } fn ${i}Coords(coords : ${u}) -> f32 { return f32(${r}[${l>1?"getOutputIndexFromCoords(coords)":"coords"}]); } `;let p=T.getBroadcastDims(e.shape,t),c=l-o,d="";if(o===0)return a?` fn ${i}Index(globalIndex : i32) -> vec4 { return get${s}(); } fn ${i}Coords(coords : ${u}) -> vec4 { return get${s}(); } `:` fn ${i}Index(globalIndex : i32) -> f32{ return get${s}(); } fn ${i}Coords(coords : ${u}) -> f32{ return get${s}(); } `;l<2&&p.length>=1?d="coords = 0;":d=p.map(g=>`coords.${yr(g+c)} = 0;`).join(` `);let h="";if(l<2&&o>0)h="coords";else if(l>1){let g=ra(o),x=e.shape.map((A,y)=>`coords.${yr(y+c)}`).join(", ");h=`${g}(${x})`}else h="coords";let f=`uniforms.${r.charAt(0).toLowerCase()+r.slice(1)}Shape`,m=`${o}D`;return a?` fn ${i}Index(globalIndex : i32) -> vec4 { var coords = getCoordsFromIndex(globalIndex); ${d} return ${r}[getIndexFromCoords${m}(${h}, ${f}) / 4]; } fn ${i}Coords(coordsIn : ${u}) -> vec4 { var coords = coordsIn; ${d} return ${r}[getIndexFromCoords${m}(${h}, ${f}) / 4]; } `:` fn ${i}Index(globalIndex : i32) -> f32 { var coords = getCoordsFromIndex(globalIndex); ${d} return f32(${r}[getIndexFromCoords${m}(${h}, ${f})]); } fn ${i}Coords(coordsIn : ${u}) -> f32 { var coords = coordsIn; ${d} return f32(${r}[getIndexFromCoords${m}(${h}, ${f})]); } `}function Une(e,t,a,n){let r=Wne(e,a);return e.shape.length<=t.length&&(r+=Vne(e,t,a,n)),r}function Gne(e,t){let{x:a,y:n=[],z:r=[]}=t,s=e.length,i=a.length+n.length+r.length;if(i!==s)return"";if(a.length===s)return`fn getOutputCoords() -> ${ra(s)}{ let globalIndex = getGlobalIndex(); return getCoordsFromIndex(globalIndex); } `;let o="",l=[a,n,r];for(let d=0;d ${p} { ${o} `;return u.length===0?c+=`return ${p}(0); }`:c+=`return ${p}(${u.join(",")}); }`,c}function Hne(e){let t="";switch(e){case 0:case 1:t+=` fn getOutputIndexFromCoords(coords : i32) -> i32 { return coords; } `;break;case 2:t+=` fn getOutputIndexFromCoords(coords : vec2) -> i32 { return dot(coords, vec2(uniforms.outShapeStrides, 1)); } `;break;case 3:t+=` fn getOutputIndexFromCoords(coords : vec3) -> i32 { return dot(coords, vec3(uniforms.outShapeStrides.x, uniforms.outShapeStrides.y, 1)); } `;break;case 4:t+=` fn getOutputIndexFromCoords(coords : vec4) -> i32 { return dot(coords, vec4( uniforms.outShapeStrides.x, uniforms.outShapeStrides.y, uniforms.outShapeStrides.z, 1)); } `;break;case 5:t+=` fn getOutputIndexFromCoords(coords : vec5) -> i32 { return coords.x * uniforms.outShapeStrides.x + coords.y * uniforms.outShapeStrides.y + coords.z * uniforms.outShapeStrides.z + coords.w * uniforms.outShapeStrides.w + coords.u; } `;break;case 6:t+=` fn getOutputIndexFromCoords(coords : vec6) -> i32 { return coords.x * uniforms.outShapeStrides.x + coords.y * uniforms.outShapeStrides.y + coords.z * uniforms.outShapeStrides.z + coords.w * uniforms.outShapeStrides.w + coords.u * uniforms.outShapeStrides.u + coords.v; } `;break;default:v.assert(!1,()=>`Unsupported ${e}D shape`);break}return t}function T8(e){return e.dispatch[1]===1&&e.dispatch[2]===1}function ad(e,t){return e==="float32"?t?"vec4":"f32":e==="int32"||e==="bool"?t?"vec4":"i32":e}function jne(e,t,a){let n=e.length,r=ad(t,a),s;if(a?s=`fn setOutputAtIndex(flatIndex : i32, value : vec4) { result[flatIndex] = ${r}(value); } fn setOutputAtIndexI32(flatIndex : i32, value : vec4) { result[flatIndex] = ${r}(value); }`:s=`fn setOutputAtIndex(flatIndex : i32, value : f32) { result[flatIndex] = ${r}(value); } fn setOutputAtIndexI32(flatIndex : i32, value : i32) { result[flatIndex] = ${r}(value); }`,n>=2){let i=["d0","d1","d2","d3","d4","d5"].slice(0,n),o=ra(n);a?s+=` fn setOutputAtCoords(${i.map(l=>`${l} : i32`).join(", ")}, value : vec4) { let flatIndex = getOutputIndexFromCoords(${o}(${i.join(", ")})); setOutputAtIndex(flatIndex / 4, value); } fn setOutputAtCoordsI32(${i.map(l=>`${l} : i32`).join(", ")}, value : vec4) { let flatIndex = getOutputIndexFromCoords(${o}(${i.join(", ")})); setOutputAtIndexI32(flatIndex / 4, value); } `:s+=` fn setOutputAtCoords(${i.map(l=>`${l} : i32`).join(", ")}, value : f32) { let flatIndex = getOutputIndexFromCoords(${o}(${i.join(", ")})); setOutputAtIndex(flatIndex, value); } fn setOutputAtCoordsI32(${i.map(l=>`${l} : i32`).join(", ")}, value : i32) { let flatIndex = getOutputIndexFromCoords(${o}(${i.join(", ")})); setOutputAtIndexI32(flatIndex, value); } `}return s}function qne(e){let t=/(\w+)\s*:\s*vec(5|6)/g;e=e.replace(t,n=>"@align(16) "+n);let a=/vec(5|6)\s*,\s*(\w+)/g;return e=e.replace(a,(n,r,s)=>`vec${r}, @align(16) ${s}`),e}function jx(e){return!(e.dispatchLayout.hasOwnProperty("y")&&e.dispatchLayout.y.length!==0||e.dispatchLayout.hasOwnProperty("z")&&e.dispatchLayout.z.length!==0)}var C8={};Xe(C8,{ArrayBufferToTypedArray:()=>R8,GPUBytesPerElement:()=>E8,MatMulProgramType:()=>Pn,computeDispatch:()=>Ne,computeWorkPerThreadForConv2d:()=>O3,computeWorkgroupInfoForMatMul:()=>N8,computeWorkgroupSizeForConv2d:()=>F3,flatDispatchLayout:()=>Ve,isWebGPUSupported:()=>D3,tilesFitEvenlyIntoShape:()=>Xne});var Ds=e=>{let t=1;for(let a=0;aa%e[n]===0)}function Ne(e,t,a=[1,1,1],n=[1,1,1]){let[r,s,i]=[Math.ceil(Ds(e.x.map(o=>t[o]))/(a[0]*n[0])),e.y?Math.ceil(Ds(e.y.map(o=>t[o]))/(a[1]*n[1])):1,e.z?Math.ceil(Ds(e.z.map(o=>t[o]))/(a[2]*n[2])):1];return[r,s,i]}function N8(e,t,a,n=!1){let r=[8,8,1],s=[4,4,1];return n||(e<=8&&(s[1]=1),t<=16&&a<=16&&(r[0]=4)),{workgroupSize:r,elementsPerThread:s}}function F3(e,t,a=!1){if(a)return[8,8,1];let n=Ds(e.x.map(s=>t[s])),r=Ds(e.y.map(s=>t[s]));return n<=4?[4,16,1]:r<=4?[16,4,1]:[16,16,1]}function O3(e,t,a=!1){if(a)return[4,4,1];let n=Ds(e.x.map(s=>t[s])),r=Ds(e.y.map(s=>t[s]));return n<=4?[1,2,1]:r<=4?[2,1,1]:[2,2,1]}function Ve(e){return{x:e.map((t,a)=>a)}}function E8(e){if(e==="float32"||e==="int32"||e==="bool"||e==="string")return 4;if(e==="complex64")return 8;throw new Error(`Unknown dtype ${e}`)}function R8(e,t){if(t==="float32")return new Float32Array(e);if(t==="int32")return new Int32Array(e);if(t==="bool"||t==="string")return Uint8Array.from(new Int32Array(e));throw new Error(`Unknown dtype ${t}`)}function D3(){return(typeof window!="undefined"||typeof WorkerGlobalScope!="undefined")&&!!navigator.gpu}var Pn;(function(e){e[e.MatMulReduceProgram=0]="MatMulReduceProgram",e[e.MatMulSplitKProgram=1]="MatMulSplitKProgram",e[e.MatMulSmallOutputSizeProgram=2]="MatMulSmallOutputSizeProgram",e[e.MatMulPackedProgram=3]="MatMulPackedProgram",e[e.MatMulMax=4]="MatMulMax"})(Pn||(Pn={}));var Kne=W().getNumber("WEBGPU_CPU_HANDOFF_SIZE_THRESHOLD"),Zne=(e,t)=>{let a=e.limits.maxComputeWorkgroupsPerDimension,n=t.dispatchLayout,r=t.dispatch;if(r.every(i=>i<=a))return r;v.assert(r[0]>a&&n.y===void 0&&n.z===void 0,()=>"Dispatch size exceeds WebGPU limits in Y or Z dimension.");let s=Math.ceil(Math.sqrt(r[0]));return s>a?(s=Math.ceil(Math.cbrt(r[0])),v.assert(s<=a,()=>"Total dispatch size exceeds WebGPU maximum."),[s,s,s]):[s,s,1]},Vh=class extends bl{constructor(e,t){if(super(),this.commandQueueOwnedIds=new WeakSet,this.dispatchNumberInEncoder=0,this.disposed=!1,this.downloadWaitMs=0,this.tensorDataPendingDisposal=[],this.stagingPendingDisposal=[],this.uniformPendingDisposal=[],this.uploadWaitMs=0,!D3())throw new Error("WebGPU is not supported on this device");this.pipelineCache={},this.device=e,this.queue=e.queue,this.currentCommandEncoder=null,this.currentComputePass=null,this.supportTimeQuery=e.features.has("timestamp-query-inside-passes"),this.adapterInfo=new $ne(t),this.thresholdToIncreaseWorkgroups=this.adapterInfo.intelGPUGeneration>=12?16:8,this.bufferManager=new _ne(this.device),this.textureManager=new Pne(this.device),this.tensorMap=new vd(this,kt()),this.supportTimeQuery&&(this.querySet=this.device.createQuerySet({type:"timestamp",count:2})),W().getBool("WEBGPU_USE_PROFILE_TOOL")&&(this.dummyCanvas=document.createElement("canvas"),this.dummyCanvas.width=1,this.dummyCanvas.height=1,this.dummyContext=this.dummyCanvas.getContext("webgpu"),this.dummyContext.configure({device:e,format:"bgra8unorm"}),document.body.appendChild(this.dummyCanvas))}nextDataId(){return Vh.nextDataId++}floatPrecision(){return 32}defaultGpuBufferUsage(){return GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST}disposeData(e,t=!1){if(this.tensorDataPendingDisposal.indexOf(e)>=0)return!1;if(!this.tensorMap.has(e))return!0;let a=this.tensorMap.get(e);if(this.decRef(e),!t&&a.refCount>0)return!1;if(this.commandQueueOwnedIds.has(e))return this.tensorDataPendingDisposal.push(e),!1;let{complexTensorInfos:n}=this.tensorMap.get(e);return n!=null&&(this.disposeData(n.real.dataId,t),this.disposeData(n.imag.dataId,t)),this.releaseResource(e),this.tensorMap.delete(e),!0}memory(){return{numBytesInGPU:this.bufferManager.numBytesUsed,numBytesAllocatedInGPU:this.bufferManager.numBytesAllocated,unreliable:!1}}releaseResource(e){let t=this.tensorMap.get(e);if(!(!t||!t.resourceInfo)){if("texture"in t.resourceInfo){let a=t.resourceInfo;a.texture instanceof GPUTexture&&this.textureManager.releaseTexture(a.texture,a.width,a.height,a.format,a.usage),a.texture=null}else{let a=t.resourceInfo;this.bufferManager.releaseBuffer(a.buffer,a.size,a.usage),a.buffer=null}t.resourceInfo=null}}refCount(e){return this.tensorMap.has(e)?this.tensorMap.get(e).refCount:0}incRef(e){let t=this.tensorMap.get(e);t.refCount++}decRef(e){if(this.tensorMap.has(e)){let t=this.tensorMap.get(e);t.refCount--}}write(e,t,a){if(a==="complex64"&&e!=null)throw new Error("Cannot write to a complex64 dtype. Please use tf.complex(real, imag).");let n={id:this.nextDataId()};return this.tensorMap.set(n,{dtype:a,shape:t,values:e,refCount:1}),n}move(e,t,a,n,r){if(n==="complex64")throw new Error("Cannot write to a complex64 dtype. Please use tf.complex(real, imag).");this.tensorMap.set(e,{dtype:n,shape:a,values:t,refCount:r})}submitQueue(){this.ensureComputePassEnded(),this.queue.submit([this.currentCommandEncoder.finish()]),this.currentCommandEncoder=null,this.dispatchNumberInEncoder=0,this.commandQueueOwnedIds=new WeakSet,this.tensorDataPendingDisposal.forEach(e=>{this.releaseResource(e),this.tensorMap.delete(e)}),this.uniformPendingDisposal.forEach(e=>this.bufferManager.releaseBuffer(e.buffer,e.size,e.usage)),this.stagingPendingDisposal.forEach(e=>this.bufferManager.releaseUploadBuffer(e.buffer,e.size,e.usage)),this.tensorDataPendingDisposal=[],this.uniformPendingDisposal=[],this.stagingPendingDisposal=[]}ensureCommandEncoderReady(){this.currentCommandEncoder||(this.currentCommandEncoder=this.device.createCommandEncoder())}ensureComputePassEnded(){this.currentComputePass&&(this.currentComputePass.end(),this.currentComputePass=null)}getComputePass(){return this.currentComputePass||(this.currentComputePass=this.currentCommandEncoder.beginComputePass()),this.currentComputePass}async getBufferData(e,t){let a=this.bufferManager.acquireBuffer(t,GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ);this.ensureCommandEncoderReady(),this.ensureComputePassEnded(),this.currentCommandEncoder.copyBufferToBuffer(e,0,a,0,t),this.submitQueue(),await a.mapAsync(GPUMapMode.READ);let n=a.getMappedRange().slice(0);return a.unmap(),a!=null&&this.bufferManager.releaseBuffer(a,t,GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ),W().getBool("WEBGPU_USE_PROFILE_TOOL")&&(v.assert(this.dummyContext!==void 0,()=>"Fail to get context for profiling tool"),this.dummyContext.getCurrentTexture()),n}convertAndCacheOnCPU(e,t){let a=this.tensorMap.get(e);return this.releaseResource(e),a.values=t,a.values}readSync(e){let t=this.tensorMap.get(e),{values:a}=t;if(a==null)throw new Error("WebGPU readSync is only available for CPU-resident tensors.");return a}async read(e){if(!this.tensorMap.has(e))throw new Error(`Tensor ${e} was not registered!`);let t=this.tensorMap.get(e),{values:a}=t;if(a!=null)return this.convertAndCacheOnCPU(e,a);let n;if(t.dtype==="complex64"){let r=await Promise.all([this.read(t.complexTensorInfos.real.dataId),this.read(t.complexTensorInfos.imag.dataId)]),s=r[0],i=r[1];n=T.mergeRealAndImagArrays(s,i)}else{let r=t.resourceInfo,s=await this.getBufferData(r.buffer,r.size);n=R8(s,t.dtype)}return this.convertAndCacheOnCPU(e,n),n}readToGPU(e){let t=this.tensorMap.get(e),{values:a,dtype:n,shape:r,resourceInfo:s}=t;if(n==="complex64")throw new Error("Does not support reading buffer for complex64 dtype.");if(s==null)throw a!=null?new Error("Data is not on GPU but on CPU."):new Error("There is no data on GPU or CPU.");let i=s.size,o=this.bufferManager.acquireBuffer(i,s.usage);this.ensureCommandEncoderReady(),this.ensureComputePassEnded(),this.currentCommandEncoder.copyBufferToBuffer(s.buffer,0,o,0,i),this.submitQueue();let l=this.makeTensorInfo(r,n),u=kt().makeTensorFromTensorInfo(l),p=this.tensorMap.get(l.dataId);return p.resourceInfo={size:i,usage:this.defaultGpuBufferUsage(),buffer:o},{tensorRef:u,buffer:o,bufSize:i}}bufferSync(e){let t=this.readSync(e.dataId);if(e.dtype==="string")try{let a=t.map(n=>v.decodeString(n));return Me(e.shape,e.dtype,a)}catch(a){throw new Error("Failed to decode encoded string bytes into utf-8")}return Me(e.shape,e.dtype,t)}async time(e){this.supportTimeQuery||console.warn("This device doesn't support timestamp-query-inside-passes extension. Start Chrome browser with flag --disable-dawn-features=disallow_unsafe_apis then try again. Otherwise, zero will be shown for the kernel time when profiling mode is enabled. Using performance.now is not workable for webgpu since it doesn't support synchronous data read from GPU.");let t=this.activeTimers,a=[],n=!1;this.programTimersStack==null?(this.programTimersStack=a,n=!0):this.activeTimers.push(a),this.activeTimers=a,e();let r=v.flatten(this.activeTimers.map(l=>l.query)).filter(l=>l!=null),s=v.flatten(this.activeTimers.map(l=>l.name)).filter(l=>l!=null);this.activeTimers=t,n&&(this.programTimersStack=null);let i={uploadWaitMs:this.uploadWaitMs,downloadWaitMs:this.downloadWaitMs,kernelMs:null,wallMs:null},o=await Promise.all(r);return i.kernelMs=v.sum(o),i.getExtraProfileInfo=()=>o.map((l,u)=>({name:s[u],ms:l})).map(l=>`${l.name}: ${l.ms}`).join(", "),this.uploadWaitMs=0,this.downloadWaitMs=0,i}makeTensorInfo(e,t,a){return t==="string"&&a!=null&&a.length>0&&v.isString(a[0])&&(a=a.map(n=>v.encodeString(n))),{dataId:this.write(a,e,t),shape:e,dtype:t}}tensorToBinding(e){if(!e)return null;let t=this.tensorMap.get(e.dataId);if("texture"in t.resourceInfo){let n=t.resourceInfo;return n.texture instanceof GPUExternalTexture?n.texture:n.texture.createView()}let a=t.resourceInfo;return{offset:0,size:a.size,buffer:a.buffer}}async getQueryTime(e){return this.supportTimeQuery?this.getTimeFromQuerySet(e):0}uploadToGPU(e){let t=this.tensorMap.get(e);if(t.resourceInfo)return;let a=E8(t.dtype)*v.sizeFromShape(t.shape),n=this.bufferManager.acquireBuffer(a,this.defaultGpuBufferUsage());if(t.resourceInfo={size:a,usage:this.defaultGpuBufferUsage(),buffer:n},t.values){let r=this.bufferManager.acquireUploadBuffer(a,GPUBufferUsage.MAP_WRITE|GPUBufferUsage.COPY_SRC),s=r.getMappedRange();t.dtype==="int32"||t.dtype==="bool"?new Int32Array(s).set(t.values):new Float32Array(s).set(t.values),r.unmap(),this.ensureCommandEncoderReady(),this.ensureComputePassEnded(),this.currentCommandEncoder.copyBufferToBuffer(r,0,n,0,a);let i={size:a,usage:GPUBufferUsage.MAP_WRITE|GPUBufferUsage.COPY_SRC,buffer:r};this.stagingPendingDisposal.push(i)}}makeUniforms(e){let t=0,a=0,n=[];e.forEach(o=>{o.data.length===0&&(o.data=[1]);let l;switch(o.data.length){case 1:l=4;break;case 2:l=8;break;case 3:l=16;break;case 4:l=16;break;case 5:l=16;break;case 6:l=16;break;default:v.assert(!1,()=>`Unsupported ${o.data.length}D shape`)}(a===5||a===6)&&(l=16),t=Math.ceil(t/l)*l,a=o.data.length,n.push(t),t+=o.data.length*4});let r=new ArrayBuffer(t);e.forEach((o,l)=>{let u=n[l];o.type==="int32"?new Int32Array(r,u,o.data.length).set(o.data):o.type==="uint32"?new Uint32Array(r,u,o.data.length).set(o.data):new Float32Array(r,u,o.data.length).set(o.data)});let s=this.bufferManager.acquireBuffer(t,GPUBufferUsage.COPY_DST|GPUBufferUsage.UNIFORM);this.queue.writeBuffer(s,0,r,0,t);let i={size:t,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.UNIFORM,buffer:s};return this.uniformPendingDisposal.push(i),{offset:0,size:t,buffer:s}}runWebGPUProgram(e,t,a,n,r){if(r||(r=this.makeTensorInfo(e.outputShape,a)),v.sizeFromShape(r.shape)===0)return this.tensorMap.get(r.dataId).values=v.getTypedArrayFromDType(r.dtype,0),r;this.uploadToGPU(r.dataId),e.dispatch=Zne(this.device,e);let s=[],i=[];if(!e.isFromPixels){s.push({type:"float32",data:[NaN]},{type:"float32",data:[1/0]}),i=t.concat(r).map(g=>g.shape);let f="int32";i.map(g=>{s.push({type:f,data:g})});let m=v.computeStrides(r.shape);if(s.push({type:f,data:m}),e.size){let g=v.sizeFromShape(e.outputShape);s.push({type:f,data:[e.isVec4?g/4:g]})}}let o=t.map((f,m)=>{if(f.dtype==="complex64")throw new Error("GPGPUProgram does not support complex64 input. For complex64 dtypes, please separate the program into real and imaginary parts.");return this.uploadToGPU(f.dataId),{dtype:this.tensorMap.get(f.dataId).dtype,shape:f.shape,name:e.variableNames[m]}}),l=Lne(e,i,o,r),u;l in this.pipelineCache?u=this.pipelineCache[l]:(u=One(this.device,e,o,r),this.pipelineCache[l]=u),n&&(s=[...s,...n]);let p=[this.tensorToBinding(r),...t.map(f=>this.tensorToBinding(f)),this.makeUniforms(s)],c=this.device.createBindGroup({layout:u.getBindGroupLayout(0),entries:p.map((f,m)=>({binding:m,resource:f}))});this.ensureCommandEncoderReady();let d=this.getComputePass(),h=this.activeTimers!=null;return h&&this.supportTimeQuery&&d.writeTimestamp(this.querySet,0),d.setPipeline(u),d.setBindGroup(0,c),d.dispatchWorkgroups(e.dispatch[0],e.dispatch[1],e.dispatch[2]),h&&this.supportTimeQuery&&d.writeTimestamp(this.querySet,1),this.dispatchNumberInEncoder++,t.forEach(f=>{this.commandQueueOwnedIds.add(f.dataId)}),this.commandQueueOwnedIds.add(r.dataId),W().get("WEBGPU_DEFERRED_SUBMIT_BATCH_SIZE")<=this.dispatchNumberInEncoder&&this.submitQueue(),h&&this.activeTimers.push({name:e.constructor.name,query:this.getQueryTime(this.querySet)}),r}async getTimeFromQuerySet(e){let t=this.bufferManager.acquireBuffer(16,GPUBufferUsage.COPY_SRC|GPUBufferUsage.QUERY_RESOLVE),a=this.bufferManager.acquireBuffer(16,GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST);this.ensureCommandEncoderReady(),this.ensureComputePassEnded(),this.currentCommandEncoder.resolveQuerySet(e,0,2,t,0),this.currentCommandEncoder.copyBufferToBuffer(t,0,a,0,16),this.submitQueue(),await a.mapAsync(GPUMapMode.READ);let n=new BigUint64Array(a.getMappedRange()),r=Number(n[1]-n[0]);return a.unmap(),this.bufferManager.releaseBuffer(a,16,GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST),this.bufferManager.releaseBuffer(t,16,GPUBufferUsage.COPY_SRC|GPUBufferUsage.QUERY_RESOLVE),r/1e6}shouldExecuteOnCPU(e,t=Kne){return W().getBool("WEBGPU_CPU_FORWARD")&&e.every(a=>this.tensorMap.get(a.dataId).resourceInfo==null&&v.sizeFromShape(a.shape){W().set("CHECK_COMPUTATION_FOR_ERRORS",!1);let e={powerPreference:W().get("WEBGPU_USE_LOW_POWER_GPU")?"low-power":"high-performance"},t=await navigator.gpu.requestAdapter(e),a={};t.features.has("timestamp-query-inside-passes")&&(a.requiredFeatures=["timestamp-query-inside-passes"]);let n=t.limits;a.requiredLimits={maxComputeWorkgroupStorageSize:n.maxComputeWorkgroupStorageSize,maxComputeWorkgroupsPerDimension:n.maxComputeWorkgroupsPerDimension,maxStorageBufferBindingSize:n.maxStorageBufferBindingSize};let r=await t.requestDevice(a),s=await t.requestAdapterInfo();return new Vh(r,s)},3);var De;(function(e){e[e.ADD=0]="ADD",e[e.ATAN2=1]="ATAN2",e[e.COMPLEX_MULTIPLY_IMAG=2]="COMPLEX_MULTIPLY_IMAG",e[e.COMPLEX_MULTIPLY_REAL=3]="COMPLEX_MULTIPLY_REAL",e[e.DIV=4]="DIV",e[e.EQUAL=5]="EQUAL",e[e.GREATER=6]="GREATER",e[e.GREATER_EQUAL=7]="GREATER_EQUAL",e[e.INT_DIV=8]="INT_DIV",e[e.LESS=9]="LESS",e[e.LESS_EQUAL=10]="LESS_EQUAL",e[e.LOGICAL_AND=11]="LOGICAL_AND",e[e.MAX=12]="MAX",e[e.MIN=13]="MIN",e[e.MOD=14]="MOD",e[e.MUL=15]="MUL",e[e.NOT_EQUAL=16]="NOT_EQUAL",e[e.POW=17]="POW",e[e.PRELU=18]="PRELU",e[e.SQUARED_DIFFERENCE=19]="SQUARED_DIFFERENCE",e[e.SUB=20]="SUB"})(De||(De={}));var M8=` if (isnan(a)) { return a; } if (isnan(b)) { return b; } `,$8=` if (isNaN.r) { resultTemp.r = valueForNaN; } if (isNaN.g) { resultTemp.g = valueForNaN; } if (isNaN.b) { resultTemp.b = valueForNaN; } if (isNaN.a) { resultTemp.a = valueForNaN; } `,z3=` let isNaN = isnanVec4(a) | isnanVec4(b); ${$8} `,Yne="return a + b;",Jne="return areal * breal - aimag * bimag;",Qne="return areal * bimag + aimag * breal;",ere="return a / b;",tre="return f32(a == b);",are="return vec4(a == b);",nre="return f32(a > b);",rre="return vec4(a > b);",sre="return f32(a >= b);",ire="return vec4(a >= b);",ore=` let s = sign(a) * sign(b); let ia = i32(round(a)); let ib = i32(round(b)); return f32(idiv(ia, ib, s)); `,lre=` let ia = vec4(round(a)); let ib = vec4(round(b)); let cond = ib != vec4(0); var resultTemp = vec4(0); let s = sign(a) * sign(b); // Windows (D3D) wants guaranteed non-zero int division at compile-time. if (cond[0]) { resultTemp[0] = idiv(ia[0], ib[0], s[0]); } if (cond[1]) { resultTemp[1] = idiv(ia[1], ib[1], s[1]); } if (cond[2]) { resultTemp[2] = idiv(ia[2], ib[2], s[2]); } if (cond[3]) { resultTemp[3] = idiv(ia[3], ib[3], s[3]); } return vec4(resultTemp); `,ure="return f32(a < b);",dre="return vec4(a < b);",pre="return f32(a <= b);",cre="return vec4(a <= b);",hre="return f32(f32(a) >= 1.0 && f32(b) >= 1.0);",fre=`return (vec4(a >= vec4(1.0)) * vec4(b >= vec4(1.0)));`,mre=` ${M8} if (b == 0.) { return uniforms.NAN; } var resultTemp = a % b; if ((a < 0. && b < 0.) || (a >= 0. && b > 0.)) { return resultTemp; } else { return (resultTemp + b) % b; } `,gre=` let valueForNaN = uniforms.NAN; var resultTemp = vec4(a % b); ${z3} if (b[0] == 0.) { resultTemp[0] = uniforms.NAN; } if (b[1] == 0.) { resultTemp[1] = uniforms.NAN; } if (b[2] == 0.) { resultTemp[2] = uniforms.NAN; } if (b[3] == 0.) { resultTemp[3] = uniforms.NAN; } if (!((a[0] < 0. && b[0] < 0.) || (a[0] >= 0. && b[0] > 0.))) { resultTemp[0] = (resultTemp[0] + b[0]) % b[0]; } if (!((a[1] < 0. && b[1] < 0.) || (a[1] >= 0. && b[1] > 0.))) { resultTemp[1] = (resultTemp[1] + b[1]) % b[1]; } if (!((a[2] < 0. && b[2] < 0.) || (a[2] >= 0. && b[2] > 0.))) { resultTemp[2] = (resultTemp[2] + b[2]) % b[2]; } if (!((a[3] < 0. && b[3] < 0.) || (a[3] >= 0. && b[3] > 0.))) { resultTemp[3] = (resultTemp[3] + b[3]) % b[3]; } return resultTemp; `,xre="return a * b;",Are=` if (isnan(a) || isnan(b)) { return 1.0; } return f32(a != b); `,yre=` var resultTemp = vec4(a != b); let valueForNaN = 1.0; ${z3} return resultTemp; `,bre=` if(a < 0.0 && floor(b) < b) { return uniforms.NAN; } if (b == 0.0) { return 1.0; } if (round(abs(b) % 2.0) != 1.0) { return pow(abs(a), b); } return sign(a) * pow(abs(a), b); `,vre=` let isModRound1Bool = vec4(round(abs(b) % vec4(2.0))) == vec4(1); let isModRound1 = vec4(isModRound1Bool); let multiplier = sign(a) * isModRound1 + (vec4(1.0) - isModRound1); var resultTemp = multiplier * pow(abs(a), b); // Ensure that a^0 = 1, including 0^0 = 1 as this correspond to TF and JS let isExpZero = b == vec4(0.0); if (isExpZero.r) { resultTemp.r = 1.0; } if (isExpZero.g) { resultTemp.g = 1.0; } if (isExpZero.b) { resultTemp.b = 1.0; } if (isExpZero.a) { resultTemp.a = 1.0; } let isNaN = (a < vec4(0.0)) & (floor(b) < b); let valueForNaN = uniforms.NAN; ${$8} return resultTemp; `,wre="if (a < 0.0) { return b * a; } return a;",kre=` let aLessThanZero = vec4(a < vec4(0.0)); return (aLessThanZero * (b * a)) + ((vec4(1.0) - aLessThanZero) * a); `,Ire="return (a - b) * (a - b);",Sre="return a - b;";function Bm(e,t,a="uniforms.NAN"){let n=t?z3:M8;return t?` let valueForNaN = ${a}; var resultTemp = vec4(${e}(a, b)); `+n+` return resultTemp; `:n+` return ${e}(a, b); `}function L3(e,t){switch(e){case De.ADD:return Yne;case De.ATAN2:return Bm("atan2",t);case De.COMPLEX_MULTIPLY_IMAG:return Qne;case De.COMPLEX_MULTIPLY_REAL:return Jne;case De.DIV:return ere;case De.EQUAL:return t?are:tre;case De.GREATER:return t?rre:nre;case De.GREATER_EQUAL:return t?ire:sre;case De.INT_DIV:return t?lre:ore;case De.LESS:return t?dre:ure;case De.LESS_EQUAL:return t?cre:pre;case De.LOGICAL_AND:return t?fre:hre;case De.MAX:return Bm("max",t);case De.MIN:return Bm("min",t);case De.MOD:return t?gre:mre;case De.MUL:return xre;case De.NOT_EQUAL:return t?yre:Are;case De.POW:return t?vre:bre;case De.PRELU:return t?kre:wre;case De.SQUARED_DIFFERENCE:return Ire;case De.SUB:return Sre;default:throw new Error(`BinaryType ${e} is not implemented!`)}}var de;(function(e){e[e.ABS=0]="ABS",e[e.ACOS=1]="ACOS",e[e.ACOSH=2]="ACOSH",e[e.ASIN=3]="ASIN",e[e.ASINH=4]="ASINH",e[e.ATAN=5]="ATAN",e[e.ATANH=6]="ATANH",e[e.CEIL=7]="CEIL",e[e.COS=8]="COS",e[e.COSH=9]="COSH",e[e.ELU=10]="ELU",e[e.ERF=11]="ERF",e[e.EXP=12]="EXP",e[e.EXPM1=13]="EXPM1",e[e.FLOOR=14]="FLOOR",e[e.IS_FINITE=15]="IS_FINITE",e[e.IS_INF=16]="IS_INF",e[e.IS_NAN=17]="IS_NAN",e[e.LINEAR=18]="LINEAR",e[e.LOG=19]="LOG",e[e.LOG1P=20]="LOG1P",e[e.LOGICAL_NOT=21]="LOGICAL_NOT",e[e.NEG=22]="NEG",e[e.RELU=23]="RELU",e[e.RELU6=24]="RELU6",e[e.LEAKYRELU=25]="LEAKYRELU",e[e.RECIPROCAL=26]="RECIPROCAL",e[e.RSQRT=27]="RSQRT",e[e.SIN=28]="SIN",e[e.SINH=29]="SINH",e[e.SIGMOID=30]="SIGMOID",e[e.SQRT=31]="SQRT",e[e.SQUARE=32]="SQUARE",e[e.TAN=33]="TAN",e[e.TANH=34]="TANH",e[e.TO_INT=35]="TO_INT"})(de||(de={}));var Tre="return abs(a);",Cre=` if (abs(a) > 1.) { return uniforms.NAN; } return acos(a); `,Nre=` if (a < 1.) { return uniforms.NAN; } return acosh(a); `,Ere=` if (abs(a) > 1.) { return uniforms.NAN; } return asin(a); `,Rre="return asinh(a);",Mre=` if (isnan(a)) { return uniforms.NAN; } return atan(a); `,$re=` if (abs(a) > 1.) { return uniforms.NAN; } if (a == 1.) { return uniforms.INFINITY; } if (a == -1.) { return -uniforms.INFINITY; } return atanh(a); `,_re="return ceil(a);",Pre="return cos(a);",Fre=` let e2x = exp(-a); return (e2x + 1.0 / e2x) / 2.0; `,Ore="return exp(a) - 1.0;",Dre="if (a >= 0.0) { return a; } return (exp(a) - 1.0);",zre=` var resFloat = exp(a) - vec4(1.0); if (a.r >= 0.0) { resFloat.r = a.r; } if (a.g >= 0.0) { resFloat.g = a.g; } if (a.b >= 0.0) { resFloat.b = a.b; } if (a.a >= 0.0) { resFloat.a = a.a; } return resFloat; `,Lre=` // Error function is calculated approximately with elementary function. // See "Handbook of Mathematical Functions with Formulas, // Graphs, and Mathematical Tables", Abramowitz and Stegun. let p = ${T.ERF_P}; let a1 = ${T.ERF_A1}; let a2 = ${T.ERF_A2}; let a3 = ${T.ERF_A3}; let a4 = ${T.ERF_A4}; let a5 = ${T.ERF_A5}; let sign = sign(a); let absA = abs(a); let t = 1.0 / (1.0 + p * absA); return sign * (1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * exp(-absA * absA)); `,Bre="return exp(a);",Wre="return floor(a);",Vre="return f32(!isnan(a) && !isinf(a));",Ure="return f32(isinf(a));",Gre="return f32(isnan(a));",Hre="return a;",jre=`if (a < 0.0) { return uniforms.NAN; } return log(a);`,qre=` if (isnan(a)) { return a; } return log(1.0 + a); `,Xre="return f32(!(a >= 1.0));",Kre="return -a;",Zre="if (a < 0.0) { return uniforms.alpha * a; } return a;",Yre=` let aLessThanZero = vec4(a < vec4(0.0)); return (aLessThanZero * (uniforms.alpha * a)) + ((vec4(1.0) - aLessThanZero) * a); `,Jre="return 1.0 / a;",Qre="return select(a, 0.0, a < 0.0);",ese="return clamp(a, 0.0, 6.0);",tse="return clamp(a, vec4(0.0, 0.0, 0.0, 0.0), vec4(6.0, 6.0, 6.0, 6.0));",ase=` return select(a, vec4(0.0), a < vec4(0.0)); `,nse="return inverseSqrt(a);",rse="return 1.0 / (1.0 + exp(-1.0 * a));",sse="return sin(a);",ise=` let e2x = exp(a); return (e2x - 1.0 / e2x) / 2.0; `,ose="return sqrt(a);",lse="return a * a;",use="return tan(a);",dse=` let e2x = exp(-2.0 * abs(a)); return sign(a) * (1.0 - e2x) / (1.0 + e2x); `,pse="return f32(i32((a)));";function Ms(e,t){switch(e){case de.ABS:return Tre;case de.ACOS:return Cre;case de.ACOSH:return Nre;case de.ASIN:return Ere;case de.ASINH:return Rre;case de.ATAN:return Mre;case de.ATANH:return $re;case de.COS:return Pre;case de.COSH:return Fre;case de.CEIL:return _re;case de.ELU:return t?zre:Dre;case de.ERF:return Lre;case de.EXP:return Bre;case de.EXPM1:return Ore;case de.FLOOR:return Wre;case de.IS_FINITE:return Vre;case de.IS_INF:return Ure;case de.IS_NAN:return Gre;case de.LINEAR:return Hre;case de.LOG:return jre;case de.LOG1P:return qre;case de.LOGICAL_NOT:return Xre;case de.NEG:return Kre;case de.LEAKYRELU:return t?Yre:Zre;case de.RECIPROCAL:return Jre;case de.RELU:return t?ase:Qre;case de.RELU6:return t?tse:ese;case de.RSQRT:return nse;case de.SIGMOID:return rse;case de.SIN:return sse;case de.SINH:return ise;case de.SQRT:return ose;case de.SQUARE:return lse;case de.TAN:return use;case de.TANH:return dse;case de.TO_INT:return pse;default:throw new Error(`BinaryType ${e} is not implemented!`)}}var Mt=e=>{switch(e){case 1:return"f32";case 2:return"vec2";case 3:return"vec3";case 4:return"vec4";default:throw new Error(`${e}-component is not supported.`)}};function Tr(e,t=!1,a=!1,n=3){if(e===null)return"";let r="";if(e==="linear")r=Ms(de.LINEAR);else if(e==="relu")r=Ms(de.RELU,a);else if(e==="elu")r=Ms(de.ELU,a);else if(e==="relu6")r=Ms(de.RELU6,a);else if(e==="prelu")r=L3(De.PRELU,a);else if(e==="sigmoid")r=Ms(de.SIGMOID,a);else if(e==="leakyrelu")r=Ms(de.LEAKYRELU,a);else throw new Error(`Activation ${e} has not been implemented for the WebGPU backend.`);let s=Mt(a?4:1),i="";return t?i=` fn activation(a : ${s}, coords : vec${n}) -> ${s} { let b = getPreluActivationWeightsByOutputCoords(coords); ${r} }`:i=` fn activation(a : ${s}, coords : vec${n}) -> ${s} { ${r} }`,i}function vo(e,t){return` ${e?"value = value + getBiasByOutputCoords(coords);":""} ${t?"value = activation(value, coords);":""} `}function _8(e,t,a,n,r=!1,s=!1,i=!1,o=1){v.assert(a&&o===1||!a,()=>`transposeA ${a} is not compatible with component size ${o}`);let l=` let batch = ${e?"0":"batchIn"}; ${a?"value = getA(batch, col, row);":"value = getA(batch, row, col);"} `,u=n?"value = getB(batch, col, row);":"value = getB(batch, row, col);";return` fn mm_readA(batchIn: i32, row: i32, colIn: i32) -> ${Mt(o)} { var value = ${Mt(o)}(0.0); let col = colIn * ${o}; ${r&&i?l:` ${a?"if(row < uniforms.dimAOuter && col < uniforms.dimInner)":"if(row < uniforms.aShape[1] && col < uniforms.aShape[2])"} { ${l} } `} return value; } fn mm_readB(batchIn: i32, row: i32, colIn: i32) -> ${Mt(o)} { let col = colIn * ${o}; let batch = ${t?"0":"batchIn"}; var value = ${Mt(o)}(0.0); ${u} return value; } `}function B3(e,t,a,n,r,s,i=!1,o=!1,l=!1,u=1){return` ${_8(a,n,r,s,i,o,l,u)} fn mm_write(batch: i32, row: i32, colIn: i32, valueIn: ${Mt(u)}) { let col = colIn * ${u}; ${i&&o?"":"if (row < uniforms.dimAOuter && col < uniforms.dimBOuter)"} { var value = valueIn; let coords = vec3(batch, row, col); ${vo(e,t)} setOutputAtCoords(coords[0], coords[1], coords[2], value); } } `}var cse=e=>e?` mm_Asub[inputRow][inputCol] = mm_readA(batch, kStart + inputRow, globalRowStart / innerElementSize + inputCol); `:` mm_Asub[inputRow][inputCol] = mm_readA(batch, globalRow + innerRow, kStart / innerElementSize + inputCol); `,hse=(e,t)=>e?` let ACached0 = mm_Asub[k * innerElementSize][localRow]; let ACached1 = mm_Asub[k * innerElementSize + 1][localRow]; let ACached2 = mm_Asub[k * innerElementSize + 2][localRow]; ${t===3?"":"let ACached3 = mm_Asub[k * innerElementSize + 3][localRow];"} for (var i = 0; i < rowPerThread; i = i + 1) { acc[i] = BCached0 * ACached0[i] + acc[i]; acc[i] = BCached1 * ACached1[i] + acc[i]; acc[i] = BCached2 * ACached2[i] + acc[i]; ${t===3?"":"acc[i] = BCached3 * ACached3[i] + acc[i];"} }`:` for (var i = 0; i < rowPerThread; i = i + 1) { let ACached = mm_Asub[tileRow + i][k]; acc[i] = BCached0 * ACached.x + acc[i]; acc[i] = BCached1 * ACached.y + acc[i]; acc[i] = BCached2 * ACached.z + acc[i]; ${t===3?"":"acc[i] = BCached3 * ACached.w + acc[i];"} }`;function Uh(e,t,a=!1,n=32,r=!1,s=32,i=!1){let o=t[1]*e[1],l=t[0]*e[0],u=a?o:n,p=a?n:o,c=u/t[0],d=n/t[1];return v.assert((a&&c===4&&e[1]===4||!a&&(c===3||c===4))&&u%t[0]===0&&n%t[1]===0&&e[0]===4,()=>`If transposeA ${a} is true, innerElementSize ${c} and workPerThread[1] ${e[1]} must be 4. Otherwise, innerElementSize ${c} must be 3 or 4. tileAWidth ${u} must be divisible by workgroupSize[0]${t[0]}. tileInner ${n} must be divisible by workgroupSize[1] ${t[1]}. colPerThread ${e[0]} must be 4.`),` var mm_Asub : array, ${u/c}>, ${p}>; var mm_Bsub : array, ${l/e[0]}>, ${n}>; const rowPerThread = ${e[1]}; const colPerThread = ${e[0]}; const innerElementSize = ${c}; const tileInner = ${n}; ${Ce()} { let localRow = i32(localId.y); let tileRow = ${i?"0":"localRow * rowPerThread"}; let tileCol = i32(localId.x); let globalRow = ${i?"0":"i32(globalId.y) * rowPerThread"}; let globalCol = i32(globalId.x); let batch = ${r?"0":"i32(globalId.z)"}; let globalRowStart = i32(workgroupId.y) * ${o}; let numTiles = ${r?`${Math.ceil(s/n)}`:"(uniforms.dimInner - 1) / tileInner + 1"}; var kStart = ${r?`i32(globalId.z) * ${s}`:"0"}; var acc: array, rowPerThread>; // Loop over shared dimension. let tileRowB = localRow * ${d}; for (var t = 0; t < numTiles; t = t + 1) { // Load one tile of A into local memory. for (var innerRow = 0; innerRow < rowPerThread; innerRow = innerRow + 1) { let inputRow = tileRow + innerRow; let inputCol = tileCol; ${cse(a)} } // Load one tile of B into local memory. for (var innerRow = 0; innerRow < ${d}; innerRow = innerRow + 1) { let inputRow = tileRowB + innerRow; let inputCol = tileCol; mm_Bsub[inputRow][inputCol] = mm_readB(batch, kStart + inputRow, globalCol); } kStart = kStart + tileInner; workgroupBarrier(); // Compute acc values for a single thread. for (var k = 0; k < tileInner / innerElementSize; k = k + 1) { let BCached0 = mm_Bsub[k * innerElementSize][tileCol]; let BCached1 = mm_Bsub[k * innerElementSize + 1][tileCol]; let BCached2 = mm_Bsub[k * innerElementSize + 2][tileCol]; ${c===3?"":"let BCached3 = mm_Bsub[k * innerElementSize + 3][tileCol];"} ${hse(a,c)} } workgroupBarrier(); } for (var innerRow = 0; innerRow < rowPerThread; innerRow = innerRow + 1) { mm_write(batch, globalRow + innerRow, globalCol, acc[innerRow]); } }`}var qx=e=>e?` mm_Asub[inputRow][inputCol] = mm_readA(batch, kStart + inputRow, globalRowStart + inputCol); `:` mm_Asub[inputRow][inputCol] = mm_readA(batch, globalRowStart + inputRow, kStart + inputCol); `,fse=e=>e?"let ACached = mm_Asub[k][tileRow + innerRow];":"let ACached = mm_Asub[tileRow + innerRow][k];";function Gh(e,t,a=!1,n=32,r=!1,s=32,i=!1){let o=e[1]*t[1],l=e[0]*t[0],u=a?o:n,p=a?n:o;v.assert(p%t[1]===0&&u%t[0]===0&&n%t[1]===0,()=>`tileAHight ${p} must be divisible by workgroupSize[1]${t[1]}, tileAWidth ${u} must be divisible by workgroupSize[0]${t[0]}, tileInner ${n} must be divisible by workgroupSize[1]${t[1]}`);let c=p/t[1],d=u/t[0],h=n/t[1],f=i?` let localRow = i32(localId.y); let localCol = i32(localId.x); let globalRowStart = i32(workgroupId.y) * ${o}; let globalColStart = i32(workgroupId.x) * ${l}; // Loop over shared dimension. for (var t = 0; t < numTiles; t = t + 1) { // Load one tile of A into local memory. for (var inputRow = localRow; inputRow < ${p}; inputRow = inputRow + ${t[1]}) { for (var inputCol = localCol; inputCol < ${u}; inputCol = inputCol + ${t[0]}) { ${qx(a)} } } // Load one tile of B into local memory. for (var inputRow = localRow; inputRow < ${n}; inputRow = inputRow + ${t[1]}) { for (var inputCol = localCol; inputCol < ${l}; inputCol = inputCol + ${t[0]}) { mm_Bsub[inputRow][inputCol] = mm_readB(batch, kStart + inputRow, globalColStart + inputCol); } } kStart = kStart + tileInner; workgroupBarrier(); // Compute acc values for a single thread. var BCached : array; for (var k = 0; k < tileInner; k = k + 1) { for (var inner = 0; inner < colPerThread; inner = inner + 1) { BCached[inner] = mm_Bsub[k][localCol + inner * ${t[0]}]; } for (var innerRow = 0; innerRow < rowPerThread; innerRow = innerRow + 1) { let ACached = ${a?`mm_Asub[k][localRow + innerRow * ${t[1]}];`:`mm_Asub[localRow + innerRow * ${t[1]}][k];`} for (var innerCol = 0; innerCol < colPerThread; innerCol = innerCol + 1) { acc[innerRow][innerCol] = acc[innerRow][innerCol] + ACached * BCached[innerCol]; } } } workgroupBarrier(); } for (var innerRow = 0; innerRow < rowPerThread; innerRow = innerRow + 1) { let gRow = globalRowStart + localRow + innerRow * ${t[1]}; for (var innerCol = 0; innerCol < colPerThread; innerCol = innerCol + 1) { let gCol = globalColStart + localCol + innerCol * ${t[0]}; mm_write(batch, gRow, gCol, acc[innerRow][innerCol]); } } `:` let tileRow = i32(localId.y) * rowPerThread; let tileCol = i32(localId.x) * colPerThread; let globalRow = i32(globalId.y) * rowPerThread; let globalCol = i32(globalId.x) * colPerThread; let globalRowStart = i32(workgroupId.y) * ${o}; let tileRowA = i32(localId.y) * ${c}; let tileColA = i32(localId.x) * ${d}; let tileRowB = i32(localId.y) * ${h}; // Loop over shared dimension. for (var t = 0; t < numTiles; t = t + 1) { // Load one tile of A into local memory. for (var innerRow = 0; innerRow < ${c}; innerRow = innerRow + 1) { for (var innerCol = 0; innerCol < ${d}; innerCol = innerCol + 1) { let inputRow = tileRowA + innerRow; let inputCol = tileColA + innerCol; ${qx(a)} } } // Load one tile of B into local memory. for (var innerRow = 0; innerRow < ${h}; innerRow = innerRow + 1) { for (var innerCol = 0; innerCol < colPerThread; innerCol = innerCol + 1) { let inputRow = tileRowB + innerRow; let inputCol = tileCol + innerCol; mm_Bsub[inputRow][inputCol] = mm_readB(batch, kStart + inputRow, globalCol + innerCol); } } kStart = kStart + tileInner; workgroupBarrier(); // Compute acc values for a single thread. var BCached : array; for (var k = 0; k < tileInner; k = k + 1) { for (var inner = 0; inner < colPerThread; inner = inner + 1) { BCached[inner] = mm_Bsub[k][tileCol + inner]; } for (var innerRow = 0; innerRow < rowPerThread; innerRow = innerRow + 1) { ${fse(a)} for (var innerCol = 0; innerCol < colPerThread; innerCol = innerCol + 1) { acc[innerRow][innerCol] = acc[innerRow][innerCol] + ACached * BCached[innerCol]; } } } workgroupBarrier(); } for (var innerRow = 0; innerRow < rowPerThread; innerRow = innerRow + 1) { for (var innerCol = 0; innerCol < colPerThread; innerCol = innerCol + 1) { mm_write(batch, globalRow + innerRow, globalCol + innerCol, acc[innerRow][innerCol]); } } `;return` var mm_Asub : array, ${p}>; var mm_Bsub : array, ${n}>; const rowPerThread = ${e[1]}; const colPerThread = ${e[0]}; const tileInner = ${n}; ${Ce()} { let batch = ${r?"0":"i32(globalId.z)"}; let numTiles = ${r?`${Math.ceil(s/n)}`:"(uniforms.dimInner - 1) / tileInner + 1"}; var kStart = ${r?`i32(globalId.z) * ${s}`:"0"}; var acc : array, rowPerThread>; // Without this initialization strange values show up in acc. for (var innerRow = 0; innerRow < rowPerThread; innerRow = innerRow + 1) { for (var innerCol = 0; innerCol < colPerThread; innerCol = innerCol + 1) { acc[innerRow][innerCol] = 0.0; } } ${f} } `}var mse=e=>e?` mm_readA(batch, colA, globalRow), mm_readA(batch, colA + 1, globalRow), mm_readA(batch, colA + 2, globalRow), mm_readA(batch, colA + 3, globalRow) `:` mm_readA(batch, globalRow, colA), mm_readA(batch, globalRow, colA + 1), mm_readA(batch, globalRow, colA + 2), mm_readA(batch, globalRow, colA + 3) `;function gse(e,t=!1){return v.assert(e[1]===1&&e[2]===1,()=>`A linear work group size is required. But got ${e}.`),` const tileSize = ${e[0]*4}; var mm_Asub : array, ${e[0]}>; ${Ce()} { let tileCol = i32(localId.x); let globalCol = i32(globalId.x); let globalRow = i32(globalId.y); let numTiles = (uniforms.dimInner - 1) / tileSize + 1; let batch = i32(globalId.z); // Without this initialization strange values show up in acc. var acc = 0.0; // Loop over shared dimension. for (var t = 0; t < numTiles; t = t + 1) { // Load one tile of A into local memory. let colA = t * tileSize + tileCol * 4; mm_Asub[tileCol] = vec4(${mse(t)}); workgroupBarrier(); // Compute acc values for a single thread. for (var k = 0; k < tileSize / 4; k = k + 1) { let rowB = t * tileSize + k * 4; let BCached = vec4(mm_readB(batch, rowB, globalCol), mm_readB(batch, rowB + 1, globalCol), mm_readB(batch, rowB + 2, globalCol), mm_readB(batch, rowB + 3, globalCol)); let ACached = mm_Asub[k]; acc = acc + dot(ACached, BCached); } workgroupBarrier(); } mm_write(batch, globalRow, globalCol, acc); } `}var xse=class{constructor(e,t,a,n,r=!1,s=!1,i=null,o=null,l=null,u=!1){this.variableNames=["A","B"],this.uniforms="dimAOuter : i32, dimBOuter : i32, dimInner : i32,",this.outputShape=t,this.dispatchLayout={x:[2],y:[1],z:[0]};let p=r?e[1]:e[2];if(this.isVec4=(p%4===0&&!r||t[1]%4===0&&r)&&t[2]%4===0&&!s,this.isVectorA=t[1]===1&&!r,!this.isVec4&&this.isVectorA)this.elementsPerThread=[1,1,1],this.workgroupSize=[32,1,1];else{let h=N8(t[1],p,t[2],r);this.workgroupSize=h.workgroupSize,this.elementsPerThread=h.elementsPerThread}this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize,this.elementsPerThread);let c=i!=null,d=l!=null;c&&this.variableNames.push("bias"),d&&this.variableNames.push("preluActivationWeights"),this.sequentialAccessByThreads=u,this.transposeA=r,this.transposeB=s,this.addBias=c,this.activation=o,this.hasPreluActivationWeights=d,this.batchAEqualOne=a,this.batchBEqualOne=n,[this.fitAOuter,this.fitBOuter,this.fitInner]=this.getShapeFit(t[1],t[2],p),this.shaderKey=`matMulPacked_${this.elementsPerThread}_${r}_${s}_${this.activation}_${this.fitAOuter}_${this.fitBOuter}_${this.fitInner}_${this.isVec4}_${this.isVectorA}_${this.batchAEqualOne}_${this.batchBEqualOne}_${this.sequentialAccessByThreads}`}getShapeFit(e,t,a){let n=this.workgroupSize[1]*this.elementsPerThread[1],r=this.workgroupSize[0]*this.elementsPerThread[0];!this.isVec4&&this.isVectorA?this.tileInner=this.workgroupSize[0]*4:this.tileInner=r;let s=e%n===0,i=t%r===0,o=a%this.tileInner===0;return[s,i,o]}getUserCode(){return` ${Tr(this.activation,this.hasPreluActivationWeights,this.isVec4)} ${B3(this.addBias,this.activation,this.batchAEqualOne,this.batchBEqualOne,!1,this.transposeB,this.fitAOuter,this.fitBOuter,this.fitInner,this.isVec4?4:1)} ${this.isVec4?Uh(this.elementsPerThread,this.workgroupSize,this.transposeA,this.tileInner,!1,null,this.isVectorA):this.isVectorA?gse(this.workgroupSize,this.transposeA):Gh(this.elementsPerThread,this.workgroupSize,this.transposeA,this.tileInner,!1,null,this.sequentialAccessByThreads)} `}};function Ase(){return` var sumValues : array; ${Ce()} { let coords = getOutputCoords(); let batch = coords[0]; let row = coords[1]; let col = coords[2]; var sum = 0.0; let Length = uniforms.dimInner; for (var k = i32(localId.x); k < Length; k = k + i32(workgroupSizeX)) { let dataA = mm_readA(batch, row, k); let dataB = mm_readB(batch, k, col); sum = sum + dataA * dataB; } sumValues[localId.x] = sum; workgroupBarrier(); for(var currentSize = workgroupSizeX / 2u; currentSize > 1u; currentSize = currentSize / 2u) { if (localId.x < currentSize) { sumValues[localId.x] = sumValues[localId.x] + sumValues[localId.x + currentSize]; } workgroupBarrier(); } if (localId.x == 0u) { sum = sumValues[0] + sumValues[1]; mm_write(batch, row, col, sum); } } `}var yse=class{constructor(e,t,a,n=!1,r=!1,s=null,i=null,o=null){this.variableNames=["A","B"],this.uniforms="dimAOuter : i32, dimBOuter : i32, dimInner : i32,",this.workgroupSize=[256,1,1],this.outputShape=e,this.dispatchLayout={x:[],y:[1,2],z:[0]},this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize);let l=s!=null,u=o!=null;l&&this.variableNames.push("bias"),u&&this.variableNames.push("preluActivationWeights"),this.transposeA=n,this.transposeB=r,this.addBias=l,this.activation=i,this.hasPreluActivationWeights=u,this.batchAEqualOne=t,this.batchBEqualOne=a,this.shaderKey=`matMulReduce_${this.activation}_${n}_${r}_${this.batchAEqualOne}_${this.batchBEqualOne}`}getUserCode(){return` ${Tr(this.activation,this.hasPreluActivationWeights)} ${B3(this.addBias,this.activation,this.batchAEqualOne,this.batchBEqualOne,this.transposeA,this.transposeB)} ${Ase()} `}};function bse(e){let t=e[1],a=e[0],n=t>a?t:a;return` var mm_Asub : array, ${t}>; var mm_Bsub : array, ${n}>; // If the output size is small for matrix multiplication, avoid to use vec4 // and handle some elements per thread to optimally utilize the ALU. // Read data from global memory to registers firstly, then store them into // shared memory, so it is instruction-Level parallelism for arithmetic // operations and others handle IO operations between barrier api, makes ALU // and load/store units work simultaneously, could improves the performance. ${Ce()} { let tileRow = i32(localId.y); let tileCol = i32(localId.x); let globalRow = i32(globalId.y); let globalCol = i32(globalId.x); let batch = i32(globalId.z); // uniforms.dimInner should be greater than 0. let numTiles = (uniforms.dimInner - 1) / ${n} + 1; var acc = 0.0; var globalColA = tileCol; var globalRowB = 0; var regA = mm_readA(batch, globalRow, globalColA); var regB0 = mm_readB(batch, globalRowB + 2 * tileRow, globalCol); var regB1 = mm_readB(batch, globalRowB + 2 * tileRow + 1, globalCol); globalColA = globalColA + ${n}; globalRowB = globalRowB + ${n}; for (var t = 0; t < numTiles; t = t + 1) { mm_Asub[tileRow][tileCol] = regA; mm_Bsub[2 * tileRow][tileCol] = regB0; mm_Bsub[2 * tileRow + 1][tileCol] = regB1; workgroupBarrier(); regA = mm_readA(batch, globalRow, globalColA); regB0 = mm_readB(batch, globalRowB + 2 * tileRow, globalCol); regB1 = mm_readB(batch, globalRowB + 2 * tileRow + 1, globalCol); globalColA = globalColA + ${n}; globalRowB = globalRowB + ${n}; for (var k = 0; k < ${n}; k = k + 1) { acc = acc + mm_Asub[tileRow][k] * mm_Bsub[k][tileCol]; } workgroupBarrier(); } mm_write(batch, globalRow, globalCol, acc); } `}var vse=class{constructor(e,t,a,n=!1,r=!1,s=null,i=null,o=null){this.variableNames=["A","B"],this.uniforms="dimAOuter : i32, dimBOuter : i32, dimInner : i32,",this.workgroupSize=[16,8,1],this.outputShape=a,this.dispatchLayout={x:[2],y:[1],z:[0]},this.dispatch=[Math.ceil(a[2]/this.workgroupSize[0]),Math.ceil(a[1]/this.workgroupSize[1]),a[0]];let l=s!=null;l&&this.variableNames.push("bias");let u=o!=null;u&&this.variableNames.push("preluActivationWeights"),this.transposeA=n,this.transposeB=r,this.addBias=l,this.activation=i,this.hasPreluActivationWeights=u,this.batchAEqualOne=e[0]===1,this.batchBEqualOne=t[0]===1,this.shaderKey=`matMulSmallOutputSize_${this.activation}_${n}_${r}_${this.batchAEqualOne}_${this.batchBEqualOne}`}getUserCode(){return` ${Tr(this.activation,this.hasPreluActivationWeights)} ${B3(this.addBias,this.activation,this.batchAEqualOne,this.batchBEqualOne,this.transposeA,this.transposeB)} ${bse(this.workgroupSize)} `}},wse=class{constructor(e,t,a,n,r=!1,s=!1){this.variableNames=["A","B"],this.uniforms="dimAOuter : i32, dimBOuter : i32, dimInner : i32,",this.workgroupSize=[8,8,1],this.atomic=!0,this.isVec4=!1,this.splitedDimInner=128,v.assert(e[0]===1,()=>"MatMulSplitKProgram only supports batch = 1."),this.outputShape=e,this.dispatchLayout={x:[2],y:[1],z:[0,3]},this.isVec4=(r&&this.outputShape[1]%4===0||!r&&t%4===0)&&this.outputShape[2]%4===0,this.elementsPerThread=[4,4,this.splitedDimInner],this.isVec4||(this.outputShape[1]<16&&(this.elementsPerThread[1]=1),this.outputShape[2]<16&&(this.elementsPerThread[0]=1)),this.dispatch=Ne(this.dispatchLayout,[this.outputShape[0],this.outputShape[1],this.outputShape[2],t],this.workgroupSize,this.elementsPerThread),this.transposeA=r,this.transposeB=s,this.batchAEqualOne=a,this.batchBEqualOne=n,this.shaderKey=`matMulSplitK_${r}_${s}_${a}_${n}_${this.elementsPerThread}_${this.isVec4}`}getUserCode(){let e=a=>` for (var i = 0; i < ${a}; i = i + 1) { var oldValue = atomicLoad(&(result[flatIndex + i])); var exchanged = false; for (; !exchanged;) { let newValueF32 = bitcast(oldValue) + ${a>1?"value[i]":"value"}; let newValue = bitcast(newValueF32); let res = atomicCompareExchangeWeak(&(result[flatIndex + i]), oldValue, newValue); oldValue = res.old_value; exchanged = res.exchanged; } } `,t=this.isVec4?4:1;return` ${_8(this.batchAEqualOne,this.batchBEqualOne,!1,this.transposeB,!1,!1,!1,t)} fn mm_write(batch: i32, row : i32, colIn : i32, value : ${Mt(t)}) { let col = colIn * ${t}; if (row < uniforms.dimAOuter && col < uniforms.dimBOuter) { let coords = vec3(batch, row, col); let flatIndex = getOutputIndexFromCoords(coords); // The problem is that we should initialize output to zero before using. // Otherwise, the original value will be added to the result. ${e(t)} } } ${this.isVec4?Uh(this.elementsPerThread,this.workgroupSize,this.transposeA,32,!0,this.splitedDimInner):Gh(this.elementsPerThread,this.workgroupSize,this.transposeA,32,!0,this.splitedDimInner)} `}},kse=class{constructor(e,t=null,a=null,n=null){this.uniforms="",this.variableNames=["x"],this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.addBias=t!=null,this.hasPreluActivationWeights=n!=null,this.activation=a,this.addBias&&this.variableNames.push("bias"),this.hasPreluActivationWeights&&this.variableNames.push("preluActivationWeights"),this.shaderKey=`biasActivation_${a}`}getUserCode(){return` ${Tr(this.activation,this.hasPreluActivationWeights)} ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); var value = getXByOutputIndex(index); ${vo(this.addBias,this.activation)} setOutputAtIndex(index, value); } } `}},Ise=class{constructor(e){this.variableNames=[],this.outputShape=[],this.uniforms="value : f32,",this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.shaderKey="fill"}getUserCode(){return` ${Ce("index")} { if (index < uniforms.size) { setOutputAtIndex(index, uniforms.value); } } `}};function Cr(e){let{backend:t,attrs:a}=e,{shape:n,value:r}=a,{dtype:s}=a;if(s=s||v.inferDtype(r),s==="string"){let i=v.getArrayFromDType(s,v.sizeFromShape(n));return i.fill(r),t.makeTensorInfo(n,s,i)}else{let i=new Ise(n),o=[{type:"float32",data:[r]}];return t.runWebGPUProgram(i,[],s,o)}}var Sse={kernelName:Fl,backendName:"webgpu",kernelFunc:Cr};function Ie(e){let{inputs:t,attrs:a}=e,{x:n}=t,{shape:r}=a,s=v.sizeFromShape(n.shape),i=v.inferFromImplicitShape(r,s),o=v.sizeFromShape(i);return v.assert(s===o,()=>`The new shape (${i}) has ${o} elements and the old shape (${n.shape}) has ${s} elements. The new shape and old shape must have the same number of elements.`),e.backend.incRef(n.dataId),{dataId:n.dataId,shape:i,dtype:n.dtype}}var Tse={kernelName:ql,backendName:"webgpu",kernelFunc:Ie};function Hh({a:e,b:t,transposeA:a,transposeB:n,backend:r,bias:s=null,preluActivationWeights:i=null,leakyreluAlpha:o=0,activation:l=null}){let u=e.shape.length,p=t.shape.length,c=a?e.shape[u-2]:e.shape[u-1],d=n?t.shape[p-1]:t.shape[p-2],h=a?e.shape[u-1]:e.shape[u-2],f=n?t.shape[p-2]:t.shape[p-1],m=e.shape.slice(0,-2),g=t.shape.slice(0,-2),x=v.sizeFromShape(m),A=v.sizeFromShape(g),y=xo.assertAndGetBroadcastShape(e.shape.slice(0,-2),t.shape.slice(0,-2)).concat([h,f]);v.assert(c===d,()=>`Error in matMul: inner shapes (${c}) and (${d}) of Tensors with shapes ${e.shape} and ${t.shape} and transposeA=${a} and transposeB=${n} must match.`);let b=a?[x,c,h]:[x,h,c],w=n?[A,f,d]:[A,d,f],S=Ie({inputs:{x:e},backend:r,attrs:{shape:b}}),C=Ie({inputs:{x:t},backend:r,attrs:{shape:w}}),E=[S,C],_=Math.max(x,A),$=x===1,M=A===1,I=[S,C],N=[{type:"int32",data:[h]},{type:"int32",data:[f]},{type:"int32",data:[c]}],O,L,B=[_,h,f],G=W().get("WEBGPU_MATMUL_PROGRAM_TYPE");if(G<0){let U=W().getNumber("WEBGPU_THRESHOLD_TO_INCREASE_WORKGROUPS_FOR_MATMUL"),H=U>0?U:r.thresholdToIncreaseWorkgroups,V=_*Math.ceil(h/32)*Math.ceil(f/32);V<=H||h<=8&&V<=H*2?_*h*f<=128?G=Pn.MatMulReduceProgram:_===1&&d>=2e3?G=Pn.MatMulSplitKProgram:G=Pn.MatMulSmallOutputSizeProgram:G=Pn.MatMulPackedProgram}switch(G){case Pn.MatMulReduceProgram:O=new yse(B,$,M,a,n,s,l,i);break;case Pn.MatMulSplitKProgram:{if(L=Cr({backend:r,attrs:{shape:B,value:0,dtype:e.dtype}}),O=new wse(B,d,$,M,a,n),s||l){L=r.runWebGPUProgram(O,I,e.dtype,N,L);let H=new kse(L.shape,s,l,i),V=null,Q=[L];s&&Q.push(s),i&&Q.push(i),l==="leakyrelu"&&(V=[{type:"float32",data:[o]}],H.uniforms+=" alpha : f32,");let Z=r.runWebGPUProgram(H,Q,L.dtype,V);E.push(L);let re=Ie({inputs:{x:Z},backend:r,attrs:{shape:y}});E.push(Z);for(let ee of E)r.disposeData(ee.dataId);return re}break}case Pn.MatMulSmallOutputSizeProgram:O=new vse(b,w,B,a,n,s,l,i);break;case Pn.MatMulPackedProgram:let U=r.adapterInfo.isIntel();O=new xse(b,B,$,M,a,n,s,l,i,U);break;default:throw new Error(`Unsupported MatMulProgramType ${G}.`)}s&&I.push(s),i&&I.push(i),l==="leakyrelu"&&(N.push({type:"float32",data:[o]}),O.uniforms+=" alpha : f32,"),L=r.runWebGPUProgram(O,I,e.dtype,N,L);let j=Ie({inputs:{x:L},backend:r,attrs:{shape:y}});E.push(L);for(let U of E)r.disposeData(U.dataId);return j}function Cse(e){let{inputs:t,backend:a,attrs:n}=e,{a:r,b:s,bias:i,preluActivationWeights:o}=t,{transposeA:l,transposeB:u,activation:p,leakyreluAlpha:c}=n;return Hh({a:r,b:s,transposeA:l,transposeB:u,backend:a,bias:i,preluActivationWeights:o,leakyreluAlpha:c,activation:p})}var Nse={kernelName:jr,backendName:"webgpu",kernelFunc:Cse},Xx=class{constructor(e,t,a){this.variableNames=["AReal","AImag","BReal","BImag"],this.workgroupSize=[128,1,1],this.size=!0,this.outputShape=T.assertAndGetBroadcastShape(t,a),this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.shaderKey=`binaryOpComplex_${e}`,this.op=e}getUserCode(){return` fn binaryOpComplex( areal : f32, aimag : f32, breal : f32, bimag : f32) -> f32 { ${L3(this.op,!1)} } ${Ce("index")} { if(index < uniforms.size) { let areal = getARealByOutputIndex(index); let aimag = getAImagByOutputIndex(index); let breal = getBRealByOutputIndex(index); let bimag = getBImagByOutputIndex(index); setOutputAtIndex(index, binaryOpComplex(areal, aimag, breal, bimag)); } } `}},P1=class{constructor(e,t,a){this.size=!0,this.variableNames=["A","B"],this.outputShape=T.assertAndGetBroadcastShape(t,a),this.dispatchLayout=Ve(this.outputShape),this.op=e,this.useSharedMemoryWithA=t.length<=1&&a.length>1&&t[0]<128,this.useSharedMemoryWithB=a.length<=1&&t.length>1&&a[0]<128,this.useSharedMemoryWithA||this.useSharedMemoryWithB?(this.isVec4=!1,this.lastDimensionSize=this.useSharedMemoryWithB?a[0]:t[0],this.shaderKey=`binary_${this.type}_${e}_${this.lastDimensionSize}_${this.useSharedMemoryWithB}`,this.type="shared",this.workgroupSize=[256,1,1],this.workPerThread=1):(v.arraysEqual(t,a)&&v.sizeFromShape(t)%4===0?(this.isVec4=!0,this.type="vec4",this.workPerThread=4):(this.isVec4=!1,this.type="plain",this.workPerThread=1),this.shaderKey=`binary_${this.type}_${e}`,this.workgroupSize=[128,1,1]),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize,[this.workPerThread,1,1])}getUserCode(){let e,t=this.isVec4?"vec4":"f32",a=` fn binaryOperation(a : ${t}, b : ${t}) -> ${t} { ${L3(this.op,this.isVec4)} }; `;if(this.type==="shared"){let n=this.lastDimensionSize>1?`coords[${this.outputShape.length-1}]`:"0",r=this.useSharedMemoryWithB?`let a = getAByOutputIndex(index); let b = sharedBuf[${n}];`:`let a = sharedBuf[${n}]; let b = getBByOutputIndex(index);`;e=` ${a} var sharedBuf : array; ${Ce("index")} { // Fill in the shared memory buffer. let localIndex = i32(localId.x); if(localIndex < ${this.lastDimensionSize}) { sharedBuf[localIndex] = f32(${this.useSharedMemoryWithB?"B":"A"}[localIndex]); } workgroupBarrier(); if(index < uniforms.size) { let coords = getCoordsFromIndex(index); ${r} setOutputAtIndex(index, binaryOperation(a, b)); } } `}else e=` ${a} ${Ce("index")} { if (index < uniforms.size) { let a = getAByOutputIndex(index); let b = getBByOutputIndex(index); setOutputAtIndex(index, binaryOperation(a, b)); } } `;return e}};function Ya(e){let{inputs:t}=e,{x:a}=t;return e.backend.incRef(a.dataId),{dataId:a.dataId,shape:a.shape,dtype:a.dtype}}var Ese={kernelName:ki,backendName:"webgpu",kernelFunc:Ya};function wo(e){let{inputs:t,backend:a}=e,{real:n,imag:r}=t,s=a.makeTensorInfo(n.shape,"complex64"),i=a.tensorMap.get(s.dataId),o=Ya({inputs:{x:n},backend:a}),l=Ya({inputs:{x:r},backend:a});return i.complexTensorInfos={real:o,imag:l},s}var Rse={kernelName:Sd,backendName:"webgpu",kernelFunc:wo},mp=class{constructor(e,t){this.variableNames=["A"],this.size=!0;let a=128;this.workgroupSize=[a,1,1],this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.op=t,this.shaderKey=`unary_${t}`}getUserCode(){return` fn unaryOperation(a : f32) -> f32 { ${Ms(this.op,!1)} } ${Ce("index")} { if (index < uniforms.size) { let a = getAByOutputIndex(index); setOutputAtIndex(index, unaryOperation(a)); } } `}};function it({opType:e,cpuKernelImpl:t,dtype:a}){return({inputs:n,backend:r})=>{let{x:s}=n,i=r,o=a||s.dtype;if(i.shouldExecuteOnCPU([s])&&t!=null){let u=i.tensorMap.get(s.dataId),p=t(u.values,o);return i.makeTensorInfo(s.shape,o,p)}let l=new mp(s.shape,e);return i.runWebGPUProgram(l,[s],o)}}function ua({opType:e,cpuKernelImpl:t,supportsComplex:a=!1,dtype:n}){return({inputs:r,backend:s})=>{let{a:i,b:o}=r,l=s;if(a&&i.dtype==="complex64"){let c=l.tensorMap.get(i.dataId),d=l.tensorMap.get(o.dataId),h,f;if(e!==De.MUL)[h,f]=[[c.complexTensorInfos.real,d.complexTensorInfos.real],[c.complexTensorInfos.imag,d.complexTensorInfos.imag]].map(g=>{let[x,A]=g,y={dataId:x.dataId,dtype:x.dtype,shape:i.shape},b={dataId:A.dataId,dtype:A.dtype,shape:o.shape},w=new P1(e,i.shape,o.shape);return l.runWebGPUProgram(w,[y,b],ca(x.dtype,A.dtype))});else{let g=new Xx(De.COMPLEX_MULTIPLY_REAL,i.shape,o.shape),x=new Xx(De.COMPLEX_MULTIPLY_IMAG,i.shape,o.shape),A=[{dataId:c.complexTensorInfos.real.dataId,dtype:c.complexTensorInfos.real.dtype,shape:i.shape},{dataId:c.complexTensorInfos.imag.dataId,dtype:c.complexTensorInfos.imag.dtype,shape:i.shape},{dataId:d.complexTensorInfos.real.dataId,dtype:d.complexTensorInfos.real.dtype,shape:o.shape},{dataId:d.complexTensorInfos.imag.dataId,dtype:d.complexTensorInfos.imag.dtype,shape:o.shape}];h=l.runWebGPUProgram(g,A,"float32"),f=l.runWebGPUProgram(x,A,"float32")}let m=wo({inputs:{real:h,imag:f},backend:l});return l.disposeData(h.dataId),l.disposeData(f.dataId),m}let u=n||ca(i.dtype,o.dtype);if((i.dtype==="string"||o.dtype==="string"||l.shouldExecuteOnCPU([i,o]))&&t!=null){let c=l.tensorMap.get(i.dataId).values,d=l.tensorMap.get(o.dataId).values,h=i.dtype==="string"?T.fromUint8ToStringArray(c):c,f=i.dtype==="string"?T.fromUint8ToStringArray(d):d,[m,g]=t(i.shape,o.shape,h,f,u);return l.makeTensorInfo(g,u,m)}let p=new P1(e,i.shape,o.shape);return l.runWebGPUProgram(p,[i,o],u)}}var{addImpl:Mse,castImpl:$se,ceilImpl:_se,concatImpl:Pse,equalImpl:Fse,expImpl:Ose,expm1Impl:Dse,floorImpl:zse,gatherNdImpl:Lse,gatherV2Impl:Bse,greaterEqualImpl:Wse,greaterImpl:Vse,lessEqualImpl:Use,lessImpl:Gse,logImpl:Hse,maxImpl:jse,maximumImpl:qse,minimumImpl:Xse,multiplyImpl:Kse,negImpl:Zse,notEqualImpl:Yse,prodImpl:Jse,rangeImpl:Qse,rsqrtImpl:eie,scatterImpl:tie,simpleAbsImpl:aie,sliceImpl:nie,stridedSliceImpl:rie,stringNGramsImpl:sie,subImpl:iie,tileImpl:oie,topKImpl:lie,transposeImpl:uie,uniqueImpl:I0e}=_h,die=it({opType:de.ABS,cpuKernelImpl:aie}),pie={kernelName:wl,backendName:"webgpu",kernelFunc:die},cie=it({opType:de.ACOS}),hie={kernelName:kl,backendName:"webgpu",kernelFunc:cie},fie=it({opType:de.ACOSH}),mie={kernelName:Il,backendName:"webgpu",kernelFunc:fie},gie=ua({opType:De.ADD,cpuKernelImpl:Mse,supportsComplex:!0}),xie={kernelName:ts,backendName:"webgpu",kernelFunc:gie},Aie=class{constructor(e){this.workPerThread=1,this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e[0],this.variableNames=e.map((t,a)=>`T${a}`),this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize,[this.workPerThread,1,1]),this.shaderKey="addN"}getUserCode(){let e=[];this.variableNames.forEach(a=>{e.push(`let v${a} = get${a}ByOutputCoords(coords);`)});let t=this.variableNames.map(a=>`v${a}`).join(" + ");return` ${Ce("index")} { for (var i = 0; i < ${this.workPerThread}; i = i + 1) { let flatIndex = index * ${this.workPerThread} + i; if (flatIndex < uniforms.size) { let coords = getCoordsFromIndex(flatIndex); ${e.join(` `)} setOutputAtIndex(flatIndex, ${t}); } } } `}};function yie(e){let{inputs:t,backend:a}=e,n=t;if(n.length===1)return Ya({inputs:{x:n[0]},backend:a});let r=n.map(o=>o.dtype).reduce((o,l)=>ca(o,l)),s=n.map(o=>o.shape),i=new Aie(s);return a.runWebGPUProgram(i,n,r)}var bie={kernelName:Ks,backendName:"webgpu",kernelFunc:yie},vie=class{constructor(e,t){this.variableNames=["A"],this.workgroupSize=[16,16,1];let a=new Array(e.length);for(let n=0;n`Must be a square tile, current tile shape is ${this.workgroupSize[0]} x ${this.workgroupSize[1]}`),` const tileSize = ${this.workgroupSize[0]}; var tile : array, ${this.workgroupSize[0]}>; ${Ce()} { var x = i32(workgroupId.x) * tileSize + i32(localId.x); var y = i32(workgroupId.y) * tileSize + i32(localId.y); let width = uniforms.outShape[0]; let height = uniforms.outShape[1]; if (x < width && y < height) { tile[localId.y][localId.x] = f32(A[y * width + x]); } workgroupBarrier(); x = i32(workgroupId.y) * tileSize + i32(localId.x); y = i32(workgroupId.x) * tileSize + i32(localId.y); if (x < height && y < width) { setOutputAtIndex((y * height + x), tile[localId.x] [localId.y]); } } `}},wie=class{constructor(e,t){this.variableNames=["A"],this.workPerThread=1,this.workgroupSize=[64,1,1],this.size=!0;let a=new Array(e.length);for(let n=0;n6)throw Error(`Transpose for rank ${t} is not yet supported`);let a=new Array(t);for(let n=0;n"} bestValue) { bestValue = candidate; }`,t="f32(x[offset])"):this.reduceType==="sum"||this.reduceType==="mean"?e=" bestValue = bestValue + candidate; ":this.reduceType==="prod"?(e=" bestValue = bestValue * candidate; ",t="1.0"):this.reduceType==="all"?(e=" bestValue = f32(bestValue >= 1.0 && candidate >= 1.0); ",t="1.0"):this.reduceType==="any"&&(e=" bestValue = f32(bestValue >= 1.0 || candidate >= 1.0); ",t="0.0");let a=this.reduceType==="mean"?"setOutputAtIndex(outputIndex, bestValue / f32(uniforms.reduceSize));":"setOutputAtIndex(outputIndex, bestValue);";return` fn DIV_CEIL(a : u32, b : u32) -> u32 { return ((a - 1u) / b + 1u); } ${` var xBestValues : array; `} fn getOffset(outputIndex : i32) -> i32 { let outputCoords = getCoordsFromIndex(outputIndex); let offset = ${this.outputShape.length===1?"outputCoords":"outputCoords[0]"} * uniforms.reduceSize; return offset; } ${Ce("index")} { let outputIndex = index / i32(workgroupSizeX); let offset = getOffset(outputIndex); var bestValue = ${t}; let Length = uniforms.reduceSize; let WorkPerThread = DIV_CEIL(u32(Length), workgroupSizeX); for (var k = i32(localId.x); k < Length && outputIndex < uniforms.size; k = k + i32(workgroupSizeX)) { let candidate = f32(x[offset + k]); ${e} } xBestValues[localId.x] = bestValue; workgroupBarrier(); var reduceSize = min(u32(Length), workgroupSizeX); for (var currentSize = reduceSize / 2u; reduceSize > 1u; currentSize = reduceSize / 2u) { let interval = DIV_CEIL(reduceSize, 2u); if (localId.x < currentSize) { let candidate = xBestValues[localId.x + interval]; ${e} xBestValues[localId.x] = bestValue; } reduceSize = interval; workgroupBarrier(); } if (localId.x == 0u && outputIndex < uniforms.size) { ${a} } } `}};function ko(e,t,a,n,r){let s=e.shape.length,i=[],o=v.parseAxisParam(t,e.shape),l=o,u=T.getAxesPermutation(l,s),p=e;u!=null&&(p=vr({inputs:{x:e},attrs:{perm:u},backend:r}),l=T.getInnerMostAxes(l.length,s),i.push(p)),T.assertAxesAreInnerMostDims(n,l,s);let[c,d]=T.computeOutAndReduceShapes(p.shape,l),h=c;a&&(h=T.expandShapeToKeepDim(c,o));let f;if((n==="max"||n==="prod")&&r.shouldExecuteOnCPU([p])){let m=r.tensorMap.get(p.dataId).values;switch(n){case"max":let g=jse(m,v.sizeFromShape(d),h,e.dtype);f=r.makeTensorInfo(h,e.dtype,g);break;case"prod":let{outVals:x,outShape:A,outDtype:y}=Jse(p.shape,p.dtype,m,l);f=r.makeTensorInfo(A,y,x);break;default:throw new Error(`${n} CPU implementation is not yet supported.`)}}else{let m=v.sizeFromShape(d),g=v.sizeFromShape(p.shape)/m,x={windowSize:m,inSize:m,batchSize:g,outSize:1},A=n==="mean"?"float32":Hd(e.dtype),y=[{type:"int32",data:[m]}],b=new Sie(x,n),w=r.runWebGPUProgram(b,[p],A,y);i.push(w),f=Ie({inputs:{x:w},attrs:{shape:h},backend:r})}return i.forEach(m=>r.disposeData(m.dataId)),f}function Tie(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{keepDims:s,axis:i}=n;return ko(r,i,s,"all",a)}var Cie={kernelName:Zs,backendName:"webgpu",kernelFunc:Tie};function Nie(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{keepDims:s,axis:i}=n;return ko(r,i,s,"any",a)}var Eie={kernelName:Ys,backendName:"webgpu",kernelFunc:Nie},P8=class{constructor(e,t,a){this.workgroupSize=[64,1,1],this.variableNames=["x"],this.uniforms="infinityValue : f32,",this.size=!0;let n=[t];this.op=a==="min"?"<":">";let[r,s]=T.computeOutAndReduceShapes(e,n);this.outputShape=r.length===0?[1]:r,this.dispatchLayout=Ve(this.outputShape),v.sizeFromShape(s)<32||v.sizeFromShape(r)>1e3?(this.type="plain",this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize)):(this.type="shared",this.dispatch=Ne(this.dispatchLayout,this.outputShape,[1,1,1])),this.inputShape=e,this.shaderKey=`argMinMax_${this.op}_${this.type}`}getUserCode(){let e=()=>this.inputShape.length===1?"uniforms.xShape":`uniforms.xShape.${yr(this.inputShape.length-1)}`,t=()=>{let a="";if(this.outputShape.length===1)this.inputShape.length!==1&&(a+="outputCoords,");else for(let n=0;n u32 { return ((a - 1u) / b + 1u); } ${` var xBestIndices : array; var xBestValues : array; `} ${Ce("index")} { let outputIndex = index / i32(workgroupSizeX); let reduceLength = ${e()}; var bestIndex = i32(localId.x); var bestValue = uniforms.infinityValue; let outputCoords = getCoordsFromIndex(outputIndex); for (var k = i32(localId.x); k < reduceLength && outputIndex < uniforms.size; k = k + i32(workgroupSizeX)) { let candidate = getX(${t()} k); if (!isnan(candidate) && candidate ${this.op} bestValue) { bestValue = candidate; bestIndex = k; } } xBestValues[localId.x] = bestValue; xBestIndices[localId.x] = bestIndex; workgroupBarrier(); var reduceSize = min(u32(reduceLength), workgroupSizeX); for (var currentSize = reduceSize / 2u; reduceSize > 1u; currentSize = reduceSize / 2u) { let interval = DIV_CEIL(reduceSize, 2u); if (localId.x < currentSize) { let candidate = xBestValues[localId.x + interval]; if (candidate ${this.op} bestValue) { bestValue = candidate; xBestValues[localId.x] = bestValue; xBestIndices[localId.x] = xBestIndices[localId.x + interval]; } } reduceSize = interval; workgroupBarrier(); } if (localId.x == 0u && outputIndex < uniforms.size) { setOutputAtIndexI32(outputIndex, xBestIndices[localId.x]); } } `:` ${Ce("index")} { if (index < uniforms.size) { let outputCoords = getCoordsFromIndex(index); var bestIndex = 0; var bestValue = getX(${t()} 0); let reduceLength = ${e()}; for (var i = 1; i < reduceLength; i++) { let candidate = getX(${t()} i); if (candidate ${this.op} bestValue) { bestValue = candidate; bestIndex = i; } } setOutputAtIndexI32(index, bestIndex); } } `}};function Rie(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s}=n,i=v.parseAxisParam(s,r.shape),o=T.getAxesPermutation(i,r.shape.length),l=r,u=[];o!=null&&(l=vr({inputs:{x:r},backend:a,attrs:{perm:o}}),u.push(l),i=T.getInnerMostAxes(i.length,l.shape.length)),T.assertAxesAreInnerMostDims("argMax",[i[0]],l.shape.length);let p=new P8(l.shape,i[0],"max"),c=[{type:"float32",data:[Number.NEGATIVE_INFINITY]}],d=a.runWebGPUProgram(p,[l],"int32",c);return u.forEach(h=>a.disposeData(h.dataId)),d}var Mie={kernelName:Js,backendName:"webgpu",kernelFunc:Rie};function $ie(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s}=n,i=v.parseAxisParam(s,r.shape),o=T.getAxesPermutation(i,r.shape.length),l=r,u=[];o!=null&&(l=vr({inputs:{x:r},backend:a,attrs:{perm:o}}),u.push(l),i=T.getInnerMostAxes(i.length,l.shape.length)),T.assertAxesAreInnerMostDims("argMin",[i[0]],l.shape.length);let p=new P8(l.shape,i[0],"min"),c=[{type:"float32",data:[Number.POSITIVE_INFINITY]}],d=a.runWebGPUProgram(p,[l],"int32",c);return u.forEach(h=>a.disposeData(h.dataId)),d}var _ie={kernelName:kd,backendName:"webgpu",kernelFunc:$ie},Pie=it({opType:de.ASIN}),Fie={kernelName:Sl,backendName:"webgpu",kernelFunc:Pie},Oie=it({opType:de.ASINH}),Die={kernelName:Tl,backendName:"webgpu",kernelFunc:Oie},zie=it({opType:de.ATAN}),Lie={kernelName:Cl,backendName:"webgpu",kernelFunc:zie},Bie=ua({opType:De.ATAN2}),Wie={kernelName:El,backendName:"webgpu",kernelFunc:Bie},Vie=it({opType:de.ATANH}),Uie={kernelName:Nl,backendName:"webgpu",kernelFunc:Vie},Kx=class{constructor(e,t){this.variableNames=["x"],this.uniforms="stride : vec2, pad : vec2, dilation : vec2, convDims : vec2, filterDims : vec2,",this.workgroupSize=[128,1,1],this.size=!0,this.outputShape=e.outShape,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.shaderKey=`pool2D_${t}`,this.poolType=t}getUserCode(){let e="resultValue = max(value, resultValue);";this.poolType==="avg"&&(e="resultValue = resultValue + value; count = count + 1.0;");let t="resultValue";return this.poolType==="avg"&&(t="resultValue / count"),` ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); let batch = coords[0]; let xRCCorner = vec2(coords.yz) * uniforms.stride - uniforms.pad; let xRCorner = xRCCorner.x; let xCCorner = xRCCorner.y; var resultValue = ${this.poolType==="avg"?"0.0":"-1.0 / pow(10.0, -20.0)"}; var count = 0.0; for (var wR = 0; wR < uniforms.filterDims.x; wR = wR + uniforms.dilation.x) { let xR = xRCorner + wR; if (xR < 0 || xR >= uniforms.convDims.x) { continue; } for (var wC = 0; wC < uniforms.filterDims.y; wC = wC + uniforms.dilation.y) { let xC = xCCorner + wC; if (xC < 0 || xC >= uniforms.convDims.y) { continue; } let value = getX(batch, xR, xC, coords[3]); ${e} } } setOutputAtIndex(index, ${t}); } } `}},Gie=class{constructor(e){this.variableNames=["x"],this.uniforms="stride : vec2,",this.workgroupSize=[256,1,1],this.size=!0,this.outputShape=e.outShape,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.shaderKey="poolWithFilterSizeEqualsOne"}getUserCode(){return` ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); let batch = coords[0]; let d = coords[3]; let xRCCorner = coords.yz * uniforms.stride; let xRCorner = xRCCorner.x; let xCCorner = xRCCorner.y; let value = getX(batch, xRCorner, xCCorner, d); setOutputAtIndex(index, value); } } `}};function W3(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{reductionIndices:s,keepDims:i}=n;return ko(r,s,i,"max",a)}var Hie={kernelName:Mi,backendName:"webgpu",kernelFunc:W3};function F8(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{keepDims:s,axis:i}=n;return ko(r,i,s,"mean",a)}var jie={kernelName:Pi,backendName:"webgpu",kernelFunc:F8};function O8(e,t,a,n){if(t.filterWidth===1&&t.filterHeight===1&&v.arraysEqual(t.inShape,t.outShape))return Ya({inputs:{x:e},backend:n});if(t.filterWidth===t.inWidth&&t.filterHeight===t.inHeight&&t.batchSize===1&&t.padInfo.type==="VALID"){let i=e.shape.length,o=Ie({inputs:{x:e},backend:n,attrs:{shape:[e.shape[i-3]*e.shape[i-2],e.shape[i-1]]}}),l;a==="avg"?l=F8({inputs:{x:o},backend:n,attrs:{axis:0,keepDims:!1}}):(v.assert(a==="max",()=>`Invalid pool type ${a}`),l=W3({inputs:{x:o},backend:n,attrs:{reductionIndices:0,keepDims:!1}}));let u=Ie({inputs:{x:l},backend:n,attrs:{shape:t.outShape}});return n.disposeData(o.dataId),n.disposeData(l.dataId),u}let r,s=[{type:"int32",data:[t.strideHeight,t.strideWidth]}];return t.filterHeight===1&&t.filterWidth===1?r=new Gie(t):(a==="avg"?r=new Kx(t,"avg"):(v.assert(a==="max",()=>`Invalid pool type ${a}`),r=new Kx(t,"max")),s.push({type:"int32",data:[t.padInfo.top,t.padInfo.left]},{type:"int32",data:[t.dilationHeight,t.dilationWidth]},{type:"int32",data:[t.inHeight,t.inWidth]},{type:"int32",data:[t.effectiveFilterHeight,t.effectiveFilterWidth]})),n.runWebGPUProgram(r,[e],e.dtype,s)}function qie(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{filterSize:s,strides:i,pad:o,dimRoundingMode:l}=n,u=1,p=T.computePool2DInfo(r.shape,s,i,u,o,l);return O8(r,p,"avg",a)}var Xie={kernelName:Qs,backendName:"webgpu",kernelFunc:qie};function Kie(e){let{inputs:t,backend:a,attrs:n}=e,{a:r,b:s}=t,{transposeA:i,transposeB:o}=n;return Hh({a:r,b:s,transposeA:i,transposeB:o,backend:a})}var Zie={kernelName:ei,backendName:"webgpu",kernelFunc:Kie},Yie=class{constructor(e,t){this.variableNames=["source"],this.workPerThread=1,this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=t,this.rank=t.length,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize,[this.workPerThread,1,1]),this.start=e,this.uniforms=`start : ${ra(e.length)}, `,this.shaderKey="slice"}getUserCode(){let e=ra(this.rank),t=Jie(this.rank),a;return this.start.length===1?a=this.outputShape.map((n,r)=>"sourceLoc = uniforms.start + coords;"):a=this.outputShape.map((n,r)=>`sourceLoc.${F1[r]} = uniforms.start.${yr(r)} + coords.${F1[r]};`),` ${Ce("index")} { if (index < uniforms.size) { var sourceLoc : ${e}; let coords = getCoordsFromIndex(index); ${a.join(` `)} setOutputAtIndex(index, getSource(${t})); } } `}},F1=["x","y","z","w","u","v"];function Jie(e){if(e===1)return"sourceLoc";if(e<=6)return F1.slice(0,e).map(t=>`sourceLoc.${t}`).join(",");throw Error(`Slicing for rank ${e} is not yet supported`)}function Au(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{begin:s,size:i}=n,[o,l]=It.parseSliceParams(r,s,i);if(It.assertParamsValid(r,o,l),a.shouldExecuteOnCPU([r])||r.dtype==="string"){let c=a.tensorMap.get(r.dataId),d=nie(c.values,o,l,r.shape,r.dtype);return a.makeTensorInfo(l,r.dtype,d)}if(v.sizeFromShape(l)===0)return a.makeTensorInfo(l,r.dtype,[]);let u=new Yie(o,l),p=[{type:"int32",data:o}];return a.runWebGPUProgram(u,[r],r.dtype,p)}var Qie={kernelName:Zl,backendName:"webgpu",kernelFunc:Au},eoe=e=>{let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{blockShape:s,crops:i}=n;v.assert(r.shape.length<=4,()=>"batchToSpaceND for rank > 4 with a WebGPU backend not implemented yet");let o=s.reduce((A,y)=>A*y),l=T.getReshaped(r.shape,s,o),u=T.getPermuted(l.length,s.length),p=T.getReshapedPermuted(r.shape,s,o),c=T.getSliceBeginCoords(i,s.length),d=T.getSliceSize(p,i,s.length),h=[],f=Ie({inputs:{x:r},backend:a,attrs:{shape:l}}),m=vr({inputs:{x:f},backend:a,attrs:{perm:u}}),g=Ie({inputs:{x:m},backend:a,attrs:{shape:p}}),x=Au({inputs:{x:g},backend:a,attrs:{begin:c,size:d}});return h.push(f),h.push(m),h.push(g),h.forEach(A=>a.disposeData(A.dataId)),x},toe={kernelName:Rl,backendName:"webgpu",kernelFunc:eoe},aoe=` fn bincount_write(index: i32, value: f32) { var oldValue = atomicLoad(& (result[index])); var exchanged = false; for (; !exchanged;) { let newValueF32 = bitcast(oldValue) + value; let newValue = bitcast(newValueF32); let res = atomicCompareExchangeWeak( &(result[index]), oldValue, newValue); oldValue = res.old_value; exchanged = res.exchanged; } } `,noe=` fn bincount_write(index: i32, value: f32) { result[index] = value; } `,D8=class{constructor(e,t,a=!1){this.outputShape=[],this.variableNames=["x"],this.uniforms="binCountSize : i32,",this.workgroupSize=[64,1,1],this.atomic=!0,this.hasWeights=!0,this.binaryOutput=!1,this.outputShape=e,this.rank=e.length,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.binaryOutput=a,a&&(this.atomic=!1),this.hasWeights=t,this.hasWeights&&this.variableNames.push("w"),this.shaderKey=`bincount_${this.hasWeights}_${this.binaryOutput}_${this.rank}`}getUserCode(){return` ${this.binaryOutput?noe:aoe} ${Ce("index")} { ${this.rank===1?`if (index < uniforms.xShape) { let indexVal = i32(getX(index)); if (indexVal < uniforms.binCountSize) { let value = ${this.binaryOutput?1:this.hasWeights?"f32(getW(index))":"1."}; bincount_write(indexVal, value); } }`:`let coord = getCoordsFromIndex(index); if (coordsInBounds2D(coord, uniforms.xShape)) { let indexVal = i32(getX(coord[0], coord[1])); if (indexVal < uniforms.binCountSize) { let value = ${this.binaryOutput?1:this.hasWeights?"f32(getW(coord[0], coord[1]))":"1."}; bincount_write(coord.x * uniforms.binCountSize + indexVal, value); } }`} } `}};function roe(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,weights:s}=t,{size:i}=n,o=v.sizeFromShape(r.shape),l=v.sizeFromShape(s.shape)>0,u=[i],p=s.dtype,c=Cr({backend:a,attrs:{shape:u,value:0,dtype:p}}),d=new D8([o],l),h=[{type:"int32",data:[i]}],f=l?[r,s]:[r];return a.runWebGPUProgram(d,f,p,h,c)}var soe={kernelName:Id,backendName:"webgpu",kernelFunc:roe},z8=ua({opType:De.NOT_EQUAL,dtype:"bool",cpuKernelImpl:Yse}),ioe={kernelName:Li,backendName:"webgpu",kernelFunc:z8};function gp(e){let{inputs:t,backend:a}=e,{input:n}=t,r=a.tensorMap.get(n.dataId);return Ya({inputs:{x:r.complexTensorInfos.real},backend:a})}var ooe={kernelName:Md,backendName:"webgpu",kernelFunc:gp};function loe(e,t){let a=new mp(e.shape,de.TO_INT),n=t.runWebGPUProgram(a,[e],"int32");return{dataId:n.dataId,shape:n.shape,dtype:n.dtype}}function O1(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{dtype:s}=n;if(s==="complex64"){if(r.dtype==="complex64")return Ya({inputs:{x:r},backend:a});let i=fn(r.shape),o=O1({inputs:{x:r},backend:a,attrs:{dtype:"float32"}}),l=wo({inputs:{real:o,imag:i},backend:a});return i.dispose(),a.disposeData(o.dataId),l}if(r.dtype==="complex64"){let i=gp({inputs:{input:r},backend:a}),o=O1({inputs:{x:i},backend:a,attrs:{dtype:s}});return a.disposeData(i.dataId),o}if(!v.hasEncodingLoss(r.dtype,s)){let i=Ya({inputs:{x:r},backend:a});return{dataId:i.dataId,shape:i.shape,dtype:s}}if(a.shouldExecuteOnCPU([r])){let i=a.tensorMap.get(r.dataId).values,[o,l,u]=$se(i,r.shape,r.dtype,s);return a.makeTensorInfo(o,l,u)}if(s==="int32")return loe(r,a);if(s==="bool"){let i=a.makeTensorInfo([],"bool",v.getTypedArrayFromDType("bool",1)),o=z8({inputs:{a:r,b:i},backend:a});return a.disposeData(i.dataId),o}throw new Error(`Error in Cast: failed to cast ${r.dtype} to ${s}`)}var uoe={kernelName:ti,backendName:"webgpu",kernelFunc:O1},doe=it({opType:de.CEIL,cpuKernelImpl:_se}),poe={kernelName:ai,backendName:"webgpu",kernelFunc:doe},coe=class{constructor(e){this.variableNames=["A"],this.uniforms="minVal : f32, maxVal : f32,",this.workPerThread=4,this.workgroupSize=[64,1,1],this.isVec4=!0,this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize,[this.workPerThread,1,1]),this.shaderKey="clipVec4"}getUserCode(){return` ${Ce("index")} { if(index < uniforms.size) { let value = getAByOutputIndex(index); var clampedValue : vec4; for (var i = 0; i < 4; i = i + 1) { if (isnan(value[i])) { clampedValue[i] = value[i]; } else { clampedValue[i] = clamp(value[i], uniforms.minVal, uniforms.maxVal); } } setOutputAtIndex(index, clampedValue); } } `}},hoe=class{constructor(e){this.variableNames=["A"],this.uniforms="minVal : f32, maxVal : f32,",this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.shaderKey="clip"}getUserCode(){return` ${Ce("index")} { if(index < uniforms.size) { let value = getAByOutputIndex(index); if (isnan(value)) { setOutputAtIndex(index, value); return; } setOutputAtIndex(index, clamp(value, uniforms.minVal, uniforms.maxVal)); } } `}};function foe(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{clipValueMin:s,clipValueMax:i}=n,o,l=[{type:"float32",data:[s]},{type:"float32",data:[i]}];return v.sizeFromShape(r.shape)%4===0?o=new coe(r.shape):o=new hoe(r.shape),a.runWebGPUProgram(o,[r],r.dtype,l)}var moe={kernelName:as,backendName:"webgpu",kernelFunc:foe},goe=class{constructor(e){this.uniforms="",this.workPerThread=1,this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=T.computeOutShape(e,1),this.variableNames=e.map((t,a)=>`T${a}`),this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize,[this.workPerThread,1,1]),this.offsetLength=e.length-1;for(let t=0;t0){e.push("if (yC < uniforms.offset0){ setOutputAtCoords(coords.x, coords.y, getT0(yR, yC)); }");for(let n=1;ngp({inputs:{input:y},backend:a})),m=e.map(y=>jh({inputs:{input:y},backend:a})),g=Ju(f,t,a),x=Ju(m,t,a),A=wo({inputs:{real:g,imag:x},backend:a});return f.forEach(y=>a.disposeData(y.dataId)),m.forEach(y=>a.disposeData(y.dataId)),a.disposeData(g.dataId),a.disposeData(x.dataId),A}let r=a.shouldExecuteOnCPU(e);if(n==="string"&&(r=!0),r){let f=e.map(w=>{let S=[-1,v.sizeFromShape(w.shape.slice(t))];return Ie({inputs:{x:w},backend:a,attrs:{shape:S}})}),m=f.map(w=>({vals:a.readSync(w.dataId),shape:w.shape})),g=T.computeOutShape(f.map(w=>w.shape),1),x=f[0].shape[0]===1,A=Pse(m,g,n,x),y=T.computeOutShape(e.map(w=>w.shape),t),b=a.makeTensorInfo(y,n,A);return f.forEach(w=>a.disposeData(w.dataId)),b}let s=a.device.limits.maxStorageBuffersPerShaderStage-1;if(e.length>s){let f=[];for(let g=0;gf.shape),u=new goe(l),p=[],c=new Array(l.length-1);if(c.length>0){c[0]=l[0][1],p.push({type:"int32",data:[c[0]]});for(let f=1;fa.disposeData(f.dataId));let h=Ie({inputs:{x:d},backend:a,attrs:{shape:o}});return a.disposeData(d.dataId),h}function Aoe(e,t,a){let n=T.computeOutShape(e.map(r=>r.shape),t);return{tensors2D:e.map(r=>Ie({inputs:{x:r},backend:a,attrs:{shape:[v.sizeFromShape(r.shape.slice(0,t)),v.sizeFromShape(r.shape.slice(t))]}})),outShape:n}}function L8(e){let{inputs:t,backend:a,attrs:n}=e,{axis:r}=n,s=v.parseAxisParam(r,t[0].shape)[0],i=t.map(u=>u.shape);T.assertParamsConsistent(i,s);let o=T.computeOutShape(t.map(u=>u.shape),s);if(v.sizeFromShape(o)===0)return a.makeTensorInfo(o,t[0].dtype,[]);let l=t.filter(u=>v.sizeFromShape(u.shape)>0);return l.length===1?Ya({inputs:{x:l[0]},backend:a}):Ju(l,s,a)}var yoe={kernelName:Ml,backendName:"webgpu",kernelFunc:L8};function boe(e,t,a,n,r=!1,s=null,i=!1,o=4,l=4,u=4){let p=E=>{switch(E){case 1:return"resData = x[xIndex];";case 3:return"resData = vec3(x[xIndex], x[xIndex + 1], x[xIndex + 2]);";case 4:return"resData = x[xIndex / 4];";default:throw new Error(`innerElementSize ${E} is not supported.`)}},c=E=>{switch(E){case 1:return"return W[row * uniforms.wShape[3] + colIn];";case 4:return"return W[row * uniforms.wShape[3] / 4 + colIn];";default:throw new Error(`innerElementSize ${E} is not supported.`)}},d=e?` let coord = vec4(batch, xRow, xCol, xCh); `:` let coord = vec4(batch, xCh, xRow, xCol); `,h=e?` let coords = vec4( batch, row / outWidth, row % outWidth, col); `:` let coords = vec4( batch, row, col / outWidth, col % outWidth); `,f=e?"uniforms.xShape[1]":"uniforms.xShape[2]",m=e?"uniforms.xShape[2]":"uniforms.xShape[3]",g=e?"row":"col",x=e?"col":"row",A=` let inChannels = uniforms.wShape[2]; let outWidth = ${e?"uniforms.outShape[2]":"uniforms.outShape[3]"}; let outRow = ${g} / outWidth; let outCol = ${g} % outWidth; let WRow = ${x} / (uniforms.filterDims[1] * inChannels); let WCol = ${x} / inChannels % uniforms.filterDims[1]; let xRow = outRow * uniforms.stride[0] + uniforms.dilation[0] * WRow - uniforms.pad[0]; let xCol = outCol * uniforms.stride[1] + uniforms.dilation[1] * WCol - uniforms.pad[1]; let xCh = ${x} % inChannels; var resData = ${Mt(o)}(0.0); // The bounds checking is always needed since we use it to pad zero for // the 'same' padding type. if (xRow >= 0 && xRow < ${f} && xCol >= 0 && xCol < ${m}) { ${d} let xIndex = getIndexFromCoords4D(coord, uniforms.xShape); ${p(o)} } return resData;`,y=e?t&&n?` let col = colIn * ${o}; ${A}`:` let col = colIn * ${o}; if (row < uniforms.dimAOuter && col < uniforms.dimInner) { ${A} } return ${Mt(o)}(0.0);`:n&&a?` let col = colIn * ${o}; ${A}`:` let col = colIn * ${o}; if (row < uniforms.dimInner && col < uniforms.dimBOuter) { ${A} } return ${Mt(o)}(0.0);`,b=`${c(l)}`,w=Mt(u),S=Mt(e?o:l),C=Mt(e?l:o);return` ${Tr(s,i,u===4,4)} fn mm_readA(batch: i32, row : i32, colIn : i32) -> ${S} { ${e?y:b} } fn mm_readB(batch: i32, row : i32, colIn : i32) -> ${C} { ${e?b:y} } fn mm_write(batch: i32, row : i32, colIn : i32, valueIn : ${w}) { let col = colIn * ${u}; if (row < uniforms.dimAOuter && col < uniforms.dimBOuter) { var value = valueIn; let outWidth = ${e?"uniforms.outShape[2]":"uniforms.outShape[3]"}; ${h} ${vo(r,s)} setOutputAtCoords(coords[0], coords[1], coords[2], coords[3], value); } }`}var voe=class{constructor(e,t,a,n,r=!1,s=null,i=!1,o=!1){this.variableNames=["x","W"],this.uniforms="filterDims : vec2, pad : vec2, stride : vec2, dilation : vec2, dimAOuter : i32, dimBOuter : i32, dimInner : i32,",this.outputShape=e.outShape,this.isChannelsLast=e.dataFormat==="channelsLast",this.isVec4=((e.inChannels%4===0||e.inChannels%3===0)&&this.isChannelsLast||e.outWidth%4===0&&!this.isChannelsLast)&&e.outChannels%4===0,this.dispatchLayout=this.isChannelsLast?{x:[3],y:[1,2],z:[0]}:{x:[2,3],y:[1],z:[0]},this.workgroupSize=F3(this.dispatchLayout,this.outputShape,this.isVec4),this.elementsPerThread=O3(this.dispatchLayout,this.outputShape,this.isVec4),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize,this.elementsPerThread),this.isVec4?(this.isChannelsLast&&e.inChannels%4!==0?(this.innerElementSize=3,this.variableTypes=["f32","vec4"]):(this.innerElementSize=4,this.variableTypes=["vec4","vec4"]),r&&(this.variableNames.push("bias"),this.variableTypes.push("vec4")),i&&(this.variableNames.push("preluActivationWeights"),this.variableTypes.push("vec4"))):(this.innerElementSize=this.elementsPerThread[0],r&&this.variableNames.push("bias"),i&&this.variableNames.push("preluActivationWeights")),this.sequentialAccessByThreads=o,this.addBias=r,this.activation=s,this.hasPreluActivationWeights=i,this.tileAOuter=this.workgroupSize[1]*this.elementsPerThread[1],this.tileBOuter=this.workgroupSize[0]*this.elementsPerThread[0],this.tileInner=Math.max(this.workgroupSize[0]*this.innerElementSize,this.workgroupSize[1]),this.fitAOuter=t%this.tileAOuter===0,this.fitBOuter=a%this.tileBOuter===0,this.fitInner=n%this.tileInner===0,this.shaderKey=`conv2DMM_${this.elementsPerThread}_${this.activation}}_${this.fitAOuter}_${this.fitBOuter}_${this.fitInner}_${this.isVec4}_${this.innerElementSize}_${this.isChannelsLast}_${this.sequentialAccessByThreads}`}getUserCode(){let e=this.isVec4?Uh(this.elementsPerThread,this.workgroupSize,!this.isChannelsLast,this.tileInner):Gh(this.elementsPerThread,this.workgroupSize,!this.isChannelsLast,this.tileInner,!1,null,this.sequentialAccessByThreads),t=this.isVec4?[this.innerElementSize,4,4]:[1,1,1];return` ${boe(this.isChannelsLast,this.fitAOuter,this.fitBOuter,this.fitInner,this.addBias,this.activation,this.hasPreluActivationWeights,t[0],t[1],t[2])} ${e} `}},woe=class{constructor(e,t=!1,a=null,n=!1){this.variableNames=["x","W"],this.uniforms="filterDims: vec2, pad: vec2, stride: vec2, dilation: vec2,",this.workgroupSize=[4,4,8],this.outputShape=e.outShape,this.isChannelsLast=e.dataFormat==="channelsLast",this.dispatchLayout=this.isChannelsLast?{x:[2],y:[1],z:[0,3]}:{x:[3],y:[2],z:[0,1]},this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.addBias=t,this.activation=a,this.hasPreluActivationWeights=n,t&&this.variableNames.push("bias"),n&&this.variableNames.push("preluActivationWeights"),this.shaderKey=`conv2dnaive_${this.activation}_${this.isChannelsLast}`}getUserCode(){return` ${Tr(this.activation,this.hasPreluActivationWeights,!1,4)} fn readInp(batch : i32, row : i32, col : i32, chan : i32) -> f32{ let coords = vec4(batch, row, col, chan); if (coordsInBounds4D(coords, uniforms.xShape)) { return getX(batch, row, col, chan); } else { return 0.0; } } fn readFilt(row : i32, col : i32, xChannel : i32, outChannel : i32) -> f32{ let coords = vec4(row, col, xChannel, outChannel); if(coordsInBounds4D(coords, uniforms.wShape)) { return getW(row, col, xChannel, outChannel); } else { return 0.0; } } fn writeResult(batch : i32, row : i32, col : i32, chan : i32, valueIn : f32) { let coords = ${this.isChannelsLast?"vec4(batch, row, col, chan);":"vec4(batch, chan, row, col);"} if (coordsInBounds4D(coords, uniforms.outShape)) { var value = valueIn; ${vo(this.addBias,this.activation)} setOutputAtCoords(coords.x, coords.y, coords.z, coords.w, value); } } ${Ce("index")} { let coords = getOutputCoords(); let batch = coords[0]; let outChannel = ${this.isChannelsLast?"coords[3];":"coords[1];"} let outRow = ${this.isChannelsLast?"coords[1];":"coords[2];"} let outCol = ${this.isChannelsLast?"coords[2];":"coords[3];"} var acc : f32 = 0.0; for (var row = 0; row < uniforms.filterDims[0]; row = row + 1) { for (var col = 0; col < uniforms.filterDims[1]; col = col + 1) { let xRow = outRow * uniforms.stride[0] + uniforms.dilation[0] * row - uniforms.pad[0]; let xCol = outCol * uniforms.stride[1] + uniforms.dilation[1] * col - uniforms.pad[1]; for (var xChannel = 0; xChannel < ${this.isChannelsLast?"uniforms.xShape[3];":"uniforms.xShape[1];"} xChannel = xChannel + 1) { ${this.isChannelsLast?"let v = readInp(batch, xRow, xCol, xChannel);":"let v = readInp(batch, xChannel, xRow, xCol);"} let f = readFilt(row, col, xChannel, outChannel); acc = acc + v * f; } } } writeResult(batch, outRow, outCol, outChannel, acc); } `}},koe=class{constructor(e,t){this.variableNames=["x"],this.uniforms=`pad : vec2, stride : vec2, dilation : vec2, outWidth : i32, itemsPerBlockRow : i32, inChannels : i32,`,this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.isChannelsLast=t,this.shaderKey=`im2col_${this.isChannelsLast}`}getUserCode(){let e=this.isChannelsLast?1:2,t=this.isChannelsLast?2:3,a=this.isChannelsLast?"coords[1]":"coords[2]",n=this.isChannelsLast?"coords[2]":"coords[1]",r=this.isChannelsLast?"getX(batch, xRow, xCol, ch)":"getX(batch, ch, xRow, xCol)";return` ${Ce("index")} { let coords = getCoordsFromIndex(index); if(index < uniforms.size) { let batch = coords[0]; let row = ${a}; let col = ${n}; let offsetY = (row / uniforms.outWidth) * uniforms.stride[0] - uniforms.pad[0]; let xRow = offsetY + uniforms.dilation[0] * (col / uniforms.itemsPerBlockRow); var value = 0.0; if(xRow < uniforms.xShape[${e}] && xRow >= 0) { let offsetX = (row % uniforms.outWidth) * uniforms.stride[1] - uniforms.pad[1]; let xCol = offsetX + uniforms.dilation[1] * ((col % uniforms.itemsPerBlockRow) / uniforms.inChannels); let ch = col % uniforms.inChannels; if(xCol < uniforms.xShape[${t}] && xCol >= 0) { value = ${r}; } } setOutputAtIndex(index, value); } } `}};function Wc(e,t){let a=e.length;return a>=3?t?[...e.slice(0,-3),e[a-3]*e[a-2],e[a-1]]:[...e.slice(0,-3),e[a-3],e[a-2]*e[a-1]]:!t&&a===1&&e[0]>1?[e[0],1]:null}function Ioe({x:e,filter:t,convInfo:a,backend:n,bias:r=null,preluActivationWeights:s=null,leakyreluAlpha:i=0,activation:o=null}){let l=a.dataFormat==="channelsLast",u=!l,p=!1,c=l&&a.filterHeight===a.inHeight&&a.filterWidth===a.inWidth&&a.padInfo.type==="VALID",d=[],h,f;if(c){let x=a.inHeight*a.inWidth*a.inChannels;h=Ie({inputs:{x:e},backend:n,attrs:{shape:[1,a.batchSize,x]}}),f=Ie({inputs:{x:t},backend:n,attrs:{shape:[1,x,a.outChannels]}})}else h=Ie({inputs:{x:e},backend:n,attrs:{shape:l?[a.batchSize,a.inHeight*a.inWidth,a.inChannels]:[a.batchSize,a.inChannels,a.inHeight*a.inWidth]}}),f=Ie({inputs:{x:t},backend:n,attrs:{shape:[1,a.inChannels,a.outChannels]}});if(d.push(h),d.push(f),s!=null){let x=Wc(s.shape,l);x!=null&&(s=Ie({inputs:{x:s},backend:n,attrs:{shape:x}}),d.push(s))}if(r!=null){let x=Wc(r.shape,l);x!=null&&(r=Ie({inputs:{x:r},backend:n,attrs:{shape:x}}),d.push(r))}let m=Hh({a:l?h:f,b:l?f:h,transposeA:u,transposeB:p,backend:n,bias:r,activation:o,preluActivationWeights:s,leakyreluAlpha:i}),g=Ie({inputs:{x:m},backend:n,attrs:{shape:a.outShape}});d.push(m);for(let x of d)n.disposeData(x.dataId);return g}function Soe({x:e,filter:t,convInfo:a,backend:n,bias:r=null,preluActivationWeights:s=null,leakyreluAlpha:i=0,activation:o=null}){let{filterWidth:l,filterHeight:u,inChannels:p,strideWidth:c,strideHeight:d,padInfo:h,outWidth:f,outHeight:m,dilationWidth:g,dilationHeight:x,dataFormat:A}=a,y=A==="channelsLast",b=l*u*p,w=m*f,S=y?[a.batchSize,w,b]:[a.batchSize,b,w],C=new koe(S,y),E=[{type:"int32",data:[h.top,h.left]},{type:"int32",data:[d,c]},{type:"int32",data:[x,g]},{type:"int32",data:[f]},{type:"int32",data:[p*l]},{type:"int32",data:[p]}],_=n.runWebGPUProgram(C,[e],e.dtype,E),$=[];$.push(_);let M=Ie({inputs:{x:t},backend:n,attrs:{shape:[1,b,-1]}});if($.push(M),s!=null){let O=Wc(s.shape,y);O!=null&&(s=Ie({inputs:{x:s},backend:n,attrs:{shape:O}}),$.push(s))}if(r!=null){let O=Wc(r.shape,y);O!=null&&(r=Ie({inputs:{x:r},backend:n,attrs:{shape:O}}),$.push(r))}let I=Hh({a:y?_:M,b:y?M:_,transposeA:!y,transposeB:!1,backend:n,bias:r,activation:o,preluActivationWeights:s,leakyreluAlpha:i}),N=Ie({inputs:{x:I},backend:n,attrs:{shape:a.outShape}});$.push(I);for(let O of $)n.disposeData(O.dataId);return N}function B8({x:e,filter:t,convInfo:a,backend:n,bias:r=null,preluActivationWeights:s=null,leakyreluAlpha:i=0,activation:o=null}){let l=r!=null,u=s!=null,p=a.dataFormat==="channelsLast",c=p&&a.filterHeight===a.inHeight&&a.filterWidth===a.inWidth&&a.padInfo.type==="VALID",d=W().getBool("WEBGPU_USE_NAIVE_CONV2D_DEBUG");if(!d&&(c||a.filterHeight===1&&a.filterWidth===1&&a.dilationHeight===1&&a.dilationWidth===1&&a.strideHeight===1&&a.strideWidth===1&&(a.padInfo.type==="SAME"||a.padInfo.type==="VALID")))return Ioe({x:e,filter:t,convInfo:a,backend:n,bias:r,activation:o,preluActivationWeights:s,leakyreluAlpha:i});let h=W().getNumber("WEBGPU_THRESHOLD_TO_INCREASE_WORKGROUPS_FOR_MATMUL"),f=h>0?h:n.thresholdToIncreaseWorkgroups,m=a.batchSize*Math.ceil(a.outHeight*a.outWidth/32)*Math.ceil(a.outChannels/32);if(W().getBool("WEBGPU_CONV_SEPARATE_IM2COL_SHADER")||m<=f)return Soe({x:e,filter:t,convInfo:a,backend:n,bias:r,preluActivationWeights:s,leakyreluAlpha:i,activation:o});let g,x=[a.padInfo.top,a.padInfo.left],A=[{type:"int32",data:[a.filterHeight,a.filterWidth]},{type:"int32",data:[...x]},{type:"int32",data:[a.strideHeight,a.strideWidth]},{type:"int32",data:[a.dilationHeight,a.dilationWidth]}];if(d)g=new woe(a,l,o,u);else{let S=p?a.outHeight*a.outWidth:a.outChannels,C=p?a.outChannels:a.outHeight*a.outWidth,E=a.filterHeight*a.filterWidth*a.inChannels;A.push({type:"int32",data:[S]},{type:"int32",data:[C]},{type:"int32",data:[E]});let _=n.adapterInfo.isIntel();g=new voe(a,S,C,E,l,o,u,_)}let y=[],b=[e,t];l&&(!p&&r.shape.length===1&&(r=Ie({inputs:{x:r},backend:n,attrs:{shape:[r.shape[0],1,1]}}),y.push(r)),b.push(r)),u&&(!p&&s.shape.length===1&&(s=Ie({inputs:{x:s},backend:n,attrs:{shape:[s.shape[0],1,1]}}),y.push(s)),b.push(s)),o==="leakyrelu"&&(A.push({type:"float32",data:[i]}),g.uniforms+=" alpha : f32,");let w=n.runWebGPUProgram(g,b,e.dtype,A);for(let S of y)n.disposeData(S.dataId);return w}function Toe(e){let{inputs:t,attrs:a,backend:n}=e,{x:r,filter:s}=t,{strides:i,pad:o,dataFormat:l,dilations:u,dimRoundingMode:p}=a,c=T.convertConv2DDataFormat(l),d=T.computeConv2DInfo(r.shape,s.shape,i,u,o,p,!1,c);return B8({x:r,filter:s,convInfo:d,backend:n})}var Coe={kernelName:ni,backendName:"webgpu",kernelFunc:Toe};function Noe(e=4){let t=n=>{switch(n){case 1:return"return W[getIndexFromCoords4D(coord, uniforms.wShape)];";case 4:return` let coord1 = vec4(coordX, coordY, col + 1, rowInner); let coord2 = vec4(coordX, coordY, col + 2, rowInner); let coord3 = vec4(coordX, coordY, col + 3, rowInner); let v0 = W[getIndexFromCoords4D(coord, uniforms.wShape)]; let v1 = W[getIndexFromCoords4D(coord1, uniforms.wShape)]; let v2 = W[getIndexFromCoords4D(coord2, uniforms.wShape)]; let v3 = W[getIndexFromCoords4D(coord3, uniforms.wShape)]; return vec4(v0, v1, v2, v3); `;default:throw new Error(`innerElementSize ${n} is not supported.`)}},a=`if (row < uniforms.dimAOuter && col < uniforms.dimInner) { ${` let outRow = row / uniforms.outShape[2]; let outCol = row % uniforms.outShape[2]; let WRow = col / (uniforms.filterDims[1] * uniforms.outBackprop[3]); let WCol = col / uniforms.outBackprop[3] % uniforms.filterDims[1]; let xR = f32(outRow - uniforms.pads[0] + WRow) / f32(uniforms.stride[0]); let xC = f32(outCol - uniforms.pads[1] + WCol) / f32(uniforms.stride[1]); if (xR < 0.0 || xR >= f32(uniforms.outBackprop[1]) || fract(xR) > 0.0) { return ${Mt(e)}(0.0); } if (xC < 0.0 || xC >= f32(uniforms.outBackprop[2]) || fract(xC) > 0.0) { return ${Mt(e)}(0.0); } let coord = vec4( batch, i32(xR), i32(xC), col % uniforms.outBackprop[3]); return x[getIndexFromCoords4D(coord, uniforms.xShape)/${e}];`} } return ${Mt(e)}(0.0);`;return` fn mm_readA(batch: i32, row : i32, colIn : i32) -> ${Mt(e)} { let col = colIn * ${e}; ${a} } fn mm_readB(batch: i32, row : i32, colIn : i32) -> ${Mt(e)} { let col = colIn * ${e}; let coordX = uniforms.filterDims.x - 1 - row / (uniforms.filterDims[1] * uniforms.outBackprop[3]); let coordY = uniforms.filterDims.y - 1 - (row / uniforms.outBackprop[3]) % uniforms.filterDims[1]; if (row < uniforms.dimInner && col < uniforms.dimBOuter && coordX >= 0 && coordY >= 0) { let rowInner = row % uniforms.outBackprop[3]; let coord = vec4(coordX, coordY, col, rowInner); ${t(e)} } return ${Mt(e)}(0.0); } fn mm_write(batch: i32, row : i32, colIn : i32, valueInput : ${Mt(e)}) { let col = colIn * ${e}; if (row < uniforms.dimAOuter && (col + ${e-1}) < uniforms.dimBOuter) { var value = valueInput; let outCoord = vec4( batch, row / uniforms.outShape[2], row % uniforms.outShape[2], col); result[getIndexFromCoords4D(outCoord, uniforms.outShape)/${e}] = value; } }`}var Eoe=class{constructor(e){this.variableNames=["x","W"],this.uniforms="filterDims : vec2, pads : vec2, stride : vec2, outBackprop : vec4, dimAOuter : i32, dimBOuter : i32, dimInner : i32,",this.outputShape=e.inShape,v.assert(e.dataFormat==="channelsLast",()=>"TODO: NCHW is unimplemented"),this.isVec4=e.inChannels%4===0&&e.outChannels%4===0,this.dispatchLayout={x:[3],y:[1,2],z:[0]},this.workgroupSize=F3(this.dispatchLayout,this.outputShape,this.isVec4),this.elementsPerThread=O3(this.dispatchLayout,this.outputShape,this.isVec4),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize,this.elementsPerThread),this.isVec4&&(this.variableTypes=["vec4","f32"]),this.shaderKey=`conv2DDerInputMM_${this.isVec4}_${this.elementsPerThread}`}getUserCode(){let e=this.isVec4?Uh(this.elementsPerThread,this.workgroupSize):Gh(this.elementsPerThread,this.workgroupSize);return` ${Noe(this.isVec4?4:1)} ${e} `}},Roe=class{constructor(e){this.variableNames=["dy","W"],this.uniforms="filterDims : vec2, pads : vec2, stride : vec2, outBackprop : vec4,",this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e.inShape,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.isChannelsLast=e.dataFormat==="channelsLast",this.shaderKey=`conv2DDerInput_${this.isChannelsLast}`}getUserCode(){let e=this.isChannelsLast?1:2,t=this.isChannelsLast?2:3,a=this.isChannelsLast?3:1;return` ${Ce("index")} { if(index < uniforms.size) { let coords = getCoordsFromIndex(index); let batch = coords[0]; let d1 = coords[${a}]; let dyCorner = vec2(coords[${e}], coords[${t}]) - uniforms.pads; let dyRCorner = dyCorner.x; let dyCCorner = dyCorner.y; // Convolve dy(?, ?, d2) with w(:, :, d1, d2) to compute dx(xR, xC, d1). // ? = to be determined. : = across all values in that axis. var dotProd = 0.0; for (var wR = 0; wR < uniforms.filterDims.x; wR = wR + 1) { let dyR = (f32(dyRCorner) + f32(wR)) / f32(uniforms.stride.x); let wRPerm = uniforms.filterDims.x - 1 - wR; if (dyR < 0.0 || dyR >= f32(uniforms.outBackprop[1]) || fract(dyR) > 0.0 || wRPerm < 0) { continue; } let idyR = i32(dyR); for (var wC = 0; wC < uniforms.filterDims.y; wC = wC + 1) { let dyC = (f32(dyCCorner) + f32(wC)) / f32(uniforms.stride.y); let wCPerm = uniforms.filterDims.y - 1 - wC; if (dyC < 0.0 || dyC >= f32(uniforms.outBackprop[2]) || fract(dyC) > 0.0 || wCPerm < 0) { continue; } let idyC = i32(dyC); for (var d2 = 0; d2 < uniforms.outBackprop[3]; d2 = d2 + 1) { if (${this.isChannelsLast}) { let xValue = getDy(batch, idyR, idyC, d2); let wValue = getW(wRPerm, wCPerm, d1, d2); dotProd = dotProd + xValue * wValue; } else { let xValue = getDy(batch, d2, idyR, idyC); let wValue = getW(wRPerm, wCPerm, d1, d2); dotProd = dotProd + xValue * wValue; } } } } setOutputAtIndex(index, dotProd); } } `}};function Moe(e){let{inputs:t,backend:a,attrs:n}=e,{dy:r,filter:s}=t,{inputShape:i,strides:o,pad:l,dataFormat:u,dimRoundingMode:p}=n,c=T.convertConv2DDataFormat(u),d=T.computeConv2DInfo(i,s.shape,o,1,l,p,!1,c),h=[{type:"int32",data:[d.filterHeight,d.filterWidth]},{type:"int32",data:[d.filterHeight-1-d.padInfo.top,d.filterWidth-1-d.padInfo.left]},{type:"int32",data:[d.strideHeight,d.strideWidth]},{type:"int32",data:[d.batchSize,d.outHeight,d.outWidth,d.outChannels]}],f;if(W().getBool("WEBGPU_USE_NAIVE_CONV2D_TRANSPOSE")||d.filterHeight<=2&&d.filterWidth<=2&&d.outChannels<=16&&d.inChannels===1)f=new Roe(d);else{f=new Eoe(d);let m=d.inHeight*d.inWidth,g=d.inChannels,x=d.filterHeight*d.filterWidth*d.outChannels;h.push({type:"uint32",data:[m]},{type:"uint32",data:[g]},{type:"uint32",data:[x]})}return a.runWebGPUProgram(f,[r,s],"float32",h)}var $oe={kernelName:ri,backendName:"webgpu",kernelFunc:Moe},_oe=it({opType:de.COS}),Poe={kernelName:si,backendName:"webgpu",kernelFunc:_oe},Foe=it({opType:de.COSH}),Ooe={kernelName:ii,backendName:"webgpu",kernelFunc:Foe},Doe=class{constructor(e,t,a,n){this.variableNames=["Image","Boxes","BoxInd"],this.uniforms="extrapolationValue : f32,",this.workgroupSize=[64,1,1],this.size=!0;let[r]=t;this.outputShape=[r,a[0],a[1],e],this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.methodId=n==="bilinear"?1:0,this.cropHeightBiggerThan1=this.outputShape[1]>1,this.cropWidthBiggerThan1=this.outputShape[2]>1,this.shaderKey=`cropAndResize_${this.methodId}_${this.cropHeightBiggerThan1}_${this.cropWidthBiggerThan1}`}getUserCode(){let[e,t]=["f32(uniforms.imageShape[1] - 1)","f32(uniforms.imageShape[2] - 1)"],[a,n,r]=this.cropHeightBiggerThan1?[`(${e} / f32(uniforms.outShape[1] - 1))`,"(y2-y1) * height_ratio",`y1*${e} + f32(y)*(height_scale)`]:["0.0","0.0",`0.5 * (y1+y2) * ${e}`],[s,i,o]=this.cropWidthBiggerThan1?[`(${t} / f32(uniforms.outShape[2] - 1))`,"(x2-x1) * width_ratio",`x1*${t} + f32(x)*(width_scale)`]:["0.0","0.0",`0.5 * (x1+x2) * ${t}`];return` ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); let height_ratio = f32(${a}); let width_ratio = f32(${s}); let b = coords[0]; let y = coords[1]; let x = coords[2]; let d = coords[3]; // get box vals let y1 = getBoxes(b, 0); let x1 = getBoxes(b, 1); let y2 = getBoxes(b, 2); let x2 = getBoxes(b, 3); // get image in batch index let bInd = i32(round(getBoxInd(b))); if(bInd < 0 || bInd >= uniforms.outShape[0]) { return; } let height_scale = ${n}; let width_scale = ${i}; let in_y = ${r}; if( in_y < 0.0 || in_y > ${e} ) { setOutputAtIndex(index, uniforms.extrapolationValue); return; } let in_x = ${o}; if( in_x < 0.0 || in_x > ${t} ) { setOutputAtIndex(index, uniforms.extrapolationValue); return; } let sourceFracIndexCR = vec2(in_x,in_y); if(${this.methodId} == 1) { // Compute the four integer indices. let sourceFloorCR = vec2(sourceFracIndexCR); let sourceCeilCR = vec2(ceil(sourceFracIndexCR)); let topLeft = getImage(bInd, sourceFloorCR.y, sourceFloorCR.x, d); let bottomLeft = getImage(bInd, sourceCeilCR.y, sourceFloorCR.x, d); let topRight = getImage(bInd, sourceFloorCR.y, sourceCeilCR.x, d); let bottomRight = getImage(bInd, sourceCeilCR.y, sourceCeilCR.x, d); let fracCR = sourceFracIndexCR - vec2(sourceFloorCR); let top = topLeft + (topRight - topLeft) * fracCR.x; let bottom = bottomLeft + (bottomRight - bottomLeft) * fracCR.x; let newValue = top + (bottom - top) * fracCR.y; setOutputAtIndex(index, newValue); } else { // Compute the coordinators of nearest neighbor point. let sourceNearestCR = vec2(floor( sourceFracIndexCR + vec2(0.5,0.5))); let newValue = getImage( bInd, sourceNearestCR.y, sourceNearestCR.x, d); setOutputAtIndex(index, newValue); } } } `}},zoe=e=>{let{inputs:t,backend:a,attrs:n}=e,{image:r,boxes:s,boxInd:i}=t,{cropSize:o,method:l,extrapolationValue:u}=n,p=new Doe(r.shape[3],s.shape,o,l),c=[{type:"float32",data:[u]}];return a.runWebGPUProgram(p,[r,s,i],"float32",c)},Loe={kernelName:ui,backendName:"webgpu",kernelFunc:zoe},bd;(function(e){e.Prod="*",e.Sum="+"})(bd||(bd={}));var Zx=class{constructor(e,t,a,n){this.variableNames=["x"],this.uniforms="index : f32,",this.size=!0,this.workgroupSize=[128,1,1],this.outputShape=t,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.exclusive=a,this.reverse=n,this.op=e,this.shaderKey=`cum_${this.op}_${this.exclusive}_${this.reverse}`}getUserCode(){let e=this.outputShape.length,t=this.op===bd.Prod?"1.0":"0.0",a=this.exclusive?t:`getX(${Yx(e,"coords",this.op)})`,n=this.outputShape[this.outputShape.length-1],r="",s="";return this.exclusive?(r=this.reverse?`end != ${n-1}`:"end != 0",s=this.reverse?"end + 1":"end - 1"):(r=this.reverse?`end + pow2 < ${n}`:"end >= pow2",s=this.reverse?"end + pow2":"end - pow2"),` ${Ce("index")} { if (index < uniforms.size) { var coords = getCoordsFromIndex(index); let end = ${Jx(e,"coords",this.op)}; var val = ${a}; let pow2 = i32(pow(2.0, uniforms.index)); if (${r}) { let idx = ${s}; ${Jx(e,"coords",this.op)} = idx; val ${this.op}= getX(${Yx(e,"coords",this.op)}); } setOutputAtIndex(index, val); } } `}};function Yx(e,t,a){if(e===1)return`${t}`;if(e===2)return`${t}.x, ${t}.y`;if(e===3)return`${t}.x, ${t}.y, ${t}.z`;if(e===4)return`${t}.x, ${t}.y, ${t}.z, ${t}.w`;throw Error(`Cumulative ${a} for rank ${e} is not yet supported`)}function Jx(e,t,a){if(e===1)return`${t}`;if(e===2)return`${t}.y`;if(e===3)return`${t}.z`;if(e===4)return`${t}.w`;throw Error(`Cumulative ${a} for rank ${e} is not yet supported`)}function W8(e,t,a,n,r,s){let i=t.shape.length,o=T.getAxesPermutation([n],i),l=t;o!=null&&(l=vr({inputs:{x:t},backend:a,attrs:{perm:o}}));let u=T.getInnerMostAxes(1,i)[0];if(u!==i-1)throw new Error(`WebGPU cumprod shader expects an inner-most axis=${t.shape.length-1} but got axis=${n}`);let p=l.shape[u],c=Ya({inputs:{x:l},backend:a});for(let d=0;d<=Math.ceil(Math.log2(p))-1;d++){let h=new Zx(e,l.shape,!1,s),f=c,m=[{type:"float32",data:[d]}];c=a.runWebGPUProgram(h,[c],c.dtype,m),a.disposeData(f.dataId)}if(r){let d=new Zx(e,l.shape,r,s),h=c,f=[{type:"float32",data:[0]}];c=a.runWebGPUProgram(d,[c],c.dtype,f),a.disposeData(h.dataId)}if(o!=null){let d=T.getUndoAxesPermutation(o),h=vr({inputs:{x:c},backend:a,attrs:{perm:d}});return a.disposeData(c.dataId),a.disposeData(l.dataId),h}return c}function Boe(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,exclusive:i,reverse:o}=n;return W8(bd.Prod,r,a,s,i,o)}var Woe={kernelName:oi,backendName:"webgpu",kernelFunc:Boe};function Voe(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,exclusive:i,reverse:o}=n;return W8(bd.Sum,r,a,s,i,o)}var Uoe={kernelName:li,backendName:"webgpu",kernelFunc:Voe};function Goe(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,weights:s}=t,{size:i,binaryOutput:o}=n,l=r.shape.length===1,u=v.sizeFromShape(s.shape)>0,p=s.dtype,c=l?[r.shape[0]]:[r.shape[0],r.shape[1]],d=l?[i]:[r.shape[0],i],h=Cr({backend:a,attrs:{shape:d,value:0,dtype:p}}),f=new D8(c,u,o),m=[{type:"int32",data:[i]}],g=u?[r,s]:[r];return a.runWebGPUProgram(f,g,p,m,h)}var Hoe={kernelName:Td,backendName:"webgpu",kernelFunc:Goe},joe=class{constructor(e,t){this.variableNames=["x"],this.workgroupSize=[64,1,1],this.size=!0,this.uniforms="blockSize : i32,",this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.shaderKey=`depthToSpace_${t}`,this.dataFormat=t}getUserCode(){return` ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); let b = coords[0]; let h = ${this.getHeightCoordString()}; let w = ${this.getWidthCoordString()}; let d = ${this.getDepthCoordString()}; let in_h = h / uniforms.blockSize; let offset_h = h % uniforms.blockSize; let in_w = w / uniforms.blockSize; let offset_w = w % uniforms.blockSize; let offset_d = (offset_h * uniforms.blockSize + offset_w) * ${this.getOutputDepthSize()}; let in_d = d + offset_d; let rlt = ${this.getInputSamplingString()}; setOutputAtIndex(index, rlt); } }`}getHeightCoordString(){return this.dataFormat==="NHWC"?"coords[1]":"coords[2]"}getWidthCoordString(){return this.dataFormat==="NHWC"?"coords[2]":"coords[3]"}getDepthCoordString(){return this.dataFormat==="NHWC"?"coords[3]":"coords[1]"}getOutputDepthSize(){return this.dataFormat==="NHWC"?"uniforms.outShape[3]":"uniforms.outShape[1]"}getInputSamplingString(){return this.dataFormat==="NHWC"?"getX(b, in_h, in_w, in_d)":"getX(b, in_d, in_h, in_w)"}};function qoe(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{blockSize:s,dataFormat:i}=n,o=r.shape[0],l=i==="NHWC"?r.shape[1]:r.shape[2],u=i==="NHWC"?r.shape[2]:r.shape[3],p=i==="NHWC"?r.shape[3]:r.shape[1],c=l*s,d=u*s,h=p/(s*s),f=i==="NHWC"?[o,c,d,h]:[o,h,c,d],m=[{type:"int32",data:[s]}],g=new joe(f,i);return a.runWebGPUProgram(g,[r],r.dtype,m)}var Xoe={kernelName:di,backendName:"webgpu",kernelFunc:qoe},Koe=class{constructor(e,t,a,n=!1,r=null,s=!1){this.variableNames=["x","W"],this.uniforms="pad : vec2, inDims : vec2,",this.workgroupSize=[16,16,1],this.outputShape=e,this.dispatchLayout={x:[3],y:[2],z:[0,1]},this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),n&&this.variableNames.push("bias"),s&&this.variableNames.push("preluActivationWeights"),this.addBias=n,this.activation=r,this.hasPreluActivation=s,this.filterHeight=t,this.filterWidth=a,this.shaderKey=`depthwiseNCHW_${this.activation}_${this.filterHeight}_${this.filterWidth}`}getUserCode(){let e=this.filterWidth*this.filterHeight,t=this.workgroupSize[0]*this.workgroupSize[1]*this.workgroupSize[2],a=this.workgroupSize[1]+this.filterHeight-1,n=this.workgroupSize[0]+this.filterWidth-1;return` ${Tr(this.activation,this.hasPreluActivation,!1,4)} var mm_Asub : array, ${a}>; var mm_Bsub : array, ${this.filterHeight}>; fn readX(batch : i32, channel : i32, row : i32, col : i32) -> f32 { var value = 0.0; if (row >=0 && row < uniforms.inDims[0] && col >=0 && col < uniforms.inDims[1]) { value = getX(batch, channel, row, col); } return value; } ${Ce()} { let coords = getOutputCoords(); let batch = coords[0]; let xRCCorner = vec2(coords.zw) - uniforms.pad; let channelMul = uniforms.wShape[3]; let d1 = coords[1] / channelMul; let q = coords[1] % channelMul; let inputRowStart = xRCCorner.x; let inputColStart = xRCCorner.y; let localRow = i32(localId.y); let localCol = i32(localId.x); // Load one tile of X into local memory. for (var inputRow = localRow; inputRow < ${a}; inputRow = inputRow + ${this.workgroupSize[1]}) { for (var inputCol = localCol; inputCol < ${n}; inputCol = inputCol + ${this.workgroupSize[0]}) { let rowOffset = inputRow - localRow; let colOffset = inputCol - localCol; mm_Asub[inputRow][inputCol] = readX(batch, d1, inputRowStart + rowOffset, inputColStart + colOffset); } } // Load one tile of W into local memory. var wIndex = i32(localIndex); ${e, inDims : vec2,",this.workgroupSize=[4,4,4],this.workPerThread=4,this.isVec4=!0,this.outputShape=e.outShape,this.dispatchLayout={x:[3],y:[2],z:[0,1]},this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize,[4,this.workPerThread,1]),v.assert(e.dataFormat==="channelsLast",()=>"TODO: NCHW is unimplemented"),t&&this.variableNames.push("bias"),n&&this.variableNames.push("preluActivationWeights"),this.convInfo=e,this.addBias=t,this.activation=a,this.hasPreluActivation=n,this.shaderKey=`depthwiseVec4_${a}_${this.convInfo.filterHeight}_${this.convInfo.filterWidth}_${this.convInfo.strideHeight}_${this.convInfo.strideWidth}_${this.workPerThread}`}getUserCode(){let e=(this.workPerThread-1)*this.convInfo.strideWidth+this.convInfo.filterWidth;return` ${Tr(this.activation,this.hasPreluActivation,!0,4)} fn readX(batch : i32, row : i32, col : i32, channel : i32) -> vec4 { var value = vec4(0.0); if (col >=0 && col < uniforms.inDims[1]) { value = getX(batch, row, col, channel); } return value; } const strideHeight = ${this.convInfo.strideHeight}; const strideWidth = ${this.convInfo.strideWidth}; ${Ce()} { let batch = i32(globalId.z) / uniforms.outShape[1]; let r = i32(globalId.z) % uniforms.outShape[1]; let c = i32(globalId.y) * ${this.workPerThread}; let d1 = i32(globalId.x) * 4; let xRCCorner = vec2(r, c) * vec2(strideHeight, strideWidth) - uniforms.pad; let xRCorner = xRCCorner.x; let xCCorner = xRCCorner.y; var xVals : array, ${e}>; var dotProd : array, ${this.workPerThread}>; for (var i = 0; i < ${this.workPerThread}; i++) { dotProd[i] = vec4(0.0); } // Use constant instead of uniform can give better performance. for (var wR = 0; wR < ${this.convInfo.filterHeight}; wR = wR + 1) { let xR = xRCorner + wR; if (xR >=0 && xR < uniforms.inDims[0]) { for (var i = 0; i < ${e}; i++) { xVals[i] = readX(batch, xR, xCCorner + i, d1); } for (var wC = 0; wC < ${this.convInfo.filterWidth}; wC = wC + 1) { let wValue = getW(wR, wC, d1, 0); for (var i = 0; i < ${this.workPerThread}; i++) { dotProd[i] = fma(xVals[i * strideWidth + wC], wValue, dotProd[i]); } } } } for (var i = 0; i < ${this.workPerThread}; i = i + 1) { let coords = vec4(batch, r, c + i, d1); if (coordsInBounds4D(coords, uniforms.outShape)) { var value = dotProd[i]; ${vo(this.addBias,this.activation)} setOutputAtCoords(coords[0], coords[1], coords[2], coords[3], value); } } } `}},U8=class{constructor(e,t=!1,a=null,n=!1){this.variableNames=["x","W"],this.uniforms=`pad : vec2, inDims : vec2, filterHeight : i32, filterWidth : i32, stride : vec2, dilation : vec2,`,this.workgroupSize=[256,1,1],this.size=!0,this.outputShape=e.outShape,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.isChannelsLast=e.dataFormat==="channelsLast",t&&this.variableNames.push("bias"),n&&this.variableNames.push("preluActivationWeights"),this.convInfo=e,this.addBias=t,this.activation=a,this.hasPreluActivation=n,this.shaderKey=`depthwise_${this.activation}_${this.isChannelsLast}`}getUserCode(){let e=this.isChannelsLast?"getX(batch, xR, xC, d1);":"getX(batch, d1, xR, xC);";return` ${Tr(this.activation,this.hasPreluActivation,!1,4)} ${Ce("index")} { if (index < uniforms.size) { let coords = getOutputCoords(); let batch = coords[0]; let xRCCorner = vec2(coords.${this.isChannelsLast?"yz":"zw"}) * uniforms.stride - uniforms.pad; let d2 = coords[${this.isChannelsLast?3:1}]; let channelMul = uniforms.wShape[3]; let d1 = d2 / channelMul; let q = d2 % channelMul; let inputRowStart = xRCCorner.x; let inputColStart = xRCCorner.y; let inputRowEnd = inputRowStart + uniforms.filterHeight * uniforms.dilation[0]; let inputColEnd = inputColStart + uniforms.filterWidth * uniforms.dilation[1]; // Convolve x(?, ?, d1)|x(d1, ?, ?) with w(:, :, d1, q) to get // y(yR, yC, d2)|y(d2, yR, yC). ? = to be determined. : = across all // values in that axis. x(?, ?, d1) and y(yR, yC, d2) is for NHWC. // x(d1, ?, ?) and y(d2, yR, yC) is for NCHW. var value = 0.0; // Extract if checking out of for loop for performance. if (inputRowStart >= 0 && inputColStart >= 0 && inputRowEnd < uniforms.inDims[0] && inputColEnd < uniforms.inDims[1]) { for (var wR = 0; wR < uniforms.filterHeight; wR = wR + 1) { let xR = inputRowStart + wR * uniforms.dilation[0]; for (var wC = 0; wC < uniforms.filterWidth; wC = wC + 1) { let xC = inputColStart + wC * uniforms.dilation[1]; let xVal = ${e}; let wVal = getW(wR, wC, d1, q); value = value + xVal * wVal; } } } else { for (var wR = 0; wR < uniforms.filterHeight; wR = wR + 1) { let xR = inputRowStart + wR * uniforms.dilation[0]; if (xR < 0 || xR >= uniforms.inDims[0]) { continue; } for (var wC = 0; wC < uniforms.filterWidth; wC = wC + 1) { let xC = inputColStart + wC * uniforms.dilation[1]; if (xC < 0 || xC >= uniforms.inDims[1]) { continue; } let xVal = ${e}; let wVal = getW(wR, wC, d1, q); value = value + xVal * wVal; } } } ${vo(this.addBias,this.activation)} setOutputAtCoords(coords[0], coords[1], coords[2], coords[3], value); } } `}};function Zoe(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,filter:s}=t,{strides:i,pad:o,dataFormat:l,dilations:u,dimRoundingMode:p}=n,c=T.convertConv2DDataFormat(l),d=u;d==null&&(d=[1,1]);let h=T.computeConv2DInfo(r.shape,s.shape,i,d,o,p,!0,c),f=[{type:"int32",data:[h.padInfo.top,h.padInfo.left]},{type:"int32",data:[h.inHeight,h.inWidth]}],m=h.dataFormat==="channelsLast",g;return!m&&h.inHeight>16&&h.inWidth>16&&h.strideHeight===1&&h.strideWidth===1&&h.dilationWidth===1&&h.dilationHeight===1&&h.inChannels===h.outChannels?g=new Koe(h.outShape,h.filterHeight,h.filterWidth):m&&h.outHeight>4&&h.outWidth>4&&h.strideWidth<=2&&h.inChannels===h.outChannels&&h.dilationHeight===1&&h.dilationWidth===1&&h.inChannels%4===0?g=new V8(h):(g=new U8(h),f.push({type:"int32",data:[h.filterHeight]},{type:"int32",data:[h.filterWidth]},{type:"int32",data:[h.strideHeight,h.strideWidth]},{type:"int32",data:[h.dilationHeight,h.dilationWidth]})),a.runWebGPUProgram(g,[r,s],r.dtype,f)}var Yoe={kernelName:pi,backendName:"webgpu",kernelFunc:Zoe},G8=ua({opType:De.MUL,cpuKernelImpl:Kse,supportsComplex:!0}),Joe={kernelName:zi,backendName:"webgpu",kernelFunc:G8};function V3(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,keepDims:i}=n;return ko(r,s,i,"sum",a)}var Qoe={kernelName:ro,backendName:"webgpu",kernelFunc:V3};function ele(e){let{inputs:t,backend:a,attrs:n}=e,{equation:r}=n,s=t,{allDims:i,summedDims:o,idDims:l}=T.decodeEinsumEquation(r,s.length);T.checkEinsumDimSizes(i.length,l,s);let{path:u,steps:p}=T.getEinsumComputePath(o,l),c=p.length,d=null,h=i.length,f=[];for(let m=0;m=0&&(d=V3({inputs:{x:d},backend:a,attrs:{axis:u[m]-(i.length-h),keepDims:!1}}),f.push(d)),h--)}for(let m of f)m!==d&&a.disposeData(m.dataId);return d}var tle={kernelName:Cd,backendName:"webgpu",kernelFunc:ele},ale=it({opType:de.ELU}),nle={kernelName:hi,backendName:"webgpu",kernelFunc:ale},rle=ua({opType:De.EQUAL,dtype:"bool",cpuKernelImpl:Fse}),sle={kernelName:fi,backendName:"webgpu",kernelFunc:rle},ile=it({opType:de.ERF}),ole={kernelName:$l,backendName:"webgpu",kernelFunc:ile},H8=it({opType:de.EXP,cpuKernelImpl:Ose,dtype:"float32"}),lle={kernelName:mi,backendName:"webgpu",kernelFunc:H8};function D1(e){let{inputs:t,attrs:a,backend:n}=e,{dim:r}=a,{input:s}=t,i=s.shape.length,o=s.shape.slice(),l=r;return r<0&&(v.assert(-(i+1)<=r,()=>`Axis must be in the interval [${-(i+1)}, ${i}]`),l=i+r+1),o.splice(l,0,1),Ie({inputs:{x:s},backend:n,attrs:{shape:o}})}var ule={kernelName:_l,backendName:"webgpu",kernelFunc:D1},dle=it({opType:de.EXPM1,cpuKernelImpl:Dse}),ple={kernelName:Pl,backendName:"webgpu",kernelFunc:dle},Qx=class{constructor(e,t){this.variableNames=["real","imag"],this.outputShape=[],this.uniforms="exponentMultiplier : f32, denominator: f32,",this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=t,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.component=e,this.shaderKey=`fft_${e}`}getUserCode(){return` fn unaryOpComplex(real: f32, expR: f32, imag: f32, expI: f32) -> f32 { ${this.component==="real"?"return real * expR - imag * expI;":"return real * expI + imag * expR;"} } fn mulMatDFT(batch: i32, index: i32) -> f32 { let indexRatio = f32(index) / f32(uniforms.realShape[1]); let exponentMultiplierTimesIndexRatio = uniforms.exponentMultiplier * indexRatio; var result = 0.0; for (var i = 0; i < uniforms.realShape[1]; i = i + 1) { // x = (-2|2 * PI / N) * index * i; let x = exponentMultiplierTimesIndexRatio * f32(i); let expR = cos(x); let expI = sin(x); let real = getReal(batch, i); let imag = getImag(batch, i); result = result + unaryOpComplex(real, expR, imag, expI) / uniforms.denominator; } return result; } ${Ce("index")} { if (index < uniforms.size) { let coords = getOutputCoords(); setOutputAtIndex(index, mulMatDFT(coords[0], coords[1])); } } `}};function j8(e,t,a){let n=a.tensorMap.get(e.dataId),r=v.sizeFromShape(e.shape),s=e.shape[e.shape.length-1],i=r/s,o=[],l=Ie({inputs:{x:e},backend:a,attrs:{shape:[i,s]}});o.push(l);let u=l.shape,p=new Qx("real",u),c=new Qx("imag",u),d=[{dataId:n.complexTensorInfos.real.dataId,dtype:n.complexTensorInfos.real.dtype,shape:u},{dataId:n.complexTensorInfos.imag.dataId,dtype:n.complexTensorInfos.imag.dtype,shape:u}],h=t?2*Math.PI:-2*Math.PI,f=t?u[1]:1,m=[{type:"float32",data:[h]},{type:"float32",data:[f]}],g=a.runWebGPUProgram(p,d,"float32",m);o.push(g);let x=a.runWebGPUProgram(c,d,"float32",m);o.push(x);let A=wo({inputs:{real:g,imag:x},backend:a});o.push(A);let y=Ie({inputs:{x:A},backend:a,attrs:{shape:e.shape}});return o.forEach(b=>a.disposeData(b.dataId)),y}function cle(e){let{inputs:t,backend:a}=e,{input:n}=t;return j8(n,!1,a)}var hle={kernelName:Nd,backendName:"webgpu",kernelFunc:cle},fle=class{constructor(e){this.outputShape=[],this.variableNames=["x"],this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.shaderKey="flipLeftRight"}getUserCode(){return` ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); let coordX = uniforms.xShape[2] - coords[2] - 1; let outputValue = getX(coords[0], coords[1], coordX, coords[3]); setOutputAtIndex(index, outputValue); } } `}},mle={kernelName:gi,backendName:"webgpu",kernelFunc:({inputs:e,backend:t})=>{let{image:a}=e,n=t,r=new fle(a.shape);return n.runWebGPUProgram(r,[a],a.dtype)}},gle=it({opType:de.FLOOR,cpuKernelImpl:zse}),xle={kernelName:xi,backendName:"webgpu",kernelFunc:gle},Ale=ua({opType:De.INT_DIV,dtype:"int32"}),yle={kernelName:Ai,backendName:"webgpu",kernelFunc:Ale},ble=class{constructor(e,t,a=!1){this.isFromPixels=!0,this.outputShape=[0],this.variableNames=[],this.workgroupSize=[256,1,1],this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize,[t,1,1]),this.importVideo=a,this.shaderKey=`fromPixels_${this.importVideo}`}getUserCode(){let e=this.importVideo?"textureLoad(src, vec2(coords.yx));":"textureLoad(src, vec2(coords.yx), 0)";return` @binding(1) @group(0) var src: ${this.importVideo?"texture_external":"texture_2d"}; ${Ce("index")} { let flatIndex = index * uniforms.numChannels; if (flatIndex < uniforms.size) { let coords = getCoordsFromIndex(flatIndex); let values = ${e}; for (var i = 0; i < uniforms.numChannels; i = i + 1) { result[flatIndex + i] = i32(floor(255.0 * values[i])); } } } `}},vle={kernelName:rd,backendName:"webgpu",kernelFunc:wle},Yo,Wm=W().getBool("CANVAS2D_WILL_READ_FREQUENTLY_FOR_GPU"),cc=new Map;function wle(e){let{inputs:t,backend:a,attrs:n}=e,{pixels:r}=t,{numChannels:s}=n;if(r==null)throw new Error("pixels passed to tf.browser.fromPixels() can not be null");let i=typeof HTMLVideoElement!="undefined"&&r instanceof HTMLVideoElement,o=typeof HTMLImageElement!="undefined"&&r instanceof HTMLImageElement,l=typeof HTMLCanvasElement!="undefined"&&r instanceof HTMLCanvasElement||typeof OffscreenCanvas!="undefined"&&r instanceof OffscreenCanvas,u=typeof ImageBitmap!="undefined"&&r instanceof ImageBitmap,[p,c]=i?[r.videoWidth,r.videoHeight]:[r.width,r.height],d=[c,p,s],h=!1,f=i||o;if(u||l||f){let A;if(h){let $=r;if(!cc.has($)||cc.get($).expired){let M={source:$};cc.set($,a.device.importExternalTexture(M))}A={width:p,height:c,format:null,usage:null,texture:cc.get($)}}else{if(f){let N=W().getBool("CANVAS2D_WILL_READ_FREQUENTLY_FOR_GPU");(Yo==null||N!==Wm)&&(Wm=N,Yo=document.createElement("canvas").getContext("2d",{willReadFrequently:Wm})),Yo.canvas.width=p,Yo.canvas.height=c,Yo.drawImage(r,0,0,p,c),r=Yo.canvas}let $=GPUTextureUsage.COPY_DST|GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING,M="rgba8unorm",I=a.textureManager.acquireTexture(d[1],d[0],M,$);a.queue.copyExternalImageToTexture({source:r},{texture:I},[d[1],d[0]]),A={width:p,height:c,format:M,usage:$,texture:I}}let y=v.sizeFromShape(d),b=v.computeStrides(d),w=new ble(d,s,h),S=[{type:"uint32",data:[y]},{type:"uint32",data:[s]},{type:"uint32",data:[...b]}],C=a.makeTensorInfo([c,p],"int32"),E=a.tensorMap.get(C.dataId);E.resourceInfo=A;let _=a.runWebGPUProgram(w,[C],"int32",S);return a.disposeData(C.dataId),_}let m=r.data,g=m;if(s!=null&&s!==4){g=new Uint8Array(r.width*r.height*s);let A=m.length,y=0;for(let b=0;b(xValue, -meanValue, offsetValue), vec3(inv, inv, 1.0))); } } `}},Ile={kernelName:yi,backendName:"webgpu",kernelFunc:({inputs:e,attrs:t,backend:a})=>{let{x:n,scale:r,offset:s,mean:i,variance:o}=e,{varianceEpsilon:l}=t,u=a,p=[n,i,o],c=null;s!=null&&(c=s.shape,p.push(s));let d=null;r!=null&&(d=r.shape,p.push(r));let h=new kle(n.shape,i.shape,o.shape,c,d),f=[{type:"float32",data:[l]}];return u.runWebGPUProgram(h,p,n.dtype,f)}};function Sle(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,filter:s,bias:i,preluActivationWeights:o}=t,{strides:l,pad:u,dataFormat:p,dilations:c,dimRoundingMode:d,activation:h,leakyreluAlpha:f}=n,m=T.convertConv2DDataFormat(p),g=T.computeConv2DInfo(r.shape,s.shape,l,c,u,d,!1,m);return B8({x:r,filter:s,convInfo:g,backend:a,bias:i,preluActivationWeights:o,leakyreluAlpha:f,activation:h})}var Tle={kernelName:qr,backendName:"webgpu",kernelFunc:Sle};function Cle(e){let{inputs:t,backend:a,attrs:n}=e,{x:r,filter:s,bias:i,preluActivationWeights:o}=t,{strides:l,pad:u,dilations:p,dimRoundingMode:c,activation:d,leakyreluAlpha:h}=n,f=p;f==null&&(f=[1,1]),v.assert(T.eitherStridesOrDilationsAreOne(l,f),()=>`Error in depthwiseConv2d: Either strides or dilations must be 1. Got strides ${l} and dilations '${f}'`);let m=T.computeConv2DInfo(r.shape,s.shape,l,f,u,c,!0),g=[r,s],x=i!=null,A=o!=null;x&&g.push(i),A&&g.push(o);let y=[{type:"int32",data:[m.padInfo.top,m.padInfo.left]},{type:"int32",data:[m.inHeight,m.inWidth]}],b;return m.outHeight>4&&m.outWidth>4&&m.strideWidth<=2&&m.inChannels===m.outChannels&&m.dilationHeight===1&&m.dilationWidth===1&&m.inChannels%4===0?b=new V8(m,x,d,A):(b=new U8(m,x,d,A),y.push({type:"int32",data:[m.filterHeight]},{type:"int32",data:[m.filterWidth]},{type:"int32",data:[m.strideHeight,m.strideWidth]},{type:"int32",data:[m.dilationHeight,m.dilationWidth]})),d==="leakyrelu"&&(y.push({type:"float32",data:[h]}),b.uniforms+=" alpha : f32,"),a.runWebGPUProgram(b,g,"float32",y)}var Nle={kernelName:Xr,backendName:"webgpu",kernelFunc:Cle},Ele=class{constructor(e,t){this.variableNames=["A","indices"],this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=t,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.shaderKey=`gathernd_${e}`,this.sliceDim=e,this.uniforms=`sliceDim : i32, strides : ${ra(e)},`}getUserCode(){let e;return this.sliceDim>1?e="uniforms.strides[j]":e="uniforms.strides",` ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); var flattenIndex = 0; for (var j = 0; j < uniforms.sliceDim; j = j + 1) { let indexTemp = i32(round(getIndices(coords[0], j))); let strideNum = ${e}; flattenIndex = flattenIndex + indexTemp * strideNum; } setOutputAtIndex(index, getA(flattenIndex, coords[1])); } } `}};function Rle(e){let{inputs:t,backend:a}=e,{params:n,indices:r}=t,s=r.shape,i=s[s.length-1],o=v.sizeFromShape(n.shape),[l,u,p,c]=T.prepareAndValidate(n,r),d=Ie({inputs:{x:r},backend:a,attrs:{shape:[u,i]}}),h=Ie({inputs:{x:n},backend:a,attrs:{shape:[v.sizeFromShape(n.shape)/p,p]}});if(a.shouldExecuteOnCPU([n,r])||n.dtype==="string"){let A=a.readSync(r.dataId),y=a.bufferSync(n),b=Lse(A,y,n.dtype,u,i,p,c,n.shape,o);return a.makeTensorInfo(l,n.dtype,b.values)}let f=new Ele(i,[u,p]),m=[{type:"int32",data:[i]},{type:"int32",data:c}],g=a.runWebGPUProgram(f,[h,d],h.dtype,m),x=Ie({inputs:{x:g},backend:a,attrs:{shape:l}});return a.disposeData(d.dataId),a.disposeData(h.dataId),a.disposeData(g.dataId),x}var Mle={kernelName:bi,backendName:"webgpu",kernelFunc:Rle},$le=class{constructor(e,t){this.variableNames=["A","indices"],this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e.slice(),this.aShape=e,this.outputShape=t,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.shaderKey="gather"}getUserCode(){let e=_le(this.aShape);return` ${Ce("index")} { if (index < uniforms.size) { let resRC = getCoordsFromIndex(index); let indexZ = i32(getIndices(resRC.x, resRC.z)); let inBounds = select(0.0, 1.0, indexZ >= 0 && indexZ < uniforms.aShape[2]); setOutputAtIndex(index, inBounds * getA(${e})); } } `}};function _le(e){let t=["resRC.x","resRC.y","resRC.z","resRC.w"],a=[];for(let n=0;na.disposeData(C.dataId)),a.makeTensorInfo(u.outputShape,S.dtype,S.values)}let m=new $le(d.shape,f),g=a.runWebGPUProgram(m,[d,h],d.dtype);c.push(g);let x=Ie({inputs:{x:g},backend:a,attrs:{shape:u.outputShape}});return c.forEach(A=>a.disposeData(A.dataId)),x}var Ple={kernelName:Ol,backendName:"webgpu",kernelFunc:q8},Fle=ua({opType:De.GREATER,cpuKernelImpl:Vse,dtype:"bool"}),Ole={kernelName:vi,backendName:"webgpu",kernelFunc:Fle},Dle=ua({opType:De.GREATER_EQUAL,dtype:"bool",cpuKernelImpl:Wse}),zle={kernelName:wi,backendName:"webgpu",kernelFunc:Dle};function Lle(e){let{inputs:t,backend:a}=e,{input:n}=t;return j8(n,!0,a)}var Ble={kernelName:Ed,backendName:"webgpu",kernelFunc:Lle},Wle=it({opType:de.IS_FINITE,dtype:"bool"}),Vle={kernelName:Dl,backendName:"webgpu",kernelFunc:Wle},Ule=it({opType:de.IS_INF,dtype:"bool"}),Gle={kernelName:zl,backendName:"webgpu",kernelFunc:Ule},Hle=it({opType:de.IS_NAN,dtype:"bool"}),jle={kernelName:Ii,backendName:"webgpu",kernelFunc:Hle};function qle(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{alpha:s}=n,i=[{type:"float32",data:[s]}],o=new mp(r.shape,de.LEAKYRELU);return o.uniforms="alpha : f32,",a.runWebGPUProgram(o,[r],"float32",i)}var Xle={kernelName:Si,backendName:"webgpu",kernelFunc:qle},Kle=ua({opType:De.LESS,dtype:"bool",cpuKernelImpl:Gse}),Zle={kernelName:Ti,backendName:"webgpu",kernelFunc:Kle},Yle=ua({opType:De.LESS_EQUAL,dtype:"bool",cpuKernelImpl:Use}),Jle={kernelName:Ci,backendName:"webgpu",kernelFunc:Yle},Qle=it({opType:de.LOG,cpuKernelImpl:Hse}),eue={kernelName:Ni,backendName:"webgpu",kernelFunc:Qle},tue=it({opType:de.LOG1P}),aue={kernelName:Ll,backendName:"webgpu",kernelFunc:tue},nue=ua({opType:De.LOGICAL_AND,dtype:"bool"}),rue={kernelName:Ei,backendName:"webgpu",kernelFunc:nue},sue=it({opType:de.LOGICAL_NOT}),iue={kernelName:Ri,backendName:"webgpu",kernelFunc:sue},oue=ua({opType:De.MAX,cpuKernelImpl:qse}),lue={kernelName:$i,backendName:"webgpu",kernelFunc:oue};function uue(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{filterSize:s,strides:i,pad:o,dimRoundingMode:l}=n,u=1,p=T.computePool2DInfo(r.shape,s,i,u,o,l);return O8(r,p,"max",a)}var due={kernelName:_i,backendName:"webgpu",kernelFunc:uue};function pue(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,keepDims:i}=n;return ko(r,s,i,"min",a)}var cue={kernelName:Fi,backendName:"webgpu",kernelFunc:pue},hue=ua({opType:De.MIN,cpuKernelImpl:Xse}),fue={kernelName:Oi,backendName:"webgpu",kernelFunc:hue},mue=class{constructor(e,t,a){this.uniforms="",this.variableNames=["x"],this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=t.map((n,r)=>n[0]+e[r]+n[1]),this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.xShape=e,t.map((n,r)=>{this.uniforms+=` pad${r} : vec2,`}),this.offset=a==="reflect"?0:1,this.shaderKey=`mirrorPad_${a}`}getUserCode(){let e=this.xShape.length,t=this.xShape.map((l,u)=>`uniforms.pad${u}[0]`).join(","),a=this.xShape.map((l,u)=>`uniforms.pad${u}[0] + uniforms.xShape${e>1?`[${u}]`:""}`).join(","),n=e===1?"start":"start[i]",r=e===1?"end":"end[i]",s=e===1?"outC":"outC[i]",i=ra(e),o=e>1?["coords[0]","coords[1]","coords[2]","coords[3]"].slice(0,e):"coords";return` ${Ce("index")} { if (index < uniforms.size) { let start = ${i}(${t}); let end = ${i}(${a}); var outC = getCoordsFromIndex(index); for (var i = 0; i < ${e}; i = i + 1) { if (${s} < ${n}) { ${s} = ${n} * 2 - ${s} - ${this.offset}; } else if(${s} >= ${r}) { ${s} = (${r} - 1) * 2 - ${s} + ${this.offset}; } } let coords = outC - start; setOutputAtIndex(index, getX(${o})); } } `}},gue={kernelName:Di,backendName:"webgpu",kernelFunc:({inputs:e,attrs:t,backend:a})=>{let{x:n}=e,{paddings:r,mode:s}=t,i=a,o=r.map(u=>({type:"int32",data:[u[0],u[1]]})),l=new mue(n.shape,r,s);return i.runWebGPUProgram(l,[n],n.dtype,o)}},xue=ua({opType:De.MOD}),Aue={kernelName:Wl,backendName:"webgpu",kernelFunc:xue};function yue(e){let{inputs:t,backend:a}=e,{x:n}=t;if(a.shouldExecuteOnCPU([n])){let s=a.tensorMap.get(n.dataId),[i,o]=Zse(s.values,n.shape,n.dtype);return a.makeTensorInfo(o,n.dtype,i)}let r=new mp(n.shape,de.NEG);return a.runWebGPUProgram(r,[n],n.dtype)}var bue={kernelName:Vl,backendName:"webgpu",kernelFunc:yue};function vue(e){console.warn("tf.nonMaxSuppression() in webgpu locks the UI thread. Call tf.nonMaxSuppressionAsync() instead");let{inputs:t,backend:a,attrs:n}=e,{boxes:r,scores:s}=t,{maxOutputSize:i,iouThreshold:o,scoreThreshold:l}=n,u=a.readSync(r.dataId),p=a.readSync(s.dataId),{selectedIndices:c}=Tn.nonMaxSuppressionV3Impl(u,p,i,o,l);return a.makeTensorInfo([c.length],"int32",new Int32Array(c))}var wue={kernelName:Bi,backendName:"webgpu",kernelFunc:vue};function kue(e){console.warn("tf.nonMaxSuppression() in webgpu locks the UI thread. Call tf.nonMaxSuppressionAsync() instead");let{inputs:t,backend:a,attrs:n}=e,{boxes:r,scores:s}=t,{maxOutputSize:i,iouThreshold:o,scoreThreshold:l,softNmsSigma:u}=n,p=a.readSync(r.dataId),c=a.readSync(s.dataId),d=i,h=o,f=l,m=u,{selectedIndices:g,selectedScores:x}=Tn.nonMaxSuppressionV5Impl(p,c,d,h,f,m);return[a.makeTensorInfo([g.length],"int32",new Int32Array(g)),a.makeTensorInfo([x.length],"float32",new Float32Array(x))]}var Iue={kernelName:Wi,backendName:"webgpu",kernelFunc:kue},Sue=class{constructor(e,t){this.variableNames=["x"],this.uniforms="onValue : f32, offValue : f32,",this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=[e,t],this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.shaderKey="onehot"}getUserCode(){return` ${Ce("index")} { if(index < uniforms.size) { let coords = getCoordsFromIndex(index); setOutputAtIndex(index, mix(uniforms.offValue, uniforms.onValue, f32(i32(round(getX(coords.x))) == coords.y))); } } `}};function Tue(e){let{inputs:t,backend:a,attrs:n}=e,{indices:r}=t,{dtype:s,depth:i,onValue:o,offValue:l}=n,u=v.sizeFromShape(r.shape),p=new Sue(u,i),c=Ie({inputs:{x:r},backend:a,attrs:{shape:[u]}}),d=[{type:"float32",data:[o]},{type:"float32",data:[l]}],h=a.runWebGPUProgram(p,[c],s,d);a.disposeData(c.dataId);let f=[...r.shape,i],m=Ie({inputs:{x:h},backend:a,attrs:{shape:f}});return a.disposeData(h.dataId),m}var Cue={kernelName:Vi,backendName:"webgpu",kernelFunc:Tue};function Vc(e){let{inputs:t,backend:a}=e,{x:n}=t;if(n.dtype==="complex64"){let r=gp({inputs:{input:n},backend:a}),s=Vc({inputs:{x:r},backend:a}),i=jh({inputs:{input:n},backend:a}),o=Vc({inputs:{x:i},backend:a}),l=wo({inputs:{real:s,imag:o},backend:a});return a.disposeData(r.dataId),a.disposeData(s.dataId),a.disposeData(i.dataId),a.disposeData(o.dataId),l}else return Cr({attrs:{shape:n.shape,dtype:n.dtype,value:n.dtype==="string"?"":0},backend:a})}var Nue={kernelName:nu,backendName:"webgpu",kernelFunc:Vc};function X8(e){let{inputs:t,backend:a}=e,{x:n}=t;if(n.dtype==="string")throw new Error("onesLike is not supported under string dtype");if(n.dtype==="complex64"){let r=gp({inputs:{input:n},backend:a}),s=X8({inputs:{x:r},backend:a}),i=jh({inputs:{input:n},backend:a}),o=Vc({inputs:{x:i},backend:a}),l=wo({inputs:{real:s,imag:o},backend:a});return a.disposeData(r.dataId),a.disposeData(s.dataId),a.disposeData(i.dataId),a.disposeData(o.dataId),l}else return Cr({attrs:{shape:n.shape,dtype:n.dtype,value:1},backend:a})}var Eue={kernelName:Gl,backendName:"webgpu",kernelFunc:X8};function Rue(e){let{inputs:t,backend:a,attrs:n}=e,{axis:r}=n;if(t.length===1)return D1({inputs:{input:t[0]},backend:a,attrs:{dim:r}});let s=t[0].shape,i=t[0].dtype;t.forEach(p=>{v.assertShapesMatch(s,p.shape,"All tensors passed to stack must have matching shapes"),v.assert(i===p.dtype,()=>"All tensors passed to stack must have matching dtypes")});let o=[],l=t.map(p=>{let c=D1({inputs:{input:p},backend:a,attrs:{dim:r}});return o.push(c),c}),u=L8({inputs:l,backend:a,attrs:{axis:r}});return o.forEach(p=>a.disposeData(p.dataId)),u}var Mue={kernelName:Hl,backendName:"webgpu",kernelFunc:Rue},$ue=class{constructor(e,t){this.variableNames=["x"],this.uniforms="constantValue : f32,",this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=t.map((a,n)=>a[0]+e[n]+a[1]),this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),t.map((a,n)=>{this.uniforms+=` pad${n} : vec2,`}),this.xShape=e,this.shaderKey="pad"}getUserCode(){let e=this.xShape.length,t=ra(e),a=this.xShape.map((u,p)=>`uniforms.pad${p}[0]`).join(","),n=this.xShape.map((u,p)=>`uniforms.pad${p}[0] + uniforms.xShape${e>1?`[${p}]`:""}`).join(","),r=e>1?`${t}(${a})`:`${a}`,s=e>1?`${t}(${n})`:`${n}`,i=e>1?"any(outC < start)":"outC < start",o=e>1?"any(outC >= end)":"outC >= end",l=e>1?["coords[0]","coords[1]","coords[2]","coords[3]"].slice(0,e):"coords";return` ${Ce("index")} { if (index < uniforms.size) { let start = ${r}; let end = ${s}; let outC = getCoordsFromIndex(index); if (${i} || ${o}) { setOutputAtIndex(index, uniforms.constantValue); } else { let coords = outC - start; setOutputAtIndex(index, getX(${l})); } } } `}},K8=e=>{let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{paddings:s,constantValue:i}=n;if(s.every(u=>v.arraysEqual(u,[0,0])))return Ya({inputs:{x:r},backend:a});if(v.sizeFromShape(r.shape)===0){let u=s.map((p,c)=>p[0]+r.shape[c]+p[1]);return Cr({backend:a,attrs:{shape:u,value:i,dtype:r.dtype}})}let o=[{type:"float32",data:[i]}];s.map(u=>o.push({type:"int32",data:[u[0],u[1]]}));let l=new $ue(r.shape,s);return a.runWebGPUProgram(l,[r],r.dtype,o)},_ue={kernelName:Ui,backendName:"webgpu",kernelFunc:K8},Pue=ua({opType:De.POW}),Fue={kernelName:Gi,backendName:"webgpu",kernelFunc:Pue};function Oue(e){let{inputs:t,backend:a}=e,{x:n,alpha:r}=t,s=new P1(De.PRELU,n.shape,r.shape);return a.runWebGPUProgram(s,[n,r],"float32")}var Due={kernelName:Hi,backendName:"webgpu",kernelFunc:Oue};function zue(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{axis:s,keepDims:i}=n;return ko(r,s,i,"prod",a)}var Lue={kernelName:ji,backendName:"webgpu",kernelFunc:zue},Bue=e=>{let{backend:t,attrs:a}=e,{start:n,stop:r,step:s,dtype:i}=a,o=Qse(n,r,s,i);return t.makeTensorInfo([o.length],i,o)},Wue={kernelName:jl,backendName:"webgpu",kernelFunc:Bue},Z8=ua({opType:De.DIV}),Vue={kernelName:ci,backendName:"webgpu",kernelFunc:Z8},Uue=it({opType:de.RECIPROCAL}),Gue={kernelName:qi,backendName:"webgpu",kernelFunc:Uue},Hue=it({opType:de.RELU}),jue={kernelName:Xi,backendName:"webgpu",kernelFunc:Hue},que=it({opType:de.RELU6}),Xue={kernelName:Yi,backendName:"webgpu",kernelFunc:que},Kue=class{constructor(e,t,a){this.variableNames=["x"],this.uniforms="adjustHeightWidth : vec2, halfPixelCenters : f32,",this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=[e[0],t,a,e[3]],this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.shaderKey="resizeBilinear"}getUserCode(){return` ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); let b = coords[0]; let d = coords[3]; let rc = coords.yz; let effectiveInSize = vec2( f32(uniforms.xShape.y) - uniforms.adjustHeightWidth[0], f32(uniforms.xShape.z) - uniforms.adjustHeightWidth[1]); let effectiveOutSize = vec2( f32(uniforms.outShape.y) - uniforms.adjustHeightWidth[0], f32(uniforms.outShape.z) - uniforms.adjustHeightWidth[1]); let effectiveInputOverOutputRatioRC = effectiveInSize / effectiveOutSize; // Fractional source index let sourceFracIndexRC = (vec2(rc) + vec2(uniforms.halfPixelCenters)) * effectiveInputOverOutputRatioRC - vec2(uniforms.halfPixelCenters); // Compute the four integer indices. let sourceFloorRC = vec2(sourceFracIndexRC); let sourceCeilRC = vec2( min(vec2(uniforms.xShape.yz) - vec2(1.0), ceil(sourceFracIndexRC))); let topLeft = getX(b, sourceFloorRC.x, sourceFloorRC.y, d); let bottomLeft = getX(b, sourceCeilRC.x, sourceFloorRC.y, d); let topRight = getX(b, sourceFloorRC.x, sourceCeilRC.y, d); let bottomRight = getX(b, sourceCeilRC.x, sourceCeilRC.y, d); let fracRC = sourceFracIndexRC - vec2(sourceFloorRC); let top = topLeft + (topRight - topLeft) * fracRC.y; let bottom = bottomLeft + (bottomRight - bottomLeft) * fracRC.y; let newValue = top + (bottom - top) * fracRC.x; setOutputAtIndex(index, newValue); } } `}};function Zue(e){let{inputs:t,backend:a,attrs:n}=e,{images:r}=t,{alignCorners:s,size:i,halfPixelCenters:o}=n,[l,u]=i,p=s&&l>1?1:0,c=s&&u>1?1:0,d=[{type:"float32",data:[p,c]},{type:"float32",data:[o?.5:0]}],h=new Kue(r.shape,l,u);return a.runWebGPUProgram(h,[r],"float32",d)}var Yue={kernelName:Zi,backendName:"webgpu",kernelFunc:Zue},Jue=class{constructor(e,t,a,n){this.variableNames=["x"],this.uniforms="adjustHeightWidth : vec2, roundBase : f32,",this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=[e[0],t,a,e[3]],this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.halfPixelCenters=n,this.shaderKey=`resizeNearest_${n}`}getUserCode(){let e;return this.halfPixelCenters?e="max((vec2(rc) + vec2(0.5)) * effectiveInputOverOutputRatioRC, vec2(0.0))":e="vec2(rc) * effectiveInputOverOutputRatioRC",` ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); let b = coords[0]; let d = coords[3]; let rc = coords.yz; let effectiveInSize = vec2( f32(uniforms.xShape.y) - uniforms.adjustHeightWidth[0], f32(uniforms.xShape.z) - uniforms.adjustHeightWidth[1]); let effectiveOutSize = vec2( f32(uniforms.outShape.y) - uniforms.adjustHeightWidth[0], f32(uniforms.outShape.z) - uniforms.adjustHeightWidth[1]); let effectiveInputOverOutputRatioRC = effectiveInSize / effectiveOutSize; // Fractional source index let sourceFracIndexRC = ${e}; // Compute the coordinators of nearest neighbor point. let inputShapeRC = vec2(f32(uniforms.xShape.y), f32(uniforms.xShape.z)); let sourceNearestRC = vec2( min(inputShapeRC - 1.0, floor(sourceFracIndexRC + uniforms.roundBase))); let newValue = getX(b, sourceNearestRC.x, sourceNearestRC.y, d); setOutputAtIndex(index, newValue); } } `}};function Que(e){let{inputs:t,backend:a,attrs:n}=e,{images:r}=t,{alignCorners:s,halfPixelCenters:i,size:o}=n,[l,u]=o,p=s&&l>1?1:0,c=s&&u>1?1:0,d=[{type:"float32",data:[p,c]},{type:"float32",data:[s?.5:0]}],h=new Jue(r.shape,l,u,i);return a.runWebGPUProgram(h,[r],r.dtype,d)}var ede={kernelName:Ki,backendName:"webgpu",kernelFunc:Que},tde=class{constructor(e){this.variableNames=["x"],this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.uniforms=" axis : vec4,",this.shaderKey="reverse"}getUserCode(){return` // Using uniform variables as judging conditions, so the function has // coherent execution within all threads. fn getReverseCoords(coords : vec4) -> vec4 { var reverseCoords = coords; if (uniforms.axis[0] == 1) { reverseCoords[0] = uniforms.xShape[0] - coords[0] - 1; } if (uniforms.axis[1] == 1) { reverseCoords[1] = uniforms.xShape[1] - coords[1] - 1; } if (uniforms.axis[2] == 1) { reverseCoords[2] = uniforms.xShape[2] - coords[2] - 1; } if (uniforms.axis[3] == 1) { reverseCoords[3] = uniforms.xShape[3] - coords[3] - 1; } return reverseCoords; } ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); let reverseCoords = getReverseCoords(coords); setOutputAtIndex(index, getX(reverseCoords[0], reverseCoords[1], reverseCoords[2], reverseCoords[3])); } } `}};function ade(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{dims:s}=n,i=r.shape.length;if(i===0)return Ya({inputs:{x:r},backend:a});let o=r.shape,l=[1,1,1,1];o.forEach((g,x)=>{let A=x+4-i;l[A]=g});let u=v.parseAxisParam(s,r.shape),p=[0,0,0,0];u.forEach(g=>{let x=g+4-i;p[x]=1});let c=[{type:"int32",data:p}],d=Ie({inputs:{x:r},backend:a,attrs:{shape:l}}),h=new tde(l),f=a.runWebGPUProgram(h,[d],d.dtype,c);a.disposeData(d.dataId);let m=Ie({inputs:{x:f},backend:a,attrs:{shape:o}});return a.disposeData(f.dataId),m}var nde={kernelName:Ji,backendName:"webgpu",kernelFunc:ade},rde=class{constructor(e,t){this.outputShape=[],this.variableNames=["x"],this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.uniforms=`centerX : f32, centerY : f32, sinRadians : f32, cosRadians : f32,`,this.shaderKey="rotate",this.outputShape=e,typeof t=="number"?(this.uniforms+=" fillValue : f32,",this.fillSnippet="var outputValue = uniforms.fillValue;",this.shaderKey+="_float"):(this.uniforms+=" fillValue : vec3,",this.fillSnippet="var outputValue = uniforms.fillValue[coords[3]];",this.shaderKey+="_vec3")}getUserCode(){return` ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); let coordXFloat = (f32(coords[2]) - uniforms.centerX) * uniforms.cosRadians - (f32(coords[1]) - uniforms.centerY) * uniforms.sinRadians; let coordYFloat = (f32(coords[2]) - uniforms.centerX) * uniforms.sinRadians + (f32(coords[1]) - uniforms.centerY) * uniforms.cosRadians; let coordX = i32(round(coordXFloat + uniforms.centerX)); let coordY = i32(round(coordYFloat + uniforms.centerY)); ${this.fillSnippet} if(coordX >= 0 && coordX < uniforms.xShape[2] && coordY >= 0 && coordY < uniforms.xShape[1]) { outputValue = getX(coords[0], coordY, coordX, coords[3]); } setOutputAtIndex(index, outputValue); } } `}},sde={kernelName:mo,backendName:"webgpu",kernelFunc:({inputs:e,attrs:t,backend:a})=>{let{image:n}=e,{radians:r,fillValue:s,center:i}=t,o=a,l=new rde(n.shape,s),[u,p]=T.getImageCenter(i,n.shape[1],n.shape[2]),c=[{type:"float32",data:[u]},{type:"float32",data:[p]},{type:"float32",data:[Math.sin(r)]},{type:"float32",data:[Math.cos(r)]}];return typeof s=="number"?c.push({type:"float32",data:[Number.parseFloat(s.toFixed(2))]}):c.push({type:"float32",data:s}),o.runWebGPUProgram(l,[n],n.dtype,c)}},ide=it({opType:de.RSQRT,cpuKernelImpl:eie}),ode={kernelName:Qi,backendName:"webgpu",kernelFunc:ide},vc=class{constructor(e,t,a,n,r,s,i,o=!0){this.variableNames=["updates","indices"],this.workgroupSize=[64,1,1],this.atomic=!0,this.outputShape=s,this.type=i,this.sumDupeIndices=o,this.dispatchLayout=Ve(e),this.dispatch=Ne(this.dispatchLayout,e,this.workgroupSize),this.sliceDimGreaterThanOne=t>1,this.shaderKey=`scatter_${a}_${n}_${this.sliceDimGreaterThanOne}_${i}_${o}`;let l=ra(r.length);this.uniforms=`sliceDim : i32, strides: ${l}, updatesSize: i32,`,this.updatesRank=n,this.indicesRank=a}getUserCode(){let e="";this.indicesRank===1?e="coords[0]":this.indicesRank===2&&(e="coords[0], j");let t=`getIndices(${e})`,a=this.sliceDimGreaterThanOne?"uniforms.strides[j]":"uniforms.strides",n="",r="";this.dispatchLayout.x.length===1?(n="flattenedIndex",r=` fn getUpdatesCoordsFromFlatIndex(index : i32) -> i32 { return index; } `):this.dispatchLayout.x.length===2&&(n="vec2(flattenedIndex, coords[1])",r=` fn getUpdatesCoordsFromFlatIndex(index : i32) -> vec2 { // N.B. |updates| could be a scalar tensor, conceptually representing a // 2D tensor with all values equal to that. By design, its size must be // the same as |outShape[1]| in one dimension, and |indicesShape[0]| // gives the other. let sliceSize = uniforms.outShape[1]; let d0 = index / sliceSize; let d1 = index - d0 * sliceSize; return vec2(d0, d1); } `);let s=`getUpdates(${Array.from({length:this.updatesRank},(o,l)=>`coords[${l}]`).join(", ")})`,i=(o,l)=>{let u=`atomicAdd(${o}, bitcast(${l}))`;this.type==="float32"&&(u=` { var oldBits = 0; var newBits = bitcast(${l}); loop { let info = atomicCompareExchangeWeak(${o}, oldBits, newBits); if (info.exchanged) { break; } oldBits = info.old_value; let oldValue = bitcast(oldBits); let newValue = oldValue + (${l}); newBits = bitcast(newValue); } } `);let p=`atomicStore(${o}, bitcast(${l}));`;return this.sumDupeIndices?u:p};return` ${r} ${Ce("index")} { if (index < uniforms.updatesSize) { let coords = getUpdatesCoordsFromFlatIndex(index); var flattenedIndex = 0; for (var j = 0; j < uniforms.sliceDim; j = j + 1) { let indexInside = i32(round(${t})); flattenedIndex = flattenedIndex + indexInside * ${a}; } let updateValue = ${ad(this.type,!1)}(${s}); let flatIndex = getOutputIndexFromCoords(${n}); ${i("&result[flatIndex]","updateValue")}; } }`}};function lde(e){let{inputs:t,backend:a,attrs:n}=e,{indices:r,updates:s}=t,{shape:i}=n,{sliceRank:o,numUpdates:l,sliceSize:u,strides:p,outputSize:c}=T.calculateShapes(s,r,i),d=[c/u,u];if(c===0)return a.makeTensorInfo(i,r.dtype);let h=Ie({inputs:{x:r},backend:a,attrs:{shape:[l,o]}}),f=Ie({inputs:{x:s},backend:a,attrs:{shape:[l,u]}}),m=f.dtype,g=Cr({backend:a,attrs:{shape:d,value:0,dtype:m}}),x=v.sizeFromShape(f.shape),A=[{type:"int32",data:[o]},{type:"int32",data:p},{type:"int32",data:[x]}],y=new vc(f.shape,o,h.shape.length,f.shape.length,p,d,m),b=a.runWebGPUProgram(y,[f,h],m,A,g),w=Ie({inputs:{x:b},backend:a,attrs:{shape:i}});return a.disposeData(h.dataId),a.disposeData(f.dataId),a.disposeData(b.dataId),w}var ude={kernelName:eo,backendName:"webgpu",kernelFunc:lde},dde=class{constructor(e,t){this.outputShape=[],this.variableNames=["sortedSequence","values"],this.uniforms="numInputs : i32,",this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.side=t,this.shaderKey=`search_sorted_${t}`}getUserCode(){return` fn findBound(batch: i32, value: f32) -> i32 { var left = i32(0); var right = uniforms.numInputs; while (left < right) { var mid = (left + right) / 2; if (getSortedSequence(batch, mid) ${this.side==="left"?"<":"<="} value) { left = mid + 1; } else { right = mid; } } return right; } ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); let value = getValuesByOutputIndex(index); setOutputAtIndexI32(index, findBound(coords[0], value)); } } `}};function pde(e){let{inputs:t,backend:a,attrs:n}=e,{sortedSequence:r,values:s}=t,{side:i}=n,o=new dde([s.shape[0],s.shape[1]],i),l=[{type:"int32",data:[r.shape[1]]}];return a.runWebGPUProgram(o,[r,s],"int32",l)}var cde={kernelName:$d,backendName:"webgpu",kernelFunc:pde},hde=class{constructor(e,t,a){this.variableNames=["c","a","b"],this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=t,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.cRank=e,this.rank=a,this.shaderKey="select"}getUserCode(){let e,t;if(this.rank>4)throw Error(`Where for rank ${this.rank} is not yet supported`);if(this.rank===1)t="resRC",e="resRC";else{let a=["resRC.x","resRC.y","resRC.z","resRC.w"],n=[],r=[];for(let s=0;s= 1.0) { setOutputAtIndex(index, getA(${t})); } else { setOutputAtIndex(index, getB(${t})); } } } `}};function fde(e){let{inputs:t,backend:a}=e,{condition:n,t:r,e:s}=t,i=new hde(n.shape.length,r.shape,r.shape.length);return a.runWebGPUProgram(i,[n,r,s],ca(r.dtype,s.dtype))}var mde={kernelName:Kl,backendName:"webgpu",kernelFunc:fde},gde=it({opType:de.SIGMOID}),xde={kernelName:ao,backendName:"webgpu",kernelFunc:gde},Ade=it({opType:de.SIN}),yde={kernelName:to,backendName:"webgpu",kernelFunc:Ade},bde=it({opType:de.SINH}),vde={kernelName:Yl,backendName:"webgpu",kernelFunc:bde},Y8=ua({opType:De.SUB,cpuKernelImpl:iie,supportsComplex:!0}),wde={kernelName:lo,backendName:"webgpu",kernelFunc:Y8};function kde(e){let{inputs:t,backend:a,attrs:n}=e,{logits:r}=t,{dim:s}=n,i=v.parseAxisParam([s],r.shape),o=W3({inputs:{x:r},backend:a,attrs:{reductionIndices:i,keepDims:!1}}),l=T.expandShapeToKeepDim(o.shape,i),u=Ie({inputs:{x:o},backend:a,attrs:{shape:l}}),p=Y8({inputs:{a:r,b:u},backend:a}),c=H8({inputs:{x:p},backend:a}),d=V3({inputs:{x:c},backend:a,attrs:{axis:i,keepDims:!1}}),h=Ie({inputs:{x:d},backend:a,attrs:{shape:l}}),f=Z8({inputs:{a:c,b:h},backend:a});return a.disposeData(o.dataId),a.disposeData(u.dataId),a.disposeData(p.dataId),a.disposeData(c.dataId),a.disposeData(d.dataId),a.disposeData(h.dataId),f}var Ide={kernelName:so,backendName:"webgpu",kernelFunc:kde},Sde=e=>{let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{blockShape:s,paddings:i}=n;v.assert(r.shape.length<=4,()=>"spaceToBatchND for rank > 4 with a WebGPU backend not implemented yet");let o=s.reduce((x,A)=>x*A),l=[[0,0]];l.push(...i);for(let x=1+s.length;xa.disposeData(x.dataId)),g},Tde={kernelName:Jl,backendName:"webgpu",kernelFunc:Sde},Cde=class{constructor(e,t){this.variableNames=["A"],this.workgroupSize=[64,1,1],this.size=!0;let a=new Array(e.length);for(let n=0;n=5)throw Error(`Tile for rank ${e} is not yet supported`);if(e===1)return`(resRC % ${t}aShape)`;let a=["resRC.x","resRC.y","resRC.z","resRC.w"],n=[];for(let r=0;r=5){let o=a.readSync(r.dataId),l=r.dtype==="string"?o.map(c=>v.decodeString(c)):o,u=Me(r.shape,r.dtype,l),p=oie(u,s);return a.makeTensorInfo(p.shape,p.dtype,p.values)}let i=new Cde(r.shape,s);return a.runWebGPUProgram(i,[r],r.dtype)}var Ede={kernelName:ns,backendName:"webgpu",kernelFunc:J8};function Rde(e){let{inputs:t,backend:a,attrs:n}=e,{sparseIndices:r,sparseValues:s,defaultValue:i}=t,{outputShape:o}=n,{sliceRank:l,numUpdates:u,sliceSize:p,strides:c,outputSize:d}=T.calculateShapes(s,r,o),h=!1;if(s.dtype==="string"){let E=a.bufferSync(r),_=a.bufferSync(s),$=v.decodeString(a.readSync(i.dataId)[0]),M=tie(E,_,o,d,p,u,l,c,$,h);return a.makeTensorInfo(o,M.dtype,M.values)}let f=[d/p,p],m=Ie({inputs:{x:r},backend:a,attrs:{shape:[u,l]}}),g=s.shape.length?Ie({inputs:{x:s},backend:a,attrs:{shape:[u,p]}}):Ya({inputs:{x:s},backend:a}),x=g.dtype,A=a.makeTensorInfo([],x,v.makeZerosTypedArray(1,x)),y=Ie({inputs:{x:i},backend:a,attrs:{shape:Array(f.length).fill(1)}}),b=J8({inputs:{x:y},backend:a,attrs:{reps:f}}),w=v.sizeFromShape([u,p]),S=[{type:"int32",data:[l]},{type:"int32",data:c},{type:"int32",data:[w]}];switch(u){case 0:break;case 1:{let E=new vc([u,p],l,m.shape.length,g.shape.length,c,f,x,h);a.runWebGPUProgram(E,[g,m],x,S,b)}break;default:{let E=new vc([u,p],l,m.shape.length,A.shape.length,c,f,x,h);a.runWebGPUProgram(E,[A,m],x,S,b)}{let E=new vc([u,p],l,m.shape.length,g.shape.length,c,f,x);a.runWebGPUProgram(E,[g,m],x,S,b)}}let C=Ie({inputs:{x:b},backend:a,attrs:{shape:o}});return a.disposeData(m.dataId),a.disposeData(g.dataId),a.disposeData(y.dataId),a.disposeData(A.dataId),a.disposeData(b.dataId),C}var Mde={kernelName:Ld,backendName:"webgpu",kernelFunc:Rde};function $de(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{numOrSizeSplits:s,axis:i}=n,o=v.parseAxisParam(i,r.shape)[0],l=T.prepareSplitSize(r,s,o),u=r.shape.length,p=new Array(u).fill(0),c=r.shape.slice();return l.map(d=>{let h=[...c];h[o]=d;let f=Au({inputs:{x:r},backend:a,attrs:{begin:p,size:h}});return p[o]+=d,f})}var _de={kernelName:Ql,backendName:"webgpu",kernelFunc:$de},Pde=it({opType:de.SQRT}),Fde={kernelName:no,backendName:"webgpu",kernelFunc:Pde},Ode={kernelName:Bd,backendName:"webgpu",kernelFunc:({inputs:e,backend:t})=>{let{x:a}=e,n=t,r=new mp(a.shape,de.SQUARE);return n.runWebGPUProgram(r,[a],a.dtype)}},Dde=ua({opType:De.SQUARED_DIFFERENCE}),zde={kernelName:io,backendName:"webgpu",kernelFunc:Dde},Lde=class{constructor(e){this.variableNames=["x"],this.workPerThread=1,this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize,[this.workPerThread,1,1]);let t=ra(this.outputShape.length);this.uniforms=`begin : ${t}, strides : ${t}, `,this.shaderKey="stridedSlice"}getUserCode(){let e=this.outputShape.length,t="";if(e===1)t="coords * uniforms.strides + uniforms.begin";else{let a=0;t=this.outputShape.map((n,r)=>(a++,this.outputShape.length===1?`coords * uniforms.strides[${r}] + uniforms.begin[${r}]`:`coords[${a-1}] * uniforms.strides[${r}] + uniforms.begin[${r}]`)).join(",")}return` ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); setOutputAtIndex(index, getX(${t})); } } `}};function Bde(e){let{inputs:t,backend:a,attrs:n}=e,{x:r}=t,{begin:s,end:i,strides:o,beginMask:l,endMask:u,ellipsisMask:p,newAxisMask:c,shrinkAxisMask:d}=n,{finalShapeSparse:h,finalShape:f,isIdentity:m,sliceDim0:g,isSimpleSlice:x,begin:A,end:y,strides:b}=It.sliceInfo(r.shape,s,i,o,l,u,p,c,d),w;if(m)w=Ie({inputs:{x:r},backend:a,attrs:{shape:f}});else if(g||x){v.assert(r.shape.length>=1,()=>`Input must have rank at least 1, got: ${r.shape.length}`);let S=It.computeOutShape(A,y,b),C=Au({inputs:{x:r},backend:a,attrs:{begin:A,size:S}});w=Ie({inputs:{x:C},backend:a,attrs:{shape:f}}),a.disposeData(C.dataId)}else if(a.shouldExecuteOnCPU([r])){let S=a.readSync(r.dataId),C=Me(r.shape,r.dtype,S),E=rie(h,C,b,A);w=a.makeTensorInfo(f,r.dtype,E.values)}else{let S=new Lde(h),C=[{type:"int32",data:A},{type:"int32",data:b}],E=a.runWebGPUProgram(S,[r],r.dtype,C);w=Ie({inputs:{x:E},backend:a,attrs:{shape:f}}),a.disposeData(E.dataId)}return w}var Wde={kernelName:oo,backendName:"webgpu",kernelFunc:Bde};function Vde(e){let{inputs:t,backend:a,attrs:n}=e,{separator:r,nGramWidths:s,leftPad:i,rightPad:o,padWidth:l,preserveShortSequences:u}=n,{data:p,dataSplits:c}=t,d=a.readSync(p.dataId),h=a.readSync(c.dataId),[f,m]=sie(d,h,r,s,i,o,l,u);return[a.makeTensorInfo([f.length],"string",f),a.makeTensorInfo(c.shape,"int32",m)]}var Ude={kernelName:tu,backendName:"webgpu",kernelFunc:Vde},Gde=it({opType:de.TAN}),Hde={kernelName:uo,backendName:"webgpu",kernelFunc:Gde},jde=it({opType:de.TANH}),qde={kernelName:po,backendName:"webgpu",kernelFunc:jde},Xde=class{constructor(e){this.variableNames=["x","indices"],this.workgroupSize=[256,1,1],this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.uniforms=`inputSize : i32, firstPass : i32, negativeInf : f32, dir : i32, inc : i32,`,this.shaderKey="swap"}getUserCode(){return` ${Ce("index")} { if (index < uniforms.size) { let outC = getCoordsFromIndex(index); let batch = outC[0]; let elemIdx = outC[1]; // We compare elements pair-wise within a group of size 2 * inc. // The comparing rule for each group alternates between ascending // and descending. Within each group, we compare each pair at // positions i and i+inc. To decide whether an element at position i // is x0 or x1, we mod it by 2 * inc, if the result is smaller than // inc, it is in the first half of the group, we denote it as x0, // otherwise we denote it as x1. // For example, as shown in the Bitonic top K paper referenced // above, Figure5(a) shows that element[1] is in the second half of // the group when group size is 2, but it is in the first half of // the group when group size is 4. let isFirstInPair = elemIdx % (2 * uniforms.inc) < uniforms.inc; var i = 0; if (isFirstInPair) { i = elemIdx; } else { i = elemIdx - uniforms.inc; } var i0 = 0; if (uniforms.firstPass == 1) { i0 = i; } else { i0 = i32(getIndices(batch, i)); } var i1 = 0; if (uniforms.firstPass == 1) { i1 = i + uniforms.inc; } else { i1 = i32(getIndices(batch, i + uniforms.inc)); } var x0 = f32(0.0); var x1 = f32(0.0); if (i0 < uniforms.inputSize) { x0 = getX(batch, i0); } else { x0 = uniforms.negativeInf; } if (i1 < uniforms.inputSize) { x1 = getX(batch, i1); } else { x1 = uniforms.negativeInf; } let reverse = elemIdx % (2 * uniforms.dir) >= uniforms.dir; let isGreater = x0 > x1 || (x0 == x1 && i1 > i0); if (reverse == isGreater) { // Elements in opposite order of direction let iTemp = i0; i0 = i1; i1 = iTemp; } if (isFirstInPair) { setOutputAtIndex(index, f32(i0)); } else { setOutputAtIndex(index, f32(i1)); } } } `}},Kde=class{constructor(e){this.variableNames=["x","indices"],this.workgroupSize=[256,1,1],this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.uniforms="inputSize : i32, firstPass : i32, k : i32,",this.shaderKey="merge"}getUserCode(){return` ${Ce("index")} { if (index < uniforms.size) { let outC = getCoordsFromIndex(index); let batch = outC[0]; let elemIdx = outC[1]; // The output size is half of the previous size. // If the previous sequence is | | | | _ _ _ _ | | | | _ _ _ _ // (k=4), we only need to output the indices at positions |, the // indices at positions _ can be thrown away, see Figure5(b) After // Phase 2 (Merge phase) in the Bitonic Top K paper referenced // above. // For example, the paper shows we only need to output the orange // bars. The output sequence should look like this | | | | | | | |. // Because the sequence is halved, to map the output index back to // the previous sequence to find the corresponding value, we need // to double the index. When we double the index, we basically // interpolate a position, so 2i looks like // | _ | _ | _ | _ | _ | _ | _. We move the | to the first k // position of each 2k positions by - elemIdx % k. E.g. for output // at index 4,5,6,7, we want to get the corresponding element at // original index 8,9,10,11, for output at index 8,9,10,11, // we want to get the corresponding element at original index // 16,17,18,19, so on and so forth. var i = 0; if (elemIdx < uniforms.k) { i = elemIdx; } else { i = elemIdx * 2 - elemIdx % uniforms.k; } var i0 = 0; if (uniforms.firstPass == 1) { i0 = i; } else { i0 = i32(getIndices(batch, i)); } var i1 = 0; if (uniforms.firstPass == 1) { i1 = i + uniforms.k; } else { i1 = i32(getIndices(batch, i + uniforms.k)); } let x0 = getX(batch, i0); var x1 = f32(0.0); if (i1 < uniforms.inputSize) { x1 = getX(batch, i1); } else { x1 = x0; } if (x0 >= x1) { setOutputAtIndex(index, f32(i0)); } else { setOutputAtIndex(index, f32(i1)); } } } `}};function Jo(e,t){t!==null&&e.disposeData(t.dataId)}function eA(e){let t=1;for(;th===null?[p,p]:[p,h],m=(b,w,S)=>{let C=f(),E=new Xde(S),_=[{type:"int32",data:[l]},{type:"int32",data:[h===null?1:0]},{type:"float32",data:[Number.NEGATIVE_INFINITY]},{type:"int32",data:[b]},{type:"int32",data:[w]}],$=h;h=a.runWebGPUProgram(E,C,"int32",_),Jo(a,$)};for(let b=1;b=1;S/=2)m(w,S,[u,d])}for(let b=d;b>c;b/=2){let w=f(),S=new Kde([u,b/2]),C=[{type:"int32",data:[l]},{type:"int32",data:[h===null?1:0]},{type:"int32",data:[c]}],E=h;h=a.runWebGPUProgram(S,w,"int32",C),Jo(a,E);let _=c/2,$=_*2;for(let M=_;M>=1;M/=2)m($,M,h.shape)}let g=h;h=Au({inputs:{x:h},backend:a,attrs:{begin:0,size:[u,s]}}),Jo(a,g);let x=q8({inputs:{x:p,indices:h},backend:a,attrs:{axis:1,batchDims:1}});Jo(a,p);let A=o.slice(0,-1);A.push(s),g=h,h=Ie({inputs:{x:h},attrs:{shape:A},backend:a}),Jo(a,g);let y=x;return x=Ie({inputs:{x},attrs:{shape:A},backend:a}),Jo(a,y),[x,h]}var Yde={kernelName:co,backendName:"webgpu",kernelFunc:Zde},Jde=class{constructor(e){this.variableNames=["Image","Transforms"],this.uniforms="interpolationModeId : i32, fillModeId : i32, fillValue : f32,",this.workgroupSize=[64,1,1],this.size=!0,this.outputShape=e,this.dispatchLayout=Ve(this.outputShape),this.dispatch=Ne(this.dispatchLayout,this.outputShape,this.workgroupSize),this.shaderKey="transform"}getUserCode(){return` fn mapCoord(outCoord : f32, len : f32) -> f32{ var inCoord = outCoord; if(uniforms.fillModeId == 2) { if (inCoord < 0.0) { if (len <= 1.0) { inCoord = 0.0; } else { let sz2 = 2.0 * len; if (inCoord < sz2) { inCoord = sz2 * f32(i32(f32(-inCoord / sz2))) + inCoord; } if (inCoord < -len) { inCoord = inCoord + sz2; } else { inCoord = -inCoord - 1.0; } } } else if (inCoord > len - 1.0) { if (len <= 1.0) { inCoord = 0.0; } else { let sz2 = 2.0 * len; inCoord = inCoord - sz2 * f32(i32(f32(inCoord / sz2))); if (inCoord >= len) { inCoord = sz2 - inCoord - 1.0; } } } return clamp(inCoord, 0.0, len - 1.0); } else if (uniforms.fillModeId == 3) { if (inCoord < 0.0) { if (len <= 1.0) { inCoord = 0.0; } else { let sz = len - 1.0; inCoord = inCoord + len * (f32(i32(f32(-inCoord / sz))) + 1.0); } } else if (inCoord > len - 1.0) { if (len <= 1.0) { inCoord = 0.0; } else { let sz = len - 1.0; inCoord = inCoord - len * f32(i32(f32(inCoord / sz))); } } return clamp(inCoord, 0.0, len - 1.0); } else if (uniforms.fillModeId == 4) { return clamp(outCoord, 0.0, len - 1.0); } return outCoord; } fn readWithFillValue(batch : i32, coordY : i32, coordX : i32, channel : i32) -> f32 { var outputValue : f32; if (0 <= coordY && coordY < uniforms.imageShape[1] && 0 <= coordX && coordX < uniforms.imageShape[2]) { outputValue = getImage(batch, coordY, coordX, channel); } else { outputValue = uniforms.fillValue; } return outputValue; } ${Ce("index")} { if (index < uniforms.size) { let coords = getCoordsFromIndex(index); var outputValue : f32; let batch = coords[0]; let x = coords[2]; let y = coords[1]; let channel = coords[3]; let xf = f32(x); let yf = f32(y); let a1 = getTransforms(batch, 0); let a2 = getTransforms(batch, 1); let a3 = getTransforms(batch, 2); let b1 = getTransforms(batch, 3); let b2 = getTransforms(batch, 4); let b3 = getTransforms(batch, 5); let c1 = getTransforms(batch, 6); let c2 = getTransforms(batch, 7); let projection = c1 * xf + c2 * yf + 1.0; if (projection == 0.0) { outputValue = uniforms.fillValue; } else { let inX = (a1 * xf + a2 * yf + a3) / projection; let inY = (b1 * xf + b2 * yf + b3) / projection; let mapX = mapCoord(inX, f32(uniforms.imageShape[2])); let mapY = mapCoord(inY, f32(uniforms.imageShape[1])); if (uniforms.interpolationModeId == 1) { let coordY = i32(round(mapY)); let coordX = i32(round(mapX)); outputValue = readWithFillValue(batch, coordY, coordX, channel); } else { let yFloor = floor(mapY); let xFloor = floor(mapX); let yCeil = yFloor + 1.0; let xCeil = xFloor + 1.0; let valueYFloor = (xCeil - mapX) * readWithFillValue(batch, i32(yFloor), i32(xFloor), channel) + (mapX - xFloor) * readWithFillValue(batch, i32(yFloor), i32(xCeil), channel); let valueYCeil = (xCeil - mapX) * readWithFillValue(batch, i32(yCeil), i32(xFloor), channel) + (mapX - xFloor) * readWithFillValue(batch, i32(yCeil), i32(xCeil), channel); outputValue = (yCeil - mapY) * valueYFloor + (mapY - yFloor) * valueYCeil; } } setOutputAtIndex(index, outputValue); } } `}};function Qde(e){let{inputs:t,backend:a,attrs:n}=e,{image:r,transforms:s}=t,{interpolation:i,fillMode:o,fillValue:l,outputShape:u}=n,[p,c,d,h]=r.shape,[f,m]=u!=null?u:[c,d],g=[p,f,m,h],x=new Jde(g),A=i==="nearest"?1:2,y;switch(o){case"constant":y=1;break;case"reflect":y=2;break;case"wrap":y=3;break;case"nearest":y=4;break;default:y=1;break}let b=[{type:"int32",data:[A]},{type:"int32",data:[y]},{type:"float32",data:[l]}];return a.runWebGPUProgram(x,[r,s],"float32",b)}var epe={kernelName:ho,backendName:"webgpu",kernelFunc:Qde};function tpe(e){let{inputs:t,backend:a,attrs:n}=e,{value:r}=t,{axis:s}=n;s<0&&(s+=r.shape.length);let i=r,o=i.shape.length,l=r.shape[s],u=new Array(o-1),p=0;for(let m=0;ma.disposeData(m.dataId)),f}var ape={kernelName:au,backendName:"webgpu",kernelFunc:tpe},npe=[Nse,pie,hie,mie,xie,bie,Cie,Eie,Mie,_ie,Fie,Die,Lie,Wie,Uie,Xie,Zie,toe,soe,uoe,poe,moe,Rse,yoe,Coe,$oe,Poe,Ooe,Loe,Woe,Uoe,Hoe,Xoe,Yoe,tle,nle,sle,ole,lle,ule,ple,hle,Sse,mle,vle,xle,yle,Ile,Tle,Nle,Mle,Ple,Ole,zle,Ese,Ble,xoe,Vle,Gle,jle,Xle,Zle,Jle,aue,eue,rue,iue,Hie,lue,due,jie,cue,fue,gue,Aue,Joe,bue,wue,Iue,ioe,Cue,Eue,Mue,_ue,Fue,Due,Lue,Wue,ooe,Vue,Gue,jue,Xue,Tse,Yue,ede,nde,sde,ode,ude,cde,mde,xde,yde,vde,Qie,Wde,Ude,Ide,Tde,Mde,_de,Fde,Ode,zde,wde,Qoe,Hde,qde,Ede,Yde,epe,Iie,ape,Nue];for(let e of npe)mn(e);var tA="4.1.0",rpe="4.1.0",spe="4.1.0",ipe="4.1.0",ope="4.1.0",lpe="0.0.1-alpha.16",xp={tfjs:tA,"tfjs-core":tA,"tfjs-converter":rpe,"tfjs-backend-cpu":spe,"tfjs-backend-webgl":ipe,"tfjs-backend-wasm":ope,"tfjs-backend-webgpu":lpe};function K(...e){let t=new Date,a=`${t.getHours().toString().padStart(2,"0")}:${t.getMinutes().toString().padStart(2,"0")}:${t.getSeconds().toString().padStart(2,"0")}.${t.getMilliseconds().toString().padStart(3,"0")}`;e&&console.log(a,"Human:",...e)}function Q8(e,t){let a=e.endsWith("/")?"":"/",r=t.startsWith(".")||t.startsWith("/")||t.startsWith("http:")||t.startsWith("https:")||t.startsWith("file:")?`${t}`:`${e}${a}${t}`;if(!r.toLocaleLowerCase().includes(".json"))throw new Error(`modelpath error: expecting json file: ${r}`);return r}var te=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function U3(e,t,a="config",n=[]){for(let r of Object.keys(t))if(typeof t[r]=="object")U3(e[r],t[r],r,n);else{let s=e&&typeof e[r]!="undefined";s||n.push({reason:"unknown property",where:`${a}.${r} = ${t[r]}`});let i=e&&typeof e[r]==typeof t[r];s&&!i&&n.push({reason:"property type mismatch",where:`${a}.${r} = ${t[r]}`,expected:typeof e[r]})}return t.debug&&a==="config"&&n.length>0&&K("invalid configuration",n),n}function Ct(...e){let t=a=>a&&typeof a=="object";return e.reduce((a,n)=>(Object.keys(n||{}).forEach(r=>{let s=a[r],i=n[r];Array.isArray(s)&&Array.isArray(i)?a[r]=s.concat(...i):t(s)&&t(i)?a[r]=Ct(s,i):a[r]=i}),a),{})}var Io={backend:"",modelBasePath:"",cacheModels:!0,validateModels:!0,wasmPath:"",wasmPlatformFetch:!1,debug:!1,async:!0,warmup:"full",cacheSensitivity:.7,skipAllowed:!1,deallocate:!1,flags:{},softwareKernels:!1,filter:{enabled:!0,equalization:!1,width:0,height:0,flip:!1,return:!0,autoBrightness:!0,brightness:0,contrast:0,sharpness:0,blur:0,saturation:0,hue:0,negative:!1,sepia:!1,vintage:!1,kodachrome:!1,technicolor:!1,polaroid:!1,pixelate:0},gesture:{enabled:!0},face:{enabled:!0,detector:{modelPath:"blazeface.json",rotation:!0,maxDetected:1,skipFrames:99,skipTime:2500,minConfidence:.2,iouThreshold:.1,mask:!1,return:!1},mesh:{enabled:!0,modelPath:"facemesh.json",keepInvalid:!1},attention:{enabled:!1,modelPath:"facemesh-attention.json"},iris:{enabled:!0,modelPath:"iris.json"},emotion:{enabled:!0,minConfidence:.1,skipFrames:99,skipTime:1500,modelPath:"emotion.json"},description:{enabled:!0,modelPath:"faceres.json",skipFrames:99,skipTime:3e3,minConfidence:.1},antispoof:{enabled:!1,skipFrames:99,skipTime:4e3,modelPath:"antispoof.json"},liveness:{enabled:!1,skipFrames:99,skipTime:4e3,modelPath:"liveness.json"}},body:{enabled:!0,modelPath:"movenet-lightning.json",maxDetected:-1,minConfidence:.3,skipFrames:1,skipTime:200},hand:{enabled:!0,rotation:!0,skipFrames:99,skipTime:1e3,minConfidence:.5,iouThreshold:.2,maxDetected:-1,landmarks:!0,detector:{modelPath:"handtrack.json"},skeleton:{modelPath:"handlandmark-lite.json"}},object:{enabled:!1,modelPath:"centernet.json",minConfidence:.2,iouThreshold:.4,maxDetected:10,skipFrames:99,skipTime:2e3},segmentation:{enabled:!1,modelPath:"rvm.json",ratio:.5,mode:"default"}};var e9=` precision highp float; attribute vec2 pos; attribute vec2 uv; varying vec2 vUv; uniform float flipY; void main(void) { vUv = uv; gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.); } `;var t9=` precision highp float; varying vec2 vUv; uniform sampler2D texture; uniform float m[20]; void main(void) { vec4 c = texture2D(texture, vUv); gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4]; gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9]; gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14]; gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19]; } `,a9=` precision highp float; varying vec2 vUv; uniform sampler2D texture; uniform float m[20]; void main(void) { vec4 c = texture2D(texture, vUv); gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4]; gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9]; gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14]; gl_FragColor.a = c.a; } `,n9=` precision highp float; varying vec2 vUv; uniform vec2 size; uniform sampler2D texture; vec2 pixelate(vec2 coord, vec2 size) { return floor( coord / size ) * size; } void main(void) { gl_FragColor = vec4(0.0); vec2 coord = pixelate(vUv, size); gl_FragColor += texture2D(texture, coord); } `,r9=` precision highp float; varying vec2 vUv; uniform sampler2D texture; uniform vec2 px; void main(void) { gl_FragColor = vec4(0.0); gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265; gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794; gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053; gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718; gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933; gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105; gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121; gl_FragColor += texture2D(texture, vUv )*0.159576912161; gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121; gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105; gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933; gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718; gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053; gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794; gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265; } `,s9=` precision highp float; varying vec2 vUv; uniform sampler2D texture; uniform vec2 px; uniform float m[9]; void main(void) { vec4 c11 = texture2D(texture, vUv - px); // top left vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y)); // top center vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y)); // top right vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) ); // mid left vec4 c22 = texture2D(texture, vUv); // mid center vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) ); // mid right vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) ); // bottom left vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) ); // bottom center vec4 c33 = texture2D(texture, vUv + px ); // bottom right gl_FragColor = c11 * m[0] + c12 * m[1] + c22 * m[2] + c21 * m[3] + c22 * m[4] + c23 * m[5] + c31 * m[6] + c32 * m[7] + c33 * m[8]; gl_FragColor.a = c22.a; } `;var G3=(e,t,a)=>{let n=new RegExp("\\b"+t+" \\w+ (\\w+)","ig");e.replace(n,(r,s)=>(a[s]=0,r))},H3=class{constructor(t,a,n){ue(this,"uniform",{});ue(this,"attribute",{});ue(this,"gl");ue(this,"id");ue(this,"compile",(t,a)=>{let n=this.gl.createShader(a);return n?(this.gl.shaderSource(n,t),this.gl.compileShader(n),this.gl.getShaderParameter(n,this.gl.COMPILE_STATUS)?n:(K(`filter: gl compile failed: ${this.gl.getShaderInfoLog(n)||"unknown"}`),null)):(K("filter: could not create shader"),null)});this.gl=t;let r=this.compile(a,this.gl.VERTEX_SHADER),s=this.compile(n,this.gl.FRAGMENT_SHADER);if(this.id=this.gl.createProgram(),!(!r||!s)){if(!this.id){K("filter: could not create webgl program");return}if(this.gl.attachShader(this.id,r),this.gl.attachShader(this.id,s),this.gl.linkProgram(this.id),!this.gl.getProgramParameter(this.id,this.gl.LINK_STATUS)){K(`filter: gl link failed: ${this.gl.getProgramInfoLog(this.id)||"unknown"}`);return}this.gl.useProgram(this.id),G3(a,"attribute",this.attribute);for(let i in this.attribute)this.attribute[i]=this.gl.getAttribLocation(this.id,i);G3(a,"uniform",this.uniform),G3(n,"uniform",this.uniform);for(let i in this.uniform)this.uniform[i]=this.gl.getUniformLocation(this.id,i)}}};function i9(){let e=0,t=null,a=!1,n=-1,r=[null,null],s=[],i=null,o=null,l=Nn(100,100),u={},p={INTERMEDIATE:1},c=l.getContext("webgl");if(!c){K("filter: cannot get webgl context");return}this.gl=c;function d(A,y){if(!(A===l.width&&y===l.height)){if(l.width=A,l.height=y,!i){let b=new Float32Array([-1,-1,0,1,1,-1,1,1,-1,1,0,0,-1,1,0,0,1,-1,1,1,1,1,1,0]);i=c.createBuffer(),c.bindBuffer(c.ARRAY_BUFFER,i),c.bufferData(c.ARRAY_BUFFER,b,c.STATIC_DRAW),c.pixelStorei(c.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0)}c.viewport(0,0,l.width,l.height),r=[null,null]}}function h(A,y){let b=c.createFramebuffer();c.bindFramebuffer(c.FRAMEBUFFER,b);let w=c.createRenderbuffer();c.bindRenderbuffer(c.RENDERBUFFER,w);let S=c.createTexture();return c.bindTexture(c.TEXTURE_2D,S),c.texImage2D(c.TEXTURE_2D,0,c.RGBA,A,y,0,c.RGBA,c.UNSIGNED_BYTE,null),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MAG_FILTER,c.LINEAR),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MIN_FILTER,c.LINEAR),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_S,c.CLAMP_TO_EDGE),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_T,c.CLAMP_TO_EDGE),c.framebufferTexture2D(c.FRAMEBUFFER,c.COLOR_ATTACHMENT0,c.TEXTURE_2D,S,0),c.bindTexture(c.TEXTURE_2D,null),c.bindFramebuffer(c.FRAMEBUFFER,null),{fbo:b,texture:S}}function f(A){return r[A]=r[A]||h(l.width,l.height),r[A]}function m(A=0){if(!o)return;let y=null,b=null,w=!1;e===0?y=t:y=f(n).texture||null,e++,a&&!(A&p.INTERMEDIATE)?(b=null,w=e%2===0):(n=(n+1)%2,b=f(n).fbo||null),c.bindTexture(c.TEXTURE_2D,y),c.bindFramebuffer(c.FRAMEBUFFER,b),c.uniform1f(o.uniform.flipY,w?-1:1),c.drawArrays(c.TRIANGLES,0,6)}function g(A){if(u[A])return o=u[A],c.useProgram((o?o.id:null)||null),o;if(o=new H3(c,e9,A),!o)return K("filter: could not get webgl program"),null;let y=Float32Array.BYTES_PER_ELEMENT,b=4*y;return c.enableVertexAttribArray(o.attribute.pos),c.vertexAttribPointer(o.attribute.pos,2,c.FLOAT,!1,b,0*y),c.enableVertexAttribArray(o.attribute.uv),c.vertexAttribPointer(o.attribute.uv,2,c.FLOAT,!1,b,2*y),u[A]=o,o}let x={colorMatrix:A=>{let y=new Float32Array(A);y[4]/=255,y[9]/=255,y[14]/=255,y[19]/=255;let b=y[18]===1&&y[3]===0&&y[8]===0&&y[13]===0&&y[15]===0&&y[16]===0&&y[17]===0&&y[19]===0?a9:t9,w=g(b);!w||(c.uniform1fv(w.uniform.m,y),m())},brightness:A=>{let y=(A||0)+1;x.colorMatrix([y,0,0,0,0,0,y,0,0,0,0,0,y,0,0,0,0,0,1,0])},saturation:A=>{let y=(A||0)*2/3+1,b=(y-1)*-.5;x.colorMatrix([y,b,b,0,0,b,y,b,0,0,b,b,y,0,0,0,0,0,1,0])},desaturate:()=>{x.saturation(-1)},contrast:A=>{let y=(A||0)+1,b=-128*(y-1);x.colorMatrix([y,0,0,0,b,0,y,0,0,b,0,0,y,0,b,0,0,0,1,0])},negative:()=>{x.contrast(-2)},hue:A=>{A=(A||0)/180*Math.PI;let y=Math.cos(A),b=Math.sin(A),w=.213,S=.715,C=.072;x.colorMatrix([w+y*(1-w)+b*-w,S+y*-S+b*-S,C+y*-C+b*(1-C),0,0,w+y*-w+b*.143,S+y*(1-S)+b*.14,C+y*-C+b*-.283,0,0,w+y*-w+b*-(1-w),S+y*-S+b*S,C+y*(1-C)+b*C,0,0,0,0,0,1,0])},desaturateLuminance:()=>{x.colorMatrix([.2764723,.929708,.0938197,0,-37.1,.2764723,.929708,.0938197,0,-37.1,.2764723,.929708,.0938197,0,-37.1,0,0,0,1,0])},sepia:()=>{x.colorMatrix([.393,.7689999,.18899999,0,0,.349,.6859999,.16799999,0,0,.272,.5339999,.13099999,0,0,0,0,0,1,0])},brownie:()=>{x.colorMatrix([.5997023498159715,.34553243048391263,-.2708298674538042,0,47.43192855600873,-.037703249837783157,.8609577587992641,.15059552388459913,0,-36.96841498319127,.24113635128153335,-.07441037908422492,.44972182064877153,0,-7.562075277591283,0,0,0,1,0])},vintagePinhole:()=>{x.colorMatrix([.6279345635605994,.3202183420819367,-.03965408211312453,0,9.651285835294123,.02578397704808868,.6441188644374771,.03259127616149294,0,7.462829176470591,.0466055556782719,-.0851232987247891,.5241648018700465,0,5.159190588235296,0,0,0,1,0])},kodachrome:()=>{x.colorMatrix([1.1285582396593525,-.3967382283601348,-.03992559172921793,0,63.72958762196502,-.16404339962244616,1.0835251566291304,-.05498805115633132,0,24.732407896706203,-.16786010706155763,-.5603416277695248,1.6014850761964943,0,35.62982807460946,0,0,0,1,0])},technicolor:()=>{x.colorMatrix([1.9125277891456083,-.8545344976951645,-.09155508482755585,0,11.793603434377337,-.3087833385928097,1.7658908555458428,-.10601743074722245,0,-70.35205161461398,-.231103377548616,-.7501899197440212,1.847597816108189,0,30.950940869491138,0,0,0,1,0])},polaroid:()=>{x.colorMatrix([1.438,-.062,-.062,0,0,-.122,1.378,-.122,0,0,-.016,-.016,1.483,0,0,0,0,0,1,0])},shiftToBGR:()=>{x.colorMatrix([0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0])},convolution:A=>{let y=new Float32Array(A),b=1/l.width,w=1/l.height,S=g(s9);!S||(c.uniform1fv(S.uniform.m,y),c.uniform2f(S.uniform.px,b,w),m())},detectEdges:()=>{x.convolution.call(this,[0,1,0,1,-4,1,0,1,0])},sobelX:()=>{x.convolution.call(this,[-1,0,1,-2,0,2,-1,0,1])},sobelY:()=>{x.convolution.call(this,[-1,-2,-1,0,0,0,1,2,1])},sharpen:A=>{let y=A||1;x.convolution.call(this,[0,-1*y,0,-1*y,1+4*y,-1*y,0,-1*y,0])},emboss:A=>{let y=A||1;x.convolution.call(this,[-2*y,-1*y,0,-1*y,1,1*y,0,1*y,2*y])},blur:A=>{let y=A/7/l.width,b=A/7/l.height,w=g(r9);!w||(c.uniform2f(w.uniform.px,0,b),m(p.INTERMEDIATE),c.uniform2f(w.uniform.px,y,0),m())},pixelate:A=>{let y=A/l.width,b=A/l.height,w=g(n9);!w||(c.uniform2f(w.uniform.size,y,b),m())}};this.add=function(A){let y=Array.prototype.slice.call(arguments,1),b=x[A];s.push({func:b,args:y})},this.reset=function(){s=[]},this.get=function(){return s},this.apply=function(A){d(A.width,A.height),e=0,t||(t=c.createTexture()),c.bindTexture(c.TEXTURE_2D,t),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_S,c.CLAMP_TO_EDGE),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_WRAP_T,c.CLAMP_TO_EDGE),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MIN_FILTER,c.NEAREST),c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MAG_FILTER,c.NEAREST),c.texImage2D(c.TEXTURE_2D,0,c.RGBA,c.RGBA,c.UNSIGNED_BYTE,A);for(let y=0;yp.data())),i=Math.max(s[0][0],s[1][0],s[2][0]),l=(i>1?255:1)/i,u;if(l>1){let p=[fe(a[0],n[0]),fe(a[1],n[1]),fe(a[2],n[2])],c=[fe(r[0],n[0]),fe(r[1],n[1]),fe(r[2],n[2])],d=[ae(p[0],l),ae(p[1],l),ae(p[2],l)],h=sa([d[0],d[1],d[2]],2);u=J(h,[1,t.shape[0]||0,t.shape[1]||0,3]),Y([...p,...c,...d])}else u=Gt(t,0);return Y([...a,...n,...r,a,t,e]),u}var Xh=3840,Jt=null,Qt=null,yu=null,xt,gn={inputSum:0,cacheDiff:1,sumMethod:0,inputTensor:void 0};function j3(){gn.inputSum=0,gn.cacheDiff=1,gn.sumMethod=0,gn.inputTensor=void 0}function Nn(e,t){let a;if(ne.browser)if(ne.worker){if(typeof OffscreenCanvas=="undefined")throw new Error("canvas error: attempted to run in web worker but OffscreenCanvas is not supported");a=new OffscreenCanvas(e,t)}else{if(typeof document=="undefined")throw new Error("canvas error: attempted to run in browser but DOM is not defined");a=document.createElement("canvas"),a.width=e,a.height=t}else typeof ne.Canvas!="undefined"?a=new ne.Canvas(e,t):typeof globalThis.Canvas!="undefined"&&(a=new globalThis.Canvas(e,t));return a}function Kh(e,t){let a=t||Nn(e.width,e.height);return a.getContext("2d").drawImage(e,0,0),a}async function Zh(e,t,a=!0){var d,h,f;if(!e)return t.debug&&K("input error: input is missing"),{tensor:null,canvas:null};if(!(e instanceof pt)&&!(typeof Image!="undefined"&&e instanceof Image)&&!(typeof globalThis.Canvas!="undefined"&&e instanceof globalThis.Canvas)&&!(typeof ImageData!="undefined"&&e instanceof ImageData)&&!(typeof ImageBitmap!="undefined"&&e instanceof ImageBitmap)&&!(typeof HTMLImageElement!="undefined"&&e instanceof HTMLImageElement)&&!(typeof HTMLMediaElement!="undefined"&&e instanceof HTMLMediaElement)&&!(typeof HTMLVideoElement!="undefined"&&e instanceof HTMLVideoElement)&&!(typeof HTMLCanvasElement!="undefined"&&e instanceof HTMLCanvasElement)&&!(typeof OffscreenCanvas!="undefined"&&e instanceof OffscreenCanvas))throw new Error("input error: type not recognized");if(e instanceof pt){let m=null;if(e.isDisposedInternal)throw new Error("input error: attempted to use tensor but it is disposed");if(!e.shape)throw new Error("input error: attempted to use tensor without a shape");if(e.shape.length===3){if(e.shape[2]===3)m=Gt(e,0);else if(e.shape[2]===4){let g=sp(e,[0,0,0],[-1,-1,3]);m=Gt(g,0),Y(g)}}else e.shape.length===4&&(e.shape[3]===3?m=wa(e):e.shape[3]===4&&(m=xh(e,[0,0,0,0],[-1,-1,-1,3])));if(m==null||m.shape.length!==4||m.shape[0]!==1||m.shape[3]!==3)throw new Error(`input error: attempted to use tensor with unrecognized shape: ${e.shape.toString()}`);if(m.dtype==="int32"){let g=He(m,"float32");Y(m),m=g}return{tensor:m,canvas:t.filter.return?Qt:null}}if(typeof e.readyState!="undefined"&&e.readyState<=2)return t.debug&&K("input stream is not ready"),{tensor:null,canvas:Jt};let n=e.naturalWidth||e.videoWidth||e.width||e.shape&&e.shape[1]>0,r=e.naturalHeight||e.videoHeight||e.height||e.shape&&e.shape[2]>0;if(!n||!r)return t.debug&&K("cannot determine input dimensions"),{tensor:null,canvas:Jt};let s=n,i=r;if(s>Xh&&(s=Xh,i=Math.trunc(s*r/n)),i>Xh&&(i=Xh,s=Math.trunc(i*n/r)),(((d=t.filter)==null?void 0:d.width)||0)>0?s=t.filter.width:(((h=t.filter)==null?void 0:h.height)||0)>0&&(s=n*((t.filter.height||0)/r)),(t.filter.height||0)>0?i=t.filter.height:(t.filter.width||0)>0&&(i=r*((t.filter.width||0)/n)),!s||!i)throw new Error("input error: cannot determine dimension");(!Jt||Jt.width!==s||Jt.height!==i)&&(Jt=Nn(s,i));let o=Jt.getContext("2d");if(typeof ImageData!="undefined"&&e instanceof ImageData?o.putImageData(e,0,0):t.filter.flip&&typeof o.translate!="undefined"?(o.translate(n,0),o.scale(-1,1),o.drawImage(e,0,0,n,r,0,0,Jt.width,Jt.height),o.setTransform(1,0,0,1,0,0)):o.drawImage(e,0,0,n,r,0,0,Jt.width,Jt.height),(!Qt||Jt.width!==Qt.width||Jt.height!==Qt.height)&&(Qt=Nn(Jt.width,Jt.height)),t.filter.enabled&&ne.webgl.supported?(xt||(xt=ne.browser?new i9:null),ne.filter=!!xt,xt!=null&&xt.add?(xt.reset(),t.filter.brightness!==0&&xt.add("brightness",t.filter.brightness),t.filter.contrast!==0&&xt.add("contrast",t.filter.contrast),t.filter.sharpness!==0&&xt.add("sharpen",t.filter.sharpness),t.filter.blur!==0&&xt.add("blur",t.filter.blur),t.filter.saturation!==0&&xt.add("saturation",t.filter.saturation),t.filter.hue!==0&&xt.add("hue",t.filter.hue),t.filter.negative&&xt.add("negative"),t.filter.sepia&&xt.add("sepia"),t.filter.vintage&&xt.add("brownie"),t.filter.sepia&&xt.add("sepia"),t.filter.kodachrome&&xt.add("kodachrome"),t.filter.technicolor&&xt.add("technicolor"),t.filter.polaroid&&xt.add("polaroid"),t.filter.pixelate!==0&&xt.add("pixelate",t.filter.pixelate),((f=xt.get())==null?void 0:f.length)>1?Qt=xt.apply(Jt):Qt=xt.draw(Jt)):(t.debug&&K("input process error: cannot initialize filters"),ne.webgl.supported=!1,t.filter.enabled=!1,Kh(Jt,Qt))):(Kh(Jt,Qt),xt&&(xt=null),ne.filter=!!xt),!a)return{tensor:null,canvas:Qt};if(!Qt)throw new Error("canvas error: cannot create output");let l,u=3;if(typeof ImageData!="undefined"&&e instanceof ImageData||e.data&&e.width&&e.height)if(ne.browser&&wr)l=wr?wr.fromPixels(e):null;else{u=e.data.length/e.height/e.width;let m=new Uint8Array(e.data.buffer);l=Be(m,[e.height,e.width,u],"int32")}else if((!yu||Qt.width!==yu.width||Qt.height!==yu.height)&&(yu=Nn(Qt.width,Qt.height)),wr&&ne.browser)t.backend==="webgl"||t.backend==="humangl"||t.backend==="webgpu"?l=wr.fromPixels(Qt):(yu=Kh(Qt),l=wr.fromPixels(yu));else{let x=Kh(Qt).getContext("2d").getImageData(0,0,s,i);u=x.data.length/s/i;let A=new Uint8Array(x.data.buffer);l=Be(A,[s,i,u])}if(u===4){let m=sp(l,[0,0,0],[-1,-1,3]);Y(l),l=m}if(!l)throw new Error("input error: cannot create tensor");let p=He(l,"float32"),c=t.filter.equalization?await qh(p):Gt(p,0);if(Y([l,p]),t.filter.autoBrightness){let m=pa(c),g=await m.data();t.filter.brightness=g[0]>1?1-g[0]/255:1-g[0],Y(m)}return{tensor:c,canvas:t.filter.return?Qt:null}}async function o9(e,t){let a=!1;if(e.cacheSensitivity===0||!t.shape||t.shape.length!==4||t.shape[1]>3840||t.shape[2]>2160)return a;if(!gn.inputTensor)gn.inputTensor=wa(t);else if(gn.inputTensor.shape[1]!==t.shape[1]||gn.inputTensor.shape[2]!==t.shape[2])Y(gn.inputTensor),gn.inputTensor=wa(t);else{let n={};n.diff=fe(t,gn.inputTensor),n.squared=ae(n.diff,n.diff),n.sum=tt(n.squared);let s=(await n.sum.data())[0]/(t.shape[1]||1)/(t.shape[2]||1)/255/3;Y([gn.inputTensor,n.diff,n.squared,n.sum]),gn.inputTensor=wa(t),a=s<=(e.cacheSensitivity||0)}return a}async function l9(e,t,a){let n={};if(!t||!a||t.shape.length!==4||t.shape.length!==a.shape.length)return e.debug||K("invalid input tensor or tensor shapes do not match:",t.shape,a.shape),0;if(t.shape[0]!==1||a.shape[0]!==1||t.shape[3]!==3||a.shape[3]!==3)return e.debug||K("input tensors must be of shape [1, height, width, 3]:",t.shape,a.shape),0;n.input1=wa(t),n.input2=t.shape[1]!==a.shape[1]||t.shape[2]!==a.shape[2]?ge.resizeBilinear(a,[t.shape[1],t.shape[2]]):wa(a),n.diff=fe(n.input1,n.input2),n.squared=ae(n.diff,n.diff),n.sum=tt(n.squared);let s=(await n.sum.data())[0]/(t.shape[1]||1)/(t.shape[2]||1)/255/3;return Y([n.input1,n.input2,n.diff,n.squared,n.sum]),s}var yp,bp,vp,Ap=class{constructor(){ue(this,"browser");ue(this,"node");ue(this,"worker");ue(this,"platform","");ue(this,"agent","");ue(this,"backends",[]);ue(this,"initial");ue(this,"filter");ue(this,"tfjs");ue(this,"offscreen");ue(this,"perfadd",!1);ue(this,"tensorflow",{version:void 0,gpu:void 0});ue(this,"wasm",{supported:void 0,backend:void 0,simd:void 0,multithread:void 0});ue(this,"webgl",{supported:void 0,backend:void 0,version:void 0,renderer:void 0,shader:void 0,vendor:void 0});ue(this,"webgpu",{supported:void 0,backend:void 0,adapter:void 0});ue(this,"cpu",{model:void 0,flags:[]});ue(this,"kernels",[]);Gn(this,yp,void 0);Gn(this,bp,void 0);Gn(this,vp,void 0);if(this.browser=typeof navigator!="undefined",this.node=typeof process!="undefined"&&typeof process.versions!="undefined"&&typeof process.versions.node!="undefined",this.tfjs={version:xp["tfjs-core"]},this.offscreen=typeof OffscreenCanvas!="undefined",this.initial=!0,this.worker=this.browser&&this.offscreen?typeof WorkerGlobalScope!="undefined":void 0,typeof navigator!="undefined"){let t=navigator.userAgent.match(/\(([^()]+)\)/g);if(t!=null&&t[0]){let a=t[0].match(/\(([^()]+)\)/g);this.platform=a!=null&&a[0]?a[0].replace(/\(|\)/g,""):"",this.agent=navigator.userAgent.replace(t[0],""),this.platform[1]&&(this.agent=this.agent.replace(t[1],"")),this.agent=this.agent.replace(/ /g," ")}}else typeof process!="undefined"&&(this.platform=`${process.platform} ${process.arch}`,this.agent=`NodeJS ${process.version}`)}get Canvas(){return Ga(this,yp)}set Canvas(t){fr(this,yp,t),globalThis.Canvas=t}get Image(){return Ga(this,bp)}set Image(t){fr(this,bp,t),globalThis.Image=t}get ImageData(){return Ga(this,vp)}set ImageData(t){fr(this,vp,t),globalThis.ImageData=t}async updateBackend(){this.backends=Object.keys(kt().registryFactory);try{this.tensorflow={version:tr().binding?tr().binding.TF_Version:void 0,gpu:tr().binding?tr().binding.isUsingGpuDevice():void 0}}catch(n){}this.wasm.supported=typeof WebAssembly!="undefined",this.wasm.backend=this.backends.includes("wasm"),this.wasm.supported&&this.wasm.backend&&(this.wasm.simd=await W().getAsync("WASM_HAS_SIMD_SUPPORT"),this.wasm.multithread=await W().getAsync("WASM_HAS_MULTITHREAD_SUPPORT"));let t=Nn(100,100),a=t?t.getContext("webgl2"):void 0;this.webgl.supported=typeof a!="undefined",this.webgl.backend=this.backends.includes("webgl"),this.webgl.supported&&this.webgl.backend&&a&&(this.webgl.version=a.getParameter(a.VERSION),this.webgl.vendor=a.getParameter(a.VENDOR),this.webgl.renderer=a.getParameter(a.RENDERER),this.webgl.shader=a.getParameter(a.SHADING_LANGUAGE_VERSION)),this.webgpu.supported=this.browser&&typeof navigator.gpu!="undefined",this.webgpu.backend=this.backends.includes("webgpu");try{if(this.webgpu.supported){let n=await navigator.gpu.requestAdapter();this.webgpu.adapter=await(n==null?void 0:n.requestAdapterInfo())}}catch(n){this.webgpu.supported=!1}try{this.kernels=Zn(ia()).map(n=>n.kernelName.toLowerCase())}catch(n){}}updateCPU(){let t={model:"",flags:[]};this.node&&this.platform.startsWith("linux"),this.cpu?this.cpu=t:Object.defineProperty(this,"cpu",{value:t})}};yp=new WeakMap,bp=new WeakMap,vp=new WeakMap;var ne=new Ap;var Jh=class{constructor(){ue(this,"config");ue(this,"element");ue(this,"stream");ue(this,"devices",[]);ue(this,"enumerate",async()=>{try{let t=await navigator.mediaDevices.enumerateDevices();this.devices=t.filter(a=>a.kind==="videoinput")}catch(t){this.devices=[]}return this.devices});ue(this,"start",async t=>{var r,s;if(t!=null&&t.debug&&(this.config.debug=t==null?void 0:t.debug),t!=null&&t.crop&&(this.config.crop=t==null?void 0:t.crop),t!=null&&t.mode&&(this.config.mode=t==null?void 0:t.mode),t!=null&&t.width&&(this.config.width=t==null?void 0:t.width),t!=null&&t.height&&(this.config.height=t==null?void 0:t.height),t!=null&&t.id&&(this.config.id=t==null?void 0:t.id),t!=null&&t.element)if(typeof t.element=="string"){let i=document.getElementById(t.element);if(i&&i instanceof HTMLVideoElement)this.element=i;else{this.config.debug&&K("webcam","cannot get dom element",t.element);return}}else if(t.element instanceof HTMLVideoElement)this.element=t.element;else{this.config.debug&&K("webcam","unknown dom element",t.element);return}else this.element=document.createElement("video");let a={audio:!1,video:{facingMode:this.config.mode==="front"?"user":"environment",resizeMode:this.config.crop?"crop-and-scale":"none"}};if(((r=this.config)==null?void 0:r.width)>0&&(a.video.width={ideal:this.config.width}),((s=this.config)==null?void 0:s.height)>0&&(a.video.height={ideal:this.config.height}),this.config.id&&(a.video.deviceId=this.config.id),this.element.addEventListener("play",()=>{this.config.debug&&K("webcam","play")}),this.element.addEventListener("pause",()=>{this.config.debug&&K("webcam","pause")}),this.element.addEventListener("click",async()=>{!this.element||!this.stream||(this.element.paused?await this.element.play():this.element.pause())}),!(navigator!=null&&navigator.mediaDevices)){this.config.debug&&K("webcam","no devices");return}try{this.stream=await navigator.mediaDevices.getUserMedia(a)}catch(i){K("webcam",i);return}if(!this.stream){this.config.debug&&K("webcam","no stream");return}this.element.srcObject=this.stream,await new Promise(i=>{this.element?this.element.onloadeddata=()=>i(!0):i(!1)}),await this.element.play(),this.config.debug&&K("webcam",{width:this.width,height:this.height,label:this.label,stream:this.stream,track:this.track,settings:this.settings,constraints:this.constraints,capabilities:this.capabilities})});ue(this,"pause",()=>{this.element&&this.element.pause()});ue(this,"play",async()=>{this.element&&await this.element.play()});ue(this,"stop",()=>{this.config.debug&&K("webcam","stop"),this.track&&this.track.stop()});this.config={element:void 0,debug:!0,mode:"front",crop:!1,width:0,height:0}}get track(){if(!!this.stream)return this.stream.getVideoTracks()[0]}get capabilities(){if(!!this.track)return this.track.getCapabilities?this.track.getCapabilities():void 0}get constraints(){if(!!this.track)return this.track.getConstraints?this.track.getConstraints():void 0}get settings(){if(!this.stream)return;let t=this.stream.getVideoTracks()[0];return t.getSettings?t.getSettings():void 0}get label(){return this.track?this.track.label:""}get paused(){var t;return((t=this.element)==null?void 0:t.paused)||!1}get width(){var t;return((t=this.element)==null?void 0:t.videoWidth)||0}get height(){var t;return((t=this.element)==null?void 0:t.videoHeight)||0}};var q3={};hr(q3,{age:()=>Ipe,"anti-spoofing":()=>ece,antispoof:()=>cpe,blazeface:()=>hpe,"blazeface-back":()=>Spe,"blazeface-front":()=>Tpe,"blazepose-detector":()=>Cpe,"blazepose-full":()=>Npe,"blazepose-heavy":()=>Epe,"blazepose-lite":()=>Rpe,centernet:()=>fpe,default:()=>hce,efficientpose:()=>Mpe,"efficientpose-i-lite":()=>tce,"efficientpose-ii-lite":()=>ace,"efficientpose-iv":()=>nce,emotion:()=>mpe,faceboxes:()=>$pe,facemesh:()=>gpe,"facemesh-attention":()=>Ppe,"facemesh-attention-pinto":()=>_pe,"facemesh-detection-full":()=>Fpe,"facemesh-detection-short":()=>Ope,faceres:()=>xpe,"faceres-deep":()=>Dpe,gear:()=>zpe,gender:()=>Bpe,"gender-ssrnet-imdb":()=>Lpe,handdetect:()=>Wpe,"handlandmark-full":()=>Vpe,"handlandmark-lite":()=>Ape,"handlandmark-sparse":()=>Upe,handskeleton:()=>Gpe,handtrack:()=>ype,"insightface-efficientnet-b0":()=>rce,"insightface-ghostnet-strides1":()=>sce,"insightface-ghostnet-strides2":()=>ice,"insightface-mobilenet-emore":()=>oce,"insightface-mobilenet-swish":()=>lce,iris:()=>bpe,liveness:()=>vpe,meet:()=>Hpe,mobileface:()=>jpe,mobilefacenet:()=>qpe,models:()=>wpe,"movenet-lightning":()=>kpe,"movenet-multipose":()=>Xpe,"movenet-thunder":()=>Kpe,nanodet:()=>Zpe,"nanodet-e":()=>uce,"nanodet-g":()=>dce,"nanodet-m":()=>pce,"nanodet-t":()=>cce,posenet:()=>Ype,rvm:()=>Jpe,selfie:()=>Qpe});var cpe=853098,hpe=538928,fpe=4030290,mpe=820516,gpe=1477958,xpe=6978814,Ape=2023432,ype=2964837,bpe=2599092,vpe=592976,wpe=0,kpe=4650216,Ipe=161240,Spe=538928,Tpe=402048,Cpe=5928856,Npe=6339202,Epe=27502466,Rpe=2726402,Mpe=5651240,$pe=2013002,_pe=2387598,Ppe=2382414,Fpe=1026192,Ope=201268,Dpe=13957620,zpe=1498916,Lpe=161236,Bpe=201808,Wpe=3515612,Vpe=5431368,Upe=5286322,Gpe=5502280,Hpe=372228,jpe=2183192,qpe=5171976,Xpe=9448838,Kpe=12477112,Zpe=7574558,Ype=5032780,Jpe=3739355,Qpe=212886,ece=853098,tce=2269064,ace=5651240,nce=25643252,rce=13013224,sce=8093408,ice=8049584,oce=6938536,lce=12168584,uce=12319156,dce=7574558,pce=1887474,cce=5294216,hce={antispoof:cpe,blazeface:hpe,centernet:fpe,emotion:mpe,facemesh:gpe,faceres:xpe,"handlandmark-lite":Ape,handtrack:ype,iris:bpe,liveness:vpe,models:wpe,"movenet-lightning":kpe,age:Ipe,"blazeface-back":Spe,"blazeface-front":Tpe,"blazepose-detector":Cpe,"blazepose-full":Npe,"blazepose-heavy":Epe,"blazepose-lite":Rpe,efficientpose:Mpe,faceboxes:$pe,"facemesh-attention-pinto":_pe,"facemesh-attention":Ppe,"facemesh-detection-full":Fpe,"facemesh-detection-short":Ope,"faceres-deep":Dpe,gear:zpe,"gender-ssrnet-imdb":Lpe,gender:Bpe,handdetect:Wpe,"handlandmark-full":Vpe,"handlandmark-sparse":Upe,handskeleton:Gpe,meet:Hpe,mobileface:jpe,mobilefacenet:qpe,"movenet-multipose":Xpe,"movenet-thunder":Kpe,nanodet:Zpe,posenet:Ype,rvm:Jpe,selfie:Qpe,"anti-spoofing":ece,"efficientpose-i-lite":tce,"efficientpose-ii-lite":ace,"efficientpose-iv":nce,"insightface-efficientnet-b0":rce,"insightface-ghostnet-strides1":sce,"insightface-ghostnet-strides2":ice,"insightface-mobilenet-emore":oce,"insightface-mobilenet-swish":lce,"nanodet-e":uce,"nanodet-g":dce,"nanodet-m":pce,"nanodet-t":cce};var Ea={cacheModels:!0,cacheSupported:!0,verbose:!0,debug:!1,modelBasePath:""},ha={};async function fce(e,t){return Ea.debug&&K("load model fetch:",e,t),fetch(e,t)}function u9(e){Ea.cacheModels=e.cacheModels,Ea.verbose=e.debug,Ea.modelBasePath=e.modelBasePath}async function Ee(e){var u,p,c,d;let t=Q8(Ea.modelBasePath,e||"");t.toLowerCase().endsWith(".json")||(t+=".json");let a=t.includes("/")?t.split("/"):t.split("\\"),n=a[a.length-1].replace(".json",""),r="indexeddb://"+n;ha[n]={name:n,sizeFromManifest:0,sizeLoadedWeights:0,sizeDesired:q3[n],inCache:!1,url:""},Ea.cacheSupported=typeof indexedDB!="undefined";let s={};try{s=Ea.cacheSupported&&Ea.cacheModels?await jn.listModels():{}}catch(h){Ea.cacheSupported=!1}ha[n].inCache=Ea.cacheSupported&&Ea.cacheModels&&Object.keys(s).includes(r),ha[n].url=ha[n].inCache?r:t;let i=typeof fetch=="undefined"?{}:{fetchFunc:(h,f)=>fce(h,f)},o=new op(ha[n].url,i),l=!1;try{o.findIOHandler(),Ea.debug&&K("model load handler:",o.handler)}catch(h){K("error finding model i/o handler:",t,h)}try{let h=await((u=o.handler)==null?void 0:u.load())||null;ha[n].sizeFromManifest=((p=h==null?void 0:h.weightData)==null?void 0:p.byteLength)||0,h?o.loadSync(h):o=await r3(ha[n].inCache?r:t,i),ha[n].sizeLoadedWeights=((d=(c=o.artifacts)==null?void 0:c.weightData)==null?void 0:d.byteLength)||0,Ea.verbose&&K("load:",{model:n,url:o.modelUrl,bytes:ha[n].sizeLoadedWeights}),l=!0}catch(h){K("error loading model:",t,h)}if(l&&Ea.cacheModels&&Ea.cacheSupported&&!ha[n].inCache)try{let h=await o.save(r);Ea.debug&&K("model saved:",r,h)}catch(h){K("error saving model:",t,h)}return o}var X3="3.0.1";var vt={name:"humangl",priority:999,canvas:null,gl:null,extensions:[],webGLattr:{alpha:!1,antialias:!1,premultipliedAlpha:!1,preserveDrawingBuffer:!1,depth:!1,stencil:!1,failIfMajorPerformanceCaveat:!1,desynchronized:!0}};function xce(){let e=vt.gl;!e||(vt.extensions=e.getSupportedExtensions())}function d9(e){var t;if(e.config.backend==="humangl"&&(vt.name in kt().registry&&!((t=vt==null?void 0:vt.gl)!=null&&t.getParameter(vt.gl.VERSION))&&(K("humangl error: backend invalid context"),e.models.reset()),!u2(vt.name))){try{vt.canvas=Nn(100,100)}catch(r){K("humangl error: cannot create canvas:",r);return}try{if(vt.gl=vt.canvas.getContext("webgl2",vt.webGLattr),!vt.gl){K("humangl error: cannot get webgl context");return}if(!vt.gl.getParameter(vt.gl.VERSION).includes("2.0")){K("backend override: using fallback webgl backend as webgl 2.0 is not detected"),e.config.backend="webgl";return}vt.canvas&&(vt.canvas.addEventListener("webglcontextlost",s=>{throw K("humangl error:",s.type),K("possible browser memory leak using webgl or conflict with multiple backend registrations"),e.emit("error"),new Error("backend error: webgl context lost")}),vt.canvas.addEventListener("webglcontextrestored",s=>{K("humangl error: context restored:",s)}),vt.canvas.addEventListener("webglcontextcreationerror",s=>{K("humangl error: context create:",s)}))}catch(r){K("humangl error: cannot get webgl context:",r);return}try{Fh(2,vt.gl)}catch(r){K("humangl error: cannot set webgl context:",r);return}try{let r=new il(vt.gl);go(vt.name,()=>new fu(r),vt.priority)}catch(r){K("humangl error: cannot register webgl backend:",r);return}try{Zn("webgl").forEach(s=>{let i={...s,backendName:vt.name};mn(i)})}catch(r){K("humangl error: cannot update webgl backend registration:",r);return}try{W().flagRegistry.WEBGL_VERSION&&W().set("WEBGL_VERSION",2)}catch(r){K("humangl error: cannot set WebGL backend flags:",r);return}xce();let a=tr(),n=typeof a.gpgpu!="undefined"?a.getGPGPUContext().gl:null;n?e.config.debug&&K("humangl backend registered:",{webgl:n.getParameter(n.VERSION),renderer:n.getParameter(n.RENDERER)}):K("humangl error: no current gl context:",n,vt.gl)}}var ze={tf255:255,tf1:1,tf2:2,tf05:.5,tf127:127.5,rgb:[.2989,.587,.114]};function p9(){ze.tf255=Fe(255,"float32"),ze.tf1=Fe(1,"float32"),ze.tf2=Fe(2,"float32"),ze.tf05=Fe(.5,"float32"),ze.tf127=Fe(127.5,"float32"),ze.rgb=Ht([.2989,.587,.114],"float32")}async function bce(){var e;return await ne.updateBackend(),(e=ne.tensorflow)!=null&&e.version?"tensorflow":ne.webgpu.supported&&ne.webgpu.backend?"webgpu":ne.webgl.supported&&ne.webgl.backend?"webgl":ne.wasm.supported&&ne.wasm.backend?"wasm":"cpu"}function vce(e){let t=[];if(!ne.kernels.includes("mod")){let a={kernelName:"Mod",backendName:ia(),kernelFunc:n=>$e(()=>fe(n.inputs.a,ae(me(n.inputs.a,n.inputs.b),n.inputs.b)))};mn(a),ne.kernels.push("mod"),t.push("mod")}if(!ne.kernels.includes("floormod")){let a={kernelName:"FloorMod",backendName:ia(),kernelFunc:n=>$e(()=>be(ae(Yd(n.inputs.a,n.inputs.b),n.inputs.b),su(n.inputs.a,n.inputs.b)))};mn(a),ne.kernels.push("floormod"),t.push("floormod")}if(!ne.kernels.includes("rotatewithoffset")&&e.softwareKernels){let a={kernelName:"RotateWithOffset",backendName:ia(),kernelFunc:n=>$e(()=>{let r=ia();Xd("cpu");let s=ge.rotateWithOffset(n.inputs.image,n.attrs.radians,n.attrs.fillValue,n.attrs.center);return Xd(r),s})};mn(a),ne.kernels.push("rotatewithoffset"),t.push("rotatewithoffset")}t.length>0&&e.debug&&K("registered kernels:",t)}var c9={};async function wp(e,t=!1){var a;if(e.state="backend",((a=e.config.backend)==null?void 0:a.length)===0&&(e.config.backend=await bce()),t||ne.initial||e.config.backend&&e.config.backend.length>0&&ia()!==e.config.backend){let n=te();if(e.config.backend&&e.config.backend.length>0){if(typeof window=="undefined"&&typeof WorkerGlobalScope!="undefined"&&e.config.debug&&e.config.debug&&K("running inside web worker"),ne.browser&&e.config.backend==="tensorflow"&&(e.config.debug&&K("override: backend set to tensorflow while running in browser"),e.config.backend="webgl"),ne.node&&(e.config.backend==="webgl"||e.config.backend==="humangl")&&(e.config.debug&&K(`override: backend set to ${e.config.backend} while running in nodejs`),e.config.backend="tensorflow"),ne.browser&&e.config.backend==="webgpu")if(typeof navigator=="undefined"||typeof navigator.gpu=="undefined")K("override: backend set to webgpu but browser does not support webgpu"),e.config.backend="webgl";else{let s=await navigator.gpu.requestAdapter();if(e.config.debug&&K("enumerated webgpu adapter:",s),!s)K("override: backend set to webgpu but browser reports no available gpu"),e.config.backend="webgl";else{let i="requestAdapterInfo"in s?await s.requestAdapterInfo():void 0;K("webgpu adapter info:",i)}}let r=Object.keys(kt().registryFactory);if(e.config.backend==="humangl"&&!r.includes("humangl")&&(d9(e),r=Object.keys(kt().registryFactory)),e.config.debug&&K("available backends:",r),r.includes(e.config.backend)||(K(`error: backend ${e.config.backend} not found in registry`),e.config.backend=ne.node?"tensorflow":"webgl",e.config.debug&&K(`override: setting backend ${e.config.backend}`)),e.config.debug&&K("setting backend:",[e.config.backend]),e.config.backend==="wasm"){if(W().flagRegistry.CANVAS2D_WILL_READ_FREQUENTLY&&W().set("CANVAS2D_WILL_READ_FREQUENTLY",!0),e.config.debug&&K("wasm path:",e.config.wasmPath),typeof Wh!="undefined")Wh(e.config.wasmPath,e.config.wasmPlatformFetch);else throw new Error("backend error: attempting to use wasm backend but wasm path is not set");let s=!1,i=!1;try{s=await W().getAsync("WASM_HAS_MULTITHREAD_SUPPORT"),i=await W().getAsync("WASM_HAS_SIMD_SUPPORT"),e.config.debug&&K(`wasm execution: ${i?"simd":"no simd"} ${s?"multithreaded":"singlethreaded"}`),e.config.debug&&!i&&K("warning: wasm simd support is not enabled")}catch(o){K("wasm detection failed")}}try{await Xd(e.config.backend),await Kd()}catch(s){return K("error: cannot set backend:",e.config.backend,s),!1}e.config.debug&&(c9=JSON.parse(JSON.stringify(W().flags)))}if((ia()==="humangl"||ia()==="webgl")&&(W().flagRegistry.WEBGL_USE_SHAPES_UNIFORMS&&W().set("WEBGL_USE_SHAPES_UNIFORMS",!0),W().flagRegistry.WEBGL_EXP_CONV&&W().set("WEBGL_EXP_CONV",!0),e.config.debug&&typeof e.config.deallocate!="undefined"&&e.config.deallocate&&(K("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",!0),W().set("WEBGL_DELETE_TEXTURE_THRESHOLD",0))),ia(),e.config.debug){let r=W().flags,s={};for(let i of Object.keys(r))c9[i]!==r[i]&&(s[i]=r[i]);e.config.debug&&Object.keys(s).length>0&&K("backend:",ia(),"flags:",s)}if(e.config.flags&&Object.keys(e.config.flags).length>0){e.config.debug&&K("flags:",e.config.flags);for(let[r,s]of Object.entries(e.config.flags))W().set(r,s)}o2(),p9(),e.performance.initBackend=Math.trunc(te()-n),e.config.backend=ia(),await ne.updateBackend(),vce(e.config),ne.initial=!1}return!0}function Qh(e,t){for(let a of e){let n={kernelName:a,backendName:t.backend,kernelFunc:r=>{var s;return t.debug&&K("kernelFunc",a,t.backend,r),(s=r==null?void 0:r.inputs)==null?void 0:s.info}};mn(n)}ne.kernels=Zn(ia()).map(a=>a.kernelName.toLowerCase())}var s0={};hr(s0,{all:()=>Jce,body:()=>t0,canvas:()=>Yce,face:()=>e0,gesture:()=>r0,hand:()=>a0,init:()=>tg,object:()=>n0,options:()=>$t,person:()=>Zce});var xn=e=>{if(!e)K("draw error: invalid canvas");else if(!e.getContext)K("draw error: canvas context not defined");else{let t=e.getContext("2d");if(!t)K("draw error: cannot get canvas context");else return t}return null},So=e=>Math.round(e*180/Math.PI),ct=(e,t,a)=>e.replace(t,typeof a=="number"?a.toFixed(1):a),To=(e,t)=>{if(!t.useDepth||typeof e=="undefined")return t.color;let a=Uint8ClampedArray.from([127+2*e,127-2*e,255]);return`rgba(${a[0]}, ${a[1]}, ${a[2]}, ${t.alpha})`};function En(e,t,a,n,r){let s=t.replace(/\[.*\]/g,"").split(` `).map(o=>o.trim()),i=Math.max(0,a);for(let o=s.length-1;o>=0;o--){let l=o*r.lineHeight+n;r.shadowColor&&r.shadowColor!==""&&(e.fillStyle=r.shadowColor,e.fillText(s[o],i+5,l+16)),e.fillStyle=r.labelColor,e.fillText(s[o],i+4,l+15)}}function Nr(e,t,a,n,r){e.fillStyle=To(n,r),e.beginPath(),e.arc(t,a,r.pointSize,0,2*Math.PI),e.fill()}function sr(e,t,a,n,r,s){if(e.beginPath(),e.lineWidth=s.lineWidth,s.useCurves){let i=(t+t+n)/2,o=(a+a+r)/2;e.ellipse(i,o,n/2,r/2,0,0,2*Math.PI)}else e.moveTo(t+s.roundRect,a),e.lineTo(t+n-s.roundRect,a),e.quadraticCurveTo(t+n,a,t+n,a+s.roundRect),e.lineTo(t+n,a+r-s.roundRect),e.quadraticCurveTo(t+n,a+r,t+n-s.roundRect,a+r),e.lineTo(t+s.roundRect,a+r),e.quadraticCurveTo(t,a+r,t,a+r-s.roundRect),e.lineTo(t,a+s.roundRect),e.quadraticCurveTo(t,a,t+s.roundRect,a),e.closePath();e.stroke()}function K3(e,t,a){if(!(t.length<2)){e.beginPath(),e.moveTo(t[0][0],t[0][1]);for(let n of t)e.strokeStyle=To(n[2]||0,a),e.lineTo(Math.trunc(n[0]),Math.trunc(n[1]));e.stroke(),a.fillPolygons&&(e.closePath(),e.fill())}}function f9(e,t,a){if(!(t.length<2)){if(e.lineWidth=a.lineWidth,!a.useCurves||t.length<=2){K3(e,t,a);return}e.moveTo(t[0][0],t[0][1]);for(let n=0;nkp[e]),M2e=kce.map(e=>kp[e]),$2e=Ice.map(e=>kp[e]);function ds(e){let t=e.map(a=>a[0]);return t.push(e[e.length-1][1]),t}var Sce=[[61,146],[146,91],[91,181],[181,84],[84,17],[17,314],[314,405],[405,321],[321,375],[375,291],[61,185],[185,40],[40,39],[39,37],[37,0],[0,267],[267,269],[269,270],[270,409],[409,291],[78,95],[95,88],[88,178],[178,87],[87,14],[14,317],[317,402],[402,318],[318,324],[324,308],[78,191],[191,80],[80,81],[81,82],[82,13],[13,312],[312,311],[311,310],[310,415],[415,308]],Tce=[[263,249],[249,390],[390,373],[373,374],[374,380],[380,381],[381,382],[382,362],[263,466],[466,388],[388,387],[387,386],[386,385],[385,384],[384,398],[398,362]],Cce=[[276,283],[283,282],[282,295],[295,285],[300,293],[293,334],[334,296],[296,336]],Nce=[[474,475],[475,476],[476,477],[477,474]],Ece=[[33,7],[7,163],[163,144],[144,145],[145,153],[153,154],[154,155],[155,133],[33,246],[246,161],[161,160],[160,159],[159,158],[158,157],[157,173],[173,133]],Rce=[[46,53],[53,52],[52,65],[65,55],[70,63],[63,105],[105,66],[66,107]],Mce=[[469,470],[470,471],[471,472],[472,469]],$ce=[[10,338],[338,297],[297,332],[332,284],[284,251],[251,389],[389,356],[356,454],[454,323],[323,361],[361,288],[288,397],[397,365],[365,379],[379,378],[378,400],[400,377],[377,152],[152,148],[148,176],[176,149],[149,150],[150,136],[136,172],[172,58],[58,132],[132,93],[93,234],[234,127],[127,162],[162,21],[21,54],[54,103],[103,67],[67,109],[109,10]],_2e={lips:ds(Sce),leftEye:ds(Tce),leftEyebrow:ds(Cce),leftIris:ds(Nce),rightEye:ds(Ece),rightEyebrow:ds(Rce),rightIris:ds(Mce),faceOval:ds($ce)};var _ce=[[61,146],[146,91],[91,181],[181,84],[84,17],[17,314],[314,405],[405,321],[321,375],[375,291],[61,185],[185,40],[40,39],[39,37],[37,0],[0,267],[267,269],[269,270],[270,409],[409,291],[78,95],[95,88],[88,178],[178,87],[87,14],[14,317],[317,402],[402,318],[318,324],[324,308],[78,191],[191,80],[80,81],[81,82],[82,13],[13,312],[312,311],[311,310],[310,415],[415,308]],Pce=[[263,249],[249,390],[390,373],[373,374],[374,380],[380,381],[381,382],[382,362],[263,466],[466,388],[388,387],[387,386],[386,385],[385,384],[384,398],[398,362]],Fce=[[276,283],[283,282],[282,295],[295,285],[300,293],[293,334],[334,296],[296,336]],Oce=[[474,475],[475,476],[476,477],[477,474]],Dce=[[33,7],[7,163],[163,144],[144,145],[145,153],[153,154],[154,155],[155,133],[33,246],[246,161],[161,160],[160,159],[159,158],[158,157],[157,173],[173,133]],zce=[[46,53],[53,52],[52,65],[65,55],[70,63],[63,105],[105,66],[66,107]],Lce=[[469,470],[470,471],[471,472],[472,469]],Bce=[[10,338],[338,297],[297,332],[332,284],[284,251],[251,389],[389,356],[356,454],[454,323],[323,361],[361,288],[288,397],[397,365],[365,379],[379,378],[378,400],[400,377],[377,152],[152,148],[148,176],[176,149],[149,150],[150,136],[136,172],[172,58],[58,132],[132,93],[93,234],[234,127],[127,162],[162,21],[21,54],[54,103],[103,67],[67,109],[109,10]];function ps(e){let t=e.map(a=>a[0]);return t.push(e[e.length-1][1]),t}var Wce={lips:ps(_ce),leftEye:ps(Pce),leftEyebrow:ps(Fce),leftIris:ps(Oce),rightEye:ps(Dce),rightEyebrow:ps(zce),rightIris:ps(Lce),faceOval:ps(Bce)},Vce=Object.entries(Wce).map(([e,t])=>t.map(a=>[a,e])).flat(),P2e=new Map(Vce),Ip=[61,146,91,181,84,17,314,405,321,375,291,185,40,39,37,0,267,269,270,409,78,95,88,178,87,14,317,402,318,324,308,191,80,81,82,13,312,311,310,415,76,77,90,180,85,16,315,404,320,307,306,184,74,73,72,11,302,303,304,408,62,96,89,179,86,15,316,403,319,325,292,183,42,41,38,12,268,271,272,407],Eo=[33,7,163,144,145,153,154,155,133,246,161,160,159,158,157,173,130,25,110,24,23,22,26,112,243,247,30,29,27,28,56,190,226,31,228,229,230,231,232,233,244,113,225,224,223,222,221,189,35,124,46,53,52,65,143,111,117,118,119,120,121,128,245,156,70,63,105,66,107,55,193],Ro=[263,249,390,373,374,380,381,382,362,466,388,387,386,385,384,398,359,255,339,254,253,252,256,341,463,467,260,259,257,258,286,414,446,261,448,449,450,451,452,453,464,342,445,444,443,442,441,413,265,353,276,283,282,295,372,340,346,347,348,349,350,357,465,383,300,293,334,296,336,285,417];var lt;function Uce(e,t){var n,r,s,i,o,l,u,p,c;if(!lt.drawLabels||((n=lt.faceLabels)==null?void 0:n.length)===0)return;let a=lt.faceLabels.slice();if(e.score&&(a=ct(a,"[score]",100*e.score)),e.gender&&(a=ct(a,"[gender]",e.gender)),e.genderScore&&(a=ct(a,"[genderScore]",100*e.genderScore)),e.age&&(a=ct(a,"[age]",e.age)),e.distance&&(a=ct(a,"[distance]",100*e.distance)),e.real&&(a=ct(a,"[real]",100*e.real)),e.live&&(a=ct(a,"[live]",100*e.live)),e.emotion&&e.emotion.length>0){let d=e.emotion.map(h=>`${Math.trunc(100*h.score)}% ${h.emotion}`);d.length>3&&(d.length=3),a=ct(a,"[emotions]",d.join(" "))}(s=(r=e.rotation)==null?void 0:r.angle)!=null&&s.roll&&(a=ct(a,"[roll]",So(e.rotation.angle.roll))),(o=(i=e.rotation)==null?void 0:i.angle)!=null&&o.yaw&&(a=ct(a,"[yaw]",So(e.rotation.angle.yaw))),(u=(l=e.rotation)==null?void 0:l.angle)!=null&&u.pitch&&(a=ct(a,"[pitch]",So(e.rotation.angle.pitch))),(c=(p=e.rotation)==null?void 0:p.gaze)!=null&&c.bearing&&(a=ct(a,"[gaze]",So(e.rotation.gaze.bearing))),En(t,a,e.box[0],e.box[1],lt)}function Gce(e,t){var a,n,r,s;if(((a=e.annotations)==null?void 0:a.leftEyeIris)&&((n=e.annotations)==null?void 0:n.leftEyeIris[0])){t.strokeStyle=lt.useDepth?"rgba(255, 200, 255, 0.3)":lt.color,t.beginPath();let i=Math.abs(e.annotations.leftEyeIris[3][0]-e.annotations.leftEyeIris[1][0])/2,o=Math.abs(e.annotations.leftEyeIris[4][1]-e.annotations.leftEyeIris[2][1])/2;t.ellipse(e.annotations.leftEyeIris[0][0],e.annotations.leftEyeIris[0][1],i,o,0,0,2*Math.PI),t.stroke(),lt.fillPolygons&&(t.fillStyle=lt.useDepth?"rgba(255, 255, 200, 0.3)":lt.color,t.fill())}if(((r=e.annotations)==null?void 0:r.rightEyeIris)&&((s=e.annotations)==null?void 0:s.rightEyeIris[0])){t.strokeStyle=lt.useDepth?"rgba(255, 200, 255, 0.3)":lt.color,t.beginPath();let i=Math.abs(e.annotations.rightEyeIris[3][0]-e.annotations.rightEyeIris[1][0])/2,o=Math.abs(e.annotations.rightEyeIris[4][1]-e.annotations.rightEyeIris[2][1])/2;t.ellipse(e.annotations.rightEyeIris[0][0],e.annotations.rightEyeIris[0][1],i,o,0,0,2*Math.PI),t.stroke(),lt.fillPolygons&&(t.fillStyle=lt.useDepth?"rgba(255, 255, 200, 0.3)":lt.color,t.fill())}}function Hce(e,t){var a;if(lt.drawGaze&&((a=e.rotation)==null?void 0:a.angle)&&typeof Path2D!="undefined"){t.strokeStyle="pink";let n=e.box[0]+e.box[2]/2-e.box[3]*So(e.rotation.angle.yaw)/90,r=e.box[1]+e.box[3]/2+e.box[2]*So(e.rotation.angle.pitch)/90,s=new Path2D(` M ${e.box[0]+e.box[2]/2} ${e.box[1]} C ${n} ${e.box[1]}, ${n} ${e.box[1]+e.box[3]}, ${e.box[0]+e.box[2]/2} ${e.box[1]+e.box[3]} `),i=new Path2D(` M ${e.box[0]} ${e.box[1]+e.box[3]/2} C ${e.box[0]} ${r}, ${e.box[0]+e.box[2]} ${r}, ${e.box[0]+e.box[2]} ${e.box[1]+e.box[3]/2} `);t.stroke(i),t.stroke(s)}}function jce(e,t){var a;if(lt.drawGaze&&((a=e.rotation)==null?void 0:a.gaze.strength)&&e.rotation.gaze.bearing&&e.annotations.leftEyeIris&&e.annotations.rightEyeIris&&e.annotations.leftEyeIris[0]&&e.annotations.rightEyeIris[0]){t.strokeStyle="pink",t.fillStyle="pink";let n=[e.annotations.leftEyeIris[0][0]+Math.sin(e.rotation.gaze.bearing)*e.rotation.gaze.strength*e.box[3],e.annotations.leftEyeIris[0][1]+Math.cos(e.rotation.gaze.bearing)*e.rotation.gaze.strength*e.box[2]];Z3(t,[e.annotations.leftEyeIris[0][0],e.annotations.leftEyeIris[0][1]],[n[0],n[1]],4);let r=[e.annotations.rightEyeIris[0][0]+Math.sin(e.rotation.gaze.bearing)*e.rotation.gaze.strength*e.box[3],e.annotations.rightEyeIris[0][1]+Math.cos(e.rotation.gaze.bearing)*e.rotation.gaze.strength*e.box[2]];Z3(t,[e.annotations.rightEyeIris[0][0],e.annotations.rightEyeIris[0][1]],[r[0],r[1]],4)}}function qce(e,t){if(lt.drawPolygons&&e.mesh.length>=468){t.lineWidth=1;for(let a=0;ae.mesh[r]);K3(t,n,lt)}Gce(e,t)}}function Xce(e,t){if(lt.drawPoints&&e.mesh.length>=468)for(let a=0;a0&&(Xce(r,n),qce(r,n),Hce(r,n),jce(r,n))}}function t0(e,t,a){var s,i;let n=Ct($t,a);if(!t||!e)return;let r=xn(e);if(!!r){r.lineJoin="round";for(let o=0;o0)){let l=n.bodyLabels.slice();l=ct(l,"[score]",100*t[o].score),En(r,l,t[o].box[0],t[o].box[1],n)}if(n.drawPoints&&t[o].keypoints)for(let l=0;l0&&t[o].keypoints){r.font=n.font;for(let l of t[o].keypoints){if(!l.score||l.score===0)continue;let u=n.bodyPartLabels.slice();u=ct(u,"[label]",l.part),u=ct(u,"[score]",100*l.score),En(r,u,l.position[0],l.position[1],n)}}if(n.drawPolygons&&t[o].keypoints&&t[o].annotations)for(let l of Object.values(t[o].annotations))for(let u of l)f9(r,u,n)}}}function a0(e,t,a){var s,i;let n=Ct($t,a);if(!t||!e)return;let r=xn(e);if(!!r){r.lineJoin="round",r.font=n.font;for(let o of t){if(n.drawBoxes){if(r.strokeStyle=n.color,r.fillStyle=n.color,sr(r,o.box[0],o.box[1],o.box[2],o.box[3],n),n.drawLabels&&((s=n.handLabels)==null?void 0:s.length)>0){let l=n.handLabels.slice();l=ct(l,"[label]",o.label),l=ct(l,"[score]",100*o.score),En(r,l,o.box[0],o.box[1],n)}r.stroke()}if(n.drawPoints&&o.keypoints&&o.keypoints.length>0)for(let l of o.keypoints)r.fillStyle=To(l[2],n),Nr(r,l[0],l[1],0,n);if(n.drawLabels&&o.annotations&&((i=n.fingerLabels)==null?void 0:i.length)>0)for(let[l,u]of Object.entries(o.annotations)){let p=n.fingerLabels.slice();p=ct(p,"[label]",l),En(r,p,u[u.length-1][0],u[u.length-1][1],n)}if(n.drawPolygons&&o.annotations){let l=u=>{if(!(!u||u.length===0||!u[0]))for(let p=0;p0?p-1:0][0],u[p>0?p-1:0][1]),r.lineTo(u[p][0],u[p][1]),r.stroke()}};r.lineWidth=n.lineWidth,l(o.annotations.index),l(o.annotations.middle),l(o.annotations.ring),l(o.annotations.pinky),l(o.annotations.thumb)}}}}function n0(e,t,a){var s;let n=Ct($t,a);if(!t||!e)return;let r=xn(e);if(!!r){r.lineJoin="round",r.font=n.font;for(let i of t)if(n.drawBoxes){if(r.strokeStyle=n.color,r.fillStyle=n.color,sr(r,i.box[0],i.box[1],i.box[2],i.box[3],n),n.drawLabels&&((s=n.objectLabels)==null?void 0:s.length)>0){let o=n.objectLabels.slice();o=ct(o,"[label]",i.label),o=ct(o,"[score]",100*i.score),En(r,o,i.box[0],i.box[1],n)}r.stroke()}}}function r0(e,t,a){var r;let n=Ct($t,a);if(!(!t||!e)&&n.drawGestures&&((r=n.gestureLabels)==null?void 0:r.length)>0){let s=xn(e);if(!s)return;s.font=n.font,s.fillStyle=n.color;let i=1;for(let o=0;o1&&u[1].length>0){let p=l[1]>0?`#${l[1]}`:"",c=n.gestureLabels.slice();c=ct(c,"[where]",l[0]),c=ct(c,"[who]",p),c=ct(c,"[what]",u[1]),En(s,c,8,2+i*n.lineHeight,n),i+=1}}}}var cs={face:`face confidence: [score]% [gender] [genderScore]% age: [age] years distance: [distance]cm real: [real]% live: [live]% [emotions] roll: [roll]\xB0 yaw:[yaw]\xB0 pitch:[pitch]\xB0 gaze: [gaze]\xB0`,body:"body [score]%",bodyPart:"[label] [score]%",object:"[label] [score]%",hand:"[label] [score]%",finger:"[label]",gesture:"[where] [who]: [what]"};var eg=0;function Zce(e,t,a){let n=Ct($t,a);if(!t||!e)return;let r=xn(e);if(!!r){r.lineJoin="round",r.font=n.font;for(let s=0;sng,kpt:()=>ag});var ag=["nose","leftEyeInside","leftEye","leftEyeOutside","rightEyeInside","rightEye","rightEyeOutside","leftEar","rightEar","leftMouth","rightMouth","leftShoulder","rightShoulder","leftElbow","rightElbow","leftWrist","rightWrist","leftPinky","rightPinky","leftIndex","rightIndex","leftThumb","rightThumb","leftHip","rightHip","leftKnee","rightKnee","leftAnkle","rightAnkle","leftHeel","rightHeel","leftFoot","rightFoot","bodyCenter","bodyTop","leftPalm","leftHand","rightPalm","rightHand"],ng={shoulders:["leftShoulder","rightShoulder"],hips:["rightHip","leftHip"],mouth:["leftMouth","rightMouth"],leftLegUpper:["leftHip","leftKnee"],leftLegLower:["leftKnee","leftAnkle"],leftFoot:["leftAnkle","leftHeel","leftFoot"],leftTorso:["leftShoulder","leftHip"],leftArmUpper:["leftShoulder","leftElbow"],leftArmLower:["leftElbow","leftWrist"],leftHand:["leftWrist","leftPalm"],leftHandPinky:["leftPalm","leftPinky"],leftHandIndex:["leftPalm","leftIndex"],leftHandThumb:["leftPalm","leftThumb"],leftEyeOutline:["leftEyeInside","leftEyeOutside"],rightLegUpper:["rightHip","rightKnee"],rightLegLower:["rightKnee","rightAnkle"],rightFoot:["rightAnkle","rightHeel","rightFoot"],rightTorso:["rightShoulder","rightHip"],rightArmUpper:["rightShoulder","rightElbow"],rightArmLower:["rightElbow","rightWrist"],rightHand:["rightWrist","rightPalm"],rightHandPinky:["rightPalm","rightPinky"],rightHandIndex:["rightPalm","rightIndex"],rightHandThumb:["rightPalm","rightThumb"],rightEyeOutline:["rightEyeInside","rightEyeOutside"]};var An,Mo=224,x9,Qce=5,o0=[8,16,32,32,32];function ehe(){let e=[],t=0;for(;ta.x)),y:Ht(e.map(a=>a.y))}}async function A9(e){if(ne.initial&&(An=null),!An&&e.body.detector&&e.body.detector.modelPath){An=await Ee(e.body.detector.modelPath);let t=An!=null&&An.executor?Object.values(An.modelSignature.inputs):void 0;Mo=Array.isArray(t)?parseInt(t[0].tensorShape.dim[1].size):0}else e.debug&&An&&K("cached model:",An.modelUrl);return ehe(),An}var g9=[5,5];function the(e,t){return $e(()=>{let a=ka(e,12,1),n=_e(a[0]),r=_e(a[1]),s=_e(a[2]),i=_e(a[3]);n=be(me(n,Mo),t.x),r=be(me(r,Mo),t.y),s=ae(me(s,Mo),g9[0]),i=ae(me(i,Mo),g9[1]);let o=fe(n,me(s,2)),l=fe(r,me(i,2)),u=be(o,s),p=be(l,i);return sa([o,l,u,p],1)})}async function ahe(e,t,a,n){var u,p;let r=[],s={};s.boxes=the(e,x9),s.scores=Da(t),s.nms=await ge.nonMaxSuppressionAsync(s.boxes,s.scores,1,((u=a.body.detector)==null?void 0:u.minConfidence)||.1,((p=a.body.detector)==null?void 0:p.iouThreshold)||.1);let i=await s.nms.data(),o=await s.scores.data(),l=await s.boxes.array();for(let c of Array.from(i)){let d=o[c],h=l[c],f=[Math.round(h[0]*n[0]),Math.round(h[1]*n[1]),Math.round(h[2]*n[0]),Math.round(h[3]*n[1])],m={score:d,boxRaw:h,box:f};r.push(m)}return Object.keys(s).forEach(c=>Y(s[c])),r}async function y9(e,t,a){let n={};n.res=An==null?void 0:An.execute(e,["Identity"]),n.logitsRaw=Pe(n.res,[0,0,0],[1,-1,1]),n.boxesRaw=Pe(n.res,[0,0,1],[1,-1,-1]),n.logits=_e(n.logitsRaw),n.boxes=_e(n.boxesRaw);let r=await ahe(n.boxes,n.logits,t,a);return Object.keys(n).forEach(s=>Y(n[s])),r}function Er(e,t=[1,1]){let a=[e.map(o=>o[0]),e.map(o=>o[1])],n=[Math.min(...a[0]),Math.min(...a[1])],r=[Math.max(...a[0]),Math.max(...a[1])],s=[n[0],n[1],r[0]-n[0],r[1]-n[1]],i=[s[0]/t[0],s[1]/t[1],s[2]/t[0],s[3]/t[1]];return{box:s,boxRaw:i}}function b9(e,t=[1,1]){let a=[e.map(u=>u[0]),e.map(u=>u[1])],n=[Math.min(...a[0]),Math.min(...a[1])],r=[Math.max(...a[0]),Math.max(...a[1])],s=[(n[0]+r[0])/2,(n[1]+r[1])/2],i=Math.max(s[0]-n[0],s[1]-n[1],-s[0]+r[0],-s[1]+r[1]),o=[Math.trunc(s[0]-i),Math.trunc(s[1]-i),Math.trunc(2*i),Math.trunc(2*i)],l=[o[0]/t[0],o[1]/t[1],o[2]/t[0],o[3]/t[1]];return{box:o,boxRaw:l}}function l0(e,t){let a=[e[2]*t,e[3]*t];return[e[0]-(a[0]-e[2])/2,e[1]-(a[1]-e[3])/2,a[0],a[1]]}var Ba,sg=256,rg=Number.MAX_SAFE_INTEGER,nhe={landmarks:["ld_3d","activation_segmentation","activation_heatmap","world_3d","output_poseflag"],detector:[]},d0=[],hs=[[0,0],[0,0],[0,0],[0,0]],v9=0,w9=e=>1-1/(1+Math.exp(e)),I9=e=>A9(e);async function S9(e){if(ne.initial&&(Ba=null),Ba)e.debug&&K("cached model:",Ba.modelUrl);else{Ba=await Ee(e.body.modelPath);let t=Ba!=null&&Ba.executor?Object.values(Ba.modelSignature.inputs):void 0;sg=Array.isArray(t)?parseInt(t[0].tensorShape.dim[1].size):0}return Ba}function k9(e,t,a){var s,i;let n={};if(!((s=e==null?void 0:e.shape)!=null&&s[1])||!((i=e==null?void 0:e.shape)!=null&&i[2]))return e;let r;if(a&&(n.cropped=ge.cropAndResize(e,[a],[0],[e.shape[1],e.shape[2]])),e.shape[1]!==e.shape[2]){let o=[e.shape[2]>e.shape[1]?Math.trunc((e.shape[2]-e.shape[1])/2):0,e.shape[2]>e.shape[1]?Math.trunc((e.shape[2]-e.shape[1])/2):0],l=[e.shape[1]>e.shape[2]?Math.trunc((e.shape[1]-e.shape[2])/2):0,e.shape[1]>e.shape[2]?Math.trunc((e.shape[1]-e.shape[2])/2):0];hs=[[0,0],o,l,[0,0]],n.pad=rr(n.cropped||e,hs),n.resize=ge.resizeBilinear(n.pad,[t,t]),r=me(n.resize,ze.tf255)}else e.shape[1]!==t?(n.resize=ge.resizeBilinear(n.cropped||e,[t,t]),r=me(n.resize,ze.tf255)):r=me(n.cropped||e,ze.tf255);return Object.keys(n).forEach(o=>Y(n[o])),r}function rhe(e,t,a){for(let n of e)n.position=[Math.trunc(n.position[0]*(t[0]+hs[2][0]+hs[2][1])/t[0]-hs[2][0]),Math.trunc(n.position[1]*(t[1]+hs[1][0]+hs[1][1])/t[1]-hs[1][0]),n.position[2]],n.positionRaw=[n.position[0]/t[0],n.position[1]/t[1],2*n.position[2]/(t[0]+t[1])];if(a){let n=a[2]-a[0],r=a[3]-a[1];for(let s of e)s.positionRaw=[s.positionRaw[0]/r+a[1],s.positionRaw[1]/n+a[0],s.positionRaw[2]],s.position=[Math.trunc(s.positionRaw[0]*t[0]),Math.trunc(s.positionRaw[1]*t[1]),s.positionRaw[2]]}return e}function she(e){let t=e.find(o=>o.part==="leftPalm"),a=e.find(o=>o.part==="leftWrist"),n=e.find(o=>o.part==="leftIndex");t.position[2]=((a.position[2]||0)+(n.position[2]||0))/2;let r=e.find(o=>o.part==="rightPalm"),s=e.find(o=>o.part==="rightWrist"),i=e.find(o=>o.part==="rightIndex");r.position[2]=((s.position[2]||0)+(i.position[2]||0))/2}async function ihe(e,t,a){if(!(Ba!=null&&Ba.executor))return null;let n={};[n.ld,n.segmentation,n.heatmap,n.world,n.poseflag]=Ba==null?void 0:Ba.execute(e,nhe.landmarks);let r=(await n.poseflag.data())[0],s=await n.ld.data(),i=await n.world.data();Object.keys(n).forEach(f=>Y(n[f]));let o=[],l=5;for(let f=0;ff.position),c=Er(p,[a[0],a[1]]),d={};for(let[f,m]of Object.entries(ng)){let g=[];for(let x=0;xb.part===m[x]),y=u.find(b=>b.part===m[x+1]);A&&y&&g.push([A.position,y.position])}d[f]=g}return{id:0,score:Math.trunc(100*r)/100,box:c.box,boxRaw:c.boxRaw,keypoints:u,annotations:d}}async function ig(e,t){var s,i,o;let a=[e.shape[2]||0,e.shape[1]||0],n=(t.body.skipTime||0)>te()-v9,r=rg<(t.body.skipFrames||0);if(t.skipAllowed&&n&&r&&d0!==null)rg++;else{let l=[];if((i=(s=t.body)==null?void 0:s.detector)!=null&&i.enabled){let u=k9(e,224);l=await y9(u,t,a),Y(u)}else l=[{box:[0,0,0,0],boxRaw:[0,0,1,1],score:0}];for(let u=0;uY(n[u])),r}async function ug(e,t){if(!(Wa!=null&&Wa.executor))return[];let a=(t.object.skipTime||0)>te()-C9,n=lg<(t.object.skipFrames||0);return t.skipAllowed&&a&&n&&og.length>0?(lg++,og):(lg=0,new Promise(async r=>{let s=[e.shape[2]||0,e.shape[1]||0],i=ge.resizeBilinear(e,[$o,$o]),o=t.object.enabled?Wa==null?void 0:Wa.execute(i,["tower_0/detections"]):null;C9=te(),Y(i);let l=await ohe(o,s,t);og=l,r(l)}))}var p0={};hr(p0,{connected:()=>pg,kpt:()=>dg});var dg=["head","neck","rightShoulder","rightElbow","rightWrist","chest","leftShoulder","leftElbow","leftWrist","bodyCenter","rightHip","rightKnee","rightAnkle","leftHip","leftKnee","leftAnkle"],pg={leftLeg:["leftHip","leftKnee","leftAnkle"],rightLeg:["rightHip","rightKnee","rightAnkle"],torso:["leftShoulder","rightShoulder","rightHip","leftHip","leftShoulder"],leftArm:["leftShoulder","leftElbow","leftWrist"],rightArm:["rightShoulder","rightElbow","rightWrist"],head:[]};var Nt,R9=0,Ra={id:0,keypoints:[],box:[0,0,0,0],boxRaw:[0,0,0,0],score:0,annotations:{}},cg=Number.MAX_SAFE_INTEGER;async function M9(e){return ne.initial&&(Nt=null),Nt?e.debug&&K("cached model:",Nt.modelUrl):Nt=await Ee(e.body.modelPath),Nt}async function lhe(e,t){let[a,n]=e.shape,r=J(e,[n*a]),s=pa(r,0),i=(await s.data())[0];if(i>t){let o=ar(r,0),l=su(o,a),u=(await l.data())[0],p=me(o,a),c=(await p.data())[0];return Y([r,s,o,l,p]),[u,c,i]}return Y([r,s]),[0,0,i]}async function hg(e,t){if(!(Nt!=null&&Nt.executor)||!(Nt!=null&&Nt.inputs[0].shape))return[];let a=(t.body.skipTime||0)>te()-R9,n=cg<(t.body.skipFrames||0);return t.skipAllowed&&a&&n&&Object.keys(Ra.keypoints).length>0?(cg++,[Ra]):(cg=0,new Promise(async r=>{let s=$e(()=>{var f,m;let c=ge.resizeBilinear(e,[((f=Nt==null?void 0:Nt.inputs[0].shape)==null?void 0:f[2])||0,((m=Nt==null?void 0:Nt.inputs[0].shape)==null?void 0:m[1])||0],!1),d=ae(c,ze.tf2);return fe(d,ze.tf1)}),i;if(t.body.enabled&&(i=Nt==null?void 0:Nt.execute(s)),R9=te(),Y(s),i){Ra.keypoints.length=0;let c=_e(i);Y(i);let d=Ta(c,2);Y(c);for(let h=0;h(t.body.minConfidence||0)&&Ra.keypoints.push({score:Math.round(100*g)/100,part:dg[h],positionRaw:[f/Nt.inputs[0].shape[2],m/Nt.inputs[0].shape[1]],position:[Math.round(e.shape[2]*f/Nt.inputs[0].shape[2]),Math.round(e.shape[1]*m/Nt.inputs[0].shape[1])]})}d.forEach(h=>Y(h))}Ra.score=Ra.keypoints.reduce((c,d)=>d.score>c?d.score:c,0);let o=Ra.keypoints.map(c=>c.position[0]),l=Ra.keypoints.map(c=>c.position[1]);Ra.box=[Math.min(...o),Math.min(...l),Math.max(...o)-Math.min(...o),Math.max(...l)-Math.min(...l)];let u=Ra.keypoints.map(c=>c.positionRaw[0]),p=Ra.keypoints.map(c=>c.positionRaw[1]);Ra.boxRaw=[Math.min(...u),Math.min(...p),Math.max(...u)-Math.min(...u),Math.max(...p)-Math.min(...p)];for(let[c,d]of Object.entries(pg)){let h=[];for(let f=0;fx.part===d[f]),g=Ra.keypoints.find(x=>x.part===d[f+1]);m&&g&&m.score>(t.body.minConfidence||0)&&g.score>(t.body.minConfidence||0)&&h.push([m.position,g.position])}Ra.annotations[c]=h}r([Ra])}))}var vu=e=>[Math.abs(e.endPoint[0]-e.startPoint[0]),Math.abs(e.endPoint[1]-e.startPoint[1])],c0=e=>[e.startPoint[0]+(e.endPoint[0]-e.startPoint[0])/2,e.startPoint[1]+(e.endPoint[1]-e.startPoint[1])/2,1],h0=(e,t)=>e?[Math.trunc(Math.max(0,e.startPoint[0])),Math.trunc(Math.max(0,e.startPoint[1])),Math.trunc(Math.min(t.shape[2]||0,e.endPoint[0])-Math.max(0,e.startPoint[0])),Math.trunc(Math.min(t.shape[1]||0,e.endPoint[1])-Math.max(0,e.startPoint[1]))]:[0,0,0,0],f0=(e,t)=>e?[e.startPoint[0]/(t.shape[2]||0),e.startPoint[1]/(t.shape[1]||0),(e.endPoint[0]-e.startPoint[0])/(t.shape[2]||0),(e.endPoint[1]-e.startPoint[1])/(t.shape[1]||0)]:[0,0,0,0],F9=(e,t)=>{let a=[e.startPoint[0]*t[0],e.startPoint[1]*t[1]],n=[e.endPoint[0]*t[0],e.endPoint[1]*t[1]];return{startPoint:a,endPoint:n,landmarks:e.landmarks,confidence:e.confidence}},fg=(e,t,a)=>{let n=t.shape[1],r=t.shape[2],s=[e.startPoint[1]/n,e.startPoint[0]/r,e.endPoint[1]/n,e.endPoint[0]/r],i=ge.cropAndResize(t,[s],[0],a),o=me(i,ze.tf255);return Y(i),o},m0=(e,t)=>{let a=c0(e),n=vu(e),r=[t*n[0]/2,t*n[1]/2];return{startPoint:[a[0]-r[0],a[1]-r[1]],endPoint:[a[0]+r[0],a[1]+r[1]],landmarks:e.landmarks,confidence:e.confidence}},g0=e=>{let t=c0(e),a=vu(e),n=Math.max(...a)/2;return{startPoint:[Math.round(t[0]-n),Math.round(t[1]-n)],endPoint:[Math.round(t[0]+n),Math.round(t[1]+n)],landmarks:e.landmarks,confidence:e.confidence}},O9=e=>{let t=e.map(n=>n[0]),a=e.map(n=>n[1]);return{startPoint:[Math.min(...t),Math.min(...a)],endPoint:[Math.max(...t),Math.max(...a)],landmarks:e}},mg=[[1,0,0],[0,1,0],[0,0,1]],uhe=e=>e-2*Math.PI*Math.floor((e+Math.PI)/(2*Math.PI)),dhe=(e,t)=>uhe(Math.PI/2-Math.atan2(-(t[1]-e[1]),t[0]-e[0]));var _9=(e,t)=>[[1,0,e],[0,1,t],[0,0,1]],_o=(e,t)=>{let a=0;for(let n=0;n{let a=[];for(let n=0;n{let a=[],n=e.length;for(let r=0;r{let a=Math.cos(e),n=Math.sin(e),r=[[a,-n,0],[n,a,0],[0,0,1]],s=_9(t[0],t[1]),i=P9(s,r),o=_9(-t[0],-t[1]);return P9(i,o)},che=e=>{let t=[[e[0][0],e[1][0]],[e[0][1],e[1][1]]],a=[e[0][2],e[1][2]],n=[-_o(t[0],a),-_o(t[1],a)];return[t[0].concat(n[0]),t[1].concat(n[1]),[0,0,1]]},hhe=(e,t)=>[_o(e,t[0]),_o(e,t[1])];function z9(e){let t=e===192?{strides:[4],anchors:[1]}:{strides:[e/16,e/8],anchors:[2,6]},a=[];for(let n=0;n[s[0]/r*(h[0]-r/2),s[1]/r*(h[1]-r/2),h[2]||0]),o=a&&a!==0&&Math.abs(a)>.2,l=o?D9(a,[0,0]):mg,u=o?i.map(h=>[...hhe(h,l),h[2]]):i,p=o?che(n):mg,c=c0(t),d=[_o(c,p[0]),_o(c,p[1])];return u.map(h=>[Math.trunc(h[0]+d[0]),Math.trunc(h[1]+d[1]),Math.trunc(h[2]||0)])}function B9(e,t,a,n){let r=t.landmarks.length>=Y3.count?Y3.symmetryLine:Co.symmetryLine,s=0,i=mg,o;if(e&&ne.kernels.includes("rotatewithoffset"))if(s=dhe(t.landmarks[r[0]],t.landmarks[r[1]]),s&&s!==0&&Math.abs(s)>.2){let u=c0(t),p=[u[0]/a.shape[2],u[1]/a.shape[1]],c=ge.rotateWithOffset(a,s,0,[p[0],p[1]]);i=D9(-s,u),o=fg(t,c,[n,n]),Y(c)}else o=fg(t,a,[n,n]);else o=fg(t,a,[n,n]);return[s,i,o]}var fhe=e=>{let t=e.map(n=>n[0]),a=e.map(n=>n[1]);return[Math.min(...t)+(Math.max(...t)-Math.min(...t))/2,Math.min(...a)+(Math.max(...a)-Math.min(...a))/2]},W9=(e,t)=>{let a=fhe(e),n=vu(t);return{startPoint:[a[0]-n[0]/2,a[1]-n[1]/2],endPoint:[a[0]+n[0]/2,a[1]+n[1]/2]}};var V9=6,mhe=1.4,Ln,xg=null,fs=0,wu=null,ku=()=>fs;async function U9(e){var t;return ne.initial&&(Ln=null),Ln?e.debug&&K("cached model:",Ln.modelUrl):Ln=await Ee((t=e.face.detector)==null?void 0:t.modelPath),fs=Ln.executor&&Ln.inputs[0].shape?Ln.inputs[0].shape[2]:256,wu=Fe(fs,"int32"),xg=Kn(z9(fs)),Ln}function ghe(e){if(!xg||!wu)return fn([0,0]);let t={};t.boxStarts=Pe(e,[0,1],[-1,2]),t.centers=be(t.boxStarts,xg),t.boxSizes=Pe(e,[0,3],[-1,2]),t.boxSizesNormalized=me(t.boxSizes,wu),t.centersNormalized=me(t.centers,wu),t.halfBoxSize=me(t.boxSizesNormalized,ze.tf2),t.starts=fe(t.centersNormalized,t.halfBoxSize),t.ends=be(t.centersNormalized,t.halfBoxSize),t.startNormalized=ae(t.starts,wu),t.endNormalized=ae(t.ends,wu);let a=ru([t.startNormalized,t.endNormalized],1);return Object.keys(t).forEach(n=>Y(t[n])),a}async function G9(e,t){var o,l,u,p;if(!e||e.isDisposedInternal||e.shape.length!==4||e.shape[1]<1||e.shape[2]<1)return[];let a={};a.resized=ge.resizeBilinear(e,[fs,fs]),a.div=me(a.resized,ze.tf127),a.normalized=fe(a.div,ze.tf05);let n=Ln==null?void 0:Ln.execute(a.normalized);if(Array.isArray(n)&&n.length>2){let c=n.sort((d,h)=>d.size-h.size);a.concat384=at([c[0],c[2]],2),a.concat512=at([c[1],c[3]],2),a.concat=at([a.concat512,a.concat384],1),a.batch=_e(a.concat,[0])}else Array.isArray(n)?a.batch=_e(n[0]):a.batch=_e(n);Y(n),a.boxes=ghe(a.batch),a.logits=Pe(a.batch,[0,0],[-1,1]),a.sigmoid=Da(a.logits),a.scores=_e(a.sigmoid),a.nms=await ge.nonMaxSuppressionAsync(a.boxes,a.scores,((o=t.face.detector)==null?void 0:o.maxDetected)||0,((l=t.face.detector)==null?void 0:l.iouThreshold)||0,((u=t.face.detector)==null?void 0:u.minConfidence)||0);let r=await a.nms.array(),s=[],i=await a.scores.data();for(let c=0;c(((p=t.face.detector)==null?void 0:p.minConfidence)||0)){let h={};h.bbox=Pe(a.boxes,[r[c],0],[1,-1]),h.slice=Pe(a.batch,[r[c],V9-1],[1,-1]),h.squeeze=_e(h.slice),h.landmarks=J(h.squeeze,[V9,-1]);let f=await h.bbox.data(),m={startPoint:[f[0],f[1]],endPoint:[f[2],f[3]],landmarks:await h.landmarks.array(),confidence:d},g=F9(m,[(e.shape[2]||0)/fs,(e.shape[1]||0)/fs]),x=m0(g,t.face.scale||mhe),A=g0(x);s.push(A),Object.keys(h).forEach(y=>Y(h[y]))}}return Object.keys(a).forEach(c=>Y(a[c])),s}var Qa,ms=0,xhe=2.3,Ag=Rn.leftEyeLower0,yg=Rn.rightEyeLower0,Iu={leftBounds:[Ag[0],Ag[Ag.length-1]],rightBounds:[yg[0],yg[yg.length-1]]},Su={upperCenter:3,lowerCenter:4,index:71,numCoordinates:76};async function K9(e){var t,a;return ne.initial&&(Qa=null),Qa?e.debug&&K("cached model:",Qa.modelUrl):Qa=await Ee((t=e.face.iris)==null?void 0:t.modelPath),ms=(Qa==null?void 0:Qa.executor)&&((a=Qa.inputs)==null?void 0:a[0].shape)?Qa.inputs[0].shape[2]:0,ms===-1&&(ms=64),Qa}function x0(e,t,a,n){for(let r=0;r{let t=e[Iu.leftBounds[0]][2],a=e[Iu.rightBounds[0]][2];return t-a},j9=(e,t,a,n,r,s=!1)=>{let i=g0(m0(O9([e[a],e[n]]),xhe)),o=vu(i),l=ge.cropAndResize(t,[[i.startPoint[1]/r,i.startPoint[0]/r,i.endPoint[1]/r,i.endPoint[0]/r]],[0],[ms,ms]);if(s&&ne.kernels.includes("flipleftright")){let u=ge.flipLeftRight(l);Y(l),l=u}return{box:i,boxSize:o,crop:l}},q9=(e,t,a,n=!1)=>{let r=[];for(let s=0;s{let n=e[Rn[`${a}EyeUpper0`][Su.upperCenter]][2],r=e[Rn[`${a}EyeLower0`][Su.lowerCenter]][2],s=(n+r)/2;return t.map((i,o)=>{let l=s;return o===2?l=n:o===4&&(l=r),[i[0],i[1],l]})};async function Z9(e,t,a){if(!(Qa!=null&&Qa.executor))return e;let{box:n,boxSize:r,crop:s}=j9(e,t,Iu.leftBounds[0],Iu.leftBounds[1],a,!0),{box:i,boxSize:o,crop:l}=j9(e,t,Iu.rightBounds[0],Iu.rightBounds[1],a,!0),u=at([s,l]);Y(s),Y(l);let p=Qa.execute(u);Y(u);let c=await p.data();Y(p);let d=c.slice(0,Su.numCoordinates*3),{rawCoords:h,iris:f}=q9(d,n,r,!0),m=c.slice(Su.numCoordinates*3),{rawCoords:g,iris:x}=q9(m,i,o,!1),A=Ahe(e);Math.abs(A)<30?(x0(e,h,"left",null),x0(e,g,"right",null)):A<1?x0(e,h,"left",["EyeUpper0","EyeLower0"]):x0(e,g,"right",["EyeUpper0","EyeLower0"]);let y=X9(e,f,"left"),b=X9(e,x,"right");return e.concat(y).concat(b)}async function J9(e,t){var s,i,o,l,u,p,c,d,h,f;let a={lips:await((i=(s=t.filter(m=>m.size===160))==null?void 0:s[0])==null?void 0:i.data()),irisL:await((l=(o=t.filter(m=>m.size===10))==null?void 0:o[0])==null?void 0:l.data()),eyeL:await((p=(u=t.filter(m=>m.size===142))==null?void 0:u[0])==null?void 0:p.data()),irisR:await((d=(c=t.filter(m=>m.size===10))==null?void 0:c[1])==null?void 0:d.data()),eyeR:await((f=(h=t.filter(m=>m.size===142))==null?void 0:h[1])==null?void 0:f.data())};for(let m of Object.values(a))if(!m)return e;let n=Eo.reduce((m,g)=>m+=e[g][2],0)/Eo.length;for(let m=0;mm+=e[g][2],0)/Ro.length;for(let m=0;mte()-ir.timestamp,n=ir.skipped<(((u=t.face.detector)==null?void 0:u.skipFrames)||0);!t.skipAllowed||!a||!n||ir.boxes.length===0?(ir.boxes=await G9(e,t),ir.timestamp=te(),ir.skipped=0):ir.skipped++;let r=[],s=[],i=0,o=Sp;for(let A=0;A$.shape[$.shape.length-1]===1).data();if(S.faceScore=Math.round(100*_[0])/100,S.faceScore<(((f=t.face.detector)==null?void 0:f.minConfidence)||1)){if(y.confidence=S.faceScore,t.face.mesh.keepInvalid){S.box=h0(y,e),S.boxRaw=f0(y,e),S.score=S.boxScore,S.mesh=y.landmarks.map($=>[(y.startPoint[0]+y.endPoint[0])/2+(y.endPoint[0]+y.startPoint[0])*$[0]/ku(),(y.startPoint[1]+y.endPoint[1])/2+(y.endPoint[1]+y.startPoint[1])*$[1]/ku()]),S.meshRaw=S.mesh.map($=>[$[0]/(e.shape[2]||1),$[1]/(e.shape[1]||1),($[2]||0)/o]);for(let $ of Object.keys(Co))S.annotations[$]=[S.mesh[Co[$]]]}}else{let $=C.find(O=>O.shape[O.shape.length-1]===1404),M=J($,[-1,3]),I=await M.array();Y(M),(m=t.face.attention)!=null&&m.enabled?I=await J9(I,C):(g=t.face.iris)!=null&&g.enabled&&(I=await Z9(I,S.tensor,Sp)),S.mesh=L9(I,y,b,w,Sp),S.meshRaw=S.mesh.map(O=>[O[0]/(e.shape[2]||0),O[1]/(e.shape[1]||0),(O[2]||0)/o]);for(let O of Object.keys(Rn))S.annotations[O]=Rn[O].map(L=>S.mesh[L]);S.score=S.faceScore;let N={...W9(S.mesh,y),confidence:y.confidence,landmarks:y.landmarks};S.box=h0(N,e),S.boxRaw=f0(N,e),s.push(N)}Y(C)}else{S.box=h0(y,e),S.boxRaw=f0(y,e),S.score=S.boxScore,S.mesh=y.landmarks.map(C=>[(y.startPoint[0]+y.endPoint[0])/2+(y.endPoint[0]+y.startPoint[0])*C[0]/ku(),(y.startPoint[1]+y.endPoint[1])/2+(y.endPoint[1]+y.startPoint[1])*C[1]/ku()]),S.meshRaw=S.mesh.map(C=>[C[0]/(e.shape[2]||0),C[1]/(e.shape[1]||0),(C[2]||0)/o]);for(let C of Object.keys(Co))S.annotations[C]=[S.mesh[Co[C]]]}S.score>(((x=t.face.detector)==null?void 0:x.minConfidence)||1)?r.push(S):Y(S.tensor)}return ir.boxes=s,r}async function ew(e){var t,a,n,r,s,i;return ne.initial&&(wt=null),((t=e.face.attention)==null?void 0:t.enabled)&&(wt==null?void 0:wt.signature)&&Object.keys(((a=wt==null?void 0:wt.signature)==null?void 0:a.outputs)||{}).length<6&&(wt=null),wt?e.debug&&K("cached model:",wt.modelUrl):(n=e.face.attention)!=null&&n.enabled?wt=await Ee(e.face.attention.modelPath):wt=await Ee((r=e.face.mesh)==null?void 0:r.modelPath),Sp=wt.executor&&((s=wt==null?void 0:wt.inputs)==null?void 0:s[0].shape)?(i=wt==null?void 0:wt.inputs)==null?void 0:i[0].shape[2]:256,wt}var tw=No,aw=kp;var bhe=["angry","disgust","fear","happy","sad","surprise","neutral"],yn,A0=[],nw=0,rw=0,vg=Number.MAX_SAFE_INTEGER;async function sw(e){var t;return ne.initial&&(yn=null),yn?e.debug&&K("cached model:",yn.modelUrl):yn=await Ee((t=e.face.emotion)==null?void 0:t.modelPath),yn}async function wg(e,t,a,n){var i,o;if(!yn)return[];let r=vg<(((i=t.face.emotion)==null?void 0:i.skipFrames)||0),s=(((o=t.face.emotion)==null?void 0:o.skipTime)||0)>te()-rw;return t.skipAllowed&&s&&r&&nw===n&&A0[a]&&A0[a].length>0?(vg++,A0[a]):(vg=0,new Promise(async l=>{var p;let u=[];if((p=t.face.emotion)!=null&&p.enabled){let c={},d=yn!=null&&yn.inputs[0].shape?yn.inputs[0].shape[2]:0;c.resize=ge.resizeBilinear(e,[d,d],!1),c.channels=ae(c.resize,ze.rgb),c.grayscale=tt(c.channels,3,!0),c.grayscaleSub=fe(c.grayscale,ze.tf05),c.grayscaleMul=ae(c.grayscaleSub,ze.tf2),c.emotion=yn==null?void 0:yn.execute(c.grayscaleMul),rw=te();let h=await c.emotion.data();for(let f=0;f(t.face.emotion.minConfidence||0)&&u.push({score:Math.min(.99,Math.trunc(100*h[f])/100),emotion:bhe[f]});u.sort((f,m)=>m.score-f.score),Object.keys(c).forEach(f=>Y(c[f]))}A0[a]=u,nw=n,l(u)}))}var fa,gs=[],ow=0,lw=0,kg=Number.MAX_SAFE_INTEGER;async function uw(e){var t;return ne.initial&&(fa=null),fa?e.debug&&K("cached model:",fa.modelUrl):fa=await Ee((t=e.face.description)==null?void 0:t.modelPath),fa}function vhe(e){let t=e.image||e.tensor||e;if(!(fa!=null&&fa.inputs[0].shape))return t;let a=ge.resizeBilinear(t,[fa.inputs[0].shape[2],fa.inputs[0].shape[1]],!1),n=ae(a,ze.tf255);return Y(a),n}async function Ig(e,t,a,n){var o,l,u,p;let r={age:0,gender:"unknown",genderScore:0,descriptor:[]};if(!(fa!=null&&fa.executor))return r;let s=kg<(((o=t.face.description)==null?void 0:o.skipFrames)||0),i=(((l=t.face.description)==null?void 0:l.skipTime)||0)>te()-ow;return t.skipAllowed&&s&&i&&lw===n&&((u=gs==null?void 0:gs[a])==null?void 0:u.age)>0&&((p=gs==null?void 0:gs[a])==null?void 0:p.genderScore)>0?(kg++,gs[a]):(kg=0,new Promise(async c=>{var d;if((d=t.face.description)!=null&&d.enabled){let h=vhe(e),f=fa==null?void 0:fa.execute(h);ow=te(),Y(h);let g=await f.find(E=>E.shape[1]===1).data(),x=Math.trunc(200*Math.abs(g[0]-.5))/100;x>(t.face.description.minConfidence||0)&&(r.gender=g[0]<=.5?"female":"male",r.genderScore=Math.min(.99,x));let A=ar(f.find(E=>E.shape[1]===100),1),y=(await A.data())[0];Y(A);let w=await f.find(E=>E.shape[1]===100).data();r.age=Math.round(w[y-1]>w[y+1]?10*y-100*w[y-1]:10*y+100*w[y+1])/10,(Number.isNaN(g[0])||Number.isNaN(w[0]))&&K("faceres error:",{model:fa,result:f});let S=f.find(E=>E.shape[1]===1024),C=S?await S.data():[];r.descriptor=Array.from(C),f.forEach(E=>Y(E))}gs[a]=r,lw=n,c(r)}))}var Tu=.1,Sg=.5;function whe(e,t,a){let n=!1,r=a.length-1;for(let s=0;st!=a[r].y>t&&e<(a[r].x-a[s].x)*(t-a[s].y)/(a[r].y-a[s].y)+a[s].x&&(n=!n);return n}async function pw(e){if(!e.tensor||!e.mesh||e.mesh.length<100)return e.tensor;let t=e.tensor.shape[2]||0,a=e.tensor.shape[1]||0,n=await e.tensor.buffer(),r=[];for(let i of Rn.silhouette)r.push({x:(e.mesh[i][0]-e.box[0])/e.box[2],y:(e.mesh[i][1]-e.box[1])/e.box[3]});Tu&&Tu>0&&(r=r.map(i=>({x:i.x>.5?i.x+Tu:i.x-Tu,y:i.y>.5?i.y+Tu:i.y-Tu})));for(let i=0;ite()-hw,s=Tg<(((o=t.face.antispoof)==null?void 0:o.skipFrames)||0);return t.skipAllowed&&r&&s&&cw===n&&y0[a]?(Tg++,y0[a]):(Tg=0,new Promise(async l=>{let u=ge.resizeBilinear(e,[ea!=null&&ea.inputs[0].shape?ea.inputs[0].shape[2]:0,ea!=null&&ea.inputs[0].shape?ea.inputs[0].shape[1]:0],!1),p=ea==null?void 0:ea.execute(u),c=(await p.data())[0];y0[a]=Math.round(100*c)/100,cw=n,hw=te(),Y([u,p]),l(y0[a])}))}var ta,b0=[],Ng=Number.MAX_SAFE_INTEGER,gw=0,xw=0;async function Aw(e){var t;return ne.initial&&(ta=null),ta?e.debug&&K("cached model:",ta.modelUrl):ta=await Ee((t=e.face.liveness)==null?void 0:t.modelPath),ta}async function Eg(e,t,a,n){var i,o;if(!(ta!=null&&ta.executor))return 0;let r=(((i=t.face.liveness)==null?void 0:i.skipTime)||0)>te()-xw,s=Ng<(((o=t.face.liveness)==null?void 0:o.skipFrames)||0);return t.skipAllowed&&r&&s&&gw===n&&b0[a]?(Ng++,b0[a]):(Ng=0,new Promise(async l=>{let u=ge.resizeBilinear(e,[ta!=null&&ta.inputs[0].shape?ta.inputs[0].shape[2]:0,ta!=null&&ta.inputs[0].shape?ta.inputs[0].shape[1]:0],!1),p=ta==null?void 0:ta.execute(u),c=(await p.data())[0];b0[a]=Math.round(100*c)/100,gw=n,xw=te(),Y([u,p]),l(b0[a])}))}var Mn,Rg=[],Ihe=["white","black","asian","indian","other"],She=[15,23,28,35.5,45.5,55.5,65],bw=0,vw=0,Mg=Number.MAX_SAFE_INTEGER;async function ww(e){var t;return ne.initial&&(Mn=null),Mn?e.debug&&K("cached model:",Mn.modelUrl):Mn=await Ee((t=e.face.gear)==null?void 0:t.modelPath),Mn}async function $g(e,t,a,n){var i,o;if(!Mn)return{age:0,gender:"unknown",genderScore:0,race:[]};let r=Mg<(((i=t.face.gear)==null?void 0:i.skipFrames)||0),s=(((o=t.face.gear)==null?void 0:o.skipTime)||0)>te()-vw;return t.skipAllowed&&s&&r&&bw===n&&Rg[a]?(Mg++,Rg[a]):(Mg=0,new Promise(async l=>{var x,A;if(!(Mn!=null&&Mn.inputs[0].shape))return;let u={},p=[[0,.1,.9,.9]];u.resize=ge.cropAndResize(e,p,[0],[Mn.inputs[0].shape[2],Mn.inputs[0].shape[1]]);let c={age:0,gender:"unknown",genderScore:0,race:[]};(x=t.face.gear)!=null&&x.enabled&&([u.age,u.gender,u.race]=Mn.execute(u.resize,["age_output","gender_output","race_output"]));let d=await u.gender.data();c.gender=d[0]>d[1]?"male":"female",c.genderScore=Math.round(100*(d[0]>d[1]?d[0]:d[1]))/100;let h=await u.race.data();for(let y=0;y(((A=t.face.gear)==null?void 0:A.minConfidence)||.2)&&c.race.push({score:Math.round(100*h[y])/100,race:Ihe[y]});c.race.sort((y,b)=>b.score-y.score);let m=Array.from(await u.age.data()).map((y,b)=>[She[b],y]).sort((y,b)=>b[1]-y[1]),g=m[0][0];for(let y=1;yY(u[y])),Rg[a]=c,bw=n,vw=te(),l(c)}))}var en,v0=[],Iw=0,Sw=0,_g=Number.MAX_SAFE_INTEGER;async function Tw(e){return ne.initial&&(en=null),en?e.debug&&K("cached model:",en.modelUrl):en=await Ee(e.face.ssrnet.modelPathAge),en}async function Pg(e,t,a,n){var i,o,l,u;if(!en)return{age:0};let r=_g<(((i=t.face.ssrnet)==null?void 0:i.skipFrames)||0),s=(((o=t.face.ssrnet)==null?void 0:o.skipTime)||0)>te()-Sw;return t.skipAllowed&&r&&s&&Iw===n&&((l=v0[a])==null?void 0:l.age)&&((u=v0[a])==null?void 0:u.age)>0?(_g++,v0[a]):(_g=0,new Promise(async p=>{var h;if(!(en!=null&&en.inputs)||!en.inputs[0]||!en.inputs[0].shape)return;let c={};c.resize=ge.resizeBilinear(e,[en.inputs[0].shape[2],en.inputs[0].shape[1]],!1),c.enhance=ae(c.resize,ze.tf255);let d={age:0};if((h=t.face.ssrnet)!=null&&h.enabled&&(c.age=en.execute(c.enhance)),c.age){let f=await c.age.data();d.age=Math.trunc(10*f[0])/10}Object.keys(c).forEach(f=>Y(c[f])),v0[a]=d,Iw=n,Sw=te(),p(d)}))}var $n,w0=[],Nw=0,Ew=0,Fg=Number.MAX_SAFE_INTEGER,Og=[.2989,.587,.114];async function Rw(e){var t;return ne.initial&&($n=null),$n?e.debug&&K("cached model:",$n.modelUrl):$n=await Ee((t=e.face.ssrnet)==null?void 0:t.modelPathGender),$n}async function Dg(e,t,a,n){var i,o,l,u;if(!$n)return{gender:"unknown",genderScore:0};let r=Fg<(((i=t.face.ssrnet)==null?void 0:i.skipFrames)||0),s=(((o=t.face.ssrnet)==null?void 0:o.skipTime)||0)>te()-Ew;return t.skipAllowed&&r&&s&&Nw===n&&((l=w0[a])==null?void 0:l.gender)&&((u=w0[a])==null?void 0:u.genderScore)>0?(Fg++,w0[a]):(Fg=0,new Promise(async p=>{var f;if(!($n!=null&&$n.inputs[0].shape))return;let c={};c.resize=ge.resizeBilinear(e,[$n.inputs[0].shape[2],$n.inputs[0].shape[1]],!1),c.enhance=$e(()=>{let[m,g,x]=ka(c.resize,3,3),A=ae(m,Og[0]),y=ae(g,Og[1]),b=ae(x,Og[2]),w=ch([A,y,b]);return ae(fe(w,ze.tf05),2)});let d={gender:"unknown",genderScore:0};(f=t.face.ssrnet)!=null&&f.enabled&&(c.gender=$n.execute(c.enhance));let h=await c.gender.data();d.gender=h[0]>h[1]?"female":"male",d.genderScore=h[0]>h[1]?Math.trunc(100*h[0])/100:Math.trunc(100*h[1])/100,Object.keys(c).forEach(m=>Y(c[m])),w0[a]=d,Nw=n,Ew=te(),p(d)}))}var tn,zg=[],$w=0,_w=0,Pw=Number.MAX_SAFE_INTEGER;async function Fw(e){var t;return ne.initial&&(tn=null),tn?e.debug&&K("cached model:",tn.modelUrl):tn=await Ee((t=e.face.mobilefacenet)==null?void 0:t.modelPath),tn}async function Lg(e,t,a,n){var i,o;if(!(tn!=null&&tn.executor))return[];let r=Pw<(((i=t.face.mobilefacenet)==null?void 0:i.skipFrames)||0),s=(((o=t.face.mobilefacenet)==null?void 0:o.skipTime)||0)>te()-_w;return t.skipAllowed&&s&&r&&$w===n&&zg[a]?(Pw++,zg[a]):new Promise(async l=>{var p;let u=[];if(((p=t.face.mobilefacenet)==null?void 0:p.enabled)&&(tn==null?void 0:tn.inputs[0].shape)){let c={};c.crop=ge.resizeBilinear(e,[tn.inputs[0].shape[2],tn.inputs[0].shape[1]],!1),c.data=tn.execute(c.crop);let d=await c.data.data();u=Array.from(d),Object.keys(c).forEach(h=>Y(c[h]))}zg[a]=u,$w=n,_w=te(),l(u)})}var an,Bg=[],Dw=0,zw=0,Lw=Number.MAX_SAFE_INTEGER;async function Bw(e){return ne.initial&&(an=null),an?e.debug&&K("cached model:",an.modelUrl):an=await Ee(e.face.insightface.modelPath),an}async function Wg(e,t,a,n){var i,o;if(!(an!=null&&an.executor))return[];let r=Lw<(((i=t.face.insightface)==null?void 0:i.skipFrames)||0),s=(((o=t.face.insightface)==null?void 0:o.skipTime)||0)>te()-zw;return t.skipAllowed&&s&&r&&Dw===n&&Bg[a]?(Lw++,Bg[a]):new Promise(async l=>{var p;let u=[];if(((p=t.face.insightface)==null?void 0:p.enabled)&&(an==null?void 0:an.inputs[0].shape)){let c={};c.crop=ge.resizeBilinear(e,[an.inputs[0].shape[2],an.inputs[0].shape[1]],!1),c.data=an.execute(c.crop);let d=await c.data.data();u=Array.from(d),Object.keys(c).forEach(h=>Y(c[h]))}Bg[a]=u,Dw=n,zw=te(),l(u)})}var The=e=>{let t=(c,d)=>Math.atan2(c[1]-d[1],c[0]-d[0]);if(!e.annotations.rightEyeIris||!e.annotations.leftEyeIris)return{bearing:0,strength:0};let a=[0,-.1],n=1,r=(e.mesh[33][2]||0)>(e.mesh[263][2]||0),s=r?e.mesh[473]:e.mesh[468],i=r?[(e.mesh[133][0]+e.mesh[33][0])/2,(e.mesh[133][1]+e.mesh[33][1])/2]:[(e.mesh[263][0]+e.mesh[362][0])/2,(e.mesh[263][1]+e.mesh[362][1])/2],o=r?[e.mesh[133][0]-e.mesh[33][0],e.mesh[23][1]-e.mesh[27][1]]:[e.mesh[263][0]-e.mesh[362][0],e.mesh[253][1]-e.mesh[257][1]],l=[(i[0]-s[0])/o[0]-a[0],n*(s[1]-i[1])/o[1]-a[1]],u=Math.sqrt(l[0]*l[0]+l[1]*l[1]);return u=Math.min(u,e.boxRaw[2]/2,e.boxRaw[3]/2),{bearing:(t([0,0],l)+Math.PI/2)%Math.PI,strength:u}},Vw=(e,t)=>{let a=m=>{let g=Math.sqrt(m[0]*m[0]+m[1]*m[1]+m[2]*m[2]);return m[0]/=g,m[1]/=g,m[2]/=g,m},n=(m,g)=>{let x=m[0]-g[0],A=m[1]-g[1],y=m[2]-g[2];return[x,A,y]},r=(m,g)=>{let x=m[1]*g[2]-m[2]*g[1],A=m[2]*g[0]-m[0]*g[2],y=m[0]*g[1]-m[1]*g[0];return[x,A,y]},s=m=>{let[g,x,A,y,b,w,S,C,E]=m,_,$,M;return y<1?y>-1?(M=Math.asin(y),$=Math.atan2(-S,g),_=Math.atan2(-w,b)):(M=-Math.PI/2,$=-Math.atan2(C,E),_=0):(M=Math.PI/2,$=Math.atan2(C,E),_=0),Number.isNaN(_)&&(_=0),Number.isNaN($)&&($=0),Number.isNaN(M)&&(M=0),{pitch:2*-_,yaw:2*-$,roll:2*-M}},i=e.meshRaw;if(!i||i.length<300)return{angle:{pitch:0,yaw:0,roll:0},matrix:[1,0,0,0,1,0,0,0,1],gaze:{bearing:0,strength:0}};let o=Math.max(e.boxRaw[2]*t[0],e.boxRaw[3]*t[1])/1.5,l=[i[10],i[152],i[234],i[454]].map(m=>[m[0]*t[0]/o,m[1]*t[1]/o,m[2]]),u=a(n(l[1],l[0])),p=a(n(l[3],l[2])),c=a(r(p,u));p=r(u,c);let d=[p[0],p[1],p[2],u[0],u[1],u[2],c[0],c[1],c[2]],h=s(d),f=i.length===478?The(e):{bearing:0,strength:0};return{angle:h,matrix:d,gaze:f}};function Uw(e,t){let a=e==null?void 0:e.annotations;if(!a)return 0;let n=Math.max(Math.abs(a.leftEyeIris[3][0]-a.leftEyeIris[1][0]),Math.abs(a.rightEyeIris[3][0]-a.rightEyeIris[1][0]))/t;return Math.round(1.17/n)/100}var Vg=async(e,t)=>{var f,m,g,x,A,y,b,w,S,C,E,_,$,M,I,N,O,L,B,G,j,U,H;let a=te(),n,r,s,i,o,l,u,p,c,d=[];e.state="run:face";let h=await Q9(t,e.config);if(e.performance.face=ne.perfadd?(e.performance.face||0)+Math.trunc(te()-a):Math.trunc(te()-a),!t.shape||t.shape.length!==4)return[];if(!h)return[];for(let V=0;V200?Vw(h[V],[t.shape[2],t.shape[1]]):null;e.analyze("Start Emotion:"),e.config.async?i=(m=e.config.face.emotion)!=null&&m.enabled?wg(h[V].tensor||Be([]),e.config,V,h.length):[]:(e.state="run:emotion",a=te(),i=(g=e.config.face.emotion)!=null&&g.enabled?await wg(h[V].tensor||Be([]),e.config,V,h.length):[],e.performance.emotion=ne.perfadd?(e.performance.emotion||0)+Math.trunc(te()-a):Math.trunc(te()-a)),e.analyze("End Emotion:"),e.analyze("Start AntiSpoof:"),e.config.async?u=(x=e.config.face.antispoof)!=null&&x.enabled?Cg(h[V].tensor||Be([]),e.config,V,h.length):0:(e.state="run:antispoof",a=te(),u=(A=e.config.face.antispoof)!=null&&A.enabled?await Cg(h[V].tensor||Be([]),e.config,V,h.length):0,e.performance.antispoof=ne.perfadd?(e.performance.antispoof||0)+Math.trunc(te()-a):Math.trunc(te()-a)),e.analyze("End AntiSpoof:"),e.analyze("Start Liveness:"),e.config.async?p=(y=e.config.face.liveness)!=null&&y.enabled?Eg(h[V].tensor||Be([]),e.config,V,h.length):0:(e.state="run:liveness",a=te(),p=(b=e.config.face.liveness)!=null&&b.enabled?await Eg(h[V].tensor||Be([]),e.config,V,h.length):0,e.performance.liveness=ne.perfadd?(e.performance.antispoof||0)+Math.trunc(te()-a):Math.trunc(te()-a)),e.analyze("End Liveness:"),e.analyze("Start GEAR:"),e.config.async?r=(w=e.config.face.gear)!=null&&w.enabled?$g(h[V].tensor||Be([]),e.config,V,h.length):null:(e.state="run:gear",a=te(),r=(S=e.config.face.gear)!=null&&S.enabled?await $g(h[V].tensor||Be([]),e.config,V,h.length):null,e.performance.gear=Math.trunc(te()-a)),e.analyze("End GEAR:"),e.analyze("Start SSRNet:"),e.config.async?(n=(C=e.config.face.ssrnet)!=null&&C.enabled?Pg(h[V].tensor||Be([]),e.config,V,h.length):null,s=(E=e.config.face.ssrnet)!=null&&E.enabled?Dg(h[V].tensor||Be([]),e.config,V,h.length):null):(e.state="run:ssrnet",a=te(),n=(_=e.config.face.ssrnet)!=null&&_.enabled?await Pg(h[V].tensor||Be([]),e.config,V,h.length):null,s=($=e.config.face.ssrnet)!=null&&$.enabled?await Dg(h[V].tensor||Be([]),e.config,V,h.length):null,e.performance.ssrnet=Math.trunc(te()-a)),e.analyze("End SSRNet:"),e.analyze("Start MobileFaceNet:"),e.config.async?o=(M=e.config.face.mobilefacenet)!=null&&M.enabled?Lg(h[V].tensor||Be([]),e.config,V,h.length):null:(e.state="run:mobilefacenet",a=te(),o=(I=e.config.face.mobilefacenet)!=null&&I.enabled?await Lg(h[V].tensor||Be([]),e.config,V,h.length):null,e.performance.mobilefacenet=Math.trunc(te()-a)),e.analyze("End MobileFaceNet:"),e.analyze("Start InsightFace:"),e.config.async?l=(N=e.config.face.insightface)!=null&&N.enabled?Wg(h[V].tensor||Be([]),e.config,V,h.length):null:(e.state="run:mobilefacenet",a=te(),l=(O=e.config.face.insightface)!=null&&O.enabled?await Wg(h[V].tensor||Be([]),e.config,V,h.length):null,e.performance.mobilefacenet=Math.trunc(te()-a)),e.analyze("End InsightFace:"),e.analyze("Start Description:"),e.config.async?c=Ig(h[V].tensor||Be([]),e.config,V,h.length):(e.state="run:description",a=te(),c=await Ig(h[V].tensor||Be([]),e.config,V,h.length),e.performance.description=ne.perfadd?(e.performance.description||0)+Math.trunc(te()-a):Math.trunc(te()-a)),e.analyze("End Description:"),e.config.async&&([n,s,i,o,l,c,r,u,p]=await Promise.all([n,s,i,o,l,c,r,u,p])),e.analyze("Finish Face:"),((L=e.config.face.ssrnet)==null?void 0:L.enabled)&&n&&s&&(c={...c,age:n.age,gender:s.gender,genderScore:s.genderScore}),((B=e.config.face.gear)==null?void 0:B.enabled)&&r&&(c={...c,age:r.age,gender:r.gender,genderScore:r.genderScore,race:r.race}),((G=e.config.face.mobilefacenet)==null?void 0:G.enabled)&&o&&(c.descriptor=o),((j=e.config.face.insightface)==null?void 0:j.enabled)&&l&&(c.descriptor=l);let Z=(U=e.config.face.iris)!=null&&U.enabled?Uw(h[V],t.shape[2]):0,re=(H=e.config.face.detector)!=null&&H.return?_e(h[V].tensor):null;Y(h[V].tensor),h[V].tensor&&delete h[V].tensor;let ee={...h[V],id:V};c.age&&(ee.age=c.age),c.gender&&(ee.gender=c.gender),c.genderScore&&(ee.genderScore=c.genderScore),c.descriptor&&(ee.embedding=c.descriptor),c.race&&(ee.race=c.race),i&&(ee.emotion=i),u&&(ee.real=u),p&&(ee.live=p),Z>0&&(ee.distance=Z),Q&&(ee.rotation=Q),re&&(ee.tensor=re),d.push(ee),e.analyze("End Face")}return e.analyze("End FaceMesh:"),e.config.async&&(e.performance.face&&delete e.performance.face,e.performance.age&&delete e.performance.age,e.performance.gender&&delete e.performance.gender,e.performance.emotion&&delete e.performance.emotion),d};var Ma={thumb:0,index:1,middle:2,ring:3,pinky:4,all:[0,1,2,3,4],nameMapping:{0:"thumb",1:"index",2:"middle",3:"ring",4:"pinky"},pointsMapping:{0:[[0,1],[1,2],[2,3],[3,4]],1:[[0,5],[5,6],[6,7],[7,8]],2:[[0,9],[9,10],[10,11],[11,12]],3:[[0,13],[13,14],[14,15],[15,16]],4:[[0,17],[17,18],[18,19],[19,20]]},getName:e=>Ma.nameMapping[e],getPoints:e=>Ma.pointsMapping[e]},As={none:0,half:1,full:2,nameMapping:{0:"none",1:"half",2:"full"},getName:e=>As.nameMapping[e]},Et={verticalUp:0,verticalDown:1,horizontalLeft:2,horizontalRight:3,diagonalUpRight:4,diagonalUpLeft:5,diagonalDownRight:6,diagonalDownLeft:7,nameMapping:{0:"verticalUp",1:"verticalDown",2:"horizontalLeft",3:"horizontalRight",4:"diagonalUpRight",5:"diagonalUpLeft",6:"diagonalDownRight",7:"diagonalDownLeft"},getName:e=>Et.nameMapping[e]},xs=class{constructor(t){ue(this,"name");ue(this,"curls");ue(this,"directions");ue(this,"weights");ue(this,"weightsRelative");this.name=t,this.curls={},this.directions={},this.weights=[1,1,1,1,1],this.weightsRelative=[1,1,1,1,1]}curl(t,a,n){typeof this.curls[t]=="undefined"&&(this.curls[t]=[]),this.curls[t].push([a,n])}direction(t,a,n){this.directions[t]||(this.directions[t]=[]),this.directions[t].push([a,n])}weight(t,a){this.weights[t]=a;let n=this.weights.reduce((r,s)=>r+s,0);this.weightsRelative=this.weights.map(r=>r*5/n)}matchAgainst(t,a){let n=0;for(let r in t){let s=t[r],i=this.curls[r];if(typeof i=="undefined"){n+=this.weightsRelative[r];continue}for(let[o,l]of i)if(s===o){n+=l*this.weightsRelative[r];break}}for(let r in a){let s=a[r],i=this.directions[r];if(typeof i=="undefined"){n+=this.weightsRelative[r];continue}for(let[o,l]of i)if(s===o){n+=l*this.weightsRelative[r];break}}return n/10}};var{thumb:Bn,index:Rr,middle:Mr,ring:Po,pinky:Fo}=Ma,{none:Wn,half:Nhe,full:Vn}=As,{verticalUp:Cu,verticalDown:zge,horizontalLeft:Ug,horizontalRight:Ehe,diagonalUpRight:Rhe,diagonalUpLeft:Nu,diagonalDownRight:Lge,diagonalDownLeft:Bge}=Et,ys=new xs("thumbs up");ys.curl(Bn,Wn,1);ys.direction(Bn,Cu,1);ys.direction(Bn,Nu,.25);ys.direction(Bn,Rhe,.25);for(let e of[Ma.index,Ma.middle,Ma.ring,Ma.pinky])ys.curl(e,Vn,1),ys.direction(e,Ug,1),ys.direction(e,Ehe,1);var Wt=new xs("victory");Wt.curl(Bn,Nhe,.5);Wt.curl(Bn,Wn,.5);Wt.direction(Bn,Cu,1);Wt.direction(Bn,Nu,1);Wt.curl(Rr,Wn,1);Wt.direction(Rr,Cu,.75);Wt.direction(Rr,Nu,1);Wt.curl(Mr,Wn,1);Wt.direction(Mr,Cu,1);Wt.direction(Mr,Nu,.75);Wt.curl(Po,Vn,1);Wt.direction(Po,Cu,.2);Wt.direction(Po,Nu,1);Wt.direction(Po,Ug,.2);Wt.curl(Fo,Vn,1);Wt.direction(Fo,Cu,.2);Wt.direction(Fo,Nu,1);Wt.direction(Fo,Ug,.2);Wt.weight(Rr,2);Wt.weight(Mr,2);var bs=new xs("point");bs.curl(Bn,Vn,1);bs.curl(Rr,Wn,.5);bs.curl(Mr,Vn,.5);bs.curl(Po,Vn,.5);bs.curl(Fo,Vn,.5);bs.weight(Rr,2);bs.weight(Mr,2);var vs=new xs("middle finger");vs.curl(Bn,Wn,1);vs.curl(Rr,Vn,.5);vs.curl(Mr,Vn,.5);vs.curl(Po,Vn,.5);vs.curl(Fo,Vn,.5);vs.weight(Rr,2);vs.weight(Mr,2);var Eu=new xs("open palm");Eu.curl(Bn,Wn,.75);Eu.curl(Rr,Wn,.75);Eu.curl(Mr,Wn,.75);Eu.curl(Po,Wn,.75);Eu.curl(Fo,Wn,.75);var Gw=[ys,Wt,bs,vs,Eu];var Mhe=.7,Oo={HALF_CURL_START_LIMIT:60,NO_CURL_START_LIMIT:130,DISTANCE_VOTE_POWER:1.1,SINGLE_ANGLE_VOTE_POWER:.9,TOTAL_ANGLE_VOTE_POWER:1.6};function Hw(e,t,a,n){let r=(t-n)/(e-a),s=Math.atan(r)*180/Math.PI;return s<=0?s=-s:s>0&&(s=180-s),s}function qw(e,t){if(!e||!t)return[0,0];let a=Hw(e[0],e[1],t[0],t[1]);if(e.length===2)return a;let n=Hw(e[1],e[2],t[1],t[2]);return[a,n]}function jw(e,t=1){let a=0,n=0,r=0;return e>=75&&e<=105?a=1*t:e>=25&&e<=155?n=1*t:r=1*t,[a,n,r]}function $he(e,t,a){let n=e[0]-t[0],r=e[0]-a[0],s=t[0]-a[0],i=e[1]-t[1],o=e[1]-a[1],l=t[1]-a[1],u=e[2]-t[2],p=e[2]-a[2],c=t[2]-a[2],d=Math.sqrt(n*n+i*i+u*u),h=Math.sqrt(r*r+o*o+p*p),f=Math.sqrt(s*s+l*l+c*c),m=(f*f+d*d-h*h)/(2*f*d);m>1?m=1:m<-1&&(m=-1);let g=Math.acos(m);g=57.2958*g%180;let x;return g>Oo.NO_CURL_START_LIMIT?x=As.none:g>Oo.HALF_CURL_START_LIMIT?x=As.half:x=As.full,x}function Xw(e,t,a,n){let r;return n===Math.abs(e)?e>0?r=Et.horizontalLeft:r=Et.horizontalRight:n===Math.abs(t)?t>0?r=Et.horizontalLeft:r=Et.horizontalRight:a>0?r=Et.horizontalLeft:r=Et.horizontalRight,r}function Kw(e,t,a,n){let r;return n===Math.abs(e)?e<0?r=Et.verticalDown:r=Et.verticalUp:n===Math.abs(t)?t<0?r=Et.verticalDown:r=Et.verticalUp:a<0?r=Et.verticalDown:r=Et.verticalUp,r}function _he(e,t,a,n,r,s,i,o){let l,u=Kw(e,t,a,n),p=Xw(r,s,i,o);return u===Et.verticalUp?p===Et.horizontalLeft?l=Et.diagonalUpLeft:l=Et.diagonalUpRight:p===Et.horizontalLeft?l=Et.diagonalDownLeft:l=Et.diagonalDownRight,l}function Phe(e,t,a,n){let r=e[0]-t[0],s=e[0]-a[0],i=t[0]-a[0],o=e[1]-t[1],l=e[1]-a[1],u=t[1]-a[1],p=Math.max(Math.abs(r),Math.abs(s),Math.abs(i)),c=Math.max(Math.abs(o),Math.abs(l),Math.abs(u)),d=0,h=0,f=0,m=c/(p+1e-5);m>1.5?d+=Oo.DISTANCE_VOTE_POWER:m>.66?h+=Oo.DISTANCE_VOTE_POWER:f+=Oo.DISTANCE_VOTE_POWER;let g=Math.sqrt(r*r+o*o),x=Math.sqrt(s*s+l*l),A=Math.sqrt(i*i+u*u),y=Math.max(g,x,A),b=e[0],w=e[1],S=a[0],C=a[1];y===g?(S=a[0],C=a[1]):y===A&&(b=t[0],w=t[1]);let $=qw([b,w],[S,C]),M=jw($,Oo.TOTAL_ANGLE_VOTE_POWER);d+=M[0],h+=M[1],f+=M[2];for(let N of n){let O=jw(N,Oo.SINGLE_ANGLE_VOTE_POWER);d+=O[0],h+=O[1],f+=O[2]}let I;return d===Math.max(d,h,f)?I=Kw(l,o,u,c):f===Math.max(h,f)?I=Xw(s,r,i,p):I=_he(l,o,u,c,s,r,i,p),I}function Zw(e){let t=[],a=[],n=[],r=[];if(!e)return{curls:n,directions:r};for(let s of Ma.all){let i=Ma.getPoints(s),o=[],l=[];for(let u of i){let p=e[u[0]],c=e[u[1]],d=qw(p,c),h=d[0],f=d[1];o.push(h),l.push(f)}t.push(o),a.push(l)}for(let s of Ma.all){let i=s===Ma.thumb?1:0,o=Ma.getPoints(s),l=e[o[i][0]],u=e[o[i+1][1]],p=e[o[3][1]],c=$he(l,u,p),d=Phe(l,u,p,t[s].slice(i));n[s]=c,r[s]=d}return{curls:n,directions:r}}function k0(e){if(!e||e.length===0)return null;let t=Zw(e),a={};for(let n of Ma.all)a[Ma.getName(n)]={curl:As.getName(t.curls[n]),direction:Et.getName(t.directions[n])};return a}function Yw(e){let t=[];if(!e||e.length===0)return t;let a=Zw(e);for(let n of Gw){let r=n.matchAgainst(a.curls,a.directions);r>=Mhe&&t.push({name:n.name,confidence:r})}return t}var Jw=e=>{if(!e)return[];let t=[];for(let a=0;al.part==="leftWrist"),r=e[a].keypoints.find(l=>l.part==="rightWrist"),s=e[a].keypoints.find(l=>l.part==="nose");s&&n&&r&&n.position[1]l.part==="leftShoulder"),o=e[a].keypoints.find(l=>l.part==="rightShoulder");i&&o&&Math.abs(i.positionRaw[1]-o.positionRaw[1])>.1&&t.push({body:a,gesture:`leaning ${i.position[1]>o.position[1]?"left":"right"}`})}return t},Qw=e=>{if(!e)return[];let t=[];for(let a=0;a450){let n=(e[a].mesh[33][2]||0)-(e[a].mesh[263][2]||0),r=e[a].mesh[33][0]-e[a].mesh[263][0];Math.abs(n/r)<=.15?t.push({face:a,gesture:"facing center"}):t.push({face:a,gesture:`facing ${n<0?"left":"right"}`}),Math.abs(e[a].mesh[374][1]-e[a].mesh[386][1])/Math.abs(e[a].mesh[443][1]-e[a].mesh[450][1])<.2&&t.push({face:a,gesture:"blink left eye"}),Math.abs(e[a].mesh[145][1]-e[a].mesh[159][1])/Math.abs(e[a].mesh[223][1]-e[a].mesh[230][1])<.2&&t.push({face:a,gesture:"blink right eye"});let o=Math.min(100,500*Math.abs(e[a].mesh[13][1]-e[a].mesh[14][1])/Math.abs(e[a].mesh[10][1]-e[a].mesh[152][1]));o>10&&t.push({face:a,gesture:`mouth ${Math.trunc(o)}% open`});let l=e[a].mesh[152][2]||0;Math.abs(l)>10&&t.push({face:a,gesture:`head ${l<0?"up":"down"}`})}return t},ek=e=>{var a,n,r,s;if(!e)return[];let t=[];for(let i=0;i.06||g>.06)&&(h=!1),m>g?m>.05&&t.push({iris:i,gesture:"looking right"}):g>.05&&t.push({iris:i,gesture:"looking left"});let x=Math.abs(e[i].mesh[145][1]-e[i].annotations.rightEyeIris[0][1])/e[i].box[3],A=Math.abs(e[i].mesh[374][1]-e[i].annotations.leftEyeIris[0][1])/e[i].box[3];(A<.01||x<.01||A>.022||x>.022)&&(h=!1),(A<.01||x<.01)&&t.push({iris:i,gesture:"looking down"}),(A>.022||x>.022)&&t.push({iris:i,gesture:"looking up"}),h&&t.push({iris:i,gesture:"looking center"})}return t},tk=e=>{if(!e)return[];let t=[];for(let a=0;a0){let r=n.reduce((i,o)=>(i.position[2]||0)<(o.position[2]||0)?i:o);t.push({hand:a,gesture:`${r.name} forward`});let s=n.reduce((i,o)=>i.position[1][s[0]*t[0],s[1]*t[1]]);return{startPoint:a,endPoint:n,palmLandmarks:r,confidence:e.confidence}}function S0(e,t=1.5){let a=Tp(e),n=I0(e),r=[t*n[0]/2,t*n[1]/2],s=[a[0]-r[0],a[1]-r[1]],i=[a[0]+r[0],a[1]+r[1]];return{startPoint:s,endPoint:i,palmLandmarks:e.palmLandmarks}}function T0(e){let t=Tp(e),a=I0(e),r=Math.max(...a)/2,s=[t[0]-r,t[1]-r],i=[t[0]+r,t[1]+r];return{startPoint:s,endPoint:i,palmLandmarks:e.palmLandmarks}}function Ohe(e){return e-2*Math.PI*Math.floor((e+Math.PI)/(2*Math.PI))}function ik(e,t){let a=Math.PI/2-Math.atan2(-(t[1]-e[1]),t[0]-e[0]);return Ohe(a)}var ak=(e,t)=>[[1,0,e],[0,1,t],[0,0,1]];function ws(e,t){let a=0;for(let n=0;n[i.x,i.y]),this.anchorsTensor=Kn(this.anchors),this.inputSize=((s=(r=(n=(a=this==null?void 0:this.model)==null?void 0:a.inputs)==null?void 0:n[0])==null?void 0:r.shape)==null?void 0:s[2])||0,this.inputSizeTensor=Ht([this.inputSize,this.inputSize]),this.doubleInputSizeTensor=Ht([this.inputSize*2,this.inputSize*2])}normalizeBoxes(t){let a={};a.boxOffsets=Pe(t,[0,0],[-1,2]),a.boxSizes=Pe(t,[0,2],[-1,2]),a.div=me(a.boxOffsets,this.inputSizeTensor),a.boxCenterPoints=be(a.div,this.anchorsTensor),a.halfBoxSizes=me(a.boxSizes,this.doubleInputSizeTensor),a.sub=fe(a.boxCenterPoints,a.halfBoxSizes),a.startPoints=ae(a.sub,this.inputSizeTensor),a.add=be(a.boxCenterPoints,a.halfBoxSizes),a.endPoints=ae(a.add,this.inputSizeTensor);let n=ru([a.startPoints,a.endPoints],1);return Object.keys(a).forEach(r=>Y(a[r])),n}normalizeLandmarks(t,a){let n={};n.reshape=J(t,[-1,7,2]),n.div=me(n.reshape,this.inputSizeTensor),n.landmarks=be(n.div,this.anchors[a]?this.anchors[a]:0);let r=ae(n.landmarks,this.inputSizeTensor);return Object.keys(n).forEach(s=>Y(n[s])),r}async predict(t,a){var o;let n={};n.resize=ge.resizeBilinear(t,[this.inputSize,this.inputSize]),n.div=me(n.resize,ze.tf127),n.image=fe(n.div,ze.tf1),n.batched=this.model.execute(n.image),n.predictions=_e(n.batched),n.slice=Pe(n.predictions,[0,0],[-1,1]),n.sigmoid=Da(n.slice),n.scores=_e(n.sigmoid);let r=await n.scores.data();n.boxes=Pe(n.predictions,[0,1],[-1,4]),n.norm=this.normalizeBoxes(n.boxes),n.nms=await ge.nonMaxSuppressionAsync(n.norm,n.scores,3*(((o=a.hand)==null?void 0:o.maxDetected)||1),a.hand.iouThreshold,a.hand.minConfidence);let s=await n.nms.array(),i=[];for(let l of s){let u={};u.box=Pe(n.norm,[l,0],[1,-1]),u.slice=Pe(n.predictions,[l,5],[1,14]),u.norm=this.normalizeLandmarks(u.slice,l),u.palmLandmarks=J(u.norm,[-1,2]);let p=await u.box.data(),c=p.slice(0,2),d=p.slice(2,4),h=await u.palmLandmarks.array(),f={startPoint:c,endPoint:d,palmLandmarks:h,confidence:r[l]},m=sk(f,[(t.shape[2]||1)/this.inputSize,(t.shape[1]||0)/this.inputSize]);i.push(m),Object.keys(u).forEach(g=>Y(u[g]))}return Object.keys(n).forEach(l=>Y(n[l])),i}};var Bhe=5,dk=1.65,pk=[0,5,9,13,17,1,2],Whe=0,Vhe=2,ck=0,N0=class{constructor(t,a){ue(this,"handDetector");ue(this,"handPoseModel");ue(this,"inputSize");ue(this,"storedBoxes");ue(this,"skipped");ue(this,"detectedHands");var n,r,s;this.handDetector=t,this.handPoseModel=a,this.inputSize=((s=(r=(n=this.handPoseModel)==null?void 0:n.inputs)==null?void 0:r[0].shape)==null?void 0:s[2])||0,this.storedBoxes=[],this.skipped=Number.MAX_SAFE_INTEGER,this.detectedHands=0}calculateLandmarksBoundingBox(t){let a=t.map(i=>i[0]),n=t.map(i=>i[1]),r=[Math.min(...a),Math.min(...n)],s=[Math.max(...a),Math.max(...n)];return{startPoint:r,endPoint:s}}getBoxForPalmLandmarks(t,a){let n=t.map(s=>jg([...s,1],a)),r=this.calculateLandmarksBoundingBox(n);return S0(T0(r),Bhe)}getBoxForHandLandmarks(t){let a=this.calculateLandmarksBoundingBox(t),n=S0(T0(a),dk);n.palmLandmarks=[];for(let r=0;r[i[0]*(h[0]-this.inputSize/2),i[1]*(h[1]-this.inputSize/2),i[2]*h[2]]),l=Hg(n,[0,0]),u=o.map(h=>[...jg(h,l),h[2]]),p=ok(r),c=[...Tp(a),1],d=[ws(c,p[0]),ws(c,p[1])];return u.map(h=>[Math.trunc(h[0]+d[0]),Math.trunc(h[1]+d[1]),Math.trunc(h[2])])}async estimateHands(t,a){let n=!1,r,s=(a.hand.skipTime||0)>te()-ck,i=this.skipped<(a.hand.skipFrames||0);a.skipAllowed&&s&&i&&(r=await this.handDetector.predict(t,a),this.skipped=0),a.skipAllowed&&this.skipped++,r&&r.length>0&&(r.length!==this.detectedHands&&this.detectedHands!==a.hand.maxDetected||!a.hand.landmarks)&&(this.detectedHands=0,this.storedBoxes=[...r],this.storedBoxes.length>0&&(n=!0));let o=[];for(let l=0;l=a.hand.minConfidence/4){let w=J(y,[-1,3]),S=await w.array();Y(y),Y(w);let C=this.transformRawCoords(S,m,p,f),E=this.getBoxForHandLandmarks(C);this.storedBoxes[l]={...E,confidence:b};let _={landmarks:C,confidence:b,boxConfidence:u.confidence,fingerConfidence:b,box:{topLeft:E.startPoint,bottomRight:E.endPoint}};o.push(_)}else this.storedBoxes[l]=null;Y(y)}else{let p=S0(T0(u),dk),c={confidence:u.confidence,boxConfidence:u.confidence,fingerConfidence:0,box:{topLeft:p.startPoint,bottomRight:p.endPoint},landmarks:[]};o.push(c)}}return this.storedBoxes=this.storedBoxes.filter(l=>l!==null),this.detectedHands=o.length,o.length>a.hand.maxDetected&&(o.length=a.hand.maxDetected),o}};var hk={thumb:[1,2,3,4],index:[5,6,7,8],middle:[9,10,11,12],ring:[13,14,15,16],pinky:[17,18,19,20],palm:[0]},Do,zo,fk;async function qg(e,t){let a=await fk.estimateHands(e,t);if(!a)return[];let n=[];for(let r=0;ra[r].landmarks[c]);let i=a[r].landmarks,o=[Number.MAX_SAFE_INTEGER,Number.MAX_SAFE_INTEGER,0,0],l=[0,0,0,0];if(i&&i.length>0){for(let p of i)p[0]o[2]&&(o[2]=p[0]),p[1]>o[3]&&(o[3]=p[1]);o[2]-=o[0],o[3]-=o[1],l=[o[0]/(e.shape[2]||0),o[1]/(e.shape[1]||0),o[2]/(e.shape[2]||0),o[3]/(e.shape[1]||0)]}else o=a[r].box?[Math.trunc(Math.max(0,a[r].box.topLeft[0])),Math.trunc(Math.max(0,a[r].box.topLeft[1])),Math.trunc(Math.min(e.shape[2]||0,a[r].box.bottomRight[0])-Math.max(0,a[r].box.topLeft[0])),Math.trunc(Math.min(e.shape[1]||0,a[r].box.bottomRight[1])-Math.max(0,a[r].box.topLeft[1]))]:[0,0,0,0],l=[a[r].box.topLeft[0]/(e.shape[2]||0),a[r].box.topLeft[1]/(e.shape[1]||0),(a[r].box.bottomRight[0]-a[r].box.topLeft[0])/(e.shape[2]||0),(a[r].box.bottomRight[1]-a[r].box.topLeft[1])/(e.shape[1]||0)];let u=k0(i);n.push({id:r,score:Math.round(100*a[r].confidence)/100,boxScore:Math.round(100*a[r].boxConfidence)/100,fingerScore:Math.round(100*a[r].fingerConfidence)/100,label:"hand",box:o,boxRaw:l,keypoints:i,annotations:s,landmarks:u})}return n}async function mk(e){var a,n;ne.initial&&(Do=null,zo=null),!Do||!zo?[Do,zo]=await Promise.all([e.hand.enabled?Ee((a=e.hand.detector)==null?void 0:a.modelPath):null,e.hand.landmarks?Ee((n=e.hand.skeleton)==null?void 0:n.modelPath):null]):(e.debug&&K("cached model:",Do.modelUrl),e.debug&&K("cached model:",zo.modelUrl));let t=Do?new C0(Do):void 0;return t&&zo&&(fk=new N0(t,zo)),[Do,zo]}var Pt=[null,null],Ghe=["StatefulPartitionedCall/Postprocessor/Slice","StatefulPartitionedCall/Postprocessor/ExpandDims_1"],ks=[[0,0],[0,0]],Hhe=["hand","fist","pinch","point","face","tip","pinchtip"],xk=4,Ak=1.6,jhe=512,qhe=1.4,E0=Number.MAX_SAFE_INTEGER,Xg=0,$r=[0,0],_t={boxes:[],hands:[]},yk={thumb:[1,2,3,4],index:[5,6,7,8],middle:[9,10,11,12],ring:[13,14,15,16],pinky:[17,18,19,20],base:[0],palm:[0,17,13,9,5,1,0]};async function bk(e){var t;if(ne.initial&&(Pt[0]=null),Pt[0])e.debug&&K("cached model:",Pt[0].modelUrl);else{Qh(["tensorlistreserve","enter","tensorlistfromtensor","merge","loopcond","switch","exit","tensorliststack","nextiteration","tensorlistsetitem","tensorlistgetitem","reciprocal","shape","split","where"],e),Pt[0]=await Ee((t=e.hand.detector)==null?void 0:t.modelPath);let a=Pt[0].executor?Object.values(Pt[0].modelSignature.inputs):void 0;ks[0][0]=Array.isArray(a)?parseInt(a[0].tensorShape.dim[1].size):0,ks[0][1]=Array.isArray(a)?parseInt(a[0].tensorShape.dim[2].size):0}return Pt[0]}async function vk(e){var t;if(ne.initial&&(Pt[1]=null),Pt[1])e.debug&&K("cached model:",Pt[1].modelUrl);else{Pt[1]=await Ee((t=e.hand.skeleton)==null?void 0:t.modelPath);let a=Pt[1].executor?Object.values(Pt[1].modelSignature.inputs):void 0;ks[1][0]=Array.isArray(a)?parseInt(a[0].tensorShape.dim[1].size):0,ks[1][1]=Array.isArray(a)?parseInt(a[0].tensorShape.dim[2].size):0}return Pt[1]}async function Xhe(e,t){let a=[];if(!e||!Pt[0])return a;let n={},r=(e.shape[2]||1)/(e.shape[1]||1),s=Math.min(Math.round((e.shape[1]||0)/8)*8,jhe),i=Math.round(s*r/8)*8;n.resize=ge.resizeBilinear(e,[s,i]),n.cast=He(n.resize,"int32"),[n.rawScores,n.rawBoxes]=await Pt[0].executeAsync(n.cast,Ghe),n.boxes=_e(n.rawBoxes,[0,2]),n.scores=_e(n.rawScores,[0]);let o=Ta(n.scores,1);Y(o[xk]),o.splice(xk,1),n.filtered=sa(o,1),Y(o),n.max=pa(n.filtered,1),n.argmax=ar(n.filtered,1);let l=0;n.nms=await ge.nonMaxSuppressionAsync(n.boxes,n.max,(t.hand.maxDetected||0)+1,t.hand.iouThreshold||0,t.hand.minConfidence||1);let u=await n.nms.data(),p=await n.max.data(),c=await n.argmax.data();for(let d of Array.from(u)){let h=Pe(n.boxes,d,1),f=await h.data();Y(h);let m=[f[1],f[0],f[3]-f[1],f[2]-f[0]],g=l0(m,qhe),x=[Math.trunc(m[0]*$r[0]),Math.trunc(m[1]*$r[1]),Math.trunc(m[2]*$r[0]),Math.trunc(m[3]*$r[1])],A=p[d],y=Hhe[c[d]],b={id:l++,score:A,box:x,boxRaw:g,label:y};a.push(b)}return Object.keys(n).forEach(d=>Y(n[d])),a.sort((d,h)=>h.score-d.score),a.length>(t.hand.maxDetected||1)&&(a.length=t.hand.maxDetected||1),a}async function Kg(e,t,a){let n={id:t.id,score:Math.round(100*t.score)/100,boxScore:Math.round(100*t.score)/100,fingerScore:0,box:t.box,boxRaw:t.boxRaw,label:t.label,keypoints:[],landmarks:{},annotations:{}};if(e&&Pt[1]&&a.hand.landmarks&&t.score>(a.hand.minConfidence||0)){let r={},s=[t.boxRaw[1],t.boxRaw[0],t.boxRaw[3]+t.boxRaw[1],t.boxRaw[2]+t.boxRaw[0]];r.crop=ge.cropAndResize(e,[s],[0],[ks[1][0],ks[1][1]],"bilinear"),r.div=me(r.crop,ze.tf255),[r.score,r.keypoints]=Pt[1].execute(r.div,["Identity_1","Identity"]);let i=(await r.score.data())[0],o=(100-Math.trunc(100/(1+Math.exp(i))))/100;if(o>=(a.hand.minConfidence||0)){n.fingerScore=o,r.reshaped=J(r.keypoints,[-1,3]);let p=(await r.reshaped.array()).map(c=>[c[0]/ks[1][1],c[1]/ks[1][0],c[2]||0]).map(c=>[c[0]*t.boxRaw[2],c[1]*t.boxRaw[3],c[2]||0]);n.keypoints=p.map(c=>[$r[0]*(c[0]+t.boxRaw[0]),$r[1]*(c[1]+t.boxRaw[1]),c[2]||0]),n.landmarks=k0(n.keypoints);for(let c of Object.keys(yk))n.annotations[c]=yk[c].map(d=>n.landmarks&&n.keypoints[d]?n.keypoints[d]:null)}Object.keys(r).forEach(l=>Y(r[l]))}return n}async function Zg(e,t){var r,s;if(!((r=Pt[0])!=null&&r.executor)||!((s=Pt[1])!=null&&s.executor)||!Pt[0].inputs[0].shape||!Pt[1].inputs[0].shape)return[];$r=[e.shape[2]||0,e.shape[1]||0],E0++;let a=(t.hand.skipTime||0)>te()-Xg,n=E0<(t.hand.skipFrames||0);return t.skipAllowed&&a&&n?_t.hands:new Promise(async i=>{let o=3*(t.hand.skipTime||0)>te()-Xg,l=E0<3*(t.hand.skipFrames||0);t.skipAllowed&&_t.hands.length===t.hand.maxDetected?_t.hands=await Promise.all(_t.boxes.map(p=>Kg(e,p,t))):t.skipAllowed&&o&&l&&_t.hands.length>0?_t.hands=await Promise.all(_t.boxes.map(p=>Kg(e,p,t))):(_t.boxes=await Xhe(e,t),Xg=te(),_t.hands=await Promise.all(_t.boxes.map(p=>Kg(e,p,t))),E0=0);let u=[..._t.boxes];if(_t.boxes.length=0,t.cacheSensitivity>0)for(let p=0;p<_t.hands.length;p++){let c=b9(_t.hands[p].keypoints,$r);if(c.box[2]/(e.shape[2]||1)>.05&&c.box[3]/(e.shape[1]||1)>.05&&_t.hands[p].fingerScore&&_t.hands[p].fingerScore>(t.hand.minConfidence||0)){let d=l0(c.box,Ak),h=l0(c.boxRaw,Ak);_t.boxes.push({...u[p],box:d,boxRaw:h})}}for(let p=0;p<_t.hands.length;p++){let c=Er(_t.hands[p].keypoints,$r);_t.hands[p].box=c.box,_t.hands[p].boxRaw=c.boxRaw}i(_t.hands)})}var or=(e=null)=>({face:[],body:[],hand:[],gesture:[],object:[],persons:[],performance:{},timestamp:0,width:0,height:0,error:e});var Cp={};hr(Cp,{connected:()=>M0,horizontal:()=>Yg,kpt:()=>R0,relative:()=>Qg,vertical:()=>Jg});var R0=["nose","leftEye","rightEye","leftEar","rightEar","leftShoulder","rightShoulder","leftElbow","rightElbow","leftWrist","rightWrist","leftHip","rightHip","leftKnee","rightKnee","leftAnkle","rightAnkle"],Yg=[["leftEye","rightEye"],["leftEar","rightEar"],["leftShoulder","rightShoulder"],["leftElbow","rightElbow"],["leftWrist","rightWrist"],["leftHip","rightHip"],["leftKnee","rightKnee"],["leftAnkle","rightAnkle"]],Jg=[["leftKnee","leftShoulder"],["rightKnee","rightShoulder"],["leftAnkle","leftKnee"],["rightAnkle","rightKnee"]],Qg=[[["leftHip","rightHip"],["leftShoulder","rightShoulder"]],[["leftElbow","rightElbow"],["leftShoulder","rightShoulder"]]],M0={leftLeg:["leftHip","leftKnee","leftAnkle"],rightLeg:["rightHip","rightKnee","rightAnkle"],torso:["leftShoulder","rightShoulder","rightHip","leftHip","leftShoulder"],leftArm:["leftShoulder","leftElbow","leftWrist"],rightArm:["rightShoulder","rightElbow","rightWrist"],head:[]};var xe=or(),e5=0;function kk(e,t){var i,o,l,u,p,c,d,h,f,m,g,x,A,y,b,w,S,C,E,_,$,M,I;let a=te();if(!e)return or();let n=Date.now()-e.timestamp,r=n<1e3?8-Math.log(n+1):1;if(e.canvas&&(xe.canvas=e.canvas),e.error&&(xe.error=e.error),!xe.body||e.body.length!==xe.body.length)xe.body=JSON.parse(JSON.stringify(e.body));else for(let N=0;N((r-1)*xe.body[N].box[H]+U)/r),L=e.body[N].boxRaw.map((U,H)=>((r-1)*xe.body[N].boxRaw[H]+U)/r),B=e.body[N].keypoints.map((U,H)=>{var V,Q,Z,re,ee,he,oe,Ae,we;return{score:U.score,part:U.part,position:[xe.body[N].keypoints[H]?((r-1)*(xe.body[N].keypoints[H].position[0]||0)+(U.position[0]||0))/r:U.position[0],xe.body[N].keypoints[H]?((r-1)*(xe.body[N].keypoints[H].position[1]||0)+(U.position[1]||0))/r:U.position[1],xe.body[N].keypoints[H]?((r-1)*(xe.body[N].keypoints[H].position[2]||0)+(U.position[2]||0))/r:U.position[2]],positionRaw:[xe.body[N].keypoints[H]?((r-1)*(xe.body[N].keypoints[H].positionRaw[0]||0)+(U.positionRaw[0]||0))/r:U.positionRaw[0],xe.body[N].keypoints[H]?((r-1)*(xe.body[N].keypoints[H].positionRaw[1]||0)+(U.positionRaw[1]||0))/r:U.positionRaw[1],xe.body[N].keypoints[H]?((r-1)*(xe.body[N].keypoints[H].positionRaw[2]||0)+(U.positionRaw[2]||0))/r:U.positionRaw[2]],distance:[xe.body[N].keypoints[H]?((r-1)*(((V=xe.body[N].keypoints[H].distance)==null?void 0:V[0])||0)+(((Q=U.distance)==null?void 0:Q[0])||0))/r:(Z=U.distance)==null?void 0:Z[0],xe.body[N].keypoints[H]?((r-1)*(((re=xe.body[N].keypoints[H].distance)==null?void 0:re[1])||0)+(((ee=U.distance)==null?void 0:ee[1])||0))/r:(he=U.distance)==null?void 0:he[1],xe.body[N].keypoints[H]?((r-1)*(((oe=xe.body[N].keypoints[H].distance)==null?void 0:oe[2])||0)+(((Ae=U.distance)==null?void 0:Ae[2])||0))/r:(we=U.distance)==null?void 0:we[2]]}}),G={},j={connected:{}};(i=t.body.modelPath)!=null&&i.includes("efficientpose")?j=p0:(o=t.body.modelPath)!=null&&o.includes("blazepose")?j=i0:(l=t.body.modelPath)!=null&&l.includes("movenet")&&(j=Cp);for(let[U,H]of Object.entries(j.connected)){let V=[];for(let Q=0;Qee.part===H[Q]),re=B.find(ee=>ee.part===H[Q+1]);Z&&re&&V.push([Z.position,re.position])}G[U]=V}xe.body[N]={...e.body[N],box:O,boxRaw:L,keypoints:B,annotations:G}}if(!xe.hand||e.hand.length!==xe.hand.length)xe.hand=JSON.parse(JSON.stringify(e.hand));else for(let N=0;N((r-1)*xe.hand[N].box[U]+j)/r),L=e.hand[N].boxRaw.map((j,U)=>((r-1)*xe.hand[N].boxRaw[U]+j)/r);xe.hand[N].keypoints.length!==e.hand[N].keypoints.length&&(xe.hand[N].keypoints=e.hand[N].keypoints);let B=e.hand[N].keypoints&&e.hand[N].keypoints.length>0?e.hand[N].keypoints.map((j,U)=>j.map((H,V)=>((r-1)*(xe.hand[N].keypoints[U][V]||1)+(H||0))/r)):[],G={};if(Object.keys(xe.hand[N].annotations).length!==Object.keys(e.hand[N].annotations).length)xe.hand[N].annotations=e.hand[N].annotations,G=xe.hand[N].annotations;else if(e.hand[N].annotations)for(let j of Object.keys(e.hand[N].annotations))G[j]=(c=(p=(u=e.hand[N])==null?void 0:u.annotations)==null?void 0:p[j])!=null&&c[0]?e.hand[N].annotations[j].map((U,H)=>U.map((V,Q)=>((r-1)*xe.hand[N].annotations[j][H][Q]+V)/r)):null;xe.hand[N]={...e.hand[N],box:O,boxRaw:L,keypoints:B,annotations:G}}if(!xe.face||e.face.length!==xe.face.length)xe.face=JSON.parse(JSON.stringify(e.face));else for(let N=0;N((r-1)*xe.face[N].box[G]+B)/r),L=e.face[N].boxRaw.map((B,G)=>((r-1)*xe.face[N].boxRaw[G]+B)/r);if(e.face[N].rotation){let B={matrix:[0,0,0,0,0,0,0,0,0],angle:{roll:0,yaw:0,pitch:0},gaze:{bearing:0,strength:0}};B.matrix=(d=e.face[N].rotation)==null?void 0:d.matrix,B.angle={roll:((r-1)*(((f=(h=xe.face[N].rotation)==null?void 0:h.angle)==null?void 0:f.roll)||0)+(((g=(m=e.face[N].rotation)==null?void 0:m.angle)==null?void 0:g.roll)||0))/r,yaw:((r-1)*(((A=(x=xe.face[N].rotation)==null?void 0:x.angle)==null?void 0:A.yaw)||0)+(((b=(y=e.face[N].rotation)==null?void 0:y.angle)==null?void 0:b.yaw)||0))/r,pitch:((r-1)*(((S=(w=xe.face[N].rotation)==null?void 0:w.angle)==null?void 0:S.pitch)||0)+(((E=(C=e.face[N].rotation)==null?void 0:C.angle)==null?void 0:E.pitch)||0))/r},B.gaze={bearing:((r-1)*(((_=xe.face[N].rotation)==null?void 0:_.gaze.bearing)||0)+((($=e.face[N].rotation)==null?void 0:$.gaze.bearing)||0))/r,strength:((r-1)*(((M=xe.face[N].rotation)==null?void 0:M.gaze.strength)||0)+(((I=e.face[N].rotation)==null?void 0:I.gaze.strength)||0))/r},xe.face[N]={...e.face[N],rotation:B,box:O,boxRaw:L}}else xe.face[N]={...e.face[N],box:O,boxRaw:L}}if(!xe.object||e.object.length!==xe.object.length)xe.object=JSON.parse(JSON.stringify(e.object));else for(let N=0;N((r-1)*xe.object[N].box[G]+B)/r),L=e.object[N].boxRaw.map((B,G)=>((r-1)*xe.object[N].boxRaw[G]+B)/r);xe.object[N]={...e.object[N],box:O,boxRaw:L}}if(e.persons){let N=e.persons;if(!xe.persons||N.length!==xe.persons.length)xe.persons=JSON.parse(JSON.stringify(N));else for(let O=0;O((r-1)*xe.persons[O].box[B]+L)/r)}e.gesture&&(xe.gesture=e.gesture),xe.width=e.width,xe.height=e.height;let s=te();return e5=ne.perfadd?e5+Math.round(s-a):Math.round(s-a),e.performance&&(xe.performance={...e.performance,interpolate:e5}),xe}var ma;async function t5(e){return!ma||ne.initial?ma=await Ee(e.segmentation.modelPath):e.debug&&K("cached model:",ma.modelUrl),ma}async function Ik(e,t){var r;if(ma||(ma=await t5(t)),!(ma!=null&&ma.executor)||!((r=ma==null?void 0:ma.inputs)!=null&&r[0].shape))return null;let a={};a.resize=ge.resizeBilinear(e,[ma.inputs[0].shape?ma.inputs[0].shape[1]:0,ma.inputs[0].shape?ma.inputs[0].shape[2]:0],!1),a.norm=me(a.resize,ze.tf255),a.res=ma.execute(a.norm),a.squeeze=_e(a.res,[0]),[a.bgRaw,a.fgRaw]=Ta(a.squeeze,2),a.fg=Ah(a.fgRaw),a.mul=ae(a.fg,ze.tf255),a.expand=Gt(a.mul,2),a.output=ge.resizeBilinear(a.expand,[e.shape[1]||0,e.shape[2]||0]);let n;switch(t.segmentation.mode||"default"){case"default":a.input=_e(e),a.concat=at([a.input,a.output],-1),n=He(a.concat,"int32");break;case"alpha":n=He(a.output,"int32");break;default:n=Be(0)}return Object.keys(a).forEach(s=>Y(a[s])),n}var $0={};hr($0,{distance:()=>a5,find:()=>Yhe,similarity:()=>Zhe});function a5(e,t,a={order:2,multiplier:25}){if(!e||!e)return Number.MAX_SAFE_INTEGER;let n=0;for(let r=0;r{if(e===0)return 1;let s=(1-(t===2?Math.sqrt(e):e**(1/t))/100-a)/(n-a);return Math.max(Math.min(s,1),0)};function Zhe(e,t,a={order:2,multiplier:25,min:.2,max:.8}){let n=a5(e,t,a);return Tk(n,a.order||2,a.min||0,a.max||1)}function Yhe(e,t,a={order:2,multiplier:25,threshold:0,min:.2,max:.8}){if(!Array.isArray(e)||!Array.isArray(t)||e.length<64||t.length===0)return{index:-1,distance:Number.POSITIVE_INFINITY,similarity:0};let n=Number.MAX_SAFE_INTEGER,r=-1;for(let i=0;iRp,validateModel:()=>L0});var Ck=.005,nn={keypoints:[],padding:[[0,0],[0,0],[0,0],[0,0]]};function n5(e){for(let t of Yg){let a=e.keypoints.findIndex(r=>r.part===t[0]),n=e.keypoints.findIndex(r=>r.part===t[1]);if(e.keypoints[a]&&e.keypoints[n]&&e.keypoints[a].position[0]r&&r.part===t[0]),n=e.keypoints.findIndex(r=>r&&r.part===t[1]);e.keypoints[a]&&e.keypoints[n]&&e.keypoints[a].position[1]u&&u.part===t[0]),r=e.keypoints.findIndex(u=>u&&u.part===t[1]),s=e.keypoints.findIndex(u=>u&&u.part===a[0]),i=e.keypoints.findIndex(u=>u&&u.part===a[1]);if(!e.keypoints[s]||!e.keypoints[i])continue;let o=e.keypoints[n]?[Math.abs(e.keypoints[s].position[0]-e.keypoints[n].position[0]),Math.abs(e.keypoints[i].position[0]-e.keypoints[n].position[0])]:[0,0],l=e.keypoints[r]?[Math.abs(e.keypoints[i].position[0]-e.keypoints[r].position[0]),Math.abs(e.keypoints[s].position[0]-e.keypoints[r].position[0])]:[0,0];if(o[0]>o[1]||l[0]>l[1]){let u=e.keypoints[n];e.keypoints[n]=e.keypoints[r],e.keypoints[r]=u}}}function Nk(e){for(let t=0;te.shape[1]?Math.trunc((e.shape[2]-e.shape[1])/2):0,e.shape[2]>e.shape[1]?Math.trunc((e.shape[2]-e.shape[1])/2):0],[e.shape[1]>e.shape[2]?Math.trunc((e.shape[1]-e.shape[2])/2):0,e.shape[1]>e.shape[2]?Math.trunc((e.shape[1]-e.shape[2])/2):0],[0,0]],a.pad=rr(e,nn.padding),a.resize=ge.resizeBilinear(a.pad,[t,t]);let n=He(a.resize,"int32");return Object.keys(a).forEach(i=>Y(a[i])),n}function Rk(e,t){e.keypoints=e.keypoints.filter(n=>n==null?void 0:n.position);for(let n of e.keypoints)n.position=[n.position[0]*(t[0]+nn.padding[2][0]+nn.padding[2][1])/t[0]-nn.padding[2][0],n.position[1]*(t[1]+nn.padding[1][0]+nn.padding[1][1])/t[1]-nn.padding[1][0]],n.positionRaw=[n.position[0]/t[0],n.position[1]/t[1]];let a=Er(e.keypoints.map(n=>n.position),t);return e.box=a.box,e.boxRaw=a.boxRaw,e}var Vt,_0=0,r5=Number.MAX_SAFE_INTEGER,Lo={boxes:[],bodies:[],last:0};async function Mk(e){var t;return ne.initial&&(Vt=null),Vt?e.debug&&K("cached model:",Vt.modelUrl):(Qh(["size"],e),Vt=await Ee(e.body.modelPath)),_0=(Vt==null?void 0:Vt.executor)&&((t=Vt==null?void 0:Vt.inputs)==null?void 0:t[0].shape)?Vt.inputs[0].shape[2]:0,_0<64&&(_0=256),Vt}function Qhe(e,t,a){let n=e[0][0],r=[],s=0;for(let p=0;pt.body.minConfidence){let c=[n[p][1],n[p][0]];r.push({score:Math.round(100*s)/100,part:R0[p],positionRaw:c,position:[Math.round((a.shape[2]||0)*c[0]),Math.round((a.shape[1]||0)*c[1])]})}s=r.reduce((p,c)=>c.score>p?c.score:p,0);let i=[],o=Er(r.map(p=>p.position),[a.shape[2],a.shape[1]]),l={};for(let[p,c]of Object.entries(M0)){let d=[];for(let h=0;hg.part===c[h]),m=r.find(g=>g.part===c[h+1]);f&&m&&f.score>(t.body.minConfidence||0)&&m.score>(t.body.minConfidence||0)&&d.push([f.position,m.position])}l[p]=d}let u={id:0,score:s,box:o.box,boxRaw:o.boxRaw,keypoints:r,annotations:l};return n5(u),i.push(u),i}function e0e(e,t,a){let n=[];for(let r=0;rt.body.minConfidence){let o=[];for(let c=0;c<17;c++){let d=s[3*c+2];if(d>t.body.minConfidence){let h=[s[3*c+1],s[3*c+0]];o.push({part:R0[c],score:Math.round(100*d)/100,positionRaw:h,position:[Math.round((a.shape[2]||0)*h[0]),Math.round((a.shape[1]||0)*h[1])]})}}let l=Er(o.map(c=>c.position),[a.shape[2],a.shape[1]]),u={};for(let[c,d]of Object.entries(M0)){let h=[];for(let f=0;fx.part===d[f]),g=o.find(x=>x.part===d[f+1]);m&&g&&m.score>(t.body.minConfidence||0)&&g.score>(t.body.minConfidence||0)&&h.push([m.position,g.position])}u[c]=h}let p={id:r,score:i,box:l.box,boxRaw:l.boxRaw,keypoints:[...o],annotations:u};n5(p),n.push(p)}}return n.sort((r,s)=>s.score-r.score),n.length>t.body.maxDetected&&(n.length=t.body.maxDetected),n}async function s5(e,t){var r;if(!(Vt!=null&&Vt.executor)||!((r=Vt==null?void 0:Vt.inputs)!=null&&r[0].shape))return[];t.skipAllowed||(Lo.boxes.length=0),r5++;let a=(t.body.skipTime||0)>te()-Lo.last,n=r5<(t.body.skipFrames||0);return t.skipAllowed&&a&&n?Lo.bodies:new Promise(async s=>{let i={};r5=0,i.input=Ek(e,_0),i.res=Vt==null?void 0:Vt.execute(i.input),Lo.last=te();let o=await i.res.array();Lo.bodies=i.res.shape[2]===17?Qhe(o,t,e):e0e(o,t,e);for(let l of Lo.bodies)Rk(l,[e.shape[2]||1,e.shape[1]||1]),Nk(l.keypoints);Object.keys(i).forEach(l=>Y(i[l])),s(Lo.bodies)})}var _n,P0=[],_k=0,i5=Number.MAX_SAFE_INTEGER,O0=0,F0=2.5;async function Pk(e){if(!_n||ne.initial){_n=await Ee(e.object.modelPath);let t=_n!=null&&_n.executor?Object.values(_n.modelSignature.inputs):void 0;O0=Array.isArray(t)?parseInt(t[0].tensorShape.dim[2].size):416}else e.debug&&K("cached model:",_n.modelUrl);return _n}async function t0e(e,t,a){var u,p;let n=0,r=[],s=O0;for(let c of[1,2,4]){let d=c*13,h=_e(e.find(y=>y.shape[1]===d**2&&(y.shape[2]||0)===bu.length)),f=await h.array(),m=_e(e.find(y=>y.shape[1]===d**2&&(y.shape[2]||0)(a.object.minConfidence||0)&&b!==61){let S=(.5+Math.trunc(y%d))/d,C=(.5+Math.trunc(y/d))/d,E=A[y].map(B=>B*(d/c/s)),[_,$]=[S-F0/c*E[0],C-F0/c*E[1]],[M,I]=[S+F0/c*E[2]-_,C+F0/c*E[3]-$],N=[_,$,M,I];N=N.map(B=>Math.max(0,Math.min(B,1)));let O=[N[0]*t[0],N[1]*t[1],N[2]*t[0],N[3]*t[1]],L={id:n++,score:Math.round(100*w)/100,class:b+1,label:bu[b].label,box:O.map(B=>Math.trunc(B)),boxRaw:N};r.push(L)}}Y([h,m,g,x])}let i=r.map(c=>[c.boxRaw[1],c.boxRaw[0],c.boxRaw[3],c.boxRaw[2]]),o=r.map(c=>c.score),l=[];if(i&&i.length>0){let c=await ge.nonMaxSuppressionAsync(i,o,a.object.maxDetected||0,a.object.iouThreshold,a.object.minConfidence);l=Array.from(await c.data()),Y(c)}return r=r.filter((c,d)=>l.includes(d)).sort((c,d)=>d.score-c.score),r}async function o5(e,t){if(!(_n!=null&&_n.executor))return[];let a=(t.object.skipTime||0)>te()-_k,n=i5<(t.object.skipFrames||0);return t.skipAllowed&&a&&n&&P0.length>0?(i5++,P0):(i5=0,!ne.kernels.includes("mod")||!ne.kernels.includes("sparsetodense")?P0:new Promise(async r=>{let s=[e.shape[2]||0,e.shape[1]||0],i=ge.resizeBilinear(e,[O0,O0],!1),o=me(i,ze.tf255),l=Ws(o,[0,3,1,2]),u;t.object.enabled&&(u=_n.execute(l)),_k=te();let p=await t0e(u,s,t);P0=p,Y([i,o,l,...u]),r(p)}))}var Ep=["nose","leftEye","rightEye","leftEar","rightEar","leftShoulder","rightShoulder","leftElbow","rightElbow","leftWrist","rightWrist","leftHip","rightHip","leftKnee","rightKnee","leftAnkle","rightAnkle"],a0e=Ep.length,Np=Ep.reduce((e,t,a)=>(e[t]=a,e),{}),n0e=[["leftHip","leftShoulder"],["leftElbow","leftShoulder"],["leftElbow","leftWrist"],["leftHip","leftKnee"],["leftKnee","leftAnkle"],["rightHip","rightShoulder"],["rightElbow","rightShoulder"],["rightElbow","rightWrist"],["rightHip","rightKnee"],["rightKnee","rightAnkle"],["leftShoulder","rightShoulder"],["leftHip","rightHip"]],M5e=n0e.map(([e,t])=>[Np[e],Np[t]]),Ok=[["nose","leftEye"],["leftEye","leftEar"],["nose","rightEye"],["rightEye","rightEar"],["nose","leftShoulder"],["leftShoulder","leftElbow"],["leftElbow","leftWrist"],["leftShoulder","leftHip"],["leftHip","leftKnee"],["leftKnee","leftAnkle"],["nose","rightShoulder"],["rightShoulder","rightElbow"],["rightElbow","rightWrist"],["rightShoulder","rightHip"],["rightHip","rightKnee"],["rightKnee","rightAnkle"]];function Dk(e){let t=e.reduce(({maxX:a,maxY:n,minX:r,minY:s},{position:{x:i,y:o}})=>({maxX:Math.max(a,i),maxY:Math.max(n,o),minX:Math.min(r,i),minY:Math.min(s,o)}),{maxX:Number.NEGATIVE_INFINITY,maxY:Number.NEGATIVE_INFINITY,minX:Number.POSITIVE_INFINITY,minY:Number.POSITIVE_INFINITY});return[t.minX,t.minY,t.maxX-t.minX,t.maxY-t.minY]}function zk(e,[t,a],[n,r]){let s=t/n,i=a/r,o=(u,p)=>({id:p,score:u.score,boxRaw:[u.box[0]/r,u.box[1]/n,u.box[2]/r,u.box[3]/n],box:[Math.trunc(u.box[0]*i),Math.trunc(u.box[1]*s),Math.trunc(u.box[2]*i),Math.trunc(u.box[3]*s)],keypoints:u.keypoints.map(({score:c,part:d,position:h})=>({score:c,part:d,position:[Math.trunc(h.x*i),Math.trunc(h.y*s)],positionRaw:[h.x/n,h.y/n]})),annotations:{}});return e.map((u,p)=>o(u,p))}var D0=class{constructor(t,a){ue(this,"priorityQueue");ue(this,"numberOfElements");ue(this,"getElementValue");this.priorityQueue=new Array(t),this.numberOfElements=-1,this.getElementValue=a}enqueue(t){this.priorityQueue[++this.numberOfElements]=t,this.swim(this.numberOfElements)}dequeue(){let t=this.priorityQueue[0];return this.exchange(0,this.numberOfElements--),this.sink(0),this.priorityQueue[this.numberOfElements+1]=null,t}empty(){return this.numberOfElements===-1}size(){return this.numberOfElements+1}all(){return this.priorityQueue.slice(0,this.numberOfElements+1)}max(){return this.priorityQueue[0]}swim(t){for(;t>0&&this.less(Math.floor(t/2),t);)this.exchange(t,Math.floor(t/2)),t=Math.floor(t/2)}sink(t){for(;2*t<=this.numberOfElements;){let a=2*t;if(aa?a:e}function Lk(e,t,a,n){let r=a-e,s=n-t;return r*r+s*s}function p5(e,t){return{x:e.x+t.x,y:e.y+t.y}}var rn,s0e=["MobilenetV1/offset_2/BiasAdd","MobilenetV1/heatmap_2/BiasAdd","MobilenetV1/displacement_fwd_2/BiasAdd","MobilenetV1/displacement_bwd_2/BiasAdd"],z0=1,Ru=16,i0e=50**2;function Bk(e,t,a,n,r,s,i=2){let o=x=>({y:s.get(x.y,x.x,e),x:s.get(x.y,x.x,s.shape[2]/2+e)}),l=(x,A,y)=>({y:d5(Math.round(x.y/Ru),0,A-1),x:d5(Math.round(x.x/Ru),0,y-1)}),[u,p]=n.shape,c=l(t.position,u,p),d=o(c),f=p5(t.position,d);for(let x=0;x[Np[d],Np[h]]),i=s.map(([,d])=>d),o=s.map(([d])=>d),l=t.shape[2],u=i.length,p=new Array(l),c=u5(e.part,Ru,a);p[e.part.id]={score:e.score,part:Ep[e.part.id],position:c};for(let d=u-1;d>=0;--d){let h=i[d],f=o[d];p[h]&&!p[f]&&(p[f]=Bk(d,p[h],f,t,a,r))}for(let d=0;dt){o=!1;break}if(!o)break}return o}function u0e(e,t){let[a,n,r]=t.shape,s=new D0(a*n*r,({score:i})=>i);for(let i=0;i{var i;let s=(i=r[n])==null?void 0:i.position;return s?Lk(a,t,s.y,s.x)<=i0e:!1})}function d0e(e,t){return t.reduce((n,{position:r,score:s},i)=>(Wk(e,r,i)||(n+=s),n),0)/t.length}function p0e(e,t,a,n,r,s){let i=[],o=u0e(s,t);for(;i.lengthh.score>s);let c=d0e(i,p),d=Dk(p);c>s&&i.push({keypoints:p,box:d,score:Math.round(100*c)/100})}return i}async function c5(e,t){if(!(rn!=null&&rn.executor))return[];let a=$e(()=>{if(!rn.inputs[0].shape)return[];let i=ge.resizeBilinear(e,[rn.inputs[0].shape[2],rn.inputs[0].shape[1]]),o=fe(me(He(i,"float32"),127.5),1),u=rn.execute(o,s0e).map(p=>_e(p,[0]));return u[1]=Da(u[1]),u}),n=await Promise.all(a.map(i=>i.buffer()));for(let i of a)Y(i);let r=p0e(n[0],n[1],n[2],n[3],t.body.maxDetected,t.body.minConfidence);return rn.inputs[0].shape?zk(r,[e.shape[1],e.shape[2]],[rn.inputs[0].shape[2],rn.inputs[0].shape[1]]):[]}async function Vk(e){return!rn||ne.initial?rn=await Ee(e.body.modelPath):e.debug&&K("cached model:",rn.modelUrl),rn}var lr,c0e=["fgr","pha","r1o","r2o","r3o","r4o"],Ut={},f5=0;function Hk(e){Y([Ut.r1i,Ut.r2i,Ut.r3i,Ut.r4i,Ut.downsample_ratio]),Ut.r1i=Be(0),Ut.r2i=Be(0),Ut.r3i=Be(0),Ut.r4i=Be(0),f5=e.segmentation.ratio||.5,Ut.downsample_ratio=Be(f5)}async function m5(e){return!lr||ne.initial?lr=await Ee(e.segmentation.modelPath):e.debug&&K("cached model:",lr.modelUrl),Hk(e),lr}var Gk=e=>$e(()=>{let t=_e(e,[0]),a=ae(t,ze.tf255);return He(a,"int32")});function h5(e,t){let a=e?Gk(e):nr([t.shape[1]||0,t.shape[2]||0,3],255,"int32"),n=t?Gk(t):nr([e.shape[1]||0,e.shape[2]||0,1],255,"int32"),r=at([a,n],-1);return Y([a,n]),r}function h0e(e){return $e(()=>{let t={};return t.unstack=Ta(e,-1),t.concat=at(t.unstack,1),t.split=ka(t.concat,4,1),t.stack=at(t.split,2),t.squeeze=_e(t.stack,[0]),t.expand=Gt(t.squeeze,-1),t.add=be(t.expand,1),t.mul=ae(t.add,127.5),t.cast=He(t.mul,"int32"),t.tile=Gr(t.cast,[1,1,3]),t.alpha=nr([t.tile.shape[0]||0,t.tile.shape[1]||0,1],255,"int32"),at([t.tile,t.alpha],-1)})}async function jk(e,t){if(lr||(lr=await m5(t)),!(lr!=null&&lr.executor))return null;Ut.src=me(e,255),f5!==t.segmentation.ratio&&Hk(t);let[a,n,r,s,i,o]=await lr.executeAsync(Ut,c0e),l;switch(t.segmentation.mode||"default"){case"default":l=h5(a,n);break;case"alpha":l=h5(null,n);break;case"foreground":l=h5(a,null);break;case"state":l=h0e(r);break;default:l=Be(0)}return Y([Ut.src,a,n,Ut.r1i,Ut.r2i,Ut.r3i,Ut.r4i]),[Ut.r1i,Ut.r2i,Ut.r3i,Ut.r4i]=[r,s,i,o],l}var ga;async function g5(e){return!ga||ne.initial?ga=await Ee(e.segmentation.modelPath):e.debug&&K("cached model:",ga.modelUrl),ga}async function Xk(e,t){var r;if(ga||(ga=await g5(t)),!(ga!=null&&ga.executor)||!((r=ga==null?void 0:ga.inputs)!=null&&r[0].shape))return null;let a={};a.resize=ge.resizeBilinear(e,[ga.inputs[0].shape?ga.inputs[0].shape[1]:0,ga.inputs[0].shape?ga.inputs[0].shape[2]:0],!1),a.norm=me(a.resize,ze.tf255),a.res=ga.execute(a.norm),a.squeeze=_e(a.res,[0]),a.alpha=ge.resizeBilinear(a.squeeze,[e.shape[1]||0,e.shape[2]||0]),a.mul=ae(a.alpha,ze.tf255);let n;switch(t.segmentation.mode||"default"){case"default":a.input=_e(e),a.concat=at([a.input,a.mul],-1),n=He(a.concat,"int32");break;case"alpha":n=He(a.mul,"int32");break;default:n=Be(0)}return Object.keys(a).forEach(s=>Y(a[s])),n}function L0(e,t,a){var u,p;if(!t||!((u=e==null?void 0:e.config)!=null&&u.validateModels))return null;let n=["const","placeholder","noop","pad","squeeze","add","sub","mul","div"],r=["biasadd","fusedbatchnormv3","matmul","switch","shape","merge","split","broadcastto"],s=[],i=[],o=t.modelUrl,l=t.executor;if((p=l==null?void 0:l.graph)!=null&&p.nodes)for(let c of Object.values(l.graph.nodes)){let d=c.op.toLowerCase();s.includes(d)||s.push(d)}else!l&&e.config.debug&&K("model not loaded",a);for(let c of s)!n.includes(c)&&!r.includes(c)&&!e.env.kernels.includes(c)&&!e.env.kernels.includes(c.replace("_",""))&&!e.env.kernels.includes(c.replace("native",""))&&!e.env.kernels.includes(c.replace("v2",""))&&i.push(c);return e.config.debug&&i.length>0&&K("model validation failed:",a,i),i.length>0?{name:a,missing:i,ops:s,url:o}:null}var Rp=class{constructor(t){ue(this,"instance");ue(this,"models",{});this.models={},this.instance=t}stats(){let t=0,a=0,n=0;for(let s of Object.values(ha))t+=s.sizeFromManifest,a+=s.sizeLoadedWeights,n+=s.sizeDesired;let r=n>0?a/n:0;return{numLoadedModels:Object.values(ha).length,numDefinedModels:Object.keys(this.models).length,percentageLoaded:r,totalSizeFromManifest:t,totalSizeWeights:a,totalSizeLoading:n,modelStats:Object.values(ha)}}reset(){for(let t of Object.keys(this.models))this.models[t]=null}async load(t){var n,r,s,i,o,l,u,p,c,d,h,f,m,g,x,A,y,b,w,S,C,E,_,$,M,I,N;ne.initial&&this.reset(),t&&(this.instance=t);let a={};a.blazeface=this.instance.config.face.enabled&&!this.models.blazeface?U9(this.instance.config):null,a.antispoof=this.instance.config.face.enabled&&((n=this.instance.config.face.antispoof)==null?void 0:n.enabled)&&!this.models.antispoof?fw(this.instance.config):null,a.liveness=this.instance.config.face.enabled&&((r=this.instance.config.face.liveness)==null?void 0:r.enabled)&&!this.models.liveness?Aw(this.instance.config):null,a.faceres=this.instance.config.face.enabled&&((s=this.instance.config.face.description)==null?void 0:s.enabled)&&!this.models.faceres?uw(this.instance.config):null,a.emotion=this.instance.config.face.enabled&&((i=this.instance.config.face.emotion)==null?void 0:i.enabled)&&!this.models.emotion?sw(this.instance.config):null,a.iris=this.instance.config.face.enabled&&((o=this.instance.config.face.iris)==null?void 0:o.enabled)&&!((l=this.instance.config.face.attention)!=null&&l.enabled)&&!this.models.iris?K9(this.instance.config):null,a.facemesh=this.instance.config.face.enabled&&((u=this.instance.config.face.mesh)==null?void 0:u.enabled)&&!this.models.facemesh?ew(this.instance.config):null,a.gear=this.instance.config.face.enabled&&((p=this.instance.config.face.gear)==null?void 0:p.enabled)&&!this.models.gear?ww(this.instance.config):null,a.ssrnetage=this.instance.config.face.enabled&&((c=this.instance.config.face.ssrnet)==null?void 0:c.enabled)&&!this.models.ssrnetage?Tw(this.instance.config):null,a.ssrnetgender=this.instance.config.face.enabled&&((d=this.instance.config.face.ssrnet)==null?void 0:d.enabled)&&!this.models.ssrnetgender?Rw(this.instance.config):null,a.mobilefacenet=this.instance.config.face.enabled&&((h=this.instance.config.face.mobilefacenet)==null?void 0:h.enabled)&&!this.models.mobilefacenet?Fw(this.instance.config):null,a.insightface=this.instance.config.face.enabled&&((f=this.instance.config.face.insightface)==null?void 0:f.enabled)&&!this.models.insightface?Bw(this.instance.config):null,a.blazepose=this.instance.config.body.enabled&&!this.models.blazepose&&((m=this.instance.config.body.modelPath)==null?void 0:m.includes("blazepose"))?S9(this.instance.config):null,a.blazeposedetect=this.instance.config.body.enabled&&!this.models.blazeposedetect&&this.instance.config.body.detector&&this.instance.config.body.detector.modelPath?I9(this.instance.config):null,a.efficientpose=this.instance.config.body.enabled&&!this.models.efficientpose&&((g=this.instance.config.body.modelPath)==null?void 0:g.includes("efficientpose"))?M9(this.instance.config):null,a.movenet=this.instance.config.body.enabled&&!this.models.movenet&&((x=this.instance.config.body.modelPath)==null?void 0:x.includes("movenet"))?Mk(this.instance.config):null,a.posenet=this.instance.config.body.enabled&&!this.models.posenet&&((A=this.instance.config.body.modelPath)==null?void 0:A.includes("posenet"))?Vk(this.instance.config):null,a.handtrack=this.instance.config.hand.enabled&&!this.models.handtrack&&((b=(y=this.instance.config.hand.detector)==null?void 0:y.modelPath)==null?void 0:b.includes("handtrack"))?bk(this.instance.config):null,a.handskeleton=this.instance.config.hand.enabled&&this.instance.config.hand.landmarks&&!this.models.handskeleton&&((S=(w=this.instance.config.hand.detector)==null?void 0:w.modelPath)==null?void 0:S.includes("handtrack"))?vk(this.instance.config):null,(E=(C=this.instance.config.hand.detector)==null?void 0:C.modelPath)!=null&&E.includes("handdetect")&&([a.handpose,a.handskeleton]=this.models.handpose?[null,null]:await mk(this.instance.config)),a.centernet=this.instance.config.object.enabled&&!this.models.centernet&&((_=this.instance.config.object.modelPath)==null?void 0:_.includes("centernet"))?N9(this.instance.config):null,a.nanodet=this.instance.config.object.enabled&&!this.models.nanodet&&(($=this.instance.config.object.modelPath)==null?void 0:$.includes("nanodet"))?Pk(this.instance.config):null,a.selfie=this.instance.config.segmentation.enabled&&!this.models.selfie&&((M=this.instance.config.segmentation.modelPath)==null?void 0:M.includes("selfie"))?g5(this.instance.config):null,a.meet=this.instance.config.segmentation.enabled&&!this.models.meet&&((I=this.instance.config.segmentation.modelPath)==null?void 0:I.includes("meet"))?t5(this.instance.config):null,a.rvm=this.instance.config.segmentation.enabled&&!this.models.rvm&&((N=this.instance.config.segmentation.modelPath)==null?void 0:N.includes("rvm"))?m5(this.instance.config):null;for(let[O,L]of Object.entries(a))L!=null&&L.then&&L.then(B=>this.models[O]=B);await Promise.all(Object.values(a))}list(){let t=Object.keys(this.models).map(a=>{var n;return{name:a,loaded:this.models[a]!==null,size:0,url:this.models[a]?(n=this.models[a])==null?void 0:n.modelUrl:null}});for(let a of t){let n=Object.keys(ha).find(r=>r.startsWith(a.name));!n||(a.size=ha[n].sizeLoadedWeights,a.url=ha[n].url)}return t}loaded(){return this.list().filter(n=>n.loaded).map(n=>n.name)}validate(){let t=[];for(let a of Object.keys(this.models)){let n=this.models[a];if(!n)continue;let r=L0(this.instance,n,a);r&&t.push(r)}return t}};function Zk(e,t,a,n,r){var o,l,u,p,c,d;let s=0,i=[];for(let h of e){let f={id:s++,face:h,body:null,hands:{left:null,right:null},gestures:[],box:[0,0,0,0]};for(let b of t)h.box[0]>b.box[0]&&h.box[0]b.box[1]&&h.box[1]+h.box[3]f.body.box[0]&&b.box[0]+b.box[2]f.body.box[1]&&b.box[1]+b.box[3]f.body.box[0]&&b.box[1]+b.box[3]>f.body.box[1]&&b.box[1]+b.box[3]{b&&b.length===4&&(m.push(b[0],b[0]+b[2]),g.push(b[1],b[1]+b[3]))};x(f.face.box),x((p=f.body)==null?void 0:p.box),x((c=f.hands.left)==null?void 0:c.box),x((d=f.hands.right)==null?void 0:d.box);let A=Math.min(...m),y=Math.min(...g);f.box=[A,y,Math.max(...m)-A,Math.max(...g)-y],(r==null?void 0:r[1])&&(r==null?void 0:r[2])&&(f.boxRaw=[f.box[0]/r[2],f.box[1]/r[1],f.box[2]/r[2],f.box[3]/r[1]]),i.push(f)}return i}var B0=` /9j/4AAQSkZJRgABAQEAYABgAAD/4QBoRXhpZgAATU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUA AAABAAAARgEoAAMAAAABAAIAAAExAAIAAAARAAAATgAAAAAAAABgAAAAAQAAAGAAAAABcGFpbnQu bmV0IDQuMi4xMwAA/9sAQwAGBAUGBQQGBgUGBwcGCAoQCgoJCQoUDg8MEBcUGBgXFBYWGh0lHxob IxwWFiAsICMmJykqKRkfLTAtKDAlKCko/9sAQwEHBwcKCAoTCgoTKBoWGigoKCgoKCgoKCgoKCgo KCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgo/8AAEQgBAAEAAwEhAAIRAQMRAf/E AB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAE EQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZH SElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1 tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEB AQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXET IjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFla Y2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG x8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A+qaKACigApGOKAML Xp8xlF5A7V4X8RtYs7PzfNImnx8sa8Kp9z3q2tEgp6angWs62ZZ5CTGoJ6DArGNz5p+UrID6EUrF PUlW1EuN0XNW7PQ2L5j3JnoKXN0KijqNP0eYoqXBdgPuuo+ZPeupisWn2Jd4+0r924XgsQOCff3/ AJ1FzRKxDqGii6m3siiQ8F1XGfXI6YNWLfRbiRQMkcZI9fpTDluT2/h6Qy8gDPbtmtG38JeY480Z 5zSLUTZg8M28YwYxjAArXtdPt402qgHbpSaLWhma3o0Uqk7Nx9DWLaaVblgPs6qRyds2M/gRSQp9 zZOni2iWS2hlQ+kjYz9OMGrdjq89vIPPVhj+8M/lQyDq9P1WOYBlMZz1AOD+VdDaTiReOKulK0jO tHmi0WDTlr0TyxRVhT8tJjIX+9SUxHXUV553BRQAVBcPhSBTSuxPY86+IGti0s5I7dsORy9fM3i6 8e8mfDO5P90ZrWWiJicNPpZZtxV/xrW0jQt4DOv6Vk2dEEdTY6BHuB25rpbPSo0QARjP0qTRI17W wA/hFaMWmoQMgflQXYsDS142rU9tpqqenfNA7GgtihxkdKuRW6qMY/GkDZY8sY4Ap4hXbyB+VArk EtuH4wPyrk/EGkOm+a3jw3suRQLc5i38SX9hJ9nnY+XnBUdPyNdFY6pa3KkkAE9l6f8AfJ/pSJT6 GhDmI+Zb4ZRycdv6ium0nUhKFydrelTsNnS2829RnrVgV6NKXNG55lWPLIM81Op+WrZkRMfmNNzT A7GivPO4KKAEY4XNYWt3vkwPg4OK0giJdjw/xrqhm87Zs8tc7pX5A+leSajf6aHYJ50kn4AZpTep rBWRm2Vobm4BXfyehPFdnpmnBFUY5rI2SN63tlToK0YI+KZpFF+3QdavwoKTLtoW0Toaswpk5pCb LCxipAhoIuP2dKevHXoaYDylRyxhlwRQI4nxVoCXWZI1GfpXGtbSWjYPGP73+NIGupt6TqMsLruZ ih4xnP5V09mQ+JLd8gn0xSYJnVaVdkook69K34zuUGunDS3Rx4qOzHVIp4rrOMY3NJQI7GivPO8K KAILt9kZrz3xlebYiu8KCCWb0XvW0NFch6ysfO3jLVjfXLIn+pQkKorl7WxNxIPl71g2dUUdpo+l pBGvHPet23iC8ihFosrxirkHQUFo0IF4FXI1O726CpKLacCrMJoJLYHAPpTwucHpSRJJ5e4AZI9x UqpxzVpCuOC8cUpQUMRnXttuB4rjNdsYyeVwfXpmpGmcvcQyafMCFJjPY10eg34BUg4DcZP8jUO4 HaRq3lLNF+IHet7R7jz7c56rwa2wz9+xhiVeFy/T1PFegeaNPWigDsc0ZrzzvDNIaAM7VpNqdegr xL4l6kywyRhseZ19lrdfAZL4jxYg3Fw20d63tJsdrDI5rm3Z3R0R0Mce1eKnQYAplIkWrMJ45oZS NO3PHbNXIyfpSGWowSOasxLUiZdjFSqtNEMkUemKlAGKsRJjAppFAiORMjmsTVrNZEO4cfSoZSOD 1eJ7WXBUzQZ+7nkfSo7e2Ei+ZaMzxntjBX2NSU1Y6/wxqojiEFzkA8KTXYaUoWRyv3W5rSjpNHPX +BmpSg8V6J5gUUAdhRXnneFFAGHrTfu5PpXzj8S70/aZtxzztXFbv4DKHxHI+H4GZiz9zxXXW8G3 GBXMjvLRXAx0oPGPSmMVeOnWrMTYpFI0bcg1fh54xmgovRcD3qxETSIZcRvzp+/BpEkqsBUqsM9K q4Em4Gkxk0yRGXrVW6i8yFhkg+tJjRxGsWrxllkUMh9eK5uMz6bcebbnfG33kPcVkay2OntPKuo0 nhXI67c8qa7Lw3c+adjcEDGK1paSRhVV4s6A0or0jyRRQ1AHX0V553hRQBz+vNtt5z3xXzX8Qbdm uic5YnOMdK3l8JnTXvlbwpYl+WySOgrp5YfLOOB9O1c62O7qQkc+9RsKChFPWp4DluOlSykaNruH ArUgHShFNF2NT1qxGO3NBmyxGcE1N2560CFzjrUysO9JAPDDjFOVuKoQuSRTWouBkazbCa3cd8cV wF7IISQccHBzUSWpV9C3o1x5b5GAjdQD1rs9DjC3kckbEhqKfxIzn8LOupRXqnkPccBSkUAzraK8 87wooA5rxMSI3HqK8B8bQl9Q8sffY5b/AAraXwkUviNrw9pH2W1ViMMRTdRjw4HpWNtDti9TPc4P FQs2M5qdyyMHLcfjV63HTAoBGtap0wK0YxigpsuRDtVhVYd6GQydVwwIqdRnqKCR23I5pCMUW6gD YNKuetAEise9KTxQBWuFyhrznxNZkXjFeN3I+tTIZg2OqmzmxNF0PO3vXp/g2+hukVl4zyPanTXv JmVR+60dpThXpnlPceopWFAbnV0V553hSGgRynjC5FujOey14Ssp1HxNmTnc+a3kvcIpv37HoEYQ QmMdVHSsnVbYJF5jVk0dsNzlruVIsl2wKxbjWrVHILjg1CRbZJb+ILHPzyhfStODWLQgFJFYd+el UJM27HUIXxhga1Y5lLVLKLkMnoauxnPPrSEx7ShF+Y/n2qrc6xBbhizDAqkK1zJuvG9nbg8ZA681 ly/Ei052RO3uKAsZlx8QGd8xxvt9Aa1NH8dK7AXMcip64zigdkdrZX8F7EJLdwwNXMkrz1qRMRly CK4TxmpidWI49felPYSOMmi80NIoOV6qRzXYeA5SskYPfirpfEjGr8LPWVHyD6U4CvQPL3ZItOYc UDOoNFeed4Uhpks4H4iE/Z5MeleMeGULeLgjds10S+BGdL+Jc9OSBU2Huc5Nc74yvUtrcDBrJnZF 63PJdXvLy/lKWw46bvQVz82jXhkLO5Y+9ZlsYthcRnbIjY9R3q3awTRkEM3WmJI6C0ea3dGRsr1x XY6TqW9FLHnjrUs0izpLK5DDjofSta3ckH09KRUkZuuTvFGdvPauE1Y3U6Mqbssf/rUxHPTaJPK2 ZmJPbBqzY6DCZh5xJC9s9aBJHU6dpemJjfEmfetJtI0+VPkUr/unFOxdiextHs33W07YHQHk11mk Xb3KbZ1xIvcd6LEyWho4Nct41sTPYb16ipexCPPZN+wYGCvH1rrPAEJmvkPoc1VL4kZVvgZ6yFwK cBXoHkkqinFaVyzo80GuE7WJRQSziPiGdthK5HQV4x4J/wBI8WPIewNdEvgRNL42emO/yj1UHNef eNpRczbC+I17DvWT2OqJxc0sMK4TCisy41q0hfEkqj8aixdwTXNOlwvmqD9anS9tXH7uVG+hosO4 /wC0oOhrR0+6G4YNIEzsNEuCxAPNdjZruA4xxUmjINSjURksOlcbqFykbnjFA1sYGoassaknCqO5 rl7rxhGm7yBnBxuJq0rkSlYpw+NLlsfd5P8AerVsvHEqSBHwPVgcgVpyMyVXU3rXxcHYETAk+hru /DWti6ZSTyOKzZqndHaxvvUGq2rQ+dYyqR24qWI8dvbr7LqDxyDAzXpvw6FvIxePGSM06Xxoyr/A zviKFHNegeX1J41zUhXioGbuaSuM6wpCaBHG/EcA6HN/exxXjXw2jL67cv8A3Qa6H8CFR+NnoWpO I4XI44rxLxrqjQzSEsQM1gdSPM9U1uR1YbmWIdXHf2rmpIb67YS28UrRlsLI3c/jW0VZGUpO5pW1 jfLNOjahawzwReYI5cjzMkDavHJ5/SrVv9uhtPtVxCPLBwzxnlT9KGghLU3tKvvPjHzbl7EGuisJ GRxWLOg7nRXJEbDjmvSNK+aFSfSoZr0KutRkphc4NcRrdkVjL9aVio7Hk3iqS8ubhrWzUlsZY9kG cZNc5D4aee5MclzJIFTzHAO0MfatqSOWu7bFS1srDUZEis0vIZoUxPvfcC+4/dx2xjr712XiTwXb WmlQ6hol3cRhoFd4rlg3zY5wR0GelavQwjq7GD4etdVvSnk2wAB+9v8A8mvcfA2kXiRo0/UdcDis ZnTTulqeoWqbUAJqWUb42X1FZlnjfjSwlGrr5S/eNdD4RkvLAAQ4yRyaUZcruVKl7TQ9I0G+mnzH ckFwM8VuIK7ac3KF2eXiKapz5UWYxipNtMyNejNch0jSar3cjR27uoyQCRVRWom9DxTx54gu5fMi lbKdMVjfCZPNlv5v9rFbVHpYqjGzbOn8SzFI9o715L4u0r7arYzk+lYdTqSujy7U/C0u4vHk+WwO xuh9q3J9dgvbdVukMV1EwbDDgn04rZMwlHoZ+orZ6hfQ3RWVnQYCgZAq+8U0ln5NtBsV2yxYcfgK JtW0CnB31LlroVwJ1nQLGDjeP7w+lb0dsFxjrWB0tHS6NuWPJ6A16ToUm63T3Gallr4S7cxiTjrX PaxaF7dlVeSMUhxZ5jd+H7qCa4eF3DSE5x3zXN3Wk6jbyeaiFWUY6ZyPStYS5SalPmVipFbX0E4c W0alvmPHJrag0rVvEE6LdljGpG2NRtQD+tW5XMI0uU9M8NeFo9PiQhecDIIrtrOMIoG3H4VlJm9t C6CB06VPGM1IHLeItGS6uw+ORT7e3jsbQvj7gzUNam0JaWE+HN7NqOqX80n3FO1RXo8YzXdS+BHk 4z+KyzGPapcU2YIv7qQtiuaxvcaWqG4O6FwfSrS1JbPnrxoxkv7qIfejcitj4V2f2exumI+8+aKn xHTT+G5d8Txlm4rjLxMsQwzWT3OiK0Mm6sEkVsAcjFc1d+FEmlGwEDPQVopaEuOpr6f4ZWNAu3tW vHpAj5ZQcUFIWaDjGMVUMQ3cVDBmvbhY7QAV2nh+T/R1yeKhlrY31+b61FcQK6nIoJMi401WblRi qr6PCw5UYq9y+YgOgWzNkRrx3xWjp+nx2v3FQcelAbmko9anQ4GBUNisPHWr1qMrQhS2K11HvmYV hamcxSRZ5xRIqluS/DKAQQXZxyXrvo2FdlL4EeZjH+/ZbjNSZpswLNBrE1Gt7VE4ODVIlnh/j61F j4lmeTGyUbq6LwdEqWbeX0YbhSqfEddP4Bddj4JIrhL5d8h7VjI6oLQqKNzelWre3yc4/ClFjaL6 wqBxxUUxwCKu5BmXRA6c+9ZjP83FSBoQuPs4BrsNBlUW659KmRrDY6G1lyQtW3Hy0lqQ1qVJnAbm oy3b9KYJCqRj3o4zRctIlhjLHmpSuOBRbQOpLGpPFaES7UqkZzKN1KsEc87/AHUUmvPLTVGv72aQ k7WJwKmRrQ3ud74Ltilgz4++2a6iNDXdS0gjyMU71my7GpqTbxSbMki3SViajTTHqkSeR/GeyZmg nQHkEE1S+F+oPPavBL96I4/Cia1udVF+4dVrkW+Fq8+v4tjMDWUkdVJ6WM0cNV+F+MVmjUcZgqnP 1qpNNnkcVRLiZtxIS1UzzIF7mghlxUZpVQdq6nTVdAoAOKzkbQWhvwM6gMM1twOJYx3NOJE11Kt1 H1/pVVlwBkk+9NocXoOQ45FPj+fkUJFF2NSB700v/hTEty5ZpkjvVyUgcCq6GM9zC14/8Se6GcZQ 1574Xs5WkI2HBPHFQ1dm1KSSZ7Rotn9l0+KPHIHNacae1dy0Vjxaj5ptlhVp+2s2CJ9ppCKzuWNx zSFc1SYrHNeNdIGpaYw25ZeRXmvheyk0jVpEdcLJ0q3ZxNKTa0O3vQHg/DNcHrsJDmsmjspnNzNt fFIJ24GazOhC+azDmgZIOOKBsp3J2qSaZodubq58yQ4QAnmhGT3NO18pb7BORmu205LfYpyKVkWp Oxr5gKYWoIZWgfGfloFq1qTPLubnGO1RPtxg4P0oBAkY/hBz6VNDDkZ6AU0W2WSdqkdKr9ZOaGSj VtcLHmnOcgmmYvcz7mBLy3MbdD1q9ouiRK6bUAVeelOC1InPlidSsWMDFOCEdq3uefykqrinYqGy rFvApMVka2DAowKAsMkRXQqwyDXn/iWyitNQ3qPl6itIvRoF8RXinW4tQ6HI6GuW8SIVBPalc6qe 5x9x97r3qruwTjrWZ0ksZ9TUmcDNAmZ9/wAoao63rR0+w22MLPtAzt6mghmfofiB76LdJBJBIp5D d/oa7bSdWLIPnpDi9TM8TeKdas51XTbIyxd3J/pXS+E/EFxqNoFu7do5OmD60maHWrnZyDRkn/69 MlEyOR0xntVoNx+FUgYjPxg4FLCuWDZyKQr2RoRnP0qO+nEFpJITgAUzLqZnhu6+0rknOTXpOmwJ Fbrt5yMmnHYyr6Oxb2ijaKLnPYMClwKQWK3n0hn+lachHOJ9pNNN0apQFzsY10a4v4hXQh0xpieQ MA1XLZNjhK80cT8OdV+3Wl3A7ZZJCw+hrR1qLcjZ/CsbnfHRnFXseHJArOYYbrUs1uPhYbuatqFP ByfSkMq3UIINYkto+87Tx6GkSxfsDbflGD7CtTw/pk4nzITtPIFMFudsukh4Rxz71paTpKwP5jcn 0qTRy0NORMDgVCqewoJTJgAoxjntTiTu7fWmFxAcnn1q3EPl+X8KZMi4gKqB1Peob/Tv7Us5bfeU yOoq4R5nYxqT5I8xieH9J1DTbvyJELRg8ODwa9Ms5mSFV9BWiptbnNVrKdmif7Q1KLg96XIZc5Is pNL5pqeUrmMtZs0jzV08phchaY00zH1p2ZNxjS1g+LdJOt6U9ssmxjyGp2urDjLlaZzng/wUPDqz TSTmWeTrjpVjVk3Rvjr2rnqQ5dDvo1XUd2cTqSNk9OKxXGCeKxZ1DAxHTr2q5C/y8GokUhsz54qu uCxzSQjQ0+FZblR2ro4bZYiMVQ0dBb7Qi5x0qzuG5QOh71LYErDufpSeWrHnimIXbjkUjLkH1Hem gGxryc+tXI19KYmWegq9YLiLJ7mtqS945cS7QsWehqxA9dEjz4krPSxyZqbFFhGxUm6smjRM55Lk HvSvNxXTY57kLT+9MNwKdhXGm5FIbkU7Bca1wMEVhaiuQcVhXWiZ14R6tHGanGBI2OtYkqEHjgVy s9ErEeo6UBsHipKEZs5qpPdRxcbhx70NCSuybTNWihc5brW9Fq6vjMnFSdEIdDRi8RRKygZbHFbu m6nb3RA3gMegNJhOm0jbXGOoxTuCc1Rz3FyoGKawz9KaAVcZqeMgCmIkB4FaUTbYwB6V00Fuzixb 0SFMuDU8Mlbs4UPeXHeiOXkUrDuXYnyKk3cVk0ap6HMxxketSMhrcwRC0dMMZFMQ3yzSeVQAeUaz 9Vj8uPd271nVV4m+GdpnHX67pCeKyLtBtNcR6xlk9RVeWTb3qRnO6trgttyIfm71z7ai8j7/AJmN DNqUVa5Yi1AnjynHuBV+11YJhWWXcP8AZNSzqgmaEerSsf3NtIQP4mGKtRavdRgMIpVI9KjU0a7n R6T43uYQI7qN2Tpkqciu503VVuQGAYZHQjFVc4alPlZrpKGAznpTwxOc9+lWjIlUACnM4XApiLNk nmvnsK0NvpXZRVonmYqV52GsmanhXitTmFkSiJTSAvwrxUxXIrJ7miOfjf1pzNWxkRlqYWpgJupu 6gQbuahvIxPA6eo4pNXVioS5WmefakGhndH4INZs5DJXA10PaTurmLO21uKpSZqGMoXGnRzBiyjd 9Kx5rcQS428fSkjanLoaOliHGZFB56VswW+mtPufcBsGOAfmxz+tFkd8HpoaUx09FAtFY8DO71qb Sms/Nb7RbecG6AEjFLS5c78t+p0djpVs9wsyQiJAdyr1rW+zqjErzSe559Sbk9S3C+MA1bjbgE1S MSXzMVG0vNUI2tPKrAuCMnrVzNd0PhR49W/O2xrHmp4TxVMzQshpIzzQBehqesnuaI5VGzT2bitz FEbNTC1ADS1JupgG6l3UAc14s04yR/aYRll+8BXCtLncDXFWjys9TCz5oW7GddH5qqNzWDOgQnC8 VSuo1kHzAGkPYopEY2+RWxV23Vzj5G/Kg3jWaNazhZuqNXS6TaKhB2c0jR1nJWOlhOxRxU4YkCgx Y0OQatQyDbyaaFYe8uF4NY3iC9ltbVGj43NTIL3h7WzMihjzXVQXYYDdW9Cf2WcOJpfaRZ3g9KsQ mupnCLIabGeaAL0LcVY3cVmzRHIxtUhetzEjZqjLUAIWpN1ArhupwagAfDKQ3Q1594v0c2bm6tx+ 5Y8j+6ayrR5onThp8s7dzkZjuqAAmuBnqC7c0iwgtzSA0rWzjfGRW3ZadDu4AoNYo2rfS4v7orSh 05UA2r0pDbsTm29KRottBNyJ0wpJ9KhD7f6U0ikNWffIFBz60zVUW52ow4UcUN6EPcx44WsbgOmd ua7TT5Bd24KHnFKnLlZFSN4koluLdueRWvp14swweG9DXoxldHlTjYtzGoo25qzEvwtUxas2jRPQ 5CNqkLVsYoYzUzdQA3dSFqBBmnqaBhuqhriCXTpVIzxUz+Fl03aSPI9QTypW2/dz0qKNw3SvOPZR Mqin8VLKRcs3O4Cuk0w/MDjt1NBtHY6O2IIHY1pxgFaETIRwMkjtVSUEk4570MlFW5bap6dKzWm8 1tqH8aY+hp2FvGoGayNevVt7/ap4xzUvYjqTLtvLPcvJxSaVcyWsxTnFZlnT2t15xHmCtOBYwQy4 B9q7cPO+jPPxFO2qLEj5HWo42+aus4HpoX4W4FTF+KlotbHII9SFuK0MUNZqiLUDE3UbqBBupwag Bc1DefPbyD/ZND2KjujyPWlKzuPesRZjHJXms9lMuw3StjnmphKDSLTJ7OfE3JrpbO4GQc9qlnRA 3LO82k5NbFvdADkjBoCSHyXIIIzgVQvdRigT7wzjgUzO1jHknlvG7qnp61etYFQDIpCZoqVijzXn 3iC8EmsOuaCGb/heR/s0ijkVv6fbxy3QMg5xmsnuX0Ldzut3+UYTPWk+2GJSe+M1pFtamcldalmx 1eO4XaThhWnC+TXqR2PHqL3maUJ4qRjxSEjj42qXdxVmaGs1MJoATfSbqBAG5p6mgAzTJTmNvpQU tzzHXY83D/U1zF5FhjgV5r3Pa6FMsV5HWnLe7RhqBRdmTwagN2d2K2rPU1C5LAnPrUs6Iysbdrq6 f3gK0BrUKj/WClY05iM6xLOcQAj3NT29uznfKSzHuadzNu7NSBFjHNSm5VO9IRnajqoWMhTzXFtA bvUfMduSeg702Qz0rS7FbTToQFwzjJqaGTFyfK5PQViyzUuFmuIdgGABya5u/vTaN5cnUHFUmLoZ zyskwlgJweSK6zQdUEwVJeGr0aUrxPLxEfe0OrhPAqVjxWhznGRtUwatDK4jNxURbmkAm6jNABup 6tQAFqhupNtu59qUnZFwV5JHnWsHdIx96w5lz15rzT2uhRmt85xWbcxMnUGmZlB0bdxmrNvFIcfM 350mWjbs7YkDJY/jW5ZWW4jikWkdNp9mqYJFaJdEHHakUULu/VB1rLn1Ld/FgetMGYd/qWSQmSa0 /AemS32pfa7piLeLkg9z6UmQtz0W7uQ2cZx0A9BVzR7cAea6j2rPqX0L99KRat5A6Dk1wOoKZ52a YfMORTYRLujiGWEq6/NWza2yKQVHNdOHerRy4laJo6TTnbbtb8KuM3Fdh5z3OJjbmpt3FaMxAtUZ agBN1GaQBzTwaAAms3VbjERUGsa07RsdeFpuUuY4jUjljWTKK4j02RE4IpJYFk6imQkVl0xWarsO mAEcUi0bNnZBR0rWtoguMCkUi21wI161mXuocEKaYXMS4u+pY/hVCSWSY4HT0pEmlouiSahdpEBl mOceleiwWcNjClvHgJH97Hc1EmVFFi3Czy7mwIl/WtJbjP7uLgd/apQ2VNVvtsBhiPzdK5S4nAuR nqOCaTGi9pcytPlU+XpmumtWII44rah8ZjiNIXRuWeNvvViQ/LXpJWPJbu7nCRvVkNxVsxBmqJmo EPiXca0YLMuOlJsuKuPlsSi5IrNuG8s4HWs5VEkbwoOTKsk+FJY4rC1K53k1xTk5O7PSpwVNWRzt 4cms+WpKICtSLTETQj5q0YeBSGiys23pUguGxQMq3E59ayrm4x3yaAKiRtO2WPHcmhruKFxFajzZ ScA44qRHoXhuMaLpxaUg6hcDLMf4F9KlhuDeXGASIl+8azZslYma68y48m1+7nFW5rtbRNhb5z1p iMKbUg0zuW4A4rPgb7VdKXOMmpA7HRbMS7nUYiUda0lkQOBngVrS+JGdbWLRt2bAx5BqeQ/LXpnj PQ4GJ+ashuK0MhWaoWcA0AaOmASMK7jRNPWYBmHyiuepO2x10qfcv6vYxCzYqoGK4HVYVTJrmb5l c6oaM5TUJ8EgGsG4kLNUHT0M64OaqMMikSRsuKbnFMRLG3zVehOaGNE445NNlnVFpDMu6uie9Vo1 8z5mOAOST2pDK91cNN+5tsrH3PrW54a06KxT7fdrlh/q1Pc+tJ6IUdZGvHPLezMcnBOWbsPap5r3 ylFtbdT1xUWNWzU0/Zbwlgfmx8zGsHWtRHmMqE59aAMyNifvHPc1f0gtPdqkY5JosJHeNci2tktY euPnNY+oXWZEVJNrZ9aun8SIq/CzodHuriIokhDIR1ronbKZr0o6o8ipoz//2Q==`,W0=` /9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAsICAoIBwsKCQoNDAsNERwSEQ8PESIZGhQcKSQrKigk JyctMkA3LTA9MCcnOEw5PUNFSElIKzZPVU5GVEBHSEX/2wBDAQwNDREPESESEiFFLicuRUVFRUVF RUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUX/wAARCASwBLADASIA AhEBAxEB/8QAGwABAAIDAQEAAAAAAAAAAAAAAAEDAgQFBgf/xABDEAEAAgECBAMECQIDBgUFAQAA AQIDBBEFEiExE0FRBiJhcRQjMkJSgZGhsWLBJDNyFSVTY3OSNEPR4fAHFjWCokT/xAAYAQEAAwEA AAAAAAAAAAAAAAAAAQIDBP/EACARAQEBAQADAQEBAQEBAAAAAAABAhEDITFBEjJRIhP/2gAMAwEA AhEDEQA/APqYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAKNTq8OkxzfNkisQC8eb1XtRNbzXT4q7eU2nu0MntRq/D8StMccvW29ZmdvgjsTyvZjxOLj +s8WLxn8TFPXs6Oj9oct7c14rkxz22nrB2I49KOdTjelmszfmpMeUxv/AA28OqwZ4icWWtt/SUi4 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmdo3nsPNe0Pt Fh09Z0+DNWL7+9O/7A3eJcZppsV5raI27esvH6jX5ddM25p79Ilo59VbUZOe2Tm/PeGvfPfT2iKR PLv1+DO678XmW/a97U6TtOyzTbTF538/T9WjTNecm9a7126tqk3rSYxY5ta1plRZqZNXGjyZcPXl mZmsx+qjBrsuO16xM7eXRt04JrdTltk5OWJnfaWf0a2lty5MdZnfzSn+WOHiOutFpjHa9e8bQ2fp +alYy462pk7zXbuxjPesbRS0f6ZZV1ET1tErzXFLHo+A+1ddZf6NrI8PJHa1vN6iJi0bxMTHwfOa zhzd61v1846utwniM6DUdb3nBaNrVmd9vjC/ZVePYirBqMWppz4rxaPgtEAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAItaK1m09ojcHnvarjM8P0vh49+a/eY8ng9D h1fGM1rxjtGPfvbzdbjuTJxHX48cTPNltM/KsS9Dw7S49Jp6UpHaGe2vjz1y9J7LYK13vHWe7bj2 ex1tvM80ekuxW3RnW3Vm6P5jRx8H0+OYmMcb+bapo8GKPdpC6bQwtdHU8JpWkdJ/JweL6e23iU67 d4dubSqyVi9Zi0bwIs68XGp36TtEq7ZJmZmevzdbifCKWtbJinkt6eTgZPFw32t+sRurbWVzxs1y Rv6T8V1NZNPtfq0seTm+Kevr+SZuxXjvaPiV8N4viycto9HseG6+uu08W6Rkj7UPmFck1tE1nlmP Ld3eA8V8HVVi1pjq6Ma/pnqce/ERMTETHaUrKgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAADW19+TQ5p/p2bLS4v04Zmt5VjeQeJ4bjnLqsupv+Ka1+ERLv4reTmcNxcuC vy3l0qdI2hlr66sT02ot0ZV7qqrInruzrVZLGSZ37JjqgYTG0K5lbaFVhDT1Ub456RPweY4hixWi eSdpjvD1eWejz3FNHWYtkpvFo9EIseb3tS3SerOms22rfpPqZKzvvHSYUz70TExG6Gdbs2rljeJ/ Mx5L0vEzPaelnOi98c9J2bFNTFpit47+a+PVUvx9T9nOIfT+GV5p3yY/ds67wvsXqpxau+G09Lx+ r3TqrEAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADV4ljnLw3U0jvO O0fs2lWqyUw6XLkyfYrWZkHldBEV09eveG3Fq1mI3jd4vPrOIaid8G9MP3Y38k6fNrt/rMk9Ou8s tfXXn49rGWInuy8SO/k5Gl1E3rG/fzbOe94wTy99mbRvTrMOOvNfJWsesywniukrG/jU6fF43WYN TmtEeJtEQ06aSmK2+bNtEd+qfSO17unF9Hmvy1y13XWyVmN4tExLxVK8PmNq5NrT58zawam+m/yc 0Xj8NpRYSvQZ7xEOdqI3rPozxayNRXe0ct/ON03jmrKB5nV4q1yTO20Obmv4c+cx8HoeI6WZpNoj q83niYmYscU0r8aJ6T1n49zeJ+Meqm1drb9J+Kd5p136StGVem9l9TbHxLDFp7W7+sS+q1nesT6w +PcAzVjiGHftzQ+v4f8AJpv6On8jH9ZgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAABp8VrW/C9TW0ztOO3b5Nxp8VmI4bn37TWYB8f1HFtTfUfR9FWJmsdZ9I7MtJxDX5s d8ta1y0xzteaR2277rcuhycP12SceLxMeWNpjttHwlu8I0mfQ1y+D7k5YmJmY36T36Ka43z/AF1t cI1ds+qxVj7/AEej19PCw9HJ4NoK4OIU5Y35YmZdzVTGebVZabx5jJS+Tmns81rNLm1Wrzc9rVw4 Yibbem72mXTTS0w0M3BvEta1bWrM95ie5EanY87wXgNOL6XPfxraXLhra/W28bR/dzYzarBqJxRe bzE7Rt5vWU9n8mPHOGmS0Ypnea1naJb+k9ncNLR7u2y/WcxXO4TOoyUrN6zD0FaW5Y3hu49FiwUi KxCvLMR0hlW0jn6ukWw3iXjOJzbDlneOj3GaN6zDzfFOH+LE7SRGo83XNSZ2lbG2/WfdlvaT2cy6 rNFInlrv1mfJ37cK4PwTTxOoidRm2+/2/KFuyMp47XB4LivXiunrH2b2iH2qn2K/J8x4fGDNxTSZ 9Nh8OviRvTyfT6xtWI+DeXs9MNZubypASqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAOZx6/LoOWPvWiHTcf2hiZ0e8fc2mf1E5+vP/AEeuSd7RC2uKtI6QjHfeINTfwtPf Jvty9WPfbt/lucP03gxfJf7d/wBoReYpm97zaNeLb4Ims9Nt94auDjem1Wo5PFi1onylS+1o7l8V bxvtupjDMdNkYtXS1+Stt+m63xImEJ4xjHER2ZxMUjeUTO3VRmydBbjLJqPi08mbeVOXJPq1sl5Q Vbkz9+rRy35rxHqzmZlVEe/Ez5LRlW5iyfR6zffaIjq1OSNZps2a21rZInafSPJhxGMl9LStLRWM lorM/A4dkrWbYfLZC2W/7K6eubX6b4RzT+W76K8b7G6X62cu3Sten59nsm3j+OXz3/0ANGIAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0OIYfpOHPijvNNo+fdvtXJO18k/ /OwPFYbz2ls3jx8VqW6xMdWPEdP9D4lkx/dt79flLLHbkxTPwY6nt2512ORTRzE2x4/dpE7cvkme E4IrW3hRMxO8THRtU1FKWtvtvK2upx22rzRCtXkqzh2jtF7ZbT122b01ndnpuWuP3Z3+Ky20qDVv fauzVy3mejZzNK8dVjqi87KLRLYtXruqvXzkQp7Qoid88R6rcl+WGlW0/Sa22mfhCZOq2x082ix6 jkm822pO8VrPdr4dNObVeDo8XW3uzMbzK+mvxT7szE27cvnu9j7PcNjSaXx8mOIzZevbrEeic5tN +SZnpt8J4fHD9HXHO3PPW0x/DeBtJxx29vaAJQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAKNRim9Z5e89Nl4DzXtVh5babURHrSf7f3ec1+qnDorWrvvt5Pccb0n0zhmWk Rvevv1+cPE2rGTFNZU26PFfxwa5dVkjelI2772nZnX6bbrEUq3o0d678u8wmuDL2ittvVjXdneeK cGv4jpJ6U56+kS7+j118+GLXpakzHaWlp9NNY3tv+bbiYiNoQy1y30uyZJlrWmZnuym6q1iIJnop yW2Te8bdWnnypQqzZOadokiIpSZntWN5lrxki19vNRxrUeBwnNNd+fJEY6/OejXLn3Xe/wDp9wyn E8uo4lqqxblv7lJ26T6vpD5X7G8QycKzeBMbzMRM1/FH/wA/h9QwZ6ajDXLitvWzRgsAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeL45w+dDrZvWv1OWd4+E+j2jX 12jx67TWw5Y6T2nzifU+rZ1y9eHwzDYxxEy18+DJodXfT5o96vafWPVbjyxDn1OOzHudbM0rt2UW iI69mVtRXZq5tREb9VUoy2iIlRbJ0UX1VZ6btTLrI7V6yk62M2oisT1c7JmtkttVMUyZp6x0beDS RWOvdKijDimvWd3G9pNRMfRcNfvZOb9Hpb0itJeP47k/3hgjaZnbaP1XxWW3T0movbNS0W645nbf 0nrMPpXs3xamoxdJiLbe/X1n8Uf3fKsOTw4jbaXo+EarJhtGTHMxeJ6xH7Sti9Zaj6x3HM4NxXFx DS1mtoi8dJrv2l011QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AGjxLhODieOIye7kr9m8d4eM4to9RwjPXFa0ZIvG9bR0fQXmPbDFvTTZPOJmEWS/V8bs9R43NxLL G8eFbePg1bajU5/s0l1ceKLx1hbjwRE9mOpx0y2uRTSZsm3PMw2aaKtIjo6kYo9EXpET0hVLXxYK xC6MZvyx1lFs0RHfaPiCnU12pLyHGNDbUajBekWma2npWN3p8+opa20e9LSyZLxExTlpM+vdOdcZ a9tPS8MyUvFrzWlI6727u1pYxYrbVmb7x+TQx6au3Nqcl7/0rcmW9axGnwZJj1novmxnZXV0fFp4 ZxLBPgTGK8xzXr5fOH0bFlpmxVyY7Rato3iYfNuG2x56Wrqa8s2jz+7Lu8O12bS6jkwzN6THNNI6 tvrN68Y4rxlx1vHa0bskAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAA4XtTTm0OKfTJ/aXdcL2pyRGjwU362yb7fkJz9eTxxyZJjyltRXzUZK7TFtl9Lbwy06YzrHwa+ fJFd/wCVt8m0bQ0eS2qzcm+1K/an+zNZFL5M1pjFXeI72ky48eGnPkvNp27+TPU6nHpMfLXaIjpE erk5dRMxOfN1mPeisfshW1ne1a1577Y6x5R3U0zze31FOWI6ze0byU098kRlzbxM9qrMlPDpyRMR Md5Vt/Ihp5898mWZm1pjftE91uCt7fCI7dWeHDEW3t723l6rslqxWZnasR+SYhFbzhnfxJ2jyeq9 lcGXWZcmW0zWKxHLaI7794eJx5fpfEKabT8t8l5isddo3l9S4VjrwrRUwzSJt3tav3pdOL6Y6dXD j8HFWm+/KsU4NRXPvtWazHquWVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAa+fXYNP9u8b+kdZBsDkZOO135cWOZn4y5Wu4xqctbe9y19Kp4njt6vi+PDm8DFMWybbzPlV 5PiGtz67UxbNbeKTtWIjaIXYpnwuaftT5tXJT3vmi1pMsrU5qIrG1V1a+5DCa7b9GFbRr5J6Wnbt Cu+Wmk0m8956z8ZWZNorbfzcbX5rZslazPux3hUt41NTntktObJ13+zX1bek01r4/HzVm0bxPXy/ +bNfDgjVa2uOY92kdfg6ufJOKvLXtttVVSqbcta2vM7zXtHpLQy5ZtMd+vWd+7Zy3mdJHXra3f0c vUarw7zFY5rT2hH1Lavnrgx81p3U49Pk4nE5L35MO/StfNRXR5tXnrS8W67WvfyiPSPi7uLHFK1p jrtSsbR5Lc4RzsXBaYreP4l45esRD2HD9fnw6evvWvO3Tfr0aGk0U55ra0TFInv6uzgrXFXlx0i0 77RPlC83Yj+JW7oddqr6vHzTTw9/f6dod+L1t9m0T8pcbFSmPHER3892W0zPuz+jSbVvidkcqmfP Sel7bekrI4n4dZnPWIrHeYnZee2Wpy8dEaml4npNZblw5qzb8M9JbYgAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAABEzFYmZnaI7yCXL1XGa0jJXT0571nbee27DiXEprp8nhbxG20W8 5cbD0ikfnKO+urTPvjoZdXqctdsmTaPSvRpWmsdZ6yztfaGplvv3lWW1tyRlz1x0vkn7Vo5atTNe Y0+1o79V2KsZsvX7Ne5mwxnyTNvsx2iGneM/rCdRSuOsTasTt5kRFtpjqmOH4t4nk7estiMNa97R Hwhna0iuKTEdmGWa4672nZtRele1N59Zlq6vLOSsYorEc07qcW65euzRvtXvPZy52naZ7ujr6fXV rWdukREK8+njHgmZmPc67bq6ivVWhxxgxZLztNrT1mZ/SP4VZs0zaOvfp84WUtNsXLvtv3699+rU z7+Jtt5qURqMnPpctaR1rMSw4ZoK57eNk6xHaJRh97Ltt7lo5Z+L1HAPZvVauZ2nFTSzMTzeJEz8 to6xPfvsZntPZ9rXxabmxzefdrv0j1dXh/BcmstW1qxTHHasR3+b0GPhGl+kWmd64dNEVjf73T7X y8vy+Ddx6O3iRakxTH5RXrMw1/lX+3Itw2MFIraN48qRHdZi0cUjmmPen9noox1iO0fNzdXEYrTt stcmd9aX0bJ+HePmiKTitO8TMLZ1cVjrMfqpz6ys4pjfrPRWZ9rXXptUit6zO+23VyaRHEc05L1/ w9J9ys/en1ljqdVbwYw452tlnl3jyjzbmmiMeKtYjpEbLeTXPUU8ee/+qjJpsV5rbkrFqzE1tEbT DpYNbW21Mnu29fKWna0KbqTdjXXjld0cvQ63ltGHNPSfs2n+HUbS9c2s2UASqAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAOVxPWe99HpP8ArmP4b+r1EabT3yT3iOkesvMVtN7za07zad5l XV5GmM9vVfEstvDx0jtaVVMlq+UJ18b5cMRvPeSuK87bUt+i2Z3PtG7zXpjkzXt6R+TXyTMzvM7t ydHqZ+zhv1+Cv/ZuqvPTHMfOYaTMil1a1K2vHSLTELq2v+KWzThGo84rH5rq8JzedqR+ZeI7WnOS 34pYTafWXR/2Pln/AMyrKOCWnvmiPyR6O1y9585lhWJvl557Q6eo4T4dYiMvW3b3UanhldHpJtGX e09unmjsT7eb1l4trI2t0hsZfrdNO0bzy+nzU20/+NmkzO9esz+TZxWis9dttvPv+Tn21jjaW8zn 26bTG3mp1M/Wzv3t0jyWXiKZJmsTERaZhXXDbNl8WaztWenxZLstPp5pau8frDtVrNMM5cfTfpMf 3aunxxbes9d/R09Dp8ebJi09ptFr3jtt2WyrW9wy1Jx132mK+Xq9PotT0iIU19ntLtExa3T47T+q 6nBaYvsZstZ+cT/LeMnUi0TXffo1s2m8Ws2/OIMWk5Jib5L328rS2t94Sh5TV4ppklpW6PT6rh+P NbebTHyas8E081mZy5P2W6OFhjxNTE/hr/LoRO0Kvo9dPqctKzMxEx1la5t3tdnjnMs4noievcrO yZjeFF1OSnNV0OG62cn1GWffj7Mz5w05joovzY7xes7TE7w0xrjPeex6Ua+j1UarBFu1o6Wj0lsN 3JfQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACrU5o0+nvlt92P3BxuM6nxNRGCs+7Tv8 2hToxm1r3m9utrTvMsonqyt7XTmcja0u3O6FMfi5t/u0/lzdJM81p9O3zdvHTwsUR5+bfPqOfX1h dqV+3O7bs1+T31oqmI3TEM4rvCdkDGIIhlFd2daboS0NXG2bD6bufxXU1vlmu/u4us/N0+L1tTSx kr9qk7w89j1FNZMV3jxLzvaJ8mer+LSOZqK2xZotbvljfr/89U453rXt9lse081xZtNjx7TGKu0t DHlrevSevaN5Y6+tJ8c7VRNMt63n3ub+6/R54rERMztDYy4a5omclYmfxKcenrjtHLvtPrCnVmdb eFe3JXmjy6eS/DrMuLVYsta9Mdt++6qLxO+0dEc8UmInr18iUfReHcXrqccb9Z27Q61Lb13eJ9nc 1Z35rTvE9avY4bTkpG8xEfB05vYxqybc07R281naGMREdoT5JQqy9mply7Q3bV3iXG1eXw7TWSka c258t7+tpT5/BjT7MfHqndz12Z+M4lMMKyziUJJiN1WSu9fku23RaOgKNJqbaTU1t9yelo+D0cTE xEx1iXmM1Nt3W4PqvFweDaffx9vjDbGvxz+TP66QDRiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAOJxzU73rp6z296zsZMkYsdr2naKxvLyObNOfNfJbvad1dXkaeOdpvsc2yuZVzfbfqybutwu s5s8R92J3dvJb3tnO4HSMegtmt3nfZvYp8SZl0z45NfSK7onH1bNcfRFqnUKJr0Y7dVtq7prjEsK 0XVpEM6028mW20IHK41aPo3J6zs4ODhdcvPnvExFevNXpMOrxi/PlrTee7PLX6Pwa09uaNlKtHg9 dM3z5d7ReOu02nu0JzZMfblrv5R5uvrcdImZ26T1mYhxs1Os7RH93PZ7axuafNfLitvbaYU3yZYt PXs9NwHhui1HBa5LVicsb81onrEuVqNNSuS8Y67dZ6xPZa59Il9uX41vEitImZme3q2Kxbxora0T Md/ROSa4Ztkj7c9OafL5LuGYubmyX3iu/TfbdSfVnpvZLT/XZK233+Mbbva1xRXyiPk8pwbH4N6T adq5a71n0tD1WDL4tPe6Xr0tDpz8YVnJHWEXYxbqlBedoef4tW0XraO09HdyztSZcbUz43C+ee9b SVMaeOfqq7+jGckQ1Yz7+7v2RN/WXPXZPjci2+2yyJaVMuy+uSJlA2d+pNoVRbeDcSxyTE+TDDlt pdRXLTynrHrDOyiyZeVFnY9TjvXJjres71tG8MnJ4Nqt4tp7T1jrV1nRL1x2cvABKAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAHJ49qfD09cNZ97JPX5PPw2uI6j6Vrsl/ux7tfk1mWr7dOM8iLdm vfebREefRsWldw7SxqNbWbR7lPesrn3Vteo7dYjDpMGCvfbeXQ0uLlxRLRxROfUc34p6fCHYrXlr EejqrjY8uzCYW7MZjdVKqK9VlaxCYrsnYExBMRMJRPZA8/xPHtmpP9W2xx76vhWOInvt/C7ike7N vwzE9kcapGfhlevTaFbFo8RqJ5vy8/RoW09ek0msxHfp3dzNoLzp4zUmZpMbT8HJyYJi20X2n0lh ZY1li/RaidBF4w2mK3jrHaFGp1lN+tptPp5IjBkid5mIp16TKu0abBPv33vPlM7z+iPdFNcWXU5I tkrNce/b1W5db1nTaf3ax9q0fxDW1ebNk2phty1mOu09VOm8W19orEz23j1TwfSeERFuEYMddptW d43dvBn21eKJ75KbW+cf/JcTgMxXTb3nbljz+TpcPmc2uyZO1KRtVtGVdi0bx07qJnllsRO6rNTe N4XVamsy8mnvPwc3R2jPwe8TPbdlxXNOPSZfhWWpwO85OFzv57qrODkzeHntSe8Sn6Rv0a3EZ218 8nXekfr1a0ZLVnqx19dWb6demXybOO7lYMvNMdW9S/VVLo0us7tPHdtUtEwJiZU3jq2Jhham8CVG PNODNTJXvWd3qcWSubFXJWd4tG8PK3pPd1OB6veLaa89Y61/u2xfxh5c/rsgNHOAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAANLimq+i6O0xPv392rdeZ4rq/pOqnlnelOkIt5F8Z7Wj27I2I6sb25YY V1ImY3dbQ08LRc23vZp2j5OJG+XJWle9p2h6HHtbJXFT7OOIpX+7TxT31j5rycdTh+Dpz+XaG/sw w18PHWseULN2trBE9UcrJKBhFU7JAQi0dEomegNDUYovM7x3jb5tO1ZvpbaTLtzRExWfWPJ08kbT Ex5NXWYYyV5omYtHWJieyeDzuizfRs19Jn6TM7Ru1uMcJxZqTkw+5f4ebqa7SV1MR4tdrx2vEfy1 axqsNOTLjnLXytVXi3Xj8+nmsxTLM16d5npPyUzpekTtSK+U7vS6vQ/SYmK1vWPS1HOn2dvvvvE/ tDO5XlcO+LbfHSd/W3o6/BdDOXPTnj3Kz38rS6Wm4FNrRyRzTH3p6RH/AKvR8L4dXSzE3jmtHn5I mbfqLV+m4dbLSsZInHjr3iI6zLpYaxS01rHuxHRHiT9mv6s67Vj1aqL6326MrWiYa+/Q54BxPaGe XRZpj8MquB4+Xg8zPnB7SX30to379GxpK1xcHiKz5IS8xr8PLPixH2bftLTy05o6dHYyVjLhy0t1 izjZa3pMVv3iO/qz1G2L+NbSajbNyW7xLsY8kTDz+fJXFqKZN4iZnafi6WHL0iYlStI7OO+7axW2 crFl7dW9jvE9ULN+J3ZbdFGOy+AYWpEqN7afNXLj+1Wd23KrJVMvCzseh0+auow1yU7WhY4fCdV4 OadPefcvPuz6S7jol649Tl4AJVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAV581NPhtkvO0R+4NPi2 r8DB4dJ9+/7Q83Po2NTqLanNbLfvPaPSFDHV66sZ5ET0hRknyW2lTtMyouz0c8usx2n7s7vScKwx zc1vu/y85p+maJh6Th+SOWeveXR4/wDLm8v+nX5mUWa9bbrInolmu5jdTNkxYFk2Isr3TuCzeGMz +THdEyDDJO9Ja823rt2XWnya946pGvktDXta0ztWu/ybvLE9dkcoOf4GbJPWK1j49VmLh9JtE33v Mevb9G7WsW8l1ccREISophiJ2jpDYpijbaOjOuOJ8ujOdqxsgVcsUjaETYvbaFFrgu5lVsm0yUtu ryg43H5m+GIj1XcJzePoL4pnrWGtxmfchr8JvfHS1622if3QljzTTLes+qrNjrkiYtCzPMxnm095 YZJ6boS5teB49Tqscza97VtvWvlv8V/FOF34RrIxTM2xXjelp/eHoeA6XnzReY3ivX/0dfivDcfE 9HbDbaLx1pb0lOs+jO7K8Lis3cN+0NKcd9PmthzV5clJ2mF9J9GHHVL108dm1SznYr/Ft0tuhLb8 mNohFbMhLWy0mJ3rPXvDvcO1karBG8/WV6Wj+7kWrvDDBlvpdRGSnbzj1hpjX4z8mOx6UYYstc2O uSk71tG7Ns5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZ2jeXneJ62dVl5KT9VTt8Z9W9xbWclPo+O fft9qfSHEU1pv48ftYST23ZTDC/p0YtlVuvVjMbM5+LCZjYGWGdrTPxiHY4ffaf3cjTxz1v6xMS6 Olty2iXVj/Dk8n+ndrkhnGRo1v8AFdW3RCrZ5uiYsqrboncSu508yjmZRYQt50TfowYTbYGVrKrT uTZjvukQnYhMIGVY2ZxPVWyrHVCWzXpVXkt3TE7Va+W4K7X3jv1auTNy3jdba0RZpamfroQN7Hk3 6wr1GTaN2OOJiu6Mu98NvgDi8Wy74d/yZ8PiPAiO2zU4nb6qIn1bugjfFE/ASp1ke9u15mbbRDZ1 Mb823kx0Ontn1OOkedoJCvT8I03gaKsz9q/WW+isRWsVjtHRKyrhe0XCfpWL6Vgr9fjjrEfeh5fF feH0V5Dj3DPoOo+k4a/U5J6xH3ZZ7z3228evytOk7NvFbo0cdols47bSybt7HbddHVqUs2aW3Qnq xVeu8LILR3SlZw3V/R8nhXn6u0/pLuPMXjeHT4Zruf6jLPvR9mZ8/g1xrvpz+TH7HUAaMAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAABRq9VXSYJyW79qx6yvmdo3l5viGs+maqYrO+OnSvx+KLeLZz2te1rZL2v ed7WneZYWnZl5K72YV1xEyxmeqJljzIEWlVkszvbZp5soN3h2SJz3pP3odCnuWmPRxuERfJrZmtZ mtY96fR28kbX3dXj/wAuTyf6bmK+9YX1s0cNtm3Sd4LFY2K23W1s16StiUJW7bp22RW3RluBuruz mWEgrmCGWyNkoExKE1QlPmsqRDKeyBjaejWy2W3ttDUyz1QKslvehVqKTNosyyTvELabXptIJpaP B39Ia2mz+JGpr51jdZefDx2hzuHZObNq58poJaGtjxJ2+LoaKP8ADRPo5+T3skx5OhpOmC0fBNQ0 5yTbn+bt8A0u9raiY6RHLVwY62mI6zMvaaHBGn0mPHt1iN5+aYVsACBXqMFNTgviyxvW0bSsAeE1 mkvw7V2w5Ote9besJx2er4rw2nEdNNekZa9aW9JeQjnxZLYskTW9Z2mJY7zz26fHrrdpbZsY7NGt mxjvso1b9NmUwpx33XRO4K7VUTE1nmrvEx1bVo2VWiJE/XY4frY1WPlt0y17x6/FuPM0m+HJGTHO 1qu9pNVXVYt46Xj7VfRtnXXL5MfzexsALsgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHM4jxOMFJphmJv529Dq ZLfjDjPEIx450+K3v2+1MeUOHSOWFc3nJkmZnf4yujpVlqunOeFpV2nctLCZUXRM7MJtsWlRkv3Q ky5NmpWt9RnrixVm17TtEQnJabXisRMzPSIew9n+CRoccajURvqLx5/chfOest642OGcIpoOG2w7 ROW9d72+LQvXevyejcPUU5M+SvpLeOataraw2a0dLbLqTtK1G3Es4lVWWUSoldFtmcXUbpidgXzK GEW3TuCUSncnsDFMMLSms9EC6J6FpVzbZE5ALy0809ZbFr9GtfrEoFMzuuwz0Ueey3HbaBLDXe7i tMOfwWnP9I+NZbuttvhs1uBRtXPb4SDm3iIvf57N7Dbl0VrS5+XrltEd+Z1Jx7cNms9N4TURRw3T +PrcO3WszEvZOD7P6aYiMlvu16S7y1QAIAABxOPcLnUY/pWCv1tI96I+9DtgmXl68Biy7/NtUu3+ O8HnFa2s0tfd75KR5fFyMWTdhrPHVnX9R0cd21S3Rzsdm1iuqs256wrmGcT0RYSx5d047X02SMmO esd49YRE9WcdSXhZ2O1p89NRji9J+cei1xMc3wXi+KZj1j1dTTaqmor06WjvWW+ddcu8XK8BZmAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAMMmWmKu952UZ9XFZmuP3revlDTtzWnmvO8q3XGmfHb9ZanV3yxtWeWn7y4es vPNtDqZJ6Ts5mppvdl/XXRMyfGvSNlu/RVvtOzLfoipLT1VTKbSpvfogRkvtDVyZOhkyvQcA4Dzz XV6yvTvTHMfvK+c9U3rkW+zvA/D21urr789cdZ8vi9KDb45rejl8Rry6iJ/FV1HP4vXbBTJEfYt1 +UpiHM295bXsqrO9l8QkZ0lZEqqLeyBZHZLGvZkhIndADKJ3TMoqWQMZ6pjsxll2jsCLSrmU2lFY 36gieyu0LJk3jbsga0wdqzK20QpyztQGprL/AFMrOE05NLkt6qdVWZxNrSe5o9vWBLiUjnzXn0vL q555dHt8HOwV928/1z/LpzXxbYccRvzTB+jucOwxh0dI22mY3ltIrHLWIjyjZKyoAAAAACJiJjaY 3iXleM8InR5J1GniZw2n3oj7s/8Ao9Wi9a3rNbRE1mNpifNFnVs65XhcWTdt47bnFuF24dm8TFEz p7T0/pn0a+HJux1OOrOux08d1ndqY7tillVkzExLOk7yd4YxGwluViJhE45raL0na0dtlWO0+bZr 1TKi+2zptZGTamT3b/tLacvJjiY3XaTWdYxZZ6/dtPm1zrv1z78fPcbwC7EAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABhkyV xUm152iAZWtFazNp2iGhm1Vss8uP3aevnKrNntqLdelI7VRHRnrX/HRjx/tZREVjZXeybW6KbWZt pCZ6S08tN7Nmbb7zCrJtyoS5145bSx5mWafelr3tsKmS/o08uXyhlly7RPV2+AcBnPNdZrK+53pS fP4ytnPVda4y4BwHxOXV6uvu96Unz+MvVxG0bQRG0bR2G0nHLb2gCUDX12LxtFmpHeazt82wT1gH mMN4tWs+rcr2aEV8DU5sM/cvO3yb+O0csLUTSdrLphRE8tlkZI7Atr2ZMazDJVKTYSCawi7Ksq7z 1QERvLK3ZGPrKbyCrbdnMcsbeaa18/RhvvM7oGEwTG0JmYYTIML22a2e28xELM19oURPNO4lOem+ n3ZY5+prVnMc2GYU4/L4A0a15cNf6rz/AC6fC6+NxCPOuOu/5tHJTbHj+F5/l1+BYumXJMd9o3/d MRXYASgAAAAAAABhlxUz4rY8lYtS0bTEvH8R4ffhmo6bzhtPu29Pg9mq1Gnx6rDbFmrzVsizq2df zXkMWTeIbNL7tbXaHLwzUctvexWn3bmPL8WFnHVL326VZ91MfFVjvvVlz79kLrcf2m7j7bNHH3bl J2SirLQoy4t1++7G0dBC/RanxI8PJPv18/WG241+alovSdrV6w6mDNGfFF4/OPSW2b1zeTPL1aAs zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAVZ9RXBTe3WZ7R6iZOpzZq4ac1p+UermZMl89+a/byj0Ra9815ted59PQ32hlrXXRjH DpCLX6ML5NlNsm/ZRqstfdXzbsZt06sLZNvNB1Za8RDWyZdo7q8udq5Mu/mIMt4md2lmy7JzZuWJ dHgfBL8RvGo1MTXTxPSPx/8AstJ1XWpIs4BwSdbeNVqq/URPu0n73/s9hEREbRG0QUpWlYrWIisR tER5JbSccur2gCUAAAAPM8Sry8Uyz67fwuxbzVPGsE49XGbvF42V4M0TEL33ERnktsxpk3sumK2j admFdPFZ33VS2Mdui2J3UU6LYlFSsN2O5NkCyJ6K7T1TEsbAsxdpReerKkTFGMxvYEz0rsqtbbpC b2VT1QEzuwtbaGUxspuJU3neWdKoiu8rq12gCI92YatLcublnzbEz1aOptyZqTuDHLfxN6R0+t5X qdJhjBp6UiPLeXl9NSMnEKxHa1+bb8nrlvxUAAAAAAAAAAABTqtNj1eC2LLXeto/R43VabJw/VTh ydY+7b1h7ho8V4dXiGlmvbJXrS3xRZ1fGv5rzeHN02bEW3cys3xZJx5ImtqztMS3MeTeGFjqlb2O 8btql3NpbZtYsnSBLeiWfdTjtutid+ghherHS5p0+f3vsX6T8Fkw181d4lMvEWdnHaGnw/UeNh5L T7+PpPxbjdyWcvAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAo1Oprgr63ntAmTqdRqK4K9etp7Q5d7Wy2m953lNrWyWm953mVd77R0 Za1104xxlN9lV8qnJl2a9s3xUXX2ybsJyRDWtl3YWydEC+2VRkzeW6q+T4tbJm+KRdfK1cmWZnlr vNp7RC/R6HU8SycmCk7ed57Q9ZwvgOn4fEXtHi5/O9o7fJaZ6z1uRyOEezVstq6jiEbV71xevzer rWtKxWsRFY6REeSRrJxz22gCUAAAAAANbX6aNVpL0npMRvWfSXlKamsRMVvXm+EvZXjmpaPWHzfL oNRjzXicfWJ8phfPxFejx72x7xMzK+sXiNoiXlq+Pi6fWV/VfTNqfLJl/WTg9Pji8R70LqvMV1Gq j/zcv6yz+lanzzZP1lWpelTET6S81Gp1P/Gyf90s412rjtnyfqql6asREdWM9+jz9eJ6yP8Az7uh odZqMt458tpB1JvEViI3/RhzRt13/R1MNaziiZiJn5K9ZNceKZiIiQcu/WekT+iYrWI3lzdTrs+8 8uW0fJzcur1Np/zsn6g79phVaIeetqNR/wAXJ/3SwnUaj/i5P+6UD0ldonum161h5mNRqP8Ai5P1 lNtRqJjacuT9Qd22WN5aGeZyZd/KHJy59RHbLf8AVq31Gp/4uT9ZEvS8Lr/vSs2npzRtL1z53wK+ oza/HW2XJNd99pmX0Rb8VAAAAAAAAAAAAAAcHj/C5yV+l4I9+v24jzj1cLFk8nu5jeNpeW41wmdL knU6ev1Vp96sfdn/ANFdTrXG+eq1q5F2LLtbZoY8m8d11bbSydErsYsm+zZrO/zcnBm226uhiyRK EtrvCrJDOJTeu8A1MWX6Lqq5N/dnpb5O5ExMbx2cPNTeJb/DM/iYPDtPvY+nzhri/jDy5/W6AuwA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAa2p1UYo5adbz+xbxMlvqJ1OqjDHLXree0ejmzNrWm953tPmTPWbWneZ7yoy5YhjrXXTjH8s75N mtkyxt0VZM2/m175N1V03yTKubMLXVXybeYLLX2VXy7eam+b0bOg4VquJW+rry4/O9uyZOq3UjVm 9r25axMzPaIdvhns1kzbZddM0p5Y47z8/R2+HcF03Doi1a8+Xzvbv+TotJnjDXkt+K8ODHp8cY8N IpSO0RCwF2YAAAAAAAAACvUZYw6fJkntWN3k8dfHz2vLucdz8mkjFE9bz1+UOZosX1UzPm0nqI/W MYo9FlcPNklfFGeH/NshLGun+Cz6PtHZtVZWlRLS+jxPkRpIn7rdoupHTdA5s6SI+7H6Mfo+32Y2 +To3neSIiZ7A0IjPXpXLePlMotGW3272t85datKzHZjbTVnsDj+FG/2Y/RlGP4R+jo20u7H6N1Ql o+H8I/REY957R+jpfReiK6eOYHLtj2tttH6KrY/6Y/R2c+kjeJiFVtLG24hxpw7/AHY/RRkw9O37 O99Hrt1YX0tfOBLjcGp4XF8c+u8fs9c4dcVcGemSI61nd3IneN1orQAAAAAAAAAAAAABFqxes1tE TE9JiUgPKcX4RbRXnNgiZwWnrH4XPi28PdXpW9JraImsxtMS8pxXhF9DecuGJtgmf+1TWW2N/la1 L7N7T5e3Vy6W3hsYcvLbqzbO9jvvCzvDR0+XeO7crO6FmGSvRThy/RtVXJ92elvk2rRvDUzU7pl4 izsd2J3jeBpcNz+Lg5LT7+Pp+Xk3W7js5eAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs0NTrN96Yp6edkW8Wzm6+LNTq4pvTHO9vOfRoWtt 1mes95YWvs1s2fZldddOczLPLn2ju0MmebT3YZc2/mpm3qqllN1drsbZIhr3yzvtHf4AsvlYYseb V5Yx4KTe0+UQ6nDvZ3UazbJqd8OKeu33peq0eh0+hxcmnxxWPOfOfm0mP+steT/ji8N9mKY9suum L37+HHaPm9DSlaVitKxWsdohI0Y22gAgAAAAAAAAAABXnyRhw3yT92Nwef4xm8bVzET0rPJH5d12 CvLhho3rN9RWs9Z23n5y6O21YhrVYbdGOCfrrLPJRpv863zVS6FS09SvZj3lVZZRdPSqmnSWdrIE ebOkK4ldTsgW1WKqd1oMZhEVZyRAImOjGI6rJ7IiATNd46qL02bHkiaxaoNGY2n4ImPgtyV2n0Vo Gvlx7x2beiyTk08RPevSVUxux00+Fn2n7N+n5rRFb4AAAAAAAAAAAAAAACLVres1tETWekxKQHlu L8InR2nPp43wz3j8P/s5dLveWrFqzW0bxPeJeV4xwmdFec+CJnDM9Y/CrY1xv8qvTZ+WYdbDk5oh 5zHk283U0eo3jaZZ2N5XYjrCnLSJhOK+8d1kxvCqzSwZvousrb7k9LfJ3nB1OLeJdLhufx9LEWn3 6e7LXN9Ofy5/W4AuxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAETaKxMzO0Qi9646Ta07RDmZ9VbPbaOlI7Qi3i+c3TPUaqcu9adKfy0722ZXvFa9 XO1OrjrESxt66ZJmcjPUanlidmhkzTZVfLN5VWvsC2b7R3U3yqrZZtO1esz2h2+F+zWTUcuXXTNM feKR3n5+iZLVbqRzNJo9TxHLyaekz62ntD1fDOA6fQbZL7Zc/wCKY6R8odLBgxabFGPDSKUjyiFj SZkYa3aALKAAAAAAAAAAAAAADQ4pl2pTFH3p3n5Q33E12Tn1eSfKscsLZ+orS00eJqbW+Lfnu1tF XaJnZsz3WpCfsyp00fWSvmPdVYOmSUDd8kR3InoQosy7JmUX7MdwZ17ro7KKT1XRPRAsrO0rYndr 79V1ZBaQiJ6JgCSIJASwrO07MpV2nqBlrv1a1o2bf2qtfLXaQUTO0sb05o3jv3ZXhjS20xEphW5h yeJjjf7UdJWNKLziyRePsz0lux1SgAQAAAAAAAAAAAAAADG9K5KTS8Rato2mJZAPIcU4ZbQZuekT OC3afT4NXFkmlntc2GmoxWx5K71tG0vHa/RX0GpmlutJ61t6wrY2xr8dXS5uesN+tt4ef0eaa223 2dnHk3juyreM81OaFGiy/RtZET9jJ7s/2bdutd2jqKeic3iNTsd8a2h1H0jTVtP2o6W+bZbOO+gA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABje9cdJt adohGTLXFTmvO0fy52bJfU23t0pHaqLeL5xdK9Rnvqb+cUjtCi94xxvK3JetKuHrdZvaa1ljb10y cnIs1Wt3naJc++TmVWvMz1YWybfMGdsm3eWek0mo4jm8PT0mfW3lDf4V7P5tdMZdRviwfvZ6/TaX DpMMYsFIpWPTzXmf+steT8jn8L4Dp+HxF77Zc/4pjpHydYGjC3oAAAAAAAAAAAAAAAAADG9opS1p 7RG7zszN6WtPe0zLua+3Joss/wBOzhzG2OsL5+IrY09dsSyYRijbHEMvOChb7KjF0yS2LQ169Mso S24noyrPVXWejNVKbTuw3T3REdQWU6LYlVvsyiUDPfqupPRr79VuOQX1lZEqoZxIMksd0gT2VT0l bPZVbuCaW8i8bwr32WxbcGnkjaZa9p2ndv5qbw5+aNugLItF6TEtvTX5sMb969HMpfazc0d9stqe vVZDdAQAAAAAAAAAAAAAAAADV1+iprtPOO/2u9bektoB4TJTJpNRbHkja1Z6uto8viVht+0HDvpG H6Tjj6zHHvbecONw7Ltfkmeqmo6Ma69DXbbZTkr1mGWO3RneOaGbZRoM30fVzSelMnT83aef1FZ7 x3h1tBqfpGnjmn369LNc3sc3kzy9bQCzIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAa+q1dNNXr7157VhGp1Xh70x+9f9ocy283m1p5rz3mVbrjXHjt91lz 5c9+fJ1nyjyhdM8lZlOOIiqrUXikd+kMreunnI5XEdX4dZiZcG+XmtNl/F83PeeWWHDOGanieSKY q+5H2rz2hMzWd1Iqx1yajJXHhrNrW6REeb1nCPZumn2z62Ivl7xTyr/6uhwzhGn4Zj2xxzZJ+1kn vLoNJnjHW7TbbsAszAAAAAAAAAAAAAAAAAAAAaPFrbaSK/itEOXt0rDf4xb/ACa/GZacRvaF58Q2 IjasQnzPIhCU92tMbZGzHmotG10C6nZkwpPRmipIllEbMIZIE7solgmJBnCyk9VMM6z1BtVllEqK z0WRILYlluriWcSDJVbusV27gwInaSWM9ECyZ3hqamnSWxFmOSOaqRx725bNnSZNs9J+OynVY+WZ YYr7TE+nVaIr0Ais81Yn1hKAAAAAAAAAAAAAAAAAABExvG09peU4nov9n66L0j6q/WPg9Y1OJaON ZpL0+9HWs/EWzeVz9PbmrEtnyc3h9reHy26TWdnSr2YX6657ijLXpLX0+onSamL/AHJ6W+Tbv2aW ekTv16JzeI1Ox6KJiYiY7Slz+E6jxdN4dp3vj6fl5Og2clnKACAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZ2jeQRMxEbzO0Q08uqtkma4ulfO3r8lefUePMxWf cjy9WvlzVxV6T1Z61/x0Y8f7Wc7Ur1lqVy+LqOWJ2hp6rXddon5rOF1tfmz5OkT0qzb8dWbxjp1c biuuilJ5Z6r+IcQrixzEy8zl1E6rNt1tMztFY81sztU1eRucN4ffi2p5esRM72n0h7rS6XFo8FcO CkVpX082nwXh3+z9FWLxHi36328vg6TZyW9ABAAAAAAAAAAAAAAAAAAAAAADj8Unm1tK/hqppHvw y1k8/EMk+m0GOPeafiFpCZYwolnXspvHvLa9mF46gmnZmwozRUiUCBKYYsoBLOFbKAX0llEqqyzi QXRLOJVRLOOwLIljZMEgrlhKyYYTAK5nZPN0RZjugUanHzVlz6xtLq361c+9eXItPpXX0dubTU+E bL2lw2++O1fSW6m/VYAISAAAAAAAAAAAAAAAAAp1GbwcfTreelYEydcuMcRrM/L9nnlsV6wqpi2r tv133mfWVkRyRtEdGFva7MzkYZNoamWN4bV4mYa9qztKIujhVppxGI8r1mJegeZpknBqKZY+7L0t LRekWrO8TG8Ns/HJ5ZypAWZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAADS12fp4VJ6z9qVuq1HgUiI+3bpDl589cOKZmevqprXPTbx477rDJlrhr1nq4+s182tMRP RqaziXiZJrWekNG17ZbxWJ336M5LXRbI3dLTJrs07RMY6fan1dHLrowY+X7MVjt6N3R6Kul0EbWm s7bz8Z+LnabQX43r7Y53php/mXj+Dnv0f1JO1x/8ZxbUzj02O15mfLtD13AvZqnDds+pmMmo26el XX0Wh0/D8EYtNjilY7+s/NstpOOTW7QBKgAAAAAAAAAAAAAAAAAAAAAADG88tLW9I3BwJtz6nNf1 vK/DHVqYJ3pzT5y3MPZeojOWMQylEKpTVjZnDCwkqzYQyRRICATCITAJZQxhMAshnEq4ZQC2srKq qrIBZCWNZZgwswmFloVyCu0dFcx1WyrtCBhv5NTPHXds2U5o3hIz4ffbPt+KHUcTSW5c9Jme0u2v VYAKpAAAAAAAAAAAAAAAAYZctcVOa35R6tLrltN795/YvknNqrfhpPLH92V5isd9mWq6fHjk6rn0 ZxG8KK5Jm/wbVZiYZtqrmkqL023bkxvCiY3lJHNyRG81mHS4Rn5sNsNp64+3yaWaNrzOzHBl+i6q mT7s9J+S+ay8mex6EIneN47SNXKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAImYiJme0JafEs3h6fkidrZOn5eaLeJk7eOdm1Hi2vmtPTry/CHmOJcUvmvOPF1n09Pm 6HF9ZGm01qxO3R5vSY7XwzmzTy47zzTEd7en5Mfvt2/PURWdo3tvPrPlKymbktFqTtMTvHzbOLDG f63JXbFX7FdnoODcDprZpq9TjiMMTvSn4vj8l5fxnrk91saPSa7i2hpOfbTVt5x1m0fLydzR6PDo dPGHBXasd585n1lsRERG0dIF5OOe6tAEqgAAAAAAAAAAAAAAAAAAAAAAADX11+TRZrf0y2Gjxe22 gtH4piP3TPpXKwxtjhuYo9xq442iIblI2pC1RET2ILd9kxCqRjZmwlCSEohIJAQAAJZISDKGUd2M MoBnVbVVCyAWVWeSuqyOwIlXZZKue4MJV2WWYT2QKbKL9YlfdRdIo35b7/Hd3KTzUrPrDh27uxpb c2mpPwX/ABX9XAKpAAAAAAAAAAAAAACekTIp1eTwtJmv+GkyJn1oafeazbfpMzLR4jq/o8b823zX 6XNF8ERCvTcNpxLV5LauvPhx9Irv3lhztdtv8TtaWLicXrt03jzjzb2k1nid56ty3s/w+a7Uwzjn 1raejlarhmbhl/FpbxMO/fzj5p/ixSeXOvTtRfeI280ZI26tfDm3pWe63LaZx7qtGvniJ6tPLvOK fOa9WzbJvTbza02jl3n5SSljscK1MajSxWZ96nSW88xw/VfQ9XMT9nfa3yemid43jtLeXsce88qQ EqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADia3UTm1l4j7OP3Y/u 7Vp2rM+kPJW1PhYcmS0+9MzKm/jbwz31weMzbV8UppazPL9q0/BF4rk1GLDSNqxPWPhCnHmnNrtT qPKteWPm6U6OdHaZvO+SaRNvhv12Ub/q3FhtrNVj0uKOt56z6R5y9zix1w4qY6RtWsREOJ7L6OKa S2rvX6zNM7T6Vh3mmZyOfya7eACzIAAAAAAAAAAAAAAAAAAAAAAAAAAczjVvqMVfW/8AZ03I41bf Lp6/OVs/UVrY47NyOzUxd4bUJpEbb3Z7IiOrKIVSjZhMLJYyhKIgmGUQSDESIEbJEgQmCITEAmGU IiGUAyhZVhDOoM4Wx2VQtqBKuyyWEgqlhKyyuyBVaGtkbNmvk7A15l1eH2300R6TMORPSXT4ZO+O 8fFefEX63gEAAAAAAAAAAAAAAAq1WPxdLlp+Kkx+y1Fvsz8gjhaDauGK8sx07y3OE3m1tT6RaP4c vU6yMNKUx73zT0ilY3l2eF6a+m0kRl/zbzz3+Ez5M8z26fJruW6wzYq5sV8d43raNpZjRzPPaTmx 5b6bJ9rHO3zb2WJ8GWPEscY9bgzxH2t62n19GWW0eHOzHU5XbjXZ1x8WTnz2iZ7S2M1IjH2+LX0V KTqs8zO9ot0j8nUthi1J3UaOFMTfLFo6xMbS9BwHWTqdHOO8+/hnln5eTjYMFo1WTH5VnePzXcIm 2k4zlpPSmXy/hfF5eMfJns69OA2cgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAADG/2LfJ874rW845mubliY7bPoto5qzHrDz0+yePNF41OotaJ7RWNtpV1OtfHqZ715fhu j8adNpcVfeyzE2/vLuanhOu1nEctIxTTFa/+ZPbZ3eHcF0vDbTfFE2yzG03t32+DokynXl9+leDB TTYKYccbUpWIhYCzEAAAAAAAAAAAAAAAAAAAAAAAAAAAAcXjE/4zDH9M/wAu04XF5/3jj/0f3Wz9 RUYmzDWxS2I7FSyjuzY1ZKpRKEygEwiWUIkGIk2QJNhKQhMIhkCYZQxhlAMoZwwZwgWQshVCyATL CWc9ldpBhZXLOVdpQK7NfJPRdaWvknoDVvPvOnwuel4+TlXn3nS4VPvXj4QtEV0wAAAAAAAAAAAA AAAAAVV02CmTxK4qRf8AFFeq0AAAanEsfPpZmO9Ji0NDLfkwdOsulrumiyzHlVzJrz4Ovoy26vB8 cTBa9NffLtMY77Rv8Yegx5ImkKdJoY1HC81Y+3OSbVn0mGGkmbY45u6tnrrTOu2xGO0RxCd+nNVj qKxTV1vH2pjaGtnyzXXYdo96ZmGXEMk15b7/AGZiVerWPTYckZcNbx5wzc7hGbnxXxzPWk7x8pdF 0S9jh1OXgAlUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAcPjEf4/FP9H93ccXjMf4vDP9Mx+62fqKrx+S+GvibEFSsqyYwlVK ZYsmIMoRKYJQIPIEiQ2ATCUQygCGUIhMAyhnDCGUIFkLIV1ZxIMpVWWSrsCuyqyyyq09ECq8tfJK 66jJ2Bp5J6upwn7dv9Lk5J951uE/av8AJaIrqAAAAAAAAAAAAAAAAAAAAAAq1Mc2myxPnWf4cmtu XT9fR0tffk0WSe28bfq5Wbamm3326MtunwfK6PCv/AxPraZ/dz9PO97/AOqf5dHhdZrw7Dv3mOb9 XOxRFM+avpe38mvkPHf/AFWlrKba7Tzt99ZxKkfR7euyNXMTrtPHfa0z+zPiM/UR8Zj+Wbdu8HpN M2bfzrV13M4dO2pyR61dNvj44/J/oAWZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADj8bj63BPzdhyeNx0wz8ZWz9RWri7Nmv VrYu0NmqaRZHZlDGGSiwxZSgCEkCBCQSCQBMJRCYgEsoYx3Z17AlMIhlCBnDOGEM4AlhZZKq4KrK 7LLKrIFN2vdfZReAaObu6/CO9vk5OePR1uEd7fJeIrqAIAAAAAAAAAAAAAAAAAAAAGtxCk5NFliI 3mI32+XVyNTyZOHTee946PQKPoeDffw4777eW/yVs60xv+ZxOnr4Okx1t05KRv8Ao41Z5q3yed5m XY1szXRZ5jvFJ/hxItP0aOSN9q7yrtr4f2tHFM5+KT16Yq/vK/iGSbXw4vO14UcPx5MGfNbPG18m 1oj4THRsTw7VanPXVYpi3gzMcnrvCnG11JOupwuN8+a3pEQ6jT4divjxWnJExa09pbjbM5HHu90A JUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAHM41H1GOf6nTc/jEf4Ws+lls/UX45uGekNujTwdm5RNIthKIZKLDFlsiQIShIC EgCUJ7AmGTGO7IDzZQhMSDJMMYZQgZwzhhDOATuqssmVdgVWVWWyqtCBTeVF19lF+wNLNG7q8I+9 8nLyupwnt+S8RXUAQAAAAAAAAAAAAAAAAAAAAAAItWL1mto3iY2lyrcLyUxzix2ia2nvPeK+jrCL OrTVnxpanhuPPemSs8l6RtE7dJj0ldpNP9GwRSZ3neZmV4cR/Vs4AJQAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANHi1d9H M+kt5ra+vPoskfDdOfqK4mn7Q3aNHBPZu0W0RdDOGFWcKLCJZeTGQQlCQSgASBsCYZQxhlAJTAmA TsmAgGcM4YQyjsgRLC3VnaVcgwsrt3Z2V2QK7tbJ1bN5a9waeWO7p8Knt8nNyebpcK8vkvlFdQBA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK9RXmwZI+ErEWjesx6wQeZwejeo0cccuW8 elpblJaaRGxVnCuss4ZrMvJEgCAASISCQIBlCYYpieoM0wx8k7gzIRueYM4Z79FcSy3QEsLJmWFp BjaVVpZWlXMoGNmvkXXlr3kGtknu6XCf7OXkl1OEdl8orqgIAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAHmskcmtzV/rls0U62OXiWX4zErcc9GmkRfWVkSqqziWayxCPIANwBIhIJSxS CRG6dwZwlhEs4BluMdzfqgZxLLdXuy3AmVdpZTKuZBjaVVpWWV2QlhZRdfZRcGpl7urwfrzfJy8r rcH61vPyWitdMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHA4nHLxKZ9awnH2ZcY jbW459aq8fZpfiI2IZwrqzhmsz3Ebm4JN0AMhCQSIASndiAziWUSriWcAyRujc80DM3RCfIETLCW UsZEsJYSslXZAwlTddPZTkBp5e7r8Gj6rJPxhx8k9Xa4PG2C8/FaK10QAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAcfjcbZMFvnDWx9m5x2PqcNvS+zSxT7sNPxH62YZQwqzhRZO6UCB KUAJTux3SDIRuAncQAmJZRLBMSgZ7iIAZRKd2DICUSlAljLCYWMLIFVukNfI2bNbIDTyT7zu8Ijb Sz/qcG/2nf4T/wCE/wD2WnxWt4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHL9oL +Hw2cm28VvEuPptfgyVj6yIn0no7/FtJfW8NzYMe3PaPd39d3iMug1WktNc2C9dvPbeP1aZ9xF+v T471tHu2iflK2HkqWmvaZj5Surqc9Ps5bx+alTHqYHm68S1Vf/NmfnC2vGNTXvyT84Ql6A3cSvHM sfaxVn5Ssrxyv3sM/lKB1xza8bwT3pePyWV4tpZ+/MfOEjfGrXiGlt2zV/PotrqcN/s5aT/+wLRj FontMSlAlKEgndO6IAZQljDIEgeQljLCzOVdkCu/SGrkbF56NPNeKxMzMRHxENe0+89DwuNtHHzl 5PJr8NcnLW3Pbf7r1nCZm2gpae8zMrz4i/W6AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAETETG0xukB4HVaeMHEtRi26RedvkyjBSfX9W77QYvC4xz7dMlYlrU7M929dWJLFc6aPK0q 7YLxPS0S22FlP6q38Zac0yR92s/KVc3tHfFf8tpbcsLRvB/dR/8ALLVnU0r9uL1+dZI1mnmdvGpv 6TOy6ym+Oto2tWJ+cJ/tW+KLK5KW+zes/KU7tG+h01p64qx8Y6NXNo6Y+uPJlp8rLf0rfG7MXtHa 0x8pZxqs9e2a8f8A7Oj7HaTHn0+f6RWM23LETfr6vRW4PoL99NT8ui7F4+vEdXXtnt+fVbXjGsr/ AOZE/OsPS29nuH27YrV+VpeV9pdPXhOtw49NG9Mld55+vXcTPd42I47qo7xSfyWV9oM8d8VJ/VxM d8l46xWF9cV7en6o/qLfxp2I9ob+eCv/AHMo9op89P8A/wBORGmyT5R+qfo2X8P7n9Q/jTsx7RR5 6ef+4/8AuHftg/8A6cWcOSO9J/WEbWr3pY7Efzp2Lcfv5YK/9zWy8d1E/ZpSv5Oba1/+Hb9lc+LP bFt87I7E/wAabWbiurvEx4nL/pjZzc2bJkn372t85ZXx55/BX85lucC0vPxnTxlnnjm32mOiZqUu LJ2p4TwnVavNWaYbRTfre0bQ99pcH0bT0xb78vmtiIiNojaErMwAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAHnfarF7umzRHaZrLjYrdIen9ocPi8JyTt1xzF4eUw23rCm3R4r6bMy wt6kdTaWLdjswmNoZontsCm0K5XWjopnuDC0dGpqG5bs08/daKV672MjbSaif6oh6Z5f2LtvptRX 0tEvUN3Jfo8f7cYve0eX4zV7B5z20xc/C8eSPuZIRficfXlcPaG7ino08HWIbePpLF2NuiyOyrHK 3fZFSwuovHVfaVF4QK5YWTM9UT0EKry6Ps1Tn4zjn8NZn9nOtLseydObiWW34cf918fWfk+PYANn KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAq1WKM+ly4p+/WYeBxTNd6zG0xO0 vobw3FcP0bi2em20Tbmj5Srr418V9sa2Z7qKyzi07MXUylhaU7yjqhLCeiq3ddaFNxFYW7NLNG8t zya+WO6Va9J7FW66mvwidnrXiPY3Ny8RyUn71Jj9Ht3RPjk19HK9pMHj8D1ER3rHN+jqqtTjjNps uOe16zAifXzfTz7kNyndpYazS9qT0mszDdoxrsi6m8LazMq6zDOsq1ZEyrt1WWlXaUCqyq0rbKbi Fdp6PReyFd8uqv8ACsfy83aXrPZHHto89/xX2/SP/dpj6y8vx6EBq5gAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAB5n2q03LfDqqx39y39npmlxbS/TOG5se29tuavzgWzeV4mtui2 O3RRSY2hdVhqO2MvI36iu9lUsrSrvDHn6spnmSiq5jooyV6tq1VV69RC32byTh43h8otMx+r6I+Z aK/g8TwX7bXh9Mid4iW+fjl8n1ICWb57xLBOm4zqse20Tbmj8+qKdnS9q8PhcTw5tumSm0/OHMxz 0Za+uzx3sX1t0Zxurr1ZxvspWiZYWZbsbT0QK7KLrZVZJFaqt5vbezNOTg9J/FaZeJns93wCvLwb T/GJn92uGHldIBowAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADuAPA67F9H4l qMW20VvO3yRWW97T4fC4rXJHSMtI/WGhVlue3b473K2KzMML4+62tujG9pnozXaOSOVFMnVbmq1t trJRW5E7wwvUxTvCyY6CHOt7moxz6Wh9PxTzYaT61h8x1MbZK/OH0zTf+Fxf6I/htj45vL9WgLMn mvbPFvocGWO9L7fq85p5maw9d7VYvE4JkmPu2if3eW0+PasdFNOnxfF1Y2hlykRsmY+LJ0MZjZXa eq2eyi8oQTO0KLdZWzPRjWu6VaqtHR73g0bcI0sf0Q8Nkq93wqNuFaWP+XDTDDytwBowAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAef9q8HNpcGaI60vtPyl56k9Iew49j8ThGe PwxFv0l4zH2U26fDfTYiyJljvsjf4sm6vJ1hrXjq2MkqLdZEVbgbMx0auGdmzNt6iHN1Ub5af6of TdPG2nxx6Vj+HzaaTm1+nx/iyVj930ysbViPRrj45vL9SAuyc7j1efguqj+jd4/T33rD3HEcPj8O 1GP8WOY/Z4TTT7sKadHhbcsZnaCJ3TPZk6VdrKbTutmP0U2nqgrGOsr8deiuI2X09EqKM1dt3uuG f/jdN/06/wAPE546S9rwud+Gaaf+XH8NMMPK2wGjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAABrcRp4nDtRWPPHP8PCYusPoWSvNjtX1iYfPuWaXtX8MzCuvjfw32siu8ptXoxi 0wy5t4YulReqmazu2skbquURWFInddM7VYRGyL291KFnCcfj8e0le/Lbmn8n0N4b2Ur4nHLWmPsY 5e5a5+OXyXugBZmiY3iY9Xz7NjnTa3Ph/BeYj5PoTxftFg8Hjk2iOmWkW/Psrr418V5WrWd2faFc V2jdnEMXWxntupmN7NiYU27iWML6dVMVnddjgVqMsdHr+CW5uE6f4Rt+7yuSsTDv+zWXn0WTHP3L /tK+GHl+O0A1c4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8Dn93W56/wDM t/L3z59qp24jn+OS38lnpr4r7ZxHQ2TEstt3PXUrt27K57rr1VT0BjKnJPRbMqMs7QlV2fYvHvrd VknyrEfu9m8f7FZI8fVU85iJewbT45NfQBKo817W4eulzxHaZrL0rje09ItwqbfhtBVs3leai8RD KLw1sduesL606dWFdsZT1jdhNeq6K9DlhCVUU6s4jZnt1YzAhnM71dH2bycmszY/K1d/0c6OzY4R fwuK4p8rTstn6z8k7HrwGzkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHz3 Vxvr80/8y38voTwGpj/F5/8AqT/JfjTx/WVeyY6FPspc9dZPVXaOq2WEwIUTVRmjo2rNfLHRI3vZ DJycXtX8dZh7t879nsnhcbwz23tt+r6I2nxyb+gCVBzuPY/E4PqI9K7ui19fTxNBnp60n+Aj5/pJ 3jZu1aOnnltMNussdfXbm+l3ZM9URHREdZVXTuT1Nk7boQiOkJw28PU47/htEp5eivJPLMTCZ9Vv x7mJ3iJ9UqNHk8XR4b+tIXuhxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD weqjbWZ4/wCZP8vePCaz/wDIaiP+Zb+UX408f0r9lOxWOifJhXWjfyYWllPRXYQxnrCrJHRd3YZI 6A1NJecHEsN/S0T+76bE7xE+r5dk93LW3pL6ZpMni6PDf8VIn9m2fjm8s9rgFmQxvHNS0esbMiew PnHLyai9fS0w2aNfUTtrs3+uf5bGPqy068fF227KtSsdFlKqNGMV6myyY6sbdIQI8tlOWOi6Jhhk j3RD0vA8nicMx9etZmHRcT2Zyb6XNT8N9/2dt0T449T2AJVAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAHhdfG3E9TH9cvdPEcXjk4zqI/q3L8aeP6xr2TsxpLOekMK6mFo6qpXSrm OqBixvHSVmzC4OfqK7S9/wAByeLwbTW9K7fo8Fqo6Paeyl+fglI/Da0NcMPK7QC7AAB8313TiOf/ AKk/y2MHWrX4jG3E9R/1Lfyv0/aFNOrHxuU7LI7MMayGTVlHWUXhNe6Z6wIUsb9d1m20q7dkDpez N9tRqKT5xEvRvKez9+Xis1/FSYerb5+OTyf6AFlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAB43j9eXjN/jWJ/Z7J5L2mry8Upb8VIF8f6aGOey2eynHvOy7bowrrYSxZSwQJ2YXZ 92N4BoanrEvVexmTm4blr+HJ/aHltRHSXofYm/1Wrp5RaJaYY+X49WA0c4AD51xONuKan/qW/lbp +0MOLRtxbU/9SU4J7KadWPjep2WQrr2WRPRk1TvsndXMpiRCb9FNu0rbTuqvKBscCjfi9PhWZeue V9n434rafTHL1TfPxy+T/QAszAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHmv avHtfTZfnV6VxPajHzcNrf8ABeJFs/XnMcr4no18c+6vr2YadkY2YM57sEDLyY37Mo7MMnYGlqO0 vQ+xNfqNVb1tEfs87qZ2rL0/sVX/AHdnt65P7Q0wx8vx6UBo5wAHz/jUbcX1PT78qtO2vaCnJxjP 8Zif2amnnspp04+OjWejKJ6MKdmcMmyJn4m5ZHzEVPMwtJv0VZLbQDqezcb8RzT6Y/7vUPM+ytZt n1OTyiIh6Ztn45N/6AFlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABocbxeLw nUR5xXm/Rvq8+OMuDJjntaswEeBxT0bNZ6NatZpNqz3rO0rqsdO3PxlaWEMpY+aqWXkryT0ZT2V3 7A0dVPuy9f7G124NM/iyT/Z4zWT7sw957MYfB4Fp4/FE2/WWmGHldcBowAAeM9qKcvFeb8VIly9P 0nq7ntbTbVYL+tJj93CwT76unR4/jo0nozhhTsy3Y1sWljM9Ce7HyQIm3RRlttVbaWrnt0Sh6n2U x8vD8mSfv3/h3XN4Bi8Lg2nj8Uc36y6TeOPXugCUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAPD8RxeBxXUU26Tbmj8+quro+02Lw+I4ssdslNvzhzazvDPbq8d7GW7Dfqz2VzG 0s2qd+iu/Zn5Ksk9BVztX1mI8930zh2LwOHabH+HHWP2fNYp4+vwYvxXiP3fUqxtWIjyjZtj45/L faQFmQADzftfj3w6fJ6WmHmsP23rvaqnNwqLfhvEvIYZ+sV038bo0noy36MK9oZQxrdMyrlnMbMZ QKrS1M07zEestq/RRjr4utwY/wAV4j91p9V18fQdJj8LR4ccfdpEfsuREbREJbuMAAAAAAAAAAAA BAJAAAAEAJEAJQAJQAJEAJQAJQAJEACUJAQlAJEAJQAJQJAAAEAJEAJBAAAJAABAJEJAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwvanDzaPFmjvjv8A tLztJ3h7HjGHx+FainnFeaPnHV4vFbeIU038VbHeGF+kso7Mb9mTdhKnLK3dRm7SIrHhGPxeP6Sv 9cT/AHfSnz72Zx+J7Q45/BWZ/Z9BbZ+OXyfQBZQABzeP4/E4NqI9Ii36S8Ng/wAx9C4jTxOH6ivr jn+Hz3B/mQi/GvjdCnWNlsdI2V07LIlg6USrt2ZzZXMoFV+zPhGLxeOaavpbm/RVltEN72Yx+Jxm b7dKUmf7L5+s9/HtRA2cqRACRACRACRACUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQCQQCRACRACRCQBCQBCQB ACRACRACRACRACL1i9LVntMbPATTwdRkxT3pea/u+gPE8Xx+DxrPHlaYt+qNfGvjvtXXsi0dOrKk dEXjZg6VMtbP2bMtXUdpEV0/Y2nNxbNf8OP+727xvsXH+N1U/wBEfy9k3nxyb+gCVQAGOWvNivX1 rMPnGGOXNNfOJ2fSZ6w+dZKeHxDPX8N7R+6L8a+L63KdoZ7q6zvEMpnowdKJ6ywmWUyqvIKM0vQ+ x+D6rU55+9aKx+TzWa36vbezmDwODYenW+95/Nphj5L6dQBo5wAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAEiAAAEoA AAAAAAAAAAAAAEAkEAkRuAkQbgkQAkQAkQAkQAl5T2nx8nEMOT8dNv0l6pwfarHvpcGWPu32/WCr YvK4mOem6b9mGKd4Z3idmFdka0y1c892zfpMtLPaNpEV6D2Kj/Eauf6YeweQ9ieuTVz8K/3evbT4 5NfQBKoAA8FxCvJxrUx/XMvevD8Zry8fz/Haf2RfjTx/6RSOnRMyypHu9kXjowrqVSrvPRnZVl6V kK0775MsUjvadn0nT4ow6bFijtSsVfPuFYvpPGtNTy54mfy6vorXDm8l9pEC7JIgBIgBIgBIgBIg BIgBIhIAgBIhIAgBIgBIIBIAAhIAhIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAAAAAAAAAAAAAAA AAAAAAAAABAJQkAEAAAAAAAAAAjc3BIjdG4Mkbo5kcwMjdhzHMDPc3V8xzAs3N1fMjmBZubq+Y5g Wbm6vmOYFm5ur5jmBZubq+Y5gWbm6vmOYFm5ur5jmBZubq+Y5gWbm6vmTzAz3N2HMnmBlu5ftFTx OEZJ/DMW/d0t2rxKni8N1FPWkiZ9eS08e7Cy8dGGn6UhZaJljXZGnmc3UT3dPP2cnUT78xCIV6j2 H/8A9c/6f7vXPI+w8bU1U+vL/d63du5NfUiDcVSIAS8b7RV5eOb/AIqRL2TyXtNX/e2KfXH/AHlF +NPH/pr4+2xcxx0hFpY11K7R16KM32ZWz3UaidqSgrc9kcPicWyZJjfw6T+727y3sXh2xarN+K0V h6lvPjj3e0ASqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJQAAAAAkQAkQAkAAAAAAAAAAAAAAA EgAAAAAAAAAAAAAAAAAAAAAgAAABKDcAN0bgkY8xzAyRux5kcwM9zdXNkTcFm6OZXzMeYFvMibKu ZHMC2bo51U2RuC2bom6rc3BZzom6sBZzI52ADPnOdggFnMc6skFnMc6rc3BbznOp3RzAv50c6nml HMC/nOf4qOY5wX85zqOc5wbHOc7X5znBsc6edr85zg2ec52vzpi4NjmY5bROG+/bllVzsNTk5dLl n0pP8BHmMHWNmzt0aum8obm08vVjfrtnxztR0mXHzTvaZdjVRMTLkZo6yiFen9iZ2pqY/wBP93rN 3kPY+/LfPX1rE/u9XzN3HfqzdO6vmTuIZ7m7Hc3Bnu8t7TR/vHBP9E/y9Pu837SV31umn+if5Rfi /j/01MMb1hjkrtKzBG0bMsmOZY11tOYamr6Und0LUc7XT7u3rJPqL8er9lcPhcFpbzyWm39v7O00 +FYvA4Zpsc94xxu227jv1IAgAAAAAAAAABKAAAASgASgBIgBIgBIgBIhIAAAAAAAAAAAAAAAAAAC UACUJAAAAAAAAAAAABIAAAAAAAAAAAAAAAAAAAAg3AEbomQZbo3YzLGbAz3RNlc3YzcFs2YzdVN2 M2Bdzom6nmNwW86JurTAMuY3REJ2BB1ZRVMVBhsbSsiqeUFXLucq3lTygp5TlXcpygp5TlXcpygp 5TlXcqOUFXKjlXcrGYBXysdlswiYBVMdUTCyY6sZBWxlnMMZgGLGZZSwkDdHMiWO4MuY5mEyjcFn N1OdVzHMC3nTzqeY5gX85zqOZPMC+Lqdbk20eb/RKOZr8QybaK/XvtH7iZ9aGlp2luzT3fg19NHS OjbmPcYX67XH1XSZ9XIzRvMuzrK7zLkZYmYnciunb9lZ5dTk+OP+71cXeP8AZnJ/ip2nf3J/l6iL /Fu5L9bMWZczXi6YuIbEWTzKIuyiwLt3nuO25uI4a/hx7/rLuczg8TicvFLbfdpEK6+NPH/phhjo stLGkctUWnoxrrU3j1cnWTzZq1jzl1clo5Zcu8c+txR63iP3Tn6pv4+g4o5cVI9IiGe7CJ2iE7t3 GyN2O6dwSINwSISAlAAlACRAAlAAlACRACRCQAAAAAAAAAASgASISAAAAAAAAAAAAACQAAAAAAAA AAAAAASAAAAAAAAAAAAAAAAIAAAQCAJljuljsCJlhMs9mOwMJYys5TkBVsjZdyHICrZPKt5E8oK4 qmKrOVOwMIqyirPY2Bjyp2ZbAI2NmSARsbMgEbI2ZAMdjZICNkbMkSCNmOzJEgx2YyzljMAwlhKy WEwCuWErJhhMArlhLOWEgxljMpljIImWMyTKJA3N0IBO5vux3NwZbnMx3NwZczT4jf3MdPW27a3a fJOq1XNP2KdIRfi+J2trSYfcjeF+Wm1OicVeWIiN9kai8xjY12ORqultnI1Ecsujq79XP1FovWYI rTgeq+j8QrWZ+3Mx+r2UXeC0WG2Ti2kiN5mL807eUREvbzbaejefHJv62Iv8WUXa0WTFhVtRdlF2 rz9WUXBtc7jR9dqc2T1ttHyhvZMvJitb0jdq6XHNcNenWVN3028U99WRj6Kb02be3Tq18/SN2Lpc 3UdN9nOmZrqKX/DaJ/d0svvTLRzV3jomK6+Pd1vvWJj0ZczT0mXxNJht60hfFnQ4qu3N1cWTEgs3 Tur5k7gz3N2O5uDM3Y7m4MtxBuCQASIASIASAAAAAAACRCQAAAAAAAAEoSAAAAAAAAAAAlAAlCQA AAAAAAAAAAASAAAAAAAAAAAAIASgAAAEJAQJQCNkbMgGOyOVnsAw5TlZ7GwMOVPKy2NgY7GzIBGx skA2AAAAAAAAAAQkBAEghEskAxYzDPZGwK5hjMLJhjMAqmGEwumrCagomFcw2JqqtUFEsLLrV82F o7gqljKyYYTGwMZRKUSCAQAboJnaN5Bjkneu0d5W4ccViIiOzHFWbTzNumP1Zarr8eeRMbxDW1Mx NO67NbkhzNVnmInqzaOZrL93JyZeV0M1++7S02jvxDWxhxx033tPpC8Z6rrezWjmZyazJG2/u03h 2vFibTHoqvamiwVwY+nLGzV0+SZ1Mx8G0/45tOhzJ5lXMc3UVXRdlF1HP+iYsDPLPPy49/tz1+Te pSIr0ho6ak5Ms5J8o2q6NImOrHV7XX488ypzTtHXo0s9t6zG7c1G1qz6ubeZiZ3UatXJG3yauSO7 cvMTEx5tPLb3prPRMVr0HB8vicNxf0+7+kt+LOJwTJyY/Bnz3tH93X36N58cWvq6LSyiyndMSlC7 mZcymLJiwLosmJVRLKLAtiU7q4lMSCzc3YxJuDMRuAlKAEgAAAlAkAAAAAABKAEgAAAAAJAAAAAA AAAAAAAEgAAAAAAAAAAAAAkAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAhIAAACAAAASgAAAAAAEAAAA hGzJAImGMwzQDDZjNVuyNgUTVhNGxysZqDVmiu1G5NN2M4waM0+DCaN2cbGcQNGaMZq3JxMJxA1J qx2bU4kU09slorWNwa20z02RXHbJbl26QvtFovbHWkxEdJt5y2MOHlr2U1W3jx+1hiw8vSO63lmI XRTaEWmtY6snRHO1VpmJ+DjavpSZl2s8b7y4HFcnh0n0gha5ebJN55KRM2mdoiPN6fh+kpwXh0Wy RHj5Otp/s5Ps1p62y31+em9aTMYt/OfVfxTiPjZ52naI7fBrI5t66xz5+a1rW7yx0eSL6iZjtEOX qNbSletom3lENjh2fbHzbbWt3iVozruc+5ztWubf4M4ybpQ2Oboyrva0Vjza8WdDR4OkXt3n9ldX kaePP9VtYqctYhdvt5oivTeCZ2YOxXk6ubqMfV0b9mrljfqlFcq88k7z2U5axeItDa1OPessuC8P ya7XRWYnwqdbT/ZMilvIu4dpslNdixXja8Y5tt85djZdbDWnGOesRtXFtuw6T27No5Kx2OrKYQlC ExKJgBnEpiyvdlEgsizKLKollFgWxLKJVRLKJBbEp3VxLKJBnuMWQJEbpBIAAAJAAAABIAAAAAAA lAJAAAAAAAAAAAAAASAAAAAAAAAAAAAJAAAABAJABAlAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAA AAABAJQAAAAgAABAAI2EoBGyJhkgGPKxmqxAKpownHC+YRMdN5BrTj67R3bOn01o7p01Iv71u89o b9a7LfBTfS1vWI2jf12VfQPSW8KX2mas+NC2iv6xMNfJpMnLtEbuuxtMRCtzF55NR5rPps1N/ctP y6uHreE6nXZ4pak48X3rT06fB7fNeI33cbX6mI32R/MWu7XF116aDSRhxbRERs8f499bkyZeeKae kzE2mdon81/tfxDLGOunwbzlzbx08oaHBvZHJlx48mrvaa94pu04y617576rNGLRRM0397JEd/lu 9Dw/S3x4qxffo6mm4NjwUiKY4iI9Ib1dHFY6QIaNabbrYrLfrpJtaK1rMzPZb/s+05IpP59OyLeJ k7eNfRaOc1ue32I7fGXYpi5Y77M8OGMeOKxHSFsU3Y29deZMzirl6dlVvhLatCjJHeYQv1rXnps1 8k9/VsW6qLVmZIi1rzitlvFKRvaZ2h6TSaenC9FFY+3brM+sqeG8Prp4+kZ+lvuxPkr1mqm95nfp DXM459676a2q1dsV7XietvNno78+CJn1cjX6mOeIm0bR33dfRU5NJjidt9t5afjG/V6JZ7I2QMNh nyo2BhsMuVG3wAhMSbbQRAMolnE+iuGUSCyJZRKuGUSCyJZK4llEgyZMYTuCUsYSCQASISAAAlCQ AAAAAAEoASCASAAAAAAAAAAAAlACRACQAAAAAAAAAEgCEoASCAAAAAAAAAAAAAAAAAAAAAAABAAA AAAAAAAISAIAAAAAAQAAACASgAAAQJAQAAhIDHZhln3do7z0WS18mWsajHjmes7pg3dNi5aRMNqO yvDHTpPRaigHZhN4hHRlaVN59JY3zRENLUavaO+yq0iNVlitJ6vNcR1MVi0zO0era1/Ea0rPvbz5 PM5MWp45qvo2GZrhmfrsnpHpHzTCseEcM/2vrr8Q1Eb4qzy44nziPN63HpYiIiI7LNHoqabBTFii IpSNohuVxrKtWMEejPwY9G1FFmHB4mWJn7MdfnIM9JpIx15to5pbUaas/a6rqViI7MxPxqX0UT1r O3wVzpbR2hviP5i03Y5s6a879FNtHljydhExCv8AMTPJXBnRZbz0iG5ptFjwe/l96zctMVamTJtE yTMibu1VrdTzRMR0j0ed4lr64MVpm0RERvMz5NvX62uOJ69XhOKX1HH9bHDtFvNYnfJeOy0Z2ojX 6jjnEq6fRUmccTvN/J9H0eKcOnx45neaxEbubwHgOHg+milI3vP2resu3Wu0JQmITsmISDHZHKz2 JgFc1RMLJhGwK9iIZ7MZgEdgmAEwyiWCdwWRLKJVxKYsC2JTuriWUSDNlEsIlMAySx3SCRCQSIAS AAACRACQAAAAAAASIASAAAAAAAAAAAAAAACRACRACQASIAAAAAAAAAAAAAAAAAAAAAAAAQCUAAAA AAAAAAIAAAAAAAAQAAAAAACBICBICAAEJAQJQCJcLjuS2ny6fPG/LWdpd1o8T0X07SXx/e7wCdJx Wa0jmneHQpxPDMdZmJfNtZm49weZrh0/j4o7VtSZ2+Uw0/8A7o49k92vBLc/ntFohFW9PqGXimOI 6Tu1L8T3eCx6r2t1O3JwvHjifO99v7t/Bwf2l1PXU6rS6eJ8qUm8x+so5TsekzcSjbvs4mt4rzW5 K2mbT0itesy2cHsvbvqtbmyz5xERWP2jd1tJwrTaONsOKtZ8585+cnDrzmn4Rq+IZObUROHD32n7 Vv8A0ej0uhxaXFGPFSK1j0bkY4jyZRVZVXFGUVWbGwKsk8mObekNrSW3pWf1a2aYjHbm7bNnQ1id PW0TvuDdhJEbQABMsLW2R0ZTMQrvfbz2YWzVhpanUxEd0dWkW5c8R5uXxDX1w4pnfr5Q19XxKuOJ 2neXltVqtVxbV/RdJ715+1bypANfiOu1HENV9C0MTfNeesx2rD1PAeBYuE6aKx72W3W9/WVnBuB4 eF4dqRzZbdb5J72l160WVK02ZxCYhOwI23TsnY2BGxsnYBjsiYZsZBjMMZZSgGEolMsQDdG6NwZ7 piVe6YkFsSziVMWZRILolMSriWUSCyJTuwhMSDMRCQSI3SAlACRCQAAEoAEoASAAAAAAAAACUACR ACQAAAAAAAAAAAAASAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAABAAAAAAAAAAAAACBKAAAAAAAQ JQAAAhICEbJAYTWJ7wx8KvpC0BV4ceieWGewDHlNmWwCNjZICNhIDmcZredBecdpiY69FXCOLW+i UiZidukulmxxlx2paN4mNng+K4+I8Hy2yaTfl37TXetoCPfRxfp1qi3F48ofKMvtvxak8s6LDv61 rZji9rPaLUf5PC+bfttS0q8q3p9W/wBrRMdpUZuKdN99nzvFqPbTVz7nD8OKs+do2/mW3h4D7Xaq ZnPrtNpqz35aRaYOHY9Zk4pNt9rR+rl6zi+OnS+WN57Rv1lXp/YrNaYtruL6zNPnGO3hxP6O5w/2 f0HDuun09Yv55Le9afznqcOvO4tBreMTHu30unnva0bWt8on+70nDuE4OHYYx4Kbesz3tPrMuhGO IjpDOKrK9YVpsyiGUQnYGOyUgI2SlAIEmwMWMs9kTAMJYzDOYRMArmGErZhhMArlHmzmGMwDE3Ts bAbs4swj5pgFkSziVcM4BZEsolXDKAZwyhjCYBkACQhIAAAAAAAJAAAAAAAAAAAAAAAAAAAShIAA AAAAAAJAAAAAAAAAAAAAABAJEAAAAAAAAAAAAAAAIEoBKAAAAAAAAAAAAAAABAlAAAAAAAIAAAAA BAkBAkBAkBAlACEgMZjdjbFW8bWrEx8YWANb6Fp+bfwab+vLDKMFK9qxH5L0bAr8OPRPKz2AY7J2 SbAjYZAI2E7AIEgIEgIEgMdkSy2NgY7MdlmyNoBXsxmFuyNgVTVjNV3KjlBRNTlXTVHKCrlIqt5T lBhEMohlFerLlBjEMohMVTEARDKCITsAk2AEgAAAkAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAD/ 2Q==`;async function g0e(e){let t=(r,s="application/octet-stream")=>fetch(`data:${s};base64,${r}`).then(i=>i.blob()),a,n;switch(e.config.warmup){case"face":a=await t(B0);break;case"body":case"full":a=await t(W0);break;default:a=null}if(a){let r=await createImageBitmap(a);n=await e.detect(r,e.config),r.close()}return n}async function x0e(e){return new Promise(t=>{let a;switch(e.config.warmup){case"face":a="data:image/jpeg;base64,"+B0;break;case"full":case"body":a="data:image/jpeg;base64,"+W0;break;default:a=""}let n;if(typeof Image!="undefined")n=new Image;else if(ne.Image)n=new ne.Image;else{t(void 0);return}n.onload=async()=>{let r=Nn(n.naturalWidth,n.naturalHeight);if(!r)K("Warmup: Canvas not found"),t(void 0);else{let s=r.getContext("2d");s&&s.drawImage(n,0,0);let i=await e.image(r,!0),o=i.tensor?await e.detect(i.tensor,e.config):void 0;t(o)}},a?n.src=a:t(void 0)})}async function A0e(e){let t=r=>Buffer.from(r,"base64"),a;e.config.warmup==="face"?a=t(B0):a=t(W0);let n;if("node"in Ue&&ia()==="tensorflow"){let r=(void 0).decodeJpeg(a),s=Gt(r,0);e.tf.dispose(r),n=await e.detect(s,e.config),e.tf.dispose(s)}else e.config.debug&&K("Warmup tfjs-node not loaded");return n}async function y0e(e){let t;return typeof createImageBitmap=="function"?t=await g0e(e):typeof Image!="undefined"||ne.Canvas!==void 0?t=await x0e(e):t=await A0e(e),t}async function b0e(e){var o,l,u,p;if(!W().flagRegistry.ENGINE_COMPILE_ONLY)return;let t=ia(),a=tr();if(t!=="webgl"&&t!=="humangl"||!(a!=null&&a.checkCompileCompletion))return;W().set("ENGINE_COMPILE_ONLY",!0);let n=kt().state.numTensors,r=[];for(let[c,d]of Object.entries(e.models.models)){if(!d)continue;let h=(d==null?void 0:d.modelSignature)&&((l=(o=d==null?void 0:d.inputs)==null?void 0:o[0])==null?void 0:l.shape)?[...d.inputs[0].shape]:[1,64,64,3],f=(d==null?void 0:d.modelSignature)&&((p=(u=d==null?void 0:d.inputs)==null?void 0:u[0])==null?void 0:p.dtype)?d.inputs[0].dtype:"float32";for(let g=0;gY(x)):Y(g)}catch(g){e.config.debug&&K("compile fail model:",c)}Y(m)}let s=await a.checkCompileCompletionAsync();a.getUniformLocations(),e.config.debug&&K("compile pass:",{models:r,kernels:s.length}),W().set("ENGINE_COMPILE_ONLY",!1);let i=kt().state.numTensors;i-n>0&&K("tensor leak:",i-n)}async function Yk(e,t){await wp(e,!1);let a=te();return e.state="warmup",t&&(e.config=Ct(e.config,t)),!e.config.warmup||e.config.warmup.length===0||e.config.warmup==="none"?or():new Promise(async n=>{await e.models.load(),await b0e(e);let r=await y0e(e),s=te();e.config.debug&&K("warmup",e.config.warmup,Math.round(s-a),"ms"),e.emit("warmup"),n(r)})}var Mu,Mp,$p,V0,Is,A5=class{constructor(t){ue(this,"version");ue(this,"config");ue(this,"result");ue(this,"state");ue(this,"process");ue(this,"tf");ue(this,"env",ne);ue(this,"draw",s0);ue(this,"match",$0);ue(this,"models");ue(this,"events");ue(this,"faceTriangulation");ue(this,"faceUVMap");ue(this,"performance");Gn(this,Mu,void 0);Gn(this,Mp,void 0);Gn(this,$p,void 0);ue(this,"analyze",(...t)=>{if(!Ga(this,Mp))return;let a=this.tf.engine().state.numTensors,n=Ga(this,Mu);fr(this,Mu,a);let r=a-n;r!==0&&K(...t,r)});Gn(this,V0,t=>{if(!Ga(this,$p))return null;if(!t)return"input is not defined";if(this.env.node&&!(t instanceof pt))return"input must be a tensor";try{this.tf.getBackend()}catch(a){return"backend not loaded"}return null});ue(this,"webcam",new Jh);ue(this,"emit",t=>{var a;(a=this.events)!=null&&a.dispatchEvent&&this.events.dispatchEvent(new Event(t))});Gn(this,Is,{});let a=(xp.tfjs||A2).replace(/-(.*)/,"");Io.wasmPath=`https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@${a}/dist/`,Io.modelBasePath=ne.browser?"../models/":"file://models/",this.version=X3,Object.defineProperty(this,"version",{value:X3}),this.config=JSON.parse(JSON.stringify(Io)),Object.seal(this.config),this.config.cacheModels=typeof indexedDB!="undefined",t&&(this.config=Ct(this.config,t)),u9(this.config),this.tf=Ue,this.state="idle",fr(this,Mu,0),fr(this,Mp,!1),fr(this,$p,!1),this.performance={},this.events=typeof EventTarget!="undefined"?new EventTarget:void 0,this.models=new Rp(this),tg(),this.result=or(),this.process={tensor:null,canvas:null},this.faceTriangulation=tw,this.faceUVMap=aw,L0(this,null,""),this.emit("create"),(this.config.debug||this.env.browser)&&K(`version: ${this.version}`),this.config.debug&&K(`tfjs version: ${this.tf.version["tfjs-core"]}`);let n=JSON.parse(JSON.stringify(this.env));delete n.kernels,delete n.initial,delete n.perfadd,this.config.debug&&K("environment:",n)}reset(){let t=this.config.backend;this.config=JSON.parse(JSON.stringify(Io)),this.config.backend=t,j3(),ne.initial=!0}validate(t){let a=U3(Io,t||this.config);return a.length===0&&(this.config=Ct(this.config,t)),a}now(){return te()}image(t,a=!1){return Zh(t,this.config,a)}async segmentation(t,a){var s,i,o;if(a&&(this.config=Ct(this.config,a)),!this.config.segmentation.enabled)return null;let n=await Zh(t,this.config);if(!n.tensor)return null;let r=null;return(s=this.config.segmentation.modelPath)!=null&&s.includes("rvm")&&(r=await jk(n.tensor,this.config)),(i=this.config.segmentation.modelPath)!=null&&i.includes("meet")&&(r=await Ik(n.tensor,this.config)),(o=this.config.segmentation.modelPath)!=null&&o.includes("selfie")&&(r=await Xk(n.tensor,this.config)),Y(n.tensor),r}compare(t,a){return l9(this.config,t,a)}async init(){await wp(this,!0),await this.tf.ready(),j3()}async load(t){this.state="load";let a=te(),n=Object.values(this.models.models).filter(i=>i).length;t&&(this.config=Ct(this.config,t)),this.env.initial&&(await wp(this,!1)||K("error: backend check failed"),await Kd(),this.env.browser&&(this.config.debug&&K("configuration:",this.config),this.config.debug&&K("tf flags:",this.tf.ENV.flags))),await this.models.load(this),this.env.initial&&this.config.debug&&K("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.env.initial=!1,Object.values(this.models.models).filter(i=>i).length!==n&&(this.models.validate(),this.emit("load"));let s=Math.trunc(te()-a);s>(this.performance.loadModels||0)&&(this.performance.loadModels=this.env.perfadd?(this.performance.loadModels||0)+s:s)}next(t=this.result){return kk(t,this.config)}async warmup(t){let a=te(),n=await Yk(this,t),r=te();return this.performance.warmup=Math.trunc(r-a),n}async profile(t,a){let n=await this.tf.profile(()=>this.detect(t,a)),r={},s=0;for(let o of n.kernels){let l=Number(o.kernelTimeMs)||0;r[o.name]?r[o.name]+=l:r[o.name]=l,s+=l}let i=[];Object.entries(r).forEach(o=>i.push({kernel:o[0],time:o[1],perc:0}));for(let o of i)o.perc=Math.round(1e3*o.time/s)/1e3,o.time=Math.round(1e3*o.time)/1e3;return i.sort((o,l)=>l.time-o.time),i.length=20,i}async detect(t,a){return this.state="detect",new Promise(async n=>{var g,x,A,y,b,w,S,C,E,_,$,M,I,N,O,L,B,G,j,U,H;this.state="config";let r;this.config=Ct(this.config,a),this.state="check";let s=Ga(this,V0).call(this,t);s&&(K(s,t),this.emit("error"),n(or(s)));let i=te();await this.load(),r=te(),this.state="image";let o=await Zh(t,this.config);if(this.process=o,this.performance.inputProcess=this.env.perfadd?(this.performance.inputProcess||0)+Math.trunc(te()-r):Math.trunc(te()-r),this.analyze("Get Image:"),!o.tensor){this.config.debug&&K("could not convert input to tensor"),this.emit("error"),n(or("could not convert input to tensor"));return}this.emit("image"),r=te(),this.config.skipAllowed=await o9(this.config,o.tensor),this.config.filter.autoBrightness=(this.config.filter.autoBrightness||!1)&&this.config.skipAllowed,this.performance.totalFrames||(this.performance.totalFrames=0),this.performance.cachedFrames||(this.performance.cachedFrames=0),this.performance.totalFrames++,this.config.skipAllowed&&this.performance.cachedFrames++,this.performance.cacheCheck=this.env.perfadd?(this.performance.cacheCheck||0)+Math.trunc(te()-r):Math.trunc(te()-r),this.analyze("Check Changed:");let l=[],u=[],p=[],c=[];this.state="detect:face",this.config.async?(l=this.config.face.enabled?Vg(this,o.tensor):[],this.performance.face&&delete this.performance.face):(r=te(),l=this.config.face.enabled?await Vg(this,o.tensor):[],this.performance.face=this.env.perfadd?(this.performance.face||0)+Math.trunc(te()-r):Math.trunc(te()-r)),this.config.async&&(this.config.body.maxDetected===-1||this.config.hand.maxDetected===-1)&&(l=await l),this.analyze("Start Body:"),this.state="detect:body";let d=this.config.body.maxDetected===-1?Ct(this.config,{body:{maxDetected:this.config.face.enabled?1*l.length:1}}):this.config;this.config.async?((g=this.config.body.modelPath)!=null&&g.includes("posenet")?u=this.config.body.enabled?c5(o.tensor,d):[]:(x=this.config.body.modelPath)!=null&&x.includes("blazepose")?u=this.config.body.enabled?ig(o.tensor,d):[]:(A=this.config.body.modelPath)!=null&&A.includes("efficientpose")?u=this.config.body.enabled?hg(o.tensor,d):[]:(y=this.config.body.modelPath)!=null&&y.includes("movenet")&&(u=this.config.body.enabled?s5(o.tensor,d):[]),this.performance.body&&delete this.performance.body):(r=te(),(b=this.config.body.modelPath)!=null&&b.includes("posenet")?u=this.config.body.enabled?await c5(o.tensor,d):[]:(w=this.config.body.modelPath)!=null&&w.includes("blazepose")?u=this.config.body.enabled?await ig(o.tensor,d):[]:(S=this.config.body.modelPath)!=null&&S.includes("efficientpose")?u=this.config.body.enabled?await hg(o.tensor,d):[]:(C=this.config.body.modelPath)!=null&&C.includes("movenet")&&(u=this.config.body.enabled?await s5(o.tensor,d):[]),this.performance.body=this.env.perfadd?(this.performance.body||0)+Math.trunc(te()-r):Math.trunc(te()-r)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.state="detect:hand";let h=this.config.hand.maxDetected===-1?Ct(this.config,{hand:{maxDetected:this.config.face.enabled?2*l.length:1}}):this.config;this.config.async?((_=(E=this.config.hand.detector)==null?void 0:E.modelPath)!=null&&_.includes("handdetect")?p=this.config.hand.enabled?qg(o.tensor,h):[]:(M=($=this.config.hand.detector)==null?void 0:$.modelPath)!=null&&M.includes("handtrack")&&(p=this.config.hand.enabled?Zg(o.tensor,h):[]),this.performance.hand&&delete this.performance.hand):(r=te(),(N=(I=this.config.hand.detector)==null?void 0:I.modelPath)!=null&&N.includes("handdetect")?p=this.config.hand.enabled?await qg(o.tensor,h):[]:(L=(O=this.config.hand.detector)==null?void 0:O.modelPath)!=null&&L.includes("handtrack")&&(p=this.config.hand.enabled?await Zg(o.tensor,h):[]),this.performance.hand=this.env.perfadd?(this.performance.hand||0)+Math.trunc(te()-r):Math.trunc(te()-r)),this.analyze("End Hand:"),this.analyze("Start Object:"),this.state="detect:object",this.config.async?((B=this.config.object.modelPath)!=null&&B.includes("nanodet")?c=this.config.object.enabled?o5(o.tensor,this.config):[]:(G=this.config.object.modelPath)!=null&&G.includes("centernet")&&(c=this.config.object.enabled?ug(o.tensor,this.config):[]),this.performance.object&&delete this.performance.object):(r=te(),(j=this.config.object.modelPath)!=null&&j.includes("nanodet")?c=this.config.object.enabled?await o5(o.tensor,this.config):[]:(U=this.config.object.modelPath)!=null&&U.includes("centernet")&&(c=this.config.object.enabled?await ug(o.tensor,this.config):[]),this.performance.object=this.env.perfadd?(this.performance.object||0)+Math.trunc(te()-r):Math.trunc(te()-r)),this.analyze("End Object:"),this.state="detect:await",this.config.async&&([l,u,p,c]=await Promise.all([l,u,p,c])),this.state="detect:gesture";let f=[];this.config.gesture.enabled&&(r=te(),f=[...Qw(l),...Jw(u),...tk(p),...ek(l)],this.config.async?this.performance.gesture&&delete this.performance.gesture:this.performance.gesture=this.env.perfadd?(this.performance.gesture||0)+Math.trunc(te()-r):Math.trunc(te()-r)),this.performance.total=this.env.perfadd?(this.performance.total||0)+Math.trunc(te()-i):Math.trunc(te()-i);let m=((H=this.process.tensor)==null?void 0:H.shape)||[0,0,0,0];this.result={face:l,body:u,hand:p,gesture:f,object:c,performance:this.performance,canvas:this.process.canvas,timestamp:Date.now(),error:null,width:m[2],height:m[1],get persons(){return Zk(l,u,p,f,m)}},Y(o.tensor),this.emit("detect"),this.state="idle",n(this.result)})}async sleep(t){return new Promise(a=>{setTimeout(a,t)})}async video(t,a=!0,n=0){a?(Ga(this,Is)[t.id]||(this.config.debug&&K("video start",t.id),Ga(this,Is)[t.id]=!0),!t.paused&&Ga(this,Is)[t.id]&&t.readyState>=2&&await this.detect(t),n>0&&await this.sleep(n),Ga(this,Is)[t.id]&&requestAnimationFrame(()=>this.video(t,a,n))):(this.config.debug&&K("video stop",t.id),Ga(this,Is)[t.id]=!1)}};Mu=new WeakMap,Mp=new WeakMap,$p=new WeakMap,V0=new WeakMap,Is=new WeakMap;return OI(w0e);})(); ================================================ FILE: extern/human/models/blazeface.json ================================================ { "format": "graph-model", "generatedBy": "https://github.com/google/mediapipe", "convertedBy": "https://github.com/vladmandic", "userDefinedMetadata": { "signature": { "inputs": { "input:0":{"name":"input:0","dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"256"},{"size":"256"},{"size":"3"}]}} }, "outputs": { "Identity_3:0":{"name":"Identity_3:0","dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"384"},{"size":"16"}]}},"Identity:0":{"name":"Identity:0","dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"512"},{"size":"1"}]}}, "Identity_1:0":{"name":"Identity_1:0","dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"384"},{"size":"1"}]}},"Identity_2:0":{"name":"Identity_2:0","dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"512"},{"size":"16"}]}} } } }, "modelTopology": { "node": [ {"name":"unknown_135","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"96"},{"size":"2"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_136","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"2"}]}}}}}, {"name":"StatefulPartitionedCall/functional_1/tf_op_layer_classificators_1/classificators_1/shape","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"3"}]}}},"dtype":{"type":"DT_INT32"}}}, {"name":"unknown_133","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"96"},{"size":"6"}]}}}}}, {"name":"unknown_134","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"6"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/tf_op_layer_classificators_2/classificators_2/shape","op":"Const","attr":{"dtype":{"type":"DT_INT32"},"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"3"}]}}}}}, {"name":"unknown_131","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"96"},{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_132","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/tf_op_layer_regressors_1/regressors_1/shape","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"3"}]}}},"dtype":{"type":"DT_INT32"}}}, {"name":"unknown_93","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"48"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_95","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"48"},{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_96","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_61","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}}}}, {"name":"unknown_63","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"48"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_64","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"48"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_57","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_59","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_60","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_53","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_55","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_56","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_49","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}}}}, {"name":"unknown_51","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_52","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}}}}, {"name":"unknown_29","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_31","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_32","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}}}}, {"name":"unknown","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"5"},{"size":"5"},{"size":"3"},{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_0","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_3","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}}}}, {"name":"unknown_4","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_5","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_7","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_8","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}}}}, {"name":"unknown_9","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_11","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_12","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_13","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_15","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}}}}, {"name":"unknown_16","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_17","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}}}}, {"name":"unknown_19","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_20","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}}}}, {"name":"unknown_21","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_23","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_24","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}}}}, {"name":"unknown_25","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_27","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_28","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_33","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_35","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}}}}, {"name":"unknown_36","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_37","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}}}}, {"name":"unknown_39","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}}}}, {"name":"unknown_40","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_41","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_43","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_44","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_45","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"24"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_47","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"24"},{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_48","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"24"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/tf_op_layer_Pad/Pad/paddings","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"4"},{"size":"2"}]}}},"dtype":{"type":"DT_INT32"}}}, {"name":"unknown_65","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"48"},{"size":"1"}]}}}}}, {"name":"unknown_67","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"48"},{"size":"48"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_68","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"48"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_69","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"48"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_71","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"48"},{"size":"48"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_72","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"48"}]}}}}}, {"name":"unknown_73","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"48"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_75","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"48"},{"size":"48"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_76","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"48"}]}}}}}, {"name":"unknown_77","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"48"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_79","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"48"},{"size":"48"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_80","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"48"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_81","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"48"},{"size":"1"}]}}}}}, {"name":"unknown_83","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"48"},{"size":"48"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_84","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"48"}]}}}}}, {"name":"unknown_85","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"48"},{"size":"1"}]}}}}}, {"name":"unknown_87","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"48"},{"size":"48"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_88","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"48"}]}}}}}, {"name":"unknown_89","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"48"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_91","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"48"},{"size":"48"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_92","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"48"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/tf_op_layer_Pad_1/Pad_1/paddings","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"4"},{"size":"2"}]}}},"dtype":{"type":"DT_INT32"}}}, {"name":"unknown_97","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"96"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_99","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"96"},{"size":"96"}]}}}}}, {"name":"unknown_100","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_101","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"96"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_103","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"96"},{"size":"96"}]}}}}}, {"name":"unknown_104","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_105","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"96"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_107","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"96"},{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_108","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_109","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"96"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_111","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"96"},{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_112","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_113","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"96"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_115","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"96"},{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_116","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_117","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"96"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_119","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"96"},{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_120","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"96"}]}}}}}, {"name":"unknown_121","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"96"},{"size":"1"}]}}}}}, {"name":"unknown_123","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"96"},{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_124","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_125","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"96"},{"size":"1"}]}}}}}, {"name":"unknown_127","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"96"},{"size":"96"}]}}}}}, {"name":"unknown_128","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_129","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"96"},{"size":"96"}]}}}}}, {"name":"unknown_130","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"96"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/tf_op_layer_regressors_2/regressors_2/shape","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"3"}]}}},"dtype":{"type":"DT_INT32"}}}, {"name":"input","op":"Placeholder","attr":{"dtype":{"type":"DT_FLOAT"},"shape":{"shape":{"dim":[{"size":"1"},{"size":"256"},{"size":"256"},{"size":"3"}]}}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d/Relu","op":"_FusedConv2D","input":["input","unknown","unknown_0"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","2","2","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"U0FNRQ=="},"fused_ops":{"list":{"s":["Qmlhc0FkZA==","UmVsdQ=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/conv2d/Relu","unknown_1"],"attr":{"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_1/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d/depthwise","unknown_3","unknown_4"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/functional_1/add/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/conv2d/Relu","StatefulPartitionedCall/functional_1/conv2d_1/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_1/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu/Relu","unknown_5"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_2/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_1/depthwise","unknown_7","unknown_8"],"device":"/device:CPU:0","attr":{"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/add_1/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu/Relu","StatefulPartitionedCall/functional_1/conv2d_2/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_1/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_1/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_2/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_1/Relu","unknown_9"],"attr":{"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_3/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_2/depthwise","unknown_11","unknown_12"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"}}}, {"name":"StatefulPartitionedCall/functional_1/add_2/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_1/Relu","StatefulPartitionedCall/functional_1/conv2d_3/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_2/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_2/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_3/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_2/Relu","unknown_13"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_4/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_3/depthwise","unknown_15","unknown_16"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_3/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_2/Relu","StatefulPartitionedCall/functional_1/conv2d_4/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_3/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_3/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_4/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_3/Relu","unknown_17"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_5/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_4/depthwise","unknown_19","unknown_20"],"device":"/device:CPU:0","attr":{"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="}}}, {"name":"StatefulPartitionedCall/functional_1/add_4/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_3/Relu","StatefulPartitionedCall/functional_1/conv2d_5/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_4/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_4/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_5/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_4/Relu","unknown_21"],"attr":{"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_6/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_5/depthwise","unknown_23","unknown_24"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_5/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_4/Relu","StatefulPartitionedCall/functional_1/conv2d_6/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_5/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_5/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_6/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_5/Relu","unknown_25"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_7/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_6/depthwise","unknown_27","unknown_28"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_6/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_5/Relu","StatefulPartitionedCall/functional_1/conv2d_7/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_6/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_6/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_7/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_6/Relu","unknown_29"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","2","2","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/max_pooling2d/MaxPool","op":"MaxPool","input":["StatefulPartitionedCall/functional_1/re_lu_6/Relu"],"attr":{"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","2","2","1"]}},"ksize":{"list":{"i":["1","2","2","1"]}},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_8/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_7/depthwise","unknown_31","unknown_32"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_7/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/conv2d_8/BiasAdd","StatefulPartitionedCall/functional_1/max_pooling2d/MaxPool"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_7/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_7/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_8/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_7/Relu","unknown_33"],"attr":{"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_9/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_8/depthwise","unknown_35","unknown_36"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_8/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_7/Relu","StatefulPartitionedCall/functional_1/conv2d_9/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_8/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_8/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_9/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_8/Relu","unknown_37"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_10/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_9/depthwise","unknown_39","unknown_40"],"device":"/device:CPU:0","attr":{"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/add_9/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_8/Relu","StatefulPartitionedCall/functional_1/conv2d_10/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_9/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_9/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_10/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_9/Relu","unknown_41"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_11/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_10/depthwise","unknown_43","unknown_44"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_10/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_9/Relu","StatefulPartitionedCall/functional_1/conv2d_11/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_10/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_10/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_11/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_10/Relu","unknown_45"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_12/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_11/depthwise","unknown_47","unknown_48"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"}}}, {"name":"StatefulPartitionedCall/functional_1/add_11/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_10/Relu","StatefulPartitionedCall/functional_1/conv2d_12/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_11/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_11/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_12/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_11/Relu","unknown_49"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_13/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_12/depthwise","unknown_51","unknown_52"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"}}}, {"name":"StatefulPartitionedCall/functional_1/add_12/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/conv2d_13/BiasAdd","StatefulPartitionedCall/functional_1/re_lu_11/Relu"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_12/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_12/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_13/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_12/Relu","unknown_53"],"attr":{"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_14/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_13/depthwise","unknown_55","unknown_56"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_13/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/conv2d_14/BiasAdd","StatefulPartitionedCall/functional_1/re_lu_12/Relu"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_13/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_13/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_14/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_13/Relu","unknown_57"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_15/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_14/depthwise","unknown_59","unknown_60"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_14/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/conv2d_15/BiasAdd","StatefulPartitionedCall/functional_1/re_lu_13/Relu"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_14/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_14/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_15/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_14/Relu","unknown_61"],"attr":{"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","2","2","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/functional_1/max_pooling2d_1/MaxPool","op":"MaxPool","input":["StatefulPartitionedCall/functional_1/re_lu_14/Relu"],"attr":{"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","2","2","1"]}},"ksize":{"list":{"i":["1","2","2","1"]}},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_16/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_15/depthwise","unknown_63","unknown_64"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/tf_op_layer_Pad/Pad","op":"Pad","input":["StatefulPartitionedCall/functional_1/max_pooling2d_1/MaxPool","StatefulPartitionedCall/functional_1/tf_op_layer_Pad/Pad/paddings"],"attr":{"T":{"type":"DT_FLOAT"},"Tpaddings":{"type":"DT_INT32"},"_cloned":{"b":true}}}, {"name":"StatefulPartitionedCall/functional_1/add_15/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/conv2d_16/BiasAdd","StatefulPartitionedCall/functional_1/tf_op_layer_Pad/Pad"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_15/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_15/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_16/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_15/Relu","unknown_65"],"attr":{"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_17/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_16/depthwise","unknown_67","unknown_68"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_16/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_15/Relu","StatefulPartitionedCall/functional_1/conv2d_17/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_16/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_16/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_17/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_16/Relu","unknown_69"],"attr":{"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_18/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_17/depthwise","unknown_71","unknown_72"],"device":"/device:CPU:0","attr":{"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="}}}, {"name":"StatefulPartitionedCall/functional_1/add_17/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_16/Relu","StatefulPartitionedCall/functional_1/conv2d_18/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_17/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_17/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_18/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_17/Relu","unknown_73"],"attr":{"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_19/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_18/depthwise","unknown_75","unknown_76"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_18/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_17/Relu","StatefulPartitionedCall/functional_1/conv2d_19/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_18/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_18/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_19/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_18/Relu","unknown_77"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_20/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_19/depthwise","unknown_79","unknown_80"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_19/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_18/Relu","StatefulPartitionedCall/functional_1/conv2d_20/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_19/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_19/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_20/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_19/Relu","unknown_81"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_21/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_20/depthwise","unknown_83","unknown_84"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_20/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_19/Relu","StatefulPartitionedCall/functional_1/conv2d_21/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_20/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_20/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_21/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_20/Relu","unknown_85"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_22/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_21/depthwise","unknown_87","unknown_88"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_21/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_20/Relu","StatefulPartitionedCall/functional_1/conv2d_22/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_21/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_21/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_22/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_21/Relu","unknown_89"],"attr":{"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_23/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_22/depthwise","unknown_91","unknown_92"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_22/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_21/Relu","StatefulPartitionedCall/functional_1/conv2d_23/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_22/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_22/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_23/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_22/Relu","unknown_93"],"attr":{"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","2","2","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/functional_1/max_pooling2d_2/MaxPool","op":"MaxPool","input":["StatefulPartitionedCall/functional_1/re_lu_22/Relu"],"attr":{"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","2","2","1"]}},"ksize":{"list":{"i":["1","2","2","1"]}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_24/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_23/depthwise","unknown_95","unknown_96"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/tf_op_layer_Pad_1/Pad_1","op":"Pad","input":["StatefulPartitionedCall/functional_1/max_pooling2d_2/MaxPool","StatefulPartitionedCall/functional_1/tf_op_layer_Pad_1/Pad_1/paddings"],"attr":{"Tpaddings":{"type":"DT_INT32"},"_cloned":{"b":true},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/add_23/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/conv2d_24/BiasAdd","StatefulPartitionedCall/functional_1/tf_op_layer_Pad_1/Pad_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_23/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_23/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_24/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_23/Relu","unknown_97"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_25/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_24/depthwise","unknown_99","unknown_100"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_24/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_23/Relu","StatefulPartitionedCall/functional_1/conv2d_25/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_24/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_24/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_25/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_24/Relu","unknown_101"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_26/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_25/depthwise","unknown_103","unknown_104"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_25/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_24/Relu","StatefulPartitionedCall/functional_1/conv2d_26/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_25/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_25/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_26/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_25/Relu","unknown_105"],"attr":{"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_27/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_26/depthwise","unknown_107","unknown_108"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"}}}, {"name":"StatefulPartitionedCall/functional_1/add_26/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_25/Relu","StatefulPartitionedCall/functional_1/conv2d_27/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_26/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_26/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_27/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_26/Relu","unknown_109"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_28/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_27/depthwise","unknown_111","unknown_112"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/functional_1/add_27/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_26/Relu","StatefulPartitionedCall/functional_1/conv2d_28/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_27/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_27/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_28/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_27/Relu","unknown_113"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_29/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_28/depthwise","unknown_115","unknown_116"],"device":"/device:CPU:0","attr":{"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="}}}, {"name":"StatefulPartitionedCall/functional_1/add_28/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_27/Relu","StatefulPartitionedCall/functional_1/conv2d_29/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_28/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_28/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_29/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_28/Relu","unknown_117"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_30/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_29/depthwise","unknown_119","unknown_120"],"device":"/device:CPU:0","attr":{"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="}}}, {"name":"StatefulPartitionedCall/functional_1/add_29/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_28/Relu","StatefulPartitionedCall/functional_1/conv2d_30/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_29/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_29/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_30/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_29/Relu","unknown_121"],"attr":{"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_31/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_30/depthwise","unknown_123","unknown_124"],"device":"/device:CPU:0","attr":{"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="}}}, {"name":"StatefulPartitionedCall/functional_1/add_30/add","op":"AddV2","input":["StatefulPartitionedCall/functional_1/re_lu_29/Relu","StatefulPartitionedCall/functional_1/conv2d_31/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_30/Relu","op":"Relu","input":["StatefulPartitionedCall/functional_1/add_30/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_33/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/re_lu_30/Relu","unknown_135","unknown_136"],"device":"/device:CPU:0","attr":{"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"U0FNRQ=="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_35/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/re_lu_30/Relu","unknown_131","unknown_132"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"padding":{"s":"U0FNRQ=="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"}}}, {"name":"StatefulPartitionedCall/functional_1/depthwise_conv2d_31/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/functional_1/re_lu_30/Relu","unknown_125"],"attr":{"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","2","2","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/functional_1/tf_op_layer_classificators_1/classificators_1","op":"Reshape","input":["StatefulPartitionedCall/functional_1/conv2d_33/BiasAdd","StatefulPartitionedCall/functional_1/tf_op_layer_classificators_1/classificators_1/shape"],"attr":{"T":{"type":"DT_FLOAT"},"Tshape":{"type":"DT_INT32"},"_cloned":{"b":true}}}, {"name":"StatefulPartitionedCall/functional_1/tf_op_layer_regressors_1/regressors_1","op":"Reshape","input":["StatefulPartitionedCall/functional_1/conv2d_35/BiasAdd","StatefulPartitionedCall/functional_1/tf_op_layer_regressors_1/regressors_1/shape"],"attr":{"T":{"type":"DT_FLOAT"},"Tshape":{"type":"DT_INT32"},"_cloned":{"b":true}}}, {"name":"StatefulPartitionedCall/functional_1/re_lu_31/Relu","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/depthwise_conv2d_31/depthwise","unknown_127","unknown_128"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA==","UmVsdQ=="]}}}}, {"name":"Identity","op":"Identity","input":["StatefulPartitionedCall/functional_1/tf_op_layer_classificators_1/classificators_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"Identity_2","op":"Identity","input":["StatefulPartitionedCall/functional_1/tf_op_layer_regressors_1/regressors_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_36/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/re_lu_31/Relu","unknown_129","unknown_130"],"device":"/device:CPU:0","attr":{"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/functional_1/conv2d_34/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/functional_1/re_lu_31/Relu","unknown_133","unknown_134"],"device":"/device:CPU:0","attr":{"num_args":{"i":"1"},"epsilon":{"f":0},"padding":{"s":"U0FNRQ=="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/functional_1/tf_op_layer_regressors_2/regressors_2","op":"Reshape","input":["StatefulPartitionedCall/functional_1/conv2d_36/BiasAdd","StatefulPartitionedCall/functional_1/tf_op_layer_regressors_2/regressors_2/shape"],"attr":{"T":{"type":"DT_FLOAT"},"Tshape":{"type":"DT_INT32"},"_cloned":{"b":true}}}, {"name":"StatefulPartitionedCall/functional_1/tf_op_layer_classificators_2/classificators_2","op":"Reshape","input":["StatefulPartitionedCall/functional_1/conv2d_34/BiasAdd","StatefulPartitionedCall/functional_1/tf_op_layer_classificators_2/classificators_2/shape"],"attr":{"_cloned":{"b":true},"T":{"type":"DT_FLOAT"},"Tshape":{"type":"DT_INT32"}}}, {"name":"Identity_3","op":"Identity","input":["StatefulPartitionedCall/functional_1/tf_op_layer_regressors_2/regressors_2"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"Identity_1","op":"Identity","input":["StatefulPartitionedCall/functional_1/tf_op_layer_classificators_2/classificators_2"],"attr":{"T":{"type":"DT_FLOAT"}}} ], "library": {}, "versions": {} }, "weightsManifest": [ { "paths": ["blazeface.bin"], "weights": [{"name":"unknown_135","shape":[1,1,96,2],"dtype":"float32"},{"name":"unknown_136","shape":[2],"dtype":"float32"},{"name":"StatefulPartitionedCall/functional_1/tf_op_layer_classificators_1/classificators_1/shape","shape":[3],"dtype":"int32"},{"name":"unknown_133","shape":[1,1,96,6],"dtype":"float32"},{"name":"unknown_134","shape":[6],"dtype":"float32"},{"name":"StatefulPartitionedCall/functional_1/tf_op_layer_classificators_2/classificators_2/shape","shape":[3],"dtype":"int32"},{"name":"unknown_131","shape":[1,1,96,32],"dtype":"float32"},{"name":"unknown_132","shape":[32],"dtype":"float32"},{"name":"StatefulPartitionedCall/functional_1/tf_op_layer_regressors_1/regressors_1/shape","shape":[3],"dtype":"int32"},{"name":"unknown_93","shape":[3,3,48,1],"dtype":"float32"},{"name":"unknown_95","shape":[1,1,48,96],"dtype":"float32"},{"name":"unknown_96","shape":[96],"dtype":"float32"},{"name":"unknown_61","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_63","shape":[1,1,24,48],"dtype":"float32"},{"name":"unknown_64","shape":[48],"dtype":"float32"},{"name":"unknown_57","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_59","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_60","shape":[24],"dtype":"float32"},{"name":"unknown_53","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_55","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_56","shape":[24],"dtype":"float32"},{"name":"unknown_49","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_51","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_52","shape":[24],"dtype":"float32"},{"name":"unknown_29","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_31","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_32","shape":[24],"dtype":"float32"},{"name":"unknown","shape":[5,5,3,24],"dtype":"float32"},{"name":"unknown_0","shape":[24],"dtype":"float32"},{"name":"unknown_1","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_3","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_4","shape":[24],"dtype":"float32"},{"name":"unknown_5","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_7","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_8","shape":[24],"dtype":"float32"},{"name":"unknown_9","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_11","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_12","shape":[24],"dtype":"float32"},{"name":"unknown_13","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_15","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_16","shape":[24],"dtype":"float32"},{"name":"unknown_17","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_19","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_20","shape":[24],"dtype":"float32"},{"name":"unknown_21","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_23","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_24","shape":[24],"dtype":"float32"},{"name":"unknown_25","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_27","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_28","shape":[24],"dtype":"float32"},{"name":"unknown_33","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_35","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_36","shape":[24],"dtype":"float32"},{"name":"unknown_37","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_39","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_40","shape":[24],"dtype":"float32"},{"name":"unknown_41","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_43","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_44","shape":[24],"dtype":"float32"},{"name":"unknown_45","shape":[3,3,24,1],"dtype":"float32"},{"name":"unknown_47","shape":[1,1,24,24],"dtype":"float32"},{"name":"unknown_48","shape":[24],"dtype":"float32"},{"name":"StatefulPartitionedCall/functional_1/tf_op_layer_Pad/Pad/paddings","shape":[4,2],"dtype":"int32"},{"name":"unknown_65","shape":[3,3,48,1],"dtype":"float32"},{"name":"unknown_67","shape":[1,1,48,48],"dtype":"float32"},{"name":"unknown_68","shape":[48],"dtype":"float32"},{"name":"unknown_69","shape":[3,3,48,1],"dtype":"float32"},{"name":"unknown_71","shape":[1,1,48,48],"dtype":"float32"},{"name":"unknown_72","shape":[48],"dtype":"float32"},{"name":"unknown_73","shape":[3,3,48,1],"dtype":"float32"},{"name":"unknown_75","shape":[1,1,48,48],"dtype":"float32"},{"name":"unknown_76","shape":[48],"dtype":"float32"},{"name":"unknown_77","shape":[3,3,48,1],"dtype":"float32"},{"name":"unknown_79","shape":[1,1,48,48],"dtype":"float32"},{"name":"unknown_80","shape":[48],"dtype":"float32"},{"name":"unknown_81","shape":[3,3,48,1],"dtype":"float32"},{"name":"unknown_83","shape":[1,1,48,48],"dtype":"float32"},{"name":"unknown_84","shape":[48],"dtype":"float32"},{"name":"unknown_85","shape":[3,3,48,1],"dtype":"float32"},{"name":"unknown_87","shape":[1,1,48,48],"dtype":"float32"},{"name":"unknown_88","shape":[48],"dtype":"float32"},{"name":"unknown_89","shape":[3,3,48,1],"dtype":"float32"},{"name":"unknown_91","shape":[1,1,48,48],"dtype":"float32"},{"name":"unknown_92","shape":[48],"dtype":"float32"},{"name":"StatefulPartitionedCall/functional_1/tf_op_layer_Pad_1/Pad_1/paddings","shape":[4,2],"dtype":"int32"},{"name":"unknown_97","shape":[3,3,96,1],"dtype":"float32"},{"name":"unknown_99","shape":[1,1,96,96],"dtype":"float32"},{"name":"unknown_100","shape":[96],"dtype":"float32"},{"name":"unknown_101","shape":[3,3,96,1],"dtype":"float32"},{"name":"unknown_103","shape":[1,1,96,96],"dtype":"float32"},{"name":"unknown_104","shape":[96],"dtype":"float32"},{"name":"unknown_105","shape":[3,3,96,1],"dtype":"float32"},{"name":"unknown_107","shape":[1,1,96,96],"dtype":"float32"},{"name":"unknown_108","shape":[96],"dtype":"float32"},{"name":"unknown_109","shape":[3,3,96,1],"dtype":"float32"},{"name":"unknown_111","shape":[1,1,96,96],"dtype":"float32"},{"name":"unknown_112","shape":[96],"dtype":"float32"},{"name":"unknown_113","shape":[3,3,96,1],"dtype":"float32"},{"name":"unknown_115","shape":[1,1,96,96],"dtype":"float32"},{"name":"unknown_116","shape":[96],"dtype":"float32"},{"name":"unknown_117","shape":[3,3,96,1],"dtype":"float32"},{"name":"unknown_119","shape":[1,1,96,96],"dtype":"float32"},{"name":"unknown_120","shape":[96],"dtype":"float32"},{"name":"unknown_121","shape":[3,3,96,1],"dtype":"float32"},{"name":"unknown_123","shape":[1,1,96,96],"dtype":"float32"},{"name":"unknown_124","shape":[96],"dtype":"float32"},{"name":"unknown_125","shape":[3,3,96,1],"dtype":"float32"},{"name":"unknown_127","shape":[1,1,96,96],"dtype":"float32"},{"name":"unknown_128","shape":[96],"dtype":"float32"},{"name":"unknown_129","shape":[1,1,96,96],"dtype":"float32"},{"name":"unknown_130","shape":[96],"dtype":"float32"},{"name":"StatefulPartitionedCall/functional_1/tf_op_layer_regressors_2/regressors_2/shape","shape":[3],"dtype":"int32"}] } ] } ================================================ FILE: extern/human/models/emotion.json ================================================ { "format": "graph-model", "generatedBy": "https://github.com/oarriaga/face_classification", "convertedBy": "https://github.com/vladmandic", "userDefinedMetadata": { "signature": { "inputs": { "input_1:0":{"name":"input_1:0","dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"-1"},{"size":"64"},{"size":"64"},{"size":"1"}]}} }, "outputs": { "Identity:0":{"name":"Identity:0","dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"-1"},{"size":"7"}]}} } } }, "modelTopology": { "node": [ {"name":"unknown_26","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_32","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"256"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"unknown_9","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"64"},{"size":"1"}]}}}}}, {"name":"unknown_15","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}}}}, {"name":"unknown_43","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"256"},{"size":"7"}]}}}}}, {"name":"unknown_44","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"7"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/global_average_pooling2d_1/Mean/reduction_indices","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"2"}]}}},"dtype":{"type":"DT_INT32"}}}, {"name":"input_1","op":"Placeholder","attr":{"shape":{"shape":{"dim":[{"size":"-1"},{"size":"64"},{"size":"64"},{"size":"1"}]}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_1/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"1"},{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_1/Conv2D_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_2/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"32"},{"size":"64"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/separable_conv2d_4/separable_conv2d_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"256"},{"size":"256"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_2/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"64"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_3/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"64"},{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/separable_conv2d_4/separable_conv2d_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"256"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_3/Conv2D_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/separable_conv2d_1/separable_conv2d_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"64"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/separable_conv2d_1/separable_conv2d_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/separable_conv2d_2/separable_conv2d_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/separable_conv2d_2/separable_conv2d_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_4/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"256"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_4/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"256"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/separable_conv2d_3/separable_conv2d_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"256"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/separable_conv2d_3/separable_conv2d_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"256"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/block1_conv1_act/Relu","op":"_FusedConv2D","input":["input_1","StatefulPartitionedCall/model_1/conv2d_1/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_1/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"fused_ops":{"list":{"s":["Qmlhc0FkZA==","UmVsdQ=="]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"padding":{"s":"VkFMSUQ="},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","2","2","1"]}},"explicit_paddings":{"list":{}},"epsilon":{"f":0}}}, {"name":"StatefulPartitionedCall/model_1/block1_conv2_act/Relu","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/block1_conv1_act/Relu","StatefulPartitionedCall/model_1/conv2d_2/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_2/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA==","UmVsdQ=="]}},"strides":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"num_args":{"i":"1"},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"data_format":{"s":"TkhXQw=="}}}, {"name":"StatefulPartitionedCall/model_1/separable_conv2d_1/separable_conv2d/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/block1_conv2_act/Relu","unknown_9"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_1/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/block1_conv2_act/Relu","StatefulPartitionedCall/model_1/conv2d_3/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_3/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"explicit_paddings":{"list":{}},"dilations":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"epsilon":{"f":0},"data_format":{"s":"TkhXQw=="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"strides":{"list":{"i":["1","2","2","1"]}},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/block2_sepconv2_act/Relu","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/separable_conv2d_1/separable_conv2d/depthwise","StatefulPartitionedCall/model_1/separable_conv2d_1/separable_conv2d_weights","StatefulPartitionedCall/model_1/separable_conv2d_1/separable_conv2d_bn_offset"],"device":"/device:CPU:0","attr":{"padding":{"s":"VkFMSUQ="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"explicit_paddings":{"list":{}},"fused_ops":{"list":{"s":["Qmlhc0FkZA==","UmVsdQ=="]}},"epsilon":{"f":0},"data_format":{"s":"TkhXQw=="}}}, {"name":"StatefulPartitionedCall/model_1/separable_conv2d_2/separable_conv2d/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/block2_sepconv2_act/Relu","unknown_15"],"attr":{"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"data_format":{"s":"TkhXQw=="}}}, {"name":"StatefulPartitionedCall/model_1/block2_sepconv2_bn/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/separable_conv2d_2/separable_conv2d/depthwise","StatefulPartitionedCall/model_1/separable_conv2d_2/separable_conv2d_weights","StatefulPartitionedCall/model_1/separable_conv2d_2/separable_conv2d_bn_offset"],"device":"/device:CPU:0","attr":{"data_format":{"s":"TkhXQw=="},"padding":{"s":"VkFMSUQ="},"explicit_paddings":{"list":{}},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"T":{"type":"DT_FLOAT"},"epsilon":{"f":0},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"strides":{"list":{"i":["1","1","1","1"]}},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/max_pooling2d_1/MaxPool","op":"MaxPool","input":["StatefulPartitionedCall/model_1/block2_sepconv2_bn/FusedBatchNormV3"],"attr":{"strides":{"list":{"i":["1","2","2","1"]}},"data_format":{"s":"TkhXQw=="},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"},"ksize":{"list":{"i":["1","3","3","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/add_1/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/max_pooling2d_1/MaxPool","StatefulPartitionedCall/model_1/batch_normalization_1/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/block3_sepconv1_act/Relu","op":"Relu","input":["StatefulPartitionedCall/model_1/add_1/add"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_2/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/add_1/add","StatefulPartitionedCall/model_1/conv2d_4/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_4/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"data_format":{"s":"TkhXQw=="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"T":{"type":"DT_FLOAT"},"num_args":{"i":"1"},"strides":{"list":{"i":["1","2","2","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/model_1/separable_conv2d_3/separable_conv2d/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/block3_sepconv1_act/Relu","unknown_26"],"attr":{"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/block3_sepconv2_act/Relu","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/separable_conv2d_3/separable_conv2d/depthwise","StatefulPartitionedCall/model_1/separable_conv2d_3/separable_conv2d_weights","StatefulPartitionedCall/model_1/separable_conv2d_3/separable_conv2d_bn_offset"],"device":"/device:CPU:0","attr":{"data_format":{"s":"TkhXQw=="},"fused_ops":{"list":{"s":["Qmlhc0FkZA==","UmVsdQ=="]}},"T":{"type":"DT_FLOAT"},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"VkFMSUQ="},"strides":{"list":{"i":["1","1","1","1"]}},"epsilon":{"f":0}}}, {"name":"StatefulPartitionedCall/model_1/separable_conv2d_4/separable_conv2d/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/block3_sepconv2_act/Relu","unknown_32"],"attr":{"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"strides":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="}}}, {"name":"StatefulPartitionedCall/model_1/block3_sepconv2_bn/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/separable_conv2d_4/separable_conv2d/depthwise","StatefulPartitionedCall/model_1/separable_conv2d_4/separable_conv2d_weights","StatefulPartitionedCall/model_1/separable_conv2d_4/separable_conv2d_bn_offset"],"device":"/device:CPU:0","attr":{"num_args":{"i":"1"},"strides":{"list":{"i":["1","1","1","1"]}},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"data_format":{"s":"TkhXQw=="},"epsilon":{"f":0},"explicit_paddings":{"list":{}},"padding":{"s":"VkFMSUQ="},"use_cudnn_on_gpu":{"b":true},"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/max_pooling2d_2/MaxPool","op":"MaxPool","input":["StatefulPartitionedCall/model_1/block3_sepconv2_bn/FusedBatchNormV3"],"attr":{"strides":{"list":{"i":["1","2","2","1"]}},"ksize":{"list":{"i":["1","3","3","1"]}},"padding":{"s":"U0FNRQ=="},"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/add_2/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/max_pooling2d_2/MaxPool","StatefulPartitionedCall/model_1/batch_normalization_2/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_5/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/add_2/add","unknown_43","unknown_44"],"device":"/device:CPU:0","attr":{"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"epsilon":{"f":0},"padding":{"s":"U0FNRQ=="},"num_args":{"i":"1"},"dilations":{"list":{"i":["1","1","1","1"]}},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"strides":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="}}}, {"name":"StatefulPartitionedCall/model_1/global_average_pooling2d_1/Mean","op":"Mean","input":["StatefulPartitionedCall/model_1/conv2d_5/BiasAdd","StatefulPartitionedCall/model_1/global_average_pooling2d_1/Mean/reduction_indices"],"attr":{"Tidx":{"type":"DT_INT32"},"T":{"type":"DT_FLOAT"},"keep_dims":{"b":false}}}, {"name":"StatefulPartitionedCall/model_1/predictions/Softmax","op":"Softmax","input":["StatefulPartitionedCall/model_1/global_average_pooling2d_1/Mean"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"Identity","op":"Identity","input":["StatefulPartitionedCall/model_1/predictions/Softmax"],"attr":{"T":{"type":"DT_FLOAT"}}} ], "library": {}, "versions": {} }, "weightsManifest": [ { "paths": ["emotion.bin"], "weights": [{"name":"unknown_26","shape":[3,3,128,1],"dtype":"float32"},{"name":"unknown_32","shape":[3,3,256,1],"dtype":"float32"},{"name":"unknown_9","shape":[3,3,64,1],"dtype":"float32"},{"name":"unknown_15","shape":[3,3,128,1],"dtype":"float32"},{"name":"unknown_43","shape":[3,3,256,7],"dtype":"float32"},{"name":"unknown_44","shape":[7],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/global_average_pooling2d_1/Mean/reduction_indices","shape":[2],"dtype":"int32"},{"name":"StatefulPartitionedCall/model_1/conv2d_1/Conv2D_weights","shape":[3,3,1,32],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/conv2d_1/Conv2D_bn_offset","shape":[32],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/conv2d_2/Conv2D_weights","shape":[3,3,32,64],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/separable_conv2d_4/separable_conv2d_weights","shape":[1,1,256,256],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/conv2d_2/Conv2D_bn_offset","shape":[64],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/conv2d_3/Conv2D_weights","shape":[1,1,64,128],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/separable_conv2d_4/separable_conv2d_bn_offset","shape":[256],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/conv2d_3/Conv2D_bn_offset","shape":[128],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/separable_conv2d_1/separable_conv2d_weights","shape":[1,1,64,128],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/separable_conv2d_1/separable_conv2d_bn_offset","shape":[128],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/separable_conv2d_2/separable_conv2d_weights","shape":[1,1,128,128],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/separable_conv2d_2/separable_conv2d_bn_offset","shape":[128],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/conv2d_4/Conv2D_weights","shape":[1,1,128,256],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/conv2d_4/Conv2D_bn_offset","shape":[256],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/separable_conv2d_3/separable_conv2d_weights","shape":[1,1,128,256],"dtype":"float32"},{"name":"StatefulPartitionedCall/model_1/separable_conv2d_3/separable_conv2d_bn_offset","shape":[256],"dtype":"float32"}] } ] } ================================================ FILE: extern/human/models/facemesh.json ================================================ { "format": "graph-model", "generatedBy": "https://github.com/google/mediapipe", "convertedBy": "https://github.com/vladmandic", "signature": { "inputs": { "input_1": {"name":"input_1:0","dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"-1"},{"size":"192"},{"size":"192"},{"size":"3"}]}} }, "outputs": { "output_mesh": {"name":"Identity_2:0","dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"-1"},{"size":"1404"}]}}, "output_faceflag": {"name":"Identity_1:0","dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"-1"},{"size":"1"}]}}, "output_contours": {"name":"Identity:0","dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"-1"},{"size":"266"}]}} } }, "modelTopology": { "node": [ {"name":"StatefulPartitionedCall/model_1/p_re_lu_25/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_24/Neg","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_23/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_22/Neg","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_21/Neg","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_19/depthwise/ReadVariableOp","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_20/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_21/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_22/depthwise/ReadVariableOp","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"32"},{"size":"1"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_27/Conv2D/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"32"},{"size":"266"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_27/BiasAdd/ReadVariableOp","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"266"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/output_contours/Const","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"2"}]}}},"dtype":{"type":"DT_INT32"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_28/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_27/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_26/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_23/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_24/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"32"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_31/Conv2D/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"32"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_31/BiasAdd/ReadVariableOp","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/output_faceflag/Const","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"2"}]}}},"dtype":{"type":"DT_INT32"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_20/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_19/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_18/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_17/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_16/Neg","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_15/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_14/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_13/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_12/Neg","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_11/Neg","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_10/Neg","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/channel_padding_3/Pad/paddings","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"4"},{"size":"2"}]}}},"dtype":{"type":"DT_INT32"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_9/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"64"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_8/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"64"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_7/Neg","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"64"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/channel_padding_2/Pad/paddings","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"4"},{"size":"2"}]}}},"dtype":{"type":"DT_INT32"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_6/Neg","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_5/Neg","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_4/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/channel_padding_1/Pad/paddings","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"4"},{"size":"2"}]}}},"dtype":{"type":"DT_INT32"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_3/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"16"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_2/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"16"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_1/Neg","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"16"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_1/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"16"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_2/depthwise/ReadVariableOp","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"16"},{"size":"1"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_3/depthwise/ReadVariableOp","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"16"},{"size":"1"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_4/depthwise/ReadVariableOp","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"32"},{"size":"1"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_5/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"32"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_6/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"32"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_7/depthwise/ReadVariableOp","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"64"},{"size":"1"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_8/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"64"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_9/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"64"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_10/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_11/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_12/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_13/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_14/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_15/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_16/depthwise/ReadVariableOp","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_17/depthwise/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_18/depthwise/ReadVariableOp","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"32"},{"size":"1"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_21/Conv2D/ReadVariableOp","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"32"},{"size":"1404"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_21/BiasAdd/ReadVariableOp","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1404"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/output_mesh/Const","op":"Const","attr":{"dtype":{"type":"DT_INT32"},"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"2"}]}}}}}, {"name":"input_1","op":"Placeholder","attr":{"dtype":{"type":"DT_FLOAT"},"shape":{"shape":{"dim":[{"size":"-1"},{"size":"192"},{"size":"192"},{"size":"3"}]}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_1/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"3"},{"size":"16"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_1/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"16"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_2/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"16"},{"size":"16"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_2/Conv2D_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"16"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_3/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"16"},{"size":"16"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_3/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"16"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_4/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"16"},{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_26/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"},{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_4/Conv2D_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_5/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"},{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_5/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_6/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"},{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_26/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_6/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_7/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"},{"size":"64"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_7/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"64"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_8/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"64"},{"size":"64"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_8/Conv2D_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"64"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_9/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"64"},{"size":"64"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_9/Conv2D_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"64"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_10/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"64"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_10/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_11/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_11/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_12/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_12/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_13/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_13/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_14/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_14/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_15/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_15/Conv2D_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_22/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_22/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_28/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_28/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_16/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_20/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"},{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_16/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_29/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_29/Conv2D_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_23/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_20/Conv2D_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_23/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_17/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_17/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_30/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"},{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_30/Conv2D_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_24/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_24/Conv2D_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_18/Conv2D_weights","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_18/Conv2D_bn_offset","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_25/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_25/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_19/Conv2D_weights","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_19/Conv2D_bn_offset","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_1/FusedBatchNormV3","op":"_FusedConv2D","input":["input_1","StatefulPartitionedCall/model_1/conv2d_1/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_1/Conv2D_bn_offset","StatefulPartitionedCall/model_1/p_re_lu_1/Neg"],"device":"/device:CPU:0","attr":{"fused_ops":{"list":{"s":["Qmlhc0FkZA==","UHJlbHU="]}},"dilations":{"list":{"i":["1","1","1","1"]}},"epsilon":{"f":0},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","2","2","1"]}},"T":{"type":"DT_FLOAT"},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"2"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_1/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/batch_normalization_1/FusedBatchNormV3","StatefulPartitionedCall/model_1/depthwise_conv2d_1/depthwise/ReadVariableOp"],"attr":{"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_2/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_1/depthwise","StatefulPartitionedCall/model_1/conv2d_2/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_2/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"strides":{"list":{"i":["1","1","1","1"]}},"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"num_args":{"i":"1"},"T":{"type":"DT_FLOAT"},"use_cudnn_on_gpu":{"b":true},"epsilon":{"f":0},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"explicit_paddings":{"list":{}},"padding":{"s":"VkFMSUQ="}}}, {"name":"StatefulPartitionedCall/model_1/add_1/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/batch_normalization_1/FusedBatchNormV3","StatefulPartitionedCall/model_1/batch_normalization_2/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_2/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_1/add","StatefulPartitionedCall/model_1/p_re_lu_2/Neg"]}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_2/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_2/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_2/depthwise/ReadVariableOp"],"attr":{"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_3/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_2/depthwise","StatefulPartitionedCall/model_1/conv2d_3/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_3/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"epsilon":{"f":0},"num_args":{"i":"1"},"data_format":{"s":"TkhXQw=="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"T":{"type":"DT_FLOAT"},"padding":{"s":"VkFMSUQ="},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/add_2/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_2/Relu","StatefulPartitionedCall/model_1/batch_normalization_3/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_3/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_2/add","StatefulPartitionedCall/model_1/p_re_lu_3/Neg"]}, {"name":"StatefulPartitionedCall/model_1/max_pooling2d_1/MaxPool","op":"MaxPool","input":["StatefulPartitionedCall/model_1/p_re_lu_3/Relu"],"attr":{"strides":{"list":{"i":["1","2","2","1"]}},"T":{"type":"DT_FLOAT"},"ksize":{"list":{"i":["1","2","2","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"VkFMSUQ="},"data_format":{"s":"TkhXQw=="}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_3/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_3/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_3/depthwise/ReadVariableOp"],"attr":{"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"},"explicit_paddings":{"list":{}},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","2","2","1"]}},"data_format":{"s":"TkhXQw=="}}}, {"name":"StatefulPartitionedCall/model_1/channel_padding_1/Pad","op":"Pad","input":["StatefulPartitionedCall/model_1/max_pooling2d_1/MaxPool","StatefulPartitionedCall/model_1/channel_padding_1/Pad/paddings"],"attr":{"T":{"type":"DT_FLOAT"},"Tpaddings":{"type":"DT_INT32"}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_4/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_3/depthwise","StatefulPartitionedCall/model_1/conv2d_4/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_4/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"num_args":{"i":"1"},"padding":{"s":"VkFMSUQ="},"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"},"use_cudnn_on_gpu":{"b":true},"epsilon":{"f":0},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/add_3/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/channel_padding_1/Pad","StatefulPartitionedCall/model_1/batch_normalization_4/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_4/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_3/add","StatefulPartitionedCall/model_1/p_re_lu_4/Neg"]}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_4/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_4/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_4/depthwise/ReadVariableOp"],"attr":{"strides":{"list":{"i":["1","1","1","1"]}},"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_5/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_4/depthwise","StatefulPartitionedCall/model_1/conv2d_5/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_5/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"num_args":{"i":"1"},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"use_cudnn_on_gpu":{"b":true}}}, {"name":"StatefulPartitionedCall/model_1/add_4/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_4/Relu","StatefulPartitionedCall/model_1/batch_normalization_5/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_5/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_4/add","StatefulPartitionedCall/model_1/p_re_lu_5/Neg"]}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_5/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_5/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_5/depthwise/ReadVariableOp"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_6/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_5/depthwise","StatefulPartitionedCall/model_1/conv2d_6/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_6/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"use_cudnn_on_gpu":{"b":true},"padding":{"s":"VkFMSUQ="},"num_args":{"i":"1"},"epsilon":{"f":0},"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/model_1/add_5/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_5/Relu","StatefulPartitionedCall/model_1/batch_normalization_6/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_6/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_5/add","StatefulPartitionedCall/model_1/p_re_lu_6/Neg"]}, {"name":"StatefulPartitionedCall/model_1/max_pooling2d_2/MaxPool","op":"MaxPool","input":["StatefulPartitionedCall/model_1/p_re_lu_6/Relu"],"attr":{"padding":{"s":"VkFMSUQ="},"ksize":{"list":{"i":["1","2","2","1"]}},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","2","2","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_6/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_6/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_6/depthwise/ReadVariableOp"],"attr":{"padding":{"s":"U0FNRQ=="},"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","2","2","1"]}},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/channel_padding_2/Pad","op":"Pad","input":["StatefulPartitionedCall/model_1/max_pooling2d_2/MaxPool","StatefulPartitionedCall/model_1/channel_padding_2/Pad/paddings"],"attr":{"T":{"type":"DT_FLOAT"},"Tpaddings":{"type":"DT_INT32"}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_7/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_6/depthwise","StatefulPartitionedCall/model_1/conv2d_7/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_7/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"VkFMSUQ="},"epsilon":{"f":0},"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/add_6/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/channel_padding_2/Pad","StatefulPartitionedCall/model_1/batch_normalization_7/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_7/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_6/add","StatefulPartitionedCall/model_1/p_re_lu_7/Neg"]}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_7/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_7/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_7/depthwise/ReadVariableOp"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_8/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_7/depthwise","StatefulPartitionedCall/model_1/conv2d_8/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_8/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"padding":{"s":"VkFMSUQ="},"num_args":{"i":"1"},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true},"strides":{"list":{"i":["1","1","1","1"]}},"epsilon":{"f":0},"explicit_paddings":{"list":{}},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/add_7/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_7/Relu","StatefulPartitionedCall/model_1/batch_normalization_8/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_8/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_7/add","StatefulPartitionedCall/model_1/p_re_lu_8/Neg"]}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_8/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_8/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_8/depthwise/ReadVariableOp"],"attr":{"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_9/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_8/depthwise","StatefulPartitionedCall/model_1/conv2d_9/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_9/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"epsilon":{"f":0},"explicit_paddings":{"list":{}},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"num_args":{"i":"1"},"use_cudnn_on_gpu":{"b":true},"padding":{"s":"VkFMSUQ="},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/add_8/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_8/Relu","StatefulPartitionedCall/model_1/batch_normalization_9/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_9/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_8/add","StatefulPartitionedCall/model_1/p_re_lu_9/Neg"]}, {"name":"StatefulPartitionedCall/model_1/max_pooling2d_3/MaxPool","op":"MaxPool","input":["StatefulPartitionedCall/model_1/p_re_lu_9/Relu"],"attr":{"ksize":{"list":{"i":["1","2","2","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"VkFMSUQ="},"strides":{"list":{"i":["1","2","2","1"]}},"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_9/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_9/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_9/depthwise/ReadVariableOp"],"attr":{"strides":{"list":{"i":["1","2","2","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/channel_padding_3/Pad","op":"Pad","input":["StatefulPartitionedCall/model_1/max_pooling2d_3/MaxPool","StatefulPartitionedCall/model_1/channel_padding_3/Pad/paddings"],"attr":{"Tpaddings":{"type":"DT_INT32"},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_10/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_9/depthwise","StatefulPartitionedCall/model_1/conv2d_10/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_10/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"strides":{"list":{"i":["1","1","1","1"]}},"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"num_args":{"i":"1"},"use_cudnn_on_gpu":{"b":true},"padding":{"s":"VkFMSUQ="},"epsilon":{"f":0}}}, {"name":"StatefulPartitionedCall/model_1/add_9/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/channel_padding_3/Pad","StatefulPartitionedCall/model_1/batch_normalization_10/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_10/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_9/add","StatefulPartitionedCall/model_1/p_re_lu_10/Neg"]}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_10/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_10/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_10/depthwise/ReadVariableOp"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_11/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_10/depthwise","StatefulPartitionedCall/model_1/conv2d_11/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_11/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"use_cudnn_on_gpu":{"b":true},"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"num_args":{"i":"1"},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/model_1/add_10/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_10/Relu","StatefulPartitionedCall/model_1/batch_normalization_11/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_11/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_10/add","StatefulPartitionedCall/model_1/p_re_lu_11/Neg"]}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_11/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_11/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_11/depthwise/ReadVariableOp"],"attr":{"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","1","1","1"]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_12/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_11/depthwise","StatefulPartitionedCall/model_1/conv2d_12/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_12/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"data_format":{"s":"TkhXQw=="},"padding":{"s":"VkFMSUQ="},"use_cudnn_on_gpu":{"b":true},"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"num_args":{"i":"1"},"T":{"type":"DT_FLOAT"},"epsilon":{"f":0},"strides":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/add_11/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_11/Relu","StatefulPartitionedCall/model_1/batch_normalization_12/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_12/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_11/add","StatefulPartitionedCall/model_1/p_re_lu_12/Neg"]}, {"name":"StatefulPartitionedCall/model_1/max_pooling2d_4/MaxPool","op":"MaxPool","input":["StatefulPartitionedCall/model_1/p_re_lu_12/Relu"],"attr":{"data_format":{"s":"TkhXQw=="},"ksize":{"list":{"i":["1","2","2","1"]}},"padding":{"s":"VkFMSUQ="},"T":{"type":"DT_FLOAT"},"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","2","2","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_12/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_12/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_12/depthwise/ReadVariableOp"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","2","2","1"]}},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_13/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_12/depthwise","StatefulPartitionedCall/model_1/conv2d_13/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_13/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"num_args":{"i":"1"},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="}}}, {"name":"StatefulPartitionedCall/model_1/add_12/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/max_pooling2d_4/MaxPool","StatefulPartitionedCall/model_1/batch_normalization_13/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_13/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_12/add","StatefulPartitionedCall/model_1/p_re_lu_13/Neg"]}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_13/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_13/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_13/depthwise/ReadVariableOp"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_14/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_13/depthwise","StatefulPartitionedCall/model_1/conv2d_14/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_14/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"VkFMSUQ="},"num_args":{"i":"1"},"strides":{"list":{"i":["1","1","1","1"]}},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"epsilon":{"f":0}}}, {"name":"StatefulPartitionedCall/model_1/add_13/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_13/Relu","StatefulPartitionedCall/model_1/batch_normalization_14/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_14/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_13/add","StatefulPartitionedCall/model_1/p_re_lu_14/Neg"]}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_14/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_14/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_14/depthwise/ReadVariableOp"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"},"padding":{"s":"U0FNRQ=="},"data_format":{"s":"TkhXQw=="}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_15/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_14/depthwise","StatefulPartitionedCall/model_1/conv2d_15/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_15/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"use_cudnn_on_gpu":{"b":true},"padding":{"s":"VkFMSUQ="},"num_args":{"i":"1"},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="},"epsilon":{"f":0},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"strides":{"list":{"i":["1","1","1","1"]}},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/add_14/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_14/Relu","StatefulPartitionedCall/model_1/batch_normalization_15/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_15/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_14/add","StatefulPartitionedCall/model_1/p_re_lu_15/Neg"]}, {"name":"StatefulPartitionedCall/model_1/max_pooling2d_6/MaxPool","op":"MaxPool","input":["StatefulPartitionedCall/model_1/p_re_lu_15/Relu"],"attr":{"strides":{"list":{"i":["1","2","2","1"]}},"data_format":{"s":"TkhXQw=="},"padding":{"s":"VkFMSUQ="},"ksize":{"list":{"i":["1","2","2","1"]}},"T":{"type":"DT_FLOAT"},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_19/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_15/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_19/depthwise/ReadVariableOp"],"attr":{"T":{"type":"DT_FLOAT"},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","2","2","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/max_pooling2d_7/MaxPool","op":"MaxPool","input":["StatefulPartitionedCall/model_1/p_re_lu_15/Relu"],"attr":{"ksize":{"list":{"i":["1","2","2","1"]}},"padding":{"s":"VkFMSUQ="},"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","2","2","1"]}},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_23/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_15/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_23/depthwise/ReadVariableOp"],"attr":{"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","2","2","1"]}},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/model_1/max_pooling2d_5/MaxPool","op":"MaxPool","input":["StatefulPartitionedCall/model_1/p_re_lu_15/Relu"],"attr":{"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","2","2","1"]}},"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"},"padding":{"s":"VkFMSUQ="},"ksize":{"list":{"i":["1","2","2","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_15/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_15/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_15/depthwise/ReadVariableOp"],"attr":{"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"},"padding":{"s":"U0FNRQ=="},"strides":{"list":{"i":["1","2","2","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_21/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_19/depthwise","StatefulPartitionedCall/model_1/conv2d_22/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_22/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"num_args":{"i":"1"},"padding":{"s":"VkFMSUQ="},"epsilon":{"f":0},"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_26/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_23/depthwise","StatefulPartitionedCall/model_1/conv2d_28/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_28/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}},"num_args":{"i":"1"},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"padding":{"s":"VkFMSUQ="},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_16/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_15/depthwise","StatefulPartitionedCall/model_1/conv2d_16/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_16/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"padding":{"s":"VkFMSUQ="},"T":{"type":"DT_FLOAT"},"num_args":{"i":"1"},"use_cudnn_on_gpu":{"b":true},"epsilon":{"f":0},"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/model_1/add_19/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/max_pooling2d_6/MaxPool","StatefulPartitionedCall/model_1/batch_normalization_21/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/add_23/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/max_pooling2d_7/MaxPool","StatefulPartitionedCall/model_1/batch_normalization_26/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/add_15/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/max_pooling2d_5/MaxPool","StatefulPartitionedCall/model_1/batch_normalization_16/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_21/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_19/add","StatefulPartitionedCall/model_1/p_re_lu_21/Neg"]}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_26/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_23/add","StatefulPartitionedCall/model_1/p_re_lu_26/Neg"]}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_16/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_15/add","StatefulPartitionedCall/model_1/p_re_lu_16/Neg"]}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_20/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_21/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_20/depthwise/ReadVariableOp"],"attr":{"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_27/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/p_re_lu_26/Relu","StatefulPartitionedCall/model_1/conv2d_29/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_29/Conv2D_bn_offset","StatefulPartitionedCall/model_1/p_re_lu_27/Neg"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"num_args":{"i":"2"},"T":{"type":"DT_FLOAT"},"fused_ops":{"list":{"s":["Qmlhc0FkZA==","UHJlbHU="]}},"padding":{"s":"VkFMSUQ="},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_16/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_16/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_16/depthwise/ReadVariableOp"],"attr":{"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_22/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_20/depthwise","StatefulPartitionedCall/model_1/conv2d_23/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_23/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}},"num_args":{"i":"1"},"T":{"type":"DT_FLOAT"},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_17/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_16/depthwise","StatefulPartitionedCall/model_1/conv2d_17/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_17/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"epsilon":{"f":0},"num_args":{"i":"1"},"explicit_paddings":{"list":{}},"padding":{"s":"VkFMSUQ="},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/add_20/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_21/Relu","StatefulPartitionedCall/model_1/batch_normalization_22/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/add_16/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_16/Relu","StatefulPartitionedCall/model_1/batch_normalization_17/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_22/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_20/add","StatefulPartitionedCall/model_1/p_re_lu_22/Neg"]}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_17/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_16/add","StatefulPartitionedCall/model_1/p_re_lu_17/Neg"]}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_24/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/batch_normalization_27/FusedBatchNormV3","StatefulPartitionedCall/model_1/depthwise_conv2d_24/depthwise/ReadVariableOp"],"attr":{"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"},"padding":{"s":"U0FNRQ=="},"strides":{"list":{"i":["1","1","1","1"]}},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_28/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_24/depthwise","StatefulPartitionedCall/model_1/conv2d_30/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_30/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"num_args":{"i":"1"},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"epsilon":{"f":0},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"},"explicit_paddings":{"list":{}},"padding":{"s":"VkFMSUQ="},"dilations":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_21/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_22/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_21/depthwise/ReadVariableOp"],"attr":{"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/add_24/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/batch_normalization_27/FusedBatchNormV3","StatefulPartitionedCall/model_1/batch_normalization_28/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_17/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/p_re_lu_17/Relu","StatefulPartitionedCall/model_1/depthwise_conv2d_17/depthwise/ReadVariableOp"],"attr":{"padding":{"s":"U0FNRQ=="},"strides":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_23/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_21/depthwise","StatefulPartitionedCall/model_1/conv2d_24/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_24/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"num_args":{"i":"1"},"use_cudnn_on_gpu":{"b":true},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"T":{"type":"DT_FLOAT"},"padding":{"s":"VkFMSUQ="},"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","1","1","1"]}},"epsilon":{"f":0}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_28/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_24/add","StatefulPartitionedCall/model_1/p_re_lu_28/Neg"]}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_18/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_17/depthwise","StatefulPartitionedCall/model_1/conv2d_18/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_18/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","1","1","1"]}},"epsilon":{"f":0},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"1"},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"padding":{"s":"VkFMSUQ="}}}, {"name":"StatefulPartitionedCall/model_1/add_21/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_22/Relu","StatefulPartitionedCall/model_1/batch_normalization_23/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/add_17/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/p_re_lu_17/Relu","StatefulPartitionedCall/model_1/batch_normalization_18/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_23/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_21/add","StatefulPartitionedCall/model_1/p_re_lu_23/Neg"]}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_18/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_17/add","StatefulPartitionedCall/model_1/p_re_lu_18/Neg"]}, {"name":"StatefulPartitionedCall/model_1/conv2d_31/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/p_re_lu_28/Relu","StatefulPartitionedCall/model_1/conv2d_31/Conv2D/ReadVariableOp","StatefulPartitionedCall/model_1/conv2d_31/BiasAdd/ReadVariableOp"],"device":"/device:CPU:0","attr":{"strides":{"list":{"i":["1","3","3","1"]}},"padding":{"s":"VkFMSUQ="},"dilations":{"list":{"i":["1","1","1","1"]}},"num_args":{"i":"1"},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"epsilon":{"f":0}}}, {"name":"StatefulPartitionedCall/model_1/activation_1/Sigmoid","op":"Sigmoid","input":["StatefulPartitionedCall/model_1/conv2d_31/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_24/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/p_re_lu_23/Relu","StatefulPartitionedCall/model_1/conv2d_25/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_25/Conv2D_bn_offset","StatefulPartitionedCall/model_1/p_re_lu_24/Neg"],"device":"/device:CPU:0","attr":{"num_args":{"i":"2"},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true},"padding":{"s":"VkFMSUQ="},"T":{"type":"DT_FLOAT"},"fused_ops":{"list":{"s":["Qmlhc0FkZA==","UHJlbHU="]}},"epsilon":{"f":0},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}}}}, {"name":"StatefulPartitionedCall/model_1/output_faceflag/Reshape","op":"Reshape","input":["StatefulPartitionedCall/model_1/activation_1/Sigmoid","StatefulPartitionedCall/model_1/output_faceflag/Const"],"attr":{"Tshape":{"type":"DT_INT32"},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_19/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/p_re_lu_18/Relu","StatefulPartitionedCall/model_1/conv2d_19/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_19/Conv2D_bn_offset","StatefulPartitionedCall/model_1/p_re_lu_19/Neg"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"num_args":{"i":"2"},"epsilon":{"f":0},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"padding":{"s":"VkFMSUQ="},"fused_ops":{"list":{"s":["Qmlhc0FkZA==","UHJlbHU="]}}}}, {"name":"Identity_1","op":"Identity","input":["StatefulPartitionedCall/model_1/output_faceflag/Reshape"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_22/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/batch_normalization_24/FusedBatchNormV3","StatefulPartitionedCall/model_1/depthwise_conv2d_22/depthwise/ReadVariableOp"],"attr":{"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"padding":{"s":"U0FNRQ=="},"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","1","1","1"]}}}}, {"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_18/depthwise","op":"DepthwiseConv2dNative","input":["StatefulPartitionedCall/model_1/batch_normalization_19/FusedBatchNormV3","StatefulPartitionedCall/model_1/depthwise_conv2d_18/depthwise/ReadVariableOp"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_25/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_22/depthwise","StatefulPartitionedCall/model_1/conv2d_26/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_26/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"use_cudnn_on_gpu":{"b":true},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","1","1","1"]}},"num_args":{"i":"1"},"data_format":{"s":"TkhXQw=="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/model_1/batch_normalization_20/FusedBatchNormV3","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/depthwise_conv2d_18/depthwise","StatefulPartitionedCall/model_1/conv2d_20/Conv2D_weights","StatefulPartitionedCall/model_1/conv2d_20/Conv2D_bn_offset"],"device":"/device:CPU:0","attr":{"padding":{"s":"VkFMSUQ="},"data_format":{"s":"TkhXQw=="},"num_args":{"i":"1"},"strides":{"list":{"i":["1","1","1","1"]}},"epsilon":{"f":0},"T":{"type":"DT_FLOAT"},"use_cudnn_on_gpu":{"b":true},"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}}}}, {"name":"StatefulPartitionedCall/model_1/add_22/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/batch_normalization_24/FusedBatchNormV3","StatefulPartitionedCall/model_1/batch_normalization_25/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/add_18/add","op":"AddV2","input":["StatefulPartitionedCall/model_1/batch_normalization_19/FusedBatchNormV3","StatefulPartitionedCall/model_1/batch_normalization_20/FusedBatchNormV3"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_25/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_22/add","StatefulPartitionedCall/model_1/p_re_lu_25/Neg"]}, {"name":"StatefulPartitionedCall/model_1/p_re_lu_20/Relu","op":"Prelu","input":["StatefulPartitionedCall/model_1/add_18/add","StatefulPartitionedCall/model_1/p_re_lu_20/Neg"]}, {"name":"StatefulPartitionedCall/model_1/conv2d_27/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/p_re_lu_25/Relu","StatefulPartitionedCall/model_1/conv2d_27/Conv2D/ReadVariableOp","StatefulPartitionedCall/model_1/conv2d_27/BiasAdd/ReadVariableOp"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"epsilon":{"f":0},"padding":{"s":"VkFMSUQ="},"num_args":{"i":"1"},"use_cudnn_on_gpu":{"b":true},"strides":{"list":{"i":["1","3","3","1"]}},"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/conv2d_21/BiasAdd","op":"_FusedConv2D","input":["StatefulPartitionedCall/model_1/p_re_lu_20/Relu","StatefulPartitionedCall/model_1/conv2d_21/Conv2D/ReadVariableOp","StatefulPartitionedCall/model_1/conv2d_21/BiasAdd/ReadVariableOp"],"device":"/device:CPU:0","attr":{"padding":{"s":"VkFMSUQ="},"strides":{"list":{"i":["1","3","3","1"]}},"explicit_paddings":{"list":{}},"epsilon":{"f":0},"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"num_args":{"i":"1"},"use_cudnn_on_gpu":{"b":true}}}, {"name":"StatefulPartitionedCall/model_1/output_contours/Reshape","op":"Reshape","input":["StatefulPartitionedCall/model_1/conv2d_27/BiasAdd","StatefulPartitionedCall/model_1/output_contours/Const"],"attr":{"Tshape":{"type":"DT_INT32"},"T":{"type":"DT_FLOAT"}}}, {"name":"StatefulPartitionedCall/model_1/output_mesh/Reshape","op":"Reshape","input":["StatefulPartitionedCall/model_1/conv2d_21/BiasAdd","StatefulPartitionedCall/model_1/output_mesh/Const"],"attr":{"T":{"type":"DT_FLOAT"},"Tshape":{"type":"DT_INT32"}}}, {"name":"Identity","op":"Identity","input":["StatefulPartitionedCall/model_1/output_contours/Reshape"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"Identity_2","op":"Identity","input":["StatefulPartitionedCall/model_1/output_mesh/Reshape"],"attr":{"T":{"type":"DT_FLOAT"}}} ], "library": {}, "versions": {} }, "weightsManifest": [ { "paths": ["facemesh.bin"], "weights": [{"name":"StatefulPartitionedCall/model_1/p_re_lu_25/Neg","shape":[1,1,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_24/Neg","shape":[1,1,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_23/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_22/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_21/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_19/depthwise/ReadVariableOp","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_20/depthwise/ReadVariableOp","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_21/depthwise/ReadVariableOp","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_22/depthwise/ReadVariableOp","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_27/Conv2D/ReadVariableOp","shape":[3,3,32,266],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_27/BiasAdd/ReadVariableOp","shape":[266],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/output_contours/Const","shape":[2],"dtype":"int32"},{"name":"StatefulPartitionedCall/model_1/p_re_lu_28/Neg","shape":[1,1,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_27/Neg","shape":[1,1,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_26/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_23/depthwise/ReadVariableOp","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_24/depthwise/ReadVariableOp","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_31/Conv2D/ReadVariableOp","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_31/BiasAdd/ReadVariableOp","shape":[1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/output_faceflag/Const","shape":[2],"dtype":"int32"},{"name":"StatefulPartitionedCall/model_1/p_re_lu_20/Neg","shape":[1,1,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_19/Neg","shape":[1,1,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_18/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_17/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_16/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_15/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_14/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_13/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_12/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_11/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_10/Neg","shape":[1,1,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/channel_padding_3/Pad/paddings","shape":[4,2],"dtype":"int32"},{"name":"StatefulPartitionedCall/model_1/p_re_lu_9/Neg","shape":[1,1,64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_8/Neg","shape":[1,1,64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_7/Neg","shape":[1,1,64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/channel_padding_2/Pad/paddings","shape":[4,2],"dtype":"int32"},{"name":"StatefulPartitionedCall/model_1/p_re_lu_6/Neg","shape":[1,1,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_5/Neg","shape":[1,1,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_4/Neg","shape":[1,1,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/channel_padding_1/Pad/paddings","shape":[4,2],"dtype":"int32"},{"name":"StatefulPartitionedCall/model_1/p_re_lu_3/Neg","shape":[1,1,16],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_2/Neg","shape":[1,1,16],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/p_re_lu_1/Neg","shape":[1,1,16],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_1/depthwise/ReadVariableOp","shape":[3,3,16,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_2/depthwise/ReadVariableOp","shape":[3,3,16,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_3/depthwise/ReadVariableOp","shape":[3,3,16,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_4/depthwise/ReadVariableOp","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_5/depthwise/ReadVariableOp","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_6/depthwise/ReadVariableOp","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_7/depthwise/ReadVariableOp","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_8/depthwise/ReadVariableOp","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_9/depthwise/ReadVariableOp","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_10/depthwise/ReadVariableOp","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_11/depthwise/ReadVariableOp","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_12/depthwise/ReadVariableOp","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_13/depthwise/ReadVariableOp","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_14/depthwise/ReadVariableOp","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_15/depthwise/ReadVariableOp","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_16/depthwise/ReadVariableOp","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_17/depthwise/ReadVariableOp","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/depthwise_conv2d_18/depthwise/ReadVariableOp","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_21/Conv2D/ReadVariableOp","shape":[3,3,32,1404],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_21/BiasAdd/ReadVariableOp","shape":[1404],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/output_mesh/Const","shape":[2],"dtype":"int32"},{"name":"StatefulPartitionedCall/model_1/conv2d_1/Conv2D_weights","shape":[3,3,3,16],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_1/Conv2D_bn_offset","shape":[16],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_2/Conv2D_weights","shape":[1,1,16,16],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_2/Conv2D_bn_offset","shape":[16],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_3/Conv2D_weights","shape":[1,1,16,16],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_3/Conv2D_bn_offset","shape":[16],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_4/Conv2D_weights","shape":[1,1,16,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_26/Conv2D_weights","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_4/Conv2D_bn_offset","shape":[32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_5/Conv2D_weights","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_5/Conv2D_bn_offset","shape":[32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_6/Conv2D_weights","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_26/Conv2D_bn_offset","shape":[32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_6/Conv2D_bn_offset","shape":[32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_7/Conv2D_weights","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_7/Conv2D_bn_offset","shape":[64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_8/Conv2D_weights","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_8/Conv2D_bn_offset","shape":[64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_9/Conv2D_weights","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_9/Conv2D_bn_offset","shape":[64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_10/Conv2D_weights","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_10/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_11/Conv2D_weights","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_11/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_12/Conv2D_weights","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_12/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_13/Conv2D_weights","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_13/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_14/Conv2D_weights","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_14/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_15/Conv2D_weights","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_15/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_22/Conv2D_weights","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_22/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_28/Conv2D_weights","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_28/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_16/Conv2D_weights","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_20/Conv2D_weights","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_16/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_29/Conv2D_weights","shape":[1,1,128,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_29/Conv2D_bn_offset","shape":[32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_23/Conv2D_weights","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_20/Conv2D_bn_offset","shape":[32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_23/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_17/Conv2D_weights","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_17/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_30/Conv2D_weights","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_30/Conv2D_bn_offset","shape":[32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_24/Conv2D_weights","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_24/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_18/Conv2D_weights","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_18/Conv2D_bn_offset","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_25/Conv2D_weights","shape":[1,1,128,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_25/Conv2D_bn_offset","shape":[32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_19/Conv2D_weights","shape":[1,1,128,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"StatefulPartitionedCall/model_1/conv2d_19/Conv2D_bn_offset","shape":[32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}}] } ] } ================================================ FILE: extern/human/models/faceres.json ================================================ { "format": "graph-model", "generatedBy": "https://github.com/HSE-asavchenko/HSE_FaceRec_tf", "convertedBy": "https://github.com/vladmandic", "signature": { "inputs": { "input_1": { "name": "input_1", "dtype": "DT_FLOAT", "tensorShape":{"dim":[{"size":"-1"},{"size":"224"},{"size":"224"},{"size":"3"}]} } }, "outputs": { "gender_pred/Sigmoid:0": {"name":"gender_pred/Sigmoid:0", "dtype":"DT_FLOAT", "tensorShape":{"dim":[{"size":"1"},{"size":"1"}]} }, "global_pooling/Mean": {"name":"global_pooling/Mean", "dtype":"DT_FLOAT", "tensorShape":{"dim":[{"size":"1"},{"size":"1024"}]} }, "age_pred/Softmax:0": {"name":"age_pred/Softmax:0", "dtype":"DT_FLOAT", "tensorShape":{"dim":[{"size":"1"},{"size":"100"}]} } } }, "modelTopology": { "node": [ {"name":"age_pred/kernel","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"256"},{"size":"100"}]}}}}}, {"name":"age_pred/bias","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"100"}]}}}}}, {"name":"feats/kernel","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1024"},{"size":"256"}]}}}}}, {"name":"feats/bias","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"256"}]}}}}}, {"name":"gender_pred/kernel","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"256"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"gender_pred/bias","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"}]}}}}}, {"name":"conv1/convolution/merged_input","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"3"},{"size":"32"}]}}}}}, {"name":"conv1_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv1_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv1_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_dw_1/depthwise_kernel","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"32"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_1_bn/batchnorm_1/mul","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}}}}, {"name":"conv_dw_1_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"32"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_1_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_1_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_pw_1/convolution/merged_input","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"32"},{"size":"64"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_1_bn/batchnorm_1/sub","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"64"}]}}}}}, {"name":"conv_pw_1_relu/Cast","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_pw_1_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_2/depthwise_kernel","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"64"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_2_bn/batchnorm_1/mul","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"64"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_2_bn/batchnorm_1/sub","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"64"}]}}}}}, {"name":"conv_dw_2_relu/Cast","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_dw_2_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_pw_2/convolution/merged_input","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"64"},{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_2_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_2_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_2_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_dw_3/depthwise_kernel","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_3_bn/batchnorm_1/mul","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"conv_dw_3_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_3_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_3_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_3/convolution/merged_input","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"128"}]}}}}}, {"name":"conv_pw_3_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_3_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_3_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_4/depthwise_kernel","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"128"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_4_bn/batchnorm_1/mul","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"conv_dw_4_bn/batchnorm_1/sub","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"128"}]}}}}}, {"name":"conv_dw_4_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_4_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_pw_4/convolution/merged_input","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"128"},{"size":"256"}]}}}}}, {"name":"conv_pw_4_bn/batchnorm_1/sub","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"256"}]}}}}}, {"name":"conv_pw_4_relu/Cast","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_pw_4_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_5/depthwise_kernel","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"256"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_5_bn/batchnorm_1/mul","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"256"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_5_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"256"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_5_relu/Cast","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_dw_5_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_pw_5/convolution/merged_input","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"256"},{"size":"256"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_5_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"256"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_5_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_5_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_6/depthwise_kernel","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"256"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_6_bn/batchnorm_1/mul","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"256"}]}}}}}, {"name":"conv_dw_6_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"256"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_6_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_6_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_6/convolution/merged_input","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"256"},{"size":"512"}]}}}}}, {"name":"conv_pw_6_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_6_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_6_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_dw_7/depthwise_kernel","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"512"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_7_bn/batchnorm_1/mul","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_7_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_7_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_7_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_pw_7/convolution/merged_input","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"512"},{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_7_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_7_relu/Cast","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_pw_7_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_8/depthwise_kernel","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"512"},{"size":"1"}]}}}}}, {"name":"conv_dw_8_bn/batchnorm_1/mul","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}}}}, {"name":"conv_dw_8_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_8_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_8_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_8/convolution/merged_input","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"512"},{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_8_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_8_relu/Cast","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_pw_8_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_dw_9/depthwise_kernel","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"512"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_9_bn/batchnorm_1/mul","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}}}}, {"name":"conv_dw_9_bn/batchnorm_1/sub","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}}}}, {"name":"conv_dw_9_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_9_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_9/convolution/merged_input","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"512"},{"size":"512"}]}}}}}, {"name":"conv_pw_9_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_9_relu/Cast","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_pw_9_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_10/depthwise_kernel","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"512"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_10_bn/batchnorm_1/mul","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}}}}, {"name":"conv_dw_10_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_10_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_10_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_pw_10/convolution/merged_input","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"512"},{"size":"512"}]}}}}}, {"name":"conv_pw_10_bn/batchnorm_1/sub","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}}}}, {"name":"conv_pw_10_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_10_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_11/depthwise_kernel","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"512"},{"size":"1"}]}}}}}, {"name":"conv_dw_11_bn/batchnorm_1/mul","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_11_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_11_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_11_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_11/convolution/merged_input","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"512"},{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_11_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_11_relu/Cast","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_pw_11_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_dw_12/depthwise_kernel","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"512"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_12_bn/batchnorm_1/mul","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}}}}, {"name":"conv_dw_12_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"512"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_12_relu/Cast","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_dw_12_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_12/convolution/merged_input","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"512"},{"size":"1024"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_12_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1024"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_12_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_12_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_dw_13/depthwise_kernel","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"3"},{"size":"3"},{"size":"1024"},{"size":"1"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_13_bn/batchnorm_1/mul","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1024"}]}}}}}, {"name":"conv_dw_13_bn/batchnorm_1/sub","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1024"}]}}}}}, {"name":"conv_dw_13_relu/Cast","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"conv_dw_13_relu/Const_1","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_13/convolution/merged_input","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1"},{"size":"1"},{"size":"1024"},{"size":"1024"}]}}}}}, {"name":"conv_pw_13_bn/batchnorm_1/sub","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{"dim":[{"size":"1024"}]}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_13_relu/Cast","op":"Const","attr":{"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_13_relu/Const_1","op":"Const","attr":{"dtype":{"type":"DT_FLOAT"},"value":{"tensor":{"dtype":"DT_FLOAT","tensorShape":{}}}}}, {"name":"global_pooling/Mean/reduction_indices","op":"Const","attr":{"dtype":{"type":"DT_INT32"},"value":{"tensor":{"dtype":"DT_INT32","tensorShape":{"dim":[{"size":"2"}]}}}}}, {"name":"input_1","op":"Placeholder","attr":{"shape":{"shape":{"dim":[{"size":"-1"},{"size":"224"},{"size":"224"},{"size":"3"}]}},"dtype":{"type":"DT_FLOAT"}}}, {"name":"conv1_bn/batchnorm_1/mul_1","op":"Conv2D","input":["input_1","conv1/convolution/merged_input"],"device":"/device:CPU:0","attr":{"strides":{"list":{"i":["1","2","2","1"]}},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"use_cudnn_on_gpu":{"b":true},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"conv1_bn/batchnorm_1/add_1","op":"Add","input":["conv1_bn/batchnorm_1/mul_1","conv1_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv1_relu/Relu","op":"Relu","input":["conv1_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv1_relu/clip_by_value/Minimum","op":"Minimum","input":["conv1_relu/Relu","conv1_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv1_relu/clip_by_value","op":"Maximum","input":["conv1_relu/clip_by_value/Minimum","conv1_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_1/depthwise","op":"DepthwiseConv2dNative","input":["conv1_relu/clip_by_value","conv_dw_1/depthwise_kernel"],"attr":{"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="}}}, {"name":"conv_dw_1_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_1/depthwise","conv_dw_1_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_1_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_1_bn/batchnorm_1/mul_1","conv_dw_1_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_1_relu/Relu","op":"Relu","input":["conv_dw_1_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_1_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_1_relu/Relu","conv_dw_1_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_1_relu/clip_by_value","op":"Maximum","input":["conv_dw_1_relu/clip_by_value/Minimum","conv_dw_1_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_1_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_1_relu/clip_by_value","conv_pw_1/convolution/merged_input"],"device":"/device:CPU:0","attr":{"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"strides":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"data_format":{"s":"TkhXQw=="}}}, {"name":"conv_pw_1_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_1_bn/batchnorm_1/mul_1","conv_pw_1_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_1_relu/Relu","op":"Relu","input":["conv_pw_1_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_1_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_1_relu/Relu","conv_pw_1_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_1_relu/clip_by_value","op":"Maximum","input":["conv_pw_1_relu/clip_by_value/Minimum","conv_pw_1_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_2/depthwise","op":"DepthwiseConv2dNative","input":["conv_pw_1_relu/clip_by_value","conv_dw_2/depthwise_kernel"],"attr":{"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","2","2","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"conv_dw_2_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_2/depthwise","conv_dw_2_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_2_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_2_bn/batchnorm_1/mul_1","conv_dw_2_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_2_relu/Relu","op":"Relu","input":["conv_dw_2_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_2_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_2_relu/Relu","conv_dw_2_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_2_relu/clip_by_value","op":"Maximum","input":["conv_dw_2_relu/clip_by_value/Minimum","conv_dw_2_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_2_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_2_relu/clip_by_value","conv_pw_2/convolution/merged_input"],"device":"/device:CPU:0","attr":{"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"padding":{"s":"U0FNRQ=="},"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}}}}, {"name":"conv_pw_2_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_2_bn/batchnorm_1/mul_1","conv_pw_2_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_2_relu/Relu","op":"Relu","input":["conv_pw_2_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_2_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_2_relu/Relu","conv_pw_2_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_2_relu/clip_by_value","op":"Maximum","input":["conv_pw_2_relu/clip_by_value/Minimum","conv_pw_2_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_3/depthwise","op":"DepthwiseConv2dNative","input":["conv_pw_2_relu/clip_by_value","conv_dw_3/depthwise_kernel"],"attr":{"strides":{"list":{"i":["1","1","1","1"]}},"dilations":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"},"padding":{"s":"U0FNRQ=="}}}, {"name":"conv_dw_3_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_3/depthwise","conv_dw_3_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_3_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_3_bn/batchnorm_1/mul_1","conv_dw_3_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_3_relu/Relu","op":"Relu","input":["conv_dw_3_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_3_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_3_relu/Relu","conv_dw_3_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_3_relu/clip_by_value","op":"Maximum","input":["conv_dw_3_relu/clip_by_value/Minimum","conv_dw_3_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_3_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_3_relu/clip_by_value","conv_pw_3/convolution/merged_input"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="}}}, {"name":"conv_pw_3_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_3_bn/batchnorm_1/mul_1","conv_pw_3_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_3_relu/Relu","op":"Relu","input":["conv_pw_3_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_3_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_3_relu/Relu","conv_pw_3_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_3_relu/clip_by_value","op":"Maximum","input":["conv_pw_3_relu/clip_by_value/Minimum","conv_pw_3_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_4/depthwise","op":"DepthwiseConv2dNative","input":["conv_pw_3_relu/clip_by_value","conv_dw_4/depthwise_kernel"],"attr":{"explicit_paddings":{"list":{}},"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","2","2","1"]}},"T":{"type":"DT_FLOAT"},"padding":{"s":"U0FNRQ=="}}}, {"name":"conv_dw_4_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_4/depthwise","conv_dw_4_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_4_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_4_bn/batchnorm_1/mul_1","conv_dw_4_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_4_relu/Relu","op":"Relu","input":["conv_dw_4_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_4_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_4_relu/Relu","conv_dw_4_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_4_relu/clip_by_value","op":"Maximum","input":["conv_dw_4_relu/clip_by_value/Minimum","conv_dw_4_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_4_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_4_relu/clip_by_value","conv_pw_4/convolution/merged_input"],"device":"/device:CPU:0","attr":{"strides":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_4_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_4_bn/batchnorm_1/mul_1","conv_pw_4_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_4_relu/Relu","op":"Relu","input":["conv_pw_4_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_4_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_4_relu/Relu","conv_pw_4_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_4_relu/clip_by_value","op":"Maximum","input":["conv_pw_4_relu/clip_by_value/Minimum","conv_pw_4_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_5/depthwise","op":"DepthwiseConv2dNative","input":["conv_pw_4_relu/clip_by_value","conv_dw_5/depthwise_kernel"],"attr":{"explicit_paddings":{"list":{}},"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"padding":{"s":"U0FNRQ=="}}}, {"name":"conv_dw_5_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_5/depthwise","conv_dw_5_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_5_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_5_bn/batchnorm_1/mul_1","conv_dw_5_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_5_relu/Relu","op":"Relu","input":["conv_dw_5_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_5_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_5_relu/Relu","conv_dw_5_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_5_relu/clip_by_value","op":"Maximum","input":["conv_dw_5_relu/clip_by_value/Minimum","conv_dw_5_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_5_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_5_relu/clip_by_value","conv_pw_5/convolution/merged_input"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true},"strides":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"explicit_paddings":{"list":{}}}}, {"name":"conv_pw_5_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_5_bn/batchnorm_1/mul_1","conv_pw_5_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_5_relu/Relu","op":"Relu","input":["conv_pw_5_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_5_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_5_relu/Relu","conv_pw_5_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_5_relu/clip_by_value","op":"Maximum","input":["conv_pw_5_relu/clip_by_value/Minimum","conv_pw_5_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_6/depthwise","op":"DepthwiseConv2dNative","input":["conv_pw_5_relu/clip_by_value","conv_dw_6/depthwise_kernel"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","2","2","1"]}}}}, {"name":"conv_dw_6_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_6/depthwise","conv_dw_6_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_6_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_6_bn/batchnorm_1/mul_1","conv_dw_6_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_6_relu/Relu","op":"Relu","input":["conv_dw_6_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_6_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_6_relu/Relu","conv_dw_6_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_6_relu/clip_by_value","op":"Maximum","input":["conv_dw_6_relu/clip_by_value/Minimum","conv_dw_6_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_6_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_6_relu/clip_by_value","conv_pw_6/convolution/merged_input"],"device":"/device:CPU:0","attr":{"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"use_cudnn_on_gpu":{"b":true},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"conv_pw_6_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_6_bn/batchnorm_1/mul_1","conv_pw_6_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_6_relu/Relu","op":"Relu","input":["conv_pw_6_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_6_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_6_relu/Relu","conv_pw_6_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_6_relu/clip_by_value","op":"Maximum","input":["conv_pw_6_relu/clip_by_value/Minimum","conv_pw_6_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_7/depthwise","op":"DepthwiseConv2dNative","input":["conv_pw_6_relu/clip_by_value","conv_dw_7/depthwise_kernel"],"attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"},"explicit_paddings":{"list":{}}}}, {"name":"conv_dw_7_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_7/depthwise","conv_dw_7_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_7_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_7_bn/batchnorm_1/mul_1","conv_dw_7_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_7_relu/Relu","op":"Relu","input":["conv_dw_7_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_7_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_7_relu/Relu","conv_dw_7_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_7_relu/clip_by_value","op":"Maximum","input":["conv_dw_7_relu/clip_by_value/Minimum","conv_dw_7_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_7_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_7_relu/clip_by_value","conv_pw_7/convolution/merged_input"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","1","1","1"]}}}}, {"name":"conv_pw_7_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_7_bn/batchnorm_1/mul_1","conv_pw_7_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_7_relu/Relu","op":"Relu","input":["conv_pw_7_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_7_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_7_relu/Relu","conv_pw_7_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_7_relu/clip_by_value","op":"Maximum","input":["conv_pw_7_relu/clip_by_value/Minimum","conv_pw_7_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_8/depthwise","op":"DepthwiseConv2dNative","input":["conv_pw_7_relu/clip_by_value","conv_dw_8/depthwise_kernel"],"attr":{"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="},"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="}}}, {"name":"conv_dw_8_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_8/depthwise","conv_dw_8_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_8_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_8_bn/batchnorm_1/mul_1","conv_dw_8_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_8_relu/Relu","op":"Relu","input":["conv_dw_8_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_8_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_8_relu/Relu","conv_dw_8_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_8_relu/clip_by_value","op":"Maximum","input":["conv_dw_8_relu/clip_by_value/Minimum","conv_dw_8_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_8_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_8_relu/clip_by_value","conv_pw_8/convolution/merged_input"],"device":"/device:CPU:0","attr":{"explicit_paddings":{"list":{}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"padding":{"s":"U0FNRQ=="},"use_cudnn_on_gpu":{"b":true},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}}}}, {"name":"conv_pw_8_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_8_bn/batchnorm_1/mul_1","conv_pw_8_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_8_relu/Relu","op":"Relu","input":["conv_pw_8_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_8_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_8_relu/Relu","conv_pw_8_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_8_relu/clip_by_value","op":"Maximum","input":["conv_pw_8_relu/clip_by_value/Minimum","conv_pw_8_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_9/depthwise","op":"DepthwiseConv2dNative","input":["conv_pw_8_relu/clip_by_value","conv_dw_9/depthwise_kernel"],"attr":{"explicit_paddings":{"list":{}},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"},"data_format":{"s":"TkhXQw=="}}}, {"name":"conv_dw_9_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_9/depthwise","conv_dw_9_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_9_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_9_bn/batchnorm_1/mul_1","conv_dw_9_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_9_relu/Relu","op":"Relu","input":["conv_dw_9_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_9_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_9_relu/Relu","conv_dw_9_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_9_relu/clip_by_value","op":"Maximum","input":["conv_dw_9_relu/clip_by_value/Minimum","conv_dw_9_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_9_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_9_relu/clip_by_value","conv_pw_9/convolution/merged_input"],"device":"/device:CPU:0","attr":{"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"},"use_cudnn_on_gpu":{"b":true},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}}}}, {"name":"conv_pw_9_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_9_bn/batchnorm_1/mul_1","conv_pw_9_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_9_relu/Relu","op":"Relu","input":["conv_pw_9_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_9_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_9_relu/Relu","conv_pw_9_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_9_relu/clip_by_value","op":"Maximum","input":["conv_pw_9_relu/clip_by_value/Minimum","conv_pw_9_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_10/depthwise","op":"DepthwiseConv2dNative","input":["conv_pw_9_relu/clip_by_value","conv_dw_10/depthwise_kernel"],"attr":{"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"},"explicit_paddings":{"list":{}},"strides":{"list":{"i":["1","1","1","1"]}}}}, {"name":"conv_dw_10_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_10/depthwise","conv_dw_10_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_10_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_10_bn/batchnorm_1/mul_1","conv_dw_10_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_10_relu/Relu","op":"Relu","input":["conv_dw_10_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_10_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_10_relu/Relu","conv_dw_10_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_10_relu/clip_by_value","op":"Maximum","input":["conv_dw_10_relu/clip_by_value/Minimum","conv_dw_10_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_10_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_10_relu/clip_by_value","conv_pw_10/convolution/merged_input"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"use_cudnn_on_gpu":{"b":true},"padding":{"s":"U0FNRQ=="},"data_format":{"s":"TkhXQw=="},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"dilations":{"list":{"i":["1","1","1","1"]}}}}, {"name":"conv_pw_10_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_10_bn/batchnorm_1/mul_1","conv_pw_10_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_10_relu/Relu","op":"Relu","input":["conv_pw_10_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_10_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_10_relu/Relu","conv_pw_10_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_10_relu/clip_by_value","op":"Maximum","input":["conv_pw_10_relu/clip_by_value/Minimum","conv_pw_10_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_11/depthwise","op":"DepthwiseConv2dNative","input":["conv_pw_10_relu/clip_by_value","conv_dw_11/depthwise_kernel"],"attr":{"padding":{"s":"U0FNRQ=="},"strides":{"list":{"i":["1","1","1","1"]}},"dilations":{"list":{"i":["1","1","1","1"]}},"T":{"type":"DT_FLOAT"},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="}}}, {"name":"conv_dw_11_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_11/depthwise","conv_dw_11_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_11_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_11_bn/batchnorm_1/mul_1","conv_dw_11_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_11_relu/Relu","op":"Relu","input":["conv_dw_11_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_11_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_11_relu/Relu","conv_dw_11_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_11_relu/clip_by_value","op":"Maximum","input":["conv_dw_11_relu/clip_by_value/Minimum","conv_dw_11_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_11_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_11_relu/clip_by_value","conv_pw_11/convolution/merged_input"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"data_format":{"s":"TkhXQw=="},"use_cudnn_on_gpu":{"b":true}}}, {"name":"conv_pw_11_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_11_bn/batchnorm_1/mul_1","conv_pw_11_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_11_relu/Relu","op":"Relu","input":["conv_pw_11_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_11_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_11_relu/Relu","conv_pw_11_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_11_relu/clip_by_value","op":"Maximum","input":["conv_pw_11_relu/clip_by_value/Minimum","conv_pw_11_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_12/depthwise","op":"DepthwiseConv2dNative","input":["conv_pw_11_relu/clip_by_value","conv_dw_12/depthwise_kernel"],"attr":{"explicit_paddings":{"list":{}},"T":{"type":"DT_FLOAT"},"dilations":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"strides":{"list":{"i":["1","2","2","1"]}},"data_format":{"s":"TkhXQw=="}}}, {"name":"conv_dw_12_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_12/depthwise","conv_dw_12_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_12_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_12_bn/batchnorm_1/mul_1","conv_dw_12_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_12_relu/Relu","op":"Relu","input":["conv_dw_12_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_12_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_12_relu/Relu","conv_dw_12_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_12_relu/clip_by_value","op":"Maximum","input":["conv_dw_12_relu/clip_by_value/Minimum","conv_dw_12_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_12_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_12_relu/clip_by_value","conv_pw_12/convolution/merged_input"],"device":"/device:CPU:0","attr":{"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"padding":{"s":"U0FNRQ=="},"use_cudnn_on_gpu":{"b":true},"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="},"explicit_paddings":{"list":{}}}}, {"name":"conv_pw_12_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_12_bn/batchnorm_1/mul_1","conv_pw_12_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_12_relu/Relu","op":"Relu","input":["conv_pw_12_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_12_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_12_relu/Relu","conv_pw_12_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_12_relu/clip_by_value","op":"Maximum","input":["conv_pw_12_relu/clip_by_value/Minimum","conv_pw_12_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_13/depthwise","op":"DepthwiseConv2dNative","input":["conv_pw_12_relu/clip_by_value","conv_dw_13/depthwise_kernel"],"attr":{"T":{"type":"DT_FLOAT"},"strides":{"list":{"i":["1","1","1","1"]}},"explicit_paddings":{"list":{}},"padding":{"s":"U0FNRQ=="},"dilations":{"list":{"i":["1","1","1","1"]}},"data_format":{"s":"TkhXQw=="}}}, {"name":"conv_dw_13_bn/batchnorm_1/mul_1","op":"Mul","input":["conv_dw_13/depthwise","conv_dw_13_bn/batchnorm_1/mul"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_13_bn/batchnorm_1/add_1","op":"Add","input":["conv_dw_13_bn/batchnorm_1/mul_1","conv_dw_13_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_13_relu/Relu","op":"Relu","input":["conv_dw_13_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_13_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_dw_13_relu/Relu","conv_dw_13_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_dw_13_relu/clip_by_value","op":"Maximum","input":["conv_dw_13_relu/clip_by_value/Minimum","conv_dw_13_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_13_bn/batchnorm_1/mul_1","op":"Conv2D","input":["conv_dw_13_relu/clip_by_value","conv_pw_13/convolution/merged_input"],"device":"/device:CPU:0","attr":{"padding":{"s":"U0FNRQ=="},"T":{"type":"DT_FLOAT"},"explicit_paddings":{"list":{}},"data_format":{"s":"TkhXQw=="},"dilations":{"list":{"i":["1","1","1","1"]}},"strides":{"list":{"i":["1","1","1","1"]}},"use_cudnn_on_gpu":{"b":true}}}, {"name":"conv_pw_13_bn/batchnorm_1/add_1","op":"Add","input":["conv_pw_13_bn/batchnorm_1/mul_1","conv_pw_13_bn/batchnorm_1/sub"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_13_relu/Relu","op":"Relu","input":["conv_pw_13_bn/batchnorm_1/add_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_13_relu/clip_by_value/Minimum","op":"Minimum","input":["conv_pw_13_relu/Relu","conv_pw_13_relu/Cast"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"conv_pw_13_relu/clip_by_value","op":"Maximum","input":["conv_pw_13_relu/clip_by_value/Minimum","conv_pw_13_relu/Const_1"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"global_pooling/Mean","op":"Mean","input":["conv_pw_13_relu/clip_by_value","global_pooling/Mean/reduction_indices"],"attr":{"Tidx":{"type":"DT_INT32"},"T":{"type":"DT_FLOAT"},"keep_dims":{"b":false}}}, {"name":"feats/Relu","op":"_FusedMatMul","input":["global_pooling/Mean","feats/kernel","feats/bias"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"T":{"type":"DT_FLOAT"},"fused_ops":{"list":{"s":["Qmlhc0FkZA==","UmVsdQ=="]}},"num_args":{"i":"1"},"transpose_a":{"b":false},"transpose_b":{"b":false}}}, {"name":"gender_pred/BiasAdd","op":"_FusedMatMul","input":["feats/Relu","gender_pred/kernel","gender_pred/bias"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"transpose_b":{"b":false},"T":{"type":"DT_FLOAT"},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"num_args":{"i":"1"},"transpose_a":{"b":false}}}, {"name":"age_pred/BiasAdd","op":"_FusedMatMul","input":["feats/Relu","age_pred/kernel","age_pred/bias"],"device":"/device:CPU:0","attr":{"epsilon":{"f":0},"T":{"type":"DT_FLOAT"},"fused_ops":{"list":{"s":["Qmlhc0FkZA=="]}},"transpose_b":{"b":false},"num_args":{"i":"1"},"transpose_a":{"b":false}}}, {"name":"gender_pred/Sigmoid","op":"Sigmoid","input":["gender_pred/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}}, {"name":"age_pred/Softmax","op":"Softmax","input":["age_pred/BiasAdd"],"attr":{"T":{"type":"DT_FLOAT"}}} ], "library": {}, "versions": {} }, "weightsManifest": [ { "paths": ["faceres.bin"], "weights": [{"name":"age_pred/kernel","shape":[256,100],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"age_pred/bias","shape":[100],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"feats/kernel","shape":[1024,256],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"feats/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"gender_pred/kernel","shape":[256,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"gender_pred/bias","shape":[1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv1/convolution/merged_input","shape":[3,3,3,32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv1_bn/batchnorm_1/sub","shape":[32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv1_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv1_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_1/depthwise_kernel","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_1_bn/batchnorm_1/mul","shape":[32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_1_bn/batchnorm_1/sub","shape":[32],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_1_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_1_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_1/convolution/merged_input","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_1_bn/batchnorm_1/sub","shape":[64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_1_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_1_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_2/depthwise_kernel","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_2_bn/batchnorm_1/mul","shape":[64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_2_bn/batchnorm_1/sub","shape":[64],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_2_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_2_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_2/convolution/merged_input","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_2_bn/batchnorm_1/sub","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_2_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_2_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_3/depthwise_kernel","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_3_bn/batchnorm_1/mul","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_3_bn/batchnorm_1/sub","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_3_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_3_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_3/convolution/merged_input","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_3_bn/batchnorm_1/sub","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_3_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_3_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_4/depthwise_kernel","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_4_bn/batchnorm_1/mul","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_4_bn/batchnorm_1/sub","shape":[128],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_4_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_4_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_4/convolution/merged_input","shape":[1,1,128,256],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_4_bn/batchnorm_1/sub","shape":[256],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_4_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_4_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_5/depthwise_kernel","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_5_bn/batchnorm_1/mul","shape":[256],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_5_bn/batchnorm_1/sub","shape":[256],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_5_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_5_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_5/convolution/merged_input","shape":[1,1,256,256],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_5_bn/batchnorm_1/sub","shape":[256],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_5_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_5_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_6/depthwise_kernel","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_6_bn/batchnorm_1/mul","shape":[256],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_6_bn/batchnorm_1/sub","shape":[256],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_6_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_6_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_6/convolution/merged_input","shape":[1,1,256,512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_6_bn/batchnorm_1/sub","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_6_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_6_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_7/depthwise_kernel","shape":[3,3,512,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_7_bn/batchnorm_1/mul","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_7_bn/batchnorm_1/sub","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_7_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_7_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_7/convolution/merged_input","shape":[1,1,512,512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_7_bn/batchnorm_1/sub","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_7_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_7_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_8/depthwise_kernel","shape":[3,3,512,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_8_bn/batchnorm_1/mul","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_8_bn/batchnorm_1/sub","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_8_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_8_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_8/convolution/merged_input","shape":[1,1,512,512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_8_bn/batchnorm_1/sub","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_8_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_8_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_9/depthwise_kernel","shape":[3,3,512,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_9_bn/batchnorm_1/mul","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_9_bn/batchnorm_1/sub","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_9_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_9_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_9/convolution/merged_input","shape":[1,1,512,512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_9_bn/batchnorm_1/sub","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_9_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_9_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_10/depthwise_kernel","shape":[3,3,512,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_10_bn/batchnorm_1/mul","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_10_bn/batchnorm_1/sub","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_10_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_10_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_10/convolution/merged_input","shape":[1,1,512,512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_10_bn/batchnorm_1/sub","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_10_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_10_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_11/depthwise_kernel","shape":[3,3,512,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_11_bn/batchnorm_1/mul","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_11_bn/batchnorm_1/sub","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_11_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_11_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_11/convolution/merged_input","shape":[1,1,512,512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_11_bn/batchnorm_1/sub","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_11_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_11_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_12/depthwise_kernel","shape":[3,3,512,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_12_bn/batchnorm_1/mul","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_12_bn/batchnorm_1/sub","shape":[512],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_12_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_12_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_12/convolution/merged_input","shape":[1,1,512,1024],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_12_bn/batchnorm_1/sub","shape":[1024],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_12_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_12_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_13/depthwise_kernel","shape":[3,3,1024,1],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_13_bn/batchnorm_1/mul","shape":[1024],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_13_bn/batchnorm_1/sub","shape":[1024],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_13_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_dw_13_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_13/convolution/merged_input","shape":[1,1,1024,1024],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_13_bn/batchnorm_1/sub","shape":[1024],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_13_relu/Cast","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"conv_pw_13_relu/Const_1","shape":[],"dtype":"float32","quantization":{"dtype":"float16","original_dtype":"float32"}},{"name":"global_pooling/Mean/reduction_indices","shape":[2],"dtype":"int32"}] } ] } ================================================ FILE: extern/khaiii/config.json ================================================ { "class_num": 500, "conv_kernels": [ 2, 3, 4, 5 ], "embed_dim": 35, "hidden_dim": 320, "vocab_size": 5625, "window": 4 } ================================================ FILE: extern/lang/code.js ================================================ var Lang = {}; Lang.category = { name: 'ko', }; Lang.type = 'ko'; Lang.fallbackType = 'ko'; Lang.ko = '한국어'; Lang.en = 'English'; Lang.jp = '日本語'; Lang.vn = 'tiếng Việt'; Lang.Command = { 1: '장면 추가하기', 2: '장면 삭제하기', 3: '장면 이름 수정', 4: '장면 순서 변경', 5: '장면 선택', 101: '블록 쓰레드 추가하기', 102: '블록 쓰레드 삭제하기', 103: '블록 삭제하기', 104: '블록 복구하기', 105: '블록 끼워넣기', 106: '블록 분리하기', 107: '블록 이동하기', 108: '블록 복제하기', 109: '블록 복제 취소하기', 110: '스크롤', 111: '블록 필드값 수정', 117: '블록 쓰레드 추가하기', 118: '블록 끼워넣기', 119: '블록 이동하기', 120: '블록 분리하기', 121: '블록 이동하기', 122: '블록 끼워넣기', 123: '블록 끼워넣기', 201: '오브젝트 선택하기', 202: '오브젝트 수정 버튼 클릭', 203: '오브젝트 그림 추가', 204: '오브젝트 그림 삭제', 205: '오브젝트 소리 추가', 206: '오브젝트 소리 삭제', 207: '오브젝트 이름 수정', 208: '오브젝트 추가', 209: '오브젝트 삭제', 210: '오브젝트 추가 버튼 클릭', 211: '오브젝트 x 수정', 212: '오브젝트 y 수정', 213: '오브젝트 size 수정', 214: '오브젝트 방향 수정', 215: '오브젝트 이동 방향 수정', 216: '오브젝트 회전방식 수정', 217: '엔터티 모델 동기화', 301: 'do', 302: 'undo', 303: 'redo', 401: '그림 수정하기', 402: '그림 수정 취소하기', 403: '그림 수정하기', 404: '그림 수정 취소하기', 405: '글상자 수정', 501: '시작하기', 502: '정지하기', 601: '컨테이너 오브젝트 선택하기', 701: '모드 바꾸기', 702: '모양 추가 버튼 클릭', 703: '소리 추가 버튼 클릭', 801: '속성 필터 선택하기', 802: '변수 추가하기 버튼 클릭', 803: '변수 추가하기', 804: '변수 삭제하기', 805: '변수 이름 설정', 806: '신호 이름 설정', 807: '신호 추가', 808: '신호 삭제', 809: '변수 스코프 정하기', 810: '변수 글로벌 체크', 811: '변수 보이기 체크', 812: '변수 기본값 설정', 813: '변수 슬라이드로 체크', 814: '변수 최솟값 정하기', 815: '변수 최댓값 정하기', 816: '리스트 추가 버튼 클릭', 817: '리스트 추가', 818: '리스트 삭제', 819: '리스트 이름 정하기', 820: '리스트 스코프 정하기', 821: '리스트 글로벌 체크', 822: '리스트 보이기 체크', 823: '리스트 길이 변경', 824: '리스트 기본값 설정', 825: '메세지 수정 enable', 826: '변수 수정 enable', 827: '리스트 수정 enable', 828: '변수 이름 정하기', 829: '리스트 이름 정하기', 900: '모달 닫기', 1001: '함수 생성 시작', 1002: '함수 수정 시작', 1003: '함수 수정 취소', 1004: '함수 생성', 1005: '함수 업데이트', }; Lang.CommandTooltip = { 101: '블록 쓰레드 추가하기', 102: '블록 쓰레드 삭제하기', 103: '블록 삭제하기', 104: '블록 복구하기', 105: '코드 분리하기$$코드 연결하기@@이 코드의 가장 위에 있는 블록을 잡고 분리하여 끌어옵니다.$$이 곳에 코드를 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 106: '블록 분리하기', 107: '블록 이동하기', 108: '블록 복제하기', 109: '블록 복제 취소하기', 110: '스크롤', 111: '블록 필드값 수정@@값을 입력하기 위해 이곳을 클릭합니다.$$선택지를 클릭합니다.$$선택지를 클릭합니다.$$&value&을 입력합니다.$$&value&를 선택합니다.$$키보드 &value&를 누릅니다.', 117: '블록 쓰레드 추가하기', 118: '블록 연결하기@@이 곳에 블록을 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 119: '블록 가져오기@@빈 곳에 블록을 끌어다 놓습니다.', 120: '블록 분리하기$$블록 삭제하기@@필요 없는 코드를 휴지통으로 끌어옵니다.$$이 곳에 코드를 버립니다.', 121: '블록 이동하기$$블록 삭제하기@@필요 없는 코드를 휴지통으로 끌어옵니다.$$이 곳에 코드를 버립니다.', 122: '블록 연결하기@@이 곳에 블록을 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 123: '코드 분리하기$$코드 연결하기@@이 코드의 가장 위에 있는 블록을 잡고 분리하여 끌어옵니다.$$이 곳에 코드를 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 201: '오브젝트 선택하기', 301: 'do', 302: 'undo', 303: 'redo', 401: '그림 수정하기', 402: '그림 수정 취소하기', 403: '그림 수정하기', 404: '그림 수정 취소하기', 501: '실행하기@@[시작하기]를 누릅니다.', 502: '정지하기@@[정지하기]를 누릅니다.', 601: '컨테이너 오브젝트 선택하기', 701: '모드 바꾸기', 702: '모양 추가하기@@모양추가를 클릭합니다.', 703: '소리 추가하기@@소리추가를 클릭합니다.', 801: '변수 속성창 필터 선택하기', 802: '변수 추가하기@@[변수 추가]를 클릭합니다.', 803: '변수 추가하기@@[확인]을 클릭합니다.', 804: '변수 삭제하기@@이 버튼을 눌러 변수를 삭제합니다.', 805: '변수 이름 설정', 1101: '확장 블록 추가하기@@확장 블록 블러오기를 클릭합니다.', }; Lang.Blocks = { download_guide: '• 연결 안내 다운로드', dictionary: '사전', ai_utilize: '인공지능', date_yesterday: '어제', date_today: '오늘', date_tomorrow: '내일', date_after_2_days: '모레', date_after_3_days: '3일 후', date_after_4_days: '4일 후', date_after_5_days: '5일 후', date_after_6_days: '6일 후', location_entire: '전체', location_seoul: '서울', location_seoul_jongno_gu: '종로구', location_seoul_jung_gu: '중구', location_seoul_yongsan_gu: '용산구', location_seoul_seongdong_gu: '성동구', location_seoul_gwangjin_gu: '광진구', location_seoul_dongdaemun_gu: '동대문구', location_seoul_jungnang_gu: '중랑구', location_seoul_seongbuk_gu: '성북구', location_seoul_gangbuk_gu: '강북구', location_seoul_dobong_gu: '도봉구', location_seoul_nowon_gu: '노원구', location_seoul_eunpyeong_gu: '은평구', location_seoul_seodaemun_gu: '서대문구', location_seoul_mapo_gu: '마포구', location_seoul_yangcheon_gu: '양천구', location_seoul_gangseo_gu: '강서구', location_seoul_guro_gu: '구로구', location_seoul_geumcheon_gu: '금천구', location_seoul_yeongdeungpo_gu: '영등포구', location_seoul_dongjak_gu: '동작구', location_seoul_gwanak_gu: '관악구', location_seoul_seocho_gu: '서초구', location_seoul_gangnam_gu: '강남구', location_seoul_songpa_gu: '송파구', location_seoul_gangdong_gu: '강동구', location_busan: '부산', location_busan_jung_gu: '중구', location_busan_seo_gu: '서구', location_busan_dong_gu: '동구', location_busan_yeongdo_gu: '영도구', location_busan_busanjin_gu: '부산진구', location_busan_dongnae_gu: '동래구', location_busan_nam_gu: '남구', location_busan_buk_gu: '북구', location_busan_haeundae_gu: '해운대구', location_busan_saha_gu: '사하구', location_busan_geumjeong_gu: '금정구', location_busan_gangseo_gu: '강서구', location_busan_yeonje: '연제구', location_busan_suyeong_gu: '수영구', location_busan_sasang_gu: '사상구', location_busan_gijang: '기장군', location_daegu: '대구', location_daegu_jung_gu: '중구', location_daegu_dong_gu: '동구', location_daegu_seo_gu: '서구', location_daegu_nam_gu: '남구', location_daegu_buk_gu: '북구', location_daegu_suseong_gu: '수성구', location_daegu_dalseo_gu: '달서구', location_daegu_dalseong: '달성군', location_incheon: '인천', location_incheon_jung_gu: '중구', location_incheon_dong_gu: '동구', location_incheon_nam_gu: '남구', location_incheon_yeonsu_gu: '연수구', location_incheon_namdong_gu: '남동구', location_incheon_bupyeong_gu: '부평구', location_incheon_gyeyang_gu: '계양구', location_incheon_seo_gu: '서구', location_incheon_ganghwa: '강화군', location_incheon_ongjin_gun: '옹진군', location_gwangju: '광주', location_gwangju_dong_gu: '동구', location_gwangju_seo_gu: '서구', location_gwangju_nam_gu: '남구', location_gwangju_buk_gu: '북구', location_gwangju_gwangsan_gu: '광산구', location_daejeon: '대전', location_daejeon_dong_gu: '동구', location_daejeon_jung_gu: '중구', location_daejeon_seo_gu: '서구', location_daejeon_yuseong_gu: '유성구', location_daejeon_daedeok_gu: '대덕구', location_ulsan: '울산', location_ulsan_jung_gu: '중구', location_ulsan_nam_gu: '남구', location_ulsan_dong_gu: '동구', location_ulsan_buk_gu: '북구', location_ulsan_ulju: '울주군', location_sejong: '세종', location_gyeonggi: '경기', location_gyeonggi_suwon_si: '수원시', location_gyeonggi_seongnam: '성남시', location_gyeonggi_uijeongbu: '의정부시', location_gyeonggi_anyang_si: '안양시', location_gyeonggi_bucheon_si: '부천시', location_gyeonggi_gwangmyeong_si: '광명시', location_gyeonggi_pyeongtaek_si: '평택시', location_gyeonggi_dongducheon_si: '동두천시', location_gyeonggi_ansan_si: '안산시', location_gyeonggi_goyang_si: '고양시', location_gyeonggi_gwacheon_si: '과천시', location_gyeonggi_guri: '구리시', location_gyeonggi_namyangju_si: '남양주시', location_gyeonggi_osan: '오산시', location_gyeonggi_siheung: '시흥시', location_gyeonggi_gunpo_si: '군포시', location_gyeonggi_uiwang_si: '의왕시', location_gyeonggi_hanam: '하남시', location_gyeonggi_yongin_si: '용인시', location_gyeonggi_paju: '파주시', location_gyeonggi_icheon: '이천시', location_gyeonggi_anseong_si: '안성시', location_gyeonggi_gimpo: '김포시', location_gyeonggi_hwaseong_si: '화성시', location_gyeonggi_gwangju: '광주시', location_gyeonggi_yangju_si: '양주시', location_gyeonggi_pocheon: '포천시', location_gyeonggi_yeoju: '여주시', location_gyeonggi_yeoncheon_gun: '연천군', location_gyeonggi_gapyeong_gun: '가평군', location_gyeonggi_yangpyeong: '양평군', location_gangwon: '강원', location_gangwon_chuncheon: '춘천시', location_gangwon_wonju: '원주시', location_gangwon_gangneung_si: '강릉시', location_gangwon_donghae: '동해시', location_gangwon_taebaek_si: '태백시', location_gangwon_sokcho: '속초시', location_gangwon_samcheok_si: '삼척시', location_gangwon_hongcheon: '홍천군', location_gangwon_hoengseong_gun: '횡성군', location_gangwon_yeongwol_gun: '영월군', location_gangwon_pyeongchang: '평창군', location_gangwon_jeongseon: '정선군', location_gangwon_cheolwon: '철원군', location_gangwon_hwacheon: '화천군', location_gangwon_yanggu: '양구군', location_gangwon_inje: '인제군', location_gangwon_goseong: '고성군', location_gangwon_yangyang: '양양군', location_chungcheongbuk: '충북', location_chungcheongbuk_cheongju: '청주시', location_chungcheongbuk_chungju: '충주시', location_chungcheongbuk_jecheon: '제천시', location_chungcheongbuk_boeun: '보은군', location_chungcheongbuk_okcheon: '옥천군', location_chungcheongbuk_yeongdong: '영동군', location_chungcheongbuk_jeungpyeong: '증평군', location_chungcheongbuk_jincheon: '진천군', location_chungcheongbuk_goesan: '괴산군', location_chungcheongbuk_eumseong: '음성군', location_chungcheongbuk_danyang: '단양군', location_chungcheongnam: '충남', location_chungcheongnam_cheonan: '천안시', location_chungcheongnam_gongju: '공주시', location_chungcheongnam_boryeong: '보령시', location_chungcheongnam_asan: '아산시', location_chungcheongnam_seosan: '서산시', location_chungcheongnam_nonsan: '논산시', location_chungcheongnam_gyeryong: '계룡시', location_chungcheongnam_dangjin: '당진시', location_chungcheongnam_geumsan: '금산군', location_chungcheongnam_buyeo: '부여군', location_chungcheongnam_seocheon: '서천군', location_chungcheongnam_cheongyang: '청양군', location_chungcheongnam_hongseong: '홍성군', location_chungcheongnam_yesan: '예산군', location_chungcheongnam_taean: '태안군', location_jeollabuk: '전북', location_jeollabuk_jeonju: '전주시', location_jeollabuk_gunsan_si: '군산시', location_jeollabuk_iksan: '익산시', location_jeollabuk_jeongeup: '정읍시', location_jeollabuk_namwon: '남원시', location_jeollabuk_gimje_si: '김제시', location_jeollabuk_wanju: '완주군', location_jeollabuk_jinan: '진안군', location_jeollabuk_muju: '무주군', location_jeollabuk_jangsu: '장수군', location_jeollabuk_imsil: '임실군', location_jeollabuk_sunchang: '순창군', location_jeollabuk_gochang: '고창군', location_jeollabuk_buan: '부안군', location_jeollanam: '전남', location_jeollanam_mokpo: '목포시', location_jeollanam_yosu: '여수시', location_jeollanam_suncheon_si: '순천시', location_jeollanam_naju: '나주시', location_jeollanam_gwangyang_si: '광양시', location_jeollanam_damyang: '담양군', location_jeollanam_gokseong: '곡성군', location_jeollanam_gurye: '구례군', location_jeollanam_goheung: '고흥군', location_jeollanam_boseong: '보성군', location_jeollanam_hwasun: '화순군', location_jeollanam_jangheung: '장흥군', location_jeollanam_gangjin: '강진군', location_jeollanam_haenam: '해남군', location_jeollanam_yeongam: '영암군', location_jeollanam_jindo: '무안군', location_jeollanam_muan: '함평군', location_jeollanam_hampyeong: '영광군', location_jeollanam_yeonggwang: '장성군', location_jeollanam_jangseong: '완도군', location_jeollanam_wando: '진도군', location_jeollanam_sinan: '신안군', location_gyeongsangbuk: '경북', location_gyeongsangbuk_pohang_si: '포항시', location_gyeongsangbuk_gyeongju_si: '경주시', location_gyeongsangbuk_gimcheon_si: '김천시', location_gyeongsangbuk_andong_si: '안동시', location_gyeongsangbuk_gumi_si: '구미시', location_gyeongsangbuk_yeongju_si: '영주시', location_gyeongsangbuk_yeongcheon_si: '영천시', location_gyeongsangbuk_sangju_si: '상주시', location_gyeongsangbuk_mungyeong_si: '문경시', location_gyeongsangbuk_gyeongsan_si: '경산시', location_gyeongsangbuk_gunwi: '군위군', location_gyeongsangbuk_uiseong: '의성군', location_gyeongsangbuk_cheongsong: '청송군', location_gyeongsangbuk_goryong: '영양군', location_gyeongsangbuk_yeongdeok: '영덕군', location_gyeongsangbuk_cheongdo: '청도군', location_gyeongsangbuk_golyeong: '고령군', location_gyeongsangbuk_seongju: '성주군', location_gyeongsangbuk_chilgok: '칠곡군', location_gyeongsangbuk_yecheon: '예천군', location_gyeongsangbuk_bonghwa: '봉화군', location_gyeongsangbuk_uljin: '울진군', location_gyeongsangbuk_ulleung: '울릉군', location_gyeongsangnam: '경남', location_gyeongsangnam_changwon_si: '창원시', location_gyeongsangnam_jinju: '진주시', location_gyeongsangnam_tongyeong_si: '통영시', location_gyeongsangnam_sacheon_si: '사천시', location_gyeongsangnam_gimhae_si: '김해시', location_gyeongsangnam_miryang_si: '밀양시', location_gyeongsangnam_geoje_si: '거제시', location_gyeongsangnam_yangsan_si: '양산시', location_gyeongsangnam_uiryeong: '의령군', location_gyeongsangnam_haman: '함안군', location_gyeongsangnam_changnyeong: '창녕군', location_gyeongsangnam_goseong: '고성군', location_gyeongsangnam_namhae: '남해군', location_gyeongsangnam_hadong: '하동군', location_gyeongsangnam_sancheong: '산청군', location_gyeongsangnam_hamyang: '함양군', location_gyeongsangnam_geochang: '거창군', location_gyeongsangnam_hapcheon: '합천군', location_jeju: '제주', location_jeju_jeju_si: '제주시', location_jeju_seogwipo: '서귀포시', EXPANSION_WEATHER_sunny: '맑음', EXPANSION_WEATHER_partly_cloudy: '구름조금', EXPANSION_WEATHER_mostly_cloudy: '구름많음', EXPANSION_WEATHER_cloudy: '흐림', EXPANSION_WEATHER_rainy: '비', EXPANSION_WEATHER_sleet: '진눈깨비', EXPANSION_WEATHER_snowy: '눈', EXPANSION_WEATHER_finedust_good: '좋음', EXPANSION_WEATHER_finedust_normal: '보통', EXPANSION_WEATHER_finedust_bad: '나쁨', EXPANSION_WEATHER_finedust_very_bad: '매우나쁨', EXPANSION_WEATHER_lowest_temperature: '최저기온(℃)', EXPANSION_WEATHER_highest_temperature: '최고기온(℃)', EXPANSION_WEATHER_humidity: '습도(%)', EXPANSION_WEATHER_precipitation: '강수량(mm)', EXPANSION_WEATHER_precipitation_probability: '강수확률(%)', EXPANSION_WEATHER_wind_speed: '풍속(m/s)', EXPANSION_WEATHER_temperature: '기온(℃)', EXPANSION_WEATHER_finedust: '미세먼지농도(㎍)', EXPANSION_FESTIVAL_title: '제목', EXPANSION_FESTIVAL_area: '지역', EXPANSION_FESTIVAL_start_date: '시작일', EXPANSION_FESTIVAL_end_date: '종료일', EXPANSION_FESTIVAL_address: '주소', EXPANSION_FESTIVAL_coordinate: '위치', EXPANSION_FESTIVAL_overview: '개요', EXPANSION_FESTIVAL_homepage: '홈페이지', no_data: '정보없음', no_sentence: '문장이 없습니다', sentence_over_20_charactor: '20자까지만 입력할 수 있습니다.', sentence_over_3000_charactor: '3000자까지만 입력할 수 있습니다.', sentence_over_2500_charactor: '2500자까지만 입력할 수 있습니다. ', unknown_sentence: '알 수 없는 문장입니다.', auto: '자동', korean: '한국어', english: '영어', spanish: '스페인어', french: '프랑스어', german: '독일어', russian: '러시아어', portuguese: '포르투갈어', hindi: '힌디어', japan: '일본어', thai: '태국어', vietnamese: '베트남', indonesian: '인도네시아어', chinese_simplified: '중국어간체', chinese_traditional: '중국어번체', italian: '이탈리아어', behaviorConduct01001: '태풍', behaviorConduct01002: '홍수', behaviorConduct01003: '호우', behaviorConduct01004: '강풍', behaviorConduct01005: '대설', behaviorConduct01006: '한파', behaviorConduct01007: '풍랑', behaviorConduct01008: '황사', behaviorConduct01009: '폭염', behaviorConduct01010: '가뭄', behaviorConduct01011: '지진', behaviorConduct01013: '해일', behaviorConduct01014: '산사태', behaviorConduct03002: '응급처치', behaviorConduct03003: '심폐소생술', behaviorConduct03004: '소화기사용법', behaviorConduct03016: '소화전사용법', behaviorConduct03005: '식중독', behaviorConduct03006: '산행안전', behaviorConduct03008: '실종유괴', behaviorConduct03009: '성폭력', behaviorConduct03010: '학교 폭력', behaviorConduct03011: '가정 폭력', behaviorConduct03012: '억류 및 납치', behaviorConduct03013: '교통사고', behaviorConduct03014: '승강기 안전사고', behaviorConduct03015: '미세먼지', behaviorConduct01001001: '태풍이 오기 전', behaviorConduct01001002: '태풍이 왔을 때', behaviorConduct01001003: '태풍이 지나간 후', behaviorConduct01002002: '홍수가 오기 전', behaviorConduct01002003: '홍수가 났을 때', behaviorConduct01002004: '홍수가 지나간 후', behaviorConduct01003002: '큰 비가 오기 전', behaviorConduct01003003: '큰 비가 내릴 때', behaviorConduct01003004: '큰 비가 그친 후', behaviorConduct01004001: '강풍이 오기 전', behaviorConduct01004002: '강풍 발생 시', behaviorConduct01005002: '대설이 오기 전', behaviorConduct01005003: '대설 내일 때', behaviorConduct01005004: '눈이 그친 후', behaviorConduct01006001: '한파가 오기 전', behaviorConduct01006002: '한파 왔을 때', behaviorConduct01007001: '풍랑이 험할 때', behaviorConduct01007002: '풍랑이 오기 전', behaviorConduct01008001: '황사가 오기 전', behaviorConduct01008002: '황사가 왔을 때', behaviorConduct01008003: '황사가 지나간 후', behaviorConduct01009001: '폭염이 오기 전', behaviorConduct01009002: '폭염이 왔을 때', behaviorConduct01010001: '가뭄이 왔을 때', behaviorConduct01011009: '지진이 오기 전', behaviorConduct01011010: '지진이 왔을 때', behaviorConduct01011012: '지진 대피 후', behaviorConduct01013002: '해일이 오기 전', behaviorConduct01013003: '해일이 왔을 때', behaviorConduct01014001: '산사태가 오기 전', behaviorConduct03002002: '화상 처치', behaviorConduct03002003: '고열 예방', behaviorConduct03002004: '뱀에 물렸을 때 처치', behaviorConduct03002005: '벌에 쏘였을 때 처치', behaviorConduct03002006: '과호흡증후군 응급처치', behaviorConduct03003001: '성인 심폐소생술', behaviorConduct03003002: '영유아 심폐소생술', behaviorConduct03003003: '자동제세동기 사용', behaviorConduct03004001: '분말소화기 사용', behaviorConduct03016001: '옥내소화전 사용', behaviorConduct03005001: '식중독 대처', behaviorConduct03006004: '산행 중 유의사항', behaviorConduct03006005: '산에서 안전한 캠핑', behaviorConduct03006002: '구조요청시 알리는', behaviorConduct03006003: '산행사고시 응급조치', behaviorConduct03008001: '실종유괴 예방', behaviorConduct03009001: '성폭력 예방', behaviorConduct03010001: '학교 폭력 예방', behaviorConduct03011001: '가정 폭력 예방', behaviorConduct03012001: '억류 및 납치 시 대처', behaviorConduct03013002: '교통사고 발생 시 대처', behaviorConduct03013005: '차량에서의 구조', behaviorConduct03014001: '승강기 안전 이용', behaviorConduct03014003: '승강기 고장시 대처', behaviorConduct03014004: '에스컬레이터 안전 이용', behaviorConduct03015007: '미세먼지 많은 날 생활', behaviorConduct03015003: '부문별 생활', tts_female: '여성', tts_male: '남성', tts_kind: '친절한', tts_sweet: '감미로운', tts_echo: '울리는', tts_mischievous: '장난스러운', tts_dainty: '앙증맞은', tts_veryslow: '매우 느린', tts_slow: '느린', tts_normal: '보통', tts_fast: '빠른', tts_veryfast: '매우 빠른', tts_verylow: '매우 낮은', tts_low: '낮은', tts_high: '높은', tts_veryhigh: '매우 높은', ARDUINO: '하드웨어', ARDUINO_download_connector: '• 연결 프로그램 다운로드', ARDUINO_open_connector: '연결 프로그램 열기', ARDUINO_download_source: '• Entry Arduino code', ARDUINO_reconnect: 'Connect Hardware', arduino_noti_text: '모바일 기기는 추후 지원 합니다.', arduino_lite_reconnect: '하드웨어 다시 연결', arduino_lite_download_firmware: '펌웨어 다운로드', arduino_lite_download_driver: '드라이버 다운로드', arduino_lite_connect: '브라우저로 연결하기', arduino_lite_disconnect: '하드웨어 선택 취소', arduino_lite_guide: '• 아두이노 연결 가이드', ROBOT_reconnect: '로봇 연결하기', ARDUINO_program: '프로그램 실행하기', ARDUINO_cloud_pc_connector: '클라우드 PC 연결하기', ARDUINO_connected: 'Hardware connected', ARDUINO_connect: '* Connect hardware', ARDUINO_arduino_get_number_1: '신호', ARDUINO_arduino_get_number_2: '의 숫자 결괏값', ARDUINO_arduino_get_sensor_number_0: '0', ARDUINO_arduino_get_sensor_number_1: '1', ARDUINO_arduino_get_sensor_number_2: '2', ARDUINO_arduino_get_sensor_number_3: '3', ARDUINO_arduino_get_sensor_number_4: '4', ARDUINO_arduino_get_sensor_number_5: '5', blacksmith_toggle_on: '켜기', blacksmith_toggle_off: '끄기', blacksmith_lcd_first_line: '첫 번째', blacksmith_lcd_seconds_line: '두 번째', BITBRICK_light: 'light', BITBRICK_IR: 'IR', BITBRICK_touch: 'touch', BITBRICK_potentiometer: 'potentiometer', BITBRICK_MIC: 'MIC', BITBRICK_UserSensor: 'UserSensor', BITBRICK_UserInput: 'UserInput', BITBRICK_dc_direction_ccw: 'CCW', BITBRICK_dc_direction_cw: 'CW', chocopi_control_event_pressed: '누를 때', chocopi_control_event_released: '뗄 때', chocopi_joystick_X: '조이스틱 좌우', chocopi_joystick_Y: '조이스틱 상하', chocopi_motion_photogate_event_blocked: '막았을 때', chocopi_motion_photogate_event_unblocked: '열었을 때', chocopi_motion_photogate_time_blocked: '막은 시간', chocopi_motion_photogate_time_unblocked: '연 시간', chocopi_port: '포트', chocopi_pot: '볼륨', chocopi_touch_event_touch: '만질 때', chocopi_touch_event_untouch: '뗄 때', CODEino_get_sensor_number_0: '0', CODEino_get_sensor_number_1: '1', CODEino_get_sensor_number_2: '2', CODEino_get_sensor_number_3: '3', CODEino_get_sensor_number_4: '4', CODEino_get_sensor_number_5: '5', CODEino_get_sensor_number_6: '6', CODEino_sensor_name_0: 'Sound', CODEino_sensor_name_1: 'Light', CODEino_sensor_name_2: 'Slider', CODEino_sensor_name_3: 'resistance-A', CODEino_sensor_name_4: 'resistance-B', CODEino_sensor_name_5: 'resistance-C', CODEino_sensor_name_6: 'resistance-D', CODEino_string_1: ' Sensor value ', CODEino_string_2: ' Operation ', CODEino_string_3: 'Push button', CODEino_string_4: 'Connected A', CODEino_string_5: 'Connected B', CODEino_string_6: 'Connected C', CODEino_string_7: 'Connected D', CODEino_string_8: ' 3-AXIS Accelerometer ', CODEino_string_9: '-axis value ', CODEino_string_10: 'Sound is ', CODEino_string_11: 'Great', CODEino_string_12: 'Small', CODEino_string_13: 'Light is ', CODEino_string_14: 'Bright', CODEino_string_15: 'Dark', CODEino_string_16: 'Left tilt', CODEino_string_17: 'Right tilt', CODEino_string_18: 'Front tilt', CODEino_string_19: 'Rear tilt', CODEino_string_20: 'Reverse', CODEino_accelerometer_X: 'X', CODEino_accelerometer_Y: 'Y', CODEino_accelerometer_Z: 'Z', CODEino_led_red: '빨강', CODEino_led_green: '초록', CODEino_led_blue: '파랑', iboard_analog_number_0: 'A0', iboard_analog_number_1: 'A1', iboard_analog_number_2: 'A2', iboard_analog_number_3: 'A3', iboard_analog_number_4: 'A4', iboard_analog_number_5: 'A5', iboard_light: '빛센서가 ', iboard_num_pin_1: 'LED 상태를', iboard_num_pin_2: '번 스위치가', iboard_num_pin_3: '아날로그', iboard_num_pin_4: '번 ', iboard_num_pin_5: '센서값', iboard_string_1: '켜짐', iboard_string_2: '꺼짐', iboard_string_3: '밝음', iboard_string_4: '어두움', iboard_string_5: '눌림', iboard_string_6: '열림', iboard_switch: '스위치 ', iboard_tilt: '기울기센서 상태가', dplay_switch: '스위치 ', dplay_light: '빛센서가 ', dplay_tilt: '기울기센서 상태가', dplay_string_1: '켜짐', dplay_string_2: '꺼짐', dplay_string_3: '밝음', dplay_string_4: '어두움', dplay_string_5: '눌림', dplay_string_6: '열림', dplay_num_pin_1: 'LED 상태를', dplay_num_pin_2: '번 스위치가', dplay_num_pin_3: '아날로그', dplay_num_pin_4: '번 ', dplay_num_pin_5: '센서값', dplay_analog_number_0: 'A0', dplay_analog_number_1: 'A1', dplay_analog_number_2: 'A2', dplay_analog_number_3: 'A3', dplay_analog_number_4: 'A4', dplay_analog_number_5: 'A5', ARDUINO_arduino_get_string_1: '신호', ARDUINO_arduino_get_string_2: '의 글자 결괏값', ARDUINO_arduino_send_1: '신호', ARDUINO_arduino_send_2: '보내기', ARDUINO_num_sensor_value_1: '아날로그', ARDUINO_num_sensor_value_2: '번 센서값', ARDUINO_get_digital_value_1: '디지털', ARDUINO_num_pin_1: 'Digital', ARDUINO_num_pin_2: 'Pin', ARDUINO_toggle_pwm_1: 'Digital', ARDUINO_toggle_pwm_2: 'Pin', ARDUINO_toggle_pwm_3: '', ARDUINO_on: 'On', ARDUINO_convert_scale_1: 'Map Value', ARDUINO_convert_scale_2: '', ARDUINO_convert_scale_3: '~', ARDUINO_convert_scale_4: 'to', ARDUINO_convert_scale_5: '~', ARDUINO_convert_scale_6: '', ARDUINO_off: 'Off', EXPANSION: '확장', brightness: '밝기', BRUSH: '붓', BRUSH_brush_erase_all: 'this.brush.removeAll()', BRUSH_change_opacity_1: 'this.brush.opacity +=', BRUSH_change_opacity_2: '', BRUSH_change_thickness_1: 'this.brush.thickness +=', BRUSH_change_thickness_2: '', BRUSH_set_color_1: 'this.brush.color =', BRUSH_set_color_2: '', BRUSH_set_opacity_1: 'this.brush.opacity =', BRUSH_set_opacity_2: '', BRUSH_set_random_color: 'this.brush.color = Entry.getRandomColor()', BRUSH_set_thickness_1: 'this.brush.thickness =', BRUSH_set_thickness_2: '', BRUSH_stamp: 'Stamp', BRUSH_start_drawing: 'this.startDraw()', BRUSH_stop_drawing: 'this.stopDraw()', CALC: '계산', CALC_calc_mod_1: 'Entry.getMod(', CALC_calc_mod_2: ',', CALC_calc_mod_3: ')', CALC_calc_operation_of_1: 'Entry.calculate(', CALC_calc_operation_of_2: ',', CALC_calc_operation_root: '루트', CALC_calc_operation_square: '제곱', CALC_calc_rand_1: 'Entry.getRandomNumber(', CALC_calc_rand_2: ',', CALC_calc_rand_3: ')', CALC_calc_share_1: 'Entry.getShare(', CALC_calc_share_2: ',', CALC_calc_share_3: ')', CALC_coordinate_mouse_1: 'Entry.getMousePosition(', CALC_coordinate_mouse_2: ')', CALC_coordinate_object_1: 'Entry.getPosition(', CALC_coordinate_object_2: ',', CALC_coordinate_object_3: ')', CALC_distance_something_1: 'Entry.getDistance(this,', CALC_distance_something_2: ')', CALC_get_angle: '각도값', CALC_get_date_1: 'Entry.getDate(', CALC_get_date_2: ')', CALC_get_date_day: '일', CALC_get_date_hour: '시각(시)', CALC_get_date_minute: '시각(분)', CALC_get_date_month: '월', CALC_get_date_second: '시각(초)', CALC_get_date_year: '연도', CALC_get_sound_duration_1: 'Entry.getSoundDuration(', CALC_get_sound_duration_2: ')', CALC_get_timer_value: 'Entry.getTimerValue()', CALC_get_x_coordinate: 'this.x', CALC_get_y_coordinate: 'this.y', CALC_timer_reset: 'Entry.resetTimer()', CALC_timer_visible_1: 'Entry.timerVisible(', CALC_timer_visible_2: ')', CALC_timer_visible_show: 'Show', CALC_timer_visible_hide: 'Hide', color: '색깔', FLOW: '흐름', FLOW__if_1: 'if (', FLOW__if_2: ')', FLOW_create_clone_1: 'Entry.createClone(', FLOW_create_clone_2: ')', FLOW_delete_clone: 'Entry.removeClone(this)', FLOW_delete_clone_all: 'Entry.removeAllClone()', FLOW_if_else_1: 'if (', FLOW_if_else_2: ')', FLOW_if_else_3: 'else', FLOW_repeat_basic_1: 'for ( i = 0', FLOW_repeat_basic_2: ')', FLOW_repeat_basic_errorMsg: '', FLOW_repeat_inf: 'while(true)', FLOW_restart: 'Entry.restart()', FLOW_stop_object_1: 'Entry.stop(', FLOW_stop_object_2: ')', FLOW_stop_object_all: '모두', FLOW_stop_object_this_object: 'this.', FLOW_stop_object_this_thread: '이', FLOW_stop_object_other_thread: '자신의 다른', FLOW_stop_object_other_objects: '다른 오브젝트의', FLOW_stop_repeat: 'break', FLOW_stop_run: '프로그램 끝내기', FLOW_wait_second_1: 'Entry.wait(', FLOW_wait_second_2: ')', FLOW_wait_until_true_1: 'while (', FLOW_wait_until_true_2: '!= true) { }', FLOW_when_clone_start: "Entry.addEventListener('clone_created')", FUNC: '함수', ANALYSIS: '데이터분석', AI: '인공지능', JUDGEMENT: '판단', JUDGEMENT_boolean_and: '&&', JUDGEMENT_boolean_not_1: 'if (!', JUDGEMENT_boolean_not_2: ')', JUDGEMENT_boolean_or: '||', JUDGEMENT_false: 'false', JUDGEMENT_is_clicked: "Entry.addEventListener('mouse_clicked')", JUDGEMENT_is_press_some_key_1: 'Entry.isKeyPressed(', JUDGEMENT_is_press_some_key_2: ')', JUDGEMENT_reach_something_1: 'Entry.isCollide(this,', JUDGEMENT_reach_something_2: ')', JUDGEMENT_true: 'true', LOOKS: '생김새', LOOKS_change_scale_percent_1: 'this.scale +=', LOOKS_change_scale_percent_2: '', LOOKS_change_to_next_shape: 'this.setToNextShape()', LOOKS_change_to_nth_shape_1: 'this.setShape(', LOOKS_change_to_nth_shape_2: ')', LOOKS_change_shape_prev: 'Prev', LOOKS_change_shape_next: 'Next', LOOKS_change_to_near_shape_1: 'this.setTo', LOOKS_change_to_near_shape_2: 'Shape()', LOOKS_dialog_1: 'this.setDialog(', LOOKS_dialog_2: ',', LOOKS_dialog_3: ')', LOOKS_dialog_time_1: 'this.setDialogByTime(', LOOKS_dialog_time_2: ',', LOOKS_dialog_time_3: ',', LOOKS_dialog_time_4: ')', LOOKS_erase_all_effects: 'this.removeAllEffects()', LOOKS_flip_x: "this.flip('vertical')", LOOKS_flip_y: "this.flip('horizontal')", LOOKS_hide: 'this.hide()', LOOKS_remove_dialog: 'this.removeDialog()', LOOKS_set_effect_1: 'this.setEffect(', LOOKS_set_effect_2: ',', LOOKS_set_effect_3: ')', LOOKS_set_effect_volume_1: 'this.addEffect(', LOOKS_set_effect_volume_2: ',', LOOKS_set_effect_volume_3: ')', LOOKS_set_object_order_1: 'Entry.setLayerOrder(this,', LOOKS_set_object_order_2: ')', LOOKS_set_scale_percent_1: 'this.scale =', LOOKS_set_scale_percent_2: '', LOOKS_show: 'this.show()', mouse_pointer: '마우스포인터', MOVING: '움직임', MOVING_bounce_wall: 'Entry.bounceWall(this)', MOVING_bounce_when_1: '', MOVING_bounce_when_2: '에 닿으면 튕기기', MOVING_flip_arrow_horizontal: '화살표 방향 좌우 뒤집기', MOVING_flip_arrow_vertical: '화살표 방향 상하 뒤집기', MOVING_locate_1: 'this.locateAt(', MOVING_locate_2: ')', MOVING_locate_time_1: '', MOVING_locate_time_2: '초 동안', MOVING_locate_time_3: '위치로 이동하기', MOVING_locate_x_1: 'this.x =', MOVING_locate_x_2: '', MOVING_locate_xy_1: 'this.setXY(', MOVING_locate_xy_2: ',', MOVING_locate_xy_3: ')', MOVING_locate_xy_time_1: 'this.setXYbyTime(', MOVING_locate_xy_time_2: ',', MOVING_locate_xy_time_3: ',', MOVING_locate_xy_time_4: ')', MOVING_locate_y_1: 'this.y =', MOVING_locate_y_2: '', MOVING_move_direction_1: 'Entry.moveToDirection(', MOVING_move_direction_2: ')', MOVING_move_direction_angle_1: 'Entry.moveToDirection(', MOVING_move_direction_angle_2: ',', MOVING_move_direction_angle_3: ')', MOVING_move_x_1: 'this.x +=', MOVING_move_x_2: '', MOVING_move_xy_time_1: 'this.moveXYbyTime(', MOVING_move_xy_time_2: ',', MOVING_move_xy_time_3: ',', MOVING_move_xy_time_4: ')', MOVING_move_y_1: 'this.y +=', MOVING_move_y_2: '', MOVING_rotate_by_angle_1: 'this.rotation +=', MOVING_rotate_by_angle_2: '', MOVING_rotate_by_angle_dropdown_1: '', MOVING_rotate_by_angle_dropdown_2: '만큼 회전하기', MOVING_rotate_by_angle_time_1: 'this.rotateByTime(', MOVING_rotate_by_angle_time_2: ',', MOVING_rotate_by_angle_time_3: ')', MOVING_rotate_direction_1: 'this.direction +=', MOVING_rotate_direction_2: '', MOVING_see_angle_1: 'this.direction =', MOVING_see_angle_2: '', MOVING_see_angle_direction_1: 'this.rotation =', MOVING_see_angle_direction_2: '', MOVING_see_angle_object_1: 'this.setDirectionTo(', MOVING_see_angle_object_2: ')', MOVING_see_direction_1: '', MOVING_see_direction_2: '쪽 보기', MOVING_set_direction_by_angle_1: 'this.rotation =', MOVING_set_direction_by_angle_2: '', MOVING_add_direction_by_angle_1: 'this.rotation =', MOVING_add_direction_by_angle_2: '', MOVING_add_direction_by_angle_time_1: 'this.rotate(', MOVING_add_direction_by_angle_time_2: ',', MOVING_add_direction_by_angle_time_3: ')', no_target: '대상 없음', oneself: '자신', opacity: '투명도', SCENE: '장면', SOUND: '소리', SOUND_sound_silent_all: 'Entry.silentAll()', SOUND_sound_something_1: 'Entry.playSound(', SOUND_sound_something_2: ')', SOUND_sound_something_second_1: 'Entry.playSoundByTime(', SOUND_sound_something_second_2: ',', SOUND_sound_something_second_3: ')', SOUND_sound_something_second_wait_1: 'Entry.playSoundAndWaitByTime(', SOUND_sound_something_second_wait_2: ',', SOUND_sound_something_second_wait_3: ')', SOUND_sound_something_wait_1: 'Entry.playSoundAndWait(', SOUND_sound_something_wait_2: ')', SOUND_sound_volume_change_1: 'Entry.volume +=', SOUND_sound_volume_change_2: '', SOUND_sound_volume_set_1: 'Entry.volume =', SOUND_sound_volume_set_2: '', speak: '말하기', think: '생각하기', START: '시작', START_add_message: '신호 추가하기', START_delete_message: '신호 삭제하기', START_message_cast: '신호 보내기', START_message_cast_1: 'Entry.dispatchEvent(', START_message_cast_2: ')', START_message_cast_wait: ')', START_message_send_wait_1: 'Entry.dispatchEventAndWait(', START_message_send_wait_2: ')', START_mouse_click_cancled: "Entry.addEventListener('mouseup')", START_mouse_clicked: "Entry.addEventListener('mousedown')", START_press_some_key_1: "Entry.addEventListener('keydown', key==", START_press_some_key_2: ')', START_press_some_key_down: '아래쪽 화살표', START_press_some_key_enter: '엔터', START_press_some_key_left: '왼쪽 화살표', START_press_some_key_right: '오른쪽 화살표', START_press_some_key_space: '스페이스', START_press_some_key_up: '위쪽 화살표', START_when_message_cast: '신호를 받았을 때', START_when_message_cast_1: 'Entry.addEventListener(', START_when_message_cast_2: ')', START_when_object_click: "this.addEventListener('mousedown')", START_when_object_click_canceled: "this.addEventListener('mouseup')", START_when_run_button_click: "Entry.addEventListener('run')", START_when_scene_start: '장면이 시작했을때', START_when_some_key_click: '키를 눌렀을 때', TEXT: '글상자', TEXT_text: 'Entry', TEXT_text_append_1: 'Entry.appendText(', TEXT_text_append_2: ')', TEXT_text_flush: 'Entry.clearText()', TEXT_text_prepend_1: 'Entry.insertText(', TEXT_text_prepend_2: ')', TEXT_text_write_1: 'Entry.writeText(', TEXT_text_write_2: ')', VARIABLE: '자료', VARIABLE_add_value_to_list: '항목을 리스트에 추가하기', VARIABLE_add_value_to_list_1: 'Entry.pushValueToList(', VARIABLE_add_value_to_list_2: ',', VARIABLE_add_value_to_list_3: ')', VARIABLE_ask_and_wait_1: 'Entry.askAndWait(', VARIABLE_ask_and_wait_2: ')', VARIABLE_change_value_list_index: '항목을 바꾸기', VARIABLE_change_value_list_index_1: 'Entry.changeValueListAt(', VARIABLE_change_value_list_index_3: ',', VARIABLE_change_value_list_index_2: ',', VARIABLE_change_value_list_index_4: ')', VARIABLE_change_variable: '변수 더하기', VARIABLE_change_variable_1: 'Entry.addValueToVariable(', VARIABLE_change_variable_2: ',', VARIABLE_change_variable_3: ')', VARIABLE_change_variable_name: '변수 이름 바꾸기', VARIABLE_combine_something_1: 'Entry.concat(', VARIABLE_combine_something_2: ',', VARIABLE_combine_something_3: ')', VARIABLE_get_canvas_input_value: 'Entry.getAnswer()', VARIABLE_get_variable: '변수값', VARIABLE_get_variable_1: 'Entry.getVariableValue(', VARIABLE_get_variable_2: ')', VARIABLE_get_y: 'Y 좌푯값', VARIABLE_hide_list: '리스트 숨기기', VARIABLE_hide_list_1: 'Entry.hideList(', VARIABLE_hide_list_2: ')', VARIABLE_hide_variable: '변수값 숨기기', VARIABLE_hide_variable_1: 'Entry.hideVariable(', VARIABLE_hide_variable_2: ')', VARIABLE_insert_value_to_list: '항목을 넣기', VARIABLE_insert_value_to_list_1: 'Entry.pushValueToListAt(', VARIABLE_insert_value_to_list_2: ',', VARIABLE_insert_value_to_list_3: ',', VARIABLE_insert_value_to_list_4: ')', VARIABLE_length_of_list: '리스트의 길이', VARIABLE_length_of_list_1: 'Entry.getLength(', VARIABLE_length_of_list_2: ')', VARIABLE_list: '리스트', VARIABLE_make_variable: '변수 만들기', VARIABLE_list_option_first: 'FIRST', VARIABLE_list_option_last: 'LAST', VARIABLE_list_option_random: 'RANDOM', VARIABLE_remove_value_from_list: '항목을 삭제하기', VARIABLE_remove_value_from_list_1: 'Entry.removeValueListAt(', VARIABLE_remove_value_from_list_2: ',', VARIABLE_remove_value_from_list_3: ')', VARIABLE_remove_variable: '변수 삭제', VARIABLE_set_variable: '변수 정하기', VARIABLE_set_variable_1: 'Entry.setValueVariable(', VARIABLE_set_variable_2: ',', VARIABLE_set_variable_3: ')', VARIABLE_show_list: '리스트 보이기', VARIABLE_show_list_1: 'Entry.showList(', VARIABLE_show_list_2: ')', VARIABLE_show_variable: '변수값 보이기', VARIABLE_show_variable_1: 'Entry.showVariable(', VARIABLE_show_variable_2: ')', VARIABLE_value_of_index_from_list: '리스트 항목의 값', VARIABLE_value_of_index_from_list_1: 'Entry.getListValueAt(', VARIABLE_value_of_index_from_list_2: ',', VARIABLE_value_of_index_from_list_3: ')', HAMSTER_hand_found: 'Entry.Hamster.isHandFound()', HAMSTER_sensor_left_proximity: 'Entry.Hamster.getLeftProximity()', HAMSTER_sensor_right_proximity: 'Entry.Hamster.getRightProximity()', HAMSTER_sensor_left_floor: 'Entry.Hamster.getLeftFloor()', HAMSTER_sensor_right_floor: 'Entry.Hamster.getRightFloor()', HAMSTER_sensor_acceleration_x: 'Entry.Hamster.getAccelerationX()', HAMSTER_sensor_acceleration_y: 'Entry.Hamster.getAccelerationY()', HAMSTER_sensor_acceleration_z: 'Entry.Hamster..getAccelerationZ()', HAMSTER_sensor_light: 'Entry.Hamster.getLight()', HAMSTER_sensor_temperature: 'Entry.Hamster.getTemperature()', HAMSTER_sensor_signal_strength: 'Entry.Hamster.getSignalStrength()', HAMSTER_sensor_input_a: 'Entry.Hamster.getInputA()', HAMSTER_sensor_input_b: 'Entry.Hamster.getInputB()', HAMSTER_move_forward_once: 'Entry.Hamster.moveForwardOnceOnBoard()', HAMSTER_turn_once_1: "Entry.Hamster.turnOnceOnBoard('", HAMSTER_turn_once_2: "')", HAMSTER_turn_once_left: 'left', HAMSTER_turn_right: 'right', HAMSTER_move_forward: 'move forward', HAMSTER_move_backward: 'move backward', HAMSTER_turn_around_1: 'turn', HAMSTER_turn_around_2: '', HAMSTER_move_forward_for_secs_1: 'move forward for', HAMSTER_move_forward_for_secs_2: 'secs', HAMSTER_move_backward_for_secs_1: 'move backward', HAMSTER_move_backward_for_secs_2: 'secs', HAMSTER_turn_for_secs_1: 'turn', HAMSTER_turn_for_secs_2: 'for', HAMSTER_turn_for_secs_3: 'secs', HAMSTER_change_both_wheels_by_1: 'change wheel by left:', HAMSTER_change_both_wheels_by_2: 'right:', HAMSTER_change_both_wheels_by_3: '', HAMSTER_set_both_wheels_to_1: 'set wheel to left:', HAMSTER_set_both_wheels_to_2: 'right:', HAMSTER_set_both_wheels_to_3: ')', HAMSTER_change_wheel_by_1: "Entry.Hamster.changeWheelsBy('", HAMSTER_change_wheel_by_2: "',", HAMSTER_change_wheel_by_3: ')', HAMSTER_left_wheel: 'left', HAMSTER_right_wheel: 'right', HAMSTER_both_wheels: 'both', HAMSTER_set_wheel_to_1: "Entry.Hamster.setWheelsTo('", HAMSTER_set_wheel_to_2: "',", HAMSTER_set_wheel_to_3: ')', HAMSTER_follow_line_using_1: "Entry.Hamster.followLineUsingFloorSensor('", HAMSTER_follow_line_using_2: "','", HAMSTER_follow_line_using_3: "')", HAMSTER_left_floor_sensor: 'left', HAMSTER_right_floor_sensor: 'right', HAMSTER_both_floor_sensors: 'both', HAMSTER_follow_line_until_1: "Entry.Hamster.followLineUntilIntersection('", HAMSTER_follow_line_until_2: "','", HAMSTER_follow_line_until_3: "')", HAMSTER_left_intersection: 'left', HAMSTER_right_intersection: 'right', HAMSTER_front_intersection: 'front', HAMSTER_rear_intersection: 'rear', HAMSTER_set_following_speed_to_1: 'Entry.Hamster.setFollowingSpeedTo(', HAMSTER_set_following_speed_to_2: ')', HAMSTER_front: 'front', HAMSTER_rear: 'rear', HAMSTER_stop: 'stop', HAMSTER_set_led_to_1: "Entry.Hamster.setLedTo('", HAMSTER_set_led_to_2: "','", HAMSTER_set_led_to_3: "')", HAMSTER_left_led: 'left', HAMSTER_right_led: 'right', HAMSTER_both_leds: 'both', HAMSTER_clear_led_1: "Entry.Hamster.clearLed('", HAMSTER_clear_led_2: "')", HAMSTER_color_cyan: 'sky blue', HAMSTER_color_magenta: 'purple', HAMSTER_color_black: 'black', HAMSTER_color_white: 'white', HAMSTER_color_red: 'red', HAMSTER_color_yellow: 'yellow', HAMSTER_color_green: 'green', HAMSTER_color_blue: 'blue', HAMSTER_beep: 'Entry.Hamster.beep()', HAMSTER_change_buzzer_by_1: 'change buzzer by', HAMSTER_change_buzzer_by_2: '', HAMSTER_set_buzzer_to_1: 'set buzzer to', HAMSTER_set_buzzer_to_2: '', HAMSTER_clear_buzzer: 'clear buzzer', HAMSTER_play_note_for_1: "Entry.Hamster.playNoteForBeats('", HAMSTER_play_note_for_2: "',", HAMSTER_play_note_for_3: ',', HAMSTER_play_note_for_4: ')', HAMSTER_rest_for_1: 'Entry.Hamster.restForBeats(', HAMSTER_rest_for_2: ')', HAMSTER_change_tempo_by_1: 'Entry.Hamster.changeTempoBy(', HAMSTER_change_tempo_by_2: ')', HAMSTER_set_tempo_to_1: 'Entry.Hamster.setTempoTo(', HAMSTER_set_tempo_to_2: ')', HAMSTER_set_port_to_1: "Entry.Hamster.setPortTo('", HAMSTER_set_port_to_2: "','", HAMSTER_set_port_to_3: "')", HAMSTER_change_output_by_1: "Entry.Hamster.changeOutputBy('", HAMSTER_change_output_by_2: "',", HAMSTER_change_output_by_3: ')', HAMSTER_set_output_to_1: "Entry.Hamster.setOutputTo('", HAMSTER_set_output_to_2: "',", HAMSTER_set_output_to_3: ')', HAMSTER_port_a: 'A', HAMSTER_port_b: 'B', HAMSTER_port_ab: 'AB', HAMSTER_analog_input: 'AnalogInput', HAMSTER_digital_input: 'DigitalInput', HAMSTER_servo_output: 'ServoOutput', HAMSTER_pwm_output: 'PwmOutput', HAMSTER_digital_output: 'DigitalOutput', ROBOID_acceleration_x: 'x축 가속도', ROBOID_acceleration_y: 'y축 가속도', ROBOID_acceleration_z: 'z축 가속도', ROBOID_back: '뒤쪽', ROBOID_both: '양쪽', ROBOID_button: '버튼', ROBOID_buzzer: '버저', ROBOID_clicked: '클릭했는가', ROBOID_color_any: '아무 색', ROBOID_color_black: '검은색', ROBOID_color_blue: '파란색', ROBOID_color_green: '초록색', ROBOID_color_number: '색깔 번호', ROBOID_color_orange: '주황색', ROBOID_color_pattern: '색깔 패턴', ROBOID_color_purple: '자주색', ROBOID_color_red: '빨간색', ROBOID_color_sky_blue: '하늘색', ROBOID_color_violet: '보라색', ROBOID_color_white: '하얀색', ROBOID_color_yellow: '노란색', ROBOID_double_clicked: '더블클릭했는가', ROBOID_floor: '바닥 센서', ROBOID_head: '머리', ROBOID_head_color: '머리 색깔', ROBOID_left: '왼쪽', ROBOID_left_wheel: '왼쪽 바퀴', ROBOID_long_pressed: '길게~눌렀는가', ROBOID_note: '음표', ROBOID_right: '오른쪽', ROBOID_right_wheel: '오른쪽 바퀴', ROBOID_sound_beep: '삐', ROBOID_sound_birthday: '생일', ROBOID_sound_dibidibidip: '디비디비딥', ROBOID_sound_engine: '엔진', ROBOID_sound_good_job: '잘 했어요', ROBOID_sound_march: '행진', ROBOID_sound_random_beep: '무작위 삐', ROBOID_sound_robot: '로봇', ROBOID_sound_siren: '사이렌', ROBOID_tail: '꼬리', ROBOID_unit_cm: 'cm', ROBOID_unit_deg: '도', ROBOID_unit_pulse: '펄스', ROBOID_unit_sec: '초', ALBERT_hand_found: 'Entry.Albert.isHandFound()', ALBERT_is_oid_1: "Entry.Albert.isOidValue('", ALBERT_is_oid_2: "',", ALBERT_is_oid_3: ')', ALBERT_front_oid: 'front', ALBERT_back_oid: 'back', ALBERT_sensor_left_proximity: 'Entry.Albert.getLeftProximity()', ALBERT_sensor_right_proximity: 'Entry.Albert.getRightProximity()', ALBERT_sensor_acceleration_x: 'Entry.Albert.getAccelerationX()', ALBERT_sensor_acceleration_y: 'Entry.Albert.getAccelerationY()', ALBERT_sensor_acceleration_z: 'Entry.Albert.getAccelerationZ()', ALBERT_sensor_light: 'Entry.Albert.getLight()', ALBERT_sensor_temperature: 'Entry.Albert.getTemperature()', ALBERT_sensor_battery: 'Entry.Albert.getBattery()', ALBERT_sensor_signal_strength: 'Entry.Albert.getSignalStrength()', ALBERT_sensor_front_oid: 'Entry.Albert.getFrontOid()', ALBERT_sensor_back_oid: 'Entry.Albert.getBackOid()', ALBERT_sensor_position_x: 'Entry.Albert.getPositionX()', ALBERT_sensor_position_y: 'Entry.Albert.getPositionY()', ALBERT_sensor_orientation: 'Entry.Albert.getOrientation()', ALBERT_move_forward: 'Entry.Albert.moveForward()', ALBERT_move_backward: 'Entry.Albert.moveBackward()', ALBERT_turn_around_1: "Entry.Albert.turn('", ALBERT_turn_around_2: "')", ALBERT_move_forward_for_secs_1: 'Entry.Albert.moveForwardForSecs(', ALBERT_move_forward_for_secs_2: ')', ALBERT_move_backward_for_secs_1: 'Entry.Albert.moveBackwardForSecs(', ALBERT_move_backward_for_secs_2: ')', ALBERT_turn_for_secs_1: "Entry.Albert.turnForSecs('", ALBERT_turn_for_secs_2: "',", ALBERT_turn_for_secs_3: ')', ALBERT_turn_left: 'left', ALBERT_turn_right: 'right', ALBERT_change_both_wheels_by_1: 'Entry.Albert.changeWheelsBy(', ALBERT_change_both_wheels_by_2: ',', ALBERT_change_both_wheels_by_3: ')', ALBERT_left_wheel: 'left', ALBERT_right_wheel: 'right', ALBERT_both_wheels: 'both', ALBERT_set_both_wheels_to_1: 'Entry.Albert.setWheelsTo(', ALBERT_set_both_wheels_to_2: ',', ALBERT_set_both_wheels_to_3: ')', ALBERT_change_wheel_by_1: "Entry.Albert.changeWheelsBy('", ALBERT_change_wheel_by_2: "',", ALBERT_change_wheel_by_3: ')', ALBERT_set_wheel_to_1: "Entry.Albert.setWheelsTo('", ALBERT_set_wheel_to_2: "',", ALBERT_set_wheel_to_3: ')', ALBERT_stop: 'Entry.Albert.stop()', ALBERT_set_board_size_to_1: 'Entry.Albert.setBoardSizeTo(', ALBERT_set_board_size_to_2: ',', ALBERT_set_board_size_to_3: ')', ALBERT_move_to_x_y_1: 'Entry.Albert.moveToOnBoard(', ALBERT_move_to_x_y_2: ',', ALBERT_move_to_x_y_3: ')', ALBERT_set_orientation_to_1: 'Entry.Albert.setOrientationToOnBoard(', ALBERT_set_orientation_to_2: ')', ALBERT_set_eye_to_1: "Entry.Albert.setEyeTo('", ALBERT_set_eye_to_2: "','", ALBERT_set_eye_to_3: "')", ALBERT_left_eye: 'left', ALBERT_right_eye: 'right', ALBERT_both_eyes: 'both', ALBERT_clear_eye_1: "Entry.Albert.clearEye('", ALBERT_clear_eye_2: "')", ALBERT_body_led_1: '', ALBERT_body_led_2: 'body led', ALBERT_front_led_1: '', ALBERT_front_led_2: 'front led', ALBERT_color_cyan: 'cyan', ALBERT_color_magenta: 'magenta', ALBERT_color_white: 'white', ALBERT_color_red: 'red', ALBERT_color_yellow: 'yellow', ALBERT_color_green: 'green', ALBERT_color_blue: 'blue', ALBERT_note_c: 'C', ALBERT_note_d: 'D', ALBERT_note_e: 'E', ALBERT_note_f: 'F', ALBERT_note_g: 'G', ALBERT_note_a: 'A', ALBERT_note_b: 'B', ALBERT_turn_body_led_1: "Entry.Albert.turnBodyLed('", ALBERT_turn_body_led_2: "')", ALBERT_turn_front_led_1: "Entry.Albert.turnFrontLed('", ALBERT_turn_front_led_2: "')'", ALBERT_turn_on: 'on', ALBERT_turn_off: 'off', ALBERT_beep: 'Entry.Albert.beep()', ALBERT_change_buzzer_by_1: 'Entry.Albert.changeBuzzerBy(', ALBERT_change_buzzer_by_2: ')', ALBERT_set_buzzer_to_1: 'Entry.Albert.setBuzzerTo(', ALBERT_set_buzzer_to_2: ')', ALBERT_clear_buzzer: 'Entry.Albert.clearBuzzer()', ALBERT_play_note_for_1: "Entry.Albert.playNoteForBeats('", ALBERT_play_note_for_2: "',", ALBERT_play_note_for_3: ',', ALBERT_play_note_for_4: ')', ALBERT_rest_for_1: 'Entry.Albert.restForBeats(', ALBERT_rest_for_2: ')', ALBERT_change_tempo_by_1: 'Entry.Albert.changeTempoBy(', ALBERT_change_tempo_by_2: ')', ALBERT_set_tempo_to_1: 'Entry.Albert.setTempoTo(', ALBERT_set_tempo_to_2: ')', VARIABLE_variable: '변수', wall: '벽', robotis_common_case_01: '(을)를', robotis_common_set: '(으)로 정하기', robotis_common_value: '값', robotis_common_clockwhise: '시계방향', robotis_common_counter_clockwhise: '반시계방향', robotis_common_wheel_mode: '회전모드', robotis_common_joint_mode: '관절모드', robotis_common_red_color: '빨간색', robotis_common_green_color: '녹색', robotis_common_blue_color: '파란색', robotis_common_on: '켜기', robotis_common_off: '끄기', robotis_common_cm: '제어기', robotis_common_port_1: '포트 1', robotis_common_port_2: '포트 2', robotis_common_port_3: '포트 3', robotis_common_port_4: '포트 4', robotis_common_port_5: '포트 5', robotis_common_port_6: '포트 6', robotis_common_play_buzzer: '연주', robotis_common_play_motion: '실행', robotis_common_motion: '모션', robotis_common_index_number: '번', robotis_common_left: '왼쪽', robotis_common_right: '오른쪽', robotis_common_minute: '분', robotis_cm_custom: '직접입력 주소', robotis_cm_spring_left: '왼쪽 접촉 센서', robotis_cm_spring_right: '오른쪽 접촉 센서', robotis_cm_led_left: '왼쪽 LED', robotis_cm_led_right: '오른쪽 LED', robotis_cm_led_both: '양 쪽 LED', robotis_cm_switch: '선택 버튼 상태', robotis_cm_user_button: '사용자 버튼 상태', robotis_cm_sound_detected: '최종 소리 감지 횟수', robotis_cm_sound_detecting: '실시간 소리 감지 횟수', robotis_cm_ir_left: '왼쪽 적외선 센서', robotis_cm_ir_right: '오른쪽 적외선 센서', robotis_cm_calibration_left: '왼쪽 적외선 센서 캘리브레이션 값', robotis_cm_calibration_right: '오른쪽 적외선 센서 캘리브레이션 값', robotis_cm_clear_sound_detected: '최종소리감지횟수 초기화', robotis_cm_buzzer_index: '음계값', robotis_cm_buzzer_melody: '멜로디', robotis_cm_led_1: '1번 LED', robotis_cm_led_4: '4번 LED', robotis_aux_servo_position: '서보모터 위치', robotis_aux_ir: '적외선센서', robotis_aux_touch: '접촉센서', robotis_aux_brightness: '조도센서(CDS)', robotis_aux_hydro_themo_humidity: '온습도센서(습도)', robotis_aux_hydro_themo_temper: '온습도센서(온도)', robotis_aux_temperature: '온도센서', robotis_aux_ultrasonic: '초음파센서', robotis_aux_magnetic: '자석센서', robotis_aux_motion_detection: '동작감지센서', robotis_aux_color: '컬러센서', robotis_aux_custom: '사용자 장치', robotis_carCont_aux_motor_speed_1: '감속모터 속도를', robotis_carCont_aux_motor_speed_2: ', 출력값을', robotis_carCont_calibration_1: '적외선 센서 캘리브레이션 값을', robotis_openCM70_aux_motor_speed_1: '감속모터 속도를', robotis_openCM70_aux_motor_speed_2: ', 출력값을', robotis_openCM70_aux_servo_mode_1: '서보모터 모드를', robotis_openCM70_aux_servo_speed_1: '서보모터 속도를', robotis_openCM70_aux_servo_speed_2: ', 출력값을', robotis_openCM70_aux_servo_position_1: '서보모터 위치를', robotis_openCM70_aux_led_module_1: 'LED 모듈을', robotis_openCM70_aux_custom_1: '사용자 장치를', XBOT_digital: '디지털', XBOT_D2_digitalInput: 'D2 디지털 입력', XBOT_D3_digitalInput: 'D3 디지털 입력', XBOT_D11_digitalInput: 'D11 디지털 입력', XBOT_analog: '아날로그', XBOT_CDS: '광 센서 값', XBOT_MIC: '마이크 센서 값', XBOT_analog0: '아날로그 0번 핀 값', XBOT_analog1: '아날로그 1번 핀 값', XBOT_analog2: '아날로그 2번 핀 값', XBOT_analog3: '아날로그 3번 핀 값', XBOT_Value: '출력 값', XBOT_pin_OutputValue: '핀, 출력 값', XBOT_High: '높음', XBOT_Low: '낮음', XBOT_Servo: '서보 모터', XBOT_Head: '머리(D8)', XBOT_ArmR: '오른 팔(D9)', XBOT_ArmL: '왼 팔(D10)', XBOT_angle: ', 각도', XBOT_DC: '바퀴(DC) 모터', XBOT_rightWheel: '오른쪽', XBOT_leftWheel: '왼쪽', XBOT_bothWheel: '양쪽', XBOT_speed: ', 속도', XBOT_rightSpeed: '바퀴(DC) 모터 오른쪽(2) 속도:', XBOT_leftSpeed: '왼쪽(1) 속도:', XBOT_RGBLED_R: 'RGB LED 켜기 R 값', XBOT_RGBLED_G: 'G 값', XBOT_RGBLED_B: 'B 값', XBOT_RGBLED_color: 'RGB LED 색', XBOT_set: '로 정하기', XBOT_c: '도', XBOT_d: '레', XBOT_e: '미', XBOT_f: '파', XBOT_g: '솔', XBOT_a: '라', XBOT_b: '시', XBOT_melody_ms: '초 연주하기', XBOT_Line: '번째 줄', XBOT_outputValue: '출력 값', roborobo_num_analog_value_1: '아날로그', roborobo_num_analog_value_2: '번 센서값', roborobo_get_digital_value_1: '디지털', roborobo_num_pin_1: '디지털', roborobo_num_pin_2: '번 핀', roborobo_on: '켜기', roborobo_off: '끄기', roborobo_motor1: '모터1', roborobo_motor2: '모터2', roborobo_motor_CW: '정회전', roborobo_motor_CCW: '역회전', roborobo_motor_stop: '정지', roborobo_input_mode: '입력', roborobo_output_mode: '출력', roborobo_pwm_mode: '전류조절(pwm)', roborobo_servo_mode: '서보모터', roborobo_color: '컬러센서', roborobo_color_red: ' 빨간색 ', roborobo_color_green: ' 녹색 ', roborobo_color_blue: ' 파란색 ', roborobo_color_yellow: '노란색 ', roborobo_color_detected: ' 감지 ', roborobo_degree: ' ˚', robotori_D2_Input: '디지털 2번 핀 입력 값', robotori_D3_Input: '디지털 3번 핀 입력 값', robotori_A0_Input: '아날로그 0번 핀 입력 값', robotori_A1_Input: '아날로그 1번 핀 입력 값', robotori_A2_Input: '아날로그 2번 핀 입력 값', robotori_A3_Input: '아날로그 3번 핀 입력 값', robotori_A4_Input: '아날로그 4번 핀 입력 값', robotori_A5_Input: '아날로그 5번 핀 입력 값', robotori_digital: '디지털', robotori_D10_Output: '10번', robotori_D11_Output: '11번', robotori_D12_Output: '12번', robotori_D13_Output: '13번', robotori_pin_OutputValue: '핀, 출력 값', robotori_On: '켜짐', robotori_Off: '꺼짐', robotori_analog: '아날로그', robotori_analog5: '5번 핀 출력 값', robotori_analog6: '6번 핀 출력 값', robotori_analog9: '9번 핀 출력 값', robotori_Servo: '서보모터', robotori_DC: 'DC모터', robotori_DC_rightmotor: '오른쪽', robotori_DC_leftmotor: '왼쪽', robotori_DC_STOP: '정지', robotori_DC_CW: '시계방향', robotori_DC_CCW: '반시계방향', robotori_DC_select: '회전', CALC_rotation_value: 'this.getRotation()', CALC_direction_value: 'this.getDirection()', VARIABLE_is_included_in_list: '리스트에 포함되어 있는가?', VARIABLE_is_included_in_list_1: 'Entry.isExistValueInList(', VARIABLE_is_included_in_list_2: ',', VARIABLE_is_included_in_list_3: ')', SCENE_when_scene_start: "this.addEventListener('sceneStart')", SCENE_start_scene_1: 'Scene.changeScene(', SCENE_start_scene_2: ')', SCENE_start_neighbor_scene_1: 'Scene.changeScene(', SCENE_start_neighbor_scene_2: ')', SCENE_start_scene_pre: 'Scene.getPrevious()', SCENE_start_scene_next: 'Scene.getNext()', FUNCTION_explanation_1: '이름', FUNCTION_character_variable: '문자/숫자값', FUNCTION_logical_variable: '판단값', FUNCTION_function: '함수', FUNCTION_define: '함수 정의하기', CALC_calc_operation_sin: 'Math.sin(value)', CALC_calc_operation_cos: 'Math.cos(value)', CALC_calc_operation_tan: 'Math.tan(value)', CALC_calc_operation_floor: 'Math.floor(value)', CALC_calc_operation_ceil: 'Math.ceil(value)', CALC_calc_operation_round: 'Math.round(value)', CALC_calc_operation_factorial: '펙토리얼값', CALC_calc_operation_asin: 'Math.asin(value)', CALC_calc_operation_acos: 'Math.acos(value)', CALC_calc_operation_atan: 'Math.atan(value)', CALC_calc_operation_log: '로그값', CALC_calc_operation_ln: '자연로그값', CALC_calc_operation_natural: 'integer value', CALC_calc_operation_unnatural: '소수점 부분', MOVING_locate_object_time_1: '', MOVING_locate_object_time_2: '초 동안', MOVING_locate_object_time_3: '위치로 이동하기', wall_up: '위쪽 벽', wall_down: '아래쪽 벽', wall_right: '오른쪽 벽', wall_left: '왼쪽 벽', CALC_coordinate_x_value: 'x 좌푯값', CALC_coordinate_y_value: 'y 좌푯값', CALC_coordinate_rotation_value: '방향', CALC_coordinate_direction_value: '이동방향', CALC_picture_index: '모양 번호', CALC_picture_name: '모양 이름', FLOW_repeat_while_true_1: 'Repeat', FLOW_repeat_while_true_2: '', TUT_when_start: "Entry.addEventListener('run_button_clicked')", TUT_move_once: 'Entry.moveOnce()', TUT_rotate_left: 'Entry.rotateLeft()', TUT_rotate_right: 'Entry.rotateRight()', TUT_jump_barrier: 'Entry.jumpBarrier()', TUT_repeat_tutorial_1: 'Entry.repeat(', TUT_repeat_tutorial_2: ')', TUT_if_barrier_1: 'if (', TUT_if_barrier_2: ')', TUT_if_conical_1: 'if (', TUT_if_conical_2: ')', TUT_repeat_until: 'while (Entry.reachToPart()) {}', TUT_repeat_until_gold: 'while (Entry.reachToPart()) {}', TUT_declare_function: 'new function()', TUT_call_function: 'call function()', CALC_calc_operation_abs: '절댓값', CONTEXT_COPY_option: '코드 복사', Delete_Blocks: '코드 삭제', Duplication_option: '코드 복사 & 붙여넣기', Paste_blocks: '붙여넣기', add_my_storage: '나의 보관함에 추가하기', export_object: '오브젝트 내보내기', Clear_all_blocks: '모든 코드 삭제하기', add_comment: '메모 추가하기', copy_paste_comment: '메모 복사 & 붙여넣기', copy_comment: '메모 복사하기', delete_comment: '메모 삭제하기', fold_comment: '메모 접기', open_comment: '메모 열기', separate_comment: '메모 분리하기', hide_all_comment: '모든 메모 숨기기', show_all_comment: '모든 메모 보이기', transparency: '투명도', BRUSH_change_brush_transparency_1: 'this.brush.opacity -=', BRUSH_change_brush_transparency_2: '', BRUSH_set_brush_transparency_1: 'this.brush.opacity -=', BRUSH_set_brush_transparency_2: '', CALC_char_at_1: '', CALC_char_at_2: '.charAt(', CALC_char_at_3: ')', CALC_length_of_string_1: '', CALC_length_of_string_2: '.length()', CALC_substring_1: '', CALC_substring_2: '.subString(', CALC_substring_3: ',', length_of_string: '', CALC_substring_4: ')', CALC_replace_string_1: '', CALC_replace_string_2: '.replace(', CALC_replace_string_3: ',', CALC_replace_string_4: ')', CALC_change_string_case_1: '', CALC_change_string_case_2: '', CALC_change_string_case_3: ' ', CALC_change_string_case_sub_1: '.uppercase()', CALC_change_string_case_sub_2: '.lowercase()', CALC_index_of_string_1: '', CALC_index_of_string_2: '.indexOf(', CALC_index_of_string_3: ')', MOVING_add_direction_by_angle_time_explain_1: '', MOVING_direction_relative_duration_1: '', MOVING_direction_relative_duration_2: '', MOVING_direction_relative_duration_3: '', CALC_get_sound_volume: 'Volume', SOUND_sound_from_to_1: '', SOUND_sound_from_to_2: '', SOUND_sound_from_to_3: '', SOUND_sound_from_to_4: '', SOUND_sound_from_to_and_wait_1: '', SOUND_sound_from_to_and_wait_2: '', SOUND_sound_from_to_and_wait_3: '', SOUND_sound_from_to_and_wait_4: '', CALC_quotient_and_mod_1: '', CALC_quotient_and_mod_2: '/', CALC_quotient_and_mod_3: '', CALC_quotient_and_mod_4: ' ', CALC_quotient_and_mod_sub_1: '몫', CALC_quotient_and_mod_sub_2: '나머지', self: '자신', CALC_coordinate_size_value: '크기', CALC_choose_project_timer_action_1: 'Entry.setTimer(', CALC_choose_project_timer_action_2: ')', CALC_choose_project_timer_action_sub_1: '시작하기', CALC_choose_project_timer_action_sub_2: '정지하기', CALC_choose_project_timer_action_sub_3: '초기화하기', LOOKS_change_object_index_1: 'Entry.setLayerOrder(this,', LOOKS_change_object_index_2: ')', LOOKS_change_object_index_sub_1: '맨 앞으로', LOOKS_change_object_index_sub_2: '앞으로', LOOKS_change_object_index_sub_3: '뒤로', LOOKS_change_object_index_sub_4: '맨 뒤로', FLOW_repeat_while_true_until: 'until', FLOW_repeat_while_true_while: 'while', copy_block: '블록 복사', delete_block: '블록 삭제', tidy_up_block: '코드 정리하기', block_hi: '안녕!', entry_bot_name: '엔트리봇', hi_entry: '안녕 엔트리!', hi_entry_en: 'Hello Entry!', bark_dog: '강아지 짖는 소리', walking_entryBot: '엔트리봇_걷기', doggi_bark: '강아지 짖는 소리', entry: '엔트리', hello: '안녕', nice: '반가워', silent: '무음', do_name: '도', do_sharp_name: '도#(레♭)', re_name: '레', re_sharp_name: '레#(미♭)', mi_name: '미', fa_name: '파', fa_sharp_name: '파#(솔♭)', sol_name: '솔', sol_sharp_name: '솔#(라♭)', la_name: '라', la_sharp_name: '라#(시♭)', DUMMY: '더미', coconut_stop_motor: '모터 정지', coconut_move_motor: '움직이기', coconut_turn_motor: '으로 돌기', coconut_move_outmotor: '외부모터', coconut_turn_left: '왼쪽', coconut_turn_right: '오른쪽', coconut_move_forward: '앞으로', coconut_move_backward: '뒤로', coconut_note_c: '도', coconut_note_d: '레', coconut_note_e: '미', coconut_note_f: '파', coconut_note_g: '솔', coconut_note_a: '라', coconut_note_b: '시', coconut_move_speed_1: '0', coconut_move_speed_2: '50', coconut_move_speed_3: '100', coconut_move_speed_4: '150', coconut_move_speed_5: '255', coconut_play_buzzer_hn: '2분음표', coconut_play_buzzer_qn: '4분음표', coconut_play_buzzer_en: '8분음표', coconut_play_buzzer_sn: '16분음표', coconut_play_buzzer_tn: '32분음표', coconut_play_buzzer_wn: '온음표', coconut_play_buzzer_dhn: '점2분음표', coconut_play_buzzer_dqn: '점4분음표', coconut_play_buzzer_den: '점8분음표', coconut_play_buzzer_dsn: '점16분음표', coconut_play_buzzer_dtn: '점32분음표', coconut_rest_buzzer_hr: '2분쉼표', coconut_rest_buzzer_qr: '4분쉼표', coconut_rest_buzzer_er: '8분쉼표', coconut_rest_buzzer_sr: '16분쉼표', coconut_rest_buzzer_tr: '32분쉼표', coconut_rest_buzzer_wr: '온쉼표', coconut_play_midi_1: '반짝반짝 작은별', coconut_play_midi_2: '곰세마리', coconut_play_midi_3: '모차르트 자장가', coconut_play_midi_4: '도레미송', coconut_play_midi_5: '나비야', coconut_floor_sensing_on: '감지', coconut_floor_sensing_off: '미감지', coconut_dotmatrix_set_on: '켜짐', coconut_dotmatrix_set_off: '꺼짐', coconut_dotmatrix_row_0: '모든', coconut_dotmatrix_row_1: '1', coconut_dotmatrix_row_2: '2', coconut_dotmatrix_row_3: '3', coconut_dotmatrix_row_4: '4', coconut_dotmatrix_row_5: '5', coconut_dotmatrix_row_6: '6', coconut_dotmatrix_row_7: '7', coconut_dotmatrix_row_8: '8', coconut_dotmatrix_col_0: '모든', coconut_dotmatrix_col_1: '1', coconut_dotmatrix_col_2: '2', coconut_dotmatrix_col_3: '3', coconut_dotmatrix_col_4: '4', coconut_dotmatrix_col_5: '5', coconut_dotmatrix_col_6: '6', coconut_dotmatrix_col_7: '7', coconut_dotmatrix_col_8: '8', coconut_sensor_left_proximity: '왼쪽 전방 센서', coconut_sensor_right_proximity: '오른쪽 전방 센서', coconut_sensor_both_proximity: '모든', coconut_sensor_left_floor: '왼쪽 바닥센서', coconut_sensor_right_floor: '오른쪽 바닥 센서', coconut_sensor_both_floor: '모든', coconut_sensor_acceleration_x: 'x축 가속도', coconut_sensor_acceleration_y: 'y축 가속도', coconut_sensor_acceleration_z: 'z축 가속도', coconut_sensor_light: '밝기', coconut_sensor_temperature: '온도', coconut_left_led: '왼쪽', coconut_right_led: '오른쪽', coconut_both_leds: '모든', coconut_color_cyan: '하늘색', coconut_color_magenta: '보라색', coconut_color_black: '검은색', coconut_color_white: '흰색', coconut_color_red: '빨간색', coconut_color_yellow: '노란색', coconut_color_green: '초록색', coconut_color_blue: '파란색', coconut_beep: '삐 소리내기', coconut_clear_buzzer: '버저 끄기', coconut_x_axis: 'X축', coconut_y_axis: 'Y축', coconut_z_axis: 'Z축', modi_enviroment_bule: '파랑', modi_enviroment_green: '초록', modi_enviroment_humidity: '습도', modi_enviroment_illuminance: '조도', modi_enviroment_red: '빨강', modi_enviroment_temperature: '온도', modi_gyroscope_xAcceleratior: 'X축 가속', modi_gyroscope_yAcceleratior: 'Y축 가속', modi_gyroscope_zAcceleratior: 'Z축 가속', modi_motor_angle: '각도', modi_motor_speed: '속도', modi_motor_torque: '회전', modi_speaker_F_DO_5: '도5', modi_speaker_F_DO_6: '도6', modi_speaker_F_DO_7: '도7', modi_speaker_F_DO_S_5: '도#5', modi_speaker_F_DO_S_6: '도#6', modi_speaker_F_DO_S_7: '도#7', modi_speaker_F_MI_5: '미5', modi_speaker_F_MI_6: '미6', modi_speaker_F_MI_7: '미7', modi_speaker_F_PA_5: '파5', modi_speaker_F_PA_6: '파6', modi_speaker_F_PA_7: '파7', modi_speaker_F_PA_S_5: '파#5', modi_speaker_F_PA_S_6: '파#6', modi_speaker_F_PA_S_7: '파#7', modi_speaker_F_RA_5: '라5', modi_speaker_F_RA_6: '라6', modi_speaker_F_RA_7: '라7', modi_speaker_F_RA_S_5: '라#5', modi_speaker_F_RA_S_6: '라#6', modi_speaker_F_RA_S_7: '라#7', modi_speaker_F_RE_5: '레5', modi_speaker_F_RE_6: '레6', modi_speaker_F_RE_7: '레7', modi_speaker_F_RE_S_5: '라#5', modi_speaker_F_RE_S_6: '레#6', modi_speaker_F_RE_S_7: '레#7', modi_speaker_F_SOL_5: '솔5', modi_speaker_F_SOL_6: '솔6', modi_speaker_F_SOL_7: '솔7', modi_speaker_F_SOL_S_5: '솔#5', modi_speaker_F_SOL_S_6: '솔#6', modi_speaker_F_SOL_S_7: '솔#7', modi_speaker_F_SO_5: '시5', modi_speaker_F_SO_6: '시6', modi_speaker_F_SO_7: '시7', si_name: '시', ev3_ccw: 'CCW', ev3_cw: 'CW', rokoboard_sensor_name_0: '소리', rokoboard_sensor_name_1: '빛', rokoboard_sensor_name_2: '슬라이더', rokoboard_sensor_name_3: '저항-A', rokoboard_sensor_name_4: '저항-B', rokoboard_sensor_name_5: '저항-C', rokoboard_sensor_name_6: '저항-D', rokoboard_string_1: '버튼을 눌렀는가?', HW_MOTOR: '모터', HW_SENSOR: '센서', HW_LED: '발광다이오드', HW_MELODY: '멜로디', HW_ROBOT: '로봇', ALTINO_ACCX: '가속도 X축', ALTINO_ACCY: '가속도 Y축', ALTINO_ACCZ: '가속도 Z축', ALTINO_BAT: '배터리 잔량 체크', ALTINO_CDS: '밝기', ALTINO_GYROX: '자이로 X축', ALTINO_GYROY: '자이로 Y축', ALTINO_GYROZ: '자이로 Z축', ALTINO_IR1: '1번 거리', ALTINO_IR2: '2번 거리', ALTINO_IR3: '3번 거리', ALTINO_IR4: '4번 거리', ALTINO_IR5: '5번 거리', ALTINO_IR6: '6번 거리', ALTINO_Led_Brake_Light: '브레이크', ALTINO_Led_Forward_Light: '전방', ALTINO_Led_Reverse_Light: '후방', ALTINO_Led_Turn_Left_Light: '왼쪽방향', ALTINO_Led_Turn_Right_Light: '오른쪽방향', ALTINO_Line: '번째 줄', ALTINO_MAGX: '나침판 X축', ALTINO_MAGY: '나침판 Y축', ALTINO_MAGZ: '나침판 Z축', ALTINO_REMOTE: '리모콘 수신 값', ALTINO_STTOR: '조향 토크', ALTINO_STVAR: '조향 가변저항', ALTINO_Steering_Angle_Center: '가운데', ALTINO_Steering_Angle_Left10: '왼쪽10', ALTINO_Steering_Angle_Left15: '왼쪽15', ALTINO_Steering_Angle_Left20: '왼쪽20', ALTINO_Steering_Angle_Left5: '왼쪽5', ALTINO_Steering_Angle_Right10: '오른쪽10', ALTINO_Steering_Angle_Right15: '오른쪽15', ALTINO_Steering_Angle_Right20: '오른쪽20', ALTINO_Steering_Angle_Right5: '오른쪽5', ALTINO_TEM: '온도', ALTINO_TOR1: '오른쪽 토크', ALTINO_TOR2: '왼쪽 토크', ALTINO_Value: '출력 값', ALTINO_a: '라', ALTINO_a2: '라#', ALTINO_b: '시', ALTINO_c: '도', ALTINO_c2: '도#', ALTINO_d: '레', ALTINO_d2: '레#', ALTINO_dot_display_1: '한문자', ALTINO_dot_display_2: '출력하기', ALTINO_e: '미', ALTINO_f: '파', ALTINO_f2: '파#', ALTINO_g: '솔', ALTINO_g2: '솔#', ALTINO_h: '끄기', ALTINO_h2: '켜기', ALTINO_leftWheel: '왼쪽', ALTINO_melody_ms: '연주하기', ALTINO_outputValue: '출력 값', ALTINO_rightWheel: '오른쪽', ALTINO_set: '로 정하기', ardublock_motor_forward: '앞', ardublock_motor_backward: '뒤', jdkit_clockwise: '시계방향', jdkit_counterclockwise: '반시계방향', jdkit_gyro_frontrear: '앞뒤', jdkit_gyro_leftright: '좌우', jdkit_joystick_leftleftright: '왼쪽 좌우', jdkit_joystick_lefttopbottom: '왼쪽 상하', jdkit_joystick_rightleftright: '오른쪽 좌우', jdkit_joystick_righttopbottom: '오른쪽 상하', jdkit_led: 'LED', jdkit_led_color_green: '초록색', jdkit_led_color_orange: '오랜지색', jdkit_led_turnoff: '끄기', jdkit_led_turnon: '켜기', jdkit_motor_leftbottom: '왼쪽아래', jdkit_motor_lefttop: '왼쪽위', jdkit_motor_rightbottom: '오른쪽아래', jdkit_motor_righttop: '오른쪽위', jdkit_tune_do: '도', jdkit_tune_fa: '파', jdkit_tune_la: '라', jdkit_tune_mi: '미', jdkit_tune_re: '레', jdkit_tune_si: '시', jdkit_tune_sol: '솔', FUNBOARD_bt_down: '노랑(B)', FUNBOARD_bt_left: '초록(C)', FUNBOARD_bt_right: '파랑(D)', FUNBOARD_bt_up: '빨강(A)', FUNBOARD_column_tag: '칸', FUNBOARD_do_off: '끄기', FUNBOARD_do_on: '켜기', FUNBOARD_led_color_all: '모두', FUNBOARD_led_color_blue: '파랑', FUNBOARD_led_color_green: '초록', FUNBOARD_led_color_red: '빨강', FUNBOARD_led_color_str: '색', FUNBOARD_led_color_yellow: '노랑', FUNBOARD_led_off_str: 'LED 끄기', FUNBOARD_led_on_str: 'LED 켜기', FUNBOARD_row_tag: '줄', FUNBOARD_scroll_down: '아래쪽으로', FUNBOARD_scroll_left: '왼쪽으로', FUNBOARD_scroll_no: '없음', FUNBOARD_scroll_right: '오른쪽으로', FUNBOARD_scroll_up: '위쪽으로', FUNBOARD_sensor_cds: 'Cds (밝기 감지)', FUNBOARD_sensor_mic: '마이크 (소리 감지)', FUNBOARD_sensor_slide: '슬라이드 (막대 조정)', FUNBOARD_sensor_state_1: '작다', FUNBOARD_sensor_state_2: '크다', FUNBOARD_touchbt_down: '노랑(B)', FUNBOARD_touchbt_enter: ' F', FUNBOARD_touchbt_escape: ' G', FUNBOARD_touchbt_left: '초록(C)', FUNBOARD_touchbt_right: '파랑(D)', FUNBOARD_touchbt_space: ' E', FUNBOARD_touchbt_up: '빨강(A)', funboard_dotmatrix_set_off: '끄기', funboard_dotmatrix_set_on: '켜기', AI_UTILIZE: '인공지능', video_show_video: '보이기', video_hide_video: '숨기기', video_brightness: '밝기', video_transparency: '투명도', video_left_right: '좌우', video_top_bottom: '상하', video_human: '사람', video_face: '얼굴', video_object: '사물', video_start: '시작하기', video_end: '중지하기', video_gender: '성별', video_age: '나이', video_emotion: '감정', video_motion_onself: '자신', video_motion_onscreen: '실행화면', video_motion_scale: '움직임', video_motion_direction_horizontal: '좌우방향', video_motion_direction_vertical: '상하방향', table_row: '행', table_col: '열', table_sum: '합', table_max: '최대', table_min: '최소', table_avg: '평균', table_stdev: '표준편차', }; Lang.video_body_coord_params = { left_eye: '왼쪽 눈', right_eye: '오른쪽 눈', nose: '코', left_mouth: '왼쪽 입꼬리', right_mouth: '오른쪽 입꼬리', upper_lip: '윗 입술', lower_lip: '아랫 입술', face: '얼굴', neck: '목', left_ear: '왼쪽 귀', right_ear: '오른쪽 귀', left_shoulder: '왼쪽 어깨', left_elbow: '왼쪽 팔꿈치', left_wrist: '왼쪽 손목', left_hip: '왼쪽 엉덩이', left_knee: '왼쪽 무릎', left_ankle: '왼쪽 발목', right_shoulder: '오른쪽 어깨', right_elbow: '오른쪽 팔꿈치', right_wrist: '오른쪽 손목', right_hip: '오른쪽 엉덩이', right_knee: '오른쪽 무릎', right_ankle: '오른쪽 발목', }; Lang.video_emotion_params = { angry: '분노', disgusted: '혐오', fearful: '두려움', happy: '행복', neutral: '무표정', sad: '슬픔', surprised: '놀람', }; Lang.video_object_params = { person: '사람', bicycle: '자전거', car: '자동차', motorcycle: '오토바이', airplane: '비행기', bus: '버스', train: '기차', truck: '트럭', boat: '보트', 'traffic light': '신호등', 'fire hydrant': '소화전', 'stop sign': '일단 정지 표지판', 'parking meter': '주차요금 계산기', bench: '벤치', bird: '새', cat: '고양이', dog: '강아지', horse: '말', sheep: '양', cow: '소', elephant: '코끼리', bear: '곰', zebra: '얼룩말', giraffe: '기린', backpack: '배낭', umbrella: '우산', handbag: '핸드백', tie: '넥타이', suitcase: '여행 가방', frisbee: '프리즈비 원반', skis: '스키', snowboard: '스노우보드', 'sports ball': '공', kite: '연', 'baseball bat': '야구 배트', 'baseball glove': '야구 글러브', skateboard: '스케이트 보드', surfboard: '서핑 보드', 'tennis racket': '테니스 라켓', bottle: '병', 'wine glass': '와인 잔', cup: '컵', fork: '포크', knife: '칼', spoon: '숟가락', bowl: '사발', banana: '바나나', apple: '사과', sandwich: '샌드위치', orange: '오렌지', broccoli: '브로콜리', carrot: '당근', 'hot dog': '핫도그', pizza: '피자', donut: '도넛', cake: '케이크', chair: '의자', couch: '소파', 'potted plant': '식물 화분', bed: '침대', 'dining table': '식탁', toilet: '변기', tv: '텔레비젼', laptop: '노트북', mouse: '마우스', remote: '리모콘', keyboard: '키보드', 'cell phone': '휴대전화', microwave: '전자렌지', oven: '오븐', toaster: '토스터기', sink: '싱크대', refrigerator: '냉장고', book: '책', clock: '시계', vase: '꽃병', scissors: '가위', 'teddy bear': '곰인형', 'hair drier': '헤어 드라이기', toothbrush: '칫솔', }; Lang.Buttons = { share_policy: '이것만은 꼭!', write_policy: '작성 가이드', lesson_list: '강의 목록', complete_study: '학습 완료하기', show_me: '미리 보기', do_this_for_me: '대신 해주기', previous: '이전', get_started: '시작하기', next_lesson: '다음 내용 학습하기', course_submit: '제출하기', course_done: '확인', mission: '미션 확인하기', basic_guide: '기본 사용 방법', apply: '적용하기', add: '추가하기', cancel: '취소', save: '확인', start: '시작', confirm: '확인', delete: '삭제', create: '학급 만들기', done: '완료', accept: '수락', refuse: '거절', yes: '예', button_no: '아니오', quiz_retry: '다시 풀어보기', discuss_upload: '불러오기', maze_popup_guide: '이용안내', maze_popup_mapHint: '힌트보기', maze_hint_btn_guide: '이용 안내', maze_hint_btn_block: '블록 도움말', maze_hint_btn_map: '힌트 보기', maze_hint_btn_goal: '목표', list_save: '저장하기', duplication: '복사하기', export_to_excel: '엑셀로 내려받기', single_line: '한 줄 쓰기', multi_line: '여러 줄 쓰기', lecture_finish_popup_reset_lecture: '처음부터 다시하기', lecture_finish_popup_show_output: '실습한 코드보기', lecture_view_hints: '잘 모르겠어요!', default_hint_title: '어떻게 만들까?', show_only_vector: '벡터 모아보기', }; Lang.Menus = { nothing_to_import: '불러오기 할 항목이 없습니다.', nothing_to_export: '내려받기 할 항목이 없습니다.', content_copied: '내용이 복사되었습니다.', list_import_title: '리스트 불러오기', list_import_placeholder: '예)\n내용1\n내용2\n내용3\n내용4\n내용5\n내용6\n내용7\n내용8', verifying_email: '인증 메일 발송하기', list_import_notice_1: '리스트 항목의 내용을 올릴 수 있습니다.', list_import_notice_2: '기존 내용은 새로 저장한 내용으로 변경됩니다.', list_export_title: '리스트 내보내기', list_export_notice: '리스트 항목의 내용을 복사하거나, 엑셀로 내려받을 수 있습니다.', robotis_opencm70: '로보티즈 IoT', cannnot_mark_favorite: '비공개 작품은 관심 작품으로 지정할 수 없습니다.', enterPassword: '비밀번호를 입력해주세요.', enterPassword_update: '변경 내용을 저장하기 위해 비밀번호를 입력해주세요.', enterNewPassword: '새로운 비밀번호를 입력하세요.', reEnterNewPassword: '새로운 비밀번호를 다시 입력하세요.', resign: '회원탈퇴', check_sended_email: '발송된 인증 메일을 확인하여 이메일 주소를 인증해 주세요.', signUpEmail_1: '입력된 이메일 주소로 인증 메일이 발송되었습니다.', signUpEmail_2: '이메일 주소를 인증해주세요.', select_email_unauthenticated_user: '해당 이메일 주소가 아래 계정에 등록되어 있습니다.\n인증을 원하는 계정을 선택해주세요.', select_user: '계정을 선택해주세요.', enter_password_withdraw: '회원탈퇴 신청을 위해 비밀번호를 입력해주세요.', instruction_agree: '안내 사항에 동의해주세요.', check_instructions: '위 안내 사항에 동의합니다.', deleteAccount_2: '회원탈퇴를 신청하신 30일 이후에는 회원정보와 작품/강의/학급/게시글/댓글/좋아요/관심 정보가 모두 삭제되며 복구가 불가능합니다.', deleteAccount_1: '회원탈퇴를 신청하신 30일 이내에 로그인하시면 회원탈퇴를 취소하실 수 있습니다.', protect_account: '안전한 비밀번호로 내정보를 보호하세요.', please_verify: '인증 메일을 발송하여 이메일 주소를 인증해 주세요.', unverified_email: '이메일 주소가 인증되지 않았습니다.', deleteAccount: '회원탈퇴 신청', corporatePersonal: '개인정보 이전에 동의 합니다', corporateTransferGuide: "개인정보 양수자('엔트리' 웹사이트 운영자) 안내", corporateReciever: '개인정보를 이전 받은 자: 재단법인 커넥트', corporateAddress: '커넥트 주소 및 연락처', corporateAddress_1: '서울시 강남구 강남대로 382 메리츠타워 7층', corporateConsent: '개인정보의 이전을 원치 않으시는 경우 ,동의 철회 방법', corporateEmail: '계정에 등록된 이메일로 탈퇴 요청 메일 발송', corporateAddition: '또한 , 영업 양도에 따라 약관 등이 아래와 같이 변경될 예정입니다.', corporateApplicationDate: '적용시기 : 2017년 10월 29일', corporateTargetChanges: '적용대상 및 변경사항 :', corporateTarget: '적용대상', corporateChanges: '변경사항', corporateTerms: '엔트리 이용약관', corporateOperator: '웹사이트 운영자의 명칭 변경', corporateClassroomTerms: '학급 서비스 이용약관', doAgreeWithClassroomTerms: '학급 서비스 이용약관에 동의합니다.', doChangePassword: '나만 알수 있는 비밀번호로 변경해주세요.', corporatePrivacyPolicy: '개인정보 처리방침', corporateConsignment: '웹사이트 운영자의 명칭 변경 및 개인정보 위탁 업체 추가', corporateEntrusted: '수탁업: NHN Technology Service(주)', corporateConsignmentDetails: '위탁업무 내용: 서비스 개발 및 운영', corporatePeriod: '보유기간 : 회원 탈퇴 시 혹은 위탁 계약 종료시 까지', corporateChangeDate: '변경 적용일 : 2017년 10월 29일 부', corporateWarning: '개인정보 이전에 동의해 주세요.', corporateConfirm: '확인', corporateTitle: '안녕하세요. 엔트리교육연구소입니다.
“엔트리”를 이용하고 계신 회원 여러분께 깊은 감사의 말씀을 드립니다.
엔트리교육연구소는 그동안 공익 목적으로 운영해오던 “엔트리” 웹사이트의 운영을
네이버가 설립한 비영리 재단인 커넥트재단에 양도하기로 합의하였습니다. 
앞으로 엔트리는 커넥트재단에서 공익 목적 하에 지속적으로 운영될 수 있도록
할 것이며, 회원 여러분께서는 기존과 동일하게 엔트리를 이용하실 수 있습니다.
 웹사이트 제공 주체가 엔트리교육연구소에서 커넥트재단으로 변경됨에 따라 아래와
같이 회원 개인 정보에 대한 이전이 있으며, 본 합의에 의해 실제 개인 정보의 위치가
물리적으로 이동한 것은 아님을 알려드립니다. ', textcoding_numberError_f: '등록된 함수 중에 이름의 첫 글자가 숫자인 함수가 있으면 모드 변환을 할 수 없습니다.', textcoding_bookedError_1f: '등록된 함수 중에 이름이', textcoding_bookedError_2f: '인 함수가 있으면 모드 변환을 할 수 없습니다.', textcoding_specialCharError_f: "등록된 함수 중 이름에 '_' 를 제외한 특수 문자가 있으면 모드 변환을 할 수 없습니다.", textcoding_numberError_v: '등록된 변수 중에 이름의 첫 글자가 숫자인 변수가 있으면 모드 변환을 할 수 없습니다.', textcoding_bookedError_1v: '등록된 변수 중에 변수 이름이 ', textcoding_bookedError_2v: ' 인 변수가 있으면 모드 변환을 할 수 없습니다.', textcoding_specialCharError_v: "등록된 변수 중 이름에 '_' 를 제외한 특수 문자가 있으면 모드 변환을 할 수 없습니다.", textcoding_numberError_l: '등록된 리스트 중에 이름의 첫 글자가 숫자인 리스트가 있으면 모드 변환을 할 수 없습니다.', textcoding_bookedError_1l: '등록된 리스트 중에 리스트 이름이', textcoding_bookedError_2l: '인 리스트가 있으면 모드 변환을 할 수 없습니다.', textcoding_specialCharError_l: "등록된 리스트 중 이름에 '_' 를 제외한 특수 문자가 있으면 모드 변환을 할 수 없습니다.", no_discuss_permission: '글을 읽을 권한이 없습니다', delete_comment: '댓글을 삭제하시겠습니까?', delete_article: '게시물을 삭제하시겠습니까?', discuss_cannot_edit: '본인의 게시물이 아닙니다.', discuss_extention: '실행파일은 첨부하실 수 없습니다.', delete_discuss_picture: '사진을 삭제하시겠습니까?', delete_discuss_file: '파일을 삭제하시겠습니까?', discuss_save_question: '글을 저장하시겠습니까?', discuss_cancle_question: '작성을 취소하시겠습니까?', discuss_saved: '이(가) 저장되었습니다.', discuss_no_write_permission: '현재 로그인된 계정으로는 글을 작성하실 수 없습니다.', discuss_no_project_permission: '현재 로그인된 계정으로는 작품을 게시하실 수 없습니다.', discuss_write_abuse_detected: '짧은 시간안에 여러 글이 작성되었습니다.\n1분 뒤에 다시 시도해주세요.', contents_abuse_detected: '5분 뒤에 다시 시도해주세요.', contents_abuse_detected_10: '10분 뒤에 다시 시도해주세요.', discuss_new_write_abuse_warn: '짧은 시간안에 새 글을 작성하는 경우 \n게시글 작성이 제한될 수 있습니다. \n이용에 주의하시길 바랍니다.', discuss_write_abuse_warn: '짧은 시간안에 여러 댓글을 작성하는 경우 \n댓글 작성이 제한될 수 있습니다. \n이용에 주의하시길 바랍니다.', find_not_your_email: '올바른 이메일을 입력해주세요.', search_lang: '검색', search_title: '제목', faq_desc: '엔트리를 이용하면서 궁금한 점들의 답변을 확인해보세요.', faq_all: '전체보기', faq_site: '사이트 이용', faq_project: '작품 만들기', faq_hardware: '하드웨어', faq_offline: '오프라인', faq_copyright: '저작권', faq_title: '자주하는 질문', faq: '자주하는 질문', malicious_warning: '불건전한 사진은 불러올 수 없습니다. 불건전한 사진이 아닌 경우 제안 및 건의에 해당 사진을 첨부하여 신고해주세요.', fword_alert_msg: '욕설이나 불건전한 글은 게시할 수 없습니다.', fword_alert_1: '주제와 무관한 욕설이나 악플은 게시할 수 없습니다.', fword_alert_2: '불건전한 단어가 포함되어 있어, 대체 문장으로 게시 됩니다.', fword_replace_1: '엔트리를 통해 누구나 쉽고 재미있게 소프트웨어를 배울 수 있어요.', fword_replace_2: '소프트웨어 교육의 첫걸음, 엔트리.', fword_replace_3: '재미있게 배우는 학습 공간 엔트리!', fword_replace_4: '엔트리에서 공유와 협업을 통해 멋진 작품을 만들어요.', fword_replace_5: '엔트리는 누구나 무료로 소프트웨어 교육을 받을 수 있게 개발된 소프트웨어 교육 플랫폼입니다.', fword_replace_6: '엔트리와 함께 건강한 소프트웨어 교육 생태계를 조성해요!', fword_replace_7: '엔트리에서 학습하고, 만들고, 공유하며 같이 성장해요.', solve_quiz: '퀴즈 풀기', submit_homework_first_title: '완성! 과제 제출하기', submit_homework_first_content: '멋진 작품이 완성되었습니다. 과제를 제출하세요. 마감 기한 전까지 다시 제출할 수 있습니다.', submit_homework_again_title: '과제 다시 제출하기', submit_homework_again_content: '이미 제출한 과제입니다.
과제를 다시 제출하시겠습니까?', submit_homework_expired_title: '과제 제출 마감', submit_homework_expired_content: '과제 제출이 마감되었습니다.', done_study_title: '완성', done_study_content: '만든 작품을 실행해 봅시다.', featured_courses: '추천 강의 모음', follow_along: '따라하기', follow_along_desc: '차근차근 따라하며 다양한 작품을 만듭니다.', do_quiz: '퀴즈풀기', do_quiz_desc: '학습한 내용을 잘 이해했는지 퀴즈를 통해 확인합니다.', challenge: '도전하기', play: '도전하기', challenge_desc: '주어진 문제를 스스로 해결하며 개념을 익힙니다.', creste_freely: '자유롭게 만들기', creste_freely_desc: '학습한 내용으로 나만의 작품을 자유롭게 만듭니다.', entry_rc_desc: '프로그래밍의 원리를 학습단계에 맞게 배울 수 있는 엔트리 강의 모음! 지금 시작해보세요!
따라하고, 도전하며 소프트웨어를 만들다 보면 어렵게 느껴졌던 프로그래밍의 원리도 쉽고 재미있게 다가옵니다!', hw_deadline: '마감 일자', rc_course_desc: '프로그래밍의 원리를 학습단계에 맞게 배울 수 있도록 구성된 엔트리 강의 모음입니다.', rc_course: '추천 강의 모음', entry_rec_course: '엔트리 추천 강의 모음', entry_rec_course_desc: '누구나 쉽게 보고 따라하면서 재미있고 다양한 소프트웨어를 만들 수 있는 엔트리 강의를 소개합니다.', guidance: '안내', wait: '잠깐', hint: '힌트', concept_guide: '개념 톡톡', group_quiz: '우리 반 퀴즈', fail_check_hint: '앗… 실패! 다시 한 번 도전해보세요!
어려울 땐 [힌트]를 확인해보세요!', sort_student: '학생별', sort_lesson: '강의별', sort_course: '강의 모음별', student_progress: '우리 반 진도', my_progress: '나의 진도', lec_in_progress: '학습 중', free_modal_asgn_over: '과제 제출이 마감되었습니다.', free_submission_closed: '과제 제출 마감', free_modal_asgn_submit_first: '멋진 작품이 완성되었습니다! 과제를 제출하세요.
마감 기한 전까지 다시 제출 할 수 있습니다.', asgn_submit: '완성! 과제 제출하기', free_modal_content_resubmit: '이미 제출한 과제입니다.
과제를 다시 제출하시겠습니까?', asgn_resubmit: '과제 다시 제출하기', free_modal_content_complete: '멋진 작품이 완성되었습니다.', guide_modal_content_complete: '만든 작품을 실행해 봅시다.', success: '성공', fail: '실패', mission_modal_content_fail: '
어려울 땐 [힌트]를 확인해보세요!', mission_modal_content_success: '만든 작품을 실행해 봅시다.', in_progress: '진행중', completed: '완료', submitted: '제출 완료', submission_closed: '마감', progress: '진행 상황', study_completed: '학습 완료', view_course_desc: '코스웨어 설명 보기', main_entry_starter: '기초부터! 엔트리 스타터', main_entry_booster: '개념탄탄! 엔트리 부스터', main_entry_master: '생각을 펼치는! 엔트리 마스터', no_students_in_classroom: '아직 등록된 학생이 없습니다.
학생을 직접 추가하거나, 초대해 보세요!', lectures: '강의', Lectures: '강의', studentHomeworkList: '과제', curriculums: '강의 모음', Curriculums: '강의 모음', quiz: '퀴즈', no_added_group_contents_teacher: '추가된 %1이(가) 없습니다.
우리 반 %1을(를) 추가해 주세요.', no_added_group_contents_student: '아직 올라온 %1이(가) 없습니다. 선생님이 %1을(를) 올려주시면, 학습 내용을 확인할 수 있습니다.', side_project: '목표 작품', custom_make_course_1: "'오픈 강의 만들기> 강의 모음 만들기'에서", custom_make_course_2: '나만의 강의 모음을 만들어 보세요.', custom_make_lecture_1: "'오픈 강의 만들기'에서", custom_make_lecture_2: '나만의 강의를 만들어 보세요', alert_enter_info: '수정할 정보를 입력해주세요.', alert_enter_new_pwd: '기존 비밀번호와 다른 비밀번호를 입력해주세요.', alert_match_pwd: '새로운 비밀번호와 재입력된 비밀번호가 일치하지 않습니다.', alert_check_pwd: '비밀번호를 확인해주세요.', alert_update_complete: '정보가 수정 되었습니다.', no_group_contents_each_prefix: '우리반 ', no_group_contents_each_suffix: ' 이(가) 없습니다.', no_group_contents_all: '학급에 올라온 컨텐츠가 없습니다.
학급 공유하기에
나만의 작품을 공유해보세요!', hw_closed: '과제 마감', tag_Lecture: '강의', tag_Curriculum: '강의모음', tag_Discuss: '공지', count_ko: '개', no_asgn_within_week: '1주일안에 제출되어야 하는 마감 임박한 과제가 없습니다.', lecture_and_curriculum: '강의 / 강의 모음', assignments_plural: '과제', assignments_singular: '과제', project_plural: '작품', group_news: '새로운 소식', stu_management: '학생 관리', stu_management_camel: '학생 관리', view_all: '전체 보기', view_all_camel: '전체 보기', view_contents_camel: '콘텐츠 보기', view_contents: '콘텐츠 보기', no_updated_news: '나의 학급에 올라온 새로운 소식이 없습니다.', homework_soon_due: '곧 마감 과제', new_homework: '최신 과제', no_new_homework: '새로운 과제가 없습니다.', student_plural: '학생', discuss: '공지', basic_project: '기본 작품', no_permission: '권한이 없습니다.', no_comment_write_permission: '현재 로그인된 계정으로는 답변을 작성하실 수 없습니다.', original_curriculum_deleted: '원본 강의 모음이 삭제되었습니다.', original_curriculum: '원본 강의 모음', save_as_my_lecture: '복사본으로 저장하기 ', delete_confirm: '삭제 알림', lecture_open_as_copied: '오픈 강의 페이지에 올라간 모든 강의는 사본으로 생성되어 공개 됩니다.', curriculum_open_as_copied: '오픈 강의 모음 페이지에 올라간 모든 강의 모음은 사본으로 생성되어 공개 됩니다.', lecture_save_as_copied_group: '우리 반 강의 페이지에 올라간 모든 강의는 사본으로 생성되어 공개 됩니다.', curriculum_save_as_copied_group: '우리 반 강의 모음 페이지에 올라간 모든 강의 모음은 사본으로 생성되어 공개 됩니다.', homework_save_as_copied_group: '우리 반 과제 페이지에 올라간 모든 과제는 사본으로 생성되어 공개 됩니다.', lecture_save_as_copied: '내가 만든 강의 모음 안에 삽입된 구성 강의는 사본으로 생성되어 저장됩니다.', done_project_save_as_copied: '내가 만든 강의 안에 삽입된 완성 작품은 사본으로 생성되어 저장됩니다.', textbook_project_can_not_applied: '교과형 만들기(실과)로 만들어진 작품은 강의로 만들 수 없습니다.', original_lecture_deleted: '원본 강의가 삭제되었습니다.', original_lecture: '원본 강의', lecture_save_as_mine_alert: "저장되었습니다.\n저장된 강의는 '마이페이지> 나의 강의'에서 확인할 수 있습니다.", lecture_save_as_mine: '내 강의로 저장하기', duplicate_username: '이미 입력한 아이디 입니다.', share_your_project: '내가 만든 작품을 공유해 보세요', not_available_student: "학급에서 발급된 '학급 아이디'입니다.\n'엔트리 회원 아이디'를 입력해주세요.", login_instruction: '로그인 안내', login_needed: '로그인 후 이용할 수 있습니다.', login_as_teacher: '선생님 계정으로 로그인 후 이용할 수 있습니다.', remove_my_storage: '나의 보관함에서 삭제하시겠습니까? 삭제한 블록/오브젝트는 복구할 수 없습니다.', submit_hw: '과제 제출하기', success_goal: '목표성공', choseok_final_result: '좋아 , 나만의 작품을 완성했어!', choseok_fail_msg_timeout: '시간이 너무 많이 지나버렸어. 목표를 잘 보고 다시 한번 도전해봐!', choseok_fail_msg_die: '생명이 0이하인데 게임이 끝나지 않았어.\n아래의 블록을 사용해서 다시 도전해 보는 건 어때?', grade_1: '초급', grade_2: '중급', grade_3: '고급', find_sally_title: '샐리를 찾아서', save_sally_title: '샐리 구하기', exit_sally_title: '샐리 탈출하기', find_sally: '라인 레인저스의 힘을 모아 \n강력한 악당 메피스토를 물리치고 샐리를 구해주세요!', save_sally: '메피스토 기지에 갇힌 샐리. \n라인 레인저스가 장애물을 피해 샐리를 찾아갈 수 있도록\n도와주세요!', exit_sally: '폭파되고 있는 메피스토 기지에서 \n샐리와 라인 레인저스가 무사히 탈출할 수 있도록\n도와주세요!', go_next_mission: '다른 미션 도전하기', share_my_project: '내가 만든 작품 공유하기', share_certification: '인증서 공유하기', print_certification: '인증서를 뽐내봐', get_cparty_events: '내가 받은 인증서를 출력해 뽐내면 푸짐한 상품을 받을 수 있어요!', go_cparty_events: '이벤트 참여하러 가기', codingparty2016_blockHelper_1_title: '앞으로 가기', codingparty2016_blockHelper_1_contents: '앞으로 가기', codingparty2016_blockHelper_2_title: '앞으로 가기', codingparty2016_blockHelper_2_contents: '회전하기', codingparty2016_blockHelper_3_title: '앞으로 가기', codingparty2016_blockHelper_3_contents: '돌 부수기', codingparty2016_blockHelper_4_title: '앞으로 가기', codingparty2016_blockHelper_4_contents: '횟수 반복하기', codingparty2016_blockHelper_5_title: '앞으로 가기', codingparty2016_blockHelper_5_contents: '꽃 던지기', codingparty2016_goalHint_1: '샐리를 구하기 위해서는 미네랄이 필요해! 미네랄을 얻으며 목적지까지 가보자!', codingparty2016_goalHint_2: '구불구불한 길이 있네. 회전 블록을 사용하면 어렵지 않을 거야!', codingparty2016_goalHint_3: '앞이 돌로 막혀있잖아? 돌을 부수며 목적지까지 가보자!', codingparty2016_goalHint_4: '복잡한 길이지만 지금까지 배운 것들로 해결할 수 있어!', codingparty2016_goalHint_5: '앞으로 쭉 가는 길이잖아? 반복 블록을 사용하여 간단하게 해결해 보자!', codingparty2016_goalHint_6: '미네랄을 모두 모아오자. 반복블록을 쓰면 쉽게 다녀올 수 있겠어!', codingparty2016_goalHint_7: '친구들이 다치지 않도록 꽃을 던져 거미집을 제거해야 해. 저 멀리 있는 거미집을 제거하고 목적지까지 가 보자.', codingparty2016_goalHint_8: '가는 길에 거미집이 많잖아? 거미집을 모두 제거하고 목적지까지 가 보자.', codingparty2016_goalHint_9: '거미집 뒤쪽에 있는 미네랄을 모두 모아오자!', codingparty2016_guide_1_1_contents: '라인 레인저스 전사들이 샐리를 구할 수 있도록 도와줘! 전사들을 움직이기 위해서는 블록 명령어를 조립해야 해.\n\n① 먼저 미션 화면과 목표를 확인하고,\n② 블록 꾸러미에서 필요한 블록을 가져와 “시작하기를 클릭했을 때“ 블록과 연결해.\n③ 다 조립되면 ‘시작하기‘ 버튼을 눌러 봐! 블록이 위에서부터 순서대로 실행되며 움직일 거야.', codingparty2016_guide_1_1_title: '라인 레인저스 전사들을 움직이려면?', codingparty2016_guide_1_2_title: '목표 블록의 개수', codingparty2016_guide_1_2_contents: '① [안 칠해진 별]의 개수만큼 블록을 조립해 미션을 해결해보자. 목표 블록보다 더 많은 블록을 사용하면 별이 빨간색으로 바뀌니 정해진 개수 안에서 문제를 해결해 봐!\n② 필요하지 않은 블록은 휴지통 또는 블록꾸러미에 넣어줘.', codingparty2016_guide_1_3_title: "'앞으로 가기' 블록을 사용하기", codingparty2016_guide_1_3_contents: '< 앞으로 가기 > 는 앞으로 한 칸 이동하는 블록이야. \n\n여러 칸을 이동하기 위해서는 이 블록을 여러 번 연결해야 해.', codingparty2016_guide_1_4_title: '미네랄 획득하기', codingparty2016_guide_1_4_contents: '[ 미네랄 ]이 있는 곳을 지나가면 미네랄을 획득할 수 있어\n\n화면에 있는 미네랄을 모두 획득하고 목적지에 도착해야만 다음 단계로 넘어갈 수 있어.', codingparty2016_guide_1_5_title: '어려울 때 도움을 받으려면?', codingparty2016_guide_1_5_contents: '미션을 수행하다가 어려울 땐 3가지 종류의 도움말 버튼을 눌러 봐.\n\n\n<안내> 지금 이 안내를 다시 보고 싶을 때!\n<블록 도움말> 블록 하나하나가 어떻게 동작하는지 궁금할 때!\n<맵 힌트> 이 단계를 해결하기 위한 힌트가 필요할 때!', codingparty2016_guide_2_1_title: '회전 블록 사용하기', codingparty2016_guide_2_1_contents: '<오른쪽으로 돌기>와 <왼쪽으로 돌기>는 \n제자리에서 90도 회전하는 블록이야. 방향만 회전하는 블록이야. \n캐릭터가 바라보고 있는 방향을 기준으로 오른쪽인지 왼쪽인지 잘 생각해 봐!\n', codingparty2016_guide_3_1_title: '(문) 능력 사용하기', codingparty2016_guide_3_1_contents: '라인 레인저스 전사들을 각자의 능력을 가지고 있어.\n나 [문] 은 <발차기하기> 로 바로 앞에 있는 [돌]을 부술 수 있어.\n[돌을] 부수고 나면 막힌 길을 지나갈 수 있겠지?\n화면에 있는 [돌]을 모두 제거해야만 다음 단계로 넘어갈 수 있어.\n그렇지만 명심해! 아무 것도 없는 곳에 능력을 낭비해서는 안 돼!', codingparty2016_guide_5_1_title: "'~번 반복하기' 블록 사용하기", codingparty2016_guide_5_1_contents: '똑같은 일을 반복해서 명령하는 건 매우 귀찮은 일이야.\n이럴 땐 명령을 사용하면 훨씬 쉽게 명령을 내릴 수 있어. \n< [ ? ] 번 반복하기> 블록 안에 반복되는 명령 블록을 넣고 \n[ ? ] 부분에 횟수를 입력하면 입력한 횟수만큼 같은 명령을 반복하게 돼.', codingparty2016_guide_5_2_title: "'~번 반복하기' 블록 사용하기", codingparty2016_guide_5_2_contents: "'< [ ? ] 번 반복하기> 블록 안에는 여러 개의 명령어를 넣을 수도 있으니 잘 활용해봐! \n도착지에 도착했더라도 반복하기 블록 안에 있는 블록이 모두 실행돼.\n 즉, 위 상황에서 목적지에 도착한 후에도 왼쪽으로 돈 다음에야 끝나는 거야!", codingparty2016_guide_7_1_title: '(코니) 능력 사용하기', codingparty2016_guide_7_1_contents: '나 ‘코니’는 <꽃 던지기>로 먼 거리에서도 앞에 있는 [거미집]을 없앨 수 있어.\n[거미집]을 없애고 나면 막힌 길을 지나갈 수 있겠지?\n화면에 있는 [거미집]을 모두 제거해야만 다음 단계로 넘어갈 수 있어.\n그렇지만 명심해! 아무것도 없는 곳에 능력을 낭비해서는 안 돼!', codingparty2016_guide_9_1_title: '조건 반복 블록 사용하기', codingparty2016_guide_9_1_contents: '반복하는 횟수를 세지 않아도, 어떤 조건을 만족할 때까지 행동을 반복할 수 있어.\n< [목적지]에 도착할 때까지 반복하기 > 블록 안에 반복되는 명령 블록을 넣으면 [목적지]에 도착할 때까지 명령을 반복해.', codingparty2016_guide_9_2_title: '조건 반복 블록 사용하기', codingparty2016_guide_9_2_contents: '<[목적지]에 도착할 때까지 반복하기> 블록 안에는 여러 개의 명령어를 넣을 수도 있으니 잘 활용해봐!\n 도착지에 도착했더라도 반복하기 블록 안에 있는 블록이 모두 실행 돼. 즉, 위 상황에서 목적지에 도착한 후에도 왼쪽으로 돈 다음에야 끝나는 거야!', find_interesting_lesson: "'우리 반 강의'에서 다양한 강의를 만나보세요!", find_interesting_course: "'우리 반 강의 모음'에서 다양한 강의를 만나보세요!", select_share_settings: '공유 공간을 선택해주세요.', faq_banner_title: '자주하는 질문 안내', check_out_faq: '궁금한 점을 확인하세요.', faq_banner_content: '엔트리에 대해 궁금하세요?
자주하는 질문을 통해 답변을 드리고 있습니다.
지금 바로 확인하세요!', faq_banner_button: '자주하는 질문
바로가기', major_updates: '주요 업데이트 안내', check_new_update: '엔트리의 변화를 확인하세요.', major_updates_notification: '엔트리의 주요 변경사항을 공지를 통해 안내해 드리고 있습니다.', find_out_now: '지금 바로 확인하세요!', offline_hw_program: '오프라인 & 하드웨어 연결 프로그램', read_more: '자세히 보기', sample_project: '예시 작품', not_supported_function: '이 기기에서는 지원하지 않는 기능입니다.', offline_download_confirm: '엔트리 오프라인 버전은 PC에서만 이용가능합니다. 다운로드 하시겠습니까?', hardware_download_confirm: '엔트리 하드웨어는 PC에서만 이용가능합니다. 다운로드 하시겠습니까?', copy_text: '텍스트를 복사하세요.', select_openArea_space: '작품 공유 공간을 선택해 주세요', mission_guide: '미션 해결하기 안내', of: ' 의', no_results_found: '검색 결과가 없습니다.', upload_pdf: 'PDF 자료 업로드', select_basic_project: '작품 선택하기', try_it_out: '만들어 보기', go_boardgame: '엔트리봇 보드게임 바로가기', go_cardgame: '엔트리봇 카드게임 바로가기', go_solve: '미션으로 학습하기', go_ws: '엔트리 만들기 바로가기', go_arts: '엔트리 공유하기 바로가기', group_delete_alert: '학급을 삭제하면, 해당 학급에서 발급한 학생임시계정을 포함하여 관련한 모든 자료가 삭제됩니다.\n정말 삭제하시겠습니까?', view_arts_list: '다른 작품 보기', hw_submit_confirm_alert: '과제가 제출 되었습니다.', hw_submit_alert: '과제를 제출 하시겠습니까? ', hw_submit_alert2: '과제를 제출하시겠습니까? 제출 시 학습 완료한 학습 단계까지만 제출이 됩니다.', hw_submit_cannot: '제출 할 수 없는 과제입니다.', see_other_missions: '다른 미션 보기', project: ' 작품', marked: ' 관심', group: '학급', lecture: '강의', Lecture: '강의', curriculum: '강의 모음', Curriculum: '강의 모음', studying: '학습 중인', open_only_shared_lecture: '오픈 강의 페이지에 <공개> 한 강의만 불러올 수 있습니다. 불러오고자 하는 강의공개여부를 확인해 주세요.', already_exist_group: '이미 존재하는 학급 입니다.', cannot_invite_you: '자기 자신을 초대할 수 없습니다.', apply_original_image: '원본 이미지 그대로 적용하기', draw_new_ques: '새로 그리기 페이지로\n이동하시겠습니까?', draw_new_ques_1: '그림을 그려 오브젝트로 저장할 수 있습니다.', draw_new_ques_2: '그리기 화면으로 이동하시겠습니까?', draw_new_go: '이동하기', draw_new_stay: '이동하지 않기', file_upload_warn_title_image: '아래와 같은 그림은 이용약관 및 관련 법률에 의해 제재를 받으실 수 있습니다.', file_upload_warn_desc_image: '폭력적이고 잔인한 그림
선정적인 신체노출 그림
불쾌감을 주거나 혐오감을 일으키는 그림
무단 사용이 금지된 저작권의 그림', file_upload_warn_title_sound: '아래와 같은 소리는 이용약관 및 관련 법률에 의해 제재를 받을 수 있습니다.', file_upload_warn_desc_sound: '폭력적이고 잔인한 소리
선정적인 내용의 소리
불쾌감을 주거나 혐오감을 일으키는 소리
무단 사용이 금지된 저작권의 소리', file_upload_warn_title_table: '아래와 같은 데이터는 이용약관 및 관련 법률에 의해 제재를 받으실 수 있습니다.', file_upload_warn_desc_table: '폭력적이고 잔인한 내용의 데이터
선정적인 내용의 데이터
불쾌감을 주거나 혐오단어가 포함된 데이터
무단 사용이 금지된 저작권의 데이터', file_upload_warn_link: '저작권에 대해 알아보기', file_upload_desc_1: '이런 그림은 \n 안돼요!', file_upload_desc_2: '폭력적이고 잔인한 그림', file_upload_desc_3: '선정적인 신체노출 그림', file_upload_desc_4: '불쾌감을 주거나 혐오감을 일으키는 그림', file_upload_desc_5: '* 위와 같은 내용은 이용약관 및 관련 법률에 의해 제재를 받으실 수 있습니다.', picture_upload_warn_old: '10MB 이하의 jpg, png, bmp 형식의 파일을 추가할 수 있습니다.', sprite_upload_warn_old: '10MB 이하의 jpg, png, bmp 이미지 또는 eo 형식의 오브젝트를 추가할 수 있습니다.', picture_upload_warn_1: '10MB 이하의 jpg, png, bmp, svg 형식의 파일을 추가할 수 있습니다.\njpg, png, bmp 형식은 비트맵 모드, svg 형식은 벡터 모드로 편집됩니다.', table_upload_warn_1: '10MB 이하의 csv, xls(x) 형식의 파일을 추가할 수 있습니다. xls(x) 형식의 경우, 함수 문장이 그대로 출력됩니다.', sprite_upload_warn: '10MB 이하의 jpg, png, bmp, svg 이미지 또는 eo 형식의 오브젝트를 추가할 수 있습니다.', sound_upload_warn_1: '10MB 이하의 mp3 형식의 파일을 추가할 수 있습니다.', sound_edit_warn: '기다려 주세요!
새로운 소리 편집 기능을 연구 중입니다.', file_upload_loading: '로딩중', lesson_by_teacher: '선생님들이 직접 만드는 강의입니다.', delete_group_art: '학급 공유하기 목록에서 삭제 하시겠습니까?', elementary_short: '초등', middle_short: '중등', grade_34: '3-4학년', grade_56: '5-6학년', grade_78: '중등', share_lesson: '강의 공유하기', share_course: '강의 모음 공유하기', from_list_ko: '을(를)', comming_soon: '준비중입니다.', no_class_alert: "선택된 학급이 없습니다. 학급이 없는경우 '나의 학급' 메뉴에서 학급을 만들어 주세요.", students_cnt: '명', defult_class_alert_1: '', defult_class_alert_2: '을(를) \n 기본학급으로 설정하시겠습니까?', default_class: '기본학급입니다.', enter_hw_name: '과제의 제목을 입력해 주세요.', hw_limit_20: '과제는 20개 까지만 만들수 있습니다.', stu_example: '예)\n 홍길동\n 홍길동\n 홍길동', hw_description_limit_200: '생성 과제에 대한 안내 사항을 입력해 주세요. (200자 이내)', hw_title_limit_50: '과제명을 입력해 주세요. (50자 이내)', create_project_class_1: "'만들기 > 작품 만들기' 에서", create_project_class_2: '학급에 공유하고 싶은 작품을 만들어 주세요.', create_lesson_assignment_1: "'만들기> 오픈 강의 만들기'에서 ", create_lesson_assignment_2: '우리 반 과제에 추가하고 싶은 강의를 만들어 주세요.', i_make_lesson: '내가 만드는 강의', lesson_to_class_1: "'학습하기>오픈 강의'에서 우리반", lesson_to_class_2: '과제에 추가하고 싶은 강의를 관심강의로 등록해 주세요.', studying_students: '학습자', lessons_count: '강의수', group_out: '나가기', enter_group_code: '학급코드 입력하기', no_group_invite: '학급 초대가 없습니다.', done_create_group: '개설이 완료되었습니다.', set_default_group: '기본학급 설정', edit_group_info: '학급 정보 관리', edit_done: '수정 완료되었습니다.', alert_group_out: '학급을 정말 나가시겠습니까?', lesson_share_cancel: '강의 공유 취소', project_share_cancel: '작품 공유 취소', lesson_share_cancel_alert: '작품을 비공개로 하시겠습니까?', course_share_cancel: '강의 모음 공유 취소', select_lesson_share: '강의 공유 공간 선택', select_project_share: '작품 공유 선택', select_lesson_share_policy_1: '강의를 공유할', select_lesson_share_policyAdd: '공간을 선택해 주세요', select_lesson_share_project_1: '작품을 공유할 공간과', select_lesson_share_policy_2: '저작권 정책을 확인해 주세요.', select_lesson_share_area: '강의 공유 공간을 선택해 주세요', select_project_share_area: '작품 공유 공간을 선택해 주세요', lesson_share_policy: '강의 공유에 따른 엔트리 저작권 정책 동의', project_share_policy: '작품 공유에 따른 엔트리 저작권 정책 동의', alert_agree_share: '공개하려면 엔트리 저작물 정책에 동의하여야 합니다.', alert_agree_all: '모든 항목에 동의해 주세요.', select_course_share: '강의 모음 공유 공간 선택', select_course_share_policy_1: '강의 모음을 공유할', select_course_share_policy_2: '저작권 정책을 확인해 주세요.', select_course_share_area: '강의 모음 공유 공간을 선택해 주세요', course_share_policy: '강의 모음 공유에 따른 엔트리 저작권 정책 동의', issued: '발급', code_expired: "코드가 만료되었습니다. '코드재발급' 버튼를 누르세요.", accept_class_invite: '학급초대 수락하기', welcome_class: '학급에 오신것을 환영합니다.', enter_info: '자신의 정보를 입력해주세요.', done_group_signup: '학급 가입이 완료되었습니다.', enter_group_code_stu: '선생님께 받은 코드를 입력해주세요.', text_limit_50: '50글자 이하로 작성해 주세요.', enter_class_name: '학급 이름을 입력해 주세요.', enter_grade: '학년을 입력해 주세요.', enter_class_info: '학급소개를 입력해 주세요.', student_dup: '은(는) 이미 학급에 존재합니다.', select_stu_print: '출력할 학생을 선택하세요.', class_id_not_exist: '학급 ID가 존재하지 않습니다.', error_try_again: '오류 발생. 다시 한 번 시도해 주세요.', error_forbidden: '권한이 없습니다.', code_not_available: '유효하지 않은 코드입니다.', gnb_create_lessons: '오픈 강의 만들기', study_lessons: '강의 학습하기', lecture_help_1: '학습을 시작할 때, 사용할 작품을 선택해 주세요. 선택한 작품으로 학습자가 학습을 시작하게 됩니다.', lecture_help_2: '이도움말을 다시 보시려면 위 버튼을 클릭해 주세요.', lecture_help_3: '오브젝트 추가하기가 없으면새로운 오브젝트를 추가하거나 삭제 할 수 없습니다.', lecture_help_4: '학습도중에 PDF자료보기를 통해 학습에 도움을 받을 수 있습니다.', lecture_help_5: '학습에 필요한 블록들만 선택해주세요. 선택하지 않은 블록은 숨겨집니다.', lecture_help_6: '블록코딩과 엔트리파이선 중에 선택하여 학습환경을 구성할 수 있습니다.', lecture_finish_popup_title: '학습 다시하기', lecture_finish_popup_content_1: '실습완료한 단계를
처음부터 다시 실습하시겠습니까?', lecture_finish_popup_content_2: '* 다시 실습해도 실습 완료 상태는 유지됩니다.', lecture_start_title: '학습 시작', lecture_goal_title: '학습 목표', lecture_goal_content: '무엇을 배울지 알아볼까요?', lecture_prepare_title: '학습 준비', lecture_summary_title: '학습 정리', lecture_summary_content: '배운 내용을 정리해 봅시다.', lecture_quiz_title: '확인 문제', lecture_quiz_content: '확인 문제를 통해 배운 내용을 점검해 봅시다.', lecture_quiz_check_answer: '정답확인', default_hint_title: '어떻게 만들까?', only_pdf: '.pdf형식의 파일만 입력 가능합니다.', enter_project_video: '적어도 하나의 작품이나 영상을 입력하세요.', enter_title: '제목을 입력하세요.', enter_recommanded_grade: '추천 학년을 입력하세요.', enter_level_diff: '난이도를 입력하세요.', enter_time_spent: '소요시간을 입력하세요.', enter_shared_area: '적어도 하나의 공유 공간을 선택하세요.', enter_goals: '학습목표를 입력하세요.', enter_lecture_description: '강의 설명을 입력하세요.', enter_curriculum_description: '강의 모음 설명을 입력하세요.', first_page: '처음 입니다.', last_page: '마지막 입니다.', alert_duplicate_lecture: '이미 등록된 강의는 다시 등록할 수 없습니다.', enter_lesson_alert: '하나 이상의 강의를 등록해주세요.', open_edit_lessons: '편집할 강의를 불러오세요.', saved_alert: '이(가) 저장되었습니다.', select_lesson_type: '어떤 학습과정을 만들지 선택해 주세요 ', create_lesson: '강의 만들기', create_lesson_desc_1: '원하는 학습 목표에 맞춰', create_lesson_desc_2: '단일 강의를 만들어', create_lesson_desc_3: '학습에 활용합니다.', create_courseware: '강의 모음 만들기', create_courseware_desc_1: '학습 과정에 맞춰 여러개의 강의를', create_courseware_desc_2: '하나의 코스로 만들어', create_courseware_desc_3: '학습에 활용합니다.', create_open_lesson: '오픈 강의 만들기 ', enter_lesson_info: '강의 정보 입력 ', select_lesson_feature: '학습 기능 선택 ', check_info_entered: '입력 정보 확인 ', enter_lefo_lesson_long: '강의를 구성하는 정보를 입력해 주세요.', lesson_info_desc: '학습자가 학습하기 화면에서 사용할 기능과 작품을 선택함으로써, 학습 목표와 내용에 최적화된 학습환경을 구성할 수 있습니다.', provide_only_used: '완성된 작품에서 사용된 블록만 불러오기', see_help: '도움말 보기', select_done_project_1: '학습자가 목표로 설정할', select_done_project_2: '완성 작품', select_done_project_3: '을 선택해 주세요.', select_project: '나의 작품 또는 관심 작품을 불러옵니다. ', youtube_desc: '유튜브 공유 링크를 통해 원하는 영상을 넣을 수 있습니다.', lesson_video: '강의 영상', lesson_title: '강의 제목', recommended_grade: '추천학년', selection_ko: '선택', selection_en: '', level_of_diff: '난이도', select_level_of_diff: '난이도 선택', enter_lesson_title: '강의 제목을 입력해 주세요(30자 이내)', select_time_spent: '소요시간 선택 ', time_spent: '소요시간', lesson_overview: '강의설명', upload_materials: '학습 자료 업로드', open: '불러오기', cancel: '취소하기', upload_lesson_video: '강의 영상 업로드', youtube_upload_desc: '유튜브 공유링크를 통해 보조영상을 삽입할 수 있습니다. ', cancel_select: '선택 취소하기', select_again: '다시 선택하기', goal_project: '완성작품', upload_study_data: '학습하기 화면에서 볼 수 있는 학습자료를 업로드해주세요. 학습자가 업로드된 학습자료의 내용을 확인하며 학습할 수 있습니다. ', upload_limit_20mb: '20MB 이하의 파일을 올려주세요.', expect_time: '예상 소요 시간', course_videos: '보조 영상', enter_courseware_info: '강의 모음 정보 입력 ', enter_course_info: '강의 모음을 소개하는 정보를 입력해 주세요 ', select_lessons_for_course: '강의 모음을 구성하는 강의를 선택해 주세요.', course_build_desc_1: '강의는', course_build_desc_2: '최대30개', course_build_desc_3: '등록할 수 있습니다.', lseeon_list: '강의 목록 보기', open_lessons: '강의 불러오기', course_title: '강의 모음 제목', title_limit_30: '강의 모음 제목을 입력해 주세요(30자 이내) ', course_overview: '강의 모음 설명', charactert_limit_200: '200자 이내로 작성할 수 있습니다.', edit_lesson: '강의 편집', courseware_by_teacher: '선생님들이 직접 만드는 강의 모음입니다.', select_lessons: '구성 강의 선택', check_course_info: '강의 모음을 구성하는 정보가 올바른지 확인해 주세요.', select_share_area: '공유 공간 선택', upload_sub_project: '목표 작품 업로드', file_download: '첨부파일 다운로드', file_remove: '첨부파일 삭제', check_lesson_info: '강의를 구성하는 정보가 올바른지 확인해 주세요.', share_area: '공유 공간', enter_sub_project: '엔트리 보조 프로젝트를 등록해 주세요.', lms_hw_title: '과제 제목', lms_hw_ready: '준비', lms_hw_progress: '진행중', lms_hw_complete: '완료', lms_hw_not_submit: '미제출', lms_hw_closed: '제출마감', submission_condition: '진행중인 과제만 제출이 가능합니다.', submit_students_only: '학생만 과제를 제출할 수 있습니다.', want_submit_hw: '과제를 제출하시겠습니까?', enter_correct_id: '올바른 아이디를 입력해 주세요.', id_not_exist: '아이디가 존재하지 않습니다. ', agree_class_policy: '학급 서비스 이용약관에 동의해 주세요.', delete_class: '학급 삭제', type_stu_name: '학생 이름을 입력해주세요. ', invite_from_1: '에서', invite_from_2: '님을 초대하였습니다. ', lms_pw_alert_1: '학급에 소속되면, 선생님 권한으로', lms_pw_alert_2: '비밀번호 재발급이 가능합니다.', lms_pw_alert_3: '선생님의 초대가 맞는지 한번 더 확인해주세요.', invitation_accepted: '초대 수락이 완료되었습니다!', cannot_issue_pw: '초대를 수락하지 않았으므로 비밀번호를 발급할 수 없습니다.', start_me_1: '<월간 엔트리>와 함께', start_me_2: 'SW교육을 시작해보세요!', monthly_desc_1: '<월간 엔트리>는 소프트웨어 교육에 익숙하지 않은 선생님들도 쉽고 재미있게', monthly_desc_2: '소프트웨어 교육을 하실 수 있도록 만들어진 SW교육 잡지입니다.', monthly_desc_3: '매월 재미있는 학습만화와 함께 하는 SW 교육 컨텐츠를 만나보세요!', monthly_desc_4: '* 월간엔트리는 2015년 11월 ~ 2016년 5월까지 발행 후 중단되었습니다.', monthly_desc_5: '엔트리의 교육자료는 교육자료 페이지에서 만나보세요.', monthly_entry: '월간 엔트리', me_desc_1: '매월 발간되는 무료 소프트웨어 교육잡지', me_desc_2: '월간엔트리를 만나보세요!', solve_desc_1: '게임을 하듯 미션을 해결하며', solve_desc_2: '소프트웨어의 기본 원리를 배워보세요!', playSw_desc_1: 'EBS 방송영상, 특별영상을 통해', playSw_desc_2: '소프트웨어를 배워보세요!', recommended_lessons: '추천 강의 모음', recommended_lessons_1: '따라하고, 도전하고, 퀴즈도 풀며 재미있게 엔트리 프로그래밍을 배워보세요!', recommended_lessons_2: '추천 강의 모음을 만나보세요!', offline_top_desc_1: '오프라인 버전의 저장 기능이 향상되고 보안이 강화되었습니다.', offline_top_desc_2: '지금 바로 다운받으세요', offline_main_desc: '엔트리 오프라인 에디터 업데이트!!', art_description: '엔트리로 만든 작품을 공유하는 공간입니다. 작품을 만들고 공유에 참여해 보세요.', art_description_1: '엔트리로 총 ', art_description_2: '개의 작품이 만들어졌습니다. 작품을 만들고 공유해 보세요.', study_index: '엔트리에서 제공하는 주제별, 학년별 학습과정을 통해 차근차근 소프트웨어를 배워보세요!', study_for_beginner: '처음 시작하는 사람들을 위한 엔트리 첫걸음', entrybot_desc_3: '안내에 따라 블록 명령어를 조립하여', entrybot_desc_4: '엔트리봇을 학교에 데려다 주세요.', move_entrybot: '엔트리봇 움직이기', can_change_entrybot_1: '블록 명령어로 엔트리봇의 색을 바꾸거나', can_change_entrybot_2: '말을 하게 할 수도 있어요.', learning_process_by_topics: '주제별 학습과정', show_detail: '자세히 보기', solve_mission: '미션 해결하기', solve_mission_desc_1: '게임을 하듯 미션을 해결하며 프로그래밍의 원리를 익혀보세요!', solve_mission_desc_2: '미로 속의 엔트리봇을 목적지까지 움직이며 순차, 반복, 선택, 비교연산 등의 개념을 자연스럽게 익힐 수 있어요.', learning_process_by_grades: '학년별 학습과정', learning_process_by_grades_sub1: '4가지 유형으로 쉽고 재미있게 배우는 프로그래밍의 원리! 지금 시작해보세요!', e3_to_e4: '초등 3-4 학년', e5_to_e6: '초등 5-6 학년', m1_to_m3: '중등 이상', make_using_entry: '엔트리로 만들기', make_using_entry_desc_1: '블록을 쌓아 여러 가지 소프트웨어를 만들어보세요!', make_using_entry_desc_2: '제공되는 교재를 다운받아 차근차근 따라하다보면 애니메이션, 미디어아트, 게임 등 다양한 작품을 만들 수 있어요.', make_through_ebs_1: 'EBS 방송영상으로 소프트웨어를 배워보세요.', make_through_ebs_2: '방송영상은 물론, 차근차근 따라 할 수 있는 특별영상과 함께 누구나 쉽게 다양한 소프트웨어를 만들 수 있어요.', support_block_js: '블록 코딩과 자바스크립트 언어를 모두 지원합니다.', study_ebs_title_1: '순서대로! 차례대로!', study_ebs_desc_1: '[실습] 엔트리봇의 심부름', study_ebs_title_2: '쉽고 간단하게!', study_ebs_desc_2: '[실습] 꽃송이 만들기', study_ebs_title_3: '언제 시작할까?', study_ebs_desc_3: '[실습] 동물가족 소개', study_ebs_title_4: '다른 선택, 다른 결과!', study_ebs_desc_4: '[실습] 텔레파시 게임', study_ebs_title_5: '정보를 담는 그릇', study_ebs_desc_5: '[실습] 덧셈 로봇 만들기', study_ebs_title_6: '요모조모 따져 봐!', study_ebs_desc_6: '[실습] 복불복 룰렛', study_ebs_title_7: '번호로 부르면 편해요!', study_ebs_desc_7: '[실습] 나만의 버킷리스트', study_ebs_title_8: '무작위 프로그램을 만들어라!', study_ebs_desc_8: '[실습] 무작위 캐릭터 만들기', study_ebs_title_9: '어떻게 찾을까?', study_ebs_desc_9: '[실습] 도서관 책 검색', study_ebs_title_10: '줄을 서시오!', study_ebs_desc_10: '[실습] 키 정렬 프로그램', event: '이벤트', divide: '분기', condition: '조건', random_number: '무작위수', search: '탐색', sorting: '정렬', parallel: '병렬', signal: '신호', input_output: '입출력', sequential: '순차', repeat: '반복', choice: '선택', repeat_advanced: '반복(횟수+조건)', function: '함수', compare_operation: '비교연산', arithmetic: '산술연산', entry_recommended_mission: '엔트리 추천 미션', more_mission: '더 많은 미션 보러가기', line_rangers_title: '라인레인저스와\n샐리 구하기', line_rangers_content: '메피스토 기지에 갇힌\n샐리를 구해주세요!', pinkbean_title_string_basic: '메이플스토리 초급 헤네시스', pinkbean_title_string_intermediate: '메이플스토리 중급 엘리니아', pinkbean_title_string_advanced: '메이플스토리 고급 엘나스', pinkbean_title: '핑크빈과 함께 신나는\n메이플 월드로!', pinkbean_content: '핑크빈이 메이플 월드 모험을\n무사히 마칠 수 있도록 도와주세요.', entrybot_school: '엔트리봇 학교 가는 길', entrybot_school_desc_1: '엔트리봇이 책가방을 챙겨 학교에', entrybot_school_desc_2: '도착할 수 있도록 도와주세요!', robot_factory: '로봇 공장', robot_factory_desc_1: '로봇공장에 갇힌 엔트리봇!', robot_factory_desc_2: '탈출하기 위해 부품을 모두 모아야해요.', electric_car: '전기 자동차', electric_car_desc_1: '엔트리봇 자동차가 계속 앞으로 나아갈 수', electric_car_desc_2: '있도록 연료를 충전해 주세요.', forest_adventure: '숲속 탐험', forest_adventure_desc_1: '엔트리봇 친구가 숲속에 갇혀있네요!', forest_adventure_desc_2: '친구를 도와주세요.', town_adventure: '마을 탐험', town_adventure_desc_1: '배고픈 엔트리봇을 위해 마을에 있는', town_adventure_desc_2: '연료를 찾아주세요.', space_trip: '우주 여행', space_trip_desc_1: '우주탐사를 마친 엔트리봇!', space_trip_desc_2: '지구로 돌아갈 수 있도록 도와주세요.', learn_programming_mission: '미션을 해결하며 배우는 프로그래밍', make_open_lecture: '오픈 강의 만들기', group_created: '만든 학급', group_signup: '가입한 학급', delete_from_list: '을(를) 목록에서 삭제하시겠습니까?', delete_from_list_en: '', lecture_collection: '강의 모음', edit_mypage_profile: '자기소개 정보 관리', main_image: '메인 이미지', edit_profile_success: '반영되었습니다.', no_project_1: '내가 만든 작품이 없습니다.', no_project_2: '지금 작품 만들기를 시작해보세요!', empty_project_1: '아직 만들어진 작품이 없습니다.', no_marked_project_1: '관심 작품이 없습니다.', no_marked_group_project_1: '학급 관심 작품이 없습니다.', no_marked_project_2: "'작품 공유하기'에서 다양한 작품을 만나보세요!", no_markedGroup_project_2: "'학급 공유하기'에서 다양한 작품을 만나보세요!", view_project_all: '작품 구경하기', no_lecture_1: '내가 만든 강의가 없습니다.', empty_lecture_1: '아직 만들어진 강의가 없습니다.', no_lecture_2: "'오픈 강의 만들기'에서 강의를 만들어보세요!", no_marked_lecture_1: '관심 강의가 없습니다.', no_marked_group_lecture_1: '학급 관심 강의가 없습니다.', no_marked_lecture_2: "'오픈 강의'에서 다양한 강의를 만나보세요!", view_lecture: '강의 살펴보기', no_studying_lecture_1: '학습 중인 강의가 없습니다.', no_studying_lecture_2: "'오픈 강의'에서 학습을 시작해보세요!", no_lecture_collect_1: '내가 만든 강의 모음이 없습니다.', empty_lecture_collect_1: '아직 만들어진 강의 모음이 없습니다.', no_lecture_collect_2: "'오픈 강의 모음 만들기'에서 강의 모음을 만들어보세요!", make_lecture_collection: '강의 모음 만들기', no_marked_lecture_collect_1: '관심 강의 모음이 없습니다.', no_marked_lecture_group_collect_1: '학급 관심 강의 모음이 없습니다.', no_marked_lecture_collect_2: "'오픈 강의'에서 다양한 강의를 만나보세요!", view_lecture_collection: '강의 모음 살펴보기', no_studying_lecture_collect_1: '학습 중인 강의 모음이 없습니다.', no_studying_lecture_collect_2: "'오픈 강의'에서 학습을 시작해보세요!", my_lecture: '나의 강의', markedGroup: '학급 관심', markedGroup_lecture: '학급 관심 강의', markedGroup_curriculum: '학급 관심 강의모음', marked_lecture: '관심 강의', marked_lecture_collection: '나의 관심 강의 모음', marked_marked_curriculum: '관심 강의 모음', studying_lecture: '학습 중인 강의', completed_lecture: '학습 완료 강의', my_lecture_collection: '나의 강의 모음', my: '나의', studying_lecture_collection: '학습 중인 강의 모음', completed_lecture_collection: '학습 완료한 강의 모음', my_curriculum: '나의 강의 모음', studying_curriculum: '학습 중인 강의 모음', completed_curriculum: '학습 완료한 강의 모음', materialCC: '엔트리에서 제공하는 모든 교육 자료는 CC-BY 2.0 라이선스에 따라 자유롭게 이용할 수 있습니다.', materialccby_new: '엔트리의 교육자료는 CC-BY 2.0 라이선스에 따라 출처를 밝히고 자유롭게 이용할 수 있습니다.', entry_copyright_info: '엔트리 저작권 가이드 보기', pdf: 'PDF', helper: '도움말', youtube: '영상', tvcast: '영상', goal: '목표', basicproject: '시작단계', hw: '하드웨어', object: '오브젝트', console: '콘솔', download_info: '모든 교육자료는 각각의 제목을 클릭 하시면 다운받으실 수 있습니다.', entry_materials_all: '엔트리 교육자료 모음', entry_material: '엔트리 교육자료', recommand_grade: '추천학년', g3_4_grades: '3-4 학년', g5_6_grades: '5-6 학년', middle_grades: '중학생 이상', entry_go_go: '엔트리 고고!', entry_go_go_desc: '학년별, 난이도 별로 준비된 교재를 만나보세요.', entry_go_go_desc2: '각 과정별로 교육과정, 학습지, 교사용 해설서 3종 세트가 제공됩니다.', stage_beginner: '초급', stage_middle: '중급', stage_high: '고급', middle_school_short: '중등', learn_entry_programming: '따라하며 배우는 엔트리 프로그래밍', entry_programming_desc: '차근차근 따라 하다 보면 어느새 나도 엔트리 고수!', ebs: 'EBS', ebs_material_desc: '방송 영상과 교사용 지도서를 활용하여 수업을 해보세요!', season_1_material: '시즌1 교사용 지도서', season_2_material: '시즌2 교사용 지도서', season_1: '시즌1', playsoftware_ebs: 'EBS 소프트웨어야 놀자!', material_teacher_guide: '교사용 지도서', season_2: '시즌2', compute_think_textbook: '교과서로 배우는 컴퓨팅 사고력', computational_sw: '국어, 수학, 과학, 미술... 학교에서 배우는 다양한 교과와 연계하여 SW를 배워보세요!', python_coding_text: '엔트리파이선', python_coding_textbook: '텍스트 코딩 세계로 떠나는 여행! 엔트리파이선', python_coding_desc: '엔트리파이선으로 텍스트 언어의 구조와 문법을 자연스럽게 배워보세요!', entry_x_hardware_text: '엔트리 X 하드웨어 교육자료', entry_x_hardware: '엔트리 X 하드웨어 교육자료 모음', e_sensor: 'E 센서보드', e_sensor_board: 'E 센서보드', e_sensor_robot: 'E 센서로봇', arduino: '아두이노', arduinoext: '아두이노 Uno 확장모드', arduinonano: '아두이노 Nano', albert: '알버트', orange_board: '오렌지보드', arduino_board: '아두이노', joystick: '조이스틱 센서 쉴드', ardublock: '아두블럭', mkboard: '디지털 몽키보드', mechatro_nano: '메카트로 나노+', mechatro_uno: '메카트로 우노+', memaker: '미메이커', edumaker: '에듀메이커 보드', codingtoolbox: '코딩툴박스', materials_etc_all: '기타 교육자료 모음', materials_teaching: '교원 연수 자료', materials_etc: '기타 참고 자료', materials_etc_resource: '참고 자료', materials_teaching_etc: '교원 연수 및 참고자료', materials_teaching_1: 'SW교육의 필요성과 교육 방법론', materials_teaching_2: '엔트리와 함께하는 언플러그드 활동', materials_teaching_3: '게임하듯 알고리즘을 배우는 엔트리 미션 해결하기', materials_teaching_4: '실생활 문제해결을 위한 엔트리 프로그래밍', materials_teaching_5: '교과연계 SW교육1 (미술,수학,사회)', materials_teaching_6: '교과연계 SW교육2 (국어,과학,음악)', materials_teaching_7: '피지컬 컴퓨팅 실습1(E센서보드)', materials_teaching_8: '피지컬 컴퓨팅 실습2(햄스터)', materials_teaching_9: '수업에 필요한 학급/강의 기능 알아보기', materials_etc_1: '엔트리 첫 사용자를 위한 스타트 가이드', materials_etc_2: '수업에 바로 활용할 수 있는 다양한 콘텐츠 모음집', materials_etc_3: '월간 엔트리', materials_etc_4: '엔트리 설명서', materials_etc_5: '엔트리 소개 자료', materials_etc_6: '엔트리 블록 책받침', materials_etc_7: '엔트리파이선 예제 및 안내', jr_if_1: '만약', jr_if_2: '앞에 있다면', jr_fail_no_pencil: '이런 그곳에는 연필이 없어. 연필이 있는 곳에서 사용해보자~', jr_fail_forgot_pencil: '앗! 책가방에 넣을 연필을 깜빡했어. 연필을 모아서 가자~', jr_fail_much_blocks: '너무많은 블록을 사용했어, 다시 도전해볼래?', cparty_jr_success_1: '좋아! 책가방을 챙겼어!', go_right: '오른쪽', go_down: ' 아래쪽', go_up: ' 위쪽', go_left: ' 왼쪽', go_forward: '앞으로 가기', jr_turn_left: '왼쪽으로 돌기', jr_turn_right: '오른쪽으로 돌기', go_slow: '천천히 가기', repeat_until_reach_1: '만날 때 까지 반복하기', repeat_until_reach_2: '', pick_up_pencil: '연필 줍기', repeat_0: '', repeat_1: '반복', when_start_clicked: '시작 버튼을 눌렀을 때', age_0: '작품체험', create_character: '캐릭터 만들기', age_7_9: '초등 저학년', going_school: '엔트리 학교가기', age_10_12_1: '초등 고학년1', collect_parts: '로봇공장 부품모으기', age_10_12_2: '초등 고학년2', driving_elec_car: '전기자동차 운전하기', age_13: '중등', travel_space: '우주여행하기', people: '사람', all: '전체', life: '일상생활', nature: '자연', animal_insect: '동물/곤충', environment: '자연환경', things: '사물', vehicles: '이동수단', others: '기타', fantasy: '판타지', instrument: '악기', piano: '피아노', marimba: '마림바', drum: '드럼', janggu: '장구', sound_effect: '효과음', others_instrument: '기타타악기', aboutEntryDesc_1: '엔트리는 누구나 무료로 소프트웨어 교육을 받을 수 있는 플랫폼입니다.', aboutEntryDesc_2: '학생들이 소프트웨어를 쉽고 재미있게 학습하고,', aboutEntryDesc_3: '선생님들은 효과적으로 학생들을 가르칠 수 있습니다.', aboutEntryDesc_4: '엔트리는 공공재와 같이', aboutEntryDesc_5: '비영리로 운영됩니다.', viewProjectTerms: '이용정책 보기', openSourceTitle: '오픈소스를 통한 생태계 조성', openSourceDesc_1: '엔트리의 소스코드 뿐 아니라', openSourceDesc_2: '모든 교육 자료는 CC라이센스를 ', openSourceDesc_3: '적용하여 공개합니다.', viewOpenSource: '오픈소스 보기', eduPlatformTitle: '국내교육 현장에 맞는 교육 플랫폼', eduPlatformDesc_1: '국내 교육 현장에 적합한 교육 도구가', eduPlatformDesc_2: '될 수 있도록 학교 선생님들과 함께', eduPlatformDesc_3: '개발하고 있습니다.', madeWith: '자문단', researchTitle: '다양한 연구를 통한 전문성 강화', researchDesc_1: '대학/학회 등과 함께 다양한 연구를', researchDesc_2: '진행하여 전문성을 강화해나가고', researchDesc_3: '있습니다.', viewResearch: '연구자료 보기', atEntry: '엔트리에서는', entryLearnDesc_1: '재미있게 배우는 학습공간', entryLearnDesc_2: '<학습하기>에서는 엔트리를 학습할 수 있는 콘텐츠가 준비되어 있습니다.', entryLearnDesc_3: '게임을 하듯이 주어진 미션을 프로그래밍으로 해결하고 영상을 시청하며 ', entryLearnDesc_4: '소프트웨어 제작 원리를 학습할 수 있습니다.', entryMakeDesc_1: '<만들기>에서는 미국 MIT에서 개발한 Scratch와 같은 블록형 프로그래밍 언어를', entryMakeDesc_2: '사용하여 프로그래밍을 처음 접하는 사람들도 쉽게 자신만의 창작물을 만들 수 있습니다.', entryMakeDesc_3: "또한 블록 코딩과 텍스트 코딩의 중간다리 역할을 하는 '엔트리파이선' 모드에서는", entryMakeDesc_4: '텍스트 언어의 구조와 문법을 자연스럽게 익힐 수 있습니다.', entryMakeDesc_5: '', entryShareDesc_1: '<공유하기>에서는 엔트리를 통해 제작한 작품을 다른 사람들과 공유할 수 있습니다.', entryShareDesc_2: '또한 공유된 작품이 어떻게 구성되었는지 살펴보고 발전시켜 자신만의 작품을 만들 수', entryShareDesc_3: '있습니다. 공동 창작도 가능하여 친구들과 협업해 더 멋진 작품을 만들어 볼 수 있습니다.', entryGroup: '학급기능', entryGroupTitle: '우리 반 학습 공간', entryGroupDesc_1: '<학급기능>은 선생님이 학급별로 학생들을 관리할 수 있는 기능입니다. 학급끼리 학습하고', entryGroupDesc_2: '작품을 공유할 수 있으며 과제를 만들고 학생들의 결과물을 확인할 수 있습니다.', entryGroupDesc_3: '또한 선생님은 강의 기능을 활용하여 학생들의 수준에 맞는 학습환경을', entryGroupDesc_4: '맞춤형으로 제공함으로써 효율적이고 편리하게 수업을 진행할 수 있습니다.', entryGroupDesc_5: '', unpluggedToPhysical: '언플러그드 활동부터 피지컬 컴퓨팅까지', algorithmActivity: '기초 알고리즘', programmignLang: '교육용 프로그래밍 언어', unpluggedDesc_1: '엔트리봇 보드게임과 카드게임을 통해 컴퓨터 없이도', unpluggedDesc_2: '소프트웨어의 기본 개념과 원리(순차, 반복, 선택, 함수)를 익힐 수 있습니다.', entryMaze: '엔트리봇 미로탈출', entryAI: '엔트리봇 우주여행', algorithmDesc_1: '게임을 하듯이 미션을 해결하고 인증서를 받아보세요.', algorithmDesc_2: '소프트웨어의 기본적인 원리를 쉽고 재미있게 배울 수 있습니다.', programmingLangDesc_1: '엔트리에서는 블록을 쌓듯이 프로그래밍을 하기 때문에 누구나 쉽게', programmingLangDesc_2: '자신만의 게임, 애니메이션, 미디어아트와 같은 멋진 작품을 만들고 공유할 수 있어 교육용으로 적합합니다.', viewSupporHwVideo: '하드웨어 가이드 영상 보기', viewSupporHw: '연결되는 하드웨어 보기', supportHwDesc_1: '엔트리와 피지컬 컴퓨팅 도구를 연결하면 현실세계와 상호작용하는 멋진 작품들을 만들어낼 수 있습니다.', supportHwDesc_2: '국내, 외 다양한 하드웨어 연결을 지원하며, 계속적으로 추가될 예정입니다.', entryEduSupport: '엔트리 교육 지원', eduSupportDesc_1: '엔트리에서는 소프트웨어 교육을 위한 다양한 교육 자료를 제작하여 무상으로 배포하고 있습니다.', eduSupportDesc_2: '모든 자료는 교육자료 페이지에서 다운받으실 수 있습니다.', materials_1_title: '수준별 교재', materials_1_desc_1: '학년별 수준에 맞는 교재를 통해 차근차근', materials_1_desc_2: '따라하며 쉽게 엔트리를 익혀보세요!', materials_2_title: 'EBS 방송 연계 교안', materials_2_desc_1: 'EBS 소프트웨어야 놀자 방송과 함께', materials_2_desc_2: '교사용 수업 지도안을 제공합니다.', materials_3_title: '초, 중등 교과 연계 수업자료', materials_3_title_2: '', materials_3_desc_1: '다양한 과목에서 만나는 실생활 문제를', materials_3_desc_2: '컴퓨팅 사고력으로 해결해 보세요.', moreMaterials: '더 많은 교육 자료 보러가기', moreInfoAboutEntry_1: '더 많은 엔트리의 소식들을 확인하고 싶다면 아래의 링크들로 접속해보세요.', moreInfoAboutEntry_2: '교육자료 외에도 다양한 SW 교육과 관련한 정보를 공유하고 있습니다.', material_menu_type_robot: '로봇형', material_menu_type_module: '모듈형', material_menu_type_board: '보드형', blog: '블로그', post: '포스트', tvCast: 'TV캐스트', about_entry_pre: '엔트리', about_youtube: '유튜브', about_facebook: '페이스북', albertSchool: '알버트 스쿨버전', arduinoBoard: '아두이노 정품보드', arduinoCompatible: '아두이노 호환보드', bitBlock: '비트블록', bitbrick: '비트브릭', creamo: '크리모', playcode: '플레이코드', funboard: '펀보드', truerobot: '뚜루뚜루', bingle: '빙글', bingles: '빙글S', codeino: '코드이노', epor: '에뽀', petrone_v2: '페트론V2', petrone_v2_drone: '드론', petrone_v2_car: '자동차', 'e-sensor': 'E-센서보드', 'e-sensorUsb': 'E-센서보드(유선연결)', 'e-sensorBT': 'E-센서보드(무선연결)', mechatronics_4d: '4D 메카트로닉스', esensor_board: 'E - 센서보드', esensor_robot: 'E - 센서로봇', hamster: '햄스터', hummingbird: '허밍버드 듀오', roboid: '로보이드', turtle: '거북이', littlebits: '리틀비츠', orangeBoard: '오렌지 보드', robotis_carcont: '로보티즈 로봇자동차', robotis_IoT: '로보티즈 IoT', robotis_IoT_Wireless: '로보티즈 IoT(무선연결)', dplay: '디플레이', iboard: '아이보드', nemoino: '네모이노', xbot_epor_edge: '엑스봇(원터치 동글/USB)', XbotBT: '엑스봇 에뽀/엣지 블투투스', robotori: '로보토리', rokoboard: '로코보드', neobot: '네오봇', neobot_sensor_theme: '네오봇 센서 테마', mechatro: '메카트로', about: '알아보기', articles: '토론하기', gallery: '구경하기', learn: '학습하기', login: '로그인', logout: '로그아웃', make: '만들기', register: '가입하기', Join: '회원가입', Edit_info: '내 정보 수정', Discuss: '글 나누기', Explore: '구경하기', Load: '불러오기', My_lesson: '오픈 강의', textbook_learning: '교과서 학습하기', Resources: '교육 자료', play_software: '소프트웨어야 놀자!', problem_solve: '엔트리 학습하기', learning_textbook: '교과서 학습하기', context_textbook: '초등 교과서 그대로 선생님은 학교 수업을 학생은 집에서 예습, 복습을 할 수 있어요.', info_banner_textbook: '* 출판사는 가나다순 노출입니다.', banner_textbook: '더욱 다양하고', banner_textbook_2: '재미있는 학습을 하고 싶다면?', banner_textbook_right_banner: '학생용 활동지와 교사용', banner_textbook_right_banner2: '학습 도움 자료가 필요하신가요?', banner_textbook_right_banner_btn: '교과서별 자료 받기', Learn: '학습하기', teaching_tools: '엔트리 교구', about_entry: '엔트리 소개', what_entry: '엔트리는?', create: '만들기', create_new: '새로 만들기', start_programming: '소프트웨어 교육의 첫걸음', Entry: '엔트리', intro_learning: '누구나 쉽고 재밌게 소프트웨어를 배울 수 있어요. ', intro_learning_anyone: '지금 바로 시작해보세요! ', start_now: 'For Free, Forever.', welcome_entry: '엔트리에 오신걸 환영합니다.', student: '학생', non_menber: '일반인', teacher: '선생님', terms_conditions: '이용약관', personal_information: '개인정보 수집 및 이용에 대한 안내', limitation_liability: '책임의 한계와 법적 고지', entry_agree: '엔트리의 이용약관에 동의 합니다.', info_agree: '개인정보 수집 및 이용에 동의합니다.', next: '다음', enter_individual_info: '개인정보 입력', enter_id: '아이디 입력', enter_password: '비밀번호 입력', confirm_password: '비밀번호 확인', enter_password_again: '비밀번호를 한번 더 입력하세요.', validation_password: '5자 이상의 영문/숫자 등을 조합하세요.', validation_id: '4~20자의 영문/숫자를 조합하세요', prev: '이전', born_year: '태어난 연도', select_born: '태어난 연도를 선택 하세요', year: '년', gender: '성별', choose_gender: '성별을 선택 하세요', male: '남성', female: '여성', language: '언어', best_language: '주 언어를 선택 하세요', korean: '한국어', english: '영어', viet: '베트남', japan: '일본어', russia: '러시아어', chinese_simplified: '중국어(간체)', chinese_traditional: '중국어(번체)', option_email: '이메일(선택)', insert_email: '이메일 주소를 입력 하세요', sign_up_complete: '회원 가입이 완료 되었습니다', agree_terms_conditions: '이용약관에 동의해 주세요.', agree_personal_information: '개인정보 수집 및 이용에 대한 안내에 동의해 주세요.', insert_studying_stage: '작품을 공유하고 싶은 학급을 선택해 주세요.', insert_born_year: '태어난 연도를 입력해 주세요.', insert_gender: '성별을 선택지에서 선택해 주세요.', select_language: '언어를 선택해 주세요.', check_email: '이메일 형식을 확인해 주세요.', already_exist_id: '이미 존재하는 아이디 입니다.', id_validation_id: '아이디는 4~20자의 영문/숫자를 조합하세요', password_validate_pwd: '패스워드는 5자 이상의 영문/숫자 등을 조합하세요.', password_validate_pwd_length: '패스워드는 최소 5자 이상으로 입력해 주세요.', neoid_username_same_id: '이미 사용중인 아이디 입니다.(NEOID)', insert_same_pwd: '같은 비밀번호를 입력해 주세요.', studying_stage_group: '작품 공유 학급', studying_stage: '작품을 공유하고 싶은 학급을 선택해 주세요.', password: '비밀번호 입력', save_id: '아이디 저장', auto_login: '자동 로그인', enter_id_pw: '아이디, 비밀번호 입력', forgot_password: '아이디와 비밀번호가 기억나지 않으세요 ?', did_not_join: '아직 엔트리 회원이 아니세요?', go_join: '회원가입하기 ', renew_index_text_00: '엔트리 교과서 학습하기', renew_index_text_01: '교과서로 엔트리를 배워보세요.', renew_index_text_02: '초등학교 교과서 강의를 통해', renew_index_text_02_2: '엔트리를 배워보세요!', renew_index_text_03: '교과서 학습하기', renew_index_text_03_2: '바로가기', renew_index_text_1: '2019년, 엔트리가 바뀝니다', renew_index_text_2: '확 바뀐 작품 만들기', renew_index_text_3: '지금 새로운 기능을 확인하고', renew_index_text_3_2: 'PC와 태블릿으로 작품을 만들어보세요!', renew_index_text_4: '자세히 보기', first_step: '소프트웨어 교육의 첫걸음', entry_content_one: '상상했던 것들을 블록 놀이하듯 하나씩 쌓아보세요.', entry_content_two: '게임, 애니메이션, 미디어아트와 같은 멋진 작품이 완성된답니다!', entry_content_three: '재미있는 놀이로 배우고, 나만의 멋진 작품을 만들어 친구들과 공유할 수 있는 멋진 엔트리의 세상으로 여러분을 초대합니다!', funny_space: '재미있게 배우는 학습공간', in_learn_section: '< 학습하기 > 에서는', learn_problem_solving: '컴퓨터를 활용해 논리적으로 문제를 해결할 수 있는 다양한 학습 콘텐츠가 준비되어 있습니다. 게임을 하듯이 주어진 미션들을 프로그래밍으로 해결해볼 수도 있고 재미있는 동영상으로 소프트웨어의 원리를 배울 수도 있습니다 .', joy_create: '창작의 즐거움', in_make: '< 만들기 > 는', make_contents: '미국 MIT에서 개발한 Scratch와 같은 비주얼 프로그래밍 언어를 사용하여 프로그래밍을 처음 접하는 사람들도 쉽게 나만의 창작물을 만들 수 있습니다. 또 엔트리를 통해 만들 수 있는 컨텐츠의 모습은 무궁무진합니다. 과학 시간에 배운 물리 법칙을 실험해 볼 수도 있고 좋아하는 캐릭터로 애니메이션을 만들거나 직접 게임을 만들어 볼 수 있습니다.', and_content: '또 엔트리를 통해 만들 수 있는 콘텐츠의 모습은 무궁무진합니다. 과학 시간에 배운 물리 법칙을 실험해 볼 수도 있고 좋아하는 캐릭터로 애니메이션을 만들거나 직접 게임을 만들어 볼 수 있습니다.', share_collaborate: '공유와 협업', explore_contents: '< 구경하기 > 에서는 엔트리를 통해 제작한 작품을 다른 사람들과 쉽게 공유할 수 있습니다. 또한 공유된 작품이 어떻게 구성되었는지 살펴볼 수 있고, 이를 발전시켜 자신만의 프로젝트를 만들 수 있습니다. 그리고 엔트리에서는 공동 창작도 가능합니다. 친구들과 협업하여 더 멋진 프로젝트를 만들어볼 수 있습니다.', why_software: '왜 소프트웨어 교육이 필요할까?', speak_obama_contents: '컴퓨터 과학을 배우는 것은 단지 여러분의 미래에만 중요한 일이 아닙니다. 이것은 우리 미국의 미래를 위해 중요한 일 입니다.', obama: '버락 오바마', us_president: '미국 대통령', billgates_contents: '컴퓨터 프로그래밍은 사고의 범위를 넓혀주고 더 나은 생각을 할 수 있게 만들며 분야에 상관없이 모든 문제에 대해 새로운 해결책을 생각할 수 있는 힘을 길러줍니다.', billgates: '빌게이츠', chairman_micro: 'Microsoft 회장', eric_contents: '현재 디지털 혁명은 지구상 대부분의 사람들에게 아직 시작도 안된 수준입니다. 프로그래밍을 통해 향후 10년간 모든 것이 변화할 것 입니다.', eric: '에릭 슈미츠', sandbug_contents: '오늘날 컴퓨터 과학에 대한 이해는 필수가 되었습니다. 우리의 국가 경쟁력은 우리가 아이들에게 이것을 얼마나 잘 가르칠 수 있느냐에 달려있습니다.', sandbug: '쉐릴 샌드버그', view_entry_tools: '엔트리와 함께할 수 있는 교구들을 살펴볼 수 있습니다.', solve_problem: '미션 해결하기', solve_problem_content: '게임을 하듯 미션을 하나 하나 해결하며 소프트웨어의 기본 원리를 배워보세요!', find_extra_title: '엔트리봇 부품 찾기 대작전', all_ages: '전 연령', total: '총', step: '단계', find_extra_contents: '로봇 강아지를 생산하던 루츠 공장에 어느 날 갑자기 일어난 정전 사태로 태어난 특별한 강아지 엔트리 봇. 아직 조립이 덜 된 나머지 부품들을 찾아 공장을 탈출 하도록 도와주면서 소프트웨어의 동작 원리를 익혀보자!', software_play_contents: "EBS에서 방영한 '소프트웨어야 놀자' 프로그램을 실습해볼 수 있습니다.", resources_contents: '엔트리를 활용한 다양한 교육자료들을 무료로 제공합니다.', from: ' 출처', sw_camp: '미래부 SW 창의캠프', elementary: '초등학교', middle: '중학교', grades: '학년', lesson: '차시', sw_contents_one: '5차시 분량으로 초등학생이 엔트리와 피지컬 컴퓨팅을 경험할 수 있는 교재입니다. 학생들은 엔트리 사용법을 학습하고, 그림판과 이야기 만들기를 합니다. 마지막에는 아두이노 교구를 활용하여 키보드를 만들어보는 활동을 합니다.', sw_camp_detail: '미래창조과학부 SW창의캠프', sw_contents_two: '5차시 분량으로 중학생이 엔트리와 피지컬 컴퓨팅을 경험할 수 있는 교재입니다. 학생들은 엔트리 사용법을 학습하고, 미로찾기 게임과, 퀴즈 프로그램을 만들어 봅니다. 마지막에는 아두이노 교구를 활용하여 키보드로 자동차를 조종하는 활동을 합니다.', sw_contents_three: "선생님들이 학교에서 시작할 수 있는 소프트웨어 수업 지도서입니다. 다양한 언플러그드 활동과, '소프트웨어야 놀자' 방송을 활용한 수업 지도안이 담겨 있습니다.", naver_sw: 'NAVER 소프트웨어야 놀자', teacher_teaching: '교사용지도서 (초등학교 5~6학년 이상)', funny_sw: '즐거운 SW놀이 교실', sw_contents_four: '소프트웨어를 놀이하듯 재미있게 배울 수 있는 교재로 엔트리보드게임을 비롯한 다양한 언플러그드 활동과 엔트리 학습모드로 소프트웨어를 만드는 기본 원리를 배우게 됩니다. 기본 원리를 배웠다면 학생들은 이제 엔트리로 이야기, 게임, 예술작품, 응용프로그램을 만드는 방법을 배우고, 자신이 생각한 소프트웨어를 만들고 발표할 수 있도록 교재가 구성되어 있습니다.', ct_text_5: '교과서와 함께 키우는 컴퓨팅 사고력', teacher_grade_5: '교원 (초등학교 5학년)', ct_text_5_content: '실생활의 문제를 해결하자는 테마로 준비된 총 8개의 학습콘텐츠가 담긴 교사용 지도안입니다. 각 콘텐츠는 개정된 교육과정을 반영한 타교과와의 연계를 통해 다양한 문제를 만나고 해결해볼 수 있도록 설계되었습니다. 아이들이 컴퓨팅 사고력을 갖춘 융합형 인재가 될 수 있도록 지금 적용해보세요!', ct_text_6: '교과서와 함께 키우는 컴퓨팅 사고력', teacher_grade_6: '교원 (초등학교 6학년)', ct_text_6_content: '실생활의 문제를 해결하자는 테마로 준비된 총 8개의 학습콘텐츠가 담긴 교사용 지도안입니다. 각 콘텐츠는 개정된 교육과정을 반영한 타교과와의 연계를 통해 다양한 문제를 만나고 해결해볼 수 있도록 설계되었습니다. 아이들이 컴퓨팅 사고력을 갖춘 융합형 인재가 될 수 있도록 지금 적용해보세요!', sw_use: '모든 교재들은 비영리 목적에 한하여 저작자를 밝히고 자유롭게 이용할 수 있습니다.', title: '제목', writer: '작성자', view: '보기', date: '등록일', find_id_pwd: '아이디와 비밀번호 찾기', send_email: '비밀번호를 잊은 경우 이메일로 비밀번호를 찾을 수 있습니다.', user_not_exist: '존재하지 않는 이메일 주소 입니다.', not_signup: '아직 회원이 아니세요?', send: '발송하기', sensorboard: '엔트리봇 센서보드', physical_computing: '피지컬 컴퓨팅', sensorboard_contents: '아두이노를 사용하기 위해서 더 이상 많은 케이블을 사용해 회로를 구성할 필요가 없습니다. 엔트리 보드는 아두이노 위에 끼우기만 하면 간단하게 LED, 온도센서, 소리센서, 빛, 슬라이더, 스위치를 활용할 수 있습니다. 이제 엔트리 보드를 활용해 누구라도 쉽게 자신만의 특별한 작품을 만들어보세요!', entrybot_boardgame: '엔트리봇 보드게임', unplugged: '언플러그드 활동', unplugged_contents: '재밌는 보드게임을 통해 컴퓨터의 작동 원리를 배워보세요. 로봇강아지인 엔트리봇이 정전된 공장에서 필요한 부품을 찾아 탈출하도록 돕다보면 컴퓨터 전문가처럼 문제를 바라 볼 수 있게됩니다.', entrybot_cardgame: '엔트리봇 카드게임 : 폭탄 대소동', entrybot_cardgame_contents: '갑자기 엔트리도시에 나타난 12종류의 폭탄들! 과연 폭탄들을 안전하게 해체할 수 있을까요? 폭탄들을 하나씩 해체하며 엔트리 블록과 함께 소프트웨어의 원리를 배워봐요! 순차, 반복, 조건을 통해 폭탄을 하나씩 해체하다 보면 엔트리도시를 구한 영웅이 될 수 있답니다!', basic_learn: '엔트리 기본 학습', basic_learn_contents: '엔트리를 활용한 다양한 교육 콘텐츠를 제공합니다.', troubleshooting: '문제해결 학습', playsoftware: '소프트웨어야 놀자', make_own_lesson: '나만의 수업을 만들어 다른 사람과 공유할 수 있습니다.', group_lecture: '우리 반 강의', group_curriculum: '우리 반 강의 모음', group_homework: '우리 반 과제', group_noproject: '전시된 작품이 없습니다.', group_nolecture: '생성된 강의가 없습니다.', group_nocurriculum: '생성된 강의 모음이 없습니다.', lecture_contents: '필요한 기능만 선택하여 나만의 수업을 만들어 볼 수 있습니다.', curriculum_contents: '여러개의 강의를 하나의 강의 모음으로 묶어 차근차근 따라할 수 있는 수업을 만들 수 있습니다.', grade_info: '학년 정보', difficulty: '난이도', usage: '사용요소', learning_concept: '학습개념', related_subject: '연계 교과', show_more: '더보기', close: '닫기', latest: '최신순', viewCount: '조회수', viewer: '조회순', like: '좋아요순', comment: '댓글순', entire_period: '전체기간', today: '오늘', latest_week: '최근 1주일', latest_month: '최근 1개월', latest_three_month: '최근 3개월', current_password: '현재 비밀번호', change_password: '비밀번호 변경', incorrect_password: '비밀번호가 일치하지 않습니다.', incorrect_password_login: '아이디 또는 비밀번호를 잘못 입력하셨습니다.', suspension_user: '이용 정지된 계정입니다.', blocked_user: '승인되지 않은 사용자 입니다.', new_password: '새로운 비밀번호', password_option_1: '영문과 숫자의 조합으로 5자 이상이 필요합니다.', again_new_password: '새로운 비밀번호 재입력', enter_new_pwd: '새로운 비밀번호를 입력하세요.', confirm_new_pwd: '새로운 비밀번호를 확인하세요.', enter_new_pwd_again: '새로운 비밀번호를 다시 입력하세요.', password_match: '비밀번호가 일치하지 않습니다.', incorrect_email: '유효한 이메일이 아닙니다', edit_button: '정보수정', edit_profile: '관리', my_project: '나의 작품', my_group: '나의 학급', mark: '관심 작품', prev_state: '이전', profile_image: '자기소개 이미지', insert_profile_image: '프로필 이미지를 등록해 주세요.', at_least_180: '180 x 180 픽셀의 이미지를 권장합니다.', upload_image: '이미지 업로드', about_me: '자기소개', save_change: '변경사항 저장', basic_image: '기본 이미지', profile_condition: '자기소개를 입력해 주세요. 50자 내외', profile_back: '돌아가기', make_project: '작품 만들기', exhibit_project: '작품 전시하기', art_list_shared: '개인', art_list_group_shared: '학급', gl_mode_boost: '부스트 모드', gl_not_supported: '부스트 모드로 실행할 수 없는 환경입니다.\n확인을 누르면 기본모드로 실행됩니다.', view_project: '코드 보기', code_view: '코드보기', noResult: '검색 결과가 없습니다.', comment_view: '댓글', upload_project: '올리기', edit: '수정', save_complete: '저장', just_like: '좋아요', share: '공유', who_likes_project: '작품을 좋아하는 사람', people_interest: '작품을 관심있어 하는 사람', none_person: '없음', inserted_date: '등록일', last_modified: '최종 수정일', original_project: '원본 작품', for_someone: '님의', original_project_deleted: '원본 작품이 삭제되었습니다.', delete_project: '삭제', delete_group_project: '목록에서 삭제', currnet_month_time: '월', current_day_time: '일', game: '게임', animation: '애니메이션', media_art: '미디어 아트', physical: '피지컬', etc: '기타', connected_contents: '연계되는 콘텐츠', connected_contents_content: '엔트리와 함께 할 수 있는 다양한 콘텐츠를 만나보세요. 처음 소프트웨어를 배우는 사람이라면 쉽게 즐기는 보드게임부터 아두이노와 같은 피지컬 컴퓨팅을 활용하여 자신만의 고급스러운 창작물을 만들어 볼 수 있습니다.', basic_mission: '기본 미션: 엔트리봇 미로찾기', basic_mission_content: '강아지 로봇을 만드는 공장에서 우연한 정전으로 혼자서 생각할 수 있게 된 엔트리봇! 공장을 탈출하고 자유를 찾을 수 있도록 엔트리봇을 도와주세요!', application_mission: '응용미션: 엔트리봇 우주여행', write_article: '글쓰기', write_contest: '제출하기', view_all_articles: '모든 글 보기', view_own_articles: '내가 쓴 글 보기', view_qna_articles: '답변 없는 글 보기', learning_materials: '교육자료', download_materials: '교육자료 내려받기', download_button: '내려받기', download_all: '모두 내려받기', ebs_software_first: '<소프트웨어야 놀자>는 네이버와 EBS가 함께 만든 교육 콘텐츠입니다. 여기에서는 엔트리를 활용하여 실제로 간단한 프로그램을 만들어보며 소프트웨어의 기초 원리를 배워나갈 수 있습니다. 또한 각 콘텐츠에서는 동영상을 통해 컴퓨터과학에 대한 선행지식이 없더라도 충분히 재미와 호기심을 느끼며 진행할 수 있도록 준비되어있습니다.', go_software: '소프트웨어야 놀자 가기', ebs_context: 'EBS 동영상 가기', ebs_context_hello: 'EBS 가기', category: '카테고리', add_picture: '사진첨부', upload_article: '글 올리기', list: '목록', report: '신고하기', upload: '올리기', staff_picks: '스태프 선정', popular_picks: '인기 작품', lecture_header_more: '더 만들어 보기', lecture_header_reset: '초기화', lecture_header_reset_exec: '초기화 하기', lecture_header_save: '저장', lecture_header_save_content: '학습내용 저장하기', lecture_header_export_project: '내 작품으로 저장하기', lecture_header_undo: '취소', lecture_header_redo: '복원', lecture_er_bugs: '버그신고', lecture_container_tab_object: '오브젝트', lecture_container_tab_video: '강의 동영상', lecture_container_tab_project: '완성된 작품', lecture_container_tab_help: '블록 도움말', illigal: '불법적인 내용 또는 사회질서를 위반하는 활동', verbal: '언어 폭력 또는 개인 정보를 침해하는 활동', commertial: '상업적인 목적을 가지고 활동', explicit: '음란물', other: '기타', check_one_more: '하나이상 표기해주세요.', enter_content: '기타의 내용을 입력해 주세요.', report_result: '결과 회신을 원하시면 메일을 입력해 주세요.', report_success: '신고하기가 정상적으로 처리 되었습니다.', etc_detail: '기타 항목 선택후 입력해주세요. 신고와 무관한 욕설 작성 시 이용이 정지될 수 있습니다.', lecture_play: '강의 보기', list_view_link: '다른 강의 모음 보기', lecture_intro: '강의 소개 보기', study_goal: '학습목표', study_description: '설명', study_created: '등록일', study_last_updated: '최종 수정일', study_remove: '삭제', study_group_lecture_remove: '목록에서 삭제', study_group_curriculum_remove: '목록에서 삭제', study_edit: '강의 모음 수정', study_comments: '댓글', study_comment_post: '올리기', study_comment_remove: '삭제', study_comment_edit: '수정', study_comment_save: '저장', study_guide_video: '안내 영상', study_basic_project: '기본 작품', study_done_project: '완성 작품을 선택하세요.', study_usage_element: '사용요소', study_concept_element: '적용개념', study_subject_element: '연계교과', study_computing_element: '컴퓨팅요소', study_element_none: '없음', study_label_like: '좋아요', study_label_interest: '관심 강의', study_label_share: '공유', study_label_like_people: '강좌를 좋아하는 사람', study_label_interest_people: '강좌를 관심있어 하는 사람', study_related_lectures: '강의 목록', study_expand: '전체보기', study_collapse: '줄이기', aftercopy: '주소가 복사되었습니다.', study_remove_curriculum: '강의 모음을 삭제하시겠습니까?', content_required: '내용을 입력하세요', upload_not_supported_file_msg: '지원하지 않는 형식의 파일입니다.', study_remove_lecture: '강의를 삭제하시겠습니까?', lecture_build: '강의 만들기', lecture_build_step1: '1. 강의를 소개하기 위한 정보를 입력해주세요', lecture_build_step2: '2. 학습에 사용되는 기능들만 선택해주세요', lecture_build_step3: '3. 모든 정보를 올바르게 입력했는지 확인해주세요', lecture_build_choice: '어떤 것을 올리시겠습니까?', lecture_build_project: '엔트리 작품', lecture_build_video: '강의 영상', lecture_build_grade: '추천학년', lecture_build_goals: '학습목표', lecture_build_add_goal: '이곳을 클릭하여 목표를 추가', lecture_build_attach: '파일 첨부', lecture_build_attach_text: '20MB 이내의 파일을 업로드해 주세요.', lecture_build_assist: '보조 영상', lecture_build_youtube_url: 'Youtube 공유 링크를 넣어주세요.', lecture_build_project_done: '완성 작품을 선택하세요.', lecture_build_scene_text1: '장면기능을 끄면 새로운 장면을 추가하거나,', lecture_build_scene_text2: '삭제할 수 없습니다.', lecture_build_object_text: '오브젝트 추가하기를 끄면 새로운 오브젝트를 추가하거나 삭제할 수 없습니다.', lecture_build_blocks_text1: '학습에 필요한 블록들만 선택해주세요.', lecture_build_blocks_text2: '선택하지 않은 블록은 숨겨집니다.', lecture_build_basic1: '학습을 시작할때 사용할 작품을 선택해 주세요.', lecture_build_basic2: '학습자는 선택한 작품을 가지고 학습을 하게 됩니다.', lecture_build_help: '이 도움말을 다시 보시려면 눌러주세요.', lecture_build_help_never: '다시보지 않기', lecture_build_close: '닫기', lecture_build_scene: '장면 1', lecture_build_add_object: '오브젝트 추가하기', lecture_build_start: '시작하기', lecture_build_tab_code: '블록', lecture_build_tab_shape: '모양', lecture_build_tab_sound: '소리', lecture_build_tab_attribute: '속성', lecture_build_tab_table: '테이블', lecture_build_block_category: '블록 카테고리를 선택하세요.', lecture_build_attr_all: '전체', lecture_build_attr_var: '변수', lecture_build_attr_signal: '신호', lecture_build_attr_list: '리스트', lecture_build_attr_func: '함수', lecture_build_edit: '강의 수정', lecture_build_remove: '삭제', curriculum_build: '강의 모음 만들기', curriculum_step1: '1. 강의 모음을 소개하는 정보를 입력해주세요.', curriculum_step2: '2. 강의 모음을 구성하는 강의를 선택해주세요.', curriculum_step3: '3. 올바르게 강의 모음이 구성되었는지 확인해주세요.', curriculum_lecture_upload: '강의 올리기', curriculum_lecture_edit: '강의 편집', curriculum_lecture_open: '불러오기', group_lecture_add: '우리 반 강의 추가하기', group_curriculum_add: '우리 반 강의 모음 추가하기', group_lecture_delete: '삭제', group_curriculum_delete: '삭제', group_select: '', group_studentNo: '학번', group_username: '이름', group_userId: '아이디', group_tempPassword: '비밀번호 수정', group_gender: '성별', group_studentCode: '코드', group_viewWorks: '작품 보기', added_group_lecture: '강의가 삭되었습니다.', added_group_curriculum: '강의 모음이 삭제되었습니다.', deleted_group_lecture: '강의가 삭제되었습니다.', deleted_group_curriculum: '강의 모음이 삭제되었습니다.', modal_my: '나의', modal_interest: '관심', modal_project: '작품', section: '단원', connect_hw: '하드웨어 연결', connect_message: '%1에 연결되었습니다.', connect_fail: '하드웨어 연결에 실패했습니다. 연결프로그램이 켜져 있는지 확인해 주세요.', interest_curriculum: '관심 강의 모음', marked_curriculum: '관심 강의 모음', searchword_required: '검색어를 입력하세요.', file_required: '파일은 필수 입력 항목입니다.', file_name_error: '올바른 파일이름을 입력해 주세요.', file_upload_max_count: '한번에 10개까지 업로드가 가능합니다.', image_file_only: '이미지 파일만 등록이 가능합니다.', file_upload_max_size: '10MB 이하만 업로드가 가능합니다.', curriculum_modal_lectures: '나의 강의', curriculum_modal_interest: '관심 강의', group_curriculum_modal_curriculums: '나의 강의 모음', group_curriculum_modal_interest: '관심 강의 모음', picture_import: '모양 가져오기', picture_select: '모양 선택', lecture_list_view: '다른 강의보기', play_software_2: 'EBS 소프트웨어야 놀자2', play_software_2_content: '네이버와 EBS가 함께 만든 두 번째 이야기, <소프트웨어야 놀자> 시즌2를 만나보세요! 재미있는 동영상 강의를 통해 소프트웨어의 기본 개념을 배워보고, 다양하고 흥미로운 주제로 실생활 문제를 해결해 볼 수 있습니다. 방송영상과 특별영상을 보며 재미있는 프로그램들을 직접 만들어보세요. 소프트웨어 교육을 처음 접하는 친구들도 쉽게 소프트웨어와 친구가 될 수 있답니다!', open_project_to_all: '공개', close_project: '비공개', category_media_art: '미디어 아트', go_further: '더 나아가기', marked_project: '관심 작품', marked_group_project: '학급 관심 작품', basic: '기본', application: '응용', the_great_escape: '탈출 모험기', escape_guide_1: '강아지 로봇을 만드는 공장에서 우연한 정전으로 혼자서 생각할 수 있게 된 엔트리봇! ', escape_guide_1_2: ' 공장을 탈출하고 자유를 찾을 수 있도록 엔트리봇을 도와주세요!', escape_guide_2: '엔트리봇이 먼 길을 가기엔 고쳐야 할 곳이 너무 많아 공장에서 탈출하면서 몸을 수리할 수 있는 부품들을 찾아보자! 아직 몸이 완전하지는 않지만 걷거나 뛰면서, 방향을 바꾸는 정도는 가능할 거야! ', escape_guide_2_2: '학습 목표: 순차적 실행', escape_guide_3: '드디어 공장을 탈출했어! 하지만 마을로 가기 위해서는 아직 가야 할 길이 멀어. 그래도 몸은 어느 정도 고쳐져서 똑같은 일을 많이 해도 무리는 없을 거야! 어? 근데 저 로봇은 뭐지? ', escape_guide_3_2: '학습 목표: 반복문과 조건문', escape_guide_4: '드디어 마을 근처까지 왔어! 아까부터 똑같은 일을 많이 했더니 이제 외울 지경이야! 차라리 쓰일 블록은 이제 기억해뒀다가 쓰면 좋을 것 같아. 여기서 배터리만 충전해 놓으면 이제 평생 자유롭게 살 수 있을 거야.', escape_guide_4_2: '학습 목표: 함수 정의와 호출', space_travel_log: '우주 여행기', space_guide_1: '머나먼 우주를 탐사하기 위해 떠난 엔트리봇. 드디어 탐사 임무를 마치고 고향별인 지구로 돌아오려 하는데 수많은 돌이 지구로 가는 길을 막고 있다! 엔트리봇이 안전하게 지구로 돌아올 수 있도록 도와주세요!', space_guide_2: '드디어 지구에 돌아갈 시간이야! 얼른 지구에 돌아가서 쉬고 싶어!앞에 돌들이 어떻게 되어 있는지 확인하고 언제 어디로 가야 하는지 알려줘! 그러면 내가 가르쳐준 방향으로 움직일게!', space_guide_2_2: '학습 목표: 조건문 중첩과 논리 연산', cfest_mission: '엔트리 체험 미션', maze_1_intro: '안녕 나는 엔트리봇이라고 해. 지금 나는 다친 친구들을 구하려고 하는데 너의 도움이 필요해. 나를 도와서 친구들을 구해줘! 먼저 앞으로 가기 블록을 조립하고 시작을 눌러봐', maze_1_title: '시작 방법', maze_1_content: '엔트리봇은 어떻게 움직이나요?', maze_1_detail: '1. 블록 꾸러미에서 원하는 블록을 꺼내어 “시작하기를 클릭했을 때” 블록과 연결해봐
2. 다 조립했으면, 시작을 눌러봐
3. 나는 네가 조립한 블록대로 위에서부터 순서대로 움직일게', maze_2_intro: '좋아! 덕분에 첫 번째 친구를 무사히 구할 수 있었어! 그럼 다음 친구를 구해볼까? 어! 그런데 앞에 벌집이 있어! 뛰어넘기 블록을 사용해서 벌집을 피하고 친구를 구해보자.', maze_2_title_1: '장애물 뛰어넘기', maze_2_content_1: '장애물이 있으면 어떻게 해야하나요?', maze_2_detail_1: '길을 가다보면 장애물을 만날 수 있어.
장애물이 앞에 있을 때에는 뛰어넘기 블록을 사용해야 해.', maze_2_title_2: '시작 방법', maze_2_content_2: '엔트리봇은 어떻게 움직이나요?', maze_2_detail_2: '1. 블록 꾸러미에서 원하는 블록을 꺼내어 “시작하기를 클릭했을 때” 블록과 연결해봐
2. 다 조립했으면, 시작을 눌러봐
3. 나는 네가 조립한 블록대로 위에서부터 순서대로 움직일게', maze_3_intro: '멋졌어! 이제 또 다른 친구를 구하러 가자~ 이번에는 아까 구한 친구가 준 반복하기 블록을 이용해볼까? 반복하기를 이용하면 똑같은 동작을 쉽게 여러번 할 수 있어! 한 번 반복할 숫자를 바꿔볼래?', maze_3_title: '반복 블록(1)', maze_3_content: '(3)회 반복하기 블록은 어떻게 사용하나요?', maze_3_detail: '같은 행동을 여러번 반복하려면 ~번 반복하기 블록을 사용해야 해.
반복하고 싶은 블록들을 ~번 반복하기 안에 넣고 반복 횟수를 입력하면 돼', maze_4_intro: '훌륭해! 이제 구해야 할 친구 로봇들도 별로 남지 않았어. 벌집에 닿지 않도록 뛰어넘기를 반복하면서 친구에게 갈 수 있게 해줘!', maze_4_title: '반복 블록(1)', maze_4_content: '(3)회 반복하기 블록은 어떻게 사용하나요?', maze_4_detail: '같은 행동을 여러번 반복하려면 ~번 반복하기 블록을 사용해야 해.
반복하고 싶은 블록들을 ~번 반복하기 안에 넣고 반복 횟수를 입력하면 돼', maze_5_intro: '대단해! 이제 반복하기 블록과 만약 블록을 같이 사용해보자~ 만약 블록을 사용하면 앞에 벽이 있을 때 벽이 없는 쪽으로 회전할 수 있어. 그럼 친구를 구해주러 출발해볼까?', maze_5_title_1: '만약 블록', maze_5_content_1: '만약 ~라면 블록은 어떻게 동작하나요?', maze_5_detail_1: "만약 앞에 {이미지}가 있다면' 블록을 사용하면 앞에 {이미지}가 있을 때 어떤 행동을 할 지 정해줄 수 있어.
앞에 {이미지}가 있을 때에만 블록 안의 블록들을 실행하고
그렇지 않으면 실행하지 않게 되는 거야.", maze_5_title_2: '반복 블록(2)', maze_5_content_2: '~를 만날 때 까지 반복하기 블록은 어떻게 사용하나요?', maze_5_detail_2: "~까지 반복하기'를 사용하면 같은 행동을 언제까지 반복할지를 정해줄 수 있어.
반복하고 싶은 블록들을 ~까지 반복하기안에 넣으면 돼.
그러면 {이미지}와 같은 타일 위에 있는 경우 반복이 멈추게 될 거야.", maze_6_intro: '이제 마지막 친구야! 아까 해본 것처럼만 하면 될거야! 그럼 마지막 친구를 구하러 가볼까?', maze_6_title_1: '만약 블록', maze_6_content_1: '만약 ~라면 블록은 어떻게 동작하나요?', maze_6_detail_1: "만약 앞에 {이미지}가 있다면' 블록을 사용하면 앞에 {이미지}가 있을 때 어떤 행동을 할 지 정해줄 수 있어.
앞에 {이미지}가 있을 때에만 블록 안의 블록들을 실행하고
그렇지 않으면 실행하지 않게 되는 거야.", maze_6_title_2: '반복 블록(2)', maze_6_content_2: '~를 만날 때 까지 반복하기 블록은 어떻게 사용하나요?', maze_6_detail_2: "~까지 반복하기'를 사용하면 같은 행동을 언제까지 반복할지를 정해줄 수 있어.
반복하고 싶은 블록들을 ~까지 반복하기안에 넣으면 돼.
그러면 {이미지}와 같은 타일 위에 있는 경우 반복이 멈추게 될 거야.", maze_programing_mode_0: '블록 코딩', maze_programing_mode_1: '자바스크립트', maze_operation1_title: '1단계 – 자바스크립트모드 안내', maze_operation1_1_desc: '나는 로봇강아지 엔트리봇이야. 나에게 명령을 내려서 미션을 해결할 수 있게 도와줘! 미션은 시작할 때마다 \'목표\'를 통해서 확인할 수 있어!', maze_operation1_2_desc: '미션을 확인했다면 명령을 내려야 해 \'명령어 꾸러미\'명령어가 있는 공간이야. 마우스키보드명령을 내릴 수 있어. 마우스로는 명령어 꾸러미에 있는 명령어를 클릭하거나, 명령어\'명령어 조립소\'로 끌고와서 나에게 명령을 내릴 수 있어!', maze_operation1_2_textset_1: '마우스로 명령어를 클릭하는 방법 ', maze_operation1_2_textset_2: '마우스로 명령어를 드래그앤드랍하는 방법 ', maze_operation1_3_desc: '키보드로 명령을 내리려면 \'명령어 꾸러미\' 에 있는 명령어를 키보드로 직접 입력하면 돼.
명령어를 입력할 때 명령어 끝에 있는 ()와 ; 를 빼먹지 않도록 주의해야해!', maze_operation1_4_desc: '미션을 해결하기 위한 명령어를 다 입력했다면 [시작하기]를 누르면 돼.
[시작하기]를 누르면 나는 명령을 내린대로 움직일 거야!
각 명령어가 궁금하다면 [명령어 도움말]을 확인해봐!', maze_operation7_title: '7단계 - 반복 명령 알아보기(횟수반복)', maze_operation7_1_desc: '똑같은 일을 반복해서 명령하는건 매우 귀찮은 일이야.
이럴땐 반복과 관련된 명령어를 사용하면 훨씬 쉽게 명령을 내릴 수 있어.', maze_operation7_2_desc: '그렇다면 반복되는 명령을 쉽게 내리는 방법을 알아보자.
먼저 반복하기 명령어를 클릭한 다음, i<1 의 숫자를 바꿔서 반복횟수를 정하고
괄호({ }) 사이에 반복할 명령어를 넣어주면 돼!', maze_operation7_3_desc: '예를 들어 이 명령어은 move(); 를 10번 반복해서 실행해.
명령어와 동일한 명령어지.', maze_operation7_4_desc: '이 명령어를 사용할 때는 { } 안에 반복할 명령어를 잘 입력했는지,
`;`는 빠지지 않았는지 잘 살펴봐!
이 명령어에 대한 자세한 설명은 [명령어 도움말]에서 볼 수 있어.', maze_operation7_1_textset_1: '똑같은 명령어를 반복해서 사용하는 경우', maze_operation7_1_textset_2: '반복 명령어를 사용하는 경우', maze_operation7_2_textset_1: '반복 횟수', maze_operation7_2_textset_2: '반복할 명령', maze_operation7_4_textset_1: '괄호({})가 빠진 경우', maze_operation7_4_textset_2: '세미콜론(;)이 빠진 경우', study_maze_operation8_title: '8단계 - 반복 명령 알아보기(횟수반복)', study_maze_operation16_title: '4단계 - 반복 명령 알아보기(조건반복)', study_maze_operation1_title: '1단계 - 반복 명령 알아보기(횟수반복)', maze_operation9_title: '9단계 - 반복 명령 알아보기(조건반복)', maze_operation9_1_desc: '앞에서는 몇 번을 반복하는 횟수반복 명령어에 대해 배웠어.
이번에는 계속해서 반복하는 명령어를 살펴보자.
이 명령어를 사용하면 미션이 끝날 때까지 동일한 행동을 계속 반복하게 돼.
이 명령어 역시 괄호({ }) 사이에 반복할 명령어를 넣어 사용할 수 있어!', maze_operation9_2_desc: '예를 들어 이 명령어 은 미션을 완료할때까지 반복해서 move(); right()를 실행해.
명령어와 동일한 명령어지.', maze_operation9_3_desc: '이 명령어를 사용할 때도 { } 안에 반복할 명령어를 잘 입력했는지,
`true`가 빠지지 않았는지 잘 살펴봐!
이 명령어에 대한 자세한 설명은 [명령어 도움말]에서 볼 수 있어.', maze_operation9_1_textset_1: '반복할 명령', maze_operation9_3_textset_1: '괄호({})가 빠진 경우', maze_operation9_3_textset_2: '세미콜론(;)이 빠진 경우', maze_operation9_3_textset_3: 'true가 빠진 경우', study_maze_operation3_title: '3단계 - 반복 명령 알아보기(조건반복)', study_maze_operation4_title: '4단계 - 조건 명령 알아보기', study_ai_operation4_title: '4단계 - 조건 명령과 레이더 알아보기', study_ai_operation6_title: '6단계 - 중첩조건문 알아보기', study_ai_operation7_title: '7단계 - 다양한 비교연산 알아보기', study_ai_operation8_title: '8단계 - 물체 레이더 알아보기', study_ai_operation9_title: '9단계 - 아이템 사용하기', maze_operation10_title: '10단계 - 조건 명령 알아보기', maze_operation10_1_desc: '앞에서는 미션이 끝날 때까지 계속 반복하는 반복 명령어에 대해 배웠어.
이번에는 특정한 조건에서만 행동을 하는 조건 명령어를 살펴보자.
에서 보는것처럼 조건 명령어를 사용하면 명령을 보다 효율적으로 잘 내릴 수 있어.', maze_operation10_2_desc: '조건 명령어는 크게 `조건``조건이 발생했을때 실행되는 명령`으로 나눌수 있어.
먼저 조건 부분을 살펴보자. If 다음에 나오는 ( ) 부분이 조건을 입력하는 부분이야.
과 같은 명령어를 예로 살펴보자. if(front == \“wall\”) 는 만약 내 앞에(front) "wall(벽)"이 있다면을 뜻해', maze_operation10_3_desc: '이제 `조건이 발생했을 때 실행되는 명령`을 살펴보자.
이 부분은 괄호{}로 묶여 있고, 조건이 발생했을때 괄호안의 명령을 실행하게 돼!
조건이 발생하지 않으면 이 부분은 무시하고 그냥 넘어가게 되지.
의 명령어를 예로 살펴보자. 조건은 만약에 `내 앞에 벽이 있을 때` 이고,
이 조건이 발생했을 때 나는 괄호안의 명령어 right(); 처럼 오른쪽으로 회전하게 돼!', maze_operation10_4_desc: '조건 명령어반복하기 명령어와 함께 쓰이는 경우가 많아.
앞으로 쭉 가다가, 벽을 만났을때만 회전하게 하려면
순서와 같이 명령을 내릴 수 있지!', maze_operation10_1_textset_1: '[일반명령]', maze_operation10_1_textset_2: '앞으로 2칸 가고
오른쪽으로 회전하고,
앞으로 3칸가고,
오른쪽으로 회전하고, 앞으로...
', maze_operation10_1_textset_3: '[조건명령]', maze_operation10_1_textset_4: '앞으로 계속 가다가
`만약에 벽을 만나면`
오른쪽으로 회전해~!
', maze_operation10_2_textset_1: '조건', maze_operation10_2_textset_2: '조건이 발생했을 때 실행되는 명령', maze_operation10_3_textset_1: '조건', maze_operation10_3_textset_2: '조건이 발생했을 때 실행되는 명령', maze_operation10_4_textset_1: '미션이 끝날때 까지
계속 앞으로 간다.
', maze_operation10_4_textset_2: '계속 앞으로 가다가,
만약에 벽을 만나면
', maze_operation10_4_textset_3: '계속 앞으로 가다가,
만약에 벽을 만나면
오른쪽으로 회전한다.
', study_maze_operation18_title: '6단계 - 조건 명령 알아보기', maze_operation15_title: '15단계 - 함수 명령 알아보기', maze_operation15_1_desc: '자주 사용하는 명령어들을 매번 입력하는건 매우 귀찮은 일이야.
자주 사용하는 명령어들을 묶어서 이름을 붙이고,
필요할 때마다 그 명령어 묶음을 불러온다면 훨씬 편리하게 명령을 내릴 수 있어!
이런 명령어 묶음을 `함수`라고 해. 이제 함수 명령에 대해 자세히 알아보자.', maze_operation15_2_desc: '함수 명령어는 명령어를 묶는 `함수만들기` 과정과,
묶은 명령어를 필요할 때 사용하는 `함수 불러오기` 과정이 있어.
먼저 함수만들기 과정을 살펴보자.
함수를 만들려면 함수의 이름과, 그 함수에 들어갈 명령어를 입력해야 해.
function을 입력한 다음 함수의 이름을 정할 수 있어. 여기서는 promise로 만들거야.
함수 이름을 만들었으면 ()를 붙여줘. 그 다음 괄호({})를 입력해.
그리고 이 괄호 안에 함수에 들어갈 명령어들을 입력하면 함수가 만들어져!', maze_operation15_3_desc: '이 명령어를 예로 살펴보자. 나는 promise 라는 함수를 만들었어.
이 함수를 불러서 실행하면 괄호({})안에 있는
move();
move();
left(); 가 실행돼!', maze_operation15_4_desc: '함수를 불러와서 실행하려면 아까 만든 함수의 이름을 입력하고 뒤에 `();`를 붙이면 돼.
promise 라는 이름으로 함수를 만들었으니 promise(); 를 입력하면 앞에서 묶어놓은
명령어들이 실행되는거지!
과 같이 명령을 내리면 처럼 동작하게 돼!
함수 명령어를 사용하려면 과 같이 함수를 만들고 함수를 불러와야해!', maze_operation15_1_textset_1: '자주 사용하는 명령어 확인하기', maze_operation15_1_textset_2: '명령어들을 묶어서 이름 붙이기', maze_operation15_1_textset_3: '명령어 묶음 불러오기', maze_operation15_2_textset_1: '명령어 묶음의 이름(함수 이름)', maze_operation15_2_textset_2: '묶을 명령어들', maze_operation15_3_textset_1: '명령어 묶음의 이름(함수 이름)', maze_operation15_3_textset_2: '묶을 명령어들', maze_operation15_4_textset_1: '함수 만들기', maze_operation15_4_textset_2: '함수 불러오기', maze_operation15_4_textset_3: '실제 상황', maze_object_title: '오브젝트 정보', maze_object_parts_box: '부품 상자', maze_object_trap: '함정', maze_object_monster: '몬스터', maze_object_obstacle1: '장애물', maze_object_obstacle2: 'bee', maze_object_obstacle3: 'banana', maze_object_friend: '친구', maze_object_wall1: 'wall', maze_object_wall2: 'wall', maze_object_wall3: 'wall', maze_object_battery: '베터리', maze_command_ex: '예시', maze_command_title: '명령어 도움말', maze_command_move_desc: '엔트리봇을 한 칸 앞으로 이동시킵니다.', maze_command_jump_desc: '아래 이미지와 같은 장애물 앞에서 장애물을 뛰어 넘습니다.
', maze_command_jump_desc_elec: '아래 이미지와 같은 장애물 앞에서 장애물을 뛰어 넘습니다.
', maze_command_right_desc: '제자리에서 오른쪽으로 90도 회전합니다.', maze_command_left_desc: '제자리에서 왼쪽으로 90도 회전합니다.', maze_command_for_desc: '괄호{} 안에 있는 명령을 입력한 횟수 만큼 반복해서 실행합니다.', maze_command_while_desc: '미션이 끝날 때가지 괄호{} 안에 있는 명령을 계속 반복해서 실행합니다.', maze_command_slow_desc: '아래 이미지와 같은 방지턱을 넘습니다.
', maze_command_if1_desc: '조건 `바로 앞에 벽이 있을때`이 발생했을 때,
괄호{} 안에 있는 명령을 실행합니다.', maze_command_if2_desc: '조건 `바로 앞에 벌집이 있을때`이 발생했을 때,
괄호{} 안에 있는 명령을 실행합니다.', maze_command_if3_desc: '조건 `바로 앞에 바나나가 있을때`이 발생했을 때,
괄호{} 안에 있는 명령을 실행합니다.', maze_command_promise_desc: 'promise 라는 함수를 만들고 실행하면 괄호{} 안에
있던 명령어가 실행합니다.', perfect: '아주 완벽해! ', succeeded_using_blocks: ' 개의 블록을 사용해서 성공했어!', succeeded_using_commands: ' 개의 명령어를 사용해서 성공했어!', awesome: '대단한 걸!', succeeded_go_to_next: '개의 블록만으로 성공했어!
다음 단계로 넘어가자.', good: '좋아! ', but: '
하지만, ', try_again: ' 개의 블록만으로 성공하는 방법도 있어.
다시 도전해 보는건 어때?', try_again_commands: ' 개의 명렁어만으로 성공하는 방법도 있어.
다시 도전해 보는건 어때?', cfest_success: '대단한걸! 덕분에 친구들을 구할 수 있었어!
아마도 너는 타고난 프로그래머 인가봐!
나중에 또 만나자~!', succeeded_and_cert: '개의 블록만으로 성공했어!
인증서를 받으러 가자.', cause_msgs_1: '에구, 앞으로 갈 수 없는 곳이였어. 다시 해보자.', cause_msgs_2: '히잉. 그냥 길에서는 뛰어 넘을 곳이 없어. 다시 해보자.', cause_msgs_3: '에고고, 아파라. 뛰어 넘었어야 했던 곳이였어. 다시 해보자.', cause_msgs_4: '아쉽지만, 이번 단계에서는 꼭 아래 블록을 써야만 해.
다시 해볼래?', cause_msgs_5: '이런, 실행할 블록들이 다 떨어졌어. 다시 해보자.', cause_msgs_6: '이런, 실행할 명령어들이 다 떨어졌어. 다시 해보자.', close_experience: '체험
종료', replay: '다시하기', go_to_next_level: '다음단계 가기', move_forward: '앞으로 한 칸 이동', turn_left: '왼쪽', turn_right: '오른쪽', turn_en: '', turn_ko: '으로 회전', jump_over: '뛰어넘기', when_start_is_pressed: '시작하기를 클릭했을 때', repeat_until_ko: '만날 때 까지 반복', repeat_until_en: '', repeat_until: '만날 때 까지 반복', if_there_is_1: '만약 앞에 ', if_there_is_2: '있다면', used_blocks: '사용 블록', maximum: '목표 블록', used_command: '사용 명령어 갯수', maximum_command: '목표 명령어 갯수', block_box: '블록 꾸러미', block_assembly: '블록 조립소', command_box: '명령어 꾸러미', command_assembly: '명령어 조립소', start: '시작하기', engine_running: '실행중', engine_replay: '돌아가기', goto_show: '보러가기', make_together: '함께 만드는 엔트리', make_together_content: '엔트리는 학교에 계신 선생님들과 학생 친구들이 함께 고민하며 만들어갑니다.', project_nobody_like: "이 작품이 마음에 든다면 '좋아요'를 눌러 주세요.", project_nobody_interest: "'관심 작품'을 누르면 마이 페이지에서 볼 수 있어요.", lecture_nobody_like: "이 강의가 마음에 든다면 '좋아요'를 눌러 주세요.", lecture_nobody_interest: "'관심 강의'을 누르면 마이 페이지에서 볼 수 있어요.", course_nobody_like: "이 강의 모음이 마음에 든다면 '좋아요'를 눌러 주세요.", course_nobody_interest: "'관심 강의 모음'을 누르면 마이 페이지에서 볼 수 있어요.", before_changed: '변경전', after_changed: '변경후', from_changed: '( 2016년 04월 17일 부터 ) ', essential: '필수', access_term_title: '안녕하세요. 엔트리 교육연구소 입니다. 
엔트리를 사랑해주시는 여러분께 감사드리며, 
엔트리 교육연구소 웹사이트 이용약관이
2016년 4월 17일 부로 다음과 같이 개정됨을 알려드립니다. ', member_info: '회원 안내', personal_info: '개인정보 수집 및 이용에 동의 합니다.', option: '선택', news: '최신소식', edu_material: '교육자료', latest_news: '최근소식', edu_data: '교육자료', training_program: '연수지원', footer_phrase: '엔트리는 누구나 무료로 소프트웨어 교육을 받을 수 있게 개발된 비영리 교육 플랫폼입니다.', footer_use_free: '모든 엔트리교육연구소의 저작물은 교육적 목적에 한하여 출처를 밝히고 자유롭게 이용할 수 있습니다.', footer_description_1: '엔트리는 비영리 교육 플랫폼으로 모든 엔트리의 저작물은 교육 목적에 한해 출처를 밝히고 자유롭게 이용할 수 있습니다.', footer_description_2: '', nonprofit_platform: '비영리 교육 플랫폼', this_is: '입니다.', privacy: '개인정보 처리방침', entry_addr: '경기도 성남시 분당구 불정로 6 NAVER 그린팩토리 16층', entry_addr_additional_phone: '1522-9182', entry_addr_additional_email: 'entry@connect.or.kr', entry_addr_additional_opensource: '오픈소스 라이선스', phone: '전화번호', alert_agree_term: '이용약관에 동의하여 주세요.', alert_private_policy: '개인정보 수집 약관에 동의하여 주세요.', agree: '동의', optional: '선택', start_software: '소프트웨어 교육의 첫걸음', analyze_procedure: '절차', analyze_repeat: '반복', analyze_condition: '분기', analyze_interaction: '상호작용', analyze_dataRepresentation: '데이터 표현', analyze_abstraction: '추상화', analyze_sync: '병렬 및 동기화', jr_intro_1: '안녕! 난 쥬니라고 해! 내 친구 엔트리봇이 오른쪽에 있어! 날 친구에게 데려다 줘!', jr_intro_2: '엔트리봇이 내 왼쪽에 있어! 왼쪽으로 가보자.', jr_intro_3: '엔트리봇이 위쪽에 있어! 친구를 만날 수 있도록 도와줘!', jr_intro_4: '어서 엔트리봇을 만나러 가자! 아래쪽으로 가보는거야~ ', jr_intro_5: '우왓! 내 친구가 멀리 떨어져있어. 엔트리봇이 있는 곳까지 안내해줄래? ', jr_intro_6: '저기 엔트리봇이 있어~ 얼른 만나러 가보자.', jr_intro_7: '예쁜 꽃이 있네. 꽃들을 모아 엔트리봇에게 가보자!', jr_intro_8: '가는 길에 꽃이 있어! 꽃을 모아 엔트리봇에게 가보자!', jr_intro_9: '엔트리봇이 멀리 떨어져 있네? 가장 빠른 길로 엔트리봇에게 가 보자.', jr_intro_10: '엔트리봇을 만나러 가는 길에 꽃을 모두 모아서 가보자.', jr_intro_11: '엔트리봇에게 가려면 오른쪽으로 다섯번이나 가야 하잖아? 반복하기 블록을 사용해서 좀 더 쉽게 가 보자.', jr_intro_12: '반복하기를 사용해서 엔트리봇을 만나러 가자.', jr_intro_13: '지금 블록으로는 친구에게 갈 수가 없어. 반복 횟수를 바꿔 엔트리봇에게 갈 수 있게 해줘.', jr_intro_14: '반복 블록을 사용하여 엔트리봇에게 데려다 줘.', jr_intro_15: '엔트리봇이 정~말 멀리 있잖아? 그래도 반복 블록을 사용하면 쉽게 엔트리봇에게 갈 수 있을 거야.', jr_whats_ur_name: '내가 받을 인증서에 적힐 이름은?', jr_down_cert: '인증서 받기', jr_popup_prefix_1: '좋아! 엔트리봇을 만났어!', jr_popup_prefix_2: '우왓! 엔트리봇을 만났어!
하지만 엔트리봇을 만나기에는 더 적은 블록을 사용해서도
만날 수 있는데 다시 해볼래? ', jr_popup_prefix_3: '좋아! 책가방을 챙겼어!', jr_popup_prefix_4: '우왓! 책가방이 있는 곳으로 왔어! 하지만 더 적은 블록을 사용해도 책가방 쪽으로 갈 수 있는데 다시 해볼래?', jr_popup_suffix_1: '고마워~ 덕분에 책가방을 챙겨서 학교에 올 수 있었어~ 다음 학교 가는 길도 함께 가자~', jr_popup_suffix: '고마워~ 덕분에 엔트리봇이랑 재밌게 놀 수 있었어~
다음에 또 엔트리봇이랑 놀자~', jr_fail_dont_go: '에궁, 그 곳으로는 갈 수 없어. 가야하는 길을 다시 알려줘~', jr_fail_dont_know: '어? 이제 어디로 가지? 어디로 가야하는 지 더 알려줘~', jr_fail_no_flower: '이런 그곳에는 꽃이 없어. 꽃이 있는 곳에서 사용해보자~', jr_fail_forgot_flower: '앗! 엔트리봇한테 줄 꽃을 깜빡했어. 꽃을 모아서 가자~', jr_fail_need_repeat: '반복 블록이 없잖아! 반복 블록을 사용해서 해보자~', jr_hint_1: '안녕! 난 쥬니라고 해! 내 친구 엔트리봇이 오른쪽에 있어! 날 친구에게 데려다 줘!', jr_hint_2: '엔트리봇이 내 왼쪽에 있어! 왼쪽으로 가보자.', jr_hint_3: '엔트리봇이 위쪽에 있어! 친구를 만날 수 있도록 도와줘!', jr_hint_4: '어서 엔트리봇을 만나러 가자! 아래쪽으로 가보는거야~', jr_hint_5: '우왓! 내 친구가 멀리 떨어져있어. 엔트리봇이 있는 곳까지 안내해줄래?', jr_hint_6: '잘못된 블록들 때문에 친구에게 가지 못하고 있어, 잘못된 블록을 지우고 엔트리봇에게 갈 수 있도록 해줘!', jr_hint_7: '예쁜 꽃이 있네. 꽃들을 모아 엔트리봇에게 가보자!', jr_hint_8: '가는 길에 꽃이 있어! 꽃을 모아 엔트리봇에게 가보자!', jr_hint_9: '엔트리봇이 멀리 떨어져 있네? 가장 빠른 길로 엔트리봇에게 가 보자.', jr_hint_10: '앗, 블록을 잘못 조립해서 제대로 갈 수가 없어. 가는 길에 꽃을 모두 모아 엔트리봇에게 가져다 줄 수 있도록 고쳐 보자.', jr_hint_11: '엔트리봇에게 가려면 오른쪽으로 다섯번이나 가야 하잖아? 반복하기 블록을 사용해서 좀 더 쉽게 가 보자.', jr_hint_12: '반복하기를 사용해서 엔트리봇을 만나러 가자.', jr_hint_13: '지금 블록으로는 친구에게 갈 수가 없어. 반복 횟수를 바꿔 엔트리봇에게 갈 수 있게 해줘.', jr_hint_14: '반복 블록을 사용하여 엔트리봇에게 데려다 줘.', jr_hint_15: '엔트리봇이 정~말 멀리 있잖아? 그래도 반복 블록을 사용하면 쉽게 엔트리봇에게 갈 수 있을 거야.', jr_certification: '인증서', jr_congrat: '축하드립니다!', jr_congrat_msg: '문제해결 과정을 성공적으로 마쳤습니다.', jr_share: '공유', go_see_friends: '친구들 만나러 가요~!', junior_naver: '쥬니어 네이버', junior_naver_contents_1: "의 멋진 곰 '쥬니'가 엔트리를 찾아 왔어요! ", junior_naver_contents_2: '그런데 쥬니는 길을 찾는 것이 아직 어렵나봐요.', junior_naver_contents_3: '쥬니가 엔트리봇을 만날 수 있도록 가야하는 방향을 알려주세요~', basic_content: '기초', jr_help: '도움말', help: '도움말', cparty_robot_intro_1: '안녕 나는 엔트리봇이야. 난 부품을 얻어서 내몸을 고쳐야해. 앞으로 가기 블록으로 부품을 얻게 도와줘!', cparty_robot_intro_2: '좋아! 앞에도 부품이 있는데 이번에는 잘못 가다간 감전되기 쉬울 것 같아. 뛰어넘기 블록을 써서 부품까지 데려다 줘.', cparty_robot_intro_3: '멋진걸! 저기에도 부품이 있어! 길이 조금 꼬여있지만 회전하기 블록을 쓰면 충분히 갈 수 있을 것 같아! ', cparty_robot_intro_4: '좋아 이제 움직이는 건 많이 편해졌어! 이번에는 회전과 뛰어넘기를 같이 써서 저 부품을 얻어보자! ', cparty_robot_intro_5: '덕분에 몸이 아주 좋아졌어! 이번에도 회전과 뛰어넘기를 같이 써야 할 거야! 어서 가보자!', cparty_robot_intro_6: '멋져! 이제 몸이 많이 좋아져서, 똑같은 일은 여러 번 해도 괜찮을 거야! 한 번 반복하기를 사용해서 가보자!', cparty_robot_intro_7: '어? 중간중간에 뛰어넘어야 할 곳이 있어! 그래도 반복하기로 충분히 갈 수 있을 거야!', cparty_robot_intro_8: '이런! 이번에는 부품이 저기 멀리 떨어져 있어. 그래도 반복하기를 사용하면 쉽게 갈수 있지! 얼른 도와줘!', cparty_robot_intro_9: '우와~ 이제 내 몸이 거의 다 고쳐진 것 같아! 이번에도 반복하기를 이용해서 부품을 구하러 가보자!', cparty_robot_intro_10: '대단해! 이제 마지막 부품만 있으면 내 몸을 완벽하게 고칠 수 있을 거야! 빨리 반복하기로 도와줘!', cparty_car_intro_1: '안녕! 나는 엔트리봇이라고 해, 자동차를 타고 계속 이동하려면 연료가 필요해! 앞에 있는 연료를 얻을 수 있게 도와줄래?', cparty_car_intro_2: '좋아! 그런데 이번에는 길이 직선이 아니네! 왼쪽/오른쪽 돌기 블록으로 잘 운전해서 함께 연료를 얻으러 가볼까?', cparty_car_intro_3: '잘했어! 이번 길 앞에는 과속방지턱이 있어. 빠르게 운전하면 사고가 날 수도 있을 것 같아, 천천히 가기 블록을 써서 연료를 얻으러 가보자!', cparty_car_intro_4: '야호, 이제 운전이 한결 편해졌어! 이 도로에서는 반복하기 블록을 사용해서 연료를 채우러 가볼까?', cparty_car_intro_5: '와 이번 도로는 조금 복잡해 보이지만, 앞으로 가기와 왼쪽/오른쪽 돌기 블록을 반복하면서 가보면 돼! 차분하게 연료까지 가보자', cparty_car_intro_6: '이번에는 도로에 장애물이 있어서 잘 돌아가야 될 것 같아, 만약에 장애물이 앞에 있다면 어떻게 해야 하는지 알려줘!', cparty_car_intro_7: '좋아 잘했어! 한번 더 만약에 블록을 사용해서 장애물을 피해 연료를 얻으러 가보자!', cparty_car_intro_8: '앗 아까 만났던 과속 방지턱이 두 개나 있네, 천천히 가기 블록을 이용해서 안전하게 연료를 채우러 가보자!', cparty_car_intro_9: '복잡해 보이는 길이지만, 앞에서 사용한 반복 블록과 만약에 블록을 잘 이용하면 충분히 운전할 수 있어, 연료를 채울 수 있도록 도와줘!', cparty_car_intro_10: '정말 멋져! 블록의 순서를 잘 나열해서 이제 마지막 남은 연료를 향해 힘을 내어 가보자!', cparty_car_popup_prefix_1: '좋아! 연료를 얻었어!', cparty_car_popup_prefix_2: '우왓! 연료를 얻었어!
하지만 연료를 얻기에는 더 적은 블록을 사용해서도
얻을 수 있는데 다시 해볼래? ', cparty_car_popup_prefix_2_text: '우왓! 연료를 얻었어!
하지만 연료를 얻기에는 더 적은 명령어 사용해서도
얻을 수 있는데 다시 해볼래? ', cparty_car_popup_suffix: '고마워~ 덕분에 모든 배터리를 얻을 수 있었어~
다음에 또 나랑 놀자~', all_grade: '모든 학년', grade_e3_e4: '초등 3 ~ 4 학년 이상', grade_e5_e6: '초등 5 ~ 6 학년 이상', grade_m1_m3: '중등 1 ~ 3 학년 이상', entry_first_step: '엔트리 첫걸음', entry_monthly: '월간 엔트리', play_sw_2: 'EBS 소프트웨어야 놀자2', entry_programming: '실전, 프로그래밍!', entry_recommanded_course: '엔트리 추천 코스', introduce_course: '누구나 쉽게 보고 따라하면서 재미있고 다양한 소프트웨어를 만들 수 있는 강의 코스를 소개합니다.', all_free: '*강의 동영상, 만들기, 교재 등이 모두 무료로 제공됩니다.', cparty_result_fail_1: '에궁, 그 곳으로는 갈 수 없어. 가야하는 길을 다시 알려줘~', cparty_result_fail_2: '에고고, 아파라. 뛰어 넘었어야 했던 곳이였어. 다시 해보자.', cparty_result_fail_3: '아이고 힘들다. 아래 블록들을 안 썼더니 너무 힘들어! 아래 블록들로 다시 만들어줘.', cparty_result_fail_4: '어? 이제 어디로 가지? 어디로 가야하는 지 더 알려줘~', cparty_result_fail_5: '앗! 과속방지턱에서는 속도를 줄여야해. 천천히 가기 블록을 사용해보자~', cparty_result_success_1: '좋아! 부품을 얻었어!', cparty_result_success_2: '우왓! 부품을 얻었어!
하지만 부품을 얻기에는 더 적은 블록을 사용해서도 얻을 수 있는데 다시 해볼래?', cparty_result_success_2_text: '우왓! 부품을 얻었어!
하지만 부품을 얻기에는 더 적은 명령어를 사용해서도 얻을 수 있는데 다시 해볼래?', cparty_result_success_3: '고마워~ 덕분에 내몸이 다 고쳐졌어~ 다음에 또 나랑 놀자~', cparty_insert_name: '이름을 입력하세요.', offline_file: '파일', offline_edit: '편집', offline_undo: '되돌리기', offline_redo: '다시실행', offline_quit: '종료', select_one: '선택해 주세요.', evaluate_challenge: '도전해본 미션의 난이도를 평가해 주세요.', very_easy: '매우쉬움', easy: '쉬움', normal: '보통', difficult: '어려움', very_difficult: '매우 어려움', save_dismiss: '바꾼 내용을 저장하지 않았습니다. 계속 하시겠습니까?', entry_info: '엔트리 정보', actual_size: '실제크기', zoom_in: '확대', zoom_out: '축소', cparty_jr_intro_1: '안녕! 난 엔트리봇 이라고 해! 학교가는 길에 책가방을 챙길 수 있도록 도와줘! ', cparty_jr_intro_2: '책가방이 내 왼쪽에 있어! 왼쪽으로 가보자.', cparty_jr_intro_3: '책가방이 위쪽에 있어! 책가방을 챙길 수 있도록 도와줘!', cparty_jr_intro_4: '어서 책가방을 챙기러 가자! 아래쪽으로 가보는 거야~', cparty_jr_intro_5: '우왓! 내 책가방이 멀리 떨어져 있어. 책가방이 있는 곳까지 안내해줄래?', cparty_jr_intro_6: '책가방이 있어! 얼른 가지러 가자~', cparty_jr_intro_7: '길 위에 내 연필이 있네. 연필들을 모아 책가방을 챙기러 가보자!', cparty_jr_intro_8: '학교 가는 길에 연필이 있어! 연필을 모아 책가방을 챙기러 가보자!', cparty_jr_intro_9: '내 책가방이 멀리 떨어져 있네? 가장 빠른 길로 책가방을 챙기러 가 보자.', cparty_jr_intro_10: '가는 길에 연필을 모두 모으고 책가방을 챙기자!', cparty_jr_intro_11: '책가방을 챙기러 가려면 오른쪽으로 다섯 번이나 가야 하잖아? 반복하기 블록을 사용해서 좀 더 쉽게 가 보자.', cparty_jr_intro_12: '반복하기를 사용해서 책가방을 챙기러 가자.', cparty_jr_intro_13: '지금 블록으로는 책가방이 있는 쪽으로 갈 수가 없어. 반복 횟수를 바꿔 책가방을 챙기러 갈 수 있게 해줘.', cparty_jr_intro_14: '반복 블록을 사용하여 책가방을 챙기러 가줘.', cparty_jr_intro_15: '학교가 정~말 멀리 있잖아? 그래도 반복 블록을 사용하면 쉽게 학교에 도착 할수 있을 거야.', make_new_project: '새로운 작품 만들기', open_old_project: '저장된 작품 불러오기', offline_download: '엔트리 다운로드', offline_release: '엔트리 오프라인 에디터 출시!', offline_description_1: '엔트리 오프라인 버전은', offline_description_2: '인터넷이 연결되어 있지 않아도 사용할 수 있습니다. ', offline_description_3: '지금 다운받아서 시작해보세요!', sw_week_2015: '2015 소프트웨어교육 체험 주간', cparty_desc: '두근두근 소프트웨어와의 첫만남', entry_offline_download: '엔트리 오프라인 \n다운로드', entry_download_detail: '다운로드\n바로가기', offline_desc_1: '엔트리 오프라인 버전은 인터넷이 연결되어 있지 않아도 사용할 수 있습니다.', offline_desc_2: '지금 다운받아서 시작해보세요!', download: '다운로드', version: '버전', file_size: '크기', update: '업데이트', use_range: '사용범위', offline_desc_free: '엔트리 오프라인은 기업과 개인 모두 제한 없이 무료로 사용하실 수 있습니다.', offline_required: '최소 요구사항', offline_required_detail: '디스크 여유 공간 1GB 이상, windows7 혹은 MAC OS 10.8 이상', offline_notice: '설치 전 참고사항', offline_notice_1: '1. 버전', offline_notice_1_1: '에서는 하드웨어 연결 프로그램이 내장되어 있습니다.', offline_notice_2: '2. 별도의 웹브라우져가 필요하지 않습니다.', offline_notice_3: '버전 별 변경 사항 안내', offline_notice_4: '버전별 다운로드', offline_notice_5: '버전별 자세한 변경 사항 보기', hardware_online_badge: '온라인', hardware_title: '엔트리 하드웨어 연결 프로그램 다운로드', hardware_desc: '엔트리 온라인 ‘작품 만들기’에서 하드웨어를 연결하여 엔트리를 이용하는 경우에만 별도로 설치가 필요합니다.', hardware_release: '하드웨어 연결 프로그램의 자세한 변경 사항은 아래 주소에서 확인 할 수 있습니다.', hardware_window_download: 'Windows 다운로드', hardware_osx_download: 'Mac 다운로드', cparty_jr_result_2: '고마워~ 덕분에 책가방을 챙겨서 학교에 올 수 있었어~
다음 학교 가는 길도 함께 가자~ ', cparty_jr_result_3: '우왓! 학교까지 왔어!
하지만 더 적은 블록을 사용해도 학교에 갈 수 있는데
다시 해볼래?', cparty_jr_result_4: '우왓! 책가방을 얻었어!
하지만 더 적은 블록을 사용해도 책가방을 얻을 수 있는데
다시 해볼래? ', lms_no_class: '아직 만든 학급이 없습니다.', lms_create_class: '학급을 만들어 주세요.', lms_add_class: '학급 만들기', lms_base_class: '기본', lms_delete_class: '삭제', lms_my_class: '나의 학급', lms_grade_1: '초등 1', lms_grade_2: '초등 2', lms_grade_3: '초등 3', lms_grade_4: '초등 4', lms_grade_5: '초등 5', lms_grade_6: '초등 6', lms_grade_7: '중등 1', lms_grade_8: '중등 2', lms_grade_9: '중등 3', lms_grade_10: '일반', lms_add_groupId_personal: '선생님께 받은 학급 아이디를 입력하여, 회원 정보에 추가하세요.', lms_add_groupId: '학급 아이디 추가하기', lms_add_group_account: '학급 계정 추가', lms_enter_group_info: '발급받은 학급 아이디와 비밀번호를 입력하세요.', lms_group_id: '학급 아이디', lms_group_pw: '비밀번호', lms_group_name: '소속 학급명', personal_pwd_alert: '올바른 비밀번호 양식을 입력해 주세요', personal_form_alert: '양식을 바르게 입력해 주세요', personal_form_alert_2: '모든 양식을 완성해 주세요', personal_no_pwd_alert: '비밀번호를 입력해 주세요', select_gender: '성별을 선택해 주세요', enter_group_id: '학급 아이디를 입력해 주세요', enter_group_pwd: '비밀번호를 입력해 주세요', info_added: '추가되었습니다', no_group_id: '학급 아이디가 존재하지 않습니다', no_group_pwd: '비밀번호가 일치하지 않습니다', lms_please_choice: '선택해 주세요.', group_lesson: '나의 학급 강의', lms_banner_add_group: '학급 기능 도입', lms_banner_entry_group: '엔트리 학급 만들기', lms_banner_desc_1: '우리 반 학생들을 엔트리에 등록하세요!', lms_banner_desc_2: '이제 보다 편리하고 쉽게 우리 반 학생들의 작품을 찾고,', lms_banner_desc_3: '성장하는 모습을 확인할 수 있습니다. ', lms_banner_download_manual: '메뉴얼 다운로드', lms_banner_detail: '자세히 보기', already_exist_email: '이미 존재하는 이메일 입니다.', same_registered_email: '중복된 이메일 입니다.', email_correnctly_please: '양식을 올바르게 입력해주세요.', remove_project: '작품을 삭제하시겠습니까?', study_lesson: '우리 반 학습하기', open_project: '작품 불러오기', make_group: '학급 만들기', project_share: '작품 공유하기', group_project_share: '학급 공유하기', group_discuss: '학급 글 나누기', my_profile: '마이 페이지', search_updated: '최신 작품', search_recent: '최근 조회수 높은 작품', search_complexity: '최근 제작에 공들인 작품', search_staffPicked: '스태프선정 작품 저장소', search_childCnt: '사본이 많은 작품', search_likeCnt: '최근 좋아요가 많은 작품', search_recentLikeCnt: '최근 좋아요가 많은 작품', gnb_share: '공유하기', gnb_community: '커뮤니티', lms_add_lectures: '강의 올리기', lms_add_course: '강의 모음 올리기', lms_add_homework: '과제 올리기', remove_lecture_confirm: '강의를 정말 삭제하시겠습니까?', popup_delete: '삭제하기', remove_course_confirm: '강의 모음을 정말 삭제하시겠습니까?', lms_no_lecture_teacher_1: '추가된 강의가 없습니다.', lms_no_lecture_teacher_2: '우리 반 강의를 추가해 주세요.', gnb_download: '다운로드', lms_no_lecture_student_1: '아직 올라온 강의가 없습니다.', lms_no_lecture_student_2: '선생님이 강의를 올려주시면,', lms_no_lecture_student_3: '학습 내용을 확인할 수 있습니다.', lms_no_class_teacher: '아직 만든 학급이 없습니다.', lms_no_course_teacher_1: '추가된 강의 모음이 없습니다.', lms_no_course_teacher_2: '우리 반 강의 모음을 추가해 주세요.', lms_no_course_student_1: '아직 올라온 강의 모음이 없습니다.', lms_no_course_student_2: '선생님이 강의 모음을 올려주시면,', lms_no_course_student_3: '학습 내용을 확인할 수 있습니다.', lms_no_hw_teacher_1: '추가된 과제가 없습니다.', lms_no_hw_teacher_2: '우리 반 과제를 추가해 주세요.', lms_no_hw_student_1: '아직 올라온 과제가 없습니다.', lms_no_hw_student_2: '선생님이 과제를 올려주시면,', lms_no_hw_student_3: '학습 내용을 확인할 수 있습니다.', modal_edit: '수정하기', modal_deadline: '마감일 설정', modal_hw_desc: '상세설명 (선택)', desc_optional: '', modal_create_hw: '과제 만들기', vol: '회차', hw_title: '과제명', hw_description: '내용', deadline: '마감일', do_homework: '과제하기', hw_progress: '진행 상태', hw_submit: '제출', view_list: '명단보기', view_desc: '내용보기', do_submit: '제출하기', popup_notice: '알림', no_selected_hw: '선택된 과제가 없습니다.', hw_delete_confirm: '선택한 과제를 정말 삭제하시겠습니까?', hw_submitter: '과제 제출자 명단', hw_student_desc_1: "* '제출하기'를 눌러 제출을 완료하기 전까지 얼마든지 수정이 가능합니다", hw_student_desc_2: '* 제출 기한이 지나면 과제를 제출할 수 없습니다.', popup_create_class: '학급 만들기', class_name: '학급 이름', image: '이미지', select_class_image: '학급 이미지를 선택해 주세요.', type_class_description: '학급 소개 입력', set_as_primary_group: '기본학급으로 지정', set_primary_group: '지정', not_primary_group: '지정안함', type_class_name: '학급 이름을 입력해주세요. ', type_class_description_long: '학급 소개를 입력해 주세요. 170자 이내', add_students: '학생 추가하기', invite_students: '학생 초대하기', invite_with_class: '1. 학급 코드로 초대하기', invite_code_expiration: '코드 만료시간', generate_code_button: '코드재발급', generate_code_desc: '학생의 학급 코드 입력 방법', generate_code_desc1: '엔트리 홈페이지에서 로그인을 해주세요.', generate_code_desc2: '메뉴바에서<나의 학급>을 선택해주세요.', generate_code_desc3: '<학급코드 입력하기>를 눌러 학급코드를 입력해주세요.', invite_with_url: '2. 학급 URL로 초대하기', copy_invite_url: '복사하기', download_as_pdf: '학급계정 PDF로 내려받기', download_as_excel: '학급계정 엑셀로 내려받기', temp_password: '임시 비밀번호 발급', step_name: '이름 입력', step_info: '정보 추가/수정', preview: '미리보기', type_name_enter: '학급에 추가할 학생의 이름을 입력하고 엔터를 치세요.', multiple_name_possible: '여러명의 이름 입력이 가능합니다.', id_auto_create: '학번은 별도로 수정하지 않으면 자동으로 생성됩니다.', student_id_desc_1: '학급 아이디는 별도의 입력없이 자동으로 생성됩니다.', student_id_desc_2: '단, 엔트리에 이미 가입된 학생을 학급에 추가한다면 학생의 엔트리 아이디를', student_id_desc_3: '입력해주세요. 해당 학생은 로그인 후, 학급 초대를 수락하면 됩니다.', student_number: '학번', temp_password_desc_1: '임시 비밀번호로 로그인 후,', temp_password_desc_2: '신규 비밀번호를 다시 설정할 수 있도록 안내해주세요.', temp_password_desc_3: '*한번 발급된 임시 비밀번호는 다시 볼 수 없습니다.', temp_password_demo: '로그인 불가능한 안내 용 예시 계정입니다.', temp_works: '작품 보기', student_delete_confirm: '학생을 정말 삭제하시겠습니까?', no_student_selected: '선택된 학생이 없습니다.', class_assignment: '학급 과제', class_list: '학급 목록', select_grade: '학년을 선택 하세요.', add_project: '작품 공유하기', no_project_display: '학생들이 전시한 작품이 없습니다.', plz_display_project: '나의 작품을 전시해 주세요.', refuse_confirm: '학급 초대를 정말 거절하시겠습니까?', select_class: '학급 선택', group_already_registered: '이미 가입된 학급입니다.', my_page_entry: '엔트리', my_page_title: '마이페이지', my_classGroup_title: '나의 학급', my_classGroup_title_view: '나의 학급 보기', my_space_area: '나만의 공간', mon: '월', tue: '화', wed: '수', thu: '목', fri: '금', sat: '토', sun: '일', jan: '1월', feb: '2월', mar: '3월', apr: '4월', may: '5월', jun: '6월', jul: '7월', aug: '8월', sep: '9월', oct: '10월', nov: '11월', dec: '12월', plz_select_lecture: '강의를 선택해 주세요.', plz_set_deadline: '마감일을 설정해 주세요.', hide_entry: '엔트리 가리기', hide_others: '기타 가리기', show_all: '모두 보기', lecture_description: '선생님들이 직접 만드는 엔트리 학습 공간입니다. 강의에서 예시작품을 보고 작품을 만들며 배워 보세요.', curriculum_description: '학습 순서와 주제에 따라 여러 강의가 모아진 학습 공간입니다. 강의 모음의 순서에 맞춰 차근차근 배워보세요.', linebreak_off_desc_1: '글상자의 크기가 글자의 크기를 결정합니다.', linebreak_off_desc_2: '내용을 한 줄로만 작성할 수 있습니다.', linebreak_off_desc_3: '새로운 글자가 추가되면 글상자의 좌우 길이가 길어집니다.', linebreak_on_desc_1: '글상자의 크기가 글자가 쓰일 수 있는 영역을 결정합니다.', linebreak_on_desc_2: '내용 작성시 엔터키로 줄바꿈을 할 수 있습니다.', linebreak_on_desc_3: '새로운 글자 추가 시 문장의 길이가 글상자의 가로 영역을 넘어가면 자동으로 줄이 바뀝니다.', not_supported_text: '해당 글씨체는 한자를 지원하지 않습니다.', entry_with: '함께 만드는 엔트리', ebs_season_1: '시즌 1 보러가기', ebs_season_2: '시즌 2 보러가기', hello_ebs: '헬로! EBS 소프트웨어', hello_ebs_desc: '<헬로! EBS 소프트웨어> 엔트리 버전의 양방향 서비스를 만나보세요! \n <헬로! EBS 소프트웨어>의 동영상 강의를 통해 \n 소프트웨어 코딩의 기본 개념을 배운 후 양방향 코딩 미션에 도전하세요!\n 방송에서는 볼 수 없었던 <대.소.동> 친구들의 \n 비하인드 스토리를 볼 수 있습니다!', hello_ebs_sub_1: 'EBS 중학 엔트리 버전의 양방향 서비스를 ', hello_ebs_sub_2: '만나보세요! ', exhibit_4th_title: '엔트리 4주년 기념', exhibit_4th_subtitle: '엔트리 작품 공모전', exhibit_4th_desc1: '엔트리 탄생 4주년을 기념하여 작품 공모전을 개최합니다.', exhibit_4th_desc2: '‘우리 모두를 위한 소프트웨어’를 주제로', exhibit_4th_desc3: '여러분의 멋진 작품을 뽐내보세요!', exhibit_4th_button: '자세히 보기', visang_edu_entry: '비상교육 엔트리 학습하기', cmass_edu_entry: '씨마스 엔트리 학습하기', chunjae_edu_entry: '천재교과서 엔트리 학습하기', kumsungemt_edu_entry: '금성출판사 엔트리 학습하기', kumsungMid_edu_entry: '금성출판사 엔트리 학습하기', gilbutEdu_edu_entry: '길벗출판사 엔트리 학습하기', miraenCoding_edu_entry: '미래엔 엔트리 학습하기', textbook_help_data: '도움자료', textbook_teaching_activity: '수업 교안&활동지', textbook_kyohacksa: '교학사', textbook_kumsung: '금성출판사', textbook_donga: '동아출판', textbook_chunjae: '천재교과서', textbook_miraen: '미래엔', textbook_visang: '비상교육', partner: '파트너', project_term_popup_title: '작품 공개에 따른 엔트리 저작권 정책 동의', project_term_popup_description_1: '작품 공개를 위해', project_term_popup_description_2: '아래 정책을 확인해주세요.', project_term_popup_description_3: '', project_term_popup_description_4: '', project_term_agree_1_1: '내가 만든 작품과 그 소스코드의 공개를 동의합니다.', project_term_agree_2_1: '다른 사람이 나의 작품을 이용하는 것을 허락합니다.', project_term_agree_2_2: '( 복제 , 배포 , 공중송신 포함 )', project_term_agree_3_1: '다른 사람이 나의 작품을 수정하는 것을 허락합니다.', project_term_agree_3_2: '( 리믹스, 변형, 2차 제작물 작성 포함)', agree_all: '전체 동의', select_login: '로그인 선택', select: '선택하세요', with_login: '로그인 하고', without_login: '로그인 안하고', start_challenge: '미션 도전하기', start_challenge_2: '미션 도전하기', if_not_save_not_login: '* 로그인을 안하고 미션에 참여하시면 진행 상황이 저장되지 않습니다.', if_not_member_yet: '엔트리 회원이 아니라면?', join_entry: '엔트리 회원 가입하기', learned_computing: '기존에 소프트웨어 교육을 받아보셨나요?', cparty_index_description_1: '두근두근 소프트웨어와 첫 만남.', cparty_index_description_2: '소프트웨어랑 재미있게 놀다 보면 소프트웨어의 원리도 배우고, 생각하는 힘도 쑥쑥!', cparty_index_description_3: '엔트리를 통해 코딩 미션에 도전하고 인증서 받으세요.', cparty_index_description_4: '2015 Online Coding Party는', cparty_index_description_5: 'SW교육 체험 주간', cparty_index_description_6: '의 일환으로써,', cparty_index_description_7: '초등컴퓨팅교사협회', cparty_index_description_8: '과 함께 만들어졌습니다.', cparty_index_description_9: '2016 Online Coding Party는', cparty_index_description_10: '2017 Online Coding Party는', cparty_index_description_11: "'SW교육을 준비하는 선생님들의 모임'", congratulation: '축하 드립니다!', warm_up: '체험', beginner: '입문', intermediate: '기본', advanced: '발전', applied: '응용', cert_msg_tail: '과정을 성공적으로 마쳤습니다.', cert_msg_head: '', maze_text_content_1: '안녕? 나는 엔트리봇이야. 지금 나는 공장에서 탈출을 해야 해! 탈출하기 위해서 먼저 몸을 고쳐야 할 것 같아. 앞에 있는 부품을 얻을 수 있게 도와줄래? move()', maze_text_content_2: '좋아 아주 잘했어! 덕분에 몸이 한결 가벼워졌어! 이번에도 부품상자까지 나를 이동시켜줘. 그런데 가는길에 장애물이 있어. 장애물 앞에서는 jump()', maze_text_content_3: '멋진걸! 저기에도 부품이 있어! 길이 조금 꼬여있지만 오른쪽, 왼쪽으로 회전할 수 있는 right(); left(); 명령어를 쓰면 충분히 갈 수 있을것 같아!', maze_text_content_4: '좋아 이제 움직이는 건 많이 편해졌어! 이번에는 지금까지 배운 명령어를 같이 써서 저 부품상자까지 가보자!', maze_text_content_5: '우와 부품이 두 개나 있잖아! 두 개 다 챙겨서 가자! 그러면 몸을 빨리 고칠 수 있을 것 같아!', maze_text_content_6: '이번이 마지막 부품들이야! 저것들만 있으면 내 몸을 다 고칠 수 있을 거야! 이번에도 도와줄 거지?', maze_text_content_7: '덕분에 몸이 아주 좋아졌어! 이제 똑같은 일을 여러 번 반복해도 무리는 없을 거야. 어? 그런데 앞에 있는 저 로봇은 뭐지? 뭔가 도움이 필요한 것 같아! 도와주자! for 명령어를 사용해서 저 친구한테 나를 데려다줘!', maze_text_content_8: '좋아! 덕분에 친구 로봇을 살릴 수 있었어! 하지만 앞에도 도움이 필요한 친구가 있네, 하지만 이번에는 벌집이 있으니까 조심해서 벌집에 안 닿게 뛰어넘어가자! 할 수 있겠지? 이번에도 for 명령어를 사용해서 친구가 있는곳까지 나를 이동시켜줘!', maze_text_content_9: '이번에는 for 명령어 대신 미션이 끝날때까지 같은 일을 반복하도록 하는 while 명령어를 사용해봐! 나를 친구에게 데려다주면 미션이 끝나!', maze_text_content_10: '이번에는 if 명령어가 나왔어! if와 while 명령어를 사용해서 내가 언제 어느 쪽으로 회전해야 하는지 알려줘!', maze_text_content_11: '좋아 아까 했던 것처럼 해볼까? 언제 왼쪽으로 돌아야 하는지 알려줄 수 있겠어?', maze_text_content_12: '이번에는 중간중간 벌집(bee)이 있네? 언제 뛰어넘어가야 할지 알려줄래?', maze_text_content_13: '여기저기 도움이 필요한 친구들이 많이 있네! 모두 가서 도와주자!', maze_text_content_14: '우와 이번에도 도와줘야 할 친구들이 많네. 먼저 조그마한 사각형을 돌도록 명령어를 만들고 만든 걸 반복해서 모든 친구를 구해보자.', maze_text_content_15: '오래 움직이다 보니 벌써 지쳐버렸어. 자주 쓰는 명령어를 function 명령어를 사용해서 함수로 만들어 놓았어! 함수를 사용하여 나를 배터리 까지 이동시켜줘!', maze_text_content_16: '좋아 멋진걸! 그럼 이번에는 함수에 들어갈 명령어들을 넣어서 나를 배터리까지 이동시켜줘!', maze_text_content_17: '좋아 이번에는 함수를 만들고, 함수를 사용해서 배터리를 얻을 수 있도록 도와줘! 함수를 만들때 jump();를 잘 섞어봐!', maze_text_content_18: '이번에는 길이 좀 복잡한걸? 그래도 언제 left();를 쓰고, 언제 right();를 쓰면 되는지 알려만 주면 배터리 까지 갈 수 있겠어!.', maze_text_content_19: '이번에는 함수가 미리 정해져 있어! 그런데 함수만 써서 배터리까지 가기 힘들것 같아. 함수와 다른 명령어들을 섞어 써서 배터리 까지 이동시켜줘!', maze_text_content_20: '좋아! 지금까지 정말 멋지게 잘 해줬어. 덕분에 이제 마지막 배터리만 채우면 앞으로는 충전이 필요 없을 거야. 함수를 이용해서 저 배터리를 얻고 내가 자유롭게 살 수 있도록 도와줘!', maze_content_1: '안녕 나는 엔트리봇이라고 해. 지금 나는 공장에서 탈출하려는데 먼저 몸을 고쳐야 할 것 같아. 앞에 있는 부품을 얻을 수 있게 도와줄래? 앞으로 가기 블록을 조립하고 시작을 눌러봐.', maze_content_2: '좋아 아주 잘했어! 덕분에 몸이 한결 가벼워졌어! 앞에도 부품이 있는데 이번에는 잘못 가다간 감전되기 쉬울 것 같아. 한 번 장애물 뛰어넘기 블록을 써서 부품까지 가볼까?', maze_content_3: '멋진걸! 저기에도 부품이 있어! 길이 조금 꼬여있지만 회전하기 블록을 쓰면 충분히 갈 수 있을 것 같아! 이번에도 도와줄 거지?', maze_content_4: '좋아 이제 움직이는 건 많이 편해졌어! 이번에는 회전과 뛰어넘기를 같이 써서 저 부품을 얻어보자!', maze_content_5: '우와 부품이 두 개나 있잖아! 두 개 다 챙겨서 가자! 그러면 몸을 빨리 고칠 수 있을 것 같아!', maze_content_6: '이번이 마지막 부품들이야! 저것들만 있으면 내 몸을 다 고칠 수 있을 거야! 이번에도 도와줄 거지?', maze_content_7: '덕분에 몸이 아주 좋아졌어! 이제 똑같은 일을 여러 번 반복해도 무리는 없을 거야. 어? 그런데 앞에 있는 저 로봇은 뭐지? 뭔가 도움이 필요한 것 같아! 도와주자! 얼른 반복하기의 숫자를 바꿔서 저 친구한테 나를 데려다줘!', maze_content_8: '좋아! 덕분에 친구 로봇을 살릴 수 있었어! 하지만 앞에도 도움이 필요한 친구가 있는 것 같아, 하지만 이번에는 벌집이 있으니까 조심해서 벌집에 안 닿게 뛰어넘어가자! 할 수 있겠지? 그럼 아까 했던 것처럼 반복을 써서 친구한테 갈 수 있게 해줄래?', maze_content_9: '이번에는 숫자만큼 반복하는 게 아니라 친구 로봇한테 갈 때까지 똑같은 일을 반복할 수 있어! 이번에도 친구를 구할 수 있도록 도와줘!', maze_content_10: '이번에는 만약 블록이란 게 있어! 만약 블록을 써서 언제 어느 쪽으로 돌아야 하는지 알려줘!', maze_content_11: '좋아 아까 했던 것처럼 해볼까? 언제 왼쪽으로 돌아야 하는지 알려줄 수 있겠어?', maze_content_12: '이번에는 중간중간 벌집이 있네? 언제 뛰어넘어가야 할지 알려줄래?', maze_content_13: '여기저기 도움이 필요한 친구들이 많이 있네! 모두 도와주자!', maze_content_14: '우와 이번에도 도와줘야 할 친구들이 많네. 먼저 조그마한 사각형을 돌도록 블록을 만들고 만든 걸 반복해서 모든 친구를 구해보자.', maze_content_15: '반복을 하도 많이 했더니 자주 쓰는 블록은 외울 수 있을 것 같아! 약속 블록은 지금 내가 외운 블록들이야! 일단은 오래 움직여서 지쳤으니까 배터리를 좀 채울 수 있게 약속 호출 블록을 써서 배터리를 채울 수 있게 해줘!', maze_content_16: '좋아 멋진걸! 그럼 이번에는 네가 자주 쓰일 블록을 나한테 가르쳐줘! 약속 정의 블록 안에 자주 쓰일 블록을 넣어보면 돼!', maze_content_17: '좋아 이번에도 그러면 약속을 이용해서 배터리를 얻을 수 있도록 도와줄 거지? 약속에 뛰어넘기를 잘 섞어봐!', maze_content_18: '이번에는 길이 좀 복잡한걸? 그래도 언제 왼쪽으로 돌고, 언제 오른쪽으로 돌면 되는지 알려만 주면 충전할 수 있을 것 같아.', maze_content_19: '이번에는 약속이 미리 정해져 있어! 그런데 바로 약속을 쓰기에는 안될 것 같아. 내가 갈 길을 보고 약속을 쓰면 배터리를 채울 수 있을 것 같은데 도와줄 거지?', maze_content_20: '좋아! 지금까지 정말 멋지게 잘 해줬어. 덕분에 이제 마지막 배터리만 채우면 앞으로는 충전이 필요 없을 거야. 그러니까 약속을 이용해서 저 배터리를 얻고 내가 자유롭게 살 수 있도록 도와줄래?', maze_content_21: '안녕? 나는 엔트리 봇이야. 지금 많은 친구들이 내 도움을 필요로 하고 있어. 반복하기를 이용해서 친구들을 도울수 있게 데려다 줘!', maze_content_22: '고마워! 이번에는 벌집을 뛰어넘어서 친구를 구하러 갈 수 있게 도와줘!', maze_content_23: '좋아! 이번에는 친구 로봇한테 갈 때까지 반복하기를 이용해서 친구를 도울 수 있게 도와줘!', maze_content_24: '안녕! 나는 엔트리 봇이야. 지금 나는 너무 오래 움직여서 배터리를 채워야 해. 약속 불러오기를 써서 배터리를 채울 수 있도록 도와줘!', maze_content_25: '멋져! 이번에는 여러 약속을 불러와서 배터리가 있는 곳까지 가보자!', maze_content_26: '좋아! 이제 약속할 블록을 나한테 가르쳐줘! 약속하기 블록 안에 자주 쓰일 블록을 넣으면 돼!', maze_content_27: '지금은 미리 약속이 정해져 있어. 그런데, 약속을 쓰기위해서는 내가 갈 방향을 보고 약속을 사용해야해. 도와줄거지?', maze_content_28: '드디어 마지막이야! 약속을 이용하여 마지막 배터리를 얻을 수 있게 도와줘!', ai_content_1: '안녕? 나는 엔트리봇이라고 해. 우주 탐사를 마치고 지구로 돌아가려는데 우주를 떠다니는 돌들 때문에 쉽지 않네. 내가 안전하게 집에 갈 수 있도록 도와줄래? 나의 우주선에는 나의 앞과 위, 아래에 무엇이 어느 정도의 거리에 있는지 알려주는 레이더가 있어 너의 판단을 도와줄 거야!', ai_content_2: '고마워! 덕분에 돌을 쉽게 피할 수 있었어. 그런데 이번엔 더 많은 돌이 있잖아? 블록들을 조립하여 돌들을 이리저리 잘 피해 보자!', ai_content_3: '좋았어! 안전하게 돌을 피했어. 그런데 앞을 봐! 아까보다 더 많은 돌이 있어. 하지만 걱정하지 마. 나에게 반복하기 블록이 있거든. 반복하기 블록 안에 움직이는 블록을 넣으면 목적지에 도착할 때까지 계속 움직일게!', ai_content_4: '대단해! 반복하기 블록을 쓰니 많은 돌을 피하기가 훨씬 수월한걸! 하지만 이렇게 일일이 조종하기는 피곤하다. 나에겐 레이더가 있으니 앞으로 무엇이 나올지 알 수 있어. 앞으로 계속 가다가 앞에 돌이 있으면 피할 수 있도록 해줄래?', ai_content_5: '잘했어! 여기까지 와서 아주 기뻐. 이번에는 레이더가 앞에 있는 물체까지의 거리를 말해줄 거야. 이 기능을 사용하여 돌을 피해 보자! 돌까지의 거리가 멀 때는 앞으로 계속 가다가, 거리가 가까워지면 피할 수 있도록 해줄래?', ai_content_6: '와~ 멋진걸? 레이더를 활용하여 돌을 잘 피해 나가고 있어! 이번에는 여러 개의 레이더를 사용하여 이리저리 돌들을 피해 나갈 수 있게 만들어줄래?', ai_content_7: '휴~ 지구에 점점 가까워지고 있어! 돌을 피할 때 기왕이면 더 안전한 길로 가고 싶어! 아마도 돌이 더 멀리 있는 쪽이 더 안전한 길이겠지? 위쪽 레이더와 아래쪽 레이더를 비교하여 더 안전한 쪽으로 움직이도록 해줄래?', ai_content_8: '좋아! 덕분에 무사히 비행하고 있어. 어? 그런데 저게 뭐지? 저건 내가 아주 위급한 상황에서 사용할 수 있는 특별한 에너지야! 이번에는 저 아이템들을 모두 모으며 움직이자!', ai_content_9: '훌륭해! 이제 지구까지 얼마 안 남았어. 그런데 앞을 보니 돌들로 길이 꽉 막혀서 지나갈 수가 없잖아? 하지만 걱정하지 마. 아이템을 획득해서 사용하면 앞에 있는 꽉 막힌 돌들을 없앨 수 있다고!', ai_content_10: '좋아! 드디어 저기 지구가 보여! 이럴 수가! 이제는 날아오는 돌들을 미리 볼 수가 없잖아? 돌들이 어떻게 날아올지 알지 못해도 지금까지처럼만 움직이면 잘 피할 수 있을 것 같아! 지구까지 가보는 거야!', maze_hints_title_1: '시작 방법', maze_hints_content_1: '엔트리봇은 어떻게 움직이나요?', maze_hints_detail_1: '1. 블록 꾸러미에서 원하는 블록을 꺼내어 “시작하기를 클릭했을 때” 블록과 연결해봐
2. 다 조립했으면, 시작을 눌러봐
3. 나는 네가 조립한 블록대로 위에서부터 순서대로 움직일게', maze_hints_title_2: '장애물 뛰어넘기', maze_hints_content_2: '장애물이 있으면 어떻게 해야하나요?', maze_hints_detail_2: '길을 가다보면 장애물을 만날 수 있어.
장애물이 앞에 있을 때에는 뛰어넘기 블록을 사용해야 해.', maze_hints_title_3: '반복 블록(1)', maze_hints_content_3: '(3)회 반복하기 블록은 어떻게 사용하나요?', maze_hints_detail_3: '같은 행동을 여러번 반복하려면 ~번 반복하기 블록을 사용해야 해.
반복하고 싶은 블록들을 ~번 반복하기 안에 넣고 반복 횟수를 입력하면 돼.', maze_hints_title_4: '반복 블록(2)', maze_hints_content_4: '~를 만날 때 까지 반복하기 블록은 어떻게 사용하나요?', maze_hints_detail_4: "~까지 반복하기'를 사용하면 같은 행동을 언제까지 반복할지를 정해줄 수 있어.
반복하고 싶은 블록들을 ~까지 반복하기안에 넣으면 돼.
그러면 {이미지}와 같은 타일 위에 있는 경우 반복이 멈추게 될 거야.", maze_hints_title_5: '만약 블록', maze_hints_content_5: '만약 ~라면 블록은 어떻게 동작하나요?', maze_hints_detail_5: "만약 앞에 {이미지}가 있다면' 블록을 사용하면 앞에 {이미지}가 있을 때 어떤 행동을 할 지 정해줄 수 있어.
앞에 {이미지}가 있을 때에만 블록 안의 블록들을 실행하고
그렇지 않으면 실행하지 않게 되는 거야.", maze_hints_title_6: '반복 블록(3)', maze_hints_content_6: '모든 ~를 만날 때 까지 블록은 어떻게 동작하나요?', maze_hints_detail_6: '모든 {타일}에 한 번씩 도착할 때까지 그 안에 있는 블록을 반복해서 실행해.
모든 {타일}에 한 번씩 도착하면 반복이 멈추게 될 거야.', maze_hints_title_7: '특별 힌트', maze_hints_content_7: '너무 어려워요. 도와주세요.', maze_hints_detail_7: '내가 가야하는 길을 자세히 봐. 작은 사각형 4개가 보여?
작은 사각형을 도는 블록을 만들고, 반복하기를 사용해 보는것은 어때?', maze_hints_title_8: '약속', maze_hints_content_8: '약속하기/약속 불러오기 무엇인가요? 어떻게 사용하나요?', maze_hints_detail_8: "나를 움직이기 위해 자주 쓰는 블록들의 묶음을 '약속하기' 블록 아래에 조립하여 약속으로 만들 수 있어.
한번 만들어 놓은 약속은 '약속 불러오기' 블록을 사용하여 여러 번 꺼내 쓸 수 있다구.", ai_hints_title_1_1: '게임의 목표', ai_hints_content_1_1: '돌을 피해 오른쪽 행성까지 안전하게 이동할 수 있도록 도와주세요.', ai_hints_detail_1_1: '돌을 피해 오른쪽 행성까지 안전하게 이동할 수 있도록 도와주세요.', ai_hints_title_1_2: '시작 방법', ai_hints_content_1_2: '어떻게 시작할 수 있나요?', ai_hints_detail_1_2: '1. 블록 꾸러미에서 원하는 블록을 꺼내어 “시작하기를 클릭했을 때” 블록과 연결해봐
2. 다 조립했으면, 시작을 눌러봐
3. 나는 네가 조립한 블록대로 위에서부터 순서대로 움직일게', ai_hints_title_1_3: '움직이게 하기', ai_hints_content_1_3: '엔트리봇은 어떻게 움직이나요?', ai_hints_detail_1_3: '나는 위쪽으로 가거나 앞으로 가거나 아래쪽으로 갈 수 있어.
방향을 정할 때에는 돌이 없는 방향으로 안전하게 갈 수 있도록 해줘.
나를 화면 밖으로 내보내면 우주미아가 되어버리니 조심해!', ai_hints_title_2_1: '게임의 목표', ai_hints_content_2_1: '반복하기 블록으로 돌들을 피할 수 있도록 도와주세요.', ai_hints_detail_2_1: '반복하기 블록으로 돌들을 피할 수 있도록 도와주세요.', ai_hints_title_2_2: '반복 블록', ai_hints_content_2_2: '반복 블록은 무슨 블록인가요?', ai_hints_detail_2_2: '휴~ 이번에 가야 할 길은 너무 멀어서 하나씩 조립하기는 힘들겠는걸? 반복하기블록을 사용해봐.
똑같이 반복되는 블록들을 반복하기 블록으로 묶어주면 아주 긴 블록을 짧게 줄여줄 수 있어!', ai_hints_content_3_1: '만약 블록으로 돌을 피할 수 있도록 도와주세요.', ai_hints_title_3_2: '만약 블록(1)', ai_hints_content_3_2: '만약 ~라면 블록은 어떻게 동작하나요?', ai_hints_detail_3_2: "만약 앞에 ~가 있다면 / 아니면 블록을 사용하면 내 바로 앞에 돌이 있는지 없는지 확인해서 다르게 움직일 수 있어~
만약 내 바로 앞에 돌이 있다면 '만약' 아래에 있는 블록들을 실행하고 돌이 없으면 '아니면' 안에 있는 블록들을 실행할 거야.
내 바로 앞에 돌이 있을 때와 없을 때, 어떻게 움직일지 잘 결정해줘~", ai_hints_content_4_1: '레이더의 사용 방법을 익히고 돌을 피해보세요.', ai_hints_detail_4_1: '레이더의 사용 방법을 익히고 돌을 피해보세요.', ai_hints_title_4_2: '레이더(1)', ai_hints_content_4_2: '레이더란 무엇인가요? 어떻게 활용할 수 있나요?', ai_hints_detail_4_2: "레이더는 지금 내가 물체와 얼마나 떨어져 있는지 알려주는 기계야.
만약 바로 내 앞에 무엇인가 있다면 앞쪽 레이더는 '1'을 보여줘.
또, 레이더는 혼자 있을 때 보다 만약 <사실>이라면 / 아니면 블록과
같이 쓰이면 아주 강력하게 쓸 수 있어.
예를 들어 내 앞에 물체와의 거리가 1보다 크다면 나는 안전하게 앞으로 갈 수 있겠지만, 아니라면 위나 아래쪽으로 피하도록 할 수 있지.", ai_hints_title_4_3: '만약 블록(2)', ai_hints_content_4_3: '만약 <사실>이라면 블록은 어떻게 사용하나요?', ai_hints_detail_4_3: "만약 <사실>이라면 / 아니면 블록은 <사실> 안에 있는 내용이 맞으면 '만약' 아래에 있는 블록을 실행하고, 아니면 '아니면' 아래에 있는 블록을 실행해.
어떤 상황에서 다르게 움직이고 싶은 지를 잘 생각해서 <사실> 안에 적절한 판단 조건을 만들어 넣어봐.
판단 조건을 만족해서 '만약' 아래에 있는 블록을 실행하고 나면 '아니면' 아래에 있는 블록들은 실행되지 않는다는 걸 기억해!", ai_hints_content_5_1: '레이더를 활용해 돌을 쉽게 피할 수 있도록 도와주세요.', ai_hints_detail_5_1: '레이더를 활용해 돌을 쉽게 피할 수 있도록 도와주세요.', ai_hints_title_5_2: '만약 블록(3)', ai_hints_content_5_2: '만약 블록이 겹쳐져 있으면 어떻게 동작하나요?', ai_hints_detail_5_2: '만약 ~ / 아니면 블록안에도 만약 ~ / 아니면 블록을 넣을 수 있어! 이렇게 되면 다양한 상황에서 내가 어떻게 행동해야 할지 정할 수 있어.
예를 들어 앞에 돌이 길을 막고 있을때와 없을때의 행동을 정한다음, 돌이 있을때의 상황에서도 상황에 따라 위쪽으로 갈지 아래쪽으로 갈지 선택 할 수 있어', ai_hints_title_6_1: '레이더(2)', ai_hints_content_6_1: '위쪽 레이더와 아래쪽 레이더의 값을 비교하고 싶을 땐 어떻게 하나요?', ai_hints_detail_6_1: '([위쪽]레이더) 블록은 위쪽 물체까지의 거리를 뜻하는 블록이야.
아래쪽과 위쪽 중에서 어느 쪽에 돌이 더 멀리 있는지 확인하기 위해서 쓸 수 있는 블록이지.
돌을 피해가는 길을 선택할 때에는 돌이 멀리 떨어져 있는 쪽으로 피하는게 앞으로 멀리 가는데 유리할거야~', ai_hints_content_7_1: '아이템을 향해 이동하여 돌을 피해보세요.', ai_hints_detail_7_1: '아이템을 향해 이동하여 돌을 피해보세요.', ai_hints_title_7_2: '물체 이름 확인', ai_hints_content_7_2: '앞으로 만날 물체의 이름을 확인해서 무엇을 할 수 있나요?', ai_hints_detail_7_2: '아이템을 얻기위해서는 아이템이 어디에 있는지 확인할 필요가 있어.
그럴 때 사용할 수 있는 블록이 [위쪽] 물체는 [아이템]인가? 블록이야.
이 블록을 활용하면 아이템이 어느 위치에 있는지 알 수 있고 아이템이 있는 방향으로 움직이도록 블록을 조립할 수 있어.', ai_hints_content_8_1: '아이템을 적절하게 사용해서 돌을 피해보세요.', ai_hints_detail_8_1: '아이템을 적절하게 사용해서 돌을 피해보세요.', ai_hints_title_8_2: '아이템', ai_hints_content_8_2: '아이템은 어떻게 얻고 사용하나요?', ai_hints_detail_8_2: '돌들을 이리저리 잘 피해 나가더라도 앞이 모두 돌들로 꽉 막혀있을 땐 빠져나갈 방법이 없겠지? 그럴 때에는 아이템사용 블럭을 사용해봐.
이 블록은 내 앞의 돌들을 모두 없애는 블록이야.
단, 아이템이 있어야지만 블록을 사용할 수 있고, 아이템은 이미지를 지나면 얻을 수 있어.', ai_hints_content_9_1: '지금까지 배운 것들을 모두 활용해서 최대한 멀리 가보세요.', ai_hints_detail_9_1: '지금까지 배운 것들을 모두 활용해서 최대한 멀리 가보세요.', ai_hints_title_9_2: '그리고', ai_hints_content_9_2: '그리고 블록은 어떻게 사용하나요?', ai_hints_detail_9_2: '그리고 블록에는 여러개의 조건을 넣을 수 있어, 넣은 모든 조건이 사실일때만 사실이 되어 만약 블록 안에 있는 블록이 실행되고, 하나라도 거짓이 있으면 거짓으로 인식해서 그 안에 있는 블록을 실행하지 않아', maze_text_goal_1: 'move(); 명령어를 사용하여 부품 상자까지 나를 이동시켜줘!', maze_text_goal_2: 'jump(); 명령어로 장애물을 피해 부품 상자까지 나를 이동시켜줘!', maze_text_goal_3: 'left(); right(); 명령어로 부품상자까지 나를 이동시켜줘!', maze_text_goal_4: '여러가지 명령어를 사용하여 부품상자까지 나를 이동시켜줘!', maze_text_goal_5: '두 부품상자에 다 갈 수 있도록 나를 이동시켜줘!', maze_text_goal_6: '두 부품상자에 다 갈 수 있도록 나를 이동시켜줘!', maze_text_goal_7: 'for 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_8: 'for 명령어를 사용하고, 장애물을 피해 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_9: 'while 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_10: 'if와 while 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_11: 'if와 while 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_12: 'if와 while 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_13: 'while과 for 명령어를 사용하여 모든 친구들을 만날 수 있도록 나를 이동시켜줘!', maze_text_goal_14: 'while과 for 명령어를 사용하여 모든 친구들을 만날 수 있도록 나를 이동시켜줘!', maze_text_goal_15: '함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_16: '함수에 명령어를 넣고 함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_17: '함수에 명령어를 넣고 함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_18: '함수에 명령어를 넣고 함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_19: '함수에 명령어를 넣고 함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_20: '함수와 다른명령어들을 섞어 사용하여 배터리까지 나를 이동시켜줘!', maze_attack_range: '공격 가능 횟수', maze_attack: '공격', maze_attack_both_sides: '양 옆 공격', above_radar: '위쪽 레이더', above_radar_text_mode: 'radar_up', bottom_radar: '아래쪽 레이더', bottom_radar_text_mode: 'radar_down', front_radar: '앞쪽 레이더', front_radar_text_mode: 'radar_right', above_object: '위쪽 물체', above_object_text_mode: 'object_up', front_object: '앞쪽 물체', front_object_text_mode: 'object_right', below_object: '아래쪽 물체', below_object_text_mode: 'object_down', destination: '목적지', asteroids: '돌', item: '아이템', wall: '벽', destination_text_mode: 'destination', asteroids_text_mode: 'stone', item_text_mode: 'item', wall_text_mode: 'wall', buy_now: '구매바로가기', goals: '목표', instructions: '이용 안내', object_info: '오브젝트 정보', entry_basic_mission: '엔트리 기본 미션', entry_application_mission: '엔트리 응용 미션', maze_move_forward: '앞으로 한 칸 이동', maze_when_run: '시작하기를 클릭했을때', maze_turn_left: '왼쪽으로 회전', maze_turn_right: '오른쪽으로 회전', maze_repeat_times_1: '', maze_repeat_times_2: '번 반복하기', maze_repeat_until_1: '', maze_repeat_until_2: '을 만날때까지 반복', maze_call_function: '약속 불러오기', maze_function: '약속하기', maze_repeat_until_all_1: '모든', maze_repeat_until_all_2: '만날 때 까지 반복', command_guide: '명령어 도움말', ai_success_msg_1: '덕분에 무사히 지구에 도착할 수 있었어! 고마워!', ai_success_msg_2: '다행이야! 덕분에', ai_success_msg_3: '번 만큼 앞쪽으로 갈 수 있어서 지구에 구조 신호를 보냈어! 이제 지구에서 구조대가 올거야! 고마워!', ai_success_msg_4: '좋았어!', ai_cause_msg_1: '이런, 어떻게 움직여야 할 지 더 말해줄래?', ai_cause_msg_2: '아이쿠! 정말로 위험했어! 다시 도전해보자', ai_cause_msg_3: '우와왓! 가야할 길에서 벗어나버리면 우주 미아가 되버릴꺼야. 다시 도전해보자', ai_cause_msg_4: '너무 복잡해, 이 블록을 써서 움직여볼래?', ai_move_forward: '앞으로 가기', ai_move_above: '위쪽으로 가기', ai_move_under: '아래쪽으로 가기', ai_repeat_until_dest: '목적지에 도달 할 때까지 반복하기', ai_if_front_1: '만약 앞에', ai_if_front_2: '가 있다면', ai_else: '아니면', ai_if_1: '만약', ai_if_2: '이라면', ai_use_item: '아이템 사용', ai_radar: '레이더', ai_above: '위쪽', ai_front: '앞쪽', ai_under: '아래쪽', ai_object_is_1: '', ai_object_is_2: '물체는', challengeMission: '다른 미션 도전하기', nextMission: '다음 미션 도전하기', withTeacher: '함께 만든 선생님들', host: '주최', support: '후원', subjectivity: '주관', learnMore: ' 더 배우고 싶어요', ai_object_is_3: '인가?', stage_is_not_available: '아직 진행할 수 없는 스테이지입니다. 순서대로 스테이지를 진행해 주세요.', progress_not_saved: '진행상황이 저장되지 않습니다.', want_refresh: '이 페이지를 새로고침 하시겠습니까?', monthly_entry_grade: '초등학교 3학년 ~ 중학교 3학년', monthly_entry_contents: '매월 발간되는 월간엔트리와 함께 소프트웨어 교육을 시작해 보세요! 차근차근 따라하며 쉽게 익힐 수 있도록 가볍게 구성되어있습니다. 기본, 응용 콘텐츠와 더 나아가기까지! 매월 업데이트되는 8개의 콘텐츠와 교재를 만나보세요~', monthly_entry_etc1: '*메인 페이지의 월간 엔트리 추천코스를 활용하면 더욱 쉽게 수업을 할 수 있습니다.', monthly_entry_etc2: '*월간엔트리는 학기 중에만 발간됩니다.', group_make_lecture_1: '내가 만든 강의가 없습니다.', group_make_lecture_2: "'만들기>오픈 강의 만들기'에서", group_make_lecture_3: '우리반 학습내용에 추가하고 싶은 강의를 만들어 주세요.', group_make_lecture_4: '강의 만들기', group_add_lecture_1: '관심 강의가 없습니다.', group_add_lecture_2: "'학습하기>오픈 강의> 강의'에서 우리반 학습내용에", group_add_lecture_3: '추가하고 싶은 강의를 관심강의로 등록해 주세요.', group_add_lecture_4: '강의 보기', group_make_course_1: '내가 만든 강의 모음이 없습니다.', group_make_course_2: "'만들기 > 오픈 강의 만들기> 강의 모음 만들기'에서", group_make_course_3: '학습내용에 추가하고 싶은 강의 모음을 만들어 주세요.', group_make_course_4: '강의 모음 만들기', group_add_course_1: '관심 강의 모음이 없습니다.', group_add_course_2: "'학습하기 > 오픈 강의 > 강의 모음'에서 우리반 학습내용에", group_add_course_3: '추가하고 싶은 강의 모음을 관심 강의 모음으로 등록해 주세요.', group_add_course_4: '강의 모음 보기', hw_main_title: '프로그램 다운로드', datablock_contest_title: '데이터분석 블록 추가', datablock_content_head: '데이터를 가공하고 표현하기', datablock_content_body1: '생활 속 다양한 데이터를 차트로 표현하고 의미를 찾아', datablock_content_body2: '실생활 문제를 해결해보세요!', campaign_contest_title: '아름다운 인터넷 세상을 만들어요', campaign_content_head: '엔트리 작품 공모전', campaign_content_body1: "'인터넷윤리'에 대해 알기 쉽고 재미있게", campaign_content_body2: '작품을 만들어 응모해주세요!', campaign_content_button: '자세히 보기', code_management_1: '엔트리 캠페인 #1 코드 잘 관리하기', code_management_2: '나의 보관함과 메모 활용', code_management_3: '새 기능 나의 보관함과 메모로 하는 코드 관리 비법!', code_management_4: '작품을 더 잘 만들고 쉽게 공유하는 방법을 알아보아요.', code_management_5: '캠페인 보기', shcoolbook_study_1: '교과서 내용 그대로 학습하세요.', shcoolbook_study_2: '교과서 학습하기', shcoolbook_study_3: '선생님은 교실에서 수업 진행을', shcoolbook_study_4: '학생은 집에서 복습을 할 수 있습니다!', shcoolbook_study_5: '학습하기', main_learn_1: '엔트리에 처음 오셨다면', main_learn_2: '엔트리 알아보기', main_learn_3: '영상을 통해 엔트리의 다양한 기능을 알아보고,', main_learn_4: '멋진 작품을 만들어 친구들과 공유해보세요!', main_learn_5: '영상보기', hw_desc_wrapper: '엔트리 하드웨어 연결 프로그램과 오프라인 버전이 \n서비스를 한층 더 강화해 업그레이드 되었습니다.\n업데이트 된 프로그램을 설치해주세요!', hw_downolad_link: '하드웨어 연결 \n프로그램 다운로드', save_as_image_all: '모든 코드 이미지로 저장하기', save_as_image: '이미지로 저장하기', maze_perfect_success: '멋져! 완벽하게 성공했어~', maze_success_many_block_1: '좋아', maze_fail_obstacle_remain: "친구들이 다치지 않도록 모든 을 없애줘.", maze_fail_item_remain: '샐리 공주를 구하기 위해 모든 미네랄을 모아 와줘.', maple_fail_item_remain: '음식을 다 먹지 못해서 힘이 나지 않아. 모든 음식을 다 먹을 수 있도록 도와줘.', maze_fail_not_found_destory_object: '아무것도 없는 곳에 능력을 낭비하면 안 돼!', maze_fail_not_found_destory_monster: '몬스터가 없는 곳에 공격을 하면 안 돼!', maple_fail_not_found_destory_monster: '공격 블록은 몬스터가 있을 때에만 해야 돼!', maze_fail_more_move: '목적지까지는 좀 더 움직여야 해!', maze_fail_wall_crash: '으앗! 거긴 갈 수 없는 곳이야!', maze_fail_contact_brick: '에구구… 부딪혔다!', maze_fail_contact_iron1: '으앗! 장애물에 부딪혀버렸어', maze_fail_contact_iron2: '으앗! 장애물이 떨어져서 다쳐버렸어. 장애물이 내려오기전에 움직여줘..', maze_fail_fall_hole: '앗, 함정에 빠져 버렸어...', maze_fail_hit_unit: '몬스터에게 당해버렸어! 위험한 몬스터를 물리치기 위해 하트 날리기 블록을 사용해줘!', maze_fail_hit_unit2: '윽, 몬스터에게 공격당했다! 두 칸 떨어진 곳에서 공격해줘!', maze_fail_hit_unit_by_mushroom: "주황버섯에게 당해버렸어!
공격하기 블록을 사용해서 나쁜 몬스터를 혼내줘!", maze_fail_hit_unit_by_lupin: "루팡에게 당해버렸어!
공격하기 블록을 두 칸 떨어진 곳에서 사용해서 나쁜 몬스터를 혼내줘!", maze_fail_elnath_fail: '으앗! 나쁜 몬스터가 나를 공격했어.
나쁜 몬스터가 나에게 다가오지 못하게 혼내줘!', maze_fail_pepe: '', maze_fail_yeti: "그 몬스터는 너무 강해서 공격하기 블록으로는 혼내줄 수 없어
공격하기 블록을 사용해보자.", maze_fail_peti: "그 몬스터에게 공격하기 블록을 사용하면,
강한 몬스터인 가 나왔을 때 혼내줄 수 없어
공격하기 블록을 사용해보자.", maze_fail_both_side: '양 옆 공격하기는 양쪽에 몬스터가 있을 때에만 사용해야 돼!', maze_wrong_attack_obstacle: "이 곳에서는 공격하기 블록을 사용할 수 없어
주황 버섯에게는 공격하기 블록을 사용해보자.", maze_fail_contact_spider: '거미집에 걸려 움직일 수가 없어...', maze_success_perfect: '멋져! 완벽하게 성공했어~', maze_success_block_excess: '좋아! %1개의 블록을 사용해서 성공했어!
하지만, %2개의 블록만으로 성공하는 방법도 있어. 다시 도전해 보는 건 어때?', maze_success_not_essential: '좋아! %1개의 블록을 사용해서 성공했어!
하지만 이 블록을 사용하면 더 쉽게 해결할 수 있어. 다시 도전해 보는 건 어때?', maze_success_final_perfect_basic: '좋아! 샐리 공주가 어디 있는지 찾았어! 이제 샐리 공주를 구할 수 있을 거야!', maze_success_final_block_excess_basic: '좋아! 샐리 공주가 어디 있는지 찾았어! 이제 샐리 공주를 구할 수 있을 거야!%1개의 블록을 사용했는데, %2개의 블록만으로 성공하는 방법도 있어. 다시 해볼래?', maze_success_final_perfect_advanced: '샐리 공주가 있는 곳까지 도착했어! 이제 악당 메피스토를 물리치고 샐리를 구하면 돼!', maze_success_final_block_excess_advanced: '샐리 공주가 있는 곳까지 도착했어! 이제 악당 메피스토를 물리치고 샐리를 구하면 돼!%1개의 블록을 사용했는데, %2개의 블록만으로 성공하는 방법도 있어. 다시 해볼래?', maze_success_final_distance: '좋아! 드디어 우리가 샐리 공주를 무사히 구해냈어. 구할 수 있도록 도와줘서 정말 고마워!
%1칸 움직였는데 다시 한 번 다시해서 60칸까지 가볼래?', maze_success_final_perfect_ai: '좋았어! 드디어 우리가 샐리 공주를 무사히 구해냈어. 구할 수 있도록 도와줘서 정말 고마워!', maple_success_perfect: '좋아! 완벽하게 성공했어!!', maple_success_block_excess: '좋아! %1개의 블록을 사용해서 성공했어!
그런데 %2개의 블록으로도 성공하는 방법이 있어. 다시 도전해 보는건 어때?', maple_success_not_essential: '좋아! %1개의 블록을 사용해서 성공했어!
그런데 이 블록을 사용하면 더 쉽게 해결할 수 있어. 다시 도전해 보는 건 어때?', maple_success_final_perfect_henesys: '멋져! 헤네시스 모험을 훌륭하게 해냈어.', maple_success_final_perfect_excess_henesys: '멋져! 헤네시스 모험을 잘 해냈어.
그런데 %2개의 블록으로도 성공하는 방법이 있어. 다시 도전해 보는 건 어때?', maple_success_final_not_essential_henesys: '멋져! 헤네시스 모험을 잘 해냈어.
그런데 이 블록을 사용하면 더 쉽게 해결할 수 있어. 다시 도전해 보는 건 어때?', maple_success_final_perfect_ellinia: '우와! 이 곳에서 정말 재밌는 모험을 했어!
다음 모험도 같이 할거지? ', maple_success_final_perfect_excess_ellinia: '우와! 이 곳에서 정말 재밌는 모험을 했어!
그런데 %2개의 블록으로도 성공하는 방법이 있어. 다시 도전해 보는 건 어때?', maple_success_final_not_essential_ellinia: '우와! 이 곳에서 정말 재밌는 모험을 했어!
그런데 이 블록을 사용하면 더 쉽게 해결할 수 있어. 다시 도전해 보는 건 어때?', maple_fail_fall_hole: '으앗! 빠져버렸어!
뛰어넘기 블록을 사용해서 건너가보자.', maple_fail_ladder_fall_hole: '으앗! 빠져버렸어!
사다리 타기 블록을 사용해서 다른 길로 가보자.', maple_fail_more_move: '성공하려면 목적지까지 조금 더 움직여야 해!', maple_fail_not_found_ladder: '이런, 여기엔 탈 수 있는 사다리가 없어.
사다리 타기 블록은 사다리가 있는 곳에서만 사용 해야해.', maple_fail_not_found_meat: '이런, 여기엔 먹을 수 있는 음식이 없어!
음식 먹기 블록은 음식이 있는 곳에서만 사용 해야해.', maple_cert_input_title: '내가 받을 인증서에 적힐 이름은?', maze_distance1: '거리 1', maze_distance2: '거리 2', maze_distance3: '거리 3', ev3: 'EV3', roborobo_roduino: '로두이노', roborobo_schoolkit: '스쿨키트', smartboard: '과학상자 코딩보드', smartboardbt: '과학상자 코딩보드(무선)', codestar: '코드스타', cobl: '코블', cobl_bt: '코블 블루투스', block_coding: '블록코딩', python_coding: '엔트리파이선', dadublock: '다두블럭', dadublock_car: '다두블럭 자동차', blacksmith: '대장장이 보드', course_submit_homework: '과제 제출', course_done_study: '학습 완료', course_show_list: '목록', modi: '모디', chocopi: '초코파이보드', coconut: '코코넛', jdkit: '제이디키트', practical_course: '교과용 만들기', entry_user_policy: '엔트리 이용정책', entry_scholarship_title: '엔트리 학술 자료', entry_scholarship_content: '엔트리는 대학/학회 등과 함께 다양한 연구를 진행하여 전문성을 강화해나가고 있습니다. 엔트리에서 제공하는 연구용 자료를 확인해보세요', entry_scholarship_content_sub: '*엔트리에서 제공하는 데이터는 연구 및 분석에 활용될 수 있도록 온라인코딩파티에 참여한 사용자들이 미션을 해결하는 일련의 과정을 로그 형태로 저장한 데이터 입니다.', entry_scholarship_download: '자료 다운로드', codingparty_2016_title: '2016 온라인 코딩파티', codingparty_2016_content: '미션에 참여한 사용자들의 블록 조립 순서, 성공/실패 유무가 학년, 성별 정보와 함께 제공됩니다.', codingparty_2017_title: '2017 온라인 코딩파티', scholarship_go_mission: '미션 확인하기', scholarship_guide: '자료 활용 방법', scholarship_see_guide: '가이드 보기', scholarship_guide_desc: '연구용 자료를 읽고 활용할 수 있는 방법이 담긴 개발 가이드 입니다. ', scholarship_example: '자료 활용 예시', scholarship_example_desc: '연구용 자료를 활용하여 발표된 논문을 확인 할 수 있습니다.', scholarship_see_example: '논문 다운로드', altino: '알티노', private_project: '비공개 작품입니다.', learn_programming_entry_mission: '"엔트리봇"과 함께 미션 해결하기', learn_programming_line_mission: '"라인레인저스"와 샐리구하기', learn_programming_choseok: '"마음의 소리"의 조석과 게임 만들기', learn_programming_maple: '"핑크빈"과 함께 신나는 메이플 월드로!', learn_programming_level_novice: '기초', learn_programming_level_inter: '중급', learn_programming_level_advanced: '고급', line_look_for: '샐리를 찾아서', line_rangers_title_string: '학습하기 : 라인 레인저스', online_codingparty_certificate_string: '온라인 코딩파티', online_codingparty_line_title_string: '라인 레인저스', line_look_for_desc_1: '라인 레인저스의 힘을 모아 강력한 악당 메피스토를 물리치고 샐리를 구해주세요!', line_save: '샐리 구하기', line_save_desc_1: '메피스토 기지에 갇힌 샐리. 라인 레인저스가 장애물을 피해 샐리를 찾아갈 수 있도록 도와주세요!', line_escape: '샐리와 탈출하기', line_escape_desc_1: '폭파되고 있는 메피스토 기지에서 샐리와 라인 레인저스가 무사히 탈출할 수 있도록 도와주세요!', solve_choseok: '가위바위보 만들기', solve_choseok_desc_1: '만화 속 조석이 가위바위보 게임을 만들 수 있도록 도와주세요!', solve_henesys: '헤네시스', solve_ellinia: '엘리니아', solve_elnath: '엘나스', solve_henesys_desc_1: '마을을 모험하며, 배고픈 핑크빈이 음식을 배불리 먹을 수 있도록 도와주세요!', solve_ellinia_desc_1: '숲 속을 탐험하며, 나쁜 몬스터들을 혼내주고 친구 몬스터들을 구해주세요!', solve_elnath_desc_1: '나쁜 몬스터가 점령한 설산을 지나, 새로운 모험을 시작할 수 있는 또 다른 포털을 찾아 떠나보세요 !', save_modified_shape: '수정된 내용을 저장하시겠습니까?', save_modified_table: '테이블에서 수정한 내용을 저장하시겠습니까?', attach_file: '첨부', enter_discuss_title: '제목을 입력해 주세요(40자 이하)', enter_discuss_title_alert: '제목을 입력해 주세요', discuss_upload_warn: '10MB이하의 파일을 올려주세요.', discuss_list: '목록보기', discuss_write_notice: '우리반 공지사항으로 지정하여 게시판 최상단에 노출합니다.', discuss_write_notice_open: '공지사항으로 지정하여 게시판 최상단에 노출합니다.', search_전체: '전체', search_게임: '게임', search_애니메이션: '애니메이션', search_미디어아트: '미디어 아트', search_피지컬: '피지컬', search_기타: '기타', discuss_write_textarea_placeholer: '엔트리 커뮤니티는 우리가 함께 만들어가는 공간입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_qna: '여기는 묻고답하기 게시판입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_tips: '여기는 노하우&팁 게시판입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_free: '여기는 엔트리 이야기 게시판입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_report: '여기는 제안 및 건의 게시판입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_contest2019: '※ 아래 양식으로 작성하여 제출해주세요.\n\n1. 학년 (예: 초등학교 5학년)\n\n2. 작품 URL (‘공유하기 > 작품 공유하기’에 작품을 공유한 다음, 작품 URL을 복사하여 적어주세요.)\n\n3. 작품 설명\n\n※ 공모전 수상자에게는 이메일이 발송될 예정입니다.\n엔트리의 ‘내 정보 수정‘에 이메일 정보를 꼭 입력해주세요!', maze_road: '길', account_deletion: '회원탈퇴', bug_report_too_many_request: '신고 내용이 전송 되고 있습니다. 잠시 후에 다시 시도해주시길 바랍니다.', pinkbean_index_title: '핑크빈과 함께 신나는 메이플 월드로!', pinkbean_index_content: '심심함을 참지 못한 핑크빈이 메이플 월드로 모험을 떠났습니다.
핑크빈과 함께 신나는 메이플 월드를 탐험하여 모험일지를 채워주세요.
각 단계를 통과하면서 자연스럽게 소프트웨어를 배워볼 수 있고, 미션을 마치면 인증서도 얻을 수 있습니다.', rangers_index_title: '라인 레인저스와 함께 샐리를 구하러 출동!', rangers_index_content: '악당 메피스토에게 납치된 샐리를 구하기 위해 라인 레인저스가 뭉쳤습니다.
소프트웨어의 원리를 통해 장애물을 극복하고, 샐리를 구출하는 영웅이 되어주세요.
각 단계를 통과하면서 자연스럽게 소프트웨어를 배워볼 수 있고, 미션을 마치면 인증서도
얻을 수 있습니다.', rangers_replay_button: '영상 다시보기', rangers_start_button: '미션 시작', lms_curriculum_intro: '학습시작', lms_curriculum_goal: '학습목표', lms_curriculum_prepare: '학습준비', lms_curriculum_study: '실습활동', lms_curriculum_summary: '학습정리', lms_curriculum_quiz: '확인문제', lms_curriculum_now_stage: '현재 단계', bug_report_title: '버그 리포트', bug_report_content: '이용 시 발생하는 오류나 버그 신고 및 엔트리를 위한 좋은 제안을 해주세요. 신고나 제안과 무관한 욕설 작성 시 이용이 정지될 수 있습니다.', object_import_syntax_error: '불러오려는 오브젝트에 엔트리파이선 문법과 맞지 않는 블록이 포함되어 있습니다. 블록코딩으로 전환한 뒤 오브젝트를 불러와주세요.', choseok_top_wrapper_panel_title: '조석과 함께 가위바위보 게임을 만들어보세요!', choseok_top_wrapper_panel_des: '마음의 소리 웹툰이 코딩파티 미션으로 탄생했습니다.
만화속 조석이 (가위바위보 게임)을 만들어가는 과정에 참여하여 미션에
도전해 보세요.
각 단계를 통과하면서 자연스럽게 소프트웨어를 배워볼 수 있고, 미션을 모두 마치면
인증서와 나만의 게임을 얻을 수 있습니다.
', choseok_mission_statement1: '조석을 움직여보자', choseok_mission_statement2: '가위바위보를 시작해보자', choseok_mission_statement3: '가위바위보 승부를 가려보자', choseok_mission_statement4: '가위바위보 게임을 완성해보자', choseok_mission_statement5: '자유롭게 만들어보자', choseok_mission_statement_top1: '미션 1 : 조석을 움직이기', choseok_mission_statement_top2: '미션 2 : 가위바위보를 시작하기', choseok_mission_statement_top3: '미션 3 : 가위바위보 승패 만들기', choseok_mission_statement_top4: '미션 4 : 가위바위보 결과 보여주기', choseok_mission_statement_top5: '미션 5 : 자유롭게 만들어보기', advisory_title: '엔트리 자문단', advisory_sub_title: '엔트리를 함께 만들어가는 선생님 학생 자문단입니다.', data_table_column: '열', data_table_row: '행', data_table_provider: '제공처', data_table_modifidate: '수정일', draw_new_table_ques_1: '데이터를 직접 입력하여 테이블로 저장할 수 있습니다.', draw_new_table_ques_2: '테이블 화면으로 이동하시겠습니까?', }; Lang.Msgs = { microbit_led_erase_all: '모두 지우기', loading_plz_wait: '로딩중입니다. 잠시만 기다려주세요', ai_utilize_audio_listening: '듣고 있어요', upload_error_title: '파일 업로드 안내', upload_error_content: '엔트리 이용정책을 지키지 않는 것으로 의심되는 파일이 제외되었습니다.', monthly_intro_0: '<월간 엔트리>는 소프트웨어 교육에 익숙하지 않은 선생님들도 쉽고 재미있게 소프트웨어 교육을 하실 수 있도록 만들어진 ', monthly_intro_1: 'SW교육 잡지입니다. 재미있는 학습만화와 함께 하는 SW 교육 컨텐츠를 만나보세요!', monthly_title_0: '강아지 산책시키기 / 선대칭 도형 그리기', monthly_title_1: '동영상의 원리 / 음악플레이어 만들기', monthly_title_2: '대한민국 지도 퍼즐 / 벚꽃 애니메이션', monthly_title_3: '마우스 졸졸, 물고기 떼 / 태양계 행성', monthly_title_4: '감자 캐기 / 딸기 우유의 진하기', monthly_description_0: '키보드 입력에 따라 움직이는 강아지와 신호와 좌표를 통해 도형을 그리는 작품을 만들어 봅시다.', monthly_description_1: '변수를 활용하여 사진 영상 작품과 음악 플레이어 작품을 만들어 봅시다.', monthly_description_2: '~인 동안 반복하기를 이용한 퍼즐 게임과 복제본, 무작위 수를 이용한 애니메이션 작품을 만들어 봅시다.', monthly_description_3: '계속 반복하기 블록과 수학 연산 블록을 활용하여 물고기 미디어 아트 작품과 태양계를 만들어 봅시다.', monthly_description_4: '신호와 변수, 수학 연산 블록을 활용하여 감자 캐기 작품과 딸기 우유 만들기 작품을 만들어 봅시다.', save_canvas_alert: '저장 중입니다.', feedback_too_many_post: '신고하신 내용이 전송되고 있습니다. 10초 뒤에 다시 시도해주세요.', feedback_duplicated: '이미 신고하였습니다.', usable_object: '사용가능 오브젝트', shared_varaible: '공유 변수', invalid_url: '영상 주소를 다시 확인해 주세요.', auth_only: '인증된 사용자만 이용이 가능합니다.', runtime_error: '실행 오류', to_be_continue: '준비 중입니다.', warn: '경고', error_occured: "다시 한번 시도해 주세요. 만약 같은 문제가 다시 발생 하면 '제안 및 건의' 게시판에 문의 바랍니다. ", error_forbidden: '로그아웃 상태라 저장을 할 수 없습니다.\n만약 로그인했다면 다른 창에서 로그아웃 했는지 확인해 주세요.\n로그인 확인 후 저장이 안 된다면 ‘제안 및 건의’ 게시판에 문의 하세요.', list_can_not_space: '리스트의 이름은 빈 칸이 될 수 없습니다.', sign_can_not_space: '신호의 이름은 빈 칸이 될 수 없습니다.', variable_can_not_space: '변수의 이름은 빈 칸이 될 수 없습니다.', training_top_title: '연수 프로그램', training_top_desc: '엔트리 연수 지원 프로그램을 안내해 드립니다.', training_main_title01: '선생님을 위한 강사 연결 프로그램', training_target01: '교육 대상 l 선생님', training_sub_title01: '“우리 교실에 SW날개를 달자”', training_desc01: '소프트웨어(SW) 교원 연수가 필요한 학교인가요?\nSW 교원 연수가 필요한 학교에 SW교육 전문 선생님(고투티처) 또는 전문 강사를 연결해드립니다.', training_etc_ment01: '* 강의비 등 연수 비용은 학교에서 지원해주셔야합니다.', training_main_title02: '소프트웨어(SW) 선도학교로 찾아가는 교원연수', training_target02: '교육 대상 l SW 선도, 연구학교', training_sub_title02: '“찾아가, 나누고, 이어가다”', training_desc02: 'SW 교원 연수를 신청한 선도학교를 무작위로 추첨하여 상반기(4,5,6월)와\n하반기(9,10,11월)에 각 지역의 SW교육 전문 선생님(고투티처)께서 알차고\n재미있는 SW 기초 연수 진행 및 풍부한 교육사례를 공유하기 위해 찾아갑니다.', training_etc_ment02: '', training_main_title03: '학부모와 학생을 위한 연결 프로그램', training_target03: '교육 대상 l 학부모, 학생', training_sub_title03: '“SW를 더 가까이 만나는 시간”', training_desc03: '학부모와 학생들을 대상으로 소프트웨어(SW) 연수가 필요한 학교에 각 지역의 SW교육 전문 선생님(고투티처) 또는 전문 강사를 연결해드립니다.', training_etc_ment03: '* 강의비 등 연수 비용은 학교에서 지원해주셔야합니다.', training_apply: '신청하기', training_ready: '준비중입니다.', new_version_title: '최신 버전 설치 안내', new_version_text1: '하드웨어 연결 프로그램이', new_version_text2: '최신 버전이 아닙니다.', new_version_text3: '서비스를 한층 더 강화해 업데이트 된', new_version_text4: '최신 버전의 연결 프로그램을 설치해 주세요.', new_version_download: "최신 버전 다운로드", not_install_title: '미설치 안내', hw_download_text1: '하드웨어 연결을 위해서', hw_download_text2: '하드웨어 연결 프로그램을 설치해 주세요.', hw_download_text3: '하드웨어 연결 프로그램이 설치되어 있지 않습니다.', hw_download_text4: '최신 버전의 연결 프로그램을 설치해 주세요.', hw_download_btn: "연결 프로그램 다운로드", not_support_browser: '지원하지 않는 브라우저입니다.', quiz_complete1: '퀴즈 풀기 완료!', quiz_complete2: '총 {0}문제 중에 {1}문제를 맞췄습니다.', quiz_incorrect: '이런 다시 한 번 생각해보자', quiz_correct: '정답이야!', hw_connection_success: '하드웨어 연결 성공', hw_connection_success_desc: '하드웨어 아이콘을 더블클릭하면, 센서값만 확인할 수 있습니다.', hw_connection_success_desc2: '작품에서 하드웨어를 사용할 수 있습니다.', hw_connection_termination_title: '하드웨어 연결 해제', hw_connection_termination_desc: '하드웨어와 연결이 해제되었습니다.', hw_connection_failed_title: '하드웨어 연결 실패', hw_connection_failed_desc: '작품에서 사용된 하드웨어가\n연결되어 있는지 확인해 주세요.', ie_page_title: '이 브라우저는
지원하지 않습니다.', ie_page_desc: '엔트리는 인터넷 익스플로러 11 버전 이상 또는 크롬 브라우저에서 이용하실 수 있습니다.
윈도우 업데이트를 진행하시거나, 크롬 브라우저를 설치해주세요.
엔트리 오프라인 버전은 인터넷이 연결되어 있지 않아도 사용할 수 있습니다. 지금 다운받아서 시작해보세요!', ie_page_chrome_download: '크롬 브라우저
다운로드', ie_page_windows_update: '윈도우 최신버전
업데이트', ie_page_offline_32bit_download: '엔트리 오프라인 32bit
다운로드', ie_page_offline_64bit_download: '엔트리 오프라인 64bit
다운로드', ie_page_offline_mac_download: '엔트리 오프라인
다운로드', cancel_deletion_your_account: '$1님의
회원탈퇴 신청을 취소하시겠습니까?', account_deletion_canceled_complete: '회원탈퇴 신청이 취소되었습니다.', journal_henesys_no1_title: '헤네시스 첫번째 모험일지', journal_henesys_no2_title: '헤네시스 두번째 모험일지', journal_henesys_no1_content: '헤네시스에서 첫 번째 모험 일지야. 오늘 헤네시스 터줏대감이라는 대장장이 집에 가려고 점프를 하다가 떨어질 뻔했어. 그 아저씨는 집 마당 앞에 왜 그렇게 구멍을 크게 만들어 놓는 거지? 나같이 대단한 몬스터가 아니고서야 이런 구멍을 뛰어넘을 수 있는 애들은 없을 거 같은데! 여하튼 정보도 얻었으니 아저씨가 추천한 맛 집으로 가볼까?', journal_henesys_no2_content: '진짜 과식했다. 특히 그 식당의 고기는 정말 맛있었어. 어떻게 그렇게 부드럽게 만들었을까! 그렇지만 그 옆집 빵은 별로였어. 보니까 주방장 아저씨가 요리 수련을 한답시고 맨날 놀러 다니는 거 같더라고. 그럴 시간에 빵 하나라도 더 만들어 보는 게 나을 텐데. 후 이제 배도 채웠으니 본격적인 모험을 시작해볼까!', journal_ellinia_no1_title: '엘리니아 첫번째 모험일지', journal_ellinia_no2_title: '엘리니아 두번째 모험일지', journal_ellinia_no1_content: '휴, 모르고 주황버섯을 깔고 앉아버렸지 뭐야. 걔네가 화날만 하지.. 그래도 그렇게 나에게 다같이 몰려들어 공격할 건 뭐람! 정말 무서운 놈들이야. 슬라임들이 힘들어 할만했어. 하지만 이 핑크빈님께서 다 혼내주었으니깐 걱정 없어. 이제 슬라임들이 친구가 되어주었으니 더욱 신나게 멋진 숲으로 모험을 이어가볼까.', journal_ellinia_no2_content: '모험하면서 만난 친구 로얄패어리가 요즘 엘나스에 흉흉한 소문이 돈다고 했는데, 그게 뭘까? 오늘밤에 친구들이랑 집에서 놀기로 했는데 그때 물어봐야겠어. 완전 궁금한걸! 그런데 뭘 입고 가야하나.. 살이 너무쪄서 입을만 한게 없을거같은데.. 뭐 나는 늘 귀여우니까 어떤걸 입고가도 다들 좋아해줄거라구!', journal_elnath_no1_title: '엘나스 첫번째 모험일지', journal_elnath_no2_title: '엘나스 두번째 모험일지', journal_elnath_no1_content: '세상에! 이게 말로만 듣던 눈인가? 내가 사는 마을은 항상 봄이여서 눈은 처음 봤어. 몬스터들을 혼내주느라 제대로 구경을 못했는데 지금보니 온세상이 이렇게나 하얗고 차갑다니 놀라워! 푹신 푹신하고 반짝거리는게 맛있어 보였는데 맛은 특별히 없네. 그런데 왠지 달콤한 초코 시럽을 뿌려먹으면 맛있을 거 같아. 조금 들고가고 싶은데 방법이 없다니 너무 아쉬운걸.', journal_elnath_no2_content: '에퉤퉤, 실수로 석탄가루를 먹어버렸네. 나쁜 몬스터들! 도망가려면 조용히 도망갈 것이지 석탄을 잔뜩 뿌리면서 도망가버렸어. 덕분에 내 윤기나고 포송포송한 핑크색 피부가 갈수록 더러워지고 있잖아. 어서 여기를 나가서 깨끗하게 목욕부터 해야겠어. 아무리 모험이 좋다지만 이렇게 더럽게 돌아다니는 건 이 핑크빈님 자존심이 허락하지 않지.', bug_report_alert_msg: '소중한 의견 감사합니다.', version_update_msg1: '엔트리 오프라인 새 버전(%1)을\n사용하실 수 있습니다.', version_update_msg2: '엔트리 하드웨어 새 버전(%1)을\n사용하실 수 있습니다.', version_update_msg3: '지금 업데이트 하시겠습니까?', select_the_hardware: '수업에 활용할
하드웨어를 선택하세요.', select_hardware_button: '하드웨어 선택하기', select_the_expansion_block: '수업에 활용할 확장 블록을 선택하세요.', select_hardware_not_support_info: '오픈강의에는 하드웨어 블록을 사용할 수 없습니다.', select_hardware_not_support_info2: '조금만 기다려주세요.', select_expansion_block_button: '확장 블록 선택하기', expansion_weather_description: '기온, 강수량, 미세먼지 농도 등 한국의 날씨와 관련된 블록 모음입니다. [웨더아이 제공]', expansion_festival_description: '국내 지역별 다양한 행사 및 축제와 관련된 불록 모음 입니다. [한국관광공사 제공]', expansion_translate_description: '파파고를 이용하여 다른 언어로 번역할 수 있는 블록 모음입니다.', expansion_behaviorConductDisaster_description: '자연재난 발생 시 국민이 지켜야하는 기본적인 행동요령에 대한 블록들의 모음입니다. [국민안전처 제공]', expansion_behaviorConductLifeSafety_description: '생활 속 안전을 위해 국민이 지켜야 하는 행동요령에 대한 블록 모음입니다. [국민안전처 제공]', ai_utilize_tts_description: 'nVoice 음성합성 기술로 다양한 목소리로 문장을 읽는 블록모음 입니다. ', hardware_need_update_title: '업데이트 안내', hardware_need_update_content: '보안 업데이트로 엔트리 웹버전은\n하드웨어 1.9.0 버전 이상만 지원합니다.\n이하 버전일 경우 프로그램을 업데이트 하세요.\n* 업데이트 후 블록이 보이지 않을 경우,\n웹브라우저의 캐시를 지워 주세요.', ai_utilize_audio_description: '마이크를 이용하여 소리와 음성을 감지할 수 있는 블록 모음입니다. (IE/Safari/Firefox 브라우저 미지원)', ai_utilize_video_description: '카메라를 이용하여 움직임과 방향 값, 그리고 촬영되는 객체 등을 인식할 수 있는 블록 모음입니다. (IE/Safari/Firefox 브라우저 미지원)', }; Lang.Users = { auth_failed: '인증에 실패하였습니다', birth_year: '태어난 해', birth_year_before_1990: '1990년 이전', edit_personal: '정보수정', email: '이메일', email_desc: '새 소식이나 정보를 받을 수 있 이메일 주소', email_inuse: '이미 등록된 메일주소 입니다', email_match: '이메일 주소를 올바르게 입력해 주세요', forgot_password: '암호를 잊으셨습니까?', job: '직업', language: '언어', name: '이름', name_desc: '사이트내에서 표현될 이름 또는 별명', name_not_empty: '이름을 반드시 입력하세요', password: '암호', password_desc: '최소 4자이상 영문자와 숫자, 특수문자', password_invalid: '암호가 틀렸습니다', password_long: '암호는 4~20자 사이의 영문자와 숫자, 특수문자로 입력해 주세요', password_required: '암호는 필수입력 항목입니다', project_list: '작품 조회', regist: '가입 완료', rememberme: '자동 로그인', repeat_password: '암호 확인', repeat_password_desc: '암호를 한번더 입력해 주세요', repeat_password_not_match: '암호가 일치하지 않습니다', sex: '성별', signup_required_for_save: '저장을 하려면 로그인이 필요합니다.', username: '아이디', username_desc: '로그인시 사용할 아이디', username_inuse: '이미 사용중인 아이디 입니다', username_long: '아이디는 4~20자 사이의 영문자로 입력해 주세요', username_unknown: '존재하지 않는 사용자 입니다', already_verified: '이미 인증된 메일 주소입니다.', email_address_unavailable: '유효하지 않은 인증 메일입니다.', email_address_invalid_for_idpw: '유효하지 않은 인증 메일입니다.\n [아이디와 비밀번호 찾기] 메일 발송하기를\n 다시 시도해 주세요.', email_address_invalid_for_certification: '유효하지 않은 인증 메일입니다.\n [인증 메일 발송하기]를 다시 시도해 주세요.', verification_complete: '이메일 주소가 인증되었습니다.', reset_password_mail_sent: '비밀번호 재설정 메일이 발송되었습니다. 메일을 확인해주세요.', email_not_verified: '인증되지 않은 이메일 주소입니다. 인증 메일을 발송하여, 먼저 이메일 주소를 인증해주세요.', verification_email_send_complete: '인증 메일이 발송되었습니다. 먼저 메일 주소를 인증해주세요.', email_send_failed: '전송에 실패했습니다. 다시 한번 시도해주세요.', email_not_exist: '등록되지 않은 이메일 주소입니다.', not_valid_email: '올바른 형식의 이메일 주소를 입력해주세요.', }; Lang.Workspace = { picture_rotation: '회전', picture_size: '크기', thickness: '굵기', follow: '따라해보기', SaveWithPicture: '저장되지 않은 그림이 있습니다. 저장하시겠습니까?', RecursiveCallWarningTitle: '함수 호출 제한', RecursiveCallWarningContent: '한 번에 너무 많은 함수가 호출되었습니다. 함수의 호출 횟수를 줄여주세요.', SelectShape: '이동', SelectCut: '자르기', Pencil: '펜', Line: '직선', Rectangle: '사각형', Ellipse: '원', Text: '글상자', Fill: '채우기', Eraser: '지우기', Magnifier: '확대/축소', block_helper: '블록 도움말', new_project: '새 프로젝트', add_object: '오브젝트 추가하기', download_image_name: '엔트리 블록', all: '전체', animal: '동물', arduino_entry: '아두이노 연결 프로그램', arduino_program: '아두이노 프로그램', arduino_sample: '엔트리 연결블록', arduino_driver: '아두이노 드라이버', cannot_add_object: '실행중에는 오브젝트를 추가할 수 없습니다.', cannot_add_picture: '실행중에는 모양을 추가할 수 없습니다.', cannot_add_sound: '실행중에는 소리를 추가할 수 없습니다.', cannot_add_expansion_block: '실행중에는 확장 블럭을 추가할 수 없습니다.', add_object_before_edit: '모양 편집을 위해
오브젝트를 추가해주세요.', add_table_before_edit: '테이블을 추가해주세요.', cannot_edit_click_to_stop: '실행 중에는 수정할 수 없습니다.
클릭하여 정지하기.', cannot_open_private_project: '비공개 작품은 불러올 수 없습니다. 홈으로 이동합니다.', cannot_save_running_project: '실행 중에는 저장할 수 없습니다.', character_gen: '캐릭터 만들기', check_runtime_error: '빨간색으로 표시된 블록을 확인해 주세요.', check_browser_error: 'IE/Safari 에서는 지원하지 않는 블록입니다.', check_microphone_error: '컴퓨터에 마이크가 연결되어있지 않습니다', check_webcam_error: '컴퓨터에 카메라가 연결되어있지 않습니다', context_download: 'PC에 저장', context_duplicate: '복제', context_remove: '삭제', context_rename: '이름 수정', coordinate: '좌표', create_function: '함수 만들기', direction: '이동 방향', drawing: '직접 그리기', enter_list_name: '새로운 리스트의 이름을 입력하세요(10글자 이하)', enter_name: '새로운 이름을 입력하세요', enter_new_message: '새로운 신호의 이름을 입력하세요.', enter_variable_name: '새로운 변수의 이름을 입력하세요(10글자 이하)', family: '엔트리봇 가족', fantasy: '판타지/기타', file_new: '새로 만들기', file_open: '온라인 작품 불러오기', file_upload: '오프라인 작품 불러오기', file_upload_login_check_msg: '오프라인 작품을 불러오기 위해서는 로그인을 해야 합니다.', file_save: '저장하기', file_save_as: '복사본으로 저장하기', file_save_download: '내 컴퓨터에 저장하기', func: '함수', function_create: '함수 만들기', function_add: '함수 추가하기', interface: '인터페이스', landscape: '배경', list: '리스트', list_add_calcel: '리스트 추가 취소', list_add_calcel_msg: '리스트 추가를 취소하였습니다.', list_add_fail: '리스트 추가 실패', list_add_fail_msg1: '같은 이름의 리스트가 이미 존재합니다.', list_add_fail_msg2: '리스트의 이름이 적절하지 않습니다.', list_add_ok: '리스트 추가 완료', list_add_ok_msg: '을(를) 추가하였습니다.', list_create: '리스트 추가하기', list_create_placeholder: '리스트의 이름을 입력해주세요.', list_dup: '같은 이름의 리스트가 이미 존재합니다.', list_newname: '새로운 이름', list_export: '리스트 내보내기', list_import: '리스트 불러오기', list_remove: '리스트 삭제', list_rename: '리스트 이름 변경', list_rename_failed: '리스트 이름 변경 실패', list_rename_ok: '리스트의 이름이 성공적으로 변경 되었습니다.', list_too_long: '리스트의 이름이 너무 깁니다.', message: '신호', message_add_cancel: '신호 추가 취소', message_add_cancel_msg: '신호 추가를 취소하였습니다.', message_add_fail: '신호 추가 실패', message_add_fail_msg: '같은 이름의 신호가 이미 존재합니다.', message_add_ok: '신호 추가 완료', message_add_ok_msg: '을(를) 추가하였습니다.', message_create: '신호 추가하기', message_create_placeholder: '신호의 이름을 입력해주세요.', message_dup: '같은 이름의 신호가 이미 존재합니다.', message_remove: '신호 삭제', message_remove_canceled: '신호 삭제를 취소하였습니다.', message_rename: '신호 이름을 변경하였습니다.', message_rename_failed: '신호 이름 변경 실패', message_rename_ok: '신호의 이름이 성공적으로 변경 되었습니다.', message_too_long: '신호의 이름이 너무 깁니다.', no_message_to_remove: '삭제할 신호가 없습니다', no_use: '사용되지 않음', no_variable_to_remove: '삭제할 변수가 없습니다.', no_variable_to_rename: '변경할 변수가 없습니다.', object_not_found: '블록에서 지정한 오브젝트가 존재하지 않습니다.', object_not_found_for_paste: '붙여넣기 할 오브젝트가 없습니다.', people: '일반 사람들', picture_add: '모양 추가하기', table_add: '테이블 추가하기', draw_new_table: '새로 만들기', plant: '식물', project: '작품', project_copied: '의 사본', PROJECTDEFAULTNAME: ['멋진', '재밌는', '착한', '큰', '대단한', '잘생긴', '행운의'], remove_object: '오브젝트 삭제', remove_object_msg: '(이)가 삭제되었습니다.', removed_msg: '(이)가 성공적으로 삭제 되었습니다.', rotate_method: '회전방식', rotation: '방향', run: '시작하기', saved: '저장완료', saved_msg: '(이)가 저장되었습니다.', save_failed: '저장시 문제가 발생하였습니다. 다시 시도해 주세요.', select_library: '오브젝트 선택', select_sprite: '적용할 스프라이트를 하나 이상 선택하세요.', shape_remove_fail: '모양 삭제 실패', shape_remove_fail_msg: '적어도 하나 이상의 모양이 존재하여야 합니다.', shape_remove_ok: '모양이 삭제 되었습니다. ', shape_remove_ok_msg: '이(가) 삭제 되었습니다.', load_expansion_block: '확장 블록 불러오기', load_ai_utilize_block: 'AI 블록 불러오기', load_ai_utilize_train_block: '모델 학습', select_expansion_block: '확장블록 선택', deselect_expansion_block_warning: '확장블록이 사용중이므로 삭제할 수 없습니다.', deselect_ai_utilize_block_warning: 'AI블록이 사용중이므로 삭제할 수 없습니다.', sound_add: '소리 추가하기', sound_remove_fail: '소리 삭제 실패', sound_remove_ok: '소리 삭제 완료', sound_remove_ok_msg: '이(가) 삭제 되었습니다.', stop: '정지하기', pause: '일시정지', restart: '다시시작', speed: '속도 조절', tab_attribute: '속성', tab_table: '테이블', tab_code: '블록', tab_picture: '모양', tab_sound: '소리', tab_text: '글상자', textbox: '글상자', textbox_edit: '글상자 편집', textbox_input: '글상자의 내용을 입력해주세요.', things: '물건', textcoding_tooltip1: '블록코딩과 엔트리파이선을
선택하여 자유롭게
코딩을 해볼 수 있습니다.', textcoding_tooltip2: '실제 개발 환경과 동일하게
엔트리파이선 모드의 실행 결과를
확인할 수 있습니다.', textcoding_tooltip3: '엔트리파이선에 대한
기본사항이 안내되어 있습니다.
<엔트리파이선 이용안내>를 확인해 주세요!', upload: '파일 올리기', upload_addfile: '파일 올리기', variable: '변수', variable_add_calcel: '변수 추가 취소', variable_add_calcel_msg: '변수 추가를 취소하였습니다.', variable_add_fail: '변수 추가 실패', variable_add_fail_msg1: '같은 이름의 변수가 이미 존재합니다.', variable_add_fail_msg2: '변수의 이름이 적절하지 않습니다.', variable_add_ok: '변수 추가 완료', variable_add_ok_msg: '을(를) 추가하였습니다.', variable_create: '변수 만들기', variable_add: '변수 추가하기', variable_dup: '같은 이름의 변수가 이미 존재합니다.', variable_newname: '새로운 이름', variable_remove: '변수 삭제', variable_remove_canceled: '변수 삭제를 취소하였습니다.', variable_rename: '변수 이름을 변경합니다. ', variable_rename_failed: '변수 이름 변경에 실패하였습니다. ', variable_rename_msg: "'변수의 이름이 성공적으로 변경 되었습니다.'", variable_rename_ok: '변수의 이름이 성공적으로 변경 되었습니다.', variable_select: '변수를 선택하세요', variable_too_long: '변수의 이름이 너무 깁니다.', open_analizy_data_import: '데이터 화면 열기', vehicle: '탈것', add_object_alert_msg: '오브젝트를 추가해주세요', add_object_alert: '경고', create_variable_block: '변수 만들기', create_list_block: '리스트 만들기', Variable_Timer: '초시계', Variable_placeholder_name: '변수 이름', Message_placeholder_name: '신호 이름', Variable_property: '변수 속성', Variable_placeholder_content: '변수의 이름을 입력해주세요.', Variable_use_all_objects: '모든 오브젝트에서 사용', Variable_use_this_object: '이 오브젝트에서 사용', Variable_used_at_all_objects: '모든 오브젝트에서 사용되는 변수', variable_create_normal: '일반 변수로 사용\n(작품에 저장)', variable_create_cloud: '공유 변수로 사용\n(서버에 저장)', variable_create_real_time: '실시간 변수로 사용\n(서버에 저장)', Variable_used_at_special_object: '특정 오브젝트에서만 사용되는 변수', Variable_used_objects: '사용된 오브젝트', draw_new: '새로 그리기', draw_new_ebs: '직접 그리기', painter_file: '파일 ▼', painter_file_save: '저장하기', painter_file_saveas: '새 모양으로 저장', new_picture: '새그림', painter_edit: '편집 ▼', get_file: '가져오기', copy_file: '복사하기', cut_picture: '자르기', paste_picture: '붙이기', remove_all: '모두 지우기', flip_horizontal: '좌우뒤집기', flip_vertical: '상하뒤집기', regular: '보통', bold: '굵게', font_underline: '밑줄', font_tilt: '기울임', font_cancel: '취소선', font_color: '글꼴 색상', font_fill: '채우기 색상', font_family: '글꼴', align_left: '왼쪽 정렬', align_center: '가운데 정렬', align_right: '오른쪽 정렬', italic: '기울임', textStyle: '글자', add_picture: '모양 추가', select_picture: '모양 선택', select_table: '테이블 선택', select_sound: '소리 선택', Size: '크기', show_variable: '변수 노출', default_value: '기본값 ', slide: '슬라이드', min_value: '최솟값', max_value: '최댓값', number_of_list: '리스트 항목 수', empty_of_list: '추가된 항목이 없습니다', use_all_objects: '모든 오브젝트에 사용', list_name: '리스트 이름', list_property: '리스트 속성', list_used_specific_objects: '특정 오브젝트에서만 사용되는 리스트', List_used_all_objects: '모든 오브젝트에서 사용되는 리스트', List_used_objects: '사용된 오브젝트', Scene_delete_error: '장면은 최소 하나 이상 존재해야 합니다.', Scene_add_error: '장면은 최대 20개까지 추가 가능합니다.', replica_of_object: '의 복제본', will_you_delete_scene: '장면은 한번 삭제하면 취소가 불가능 합니다. \n정말 삭제 하시겠습니까?', will_you_delete_function: '함수는 한번 삭제하면 취소가 불가능 합니다. \n정말 삭제 하시겠습니까?', duplicate_scene: '복제하기', block_explain: '블록 설명 ', block_intro: '블록을 클릭하면 블록에 대한 설명이 나타납니다.', blocks_reference: '블록 설명', hardware_guide: '하드웨어 연결 안내', robot_guide: '로봇 연결 안내', python_guide: '엔트리파이선 이용 안내', show_list_workspace: '리스트 노출', list_create_normal: '일반 리스트로 사용\n(작품에 저장)', list_create_cloud: '공유 리스트로 사용 \n(서버에 저장)', list_create_real_time: '실시간 리스트로 사용\n(서버에 저장)', confirm_quit: '바꾼 내용을 저장하지 않았습니다.', confirm_load_temporary: '저장되지 않은 작품이 있습니다. 여시겠습니까?', login_to_save: '로그인후에 저장 바랍니다.', cannot_save_in_edit_func: '함수 편집중에는 저장할 수 없습니다.', new_object: '새 오브젝트', arduino_connect: '하드웨어 연결', arduino_connect_success: '하드웨어가 연결되었습니다.', confirm_load_header: '작품 복구', uploading_msg: '업로드 중입니다', upload_fail_msg: '업로드에 실패하였습니다.
다시 한번 시도해주세요.', upload_not_supported_msg: '지원하지 않는 형식입니다.', upload_not_supported_file_msg: '지원하지 않는 형식의 파일입니다.', file_converting_msg: '파일 변환 중입니다.', file_converting_fail_msg: '파일 변환에 실패하였습니다.', fail_contact_msg: '문제가 계속된다면
entry@connect.or.kr 로 문의해주세요.', saving_msg: '저장 중입니다', saving_fail_msg: '저장에 실패하였습니다.
다시 한번 시도해주세요.', loading_msg: '불러오는 중입니다', loading_fail_msg: '불러오기에 실패하였습니다.
다시 한번 시도해주세요.', restore_project_msg: '정상적으로 저장되지 않은 작품이 있습니다. 해당 작품을 복구하시겠습니까?', quit_stop_msg: '저장 중에는 종료하실 수 없습니다.', ent_drag_and_drop: '업로드 하려면 파일을 놓으세요', not_supported_file_msg: '지원하지 않은 형식의 파일입니다.', broken_file_msg: '파일이 깨졌거나 잘못된 파일을 불러왔습니다.', check_audio_msg: 'mp3 외 오디오 파일은 재생할 수 없습니다.', check_entry_file_msg: 'ENT 파일만 불러오기가 가능합니다.', hardware_version_alert_text: '5월 30일 부터 구버전의 연결프로그램의 사용이 중단 됩니다.\n하드웨어 연결 프로그램을 최신 버전으로 업데이트 해주시기 바랍니다.', variable_name_auto_edited_title: '변수 이름 자동 변경', variable_name_auto_edited_content: '변수의 이름은 10글자를 넘을 수 없습니다.', list_name_auto_edited_title: '리스트 이름 자동 변경', list_name_auto_edited_content: '리스트의 이름은 10글자를 넘을 수 없습니다.', cloned_scene: '복제본_', default_mode: '기본형', practical_course_mode: '교과형', practical_course: '실과', select_mode: '모드선택', select_mode_popup_title: '엔트리 만들기 환경을 선택해 주세요.', select_mode_popup_lable1: '기본형', select_mode_popup_lable2: '교과형', select_mode_popup_desc1: '엔트리의 모든 기능을 이용하여
자유롭게 작품을 만듭니다.', select_mode_popup_desc2: '실과 교과서에 등장하는 기능만을
이용하여 작품을 만듭니다.', practical_course_notice: '안내', practical_course_desc: "교과용 만들기
실과 교과서로 소프트웨어를 배울 때
필요한 기능만을 제공합니다.", practical_course_desc2: '*기본형 작품 만들기를 이용하면 더 많은 기능을
이용해 작품을 만들 수 있습니다.', practical_course_tooltip: '모든 기능을 이용하기 위해서는
기본형을 선택해 주세요.', name_already_exists: '이름이 중복 되었습니다.', enter_the_name: '이름을 입력하여 주세요.', object_not_exist_error: '오브젝트가 존재하지 않습니다. 오브젝트를 추가한 후 시도해주세요.', workspace_tutorial_popup_desc: "작품 만들기
창의적인 작품을 만들 수 있도록
다양한 블록과 기능을 제공합니다.", start_guide_tutorial: '만들기 이용 안내', language: '언어 선택', file: '파일', save: '저장하기', help: '도움말', print: '인쇄', undo: '입력 취소', redo: '다시 실행', workspace_title_tooltip: '기본작품명이 변경되었습니다.\n작품을 만든 날짜를 통해 어떤 작품인지 쉽게 알 수 있습니다.', workspace_object_tooltip: '오브젝트의 순서는 오브젝트의 대표 이미지를 잡고\n위아래로 이동하여 변경할 수 있습니다.\n(모양과 소리탭에서도 동일하게 동작합니다.)', workspace_comment_tooltip: '조립소에 추가한 메모를\n한꺼번에 숨기거나 보이게 할 수 있습니다.', workspace_zoom_tooltip: '조립소에 추가된 블록의 크기를 바꿀 수 있습니다.\n가운데 = 아이콘을 누르면 기본 크기로 돌아옵니다.', workspace_image_tooltip: '새로워진\n작품 만들기를\n소개합니다.', playground_block_drop: '나의 보관함의 블록을\n조립소에 추가합니다.', container_object_drop: '나의 보관함의 오브젝트를\n오브젝트 리스트에 추가합니다.', my_storage_block_drop: '블록을\n나의 보관함에\n추가합니다.', my_storage_object_drop: '오브젝트를\n나의 보관함에\n추가합니다.', my_storage: '나의 보관함', my_block: '나의 블록', red: '빨강(R)', green: '녹색(G)', blue: '파랑(B)', hue: '색상', saturation: '채도', brightness: '명도', spoid: '스포이드', palette_mode: '팔레트 모드', slider_mode: '슬라이더 모드', toast_error_title_object_center: '주의', toast_error_contents_object_center: '오브젝트 중심점이 오브젝트와 멀리 떨어져 실행화면 밖으로 벗어날 경우, 원위치로 돌아옵니다.', blocks_comming_soon: '열심히 연구 중입니다.\n조금만 기다려 주세요!', data_table: '테이블', select_all: '모두', now_loading_msg: '로딩 중입니다.\n잠시만 기다려주세요.', }; Lang.code = '코드보기'; Lang.EntryStatic = { event100: '이벤트', groupProject: '학급 공유하기', usage_parallel: '병렬', usage_expansion: '확장', usage_hw: '하드웨어', usage_sequence: '순차', privateProject: '나만보기', privateCurriculum: '나만보기', publicCurriculum: '강의 모음 공유하기', publicProject: '작품 공유하기', group: '학급 공유하기', groupCurriculum: '학급 공유하기', private: '나만보기', public: '강의 공유하기', lecture_is_open_true: '공개', lecture_is_open_false: '비공개', category_all: '모든 작품', category_game: '게임', category_animation: '애니메이션', category_media_art: '미디어 아트', category_physical: '피지컬', category_etc: '기타', category_category_game: '게임', category_category_animation: '애니메이션', category_category_media_art: '미디어 아트', category_category_physical: '피지컬', category_category_etc: '기타', sort_created: '최신순', sort_updated: '최신순', sort_visit: '조회순', sort_likeCnt: '좋아요순', sort_comment: '댓글순', period_all: '전체기간', period_1: '오늘', period_7: '최근 1주일', period_30: '최근 1개월', period_90: '최근 3개월', lecture_required_time_1: ' ~ 15분', lecture_required_time_2: '15분 ~ 30분', lecture_required_time_3: '30분 ~ 45분', lecture_required_time_4: '45 분 ~ 60분', lecture_required_time_5: '1시간 이상', usage_event: '이벤트', usage_signal: '신호보내기', usage_scene: '장면', usage_repeat: '반복', usage_condition_repeat: '조건반복', usage_condition: '선택', usage_clone: '복제본', usage_rotation: '회전', usage_coordinate: '좌표이동', usage_arrow_move: '화살표이동', usage_shape: '모양', usage_speak: '말하기', usage_picture_effect: '그림효과', usage_textBox: '글상자', usage_draw: '그리기', usage_sound: '소리', usage_confirm: '판단', usage_comp_operation: '비교연산', usage_logical_operation: '논리연산', usage_math_operation: '수리연산', usage_random: '무작위수', usage_timer: '초시계', usage_variable: '변수', usage_list: '리스트', usage_ask_answer: '입출력', usage_function: '함수', usage_arduino: '아두이노', concept_resource_analytics: '자료수집/분석/표현', concept_procedual: '알고리즘과 절차', concept_abstractive: '추상화', concept_individual: '문제분해', concept_automation: '자동화', concept_simulation: '시뮬레이션', concept_parallel: '병렬화', subject_korean: '국어', subject_english: '영어', subject_mathmatics: '수학', subject_social: '사회', subject_science: '과학', subject_music: '음악', subject_paint: '미술', subject_athletic: '체육', subject_courtesy: '도덕', subject_progmatic: '실과', lecture_grade_1: '초1', lecture_grade_2: '초2', lecture_grade_3: '초3', lecture_grade_4: '초4', lecture_grade_5: '초5', lecture_grade_6: '초6', lecture_grade_7: '중1', lecture_grade_8: '중2', lecture_grade_9: '중3', lecture_grade_10: '일반', lecture_level_1: '쉬움', lecture_level_2: '중간', lecture_level_3: '어려움', listEnable: '리스트', functionEnable: '함수', messageEnable: '신호', objectEditable: '오브젝트', pictureeditable: '모양', sceneEditable: '장면', soundeditable: '소리', variableEnable: '변수', e_1: '초등 1학년', e_2: '초등 2학년', e_3: '초등 3학년', e_4: '초등 4학년', e_5: '초등 5학년', e_6: '초등 6학년', m_1: '중등 1학년', m_2: '중등 2학년', m_3: '중등 3학년', general: '일반', curriculum_is_open_true: '공개', curriculum_open_false: '비공개', contest2019: '공모전', exhibit: '공모전', notice: '공지사항', qna: '묻고답하기', tips: '노하우&팁', free: '엔트리 이야기', report: '제안 및 건의', art_category_all: '모든 작품', art_category_game: '게임', art_category_animation: '애니메이션', art_category_physical: '피지컬', art_category_etc: '기타', art_category_media: '미디어 아트', art_sort_updated: '최신순', art_sort_visit: '조회순', art_sort_likeCnt: '좋아요순', art_sort_comment: '댓글순', art_period_all: '전체기간', art_period_day: '오늘', art_period_week: '최근 1주일', art_period_month: '최근 1개월', art_period_three_month: '최근 3개월', level_high: '상', level_mid: '중', level_row: '하', discuss_sort_created: '최신순', discuss_sort_visit: '조회순', discuss_sort_likesLength: '좋아요순', discuss_sort_commentsLength: '댓글순', discuss_period_all: '전체기간', discuss_period_day: '오늘', discuss_period_week: '최근 1주일', discuss_period_month: '최근 1개월', discuss_period_three_month: '최근 3개월', }; Lang.Helper = { when_run_button_click: '시작하기 버튼을 클릭하면 아래에 연결된 블록들을 실행합니다.', when_some_key_pressed: '선택한 키를 누르면 아래에 연결된 블록들을 실행합니다.', mouse_clicked: '마우스를 클릭했을 때 아래에 연결된 블록들을 실행합니다.', mouse_click_cancled: '마우스 클릭을 해제했을 때 아래에 연결된 블록들을 실행합니다.', when_object_click: '오브젝트를 클릭했을 때 아래에 연결된 블록들을 실행합니다.', when_object_click_canceled: '오브젝트 클릭을 해제했을 때 아래에 연결된 블록들을 실행합니다.', when_message_cast: '선택한 신호를 받으면 아래에 연결된 블록들을 실행합니다.', message_cast: '선택한 신호를 보냅니다.', message_cast_wait: '선택한 신호를 보내고, 해당 신호를 받는 블록들의 실행이 끝날 때 까지 기다립니다.', when_scene_start: '장면이 시작되면 아래에 연결된 블록들을 실행합니다. ', start_scene: '선택한 장면을 시작합니다.', start_neighbor_scene: '이전 또는 다음 장면을 시작합니다.', wait_second: '입력한 시간만큼 기다린 후 다음 블록을 실행합니다.', repeat_basic: '입력한 횟수만큼 감싸고 있는 블록들을 반복 실행합니다.', repeat_inf: '감싸고 있는 블록들을 계속해서 반복 실행합니다.', repeat_while_true: '판단값에 따라 블록의 반복여부를 결정합니다.\n이 될 때까지: 판단이 참이 될 때까지 감싸고 있는 블록들을 반복 실행합니다.\n인 동안: 판단이 참인 동안 감싸고 있는 블록들을 반복 실행합니다.', stop_repeat: '이 블록을 감싸는 가장 가까운 반복 블록의 반복을 중단합니다.', _if: '만일 판단이 참이라면, 감싸고 있는 블록들을 실행합니다.', if_else: '만일 판단이 참이라면 첫 번째 감싸고 있는 블록들을 실행하고, 거짓이면 두 번째 감싸고 있는 블록들을 실행합니다.', restart_project: '작품을 처음부터 다시 실행합니다.', stop_object: '블록이 실행을 멈춥니다. 현재 실행중인 동작을 멈추는 블록이며, 프로그램을 종료하지 않습니다.\n모든 : 작품의 모든 블록이 실행을 멈춥니다. \n자신 : 해당 오브젝트의 모든 블록이 실행을 멈춥니다.\n이 코드 : 이 블록이 포함된 블록들이 실행을 멈춥니다.\n자신의 다른 코드 : 해당 오브젝트 중 이 블록이 포함된 블록들을 제외한 모든 블록이 실행을 멈춥니다.\n다른 오브젝트의 : 다른 오브젝트의 모든 블록이 실행을 멈춥니다.', wait_until_true: '판단이 참이 될 때까지 실행을 멈추고 기다립니다.', when_clone_start: '해당 오브젝트의 복제본이 새로 생성되었을 때 아래에 연결된 블록들을 실행합니다.', create_clone: '선택한 오브젝트의 복제본을 생성합니다.', delete_clone: '‘복제본이 처음 생성되었을 때’ 블록과 함께 사용되며, 연결된 블록들이 실행되고 있는 복제본을 삭제합니다.', remove_all_clones: '해당 오브젝트의 모든 복제본을 삭제합니다.', move_direction: '입력한 값만큼 오브젝트의 이동 방향 화살표가 가리키는 방향으로 움직입니다.', move_x: '오브젝트의 x 좌표를 입력한 값만큼 바꿉니다. ', move_y: '오브젝트의 y 좌표를 입력한 값만큼 바꿉니다.', move_xy_time: '오브젝트가 입력한 시간에 걸쳐 x와 y 좌표를 입력한 값만큼 바꿉니다.', locate_object_time: '오브젝트가 입력한 시간에 걸쳐 선택한 오브젝트 또는 마우스 포인터의 위치로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_x: '오브젝트가 입력한 x 좌표로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_y: '오브젝트가 입력한 y 좌표로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_xy: '오브젝트가 입력한 x와 y 좌표로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_xy_time: '오브젝트가 입력한 시간에 걸쳐 입력한 x와 y 좌표로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate: '오브젝트가 선택한 오브젝트 또는 마우스 포인터의 위치로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', rotate_absolute: '오브젝트의 방향을 입력한 각도로 정합니다.', rotate_by_time: '오브젝트의 방향이 입력한 시간에 걸쳐 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', rotate_relative: '오브젝트의 방향이 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', direction_absolute: '오브젝트의 이동 방향을 입력한 각도로 정합니다.', direction_relative: '오브젝트의 이동 방향이 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', move_to_angle: '오브젝트가 입력한 각도 방향으로 입력한 값만큼 움직입니다. (실행화면 위쪽이 0도를 나타내며, 시계방향으로 갈수록 각도가 증가합니다.)', see_angle_object: '해당 오브젝트가 방향을 회전하여 선택한 오브젝트 또는 마우스 포인터 쪽을 바라봅니다. ', bounce_wall: '오브젝트가 실행화면 끝에 닿으면 튕겨 나옵니다.', show: '오브젝트를 실행화면에 보이게 합니다.', hide: '오브젝트를 실행화면에 보이지 않게 합니다.', dialog_time: '오브젝트가 입력한 내용을 입력한 시간 동안 말풍선으로 말한 후 다음 블록을 실행합니다.', dialog: '오브젝트가 입력한 내용을 말풍선으로 말하는 동시에 다음 블록을 실행합니다.', remove_dialog: '오브젝트가 말하고 있는 말풍선을 지웁니다.', change_to_some_shape: '오브젝트를 선택한 모양으로 바꿉니다. (내부 블록을 분리하고 모양의 번호를 입력하여 모양을 바꿀 수 있습니다.)', change_to_next_shape: '오브젝트의 모양을 이전 또는 다음 모양으로 바꿉니다.', set_effect_volume: '오브젝트에 선택한 효과를 입력한 값만큼 줍니다.', set_effect_amount: '오브젝트에 선택한 효과를 입력한 값만큼 줍니다.', set_effect: '오브젝트의 효과를 입력한 값으로 정합니다.\n색깔 : 0~100을 주기로 반복됩니다.\n밝기 : -100~100 사이의 범위로 설정할 수 있습니다. (-100 이하는 -100으로 100 이상은 100으로 처리됩니다.)\n투명도 : 0~100 사이의 범위로 설정할 수 있습니다. (0 이하는 0으로, 100 이상은 100으로 처리됩니다.)', set_entity_effect: '오브젝트의 효과를 입력한 값으로 정합니다.\n색깔 : 0~100을 주기로 반복됩니다.\n밝기 : -100~100 사이의 범위로 설정할 수 있습니다. (-100 이하는 -100으로 100 이상은 100으로 처리됩니다.)\n투명도 : 0~100 사이의 범위로 설정할 수 있습니다. (0 이하는 0으로, 100 이상은 100으로 처리됩니다.)', add_effect_amount: '오브젝트에 선택한 효과를 입력한 값만큼 줍니다.', change_effect_amount: '오브젝트의 효과를 입력한 값으로 정합니다.\n색깔 : 0~100을 주기로 반복됩니다.\n밝기 : -100~100 사이의 범위로 설정할 수 있습니다. (-100 이하는 -100으로 100 이상은 100으로 처리됩니다.)\n투명도 : 0~100 사이의 범위로 설정할 수 있습니다. (0 이하는 0으로, 100 이상은 100으로 처리됩니다.)', change_scale_percent: '오브젝트의 크기를 입력한 값만큼 바꿉니다.', set_scale_percent: '오브젝트의 크기를 입력한 값으로 정합니다.', change_scale_size: '오브젝트의 크기를 입력한 값만큼 바꿉니다.', set_scale_size: '오브젝트의 크기를 입력한 값으로 정합니다.', flip_x: '오브젝트의 상하 모양을 뒤집습니다.', flip_y: '오브젝트의 좌우 모양을 뒤집습니다.', change_object_index: '오브젝트가 실행화면에 보이는 순서를 변경합니다.\n맨 앞으로 : 해당 오브젝트를 실행화면의 가장 앞쪽으로 가져옵니다. \n앞으로 : 해당 오브젝트를 한 층 앞쪽으로 가져옵니다.\n뒤로 : 해당 오브젝트를 한 층 뒤쪽으로 보냅니다. \n맨 뒤로 : 해당 오브젝트를 실행화면의 가장 뒤쪽으로 보냅니다.', set_object_order: '해당 오브젝트가 설정한 순서로 올라옵니다.', brush_stamp: '오브젝트의 모양을 도장처럼 실행화면 위에 찍습니다.', start_drawing: '오브젝트가 이동하는 경로를 따라 선이 그리기 시작합니다. (오브젝트의 중심점이 기준이 됩니다.)', stop_drawing: '오브젝트가 선 그리는 것을 멈춥니다.', set_color: '오브젝트가 그리는 선의 색을 선택한 색으로 정합니다.', set_random_color: '오브젝트가 그리는 선의 색을 무작위로 정합니다. ', change_thickness: '오브젝트가 그리는 선의 굵기를 입력한 값만큼 바꿉니다.', set_thickness: '오브젝트가 그리는 선의 굵기를 입력한 값으로 정합니다. 1~무한의 범위로 설정할 수 있습니다. (1 이하는 1로 처리합니다.)', change_opacity: '해당 오브젝트가 그리는 붓의 투명도를 입력한 값만큼 바꿉니다.', change_brush_transparency: '해당 오브젝트가 그리는 붓의 투명도를 입력한 값만큼 바꿉니다.', set_opacity: '해당 오브젝트가 그리는 붓의 투명도를 입력한 값으로 정합니다. 0~100의 범위로 설정할 수 있습니다. (0 이하는 0, 100 이상은 100으로 처리합니다.)', set_brush_tranparency: '해당 오브젝트가 그리는 붓의 투명도를 입력한 값으로 정합니다. 0~100의 범위로 설정할 수 있습니다. (0 이하는 0, 100 이상은 100으로 처리합니다.)', brush_erase_all: '해당 오브젝트가 그린 선과 도장을 모두 지웁니다.', sound_something_with_block: '해당 오브젝트가 선택한 소리를 재생하는 동시에 다음 블록을 실행합니다.', sound_something_second_with_block: '해당 오브젝트가 선택한 소리를 입력한 시간 만큼 재생하는 동시에 다음 블록을 실행합니다.', sound_something_wait_with_block: '해당 오브젝트가 선택한 소리를 재생한 후 다음 블록을 실행합니다.', sound_something_second_wait_with_block: '해당 오브젝트가 선택한 소리를 입력한 시간 만큼 재생한 후 다음 블록을 실행합니다.', sound_volume_change: '작품에서 재생되는 모든 소리의 크기를 입력한 값만큼 바꿉니다.', sound_volume_set: '작품에서 재생되는 모든 소리의 크기를 입력한 값으로 정합니다.', sound_silent_all: '재생 중인 모든 소리를 멈춥니다.', is_clicked: '마우스를 클릭한 경우 ‘참’으로 판단합니다.', is_press_some_key: '선택한 키가 눌려져 있는 경우 ‘참’으로 판단합니다.', reach_something: '해당 오브젝트가 선택한 항목과 닿은 경우 ‘참’으로 판단합니다.', is_included_in_list: "선택한 리스트가 입력한 값을 가진 항목을 포함하는 경우 '참'으로 판단합니다.", boolean_basic_operator: "입력한 두 값을 비교합니다.\n= : 왼쪽에 위치한 값과 오른쪽에 위치한 값이 같은 경우 '참'으로 판단합니다.\n> : 왼쪽에 위치한 값이 오른쪽에 위치한 값보다 큰 경우 '참'으로 판단합니다.\n< : 왼쪽에 위치한 값이 오른쪽에 위치한 값보다 작은 경우 '참'으로 판단합니다.\n≥ : 왼쪽에 위치한 값이 오른쪽에 위치한 값보다 크거나 같은 경우 '참'으로 판단합니다.\n≤ : 왼쪽에 위치한 값이 오른쪽에 위치한 값보다 작거나 같은 경우 '참'으로 판단합니다.", function_create: '자주 쓰는 코드를 이 블록 아래에 조립하여 함수로 만듭니다. [함수 정의하기]의 오른쪽 빈칸에 [이름]을 조립하여 함수의 이름을 정할 수 있습니다. 함수를 실행하는 데 입력값이 필요한 경우 빈칸에 [문자/숫자값], [판단값]을 조립하여 매개변수로 사용합니다.', function_field_label: "함수 정의하기' 블록 안에 조립하며, 함수의 이름을 정합니다. ", function_field_string: "함수 정의하기' 블록 안에 조립하며, 입력한 문자/숫자값(매개변수)에 따라 함수의 실행 결과가 달라집니다. 이 블록을 분리하여 함수의 코드 중 필요한 부분에 넣어 사용합니다.", function_field_boolean: "함수 정의하기' 블록 안에 조립하며, 참 또는 거짓의 판단값에 따라 함수의 실행 결과가 달라집니다. 이 블록을 분리하여 함수의 코드 중 필요한 부분에 넣어 사용합니다.", function_general: '현재 만들고 있는 함수 블록 또는 지금까지 만들어 둔 함수 블록입니다.', boolean_and: '두 판단이 모두 참인 경우 ‘참’으로 판단합니다.', boolean_or: '두 판단 중 하나라도 참이 있는 경우 ‘참’으로 판단합니다.', boolean_not: '해당 판단이 참이면 거짓, 거짓이면 참으로 만듭니다.', calc_basic: '입력한 두 수의 사칙연산 값입니다.\n+ : 입력한 두 수를 더한 값입니다.\n- : 입력한 두 수를 뺀 값입니다.\n* : 입력한 두 수를 곱한 값입니다.\n/ : 입력한 두 수를 나눈 값입니다.', calc_rand: '입력한 두 수 사이에서 선택된 무작위 수 값입니다. (두 수 모두 정수를 입력한 경우 정수가, 두 수 중 하나라도 소수를 입력한 경우 소숫점 둘째 자리의 소수 값이 선택됩니다.)', get_x_coordinate: '해당 오브젝트의 x 좌푯값을 의미합니다.', get_y_coordinate: '해당 오브젝트의 y 좌푯값을 의미합니다.', coordinate_mouse: '마우스 포인터의 x 또는 y 좌푯값입니다.', coordinate_object: '선택한 오브젝트의 각종 정보 값입니다. (x 좌표, y 좌표, 방향, 이동방향, 크기, 모양번호, 모양이름)', quotient_and_mod: '입력된 두 수를 나눈 결괏값입니다.\n몫 : 앞의 수에서 뒤의 수를 나누어 생긴 몫의 값입니다. \n나머지 : 앞의 수에서 뒤의 수를 나누어 생긴 나머지 값입니다.', get_rotation_direction: '해당 오브젝트의 방향값, 이동 방향값을 의미합니다.', calc_share: '앞 수에서 뒤 수를 나누어 생긴 몫을 의미합니다.', calc_mod: '앞 수에서 뒤 수를 나누어 생긴 나머지를 의미합니다.', calc_operation: '입력한 수에 대한 다양한 수학식의 계산값입니다. (제곱, 루트, 사인값, 코사인값, 탄젠트값, 아크사인값, 아크코사인값, 아크탄젠트값, 로그값, 자연로그값, 소수점 부분, 소수점 버림값, 소수점 올림값, 소수점 반올림값, 펙토리얼값, 절대값)', get_date: '현재 연도, 월, 일, 시각과 같이 시간에 대한 값입니다.', distance_something: '해당 오브젝트와 선택한 오브젝트 또는 마우스 포인터 간의 거릿값입니다.', get_sound_duration: '선택한 소리의 길이(초) 값입니다.', get_user_name: '작품을 실행하고 있는 사용자의 이름값입니다.', get_project_timer_value: '이 블록이 실행되는 순간 초시계에 저장된 값입니다.', choose_project_timer_action: '초시계의 상태를 결정합니다.\n시작하기: 초시계를 시작합니다. \n정지하기: 초시계를 정지합니다. \n초기화하기: 초시계의 값을 0으로 초기화합니다. ', reset_project_timer: '실행되고 있던 타이머를 0으로 초기화합니다.', set_visible_project_timer: '초시계 창을 실행화면에서 숨기거나 보이게 합니다.', ask_and_wait: '오브젝트가 입력한 문자를 말풍선으로 묻고, 대답을 입력받습니다. (이 블록이 실행되면 실행화면에 ‘대답 창’이 생성됩니다.)', get_canvas_input_value: "사용자가 '대답 창'에 입력한 값입니다.", set_visible_answer: "대답 창'을 실행화면에서 숨기거나 보이게 합니다.", combine_something: '입력한 두 값을 결합한 값입니다.', get_variable: '선택한 변수에 저장된 값입니다.', change_variable: '선택한 변수에 입력한 값을 더합니다.', set_variable: '선택한 변수의 값을 입력한 값으로 정합니다.', robotis_carCont_sensor_value: '왼쪽 접속 센서 : 접촉(1), 비접촉(0) 값 입니다.
오른쪽 접촉 센서 : 접촉(1), 비접촉(0) 값 입니다.
선택 버튼 상태 : 접촉(1), 비접촉(0) 값 입니다.
최종 소리 감지 횟수 : 마지막 실시간 소리 감지 횟수 값 입니다.
실시간 소리 감지 횟수 : 약 1초 안에 다음 소리가 감지되면 1씩 증가합니다.
왼쪽 적외선 센서 : 물체와 가까울 수록 큰 값 입니다.
오른쪽 적외선 센서 : 물체와 가까울 수록 큰 값 값 입니다.
왼쪽 적외선 센서 캘리브레이션 값 : 적외선 센서의 캘리브레이션 값 입니다.
오른쪽 적외선 센서 캘리브레이션 값 : 적외선 센서의 캘리브레이션 값 입니다.
(*캘리브레이션 값 - 적외선센서 조정 값)', robotis_carCont_cm_led: '4개의 LED 중 1번 또는 4번 LED 를 켜거나 끕니다.
LED 2번과 3번은 동작 지원하지 않습니다.', robotis_carCont_cm_sound_detected_clear: '최종 소리 감지횟 수를 0 으로 초기화 합니다.', robotis_carCont_aux_motor_speed: '감속모터 속도를 0 ~ 1023 의 값(으)로 정합니다.', robotis_carCont_cm_calibration: '적외선센서 조정 값(http://support.robotis.com/ko/: 자동차로봇> 2. B. 적외선 값 조정)을 직접 정합니다.', robotis_openCM70_sensor_value: '최종 소리 감지 횟수 : 마지막 실시간 소리 감지 횟수 값 입니다.
실시간 소리 감지 횟수 : 약 1초 안에 다음 소리가 감지되면 1씩 증가합니다.
사용자 버튼 상태 : 접촉(1), 비접촉(0) 값 입니다.최종 소리 감지 횟수 : 마지막 실시간 소리 감지 횟수 값 입니다.
실시간 소리 감지 횟수 : 약 1초 안에 다음 소리가 감지되면 1씩 증가합니다.
사용자 버튼 상태 : 접촉(1), 비접촉(0) 값 입니다.', robotis_openCM70_aux_sensor_value: '서보모터 위치 : 0 ~ 1023, 중간 위치의 값은 512 입니다.
적외선센서 : 물체와 가까울 수록 큰 값 입니다.
접촉센서 : 접촉(1), 비접촉(0) 값 입니다.
조도센서(CDS) : 0 ~ 1023, 밝을 수록 큰 값 입니다.
온습도센서(습도) : 0 ~ 100, 습할 수록 큰 값 입니다.
온습도센서(온도) : -20 ~ 100, 온도가 높을 수록 큰 값 입니다.
온도센서 : -20 ~ 100, 온도가 높을 수록 큰 값 입니다.
초음파센서 : -
자석센서 : 접촉(1), 비접촉(0) 값 입니다.
동작감지센서 : 동작 감지(1), 동작 미감지(0) 값 입니다.
컬러센서 : 알수없음(0), 흰색(1), 검은색(2), 빨간색(3), 녹색(4), 파란색(5), 노란색(6) 값 입니다.
사용자 장치 : 사용자 센서 제작에 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.', robotis_openCM70_cm_buzzer_index: '음계를 0.1 ~ 5 초 동안 연주 합니다.', robotis_openCM70_cm_buzzer_melody: "멜로디를 연주 합니다.
멜로디를 연속으로 재생하는 경우, 다음 소리가 재생되지 않으면 '흐름 > X 초 기다리기' 블록을 사용하여 기다린 후 실행합니다.", robotis_openCM70_cm_sound_detected_clear: '최종 소리 감지횟 수를 0 으로 초기화 합니다.', robotis_openCM70_cm_led: '제어기의 빨간색, 녹색, 파란색 LED 를 켜거나 끕니다.', robotis_openCM70_cm_motion: '제어기에 다운로드 되어있는 모션을 실행합니다.', robotis_openCM70_cm_autodrive_motor: '자율주행 자동차의 모터 포트를 지정합니다.', robotis_openCM70_cm_autodrive_ir: '자율주행 자동차의 적외선 센서 포트를 지정합니다.', robotis_openCM70_cm_autodrive_speed: '차로를 따라 지정한 속도로 자율주행을 수행합니다.', robotis_openCM70_aux_motor_speed: '감속모터 속도를 0 ~ 100% 의 값(으)로 정합니다.', robotis_openCM70_aux_servo_mode: '서보모터를 회전모드 또는 관절모드로 정합니다.
한번 설정된 모드는 계속 적용됩니다.
회전모드는 서보모터 속도를 지정하여 서보모터를 회전 시킵니다.
관절모드는 지정한 서보모터 속도로 서보모터 위치를 이동 시킵니다.', robotis_openCM70_aux_servo_speed: '서보모터 속도를 0 ~ 100% 의 값(으)로 정합니다.', robotis_openCM70_aux_servo_position: '서보모터 위치를 -150도 ~ 150도 의 값(으)로 정합니다.
서보모터 속도와 같이 사용해야 합니다.', robotis_openCM70_aux_led_module: 'LED 모듈의 LED 를 켜거나 끕니다.', robotis_openCM70_aux_custom: '사용자 센서 제작에 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.', robotis_openCM70_cm_poweroff_timer: '제어기의 자동꺼짐 타이머를 설정합니다.
설정된 만큼의 시간동안 통신이 진행되지 않으면 제어기는 자동으로 꺼집니다.', robotis_openCM70_cm_custom_value: '컨트롤 테이블 주소를 직접 입력하여 값을 확인 합니다.
컨트롤 테이블 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.', robotis_openCM70_cm_custom: '컨트롤 테이블 주소를 직접 입력하여 값을 정합니다.
컨트롤 테이블 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.', show_variable: "선택한 변수의 '변수 창'을 실행화면에 보이게 합니다.", hide_variable: "선택한 변수의 '변수 창'을 실행화면에서 숨깁니다.", value_of_index_from_list: '선택한 리스트에서 입력한 순서에 있는 항목 값입니다.', add_value_to_list: '입력한 값을 선택한 리스트의 마지막 항목에 추가합니다.', remove_value_from_list: '선택한 리스트의 입력한 순서에 있는 항목을 삭제합니다.', insert_value_to_list: '입력한 값을 선택한 리스트의 입력한 순서의 항목으로 추가합니다. (입력한 항목 뒤에 있는 항목들은 순서가 하나씩 밀려납니다.)', change_value_list_index: '선택한 리스트에서 입력한 순서에 있는 항목의 값을 입력한 값으로 바꿉니다.', length_of_list: '선택한 리스트가 보유한 항목의 개수입니다.', show_list: "선택한 리스트의 '리스트 창'을 실행화면에 보이게 합니다.", hide_list: "선택한 리스트의 '리스트 창'을 실행화면에서 숨깁니다.", text: '해당 글상자가 표시하고 있는 문자값을 의미합니다.', text_read: '선택한 글상자에 작성된 내용입니다. (내용 안에 줄 바꿈이 있는 경우, 띄어쓰기하여 반환됩니다.)', text_write: '글상자의 내용을 입력한 값으로 고쳐 씁니다.', text_append: '글상자의 내용 뒤에 입력한 값을 추가합니다.', text_prepend: '글상자의 내용 앞에 입력한 값을 추가합니다.', text_flush: '글상자의 내용을 모두 지웁니다.', erase_all_effects: '오브젝트에 적용된 효과를 모두 지웁니다.', char_at: '입력한 값에서 입력한 숫자 번째의 글자 값입니다. (공백을 포함합니다.)', length_of_string: '입력한 값의 공백을 포함한 글자 수입니다.', substring: '입력한 값에서 입력한 범위 내의 글자 값입니다. (공백을 포함합니다.)', replace_string: '입력한 값에서 지정한 값을 찾아 추가로 입력한 값으로 모두 바꾼 값입니다. (영문 입력 시 대소문자를 구분합니다.)', index_of_string: '입력한 값에서 지정한 값이 처음으로 등장하는 위치 값입니다. (공백을 포함합니다.)', change_string_case: '입력한 영문의 모든 알파벳을 대문자 또는 소문자로 바꾼 값입니다.', direction_relative_duration: '오브젝트의 이동 방향이 입력한 시간에 걸쳐 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', get_sound_volume: '작품에 설정된 소리의 크기 값입니다.', sound_from_to: '해당 오브젝트가 선택한 소리를 입력한 구간을 재생하는 동시에 다음 블록을 실행합니다.', sound_from_to_and_wait: '해당 오브젝트가 선택한 소리를 입력한 구간을 재생한 후 다음 블록을 실행합니다.', Block_info: '블록 설명', Block_click_msg: '블록을 클릭하면
블록에 대한 설명이 나타납니다.', hamster_beep: '버저 소리를 짧게 냅니다.', hamster_change_both_wheels_by: '왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', hamster_change_buzzer_by: '버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.', hamster_change_output_by: '선택한 외부 확장 포트의 현재 출력 값에 입력한 값을 더합니다. 더한 결과는 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH', hamster_change_tempo_by: '연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.', hamster_change_wheel_by: '왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', hamster_clear_buzzer: '버저 소리를 끕니다.', hamster_clear_led: '왼쪽/오른쪽/양쪽 LED를 끕니다.', hamster_follow_line_until: '왼쪽/오른쪽/앞쪽/뒤쪽의 검은색/하얀색 선을 따라 이동하다가 교차로를 만나면 정지합니다.', hamster_follow_line_using: '왼쪽/오른쪽/양쪽 바닥 센서를 사용하여 검은색/하얀색 선을 따라 이동합니다.', hamster_hand_found: "근접 센서 앞에 손 또는 물체가 있으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", hamster_move_backward_for_secs: '입력한 시간(초) 동안 뒤로 이동합니다.', hamster_move_forward_for_secs: '입력한 시간(초) 동안 앞으로 이동합니다.', hamster_move_forward_once: '말판 위에서 한 칸 앞으로 이동합니다.', hamster_play_note_for: '선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.', hamster_rest_for: '입력한 박자만큼 쉽니다.', hamster_set_both_wheels_to: '왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', hamster_set_buzzer_to: '버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 버저 소리를 끕니다.', hamster_set_following_speed_to: '선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.', hamster_set_led_to: '왼쪽/오른쪽/양쪽 LED를 선택한 색깔로 켭니다.', hamster_set_output_to: '선택한 외부 확장 포트의 출력 값을 입력한 값으로 설정합니다. 입력하는 값은 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH', hamster_set_port_to: '선택한 외부 확장 포트의 입출력 모드를 선택한 모드로 설정합니다.', hamster_set_tempo_to: '연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.', hamster_set_wheel_to: '왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', hamster_stop: '양쪽 바퀴를 정지합니다.', hamster_turn_for_secs: '입력한 시간(초) 동안 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.', hamster_turn_once: '말판 위에서 왼쪽/오른쪽 방향으로 제자리에서 90도 회전합니다.', hamster_value: '왼쪽 근접 센서: 왼쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
오른쪽 근접 센서: 오른쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
왼쪽 바닥 센서: 왼쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
오른쪽 바닥 센서: 오른쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.
밝기: 밝기 센서의 값 (값의 범위: 0 ~ 65535, 초기값: 0) 밝을 수록 값이 커집니다.
온도: 로봇 내부의 온도 값 (값의 범위: 섭씨 -40 ~ 88도, 초기값: 0)
신호 세기: 블루투스 무선 통신의 신호 세기 (값의 범위: -128 ~ 0 dBm, 초기값: 0) 신호의 세기가 셀수록 값이 커집니다.
입력 A: 외부 확장 포트 A로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)
입력 B: 외부 확장 포트 B로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)', roboid_hamster_beep: '버저 소리를 짧게 냅니다.', roboid_hamster_change_both_wheels_by: '왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', roboid_hamster_change_buzzer_by: '버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.', roboid_hamster_change_output_by: '선택한 외부 확장 포트의 현재 출력 값에 입력한 값을 더합니다. 더한 결과는 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH', roboid_hamster_change_tempo_by: '연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.', roboid_hamster_change_wheel_by: '왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', roboid_hamster_clear_buzzer: '버저 소리를 끕니다.', roboid_hamster_clear_led: '왼쪽/오른쪽/양쪽 LED를 끕니다.', roboid_hamster_follow_line_until: '왼쪽/오른쪽/앞쪽/뒤쪽의 검은색/하얀색 선을 따라 이동하다가 교차로를 만나면 정지합니다.', roboid_hamster_follow_line_using: '왼쪽/오른쪽/양쪽 바닥 센서를 사용하여 검은색/하얀색 선을 따라 이동합니다.', roboid_hamster_hand_found: "근접 센서 앞에 손 또는 물체가 있으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", roboid_hamster_move_backward_for_secs: '입력한 시간(초) 동안 뒤로 이동합니다.', roboid_hamster_move_forward_for_secs: '입력한 시간(초) 동안 앞으로 이동합니다.', roboid_hamster_move_forward_once: '말판 위에서 한 칸 앞으로 이동합니다.', roboid_hamster_play_note_for: '선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.', roboid_hamster_rest_for: '입력한 박자만큼 쉽니다.', roboid_hamster_set_both_wheels_to: '왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', roboid_hamster_set_buzzer_to: '버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 버저 소리를 끕니다.', roboid_hamster_set_following_speed_to: '선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.', roboid_hamster_set_led_to: '왼쪽/오른쪽/양쪽 LED를 선택한 색깔로 켭니다.', roboid_hamster_set_output_to: '선택한 외부 확장 포트의 출력 값을 입력한 값으로 설정합니다. 입력하는 값은 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH', roboid_hamster_set_port_to: '선택한 외부 확장 포트의 입출력 모드를 선택한 모드로 설정합니다.', roboid_hamster_set_tempo_to: '연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.', roboid_hamster_set_wheel_to: '왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', roboid_hamster_stop: '양쪽 바퀴를 정지합니다.', roboid_hamster_turn_for_secs: '입력한 시간(초) 동안 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.', roboid_hamster_turn_once: '말판 위에서 왼쪽/오른쪽 방향으로 제자리에서 90도 회전합니다.', roboid_hamster_value: '왼쪽 근접 센서: 왼쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
오른쪽 근접 센서: 오른쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
왼쪽 바닥 센서: 왼쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
오른쪽 바닥 센서: 오른쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.
밝기: 밝기 센서의 값 (값의 범위: 0 ~ 65535, 초기값: 0) 밝을 수록 값이 커집니다.
온도: 로봇 내부의 온도 값 (값의 범위: 섭씨 -40 ~ 88도, 초기값: 0)
신호 세기: 블루투스 무선 통신의 신호 세기 (값의 범위: -128 ~ 0 dBm, 초기값: 0) 신호의 세기가 셀수록 값이 커집니다.
입력 A: 외부 확장 포트 A로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)
입력 B: 외부 확장 포트 B로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)', roboid_turtle_button_state: "등 버튼을 클릭했으면/더블클릭했으면/길게 눌렀으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", roboid_turtle_change_buzzer_by: '버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.', roboid_turtle_change_head_led_by_rgb: '머리 LED의 현재 R, G, B 값에 입력한 값을 각각 더합니다.', roboid_turtle_change_tempo_by: '연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.', roboid_turtle_change_wheel_by: '왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', roboid_turtle_change_wheels_by_left_right: '왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', roboid_turtle_clear_head_led: '머리 LED를 끕니다.', roboid_turtle_clear_sound: '소리를 끕니다.', roboid_turtle_cross_intersection: '검은색 교차로에서 잠시 앞으로 이동한 후 검은색 선을 찾아 다시 이동합니다.', roboid_turtle_follow_line: '하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동합니다.', roboid_turtle_follow_line_until: '하얀색 바탕 위에서 검은색 선을 따라 이동하다가 선택한 색깔을 컬러 센서가 감지하면 정지합니다.', roboid_turtle_follow_line_until_black: '하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동하다가 컬러 센서가 검은색을 감지하면 정지합니다.', roboid_turtle_is_color_pattern: "선택한 색깔 패턴을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", roboid_turtle_move_backward_unit: '입력한 거리(cm)/시간(초)/펄스만큼 뒤로 이동합니다.', roboid_turtle_move_forward_unit: '입력한 거리(cm)/시간(초)/펄스만큼 앞으로 이동합니다.', roboid_turtle_pivot_around_wheel_unit_in_direction: '왼쪽/오른쪽 바퀴 중심으로 입력한 각도(도)/시간(초)/펄스만큼 머리/꼬리 방향으로 회전합니다.', roboid_turtle_play_note: '선택한 계이름과 옥타브의 음을 계속 소리 냅니다.', roboid_turtle_play_note_for_beats: '선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.', roboid_turtle_play_sound_times: '선택한 소리를 입력한 횟수만큼 재생합니다.', roboid_turtle_play_sound_times_until_done: '선택한 소리를 입력한 횟수만큼 재생하고, 재생이 완료될 때까지 기다립니다.', roboid_turtle_rest_for_beats: '입력한 박자만큼 쉽니다.', roboid_turtle_set_buzzer_to: '버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 소리를 끕니다.', roboid_turtle_set_following_speed_to: '선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.', roboid_turtle_set_head_led_to: '머리 LED를 선택한 색깔로 켭니다.', roboid_turtle_set_head_led_to_rgb: '머리 LED의 R, G, B 값을 입력한 값으로 각각 설정합니다.', roboid_turtle_set_tempo_to: '연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.', roboid_turtle_set_wheel_to: '왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', roboid_turtle_set_wheels_to_left_right: '왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', roboid_turtle_stop: '양쪽 바퀴를 정지합니다.', roboid_turtle_touching_color: "선택한 색깔을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", roboid_turtle_turn_at_intersection: '검은색 교차로에서 잠시 앞으로 이동한 후 제자리에서 왼쪽/오른쪽/뒤쪽으로 회전하고 검은색 선을 찾아 다시 이동합니다.', roboid_turtle_turn_unit_in_place: '입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.', roboid_turtle_turn_unit_with_radius_in_direction: '입력한 반지름의 원을 그리면서 입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽, 머리/꼬리 방향으로 회전합니다.', roboid_turtle_value: '색깔 번호: 컬러 센서가 감지한 색깔의 번호 (값의 범위: -1 ~ 8, 초기값: -1)
색깔 패턴: 컬러 센서가 감지한 색깔 패턴의 값 (값의 범위: -1 ~ 88, 초기값: -1)
바닥 센서: 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
버튼: 거북이 등 버튼의 상태 값 (누르면 1, 아니면 0, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.', turtle_button_state: "등 버튼을 클릭했으면/더블클릭했으면/길게 눌렀으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", turtle_change_buzzer_by: '버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.', turtle_change_head_led_by_rgb: '머리 LED의 현재 R, G, B 값에 입력한 값을 각각 더합니다.', turtle_change_tempo_by: '연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.', turtle_change_wheel_by: '왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', turtle_change_wheels_by_left_right: '왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', turtle_clear_head_led: '머리 LED를 끕니다.', turtle_clear_sound: '소리를 끕니다.', turtle_cross_intersection: '검은색 교차로에서 잠시 앞으로 이동한 후 검은색 선을 찾아 다시 이동합니다.', turtle_follow_line: '하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동합니다.', turtle_follow_line_until: '하얀색 바탕 위에서 검은색 선을 따라 이동하다가 선택한 색깔을 컬러 센서가 감지하면 정지합니다.', turtle_follow_line_until_black: '하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동하다가 컬러 센서가 검은색을 감지하면 정지합니다.', turtle_is_color_pattern: "선택한 색깔 패턴을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", turtle_move_backward_unit: '입력한 거리(cm)/시간(초)/펄스만큼 뒤로 이동합니다.', turtle_move_forward_unit: '입력한 거리(cm)/시간(초)/펄스만큼 앞으로 이동합니다.', turtle_pivot_around_wheel_unit_in_direction: '왼쪽/오른쪽 바퀴 중심으로 입력한 각도(도)/시간(초)/펄스만큼 머리/꼬리 방향으로 회전합니다.', turtle_play_note: '선택한 계이름과 옥타브의 음을 계속 소리 냅니다.', turtle_play_note_for_beats: '선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.', turtle_play_sound_times: '선택한 소리를 입력한 횟수만큼 재생합니다.', turtle_play_sound_times_until_done: '선택한 소리를 입력한 횟수만큼 재생하고, 재생이 완료될 때까지 기다립니다.', turtle_rest_for_beats: '입력한 박자만큼 쉽니다.', turtle_set_buzzer_to: '버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 소리를 끕니다.', turtle_set_following_speed_to: '선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.', turtle_set_head_led_to: '머리 LED를 선택한 색깔로 켭니다.', turtle_set_head_led_to_rgb: '머리 LED의 R, G, B 값을 입력한 값으로 각각 설정합니다.', turtle_set_tempo_to: '연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.', turtle_set_wheel_to: '왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', turtle_set_wheels_to_left_right: '왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', turtle_stop: '양쪽 바퀴를 정지합니다.', turtle_touching_color: "선택한 색깔을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", turtle_turn_at_intersection: '검은색 교차로에서 잠시 앞으로 이동한 후 제자리에서 왼쪽/오른쪽/뒤쪽으로 회전하고 검은색 선을 찾아 다시 이동합니다.', turtle_turn_unit_in_place: '입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.', turtle_turn_unit_with_radius_in_direction: '입력한 반지름의 원을 그리면서 입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽, 머리/꼬리 방향으로 회전합니다.', turtle_value: '색깔 번호: 컬러 센서가 감지한 색깔의 번호 (값의 범위: -1 ~ 8, 초기값: -1)
색깔 패턴: 컬러 센서가 감지한 색깔 패턴의 값 (값의 범위: -1 ~ 88, 초기값: -1)
바닥 센서: 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
버튼: 거북이 등 버튼의 상태 값 (누르면 1, 아니면 0, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.', neobot_sensor_value: 'IN1 ~ IN3 포트 및 리모컨에서 입력되는 값 그리고 배터리 정보를 0부터 255의 숫자로 표시합니다.', neobot_sensor_convert_scale: '선택한 포트 입력값의 변화를 특정범위의 값으로 표현범위를 조절할 수 있습니다.', neobot_left_motor: 'L모터 포트에 연결한 모터의 회전방향 및 속도를 설정합니다.', neobot_stop_left_motor: 'L모터 포트에 연결한 모터를 정지합니다.', neobot_right_motor: 'R모터 포트에 연결한 모터의 회전방향 및 속도를 설정합니다.', neobot_stop_right_motor: 'R모터 포트에 연결한 모터를 정지합니다.', neobot_all_motor: 'L모터 및 R모터 포트에 2개 모터를 연결하여 바퀴로 활용할 때 전, 후, 좌, 우 이동 방향 및 속도, 시간을 설정할 수 있습니다.', neobot_stop_all_motor: 'L모터 및 R모터에 연결한 모터를 모두 정지합니다.', neobot_set_servo: 'OUT1 ~ OUT3에 서보모터를 연결했을 때 0도 ~ 180도 범위 내에서 각도를 조절할 수 있습니다.', neobot_set_output: 'OUT1 ~ OUT3에 라이팅블록 및 전자회로를 연결했을 때 출력 전압을 설정할 수 있습니다.
0은 0V, 1 ~ 255는 2.4 ~ 4.96V의 전압을 나타냅니다.', neobot_set_fnd: 'FND로 0~99 까지의 숫자를 표시할 수 있습니다.', neobot_set_fnd_off: 'FND에 표시한 숫자를 끌 수 있습니다.', neobot_play_note_for: '주파수 발진 방법을 이용해 멜로디에 반음 단위의 멜로디 음을 발생시킬 수 있습니다.', rotate_by_angle_dropdown: '오브젝트의 방향을 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', chocopi_control_button: '버튼이 눌리면 참이 됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_control_event: '버튼을 누르거나 뗄 때 처리할 엔트리 블록들을 연결합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_control_joystick: '조이스틱 좌우, 상하, 볼륨의 값은 0~4095까지 입니다.
따라서 2047 근처가 중간이 됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_dc_motor: 'DC모터 모듈에는 직류전동기 두개를 연결 할 수 있습니다.
직류 전동기는 최대 5V로 동작하게 됩니다.
값은 100이 최대(100%)이고 음수를 넣으면 반대 방향으로 회전합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_led: 'LED번호는 LED블록에 연결된 순서이고 1번부터 시작합니다.
RGB값은 0~255사이의 값입니다.
빨강(Red),녹색(Green), 파랑(Blue)순서로 입력합니다.
밝은 LED를 직접보면 눈이 아프니까 값을 0~5정도로 씁니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_motion_photogate_event: '포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
빛센서를 물체로 가리거나 치우면 시작되는 엔트리 블록을 연결합니다
모션 모듈에는 포토게이트 2개를 연결할 수 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_motion_photogate_status: '포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
물체가 빛센서를 가리면 참이됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_motion_photogate_time: '포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
이 블록은 물체가 빛센서를 가리거나 벗어난 시간을 가집니다.
1/10000초까지 측정할 수 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_motion_value: '모션 모듈에는 3개의 적외선 센서가 있습니다.
0~4095사이의 값을 가질 수 있는데 물체가 빛을 많이 반사할 수록 작은 값을 가집니다.
거리를 대략적으로 측정할 수 있습니다.
가속도와 각가속도 값의 범위는 -32768~32767 까지입니다.
가속도를 이용해서 센서의 기울기를 측정할 수도 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_sensor: '온도 값은 섭씨 온도입니다.
습도 값은 백분율로 나타낸 상대습도 값입니다.
빛은 로그스케일로 0~4095사이입니다.
아날로그 값은 0~4095사이입니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_servo_motor: '서보모터 모듈에는 4개의 서보모터를 연결 할 수 있습니다.
서보모터는 5V로 동작하게 됩니다.
각도는 0~200도까지 지정할 수 있습니다.
연속회전식 서보모터를 연결하면 각도에 따라 속도가 변하게됩니다.
90~100 사이가 중간값입니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_touch_event: '터치 모듈에는 1~12번의 연결 패드가 있습니다.
만지거나 뗄 때 처리할 엔트리 블록들을 연결합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_touch_status: '터치 모듈의 패드를 만지면 참이됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_touch_value: '터치패드에 연결된 물체의 전기용량이 커지면 값이 작아집니다.
여러 명이 손잡고 만지면 더 작은 값이 됩니다.
전기용량이란 물체에 전기를 띈 입자를 얼마나 가지고 있을 수 있는 지를 말합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', boolean_and_or: '그리고 : 두 판단이 모두 참인 경우 ‘참’으로 판단합니다.
또는 : 두 판단 중 하나라도 참이 있는 경우 ‘참’으로 판단합니다.', check_weather: '
선택한 날짜와 지역의 날씨 정보를 실제 날씨 상태와 비교하여 일치하는 경우 ‘참’으로 판단합니다.
* 옵션
날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
날씨: 맑음, 구름조금, 구름많음, 흐림, 비, 진눈깨비, 눈', check_finedust: '
선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.
* 옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
미세먼지 등급: 좋음, 보통, 나쁨, 매우나쁨', get_weather_data: '
선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.
* 옵션
날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
정보: 최저기온(℃), 최고기온(℃), 습도(%), 강수량(mm), 강수확률(%), 풍속(m/s)', get_current_weather_data: '
현재 선택한 지역의 날씨 정보값(기온, 미세먼지농도)입니다.
* 옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
정보: (기온(℃)), 미세먼지농도(㎍)', get_today_temperature: '
오늘 선택한 지역과 시간대의 기온을 의미합니다.
* 옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시간대: 00, 03, 06, 09, 12, 15, 18, 21', check_city_weather: '선택한 날짜와 지역의 날씨 정보를 실제 날씨 상태와 비교하여 일치하는 경우 ‘참’으로 판단합니다.\n* 옵션\n날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후\n시도: 서울, 강원, 경기, 경남, 경북 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n날씨: 맑음, 구름조금, 구름많음, 흐림, 비, 진눈깨비, 눈', check_city_finedust: '선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.\n* 옵션\n시도: 서울, 강원, 경기, 경남, 경북,광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n미세먼지 등급: 좋음, 보통, 나쁨, 매우나쁨', get_city_weather_data: '선택한 날짜와 지역의 각종 날씨 정보입니다.\n *옵션\n날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후\n시도:서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n정보: 최저기온(℃), 최고기온(℃), 습도(%), 강수량(mm), 강수확률(%), 풍속(m/s)', get_current_city_weather_data: '현재 선택한 지역의 날씨 정보입니다.\n*옵션\n시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n정보: 기온(℃), 미세먼지농도(㎍)', get_today_city_temperature: '오늘 선택한 지역과 시간대의 기온입니다.\n*옵션\n시도: 서울, 강원, 경기, 경남, 경북 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n시간대: 00, 03, 06, 09, 12, 15, 18, 21', count_festival: '선택한 날짜와 지역에서 열리는 행사의 수입니다.\n* 옵션 \n지역: 서울, 강원, 경기, 경남, 경북 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n행사일: 1~12월', get_festival_info: '선택한 날짜와 지역에서 열리는 행사에 대한 정보입니다.\n* 옵션 \n지역: 서울, 강원, 경기, 경남, 경북 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n행사일: 1~12월 \n정보: 제목, 지역, 시작일, 종료일, 주소, 개요, 홈페이지', get_translated_string: '입력한 문자값을 선택한 언어로 번역합니다. 입력은 3000자까지 가능합니다.\n*번역 가능한 언어 \n - 한국어 → 영어, 중국어 간체, 중국어 번체, 베트남어, 스페인어, 인도네시아어, 태국어, 프랑스어\n - 영어 → 일본어, 프랑스어, 한국어\n - 중국어 간체, 중국어 번체, 베트남어, 스페인어, 인도네시아어, 태국어, 프랑스어 → 한국어\n - 일본어 →영어 \n - 프랑스어 → 영어', check_language: '입력된 문자값의 언어를 감지합니다. 입력은 문장 형태로 3000자까지 가능합니다.', count_disaster_behavior: '선택한 자연재해가 발생했을 때 해야할 행동요령의 수입니다.
*옵션
자연재해: 태풍, 홍수, 호우, 강풍, 대설, 한파, 풍랑, 황사, 폭염, 가뭄, 지진, 해일, 산사태
상황: 자연재해에 따라 다름 ', get_disaster_behavior: '선택한 자연재해가 발생했을 때 해야하는 행동요령에 대한 정보입니다.
*옵션
자연재해: 태풍, 홍수, 호우, 강풍, 대설, 한파, 풍랑, 황사, 폭염, 가뭄, 지진, 해일, 산사태
상황: 자연재해에 따라 다름', count_lifeSafety_behavior: '선택한 생활 속 문제가 발생했을 때 해야할 행동요령의 수입니다.
*옵션
생활 속 문제: 응급처치, 심폐소생술, 소화기·소화전 사용법, 식중독, 산행안전, 실종유괴, 성폭력, 학교폭력, 가정 폭력, 억류 및 납치, 교통사고, 승강기 안전사고, 미세먼지
상황: 생활 속 문제에 따라 다름 ', get_lifeSafety_behavior: '선택한 생활 속 문제가 발생했을 때 해야할 행동요령에 대한 정보입니다.
*옵션
생활 속 문제: 응급처치, 심폐소생술, 소화기·소화전 사용법, 식중독, 산행안전, 실종유괴, 성폭력, 학교폭력, 가정 폭력, 억류 및 납치, 교통사고, 승강기 안전사고, 미세먼지
상황: 생활 속 문제에 따라 다름 ', read_text: '입력한 문자값을 설정된 목소리로 읽습니다.
입력은 2500자까지 가능합니다.
인터넷에 연결되어 있지 않거나 인터넷 환경이 불안할 경우, 해당 블록이 실행되지 않고 다음 블록으로 넘어갈 수 있습니다.', set_tts_property: '선택한 목소리가 선택한 속도와 선택한 음높이로 설정됩니다.', read_text_wait_with_block: '입력한 문자값을 읽어준 후 다음 블록을 실행합니다.', check_microphone: "컴퓨터에 마이크가 연결되어 있는 경우 '참'으로 판단합니다. (IE/Safari 브라우저 지원하지 않음)", speech_to_text_convert: '마이크에 입력되는 사람의 목소리를 텍스트로 변환합니다. (IE/Safari 브라우저 지원하지 않음)', get_microphone_volume: '마이크에 입력되는 소리의 크기 값입니다. (IE/Safari 브라우저 지원하지 않음)', speech_to_text_get_value: '사람의 목소리를 문자로 바꾼 값입니다. 목소리가 입력되지 않거나, 음성인식 도중 오류가 발생한 경우 무조건 0 값을 갖습니다. (IE/Safari 브라우저 지원하지 않음)', video_draw_webcam: '컴퓨터에 연결된 카메라에 촬영되는 화면을 실행화면에서 보이게하거나 숨깁니다.', video_check_webcam: "컴퓨터에 카메라가 연결되어 있는 경우 '참'으로 판단합니다.", video_set_camera_option: '촬영되는 화면의 효과를 입력한 값으로 정합니다. 밝기: -100~100 사이의 범위로 설정할 수 있습니다. (-100 이하는 -100으로 100 이상은 100으로 처리됩니다.) 투명도: 0~100 사이의 범위로 설정할 수 있습니다. (0 이하는 0으로 100 이상은 100으로 처리됩니다.)', video_flip_camera: '촬영되는 화면을 좌우 혹은 상하로 뒤집습니다.', video_toggle_model: '선택한 인식모델을 동작시키거나 중지시킵니다. 얼굴 인식: 사람의 얼굴을 인식하여 눈, 코, 입, 귀의 위치나 예상되는 성별, 나이, 감정을 알 수 있습니다. 사람 인식: 사람의 몸을 인식하여 각 신체부위의 위치 등을 알 수 있습니다. 객체 인식: 인식된 객체의 종류를 알 수 있습니다. (사람이나 물건)', video_toggle_ind: '인식 된 사람 / 얼굴 / 사물 을 화면에 표시하거나 숨깁니다', video_number_detect: '인식된 사람 / 얼굴 / 사물의 숫자입니다 촬영되는 화면에 객체로 인식된 객체의 개수입니다. *인식할 수 있는 사물: 사람, 자전거, 자동차, 오토바이, 비행기, 버스, 기차, 트럭, 보트,교통 신호등, 소화전, 정지 신호, 주차 미터, 벤치, 새, 고양이, 개, 말, 양, 암소, 코끼리, 곰, 얼룩말, 기린, 책가방, 우산, 핸드백, 넥타이, 가방, 프리스비, 스키, 스노보드, 스포츠 볼, 연, 야구 방망이, 야구 글러브, 스케이트 보드, 서핑 보드, 테니스 라켓, 병, 와인 글라스, 컵, 포크, 나이프, 숟가락, 그릇, 바나나, 애플, 샌드위치, 주황색, 브로콜리, 당근, 핫도그, 피자, 도넛, 케이크, 의자, 소파, 화분, 침대, 식사테이블, 화장실, TV 모니터, 노트북, 마우스, 원격, 키보드, 휴대 전화, 전자 레인지, 오븐, 토스터기, 싱크대, 냉장고, 도서, 시계, 꽃병, 가위, 테디베어, 헤어드라이어, 칫솔', video_detected_face_info: '입력한 순서의 얼굴의 선택한 정보의 추정값입니다. 인식이 잘 되지 않는 경우 무조건 0으로 출력됩니다. (성별, 나이, 감정)', video_motion_value: '선택한 오브젝트 혹은 실행화면 위에서 감지되는 움직임 혹은 방향 값입니다. 움직임: 움직임이 크고 빠를 수록 값이 커집니다. 방향: 오른쪽 혹은 위쪽으로 움직일 때 양수, 왼쪽 혹은 아래쪽으로 움직일 때 음수가 됩니다.', video_face_part_coord: '입력한 순서의 얼굴 중 선택된 얼굴 부위의 위치값입니다. 인식이 잘 되지 않는 경우 무조건 0으로 출력됩니다. (왼쪽 눈, 오른쪽 눈, 코, 왼쪽 입꼬리, 오른쪽 입꼬리, 윗 입술, 아랫입술)', video_body_part_coord: '입력한 순서의 사람의 선택한 신체 부위의 위치값입니다. (얼굴, 왼쪽 어깨, 왼쪽 팔꿈치, 왼쪽 손목, 왼쪽 엉덩이, 왼쪽 무릎, 왼쪽 발목, 오른쪽 어깨, 오른쪽 팔꿈치, 오른쪽 손목, 오른쪽 엉덩이, 오른쪽 무릎, 오른쪽 발목)', append_row_to_table: '선택한 테이블의 마지막에 행(열)을 추가합니다. 추가된 행(열)의 모든 열(행) 값은 0입니다.', insert_row_to_table: '선택한 테이블의 입력한 순서에 행(열)을 추가합니다. 추가된 행(열)의 모든 열(행) 값은 0입니다. (입력한 행(열) 뒤에 있는 행들은 순서가 하나씩 밀려납니다.', delete_row_from_table: '선택한 테이블의 입력한 순서에 있는 행(열)을 삭제합니다.', set_value_from_table: '선택한 테이블에서 입력한 순서의 선택된 열값을 입력한 값으로 바꿉니다.', get_table_count: '선택한 테이블이 보유한 행과 열의 개수입니다.', get_value_from_table: '선택한 테이블에서 입력한 순서의 선택된 열 값 입니다.', calc_values_from_table: '선택한 테이블에서 선택한 열들에 대한 계산값입니다. (합, 최댓값, 최솟값, 평균값, 표준편차)', open_table_chart: '선택한 테이블의 차트창을 엽니다.', close_table_chart: '열려있는 테이블 차트창을 닫습니다.', get_coefficient: '선택한 테이블에서 두 속성 사이의 상관계수입니다. 상관계수가 1(-1)에 가까울 수록 강한 양(음)의 선형 상관관계를 갖습니다.', }; Lang.Category = { entrybot_friends: '엔트리봇 친구들', people: '사람', animal: '동물', animal_flying: '하늘', animal_land: '땅', animal_water: '물', animal_others: '기타', plant: '식물', plant_flower: '꽃', plant_grass: '풀', plant_tree: '나무', plant_others: '기타', vehicles: '탈것', vehicles_flying: '하늘', vehicles_land: '땅', vehicles_water: '물', vehicles_others: '기타', architect: '건물', architect_building: '건축물', architect_monument: '기념물', architect_others: '기타', food: '음식', food_vegetables: '과일/채소', food_meat: '고기', food_drink: '음료', food_others: '기타', environment: '환경', environment_nature: '자연', environment_space: '우주', environment_others: '기타', stuff: '물건', stuff_living: '생활', stuff_hobby: '취미', stuff_others: '기타', fantasy: '판타지', interface: '인터페이스', interface_website: '웹사이트', interface_game: '게임', interface_others: '기타', background: '배경', background_outdoor: '실외', background_indoor: '실내', background_nature: '자연', background_others: '기타', }; Lang.Device = { arduino: '아두이노', hamster: '햄스터', roboid: '로보이드', turtle: '거북이', albert: '알버트', robotis_carCont: '로보티즈 자동차 로봇', robotis_openCM70: '로보티즈 IoT', sensorBoard: '엔트리 센서보드', trueRobot: '뚜루뚜루', CODEino: '코드이노', bitbrick: '비트브릭', creamo: '크리모', playcode: '플레이코드', funboard: '펀보드', bitBlock: '비트블록', xbot_epor_edge: '엑스봇', dplay: '디플레이', iboard: '아이보드', nemoino: '네모이노', ev3: 'EV3', robotori: '로보토리', smartBoard: '스마트보드', chocopi: '초코파이보드', rokoboard: '로코보드', altino: '알티노', mechatro: '메카트로', }; Lang.General = { turn_on: '켜기', turn_off: '끄기', left: '왼쪽', right: '오른쪽', param_string: 'string', both: '양쪽', transparent: '투명', black: '검은색', brown: '갈색', red: '빨간색', yellow: '노란색', green: '초록색', skyblue: '하늘색', blue: '파란색', purple: '보라색', white: '하얀색', note_c: '도', note_d: '레', note_e: '미', note_f: '파', note_g: '솔', note_a: '라', note_b: '시', questions: '문제', clock: '시계', counter_clock: '반시계', font_size: '글자 크기', second: '초', alert_title: '알림', confirm_title: '확인', update_title: '업데이트 알림', recent_download: '최신 버전 다운로드', recent_download2: '최신버전 다운로드', latest_version: '최신 버전입니다.', dont_show_again: '다시보지 않기', }; Lang.Fonts = { jeju_hallasan: '한라산체', gothic_coding: '코딩고딕체', batang: '바탕체', gothic: '나눔고딕체', myeongjo: '나눔명조', pen_script: '나눔손글씨', square_round: '나눔스퀘어라운드체', jalnan: '잘난체', designhouse: '디자인하우스체', malssami815: '말싸미815체', dunggeunmo: '둥근모꼴체', hs_bombaram: 'HS봄바람체', yisunshin: '이순신체', goyang: '고양체', flower_road: '꽃길체', uhbeemysen: '어비마이센체', sd_comic_stencil: '산돌 코믹스탠실', sd_childfundkorea: '산돌 초록우산 어린이', sd_cinema_theater: '산돌 씨네마극장', sd_mapssi: '산돌 맵씨', sd_shabang: '산돌 별이샤방샤방', sd_woodcarving: '산돌 목각', sd_yongbi: '산돌 용비어천가', }; Lang.Hw = { note: '음표', leftWheel: '왼쪽 바퀴', rightWheel: '오른쪽 바퀴', leftEye: '왼쪽 눈', rightEye: '오른쪽 눈', led: '불빛', led_en: 'LED', body: '몸통', front: '앞쪽', port_en: '', port_ko: '번 포트', sensor: '센서', light: '빛', temp: '온도', switch_: '스위치', right_ko: '오른쪽', right_en: '', left_ko: '왼쪽', left_en: '', up_ko: '위쪽', up_en: '', down_ko: '아래쪽', down_en: '', output: '출력', left: '왼쪽', right: '오른쪽', sub: '서보', motor: '모터', '': '', buzzer: '버저', IR: '적외선', acceleration: '가속', analog: '아날로그', angular_acceleration: '각가속', button: '버튼', humidity: '습도', joystick: '조이스틱', port: '포트', potentiometer: '포텐시오미터', servo: '서보', }; Lang.template = { albert_hand_found: 'Entry.Albert.isHandFound()', albert_is_oid_value: "Entry.Albert.isOidValue(' %1 ' , %2 )", albert_value: '%1', albert_move_forward_for_secs: 'Entry.Albert.moveForwardForSecs( %1 ) %2', albert_move_backward_for_secs: 'Entry.Albert.moveBackwardForSecs( %1 ) %2', albert_turn_for_secs: "Entry.Albert.turnForSecs(' %1 ', %2 ) %3", albert_change_both_wheels_by: 'Entry.Albert.changeWheelsBy( %1 , %2 ) %3', albert_set_both_wheels_to: 'Entry.Albert.setWheelsTo( %1 , %2 ) %3', albert_change_wheel_by: "Entry.Albert.changeWheelsBy(' %1 ', %2 ) %3", albert_set_wheel_to: "Entry.Albert.setWheelsTo(' %1 ', %2 ) %3", albert_stop: 'Entry.Albert.stop() %1', albert_set_pad_size_to: 'Entry.Albert.setBoardSizeTo( %1 , %2 ) %3', albert_move_to_x_y_on_board: 'Entry.Albert.moveToOnBoard( %1 , %2 ) %3', albert_set_orientation_on_board: 'Entry.Albert.setOrientationToOnBoard( %1 )', albert_set_eye_to: "Entry.Albert.setEyeTo(' %1 ',' %2 ') %3", albert_clear_eye: "Entry.Albert.clearEye(' %1 ') %2", albert_body_led: "Entry.Albert.turnBodyLed(' %1 ') %2", albert_front_led: "Entry.Albert.turnFrontLed(' %1 ') %2", albert_beep: 'Entry.Albert.beep() %1', albert_change_buzzer_by: 'Entry.Albert.changeBuzzerBy( %1 ) %2', albert_set_buzzer_to: 'Entry.Albert.setBuzzerTo( %1 ) %2', albert_clear_buzzer: 'Entry.Albert.clearBuzzer() %1', albert_play_note_for: "Entry.Albert.playNoteForBeats(' %1 ', %2 , %3 ) %4", albert_rest_for: 'Entry.Albert.restForBeats( %1 ) %2', albert_change_tempo_by: 'Entry.Albert.changeTempoBy( %1 ) %2', albert_set_tempo_to: 'Entry.Albert.setTempoTo( %1 ) %2', albert_move_forward: 'move forward %1', albert_move_backward: 'move backward %1', albert_turn_around: 'turn %1 %2', albert_set_led_to: "Entry.Hamster.setLedTo(' %1 %2 ') %3", albert_clear_led: "Entry.Hamster.clearLed(' %1 ') %2", albert_change_wheels_by: '%1 %2 %3', albert_set_wheels_to: '%1 %2 %3', arduino_text: '%1', arduino_get_sensor_number: '%1 ', arduino_get_port_number: '%1 ', arduino_get_digital_toggle: '%1 ', arduino_get_pwm_port_number: '%1 ', arduino_get_number_sensor_value: '아날로그 %1 번 센서값 ', arduino_ext_get_analog_value: '아날로그 %1 번 센서값', arduino_ext_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', arduino_ext_get_ultrasonic_value: '울트라소닉 Trig %1 Echo %2 센서값', arduino_ext_toggle_led: '디지털 %1 번 핀 %2 %3', arduino_ext_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', arduino_ext_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', arduino_ext_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', arduino_ext_get_digital: '디지털 %1 번 센서값', blacksmith_get_analog_value: '아날로그 %1 번 핀 센서 값', blacksmith_get_analog_mapping: '아날로그 %1 번 핀 센서 값의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼 값', blacksmith_get_digital_bluetooth: '블루투스 RX 2 핀 데이터 값', blacksmith_get_digital_ultrasonic: '초음파 Trig %1 핀 Echo %2 핀 센서 값', blacksmith_get_digital_toggle: '디지털 %1 번 핀 센서 값', blacksmith_set_digital_toggle: '디지털 %1 번 핀 %2 %3', blacksmith_set_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', blacksmith_set_digital_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', blacksmith_set_digital_buzzer: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', blacksmith_set_digital_lcd: 'LCD화면 %1 줄에 %2 나타내기 %3', blacksmith_set_digital_bluetooth: '블루투스 TX 3 핀에 %1 데이터 보내기 %2', dplay_get_number_sensor_value: '아날로그 %1 번 센서값 ', nemoino_get_number_sensor_value: '아날로그 %1 번 센서값 ', sensorBoard_get_number_sensor_value: '아날로그 %1 번 센서값 ', truetrue_get_accsensor: '가속도센서 %1 의 값', truetrue_get_bottomcolorsensor: '바닥컬러센서 %1 의 값', truetrue_get_frontcolorsensor: '전면컬러센서 %1 의 값', truetrue_get_linesensor: '라인센서 %1 의 값', truetrue_get_proxisensor: '근접센서 %1 의 값', truetrue_set_colorled: '컬러LED Red %1 Green %2 Blue %3 로 설정 %4', truetrue_set_dualmotor: 'DC모터 좌 %1 우 %2 속도로 %3 초 구동 %4', truetrue_set_led_colorsensor: '%1 조명용 LED %2 %3', truetrue_set_led_linesensor: '라인센서 조명용 LED %1 %2', truetrue_set_led_proxi: '%1 조명용 LED %2 %3', truetrue_set_linetracer: '라인트레이싱 모드 %1 %2', truetrue_set_singlemotor: 'DC모터 %1 속도 %2 로 설정 %3', CODEino_get_number_sensor_value: '아날로그 %1 번 센서값 ', ardublock_get_number_sensor_value: '아날로그 %1 번 센서값 ', arduino_get_digital_value: '디지털 %1 번 센서값 ', dplay_get_digital_value: '디지털 %1 번 센서값 ', nemoino_get_digital_value: '디지털 %1 번 센서값 ', sensorBoard_get_digital_value: '디지털 %1 번 센서값 ', CODEino_get_digital_value: '디지털 %1 핀의 값 ', CODEino_set_digital_value: '디지털 %1 핀의 %2 %3', CODEino_set_pwm_value: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', ardublock_get_digital_value: '디지털 %1 번 센서값 ', arduino_toggle_led: 'Digital %1 Pin %2 %3', dplay_toggle_led: 'Digital %1 Pin %2 %3', nemoino_toggle_led: 'Digital %1 Pin %2 %3', sensorBoard_toggle_led: 'Digital %1 Pin %2 %3', CODEino_toggle_led: 'Digital %1 Pin %2 %3', arduino_toggle_pwm: 'Digital %1 Pin %2 %3', dplay_toggle_pwm: 'Digital %1 Pin %2 %3', nemoino_toggle_pwm: 'Digital %1 Pin %2 %3', sensorBoard_toggle_pwm: 'Digital %1 Pin %2 %3', CODEino_toggle_pwm: 'Digital %1 Pin %2 %3', ardublock_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', arduino_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', dplay_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', nemoino_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', sensorBoard_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', CODEino_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', CODEino_set_rgb_value: '컬러 LED의 %1 색상을 %2 (으)로 정하기 %3', CODEino_set_rgb_add_value: '컬러 LED의 %1 색상에 %2 만큼 더하기 %3', CODEino_set_rgb_off: '컬러 LED 끄기 %1', CODEino_set__led_by_rgb: '컬러 LED 색상을 빨강 %1 초록 %2 파랑 %3 (으)로 정하기 %4', CODEino_rgb_set_color: '컬러 LED의 색상을 %1 (으)로 정하기 %2', CODEino_led_by_value: '컬러 LED 켜기 %1', ardublock_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', joystick_get_number_sensor_value: '아날로그 %1 번 센서값 ', joystick_get_digital_value: '디지털 %1 번 센서값 ', joystick_toggle_led: 'Digital %1 Pin %2 %3', joystick_toggle_pwm: 'Digital %1 Pin %2 %3', joystick_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', sensorBoard_get_named_sensor_value: '%1 센서값', sensorBoard_is_button_pressed: '%1 버튼을 눌렀는가?', sensorBoard_led: '%1 LED %2 %3', arduino_download_connector: '%1', download_guide: '%1', arduino_download_source: '%1', arduino_connected: '%1', arduino_connect: '%1', arduino_reconnect: '%1', CODEino_get_sensor_number: '%1 ', CODEino_get_named_sensor_value: ' %1 Sensor value ', CODEino_get_sound_status: 'Sound is %1 ', CODEino_get_light_status: 'Light is %1 ', CODEino_is_button_pressed: ' Operation %1 ', CODEino_get_accelerometer_direction: ' 3-AXIS Accelerometer %1 ', CODEino_get_accelerometer_value: ' 3-AXIS Accelerometer %1 -axis value ', CODEino_get_analog_value: '아날로그 %1 센서의 값', iboard_button: '%1 버튼을 눌렀는가?', iboard_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', iboard_get_analog_value: '아날로그 %1 번 센서값 ', iboard_get_analog_value_map: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', iboard_get_digital: '디지털 %1 번 센서값 ', iboard_led: 'LED %1 번을 %2 %3', iboard_motor: '모터를 %2 으로 동작하기 %3', iboard_pwm_led: 'LED %1 번의 밝기를 %2 (으)로 정하기 %3', iboard_rgb_led: 'RGB LED의 %1 LED %2 %3', iboard_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', iboard_toggle_led: '디지털 %1 번 핀 %2 %3', bitbrick_when_button_pressed: '%1 버튼 %2 눌러졌을 때', bitbrick_when_sensor_get_value: '%1 %2 값 %3 %4 일 때', bitbrick_is_touch_pressed: '버튼 %1 이(가) %2 인가?', bitbrick_is_sensor_value_compare: '%1 값 %2 %3 인가?', bitbrick_sensor_value: '%1 값', bitbrick_convert_scale: '변환 %1 값 %2 ~ %3 에서 %4 ~ %5', bitbrick_turn_on_color_led_by_rgb: '엘이디를 빨강 %1 초록 %2 파랑 %3 %4 (으)로 켜기', bitbrick_turn_on_color_led_by_picker: '엘이디를 %1 (으)로 켜기 %2', bitbrick_turn_on_color_led_by_value: '엘이디를 %1 (으)로 켜기 %2', bitbrick_turn_off_color_led: '엘이디 끄기 %1', bitbrick_buzzer: '버저음 %1 내기 %2', bitbrick_servomotor_angle: '서보모터 %1 각도 %2 %3', bitbrick_dc_direction_speed: '디씨모터 %1 방향 %2 속력 %3 %4', bitbrick_dc_speed: '디씨모터 %1 속도 %2 %3', bitbrick_turn_off_all_motors: '모든 모터 멈추기 %1', start_drawing: 'this.startDraw() %1', stop_drawing: 'this.stopDraw() %1', set_color: 'this.brush.color = %1 %2', set_random_color: 'this.brush.color = Entry.getRandomColor() %1', change_thickness: 'this.brush.thickness += %1 %2', set_thickness: 'this.brush.thickness = %1 %2', change_opacity: 'this.brush.opacity += %1 %2', set_opacity: 'this.brush.opacity = %1 %2', brush_erase_all: 'this.brush.removeAll() %1', brush_stamp: 'Stamp %1', change_brush_transparency: 'this.brush.opacity -= %1 %2', set_brush_tranparency: 'this.brush.opacity -= %1 %2', number: '%1', angle: '%1', color: '%1', get_x_coordinate: '%1', get_y_coordinate: '%1', get_angle: '%1', get_rotation_direction: '%1 ', distance_something: '%1 %2 %3', coordinate_mouse: '%1 %2 %3', coordinate_object: '%1 %2 %3 %4', calc_basic: '%1 %2 %3', calc_plus: '%1 %2 %3', calc_minus: '%1 %2 %3', calc_times: '%1 %2 %3', calc_divide: '%1 %2 %3', calc_mod: '%1 %2 %3 %4 %5', calc_share: '%1 %2 %3 %4 %5', calc_operation: '%1 %2 %3 %4 ', calc_rand: '%1 %2 %3 %4 %5', get_date: '%1 %2 %3', get_sound_duration: '%1 %2 %3', get_user_name: '사용자이름', reset_project_timer: '%1', set_visible_project_timer: '%1 %2 %3 %4', timer_variable: '%1 %2', get_project_timer_value: '%1 %2', char_at: '%1 %2 %3 %4 %5', length_of_string: '%1 %2 %3', substring: '%1 %2 %3 %4 %5 %6 %7', replace_string: '%1 %2 %3 %4 %5 %6 %7', change_string_case: '%1 %2 %3 %4 %5', index_of_string: '%1 %2 %3 %4 %5', combine_something: '%1 %2 %3 %4 %5', get_sound_volume: '%1 %2', quotient_and_mod: '%1 %2 %3 %4 %5 %6', choose_project_timer_action: '%1 %2 %3 %4', wait_second: 'Entry.wait( %1 ) %2', repeat_basic: 'for ( i = 0 %1 ) %2', hidden_loop: 'for ( i = 0 %1 ) %2', repeat_inf: 'while(true) %1', stop_repeat: 'break %1', wait_until_true: 'while ( %1 != true) { } %2', _if: 'if ( %1 ) %2', if_else: 'if ( %1 ) %2 %3 else', create_clone: 'Entry.createClone( %1 ) %2', delete_clone: 'Entry.removeClone(this) %1', when_clone_start: "%1 Entry.addEventListener('clone_created')", stop_run: '프로그램 끝내기 %1', repeat_while_true: 'Repeat %1 %2 %3', stop_object: 'Entry.stop( %1 ) %2', restart_project: 'Entry.restart() %1', remove_all_clones: 'Entry.removeAllClone() %1', functionAddButton: '%1', function_field_label: '%1%2', function_field_string: '%1%2', function_field_boolean: '%1%2', function_param_string: 'Character/Number', function_param_boolean: 'Judgement', function_create: 'define function %1 %2', function_general: 'function %1', expansionBlockAddButton: '%1', aiUtilizeBlockAddButton: '%1', aiUtilizeModelTrainButton: '%1', weather_title: '%1', check_weather: '%1 %2 의 날씨가 %3인가?', check_finedust: '현재 %1 의 미세먼지 등급이 %2인가?', get_weather_data: '%1 %2 의 %3', get_current_weather_data: '현재 %1 의 %2', get_today_temperature: '오늘 %1의 %2시 기온', check_city_weather: '%1 %2 %3의 날씨가 %4인가?', check_city_finedust: '현재 %1 %2 의 미세먼지 등급이 %3인가?', get_city_weather_data: '%1 %2 %3 의 %4', get_current_city_weather_data: '현재 %1 %2 의 %3', get_today_city_temperature: '오늘 %1 %2의 %3시 기온', translate_title: '%1', get_translated_string: '%1 %2 을(를) %3로 번역한 값', check_language: '%1의 언어', festival_title: '%1', count_festival: '%1 %2 행사의 수', get_festival_info: '%1 %2 행사 %3 번째 항목의 %4', behaviorConductDisaster_title: '%1', count_disaster_behavior: '%1 %2 해야할 행동요령 수', get_disaster_behavior: '자연재난%1 %2 해야할 행동요령 %3 번째 항목', behaviorConductLifeSafety_title: '%1', count_lifeSafety_behavior: '%1 에서 %2 방법의 수', get_lifeSafety_behavior: '%1 에서 %2 방법 %3 번째 항목', tts_title: '%1', audio_title: '%1', video_title: '%1', read_text: '%1 읽어주기 %2', set_tts_property: '%1 목소리를 %2 속도 %3 음높이로 설정하기 %4', read_text_wait_with_block: '%1 읽어주고 기다리기 %2', load_expansion_block: '확장 블록 불러오기', load_ai_utilize_block: 'AI 블록 불러오기', load_ai_utilize_train_block: '모델 학습', expansion_block_descriptions: '확장 블록은 인터넷이 연결되어 있어야 정상적으로 동작합니다.', aiUtilize_block_descriptions: 'AI 활용블록은 인터넷이 연결되어 있어야 정상적으로 동작합니다.', weather_title_text: '날씨', translate_title_text: '번역', festival_title_text: '행사', audio_title_text: '오디오 감지', check_microphone: '마이크가 연결되었는가?', get_microphone_volume: '마이크 소리크기', speech_to_text_convert: '음성 인식하기 %1', speech_to_text_get_value: '음성을 문자로 바꾼 값', video_title_text: '비디오 감지', video_draw_webcam: '비디오 화면 %1 %2', video_check_webcam: '비디오가 연결되었는가?', video_set_camera_opacity_option: '비디오 투명도 효과를 %1 으로 정하기 %2', video_flip_camera: '비디오 화면 %1 뒤집기 %2', video_toggle_model: '%1 인식 %2 %3', video_toggle_ind: '인식된 %1 %2 %3', video_number_detect: '인식된 %1 의 수', video_detected_face_info: '%1 번째 얼굴의 %2', video_motion_value: '%1 에서 감지한 %2 값', video_face_part_coord: '%1 번째 얼굴의 %2 의 %3 좌표', video_body_part_coord: '%1 번째 사람의 %2 의 %3 좌표', behaviorConductDisaster_title_text: '자연재난 국민행동요령', behaviorConductLifeSafety_title_text: '생활안전 국민행동요령', tts_title_text: '읽어주기', hamster_hand_found: 'Entry.Hamster.isHandFound()', hamster_value: '%1', hamster_move_forward_once: 'Entry.Hamster.moveForwardOnceOnBoard() %1', hamster_turn_once: "Entry.Hamster.turnOnceOnBoard(' %1 ') %2", hamster_move_forward_for_secs: 'Entry.Hamster.moveForwardForSecs( %1 ) %2', hamster_move_backward_for_secs: 'Entry.Hamster.moveBackwardForSecs( %1 ) %2', hamster_turn_for_secs: "Entry.Hamster.turnForSecs(' %1 ', %2 ) %3", hamster_change_both_wheels_by: 'Entry.Hamster.changeWheelsBy( %1, %2 ) %3', hamster_set_both_wheels_to: 'Entry.Hamster.setWheelsTo( %1, %2 ) %3', hamster_change_wheel_by: "Entry.Hamster.changeWheelsBy(' %1 ', %2 ) %3", hamster_set_wheel_to: "Entry.Hamster.setWheelsTo(' %1 ', %2 ) %3", hamster_follow_line_using: "Entry.Hamster.followLineUsingFloorSensor(' %1 ',' %2 ') %3", hamster_follow_line_until: "Entry.Hamster.followLineUntilIntersection(' %1 ',' %2 ') %3", hamster_set_following_speed_to: 'Entry.Hamster.setFollowingSpeedTo( %1 ) %2', hamster_stop: 'Entry.Hamster.stop() %1', hamster_set_led_to: "Entry.Hamster.setLedTo(' %1 ',' %2 ') %3", hamster_clear_led: "Entry.Hamster.clearLed(' %1 ') %2", hamster_beep: 'Entry.Hamster.beep() %1', hamster_change_buzzer_by: 'Entry.Hamster.changeBuzzerBy( %1 ) %2', hamster_set_buzzer_to: 'Entry.Hamster.setBuzzerTo( %1 ) %2', hamster_clear_buzzer: 'Entry.Hamster.clearBuzzer() %1', hamster_play_note_for: "Entry.Hamster.playNoteForBeats(' %1 ', %2 , %3 ) %4", hamster_rest_for: 'Entry.Hamster.restForBeats( %1 ) %2', hamster_change_tempo_by: 'Entry.Hamster.changeTempoBy( %1 ) %2', hamster_set_tempo_to: 'Entry.Hamster.setTempoTo( %1 ) %2', hamster_set_port_to: "Entry.Hamster.setPortTo(' %1 ',' %2 ') %3", hamster_change_output_by: "Entry.Hamster.changeOutputBy(' %1 ', %2 ) %3", hamster_set_output_to: "Entry.Hamster.setOutputTo(' %1 ', %2 ) %3", roboid_hamster_beep: '햄스터 %1: 삐 소리내기 %2', roboid_hamster_change_both_wheels_by: '햄스터 %1: 왼쪽 바퀴 %2 오른쪽 바퀴 %3 만큼 바꾸기 %4', roboid_hamster_change_buzzer_by: '햄스터 %1: 버저 음을 %2 만큼 바꾸기 %3', roboid_hamster_change_output_by: '햄스터 %1: 출력 %2 를 %3 만큼 바꾸기 %4', roboid_hamster_change_tempo_by: '햄스터 %1: 연주 속도를 %2 만큼 바꾸기 %3', roboid_hamster_change_wheel_by: '햄스터 %1: %2 바퀴 %3 만큼 바꾸기 %4', roboid_hamster_clear_buzzer: '햄스터 %1: 버저 끄기 %2', roboid_hamster_clear_led: '햄스터 %1: %2 LED 끄기 %3', roboid_hamster_follow_line_until: '햄스터 %1: %2 선을 따라 %3 교차로까지 이동하기 %4', roboid_hamster_follow_line_using: '햄스터 %1: %2 선을 %3 바닥 센서로 따라가기 %4', roboid_hamster_hand_found: '햄스터 %1: 손 찾음?', roboid_hamster_move_backward_for_secs: '햄스터 %1: 뒤로 %2 초 이동하기 %3', roboid_hamster_move_forward_for_secs: '햄스터 %1: 앞으로 %2 초 이동하기 %3', roboid_hamster_move_forward_once: '햄스터 %1: 말판 앞으로 한 칸 이동하기 %2', roboid_hamster_play_note_for: '햄스터 %1: %2 %3 음을 %4 박자 연주하기 %5', roboid_hamster_rest_for: '햄스터 %1: %2 박자 쉬기 %3', roboid_hamster_set_both_wheels_to: '햄스터 %1: 왼쪽 바퀴 %2 오른쪽 바퀴 %3 (으)로 정하기 %4', roboid_hamster_set_buzzer_to: '햄스터 %1: 버저 음을 %2 (으)로 정하기 %3', roboid_hamster_set_following_speed_to: '햄스터 %1: 선 따라가기 속도를 %2 (으)로 정하기 %3', roboid_hamster_set_led_to: '햄스터 %1: %2 LED를 %3 으로 정하기 %4', roboid_hamster_set_output_to: '햄스터 %1: 출력 %2 를 %3 (으)로 정하기 %4', roboid_hamster_set_port_to: '햄스터 %1: 포트 %2 를 %3 으로 정하기 %4', roboid_hamster_set_tempo_to: '햄스터 %1: 연주 속도를 %2 BPM으로 정하기 %3', roboid_hamster_set_wheel_to: '햄스터 %1: %2 바퀴 %3 (으)로 정하기 %4', roboid_hamster_stop: '햄스터 %1: 정지하기 %2', roboid_hamster_turn_for_secs: '햄스터 %1: %2 으로 %3 초 돌기 %4', roboid_hamster_turn_once: '햄스터 %1: 말판 %2 으로 한 번 돌기 %3', roboid_hamster_value: '햄스터 %1: %2', roboid_turtle_button_state: '거북이 %1: 버튼을 %2 ?', roboid_turtle_change_buzzer_by: '거북이 %1: 버저 음을 %2 만큼 바꾸기 %3', roboid_turtle_change_head_led_by_rgb: '거북이 %1: 머리 LED를 R: %2 G: %3 B: %4 만큼 바꾸기 %5', roboid_turtle_change_tempo_by: '거북이 %1: 연주 속도를 %2 만큼 바꾸기 %3', roboid_turtle_change_wheel_by: '거북이 %1: %2 바퀴 %3 만큼 바꾸기 %4', roboid_turtle_change_wheels_by_left_right: '거북이 %1: 왼쪽 바퀴 %2 오른쪽 바퀴 %3 만큼 바꾸기 %4', roboid_turtle_clear_head_led: '거북이 %1: 머리 LED 끄기 %2', roboid_turtle_clear_sound: '거북이 %1: 소리 끄기 %2', roboid_turtle_cross_intersection: '거북이 %1: 검은색 교차로 건너가기 %2', roboid_turtle_follow_line: '거북이 %1: %2 선을 따라가기 %3', roboid_turtle_follow_line_until: '거북이 %1: 검은색 선을 따라 %2 까지 이동하기 %3', roboid_turtle_follow_line_until_black: '거북이 %1: %2 선을 따라 검은색까지 이동하기 %3', roboid_turtle_is_color_pattern: '거북이 %1: 색깔 패턴이 %2 %3 인가?', roboid_turtle_move_backward_unit: '거북이 %1: 뒤로 %2 %3 이동하기 %4', roboid_turtle_move_forward_unit: '거북이 %1: 앞으로 %2 %3 이동하기 %4', roboid_turtle_pivot_around_wheel_unit_in_direction: '거북이 %1: %2 바퀴 중심으로 %3 %4 %5 방향으로 돌기 %6', roboid_turtle_play_note: '거북이 %1: %2 %3 음을 연주하기 %4', roboid_turtle_play_note_for_beats: '거북이 %1: %2 %3 음을 %4 박자 연주하기 %5', roboid_turtle_play_sound_times: '거북이 %1: %2 소리 %3 번 재생하기 %4', roboid_turtle_play_sound_times_until_done: '거북이 %1: %2 소리 %3 번 재생하고 기다리기 %4', roboid_turtle_rest_for_beats: '거북이 %1: %2 박자 쉬기 %3', roboid_turtle_set_buzzer_to: '거북이 %1: 버저 음을 %2 (으)로 정하기 %3', roboid_turtle_set_following_speed_to: '거북이 %1: 선 따라가기 속도를 %2 (으)로 정하기 %3', roboid_turtle_set_head_led_to: '거북이 %1: 머리 LED를 %2 으로 정하기 %3', roboid_turtle_set_head_led_to_rgb: '거북이 %1: 머리 LED를 R: %2 G: %3 B: %4 (으)로 정하기 %5', roboid_turtle_set_tempo_to: '거북이 %1: 연주 속도를 %2 BPM으로 정하기 %3', roboid_turtle_set_wheel_to: '거북이 %1: %2 바퀴 %3 (으)로 정하기 %4', roboid_turtle_set_wheels_to_left_right: '거북이 %1: 왼쪽 바퀴 %2 오른쪽 바퀴 %3 (으)로 정하기 %4', roboid_turtle_stop: '거북이 %1: 정지하기 %2', roboid_turtle_touching_color: '거북이 %1: %2 에 닿았는가?', roboid_turtle_turn_at_intersection: '거북이 %1: 검은색 교차로에서 %2 으로 돌기 %3', roboid_turtle_turn_unit_in_place: '거북이 %1: %2 으로 %3 %4 제자리 돌기 %5', roboid_turtle_turn_unit_with_radius_in_direction: '거북이 %1: %2 으로 %3 %4 반지름 %5 cm를 %6 방향으로 돌기 %7', roboid_turtle_value: '거북이 %1: %2', turtle_button_state: '버튼을 %1 ?', turtle_change_buzzer_by: '버저 음을 %1 만큼 바꾸기 %2', turtle_change_head_led_by_rgb: '머리 LED를 R: %1 G: %2 B: %3 만큼 바꾸기 %4', turtle_change_tempo_by: '연주 속도를 %1 만큼 바꾸기 %2', turtle_change_wheel_by: '%1 바퀴 %2 만큼 바꾸기 %3', turtle_change_wheels_by_left_right: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 만큼 바꾸기 %3', turtle_clear_head_led: '머리 LED 끄기 %1', turtle_clear_sound: '소리 끄기 %1', turtle_cross_intersection: '검은색 교차로 건너가기 %1', turtle_follow_line: '%1 선을 따라가기 %2', turtle_follow_line_until: '검은색 선을 따라 %1 까지 이동하기 %2', turtle_follow_line_until_black: '%1 선을 따라 검은색까지 이동하기 %2', turtle_is_color_pattern: '색깔 패턴이 %1 %2 인가?', turtle_move_backward_unit: '뒤로 %1 %2 이동하기 %3', turtle_move_forward_unit: '앞으로 %1 %2 이동하기 %3', turtle_pivot_around_wheel_unit_in_direction: '%1 바퀴 중심으로 %2 %3 %4 방향으로 돌기 %5', turtle_play_note: '%1 %2 음을 연주하기 %3', turtle_play_note_for_beats: '%1 %2 음을 %3 박자 연주하기 %4', turtle_play_sound_times: '%1 소리 %2 번 재생하기 %3', turtle_play_sound_times_until_done: '%1 소리 %2 번 재생하고 기다리기 %3', turtle_rest_for_beats: '%1 박자 쉬기 %2', turtle_set_buzzer_to: '버저 음을 %1 (으)로 정하기 %2', turtle_set_following_speed_to: '선 따라가기 속도를 %1 (으)로 정하기 %2', turtle_set_head_led_to: '머리 LED를 %1 으로 정하기 %2', turtle_set_head_led_to_rgb: '머리 LED를 R: %1 G: %2 B: %3 (으)로 정하기 %4', turtle_set_tempo_to: '연주 속도를 %1 BPM으로 정하기 %2', turtle_set_wheel_to: '%1 바퀴 %2 (으)로 정하기 %3', turtle_set_wheels_to_left_right: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 (으)로 정하기 %3', turtle_stop: '정지하기 %1', turtle_touching_color: '%1 에 닿았는가?', turtle_turn_at_intersection: '검은색 교차로에서 %1 으로 돌기 %2', turtle_turn_unit_in_place: '%1 으로 %2 %3 제자리 돌기 %4', turtle_turn_unit_with_radius_in_direction: '%1 으로 %2 %3 반지름 %4 cm를 %5 방향으로 돌기 %6', turtle_value: '%1', is_clicked: '%1', is_press_some_key: '%1 %2', reach_something: '%1 %2 %3', boolean_comparison: '%1 %2 %3', boolean_equal: '%1 %2 %3', boolean_bigger: '%1 %2 %3', boolean_smaller: '%1 %2 %3', boolean_and_or: '%1 %2 %3', boolean_and: '%1 %2 %3', boolean_or: '%1 %2 %3', boolean_not: '%1 %2 %3', true_or_false: '%1', True: '%1 ', False: '%1 ', boolean_basic_operator: '%1 %2 %3', show: 'this.show() %1', hide: 'this.hide() %1', dialog_time: 'this.setDialogByTime( %1 , %2 , %3 ) %4', dialog: 'this.setDialog( %1 , %2 ) %3', remove_dialog: 'this.removeDialog() %1', change_to_nth_shape: 'this.setShape( %1 ) %2', change_to_next_shape: 'this.setTo %1 Shape() %2', set_effect_volume: 'this.addEffect( %1 , %2 ) %3', set_effect: 'this.setEffect( %1 , %2 ) %3', erase_all_effects: 'this.removeAllEffects() %1', change_scale_percent: 'this.scale += %1 %2', set_scale_percent: 'this.scale = %1 %2', change_scale_size: 'this.scale += %1 %2', set_scale_size: 'this.scale = %1 %2', flip_y: "this.flip('horizontal') %1", flip_x: "this.flip('vertical') %1", set_object_order: 'Entry.setLayerOrder(this, %1 ) %2', get_pictures: '%1 ', change_to_some_shape: 'this.setShape( %1 ) %2', add_effect_amount: 'this.addEffect( %1 , %2 ) %3', change_effect_amount: 'this.setEffect( %1 , %2 ) %3', set_effect_amount: 'this.addEffect( %1 , %2 ) %3', set_entity_effect: 'this.setEffect( %1 , %2 ) %3', change_object_index: 'Entry.setLayerOrder(this, %1 ) %2', move_direction: 'Entry.moveToDirection( %1 ) %2', move_x: 'this.x += %1 %2', move_y: 'this.y += %1 %2', locate_xy_time: 'this.setXYbyTime( %1 , %2 , %3 ) %4', rotate_by_angle: 'this.rotation += %1 %2', rotate_by_angle_dropdown: '%1 만큼 회전하기 %2', see_angle: 'this.direction = %1 %2', see_direction: '%1 쪽 보기 %2', locate_xy: 'this.setXY( %1 , %2 ) %3', locate_x: 'this.x = %1 %2', locate_y: 'this.y = %1 %2', locate: 'this.locateAt( %1 ) %2', move_xy_time: 'this.moveXYbyTime( %1 , %2 , %3 ) %4', rotate_by_angle_time: 'this.rotateByTime( %1 , %2 ) %3', bounce_wall: 'Entry.bounceWall(this) %1', flip_arrow_horizontal: '화살표 방향 좌우 뒤집기 %1', flip_arrow_vertical: '화살표 방향 상하 뒤집기 %1', see_angle_object: 'this.setDirectionTo( %1 ) %2', see_angle_direction: 'this.rotation = %1 %2', rotate_direction: 'this.direction += %1 %2', locate_object_time: '%1 초 동안 %2 위치로 이동하기 %3', rotate_absolute: 'this.rotation = %1 %2', rotate_relative: 'this.rotation = %1 %2', direction_absolute: 'this.direction = %1 %2', direction_relative: 'this.direction += %1 %2', move_to_angle: 'Entry.moveToDirection( %1 , %2 ) %3', rotate_by_time: '%1 , this.rotate( %2 ) %3', direction_relative_duration: '%1 %2 %3', neobot_sensor_value: '%1 값', neobot_turn_left: '왼쪽모터를 %1 %2 회전 %3', neobot_stop_left: '왼쪽모터 정지 %1', neobot_turn_right: '오른쪽모터를 %1 %2 회전 %3', neobot_stop_right: '오른쪽모터 정지 %1', neobot_run_motor: '%1 모터를 %2 초간 %3 %4 %5', neobot_servo_1: 'SERVO1에 연결된 서보모터를 %1 속도로 %2 로 이동 %3', neobot_servo_2: 'SERVO2에 연결된 서보모터를 %1 속도로 %2 로 이동 %3', neobot_play_note_for: '멜로디 %1 을(를) %2 옥타브로 %3 길이만큼 소리내기 %4', neobot_set_sensor_value: '%1 번 포트의 값을 %2 %3', robotis_openCM70_cm_custom_value: '직접입력 주소 ( %1 ) %2 값', robotis_openCM70_sensor_value: '제어기 %1 값', robotis_openCM70_aux_sensor_value: '%1 %2 값', robotis_openCM70_cm_buzzer_index: '제어기 음계값 %1 , %2 , 연주 %3', robotis_openCM70_cm_buzzer_melody: '제어기 멜로디 %1 번 연주 %2', robotis_openCM70_cm_sound_detected_clear: '최종소리감지횟수 초기화 %1', robotis_openCM70_cm_led: '제어기 %1 LED %2 %3', robotis_openCM70_cm_motion: '모션 %1 번 실행 %2', robotis_openCM70_cm_autodrive_motor: '자율주행 자동차 %1모터를 %2 에 연결 %3', robotis_openCM70_cm_autodrive_ir: '자율주행 자동차 %1적외선센서를 %2 에 연결 %3', robotis_openCM70_cm_autodrive_speed: '차로를 따라 %1의 속도로 자율주행 %2', robotis_openCM70_aux_motor_speed: '%1 감속모터 속도를 %2, 출력값을 %3%로 정하기 %4', robotis_openCM70_aux_servo_mode: '%1 서보모터 모드를 %2 (으)로 정하기 %3', robotis_openCM70_aux_servo_speed: '%1 서보모터 속도를 %2, 출력값을 %3%로 정하기 %4', robotis_openCM70_aux_servo_position: '%1 서보모터 위치를 %2도로 정하기 %3', robotis_openCM70_aux_led_module: '%1 LED 모듈을 %2 (으)로 정하기 %3', robotis_openCM70_aux_custom: '%1 사용자 장치를 %2 (으)로 정하기 %3', robotis_openCM70_cm_poweroff_timer: '제어기 자동꺼짐 타이머 %1 %2', robotis_openCM70_cm_custom: '직접입력 주소 ( %1 ) (을)를 %2 (으)로 정하기 %3', robotis_carCont_sensor_value: '%1 값', robotis_carCont_cm_led: '4번 LED %1 , 1번 LED %2 %3', robotis_carCont_cm_sound_detected_clear: '최종소리감지횟수 초기화 %1', robotis_carCont_aux_motor_speed: '%1 감속모터 속도를 %2 , 출력값을 %3 (으)로 정하기 %4', robotis_carCont_cm_calibration: '%1 적외선 센서 캘리브레이션 값을 %2 (으)로 정하기 %3', roduino_get_analog_number: '%1 ', roduino_get_port_number: '%1 ', roduino_get_analog_value: '아날로그 %1 번 센서값 ', roduino_get_digital_value: '디지털 %1 번 센서값 ', roduino_set_digital: '디지털 %1 번 핀 %2 %3', roduino_motor: '%1 %2 %3', roduino_set_color_pin: '컬러센서 R : %1, G : %2, B : %3 %4', roduino_get_color: '컬러센서 %1 감지', roduino_on_block: ' On ', roduino_off_block: ' Off ', schoolkit_get_in_port_number: '%1 ', schoolkit_get_out_port_number: '%1 ', schoolkit_get_servo_port_number: '%1 ', schoolkit_get_input_value: '디지털 %1 번 센서값 ', schoolkit_set_output: '디지털 %1 번 핀 %2 %3', schoolkit_motor: '%1 속도 %2(으)로 %3 %4', schoolkit_set_servo_value: '서보모터 %1 번 핀 %2˚ %3', schoolkit_on_block: ' On ', schoolkit_off_block: ' Off ', when_scene_start: "%1 this.addEventListener('sceneStart')", start_scene: 'Scene.changeScene( %1 ) %2', start_neighbor_scene: 'Scene.changeScene( %1 ) %2', sound_something: 'Entry.playSound( %1 ) %2', sound_something_second: 'Entry.playSoundByTime( %1 , %2 ) %3', sound_something_wait: 'Entry.playSoundAndWait( %1 ) %2', sound_something_second_wait: 'Entry.playSoundAndWaitByTime( %1 , %2 ) %3', sound_volume_change: 'Entry.volume += %1 %2', sound_volume_set: 'Entry.volume = %1 %2', sound_silent_all: 'Entry.silentAll() %1', get_sounds: '%1 ', sound_something_with_block: 'Entry.playSound( %1 ) %2', sound_something_second_with_block: 'Entry.playSoundByTime( %1 , %2 ) %3', sound_something_wait_with_block: 'Entry.playSoundAndWait( %1 ) %2', sound_something_second_wait_with_block: 'Entry.playSoundAndWaitByTime( %1 , %2 ) %3', sound_from_to: '%1 %2 %3 %4', sound_from_to_and_wait: '%1 %2 %3 %4', when_run_button_click: "%1 Entry.addEventListener('run')", press_some_key: "%1 Entry.addEventListener('keydown', key== %2 ) %3", when_some_key_pressed: "%1 Entry.addEventListener('keydown', key== %2 )", mouse_clicked: "%1 Entry.addEventListener('mousedown')", mouse_click_cancled: "%1 Entry.addEventListener('mouseup')", when_object_click: "%1 this.addEventListener('mousedown')", when_object_click_canceled: "%1 this.addEventListener('mouseup')", when_some_key_click: '%1 키를 눌렀을 때', when_message_cast: '%1 Entry.addEventListener( %2 )', message_cast: 'Entry.dispatchEvent( %1 ) %2', message_cast_wait: 'Entry.dispatchEventAndWait( %1 ) %2', text: '%1', text_read: 'Entry.contents_of_textbox( %1 )', text_write: 'Entry.writeText( %1 ) %2', text_append: 'Entry.appendText( %1 ) %2', text_prepend: 'Entry.insertText( %1 ) %2', text_flush: 'Entry.clearText() %1', analizyDataAddButton: '%1', append_row_to_table: '테이블 %1에 %2 추가하기 %3', insert_row_to_table: '테이블 %1 %2번째에 %3 추가하기 %4', delete_row_from_table: '테이블 %1 %2번째 %3 삭제하기 %4', set_value_from_table: '테이블 %1 %2번째 행의 %3을(를) %4(으)로 바꾸기 %5', get_table_count: '테이블 %1의 %2개수', get_value_from_table: '테이블 %1 %2번째 행의 %3 값', calc_values_from_table: '테이블 %1 %2의 %3', open_table_chart: '테이블 %1의 차트 창 열기 %2', close_table_chart: '테이블 차트 창 닫기 %1', get_coefficient: '테이블 %1 %2과(와) %3의 상관계수', variableAddButton: '%1', listAddButton: '%1', change_variable: 'Entry.addValueToVariable( %1 , %2 ) %3', set_variable: 'Entry.setValueVariable( %1 , %2 ) %3', show_variable: 'Entry.showVariable( %1 ) %2', hide_variable: 'Entry.hideVariable( %1 ) %2', get_variable: 'Entry.getVariableValue( %1 )', ask_and_wait: 'Entry.askAndWait( %1 ) %2', get_canvas_input_value: '%1 ', add_value_to_list: 'Entry.pushValueToList( %1 , %2 ) %3', remove_value_from_list: 'Entry.removeValueListAt( %1 , %2 ) %3', insert_value_to_list: 'Entry.pushValueToListAt( %1 , %2 , %3 ) %4', change_value_list_index: 'Entry.changeValueListAt( %1 , %2 , %3 ) %4', value_of_index_from_list: '%1 %2 %3 %4 %5', length_of_list: '%1 %2 %3', show_list: 'Entry.showList( %1 ) %2', hide_list: 'Entry.hideList( %1 ) %2', options_for_list: '%1 ', set_visible_answer: 'Entry.getAnswer() %1 %2', is_included_in_list: '%1 %2 %3 %4 %5', xbot_digitalInput: '%1', xbot_analogValue: '%1', xbot_digitalOutput: '디지털 %1 핀, 출력 값 %2 %3', xbot_analogOutput: '아날로그 %1 %2 %3', xbot_servo: '서보 모터 %1 , 각도 %2 %3', xbot_oneWheel: '바퀴(DC) 모터 %1 , 속도 %2 %3', xbot_twoWheel: '바퀴(DC) 모터 오른쪽(2) 속도: %1 왼쪽(1) 속도: %2 %3', xbot_rgb: 'RGB LED 켜기 R 값 %1 G 값 %2 B 값 %3 %4', xbot_rgb_picker: 'RGB LED 색 %1 로 정하기 %2', xbot_buzzer: "Entry.Hamster.playNoteForBeats(' %1 %2 , %3 초 연주하기 %4", xbot_lcd: 'LCD %1 번째 줄 , 출력 값 %2 %3', run: '', mutant: 'test mutant block', jr_start: '%1', jr_repeat: '%1 %2 반복', jr_item: '꽃 모으기 %1', cparty_jr_item: '연필 줍기 %1', jr_north: ' 위쪽 %1', jr_east: '오른쪽 %1', jr_south: ' 아래쪽 %1', jr_west: ' 왼쪽 %1', jr_start_basic: '%1 %2', jr_go_straight: '앞으로 가기%1', jr_turn_left: '왼쪽으로 돌기%1', jr_turn_right: '오른쪽으로 돌기%1', jr_go_slow: '천천히 가기 %1', jr_repeat_until_dest: '%1 만날 때까지 반복하기 %2', jr_if_construction: '만약 %1 앞에 있다면 %2', jr_if_speed: '만약 %1 앞에 있다면 %2', maze_step_start: '%1 시작하기를 클릭했을 때', maze_step_jump: '뛰어넘기%1', maze_step_jump2: '뛰어넘기%1', maze_step_jump_pinkbean: '뛰어넘기%1', maze_step_for: '%1 번 반복하기%2', test: '%1 this is test block %2', maze_repeat_until_1: '%1 만날 때 까지 반복%2', maze_repeat_until_2: '모든 %1 만날 때 까지 반복%2', maze_step_if_1: '만약 앞에 %1 있다면%2', maze_step_if_2: '만약 앞에 %1 있다면%2', maze_call_function: '약속 불러오기%1', maze_define_function: '약속하기%1', maze_step_if_3: '만약 앞에 %1 있다면%2', maze_step_if_4: '만약 앞에 %1 있다면%2', maze_step_move_step: '앞으로 한 칸 이동%1', maze_step_rotate_left: '왼쪽으로 회전%1', maze_step_rotate_right: '오른쪽으로 회전%1', maze_step_forward: '앞으로 가기%1', maze_turn_right: '오른쪽 바라보기%1', maze_turn_left: '왼쪽 바라보기%1', maze_ladder_climb: '사다리 타기%1', maze_attack_lupin: '%1공격하기%2', maze_attack_both_side: '양옆 공격하기%1', maze_attack_pepe: '%1 공격하기%2', maze_attack_yeti: '%1 공격하기%2', maze_attack_mushroom: '%1 공격하기%2', maze_attack_peti: '%1 공격하기%2', maze_eat_item: '음식 먹기%1', maze_step_if_mushroom: '만약 한 칸 앞에 %1가 있다면 %2', maze_step_if_yeti: '만약 앞에 %1가 있다면 %2 %3 아니면', maze_step_if_left_monster: '만약 왼쪽 공격범위에 몬스터가 있다면 %1 %2 아니면', maze_step_if_right_monster: '만약 오른쪽 공격범위에 몬스터가 있다면 %1 %2 아니면', maze_step_if_lupin: '만약 두 칸 앞에 %1가 있다면 %2', maze_step_if_else_road: '만약 한 칸 앞에 길이 있다면 %1 %2아니면', maze_step_if_else_mushroom: '만약 한 칸 앞에 %1가 있다면 %2 %3아니면', maze_step_if_else_lupin: '만약 두 칸 앞에 %1가 있다면 %2 %3아니면', maze_step_if_else_ladder: '만약 한 칸 앞에 %1가 있다면 %2 %3아니면', maze_rotate_left: '왼쪽으로 돌기%1', maze_rotate_right: '오른쪽으로 돌기%1', maze_moon_kick: '발차기하기%1', maze_repeat_until_3: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_4: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_5: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_6: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_7: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_goal: '목적지에 도착할 때까지 반복하기%1', maze_repeat_until_beat_monster: '모든 몬스터를 혼내줄 때까지 반복하기%1', maze_radar_check: '%1에 %2이 있다', maze_cony_flower_throw: '꽃 던지기%1', maze_brown_punch: '주먹 날리기%1', maze_iron_switch: '장애물 조종하기%1', maze_james_heart: '하트 날리기%1', maze_step_if_5: '만약 앞에 길이 없다면%2', maze_step_if_6: '만약 앞에 %1이 없다면%2', maze_step_if_7: '만약 앞에 %1이 있다면%2', maze_step_if_8: '만약 %1이라면%2', maze_step_if_else: '만약 %1이라면%2 %3 아니면', test_wrapper: '%1 this is test block %2', basic_button: '%1', ai_move_right: '앞으로 가기 %1', ai_move_up: '위쪽으로 가기 %1', ai_move_down: '아래쪽으로 가기 %1', ai_repeat_until_reach: '목적지에 도달 할 때까지 반복하기 %1', ai_if_else_1: '만약 앞에 %1가 있다면 %2 %3 아니면', ai_boolean_distance: '%1 레이더 %2 %3', ai_distance_value: '%1 레이더', ai_boolean_object: '%1 물체는 %2 인가?', ai_use_item: '아이템 사용 %1', ai_boolean_and: '%1 %2 %3', ai_True: '%1', ai_if_else: 'if ( %1 ) %2 %3 else', smartBoard_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값', smartBoard_get_named_sensor_value: '%1 센서값', smartBoard_is_button_pressed: '%1 버튼을 눌렀는가?', smartBoard_set_dc_motor_direction: '%1 DC 모터를 %2 방향으로 정하기 %3', smartBoard_set_dc_motor_speed: '%1 DC모터를 %2 %3', smartBoard_set_dc_motor_pwm: '%1 DC모터를 %2 속도로 돌리기 %3', smartBoard_set_servo_speed: '%1 번 서보모터의 속도를 %2 %3', smartBoard_set_servo_angle: '%1 번 서보모터를 %2 도 로 움직이기 %3', smartBoard_set_number_eight_pin: '%1 포트를 %2 %3', smartBoard_set_gs1_pwm: 'GS1 포트의 PWM을 %1 로 정하기 %2', robotori_digitalInput: '%1', robotori_analogInput: '%1', robotori_digitalOutput: '디지털 %1 핀, 출력 값 %2 %3', robotori_analogOutput: '아날로그 %1 %2 %3', robotori_servo: '서보모터 각도 %1 %2', robotori_dc_direction: 'DC모터 %1 회전 %2 %3', dadublock_get_analog_value: '아날로그 %1 번 센서값', dadublock_get_analog_value_map: '아날로그 %1번 센서값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값', dadublock_get_ultrasonic_value: '울트라소닉 Trig %1번핀 Echo %2번핀 센서값', dadublock_toggle_led: '디지털 %1 번 핀 %2 %3', dadublock_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', dadublock_set_tone: '디지털 %1 번 핀을 %2 음으로 %3 옥타브로 %4 만큼 연주하기 %5', dadublock_set_servo: '서보모터 %1 번 핀을 %2 의 각도로 정하기 %3', coconut_stop_motor: '모터 정지 %1', coconut_move_motor: '%1 움직이기 %2', coconut_turn_motor: '%1 으로 돌기 %2', coconut_move_for_secs: '%1 %2 초동안 움직이기 %3', coconut_turn_for_secs: '%1 으로 %2 초동안 돌기 %3', coconut_turn_to_led: '%1 으로 회전하는 동안 %2LED 켜기 %3', coconut_move_outmotor: '외부모터 %1(으로) 움직이기 속도 %2 %3', coconut_set_led_to: '%1 LED를 %2 으로 켜기 %3', coconut_clear_led: '%1 LED 끄기 %2', coconut_set_led_clear: '%1 LED %2 끄기 %3', coconut_set_led_time: '%1 LED %2 으로 %3 초동안 켜기 %4', coconut_beep: '버저 켜기 %1', coconut_buzzer_time: '버저음을 %1 초 동안 소리내기 %2', coconut_buzzer_set_hz: '버즈음 %1 Hz를 %2초 동안 소리내기 %3', coconut_clear_buzzer: '버저 끄기 %1', coconut_play_buzzer: '%1 %2 %3 음을 %4 박자로 연주하기 %5', coconut_rest_buzzer: '%1 동안 쉬기 %2', coconut_play_buzzer_led: '%1 %2 %3 음을 %4 박자로 연주하는 동안 %5 LED %6 켜기 %7', coconut_play_midi: '%1 연주하기 %2', coconut_floor_sensor: '%1 바닥센서', coconut_floor_sensing: '%1 바닥센서 %2', coconut_following_line: '선 따라가기 %1', coconut_front_sensor: '%1 전방센서', coconut_front_sensing: '%1 전방센서 %2', coconut_obstruct_sensing: '장애물 감지', coconut_avoid_mode: '어보이드 모드 %1', coconut_dotmatrix_set: '도트매트릭스 %1 ( %2줄, %3칸 ) %4', coconut_dotmatrix_on: '도트매트릭스 모두 켜기 %1', coconut_dotmatrix_off: '도트매트릭스 모두 끄기 %1', coconut_dotmatrix_num: '도트매트릭스 숫자 %1표시 %2', coconut_dotmatrix_small_eng: '도트매트릭스 소문자 %1표시 %2', coconut_dotmatrix_big_eng: '도트매트릭스 대문자 %1표시 %2', coconut_dotmatrix_kor: '도트매트릭스 한글 %1표시 %2', coconut_light_sensor: '밝기', coconut_tem_sensor: '온도', coconut_ac_sensor: '%1 가속도', coconut_outled_sensor: '외부 LED 설정 %1 %2 초동안 켜기 %3', coconut_outspk_sensor: '외부 스피커 설정 %1 %2Hz로 %3초 동안 소리내기 %4', coconut_outspk_sensor_off: '외부 스피커 %1 끄기 %2', coconut_outinfrared_sensor: '외부 적외선센서 %1', coconut_outcds_sensor: '외부 빛센서(Cds) %1', coconut_servomotor_angle: '서보모터 연결 %1 각도 %2 %3', chocopi_control_button: '%1 컨트롤 %2번을 누름', chocopi_control_event: '%1 %2 컨트롤 %3을 %4', chocopi_control_joystick: '%1 컨트롤 %2의 값', chocopi_dc_motor: '%1 DC모터 %2 %3% 세기 %4 방향 %5', chocopi_led: '%1 LED %2 RGB(%3 %4 %5) %6', chocopi_motion_photogate_event: '%1 %2 포토게이트 %3번을 %4', chocopi_motion_photogate_status: '%1 포토게이트 %2번이 막힘', chocopi_motion_photogate_time: '%1 포토게이트%2번을 %3', chocopi_motion_value: '%1 모션 %2의 값', chocopi_sensor: '%1 센서 %2', chocopi_servo_motor: '%1 서보모터 %2번 %3도 %4', chocopi_touch_event: '%1 %2 터치 %3번을 %4', chocopi_touch_status: '%1 터치 %2번을 만짐', chocopi_touch_value: '%1 터치 %2번의 값', dadublock_car_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', dadublock_car_get_analog_value: '아날로그 %1 번 센서값', dadublock_car_get_analog_value_map: '아날로그 %1번 센서값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', dadublock_car_get_digital: '디지털 %1 번 센서값', dadublock_car_get_irsensor: '적외선 %1 번 센서값', dadublock_car_get_ultrasonic_value: '울트라소닉 Trig %1번핀 Echo %2번핀 센서값', dadublock_car_motor: '모터 %1 번을 %2 (으)로 %3 %의 속도로 움직이기 %4', dadublock_car_motor_stop: '모터 %1 번 멈추기 %2', dadublock_car_set_servo: '서보모터 %1 번 핀을 %2 의 각도로 정하기 %3', dadublock_car_set_tone: '디지털 %1 번 핀 을 %2 음으로 %3의 옥타브로 %4 만큼 연주하기 %5', dadublock_car_toggle_led: '디지털 %1 번 핀 %2 %3', dadublock_get_digital: '디지털 %1 번 센서값', ev3_get_sensor_value: '%1 의 값', ev3_touch_sensor: '%1 의 터치센서가 작동되었는가?', ev3_color_sensor: '%1 의 %2 값', ev3_motor_power: '%1 의 값을 %2 으로 출력 %3', ev3_motor_power_on_time: '%1 의 값을 %2 초 동안 %3 으로 출력 %4', ev3_motor_degrees: '%1 의 값을 %2 으로 %3 도 만큼 회전 %4', rokoboard_get_sensor_value_by_name: '%1 의 센서값', ardublock_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', ardublock_get_analog_value: '아날로그 %1 번 센서값', ardublock_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', ardublock_get_digital: '디지털 %1 번 센서값', ardublock_get_left_cds_analog_value: '왼쪽 조도센서 %1 센서값', ardublock_get_right_cds_analog_value: '오른쪽 조도센서 %1 센서값', ardublock_get_sound_analog_value: '사운드(소리) 센서 %1 센서값', ardublock_get_ultrasonic_value: '초음파센서 Trig %1 Echo %2 센서값', ardublock_set_left_motor: '왼쪽모터를 %1 으로 %2 회전 속도로 정하기 %3', ardublock_set_right_motor: '오른쪽모터를 %1 으로 %2 회전 속도로 정하기 %3', ardublock_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', ardublock_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', ardublock_toggle_led: '디지털 %1 번 핀 %2 %3', ardublock_toggle_left_led: '왼쪽 라이트 %1 번 핀 %2 %3', ardublock_toggle_right_led: '오른쪽 라이트 %1 번 핀 %2 %3', mkboard_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', mkboard_get_analog_value: '아날로그 %1 번 센서값', mkboard_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', mkboard_get_digital: '디지털 %1 번 센서값', mkboard_get_ultrasonic_value: '초음파센서 Trig %1 Echo %2 센서값', mkboard_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', mkboard_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', mkboard_toggle_led: '디지털 %1 번 핀 %2 %3', mkboard_set_lcd: '1602 문자 LCD %1 행 , %2열에 %3 출력하기 %4', mkboard_lcd_command: '1602 문자 LCD %1 명령실행하기 %2', altino_analogValue: '알티노 %1 센서값', altino_dot_display: '전광판에 %1 글자 표시하기 %2', altino_dot_display_line: '1열 %1 2열 %2 3열 %3 4열 %4 5열 %5 6열 %6 7열 %7 8열 %8 출력하기 %9', altino_light: '%1 등을 %2 %3', altino_rear_wheel: '뒷바퀴 오른쪽 %1 왼쪽 %2 로 정하기 %3', altino_sound: '%1 옥타브 %2 음을 연주하기 %3', altino_steering: '방향을 %1 로 정하기 %2', jdkit_altitude: '드론을 %1 높이만큼 날리기 %2', jdkit_button: '%1번 버튼 값 읽어오기', jdkit_connect: '드론 연결 상태 읽어오기', jdkit_emergency: '드론을 즉시 멈추기 %1', jdkit_gyro: '보드 %1 기울기 값 읽어오기', jdkit_joystick: '조이스틱 %1 읽기', jdkit_led: '%1 LED %2 %3', jdkit_motor: '%1 모터를 %2 세기로 돌리기 %3', jdkit_ready: '드론 비행 준비 상태 읽어오기', jdkit_rollpitch: '드론을 %1 방향 %2 세기로 움직이기 %3', jdkit_throttle: '드론 프로펠러를 %1 만큼 세기로 돌리기 %2', jdkit_tune: '%1 음을 %2 초동안 소리내기 %3', jdkit_ultrasonic: '거리(초음파)값 읽어오기', jdkit_yaw: '드론을 %1 만큼 회전하기 %2', memaker_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', memaker_get_analog_value: '아날로그 %1 번 센서값', memaker_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', memaker_get_digital: '디지털 %1 번 센서값', memaker_get_ultrasonic_value: '초음파센서 Trig %1 Echo %2 센서값', memaker_set_lcd: '1602 문자 LCD %1 행 , %2열에 %3 출력하기 %4', memaker_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', memaker_toggle_led: '디지털 %1 번 핀 %2 %3', memaker_lcd_command: '1602 문자 LCD %1 명령실행하기 %2', edumaker_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', edumaker_get_analog_value: '아날로그 %1 번 센서값', edumaker_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', edumaker_get_digital: '디지털 %1 번 센서값', edumaker_get_ultrasonic_value: '울트라소닉 Trig %1 Echo %2 센서값', edumaker_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', edumaker_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', edumaker_toggle_led: '디지털 %1 번 핀 %2 %3', creamo_get_number_sensor_value: '가변저항_블록 %1 번 센서값 ', creamo_get_port_number: '%1', creamo_get_pwm_port_number: '%1 ', creamo_motor_port_number: '%1', creamo_toggle_led: 'LED_블록 %1 번 핀 %2 %3', creamo_toggle_motor: 'Motor_블록 %1 번 핀 %2 %3', creamo_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', mechatro_get_dc_motor_current: '%1모터 사용전류값', mechatro_get_digital: '%1 디지털 값', mechatro_get_sensor_value: '%1 센서값', mechatro_get_ultrasonic_value: '초음파센서 Trig %1 Echo %2 의 거리값 [cm]', mechatro_set_blue_pw: '블루투스 비밀번호 : %1%2%3%4로 정하기%5', mechatro_set_dc_motor: '%1모터 속도 %2로 정하기%3', mechatro_set_digital: '%1번 %2 %3', mechatro_set_pwm: '%1PWM을 %2%로 정하기 %3', mechatro_set_servo_position: '%1서보모터 위치 :%2도로 옮기기 %3', mechatro_set_servo_speed: '%1서보모터 속도 : 1초당 %2도로 정하기 %3', mechatro_set_threshold: '%1 센서 감도 : %2로 정하기%3', mechatro_set_tone: '%1버저 %2 %3 음으로 연주 %4', mechatro_set_tone_time: '%1버저 %2 %3 음으로 %4 초 연주 %5', funboard_buzzer_onoff: '버저 %1 %2', funboard_buzzer_second: '버저%1%2초 동안%3', funboard_buzzer_tone_simple: '%1%2음을%3초 연주하기%4', funboard_color_led_on_pwm: '%1색 LED %2 % %3', funboard_color_led_onoff: '%1색 LED %2 %3', funboard_convert_scale: '%1값 %2~%3 에서 %4~%5 으로 변환값', funboard_dotmatrix_1column: '%1칸 %2표시하기 %3', funboard_dotmatrix_1row: '%1줄 %2표시하기 %3', funboard_dotmatrix_1row_1column: '%1%2 %3표시하기 %4', funboard_dotmatrix_64_display: '%1 (8x8)표시하기%2', funboard_dotmatrix_big_eng: '대문자 %1표시하기 %2', funboard_dotmatrix_char_display: '문자%1표시하기%2', funboard_dotmatrix_extra_char: '문자 %1표시하기 %2', funboard_dotmatrix_intensity: '밝기 %1% %2', funboard_dotmatrix_kor: '▦ 한글 %1표시하기 %2', funboard_dotmatrix_num: '숫자 %1표시하기 %2', funboard_dotmatrix_onoff: '모두 %1 %2', funboard_dotmatrix_scroll_option: '스크롤 방향%1%2', funboard_dotmatrix_scroll_rapid: '스크롤 속도 %1% %2', funboard_dotmatrix_set: '%1줄 %2칸 %3 %4', funboard_dotmatrix_small_eng: '소문자 %1표시하기 %2', funboard_dotmatrix_string_display: '문자열%1표시하기%2', funboard_dotmatrix_string_display_scroll: '문자열%1표시하기%2스크롤%3', funboard_dotmatrix_symbol: '기호 %1표시하기 %2', funboard_get_analog_sensor_2state: '%1값 %2', funboard_get_digital_button_value: '%1 버튼 값', funboard_get_number_sensor_value: '%1 값', funboard_get_touch_button_value: '%1 터치 값', funboard_set_digital_buzzer: '버저를 %1옥타브 %2음 %3초 연주%4', funboard_what_button_pressed: '%1 버튼 눌림', funboard_what_touch_button_pressed: '%1 터치됨', }; Lang.TextCoding = { block_name: '블록명', title_syntax: '문법오류 ', title_converting: '변환오류', message_syntax_default: '문법에 오류가 있습니다', message_syntax_unexpected_token: '문법에 맞지 않는 토큰이 포함되어 있습니다', message_syntax_reserved_token: '사용할 수 없는 변수명입니다.', message_syntax_reserved_token_list: '사용할 수 없는 리스트명입니다.', message_syntax_unexpected_character: '문법에 맞지 않는 문자가 포함되어 있습니다', message_syntax_unexpected_indent: '문법에 맞지 않는 띄어쓰기가 포함되어 있습니다', message_conv_default: '지원하지 않는 코드입니다', message_conv_no_support: '변환될 수 없는 코드입니다', message_conv_no_variable: '변수가 선언되지 않았습니다', message_conv_no_list: '리스트가 선언되지 않았습니다', message_conv_no_object: '객체는 지원되지 않습니다', message_conv_no_function: '함수가 변환될 수 없습니다', message_conv_no_entry_event_function: '엔트리 이벤트 함수는 다른 함수 안에 존재할 수 없습니다.', message_conv_undefined_function: '정의되지 않은 명령어 입니다. 명령어가 올바르게 입력되었는지 확인해주세요.', message_conv_is_expect1: '올바르지 않은 문법입니다. ', message_conv_is_expect2: ' 가 올바르게 입력되었는지 확인해주세요.', message_conv_instead: '올바르지 않은 문법입니다. %1 대신 %2 가 필요합니다.', message_conv_is_wrong1: '올바르지 않은 문법입니다. ', message_conv_is_wrong2: '(은/는) 올 수 없는 위치입니다.', message_conv_or: ' 나 ', subject_syntax_default: '기타', subject_syntax_token: '토큰', subject_syntax_character: '문자', subject_syntax_indent: '띄워쓰기', subject_conv_default: '기타', subject_conv_general: '일반', subject_conv_variable: '변수', subject_conv_list: '리스트', subject_conv_object: '객체', subject_conv_function: '함수', alert_variable_empty_text: '등록된 변수 중에 공백(띄어쓰기)이 포함된 변수가 있으면 모드 변환을 할 수 없습니다.', alert_list_empty_text: '등록된 리스트 중에 공백(띄어쓰기)이 포함된 리스트가 있으면 모드 변환을 할 수 없습니다.', alert_function_name_field_multi: '등록된 함수 중에 함수 이름에 [이름] 블록이 두번이상 포함되어 있으면 모드 변환을 할 수 없습니다.', alert_function_name_disorder: '등록된 함수 중에[이름] 블록이 [문자/숫자값] 또는 [판단값] 블록보다 뒤에 쓰이면 모드 변환을 할 수 없습니다.', alert_function_has_boolean: '엔트리파이선으로 변환 후 다시 블록코딩으로 모드로 변경하면 함수에 사용된 [판단값]은 모두 [문자/숫자형]으로 변환됩니다.', alert_function_editor: '함수 생성 및 편집 중에는 모드 변환을 할 수 없습니다.', alert_function_no_support: '텍스트모드에서는 함수 생성 및 편집을 할 수 없습니다.', alert_list_no_support: '텍스트모드에서는 리스트 생성 및 편집을 할 수 없습니다.', alert_variable_no_support: '텍스트모드에서는 변수 생성 및 편집을 할 수 없습니다.', alert_signal_no_support: '텍스트모드에서는 신호 생성 및 편집을 할 수 없습니다.', alert_legacy_no_support: '전환할 수 없는 블록이 존재하여 모드 변환을 할 수 없습니다.', alert_variable_empty_text_add_change: '변수명 공백(띄어쓰기)이 포함될 수 없습니다.', alert_list_empty_text_add_change: '리스트명에 공백(띄어쓰기)이 포함될 수 없습니다.', alert_list_contains_exceed_length_value: '리스트 항목에 15자리 이상의 수가 입력되어 있으면 모드 변환을 할 수 없습니다.', alert_function_name_empty_text_add_change: '함수명에 공백(띄어쓰기)이 포함될 수 없습니다.', alert_no_save_on_error: '문법 오류가 존재하여 작품을 저장할 수 없습니다.', alert_api_no_support: '작품에 엔트리파이썬에서 지원하지 않는 \n블록이 조립되어 있습니다. \n해당 블록을 삭제하고 만들기 모드를 변경할까요?', warn_unnecessary_arguments: '&(calleeName)(); 는 괄호 사이에 값이 입력될 필요가 없는 명령어 입니다. (line:&(lineNumber))', python_code: ' 오브젝트의 파이선 코드', eof: '줄바꿈', newline: '줄바꿈', indent: '들여쓰기', num: '숫자', string: '문자열', name: '변수명', }; Lang.PythonHelper = { when_run_button_click_desc: '[시작하기]버튼을 클릭하면 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_run_button_click_exampleCode: 'def when_start():\n Entry.print("안녕!")', when_run_button_click_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕!"이라 말합니다.', when_some_key_pressed_desc: 'A키를 누르면 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_some_key_pressed_elements: 'A-- 아래 선택지 중 하나
① 알파벳 : "A", "B" ~ "Z" 등(소문자 가능)
② 숫자 : 1, 2, 3, 4 ~ 9, 0
③ 특수키 : "space", "enter"
④ 방향키 : "up", "down", "right", "left"', when_some_key_pressed_exampleCode: 'def when_press_key("W"):\n Entry.move_to_direction(10)\n\ndef when_press_key(1):\n Entry.add_size(10)', when_some_key_pressed_exampleDesc: 'W키를 누르면 오브젝트가 이동방향으로 10만큼 이동하고, 1키를 누르면 오브젝트의 크기가 10만큼 커집니다.', mouse_clicked_desc: '마우스를 클릭했을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', mouse_clicked_exampleCode: 'def when_click_mouse_on():\n Entry.add_size(10)\n Entry.move_to_direction(10)', mouse_clicked_exampleDesc: '마우스를 클릭하면 오브젝트의 크기가 10만큼 커지면서 이동방향으로 10만큼 이동합니다.', mouse_click_cancled_desc: '마우스 클릭을 해제했을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', mouse_click_cancled_exampleCode: 'def when_click_mouse_off():\n Entry.move_to_direction(-10)\n\ndef when_click_mouse_on():\n Entry.move_to_direction(10)', mouse_click_cancled_exampleDesc: '마우스를 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 마우스 클릭을 해제하면 오브젝트가 이동방향으로 -10만큼 이동합니다.', when_object_click_desc: '해당 오브젝트를 클릭했을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_object_click_exampleCode: 'def when_click_object_on():\n Entry.print_for_sec("회전!", 0.5)\n Entry.add_rotation(90)', when_object_click_exampleDesc: '오브젝트를 클릭하면 오브젝트가 "회전!"이라 말하고, 90도 만큼 회전합니다.', when_object_click_canceled_desc: '해당 오브젝트 클릭을 해제했을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_object_click_canceled_exampleCode: 'def when_click_object_on():\n Entry.add_rotation(90)\n\ndef when_click_object_off():\n Entry.add_rotation(-90)', when_object_click_canceled_exampleDesc: '오브젝트를 클릭하면 오브젝트가 90도 만큼 회전하고, 오브젝트 클릭을 해제하면 오브젝트가 -90도 만큼 회전합니다.', when_message_cast_desc: 'A 신호를 받으면 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.
만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.', when_message_cast_elements: 'A-- "신호 이름"', when_message_cast_exampleCode: 'def when_click_mouse_on():\n Entry.send_signal("신호")\n\ndef when_get_signal("신호"):\n Entry.print_for_sec("안녕! 반가워", 0.5)', when_message_cast_exampleDesc: '마우스를 클릭하면 "신호"를 보내고, "신호"를 받았을때 "안녕! 반가워"라고 0.5초간 말합니다.', message_cast_desc: 'A에 입력된 신호를 보냅니다.
만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.', message_cast_elements: 'A-- "신호 이름"', message_cast_exampleCode: '#"오브젝트1"의 파이선 코드\ndef when_start():\n Entry.print_for_sec("안녕! 넌 몇살이니?", 2)\n Entry.send_signal("신호")\n\n#"오브젝트2"의 파이선 코드\ndef when_get_signal("신호"):\n Entry.print_for_sec("안녕? 난 세 살이야.", 2)', message_cast_exampleDesc: '[시작하기]버튼을 클릭하면 "오브젝트1"이 "안녕! 넌 몇살이니?"라고 2초간 말하고 "신호를 보냅니다., "오브젝트2"가 "신호"를 받았을때 "안녕? 난 세 살이야."라고 2초간 말합니다.', message_cast_wait_desc: 'A에 입력된 신호를 보내고, 해당 신호를 받는 명령어들의 실행이 끝날 때까지 기다립니다.
만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.', message_cast_wait_elements: 'A-- "신호 이름"', message_cast_wait_exampleCode: '#"오브젝트1"의 파이선 코드\ndef when_start():\n Entry.print_for_sec("숨바꼭질하자!", 2)\n Entry.send_signal_wait("신호")\n Entry.hide()\n\n#"오브젝트2"의 파이선 코드\ndef when_get_signal("신호"):\n Entry.print_for_sec("그래!", 2)', message_cast_wait_exampleDesc: '[시작하기]버튼을 클릭하면 "오브젝트1"이 "숨바꼭질하자!"라고 2초 동안 말하고 "신호"를 보낸 후 기다립니다. "오브젝트2"가 "신호"를 받으면 "그래!"를 2초 동안 말합니다. "오브젝트1"이 그 후에 모양을 숨깁니다.', when_scene_start_desc: '장면이 시작되면 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_scene_start_exampleCode: '#"장면 1"의 파이선 코드\ndef when_start():\n Entry.print_for_sec("다른 곳으로 가볼까?", 2)\n Entry.start_scene("장면 2")\n\n#"장면 2"의 파이선 코드\ndef when_start_scene():\n Entry.print("여기가 어디지?")', when_scene_start_exampleDesc: '"장면 1"에서 [시작하기]버튼을 클릭하면 "다른 곳으로 가볼까?"라고 2초간 말하고, "장면 2"가 시작됩니다. "장면 2"가 시작되면 오브젝트가 "여기가 어디지?"라고 말합니다.', start_scene_desc: 'A 장면을 시작합니다.', start_scene_elements: 'A-- "장면 이름"', start_scene_exampleCode: '#"장면 1"의 파이선 코드\ndef when_click_object_on():\n Entry.start_scene("장면 2")', start_scene_exampleDesc: '"장면 1"에서 해당 오브젝트를 클릭하면 "장면 2"가 시작됩니다.', start_neighbor_scene_desc: 'A에 입력한 다음 또는 이전 장면을 시작합니다.', start_neighbor_scene_elements: 'A-- 아래 선택지 중 하나
① 다음 장면: "next" 또는 "다음"
② 이전 장면: "prev" 또는 "이전"', start_neighbor_scene_exampleCode: '#"장면 1"의 파이선 코드\ndef when_press_key("right"):\n Entry.start_scene_of("next")\n\n#"장면 2"의 파이선 코드\ndef when_press_key("left"):\n Entry.start_scene_of("prev")', start_neighbor_scene_exampleDesc: '"장면 1"에서 오른쪽화살표키를 누르면 다음 장면이, "장면 2"에서 왼쪽화살표키를 누르면 이전 장면이 시작됩니다.', wait_second_desc: 'A초만큼 기다린 후 다음 블록을 실행합니다.', wait_second_elements: 'A-- 초에 해당하는 수 입력', wait_second_exampleCode: 'def when_start():\n Entry.add_effect("color", 10)\n Entry.wait_for_sec(2)\n Entry.add_size(10)', wait_second_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트에 색깔효과를 10만큼 주고, 2초동안 기다린 다음 크기를 10만큼 커지게 합니다.', repeat_basic_desc: '아래 명령어들을 A번 반복하여 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', repeat_basic_elements: 'A-- 반복할 횟수 입력', repeat_basic_exampleCode: 'def when_start():\n for i in range(10):\n Entry.move_to_direction(10)\n Entry.stamp()', repeat_basic_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 도장찍는 행동을 10번 반복합니다.', repeat_inf_desc: 'A 판단이 True인 동안 아래 명령어들을 반복 실행합니다. A에 True를 입력하면 계속 반복됩니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', repeat_inf_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', repeat_inf_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n Entry.bounce_on_edge()', repeat_inf_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 계속해서 이동방향으로 10만큼 이동하고, 벽에 닿으면 튕깁니다.', repeat_while_true_desc: 'A 판단이 True가 될 때까지 아래 명령어들을 반복 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', repeat_while_true_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', repeat_while_true_exampleCode: 'def when_start():\n while not Entry.is_key_pressed("space"):\n Entry.add_rotation(90)', repeat_while_true_exampleDesc: '[시작하기]버튼을 클릭하면 스페이스키를 누를때까지 오브젝트가 90도 만큼 회전합니다.', stop_repeat_desc: '이 명령어와 가장 가까운 반복 명령어의 반복을 중단합니다.', stop_repeat_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n if Entry.is_key_pressed("enter"):\n break', stop_repeat_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 계속 이동합니다. 엔터키를 누르면 반복이 중단됩니다.', _if_desc: 'A 부분의 판단이 True이면 if A:아래 명령어들을 실행하고, False이면 실행하지 않습니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', _if_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', _if_exampleCode: 'def when_click_mouse_on():\n if (Entry.value_of_mouse_pointer("x") > 0):\n Entry.print_for_sec("오른쪽!", 0.5)', _if_exampleDesc: '마우스를 클릭했을 때 마우스 x좌표가 0보다 크면 오브젝트가 "오른쪽!"이라고 0.5초 동안 말합니다.', if_else_desc: 'A 부분의 판단이 True이면 if A: 아래 명령어들을 실행하고, False이면 else: 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', if_else_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', if_else_exampleCode: 'def when_click_mouse_on():\n if Entry.is_touched("mouse_pointer"):\n Entry.print("닿았다!")\n else:\n Entry.print("안 닿았다!")', if_else_exampleDesc: '마우스를 클릭했을 때 마우스포인터가 오브젝트에 닿았으면 "닿았다!"를 그렇지 않으면 "안 닿았다!"를 말합니다.', wait_until_true_desc: 'A 부분의 판단이 True가 될 때까지 코드의 실행을 멈추고 기다립니다.', wait_until_true_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', wait_until_true_exampleCode: 'def when_start():\n Entry.print("엔터를 눌러봐!")\n Entry.wait_until(Entry.is_key_pressed("enter"))\n Entry.print("잘했어!")', wait_until_true_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "엔터를 눌러봐!"라 말하고, 엔터키를 누를 때까지 기다립니다. 엔터키를 누르면 "잘했어!"라 말합니다.', stop_object_desc: 'A코드의 실행을 중지합니다.', stop_object_elements: 'A-- 아래 선택지 중 하나
① "all": 모든 오브젝트의 모든 코드
② "self" : 해당 오브젝트의 모든 코드
③ "this": 이 명령어가 포함된 코드
④ "others" : 해당 오브젝트의 코드 중 이 명령어가 포함된 코드를 제외한 모든 코드
⑤ "ohter_objects" : 이 오브젝트를 제외한 다른 모든 오브젝트의 코드', stop_object_exampleCode: 'def when_start():\n while True:\n Entry.move_to("mouse_pointer")\n\ndef when_press_key("space"):\n Entry.stop_code("all")\n', stop_object_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 계속해서 마우스포인터 위치로 이동합니다. 스페이스키를 누르면 모든 코드의 실행이 중지됩니다.', restart_project_desc: '작품을 처음부터 다시 실행합니다.', restart_project_exampleCode: 'def when_start():\n while True:\n Entry.add_size(10)\n\ndef when_press_key("enter"):\n Entry.start_again()', restart_project_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트의 크기가 커집니다. 엔터키를 누르면 작품을 처음부터 다시 실행합니다.', when_clone_start_desc: '해당 오브젝트의 복제본이 새로 생성되었을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_clone_start_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("self")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))', when_clone_start_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다.', create_clone_desc: 'A 오브젝트의 복제본을 생성합니다.', create_clone_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "self" 또는 "자신"', create_clone_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("self")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))', create_clone_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다.', delete_clone_desc: 'Entry.make_clone_of(A) 명령에 의해 생성된 복제본을 삭제합니다.', delete_clone_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("자신")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))\n\ndef when_click_object_on():\n Entry.remove_this_clone()', delete_clone_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다. 복제본을 클릭하면 클릭된 복제본을 삭제합니다.', remove_all_clones_desc: '해당 오브젝트의 모든 복제본을 삭제합니다.', remove_all_clones_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("자신")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))\n\ndef when_press_key("space"):\n Entry.remove_all_clone()', remove_all_clones_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다. 스페이스 키를 누르면 모든 복제본을 삭제합니다.', move_direction_desc: 'A만큼 오브젝트의 이동방향 화살표가 가리키는 방향으로 움직입니다.', move_direction_elements: 'A-- 이동할 거리에 해당하는 수', move_direction_exampleCode: 'def when_start():\n Entry.move_to_direction(10)', move_direction_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동합니다.', bounce_wall_desc: '오브젝트가 화면 끝에 닿으면 튕겨져 나옵니다.', bounce_wall_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n Entry.bounce_on_edge()', bounce_wall_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 계속해서 이동방향으로 10만큼 이동하고, 벽에 닿으면 튕깁니다.', move_x_desc: '오브젝트의 x좌표를 A만큼 바꿉니다.', move_x_elements: 'A-- x좌표의 변화 값
① 양수: 오브젝트가 오른쪽으로 이동합니다.
② 음수: 오브젝트가 왼쪽으로 이동합니다.', move_x_exampleCode: 'def when_start():\n Entry.add_x(10)\n Entry.wait_for_sec(2)\n Entry.add_x(-10)', move_x_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오른쪽으로 10만큼 이동하고 2초 동안 기다린 후 왼쪽으로 10만큼 이동합니다.', move_y_desc: '오브젝트의 y좌표를 A만큼 바꿉니다.', move_y_elements: 'A-- y좌표의 변화 값
① 양수: 오브젝트가 위쪽으로 이동합니다.
② 음수: 오브젝트가 아래쪽으로 이동합니다.', move_y_exampleCode: 'def when_start():\n Entry.add_y(10)\n Entry.wait_for_sec(2)\n Entry.add_y(-10)', move_y_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 위쪽으로 10만큼 이동하고 2초 동안 기다린 후 아래쪽으로 10만큼 이동합니다.', move_xy_time_desc: '오브젝트가 x와 y좌표를 각각 A와 B만큼 C초에 걸쳐 서서히 바꿉니다.', move_xy_time_elements: 'A-- x좌표의 변화 값
① 양수: 오브젝트가 오른쪽으로 이동합니다.
② 음수: 오브젝트가 왼쪽으로 이동합니다.%nextB-- y좌표의 변화 값
① 양수: 오브젝트가 위쪽으로 이동합니다.
② 음수: 오브젝트가 아래쪽으로 이동합니다.%nextC-- 이동하는 시간(초)', move_xy_time_exampleCode: 'def when_start():\n Entry.add_xy_for_sec(100, 100, 2)\n Entry.add_xy_for_sec(-100, -100, 2)', move_xy_time_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오른쪽 위로 100만큼 2초 동안 이동한 후 왼쪽 아래로 100만큼 2초 동안 이동합니다.', locate_x_desc: '오브젝트의 x좌표를 A로 정합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_x_elements: 'A-- 이동할 x좌표', locate_x_exampleCode: 'def when_press_key("right"):\n Entry.set_x(100)\n\ndef when_press_key("left"):\n Entry.set_x(-100)\n', locate_x_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 x좌표를 100으로 정하고, 왼쪽화살표키를 누르면 오브젝트의 x좌표를 -100으로 정합니다.', locate_y_desc: '오브젝트의 y좌표를 A로 정합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_y_elements: 'B-- 이동할 y좌표', locate_y_exampleCode: 'def when_press_key("up"):\n Entry.set_y(100)\n\ndef when_press_key("down"):\n Entry.set_y(-100)', locate_y_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 y좌표를 100으로 정하고, 아래쪽화살표키를 누르면 오브젝트의 y좌표를 -100으로 정합니다.', locate_xy_desc: '오브젝트가 좌표(A, B)로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_xy_elements: 'A-- 이동할 x좌표%nextB-- 이동할 y좌표', locate_xy_exampleCode: 'def when_click_mouse_on():\n Entry.set_xy(0, 0)\n\ndef when_press_key("right"):\n Entry.add_x(10)\n\ndef when_press_key("up"):\n Entry.add_y(10)', locate_xy_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 x좌표를 10만큼 바꾸고, 위쪽화살표키를 누르면 오브젝트의 y좌표를 10만큼 바꿉니다. 마우스를 클릭하면 오브젝트의 x, y좌표를 0으로 정합니다.', locate_xy_time_desc: '오브젝트가 좌표(A, B)로 C초에 걸쳐 서서히 이동합니다.(오브젝트의 중심점이 기준이 됩니다.)', locate_xy_time_elements: 'A-- 이동할 x좌표%nextB-- 이동할 y좌표%nextC-- 이동하는 시간', locate_xy_time_exampleCode: 'def when_click_mouse_on():\n Entry.set_xy_for_sec(0, 0, 2)\n\ndef when_press_key("right"):\n Entry.add_x(10)\n\ndef when_press_key("up"):\n Entry.add_y(10)', locate_xy_time_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 x좌표를 10만큼 바꾸고, 위쪽화살표키를 누르면 오브젝트의 y좌표를 10만큼 바꿉니다. 마우스를 클릭하면 2초 동안 오브젝트를 x,y 좌표 0으로 이동시킵니다.', locate_desc: '오브젝트가 A의 위치로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "mouse_pointer" 또는 "마우스포인터"', locate_exampleCode: 'def when_click_mouse_on():\n Entry.move_to("mouse_pointer")\n\ndef when_press_key("space"):\n Entry.move_to("오브젝트")', locate_exampleDesc: '마우스를 클릭하면 오브젝트가 마우스포인터 위치로 이동합니다.
스페이스키를 누르면 오브젝트가 "오브젝트" 위치로 이동합니다.', locate_object_time_desc: '오브젝트가 A의 위치로 B초에 걸쳐 서서히 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_object_time_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "mouse_pointer" 또는 "마우스포인터" %nextB-- 이동하는 시간(초)', locate_object_time_exampleCode: 'def when_click_mouse_on():\n Entry.move_to_for_sec("mouse_pointer", 2)', locate_object_time_exampleDesc: '마우스를 클릭하면 오브젝트가 2초 동안 서서히 마우스포인터 위치로 이동합니다.', rotate_relative_desc: '오브젝트의 방향을 A도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', rotate_relative_elements: 'A-- 회전할 각도', rotate_relative_exampleCode: 'def when_click_object_on():\n Entry.add_rotation(90)\n\ndef when_click_object_off():\n Entry.add_rotation(-90)', rotate_relative_exampleDesc: '오브젝트를 클릭하면 오브젝트가 90도 만큼 회전하고, 오브젝트 클릭을 해제하면 오브젝트가 -90도 만큼 회전합니다.', direction_relative_desc: '오브젝트의 이동 방향을 A도만큼 회전합니다.', direction_relative_elements: 'A-- 회전할 각도', direction_relative_exampleCode: 'def when_start():\n Entry.move_to_direction(50)\n Entry.wait_for_sec(0.5)\n Entry.add_direction(90)\n Entry.wait_for_sec(0.5)\n Entry.move_to_direction(50)', direction_relative_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 50만큼 이동한 다음 0.5초간 기다립니다. 그 후 이동방향을 90도 만큼 회전하고 0.5초간 기다린 후 이동방향으로 50만큼 이동합니다.', rotate_by_time_desc: '오브젝트의 방향을 시계방향으로 A도만큼 B초에 걸쳐 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', rotate_by_time_elements: 'A-- 회전할 각도%nextB-- 회전할 시간(초)', rotate_by_time_exampleCode: 'def when_start():\n Entry.add_rotation_for_sec(90, 2)\n Entry.add_rotation_for_sec(-90, 2)', rotate_by_time_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 2초 동안 90도 만큼 회전하고, 다시 2초 동안 -90도 만큼 회전합니다.', direction_relative_duration_desc: '오브젝트의 이동방향을 시계방향으로 A도만큼 B초에 걸쳐 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', direction_relative_duration_elements: 'A-- 회전할 각도%nextB-- 회전할 시간(초)', direction_relative_duration_exampleCode: 'def when_start():\n Entry.add_direction_for_sec(90, 2)\n\ndef when_start():\n while True:\n Entry.move_to_direction(1)', direction_relative_duration_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트의 이동방향을 2초 동안 90도만큼 회전시킵니다. 동시에 오브젝트는 이동방향으로 1만큼 계속 이동합니다.', rotate_absolute_desc: '오브젝트의 방향을 A로 정합니다.', rotate_absolute_elements: 'A-- 설정할 방향', rotate_absolute_exampleCode: 'def when_press_key("right"):\n Entry.set_rotation(90)\n\ndef when_press_key("left"):\n Entry.set_rotation(270)', rotate_absolute_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 방향을 90으로 정하고, 왼쪽화살표키를 누르면 오브젝트의 방향을 270으로 정합니다.', direction_absolute_desc: '오브젝트의 이동방향을 A로 정합니다.', direction_absolute_elements: 'A-- 설정할 이동방향', direction_absolute_exampleCode: 'def when_press_key("right"):\n Entry.set_direction(90)\n Entry.move_to_direction(10)\n\ndef when_press_key("left"):\n Entry.set_direction(270)\n Entry.move_to_direction(10)', direction_absolute_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 이동방향을 90으로 정한 후 해당 쪽으로 10만큼 이동하고, 왼쪽화살표키를 누르면 오브젝트의 이동방향을 270으로 정하고 해당쪽으로 10만큼 이동합니다.', see_angle_object_desc: '오브젝트가 A쪽을 바라봅니다. (이동방향이 A를 향하도록 오브젝트의 방향을 회전해줍니다.)', see_angle_object_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "mouse_pointer" 또는 "마우스포인터"', see_angle_object_exampleCode: 'def when_click_mouse_on():\n Entry.look_at("mouse_pointer")\n\ndef when_press_key("space"):\n Entry.look_at("오브젝트")', see_angle_object_exampleDesc: '마우스를 클릭하면 오브젝트가 마우스포인터쪽을 바라보고, 스페이스키를 누르면 "오브젝트"쪽을 바라봅니다.', move_to_angle_desc: '오브젝트가 A만큼 B방향으로 움직입니다.', move_to_angle_elements: 'A-- 이동할 거리에 해당하는 수%nextB-- 이동할 방향(12시 방향이 0도, 시계방향으로 증가)', move_to_angle_exampleCode: 'def when_press_key("up"):\n Entry.move_to_degree(10, 0)\n\ndef when_press_key("down"):\n Entry.move_to_degree(10, 180)', move_to_angle_exampleDesc: '위쪽화살표키를 누르면 오브젝트가 0도방향으로 10만큼 이동하고, 아래쪽화살표키를 누르면 오브젝트가 180도방향으로 10만큼 이동합니다.', show_desc: '오브젝트를 화면에 나타냅니다.', show_exampleCode: 'def when_start():\n Entry.wait_for_sec(1)\n Entry.hide()\n Entry.wait_for_sec(1)\n Entry.show()', show_exampleDesc: '[시작하기]버튼을 클릭하면 1초 뒤에 오브젝트 모양이 숨겨지고, 다음 1초 뒤에 오브젝트 모양이 나타납니다.', hide_desc: '오브젝트를 화면에서 보이지 않게 합니다.', hide_exampleCode: 'def when_start():\n Entry.wait_for_sec(1)\n Entry.hide()\n Entry.wait_for_sec(1)\n Entry.show()', hide_exampleDesc: '[시작하기]버튼을 클릭하면 1초 뒤에 오브젝트 모양이 숨겨지고, 다음 1초 뒤에 오브젝트 모양이 나타납니다.', dialog_time_desc: '오브젝트가 A를 B초 동안 말풍선으로 말한 후 다음 명령어가 실행됩니다. 콘솔창에서도 실행 결과를 볼 수 있습니다.', dialog_time_elements: 'A-- 말할 내용
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등%nextB-- 말하는 시간(초)', dialog_time_exampleCode: 'def when_start():\n Entry.print_for_sec("안녕! 나는", 2)\n Entry.print_for_sec(16, 2)\n Entry.print_for_sec("살이야", 2)', dialog_time_exampleDesc: '[시작하기]버튼을 클릭하면 "안녕! 나는", 16, "살이야"를 각각 2초 동안 차례대로 말합니다.', dialog_desc: '오브젝트가 A를 말풍선으로 말합니다. 콘솔창에서도 실행 결과를 볼 수 있습니다.', dialog_elements: 'A-- 말할 내용
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', dialog_exampleCode: 'def when_start():\n Entry.print("키보드로 숫자 1,2 를 누르면 숫자를 말해볼게")\n\ndef when_press_key(1):\n Entry.print(1)\n\ndef when_press_key(2):\n Entry.print(2)\n', dialog_exampleDesc: '[시작하기]버튼을 클릭하면 "키보드로 숫자 1,2 를 누르면 숫자를 말해볼게"를 말하고, 키보드로 1, 2를 누르면 각각 1, 2라 말합니다.', remove_dialog_desc: '오브젝트가 말하고 있는 말풍선을 지웁니다.', remove_dialog_exampleCode: 'def when_start():\n Entry.print("말풍선을 지우려면 엔터를 눌러!")\n\ndef when_press_key("enter"):\n Entry.clear_print()', remove_dialog_exampleDesc: '[시작하기]버튼을 클릭하면 "말풍선을 지우려면 엔터를 눌러!"라 말하고, 엔터키를 누르면 말풍선이 사라집니다.', change_to_some_shape_desc: '오브젝트를 A 모양으로 바꿉니다.', change_to_some_shape_elements: 'A-- 아래 선택지 중 하나
① 모양 이름 : [속성] 탭의 "모양 이름"을 적음
② 모양 번호 : [속성] 탭의 모양 번호를 적음', change_to_some_shape_exampleCode: 'def when_start():\n Entry.wait_for_sec(0.3)\n Entry.change_shape("오브젝트모양")\n Entry.wait_for_sec(0.3)\n Entry.change_shape("오브젝트모양")', change_to_some_shape_exampleDesc: '[시작하기]버튼을 클릭하면 0.3초간 기다린 다음 "오브젝트모양"으로 모양을 바꾸고 0.3초간 기다린 다음 "오브젝트모양"모양으로 모양을 바꿉니다.', change_to_next_shape_desc: '오브젝트의 모양을 다음 또는 이전 모양으로 바꿉니다.', change_to_next_shape_elements: 'A-- 아래 선택지 중 하나
① 다음 모양 : "next" 또는 "다음"
② 이전 모양 : "pre" 또는 "이전"', change_to_next_shape_exampleCode: 'def when_start():\n Entry.wait_for_sec(0.3)\n Entry.change_shape_to("next")\n Entry.wait_for_sec(0.3)\n Entry.change_shape_to("pre")', change_to_next_shape_exampleDesc: '[시작하기]버튼을 클릭하면 0.3초간 기다린 다음 모양으로 오브젝트 모양을 바꾸고 0.3초간 기다린 다음 이전 모양으로 오브젝트 모양을 바꿉니다.', add_effect_amount_desc: '오브젝트에 A 효과를 B만큼 줍니다.', add_effect_amount_elements: 'A -- 아래 선택지 중 하나
① “color” 또는 “색깔“
② “brightness” 또는 “밝기”
③ “transparency” 또는 “투명도”%nextB-- 효과의 변화 정도', add_effect_amount_exampleCode: 'def when_click_mouse_on():\n Entry.add_effect("color", 50)\n Entry.wait_for_sec(1)\n Entry.add_effect("brightness", -50)\n Entry.wait_for_sec(1)\n Entry.add_effect("transparency", 50)', add_effect_amount_exampleDesc: '마우스를 클릭하면 오브젝트에 색깔 효과를 50만큼 주고 1초간 기다리고, 밝기 효과를 -50만큼 주고 1초간 기다립니다. 그 후 투명도 효과를 50만큼 줍니다.', change_effect_amount_desc: '오브젝트의 A 효과를 B로 정합니다.', change_effect_amount_elements: 'A-- 아래 선택지 중 하나
① “color” 또는 “색깔“
② “brightness” 또는 “밝기”
③ “transparency” 또는 “투명도”%nextB-- 효과의 값
① color: 0~100 범위의 수, 100을 주기로 반복됨
② brightness: -100~100 사이 범위의 수, -100이하는 -100 으로 100 이상은 100 으로 처리 됨
③ transparency: 0~100 사이 범위의 수, 0 이하는 0으로, 100이상은 100으로 처리 됨', change_effect_amount_exampleCode: 'def when_click_mouse_on():\n Entry.set_effect("color", 50)\n Entry.set_effect("brightness", 50)\n Entry.set_effect("transparency", 50)\n\ndef when_click_mouse_off():\n Entry.set_effect("color", 0)\n Entry.set_effect("brightness", 0)\n Entry.set_effect("transparency", 0)', change_effect_amount_exampleDesc: '마우스를 클릭하면 오브젝트에 색깔, 밝기, 투명도 효과를 50으로 정하고, 마우스 클릭을 해제하면 각 효과를 0으로 정합니다.', erase_all_effects_desc: '오브젝트에 적용된 효과를 모두 지웁니다.', erase_all_effects_exampleCode: 'def when_click_mouse_on():\n Entry.set_effect("color", 50)\n Entry.set_effect("brightness", 50)\n Entry.set_effect("transparency", 50)\n\ndef when_click_mouse_off():\n Entry.clear_effect()\n', erase_all_effects_exampleDesc: '마우스를 클릭하면 오브젝트에 색깔, 밝기, 투명도 효과를 50으로 정하고, 마우스 클릭을 해제하면 오브젝트에 적용된 모든 효과를 지웁니다.', change_scale_size_desc: '오브젝트의 크기를 A만큼 바꿉니다.', change_scale_size_elements: 'A-- 크기 변화 값', change_scale_size_exampleCode: 'def when_press_key("up"):\n Entry.add_size(10)\n\ndef when_press_key("down"):\n Entry.add_size(-10)\n\ndef when_press_key("space"):\n Entry.set_size(100)', change_scale_size_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 크기가 10만큼 커지고, 아래쪽화살표키를 누르면 오브젝트의 크기가 10만큼 작아집니다. 스페이스키를 누르면 오브젝트의 크기를 100으로 정합니다.', set_scale_size_desc: '오브젝트의 크기를 A로 정합니다.', set_scale_size_elements: 'A-- 크기값', set_scale_size_exampleCode: 'def when_press_key("up"):\n Entry.add_size(10)\n\ndef when_press_key("down"):\n Entry.add_size(-10)\n\ndef when_press_key("space"):\n Entry.set_size(100)', set_scale_size_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 크기가 10만큼 커지고, 아래쪽화살표키를 누르면 오브젝트의 크기가 10만큼 작아집니다. 스페이스키를 누르면 오브젝트의 크기를 100으로 정합니다.', flip_x_desc: '오브젝트의 상하 모양을 뒤집습니다.', flip_x_exampleCode: 'def when_press_key("up"):\n Entry.flip_horizontal()\n\ndef when_press_key("right"):\n Entry.flip_vertical()', flip_x_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 상하 모양을 뒤집고, 오른쪽화살표키를 누르면 오브젝트의 좌우 모양을 뒤집습니다.', flip_y_desc: '오브젝트의 좌우 모양을 뒤집습니다.', flip_y_exampleCode: 'def when_press_key("up"):\n Entry.flip_horizontal()\n\ndef when_press_key("right"):\n Entry.flip_vertical()', flip_y_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 상하 모양을 뒤집고, 오른쪽화살표키를 누르면 오브젝트의 좌우 모양을 뒤집습니다.', change_object_index_desc: '오브젝트의 레이어를 A로 가져옵니다.', change_object_index_elements: 'A-- 아래 선택지 중 하나
① “front" 또는 “맨 앞“
② “forward” 또는 “앞”
③ “backward” 또는 “뒤”
④ “back” 또는 “맨 뒤”', change_object_index_exampleCode: 'def when_start():\n Entry.send_layer_to("front")\n Entry.wait_for_sec(2)\n Entry.send_layer_to("backward")', change_object_index_exampleDesc: '오브젝트가 여러개가 겹쳐 있을 경우 [시작하기]버튼을 클릭하면 해당 오브젝트의 레이어를 가장 앞으로 가져와서 보여줍니다.', brush_stamp_desc: '오브젝트의 모양을 도장처럼 실행화면 위에 찍습니다.', brush_stamp_exampleCode: 'def when_start():\n for i in range(10):\n Entry.move_to_direction(10)\n Entry.stamp()', brush_stamp_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 도장찍는 행동을 10번 반복합니다.', start_drawing_desc: '오브젝트가 이동하는 경로를 따라 선이 그려지기 시작합니다. (오브젝트의 중심점이 기준)', start_drawing_exampleCode: 'def when_start():\n Entry.start_drawing()\n for i in range(10):\n Entry.move_to_direction(10)', start_drawing_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 오브젝트가 이동방향으로 10만큼 10번 이동할 때 오브젝트의 이동경로를 따라 선이 그려집니다.', stop_drawing_desc: '오브젝트가 선을 그리는 것을 멈춥니다.', stop_drawing_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(1)\n\ndef when_click_mouse_on():\n Entry.stop_drawing()', stop_drawing_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고 계속해서 오브젝트가 이동방향으로 10만큼 이동합니다. 마우스를 클릭하면 그리는것을 멈춥니다.', set_color_desc: '오브젝트가 그리는 선의 색을 A로 정합니다.', set_color_elements: 'A-- 아래 선택지 중 하나
① 색상 코드 : "#FF0000", "#FFCC00", "#3333FF", "#000000" 등
② 색깔명 : "red", "orange", "yellow", "green", "blue", "navy", "purple", "black", "white", "brown"', set_color_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_color_to("#000099")\n while True:\n Entry.move_to_direction(1)', set_color_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 색을 "#000099"로 정합니다. 오브젝트는 계속해서 이동방향으로 1만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.', set_random_color_desc: '오브젝트가 그리는 선의 색을 무작위로 정합니다.', set_random_color_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(1)\n Entry.set_brush_color_to_random()', set_random_color_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 1만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 색깔은 계속해서 무작위로 정해집니다.', change_thickness_desc: '오브젝트가 그리는 선의 굵기를 A만큼 바꿉니다.', change_thickness_elements: 'A-- 굵기 변화 값', change_thickness_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.add_brush_size(1)\n Entry.move_to_direction(10)', change_thickness_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 굵기는 계속해서 1씩 커집니다.', set_thickness_desc: '오브젝트가 그리는 선의 굵기를 A로 정합니다.', set_thickness_elements: 'A-- 굵기값(1이상의 수)', set_thickness_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n while True:\n Entry.move_to_direction(10)', set_thickness_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.', change_brush_transparency_desc: '오브젝트가 그리는 선의 투명도를 A만큼 바꿉니다.', change_brush_transparency_elements: 'A-- 투명도 변화 값', change_brush_transparency_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n while True:\n Entry.move_to_direction(10)\n Entry.add_brush_transparency(5)', change_brush_transparency_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 투명도는 계속해서 5만큼 바꿉니다.', set_brush_tranparency_desc: '오브젝트가 그리는 선의 투명도를 A로 정합니다.', set_brush_tranparency_elements: 'A-- 투명도값(0~100 의 범위)', set_brush_tranparency_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n Entry.set_brush_transparency(50)\n while True:\n Entry.move_to_direction(10)', set_brush_tranparency_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로, 선의 투명도를 50으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.', brush_erase_all_desc: '오브젝트가 그린 선과 도장을 모두 지웁니다.', brush_erase_all_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(10)\n\ndef when_click_mouse_on():\n Entry.clear_drawing()', brush_erase_all_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 마우스를 클릭하면 오브젝트가 그린 선을 모두 지웁니다.', text_read_desc: '글상자 A의 내용입니다.
(내용 안에 개행이 있는 경우, 띄어쓰기하여 반환됩니다.)', text_read_elements: 'A-- 아래 선택지 중 하나
① "오브젝트(글상자) 이름"
② 자기 자신', text_read_exampleCode: 'def when_start():\n Entry.print(Entry.contents_of_textbox("A"))', text_read_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 글상자 "A"의 내용을 말합니다.​', text_write_desc: '글상자의 내용을 A로 고쳐씁니다.', text_write_elements: 'A-- 글상자의 내용
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', text_write_exampleCode: 'def when_start():\n Entry.write_text("엔트리")', text_write_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용을 "엔트리"로 바꿉니다.', text_append_desc: '글상자의 내용 뒤에 A를 추가합니다.', text_append_elements: 'A-- 글상자의 내용
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', text_append_exampleCode: 'def when_start():\n Entry.write_text("안녕?")\n Entry.wait_for_sec(1)\n Entry.append_text("엔트리!")', text_append_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용이 "안녕?"이 되었다가 1초 뒤에 "엔트리!"가 추가되어 "안녕?엔트리!"가 됩니다.', text_prepend_desc: '글상자의 내용 앞에 A를 추가합니다.', text_prepend_elements: 'A-- 글상자의 내용
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', text_prepend_exampleCode: 'def when_start():\n Entry.write_text("반가워!")\n Entry.wait_for_sec(1)\n Entry.prepend_text("엔트리!")', text_prepend_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용이 "반가워!"가 되었다가 1초 뒤에 "엔트리!"가 앞에 추가되어 "엔트리!반가워!"가 됩니다.', text_flush_desc: '글상자에 저장된 값을 모두 지웁니다.', text_flush_exampleCode: 'def when_start():\n Entry.write_text("엔트리")\n Entry.wait_for_sec(1)\n Entry.clear_text()', text_flush_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용이 "엔트리"가 되었다가 1초 뒤에 모든 내용이 사라집니다.', sound_something_with_block_desc: '오브젝트가 A 소리를 재생합니다.', sound_something_with_block_elements: 'A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 "소리 이름"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_with_block_exampleCode: 'def when_start():\n Entry.play_sound("소리")\n Entry.add_size(50)', sound_something_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 재생하면서 오브젝트의 크기가 50만큼 커집니다.', sound_something_second_with_block_desc: '오브젝트가 A소리를 B초 만큼 재생합니다.', sound_something_second_with_block_elements: 'A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 "소리 이름"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_second_with_block_exampleCode: 'def when_start():\n Entry.play_sound_for_sec("소리", 1)\n Entry.add_size(50)', sound_something_second_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 1초 동안 재생하면서, 오브젝트의 크기가 50만큼 커집니다.', sound_from_to_desc: '오브젝트가 A소리를 B초부터 C초까지 재생합니다.', sound_from_to_elements: 'A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 "소리 이름"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_from_to_exampleCode: 'def when_start():\n Entry.play_sound_from_to("소리", 0.5, 1)\n Entry.add_size(50)', sound_from_to_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 0.5초부터 1초 구간까지만 재생하면서, 오브젝트의 크기가 50만큼 커집니다.', sound_something_wait_with_block_desc: '오브젝트가 A 소리를 재생하고, 재생이 끝나면 다음 명령을 실행합니다.', sound_something_wait_with_block_elements: 'A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 "소리 이름"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_wait_with_block_exampleCode: 'def when_start():\n Entry.play_sound_and_wait("소리")\n Entry.add_size(50)', sound_something_wait_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.', sound_something_second_wait_with_block_desc: '오브젝트가 A소리를 B초 만큼 재생하고, 재생이 끝나면 다음 명령을 실행합니다.', sound_something_second_wait_with_block_elements: 'A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 "소리 이름"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_second_wait_with_block_exampleCode: 'def when_start():\n Entry.play_sound_for_sec_and_wait("소리", 1)\n Entry.add_size(50)', sound_something_second_wait_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 1초 동안 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.', sound_from_to_and_wait_desc: '오브젝트가 A소리를 B초부터 C초까지 재생하고, 재생이 끝나면 다음 명령을 실행합니다.', sound_from_to_and_wait_elements: 'A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 "소리 이름"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_from_to_and_wait_exampleCode: 'def when_start():\n Entry.play_sound_from_to_and_wait("소리", 0.5, 1)\n Entry.add_size(50)', sound_from_to_and_wait_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 0.5초부터 1초 구간까지만 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.', sound_volume_change_desc: '작품에서 재생되는 모든 소리의 크기를 A퍼센트만큼 바꿉니다.', sound_volume_change_elements: 'A-- 소리 크기 변화 값', sound_volume_change_exampleCode: 'def when_press_key("up"):\n Entry.add_sound_volume(10)\n\ndef when_press_key("down"):\n Entry.add_sound_volume(-10)\n\ndef when_start():\n while True:\n Entry.play_sound_and_wait("소리")', sound_volume_change_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 계속 재생합니다. 위쪽화살표키를 누르면 소리의 크기가 10" 커지고, 아래쪽화살표키를 누르면 소리의 크기가 10"작아집니다.', sound_volume_set_desc: '작품에서 재생되는 모든 소리의 크기를 A퍼센트로 정합니다.', sound_volume_set_elements: 'A-- 소리 크기값', sound_volume_set_exampleCode: 'def when_press_key("up"):\n Entry.add_sound_volume(10)\n\ndef when_press_key("down"):\n Entry.add_sound_volume(-10)\n\ndef when_press_key("enter"):\n Entry.set_sound_volume(100)\n\ndef when_start():\n while True:\n Entry.play_sound_and_wait("소리")', sound_volume_set_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 계속 재생합니다. 위쪽화살표키를 누르면 소리의 크기가 10" 커지고, 아래쪽화살표키를 누르면 소리의 크기가 10"작아집니다. 엔터키를 누르면 소리의 크기를 100"로 정합니다.', sound_silent_all_desc: '현재 재생 중인 모든 소리를 멈춥니다.', sound_silent_all_exampleCode: 'def when_start():\n while True:\n Entry.play_sound_and_wait("소리")\n\ndef when_press_key("enter"):\n Entry.stop_sound()', sound_silent_all_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 계속 재생합니다. 엔터키를 누르면 현재 재생 중인 소리를 멈춥니다.', is_clicked_desc: '마우스를 클릭한 경우 True로 판단합니다.', is_clicked_exampleCode: 'def when_start():\n while True:\n if Entry.is_mouse_clicked():\n Entry.print_for_sec("반가워!", 0.5)', is_clicked_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 마우스를 클릭했는지 확인합니다. 만약 마우스를 클릭하면 오브젝트가 "반가워!"라고 0.5초간 말합니다.', is_press_some_key_desc: 'A 키가 눌려져 있는 경우 True로 판단합니다.', is_press_some_key_elements: 'A-- 아래 선택지 중 하나
① 알파벳 : "A", "B" ~ "Z" 등(소문자 가능)
② 숫자: 1, 2, 3, 4 ~ 9, 0
③ 특수키: "space", "enter"
④ 방향키 : "up", "down", "right", "left"', is_press_some_key_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("space"):\n Entry.move_to_direction(10)', is_press_some_key_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 선택한 키를 눌렀는지 확인합니다. 만약 스페이스 키를 누르면 오브젝트가 이동방향으로 10만큼 이동합니다.', reach_something_desc: '오브젝트가 A와 닿은 경우 True으로 판단합니다.', reach_something_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "mouse_pointer" 또는 "마우스포인터"
③ "edge", "edge_up", "edge_down", "edge_right", "edge_left"', reach_something_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n if Entry.is_touched("edge"):\n Entry.add_rotation(150)', reach_something_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트가 이동방향으로 10만큼 이동합니다. 만약 오브젝트가 벽에 닿으면 150만큼 회전하게 됩니다.', boolean_basic_operator_desc: 'A와 B를 비교하여 True 또는 False로 판단합니다.', boolean_basic_operator_elements: 'A, B-- 비교하고자 하는 숫자값
① == : A와 B의 값이 같으면 True, 아니면 False
② > : A의 값이 B의 값보다 크면 true, 아니면 False
③ < : A의 값이 B의 값보다 작으면 true, 아니면 False
④ >= : A의 값이 B의 값보다 크거나 같으면 true, 아니면 False
⑤ <= : A의 값이 B의 값보다 작거나 같으면 true, 아니면 False', boolean_basic_operator_exampleCode: 'def when_start():\n while True:\n Entry.add_x(10)\n if Entry.value_of_object("오브젝트", "x") > 240:\n Entry.set_x(0)', boolean_basic_operator_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트 x좌표를 10만큼 바꿉니다. 만약 오브젝트 x좌표가 240보다 크면 오브젝트 x좌표를 0으로 정합니다.', boolean_and_desc: 'A와 B의 판단이 모두 True인 경우 True, 아닌 경우 False로 판단합니다.', boolean_and_elements: 'A, B-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', boolean_and_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("a") and Entry.is_key_pressed("s"):\n Entry.add_effect("color", 10)', boolean_and_exampleDesc: '[시작하기]버튼을 클릭하고 키보드의 "a" 와 "s"키를 동시에 눌렀을 때, 색깔 효과를 10만큼 줍니다.', boolean_or_desc: 'A와 B의 판단 중 하나라도 True인 경우 True, 아닌 경우 False로 판단합니다.', boolean_or_elements: 'A, B-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', boolean_or_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("a") or Entry.is_key_pressed("s"):\n Entry.add_effect("color", 10)', boolean_or_exampleDesc: '[시작하기]버튼을 클릭하면 키보드의 "a"나 "s"키 중 무엇이든 하나를 누르면 오브젝트에 색깔 효과를 10만큼 줍니다.', boolean_not_desc: 'A 판단이 True이면 False, False이면 True로 판단합니다.', boolean_not_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', boolean_not_exampleCode: 'def when_start():\n while True:\n if not Entry.is_mouse_clicked():\n Entry.add_size(1)', boolean_not_exampleDesc: '[시작하기]버튼을 클릭하면 마우스를 클릭하지 않은 동안 크기가 1씩 커집니다.', calc_basic_desc: 'A와 B의 연산값입니다.', calc_basic_elements: 'A, B-- 연산하고자 하는 숫자값
① + : A와 B를 더한 값
② - : A와 B를 뺀 값
③ x : A와 B를 곱한 값
④ / : A와 B를 나눈 값', calc_basic_exampleCode: 'def when_start():\n Entry.print_for_sec(10 + 10, 2)\n Entry.print_for_sec(10 - 10, 2)\n Entry.print_for_sec(10 * 10, 2)\n Entry.print_for_sec(10 / 10, 2)', calc_basic_exampleDesc: '[시작하기]버튼을 클릭하면 10과 10을 더한값, 뺀값, 곱한값, 나눈값을 각 2초간 말합니다.', calc_rand_desc: 'A와 B 사이에서 선택된 무작위 수의 값입니다. (두 수 모두 정수를 입력한 경우 정수로,두 수 중 하나라도 소수를 입력한 경우 소수로 무작위 수가 선택됩니다.)', calc_rand_elements: 'A, B-- 무작위 수를 추출할 범위
① random.randint(A, B) : A, B를 정수로 입력하면 정수 범위에서 무작위 수를 추출
② random.uniform(A, B) : A, B를 실수로 입력하면 실수 범위에서 무작위 수를 추출', calc_rand_exampleCode: 'def when_start():\n Entry.print_for_sec(random.randint(1, 10), 2)\n Entry.print_for_sec(random.uniform(0.1, 2), 2)', calc_rand_exampleDesc: '[시작하기]버튼을 클릭하면 1부터 10사이의 정수중 무작위 수를 뽑아 2초간 말합니다. 그 후 0.1부터 2사이의 실수중 무작위 수를 뽑아 2초간 말합니다.', coordinate_mouse_desc: '마우스 포인터의 A 좌표 값을 의미합니다.', coordinate_mouse_elements: 'A-- 아래 선택지 중 하나
① "x" 또는 "X"
② "y" 또는 "Y"', coordinate_mouse_exampleCode: 'def when_start():\n while True:\n Entry.print(Entry.value_of_mouse_pointer("x"))', coordinate_mouse_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 마우스 포인터의 x좌표를 계속해서 말합니다.', coordinate_object_desc: 'A에 대한 B정보값입니다.', coordinate_object_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "self" 또는 "자신"%nextB-- 아래 선택지 중 하나
① "x" 또는 "X"
② "y" 또는 "Y"
③ "rotation" 또는 "방향"
④ "direction" 또는 "이동 방향"
⑤ "size" 또는 "크기"
⑥ "shape_number" 또는 "모양 번호"
⑦ "shape_name" 또는 "모양 이름"', coordinate_object_exampleCode: 'def when_start():\n while True:\n Entry.add_x(1)\n Entry.print(Entry.value_of_object("오브젝트", "x"))\n', coordinate_object_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트의 x좌표가 1씩 증가하며, "오브젝트"의 x좌표를 말합니다.', get_sound_volume_desc: '현재 작품에 설정된 소리의 크기값입니다.', get_sound_volume_exampleCode: 'def when_start():\n while True:\n Entry.print(Entry.value_of_sound_volume())', get_sound_volume_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 소리의 크기값을 계속해서 말합니다.', quotient_and_mod_desc: 'A와 B의 연산값입니다.', quotient_and_mod_elements: 'A, B-- 연산하고자 하는 숫자값
① // : A / B의 몫에 해당하는 값
② % : A / B의 나머지에 해당하는 값', quotient_and_mod_exampleCode: 'def when_start():\n Entry.print_for_sec(10 // 3, 2)\n Entry.print_for_sec(10 % 3, 2)', quotient_and_mod_exampleDesc: '[시작하기]버튼을 클릭하면 10 / 3의 몫인 3을 2초 동안 말하고, 나머지인 1을 2초 동안 말합니다.', calc_operation_desc: 'A의 연산값입니다.', calc_operation_elements: 'A, B-- 연산하고자 하는 숫자값
① A ** 2 : A를 제곱한 값
② math.sqrt(A): A의 루트값
③ math.sin(A): A의 사인값
④ math.cos(A): A의 코사인 값
⑤ math.tan(A): A의 탄젠트값
⑥ math.asin(A): A의 아크사인값
⑦ math.acos(A): A의 아크코사인값
⑧ math.atan(): A의 아크탄젠트값
⑨ math.log10(A): A의 로그값
⑩ math.log(A): A의 자연로그값
⑪ A - math.floor(A): A의 소수점 부분
⑫ math.floor(A): A의 소수점 버림값
⑬ math.ceil(A): A의 소수점 올림값
⑭ math.round(A): A의 소수점 반올림값
⑮ math.factorial(A): A의 팩토리얼 값
⑯ math.fabs(A): A의 절댓값', calc_operation_exampleCode: 'def when_start():\n Entry.print_for_sec(10 ** 2, 2)\n Entry.print_for_sec(math.sqrt(9), 2)\n Entry.print_for_sec(math.sin(90), 2)\n Entry.print_for_sec(math.fabs(-10), 2)', calc_operation_exampleDesc: '[시작하기]버튼을 클릭하면 10의 제곱, 9의 루트값, 90의 사인값, -10의 절댓값을 각 2초 동안 말합니다.', get_project_timer_value_desc: '이 명령이 실행되는 순간 초시계에 저장된 값입니다.', get_project_timer_value_exampleCode: 'def when_start():\n Entry.timer("start")\n Entry.wait_for_sec(3)\n Entry.timer("stop")\n Entry.timer_view("hide")\n Entry.print(Entry.value_of_timer())', get_project_timer_value_exampleDesc: '[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.', choose_project_timer_action_desc: '초시계의 동작을 A로 정합니다.
(이 명령어를 사용하면 실행화면에 ‘초시계 창’이 생성됩니다.)', choose_project_timer_action_elements: 'A-- 아래 선택지 중 하나
① "start" : 초시계를 시작
② "stop" : 초시계를 정지
③ "reset" : 초시계를 초기화', choose_project_timer_action_exampleCode: 'def when_start():\n Entry.timer("start")\n Entry.wait_for_sec(3)\n Entry.timer("stop")\n Entry.timer_view("hide")\n Entry.print(Entry.value_of_timer())', choose_project_timer_action_exampleDesc: '[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.', set_visible_project_timer_desc: '실행화면의 초시계 창을 A로 설정합니다.', set_visible_project_timer_elements: 'A-- 아래 선택지 중 하나
① "hide" : 초시계창을 숨김
② "show" : 초시계창을 보임', set_visible_project_timer_exampleCode: 'def when_start():\n Entry.timer("start")\n Entry.wait_for_sec(3)\n Entry.timer("stop")\n Entry.timer_view("hide")\n Entry.print(Entry.value_of_timer())', set_visible_project_timer_exampleDesc: '[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.', get_date_desc: '현재 A에 대한 값입니다.', get_date_elements: 'A-- 아래 선택지 중 하나
① "year" : 현재 연도 값
② "month" : 현재 월 값
③ "day" : 현재 일 값
④ "hour" : 현재 시간 값
⑤ "minute" : 현재 분 값
⑥ "second" : 현재 초 값', get_date_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_current_time("year") + "년" + Entry.value_of_current_time("month") + "월")', get_date_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 현재년도와 월을 말합니다.', distance_something_desc: '자신과 A까지의 거리 값입니다.', distance_something_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "mouse_pointer" 또는 "마우스포인터"', distance_something_exampleCode: 'def when_start():\n while True:\n Entry.print(Entry.value_of_distance_to("mouse_pointer"))', distance_something_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 마우스포인터와의 거리를 계속해서 말합니다.', get_sound_duration_desc: '소리 A의 길이(초)값입니다.', get_sound_duration_elements: 'A-- "소리 이름"', get_sound_duration_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_sound_length_of("소리"))', get_sound_duration_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "소리"의 길이를 말합니다.', get_user_name_desc: '작품을 실행하고 있는 사용자의 이름 값입니다.', get_user_name_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_username())', get_user_name_exampleDesc: '[시작하기]버튼을 클릭하면 작품을 실행하고 있는 사용자의 이름 값을 말합니다.', length_of_string_desc: '입력한 문자값의 공백을 포함한 글자 수입니다.', length_of_string_elements: 'A-- "문자열"', length_of_string_exampleCode: 'def when_start():\n Entry.print_for_sec(len("안녕"), 2)\n Entry.print_for_sec(len("엔트리"), 2)', length_of_string_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕"과 "엔트리"의 글자 수를 각각 2초 동안 말합니다.', combine_something_desc: 'A 문자열과 B 문자열을 결합한 값입니다. (A, B 중 하나가 숫자면 문자열로 바꾸어 처리되고, 둘 다 숫자면 덧셈 연산으로 처리됩니다.)', combine_something_elements: 'A, B-- "문자열"', combine_something_exampleCode: 'def when_start():\n Entry.print("안녕! " + "엔트리")', combine_something_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕!"과 "엔트리"를 결합한 "안녕! 엔트리"를 말합니다.', char_at_desc: 'A 문자열의 B번째의 글자 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)', char_at_elements: 'A-- "문자열"%nextB-- 찾고자 하는 문자열의 위치', char_at_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!"[0])', char_at_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"의 0번째 글자인 "안"을 말합니다.', substring_desc: 'A 문자열의 B위치부터 C-1위치까지의 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)', substring_elements: 'A-- "문자열"%nextB-- 포함할 문자열의 시작 위치
첫 번째 글자는 0부터 시작%nextC-- 문자열을 포함하지 않는 위치', substring_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!"[1:5])', substring_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"의 1에서 4번째 글자인 "녕 엔트"를 말합니다.', index_of_string_desc: 'A문자열에서 B문자열이 처음으로 등장하는 위치의 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)', index_of_string_elements: 'A, B-- "문자열"', index_of_string_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!".find("엔트리"))', index_of_string_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"에서 "엔트리"가 처음으로 등장하는 위치인 3을 말합니다.', replace_string_desc: 'A 문자열에서 B문자열을 모두 찾아 C문자열로 바꾼 값입니다.
(영문 입력시 대소문자를 구분합니다.)', replace_string_elements: 'A, B, C-- "문자열"', replace_string_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!".replace( "안녕", "반가워"))', replace_string_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"에서 "안녕"을 "반가워"로 바꾼 "반가워 엔트리!"를 말합니다.', change_string_case_desc: 'A의 모든 알파벳을 대문자 또는 소문자로 바꾼 문자값입니다.', change_string_case_elements: 'A-- "문자열"
① A.upper(): A의 모든 알파벳을 대문자로 바꾼 값
② A.lower() : A의 모든 알파벳을 소문자로 바꾼 값', change_string_case_exampleCode: 'def when_start():\n Entry.print_for_sec("Hello Entry!".upper(), 2)\n Entry.print_for_sec("Hello Entry!".lower(), 2)', change_string_case_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "Hello Entry!"를 모두 대문자로 바꾼 "HELLO ENTRY!"를 2초간 말한 다음 모두 소문자로 바꾼 "hello entry!"를 2초간 말합니다.', ask_and_wait_desc: "오브젝트가 A 내용을 말풍선으로 묻고, 대답을 입력받습니다. 대답은 실행화면 또는 콘솔창에서 입력할 수 있으며 입력된 값은 'Entry.answer()'에 저장됩니다.
(이 명령어를 사용하면 실행화면에 ‘대답 창’이 생성됩니다.)", ask_and_wait_elements: 'A-- "문자열"', ask_and_wait_exampleCode: 'def when_start():\n Entry.input("이름을 입력해보세요.")\n Entry.print(Entry.answer() + " 반가워!")', ask_and_wait_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "이름을 입력해보세요."라고 말풍선으로 묻습니다. 이름을 입력하면 "(입력한 이름) 반가워!"라 말합니다.', get_canvas_input_value_desc: 'Entry.input(A) 명령에 의해 실행화면 또는 콘솔에서 입력받은 값입니다.', get_canvas_input_value_exampleCode: 'def when_start():\n Entry.input("이름을 입력해보세요.")\n Entry.print(Entry.answer() + " 반가워!")', get_canvas_input_value_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "이름을 입력해보세요."라고 말풍선으로 묻습니다. 이름을 입력하면 "(입력한 이름) 반가워!"라 말합니다.', set_visible_answer_desc: '실행화면의 대답 창을 A로 설정합니다.', set_visible_answer_elements: 'A-- 아래 선택지 중 하나
① "hide" : 대답 창을 숨김
② "show" : 대답 창을 보임', set_visible_answer_exampleCode: 'def when_start():\n Entry.answer_view("hide")\n Entry.input("나이를 입력하세요.")\n Entry.print(Entry.answer())', set_visible_answer_exampleDesc: '[시작하기]버튼을 클릭하면 대답창이 숨겨지고, 오브젝트가 "나이를 입력하세요."라고 말풍선으로 묻습니다. 나이를 입력하면 오브젝트가 입력한 나이를 말합니다.', get_variable_desc: 'A 변수에 저장된 값입니다.', get_variable_elements: 'A-- 변수명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A', get_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.print(age)', get_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 말합니다.', change_variable_desc: 'A 변수에 B만큼 더합니다.', change_variable_elements: 'A-- 변수명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 숫자값', change_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.print_for_sec(age, 2)\n age += 2\n Entry.print_for_sec(age, 2)', change_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 2초 동안 말합니다. 그 후 age변수에 2를 더하고 더한값인 "18"을 2초 동안 말합니다.', set_variable_desc: 'A 변수의 값을 B로 정합니다. 만약 A 변수가 없으면 [속성] 탭에 A 변수가 자동 생성됩니다.', set_variable_elements: 'A-- 변수명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 변수에 넣을 값
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', set_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.print(age)', set_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 말합니다.', show_variable_desc: 'A 변수 창을 실행화면에 보이게 합니다.', show_variable_elements: 'A-- "변수명"
① 모든 오브젝트에서 사용: "A"
② 이 오브젝트에서 사용: "self.A"', show_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.hide_variable("age")\n Entry.wait_for_sec(2)\n age = 20\n Entry.show_variable("age")', show_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 age변수창을 실행화면에서 숨깁니다. 2초 후 변수값을 17로 바꾸고 age변수창을 실행화면에 보이게 합니다.', hide_variable_desc: 'A 변수 창을 실행화면에서 숨깁니다.', hide_variable_elements: 'A-- "변수명"
① 모든 오브젝트에서 사용: "A"
② 이 오브젝트에서 사용: "self.A"', hide_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.hide_variable("age")\n Entry.print_for_sec(age, 2)', hide_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 age변수창을 실행화면에서 숨기고, 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 2초 동안 말합니다.', value_of_index_from_list_desc: 'A 리스트에서 B위치의 항목 값을 의미합니다.
(첫 번째 항목의 위치는 0부터 시작합니다.)', value_of_index_from_list_elements: 'A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치', value_of_index_from_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.print(basket[1])\n', value_of_index_from_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 오브젝트가 basket 리스트의 1번째 항목인 orange를 말합니다.', add_value_to_list_desc: 'A 리스트의 마지막 항목으로 B값이 추가됩니다.', add_value_to_list_elements: 'A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트에 넣을 항목 값
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', add_value_to_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n basket.append("juice")\n Entry.print(basket[4])', add_value_to_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 "juice"를 basket의 마지막 항목으로 추가합니다. 오브젝트는 basket의 4번째 항목인 "juice"를 말합니다.', remove_value_from_list_desc: 'A 리스트의 B위치에 있는 항목을 삭제합니다.
(첫 번째 항목의 위치는 0부터 시작합니다.)', remove_value_from_list_elements: 'A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치값', remove_value_from_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\ndef when_start():\n basket.pop(0)\n Entry.print(basket[0])', remove_value_from_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 0번째 항목인 apple을 삭제합니다. 오브젝트는 새롭게 basket의 0번째 항목이 된 "orange"를 말합니다.', insert_value_to_list_desc: 'A 리스트의 B위치에 C항목을 끼워 넣습니다.
(첫 번째 항목의 위치는 0부터 시작합니다. B위치보다 뒤에 있는 항목들은 순서가 하나씩 밀려납니다.)', insert_value_to_list_elements: 'A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치%nextC-- 리스트에 넣을 항목 값
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', insert_value_to_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n basket.insert(1, "juice")\n Entry.print(basket[2])', insert_value_to_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 1번째 위치에 항목 "juice"를 끼워 넣습니다. 오브젝트는 새롭게 basket의 2번째 항목이 된 "orange"를 말합니다.', change_value_list_index_desc: 'A 리스트에서 B위치에 있는 항목의 값을 C 값으로 바꿉니다.
(첫 번째 항목의 위치는 0부터 시작합니다.)', change_value_list_index_elements: 'A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치%nextC-- 리스트에 넣을 항목 값
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', change_value_list_index_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n basket[0] = "juice"\n Entry.print(basket[0])', change_value_list_index_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 0번째 위치의 항목 "apple"을 "juice"로 바꿉니다. 오브젝트는 바뀐 basket의 0번째 항목 "juice"를 말합니다.', length_of_list_desc: 'A 리스트가 보유한 항목 개수 값입니다.', length_of_list_elements: 'A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A', length_of_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.print(len(basket))', length_of_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 오브젝트는 basket의 항목 개수인 4를 말합니다.', is_included_in_list_desc: 'A값을 가진 항목이 B리스트에 포함되어 있는지 확인합니다.', is_included_in_list_elements: 'A-- 리스트의 항목 값
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등%nextB-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A', is_included_in_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n if "apple" in basket:\n Entry.print("사과가 있어!")', is_included_in_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트에 "apple"항목이 있는지 확인합니다. "apple"항목이 있기 때문에 오브젝트는 "사과가 있어!"라 말합니다.', show_list_desc: '선택한 리스트 창을 실행화면에 보이게 합니다.', show_list_elements: 'A-- "리스트명"
① 모든 오브젝트에서 사용: "A"
② 이 오브젝트에서 사용: "self.A"', show_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.hide_list("basket")\n Entry.wait_for_sec(2)\n Entry.show_list("basket")', show_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트를 2초간 숨긴 다음 보여줍니다.', hide_list_desc: '선택한 리스트 창을 실행화면에서 숨깁니다.', hide_list_elements: 'A-- "리스트명"
① 모든 오브젝트에서 사용: "A"
② 이 오브젝트에서 사용: "self.A"', hide_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.hide_list("basket")\n Entry.wait_for_sec(2)\n Entry.show_list("basket")', hide_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트를 2초간 숨긴 다음 보여줍니다.', boolean_and_or_desc: 'A와 B의 판단값을 확인하여 True 또는 False로 판단합니다.', boolean_and_or_elements: '② or : A와 B의 판단 중 하나라도 True인 경우 True, 아닌 경우 False', boolean_and_or_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("a") and Entry.is_key_pressed("s"):\n Entry.add_effect("color", 10)', boolean_and_or_exampleDesc: '[시작하기]버튼을 클릭하고 키보드의 "a" 와 "s"키를 동시에 눌렀을 때, 색깔 효과를 10만큼 줍니다.', check_weather_desc: 'B날짜에 C지역의 날씨가 A인 경우 True로 판단합니다.', check_weather_elements: 'A-- 아래 선택지 중 하나
①    "sunny" : 맑음
②    "partly cloudy" : 구름조금
③    "mostly cloudy" : 구름많음
④    "cloudy" : 흐림
⑤    "rainy" : 비
⑥    "sleet" : 진눈깨비
⑦    "snowy" : 눈%nextB-- 아래 선택지 중 하나
①    "yesterday" : 어제
②    "today" : 오늘
③    "tomorrow" : 내일
④    "After 2 days" : 모레
⑤    "After 3 days" : 3일 후
⑥    "After 4 days" : 4일 후
⑦    "After 5 days" : 5일 후
⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북', check_weather_exampleCode: 'def when_start():\n if Weather.is_condition_sunny("today", "Seoul"):\n Entry.print("오늘 서울의 날씨는 맑습니다.")', check_weather_exampleDesc: '[시작하기]버튼을 클릭하면 오늘 서울의 날씨가 맑은지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 "오늘 서울의 날씨는 맑습니다."라고 말합니다.​', check_finedust_desc: '선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.', check_finedust_elements: 'A-- 아래 선택지 중 하나
①    "good" : 좋음
②    "normal" : 보통
③    "bad" : 나쁨
④    "very bad" : 매우나쁨%nextB-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북', check_finedust_exampleCode: 'def when_start():\n if Weather.is_current_finedust_grade_good("Seoul"):\n Entry.print("현재 서울의 미세먼지 등급은 좋음입니다.")', check_finedust_exampleDesc: '[시작하기]버튼을 클릭하면 현재 서울의 미세먼지 등급이 좋음인지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 “오늘 서울의 미세먼지 등급은 좋음입니다.”라고 말합니다.​', get_weather_data_desc: '선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.', get_weather_data_elements: 'A-- 아래 선택지 중 하나
①    "the lowest temperature" : 최저기온
②    "the highest temperature" : 최고기온
③    "humidity" : 습도
④    "precipitation" : 강수량
⑤    "precipitation probability" : 강수확률
⑥    "wind speed" : 풍속%nextB-- 아래 선택지 중 하나
①    "yesterday" : 어제
②    "today" : 오늘
③    "tomorrow" : 내일
④    "After 2 days" : 모레
⑤    "After 3 days" : 3일 후
⑥    "After 4 days" : 4일 후
⑦    "After 5 days" : 5일 후
⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북', get_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_lowest_temperature("today", "Seoul"))', get_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 최저기온을 말합니다.​', get_current_weather_data_desc: '현재 B지역의 A 날씨 정보값을 의미합니다.', get_current_weather_data_elements: 'A-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나
①    "temperature" : 기온
②    "concentration of fine dust" : 미세먼지농도', get_current_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_current_temperature("Seoul"))', get_current_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 현재 서울의 기온을 말합니다.', get_today_temperature_desc: '오늘 A지역의 B 시간대 기온 정보값을 의미합니다.', get_today_temperature_elements: 'A-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나
①    "00" : 당일 00시 측정된 기온값
②    "03" : 당일 03시 측정된 기온값
③    "06" : 당일 06시 측정된 기온값
④    "09" : 당일 09시 측정된 기온값
⑤    "12" : 당일 12시 측정된 기온값
⑥    "15" : 당일 15시 측정된 기온값
⑦    "18" : 당일 18시 측정된 기온값
⑧    "21" : 당일 21시 측정된 기온값', get_today_temperature_exampleCode: 'def when_start():\n Entry.print(Weather.get_today_temperature("Seoul", 00))', get_today_temperature_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 00시 기온을 말합니다.​', check_city_weather_desc: 'B날짜에 C지역의 날씨가 A인 경우 True로 판단합니다.', check_city_weather_elements: 'A-- 아래 선택지 중 하나
①    "sunny" : 맑음
②    "partly cloudy" : 구름조금
③    "mostly cloudy" : 구름많음
④    "cloudy" : 흐림
⑤    "rainy" : 비
⑥    "sleet" : 진눈깨비
⑦    "snowy" : 눈%nextB-- 아래 선택지 중 하나
①    "yesterday" : 어제
②    "today" : 오늘
③    "tomorrow" : 내일
④    "After 2 days" : 모레
⑤    "After 3 days" : 3일 후
⑥    "After 4 days" : 4일 후
⑦    "After 5 days" : 5일 후
⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북', check_city_weather_exampleCode: 'def when_start():\n if Weather.is_condition_sunny("today", "Seoul"):\n Entry.print("오늘 서울의 날씨는 맑습니다.")', check_city_weather_exampleDesc: '[시작하기]버튼을 클릭하면 오늘 서울의 날씨가 맑은지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 "오늘 서울의 날씨는 맑습니다."라고 말합니다.​', check_city_finedust_desc: '선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.', check_city_finedust_elements: 'A-- 아래 선택지 중 하나
①    "good" : 좋음
②    "normal" : 보통
③    "bad" : 나쁨
④    "very bad" : 매우나쁨%nextB-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북', check_city_finedust_exampleCode: 'def when_start():\n if Weather.is_current_finedust_grade_good("Seoul"):\n Entry.print("현재 서울의 미세먼지 등급은 좋음입니다.")', check_city_finedust_exampleDesc: '[시작하기]버튼을 클릭하면 현재 서울의 미세먼지 등급이 좋음인지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 “오늘 서울의 미세먼지 등급은 좋음입니다.”라고 말합니다.​', get_city_weather_data_desc: '선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.', get_city_weather_data_elements: 'A-- 아래 선택지 중 하나
①    "the lowest temperature" : 최저기온
②    "the highest temperature" : 최고기온
③    "humidity" : 습도
④    "precipitation" : 강수량
⑤    "precipitation probability" : 강수확률
⑥    "wind speed" : 풍속%nextB-- 아래 선택지 중 하나
①    "yesterday" : 어제
②    "today" : 오늘
③    "tomorrow" : 내일
④    "After 2 days" : 모레
⑤    "After 3 days" : 3일 후
⑥    "After 4 days" : 4일 후
⑦    "After 5 days" : 5일 후
⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북', get_city_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_lowest_temperature("today", "Seoul"))', get_city_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 최저기온을 말합니다.​', get_current_city_weather_data_desc: '현재 B지역의 A 날씨 정보값을 의미합니다.', get_current_city_weather_data_elements: 'A-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나
①    "temperature" : 기온
②    "concentration of fine dust" : 미세먼지농도', get_current_city_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_current_temperature("Seoul"))', get_current_city_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 현재 서울의 기온을 말합니다.', get_today_city_temperature_desc: '오늘 A지역의 B 시간대 기온 정보값을 의미합니다.', get_today_city_temperature_elements: 'A-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나
①    "00" : 당일 00시 측정된 기온값
②    "03" : 당일 03시 측정된 기온값
③    "06" : 당일 06시 측정된 기온값
④    "09" : 당일 09시 측정된 기온값
⑤    "12" : 당일 12시 측정된 기온값
⑥    "15" : 당일 15시 측정된 기온값
⑦    "18" : 당일 18시 측정된 기온값
⑧    "21" : 당일 21시 측정된 기온값', get_today_city_temperature_exampleCode: 'def when_start():\n Entry.print(Weather.get_today_city_temperature("Seoul", 00))', get_today_city_temperature_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 00시 기온을 말합니다.​', }; Lang.Painter = { select_cut: '사각 점선 모양으로 오릴 수 있어요.', thickness_of_eraser: '지우개 굵기', font: '글꼴', font_color: '글꼴 색상', outline_color: '윤곽선 색상', outline_thickness: '윤곽선 굵기', fill_color: '채우기 색상', inversion: '반전', font_size: '글꼴 크기', font_family: '글꼴 스타일', fullscreen: '전체화면', exit_fullscreen: '전체화면 해제', picture_import: '모양 가져오기', edit_way: '편집 방법', line: '직선', vertex: '꼭지점', bitmap: '비트맵', vector: '벡터', forward: '앞으로', backward: '뒤로', front: '맨 앞으로', back: '맨 뒤로', group: '그룹화', ungroup: '그룹 해제', copy_picture: '복사', delete_picture: '삭제', cut_picture: '자르기', paste_picture: '붙여넣기', remove_all: '모두 삭제', new_picture: '새그림', edit: '편집', picture_size: '크기', picture_rotation: '회전', thickness: '굵기', font_fill: '채우기 색상', painter_file_save: '저장하기', painter_file_saveas: '새 모양으로 저장', file: '파일', Pencil: '펜', Line: '직선', Path: '형태', Pan: '이동', Select: '선택', Rectangle: '사각형', Ellipse: '원', Text: '글상자', Fill: '채우기', Eraser: '지우기', get_file: '가져오기', copy_file: '복사하기', }; Lang.DataAnalytics = { data_analysis: '데이터분석', create_table: '테이블 만들기', data: '데이터', add_table: '테이블 추가하기', show_chart: '차트 보기', legend: '범례', dashboard: '요약', table: '테이블', chart: '차트', attribute: '열', row: '행', average: '평균', standard_deviation: '표준 편차', maximum: '최댓값', minimum: '최솟값', median: '중간값', average_explain: '해당 열의 모든 값을 더한 후 열의 개수 만큼 나눈 값', standard_deviation_explain: '데이터가 평균을 중심으로 얼마나 퍼져있는지 알려주는 값.\n0에 가까울 수록 값들이 평균 근처에 집중되어 있다는 것을 의미', maximum_minimum_explain: '해당 열의 가장 큰 값과 가장 작은 값', median_explain: '해당 열의 모든 값을 크기순으로 배열했을 때\n전체의 중앙에 위치하는 값', add_row_above: '위에 행 추가하기', add_row_below: '아래에 행 추가하기', delete_row: '행 삭제하기', add_property_left: '왼쪽에 열 추가하기', add_property_right: '오른쪽에 열 추가하기', delete_attribute: '열 삭제', data_alert: '숫자가 아닌 값이 포함된 열은 개수만 확인할 수 있습니다.', save: '저장하기', cancel: '취소', confirm: '확인', attribute_count: '개', row_count: '행', cell_count: '개', count: '개수', add_chart_alert: '추가된 차트가 없습니다.\n차트를 생성해주세요.', enter_attribute_name: '열 이름을 입력해 주세요.(10자 이내)', placeholder_attribute_name: '열 이름', new_attribute: '새로운 열', chart_title: '차트 제목', remove_chart: '차트 삭제하기', add_chart_first: '차트를 먼저 추가해주세요.', bar: '막대', line: '꺾은선', pie: '원형', scatter: '분산형', select_x_axis: '가로축을 선택해주세요.', x_axis: '가로축', y_axis: '세로축', select_y_axis: '세로축을 선택해주세요.', select_y_axis_or_legend: '세로축 혹은 범례를 선택해주세요.', select_legend: '범례를 선택해주세요', cell: '칸', unable_to_express_chart: '차트로 표현할 수 없습니다.', edit_attribute_name: '이름 바꾸기', duplicate_attribute_name_title: '열 이름 변경에 실패하였습니다.', duplicate_attribute_name_content: '같은 이름의 열이 존재합니다.', fail_save_table: '테이블 저장에 실패하였습니다.', duplicate_table_name_content: '같은 이름의 테이블이 존재합니다.', saved_table_title: '저장되었습니다.', saved_table_content: '테이블과 차트의 정보가 저장되었습니다.', empty_table_name_content: '테이블 이름은 빈 칸이 될 수 없습니다', do_not_delete_row: '행을 삭제할 수 없습니다.', rows_cannot_less_one: '테이블에는 한 개 이상의 행이 있어야합니다.', }; Lang.SharePolicy = { title: '엔트리 작품/게시물 공유 가이드', }; Lang.Support = ['ko', 'en', 'vn', 'jp']; if (typeof exports == 'object') exports.Lang = Lang; ================================================ FILE: extern/lang/ebs.js ================================================ var Lang = {}; Lang.category = { name: 'ko', }; Lang.type = 'ko'; Lang.fallbackType = 'ko'; Lang.ko = '한국어'; Lang.en = 'English'; Lang.jp = '日本語'; Lang.vn = 'tiếng Việt'; Lang.Command = { 1: '장면 추가하기', 2: '장면 삭제하기', 3: '장면 이름 수정', 4: '장면 순서 변경', 5: '장면 선택', 101: '블록 쓰레드 추가하기', 102: '블록 쓰레드 삭제하기', 103: '블록 삭제하기', 104: '블록 복구하기', 105: '블록 끼워넣기', 106: '블록 분리하기', 107: '블록 이동하기', 108: '블록 복제하기', 109: '블록 복제 취소하기', 110: '스크롤', 111: '블록 필드값 수정', 117: '블록 쓰레드 추가하기', 118: '블록 끼워넣기', 119: '블록 이동하기', 120: '블록 분리하기', 121: '블록 이동하기', 122: '블록 끼워넣기', 123: '블록 끼워넣기', 201: '오브젝트 선택하기', 202: '오브젝트 수정 버튼 클릭', 203: '오브젝트 그림 추가', 204: '오브젝트 그림 삭제', 205: '오브젝트 소리 추가', 206: '오브젝트 소리 삭제', 207: '오브젝트 이름 수정', 208: '오브젝트 추가', 209: '오브젝트 삭제', 210: '오브젝트 추가 버튼 클릭', 211: '오브젝트 x 수정', 212: '오브젝트 y 수정', 213: '오브젝트 size 수정', 214: '오브젝트 방향 수정', 215: '오브젝트 이동 방향 수정', 216: '오브젝트 회전방식 수정', 217: '엔터티 모델 동기화', 301: 'do', 302: 'undo', 303: 'redo', 401: '그림 수정하기', 402: '그림 수정 취소하기', 403: '그림 수정하기', 404: '그림 수정 취소하기', 405: '글상자 수정', 501: '시작하기', 502: '정지하기', 601: '컨테이너 오브젝트 선택하기', 701: '모드 바꾸기', 702: '모양 추가 버튼 클릭', 703: '소리 추가 버튼 클릭', 801: '속성 필터 선택하기', 802: '변수 추가하기 버튼 클릭', 803: '변수 추가하기', 804: '변수 삭제하기', 805: '변수 이름 설정', 806: '신호 이름 설정', 807: '신호 추가', 808: '신호 삭제', 809: '변수 스코프 정하기', 810: '변수 글로벌 체크', 811: '변수 보이기 체크', 812: '변수 기본값 설정', 813: '변수 슬라이드로 체크', 814: '변수 최솟값 정하기', 815: '변수 최댓값 정하기', 816: '리스트 추가 버튼 클릭', 817: '리스트 추가', 818: '리스트 삭제', 819: '리스트 이름 정하기', 820: '리스트 스코프 정하기', 821: '리스트 글로벌 체크', 822: '리스트 보이기 체크', 823: '리스트 길이 변경', 824: '리스트 기본값 설정', 825: '메세지 수정 enable', 826: '변수 수정 enable', 827: '리스트 수정 enable', 828: '변수 이름 정하기', 829: '리스트 이름 정하기', 900: '모달 닫기', 1001: '함수 생성 시작', 1002: '함수 수정 시작', 1003: '함수 수정 취소', 1004: '함수 생성', 1005: '함수 업데이트', }; Lang.CommandTooltip = { 101: '블록 쓰레드 추가하기', 102: '블록 쓰레드 삭제하기', 103: '블록 삭제하기', 104: '블록 복구하기', 105: '코드 분리하기$$코드 연결하기@@이 코드의 가장 위에 있는 블록을 잡고 분리하여 끌어옵니다.$$이 곳에 코드를 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 106: '블록 분리하기', 107: '블록 이동하기', 108: '블록 복제하기', 109: '블록 복제 취소하기', 110: '스크롤', 111: '블록 필드값 수정@@값을 입력하기 위해 이곳을 클릭합니다.$$선택지를 클릭합니다.$$선택지를 클릭합니다.$$&value&을 입력합니다.$$&value&를 선택합니다.$$키보드 &value&를 누릅니다.', 117: '블록 쓰레드 추가하기', 118: '블록 연결하기@@이 곳에 블록을 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 119: '블록 가져오기@@빈 곳에 블록을 끌어다 놓습니다.', 120: '블록 분리하기$$블록 삭제하기@@필요 없는 코드를 휴지통으로 끌어옵니다.$$이 곳에 코드를 버립니다.', 121: '블록 이동하기$$블록 삭제하기@@필요 없는 코드를 휴지통으로 끌어옵니다.$$이 곳에 코드를 버립니다.', 122: '블록 연결하기@@이 곳에 블록을 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 123: '코드 분리하기$$코드 연결하기@@이 코드의 가장 위에 있는 블록을 잡고 분리하여 끌어옵니다.$$이 곳에 코드를 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 201: '오브젝트 선택하기', 301: 'do', 302: 'undo', 303: 'redo', 401: '그림 수정하기', 402: '그림 수정 취소하기', 403: '그림 수정하기', 404: '그림 수정 취소하기', 501: '실행하기@@[시작하기]를 누릅니다.', 502: '정지하기@@[정지하기]를 누릅니다.', 601: '컨테이너 오브젝트 선택하기', 701: '모드 바꾸기', 702: '모양 추가하기@@모양추가를 클릭합니다.', 703: '소리 추가하기@@소리추가를 클릭합니다.', 801: '변수 속성창 필터 선택하기', 802: '변수 추가하기@@[변수 추가]를 클릭합니다.', 803: '변수 추가하기@@[확인]을 클릭합니다.', 804: '변수 삭제하기@@이 버튼을 눌러 변수를 삭제합니다.', 805: '변수 이름 설정', 1101: '확장 블록 추가하기@@확장 블록 블러오기를 클릭합니다.', }; Lang.Blocks = { download_guide: '• 연결 안내 다운로드', dictionary: '사전', ai_utilize: '인공지능', date_yesterday: '어제', date_today: '오늘', date_tomorrow: '내일', date_after_2_days: '모레', date_after_3_days: '3일 후', date_after_4_days: '4일 후', date_after_5_days: '5일 후', date_after_6_days: '6일 후', location_entire: '전체', location_seoul: '서울', location_seoul_jongno_gu: '종로구', location_seoul_jung_gu: '중구', location_seoul_yongsan_gu: '용산구', location_seoul_seongdong_gu: '성동구', location_seoul_gwangjin_gu: '광진구', location_seoul_dongdaemun_gu: '동대문구', location_seoul_jungnang_gu: '중랑구', location_seoul_seongbuk_gu: '성북구', location_seoul_gangbuk_gu: '강북구', location_seoul_dobong_gu: '도봉구', location_seoul_nowon_gu: '노원구', location_seoul_eunpyeong_gu: '은평구', location_seoul_seodaemun_gu: '서대문구', location_seoul_mapo_gu: '마포구', location_seoul_yangcheon_gu: '양천구', location_seoul_gangseo_gu: '강서구', location_seoul_guro_gu: '구로구', location_seoul_geumcheon_gu: '금천구', location_seoul_yeongdeungpo_gu: '영등포구', location_seoul_dongjak_gu: '동작구', location_seoul_gwanak_gu: '관악구', location_seoul_seocho_gu: '서초구', location_seoul_gangnam_gu: '강남구', location_seoul_songpa_gu: '송파구', location_seoul_gangdong_gu: '강동구', location_busan: '부산', location_busan_jung_gu: '중구', location_busan_seo_gu: '서구', location_busan_dong_gu: '동구', location_busan_yeongdo_gu: '영도구', location_busan_busanjin_gu: '부산진구', location_busan_dongnae_gu: '동래구', location_busan_nam_gu: '남구', location_busan_buk_gu: '북구', location_busan_haeundae_gu: '해운대구', location_busan_saha_gu: '사하구', location_busan_geumjeong_gu: '금정구', location_busan_gangseo_gu: '강서구', location_busan_yeonje: '연제구', location_busan_suyeong_gu: '수영구', location_busan_sasang_gu: '사상구', location_busan_gijang: '기장군', location_daegu: '대구', location_daegu_jung_gu: '중구', location_daegu_dong_gu: '동구', location_daegu_seo_gu: '서구', location_daegu_nam_gu: '남구', location_daegu_buk_gu: '북구', location_daegu_suseong_gu: '수성구', location_daegu_dalseo_gu: '달서구', location_daegu_dalseong: '달성군', location_incheon: '인천', location_incheon_jung_gu: '중구', location_incheon_dong_gu: '동구', location_incheon_nam_gu: '남구', location_incheon_yeonsu_gu: '연수구', location_incheon_namdong_gu: '남동구', location_incheon_bupyeong_gu: '부평구', location_incheon_gyeyang_gu: '계양구', location_incheon_seo_gu: '서구', location_incheon_ganghwa: '강화군', location_incheon_ongjin_gun: '옹진군', location_gwangju: '광주', location_gwangju_dong_gu: '동구', location_gwangju_seo_gu: '서구', location_gwangju_nam_gu: '남구', location_gwangju_buk_gu: '북구', location_gwangju_gwangsan_gu: '광산구', location_daejeon: '대전', location_daejeon_dong_gu: '동구', location_daejeon_jung_gu: '중구', location_daejeon_seo_gu: '서구', location_daejeon_yuseong_gu: '유성구', location_daejeon_daedeok_gu: '대덕구', location_ulsan: '울산', location_ulsan_jung_gu: '중구', location_ulsan_nam_gu: '남구', location_ulsan_dong_gu: '동구', location_ulsan_buk_gu: '북구', location_ulsan_ulju: '울주군', location_sejong: '세종', location_gyeonggi: '경기', location_gyeonggi_suwon_si: '수원시', location_gyeonggi_seongnam: '성남시', location_gyeonggi_uijeongbu: '의정부시', location_gyeonggi_anyang_si: '안양시', location_gyeonggi_bucheon_si: '부천시', location_gyeonggi_gwangmyeong_si: '광명시', location_gyeonggi_pyeongtaek_si: '평택시', location_gyeonggi_dongducheon_si: '동두천시', location_gyeonggi_ansan_si: '안산시', location_gyeonggi_goyang_si: '고양시', location_gyeonggi_gwacheon_si: '과천시', location_gyeonggi_guri: '구리시', location_gyeonggi_namyangju_si: '남양주시', location_gyeonggi_osan: '오산시', location_gyeonggi_siheung: '시흥시', location_gyeonggi_gunpo_si: '군포시', location_gyeonggi_uiwang_si: '의왕시', location_gyeonggi_hanam: '하남시', location_gyeonggi_yongin_si: '용인시', location_gyeonggi_paju: '파주시', location_gyeonggi_icheon: '이천시', location_gyeonggi_anseong_si: '안성시', location_gyeonggi_gimpo: '김포시', location_gyeonggi_hwaseong_si: '화성시', location_gyeonggi_gwangju: '광주시', location_gyeonggi_yangju_si: '양주시', location_gyeonggi_pocheon: '포천시', location_gyeonggi_yeoju: '여주시', location_gyeonggi_yeoncheon_gun: '연천군', location_gyeonggi_gapyeong_gun: '가평군', location_gyeonggi_yangpyeong: '양평군', location_gangwon: '강원', location_gangwon_chuncheon: '춘천시', location_gangwon_wonju: '원주시', location_gangwon_gangneung_si: '강릉시', location_gangwon_donghae: '동해시', location_gangwon_taebaek_si: '태백시', location_gangwon_sokcho: '속초시', location_gangwon_samcheok_si: '삼척시', location_gangwon_hongcheon: '홍천군', location_gangwon_hoengseong_gun: '횡성군', location_gangwon_yeongwol_gun: '영월군', location_gangwon_pyeongchang: '평창군', location_gangwon_jeongseon: '정선군', location_gangwon_cheolwon: '철원군', location_gangwon_hwacheon: '화천군', location_gangwon_yanggu: '양구군', location_gangwon_inje: '인제군', location_gangwon_goseong: '고성군', location_gangwon_yangyang: '양양군', location_chungcheongbuk: '충북', location_chungcheongbuk_cheongju: '청주시', location_chungcheongbuk_chungju: '충주시', location_chungcheongbuk_jecheon: '제천시', location_chungcheongbuk_boeun: '보은군', location_chungcheongbuk_okcheon: '옥천군', location_chungcheongbuk_yeongdong: '영동군', location_chungcheongbuk_jeungpyeong: '증평군', location_chungcheongbuk_jincheon: '진천군', location_chungcheongbuk_goesan: '괴산군', location_chungcheongbuk_eumseong: '음성군', location_chungcheongbuk_danyang: '단양군', location_chungcheongnam: '충남', location_chungcheongnam_cheonan: '천안시', location_chungcheongnam_gongju: '공주시', location_chungcheongnam_boryeong: '보령시', location_chungcheongnam_asan: '아산시', location_chungcheongnam_seosan: '서산시', location_chungcheongnam_nonsan: '논산시', location_chungcheongnam_gyeryong: '계룡시', location_chungcheongnam_dangjin: '당진시', location_chungcheongnam_geumsan: '금산군', location_chungcheongnam_buyeo: '부여군', location_chungcheongnam_seocheon: '서천군', location_chungcheongnam_cheongyang: '청양군', location_chungcheongnam_hongseong: '홍성군', location_chungcheongnam_yesan: '예산군', location_chungcheongnam_taean: '태안군', location_jeollabuk: '전북', location_jeollabuk_jeonju: '전주시', location_jeollabuk_gunsan_si: '군산시', location_jeollabuk_iksan: '익산시', location_jeollabuk_jeongeup: '정읍시', location_jeollabuk_namwon: '남원시', location_jeollabuk_gimje_si: '김제시', location_jeollabuk_wanju: '완주군', location_jeollabuk_jinan: '진안군', location_jeollabuk_muju: '무주군', location_jeollabuk_jangsu: '장수군', location_jeollabuk_imsil: '임실군', location_jeollabuk_sunchang: '순창군', location_jeollabuk_gochang: '고창군', location_jeollabuk_buan: '부안군', location_jeollanam: '전남', location_jeollanam_mokpo: '목포시', location_jeollanam_yosu: '여수시', location_jeollanam_suncheon_si: '순천시', location_jeollanam_naju: '나주시', location_jeollanam_gwangyang_si: '광양시', location_jeollanam_damyang: '담양군', location_jeollanam_gokseong: '곡성군', location_jeollanam_gurye: '구례군', location_jeollanam_goheung: '고흥군', location_jeollanam_boseong: '보성군', location_jeollanam_hwasun: '화순군', location_jeollanam_jangheung: '장흥군', location_jeollanam_gangjin: '강진군', location_jeollanam_haenam: '해남군', location_jeollanam_yeongam: '영암군', location_jeollanam_jindo: '무안군', location_jeollanam_muan: '함평군', location_jeollanam_hampyeong: '영광군', location_jeollanam_yeonggwang: '장성군', location_jeollanam_jangseong: '완도군', location_jeollanam_wando: '진도군', location_jeollanam_sinan: '신안군', location_gyeongsangbuk: '경북', location_gyeongsangbuk_pohang_si: '포항시', location_gyeongsangbuk_gyeongju_si: '경주시', location_gyeongsangbuk_gimcheon_si: '김천시', location_gyeongsangbuk_andong_si: '안동시', location_gyeongsangbuk_gumi_si: '구미시', location_gyeongsangbuk_yeongju_si: '영주시', location_gyeongsangbuk_yeongcheon_si: '영천시', location_gyeongsangbuk_sangju_si: '상주시', location_gyeongsangbuk_mungyeong_si: '문경시', location_gyeongsangbuk_gyeongsan_si: '경산시', location_gyeongsangbuk_gunwi: '군위군', location_gyeongsangbuk_uiseong: '의성군', location_gyeongsangbuk_cheongsong: '청송군', location_gyeongsangbuk_goryong: '영양군', location_gyeongsangbuk_yeongdeok: '영덕군', location_gyeongsangbuk_cheongdo: '청도군', location_gyeongsangbuk_golyeong: '고령군', location_gyeongsangbuk_seongju: '성주군', location_gyeongsangbuk_chilgok: '칠곡군', location_gyeongsangbuk_yecheon: '예천군', location_gyeongsangbuk_bonghwa: '봉화군', location_gyeongsangbuk_uljin: '울진군', location_gyeongsangbuk_ulleung: '울릉군', location_gyeongsangnam: '경남', location_gyeongsangnam_changwon_si: '창원시', location_gyeongsangnam_jinju: '진주시', location_gyeongsangnam_tongyeong_si: '통영시', location_gyeongsangnam_sacheon_si: '사천시', location_gyeongsangnam_gimhae_si: '김해시', location_gyeongsangnam_miryang_si: '밀양시', location_gyeongsangnam_geoje_si: '거제시', location_gyeongsangnam_yangsan_si: '양산시', location_gyeongsangnam_uiryeong: '의령군', location_gyeongsangnam_haman: '함안군', location_gyeongsangnam_changnyeong: '창녕군', location_gyeongsangnam_goseong: '고성군', location_gyeongsangnam_namhae: '남해군', location_gyeongsangnam_hadong: '하동군', location_gyeongsangnam_sancheong: '산청군', location_gyeongsangnam_hamyang: '함양군', location_gyeongsangnam_geochang: '거창군', location_gyeongsangnam_hapcheon: '합천군', location_jeju: '제주', location_jeju_jeju_si: '제주시', location_jeju_seogwipo: '서귀포시', EXPANSION_WEATHER_sunny: '맑음', EXPANSION_WEATHER_partly_cloudy: '구름조금', EXPANSION_WEATHER_mostly_cloudy: '구름많음', EXPANSION_WEATHER_cloudy: '흐림', EXPANSION_WEATHER_rainy: '비', EXPANSION_WEATHER_sleet: '진눈깨비', EXPANSION_WEATHER_snowy: '눈', EXPANSION_WEATHER_finedust_good: '좋음', EXPANSION_WEATHER_finedust_normal: '보통', EXPANSION_WEATHER_finedust_bad: '나쁨', EXPANSION_WEATHER_finedust_very_bad: '매우나쁨', EXPANSION_WEATHER_lowest_temperature: '최저기온(℃)', EXPANSION_WEATHER_highest_temperature: '최고기온(℃)', EXPANSION_WEATHER_humidity: '습도(%)', EXPANSION_WEATHER_precipitation: '강수량(mm)', EXPANSION_WEATHER_precipitation_probability: '강수확률(%)', EXPANSION_WEATHER_wind_speed: '풍속(m/s)', EXPANSION_WEATHER_temperature: '기온(℃)', EXPANSION_WEATHER_finedust: '미세먼지농도(㎍)', EXPANSION_FESTIVAL_title: '제목', EXPANSION_FESTIVAL_area: '지역', EXPANSION_FESTIVAL_start_date: '시작일', EXPANSION_FESTIVAL_end_date: '종료일', EXPANSION_FESTIVAL_address: '주소', EXPANSION_FESTIVAL_coordinate: '위치', EXPANSION_FESTIVAL_overview: '개요', EXPANSION_FESTIVAL_homepage: '홈페이지', no_data: '정보없음', no_sentence: '문장이 없습니다', sentence_over_20_charactor: '20자까지만 입력할 수 있습니다.', sentence_over_3000_charactor: '3000자까지만 입력할 수 있습니다.', sentence_over_2500_charactor: '2500자까지만 입력할 수 있습니다. ', unknown_sentence: '알 수 없는 문장입니다.', auto: '자동', korean: '한국어', english: '영어', spanish: '스페인어', french: '프랑스어', german: '독일어', russian: '러시아어', portuguese: '포르투갈어', hindi: '힌디어', japan: '일본어', thai: '태국어', vietnamese: '베트남', indonesian: '인도네시아어', chinese_simplified: '중국어간체', chinese_traditional: '중국어번체', italian: '이탈리아어', behaviorConduct01001: '태풍', behaviorConduct01002: '홍수', behaviorConduct01003: '호우', behaviorConduct01004: '강풍', behaviorConduct01005: '대설', behaviorConduct01006: '한파', behaviorConduct01007: '풍랑', behaviorConduct01008: '황사', behaviorConduct01009: '폭염', behaviorConduct01010: '가뭄', behaviorConduct01011: '지진', behaviorConduct01013: '해일', behaviorConduct01014: '산사태', behaviorConduct03002: '응급처치', behaviorConduct03003: '심폐소생술', behaviorConduct03004: '소화기사용법', behaviorConduct03016: '소화전사용법', behaviorConduct03005: '식중독', behaviorConduct03006: '산행안전', behaviorConduct03008: '실종유괴', behaviorConduct03009: '성폭력', behaviorConduct03010: '학교 폭력', behaviorConduct03011: '가정 폭력', behaviorConduct03012: '억류 및 납치', behaviorConduct03013: '교통사고', behaviorConduct03014: '승강기 안전사고', behaviorConduct03015: '미세먼지', behaviorConduct01001001: '태풍이 오기 전', behaviorConduct01001002: '태풍이 왔을 때', behaviorConduct01001003: '태풍이 지나간 후', behaviorConduct01002002: '홍수가 오기 전', behaviorConduct01002003: '홍수가 났을 때', behaviorConduct01002004: '홍수가 지나간 후', behaviorConduct01003002: '큰 비가 오기 전', behaviorConduct01003003: '큰 비가 내릴 때', behaviorConduct01003004: '큰 비가 그친 후', behaviorConduct01004001: '강풍이 오기 전', behaviorConduct01004002: '강풍 발생 시', behaviorConduct01005002: '대설이 오기 전', behaviorConduct01005003: '대설 내일 때', behaviorConduct01005004: '눈이 그친 후', behaviorConduct01006001: '한파가 오기 전', behaviorConduct01006002: '한파 왔을 때', behaviorConduct01007001: '풍랑이 험할 때', behaviorConduct01007002: '풍랑이 오기 전', behaviorConduct01008001: '황사가 오기 전', behaviorConduct01008002: '황사가 왔을 때', behaviorConduct01008003: '황사가 지나간 후', behaviorConduct01009001: '폭염이 오기 전', behaviorConduct01009002: '폭염이 왔을 때', behaviorConduct01010001: '가뭄이 왔을 때', behaviorConduct01011009: '지진이 오기 전', behaviorConduct01011010: '지진이 왔을 때', behaviorConduct01011012: '지진 대피 후', behaviorConduct01013002: '해일이 오기 전', behaviorConduct01013003: '해일이 왔을 때', behaviorConduct01014001: '산사태가 오기 전', behaviorConduct03002002: '화상 처치', behaviorConduct03002003: '고열 예방', behaviorConduct03002004: '뱀에 물렸을 때 처치', behaviorConduct03002005: '벌에 쏘였을 때 처치', behaviorConduct03002006: '과호흡증후군 응급처치', behaviorConduct03003001: '성인 심폐소생술', behaviorConduct03003002: '영유아 심폐소생술', behaviorConduct03003003: '자동제세동기 사용', behaviorConduct03004001: '분말소화기 사용', behaviorConduct03016001: '옥내소화전 사용', behaviorConduct03005001: '식중독 대처', behaviorConduct03006004: '산행 중 유의사항', behaviorConduct03006005: '산에서 안전한 캠핑', behaviorConduct03006002: '구조요청시 알리는', behaviorConduct03006003: '산행사고시 응급조치', behaviorConduct03008001: '실종유괴 예방', behaviorConduct03009001: '성폭력 예방', behaviorConduct03010001: '학교 폭력 예방', behaviorConduct03011001: '가정 폭력 예방', behaviorConduct03012001: '억류 및 납치 시 대처', behaviorConduct03013002: '교통사고 발생 시 대처', behaviorConduct03013005: '차량에서의 구조', behaviorConduct03014001: '승강기 안전 이용', behaviorConduct03014003: '승강기 고장시 대처', behaviorConduct03014004: '에스컬레이터 안전 이용', behaviorConduct03015007: '미세먼지 많은 날 생활', behaviorConduct03015003: '부문별 생활', tts_female: '여성', tts_male: '남성', tts_kind: '친절한', tts_sweet: '감미로운', tts_echo: '울리는', tts_mischievous: '장난스러운', tts_dainty: '앙증맞은', tts_veryslow: '매우 느린', tts_slow: '느린', tts_normal: '보통', tts_fast: '빠른', tts_veryfast: '매우 빠른', tts_verylow: '매우 낮은', tts_low: '낮은', tts_high: '높은', tts_veryhigh: '매우 높은', ARDUINO: '하드웨어', ARDUINO_download_connector: '• 연결 프로그램 다운로드', ARDUINO_open_connector: '연결 프로그램 열기', ARDUINO_download_source: '• 엔트리 아두이노 소스', ARDUINO_reconnect: '하드웨어 연결하기', arduino_noti_text: '모바일 기기는 추후 지원 합니다.', arduino_lite_reconnect: '하드웨어 다시 연결', arduino_lite_download_firmware: '펌웨어 다운로드', arduino_lite_download_driver: '드라이버 다운로드', arduino_lite_connect: '브라우저로 연결하기', arduino_lite_disconnect: '하드웨어 선택 취소', arduino_lite_guide: '• 아두이노 연결 가이드', ROBOT_reconnect: '로봇 연결하기', ARDUINO_program: '프로그램 실행하기', ARDUINO_cloud_pc_connector: '클라우드 PC 연결하기', ARDUINO_connected: '하드웨어가 연결되었습니다. ', ARDUINO_connect: '* 하드웨어를 연결하세요.', ARDUINO_arduino_get_number_1: '신호', ARDUINO_arduino_get_number_2: '의 숫자 결괏값', ARDUINO_arduino_get_sensor_number_0: 'A0', ARDUINO_arduino_get_sensor_number_1: 'A1', ARDUINO_arduino_get_sensor_number_2: 'A2', ARDUINO_arduino_get_sensor_number_3: 'A3', ARDUINO_arduino_get_sensor_number_4: 'A4', ARDUINO_arduino_get_sensor_number_5: 'A5', blacksmith_toggle_on: '켜기', blacksmith_toggle_off: '끄기', blacksmith_lcd_first_line: '첫 번째', blacksmith_lcd_seconds_line: '두 번째', BITBRICK_light: '밝기 센서', BITBRICK_IR: '적외선 센서', BITBRICK_touch: '버튼', BITBRICK_potentiometer: '가변저항', BITBRICK_MIC: '소리 센서', BITBRICK_UserSensor: '사용자 입력', BITBRICK_UserInput: '사용자 입력', BITBRICK_dc_direction_ccw: '반시계', BITBRICK_dc_direction_cw: '시계', chocopi_control_event_pressed: '누를 때', chocopi_control_event_released: '뗄 때', chocopi_joystick_X: '조이스틱 좌우', chocopi_joystick_Y: '조이스틱 상하', chocopi_motion_photogate_event_blocked: '막았을 때', chocopi_motion_photogate_event_unblocked: '열었을 때', chocopi_motion_photogate_time_blocked: '막은 시간', chocopi_motion_photogate_time_unblocked: '연 시간', chocopi_port: '포트', chocopi_pot: '볼륨', chocopi_touch_event_touch: '만질 때', chocopi_touch_event_untouch: '뗄 때', CODEino_get_sensor_number_0: '0', CODEino_get_sensor_number_1: '1', CODEino_get_sensor_number_2: '2', CODEino_get_sensor_number_3: '3', CODEino_get_sensor_number_4: '4', CODEino_get_sensor_number_5: '5', CODEino_get_sensor_number_6: '6', CODEino_sensor_name_0: '소리', CODEino_sensor_name_1: '빛', CODEino_sensor_name_2: '슬라이더', CODEino_sensor_name_3: '저항-A', CODEino_sensor_name_4: '저항-B', CODEino_sensor_name_5: '저항-C', CODEino_sensor_name_6: '저항-D', CODEino_string_1: ' 센서값 ', CODEino_string_2: ' 보드의 ', CODEino_string_3: '버튼누름', CODEino_string_4: 'A 연결됨', CODEino_string_5: 'B 연결됨', CODEino_string_6: 'C 연결됨', CODEino_string_7: 'D 연결됨', CODEino_string_8: ' 3축 가속도센서 ', CODEino_string_9: '축의 센서값 ', CODEino_string_10: '소리센서 ', CODEino_string_11: '소리큼', CODEino_string_12: '소리작음', CODEino_string_13: '빛센서 ', CODEino_string_14: '밝음', CODEino_string_15: '어두움', CODEino_string_16: '왼쪽 기울임', CODEino_string_17: '오른쪽 기울임', CODEino_string_18: '위쪽 기울임', CODEino_string_19: '아래쪽 기울임', CODEino_string_20: '뒤집힘', CODEino_accelerometer_X: 'X', CODEino_accelerometer_Y: 'Y', CODEino_accelerometer_Z: 'Z', CODEino_led_red: '빨강', CODEino_led_green: '초록', CODEino_led_blue: '파랑', iboard_analog_number_0: 'A0', iboard_analog_number_1: 'A1', iboard_analog_number_2: 'A2', iboard_analog_number_3: 'A3', iboard_analog_number_4: 'A4', iboard_analog_number_5: 'A5', iboard_light: '빛센서가 ', iboard_num_pin_1: 'LED 상태를', iboard_num_pin_2: '번 스위치가', iboard_num_pin_3: '아날로그', iboard_num_pin_4: '번 ', iboard_num_pin_5: '센서값', iboard_string_1: '켜짐', iboard_string_2: '꺼짐', iboard_string_3: '밝음', iboard_string_4: '어두움', iboard_string_5: '눌림', iboard_string_6: '열림', iboard_switch: '스위치 ', iboard_tilt: '기울기센서 상태가', dplay_switch: '스위치 ', dplay_light: '빛센서가 ', dplay_tilt: '기울기센서 상태가', dplay_string_1: '켜짐', dplay_string_2: '꺼짐', dplay_string_3: '밝음', dplay_string_4: '어두움', dplay_string_5: '눌림', dplay_string_6: '열림', dplay_num_pin_1: 'LED 상태를', dplay_num_pin_2: '번 스위치가', dplay_num_pin_3: '아날로그', dplay_num_pin_4: '번 ', dplay_num_pin_5: '센서값', dplay_analog_number_0: 'A0', dplay_analog_number_1: 'A1', dplay_analog_number_2: 'A2', dplay_analog_number_3: 'A3', dplay_analog_number_4: 'A4', dplay_analog_number_5: 'A5', ARDUINO_arduino_get_string_1: '신호', ARDUINO_arduino_get_string_2: '의 글자 결괏값', ARDUINO_arduino_send_1: '신호', ARDUINO_arduino_send_2: '보내기', ARDUINO_num_sensor_value_1: '', ARDUINO_num_sensor_value_2: '번 센서값', ARDUINO_get_digital_value_1: '', ARDUINO_num_pin_1: '', ARDUINO_num_pin_2: '번 LED', ARDUINO_toggle_pwm_1: '', ARDUINO_toggle_pwm_2: '번 Pin', ARDUINO_toggle_pwm_3: '', ARDUINO_on: '켜기', ARDUINO_convert_scale_1: '', ARDUINO_convert_scale_2: '값의 범위를', ARDUINO_convert_scale_3: '~', ARDUINO_convert_scale_4: '에서', ARDUINO_convert_scale_5: '~', ARDUINO_convert_scale_6: '(으)로 바꾼값', ARDUINO_off: '끄기', EXPANSION: '확장', brightness: '밝기', BRUSH: '붓', BRUSH_brush_erase_all: '모든 붓 지우기', BRUSH_change_opacity_1: '붓의 투명도를', BRUSH_change_opacity_2: '% 만큼 바꾸기', BRUSH_change_thickness_1: '붓의 굵기를', BRUSH_change_thickness_2: '만큼 바꾸기', BRUSH_set_color_1: '붓의 색을', BRUSH_set_color_2: '(으)로 정하기', BRUSH_set_opacity_1: '붓의 투명도를', BRUSH_set_opacity_2: '% 로 정하기', BRUSH_set_random_color: '붓의 색을 무작위로 정하기', BRUSH_set_thickness_1: '붓의 굵기를', BRUSH_set_thickness_2: '로 정하기', BRUSH_stamp: '도장 찍기', BRUSH_start_drawing: '그리기 시작하기', BRUSH_stop_drawing: '그리기 멈추기', CALC: '계산', CALC_calc_mod_1: '', CALC_calc_mod_2: '/', CALC_calc_mod_3: '의 나머지', CALC_calc_operation_of_1: '', CALC_calc_operation_of_2: '의', CALC_calc_operation_root: '루트', CALC_calc_operation_square: '제곱', CALC_calc_rand_1: '', CALC_calc_rand_2: '부터', CALC_calc_rand_3: '사이에서의 무작위 수', CALC_calc_share_1: '', CALC_calc_share_2: '/', CALC_calc_share_3: '의 몫', CALC_coordinate_mouse_1: '마우스', CALC_coordinate_mouse_2: '좌표', CALC_coordinate_object_1: '', CALC_coordinate_object_2: '의', CALC_coordinate_object_3: '', CALC_distance_something_1: '', CALC_distance_something_2: '까지의 거리', CALC_get_angle: '각도값', CALC_get_date_1: ' 현재', CALC_get_date_2: '', CALC_get_date_day: '일', CALC_get_date_hour: '시각(시)', CALC_get_date_minute: '시각(분)', CALC_get_date_month: '월', CALC_get_date_second: '시각(초)', CALC_get_date_day_of_week: '요일', CALC_get_date_year: '연도', CALC_get_sound_duration_1: '', CALC_get_sound_duration_2: '소리의 길이', CALC_get_timer_value: ' 초시계 값', CALC_get_x_coordinate: 'X 좌푯값', CALC_get_y_coordinate: 'Y 좌푯값', CALC_timer_reset: '초시계 초기화', CALC_timer_visible_1: '초시계', CALC_timer_visible_2: '', CALC_timer_visible_show: '보이기', CALC_timer_visible_hide: '숨기기', color: '색깔', FLOW: '흐름', FLOW__if_1: '만일', FLOW__if_2: '이라면', FLOW_create_clone_1: '', FLOW_create_clone_2: '의 복제본 만들기', FLOW_delete_clone: '이 복제본 삭제하기', FLOW_delete_clone_all: '모든 복제본 삭제하기', FLOW_if_else_1: '만일', FLOW_if_else_2: '이라면', FLOW_if_else_3: '아니면', FLOW_repeat_basic_1: '', FLOW_repeat_basic_2: '번 반복하기', FLOW_repeat_basic_errorMsg: '반복 횟수는 0보다 같거나 커야 합니다.', FLOW_repeat_inf: '무한 반복하기', FLOW_restart: '처음부터 다시 실행하기', FLOW_stop_object_1: '', FLOW_stop_object_2: '멈추기', FLOW_stop_object_all: '모두', FLOW_stop_object_this_object: '자신', FLOW_stop_object_this_thread: '이', FLOW_stop_object_other_thread: '자신의 다른', FLOW_stop_object_other_objects: '다른 오브젝트의', FLOW_stop_repeat: '반복 중단하기', FLOW_stop_run: '프로그램 끝내기', FLOW_wait_second_1: '', FLOW_wait_second_2: '초 기다리기', FLOW_wait_until_true_1: '', FLOW_wait_until_true_2: '이 될 때까지 기다리기', FLOW_when_clone_start: '복제본이 처음 생성되었을때', FUNC: '함수', ANALYSIS: '데이터분석', AI: '인공지능', JUDGEMENT: '판단', JUDGEMENT_boolean_and: '그리고', JUDGEMENT_boolean_not_1: '', JUDGEMENT_boolean_not_2: '(이)가 아니다', JUDGEMENT_boolean_or: '또는', JUDGEMENT_false: ' 거짓 ', JUDGEMENT_is_clicked: '마우스를 클릭했는가?', JUDGEMENT_is_object_clicked: '오브젝트를 클릭했는가?', JUDGEMENT_is_press_some_key_1: '', JUDGEMENT_is_press_some_key_2: '키가 눌러져 있는가?', JUDGEMENT_reach_something_1: '', JUDGEMENT_reach_something_2: '에 닿았는가?', JUDGEMENT_is_type_1: '(이)가', JUDGEMENT_is_type_2: '인가?', is_type_number: '숫자', JUDGEMENT_true: ' 참 ', LOOKS: '생김새', LOOKS_change_scale_percent_1: '크기를', LOOKS_change_scale_percent_2: '만큼 바꾸기', LOOKS_change_to_next_shape: '다음 모양으로 바꾸기', LOOKS_change_to_nth_shape_1: '', LOOKS_change_to_nth_shape_2: '모양으로 바꾸기', LOOKS_change_shape_prev: '이전', LOOKS_change_shape_next: '다음', LOOKS_change_to_near_shape_1: '', LOOKS_change_to_near_shape_2: '모양으로 바꾸기', LOOKS_dialog_1: '', LOOKS_dialog_2: '을(를)', LOOKS_dialog_3: '', LOOKS_dialog_time_1: '', LOOKS_dialog_time_2: '을(를)', LOOKS_dialog_time_3: '초 동안', LOOKS_dialog_time_4: '', LOOKS_erase_all_effects: '효과 모두 지우기', LOOKS_flip_x: '상하 모양 뒤집기', LOOKS_flip_y: '좌우 모양 뒤집기', LOOKS_hide: '모양 숨기기', LOOKS_remove_dialog: '말하기 지우기', LOOKS_set_effect_1: '', LOOKS_set_effect_2: '효과를', LOOKS_set_effect_3: '로 정하기', LOOKS_set_effect_volume_1: '', LOOKS_set_effect_volume_2: '효과를', LOOKS_set_effect_volume_3: '만큼 주기', LOOKS_set_object_order_1: '', LOOKS_set_object_order_2: '번째로 올라오기', LOOKS_set_scale_percent_1: '크기를', LOOKS_set_scale_percent_2: ' 로 정하기', LOOKS_show: '모양 보이기', mouse_pointer: '마우스포인터', MOVING: '움직임', MOVING_bounce_wall: '화면 끝에 닿으면 튕기기', MOVING_bounce_when_1: '', MOVING_bounce_when_2: '에 닿으면 튕기기', MOVING_flip_arrow_horizontal: '화살표 방향 좌우 뒤집기', MOVING_flip_arrow_vertical: '화살표 방향 상하 뒤집기', MOVING_locate_1: '', MOVING_locate_2: '위치로 이동하기', MOVING_locate_time_1: '', MOVING_locate_time_2: '초 동안', MOVING_locate_time_3: '위치로 이동하기', MOVING_locate_x_1: 'x:', MOVING_locate_x_2: '위치로 이동하기', MOVING_locate_xy_1: 'x:', MOVING_locate_xy_2: 'y:', MOVING_locate_xy_3: '위치로 이동하기', MOVING_locate_xy_time_1: '', MOVING_locate_xy_time_2: '초 동안 x:', MOVING_locate_xy_time_3: 'y:', MOVING_locate_xy_time_4: '위치로 이동하기', MOVING_locate_y_1: 'y:', MOVING_locate_y_2: '위치로 이동하기', MOVING_move_direction_1: '이동 방향으로', MOVING_move_direction_2: '만큼 움직이기', MOVING_move_direction_angle_1: '', MOVING_move_direction_angle_2: '방향으로', MOVING_move_direction_angle_3: '만큼 움직이기', MOVING_move_x_1: 'x 좌표를', MOVING_move_x_2: '만큼 바꾸기', MOVING_move_xy_time_1: '', MOVING_move_xy_time_2: '초 동안 x:', MOVING_move_xy_time_3: 'y:', MOVING_move_xy_time_4: '만큼 움직이기', MOVING_move_y_1: 'y 좌표를', MOVING_move_y_2: '만큼 바꾸기', MOVING_rotate_by_angle_1: '오브젝트를', MOVING_rotate_by_angle_2: '만큼 회전하기', MOVING_rotate_by_angle_dropdown_1: '', MOVING_rotate_by_angle_dropdown_2: '만큼 회전하기', MOVING_rotate_by_angle_time_1: '오브젝트를', MOVING_rotate_by_angle_time_2: '초 동안', MOVING_rotate_by_angle_time_3: '만큼 회전하기', MOVING_rotate_direction_1: '이동 방향을', MOVING_rotate_direction_2: '만큼 회전하기', MOVING_see_angle_1: '이동 방향을', MOVING_see_angle_2: '(으)로 정하기', MOVING_see_angle_direction_1: '오브젝트를', MOVING_see_angle_direction_2: '(으)로 정하기', MOVING_see_angle_object_1: '', MOVING_see_angle_object_2: '쪽 바라보기', MOVING_see_direction_1: '', MOVING_see_direction_2: '쪽 보기', MOVING_set_direction_by_angle_1: '방향을', MOVING_set_direction_by_angle_2: '(으)로 정하기', MOVING_add_direction_by_angle_1: '방향을', MOVING_add_direction_by_angle_2: '만큼 회전하기', MOVING_add_direction_by_angle_time_1: '방향을', MOVING_add_direction_by_angle_time_2: '초 동안', MOVING_add_direction_by_angle_time_3: '만큼 회전하기', no_target: '대상 없음', oneself: '자신', opacity: '투명도', SCENE: '장면', SOUND: '소리', SOUND_sound_silent_all: '모든 소리 멈추기', SOUND_sound_something_1: '소리', SOUND_sound_something_2: '재생하기', SOUND_sound_something_second_1: '소리', SOUND_sound_something_second_2: '', SOUND_sound_something_second_3: '초 재생하기', SOUND_sound_something_second_wait_1: '소리', SOUND_sound_something_second_wait_2: '', SOUND_sound_something_second_wait_3: '초 재생하고 기다리기', SOUND_sound_something_wait_1: '소리', SOUND_sound_something_wait_2: '재생하고 기다리기', SOUND_sound_volume_change_1: '소리 크기를', SOUND_sound_volume_change_2: '% 만큼 바꾸기', SOUND_sound_volume_set_1: '소리 크기를', SOUND_sound_volume_set_2: '% 로 정하기', speak: '말하기', think: '생각하기', START: '시작', START_add_message: '신호 추가하기', START_delete_message: '신호 삭제하기', START_message_cast: '신호 보내기', START_message_cast_1: '', START_message_cast_2: '신호 보내기', START_message_cast_wait: '신호 보내고 기다리기', START_message_send_wait_1: '', START_message_send_wait_2: '신호 보내고 기다리기', START_mouse_click_cancled: '마우스 클릭을 해제했을 때', START_mouse_clicked: '마우스를 클릭했을 때', START_press_some_key_1: '', START_press_some_key_2: '키를 눌렀을 때', START_press_some_key_down: '아래쪽 화살표', START_press_some_key_enter: '엔터', START_press_some_key_left: '왼쪽 화살표', START_press_some_key_right: '오른쪽 화살표', START_press_some_key_space: '스페이스', START_press_some_key_up: '위쪽 화살표', START_when_message_cast: '신호를 받았을 때', START_when_message_cast_1: '', START_when_message_cast_2: '신호를 받았을 때', START_when_object_click: '오브젝트를 클릭했을 때', START_when_object_click_canceled: '오브젝트 클릭을 해제했을 때', START_when_run_button_click: '시작하기 버튼을 클릭했을 때', START_when_scene_start: '장면이 시작했을때', START_when_some_key_click: '키를 눌렀을 때', TEXT: '글상자', TEXT_text: '엔트리', TEXT_text_append_1: '', TEXT_text_append_2: '라고 뒤에 이어쓰기', TEXT_text_flush: '텍스트 모두 지우기', TEXT_text_prepend_1: '', TEXT_text_prepend_2: '라고 앞에 추가하기', TEXT_text_write_1: '', TEXT_text_write_2: '라고 글쓰기', VARIABLE: '변수', VARIABLE_add_value_to_list: '', VARIABLE_add_value_to_list_1: '', VARIABLE_add_value_to_list_2: '항목을', VARIABLE_add_value_to_list_3: '에 추가하기', VARIABLE_ask_and_wait_1: '', VARIABLE_ask_and_wait_2: '을(를) 묻고 기다리기', VARIABLE_change_value_list_index: '', VARIABLE_change_value_list_index_1: '', VARIABLE_change_value_list_index_3: '번째 항목을', VARIABLE_change_value_list_index_2: '', VARIABLE_change_value_list_index_4: '(으)로 바꾸기', VARIABLE_change_variable: '변수 더하기', VARIABLE_change_variable_1: '', VARIABLE_change_variable_2: '에', VARIABLE_change_variable_3: '만큼 더하기', VARIABLE_change_variable_name: '변수 이름 바꾸기', VARIABLE_combine_something_1: '', VARIABLE_combine_something_2: '과(와)', VARIABLE_combine_something_3: '결합하기', VARIABLE_get_canvas_input_value: ' 대답 ', VARIABLE_get_variable: '변수', VARIABLE_get_variable_1: '값', VARIABLE_get_variable_2: '값', VARIABLE_get_y: 'Y 좌푯값', VARIABLE_hide_list: '', VARIABLE_hide_list_1: '리스트', VARIABLE_hide_list_2: '숨기기', VARIABLE_hide_variable: '변수값 숨기기', VARIABLE_hide_variable_1: '', VARIABLE_hide_variable_2: '숨기기', VARIABLE_insert_value_to_list: '', VARIABLE_insert_value_to_list_1: '', VARIABLE_insert_value_to_list_2: '을(를)', VARIABLE_insert_value_to_list_3: '의', VARIABLE_insert_value_to_list_4: '번째에 넣기', VARIABLE_length_of_list: '', VARIABLE_length_of_list_1: '', VARIABLE_length_of_list_2: '의 길이', VARIABLE_list: '리스트', VARIABLE_make_variable: '변수 만들기', VARIABLE_list_option_first: '첫번째', VARIABLE_list_option_last: '마지막', VARIABLE_list_option_random: '무작위', VARIABLE_remove_value_from_list: '', VARIABLE_remove_value_from_list_1: '', VARIABLE_remove_value_from_list_2: '번째 항목을', VARIABLE_remove_value_from_list_3: '에서 삭제하기', VARIABLE_remove_variable: '변수 삭제', VARIABLE_set_variable: '변수 정하기', VARIABLE_set_variable_1: '', VARIABLE_set_variable_2: '를', VARIABLE_set_variable_3: '로 정하기', VARIABLE_show_list: '', VARIABLE_show_list_1: '리스트', VARIABLE_show_list_2: '보이기', VARIABLE_show_variable: '변수값 보이기', VARIABLE_show_variable_1: '', VARIABLE_show_variable_2: '보이기', VARIABLE_value_of_index_from_list: '', VARIABLE_value_of_index_from_list_1: '', VARIABLE_value_of_index_from_list_2: '의', VARIABLE_value_of_index_from_list_3: '번째 항목', HAMSTER_hand_found: '손 찾음?', HAMSTER_sensor_left_proximity: '왼쪽 근접 센서', HAMSTER_sensor_right_proximity: '오른쪽 근접 센서', HAMSTER_sensor_left_floor: '왼쪽 바닥 센서', HAMSTER_sensor_right_floor: '오른쪽 바닥 센서', HAMSTER_sensor_acceleration_x: 'x축 가속도', HAMSTER_sensor_acceleration_y: 'y축 가속도', HAMSTER_sensor_acceleration_z: 'z축 가속도', HAMSTER_sensor_light: '밝기', HAMSTER_sensor_temperature: '온도', HAMSTER_sensor_signal_strength: '신호 세기', HAMSTER_sensor_input_a: '입력 A', HAMSTER_sensor_input_b: '입력 B', HAMSTER_move_forward_once: '말판 앞으로 한 칸 이동하기', HAMSTER_turn_once_1: '말판', HAMSTER_turn_once_2: '으로 한 번 돌기', HAMSTER_turn_once_left: '왼쪽', HAMSTER_turn_right: '오른쪽', HAMSTER_move_forward: '앞으로 이동하기', HAMSTER_move_backward: '뒤로 이동하기', HAMSTER_turn_around_1: '', HAMSTER_turn_around_2: '으로 돌기', HAMSTER_move_forward_for_secs_1: '앞으로', HAMSTER_move_forward_for_secs_2: '초 이동하기', HAMSTER_move_backward_for_secs_1: '뒤로', HAMSTER_move_backward_for_secs_2: '초 이동하기', HAMSTER_turn_for_secs_1: '', HAMSTER_turn_for_secs_2: '으로', HAMSTER_turn_for_secs_3: '초 돌기', HAMSTER_change_both_wheels_by_1: '왼쪽 바퀴', HAMSTER_change_both_wheels_by_2: '오른쪽 바퀴', HAMSTER_change_both_wheels_by_3: '만큼 바꾸기', HAMSTER_set_both_wheels_to_1: '왼쪽 바퀴', HAMSTER_set_both_wheels_to_2: '오른쪽 바퀴', HAMSTER_set_both_wheels_to_3: '(으)로 정하기', HAMSTER_change_wheel_by_1: '', HAMSTER_change_wheel_by_2: '바퀴', HAMSTER_change_wheel_by_3: '만큼 바꾸기', HAMSTER_left_wheel: '왼쪽', HAMSTER_right_wheel: '오른쪽', HAMSTER_both_wheels: '양쪽', HAMSTER_set_wheel_to_1: '', HAMSTER_set_wheel_to_2: '바퀴', HAMSTER_set_wheel_to_3: '(으)로 정하기', HAMSTER_follow_line_using_1: '', HAMSTER_follow_line_using_2: '선을', HAMSTER_follow_line_using_3: '바닥 센서로 따라가기', HAMSTER_left_floor_sensor: '왼쪽', HAMSTER_right_floor_sensor: '오른쪽', HAMSTER_both_floor_sensors: '양쪽', HAMSTER_follow_line_until_1: '', HAMSTER_follow_line_until_2: '선을 따라', HAMSTER_follow_line_until_3: '교차로까지 이동하기', HAMSTER_left_intersection: '왼쪽', HAMSTER_right_intersection: '오른쪽', HAMSTER_front_intersection: '앞쪽', HAMSTER_rear_intersection: '뒤쪽', HAMSTER_set_following_speed_to_1: '선 따라가기 속도를', HAMSTER_set_following_speed_to_2: '(으)로 정하기', HAMSTER_front: '앞쪽', HAMSTER_rear: '뒤쪽', HAMSTER_stop: '정지하기', HAMSTER_set_led_to_1: '', HAMSTER_set_led_to_2: 'LED를', HAMSTER_set_led_to_3: '으로 정하기', HAMSTER_left_led: '왼쪽', HAMSTER_right_led: '오른쪽', HAMSTER_both_leds: '양쪽', HAMSTER_clear_led_1: '', HAMSTER_clear_led_2: 'LED 끄기', HAMSTER_color_cyan: '하늘색', HAMSTER_color_magenta: '자주색', HAMSTER_color_black: '검은색', HAMSTER_color_white: '하얀색', HAMSTER_color_red: '빨간색', HAMSTER_color_yellow: '노란색', HAMSTER_color_green: '초록색', HAMSTER_color_blue: '파란색', HAMSTER_beep: '삐 소리내기', HAMSTER_change_buzzer_by_1: '버저 음을', HAMSTER_change_buzzer_by_2: '만큼 바꾸기', HAMSTER_set_buzzer_to_1: '버저 음을', HAMSTER_set_buzzer_to_2: '(으)로 하기', HAMSTER_clear_buzzer: '버저 끄기', HAMSTER_play_note_for_1: '', HAMSTER_play_note_for_2: '', HAMSTER_play_note_for_3: '음을', HAMSTER_play_note_for_4: '박자 연주하기', HAMSTER_rest_for_1: '', HAMSTER_rest_for_2: '박자 쉬기', HAMSTER_change_tempo_by_1: '연주 속도를', HAMSTER_change_tempo_by_2: '만큼 바꾸기', HAMSTER_set_tempo_to_1: '연주 속도를 분당', HAMSTER_set_tempo_to_2: '박자로 정하기', HAMSTER_set_port_to_1: '포트', HAMSTER_set_port_to_2: '를', HAMSTER_set_port_to_3: '으로 정하기', HAMSTER_change_output_by_1: '출력', HAMSTER_change_output_by_2: '를', HAMSTER_change_output_by_3: '만큼 바꾸기', HAMSTER_set_output_to_1: '출력', HAMSTER_set_output_to_2: '를', HAMSTER_set_output_to_3: '(으)로 정하기', HAMSTER_port_a: 'A', HAMSTER_port_b: 'B', HAMSTER_port_ab: 'A와 B', HAMSTER_analog_input: '아날로그 입력', HAMSTER_digital_input: '디지털 입력', HAMSTER_servo_output: '서보 출력', HAMSTER_pwm_output: 'PWM 출력', HAMSTER_digital_output: '디지털 출력', ROBOID_acceleration_x: 'x축 가속도', ROBOID_acceleration_y: 'y축 가속도', ROBOID_acceleration_z: 'z축 가속도', ROBOID_back: '뒤쪽', ROBOID_both: '양쪽', ROBOID_button: '버튼', ROBOID_buzzer: '버저', ROBOID_clicked: '클릭했는가', ROBOID_color_any: '아무 색', ROBOID_color_black: '검은색', ROBOID_color_blue: '파란색', ROBOID_color_green: '초록색', ROBOID_color_number: '색깔 번호', ROBOID_color_orange: '주황색', ROBOID_color_pattern: '색깔 패턴', ROBOID_color_purple: '자주색', ROBOID_color_red: '빨간색', ROBOID_color_sky_blue: '하늘색', ROBOID_color_violet: '보라색', ROBOID_color_white: '하얀색', ROBOID_color_yellow: '노란색', ROBOID_double_clicked: '더블클릭했는가', ROBOID_floor: '바닥 센서', ROBOID_head: '머리', ROBOID_head_color: '머리 색깔', ROBOID_left: '왼쪽', ROBOID_left_wheel: '왼쪽 바퀴', ROBOID_long_pressed: '길게~눌렀는가', ROBOID_note: '음표', ROBOID_right: '오른쪽', ROBOID_right_wheel: '오른쪽 바퀴', ROBOID_sound_beep: '삐', ROBOID_sound_birthday: '생일', ROBOID_sound_dibidibidip: '디비디비딥', ROBOID_sound_engine: '엔진', ROBOID_sound_good_job: '잘 했어요', ROBOID_sound_march: '행진', ROBOID_sound_random_beep: '무작위 삐', ROBOID_sound_robot: '로봇', ROBOID_sound_siren: '사이렌', ROBOID_tail: '꼬리', ROBOID_unit_cm: 'cm', ROBOID_unit_deg: '도', ROBOID_unit_pulse: '펄스', ROBOID_unit_sec: '초', ALBERT_hand_found: '손 찾음?', ALBERT_is_oid_1: '', ALBERT_is_oid_2: 'OID 값이', ALBERT_is_oid_3: '인가?', ALBERT_front_oid: '앞쪽', ALBERT_back_oid: '뒤쪽', ALBERT_sensor_left_proximity: '왼쪽 근접 센서', ALBERT_sensor_right_proximity: '오른쪽 근접 센서', ALBERT_sensor_acceleration_x: 'x축 가속도', ALBERT_sensor_acceleration_y: 'y축 가속도', ALBERT_sensor_acceleration_z: 'z축 가속도', ALBERT_sensor_light: '밝기', ALBERT_sensor_temperature: '온도', ALBERT_sensor_battery: '배터리', ALBERT_sensor_signal_strength: '신호 세기', ALBERT_sensor_front_oid: '앞쪽 OID', ALBERT_sensor_back_oid: '뒤쪽 OID', ALBERT_sensor_position_x: 'x 위치', ALBERT_sensor_position_y: 'y 위치', ALBERT_sensor_orientation: '방향', ALBERT_move_forward: '앞으로 이동하기', ALBERT_move_backward: '뒤로 이동하기', ALBERT_turn_around_1: '', ALBERT_turn_around_2: '으로 돌기', ALBERT_move_forward_for_secs_1: '앞으로', ALBERT_move_forward_for_secs_2: '초 이동하기', ALBERT_move_backward_for_secs_1: '뒤로', ALBERT_move_backward_for_secs_2: '초 이동하기', ALBERT_turn_for_secs_1: '', ALBERT_turn_for_secs_2: '으로', ALBERT_turn_for_secs_3: '초 돌기', ALBERT_turn_left: '왼쪽', ALBERT_turn_right: '오른쪽', ALBERT_change_both_wheels_by_1: '왼쪽 바퀴', ALBERT_change_both_wheels_by_2: '오른쪽 바퀴', ALBERT_change_both_wheels_by_3: '만큼 바꾸기', ALBERT_left_wheel: '왼쪽', ALBERT_right_wheel: '오른쪽', ALBERT_both_wheels: '양쪽', ALBERT_set_both_wheels_to_1: '왼쪽 바퀴', ALBERT_set_both_wheels_to_2: '오른쪽 바퀴', ALBERT_set_both_wheels_to_3: '(으)로 정하기', ALBERT_change_wheel_by_1: '', ALBERT_change_wheel_by_2: '바퀴', ALBERT_change_wheel_by_3: '만큼 바꾸기', ALBERT_set_wheel_to_1: '', ALBERT_set_wheel_to_2: '바퀴', ALBERT_set_wheel_to_3: '(으)로 정하기', ALBERT_stop: '정지하기', ALBERT_set_board_size_to_1: '말판 크기를 폭', ALBERT_set_board_size_to_2: '높이', ALBERT_set_board_size_to_3: '(으)로 정하기', ALBERT_move_to_x_y_1: '말판 x:', ALBERT_move_to_x_y_2: 'y:', ALBERT_move_to_x_y_3: '위치로 이동하기', ALBERT_set_orientation_to_1: '말판', ALBERT_set_orientation_to_2: '방향으로 바라보기', ALBERT_set_eye_to_1: '', ALBERT_set_eye_to_2: '눈을', ALBERT_set_eye_to_3: '으로 정하기', ALBERT_left_eye: '왼쪽', ALBERT_right_eye: '오른쪽', ALBERT_both_eyes: '양쪽', ALBERT_clear_eye_1: '', ALBERT_clear_eye_2: '눈 끄기', ALBERT_body_led_1: '몸통 LED', ALBERT_body_led_2: '', ALBERT_front_led_1: '앞쪽 LED', ALBERT_front_led_2: '', ALBERT_color_cyan: '하늘색', ALBERT_color_magenta: '보라색', ALBERT_color_white: '하얀색', ALBERT_color_red: '빨간색', ALBERT_color_yellow: '노란색', ALBERT_color_green: '초록색', ALBERT_color_blue: '파란색', ALBERT_note_c: '도', ALBERT_note_d: '레', ALBERT_note_e: '미', ALBERT_note_f: '파', ALBERT_note_g: '솔', ALBERT_note_a: '라', ALBERT_note_b: '시', ALBERT_turn_body_led_1: '몸통 LED', ALBERT_turn_body_led_2: '', ALBERT_turn_front_led_1: '앞쪽 LED', ALBERT_turn_front_led_2: '', ALBERT_turn_on: '켜기', ALBERT_turn_off: '끄기', ALBERT_beep: '삐 소리내기', ALBERT_change_buzzer_by_1: '버저 음을', ALBERT_change_buzzer_by_2: '만큼 바꾸기', ALBERT_set_buzzer_to_1: '버저 음을', ALBERT_set_buzzer_to_2: '(으)로 정하기', ALBERT_clear_buzzer: '버저 끄기', ALBERT_play_note_for_1: '', ALBERT_play_note_for_2: '', ALBERT_play_note_for_3: '음을', ALBERT_play_note_for_4: '박자 연주하기', ALBERT_rest_for_1: '', ALBERT_rest_for_2: '박자 쉬기', ALBERT_change_tempo_by_1: '연주 속도를', ALBERT_change_tempo_by_2: '만큼 바꾸기', ALBERT_set_tempo_to_1: '연주 속도를 분당', ALBERT_set_tempo_to_2: '박자로 정하기', VARIABLE_variable: '변수', wall: '벽', robotis_common_case_01: '(을)를', robotis_common_set: '(으)로 정하기', robotis_common_value: '값', robotis_common_clockwhise: '시계방향', robotis_common_counter_clockwhise: '반시계방향', robotis_common_wheel_mode: '회전모드', robotis_common_joint_mode: '관절모드', robotis_common_red_color: '빨간색', robotis_common_green_color: '녹색', robotis_common_blue_color: '파란색', robotis_common_on: '켜기', robotis_common_off: '끄기', robotis_common_cm: '제어기', robotis_common_port_1: '포트 1', robotis_common_port_2: '포트 2', robotis_common_port_3: '포트 3', robotis_common_port_4: '포트 4', robotis_common_port_5: '포트 5', robotis_common_port_6: '포트 6', robotis_common_play_buzzer: '연주', robotis_common_play_motion: '실행', robotis_common_motion: '모션', robotis_common_index_number: '번', robotis_common_left: '왼쪽', robotis_common_right: '오른쪽', robotis_common_minute: '분', robotis_cm_custom: '직접입력 주소', robotis_cm_spring_left: '왼쪽 접촉 센서', robotis_cm_spring_right: '오른쪽 접촉 센서', robotis_cm_led_left: '왼쪽 LED', robotis_cm_led_right: '오른쪽 LED', robotis_cm_led_both: '양 쪽 LED', robotis_cm_switch: '선택 버튼 상태', robotis_cm_user_button: '사용자 버튼 상태', robotis_cm_sound_detected: '최종 소리 감지 횟수', robotis_cm_sound_detecting: '실시간 소리 감지 횟수', robotis_cm_ir_left: '왼쪽 적외선 센서', robotis_cm_ir_right: '오른쪽 적외선 센서', robotis_cm_calibration_left: '왼쪽 적외선 센서 캘리브레이션 값', robotis_cm_calibration_right: '오른쪽 적외선 센서 캘리브레이션 값', robotis_cm_clear_sound_detected: '최종소리감지횟수 초기화', robotis_cm_buzzer_index: '음계값', robotis_cm_buzzer_melody: '멜로디', robotis_cm_led_1: '1번 LED', robotis_cm_led_4: '4번 LED', robotis_aux_servo_position: '서보모터 위치', robotis_aux_ir: '적외선센서', robotis_aux_touch: '접촉센서', robotis_aux_brightness: '조도센서(CDS)', robotis_aux_hydro_themo_humidity: '온습도센서(습도)', robotis_aux_hydro_themo_temper: '온습도센서(온도)', robotis_aux_temperature: '온도센서', robotis_aux_ultrasonic: '초음파센서', robotis_aux_magnetic: '자석센서', robotis_aux_motion_detection: '동작감지센서', robotis_aux_color: '컬러센서', robotis_aux_custom: '사용자 장치', robotis_carCont_aux_motor_speed_1: '감속모터 속도를', robotis_carCont_aux_motor_speed_2: ', 출력값을', robotis_carCont_calibration_1: '적외선 센서 캘리브레이션 값을', robotis_openCM70_aux_motor_speed_1: '감속모터 속도를', robotis_openCM70_aux_motor_speed_2: ', 출력값을', robotis_openCM70_aux_servo_mode_1: '서보모터 모드를', robotis_openCM70_aux_servo_speed_1: '서보모터 속도를', robotis_openCM70_aux_servo_speed_2: ', 출력값을', robotis_openCM70_aux_servo_position_1: '서보모터 위치를', robotis_openCM70_aux_led_module_1: 'LED 모듈을', robotis_openCM70_aux_custom_1: '사용자 장치를', XBOT_digital: '디지털', XBOT_D2_digitalInput: 'D2 디지털 입력', XBOT_D3_digitalInput: 'D3 디지털 입력', XBOT_D11_digitalInput: 'D11 디지털 입력', XBOT_analog: '아날로그', XBOT_CDS: '광 센서 값', XBOT_MIC: '마이크 센서 값', XBOT_analog0: '아날로그 0번 핀 값', XBOT_analog1: '아날로그 1번 핀 값', XBOT_analog2: '아날로그 2번 핀 값', XBOT_analog3: '아날로그 3번 핀 값', XBOT_Value: '출력 값', XBOT_pin_OutputValue: '핀, 출력 값', XBOT_High: '높음', XBOT_Low: '낮음', XBOT_Servo: '서보 모터', XBOT_Head: '머리(D8)', XBOT_ArmR: '오른 팔(D9)', XBOT_ArmL: '왼 팔(D10)', XBOT_angle: ', 각도', XBOT_DC: '바퀴(DC) 모터', XBOT_rightWheel: '오른쪽', XBOT_leftWheel: '왼쪽', XBOT_bothWheel: '양쪽', XBOT_speed: ', 속도', XBOT_rightSpeed: '바퀴(DC) 모터 오른쪽(2) 속도:', XBOT_leftSpeed: '왼쪽(1) 속도:', XBOT_RGBLED_R: 'RGB LED 켜기 R 값', XBOT_RGBLED_G: 'G 값', XBOT_RGBLED_B: 'B 값', XBOT_RGBLED_color: 'RGB LED 색', XBOT_set: '로 정하기', XBOT_c: '도', XBOT_d: '레', XBOT_e: '미', XBOT_f: '파', XBOT_g: '솔', XBOT_a: '라', XBOT_b: '시', XBOT_melody_ms: '초 연주하기', XBOT_Line: '번째 줄', XBOT_outputValue: '출력 값', roborobo_num_analog_value_1: '아날로그', roborobo_num_analog_value_2: '번 센서값', roborobo_get_digital_value_1: '디지털', roborobo_num_pin_1: '디지털', roborobo_num_pin_2: '번 핀', roborobo_on: '켜기', roborobo_off: '끄기', roborobo_motor1: '모터1', roborobo_motor2: '모터2', roborobo_motor_CW: '정회전', roborobo_motor_CCW: '역회전', roborobo_motor_stop: '정지', roborobo_input_mode: '입력', roborobo_output_mode: '출력', roborobo_pwm_mode: '전류조절(pwm)', roborobo_servo_mode: '서보모터', roborobo_color: '컬러센서', roborobo_color_red: ' 빨간색 ', roborobo_color_green: ' 녹색 ', roborobo_color_blue: ' 파란색 ', roborobo_color_yellow: ' 노란색 ', roborobo_color_detected: ' 감지 ', roborobo_degree: ' ˚', robotori_D2_Input: '디지털 2번 핀 입력 값', robotori_D3_Input: '디지털 3번 핀 입력 값', robotori_A0_Input: '아날로그 0번 핀 입력 값', robotori_A1_Input: '아날로그 1번 핀 입력 값', robotori_A2_Input: '아날로그 2번 핀 입력 값', robotori_A3_Input: '아날로그 3번 핀 입력 값', robotori_A4_Input: '아날로그 4번 핀 입력 값', robotori_A5_Input: '아날로그 5번 핀 입력 값', robotori_digital: '디지털', robotori_D10_Output: '10번', robotori_D11_Output: '11번', robotori_D12_Output: '12번', robotori_D13_Output: '13번', robotori_pin_OutputValue: '핀, 출력 값', robotori_On: '켜짐', robotori_Off: '꺼짐', robotori_analog: '아날로그', robotori_analog5: '5번 핀 출력 값', robotori_analog6: '6번 핀 출력 값', robotori_analog9: '9번 핀 출력 값', robotori_Servo: '서보모터', robotori_DC: 'DC모터', robotori_DC_rightmotor: '오른쪽', robotori_DC_leftmotor: '왼쪽', robotori_DC_STOP: '정지', robotori_DC_CW: '시계방향', robotori_DC_CCW: '반시계방향', robotori_DC_select: '회전', CALC_rotation_value: '방향값', CALC_direction_value: '이동 방향값', VARIABLE_is_included_in_list: '', VARIABLE_is_included_in_list_1: '', VARIABLE_is_included_in_list_2: '에', VARIABLE_is_included_in_list_3: '이 포함되어 있는가?', SCENE_when_scene_start: '장면이 시작되었을 때', SCENE_start_scene_1: '', SCENE_start_scene_2: '시작하기', SCENE_start_neighbor_scene_1: '', SCENE_start_neighbor_scene_2: '장면 시작하기', SCENE_start_scene_pre: '이전', SCENE_start_scene_next: '다음', FUNCTION_explanation_1: '이름', FUNCTION_character_variable: '문자/숫자값', FUNCTION_logical_variable: '판단값', FUNCTION_function: '함수', FUNCTION_define: '함수 정의하기', CALC_calc_operation_sin: '사인값', CALC_calc_operation_cos: '코사인값', CALC_calc_operation_tan: '탄젠트값', CALC_calc_operation_floor: '소수점 버림값', CALC_calc_operation_ceil: '소수점 올림값', CALC_calc_operation_round: '소수점 반올림값', CALC_calc_operation_factorial: '펙토리얼값', CALC_calc_operation_asin: '아크사인값', CALC_calc_operation_acos: '아크코사인값', CALC_calc_operation_atan: '아크탄젠트값', CALC_calc_operation_log: '로그값', CALC_calc_operation_ln: '자연로그값', CALC_calc_operation_natural: '정수 부분', CALC_calc_operation_unnatural: '소수점 부분', MOVING_locate_object_time_1: '', MOVING_locate_object_time_2: '초 동안', MOVING_locate_object_time_3: '위치로 이동하기', wall_up: '위쪽 벽', wall_down: '아래쪽 벽', wall_right: '오른쪽 벽', wall_left: '왼쪽 벽', CALC_coordinate_x_value: 'x 좌푯값', CALC_coordinate_y_value: 'y 좌푯값', CALC_coordinate_rotation_value: '방향', CALC_coordinate_direction_value: '이동방향', CALC_picture_index: '모양 번호', CALC_picture_name: '모양 이름', FLOW_repeat_while_true_1: '', FLOW_repeat_while_true_2: ' 반복하기', TUT_when_start: '프로그램 실행을 클릭했을때', TUT_move_once: '앞으로 한 칸 이동', TUT_rotate_left: '왼쪽으로 회전', TUT_rotate_right: '오른쪽으로 회전', TUT_jump_barrier: '장애물 뛰어넘기', TUT_repeat_tutorial_1: '', TUT_repeat_tutorial_2: '번 반복', TUT_if_barrier_1: '만약 앞에', TUT_if_barrier_2: ' 이 있다면', TUT_if_conical_1: '만약 앞에', TUT_if_conical_2: ' 이 있다면', TUT_repeat_until: '부품에 도달할 때 까지 반복', TUT_repeat_until_gold: '부품에 도달할 때 까지 반복', TUT_declare_function: '함수 선언', TUT_call_function: '함수 호출', CALC_calc_operation_abs: '절댓값', CONTEXT_COPY_option: '코드 복사', Delete_Blocks: '코드 삭제', Duplication_option: '코드 복사 & 붙여넣기', Paste_blocks: '붙여넣기', add_my_storage: '나의 보관함에 추가하기', export_object: '오브젝트 내보내기', Clear_all_blocks: '모든 코드 삭제하기', add_comment: '메모 추가하기', copy_paste_comment: '메모 복사 & 붙여넣기', copy_comment: '메모 복사하기', delete_comment: '메모 삭제하기', fold_comment: '메모 접기', open_comment: '메모 열기', separate_comment: '메모 분리하기', hide_all_comment: '모든 메모 숨기기', show_all_comment: '모든 메모 보이기', transparency: '투명도', BRUSH_change_brush_transparency_1: '붓의 투명도를', BRUSH_change_brush_transparency_2: '% 만큼 바꾸기', BRUSH_set_brush_transparency_1: '붓의 투명도를', BRUSH_set_brush_transparency_2: '% 로 정하기', CALC_char_at_1: '', CALC_char_at_2: '의', CALC_char_at_3: '번째 글자', CALC_length_of_string_1: '', CALC_length_of_string_2: '의 글자 수', CALC_reverse_of_string_1: '', CALC_reverse_of_string_2: '을(를) 뒤집은 값', CALC_substring_1: '', CALC_substring_2: '의', CALC_substring_3: '번째 글자부터', length_of_string: '번째 글자부터', CALC_substring_4: '번째 글자까지의 글자', CALC_replace_string_1: '', CALC_replace_string_2: '의', CALC_replace_string_3: '을(를)', CALC_replace_string_4: '로 바꾸기', CALC_change_string_case_1: '', CALC_change_string_case_2: '의', CALC_change_string_case_3: ' ', CALC_change_string_case_sub_1: '대문자', CALC_change_string_case_sub_2: '소문자', CALC_count_match_string_1: '에서', CALC_count_match_string_2: '의 글자 수', CALC_index_of_string_1: '', CALC_index_of_string_2: '에서', CALC_index_of_string_3: '의 시작 위치', MOVING_add_direction_by_angle_time_explain_1: '', MOVING_direction_relative_duration_1: '', MOVING_direction_relative_duration_2: '초 동안 이동 방향', MOVING_direction_relative_duration_3: '만큼 회전하기', CALC_get_sound_volume: ' 소리 크기', SOUND_sound_from_to_1: '소리', SOUND_sound_from_to_2: '', SOUND_sound_from_to_3: '초 부터', SOUND_sound_from_to_4: '초까지 재생하기', SOUND_sound_from_to_and_wait_1: '소리', SOUND_sound_from_to_and_wait_2: '', SOUND_sound_from_to_and_wait_3: '초 부터', SOUND_sound_from_to_and_wait_4: '초까지 재생하고 기다리기', CALC_quotient_and_mod_1: '', CALC_quotient_and_mod_2: '/', CALC_quotient_and_mod_3: '의', CALC_quotient_and_mod_4: '', CALC_quotient_and_mod_sub_1: '몫', CALC_quotient_and_mod_sub_2: '나머지', self: '자신', CALC_coordinate_size_value: '크기', CALC_choose_project_timer_action_1: '초시계', CALC_choose_project_timer_action_2: '', CALC_choose_project_timer_action_sub_1: '시작하기', CALC_choose_project_timer_action_sub_2: '정지하기', CALC_choose_project_timer_action_sub_3: '초기화하기', LOOKS_change_object_index_1: '', LOOKS_change_object_index_2: '보내기', LOOKS_change_object_index_sub_1: '맨 앞으로', LOOKS_change_object_index_sub_2: '앞으로', LOOKS_change_object_index_sub_3: '뒤로', LOOKS_change_object_index_sub_4: '맨 뒤로', FLOW_repeat_while_true_until: '', FLOW_repeat_while_true_while: '', copy_block: '', delete_block: '', tidy_up_block: '코드 정리하기', block_hi: '안녕!', entry_bot_name: '엔트리봇', hi_entry: '', hi_entry_en: '', bark_dog: '', walking_entryBot: '엔트리봇_걷기', doggi_bark: '강아지 짖는 소리', entry: '엔트리', hello: '', nice: '', silent: '무음', do_name: '도', do_sharp_name: '도#(레♭)', re_name: '레', re_sharp_name: '레#(미♭)', mi_name: '미', fa_name: '파', fa_sharp_name: '파#(솔♭)', sol_name: '솔', sol_sharp_name: '솔#(라♭)', la_name: '라', la_sharp_name: '라#(시♭)', DUMMY: '더미', coconut_stop_motor: '모터 정지', coconut_move_motor: '움직이기', coconut_turn_motor: '으로 돌기', coconut_move_outmotor: '외부모터', coconut_turn_left: '왼쪽', coconut_turn_right: '오른쪽', coconut_move_forward: '앞으로', coconut_move_backward: '뒤로', coconut_note_c: '도', coconut_note_d: '레', coconut_note_e: '미', coconut_note_f: '파', coconut_note_g: '솔', coconut_note_a: '라', coconut_note_b: '시', coconut_move_speed_1: '0', coconut_move_speed_2: '50', coconut_move_speed_3: '100', coconut_move_speed_4: '150', coconut_move_speed_5: '255', coconut_play_buzzer_hn: '2분음표', coconut_play_buzzer_qn: '4분음표', coconut_play_buzzer_en: '8분음표', coconut_play_buzzer_sn: '16분음표', coconut_play_buzzer_tn: '32분음표', coconut_play_buzzer_wn: '온음표', coconut_play_buzzer_dhn: '점2분음표', coconut_play_buzzer_dqn: '점4분음표', coconut_play_buzzer_den: '점8분음표', coconut_play_buzzer_dsn: '점16분음표', coconut_play_buzzer_dtn: '점32분음표', coconut_rest_buzzer_hr: '2분쉼표', coconut_rest_buzzer_qr: '4분쉼표', coconut_rest_buzzer_er: '8분쉼표', coconut_rest_buzzer_sr: '16분쉼표', coconut_rest_buzzer_tr: '32분쉼표', coconut_rest_buzzer_wr: '온쉼표', coconut_play_midi_1: '반짝반짝 작은별', coconut_play_midi_2: '곰세마리', coconut_play_midi_3: '모차르트 자장가', coconut_play_midi_4: '도레미송', coconut_play_midi_5: '나비야', coconut_floor_sensing_on: '감지', coconut_floor_sensing_off: '미감지', coconut_dotmatrix_set_on: '켜짐', coconut_dotmatrix_set_off: '꺼짐', coconut_dotmatrix_row_0: '모든', coconut_dotmatrix_row_1: '1', coconut_dotmatrix_row_2: '2', coconut_dotmatrix_row_3: '3', coconut_dotmatrix_row_4: '4', coconut_dotmatrix_row_5: '5', coconut_dotmatrix_row_6: '6', coconut_dotmatrix_row_7: '7', coconut_dotmatrix_row_8: '8', coconut_dotmatrix_col_0: '모든', coconut_dotmatrix_col_1: '1', coconut_dotmatrix_col_2: '2', coconut_dotmatrix_col_3: '3', coconut_dotmatrix_col_4: '4', coconut_dotmatrix_col_5: '5', coconut_dotmatrix_col_6: '6', coconut_dotmatrix_col_7: '7', coconut_dotmatrix_col_8: '8', coconut_sensor_left_proximity: '왼쪽 전방 센서', coconut_sensor_right_proximity: '오른쪽 전방 센서', coconut_sensor_both_proximity: '모든', coconut_sensor_left_floor: '왼쪽 바닥센서', coconut_sensor_right_floor: '오른쪽 바닥 센서', coconut_sensor_both_floor: '모든', coconut_sensor_acceleration_x: 'x축 가속도', coconut_sensor_acceleration_y: 'y축 가속도', coconut_sensor_acceleration_z: 'z축 가속도', coconut_sensor_light: '밝기', coconut_sensor_temperature: '온도', coconut_left_led: '왼쪽', coconut_right_led: '오른쪽', coconut_both_leds: '모든', coconut_color_cyan: '하늘색', coconut_color_magenta: '보라색', coconut_color_black: '검은색', coconut_color_white: '흰색', coconut_color_red: '빨간색', coconut_color_yellow: '노란색', coconut_color_green: '초록색', coconut_color_blue: '파란색', coconut_beep: '삐 소리내기', coconut_clear_buzzer: '버저 끄기', coconut_x_axis: 'X축', coconut_y_axis: 'Y축', coconut_z_axis: 'Z축', modi_enviroment_bule: '파랑', modi_enviroment_green: '초록', modi_enviroment_humidity: '습도', modi_enviroment_illuminance: '조도', modi_enviroment_red: '빨강', modi_enviroment_temperature: '온도', modi_gyroscope_xAcceleratior: 'X축 가속', modi_gyroscope_yAcceleratior: 'Y축 가속', modi_gyroscope_zAcceleratior: 'Z축 가속', modi_motor_angle: '각도', modi_motor_speed: '속도', modi_motor_torque: '회전', modi_speaker_F_DO_5: '도5', modi_speaker_F_DO_6: '도6', modi_speaker_F_DO_7: '도7', modi_speaker_F_DO_S_5: '도#5', modi_speaker_F_DO_S_6: '도#6', modi_speaker_F_DO_S_7: '도#7', modi_speaker_F_MI_5: '미5', modi_speaker_F_MI_6: '미6', modi_speaker_F_MI_7: '미7', modi_speaker_F_PA_5: '파5', modi_speaker_F_PA_6: '파6', modi_speaker_F_PA_7: '파7', modi_speaker_F_PA_S_5: '파#5', modi_speaker_F_PA_S_6: '파#6', modi_speaker_F_PA_S_7: '파#7', modi_speaker_F_RA_5: '라5', modi_speaker_F_RA_6: '라6', modi_speaker_F_RA_7: '라7', modi_speaker_F_RA_S_5: '라#5', modi_speaker_F_RA_S_6: '라#6', modi_speaker_F_RA_S_7: '라#7', modi_speaker_F_RE_5: '레5', modi_speaker_F_RE_6: '레6', modi_speaker_F_RE_7: '레7', modi_speaker_F_RE_S_5: '라#5', modi_speaker_F_RE_S_6: '레#6', modi_speaker_F_RE_S_7: '레#7', modi_speaker_F_SOL_5: '솔5', modi_speaker_F_SOL_6: '솔6', modi_speaker_F_SOL_7: '솔7', modi_speaker_F_SOL_S_5: '솔#5', modi_speaker_F_SOL_S_6: '솔#6', modi_speaker_F_SOL_S_7: '솔#7', modi_speaker_F_SO_5: '시5', modi_speaker_F_SO_6: '시6', modi_speaker_F_SO_7: '시7', si_name: '시', ev3_ccw: '반시계', ev3_cw: '시계', rokoboard_sensor_name_0: '소리', rokoboard_sensor_name_1: '빛', rokoboard_sensor_name_2: '슬라이더', rokoboard_sensor_name_3: '저항-A', rokoboard_sensor_name_4: '저항-B', rokoboard_sensor_name_5: '저항-C', rokoboard_sensor_name_6: '저항-D', rokoboard_string_1: '버튼을 눌렀는가?', HW_MOTOR: '모터', HW_SENSOR: '센서', HW_LED: '발광다이오드', HW_MELODY: '멜로디', HW_ROBOT: '로봇', ALTINO_ACCX: '가속도 X축', ALTINO_ACCY: '가속도 Y축', ALTINO_ACCZ: '가속도 Z축', ALTINO_BAT: '배터리 잔량 체크', ALTINO_CDS: '밝기', ALTINO_GYROX: '자이로 X축', ALTINO_GYROY: '자이로 Y축', ALTINO_GYROZ: '자이로 Z축', ALTINO_IR1: '1번 거리', ALTINO_IR2: '2번 거리', ALTINO_IR3: '3번 거리', ALTINO_IR4: '4번 거리', ALTINO_IR5: '5번 거리', ALTINO_IR6: '6번 거리', ALTINO_Led_Brake_Light: '브레이크', ALTINO_Led_Forward_Light: '전방', ALTINO_Led_Reverse_Light: '후방', ALTINO_Led_Turn_Left_Light: '왼쪽방향', ALTINO_Led_Turn_Right_Light: '오른쪽방향', ALTINO_Line: '번째 줄', ALTINO_MAGX: '나침판 X축', ALTINO_MAGY: '나침판 Y축', ALTINO_MAGZ: '나침판 Z축', ALTINO_REMOTE: '리모콘 수신 값', ALTINO_STTOR: '조향 토크', ALTINO_STVAR: '조향 가변저항', ALTINO_Steering_Angle_Center: '가운데', ALTINO_Steering_Angle_Left10: '왼쪽10', ALTINO_Steering_Angle_Left15: '왼쪽15', ALTINO_Steering_Angle_Left20: '왼쪽20', ALTINO_Steering_Angle_Left5: '왼쪽5', ALTINO_Steering_Angle_Right10: '오른쪽10', ALTINO_Steering_Angle_Right15: '오른쪽15', ALTINO_Steering_Angle_Right20: '오른쪽20', ALTINO_Steering_Angle_Right5: '오른쪽5', ALTINO_TEM: '온도', ALTINO_TOR1: '오른쪽 토크', ALTINO_TOR2: '왼쪽 토크', ALTINO_Value: '출력 값', ALTINO_a: '라', ALTINO_a2: '라#', ALTINO_b: '시', ALTINO_c: '도', ALTINO_c2: '도#', ALTINO_d: '레', ALTINO_d2: '레#', ALTINO_dot_display_1: '한문자', ALTINO_dot_display_2: '출력하기', ALTINO_e: '미', ALTINO_f: '파', ALTINO_f2: '파#', ALTINO_g: '솔', ALTINO_g2: '솔#', ALTINO_h: '끄기', ALTINO_h2: '켜기', ALTINO_leftWheel: '왼쪽', ALTINO_melody_ms: '연주하기', ALTINO_outputValue: '출력 값', ALTINO_rightWheel: '오른쪽', ALTINO_set: '로 정하기', ardublock_motor_forward: '앞', ardublock_motor_backward: '뒤', jdkit_clockwise: '시계방향', jdkit_counterclockwise: '반시계방향', jdkit_gyro_frontrear: '앞뒤', jdkit_gyro_leftright: '좌우', jdkit_joystick_leftleftright: '왼쪽 좌우', jdkit_joystick_lefttopbottom: '왼쪽 상하', jdkit_joystick_rightleftright: '오른쪽 좌우', jdkit_joystick_righttopbottom: '오른쪽 상하', jdkit_led: 'LED', jdkit_led_color_green: '초록색', jdkit_led_color_orange: '오랜지색', jdkit_led_turnoff: '끄기', jdkit_led_turnon: '켜기', jdkit_motor_leftbottom: '왼쪽아래', jdkit_motor_lefttop: '왼쪽위', jdkit_motor_rightbottom: '오른쪽아래', jdkit_motor_righttop: '오른쪽위', jdkit_tune_do: '도', jdkit_tune_fa: '파', jdkit_tune_la: '라', jdkit_tune_mi: '미', jdkit_tune_re: '레', jdkit_tune_si: '시', jdkit_tune_sol: '솔', FUNBOARD_bt_down: '노랑(B)', FUNBOARD_bt_left: '초록(C)', FUNBOARD_bt_right: '파랑(D)', FUNBOARD_bt_up: '빨강(A)', FUNBOARD_column_tag: '칸', FUNBOARD_do_off: '끄기', FUNBOARD_do_on: '켜기', FUNBOARD_led_color_all: '모두', FUNBOARD_led_color_blue: '파랑', FUNBOARD_led_color_green: '초록', FUNBOARD_led_color_red: '빨강', FUNBOARD_led_color_str: '색', FUNBOARD_led_color_yellow: '노랑', FUNBOARD_led_off_str: 'LED 끄기', FUNBOARD_led_on_str: 'LED 켜기', FUNBOARD_row_tag: '줄', FUNBOARD_scroll_down: '아래쪽으로', FUNBOARD_scroll_left: '왼쪽으로', FUNBOARD_scroll_no: '없음', FUNBOARD_scroll_right: '오른쪽으로', FUNBOARD_scroll_up: '위쪽으로', FUNBOARD_sensor_cds: 'Cds (밝기 감지)', FUNBOARD_sensor_mic: '마이크 (소리 감지)', FUNBOARD_sensor_slide: '슬라이드 (막대 조정)', FUNBOARD_sensor_state_1: '작다', FUNBOARD_sensor_state_2: '크다', FUNBOARD_touchbt_down: '노랑(B)', FUNBOARD_touchbt_enter: ' F', FUNBOARD_touchbt_escape: ' G', FUNBOARD_touchbt_left: '초록(C)', FUNBOARD_touchbt_right: '파랑(D)', FUNBOARD_touchbt_space: ' E', FUNBOARD_touchbt_up: '빨강(A)', funboard_dotmatrix_set_off: '끄기', funboard_dotmatrix_set_on: '켜기', AI_UTILIZE: '인공지능', video_show_video: '보이기', video_hide_video: '숨기기', video_brightness: '밝기', video_transparency: '투명도', video_left_right: '좌우', video_top_bottom: '상하', video_human: '사람', video_face: '얼굴', video_object: '사물', video_start: '시작하기', video_end: '중지하기', video_gender: '성별', video_age: '나이', video_emotion: '감정', video_motion_onself: '자신', video_motion_onscreen: '실행화면', video_motion_scale: '움직임', video_motion_direction_horizontal: '좌우방향', video_motion_direction_vertical: '상하방향', table_row: '행', table_col: '열', table_sum: '합', table_max: '최대', table_min: '최소', table_avg: '평균', table_stdev: '표준편차', }; Lang.video_body_coord_params = { left_eye: '왼쪽 눈', right_eye: '오른쪽 눈', nose: '코', left_mouth: '왼쪽 입꼬리', right_mouth: '오른쪽 입꼬리', upper_lip: '윗 입술', lower_lip: '아랫 입술', face: '얼굴', neck: '목', left_ear: '왼쪽 귀', right_ear: '오른쪽 귀', left_shoulder: '왼쪽 어깨', left_elbow: '왼쪽 팔꿈치', left_wrist: '왼쪽 손목', left_hip: '왼쪽 엉덩이', left_knee: '왼쪽 무릎', left_ankle: '왼쪽 발목', right_shoulder: '오른쪽 어깨', right_elbow: '오른쪽 팔꿈치', right_wrist: '오른쪽 손목', right_hip: '오른쪽 엉덩이', right_knee: '오른쪽 무릎', right_ankle: '오른쪽 발목', }; Lang.video_emotion_params = { angry: '분노', disgusted: '혐오', fearful: '두려움', happy: '행복', neutral: '무표정', sad: '슬픔', surprised: '놀람', }; Lang.video_object_params = { person: '사람', bicycle: '자전거', car: '자동차', motorcycle: '오토바이', airplane: '비행기', bus: '버스', train: '기차', truck: '트럭', boat: '보트', 'traffic light': '신호등', 'fire hydrant': '소화전', 'stop sign': '일단 정지 표지판', 'parking meter': '주차요금 계산기', bench: '벤치', bird: '새', cat: '고양이', dog: '강아지', horse: '말', sheep: '양', cow: '소', elephant: '코끼리', bear: '곰', zebra: '얼룩말', giraffe: '기린', backpack: '배낭', umbrella: '우산', handbag: '핸드백', tie: '넥타이', suitcase: '여행 가방', frisbee: '프리즈비 원반', skis: '스키', snowboard: '스노우보드', 'sports ball': '공', kite: '연', 'baseball bat': '야구 배트', 'baseball glove': '야구 글러브', skateboard: '스케이트 보드', surfboard: '서핑 보드', 'tennis racket': '테니스 라켓', bottle: '병', 'wine glass': '와인 잔', cup: '컵', fork: '포크', knife: '칼', spoon: '숟가락', bowl: '사발', banana: '바나나', apple: '사과', sandwich: '샌드위치', orange: '오렌지', broccoli: '브로콜리', carrot: '당근', 'hot dog': '핫도그', pizza: '피자', donut: '도넛', cake: '케이크', chair: '의자', couch: '소파', 'potted plant': '식물 화분', bed: '침대', 'dining table': '식탁', toilet: '변기', tv: '텔레비젼', laptop: '노트북', mouse: '마우스', remote: '리모콘', keyboard: '키보드', 'cell phone': '휴대전화', microwave: '전자렌지', oven: '오븐', toaster: '토스터기', sink: '싱크대', refrigerator: '냉장고', book: '책', clock: '시계', vase: '꽃병', scissors: '가위', 'teddy bear': '곰인형', 'hair drier': '헤어 드라이기', toothbrush: '칫솔', }; Lang.Buttons = { share_policy: '이것만은 꼭!', write_policy: '작성 가이드', lesson_list: '강의 목록', complete_study: '학습 완료하기', show_me: '미리 보기', do_this_for_me: '대신 해주기', previous: '이전', get_started: '시작하기', next_lesson: '다음 내용 학습하기', course_submit: '제출하기', course_done: '확인', mission: '미션 확인하기', basic_guide: '기본 사용 방법', apply: '적용하기', add: '추가하기', cancel: '취소', save: '확인', start: '시작', confirm: '확인', delete: '삭제', create: '학급 만들기', done: '완료', accept: '수락', refuse: '거절', yes: '예', button_no: '아니오', quiz_retry: '다시 풀어보기', discuss_upload: '불러오기', maze_popup_guide: '이용안내', maze_popup_mapHint: '힌트보기', maze_hint_btn_guide: '이용 안내', maze_hint_btn_block: '블록 도움말', maze_hint_btn_map: '힌트 보기', maze_hint_btn_goal: '목표', list_save: '저장하기', duplication: '복사하기', export_to_excel: '엑셀로 내려받기', single_line: '한 줄 쓰기', multi_line: '여러 줄 쓰기', lecture_finish_popup_reset_lecture: '처음부터 다시하기', lecture_finish_popup_show_output: '실습한 코드보기', lecture_view_hints: '잘 모르겠어요!', default_hint_title: '어떻게 만들까?', show_only_vector: '벡터 모아보기', }; Lang.Menus = { nothing_to_import: '불러오기 할 항목이 없습니다.', nothing_to_export: '내려받기 할 항목이 없습니다.', content_copied: '내용이 복사되었습니다.', list_import_title: '리스트 불러오기', list_import_placeholder: '예)\n내용1\n내용2\n내용3\n내용4\n내용5\n내용6\n내용7\n내용8', verifying_email: '인증 메일 발송하기', list_import_notice_1: '리스트 항목의 내용을 올릴 수 있습니다.', list_import_notice_2: '기존 내용은 새로 저장한 내용으로 변경됩니다.', list_export_title: '리스트 내보내기', list_export_notice: '리스트 항목의 내용을 복사하거나, 엑셀로 내려받을 수 있습니다.', robotis_opencm70: '로보티즈 IoT', cannnot_mark_favorite: '비공개 작품은 관심 작품으로 지정할 수 없습니다.', enterPassword: '비밀번호를 입력해주세요.', enterPassword_update: '변경 내용을 저장하기 위해 비밀번호를 입력해주세요.', enterNewPassword: '새로운 비밀번호를 입력하세요.', reEnterNewPassword: '새로운 비밀번호를 다시 입력하세요.', resign: '회원탈퇴', check_sended_email: '발송된 인증 메일을 확인하여 이메일 주소를 인증해 주세요.', signUpEmail_1: '입력된 이메일 주소로 인증 메일이 발송되었습니다.', signUpEmail_2: '이메일 주소를 인증해주세요.', select_email_unauthenticated_user: '해당 이메일 주소가 아래 계정에 등록되어 있습니다.\n인증을 원하는 계정을 선택해주세요.', select_user: '계정을 선택해주세요.', enter_password_withdraw: '회원탈퇴 신청을 위해 비밀번호를 입력해주세요.', instruction_agree: '안내 사항에 동의해주세요.', check_instructions: '위 안내 사항에 동의합니다.', deleteAccount_2: '회원탈퇴를 신청하신 30일 이후에는 회원정보와 작품/강의/학급/게시글/댓글/좋아요/관심 정보가 모두 삭제되며 복구가 불가능합니다.', deleteAccount_1: '회원탈퇴를 신청하신 30일 이내에 로그인하시면 회원탈퇴를 취소하실 수 있습니다.', protect_account: '안전한 비밀번호로 내정보를 보호하세요.', please_verify: '인증 메일을 발송하여 이메일 주소를 인증해 주세요.', unverified_email: '이메일 주소가 인증되지 않았습니다.', deleteAccount: '회원탈퇴 신청', corporatePersonal: '개인정보 이전에 동의 합니다', corporateTransferGuide: "개인정보 양수자('엔트리' 웹사이트 운영자) 안내", corporateReciever: '개인정보를 이전 받은 자: 재단법인 커넥트', corporateAddress: '커넥트 주소 및 연락처', corporateAddress_1: '서울시 강남구 강남대로 382 메리츠타워 7층', corporateConsent: '개인정보의 이전을 원치 않으시는 경우 ,동의 철회 방법', corporateEmail: '계정에 등록된 이메일로 탈퇴 요청 메일 발송', corporateAddition: '또한 , 영업 양도에 따라 약관 등이 아래와 같이 변경될 예정입니다.', corporateApplicationDate: '적용시기 : 2017년 10월 29일', corporateTargetChanges: '적용대상 및 변경사항 :', corporateTarget: '적용대상', corporateChanges: '변경사항', corporateTerms: '엔트리 이용약관', corporateOperator: '웹사이트 운영자의 명칭 변경', corporateClassroomTerms: '학급 서비스 이용약관', doAgreeWithClassroomTerms: '학급 서비스 이용약관에 동의합니다.', doChangePassword: '나만 알수 있는 비밀번호로 변경해주세요.', corporatePrivacyPolicy: '개인정보 처리방침', corporateConsignment: '웹사이트 운영자의 명칭 변경 및 개인정보 위탁 업체 추가', corporateEntrusted: '수탁업: NHN Technology Service(주)', corporateConsignmentDetails: '위탁업무 내용: 서비스 개발 및 운영', corporatePeriod: '보유기간 : 회원 탈퇴 시 혹은 위탁 계약 종료시 까지', corporateChangeDate: '변경 적용일 : 2017년 10월 29일 부', corporateWarning: '개인정보 이전에 동의해 주세요.', corporateConfirm: '확인', corporateTitle: '안녕하세요. 엔트리교육연구소입니다.
“엔트리”를 이용하고 계신 회원 여러분께 깊은 감사의 말씀을 드립니다.
엔트리교육연구소는 그동안 공익 목적으로 운영해오던 “엔트리” 웹사이트의 운영을
네이버가 설립한 비영리 재단인 커넥트재단에 양도하기로 합의하였습니다. 
앞으로 엔트리는 커넥트재단에서 공익 목적 하에 지속적으로 운영될 수 있도록
할 것이며, 회원 여러분께서는 기존과 동일하게 엔트리를 이용하실 수 있습니다.
 웹사이트 제공 주체가 엔트리교육연구소에서 커넥트재단으로 변경됨에 따라 아래와
같이 회원 개인 정보에 대한 이전이 있으며, 본 합의에 의해 실제 개인 정보의 위치가
물리적으로 이동한 것은 아님을 알려드립니다. ', textcoding_numberError_f: '등록된 함수 중에 이름의 첫 글자가 숫자인 함수가 있으면 모드 변환을 할 수 없습니다.', textcoding_bookedError_1f: '등록된 함수 중에 이름이', textcoding_bookedError_2f: '인 함수가 있으면 모드 변환을 할 수 없습니다.', textcoding_specialCharError_f: "등록된 함수 중 이름에 '_' 를 제외한 특수 문자가 있으면 모드 변환을 할 수 없습니다.", textcoding_numberError_v: '등록된 변수 중에 이름의 첫 글자가 숫자인 변수가 있으면 모드 변환을 할 수 없습니다.', textcoding_bookedError_1v: '등록된 변수 중에 변수 이름이 ', textcoding_bookedError_2v: ' 인 변수가 있으면 모드 변환을 할 수 없습니다.', textcoding_specialCharError_v: "등록된 변수 중 이름에 '_' 를 제외한 특수 문자가 있으면 모드 변환을 할 수 없습니다.", textcoding_numberError_l: '등록된 리스트 중에 이름의 첫 글자가 숫자인 리스트가 있으면 모드 변환을 할 수 없습니다.', textcoding_bookedError_1l: '등록된 리스트 중에 리스트 이름이', textcoding_bookedError_2l: '인 리스트가 있으면 모드 변환을 할 수 없습니다.', textcoding_specialCharError_l: "등록된 리스트 중 이름에 '_' 를 제외한 특수 문자가 있으면 모드 변환을 할 수 없습니다.", no_discuss_permission: '글을 읽을 권한이 없습니다', delete_comment: '댓글을 삭제하시겠습니까?', delete_article: '게시물을 삭제하시겠습니까?', discuss_cannot_edit: '본인의 게시물이 아닙니다.', discuss_extention: '실행파일은 첨부하실 수 없습니다.', delete_discuss_picture: '사진을 삭제하시겠습니까?', delete_discuss_file: '파일을 삭제하시겠습니까?', discuss_save_question: '글을 저장하시겠습니까?', discuss_cancle_question: '작성을 취소하시겠습니까?', discuss_saved: '이(가) 저장되었습니다.', discuss_no_write_permission: '현재 로그인된 계정으로는 글을 작성하실 수 없습니다.', discuss_no_project_permission: '현재 로그인된 계정으로는 작품을 게시하실 수 없습니다.', discuss_write_abuse_detected: '짧은 시간안에 여러 글이 작성되었습니다.\n1분 뒤에 다시 시도해주세요.', contents_abuse_detected: '5분 뒤에 다시 시도해주세요.', contents_abuse_detected_10: '10분 뒤에 다시 시도해주세요.', discuss_new_write_abuse_warn: '짧은 시간안에 새 글을 작성하는 경우 \n게시글 작성이 제한될 수 있습니다. \n이용에 주의하시길 바랍니다.', discuss_write_abuse_warn: '짧은 시간안에 여러 댓글을 작성하는 경우 \n댓글 작성이 제한될 수 있습니다. \n이용에 주의하시길 바랍니다.', find_not_your_email: '올바른 이메일을 입력해주세요.', search_lang: '검색', search_title: '제목', faq_desc: '엔트리를 이용하면서 궁금한 점들의 답변을 확인해보세요.', faq_all: '전체보기', faq_site: '사이트 이용', faq_project: '작품 만들기', faq_hardware: '하드웨어', faq_offline: '오프라인', faq_copyright: '저작권', faq_title: '자주하는 질문', faq: '자주하는 질문', malicious_warning: '불건전한 사진은 불러올 수 없습니다. 불건전한 사진이 아닌 경우 제안 및 건의에 해당 사진을 첨부하여 신고해주세요.', fword_alert_msg: '욕설이나 불건전한 글은 게시할 수 없습니다.', fword_alert_1: '주제와 무관한 욕설이나 악플은 게시할 수 없습니다.', fword_alert_2: '불건전한 단어가 포함되어 있어, 대체 문장으로 게시 됩니다.', fword_replace_1: '엔트리를 통해 누구나 쉽고 재미있게 소프트웨어를 배울 수 있어요.', fword_replace_2: '소프트웨어 교육의 첫걸음, 엔트리.', fword_replace_3: '재미있게 배우는 학습 공간 엔트리!', fword_replace_4: '엔트리에서 공유와 협업을 통해 멋진 작품을 만들어요.', fword_replace_5: '엔트리는 누구나 무료로 소프트웨어 교육을 받을 수 있게 개발된 소프트웨어 교육 플랫폼입니다.', fword_replace_6: '엔트리와 함께 건강한 소프트웨어 교육 생태계를 조성해요!', fword_replace_7: '엔트리에서 학습하고, 만들고, 공유하며 같이 성장해요.', solve_quiz: '퀴즈 풀기', submit_homework_first_title: '완성! 과제 제출하기', submit_homework_first_content: '멋진 작품이 완성되었습니다. 과제를 제출하세요. 마감 기한 전까지 다시 제출할 수 있습니다.', submit_homework_again_title: '과제 다시 제출하기', submit_homework_again_content: '이미 제출한 과제입니다.
과제를 다시 제출하시겠습니까?', submit_homework_expired_title: '과제 제출 마감', submit_homework_expired_content: '과제 제출이 마감되었습니다.', done_study_title: '완성', done_study_content: '만든 작품을 실행해 봅시다.', featured_courses: '추천 강의 모음', follow_along: '따라하기', follow_along_desc: '차근차근 따라하며 다양한 작품을 만듭니다.', do_quiz: '퀴즈풀기', do_quiz_desc: '학습한 내용을 잘 이해했는지 퀴즈를 통해 확인합니다.', challenge: '도전하기', play: '도전하기', challenge_desc: '주어진 문제를 스스로 해결하며 개념을 익힙니다.', creste_freely: '자유롭게 만들기', creste_freely_desc: '학습한 내용으로 나만의 작품을 자유롭게 만듭니다.', entry_rc_desc: '프로그래밍의 원리를 학습단계에 맞게 배울 수 있는 엔트리 강의 모음! 지금 시작해보세요!
따라하고, 도전하며 소프트웨어를 만들다 보면 어렵게 느껴졌던 프로그래밍의 원리도 쉽고 재미있게 다가옵니다!', hw_deadline: '마감 일자', rc_course_desc: '프로그래밍의 원리를 학습단계에 맞게 배울 수 있도록 구성된 엔트리 강의 모음입니다.', rc_course: '추천 강의 모음', entry_rec_course: '엔트리 추천 강의 모음', entry_rec_course_desc: '누구나 쉽게 보고 따라하면서 재미있고 다양한 소프트웨어를 만들 수 있는 엔트리 강의를 소개합니다.', guidance: '안내', wait: '잠깐', hint: '힌트', concept_guide: '개념 톡톡', group_quiz: '우리 반 퀴즈', fail_check_hint: '앗… 실패! 다시 한 번 도전해보세요!
어려울 땐 [힌트]를 확인해보세요!', sort_student: '학생별', sort_lesson: '강의별', sort_course: '강의 모음별', student_progress: '우리 반 진도', my_progress: '나의 진도', lec_in_progress: '학습 중', free_modal_asgn_over: '과제 제출이 마감되었습니다.', free_submission_closed: '과제 제출 마감', free_modal_asgn_submit_first: '멋진 작품이 완성되었습니다! 과제를 제출하세요.
마감 기한 전까지 다시 제출 할 수 있습니다.', asgn_submit: '완성! 과제 제출하기', free_modal_content_resubmit: '이미 제출한 과제입니다.
과제를 다시 제출하시겠습니까?', asgn_resubmit: '과제 다시 제출하기', free_modal_content_complete: '멋진 작품이 완성되었습니다.', guide_modal_content_complete: '만든 작품을 실행해 봅시다.', success: '성공', fail: '실패', mission_modal_content_fail: '
어려울 땐 [힌트]를 확인해보세요!', mission_modal_content_success: '만든 작품을 실행해 봅시다.', in_progress: '진행중', completed: '완료', submitted: '제출 완료', submission_closed: '마감', progress: '진행 상황', study_completed: '학습 완료', view_course_desc: '코스웨어 설명 보기', main_entry_starter: '기초부터! 엔트리 스타터', main_entry_booster: '개념탄탄! 엔트리 부스터', main_entry_master: '생각을 펼치는! 엔트리 마스터', no_students_in_classroom: '아직 등록된 학생이 없습니다.
학생을 직접 추가하거나, 초대해 보세요!', lectures: '강의', Lectures: '강의', studentHomeworkList: '과제', curriculums: '강의 모음', Curriculums: '강의 모음', quiz: '퀴즈', no_added_group_contents_teacher: '추가된 %1이(가) 없습니다.
우리 반 %1을(를) 추가해 주세요.', no_added_group_contents_student: '아직 올라온 %1이(가) 없습니다. 선생님이 %1을(를) 올려주시면, 학습 내용을 확인할 수 있습니다.', side_project: '목표 작품', custom_make_course_1: "'오픈 강의 만들기> 강의 모음 만들기'에서", custom_make_course_2: '나만의 강의 모음을 만들어 보세요.', custom_make_lecture_1: "'오픈 강의 만들기'에서", custom_make_lecture_2: '나만의 강의를 만들어 보세요', alert_enter_info: '수정할 정보를 입력해주세요.', alert_enter_new_pwd: '기존 비밀번호와 다른 비밀번호를 입력해주세요.', alert_match_pwd: '새로운 비밀번호와 재입력된 비밀번호가 일치하지 않습니다.', alert_check_pwd: '비밀번호를 확인해주세요.', alert_update_complete: '정보가 수정 되었습니다.', no_group_contents_each_prefix: '우리반 ', no_group_contents_each_suffix: ' 이(가) 없습니다.', no_group_contents_all: '학급에 올라온 컨텐츠가 없습니다.
학급 공유하기에
나만의 작품을 공유해보세요!', hw_closed: '과제 마감', tag_Lecture: '강의', tag_Curriculum: '강의모음', tag_Discuss: '공지', count_ko: '개', no_asgn_within_week: '1주일안에 제출되어야 하는 마감 임박한 과제가 없습니다.', lecture_and_curriculum: '강의 / 강의 모음', assignments_plural: '과제', assignments_singular: '과제', project_plural: '작품', group_news: '새로운 소식', stu_management: '학생 관리', stu_management_camel: '학생 관리', view_all: '전체 보기', view_all_camel: '전체 보기', view_contents_camel: '콘텐츠 보기', view_contents: '콘텐츠 보기', no_updated_news: '나의 학급에 올라온 새로운 소식이 없습니다.', homework_soon_due: '곧 마감 과제', new_homework: '최신 과제', no_new_homework: '새로운 과제가 없습니다.', student_plural: '학생', discuss: '공지', basic_project: '기본 작품', no_permission: '권한이 없습니다.', no_comment_write_permission: '현재 로그인된 계정으로는 답변을 작성하실 수 없습니다.', original_curriculum_deleted: '원본 강의 모음이 삭제되었습니다.', original_curriculum: '원본 강의 모음', save_as_my_lecture: '복사본으로 저장하기 ', delete_confirm: '삭제 알림', lecture_open_as_copied: '오픈 강의 페이지에 올라간 모든 강의는 사본으로 생성되어 공개 됩니다.', curriculum_open_as_copied: '오픈 강의 모음 페이지에 올라간 모든 강의 모음은 사본으로 생성되어 공개 됩니다.', lecture_save_as_copied_group: '우리 반 강의 페이지에 올라간 모든 강의는 사본으로 생성되어 공개 됩니다.', curriculum_save_as_copied_group: '우리 반 강의 모음 페이지에 올라간 모든 강의 모음은 사본으로 생성되어 공개 됩니다.', homework_save_as_copied_group: '우리 반 과제 페이지에 올라간 모든 과제는 사본으로 생성되어 공개 됩니다.', lecture_save_as_copied: '내가 만든 강의 모음 안에 삽입된 구성 강의는 사본으로 생성되어 저장됩니다.', done_project_save_as_copied: '내가 만든 강의 안에 삽입된 완성 작품은 사본으로 생성되어 저장됩니다.', textbook_project_can_not_applied: '교과형 만들기(실과)로 만들어진 작품은 강의로 만들 수 없습니다.', original_lecture_deleted: '원본 강의가 삭제되었습니다.', original_lecture: '원본 강의', lecture_save_as_mine_alert: "저장되었습니다.\n저장된 강의는 '마이페이지> 나의 강의'에서 확인할 수 있습니다.", lecture_save_as_mine: '내 강의로 저장하기', duplicate_username: '이미 입력한 아이디 입니다.', share_your_project: '내가 만든 작품을 공유해 보세요', not_available_student: "학급에서 발급된 '학급 아이디'입니다.\n'엔트리 회원 아이디'를 입력해주세요.", login_instruction: '로그인 안내', login_needed: '로그인 후 이용할 수 있습니다.', login_as_teacher: '선생님 계정으로 로그인 후 이용할 수 있습니다.', remove_my_storage: '나의 보관함에서 삭제하시겠습니까? 삭제한 블록/오브젝트는 복구할 수 없습니다.', submit_hw: '과제 제출하기', success_goal: '목표성공', choseok_final_result: '좋아 , 나만의 작품을 완성했어!', choseok_fail_msg_timeout: '시간이 너무 많이 지나버렸어. 목표를 잘 보고 다시 한번 도전해봐!', choseok_fail_msg_die: '생명이 0이하인데 게임이 끝나지 않았어.\n아래의 블록을 사용해서 다시 도전해 보는 건 어때?', grade_1: '초급', grade_2: '중급', grade_3: '고급', find_sally_title: '샐리를 찾아서', save_sally_title: '샐리 구하기', exit_sally_title: '샐리 탈출하기', find_sally: '라인 레인저스의 힘을 모아 \n강력한 악당 메피스토를 물리치고 샐리를 구해주세요!', save_sally: '메피스토 기지에 갇힌 샐리. \n라인 레인저스가 장애물을 피해 샐리를 찾아갈 수 있도록\n도와주세요!', exit_sally: '폭파되고 있는 메피스토 기지에서 \n샐리와 라인 레인저스가 무사히 탈출할 수 있도록\n도와주세요!', go_next_mission: '다른 미션 도전하기', share_my_project: '내가 만든 작품 공유하기', share_certification: '인증서 공유하기', print_certification: '인증서를 뽐내봐', get_cparty_events: '내가 받은 인증서를 출력해 뽐내면 푸짐한 상품을 받을 수 있어요!', go_cparty_events: '이벤트 참여하러 가기', codingparty2016_blockHelper_1_title: '앞으로 가기', codingparty2016_blockHelper_1_contents: '앞으로 가기', codingparty2016_blockHelper_2_title: '앞으로 가기', codingparty2016_blockHelper_2_contents: '회전하기', codingparty2016_blockHelper_3_title: '앞으로 가기', codingparty2016_blockHelper_3_contents: '돌 부수기', codingparty2016_blockHelper_4_title: '앞으로 가기', codingparty2016_blockHelper_4_contents: '횟수 반복하기', codingparty2016_blockHelper_5_title: '앞으로 가기', codingparty2016_blockHelper_5_contents: '꽃 던지기', codingparty2016_goalHint_1: '샐리를 구하기 위해서는 미네랄이 필요해! 미네랄을 얻으며 목적지까지 가보자!', codingparty2016_goalHint_2: '구불구불한 길이 있네. 회전 블록을 사용하면 어렵지 않을 거야!', codingparty2016_goalHint_3: '앞이 돌로 막혀있잖아? 돌을 부수며 목적지까지 가보자!', codingparty2016_goalHint_4: '복잡한 길이지만 지금까지 배운 것들로 해결할 수 있어!', codingparty2016_goalHint_5: '앞으로 쭉 가는 길이잖아? 반복 블록을 사용하여 간단하게 해결해 보자!', codingparty2016_goalHint_6: '미네랄을 모두 모아오자. 반복블록을 쓰면 쉽게 다녀올 수 있겠어!', codingparty2016_goalHint_7: '친구들이 다치지 않도록 꽃을 던져 거미집을 제거해야 해. 저 멀리 있는 거미집을 제거하고 목적지까지 가 보자.', codingparty2016_goalHint_8: '가는 길에 거미집이 많잖아? 거미집을 모두 제거하고 목적지까지 가 보자.', codingparty2016_goalHint_9: '거미집 뒤쪽에 있는 미네랄을 모두 모아오자!', codingparty2016_guide_1_1_contents: '라인 레인저스 전사들이 샐리를 구할 수 있도록 도와줘! 전사들을 움직이기 위해서는 블록 명령어를 조립해야 해.\n\n① 먼저 미션 화면과 목표를 확인하고,\n② 블록 꾸러미에서 필요한 블록을 가져와 “시작하기를 클릭했을 때“ 블록과 연결해.\n③ 다 조립되면 ‘시작하기‘ 버튼을 눌러 봐! 블록이 위에서부터 순서대로 실행되며 움직일 거야.', codingparty2016_guide_1_1_title: '라인 레인저스 전사들을 움직이려면?', codingparty2016_guide_1_2_title: '목표 블록의 개수', codingparty2016_guide_1_2_contents: '① [안 칠해진 별]의 개수만큼 블록을 조립해 미션을 해결해보자. 목표 블록보다 더 많은 블록을 사용하면 별이 빨간색으로 바뀌니 정해진 개수 안에서 문제를 해결해 봐!\n② 필요하지 않은 블록은 휴지통 또는 블록꾸러미에 넣어줘.', codingparty2016_guide_1_3_title: "'앞으로 가기' 블록을 사용하기", codingparty2016_guide_1_3_contents: '< 앞으로 가기 > 는 앞으로 한 칸 이동하는 블록이야. \n\n여러 칸을 이동하기 위해서는 이 블록을 여러 번 연결해야 해.', codingparty2016_guide_1_4_title: '미네랄 획득하기', codingparty2016_guide_1_4_contents: '[ 미네랄 ]이 있는 곳을 지나가면 미네랄을 획득할 수 있어\n\n화면에 있는 미네랄을 모두 획득하고 목적지에 도착해야만 다음 단계로 넘어갈 수 있어.', codingparty2016_guide_1_5_title: '어려울 때 도움을 받으려면?', codingparty2016_guide_1_5_contents: '미션을 수행하다가 어려울 땐 3가지 종류의 도움말 버튼을 눌러 봐.\n\n\n<안내> 지금 이 안내를 다시 보고 싶을 때!\n<블록 도움말> 블록 하나하나가 어떻게 동작하는지 궁금할 때!\n<맵 힌트> 이 단계를 해결하기 위한 힌트가 필요할 때!', codingparty2016_guide_2_1_title: '회전 블록 사용하기', codingparty2016_guide_2_1_contents: '<오른쪽으로 돌기>와 <왼쪽으로 돌기>는 \n제자리에서 90도 회전하는 블록이야. 방향만 회전하는 블록이야. \n캐릭터가 바라보고 있는 방향을 기준으로 오른쪽인지 왼쪽인지 잘 생각해 봐!\n', codingparty2016_guide_3_1_title: '(문) 능력 사용하기', codingparty2016_guide_3_1_contents: '라인 레인저스 전사들을 각자의 능력을 가지고 있어.\n나 [문] 은 <발차기하기> 로 바로 앞에 있는 [돌]을 부술 수 있어.\n[돌을] 부수고 나면 막힌 길을 지나갈 수 있겠지?\n화면에 있는 [돌]을 모두 제거해야만 다음 단계로 넘어갈 수 있어.\n그렇지만 명심해! 아무 것도 없는 곳에 능력을 낭비해서는 안 돼!', codingparty2016_guide_5_1_title: "'~번 반복하기' 블록 사용하기", codingparty2016_guide_5_1_contents: '똑같은 일을 반복해서 명령하는 건 매우 귀찮은 일이야.\n이럴 땐 명령을 사용하면 훨씬 쉽게 명령을 내릴 수 있어. \n< [ ? ] 번 반복하기> 블록 안에 반복되는 명령 블록을 넣고 \n[ ? ] 부분에 횟수를 입력하면 입력한 횟수만큼 같은 명령을 반복하게 돼.', codingparty2016_guide_5_2_title: "'~번 반복하기' 블록 사용하기", codingparty2016_guide_5_2_contents: "'< [ ? ] 번 반복하기> 블록 안에는 여러 개의 명령어를 넣을 수도 있으니 잘 활용해봐! \n도착지에 도착했더라도 반복하기 블록 안에 있는 블록이 모두 실행돼.\n 즉, 위 상황에서 목적지에 도착한 후에도 왼쪽으로 돈 다음에야 끝나는 거야!", codingparty2016_guide_7_1_title: '(코니) 능력 사용하기', codingparty2016_guide_7_1_contents: '나 ‘코니’는 <꽃 던지기>로 먼 거리에서도 앞에 있는 [거미집]을 없앨 수 있어.\n[거미집]을 없애고 나면 막힌 길을 지나갈 수 있겠지?\n화면에 있는 [거미집]을 모두 제거해야만 다음 단계로 넘어갈 수 있어.\n그렇지만 명심해! 아무것도 없는 곳에 능력을 낭비해서는 안 돼!', codingparty2016_guide_9_1_title: '조건 반복 블록 사용하기', codingparty2016_guide_9_1_contents: '반복하는 횟수를 세지 않아도, 어떤 조건을 만족할 때까지 행동을 반복할 수 있어.\n< [목적지]에 도착할 때까지 반복하기 > 블록 안에 반복되는 명령 블록을 넣으면 [목적지]에 도착할 때까지 명령을 반복해.', codingparty2016_guide_9_2_title: '조건 반복 블록 사용하기', codingparty2016_guide_9_2_contents: '<[목적지]에 도착할 때까지 반복하기> 블록 안에는 여러 개의 명령어를 넣을 수도 있으니 잘 활용해봐!\n 도착지에 도착했더라도 반복하기 블록 안에 있는 블록이 모두 실행 돼. 즉, 위 상황에서 목적지에 도착한 후에도 왼쪽으로 돈 다음에야 끝나는 거야!', find_interesting_lesson: "'우리 반 강의'에서 다양한 강의를 만나보세요!", find_interesting_course: "'우리 반 강의 모음'에서 다양한 강의를 만나보세요!", select_share_settings: '공유 공간을 선택해주세요.', faq_banner_title: '자주하는 질문 안내', check_out_faq: '궁금한 점을 확인하세요.', faq_banner_content: '엔트리에 대해 궁금하세요?
자주하는 질문을 통해 답변을 드리고 있습니다.
지금 바로 확인하세요!', faq_banner_button: '자주하는 질문
바로가기', major_updates: '주요 업데이트 안내', check_new_update: '엔트리의 변화를 확인하세요.', major_updates_notification: '엔트리의 주요 변경사항을 공지를 통해 안내해 드리고 있습니다.', find_out_now: '지금 바로 확인하세요!', offline_hw_program: '오프라인 & 하드웨어 연결 프로그램', read_more: '자세히 보기', sample_project: '예시 작품', not_supported_function: '이 기기에서는 지원하지 않는 기능입니다.', offline_download_confirm: '엔트리 오프라인 버전은 PC에서만 이용가능합니다. 다운로드 하시겠습니까?', hardware_download_confirm: '엔트리 하드웨어는 PC에서만 이용가능합니다. 다운로드 하시겠습니까?', copy_text: '텍스트를 복사하세요.', select_openArea_space: '작품 공유 공간을 선택해 주세요', mission_guide: '미션 해결하기 안내', of: ' 의', no_results_found: '검색 결과가 없습니다.', upload_pdf: 'PDF 자료 업로드', select_basic_project: '작품 선택하기', try_it_out: '만들어 보기', go_boardgame: '엔트리봇 보드게임 바로가기', go_cardgame: '엔트리봇 카드게임 바로가기', go_solve: '미션으로 학습하기', go_ws: '엔트리 만들기 바로가기', go_arts: '엔트리 공유하기 바로가기', group_delete_alert: '학급을 삭제하면, 해당 학급에서 발급한 학생임시계정을 포함하여 관련한 모든 자료가 삭제됩니다.\n정말 삭제하시겠습니까?', view_arts_list: '다른 작품 보기', hw_submit_confirm_alert: '과제가 제출 되었습니다.', hw_submit_alert: '과제를 제출 하시겠습니까? ', hw_submit_alert2: '과제를 제출하시겠습니까? 제출 시 학습 완료한 학습 단계까지만 제출이 됩니다.', hw_submit_cannot: '제출 할 수 없는 과제입니다.', see_other_missions: '다른 미션 보기', project: ' 작품', marked: ' 관심', group: '학급', lecture: '강의', Lecture: '강의', curriculum: '강의 모음', Curriculum: '강의 모음', studying: '학습 중인', open_only_shared_lecture: '오픈 강의 페이지에 <공개> 한 강의만 불러올 수 있습니다. 불러오고자 하는 강의공개여부를 확인해 주세요.', already_exist_group: '이미 존재하는 학급 입니다.', cannot_invite_you: '자기 자신을 초대할 수 없습니다.', apply_original_image: '원본 이미지 그대로 적용하기', draw_new_ques: '새로 그리기 페이지로\n이동하시겠습니까?', draw_new_ques_1: '그림을 그려 오브젝트로 저장할 수 있습니다.', draw_new_ques_2: '그리기 화면으로 이동하시겠습니까?', draw_new_go: '이동하기', draw_new_stay: '이동하지 않기', file_upload_warn_title_image: '아래와 같은 그림은 이용약관 및 관련 법률에 의해 제재를 받으실 수 있습니다.', file_upload_warn_desc_image: '폭력적이고 잔인한 그림
선정적인 신체노출 그림
불쾌감을 주거나 혐오감을 일으키는 그림
무단 사용이 금지된 저작권의 그림', file_upload_warn_title_sound: '아래와 같은 소리는 이용약관 및 관련 법률에 의해 제재를 받을 수 있습니다.', file_upload_warn_desc_sound: '폭력적이고 잔인한 소리
선정적인 내용의 소리
불쾌감을 주거나 혐오감을 일으키는 소리
무단 사용이 금지된 저작권의 소리', file_upload_warn_title_table: '아래와 같은 데이터는 이용약관 및 관련 법률에 의해 제재를 받으실 수 있습니다.', file_upload_warn_desc_table: '폭력적이고 잔인한 내용의 데이터
선정적인 내용의 데이터
불쾌감을 주거나 혐오단어가 포함된 데이터
무단 사용이 금지된 저작권의 데이터', file_upload_warn_link: '저작권에 대해 알아보기', file_upload_desc_1: '이런 그림은 \n 안돼요!', file_upload_desc_2: '폭력적이고 잔인한 그림', file_upload_desc_3: '선정적인 신체노출 그림', file_upload_desc_4: '불쾌감을 주거나 혐오감을 일으키는 그림', file_upload_desc_5: '* 위와 같은 내용은 이용약관 및 관련 법률에 의해 제재를 받으실 수 있습니다.', picture_upload_warn_old: '10MB 이하의 jpg, png, bmp 형식의 파일을 추가할 수 있습니다.', sprite_upload_warn_old: '10MB 이하의 jpg, png, bmp 이미지 또는 eo 형식의 오브젝트를 추가할 수 있습니다.', picture_upload_warn_1: '10MB 이하의 jpg, png, bmp, svg 형식의 파일을 추가할 수 있습니다.\njpg, png, bmp 형식은 비트맵 모드, svg 형식은 벡터 모드로 편집됩니다.', table_upload_warn_1: '10MB 이하의 csv, xls(x) 형식의 파일을 추가할 수 있습니다. xls(x) 형식의 경우, 함수 문장이 그대로 출력됩니다.', sprite_upload_warn: '10MB 이하의 jpg, png, bmp, svg 이미지 또는 eo 형식의 오브젝트를 추가할 수 있습니다.', sound_upload_warn_1: '10MB 이하의 mp3 형식의 파일을 추가할 수 있습니다.', sound_edit_warn: '기다려 주세요!
새로운 소리 편집 기능을 연구 중입니다.', file_upload_loading: '로딩중', lesson_by_teacher: '선생님들이 직접 만드는 강의입니다.', delete_group_art: '학급 공유하기 목록에서 삭제 하시겠습니까?', elementary_short: '초등', middle_short: '중등', grade_34: '3-4학년', grade_56: '5-6학년', grade_78: '중등', share_lesson: '강의 공유하기', share_course: '강의 모음 공유하기', from_list_ko: '을(를)', comming_soon: '준비중입니다.', no_class_alert: "선택된 학급이 없습니다. 학급이 없는경우 '나의 학급' 메뉴에서 학급을 만들어 주세요.", students_cnt: '명', defult_class_alert_1: '', defult_class_alert_2: '을(를) \n 기본학급으로 설정하시겠습니까?', default_class: '기본학급입니다.', enter_hw_name: '과제의 제목을 입력해 주세요.', hw_limit_20: '과제는 20개 까지만 만들수 있습니다.', stu_example: '예)\n 홍길동\n 홍길동\n 홍길동', hw_description_limit_200: '생성 과제에 대한 안내 사항을 입력해 주세요. (200자 이내)', hw_title_limit_50: '과제명을 입력해 주세요. (50자 이내)', create_project_class_1: "'만들기 > 작품 만들기' 에서", create_project_class_2: '학급에 공유하고 싶은 작품을 만들어 주세요.', create_lesson_assignment_1: "'만들기> 오픈 강의 만들기'에서 ", create_lesson_assignment_2: '우리 반 과제에 추가하고 싶은 강의를 만들어 주세요.', i_make_lesson: '내가 만드는 강의', lesson_to_class_1: "'학습하기>오픈 강의'에서 우리반", lesson_to_class_2: '과제에 추가하고 싶은 강의를 관심강의로 등록해 주세요.', studying_students: '학습자', lessons_count: '강의수', group_out: '나가기', enter_group_code: '학급코드 입력하기', no_group_invite: '학급 초대가 없습니다.', done_create_group: '개설이 완료되었습니다.', set_default_group: '기본학급 설정', edit_group_info: '학급 정보 관리', edit_done: '수정 완료되었습니다.', alert_group_out: '학급을 정말 나가시겠습니까?', lesson_share_cancel: '강의 공유 취소', project_share_cancel: '작품 공유 취소', lesson_share_cancel_alert: '작품을 비공개로 하시겠습니까?', course_share_cancel: '강의 모음 공유 취소', select_lesson_share: '강의 공유 공간 선택', select_project_share: '작품 공유 선택', select_lesson_share_policy_1: '강의를 공유할', select_lesson_share_policyAdd: '공간을 선택해 주세요', select_lesson_share_project_1: '작품을 공유할 공간과', select_lesson_share_policy_2: '저작권 정책을 확인해 주세요.', select_lesson_share_area: '강의 공유 공간을 선택해 주세요', select_project_share_area: '작품 공유 공간을 선택해 주세요', lesson_share_policy: '강의 공유에 따른 엔트리 저작권 정책 동의', project_share_policy: '작품 공유에 따른 엔트리 저작권 정책 동의', alert_agree_share: '공개하려면 엔트리 저작물 정책에 동의하여야 합니다.', alert_agree_all: '모든 항목에 동의해 주세요.', select_course_share: '강의 모음 공유 공간 선택', select_course_share_policy_1: '강의 모음을 공유할', select_course_share_policy_2: '저작권 정책을 확인해 주세요.', select_course_share_area: '강의 모음 공유 공간을 선택해 주세요', course_share_policy: '강의 모음 공유에 따른 엔트리 저작권 정책 동의', issued: '발급', code_expired: "코드가 만료되었습니다. '코드재발급' 버튼를 누르세요.", accept_class_invite: '학급초대 수락하기', welcome_class: '학급에 오신것을 환영합니다.', enter_info: '자신의 정보를 입력해주세요.', done_group_signup: '학급 가입이 완료되었습니다.', enter_group_code_stu: '선생님께 받은 코드를 입력해주세요.', text_limit_50: '50글자 이하로 작성해 주세요.', enter_class_name: '학급 이름을 입력해 주세요.', enter_grade: '학년을 입력해 주세요.', enter_class_info: '학급소개를 입력해 주세요.', student_dup: '은(는) 이미 학급에 존재합니다.', select_stu_print: '출력할 학생을 선택하세요.', class_id_not_exist: '학급 ID가 존재하지 않습니다.', error_try_again: '오류 발생. 다시 한 번 시도해 주세요.', error_forbidden: '권한이 없습니다.', code_not_available: '유효하지 않은 코드입니다.', gnb_create_lessons: '오픈 강의 만들기', study_lessons: '강의 학습하기', lecture_help_1: '학습을 시작할 때, 사용할 작품을 선택해 주세요. 선택한 작품으로 학습자가 학습을 시작하게 됩니다.', lecture_help_2: '이도움말을 다시 보시려면 위 버튼을 클릭해 주세요.', lecture_help_3: '오브젝트 추가하기가 없으면새로운 오브젝트를 추가하거나 삭제 할 수 없습니다.', lecture_help_4: '학습도중에 PDF자료보기를 통해 학습에 도움을 받을 수 있습니다.', lecture_help_5: '학습에 필요한 블록들만 선택해주세요. 선택하지 않은 블록은 숨겨집니다.', lecture_help_6: '블록코딩과 엔트리파이선 중에 선택하여 학습환경을 구성할 수 있습니다.', lecture_finish_popup_title: '학습 다시하기', lecture_finish_popup_content_1: '실습완료한 단계를
처음부터 다시 실습하시겠습니까?', lecture_finish_popup_content_2: '* 다시 실습해도 실습 완료 상태는 유지됩니다.', lecture_start_title: '학습 시작', lecture_goal_title: '학습 목표', lecture_goal_content: '무엇을 배울지 알아볼까요?', lecture_prepare_title: '학습 준비', lecture_summary_title: '학습 정리', lecture_summary_content: '배운 내용을 정리해 봅시다.', lecture_quiz_title: '확인 문제', lecture_quiz_content: '확인 문제를 통해 배운 내용을 점검해 봅시다.', lecture_quiz_check_answer: '정답확인', default_hint_title: '어떻게 만들까?', only_pdf: '.pdf형식의 파일만 입력 가능합니다.', enter_project_video: '적어도 하나의 작품이나 영상을 입력하세요.', enter_title: '제목을 입력하세요.', enter_recommanded_grade: '추천 학년을 입력하세요.', enter_level_diff: '난이도를 입력하세요.', enter_time_spent: '소요시간을 입력하세요.', enter_shared_area: '적어도 하나의 공유 공간을 선택하세요.', enter_goals: '학습목표를 입력하세요.', enter_lecture_description: '강의 설명을 입력하세요.', enter_curriculum_description: '강의 모음 설명을 입력하세요.', first_page: '처음 입니다.', last_page: '마지막 입니다.', alert_duplicate_lecture: '이미 등록된 강의는 다시 등록할 수 없습니다.', enter_lesson_alert: '하나 이상의 강의를 등록해주세요.', open_edit_lessons: '편집할 강의를 불러오세요.', saved_alert: '이(가) 저장되었습니다.', select_lesson_type: '어떤 학습과정을 만들지 선택해 주세요 ', create_lesson: '강의 만들기', create_lesson_desc_1: '원하는 학습 목표에 맞춰', create_lesson_desc_2: '단일 강의를 만들어', create_lesson_desc_3: '학습에 활용합니다.', create_courseware: '강의 모음 만들기', create_courseware_desc_1: '학습 과정에 맞춰 여러개의 강의를', create_courseware_desc_2: '하나의 코스로 만들어', create_courseware_desc_3: '학습에 활용합니다.', create_open_lesson: '오픈 강의 만들기 ', enter_lesson_info: '강의 정보 입력 ', select_lesson_feature: '학습 기능 선택 ', check_info_entered: '입력 정보 확인 ', enter_lefo_lesson_long: '강의를 구성하는 정보를 입력해 주세요.', lesson_info_desc: '학습자가 학습하기 화면에서 사용할 기능과 작품을 선택함으로써, 학습 목표와 내용에 최적화된 학습환경을 구성할 수 있습니다.', provide_only_used: '완성된 작품에서 사용된 블록만 불러오기', see_help: '도움말 보기', select_done_project_1: '학습자가 목표로 설정할', select_done_project_2: '완성 작품', select_done_project_3: '을 선택해 주세요.', select_project: '나의 작품 또는 관심 작품을 불러옵니다. ', youtube_desc: '유튜브 공유 링크를 통해 원하는 영상을 넣을 수 있습니다.', lesson_video: '강의 영상', lesson_title: '강의 제목', recommended_grade: '추천학년', selection_ko: '선택', selection_en: '', level_of_diff: '난이도', select_level_of_diff: '난이도 선택', enter_lesson_title: '강의 제목을 입력해 주세요(30자 이내)', select_time_spent: '소요시간 선택 ', time_spent: '소요시간', lesson_overview: '강의설명', upload_materials: '학습 자료 업로드', open: '불러오기', cancel: '취소하기', upload_lesson_video: '강의 영상 업로드', youtube_upload_desc: '유튜브 공유링크를 통해 보조영상을 삽입할 수 있습니다. ', cancel_select: '선택 취소하기', select_again: '다시 선택하기', goal_project: '완성작품', upload_study_data: '학습하기 화면에서 볼 수 있는 학습자료를 업로드해주세요. 학습자가 업로드된 학습자료의 내용을 확인하며 학습할 수 있습니다. ', upload_limit_20mb: '20MB 이하의 파일을 올려주세요.', expect_time: '예상 소요 시간', course_videos: '보조 영상', enter_courseware_info: '강의 모음 정보 입력 ', enter_course_info: '강의 모음을 소개하는 정보를 입력해 주세요 ', select_lessons_for_course: '강의 모음을 구성하는 강의를 선택해 주세요.', course_build_desc_1: '강의는', course_build_desc_2: '최대30개', course_build_desc_3: '등록할 수 있습니다.', lseeon_list: '강의 목록 보기', open_lessons: '강의 불러오기', course_title: '강의 모음 제목', title_limit_30: '강의 모음 제목을 입력해 주세요(30자 이내) ', course_overview: '강의 모음 설명', charactert_limit_200: '200자 이내로 작성할 수 있습니다.', edit_lesson: '강의 편집', courseware_by_teacher: '선생님들이 직접 만드는 강의 모음입니다.', select_lessons: '구성 강의 선택', check_course_info: '강의 모음을 구성하는 정보가 올바른지 확인해 주세요.', select_share_area: '공유 공간 선택', upload_sub_project: '목표 작품 업로드', file_download: '첨부파일 다운로드', file_remove: '첨부파일 삭제', check_lesson_info: '강의를 구성하는 정보가 올바른지 확인해 주세요.', share_area: '공유 공간', enter_sub_project: '엔트리 보조 프로젝트를 등록해 주세요.', lms_hw_title: '과제 제목', lms_hw_ready: '준비', lms_hw_progress: '진행중', lms_hw_complete: '완료', lms_hw_not_submit: '미제출', lms_hw_closed: '제출마감', submission_condition: '진행중인 과제만 제출이 가능합니다.', submit_students_only: '학생만 과제를 제출할 수 있습니다.', want_submit_hw: '과제를 제출하시겠습니까?', enter_correct_id: '올바른 아이디를 입력해 주세요.', id_not_exist: '아이디가 존재하지 않습니다. ', agree_class_policy: '학급 서비스 이용약관에 동의해 주세요.', delete_class: '학급 삭제', type_stu_name: '학생 이름을 입력해주세요. ', invite_from_1: '에서', invite_from_2: '님을 초대하였습니다. ', lms_pw_alert_1: '학급에 소속되면, 선생님 권한으로', lms_pw_alert_2: '비밀번호 재발급이 가능합니다.', lms_pw_alert_3: '선생님의 초대가 맞는지 한번 더 확인해주세요.', invitation_accepted: '초대 수락이 완료되었습니다!', cannot_issue_pw: '초대를 수락하지 않았으므로 비밀번호를 발급할 수 없습니다.', start_me_1: '<월간 엔트리>와 함께', start_me_2: 'SW교육을 시작해보세요!', monthly_desc_1: '<월간 엔트리>는 소프트웨어 교육에 익숙하지 않은 선생님들도 쉽고 재미있게', monthly_desc_2: '소프트웨어 교육을 하실 수 있도록 만들어진 SW교육 잡지입니다.', monthly_desc_3: '매월 재미있는 학습만화와 함께 하는 SW 교육 컨텐츠를 만나보세요!', monthly_desc_4: '* 월간엔트리는 2015년 11월 ~ 2016년 5월까지 발행 후 중단되었습니다.', monthly_desc_5: '엔트리의 교육자료는 교육자료 페이지에서 만나보세요.', monthly_entry: '월간 엔트리', me_desc_1: '매월 발간되는 무료 소프트웨어 교육잡지', me_desc_2: '월간엔트리를 만나보세요!', solve_desc_1: '게임을 하듯 미션을 해결하며', solve_desc_2: '소프트웨어의 기본 원리를 배워보세요!', playSw_desc_1: 'EBS 방송영상, 특별영상을 통해', playSw_desc_2: '소프트웨어를 배워보세요!', recommended_lessons: '추천 강의 모음', recommended_lessons_1: '따라하고, 도전하고, 퀴즈도 풀며 재미있게 엔트리 프로그래밍을 배워보세요!', recommended_lessons_2: '추천 강의 모음을 만나보세요!', offline_top_desc_1: '오프라인 버전의 저장 기능이 향상되고 보안이 강화되었습니다.', offline_top_desc_2: '지금 바로 다운받으세요', offline_main_desc: '엔트리 오프라인 에디터 업데이트!!', art_description: '엔트리로 만든 작품을 공유하는 공간입니다. 작품을 만들고 공유에 참여해 보세요.', art_description_1: '엔트리로 총 ', art_description_2: '개의 작품이 만들어졌습니다. 작품을 만들고 공유해 보세요.', study_index: '엔트리에서 제공하는 주제별, 학년별 학습과정을 통해 차근차근 소프트웨어를 배워보세요!', study_for_beginner: '처음 시작하는 사람들을 위한 엔트리 첫걸음', entrybot_desc_3: '안내에 따라 블록 명령어를 조립하여', entrybot_desc_4: '엔트리봇을 학교에 데려다 주세요.', move_entrybot: '엔트리봇 움직이기', can_change_entrybot_1: '블록 명령어로 엔트리봇의 색을 바꾸거나', can_change_entrybot_2: '말을 하게 할 수도 있어요.', learning_process_by_topics: '주제별 학습과정', show_detail: '자세히 보기', solve_mission: '미션 해결하기', solve_mission_desc_1: '게임을 하듯 미션을 해결하며 프로그래밍의 원리를 익혀보세요!', solve_mission_desc_2: '미로 속의 엔트리봇을 목적지까지 움직이며 순차, 반복, 선택, 비교연산 등의 개념을 자연스럽게 익힐 수 있어요.', learning_process_by_grades: '학년별 학습과정', learning_process_by_grades_sub1: '4가지 유형으로 쉽고 재미있게 배우는 프로그래밍의 원리! 지금 시작해보세요!', e3_to_e4: '초등 3-4 학년', e5_to_e6: '초등 5-6 학년', m1_to_m3: '중등 이상', make_using_entry: '엔트리로 만들기', make_using_entry_desc_1: '블록을 쌓아 여러 가지 소프트웨어를 만들어보세요!', make_using_entry_desc_2: '제공되는 교재를 다운받아 차근차근 따라하다보면 애니메이션, 미디어아트, 게임 등 다양한 작품을 만들 수 있어요.', make_through_ebs_1: 'EBS 방송영상으로 소프트웨어를 배워보세요.', make_through_ebs_2: '방송영상은 물론, 차근차근 따라 할 수 있는 특별영상과 함께 누구나 쉽게 다양한 소프트웨어를 만들 수 있어요.', support_block_js: '블록 코딩과 자바스크립트 언어를 모두 지원합니다.', study_ebs_title_1: '순서대로! 차례대로!', study_ebs_desc_1: '[실습] 엔트리봇의 심부름', study_ebs_title_2: '쉽고 간단하게!', study_ebs_desc_2: '[실습] 꽃송이 만들기', study_ebs_title_3: '언제 시작할까?', study_ebs_desc_3: '[실습] 동물가족 소개', study_ebs_title_4: '다른 선택, 다른 결과!', study_ebs_desc_4: '[실습] 텔레파시 게임', study_ebs_title_5: '정보를 담는 그릇', study_ebs_desc_5: '[실습] 덧셈 로봇 만들기', study_ebs_title_6: '요모조모 따져 봐!', study_ebs_desc_6: '[실습] 복불복 룰렛', study_ebs_title_7: '번호로 부르면 편해요!', study_ebs_desc_7: '[실습] 나만의 버킷리스트', study_ebs_title_8: '무작위 프로그램을 만들어라!', study_ebs_desc_8: '[실습] 무작위 캐릭터 만들기', study_ebs_title_9: '어떻게 찾을까?', study_ebs_desc_9: '[실습] 도서관 책 검색', study_ebs_title_10: '줄을 서시오!', study_ebs_desc_10: '[실습] 키 정렬 프로그램', event: '이벤트', divide: '분기', condition: '조건', random_number: '무작위수', search: '탐색', sorting: '정렬', parallel: '병렬', signal: '신호', input_output: '입출력', sequential: '순차', repeat: '반복', choice: '선택', repeat_advanced: '반복(횟수+조건)', function: '함수', compare_operation: '비교연산', arithmetic: '산술연산', entry_recommended_mission: '엔트리 추천 미션', more_mission: '더 많은 미션 보러가기', line_rangers_title: '라인레인저스와\n샐리 구하기', line_rangers_content: '메피스토 기지에 갇힌\n샐리를 구해주세요!', pinkbean_title_string_basic: '메이플스토리 초급 헤네시스', pinkbean_title_string_intermediate: '메이플스토리 중급 엘리니아', pinkbean_title_string_advanced: '메이플스토리 고급 엘나스', pinkbean_title: '핑크빈과 함께 신나는\n메이플 월드로!', pinkbean_content: '핑크빈이 메이플 월드 모험을\n무사히 마칠 수 있도록 도와주세요.', entrybot_school: '엔트리봇 학교 가는 길', entrybot_school_desc_1: '엔트리봇이 책가방을 챙겨 학교에', entrybot_school_desc_2: '도착할 수 있도록 도와주세요!', robot_factory: '로봇 공장', robot_factory_desc_1: '로봇공장에 갇힌 엔트리봇!', robot_factory_desc_2: '탈출하기 위해 부품을 모두 모아야해요.', electric_car: '전기 자동차', electric_car_desc_1: '엔트리봇 자동차가 계속 앞으로 나아갈 수', electric_car_desc_2: '있도록 연료를 충전해 주세요.', forest_adventure: '숲속 탐험', forest_adventure_desc_1: '엔트리봇 친구가 숲속에 갇혀있네요!', forest_adventure_desc_2: '친구를 도와주세요.', town_adventure: '마을 탐험', town_adventure_desc_1: '배고픈 엔트리봇을 위해 마을에 있는', town_adventure_desc_2: '연료를 찾아주세요.', space_trip: '우주 여행', space_trip_desc_1: '우주탐사를 마친 엔트리봇!', space_trip_desc_2: '지구로 돌아갈 수 있도록 도와주세요.', learn_programming_mission: '미션을 해결하며 배우는 프로그래밍', make_open_lecture: '오픈 강의 만들기', group_created: '만든 학급', group_signup: '가입한 학급', delete_from_list: '을(를) 목록에서 삭제하시겠습니까?', delete_from_list_en: '', lecture_collection: '강의 모음', edit_mypage_profile: '자기소개 정보 관리', main_image: '메인 이미지', edit_profile_success: '반영되었습니다.', no_project_1: '내가 만든 작품이 없습니다.', no_project_2: '지금 작품 만들기를 시작해보세요!', empty_project_1: '아직 만들어진 작품이 없습니다.', no_marked_project_1: '관심 작품이 없습니다.', no_marked_group_project_1: '학급 관심 작품이 없습니다.', no_marked_project_2: "'작품 공유하기'에서 다양한 작품을 만나보세요!", no_markedGroup_project_2: "'학급 공유하기'에서 다양한 작품을 만나보세요!", view_project_all: '작품 구경하기', no_lecture_1: '내가 만든 강의가 없습니다.', empty_lecture_1: '아직 만들어진 강의가 없습니다.', no_lecture_2: "'오픈 강의 만들기'에서 강의를 만들어보세요!", no_marked_lecture_1: '관심 강의가 없습니다.', no_marked_group_lecture_1: '학급 관심 강의가 없습니다.', no_marked_lecture_2: "'오픈 강의'에서 다양한 강의를 만나보세요!", view_lecture: '강의 살펴보기', no_studying_lecture_1: '학습 중인 강의가 없습니다.', no_studying_lecture_2: "'오픈 강의'에서 학습을 시작해보세요!", no_lecture_collect_1: '내가 만든 강의 모음이 없습니다.', empty_lecture_collect_1: '아직 만들어진 강의 모음이 없습니다.', no_lecture_collect_2: "'오픈 강의 모음 만들기'에서 강의 모음을 만들어보세요!", make_lecture_collection: '강의 모음 만들기', no_marked_lecture_collect_1: '관심 강의 모음이 없습니다.', no_marked_lecture_group_collect_1: '학급 관심 강의 모음이 없습니다.', no_marked_lecture_collect_2: "'오픈 강의'에서 다양한 강의를 만나보세요!", view_lecture_collection: '강의 모음 살펴보기', no_studying_lecture_collect_1: '학습 중인 강의 모음이 없습니다.', no_studying_lecture_collect_2: "'오픈 강의'에서 학습을 시작해보세요!", my_lecture: '나의 강의', markedGroup: '학급 관심', markedGroup_lecture: '학급 관심 강의', markedGroup_curriculum: '학급 관심 강의모음', marked_lecture: '관심 강의', marked_lecture_collection: '나의 관심 강의 모음', marked_marked_curriculum: '관심 강의 모음', studying_lecture: '학습 중인 강의', completed_lecture: '학습 완료 강의', my_lecture_collection: '나의 강의 모음', my: '나의', studying_lecture_collection: '학습 중인 강의 모음', completed_lecture_collection: '학습 완료한 강의 모음', my_curriculum: '나의 강의 모음', studying_curriculum: '학습 중인 강의 모음', completed_curriculum: '학습 완료한 강의 모음', materialCC: '엔트리에서 제공하는 모든 교육 자료는 CC-BY 2.0 라이선스에 따라 자유롭게 이용할 수 있습니다.', materialccby_new: '엔트리의 교육자료는 CC-BY 2.0 라이선스에 따라 출처를 밝히고 자유롭게 이용할 수 있습니다.', entry_copyright_info: '엔트리 저작권 가이드 보기', pdf: 'PDF', helper: '도움말', youtube: '영상', tvcast: '영상', goal: '목표', basicproject: '시작단계', hw: '하드웨어', object: '오브젝트', console: '콘솔', download_info: '모든 교육자료는 각각의 제목을 클릭 하시면 다운받으실 수 있습니다.', entry_materials_all: '엔트리 교육자료 모음', entry_material: '엔트리 교육자료', recommand_grade: '추천학년', g3_4_grades: '3-4 학년', g5_6_grades: '5-6 학년', middle_grades: '중학생 이상', entry_go_go: '엔트리 고고!', entry_go_go_desc: '학년별, 난이도 별로 준비된 교재를 만나보세요.', entry_go_go_desc2: '각 과정별로 교육과정, 학습지, 교사용 해설서 3종 세트가 제공됩니다.', stage_beginner: '초급', stage_middle: '중급', stage_high: '고급', middle_school_short: '중등', learn_entry_programming: '따라하며 배우는 엔트리 프로그래밍', entry_programming_desc: '차근차근 따라 하다 보면 어느새 나도 엔트리 고수!', ebs: 'EBS', ebs_material_desc: '방송 영상과 교사용 지도서를 활용하여 수업을 해보세요!', season_1_material: '시즌1 교사용 지도서', season_2_material: '시즌2 교사용 지도서', season_1: '시즌1', playsoftware_ebs: 'EBS 소프트웨어야 놀자!', material_teacher_guide: '교사용 지도서', season_2: '시즌2', compute_think_textbook: '교과서로 배우는 컴퓨팅 사고력', computational_sw: '국어, 수학, 과학, 미술... 학교에서 배우는 다양한 교과와 연계하여 SW를 배워보세요!', python_coding_text: '엔트리파이선', python_coding_textbook: '텍스트 코딩 세계로 떠나는 여행! 엔트리파이선', python_coding_desc: '엔트리파이선으로 텍스트 언어의 구조와 문법을 자연스럽게 배워보세요!', entry_x_hardware_text: '엔트리 X 하드웨어 교육자료', entry_x_hardware: '엔트리 X 하드웨어 교육자료 모음', e_sensor: 'E 센서보드', e_sensor_board: 'E 센서보드', e_sensor_robot: 'E 센서로봇', arduino: '아두이노', arduinoext: '아두이노 Uno 확장모드', arduinonano: '아두이노 Nano', albert: '알버트', orange_board: '오렌지보드', arduino_board: '아두이노', joystick: '조이스틱 센서 쉴드', ardublock: '아두블럭', mkboard: '디지털 몽키보드', mechatro_nano: '메카트로 나노+', mechatro_uno: '메카트로 우노+', memaker: '미메이커', edumaker: '에듀메이커 보드', codingtoolbox: '코딩툴박스', materials_etc_all: '기타 교육자료 모음', materials_teaching: '교원 연수 자료', materials_etc: '기타 참고 자료', materials_etc_resource: '참고 자료', materials_teaching_etc: '교원 연수 및 참고자료', materials_teaching_1: 'SW교육의 필요성과 교육 방법론', materials_teaching_2: '엔트리와 함께하는 언플러그드 활동', materials_teaching_3: '게임하듯 알고리즘을 배우는 엔트리 미션 해결하기', materials_teaching_4: '실생활 문제해결을 위한 엔트리 프로그래밍', materials_teaching_5: '교과연계 SW교육1 (미술,수학,사회)', materials_teaching_6: '교과연계 SW교육2 (국어,과학,음악)', materials_teaching_7: '피지컬 컴퓨팅 실습1(E센서보드)', materials_teaching_8: '피지컬 컴퓨팅 실습2(햄스터)', materials_teaching_9: '수업에 필요한 학급/강의 기능 알아보기', materials_etc_1: '엔트리 첫 사용자를 위한 스타트 가이드', materials_etc_2: '수업에 바로 활용할 수 있는 다양한 콘텐츠 모음집', materials_etc_3: '월간 엔트리', materials_etc_4: '엔트리 설명서', materials_etc_5: '엔트리 소개 자료', materials_etc_6: '엔트리 블록 책받침', materials_etc_7: '엔트리파이선 예제 및 안내', jr_if_1: '만약', jr_if_2: '앞에 있다면', jr_fail_no_pencil: '이런 그곳에는 연필이 없어. 연필이 있는 곳에서 사용해보자~', jr_fail_forgot_pencil: '앗! 책가방에 넣을 연필을 깜빡했어. 연필을 모아서 가자~', jr_fail_much_blocks: '너무많은 블록을 사용했어, 다시 도전해볼래?', cparty_jr_success_1: '좋아! 책가방을 챙겼어!', go_right: '오른쪽', go_down: ' 아래쪽', go_up: ' 위쪽', go_left: ' 왼쪽', go_forward: '앞으로 가기', jr_turn_left: '왼쪽으로 돌기', jr_turn_right: '오른쪽으로 돌기', go_slow: '천천히 가기', repeat_until_reach_1: '만날 때 까지 반복하기', repeat_until_reach_2: '', pick_up_pencil: '연필 줍기', repeat_0: '', repeat_1: '반복', when_start_clicked: '시작 버튼을 눌렀을 때', age_0: '작품체험', create_character: '캐릭터 만들기', age_7_9: '초등 저학년', going_school: '엔트리 학교가기', age_10_12_1: '초등 고학년1', collect_parts: '로봇공장 부품모으기', age_10_12_2: '초등 고학년2', driving_elec_car: '전기자동차 운전하기', age_13: '중등', travel_space: '우주여행하기', people: '사람', all: '전체', life: '일상생활', nature: '자연', animal_insect: '동물/곤충', environment: '자연환경', things: '사물', vehicles: '이동수단', others: '기타', fantasy: '판타지', instrument: '악기', piano: '피아노', marimba: '마림바', drum: '드럼', janggu: '장구', sound_effect: '효과음', others_instrument: '기타타악기', aboutEntryDesc_1: '엔트리는 누구나 무료로 소프트웨어 교육을 받을 수 있는 플랫폼입니다.', aboutEntryDesc_2: '학생들이 소프트웨어를 쉽고 재미있게 학습하고,', aboutEntryDesc_3: '선생님들은 효과적으로 학생들을 가르칠 수 있습니다.', aboutEntryDesc_4: '엔트리는 공공재와 같이', aboutEntryDesc_5: '비영리로 운영됩니다.', viewProjectTerms: '이용정책 보기', openSourceTitle: '오픈소스를 통한 생태계 조성', openSourceDesc_1: '엔트리의 소스코드 뿐 아니라', openSourceDesc_2: '모든 교육 자료는 CC라이센스를 ', openSourceDesc_3: '적용하여 공개합니다.', viewOpenSource: '오픈소스 보기', eduPlatformTitle: '국내교육 현장에 맞는 교육 플랫폼', eduPlatformDesc_1: '국내 교육 현장에 적합한 교육 도구가', eduPlatformDesc_2: '될 수 있도록 학교 선생님들과 함께', eduPlatformDesc_3: '개발하고 있습니다.', madeWith: '자문단', researchTitle: '다양한 연구를 통한 전문성 강화', researchDesc_1: '대학/학회 등과 함께 다양한 연구를', researchDesc_2: '진행하여 전문성을 강화해나가고', researchDesc_3: '있습니다.', viewResearch: '연구자료 보기', atEntry: '엔트리에서는', entryLearnDesc_1: '재미있게 배우는 학습공간', entryLearnDesc_2: '<학습하기>에서는 엔트리를 학습할 수 있는 콘텐츠가 준비되어 있습니다.', entryLearnDesc_3: '게임을 하듯이 주어진 미션을 프로그래밍으로 해결하고 영상을 시청하며 ', entryLearnDesc_4: '소프트웨어 제작 원리를 학습할 수 있습니다.', entryMakeDesc_1: '<만들기>에서는 미국 MIT에서 개발한 Scratch와 같은 블록형 프로그래밍 언어를', entryMakeDesc_2: '사용하여 프로그래밍을 처음 접하는 사람들도 쉽게 자신만의 창작물을 만들 수 있습니다.', entryMakeDesc_3: "또한 블록 코딩과 텍스트 코딩의 중간다리 역할을 하는 '엔트리파이선' 모드에서는", entryMakeDesc_4: '텍스트 언어의 구조와 문법을 자연스럽게 익힐 수 있습니다.', entryMakeDesc_5: '', entryShareDesc_1: '<공유하기>에서는 엔트리를 통해 제작한 작품을 다른 사람들과 공유할 수 있습니다.', entryShareDesc_2: '또한 공유된 작품이 어떻게 구성되었는지 살펴보고 발전시켜 자신만의 작품을 만들 수', entryShareDesc_3: '있습니다. 공동 창작도 가능하여 친구들과 협업해 더 멋진 작품을 만들어 볼 수 있습니다.', entryGroup: '학급기능', entryGroupTitle: '우리 반 학습 공간', entryGroupDesc_1: '<학급기능>은 선생님이 학급별로 학생들을 관리할 수 있는 기능입니다. 학급끼리 학습하고', entryGroupDesc_2: '작품을 공유할 수 있으며 과제를 만들고 학생들의 결과물을 확인할 수 있습니다.', entryGroupDesc_3: '또한 선생님은 강의 기능을 활용하여 학생들의 수준에 맞는 학습환경을', entryGroupDesc_4: '맞춤형으로 제공함으로써 효율적이고 편리하게 수업을 진행할 수 있습니다.', entryGroupDesc_5: '', unpluggedToPhysical: '언플러그드 활동부터 피지컬 컴퓨팅까지', algorithmActivity: '기초 알고리즘', programmignLang: '교육용 프로그래밍 언어', unpluggedDesc_1: '엔트리봇 보드게임과 카드게임을 통해 컴퓨터 없이도', unpluggedDesc_2: '소프트웨어의 기본 개념과 원리(순차, 반복, 선택, 함수)를 익힐 수 있습니다.', entryMaze: '엔트리봇 미로탈출', entryAI: '엔트리봇 우주여행', algorithmDesc_1: '게임을 하듯이 미션을 해결하고 인증서를 받아보세요.', algorithmDesc_2: '소프트웨어의 기본적인 원리를 쉽고 재미있게 배울 수 있습니다.', programmingLangDesc_1: '엔트리에서는 블록을 쌓듯이 프로그래밍을 하기 때문에 누구나 쉽게', programmingLangDesc_2: '자신만의 게임, 애니메이션, 미디어아트와 같은 멋진 작품을 만들고 공유할 수 있어 교육용으로 적합합니다.', viewSupporHwVideo: '하드웨어 가이드 영상 보기', viewSupporHw: '연결되는 하드웨어 보기', supportHwDesc_1: '엔트리와 피지컬 컴퓨팅 도구를 연결하면 현실세계와 상호작용하는 멋진 작품들을 만들어낼 수 있습니다.', supportHwDesc_2: '국내, 외 다양한 하드웨어 연결을 지원하며, 계속적으로 추가될 예정입니다.', entryEduSupport: '엔트리 교육 지원', eduSupportDesc_1: '엔트리에서는 소프트웨어 교육을 위한 다양한 교육 자료를 제작하여 무상으로 배포하고 있습니다.', eduSupportDesc_2: '모든 자료는 교육자료 페이지에서 다운받으실 수 있습니다.', materials_1_title: '수준별 교재', materials_1_desc_1: '학년별 수준에 맞는 교재를 통해 차근차근', materials_1_desc_2: '따라하며 쉽게 엔트리를 익혀보세요!', materials_2_title: 'EBS 방송 연계 교안', materials_2_desc_1: 'EBS 소프트웨어야 놀자 방송과 함께', materials_2_desc_2: '교사용 수업 지도안을 제공합니다.', materials_3_title: '초, 중등 교과 연계 수업자료', materials_3_title_2: '', materials_3_desc_1: '다양한 과목에서 만나는 실생활 문제를', materials_3_desc_2: '컴퓨팅 사고력으로 해결해 보세요.', moreMaterials: '더 많은 교육 자료 보러가기', moreInfoAboutEntry_1: '더 많은 엔트리의 소식들을 확인하고 싶다면 아래의 링크들로 접속해보세요.', moreInfoAboutEntry_2: '교육자료 외에도 다양한 SW 교육과 관련한 정보를 공유하고 있습니다.', material_menu_type_robot: '로봇형', material_menu_type_module: '모듈형', material_menu_type_board: '보드형', blog: '블로그', post: '포스트', tvCast: 'TV캐스트', about_entry_pre: '엔트리', about_youtube: '유튜브', about_facebook: '페이스북', albertSchool: '알버트 스쿨버전', arduinoBoard: '아두이노 정품보드', arduinoCompatible: '아두이노 호환보드', bitBlock: '비트블록', bitbrick: '비트브릭', creamo: '크리모', playcode: '플레이코드', funboard: '펀보드', truerobot: '뚜루뚜루', bingle: '빙글', bingles: '빙글S', codeino: '코드이노', epor: '에뽀', petrone_v2: '페트론V2', petrone_v2_drone: '드론', petrone_v2_car: '자동차', 'e-sensor': 'E-센서보드', 'e-sensorUsb': 'E-센서보드(유선연결)', 'e-sensorBT': 'E-센서보드(무선연결)', mechatronics_4d: '4D 메카트로닉스', esensor_board: 'E - 센서보드', esensor_robot: 'E - 센서로봇', hamster: '햄스터', hummingbird: '허밍버드 듀오', roboid: '로보이드', turtle: '거북이', littlebits: '리틀비츠', orangeBoard: '오렌지 보드', robotis_carcont: '로보티즈 로봇자동차', robotis_IoT: '로보티즈 IoT', robotis_IoT_Wireless: '로보티즈 IoT(무선연결)', dplay: '디플레이', iboard: '아이보드', nemoino: '네모이노', xbot_epor_edge: '엑스봇(원터치 동글/USB)', XbotBT: '엑스봇 에뽀/엣지 블투투스', robotori: '로보토리', rokoboard: '로코보드', neobot: '네오봇', neobot_sensor_theme: '네오봇 센서 테마', mechatro: '메카트로', about: '알아보기', articles: '토론하기', gallery: '구경하기', learn: '학습하기', login: '로그인', logout: '로그아웃', make: '만들기', register: '가입하기', Join: '회원가입', Edit_info: '내 정보 수정', Discuss: '글 나누기', Explore: '구경하기', Load: '불러오기', My_lesson: '오픈 강의', textbook_learning: '교과서 학습하기', Resources: '교육 자료', play_software: '소프트웨어야 놀자!', problem_solve: '엔트리 학습하기', learning_textbook: '교과서 학습하기', context_textbook: '초등 교과서 그대로 선생님은 학교 수업을 학생은 집에서 예습, 복습을 할 수 있어요.', info_banner_textbook: '* 출판사는 가나다순 노출입니다.', banner_textbook: '더욱 다양하고', banner_textbook_2: '재미있는 학습을 하고 싶다면?', banner_textbook_right_banner: '학생용 활동지와 교사용', banner_textbook_right_banner2: '학습 도움 자료가 필요하신가요?', banner_textbook_right_banner_btn: '교과서별 자료 받기', Learn: '학습하기', teaching_tools: '엔트리 교구', about_entry: '엔트리 소개', what_entry: '엔트리는?', create: '만들기', create_new: '새로 만들기', start_programming: '소프트웨어 교육의 첫걸음', Entry: '엔트리', intro_learning: '누구나 쉽고 재밌게 소프트웨어를 배울 수 있어요. ', intro_learning_anyone: '지금 바로 시작해보세요! ', start_now: 'For Free, Forever.', welcome_entry: '엔트리에 오신걸 환영합니다.', student: '학생', non_menber: '일반인', teacher: '선생님', terms_conditions: '이용약관', personal_information: '개인정보 수집 및 이용에 대한 안내', limitation_liability: '책임의 한계와 법적 고지', entry_agree: '엔트리의 이용약관에 동의 합니다.', info_agree: '개인정보 수집 및 이용에 동의합니다.', next: '다음', enter_individual_info: '개인정보 입력', enter_id: '아이디 입력', enter_password: '비밀번호 입력', confirm_password: '비밀번호 확인', enter_password_again: '비밀번호를 한번 더 입력하세요.', validation_password: '5자 이상의 영문/숫자 등을 조합하세요.', validation_id: '4~20자의 영문/숫자를 조합하세요', prev: '이전', born_year: '태어난 연도', select_born: '태어난 연도를 선택 하세요', year: '년', gender: '성별', choose_gender: '성별을 선택 하세요', male: '남성', female: '여성', language: '언어', best_language: '주 언어를 선택 하세요', korean: '한국어', english: '영어', viet: '베트남', japan: '일본어', russia: '러시아어', chinese_simplified: '중국어(간체)', chinese_traditional: '중국어(번체)', option_email: '이메일(선택)', insert_email: '이메일 주소를 입력 하세요', sign_up_complete: '회원 가입이 완료 되었습니다', agree_terms_conditions: '이용약관에 동의해 주세요.', agree_personal_information: '개인정보 수집 및 이용에 대한 안내에 동의해 주세요.', insert_studying_stage: '작품을 공유하고 싶은 학급을 선택해 주세요.', insert_born_year: '태어난 연도를 입력해 주세요.', insert_gender: '성별을 선택지에서 선택해 주세요.', select_language: '언어를 선택해 주세요.', check_email: '이메일 형식을 확인해 주세요.', already_exist_id: '이미 존재하는 아이디 입니다.', id_validation_id: '아이디는 4~20자의 영문/숫자를 조합하세요', password_validate_pwd: '패스워드는 5자 이상의 영문/숫자 등을 조합하세요.', password_validate_pwd_length: '패스워드는 최소 5자 이상으로 입력해 주세요.', neoid_username_same_id: '이미 사용중인 아이디 입니다.(NEOID)', insert_same_pwd: '같은 비밀번호를 입력해 주세요.', studying_stage_group: '작품 공유 학급', studying_stage: '작품을 공유하고 싶은 학급을 선택해 주세요.', password: '비밀번호 입력', save_id: '아이디 저장', auto_login: '자동 로그인', enter_id_pw: '아이디, 비밀번호 입력', forgot_password: '아이디와 비밀번호가 기억나지 않으세요 ?', did_not_join: '아직 엔트리 회원이 아니세요?', go_join: '회원가입하기 ', renew_index_text_00: '엔트리 교과서 학습하기', renew_index_text_01: '교과서로 엔트리를 배워보세요.', renew_index_text_02: '초등학교 교과서 강의를 통해', renew_index_text_02_2: '엔트리를 배워보세요!', renew_index_text_03: '교과서 학습하기', renew_index_text_03_2: '바로가기', renew_index_text_1: '2019년, 엔트리가 바뀝니다', renew_index_text_2: '확 바뀐 작품 만들기', renew_index_text_3: '지금 새로운 기능을 확인하고', renew_index_text_3_2: 'PC와 태블릿으로 작품을 만들어보세요!', renew_index_text_4: '자세히 보기', first_step: '소프트웨어 교육의 첫걸음', entry_content_one: '상상했던 것들을 블록 놀이하듯 하나씩 쌓아보세요.', entry_content_two: '게임, 애니메이션, 미디어아트와 같은 멋진 작품이 완성된답니다!', entry_content_three: '재미있는 놀이로 배우고, 나만의 멋진 작품을 만들어 친구들과 공유할 수 있는 멋진 엔트리의 세상으로 여러분을 초대합니다!', funny_space: '재미있게 배우는 학습공간', in_learn_section: '< 학습하기 > 에서는', learn_problem_solving: '컴퓨터를 활용해 논리적으로 문제를 해결할 수 있는 다양한 학습 콘텐츠가 준비되어 있습니다. 게임을 하듯이 주어진 미션들을 프로그래밍으로 해결해볼 수도 있고 재미있는 동영상으로 소프트웨어의 원리를 배울 수도 있습니다 .', joy_create: '창작의 즐거움', in_make: '< 만들기 > 는', make_contents: '미국 MIT에서 개발한 Scratch와 같은 비주얼 프로그래밍 언어를 사용하여 프로그래밍을 처음 접하는 사람들도 쉽게 나만의 창작물을 만들 수 있습니다. 또 엔트리를 통해 만들 수 있는 컨텐츠의 모습은 무궁무진합니다. 과학 시간에 배운 물리 법칙을 실험해 볼 수도 있고 좋아하는 캐릭터로 애니메이션을 만들거나 직접 게임을 만들어 볼 수 있습니다.', and_content: '또 엔트리를 통해 만들 수 있는 콘텐츠의 모습은 무궁무진합니다. 과학 시간에 배운 물리 법칙을 실험해 볼 수도 있고 좋아하는 캐릭터로 애니메이션을 만들거나 직접 게임을 만들어 볼 수 있습니다.', share_collaborate: '공유와 협업', explore_contents: '< 구경하기 > 에서는 엔트리를 통해 제작한 작품을 다른 사람들과 쉽게 공유할 수 있습니다. 또한 공유된 작품이 어떻게 구성되었는지 살펴볼 수 있고, 이를 발전시켜 자신만의 프로젝트를 만들 수 있습니다. 그리고 엔트리에서는 공동 창작도 가능합니다. 친구들과 협업하여 더 멋진 프로젝트를 만들어볼 수 있습니다.', why_software: '왜 소프트웨어 교육이 필요할까?', speak_obama_contents: '컴퓨터 과학을 배우는 것은 단지 여러분의 미래에만 중요한 일이 아닙니다. 이것은 우리 미국의 미래를 위해 중요한 일 입니다.', obama: '버락 오바마', us_president: '미국 대통령', billgates_contents: '컴퓨터 프로그래밍은 사고의 범위를 넓혀주고 더 나은 생각을 할 수 있게 만들며 분야에 상관없이 모든 문제에 대해 새로운 해결책을 생각할 수 있는 힘을 길러줍니다.', billgates: '빌게이츠', chairman_micro: 'Microsoft 회장', eric_contents: '현재 디지털 혁명은 지구상 대부분의 사람들에게 아직 시작도 안된 수준입니다. 프로그래밍을 통해 향후 10년간 모든 것이 변화할 것 입니다.', eric: '에릭 슈미츠', sandbug_contents: '오늘날 컴퓨터 과학에 대한 이해는 필수가 되었습니다. 우리의 국가 경쟁력은 우리가 아이들에게 이것을 얼마나 잘 가르칠 수 있느냐에 달려있습니다.', sandbug: '쉐릴 샌드버그', view_entry_tools: '엔트리와 함께할 수 있는 교구들을 살펴볼 수 있습니다.', solve_problem: '미션 해결하기', solve_problem_content: '게임을 하듯 미션을 하나 하나 해결하며 소프트웨어의 기본 원리를 배워보세요!', find_extra_title: '엔트리봇 부품 찾기 대작전', all_ages: '전 연령', total: '총', step: '단계', find_extra_contents: '로봇 강아지를 생산하던 루츠 공장에 어느 날 갑자기 일어난 정전 사태로 태어난 특별한 강아지 엔트리 봇. 아직 조립이 덜 된 나머지 부품들을 찾아 공장을 탈출 하도록 도와주면서 소프트웨어의 동작 원리를 익혀보자!', software_play_contents: "EBS에서 방영한 '소프트웨어야 놀자' 프로그램을 실습해볼 수 있습니다.", resources_contents: '엔트리를 활용한 다양한 교육자료들을 무료로 제공합니다.', from: ' 출처', sw_camp: '미래부 SW 창의캠프', elementary: '초등학교', middle: '중학교', grades: '학년', lesson: '차시', sw_contents_one: '5차시 분량으로 초등학생이 엔트리와 피지컬 컴퓨팅을 경험할 수 있는 교재입니다. 학생들은 엔트리 사용법을 학습하고, 그림판과 이야기 만들기를 합니다. 마지막에는 아두이노 교구를 활용하여 키보드를 만들어보는 활동을 합니다.', sw_camp_detail: '미래창조과학부 SW창의캠프', sw_contents_two: '5차시 분량으로 중학생이 엔트리와 피지컬 컴퓨팅을 경험할 수 있는 교재입니다. 학생들은 엔트리 사용법을 학습하고, 미로찾기 게임과, 퀴즈 프로그램을 만들어 봅니다. 마지막에는 아두이노 교구를 활용하여 키보드로 자동차를 조종하는 활동을 합니다.', sw_contents_three: "선생님들이 학교에서 시작할 수 있는 소프트웨어 수업 지도서입니다. 다양한 언플러그드 활동과, '소프트웨어야 놀자' 방송을 활용한 수업 지도안이 담겨 있습니다.", naver_sw: 'NAVER 소프트웨어야 놀자', teacher_teaching: '교사용지도서 (초등학교 5~6학년 이상)', funny_sw: '즐거운 SW놀이 교실', sw_contents_four: '소프트웨어를 놀이하듯 재미있게 배울 수 있는 교재로 엔트리보드게임을 비롯한 다양한 언플러그드 활동과 엔트리 학습모드로 소프트웨어를 만드는 기본 원리를 배우게 됩니다. 기본 원리를 배웠다면 학생들은 이제 엔트리로 이야기, 게임, 예술작품, 응용프로그램을 만드는 방법을 배우고, 자신이 생각한 소프트웨어를 만들고 발표할 수 있도록 교재가 구성되어 있습니다.', ct_text_5: '교과서와 함께 키우는 컴퓨팅 사고력', teacher_grade_5: '교원 (초등학교 5학년)', ct_text_5_content: '실생활의 문제를 해결하자는 테마로 준비된 총 8개의 학습콘텐츠가 담긴 교사용 지도안입니다. 각 콘텐츠는 개정된 교육과정을 반영한 타교과와의 연계를 통해 다양한 문제를 만나고 해결해볼 수 있도록 설계되었습니다. 아이들이 컴퓨팅 사고력을 갖춘 융합형 인재가 될 수 있도록 지금 적용해보세요!', ct_text_6: '교과서와 함께 키우는 컴퓨팅 사고력', teacher_grade_6: '교원 (초등학교 6학년)', ct_text_6_content: '실생활의 문제를 해결하자는 테마로 준비된 총 8개의 학습콘텐츠가 담긴 교사용 지도안입니다. 각 콘텐츠는 개정된 교육과정을 반영한 타교과와의 연계를 통해 다양한 문제를 만나고 해결해볼 수 있도록 설계되었습니다. 아이들이 컴퓨팅 사고력을 갖춘 융합형 인재가 될 수 있도록 지금 적용해보세요!', sw_use: '모든 교재들은 비영리 목적에 한하여 저작자를 밝히고 자유롭게 이용할 수 있습니다.', title: '제목', writer: '작성자', view: '보기', date: '등록일', find_id_pwd: '아이디와 비밀번호 찾기', send_email: '비밀번호를 잊은 경우 이메일로 비밀번호를 찾을 수 있습니다.', user_not_exist: '존재하지 않는 이메일 주소 입니다.', not_signup: '아직 회원이 아니세요?', send: '발송하기', sensorboard: '엔트리봇 센서보드', physical_computing: '피지컬 컴퓨팅', sensorboard_contents: '아두이노를 사용하기 위해서 더 이상 많은 케이블을 사용해 회로를 구성할 필요가 없습니다. 엔트리 보드는 아두이노 위에 끼우기만 하면 간단하게 LED, 온도센서, 소리센서, 빛, 슬라이더, 스위치를 활용할 수 있습니다. 이제 엔트리 보드를 활용해 누구라도 쉽게 자신만의 특별한 작품을 만들어보세요!', entrybot_boardgame: '엔트리봇 보드게임', unplugged: '언플러그드 활동', unplugged_contents: '재밌는 보드게임을 통해 컴퓨터의 작동 원리를 배워보세요. 로봇강아지인 엔트리봇이 정전된 공장에서 필요한 부품을 찾아 탈출하도록 돕다보면 컴퓨터 전문가처럼 문제를 바라 볼 수 있게됩니다.', entrybot_cardgame: '엔트리봇 카드게임 : 폭탄 대소동', entrybot_cardgame_contents: '갑자기 엔트리도시에 나타난 12종류의 폭탄들! 과연 폭탄들을 안전하게 해체할 수 있을까요? 폭탄들을 하나씩 해체하며 엔트리 블록과 함께 소프트웨어의 원리를 배워봐요! 순차, 반복, 조건을 통해 폭탄을 하나씩 해체하다 보면 엔트리도시를 구한 영웅이 될 수 있답니다!', basic_learn: '엔트리 기본 학습', basic_learn_contents: '엔트리를 활용한 다양한 교육 콘텐츠를 제공합니다.', troubleshooting: '문제해결 학습', playsoftware: '소프트웨어야 놀자', make_own_lesson: '나만의 수업을 만들어 다른 사람과 공유할 수 있습니다.', group_lecture: '우리 반 강의', group_curriculum: '우리 반 강의 모음', group_homework: '우리 반 과제', group_noproject: '전시된 작품이 없습니다.', group_nolecture: '생성된 강의가 없습니다.', group_nocurriculum: '생성된 강의 모음이 없습니다.', lecture_contents: '필요한 기능만 선택하여 나만의 수업을 만들어 볼 수 있습니다.', curriculum_contents: '여러개의 강의를 하나의 강의 모음으로 묶어 차근차근 따라할 수 있는 수업을 만들 수 있습니다.', grade_info: '학년 정보', difficulty: '난이도', usage: '사용요소', learning_concept: '학습개념', related_subject: '연계 교과', show_more: '더보기', close: '닫기', latest: '최신순', viewCount: '조회수', viewer: '조회순', like: '좋아요순', comment: '댓글순', entire_period: '전체기간', today: '오늘', latest_week: '최근 1주일', latest_month: '최근 1개월', latest_three_month: '최근 3개월', current_password: '현재 비밀번호', change_password: '비밀번호 변경', incorrect_password: '비밀번호가 일치하지 않습니다.', incorrect_password_login: '아이디 또는 비밀번호를 잘못 입력하셨습니다.', suspension_user: '이용 정지된 계정입니다.', blocked_user: '승인되지 않은 사용자 입니다.', new_password: '새로운 비밀번호', password_option_1: '영문과 숫자의 조합으로 5자 이상이 필요합니다.', again_new_password: '새로운 비밀번호 재입력', enter_new_pwd: '새로운 비밀번호를 입력하세요.', confirm_new_pwd: '새로운 비밀번호를 확인하세요.', enter_new_pwd_again: '새로운 비밀번호를 다시 입력하세요.', password_match: '비밀번호가 일치하지 않습니다.', incorrect_email: '유효한 이메일이 아닙니다', edit_button: '정보수정', edit_profile: '관리', my_project: '나의 작품', my_group: '나의 학급', mark: '관심 작품', prev_state: '이전', profile_image: '자기소개 이미지', insert_profile_image: '프로필 이미지를 등록해 주세요.', at_least_180: '180 x 180 픽셀의 이미지를 권장합니다.', upload_image: '이미지 업로드', about_me: '자기소개', save_change: '변경사항 저장', basic_image: '기본 이미지', profile_condition: '자기소개를 입력해 주세요. 50자 내외', profile_back: '돌아가기', make_project: '작품 만들기', exhibit_project: '작품 전시하기', art_list_shared: '개인', art_list_group_shared: '학급', gl_mode_boost: '부스트 모드', gl_not_supported: '부스트 모드로 실행할 수 없는 환경입니다.\n확인을 누르면 기본모드로 실행됩니다.', view_project: '코드 보기', code_view: '코드보기', noResult: '검색 결과가 없습니다.', comment_view: '댓글', upload_project: '올리기', edit: '수정', save_complete: '저장', just_like: '좋아요', share: '공유', who_likes_project: '작품을 좋아하는 사람', people_interest: '작품을 관심있어 하는 사람', none_person: '없음', inserted_date: '등록일', last_modified: '최종 수정일', original_project: '원본 작품', for_someone: '님의', original_project_deleted: '원본 작품이 삭제되었습니다.', delete_project: '삭제', delete_group_project: '목록에서 삭제', currnet_month_time: '월', current_day_time: '일', game: '게임', animation: '애니메이션', media_art: '미디어 아트', physical: '피지컬', etc: '기타', connected_contents: '연계되는 콘텐츠', connected_contents_content: '엔트리와 함께 할 수 있는 다양한 콘텐츠를 만나보세요. 처음 소프트웨어를 배우는 사람이라면 쉽게 즐기는 보드게임부터 아두이노와 같은 피지컬 컴퓨팅을 활용하여 자신만의 고급스러운 창작물을 만들어 볼 수 있습니다.', basic_mission: '기본 미션: 엔트리봇 미로찾기', basic_mission_content: '강아지 로봇을 만드는 공장에서 우연한 정전으로 혼자서 생각할 수 있게 된 엔트리봇! 공장을 탈출하고 자유를 찾을 수 있도록 엔트리봇을 도와주세요!', application_mission: '응용미션: 엔트리봇 우주여행', write_article: '글쓰기', write_contest: '제출하기', view_all_articles: '모든 글 보기', view_own_articles: '내가 쓴 글 보기', view_qna_articles: '답변 없는 글 보기', learning_materials: '교육자료', download_materials: '교육자료 내려받기', download_button: '내려받기', download_all: '모두 내려받기', ebs_software_first: '<소프트웨어야 놀자>는 네이버와 EBS가 함께 만든 교육 콘텐츠입니다. 여기에서는 엔트리를 활용하여 실제로 간단한 프로그램을 만들어보며 소프트웨어의 기초 원리를 배워나갈 수 있습니다. 또한 각 콘텐츠에서는 동영상을 통해 컴퓨터과학에 대한 선행지식이 없더라도 충분히 재미와 호기심을 느끼며 진행할 수 있도록 준비되어있습니다.', go_software: '소프트웨어야 놀자 가기', ebs_context: 'EBS 동영상 가기', ebs_context_hello: 'EBS 가기', category: '카테고리', add_picture: '사진첨부', upload_article: '글 올리기', list: '목록', report: '신고하기', upload: '올리기', staff_picks: '스태프 선정', popular_picks: '인기 작품', lecture_header_more: '더 만들어 보기', lecture_header_reset: '초기화', lecture_header_reset_exec: '초기화 하기', lecture_header_save: '저장', lecture_header_save_content: '학습내용 저장하기', lecture_header_export_project: '내 작품으로 저장하기', lecture_header_undo: '취소', lecture_header_redo: '복원', lecture_er_bugs: '버그신고', lecture_container_tab_object: '오브젝트', lecture_container_tab_video: '강의 동영상', lecture_container_tab_project: '완성된 작품', lecture_container_tab_help: '블록 도움말', illigal: '불법적인 내용 또는 사회질서를 위반하는 활동', verbal: '언어 폭력 또는 개인 정보를 침해하는 활동', commertial: '상업적인 목적을 가지고 활동', explicit: '음란물', other: '기타', check_one_more: '하나이상 표기해주세요.', enter_content: '기타의 내용을 입력해 주세요.', report_result: '결과 회신을 원하시면 메일을 입력해 주세요.', report_success: '신고하기가 정상적으로 처리 되었습니다.', etc_detail: '기타 항목 선택후 입력해주세요. 신고와 무관한 욕설 작성 시 이용이 정지될 수 있습니다.', lecture_play: '강의 보기', list_view_link: '다른 강의 모음 보기', lecture_intro: '강의 소개 보기', study_goal: '학습목표', study_description: '설명', study_created: '등록일', study_last_updated: '최종 수정일', study_remove: '삭제', study_group_lecture_remove: '목록에서 삭제', study_group_curriculum_remove: '목록에서 삭제', study_edit: '강의 모음 수정', study_comments: '댓글', study_comment_post: '올리기', study_comment_remove: '삭제', study_comment_edit: '수정', study_comment_save: '저장', study_guide_video: '안내 영상', study_basic_project: '기본 작품', study_done_project: '완성 작품을 선택하세요.', study_usage_element: '사용요소', study_concept_element: '적용개념', study_subject_element: '연계교과', study_computing_element: '컴퓨팅요소', study_element_none: '없음', study_label_like: '좋아요', study_label_interest: '관심 강의', study_label_share: '공유', study_label_like_people: '강좌를 좋아하는 사람', study_label_interest_people: '강좌를 관심있어 하는 사람', study_related_lectures: '강의 목록', study_expand: '전체보기', study_collapse: '줄이기', aftercopy: '주소가 복사되었습니다.', study_remove_curriculum: '강의 모음을 삭제하시겠습니까?', content_required: '내용을 입력하세요', upload_not_supported_file_msg: '지원하지 않는 형식의 파일입니다.', study_remove_lecture: '강의를 삭제하시겠습니까?', lecture_build: '강의 만들기', lecture_build_step1: '1. 강의를 소개하기 위한 정보를 입력해주세요', lecture_build_step2: '2. 학습에 사용되는 기능들만 선택해주세요', lecture_build_step3: '3. 모든 정보를 올바르게 입력했는지 확인해주세요', lecture_build_choice: '어떤 것을 올리시겠습니까?', lecture_build_project: '엔트리 작품', lecture_build_video: '강의 영상', lecture_build_grade: '추천학년', lecture_build_goals: '학습목표', lecture_build_add_goal: '이곳을 클릭하여 목표를 추가', lecture_build_attach: '파일 첨부', lecture_build_attach_text: '20MB 이내의 파일을 업로드해 주세요.', lecture_build_assist: '보조 영상', lecture_build_youtube_url: 'Youtube 공유 링크를 넣어주세요.', lecture_build_project_done: '완성 작품을 선택하세요.', lecture_build_scene_text1: '장면기능을 끄면 새로운 장면을 추가하거나,', lecture_build_scene_text2: '삭제할 수 없습니다.', lecture_build_object_text: '오브젝트 추가하기를 끄면 새로운 오브젝트를 추가하거나 삭제할 수 없습니다.', lecture_build_blocks_text1: '학습에 필요한 블록들만 선택해주세요.', lecture_build_blocks_text2: '선택하지 않은 블록은 숨겨집니다.', lecture_build_basic1: '학습을 시작할때 사용할 작품을 선택해 주세요.', lecture_build_basic2: '학습자는 선택한 작품을 가지고 학습을 하게 됩니다.', lecture_build_help: '이 도움말을 다시 보시려면 눌러주세요.', lecture_build_help_never: '다시보지 않기', lecture_build_close: '닫기', lecture_build_scene: '장면 1', lecture_build_add_object: '오브젝트 추가하기', lecture_build_start: '시작하기', lecture_build_tab_code: '블록', lecture_build_tab_shape: '모양', lecture_build_tab_sound: '소리', lecture_build_tab_attribute: '속성', lecture_build_tab_table: '테이블', lecture_build_block_category: '블록 카테고리를 선택하세요.', lecture_build_attr_all: '전체', lecture_build_attr_var: '변수', lecture_build_attr_signal: '신호', lecture_build_attr_list: '리스트', lecture_build_attr_func: '함수', lecture_build_edit: '강의 수정', lecture_build_remove: '삭제', curriculum_build: '강의 모음 만들기', curriculum_step1: '1. 강의 모음을 소개하는 정보를 입력해주세요.', curriculum_step2: '2. 강의 모음을 구성하는 강의를 선택해주세요.', curriculum_step3: '3. 올바르게 강의 모음이 구성되었는지 확인해주세요.', curriculum_lecture_upload: '강의 올리기', curriculum_lecture_edit: '강의 편집', curriculum_lecture_open: '불러오기', group_lecture_add: '우리 반 강의 추가하기', group_curriculum_add: '우리 반 강의 모음 추가하기', group_lecture_delete: '삭제', group_curriculum_delete: '삭제', group_select: '', group_studentNo: '학번', group_username: '이름', group_userId: '아이디', group_tempPassword: '비밀번호 수정', group_gender: '성별', group_studentCode: '코드', group_viewWorks: '작품 보기', added_group_lecture: '강의가 삭되었습니다.', added_group_curriculum: '강의 모음이 삭제되었습니다.', deleted_group_lecture: '강의가 삭제되었습니다.', deleted_group_curriculum: '강의 모음이 삭제되었습니다.', modal_my: '나의', modal_interest: '관심', modal_project: '작품', section: '단원', connect_hw: '하드웨어 연결', connect_message: '%1에 연결되었습니다.', connect_fail: '하드웨어 연결에 실패했습니다. 연결프로그램이 켜져 있는지 확인해 주세요.', interest_curriculum: '관심 강의 모음', marked_curriculum: '관심 강의 모음', searchword_required: '검색어를 입력하세요.', file_required: '파일은 필수 입력 항목입니다.', file_name_error: '올바른 파일이름을 입력해 주세요.', file_upload_max_count: '한번에 10개까지 업로드가 가능합니다.', image_file_only: '이미지 파일만 등록이 가능합니다.', file_upload_max_size: '10MB 이하만 업로드가 가능합니다.', curriculum_modal_lectures: '나의 강의', curriculum_modal_interest: '관심 강의', group_curriculum_modal_curriculums: '나의 강의 모음', group_curriculum_modal_interest: '관심 강의 모음', picture_import: '모양 가져오기', picture_select: '모양 선택', lecture_list_view: '다른 강의보기', play_software_2: 'EBS 소프트웨어야 놀자2', play_software_2_content: '네이버와 EBS가 함께 만든 두 번째 이야기, <소프트웨어야 놀자> 시즌2를 만나보세요! 재미있는 동영상 강의를 통해 소프트웨어의 기본 개념을 배워보고, 다양하고 흥미로운 주제로 실생활 문제를 해결해 볼 수 있습니다. 방송영상과 특별영상을 보며 재미있는 프로그램들을 직접 만들어보세요. 소프트웨어 교육을 처음 접하는 친구들도 쉽게 소프트웨어와 친구가 될 수 있답니다!', open_project_to_all: '공개', close_project: '비공개', category_media_art: '미디어 아트', go_further: '더 나아가기', marked_project: '관심 작품', marked_group_project: '학급 관심 작품', basic: '기본', application: '응용', the_great_escape: '탈출 모험기', escape_guide_1: '강아지 로봇을 만드는 공장에서 우연한 정전으로 혼자서 생각할 수 있게 된 엔트리봇! ', escape_guide_1_2: ' 공장을 탈출하고 자유를 찾을 수 있도록 엔트리봇을 도와주세요!', escape_guide_2: '엔트리봇이 먼 길을 가기엔 고쳐야 할 곳이 너무 많아 공장에서 탈출하면서 몸을 수리할 수 있는 부품들을 찾아보자! 아직 몸이 완전하지는 않지만 걷거나 뛰면서, 방향을 바꾸는 정도는 가능할 거야! ', escape_guide_2_2: '학습 목표: 순차적 실행', escape_guide_3: '드디어 공장을 탈출했어! 하지만 마을로 가기 위해서는 아직 가야 할 길이 멀어. 그래도 몸은 어느 정도 고쳐져서 똑같은 일을 많이 해도 무리는 없을 거야! 어? 근데 저 로봇은 뭐지? ', escape_guide_3_2: '학습 목표: 반복문과 조건문', escape_guide_4: '드디어 마을 근처까지 왔어! 아까부터 똑같은 일을 많이 했더니 이제 외울 지경이야! 차라리 쓰일 블록은 이제 기억해뒀다가 쓰면 좋을 것 같아. 여기서 배터리만 충전해 놓으면 이제 평생 자유롭게 살 수 있을 거야.', escape_guide_4_2: '학습 목표: 함수 정의와 호출', space_travel_log: '우주 여행기', space_guide_1: '머나먼 우주를 탐사하기 위해 떠난 엔트리봇. 드디어 탐사 임무를 마치고 고향별인 지구로 돌아오려 하는데 수많은 돌이 지구로 가는 길을 막고 있다! 엔트리봇이 안전하게 지구로 돌아올 수 있도록 도와주세요!', space_guide_2: '드디어 지구에 돌아갈 시간이야! 얼른 지구에 돌아가서 쉬고 싶어!앞에 돌들이 어떻게 되어 있는지 확인하고 언제 어디로 가야 하는지 알려줘! 그러면 내가 가르쳐준 방향으로 움직일게!', space_guide_2_2: '학습 목표: 조건문 중첩과 논리 연산', cfest_mission: '엔트리 체험 미션', maze_1_intro: '안녕 나는 엔트리봇이라고 해. 지금 나는 다친 친구들을 구하려고 하는데 너의 도움이 필요해. 나를 도와서 친구들을 구해줘! 먼저 앞으로 가기 블록을 조립하고 시작을 눌러봐', maze_1_title: '시작 방법', maze_1_content: '엔트리봇은 어떻게 움직이나요?', maze_1_detail: '1. 블록 꾸러미에서 원하는 블록을 꺼내어 “시작하기를 클릭했을 때” 블록과 연결해봐
2. 다 조립했으면, 시작을 눌러봐
3. 나는 네가 조립한 블록대로 위에서부터 순서대로 움직일게', maze_2_intro: '좋아! 덕분에 첫 번째 친구를 무사히 구할 수 있었어! 그럼 다음 친구를 구해볼까? 어! 그런데 앞에 벌집이 있어! 뛰어넘기 블록을 사용해서 벌집을 피하고 친구를 구해보자.', maze_2_title_1: '장애물 뛰어넘기', maze_2_content_1: '장애물이 있으면 어떻게 해야하나요?', maze_2_detail_1: '길을 가다보면 장애물을 만날 수 있어.
장애물이 앞에 있을 때에는 뛰어넘기 블록을 사용해야 해.', maze_2_title_2: '시작 방법', maze_2_content_2: '엔트리봇은 어떻게 움직이나요?', maze_2_detail_2: '1. 블록 꾸러미에서 원하는 블록을 꺼내어 “시작하기를 클릭했을 때” 블록과 연결해봐
2. 다 조립했으면, 시작을 눌러봐
3. 나는 네가 조립한 블록대로 위에서부터 순서대로 움직일게', maze_3_intro: '멋졌어! 이제 또 다른 친구를 구하러 가자~ 이번에는 아까 구한 친구가 준 반복하기 블록을 이용해볼까? 반복하기를 이용하면 똑같은 동작을 쉽게 여러번 할 수 있어! 한 번 반복할 숫자를 바꿔볼래?', maze_3_title: '반복 블록(1)', maze_3_content: '(3)회 반복하기 블록은 어떻게 사용하나요?', maze_3_detail: '같은 행동을 여러번 반복하려면 ~번 반복하기 블록을 사용해야 해.
반복하고 싶은 블록들을 ~번 반복하기 안에 넣고 반복 횟수를 입력하면 돼', maze_4_intro: '훌륭해! 이제 구해야 할 친구 로봇들도 별로 남지 않았어. 벌집에 닿지 않도록 뛰어넘기를 반복하면서 친구에게 갈 수 있게 해줘!', maze_4_title: '반복 블록(1)', maze_4_content: '(3)회 반복하기 블록은 어떻게 사용하나요?', maze_4_detail: '같은 행동을 여러번 반복하려면 ~번 반복하기 블록을 사용해야 해.
반복하고 싶은 블록들을 ~번 반복하기 안에 넣고 반복 횟수를 입력하면 돼', maze_5_intro: '대단해! 이제 반복하기 블록과 만약 블록을 같이 사용해보자~ 만약 블록을 사용하면 앞에 벽이 있을 때 벽이 없는 쪽으로 회전할 수 있어. 그럼 친구를 구해주러 출발해볼까?', maze_5_title_1: '만약 블록', maze_5_content_1: '만약 ~라면 블록은 어떻게 동작하나요?', maze_5_detail_1: "만약 앞에 {이미지}가 있다면' 블록을 사용하면 앞에 {이미지}가 있을 때 어떤 행동을 할 지 정해줄 수 있어.
앞에 {이미지}가 있을 때에만 블록 안의 블록들을 실행하고
그렇지 않으면 실행하지 않게 되는 거야.", maze_5_title_2: '반복 블록(2)', maze_5_content_2: '~를 만날 때 까지 반복하기 블록은 어떻게 사용하나요?', maze_5_detail_2: "~까지 반복하기'를 사용하면 같은 행동을 언제까지 반복할지를 정해줄 수 있어.
반복하고 싶은 블록들을 ~까지 반복하기안에 넣으면 돼.
그러면 {이미지}와 같은 타일 위에 있는 경우 반복이 멈추게 될 거야.", maze_6_intro: '이제 마지막 친구야! 아까 해본 것처럼만 하면 될거야! 그럼 마지막 친구를 구하러 가볼까?', maze_6_title_1: '만약 블록', maze_6_content_1: '만약 ~라면 블록은 어떻게 동작하나요?', maze_6_detail_1: "만약 앞에 {이미지}가 있다면' 블록을 사용하면 앞에 {이미지}가 있을 때 어떤 행동을 할 지 정해줄 수 있어.
앞에 {이미지}가 있을 때에만 블록 안의 블록들을 실행하고
그렇지 않으면 실행하지 않게 되는 거야.", maze_6_title_2: '반복 블록(2)', maze_6_content_2: '~를 만날 때 까지 반복하기 블록은 어떻게 사용하나요?', maze_6_detail_2: "~까지 반복하기'를 사용하면 같은 행동을 언제까지 반복할지를 정해줄 수 있어.
반복하고 싶은 블록들을 ~까지 반복하기안에 넣으면 돼.
그러면 {이미지}와 같은 타일 위에 있는 경우 반복이 멈추게 될 거야.", maze_programing_mode_0: '블록 코딩', maze_programing_mode_1: '자바스크립트', maze_operation1_title: '1단계 – 자바스크립트모드 안내', maze_operation1_1_desc: '나는 로봇강아지 엔트리봇이야. 나에게 명령을 내려서 미션을 해결할 수 있게 도와줘! 미션은 시작할 때마다 \'목표\'를 통해서 확인할 수 있어!', maze_operation1_2_desc: '미션을 확인했다면 명령을 내려야 해 \'명령어 꾸러미\'명령어가 있는 공간이야. 마우스키보드명령을 내릴 수 있어. 마우스로는 명령어 꾸러미에 있는 명령어를 클릭하거나, 명령어\'명령어 조립소\'로 끌고와서 나에게 명령을 내릴 수 있어!', maze_operation1_2_textset_1: '마우스로 명령어를 클릭하는 방법 ', maze_operation1_2_textset_2: '마우스로 명령어를 드래그앤드랍하는 방법 ', maze_operation1_3_desc: '키보드로 명령을 내리려면 \'명령어 꾸러미\' 에 있는 명령어를 키보드로 직접 입력하면 돼.
명령어를 입력할 때 명령어 끝에 있는 ()와 ; 를 빼먹지 않도록 주의해야해!', maze_operation1_4_desc: '미션을 해결하기 위한 명령어를 다 입력했다면 [시작하기]를 누르면 돼.
[시작하기]를 누르면 나는 명령을 내린대로 움직일 거야!
각 명령어가 궁금하다면 [명령어 도움말]을 확인해봐!', maze_operation7_title: '7단계 - 반복 명령 알아보기(횟수반복)', maze_operation7_1_desc: '똑같은 일을 반복해서 명령하는건 매우 귀찮은 일이야.
이럴땐 반복과 관련된 명령어를 사용하면 훨씬 쉽게 명령을 내릴 수 있어.', maze_operation7_2_desc: '그렇다면 반복되는 명령을 쉽게 내리는 방법을 알아보자.
먼저 반복하기 명령어를 클릭한 다음, i<1 의 숫자를 바꿔서 반복횟수를 정하고
괄호({ }) 사이에 반복할 명령어를 넣어주면 돼!', maze_operation7_3_desc: '예를 들어 이 명령어은 move(); 를 10번 반복해서 실행해.
명령어와 동일한 명령어지.', maze_operation7_4_desc: '이 명령어를 사용할 때는 { } 안에 반복할 명령어를 잘 입력했는지,
`;`는 빠지지 않았는지 잘 살펴봐!
이 명령어에 대한 자세한 설명은 [명령어 도움말]에서 볼 수 있어.', maze_operation7_1_textset_1: '똑같은 명령어를 반복해서 사용하는 경우', maze_operation7_1_textset_2: '반복 명령어를 사용하는 경우', maze_operation7_2_textset_1: '반복 횟수', maze_operation7_2_textset_2: '반복할 명령', maze_operation7_4_textset_1: '괄호({})가 빠진 경우', maze_operation7_4_textset_2: '세미콜론(;)이 빠진 경우', study_maze_operation8_title: '8단계 - 반복 명령 알아보기(횟수반복)', study_maze_operation16_title: '4단계 - 반복 명령 알아보기(조건반복)', study_maze_operation1_title: '1단계 - 반복 명령 알아보기(횟수반복)', maze_operation9_title: '9단계 - 반복 명령 알아보기(조건반복)', maze_operation9_1_desc: '앞에서는 몇 번을 반복하는 횟수반복 명령어에 대해 배웠어.
이번에는 계속해서 반복하는 명령어를 살펴보자.
이 명령어를 사용하면 미션이 끝날 때까지 동일한 행동을 계속 반복하게 돼.
이 명령어 역시 괄호({ }) 사이에 반복할 명령어를 넣어 사용할 수 있어!', maze_operation9_2_desc: '예를 들어 이 명령어 은 미션을 완료할때까지 반복해서 move(); right()를 실행해.
명령어와 동일한 명령어지.', maze_operation9_3_desc: '이 명령어를 사용할 때도 { } 안에 반복할 명령어를 잘 입력했는지,
`true`가 빠지지 않았는지 잘 살펴봐!
이 명령어에 대한 자세한 설명은 [명령어 도움말]에서 볼 수 있어.', maze_operation9_1_textset_1: '반복할 명령', maze_operation9_3_textset_1: '괄호({})가 빠진 경우', maze_operation9_3_textset_2: '세미콜론(;)이 빠진 경우', maze_operation9_3_textset_3: 'true가 빠진 경우', study_maze_operation3_title: '3단계 - 반복 명령 알아보기(조건반복)', study_maze_operation4_title: '4단계 - 조건 명령 알아보기', study_ai_operation4_title: '4단계 - 조건 명령과 레이더 알아보기', study_ai_operation6_title: '6단계 - 중첩조건문 알아보기', study_ai_operation7_title: '7단계 - 다양한 비교연산 알아보기', study_ai_operation8_title: '8단계 - 물체 레이더 알아보기', study_ai_operation9_title: '9단계 - 아이템 사용하기', maze_operation10_title: '10단계 - 조건 명령 알아보기', maze_operation10_1_desc: '앞에서는 미션이 끝날 때까지 계속 반복하는 반복 명령어에 대해 배웠어.
이번에는 특정한 조건에서만 행동을 하는 조건 명령어를 살펴보자.
에서 보는것처럼 조건 명령어를 사용하면 명령을 보다 효율적으로 잘 내릴 수 있어.', maze_operation10_2_desc: '조건 명령어는 크게 `조건``조건이 발생했을때 실행되는 명령`으로 나눌수 있어.
먼저 조건 부분을 살펴보자. If 다음에 나오는 ( ) 부분이 조건을 입력하는 부분이야.
과 같은 명령어를 예로 살펴보자. if(front == \“wall\”) 는 만약 내 앞에(front) "wall(벽)"이 있다면을 뜻해', maze_operation10_3_desc: '이제 `조건이 발생했을 때 실행되는 명령`을 살펴보자.
이 부분은 괄호{}로 묶여 있고, 조건이 발생했을때 괄호안의 명령을 실행하게 돼!
조건이 발생하지 않으면 이 부분은 무시하고 그냥 넘어가게 되지.
의 명령어를 예로 살펴보자. 조건은 만약에 `내 앞에 벽이 있을 때` 이고,
이 조건이 발생했을 때 나는 괄호안의 명령어 right(); 처럼 오른쪽으로 회전하게 돼!', maze_operation10_4_desc: '조건 명령어반복하기 명령어와 함께 쓰이는 경우가 많아.
앞으로 쭉 가다가, 벽을 만났을때만 회전하게 하려면
순서와 같이 명령을 내릴 수 있지!', maze_operation10_1_textset_1: '[일반명령]', maze_operation10_1_textset_2: '앞으로 2칸 가고
오른쪽으로 회전하고,
앞으로 3칸가고,
오른쪽으로 회전하고, 앞으로...
', maze_operation10_1_textset_3: '[조건명령]', maze_operation10_1_textset_4: '앞으로 계속 가다가
`만약에 벽을 만나면`
오른쪽으로 회전해~!
', maze_operation10_2_textset_1: '조건', maze_operation10_2_textset_2: '조건이 발생했을 때 실행되는 명령', maze_operation10_3_textset_1: '조건', maze_operation10_3_textset_2: '조건이 발생했을 때 실행되는 명령', maze_operation10_4_textset_1: '미션이 끝날때 까지
계속 앞으로 간다.
', maze_operation10_4_textset_2: '계속 앞으로 가다가,
만약에 벽을 만나면
', maze_operation10_4_textset_3: '계속 앞으로 가다가,
만약에 벽을 만나면
오른쪽으로 회전한다.
', study_maze_operation18_title: '6단계 - 조건 명령 알아보기', maze_operation15_title: '15단계 - 함수 명령 알아보기', maze_operation15_1_desc: '자주 사용하는 명령어들을 매번 입력하는건 매우 귀찮은 일이야.
자주 사용하는 명령어들을 묶어서 이름을 붙이고,
필요할 때마다 그 명령어 묶음을 불러온다면 훨씬 편리하게 명령을 내릴 수 있어!
이런 명령어 묶음을 `함수`라고 해. 이제 함수 명령에 대해 자세히 알아보자.', maze_operation15_2_desc: '함수 명령어는 명령어를 묶는 `함수만들기` 과정과,
묶은 명령어를 필요할 때 사용하는 `함수 불러오기` 과정이 있어.
먼저 함수만들기 과정을 살펴보자.
함수를 만들려면 함수의 이름과, 그 함수에 들어갈 명령어를 입력해야 해.
function을 입력한 다음 함수의 이름을 정할 수 있어. 여기서는 promise로 만들거야.
함수 이름을 만들었으면 ()를 붙여줘. 그 다음 괄호({})를 입력해.
그리고 이 괄호 안에 함수에 들어갈 명령어들을 입력하면 함수가 만들어져!', maze_operation15_3_desc: '이 명령어를 예로 살펴보자. 나는 promise 라는 함수를 만들었어.
이 함수를 불러서 실행하면 괄호({})안에 있는
move();
move();
left(); 가 실행돼!', maze_operation15_4_desc: '함수를 불러와서 실행하려면 아까 만든 함수의 이름을 입력하고 뒤에 `();`를 붙이면 돼.
promise 라는 이름으로 함수를 만들었으니 promise(); 를 입력하면 앞에서 묶어놓은
명령어들이 실행되는거지!
과 같이 명령을 내리면 처럼 동작하게 돼!
함수 명령어를 사용하려면 과 같이 함수를 만들고 함수를 불러와야해!', maze_operation15_1_textset_1: '자주 사용하는 명령어 확인하기', maze_operation15_1_textset_2: '명령어들을 묶어서 이름 붙이기', maze_operation15_1_textset_3: '명령어 묶음 불러오기', maze_operation15_2_textset_1: '명령어 묶음의 이름(함수 이름)', maze_operation15_2_textset_2: '묶을 명령어들', maze_operation15_3_textset_1: '명령어 묶음의 이름(함수 이름)', maze_operation15_3_textset_2: '묶을 명령어들', maze_operation15_4_textset_1: '함수 만들기', maze_operation15_4_textset_2: '함수 불러오기', maze_operation15_4_textset_3: '실제 상황', maze_object_title: '오브젝트 정보', maze_object_parts_box: '부품 상자', maze_object_trap: '함정', maze_object_monster: '몬스터', maze_object_obstacle1: '장애물', maze_object_obstacle2: 'bee', maze_object_obstacle3: 'banana', maze_object_friend: '친구', maze_object_wall1: 'wall', maze_object_wall2: 'wall', maze_object_wall3: 'wall', maze_object_battery: '베터리', maze_command_ex: '예시', maze_command_title: '명령어 도움말', maze_command_move_desc: '엔트리봇을 한 칸 앞으로 이동시킵니다.', maze_command_jump_desc: '아래 이미지와 같은 장애물 앞에서 장애물을 뛰어 넘습니다.
', maze_command_jump_desc_elec: '아래 이미지와 같은 장애물 앞에서 장애물을 뛰어 넘습니다.
', maze_command_right_desc: '제자리에서 오른쪽으로 90도 회전합니다.', maze_command_left_desc: '제자리에서 왼쪽으로 90도 회전합니다.', maze_command_for_desc: '괄호{} 안에 있는 명령을 입력한 횟수 만큼 반복해서 실행합니다.', maze_command_while_desc: '미션이 끝날 때가지 괄호{} 안에 있는 명령을 계속 반복해서 실행합니다.', maze_command_slow_desc: '아래 이미지와 같은 방지턱을 넘습니다.
', maze_command_if1_desc: '조건 `바로 앞에 벽이 있을때`이 발생했을 때,
괄호{} 안에 있는 명령을 실행합니다.', maze_command_if2_desc: '조건 `바로 앞에 벌집이 있을때`이 발생했을 때,
괄호{} 안에 있는 명령을 실행합니다.', maze_command_if3_desc: '조건 `바로 앞에 바나나가 있을때`이 발생했을 때,
괄호{} 안에 있는 명령을 실행합니다.', maze_command_promise_desc: 'promise 라는 함수를 만들고 실행하면 괄호{} 안에
있던 명령어가 실행합니다.', perfect: '아주 완벽해! ', succeeded_using_blocks: ' 개의 블록을 사용해서 성공했어!', succeeded_using_commands: ' 개의 명령어를 사용해서 성공했어!', awesome: '대단한 걸!', succeeded_go_to_next: '개의 블록만으로 성공했어!
다음 단계로 넘어가자.', good: '좋아! ', but: '
하지만, ', try_again: ' 개의 블록만으로 성공하는 방법도 있어.
다시 도전해 보는건 어때?', try_again_commands: ' 개의 명렁어만으로 성공하는 방법도 있어.
다시 도전해 보는건 어때?', cfest_success: '대단한걸! 덕분에 친구들을 구할 수 있었어!
아마도 너는 타고난 프로그래머 인가봐!
나중에 또 만나자~!', succeeded_and_cert: '개의 블록만으로 성공했어!
인증서를 받으러 가자.', cause_msgs_1: '에구, 앞으로 갈 수 없는 곳이였어. 다시 해보자.', cause_msgs_2: '히잉. 그냥 길에서는 뛰어 넘을 곳이 없어. 다시 해보자.', cause_msgs_3: '에고고, 아파라. 뛰어 넘었어야 했던 곳이였어. 다시 해보자.', cause_msgs_4: '아쉽지만, 이번 단계에서는 꼭 아래 블록을 써야만 해.
다시 해볼래?', cause_msgs_5: '이런, 실행할 블록들이 다 떨어졌어. 다시 해보자.', cause_msgs_6: '이런, 실행할 명령어들이 다 떨어졌어. 다시 해보자.', close_experience: '체험
종료', replay: '다시하기', go_to_next_level: '다음단계 가기', move_forward: '앞으로 한 칸 이동', turn_left: '왼쪽', turn_right: '오른쪽', turn_en: '', turn_ko: '으로 회전', jump_over: '뛰어넘기', when_start_is_pressed: '시작하기를 클릭했을 때', repeat_until_ko: '만날 때 까지 반복', repeat_until_en: '', repeat_until: '만날 때 까지 반복', if_there_is_1: '만약 앞에 ', if_there_is_2: '있다면', used_blocks: '사용 블록', maximum: '목표 블록', used_command: '사용 명령어 갯수', maximum_command: '목표 명령어 갯수', block_box: '블록 꾸러미', block_assembly: '블록 조립소', command_box: '명령어 꾸러미', command_assembly: '명령어 조립소', start: '시작하기', engine_running: '실행중', engine_replay: '돌아가기', goto_show: '보러가기', make_together: '함께 만드는 엔트리', make_together_content: '엔트리는 학교에 계신 선생님들과 학생 친구들이 함께 고민하며 만들어갑니다.', project_nobody_like: "이 작품이 마음에 든다면 '좋아요'를 눌러 주세요.", project_nobody_interest: "'관심 작품'을 누르면 마이 페이지에서 볼 수 있어요.", lecture_nobody_like: "이 강의가 마음에 든다면 '좋아요'를 눌러 주세요.", lecture_nobody_interest: "'관심 강의'을 누르면 마이 페이지에서 볼 수 있어요.", course_nobody_like: "이 강의 모음이 마음에 든다면 '좋아요'를 눌러 주세요.", course_nobody_interest: "'관심 강의 모음'을 누르면 마이 페이지에서 볼 수 있어요.", before_changed: '변경전', after_changed: '변경후', from_changed: '( 2016년 04월 17일 부터 ) ', essential: '필수', access_term_title: '안녕하세요. 엔트리 교육연구소 입니다. 
엔트리를 사랑해주시는 여러분께 감사드리며, 
엔트리 교육연구소 웹사이트 이용약관이
2016년 4월 17일 부로 다음과 같이 개정됨을 알려드립니다. ', member_info: '회원 안내', personal_info: '개인정보 수집 및 이용에 동의 합니다.', option: '선택', news: '최신소식', edu_material: '교육자료', latest_news: '최근소식', edu_data: '교육자료', training_program: '연수지원', footer_phrase: '엔트리는 누구나 무료로 소프트웨어 교육을 받을 수 있게 개발된 비영리 교육 플랫폼입니다.', footer_use_free: '모든 엔트리교육연구소의 저작물은 교육적 목적에 한하여 출처를 밝히고 자유롭게 이용할 수 있습니다.', footer_description_1: '엔트리는 비영리 교육 플랫폼으로 모든 엔트리의 저작물은 교육 목적에 한해 출처를 밝히고 자유롭게 이용할 수 있습니다.', footer_description_2: '', nonprofit_platform: '비영리 교육 플랫폼', this_is: '입니다.', privacy: '개인정보 처리방침', entry_addr: '경기도 성남시 분당구 불정로 6 NAVER 그린팩토리 16층', entry_addr_additional_phone: '1522-9182', entry_addr_additional_email: 'entry@connect.or.kr', entry_addr_additional_opensource: '오픈소스 라이선스', phone: '전화번호', alert_agree_term: '이용약관에 동의하여 주세요.', alert_private_policy: '개인정보 수집 약관에 동의하여 주세요.', agree: '동의', optional: '선택', start_software: '소프트웨어 교육의 첫걸음', analyze_procedure: '절차', analyze_repeat: '반복', analyze_condition: '분기', analyze_interaction: '상호작용', analyze_dataRepresentation: '데이터 표현', analyze_abstraction: '추상화', analyze_sync: '병렬 및 동기화', jr_intro_1: '안녕! 난 쥬니라고 해! 내 친구 엔트리봇이 오른쪽에 있어! 날 친구에게 데려다 줘!', jr_intro_2: '엔트리봇이 내 왼쪽에 있어! 왼쪽으로 가보자.', jr_intro_3: '엔트리봇이 위쪽에 있어! 친구를 만날 수 있도록 도와줘!', jr_intro_4: '어서 엔트리봇을 만나러 가자! 아래쪽으로 가보는거야~ ', jr_intro_5: '우왓! 내 친구가 멀리 떨어져있어. 엔트리봇이 있는 곳까지 안내해줄래? ', jr_intro_6: '저기 엔트리봇이 있어~ 얼른 만나러 가보자.', jr_intro_7: '예쁜 꽃이 있네. 꽃들을 모아 엔트리봇에게 가보자!', jr_intro_8: '가는 길에 꽃이 있어! 꽃을 모아 엔트리봇에게 가보자!', jr_intro_9: '엔트리봇이 멀리 떨어져 있네? 가장 빠른 길로 엔트리봇에게 가 보자.', jr_intro_10: '엔트리봇을 만나러 가는 길에 꽃을 모두 모아서 가보자.', jr_intro_11: '엔트리봇에게 가려면 오른쪽으로 다섯번이나 가야 하잖아? 반복하기 블록을 사용해서 좀 더 쉽게 가 보자.', jr_intro_12: '반복하기를 사용해서 엔트리봇을 만나러 가자.', jr_intro_13: '지금 블록으로는 친구에게 갈 수가 없어. 반복 횟수를 바꿔 엔트리봇에게 갈 수 있게 해줘.', jr_intro_14: '반복 블록을 사용하여 엔트리봇에게 데려다 줘.', jr_intro_15: '엔트리봇이 정~말 멀리 있잖아? 그래도 반복 블록을 사용하면 쉽게 엔트리봇에게 갈 수 있을 거야.', jr_whats_ur_name: '내가 받을 인증서에 적힐 이름은?', jr_down_cert: '인증서 받기', jr_popup_prefix_1: '좋아! 엔트리봇을 만났어!', jr_popup_prefix_2: '우왓! 엔트리봇을 만났어!
하지만 엔트리봇을 만나기에는 더 적은 블록을 사용해서도
만날 수 있는데 다시 해볼래? ', jr_popup_prefix_3: '좋아! 책가방을 챙겼어!', jr_popup_prefix_4: '우왓! 책가방이 있는 곳으로 왔어! 하지만 더 적은 블록을 사용해도 책가방 쪽으로 갈 수 있는데 다시 해볼래?', jr_popup_suffix_1: '고마워~ 덕분에 책가방을 챙겨서 학교에 올 수 있었어~ 다음 학교 가는 길도 함께 가자~', jr_popup_suffix: '고마워~ 덕분에 엔트리봇이랑 재밌게 놀 수 있었어~
다음에 또 엔트리봇이랑 놀자~', jr_fail_dont_go: '에궁, 그 곳으로는 갈 수 없어. 가야하는 길을 다시 알려줘~', jr_fail_dont_know: '어? 이제 어디로 가지? 어디로 가야하는 지 더 알려줘~', jr_fail_no_flower: '이런 그곳에는 꽃이 없어. 꽃이 있는 곳에서 사용해보자~', jr_fail_forgot_flower: '앗! 엔트리봇한테 줄 꽃을 깜빡했어. 꽃을 모아서 가자~', jr_fail_need_repeat: '반복 블록이 없잖아! 반복 블록을 사용해서 해보자~', jr_hint_1: '안녕! 난 쥬니라고 해! 내 친구 엔트리봇이 오른쪽에 있어! 날 친구에게 데려다 줘!', jr_hint_2: '엔트리봇이 내 왼쪽에 있어! 왼쪽으로 가보자.', jr_hint_3: '엔트리봇이 위쪽에 있어! 친구를 만날 수 있도록 도와줘!', jr_hint_4: '어서 엔트리봇을 만나러 가자! 아래쪽으로 가보는거야~', jr_hint_5: '우왓! 내 친구가 멀리 떨어져있어. 엔트리봇이 있는 곳까지 안내해줄래?', jr_hint_6: '잘못된 블록들 때문에 친구에게 가지 못하고 있어, 잘못된 블록을 지우고 엔트리봇에게 갈 수 있도록 해줘!', jr_hint_7: '예쁜 꽃이 있네. 꽃들을 모아 엔트리봇에게 가보자!', jr_hint_8: '가는 길에 꽃이 있어! 꽃을 모아 엔트리봇에게 가보자!', jr_hint_9: '엔트리봇이 멀리 떨어져 있네? 가장 빠른 길로 엔트리봇에게 가 보자.', jr_hint_10: '앗, 블록을 잘못 조립해서 제대로 갈 수가 없어. 가는 길에 꽃을 모두 모아 엔트리봇에게 가져다 줄 수 있도록 고쳐 보자.', jr_hint_11: '엔트리봇에게 가려면 오른쪽으로 다섯번이나 가야 하잖아? 반복하기 블록을 사용해서 좀 더 쉽게 가 보자.', jr_hint_12: '반복하기를 사용해서 엔트리봇을 만나러 가자.', jr_hint_13: '지금 블록으로는 친구에게 갈 수가 없어. 반복 횟수를 바꿔 엔트리봇에게 갈 수 있게 해줘.', jr_hint_14: '반복 블록을 사용하여 엔트리봇에게 데려다 줘.', jr_hint_15: '엔트리봇이 정~말 멀리 있잖아? 그래도 반복 블록을 사용하면 쉽게 엔트리봇에게 갈 수 있을 거야.', jr_certification: '인증서', jr_congrat: '축하드립니다!', jr_congrat_msg: '문제해결 과정을 성공적으로 마쳤습니다.', jr_share: '공유', go_see_friends: '친구들 만나러 가요~!', junior_naver: '쥬니어 네이버', junior_naver_contents_1: "의 멋진 곰 '쥬니'가 엔트리를 찾아 왔어요! ", junior_naver_contents_2: '그런데 쥬니는 길을 찾는 것이 아직 어렵나봐요.', junior_naver_contents_3: '쥬니가 엔트리봇을 만날 수 있도록 가야하는 방향을 알려주세요~', basic_content: '기초', jr_help: '도움말', help: '도움말', cparty_robot_intro_1: '안녕 나는 엔트리봇이야. 난 부품을 얻어서 내몸을 고쳐야해. 앞으로 가기 블록으로 부품을 얻게 도와줘!', cparty_robot_intro_2: '좋아! 앞에도 부품이 있는데 이번에는 잘못 가다간 감전되기 쉬울 것 같아. 뛰어넘기 블록을 써서 부품까지 데려다 줘.', cparty_robot_intro_3: '멋진걸! 저기에도 부품이 있어! 길이 조금 꼬여있지만 회전하기 블록을 쓰면 충분히 갈 수 있을 것 같아! ', cparty_robot_intro_4: '좋아 이제 움직이는 건 많이 편해졌어! 이번에는 회전과 뛰어넘기를 같이 써서 저 부품을 얻어보자! ', cparty_robot_intro_5: '덕분에 몸이 아주 좋아졌어! 이번에도 회전과 뛰어넘기를 같이 써야 할 거야! 어서 가보자!', cparty_robot_intro_6: '멋져! 이제 몸이 많이 좋아져서, 똑같은 일은 여러 번 해도 괜찮을 거야! 한 번 반복하기를 사용해서 가보자!', cparty_robot_intro_7: '어? 중간중간에 뛰어넘어야 할 곳이 있어! 그래도 반복하기로 충분히 갈 수 있을 거야!', cparty_robot_intro_8: '이런! 이번에는 부품이 저기 멀리 떨어져 있어. 그래도 반복하기를 사용하면 쉽게 갈수 있지! 얼른 도와줘!', cparty_robot_intro_9: '우와~ 이제 내 몸이 거의 다 고쳐진 것 같아! 이번에도 반복하기를 이용해서 부품을 구하러 가보자!', cparty_robot_intro_10: '대단해! 이제 마지막 부품만 있으면 내 몸을 완벽하게 고칠 수 있을 거야! 빨리 반복하기로 도와줘!', cparty_car_intro_1: '안녕! 나는 엔트리봇이라고 해, 자동차를 타고 계속 이동하려면 연료가 필요해! 앞에 있는 연료를 얻을 수 있게 도와줄래?', cparty_car_intro_2: '좋아! 그런데 이번에는 길이 직선이 아니네! 왼쪽/오른쪽 돌기 블록으로 잘 운전해서 함께 연료를 얻으러 가볼까?', cparty_car_intro_3: '잘했어! 이번 길 앞에는 과속방지턱이 있어. 빠르게 운전하면 사고가 날 수도 있을 것 같아, 천천히 가기 블록을 써서 연료를 얻으러 가보자!', cparty_car_intro_4: '야호, 이제 운전이 한결 편해졌어! 이 도로에서는 반복하기 블록을 사용해서 연료를 채우러 가볼까?', cparty_car_intro_5: '와 이번 도로는 조금 복잡해 보이지만, 앞으로 가기와 왼쪽/오른쪽 돌기 블록을 반복하면서 가보면 돼! 차분하게 연료까지 가보자', cparty_car_intro_6: '이번에는 도로에 장애물이 있어서 잘 돌아가야 될 것 같아, 만약에 장애물이 앞에 있다면 어떻게 해야 하는지 알려줘!', cparty_car_intro_7: '좋아 잘했어! 한번 더 만약에 블록을 사용해서 장애물을 피해 연료를 얻으러 가보자!', cparty_car_intro_8: '앗 아까 만났던 과속 방지턱이 두 개나 있네, 천천히 가기 블록을 이용해서 안전하게 연료를 채우러 가보자!', cparty_car_intro_9: '복잡해 보이는 길이지만, 앞에서 사용한 반복 블록과 만약에 블록을 잘 이용하면 충분히 운전할 수 있어, 연료를 채울 수 있도록 도와줘!', cparty_car_intro_10: '정말 멋져! 블록의 순서를 잘 나열해서 이제 마지막 남은 연료를 향해 힘을 내어 가보자!', cparty_car_popup_prefix_1: '좋아! 연료를 얻었어!', cparty_car_popup_prefix_2: '우왓! 연료를 얻었어!
하지만 연료를 얻기에는 더 적은 블록을 사용해서도
얻을 수 있는데 다시 해볼래? ', cparty_car_popup_prefix_2_text: '우왓! 연료를 얻었어!
하지만 연료를 얻기에는 더 적은 명령어 사용해서도
얻을 수 있는데 다시 해볼래? ', cparty_car_popup_suffix: '고마워~ 덕분에 모든 배터리를 얻을 수 있었어~
다음에 또 나랑 놀자~', all_grade: '모든 학년', grade_e3_e4: '초등 3 ~ 4 학년 이상', grade_e5_e6: '초등 5 ~ 6 학년 이상', grade_m1_m3: '중등 1 ~ 3 학년 이상', entry_first_step: '엔트리 첫걸음', entry_monthly: '월간 엔트리', play_sw_2: 'EBS 소프트웨어야 놀자2', entry_programming: '실전, 프로그래밍!', entry_recommanded_course: '엔트리 추천 코스', introduce_course: '누구나 쉽게 보고 따라하면서 재미있고 다양한 소프트웨어를 만들 수 있는 강의 코스를 소개합니다.', all_free: '*강의 동영상, 만들기, 교재 등이 모두 무료로 제공됩니다.', cparty_result_fail_1: '에궁, 그 곳으로는 갈 수 없어. 가야하는 길을 다시 알려줘~', cparty_result_fail_2: '에고고, 아파라. 뛰어 넘었어야 했던 곳이였어. 다시 해보자.', cparty_result_fail_3: '아이고 힘들다. 아래 블록들을 안 썼더니 너무 힘들어! 아래 블록들로 다시 만들어줘.', cparty_result_fail_4: '어? 이제 어디로 가지? 어디로 가야하는 지 더 알려줘~', cparty_result_fail_5: '앗! 과속방지턱에서는 속도를 줄여야해. 천천히 가기 블록을 사용해보자~', cparty_result_success_1: '좋아! 부품을 얻었어!', cparty_result_success_2: '우왓! 부품을 얻었어!
하지만 부품을 얻기에는 더 적은 블록을 사용해서도 얻을 수 있는데 다시 해볼래?', cparty_result_success_2_text: '우왓! 부품을 얻었어!
하지만 부품을 얻기에는 더 적은 명령어를 사용해서도 얻을 수 있는데 다시 해볼래?', cparty_result_success_3: '고마워~ 덕분에 내몸이 다 고쳐졌어~ 다음에 또 나랑 놀자~', cparty_insert_name: '이름을 입력하세요.', offline_file: '파일', offline_edit: '편집', offline_undo: '되돌리기', offline_redo: '다시실행', offline_quit: '종료', select_one: '선택해 주세요.', evaluate_challenge: '도전해본 미션의 난이도를 평가해 주세요.', very_easy: '매우쉬움', easy: '쉬움', normal: '보통', difficult: '어려움', very_difficult: '매우 어려움', save_dismiss: '바꾼 내용을 저장하지 않았습니다. 계속 하시겠습니까?', entry_info: '엔트리 정보', actual_size: '실제크기', zoom_in: '확대', zoom_out: '축소', cparty_jr_intro_1: '안녕! 난 엔트리봇 이라고 해! 학교가는 길에 책가방을 챙길 수 있도록 도와줘! ', cparty_jr_intro_2: '책가방이 내 왼쪽에 있어! 왼쪽으로 가보자.', cparty_jr_intro_3: '책가방이 위쪽에 있어! 책가방을 챙길 수 있도록 도와줘!', cparty_jr_intro_4: '어서 책가방을 챙기러 가자! 아래쪽으로 가보는 거야~', cparty_jr_intro_5: '우왓! 내 책가방이 멀리 떨어져 있어. 책가방이 있는 곳까지 안내해줄래?', cparty_jr_intro_6: '책가방이 있어! 얼른 가지러 가자~', cparty_jr_intro_7: '길 위에 내 연필이 있네. 연필들을 모아 책가방을 챙기러 가보자!', cparty_jr_intro_8: '학교 가는 길에 연필이 있어! 연필을 모아 책가방을 챙기러 가보자!', cparty_jr_intro_9: '내 책가방이 멀리 떨어져 있네? 가장 빠른 길로 책가방을 챙기러 가 보자.', cparty_jr_intro_10: '가는 길에 연필을 모두 모으고 책가방을 챙기자!', cparty_jr_intro_11: '책가방을 챙기러 가려면 오른쪽으로 다섯 번이나 가야 하잖아? 반복하기 블록을 사용해서 좀 더 쉽게 가 보자.', cparty_jr_intro_12: '반복하기를 사용해서 책가방을 챙기러 가자.', cparty_jr_intro_13: '지금 블록으로는 책가방이 있는 쪽으로 갈 수가 없어. 반복 횟수를 바꿔 책가방을 챙기러 갈 수 있게 해줘.', cparty_jr_intro_14: '반복 블록을 사용하여 책가방을 챙기러 가줘.', cparty_jr_intro_15: '학교가 정~말 멀리 있잖아? 그래도 반복 블록을 사용하면 쉽게 학교에 도착 할수 있을 거야.', make_new_project: '새로운 작품 만들기', open_old_project: '저장된 작품 불러오기', offline_download: '엔트리 다운로드', offline_release: '엔트리 오프라인 에디터 출시!', offline_description_1: '엔트리 오프라인 버전은', offline_description_2: '인터넷이 연결되어 있지 않아도 사용할 수 있습니다. ', offline_description_3: '지금 다운받아서 시작해보세요!', sw_week_2015: '2015 소프트웨어교육 체험 주간', cparty_desc: '두근두근 소프트웨어와의 첫만남', entry_offline_download: '엔트리 오프라인 \n다운로드', entry_download_detail: '다운로드\n바로가기', offline_desc_1: '엔트리 오프라인 버전은 인터넷이 연결되어 있지 않아도 사용할 수 있습니다.', offline_desc_2: '지금 다운받아서 시작해보세요!', download: '다운로드', version: '버전', file_size: '크기', update: '업데이트', use_range: '사용범위', offline_desc_free: '엔트리 오프라인은 기업과 개인 모두 제한 없이 무료로 사용하실 수 있습니다.', offline_required: '최소 요구사항', offline_required_detail: '디스크 여유 공간 1GB 이상, windows7 혹은 MAC OS 10.8 이상', offline_notice: '설치 전 참고사항', offline_notice_1: '1. 버전', offline_notice_1_1: '에서는 하드웨어 연결 프로그램이 내장되어 있습니다.', offline_notice_2: '2. 별도의 웹브라우져가 필요하지 않습니다.', offline_notice_3: '버전 별 변경 사항 안내', offline_notice_4: '버전별 다운로드', offline_notice_5: '버전별 자세한 변경 사항 보기', hardware_online_badge: '온라인', hardware_title: '엔트리 하드웨어 연결 프로그램 다운로드', hardware_desc: '엔트리 온라인 ‘작품 만들기’에서 하드웨어를 연결하여 엔트리를 이용하는 경우에만 별도로 설치가 필요합니다.', hardware_release: '하드웨어 연결 프로그램의 자세한 변경 사항은 아래 주소에서 확인 할 수 있습니다.', hardware_window_download: 'Windows 다운로드', hardware_osx_download: 'Mac 다운로드', cparty_jr_result_2: '고마워~ 덕분에 책가방을 챙겨서 학교에 올 수 있었어~
다음 학교 가는 길도 함께 가자~ ', cparty_jr_result_3: '우왓! 학교까지 왔어!
하지만 더 적은 블록을 사용해도 학교에 갈 수 있는데
다시 해볼래?', cparty_jr_result_4: '우왓! 책가방을 얻었어!
하지만 더 적은 블록을 사용해도 책가방을 얻을 수 있는데
다시 해볼래? ', lms_no_class: '아직 만든 학급이 없습니다.', lms_create_class: '학급을 만들어 주세요.', lms_add_class: '학급 만들기', lms_base_class: '기본', lms_delete_class: '삭제', lms_my_class: '나의 학급', lms_grade_1: '초등 1', lms_grade_2: '초등 2', lms_grade_3: '초등 3', lms_grade_4: '초등 4', lms_grade_5: '초등 5', lms_grade_6: '초등 6', lms_grade_7: '중등 1', lms_grade_8: '중등 2', lms_grade_9: '중등 3', lms_grade_10: '일반', lms_add_groupId_personal: '선생님께 받은 학급 아이디를 입력하여, 회원 정보에 추가하세요.', lms_add_groupId: '학급 아이디 추가하기', lms_add_group_account: '학급 계정 추가', lms_enter_group_info: '발급받은 학급 아이디와 비밀번호를 입력하세요.', lms_group_id: '학급 아이디', lms_group_pw: '비밀번호', lms_group_name: '소속 학급명', personal_pwd_alert: '올바른 비밀번호 양식을 입력해 주세요', personal_form_alert: '양식을 바르게 입력해 주세요', personal_form_alert_2: '모든 양식을 완성해 주세요', personal_no_pwd_alert: '비밀번호를 입력해 주세요', select_gender: '성별을 선택해 주세요', enter_group_id: '학급 아이디를 입력해 주세요', enter_group_pwd: '비밀번호를 입력해 주세요', info_added: '추가되었습니다', no_group_id: '학급 아이디가 존재하지 않습니다', no_group_pwd: '비밀번호가 일치하지 않습니다', lms_please_choice: '선택해 주세요.', group_lesson: '나의 학급 강의', lms_banner_add_group: '학급 기능 도입', lms_banner_entry_group: '엔트리 학급 만들기', lms_banner_desc_1: '우리 반 학생들을 엔트리에 등록하세요!', lms_banner_desc_2: '이제 보다 편리하고 쉽게 우리 반 학생들의 작품을 찾고,', lms_banner_desc_3: '성장하는 모습을 확인할 수 있습니다. ', lms_banner_download_manual: '메뉴얼 다운로드', lms_banner_detail: '자세히 보기', already_exist_email: '이미 존재하는 이메일 입니다.', same_registered_email: '중복된 이메일 입니다.', email_correnctly_please: '양식을 올바르게 입력해주세요.', remove_project: '작품을 삭제하시겠습니까?', study_lesson: '우리 반 학습하기', open_project: '작품 불러오기', make_group: '학급 만들기', project_share: '작품 공유하기', group_project_share: '학급 공유하기', group_discuss: '학급 글 나누기', my_profile: '마이 페이지', search_updated: '최신 작품', search_recent: '최근 조회수 높은 작품', search_complexity: '최근 제작에 공들인 작품', search_staffPicked: '스태프선정 작품 저장소', search_childCnt: '사본이 많은 작품', search_likeCnt: '최근 좋아요가 많은 작품', search_recentLikeCnt: '최근 좋아요가 많은 작품', gnb_share: '공유하기', gnb_community: '커뮤니티', lms_add_lectures: '강의 올리기', lms_add_course: '강의 모음 올리기', lms_add_homework: '과제 올리기', remove_lecture_confirm: '강의를 정말 삭제하시겠습니까?', popup_delete: '삭제하기', remove_course_confirm: '강의 모음을 정말 삭제하시겠습니까?', lms_no_lecture_teacher_1: '추가된 강의가 없습니다.', lms_no_lecture_teacher_2: '우리 반 강의를 추가해 주세요.', gnb_download: '다운로드', lms_no_lecture_student_1: '아직 올라온 강의가 없습니다.', lms_no_lecture_student_2: '선생님이 강의를 올려주시면,', lms_no_lecture_student_3: '학습 내용을 확인할 수 있습니다.', lms_no_class_teacher: '아직 만든 학급이 없습니다.', lms_no_course_teacher_1: '추가된 강의 모음이 없습니다.', lms_no_course_teacher_2: '우리 반 강의 모음을 추가해 주세요.', lms_no_course_student_1: '아직 올라온 강의 모음이 없습니다.', lms_no_course_student_2: '선생님이 강의 모음을 올려주시면,', lms_no_course_student_3: '학습 내용을 확인할 수 있습니다.', lms_no_hw_teacher_1: '추가된 과제가 없습니다.', lms_no_hw_teacher_2: '우리 반 과제를 추가해 주세요.', lms_no_hw_student_1: '아직 올라온 과제가 없습니다.', lms_no_hw_student_2: '선생님이 과제를 올려주시면,', lms_no_hw_student_3: '학습 내용을 확인할 수 있습니다.', modal_edit: '수정하기', modal_deadline: '마감일 설정', modal_hw_desc: '상세설명 (선택)', desc_optional: '', modal_create_hw: '과제 만들기', vol: '회차', hw_title: '과제명', hw_description: '내용', deadline: '마감일', do_homework: '과제하기', hw_progress: '진행 상태', hw_submit: '제출', view_list: '명단보기', view_desc: '내용보기', do_submit: '제출하기', popup_notice: '알림', no_selected_hw: '선택된 과제가 없습니다.', hw_delete_confirm: '선택한 과제를 정말 삭제하시겠습니까?', hw_submitter: '과제 제출자 명단', hw_student_desc_1: "* '제출하기'를 눌러 제출을 완료하기 전까지 얼마든지 수정이 가능합니다", hw_student_desc_2: '* 제출 기한이 지나면 과제를 제출할 수 없습니다.', popup_create_class: '학급 만들기', class_name: '학급 이름', image: '이미지', select_class_image: '학급 이미지를 선택해 주세요.', type_class_description: '학급 소개 입력', set_as_primary_group: '기본학급으로 지정', set_primary_group: '지정', not_primary_group: '지정안함', type_class_name: '학급 이름을 입력해주세요. ', type_class_description_long: '학급 소개를 입력해 주세요. 170자 이내', add_students: '학생 추가하기', invite_students: '학생 초대하기', invite_with_class: '1. 학급 코드로 초대하기', invite_code_expiration: '코드 만료시간', generate_code_button: '코드재발급', generate_code_desc: '학생의 학급 코드 입력 방법', generate_code_desc1: '엔트리 홈페이지에서 로그인을 해주세요.', generate_code_desc2: '메뉴바에서<나의 학급>을 선택해주세요.', generate_code_desc3: '<학급코드 입력하기>를 눌러 학급코드를 입력해주세요.', invite_with_url: '2. 학급 URL로 초대하기', copy_invite_url: '복사하기', download_as_pdf: '학급계정 PDF로 내려받기', download_as_excel: '학급계정 엑셀로 내려받기', temp_password: '임시 비밀번호 발급', step_name: '이름 입력', step_info: '정보 추가/수정', preview: '미리보기', type_name_enter: '학급에 추가할 학생의 이름을 입력하고 엔터를 치세요.', multiple_name_possible: '여러명의 이름 입력이 가능합니다.', id_auto_create: '학번은 별도로 수정하지 않으면 자동으로 생성됩니다.', student_id_desc_1: '학급 아이디는 별도의 입력없이 자동으로 생성됩니다.', student_id_desc_2: '단, 엔트리에 이미 가입된 학생을 학급에 추가한다면 학생의 엔트리 아이디를', student_id_desc_3: '입력해주세요. 해당 학생은 로그인 후, 학급 초대를 수락하면 됩니다.', student_number: '학번', temp_password_desc_1: '임시 비밀번호로 로그인 후,', temp_password_desc_2: '신규 비밀번호를 다시 설정할 수 있도록 안내해주세요.', temp_password_desc_3: '*한번 발급된 임시 비밀번호는 다시 볼 수 없습니다.', temp_password_demo: '로그인 불가능한 안내 용 예시 계정입니다.', temp_works: '작품 보기', student_delete_confirm: '학생을 정말 삭제하시겠습니까?', no_student_selected: '선택된 학생이 없습니다.', class_assignment: '학급 과제', class_list: '학급 목록', select_grade: '학년을 선택 하세요.', add_project: '작품 공유하기', no_project_display: '학생들이 전시한 작품이 없습니다.', plz_display_project: '나의 작품을 전시해 주세요.', refuse_confirm: '학급 초대를 정말 거절하시겠습니까?', select_class: '학급 선택', group_already_registered: '이미 가입된 학급입니다.', my_page_entry: '엔트리', my_page_title: '마이페이지', my_classGroup_title: '나의 학급', my_classGroup_title_view: '나의 학급 보기', my_space_area: '나만의 공간', mon: '월', tue: '화', wed: '수', thu: '목', fri: '금', sat: '토', sun: '일', jan: '1월', feb: '2월', mar: '3월', apr: '4월', may: '5월', jun: '6월', jul: '7월', aug: '8월', sep: '9월', oct: '10월', nov: '11월', dec: '12월', plz_select_lecture: '강의를 선택해 주세요.', plz_set_deadline: '마감일을 설정해 주세요.', hide_entry: '엔트리 가리기', hide_others: '기타 가리기', show_all: '모두 보기', lecture_description: '선생님들이 직접 만드는 엔트리 학습 공간입니다. 강의에서 예시작품을 보고 작품을 만들며 배워 보세요.', curriculum_description: '학습 순서와 주제에 따라 여러 강의가 모아진 학습 공간입니다. 강의 모음의 순서에 맞춰 차근차근 배워보세요.', linebreak_off_desc_1: '글상자의 크기가 글자의 크기를 결정합니다.', linebreak_off_desc_2: '내용을 한 줄로만 작성할 수 있습니다.', linebreak_off_desc_3: '새로운 글자가 추가되면 글상자의 좌우 길이가 길어집니다.', linebreak_on_desc_1: '글상자의 크기가 글자가 쓰일 수 있는 영역을 결정합니다.', linebreak_on_desc_2: '내용 작성시 엔터키로 줄바꿈을 할 수 있습니다.', linebreak_on_desc_3: '새로운 글자 추가 시 문장의 길이가 글상자의 가로 영역을 넘어가면 자동으로 줄이 바뀝니다.', not_supported_text: '해당 글씨체는 한자를 지원하지 않습니다.', entry_with: '함께 만드는 엔트리', ebs_season_1: '시즌 1 보러가기', ebs_season_2: '시즌 2 보러가기', hello_ebs: '헬로! EBS 소프트웨어', hello_ebs_desc: '<헬로! EBS 소프트웨어> 엔트리 버전의 양방향 서비스를 만나보세요! \n <헬로! EBS 소프트웨어>의 동영상 강의를 통해 \n 소프트웨어 코딩의 기본 개념을 배운 후 양방향 코딩 미션에 도전하세요!\n 방송에서는 볼 수 없었던 <대.소.동> 친구들의 \n 비하인드 스토리를 볼 수 있습니다!', hello_ebs_sub_1: 'EBS 중학 엔트리 버전의 양방향 서비스를 ', hello_ebs_sub_2: '만나보세요! ', exhibit_4th_title: '엔트리 4주년 기념', exhibit_4th_subtitle: '엔트리 작품 공모전', exhibit_4th_desc1: '엔트리 탄생 4주년을 기념하여 작품 공모전을 개최합니다.', exhibit_4th_desc2: '‘우리 모두를 위한 소프트웨어’를 주제로', exhibit_4th_desc3: '여러분의 멋진 작품을 뽐내보세요!', exhibit_4th_button: '자세히 보기', visang_edu_entry: '비상교육 엔트리 학습하기', cmass_edu_entry: '씨마스 엔트리 학습하기', chunjae_edu_entry: '천재교과서 엔트리 학습하기', kumsungemt_edu_entry: '금성출판사 엔트리 학습하기', kumsungMid_edu_entry: '금성출판사 엔트리 학습하기', gilbutEdu_edu_entry: '길벗출판사 엔트리 학습하기', miraenCoding_edu_entry: '미래엔 엔트리 학습하기', textbook_help_data: '도움자료', textbook_teaching_activity: '수업 교안&활동지', textbook_kyohacksa: '교학사', textbook_kumsung: '금성출판사', textbook_donga: '동아출판', textbook_chunjae: '천재교과서', textbook_miraen: '미래엔', textbook_visang: '비상교육', partner: '파트너', project_term_popup_title: '작품 공개에 따른 엔트리 저작권 정책 동의', project_term_popup_description_1: '작품 공개를 위해', project_term_popup_description_2: '아래 정책을 확인해주세요.', project_term_popup_description_3: '', project_term_popup_description_4: '', project_term_agree_1_1: '내가 만든 작품과 그 소스코드의 공개를 동의합니다.', project_term_agree_2_1: '다른 사람이 나의 작품을 이용하는 것을 허락합니다.', project_term_agree_2_2: '( 복제 , 배포 , 공중송신 포함 )', project_term_agree_3_1: '다른 사람이 나의 작품을 수정하는 것을 허락합니다.', project_term_agree_3_2: '( 리믹스, 변형, 2차 제작물 작성 포함)', agree_all: '전체 동의', select_login: '로그인 선택', select: '선택하세요', with_login: '로그인 하고', without_login: '로그인 안하고', start_challenge: '미션 도전하기', start_challenge_2: '미션 도전하기', if_not_save_not_login: '* 로그인을 안하고 미션에 참여하시면 진행 상황이 저장되지 않습니다.', if_not_member_yet: '엔트리 회원이 아니라면?', join_entry: '엔트리 회원 가입하기', learned_computing: '기존에 소프트웨어 교육을 받아보셨나요?', cparty_index_description_1: '두근두근 소프트웨어와 첫 만남.', cparty_index_description_2: '소프트웨어랑 재미있게 놀다 보면 소프트웨어의 원리도 배우고, 생각하는 힘도 쑥쑥!', cparty_index_description_3: '엔트리를 통해 코딩 미션에 도전하고 인증서 받으세요.', cparty_index_description_4: '2015 Online Coding Party는', cparty_index_description_5: 'SW교육 체험 주간', cparty_index_description_6: '의 일환으로써,', cparty_index_description_7: '초등컴퓨팅교사협회', cparty_index_description_8: '과 함께 만들어졌습니다.', cparty_index_description_9: '2016 Online Coding Party는', cparty_index_description_10: '2017 Online Coding Party는', cparty_index_description_11: "'SW교육을 준비하는 선생님들의 모임'", congratulation: '축하 드립니다!', warm_up: '체험', beginner: '입문', intermediate: '기본', advanced: '발전', applied: '응용', cert_msg_tail: '과정을 성공적으로 마쳤습니다.', cert_msg_head: '', maze_text_content_1: '안녕? 나는 엔트리봇이야. 지금 나는 공장에서 탈출을 해야 해! 탈출하기 위해서 먼저 몸을 고쳐야 할 것 같아. 앞에 있는 부품을 얻을 수 있게 도와줄래? move()', maze_text_content_2: '좋아 아주 잘했어! 덕분에 몸이 한결 가벼워졌어! 이번에도 부품상자까지 나를 이동시켜줘. 그런데 가는길에 장애물이 있어. 장애물 앞에서는 jump()', maze_text_content_3: '멋진걸! 저기에도 부품이 있어! 길이 조금 꼬여있지만 오른쪽, 왼쪽으로 회전할 수 있는 right(); left(); 명령어를 쓰면 충분히 갈 수 있을것 같아!', maze_text_content_4: '좋아 이제 움직이는 건 많이 편해졌어! 이번에는 지금까지 배운 명령어를 같이 써서 저 부품상자까지 가보자!', maze_text_content_5: '우와 부품이 두 개나 있잖아! 두 개 다 챙겨서 가자! 그러면 몸을 빨리 고칠 수 있을 것 같아!', maze_text_content_6: '이번이 마지막 부품들이야! 저것들만 있으면 내 몸을 다 고칠 수 있을 거야! 이번에도 도와줄 거지?', maze_text_content_7: '덕분에 몸이 아주 좋아졌어! 이제 똑같은 일을 여러 번 반복해도 무리는 없을 거야. 어? 그런데 앞에 있는 저 로봇은 뭐지? 뭔가 도움이 필요한 것 같아! 도와주자! for 명령어를 사용해서 저 친구한테 나를 데려다줘!', maze_text_content_8: '좋아! 덕분에 친구 로봇을 살릴 수 있었어! 하지만 앞에도 도움이 필요한 친구가 있네, 하지만 이번에는 벌집이 있으니까 조심해서 벌집에 안 닿게 뛰어넘어가자! 할 수 있겠지? 이번에도 for 명령어를 사용해서 친구가 있는곳까지 나를 이동시켜줘!', maze_text_content_9: '이번에는 for 명령어 대신 미션이 끝날때까지 같은 일을 반복하도록 하는 while 명령어를 사용해봐! 나를 친구에게 데려다주면 미션이 끝나!', maze_text_content_10: '이번에는 if 명령어가 나왔어! if와 while 명령어를 사용해서 내가 언제 어느 쪽으로 회전해야 하는지 알려줘!', maze_text_content_11: '좋아 아까 했던 것처럼 해볼까? 언제 왼쪽으로 돌아야 하는지 알려줄 수 있겠어?', maze_text_content_12: '이번에는 중간중간 벌집(bee)이 있네? 언제 뛰어넘어가야 할지 알려줄래?', maze_text_content_13: '여기저기 도움이 필요한 친구들이 많이 있네! 모두 가서 도와주자!', maze_text_content_14: '우와 이번에도 도와줘야 할 친구들이 많네. 먼저 조그마한 사각형을 돌도록 명령어를 만들고 만든 걸 반복해서 모든 친구를 구해보자.', maze_text_content_15: '오래 움직이다 보니 벌써 지쳐버렸어. 자주 쓰는 명령어를 function 명령어를 사용해서 함수로 만들어 놓았어! 함수를 사용하여 나를 배터리 까지 이동시켜줘!', maze_text_content_16: '좋아 멋진걸! 그럼 이번에는 함수에 들어갈 명령어들을 넣어서 나를 배터리까지 이동시켜줘!', maze_text_content_17: '좋아 이번에는 함수를 만들고, 함수를 사용해서 배터리를 얻을 수 있도록 도와줘! 함수를 만들때 jump();를 잘 섞어봐!', maze_text_content_18: '이번에는 길이 좀 복잡한걸? 그래도 언제 left();를 쓰고, 언제 right();를 쓰면 되는지 알려만 주면 배터리 까지 갈 수 있겠어!.', maze_text_content_19: '이번에는 함수가 미리 정해져 있어! 그런데 함수만 써서 배터리까지 가기 힘들것 같아. 함수와 다른 명령어들을 섞어 써서 배터리 까지 이동시켜줘!', maze_text_content_20: '좋아! 지금까지 정말 멋지게 잘 해줬어. 덕분에 이제 마지막 배터리만 채우면 앞으로는 충전이 필요 없을 거야. 함수를 이용해서 저 배터리를 얻고 내가 자유롭게 살 수 있도록 도와줘!', maze_content_1: '안녕 나는 엔트리봇이라고 해. 지금 나는 공장에서 탈출하려는데 먼저 몸을 고쳐야 할 것 같아. 앞에 있는 부품을 얻을 수 있게 도와줄래? 앞으로 가기 블록을 조립하고 시작을 눌러봐.', maze_content_2: '좋아 아주 잘했어! 덕분에 몸이 한결 가벼워졌어! 앞에도 부품이 있는데 이번에는 잘못 가다간 감전되기 쉬울 것 같아. 한 번 장애물 뛰어넘기 블록을 써서 부품까지 가볼까?', maze_content_3: '멋진걸! 저기에도 부품이 있어! 길이 조금 꼬여있지만 회전하기 블록을 쓰면 충분히 갈 수 있을 것 같아! 이번에도 도와줄 거지?', maze_content_4: '좋아 이제 움직이는 건 많이 편해졌어! 이번에는 회전과 뛰어넘기를 같이 써서 저 부품을 얻어보자!', maze_content_5: '우와 부품이 두 개나 있잖아! 두 개 다 챙겨서 가자! 그러면 몸을 빨리 고칠 수 있을 것 같아!', maze_content_6: '이번이 마지막 부품들이야! 저것들만 있으면 내 몸을 다 고칠 수 있을 거야! 이번에도 도와줄 거지?', maze_content_7: '덕분에 몸이 아주 좋아졌어! 이제 똑같은 일을 여러 번 반복해도 무리는 없을 거야. 어? 그런데 앞에 있는 저 로봇은 뭐지? 뭔가 도움이 필요한 것 같아! 도와주자! 얼른 반복하기의 숫자를 바꿔서 저 친구한테 나를 데려다줘!', maze_content_8: '좋아! 덕분에 친구 로봇을 살릴 수 있었어! 하지만 앞에도 도움이 필요한 친구가 있는 것 같아, 하지만 이번에는 벌집이 있으니까 조심해서 벌집에 안 닿게 뛰어넘어가자! 할 수 있겠지? 그럼 아까 했던 것처럼 반복을 써서 친구한테 갈 수 있게 해줄래?', maze_content_9: '이번에는 숫자만큼 반복하는 게 아니라 친구 로봇한테 갈 때까지 똑같은 일을 반복할 수 있어! 이번에도 친구를 구할 수 있도록 도와줘!', maze_content_10: '이번에는 만약 블록이란 게 있어! 만약 블록을 써서 언제 어느 쪽으로 돌아야 하는지 알려줘!', maze_content_11: '좋아 아까 했던 것처럼 해볼까? 언제 왼쪽으로 돌아야 하는지 알려줄 수 있겠어?', maze_content_12: '이번에는 중간중간 벌집이 있네? 언제 뛰어넘어가야 할지 알려줄래?', maze_content_13: '여기저기 도움이 필요한 친구들이 많이 있네! 모두 도와주자!', maze_content_14: '우와 이번에도 도와줘야 할 친구들이 많네. 먼저 조그마한 사각형을 돌도록 블록을 만들고 만든 걸 반복해서 모든 친구를 구해보자.', maze_content_15: '반복을 하도 많이 했더니 자주 쓰는 블록은 외울 수 있을 것 같아! 약속 블록은 지금 내가 외운 블록들이야! 일단은 오래 움직여서 지쳤으니까 배터리를 좀 채울 수 있게 약속 호출 블록을 써서 배터리를 채울 수 있게 해줘!', maze_content_16: '좋아 멋진걸! 그럼 이번에는 네가 자주 쓰일 블록을 나한테 가르쳐줘! 약속 정의 블록 안에 자주 쓰일 블록을 넣어보면 돼!', maze_content_17: '좋아 이번에도 그러면 약속을 이용해서 배터리를 얻을 수 있도록 도와줄 거지? 약속에 뛰어넘기를 잘 섞어봐!', maze_content_18: '이번에는 길이 좀 복잡한걸? 그래도 언제 왼쪽으로 돌고, 언제 오른쪽으로 돌면 되는지 알려만 주면 충전할 수 있을 것 같아.', maze_content_19: '이번에는 약속이 미리 정해져 있어! 그런데 바로 약속을 쓰기에는 안될 것 같아. 내가 갈 길을 보고 약속을 쓰면 배터리를 채울 수 있을 것 같은데 도와줄 거지?', maze_content_20: '좋아! 지금까지 정말 멋지게 잘 해줬어. 덕분에 이제 마지막 배터리만 채우면 앞으로는 충전이 필요 없을 거야. 그러니까 약속을 이용해서 저 배터리를 얻고 내가 자유롭게 살 수 있도록 도와줄래?', maze_content_21: '안녕? 나는 엔트리 봇이야. 지금 많은 친구들이 내 도움을 필요로 하고 있어. 반복하기를 이용해서 친구들을 도울수 있게 데려다 줘!', maze_content_22: '고마워! 이번에는 벌집을 뛰어넘어서 친구를 구하러 갈 수 있게 도와줘!', maze_content_23: '좋아! 이번에는 친구 로봇한테 갈 때까지 반복하기를 이용해서 친구를 도울 수 있게 도와줘!', maze_content_24: '안녕! 나는 엔트리 봇이야. 지금 나는 너무 오래 움직여서 배터리를 채워야 해. 약속 불러오기를 써서 배터리를 채울 수 있도록 도와줘!', maze_content_25: '멋져! 이번에는 여러 약속을 불러와서 배터리가 있는 곳까지 가보자!', maze_content_26: '좋아! 이제 약속할 블록을 나한테 가르쳐줘! 약속하기 블록 안에 자주 쓰일 블록을 넣으면 돼!', maze_content_27: '지금은 미리 약속이 정해져 있어. 그런데, 약속을 쓰기위해서는 내가 갈 방향을 보고 약속을 사용해야해. 도와줄거지?', maze_content_28: '드디어 마지막이야! 약속을 이용하여 마지막 배터리를 얻을 수 있게 도와줘!', ai_content_1: '안녕? 나는 엔트리봇이라고 해. 우주 탐사를 마치고 지구로 돌아가려는데 우주를 떠다니는 돌들 때문에 쉽지 않네. 내가 안전하게 집에 갈 수 있도록 도와줄래? 나의 우주선에는 나의 앞과 위, 아래에 무엇이 어느 정도의 거리에 있는지 알려주는 레이더가 있어 너의 판단을 도와줄 거야!', ai_content_2: '고마워! 덕분에 돌을 쉽게 피할 수 있었어. 그런데 이번엔 더 많은 돌이 있잖아? 블록들을 조립하여 돌들을 이리저리 잘 피해 보자!', ai_content_3: '좋았어! 안전하게 돌을 피했어. 그런데 앞을 봐! 아까보다 더 많은 돌이 있어. 하지만 걱정하지 마. 나에게 반복하기 블록이 있거든. 반복하기 블록 안에 움직이는 블록을 넣으면 목적지에 도착할 때까지 계속 움직일게!', ai_content_4: '대단해! 반복하기 블록을 쓰니 많은 돌을 피하기가 훨씬 수월한걸! 하지만 이렇게 일일이 조종하기는 피곤하다. 나에겐 레이더가 있으니 앞으로 무엇이 나올지 알 수 있어. 앞으로 계속 가다가 앞에 돌이 있으면 피할 수 있도록 해줄래?', ai_content_5: '잘했어! 여기까지 와서 아주 기뻐. 이번에는 레이더가 앞에 있는 물체까지의 거리를 말해줄 거야. 이 기능을 사용하여 돌을 피해 보자! 돌까지의 거리가 멀 때는 앞으로 계속 가다가, 거리가 가까워지면 피할 수 있도록 해줄래?', ai_content_6: '와~ 멋진걸? 레이더를 활용하여 돌을 잘 피해 나가고 있어! 이번에는 여러 개의 레이더를 사용하여 이리저리 돌들을 피해 나갈 수 있게 만들어줄래?', ai_content_7: '휴~ 지구에 점점 가까워지고 있어! 돌을 피할 때 기왕이면 더 안전한 길로 가고 싶어! 아마도 돌이 더 멀리 있는 쪽이 더 안전한 길이겠지? 위쪽 레이더와 아래쪽 레이더를 비교하여 더 안전한 쪽으로 움직이도록 해줄래?', ai_content_8: '좋아! 덕분에 무사히 비행하고 있어. 어? 그런데 저게 뭐지? 저건 내가 아주 위급한 상황에서 사용할 수 있는 특별한 에너지야! 이번에는 저 아이템들을 모두 모으며 움직이자!', ai_content_9: '훌륭해! 이제 지구까지 얼마 안 남았어. 그런데 앞을 보니 돌들로 길이 꽉 막혀서 지나갈 수가 없잖아? 하지만 걱정하지 마. 아이템을 획득해서 사용하면 앞에 있는 꽉 막힌 돌들을 없앨 수 있다고!', ai_content_10: '좋아! 드디어 저기 지구가 보여! 이럴 수가! 이제는 날아오는 돌들을 미리 볼 수가 없잖아? 돌들이 어떻게 날아올지 알지 못해도 지금까지처럼만 움직이면 잘 피할 수 있을 것 같아! 지구까지 가보는 거야!', maze_hints_title_1: '시작 방법', maze_hints_content_1: '엔트리봇은 어떻게 움직이나요?', maze_hints_detail_1: '1. 블록 꾸러미에서 원하는 블록을 꺼내어 “시작하기를 클릭했을 때” 블록과 연결해봐
2. 다 조립했으면, 시작을 눌러봐
3. 나는 네가 조립한 블록대로 위에서부터 순서대로 움직일게', maze_hints_title_2: '장애물 뛰어넘기', maze_hints_content_2: '장애물이 있으면 어떻게 해야하나요?', maze_hints_detail_2: '길을 가다보면 장애물을 만날 수 있어.
장애물이 앞에 있을 때에는 뛰어넘기 블록을 사용해야 해.', maze_hints_title_3: '반복 블록(1)', maze_hints_content_3: '(3)회 반복하기 블록은 어떻게 사용하나요?', maze_hints_detail_3: '같은 행동을 여러번 반복하려면 ~번 반복하기 블록을 사용해야 해.
반복하고 싶은 블록들을 ~번 반복하기 안에 넣고 반복 횟수를 입력하면 돼.', maze_hints_title_4: '반복 블록(2)', maze_hints_content_4: '~를 만날 때 까지 반복하기 블록은 어떻게 사용하나요?', maze_hints_detail_4: "~까지 반복하기'를 사용하면 같은 행동을 언제까지 반복할지를 정해줄 수 있어.
반복하고 싶은 블록들을 ~까지 반복하기안에 넣으면 돼.
그러면 {이미지}와 같은 타일 위에 있는 경우 반복이 멈추게 될 거야.", maze_hints_title_5: '만약 블록', maze_hints_content_5: '만약 ~라면 블록은 어떻게 동작하나요?', maze_hints_detail_5: "만약 앞에 {이미지}가 있다면' 블록을 사용하면 앞에 {이미지}가 있을 때 어떤 행동을 할 지 정해줄 수 있어.
앞에 {이미지}가 있을 때에만 블록 안의 블록들을 실행하고
그렇지 않으면 실행하지 않게 되는 거야.", maze_hints_title_6: '반복 블록(3)', maze_hints_content_6: '모든 ~를 만날 때 까지 블록은 어떻게 동작하나요?', maze_hints_detail_6: '모든 {타일}에 한 번씩 도착할 때까지 그 안에 있는 블록을 반복해서 실행해.
모든 {타일}에 한 번씩 도착하면 반복이 멈추게 될 거야.', maze_hints_title_7: '특별 힌트', maze_hints_content_7: '너무 어려워요. 도와주세요.', maze_hints_detail_7: '내가 가야하는 길을 자세히 봐. 작은 사각형 4개가 보여?
작은 사각형을 도는 블록을 만들고, 반복하기를 사용해 보는것은 어때?', maze_hints_title_8: '약속', maze_hints_content_8: '약속하기/약속 불러오기 무엇인가요? 어떻게 사용하나요?', maze_hints_detail_8: "나를 움직이기 위해 자주 쓰는 블록들의 묶음을 '약속하기' 블록 아래에 조립하여 약속으로 만들 수 있어.
한번 만들어 놓은 약속은 '약속 불러오기' 블록을 사용하여 여러 번 꺼내 쓸 수 있다구.", ai_hints_title_1_1: '게임의 목표', ai_hints_content_1_1: '돌을 피해 오른쪽 행성까지 안전하게 이동할 수 있도록 도와주세요.', ai_hints_detail_1_1: '돌을 피해 오른쪽 행성까지 안전하게 이동할 수 있도록 도와주세요.', ai_hints_title_1_2: '시작 방법', ai_hints_content_1_2: '어떻게 시작할 수 있나요?', ai_hints_detail_1_2: '1. 블록 꾸러미에서 원하는 블록을 꺼내어 “시작하기를 클릭했을 때” 블록과 연결해봐
2. 다 조립했으면, 시작을 눌러봐
3. 나는 네가 조립한 블록대로 위에서부터 순서대로 움직일게', ai_hints_title_1_3: '움직이게 하기', ai_hints_content_1_3: '엔트리봇은 어떻게 움직이나요?', ai_hints_detail_1_3: '나는 위쪽으로 가거나 앞으로 가거나 아래쪽으로 갈 수 있어.
방향을 정할 때에는 돌이 없는 방향으로 안전하게 갈 수 있도록 해줘.
나를 화면 밖으로 내보내면 우주미아가 되어버리니 조심해!', ai_hints_title_2_1: '게임의 목표', ai_hints_content_2_1: '반복하기 블록으로 돌들을 피할 수 있도록 도와주세요.', ai_hints_detail_2_1: '반복하기 블록으로 돌들을 피할 수 있도록 도와주세요.', ai_hints_title_2_2: '반복 블록', ai_hints_content_2_2: '반복 블록은 무슨 블록인가요?', ai_hints_detail_2_2: '휴~ 이번에 가야 할 길은 너무 멀어서 하나씩 조립하기는 힘들겠는걸? 반복하기블록을 사용해봐.
똑같이 반복되는 블록들을 반복하기 블록으로 묶어주면 아주 긴 블록을 짧게 줄여줄 수 있어!', ai_hints_content_3_1: '만약 블록으로 돌을 피할 수 있도록 도와주세요.', ai_hints_title_3_2: '만약 블록(1)', ai_hints_content_3_2: '만약 ~라면 블록은 어떻게 동작하나요?', ai_hints_detail_3_2: "만약 앞에 ~가 있다면 / 아니면 블록을 사용하면 내 바로 앞에 돌이 있는지 없는지 확인해서 다르게 움직일 수 있어~
만약 내 바로 앞에 돌이 있다면 '만약' 아래에 있는 블록들을 실행하고 돌이 없으면 '아니면' 안에 있는 블록들을 실행할 거야.
내 바로 앞에 돌이 있을 때와 없을 때, 어떻게 움직일지 잘 결정해줘~", ai_hints_content_4_1: '레이더의 사용 방법을 익히고 돌을 피해보세요.', ai_hints_detail_4_1: '레이더의 사용 방법을 익히고 돌을 피해보세요.', ai_hints_title_4_2: '레이더(1)', ai_hints_content_4_2: '레이더란 무엇인가요? 어떻게 활용할 수 있나요?', ai_hints_detail_4_2: "레이더는 지금 내가 물체와 얼마나 떨어져 있는지 알려주는 기계야.
만약 바로 내 앞에 무엇인가 있다면 앞쪽 레이더는 '1'을 보여줘.
또, 레이더는 혼자 있을 때 보다 만약 <사실>이라면 / 아니면 블록과
같이 쓰이면 아주 강력하게 쓸 수 있어.
예를 들어 내 앞에 물체와의 거리가 1보다 크다면 나는 안전하게 앞으로 갈 수 있겠지만, 아니라면 위나 아래쪽으로 피하도록 할 수 있지.", ai_hints_title_4_3: '만약 블록(2)', ai_hints_content_4_3: '만약 <사실>이라면 블록은 어떻게 사용하나요?', ai_hints_detail_4_3: "만약 <사실>이라면 / 아니면 블록은 <사실> 안에 있는 내용이 맞으면 '만약' 아래에 있는 블록을 실행하고, 아니면 '아니면' 아래에 있는 블록을 실행해.
어떤 상황에서 다르게 움직이고 싶은 지를 잘 생각해서 <사실> 안에 적절한 판단 조건을 만들어 넣어봐.
판단 조건을 만족해서 '만약' 아래에 있는 블록을 실행하고 나면 '아니면' 아래에 있는 블록들은 실행되지 않는다는 걸 기억해!", ai_hints_content_5_1: '레이더를 활용해 돌을 쉽게 피할 수 있도록 도와주세요.', ai_hints_detail_5_1: '레이더를 활용해 돌을 쉽게 피할 수 있도록 도와주세요.', ai_hints_title_5_2: '만약 블록(3)', ai_hints_content_5_2: '만약 블록이 겹쳐져 있으면 어떻게 동작하나요?', ai_hints_detail_5_2: '만약 ~ / 아니면 블록안에도 만약 ~ / 아니면 블록을 넣을 수 있어! 이렇게 되면 다양한 상황에서 내가 어떻게 행동해야 할지 정할 수 있어.
예를 들어 앞에 돌이 길을 막고 있을때와 없을때의 행동을 정한다음, 돌이 있을때의 상황에서도 상황에 따라 위쪽으로 갈지 아래쪽으로 갈지 선택 할 수 있어', ai_hints_title_6_1: '레이더(2)', ai_hints_content_6_1: '위쪽 레이더와 아래쪽 레이더의 값을 비교하고 싶을 땐 어떻게 하나요?', ai_hints_detail_6_1: '([위쪽]레이더) 블록은 위쪽 물체까지의 거리를 뜻하는 블록이야.
아래쪽과 위쪽 중에서 어느 쪽에 돌이 더 멀리 있는지 확인하기 위해서 쓸 수 있는 블록이지.
돌을 피해가는 길을 선택할 때에는 돌이 멀리 떨어져 있는 쪽으로 피하는게 앞으로 멀리 가는데 유리할거야~', ai_hints_content_7_1: '아이템을 향해 이동하여 돌을 피해보세요.', ai_hints_detail_7_1: '아이템을 향해 이동하여 돌을 피해보세요.', ai_hints_title_7_2: '물체 이름 확인', ai_hints_content_7_2: '앞으로 만날 물체의 이름을 확인해서 무엇을 할 수 있나요?', ai_hints_detail_7_2: '아이템을 얻기위해서는 아이템이 어디에 있는지 확인할 필요가 있어.
그럴 때 사용할 수 있는 블록이 [위쪽] 물체는 [아이템]인가? 블록이야.
이 블록을 활용하면 아이템이 어느 위치에 있는지 알 수 있고 아이템이 있는 방향으로 움직이도록 블록을 조립할 수 있어.', ai_hints_content_8_1: '아이템을 적절하게 사용해서 돌을 피해보세요.', ai_hints_detail_8_1: '아이템을 적절하게 사용해서 돌을 피해보세요.', ai_hints_title_8_2: '아이템', ai_hints_content_8_2: '아이템은 어떻게 얻고 사용하나요?', ai_hints_detail_8_2: '돌들을 이리저리 잘 피해 나가더라도 앞이 모두 돌들로 꽉 막혀있을 땐 빠져나갈 방법이 없겠지? 그럴 때에는 아이템사용 블럭을 사용해봐.
이 블록은 내 앞의 돌들을 모두 없애는 블록이야.
단, 아이템이 있어야지만 블록을 사용할 수 있고, 아이템은 이미지를 지나면 얻을 수 있어.', ai_hints_content_9_1: '지금까지 배운 것들을 모두 활용해서 최대한 멀리 가보세요.', ai_hints_detail_9_1: '지금까지 배운 것들을 모두 활용해서 최대한 멀리 가보세요.', ai_hints_title_9_2: '그리고', ai_hints_content_9_2: '그리고 블록은 어떻게 사용하나요?', ai_hints_detail_9_2: '그리고 블록에는 여러개의 조건을 넣을 수 있어, 넣은 모든 조건이 사실일때만 사실이 되어 만약 블록 안에 있는 블록이 실행되고, 하나라도 거짓이 있으면 거짓으로 인식해서 그 안에 있는 블록을 실행하지 않아', maze_text_goal_1: 'move(); 명령어를 사용하여 부품 상자까지 나를 이동시켜줘!', maze_text_goal_2: 'jump(); 명령어로 장애물을 피해 부품 상자까지 나를 이동시켜줘!', maze_text_goal_3: 'left(); right(); 명령어로 부품상자까지 나를 이동시켜줘!', maze_text_goal_4: '여러가지 명령어를 사용하여 부품상자까지 나를 이동시켜줘!', maze_text_goal_5: '두 부품상자에 다 갈 수 있도록 나를 이동시켜줘!', maze_text_goal_6: '두 부품상자에 다 갈 수 있도록 나를 이동시켜줘!', maze_text_goal_7: 'for 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_8: 'for 명령어를 사용하고, 장애물을 피해 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_9: 'while 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_10: 'if와 while 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_11: 'if와 while 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_12: 'if와 while 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_13: 'while과 for 명령어를 사용하여 모든 친구들을 만날 수 있도록 나를 이동시켜줘!', maze_text_goal_14: 'while과 for 명령어를 사용하여 모든 친구들을 만날 수 있도록 나를 이동시켜줘!', maze_text_goal_15: '함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_16: '함수에 명령어를 넣고 함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_17: '함수에 명령어를 넣고 함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_18: '함수에 명령어를 넣고 함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_19: '함수에 명령어를 넣고 함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_20: '함수와 다른명령어들을 섞어 사용하여 배터리까지 나를 이동시켜줘!', maze_attack_range: '공격 가능 횟수', maze_attack: '공격', maze_attack_both_sides: '양 옆 공격', above_radar: '위쪽 레이더', above_radar_text_mode: 'radar_up', bottom_radar: '아래쪽 레이더', bottom_radar_text_mode: 'radar_down', front_radar: '앞쪽 레이더', front_radar_text_mode: 'radar_right', above_object: '위쪽 물체', above_object_text_mode: 'object_up', front_object: '앞쪽 물체', front_object_text_mode: 'object_right', below_object: '아래쪽 물체', below_object_text_mode: 'object_down', destination: '목적지', asteroids: '돌', item: '아이템', wall: '벽', destination_text_mode: 'destination', asteroids_text_mode: 'stone', item_text_mode: 'item', wall_text_mode: 'wall', buy_now: '구매바로가기', goals: '목표', instructions: '이용 안내', object_info: '오브젝트 정보', entry_basic_mission: '엔트리 기본 미션', entry_application_mission: '엔트리 응용 미션', maze_move_forward: '앞으로 한 칸 이동', maze_when_run: '시작하기를 클릭했을때', maze_turn_left: '왼쪽으로 회전', maze_turn_right: '오른쪽으로 회전', maze_repeat_times_1: '', maze_repeat_times_2: '번 반복하기', maze_repeat_until_1: '', maze_repeat_until_2: '을 만날때까지 반복', maze_call_function: '약속 불러오기', maze_function: '약속하기', maze_repeat_until_all_1: '모든', maze_repeat_until_all_2: '만날 때 까지 반복', command_guide: '명령어 도움말', ai_success_msg_1: '덕분에 무사히 지구에 도착할 수 있었어! 고마워!', ai_success_msg_2: '다행이야! 덕분에', ai_success_msg_3: '번 만큼 앞쪽으로 갈 수 있어서 지구에 구조 신호를 보냈어! 이제 지구에서 구조대가 올거야! 고마워!', ai_success_msg_4: '좋았어!', ai_cause_msg_1: '이런, 어떻게 움직여야 할 지 더 말해줄래?', ai_cause_msg_2: '아이쿠! 정말로 위험했어! 다시 도전해보자', ai_cause_msg_3: '우와왓! 가야할 길에서 벗어나버리면 우주 미아가 되버릴꺼야. 다시 도전해보자', ai_cause_msg_4: '너무 복잡해, 이 블록을 써서 움직여볼래?', ai_move_forward: '앞으로 가기', ai_move_above: '위쪽으로 가기', ai_move_under: '아래쪽으로 가기', ai_repeat_until_dest: '목적지에 도달 할 때까지 반복하기', ai_if_front_1: '만약 앞에', ai_if_front_2: '가 있다면', ai_else: '아니면', ai_if_1: '만약', ai_if_2: '이라면', ai_use_item: '아이템 사용', ai_radar: '레이더', ai_above: '위쪽', ai_front: '앞쪽', ai_under: '아래쪽', ai_object_is_1: '', ai_object_is_2: '물체는', challengeMission: '다른 미션 도전하기', nextMission: '다음 미션 도전하기', withTeacher: '함께 만든 선생님들', host: '주최', support: '후원', subjectivity: '주관', learnMore: ' 더 배우고 싶어요', ai_object_is_3: '인가?', stage_is_not_available: '아직 진행할 수 없는 스테이지입니다. 순서대로 스테이지를 진행해 주세요.', progress_not_saved: '진행상황이 저장되지 않습니다.', want_refresh: '이 페이지를 새로고침 하시겠습니까?', monthly_entry_grade: '초등학교 3학년 ~ 중학교 3학년', monthly_entry_contents: '매월 발간되는 월간엔트리와 함께 소프트웨어 교육을 시작해 보세요! 차근차근 따라하며 쉽게 익힐 수 있도록 가볍게 구성되어있습니다. 기본, 응용 콘텐츠와 더 나아가기까지! 매월 업데이트되는 8개의 콘텐츠와 교재를 만나보세요~', monthly_entry_etc1: '*메인 페이지의 월간 엔트리 추천코스를 활용하면 더욱 쉽게 수업을 할 수 있습니다.', monthly_entry_etc2: '*월간엔트리는 학기 중에만 발간됩니다.', group_make_lecture_1: '내가 만든 강의가 없습니다.', group_make_lecture_2: "'만들기>오픈 강의 만들기'에서", group_make_lecture_3: '우리반 학습내용에 추가하고 싶은 강의를 만들어 주세요.', group_make_lecture_4: '강의 만들기', group_add_lecture_1: '관심 강의가 없습니다.', group_add_lecture_2: "'학습하기>오픈 강의> 강의'에서 우리반 학습내용에", group_add_lecture_3: '추가하고 싶은 강의를 관심강의로 등록해 주세요.', group_add_lecture_4: '강의 보기', group_make_course_1: '내가 만든 강의 모음이 없습니다.', group_make_course_2: "'만들기 > 오픈 강의 만들기> 강의 모음 만들기'에서", group_make_course_3: '학습내용에 추가하고 싶은 강의 모음을 만들어 주세요.', group_make_course_4: '강의 모음 만들기', group_add_course_1: '관심 강의 모음이 없습니다.', group_add_course_2: "'학습하기 > 오픈 강의 > 강의 모음'에서 우리반 학습내용에", group_add_course_3: '추가하고 싶은 강의 모음을 관심 강의 모음으로 등록해 주세요.', group_add_course_4: '강의 모음 보기', hw_main_title: '프로그램 다운로드', datablock_contest_title: '데이터분석 블록 추가', datablock_content_head: '데이터를 가공하고 표현하기', datablock_content_body1: '생활 속 다양한 데이터를 차트로 표현하고 의미를 찾아', datablock_content_body2: '실생활 문제를 해결해보세요!', campaign_contest_title: '아름다운 인터넷 세상을 만들어요', campaign_content_head: '엔트리 작품 공모전', campaign_content_body1: "'인터넷윤리'에 대해 알기 쉽고 재미있게", campaign_content_body2: '작품을 만들어 응모해주세요!', campaign_content_button: '자세히 보기', code_management_1: '엔트리 캠페인 #1 코드 잘 관리하기', code_management_2: '나의 보관함과 메모 활용', code_management_3: '새 기능 나의 보관함과 메모로 하는 코드 관리 비법!', code_management_4: '작품을 더 잘 만들고 쉽게 공유하는 방법을 알아보아요.', code_management_5: '캠페인 보기', shcoolbook_study_1: '교과서 내용 그대로 학습하세요.', shcoolbook_study_2: '교과서 학습하기', shcoolbook_study_3: '선생님은 교실에서 수업 진행을', shcoolbook_study_4: '학생은 집에서 복습을 할 수 있습니다!', shcoolbook_study_5: '학습하기', main_learn_1: '엔트리에 처음 오셨다면', main_learn_2: '엔트리 알아보기', main_learn_3: '영상을 통해 엔트리의 다양한 기능을 알아보고,', main_learn_4: '멋진 작품을 만들어 친구들과 공유해보세요!', main_learn_5: '영상보기', hw_desc_wrapper: '엔트리 하드웨어 연결 프로그램과 오프라인 버전이 \n서비스를 한층 더 강화해 업그레이드 되었습니다.\n업데이트 된 프로그램을 설치해주세요!', hw_downolad_link: '하드웨어 연결 \n프로그램 다운로드', save_as_image_all: '모든 코드 이미지로 저장하기', save_as_image: '이미지로 저장하기', maze_perfect_success: '멋져! 완벽하게 성공했어~', maze_success_many_block_1: '좋아', maze_fail_obstacle_remain: "친구들이 다치지 않도록 모든 을 없애줘.", maze_fail_item_remain: '샐리 공주를 구하기 위해 모든 미네랄을 모아 와줘.', maple_fail_item_remain: '음식을 다 먹지 못해서 힘이 나지 않아. 모든 음식을 다 먹을 수 있도록 도와줘.', maze_fail_not_found_destory_object: '아무것도 없는 곳에 능력을 낭비하면 안 돼!', maze_fail_not_found_destory_monster: '몬스터가 없는 곳에 공격을 하면 안 돼!', maple_fail_not_found_destory_monster: '공격 블록은 몬스터가 있을 때에만 해야 돼!', maze_fail_more_move: '목적지까지는 좀 더 움직여야 해!', maze_fail_wall_crash: '으앗! 거긴 갈 수 없는 곳이야!', maze_fail_contact_brick: '에구구… 부딪혔다!', maze_fail_contact_iron1: '으앗! 장애물에 부딪혀버렸어', maze_fail_contact_iron2: '으앗! 장애물이 떨어져서 다쳐버렸어. 장애물이 내려오기전에 움직여줘..', maze_fail_fall_hole: '앗, 함정에 빠져 버렸어...', maze_fail_hit_unit: '몬스터에게 당해버렸어! 위험한 몬스터를 물리치기 위해 하트 날리기 블록을 사용해줘!', maze_fail_hit_unit2: '윽, 몬스터에게 공격당했다! 두 칸 떨어진 곳에서 공격해줘!', maze_fail_hit_unit_by_mushroom: "주황버섯에게 당해버렸어!
공격하기 블록을 사용해서 나쁜 몬스터를 혼내줘!", maze_fail_hit_unit_by_lupin: "루팡에게 당해버렸어!
공격하기 블록을 두 칸 떨어진 곳에서 사용해서 나쁜 몬스터를 혼내줘!", maze_fail_elnath_fail: '으앗! 나쁜 몬스터가 나를 공격했어.
나쁜 몬스터가 나에게 다가오지 못하게 혼내줘!', maze_fail_pepe: '', maze_fail_yeti: "그 몬스터는 너무 강해서 공격하기 블록으로는 혼내줄 수 없어
공격하기 블록을 사용해보자.", maze_fail_peti: "그 몬스터에게 공격하기 블록을 사용하면,
강한 몬스터인 가 나왔을 때 혼내줄 수 없어
공격하기 블록을 사용해보자.", maze_fail_both_side: '양 옆 공격하기는 양쪽에 몬스터가 있을 때에만 사용해야 돼!', maze_wrong_attack_obstacle: "이 곳에서는 공격하기 블록을 사용할 수 없어
주황 버섯에게는 공격하기 블록을 사용해보자.", maze_fail_contact_spider: '거미집에 걸려 움직일 수가 없어...', maze_success_perfect: '멋져! 완벽하게 성공했어~', maze_success_block_excess: '좋아! %1개의 블록을 사용해서 성공했어!
하지만, %2개의 블록만으로 성공하는 방법도 있어. 다시 도전해 보는 건 어때?', maze_success_not_essential: '좋아! %1개의 블록을 사용해서 성공했어!
하지만 이 블록을 사용하면 더 쉽게 해결할 수 있어. 다시 도전해 보는 건 어때?', maze_success_final_perfect_basic: '좋아! 샐리 공주가 어디 있는지 찾았어! 이제 샐리 공주를 구할 수 있을 거야!', maze_success_final_block_excess_basic: '좋아! 샐리 공주가 어디 있는지 찾았어! 이제 샐리 공주를 구할 수 있을 거야!%1개의 블록을 사용했는데, %2개의 블록만으로 성공하는 방법도 있어. 다시 해볼래?', maze_success_final_perfect_advanced: '샐리 공주가 있는 곳까지 도착했어! 이제 악당 메피스토를 물리치고 샐리를 구하면 돼!', maze_success_final_block_excess_advanced: '샐리 공주가 있는 곳까지 도착했어! 이제 악당 메피스토를 물리치고 샐리를 구하면 돼!%1개의 블록을 사용했는데, %2개의 블록만으로 성공하는 방법도 있어. 다시 해볼래?', maze_success_final_distance: '좋아! 드디어 우리가 샐리 공주를 무사히 구해냈어. 구할 수 있도록 도와줘서 정말 고마워!
%1칸 움직였는데 다시 한 번 다시해서 60칸까지 가볼래?', maze_success_final_perfect_ai: '좋았어! 드디어 우리가 샐리 공주를 무사히 구해냈어. 구할 수 있도록 도와줘서 정말 고마워!', maple_success_perfect: '좋아! 완벽하게 성공했어!!', maple_success_block_excess: '좋아! %1개의 블록을 사용해서 성공했어!
그런데 %2개의 블록으로도 성공하는 방법이 있어. 다시 도전해 보는건 어때?', maple_success_not_essential: '좋아! %1개의 블록을 사용해서 성공했어!
그런데 이 블록을 사용하면 더 쉽게 해결할 수 있어. 다시 도전해 보는 건 어때?', maple_success_final_perfect_henesys: '멋져! 헤네시스 모험을 훌륭하게 해냈어.', maple_success_final_perfect_excess_henesys: '멋져! 헤네시스 모험을 잘 해냈어.
그런데 %2개의 블록으로도 성공하는 방법이 있어. 다시 도전해 보는 건 어때?', maple_success_final_not_essential_henesys: '멋져! 헤네시스 모험을 잘 해냈어.
그런데 이 블록을 사용하면 더 쉽게 해결할 수 있어. 다시 도전해 보는 건 어때?', maple_success_final_perfect_ellinia: '우와! 이 곳에서 정말 재밌는 모험을 했어!
다음 모험도 같이 할거지? ', maple_success_final_perfect_excess_ellinia: '우와! 이 곳에서 정말 재밌는 모험을 했어!
그런데 %2개의 블록으로도 성공하는 방법이 있어. 다시 도전해 보는 건 어때?', maple_success_final_not_essential_ellinia: '우와! 이 곳에서 정말 재밌는 모험을 했어!
그런데 이 블록을 사용하면 더 쉽게 해결할 수 있어. 다시 도전해 보는 건 어때?', maple_fail_fall_hole: '으앗! 빠져버렸어!
뛰어넘기 블록을 사용해서 건너가보자.', maple_fail_ladder_fall_hole: '으앗! 빠져버렸어!
사다리 타기 블록을 사용해서 다른 길로 가보자.', maple_fail_more_move: '성공하려면 목적지까지 조금 더 움직여야 해!', maple_fail_not_found_ladder: '이런, 여기엔 탈 수 있는 사다리가 없어.
사다리 타기 블록은 사다리가 있는 곳에서만 사용 해야해.', maple_fail_not_found_meat: '이런, 여기엔 먹을 수 있는 음식이 없어!
음식 먹기 블록은 음식이 있는 곳에서만 사용 해야해.', maple_cert_input_title: '내가 받을 인증서에 적힐 이름은?', maze_distance1: '거리 1', maze_distance2: '거리 2', maze_distance3: '거리 3', ev3: 'EV3', roborobo_roduino: '로두이노', roborobo_schoolkit: '스쿨키트', smartboard: '과학상자 코딩보드', smartboardbt: '과학상자 코딩보드(무선)', codestar: '코드스타', cobl: '코블', cobl_bt: '코블 블루투스', block_coding: '블록코딩', python_coding: '엔트리파이선', dadublock: '다두블럭', dadublock_car: '다두블럭 자동차', blacksmith: '대장장이 보드', course_submit_homework: '과제 제출', course_done_study: '학습 완료', course_show_list: '목록', modi: '모디', chocopi: '초코파이보드', coconut: '코코넛', jdkit: '제이디키트', practical_course: '교과용 만들기', entry_user_policy: '엔트리 이용정책', entry_scholarship_title: '엔트리 학술 자료', entry_scholarship_content: '엔트리는 대학/학회 등과 함께 다양한 연구를 진행하여 전문성을 강화해나가고 있습니다. 엔트리에서 제공하는 연구용 자료를 확인해보세요', entry_scholarship_content_sub: '*엔트리에서 제공하는 데이터는 연구 및 분석에 활용될 수 있도록 온라인코딩파티에 참여한 사용자들이 미션을 해결하는 일련의 과정을 로그 형태로 저장한 데이터 입니다.', entry_scholarship_download: '자료 다운로드', codingparty_2016_title: '2016 온라인 코딩파티', codingparty_2016_content: '미션에 참여한 사용자들의 블록 조립 순서, 성공/실패 유무가 학년, 성별 정보와 함께 제공됩니다.', codingparty_2017_title: '2017 온라인 코딩파티', scholarship_go_mission: '미션 확인하기', scholarship_guide: '자료 활용 방법', scholarship_see_guide: '가이드 보기', scholarship_guide_desc: '연구용 자료를 읽고 활용할 수 있는 방법이 담긴 개발 가이드 입니다. ', scholarship_example: '자료 활용 예시', scholarship_example_desc: '연구용 자료를 활용하여 발표된 논문을 확인 할 수 있습니다.', scholarship_see_example: '논문 다운로드', altino: '알티노', private_project: '비공개 작품입니다.', learn_programming_entry_mission: '"엔트리봇"과 함께 미션 해결하기', learn_programming_line_mission: '"라인레인저스"와 샐리구하기', learn_programming_choseok: '"마음의 소리"의 조석과 게임 만들기', learn_programming_maple: '"핑크빈"과 함께 신나는 메이플 월드로!', learn_programming_level_novice: '기초', learn_programming_level_inter: '중급', learn_programming_level_advanced: '고급', line_look_for: '샐리를 찾아서', line_rangers_title_string: '학습하기 : 라인 레인저스', online_codingparty_certificate_string: '온라인 코딩파티', online_codingparty_line_title_string: '라인 레인저스', line_look_for_desc_1: '라인 레인저스의 힘을 모아 강력한 악당 메피스토를 물리치고 샐리를 구해주세요!', line_save: '샐리 구하기', line_save_desc_1: '메피스토 기지에 갇힌 샐리. 라인 레인저스가 장애물을 피해 샐리를 찾아갈 수 있도록 도와주세요!', line_escape: '샐리와 탈출하기', line_escape_desc_1: '폭파되고 있는 메피스토 기지에서 샐리와 라인 레인저스가 무사히 탈출할 수 있도록 도와주세요!', solve_choseok: '가위바위보 만들기', solve_choseok_desc_1: '만화 속 조석이 가위바위보 게임을 만들 수 있도록 도와주세요!', solve_henesys: '헤네시스', solve_ellinia: '엘리니아', solve_elnath: '엘나스', solve_henesys_desc_1: '마을을 모험하며, 배고픈 핑크빈이 음식을 배불리 먹을 수 있도록 도와주세요!', solve_ellinia_desc_1: '숲 속을 탐험하며, 나쁜 몬스터들을 혼내주고 친구 몬스터들을 구해주세요!', solve_elnath_desc_1: '나쁜 몬스터가 점령한 설산을 지나, 새로운 모험을 시작할 수 있는 또 다른 포털을 찾아 떠나보세요 !', save_modified_shape: '수정된 내용을 저장하시겠습니까?', save_modified_table: '테이블에서 수정한 내용을 저장하시겠습니까?', attach_file: '첨부', enter_discuss_title: '제목을 입력해 주세요(40자 이하)', enter_discuss_title_alert: '제목을 입력해 주세요', discuss_upload_warn: '10MB이하의 파일을 올려주세요.', discuss_list: '목록보기', discuss_write_notice: '우리반 공지사항으로 지정하여 게시판 최상단에 노출합니다.', discuss_write_notice_open: '공지사항으로 지정하여 게시판 최상단에 노출합니다.', search_전체: '전체', search_게임: '게임', search_애니메이션: '애니메이션', search_미디어아트: '미디어 아트', search_피지컬: '피지컬', search_기타: '기타', discuss_write_textarea_placeholer: '엔트리 커뮤니티는 우리가 함께 만들어가는 공간입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_qna: '여기는 묻고답하기 게시판입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_tips: '여기는 노하우&팁 게시판입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_free: '여기는 엔트리 이야기 게시판입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_report: '여기는 제안 및 건의 게시판입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_contest2019: '※ 아래 양식으로 작성하여 제출해주세요.\n\n1. 학년 (예: 초등학교 5학년)\n\n2. 작품 URL (‘공유하기 > 작품 공유하기’에 작품을 공유한 다음, 작품 URL을 복사하여 적어주세요.)\n\n3. 작품 설명\n\n※ 공모전 수상자에게는 이메일이 발송될 예정입니다.\n엔트리의 ‘내 정보 수정‘에 이메일 정보를 꼭 입력해주세요!', maze_road: '길', account_deletion: '회원탈퇴', bug_report_too_many_request: '신고 내용이 전송 되고 있습니다. 잠시 후에 다시 시도해주시길 바랍니다.', pinkbean_index_title: '핑크빈과 함께 신나는 메이플 월드로!', pinkbean_index_content: '심심함을 참지 못한 핑크빈이 메이플 월드로 모험을 떠났습니다.
핑크빈과 함께 신나는 메이플 월드를 탐험하여 모험일지를 채워주세요.
각 단계를 통과하면서 자연스럽게 소프트웨어를 배워볼 수 있고, 미션을 마치면 인증서도 얻을 수 있습니다.', rangers_index_title: '라인 레인저스와 함께 샐리를 구하러 출동!', rangers_index_content: '악당 메피스토에게 납치된 샐리를 구하기 위해 라인 레인저스가 뭉쳤습니다.
소프트웨어의 원리를 통해 장애물을 극복하고, 샐리를 구출하는 영웅이 되어주세요.
각 단계를 통과하면서 자연스럽게 소프트웨어를 배워볼 수 있고, 미션을 마치면 인증서도
얻을 수 있습니다.', rangers_replay_button: '영상 다시보기', rangers_start_button: '미션 시작', lms_curriculum_intro: '학습시작', lms_curriculum_goal: '학습목표', lms_curriculum_prepare: '학습준비', lms_curriculum_study: '실습활동', lms_curriculum_summary: '학습정리', lms_curriculum_quiz: '확인문제', lms_curriculum_now_stage: '현재 단계', bug_report_title: '버그 리포트', bug_report_content: '이용 시 발생하는 오류나 버그 신고 및 엔트리를 위한 좋은 제안을 해주세요. 신고나 제안과 무관한 욕설 작성 시 이용이 정지될 수 있습니다.', object_import_syntax_error: '불러오려는 오브젝트에 엔트리파이선 문법과 맞지 않는 블록이 포함되어 있습니다. 블록코딩으로 전환한 뒤 오브젝트를 불러와주세요.', choseok_top_wrapper_panel_title: '조석과 함께 가위바위보 게임을 만들어보세요!', choseok_top_wrapper_panel_des: '마음의 소리 웹툰이 코딩파티 미션으로 탄생했습니다.
만화속 조석이 (가위바위보 게임)을 만들어가는 과정에 참여하여 미션에
도전해 보세요.
각 단계를 통과하면서 자연스럽게 소프트웨어를 배워볼 수 있고, 미션을 모두 마치면
인증서와 나만의 게임을 얻을 수 있습니다.
', choseok_mission_statement1: '조석을 움직여보자', choseok_mission_statement2: '가위바위보를 시작해보자', choseok_mission_statement3: '가위바위보 승부를 가려보자', choseok_mission_statement4: '가위바위보 게임을 완성해보자', choseok_mission_statement5: '자유롭게 만들어보자', choseok_mission_statement_top1: '미션 1 : 조석을 움직이기', choseok_mission_statement_top2: '미션 2 : 가위바위보를 시작하기', choseok_mission_statement_top3: '미션 3 : 가위바위보 승패 만들기', choseok_mission_statement_top4: '미션 4 : 가위바위보 결과 보여주기', choseok_mission_statement_top5: '미션 5 : 자유롭게 만들어보기', advisory_title: '엔트리 자문단', advisory_sub_title: '엔트리를 함께 만들어가는 선생님 학생 자문단입니다.', data_table_column: '열', data_table_row: '행', data_table_provider: '제공처', data_table_modifidate: '수정일', draw_new_table_ques_1: '데이터를 직접 입력하여 테이블로 저장할 수 있습니다.', draw_new_table_ques_2: '테이블 화면으로 이동하시겠습니까?', }; Lang.Msgs = { microbit_led_erase_all: '모두 지우기', loading_plz_wait: '로딩중입니다. 잠시만 기다려주세요', ai_utilize_audio_listening: '듣고 있어요', upload_error_title: '파일 업로드 안내', upload_error_content: '엔트리 이용정책을 지키지 않는 것으로 의심되는 파일이 제외되었습니다.', monthly_intro_0: '<월간 엔트리>는 소프트웨어 교육에 익숙하지 않은 선생님들도 쉽고 재미있게 소프트웨어 교육을 하실 수 있도록 만들어진 ', monthly_intro_1: 'SW교육 잡지입니다. 재미있는 학습만화와 함께 하는 SW 교육 컨텐츠를 만나보세요!', monthly_title_0: '강아지 산책시키기 / 선대칭 도형 그리기', monthly_title_1: '동영상의 원리 / 음악플레이어 만들기', monthly_title_2: '대한민국 지도 퍼즐 / 벚꽃 애니메이션', monthly_title_3: '마우스 졸졸, 물고기 떼 / 태양계 행성', monthly_title_4: '감자 캐기 / 딸기 우유의 진하기', monthly_description_0: '키보드 입력에 따라 움직이는 강아지와 신호와 좌표를 통해 도형을 그리는 작품을 만들어 봅시다.', monthly_description_1: '변수를 활용하여 사진 영상 작품과 음악 플레이어 작품을 만들어 봅시다.', monthly_description_2: '~인 동안 반복하기를 이용한 퍼즐 게임과 복제본, 무작위 수를 이용한 애니메이션 작품을 만들어 봅시다.', monthly_description_3: '계속 반복하기 블록과 수학 연산 블록을 활용하여 물고기 미디어 아트 작품과 태양계를 만들어 봅시다.', monthly_description_4: '신호와 변수, 수학 연산 블록을 활용하여 감자 캐기 작품과 딸기 우유 만들기 작품을 만들어 봅시다.', save_canvas_alert: '저장 중입니다.', feedback_too_many_post: '신고하신 내용이 전송되고 있습니다. 10초 뒤에 다시 시도해주세요.', feedback_duplicated: '이미 신고하였습니다.', usable_object: '사용가능 오브젝트', shared_varaible: '공유 변수', invalid_url: '영상 주소를 다시 확인해 주세요.', auth_only: '인증된 사용자만 이용이 가능합니다.', runtime_error: '실행 오류', to_be_continue: '준비 중입니다.', warn: '경고', error_occured: "다시 한번 시도해 주세요. 만약 같은 문제가 다시 발생 하면 '제안 및 건의' 게시판에 문의 바랍니다. ", error_forbidden: '로그아웃 상태라 저장을 할 수 없습니다.\n만약 로그인했다면 다른 창에서 로그아웃 했는지 확인해 주세요.\n로그인 확인 후 저장이 안 된다면 ‘제안 및 건의’ 게시판에 문의 하세요.', list_can_not_space: '리스트의 이름은 빈 칸이 될 수 없습니다.', sign_can_not_space: '신호의 이름은 빈 칸이 될 수 없습니다.', variable_can_not_space: '변수의 이름은 빈 칸이 될 수 없습니다.', training_top_title: '연수 프로그램', training_top_desc: '엔트리 연수 지원 프로그램을 안내해 드립니다.', training_main_title01: '선생님을 위한 강사 연결 프로그램', training_target01: '교육 대상 l 선생님', training_sub_title01: '“우리 교실에 SW날개를 달자”', training_desc01: '소프트웨어(SW) 교원 연수가 필요한 학교인가요?\nSW 교원 연수가 필요한 학교에 SW교육 전문 선생님(고투티처) 또는 전문 강사를 연결해드립니다.', training_etc_ment01: '* 강의비 등 연수 비용은 학교에서 지원해주셔야합니다.', training_main_title02: '소프트웨어(SW) 선도학교로 찾아가는 교원연수', training_target02: '교육 대상 l SW 선도, 연구학교', training_sub_title02: '“찾아가, 나누고, 이어가다”', training_desc02: 'SW 교원 연수를 신청한 선도학교를 무작위로 추첨하여 상반기(4,5,6월)와\n하반기(9,10,11월)에 각 지역의 SW교육 전문 선생님(고투티처)께서 알차고\n재미있는 SW 기초 연수 진행 및 풍부한 교육사례를 공유하기 위해 찾아갑니다.', training_etc_ment02: '', training_main_title03: '학부모와 학생을 위한 연결 프로그램', training_target03: '교육 대상 l 학부모, 학생', training_sub_title03: '“SW를 더 가까이 만나는 시간”', training_desc03: '학부모와 학생들을 대상으로 소프트웨어(SW) 연수가 필요한 학교에 각 지역의 SW교육 전문 선생님(고투티처) 또는 전문 강사를 연결해드립니다.', training_etc_ment03: '* 강의비 등 연수 비용은 학교에서 지원해주셔야합니다.', training_apply: '신청하기', training_ready: '준비중입니다.', new_version_title: '최신 버전 설치 안내', new_version_text1: '하드웨어 연결 프로그램이', new_version_text2: '최신 버전이 아닙니다.', new_version_text3: '서비스를 한층 더 강화해 업데이트 된', new_version_text4: '최신 버전의 연결 프로그램을 설치해 주세요.', new_version_download: "최신 버전 다운로드", not_install_title: '미설치 안내', hw_download_text1: '하드웨어 연결을 위해서', hw_download_text2: '하드웨어 연결 프로그램을 설치해 주세요.', hw_download_text3: '하드웨어 연결 프로그램이 설치되어 있지 않습니다.', hw_download_text4: '최신 버전의 연결 프로그램을 설치해 주세요.', hw_download_btn: "연결 프로그램 다운로드", not_support_browser: '지원하지 않는 브라우저입니다.', quiz_complete1: '퀴즈 풀기 완료!', quiz_complete2: '총 {0}문제 중에 {1}문제를 맞췄습니다.', quiz_incorrect: '이런 다시 한 번 생각해보자', quiz_correct: '정답이야!', hw_connection_success: '하드웨어 연결 성공', hw_connection_success_desc: '하드웨어 아이콘을 더블클릭하면, 센서값만 확인할 수 있습니다.', hw_connection_success_desc2: '작품에서 하드웨어를 사용할 수 있습니다.', hw_connection_termination_title: '하드웨어 연결 해제', hw_connection_termination_desc: '하드웨어와 연결이 해제되었습니다.', hw_connection_failed_title: '하드웨어 연결 실패', hw_connection_failed_desc: '작품에서 사용된 하드웨어가\n연결되어 있는지 확인해 주세요.', ie_page_title: '이 브라우저는
지원하지 않습니다.', ie_page_desc: '엔트리는 인터넷 익스플로러 11 버전 이상 또는 크롬 브라우저에서 이용하실 수 있습니다.
윈도우 업데이트를 진행하시거나, 크롬 브라우저를 설치해주세요.
엔트리 오프라인 버전은 인터넷이 연결되어 있지 않아도 사용할 수 있습니다. 지금 다운받아서 시작해보세요!', ie_page_chrome_download: '크롬 브라우저
다운로드', ie_page_windows_update: '윈도우 최신버전
업데이트', ie_page_offline_32bit_download: '엔트리 오프라인 32bit
다운로드', ie_page_offline_64bit_download: '엔트리 오프라인 64bit
다운로드', ie_page_offline_mac_download: '엔트리 오프라인
다운로드', cancel_deletion_your_account: '$1님의
회원탈퇴 신청을 취소하시겠습니까?', account_deletion_canceled_complete: '회원탈퇴 신청이 취소되었습니다.', journal_henesys_no1_title: '헤네시스 첫번째 모험일지', journal_henesys_no2_title: '헤네시스 두번째 모험일지', journal_henesys_no1_content: '헤네시스에서 첫 번째 모험 일지야. 오늘 헤네시스 터줏대감이라는 대장장이 집에 가려고 점프를 하다가 떨어질 뻔했어. 그 아저씨는 집 마당 앞에 왜 그렇게 구멍을 크게 만들어 놓는 거지? 나같이 대단한 몬스터가 아니고서야 이런 구멍을 뛰어넘을 수 있는 애들은 없을 거 같은데! 여하튼 정보도 얻었으니 아저씨가 추천한 맛 집으로 가볼까?', journal_henesys_no2_content: '진짜 과식했다. 특히 그 식당의 고기는 정말 맛있었어. 어떻게 그렇게 부드럽게 만들었을까! 그렇지만 그 옆집 빵은 별로였어. 보니까 주방장 아저씨가 요리 수련을 한답시고 맨날 놀러 다니는 거 같더라고. 그럴 시간에 빵 하나라도 더 만들어 보는 게 나을 텐데. 후 이제 배도 채웠으니 본격적인 모험을 시작해볼까!', journal_ellinia_no1_title: '엘리니아 첫번째 모험일지', journal_ellinia_no2_title: '엘리니아 두번째 모험일지', journal_ellinia_no1_content: '휴, 모르고 주황버섯을 깔고 앉아버렸지 뭐야. 걔네가 화날만 하지.. 그래도 그렇게 나에게 다같이 몰려들어 공격할 건 뭐람! 정말 무서운 놈들이야. 슬라임들이 힘들어 할만했어. 하지만 이 핑크빈님께서 다 혼내주었으니깐 걱정 없어. 이제 슬라임들이 친구가 되어주었으니 더욱 신나게 멋진 숲으로 모험을 이어가볼까.', journal_ellinia_no2_content: '모험하면서 만난 친구 로얄패어리가 요즘 엘나스에 흉흉한 소문이 돈다고 했는데, 그게 뭘까? 오늘밤에 친구들이랑 집에서 놀기로 했는데 그때 물어봐야겠어. 완전 궁금한걸! 그런데 뭘 입고 가야하나.. 살이 너무쪄서 입을만 한게 없을거같은데.. 뭐 나는 늘 귀여우니까 어떤걸 입고가도 다들 좋아해줄거라구!', journal_elnath_no1_title: '엘나스 첫번째 모험일지', journal_elnath_no2_title: '엘나스 두번째 모험일지', journal_elnath_no1_content: '세상에! 이게 말로만 듣던 눈인가? 내가 사는 마을은 항상 봄이여서 눈은 처음 봤어. 몬스터들을 혼내주느라 제대로 구경을 못했는데 지금보니 온세상이 이렇게나 하얗고 차갑다니 놀라워! 푹신 푹신하고 반짝거리는게 맛있어 보였는데 맛은 특별히 없네. 그런데 왠지 달콤한 초코 시럽을 뿌려먹으면 맛있을 거 같아. 조금 들고가고 싶은데 방법이 없다니 너무 아쉬운걸.', journal_elnath_no2_content: '에퉤퉤, 실수로 석탄가루를 먹어버렸네. 나쁜 몬스터들! 도망가려면 조용히 도망갈 것이지 석탄을 잔뜩 뿌리면서 도망가버렸어. 덕분에 내 윤기나고 포송포송한 핑크색 피부가 갈수록 더러워지고 있잖아. 어서 여기를 나가서 깨끗하게 목욕부터 해야겠어. 아무리 모험이 좋다지만 이렇게 더럽게 돌아다니는 건 이 핑크빈님 자존심이 허락하지 않지.', bug_report_alert_msg: '소중한 의견 감사합니다.', version_update_msg1: '엔트리 오프라인 새 버전(%1)을\n사용하실 수 있습니다.', version_update_msg2: '엔트리 하드웨어 새 버전(%1)을\n사용하실 수 있습니다.', version_update_msg3: '지금 업데이트 하시겠습니까?', select_the_hardware: '수업에 활용할
하드웨어를 선택하세요.', select_hardware_button: '하드웨어 선택하기', select_the_expansion_block: '수업에 활용할 확장 블록을 선택하세요.', select_hardware_not_support_info: '오픈강의에는 하드웨어 블록을 사용할 수 없습니다.', select_hardware_not_support_info2: '조금만 기다려주세요.', select_expansion_block_button: '확장 블록 선택하기', expansion_weather_description: '기온, 강수량, 미세먼지 농도 등 한국의 날씨와 관련된 블록 모음입니다. [웨더아이 제공]', expansion_festival_description: '국내 지역별 다양한 행사 및 축제와 관련된 불록 모음 입니다. [한국관광공사 제공]', expansion_translate_description: '파파고를 이용하여 다른 언어로 번역할 수 있는 블록 모음입니다.', expansion_behaviorConductDisaster_description: '자연재난 발생 시 국민이 지켜야하는 기본적인 행동요령에 대한 블록들의 모음입니다. [국민안전처 제공]', expansion_behaviorConductLifeSafety_description: '생활 속 안전을 위해 국민이 지켜야 하는 행동요령에 대한 블록 모음입니다. [국민안전처 제공]', ai_utilize_tts_description: 'nVoice 음성합성 기술로 다양한 목소리로 문장을 읽는 블록모음 입니다. ', hardware_need_update_title: '업데이트 안내', hardware_need_update_content: '보안 업데이트로 엔트리 웹버전은\n하드웨어 1.9.0 버전 이상만 지원합니다.\n이하 버전일 경우 프로그램을 업데이트 하세요.\n* 업데이트 후 블록이 보이지 않을 경우,\n웹브라우저의 캐시를 지워 주세요.', ai_utilize_audio_description: '마이크를 이용하여 소리와 음성을 감지할 수 있는 블록 모음입니다. (IE/Safari/Firefox 브라우저 미지원)', ai_utilize_video_description: '카메라를 이용하여 움직임과 방향 값, 그리고 촬영되는 객체 등을 인식할 수 있는 블록 모음입니다. (IE/Safari/Firefox 브라우저 미지원)', }; Lang.Users = { auth_failed: '인증에 실패하였습니다', birth_year: '태어난 해', birth_year_before_1990: '1990년 이전', edit_personal: '정보수정', email: '이메일', email_desc: '새 소식이나 정보를 받을 수 있 이메일 주소', email_inuse: '이미 등록된 메일주소 입니다', email_match: '이메일 주소를 올바르게 입력해 주세요', forgot_password: '암호를 잊으셨습니까?', job: '직업', language: '언어', name: '이름', name_desc: '사이트내에서 표현될 이름 또는 별명', name_not_empty: '이름을 반드시 입력하세요', password: '암호', password_desc: '최소 4자이상 영문자와 숫자, 특수문자', password_invalid: '암호가 틀렸습니다', password_long: '암호는 4~20자 사이의 영문자와 숫자, 특수문자로 입력해 주세요', password_required: '암호는 필수입력 항목입니다', project_list: '작품 조회', regist: '가입 완료', rememberme: '자동 로그인', repeat_password: '암호 확인', repeat_password_desc: '암호를 한번더 입력해 주세요', repeat_password_not_match: '암호가 일치하지 않습니다', sex: '성별', signup_required_for_save: '저장을 하려면 로그인이 필요합니다.', username: '아이디', username_desc: '로그인시 사용할 아이디', username_inuse: '이미 사용중인 아이디 입니다', username_long: '아이디는 4~20자 사이의 영문자로 입력해 주세요', username_unknown: '존재하지 않는 사용자 입니다', already_verified: '이미 인증된 메일 주소입니다.', email_address_unavailable: '유효하지 않은 인증 메일입니다.', email_address_invalid_for_idpw: '유효하지 않은 인증 메일입니다.\n [아이디와 비밀번호 찾기] 메일 발송하기를\n 다시 시도해 주세요.', email_address_invalid_for_certification: '유효하지 않은 인증 메일입니다.\n [인증 메일 발송하기]를 다시 시도해 주세요.', verification_complete: '이메일 주소가 인증되었습니다.', reset_password_mail_sent: '비밀번호 재설정 메일이 발송되었습니다. 메일을 확인해주세요.', email_not_verified: '인증되지 않은 이메일 주소입니다. 인증 메일을 발송하여, 먼저 이메일 주소를 인증해주세요.', verification_email_send_complete: '인증 메일이 발송되었습니다. 먼저 메일 주소를 인증해주세요.', email_send_failed: '전송에 실패했습니다. 다시 한번 시도해주세요.', email_not_exist: '등록되지 않은 이메일 주소입니다.', not_valid_email: '올바른 형식의 이메일 주소를 입력해주세요.', }; Lang.Workspace = { picture_rotation: '회전', picture_size: '크기', thickness: '굵기', follow: '따라해보기', SaveWithPicture: '저장되지 않은 그림이 있습니다. 저장하시겠습니까?', RecursiveCallWarningTitle: '함수 호출 제한', RecursiveCallWarningContent: '한 번에 너무 많은 함수가 호출되었습니다. 함수의 호출 횟수를 줄여주세요.', SelectShape: '이동', SelectCut: '자르기', Pencil: '펜', Line: '직선', Rectangle: '사각형', Ellipse: '원', Text: '글상자', Fill: '채우기', Eraser: '지우기', Magnifier: '확대/축소', block_helper: '블록 도움말', new_project: '새 프로젝트', add_object: '오브젝트 추가하기', download_image_name: '엔트리 블록', all: '전체', animal: '동물', arduino_entry: '아두이노 연결 프로그램', arduino_program: '아두이노 프로그램', arduino_sample: '엔트리 연결블록', arduino_driver: '아두이노 드라이버', cannot_add_object: '실행중에는 오브젝트를 추가할 수 없습니다.', cannot_add_picture: '실행중에는 모양을 추가할 수 없습니다.', cannot_add_sound: '실행중에는 소리를 추가할 수 없습니다.', cannot_add_expansion_block: '실행중에는 확장 블럭을 추가할 수 없습니다.', add_object_before_edit: '모양 편집을 위해
오브젝트를 추가해주세요.', add_table_before_edit: '테이블을 추가해주세요.', cannot_edit_click_to_stop: '실행 중에는 수정할 수 없습니다.
클릭하여 정지하기.', cannot_open_private_project: '비공개 작품은 불러올 수 없습니다. 홈으로 이동합니다.', cannot_save_running_project: '실행 중에는 저장할 수 없습니다.', character_gen: '캐릭터 만들기', check_runtime_error: '빨간색으로 표시된 블록을 확인해 주세요.', check_browser_error: 'IE/Safari 에서는 지원하지 않는 블록입니다.', check_microphone_error: '컴퓨터에 마이크가 연결되어있지 않습니다', check_webcam_error: '컴퓨터에 카메라가 연결되어있지 않습니다', context_download: 'PC에 저장', context_duplicate: '복제', context_remove: '삭제', context_rename: '이름 수정', coordinate: '좌표', create_function: '함수 만들기', direction: '이동 방향', drawing: '직접 그리기', enter_list_name: '새로운 리스트의 이름을 입력하세요(10글자 이하)', enter_name: '새로운 이름을 입력하세요', enter_new_message: '새로운 신호의 이름을 입력하세요.', enter_variable_name: '새로운 변수의 이름을 입력하세요(10글자 이하)', family: '엔트리봇 가족', fantasy: '판타지/기타', file_new: '새로 만들기', file_open: '온라인 작품 불러오기', file_upload: '오프라인 작품 불러오기', file_upload_login_check_msg: '오프라인 작품을 불러오기 위해서는 로그인을 해야 합니다.', file_save: '저장하기', file_save_as: '복사본으로 저장하기', file_save_download: '내 컴퓨터에 저장하기', func: '함수', function_create: '함수 만들기', function_add: '함수 추가하기', interface: '인터페이스', landscape: '배경', list: '리스트', list_add_calcel: '리스트 추가 취소', list_add_calcel_msg: '리스트 추가를 취소하였습니다.', list_add_fail: '리스트 추가 실패', list_add_fail_msg1: '같은 이름의 리스트가 이미 존재합니다.', list_add_fail_msg2: '리스트의 이름이 적절하지 않습니다.', list_add_ok: '리스트 추가 완료', list_add_ok_msg: '을(를) 추가하였습니다.', list_create: '리스트 추가하기', list_create_placeholder: '리스트의 이름을 입력해주세요.', list_dup: '같은 이름의 리스트가 이미 존재합니다.', list_newname: '새로운 이름', list_export: '리스트 내보내기', list_import: '리스트 불러오기', list_remove: '리스트 삭제', list_rename: '리스트 이름 변경', list_rename_failed: '리스트 이름 변경 실패', list_rename_ok: '리스트의 이름이 성공적으로 변경 되었습니다.', list_too_long: '리스트의 이름이 너무 깁니다.', message: '신호', message_add_cancel: '신호 추가 취소', message_add_cancel_msg: '신호 추가를 취소하였습니다.', message_add_fail: '신호 추가 실패', message_add_fail_msg: '같은 이름의 신호가 이미 존재합니다.', message_add_ok: '신호 추가 완료', message_add_ok_msg: '을(를) 추가하였습니다.', message_create: '신호 추가하기', message_create_placeholder: '신호의 이름을 입력해주세요.', message_dup: '같은 이름의 신호가 이미 존재합니다.', message_remove: '신호 삭제', message_remove_canceled: '신호 삭제를 취소하였습니다.', message_rename: '신호 이름을 변경하였습니다.', message_rename_failed: '신호 이름 변경 실패', message_rename_ok: '신호의 이름이 성공적으로 변경 되었습니다.', message_too_long: '신호의 이름이 너무 깁니다.', no_message_to_remove: '삭제할 신호가 없습니다', no_use: '사용되지 않음', no_variable_to_remove: '삭제할 변수가 없습니다.', no_variable_to_rename: '변경할 변수가 없습니다.', object_not_found: '블록에서 지정한 오브젝트가 존재하지 않습니다.', object_not_found_for_paste: '붙여넣기 할 오브젝트가 없습니다.', people: '일반 사람들', picture_add: '모양 추가하기', table_add: '테이블 추가하기', draw_new_table: '새로 만들기', plant: '식물', project: '작품', project_copied: '의 사본', PROJECTDEFAULTNAME: ['멋진', '재밌는', '착한', '큰', '대단한', '잘생긴', '행운의'], remove_object: '오브젝트 삭제', remove_object_msg: '(이)가 삭제되었습니다.', removed_msg: '(이)가 성공적으로 삭제 되었습니다.', rotate_method: '회전방식', rotation: '방향', run: '시작하기', saved: '저장완료', saved_msg: '(이)가 저장되었습니다.', save_failed: '저장시 문제가 발생하였습니다. 다시 시도해 주세요.', select_library: '오브젝트 선택', select_sprite: '적용할 스프라이트를 하나 이상 선택하세요.', shape_remove_fail: '모양 삭제 실패', shape_remove_fail_msg: '적어도 하나 이상의 모양이 존재하여야 합니다.', shape_remove_ok: '모양이 삭제 되었습니다. ', shape_remove_ok_msg: '이(가) 삭제 되었습니다.', load_expansion_block: '확장 블록 불러오기', load_ai_utilize_block: 'AI 블록 불러오기', load_ai_utilize_train_block: '모델 학습', select_expansion_block: '확장블록 선택', deselect_expansion_block_warning: '확장블록이 사용중이므로 삭제할 수 없습니다.', deselect_ai_utilize_block_warning: 'AI블록이 사용중이므로 삭제할 수 없습니다.', sound_add: '소리 추가하기', sound_remove_fail: '소리 삭제 실패', sound_remove_ok: '소리 삭제 완료', sound_remove_ok_msg: '이(가) 삭제 되었습니다.', stop: '정지하기', pause: '일시정지', restart: '다시시작', speed: '속도 조절', tab_attribute: '속성', tab_table: '테이블', tab_code: '블록', tab_picture: '모양', tab_sound: '소리', tab_text: '글상자', textbox: '글상자', textbox_edit: '글상자 편집', textbox_input: '글상자의 내용을 입력해주세요.', things: '물건', textcoding_tooltip1: '블록코딩과 엔트리파이선을
선택하여 자유롭게
코딩을 해볼 수 있습니다.', textcoding_tooltip2: '실제 개발 환경과 동일하게
엔트리파이선 모드의 실행 결과를
확인할 수 있습니다.', textcoding_tooltip3: '엔트리파이선에 대한
기본사항이 안내되어 있습니다.
<엔트리파이선 이용안내>를 확인해 주세요!', upload: '파일 올리기', upload_addfile: '파일 올리기', variable: '변수', variable_add_calcel: '변수 추가 취소', variable_add_calcel_msg: '변수 추가를 취소하였습니다.', variable_add_fail: '변수 추가 실패', variable_add_fail_msg1: '같은 이름의 변수가 이미 존재합니다.', variable_add_fail_msg2: '변수의 이름이 적절하지 않습니다.', variable_add_ok: '변수 추가 완료', variable_add_ok_msg: '을(를) 추가하였습니다.', variable_create: '변수 만들기', variable_add: '변수 추가하기', variable_dup: '같은 이름의 변수가 이미 존재합니다.', variable_newname: '새로운 이름', variable_remove: '변수 삭제', variable_remove_canceled: '변수 삭제를 취소하였습니다.', variable_rename: '변수 이름을 변경합니다. ', variable_rename_failed: '변수 이름 변경에 실패하였습니다. ', variable_rename_msg: "'변수의 이름이 성공적으로 변경 되었습니다.'", variable_rename_ok: '변수의 이름이 성공적으로 변경 되었습니다.', variable_select: '변수를 선택하세요', variable_too_long: '변수의 이름이 너무 깁니다.', open_analizy_data_import: '데이터 화면 열기', vehicle: '탈것', add_object_alert_msg: '오브젝트를 추가해주세요', add_object_alert: '경고', create_variable_block: '변수 만들기', create_list_block: '리스트 만들기', Variable_Timer: '초시계', Variable_placeholder_name: '변수 이름', Message_placeholder_name: '신호 이름', Variable_property: '변수 속성', Variable_placeholder_content: '변수의 이름을 입력해주세요.', Variable_use_all_objects: '모든 오브젝트에서 사용', Variable_use_this_object: '이 오브젝트에서 사용', Variable_used_at_all_objects: '모든 오브젝트에서 사용되는 변수', variable_create_normal: '일반 변수로 사용\n(작품에 저장)', variable_create_cloud: '공유 변수로 사용\n(서버에 저장)', variable_create_real_time: '실시간 변수로 사용\n(서버에 저장)', Variable_used_at_special_object: '특정 오브젝트에서만 사용되는 변수', Variable_used_objects: '사용된 오브젝트', draw_new: '새로 그리기', draw_new_ebs: '직접 그리기', painter_file: '파일 ▼', painter_file_save: '저장하기', painter_file_saveas: '새 모양으로 저장', new_picture: '새그림', painter_edit: '편집 ▼', get_file: '가져오기', copy_file: '복사하기', cut_picture: '자르기', paste_picture: '붙이기', remove_all: '모두 지우기', flip_horizontal: '좌우뒤집기', flip_vertical: '상하뒤집기', regular: '보통', bold: '굵게', font_underline: '밑줄', font_tilt: '기울임', font_cancel: '취소선', font_color: '글꼴 색상', font_fill: '채우기 색상', font_family: '글꼴', align_left: '왼쪽 정렬', align_center: '가운데 정렬', align_right: '오른쪽 정렬', italic: '기울임', textStyle: '글자', add_picture: '모양 추가', select_picture: '모양 선택', select_table: '테이블 선택', select_sound: '소리 선택', Size: '크기', show_variable: '변수 노출', default_value: '기본값 ', slide: '슬라이드', min_value: '최솟값', max_value: '최댓값', number_of_list: '리스트 항목 수', empty_of_list: '추가된 항목이 없습니다', use_all_objects: '모든 오브젝트에 사용', list_name: '리스트 이름', list_property: '리스트 속성', list_used_specific_objects: '특정 오브젝트에서만 사용되는 리스트', List_used_all_objects: '모든 오브젝트에서 사용되는 리스트', List_used_objects: '사용된 오브젝트', Scene_delete_error: '장면은 최소 하나 이상 존재해야 합니다.', Scene_add_error: '장면은 최대 20개까지 추가 가능합니다.', replica_of_object: '의 복제본', will_you_delete_scene: '장면은 한번 삭제하면 취소가 불가능 합니다. \n정말 삭제 하시겠습니까?', will_you_delete_function: '함수는 한번 삭제하면 취소가 불가능 합니다. \n정말 삭제 하시겠습니까?', duplicate_scene: '복제하기', block_explain: '블록 설명 ', block_intro: '블록을 클릭하면 블록에 대한 설명이 나타납니다.', blocks_reference: '블록 설명', hardware_guide: '하드웨어 연결 안내', robot_guide: '로봇 연결 안내', python_guide: '엔트리파이선 이용 안내', show_list_workspace: '리스트 노출', list_create_normal: '일반 리스트로 사용\n(작품에 저장)', list_create_cloud: '공유 리스트로 사용 \n(서버에 저장)', list_create_real_time: '실시간 리스트로 사용\n(서버에 저장)', confirm_quit: '바꾼 내용을 저장하지 않았습니다.', confirm_load_temporary: '저장되지 않은 작품이 있습니다. 여시겠습니까?', login_to_save: '로그인후에 저장 바랍니다.', cannot_save_in_edit_func: '함수 편집중에는 저장할 수 없습니다.', new_object: '새 오브젝트', arduino_connect: '하드웨어 연결', arduino_connect_success: '하드웨어가 연결되었습니다.', confirm_load_header: '작품 복구', uploading_msg: '업로드 중입니다', upload_fail_msg: '업로드에 실패하였습니다.
다시 한번 시도해주세요.', upload_not_supported_msg: '지원하지 않는 형식입니다.', upload_not_supported_file_msg: '지원하지 않는 형식의 파일입니다.', file_converting_msg: '파일 변환 중입니다.', file_converting_fail_msg: '파일 변환에 실패하였습니다.', fail_contact_msg: '문제가 계속된다면
entry@connect.or.kr 로 문의해주세요.', saving_msg: '저장 중입니다', saving_fail_msg: '저장에 실패하였습니다.
다시 한번 시도해주세요.', loading_msg: '불러오는 중입니다', loading_fail_msg: '불러오기에 실패하였습니다.
다시 한번 시도해주세요.', restore_project_msg: '정상적으로 저장되지 않은 작품이 있습니다. 해당 작품을 복구하시겠습니까?', quit_stop_msg: '저장 중에는 종료하실 수 없습니다.', ent_drag_and_drop: '업로드 하려면 파일을 놓으세요', not_supported_file_msg: '지원하지 않은 형식의 파일입니다.', broken_file_msg: '파일이 깨졌거나 잘못된 파일을 불러왔습니다.', check_audio_msg: 'mp3 외 오디오 파일은 재생할 수 없습니다.', check_entry_file_msg: 'ENT 파일만 불러오기가 가능합니다.', hardware_version_alert_text: '5월 30일 부터 구버전의 연결프로그램의 사용이 중단 됩니다.\n하드웨어 연결 프로그램을 최신 버전으로 업데이트 해주시기 바랍니다.', variable_name_auto_edited_title: '변수 이름 자동 변경', variable_name_auto_edited_content: '변수의 이름은 10글자를 넘을 수 없습니다.', list_name_auto_edited_title: '리스트 이름 자동 변경', list_name_auto_edited_content: '리스트의 이름은 10글자를 넘을 수 없습니다.', cloned_scene: '복제본_', default_mode: '기본형', practical_course_mode: '교과형', practical_course: '실과', select_mode: '모드선택', select_mode_popup_title: '엔트리 만들기 환경을 선택해 주세요.', select_mode_popup_lable1: '기본형', select_mode_popup_lable2: '교과형', select_mode_popup_desc1: '엔트리의 모든 기능을 이용하여
자유롭게 작품을 만듭니다.', select_mode_popup_desc2: '실과 교과서에 등장하는 기능만을
이용하여 작품을 만듭니다.', practical_course_notice: '안내', practical_course_desc: "교과용 만들기
실과 교과서로 소프트웨어를 배울 때
필요한 기능만을 제공합니다.", practical_course_desc2: '*기본형 작품 만들기를 이용하면 더 많은 기능을
이용해 작품을 만들 수 있습니다.', practical_course_tooltip: '모든 기능을 이용하기 위해서는
기본형을 선택해 주세요.', name_already_exists: '이름이 중복 되었습니다.', enter_the_name: '이름을 입력하여 주세요.', object_not_exist_error: '오브젝트가 존재하지 않습니다. 오브젝트를 추가한 후 시도해주세요.', workspace_tutorial_popup_desc: "작품 만들기
창의적인 작품을 만들 수 있도록
다양한 블록과 기능을 제공합니다.", start_guide_tutorial: '만들기 이용 안내', language: '언어 선택', file: '파일', save: '저장하기', help: '도움말', print: '인쇄', undo: '입력 취소', redo: '다시 실행', workspace_title_tooltip: '기본작품명이 변경되었습니다.\n작품을 만든 날짜를 통해 어떤 작품인지 쉽게 알 수 있습니다.', workspace_object_tooltip: '오브젝트의 순서는 오브젝트의 대표 이미지를 잡고\n위아래로 이동하여 변경할 수 있습니다.\n(모양과 소리탭에서도 동일하게 동작합니다.)', workspace_comment_tooltip: '조립소에 추가한 메모를\n한꺼번에 숨기거나 보이게 할 수 있습니다.', workspace_zoom_tooltip: '조립소에 추가된 블록의 크기를 바꿀 수 있습니다.\n가운데 = 아이콘을 누르면 기본 크기로 돌아옵니다.', workspace_image_tooltip: '새로워진\n작품 만들기를\n소개합니다.', playground_block_drop: '나의 보관함의 블록을\n조립소에 추가합니다.', container_object_drop: '나의 보관함의 오브젝트를\n오브젝트 리스트에 추가합니다.', my_storage_block_drop: '블록을\n나의 보관함에\n추가합니다.', my_storage_object_drop: '오브젝트를\n나의 보관함에\n추가합니다.', my_storage: '나의 보관함', my_block: '나의 블록', red: '빨강(R)', green: '녹색(G)', blue: '파랑(B)', hue: '색상', saturation: '채도', brightness: '명도', spoid: '스포이드', palette_mode: '팔레트 모드', slider_mode: '슬라이더 모드', toast_error_title_object_center: '주의', toast_error_contents_object_center: '오브젝트 중심점이 오브젝트와 멀리 떨어져 실행화면 밖으로 벗어날 경우, 원위치로 돌아옵니다.', blocks_comming_soon: '열심히 연구 중입니다.\n조금만 기다려 주세요!', data_table: '테이블', select_all: '모두', now_loading_msg: '로딩 중입니다.\n잠시만 기다려주세요.', }; Lang.code = '코드보기'; Lang.EntryStatic = { event100: '이벤트', groupProject: '학급 공유하기', usage_parallel: '병렬', usage_expansion: '확장', usage_hw: '하드웨어', usage_sequence: '순차', privateProject: '나만보기', privateCurriculum: '나만보기', publicCurriculum: '강의 모음 공유하기', publicProject: '작품 공유하기', group: '학급 공유하기', groupCurriculum: '학급 공유하기', private: '나만보기', public: '강의 공유하기', lecture_is_open_true: '공개', lecture_is_open_false: '비공개', category_all: '모든 작품', category_game: '게임', category_animation: '애니메이션', category_media_art: '미디어 아트', category_physical: '피지컬', category_etc: '기타', category_category_game: '게임', category_category_animation: '애니메이션', category_category_media_art: '미디어 아트', category_category_physical: '피지컬', category_category_etc: '기타', sort_created: '최신순', sort_updated: '최신순', sort_visit: '조회순', sort_likeCnt: '좋아요순', sort_comment: '댓글순', period_all: '전체기간', period_1: '오늘', period_7: '최근 1주일', period_30: '최근 1개월', period_90: '최근 3개월', lecture_required_time_1: ' ~ 15분', lecture_required_time_2: '15분 ~ 30분', lecture_required_time_3: '30분 ~ 45분', lecture_required_time_4: '45 분 ~ 60분', lecture_required_time_5: '1시간 이상', usage_event: '이벤트', usage_signal: '신호보내기', usage_scene: '장면', usage_repeat: '반복', usage_condition_repeat: '조건반복', usage_condition: '선택', usage_clone: '복제본', usage_rotation: '회전', usage_coordinate: '좌표이동', usage_arrow_move: '화살표이동', usage_shape: '모양', usage_speak: '말하기', usage_picture_effect: '그림효과', usage_textBox: '글상자', usage_draw: '그리기', usage_sound: '소리', usage_confirm: '판단', usage_comp_operation: '비교연산', usage_logical_operation: '논리연산', usage_math_operation: '수리연산', usage_random: '무작위수', usage_timer: '초시계', usage_variable: '변수', usage_list: '리스트', usage_ask_answer: '입출력', usage_function: '함수', usage_arduino: '아두이노', concept_resource_analytics: '자료수집/분석/표현', concept_procedual: '알고리즘과 절차', concept_abstractive: '추상화', concept_individual: '문제분해', concept_automation: '자동화', concept_simulation: '시뮬레이션', concept_parallel: '병렬화', subject_korean: '국어', subject_english: '영어', subject_mathmatics: '수학', subject_social: '사회', subject_science: '과학', subject_music: '음악', subject_paint: '미술', subject_athletic: '체육', subject_courtesy: '도덕', subject_progmatic: '실과', lecture_grade_1: '초1', lecture_grade_2: '초2', lecture_grade_3: '초3', lecture_grade_4: '초4', lecture_grade_5: '초5', lecture_grade_6: '초6', lecture_grade_7: '중1', lecture_grade_8: '중2', lecture_grade_9: '중3', lecture_grade_10: '일반', lecture_level_1: '쉬움', lecture_level_2: '중간', lecture_level_3: '어려움', listEnable: '리스트', functionEnable: '함수', messageEnable: '신호', objectEditable: '오브젝트', pictureeditable: '모양', sceneEditable: '장면', soundeditable: '소리', variableEnable: '변수', e_1: '초등 1학년', e_2: '초등 2학년', e_3: '초등 3학년', e_4: '초등 4학년', e_5: '초등 5학년', e_6: '초등 6학년', m_1: '중등 1학년', m_2: '중등 2학년', m_3: '중등 3학년', general: '일반', curriculum_is_open_true: '공개', curriculum_open_false: '비공개', contest2019: '공모전', exhibit: '공모전', notice: '공지사항', qna: '묻고답하기', tips: '노하우&팁', free: '엔트리 이야기', report: '제안 및 건의', art_category_all: '모든 작품', art_category_game: '게임', art_category_animation: '애니메이션', art_category_physical: '피지컬', art_category_etc: '기타', art_category_media: '미디어 아트', art_sort_updated: '최신순', art_sort_visit: '조회순', art_sort_likeCnt: '좋아요순', art_sort_comment: '댓글순', art_period_all: '전체기간', art_period_day: '오늘', art_period_week: '최근 1주일', art_period_month: '최근 1개월', art_period_three_month: '최근 3개월', level_high: '상', level_mid: '중', level_row: '하', discuss_sort_created: '최신순', discuss_sort_visit: '조회순', discuss_sort_likesLength: '좋아요순', discuss_sort_commentsLength: '댓글순', discuss_period_all: '전체기간', discuss_period_day: '오늘', discuss_period_week: '최근 1주일', discuss_period_month: '최근 1개월', discuss_period_three_month: '최근 3개월', }; Lang.Helper = { when_run_button_click: '시작하기 버튼을 클릭하면 아래에 연결된 블록들을 실행합니다.', when_some_key_pressed: '선택한 키를 누르면 아래에 연결된 블록들을 실행합니다.', mouse_clicked: '마우스를 클릭했을 때 아래에 연결된 블록들을 실행합니다.', mouse_click_cancled: '마우스 클릭을 해제했을 때 아래에 연결된 블록들을 실행합니다.', when_object_click: '오브젝트를 클릭했을 때 아래에 연결된 블록들을 실행합니다.', when_object_click_canceled: '오브젝트 클릭을 해제했을 때 아래에 연결된 블록들을 실행합니다.', when_message_cast: '선택한 신호를 받으면 아래에 연결된 블록들을 실행합니다.', message_cast: '선택한 신호를 보냅니다.', message_cast_wait: '선택한 신호를 보내고, 해당 신호를 받는 블록들의 실행이 끝날 때 까지 기다립니다.', when_scene_start: '장면이 시작되면 아래에 연결된 블록들을 실행합니다. ', start_scene: '선택한 장면을 시작합니다.', start_neighbor_scene: '이전 또는 다음 장면을 시작합니다.', wait_second: '입력한 시간만큼 기다린 후 다음 블록을 실행합니다.', repeat_basic: '입력한 횟수만큼 감싸고 있는 블록들을 반복 실행합니다.', repeat_inf: '감싸고 있는 블록들을 계속해서 반복 실행합니다.', repeat_while_true: '판단값에 따라 블록의 반복여부를 결정합니다.\n이 될 때까지: 판단이 참이 될 때까지 감싸고 있는 블록들을 반복 실행합니다.\n인 동안: 판단이 참인 동안 감싸고 있는 블록들을 반복 실행합니다.', stop_repeat: '이 블록을 감싸는 가장 가까운 반복 블록의 반복을 중단합니다.', _if: '만일 판단이 참이라면, 감싸고 있는 블록들을 실행합니다.', if_else: '만일 판단이 참이라면 첫 번째 감싸고 있는 블록들을 실행하고, 거짓이면 두 번째 감싸고 있는 블록들을 실행합니다.', restart_project: '작품을 처음부터 다시 실행합니다.', stop_object: '블록이 실행을 멈춥니다. 현재 실행중인 동작을 멈추는 블록이며, 프로그램을 종료하지 않습니다.\n모든 : 작품의 모든 블록이 실행을 멈춥니다. \n자신 : 해당 오브젝트의 모든 블록이 실행을 멈춥니다.\n이 코드 : 이 블록이 포함된 블록들이 실행을 멈춥니다.\n자신의 다른 코드 : 해당 오브젝트 중 이 블록이 포함된 블록들을 제외한 모든 블록이 실행을 멈춥니다.\n다른 오브젝트의 : 다른 오브젝트의 모든 블록이 실행을 멈춥니다.', wait_until_true: '판단이 참이 될 때까지 실행을 멈추고 기다립니다.', when_clone_start: '해당 오브젝트의 복제본이 새로 생성되었을 때 아래에 연결된 블록들을 실행합니다.', create_clone: '선택한 오브젝트의 복제본을 생성합니다.', delete_clone: '‘복제본이 처음 생성되었을 때’ 블록과 함께 사용되며, 연결된 블록들이 실행되고 있는 복제본을 삭제합니다.', remove_all_clones: '해당 오브젝트의 모든 복제본을 삭제합니다.', move_direction: '입력한 값만큼 오브젝트의 이동 방향 화살표가 가리키는 방향으로 움직입니다.', move_x: '오브젝트의 x 좌표를 입력한 값만큼 바꿉니다. ', move_y: '오브젝트의 y 좌표를 입력한 값만큼 바꿉니다.', move_xy_time: '오브젝트가 입력한 시간에 걸쳐 x와 y 좌표를 입력한 값만큼 바꿉니다.', locate_object_time: '오브젝트가 입력한 시간에 걸쳐 선택한 오브젝트 또는 마우스 포인터의 위치로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_x: '오브젝트가 입력한 x 좌표로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_y: '오브젝트가 입력한 y 좌표로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_xy: '오브젝트가 입력한 x와 y 좌표로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_xy_time: '오브젝트가 입력한 시간에 걸쳐 입력한 x와 y 좌표로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate: '오브젝트가 선택한 오브젝트 또는 마우스 포인터의 위치로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', rotate_absolute: '오브젝트의 방향을 입력한 각도로 정합니다.', rotate_by_time: '오브젝트의 방향이 입력한 시간에 걸쳐 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', rotate_relative: '오브젝트의 방향이 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', direction_absolute: '오브젝트의 이동 방향을 입력한 각도로 정합니다.', direction_relative: '오브젝트의 이동 방향이 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', move_to_angle: '오브젝트가 입력한 각도 방향으로 입력한 값만큼 움직입니다. (실행화면 위쪽이 0도를 나타내며, 시계방향으로 갈수록 각도가 증가합니다.)', see_angle_object: '해당 오브젝트가 방향을 회전하여 선택한 오브젝트 또는 마우스 포인터 쪽을 바라봅니다. ', bounce_wall: '오브젝트가 실행화면 끝에 닿으면 튕겨 나옵니다.', show: '오브젝트를 실행화면에 보이게 합니다.', hide: '오브젝트를 실행화면에 보이지 않게 합니다.', dialog_time: '오브젝트가 입력한 내용을 입력한 시간 동안 말풍선으로 말한 후 다음 블록을 실행합니다.', dialog: '오브젝트가 입력한 내용을 말풍선으로 말하는 동시에 다음 블록을 실행합니다.', remove_dialog: '오브젝트가 말하고 있는 말풍선을 지웁니다.', change_to_some_shape: '오브젝트를 선택한 모양으로 바꿉니다. (내부 블록을 분리하고 모양의 번호를 입력하여 모양을 바꿀 수 있습니다.)', change_to_next_shape: '오브젝트의 모양을 이전 또는 다음 모양으로 바꿉니다.', set_effect_volume: '오브젝트에 선택한 효과를 입력한 값만큼 줍니다.', set_effect_amount: '오브젝트에 선택한 효과를 입력한 값만큼 줍니다.', set_effect: '오브젝트의 효과를 입력한 값으로 정합니다.\n색깔 : 0~100을 주기로 반복됩니다.\n밝기 : -100~100 사이의 범위로 설정할 수 있습니다. (-100 이하는 -100으로 100 이상은 100으로 처리됩니다.)\n투명도 : 0~100 사이의 범위로 설정할 수 있습니다. (0 이하는 0으로, 100 이상은 100으로 처리됩니다.)', set_entity_effect: '오브젝트의 효과를 입력한 값으로 정합니다.\n색깔 : 0~100을 주기로 반복됩니다.\n밝기 : -100~100 사이의 범위로 설정할 수 있습니다. (-100 이하는 -100으로 100 이상은 100으로 처리됩니다.)\n투명도 : 0~100 사이의 범위로 설정할 수 있습니다. (0 이하는 0으로, 100 이상은 100으로 처리됩니다.)', add_effect_amount: '오브젝트에 선택한 효과를 입력한 값만큼 줍니다.', change_effect_amount: '오브젝트의 효과를 입력한 값으로 정합니다.\n색깔 : 0~100을 주기로 반복됩니다.\n밝기 : -100~100 사이의 범위로 설정할 수 있습니다. (-100 이하는 -100으로 100 이상은 100으로 처리됩니다.)\n투명도 : 0~100 사이의 범위로 설정할 수 있습니다. (0 이하는 0으로, 100 이상은 100으로 처리됩니다.)', change_scale_percent: '오브젝트의 크기를 입력한 값만큼 바꿉니다.', set_scale_percent: '오브젝트의 크기를 입력한 값으로 정합니다.', change_scale_size: '오브젝트의 크기를 입력한 값만큼 바꿉니다.', set_scale_size: '오브젝트의 크기를 입력한 값으로 정합니다.', flip_x: '오브젝트의 상하 모양을 뒤집습니다.', flip_y: '오브젝트의 좌우 모양을 뒤집습니다.', change_object_index: '오브젝트가 실행화면에 보이는 순서를 변경합니다.\n맨 앞으로 : 해당 오브젝트를 실행화면의 가장 앞쪽으로 가져옵니다. \n앞으로 : 해당 오브젝트를 한 층 앞쪽으로 가져옵니다.\n뒤로 : 해당 오브젝트를 한 층 뒤쪽으로 보냅니다. \n맨 뒤로 : 해당 오브젝트를 실행화면의 가장 뒤쪽으로 보냅니다.', set_object_order: '해당 오브젝트가 설정한 순서로 올라옵니다.', brush_stamp: '오브젝트의 모양을 도장처럼 실행화면 위에 찍습니다.', start_drawing: '오브젝트가 이동하는 경로를 따라 선이 그리기 시작합니다. (오브젝트의 중심점이 기준이 됩니다.)', stop_drawing: '오브젝트가 선 그리는 것을 멈춥니다.', set_color: '오브젝트가 그리는 선의 색을 선택한 색으로 정합니다.', set_random_color: '오브젝트가 그리는 선의 색을 무작위로 정합니다. ', change_thickness: '오브젝트가 그리는 선의 굵기를 입력한 값만큼 바꿉니다.', set_thickness: '오브젝트가 그리는 선의 굵기를 입력한 값으로 정합니다. 1~무한의 범위로 설정할 수 있습니다. (1 이하는 1로 처리합니다.)', change_opacity: '해당 오브젝트가 그리는 붓의 투명도를 입력한 값만큼 바꿉니다.', change_brush_transparency: '해당 오브젝트가 그리는 붓의 투명도를 입력한 값만큼 바꿉니다.', set_opacity: '해당 오브젝트가 그리는 붓의 투명도를 입력한 값으로 정합니다. 0~100의 범위로 설정할 수 있습니다. (0 이하는 0, 100 이상은 100으로 처리합니다.)', set_brush_tranparency: '해당 오브젝트가 그리는 붓의 투명도를 입력한 값으로 정합니다. 0~100의 범위로 설정할 수 있습니다. (0 이하는 0, 100 이상은 100으로 처리합니다.)', brush_erase_all: '해당 오브젝트가 그린 선과 도장을 모두 지웁니다.', sound_something_with_block: '해당 오브젝트가 선택한 소리를 재생하는 동시에 다음 블록을 실행합니다.', sound_something_second_with_block: '해당 오브젝트가 선택한 소리를 입력한 시간 만큼 재생하는 동시에 다음 블록을 실행합니다.', sound_something_wait_with_block: '해당 오브젝트가 선택한 소리를 재생한 후 다음 블록을 실행합니다.', sound_something_second_wait_with_block: '해당 오브젝트가 선택한 소리를 입력한 시간 만큼 재생한 후 다음 블록을 실행합니다.', sound_volume_change: '작품에서 재생되는 모든 소리의 크기를 입력한 값만큼 바꿉니다.', sound_volume_set: '작품에서 재생되는 모든 소리의 크기를 입력한 값으로 정합니다.', sound_silent_all: '재생 중인 모든 소리를 멈춥니다.', is_clicked: '마우스를 클릭한 경우 ‘참’으로 판단합니다.', is_object_clicked: '오브젝트를 클릭한 경우 ‘참’으로 판단합니다.', is_press_some_key: '선택한 키가 눌려져 있는 경우 ‘참’으로 판단합니다.', reach_something: '해당 오브젝트가 선택한 항목과 닿은 경우 ‘참’으로 판단합니다.', is_type: '입력한 값이 숫자라면 ‘참’으로 판단합니다.', is_included_in_list: "선택한 리스트가 입력한 값을 가진 항목을 포함하는 경우 '참'으로 판단합니다.", boolean_basic_operator: "입력한 두 값을 비교합니다.\n= : 왼쪽에 위치한 값과 오른쪽에 위치한 값이 같은 경우 '참'으로 판단합니다.\n> : 왼쪽에 위치한 값이 오른쪽에 위치한 값보다 큰 경우 '참'으로 판단합니다.\n< : 왼쪽에 위치한 값이 오른쪽에 위치한 값보다 작은 경우 '참'으로 판단합니다.\n≥ : 왼쪽에 위치한 값이 오른쪽에 위치한 값보다 크거나 같은 경우 '참'으로 판단합니다.\n≤ : 왼쪽에 위치한 값이 오른쪽에 위치한 값보다 작거나 같은 경우 '참'으로 판단합니다.", function_create: '자주 쓰는 코드를 이 블록 아래에 조립하여 함수로 만듭니다. [함수 정의하기]의 오른쪽 빈칸에 [이름]을 조립하여 함수의 이름을 정할 수 있습니다. 함수를 실행하는 데 입력값이 필요한 경우 빈칸에 [문자/숫자값], [판단값]을 조립하여 매개변수로 사용합니다.', function_field_label: "함수 정의하기' 블록 안에 조립하며, 함수의 이름을 정합니다. ", function_field_string: "함수 정의하기' 블록 안에 조립하며, 입력한 문자/숫자값(매개변수)에 따라 함수의 실행 결과가 달라집니다. 이 블록을 분리하여 함수의 코드 중 필요한 부분에 넣어 사용합니다.", function_field_boolean: "함수 정의하기' 블록 안에 조립하며, 참 또는 거짓의 판단값에 따라 함수의 실행 결과가 달라집니다. 이 블록을 분리하여 함수의 코드 중 필요한 부분에 넣어 사용합니다.", function_general: '현재 만들고 있는 함수 블록 또는 지금까지 만들어 둔 함수 블록입니다.', boolean_and: '두 판단이 모두 참인 경우 ‘참’으로 판단합니다.', boolean_or: '두 판단 중 하나라도 참이 있는 경우 ‘참’으로 판단합니다.', boolean_not: '해당 판단이 참이면 거짓, 거짓이면 참으로 만듭니다.', calc_basic: '입력한 두 수의 사칙연산 값입니다.\n+ : 입력한 두 수를 더한 값입니다.\n- : 입력한 두 수를 뺀 값입니다.\n* : 입력한 두 수를 곱한 값입니다.\n/ : 입력한 두 수를 나눈 값입니다.', calc_rand: '입력한 두 수 사이에서 선택된 무작위 수 값입니다. (두 수 모두 정수를 입력한 경우 정수가, 두 수 중 하나라도 소수를 입력한 경우 소숫점 둘째 자리의 소수 값이 선택됩니다.)', get_x_coordinate: '해당 오브젝트의 x 좌푯값을 의미합니다.', get_y_coordinate: '해당 오브젝트의 y 좌푯값을 의미합니다.', coordinate_mouse: '마우스 포인터의 x 또는 y 좌푯값입니다.', coordinate_object: '선택한 오브젝트의 각종 정보 값입니다. (x 좌표, y 좌표, 방향, 이동방향, 크기, 모양번호, 모양이름)', quotient_and_mod: '입력된 두 수를 나눈 결괏값입니다.\n몫 : 앞의 수에서 뒤의 수를 나누어 생긴 몫의 값입니다. \n나머지 : 앞의 수에서 뒤의 수를 나누어 생긴 나머지 값입니다.', get_rotation_direction: '해당 오브젝트의 방향값, 이동 방향값을 의미합니다.', calc_share: '앞 수에서 뒤 수를 나누어 생긴 몫을 의미합니다.', calc_mod: '앞 수에서 뒤 수를 나누어 생긴 나머지를 의미합니다.', calc_operation: '입력한 수에 대한 다양한 수학식의 계산값입니다. (제곱, 루트, 사인값, 코사인값, 탄젠트값, 아크사인값, 아크코사인값, 아크탄젠트값, 로그값, 자연로그값, 소수점 부분, 소수점 버림값, 소수점 올림값, 소수점 반올림값, 펙토리얼값, 절대값)', get_date: '현재 연도, 월, 일, 요일, 시각과 같이 시간에 대한 값입니다.', distance_something: '해당 오브젝트와 선택한 오브젝트 또는 마우스 포인터 간의 거릿값입니다.', get_sound_duration: '선택한 소리의 길이(초) 값입니다.', get_user_name: '작품을 실행하고 있는 사용자의 이름값입니다.', get_project_timer_value: '이 블록이 실행되는 순간 초시계에 저장된 값입니다.', choose_project_timer_action: '초시계의 상태를 결정합니다.\n시작하기: 초시계를 시작합니다. \n정지하기: 초시계를 정지합니다. \n초기화하기: 초시계의 값을 0으로 초기화합니다. ', reset_project_timer: '실행되고 있던 타이머를 0으로 초기화합니다.', set_visible_project_timer: '초시계 창을 실행화면에서 숨기거나 보이게 합니다.', ask_and_wait: '오브젝트가 입력한 문자를 말풍선으로 묻고, 대답을 입력받습니다. (이 블록이 실행되면 실행화면에 ‘대답 창’이 생성됩니다.)', get_canvas_input_value: "사용자가 '대답 창'에 입력한 값입니다.", set_visible_answer: "대답 창'을 실행화면에서 숨기거나 보이게 합니다.", combine_something: '입력한 두 값을 결합한 값입니다.', reverse_of_string: '입력한 값을 뒤집은 값입니다.', get_variable: '선택한 변수에 저장된 값입니다.', change_variable: '선택한 변수에 입력한 값을 더합니다.', set_variable: '선택한 변수의 값을 입력한 값으로 정합니다.', robotis_carCont_sensor_value: '왼쪽 접속 센서 : 접촉(1), 비접촉(0) 값 입니다.
오른쪽 접촉 센서 : 접촉(1), 비접촉(0) 값 입니다.
선택 버튼 상태 : 접촉(1), 비접촉(0) 값 입니다.
최종 소리 감지 횟수 : 마지막 실시간 소리 감지 횟수 값 입니다.
실시간 소리 감지 횟수 : 약 1초 안에 다음 소리가 감지되면 1씩 증가합니다.
왼쪽 적외선 센서 : 물체와 가까울 수록 큰 값 입니다.
오른쪽 적외선 센서 : 물체와 가까울 수록 큰 값 값 입니다.
왼쪽 적외선 센서 캘리브레이션 값 : 적외선 센서의 캘리브레이션 값 입니다.
오른쪽 적외선 센서 캘리브레이션 값 : 적외선 센서의 캘리브레이션 값 입니다.
(*캘리브레이션 값 - 적외선센서 조정 값)', robotis_carCont_cm_led: '4개의 LED 중 1번 또는 4번 LED 를 켜거나 끕니다.
LED 2번과 3번은 동작 지원하지 않습니다.', robotis_carCont_cm_sound_detected_clear: '최종 소리 감지횟 수를 0 으로 초기화 합니다.', robotis_carCont_aux_motor_speed: '감속모터 속도를 0 ~ 1023 의 값(으)로 정합니다.', robotis_carCont_cm_calibration: '적외선센서 조정 값(http://support.robotis.com/ko/: 자동차로봇> 2. B. 적외선 값 조정)을 직접 정합니다.', robotis_openCM70_sensor_value: '최종 소리 감지 횟수 : 마지막 실시간 소리 감지 횟수 값 입니다.
실시간 소리 감지 횟수 : 약 1초 안에 다음 소리가 감지되면 1씩 증가합니다.
사용자 버튼 상태 : 접촉(1), 비접촉(0) 값 입니다.최종 소리 감지 횟수 : 마지막 실시간 소리 감지 횟수 값 입니다.
실시간 소리 감지 횟수 : 약 1초 안에 다음 소리가 감지되면 1씩 증가합니다.
사용자 버튼 상태 : 접촉(1), 비접촉(0) 값 입니다.', robotis_openCM70_aux_sensor_value: '서보모터 위치 : 0 ~ 1023, 중간 위치의 값은 512 입니다.
적외선센서 : 물체와 가까울 수록 큰 값 입니다.
접촉센서 : 접촉(1), 비접촉(0) 값 입니다.
조도센서(CDS) : 0 ~ 1023, 밝을 수록 큰 값 입니다.
온습도센서(습도) : 0 ~ 100, 습할 수록 큰 값 입니다.
온습도센서(온도) : -20 ~ 100, 온도가 높을 수록 큰 값 입니다.
온도센서 : -20 ~ 100, 온도가 높을 수록 큰 값 입니다.
초음파센서 : -
자석센서 : 접촉(1), 비접촉(0) 값 입니다.
동작감지센서 : 동작 감지(1), 동작 미감지(0) 값 입니다.
컬러센서 : 알수없음(0), 흰색(1), 검은색(2), 빨간색(3), 녹색(4), 파란색(5), 노란색(6) 값 입니다.
사용자 장치 : 사용자 센서 제작에 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.', robotis_openCM70_cm_buzzer_index: '음계를 0.1 ~ 5 초 동안 연주 합니다.', robotis_openCM70_cm_buzzer_melody: "멜로디를 연주 합니다.
멜로디를 연속으로 재생하는 경우, 다음 소리가 재생되지 않으면 '흐름 > X 초 기다리기' 블록을 사용하여 기다린 후 실행합니다.", robotis_openCM70_cm_sound_detected_clear: '최종 소리 감지횟 수를 0 으로 초기화 합니다.', robotis_openCM70_cm_led: '제어기의 빨간색, 녹색, 파란색 LED 를 켜거나 끕니다.', robotis_openCM70_cm_motion: '제어기에 다운로드 되어있는 모션을 실행합니다.', robotis_openCM70_cm_autodrive_motor: '자율주행 자동차의 모터 포트를 지정합니다.', robotis_openCM70_cm_autodrive_ir: '자율주행 자동차의 적외선 센서 포트를 지정합니다.', robotis_openCM70_cm_autodrive_speed: '지정한 속도로 자율주행을 수행합니다.', robotis_openCM70_aux_car_move: '로봇을 지정한 속도와 방향으로 움직이도록 합니다.', robotis_openCM70_aux_motor_speed: '감속모터 속도를 0 ~ 100% 의 값으로 정합니다.', robotis_openCM70_aux_servo_mode: '서보모터를 회전모드 또는 관절모드로 정합니다.
한번 설정된 모드는 계속 적용됩니다.
회전모드는 서보모터 속도를 지정하여 서보모터를 회전 시킵니다.
관절모드는 지정한 서보모터 속도로 서보모터 위치를 이동 시킵니다.', robotis_openCM70_aux_servo_speed: '서보모터 속도를 0 ~ 100% 의 값으로 정합니다.', robotis_openCM70_aux_servo_position: '서보모터 위치를 -150도 ~ 150도 의 값(으)로 정합니다.
서보모터 속도와 같이 사용해야 합니다.', robotis_openCM70_aux_led_module: 'LED 모듈의 LED 를 켜거나 끕니다.', robotis_openCM70_aux_custom: '사용자 센서 제작에 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.', robotis_openCM70_cm_poweroff_timer: '제어기의 자동꺼짐 타이머를 설정합니다.
설정된 만큼의 시간동안 통신이 진행되지 않으면 제어기는 자동으로 꺼집니다.', robotis_openCM70_cm_custom_value: '컨트롤 테이블 주소를 직접 입력하여 값을 확인 합니다.
컨트롤 테이블 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.', robotis_openCM70_cm_custom: '컨트롤 테이블 주소를 직접 입력하여 값을 정합니다.
컨트롤 테이블 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.', show_variable: "선택한 변수의 '변수 창'을 실행화면에 보이게 합니다.", hide_variable: "선택한 변수의 '변수 창'을 실행화면에서 숨깁니다.", value_of_index_from_list: '선택한 리스트에서 입력한 순서에 있는 항목 값입니다.', add_value_to_list: '입력한 값을 선택한 리스트의 마지막 항목에 추가합니다.', remove_value_from_list: '선택한 리스트의 입력한 순서에 있는 항목을 삭제합니다.', insert_value_to_list: '입력한 값을 선택한 리스트의 입력한 순서의 항목으로 추가합니다. (입력한 항목 뒤에 있는 항목들은 순서가 하나씩 밀려납니다.)', change_value_list_index: '선택한 리스트에서 입력한 순서에 있는 항목의 값을 입력한 값으로 바꿉니다.', length_of_list: '선택한 리스트가 보유한 항목의 개수입니다.', show_list: "선택한 리스트의 '리스트 창'을 실행화면에 보이게 합니다.", hide_list: "선택한 리스트의 '리스트 창'을 실행화면에서 숨깁니다.", text: '해당 글상자가 표시하고 있는 문자값을 의미합니다.', text_read: '선택한 글상자에 작성된 내용입니다. (내용 안에 줄 바꿈이 있는 경우, 띄어쓰기하여 반환됩니다.)', text_write: '글상자의 내용을 입력한 값으로 고쳐 씁니다.', text_append: '글상자의 내용 뒤에 입력한 값을 추가합니다.', text_prepend: '글상자의 내용 앞에 입력한 값을 추가합니다.', text_flush: '글상자의 내용을 모두 지웁니다.', erase_all_effects: '오브젝트에 적용된 효과를 모두 지웁니다.', char_at: '입력한 값에서 입력한 숫자 번째의 글자 값입니다. (공백을 포함합니다.)', length_of_string: '입력한 값의 공백을 포함한 글자 수입니다.', substring: '입력한 값에서 입력한 범위 내의 글자 값입니다. (공백을 포함합니다.)', count_match_string: '입력한 값에서 지정한 값의 글자 수이며, 영문의 경우 대문자와 소문자를 구분하여 수를 셉니다.', replace_string: '입력한 값에서 지정한 값을 찾아 추가로 입력한 값으로 모두 바꾼 값입니다. (영문 입력 시 대소문자를 구분합니다.)', index_of_string: '입력한 값에서 지정한 값이 처음으로 등장하는 위치 값입니다. (공백을 포함합니다.)', change_string_case: '입력한 영문의 모든 알파벳을 대문자 또는 소문자로 바꾼 값입니다.', direction_relative_duration: '오브젝트의 이동 방향이 입력한 시간에 걸쳐 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', get_sound_volume: '작품에 설정된 소리의 크기 값입니다.', sound_from_to: '해당 오브젝트가 선택한 소리를 입력한 구간을 재생하는 동시에 다음 블록을 실행합니다.', sound_from_to_and_wait: '해당 오브젝트가 선택한 소리를 입력한 구간을 재생한 후 다음 블록을 실행합니다.', Block_info: '블록 설명', Block_click_msg: '블록을 클릭하면
블록에 대한 설명이 나타납니다.', hamster_beep: '버저 소리를 짧게 냅니다.', hamster_change_both_wheels_by: '왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', hamster_change_buzzer_by: '버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.', hamster_change_output_by: '선택한 외부 확장 포트의 현재 출력 값에 입력한 값을 더합니다. 더한 결과는 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH', hamster_change_tempo_by: '연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.', hamster_change_wheel_by: '왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', hamster_clear_buzzer: '버저 소리를 끕니다.', hamster_clear_led: '왼쪽/오른쪽/양쪽 LED를 끕니다.', hamster_follow_line_until: '왼쪽/오른쪽/앞쪽/뒤쪽의 검은색/하얀색 선을 따라 이동하다가 교차로를 만나면 정지합니다.', hamster_follow_line_using: '왼쪽/오른쪽/양쪽 바닥 센서를 사용하여 검은색/하얀색 선을 따라 이동합니다.', hamster_hand_found: "근접 센서 앞에 손 또는 물체가 있으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", hamster_move_backward_for_secs: '입력한 시간(초) 동안 뒤로 이동합니다.', hamster_move_forward_for_secs: '입력한 시간(초) 동안 앞으로 이동합니다.', hamster_move_forward_once: '말판 위에서 한 칸 앞으로 이동합니다.', hamster_play_note_for: '선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.', hamster_rest_for: '입력한 박자만큼 쉽니다.', hamster_set_both_wheels_to: '왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', hamster_set_buzzer_to: '버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 버저 소리를 끕니다.', hamster_set_following_speed_to: '선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.', hamster_set_led_to: '왼쪽/오른쪽/양쪽 LED를 선택한 색깔로 켭니다.', hamster_set_output_to: '선택한 외부 확장 포트의 출력 값을 입력한 값으로 설정합니다. 입력하는 값은 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH', hamster_set_port_to: '선택한 외부 확장 포트의 입출력 모드를 선택한 모드로 설정합니다.', hamster_set_tempo_to: '연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.', hamster_set_wheel_to: '왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', hamster_stop: '양쪽 바퀴를 정지합니다.', hamster_turn_for_secs: '입력한 시간(초) 동안 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.', hamster_turn_once: '말판 위에서 왼쪽/오른쪽 방향으로 제자리에서 90도 회전합니다.', hamster_value: '왼쪽 근접 센서: 왼쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
오른쪽 근접 센서: 오른쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
왼쪽 바닥 센서: 왼쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
오른쪽 바닥 센서: 오른쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.
밝기: 밝기 센서의 값 (값의 범위: 0 ~ 65535, 초기값: 0) 밝을 수록 값이 커집니다.
온도: 로봇 내부의 온도 값 (값의 범위: 섭씨 -40 ~ 88도, 초기값: 0)
신호 세기: 블루투스 무선 통신의 신호 세기 (값의 범위: -128 ~ 0 dBm, 초기값: 0) 신호의 세기가 셀수록 값이 커집니다.
입력 A: 외부 확장 포트 A로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)
입력 B: 외부 확장 포트 B로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)', roboid_hamster_beep: '버저 소리를 짧게 냅니다.', roboid_hamster_change_both_wheels_by: '왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', roboid_hamster_change_buzzer_by: '버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.', roboid_hamster_change_output_by: '선택한 외부 확장 포트의 현재 출력 값에 입력한 값을 더합니다. 더한 결과는 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH', roboid_hamster_change_tempo_by: '연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.', roboid_hamster_change_wheel_by: '왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', roboid_hamster_clear_buzzer: '버저 소리를 끕니다.', roboid_hamster_clear_led: '왼쪽/오른쪽/양쪽 LED를 끕니다.', roboid_hamster_follow_line_until: '왼쪽/오른쪽/앞쪽/뒤쪽의 검은색/하얀색 선을 따라 이동하다가 교차로를 만나면 정지합니다.', roboid_hamster_follow_line_using: '왼쪽/오른쪽/양쪽 바닥 센서를 사용하여 검은색/하얀색 선을 따라 이동합니다.', roboid_hamster_hand_found: "근접 센서 앞에 손 또는 물체가 있으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", roboid_hamster_move_backward_for_secs: '입력한 시간(초) 동안 뒤로 이동합니다.', roboid_hamster_move_forward_for_secs: '입력한 시간(초) 동안 앞으로 이동합니다.', roboid_hamster_move_forward_once: '말판 위에서 한 칸 앞으로 이동합니다.', roboid_hamster_play_note_for: '선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.', roboid_hamster_rest_for: '입력한 박자만큼 쉽니다.', roboid_hamster_set_both_wheels_to: '왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', roboid_hamster_set_buzzer_to: '버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 버저 소리를 끕니다.', roboid_hamster_set_following_speed_to: '선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.', roboid_hamster_set_led_to: '왼쪽/오른쪽/양쪽 LED를 선택한 색깔로 켭니다.', roboid_hamster_set_output_to: '선택한 외부 확장 포트의 출력 값을 입력한 값으로 설정합니다. 입력하는 값은 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH', roboid_hamster_set_port_to: '선택한 외부 확장 포트의 입출력 모드를 선택한 모드로 설정합니다.', roboid_hamster_set_tempo_to: '연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.', roboid_hamster_set_wheel_to: '왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', roboid_hamster_stop: '양쪽 바퀴를 정지합니다.', roboid_hamster_turn_for_secs: '입력한 시간(초) 동안 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.', roboid_hamster_turn_once: '말판 위에서 왼쪽/오른쪽 방향으로 제자리에서 90도 회전합니다.', roboid_hamster_value: '왼쪽 근접 센서: 왼쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
오른쪽 근접 센서: 오른쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
왼쪽 바닥 센서: 왼쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
오른쪽 바닥 센서: 오른쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.
밝기: 밝기 센서의 값 (값의 범위: 0 ~ 65535, 초기값: 0) 밝을 수록 값이 커집니다.
온도: 로봇 내부의 온도 값 (값의 범위: 섭씨 -40 ~ 88도, 초기값: 0)
신호 세기: 블루투스 무선 통신의 신호 세기 (값의 범위: -128 ~ 0 dBm, 초기값: 0) 신호의 세기가 셀수록 값이 커집니다.
입력 A: 외부 확장 포트 A로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)
입력 B: 외부 확장 포트 B로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)', roboid_turtle_button_state: "등 버튼을 클릭했으면/더블클릭했으면/길게 눌렀으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", roboid_turtle_change_buzzer_by: '버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.', roboid_turtle_change_head_led_by_rgb: '머리 LED의 현재 R, G, B 값에 입력한 값을 각각 더합니다.', roboid_turtle_change_tempo_by: '연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.', roboid_turtle_change_wheel_by: '왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', roboid_turtle_change_wheels_by_left_right: '왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', roboid_turtle_clear_head_led: '머리 LED를 끕니다.', roboid_turtle_clear_sound: '소리를 끕니다.', roboid_turtle_cross_intersection: '검은색 교차로에서 잠시 앞으로 이동한 후 검은색 선을 찾아 다시 이동합니다.', roboid_turtle_follow_line: '하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동합니다.', roboid_turtle_follow_line_until: '하얀색 바탕 위에서 검은색 선을 따라 이동하다가 선택한 색깔을 컬러 센서가 감지하면 정지합니다.', roboid_turtle_follow_line_until_black: '하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동하다가 컬러 센서가 검은색을 감지하면 정지합니다.', roboid_turtle_is_color_pattern: "선택한 색깔 패턴을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", roboid_turtle_move_backward_unit: '입력한 거리(cm)/시간(초)/펄스만큼 뒤로 이동합니다.', roboid_turtle_move_forward_unit: '입력한 거리(cm)/시간(초)/펄스만큼 앞으로 이동합니다.', roboid_turtle_pivot_around_wheel_unit_in_direction: '왼쪽/오른쪽 바퀴 중심으로 입력한 각도(도)/시간(초)/펄스만큼 머리/꼬리 방향으로 회전합니다.', roboid_turtle_play_note: '선택한 계이름과 옥타브의 음을 계속 소리 냅니다.', roboid_turtle_play_note_for_beats: '선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.', roboid_turtle_play_sound_times: '선택한 소리를 입력한 횟수만큼 재생합니다.', roboid_turtle_play_sound_times_until_done: '선택한 소리를 입력한 횟수만큼 재생하고, 재생이 완료될 때까지 기다립니다.', roboid_turtle_rest_for_beats: '입력한 박자만큼 쉽니다.', roboid_turtle_set_buzzer_to: '버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 소리를 끕니다.', roboid_turtle_set_following_speed_to: '선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.', roboid_turtle_set_head_led_to: '머리 LED를 선택한 색깔로 켭니다.', roboid_turtle_set_head_led_to_rgb: '머리 LED의 R, G, B 값을 입력한 값으로 각각 설정합니다.', roboid_turtle_set_tempo_to: '연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.', roboid_turtle_set_wheel_to: '왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', roboid_turtle_set_wheels_to_left_right: '왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', roboid_turtle_stop: '양쪽 바퀴를 정지합니다.', roboid_turtle_touching_color: "선택한 색깔을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", roboid_turtle_turn_at_intersection: '검은색 교차로에서 잠시 앞으로 이동한 후 제자리에서 왼쪽/오른쪽/뒤쪽으로 회전하고 검은색 선을 찾아 다시 이동합니다.', roboid_turtle_turn_unit_in_place: '입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.', roboid_turtle_turn_unit_with_radius_in_direction: '입력한 반지름의 원을 그리면서 입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽, 머리/꼬리 방향으로 회전합니다.', roboid_turtle_value: '색깔 번호: 컬러 센서가 감지한 색깔의 번호 (값의 범위: -1 ~ 8, 초기값: -1)
색깔 패턴: 컬러 센서가 감지한 색깔 패턴의 값 (값의 범위: -1 ~ 88, 초기값: -1)
바닥 센서: 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
버튼: 거북이 등 버튼의 상태 값 (누르면 1, 아니면 0, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.', turtle_button_state: "등 버튼을 클릭했으면/더블클릭했으면/길게 눌렀으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", turtle_change_buzzer_by: '버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.', turtle_change_head_led_by_rgb: '머리 LED의 현재 R, G, B 값에 입력한 값을 각각 더합니다.', turtle_change_tempo_by: '연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.', turtle_change_wheel_by: '왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', turtle_change_wheels_by_left_right: '왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', turtle_clear_head_led: '머리 LED를 끕니다.', turtle_clear_sound: '소리를 끕니다.', turtle_cross_intersection: '검은색 교차로에서 잠시 앞으로 이동한 후 검은색 선을 찾아 다시 이동합니다.', turtle_follow_line: '하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동합니다.', turtle_follow_line_until: '하얀색 바탕 위에서 검은색 선을 따라 이동하다가 선택한 색깔을 컬러 센서가 감지하면 정지합니다.', turtle_follow_line_until_black: '하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동하다가 컬러 센서가 검은색을 감지하면 정지합니다.', turtle_is_color_pattern: "선택한 색깔 패턴을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", turtle_move_backward_unit: '입력한 거리(cm)/시간(초)/펄스만큼 뒤로 이동합니다.', turtle_move_forward_unit: '입력한 거리(cm)/시간(초)/펄스만큼 앞으로 이동합니다.', turtle_pivot_around_wheel_unit_in_direction: '왼쪽/오른쪽 바퀴 중심으로 입력한 각도(도)/시간(초)/펄스만큼 머리/꼬리 방향으로 회전합니다.', turtle_play_note: '선택한 계이름과 옥타브의 음을 계속 소리 냅니다.', turtle_play_note_for_beats: '선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.', turtle_play_sound_times: '선택한 소리를 입력한 횟수만큼 재생합니다.', turtle_play_sound_times_until_done: '선택한 소리를 입력한 횟수만큼 재생하고, 재생이 완료될 때까지 기다립니다.', turtle_rest_for_beats: '입력한 박자만큼 쉽니다.', turtle_set_buzzer_to: '버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 소리를 끕니다.', turtle_set_following_speed_to: '선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.', turtle_set_head_led_to: '머리 LED를 선택한 색깔로 켭니다.', turtle_set_head_led_to_rgb: '머리 LED의 R, G, B 값을 입력한 값으로 각각 설정합니다.', turtle_set_tempo_to: '연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.', turtle_set_wheel_to: '왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', turtle_set_wheels_to_left_right: '왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', turtle_stop: '양쪽 바퀴를 정지합니다.', turtle_touching_color: "선택한 색깔을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", turtle_turn_at_intersection: '검은색 교차로에서 잠시 앞으로 이동한 후 제자리에서 왼쪽/오른쪽/뒤쪽으로 회전하고 검은색 선을 찾아 다시 이동합니다.', turtle_turn_unit_in_place: '입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.', turtle_turn_unit_with_radius_in_direction: '입력한 반지름의 원을 그리면서 입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽, 머리/꼬리 방향으로 회전합니다.', turtle_value: '색깔 번호: 컬러 센서가 감지한 색깔의 번호 (값의 범위: -1 ~ 8, 초기값: -1)
색깔 패턴: 컬러 센서가 감지한 색깔 패턴의 값 (값의 범위: -1 ~ 88, 초기값: -1)
바닥 센서: 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
버튼: 거북이 등 버튼의 상태 값 (누르면 1, 아니면 0, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.', neobot_sensor_value: 'IN1 ~ IN3 포트 및 리모컨에서 입력되는 값 그리고 배터리 정보를 0부터 255의 숫자로 표시합니다.', neobot_sensor_convert_scale: '선택한 포트 입력값의 변화를 특정범위의 값으로 표현범위를 조절할 수 있습니다.', neobot_left_motor: 'L모터 포트에 연결한 모터의 회전방향 및 속도를 설정합니다.', neobot_stop_left_motor: 'L모터 포트에 연결한 모터를 정지합니다.', neobot_right_motor: 'R모터 포트에 연결한 모터의 회전방향 및 속도를 설정합니다.', neobot_stop_right_motor: 'R모터 포트에 연결한 모터를 정지합니다.', neobot_all_motor: 'L모터 및 R모터 포트에 2개 모터를 연결하여 바퀴로 활용할 때 전, 후, 좌, 우 이동 방향 및 속도, 시간을 설정할 수 있습니다.', neobot_stop_all_motor: 'L모터 및 R모터에 연결한 모터를 모두 정지합니다.', neobot_set_servo: 'OUT1 ~ OUT3에 서보모터를 연결했을 때 0도 ~ 180도 범위 내에서 각도를 조절할 수 있습니다.', neobot_set_output: 'OUT1 ~ OUT3에 라이팅블록 및 전자회로를 연결했을 때 출력 전압을 설정할 수 있습니다.
0은 0V, 1 ~ 255는 2.4 ~ 4.96V의 전압을 나타냅니다.', neobot_set_fnd: 'FND로 0~99 까지의 숫자를 표시할 수 있습니다.', neobot_set_fnd_off: 'FND에 표시한 숫자를 끌 수 있습니다.', neobot_play_note_for: '주파수 발진 방법을 이용해 멜로디에 반음 단위의 멜로디 음을 발생시킬 수 있습니다.', rotate_by_angle_dropdown: '오브젝트의 방향을 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', chocopi_control_button: '버튼이 눌리면 참이 됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_control_event: '버튼을 누르거나 뗄 때 처리할 엔트리 블록들을 연결합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_control_joystick: '조이스틱 좌우, 상하, 볼륨의 값은 0~4095까지 입니다.
따라서 2047 근처가 중간이 됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_dc_motor: 'DC모터 모듈에는 직류전동기 두개를 연결 할 수 있습니다.
직류 전동기는 최대 5V로 동작하게 됩니다.
값은 100이 최대(100%)이고 음수를 넣으면 반대 방향으로 회전합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_led: 'LED번호는 LED블록에 연결된 순서이고 1번부터 시작합니다.
RGB값은 0~255사이의 값입니다.
빨강(Red),녹색(Green), 파랑(Blue)순서로 입력합니다.
밝은 LED를 직접보면 눈이 아프니까 값을 0~5정도로 씁니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_motion_photogate_event: '포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
빛센서를 물체로 가리거나 치우면 시작되는 엔트리 블록을 연결합니다
모션 모듈에는 포토게이트 2개를 연결할 수 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_motion_photogate_status: '포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
물체가 빛센서를 가리면 참이됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_motion_photogate_time: '포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
이 블록은 물체가 빛센서를 가리거나 벗어난 시간을 가집니다.
1/10000초까지 측정할 수 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_motion_value: '모션 모듈에는 3개의 적외선 센서가 있습니다.
0~4095사이의 값을 가질 수 있는데 물체가 빛을 많이 반사할 수록 작은 값을 가집니다.
거리를 대략적으로 측정할 수 있습니다.
가속도와 각가속도 값의 범위는 -32768~32767 까지입니다.
가속도를 이용해서 센서의 기울기를 측정할 수도 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_sensor: '온도 값은 섭씨 온도입니다.
습도 값은 백분율로 나타낸 상대습도 값입니다.
빛은 로그스케일로 0~4095사이입니다.
아날로그 값은 0~4095사이입니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_servo_motor: '서보모터 모듈에는 4개의 서보모터를 연결 할 수 있습니다.
서보모터는 5V로 동작하게 됩니다.
각도는 0~200도까지 지정할 수 있습니다.
연속회전식 서보모터를 연결하면 각도에 따라 속도가 변하게됩니다.
90~100 사이가 중간값입니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_touch_event: '터치 모듈에는 1~12번의 연결 패드가 있습니다.
만지거나 뗄 때 처리할 엔트리 블록들을 연결합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_touch_status: '터치 모듈의 패드를 만지면 참이됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_touch_value: '터치패드에 연결된 물체의 전기용량이 커지면 값이 작아집니다.
여러 명이 손잡고 만지면 더 작은 값이 됩니다.
전기용량이란 물체에 전기를 띈 입자를 얼마나 가지고 있을 수 있는 지를 말합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', boolean_and_or: '그리고 : 두 판단이 모두 참인 경우 ‘참’으로 판단합니다.
또는 : 두 판단 중 하나라도 참이 있는 경우 ‘참’으로 판단합니다.', check_weather: '
선택한 날짜와 지역의 날씨 정보를 실제 날씨 상태와 비교하여 일치하는 경우 ‘참’으로 판단합니다.
* 옵션
날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
날씨: 맑음, 구름조금, 구름많음, 흐림, 비, 진눈깨비, 눈', check_finedust: '
선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.
* 옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
미세먼지 등급: 좋음, 보통, 나쁨, 매우나쁨', get_weather_data: '
선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.
* 옵션
날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
정보: 최저기온(℃), 최고기온(℃), 습도(%), 강수량(mm), 강수확률(%), 풍속(m/s)', get_current_weather_data: '
현재 선택한 지역의 날씨 정보값(기온, 미세먼지농도)입니다.
* 옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
정보: (기온(℃)), 미세먼지농도(㎍)', get_today_temperature: '
오늘 선택한 지역과 시간대의 기온을 의미합니다.
* 옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시간대: 00, 03, 06, 09, 12, 15, 18, 21', check_city_weather: '선택한 날짜와 지역의 날씨 정보를 실제 날씨 상태와 비교하여 일치하는 경우 ‘참’으로 판단합니다.\n* 옵션\n날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후\n시도: 서울, 강원, 경기, 경남, 경북 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n날씨: 맑음, 구름조금, 구름많음, 흐림, 비, 진눈깨비, 눈', check_city_finedust: '선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.\n* 옵션\n시도: 서울, 강원, 경기, 경남, 경북,광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n미세먼지 등급: 좋음, 보통, 나쁨, 매우나쁨', get_city_weather_data: '선택한 날짜와 지역의 각종 날씨 정보입니다.\n *옵션\n날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후\n시도:서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n정보: 최저기온(℃), 최고기온(℃), 습도(%), 강수량(mm), 강수확률(%), 풍속(m/s)', get_current_city_weather_data: '현재 선택한 지역의 날씨 정보입니다.\n*옵션\n시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n정보: 기온(℃), 미세먼지농도(㎍)', get_today_city_temperature: '오늘 선택한 지역과 시간대의 기온입니다.\n*옵션\n시도: 서울, 강원, 경기, 경남, 경북 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n시간대: 00, 03, 06, 09, 12, 15, 18, 21', count_festival: '선택한 날짜와 지역에서 열리는 행사의 수입니다.\n* 옵션 \n지역: 서울, 강원, 경기, 경남, 경북 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n행사일: 1~12월', get_festival_info: '선택한 날짜와 지역에서 열리는 행사에 대한 정보입니다.\n* 옵션 \n지역: 서울, 강원, 경기, 경남, 경북 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n행사일: 1~12월 \n정보: 제목, 지역, 시작일, 종료일, 주소, 개요, 홈페이지', get_translated_string: '입력한 문자값을 선택한 언어로 번역합니다. 입력은 3000자까지 가능합니다.\n*번역 가능한 언어 \n - 한국어 → 영어, 중국어 간체, 중국어 번체, 베트남어, 스페인어, 인도네시아어, 태국어, 프랑스어\n - 영어 → 일본어, 프랑스어, 한국어\n - 중국어 간체, 중국어 번체, 베트남어, 스페인어, 인도네시아어, 태국어, 프랑스어 → 한국어\n - 일본어 →영어 \n - 프랑스어 → 영어', check_language: '입력된 문자값의 언어를 감지합니다. 입력은 문장 형태로 3000자까지 가능합니다.', count_disaster_behavior: '선택한 자연재해가 발생했을 때 해야할 행동요령의 수입니다.
*옵션
자연재해: 태풍, 홍수, 호우, 강풍, 대설, 한파, 풍랑, 황사, 폭염, 가뭄, 지진, 해일, 산사태
상황: 자연재해에 따라 다름 ', get_disaster_behavior: '선택한 자연재해가 발생했을 때 해야하는 행동요령에 대한 정보입니다.
*옵션
자연재해: 태풍, 홍수, 호우, 강풍, 대설, 한파, 풍랑, 황사, 폭염, 가뭄, 지진, 해일, 산사태
상황: 자연재해에 따라 다름', count_lifeSafety_behavior: '선택한 생활 속 문제가 발생했을 때 해야할 행동요령의 수입니다.
*옵션
생활 속 문제: 응급처치, 심폐소생술, 소화기·소화전 사용법, 식중독, 산행안전, 실종유괴, 성폭력, 학교폭력, 가정 폭력, 억류 및 납치, 교통사고, 승강기 안전사고, 미세먼지
상황: 생활 속 문제에 따라 다름 ', get_lifeSafety_behavior: '선택한 생활 속 문제가 발생했을 때 해야할 행동요령에 대한 정보입니다.
*옵션
생활 속 문제: 응급처치, 심폐소생술, 소화기·소화전 사용법, 식중독, 산행안전, 실종유괴, 성폭력, 학교폭력, 가정 폭력, 억류 및 납치, 교통사고, 승강기 안전사고, 미세먼지
상황: 생활 속 문제에 따라 다름 ', read_text: '입력한 문자값을 설정된 목소리로 읽습니다.
입력은 2500자까지 가능합니다.
인터넷에 연결되어 있지 않거나 인터넷 환경이 불안할 경우, 해당 블록이 실행되지 않고 다음 블록으로 넘어갈 수 있습니다.', set_tts_property: '선택한 목소리가 선택한 속도와 선택한 음높이로 설정됩니다.', read_text_wait_with_block: '입력한 문자값을 읽어준 후 다음 블록을 실행합니다.', check_microphone: "컴퓨터에 마이크가 연결되어 있는 경우 '참'으로 판단합니다. (IE/Safari 브라우저 지원하지 않음)", speech_to_text_convert: '마이크에 입력되는 사람의 목소리를 텍스트로 변환합니다. (IE/Safari 브라우저 지원하지 않음)', get_microphone_volume: '마이크에 입력되는 소리의 크기 값입니다. (IE/Safari 브라우저 지원하지 않음)', speech_to_text_get_value: '사람의 목소리를 문자로 바꾼 값입니다. 목소리가 입력되지 않거나, 음성인식 도중 오류가 발생한 경우 무조건 0 값을 갖습니다. (IE/Safari 브라우저 지원하지 않음)', video_draw_webcam: '컴퓨터에 연결된 카메라에 촬영되는 화면을 실행화면에서 보이게하거나 숨깁니다.', video_check_webcam: "컴퓨터에 카메라가 연결되어 있는 경우 '참'으로 판단합니다.", video_set_camera_option: '촬영되는 화면의 효과를 입력한 값으로 정합니다. 밝기: -100~100 사이의 범위로 설정할 수 있습니다. (-100 이하는 -100으로 100 이상은 100으로 처리됩니다.) 투명도: 0~100 사이의 범위로 설정할 수 있습니다. (0 이하는 0으로 100 이상은 100으로 처리됩니다.)', video_flip_camera: '촬영되는 화면을 좌우 혹은 상하로 뒤집습니다.', video_toggle_model: '선택한 인식모델을 동작시키거나 중지시킵니다. 얼굴 인식: 사람의 얼굴을 인식하여 눈, 코, 입, 귀의 위치나 예상되는 성별, 나이, 감정을 알 수 있습니다. 사람 인식: 사람의 몸을 인식하여 각 신체부위의 위치 등을 알 수 있습니다. 객체 인식: 인식된 객체의 종류를 알 수 있습니다. (사람이나 물건)', video_toggle_ind: '인식 된 사람 / 얼굴 / 사물 을 화면에 표시하거나 숨깁니다', video_number_detect: '인식된 사람 / 얼굴 / 사물의 숫자입니다 촬영되는 화면에 객체로 인식된 객체의 개수입니다. *인식할 수 있는 사물: 사람, 자전거, 자동차, 오토바이, 비행기, 버스, 기차, 트럭, 보트,교통 신호등, 소화전, 정지 신호, 주차 미터, 벤치, 새, 고양이, 개, 말, 양, 암소, 코끼리, 곰, 얼룩말, 기린, 책가방, 우산, 핸드백, 넥타이, 가방, 프리스비, 스키, 스노보드, 스포츠 볼, 연, 야구 방망이, 야구 글러브, 스케이트 보드, 서핑 보드, 테니스 라켓, 병, 와인 글라스, 컵, 포크, 나이프, 숟가락, 그릇, 바나나, 애플, 샌드위치, 주황색, 브로콜리, 당근, 핫도그, 피자, 도넛, 케이크, 의자, 소파, 화분, 침대, 식사테이블, 화장실, TV 모니터, 노트북, 마우스, 원격, 키보드, 휴대 전화, 전자 레인지, 오븐, 토스터기, 싱크대, 냉장고, 도서, 시계, 꽃병, 가위, 테디베어, 헤어드라이어, 칫솔', video_detected_face_info: '입력한 순서의 얼굴의 선택한 정보의 추정값입니다. 인식이 잘 되지 않는 경우 무조건 0으로 출력됩니다. (성별, 나이, 감정)', video_motion_value: '선택한 오브젝트 혹은 실행화면 위에서 감지되는 움직임 혹은 방향 값입니다. 움직임: 움직임이 크고 빠를 수록 값이 커집니다. 방향: 오른쪽 혹은 위쪽으로 움직일 때 양수, 왼쪽 혹은 아래쪽으로 움직일 때 음수가 됩니다.', video_face_part_coord: '입력한 순서의 얼굴 중 선택된 얼굴 부위의 위치값입니다. 인식이 잘 되지 않는 경우 무조건 0으로 출력됩니다. (왼쪽 눈, 오른쪽 눈, 코, 왼쪽 입꼬리, 오른쪽 입꼬리, 윗 입술, 아랫입술)', video_body_part_coord: '입력한 순서의 사람의 선택한 신체 부위의 위치값입니다. (얼굴, 왼쪽 어깨, 왼쪽 팔꿈치, 왼쪽 손목, 왼쪽 엉덩이, 왼쪽 무릎, 왼쪽 발목, 오른쪽 어깨, 오른쪽 팔꿈치, 오른쪽 손목, 오른쪽 엉덩이, 오른쪽 무릎, 오른쪽 발목)', append_row_to_table: '선택한 테이블의 마지막에 행(열)을 추가합니다. 추가된 행(열)의 모든 열(행) 값은 0입니다.', insert_row_to_table: '선택한 테이블의 입력한 순서에 행(열)을 추가합니다. 추가된 행(열)의 모든 열(행) 값은 0입니다. (입력한 행(열) 뒤에 있는 행들은 순서가 하나씩 밀려납니다.', delete_row_from_table: '선택한 테이블의 입력한 순서에 있는 행(열)을 삭제합니다.', set_value_from_table: '선택한 테이블에서 입력한 순서의 선택된 열값을 입력한 값으로 바꿉니다.', get_table_count: '선택한 테이블이 보유한 행과 열의 개수입니다.', get_value_from_table: '선택한 테이블에서 입력한 순서의 선택된 열 값 입니다.', calc_values_from_table: '선택한 테이블에서 선택한 열들에 대한 계산값입니다. (합, 최댓값, 최솟값, 평균값, 표준편차)', open_table_chart: '선택한 테이블의 차트창을 엽니다.', close_table_chart: '열려있는 테이블 차트창을 닫습니다.', get_coefficient: '선택한 테이블에서 두 속성 사이의 상관계수입니다. 상관계수가 1(-1)에 가까울 수록 강한 양(음)의 선형 상관관계를 갖습니다.', }; Lang.Category = { entrybot_friends: '엔트리봇 친구들', people: '사람', animal: '동물', animal_flying: '하늘', animal_land: '땅', animal_water: '물', animal_others: '기타', plant: '식물', plant_flower: '꽃', plant_grass: '풀', plant_tree: '나무', plant_others: '기타', vehicles: '탈것', vehicles_flying: '하늘', vehicles_land: '땅', vehicles_water: '물', vehicles_others: '기타', architect: '건물', architect_building: '건축물', architect_monument: '기념물', architect_others: '기타', food: '음식', food_vegetables: '과일/채소', food_meat: '고기', food_drink: '음료', food_others: '기타', environment: '환경', environment_nature: '자연', environment_space: '우주', environment_others: '기타', stuff: '물건', stuff_living: '생활', stuff_hobby: '취미', stuff_others: '기타', fantasy: '판타지', interface: '인터페이스', interface_website: '웹사이트', interface_game: '게임', interface_others: '기타', background: '배경', background_outdoor: '실외', background_indoor: '실내', background_nature: '자연', background_others: '기타', }; Lang.Device = { arduino: '아두이노', hamster: '햄스터', roboid: '로보이드', turtle: '거북이', albert: '알버트', robotis_carCont: '로보티즈 자동차 로봇', robotis_openCM70: '로보티즈 IoT', sensorBoard: '엔트리 센서보드', trueRobot: '뚜루뚜루', CODEino: '코드이노', bitbrick: '비트브릭', creamo: '크리모', playcode: '플레이코드', funboard: '펀보드', bitBlock: '비트블록', xbot_epor_edge: '엑스봇', dplay: '디플레이', iboard: '아이보드', nemoino: '네모이노', ev3: 'EV3', robotori: '로보토리', smartBoard: '스마트보드', chocopi: '초코파이보드', rokoboard: '로코보드', altino: '알티노', mechatro: '메카트로', }; Lang.General = { turn_on: '켜기', turn_off: '끄기', left: '왼쪽', right: '오른쪽', param_string: '문자값', both: '양쪽', transparent: '투명', black: '검은색', brown: '갈색', red: '빨간색', yellow: '노란색', green: '초록색', skyblue: '하늘색', blue: '파란색', purple: '보라색', white: '하얀색', note_c: '도', note_d: '레', note_e: '미', note_f: '파', note_g: '솔', note_a: '라', note_b: '시', questions: '문제', clock: '시계', counter_clock: '반시계', font_size: '글자 크기', second: '초', alert_title: '알림', confirm_title: '확인', update_title: '업데이트 알림', recent_download: '최신 버전 다운로드', recent_download2: '최신버전 다운로드', latest_version: '최신 버전입니다.', dont_show_again: '다시보지 않기', }; Lang.Fonts = { jeju_hallasan: '한라산체', gothic_coding: '코딩고딕체', batang: '바탕체', gothic: '나눔고딕체', myeongjo: '나눔명조', pen_script: '나눔손글씨', square_round: '나눔스퀘어라운드체', jalnan: '잘난체', designhouse: '디자인하우스체', malssami815: '말싸미815체', dunggeunmo: '둥근모꼴체', hs_bombaram: 'HS봄바람체', yisunshin: '이순신체', goyang: '고양체', flower_road: '꽃길체', uhbeemysen: '어비마이센체', sd_comic_stencil: '산돌 코믹스탠실', sd_childfundkorea: '산돌 초록우산 어린이', sd_cinema_theater: '산돌 씨네마극장', sd_mapssi: '산돌 맵씨', sd_shabang: '산돌 별이샤방샤방', sd_woodcarving: '산돌 목각', sd_yongbi: '산돌 용비어천가', }; Lang.Hw = { note: '음표', leftWheel: '왼쪽 바퀴', rightWheel: '오른쪽 바퀴', leftEye: '왼쪽 눈', rightEye: '오른쪽 눈', led: '불빛', led_en: 'LED', body: '몸통', front: '앞쪽', port_en: '', port_ko: '번 포트', sensor: '센서', light: '빛', temp: '온도', switch_: '스위치', right_ko: '오른쪽', right_en: '', left_ko: '왼쪽', left_en: '', up_ko: '위쪽', up_en: '', down_ko: '아래쪽', down_en: '', output: '출력', left: '왼쪽', right: '오른쪽', sub: '서보', motor: '모터', '': '', buzzer: '버저', IR: '적외선', acceleration: '가속', analog: '아날로그', angular_acceleration: '각가속', button: '버튼', humidity: '습도', joystick: '조이스틱', port: '포트', potentiometer: '포텐시오미터', servo: '서보', }; Lang.template = { albert_hand_found: '손 찾음?', albert_is_oid_value: ' %1 OID 값이 %2 인가? ', albert_value: '%1', albert_move_forward_for_secs: '앞으로 %1 초 이동하기 %2', albert_move_backward_for_secs: '뒤로 %1 초 이동하기 %2', albert_turn_for_secs: '%1 으로 %2 초 돌기 %3', albert_change_both_wheels_by: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 만큼 바꾸기 %3', albert_set_both_wheels_to: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 (으)로 정하기 %3', albert_change_wheel_by: '%1 바퀴 %2 만큼 바꾸기 %3', albert_set_wheel_to: '%1 바퀴 %2 (으)로 정하기 %3', albert_stop: '정지하기 %1', albert_set_pad_size_to: '말판 크기를 폭 %1 높이 %2 (으)로 정하기 %3', albert_move_to_x_y_on_board: '밑판 x: %1 y: %2 위치로 이동하기 %3', albert_set_orientation_on_board: '말판 %1도 방향으로 바라보기 %2', albert_set_eye_to: '%1 눈을 %2 으로 정하기 %3', albert_clear_eye: '%1 눈 끄기 %2', albert_body_led: '몸통 LED %1 %2', albert_front_led: '앞쪽 LED %1 %2', albert_beep: '삐 소리내기 %1', albert_change_buzzer_by: '버저 음을 %1 만큼 바꾸기 %2', albert_set_buzzer_to: '버저 음을 %1 (으)로 정하기 %2', albert_clear_buzzer: '버저 끄기 %1', albert_play_note_for: '%1 %2 음을 %3 박자 연주하기 %4', albert_rest_for: '%1 박자 쉬기 %2', albert_change_tempo_by: '연주 속도를 %1 만큼 바꾸기 %2', albert_set_tempo_to: '연주 속도를 %1 BPM으로 정하기 %2', albert_move_forward: '앞으로 이동하기 %1', albert_move_backward: '뒤로 이동하기 %1', albert_turn_around: '%1 으로 돌기 %2', albert_set_led_to: '%1 %2 으로 정하기 %3', albert_clear_led: '%1 %2', albert_change_wheels_by: '%1 %2 %3', albert_set_wheels_to: '%1 %2 %3', arduino_text: '%1', arduino_get_sensor_number: '%1 ', arduino_get_port_number: '%1 ', arduino_get_digital_toggle: '%1 ', arduino_get_pwm_port_number: '%1 ', arduino_get_number_sensor_value: '아날로그 %1 번 센서값 ', arduino_ext_get_analog_value: '아날로그 %1 번 센서값', arduino_ext_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', arduino_ext_get_ultrasonic_value: '울트라소닉 Trig %1 Echo %2 센서값', arduino_ext_toggle_led: '디지털 %1 번 핀 %2 %3', arduino_ext_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', arduino_ext_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', arduino_ext_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', arduino_ext_get_digital: '디지털 %1 번 센서값', blacksmith_get_analog_value: '아날로그 %1 번 핀 센서 값', blacksmith_get_analog_mapping: '아날로그 %1 번 핀 센서 값의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼 값', blacksmith_get_digital_bluetooth: '블루투스 RX 2 핀 데이터 값', blacksmith_get_digital_ultrasonic: '초음파 Trig %1 핀 Echo %2 핀 센서 값', blacksmith_get_digital_toggle: '디지털 %1 번 핀 센서 값', blacksmith_set_digital_toggle: '디지털 %1 번 핀 %2 %3', blacksmith_set_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', blacksmith_set_digital_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', blacksmith_set_digital_buzzer: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', blacksmith_set_digital_lcd: 'LCD화면 %1 줄에 %2 나타내기 %3', blacksmith_set_digital_bluetooth: '블루투스 TX 3 핀에 %1 데이터 보내기 %2', dplay_get_number_sensor_value: '아날로그 %1 번 센서값 ', nemoino_get_number_sensor_value: '아날로그 %1 번 센서값 ', sensorBoard_get_number_sensor_value: '아날로그 %1 번 센서값 ', truetrue_get_accsensor: '가속도센서 %1 의 값', truetrue_get_bottomcolorsensor: '바닥컬러센서 %1 의 값', truetrue_get_frontcolorsensor: '전면컬러센서 %1 의 값', truetrue_get_linesensor: '라인센서 %1 의 값', truetrue_get_proxisensor: '근접센서 %1 의 값', truetrue_set_colorled: '컬러LED Red %1 Green %2 Blue %3 로 설정 %4', truetrue_set_dualmotor: 'DC모터 좌 %1 우 %2 속도로 %3 초 구동 %4', truetrue_set_led_colorsensor: '%1 조명용 LED %2 %3', truetrue_set_led_linesensor: '라인센서 조명용 LED %1 %2', truetrue_set_led_proxi: '%1 조명용 LED %2 %3', truetrue_set_linetracer: '라인트레이싱 모드 %1 %2', truetrue_set_singlemotor: 'DC모터 %1 속도 %2 로 설정 %3', CODEino_get_number_sensor_value: '아날로그 %1 번 센서값 ', ardublock_get_number_sensor_value: '아날로그 %1 번 센서값 ', arduino_get_digital_value: '디지털 %1 번 센서값 ', dplay_get_digital_value: '디지털 %1 번 센서값 ', nemoino_get_digital_value: '디지털 %1 번 센서값 ', sensorBoard_get_digital_value: '디지털 %1 번 센서값 ', CODEino_get_digital_value: '디지털 %1 핀의 값 ', CODEino_set_digital_value: '디지털 %1 핀의 %2 %3', CODEino_set_pwm_value: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', ardublock_get_digital_value: '디지털 %1 번 센서값 ', arduino_toggle_led: '디지털 %1 번 핀 %2 %3', dplay_toggle_led: '디지털 %1 번 핀 %2 %3', nemoino_toggle_led: '디지털 %1 번 핀 %2 %3', sensorBoard_toggle_led: '디지털 %1 번 핀 %2 %3', CODEino_toggle_led: '디지털 %1 번 핀 %2 %3', arduino_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', dplay_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', nemoino_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', sensorBoard_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', CODEino_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', ardublock_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', arduino_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', dplay_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', nemoino_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', sensorBoard_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', CODEino_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', CODEino_set_rgb_value: '컬러 LED의 %1 색상을 %2 (으)로 정하기 %3', CODEino_set_rgb_add_value: '컬러 LED의 %1 색상에 %2 만큼 더하기 %3', CODEino_set_rgb_off: '컬러 LED 끄기 %1', CODEino_set__led_by_rgb: '컬러 LED 색상을 빨강 %1 초록 %2 파랑 %3 (으)로 정하기 %4', CODEino_rgb_set_color: '컬러 LED의 색상을 %1 (으)로 정하기 %2', CODEino_led_by_value: '컬러 LED 켜기 %1', ardublock_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', joystick_get_number_sensor_value: '아날로그 %1 번 센서값 ', joystick_get_digital_value: '디지털 %1 번 센서값 ', joystick_toggle_led: '디지털 %1 번 핀 %2 %3', joystick_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', joystick_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', sensorBoard_get_named_sensor_value: '%1 센서값', sensorBoard_is_button_pressed: '%1 버튼을 눌렀는가?', sensorBoard_led: '%1 LED %2 %3', arduino_download_connector: '%1', download_guide: '%1', arduino_download_source: '%1', arduino_connected: '%1', arduino_connect: '%1', arduino_reconnect: '%1', CODEino_get_sensor_number: '%1 ', CODEino_get_named_sensor_value: ' %1 센서값 ', CODEino_get_sound_status: '소리센서 %1 ', CODEino_get_light_status: '빛센서 %1 ', CODEino_is_button_pressed: ' 보드의 %1 ', CODEino_get_accelerometer_direction: ' 3축 가속도센서 %1 ', CODEino_get_accelerometer_value: ' 3축 가속도센서 %1 축의 센서값 ', CODEino_get_analog_value: '아날로그 %1 센서의 값', iboard_button: '%1 버튼을 눌렀는가?', iboard_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', iboard_get_analog_value: '아날로그 %1 번 센서값 ', iboard_get_analog_value_map: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', iboard_get_digital: '디지털 %1 번 센서값 ', iboard_led: 'LED %1 번을 %2 %3', iboard_motor: '모터를 %2 으로 동작하기 %3', iboard_pwm_led: 'LED %1 번의 밝기를 %2 (으)로 정하기 %3', iboard_rgb_led: 'RGB LED의 %1 LED %2 %3', iboard_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', iboard_toggle_led: '디지털 %1 번 핀 %2 %3', bitbrick_when_button_pressed: '%1 버튼 %2 눌러졌을 때', bitbrick_when_sensor_get_value: '%1 %2 값 %3 %4 일 때', bitbrick_is_touch_pressed: '버튼 %1 이(가) %2 인가?', bitbrick_is_sensor_value_compare: '%1 값 %2 %3 인가?', bitbrick_sensor_value: '%1 값', bitbrick_convert_scale: '변환 %1 값 %2 ~ %3 에서 %4 ~ %5', bitbrick_turn_on_color_led_by_rgb: '엘이디를 빨강 %1 초록 %2 파랑 %3 %4 (으)로 켜기', bitbrick_turn_on_color_led_by_picker: '엘이디를 %1 (으)로 켜기 %2', bitbrick_turn_on_color_led_by_value: '엘이디를 %1 (으)로 켜기 %2', bitbrick_turn_off_color_led: '엘이디 끄기 %1', bitbrick_buzzer: '버저음 %1 내기 %2', bitbrick_servomotor_angle: '서보모터 %1 각도 %2 %3', bitbrick_dc_direction_speed: '디씨모터 %1 방향 %2 속력 %3 %4', bitbrick_dc_speed: '디씨모터 %1 속도 %2 %3', bitbrick_turn_off_all_motors: '모든 모터 멈추기 %1', start_drawing: '그리기 시작하기 %1', stop_drawing: '그리기 멈추기 %1', set_color: '붓의 색을 %1 (으)로 정하기 %2', set_random_color: '붓의 색을 무작위로 정하기 %1', change_thickness: '붓의 굵기를 %1 만큼 바꾸기 %2', set_thickness: '붓의 굵기를 %1 (으)로 정하기 %2', change_opacity: '붓의 불투명도를 %1 % 만큼 바꾸기 %2', set_opacity: '붓의 불투명도를 %1 % 로 정하기 %2', brush_erase_all: '모든 붓 지우기 %1', brush_stamp: '도장 찍기 %1', change_brush_transparency: '붓의 투명도를 %1 % 만큼 바꾸기 %2', set_brush_tranparency: '붓의 투명도를 %1 % 로 정하기 %2', number: '%1', angle: '%1', get_x_coordinate: '%1', get_y_coordinate: '%1', get_angle: '%1', get_rotation_direction: '%1 ', distance_something: '%1 %2 %3', coordinate_mouse: '%1 %2 %3', coordinate_object: '%1 %2 %3 %4', calc_basic: '%1 %2 %3', calc_plus: '%1 %2 %3', calc_minus: '%1 %2 %3', calc_times: '%1 %2 %3', calc_divide: '%1 %2 %3', calc_mod: '%1 %2 %3 %4', calc_share: '%1 %2 %3 %4', calc_operation: '%1 %2 %3 %4', calc_rand: '%1 %2 %3 %4 %5', get_date: '%1 %2 %3', get_sound_duration: '%1 %2 %3', get_user_name: '사용자이름', reset_project_timer: '%1', set_visible_project_timer: '%1 %2 %3 %4', timer_variable: '%1 %2', get_project_timer_value: '%1 %2', char_at: '%1 %2 %3 %4 %5', length_of_string: '%1 %2 %3', reverse_of_string: '%1 %2 %3', substring: '%1 %2 %3 %4 %5 %6 %7', replace_string: '%1 %2 %3 %4 %5 %6 %7', change_string_case: '%1 %2 %3 %4 %5', index_of_string: '%1 %2 %3 %4 %5', count_match_string: '%1 %2 %3 %4', combine_something: '%1 %2 %3 %4 %5', get_sound_volume: '%1 %2', quotient_and_mod: '%1 %2 %3 %4 %5 %6', choose_project_timer_action: '%1 %2 %3 %4', wait_second: '%1 초 기다리기 %2', repeat_basic: '%1 번 반복하기 %2', hidden_loop: '%1 번 반복하기 %2', repeat_inf: '계속 반복하기 %1', stop_repeat: '반복 중단하기 %1', wait_until_true: '%1 이(가) 될 때까지 기다리기 %2', _if: '만일 %1 (이)라면 %2', if_else: '만일 %1 (이)라면 %2 %3 아니면', create_clone: '%1 의 복제본 만들기 %2', delete_clone: '이 복제본 삭제하기 %1', when_clone_start: '%1 복제본이 처음 생성되었을때', stop_run: '프로그램 끝내기 %1', repeat_while_true: '%1 %2 반복하기 %3', stop_object: '%1 코드 멈추기 %2', restart_project: '처음부터 다시 실행하기 %1', remove_all_clones: '모든 복제본 삭제하기 %1', functionAddButton: '%1', function_field_label: '%1%2', function_field_string: '%1%2', function_field_boolean: '%1%2', function_param_string: '문자/숫자값', function_param_boolean: '판단값', function_create: '함수 정의하기 %1 %2', function_general: '함수 %1', expansionBlockAddButton: '%1', aiUtilizeBlockAddButton: '%1', aiUtilizeModelTrainButton: '%1', weather_title: '%1', check_weather: '%1 %2 의 날씨가 %3인가?', check_finedust: '현재 %1 의 미세먼지 등급이 %2인가?', get_weather_data: '%1 %2 의 %3', get_current_weather_data: '현재 %1 의 %2', get_today_temperature: '오늘 %1의 %2시 기온', check_city_weather: '%1 %2 %3의 날씨가 %4인가?', check_city_finedust: '현재 %1 %2 의 미세먼지 등급이 %3인가?', get_city_weather_data: '%1 %2 %3 의 %4', get_current_city_weather_data: '현재 %1 %2 의 %3', get_today_city_temperature: '오늘 %1 %2의 %3시 기온', translate_title: '%1', get_translated_string: '%1 %2 을(를) %3로 번역한 값', check_language: '%1의 언어', festival_title: '%1', count_festival: '%1 %2 행사의 수', get_festival_info: '%1 %2 행사 %3 번째 항목의 %4', behaviorConductDisaster_title: '%1', count_disaster_behavior: '%1 %2 해야할 행동요령 수', get_disaster_behavior: '자연재난%1 %2 해야할 행동요령 %3 번째 항목', behaviorConductLifeSafety_title: '%1', count_lifeSafety_behavior: '%1 에서 %2 방법의 수', get_lifeSafety_behavior: '%1 에서 %2 방법 %3 번째 항목', tts_title: '%1', audio_title: '%1', video_title: '%1', read_text: '%1 읽어주기 %2', set_tts_property: '%1 목소리를 %2 속도 %3 음높이로 설정하기 %4', read_text_wait_with_block: '%1 읽어주고 기다리기 %2', load_expansion_block: '확장 블록 불러오기', load_ai_utilize_block: 'AI 블록 불러오기', load_ai_utilize_train_block: '모델 학습', expansion_block_descriptions: '확장 블록은 인터넷이 연결되어 있어야 정상적으로 동작합니다.', aiUtilize_block_descriptions: 'AI 활용블록은 인터넷이 연결되어 있어야 정상적으로 동작합니다.', weather_title_text: '날씨', translate_title_text: '번역', festival_title_text: '행사', audio_title_text: '오디오 감지', check_microphone: '마이크가 연결되었는가?', get_microphone_volume: '마이크 소리크기', speech_to_text_convert: '음성 인식하기 %1', speech_to_text_get_value: '음성을 문자로 바꾼 값', video_title_text: '비디오 감지', video_draw_webcam: '비디오 화면 %1 %2', video_check_webcam: '비디오가 연결되었는가?', video_set_camera_opacity_option: '비디오 투명도 효과를 %1 으로 정하기 %2', video_flip_camera: '비디오 화면 %1 뒤집기 %2', video_toggle_model: '%1 인식 %2 %3', video_toggle_ind: '인식된 %1 %2 %3', video_number_detect: '인식된 %1 의 수', video_detected_face_info: '%1 번째 얼굴의 %2', video_motion_value: '%1 에서 감지한 %2 값', video_face_part_coord: '%1 번째 얼굴의 %2 의 %3 좌표', video_body_part_coord: '%1 번째 사람의 %2 의 %3 좌표', behaviorConductDisaster_title_text: '자연재난 국민행동요령', behaviorConductLifeSafety_title_text: '생활안전 국민행동요령', tts_title_text: '읽어주기', hamster_hand_found: '손 찾음?', hamster_value: '%1', hamster_move_forward_once: '말판 앞으로 한 칸 이동하기 %1', hamster_turn_once: '말판 %1 으로 한 번 돌기 %2', hamster_move_forward_for_secs: '앞으로 %1 초 이동하기 %2', hamster_move_backward_for_secs: '뒤로 %1 초 이동하기 %2', hamster_turn_for_secs: '%1 으로 %2 초 돌기 %3', hamster_change_both_wheels_by: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 만큼 바꾸기 %3', hamster_set_both_wheels_to: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 (으)로 정하기 %3', hamster_change_wheel_by: '%1 바퀴 %2 만큼 바꾸기 %3', hamster_set_wheel_to: '%1 바퀴 %2 (으)로 정하기 %3', hamster_follow_line_using: '%1 선을 %2 바닥 센서로 따라가기 %3', hamster_follow_line_until: '%1 선을 따라 %2 교차로까지 이동하기 %3', hamster_set_following_speed_to: '선 따라가기 속도를 %1 (으)로 정하기 %2', hamster_stop: '정지하기 %1', hamster_set_led_to: '%1 LED를 %2 으로 정하기 %3', hamster_clear_led: '%1 LED 끄기 %2', hamster_beep: '삐 소리내기 %1', hamster_change_buzzer_by: '버저 음을 %1 만큼 바꾸기 %2', hamster_set_buzzer_to: '버저 음을 %1 (으)로 정하기 %2', hamster_clear_buzzer: '버저 끄기 %1', hamster_play_note_for: '%1 %2 음을 %3 박자 연주하기 %4', hamster_rest_for: '%1 박자 쉬기 %2', hamster_change_tempo_by: '연주 속도를 %1 만큼 바꾸기 %2', hamster_set_tempo_to: '연주 속도를 %1 BPM으로 정하기 %2', hamster_set_port_to: '포트 %1 를 %2 으로 정하기 %3', hamster_change_output_by: '출력 %1 를 %2 만큼 바꾸기 %3', hamster_set_output_to: '출력 %1 를 %2 (으)로 정하기 %3', roboid_hamster_beep: '햄스터 %1: 삐 소리내기 %2', roboid_hamster_change_both_wheels_by: '햄스터 %1: 왼쪽 바퀴 %2 오른쪽 바퀴 %3 만큼 바꾸기 %4', roboid_hamster_change_buzzer_by: '햄스터 %1: 버저 음을 %2 만큼 바꾸기 %3', roboid_hamster_change_output_by: '햄스터 %1: 출력 %2 를 %3 만큼 바꾸기 %4', roboid_hamster_change_tempo_by: '햄스터 %1: 연주 속도를 %2 만큼 바꾸기 %3', roboid_hamster_change_wheel_by: '햄스터 %1: %2 바퀴 %3 만큼 바꾸기 %4', roboid_hamster_clear_buzzer: '햄스터 %1: 버저 끄기 %2', roboid_hamster_clear_led: '햄스터 %1: %2 LED 끄기 %3', roboid_hamster_follow_line_until: '햄스터 %1: %2 선을 따라 %3 교차로까지 이동하기 %4', roboid_hamster_follow_line_using: '햄스터 %1: %2 선을 %3 바닥 센서로 따라가기 %4', roboid_hamster_hand_found: '햄스터 %1: 손 찾음?', roboid_hamster_move_backward_for_secs: '햄스터 %1: 뒤로 %2 초 이동하기 %3', roboid_hamster_move_forward_for_secs: '햄스터 %1: 앞으로 %2 초 이동하기 %3', roboid_hamster_move_forward_once: '햄스터 %1: 말판 앞으로 한 칸 이동하기 %2', roboid_hamster_play_note_for: '햄스터 %1: %2 %3 음을 %4 박자 연주하기 %5', roboid_hamster_rest_for: '햄스터 %1: %2 박자 쉬기 %3', roboid_hamster_set_both_wheels_to: '햄스터 %1: 왼쪽 바퀴 %2 오른쪽 바퀴 %3 (으)로 정하기 %4', roboid_hamster_set_buzzer_to: '햄스터 %1: 버저 음을 %2 (으)로 정하기 %3', roboid_hamster_set_following_speed_to: '햄스터 %1: 선 따라가기 속도를 %2 (으)로 정하기 %3', roboid_hamster_set_led_to: '햄스터 %1: %2 LED를 %3 으로 정하기 %4', roboid_hamster_set_output_to: '햄스터 %1: 출력 %2 를 %3 (으)로 정하기 %4', roboid_hamster_set_port_to: '햄스터 %1: 포트 %2 를 %3 으로 정하기 %4', roboid_hamster_set_tempo_to: '햄스터 %1: 연주 속도를 %2 BPM으로 정하기 %3', roboid_hamster_set_wheel_to: '햄스터 %1: %2 바퀴 %3 (으)로 정하기 %4', roboid_hamster_stop: '햄스터 %1: 정지하기 %2', roboid_hamster_turn_for_secs: '햄스터 %1: %2 으로 %3 초 돌기 %4', roboid_hamster_turn_once: '햄스터 %1: 말판 %2 으로 한 번 돌기 %3', roboid_hamster_value: '햄스터 %1: %2', roboid_turtle_button_state: '거북이 %1: 버튼을 %2 ?', roboid_turtle_change_buzzer_by: '거북이 %1: 버저 음을 %2 만큼 바꾸기 %3', roboid_turtle_change_head_led_by_rgb: '거북이 %1: 머리 LED를 R: %2 G: %3 B: %4 만큼 바꾸기 %5', roboid_turtle_change_tempo_by: '거북이 %1: 연주 속도를 %2 만큼 바꾸기 %3', roboid_turtle_change_wheel_by: '거북이 %1: %2 바퀴 %3 만큼 바꾸기 %4', roboid_turtle_change_wheels_by_left_right: '거북이 %1: 왼쪽 바퀴 %2 오른쪽 바퀴 %3 만큼 바꾸기 %4', roboid_turtle_clear_head_led: '거북이 %1: 머리 LED 끄기 %2', roboid_turtle_clear_sound: '거북이 %1: 소리 끄기 %2', roboid_turtle_cross_intersection: '거북이 %1: 검은색 교차로 건너가기 %2', roboid_turtle_follow_line: '거북이 %1: %2 선을 따라가기 %3', roboid_turtle_follow_line_until: '거북이 %1: 검은색 선을 따라 %2 까지 이동하기 %3', roboid_turtle_follow_line_until_black: '거북이 %1: %2 선을 따라 검은색까지 이동하기 %3', roboid_turtle_is_color_pattern: '거북이 %1: 색깔 패턴이 %2 %3 인가?', roboid_turtle_move_backward_unit: '거북이 %1: 뒤로 %2 %3 이동하기 %4', roboid_turtle_move_forward_unit: '거북이 %1: 앞으로 %2 %3 이동하기 %4', roboid_turtle_pivot_around_wheel_unit_in_direction: '거북이 %1: %2 바퀴 중심으로 %3 %4 %5 방향으로 돌기 %6', roboid_turtle_play_note: '거북이 %1: %2 %3 음을 연주하기 %4', roboid_turtle_play_note_for_beats: '거북이 %1: %2 %3 음을 %4 박자 연주하기 %5', roboid_turtle_play_sound_times: '거북이 %1: %2 소리 %3 번 재생하기 %4', roboid_turtle_play_sound_times_until_done: '거북이 %1: %2 소리 %3 번 재생하고 기다리기 %4', roboid_turtle_rest_for_beats: '거북이 %1: %2 박자 쉬기 %3', roboid_turtle_set_buzzer_to: '거북이 %1: 버저 음을 %2 (으)로 정하기 %3', roboid_turtle_set_following_speed_to: '거북이 %1: 선 따라가기 속도를 %2 (으)로 정하기 %3', roboid_turtle_set_head_led_to: '거북이 %1: 머리 LED를 %2 으로 정하기 %3', roboid_turtle_set_head_led_to_rgb: '거북이 %1: 머리 LED를 R: %2 G: %3 B: %4 (으)로 정하기 %5', roboid_turtle_set_tempo_to: '거북이 %1: 연주 속도를 %2 BPM으로 정하기 %3', roboid_turtle_set_wheel_to: '거북이 %1: %2 바퀴 %3 (으)로 정하기 %4', roboid_turtle_set_wheels_to_left_right: '거북이 %1: 왼쪽 바퀴 %2 오른쪽 바퀴 %3 (으)로 정하기 %4', roboid_turtle_stop: '거북이 %1: 정지하기 %2', roboid_turtle_touching_color: '거북이 %1: %2 에 닿았는가?', roboid_turtle_turn_at_intersection: '거북이 %1: 검은색 교차로에서 %2 으로 돌기 %3', roboid_turtle_turn_unit_in_place: '거북이 %1: %2 으로 %3 %4 제자리 돌기 %5', roboid_turtle_turn_unit_with_radius_in_direction: '거북이 %1: %2 으로 %3 %4 반지름 %5 cm를 %6 방향으로 돌기 %7', roboid_turtle_value: '거북이 %1: %2', turtle_button_state: '버튼을 %1 ?', turtle_change_buzzer_by: '버저 음을 %1 만큼 바꾸기 %2', turtle_change_head_led_by_rgb: '머리 LED를 R: %1 G: %2 B: %3 만큼 바꾸기 %4', turtle_change_tempo_by: '연주 속도를 %1 만큼 바꾸기 %2', turtle_change_wheel_by: '%1 바퀴 %2 만큼 바꾸기 %3', turtle_change_wheels_by_left_right: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 만큼 바꾸기 %3', turtle_clear_head_led: '머리 LED 끄기 %1', turtle_clear_sound: '소리 끄기 %1', turtle_cross_intersection: '검은색 교차로 건너가기 %1', turtle_follow_line: '%1 선을 따라가기 %2', turtle_follow_line_until: '검은색 선을 따라 %1 까지 이동하기 %2', turtle_follow_line_until_black: '%1 선을 따라 검은색까지 이동하기 %2', turtle_is_color_pattern: '색깔 패턴이 %1 %2 인가?', turtle_move_backward_unit: '뒤로 %1 %2 이동하기 %3', turtle_move_forward_unit: '앞으로 %1 %2 이동하기 %3', turtle_pivot_around_wheel_unit_in_direction: '%1 바퀴 중심으로 %2 %3 %4 방향으로 돌기 %5', turtle_play_note: '%1 %2 음을 연주하기 %3', turtle_play_note_for_beats: '%1 %2 음을 %3 박자 연주하기 %4', turtle_play_sound_times: '%1 소리 %2 번 재생하기 %3', turtle_play_sound_times_until_done: '%1 소리 %2 번 재생하고 기다리기 %3', turtle_rest_for_beats: '%1 박자 쉬기 %2', turtle_set_buzzer_to: '버저 음을 %1 (으)로 정하기 %2', turtle_set_following_speed_to: '선 따라가기 속도를 %1 (으)로 정하기 %2', turtle_set_head_led_to: '머리 LED를 %1 으로 정하기 %2', turtle_set_head_led_to_rgb: '머리 LED를 R: %1 G: %2 B: %3 (으)로 정하기 %4', turtle_set_tempo_to: '연주 속도를 %1 BPM으로 정하기 %2', turtle_set_wheel_to: '%1 바퀴 %2 (으)로 정하기 %3', turtle_set_wheels_to_left_right: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 (으)로 정하기 %3', turtle_stop: '정지하기 %1', turtle_touching_color: '%1 에 닿았는가?', turtle_turn_at_intersection: '검은색 교차로에서 %1 으로 돌기 %2', turtle_turn_unit_in_place: '%1 으로 %2 %3 제자리 돌기 %4', turtle_turn_unit_with_radius_in_direction: '%1 으로 %2 %3 반지름 %4 cm를 %5 방향으로 돌기 %6', turtle_value: '%1', is_clicked: '%1', is_object_clicked: '%1', is_press_some_key: '%1 %2', reach_something: '%1 %2 %3', is_type: '%1 %2 %3 %4', boolean_comparison: '%1 %2 %3', boolean_equal: '%1 %2 %3', boolean_bigger: '%1 %2 %3', boolean_smaller: '%1 %2 %3', boolean_and_or: '%1 %2 %3', boolean_and: '%1 %2 %3', boolean_or: '%1 %2 %3', boolean_not: '%1 %2 %3', true_or_false: '%1', True: '%1 ', False: '%1 ', boolean_basic_operator: '%1 %2 %3', show: '모양 보이기 %1', hide: '모양 숨기기 %1', dialog_time: '%1 을(를) %2 초 동안 %3 %4', dialog: '%1 을(를) %2 %3', remove_dialog: '말하기 지우기 %1', change_to_nth_shape: '%1 모양으로 바꾸기 %2', change_to_next_shape: '%1 모양으로 바꾸기 %2', set_effect_volume: '%1 효과를 %2 만큼 주기 %3', set_effect: '%1 효과를 %2 (으)로 정하기 %3', erase_all_effects: '효과 모두 지우기 %1', change_scale_percent: '크기를 %1 만큼 바꾸기 %2', set_scale_percent: '크기를 %1 (으)로 정하기 %2', change_scale_size: '크기를 %1 만큼 바꾸기 %2', set_scale_size: '크기를 %1 (으)로 정하기 %2', flip_y: '좌우 모양 뒤집기 %1', flip_x: '상하 모양 뒤집기 %1', set_object_order: '%1 번째로 올라오기 %2', get_pictures: '%1 ', change_to_some_shape: '%1 모양으로 바꾸기 %2', add_effect_amount: '%1 효과를 %2 만큼 주기 %3', change_effect_amount: '%1 효과를 %2 (으)로 정하기 %3', set_effect_amount: '%1 효과를 %2 만큼 주기 %3', set_entity_effect: '%1 효과를 %2 (으)로 정하기 %3', change_object_index: '%1 보내기 %2', move_direction: '이동 방향으로 %1 만큼 움직이기 %2', move_x: 'x 좌표를 %1 만큼 바꾸기 %2', move_y: 'y 좌표를 %1 만큼 바꾸기 %2', locate_xy_time: '%1 초 동안 x: %2 y: %3 위치로 이동하기 %4', rotate_by_angle: '오브젝트를 %1 만큼 회전하기 %2', rotate_by_angle_dropdown: '%1 만큼 회전하기 %2', see_angle: '이동 방향을 %1 (으)로 정하기 %2', see_direction: '%1 쪽 보기 %2', locate_xy: 'x: %1 y: %2 위치로 이동하기 %3', locate_x: 'x: %1 위치로 이동하기 %2', locate_y: 'y: %1 위치로 이동하기 %2', locate: '%1 위치로 이동하기 %2', move_xy_time: '%1 초 동안 x: %2 y: %3 만큼 움직이기 %4', rotate_by_angle_time: '오브젝트를 %1 초 동안 %2 만큼 회전하기 %3', bounce_wall: '화면 끝에 닿으면 튕기기 %1', flip_arrow_horizontal: '화살표 방향 좌우 뒤집기 %1', flip_arrow_vertical: '화살표 방향 상하 뒤집기 %1', see_angle_object: '%1 쪽 바라보기 %2', see_angle_direction: '오브젝트를 %1 (으)로 정하기 %2', rotate_direction: '이동 방향을 %1 만큼 회전하기 %2', locate_object_time: '%1 초 동안 %2 위치로 이동하기 %3', rotate_absolute: '방향을 %1 (으)로 정하기 %2', rotate_relative: '방향을 %1 만큼 회전하기 %2', direction_absolute: '이동 방향을 %1 (으)로 정하기 %2', direction_relative: '이동 방향을 %1 만큼 회전하기 %2', move_to_angle: '%1 방향으로 %2 만큼 움직이기 %3', rotate_by_time: '%1 초 동안 방향을 %2 만큼 회전하기 %3', direction_relative_duration: '%1 초 동안 이동 방향 %2 만큼 회전하기 %3', neobot_sensor_value: '%1 값', neobot_turn_left: '왼쪽모터를 %1 %2 회전 %3', neobot_stop_left: '왼쪽모터 정지 %1', neobot_turn_right: '오른쪽모터를 %1 %2 회전 %3', neobot_stop_right: '오른쪽모터 정지 %1', neobot_run_motor: '%1 모터를 %2 초간 %3 %4 %5', neobot_servo_1: 'SERVO1에 연결된 서보모터를 %1 속도로 %2 로 이동 %3', neobot_servo_2: 'SERVO2에 연결된 서보모터를 %1 속도로 %2 로 이동 %3', neobot_play_note_for: '멜로디 %1 을(를) %2 옥타브로 %3 길이만큼 소리내기 %4', neobot_set_sensor_value: '%1 번 포트의 값을 %2 %3', robotis_openCM70_cm_custom_value: '직접입력 주소 ( %1 ) %2 값', robotis_openCM70_sensor_value: '제어기 %1 값', robotis_openCM70_aux_sensor_value: '%1 %2 값', robotis_openCM70_cm_buzzer_index: '제어기 음계값 %1 을(를) %2 초 동안 연주 %3', robotis_openCM70_cm_buzzer_melody: '제어기 멜로디 %1 번 연주 %2', robotis_openCM70_cm_sound_detected_clear: '최종소리감지횟수 초기화 %1', robotis_openCM70_cm_led: '제어기 %1 LED %2 %3', robotis_openCM70_cm_motion: '모션 %1 번 실행 %2', robotis_openCM70_cm_autodrive_motor: '자율주행 자동차 %1 모터를 %2 에 연결 %3', robotis_openCM70_cm_autodrive_ir: '자율주행 자동차 %1 적외선센서를 %2 에 연결 %3', robotis_openCM70_cm_autodrive_speed: '차로를 따라 %1의 속도로 자율주행 %2', robotis_openCM70_aux_car_move: '로봇을 %1% 의 속도로 %2 %3', robotis_openCM70_aux_motor_speed: '%1 감속모터 속도를 %2 , 출력값을 %3%로 정하기 %4', robotis_openCM70_aux_servo_mode: '%1 서보모터 모드를 %2 (으)로 정하기 %3', robotis_openCM70_aux_servo_speed: '%1 서보모터 속도를 %2 , 출력값을 %3%로 정하기 %4', robotis_openCM70_aux_servo_position: '%1 서보모터 위치를 %2도로 정하기 %3', robotis_openCM70_aux_led_module: '%1 LED 모듈을 %2 (으)로 정하기 %3', robotis_openCM70_aux_custom: '%1 사용자 장치를 %2 (으)로 정하기 %3', robotis_openCM70_cm_poweroff_timer: '제어기 자동꺼짐 타이머 %1 %2', robotis_openCM70_cm_custom: '직접입력 주소 ( %1 ) (을)를 %2 (으)로 정하기 %3', robotis_carCont_sensor_value: '%1 값', robotis_carCont_cm_led: '4번 LED %1 , 1번 LED %2 %3', robotis_carCont_cm_sound_detected_clear: '최종소리감지횟수 초기화 %1', robotis_carCont_aux_motor_speed: '%1 감속모터 속도를 %2 , 출력값을 %3 (으)로 정하기 %4', robotis_carCont_cm_calibration: '%1 적외선 센서 캘리브레이션 값을 %2 (으)로 정하기 %3', roduino_get_analog_number: '%1 ', roduino_get_port_number: '%1 ', roduino_get_analog_value: '아날로그 %1 번 센서값 ', roduino_get_digital_value: '디지털 %1 번 센서값 ', roduino_set_digital: '디지털 %1 번 핀 %2 %3', roduino_motor: '%1 %2 %3', roduino_set_color_pin: '컬러센서 R : %1, G : %2, B : %3 %4', roduino_get_color: '컬러센서 %1 감지', roduino_on_block: ' On ', roduino_off_block: ' Off ', schoolkit_get_in_port_number: '%1 ', schoolkit_get_out_port_number: '%1 ', schoolkit_get_servo_port_number: '%1 ', schoolkit_get_input_value: '디지털 %1 번 센서값 ', schoolkit_set_output: '디지털 %1 번 핀 %2 %3', schoolkit_motor: '%1 속도 %2(으)로 %3 %4', schoolkit_set_servo_value: '서보모터 %1 번 핀 %2˚ %3', schoolkit_on_block: ' On ', schoolkit_off_block: ' Off ', when_scene_start: '%1 장면이 시작되었을 때', start_scene: '%1 시작하기 %2', start_neighbor_scene: '%1 장면 시작하기 %2', sound_something: '소리 %1 재생하기 %2', sound_something_second: '소리 %1 %2 초 재생하기 %3', sound_something_wait: '소리 %1 재생하고 기다리기 %2', sound_something_second_wait: '소리 %1 %2 초 재생하고 기다리기 %3', sound_volume_change: '소리 크기를 %1 % 만큼 바꾸기 %2', sound_volume_set: '소리 크기를 %1 % 로 정하기 %2', sound_silent_all: '모든 소리 멈추기 %1', get_sounds: '%1 ', sound_something_with_block: '소리 %1 재생하기 %2', sound_something_second_with_block: '소리 %1 %2 초 재생하기 %3', sound_something_wait_with_block: '소리 %1 재생하고 기다리기 %2', sound_something_second_wait_with_block: '소리 %1 %2 초 재생하고 기다리기 %3', sound_from_to: '소리 %1 %2 초 부터 %3 초까지 재생하기 %4', sound_from_to_and_wait: '소리 %1 %2 초 부터 %3 초까지 재생하고 기다리기 %4', when_run_button_click: '%1 시작하기 버튼을 클릭했을 때', press_some_key: '%1 %2 키를 눌렀을 때 %3', when_some_key_pressed: '%1 %2 키를 눌렀을 때', mouse_clicked: '%1 마우스를 클릭했을 때', mouse_click_cancled: '%1 마우스 클릭을 해제했을 때', when_object_click: '%1 오브젝트를 클릭했을 때', when_object_click_canceled: '%1 오브젝트 클릭을 해제했을 때', when_some_key_click: '%1 키를 눌렀을 때', when_message_cast: '%1 %2 신호를 받았을 때', message_cast: '%1 신호 보내기 %2', message_cast_wait: '%1 신호 보내고 기다리기 %2', text: '%1', text_read: '글상자 %1의 내용', text_write: '%1 라고 글쓰기 %2', text_append: '%1 라고 뒤에 이어쓰기 %2', text_prepend: '%1 라고 앞에 추가하기 %2', text_flush: '텍스트 모두 지우기 %1', analizyDataAddButton: '%1', append_row_to_table: '테이블 %1에 %2 추가하기 %3', insert_row_to_table: '테이블 %1 %2번째에 %3 추가하기 %4', delete_row_from_table: '테이블 %1 %2번째 %3 삭제하기 %4', set_value_from_table: '테이블 %1 %2번째 행의 %3을(를) %4(으)로 바꾸기 %5', get_table_count: '테이블 %1의 %2개수', get_value_from_table: '테이블 %1 %2번째 행의 %3 값', calc_values_from_table: '테이블 %1 %2의 %3', open_table_chart: '테이블 %1의 차트 창 열기 %2', close_table_chart: '테이블 차트 창 닫기 %1', get_coefficient: '테이블 %1 %2과(와) %3의 상관계수', variableAddButton: '%1', listAddButton: '%1', change_variable: '%1 에 %2 만큼 더하기 %3', set_variable: '%1 를 %2 (으)로 정하기 %3', show_variable: '변수 %1 보이기 %2', hide_variable: '변수 %1 숨기기 %2', get_variable: '%1 %2', ask_and_wait: '%1 을(를) 묻고 대답 기다리기 %2', get_canvas_input_value: '%1 ', add_value_to_list: '%1 항목을 %2 에 추가하기 %3', remove_value_from_list: '%1 번째 항목을 %2 에서 삭제하기 %3', insert_value_to_list: '%1 을(를) %2 의 %3 번째에 넣기 %4', change_value_list_index: '%1 %2 번째 항목을 %3 (으)로 바꾸기 %4', value_of_index_from_list: '%1 %2 %3 %4 %5', length_of_list: '%1 %2 %3', show_list: '리스트 %1 보이기 %2', hide_list: '리스트 %1 숨기기 %2', options_for_list: '%1 ', set_visible_answer: '대답 %1 %2', is_included_in_list: '%1 %2 %3 %4 %5', xbot_digitalInput: '%1', xbot_analogValue: '%1', xbot_digitalOutput: '디지털 %1 핀, 출력 값 %2 %3', xbot_analogOutput: '아날로그 %1 %2 %3', xbot_servo: '서보 모터 %1 , 각도 %2 %3', xbot_oneWheel: '바퀴(DC) 모터 %1 , 속도 %2 %3', xbot_twoWheel: '바퀴(DC) 모터 오른쪽(2) 속도: %1 왼쪽(1) 속도: %2 %3', xbot_rgb: 'RGB LED 켜기 R 값 %1 G 값 %2 B 값 %3 %4', xbot_rgb_picker: 'RGB LED 색 %1 로 정하기 %2', xbot_buzzer: '%1 %2 음을 %3 초 연주하기 %4', xbot_lcd: 'LCD %1 번째 줄 , 출력 값 %2 %3', run: '', mutant: 'test mutant block', jr_start: '%1', jr_repeat: '%1 %2 반복', jr_item: '꽃 모으기 %1', cparty_jr_item: '연필 줍기 %1', jr_north: ' 위쪽 %1', jr_east: '오른쪽 %1', jr_south: ' 아래쪽 %1', jr_west: ' 왼쪽 %1', jr_start_basic: '%1 %2', jr_go_straight: '앞으로 가기%1', jr_turn_left: '왼쪽으로 돌기%1', jr_turn_right: '오른쪽으로 돌기%1', jr_go_slow: '천천히 가기 %1', jr_repeat_until_dest: '%1 만날 때까지 반복하기 %2', jr_if_construction: '만약 %1 앞에 있다면 %2', jr_if_speed: '만약 %1 앞에 있다면 %2', maze_step_start: '%1 시작하기를 클릭했을 때', maze_step_jump: '뛰어넘기%1', maze_step_jump2: '뛰어넘기%1', maze_step_jump_pinkbean: '뛰어넘기%1', maze_step_for: '%1 번 반복하기%2', test: '%1 this is test block %2', maze_repeat_until_1: '%1 만날 때 까지 반복%2', maze_repeat_until_2: '모든 %1 만날 때 까지 반복%2', maze_step_if_1: '만약 앞에 %1 있다면%2', maze_step_if_2: '만약 앞에 %1 있다면%2', maze_call_function: '약속 불러오기%1', maze_define_function: '약속하기%1', maze_step_if_3: '만약 앞에 %1 있다면%2', maze_step_if_4: '만약 앞에 %1 있다면%2', maze_step_move_step: '앞으로 한 칸 이동%1', maze_step_rotate_left: '왼쪽으로 회전%1', maze_step_rotate_right: '오른쪽으로 회전%1', maze_step_forward: '앞으로 가기%1', maze_turn_right: '오른쪽 바라보기%1', maze_turn_left: '왼쪽 바라보기%1', maze_ladder_climb: '사다리 타기%1', maze_attack_lupin: '%1공격하기%2', maze_attack_both_side: '양옆 공격하기%1', maze_attack_pepe: '%1 공격하기%2', maze_attack_yeti: '%1 공격하기%2', maze_attack_mushroom: '%1 공격하기%2', maze_attack_peti: '%1 공격하기%2', maze_eat_item: '음식 먹기%1', maze_step_if_mushroom: '만약 한 칸 앞에 %1가 있다면 %2', maze_step_if_yeti: '만약 앞에 %1가 있다면 %2 %3 아니면', maze_step_if_left_monster: '만약 왼쪽 공격범위에 몬스터가 있다면 %1 %2 아니면', maze_step_if_right_monster: '만약 오른쪽 공격범위에 몬스터가 있다면 %1 %2 아니면', maze_step_if_lupin: '만약 두 칸 앞에 %1가 있다면 %2', maze_step_if_else_road: '만약 한 칸 앞에 길이 있다면 %1 %2아니면', maze_step_if_else_mushroom: '만약 한 칸 앞에 %1가 있다면 %2 %3아니면', maze_step_if_else_lupin: '만약 두 칸 앞에 %1가 있다면 %2 %3아니면', maze_step_if_else_ladder: '만약 한 칸 앞에 %1가 있다면 %2 %3아니면', maze_rotate_left: '왼쪽으로 돌기%1', maze_rotate_right: '오른쪽으로 돌기%1', maze_moon_kick: '발차기하기%1', maze_repeat_until_3: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_4: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_5: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_6: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_7: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_goal: '목적지에 도착할 때까지 반복하기%1', maze_repeat_until_beat_monster: '모든 몬스터를 혼내줄 때까지 반복하기%1', maze_radar_check: '%1에 %2이 있다', maze_cony_flower_throw: '꽃 던지기%1', maze_brown_punch: '주먹 날리기%1', maze_iron_switch: '장애물 조종하기%1', maze_james_heart: '하트 날리기%1', maze_step_if_5: '만약 앞에 길이 없다면%2', maze_step_if_6: '만약 앞에 %1이 없다면%2', maze_step_if_7: '만약 앞에 %1이 있다면%2', maze_step_if_8: '만약 %1이라면%2', maze_step_if_else: '만약 %1이라면%2 %3 아니면', test_wrapper: '%1 this is test block %2', basic_button: '%1', ai_move_right: '앞으로 가기 %1', ai_move_up: '위쪽으로 가기 %1', ai_move_down: '아래쪽으로 가기 %1', ai_repeat_until_reach: '목적지에 도달 할 때까지 반복하기 %1', ai_if_else_1: '만약 앞에 %1가 있다면 %2 %3 아니면', ai_boolean_distance: '%1 레이더 %2 %3', ai_distance_value: '%1 레이더', ai_boolean_object: '%1 물체는 %2 인가?', ai_use_item: '아이템 사용 %1', ai_boolean_and: '%1 %2 %3', ai_True: '%1', ai_if_else: '만일 %1 (이)라면 %2 %3 아니면', smartBoard_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값', smartBoard_get_named_sensor_value: '%1 센서값', smartBoard_is_button_pressed: '%1 버튼을 눌렀는가?', smartBoard_set_dc_motor_direction: '%1 DC 모터를 %2 방향으로 정하기 %3', smartBoard_set_dc_motor_speed: '%1 DC모터를 %2 %3', smartBoard_set_dc_motor_pwm: '%1 DC모터를 %2 속도로 돌리기 %3', smartBoard_set_servo_speed: '%1 번 서보모터의 속도를 %2 %3', smartBoard_set_servo_angle: '%1 번 서보모터를 %2 도 로 움직이기 %3', smartBoard_set_number_eight_pin: '%1 포트를 %2 %3', smartBoard_set_gs1_pwm: 'GS1 포트의 PWM을 %1 로 정하기 %2', robotori_digitalInput: '%1', robotori_analogInput: '%1', robotori_digitalOutput: '디지털 %1 핀, 출력 값 %2 %3', robotori_analogOutput: '아날로그 %1 %2 %3', robotori_servo: '서보모터 각도 %1 %2', robotori_dc_direction: 'DC모터 %1 회전 %2 %3', dadublock_get_analog_value: '아날로그 %1 번 센서값', dadublock_get_analog_value_map: '아날로그 %1번 센서값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값', dadublock_get_ultrasonic_value: '울트라소닉 Trig %1번핀 Echo %2번핀 센서값', dadublock_toggle_led: '디지털 %1 번 핀 %2 %3', dadublock_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', dadublock_set_tone: '디지털 %1 번 핀을 %2 음으로 %3 옥타브로 %4 만큼 연주하기 %5', dadublock_set_servo: '서보모터 %1 번 핀을 %2 의 각도로 정하기 %3', coconut_stop_motor: '모터 정지 %1', coconut_move_motor: '%1 움직이기 %2', coconut_turn_motor: '%1 으로 돌기 %2', coconut_move_for_secs: '%1 %2 초동안 움직이기 %3', coconut_turn_for_secs: '%1 으로 %2 초동안 돌기 %3', coconut_turn_to_led: '%1 으로 회전하는 동안 %2LED 켜기 %3', coconut_move_outmotor: '외부모터 %1(으로) 움직이기 속도 %2 %3', coconut_set_led_to: '%1 LED를 %2 으로 켜기 %3', coconut_clear_led: '%1 LED 끄기 %2', coconut_set_led_clear: '%1 LED %2 끄기 %3', coconut_set_led_time: '%1 LED %2 으로 %3 초동안 켜기 %4', coconut_beep: '버저 켜기 %1', coconut_buzzer_time: '버저음을 %1 초 동안 소리내기 %2', coconut_buzzer_set_hz: '버즈음 %1 Hz를 %2초 동안 소리내기 %3', coconut_clear_buzzer: '버저 끄기 %1', coconut_play_buzzer: '%1 %2 %3 음을 %4 박자로 연주하기 %5', coconut_rest_buzzer: '%1 동안 쉬기 %2', coconut_play_buzzer_led: '%1 %2 %3 음을 %4 박자로 연주하는 동안 %5 LED %6 켜기 %7', coconut_play_midi: '%1 연주하기 %2', coconut_floor_sensor: '%1 바닥센서', coconut_floor_sensing: '%1 바닥센서 %2', coconut_following_line: '선 따라가기 %1', coconut_front_sensor: '%1 전방센서', coconut_front_sensing: '%1 전방센서 %2', coconut_obstruct_sensing: '장애물 감지', coconut_avoid_mode: '어보이드 모드 %1', coconut_dotmatrix_set: '도트매트릭스 %1 ( %2줄, %3칸 ) %4', coconut_dotmatrix_on: '도트매트릭스 모두 켜기 %1', coconut_dotmatrix_off: '도트매트릭스 모두 끄기 %1', coconut_dotmatrix_num: '도트매트릭스 숫자 %1표시 %2', coconut_dotmatrix_small_eng: '도트매트릭스 소문자 %1표시 %2', coconut_dotmatrix_big_eng: '도트매트릭스 대문자 %1표시 %2', coconut_dotmatrix_kor: '도트매트릭스 한글 %1표시 %2', coconut_light_sensor: '밝기', coconut_tem_sensor: '온도', coconut_ac_sensor: '%1 가속도', coconut_outled_sensor: '외부 LED 설정 %1 %2 초동안 켜기 %3', coconut_outspk_sensor: '외부 스피커 설정 %1 %2Hz로 %3초 동안 소리내기 %4', coconut_outspk_sensor_off: '외부 스피커 %1 끄기 %2', coconut_outinfrared_sensor: '외부 적외선센서 %1', coconut_outcds_sensor: '외부 빛센서(Cds) %1', coconut_servomotor_angle: '서보모터 연결 %1 각도 %2 %3', chocopi_control_button: '%1 컨트롤 %2번을 누름', chocopi_control_event: '%1 %2 컨트롤 %3을 %4', chocopi_control_joystick: '%1 컨트롤 %2의 값', chocopi_dc_motor: '%1 DC모터 %2 %3% 세기 %4 방향 %5', chocopi_led: '%1 LED %2 RGB(%3 %4 %5) %6', chocopi_motion_photogate_event: '%1 %2 포토게이트 %3번을 %4', chocopi_motion_photogate_status: '%1 포토게이트 %2번이 막힘', chocopi_motion_photogate_time: '%1 포토게이트%2번을 %3', chocopi_motion_value: '%1 모션 %2의 값', chocopi_sensor: '%1 센서 %2', chocopi_servo_motor: '%1 서보모터 %2번 %3도 %4', chocopi_touch_event: '%1 %2 터치 %3번을 %4', chocopi_touch_status: '%1 터치 %2번을 만짐', chocopi_touch_value: '%1 터치 %2번의 값', dadublock_car_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', dadublock_car_get_analog_value: '아날로그 %1 번 센서값', dadublock_car_get_analog_value_map: '아날로그 %1번 센서값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', dadublock_car_get_digital: '디지털 %1 번 센서값', dadublock_car_get_irsensor: '적외선 %1 번 센서값', dadublock_car_get_ultrasonic_value: '울트라소닉 Trig %1번핀 Echo %2번핀 센서값', dadublock_car_motor: '모터 %1 번을 %2 (으)로 %3 %의 속도로 움직이기 %4', dadublock_car_motor_stop: '모터 %1 번 멈추기 %2', dadublock_car_set_servo: '서보모터 %1 번 핀을 %2 의 각도로 정하기 %3', dadublock_car_set_tone: '디지털 %1 번 핀 을 %2 음으로 %3의 옥타브로 %4 만큼 연주하기 %5', dadublock_car_toggle_led: '디지털 %1 번 핀 %2 %3', dadublock_get_digital: '디지털 %1 번 센서값', ev3_get_sensor_value: '%1 의 값', ev3_touch_sensor: '%1 의 터치센서가 작동되었는가?', ev3_color_sensor: '%1 의 %2 값', ev3_motor_power: '%1 의 값을 %2 으로 출력 %3', ev3_motor_power_on_time: '%1 의 값을 %2 초 동안 %3 으로 출력 %4', ev3_motor_degrees: '%1 의 값을 %2 으로 %3 도 만큼 회전 %4', rokoboard_get_sensor_value_by_name: '%1 의 센서값', ardublock_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', ardublock_get_analog_value: '아날로그 %1 번 센서값', ardublock_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', ardublock_get_digital: '디지털 %1 번 센서값', ardublock_get_left_cds_analog_value: '왼쪽 조도센서 %1 센서값', ardublock_get_right_cds_analog_value: '오른쪽 조도센서 %1 센서값', ardublock_get_sound_analog_value: '사운드(소리) 센서 %1 센서값', ardublock_get_ultrasonic_value: '초음파센서 Trig %1 Echo %2 센서값', ardublock_set_left_motor: '왼쪽모터를 %1 으로 %2 회전 속도로 정하기 %3', ardublock_set_right_motor: '오른쪽모터를 %1 으로 %2 회전 속도로 정하기 %3', ardublock_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', ardublock_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', ardublock_toggle_led: '디지털 %1 번 핀 %2 %3', ardublock_toggle_left_led: '왼쪽 라이트 %1 번 핀 %2 %3', ardublock_toggle_right_led: '오른쪽 라이트 %1 번 핀 %2 %3', mkboard_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', mkboard_get_analog_value: '아날로그 %1 번 센서값', mkboard_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', mkboard_get_digital: '디지털 %1 번 센서값', mkboard_get_ultrasonic_value: '초음파센서 Trig %1 Echo %2 센서값', mkboard_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', mkboard_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', mkboard_toggle_led: '디지털 %1 번 핀 %2 %3', mkboard_set_lcd: '1602 문자 LCD %1 행 , %2열에 %3 출력하기 %4', mkboard_lcd_command: '1602 문자 LCD %1 명령실행하기 %2', altino_analogValue: '알티노 %1 센서값', altino_dot_display: '전광판에 %1 글자 표시하기 %2', altino_dot_display_line: '1열 %1 2열 %2 3열 %3 4열 %4 5열 %5 6열 %6 7열 %7 8열 %8 출력하기 %9', altino_light: '%1 등을 %2 %3', altino_rear_wheel: '뒷바퀴 오른쪽 %1 왼쪽 %2 로 정하기 %3', altino_sound: '%1 옥타브 %2 음을 연주하기 %3', altino_steering: '방향을 %1 로 정하기 %2', jdkit_altitude: '드론을 %1 높이만큼 날리기 %2', jdkit_button: '%1번 버튼 값 읽어오기', jdkit_connect: '드론 연결 상태 읽어오기', jdkit_emergency: '드론을 즉시 멈추기 %1', jdkit_gyro: '보드 %1 기울기 값 읽어오기', jdkit_joystick: '조이스틱 %1 읽기', jdkit_led: '%1 LED %2 %3', jdkit_motor: '%1 모터를 %2 세기로 돌리기 %3', jdkit_ready: '드론 비행 준비 상태 읽어오기', jdkit_rollpitch: '드론을 %1 방향 %2 세기로 움직이기 %3', jdkit_throttle: '드론 프로펠러를 %1 만큼 세기로 돌리기 %2', jdkit_tune: '%1 음을 %2 초동안 소리내기 %3', jdkit_ultrasonic: '거리(초음파)값 읽어오기', jdkit_yaw: '드론을 %1 만큼 회전하기 %2', memaker_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', memaker_get_analog_value: '아날로그 %1 번 센서값', memaker_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', memaker_get_digital: '디지털 %1 번 센서값', memaker_get_ultrasonic_value: '초음파센서 Trig %1 Echo %2 센서값', memaker_set_lcd: '1602 문자 LCD %1 행 , %2열에 %3 출력하기 %4', memaker_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', memaker_toggle_led: '디지털 %1 번 핀 %2 %3', memaker_lcd_command: '1602 문자 LCD %1 명령실행하기 %2', edumaker_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', edumaker_get_analog_value: '아날로그 %1 번 센서값', edumaker_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', edumaker_get_digital: '디지털 %1 번 센서값', edumaker_get_ultrasonic_value: '울트라소닉 Trig %1 Echo %2 센서값', edumaker_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', edumaker_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', edumaker_toggle_led: '디지털 %1 번 핀 %2 %3', creamo_get_number_sensor_value: '가변저항_블록 %1 번 센서값 ', creamo_get_port_number: '%1', creamo_get_pwm_port_number: '%1 ', creamo_motor_port_number: '%1', creamo_toggle_led: 'LED_블록 %1 번 핀 %2 %3', creamo_toggle_motor: 'Motor_블록 %1 번 핀 %2 %3', creamo_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', mechatro_get_dc_motor_current: '%1모터 사용전류값', mechatro_get_digital: '%1 디지털 값', mechatro_get_sensor_value: '%1 센서값', mechatro_get_ultrasonic_value: '초음파센서 Trig %1 Echo %2 의 거리값 [cm]', mechatro_set_blue_pw: '블루투스 비밀번호 : %1%2%3%4로 정하기%5', mechatro_set_dc_motor: '%1모터 속도 %2로 정하기%3', mechatro_set_digital: '%1번 %2 %3', mechatro_set_pwm: '%1PWM을 %2%로 정하기 %3', mechatro_set_servo_position: '%1서보모터 위치 :%2도로 옮기기 %3', mechatro_set_servo_speed: '%1서보모터 속도 : 1초당 %2도로 정하기 %3', mechatro_set_threshold: '%1 센서 감도 : %2로 정하기%3', mechatro_set_tone: '%1버저 %2 %3 음으로 연주 %4', mechatro_set_tone_time: '%1버저 %2 %3 음으로 %4 초 연주 %5', funboard_buzzer_onoff: '버저 %1 %2', funboard_buzzer_second: '버저%1%2초 동안%3', funboard_buzzer_tone_simple: '%1%2음을%3초 연주하기%4', funboard_color_led_on_pwm: '%1색 LED %2 % %3', funboard_color_led_onoff: '%1색 LED %2 %3', funboard_convert_scale: '%1값 %2~%3 에서 %4~%5 으로 변환값', funboard_dotmatrix_1column: '%1칸 %2표시하기 %3', funboard_dotmatrix_1row: '%1줄 %2표시하기 %3', funboard_dotmatrix_1row_1column: '%1%2 %3표시하기 %4', funboard_dotmatrix_64_display: '%1 (8x8)표시하기%2', funboard_dotmatrix_big_eng: '대문자 %1표시하기 %2', funboard_dotmatrix_char_display: '문자%1표시하기%2', funboard_dotmatrix_extra_char: '문자 %1표시하기 %2', funboard_dotmatrix_intensity: '밝기 %1% %2', funboard_dotmatrix_kor: '▦ 한글 %1표시하기 %2', funboard_dotmatrix_num: '숫자 %1표시하기 %2', funboard_dotmatrix_onoff: '모두 %1 %2', funboard_dotmatrix_scroll_option: '스크롤 방향%1%2', funboard_dotmatrix_scroll_rapid: '스크롤 속도 %1% %2', funboard_dotmatrix_set: '%1줄 %2칸 %3 %4', funboard_dotmatrix_small_eng: '소문자 %1표시하기 %2', funboard_dotmatrix_string_display: '문자열%1표시하기%2', funboard_dotmatrix_string_display_scroll: '문자열%1표시하기%2스크롤%3', funboard_dotmatrix_symbol: '기호 %1표시하기 %2', funboard_get_analog_sensor_2state: '%1값 %2', funboard_get_digital_button_value: '%1 버튼 값', funboard_get_number_sensor_value: '%1 값', funboard_get_touch_button_value: '%1 터치 값', funboard_set_digital_buzzer: '버저를 %1옥타브 %2음 %3초 연주%4', funboard_what_button_pressed: '%1 버튼 눌림', funboard_what_touch_button_pressed: '%1 터치됨', }; Lang.TextCoding = { block_name: '블록명', title_syntax: '문법오류 ', title_converting: '변환오류', message_syntax_default: '문법에 오류가 있습니다', message_syntax_unexpected_token: '문법에 맞지 않는 토큰이 포함되어 있습니다', message_syntax_reserved_token: '사용할 수 없는 변수명입니다.', message_syntax_reserved_token_list: '사용할 수 없는 리스트명입니다.', message_syntax_unexpected_character: '문법에 맞지 않는 문자가 포함되어 있습니다', message_syntax_unexpected_indent: '문법에 맞지 않는 띄어쓰기가 포함되어 있습니다', message_conv_default: '지원하지 않는 코드입니다', message_conv_no_support: '변환될 수 없는 코드입니다', message_conv_no_variable: '변수가 선언되지 않았습니다', message_conv_no_list: '리스트가 선언되지 않았습니다', message_conv_no_object: '객체는 지원되지 않습니다', message_conv_no_function: '함수가 변환될 수 없습니다', message_conv_no_entry_event_function: '엔트리 이벤트 함수는 다른 함수 안에 존재할 수 없습니다.', message_conv_undefined_function: '정의되지 않은 명령어 입니다. 명령어가 올바르게 입력되었는지 확인해주세요.', message_conv_is_expect1: '올바르지 않은 문법입니다. ', message_conv_is_expect2: ' 가 올바르게 입력되었는지 확인해주세요.', message_conv_instead: '올바르지 않은 문법입니다. %1 대신 %2 가 필요합니다.', message_conv_is_wrong1: '올바르지 않은 문법입니다. ', message_conv_is_wrong2: '(은/는) 올 수 없는 위치입니다.', message_conv_or: ' 나 ', subject_syntax_default: '기타', subject_syntax_token: '토큰', subject_syntax_character: '문자', subject_syntax_indent: '띄워쓰기', subject_conv_default: '기타', subject_conv_general: '일반', subject_conv_variable: '변수', subject_conv_list: '리스트', subject_conv_object: '객체', subject_conv_function: '함수', alert_variable_empty_text: '등록된 변수 중에 공백(띄어쓰기)이 포함된 변수가 있으면 모드 변환을 할 수 없습니다.', alert_list_empty_text: '등록된 리스트 중에 공백(띄어쓰기)이 포함된 리스트가 있으면 모드 변환을 할 수 없습니다.', alert_function_name_field_multi: '등록된 함수 중에 함수 이름에 [이름] 블록이 두번이상 포함되어 있으면 모드 변환을 할 수 없습니다.', alert_function_name_disorder: '등록된 함수 중에[이름] 블록이 [문자/숫자값] 또는 [판단값] 블록보다 뒤에 쓰이면 모드 변환을 할 수 없습니다.', alert_function_has_boolean: '엔트리파이선으로 변환 후 다시 블록코딩으로 모드로 변경하면 함수에 사용된 [판단값]은 모두 [문자/숫자형]으로 변환됩니다.', alert_function_editor: '함수 생성 및 편집 중에는 모드 변환을 할 수 없습니다.', alert_function_no_support: '텍스트모드에서는 함수 생성 및 편집을 할 수 없습니다.', alert_list_no_support: '텍스트모드에서는 리스트 생성 및 편집을 할 수 없습니다.', alert_variable_no_support: '텍스트모드에서는 변수 생성 및 편집을 할 수 없습니다.', alert_signal_no_support: '텍스트모드에서는 신호 생성 및 편집을 할 수 없습니다.', alert_legacy_no_support: '전환할 수 없는 블록이 존재하여 모드 변환을 할 수 없습니다.', alert_variable_empty_text_add_change: '변수명 공백(띄어쓰기)이 포함될 수 없습니다.', alert_list_empty_text_add_change: '리스트명에 공백(띄어쓰기)이 포함될 수 없습니다.', alert_list_contains_exceed_length_value: '리스트 항목에 15자리 이상의 수가 입력되어 있으면 모드 변환을 할 수 없습니다.', alert_function_name_empty_text_add_change: '함수명에 공백(띄어쓰기)이 포함될 수 없습니다.', alert_no_save_on_error: '문법 오류가 존재하여 작품을 저장할 수 없습니다.', alert_api_no_support: '작품에 엔트리파이썬에서 지원하지 않는 \n블록이 조립되어 있습니다. \n해당 블록을 삭제하고 만들기 모드를 변경할까요?', warn_unnecessary_arguments: '&(calleeName)(); 는 괄호 사이에 값이 입력될 필요가 없는 명령어 입니다. (line:&(lineNumber))', python_code: ' 오브젝트의 파이선 코드', eof: '줄바꿈', newline: '줄바꿈', indent: '들여쓰기', num: '숫자', string: '문자열', name: '변수명', }; Lang.PythonHelper = { when_run_button_click_desc: '[시작하기]버튼을 클릭하면 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_run_button_click_exampleCode: 'def when_start():\n Entry.print("안녕!")', when_run_button_click_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕!"이라 말합니다.', when_some_key_pressed_desc: 'A키를 누르면 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_some_key_pressed_elements: 'A-- 아래 선택지 중 하나
① 알파벳 : "A", "B" ~ "Z" 등(소문자 가능)
② 숫자 : 1, 2, 3, 4 ~ 9, 0
③ 특수키 : "space", "enter"
④ 방향키 : "up", "down", "right", "left"', when_some_key_pressed_exampleCode: 'def when_press_key("W"):\n Entry.move_to_direction(10)\n\ndef when_press_key(1):\n Entry.add_size(10)', when_some_key_pressed_exampleDesc: 'W키를 누르면 오브젝트가 이동방향으로 10만큼 이동하고, 1키를 누르면 오브젝트의 크기가 10만큼 커집니다.', mouse_clicked_desc: '마우스를 클릭했을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', mouse_clicked_exampleCode: 'def when_click_mouse_on():\n Entry.add_size(10)\n Entry.move_to_direction(10)', mouse_clicked_exampleDesc: '마우스를 클릭하면 오브젝트의 크기가 10만큼 커지면서 이동방향으로 10만큼 이동합니다.', mouse_click_cancled_desc: '마우스 클릭을 해제했을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', mouse_click_cancled_exampleCode: 'def when_click_mouse_off():\n Entry.move_to_direction(-10)\n\ndef when_click_mouse_on():\n Entry.move_to_direction(10)', mouse_click_cancled_exampleDesc: '마우스를 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 마우스 클릭을 해제하면 오브젝트가 이동방향으로 -10만큼 이동합니다.', when_object_click_desc: '해당 오브젝트를 클릭했을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_object_click_exampleCode: 'def when_click_object_on():\n Entry.print_for_sec("회전!", 0.5)\n Entry.add_rotation(90)', when_object_click_exampleDesc: '오브젝트를 클릭하면 오브젝트가 "회전!"이라 말하고, 90도 만큼 회전합니다.', when_object_click_canceled_desc: '해당 오브젝트 클릭을 해제했을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_object_click_canceled_exampleCode: 'def when_click_object_on():\n Entry.add_rotation(90)\n\ndef when_click_object_off():\n Entry.add_rotation(-90)', when_object_click_canceled_exampleDesc: '오브젝트를 클릭하면 오브젝트가 90도 만큼 회전하고, 오브젝트 클릭을 해제하면 오브젝트가 -90도 만큼 회전합니다.', when_message_cast_desc: 'A 신호를 받으면 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.
만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.', when_message_cast_elements: 'A-- "신호 이름"', when_message_cast_exampleCode: 'def when_click_mouse_on():\n Entry.send_signal("신호")\n\ndef when_get_signal("신호"):\n Entry.print_for_sec("안녕! 반가워", 0.5)', when_message_cast_exampleDesc: '마우스를 클릭하면 "신호"를 보내고, "신호"를 받았을때 "안녕! 반가워"라고 0.5초간 말합니다.', message_cast_desc: 'A에 입력된 신호를 보냅니다.
만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.', message_cast_elements: 'A-- "신호 이름"', message_cast_exampleCode: '#"오브젝트1"의 파이선 코드\ndef when_start():\n Entry.print_for_sec("안녕! 넌 몇살이니?", 2)\n Entry.send_signal("신호")\n\n#"오브젝트2"의 파이선 코드\ndef when_get_signal("신호"):\n Entry.print_for_sec("안녕? 난 세 살이야.", 2)', message_cast_exampleDesc: '[시작하기]버튼을 클릭하면 "오브젝트1"이 "안녕! 넌 몇살이니?"라고 2초간 말하고 "신호를 보냅니다., "오브젝트2"가 "신호"를 받았을때 "안녕? 난 세 살이야."라고 2초간 말합니다.', message_cast_wait_desc: 'A에 입력된 신호를 보내고, 해당 신호를 받는 명령어들의 실행이 끝날 때까지 기다립니다.
만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.', message_cast_wait_elements: 'A-- "신호 이름"', message_cast_wait_exampleCode: '#"오브젝트1"의 파이선 코드\ndef when_start():\n Entry.print_for_sec("숨바꼭질하자!", 2)\n Entry.send_signal_wait("신호")\n Entry.hide()\n\n#"오브젝트2"의 파이선 코드\ndef when_get_signal("신호"):\n Entry.print_for_sec("그래!", 2)', message_cast_wait_exampleDesc: '[시작하기]버튼을 클릭하면 "오브젝트1"이 "숨바꼭질하자!"라고 2초 동안 말하고 "신호"를 보낸 후 기다립니다. "오브젝트2"가 "신호"를 받으면 "그래!"를 2초 동안 말합니다. "오브젝트1"이 그 후에 모양을 숨깁니다.', when_scene_start_desc: '장면이 시작되면 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_scene_start_exampleCode: '#"장면 1"의 파이선 코드\ndef when_start():\n Entry.print_for_sec("다른 곳으로 가볼까?", 2)\n Entry.start_scene("장면 2")\n\n#"장면 2"의 파이선 코드\ndef when_start_scene():\n Entry.print("여기가 어디지?")', when_scene_start_exampleDesc: '"장면 1"에서 [시작하기]버튼을 클릭하면 "다른 곳으로 가볼까?"라고 2초간 말하고, "장면 2"가 시작됩니다. "장면 2"가 시작되면 오브젝트가 "여기가 어디지?"라고 말합니다.', start_scene_desc: 'A 장면을 시작합니다.', start_scene_elements: 'A-- "장면 이름"', start_scene_exampleCode: '#"장면 1"의 파이선 코드\ndef when_click_object_on():\n Entry.start_scene("장면 2")', start_scene_exampleDesc: '"장면 1"에서 해당 오브젝트를 클릭하면 "장면 2"가 시작됩니다.', start_neighbor_scene_desc: 'A에 입력한 다음 또는 이전 장면을 시작합니다.', start_neighbor_scene_elements: 'A-- 아래 선택지 중 하나
① 다음 장면: "next" 또는 "다음"
② 이전 장면: "prev" 또는 "이전"', start_neighbor_scene_exampleCode: '#"장면 1"의 파이선 코드\ndef when_press_key("right"):\n Entry.start_scene_of("next")\n\n#"장면 2"의 파이선 코드\ndef when_press_key("left"):\n Entry.start_scene_of("prev")', start_neighbor_scene_exampleDesc: '"장면 1"에서 오른쪽화살표키를 누르면 다음 장면이, "장면 2"에서 왼쪽화살표키를 누르면 이전 장면이 시작됩니다.', wait_second_desc: 'A초만큼 기다린 후 다음 블록을 실행합니다.', wait_second_elements: 'A-- 초에 해당하는 수 입력', wait_second_exampleCode: 'def when_start():\n Entry.add_effect("color", 10)\n Entry.wait_for_sec(2)\n Entry.add_size(10)', wait_second_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트에 색깔효과를 10만큼 주고, 2초동안 기다린 다음 크기를 10만큼 커지게 합니다.', repeat_basic_desc: '아래 명령어들을 A번 반복하여 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', repeat_basic_elements: 'A-- 반복할 횟수 입력', repeat_basic_exampleCode: 'def when_start():\n for i in range(10):\n Entry.move_to_direction(10)\n Entry.stamp()', repeat_basic_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 도장찍는 행동을 10번 반복합니다.', repeat_inf_desc: 'A 판단이 True인 동안 아래 명령어들을 반복 실행합니다. A에 True를 입력하면 계속 반복됩니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', repeat_inf_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', repeat_inf_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n Entry.bounce_on_edge()', repeat_inf_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 계속해서 이동방향으로 10만큼 이동하고, 벽에 닿으면 튕깁니다.', repeat_while_true_desc: 'A 판단이 True가 될 때까지 아래 명령어들을 반복 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', repeat_while_true_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', repeat_while_true_exampleCode: 'def when_start():\n while not Entry.is_key_pressed("space"):\n Entry.add_rotation(90)', repeat_while_true_exampleDesc: '[시작하기]버튼을 클릭하면 스페이스키를 누를때까지 오브젝트가 90도 만큼 회전합니다.', stop_repeat_desc: '이 명령어와 가장 가까운 반복 명령어의 반복을 중단합니다.', stop_repeat_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n if Entry.is_key_pressed("enter"):\n break', stop_repeat_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 계속 이동합니다. 엔터키를 누르면 반복이 중단됩니다.', _if_desc: 'A 부분의 판단이 True이면 if A:아래 명령어들을 실행하고, False이면 실행하지 않습니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', _if_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', _if_exampleCode: 'def when_click_mouse_on():\n if (Entry.value_of_mouse_pointer("x") > 0):\n Entry.print_for_sec("오른쪽!", 0.5)', _if_exampleDesc: '마우스를 클릭했을 때 마우스 x좌표가 0보다 크면 오브젝트가 "오른쪽!"이라고 0.5초 동안 말합니다.', if_else_desc: 'A 부분의 판단이 True이면 if A: 아래 명령어들을 실행하고, False이면 else: 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', if_else_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', if_else_exampleCode: 'def when_click_mouse_on():\n if Entry.is_touched("mouse_pointer"):\n Entry.print("닿았다!")\n else:\n Entry.print("안 닿았다!")', if_else_exampleDesc: '마우스를 클릭했을 때 마우스포인터가 오브젝트에 닿았으면 "닿았다!"를 그렇지 않으면 "안 닿았다!"를 말합니다.', wait_until_true_desc: 'A 부분의 판단이 True가 될 때까지 코드의 실행을 멈추고 기다립니다.', wait_until_true_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', wait_until_true_exampleCode: 'def when_start():\n Entry.print("엔터를 눌러봐!")\n Entry.wait_until(Entry.is_key_pressed("enter"))\n Entry.print("잘했어!")', wait_until_true_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "엔터를 눌러봐!"라 말하고, 엔터키를 누를 때까지 기다립니다. 엔터키를 누르면 "잘했어!"라 말합니다.', stop_object_desc: 'A코드의 실행을 중지합니다.', stop_object_elements: 'A-- 아래 선택지 중 하나
① "all": 모든 오브젝트의 모든 코드
② "self" : 해당 오브젝트의 모든 코드
③ "this": 이 명령어가 포함된 코드
④ "others" : 해당 오브젝트의 코드 중 이 명령어가 포함된 코드를 제외한 모든 코드
⑤ "ohter_objects" : 이 오브젝트를 제외한 다른 모든 오브젝트의 코드', stop_object_exampleCode: 'def when_start():\n while True:\n Entry.move_to("mouse_pointer")\n\ndef when_press_key("space"):\n Entry.stop_code("all")\n', stop_object_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 계속해서 마우스포인터 위치로 이동합니다. 스페이스키를 누르면 모든 코드의 실행이 중지됩니다.', restart_project_desc: '작품을 처음부터 다시 실행합니다.', restart_project_exampleCode: 'def when_start():\n while True:\n Entry.add_size(10)\n\ndef when_press_key("enter"):\n Entry.start_again()', restart_project_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트의 크기가 커집니다. 엔터키를 누르면 작품을 처음부터 다시 실행합니다.', when_clone_start_desc: '해당 오브젝트의 복제본이 새로 생성되었을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_clone_start_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("self")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))', when_clone_start_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다.', create_clone_desc: 'A 오브젝트의 복제본을 생성합니다.', create_clone_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "self" 또는 "자신"', create_clone_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("self")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))', create_clone_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다.', delete_clone_desc: 'Entry.make_clone_of(A) 명령에 의해 생성된 복제본을 삭제합니다.', delete_clone_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("자신")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))\n\ndef when_click_object_on():\n Entry.remove_this_clone()', delete_clone_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다. 복제본을 클릭하면 클릭된 복제본을 삭제합니다.', remove_all_clones_desc: '해당 오브젝트의 모든 복제본을 삭제합니다.', remove_all_clones_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("자신")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))\n\ndef when_press_key("space"):\n Entry.remove_all_clone()', remove_all_clones_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다. 스페이스 키를 누르면 모든 복제본을 삭제합니다.', move_direction_desc: 'A만큼 오브젝트의 이동방향 화살표가 가리키는 방향으로 움직입니다.', move_direction_elements: 'A-- 이동할 거리에 해당하는 수', move_direction_exampleCode: 'def when_start():\n Entry.move_to_direction(10)', move_direction_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동합니다.', bounce_wall_desc: '오브젝트가 화면 끝에 닿으면 튕겨져 나옵니다.', bounce_wall_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n Entry.bounce_on_edge()', bounce_wall_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 계속해서 이동방향으로 10만큼 이동하고, 벽에 닿으면 튕깁니다.', move_x_desc: '오브젝트의 x좌표를 A만큼 바꿉니다.', move_x_elements: 'A-- x좌표의 변화 값
① 양수: 오브젝트가 오른쪽으로 이동합니다.
② 음수: 오브젝트가 왼쪽으로 이동합니다.', move_x_exampleCode: 'def when_start():\n Entry.add_x(10)\n Entry.wait_for_sec(2)\n Entry.add_x(-10)', move_x_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오른쪽으로 10만큼 이동하고 2초 동안 기다린 후 왼쪽으로 10만큼 이동합니다.', move_y_desc: '오브젝트의 y좌표를 A만큼 바꿉니다.', move_y_elements: 'A-- y좌표의 변화 값
① 양수: 오브젝트가 위쪽으로 이동합니다.
② 음수: 오브젝트가 아래쪽으로 이동합니다.', move_y_exampleCode: 'def when_start():\n Entry.add_y(10)\n Entry.wait_for_sec(2)\n Entry.add_y(-10)', move_y_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 위쪽으로 10만큼 이동하고 2초 동안 기다린 후 아래쪽으로 10만큼 이동합니다.', move_xy_time_desc: '오브젝트가 x와 y좌표를 각각 A와 B만큼 C초에 걸쳐 서서히 바꿉니다.', move_xy_time_elements: 'A-- x좌표의 변화 값
① 양수: 오브젝트가 오른쪽으로 이동합니다.
② 음수: 오브젝트가 왼쪽으로 이동합니다.%nextB-- y좌표의 변화 값
① 양수: 오브젝트가 위쪽으로 이동합니다.
② 음수: 오브젝트가 아래쪽으로 이동합니다.%nextC-- 이동하는 시간(초)', move_xy_time_exampleCode: 'def when_start():\n Entry.add_xy_for_sec(100, 100, 2)\n Entry.add_xy_for_sec(-100, -100, 2)', move_xy_time_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오른쪽 위로 100만큼 2초 동안 이동한 후 왼쪽 아래로 100만큼 2초 동안 이동합니다.', locate_x_desc: '오브젝트의 x좌표를 A로 정합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_x_elements: 'A-- 이동할 x좌표', locate_x_exampleCode: 'def when_press_key("right"):\n Entry.set_x(100)\n\ndef when_press_key("left"):\n Entry.set_x(-100)\n', locate_x_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 x좌표를 100으로 정하고, 왼쪽화살표키를 누르면 오브젝트의 x좌표를 -100으로 정합니다.', locate_y_desc: '오브젝트의 y좌표를 A로 정합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_y_elements: 'B-- 이동할 y좌표', locate_y_exampleCode: 'def when_press_key("up"):\n Entry.set_y(100)\n\ndef when_press_key("down"):\n Entry.set_y(-100)', locate_y_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 y좌표를 100으로 정하고, 아래쪽화살표키를 누르면 오브젝트의 y좌표를 -100으로 정합니다.', locate_xy_desc: '오브젝트가 좌표(A, B)로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_xy_elements: 'A-- 이동할 x좌표%nextB-- 이동할 y좌표', locate_xy_exampleCode: 'def when_click_mouse_on():\n Entry.set_xy(0, 0)\n\ndef when_press_key("right"):\n Entry.add_x(10)\n\ndef when_press_key("up"):\n Entry.add_y(10)', locate_xy_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 x좌표를 10만큼 바꾸고, 위쪽화살표키를 누르면 오브젝트의 y좌표를 10만큼 바꿉니다. 마우스를 클릭하면 오브젝트의 x, y좌표를 0으로 정합니다.', locate_xy_time_desc: '오브젝트가 좌표(A, B)로 C초에 걸쳐 서서히 이동합니다.(오브젝트의 중심점이 기준이 됩니다.)', locate_xy_time_elements: 'A-- 이동할 x좌표%nextB-- 이동할 y좌표%nextC-- 이동하는 시간', locate_xy_time_exampleCode: 'def when_click_mouse_on():\n Entry.set_xy_for_sec(0, 0, 2)\n\ndef when_press_key("right"):\n Entry.add_x(10)\n\ndef when_press_key("up"):\n Entry.add_y(10)', locate_xy_time_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 x좌표를 10만큼 바꾸고, 위쪽화살표키를 누르면 오브젝트의 y좌표를 10만큼 바꿉니다. 마우스를 클릭하면 2초 동안 오브젝트를 x,y 좌표 0으로 이동시킵니다.', locate_desc: '오브젝트가 A의 위치로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "mouse_pointer" 또는 "마우스포인터"', locate_exampleCode: 'def when_click_mouse_on():\n Entry.move_to("mouse_pointer")\n\ndef when_press_key("space"):\n Entry.move_to("오브젝트")', locate_exampleDesc: '마우스를 클릭하면 오브젝트가 마우스포인터 위치로 이동합니다.
스페이스키를 누르면 오브젝트가 "오브젝트" 위치로 이동합니다.', locate_object_time_desc: '오브젝트가 A의 위치로 B초에 걸쳐 서서히 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_object_time_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "mouse_pointer" 또는 "마우스포인터" %nextB-- 이동하는 시간(초)', locate_object_time_exampleCode: 'def when_click_mouse_on():\n Entry.move_to_for_sec("mouse_pointer", 2)', locate_object_time_exampleDesc: '마우스를 클릭하면 오브젝트가 2초 동안 서서히 마우스포인터 위치로 이동합니다.', rotate_relative_desc: '오브젝트의 방향을 A도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', rotate_relative_elements: 'A-- 회전할 각도', rotate_relative_exampleCode: 'def when_click_object_on():\n Entry.add_rotation(90)\n\ndef when_click_object_off():\n Entry.add_rotation(-90)', rotate_relative_exampleDesc: '오브젝트를 클릭하면 오브젝트가 90도 만큼 회전하고, 오브젝트 클릭을 해제하면 오브젝트가 -90도 만큼 회전합니다.', direction_relative_desc: '오브젝트의 이동 방향을 A도만큼 회전합니다.', direction_relative_elements: 'A-- 회전할 각도', direction_relative_exampleCode: 'def when_start():\n Entry.move_to_direction(50)\n Entry.wait_for_sec(0.5)\n Entry.add_direction(90)\n Entry.wait_for_sec(0.5)\n Entry.move_to_direction(50)', direction_relative_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 50만큼 이동한 다음 0.5초간 기다립니다. 그 후 이동방향을 90도 만큼 회전하고 0.5초간 기다린 후 이동방향으로 50만큼 이동합니다.', rotate_by_time_desc: '오브젝트의 방향을 시계방향으로 A도만큼 B초에 걸쳐 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', rotate_by_time_elements: 'A-- 회전할 각도%nextB-- 회전할 시간(초)', rotate_by_time_exampleCode: 'def when_start():\n Entry.add_rotation_for_sec(90, 2)\n Entry.add_rotation_for_sec(-90, 2)', rotate_by_time_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 2초 동안 90도 만큼 회전하고, 다시 2초 동안 -90도 만큼 회전합니다.', direction_relative_duration_desc: '오브젝트의 이동방향을 시계방향으로 A도만큼 B초에 걸쳐 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', direction_relative_duration_elements: 'A-- 회전할 각도%nextB-- 회전할 시간(초)', direction_relative_duration_exampleCode: 'def when_start():\n Entry.add_direction_for_sec(90, 2)\n\ndef when_start():\n while True:\n Entry.move_to_direction(1)', direction_relative_duration_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트의 이동방향을 2초 동안 90도만큼 회전시킵니다. 동시에 오브젝트는 이동방향으로 1만큼 계속 이동합니다.', rotate_absolute_desc: '오브젝트의 방향을 A로 정합니다.', rotate_absolute_elements: 'A-- 설정할 방향', rotate_absolute_exampleCode: 'def when_press_key("right"):\n Entry.set_rotation(90)\n\ndef when_press_key("left"):\n Entry.set_rotation(270)', rotate_absolute_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 방향을 90으로 정하고, 왼쪽화살표키를 누르면 오브젝트의 방향을 270으로 정합니다.', direction_absolute_desc: '오브젝트의 이동방향을 A로 정합니다.', direction_absolute_elements: 'A-- 설정할 이동방향', direction_absolute_exampleCode: 'def when_press_key("right"):\n Entry.set_direction(90)\n Entry.move_to_direction(10)\n\ndef when_press_key("left"):\n Entry.set_direction(270)\n Entry.move_to_direction(10)', direction_absolute_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 이동방향을 90으로 정한 후 해당 쪽으로 10만큼 이동하고, 왼쪽화살표키를 누르면 오브젝트의 이동방향을 270으로 정하고 해당쪽으로 10만큼 이동합니다.', see_angle_object_desc: '오브젝트가 A쪽을 바라봅니다. (이동방향이 A를 향하도록 오브젝트의 방향을 회전해줍니다.)', see_angle_object_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "mouse_pointer" 또는 "마우스포인터"', see_angle_object_exampleCode: 'def when_click_mouse_on():\n Entry.look_at("mouse_pointer")\n\ndef when_press_key("space"):\n Entry.look_at("오브젝트")', see_angle_object_exampleDesc: '마우스를 클릭하면 오브젝트가 마우스포인터쪽을 바라보고, 스페이스키를 누르면 "오브젝트"쪽을 바라봅니다.', move_to_angle_desc: '오브젝트가 A만큼 B방향으로 움직입니다.', move_to_angle_elements: 'A-- 이동할 거리에 해당하는 수%nextB-- 이동할 방향(12시 방향이 0도, 시계방향으로 증가)', move_to_angle_exampleCode: 'def when_press_key("up"):\n Entry.move_to_degree(10, 0)\n\ndef when_press_key("down"):\n Entry.move_to_degree(10, 180)', move_to_angle_exampleDesc: '위쪽화살표키를 누르면 오브젝트가 0도방향으로 10만큼 이동하고, 아래쪽화살표키를 누르면 오브젝트가 180도방향으로 10만큼 이동합니다.', show_desc: '오브젝트를 화면에 나타냅니다.', show_exampleCode: 'def when_start():\n Entry.wait_for_sec(1)\n Entry.hide()\n Entry.wait_for_sec(1)\n Entry.show()', show_exampleDesc: '[시작하기]버튼을 클릭하면 1초 뒤에 오브젝트 모양이 숨겨지고, 다음 1초 뒤에 오브젝트 모양이 나타납니다.', hide_desc: '오브젝트를 화면에서 보이지 않게 합니다.', hide_exampleCode: 'def when_start():\n Entry.wait_for_sec(1)\n Entry.hide()\n Entry.wait_for_sec(1)\n Entry.show()', hide_exampleDesc: '[시작하기]버튼을 클릭하면 1초 뒤에 오브젝트 모양이 숨겨지고, 다음 1초 뒤에 오브젝트 모양이 나타납니다.', dialog_time_desc: '오브젝트가 A를 B초 동안 말풍선으로 말한 후 다음 명령어가 실행됩니다. 콘솔창에서도 실행 결과를 볼 수 있습니다.', dialog_time_elements: 'A-- 말할 내용
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등%nextB-- 말하는 시간(초)', dialog_time_exampleCode: 'def when_start():\n Entry.print_for_sec("안녕! 나는", 2)\n Entry.print_for_sec(16, 2)\n Entry.print_for_sec("살이야", 2)', dialog_time_exampleDesc: '[시작하기]버튼을 클릭하면 "안녕! 나는", 16, "살이야"를 각각 2초 동안 차례대로 말합니다.', dialog_desc: '오브젝트가 A를 말풍선으로 말합니다. 콘솔창에서도 실행 결과를 볼 수 있습니다.', dialog_elements: 'A-- 말할 내용
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', dialog_exampleCode: 'def when_start():\n Entry.print("키보드로 숫자 1,2 를 누르면 숫자를 말해볼게")\n\ndef when_press_key(1):\n Entry.print(1)\n\ndef when_press_key(2):\n Entry.print(2)\n', dialog_exampleDesc: '[시작하기]버튼을 클릭하면 "키보드로 숫자 1,2 를 누르면 숫자를 말해볼게"를 말하고, 키보드로 1, 2를 누르면 각각 1, 2라 말합니다.', remove_dialog_desc: '오브젝트가 말하고 있는 말풍선을 지웁니다.', remove_dialog_exampleCode: 'def when_start():\n Entry.print("말풍선을 지우려면 엔터를 눌러!")\n\ndef when_press_key("enter"):\n Entry.clear_print()', remove_dialog_exampleDesc: '[시작하기]버튼을 클릭하면 "말풍선을 지우려면 엔터를 눌러!"라 말하고, 엔터키를 누르면 말풍선이 사라집니다.', change_to_some_shape_desc: '오브젝트를 A 모양으로 바꿉니다.', change_to_some_shape_elements: 'A-- 아래 선택지 중 하나
① 모양 이름 : [속성] 탭의 "모양 이름"을 적음
② 모양 번호 : [속성] 탭의 모양 번호를 적음', change_to_some_shape_exampleCode: 'def when_start():\n Entry.wait_for_sec(0.3)\n Entry.change_shape("오브젝트모양")\n Entry.wait_for_sec(0.3)\n Entry.change_shape("오브젝트모양")', change_to_some_shape_exampleDesc: '[시작하기]버튼을 클릭하면 0.3초간 기다린 다음 "오브젝트모양"으로 모양을 바꾸고 0.3초간 기다린 다음 "오브젝트모양"모양으로 모양을 바꿉니다.', change_to_next_shape_desc: '오브젝트의 모양을 다음 또는 이전 모양으로 바꿉니다.', change_to_next_shape_elements: 'A-- 아래 선택지 중 하나
① 다음 모양 : "next" 또는 "다음"
② 이전 모양 : "pre" 또는 "이전"', change_to_next_shape_exampleCode: 'def when_start():\n Entry.wait_for_sec(0.3)\n Entry.change_shape_to("next")\n Entry.wait_for_sec(0.3)\n Entry.change_shape_to("pre")', change_to_next_shape_exampleDesc: '[시작하기]버튼을 클릭하면 0.3초간 기다린 다음 모양으로 오브젝트 모양을 바꾸고 0.3초간 기다린 다음 이전 모양으로 오브젝트 모양을 바꿉니다.', add_effect_amount_desc: '오브젝트에 A 효과를 B만큼 줍니다.', add_effect_amount_elements: 'A -- 아래 선택지 중 하나
① “color” 또는 “색깔“
② “brightness” 또는 “밝기”
③ “transparency” 또는 “투명도”%nextB-- 효과의 변화 정도', add_effect_amount_exampleCode: 'def when_click_mouse_on():\n Entry.add_effect("color", 50)\n Entry.wait_for_sec(1)\n Entry.add_effect("brightness", -50)\n Entry.wait_for_sec(1)\n Entry.add_effect("transparency", 50)', add_effect_amount_exampleDesc: '마우스를 클릭하면 오브젝트에 색깔 효과를 50만큼 주고 1초간 기다리고, 밝기 효과를 -50만큼 주고 1초간 기다립니다. 그 후 투명도 효과를 50만큼 줍니다.', change_effect_amount_desc: '오브젝트의 A 효과를 B로 정합니다.', change_effect_amount_elements: 'A-- 아래 선택지 중 하나
① “color” 또는 “색깔“
② “brightness” 또는 “밝기”
③ “transparency” 또는 “투명도”%nextB-- 효과의 값
① color: 0~100 범위의 수, 100을 주기로 반복됨
② brightness: -100~100 사이 범위의 수, -100이하는 -100 으로 100 이상은 100 으로 처리 됨
③ transparency: 0~100 사이 범위의 수, 0 이하는 0으로, 100이상은 100으로 처리 됨', change_effect_amount_exampleCode: 'def when_click_mouse_on():\n Entry.set_effect("color", 50)\n Entry.set_effect("brightness", 50)\n Entry.set_effect("transparency", 50)\n\ndef when_click_mouse_off():\n Entry.set_effect("color", 0)\n Entry.set_effect("brightness", 0)\n Entry.set_effect("transparency", 0)', change_effect_amount_exampleDesc: '마우스를 클릭하면 오브젝트에 색깔, 밝기, 투명도 효과를 50으로 정하고, 마우스 클릭을 해제하면 각 효과를 0으로 정합니다.', erase_all_effects_desc: '오브젝트에 적용된 효과를 모두 지웁니다.', erase_all_effects_exampleCode: 'def when_click_mouse_on():\n Entry.set_effect("color", 50)\n Entry.set_effect("brightness", 50)\n Entry.set_effect("transparency", 50)\n\ndef when_click_mouse_off():\n Entry.clear_effect()\n', erase_all_effects_exampleDesc: '마우스를 클릭하면 오브젝트에 색깔, 밝기, 투명도 효과를 50으로 정하고, 마우스 클릭을 해제하면 오브젝트에 적용된 모든 효과를 지웁니다.', change_scale_size_desc: '오브젝트의 크기를 A만큼 바꿉니다.', change_scale_size_elements: 'A-- 크기 변화 값', change_scale_size_exampleCode: 'def when_press_key("up"):\n Entry.add_size(10)\n\ndef when_press_key("down"):\n Entry.add_size(-10)\n\ndef when_press_key("space"):\n Entry.set_size(100)', change_scale_size_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 크기가 10만큼 커지고, 아래쪽화살표키를 누르면 오브젝트의 크기가 10만큼 작아집니다. 스페이스키를 누르면 오브젝트의 크기를 100으로 정합니다.', set_scale_size_desc: '오브젝트의 크기를 A로 정합니다.', set_scale_size_elements: 'A-- 크기값', set_scale_size_exampleCode: 'def when_press_key("up"):\n Entry.add_size(10)\n\ndef when_press_key("down"):\n Entry.add_size(-10)\n\ndef when_press_key("space"):\n Entry.set_size(100)', set_scale_size_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 크기가 10만큼 커지고, 아래쪽화살표키를 누르면 오브젝트의 크기가 10만큼 작아집니다. 스페이스키를 누르면 오브젝트의 크기를 100으로 정합니다.', flip_x_desc: '오브젝트의 상하 모양을 뒤집습니다.', flip_x_exampleCode: 'def when_press_key("up"):\n Entry.flip_horizontal()\n\ndef when_press_key("right"):\n Entry.flip_vertical()', flip_x_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 상하 모양을 뒤집고, 오른쪽화살표키를 누르면 오브젝트의 좌우 모양을 뒤집습니다.', flip_y_desc: '오브젝트의 좌우 모양을 뒤집습니다.', flip_y_exampleCode: 'def when_press_key("up"):\n Entry.flip_horizontal()\n\ndef when_press_key("right"):\n Entry.flip_vertical()', flip_y_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 상하 모양을 뒤집고, 오른쪽화살표키를 누르면 오브젝트의 좌우 모양을 뒤집습니다.', change_object_index_desc: '오브젝트의 레이어를 A로 가져옵니다.', change_object_index_elements: 'A-- 아래 선택지 중 하나
① “front" 또는 “맨 앞“
② “forward” 또는 “앞”
③ “backward” 또는 “뒤”
④ “back” 또는 “맨 뒤”', change_object_index_exampleCode: 'def when_start():\n Entry.send_layer_to("front")\n Entry.wait_for_sec(2)\n Entry.send_layer_to("backward")', change_object_index_exampleDesc: '오브젝트가 여러개가 겹쳐 있을 경우 [시작하기]버튼을 클릭하면 해당 오브젝트의 레이어를 가장 앞으로 가져와서 보여줍니다.', brush_stamp_desc: '오브젝트의 모양을 도장처럼 실행화면 위에 찍습니다.', brush_stamp_exampleCode: 'def when_start():\n for i in range(10):\n Entry.move_to_direction(10)\n Entry.stamp()', brush_stamp_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 도장찍는 행동을 10번 반복합니다.', start_drawing_desc: '오브젝트가 이동하는 경로를 따라 선이 그려지기 시작합니다. (오브젝트의 중심점이 기준)', start_drawing_exampleCode: 'def when_start():\n Entry.start_drawing()\n for i in range(10):\n Entry.move_to_direction(10)', start_drawing_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 오브젝트가 이동방향으로 10만큼 10번 이동할 때 오브젝트의 이동경로를 따라 선이 그려집니다.', stop_drawing_desc: '오브젝트가 선을 그리는 것을 멈춥니다.', stop_drawing_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(1)\n\ndef when_click_mouse_on():\n Entry.stop_drawing()', stop_drawing_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고 계속해서 오브젝트가 이동방향으로 10만큼 이동합니다. 마우스를 클릭하면 그리는것을 멈춥니다.', set_color_desc: '오브젝트가 그리는 선의 색을 A로 정합니다.', set_color_elements: 'A-- 아래 선택지 중 하나
① 색상 코드 : "#FF0000", "#FFCC00", "#3333FF", "#000000" 등
② 색깔명 : "red", "orange", "yellow", "green", "blue", "navy", "purple", "black", "white", "brown"', set_color_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_color_to("#000099")\n while True:\n Entry.move_to_direction(1)', set_color_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 색을 "#000099"로 정합니다. 오브젝트는 계속해서 이동방향으로 1만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.', set_random_color_desc: '오브젝트가 그리는 선의 색을 무작위로 정합니다.', set_random_color_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(1)\n Entry.set_brush_color_to_random()', set_random_color_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 1만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 색깔은 계속해서 무작위로 정해집니다.', change_thickness_desc: '오브젝트가 그리는 선의 굵기를 A만큼 바꿉니다.', change_thickness_elements: 'A-- 굵기 변화 값', change_thickness_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.add_brush_size(1)\n Entry.move_to_direction(10)', change_thickness_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 굵기는 계속해서 1씩 커집니다.', set_thickness_desc: '오브젝트가 그리는 선의 굵기를 A로 정합니다.', set_thickness_elements: 'A-- 굵기값(1이상의 수)', set_thickness_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n while True:\n Entry.move_to_direction(10)', set_thickness_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.', change_brush_transparency_desc: '오브젝트가 그리는 선의 투명도를 A만큼 바꿉니다.', change_brush_transparency_elements: 'A-- 투명도 변화 값', change_brush_transparency_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n while True:\n Entry.move_to_direction(10)\n Entry.add_brush_transparency(5)', change_brush_transparency_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 투명도는 계속해서 5만큼 바꿉니다.', set_brush_tranparency_desc: '오브젝트가 그리는 선의 투명도를 A로 정합니다.', set_brush_tranparency_elements: 'A-- 투명도값(0~100 의 범위)', set_brush_tranparency_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n Entry.set_brush_transparency(50)\n while True:\n Entry.move_to_direction(10)', set_brush_tranparency_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로, 선의 투명도를 50으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.', brush_erase_all_desc: '오브젝트가 그린 선과 도장을 모두 지웁니다.', brush_erase_all_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(10)\n\ndef when_click_mouse_on():\n Entry.clear_drawing()', brush_erase_all_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 마우스를 클릭하면 오브젝트가 그린 선을 모두 지웁니다.', text_read_desc: '글상자 A의 내용입니다.
(내용 안에 개행이 있는 경우, 띄어쓰기하여 반환됩니다.)', text_read_elements: 'A-- 아래 선택지 중 하나
① "오브젝트(글상자) 이름"
② 자기 자신', text_read_exampleCode: 'def when_start():\n Entry.print(Entry.contents_of_textbox("A"))', text_read_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 글상자 "A"의 내용을 말합니다.​', text_write_desc: '글상자의 내용을 A로 고쳐씁니다.', text_write_elements: 'A-- 글상자의 내용
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', text_write_exampleCode: 'def when_start():\n Entry.write_text("엔트리")', text_write_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용을 "엔트리"로 바꿉니다.', text_append_desc: '글상자의 내용 뒤에 A를 추가합니다.', text_append_elements: 'A-- 글상자의 내용
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', text_append_exampleCode: 'def when_start():\n Entry.write_text("안녕?")\n Entry.wait_for_sec(1)\n Entry.append_text("엔트리!")', text_append_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용이 "안녕?"이 되었다가 1초 뒤에 "엔트리!"가 추가되어 "안녕?엔트리!"가 됩니다.', text_prepend_desc: '글상자의 내용 앞에 A를 추가합니다.', text_prepend_elements: 'A-- 글상자의 내용
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', text_prepend_exampleCode: 'def when_start():\n Entry.write_text("반가워!")\n Entry.wait_for_sec(1)\n Entry.prepend_text("엔트리!")', text_prepend_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용이 "반가워!"가 되었다가 1초 뒤에 "엔트리!"가 앞에 추가되어 "엔트리!반가워!"가 됩니다.', text_flush_desc: '글상자에 저장된 값을 모두 지웁니다.', text_flush_exampleCode: 'def when_start():\n Entry.write_text("엔트리")\n Entry.wait_for_sec(1)\n Entry.clear_text()', text_flush_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용이 "엔트리"가 되었다가 1초 뒤에 모든 내용이 사라집니다.', sound_something_with_block_desc: '오브젝트가 A 소리를 재생합니다.', sound_something_with_block_elements: 'A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 "소리 이름"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_with_block_exampleCode: 'def when_start():\n Entry.play_sound("소리")\n Entry.add_size(50)', sound_something_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 재생하면서 오브젝트의 크기가 50만큼 커집니다.', sound_something_second_with_block_desc: '오브젝트가 A소리를 B초 만큼 재생합니다.', sound_something_second_with_block_elements: 'A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 "소리 이름"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_second_with_block_exampleCode: 'def when_start():\n Entry.play_sound_for_sec("소리", 1)\n Entry.add_size(50)', sound_something_second_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 1초 동안 재생하면서, 오브젝트의 크기가 50만큼 커집니다.', sound_from_to_desc: '오브젝트가 A소리를 B초부터 C초까지 재생합니다.', sound_from_to_elements: 'A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 "소리 이름"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_from_to_exampleCode: 'def when_start():\n Entry.play_sound_from_to("소리", 0.5, 1)\n Entry.add_size(50)', sound_from_to_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 0.5초부터 1초 구간까지만 재생하면서, 오브젝트의 크기가 50만큼 커집니다.', sound_something_wait_with_block_desc: '오브젝트가 A 소리를 재생하고, 재생이 끝나면 다음 명령을 실행합니다.', sound_something_wait_with_block_elements: 'A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 "소리 이름"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_wait_with_block_exampleCode: 'def when_start():\n Entry.play_sound_and_wait("소리")\n Entry.add_size(50)', sound_something_wait_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.', sound_something_second_wait_with_block_desc: '오브젝트가 A소리를 B초 만큼 재생하고, 재생이 끝나면 다음 명령을 실행합니다.', sound_something_second_wait_with_block_elements: 'A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 "소리 이름"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_second_wait_with_block_exampleCode: 'def when_start():\n Entry.play_sound_for_sec_and_wait("소리", 1)\n Entry.add_size(50)', sound_something_second_wait_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 1초 동안 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.', sound_from_to_and_wait_desc: '오브젝트가 A소리를 B초부터 C초까지 재생하고, 재생이 끝나면 다음 명령을 실행합니다.', sound_from_to_and_wait_elements: 'A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 "소리 이름"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_from_to_and_wait_exampleCode: 'def when_start():\n Entry.play_sound_from_to_and_wait("소리", 0.5, 1)\n Entry.add_size(50)', sound_from_to_and_wait_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 0.5초부터 1초 구간까지만 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.', sound_volume_change_desc: '작품에서 재생되는 모든 소리의 크기를 A퍼센트만큼 바꿉니다.', sound_volume_change_elements: 'A-- 소리 크기 변화 값', sound_volume_change_exampleCode: 'def when_press_key("up"):\n Entry.add_sound_volume(10)\n\ndef when_press_key("down"):\n Entry.add_sound_volume(-10)\n\ndef when_start():\n while True:\n Entry.play_sound_and_wait("소리")', sound_volume_change_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 계속 재생합니다. 위쪽화살표키를 누르면 소리의 크기가 10" 커지고, 아래쪽화살표키를 누르면 소리의 크기가 10"작아집니다.', sound_volume_set_desc: '작품에서 재생되는 모든 소리의 크기를 A퍼센트로 정합니다.', sound_volume_set_elements: 'A-- 소리 크기값', sound_volume_set_exampleCode: 'def when_press_key("up"):\n Entry.add_sound_volume(10)\n\ndef when_press_key("down"):\n Entry.add_sound_volume(-10)\n\ndef when_press_key("enter"):\n Entry.set_sound_volume(100)\n\ndef when_start():\n while True:\n Entry.play_sound_and_wait("소리")', sound_volume_set_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 계속 재생합니다. 위쪽화살표키를 누르면 소리의 크기가 10" 커지고, 아래쪽화살표키를 누르면 소리의 크기가 10"작아집니다. 엔터키를 누르면 소리의 크기를 100"로 정합니다.', sound_silent_all_desc: '현재 재생 중인 모든 소리를 멈춥니다.', sound_silent_all_exampleCode: 'def when_start():\n while True:\n Entry.play_sound_and_wait("소리")\n\ndef when_press_key("enter"):\n Entry.stop_sound()', sound_silent_all_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 계속 재생합니다. 엔터키를 누르면 현재 재생 중인 소리를 멈춥니다.', is_clicked_desc: '마우스를 클릭한 경우 True로 판단합니다.', is_clicked_exampleCode: 'def when_start():\n while True:\n if Entry.is_mouse_clicked():\n Entry.print_for_sec("반가워!", 0.5)', is_clicked_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 마우스를 클릭했는지 확인합니다. 만약 마우스를 클릭하면 오브젝트가 "반가워!"라고 0.5초간 말합니다.', is_press_some_key_desc: 'A 키가 눌려져 있는 경우 True로 판단합니다.', is_press_some_key_elements: 'A-- 아래 선택지 중 하나
① 알파벳 : "A", "B" ~ "Z" 등(소문자 가능)
② 숫자: 1, 2, 3, 4 ~ 9, 0
③ 특수키: "space", "enter"
④ 방향키 : "up", "down", "right", "left"', is_press_some_key_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("space"):\n Entry.move_to_direction(10)', is_press_some_key_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 선택한 키를 눌렀는지 확인합니다. 만약 스페이스 키를 누르면 오브젝트가 이동방향으로 10만큼 이동합니다.', reach_something_desc: '오브젝트가 A와 닿은 경우 True으로 판단합니다.', reach_something_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "mouse_pointer" 또는 "마우스포인터"
③ "edge", "edge_up", "edge_down", "edge_right", "edge_left"', reach_something_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n if Entry.is_touched("edge"):\n Entry.add_rotation(150)', reach_something_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트가 이동방향으로 10만큼 이동합니다. 만약 오브젝트가 벽에 닿으면 150만큼 회전하게 됩니다.', boolean_basic_operator_desc: 'A와 B를 비교하여 True 또는 False로 판단합니다.', boolean_basic_operator_elements: 'A, B-- 비교하고자 하는 숫자값
① == : A와 B의 값이 같으면 True, 아니면 False
② > : A의 값이 B의 값보다 크면 true, 아니면 False
③ < : A의 값이 B의 값보다 작으면 true, 아니면 False
④ >= : A의 값이 B의 값보다 크거나 같으면 true, 아니면 False
⑤ <= : A의 값이 B의 값보다 작거나 같으면 true, 아니면 False', boolean_basic_operator_exampleCode: 'def when_start():\n while True:\n Entry.add_x(10)\n if Entry.value_of_object("오브젝트", "x") > 240:\n Entry.set_x(0)', boolean_basic_operator_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트 x좌표를 10만큼 바꿉니다. 만약 오브젝트 x좌표가 240보다 크면 오브젝트 x좌표를 0으로 정합니다.', boolean_and_desc: 'A와 B의 판단이 모두 True인 경우 True, 아닌 경우 False로 판단합니다.', boolean_and_elements: 'A, B-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', boolean_and_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("a") and Entry.is_key_pressed("s"):\n Entry.add_effect("color", 10)', boolean_and_exampleDesc: '[시작하기]버튼을 클릭하고 키보드의 "a" 와 "s"키를 동시에 눌렀을 때, 색깔 효과를 10만큼 줍니다.', boolean_or_desc: 'A와 B의 판단 중 하나라도 True인 경우 True, 아닌 경우 False로 판단합니다.', boolean_or_elements: 'A, B-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', boolean_or_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("a") or Entry.is_key_pressed("s"):\n Entry.add_effect("color", 10)', boolean_or_exampleDesc: '[시작하기]버튼을 클릭하면 키보드의 "a"나 "s"키 중 무엇이든 하나를 누르면 오브젝트에 색깔 효과를 10만큼 줍니다.', boolean_not_desc: 'A 판단이 True이면 False, False이면 True로 판단합니다.', boolean_not_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', boolean_not_exampleCode: 'def when_start():\n while True:\n if not Entry.is_mouse_clicked():\n Entry.add_size(1)', boolean_not_exampleDesc: '[시작하기]버튼을 클릭하면 마우스를 클릭하지 않은 동안 크기가 1씩 커집니다.', calc_basic_desc: 'A와 B의 연산값입니다.', calc_basic_elements: 'A, B-- 연산하고자 하는 숫자값
① + : A와 B를 더한 값
② - : A와 B를 뺀 값
③ x : A와 B를 곱한 값
④ / : A와 B를 나눈 값', calc_basic_exampleCode: 'def when_start():\n Entry.print_for_sec(10 + 10, 2)\n Entry.print_for_sec(10 - 10, 2)\n Entry.print_for_sec(10 * 10, 2)\n Entry.print_for_sec(10 / 10, 2)', calc_basic_exampleDesc: '[시작하기]버튼을 클릭하면 10과 10을 더한값, 뺀값, 곱한값, 나눈값을 각 2초간 말합니다.', calc_rand_desc: 'A와 B 사이에서 선택된 무작위 수의 값입니다. (두 수 모두 정수를 입력한 경우 정수로,두 수 중 하나라도 소수를 입력한 경우 소수로 무작위 수가 선택됩니다.)', calc_rand_elements: 'A, B-- 무작위 수를 추출할 범위
① random.randint(A, B) : A, B를 정수로 입력하면 정수 범위에서 무작위 수를 추출
② random.uniform(A, B) : A, B를 실수로 입력하면 실수 범위에서 무작위 수를 추출', calc_rand_exampleCode: 'def when_start():\n Entry.print_for_sec(random.randint(1, 10), 2)\n Entry.print_for_sec(random.uniform(0.1, 2), 2)', calc_rand_exampleDesc: '[시작하기]버튼을 클릭하면 1부터 10사이의 정수중 무작위 수를 뽑아 2초간 말합니다. 그 후 0.1부터 2사이의 실수중 무작위 수를 뽑아 2초간 말합니다.', coordinate_mouse_desc: '마우스 포인터의 A 좌표 값을 의미합니다.', coordinate_mouse_elements: 'A-- 아래 선택지 중 하나
① "x" 또는 "X"
② "y" 또는 "Y"', coordinate_mouse_exampleCode: 'def when_start():\n while True:\n Entry.print(Entry.value_of_mouse_pointer("x"))', coordinate_mouse_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 마우스 포인터의 x좌표를 계속해서 말합니다.', coordinate_object_desc: 'A에 대한 B정보값입니다.', coordinate_object_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "self" 또는 "자신"%nextB-- 아래 선택지 중 하나
① "x" 또는 "X"
② "y" 또는 "Y"
③ "rotation" 또는 "방향"
④ "direction" 또는 "이동 방향"
⑤ "size" 또는 "크기"
⑥ "shape_number" 또는 "모양 번호"
⑦ "shape_name" 또는 "모양 이름"', coordinate_object_exampleCode: 'def when_start():\n while True:\n Entry.add_x(1)\n Entry.print(Entry.value_of_object("오브젝트", "x"))\n', coordinate_object_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트의 x좌표가 1씩 증가하며, "오브젝트"의 x좌표를 말합니다.', get_sound_volume_desc: '현재 작품에 설정된 소리의 크기값입니다.', get_sound_volume_exampleCode: 'def when_start():\n while True:\n Entry.print(Entry.value_of_sound_volume())', get_sound_volume_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 소리의 크기값을 계속해서 말합니다.', quotient_and_mod_desc: 'A와 B의 연산값입니다.', quotient_and_mod_elements: 'A, B-- 연산하고자 하는 숫자값
① // : A / B의 몫에 해당하는 값
② % : A / B의 나머지에 해당하는 값', quotient_and_mod_exampleCode: 'def when_start():\n Entry.print_for_sec(10 // 3, 2)\n Entry.print_for_sec(10 % 3, 2)', quotient_and_mod_exampleDesc: '[시작하기]버튼을 클릭하면 10 / 3의 몫인 3을 2초 동안 말하고, 나머지인 1을 2초 동안 말합니다.', calc_operation_desc: 'A의 연산값입니다.', calc_operation_elements: 'A, B-- 연산하고자 하는 숫자값
① A ** 2 : A를 제곱한 값
② math.sqrt(A): A의 루트값
③ math.sin(A): A의 사인값
④ math.cos(A): A의 코사인 값
⑤ math.tan(A): A의 탄젠트값
⑥ math.asin(A): A의 아크사인값
⑦ math.acos(A): A의 아크코사인값
⑧ math.atan(): A의 아크탄젠트값
⑨ math.log10(A): A의 로그값
⑩ math.log(A): A의 자연로그값
⑪ A - math.floor(A): A의 소수점 부분
⑫ math.floor(A): A의 소수점 버림값
⑬ math.ceil(A): A의 소수점 올림값
⑭ math.round(A): A의 소수점 반올림값
⑮ math.factorial(A): A의 팩토리얼 값
⑯ math.fabs(A): A의 절댓값', calc_operation_exampleCode: 'def when_start():\n Entry.print_for_sec(10 ** 2, 2)\n Entry.print_for_sec(math.sqrt(9), 2)\n Entry.print_for_sec(math.sin(90), 2)\n Entry.print_for_sec(math.fabs(-10), 2)', calc_operation_exampleDesc: '[시작하기]버튼을 클릭하면 10의 제곱, 9의 루트값, 90의 사인값, -10의 절댓값을 각 2초 동안 말합니다.', get_project_timer_value_desc: '이 명령이 실행되는 순간 초시계에 저장된 값입니다.', get_project_timer_value_exampleCode: 'def when_start():\n Entry.timer("start")\n Entry.wait_for_sec(3)\n Entry.timer("stop")\n Entry.timer_view("hide")\n Entry.print(Entry.value_of_timer())', get_project_timer_value_exampleDesc: '[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.', choose_project_timer_action_desc: '초시계의 동작을 A로 정합니다.
(이 명령어를 사용하면 실행화면에 ‘초시계 창’이 생성됩니다.)', choose_project_timer_action_elements: 'A-- 아래 선택지 중 하나
① "start" : 초시계를 시작
② "stop" : 초시계를 정지
③ "reset" : 초시계를 초기화', choose_project_timer_action_exampleCode: 'def when_start():\n Entry.timer("start")\n Entry.wait_for_sec(3)\n Entry.timer("stop")\n Entry.timer_view("hide")\n Entry.print(Entry.value_of_timer())', choose_project_timer_action_exampleDesc: '[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.', set_visible_project_timer_desc: '실행화면의 초시계 창을 A로 설정합니다.', set_visible_project_timer_elements: 'A-- 아래 선택지 중 하나
① "hide" : 초시계창을 숨김
② "show" : 초시계창을 보임', set_visible_project_timer_exampleCode: 'def when_start():\n Entry.timer("start")\n Entry.wait_for_sec(3)\n Entry.timer("stop")\n Entry.timer_view("hide")\n Entry.print(Entry.value_of_timer())', set_visible_project_timer_exampleDesc: '[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.', get_date_desc: '현재 A에 대한 값입니다.', get_date_elements: 'A-- 아래 선택지 중 하나
① "year" : 현재 연도 값
② "month" : 현재 월 값
③ "day" : 현재 일 값
④ "hour" : 현재 시간 값
⑤ "minute" : 현재 분 값
⑥ "second" : 현재 초 값', get_date_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_current_time("year") + "년" + Entry.value_of_current_time("month") + "월")', get_date_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 현재년도와 월을 말합니다.', distance_something_desc: '자신과 A까지의 거리 값입니다.', distance_something_elements: 'A-- 아래 선택지 중 하나
① "오브젝트 이름"
② "mouse_pointer" 또는 "마우스포인터"', distance_something_exampleCode: 'def when_start():\n while True:\n Entry.print(Entry.value_of_distance_to("mouse_pointer"))', distance_something_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 마우스포인터와의 거리를 계속해서 말합니다.', get_sound_duration_desc: '소리 A의 길이(초)값입니다.', get_sound_duration_elements: 'A-- "소리 이름"', get_sound_duration_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_sound_length_of("소리"))', get_sound_duration_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "소리"의 길이를 말합니다.', get_user_name_desc: '작품을 실행하고 있는 사용자의 이름 값입니다.', get_user_name_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_username())', get_user_name_exampleDesc: '[시작하기]버튼을 클릭하면 작품을 실행하고 있는 사용자의 이름 값을 말합니다.', length_of_string_desc: '입력한 문자값의 공백을 포함한 글자 수입니다.', length_of_string_elements: 'A-- "문자열"', length_of_string_exampleCode: 'def when_start():\n Entry.print_for_sec(len("안녕"), 2)\n Entry.print_for_sec(len("엔트리"), 2)', length_of_string_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕"과 "엔트리"의 글자 수를 각각 2초 동안 말합니다.', combine_something_desc: 'A 문자열과 B 문자열을 결합한 값입니다. (A, B 중 하나가 숫자면 문자열로 바꾸어 처리되고, 둘 다 숫자면 덧셈 연산으로 처리됩니다.)', combine_something_elements: 'A, B-- "문자열"', combine_something_exampleCode: 'def when_start():\n Entry.print("안녕! " + "엔트리")', combine_something_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕!"과 "엔트리"를 결합한 "안녕! 엔트리"를 말합니다.', char_at_desc: 'A 문자열의 B번째의 글자 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)', char_at_elements: 'A-- "문자열"%nextB-- 찾고자 하는 문자열의 위치', char_at_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!"[0])', char_at_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"의 0번째 글자인 "안"을 말합니다.', substring_desc: 'A 문자열의 B위치부터 C-1위치까지의 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)', substring_elements: 'A-- "문자열"%nextB-- 포함할 문자열의 시작 위치
첫 번째 글자는 0부터 시작%nextC-- 문자열을 포함하지 않는 위치', substring_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!"[1:5])', substring_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"의 1에서 4번째 글자인 "녕 엔트"를 말합니다.', index_of_string_desc: 'A문자열에서 B문자열이 처음으로 등장하는 위치의 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)', index_of_string_elements: 'A, B-- "문자열"', index_of_string_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!".find("엔트리"))', index_of_string_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"에서 "엔트리"가 처음으로 등장하는 위치인 3을 말합니다.', replace_string_desc: 'A 문자열에서 B문자열을 모두 찾아 C문자열로 바꾼 값입니다.
(영문 입력시 대소문자를 구분합니다.)', replace_string_elements: 'A, B, C-- "문자열"', replace_string_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!".replace( "안녕", "반가워"))', replace_string_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"에서 "안녕"을 "반가워"로 바꾼 "반가워 엔트리!"를 말합니다.', change_string_case_desc: 'A의 모든 알파벳을 대문자 또는 소문자로 바꾼 문자값입니다.', change_string_case_elements: 'A-- "문자열"
① A.upper(): A의 모든 알파벳을 대문자로 바꾼 값
② A.lower() : A의 모든 알파벳을 소문자로 바꾼 값', change_string_case_exampleCode: 'def when_start():\n Entry.print_for_sec("Hello Entry!".upper(), 2)\n Entry.print_for_sec("Hello Entry!".lower(), 2)', change_string_case_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "Hello Entry!"를 모두 대문자로 바꾼 "HELLO ENTRY!"를 2초간 말한 다음 모두 소문자로 바꾼 "hello entry!"를 2초간 말합니다.', ask_and_wait_desc: "오브젝트가 A 내용을 말풍선으로 묻고, 대답을 입력받습니다. 대답은 실행화면 또는 콘솔창에서 입력할 수 있으며 입력된 값은 'Entry.answer()'에 저장됩니다.
(이 명령어를 사용하면 실행화면에 ‘대답 창’이 생성됩니다.)", ask_and_wait_elements: 'A-- "문자열"', ask_and_wait_exampleCode: 'def when_start():\n Entry.input("이름을 입력해보세요.")\n Entry.print(Entry.answer() + " 반가워!")', ask_and_wait_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "이름을 입력해보세요."라고 말풍선으로 묻습니다. 이름을 입력하면 "(입력한 이름) 반가워!"라 말합니다.', get_canvas_input_value_desc: 'Entry.input(A) 명령에 의해 실행화면 또는 콘솔에서 입력받은 값입니다.', get_canvas_input_value_exampleCode: 'def when_start():\n Entry.input("이름을 입력해보세요.")\n Entry.print(Entry.answer() + " 반가워!")', get_canvas_input_value_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "이름을 입력해보세요."라고 말풍선으로 묻습니다. 이름을 입력하면 "(입력한 이름) 반가워!"라 말합니다.', set_visible_answer_desc: '실행화면의 대답 창을 A로 설정합니다.', set_visible_answer_elements: 'A-- 아래 선택지 중 하나
① "hide" : 대답 창을 숨김
② "show" : 대답 창을 보임', set_visible_answer_exampleCode: 'def when_start():\n Entry.answer_view("hide")\n Entry.input("나이를 입력하세요.")\n Entry.print(Entry.answer())', set_visible_answer_exampleDesc: '[시작하기]버튼을 클릭하면 대답창이 숨겨지고, 오브젝트가 "나이를 입력하세요."라고 말풍선으로 묻습니다. 나이를 입력하면 오브젝트가 입력한 나이를 말합니다.', get_variable_desc: 'A 변수에 저장된 값입니다.', get_variable_elements: 'A-- 변수명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A', get_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.print(age)', get_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 말합니다.', change_variable_desc: 'A 변수에 B만큼 더합니다.', change_variable_elements: 'A-- 변수명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 숫자값', change_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.print_for_sec(age, 2)\n age += 2\n Entry.print_for_sec(age, 2)', change_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 2초 동안 말합니다. 그 후 age변수에 2를 더하고 더한값인 "18"을 2초 동안 말합니다.', set_variable_desc: 'A 변수의 값을 B로 정합니다. 만약 A 변수가 없으면 [속성] 탭에 A 변수가 자동 생성됩니다.', set_variable_elements: 'A-- 변수명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 변수에 넣을 값
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', set_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.print(age)', set_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 말합니다.', show_variable_desc: 'A 변수 창을 실행화면에 보이게 합니다.', show_variable_elements: 'A-- "변수명"
① 모든 오브젝트에서 사용: "A"
② 이 오브젝트에서 사용: "self.A"', show_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.hide_variable("age")\n Entry.wait_for_sec(2)\n age = 20\n Entry.show_variable("age")', show_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 age변수창을 실행화면에서 숨깁니다. 2초 후 변수값을 17로 바꾸고 age변수창을 실행화면에 보이게 합니다.', hide_variable_desc: 'A 변수 창을 실행화면에서 숨깁니다.', hide_variable_elements: 'A-- "변수명"
① 모든 오브젝트에서 사용: "A"
② 이 오브젝트에서 사용: "self.A"', hide_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.hide_variable("age")\n Entry.print_for_sec(age, 2)', hide_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 age변수창을 실행화면에서 숨기고, 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 2초 동안 말합니다.', value_of_index_from_list_desc: 'A 리스트에서 B위치의 항목 값을 의미합니다.
(첫 번째 항목의 위치는 0부터 시작합니다.)', value_of_index_from_list_elements: 'A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치', value_of_index_from_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.print(basket[1])\n', value_of_index_from_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 오브젝트가 basket 리스트의 1번째 항목인 orange를 말합니다.', add_value_to_list_desc: 'A 리스트의 마지막 항목으로 B값이 추가됩니다.', add_value_to_list_elements: 'A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트에 넣을 항목 값
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', add_value_to_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n basket.append("juice")\n Entry.print(basket[4])', add_value_to_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 "juice"를 basket의 마지막 항목으로 추가합니다. 오브젝트는 basket의 4번째 항목인 "juice"를 말합니다.', remove_value_from_list_desc: 'A 리스트의 B위치에 있는 항목을 삭제합니다.
(첫 번째 항목의 위치는 0부터 시작합니다.)', remove_value_from_list_elements: 'A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치값', remove_value_from_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\ndef when_start():\n basket.pop(0)\n Entry.print(basket[0])', remove_value_from_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 0번째 항목인 apple을 삭제합니다. 오브젝트는 새롭게 basket의 0번째 항목이 된 "orange"를 말합니다.', insert_value_to_list_desc: 'A 리스트의 B위치에 C항목을 끼워 넣습니다.
(첫 번째 항목의 위치는 0부터 시작합니다. B위치보다 뒤에 있는 항목들은 순서가 하나씩 밀려납니다.)', insert_value_to_list_elements: 'A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치%nextC-- 리스트에 넣을 항목 값
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', insert_value_to_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n basket.insert(1, "juice")\n Entry.print(basket[2])', insert_value_to_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 1번째 위치에 항목 "juice"를 끼워 넣습니다. 오브젝트는 새롭게 basket의 2번째 항목이 된 "orange"를 말합니다.', change_value_list_index_desc: 'A 리스트에서 B위치에 있는 항목의 값을 C 값으로 바꿉니다.
(첫 번째 항목의 위치는 0부터 시작합니다.)', change_value_list_index_elements: 'A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치%nextC-- 리스트에 넣을 항목 값
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등', change_value_list_index_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n basket[0] = "juice"\n Entry.print(basket[0])', change_value_list_index_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 0번째 위치의 항목 "apple"을 "juice"로 바꿉니다. 오브젝트는 바뀐 basket의 0번째 항목 "juice"를 말합니다.', length_of_list_desc: 'A 리스트가 보유한 항목 개수 값입니다.', length_of_list_elements: 'A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A', length_of_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.print(len(basket))', length_of_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 오브젝트는 basket의 항목 개수인 4를 말합니다.', is_included_in_list_desc: 'A값을 가진 항목이 B리스트에 포함되어 있는지 확인합니다.', is_included_in_list_elements: 'A-- 리스트의 항목 값
① 문자 : "안녕!", "엔트리" 등
② 숫자 : 0, 10, 35 등%nextB-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A', is_included_in_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n if "apple" in basket:\n Entry.print("사과가 있어!")', is_included_in_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트에 "apple"항목이 있는지 확인합니다. "apple"항목이 있기 때문에 오브젝트는 "사과가 있어!"라 말합니다.', show_list_desc: '선택한 리스트 창을 실행화면에 보이게 합니다.', show_list_elements: 'A-- "리스트명"
① 모든 오브젝트에서 사용: "A"
② 이 오브젝트에서 사용: "self.A"', show_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.hide_list("basket")\n Entry.wait_for_sec(2)\n Entry.show_list("basket")', show_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트를 2초간 숨긴 다음 보여줍니다.', hide_list_desc: '선택한 리스트 창을 실행화면에서 숨깁니다.', hide_list_elements: 'A-- "리스트명"
① 모든 오브젝트에서 사용: "A"
② 이 오브젝트에서 사용: "self.A"', hide_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.hide_list("basket")\n Entry.wait_for_sec(2)\n Entry.show_list("basket")', hide_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트를 2초간 숨긴 다음 보여줍니다.', boolean_and_or_desc: 'A와 B의 판단값을 확인하여 True 또는 False로 판단합니다.', boolean_and_or_elements: '② or : A와 B의 판단 중 하나라도 True인 경우 True, 아닌 경우 False', boolean_and_or_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("a") and Entry.is_key_pressed("s"):\n Entry.add_effect("color", 10)', boolean_and_or_exampleDesc: '[시작하기]버튼을 클릭하고 키보드의 "a" 와 "s"키를 동시에 눌렀을 때, 색깔 효과를 10만큼 줍니다.', check_weather_desc: 'B날짜에 C지역의 날씨가 A인 경우 True로 판단합니다.', check_weather_elements: 'A-- 아래 선택지 중 하나
①    "sunny" : 맑음
②    "partly cloudy" : 구름조금
③    "mostly cloudy" : 구름많음
④    "cloudy" : 흐림
⑤    "rainy" : 비
⑥    "sleet" : 진눈깨비
⑦    "snowy" : 눈%nextB-- 아래 선택지 중 하나
①    "yesterday" : 어제
②    "today" : 오늘
③    "tomorrow" : 내일
④    "After 2 days" : 모레
⑤    "After 3 days" : 3일 후
⑥    "After 4 days" : 4일 후
⑦    "After 5 days" : 5일 후
⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북', check_weather_exampleCode: 'def when_start():\n if Weather.is_condition_sunny("today", "Seoul"):\n Entry.print("오늘 서울의 날씨는 맑습니다.")', check_weather_exampleDesc: '[시작하기]버튼을 클릭하면 오늘 서울의 날씨가 맑은지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 "오늘 서울의 날씨는 맑습니다."라고 말합니다.​', check_finedust_desc: '선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.', check_finedust_elements: 'A-- 아래 선택지 중 하나
①    "good" : 좋음
②    "normal" : 보통
③    "bad" : 나쁨
④    "very bad" : 매우나쁨%nextB-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북', check_finedust_exampleCode: 'def when_start():\n if Weather.is_current_finedust_grade_good("Seoul"):\n Entry.print("현재 서울의 미세먼지 등급은 좋음입니다.")', check_finedust_exampleDesc: '[시작하기]버튼을 클릭하면 현재 서울의 미세먼지 등급이 좋음인지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 “오늘 서울의 미세먼지 등급은 좋음입니다.”라고 말합니다.​', get_weather_data_desc: '선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.', get_weather_data_elements: 'A-- 아래 선택지 중 하나
①    "the lowest temperature" : 최저기온
②    "the highest temperature" : 최고기온
③    "humidity" : 습도
④    "precipitation" : 강수량
⑤    "precipitation probability" : 강수확률
⑥    "wind speed" : 풍속%nextB-- 아래 선택지 중 하나
①    "yesterday" : 어제
②    "today" : 오늘
③    "tomorrow" : 내일
④    "After 2 days" : 모레
⑤    "After 3 days" : 3일 후
⑥    "After 4 days" : 4일 후
⑦    "After 5 days" : 5일 후
⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북', get_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_lowest_temperature("today", "Seoul"))', get_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 최저기온을 말합니다.​', get_current_weather_data_desc: '현재 B지역의 A 날씨 정보값을 의미합니다.', get_current_weather_data_elements: 'A-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나
①    "temperature" : 기온
②    "concentration of fine dust" : 미세먼지농도', get_current_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_current_temperature("Seoul"))', get_current_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 현재 서울의 기온을 말합니다.', get_today_temperature_desc: '오늘 A지역의 B 시간대 기온 정보값을 의미합니다.', get_today_temperature_elements: 'A-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나
①    "00" : 당일 00시 측정된 기온값
②    "03" : 당일 03시 측정된 기온값
③    "06" : 당일 06시 측정된 기온값
④    "09" : 당일 09시 측정된 기온값
⑤    "12" : 당일 12시 측정된 기온값
⑥    "15" : 당일 15시 측정된 기온값
⑦    "18" : 당일 18시 측정된 기온값
⑧    "21" : 당일 21시 측정된 기온값', get_today_temperature_exampleCode: 'def when_start():\n Entry.print(Weather.get_today_temperature("Seoul", 00))', get_today_temperature_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 00시 기온을 말합니다.​', check_city_weather_desc: 'B날짜에 C지역의 날씨가 A인 경우 True로 판단합니다.', check_city_weather_elements: 'A-- 아래 선택지 중 하나
①    "sunny" : 맑음
②    "partly cloudy" : 구름조금
③    "mostly cloudy" : 구름많음
④    "cloudy" : 흐림
⑤    "rainy" : 비
⑥    "sleet" : 진눈깨비
⑦    "snowy" : 눈%nextB-- 아래 선택지 중 하나
①    "yesterday" : 어제
②    "today" : 오늘
③    "tomorrow" : 내일
④    "After 2 days" : 모레
⑤    "After 3 days" : 3일 후
⑥    "After 4 days" : 4일 후
⑦    "After 5 days" : 5일 후
⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북', check_city_weather_exampleCode: 'def when_start():\n if Weather.is_condition_sunny("today", "Seoul"):\n Entry.print("오늘 서울의 날씨는 맑습니다.")', check_city_weather_exampleDesc: '[시작하기]버튼을 클릭하면 오늘 서울의 날씨가 맑은지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 "오늘 서울의 날씨는 맑습니다."라고 말합니다.​', check_city_finedust_desc: '선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.', check_city_finedust_elements: 'A-- 아래 선택지 중 하나
①    "good" : 좋음
②    "normal" : 보통
③    "bad" : 나쁨
④    "very bad" : 매우나쁨%nextB-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북', check_city_finedust_exampleCode: 'def when_start():\n if Weather.is_current_finedust_grade_good("Seoul"):\n Entry.print("현재 서울의 미세먼지 등급은 좋음입니다.")', check_city_finedust_exampleDesc: '[시작하기]버튼을 클릭하면 현재 서울의 미세먼지 등급이 좋음인지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 “오늘 서울의 미세먼지 등급은 좋음입니다.”라고 말합니다.​', get_city_weather_data_desc: '선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.', get_city_weather_data_elements: 'A-- 아래 선택지 중 하나
①    "the lowest temperature" : 최저기온
②    "the highest temperature" : 최고기온
③    "humidity" : 습도
④    "precipitation" : 강수량
⑤    "precipitation probability" : 강수확률
⑥    "wind speed" : 풍속%nextB-- 아래 선택지 중 하나
①    "yesterday" : 어제
②    "today" : 오늘
③    "tomorrow" : 내일
④    "After 2 days" : 모레
⑤    "After 3 days" : 3일 후
⑥    "After 4 days" : 4일 후
⑦    "After 5 days" : 5일 후
⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북', get_city_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_lowest_temperature("today", "Seoul"))', get_city_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 최저기온을 말합니다.​', get_current_city_weather_data_desc: '현재 B지역의 A 날씨 정보값을 의미합니다.', get_current_city_weather_data_elements: 'A-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나
①    "temperature" : 기온
②    "concentration of fine dust" : 미세먼지농도', get_current_city_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_current_temperature("Seoul"))', get_current_city_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 현재 서울의 기온을 말합니다.', get_today_city_temperature_desc: '오늘 A지역의 B 시간대 기온 정보값을 의미합니다.', get_today_city_temperature_elements: 'A-- 아래 선택지 중 하나
①    "Seoul" : 서울
②    "Gangwon-do" : 강원
③    "Gyeonggi-do" : 경기
④    "Gyeongsangnam-do" : 경남
⑤    "Gyeongsangbuk-do" : 경북
⑥    "Gwangju" : 광주
⑦    "Daegu" : 대구
⑧    "Daejeon" : 대전
⑨    "Busan" : 부산
⑩    "Sejong" : 세종
⑪    "Ulsan" : 울산
⑫    "Incheon" : 인천
⑬    "Jeollanam-do" : 전남
⑭    "Jeollabuk-do" : 전북
⑮    "Jeju" : 제주
Ⓐ "Chungcheongnam-do" : 충남
Ⓑ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나
①    "00" : 당일 00시 측정된 기온값
②    "03" : 당일 03시 측정된 기온값
③    "06" : 당일 06시 측정된 기온값
④    "09" : 당일 09시 측정된 기온값
⑤    "12" : 당일 12시 측정된 기온값
⑥    "15" : 당일 15시 측정된 기온값
⑦    "18" : 당일 18시 측정된 기온값
⑧    "21" : 당일 21시 측정된 기온값', get_today_city_temperature_exampleCode: 'def when_start():\n Entry.print(Weather.get_today_city_temperature("Seoul", 00))', get_today_city_temperature_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 00시 기온을 말합니다.​', }; Lang.Painter = { select_cut: '사각 점선 모양으로 오릴 수 있어요.', thickness_of_eraser: '지우개 굵기', font: '글꼴', font_color: '글꼴 색상', outline_color: '윤곽선 색상', outline_thickness: '윤곽선 굵기', fill_color: '채우기 색상', inversion: '반전', font_size: '글꼴 크기', font_family: '글꼴 스타일', fullscreen: '전체화면', exit_fullscreen: '전체화면 해제', picture_import: '모양 가져오기', edit_way: '편집 방법', line: '직선', vertex: '꼭지점', bitmap: '비트맵', vector: '벡터', forward: '앞으로', backward: '뒤로', front: '맨 앞으로', back: '맨 뒤로', group: '그룹화', ungroup: '그룹 해제', copy_picture: '복사', delete_picture: '삭제', cut_picture: '자르기', paste_picture: '붙여넣기', remove_all: '모두 삭제', new_picture: '새그림', edit: '편집', picture_size: '크기', picture_rotation: '회전', thickness: '굵기', font_fill: '채우기 색상', painter_file_save: '저장하기', painter_file_saveas: '새 모양으로 저장', file: '파일', Pencil: '펜', Line: '직선', Path: '형태', Pan: '이동', Select: '선택', Rectangle: '사각형', Ellipse: '원', Text: '글상자', Fill: '채우기', Eraser: '지우기', get_file: '가져오기', copy_file: '복사하기', }; Lang.DataAnalytics = { data_analysis: '데이터분석', create_table: '테이블 만들기', data: '데이터', add_table: '테이블 추가하기', show_chart: '차트 보기', legend: '범례', dashboard: '요약', table: '테이블', chart: '차트', attribute: '열', row: '행', average: '평균', standard_deviation: '표준 편차', maximum: '최댓값', minimum: '최솟값', median: '중간값', average_explain: '해당 열의 모든 값을 더한 후 열의 개수 만큼 나눈 값', standard_deviation_explain: '데이터가 평균을 중심으로 얼마나 퍼져있는지 알려주는 값.\n0에 가까울 수록 값들이 평균 근처에 집중되어 있다는 것을 의미', maximum_minimum_explain: '해당 열의 가장 큰 값과 가장 작은 값', median_explain: '해당 열의 모든 값을 크기순으로 배열했을 때\n전체의 중앙에 위치하는 값', add_row_above: '위에 행 추가하기', add_row_below: '아래에 행 추가하기', delete_row: '행 삭제하기', add_property_left: '왼쪽에 열 추가하기', add_property_right: '오른쪽에 열 추가하기', delete_attribute: '열 삭제', data_alert: '숫자가 아닌 값이 포함된 열은 개수만 확인할 수 있습니다.', save: '저장하기', cancel: '취소', confirm: '확인', attribute_count: '개', row_count: '행', cell_count: '개', count: '개수', add_chart_alert: '추가된 차트가 없습니다.\n차트를 생성해주세요.', enter_attribute_name: '열 이름을 입력해 주세요.(10자 이내)', placeholder_attribute_name: '열 이름', new_attribute: '새로운 열', chart_title: '차트 제목', remove_chart: '차트 삭제하기', add_chart_first: '차트를 먼저 추가해주세요.', bar: '막대', line: '꺾은선', pie: '원형', scatter: '분산형', select_x_axis: '가로축을 선택해주세요.', x_axis: '가로축', y_axis: '세로축', select_y_axis: '세로축을 선택해주세요.', select_y_axis_or_legend: '세로축 혹은 범례를 선택해주세요.', select_legend: '범례를 선택해주세요', cell: '칸', unable_to_express_chart: '차트로 표현할 수 없습니다.', edit_attribute_name: '이름 바꾸기', duplicate_attribute_name_title: '열 이름 변경에 실패하였습니다.', duplicate_attribute_name_content: '같은 이름의 열이 존재합니다.', fail_save_table: '테이블 저장에 실패하였습니다.', duplicate_table_name_content: '같은 이름의 테이블이 존재합니다.', saved_table_title: '저장되었습니다.', saved_table_content: '테이블과 차트의 정보가 저장되었습니다.', empty_table_name_content: '테이블 이름은 빈 칸이 될 수 없습니다', do_not_delete_row: '행을 삭제할 수 없습니다.', rows_cannot_less_one: '테이블에는 한 개 이상의 행이 있어야합니다.', }; Lang.SharePolicy = { title: '엔트리 작품/게시물 공유 가이드', }; Lang.Support = ['ko', 'en', 'vn', 'jp']; if (typeof exports == 'object') exports.Lang = Lang; ================================================ FILE: extern/lang/en.js ================================================ var Lang = {}; Lang.category = { name: 'en', }; Lang.type = 'en'; Lang.fallbackType = 'ko'; Lang.ko = '한국어'; Lang.en = 'English'; Lang.jp = '日本語'; Lang.vn = 'tiếng Việt'; Lang.Command = { 1: '장면 추가하기', 2: '장면 삭제하기', 3: '장면 이름 수정', 4: '장면 순서 변경', 5: '장면 선택', 101: '블록 쓰레드 추가하기', 102: '블록 쓰레드 삭제하기', 103: '블록 삭제하기', 104: '블록 복구하기', 105: '블록 끼워넣기', 106: '블록 분리하기', 107: '블록 이동하기', 108: '블록 복제하기', 109: '블록 복제 취소하기', 110: '스크롤', 111: '블록 필드값 수정', 117: '블록 쓰레드 추가하기', 118: '블록 끼워넣기', 119: '블록 이동하기', 120: '블록 분리하기', 121: '블록 이동하기', 122: '블록 끼워넣기', 123: '블록 끼워넣기', 201: '오브젝트 선택하기', 202: '오브젝트 수정 버튼 클릭', 203: '오브젝트 그림 추가', 204: '오브젝트 그림 삭제', 205: '오브젝트 소리 추가', 206: '오브젝트 소리 삭제', 207: '오브젝트 이름 수정', 208: '오브젝트 추가', 209: '오브젝트 삭제', 210: '오브젝트 추가 버튼 클릭', 211: '오브젝트 x 수정', 212: '오브젝트 y 수정', 213: '오브젝트 size 수정', 214: '오브젝트 방향 수정', 215: '오브젝트 이동 방향 수정', 216: '오브젝트 회전방식 수정', 217: '엔터티 모델 동기화', 301: 'do', 302: 'undo', 303: 'redo', 401: '그림 수정하기', 402: '그림 수정 취소하기', 403: '그림 수정하기', 404: '그림 수정 취소하기', 405: '글상자 수정', 501: '시작하기', 502: '정지하기', 601: '컨테이너 오브젝트 선택하기', 701: '모드 바꾸기', 702: '모양 추가 버튼 클릭', 703: '소리 추가 버튼 클릭', 801: '속성 필터 선택하기', 802: '변수 추가하기 버튼 클릭', 803: '변수 추가하기', 804: '변수 삭제하기', 805: '변수 이름 설정', 806: '신호 이름 설정', 807: '신호 추가', 808: '신호 삭제', 809: '변수 스코프 정하기', 810: '변수 글로벌 체크', 811: '변수 보이기 체크', 812: '변수 기본값 설정', 813: '변수 슬라이드로 체크', 814: '변수 최솟값 정하기', 815: '변수 최댓값 정하기', 816: '리스트 추가 버튼 클릭', 817: '리스트 추가', 818: '리스트 삭제', 819: '리스트 이름 정하기', 820: '리스트 스코프 정하기', 821: '리스트 글로벌 체크', 822: '리스트 보이기 체크', 823: '리스트 길이 변경', 824: '리스트 기본값 설정', 825: '메세지 수정 enable', 826: '변수 수정 enable', 827: '리스트 수정 enable', 828: '변수 이름 정하기', 829: '리스트 이름 정하기', 900: '모달 닫기', 1001: '함수 생성 시작', 1002: '함수 수정 시작', 1003: '함수 수정 취소', 1004: '함수 생성', 1005: '함수 업데이트', }; Lang.CommandTooltip = { 101: '블록 쓰레드 추가하기', 102: '블록 쓰레드 삭제하기', 103: '블록 삭제하기', 104: '블록 복구하기', 105: '코드 분리하기$$코드 연결하기@@이 코드의 가장 위에 있는 블록을 잡고 분리하여 끌어옵니다.$$이 곳에 코드를 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 106: '블록 분리하기', 107: '블록 이동하기', 108: '블록 복제하기', 109: '블록 복제 취소하기', 110: '스크롤', 111: '블록 필드값 수정@@값을 입력하기 위해 이곳을 클릭합니다.$$선택지를 클릭합니다.$$선택지를 클릭합니다.$$&value&을 입력합니다.$$&value&를 선택합니다.$$키보드 &value&를 누릅니다.', 117: '블록 쓰레드 추가하기', 118: '블록 연결하기@@이 곳에 블록을 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 119: '블록 가져오기@@빈 곳에 블록을 끌어다 놓습니다.', 120: '블록 분리하기$$블록 삭제하기@@필요 없는 코드를 휴지통으로 끌어옵니다.$$이 곳에 코드를 버립니다.', 121: '블록 이동하기$$블록 삭제하기@@필요 없는 코드를 휴지통으로 끌어옵니다.$$이 곳에 코드를 버립니다.', 122: '블록 연결하기@@이 곳에 블록을 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 123: '코드 분리하기$$코드 연결하기@@이 코드의 가장 위에 있는 블록을 잡고 분리하여 끌어옵니다.$$이 곳에 코드를 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 201: '오브젝트 선택하기', 301: 'do', 302: 'undo', 303: 'redo', 401: '그림 수정하기', 402: '그림 수정 취소하기', 403: '그림 수정하기', 404: '그림 수정 취소하기', 501: '실행하기@@[시작하기]를 누릅니다.', 502: '정지하기@@[정지하기]를 누릅니다.', 601: '컨테이너 오브젝트 선택하기', 701: '모드 바꾸기', 702: '모양 추가하기@@모양추가를 클릭합니다.', 703: '소리 추가하기@@소리추가를 클릭합니다.', 801: '변수 속성창 필터 선택하기', 802: '변수 추가하기@@[변수 추가]를 클릭합니다.', 803: '변수 추가하기@@[확인]을 클릭합니다.', 804: '변수 삭제하기@@이 버튼을 눌러 변수를 삭제합니다.', 805: '변수 이름 설정', 1101: '확장 블록 추가하기@@확장 블록 블러오기를 클릭합니다.', }; Lang.Blocks = { START_when_object_click: 'When object clicked', START_when_object_click_canceled: 'When object click released', START_when_run_button_click: 'When run', START_when_scene_start: 'When scene was started', START_when_some_key_click: 'When press some key', TEXT_text: 'Entry', TEXT_text_append_1: 'After writing that', TEXT_text_append_2: '', TEXT_text_flush: 'Remove all text', TEXT_text_prepend_1: 'Add', TEXT_text_prepend_2: 'in front of that', TEXT_text_write_1: 'Writing that', TEXT_text_write_2: '', VARIABLE_add_value_to_list: '', VARIABLE_add_value_to_list_3: '', VARIABLE_ask_and_wait_1: 'Ask', VARIABLE_ask_and_wait_2: 'and wait', VARIABLE_change_value_list_index: '', VARIABLE_change_value_list_index_2: '', VARIABLE_change_value_list_index_4: '', VARIABLE_change_variable_1: 'Plus to', VARIABLE_change_variable_2: 'by', VARIABLE_change_variable_3: '', VARIABLE_change_variable_name: 'Rename variable', VARIABLE_get_variable_2: '', VARIABLE_get_y: 'Y Coordinate', VARIABLE_hide_list: '', VARIABLE_hide_list_2: '', VARIABLE_hide_variable_1: 'Hide variable', VARIABLE_hide_variable_2: 'value', VARIABLE_insert_value_to_list: '', VARIABLE_insert_value_to_list_3: '', VARIABLE_length_of_list: '', VARIABLE_length_of_list_2: '', VARIABLE_list: '', VARIABLE_make_variable: 'Make variable', VARIABLE_list_option_first: 'First', VARIABLE_list_option_last: 'Last', VARIABLE_list_option_random: 'Randomly', VARIABLE_remove_value_from_list: '', VARIABLE_remove_value_from_list_3: '', VARIABLE_remove_variable: 'Remove variable', VARIABLE_set_variable_1: 'Set', VARIABLE_set_variable_2: 'to', VARIABLE_set_variable_3: '', VARIABLE_show_list: '', VARIABLE_show_list_2: '', VARIABLE_show_variable_1: 'Show variable', VARIABLE_show_variable_2: 'value', VARIABLE_value_of_index_from_list: '', VARIABLE_value_of_index_from_list_2: '', HAMSTER_hand_found: 'hand found?', HAMSTER_move_forward_once: 'move forward once on board', HAMSTER_turn_once_1: 'turn', HAMSTER_turn_once_2: 'once on board', HAMSTER_move_forward: 'move forward', HAMSTER_move_backward: 'move backward', HAMSTER_turn_around_1: 'turn', HAMSTER_turn_around_2: '', HAMSTER_move_forward_for_secs_1: 'move forward for', HAMSTER_move_forward_for_secs_2: 'secs', HAMSTER_move_backward_for_secs_1: 'move backward', HAMSTER_move_backward_for_secs_2: 'secs', HAMSTER_turn_for_secs_1: 'turn', HAMSTER_turn_for_secs_2: 'for', HAMSTER_turn_for_secs_3: 'secs', HAMSTER_change_both_wheels_by_1: 'change wheel by left:', HAMSTER_change_both_wheels_by_2: 'right:', HAMSTER_change_both_wheels_by_3: '', HAMSTER_set_both_wheels_to_1: 'set wheel to left:', HAMSTER_set_both_wheels_to_2: 'right:', HAMSTER_set_both_wheels_to_3: '', HAMSTER_change_wheel_by_1: 'change', HAMSTER_change_wheel_by_2: 'wheel by', HAMSTER_change_wheel_by_3: '', HAMSTER_set_wheel_to_1: 'set', HAMSTER_set_wheel_to_2: 'wheel to', HAMSTER_set_wheel_to_3: '', HAMSTER_follow_line_using_1: 'follow', HAMSTER_follow_line_using_2: 'line using', HAMSTER_follow_line_using_3: 'floor sensor', HAMSTER_follow_line_until_1: 'follow', HAMSTER_follow_line_until_2: 'line until', HAMSTER_follow_line_until_3: 'intersection', HAMSTER_left_intersection: 'left', HAMSTER_right_intersection: 'right', HAMSTER_front_intersection: 'front', HAMSTER_rear_intersection: 'rear', HAMSTER_set_following_speed_to_1: 'set following speed to', HAMSTER_set_following_speed_to_2: '', HAMSTER_stop: 'stop', HAMSTER_set_led_to_1: 'set', HAMSTER_set_led_to_2: 'led to', HAMSTER_set_led_to_3: '', HAMSTER_clear_led_1: 'clear', HAMSTER_clear_led_2: 'led', HAMSTER_beep: 'beep', HAMSTER_change_buzzer_by_1: 'change buzzer by', HAMSTER_change_buzzer_by_2: '', HAMSTER_set_buzzer_to_1: 'set buzzer to', HAMSTER_set_buzzer_to_2: '', HAMSTER_clear_buzzer: 'clear buzzer', HAMSTER_play_note_for_1: 'play note', HAMSTER_play_note_for_2: '', HAMSTER_play_note_for_3: 'for', HAMSTER_play_note_for_4: 'beats', HAMSTER_rest_for_1: 'rest for', HAMSTER_rest_for_2: 'beats', HAMSTER_change_tempo_by_1: 'change tempo by', HAMSTER_change_tempo_by_2: '', HAMSTER_set_tempo_to_1: 'set tempo to', HAMSTER_set_tempo_to_2: 'bpm', HAMSTER_set_port_to_1: 'set port', HAMSTER_set_port_to_2: 'to', HAMSTER_set_port_to_3: '', HAMSTER_change_output_by_1: 'change output', HAMSTER_change_output_by_2: 'by', HAMSTER_change_output_by_3: '', HAMSTER_set_output_to_1: 'set output', HAMSTER_set_output_to_2: 'to', HAMSTER_set_output_to_3: '', ROBOID_buzzer: 'buzzer', ROBOID_color_pattern: 'color pattern', ROBOID_head_color: 'head color', ROBOID_left_wheel: 'left wheel', ROBOID_note: 'note', ROBOID_right_wheel: 'right wheel', ALBERT_hand_found: 'hand found?', ALBERT_is_oid_1: 'oid is', ALBERT_is_oid_2: '', ALBERT_is_oid_3: '?', ALBERT_front_oid: 'front', ALBERT_back_oid: 'back', ALBERT_sensor_battery: 'battery', ALBERT_move_forward: 'move forward', ALBERT_move_backward: 'move backward', ALBERT_turn_around_1: 'turn', ALBERT_turn_around_2: '', ALBERT_move_forward_for_secs_1: 'move forward for', ALBERT_move_forward_for_secs_2: 'secs', ALBERT_move_backward_for_secs_1: 'move backward for', ALBERT_move_backward_for_secs_2: 'secs', ALBERT_turn_for_secs_1: 'turn', ALBERT_turn_for_secs_2: 'for', ALBERT_turn_for_secs_3: 'secs', ALBERT_turn_left: 'left', ALBERT_turn_right: 'right', ALBERT_change_both_wheels_by_1: 'change wheels by left:', ALBERT_change_both_wheels_by_2: 'right:', ALBERT_change_both_wheels_by_3: '', ALBERT_left_wheel: 'left', ALBERT_right_wheel: 'right', ALBERT_both_wheels: 'both', ALBERT_set_both_wheels_to_1: 'set wheels to left:', ALBERT_set_both_wheels_to_2: 'right:', ALBERT_set_both_wheels_to_3: '', ALBERT_change_wheel_by_1: 'change', ALBERT_change_wheel_by_2: 'wheel by', ALBERT_change_wheel_by_3: '', ALBERT_set_wheel_to_1: 'set', ALBERT_set_wheel_to_2: 'wheel to', ALBERT_set_wheel_to_3: '', ALBERT_stop: 'stop', ALBERT_set_board_size_to_1: 'set board size to width:', ALBERT_set_board_size_to_2: 'height:', ALBERT_set_board_size_to_3: '', ALBERT_move_to_x_y_1: 'move to x:', ALBERT_move_to_x_y_2: 'y:', ALBERT_move_to_x_y_3: 'on board', ALBERT_set_orientation_to_1: 'set orientation to', ALBERT_set_orientation_to_2: 'degrees on board', ALBERT_set_eye_to_1: 'set', ALBERT_set_eye_to_2: 'eye to', ALBERT_set_eye_to_3: '', ALBERT_left_eye: 'left', ALBERT_right_eye: 'right', ALBERT_both_eyes: 'both', ALBERT_clear_eye_1: 'clear', ALBERT_clear_eye_2: 'eye', ALBERT_body_led_1: 'turn', ALBERT_body_led_2: 'body led', ALBERT_front_led_1: 'turn', ALBERT_front_led_2: 'front led', ALBERT_color_cyan: 'cyan', ALBERT_color_magenta: 'magenta', ALBERT_color_white: 'white', ALBERT_color_red: 'red', ALBERT_color_yellow: 'yellow', ALBERT_color_green: 'green', ALBERT_color_blue: 'blue', ALBERT_turn_body_led_1: 'turn', ALBERT_turn_body_led_2: 'body led', ALBERT_turn_front_led_1: 'turn', ALBERT_turn_front_led_2: 'front led', ALBERT_turn_on: 'on', ALBERT_turn_off: 'off', ALBERT_beep: 'beep', ALBERT_change_buzzer_by_1: 'change buzzer by', ALBERT_change_buzzer_by_2: '', ALBERT_set_buzzer_to_1: 'set buzzer to', ALBERT_set_buzzer_to_2: '', ALBERT_clear_buzzer: 'clear buzzer', ALBERT_play_note_for_1: 'play note', ALBERT_play_note_for_2: "',", ALBERT_play_note_for_3: 'for', ALBERT_play_note_for_4: 'beats', ALBERT_rest_for_1: 'rest for', ALBERT_rest_for_2: 'beats', ALBERT_change_tempo_by_1: 'change tempo by', ALBERT_change_tempo_by_2: '', ALBERT_set_tempo_to_1: 'set tempo to', ALBERT_set_tempo_to_2: 'bpm', VARIABLE_variable: 'variable', robotis_common_case_01: '(을)를', robotis_common_set: 'the output value', robotis_common_value: 'Value', robotis_common_cm: 'Controller', robotis_common_play_buzzer: 'Play', robotis_common_play_motion: 'Play', robotis_common_motion: 'Motion', robotis_common_index_number: 'Number', robotis_common_left: 'Left', robotis_common_right: 'Right', robotis_common_minute: 'minute(s)', robotis_cm_custom: 'Custom address', robotis_cm_clear_sound_detected: 'Initialize the final number of sound detection', robotis_cm_buzzer_index: 'Scale index', robotis_cm_buzzer_melody: 'Melody', robotis_cm_led_1: 'LED 1', robotis_cm_led_4: 'LED 4', robotis_carCont_aux_motor_speed_1: 'Speed of decelerating motor', robotis_carCont_aux_motor_speed_2: ', the output value', robotis_carCont_calibration_1: 'Value of the infrared sensor calibration ', robotis_openCM70_aux_motor_speed_1: 'Speed of decelerating motor', robotis_openCM70_aux_motor_speed_2: ', Set as', robotis_openCM70_aux_servo_mode_1: 'Servo motor mode', robotis_openCM70_aux_servo_speed_1: 'Servo motor speed', robotis_openCM70_aux_servo_speed_2: ', the output value', robotis_openCM70_aux_servo_position_1: 'Position of servo motor', robotis_openCM70_aux_led_module_1: 'LED module', robotis_openCM70_aux_custom_1: 'User device', XBOT_digital: 'Digital', XBOT_analog: 'Analog', XBOT_Value: 'Ouput Value', XBOT_pin_OutputValue: 'PIN, Ouput Value', XBOT_Servo: 'Servo Motor', XBOT_angle: ', Angle', XBOT_DC: 'Wheel(DC) Motor', XBOT_speed: ', Speed', XBOT_rightSpeed: 'Wheel(DC) Motor Right(2) Speed:', XBOT_leftSpeed: 'Left(1) Speed:', XBOT_RGBLED_R: 'RGB LED Color from Red', XBOT_RGBLED_G: 'Green', XBOT_RGBLED_B: 'Blue', XBOT_RGBLED_color: 'RGB LED Color from', XBOT_set: ' ', XBOT_melody_ms: 'sec of Melody Playing', XBOT_Line: 'th Line', XBOT_outputValue: 'Text', roborobo_num_analog_value_1: 'Analog', roborobo_num_analog_value_2: 'Sensor Value', roborobo_get_digital_value_1: 'Digital', roborobo_num_pin_1: 'Digital', roborobo_num_pin_2: 'Pin', roborobo_input_mode: 'Input', roborobo_output_mode: 'Output', roborobo_pwm_mode: 'PWM', roborobo_servo_mode: 'Servo', roborobo_color: 'Color Sensor ', roborobo_color_detected: ' Detected ', roborobo_degree: ' ˚', robotori_digital: 'Digital', robotori_pin_OutputValue: 'Output Value', robotori_analog: 'Analog', robotori_Servo: 'Servo Motor', robotori_DC: 'DC Motor', robotori_DC_select: 'direction', VARIABLE_is_included_in_list: '', VARIABLE_is_included_in_list_3: '', CALC_calc_operation_natural: 'integer value', MOVING_locate_object_time_1: 'factorial value', MOVING_locate_object_time_2: 'seconds to the', MOVING_locate_object_time_3: '', FLOW_repeat_while_true_1: 'Repeat', FLOW_repeat_while_true_2: ' ', TUT_when_start: '', TUT_move_once: '', TUT_rotate_left: '', TUT_rotate_right: '', TUT_jump_barrier: '', TUT_repeat_tutorial_1: '', TUT_repeat_tutorial_2: '', TUT_if_barrier_1: '', TUT_if_barrier_2: '', TUT_if_conical_1: '', TUT_if_conical_2: '', TUT_repeat_until: '', TUT_repeat_until_gold: '', TUT_declare_function: '', TUT_call_function: '', BRUSH_change_brush_transparency_1: 'Change transparency by', BRUSH_change_brush_transparency_2: '%', BRUSH_set_brush_transparency_1: 'Set transparency to', BRUSH_set_brush_transparency_2: '%', CALC_char_at_3: '', CALC_length_of_string_2: '', CALC_reverse_of_string_2: '', CALC_substring_4: '', CALC_replace_string_4: '', CALC_change_string_case_1: '', CALC_index_of_string_3: '', MOVING_add_direction_by_angle_time_explain_1: 'For', MOVING_direction_relative_duration_1: 'For', MOVING_direction_relative_duration_2: 'secs set direction to', MOVING_direction_relative_duration_3: '', SOUND_sound_from_to_1: 'Play', SOUND_sound_from_to_2: 'sound from', SOUND_sound_from_to_3: 'to', SOUND_sound_from_to_4: 'secs', SOUND_sound_from_to_and_wait_1: 'Play', SOUND_sound_from_to_and_wait_2: 'sound from', SOUND_sound_from_to_and_wait_3: 'to', SOUND_sound_from_to_and_wait_4: 'secs and wait', CALC_quotient_and_mod_1: '', CALC_quotient_and_mod_4: ' ', CALC_choose_project_timer_action_1: '', LOOKS_change_object_index_1: 'bring to', LOOKS_change_object_index_2: '', copy_block: 'copy block(s)', delete_block: 'delete block(s)', bark_dog: 'dog barking', DUMMY: '더미', coconut_stop_motor: 'stop motor', coconut_move_motor: 'move motor', coconut_turn_motor: 'turn', coconut_move_outmotor: 'external motor', coconut_move_speed_1: '0', coconut_move_speed_2: '50', coconut_move_speed_3: '100', coconut_move_speed_4: '150', coconut_move_speed_5: '255', coconut_color_black: 'Black', coconut_beep: 'buzzer on', coconut_clear_buzzer: 'buzzer off', modi_speaker_F_DO_5: 'DO 5', modi_speaker_F_DO_S_5: 'DO #5', modi_speaker_F_MI_5: 'MI 5', modi_speaker_F_PA_7: 'FA 7', modi_speaker_F_PA_S_7: 'FA #7', modi_speaker_F_RA_7: 'LA 7', modi_speaker_F_RA_S_7: 'LA #7', modi_speaker_F_RE_5: 'RE 5', modi_speaker_F_RE_S_5: 'LA #5', modi_speaker_F_SOL_7: 'SOL 7', modi_speaker_F_SOL_S_7: 'SOL #7', modi_speaker_F_SO_7: 'TI 7', ALTINO_Line: 'line', ALTINO_REMOTE: 'remote control', ALTINO_STVAR: 'steering potentiometer', ALTINO_Value: 'output value', ALTINO_dot_display_1: 'one char', ALTINO_dot_display_2: 'display', ALTINO_leftWheel: 'left', ALTINO_melody_ms: 'play', ALTINO_outputValue: 'output', ALTINO_rightWheel: 'right', ALTINO_set: ' display', FUNBOARD_led_color_str: 'color ', FUNBOARD_led_off_str: 'Turn off the LED', FUNBOARD_led_on_str: 'Turn on the LED', funboard_dotmatrix_set_off: 'off', funboard_dotmatrix_set_on: 'on', copy_paste_comment: 'Copy & paste the memo', copy_comment: 'Copy the memo', delete_comment: 'Delete the memo', fold_comment: 'Hide the memo', open_comment: 'Show the memo', separate_comment: 'Take the memo off', video_pose_model: 'Human model', video_face_model: 'Face model', video_object_model: 'Object model', ALBERT_sensor_acceleration_x: 'x acceleration', ALBERT_sensor_acceleration_y: 'y acceleration', ALBERT_sensor_acceleration_z: 'z acceleration', ALBERT_sensor_front_oid: 'front oid', ALBERT_sensor_back_oid: 'back oid', ALBERT_sensor_position_x: 'x position', ALBERT_sensor_position_y: 'y position', ALBERT_sensor_orientation: 'orientation', ALBERT_sensor_temperature: 'temperature', ALBERT_sensor_signal_strength: 'signal strength', ALBERT_sensor_left_proximity: 'left proximity', ALBERT_sensor_right_proximity: 'right proximity', ALBERT_sensor_light: 'light', chocopi_port: 'P', coconut_sensor_temperature: 'temperature', coconut_sensor_acceleration_x: 'X-Axis Accelerometer', coconut_sensor_acceleration_y: 'Y-Axis Accelerometer', coconut_sensor_acceleration_z: 'Z-Axis Accelerometer', coconut_sensor_left_proximity: 'left IR distance', coconut_sensor_right_proximity: 'right IR distance', coconut_sensor_left_floor: 'left line tracer', coconut_sensor_right_floor: 'right line tracer', coconut_sensor_light: 'light sensor', HAMSTER_sensor_temperature: 'temperature', HAMSTER_sensor_input_a: 'input A', HAMSTER_sensor_input_b: 'input B', HAMSTER_sensor_acceleration_x: 'x acceleration', HAMSTER_sensor_acceleration_y: 'y acceleration', HAMSTER_sensor_acceleration_z: 'z acceleration', HAMSTER_sensor_left_proximity: 'left proximity', HAMSTER_sensor_right_proximity: 'right proximity', HAMSTER_sensor_left_floor: 'left floor', HAMSTER_sensor_right_floor: 'right floor', HAMSTER_sensor_light: 'light', jdkit_joystick_leftleftright: '왼쪽 좌우', jdkit_joystick_lefttopbottom: '왼쪽 상하', jdkit_joystick_rightleftright: '오른쪽 좌우', jdkit_joystick_righttopbottom: '오른쪽 상하', ROBOID_color_number: 'color number', ROBOID_floor: 'floor', ROBOID_button: 'button', ROBOID_acceleration_x: 'x acceleration', ROBOID_acceleration_y: 'y acceleration', ROBOID_acceleration_z: 'z acceleration', learn_popup_title: 'Input Data', arduino_noti_text: 'HW connection is\nonly supported on desktop.\n \nPlease contact HW\nmanufacturer for tablet.', arduino_lite_alert: 'Device not found.\nPlease check if firmware\nis installed on device,\nor if PC and device are connected.', arduino_lite_reconnect: 'Retry', arduino_lite_download_firmware: 'Download firmware', arduino_lite_download_driver: 'Download Driver', arduino_lite_connect: 'Connect through web', arduino_lite_disconnect: 'Cancel', arduino_lite_guide: '• connection guide', arduino_lite_connected_noti: 'Please save the project\nwith the device selected.', ARDUINO_download_connector: '• Download Connector', download_guide: '• Download Guide', ARDUINO_download_source: '• Entry Arduino code', ARDUINO_connected: 'Hardware connected', ARDUINO_connect: '* Connect hardware', ARDUINO_reconnect: 'Connect HW', hardware_connect_helper: 'Help (Korean Only)', hardware_noti_installed: 'When using connection program', hardware_noti_not_installed: 'When using web browser', hardware_device_name_title: 'Name:', hardware_device_name_title_robot: 'Name:', hardware_device_name_content: 'None', hardware_program_download: 'Download program', hardware_connected_noti: 'Please check connection program.', ROBOT_reconnect: 'Connect Robot', ARDUINO_open_connector: 'Open program', ARDUINO_cloud_pc_connector: 'Connect to Cloud PC', CALC_get_x_coordinate: 'X Coordinate', CALC_get_y_coordinate: 'Y Coordinate', CALC_get_angle: 'Angle value', CALC_rotation_value: 'rotation value', CALC_direction_value: 'direction value', CALC_calc_mod_3: 'the rest of', CALC_timer_visible_1: '', CALC_timer_visible_show: 'Show', CALC_timer_visible_hide: 'Hide', CALC_timer_visible_2: 'Timer', FUNC: 'Function', color: 'color', brightness: 'brightness', opacity: 'Opacity', transparency: 'transparency', JUDGEMENT_boolean_and: 'AND', JUDGEMENT_boolean_or: 'OR', JUDGEMENT_true: 'True', JUDGEMENT_false: 'False', wall: 'wall', START_press_some_key_up: 'Up', START_press_some_key_down: 'Down', START_press_some_key_right: 'Right', START_press_some_key_left: 'Left', START_press_some_key_space: 'Space', START_press_some_key_enter: 'Enter', START_press_some_key_back_space: 'Backspace', START_press_some_key_back_slash: 'Backslash', SCENE_when_scene_start: 'When scene started', SCENE_start_scene_1: 'Start', SCENE_start_scene_2: 'scene', SCENE_start_neighbor_scene_1: 'Start', SCENE_start_neighbor_scene_2: 'scene', SCENE_start_scene_pre: 'prev', SCENE_start_scene_next: 'next', FUNCTION_explanation_1: 'name', FUNCTION_character_variable: 'string/number', FUNCTION_logical_variable: 'logical variable', FUNCTION_function: 'function', FUNCTION_define: 'Define function', FLOW_repeat_while_true_until: 'until', FLOW_repeat_while_true_while: 'while', FLOW_stop_object_all: 'All objects', FLOW_stop_object_this_object: 'This', FLOW_stop_object_this_thread: 'This code', FLOW_stop_object_other_thread: 'Other block of this object', FLOW_stop_object_other_objects: 'Other object', speak: 'Speak', think: 'Think', block_hi: 'Hi', LOOKS_change_shape_next: 'next', LOOKS_change_shape_prev: 'previous', LOOKS_change_object_index_sub_1: 'front', LOOKS_change_object_index_sub_2: 'forward', LOOKS_change_object_index_sub_3: 'backward', LOOKS_change_object_index_sub_4: 'back', entry: 'Entry', JUDGEMENT_is_clicked: 'mouse clicked?', JUDGEMENT_is_object_clicked: 'object clicked?', JUDGEMENT_is_type_1: 'is', JUDGEMENT_is_type_2: '?', is_type_number: 'number', JUDGEMENT_is_press_some_key_2: 'key pressed?', JUDGEMENT_reach_something_1: 'touching', JUDGEMENT_reach_something_2: '?', JUDGEMENT_boolean_not_1: 'is not', JUDGEMENT_boolean_not_2: '', JUDGEMENT_is_boost_mode: 'is the boost mode on?', CALC_calc_rand_1: 'random number between', CALC_calc_rand_2: 'and', CALC_calc_rand_3: '', CALC_coordinate_mouse_1: 'mouse pointer', CALC_coordinate_mouse_2: 'coordinate', CALC_coordinate_object_1: '', CALC_coordinate_object_2: 'of', CALC_coordinate_x_value: 'x coordinate', CALC_coordinate_y_value: 'y coordinate', CALC_coordinate_rotation_value: 'rotation', CALC_coordinate_direction_value: 'direction', CALC_coordinate_size_value: 'size', CALC_picture_index: 'shape number', CALC_picture_name: 'shape name', CALC_get_sound_volume: 'Volume', CALC_quotient_and_mod_1: '', CALC_quotient_and_mod_2: 'of', CALC_quotient_and_mod_3: '/', CALC_quotient_and_mod_sub_1: 'quotient', CALC_quotient_and_mod_sub_2: 'remainder', CALC_calc_operation_of_1: '', CALC_calc_operation_of_2: 'of', CALC_calc_operation_square: 'square', CALC_calc_operation_root: 'root', CALC_calc_operation_sin: 'sin', CALC_calc_operation_cos: 'cos', CALC_calc_operation_tan: 'tan', CALC_calc_operation_asin: 'asin', CALC_calc_operation_acos: 'acos', CALC_calc_operation_atan: 'atan', CALC_calc_operation_log: 'log', CALC_calc_operation_ln: 'natural log', CALC_calc_operation_unnatural: 'decimal value', CALC_calc_operation_floor: 'floor value', CALC_calc_operation_ceil: 'ceil value', CALC_calc_operation_round: 'round value', CALC_calc_operation_factorial: 'factorial value', CALC_calc_operation_abs: 'absolute value', CALC_get_timer_value: 'timer value', CALC_choose_project_timer_action_sub_1: 'Start', CALC_choose_project_timer_action_sub_2: 'Stop', CALC_choose_project_timer_action_sub_3: 'Reset', CALC_choose_project_timer_action_2: 'timer', CALC_get_date_1: 'current', CALC_get_date_year: 'year', CALC_get_date_month: 'month', CALC_get_date_day: 'day', CALC_get_date_hour: 'time(hour)', CALC_get_date_minute: 'time(minutes)', CALC_get_date_second: 'time(seconds)', CALC_get_date_day_of_week: 'day of week', CALC_get_date_2: '', CALC_distance_something_1: 'distance to', CALC_distance_something_2: '', CALC_get_sound_duration_1: 'Length of', CALC_get_sound_duration_2: 'sound', CALC_length_of_string_1: 'length of', CALC_reverse_of_string_1: 'reverse', VARIABLE_combine_something_1: 'join', VARIABLE_combine_something_2: 'and', VARIABLE_combine_something_3: '', CALC_char_at_1: '', CALC_char_at_2: 'th letter of', hi_entry: 'Hello Entry!', hi_entry_en: 'Hello Entry!', CALC_substring_1: 'substring of', CALC_substring_2: 'from', CALC_substring_3: 'to', CALC_count_match_string_1: 'count of', CALC_count_match_string_2: 'in', CALC_index_of_string_1: 'index of', CALC_index_of_string_2: 'in', CALC_replace_string_1: 'replace', CALC_replace_string_2: 'in', CALC_replace_string_3: 'with', hello: 'Hello', nice: 'nice to meet you', CALC_change_string_case_2: 'to', CALC_change_string_case_sub_1: 'uppercase', CALC_change_string_case_sub_2: 'lowercase', CALC_change_string_case_3: ' ', VARIABLE_get_canvas_input_value: 'response', VARIABLE_get_variable_1: 'Value of', VARIABLE_value_of_index_from_list_1: 'value of', VARIABLE_value_of_index_from_list_3: 'th element', VARIABLE_length_of_list_1: 'length of', VARIABLE_is_included_in_list_1: 'is included in', VARIABLE_is_included_in_list_2: 'value', table_row: 'row', table_col: 'column', table_sum: 'sum', table_max: 'max', table_min: 'min', table_avg: 'average', table_stdev: 'standard deviation', table_median: 'median', date_yesterday: 'yesterday', date_today: 'today', date_tomorrow: 'tomorrow', date_after_2_days: 'after 2 days', date_after_3_days: 'after 3 days', date_after_4_days: 'after 4 days', date_after_5_days: 'after 5 days', date_after_6_days: 'after 6 days', tts_kind: 'kind', tts_sweet: 'sweet', tts_echo: 'echo', tts_mischievous: 'mischievous', tts_dainty: 'dainty', tts_sabina: 'Witch', tts_mammon: 'Demon', tts_kitty: 'Kitty', tts_doggy: 'Doggy', tts_veryslow: 'very slow', tts_slow: 'slow', tts_normal: 'normal', tts_fast: 'fast', tts_veryfast: 'very fast', tts_verylow: 'very low', tts_low: 'low', tts_high: 'high', tts_veryhigh: 'very high', korean: 'Korean', english: 'English', japan: 'Japanese', korean_s: 'korean', english_s: 'english', japan_s: 'japanese', chinese_simplified: 'Simplified Chinese', chinese_traditional: 'Traditional Chinese', spanish: 'Spanish', french: 'French', german: 'German', russian: 'Russian', portuguese: 'Portuguese', thai: 'Thai', vietnamese: 'Vietnamese', indonesian: 'Indonesian', hindi: 'Hindi', AI_UTILIZE: 'AI', video_show_video: 'Show', video_hide_video: 'Hide', video_brightness: 'brightness', video_transparency: 'transparency', video_left_right: 'horizontally', video_top_bottom: 'vertically', video_human: 'Human', video_face: 'Face', video_object: 'object', video_start: 'Start', video_end: 'Stop', video_gender: 'gender', video_age: 'age', video_emotion: 'emotion', video_motion_onself: 'this object', video_motion_onscreen: 'screen', video_motion_scale: 'Motion', video_motion_direction_horizontal: 'X direction', video_motion_direction_vertical: 'Y direction', ALTINO_Steering_Angle_Left10: 'left10', ALTINO_Steering_Angle_Left15: 'left15', ALTINO_Steering_Angle_Left20: 'left20', ALTINO_Steering_Angle_Right5: 'right5', ALTINO_Steering_Angle_Right10: 'right10', ALTINO_Steering_Angle_Right15: 'right15', XBOT_D2_digitalInput: 'D2 Digital Input', XBOT_D3_digitalInput: 'D3 Digital Input', XBOT_D11_digitalInput: 'D11 Digital Input', XBOT_CDS: 'Light Sensor Value', XBOT_MIC: 'Mic Sensor Value', XBOT_analog0: 'Analog PIN0 Value', ALTINO_Steering_Angle_Right20: 'right20', XBOT_analog1: 'Analog PIN1 Value', XBOT_analog2: 'Analog PIN2 Value', XBOT_analog3: 'Analog PIN3 Value', XBOT_High: 'HI', XBOT_Low: 'LO', ALTINO_h: 'off', XBOT_Head: 'Head(D8)', ALTINO_c: 'do', XBOT_ArmR: 'Right Arm(D9)', XBOT_ArmL: 'Left Arm(D10)', XBOT_rightWheel: 'Right', ALTINO_c2: 'do#', ALTINO_d: 're', ALTINO_d2: 're#', ALTINO_e: 'mi', EXPANSION_WEATHER_sunny: 'sunny', ALTINO_f: 'fa', XBOT_leftWheel: 'Left', ALTINO_f2: 'fa#', XBOT_bothWheel: 'Both', XBOT_c: 'C', XBOT_d: 'D', XBOT_e: 'E', XBOT_f: 'F', XBOT_g: 'G', XBOT_a: 'A', XBOT_b: 'B', EXPANSION_WEATHER_partly_cloudy: 'partly cloudy', EXPANSION_WEATHER_mostly_cloudy: 'mostly cloudy', EXPANSION_WEATHER_cloudy: 'cloudy', ALTINO_g: 'sol', EXPANSION_WEATHER_rainy: 'rainy', EXPANSION_WEATHER_sleet: 'sleet', EXPANSION_WEATHER_snowy: 'snowy', ALTINO_g2: 'sol#', EXPANSION_WEATHER_finedust_good: 'good', ALTINO_a: 'la', EXPANSION_WEATHER_finedust_normal: 'normal', ALTINO_a2: 'la#', EXPANSION_WEATHER_finedust_bad: 'bad', ALTINO_b: 'si', EXPANSION_WEATHER_finedust_very_bad: 'very bad', ALTINO_Led_Forward_Light: 'forward', EXPANSION_WEATHER_lowest_temperature: 'the lowest temperature(℃)', ALTINO_Led_Turn_Left_Light: 'left direction', EXPANSION_WEATHER_highest_temperature: 'the highest temperature(℃)', ALTINO_Led_Turn_Right_Light: 'right direction', EXPANSION_WEATHER_humidity: 'humidity(%)', ALTINO_Led_Brake_Light: 'brake', EXPANSION_WEATHER_precipitation: 'precipitation(mm)', ALTINO_Led_Reverse_Light: 'backward', EXPANSION_WEATHER_precipitation_probability: 'precipitation probability(%)', ALTINO_h2: 'on', EXPANSION_WEATHER_wind_speed: 'wind speed(m/s)', EXPANSION_WEATHER_temperature: 'temperature(℃)', EXPANSION_WEATHER_finedust: 'concentration of fine dust(㎍)', ardublock_motor_forward: 'Forward', ardublock_motor_backward: 'Backward', ARDUINO_on: 'Turn on', ARDUINO_off: 'Turn off', EXPANSION_FESTIVAL_title: 'Title', EXPANSION_FESTIVAL_area: 'area', EXPANSION_FESTIVAL_start_date: 'start date', EXPANSION_FESTIVAL_end_date: 'end date', EXPANSION_FESTIVAL_address: 'address', EXPANSION_FESTIVAL_overview: 'overview', EXPANSION_FESTIVAL_homepage: 'homepage', behaviorConduct01001: 'Typhoon', behaviorConduct01002: 'Flood', behaviorConduct01003: 'Heavy rain', behaviorConduct01004: 'Gale', behaviorConduct01005: 'Heavy snow', behaviorConduct01006: 'Cold wave', behaviorConduct01007: 'Storm', behaviorConduct01008: 'Dust storm', behaviorConduct01009: 'Heatwave', behaviorConduct01010: 'Drought', behaviorConduct01011: 'Earthquake', behaviorConduct01013: 'Tsunami', behaviorConduct01014: 'Landslide', behaviorConduct03002: 'First aid', behaviorConduct03003: 'CPR', behaviorConduct03004: 'Fire extinguishers use', behaviorConduct03016: 'Fireplug use', ROBOID_head: 'head', behaviorConduct03005: 'Food poisoning', behaviorConduct03006: 'Climbing safety', behaviorConduct03008: 'Kidnapping·Missing', behaviorConduct03009: 'SAE', behaviorConduct03010: 'School violence', behaviorConduct03011: 'Domestic Violence', behaviorConduct03012: 'Detention and abduction', behaviorConduct03013: 'Traffic Accident', behaviorConduct03014: 'Elevator accident', behaviorConduct03015: 'Fine dust', behaviorConduct01001001: 'Before the typhoon comes', behaviorConduct01001002: 'When the typhoon warning occurs', behaviorConduct01001003: 'After the typhoon has passed', behaviorConduct01002002: 'When the flood forecast occurs', behaviorConduct01002003: 'When the water is pushed', behaviorConduct01002004: 'After the water ir removed', behaviorConduct01003002: 'When the heavy rain forecast occurs', behaviorConduct01003003: 'When the heavy rain warning occurs', behaviorConduct01003004: 'After the heavy rain has passed', behaviorConduct01004001: 'Before the gale comes', behaviorConduct01004002: 'When the gale occurs', behaviorConduct01005002: 'Before the heavy snow comes', behaviorConduct01005003: 'When the heavy snow occurs', behaviorConduct01005004: 'After the heavy snow has passed', behaviorConduct01006001: 'Before the cold wave comes', behaviorConduct01006002: 'When the cold wave occurs', behaviorConduct01007001: 'When the storm warning occurs', behaviorConduct01007002: 'Before the storm comes', behaviorConduct01008001: 'When the dust storm forecast occurs', behaviorConduct01008002: 'When the dust storm occurs', behaviorConduct01008003: 'After the dust storm has passed', behaviorConduct01009001: 'Before the heatwave comes', behaviorConduct01009002: 'When the heatwave watch occurs', behaviorConduct01010001: 'When the drought occurs', behaviorConduct01011009: 'Before the earthquakes comes', behaviorConduct01011010: 'When the earthquake occurs', behaviorConduct01011012: 'After the earthquake evacuation', behaviorConduct01013002: 'Before the tsunami comes', behaviorConduct01013003: 'When the tsunami occurs', behaviorConduct01014001: 'When the landslide watch occurs', behaviorConduct03002002: 'treat burns', behaviorConduct03002003: 'prevent fever', behaviorConduct03002004: 'treat when bitten by a snake', behaviorConduct03002005: 'treat when shot by bee', behaviorConduct03002006: 'do first aid hyperventilation syndrome', behaviorConduct03003001: 'do adult CPR', behaviorConduct03003002: 'do infant CPR', behaviorConduct03003003: 'use an automatic defibrillator', behaviorConduct03004001: 'use a powder fire extinguisher', behaviorConduct03016001: 'use a indoor fire hydrants', behaviorConduct03005001: 'treat food poisoning', behaviorConduct03006004: 'climb the mountain safely', behaviorConduct03006005: 'In the mountain safe camping', behaviorConduct03006002: 'notify information on a rescue request', behaviorConduct03006003: 'do first aid in mountain accident', behaviorConduct03008001: 'prevent kidnapping∙missing', behaviorConduct03009001: 'prevent harassment', behaviorConduct03010001: 'prevent school violence', behaviorConduct03011001: 'prevent domestic violence', behaviorConduct03012001: 'handle detention∙abduction', behaviorConduct03013002: 'handle traffic accidents', behaviorConduct03013005: 'rescue from a vehicle', behaviorConduct03014001: 'use elevator safely', behaviorConduct03014003: 'handle elevator malfunction', behaviorConduct03014004: 'use escalator safely', behaviorConduct03015007: 'live on fine dusty day', behaviorConduct03015003: 'live by sector', emergencyActionGuidelines01001: 'typhoon', emergencyActionGuidelines01001001: '태풍 예보 시', emergencyActionGuidelines01001002: '태풍 특보 시', emergencyActionGuidelines01001003: '태풍 이후', emergencyActionGuidelines01002: 'flood', emergencyActionGuidelines01002001: '홍수 예·경보 시', emergencyActionGuidelines01002002: '홍수 우려 때', emergencyActionGuidelines01002003: '물이 밀려들 때', emergencyActionGuidelines01002004: '물이 빠진 후에', emergencyActionGuidelines01003: 'heavy rain', emergencyActionGuidelines01003001: '호우 대비', emergencyActionGuidelines01003002: '호우 예보 시', emergencyActionGuidelines01003003: '호우 특보 중', emergencyActionGuidelines01003004: '호우 이후', emergencyActionGuidelines01004: 'strong wind', emergencyActionGuidelines01004001: '강풍 대비', emergencyActionGuidelines01004002: '강풍 발생 시', emergencyActionGuidelines01004003: '강풍 관련', emergencyActionGuidelines01005: 'heavy snow', emergencyActionGuidelines01005001: '대설 대비', emergencyActionGuidelines01005002: '대설 예보 시', emergencyActionGuidelines01005003: '대설 특보 시', emergencyActionGuidelines01005004: '대설 이후', emergencyActionGuidelines01006: 'cold wave', emergencyActionGuidelines01006001: '한파 대비', emergencyActionGuidelines01006002: '한파 발생 시', emergencyActionGuidelines01007: 'rough seas', emergencyActionGuidelines01007001: '풍랑 특보 시', emergencyActionGuidelines01008: 'yellow dust', emergencyActionGuidelines01008001: '황사 대비', emergencyActionGuidelines01008002: '황사 발생 시', emergencyActionGuidelines01008003: '황사 이후', emergencyActionGuidelines01008003: '황사 관련', emergencyActionGuidelines01009: 'heat wave', emergencyActionGuidelines01009001: '폭염 대비', emergencyActionGuidelines01009002: '폭염 발생 시', emergencyActionGuidelines01009003: '폭염 관련', emergencyActionGuidelines01010: 'drought', emergencyActionGuidelines01010001: '가뭄 시 생활', emergencyActionGuidelines01010002: '가뭄 시 농촌', emergencyActionGuidelines01011: 'earthquake', emergencyActionGuidelines01011007: '지진 발생 시 상황별', emergencyActionGuidelines01011008: '지진 발생 시 장소별', emergencyActionGuidelines01011009: '지진 대비', emergencyActionGuidelines01011010: '지진 발생 시', emergencyActionGuidelines01011011: '지진 장소별', emergencyActionGuidelines01011012: '지진 대피 후', emergencyActionGuidelines01012: 'tsunami', emergencyActionGuidelines01012005: '발생 시 (선박 위)', emergencyActionGuidelines01012006: '발생 시 (지상 대피)', emergencyActionGuidelines01013: 'tidal wave', emergencyActionGuidelines01013001: '해일 대비', emergencyActionGuidelines01013002: '해일 때', emergencyActionGuidelines01013003: '해일 발생 때', emergencyActionGuidelines01013004: '미쳐 대피 못한 때', emergencyActionGuidelines01013005: '폭풍해일', emergencyActionGuidelines01014: 'landslide', emergencyActionGuidelines01014001: '산사태 취약 지역 (주의보)', emergencyActionGuidelines01014002: '산사태 취약 지역 (경보)', emergencyActionGuidelines01014003: '일반 지역 (주의보)', emergencyActionGuidelines01014004: '일반 지역 (경보)', emergencyActionGuidelines01015: 'volcanic eruption', emergencyActionGuidelines01015001: '화산재 낙하 대비', emergencyActionGuidelines01015002: '화산재 낙하 시', emergencyActionGuidelines01015003: '화산재 제거 이유', emergencyActionGuidelines02001: 'marine pollution', emergencyActionGuidelines02001001: '발생 전', emergencyActionGuidelines02001002: '발생 시', emergencyActionGuidelines02001003: '조치 완료 후', emergencyActionGuidelines02002: 'large-scale water pollution', emergencyActionGuidelines02002001: '사고 시', emergencyActionGuidelines02002002: '구별 방법', emergencyActionGuidelines02003: 'water shortage', emergencyActionGuidelines02003001: '급수중단 발령 시', emergencyActionGuidelines02003002: 'Ⅰ급상황 발생 시', emergencyActionGuidelines02003003: 'Ⅱ급상황 발생 시', emergencyActionGuidelines02004: 'utility tunnel disaster', emergencyActionGuidelines02004001: '발생 우려 시', emergencyActionGuidelines02004002: '발생 시', emergencyActionGuidelines02005: 'livestock disease', emergencyActionGuidelines02005001: '구제역 발생 시', emergencyActionGuidelines02005002: '조류인플루엔자(AI) 발생 시', emergencyActionGuidelines02005003: '발생 방지 대책', emergencyActionGuidelines02005004: '발생 의심 시', emergencyActionGuidelines02005005: '발생 확인 시', emergencyActionGuidelines02006: 'infectious disease', emergencyActionGuidelines02006001: '예방 대책', emergencyActionGuidelines02006002: '증상이 나타날 때', emergencyActionGuidelines02006003: '중동호흡기증후군(MERS)', emergencyActionGuidelines02007: 'railway and subway', emergencyActionGuidelines02007001: '지하철 화재 발생 시', emergencyActionGuidelines02007002: '고속철도 화재 발생 시', emergencyActionGuidelines02007003: '사고 및 테러(독가스) 발생 시', emergencyActionGuidelines02008: 'financial IT system', emergencyActionGuidelines02008001: '보이스피싱 피해금 지급 정지', emergencyActionGuidelines02008002: '보이스피싱 피해 예방', emergencyActionGuidelines02009: 'nuclear power plant accident', emergencyActionGuidelines02009001: '국민보호조치 발표 시', emergencyActionGuidelines02009002: '방사능구름 통과 시', emergencyActionGuidelines02009003: '옥내 대피 및 소개 시', emergencyActionGuidelines02010: 'chemical accident', emergencyActionGuidelines02010001: '화학물질 유출 시', emergencyActionGuidelines02010002: '니트로글리세린 누출 시', emergencyActionGuidelines02010003: '트리니트로톨루엔 누출 시', emergencyActionGuidelines02010004: '화학유해물질(독성가스) 누출 시', emergencyActionGuidelines02011: 'fire', emergencyActionGuidelines02011001: '일반', emergencyActionGuidelines02011002: '예방 대책', emergencyActionGuidelines02011003: '화재 발생 후', emergencyActionGuidelines02011004: '화재 시', emergencyActionGuidelines02011005: '화재 시 긴급 대피', emergencyActionGuidelines02011006: '화재 시 피해 복구', emergencyActionGuidelines02011007: '가정에서의 안전', emergencyActionGuidelines02011008: '연기 관련 정보', emergencyActionGuidelines02011009: '아파트 화재 시', emergencyActionGuidelines02011010: '아파트 화재 대비', emergencyActionGuidelines02011011: '도로 터널 화재', emergencyActionGuidelines02011012: '대형 화재', emergencyActionGuidelines02011013: '고층 건물 화재', emergencyActionGuidelines02011014: '지하상가 화재 안전수칙', emergencyActionGuidelines02011015: '지하철 화재 발생 시', emergencyActionGuidelines02012: 'wildfire', emergencyActionGuidelines02012001: '주택가 산불 확산 시', emergencyActionGuidelines02012002: '산불 방지', emergencyActionGuidelines02012003: '봄철 산불 관련', emergencyActionGuidelines02012004: '산불 예방', emergencyActionGuidelines02012005: '산불 발생 후', emergencyActionGuidelines02012006: '산불 대피', emergencyActionGuidelines02012007: '산불 피해 지역 가축 관리', emergencyActionGuidelines02013: 'building collapse', emergencyActionGuidelines02013001: '사고 발생 시', emergencyActionGuidelines02013002: '징조를 느낄 때', emergencyActionGuidelines02013003: '건물 내부에 있을 때', emergencyActionGuidelines02013004: '건물 외부에 있을 때', emergencyActionGuidelines02013005: '붕괴, 매몰된 경우', emergencyActionGuidelines02013007: '도로 공사장 붕괴', emergencyActionGuidelines02013008: '상수도 공사장 붕괴', emergencyActionGuidelines02013009: '아파트 공사장 붕괴', emergencyActionGuidelines02013010: '지하철 공사장 붕괴', emergencyActionGuidelines02014: 'dam collapse', emergencyActionGuidelines02014001: '붕괴 우려 시', emergencyActionGuidelines02014002: '붕괴 발생 시', emergencyActionGuidelines02014003: '물이 빠진 후', emergencyActionGuidelines02015: 'explosion', emergencyActionGuidelines02015001: '가스 폭발 시', emergencyActionGuidelines02015004: '폭발 현장', emergencyActionGuidelines02016: 'aircraft accident', emergencyActionGuidelines02016001: '항공기 사고 예방', emergencyActionGuidelines02017: 'CBRN incident', emergencyActionGuidelines02017001: '사고 발생 시', emergencyActionGuidelines02018: 'power outage', emergencyActionGuidelines02018001: '정전 시', emergencyActionGuidelines02018002: '정전 발생 시', emergencyActionGuidelines02018003: '정전 상황별', emergencyActionGuidelines02019: 'electricity·gas', emergencyActionGuidelines02019001: '전기사고 예방', emergencyActionGuidelines02019002: '침수지역 감전 사고 예방', emergencyActionGuidelines02019003: '대피 명령 시 전기설비 조치', emergencyActionGuidelines02019004: '정전 발생 시 조치', emergencyActionGuidelines02019005: '야외 주의 사항', emergencyActionGuidelines02019006: '가스사고 예방', emergencyActionGuidelines02019007: '가스사고 발생 시', emergencyActionGuidelines02019008: 'LPG 응급조치', emergencyActionGuidelines02019009: '도시가스(LNG) 응급조치', emergencyActionGuidelines02019010: '이동식 부탄가스 안전점검', emergencyActionGuidelines02019011: '가스 사용 시 안전점검', emergencyActionGuidelines02019012: '가스 누출 발생 시 대피', emergencyActionGuidelines02019013: '배관 등에서 대량 누출 시', emergencyActionGuidelines02019014: '기타 사항', emergencyActionGuidelines02019015: '암모니아가스 인체 접촉 시', emergencyActionGuidelines02019016: '염소가스 누출 시', emergencyActionGuidelines02020: 'passenger ship', emergencyActionGuidelines02020001: '이용객 금지 행위', emergencyActionGuidelines02020002: '사고 발생 시', emergencyActionGuidelines02021: 'water accident', emergencyActionGuidelines02021001: '하천이나 계곡물', emergencyActionGuidelines02021002: '무릎 이상의 깊은 급류', emergencyActionGuidelines02021003: '물에 빠졌을 때', emergencyActionGuidelines02021004: '파도가 높아져 위험할 때', emergencyActionGuidelines02021005: '수초에 감겼을 때', emergencyActionGuidelines02021006: '의식 없는 사고자를 구했을 때', emergencyActionGuidelines02021007: '고립 지역', emergencyActionGuidelines02021008: '계곡에서 야영지를 선택 시', emergencyActionGuidelines02021009: '보트 전복 등에 따른 대처', emergencyActionGuidelines02021010: '갯바위 등 바다낚시 사고 예방', emergencyActionGuidelines02021011: '갯벌 해루질 사고 예방', emergencyActionGuidelines02022: 'terrorism', emergencyActionGuidelines02022007: '신고 요령', emergencyActionGuidelines02022008: '대형, 고층건물 재난 시', emergencyActionGuidelines02022009: '폭발물 발견 시', emergencyActionGuidelines02022010: '화학 테러(독가스 등) 발생 시', emergencyActionGuidelines02022011: '생물 테러 발생 시', emergencyActionGuidelines02022012: '방사능 테러 발생 시', emergencyActionGuidelines02022013: '화재 발생 시', emergencyActionGuidelines02022014: '총격 현장', emergencyActionGuidelines02022015: '매몰, 붕괴 시', emergencyActionGuidelines02022016: '억류, 납치 시', emergencyActionGuidelines02022017: '테러범·의심물체 등', emergencyActionGuidelines02023: 'power shortage', emergencyActionGuidelines02023001: '단계별', emergencyActionGuidelines03002: 'first aid', emergencyActionGuidelines03002001: '일반', emergencyActionGuidelines03002002: '화상', emergencyActionGuidelines03002003: '온열질환', emergencyActionGuidelines03002004: '뱀에 물렸을 때', emergencyActionGuidelines03002005: '벌에 쏘였을 때', emergencyActionGuidelines03002006: '과호흡증후군', emergencyActionGuidelines03002007: '상비약', emergencyActionGuidelines03003: 'CPR', emergencyActionGuidelines03003001: '성인', emergencyActionGuidelines03003002: '영유아', emergencyActionGuidelines03003003: '자동제세동기', emergencyActionGuidelines03004: 'fire extinguisher', emergencyActionGuidelines03004001: '분말 소화기', emergencyActionGuidelines03004002: '투척용 소화기', emergencyActionGuidelines03004003: '설치/취급 및 사용법', emergencyActionGuidelines03004004: '소화기의 종류', emergencyActionGuidelines03005: 'food poisoning', emergencyActionGuidelines03005001: '일반', emergencyActionGuidelines03005002: '음식점/급식소 운영자', emergencyActionGuidelines03006: 'hiking', emergencyActionGuidelines03006001: '위급 상황 시', emergencyActionGuidelines03006002: '구조 요청 시', emergencyActionGuidelines03006003: '응급조치', emergencyActionGuidelines03007: "children's playground", emergencyActionGuidelines03007001: '탑승 대기', emergencyActionGuidelines03007002: '안전 이용', emergencyActionGuidelines03007003: '탑승 제한', emergencyActionGuidelines03007004: '어린이 탑승', emergencyActionGuidelines03007005: '탑승 시 주의', emergencyActionGuidelines03007006: '운행 중 자세', emergencyActionGuidelines03007007: '탑승 완료 후 퇴장', emergencyActionGuidelines03008: 'missing·kidnapping', emergencyActionGuidelines03008001: '예방 방법', emergencyActionGuidelines03009: 'sexual violence', emergencyActionGuidelines03009001: '예방 방법', emergencyActionGuidelines03010: 'school violence', emergencyActionGuidelines03010001: '예방 방법', emergencyActionGuidelines03011: 'domestic violence', emergencyActionGuidelines03011001: '예방 방법', emergencyActionGuidelines03012: 'detention·abduction', emergencyActionGuidelines03012001: '대처 요령', emergencyActionGuidelines03013: 'traffic accident', emergencyActionGuidelines03013001: '사고 예방', emergencyActionGuidelines03013002: '발생 시', emergencyActionGuidelines03013003: '상황 판단', emergencyActionGuidelines03013004: '구출', emergencyActionGuidelines03013005: '차량에서의 구조', emergencyActionGuidelines03014: 'elevator', emergencyActionGuidelines03014001: '안전 이용', emergencyActionGuidelines03014002: '안전 문화', emergencyActionGuidelines03014003: '고장 시 안전 구조', emergencyActionGuidelines03014004: '에스컬레이터 안전 수칙', emergencyActionGuidelines03014005: '엘리베이터 사고 예방', emergencyActionGuidelines03014006: '에스컬레이터 및 무빙워크 사고 예방', emergencyActionGuidelines03015: 'fine dust', emergencyActionGuidelines03015001: '특성', emergencyActionGuidelines03015002: '미세먼지 예보 등급별', emergencyActionGuidelines03015003: '부문별 생활 수칙', emergencyActionGuidelines03015004: '인체에 미치는 영향', emergencyActionGuidelines03015005: '미세먼지 정보', emergencyActionGuidelines03015006: '미세먼지 발생 시', emergencyActionGuidelines03015007: '미세먼지 많은 날', emergencyActionGuidelines03016: 'fire hydrant', emergencyActionGuidelines03016001: '옥내소화전 사용법', emergencyActionGuidelines03016002: '경보 설비', emergencyActionGuidelines03017: 'home safety inspection', emergencyActionGuidelines03017001: '안전점검의 날 준비', emergencyActionGuidelines03017002: '계절별 대비', tts_female: 'female', tts_male: 'male', ROBOID_tail: 'tail', SCENE: 'Scene', entry_bot_name: 'Entrybot', doggi_bark: "Doggi's Bark", walking_entryBot: 'Walking Entrybot', silent: 'Silent', do_name: 'Do', do_sharp_name: 'Do#(Re♭)', re_name: 'Re', re_sharp_name: 'Re(Mi♭)', BITBRICK_dc_direction_cw: 'CW', BITBRICK_dc_direction_ccw: 'CCW', blacksmith_toggle_on: 'on', blacksmith_toggle_off: 'off', blacksmith_lcd_first_line: 'first', show_all_comment: 'show all memos', blacksmith_lcd_seconds_line: 'seconds', mi_name: 'Mi', fa_name: 'Fa', fa_sharp_name: 'Fa#(Sol♭)', sol_name: 'Sol', sol_sharp_name: 'Sol#(La♭)', la_name: 'La', la_sharp_name: 'La#(Si♭)', si_name: 'Si', ROBOID_color_black: 'black', ROBOID_clicked: 'clicked', ROBOID_double_clicked: 'double-clicked', ROBOID_long_pressed: 'long-pressed', ROBOID_color_any: 'any color', ROBOID_back: 'back', START: 'Start', FLOW: 'Flow', MOVING: 'Motion', LOOKS: 'Looks', BRUSH: 'Brush', ROBOID_sound_dibidibidip: 'dibidibidip', TEXT: 'Text', ROBOID_sound_good_job: 'good job', SOUND: 'Sound', JUDGEMENT: 'Decision', CALC: 'Figures', VARIABLE: 'Variable', ANALYSIS: 'Table', EXPANSION: 'Extension', ARDUINO: 'Hardware', ROBOID_sound_march: 'march', ROBOID_sound_birthday: 'birthday', no_target: 'No Target', Paste_blocks: 'paste code(s)', tidy_up_block: 'tidy up the blocks', Clear_all_blocks: 'remove all codes', add_comment: 'add a memo', hide_all_comment: 'hide all memos', ROBOID_left: 'left', ROBOID_right: 'right', ROBOID_both: 'both', ROBOID_color_red: 'red', ROBOID_color_yellow: 'yellow', ROBOID_color_green: 'green', ROBOID_color_sky_blue: 'sky blue', ROBOID_color_blue: 'blue', ROBOID_color_purple: 'purple', ROBOID_color_white: 'white', ROBOID_unit_cm: 'cm', oneself: 'Self', ROBOID_unit_sec: 'seconds', ROBOID_unit_pulse: 'pulses', ROBOID_unit_deg: 'degrees', ROBOID_color_orange: 'orange', ROBOID_color_violet: 'violet', ROBOID_sound_beep: 'beep', ROBOID_sound_random_beep: 'random beep', ROBOID_sound_siren: 'siren', ROBOID_sound_engine: 'engine', ROBOID_sound_robot: 'robot', ALTINO_CDS: 'light', ALTINO_ACCX: 'acceleration X axis', ALTINO_ACCY: 'acceleration Y axis', ALTINO_ACCZ: 'acceleration Z axis', ALTINO_MAGX: 'geomagnetic X axis', ALTINO_MAGY: 'geomagnetic Y axis', ALTINO_MAGZ: 'geomagnetic Z axis', ALTINO_GYROX: 'gyro X axis', ALTINO_GYROY: 'gyro Y axis', ALTINO_GYROZ: 'gyro Z axis', ALTINO_IR1: '1 distance', ALTINO_IR2: '2 distance', ALTINO_IR3: '3 distance', ALTINO_IR4: '4 distance', ALTINO_IR5: '5 distance', ALTINO_IR6: '6 distance', ALTINO_TEM: 'temperature', ALTINO_TOR2: 'left torque', ALTINO_TOR1: 'right torque', ALTINO_STTOR: 'steering torque', ALTINO_BAT: 'battery check', ALTINO_Steering_Angle_Center: 'center', ALTINO_Steering_Angle_Left5: 'left5', mouse_pointer: 'mouse cursor', self: 'self', wall_up: 'upper wall', wall_down: 'down wall', wall_right: 'right wall', wall_left: 'left wall', length_of_string: 'to', auto: 'auto', chocopi_touch_event_touch: 'touched', chocopi_touch_event_untouch: 'untouched', chocopi_control_event_pressed: 'pressed', chocopi_control_event_released: 'released', chocopi_joystick_X: 'joystick X', chocopi_joystick_Y: 'joystick Y', chocopi_pot: 'potentiometer', chocopi_motion_photogate_time_unblocked: 'unblocked', chocopi_motion_photogate_time_blocked: 'blocked', chocopi_motion_photogate_event_unblocked: 'unblocked', chocopi_motion_photogate_event_blocked: 'blocked', coconut_move_forward: 'forward', coconut_move_backward: 'backward', coconut_turn_left: 'left', coconut_turn_right: 'right', coconut_color_red: 'Red', coconut_color_yellow: 'Yellow', coconut_color_green: 'Green', coconut_color_cyan: 'Cyan', coconut_color_blue: 'Blue', coconut_color_magenta: 'Magenta', coconut_color_white: 'White', coconut_left_led: 'left led', coconut_right_led: 'right led', coconut_both_leds: 'both led', coconut_note_c: 'note_c', coconut_note_d: 'note_d', coconut_note_e: 'note_e', coconut_note_f: 'note_f', coconut_note_g: 'note_g', coconut_note_a: 'note_a', coconut_note_b: 'note_b', coconut_play_buzzer_hn: 'Half', coconut_play_buzzer_qn: 'Quater', coconut_play_buzzer_en: 'Eighth', coconut_play_buzzer_sn: 'Sixteenth', coconut_play_buzzer_tn: 'Thirty-second', coconut_play_buzzer_wn: 'Whole', coconut_play_buzzer_dhn: 'Dotted half', coconut_play_buzzer_dqn: 'Dotted quarter', coconut_play_buzzer_den: 'Dotted eighth', coconut_play_buzzer_dsn: 'Dotted sixteenth', coconut_play_buzzer_dtn: 'Dotted thirty-second', coconut_rest_buzzer_hr: 'Half_rest', coconut_rest_buzzer_qr: 'Quater_rest', coconut_rest_buzzer_er: 'Eighth_rest', coconut_rest_buzzer_sr: 'Sixteenth_rest', coconut_rest_buzzer_tr: 'Thirty-second rest', coconut_rest_buzzer_wr: 'Whole_rest', ALBERT_note_c: 'C', ALBERT_note_d: 'D', ALBERT_note_e: 'E', ALBERT_note_f: 'F', ALBERT_note_g: 'G', ALBERT_note_a: 'A', ALBERT_note_b: 'B', coconut_play_midi_1: 'Twinkle Twinkle little star', coconut_play_midi_2: 'Three bears', coconut_play_midi_3: "Mozart's Lullaby", coconut_play_midi_4: 'Do-Re-Mi', coconut_play_midi_5: 'Butterfly', coconut_sensor_both_floor: 'both line tracer', coconut_floor_sensing_on: 'detect', coconut_floor_sensing_off: 'not detect', coconut_sensor_both_proximity: 'both IR distance', coconut_dotmatrix_set_on: 'on', coconut_dotmatrix_set_off: 'off', coconut_dotmatrix_row_0: 'all', coconut_dotmatrix_row_1: '1', coconut_dotmatrix_row_2: '2', coconut_dotmatrix_row_3: '3', coconut_dotmatrix_row_4: '4', coconut_dotmatrix_row_5: '5', coconut_dotmatrix_row_6: '6', coconut_dotmatrix_row_7: '7', coconut_dotmatrix_row_8: '8', coconut_dotmatrix_col_0: 'all', coconut_dotmatrix_col_1: '1', coconut_dotmatrix_col_2: '2', coconut_dotmatrix_col_3: '3', coconut_dotmatrix_col_4: '4', coconut_dotmatrix_col_5: '5', coconut_dotmatrix_col_6: '6', coconut_dotmatrix_col_7: '7', coconut_dotmatrix_col_8: '8', coconut_x_axis: 'X-Axis', coconut_y_axis: 'Y-Axis', coconut_z_axis: 'Z-Axis', CODEino_sensor_name_0: 'Sound', CODEino_sensor_name_1: 'Light', CODEino_sensor_name_2: 'Slider', CODEino_sensor_name_3: 'resistance-A', CODEino_sensor_name_4: 'resistance-B', CODEino_sensor_name_5: 'resistance-C', CODEino_sensor_name_6: 'resistance-D', CODEino_string_11: 'Great', CODEino_string_12: 'Small', CODEino_string_14: 'Bright', CODEino_string_15: 'Dark', CODEino_string_3: 'Push button', CODEino_string_4: 'Connected A', CODEino_string_5: 'Connected B', CODEino_string_6: 'Connected C', CODEino_string_7: 'Connected D', CODEino_string_16: 'Left tilt', CODEino_string_17: 'Right tilt', CODEino_string_18: 'Front tilt', CODEino_string_19: 'Rear tilt', CODEino_string_20: 'Reverse', CODEino_led_red: 'Red', CODEino_led_green: 'Green', CODEino_led_blue: 'Blue', jdkit_led_turnon: 'Turn on', jdkit_led_turnoff: 'Turn off', jdkit_led: 'LED', ev3_cw: 'CW', ev3_ccw: 'CCW', roborobo_motor_stop: 'Stop', roborobo_motor_CW: 'ClockWise', roborobo_motor_CCW: 'CounterClockWise', FUNBOARD_bt_up: 'red(A)', FUNBOARD_bt_down: 'yellow(B)', FUNBOARD_bt_left: 'green(C)', FUNBOARD_bt_right: 'blue(D)', FUNBOARD_touchbt_up: 'red(A)', FUNBOARD_touchbt_down: 'yellow(B)', FUNBOARD_touchbt_left: 'green(C)', FUNBOARD_touchbt_right: 'blue(D)', FUNBOARD_touchbt_space: ' E', FUNBOARD_touchbt_enter: ' F', FUNBOARD_touchbt_escape: ' G', FUNBOARD_sensor_slide: 'potentiometer', FUNBOARD_sensor_cds: 'light sensor', FUNBOARD_sensor_mic: 'microphone sensor', FUNBOARD_sensor_state_1: 'low', FUNBOARD_sensor_state_2: 'high', FUNBOARD_led_color_red: 'red', FUNBOARD_led_color_yellow: 'yellow', FUNBOARD_led_color_green: 'green', FUNBOARD_led_color_blue: 'blue', FUNBOARD_led_color_all: 'all', FUNBOARD_do_on: 'on', FUNBOARD_do_off: 'off', FUNBOARD_row_tag: 'row', FUNBOARD_column_tag: 'column', FUNBOARD_scroll_no: 'no', FUNBOARD_scroll_left: 'leftward', FUNBOARD_scroll_right: 'rightward', FUNBOARD_scroll_up: 'upwards', FUNBOARD_scroll_down: 'downward', HAMSTER_sensor_signal_strength: 'signal strength', HAMSTER_turn_once_left: 'left', HAMSTER_turn_right: 'right', HAMSTER_left_wheel: 'left', HAMSTER_right_wheel: 'right', HAMSTER_both_wheels: 'both', HAMSTER_color_black: 'black', HAMSTER_color_white: 'white', HAMSTER_left_floor_sensor: 'left', HAMSTER_right_floor_sensor: 'right', HAMSTER_both_floor_sensors: 'both', HAMSTER_front: 'front', HAMSTER_rear: 'rear', HAMSTER_left_led: 'left', HAMSTER_right_led: 'right', HAMSTER_both_leds: 'both', HAMSTER_color_red: 'red', HAMSTER_color_yellow: 'yellow', HAMSTER_color_green: 'green', HAMSTER_color_cyan: 'sky blue', HAMSTER_color_blue: 'blue', HAMSTER_color_magenta: 'purple', HAMSTER_port_a: 'A', HAMSTER_port_b: 'B', HAMSTER_port_ab: 'A and B', HAMSTER_analog_input: 'analog input', HAMSTER_digital_input: 'digital input', HAMSTER_servo_output: 'servo output', HW_MOTOR: 'Motor', HW_MELODY: 'Melody', HW_SENSOR: 'Sensor', HW_LED: 'Led', HW_ROBOT: 'Robot', HAMSTER_pwm_output: 'pwm output', HAMSTER_digital_output: 'digital output', jdkit_clockwise: '시계방향', jdkit_counterclockwise: '반시계방향', jdkit_motor_lefttop: '왼쪽위', jdkit_motor_leftbottom: '왼쪽아래', jdkit_motor_righttop: '오른쪽위', jdkit_motor_rightbottom: '오른쪽아래', jdkit_gyro_frontrear: '앞뒤', jdkit_gyro_leftright: '좌우', jdkit_led_color_green: '초록색', jdkit_led_color_orange: '오랜지색', jdkit_tune_do: '도', jdkit_tune_re: '레', jdkit_tune_mi: '미', jdkit_tune_fa: '파', jdkit_tune_sol: '솔', jdkit_tune_la: '라', jdkit_tune_si: '시', modi_enviroment_temperature: 'Temparature', modi_enviroment_humidity: 'Humidity', modi_enviroment_illuminance: 'Illuminance', modi_enviroment_red: 'Red', modi_enviroment_bule: 'Blue', modi_enviroment_green: 'Green', modi_gyroscope_xAcceleratior: 'X-axis acceleration', modi_gyroscope_yAcceleratior: 'Y-axis acceleration', modi_gyroscope_zAcceleratior: 'Z-axis acceleration', modi_motor_angle: 'Angle', modi_motor_speed: 'Speed', modi_motor_torque: 'Torque', modi_speaker_F_PA_5: 'FA 5', modi_speaker_F_SOL_5: 'SOL 5', modi_speaker_F_RA_5: 'LA 5', modi_speaker_F_SO_5: 'TI 5', modi_speaker_F_PA_S_5: 'FA #5', modi_speaker_F_SOL_S_5: 'SOL #5', modi_speaker_F_RA_S_5: 'LA #5', modi_speaker_F_DO_6: 'DO 6', modi_speaker_F_RE_6: 'RE 6', modi_speaker_F_MI_6: 'MI 6', modi_speaker_F_PA_6: 'FA 6', modi_speaker_F_SOL_6: 'SOL 6', modi_speaker_F_RA_6: 'LA 6', modi_speaker_F_SO_6: 'TI 6', modi_speaker_F_DO_S_6: 'DO #6', modi_speaker_F_RE_S_6: 'RE #6', modi_speaker_F_PA_S_6: 'FA #6', modi_speaker_F_SOL_S_6: 'SOL #6', modi_speaker_F_RA_S_6: 'LA #6', modi_speaker_F_DO_7: 'DO 7', modi_speaker_F_RE_7: 'RE 7', modi_speaker_F_MI_7: 'MI 7', modi_speaker_F_DO_S_7: 'DO #7', modi_speaker_F_RE_S_7: 'RE #7', roborobo_color_red: ' Red ', roborobo_color_green: ' Green ', roborobo_color_blue: ' Blue ', roborobo_color_yellow: ' Yellow ', roborobo_on: 'On', roborobo_off: 'Off', roborobo_motor1: 'motor1', roborobo_motor2: 'motor2', robotis_cm_spring_left: 'Left contact sensor', robotis_cm_spring_right: 'Right contact sensor', robotis_cm_switch: 'Status of the switch', robotis_cm_sound_detected: 'Final number of sound detection ', robotis_cm_sound_detecting: 'Number of live sound detection ', robotis_cm_ir_left: 'Left infrared sensor', robotis_cm_ir_right: 'Right infrared sensor', robotis_cm_calibration_left: 'Value of the left infrared sensor calibration ', robotis_cm_calibration_right: 'Value of the right infrared sensor calibration ', robotis_common_on: 'Turn on', robotis_common_off: 'Turn off', robotis_common_clockwhise: 'Clockwise', robotis_common_counter_clockwhise: 'Counterclockwise', robotis_cm_user_button: 'Status of user button', robotis_aux_servo_position: 'Position of servo motor', robotis_aux_ir: 'Infrared sensor', robotis_aux_touch: 'Contact sensor', robotis_aux_brightness: 'CDS', robotis_aux_hydro_themo_humidity: 'Temperature-humidity sensor (humidity)', robotis_aux_hydro_themo_temper: 'Temperature-humidity sensor (temperature)', robotis_aux_temperature: 'Temperature sensor', robotis_aux_ultrasonic: 'Ultrasonic sensor', robotis_aux_magnetic: 'Magnetic sensor', robotis_aux_motion_detection: 'Motion detector', robotis_aux_color: 'Color sensor', robotis_aux_custom: 'User device', robotis_common_red_color: 'Red', robotis_common_green_color: 'Green', robotis_common_blue_color: 'Blue', robotis_common_port_1: 'Port 1', robotis_common_port_2: 'Port 2', robotis_common_port_3: 'Port 3', robotis_common_port_4: 'Port 4', robotis_common_port_5: 'Port 5', robotis_common_port_6: 'Port 6', robotis_common_wheel_mode: 'Wheel mode', robotis_common_joint_mode: 'Joint mode', robotis_cm_led_both: 'Both LED', robotis_cm_led_right: 'Right LED', robotis_cm_led_left: 'Left LED', robotori_D2_Input: 'Digital Pin 2 Input Value', robotori_D3_Input: 'Digital Pin 3 Input Value', robotori_A0_Input: 'Analog Pin 0 Input Value', robotori_A1_Input: 'Analog Pin 1 Input Value', robotori_A2_Input: 'Analog Pin 2 Input Value', robotori_A3_Input: 'Analog Pin 3 Input Value', robotori_A4_Input: 'Analog Pin 4 Input Value', robotori_A5_Input: 'Analog Pin 5 Input Value', robotori_D10_Output: 'Pin 10', robotori_D11_Output: 'Pin 11', robotori_D12_Output: 'Pin 12', robotori_D13_Output: 'Pin 13', robotori_On: 'On', robotori_Off: 'Off', robotori_analog5: 'Pin 5 Output Value', robotori_analog6: 'Pin 6 Output Value', robotori_analog9: 'Pin 9 Output Value', robotori_DC_rightmotor: 'Right', robotori_DC_leftmotor: 'Left', robotori_DC_STOP: 'Stop', robotori_DC_CW: 'clockwise', robotori_DC_CCW: 'anticlockwise', rokoboard_sensor_name_1: 'Light', rokoboard_sensor_name_0: 'Sound', rokoboard_sensor_name_2: 'Slider', rokoboard_sensor_name_3: 'resistance-A', rokoboard_sensor_name_4: 'resistance-B', rokoboard_sensor_name_5: 'resistance-C', rokoboard_sensor_name_6: 'resistance-D', rokoboard_string_1: 'Button Pressed', VARIABLE_change_variable: 'Adding variable', VARIABLE_get_variable: 'Value of variable', VARIABLE_set_variable: 'Set variable', VARIABLE_show_variable: 'Show variable', VARIABLE_hide_variable: 'Hide variable', VARIABLE_add_value_to_list_1: 'add', VARIABLE_add_value_to_list_2: 'to the list', VARIABLE_remove_value_from_list_1: 'remove', VARIABLE_remove_value_from_list_2: 'th element from', VARIABLE_insert_value_to_list_1: 'insert', VARIABLE_insert_value_to_list_2: 'to', VARIABLE_insert_value_to_list_4: 'th position', VARIABLE_change_value_list_index_1: 'change', VARIABLE_change_value_list_index_3: 'th element to', VARIABLE_show_list_1: 'Show list', VARIABLE_hide_list_1: 'Hide list', START_when_message_cast: 'When message received', START_when_message_cast_1: 'When', START_when_message_cast_2: 'message received', START_message_cast: 'Send message', START_message_cast_1: 'Send', START_message_cast_2: 'message', START_message_cast_wait: 'message and wait', START_message_send_wait_1: 'Send', START_message_send_wait_2: ' message and wait', Duplication_option: 'Duplicate', cut_blocks: 'Cut', AI_analyze_option: 'AI Analyze', CONTEXT_COPY_option: 'Copy', Delete_Blocks: 'Remove', add_my_storage: 'add to my storage', export_object: 'Export Object', this_project: 'this project', this_object: 'this object', right_hand: 'Right hand', left_hand: 'Left hand', thumb: 'thumb', index_finger: 'index finger', middle_finger: 'middle finger', ring_finger: 'ring finger', little_finger: 'little finger', wrist: 'wrist', tip: 'TIP', dip: 'DIP', pip: 'PIP', none: 'NONE', media_pipe_title_text: 'Video Detection', pose_landmarker_title_text: 'Human Detection', face_landmarker_title_text: 'Face Detection', object_detector_title_text: 'Object Detection', hand_detection_title_text: 'Hand Detection', unknown: 'Unknown', is_type_en: 'alphabet', is_type_ko: 'hangeul', location_entire: 'all', location_seoul: 'Seoul', location_seoul_jongno_gu: 'Jongno-gu', location_seoul_jung_gu: 'Jung-gu', location_seoul_yongsan_gu: 'Yongsan-gu', location_seoul_seongdong_gu: 'Seongdong-gu', location_seoul_gwangjin_gu: 'Gwangjin-gu', location_seoul_dongdaemun_gu: 'Dongdaemun-gu', location_seoul_jungnang_gu: 'Jungrang-gu', location_seoul_seongbuk_gu: 'Seongbuk-gu', location_seoul_gangbuk_gu: 'Gangbuk-gu', location_seoul_dobong_gu: 'Dobong-gu', location_seoul_nowon_gu: 'Nowon-gu', location_seoul_eunpyeong_gu: 'Eunpyeong-gu', location_seoul_seodaemun_gu: 'Seodaemun-gu', location_seoul_mapo_gu: 'Mapo-gu', location_seoul_yangcheon_gu: 'Yangcheon-gu', location_seoul_gangseo_gu: 'Gangseo-gu', location_seoul_guro_gu: 'Guro-gu', location_seoul_geumcheon_gu: 'Geumcheon-gu', location_seoul_yeongdeungpo_gu: 'Yeongdeungpo-gu', location_seoul_dongjak_gu: 'Dongjak-gu', location_seoul_gwanak_gu: 'Gwanak-gu', location_seoul_seocho_gu: 'Seocho-gu', location_seoul_gangnam_gu: 'Gangnam-gu', location_seoul_songpa_gu: 'Songpa-gu', location_seoul_gangdong_gu: 'Gangdong-gu', location_gangwon: 'Gangwon-do', location_gangwon_chuncheon: 'Chuncheon-si', location_gangwon_wonju: 'Wonju-si', location_gangwon_gangneung_si: 'Gangneung-si', location_gangwon_donghae: 'Donghae-si', location_gangwon_taebaek_si: 'Taebaek-si', location_gangwon_sokcho: 'Sokcho-si', location_gangwon_samcheok_si: 'Samcheok-si', location_gangwon_hongcheon: 'Hongcheon-gun', location_gangwon_hoengseong_gun: 'Hoengseong-gun', location_gangwon_yeongwol_gun: 'Yeongwol-gun', location_gangwon_pyeongchang: 'Pyeongchang-gun', location_gangwon_jeongseon: 'Jeongseon-gun', location_gangwon_cheolwon: 'Cheorwon-gun', location_gangwon_hwacheon: 'Hwacheon-gun', location_gangwon_yanggu: 'Yanggu-gun', location_gangwon_inje: 'Inje-gun', location_gangwon_goseong: 'Goseong-gun', location_gangwon_yangyang: 'Yangyang-gun', location_gyeonggi: 'Gyeonggi-do', location_gyeonggi_suwon_si: 'Suwon-si', location_gyeonggi_seongnam: 'Seongnam-si', location_gyeonggi_uijeongbu: 'Uijeongbu-si', location_gyeonggi_anyang_si: 'Anyang-si', location_gyeonggi_bucheon_si: 'Bucheon-si', location_gyeonggi_gwangmyeong_si: 'Gwangmyeong-si', location_gyeonggi_pyeongtaek_si: 'Pyeongtaek-si', location_gyeonggi_dongducheon_si: 'Dongducheon-si', location_gyeonggi_ansan_si: 'Ansan-si', location_gyeonggi_goyang_si: 'Goyang-si', location_gyeonggi_gwacheon_si: 'Gwacheon-si', location_gyeonggi_guri: 'Guri-si', location_gyeonggi_namyangju_si: 'Namyangju-si', location_gyeonggi_osan: 'Osan-si', location_jeollanam_goheung: 'Goheung-gun', location_gyeonggi_siheung: 'Siheung-si', location_jeollanam_boseong: 'Boseong-gun', location_jeollanam_hwasun: 'Hwasun-gun', location_gyeonggi_gunpo_si: 'Gunpo-si', location_jeollanam_jangheung: 'Jangheung-gun', location_gyeonggi_uiwang_si: 'Uiwang-si', location_jeollanam_gangjin: 'Gangjin-gun', location_gyeonggi_hanam: 'Hanam-si', location_jeollanam_haenam: 'Haenam-gun', location_gyeonggi_yongin_si: 'Yongin-si', location_jeollanam_yeongam: 'Yeongam-gun', location_gyeonggi_paju: 'Paju-si', location_jeollanam_jindo: 'Muan-gun', location_gyeonggi_icheon: 'Icheon-si', location_jeollanam_muan: 'Hampyeong-gun', location_jeollanam_hampyeong: 'Yeonggwang-gun', location_gyeonggi_anseong_si: 'Anseong-si', location_jeollanam_yeonggwang: 'Jangseong-gun', location_gyeonggi_gimpo: 'Gimpo-si', location_jeollanam_jangseong: 'Wando-gun', location_gyeonggi_hwaseong_si: 'Hwaseong-si', location_jeollanam_wando: 'Jindo-gun', location_gyeonggi_gwangju: 'Guangju-si', location_jeollanam_sinan: 'Shinan-gun', location_jeollabuk: 'Jeonbuk-do', location_gyeonggi_yangju_si: 'Yangju-si', location_jeollabuk_jeonju: 'Jeonju-si', location_gyeonggi_pocheon: 'Pocheon-si', location_jeollabuk_gunsan_si: 'Gunsan-si', location_gyeonggi_yeoju: 'Yeoju-si', location_jeollabuk_iksan: 'Iksan-si', location_gyeonggi_yeoncheon_gun: 'Yeoncheon-gun', location_gyeonggi_gapyeong_gun: 'Gapyeong-gun', location_jeollabuk_jeongeup: 'Jeongeup-si', location_gyeonggi_yangpyeong: 'Yangpyeong-gun', location_jeollabuk_namwon: 'Namwon-si', location_gyeongsangnam: 'Gyeongsangnam-do', location_jeollabuk_gimje_si: 'Gimje-si', location_gyeongsangnam_changwon_si: 'Changwon-si', location_jeollabuk_wanju: 'Wanju-gun', location_gyeongsangnam_jinju: 'Jinju-si', location_jeollabuk_jinan: 'Jinan-gun', location_gyeongsangnam_tongyeong_si: 'Tongyeong-si', location_jeollabuk_muju: 'Muju-gun', location_gyeongsangnam_sacheon_si: 'Sacheon-si', location_jeollabuk_jangsu: 'Jangsu-gun', location_gyeongsangnam_gimhae_si: 'Gimhae-si', location_jeollabuk_imsil: 'Imsil-gun', location_gyeongsangnam_miryang_si: 'Miryang-si', location_jeollabuk_sunchang: 'Sunchang-gun', location_gyeongsangnam_geoje_si: 'Geoje-si', location_jeollabuk_gochang: 'Gochang-gun', location_gyeongsangnam_yangsan_si: 'Yangsan-si', location_jeollabuk_buan: 'Buan-gun', location_gyeongsangnam_uiryeong: 'Uiryeong-gun', location_jeju: 'Jeju-do', location_gyeongsangnam_haman: 'Haman-gun', location_jeju_jeju_si: 'Jeju-si', location_gyeongsangnam_changnyeong: 'Changnyeong-gun', location_jeju_seogwipo: 'Seogwipo-si', location_gyeongsangnam_goseong: 'Goseong-gun', location_gyeongsangnam_namhae: 'Namhae-gun', location_chungcheongnam: 'Chungcheongnam-do', location_gyeongsangnam_hadong: 'Hadong-gun', location_chungcheongnam_cheonan: 'Cheonan-si', location_gyeongsangnam_sancheong: 'Sancheong-gun', location_chungcheongnam_gongju: 'Gongju-si', location_gyeongsangnam_hamyang: 'Hamyang-gun', location_gyeongsangnam_geochang: 'Geochang-gun', location_chungcheongnam_boryeong: 'Boryeong-si', location_gyeongsangnam_hapcheon: 'Hapcheon-gun', location_chungcheongnam_asan: 'Asan-si', location_gyeongsangbuk: 'Gyeongsangbuk-do', location_chungcheongnam_seosan: 'Seosan-si', location_gyeongsangbuk_pohang_si: 'Pohang-si', location_gyeongsangbuk_gyeongju_si: 'Gyeongju-si', location_chungcheongnam_nonsan: 'Nonsan-si', location_gyeongsangbuk_gimcheon_si: 'Gimcheon-si', location_chungcheongnam_gyeryong: 'Gyeryong-si', location_gyeongsangbuk_andong_si: 'Andong-si', location_chungcheongnam_dangjin: 'Dangjin-si', location_gyeongsangbuk_gumi_si: 'Gumi-si', location_gyeongsangbuk_yeongju_si: 'Yeongju-si', location_chungcheongnam_geumsan: 'Geumsan-gun', location_chungcheongnam_buyeo: 'Buyeo-gun', location_gyeongsangbuk_yeongcheon_si: 'Yeongcheon-si', location_chungcheongnam_seocheon: 'Seocheon-gun', location_gyeongsangbuk_sangju_si: 'Sangju-si', location_chungcheongnam_cheongyang: 'Cheongyang-gun', location_gyeongsangbuk_mungyeong_si: 'Mungyeong-si', location_gyeongsangbuk_gyeongsan_si: 'Gyeongsan-si', location_chungcheongnam_hongseong: 'Hongseong-gun', location_gyeongsangbuk_gunwi: 'Gunwi-gun', location_chungcheongnam_yesan: 'Yesan-gun', location_gyeongsangbuk_uiseong: 'Uiseong-gun', location_chungcheongnam_taean: 'Taean-gun', location_gyeongsangbuk_cheongsong: 'Cheongsong-gun', location_chungcheongbuk: 'Chungcheongbuk-do', location_gyeongsangbuk_goryong: 'Yeongyang-gun', location_chungcheongbuk_cheongju: 'Cheongju-si', location_gyeongsangbuk_yeongdeok: 'Yeongdeok-gun', location_gyeongsangbuk_cheongdo: 'Cheongdo-gun', location_chungcheongbuk_chungju: 'Chungju-si', location_gyeongsangbuk_golyeong: 'Goryeong-gun', location_chungcheongbuk_jecheon: 'Jecheon-si', location_gyeongsangbuk_seongju: 'Seongju-gun', location_chungcheongbuk_boeun: 'Boeun-gun', location_gyeongsangbuk_chilgok: 'Chilgok-gun', location_chungcheongbuk_okcheon: 'Okcheon-gun', location_gyeongsangbuk_yecheon: 'Yecheon-gun', location_chungcheongbuk_yeongdong: 'Yeongdong-gun', location_gyeongsangbuk_bonghwa: 'Bonghwa-gun', location_chungcheongbuk_jeungpyeong: 'Jeungpyeong-gun', location_gyeongsangbuk_uljin: 'Uljin-gun', location_chungcheongbuk_jincheon: 'Jincheon-gun', location_gyeongsangbuk_ulleung: 'Ulleung-gun', location_chungcheongbuk_goesan: 'Goesan-gun', location_gwangju: 'Gwangju', location_chungcheongbuk_eumseong: 'Eumseong-gun', location_gwangju_dong_gu: 'Dong-gu', location_chungcheongbuk_danyang: 'Danyang-gun', location_gwangju_seo_gu: 'Seo-gu', location_gwangju_nam_gu: 'Nam-gu', location_gwangju_buk_gu: 'Buk-gu', location_gwangju_gwangsan_gu: 'Gwangsan-gu', location_daegu: 'Daegu', location_daegu_jung_gu: 'Jung-gu', location_daegu_dong_gu: 'Dong-gu', location_daegu_seo_gu: 'Seo-gu', location_daegu_nam_gu: 'Nam-gu', location_daegu_buk_gu: 'Buk-gu', location_daegu_suseong_gu: 'Suseong-gu', location_daegu_dalseo_gu: 'Dalseo-gu', location_daegu_dalseong: 'Dalseong-gun', location_daegu_gunwi: 'Gunwi-gun', location_daejeon: 'Daejeon', location_daejeon_dong_gu: 'Dong-gu', location_daejeon_jung_gu: 'Jung-gu', location_daejeon_seo_gu: 'Seo-gu', location_daejeon_yuseong_gu: 'Yuseong-gu', location_daejeon_daedeok_gu: 'Daedeok-gu', location_busan: 'Busan', location_busan_jung_gu: 'Jung-gu', location_busan_seo_gu: 'Seo-gu', location_busan_dong_gu: 'Dong-gu', location_busan_yeongdo_gu: 'Yeongdo-gu', location_busan_busanjin_gu: 'Busanjin-gu', location_busan_dongnae_gu: 'Dongnae-gu', location_busan_nam_gu: 'Nam-gu', location_busan_buk_gu: 'Buk-gu', location_busan_haeundae_gu: 'Haeundae-gu', location_busan_saha_gu: 'Saha-gu', location_busan_geumjeong_gu: 'Geumjeong-gu', location_busan_gangseo_gu: 'Gangseo-gu', location_busan_yeonje: 'Yeonje-gu', location_busan_suyeong_gu: 'Suyoung-gu', location_busan_sasang_gu: 'Sasang-gu', location_busan_gijang: 'Gijang-gun', location_sejong: 'Sejong-si', location_ulsan: 'Ulsan', location_ulsan_jung_gu: 'Jung-gu', location_ulsan_nam_gu: 'Nam-gu', location_ulsan_dong_gu: 'Dong-gu', location_ulsan_buk_gu: 'Buk-gu', location_ulsan_ulju: 'Ulju-gun', location_incheon: 'Incheon', location_incheon_jung_gu: 'Jung-gu', location_incheon_dong_gu: 'Dong-gu', location_incheon_nam_gu: 'Michuhol-gu', location_incheon_yeonsu_gu: 'Yeonsu-gu', location_incheon_namdong_gu: 'Namdong-gu', location_incheon_bupyeong_gu: 'Bupyeong-gu', location_incheon_gyeyang_gu: 'Gyeyang-gu', location_incheon_seo_gu: 'Seo-gu', location_incheon_ganghwa: 'Ganghwa-gun', location_incheon_ongjin_gun: 'Ongjin-gun', location_jeollanam: 'Jeollanam-do', location_jeollanam_mokpo: 'Mokpo-si', location_jeollanam_yosu: 'Yeosu-si', location_jeollanam_suncheon_si: 'Suncheon-si', location_jeollanam_naju: 'Naju-si', location_jeollanam_gwangyang_si: 'Gwangyang-si', location_jeollanam_damyang: 'Damyang-gun', location_jeollanam_gokseong: 'Gokseong-gun', location_jeollanam_gurye: 'Gurye-gun', width: 'width', height: 'height', desktop: 'desktop', tablet: 'tablet', smartphone: 'smartphone', }; Lang.video_body_coord_params = { left_eye: 'left eye', right_eye: 'right eye', nose: 'nose', left_mouth: 'left corner of lips', right_mouth: 'right corner of lips', upper_lip: 'upper lip', lower_lip: 'lower lip', face: 'face', neck: 'neck', left_ear: 'left ear', right_ear: 'right ear', left_shoulder: 'left shoulder', left_elbow: 'left elbow', left_wrist: 'left wrist', left_hip: 'left hip', left_knee: 'left knee', left_ankle: 'left ankle', right_shoulder: 'right shoulder', right_elbow: 'right elbow', right_wrist: 'right wrist', right_hip: 'right hip', right_knee: 'right knee', right_ankle: 'right ankle', }; Lang.video_gender = { male: 'Male', female: 'Female', }; Lang.video_emotion_params = { angry: 'Anger', disgusted: 'Disgust', fearful: 'Fearful', happy: 'Happiness', neutral: 'Neutral', sad: 'Sadness', surprised: 'Surprised', disgust: 'Disgust', fear: 'Fearful', surprise: 'Surprised', }; Lang.video_object_params = { person: 'Person', bicycle: 'Bicycle', car: 'Car', motorcycle: 'Motorcycle', airplane: 'Airplane', bus: 'Bus', train: 'Train', truck: 'Truck', boat: 'Boat', 'traffic light': 'Traffic light', 'fire hydrant': 'Fire hydrant', 'stop sign': 'Stop sign', 'parking meter': 'Parking meter', bench: 'Bench', bird: 'Bird', cat: 'Cat', dog: 'Dog', horse: 'Horse', sheep: 'Sheep', cow: 'Cow', elephant: 'Elephant', bear: 'Bear', zebra: 'Zebra', giraffe: 'Giraffe', backpack: 'Backpack', umbrella: 'Umbrella', handbag: 'Handbag', tie: 'Tie', suitcase: 'Suitcase', frisbee: 'Frisbee', skis: 'Skis', snowboard: 'Snowboard', 'sports ball': 'Sports ball', kite: 'Kite', 'baseball bat': 'Baseball bat', 'baseball glove': 'Baseball glove', skateboard: 'Skateboard', surfboard: 'Surfboard', 'tennis racket': 'Tennis racket', bottle: 'Bottle', 'wine glass': 'Wine glass', cup: 'Cup', fork: 'Fork', knife: 'Knife', spoon: 'Spoon', bowl: 'Bowl', banana: 'Banana', apple: 'Apple', sandwich: 'Sandwich', orange: 'Orange', broccoli: 'Broccoli', carrot: 'Carrot', 'hot dog': 'Hot dog', pizza: 'Pizza', donut: 'Donut', cake: 'Cake', chair: 'Chair', couch: 'Couch', 'potted plant': 'Potted plant', bed: 'Bed', 'dining table': 'Dining table', toilet: 'Toilet', tv: 'Tv', laptop: 'Laptop', mouse: 'Mouse', remote: 'Remote', keyboard: 'Keyboard', 'cell phone': 'Cell phone', microwave: 'Microwave', oven: 'Oven', toaster: 'Toaster', sink: 'Sink', refrigerator: 'Refrigerator', book: 'Book', clock: 'Clock', vase: 'Vase', scissors: 'Scissors', 'teddy bear': 'Teddy bear', 'hair drier': 'Hair dryer', toothbrush: 'Toothbrush', }; Lang.Buttons = { share_policy: 'Share Guide', write_policy: 'Write Guide', lesson_list: 'List', complete_study: 'Complete', show_me: 'Show Me', do_this_for_me: 'Do This For Me', previous: 'Previous ', get_started: 'Get Started', next_lesson: 'Next lesson', course_submit: 'Submit', course_done: 'OK', mission: 'Introduction ', basic_guide: 'User Guide', apply: 'Apply', add: 'Add', cancel: 'Cancel', save: 'Save', start: 'Start', confirm: 'OK', delete: 'Delete', create: 'Create Class', done: 'Done', accept: 'Accept', select: 'Select', refuse: 'Refuse', yes: 'Yes', button_no: 'No', quiz_retry: 'Try Again', discuss_upload: 'Upload', maze_popup_guide: 'User Guide', maze_popup_mapHint: 'Hint', maze_hint_btn_guide: 'User Guide', maze_hint_btn_block: 'Block Help', maze_hint_btn_map: 'Map Hint', maze_hint_btn_goal: 'goal', list_save: 'Upload', duplication: 'Copy', export_to_excel: 'Download', convert_table: 'Export to table', single_line: 'Single line', multi_line: 'Multi line', lecture_finish_popup_reset_lecture: 'Do it again', lecture_finish_popup_show_output: 'See the exercised', lecture_view_hints: 'View hints', default_hint_title: 'How do you make it?', show_only_vector: 'Only Vector', sound_menu_trim: 'Trim', sound_menu_adjust: 'Adjust', sound_button_reset: 'Reset', sound_button_save: 'Save', back: 'Go back', add2: 'Add', load: 'Load', move: 'Move', create_new_table: 'Create', add_variable: 'Add variable', add_list: 'Add list', add_message: 'Add Message', }; Lang.Menus = { nothing_to_import: 'There is no content to upload.', nothing_to_export: 'There is no content to download.', content_copied: 'The data is copied.', list_import_title: 'Import', list_import_placeholder: 'Example)\nData1\nData2\nData3', verifying_email: 'Verifying email', list_import_notice_1: 'You can enter items and default values in a list at once.', list_import_notice_2: 'The items and default values entered here are saved as a list.', list_export_title: 'Export', list_export_notice1: 'You can copy the items in the list directly or', list_export_notice2: 'export them to a file or table.', list_export_notice: 'You can copy or download the data in the list.', robotis_opencm70: 'Robotis Open CM70', cannnot_mark_favorite: 'Private project cannot be marked as a favorite.', enterPassword: 'Enter password.', enterPassword_update: 'Please enter your password to save your changes.', enterNewPassword: 'Enter new password.', reEnterNewPassword: 'Re-enter new password.', resign: 'Account deletion', check_sended_email: 'Please check your inbox to verify your email.', signUpEmail_1: 'Verification mail has been sent. ', signUpEmail_2: 'Please verify your email.', select_email_unauthenticated_user: 'The email address is registered to the IDs below.\nPlease choose the right one.', select_user: 'Please choose the ID.', enter_password_withdraw: 'Enter password to delete your account', instruction_agree: 'Please check instruction and agree.', check_instructions: 'I check instructions and agree.', deleteAccount_2: 'After 30 days, every data that you created in Entry such as project/lecture/class/post/comment/like/favourite will be deleted and cannot be restored.', deleteAccount_1: 'If you sign in again within 30 days, you can withdraw account deletion.', protect_account: 'Protect your account with a safe password.', please_verify: "Please verify your email to click 'Verifying email'", unverified_email: 'Unverified email', deleteAccount: 'Delete account', corporatePersonal: 'Agree to the transfer of personal information.', corporateTransferGuide: 'Personal Information transfer guide', corporateReciever: 'Information reciever : Connect Foundation', corporateAddress: 'Connect Foundation Address&Contact', corporateAddress_1: 'Meritz Tower 7, Seoul Gangnam-gu Gangnam-daero 382, Seoul, Korea', corporateConsent: 'If you do not want to transfer your information, you may withdraw the consent.', corporateEmail: 'For withdraw the consent, send an email to', corporateAddition: 'In addition, the terms and conditions of the agreement will be changed, depending on the transfer.', corporateApplicationDate: 'Application date : From October 29, 2017', corporateTargetChanges: 'Application Targets and Changes : ', corporateTarget: 'Targets', corporateChanges: 'Changes', corporateTerms: 'Terms', corporateOperator: 'The name of the ‘Entry’ operator', corporateClassroomTerms: 'Classroom Service Terms of Use', doAgreeWithClassroomTerms: 'Agree to the Classroom Service Terms of Use.', doChangePassword: 'Please change the password into the one that only you can know.', corporatePrivacyPolicy: 'Privacy Policy', corporateConsignment: 'The name of the ‘Entry’ operator. And consignment of personal information', corporateEntrusted: 'Entrusted Company : NHN Technology Services Corporation.', corporateConsignmentDetails: 'Details of Consignment : Service operation.', corporatePeriod: 'Consignment Period : Until the member cancels membership or the consignment contract ends.', corporateChangeDate: 'Date of change : October 29, 2017', corporateWarning: 'Please Agree to the transfer of personal information.', corporateConfirm: 'Confirm', corporateTitle: "Hello. This is EntryLabs.
We are very grateful to you who are using 'Entry'.
Recently we have agreed to transfer the ownership of Entry web site, which has been operated for public interest purposes, to the 'Connect Foundation'.
Connect Foundation is a non-profit foundation founded by Naver. 'Entry' will be continuously operated under public interest purpose by 'Connect Foundation'. Therefore, All of “Entry” users will be guaranteed to use the entry exactly as same as before.
Since the website provider has changed from the 'EntryLabs' to the 'Connect Foundation', there is a transfer of personal information as below. However, this doesn’t mean that your information will be physically moved.
", textcoding_numberError_f: "You can't convert into the text mode if there is function names start with a number.", textcoding_bookedError_1f: "You can't convert into the text mode if there is function named ", textcoding_bookedError_2f: '.', textcoding_specialCharError_f: "You can't convert into the text mode if there is function names include special character except for underscore.", textcoding_numberError_v: "You can't convert into the text mode if there is variable names start with a number.", textcoding_bookedError_1v: "You can't convert into the text mode if there is variable named ", textcoding_bookedError_2v: '.', textcoding_specialCharError_v: "You can't convert into the text mode if there is variable names include special character except for underscore.", textcoding_numberError_l: "You can't convert into the text mode if there is list names start with a number.", textcoding_bookedError_1l: "You can't convert into the text mode if there is list named ", textcoding_bookedError_2l: '.', textcoding_specialCharError_l: "You can't convert into the text mode if there is list names include special character except for underscore.", no_discuss_permission: "You don't have permission to view this post.", delete_comment: 'Are you sure you want to delete commnet', delete_article: 'Are you sure you want to delete article', discuss_cannot_edit: 'You cannot edit this post', discuss_extention: 'You cannot upload files with that extension', delete_discuss_picture: 'Do you want to delete the photo?', delete_discuss_file: 'Do you want to delete the file?', discuss_save_question: 'Do you want save your post?', discuss_cancle_question: 'Do you want to leave without saving?', discuss_saved: 'is saved', discuss_no_write_permission: 'Cannot be saved with the current login account.', discuss_no_project_permission: 'Cannot be saved with the current login account.', discuss_write_abuse_detected: 'Several articles have been written within a \nshort period of time. \nPlease try again in 1 minutes.', contents_abuse_detected: 'Please try again in 5 minutes.', contents_abuse_detected_10: 'Please try again in 10 minutes.', discuss_new_write_abuse_warn: 'Posting multiple comments within a \nshort period of time may limit the post \nof comments.\nBe careful of your use.', discuss_write_abuse_warn: 'Posting multiple comments within a \nshort period of time may limit the post \nof comments.\nBe careful of your use.', find_not_your_email: 'Please enter a valid email.', search_lang: 'search', search_title: 'title', faq_desc: 'Check the answers for the questions you had while using the Entry.', faq_all: 'Total', faq_site: 'Site guide', faq_project: 'Project', faq_hardware: 'Hardware', faq_offline: 'Offline editor', faq_copyright: 'Copyright', faq_title: 'FAQ', faq: 'FAQ', malicious_warning: "You cannot attach an unwholesome image. If the image doesn't unwholesome, please report it.", fword_alert_msg: 'You can not post abusive or malicious sentences.', fword_alert_1: 'You can not post abusive comments or malicious comments', fword_alert_2: 'Your post will be replaced alternative sentence because it contains unhealthy words.', fword_replace_1: 'Entry is an education platform created to help anyone learn to code.', fword_replace_2: 'Entry is an education platform created to help anyone learn to code.', fword_replace_3: 'Entry is an education platform created to help anyone learn to code.', fword_replace_4: 'Entry is an education platform created to help anyone learn to code.', fword_replace_5: 'Entry is an education platform created to help anyone learn to code.', fword_replace_6: 'Entry is an education platform created to help anyone learn to code.', fword_replace_7: 'Entry is an education platform created to help anyone learn to code.', solve_quiz: 'Quiz', submit_homework_first_title: 'Complete! Submit an assignment', submit_homework_first_content: 'Great work is done! Submit your assignment.
You may resubmit your assignment before the deadline.', submit_homework_again_title: 'Resubmit', submit_homework_again_content: 'This project has been submitted already.
Would you like to resubmit?', submit_homework_expired_title: 'Submission Closed', submit_homework_expired_content: 'Assignment deadline is over.', done_study_title: 'Complete', done_study_content: 'Fabulous project is complete', featured_courses: 'Featured Courses', follow_along: 'Follow Along', follow_along_desc: 'Create various projects as you follow along step by step.', do_quiz: 'Quiz', do_quiz_desc: 'Check your knowledge through quizzes.', challenge: 'Challenge', play: 'Play', challenge_desc: 'Learn programming concepts by solving problems.', creste_freely: 'Create freely', creste_freely_desc: "Create your projects using what you've learned.", entry_rc_desc: 'Learn programming concepts in steps with Entry lectures! Start now!', hw_deadline: 'Deadline', rc_course_desc: 'Lecture collection created for learning programming concepts level by level', rc_course: 'Entry Recommended Courses', entry_rec_course: 'Entry Recommended Courses', entry_rec_course_desc: 'Anyone can follow along and easily create projects with Entry Lectures.', guidance: 'Guidance', wait: 'Wait', hint: 'Hint', concept_guide: 'Concept Guide', group_quiz: 'Quiz', fail_check_hint: 'Oh no! Try again!
Check [Hint] if you are stuck!', sort_student: 'Student', sort_lesson: 'Lesson', sort_course: 'Course', student_progress: 'Student Progress', my_progress: 'Progress', lec_in_progress: 'in progress', free_modal_asgn_over: 'Assignment deadline is over.', free_submission_closed: 'Submission Closed', free_modal_asgn_submit_first: 'Great work is done! Submit your assignment.
You may resubmit your assignment before the deadline.', asgn_submit: 'Complete! Submit an assignment.', free_modal_content_resubmit: 'This project has been submitted already.
Would you like to resubmit?', asgn_resubmit: 'Resubmit', free_modal_content_complete: 'Fabulous Project is complete.', guide_modal_content_complete: "Let's run the program", success: 'Success', fail: 'Fail', mission_modal_content_fail: '
Check [Hint] if you are stuck!', mission_modal_content_success: "Let's run the program", in_progress: 'in progress', completed: 'Completed', submitted: 'submitted', submission_closed: 'Submission Closed', progress: 'Progress', study_completed: 'completed', view_course_desc: 'View Description', main_entry_starter: 'From basics! Entry Starter', main_entry_booster: 'Concepts! Entry Booster', main_entry_master: 'Ideas unfold! Entry Master', no_students_in_classroom: 'No students yet.
Please add or invite students.', lectures: 'lessons', Lectures: 'Lessons', studentHomeworkList: 'assignment', curriculums: 'courseware', Curriculums: 'Courseware', quiz: 'quiz', no_added_group_contents_teacher: 'There is no %1.
Please create a %1.', no_added_group_contents_student: 'There is no %1.', side_project: 'Goal project', custom_make_course_1: 'Create courseware from', custom_make_course_2: "'Create lessons > Create Courseware'", custom_make_lecture_1: "Create lessons from 'open lessons'", custom_make_lecture_2: '', alert_enter_info: 'Please enter your information', alert_enter_new_pwd: 'Enter new password', alert_match_pwd: "Password doesn't match the confirmation", alert_check_pwd: 'Please check your password', alert_update_complete: 'Edit complete', no_group_contents_each_prefix: 'There is no ', no_group_contents_each_suffix: ' in our classroom.', no_group_contents_all: 'There is no new content.
Share projects in My Classroom gallery.', hw_closed: 'submission closed', tag_Lecture: 'Lessons', tag_Curriculum: 'Courseware', tag_Discuss: 'Discuss', count_ko: '.', no_asgn_within_week: 'There is no assignment due within a week', lecture_and_curriculum: 'Open Lessons', assignments_plural: 'Assignments', assignments_singular: 'Assignment', project_plural: 'Projects', group_news: 'News', stu_management: 'Student management', stu_management_camel: 'Student Management', view_all: 'View all', view_all_camel: 'View All', view_contents_camel: 'View All', view_contents: 'Contents', no_updated_news: 'There is no update', homework_soon_due: 'Assignment soon due', new_homework: 'New Assignment', no_new_homework: 'There is no new Assignment', student_plural: 'Students', discuss: 'notice', basic_project: 'Basic Project', no_permission: 'You have no permission.', no_comment_write_permission: 'Cannot write comments with the currently logged in account.', original_curriculum_deleted: 'The original courseware was deleted', original_curriculum: 'Original courseware', save_as_my_lecture: 'Save as My Lecture', delete_confirm: 'Confirm', lecture_open_as_copied: 'All lectures in Open Lesson are saved as copy and open to public view', curriculum_open_as_copied: 'All Courseware listed under Open Lesson are saved as copy and open to public view', lecture_save_as_copied_group: 'All lectures in My Class Lecture are saved as copy and open to public view', curriculum_save_as_copied_group: 'All Lecture Collection listed under My Class Lecture Collection are saved as copy and open to public view', homework_save_as_copied_group: 'All Assignments listed under Class Assignment page are saved as copy and open to public view', lecture_save_as_copied: 'Lecture inserted in the Lecture collection is saved as a copy.', done_project_save_as_copied: 'Completed project inserted in the Lecture is saved as a copy.', textbook_project_can_not_applied: '', original_lecture_deleted: 'The original lecture was deleted', original_lecture: 'Original lecture', lecture_save_as_mine_alert: "Saved.\nnSaved Lecture is listed under 'My Page > My Lecture'", lecture_save_as_mine: 'Save as My Lecture', duplicate_username: 'The ID you entered is already in use', share_your_project: '', not_available_student: "ID entered is class issued 'Class ID'. \nPlease enter 'Entry Member ID'.", login_instruction: 'Log-in instructions', login_needed: 'Service is available after log-in', login_as_teacher: 'Log in as Teacher to use the service', remove_my_storage: 'Are you sure to remove it from my storage? Deleted blocks/objects cannot be recovered.', submit_hw: 'submit', success_goal: 'Success', choseok_final_result: 'Great! I completed my own project!', choseok_fail_msg_timeout: '시간이 너무 많이 지나버렸어. 목표를 잘 보고 다시 한번 도전해봐!', choseok_fail_msg_die: '생명이 0이하인데 게임이 끝나지 않았어.\n아래의 블록을 사용해서 다시 도전해 보는 건 어때?', grade_1: 'Basic', grade_2: 'Intermediate', grade_3: 'Advanced', find_sally_title: 'Finding Sally', save_sally_title: 'Saving Sally', exit_sally_title: 'Escaping', find_sally: 'Combine the power of the LINE Rangers\nand defeat the powerful villain Mephisto\nand save Sally!', save_sally: "Sally is trapped at Mephisto's base.\nHelp the LINE Rangers get to Sally by avoiding\nobstacles!", exit_sally: 'Help Sally and LINE Rangers escape safely\nfrom the exploding Mephisto base!', go_next_mission: '다른 미션 도전하기', share_my_project: '내가 만든 작품 공유하기', share_certification: '인증서 공유하기', print_certification: '인증서를 뽐내봐', get_cparty_events: '내가 받은 인증서를 출력해 뽐내면 푸짐한 상품을 받을 수 있어요!', go_cparty_events: '이벤트 참여하러 가기', codingparty2016_blockHelper_1_title: '', codingparty2016_blockHelper_1_contents: '', codingparty2016_blockHelper_2_title: '', codingparty2016_blockHelper_2_contents: '', codingparty2016_blockHelper_3_title: '', codingparty2016_blockHelper_3_contents: '', codingparty2016_blockHelper_4_title: '', codingparty2016_blockHelper_4_contents: '', codingparty2016_blockHelper_5_title: '', codingparty2016_blockHelper_5_contents: '', codingparty2016_goalHint_1: '', codingparty2016_goalHint_2: '', codingparty2016_goalHint_3: '', codingparty2016_goalHint_4: '', codingparty2016_goalHint_5: '', codingparty2016_goalHint_6: '', codingparty2016_goalHint_7: '', codingparty2016_goalHint_8: '', codingparty2016_goalHint_9: '', codingparty2016_guide_1_1_contents: '', codingparty2016_guide_1_1_title: '', codingparty2016_guide_1_2_title: '', codingparty2016_guide_1_2_contents: '', codingparty2016_guide_1_3_title: '', codingparty2016_guide_1_3_contents: '', codingparty2016_guide_1_4_title: '', codingparty2016_guide_1_4_contents: '', codingparty2016_guide_1_5_title: '', codingparty2016_guide_1_5_contents: '', codingparty2016_guide_2_1_title: '', codingparty2016_guide_2_1_contents: '', codingparty2016_guide_3_1_title: '', codingparty2016_guide_3_1_contents: '', codingparty2016_guide_5_1_title: '', codingparty2016_guide_5_1_contents: '', codingparty2016_guide_5_2_title: '', codingparty2016_guide_5_2_contents: '', codingparty2016_guide_7_1_title: '', codingparty2016_guide_7_1_contents: '', codingparty2016_guide_9_1_title: '', codingparty2016_guide_9_1_contents: '', codingparty2016_guide_9_2_title: '', codingparty2016_guide_9_2_contents: '', find_interesting_lesson: "Browse through 'Class lessons’ section to find interesting lessons!", find_interesting_course: "Browse through 'Class courseware’ section to find interesting courseware!", select_share_settings: 'Select share settings', faq_banner_title: 'FAQ', check_out_faq: 'Check out Entry’s FAQ', faq_banner_content: 'Do you have any question about Entry?
We give you the answer in FAQ.
Find out now!', faq_banner_button: 'Go to FAQ', major_updates: 'Major updates', check_new_update: "Check out\nEntry's new updates", major_updates_notification: "Entry's major updates are announced by notification. ", find_out_now: 'Find out now!', offline_hw_program: 'Offline and Hardware Connection Program', read_more: 'read more', sample_project: 'Sample Project', not_supported_function: 'This tablet does not support this feature.', offline_download_confirm: 'Entry Offline Editor is available for PC. Would you like to download?', hardware_download_confirm: 'Entry Hardware Program is available for PC. Would you like to download?', copy_text: 'Copy text.', select_openArea_space: 'Select share settings', mission_guide: 'Mission guide', of: " 's ", no_results_found: 'No results found', upload_pdf: 'Upload PDF materials', select_basic_project: 'Select Project', try_it_out: 'TRY IT OUT', go_boardgame: 'ENTRY-Bot Board Game', go_cardgame: 'ENTRY Bot Card game', go_solve: 'Learn programming', go_ws: 'Entry Create', go_arts: 'Entry Share', group_delete_alert: 'Once you delete this class, all data including temporary student accounts will be deleted.\nAre you sure you want to delete?', view_arts_list: 'list', hw_submit_confirm_alert: 'Assignment submitted', hw_submit_alert: 'Would you like to submit your assignment?', hw_submit_alert2: "Would you like to submit your assignment? Submission will only submit what you've completed.", hw_submit_cannot: 'You cannot submit this assignment', see_other_missions: 'See other missions', project: 'Project', marked: 'favorite', group: 'Group', lecture: 'Lessons', Lecture: 'Lessons', curriculum: 'Courseware', Curriculum: 'Courseware', studying: 'studying', open_only_shared_lecture: '오픈 강의 페이지에 <공개> 한 강의만 불러올 수 있습니다. 불러오고자 하는 강의공개여부를 확인해 주세요.', already_exist_group: 'group already exists', cannot_invite_you: "Can't invite by yourself", apply_original_image: 'Save original image', draw_new_ques: "Are you sure you want to go to \n'Draw new object' page?", draw_new_ques_1: 'You can draw an object and save it.', draw_new_ques_2: 'Do you want to move to draw?', draw_new_go: 'Move', draw_new_stay: 'No, Stay', file_upload_warn_title_image: 'The following pictures are subject to the Terms of Use and related laws.', file_upload_warn_desc_image: 'Violent and brutal picture, Sacred body exposure picture, Offensive or disgusting picture, Picture of copyright prohibited from unauthorized use', file_upload_warn_title_sound: 'The following sounds are subject to the Terms of Use and related laws.', file_upload_warn_desc_sound: 'Violent and cruel sound, Suggestive sound, Offensive or disgusting sound, Sound of copyright prohibited from unauthorized use', file_upload_warn_title_table: 'The following datas are subject to the Terms of Use and related laws.', file_upload_warn_desc_table: 'Violent and brutal data, Sacred body exposure data, Offensive or disgusting data, Data of copyright prohibited from unauthorized use', file_upload_warn_link: 'Learn about copyright', file_upload_desc_1: "Make sure you don't upload", file_upload_desc_2: 'Violent and brutal picture', file_upload_desc_3: 'Sacred body exposure picture', file_upload_desc_4: 'Offensive or disgusting picture', file_upload_desc_5: '* Uploading of above contents may be restricted under user policy and related laws.', picture_upload_warn_old: 'You can only upload jpg, png, bmp files that are less than 10MB.', sprite_upload_warn_old: 'You can only upload images in jpg, png, bmp format or objects in eo format that are less than 10MB.', picture_upload_warn_1: 'You can only upload jpg, png, bmp, svg files that are less than 5MB.\nThe jpg, png, and bmp images are edited in bitmap mode and the svg image is in vector mode.', table_upload_warn_1: 'You can only upload csv, xls(x) files that are less than 10MB.', sprite_upload_warn: 'You can only upload images in jpg, png, bmp, svg format or objects in eo format that are less than 5MB.', sound_upload_warn_1: 'You can only upload mp3 files that are less than 10MB.', sound_edit_warn: "Please wait!\nWe're working on the Sound Editing function.", file_upload_loading: 'Loading', lesson_by_teacher: 'Teacher created lesson', delete_group_art: 'from the list?', elementary_short: 'elementary', middle_short: 'middle school', grade_34: '3-4th', grade_56: '5-6th', grade_78: '7+', share_lesson: 'sharing lesson', share_course: 'sharing courseware', from_list_ko: '', comming_soon: 'Coming soon', no_class_alert: "Class selected does not exist. To create a class, go to 'My Class' to create a class.", students_cnt: '', defult_class_alert_1: 'Do you want to set ', defult_class_alert_2: '\n as default class?', default_class: 'Default classroom', enter_hw_name: 'Enter Assignment name.', hw_limit_20: 'You can created up to 20 assignments', stu_example: 'Example)\n John Doe\n John Doe\n John Doe', hw_description_limit_200: 'Add assignment description. (within 200 characters)', hw_title_limit_50: 'Enter Assignment name. (within 50 characters)', create_project_class_1: 'Create projects you want to share ', create_project_class_2: "with the class from 'Create> Create Project'", create_lesson_assignment_1: 'Create lessons you want to add as', create_lesson_assignment_2: "course assignment from 'Create > Create lessons'", i_make_lesson: 'Create lessons', lesson_to_class_1: "'Favorite lessons you want to add as", lesson_to_class_2: "course assignment from 'Learn > Open lessons'", studying_students: 'Student', lessons_count: 'Number of Lessons', group_out: 'Leave', enter_group_code: 'Enter class code', no_group_invite: 'There is no class invitation', done_create_group: 'Class is created', set_default_group: 'Set as default classroom', edit_group_info: 'Modify class information', edit_done: 'Edit complete', alert_group_out: 'Do you want to leave the class?', lesson_share_cancel: 'Cancel Sharing Lesson', project_share_cancel: 'Cancel Sharing Project', lesson_share_cancel_alert: 'Are you sure to change it?', course_share_cancel: 'Cancel Sharing Courseware', select_lesson_share: 'Select lesson to share', select_project_share: 'Select project to share', select_lesson_share_policy_1: 'Please check share settings', select_lesson_share_policyAdd: 'Please check share settings', select_lesson_share_project_1: 'Please check share settings', select_lesson_share_policy_2: 'and copyright policies', select_lesson_share_area: 'Select share settings', select_project_share_area: 'Select share settings', lesson_share_policy: "I agree to Entry's Copyright Policies.", project_share_policy: "I agree to Entry's Copyright Policies.", alert_agree_share: "To share publicly, you must agree to Entry's copyright policies", alert_agree_all: 'Agree to all items', select_course_share: 'Select courseware to share', select_course_share_policy_1: 'Please check share settings', select_course_share_policy_2: 'and copyright policies', select_course_share_area: 'Select share settings', course_share_policy: "I agree to Entry's Copyright Policies.", issued: 'Issued', code_expired: "Code has expired. Press 'Reissue Code' button", accept_class_invite: 'Accept class invitation', welcome_class: 'Welcome to the class.', enter_info: 'Please enter your information.', done_group_signup: 'You have successfully enrolled to this class', enter_group_code_stu: 'Enter the class code sent from your teacher', text_limit_50: 'Enter 50 characters or less.', enter_class_name: 'Please enter your class name', enter_grade: 'Please enter your grade', enter_class_info: 'Please enter your class introduction', student_dup: 'exits in this class already.', select_stu_print: 'Select student to print', class_id_not_exist: 'The class ID does not exist', error_try_again: 'Error occured. Please try again', error_forbidden: 'You have no permission', code_not_available: 'The code is not valid', gnb_create_lessons: 'Create lessons', study_lessons: 'Learn Lesson', lecture_help_1: 'Select the base project that the learner will start building his/her project on.', lecture_help_2: 'To see this help message again, click the button above.', lecture_help_3: "If 'add object' is not shown, adding or deleting object is not possible.", lecture_help_4: 'See PDF attachment to get help', lecture_help_5: 'Select blocks needed to create project. Unselected blocks will be hidden.', lecture_help_6: 'choose between block Coding and Entry Python to organize your learning environment.', lecture_finish_popup_title: 'Re-learn', lecture_finish_popup_content_1: 'Practice Completion Do you want to practice one step from the beginning?', lecture_finish_popup_content_2: '* The practice completion status is maintained', lecture_start_title: 'Start', lecture_goal_title: 'Goal', lecture_goal_content: 'Goal', lecture_prepare_title: 'Prepare', lecture_summary_title: 'Summary', lecture_summary_content: "Let's summarize what we learned.", lecture_quiz_title: 'Quiz', lecture_quiz_content: "Let's check what we learned through the verification problem.", lecture_quiz_check_answer: 'Check the answer', default_hint_title: 'How do you make it?', only_pdf: 'Only pdf file is uploadable', enter_project_video: 'Enter at least one project or video', enter_title: 'Enter title.', enter_recommanded_grade: 'Enter recommanded grade.', enter_level_diff: 'Enter level of difficulty.', enter_time_spent: 'Enter time spent.', enter_shared_area: 'Select at least one sharing space', enter_goals: 'Enter goals', enter_lecture_description: 'Enter lecture information', enter_curriculum_description: 'Enter courseware information', first_page: '처음 입니다.', last_page: '마지막 입니다.', alert_duplicate_lecture: 'The lesson is already registered', enter_lesson_alert: 'Register one or more lessons', open_edit_lessons: 'Open lesson to be edited', saved_alert: 'was successfully saved.', select_lesson_type: 'Select type of lesson you want to create.', create_lesson: 'create lesson', create_lesson_desc_1: 'create a lesson', create_lesson_desc_2: 'according to learning objectives', create_lesson_desc_3: 'for your course.', create_courseware: 'Create courseware', create_courseware_desc_1: 'put multiple lessons together', create_courseware_desc_2: 'to create a courseware', create_courseware_desc_3: '', create_open_lesson: 'Create open lesson', enter_lesson_info: 'Enter lesson information', select_lesson_feature: 'Select lesson feature', check_info_entered: 'Check information entered', enter_lefo_lesson_long: 'Enter information about the lesson.', lesson_info_desc: 'Select features and projects that learners will use to create optimal learning environment.', provide_only_used: 'Only provide blocks used in the goal project', see_help: 'See help', select_done_project_1: 'Select', select_done_project_2: 'the goal project', select_done_project_3: 'that the learner is to create', select_project: 'Select my project or my favorite project', youtube_desc: 'Enter Youtube links', lesson_video: 'Lesson video', lesson_title: 'Lesson title', recommended_grade: 'grade level', selection_ko: '', selection_en: 'Select', level_of_diff: 'difficulty', select_level_of_diff: 'Select difficulty', enter_lesson_title: 'enter lesson title (in 30 characters or less)', select_time_spent: 'Select time', time_spent: 'time', lesson_overview: 'Lesson Overview', upload_materials: 'Upload course materials', open: 'Open', cancel: 'Cancel', upload_lesson_video: 'Upload lesson video', youtube_upload_desc: 'Insert Youtube link for course videos', cancel_select: 'Undo select', select_again: 'Select again', goal_project: 'Goal', upload_study_data: 'Upload learning materials that learners can view while building the project.', upload_limit_20mb: 'Upload up to 20MB', expect_time: 'Time spent', course_videos: 'course videos', enter_courseware_info: 'Enter courseware information', enter_course_info: 'Enter courseware information', select_lessons_for_course: 'Select lessons to create a courseware.', course_build_desc_1: '', course_build_desc_2: 'Up to 30 lessons', course_build_desc_3: 'allowed.', lseeon_list: 'show lesson List', open_lessons: 'Open lessons', course_title: 'Courseware title', title_limit_30: 'Enter courseware title(within 30 characters)', course_overview: 'Courseware Overview', charactert_limit_200: 'Enter within 200 characters', edit_lesson: 'Edit lesson', courseware_by_teacher: 'Teacher created lesson collections', select_lessons: 'Select lessons', check_course_info: 'Check if the lesson collection information is correct', select_share_area: 'Select sharing space', upload_sub_project: 'Goal project upload', file_download: 'Download file', file_remove: 'Remove file', check_lesson_info: 'Check if the lesson information is correct', share_area: 'Sharing space', enter_sub_project: 'Register side project', lms_hw_title: 'Title', lms_hw_ready: 'Ready', lms_hw_progress: 'In progress', lms_hw_complete: 'Complete', lms_hw_not_submit: 'Unfinished', lms_hw_closed: 'Closed', submission_condition: 'Submission is allowed only for assignments in progress', submit_students_only: 'Only students are allowed to submit assignments', want_submit_hw: 'Are you sure you want to submit your assignment?', enter_correct_id: 'Enter correct ID', id_not_exist: 'The ID does not exist.', agree_class_policy: 'Agree to class service usage policy.', delete_class: 'Delete classs', type_stu_name: 'Please enter the student name.', invite_from_1: 'is invited to', invite_from_2: '', lms_pw_alert_1: 'Once you enter class,', lms_pw_alert_2: 'teacher is allowed to reissue your login password.', lms_pw_alert_3: 'Make sure that the invitation is from your teacher.', invitation_accepted: 'Invitation Accepted!', cannot_issue_pw: 'Password cannot be issued because invitation has not been accepted', start_me_1: 'Start coding education', start_me_2: 'with !', monthly_desc_1: 'Monthly Entry is a monthly distributed magazine created ', monthly_desc_2: 'to help teachers learn to teach programming in fun and easy way.', monthly_desc_3: 'Check out the fun cartoons and programming contents every month!', monthly_desc_4: '* The Monthly Entry has ceased publication.', monthly_desc_5: 'Download educational materials from the Educational Materials page.', monthly_entry: 'Monthly Entry', me_desc_1: 'Meet Monthly Entry magazine distributed monthly!', me_desc_2: '', solve_desc_1: 'Learn the basics of', solve_desc_2: 'software programming by solving', playSw_desc_1: 'Learn to code by watching EBS TV Series and special tutorial videos!', playSw_desc_2: '', recommended_lessons: 'Recommendations', recommended_lessons_1: 'Follow along, challenge, solve quizzes and learn to program with Entry!', recommended_lessons_2: '', offline_top_desc_1: "Offline Editor's Save Feature has improved as well as security.", offline_top_desc_2: 'Download now', offline_main_desc: 'Update Entry Offline Editor', art_description: 'This is a project sharing space. Create your own project and share.', art_description_1: '', art_description_2: 'projects created. Create your own project and share.', study_index: "Learn to code with Entry's coursewares by topic and grade levels", study_for_beginner: 'Entry First Steps for Starters', entrybot_desc_3: 'Take Entrybot to school', entrybot_desc_4: 'by assembling command blocks', move_entrybot: 'Control Entrybot', can_change_entrybot_1: "Change Entrybot's color, make it talk", can_change_entrybot_2: 'using block commands', learning_process_by_topics: 'Courseware by topic', show_detail: 'See Details', solve_mission: 'Solve Mission', solve_mission_desc_1: 'Learn to code while playing games and solving missions!', solve_mission_desc_2: 'Control Entrybot move through the maze so it can reach its destination while learning the concepts of sequence, repeat, select and comparison.', learning_process_by_grades: 'Courseware by grade levels', learning_process_by_grades_sub1: 'Learn programming concepts in steps with Entry lectures! Start now!', e3_to_e4: 'Elementary 3-4th grade', e5_to_e6: 'Elementary 5-6th grade', m1_to_m3: '7th+ and above', make_using_entry: 'Create projects with Entry', make_using_entry_desc_1: 'Assemble block to create your own program!', make_using_entry_desc_2: 'Download and follow along the learning materials to create animation, media art, game and other fun programs.', make_through_ebs_1: 'Learn to code by watching EBS TV Series.', make_through_ebs_2: 'The fun TV Series are accompanied by step-by-step tutorial videos so anyone can easily create programs.', support_block_js: 'Block code and javascript are supported', study_ebs_title_1: '순서대로! 차례대로!', study_ebs_desc_1: '[실습] 엔트리봇의 심부름', study_ebs_title_2: '쉽고 간단하게!', study_ebs_desc_2: '[실습] 꽃송이 만들기', study_ebs_title_3: '언제 시작할까?', study_ebs_desc_3: '[실습] 동물가족 소개', study_ebs_title_4: '다른 선택, 다른 결과!', study_ebs_desc_4: '[실습] 텔레파시 게임', study_ebs_title_5: '정보를 담는 그릇', study_ebs_desc_5: '[실습] 덧셈 로봇 만들기', study_ebs_title_6: '요모조 따져 봐!', study_ebs_desc_6: '[실습] 복불복 룰렛', study_ebs_title_7: '번호로 부르면 편해요!', study_ebs_desc_7: '[실습] 나만의 버킷리스트', study_ebs_title_8: '무작위 프로그램을 만들어라!', study_ebs_desc_8: '[실습] 무작위 캐릭터 만들기', study_ebs_title_9: '어떻게 찾을까?', study_ebs_desc_9: '[실습] 도서관 책 검색', study_ebs_title_10: '줄을 서시오!', study_ebs_desc_10: '[실습] 키 정렬 프로그램', event: '이벤트', divide: '분기', condition: 'conditionals', random_number: '무작위수', search: '탐색', sorting: '정렬', parallel: '병렬', signal: '신호', input_output: '입출력', sequential: 'sequence', repeat: 'repeat', choice: 'selection', repeat_advanced: 'repeat(sequence+condition)', function: 'Function', compare_operation: 'comparison', arithmetic: '산술연산', entry_recommended_mission: 'Entry Recommended Mission', more_mission: 'More Mission', line_rangers_title: 'Saving Sally with\nLINE Rangers', line_rangers_content: 'Save Sally trapped\nin the Mepisto base.', pinkbean_title_string_basic: 'Maple Story Basic Henesys', pinkbean_title_string_intermediate: 'Maple Story Intermediate Ellinia', pinkbean_title_string_advanced: 'Maple Story Advanced Elnath', pinkbean_title: 'To the Maple World\nwith PINK BEAN!', pinkbean_content: 'Help Pinkbean to finish\nhis Maple World adventure.', entrybot_school: 'Go to school', entrybot_school_desc_1: 'Help Entrybot to get backpack and go to school', entrybot_school_desc_2: '', robot_factory: 'Robot Factory', robot_factory_desc_1: 'Entrybot is trapped in a robot factory!', robot_factory_desc_2: 'Collect all parts to escape the factory.', electric_car: 'Electric Car', electric_car_desc_1: "Help Entrybot's car move forward ", electric_car_desc_2: 'by making sure it has enough fuel.', forest_adventure: 'Forest Adventures', forest_adventure_desc_1: "Entrybot's friends are trapped in the forest!", forest_adventure_desc_2: "Help Entrybot's friends escape.", town_adventure: 'Village Adventures', town_adventure_desc_1: 'Help Entrybot find fuel', town_adventure_desc_2: 'in the village.', space_trip: 'Space Travels', space_trip_desc_1: 'Entrybot just completed its space exploration.', space_trip_desc_2: 'Help Entrybot return to Earth.', learn_programming_mission: 'Learn programming by playing challenges', make_open_lecture: 'Create open lessons', group_created: 'Class created', group_signup: 'Class enrolled', delete_from_list: 'from the list?', delete_from_list_en: 'Are you sure you want to delete', lecture_collection: 'Courseware', edit_mypage_profile: 'Managae my info', main_image: 'Main image', edit_profile_success: 'Applied.', no_project_1: 'There are no projects to show.', no_project_2: 'How about creating your project now?', empty_project_1: 'There is no work made yet.', no_marked_project_1: 'There is no favorite project at this moment.', no_marked_group_project_1: 'There is no favorite class project at this moment.', no_marked_project_2: "'Browse through 'Share' section to find interesting projects! ", no_markedGroup_project_2: "Browse through 'Class share' section to find interesting projects!", view_project_all: 'Browse project', no_lecture_1: 'There are no lessons to show.', empty_lecture_1: 'There is no lecture made yet.', no_lecture_2: "Create lessons from 'open lessons'", no_marked_lecture_1: 'There is no favorite lesson to show.', no_marked_group_lecture_1: 'There is no favorite class lesson to show.', no_marked_lecture_2: "Browse through 'Open lessons' to see various lessons!", view_lecture: 'Browse lessons', no_studying_lecture_1: 'There are no lessons to show.', no_studying_lecture_2: "Start learning from 'Open lessons' section!", no_lecture_collect_1: 'There are no courseware to show.', empty_lecture_collect_1: 'There is no courseware made yet.', no_lecture_collect_2: "Create courseware from 'Create open courseware'", make_lecture_collection: 'Create courseware', no_marked_lecture_collect_1: 'There is no favorite courseware to show.', no_marked_lecture_group_collect_1: 'There is no favorite class courseware to show.', no_marked_lecture_collect_2: "Browse through 'Open lessons' to see various lessons!", view_lecture_collection: 'Browse courseware', no_studying_lecture_collect_1: 'There are no courseware to show.', no_studying_lecture_collect_2: "Start learning from 'Open lessons' section!", my_lecture: 'My lessons', markedGroup: 'Favorite group', markedGroup_lecture: 'Favorite group lessons', markedGroup_curriculum: 'Favorite group curriculum', marked_lecture: 'Favorite lessons', marked_lecture_collection: 'My courseware', marked_marked_curriculum: 'My courseware', studying_lecture: 'Lessons in progress', completed_lecture: 'Lessons completed', my_lecture_collection: 'My courseware', my: 'My', studying_lecture_collection: 'Courseware in progress', completed_lecture_collection: 'Courseware completed', my_curriculum: 'My Courses', studying_curriculum: 'Courseware in progress', completed_curriculum: 'Courseware completed', materialCC: 'All contents provided are released under Creative Commons CC-BY 2.0 License.', materialccby_new: 'All contents provided are released under Creative Commons CC-BY 2.0 License.', entry_copyright_info: 'ENTRY copyright guide', pdf: 'PDF', helper: 'helper', youtube: 'vedio', tvcast: 'vedio', goal: 'goal', basicproject: 'basic', hw: 'hardware', object: 'object', console: 'Console', download_info: 'Click on the title to download resource', entry_materials_all: 'Entry Educational Materials', entry_material: 'Learning Entry', recommand_grade: 'Grade levels', g3_4_grades: '3-4th', g5_6_grades: '5-6th', middle_grades: '7th+', entry_go_go: 'Entry Go Go!', entry_go_go_desc: "Explore a set of courseware, student activity book and teacher's guide", entry_go_go_desc2: 'ndevided by grade and difficulty.', stage_beginner: 'Basic', stage_middle: 'Advanced', stage_high: 'Expert', middle_school_short: '7th+', learn_entry_programming: 'Follow along step by step.', entry_programming_desc: 'Entry Programming: Become an Entry expert!', ebs: '', ebs_material_desc: "Teach using the EBS TV Series and Teacher's Guide!", season_1_material: "Season 1 Teacher's Guide", season_2_material: "Season 2 Teacher's Guide", season_1: 'Season 1', playsoftware_ebs: 'EBS Let’s play, SW!', material_teacher_guide: "Teacher's Guide", season_2: 'Season 2', compute_think_textbook: 'Improve computational thinking skills', computational_sw: 'Learn to code for subjects such as language arts, math, science, fine arts!', python_coding_text: 'Entry Python', python_coding_textbook: 'Travel to the text coding world! Entry Python', python_coding_desc: 'Learn the structure and grammar of text coding with Entry Python!', entry_x_hardware_text: 'Entry X Hardware', entry_x_hardware: 'Entry Hardware Educational Materials', e_sensor: 'E Sensorboard', e_sensor_board: 'E Sensor-board', e_sensor_robot: 'E Sensor-robot', arduino: 'Arduino', arduinoext: 'ArduinoExt Uno', arduinonano: 'Arduino Nano', albert: 'albert', orange_board: 'orangeBoard', arduino_board: 'Arduino', joystick: 'joystick sensor shield', ardublock: 'ardublock', mkboard: 'digital monkeyboard', mechatro_nano: 'Mechatro Nano+', mechatro_uno: 'Mechatro Uno+', memaker: 'memaker', edumaker: 'EduMaker Board', codingtoolbox: 'codingtoolbox', materials_etc_all: 'Other Educational Materials', materials_teaching: 'For Teacher Education', materials_etc: 'Other Resources', materials_etc_resource: 'Resources', materials_teaching_etc: 'Teacher training', materials_teaching_1: 'Why Coding?', materials_teaching_2: 'Unplugged Acitivies with Entry', materials_teaching_3: 'Learn by playing in Entry Coding Missions', materials_teaching_4: 'Entry for Real World Problem Solving', materials_teaching_5: 'Interdisciplinary Coding(Art,Math,Social)', materials_teaching_6: 'Interdisciplinary Coding(Korean,Science,Music)', materials_teaching_7: 'Physical Computing 1 (E-Sensorboard)', materials_teaching_8: 'Physical Computing 2 (Hamster Robot)', materials_teaching_9: 'Learn to use Entry LMS effectively ', materials_etc_1: 'Getting Started Guide', materials_etc_2: 'Contents for Classroom Use', materials_etc_3: 'Monthly Entry', materials_etc_4: 'About Entry', materials_etc_5: 'Introducing Entry', materials_etc_6: 'Entry Block Catalogue', materials_etc_7: 'Entry Python Guide', jr_if_1: 'if', jr_if_2: 'in front', jr_fail_no_pencil: "There is no pencil. Use 'pencil block' at the pencil!", jr_fail_forgot_pencil: "Oh no! I forgot my pencil. Let's pick up the pencil.", jr_fail_much_blocks: '너무많은 블록을 사용했어, 다시 도전해볼래?', cparty_jr_success_1: 'Hooray! I got my backpack!', go_right: 'go right', go_down: 'go down', go_up: 'go up', go_left: 'go left', go_forward: 'Go forward', jr_turn_left: 'Turn left', jr_turn_right: 'Turn right', go_slow: 'Go slow', repeat_until_reach_1: '', repeat_until_reach_2: 'Repeat until reach', pick_up_pencil: 'Pick up', repeat_0: 'Repeat', repeat_1: '', when_start_clicked: 'When start button clicked', age_0: 'Age 0+', create_character: 'Creating Character', age_7_9: 'Age 7~9', going_school: 'Going to School', age_10_12_1: 'Age 10~12', collect_parts: 'Collecting Parts', age_10_12_2: 'Age 10~12', driving_elec_car: 'Driving Electric Car', age_13: 'Age 13+', travel_space: 'Traveling Space', people: 'Person', all: 'All', life: 'Life', nature: 'Nature', animal_insect: 'Animal/Insect', environment: 'Environment', things: 'Things', vehicles: 'Vehicles', others: 'Others', fantasy: 'Fantasy', instrument: 'Instrument', piano: 'Piano', marimba: 'Marimba', drum: 'Drum', janggu: 'Janggu', sound_effect: 'Sound', others_instrument: 'Others', aboutEntryDesc_1: 'Entry is an education platform created to help anyone learn to code.', aboutEntryDesc_2: 'Students are able to learn to code while playing,', aboutEntryDesc_3: 'teachers are able to teach effectively.', aboutEntryDesc_4: 'Entry is a non-profit service.', aboutEntryDesc_5: '', viewProjectTerms: 'See usage policy', openSourceTitle: 'Promoting open source culture', openSourceDesc_1: "Entry's source code and ", openSourceDesc_2: 'all educational materials', openSourceDesc_3: 'are open to public', viewOpenSource: 'See open source code', eduPlatformTitle: 'Entry for Classroom Use', eduPlatformDesc_1: 'Entry is developed with teachers ', eduPlatformDesc_2: 'to promote learning', eduPlatformDesc_3: 'in classroom settings.', madeWith: 'Advisory group', researchTitle: 'Continuous improvement through research', researchDesc_1: 'Entry collaborates with researchers to strengthen learning effectiveness', researchDesc_2: '', researchDesc_3: '', viewResearch: 'See research materials', atEntry: 'Entry provides', entryLearnDesc_1: 'learn while playing', entryLearnDesc_2: '< Learn > section provides various coursewares and learning materials.', entryLearnDesc_3: 'Watch videos, solve problems and learn while playing.', entryLearnDesc_4: '', entryMakeDesc_1: ' section provides block-based coding tool which enables', entryMakeDesc_2: 'even first time learners to easily create programs.', entryMakeDesc_3: 'And also provides ‘entry phython’ mode which is between block-based coding', entryMakeDesc_4: 'and text-based coding to help you understand the structure and grammar', entryMakeDesc_5: 'of programming languages.', entryShareDesc_1: ' section allows users to share his or her project with others.', entryShareDesc_2: 'Explore how the shared projects are created, make improvements,', entryShareDesc_3: 'collaborate with friends to make even cooler projects.', entryGroup: 'Learning Management Tool', entryGroupTitle: 'My Class', entryGroupDesc_1: ' is created to help teachers easily manage students.', entryGroupDesc_2: 'Create your own class, assign homework,', entryGroupDesc_3: 'share project within the class, and check student progress.', entryGroupDesc_4: 'And teacher can lead the class effectively by providing more suitable coursewares', entryGroupDesc_5: 'according to the students’ level.', unpluggedToPhysical: 'From Unplugged Activity to Physical Computing', algorithmActivity: 'Basic Algorithm', programmignLang: 'Block-based Coding', unpluggedDesc_1: 'Learn the basics of programming such as sequence, repetition,', unpluggedDesc_2: 'selection and function by playing Entry Boardgame and Cardgame.', entryMaze: 'Entrybot Maze Escape', entryAI: 'Space Travels', algorithmDesc_1: 'Earn a certificate by completing the coding missions.', algorithmDesc_2: 'Learn to code while playing.', programmingLangDesc_1: 'Coding is made easy with Entry.', programmingLangDesc_2: 'Create your own games, animation, media art and much more.', viewSupporHwVideo: 'See the hardware guide videos', viewSupporHw: 'see which hardware connects', supportHwDesc_1: 'Entry connects to many physical computing devices to create awesome projects', supportHwDesc_2: 'that interacts with the physical world. More devices are continuously added!', entryEduSupport: 'Entry Education Support', eduSupportDesc_1: 'Entry Labs provides educational materials for free.', eduSupportDesc_2: 'Download educational materials from the Educational Materials page.', materials_1_title: 'Textbook by grade levels', materials_1_desc_1: 'Improve coding skills step by step', materials_1_desc_2: '', materials_2_title: "EBS TV program and teacher's guide", materials_2_desc_1: 'EBS TV series are accompanied', materials_2_desc_2: "by teacher's guide", materials_3_title: 'Educational materials', materials_3_title_2: 'for elementary and mid to high school', materials_3_desc_1: 'Improve computational thinking skills.', materials_3_desc_2: '', moreMaterials: 'See more educational materials', moreInfoAboutEntry_1: "Click on the links below to get Entry's latest updates.", moreInfoAboutEntry_2: 'Educational materials as well as exciting news are shared.', material_menu_type_robot: 'Robot\nType', material_menu_type_module: 'Module\nType', material_menu_type_board: 'Board\nType', blog: 'Blog', post: 'Post', tvCast: 'TVCast', about_entry_pre: 'Entry', about_youtube: 'Youtube', about_facebook: 'Facebook', albertSchool: 'Albert', arduinoBoard: 'Arduino certified', arduinoCompatible: 'non-certified', bitBlock: 'BitBlock', bitbrick: 'Bitbrick', creamo: 'creamo', playcode: 'playcode', funboard: 'funboard', truerobot: 'TrueTrue', bingle: 'BINGLE', bingles: 'BINGLE · S', codeino: 'CODEino', epor: 'EPOR', petrone_v2: 'Petrone V2', petrone_v2_drone: 'flight', petrone_v2_car: 'drive', 'e-sensor': 'E-Sensorboard', 'e-sensorUsb': 'E-Sensor board', 'e-sensorBT': 'E-Sensor board(Bluetooth)', mechatronics_4d: '4D Mechatronics', esensor_board: 'E-Sensor Board', esensor_robot: 'E-Sensor Robot', hamster: 'Hamster', hummingbird: 'Hummingbird Duo', roboid: 'Roboid', turtle: 'Turtle', littlebits: 'Littlebits', orangeBoard: 'OrangeBoard', robotis_carcont: 'Robotis Robot Car', robotis_IoT: 'Robotis IoT', robotis_IoT_Wireless: 'Robotis IoT(Wireless)', dplay: 'DPLAY', iboard: 'iboard', nemoino: 'NEMOino', xbot_epor_edge: 'XBOT(OneTouch Dongle/USB)', XbotBT: 'XBOT EPOR and EDGE Bluetooth', robotori: 'robotori', rokoboard: 'rokoboard', neobot: 'NEOBOT', neobot_sensor_theme: 'NEOBOT Senosor Theme', mechatro: 'mechatro', about: 'About', articles: 'Articles', gallery: 'Gallery', learn: 'Learn', login: 'Sign In', logout: 'Sign Out', make: 'Create', register: 'Sign Up', Join: 'Join', Edit_info: 'Edit Info', Discuss: 'Discuss', Explore: 'Explore', Load: 'Load', My_lesson: 'Open Lessons', textbook_learning: 'Learning Text book', Resources: 'Resources', play_software: 'EBS Let’s play, SW!', problem_solve: 'Entry Learn', learning_textbook: 'Learning Text book', context_textbook: 'Teachers can teach the school class and students can prepare and review at home with the same content as their textbooks.', info_banner_textbook: ' ', banner_textbook: 'Do you want to learn more', banner_textbook_2: 'diverse and interesting things?', banner_textbook_right_banner: 'Do you need educational ', banner_textbook_right_banner2: 'materials for teachers?', banner_textbook_right_banner_btn: 'Download material', Learn: 'Learn', teaching_tools: 'Teaching Tools', about_entry: 'About ENTRY', what_entry: 'What is Entry?', create: 'Create', create_new: 'Create new', start_programming: 'First Step for Software Education', Entry: 'Entry', intro_learning: 'Learn to code in fun and easy way.', intro_learning_anyone: 'Start now with Entry!', start_now: 'For Free, Forever.', welcome_entry: 'Welcome to ENTRY', student: 'Student', non_menber: 'General', teacher: 'Teacher', terms_conditions: 'Terms and Conditions', personal_information: 'Information about the collection and use of personal information ', limitation_liability: 'Limitation of Liability', entry_agree: 'Agree to ENTRY’s Terms of Use', info_agree: '', next: 'Next', enter_individual_info: 'Enter personal information', enter_id: 'Enter ID', enter_password: 'Enter Password', confirm_password: 'Confirm Password', enter_password_again: 'Enter your password again', validation_password: 'Please use at least 5 letters and/or numbers', validation_id: 'Please use 4-20 letters and/or numbers.', prev: 'Back', born_year: 'Year born ', select_born: 'Select the year you were born.', year: 'years', gender: 'Gender', choose_gender: 'Choose gender', male: 'Male', female: 'Female', language: 'Language', best_language: 'Select your best language', korean: 'Korean', english: 'English', viet: 'Vietnamese', japan: 'Japanese', russia: 'russia', korean_s: 'korean', english_s: 'english', japan_s: 'japanese', chinese_simplified: 'Chinese(Simplified)', chinese_traditional: 'Chinese(Traditional)', option_email: 'Email (optional)', insert_email: 'Enter your email address', sign_up_complete: 'Sign up complete!', agree_terms_conditions: 'Please agree Terms and Conditions', agree_personal_information: 'Please agree to the collection and use of personal information.', insert_studying_stage: 'Please select the group you want to share your project .', insert_born_year: 'Insert the year you were born', insert_gender: 'Please select gender from the options.', select_language: 'select language', check_email: "Check email's format", already_exist_id: 'ID already exists', id_validation_id: 'ID use 4-20 letters and/or numbers.', password_validate_pwd: 'Password use at least 5 letters and/or numbers', password_validate_pwd_length: 'Please use at least 5 numbers.', neoid_username_same_id: 'Username already taken (NEOID)', insert_same_pwd: 'Insert same password', studying_stage_group: 'Sharing class', studying_stage: 'Please select the group you want to share.', password: 'Password', save_id: 'Save ID', auto_login: 'Keep me sign in', enter_id_pw: 'Entry ID, Password', forgot_password: 'Forgot your ID or password?', did_not_join: 'Haven’t signed up yet?', go_join: 'Go to join', renew_index_text_00: 'Learn textbook', renew_index_text_01: "Let's learn Entry with textbook.", renew_index_text_02: 'Through elementry textbook lectures,', renew_index_text_02_2: 'learn Entry!', renew_index_text_03: 'Go to', renew_index_text_03_2: 'learn textbook', renew_index_text_1: '2019, Meet the changed Entry', renew_index_text_2: "The brand new 'Create Project'", renew_index_text_3: "Go to the 'Create Project'", renew_index_text_3_2: 'and find out the new functions!', renew_index_text_4: 'View Details', first_step: 'First Step for Software Education', entry_content_one: 'Bring your imagination to life with ENTRY.', entry_content_two: 'Create games, animations, media art, and other cool projects!', entry_content_three: 'Create projects and share with your friends. Enter the exciting world of ENTRY!', funny_space: 'A Fun Learning Space', in_learn_section: 'In < Learn > section,', learn_problem_solving: 'Various learning contents and mini challenges are available for you in the < Learn > section. Solve mini challenges by coding. Watch fun videos and learn to program.', joy_create: 'A Creative Space', in_make: 'In < Create > section', make_contents: 'In the section, create your own program with block-based programming language. Create simulation programs to test laws of Physics. Create animation program with your favorite characters. Bring your imagination to life with Entry. ', and_content: 'There is no limit to what you can create. You can experiment physical laws you’ve learned in science class, create animations featuring your favorite characters, and even make your own games. ', share_collaborate: 'A Sharing Space', explore_contents: 'The section, showcases thousands of projects created and shared by the Entry community. Try out the fun and creative projects, see how they are coded, and improve them. You can also cooperate with your peers to create exciting projects.', why_software: 'Why is learning to code important?', speak_obama_contents: 'Learning these skills isn’t just important for your future. It’s important for our country’s future.', obama: 'Barack Obama', us_president: 'U.S President', billgates_contents: 'Learning to write programs stretches your mind, and helps you think better, creates a way of thinking about things that I think is helpful in all domains.', billgates: 'Bill Gates', chairman_micro: 'Chairman, Microsoft', eric_contents: "For most people on Earth, the digital revolution hasn't even started yet. Within the next 10 years, all that will change. Let's get the whole world coding!", eric: 'Eric Schmidt', sandbug_contents: 'An understanding of computer science is becoming increasingly essential in today’s world. Our national competitiveness depends upon our ability to educate our children—and that includes our girls—in this critical field.', sandbug: 'sheryl Sandberg', view_entry_tools: 'Introducing Entry’s unplugged games for teaching programming.', solve_problem: 'Solve Mission', solve_problem_content: 'Mini challenges will help you learn the basics of programming.', find_extra_title: 'ENTRY Bot part finding extravaganza', all_ages: 'For all ages', total: 'Total', step: 'steps', find_extra_contents: 'Entry bot is special robot created one day at the Rutz Robot Toy Factory during a blackout. Help him find his missing parts and escape the factory while learning to code.', software_play_contents: 'Watch ‘Let’s Play Software’ , follow along the tutorials and learn to create fun programs.', resources_contents: 'Get various Entry educational materials for free', from: 'From', sw_camp: 'Software Creativity Camp, Ministry of Science, ICT and Future Planning', elementary: 'Elementary', middle: 'Middle school', grades: 'Grades', lesson: 'Lessons', sw_contents_one: 'This guidebook is for elementary students learn physical computing over a 5-lesson course. Students learn to use Entry and create images and stoires. In the final section, students use Arduino to create a musical keyboard', sw_camp_detail: 'Ministry of Science, ICT and Future Planning Software Creation Camp', sw_contents_two: 'This textbook allows middle school students to experience ENTRY and physical computing over a 5-lesson course. Students learn how to use ENTRY, and create a maze game and quiz program. In the final section, students use Arduino and keyboard to steer a car.', sw_contents_three: 'This is a teacher’s guide for starting computing classes in schools. It contains a variety of unplugged activities and lesson plans using clips from ‘Let’s play, Software!’broadcasts. ', naver_sw: 'NAVER Let’s play, Software!', teacher_teaching: 'Teacher’s Guide (for elementary grades 5-6 and above)', funny_sw: 'Have Fun with Software', sw_contents_four: 'This textbook allows students to learn about computing in a fun and playful way through a variety of unplugged activities such as ENTRY Board, and teaches students the basic principles of programming via ENTRY Course Mode. Once they have got down the basics, students learn how to create stories, games, artistic works, and applications using ENTRY. The textbook allows students to create and present their own software. ', ct_text_5: 'Grow computational thinking with skills.', teacher_grade_5: '교원 (초등학교 5학년)', ct_text_5_content: "This teacher's guide contains 8 problem solving tasks. Each task is designed to reflect the revised National Curriculum and contains interdisciplinary themes. Cultivate computational thinking skills.", ct_text_6: '교과서와 함께 키우는 컴퓨팅 사고력', teacher_grade_6: '교원 (초등학교 6학년)', ct_text_6_content: '실생활의 문제를 해결하자는 테마로 준비된 총 8개의 학습콘텐츠가 담긴 교사용 지도안입니다. 각 콘텐츠는 개정된 교육과정을 반영한 타교과와의 연계를 통해 다양한 문제를 만나고 해결해볼 수 있도록 설계되었습니다. 아이들이 컴퓨팅 사고력을 갖춘 융합형 인재가 될 수 있도록 지금 적용해보세요!', sw_use: 'All textbooks are for non-commercial use only, and can be used freely so long as the author is credited. ', title: 'Title', writer: 'By', view: 'View', date: 'Date', find_id_pwd: 'Find ID or Password', send_email: 'A link to change your password has been sent to you by email.', user_not_exist: 'This email does not exist.', not_signup: "Haven't signed up yet?", send: 'Send', sensorboard: 'ENTRY Sensor Board', physical_computing: 'Physical Computing', sensorboard_contents: 'Using Arduino no longer requires building a circuit using lots of wires. With ENTRY Board, you can use LED lights, temperature, sound, light sensors, a slider, and switches by simply mounting it onto an Arduino board. Now anyone can easily create their own unique projects using ENTRY Board!', entrybot_boardgame: 'ENTRY-Bot Board Game', unplugged: 'Unplugged Activities', unplugged_contents: 'Learn the principles of programming through Entry-bot Board Game. By helping Entrybot escape the factory, you can learn to think like a computer scientist.', entrybot_cardgame: 'ENTRY Bot Cardgame : Bomb Tempest', entrybot_cardgame_contents: '12 different types of bombs appear at the city of Entry! Dismantle the bombs one at a time and learn the basics of programming. By using the concepts of sequence, repetition and conditionals, save the City and become a hero!', basic_learn: 'Entry Basics', basic_learn_contents: 'Learn to program with Entry’s coursewares', troubleshooting: 'Problem Solving', playsoftware: "Let's play, Software!", make_own_lesson: 'Create your own lessons and share them with everyone.', group_lecture: 'Lessons', group_curriculum: 'Courseware', group_homework: 'Assignment', group_noproject: 'No Project', group_nolecture: 'No Lessons', group_nocurriculum: 'No Courseware', lecture_contents: 'Create customized lessons with limited blocks.', curriculum_contents: 'Create a course by putting together series of lessons.', grade_info: 'Grades information', difficulty: 'Difficulty', usage: 'Usages', learning_concept: 'Learning concepts', related_subject: 'Related subjects', show_more: 'Show more', close: 'Close', latest: 'By Latest', viewCount: 'view count', viewer: 'By Viewers', like: 'By Likes', comment: 'By Comments', entire_period: 'Entire period', today: 'Today', latest_week: 'Latest 1 week', latest_month: 'Latest 1 month', latest_three_month: 'Latest 3 months', current_password: 'Current password', change_password: 'Change password', incorrect_password: 'Incorrect! Try again.', incorrect_password_login: 'The Username or Password you entered is incorrect.', suspension_user: 'The login of the account is prohibited.', blocked_user: 'Blocked!!', new_password: 'New password', password_option_1: 'Please use at least 5 letters and/or numbers.', again_new_password: 'Confirm new password', enter_new_pwd: 'Enter new password.', confirm_new_pwd: 'Confirm new password.', enter_new_pwd_again: 'Enter new password again.', password_match: 'Passwords do not match.', incorrect_email: 'Incorrect email. Try again.', edit_button: 'Edit info', edit_profile: 'Edit', my_project: 'My projects', my_group: 'My Class', mark: 'Marking', prev_state: 'Back', profile_image: 'Profile image', insert_profile_image: 'Please upload a profile image.', at_least_180: 'At least 180x180 pixels is recommended.', upload_image: 'Upload image', about_me: 'About me', save_change: 'Save changes', basic_image: 'Basic Image', profile_condition: 'Enter something about yourself. (in 50 characters)', profile_back: 'Go back', make_project: 'Create project', exhibit_project: 'Exhibit Project', art_list_shared: 'Shared', art_list_group_shared: 'Group', gl_mode_boost: 'Boost Mode', gl_not_supported: 'Can not run in boost mode.\nClick OK to run in default mode.', view_project: 'View Code', code_view: 'View Code', noResult: 'No results found', comment_view: 'Comment', upload_project: 'Upload', edit: 'Edit', save_complete: 'Save', just_like: 'Like', share: 'Share', who_likes_project: 'Who likes the projects', people_interest: 'People interested projects', none_person: 'Nobody', inserted_date: 'Date', last_modified: 'Last Modified', original_project: 'Original project', for_someone: "'s", original_project_deleted: 'The original project was deleted', delete_project: 'Delete', delete_group_project: 'Delete From List', currnet_month_time: 'months', current_day_time: 'days', game: 'Game', animation: 'Animation', media_art: 'Media Arts', physical: 'Physical', etc: 'ETC', connected_contents: 'Linking content', connected_contents_content: "Discover the variety of content that can be done with the entry . If you're new software to learn easily from person to enjoy board games , you can take advantage of the Arduino and physical computing , such as creating a luxurious view of your own creation .", basic_mission: 'Basic mission : Entry bot Maze', basic_mission_content: 'A power outage at a toy robot factory magically enabled Entrybot to come to life. Help Entrybot escape the factory and find freedom!', application_mission: "Application mission: Entry bot's Space Odyssey", write_article: 'Write', write_contest: 'Submit', view_all_articles: 'View all posts', view_own_articles: 'View my posts', view_qna_articles: 'View no answered posts', learning_materials: 'Learning materials', download_materials: 'Learning materials download', download_button: 'download', download_all: 'download all', ebs_software_first: " is a TV series created by Naver, EBS and Entry Labs. Learn the basic principles of programming. Watch the show, follow along the video tutorials, and learn to code!", go_software: "Visit Let's play software!", ebs_context: 'Visit EBS', ebs_context_hello: 'Visit EBS', category: 'Category', add_picture: 'Add Picture', upload_article: 'Upload article', list: 'List', report: 'Report', upload: 'Upload', staff_picks: 'Staff Picks', popular_picks: 'Popular Projects', lecture_header_more: 'More Projects', lecture_header_reset: 'Reset', lecture_header_reset_exec: 'Reset to basic project', lecture_header_save: 'Save', lecture_header_save_content: 'Save current lecture', lecture_header_export_project: 'Export to my project', lecture_header_undo: 'Undo', lecture_header_redo: 'Redo', lecture_er_bugs: 'Feedback', lecture_container_tab_object: 'Objects', lecture_container_tab_video: 'Video', lecture_container_tab_project: 'Final project', lecture_container_tab_help: 'Help', illigal: 'Illegal or inappropriate behavior', verbal: 'Verbal abuse or posting personal information', commertial: 'Posting for commercial purposes', explicit: 'Explicit content', other: 'Other', check_one_more: 'Please select the reason more than one.', enter_content: 'Please enter the reason for your report.', report_result: 'Please enter email address to be informed of report results. ', report_success: 'Your report was submitted successfully.', etc_detail: 'Please give details', lecture_play: 'Play', list_view_link: 'List', lecture_intro: 'Introduction Lessons', study_goal: 'Goals', study_description: 'Description', study_created: 'Created', study_last_updated: 'Updated', study_remove: 'Remove', study_group_lecture_remove: 'Remove From List', study_group_curriculum_remove: 'Remove From List', study_edit: 'Edit', study_comments: 'Comments', study_comment_post: 'Post', study_comment_remove: 'Remove', study_comment_edit: 'Edit', study_comment_save: 'Save', study_guide_video: 'Guide Video', study_basic_project: 'Initial Project', study_done_project: 'Complete Project', study_usage_element: 'Usage', study_concept_element: 'Concept', study_subject_element: 'Related', study_computing_element: 'Computational Thinking', study_element_none: 'None', study_label_like: 'Like', study_label_interest: 'Interest', study_label_share: 'Share', study_label_like_people: 'People who liked this lecture', study_label_interest_people: 'People who interested this lecture', study_related_lectures: 'Related lectures', study_expand: 'Show all', study_collapse: 'Collapse', aftercopy: 'Copied to clipboard', study_remove_curriculum: 'Are you sure to remove this course?', content_required: ' Please enter the contents.', upload_not_supported_file_msg: 'Not supported file type.', study_remove_lecture: 'Are you sure to remove this lesson?', lecture_build: 'Make a lesson', lecture_build_step1: '1. Enter basic lesson information', lecture_build_step2: '2. Selecte required functions', lecture_build_step3: '3. Confirm all of information correctly.', lecture_build_choice: 'What is main content?', lecture_build_project: 'Entry Project', lecture_build_video: 'Lessons Video', lecture_build_grade: 'Grades', lecture_build_goals: 'Goals', lecture_build_add_goal: 'Add a goal', lecture_build_attach: 'Attachment', lecture_build_attach_text: 'Less than 20MB', lecture_build_assist: 'Additional', lecture_build_youtube_url: 'Paste a Youtube share link', lecture_build_project_done: 'Select a completed project.', lecture_build_scene_text1: 'Using scene function or not', lecture_build_scene_text2: '', lecture_build_object_text: 'Using Object add function or not', lecture_build_blocks_text1: 'Select required blocks only.', lecture_build_blocks_text2: '', lecture_build_basic1: 'Select a project.', lecture_build_basic2: 'User start with this project.', lecture_build_help: '', lecture_build_help_never: 'Close permanently', lecture_build_close: 'Close', lecture_build_scene: 'Scene 1', lecture_build_add_object: 'Add Object', lecture_build_start: 'Start', lecture_build_tab_code: 'Block', lecture_build_tab_shape: 'Shape', lecture_build_tab_sound: 'Sound', lecture_build_tab_attribute: 'Attribute', lecture_build_tab_table: 'Table', lecture_build_block_category: 'Select block category.', lecture_build_attr_all: 'All', lecture_build_attr_var: 'Variable', lecture_build_attr_signal: 'Signal', lecture_build_attr_list: 'List', lecture_build_attr_func: 'Function', lecture_build_edit: 'Edit', lecture_build_remove: 'Remove', curriculum_build: 'Create a courseware', curriculum_step1: 'Fill information about this course.', curriculum_step2: 'Select lessons for this course.', curriculum_step3: 'Confirm information.', curriculum_lecture_upload: 'Upload', curriculum_lecture_edit: 'Edit', curriculum_lecture_open: 'Open', group_lecture_add: 'Add my group lessons', group_curriculum_add: 'Add my group curriculum', group_lecture_delete: 'Delete', group_curriculum_delete: 'Delete', group_select: '', group_studentNo: 'Student No', group_username: 'Name', group_userId: 'ID', group_tempPassword: 'Modify PW', group_gender: 'Gender', group_studentCode: 'Code', file_load_web_table_title: 'Import table from the Google Sheets', file_load_web_table_sub_title: 'You can import table from Google Sheets documents.', file_input_sheet_id: 'Google Sheets ID', file_input_sheet_id_require: 'Required', file_input_sheet_id_placeholder: 'Please enter Google Sheets ID.', file_input_sheet_name: 'Sheet name', file_input_sheet_name_placeholder: 'Please enter sheet name.', file_load_web_warn_title_1: "You can import the contents of a Google Sheets document and add them to the table.\nThis can only be imported if the access rights are set to 'Anyone with link'", file_load_web_warn_title_2: 'The following datas are subject to the Terms of Use and related laws.', file_load_web_warn_desc_2_1: 'Violent and brutal data, Sacred body exposure data, Offensive or disgusting data, \nData of copyright prohibited from unauthorized use', file_load_web_error_sheet_id_1: 'Google Sheets ID is not entered.', file_load_web_error_sheet_id_2: 'Invalid Google Sheets ID.', group_viewWorks: 'View Works', added_group_lecture: 'lessons deleted', added_group_curriculum: 'Course deleted', deleted_group_lecture: 'lessons deleted', deleted_group_curriculum: 'Course deleted', modal_my: 'My', modal_interest: 'Marked', modal_project: 'Project', section: 'Sections', connect_hw: 'connect hardware', connect_message: 'Connected to %1', connect_fail: 'Connect fail', interest_curriculum: 'Interest', marked_curriculum: 'Interest Curriculum', searchword_required: 'Please enter your search keyword.', file_required: 'File is required.', file_name_error: 'please insert correct file name', file_upload_max_count: 'You can only upload 10 files at a time.', image_file_only: 'You can only upload jpg, png, bmp files.', file_upload_max_size: 'You can only upload less than 10MB in file size.', curriculum_modal_lectures: 'My Lessons', curriculum_modal_interest: 'Interest', group_curriculum_modal_curriculums: 'My Courses', group_curriculum_modal_interest: 'Interest', picture_import: 'Import a picture', picture_select: 'Select a picture', lecture_list_view: 'list', play_software_2: 'Let’s play, Software2!', play_software_2_content: " is a TV series created by Naver, EBS and Entry Labs. Learn the basic principles of programming. Watch the show, follow along the video tutorials, and learn to code!", open_project_to_all: 'Open', close_project: 'Close', category_media_art: 'Media Art', go_further: 'Go further', marked_project: 'Bookmark Project', marked_group_project: 'Favorite group project', basic: 'Basic', application: 'Application', the_great_escape: 'The Great Escape', escape_guide_1: 'ENTRY Bot suddenly began to think for himself during a power failure at the robot dog factory! ', escape_guide_1_2: ' Help ENTRY Bot escape the factory and find his freedom!', escape_guide_2: 'ENTRY Bot is missing too many parts to make it far. Help him find his parts as he makes his way out the factory!', escape_guide_2_2: 'Objectives: Sequential Execution', escape_guide_3: 'I’ve finally escaped the factory! But it’s still a long way to the village. I think I’m fixed up enough to make it there without too much difficulty. Hey, what’s that robot?', escape_guide_3_2: 'Objectives: Repetitive and Conditional Statements', escape_guide_4: 'We’re finally getting close to the village! I’m starting to really get the hang of this! I think it might be better to just use the blocks from memory. If I just recharge my battery here, I’ll be able to live free forever.', escape_guide_4_2: 'Objectives: Definitions of Function and Function Call', space_travel_log: 'Space Travel Log', space_guide_1: 'ENTRY Bot has finally completed his exploration of distant space. He’s trying to make his way back home to Earth, but his path is being blocked by a bunch of space rocks! Help ENTRY Bot make it back to Earth safely!', space_guide_2: 'It’s finally time to return to Earth! I can’t wait to get back and rest! Tell me the positions of the rocks ahead so I can navigate through them! I’ll go the way you tell me to!', space_guide_2_2: 'Objective: Reiterating IF Statements and Logical Operation', cfest_mission: 'ENTRY Experiential Mission', maze_1_intro: 'Hi. I’m ENTRY Bot. I’m about to save my injured friends and I need your help. Help me save my friends! First, set up the ‘Move forward one space’ block and press ‘Start’.', maze_1_title: 'How to Start', maze_1_content: 'How do I move ENTRY Bot?', maze_1_detail: '1. Take a block from the Block Box and connect it with the ‘When Start is pressed’ block.
2. Press Start once you have finished assembling.
3. I will move in the order of your assembled blocks from top to bottom. ', maze_2_intro: 'Alright! You’ve saved the first of my friends! Now let’s save my next friend. Oh! There’s a beehive in the way! Use the Jump Over block to avoid the beehive and save my friend!', maze_2_title_1: 'Jump Over', maze_2_content_1: 'How do I get around obstacles?', maze_2_detail_1: 'Sometimes your path may be blocked by an obstacle.
When there’s an obstacle in your path, you need to use the ‘Jump Over’ block.', maze_2_title_2: 'How to Start', maze_2_content_2: 'How do I move ENTRY Bot?', maze_2_detail_2: '1. Take a block from the Block Box and connect it with the ‘When Start is pressed’ block.
2. Press Start once you have finished assembling.
3. I will move in the order of your assembled blocks from top to bottom. ', maze_3_intro: 'Awesome! Now let’s go save another friend! How about we use the ‘Repeat’ block that my other friend gave use? You can easily repeat the same movements over again using the ‘Repeat’ block! Try changing the number of times to repeat. ', maze_3_title: 'Repeat Block (1)', maze_3_content: 'How do I use the ‘Repeat (3)’ block?', maze_3_detail: 'To perform the same action/s more than once, you need to use the ‘Repeat’ block.
Put the blocks that you want to repeat inside the Repeat box and select the number of times you want to repeat.', maze_4_intro: 'Super! Not too many robot friends left to save now. Take us to my friend by using the ‘Jump Over’ block on repeat while also evading the beehive!', maze_4_title: 'Repeat Block (1)', maze_4_content: 'How do I use the ‘Repeat (3)’ block?', maze_4_detail: 'To perform the same action/s more than once, you need to use the ‘Repeat’ block.
Put the blocks that you want to repeat inside the Repeat box and select the number of times you want to repeat.', maze_5_intro: 'Cool! Now let’s try using the ‘Repeat’ block and ‘IF’ block together! Using the ‘IF’ block, you can turn in a direction where there are no walls when you come across a wall. Well then, shall we set off to save my friend?', maze_5_title_1: 'IF block', maze_5_content_1: 'How does the ‘IF’ block work?', maze_5_detail_1: 'You can determine what action to take when you come across a {IMAGE}.
The blocks are used only when you come across a {IMAGE}.
If there is none, the block is not used.', maze_5_title_2: 'Repeat Block (2)', maze_5_content_2: 'How do I use the ‘Repeat until’block?', maze_5_detail_2: 'Using the ‘Repeat until’block, you can determine until when a specified action is repeated.
Just put the blocks you want to repeat inside the ‘Repeat until’ block.
Then, the repetition will stop when you reach the space where the {IMAGE} is located. ', maze_6_intro: 'Only one friend left! Just do as we’ve practiced and you’ll succeed! Now, let’s go save him!', maze_6_title_1: 'IF block', maze_6_content_1: 'How does the ‘IF’ block work?', maze_6_detail_1: 'You can determine what action to take when you come across a {IMAGE}.
The blocks are used only when you come across a {IMAGE}.
If there is none, the block is not used.', maze_6_title_2: 'Repeat Block (2)', maze_6_content_2: 'How do I use the ‘Repeat until’block?', maze_6_detail_2: 'Using the ‘Repeat until’block, you can determine until when a specified action is repeated.
Just put the blocks you want to repeat inside the ‘Repeat until’ block.
Then, the repetition will stop when you reach the space where the {IMAGE} is located. ', maze_programing_mode_0: 'Block Coding', maze_programing_mode_1: 'Javascript', maze_operation1_title: 'STEP 1 – Javascript mode guide', maze_operation1_1_desc: "Hi, I'm Entrybot, the robot dog. Give me commands to reach the mission goals. You can learn about the mission when you begin under 'Goals.'", maze_operation1_2_desc: 'Once you learn your goal, you need to give me commands. ’Command Box’ is where the commands reside. You can create commands using mouse and keyboard. With the mouse, you can click or drag the commands to create instructions.', maze_operation1_2_textset_1: 'How to click on the commands', maze_operation1_2_textset_2: 'How to drag and drop commands', maze_operation1_3_desc: 'If you want to use the keyboard to give commands, type in the commands in the ’Command Box.’
When you type in the commands, be careful not to ommit () and ;', maze_operation1_4_desc: 'Once you have finished inputting the commands, click [Run.]
I will move according to your code once you click [Run.]
If you want to know more about each command, check out the [Command guide.]', maze_operation7_title: 'STEP 7 - How repeat works (repeat number of times)', maze_operation7_1_desc: 'Repeating the same command over and over is a cumbersome task.
Simplify the command using the repeat commands.', maze_operation7_2_desc: 'Then let\'s look at how we can simplify commands that repeat.
First, click the repeat command. Then change the number ini<1
Then insert the commands to repeat within { }', maze_operation7_3_desc: 'For example, this command executes move(); 10 times.
It is the same as command ', maze_operation7_4_desc: 'When using commands, make sure to spell the commands correctly within { }
and that you don\'t forget ’;\'.
Learn more about the commands in the \'command guide\'', maze_operation7_1_textset_1: 'When using commands repeatedly', maze_operation7_1_textset_2: 'When using repeat command', maze_operation7_2_textset_1: 'Number of times to repeat', maze_operation7_2_textset_2: 'Commands to repeat', maze_operation7_4_textset_1: 'When ({}) is missing', maze_operation7_4_textset_2: 'When semicolon(;) is missing', study_maze_operation8_title: 'STEP 4 - How repeat works (repeat number of times)', study_maze_operation16_title: 'STEP 4 - How repeat works (repeat number of times)', study_maze_operation1_title: 'STEP 1 - How repeat works (repeat number of times)', maze_operation9_title: 'STEP 9 - How repeat works(Conditional loop)', maze_operation9_1_desc: 'We learned about repeating for set number of times.
This time, let\'s explore commands for repeating continuously.
When you use this command, the action will be executed until end of the mission.
Insert commands to be repeated within ({ }).', maze_operation9_2_desc: ' move(); right(); until end of mission.
It is the same as command ', maze_operation9_3_desc: 'Make sure to spell the commands correctly within { }
and make sure ‘true\' isn\'t missing!
You can learn more about this command in the \'command guide\'', maze_operation9_1_textset_1: 'Commands to repeat', maze_operation9_3_textset_1: 'When ({}) is missing', maze_operation9_3_textset_2: 'When semicolon(;) is missing', maze_operation9_3_textset_3: 'When semicolon(;) is missing', study_maze_operation3_title: 'STEP 3 - How repeat works(Conditional loop)', study_maze_operation4_title: 'STEP 4 – How condition works', study_ai_operation4_title: 'STEP 4 – How condition works', study_ai_operation6_title: 'STEP 6 – How condition works', study_ai_operation7_title: 'STEP 7 – How condition works', study_ai_operation8_title: 'STEP 8 – How condition works', study_ai_operation9_title: 'STEP 9 – How condition works', maze_operation10_title: 'STEP 10 – How condition works', maze_operation10_1_desc: 'We learned about repeating commands until end of the mission.
This time, let\'s explore the commands that are only executed under certain conditions.
As you can see in , using conditional statement can make commands more efficient.', maze_operation10_2_desc: 'conditional statement can be split into condition and commands to be executed when met with the condition.
First, let\'s look at the conditions. Insert the condition within ( ) that follows ‘if\'.
For example if(front == ‘wall\') means, ’if there is a wall in front of me.’', maze_operation10_3_desc: 'Now let\'s explore commands to execute when met with the condition. These commands are tied within curly braces {} and are executed when met with the given condition.When condition is not met, the commands are ignored.Let\'s look at an example . If the condition is \'when a wall is in front of me\', and the condition is met, then I execute the commands within the braces and turn right following the command right();', maze_operation10_4_desc: 'The conditional statements are often used with repeat commands.
Go straight and turn only when met with a wall.
I can create commands in the order of ', maze_operation10_1_textset_1: '[commands]', maze_operation10_1_textset_2: 'move 2 forward
turn right,
move 3 forward
turn right, move forward…
', maze_operation10_1_textset_3: '[conditional statements]', maze_operation10_1_textset_4: 'Go forward
\'when met with a wall’
turn right!
', maze_operation10_2_textset_1: 'condition', maze_operation10_2_textset_2: 'commands to execute when condition is met', maze_operation10_3_textset_1: 'condition', maze_operation10_3_textset_2: 'commands to execute when condition is met', maze_operation10_4_textset_1: 'Go forward
until end of mission
', maze_operation10_4_textset_2: 'Go forward
until met with a wall
', maze_operation10_4_textset_3: 'Go forward
until met with a wall
then turn right
', study_maze_operation18_title: 'STEP 6 – How condition works', maze_operation15_title: 'STEP 15 – How function works', maze_operation15_1_desc: 'It is a cumbersome task to type out the commands that are used often.
Give a name to the set of commands that are used often.
Then call the set of commands by its name to create commands conveniently.
These sets commands are called \'functions\'. Now let\'s explore what functions are.', maze_operation15_2_desc: 'Using a function involves process of creating a function by grouping a set of functions, and calling the set of commands by \'call function’.
Let\'s take a look at the process of defining a function.To define a function, give a function name and set of commands to execute.
First input ‘function\' and then give the function name. This time, I\'ll call it promise.
Once you\'ve given it a name, insert (). Then type in ({ }).Once you insert the commands within these brackets, you have finished defining a function!', maze_operation15_3_desc: 'Take a look at this command. I created a function called promise
When I call this function, then the commands within the brackets({}) will execute
move();
move();
left();
', maze_operation15_4_desc: 'To call and execute functions, input the name of the functions, then add \'();\' behind it.
So to call a function called \'promise\', I need to type promise();
to execute the function.
When I make commands like , the program will execute as that of
To use the function, define function as and call it.', maze_operation15_1_textset_1: 'Checking the commands that are used often', maze_operation15_1_textset_2: 'Giving a name for set of commands', maze_operation15_1_textset_3: 'Calling a set of commands', maze_operation15_2_textset_1: 'Name of the command set (function name)', maze_operation15_2_textset_2: 'commads to group as a set', maze_operation15_3_textset_1: 'Name of the command set (function name)', maze_operation15_3_textset_2: 'commads to group as a set', maze_operation15_4_textset_1: 'Defining function', maze_operation15_4_textset_2: 'Calling function', maze_operation15_4_textset_3: 'Real situation', maze_object_title: 'Object info', maze_object_parts_box: 'Tool box', maze_object_trap: 'trap', maze_object_monster: 'monster', maze_object_obstacle1: 'obstacle', maze_object_obstacle2: 'bee', maze_object_obstacle3: 'banana', maze_object_friend: 'friend', maze_object_wall1: 'wall', maze_object_wall2: 'wall', maze_object_wall3: 'wall', maze_object_battery: 'battery', maze_command_ex: 'example', maze_command_title: 'command guide', maze_command_move_desc: 'moves entrybot one forward', maze_command_jump_desc: 'jumps over obstacles like the image below.
', maze_command_jump_desc_elec: 'jumps over obstacles like the image below.
', maze_command_right_desc: 'turn 90 degrees right in place.', maze_command_left_desc: 'turn 90 degrees left in place.', maze_command_for_desc: 'repeat commands within curly braces {} for given number of times.', maze_command_while_desc: 'repeat commands within curly braces {} until end of mission', maze_command_slow_desc: 'When condition \'when met with a wall’ is fulfilled,
execute commands within curly braces {}', maze_command_if1_desc: 'When condition \'when met with a wall’ is fulfilled,
execute commands within curly braces {}', maze_command_if2_desc: 'When condition \'when met with a beehive’ is fulfilled,
execute commands within curly braces {}', maze_command_if3_desc: 'When condition \'when met with a banana’ is fulfilled,
execute commands within curly braces {}', maze_command_promise_desc: 'when a function called \'promise\' is defined and executed,
then the functions within the curly braces {} will execute. ', perfect: 'Perfect! You succeeded using ', succeeded_using_blocks: ' blocks!', succeeded_using_commands: ' commands!', awesome: 'Awesome! You succeeded using just', succeeded_go_to_next: ' blocks!', good: 'Good!', but: '
But, there is a way to succeed using just ', try_again: ' blocks.
Why don’t you try again?', try_again_commands: ' commands.
Why don’t you try again?', cfest_success: 'Awesome! You helped save my friends!
Looks like you’re a natural born programmer!
See you again soon!', succeeded_and_cert: 'blocks!
My certificate of completion is ready!', cause_msgs_1: 'Oh dear, it’s a dead end. Try again.', cause_msgs_2: 'Oops. There’s nothing to jump over. Try again.', cause_msgs_3: 'Ouch! That hurt. You should have jumped over this. Try again.', cause_msgs_4: 'Sorry, but you need to use the below blocks in this level.
Do you want to try again?', cause_msgs_5: 'Uh oh… You’ve run out of blocks. Try again.', cause_msgs_6: 'Uh oh… You’ve run out of commands. Try again.', close_experience: 'The
End', replay: 'Replay', go_to_next_level: 'Next', move_forward: 'Move forward', turn_left: 'Left', turn_right: 'Right', turn_en: 'Turn ', turn_ko: '', jump_over: 'Jump Over', when_start_is_pressed: 'When Start is pressed', repeat_until_ko: '', repeat_until_en: 'Repeat until', repeat_until: 'Repeat until', if_there_is_1: 'If there is a ', if_there_is_2: '', used_blocks: 'Blocks used', maximum: 'Maximum', used_command: 'Command used', maximum_command: 'Maximum command', block_box: 'Block Box', block_assembly: 'Block Assembly', command_box: 'Command Box', command_assembly: 'Command Assembly', start: 'Start', engine_running: 'Play', engine_replay: 'Replay', goto_show: 'Learn more', make_together: "Let's build together!", make_together_content: 'Entry is created with teachers and students', project_nobody_like: "Click 'Like', if you like it!", project_nobody_interest: "Click 'Mark' to keep it on your blog.", lecture_nobody_like: "Click 'Like', if you like it!", lecture_nobody_interest: "Click 'Mark' to keep it on your blog.", course_nobody_like: "Click 'Like', if you like it!", course_nobody_interest: "Click 'Mark' to keep it on your blog.", before_changed: 'before changed', after_changed: 'after changed', from_changed: '( From 17 Apr 2016 ) ', essential: 'essential', access_term_title: 'Hello we are an educational institute Entry .
Thank you for loving your entry
From April 17, 2016 Entry Training Institute Website Terms and Conditions
is amended to read as follows:', member_info: 'Member information', personal_info: 'Agree to the transfer of personal information.', option: 'select one', news: 'news', edu_material: 'materials', latest_news: 'Latest news', edu_data: 'Educational', training_program: 'Training', footer_phrase: 'Entry is a nonprofit education platform powered by Naver and CONNECT Foundation', footer_use_free: 'All materials created by Entry Labs may be used freely for educational purposes as long as the original source is credited.', footer_description_1: 'Entry is a nonprofit education platform.', footer_description_2: 'All materials created by Entry Labs may be used freely for educational purposes as long as the original source is credited.', nonprofit_platform: 'nonprofit educational platform', this_is: 'powered by Naver and CONNECT Foundation', privacy: 'Privacy policy', entry_addr: '16F, 6, Buljeong-ro, Bundang-gu, Seongnam-si, Gyeonggi-do', entry_addr_additional_phone: '1522-9182', entry_addr_additional_email: 'entry@connect.or.kr', entry_addr_additional_opensource: 'Open Source License', phone: 'phone', alert_agree_term: 'Please agree to ENTRY’s Terms of Use', alert_private_policy: 'Please agree to the collection and use of personal information.', agree: 'Agree', optional: 'option', start_software: 'first step of software education', analyze_procedure: '절차', analyze_repeat: '반복', analyze_condition: '분기', analyze_interaction: '상호작용', analyze_dataRepresentation: '데이터 표현', analyze_abstraction: '추상화', analyze_sync: '병렬 및 동기화', jr_intro_1: 'Hi! My name is Juny! My friend Entry-Bot is by my right side. Please take me to him! ', jr_intro_2: "Entry-Bot is by my left! Let's go the left side. ", jr_intro_3: 'Entry-Bot is by my top side. Please help me meet my friend. ', jr_intro_4: "Come on! Let's meet Entry-Bot! He is by my bottom side. ", jr_intro_5: 'Wow! My friend is far away from me. Can you guide me so I can meet Entry-Bot ', jr_intro_6: "Entry-Bot is really far away from here! But It's okay. If we use repeat block, we could reach the Entry-Bot easily.", jr_intro_7: "There are beautiful flowers here! Let's give it to my friend!", jr_intro_8: "On a way to my friend, you can see the flower. Let's give it to my friend.", jr_intro_9: "Oh, my friend is far away from me. Let's find a fastest way to him!", jr_intro_10: "There are flowers! Let's pick it up! ", jr_intro_11: "We should go right side exactly 5 times! Let's use repeat block so we can reach there more easily", jr_intro_12: "Let's meet my friend Entry-Bot using repeat block.", jr_intro_13: "With this misplaced block, I can't reach my friend. Please change the input number of repeat block.", jr_intro_14: 'Please take me to my friend Entry-Bot using repeat block.', jr_intro_15: "Entry-Bot is really far away from here! But It's okay. If we use repeat block, we could reach the Entry-Bot easily.", jr_whats_ur_name: 'What is your name to be showned on certification.', jr_down_cert: 'Certification', jr_popup_prefix_1: 'Hooray! I met Entry-Bot!', jr_popup_prefix_2: 'Nice! I met Entry-Bot! But we can make it with fewer blocks. How about try again?', jr_popup_prefix_3: 'Hooray! I got my backpack!', jr_popup_prefix_4: 'Great! I have my backpack! But we can make it with fewer blocks. How about we try again?', jr_popup_suffix_1: 'Thank you! I had so much fun with you. See you around!', jr_popup_suffix: 'Thanks to you! I had fun time with Entry-Bot. See you around~', jr_fail_dont_go: "Oops, I can't go there. Please guide me again~", jr_fail_dont_know: 'Hmm. Where should I go? Please guide me more~', jr_fail_no_flower: "There is no flower. Use 'flower block' at the flower!", jr_fail_forgot_flower: "I need more flowers for Entry-Bot. Let's try again.", jr_fail_need_repeat: "Uh? I should use 'repeat block' ! Let's try again with the block~", jr_hint_1: 'Hi! My name is Juny! My friend Entry-Bot is by my right side. Please take me to him!', jr_hint_2: "Entry-Bot is by my left! Let's go the left side.", jr_hint_3: 'Entry-Bot is by my top side. Please help me meet my friend.', jr_hint_4: "Come on! Let's meet Entry-Bot! He is by my bottom side.", jr_hint_5: 'Wow! My friend is far away from me. Can you guide me so I can meet Entry-Bot?', jr_hint_6: "Because of the blocks that put together by mistake, I can't reach my friend. Please fix it for me so I can reach my friend Entry-Bot!", jr_hint_7: "There are beautiful flowers here! Let's give it to my friend!", jr_hint_8: "On a way to my friend, you can see the flower. Let's give it to my friend.", jr_hint_9: "Oh, my friend is far away from me. Let's find a fastest way to him!", jr_hint_10: "Oops, I can't reach to my friend because of misplaced blocks. Please fix it so I can give all of flowers to my friend.", jr_hint_11: "We should go right side exactly 5 times! Let's use repeat block so we can reach there more easily.", jr_hint_12: "Let's meet my friend Entry-Bot using repeat block.", jr_hint_13: "With this misplaced block, I can't reach my friend. Please change the input number of repeat block.", jr_hint_14: 'Please take me to my friend Entry-Bot using repeat block.', jr_hint_15: "Entry-Bot is really far away from here! But It's okay. If we use repeat block, we could reach the Entry-Bot easily.", jr_certification: 'Certification', jr_congrat: 'Congratulation!', jr_congrat_msg: 'Successfully completed for problem solving courses.', jr_share: 'Share', go_see_friends: 'Let us see your friends~!', junior_naver: 'Junior Naver', junior_naver_contents_1: "'s cool bear , Juni came looking for entries! ", junior_naver_contents_2: "But Juni' is difficult to find a way yet. ", junior_naver_contents_3: 'Please tell Juni to go , so he can meet entrybot.', basic_content: 'Basic', jr_help: 'Help', help: 'Help', cparty_robot_intro_1: "Hi, My name is Entry-bot. I need to to fix myself. Please help me get my parts with 'move forward' block.", cparty_robot_intro_2: "Great! My part is right in front of me but I need to be careful not to get electrocuted. Use 'jump over' block to get to the part.", cparty_robot_intro_3: "Great! There's my part! The path is challenging but using the 'turn' block I can get there easily! Will you help?", cparty_robot_intro_4: "Nice! I feel a lot better! Try using the 'turn' block and 'jump over' block to get the parts!", cparty_robot_intro_5: "Thanks to you, I'm feeling great! Make sure to use 'turn' and 'jump over' to get the part!", cparty_robot_intro_6: 'Great! I feel like I can repeat! Use repeat to get to the part!', cparty_robot_intro_7: "Watch out! There are dangerous holes to jump over but no worries! Let's use repeat to get to the part.", cparty_robot_intro_8: 'Oh no! The part is far from here. Using repeat can get me there easily. Help me! ', cparty_robot_intro_9: "Wow~ I'm almost complete! Let's use 'repeat' to get to the part!", cparty_robot_intro_10: "Cool! The last part will make me complete! Let's use 'repeat' to get to my last part! ", cparty_car_intro_1: 'Hi, My name is Entry-bot. I need battery pack to travel! Can you me get to the battery pack?', cparty_car_intro_2: "Good! We can't go straight this time! Let's use the 'turn left/right' block to get to the battery pack.", cparty_car_intro_3: "Great! There's a speed bump on our way. It'll be dangerous to drive fast. Let's use the 'go slow' block to get to the battery pack.", cparty_car_intro_4: "Yeah! The drive doesn't look easy but using the move forward, 'turn left/ right' block", cparty_car_intro_5: "The road looks challenging but we can safely get to the battery pack by repeating 'turn left/ right' blocks", cparty_car_intro_6: 'There are obstacles on our way so let me know how to get around one!', cparty_car_intro_7: "Great! Let's use the 'if' block to get around obastacles and get to the battery pack.", cparty_car_intro_8: "There are two speed bumps this time! Use 'go slow' block to safely travel to the battery pack.", cparty_car_intro_9: "The road looks challenging but using the 'repeat' block and 'if' block, we can make it! Help me get to the battery pack!", cparty_car_intro_10: "Awesome! We're almost there. Let's get that last battery pack!", cparty_car_popup_prefix_1: 'Hooray! I got a battery!', cparty_car_popup_prefix_2: 'Nice! I got a battery! But we can make it with fewer blocks. How about try again?', cparty_car_popup_prefix_2_text: 'Nice! I got a battery! But we can make it with fewer commands How about try again?', cparty_car_popup_suffix: "Thanks to you! I've got all the battery. See you around~", all_grade: 'All grades', grade_e3_e4: 'Elementary 3~4th grade & up', grade_e5_e6: 'Elementary 5~6th grade & up', grade_m1_m3: 'Middle School 1~3rd grade & up', entry_first_step: 'Entry First Steps', entry_monthly: 'Monthly Entry', play_sw_2: "Let's Play Software 2", entry_programming: "Let's Program!", entry_recommanded_course: 'Entry Recommended Courses', introduce_course: 'Follow along and create various projects made easy and fun for everyone!', all_free: '*Course videos, customized projects, and resources are provided for free. ', cparty_result_fail_1: "Oops, I can't go there. Please guide me again~", cparty_result_fail_2: 'Ouch! That hurt. You should have jumped over this. Try again.', cparty_result_fail_3: "I'm worn out! Try using the blocks below and make the travel easier.", cparty_result_fail_4: 'Hmm... Where should I go? Please give me further instructions.', cparty_result_fail_5: "Oh no! You need to slow down at the speed bump. Try using the 'go slow' block.", cparty_result_success_1: 'Hooray! I got a parts', cparty_result_success_2: 'Nice! I got a parts! But we can make it with fewer blocks. How about we try again?', cparty_result_success_2_text: 'Nice! I got a parts! But we can make it with fewer commands How about we try again?', cparty_result_success_3: "Thanks to you! I've fixed all~ See you around~", cparty_insert_name: 'insert your name', offline_file: 'File', offline_edit: 'Edit', offline_undo: 'Un-do', offline_redo: 'Re-do', offline_quit: 'Quit', select_one: 'Please select one.', evaluate_challenge: 'please evaluate the level of difficulty of the mission challenged.', very_easy: 'very easy', easy: 'easy', normal: 'normal', difficult: 'difficult', very_difficult: 'very difficult', save_dismiss: "You didn't saved your changes. Are you sure want to continue?", entry_info: 'About Entry', actual_size: 'Actual Size', zoom_in: 'Zoom In', zoom_out: 'Zoom Out', cparty_jr_intro_1: 'Hi! My name is Entry-Bot! Please help me get my backpack on my way to school.', cparty_jr_intro_2: "My backpack to my left! Let's go left.", cparty_jr_intro_3: 'My backpack is located above. Please help me to get my backpack.', cparty_jr_intro_4: "Come on! Let's pick up the backpack by going downwards.", cparty_jr_intro_5: 'Wow! My backpack is far away from me. Could you take me to my backpack?', cparty_jr_intro_6: "There is backpack! Let's pick it up!", cparty_jr_intro_7: "There are pencils along the way. Let's pick them up on our way to the backpack.", cparty_jr_intro_8: "A pencil on our way to school! Let's pick up the pencil on our way to the backpack.", cparty_jr_intro_9: "Oh, my backpack is far away. Let's find the fastest path to it!", cparty_jr_intro_10: "Let's pick up the pencils on my way to the backpack!", cparty_jr_intro_11: "We should go right exactly 5 times! Let's use the repeat block so we can get there more easily", cparty_jr_intro_12: "Let's pick up the backpack using the repeat block.", cparty_jr_intro_13: "I can't reach my backpack with this misplaced block. Please change the number of repeats.", cparty_jr_intro_14: 'Please take me to my backpack using the repeat blocks.', cparty_jr_intro_15: "School is really far from here! But that's okay. If we use the repeat block, we can get to school easily.", make_new_project: 'Create New Project', open_old_project: 'Open Project', offline_download: 'Entry Download', offline_release: 'Download Entry Offline Editor!', offline_description_1: 'Install and use Entry Offline Editor', offline_description_2: 'without internet connection.', offline_description_3: 'Download and try it out!', sw_week_2015: '2015 소프트웨어교육 체험 주간', cparty_desc: '두근두근 소프트웨어와의 첫만남', entry_offline_download: 'Download \nOffline Editor', entry_download_detail: 'Download\nVeiw Details', offline_desc_1: 'Install and use Entry Offline Editor without internet connection.', offline_desc_2: 'Download and try it out!', download: 'download', version: 'version', file_size: 'size', update: 'update', use_range: 'Scope of use', offline_desc_free: 'Entry Offline Editor is free for both individual and corporate use.', offline_required: 'System Requirement', offline_required_detail: 'Minimum 1GB disk space is required, Windows7 and above or, Mac OS 10.8 and above', offline_notice: 'Side notes', offline_notice_1: '1. Version', offline_notice_1_1: 'does not support installation of all-in-one hardware connection program', offline_notice_2: '2. Web browser is not needed.', offline_notice_3: 'Release note', offline_notice_4: 'Download by version', offline_notice_5: 'Release note', hardware_online_badge: 'Online', hardware_title: 'Entry Hardware Connector Program Download', hardware_desc: "In order to connect to hardware projects and 'Create Project' online, download and install Entry Hardware Connector Program.", hardware_release: 'Details on Hardware Connector Program updates are available in the link below.', hardware_window_download: 'Windows Download', hardware_osx_download: 'Mac Download', cparty_jr_result_2: 'Thank you! I had so much fun with you.
See you around!', cparty_jr_result_3: "Great! I've arrived school! But we can make it with fewer blocks.
How about we try again? ", cparty_jr_result_4: '', lms_no_class: 'There is no class.', lms_create_class: 'Please create a class.', lms_add_class: 'Create class', lms_base_class: 'Default', lms_delete_class: 'Delete', lms_my_class: 'My Class', lms_grade_1: 'elementary school 1', lms_grade_2: 'elementary school 2', lms_grade_3: 'elementary school 3', lms_grade_4: 'elementary school 4', lms_grade_5: 'elementary school 5', lms_grade_6: 'elementary school 6', lms_grade_7: 'middle school 1', lms_grade_8: 'middle school 2', lms_grade_9: 'middle school 3', lms_grade_10: 'general', lms_add_groupId_personal: 'Add classroom ID to your member profile.', lms_add_groupId: 'Add Classroom ID', lms_add_group_account: 'Add Classroom ID', lms_enter_group_info: 'Enter classroom ID and password', lms_group_id: 'Classroom ID', lms_group_pw: 'Password', lms_group_name: 'Class Name', personal_pwd_alert: 'Enter correct password', personal_form_alert: '양식을 바르게 입력해 주세요', personal_form_alert_2: '모든 양식을 완성해 주세요', personal_no_pwd_alert: 'Enter password', select_gender: 'Please enter your gender', enter_group_id: 'Enter classroom ID', enter_group_pwd: 'Enter password', info_added: '추가되었습니다', no_group_id: 'The Class ID does not exist', no_group_pwd: '비밀번호가 일치하지 않습니다', lms_please_choice: 'Choose', group_lesson: '나의 학급 강의', lms_banner_add_group: 'Learning Management System is now available', lms_banner_entry_group: 'Create Entry class ', lms_banner_desc_1: 'Add your students', lms_banner_desc_2: "Manage your student's projects", lms_banner_desc_3: 'and track their growth.', lms_banner_download_manual: 'Manual Download', lms_banner_detail: 'Try it out!', already_exist_email: 'email already exists', same_registered_email: 'Registered email.', email_correnctly_please: 'Please enter a valid email', remove_project: 'Are you sure to remove this project?', study_lesson: 'Class Lessons', open_project: 'Open projects', make_group: 'Create Class', project_share: 'Project share', group_project_share: 'Class Share', group_discuss: 'Class Discuss', my_profile: 'My page', search_updated: 'Recent Project', search_recent: 'Project with most views', search_complexity: 'Project with most effort', search_staffPicked: 'Staff pick project save area', search_childCnt: 'Project with most copies', search_likeCnt: 'Project with most likes', search_recentLikeCnt: 'Project with most likes', gnb_share: 'Share', gnb_community: 'Community', lms_add_lectures: 'Add Lessons', lms_add_course: 'Add Courseware', lms_add_homework: 'Add Assignment', remove_lecture_confirm: 'Are you sure you want to delete?', popup_delete: 'Delete', remove_course_confirm: 'Are you sure you want to delete?', lms_no_lecture_teacher_1: 'There is no lessons.', lms_no_lecture_teacher_2: 'Please create a lessons.', gnb_download: 'Download', lms_no_lecture_student_1: '', lms_no_lecture_student_2: 'There is no lessons.', lms_no_lecture_student_3: '', lms_no_class_teacher: 'There is no class.', lms_no_course_teacher_1: 'There is no courseware.', lms_no_course_teacher_2: 'Please create a courseware.', lms_no_course_student_1: '', lms_no_course_student_2: 'There is no courseware.', lms_no_course_student_3: '', lms_no_hw_teacher_1: 'There is no assignment.', lms_no_hw_teacher_2: 'Please create a assignment.', lms_no_hw_student_1: '', lms_no_hw_student_2: 'There is no assignment.', lms_no_hw_student_3: '', modal_edit: 'edit', modal_deadline: 'Deadline', modal_hw_desc: 'Description', desc_optional: '(optional)', modal_create_hw: 'Create Assignment', vol: 'Vol.', hw_title: 'Title', hw_description: 'Description', deadline: 'Deadline', do_homework: 'Do Assignment', hw_progress: 'Progress', hw_submit: 'submit', view_list: 'Submitter', view_desc: 'content', do_submit: 'submit', popup_notice: 'Alert', no_selected_hw: 'No Assignment is selected', hw_delete_confirm: 'Are you sure you want to delete?', hw_submitter: 'List of Assignment submissions', hw_student_desc_1: "* You may edit the project until 'Submit' button completes the submission process.", hw_student_desc_2: '* Once submission period is over, project cannot be submitted.', popup_create_class: 'Create Class', class_name: 'Class name', image: 'Image', select_class_image: 'Please select a class image.', type_class_description: 'Class Introduction.', set_as_primary_group: 'Set as default classroom', set_primary_group: 'assign', not_primary_group: 'not assigned', type_class_name: 'Please enter the class name.', type_class_description_long: 'Please enter the class introduction.', add_students: 'Add students', invite_students: 'Invite students', invite_with_class: '1. Invite with class code', invite_code_expiration: 'Code expiration time', generate_code_button: 'reissue code', generate_code_desc: 'Student instructions for entering class code', generate_code_desc1: 'Log in at playentry.org', generate_code_desc2: 'Select from the menu.', generate_code_desc3: 'Click then paste in the class code.', invite_with_url: '2. Invite using class URL', copy_invite_url: 'Copy', download_as_pdf: 'Download code as PDF file', download_as_excel: 'Download code as Excel file', temp_password: 'Temporary password', step_name: 'Name', step_info: 'Additional Information', preview: 'Preview', type_name_enter: 'To add student, type in the student name and hit enter. ', multiple_name_possible: 'Adding multiple student names is possible.', id_auto_create: 'Student number is automatically created if not edited', student_id_desc_1: 'Class ID is created automatically without manual input', student_id_desc_2: 'If student account already exists, add student information. When the student logs in,', student_id_desc_3: 'class invitation is sent. No extra step for sharing account information is necessary.', student_number: 'Student number', temp_password_desc_1: 'After logging in with temporary password,', temp_password_desc_2: 'guide the students to reset the password.', temp_password_desc_3: '*You cannot see temporary password once issued', temp_password_demo: 'This is an informational account that can not log in.', temp_works: 'View works', student_delete_confirm: 'Are you sure you want to delete?', no_student_selected: 'No student is selected', class_assignment: 'Class Assignments', class_list: 'Class List', select_grade: 'Please select the grade.', add_project: 'sharing Project', no_project_display: 'There is no project to display.', plz_display_project: 'Please display a project.', refuse_confirm: 'Are you sure you want to refuse?', select_class: '학급 선택', group_already_registered: 'Already registered.', my_page_entry: 'Entry', my_page_title: 'My Page', my_classGroup_title: 'My Class', my_classGroup_title_view: 'view my class', my_space_area: 'my own space', mon: 'MON', tue: 'TUE', wed: 'WED', thu: 'THU', fri: 'FRI', sat: 'SAT', sun: 'SUN', jan: 'Jan', feb: 'Feb', mar: 'Mar', apr: 'Apr', may: 'May', jun: 'Jun', jul: 'Jul', aug: 'Aug', sep: 'Sep', oct: 'Oct', nov: 'Nov', dec: 'Dec', plz_select_lecture: 'Please select a lessons.', plz_set_deadline: 'Please set the deadline.', hide_entry: 'Hide Entry', hide_others: 'Hide Others', show_all: 'Show All', lecture_description: 'Lessons are listed by topics and levels. Follow along in step-by-step order.', curriculum_description: 'Teacher created Entry learning space. See example projects and try creating them.', linebreak_off_desc_1: 'The size of textbox determines the font size.', linebreak_off_desc_2: 'Your content can only be written in one line.', linebreak_off_desc_3: 'The left and the right sides of the textbox will lengthen when you add extra words.', linebreak_on_desc_1: 'The size of textbox determines how much you can write.', linebreak_on_desc_2: "You can change the line by pressing the 'Enter' key.", linebreak_on_desc_3: 'Your content will automatically go to the next line if the length exceeds the width of the textbox, when writing or adding new words.', not_supported_text: 'Current font does not support Chinese characters', entry_with: 'Entry is Created With Teachers', ebs_season_1: 'Visit Season 1', ebs_season_2: 'Visit Season 2', hello_ebs: 'Hello! EBS software', hello_ebs_desc: 'Learn the basic principles of programming. \n Watch the show, follow along the video tutorials, \n and learn to code!', hello_ebs_sub_1: "Meet EBS's interactive middle ", hello_ebs_sub_2: 'school age program.', exhibit_4th_title: '4th Anniversary of Entry', exhibit_4th_subtitle: 'Entry Project Contest', exhibit_4th_desc1: 'We hold an Entry Project Contest ', exhibit_4th_desc2: 'to celebrate the 4th anniversary of entry.', exhibit_4th_desc3: 'Show off your great project!', exhibit_4th_button: 'View Details', visang_edu_entry: '비상교육 엔트리 학습하기', cmass_edu_entry: '씨마스 엔트리 학습하기', chunjae_edu_entry: '천재교과서 엔트리 학습하기', kumsungemt_edu_entry: '금성출판사 엔트리 학습하기', kumsungMid_edu_entry: '금성출판사 엔트리 학습하기', gilbutEdu_edu_entry: '길벗출판사 엔트리 학습하기', miraenCoding_edu_entry: '미래엔 엔트리 학습하기', textbook_help_data: 'Help data', textbook_teaching_activity: 'teaching and activity', textbook_kyohacksa: 'Kyohaksa', textbook_kumsung: 'Kumsung Publishing', textbook_donga: 'Dong-a Publishing', textbook_chunjae: 'Chunjae Education', textbook_miraen: 'Mirae-n', textbook_visang: 'Visang', partner: 'Our Partners', project_term_popup_title: 'Copyright policy', project_term_popup_description_1: 'Please review the Entry ', project_term_popup_description_2: 'copyright policy ', project_term_popup_description_3: 'to allow public viewing ', project_term_popup_description_4: 'of the project.', project_term_agree_1_1: 'I agree to the release of my work itself and its source code.', project_term_agree_2_1: 'I permit others to use it.', project_term_agree_2_2: '(includes copy, distribution, and transmission through airwaves)', project_term_agree_3_1: 'I permit others to make modifications to it.', project_term_agree_3_2: '(includes remixes, modifications, and derivative works)', agree_all: 'I agree to all conditions.', select_login: 'Log in', select: 'Please select', with_login: 'Log in and', without_login: 'Start Challenge', start_challenge: 'Start Challenge', start_challenge_2: 'without Logging in', if_not_save_not_login: '* Your progress will not be saved if not logged in.', if_not_member_yet: "If you aren't a member yet,", join_entry: 'Join Entry', learned_computing: 'Have you learned computing before?', cparty_index_description_1: 'My first computing.', cparty_index_description_2: 'Learn programming concepts and develop your thinking skills while playing Entry. ', cparty_index_description_3: 'Challenge yourself to exciting mission stages and earn certificates.', cparty_index_description_4: '2015 Online Coding Party is part of', cparty_index_description_5: 'Software Programming Experience Week', cparty_index_description_6: 'prepared with', cparty_index_description_7: 'Association of Teachers for Computing.', cparty_index_description_8: '', cparty_index_description_9: '2016 Online Coding Party is part of', cparty_index_description_10: '2017 Online Coding Party is part of', cparty_index_description_11: 'Association of Teachers for Computing.', congratulation: 'Congratulation!', warm_up: 'warm-up', beginner: 'beginner', intermediate: 'intermediate', advanced: 'advanced', applied: 'applied', cert_msg_tail: 'track.', cert_msg_head: 'You have successfully completed the', maze_text_content_1: ' 명령어를 사용해서 나를 부품 상자까지 이동시켜줘!', maze_text_content_2: ' 명령어를 사용해서 장애물을 뛰어넘어야해!', maze_text_content_3: "Nice! I see another part over there. The path is twisted but I can get there using the 'right();', 'left();' commands. ", maze_text_content_4: "I can move smoothly now. Take me to my parts using the commands we've learned so far.", maze_text_content_5: "Wow! Two parts! Let's collect them both so I can recover faster.", maze_text_content_6: "Last part! I'll recover fully with that last piece. You'll help me, right?", maze_text_content_7: "I'm feeling great! I can repeat tasks without stress now. Oh no! What is that robot in front of us? I think it needs help! Use 'for' command to get to the friend!", maze_text_content_8: "Excellent! I was able to rescue my robot friend thanks to you. I see another friend over there. Be careful. There are beehives to avoid. You can do it! Let's use the 'for' command to get to my friend.", maze_text_content_9: "Use 'while' instead of 'for' to repeat until we've accomplished our goal. Take me to my friend.", maze_text_content_10: "Now we have 'if' command. Use 'if' and 'while' to let me know which way to turn.", maze_text_content_11: "Great! Let's do this once more. Tell me when to turn left.", maze_text_content_12: 'There are beehives scattered in the pathway. Tell me when to jump over.', maze_text_content_13: "So many friends need help! Let's go help them", maze_text_content_14: "More friends to rescue! Let's first try going around those square blocks and repeat to get to all of my friends.", maze_text_content_15: "I'm tired from moving so much. I've grouped the commands that are often used into 'functions'. Use functions to get me to my battery!", maze_text_content_16: 'Excellent! Create functions and take me to my battery!', maze_text_content_17: "Great job! Let's create functions with 'jump()", maze_text_content_18: "The pathway is complex this time. But no worries! Just tell me when to use 'left()", maze_text_content_19: "The functions are already defined! However, it seems difficult to get to the battery using only the functions. Let's try mixing functions and commands to get to the battery.", maze_text_content_20: "You've done a fantastic job so far! After I retrieve that last battery, I will no longer need charging. Help me get to the battery using the functions so I can live free forever!", maze_content_1: "Hi, I'm Entrybot. I'm trying to escape from this factory but first, I have to fix myself. Will you help me fetch my parts? Assemble 'Move forward' block and press Start. ", maze_content_2: "Very good! I'm feeling much better! I see my part over there but I might get electrocuted if I don't be careful. Let's use 'jump over obstacle' block to get to the part.", maze_content_3: "Great! My part is right over there. The path is a bit twisted but I can get there using 'rotate' blocks. You'll help me, right?", maze_content_4: "Nice! I can almost move freely now. Let's get the part using 'rotate' and 'jump' blocks.", maze_content_5: "Wow! Two parts! Let's get them both so I can restore my health faster.", maze_content_6: "Thanks to you I'm feeling much better! I'm able to get better with those parts. You'll help me, right?", maze_content_7: "I'm feeling great! I can repeat the same task without trouble now. Oh! Do you see the robot over there? I think she might need help. Let's go help her out. Bring me to her by changing the number of 'repeat's", maze_content_8: "Excellent! I was able to rescue my pal! It looks like another one of my friends need help. Be careful there are beehives. Be sure to jump over the beehives! Can you do it? Help me reach her using the 'repeat' block. ", maze_content_9: 'Instead of repeating a task for set number of times, I can repeat until I reach my robot pal instead! Help me save my friend!', maze_content_10: "Now we can use the 'if' block. Help me use the 'if' block to turn at right timing.", maze_content_11: "Let's try it again! Let me know when to turn left.", maze_content_12: 'There are beehives all over the place. Tell me when to jump!', maze_content_13: "My friends need help! Let's go help them!", maze_content_14: "More friends need rescue! Let's first go around the small square and repeat it to rescue all my friends.", maze_content_15: "Now I can memorize blocks that are used repeatedly. Promise blocks are the ones that I was able to memorize. I'm a bit tired from moving so much. Help me refill my battery using the Promise feature!", maze_content_16: 'Great! Tell me which blocks are used often and put them under the Promise block!', maze_content_17: "Nice! Use Promise blocks to help me get my battery. Make sure to insert 'Jump' blocks in the Promise block.", maze_content_18: 'The path looks complex! We can get through this if we turn left and right at the right time.', maze_content_19: "The 'Promise' if already set for us! However, we can't use the Promise blocks as is. I'll need to use the Promise blocks at the right timing to get the battery.", maze_content_20: "Excellent! You've done great so far! After the final battery, I won't need to charge any more. So help me get the last battery using the Promise so I can live forever free!", maze_content_21: '안녕? 나는 엔트리 봇이야. 지금 많은 친구들이 내 도움을 필요로 하고 있어. 반복하기를 이용해서 친구들을 도울수 있게 데려다 줘!', maze_content_22: '고마워! 이번에는 벌집을 뛰어넘어서 친구를 구하러 갈 수 있게 도와줘!', maze_content_23: '좋아! 이번에는 친구 로봇한테 갈 때까지 반복하기를 이용해서 친구를 도울 수 있게 도와줘!', maze_content_24: '안녕! 나는 엔트리 봇이야. 지금 나는 너무 오래 움직여서 배터리를 채워야 해. 약속 불러오기를 써서 배터리를 채울 수 있도록 도와줘!', maze_content_25: '멋져! 이번에는 여러 약속을 불러와서 배터리가 있는 곳까지 가보자!', maze_content_26: '좋아! 이제 약속할 블록을 나한테 가르쳐줘! 약속하기 블록 안에 자주 쓰일 블록을 넣으면 돼!', maze_content_27: '지금은 미리 약속이 정해져 있어. 그런데, 약속을 쓰기위해서는 내가 갈 방향을 보고 약속을 사용해야해. 도와줄거지?', maze_content_28: '드디어 마지막이야! 약속을 이용하여 마지막 배터리를 얻을 수 있게 도와줘!', ai_content_1: "Hi! I'm Entrybot. I just completed the space exploration mission and I need to return to Earth but it's not easy because of the asteroids. Could you help me return home? I have radars on top, front and back of the spaceship to detect how far an obstacle exists. It'll help you make smart decisions.", ai_content_2: "Thank you! I was able to avoid the asteroids without trouble. There are more asteroids this time. Let's try avoiding them!", ai_content_3: "Great! I was able to safely avoid the asteroids! There are more asteroids now! Don't worry though! I have the 'repeat' block. Place blocks in the 'repeat' block so we can get to the destination!", ai_content_4: "Excellent! It's so much more easier to avoid the asteroids using the repeat blocks! However, it's tiring driving the spaceship at all times! I can use the radar to sense what's coming. Help avoid the asteroids using the radar.", ai_content_5: "Nice! I'm so glad we've come this far. The radar will tell how far an object exists. Let's use the radar to avoid the asteroids! Move forward until we come close to an asteroid then avoid!", ai_content_6: "Great job! You're using radar to avoid tha asteroids. Use multiple radars to avoid the asteroids.", ai_content_7: "We're getting close to Earth! I want to go in a safer path if possible. It must be safer to move farther from the asteroids, right? Compare the distance to the obstacle using the radar on the top and bottom of the spaceship to move to a safer direction.", ai_content_8: "Excellent! We're safely cruising through space. Oh! What is that? That's looks like my special energy! Let's collect the special energy on our way!", ai_content_9: "Very good! We're almost there. The path is filled with asteroid. But don’t worry! We can get rid of the obstacles using the special item.", ai_content_10: "Good! I can see Earth! But now it's impossible to see the asteroids ahead! I'm not worried though. We can avoid the asteroids with more caution. Let's go home!", maze_hints_title_1: 'How to start', maze_hints_content_1: 'How do I move Entrybot?', maze_hints_detail_1: "1. Drag the block you want to use and place it under 'When Run'
2. Once finished, click 'Run'
3. I will follow the block instructions step by step, reading them from top to bottom", maze_hints_title_2: 'Jumping over obstacles', maze_hints_content_2: 'What do I do when I come across an obstacle?', maze_hints_detail_2: "On your pathway, you might come across obstacles.
Use 'jump over' block to jump over the obstacle. ", maze_hints_title_3: 'Repeat block(1)', maze_hints_content_3: 'How do I use repeat (3) times block?', maze_hints_detail_3: "If you want to repeat an action multiple times, use 'repeat ~times' block.
Place the blocks you want to repeat within the 'repeat ~times' block and input how many times to repeat.", maze_hints_title_4: 'Repeat block(2)', maze_hints_content_4: "How do I use 'repeat until ~' block?", maze_hints_detail_4: "Use 'repeat until~do' block to set until when an action should be performed.
Place the blocks you want to repeat within 'repeat until~' block.
Then once met with {image}, repeat will stop.", maze_hints_title_5: 'If block', maze_hints_content_5: "How do I use 'if~' block?", maze_hints_detail_5: "Using 'If {image}' block, you can designate what action should follow when met with {image}.
Blocks within the 'If {image}' will only execute when met with {image}.", maze_hints_title_6: 'Repeat block(3)', maze_hints_content_6: "How does 'Until met with all ~' block work?", maze_hints_detail_6: "Repeat blocks within 'Until met with all ~' block until met with all {tile}.
Once met with all {tile} repeat will stop.", maze_hints_title_7: 'Special Hint', maze_hints_content_7: "It's too difficult. Help!", maze_hints_detail_7: 'Look at the path that I should travel. See the 4 small squares?
First create blocks that will take me around the square and repeat.', maze_hints_title_8: 'Function', maze_hints_content_8: "What is 'Functions/ Call Functions'? How do I use them?", maze_hints_detail_8: "Put the most often used sets of blocks under 'Function'.
Once you create functions, use 'Call Function' to use it as often as needed.", ai_hints_title_1_1: 'Goal of the game', ai_hints_content_1_1: 'Avoid asteroids and help me get to Earth', ai_hints_detail_1_1: 'Avoid asteroids and help me get to Earth', ai_hints_title_1_2: 'Instructions', ai_hints_content_1_2: 'How do I begin?', ai_hints_detail_1_2: "1. Drag out blocks from the block box and connect is with the 'when run' block
2. Once finished assembling blocks, click 'Run'
3. I'll move according to your block instructions.", ai_hints_title_1_3: 'To move', ai_hints_content_1_3: 'How do I move the entrybot?', ai_hints_detail_1_3: 'I can move up, forward or below.
When creating instructions, make sure I avoid the asteroids.
If you send me out of the screen, I can be lost in space forever! So be careful.', ai_hints_title_2_1: 'Goal of the game', ai_hints_content_2_1: 'Use repeat blocks to avoid the asteroids.', ai_hints_detail_2_1: 'Use repeat blocks to avoid the asteroids.', ai_hints_title_2_2: 'Repeat block', ai_hints_content_2_2: 'What is a repeat block?', ai_hints_detail_2_2: "Geez! It's a long way home so putting blocks together one by one is too tiresome. Let's try using the repeat block.
Once you group the blocks under the repeat block, you can shorten the length of the blocks!", ai_hints_content_3_1: "Help me avoid the asteroids using the 'if' block", ai_hints_title_3_2: 'if block(1)', ai_hints_content_3_2: "How does 'if ~' block work? ", ai_hints_detail_3_2: "Using 'if~ in front/ else' block can help me check if there are asteroids in front of me and help me avoid them.
If there's an asteroid in front of me, then blocks under 'if' will execute or if there isn't an asteroid, the blocks under 'else' will execute.
Tell me which way to go depending on whether there's an asteroid to avoid or not.", ai_hints_content_4_1: 'Learn to use the radar to avoid the asteroids.', ai_hints_detail_4_1: 'Learn to use the radar to avoid the asteroids.', ai_hints_title_4_2: 'radar(1)', ai_hints_content_4_2: 'What is a radar and how can I use it?', ai_hints_detail_4_2: "Radar tells me how far an object exists from where I am located.
If there is an object in front of me, the front radar will show '1'.
Also, radar can become a powerful tool when used with 'if <true>/else' block.
For example, when the distance to an object in front of me shows value greater than 1, then I am able to move forward safely.
However, if not, then I can go above or under to avoid it.", ai_hints_title_4_3: 'if block(2)', ai_hints_content_4_3: "How do I use 'if ' block?", ai_hints_detail_4_3: "if <true> block/ else' block executes blocks under 'if' when condition is met and executes blocks under 'else' when condition is not met.
Think about how you want to move at different situations and create a condition within <true> block.
Remember that when condition is met and blocks under 'if' are executed, then the blocks under 'else' will be ignored.", ai_hints_content_5_1: 'Use the radar to help me avoid the asteroids.', ai_hints_detail_5_1: 'Use the radar to help me avoid the asteroids.', ai_hints_title_5_2: 'if block(3)', ai_hints_content_5_2: 'How does nested if blocks work?', ai_hints_detail_5_2: "I can nest 'if ~/else' block within 'if ~/else' block. This will help me make smart decisions in various situations.
For example, I can act according to whether an asteroid is in my path or not, then when I'm met with and asteroid, I can decide whether to go under or above.", ai_hints_title_6_1: 'Radar(2)', ai_hints_content_6_1: 'How do I compare the values given by radar above and radar below?', ai_hints_detail_6_1: "([above]radar) block shows distance to an object above.
You can use this block to check which asteroid above or below exist further away.
When deciding which way to avoid the asteroid, it'll be a smarter move to go in the direction where the asteroid is further away.", ai_hints_content_7_1: 'Use the item to avoid the asteroids.', ai_hints_detail_7_1: 'Use the item to avoid the asteroids.', ai_hints_title_7_2: 'Checking object name', ai_hints_content_7_2: 'What can I do by checking the object name in front of me?', ai_hints_detail_7_2: "To gain a special item, you need to check where the item is located.
Use 'object [above] is [item]' block.
By using this block, you can figure out where the item is located and move towards it.", ai_hints_content_8_1: 'Use the item to help me avoid the asteroids.', ai_hints_detail_8_1: 'Use the item to help me avoid the asteroids.', ai_hints_title_8_2: 'Item', ai_hints_content_8_2: 'How do I gain special item and use it?', ai_hints_detail_8_2: "Even though you succeed in avoiding the asteroids, when the pathway is lined with asteroids, there is no way to avoid them. In this case, use the 'use item' block.
It will get rid of all blocks in front.
However, you can only use this block when you've gained the item by passing through the item.", ai_hints_content_9_1: 'Use all your skills and knowledge to go as far as you can.', ai_hints_detail_9_1: 'Use all your skills and knowledge to go as far as you can.', ai_hints_title_9_2: 'and', ai_hints_content_9_2: "How do I use the 'and' block?", ai_hints_detail_9_2: "and' block can fit in many conditions. When all conditions in the 'and' block is met, then the blocks will be executed. If one of them is false, the whole 'and' statement will be false and the blocks will not be executed.", maze_text_goal_1: 'Use move(); command to move me to the part box!', maze_text_goal_2: 'Use jump(); command to avoid obstacles.', maze_text_goal_3: 'Use left(); right(); command to take me to my parts.', maze_text_goal_4: 'Use various commands to take me to my parts.', maze_text_goal_5: 'Move me so I can collect both of my part boxes.', maze_text_goal_6: 'Move me so I can collect both of my part boxes.', maze_text_goal_7: 'Use for command to take me to my friend!', maze_text_goal_8: 'Use for command and avoid obstacles to take me to my friend!', maze_text_goal_9: 'Use while command to take me to my friend.', maze_text_goal_10: 'Use if and while commands to take me to all my friends.', maze_text_goal_11: 'Use if and while commands to take me to all my friends.', maze_text_goal_12: 'Use if and while commands to take me to all my friends.', maze_text_goal_13: 'Call function to take me to my battery', maze_text_goal_14: 'Call function to take me to my battery', maze_text_goal_15: 'Insert commands within function. Then call the function to take me to my battery', maze_text_goal_16: 'Insert commands under a function. Then call the function to move me to the battery!', maze_text_goal_17: 'Insert commands under a function. Then call the function to move me to the battery!', maze_text_goal_18: 'Insert commands under a function. Then call the function to move me to the battery!', maze_text_goal_19: 'Insert commands under a function. Then call the function to move me to the battery!', maze_text_goal_20: 'Call the function and mix it with other commands and take me to my battery.', maze_attack_range: 'Attack range', maze_attack: 'Attack', maze_attack_both_sides: 'Attack both sides', above_radar: 'above radar', above_radar_text_mode: 'radar_up', bottom_radar: 'bottom radar', bottom_radar_text_mode: 'radar_down', front_radar: 'front radar', front_radar_text_mode: 'radar_right', above_object: 'object above', above_object_text_mode: 'object_up', front_object: 'object in front', front_object_text_mode: 'object_right', below_object: 'object below', below_object_text_mode: 'object_down', destination: 'destination', asteroids: 'asteroids', item: 'item', wall: 'wall', destination_text_mode: 'destination', asteroids_text_mode: 'stone', item_text_mode: 'item', wall_text_mode: 'wall', buy_now: 'Buy now', goals: 'Goal', instructions: 'Instructions', object_info: 'Object info', entry_basic_mission: 'Entry basic mission', entry_application_mission: 'Entry application mission', maze_move_forward: 'move one forward', maze_when_run: 'when Run', maze_turn_left: 'turn left', maze_turn_right: 'turn right', maze_repeat_times_1: 'repeat', maze_repeat_times_2: 'times', maze_repeat_until_1: 'repeat until', maze_repeat_until_2: '', maze_call_function: 'call function', maze_function: 'function', maze_repeat_until_all_1: 'repeat until all of', maze_repeat_until_all_2: '', command_guide: 'Command guide', ai_success_msg_1: "Thanks to you I've safely arrived home!", ai_success_msg_2: 'Phew! I was able to travel ', ai_success_msg_3: 'distance enough to send a rescue signal to Earth! The rescue crew is on its way! Thank you!', ai_success_msg_4: 'Great! You succeeded using ', ai_cause_msg_1: 'Oh no. Tell me which way to go.', ai_cause_msg_2: "Yikes! That was close! Let's try again.", ai_cause_msg_3: "Yikes! I might get lost in space if I go off the path. Let's try again.", ai_cause_msg_4: "It's too complicated. Try this block to move.", ai_move_forward: 'move forward', ai_move_above: 'go above', ai_move_under: 'go under', ai_repeat_until_dest: 'repeat until destination', ai_if_front_1: 'if', ai_if_front_2: 'in front', ai_else: 'else', ai_if_1: 'if', ai_if_2: '', ai_use_item: 'use item', ai_radar: 'radar', ai_above: 'above', ai_front: 'front', ai_under: 'under', ai_object_is_1: 'is', ai_object_is_2: 'object', challengeMission: 'back', nextMission: 'next', withTeacher: 'Advisory teachers', host: 'Host', support: 'Support', subjectivity: 'Subjectivity', learnMore: 'Learn more ', ai_object_is_3: '?', stage_is_not_available: "The stage isn't available yet. Please enter the stages in the given order.", progress_not_saved: 'Your progress will not be saved.', want_refresh: 'Do you still want to refresh the page?', monthly_entry_grade: 'Elementary 3rd - Middle school 3rd grade', monthly_entry_contents: 'Learn to program with Monthly Entry. This monthly digest provides project tutorials, tips and tricks and fun comics. ', monthly_entry_etc1: "*The Monthly Entry project templates are provided in the main page's recommended course", monthly_entry_etc2: '* Monthly Entry is published during school semesters only', group_make_lecture_1: 'There are no lessons to show.', group_make_lecture_2: ' Create lessons for your class from ', group_make_lecture_3: "'Create > Create lessons'", group_make_lecture_4: 'Create a lessons', group_add_lecture_1: 'Favorite Lesson does not exist.', group_add_lecture_2: "'학습하기>오픈 강의> 강의'에서 우리반 학습내용에", group_add_lecture_3: '추가하고 싶은 강의를 관심강의로 등록해 주세요.', group_add_lecture_4: 'See Lesson', group_make_course_1: 'My courseware is not exist.', group_make_course_2: 'Create courseware for your class from', group_make_course_3: "'Create > Create lessons > Create Courseware'", group_make_course_4: 'Create courseware', group_add_course_1: 'Favorite Courseware does not exist.', group_add_course_2: 'Favorite lessons you want to add as course assignment from', group_add_course_3: "'Learn > Open Lessons > Courseware", group_add_course_4: 'Browse courseware', hw_main_title: 'Download Program', datablock_contest_title: 'Data Analysis Block', datablock_content_head: 'Process and Represent the Data', datablock_content_body1: 'Find meaning by charting various data in your life', datablock_content_body2: 'and solve real-life problems with it!', campaign_contest_title: "Let's make a beautiful internet world", campaign_content_head: 'Entry Project Contest', campaign_content_body1: "Create an originative project about 'internet ethics'", campaign_content_body2: 'and apply for the contest!', campaign_content_button: 'View details', code_management_1: 'Entry campaign #1 How to manage code', code_management_2: 'My Storage and Memo', code_management_3: 'Code management secret using my storage and memo!', code_management_4: 'Learn how to make your project better and share it easily.', code_management_5: 'View Campaigns', shcoolbook_study_1: 'Learn the contents of the textbook in entry.', shcoolbook_study_2: 'Learning Textbook', shcoolbook_study_3: 'Teachers can teach in the classroom', shcoolbook_study_4: 'and students can review at home!', shcoolbook_study_5: 'Learn now', main_learn_1: 'If you are new to Entry', main_learn_2: 'Learn about Entry', main_learn_3: 'Watch the video to learn about the various functions of Entry,', main_learn_4: 'create and share your project!', main_learn_5: 'Watch the video', hw_desc_wrapper: 'Install the Upgraded \nEntry Hardware Connection Program\nand Offline Editor', hw_downolad_link: 'Download Hardware Connection Program', save_as_image_all: 'Save code as image', save_as_image: 'Save as image', maze_perfect_success: 'Awesome! That is perfect!', maze_success_many_block_1: '좋아', maze_fail_obstacle_remain: 'Get rid of all obstacles to keep your friends from getting hurt.', maze_fail_item_remain: 'Collect all the Minerals to save Princess Sally.', maple_fail_item_remain: "I can't use my strength because I didn’t take all the food.
Help me to take all the food.", maze_fail_not_found_destory_object: "Don't waste your power on an empty space!", maze_fail_not_found_destory_monster: "Don't attack an empty space!", maple_fail_not_found_destory_monster: 'You should use the attack blocks only when there are monsters!', maze_fail_more_move: 'You have to move to the destination a little bit more!', maze_fail_wall_crash: "Ow! You can't go there!", maze_fail_contact_brick: 'Ouch... you ran into something!', maze_fail_contact_iron1: 'Ow! I hit an obstacle', maze_fail_contact_iron2: 'Ow! I was hurt because an obstacle fell on me. Move before an obstacle falls down.', maze_fail_fall_hole: 'I fell into a trap...', maze_fail_hit_unit: '몬스터에게 당해버렸어! 위험한 몬스터를 물리치기 위해 하트 날리기 블록을 사용해줘!', maze_fail_hit_unit2: 'Ow, I was attacked by a monster! You have to attack from two cells away!', maze_fail_hit_unit_by_mushroom: "The Orange Mushroom got me!
Use the Attack block to defeat the bad monsters!", maze_fail_hit_unit_by_lupin: "I got hit by Lupin!
Use the Attack block two spaces away to defeat the bad monster!", maze_fail_elnath_fail: 'Oww! A bad monster attacked me.
Defeat the bad monsters to keep them from reaching me!', maze_fail_pepe: '', maze_fail_yeti: "That monster is so strong that you can't defeat it with the Attack block.
Let's use the Attack block.", maze_fail_peti: "If you use the Attack block to attack that monster, you can't defeat the strong monsters when they spawn.
Let's use the Attack block.", maze_fail_both_side: 'You should only use the Attack on both sides if there are monsters on both sides! ', maze_wrong_attack_obstacle: "You can't use the Attack block here.
Let's use the Attack block for Orange Mushrooms.", maze_fail_contact_spider: "You're caught on a cobweb and can't move...", maze_success_perfect: 'Awesome! That is perfect!', maze_success_block_excess: 'Great! You succeeded using %1 blocks!
But you can actually get there by only using %2 blocks! How about another go at it?', maze_success_not_essential: 'Great! You succeeded using %1 blocks!
But using this block makes it easier to solve. How about another go at it?', maze_success_final_perfect_basic: 'Okay, we found where Princess Sally is! Now you can save Princess Sally!', maze_success_final_block_excess_basic: 'Great! We found where Princess Sally is! Now you can save Princess Sally! You used %1 blocks, but you can actually succeed by only using %2 blocks! Wanna try again?', maze_success_final_perfect_advanced: "You've reached the place where Princess Sally is! Now defeat the villain Mephisto and save Sally!", maze_success_final_block_excess_advanced: "You've reached the place where Princess Sally is! Now defeat the villain Mephisto and save Sally! You used %1 blocks, but you can actually succeed by only using %2 blocks! Wanna try again?", maze_success_final_distance: 'Great! We finally saved Princess Sally safe and sound. Thank you so much for helping!
You moved %1 cells. Wanna try again and aim for 60 cells?', maze_success_final_perfect_ai: 'There you go! We finally saved Princess Sally safe and sound. Thank you so much for helping!', maple_success_perfect: 'Great! That was perfect!', maple_success_block_excess: 'Great! You’ve succeeded using %1 blocks!
But there is a way to succeed with %2 blocks. Why don’t you try again?', maple_success_not_essential: "Great! You’ve succeeded using %1 blocks!
But using this block will make it easier. Why don't you try again?", maple_success_final_perfect_henesys: 'Awesome! You’ve completed the Henesys Adventure.', maple_success_final_perfect_excess_henesys: 'Awesome! You’ve completed the Henesys Adventure.
But there is a way to succeed with %2 blocks. Would you like to try again?', maple_success_final_not_essential_henesys: 'Awesome! You’ve completed the Henesys Adventure.
But using this block will make it easier. Would you like to try again?', maple_success_final_perfect_ellinia: "Wow! That was a really fun adventure!
You're going to come back for another adventure, right?", maple_success_final_perfect_excess_ellinia: 'Wow! That was a really fun adventure!
But there is a way to succeed with %2 blocks. Would you like to try again?', maple_success_final_not_essential_ellinia: 'Wow! That was a really fun adventure!
But using this block will make it easier. Would you like to try again?', maple_fail_fall_hole: "Oww! You’ve fallen down!
Let's skip using the Jump block.", maple_fail_ladder_fall_hole: "Oww! You’ve fallen down!
Let's go the other way using the Climb ladder block.", maple_fail_more_move: 'To succeed, we have to move a little bit further to the destination!', maple_fail_not_found_ladder: "Oh, there's no ladder to climb here.
You should only use the Climb ladder block where there is a ladder.", maple_fail_not_found_meat: "Oh, there's no food to take here.
You should only use Take food block where there is food.", maple_cert_input_title: 'What name do you want in the certificate?', maze_distance1: 'distance 1', maze_distance2: 'distance 2', maze_distance3: 'distance 3', ev3: 'EV3', roborobo_roduino: 'Roduino', roborobo_schoolkit: 'School Kit', smartboard: 'Sciencebox Codingboard', smartboardbt: 'Sciencebox Codingboard(Bluetooth)', codestar: 'Codestar', cobl: 'Cobl', cobl_bt: 'Cobl BT', block_coding: 'Block Coding', python_coding: 'Entry Python', dadublock: 'DaduBlock', dadublock_car: 'DaduBlock Car', blacksmith: 'Blacksmith Board', course_submit_homework: 'Submit', course_done_study: 'Complete', course_show_list: 'List', modi: 'MODI', chocopi: 'ChocoPi', coconut: 'coconut', jdkit: 'JDKit', practical_course: 'Textbook', entry_user_policy: 'Entry usage policy', entry_scholarship_title: 'Entry scholarly data', entry_scholarship_content: 'Entry collaborates with researchers to strengthen learning effectiveness. Check out our data.', entry_scholarship_content_sub: '*We provide data which is saved in the form of a sequence of processes by users participating in the Online coding party to assist in study and analysis.', entry_scholarship_download: 'Data download', codingparty_2016_title: '2016 Online coding party', codingparty_2016_content: "We provide user's active log, who played a coding mission, with whether he/she has succeeded or not, and user age, gender", codingparty_2017_title: '2017 Online coding party', scholarship_go_mission: 'Coding mission', scholarship_guide: 'Guide', scholarship_see_guide: 'Guide', scholarship_guide_desc: "It's a guide for how to read and use data.", scholarship_example: 'Example', scholarship_example_desc: 'Check out our paper by using scholarly data.', scholarship_see_example: 'Download', altino: 'Altino', private_project: 'This is a private project', learn_programming_entry_mission: 'Solving missions with EntryBot', learn_programming_line_mission: 'Saving Sally with LINE Rangers', learn_programming_choseok: 'Making a game with Cho Seok, author of "The Sound of Your Heart"', learn_programming_maple: 'Going to the Maple World with "PINK BEAN"', learn_programming_level_novice: 'easy', learn_programming_level_inter: 'normal', learn_programming_level_advanced: 'hard', line_look_for: 'Finding Sally', line_rangers_title_string: 'Learning: Line Rangers', online_codingparty_certificate_string: 'Online coding party', online_codingparty_line_title_string: 'Line Rangers', line_look_for_desc_1: 'Combine the power of the LINE Rangers and defeat the powerful villain Mephisto and save Sally!', line_save: 'Saving Sally', line_save_desc_1: "Sally is trapped at Mephisto's base. Help the LINE Rangers get to Sally by avoiding obstacles!", line_escape: 'Escaping with Sally', line_escape_desc_1: 'Help Sally and LINE Rangers escape safely from the exploding Mephisto base!', solve_choseok: 'rock-paper-scissors', solve_choseok_desc_1: 'Help Cho Seok create a rock-paper-scissors game!', solve_henesys: 'HENESYS', solve_ellinia: 'ELLINIA', solve_elnath: 'ELNATH', solve_henesys_desc_1: 'Venture into the town, and help PINK BEAN to have enough food!', solve_ellinia_desc_1: 'Venture into the forest, and fight against the bad monsters to save the good monsters!', solve_elnath_desc_1: 'Passing through the snow mountain occupied by bad monsters, go find another portal to start a new adventure!', save_modified_shape: 'You have unsaved changes.\nDo you want to save?', save_modified_table: 'Do you want to save the modified table?', attach_file: 'File', enter_discuss_title: 'Please enter the title(in 40 characters or less)', enter_discuss_title_alert: 'Please enter the title', discuss_upload_warn: 'You can only upload less than 10MB in file size', discuss_list: 'list', discuss_write_notice: 'Select this post as a notice and show it first.', discuss_write_notice_open: 'Select this post as a notice and show it first.', search_전체: 'All', search_게임: 'Game', search_애니메이션: 'Animation', search_미디어아트: 'Media Art', search_피지컬: 'Physical', search_기타: 'ETC', discuss_write_textarea_placeholer: "Entry community is a space we make together.\nLet's make a fun community with consideration for each other.", discuss_write_textarea_placeholer_qna: "This community is for Q&A.\nLet's make a fun community with consideration for each other!", discuss_write_textarea_placeholer_tips: "This community is for Tips&Tricks.\nLet's make a fun community with consideration for each other!", discuss_write_textarea_placeholer_free: "This community is for Discussion.\nLet's make a fun community with consideration for each other!", discuss_write_textarea_placeholer_report: "This community is for Suggestions.\nLet's make a fun community with consideration for each other!", discuss_write_textarea_placeholer_contest2019: '※ 아래 양식으로 작성하여 제출해주세요.\n\n1. 학년 (예: 초등학교 5학년)\n\n2. 작품 URL (‘공유하기 > 작품 공유하기’에 작품을 공유한 다음, 작품 URL을 복사하여 적어주세요.)\n\n3. 작품 설명\n\n※ 공모전 수상자에게는 이메일이 발송될 예정입니다.\n엔트리의 ‘내 정보 수정‘에 이메일 정보를 꼭 입력해주세요!', maze_road: 'road', account_deletion: 'Account deletion', bug_report_too_many_request: 'Your report is being sent. Please try again later.', pinkbean_index_title: 'Let’s head to the exciting Maple World with Pink Bean!', pinkbean_index_content: 'Pink Bean, who couldn’t stand boredom, has ventured into Maple World.
Explore the exciting Maple World with Pink Bean and fill the adventure journal.
You can learn the software while passing through each step, and you can get a certificate after you complete the mission.', rangers_index_title: 'Saving Sally with LINE Rangers!', rangers_index_content: 'LINE Rangers are combined to defeat the powerful villain Mephisto and save Sally.
Be the hero by avoiding obstacles and saving Sally through the principle of software.
You can learn about software passing through each steps and get the licence
after finishing the mission.', rangers_replay_button: 'Replay', rangers_start_button: 'Start', lms_curriculum_intro: '', lms_curriculum_goal: '', lms_curriculum_prepare: '', lms_curriculum_study: '', lms_curriculum_summary: '', lms_curriculum_quiz: '', lms_curriculum_now_stage: '', bug_report_title: 'Bug Report', bug_report_content: 'Please tell us about errors or good suggestions that you find when you use Entry.', object_import_syntax_error: 'Since the object has syntax error blocks, it cannot be loaded. Please convert into block mode to load the object.', choseok_top_wrapper_panel_title: '조석과 함께 가위바위보 게임을 만들어보세요!', choseok_top_wrapper_panel_des: '마음의 소리 웹툰이 코딩파티 미션으로 탄생했습니다.
만화속 조석이 (가위바위보 게임)을 만들어가는 과정에 참여하여 미션에
도전해 보세요.
각 단계를 통과하면서 자연스럽게 소프트웨어를 배워볼 수 있고, 미션을 모두 마치면
인증서와 나만의 게임을 얻을 수 있습니다.
', choseok_mission_statement1: '조석을 움직여보자', choseok_mission_statement2: '가위바위보를 시작해보자', choseok_mission_statement3: '가위바위보 승부를 가려보자', choseok_mission_statement4: '가위바위보 게임을 완성해보자', choseok_mission_statement5: '자유롭게 만들어보자', choseok_mission_statement_top1: '미션 1 : 조석을 움직이기', choseok_mission_statement_top2: '미션 2 : 가위바위보를 시작하기', choseok_mission_statement_top3: '미션 3 : 가위바위보 승패 만들기', choseok_mission_statement_top4: '미션 4 : 가위바위보 결과 보여주기', choseok_mission_statement_top5: '미션 5 : 자유롭게 만들어보기', advisory_title: 'Entry Advisory Group', advisory_sub_title: 'This is an advisory group including teachers and students who make Entry together.', data_table_column: 'column', data_table_row: 'row', data_table_provider: 'Source', data_table_modifidate: 'modify', draw_new_table_ques_1: 'You can enter data and save to table.', draw_new_table_ques_2: 'Do you want to move to enter data?', file_upload: 'Upload file', no_marked_project: 'There are no projects to show.', temp_save_project_study: 'Temporary save', in_progress2: 'Studying', file_upload_table_title: 'Add new table', file_upload_table_sub_title: 'You can create a table by entering data directly.', file_upload_warn_desc_table_1: 'Violent and brutal data, Sacred body exposure data, Offensive or disgusting data,', file_upload_warn_desc_table_2: 'Data of copyright prohibited from unauthorized use', table_drag_upload_title: 'Drag-and-drop or click to upload a file', table_drag_upload_desc: 'You can drag and drop CSV, XLS(X) files here or click to upload them.', upload_select_file: 'Select file', file_upload_add: 'Add', file_upload_max_size_image: 'You can only upload less than 5MB in file size.', realtime: 'Realtime', cloud: 'Cloud', }; Lang.Msgs = { microbit_led_erase_all: 'Reset', loading_plz_wait: 'Now Loading. Please Wait.', ai_utilize_audio_listening: 'Listening', ai_utilize_audio_progress: 'Recognizing', upload_error_title: 'File rejected', upload_error_content: 'Files not complying with the entry usage policy are excluded', monthly_intro_0: 'Monthly entry is an SW training magazine designed to help teachers who are unfamiliar with SW.', monthly_intro_1: 'Meet the Learning contents with fun learning cartoon!', monthly_title_0: 'Taking a dog walk / Drawing diagram', monthly_title_1: 'Create a video / Music player', monthly_title_2: 'South Korea map puzzle / Cosmos animation', monthly_title_3: 'Following fishes / Planets', monthly_title_4: 'Harvesting potatoes / Strawberry milk', monthly_description_0: "Let's make the dog that moved by your keyboard, and paint drawing project using signal and coordinate.", monthly_description_1: "Let's make the photo-movie project and music player using variable.", monthly_description_2: "Let's make the puzzle game that made of 'while' statement, and animation project using clone and random.", monthly_description_3: "Let's make fish-art and solar system using loop, math calculation blocks.", monthly_description_4: "Let's make the potato-digging and strawberry milk project using signal, variable and math calculation blocks.", save_canvas_alert: 'Currently saving.', feedback_too_many_post: 'Message sending. Please try after 10 seconds.', feedback_duplicated: 'It is already reported.', usable_object: 'Usable Object', shared_varaible: 'Shared Variable', invalid_url: 'Video URL is invalid.', auth_only: 'Authenticated users only', runtime_error: 'Runtime Error', to_be_continue: 'Still not working', warn: 'Warning', error_occured: "Oops, something went wrong. Why don't you try again? If you see this more than once, please let us know by Proposal board!", error_forbidden: 'Can not save because you are not signed in.\nPlease make sure if you haven’t signed out in another tab.\nIf you still can not save after sign in, please leave a message via ‘Suggestion’.', list_can_not_space: "List's name can't be space", sign_can_not_space: "Sign's name can't be space", variable_can_not_space: "Variable's name can't be space", training_top_title: 'Programs', training_top_desc: 'Introducing Professional Development Programs', training_main_title01: 'Instructors for your Professional Development Seminar', training_target01: 'For l Teachers', training_sub_title01: '“Give a Boost to your Classroom”', training_desc01: 'Are you looking for instructors to train your teachers?\nWe will match you with excellent instructors with knowledge and experience.', training_etc_ment01: '* Seminar are hosted and paid for by the requesting schools', training_main_title02: 'Teacher Development Program for Lead Schools', training_target02: 'For l Lead and Research Schools', training_sub_title02: '“Go, Share, and Connect”', training_desc02: 'We randomly select schools from the Lead and Research schools and provide Development Seminars for free.\nSeminars are taught by Go-to-Teacher Program teachers.', training_etc_ment02: '', training_main_title03: 'Experienced Instructors for Parent and Student seminars', training_target03: 'For l Parents, Students', training_sub_title03: '“Time to Explore Software Education”', training_desc03: 'Need instructors to introduce coding to parents and students?\nWe will match you with our instructors with knowledge and experience. ', training_etc_ment03: '* Seminar are hosted and paid for by the requesting schools', training_apply: 'Apply', training_ready: 'Ready', new_version_title: 'Install the latest version', new_version_text1: 'Current Hardware Connection Program', new_version_text2: 'is not the most updated version.', new_version_text3: 'Please install the latest version.', new_version_text4: '', new_version_download: "Download", not_install_title: 'Uninstalled', hw_download_text1: 'Install to connect hardware.', hw_download_text2: '', hw_download_text3: 'Hardware Connector Program is not installed.', hw_download_text4: 'Please install the latest version.', hw_download_btn: "Download", not_support_browser: 'Your browser is not supported.', quiz_complete1: 'Quiz is finished', quiz_complete2: "You've got {1} correct out of {0} problems", quiz_incorrect: "Let's think again", quiz_correct: "That's the answer", hw_connection_success: 'Connection Successful', hw_connection_success_desc: 'Double click the hardware icon to check sensor values', hw_connection_success_desc2: 'You can use the device in the project.', hw_connection_termination_title: 'Disconnected', hw_connection_termination_desc: 'The device has been disconnected.', hw_connection_failed_title: 'Connection Failed', hw_connection_failed_desc: 'Please make sure that\nthe device used in the project is connected.', ie_page_title: 'This browser is not supported', ie_page_desc: 'Entry is available in Internet Explorer 10 or higher or in Chrome browser.
Please update the Windows or install a Chrome browser.
Offline versions are available even though the internet is not connected. Get download now!', ie_page_chrome_download: 'Chrome
download', ie_page_windows_update: 'Windows
update', ie_page_offline_32bit_download: 'Windows 32bit
download', ie_page_offline_64bit_download: 'Windows 64bit
download', ie_page_offline_mac_download: 'Mac
download', cancel_deletion_your_account: 'Do you want to cancel the deletion of your account?', account_deletion_canceled_complete: 'Account deletion has been canceled.', journal_henesys_no1_title: 'Henesys Adventure Journal No. 1', journal_henesys_no2_title: 'Henesys Adventure Journal No. 2', journal_henesys_no1_content: "This is the first journal for Henesys. Today, I almost fell trying to jump on the way to the blacksmith’s house. He’s important in Henesys. Why did he make such a big hole in front of his yard? I don't think there’s anyone who can jump through these holes unless it's a great monster like me! let’s go to that restaurant. It’s supposed to be good!", journal_henesys_no2_content: 'I really did eat too much. The meat in that restaurant was really delicious. How could it be so tender? But the bread next door wasn’t great. The chef seemed to be always playing around, saying he’s “learning how to cook better.” He should use that time to get some more practice. Now that I’ve filled my belly, time to start a full-scale adventure!', journal_ellinia_no1_title: 'Ellinia Adventure Journal No. 1', journal_ellinia_no2_title: 'Ellinia Adventure Journal No. 2', journal_ellinia_no1_content: 'Phew, I sat on an Orange Mushroom without even knowing. I guess that’s a good reason to get mad... But piling on me was too much! They’re a scary bunch. No wonder the slimes had a hard time. No need to worry, though! Yours truly took care of it! Now that the slimes are my friends, I’m gonna continue the adventure into this gorgeous forest.', journal_ellinia_no2_content: 'My adventurous friend, Royal Fairy, told me there are some scary rumors going on around Elnath. I wonder what that is? I’m supposed to play with my friends at home tonight, so I’ll ask then. I can’t wait! But what should I wear ... I don’t think anything is going to fit because I got bigger... Well, I’m always cute, so no matter what I wear, everyone will love it!', journal_elnath_no1_title: 'Elnath Adventure Journal No. 1', journal_elnath_no2_title: 'Elnath Adventure Journal No. 2', journal_elnath_no1_content: "Oh, my gosh! So this is \"snow\" I heard so much about, huh? It's always spring where I live, so this is my first snow. I wasn't paying much attention because I was busy fighting the monsters, but now I see the whole world is so white and cold! I thought it’d be tasty, but it's flavorless. I wish I can bring some back, but there's no way. Oh, too bad.", journal_elnath_no2_content: 'Eww, I accidentally ate coal dust! Those bad monsters! Least they could do is run away quietly, but they just had to spread coal all over. Thanks to them, my shiny, fluffy pink skin is getting dirtier. I need to get out of here and take a clean bath. Adventure is nice, but no self-respecting monster should walk around looking this dirty.', bug_report_alert_msg: 'Thank you for the report.', version_update_msg1: 'You can use the latest Entry Offline version(%1).', version_update_msg2: 'You can use the latest Entry Hardware version(%1).', version_update_msg3: 'Do you want to update now?', select_the_hardware: 'Select the hardware
that you would use in the lesson.', select_hardware_button: 'Select', select_the_expansion_block: 'Select the expansion block that you would use in the lesson.', select_hardware_not_support_info: 'Hardware blocks are not available for open classes.', select_hardware_not_support_info2: 'Please wait a little bit.', select_expansion_block_button: 'Select', expansion_weather_description: 'It is a collection of blocks related to weather in Korea such as temperature, precipitation, and fine dust concentration.', expansion_festival_description: 'It is a collection of blocks related to various events and festivals by local area.', expansion_translate_description: 'It is a collection of blocks that can translate into other languages using the Papago.', expansion_behaviorConductDisaster_description: 'It is a collection of blocks about behavior-guidelines that the public should follow when natural disasters occur. (Provided by MPSS)', expansion_behaviorConductLifeSafety_description: 'It is a collection of blocks about basic behavior-guidelines that the public should follow for safty in life. (Provided by MPSS)', expansion_emergencyActionGuidelines_description: 'It is a collection of blocks about emergency action guidelines for citizens to follow in order to stay safe during natural and social disasters, as well as in everyday life.', ai_utilize_tts_description: 'It is a collection of blocks that can read text in a variety of voice using the Clova.', hardware_need_update_title: 'Entry HW update', hardware_need_update_content: "Please update to the latest version,\nif you are using below version.\nEntry website only supported v1.9.73 or later.\nPlease remove the web browser cache,\nif any block doesn't appear after updating.", ai_utilize_audio_description: 'It is a collection of blocks that recognize speech using microphone.', ai_utilize_video_description: 'It is a collection of blocks that can recognize movement, direction and object to be shot by using camera. (IE / iOS Not Supported)', cannot_delete_function: 'Function already in use.\nTo change the return value setting,\nthere must be no object with a function block.', local_variable_deletion_warning: 'If you have a local variable in use,\nthe associated block may be deleted.\nDo you really want to change it?', warning_function_aleady_being_edited: "To add a new function,\nclick 'Save' or 'Cancel' to exit\nthe Add function screen.", ai_utilize_pose_landmarker_description: 'It is a collection of blocks that detect human bodies using camera.', ai_utilize_face_landmarker_description: 'It is a collection of blocks that detect human faces using camera.', ai_utilize_object_detector_description: 'It is a collection of blocks that detect objects using camera.', ai_utilize_gesture_recognition_description: 'It is a collection of blocks that detect human hands using camera.', sound_empty1: 'Click [Add Sound] to add sound.', sound_empty2: 'How to add sound', sound_empty3: "On the 'Select sound' tab, select the default sound provided by the Entry.", sound_empty4: "On the 'Upload files' tab, upload the MP3 file directly.", sound_empty5: "You can cut only the parts you need in the 'Trim' mode, or adjust the volume, speed and pitch in the 'Adjust' mode.", sound_loading: 'Loading sound', parameter_can_not_space: "Value can't be blank.", ai_utilize_train_pop_error: 'The model applied to the project has been deactivated or deleted.', video_model_load_success: 'Load Success', video_model_load_completed: 'Video sensing enabled', ai_utilize_video_loading: 'video sensing block is now loading.
It takes up to 1 minute', }; Lang.Users = { auth_failed: 'Authentication failed', birth_year: 'Birth Year', birth_year_before_1990: 'Before 1990s', edit_personal: 'Edit Personal', email: 'Email', email_desc: 'Enter your Email address to receive newsletters', email_inuse: 'E-mail address is already in-use', email_match: 'Please enter a valid email', forgot_password: 'Forgot your password?', job: 'Job', language: 'Language', name: 'Full Name', name_desc: 'Enter your name', name_not_empty: 'You must enter your name', password: 'Password', password_desc: '', password_invalid: 'Invalid Password', password_long: 'Password must be between 4-20 characters long', password_required: 'Password can not be blank', project_list: 'Project List', regist: 'Signup Complete', rememberme: 'Remember me', repeat_password: 'Repeat Password', repeat_password_desc: 'Repeat Password', repeat_password_not_match: 'Passwords do not match', sex: 'Sex', signup_required_for_save: 'Signin required for saving a project.', username: 'Username', username_desc: 'Enter your unique name for signin', username_inuse: 'Username already taken', username_long: 'Username must be between 4-20 characters long', username_unknown: 'Unknown user', already_verified: 'Already verified', email_address_unavailable: 'The email address is unavailable.', email_address_invalid_for_idpw: "The email address is not available.\n Please try 'Find ID or Password' again to resend. ", email_address_invalid_for_certification: 'The email address is not available.\n Please verify your email again.', verification_complete: 'Verification has been completed.', reset_password_mail_sent: 'Email for password resetting has been sent. Please check your email.', email_not_verified: "This email is not verified. Please verify your email to click 'Verifying email' first.", verification_email_send_complete: 'Verifying email has been sent. Please verify your email first.', email_send_failed: 'Sending email was failed. Please try again.', email_not_exist: 'This email does not exist.', not_valid_email: 'Please enter a correct type of email.', }; Lang.Workspace = { picture_rotation: 'Rotation', picture_size: 'Size', thickness: 'thickness', follow: 'Follow', SaveWithPicture: 'You have a unsaved drawing. Do you want to save it?', RecursiveCallWarningTitle: 'Limitation of function call', RecursiveCallWarningContent: 'Too many functions were called at once. Please reduce the function calls.', check_result_value: 'Return a value', check_local_variable: 'Use local variable', local_variable: 'Local variable', local_variable_dup: 'The local variable name changed automatically because it already exists.', local_variable_rename: 'Rename completed', local_variable_rename_failed: 'Rename failed', local_variable_rename_ok: 'The local variable has been renamed.', use_block_objects1: 'Object using the function ({0} block(s))', use_block_objects2: 'Object using the function ({0})', message_too_long: 'Message name too long.', use_block_function: 'Assembled inside the function.', use_block_project: 'Block : {0}', use_blocks_project: 'Blocks : {0}', pose_landmarker_title_text: 'Human detection', face_landmarker_title_text: 'Face Detection', object_detector_title_text: 'Object detection', gesture_recognition_title_text: 'Hand detection', sound_start_point: 'Start point', sound_end_point: 'End point', sound_selection: 'Selection', sound_volume: 'Volume', sound_speed: 'Speed', sound_pitch: 'Pitch', SelectShape: 'Move', SelectCut: 'Cut', Pencil: 'Pen', Line: 'Line', Rectangle: 'Rectangle', Ellipse: 'Ellipse', Text: 'Text Box', Fill: 'Fill', Eraser: 'Eraser', Magnifier: 'Zoom in/out', block_helper: 'Block helper', new_project: 'New Project', add_object: 'Add objects', download_image_name: 'entry block', all: 'All', animal: 'Animal', arduino_entry: 'Program for connect to Arduino', arduino_program: 'Arduino program', arduino_sample: 'Sample code for Arduino', arduino_driver: 'Driver for arduino', cannot_add_object: 'Cannot add objects while running a project.', cannot_add_picture: 'Cannot add picture while running a project.', cannot_add_sound: 'Cannot add sound while running a project.', cannot_add_expansion_block: 'Cannot add expansion block while running a project.', add_object_before_edit: 'Add object firstly,\nto edit the shape.', add_table_before_edit: 'Add table.', cannot_edit_click_to_stop: 'Can not modify a project.\nClick to stop', cannot_open_private_project: "You cannot view the code of the unshared projects. Click 'OK' to move to the previous page.", cannot_save_running_project: 'Can not save while running a project.', character_gen: 'Make an avarta', check_runtime_error: 'Please check the block marked with red.', check_browser_error: 'This block is not compatible to IE/Safari', check_microphone_error: 'There is no microphone connected to the computer', check_webcam_error: 'There is no camera connected to the computer', context_download: 'Download to PC', context_duplicate: 'Duplicate', context_remove: 'Remove', context_rename: 'Rename', coordinate: 'Coord', create_function: 'Create Function', direction: 'Direction', drawing: 'Paint', enter_list_name: '', enter_name: 'Enter a new name', enter_new_message: 'Enter new message name.', enter_variable_name: 'Enter the new variable name (less than 10)', family: 'Family', fantasy: 'Fantasy/etc', file_new: 'New Project', file_open: 'Open project', file_upload: 'Upload my project', file_upload_login_check_msg: 'For the uploading your project you have to sign in', file_save: 'Save', file_save_as: 'Save as clone', file_save_download: 'Download project', func: 'Function', function_create: 'Add function', function_add: 'Add function', interface: 'Interface', landscape: 'Landscape', list: 'List', list_add_calcel: '', list_add_calcel_msg: '', list_add_fail: '', list_add_fail_msg1: '', list_add_fail_msg2: '', list_add_ok: '', list_add_ok_msg: '', list_create: 'Add list', list_create_placeholder: 'Input the name of the list.', list_dup: 'The name has been changed automatically.', list_newname: 'New name', list_export: 'Export', list_import: 'Import', list_remove: 'Remove list', list_rename: 'Rename list', list_rename_failed: 'Rename list failed', list_rename_ok: 'The name has been changed successfully.', list_too_long: 'The name cannot exceed 10 characters.', message: 'Signal', message_add_cancel: 'Canceled', message_add_cancel_msg: 'Add a message was canceled.', message_add_fail: 'Failed', message_add_fail_msg: 'Message name conflicted.', message_add_ok: 'Message added', message_add_ok_msg: 'was successfully added.', message_create: 'Add Signal', message_add: 'Add Signal', message_create_placeholder: 'Input the name of the signal', message_dup: 'Message name conflicted.', message_remove: 'Remove a message', message_remove_canceled: 'Remove a message was canceled', message_rename: 'Rename a message', message_rename_failed: 'Rename message failed', message_rename_ok: 'Successfully rename message.', no_message_to_remove: 'There is no message to remove.', no_use: 'Not assembled on object.', no_variable_to_remove: '', no_variable_to_rename: 'There is no varibale to remove', object_not_found: 'No object is specified in the block.', object_not_found_for_paste: 'There is no object to paste.', people: 'People', picture_add: 'Add Shape', table_add: 'Add Table', draw_new_table: 'New Table', plant: 'Plant', project: 'Project', project_copied: 'Copy', PROJECTDEFAULTNAME: ['Cool', 'Funny', 'Nice', 'Huge', 'Great', 'Handsome', 'Lucky'], remove_object: 'Remove Object', remove_object_msg: 'remove was successfully completed.', removed_msg: 'was successfully removed', rotate_method: 'Rotate', rotation: 'Rotation', run: 'Run', saved: 'Saved', saved_msg: 'was successfully saved.', save_failed: 'Problem occurred while saving a project. Please try again.', select_library: 'Select object', select_sprite: 'Please select at least one sprite to apply.', shape_remove_fail: 'Remove a shape was failed.', shape_remove_fail_msg: 'At least one or more shapes required.', shape_remove_ok: 'Shape Removed', shape_remove_ok_msg: 'was removed.', load_expansion_block: 'Load Expansion Block', load_ai_utilize_block: 'Load AI Block', load_ai_utilize_train_block: 'Train Model', select_expansion_block: 'Select block', deselect_expansion_block_warning: "The extension block can't be deselected because it is assembled to the project.", deselect_ai_utilize_block_warning: "The AI block can't be deselected because it is assembled to the project.", sound_add: 'Add Sound', sound_remove_fail: 'Remove a sound was failed.', sound_remove_ok: 'Sound Removed', sound_remove_ok_msg: 'was removed.', stop: 'Stop', pause: 'Pause', restart: 'Restart', speed: 'Speed', tab_attribute: 'Attribute', tab_table: 'Table', tab_code: 'Block', tab_picture: 'Shape', tab_sound: 'Sound', tab_text: 'TextBox', textbox: 'Textbox', textbox_edit: 'Edit Textbox', textbox_input: 'Please input text for apply.', things: 'Things', textcoding_tooltip1: "Instructions for 'Entry Python'
is available. Check out !", textcoding_tooltip2: 'Code with blocks or by Python
whichever you prefer.', textcoding_tooltip3: 'See Python code execution results.', upload: 'Upload files', upload_addfile: 'Add a file', variable: 'Variable', variable_add_calcel: 'Canceled', variable_add_calcel_msg: 'Add a variable was canceled.', variable_add_fail: 'Failed', variable_add_fail_msg1: 'Variable name conflicted.', variable_add_fail_msg2: 'Variable name is not proper.', variable_add_ok: 'Variable added', variable_add_ok_msg: 'was successfully added.', variable_create: 'Add variable', variable_add: 'Add variable', variable_dup: 'Variable name was already exists.', variable_newname: 'New Name', variable_remove: 'Remove variable', variable_remove_canceled: 'Remove a variable was canceled', variable_rename: 'Rename variable name', variable_rename_failed: 'Failed', variable_rename_msg: "'Rename variable was successfully completed.'", variable_rename_ok: 'Rename variabled was successfully completed.', variable_select: 'Select a variable', variable_too_long: 'Variable name too long.', open_analizy_data_import: 'Load Data Table', vehicle: 'Vehicles', add_object_alert_msg: 'Object does not exist. Please add object and try again.', add_object_alert: 'Alert', create_variable_block: 'Create variable', create_list_block: 'Add list', Variable_Timer: 'timer', Variable_placeholder_name: 'variable name', Message_placeholder_name: 'Signal name', Variable_property: 'Attribute of the variable', Variable_placeholder_content: 'Input the name of the variable.', Variable_use_all_objects: 'Use for all objects', Variable_use_this_object: 'Use for this object', Variable_used_at_all_objects: 'variable used at all objects', variable_create_normal: 'Use for variable\n(Stored in Project)', variable_create_cloud: 'Use for shared variable\n(Stored in Server)', variable_create_real_time: 'Use for real-time variable\n(Stored in Server)', Variable_used_at_special_object: 'variable used at special object', Variable_used_objects: 'Object used for the variable', draw_new: 'Draw new', draw_new_ebs: 'Draw new', painter_file: 'File ▼', painter_file_save: 'Save', painter_file_saveas: 'Save as a new shape', new_picture: 'New shape', painter_edit: 'Edit ▼', get_file: 'get', copy_file: 'Copy', cut_picture: 'cut', paste_picture: 'paste', remove_all: 'remove all', flip_horizontal: 'flip horizontal', flip_vertical: 'flip vertical', regular: 'Regular', bold: 'Bold', font_underline: 'underline', font_tilt: 'tilt', font_cancel: 'cancel', font_color: 'font color', font_fill: 'Fill', font_family: 'Font', align_left: 'left align ', align_center: 'center align', align_right: 'right align', italic: 'Italic', textStyle: 'text', add_picture: 'Add Shape', select_picture: 'Select Library', select_table: 'Select Table', load_web: 'Import table', select_sound: 'Select sound', Size: 'Size', show_variable: ' Show variable', default_value: 'default', slide: 'slide', min_value: 'min', max_value: 'max', number_of_list: 'number of list items', empty_of_list: 'No items added.', use_all_objects: 'Use for all objects', list_name: 'List name', list_property: 'Attribute of the list', list_used_specific_objects: 'List used for specific object', List_used_all_objects: 'List used for all objects', List_used_objects: 'Object used for the list', Scene_delete_error: 'The scene is, there should be at least one.', Scene_add_error: 'The scene is up to 20.', replica_of_object: "'s replicas", will_you_delete_scene: 'Deleting scene can not be restored.\nAre you sure you want to delete scene?', will_you_delete_function: 'Deleting function can not be restored.\nAre you sure you want to delete function?', duplicate_scene: 'Duplicate', block_explain: 'Block description ', block_intro: 'Clicking on the block comes the description of the block . ', blocks_reference: 'Blocks Reference', hardware_guide: 'Hardware Guide', robot_guide: 'Robot Guide', python_guide: 'Entry Python Guide', show_list_workspace: 'Show list', list_create_normal: 'Use for list\n(Stored in Project)', list_create_cloud: 'Use for shared list \n(Stored in Server)', list_create_real_time: 'Use for real-time list\n(Stored in Server)', confirm_quit: "You didn't saved your changes.", confirm_load_temporary: 'You have unsaved project. Do you want to open it?', login_to_save: 'Try to save after login.', cannot_save_in_edit_func: 'Can not save while editing function.', new_object: 'New object', arduino_connect: '', arduino_connect_success: '', confirm_load_header: 'Project Recovery', uploading_msg: 'Uploading', upload_fail_msg: 'Upload failed. Please try again.', upload_not_supported_msg: 'Not supported file type.', upload_not_supported_file_msg: 'Not supported file type.', file_converting_msg: '​File converting in process', file_converting_fail_msg: '​File conversion has failed', fail_contact_msg: 'If the problem persists,
contact entry@connect.or.kr', saving_msg: 'Saving', saving_fail_msg: 'Save failed. Please try again.', loading_msg: 'Loading', loading_fail_msg: 'Load failed. Please try again.', restore_project_msg: 'Project is not saved properly. Would you like to restore this project?', quit_stop_msg: 'Program cannot be closed during save.', ent_drag_and_drop: 'Drag and drop the file to upload', not_supported_file_msg: 'This file format is not supported', broken_file_msg: 'File is corrupt or wrong file is loaded', check_audio_msg: 'Not supported file type.', check_entry_file_msg: 'Only ENT files are loadable', hardware_version_alert_text: 'Please update your hardware connector to the latest version.', variable_name_auto_edited_title: 'variable name auto-edited', variable_name_auto_edited_content: 'variable name cannot exceed 10 characters', list_name_auto_edited_title: 'list name auto-edited', list_name_auto_edited_content: 'list name cannot exceed 10 characters', list_cant_add_item: 'Warning', list_max_length_exceeded: 'You can add up to 5,000 items to a list.', list_truncated_on_load: 'The number of list items in this project exceeds 5,000, so some may not be displayed.\n\nFor stable use,\nplease reduce the list to 5,000 or fewer.', list_truncated_on_load_title: 'Notice', cloned_scene: 'Cloned_', default_mode: 'Standard', practical_course_mode: 'Textbook', practical_course: 'practical course', select_mode: 'Mode', select_mode_popup_title: "Choose 'Create' option", select_mode_popup_lable1: 'Standard', select_mode_popup_lable2: 'Textbook(Practical Course)', select_mode_popup_desc1: 'Create projects with
unlimited Entry features', select_mode_popup_desc2: "Create projects using
'Practical Course' features", practical_course_notice: 'Notice', practical_course_desc: "교과용 만들기
실과 교과서로 소프트웨어를 배울 때
필요한 기능만을 제공합니다.", practical_course_desc2: '*기본형 작품 만들기를 이용하면 더 많은 기능을
이용해 작품을 만들 수 있습니다.', practical_course_tooltip: '모든 기능을 이용하기 위해서는
기본형을 선택해 주세요.', name_already_exists: 'The name already exists.', enter_the_name: 'Please enter the name.', object_not_exist_error: 'Object does not exist. Please add object and try again.', workspace_tutorial_popup_desc: "작품 만들기
창의적인 작품을 만들 수 있도록
다양한 블록과 기능을 제공합니다.", start_guide_tutorial: 'Creating Guide', language: 'language', file: 'file', save: 'save', help: 'help', print: 'print', undo: 'undo', redo: 'redo', workspace_title_tooltip: 'The default project name has changed. You can\nrecognize what project is through the date you create in\nthe project name.', workspace_object_tooltip: 'You can change the order of the object by\ndragging the image of the object. (It is the same\nin the ‘Shape’ and ‘Sound’ sections.)', workspace_comment_tooltip: 'You can hide or show all the memos\nadded.', workspace_zoom_tooltip: 'You can zoom in/out the blocks. If you click ‘=’\nthe block will be back to original size.', workspace_image_tooltip: 'Create your own\nproject with new\nfunctions!', playground_block_drop: 'Add the blocks in my storage\nto assembly station', container_object_drop: 'Add the object in my storage\nto object list', my_storage_block_drop: 'Add\nthe blocks\nto my storage', my_storage_object_drop: 'Add\nthe object\nto my storage', my_storage: 'My storage', my_block: 'My Block', red: 'Red', green: 'Green', blue: 'Blue', hue: 'Hue', saturation: 'Saturation', brightness: 'Brightness', spoid: 'Spoid', palette_mode: 'Palette mode', slider_mode: 'Slider mode', toast_error_title_object_center: 'Caution', toast_error_contents_object_center: 'If the center point is far from the object and goes out of the canvas, it returns to its original position.', blocks_comming_soon: "I'm working hard.\nPlease wait a little longer!", data_table: 'table', select_all: 'Select all', now_loading_msg: 'Now Loading.\nPlease Wait.', font_textblock_strikethrough: 'Strikethrough', font_textblock_underline: 'Underline', font_textblock_italic: 'Italic', font_textblock_bold: 'Bold', function_attribute: 'Attribute', variable_default_value: 'Default value', list_default_value: 'Default value', func_property: 'Attribute of the function', bring_forward: 'Bring Forward', send_backward: 'Send Backward', upload_error_msg: 'Unable to upload as image is suspected of violating usage policy.', confirm_firmware_hwlite_block_title: 'Verify firmware Installation', confirm_firmware_hwlite_block_msg: 'To use %1 in Entry,\n please install the firmware first.', confirm_firmware_hwlite_block_pass: 'Already installed', confirm_firmware_hwlite_block_download: 'Install firmware', confirm_firmware_hwlite_block_usb_connect: 'USB connect', progress_firmware_hwlite_title: 'Install firmware', progress_firmware_hwlite_step1_title: 'Check USB port', progress_firmware_hwlite_step1_content1: 'Connect the device and PC with USB.', progress_firmware_hwlite_step1_content2: 'Select the device to connect.\nWait for a USB connection.', progress_firmware_hwlite_step1_content3: 'USB connection detected.', progress_firmware_hwlite_step2_title: 'Install firmware', progress_firmware_hwlite_step2_content1: 'Installing firmware.\nPlease wait.', progress_firmware_hwlite_step2_content_complete: 'Installation is complete.', progress_firmware_hwlite_step2_content_fail: 'Firmware installation failed.', progress_firmware_hwlite_step2_content_select: 'Select the firmware version to install.', progress_firmware_hwlite_button_select: 'Check', progress_firmware_hwlite_button_reselect: 'Retry', progress_firmware_hwlite_button_install: 'Install firmware', progress_firmware_hwlite_button_connect_device: 'Connect device', progress_firmware_hwlite_button_retry: 'Retry', usbconnect_fail_alert: "USB connection failed. Check the connection status and click 'Retry'.", select_hwlite_block_duplicated: 'Please select only one hardware device.', select_hwlite_block_none: 'Please select the hardware device to connect.', select_firmware_hwlite_title: 'Download Firmware', select_firmware_hwlite_content: 'Please download and install the appropriate firmware \n for your hardware version.', select_flash_firmware_hwlite_title: 'Select firmware to install', select_flash_firmware_hwlite_content: 'Please select the version of\n the Microbit you want to connect to.\n When the installation is complete,\n a message is displayed.', flash_firmware_success: 'Firmware installation is complete.', flash_firmware_failed: 'Firmware installation failed. Please try again.', }; Lang.code = 'view code'; Lang.EntryStatic = { event100: 'Event', groupProject: 'open group', usage_parallel: 'Parallel', usage_expansion: 'Expansion', usage_hw: 'Hardware', usage_sequence: 'Sequence', privateProject: 'only owner', privateCurriculum: 'only owner', publicCurriculum: 'curriculum share', publicProject: 'project share', group: 'share to group', groupCurriculum: 'open group', private: 'only owner', public: 'open lessons', lecture_is_open_true: 'open', lecture_is_open_false: 'closed', category_all: 'All Categories', category_game: 'Game', category_animation: 'Animation', category_media_art: 'Media Art', category_physical: 'Physical', category_etc: 'etc', category_category_game: 'Game', category_category_animation: 'Animation', category_category_media_art: 'Media Art', category_category_physical: 'Physical', category_category_etc: 'etc', sort_created: 'By Latest', sort_updated: 'By Latest', sort_visit: 'By Viewers', sort_likeCnt: 'By Likes', sort_comment: 'By Comments', period_all: 'Entire period', period_1: 'Today', period_7: 'Latest 1 week', period_30: 'Latest 1 month', period_90: 'Latest 3 months', lecture_required_time_1: 'Less than 15 min.', lecture_required_time_2: '15 to 30 min.', lecture_required_time_3: '30 to 45 min.', lecture_required_time_4: '45 to 60 min', lecture_required_time_5: 'over 1 hour', usage_event: 'Event', usage_signal: 'Signal', usage_scene: 'Scene', usage_repeat: 'Repeat', usage_condition_repeat: 'Condition repeat', usage_condition: 'Condition', usage_clone: 'Cloned Object', usage_rotation: 'Rotation', usage_coordinate: 'Coordinate', usage_arrow_move: 'Arrow move', usage_shape: 'Shape', usage_speak: 'Speak', usage_picture_effect: 'Effect', usage_textBox: 'Textbox', usage_draw: 'Draw', usage_sound: 'Sound', usage_confirm: 'Confirm', usage_comp_operation: 'Compare operation', usage_logical_operation: 'Logical operation', usage_math_operation: 'Math operation', usage_random: 'Random', usage_timer: 'Timer', usage_variable: 'Variable', usage_list: 'List', usage_ask_answer: ' Input/Output', usage_function: 'Function', usage_arduino: 'Arduino', concept_resource_analytics: 'Procedual Thinking', concept_procedual: 'Abstractive Thinking', concept_abstractive: 'Korean', concept_individual: 'English', concept_automation: 'Automation', concept_simulation: 'Simulation', concept_parallel: 'Parallel', subject_korean: 'Korean', subject_english: 'English', subject_mathmatics: 'Mathmatics', subject_social: 'Social', subject_science: 'Science', subject_music: 'Music', subject_paint: 'Paint', subject_athletic: 'Athletics', subject_courtesy: 'Courtesy', subject_progmatic: 'Progmatic', lecture_grade_1: '1 th', lecture_grade_2: '2 th', lecture_grade_3: '3 th', lecture_grade_4: '4 th', lecture_grade_5: '5 th', lecture_grade_6: '6 th', lecture_grade_7: '7 th', lecture_grade_8: '8 th', lecture_grade_9: '9 th', lecture_grade_10: 'Graduated', lecture_level_1: 'Low', lecture_level_2: 'Middle', lecture_level_3: 'High', listEnable: 'list', functionEnable: 'function', messageEnable: 'message', objectEditable: 'object', pictureeditable: 'shape', sceneEditable: 'scene', soundeditable: 'sound', variableEnable: 'variable', e_1: 'elementary school 1', e_2: 'elementary school 2', e_3: 'elementary school 3', e_4: 'elementary school 4', e_5: 'elementary school 5', e_6: 'elementary school 6', m_1: 'middle school 1', m_2: 'middle school 2', m_3: 'middle school 3', general: 'general', curriculum_is_open_true: 'open', curriculum_open_false: 'closed', contest2019: 'Contest', exhibit: 'Contest', notice: 'Notice', qna: 'Q&A', tips: 'Tips & Tricks', free: 'Discussions', report: 'Suggestions', art_category_all: 'All projects', art_category_game: 'Games', art_category_animation: 'Animation', art_category_physical: 'Physical', art_category_etc: 'etc', art_category_media: 'media art', art_sort_updated: 'Most Recent', art_sort_visit: 'Views', art_sort_likeCnt: 'Likes', art_sort_comment: 'Comments', art_period_all: 'All', art_period_day: 'Today', art_period_week: 'Recent week', art_period_month: 'Recent month', art_period_three_month: 'Recent three month', level_high: 'Row', level_mid: 'Middle', level_row: 'High', discuss_sort_created: 'Most Recent', discuss_sort_visit: 'Views', discuss_sort_likesLength: 'Likes', discuss_sort_commentsLength: 'Comments', discuss_period_all: 'All', discuss_period_day: 'Today', discuss_period_week: 'Recent week', discuss_period_month: 'Recent month', discuss_period_three_month: 'Recent three month', art_category_living: 'Living Supplies', art_category_storytelling: 'Storytelling', art_category_arts: 'Arts', art_category_knowledge: 'Knowledges', art_period_today: 'Today', art_period_quarter: 'Recent 3 months', }; Lang.Helper = { when_run_button_click: 'When the Start button is clicked, the connected blocks below will run.', when_some_key_pressed: 'When the assigned key is pressed, the connected blocks below will run.', mouse_clicked: 'When the mouse is clicked, the connected blocks below will run.', mouse_click_cancled: 'When the mouse click is released, the connected blocks below will run.', when_object_click: 'When the object is clicked, the connected blocks below will run.', when_object_click_canceled: 'When the object click is released, the connect blocks below will run.', when_message_cast: 'When the signal is received, the connected blocks below will run.', message_cast: 'Sends signal selected from the list', message_cast_wait: 'Sends signal selected from the list, and wait util the blocks finish running.', when_scene_start: 'When the scene starts, the connected blocks below will run.', start_scene: 'Selected scene starts.', start_neighbor_scene: 'The previous or the next scene starts.', wait_second: 'Runs the next block after waiting for the entered amount of time.', repeat_basic: 'Repeats the blocks inside for the entered number of times.', repeat_inf: 'Repeats the blocks inside infinitely.', repeat_while_true: 'Repeats the blocks inside until/while the condition is True/False. ', stop_repeat: "Stops the closest block that encloses this block.\n It works with various C-shaped blocks like 'repeat' block.", continue_repeat: 'Skip this repeat and run it from the beginning of the next repeat.', _if: 'If the condition is True/False, run the blocks inside.', if_else: "If the condition is True/False, run the blocks inside the 'if' section.\nIf not, run the blocks inside the 'else' section.", restart_project: 'The project restarts.', stop_object: 'All objects : Stops all the blocks of all the objects.\nThis : Stop all the blcoks of this object.\nThis code : Stop all the blocks that includes this block.\nOther block of this object : Stop the blocks not connected to the blocks of this object.\nOther object : Stop all the blocks of the other objects.', wait_until_true: 'Stops running and wait until the condition is True/False.', when_clone_start: 'When the new clone of the object is created, the connected blocks below will run.', create_clone: 'Self : Create the clone of this object.\nEntrybot : Create the clone of Entrybot.', delete_clone: "Removes the clone of this object using with 'When clone is created'.", remove_all_clones: 'Removes all the clones of this object.', move_direction: 'Moves in the direction of the arrow by input value.', move_x: 'Changes the x-postion of the object by the input value.', move_y: 'Changes the y-postion of the object by the input value.', move_xy_time: 'Changes the x and y-postion of the object by input value for the input seconds.', locate_object_time: 'Moves the object to the position of the selected object for the input seconds.', locate_x: 'Moves the object to the entered x-position.', locate_y: 'Moves the object to the entered y-position.', locate_xy: 'Moves the object to the entered x and y-position.', locate_xy_time: 'Moves the object to the entered x and y-position for the input seconds.', locate: 'Moves the object to the position of the selected object.', rotate_absolute: 'Sets the rotation of the object at an angle of the input degrees.', rotate_by_time: 'Rotates the object at an angle of the input degrees for the input seconds.', rotate_relative: 'Rotates the object at an angle of the input degrees.', direction_absolute: 'Sets the direction of the object at an angle of the input degrees.', direction_relative: 'Changes the direction of the object at an angle of the input degrees.', move_to_angle: 'Moves the object by the input value in the direction of the input degrees.', see_angle_object: 'Turns the object toward the selected object.', bounce_wall: 'When object touches the edge of the screen, it bounces back.', show: 'Makes the object show on the screen.', hide: 'Hides the object from the screen.', dialog_time: 'Runs the next block after the object speaks the input content for the input seconds.', dialog: 'Runs the next block after the object speaks the input content.', remove_dialog: 'Removes the speech bubble spoken and thought by the object.', change_to_some_shape: 'Changes the object to the selected shape.\nYou can select shape by entering shape name or shape number.', change_to_next_shape: 'Changes the object to the next/previous shape.', set_effect_volume: 'Applies the selected effect to the object by the input value.', set_effect_amount: 'Applies the selected effect to the object by the input value.', set_effect: 'Sets the selected effect to the object by the input value.', set_entity_effect: 'Sets the selected effect to the object by the input value.', add_effect_amount: 'Applies the selected effect to the object by the input value.\n\n- Color: 1~100.\n- Brightness: It can be set it in the range of -100 to 100.\n- Transparency: It can be set in the range of 0 to 100.', change_effect_amount: 'Sets the selected effect to the object by the input value.\n\n- Color: 1~100.\n- Brightness: It can be set it in the range of -100 to 100.\n- Transparency: It can be set in the range of 0 to 100.', change_scale_percent: 'Changes the size of the object by the input value.', set_scale_percent: 'Sets the size of the object to the input value.', change_scale_size: 'Changes the size of the object by the input value.', set_scale_size: 'Sets the size of the object to the input value.', stretch_scale_size: 'Stretches the width/length of the object by the input value.', reset_scale_size: 'Resets the object to its original size.', flip_x: 'Flips the object vertically. ', flip_y: 'Flips the object horizontally.', change_object_index: 'Brings objects forward or backward on the screen.\n- Front : Bring object to the very front.\n- Forward : Bring object one layer front.\n- Backward : Send object one layer back.\n- Back : Send object the very back.', set_object_order: 'Shows the object in the set order.', brush_stamp: 'Clones the object on stage like a stamp.', start_drawing: 'Starts drawing along the path of the object.', stop_drawing: "Stops object's drawing.", start_fill: 'Starts filling along the path of the object.', stop_fill: 'Stops filling.', set_color: 'Sets the brush color of the object to the selected color.', set_random_color: 'Sets the brush color of the object to random.', set_fill_color: 'Sets the fill color of the object to the selected color.', change_thickness: 'Changes the brush thickness of the object to the input value.', set_thickness: 'Sets the brush thickness of the object to the input value.', change_opacity: 'Changes the brush transparency of the object to the input value.', change_brush_transparency: 'Changes the brush transparency of the object to the input value.', set_opacity: 'Sets the brush transparency of the object to the input value.', set_brush_tranparency: 'Sets the brush transparency of the object to the input value.', brush_erase_all: 'Removes all the brush effects on the object.', sound_something_with_block: "Plays object's selected sound while the next block runs.", sound_something_second_with_block: "Plays object's selected sound for input seconds while the next block runs.", sound_something_wait_with_block: "Plays object's selected sound and then runs the next block.", sound_something_second_wait_with_block: "Plays object's selected sound for the input seconds and then runs the next block.", sound_volume_change: 'Changes the volume of all sounds by the input value.', sound_volume_set: 'Sets the volume of all sounds to the input value.', get_sound_speed: 'Reports the sound speed.', sound_speed_change: 'Changes the speed of all sounds by the input value.', sound_speed_set: 'Sets the speed of all sounds to the input value.', sound_silent_all: 'Stops the selected sound.', play_bgm: 'Plays selected sound as background music while the next block runs.', stop_bgm: 'Stops background music', is_clicked: 'Checks whether mouse is clicked.', is_object_clicked: 'Checks whether object is clicked.', is_press_some_key: 'Checks whether the selected key is pressed.', reach_something: "Checks whether the object touches the selected item. If the object touches the selected item, it is judged as 'True'.", is_type: 'Checks whether the input text consists of the selected characters. If the input text consists of the selected characters, it is judged as `True`.', is_included_in_list: 'Checks whether selected list contains the input value.', boolean_basic_operator: "Compare the two values entered.\n= : If the value on the left and the value on the right are the same, it is judged as 'true'.\n!= : If the value on the left and the value on the right are not the same, it is judged as 'true'.\n> : If the value on the left is more than the value on the right, it is judged as 'true'.\n< : If the value on the left is less than the value on the right, it is judged as 'true'.\n≥ : If the value on the left is more than or equal to the value on the right, it is judged as 'true'\n.≤ : If the value on the left is less than or equal to the value on the right, it is judged as 'true'.", function_create: 'Define a function by placing frequently used sets of blocks under this block. Place [name] next to [Define function] to give function a name. Pass on number of text values by placing [numeric/text value] block. Pass on boolean value of true or false by placing the [boolean value] block.', function_field_label: 'Place inside the [Define function] block and gives function a name.', function_field_string: 'Place inside the [Define function] block and the result depends on the input numeric/text value. Grab/copy the [numberic/text value] block in the [Define function] block and use its value in function.', function_field_boolean: 'Place inside the [Define function] block and the result depends on the boolean value of true or false. Grab/copy the [numberic/text value] block in the [Define function] block and use its value in function.', function_general: 'This is current function block or function blocks created so far.', boolean_and: 'Checks whether both conditions are true.', boolean_or: 'Checks whether at least one of the two conditions is true.', boolean_not: "Changes the input conditions to its opposite.\n(If the input condition is true, it returns 'False'. And if the input condition is false, it returns 'True'.)", is_boost_mode: "Checks whether the boost mode is turned on or not.\nIf the boost mode is on, it is judged as 'True'.", is_current_device_type: "If the device that runs the project is the selected device, it is judged as 'true'.", is_touch_supported: "If the device that runs the project is a touch screen, it is judged as 'true'.", calc_basic: 'Reports the value of the two input numbers of quadratic operations.\n+ : Adds two input numbers.\n- : Subtracts two input numbers.\n* : Multiplies two input numbers.\n/ : Divides two input numbers.', calc_rand: 'Selects a random value between the two input numbers. (If both of the input numbers are integers, an integer between the two numbers is selected. If either the input number is a decimal value a number up to the second decimal place is selected.)', get_x_coordinate: 'Reports the x-position value of the object.', get_y_coordinate: 'Reports the y-position value of the object.', coordinate_mouse: 'Reports either the x/y coordinate value of the mouse pointer.', coordinate_object: 'Reports the x/y coordinate value or various information (rotation, direction, size, etc.) of the object.', quotient_and_mod: 'Reports the result of dividing the two input numbers.\n- Quotient: The answer after dividing the first input number by the second input number.\n- Remainder: The amount left over after division.', get_rotation_direction: 'Reports the object’s value of direction and value of movement.', calc_share: 'Reports the quotient occurring from first number divided by the second number. ', calc_mod: 'Reports the remainder occurring from the first number divided by the second number.', calc_operation: 'Reports calculated values of a variety of equations relating to input numbers.\n(Square, Root, Sine, Cosine, Tangent, Arcsine, Arccosine, Arctangent, Log, Natural log, Decimal value, Floor value, Ceil value, Round value, Factorial value, Absolute value)', get_date: 'Reports the values regarding the current year, month, day, day of the week and time.\n- Year: Returns the current year.\n- Month: Returns the current month.\n- Day: Returns the current day.\n- Day of the week: Returns the current day of the week as a number.\nReturns Sunday, Monday, Tuesdays, Wednesdays, Thursdays, Fridays, Saturdays as 0, 1, 2, 3, 4, 5, 6 in turn.\n- Time: Returns the current time in hours, minutes, and seconds, respectively.', distance_something: 'Reports the distance between the object and the selected object.', get_sound_duration: 'Reports the time length of the selected sound.', get_user_name: 'Reports the user ID who runs the project.\nThe value is masked for privacy.', get_nickname: 'Reports the user nickname who runs the project.', get_project_timer_value: 'Reports how many seconds have passed since the project started.', choose_project_timer_action: 'Sets the status of the timer.\n- Start : The timer starts.\n- Stop : The timer stops.\n- Reset : The timer resets to 0.', reset_project_timer: 'Resets the timer to 0.', set_visible_project_timer: 'Shows or hides the timer.', ask_and_wait: 'The object asks the input text, and then receives an answer as a response.', get_canvas_input_value: 'Reports the answer which is taken after the object asked.', set_visible_answer: 'Hide or show the response window.', combine_something: 'Combines two input texts.', reverse_of_string: 'Reports the text that reversed input text.', get_variable: 'Reports the value of the selected variable.', change_variable: 'Adds the input value to the selected variable.', set_variable: 'Sets the value of the selected variable to the input value.', robotis_carCont_sensor_value: "Left connected sensor : the value of contact (1), non-contact (0).
Right contact sensor: the value of contact (1), non-contact (0).
Final number of sound detection : the value of the number of last live sound detection.
Number of live sound detection : increases by 1 when it detects the next sound within 1 second.
Right infrared sensor: the value is larger when it's closer to an object.
Value of left infrared sensor calibration : the calibration value of the infrared sensor.
Value of right infrared sensor calibration : the calibration value of the infrared sensor.
(*Calibration value - control value of infrared sensor)", robotis_carCont_cm_led: 'Turns LED 1 or LED 4 among the 4 LEDs on or off.
Not applicable to LED 2 and LED 3.', robotis_carCont_cm_sound_detected_clear: 'Initializes the final amount of detected sound to 0.', robotis_carCont_aux_motor_speed: 'Sets the speed of decelerating motor to the value of 0-1023.', robotis_carCont_cm_calibration: 'Sets the controlling value of infrared sensor (http://support.robotis.com/ko/: automobile robot> 2. B. control infrared value).', robotis_openCM70_sensor_value: 'Final number of sound detection : the value of the final detected sound times.
Number of live sound detection : increases by 1 when it detects the next sound within 1 second.
Status of user button: the value of contact (1), non-contact (0).Final number of sound detection : the value of the number of last live sound detection.
Number of live sound detection : increases by 1 when it detects the next sound within 1 second.
Status of user button : the value of contact (1), non-contact (0).', robotis_openCM70_aux_sensor_value: "Position of servo motor: 0-1023, the value of the middle is 512.
Infrared sensor : the value is larger when it's close to an object.
Contact sensor: the value of contact(1), non-contact(0).
CDS: 0-1023, the value is larger when it's brighter.
Temperature-humidity sensor (humidity) : 0-100, the value is larger when it's more humid.
Temperature-humidity sensor (temperature) : -20 - 100, the value is larger when it's higher in temperature.
Temperature sensor : -20 - 100, the value is larger when it's higher in temperature.
Ultrasound sensor: -
Magnetic sensor : the value of contact(1), non-contact(0).
Motion detector: the value of detected motion(1), non-detected motion(0).
Color sensor: the value of unknown(0), white(1), black(2), red(3), green(4), blue(5), yellow(6).
User device: please refer to ROBOTIS e-manual (http://support.robotis.com/ko/) for the explanation on user sensor production.", robotis_openCM70_cm_buzzer_index: 'Plays the scale for 0.1 to 5 seconds.', robotis_openCM70_cm_buzzer_melody: "Plays melody.
If the following sound doesn't play when repeatedly playing melodies, use the block 'flow > wait for X seconds' and execute it again.", robotis_openCM70_cm_sound_detected_clear: 'Final number of sound detection ', robotis_openCM70_cm_led: 'Turns the red, green, blue LED of the device on or off.', robotis_openCM70_cm_motion: 'Executes the motion downloaded on the device.', robotis_openCM70_cm_autodrive_motor: 'Specifies the motor port of the autonomous driving car.', robotis_openCM70_cm_autodrive_ir: 'Specifies the IR sensor port of the autonomous driving car.', robotis_openCM70_cm_autodrive_speed: 'Perform autonomous driving at the specified speed along the lane.', robotis_openCM70_aux_car_move: 'Make the robot move at the specified speed and direction.', robotis_openCM70_aux_motor_speed: 'Sets the speed of decelerating motor to the value of 0 - 100%.', robotis_openCM70_aux_servo_mode: "Sets the servo motor as wheel mode or joint mode.
The same mode continues to apply once it's set.
Wheel mode designates the servo motor's speed, and spins the servo motor.
Joint mode moves the servo motor's position with the set servo motor speed.", robotis_openCM70_aux_servo_speed: "Sets servo motor's speed to the value of 0 - 1023.", robotis_openCM70_aux_servo_position: "Sets servo motor's position to the value of -150 - 150 degree.
Use as servo motor speed", robotis_openCM70_aux_led_module: 'Turns the LED of LED module on or off.', robotis_openCM70_aux_custom: 'Please refer to the ROBOTIS e-manual (http://support.robotis.com/ko/) for the explanation of user sensor production.', robotis_openCM70_cm_poweroff_timer: "Set the controller's auto-off timer.
If there is no communication for the set amount of time, the controller will automatically turn off.", robotis_openCM70_cm_custom_value: 'Checks the value by directly inputting the control table address.
Please refer to the ROBOTIS e-manual (http://support.robotis.com/ko/) for the explanation about control table.', robotis_openCM70_cm_custom: 'Checks the value by directly inputting the control table address.
Please refer to the ROBOTIS e-manual (http://support.robotis.com/ko/) for the explanation about control table.', show_variable: 'Shows the value of the selected variable on the stage.', hide_variable: 'Hides the value of the selected variable from the stage.', value_of_index_from_list: 'Reports the item at the location of the input value on the selected list.', add_value_to_list: 'Adds the input item to the end location of the selected list.', remove_value_from_list: 'Deletes the item at the location of the input value from the selected list. ', insert_value_to_list: 'Inserts the input item at the location of the input value on the selected list.', change_value_list_index: 'Replaces the item at the location of the input value to the input text.', length_of_list: 'Reports the number of items contained on the selected list.', show_list: 'Shows the selected list on the stage.', hide_list: 'Hides the selected list from the stage.', text: 'Reports the text in the text box. ', text_read: 'Reports the content of the text box or the text box itself.\n(If there is a line break in the content, it will be returned as a space.)', text_write: 'Changes the content of the text box into the input text.', text_append: 'Adds the input text behind the text box.', text_prepend: 'Adds the input text in front of the text box.', text_flush: 'Removes all saved text in the text box.', erase_all_effects: 'Removes all the effects on the object.', char_at: 'Reports the letter of the input text.', length_of_string: 'Reports the length of input text including space.', substring: 'Reports the text extracted from the input text between two specified indices. (includes space)', count_match_string: 'Reports the number of letters in a specific text in the input text case sensitively.', replace_string: 'Reports the text where the specific text has been replaced with the input text. (distinguishes uppercase and lowercase)', index_of_string: 'Reports the index of first input text in second input text. (includes space)', change_string_case: 'Reports the text that converted to uppercase or lowercase.', get_block_count: 'Reports the number of blocks used by the selected item.\nCounts based on the blocks assembled to the start block.\n- this project: Counts all the blocks of this project\n- this object: Counts the blocks of this object\n- (object): Counts the blocks of the selected object\n- (scene): Counts the blocks of the selected scene', get_boolean_value: 'Returns boolean to string.', direction_relative_duration: 'Rotates the direction of the object at an angle of the input degrees for the input seconds.', get_sound_volume: 'Reports the sound volume.', sound_from_to: "Plays object's selected sound between the input seconds while the next block runs.", sound_from_to_and_wait: "Plays object's selected sound between the input seconds and then runs the next block.", Block_info: 'Block Info ', Block_click_msg: 'Clicking on the block comes the description of the block . ', hamster_beep: 'Plays beep sound.', hamster_change_both_wheels_by: 'Adds the entered values to the current speed values (%) of the left and right wheels respectively. If the result is positive, the wheel rotates forward; if negative, the wheel rotates backward.', hamster_change_buzzer_by: 'Adds the entered value to the current pitch (Hz) of the buzzer sound. You can enter up to two decimal places.', hamster_change_output_by: 'Adds the entered value to the current output value of the selected external port. The result will be in the following range depending on the mode of the external port.
Servo output: valid range from 1 to 180 degrees; if 0, output 0 without PWM pulse
PWM output: 0 to 100%, duty ratio (%) of ON state in PWM waveform
Digital output: LOW when 0, otherwise HIGH', hamster_change_tempo_by: 'Adds the entered value to the current BPM (beats per minute) of the playing or resting speed.', hamster_change_wheel_by: 'Adds the entered value to the current speed value (%) of the left/right/both wheels. If the result is positive, the wheel rotates forward; if negative, the wheel rotates backward.', hamster_clear_buzzer: 'Turns off buzzer sound.', hamster_clear_led: 'Turns off the left/right/both LEDs.', hamster_follow_line_until: 'Moves along the black/white line on the left/right/front/back, then stops when the robot meets the intersection.', hamster_follow_line_using: 'Moves along the black/white line by using the left/right/both floor sensors.', hamster_hand_found: 'If there is a hand or object in front of the proximity sensor, true, otherwise false', hamster_move_backward_for_secs: 'Moves backward for the number of seconds entered.', hamster_move_forward_for_secs: 'Moves forward for the number of seconds entered.', hamster_move_forward_once: 'Moves one space forward on the board.', hamster_play_note_for: 'It sounds the selected tone and octave as much as the beat you entered.', hamster_rest_for: 'Rests as much as the beat you entered.', hamster_set_both_wheels_to: 'Sets the speed of the left and right wheels to the entered values (-100 to 100%), respectively. If you enter a positive value, the wheel rotates forward. If you enter a negative value, the wheel rotates backward. Entering the number 0 stops it.', hamster_set_buzzer_to: 'Sets the pitch of the buzzer sound to the entered value (Hz). You can enter up to two decimal places. Entering the number 0 turns off the buzzer sound.', hamster_set_following_speed_to: 'Sets the speed (1 to 8) to move along the line. The larger the number, the faster the movement.', hamster_set_led_to: 'Turns left/right/both LEDs to the selected color.', hamster_set_output_to: 'Sets the output value of the selected external port to the entered value. The value has the following range according to the mode of external port.
Servo output: valid range from 1 to 180 degrees; if 0, output 0 without PWM pulse
PWM output: 0 to 100%, duty ratio (%) of ON state in PWM waveform
Digital output: LOW when 0, otherwise HIGH', hamster_set_port_to: 'Sets the io mode of the selected external port to the selected mode.', hamster_set_tempo_to: 'Sets the playing or resting speed to the entered BPM (beats per minute).', hamster_set_wheel_to: 'Sets the speed of the left/right/both wheels to the entered value (-100 to 100%). If you enter a positive value, the wheel rotates forward. If you enter a negative value, the wheel rotates backward. Entering the number 0 stops it.', hamster_stop: 'Stops both wheels.', hamster_turn_for_secs: 'Turns left/right for the number of seconds entered.', hamster_turn_once: 'Turns left/right 90 degrees on the board.', hamster_value: 'left proximity: value of left proximity sensor (range: 0 to 255, initial value: 0)
right proximity: value of right proximity sensor (range: 0 to 255, initial value: 0)
left floor: value of left floor sensor (range: 0 to 100, initial value: 0)
right floor: value of right floor sensor (range: 0 to 100, initial value: 0)
x acceleration: x-axis value of acceleration sensor (range: -32768 to 32767, initial value: 0) The direction in which the robot moves forward is the positive direction of the x axis.
y acceleration: y-axis value of acceleration sensor (range: -32768 to 32767, initial value: 0) The left direction of the robot is the positive direction of the y axis.
z acceleration: z-axis value of acceleration sensor (range: -32768 to 32767, initial value: 0) The upward direction of the robot is the positive direction of the z axis.
light: value of light sensor (range: 0 to 65535, initial value: 0) The brighter, the larger the value.
temperature: temperature value inside the robot (range: -40 to 88 degrees Celsius, initial value: 0)
signal strength: signal strength of Bluetooth communication (range: -128 to 0 dBm, initial value: 0) As the signal strength increases, the value increases.
input A: value of signal input to external port A (range: analog input 0 to 255, digital input 0 or 1, initial value: 0)
input B: value of signal input to external port B (range: analog input 0 to 255, digital input 0 or 1, initial value: 0)', roboid_hamster_beep: 'Plays beep sound.', roboid_hamster_change_both_wheels_by: 'Adds the entered values to the current speed values (%) of the left and right wheels respectively. If the result is positive, the wheel rotates forward; if negative, the wheel rotates backward.', roboid_hamster_change_buzzer_by: 'Adds the entered value to the current pitch (Hz) of the buzzer sound. You can enter up to two decimal places.', roboid_hamster_change_output_by: 'Adds the entered value to the current output value of the selected external port. The result will be in the following range depending on the mode of the external port.
Servo output: valid range from 1 to 180 degrees; if 0, output 0 without PWM pulse
PWM output: 0 to 100%, duty ratio (%) of ON state in PWM waveform
Digital output: LOW when 0, otherwise HIGH', roboid_hamster_change_tempo_by: 'Adds the entered value to the current BPM (beats per minute) of the playing or resting speed.', roboid_hamster_change_wheel_by: 'Adds the entered value to the current speed value (%) of the left/right/both wheels. If the result is positive, the wheel rotates forward; if negative, the wheel rotates backward.', roboid_hamster_clear_buzzer: 'Turns off buzzer sound.', roboid_hamster_clear_led: 'Turns off the left/right/both LEDs.', roboid_hamster_follow_line_until: 'Moves along the black/white line on the left/right/front/back, then stops when the robot meets the intersection.', roboid_hamster_follow_line_using: 'Moves along the black/white line by using the left/right/both floor sensors.', roboid_hamster_hand_found: 'If there is a hand or object in front of the proximity sensor, true, otherwise false', roboid_hamster_move_backward_for_secs: 'Moves backward for the number of seconds entered.', roboid_hamster_move_forward_for_secs: 'Moves forward for the number of seconds entered.', roboid_hamster_move_forward_once: 'Moves one space forward on the board.', roboid_hamster_play_note_for: 'It sounds the selected tone and octave as much as the beat you entered.', roboid_hamster_rest_for: 'Rests as much as the beat you entered.', roboid_hamster_set_both_wheels_to: 'Sets the speed of the left and right wheels to the entered values (-100 to 100%), respectively. If you enter a positive value, the wheel rotates forward. If you enter a negative value, the wheel rotates backward. Entering the number 0 stops it.', roboid_hamster_set_buzzer_to: 'Sets the pitch of the buzzer sound to the entered value (Hz). You can enter up to two decimal places. Entering the number 0 turns off the buzzer sound.', roboid_hamster_set_following_speed_to: 'Sets the speed (1 to 8) to move along the line. The larger the number, the faster the movement.', roboid_hamster_set_led_to: 'Turns left/right/both LEDs to the selected color.', roboid_hamster_set_output_to: 'Sets the output value of the selected external port to the entered value. The value has the following range according to the mode of external port.
Servo output: valid range from 1 to 180 degrees; if 0, output 0 without PWM pulse
PWM output: 0 to 100%, duty ratio (%) of ON state in PWM waveform
Digital output: LOW when 0, otherwise HIGH', roboid_hamster_set_port_to: 'Sets the io mode of the selected external port to the selected mode.', roboid_hamster_set_tempo_to: 'Sets the playing or resting speed to the entered BPM (beats per minute).', roboid_hamster_set_wheel_to: 'Sets the speed of the left/right/both wheels to the entered value (-100 to 100%). If you enter a positive value, the wheel rotates forward. If you enter a negative value, the wheel rotates backward. Entering the number 0 stops it.', roboid_hamster_stop: 'Stops both wheels.', roboid_hamster_turn_for_secs: 'Turns left/right for the number of seconds entered.', roboid_hamster_turn_once: 'Turns left/right 90 degrees on the board.', roboid_hamster_value: 'left proximity: value of left proximity sensor (range: 0 to 255, initial value: 0)
right proximity: value of right proximity sensor (range: 0 to 255, initial value: 0)
left floor: value of left floor sensor (range: 0 to 100, initial value: 0)
right floor: value of right floor sensor (range: 0 to 100, initial value: 0)
x acceleration: x-axis value of acceleration sensor (range: -32768 to 32767, initial value: 0) The direction in which the robot moves forward is the positive direction of the x axis.
y acceleration: y-axis value of acceleration sensor (range: -32768 to 32767, initial value: 0) The left direction of the robot is the positive direction of the y axis.
z acceleration: z-axis value of acceleration sensor (range: -32768 to 32767, initial value: 0) The upward direction of the robot is the positive direction of the z axis.
light: value of light sensor (range: 0 to 65535, initial value: 0) The brighter, the larger the value.
temperature: temperature value inside the robot (range: -40 to 88 degrees Celsius, initial value: 0)
signal strength: signal strength of Bluetooth communication (range: -128 to 0 dBm, initial value: 0) As the signal strength increases, the value increases.
input A: value of signal input to external port A (range: analog input 0 to 255, digital input 0 or 1, initial value: 0)
input B: value of signal input to external port B (range: analog input 0 to 255, digital input 0 or 1, initial value: 0)', roboid_turtle_button_state: 'If the button clicked/double-clicked/long-pressed, true, otherwise false.', roboid_turtle_change_buzzer_by: 'Adds the entered value to the current pitch (Hz) of the buzzer sound. You can enter up to two decimal places.', roboid_turtle_change_head_led_by_rgb: 'Adds the entered values to the current R, G, B values of the head LED, respectively.', roboid_turtle_change_tempo_by: 'Adds the entered value to the current BPM (beats per minute) of the playing or resting speed.', roboid_turtle_change_wheel_by: 'Adds the entered value to the current speed value (%) of the left/right/both wheels. If the result is positive, the wheel rotates forward; if negative, the wheel rotates backward.', roboid_turtle_change_wheels_by_left_right: 'Adds the entered values to the current speed values (%) of the left and right wheels respectively. If the result is positive, the wheel rotates forward; if negative, the wheel rotates backward.', roboid_turtle_clear_head_led: 'Turns off the head LED.', roboid_turtle_clear_sound: 'Turns off sound.', roboid_turtle_cross_intersection: 'Moves forward for a moment at the black intersection, then finds the black line and moves again.', roboid_turtle_follow_line: 'Moves along the selected color line on a white background.', roboid_turtle_follow_line_until: 'Moves along the black line on a white background and stops when the color sensor detects the selected color.', roboid_turtle_follow_line_until_black: 'Moves along the selected color line on a white background and stops when the color sensor detects black.', roboid_turtle_is_color_pattern: 'If the color sensor detects the selected color pattern, true, otherwise false.', roboid_turtle_move_backward_unit: 'Moves backward for the number of cm/seconds/pulses entered.', roboid_turtle_move_forward_unit: 'Moves forward for the number of cm/seconds/pulses entered.', roboid_turtle_pivot_around_wheel_unit_in_direction: 'Pivots around the left/right wheel in the head/tail direction for the number of degrees/seconds/pulses entered.', roboid_turtle_play_note: 'It sounds the selected tone and octave.', roboid_turtle_play_note_for_beats: 'It sounds the selected tone and octave as much as the beat you entered.', roboid_turtle_play_sound_times: 'Plays the selected sound as many times as entered.', roboid_turtle_play_sound_times_until_done: 'Plays the selected sound as many times as entered, and waits for completion.', roboid_turtle_rest_for_beats: 'Rests as much as the beat you entered.', roboid_turtle_set_buzzer_to: 'Sets the pitch of the buzzer sound to the entered value (Hz). You can enter up to two decimal places. Entering the number 0 turns off the buzzer sound.', roboid_turtle_set_following_speed_to: 'Sets the speed (1 to 8) to move along the line. The larger the number, the faster the movement.', roboid_turtle_set_head_led_to: 'Turns the head LED to the selected color.', roboid_turtle_set_head_led_to_rgb: 'Sets the R, G, B values of the head LED to the entered values.', roboid_turtle_set_tempo_to: 'Sets the playing or resting speed to the entered BPM (beats per minute).', roboid_turtle_set_wheel_to: 'Sets the speed of the left/right/both wheels to the entered value (-400 to 400%). If you enter a positive value, the wheel rotates forward. If you enter a negative value, the wheel rotates backward. Entering the number 0 stops it.', roboid_turtle_set_wheels_to_left_right: 'Sets the speed of the left and right wheels to the entered values (-400 to 400%), respectively. If you enter a positive value, the wheel rotates forward. If you enter a negative value, the wheel rotates backward. Entering the number 0 stops it.', roboid_turtle_stop: 'Stops both wheels.', roboid_turtle_touching_color: 'If the color sensor detects the selected color, true, otherwise false.', roboid_turtle_turn_at_intersection: 'Moves forward for a moment at the black intersection, then turns left/right/back in place, finds the black line and moves again.', roboid_turtle_turn_unit_in_place: 'Turns left/right in place for the number of degrees/seconds/pulses entered.', roboid_turtle_turn_unit_with_radius_in_direction: 'Turns left/right drawing the circle of the entered radius in the head/tail direction for the number of degrees/seconds/pulses entered.', roboid_turtle_value: 'color number: color number detected by the color sensor (range: -1 to 8, initial value: -1)
color pattern: value of the color pattern detected by the color sensor (range: -1 ~ 88, initial value: -1)
floor: value of floor sensor (range: 0 to 100, initial value: 0)
button: status of the button (when pressed 1, otherwise 0, initial value: 0)
x acceleration: x-axis value of acceleration sensor (range: -32768 to 32767, initial value: 0) The direction in which the robot moves forward is the positive direction of the x axis.
y acceleration: y-axis value of acceleration sensor (range: -32768 to 32767, initial value: 0) The left direction of the robot is the positive direction of the y axis.
z acceleration: z-axis value of acceleration sensor (range: -32768 to 32767, initial value: 0) The upward direction of the robot is the positive direction of the z axis.', turtle_button_state: 'If the button clicked/double-clicked/long-pressed, true, otherwise false.', turtle_change_buzzer_by: 'Adds the entered value to the current pitch (Hz) of the buzzer sound. You can enter up to two decimal places.', turtle_change_head_led_by_rgb: 'Adds the entered values to the current R, G, B values of the head LED, respectively.', turtle_change_tempo_by: 'Adds the entered value to the current BPM (beats per minute) of the playing or resting speed.', turtle_change_wheel_by: 'Adds the entered value to the current speed value (%) of the left/right/both wheels. If the result is positive, the wheel rotates forward; if negative, the wheel rotates backward.', turtle_change_wheels_by_left_right: 'Adds the entered values to the current speed values (%) of the left and right wheels respectively. If the result is positive, the wheel rotates forward; if negative, the wheel rotates backward.', turtle_clear_head_led: 'Turns off the head LED.', turtle_clear_sound: 'Turns off sound.', turtle_cross_intersection: 'Moves forward for a moment at the black intersection, then finds the black line and moves again.', turtle_follow_line: 'Moves along the selected color line on a white background.', turtle_follow_line_until: 'Moves along the black line on a white background and stops when the color sensor detects the selected color.', turtle_follow_line_until_black: 'Moves along the selected color line on a white background and stops when the color sensor detects black.', turtle_is_color_pattern: 'If the color sensor detects the selected color pattern, true, otherwise false.', turtle_move_backward_unit: 'Moves backward for the number of cm/seconds/pulses entered.', turtle_move_forward_unit: 'Moves forward for the number of cm/seconds/pulses entered.', turtle_pivot_around_wheel_unit_in_direction: 'Pivots around the left/right wheel in the head/tail direction for the number of degrees/seconds/pulses entered.', turtle_play_note: 'It sounds the selected tone and octave.', turtle_play_note_for_beats: 'It sounds the selected tone and octave as much as the beat you entered.', turtle_play_sound_times: 'Plays the selected sound as many times as entered.', turtle_play_sound_times_until_done: 'Plays the selected sound as many times as entered, and waits for completion.', turtle_rest_for_beats: 'Rests as much as the beat you entered.', turtle_set_buzzer_to: 'Sets the pitch of the buzzer sound to the entered value (Hz). You can enter up to two decimal places. Entering the number 0 turns off the buzzer sound.', turtle_set_following_speed_to: 'Sets the speed (1 to 8) to move along the line. The larger the number, the faster the movement.', turtle_set_head_led_to: 'Turns the head LED to the selected color.', turtle_set_head_led_to_rgb: 'Sets the R, G, B values of the head LED to the entered values.', turtle_set_tempo_to: 'Sets the playing or resting speed to the entered BPM (beats per minute).', turtle_set_wheel_to: 'Sets the speed of the left/right/both wheels to the entered value (-400 to 400%). If you enter a positive value, the wheel rotates forward. If you enter a negative value, the wheel rotates backward. Entering the number 0 stops it.', turtle_set_wheels_to_left_right: 'Sets the speed of the left and right wheels to the entered values (-400 to 400%), respectively. If you enter a positive value, the wheel rotates forward. If you enter a negative value, the wheel rotates backward. Entering the number 0 stops it.', turtle_stop: 'Stops both wheels.', turtle_touching_color: 'If the color sensor detects the selected color, true, otherwise false.', turtle_turn_at_intersection: 'Moves forward for a moment at the black intersection, then turns left/right/back in place, finds the black line and moves again.', turtle_turn_unit_in_place: 'Turns left/right in place for the number of degrees/seconds/pulses entered.', turtle_turn_unit_with_radius_in_direction: 'Turns left/right drawing the circle of the entered radius in the head/tail direction for the number of degrees/seconds/pulses entered.', turtle_value: 'color number: color number detected by the color sensor (range: -1 to 8, initial value: -1)
color pattern: value of the color pattern detected by the color sensor (range: -1 ~ 88, initial value: -1)
floor: value of floor sensor (range: 0 to 100, initial value: 0)
button: status of the button (when pressed 1, otherwise 0, initial value: 0)
x acceleration: x-axis value of acceleration sensor (range: -32768 to 32767, initial value: 0) The direction in which the robot moves forward is the positive direction of the x axis.
y acceleration: y-axis value of acceleration sensor (range: -32768 to 32767, initial value: 0) The left direction of the robot is the positive direction of the y axis.
z acceleration: z-axis value of acceleration sensor (range: -32768 to 32767, initial value: 0) The upward direction of the robot is the positive direction of the z axis.', neobot_sensor_value: 'Indicates the input value from ports IN1 - IN3 and the battery information as number from 0 to 255.', neobot_sensor_convert_scale: "The expressed scale of the selected port's change of input value as the value of a particular scale can be adjusted.", neobot_left_motor: 'Sets the wheel direction and speed of the motor connected to L motor port.', neobot_stop_left_motor: 'Stops the motor connected to L motor port.', neobot_right_motor: 'Sets the wheel direction and speed of the motor connected to R motor port.', neobot_stop_right_motor: 'Stops the motor connected to R motor port.', neobot_all_motor: 'The speed, time, and direction towards front, back, left and right, when connecting 2 motors to L and R motor ports can be set and used as wheels. ', neobot_stop_all_motor: 'Stops the motor connected to both L and R motor ports.', neobot_set_servo: 'The angle within 0 - 180 degrees when connecting servo motor to OUT1 - OUT3 can be adjusted', neobot_set_output: 'The output voltage when connecting lighting block and electronic circuit to OUT1 - OUT3 can be set.
0 indicates 0V, and 1 ~ 255 indicates 2.4 ~ 4.96V.', neobot_set_fnd: 'Numbers from 0 to 99 with FND can be indicated.', neobot_set_fnd_off: 'Number indicated on FND can be turned off.', neobot_play_note_for: 'Notes in semitone units of the melody can be played by utilizing frequency oscillation. ', rotate_by_angle_dropdown: 'Rotates the object by the input number of degrees.', chocopi_control_button: 'This block will be true if the button is pressed.


Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used', chocopi_control_event: 'You can attach blocks to process when the button is pressed or released


Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used', chocopi_control_joystick: 'Joystick X,Y and potentiometer has range of 0~4095.
so, around 2047 will be center value.


Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used', chocopi_dc_motor: "Two DC motors can be connected to 'DC motor' module
The motor will be supplied with maximum 5V.
Maximum value is 100 (100%), is negative value is used then it will rotate opposite direction.

Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used", chocopi_led: 'LED number start from 1 and is the connecting order from the LED module.
You can assign RGB values from 0 to 255
RGB(Red Green Blue) order
To watch an LED with bright light can be painful,
so, please use small number like 0 to 5.

Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used', chocopi_motion_photogate_event: "Two photogates can be connected to 'Motion' module
A photogate is a device with light sensor facing light source in opposite side
You can attach blocks when an object blocks or unblocks light sensor


Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used", chocopi_motion_photogate_status: "Two photogates can be connected to 'Motion' module
A photogate is a device with light sensor facing light source in opposite side
This block will be true if an object blocks sensor

Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used", chocopi_motion_photogate_time: "Two photogates can be connected to 'Motion' module
A photogate is a device with light sensor facing light source in opposite side
This block will have the time when an object blocked or unblocked the sensor
It can measure time with resolution of 1/10000 sec

Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used", chocopi_motion_value: "'Motion' module has three infrared sensors
The value has range of 0~4095, the more reflection from object, the smaller the value is
It can be used to measure approximate distance between the sensor and an object
Acceleration and angular acceleration value ranges from -32768 to 32767.
You can measure inclination of the sensor using these values.

Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used", chocopi_sensor: 'Temperature value is Celsius.
Relative humidity value ranges from 0 to 100%.
Light value ranges 0~4095 in log scale.
Analog value ranges from 0 to 4095.

Port number(P1~P8) is automatically selected internally.
It is needed only when multiple modules with the same kind are used', chocopi_servo_motor: "'Servo' module can be connected to four servo motors
Servo motors are provided with 5V
You can assign 0~200 in degree unit.
If a contineous rotational servo motor is connected, it's speed is determined by the degree value.
Center value is from 90 to 100 varying by motor model.

Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used", chocopi_touch_event: 'Touch module has #1~12 connecting pads.
You can attach block to process when these pads are touched or untouched.


Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used', chocopi_touch_status: 'It will be true if the pad is touched.


Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used', chocopi_touch_value: "The value will be smaller if the capacitance of the obeject is larger.
If many people hold each other's hand and touch, the value will be smaller
'Capacitance' means how many electric particles the object can hold.


Port number(P1~P8) is automatically selected internally
It is needed only when multiple modules with the same kind are used", boolean_and_or: 'AND: Checks whether both conditions are true.\nOR: Checks whether at least one of the two conditions is true.', check_weather: '\nChecks whether the weather information of the selected date and region matches the actual weather conditions.', check_finedust: '\nChecks whether the current fine dust information of the selected region matches the actual fine dust grade.', get_weather_data: '\nReports various weather information values (the lowest temperature, the highest temperature, humidity, precipitation, precipitation probability, wind speed) of the selected date and region.', get_current_weather_data: '\nReports the current weather information (temperature, fine dust grade) of the selected region.', get_today_temperature: '\nReports the today temperature of selected area and time zone.', check_city_weather: 'Checks whether the weather information of the selected date and region matches the actual weather conditions.', check_city_finedust: 'Checks whether the current fine dust information of the selected region matches the actual fine dust grade.', get_city_weather_data: 'Reports various weather information values (the lowest temperature, the highest temperature, humidity, precipitation, precipitation probability, wind speed) of the selected date and region.', get_current_city_weather_data: 'Reports the current weather information (temperature, fine dust grade) of the selected region.', get_today_city_temperature: 'Report the today temperature of selected area and time zone.', get_cur_weather: '\nReports the current weather in the selected area.', get_cur_wind: '\nReports the current wind direction in the selected area.', get_cur_weather_data: '\nReports the current weather information in the selected area.\n- Weather information : temperature(℃), fine dust concentration(PM10, ㎍)', check_cur_weather: "\nChecks whether the current weather in the selected area matches the selected weather conditions. If so, it is judged as 'True'.", check_cur_finddust: "\nChecks whether the current fine dust grade in the selected area matches the selected fine dust grade. If so, it is judged as 'True'.", get_day_weather: '\nReports the daily weather in the selected area.', get_day_weather_data: '\nReports the daily weather information in the selected area.\n- Weather information: the lowest temperature(℃), the highest temperature(℃), humidity(%), precipitation(mm), precipitation probability(%), wind speed(m/s)', check_day_weather: "\nChecks whether the daily weather in the selected area matches the selected weather conditions. If so, it is judged as 'True'. ", get_time_weather: '\nReports the weather by hour(every 3 hours) in the selected area.', get_time_weather_data: '\nReports the weather information by hour(every 3 hours) in the selected area.\n- Weather information: the lowest temperature(℃), the highest temperature(℃), humidity(%), precipitation(mm), precipitation probability(%), wind speed(m/s)', check_time_weather: "\nChecks whether the weather by hour in the selected area matches the selected weather conditions. If so, it is judged as 'True'. ", count_festival: 'Translate the input text into the selected language. You can enter up to 20 charactors. ', get_festival_info: 'Detects the language of the input text. You can enter up to 20 charactors.', get_translated_string: 'The number of events held on the selected date and region.', check_language: 'Reports the information(Title, area, start date, end date, address, overview, homepage) about events held on the selected date and region.', count_disaster_behavior: "\nThe number of behavior-guideline's when selected natural disaster occurs.", get_disaster_behavior: '\nReports the information about behavior-guidelines when selected natural disaster occurs.', count_lifeSafety_behavior: "\nThe number of behavior-guideline's when selected life problem occurs.", get_lifeSafety_behavior: '\nReports the information about behavior-guidelines when selected life problem occurs.', count_disaster_guideline: 'The number of guidelines in the selected natural disaster.\n\n- Natural disaster: typhoon, flood, heavy rain, strong wind, heavy snow, cold wave, rough seas, yellow dust, heat wave, drought, earthquake, tsunami, tidal wave, landslide, volcanic eruption', get_disaster_guideline: 'Reports the information about the guidelines of the selected natural disaster.\n\n- Natural disaster: typhoon, flood, heavy rain, strong wind, heavy snow, cold wave, rough seas, yellow dust, heat wave, drought, earthquake, tsunami, tidal wave, landslide, volcanic eruption', count_social_disaster_guideline: 'Reports the information about the guidelines of the selected social disaster.\n\n- Social disaster: marine pollution, large-scale water pollution, water shortage, utility tunnel disaster, livestock disease, infectious disease, railway and subway, financial IT system, nuclear power plant accident, chemical accident, fire, wildfire, building collapse, dam collapse, explosion, aircraft accident, CBRN incident, power outage, electricity·gas, passenger ship, water accident, terrorism, power shortage', get_social_disaster_guideline: 'Reports the information about the guidelines of the selected social disaster.\n\n- Social disaster: marine pollution, large-scale water pollution, water shortage, utility tunnel disaster, livestock disease, infectious disease, railway and subway, financial IT system, nuclear power plant accident, chemical accident, fire, wildfire, building collapse, dam collapse, explosion, aircraft accident, CBRN incident, power outage, electricity·gas, passenger ship, water accident, terrorism, power shortage"', count_safety_accident_guideline: "The number of methods in the selected life safety accident.\n\n- Life safety accidents: first aid, CPR, fire extinguisher, food poisoning, hiking, children's playground, missing·kidnapping, sexual violence, school violence, domestic violence, detention·abduction, traffic accident, elevator, fine dust, fire hydrant, home safety inspection", get_safety_accident_guideline: "first aid, CPR, fire extinguisher, food poisoning, hiking, children's playground, missing·kidnapping, sexual violence, school violence, domestic violence, detention·abduction, traffic accident, elevator, fine dust, fire hydrant, home safety inspection", read_text: 'Read the entered text in setted voice.', set_tts_property: 'Set the selected voice to selected speed and selected pitch. \n The selected voice will be set up to selected speed and selected pitch.', read_text_wait_with_block: 'Read the entered text in setted voice then the next block runs after the reading finished.', check_microphone: "If the microphone is connected to the computer, it is judged as 'True'.", speech_to_text_convert: 'Recognizes speech recorded through the microphone.', timed_speech_to_text_convert: 'Recognizes speech recorded through the microphone for the input seconds.', set_visible_speech_to_text: 'Shows or hides the recognized speech on the screen.', speech_to_text_get_value: "Reports the value of the person's speech to text. If no speech is input or an error occurs during recognition, it will report null values.", get_microphone_volume: 'Reports the volume of sound input through microphone.', video_draw_webcam: 'Show or hide the video screen. (IE / iOS Not Supported)', video_check_webcam: 'Check whether video is connected with the computer. (IE / iOS Not Supported)', video_set_camera_option: 'Set the selected effect to the video screen by the input value.', video_flip_camera: 'Flips the video screen horizontally or vertically. (IE / iOS Not Supported)', video_toggle_model: "Start or stop the selected recognition model. Face Recognition: Recognizes a person's face to know where the eyes, nose, mouth, and ear are located, or the expected gender, age, and emotion. Human Recognition: Recognizes a person's body to know where each part is located Object Recognition: Shows the recognized object type. (Person or thing) (IE / iOS Not Supported)", video_toggle_ind: 'Show location and index of the detected humans/faces/objects on the screen. (IE / iOS Not Supported)', video_number_detect: 'Reports number of humans/faces/objects detected on the video screen. (IE / iOS Not Supported)', video_detected_face_info: 'Reports the estimated value of the selected face area among the faces in the input order. If it is not recognized, it is outputted as 0 unconditionally. (Gender, Age, Emotion) (IE / iOS Not Supported)', video_motion_value: 'Reports the motion or direction value detected on the selected object or screen. (IE / iOS Not Supported)', video_face_part_coord: 'Reports the position value of the selected face area among the faces in the input order. If it is not recognized, it is outputted as 0 unconditionally. (Left eye, Right eye, Nose, Left mouse, Right mouse, Top Lip, Bottom Lip) (IE / iOS Not Supported)', video_body_part_coord: 'Reports number of human detected on the video screen. (Face, Right shoulder, Right elbow, Right wrist, Left shoulder, Left elbow, Left wrist, Right hip, Right knee, Right ankle, Left hip, Left knee, Left ankle) (IE / iOS Not Supported)', append_row_to_table: 'Adds a row(column) to the end of the selected table. All cell values ​​in the added row(column) are 0.', insert_row_to_table: 'Adds a row(column) to the entered order of the selected table. All cell values ​​in the added row(column) are 0. The rows(columns) after the added row(column) are pushed back one by one.', delete_row_from_table: 'Deletes the row(column) in the entered order of the selected table.', set_value_from_table: 'Replaces the attribute of the entered row with the values ​​entered in the selected table.', save_current_table: 'Save the table as it is. Even if you stop the project, your changes in the table are maintained.', get_table_count: 'The number of rows(columns) in the selected table.', get_value_from_table: 'The selected attribute value of the entered row in the selected table. Instead of an attribute value block, you can also combine a value block (meaning a column).', get_value_from_last_row: 'The selected attribute value of the last row in the selected table. Instead of an attribute value block, you can also combine a value block (meaning a column).', calc_values_from_table: 'Reports calculated value of the selected attributes in the selected table. (Sum, Maximum, Minimum, Average, Standard deviation, Median)', open_table: 'Open the window of the selected table.', open_table_wait: 'Open the window of the selected table for the seconds entered.', open_table_chart: 'Opens the chart of the selected table.', close_table_chart: 'Close the table chart.', get_coefficient: 'Correlation coefficient between two attributes in the selected table. The closer the correlation coefficient is to 1 (-1), the stronger the positive (negative) linear correlation.', set_value_from_cell: 'Replaces the cell with the values ​​entered in the selected table.', get_value_from_cell: 'The cell value in the selected table.', get_value_v_lookup: 'Searches for a value in selected column of a table and returns a corresponding value from a specified column in the same row.', change_rgb_to_hex: 'Reports the value of the entered red, green, and blue values converted to HEX value.', change_hex_to_rgb: 'Reports the HEX value entered converted to either red, green, or blue.', media_pipe_video_screen: 'Shows or hides the video screen.', media_pipe_switch_camera: 'Switches the camera that films the video.', check_connected_camera: "If the camera is connected to the computer, it is judged as 'True'.", media_pipe_flip_camera: 'Flips the video screen horizontally or vertically.', media_pipe_set_opacity_camera: 'Sets the transparency effect of video screen to the input value. It can be set in the range from 0 to 100.\n(The default value is 50. Values under 0 is treated as 0 and over 100 is treated as 100.)', media_pipe_motion_value: 'Reports the motion or direction value detected on the selected object or screen.\n- Motion: The larger and faster the movement, the larger the value.\n- Direction: Positive when moving right or up, and negative when moving left or down', when_pose_landmarker: 'When human detected, the connected blocks below will run.', pose_landmarker: 'Start or stop the human detection model.\n- Human Detection: Detects a human and determines where each body parts are located.', draw_detected_pose: 'Shows or hides the location and order of the detected humans on the screen.', check_detected_pose: "If the human is detected, it is judged as 'True'.", count_detected_pose: 'Reports the number of the humans detected on the video screen.', locate_to_pose: 'Moves the object to the position of the selected body part.', locate_time_to_pose: 'Moves the object to the position of the selected body part for the input seconds.', axis_detected_pose: 'Reports the location value of the selected body part of the human in the order entered.\n(Body parts: nose, left eye (inner), left eye, left eye (outer), right eye (inner), right eye, right eye (outer), left ear, right ear, mouth (left), mouth (right), left shoulder, right shoulder, left elbow, right elbow, left wrist, right wrist, left pinky, right pinky, left index, right index, left thumb, right thumb, left hip, right hip, left knee, right knee, left ankle, right ankle, left heel, right heel, left foot index, right foot index)', when_face_landmarker: 'When face detected, the connected blocks below will run.', face_landmarker: "Start or stop the face detection model.\n- Face Detection: Detects a human's face and determines where the eyes, nose, mouth, and ear are located.", draw_detected_face: 'Shows or hides the location and order of the detected faces on the screen.', check_detected_face: "If the face is detected, it is judged as 'True'.", count_detected_face: 'Reports the number of the faces detected on the video screen.', locate_to_face: 'Moves the object to the position of the selected face part.', locate_time_to_face: 'Moves the object to the position of the selected body part for the input seconds.', check_detected_gender: "If the selected face is the selected gender, it is judged as 'True'.", check_compare_age: "If the age of the selected face matches the formula, it is judged as 'True'.", check_detected_emotion: "If the selected face is the selected emotion, it is judged as 'True'.", axis_detected_face: 'Reports the location value of the selected face area of the face in the order entered. (Face area: left eye, right eye, nose, left corner of lips, right corner of lips, upper lip, lower lip)', get_detected_face_value: 'Reports the estimated value of the gender/age/emotion of the face in the order entered. If it is not detected, it returns 0.', when_object_detector: 'When object detected, the connected blocks below will run.', object_detector: 'Start or stop the object detection model.\n- Object Detection: Detects the type of object.', draw_detected_object: 'Shows or hides the location and order of the detected object on the screen.', check_detected_object: "If the object is detected, it is judged as 'True'.", count_detected_object: 'Reports the number of the objects detected on the video screen.', is_detected_among_objects: "If the selected object is detected, it is judged as 'True'.", when_hand_detection: 'When hand detected, the connected blocks below will run.', hand_detection: 'Start or stop hand detection model.\n- Hand Detection: Detects a human’s hand and determines where each hand parts are located.', draw_detected_hand: 'Shows or hides the location of the hand on the screen.', check_detected_hand: "If the hand is detected, it is judged as 'True'.", count_detected_hand: 'Reports the number of hand detected on the video screen.', locate_to_hand: 'Moves the object to the position of the selected part of the hand.', locate_time_to_hand: 'Moves the object to the position of the selected part of the hand for the input seconds.', axis_detected_hand: 'Reports the location value of the selected part of the hand in the order entered.', is_which_hand: "If the hand in the order you entered is the selected hand, it is judged as 'True'.", get_which_hand: 'Reports the value of the hand in the order you entered.', is_which_gesture: "If the hand in the order you entered is the gesture you selected, it is judged as 'True'.", get_which_gesture: 'Reports the gesture of the hand in the order you entered.', text_change_effect: 'Applies the selected text effect in the text box.', text_change_font: 'Changes the text of the box to the selected font.', text_change_font_color: 'Changes the text in the box to the selected color.', text_change_bg_color: 'Changes the text box to the selected background color.', insert_data_for_test: 'Enter data and recognize it as a trained model.', video_capture_for_image_test: 'Classifies or stops image data taken through the camera to the model you learned.', insert_text_block_for_test: 'Enter data and recognize it as a trained model.', test_result: 'The value of the result that the model recognizes the data entered. The value is expressed by the class name (text) of the model.', accuracy_of_result: 'The reliability value for the selected class of the data entered. The value is expressed as a probability (number).', is_group: "Determine 'True' if the recognition result of the data entered is the selected class.", model_is_trained: "If the model has trained, it is determined as 'True'. If the model is being trained or hasn't trained, it is determined as 'False'.", set_train_visible: 'Shows or hides the window displaying the state of the model on the screen.', set_train_chart: 'Opens or closes a chart window showing the entered data and clusters of learned models in a two-dimensional coordinate plane.', set_regression_option: "Change the learning conditions of the model. The changed learning conditions take effect when the model is re-learned with the 'Re-learn Model' block.", get_regression_predict_1: 'Returns the value predicted by the model with the key properties entered.', get_regression_predict_2: 'Returns the value predicted by the model with the key properties entered.', get_regression_predict_3: 'Returns the value predicted by the model with the key properties entered.', get_regression_predict_4: 'Returns the value predicted by the model with the key properties entered.', get_regression_predict_5: 'Returns the value predicted by the model with the key properties entered.', get_regression_predict_6: 'Returns the value predicted by the model with the key properties entered.', get_regression_accuracy: "Returns the model's coefficient of determination as a value.", set_cluster_option_k: "Sets the number of clusters to the entered value. The number of clusters changed will take effect when the model is re-learned with the 'Re-learn Model' block.", set_cluster_option_centroids: "Replace the cluster's initial center point criteria with the selected criteria. The center point criteria that you changed will take effect when you re-learn the model with the 'Re-learn Model' block.", get_cluster_centriod_count: 'Returns the number of clusters in the model as values.', get_cluster_centriod_value: 'Returns the core properties for the center point of the specified cluster. If you have multiple core properties, you can select them from the list box.', get_cluster_centriod_index_1: 'Returns which cluster the model belongs to, if any, to, the core property entered. Values are represented by text (cluster name).', get_cluster_centriod_index_2: 'Returns which cluster the model belongs to, if any, to, the core property entered. Values are represented by text (cluster name).', get_cluster_centriod_index_3: 'Returns which cluster the model belongs to, if any, to, the core property entered. Values are represented by text (cluster name).', get_cluster_centriod_index_4: 'Returns which cluster the model belongs to, if any, to, the core property entered. Values are represented by text (cluster name).', get_cluster_centriod_index_5: 'Returns which cluster the model belongs to, if any, to, the core property entered. Values are represented by text (cluster name).', get_cluster_centriod_index_6: 'Returns which cluster the model belongs to, if any, to, the core property entered. Values are represented by text (cluster name).', set_number_learning_option_k: "Sets the number of neighbors to the entered value. The number of neighbors changed will take effect when the model is re-learned with the 'Re-learn Model' block.", get_number_learning_predict_1: 'The value that classifies the entered data in the model. The value is represented by the class name (text) of the model.', get_number_learning_predict_2: 'The value that classifies the entered data in the model. The value is represented by the class name (text) of the model.', get_number_learning_predict_3: 'The value that classifies the entered data in the model. The value is represented by the class name (text) of the model.', get_number_learning_predict_4: 'The value that classifies the entered data in the model. The value is represented by the class name (text) of the model.', get_number_learning_predict_5: 'The value that classifies the entered data in the model. The value is represented by the class name (text) of the model.', get_number_learning_predict_6: 'The value that classifies the entered data in the model. The value is represented by the class name (text) of the model.', get_number_learning_predict_param_1: 'The classification confidence value for the selected class of data entered. Values are expressed numerically.', get_number_learning_predict_param_2: 'The classification confidence value for the selected class of data entered. Values are expressed numerically.', get_number_learning_predict_param_3: 'The classification confidence value for the selected class of data entered. Values are expressed numerically.', get_number_learning_predict_param_4: 'The classification confidence value for the selected class of data entered. Values are expressed numerically.', get_number_learning_predict_param_5: 'The classification confidence value for the selected class of data entered. Values are expressed numerically.', get_number_learning_predict_param_6: 'The classification confidence value for the selected class of data entered. Values are expressed numerically.', is_number_learning_group_1: 'If the classification result of the entered data is a class of your choice, determine True.', is_number_learning_group_2: 'If the classification result of the entered data is a class of your choice, determine True.', is_number_learning_group_3: 'If the classification result of the entered data is a class of your choice, determine True.', is_number_learning_group_4: 'If the classification result of the entered data is a class of your choice, determine True.', is_number_learning_group_5: 'If the classification result of the entered data is a class of your choice, determine True.', is_number_learning_group_6: 'If the classification result of the entered data is a class of your choice, determine True.', video_change_cam: 'Change the camera you are filming.', video_set_camera_opacity_option: 'Set the transparency effect to the video screen by the input value.(IE / iOS Not Supported)', video_is_model_loaded: 'Check whether human/face/object is detected. (IE / iOS Not Supported)', video_object_detected: 'Check whether selected object is recognized. (IE / iOS Not Supported)', target_project: 'Target project', study_goal: 'Learning objectives', show_hint: 'Hints', }; Lang.AiLearning = { equation: 'Equation', predict: 'Predict', cluster_number: 'Cluster', centriod: 'Centriod', class: 'Class', show: 'Show', hide: 'Hide', open: 'Open', close: 'Close', start: 'Start', stop: 'Stop', probability: 'Reliability', neighbor_count: 'Neighbor count', cluster_option_centroids_kmpp: 'Furthest', cluster_option_centroids_random: 'Random', model_attr_str: 'Property', model_status_0: 'Status: Ready', model_status_1: 'Status: Training', model_status_2: 'Status: Trained', model_status_3: 'Status: No Model', train_param_learningRate: 'Learning Rate', train_param_epochs: 'Epoch', train_param_validationRate: 'Validation Rate', chart_title: 'Model chart', trained_table_postfix: 'Trained', train_param_error: 'If table column information has changed, re-learning is not possible.', }; Lang.Category = { entrybot_friends: 'Entrybot friends', people: 'People', animal: 'Animal', animal_flying: 'Flying', animal_land: 'Land', animal_water: 'Water', animal_others: 'Others', plant: 'Plant', plant_flower: 'Flowers', plant_grass: 'Grass', plant_tree: 'Tree', plant_others: 'Others', vehicles: 'Vehicles', vehicles_flying: 'Flying', vehicles_land: 'Land', vehicles_water: 'Water', vehicles_others: 'Others', architect: 'Building', architect_building: 'Structure', architect_monument: 'Monument', architect_others: 'Others', food: 'Food', food_vegetables: 'Fruits/Vegetables', food_meat: 'Meat', food_drink: 'Drink', food_others: 'Others', environment: 'Environment', environment_nature: 'Nature', environment_space: 'Space', environment_others: 'Others', stuff: 'Things', stuff_living: 'Living', stuff_hobby: 'Hobby', stuff_others: 'Others', fantasy: 'Fantasy', interface: 'Interface', interface_website: 'Website', interface_game: 'Game', interface_others: 'Others', background: 'Background', background_outdoor: 'Outdoor', background_indoor: 'Indoor', background_nature: 'Nature', background_others: 'Others', }; Lang.Device = { arduino: 'arduino', hamster: 'hamster', roboid: 'roboid', turtle: 'turtle', albert: 'albert', robotis_carCont: '', robotis_openCM70: '', sensorBoard: 'Entry Sensor Board', trueRobot: 'TrueTrueRobot', CODEino: 'CODEino', bitbrick: 'bitbrick', creamo: 'creamo', playcode: 'playcode', funboard: 'funboard', bitBlock: 'bitBlock', xbot_epor_edge: 'XBOT', dplay: 'DPLAY', iboard: 'iboard', nemoino: 'NEMOino', ev3: 'EV3', robotori: 'robotori', smartBoard: 'smartBoard', chocopi: 'ChocoPi', rokoboard: 'rokoboard', altino: 'altino', mechatro: 'mechatro', }; Lang.General = { turn_on: 'turn on', turn_off: 'turn off', left: 'left', right: 'right', param_string: 'string', both: 'both', transparent: 'transparent', black: 'black', brown: 'brown', red: 'red', yellow: 'yellow', green: 'green', skyblue: 'sykblue', blue: 'blue', purple: 'purple', white: 'white', note_c: 'C', note_d: 'D', note_e: 'E', note_f: 'F', note_g: 'G', note_a: 'A', note_b: 'B', questions: 'Question', clock: 'clock', counter_clock: 'counterclock', font_size: 'font size', second: '"', alert_title: 'Alert', confirm_title: 'Confirm', update_title: 'Alert', recent_download: 'Download', recent_download2: 'Download the latest version', latest_version: 'You are running the latest version.', dont_show_again: 'Do not show this again', apply: 'Apply', clear: 'Clear', }; Lang.Fonts = { jeju_hallasan: 'Hallasan', gothic_coding: 'GothicCoding', batang: 'Batang', gothic: 'NanumGothic', myeongjo: 'NanumMyeongjo', pen_script: 'NanumPenScript', square_round: 'NanumSquareRound', jalnan: 'Jalnan', designhouse: 'Designhouse', malssami815: 'Malssami815', dunggeunmo: 'DungGeunMo', hs_bombaram: 'HS Bombaram', yisunshin: 'YiSunShin', goyang: 'Goyang', flower_road: 'SangSangFlowerRoad', uhbeemysen: 'UhBeemysen', sd_comic_stencil: 'SD Comicstencil', sd_childfundkorea: 'SD Childfundkorea', sd_cinema_theater: 'SD CinemaTheater', sd_mapssi: 'SD Mapssi', sd_shabang: 'SD Shabang', sd_woodcarving: 'SD Woodcarving', sd_yongbi: 'SD Yongbi', maruburi: 'MaruBuri', nanumbarunpen: 'NanumBarunpen.', notosans: 'NotoSans', d2coding: 'D2Coding', }; Lang.Hw = { note: 'note', leftWheel: 'left wheel', rightWheel: 'right wheel', leftEye: 'left eye', rightEye: 'right eye', led: 'LED', led_en: 'LED', body: 'body', front: ' front', port_en: 'port', port_ko: '', sensor: 'sensor', light: 'light', temp: 'temp', switch_: 'sw_', right_ko: '', right_en: 'R', left_ko: '', left_en: 'L', up_ko: '', up_en: 'U', down_ko: '', down_en: 'D', output: 'output', left: 'left', right: 'right', sub: 'servo', motor: 'motor', '': '', buzzer: 'buzzer', IR: 'infrared', acceleration: 'acceleration', analog: 'analog', angular_acceleration: 'angular acceleration', button: 'button', humidity: 'humidity', joystick: 'joystick', port: 'port', potentiometer: 'potentiometer', servo: 'servo', }; Lang.template = { albert_hand_found: 'hand found?', albert_is_oid_value: '%1 oid %2?', albert_value: '%1', albert_move_forward_for_secs: 'move forward for %1 secs %2', albert_move_backward_for_secs: 'move backward for %1 secs %2', albert_turn_for_secs: 'turn %1 for %2 secs %3', albert_change_both_wheels_by: 'change wheels by left: %1 right: %2 %3', albert_set_both_wheels_to: 'set wheels to left: %1 right: %2 %3', albert_change_wheel_by: 'change %1 wheel by %2 %3', albert_set_wheel_to: 'set %1 wheel to %2 %3', albert_stop: 'stop %1', albert_set_pad_size_to: 'set board size to width: %1 height: %2 %3', albert_move_to_x_y_on_board: 'move to x: %1 y: %2 on board %3', albert_set_orientation_on_board: 'set orientation to %1 degrees on board %2', albert_set_eye_to: 'set %1 eye to %2 %3', albert_clear_eye: 'clear %1 eye %2', albert_body_led: 'turn %1 body led %2', albert_front_led: 'turn %1 front led %2', albert_beep: 'beep %1', albert_change_buzzer_by: 'change buzzer by %1 %2', albert_set_buzzer_to: 'set buzzer to %1 %2', albert_clear_buzzer: 'clear buzzer %1', albert_play_note_for: 'play note %1 %2 for %3 beats %4', albert_rest_for: 'rest for %1 beats %2', albert_change_tempo_by: 'change tempo by %1 %2', albert_set_tempo_to: 'set tempo to %1 bpm %2', albert_move_forward: 'move forward %1', albert_move_backward: 'move backward %1', albert_turn_around: 'turn %1 %2', albert_set_led_to: 'set %1 led %2 %3', albert_clear_led: 'clear %1 led %2', albert_change_wheels_by: '%1 %2 %3', albert_set_wheels_to: '%1 %2 %3', arduino_text: '%1', arduino_get_sensor_number: '%1 ', arduino_get_port_number: '%1 ', arduino_get_digital_toggle: '%1 ', arduino_get_pwm_port_number: '%1 ', arduino_get_number_sensor_value: 'Analog %1 Sensor value ', arduino_ext_get_analog_value: 'Analog %1 Sensor value', arduino_ext_get_analog_value_map: 'Map Value %1 %2 ~ %3 to %4 ~ %5', arduino_ext_get_ultrasonic_value: 'Read ultrasonic sensor trig pin %1 echo pin %2', arduino_ext_toggle_led: 'Digital %1 Pin %2 %3', arduino_ext_digital_pwm: 'Digital %1 Pin %2 %3', arduino_ext_set_tone: 'Play tone pin %1 on note %2 octave %3 beat %4 %5', arduino_ext_set_servo: 'Set servo pin %1 angle as %2 %3', arduino_ext_get_digital: 'Digital %1 Sensor value', blacksmith_get_analog_value: 'Read analog %1 pin sensor value', blacksmith_get_analog_mapping: 'Map analog %1 pin sensor value from %2 ~ %3 to %4 ~ %5', blacksmith_get_digital_bluetooth: 'Bluetooth RX 2 value', blacksmith_get_digital_ultrasonic: 'Read ultrasonic Trig %1 Echo %2 sensor value', blacksmith_get_digital_toggle: 'Digital %1 pin sensor value', blacksmith_set_digital_toggle: 'Digital %1 pin %2 %3', blacksmith_set_digital_pwm: 'Digital pwm %1 Pin %2 %3', blacksmith_set_digital_servo: 'Set servo pin %1 angle as %2 %3', blacksmith_set_digital_buzzer: 'Play tone pin %1 on note %2 octave %3 beat %4 %5', blacksmith_set_digital_lcd: 'LCD %1 line %2 appear %3', blacksmith_set_digital_bluetooth: 'Bluetooth TX 3 Pin %1 data send %2', dplay_get_number_sensor_value: 'Analog %1 Sensor value ', nemoino_get_number_sensor_value: 'Analog %1 Sensor value ', sensorBoard_get_number_sensor_value: 'Analog %1 Sensor value ', truetrue_get_accsensor: '3-AXIS Accelerometer %1 Sensor value', truetrue_get_bottomcolorsensor: 'Bottom Color %1 Sensor value', truetrue_get_frontcolorsensor: 'Front Color %1 Sensor value', truetrue_get_linesensor: 'Line %1 Sensor value', truetrue_get_proxisensor: 'Proximity %1 Sensor value', truetrue_set_colorled: 'Set Color LED Red %1 Green %2 Blue %3 %4', truetrue_set_dualmotor: 'Set DC motor left %1 right %2 during %3 seconds %4', truetrue_set_led_colorsensor: 'LED for %1 color sensor %2 %3', truetrue_set_led_linesensor: 'LED for line sensor %1 %2', truetrue_set_led_proxi: 'LED for %1 proximity sensor %2 %3', truetrue_set_linetracer: 'Line tracing mode %1 %2', truetrue_set_singlemotor: 'Set DC motor %1 speed %2 %3', CODEino_get_number_sensor_value: 'Analog %1 Sensor value ', ardublock_get_number_sensor_value: 'Analog %1 Sensor value ', arduino_get_digital_value: 'Digital %1 Sensor value ', dplay_get_digital_value: 'Digital %1 Sensor value ', nemoino_get_digital_value: 'Digital %1 Sensor value ', sensorBoard_get_digital_value: 'Digital %1 Sensor value ', CODEino_get_digital_value: 'Digital %1 Pin value ', CODEino_set_digital_value: 'Digital %1 Pin %2 %3', CODEino_set_pwm_value: 'Digital %1 Pin %2 %3', ardublock_get_digital_value: 'Digital %1 Sensor value ', arduino_toggle_led: 'Digital %1 Pin %2 %3', dplay_toggle_led: 'Digital %1 Pin %2 %3', nemoino_toggle_led: 'Digital %1 Pin %2 %3', sensorBoard_toggle_led: 'Digital %1 Pin %2 %3', CODEino_toggle_led: 'Digital %1 Pin %2 %3', arduino_toggle_pwm: 'Digital %1 Pin %2 %3', dplay_toggle_pwm: 'Digital %1 Pin %2 %3', nemoino_toggle_pwm: 'Digital %1 Pin %2 %3', sensorBoard_toggle_pwm: 'Digital %1 Pin %2 %3', CODEino_toggle_pwm: 'Digital %1 Pin %2 %3', ardublock_toggle_pwm: 'Digital %1 Pin %2 %3', arduino_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', dplay_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', nemoino_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', sensorBoard_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', CODEino_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', CODEino_set_rgb_value: 'Set color LED %1 by %2 %3', CODEino_set_rgb_add_value: 'Add color LED %1 by %2 %3', CODEino_set_rgb_off: 'Turn off LED %1', CODEino_set__led_by_rgb: 'Turn on color LED, Red %1 Green %2 Blue %3 %4', CODEino_rgb_set_color: 'Select %1 for color LED %2', CODEino_led_by_value: 'Turn on LED %1', ardublock_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', joystick_get_number_sensor_value: 'Analog %1 Sensor value ', joystick_get_digital_value: 'Digital %1 Sensor value ', joystick_toggle_led: 'Digital %1 Pin %2 %3', joystick_toggle_pwm: 'Digital %1 Pin %2 %3', joystick_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', sensorBoard_get_named_sensor_value: '%1 Sensor value', sensorBoard_is_button_pressed: 'Pressed %1 button?', sensorBoard_led: '%1 LED %2 %3', arduino_download_connector: '%1', download_guide: '%1', arduino_download_source: '%1', arduino_connected: '%1', arduino_connect: '%1', arduino_reconnect: '%1', CODEino_get_sensor_number: '%1 ', CODEino_get_named_sensor_value: ' %1 Sensor value ', CODEino_get_sound_status: 'Sound is %1 ', CODEino_get_light_status: 'Light is %1 ', CODEino_is_button_pressed: ' Operation %1 ', CODEino_get_accelerometer_direction: ' 3-AXIS Accelerometer %1 ', CODEino_get_accelerometer_value: ' 3-AXIS Accelerometer %1 -axis value ', CODEino_get_analog_value: 'Analog %1 Sensor value', iboard_button: 'Pressed %1 button?', iboard_digital_pwm: 'Digital %1 Pin %2 %3', iboard_get_analog_value: 'Analog %1 Sensor value ', iboard_get_analog_value_map: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', iboard_get_digital: 'Digital %1 Sensor value ', iboard_led: 'Digital %1 Pin %2 %3', iboard_motor: 'Digital %1 Pin %2 %3', iboard_pwm_led: 'Digital %1 Pin %2 %3', iboard_rgb_led: ' %1 LED %2 %3', iboard_set_tone: 'Play tone pin %1 on note %2 octave %3 beat %4 %5', iboard_toggle_led: 'Digital %1 Pin %2 %3', bitbrick_when_button_pressed: '%1 when button %2', bitbrick_when_sensor_get_value: '%1 when %2 value %3 %4', bitbrick_is_touch_pressed: 'button %1 %2?', bitbrick_is_sensor_value_compare: '%1 %2 %3?', bitbrick_sensor_value: '%1 value', bitbrick_convert_scale: 'map %1 value from %2 ~ %3 to %4 ~ %5', bitbrick_turn_on_color_led_by_rgb: 'set LED color to Red %1 Green %2 Blue %3 %4', bitbrick_turn_on_color_led_by_picker: 'set LED color to %1 %2', bitbrick_turn_on_color_led_by_value: 'set LED color %1 %2', bitbrick_turn_off_color_led: 'turn off LED %1', bitbrick_buzzer: 'buzz note %1 %2', bitbrick_servomotor_angle: 'servo motor %1 degree %2 %3', bitbrick_dc_direction_speed: 'dc motor %1 direction %2 speed %3 %4', bitbrick_dc_speed: 'dc motor %1 velocity %2 %3', bitbrick_turn_off_all_motors: 'stop all motors %1', start_drawing: 'Start drawing %1', stop_drawing: 'Stop drawing %1', start_fill: 'Start filling %1', stop_fill: 'Stop filling %1', set_color: 'Set brush color to %1 %2', set_random_color: 'Set brush color to random %1', set_fill_color: 'Set fill color to %1 %2', change_thickness: 'Change thickness by %1 %2', set_thickness: 'Set thickness to %1 %2', change_opacity: 'Change opacity by %1 % %2', set_opacity: 'Set opacity to %1 % %2', brush_erase_all: 'Erase all brush %1', brush_stamp: 'Stamp %1', change_brush_transparency: 'Change transparency by %1 % %2', set_brush_tranparency: 'Set transparency to %1 % %2', number: '%1', angle: '%1', color: '%1', get_x_coordinate: '%1', get_y_coordinate: '%1', get_angle: '%1', get_rotation_direction: '%1 ', distance_something: '%1 %2 %3', coordinate_mouse: '%1 %2 %3', coordinate_object: '%1 %4 %3 %2', calc_basic: '%1 %2 %3', calc_plus: '%1 %2 %3', calc_minus: '%1 %2 %3', calc_times: '%1 %2 %3', calc_divide: '%1 %2 %3', calc_mod: '%1 %2 %3', calc_share: '%1 %2 %3', calc_operation: '%1 %4 %3 %2', calc_rand: '%1 %2 %3 %4', get_date: '%1 %2 %3', get_sound_duration: '%1 %2 %3', get_user_name: 'username', get_nickname: 'nickname', reset_project_timer: '%1', set_visible_project_timer: '%1 %2 %3 %4', timer_variable: '%1 %2', get_project_timer_value: '%1 %2', char_at: '%4 %3 %2', length_of_string: '%1 %2', reverse_of_string: '%1 %2', combine_something: '%1 %2 %3 %4', substring: '%1 %2 %3 %4 %5 %6', replace_string: '%1 %4 %3 %6 %5 %2', change_string_case: '%2 %3 %4', count_match_string: '%2 %3 %4 %1', index_of_string: '%1 %4 %3 %2', get_sound_volume: '%1 %2', quotient_and_mod: ' %1 %6 %3 %2 %5 %4', choose_project_timer_action: '%1 %2 %3 %4', wait_second: 'Wait %1 seconds %2', repeat_basic: 'Repeat %1 times %2', hidden_loop: 'Repeat %1 times %2', repeat_inf: 'Repeat infinitely %1', stop_repeat: 'Stop repeat %1', continue_repeat: 'Skip this repeat %1', wait_until_true: 'Wait until %1 %2', _if: 'If %1 then %2', if_else: 'If %1 then %2 %3 else', create_clone: "Create %1 's clone %2", delete_clone: 'Remove this clone %1', when_clone_start: '%1 When clone is created', stop_run: 'Exit program %1', repeat_while_true: 'Repeat %2 %1 %3', stop_object: 'Stop %1 %2', restart_project: 'Restart Project %1', remove_all_clones: 'Remove all clone %1', functionAddButton: '%1', function_field_label: '%1%2', function_field_string: '%1%2', function_field_boolean: '%1%2', get_block_count: 'number of blocks in %1', get_boolean_value: 'string %1', change_rgb_to_hex: 'HEX value of R: %1 G: %2 B: %3', change_hex_to_rgb: '%2 value of HEX %1', function_param_string: 'Character/Number', function_param_boolean: 'Judgement', function_create: 'define function %1 %2', function_general: 'function %1', expansionBlockAddButton: '%1', aiUtilizeBlockAddButton: '%1', aiUtilizeModelTrainButton: '%1', weather_title: '%1', check_weather: "%1 %2's weather is %3?", check_finedust: "Current %1's fine dust grade is %2?", get_weather_data: "%1 %2's %3", get_current_weather_data: "Current %1's %2", get_today_temperature: "Today %1's %2h temperature(℃)", check_city_weather: "%1 %2 %3's weather is %4?", check_city_finedust: "Current %1 %2's fine dust grade is %3?", get_city_weather_data: "%1 %2 %3's %4", get_current_city_weather_data: "Current %1 %2's %3", get_today_city_temperature: "Today %1 %2's %3h temperature(℃)", get_cur_weather: 'Current weather in %1', get_cur_wind: 'Current wind direction in %1', get_cur_weather_data: 'Current %2 in %1', check_cur_weather: 'Is current weather in %1 %2?', check_cur_finddust: 'Is current fine dust grade in %1 %2?', get_day_weather: 'Weather in %2 %3 %1', get_day_weather_data: '%3 in %2 %1', check_day_weather: 'Is %1 weather in %2 %3?', get_time_weather: "%2 o'clock weather in %1", get_time_weather_data: "%2 o'clock %3 in %1", check_time_weather: "Is %2 o'clock weather in %1 %3?", translate_title: '%1', get_translated_string: 'Translate %1 %2 into %3', check_language: 'language of %1', festival_title: '%1', count_festival: "%1 %2's number of events", get_festival_info: '%4 of item %3 of event in %1 %2', behaviorConductDisaster_title: '%1', count_disaster_behavior: "%1 %2 behavior-guidelines's number", get_disaster_behavior: 'value of item %3 of %1 %2 behavior-guidelines', behaviorConductLifeSafety_title: '%1', count_lifeSafety_behavior: "%1 %2 behavior-guidelines's number", get_lifeSafety_behavior: 'value of item %3 of %1 how to %2', tts_title: '%1', audio_title: '%1', video_title: '%1', read_text: 'read %1 %2', set_tts_property: 'set in a %1 voice at %2 speed and %3 pitch %4', read_text_wait_with_block: 'read %1 and wait %2', load_expansion_block: 'Add extention', load_ai_utilize_block: 'Load AI Block', load_ai_utilize_train_block: 'Training Model', expansion_block_descriptions: 'The expansion block works normally when the Internet is connected.', aiUtilize_block_descriptions: 'The A.I. Utilization block works normally when the Internet is connected.', weather_title_text: 'Weather', translate_title_text: 'Translate', festival_title_text: 'Festival', audio_title_text: 'Audio sensing', voice_title_text: 'Speech recognition', check_microphone: 'connected to microphone?', get_microphone_volume: 'microphone volume value', speech_to_text_title: '%1', speech_to_text_convert: 'Recognize %1 speech %2', timed_speech_to_text_convert: 'For %1 secs recognize %2 speech %3', set_visible_speech_to_text: '%1 recognized speech %2', speech_to_text_get_value: 'speech-to-text value', video_title_text: 'Video detection', video_draw_webcam: '%1 the camera screen', video_check_webcam: 'connected with video?', video_set_camera_opacity_option: 'Set video transparency effect to %1 %2', video_flip_camera: 'Flip camera screen %1 %2', video_toggle_model: '%1 recognition %2 %3', video_toggle_ind: '%2 detected %1 %3', video_number_detect: 'Number of detected %1', video_detected_face_info: '%2 of %1 th face', video_motion_value: 'Camera %2 value on %1', video_face_part_coord: '%3 coordinate of %2 in %1 th face', video_body_part_coord: "%3 coordinate of %1 th human's %2", behaviorConductDisaster_title_text: 'Disaster', behaviorConductLifeSafety_title_text: 'LifeSafety', emergencyActionGuidelines_title_text: 'Emergency action guidelines', count_disaster_guideline: 'number of guidelines in natural disaster %1 %2', get_disaster_guideline: '%3 th item of guidelines in natural disaster %1 %2', count_social_disaster_guideline: 'number of guidelines in social disaster %1 %2', get_social_disaster_guideline: '%3 th item of guidelines in social disaster %1 %2', count_safety_accident_guideline: 'number of guidelines in life safety accident %1 %2', get_safety_accident_guideline: '%3 th item of guidelines in life safety accident %1 %2', tts_title_text: 'Read', hamster_hand_found: 'hand found?', hamster_value: '%1', hamster_move_forward_once: 'move forward once on board %1', hamster_turn_once: 'turn %1 once on board %2', hamster_move_forward_for_secs: 'move forward for %1 secs %2', hamster_move_backward_for_secs: 'move backward for %1 secs %2', hamster_turn_for_secs: 'turn %1 for %2 secs %3', hamster_change_both_wheels_by: 'change wheels by left: %1 right: %2 %3', hamster_set_both_wheels_to: 'set wheels to left: %1 right: %2 %3', hamster_change_wheel_by: 'change %1 wheel by %2 %3', hamster_set_wheel_to: 'set %1 wheel to %2 %3', hamster_follow_line_using: 'follow %1 line using %2 floor sensor %3', hamster_follow_line_until: 'follow %1 line until %2 intersection %3', hamster_set_following_speed_to: 'set following speed to %1 %2', hamster_stop: 'stop %1', hamster_set_led_to: 'set %1 led to %2 %3', hamster_clear_led: 'clear %1 led %2', hamster_beep: 'beep %1', hamster_change_buzzer_by: 'change buzzer by %1 %2', hamster_set_buzzer_to: 'set buzzer to %1 %2', hamster_clear_buzzer: 'clear buzzer %1', hamster_play_note_for: 'play note %1 %2 for %3 beats %4', hamster_rest_for: 'rest for %1 beats %2', hamster_change_tempo_by: 'change tempo by %1 %2', hamster_set_tempo_to: 'set tempo to %1 bpm %2', hamster_set_port_to: 'set port %1 to %2 %3', hamster_change_output_by: 'change output %1 by %2 %3', hamster_set_output_to: 'set output %1 to %2 %3', roboid_hamster_beep: 'Hamster %1: beep %2', roboid_hamster_change_both_wheels_by: 'Hamster %1: change wheels by left: %2 right: %3 %4', roboid_hamster_change_buzzer_by: 'Hamster %1: change buzzer by %2 %3', roboid_hamster_change_output_by: 'Hamster %1: change output %2 by %3 %4', roboid_hamster_change_tempo_by: 'Hamster %1: change tempo by %2 %3', roboid_hamster_change_wheel_by: 'Hamster %1: change %2 wheel by %3 %4', roboid_hamster_clear_buzzer: 'Hamster %1: clear buzzer %2', roboid_hamster_clear_led: 'Hamster %1: clear %2 led %3', roboid_hamster_follow_line_until: 'Hamster %1: follow %2 line until %3 intersection %4', roboid_hamster_follow_line_using: 'Hamster %1: follow %2 line using %3 floor sensor %4', roboid_hamster_hand_found: 'Hamster %1: hand found?', roboid_hamster_move_backward_for_secs: 'Hamster %1: move backward for %2 secs %3', roboid_hamster_move_forward_for_secs: 'Hamster %1: move forward for %2 secs %3', roboid_hamster_move_forward_once: 'Hamster %1: move forward once on board %2', roboid_hamster_play_note_for: 'Hamster %1: play note %2 %3 for %4 beats %5', roboid_hamster_rest_for: 'Hamster %1: rest for %2 beats %3', roboid_hamster_set_both_wheels_to: 'Hamster %1: set wheels to left: %2 right: %3 %4', roboid_hamster_set_buzzer_to: 'Hamster %1: set buzzer to %2 %3', roboid_hamster_set_following_speed_to: 'Hamster %1: set following speed to %2 %3', roboid_hamster_set_led_to: 'Hamster %1: set %2 led to %3 %4', roboid_hamster_set_output_to: 'Hamster %1: set output %2 to %3 %4', roboid_hamster_set_port_to: 'Hamster %1: set port %2 to %3 %4', roboid_hamster_set_tempo_to: 'Hamster %1: set tempo to %2 bpm %3', roboid_hamster_set_wheel_to: 'Hamster %1: set %2 wheel to %3 %4', roboid_hamster_stop: 'Hamster %1: stop %2', roboid_hamster_turn_for_secs: 'Hamster %1: turn %2 for %3 secs %4', roboid_hamster_turn_once: 'Hamster %1: turn %2 once on board %3', roboid_hamster_value: 'Hamster %1: %2', roboid_turtle_button_state: 'Turtle %1: button %2 ?', roboid_turtle_change_buzzer_by: 'Turtle %1: change buzzer by %2 %3', roboid_turtle_change_head_led_by_rgb: 'Turtle %1: change head led by r: %2 g: %3 b: %4 %5', roboid_turtle_change_tempo_by: 'Turtle %1: change tempo by %2 %3', roboid_turtle_change_wheel_by: 'Turtle %1: change %2 wheel by %3 %4', roboid_turtle_change_wheels_by_left_right: 'Turtle %1: change wheels by left: %2 right: %3 %4', roboid_turtle_clear_head_led: 'Turtle %1: clear head led %2', roboid_turtle_clear_sound: 'Turtle %1: clear sound %2', roboid_turtle_cross_intersection: 'Turtle %1: cross black intersection %2', roboid_turtle_follow_line: 'Turtle %1: follow %2 line %3', roboid_turtle_follow_line_until: 'Turtle %1: follow black line until %2 %3', roboid_turtle_follow_line_until_black: 'Turtle %1: follow %2 line until black %3', roboid_turtle_is_color_pattern: 'Turtle %1: color pattern %2 %3 ?', roboid_turtle_move_backward_unit: 'Turtle %1: move backward %2 %3 %4', roboid_turtle_move_forward_unit: 'Turtle %1: move forward %2 %3 %4', roboid_turtle_pivot_around_wheel_unit_in_direction: 'Turtle %1: pivot around %2 wheel %3 %4 in %5 direction %6', roboid_turtle_play_note: 'Turtle %1: play note %2 %3 %4', roboid_turtle_play_note_for_beats: 'Turtle %1: play note %2 %3 for %4 beats %5', roboid_turtle_play_sound_times: 'Turtle %1: play sound %2 %3 times %4', roboid_turtle_play_sound_times_until_done: 'Turtle %1: play sound %2 %3 times until done %4', roboid_turtle_rest_for_beats: 'Turtle %1: rest for %2 beats %3', roboid_turtle_set_buzzer_to: 'Turtle %1: set buzzer to %2 %3', roboid_turtle_set_following_speed_to: 'Turtle %1: set following speed to %2 %3', roboid_turtle_set_head_led_to: 'Turtle %1: set head led to %2 %3', roboid_turtle_set_head_led_to_rgb: 'Turtle %1: set head led to r: %2 g: %3 b: %4 %5', roboid_turtle_set_tempo_to: 'Turtle %1: set tempo to %2 bpm %3', roboid_turtle_set_wheel_to: 'Turtle %1: set %2 wheel to %3 %4', roboid_turtle_set_wheels_to_left_right: 'Turtle %1: set wheels to left: %2 right: %3 %4', roboid_turtle_stop: 'Turtle %1: stop %2', roboid_turtle_touching_color: 'Turtle %1: touching %2 ?', roboid_turtle_turn_at_intersection: 'Turtle %1: turn %2 at black intersection %3', roboid_turtle_turn_unit_in_place: 'Turtle %1: turn %2 %3 %4 in place %5', roboid_turtle_turn_unit_with_radius_in_direction: 'Turtle %1: turn %2 %3 %4 with radius %5 cm in %6 direction %7', roboid_turtle_value: 'Turtle %1: %2', turtle_button_state: 'button %1 ?', turtle_change_buzzer_by: 'change buzzer by %1 %2', turtle_change_head_led_by_rgb: 'change head led by r: %1 g: %2 b: %3 %4', turtle_change_tempo_by: 'change tempo by %1 %2', turtle_change_wheel_by: 'change %1 wheel by %2 %3', turtle_change_wheels_by_left_right: 'change wheels by left: %1 right: %2 %3', turtle_clear_head_led: 'clear head led %1', turtle_clear_sound: 'clear sound %1', turtle_cross_intersection: 'cross black intersection %1', turtle_follow_line: 'follow %1 line %2', turtle_follow_line_until: 'follow black line until %1 %2', turtle_follow_line_until_black: 'follow %1 line until black %2', turtle_is_color_pattern: 'color pattern %1 %2 ?', turtle_move_backward_unit: 'move backward %1 %2 %3', turtle_move_forward_unit: 'move forward %1 %2 %3', turtle_pivot_around_wheel_unit_in_direction: 'pivot around %1 wheel %2 %3 in %4 direction %5', turtle_play_note: 'play note %1 %2 %3', turtle_play_note_for_beats: 'play note %1 %2 for %3 beats %4', turtle_play_sound_times: 'play sound %1 %2 times %3', turtle_play_sound_times_until_done: 'play sound %1 %2 times until done %3', turtle_rest_for_beats: 'rest for %1 beats %2', turtle_set_buzzer_to: 'set buzzer to %1 %2', turtle_set_following_speed_to: 'set following speed to %1 %2', turtle_set_head_led_to: 'set head led to %1 %2', turtle_set_head_led_to_rgb: 'set head led to r: %1 g: %2 b: %3 %4', turtle_set_tempo_to: 'set tempo to %1 bpm %2', turtle_set_wheel_to: 'set %1 wheel to %2 %3', turtle_set_wheels_to_left_right: 'set wheels to left: %1 right: %2 %3', turtle_stop: 'stop %1', turtle_touching_color: 'touching %1 ?', turtle_turn_at_intersection: 'turn %1 at black intersection %2', turtle_turn_unit_in_place: 'turn %1 %2 %3 in place %4', turtle_turn_unit_with_radius_in_direction: 'turn %1 %2 %3 with radius %4 cm in %5 direction %6', turtle_value: '%1', is_clicked: '%1', is_object_clicked: '%1', is_press_some_key: '%1 %2', reach_something: '%1 %2 %3', is_type: '%1 %2 %3 %4', boolean_comparison: '%1 %2 %3', boolean_equal: '%1 %2 %3', boolean_bigger: '%1 %2 %3', boolean_smaller: '%1 %2 %3', boolean_and_or: '%1 %2 %3', boolean_and: '%1 %2 %3', boolean_or: '%1 %2 %3', boolean_not: '%1 %2 %3', is_boost_mode: '%1', is_current_device_type: 'is the project running on %1 ?', is_touch_supported: 'touch screen?', true_or_false: '%1', True: '%1 ', False: '%1 ', boolean_basic_operator: '%1 %2 %3', show: 'Show shape %1', hide: 'Hide shape %1', dialog_time: '%3 %1 for %2 second(s) %4', dialog: '%2 %1 %3', remove_dialog: 'Remove speech bubble %1', change_to_nth_shape: 'Change shape to %1 %2', change_to_next_shape: 'Change to %1 shape %2', set_effect_volume: 'Change %1 effect by %2 %3', set_effect: 'Set %1 effect to %2 %3', erase_all_effects: 'Remove all effects %1', change_scale_percent: 'Change scale by %1 %2', set_scale_percent: 'Set scale to %1 %2', change_scale_size: 'Change size by %1 %2', set_scale_size: 'Set size to %1 %2', stretch_scale_size: 'Stretch %1 by %2 %3', reset_scale_size: 'Reset size %1', flip_y: 'Flip horizontally %1', flip_x: 'Flip vertically %1', set_object_order: 'go to %1 th layer %2', get_pictures: '%1 ', change_to_some_shape: 'Change shape to %1 %2', add_effect_amount: 'Apply %1 effect by %2 %3', change_effect_amount: 'Set %1 effect to %2 %3', set_effect_amount: 'Change %1 effect by %2 %3', set_entity_effect: 'Set %1 effect to %2 %3', change_object_index: 'Bring (to) %1 %2', move_direction: 'Move %1 forward %2', move_x: 'Change X by %1 %2', move_y: 'Change Y by %1 %2', locate_xy_time: 'Moving while %1 seconds to x: %2 y: %3 %4', rotate_by_angle: 'Rotate by %1 degree %2', rotate_by_angle_dropdown: 'Rotate by %1 degree %2', see_angle: 'Set direction to %1 %2', see_direction: 'Rotate to the %1 %2', locate_xy: 'Move to the X: %1 Y: %2 %3', locate_x: 'Move to the X: %1 %2', locate_y: 'Move to the Y: %1 %2', locate: 'Move to %1 %2', move_xy_time: 'For %1 secs move to X: %2 Y: %3 %4', rotate_by_angle_time: 'Rotate while %1 seconds by %2 degree %3', bounce_wall: 'if on edge, bounce %1', flip_arrow_horizontal: 'Flip horizontally by arrow direction %1', flip_arrow_vertical: 'Flip vertically by arrow direction %1', see_angle_object: 'Turn towards %1 %2', see_angle_direction: 'See angle to %1 degree %2', rotate_direction: 'Change direction by %1 %2', locate_object_time: 'for %1 secs move to %2 %3', rotate_absolute: 'Set rotation to %1 %2', rotate_relative: 'Rotate %1 %2', direction_absolute: 'Set direction to %1 %2', direction_relative: 'Change direction by %1 %2', move_to_angle: 'Rotate %1 and move %2 %3', rotate_by_time: 'For %1 secs rotate %2 %3', direction_relative_duration: 'For %1 secs set direction to %2 %3', neobot_sensor_value: '%1 값', neobot_turn_left: 'Rotate left motor %1 %2 %3', neobot_stop_left: 'Stop left motor %1', neobot_turn_right: 'Rotate right motor %1 %2 %3', neobot_stop_right: 'Stop right motor %1', neobot_run_motor: 'Run %1 motor for %2 secs', neobot_servo_1: 'Move the servo motor connected to SERVO1 to %2 with the speed of %1 %3', neobot_servo_2: 'Move the servo motor connected to SERVO2 to %2 with the speed of %1 %3', neobot_play_note_for: 'Play %1 melody to octave %2 as long as %3 %4', neobot_set_sensor_value: '%1 value of the port to %2 %3', robotis_openCM70_cm_custom_value: 'Custom address ( %1 ) value %2', robotis_openCM70_sensor_value: 'Controller value %1', robotis_openCM70_aux_sensor_value: 'Value %1 %2', robotis_openCM70_cm_buzzer_index: 'Play %1 controller scale value for %2 seconds %3 ', robotis_openCM70_cm_buzzer_melody: 'Play controller melody %1 times %2', robotis_openCM70_cm_sound_detected_clear: 'Initialize the final number of sound detection %1', robotis_openCM70_cm_led: 'Controller %1 LED %2 %3', robotis_openCM70_cm_motion: 'Play the motion %1 times', robotis_openCM70_cm_autodrive_motor: 'Autonomous driving car %1 motor uses %2 %3', robotis_openCM70_cm_autodrive_ir: 'Autonomous driving car %1 IR sensor uses %2 %3', robotis_openCM70_cm_autodrive_speed: 'Perform autonomous driving at the speed of %1 %2', robotis_openCM70_aux_car_move: 'Make the robot %2 at a speed of %1% %3', robotis_openCM70_aux_motor_speed: 'Set the speed of decelerating motor of %1 to %2 , and the output value to %3% %4', robotis_openCM70_aux_servo_mode: 'Set the mode of %1 servo motor to %2 %3', robotis_openCM70_aux_servo_speed: 'Set the speed of servo motor of %1 to %2 , and the output value to %3% %4', robotis_openCM70_aux_servo_position: 'Set the position of %1 servo motor to %2 degree %3', robotis_openCM70_aux_led_module: 'Set the LED module of %1 as %2 %3', robotis_openCM70_aux_custom: 'Set the user device of %1 as %2 %3', robotis_openCM70_cm_poweroff_timer: 'Set auto-off timer as %1 %2', robotis_openCM70_cm_custom: 'Set the custom address ( %1 ) as %2 %3', robotis_carCont_sensor_value: 'Value %1', robotis_carCont_cm_led: '%1 LED 4, %2 LED %3', robotis_carCont_cm_sound_detected_clear: 'Initialize the final number of sound detection %1', robotis_carCont_aux_motor_speed: 'Set the speed of decelerating motor of %1 to %2, and the output value to %3 %4', robotis_carCont_cm_calibration: 'Set %1 value of infrared sensor calibration to %2 %3', roduino_get_analog_number: '%1 ', roduino_get_port_number: '%1 ', roduino_get_analog_value: 'Analog %1 Sensor value ', roduino_get_digital_value: 'Digital %1 Sensor value ', roduino_set_digital: 'Digital %1 Pin %2 %3', roduino_motor: '%1 %2 %3', roduino_set_color_pin: 'Color Sensor R : %1, G : %2, B : %3 %4', roduino_get_color: 'Color Sensor %1 Detected ', roduino_on_block: ' On ', roduino_off_block: ' Off ', schoolkit_get_in_port_number: '%1 ', schoolkit_get_out_port_number: '%1 ', schoolkit_get_servo_port_number: '%1 ', schoolkit_get_input_value: 'Digital %1 Sensor value ', schoolkit_set_output: 'Digital %1 Pin %2 %3', schoolkit_motor: '%1 Speed %2 %3 %4', schoolkit_set_servo_value: 'Servo %1 Pin %2˚ %3', schoolkit_on_block: ' On ', schoolkit_off_block: ' Off ', when_scene_start: '%1 When scene started', start_scene: 'Start %1 scene %2', start_neighbor_scene: 'Start %1 scene %2', sound_something: 'Play %1 Sound %2', sound_something_second: 'Play %1 sound for %2 secs %3', sound_something_wait: 'Play %1 Sound and wait %2', sound_something_second_wait: 'Play %1 Sound for %2 secs and wait %3', sound_volume_change: 'Change volume by %1 %2', sound_volume_set: 'Set volume to %1 % %2', get_sound_speed: 'Speed', sound_speed_change: 'Change speed by %1 %2', sound_speed_set: 'Set speed at %1 times %2', sound_silent_all: 'Stop sound of %1 %2', play_bgm: 'Play %1 as background music %2', stop_bgm: 'Stop background music %1', get_sounds: '%1 ', sound_something_with_block: 'Play %1 sound %2', sound_something_second_with_block: 'Play %1 sound for %2 secs %3', sound_something_wait_with_block: 'Play %1 sound and wait %2', sound_something_second_wait_with_block: 'Play %1 sound for %2 secs and wait %3', sound_from_to: 'Play %1 sound from %2 to %3 secs %4', sound_from_to_and_wait: 'Play %1 sound from %2 to %3 secs and wait %4', messageAddButton: '%1', when_run_button_click: '%1 When run', press_some_key: '%1 When key %2 pressed %3', when_some_key_pressed: '%1 When key %2 pressed', mouse_clicked: '%1 When mouse clicked', mouse_click_cancled: '%1 When mouse click released', when_object_click: '%1 When object clicked', when_object_click_canceled: '%1 When object click released', when_some_key_click: '%1 When press some key', when_message_cast: '%1 When %2 message received', message_cast: 'Send %1 message %2', message_cast_wait: 'Send %1 message and wait %2', text: '%1', text_read: 'Textbox %1’s contents', text_write: 'Writing that %1 %2', text_append: 'After writing that %1 %2', text_prepend: 'Add %1 in front of that %2', text_flush: 'Remove all text %1', analizyDataAddButton: '%1', append_row_to_table: 'Add a %2 to table %1 %3', insert_row_to_table: 'Insert %3 to %2 th row in table %1 %4', delete_row_from_table: 'Remove %2 th %3 in table %1 %4', set_value_from_table: 'Change %3 in table %1 %2 th row to %4 %5', save_current_table: 'Save table %1 as it is %2', get_table_count: 'number of %2 in table %1', get_value_from_table: '%3 value of %2 th row in table %1', get_value_from_last_row: '%2 value of the last row in table %1', calc_values_from_table: '%3 of %2 in table %1', open_table: 'Open table %1 window %2', open_table_wait: 'Open table %1 window for %2 second(s) %3', open_table_chart: 'Open chart %2 of table %1 %3', close_table_chart: 'Close table chart %1', get_coefficient: 'correlation coefficient between %2 and %3 in table %1', set_value_from_cell: 'Change %2 cell in table %1 to %3 %4', get_value_from_cell: 'value of %2 cell in table %1', get_value_v_lookup: '%4 value of the row that %2 is %3 in table %1', variableAddButton: '%1', listAddButton: '%1', change_variable: 'Plus to %1 by %2 %3', set_variable: 'Set %1 to %2 %3', show_variable: 'Show variable %1 value %2', hide_variable: 'Hide variable %1 value %2', get_variable: '%2 %1', ask_and_wait: 'Ask %1 and wait %2', get_canvas_input_value: '%1 ', add_value_to_list: 'add %1 to the list %2 %3', remove_value_from_list: 'remove %1 th element from %2 %3', insert_value_to_list: 'insert %1 to %2 %3 th position %4', change_value_list_index: 'change %1 %2 th element to %3 %4', value_of_index_from_list: '%1 %2 %3 %4 %5', length_of_list: '%1 %2 %3', show_list: 'Show list %1 %2', hide_list: 'Hide list %1 %2', options_for_list: '%1 ', set_visible_answer: 'response %1 %2', is_included_in_list: '%1 %2 %3 %4 %5', xbot_digitalInput: '%1', xbot_analogValue: '%1', xbot_digitalOutput: 'Digital %1 PIN, Ouput Value %2 %3', xbot_analogOutput: 'Analog %1 %2 %3', xbot_servo: 'Servo Motor %1 , Angle %2 %3', xbot_oneWheel: 'Wheel(DC) Motor %1 , Speed %2 %3', xbot_twoWheel: 'Wheel(DC) Motor Right(2) Speed: %1 Left(1) Speed: %2 %3', xbot_rgb: 'RGB LED Color from Red %1 Green %2 Blue %3 %4', xbot_rgb_picker: 'RGB LED Color from %1 %2', xbot_buzzer: 'play note %1 %2 for %3 sec of Melody Playing %4', xbot_lcd: 'LCD %1 th Line , Text %2 %3', run: '', mutant: 'test mutant block', jr_start: '%1', jr_repeat: 'Repeat %1 %2', jr_item: 'Gather flower %1', cparty_jr_item: 'Pick up %1', jr_north: 'Up %1', jr_east: 'Right %1', jr_south: 'Down %1', jr_west: 'Left %1', jr_start_basic: '%1 %2', jr_go_straight: 'Go forward %1', jr_turn_left: 'Turn left %1', jr_turn_right: 'Turn right %1', jr_go_slow: 'Go slow %1', jr_repeat_until_dest: 'Repeat until meeting up with %1 %2', jr_if_construction: 'If %1 in front %2', jr_if_speed: 'If %1 in front %2', maze_step_start: '%1 When Run', maze_step_jump: 'Skip%1', maze_step_jump2: 'Jump%1', maze_step_jump_pinkbean: 'Jump%1', maze_step_for: 'Repeat %1 times %2', test: '%1 this is test block %2', maze_repeat_until_1: 'Repeat until meeting up with %1 %2', maze_repeat_until_2: 'Repeat until meeting up with all %1 %2', maze_step_if_1: 'If %1 is in front %2', maze_step_if_2: 'If %1 is in front %2', maze_call_function: 'Import promise %1', maze_define_function: 'Promise %1', maze_step_if_3: 'If %1 is in front %2', maze_step_if_4: 'If %1 is in front %2', maze_step_move_step: 'Move one step forward %1', maze_step_rotate_left: 'Turn to the left %1', maze_step_rotate_right: 'Turn to the right %1', maze_step_forward: 'Go forward %1', maze_turn_right: 'look right side %1', maze_turn_left: 'look left side %1', maze_ladder_climb: 'Climb ladder%1', maze_attack_lupin: 'Attack %1 %2', maze_attack_both_side: 'Attack both sides%1', maze_attack_pepe: 'Attack %1 %2', maze_attack_yeti: 'Attack %1 %2', maze_attack_mushroom: 'Attack %1 %2', maze_attack_peti: 'Attack %1 %2', maze_eat_item: 'Take food%1', maze_step_if_mushroom: 'If there is %1 one space forward %2', maze_step_if_yeti: 'If there is %1 in front %2 %3 else', maze_step_if_left_monster: 'If there is a monster in the left side attack range %1 %2 else', maze_step_if_right_monster: 'If there is a monster in the right side attack range %1 %2 else', maze_step_if_lupin: 'If there is %1 two spaces forward %2', maze_step_if_else_road: 'If there is road one space forward %1 %2else', maze_step_if_else_mushroom: 'If there is %1 one space forward %2 %3 else', maze_step_if_else_lupin: 'If there is %1 two spaces forward %2 %3 else', maze_step_if_else_ladder: 'If there is %1 one space forward %2 %3 else', maze_rotate_left: 'Spin to the left %1', maze_rotate_right: 'Spin to the right %1', maze_moon_kick: 'Kick %1', maze_repeat_until_3: 'Repeat until meeting up with %1 %2', maze_repeat_until_4: 'Repeat until meeting up with %1 %2', maze_repeat_until_5: 'Repeat until meeting up with %1 %2', maze_repeat_until_6: 'Repeat until arriving to %1 %2', maze_repeat_until_7: 'Repeat until reaching %1 %2', maze_repeat_until_goal: 'Repeat until arrival to destination%1', maze_repeat_until_beat_monster: 'Repeat until all monsters are defeated %1', maze_radar_check: '%2 is in %1', maze_cony_flower_throw: 'Throw flower %1', maze_brown_punch: 'Punch %1', maze_iron_switch: 'Control obstacles %1', maze_james_heart: 'Toss cakes %1', maze_step_if_5: 'If there is no road in front %2', maze_step_if_6: "If %1 isn't in front %2", maze_step_if_7: 'If %1 is in front %2', maze_step_if_8: 'If it is %1 %2', maze_step_if_else: 'If it is %1 %2 %3 or', test_wrapper: '%1 this is test block %2', basic_button: '%1', ai_move_right: 'move forward %1', ai_move_up: 'go above %1', ai_move_down: 'go under %1', ai_repeat_until_reach: 'repeat until destination %1', ai_if_else_1: 'if %1 in front %2 %3 else', ai_boolean_distance: '%1 radar %2 %3', ai_distance_value: '%1 radar', ai_boolean_object: 'is %1 object %2 ?', ai_use_item: 'use item %1', ai_boolean_and: '%1 %2 %3', ai_True: '%1', ai_if_else: 'If %1 then %2 %3 else', smartBoard_convert_scale: 'Map Value %1 %2 ~ %3 to %4 ~ %5', smartBoard_get_named_sensor_value: '%1 Sensor value', smartBoard_is_button_pressed: 'Pressed %1 button?', smartBoard_set_dc_motor_direction: '%1 DC Motor change direction %2 %3', smartBoard_set_dc_motor_speed: '%1 DC Motor %2 %3', smartBoard_set_dc_motor_pwm: '%1 DC Motor set speed %2 %3', smartBoard_set_servo_speed: '%1 RC Servo Motor Speed %2 %3', smartBoard_set_servo_angle: '%1 RC Servo Motor set angle %2 %3', smartBoard_set_number_eight_pin: '%1 port %2 %3', smartBoard_set_gs1_pwm: 'GS1 port %1 %2', robotori_digitalInput: '%1', robotori_analogInput: '%1', robotori_digitalOutput: 'Digital %1 PIN, Output Value %2 %3', robotori_analogOutput: 'Analog %1 %2 %3', robotori_servo: 'Servo Motor Angle %1 %2', robotori_dc_direction: 'DC Motor %1 Direction %2 %3', dadublock_get_analog_value: 'Analog %1 Sensor value', dadublock_get_analog_value_map: 'Map Value %1 %2 ~ %3 to %4 ~ %5 ', dadublock_get_ultrasonic_value: 'Read ultrasonic sensor trig pin %1 echo pin %2', dadublock_toggle_led: 'Digital %1 Pin %2 %3', dadublock_digital_pwm: 'Digital %1 Pin %2 %3', dadublock_set_tone: 'Play tone pin %1 on note %2 octave %3 beat %4 %5', dadublock_set_servo: 'Set servo pin %1 angle as %2 %3', coconut_stop_motor: 'stop motor %1', coconut_move_motor: 'move %1 %2', coconut_turn_motor: 'turn %1 %2', coconut_move_for_secs: 'move %1 for time %2 %3', coconut_turn_for_secs: 'turn %1 for %2 secs %3', coconut_turn_to_led: 'turn %1 RGB %2 %3', coconut_move_outmotor: 'external Motor %1 speed %2 %3', coconut_set_led_to: 'turn on RGB %1 %2 %3', coconut_clear_led: 'turn off RGB %1 %2', coconut_set_led_clear: 'turn off RGB %1 %2 %3', coconut_set_led_time: 'turn on RGB %1 %2 for time %3 %4', coconut_beep: 'buzzer on %1', coconut_buzzer_time: 'play buzzer for time %1 %2', coconut_buzzer_set_hz: 'play buzzer on frequency %1 Hz for time %2 %3', coconut_clear_buzzer: 'buzzer off %1', coconut_play_buzzer: 'play buzzer on note %1 octave %2 %3 beat %4 %5', coconut_rest_buzzer: 'rest beat %1 %2', coconut_play_buzzer_led: 'play buzzer on note %1 octave %2 %3 beat %4 RGB %5 %6 %7', coconut_play_midi: 'play melody %1 %2', coconut_floor_sensor: 'line tracer %1', coconut_floor_sensing: 'line tracer detect %1 %2', coconut_following_line: 'follow the line %1', coconut_front_sensor: 'IR distance sensor %1', coconut_front_sensing: 'detecting obstacle %1 %2', coconut_obstruct_sensing: 'detecting obstacle', coconut_avoid_mode: 'avoid mode %1', coconut_dotmatrix_set: 'LED Matrix %1 ( ROW %2, COL %3 ) %4', coconut_dotmatrix_on: 'turn on all LED Matrix %1', coconut_dotmatrix_off: 'LED Matrix clear all %1', coconut_dotmatrix_num: 'LED Matrix show %1 %2', coconut_dotmatrix_small_eng: 'LED Matrix show small letter %1 %2', coconut_dotmatrix_big_eng: 'LED Matrix show capital letters %1 %2', coconut_dotmatrix_kor: 'LED Matrix show Korean %1 %2', coconut_light_sensor: 'light sensor', coconut_tem_sensor: 'temperature', coconut_ac_sensor: '3-Axis Accelerometer %1 angle', coconut_outled_sensor: 'set external LED pin %1 for time %2 %3', coconut_outspk_sensor: 'set Speaker pin %1 frequency %2 (Hz) duration %3 seconds %4', coconut_outspk_sensor_off: 'stop Speaker pin %1 %2', coconut_outinfrared_sensor: 'external IR sensor %1', coconut_outcds_sensor: 'external Cds sensor %1', coconut_servomotor_angle: 'set servo pin %1 angle as %2 %3', chocopi_control_button: '%1 controller %2 is pressed', chocopi_control_event: '%1 When %2 controller %3 is %4', chocopi_control_joystick: '%1 controller %2 value', chocopi_dc_motor: '%1 DC motor #%2 %3 % direction %4 %5', chocopi_led: '%1 LED #%2 RGB(%3 %4 %5) %6', chocopi_motion_photogate_event: '%1 When %2 photogate %3 is %4', chocopi_motion_photogate_status: '%1 photogate #%2 is blocked', chocopi_motion_photogate_time: 'time when %1 photogate %2 was %3', chocopi_motion_value: '%1 motion %2 value', chocopi_sensor: '%1 sensor %2', chocopi_servo_motor: '%1 set servo motor #%2 %3 degree %4', chocopi_touch_event: '%1 When %2 touch pad%3 is %4', chocopi_touch_status: '%1 touch pad%2 is touched', chocopi_touch_value: '%1 touch pad%2 value', dadublock_car_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', dadublock_car_get_analog_value: '아날로그 %1 번 센서값', dadublock_car_get_analog_value_map: '아날로그 %1번 센서값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', dadublock_car_get_digital: '디지털 %1 번 센서값', dadublock_car_get_irsensor: '적외선 %1 번 센서값', dadublock_car_get_ultrasonic_value: '울트라소닉 Trig %1번핀 Echo %2번핀 센서값', dadublock_car_motor: '모터 %1 번을 %2 (으)로 %3 %의 속도로 움직이기 %4', dadublock_car_motor_stop: '모터 %1 번 멈추기 %2', dadublock_car_set_servo: '서보모터 %1 번 핀을 %2 의 각도로 정하기 %3', dadublock_car_set_tone: '디지털 %1 번 핀 을 %2 음으로 %3의 옥타브로 %4 만큼 연주하기 %5', dadublock_car_toggle_led: '디지털 %1 번 핀 %2 %3', dadublock_get_digital: '디지털 %1 번 센서값', ev3_get_sensor_value: "%1's value", ev3_touch_sensor: "%1's touch sensor activted?", ev3_color_sensor: "%1's %2 value", ev3_motor_power: "%1's value print as %2 %3", ev3_motor_power_on_time: "%1's value for %2seconds %3 printed %4", ev3_motor_degrees: "%1's value in %2 direction turn %3 degrees %4", rokoboard_get_sensor_value_by_name: '%1 value', ardublock_digital_pwm: 'Digital %1 Pin %2 %3', ardublock_get_analog_value: 'Analog %1 Sensor value', ardublock_get_analog_value_map: 'Map Value %1 %2 ~ %3 to %4 ~ %5', ardublock_get_digital: 'Digital %1 Sensor value', ardublock_get_left_cds_analog_value: 'Left CDS %1 Sensor value', ardublock_get_right_cds_analog_value: 'Left CDS %1 Sensor value', ardublock_get_sound_analog_value: 'Analog Sound %1 Sensor value', ardublock_get_ultrasonic_value: 'Read ultrasonic sensor trig pin %1 echo pin %2', ardublock_set_left_motor: 'Left motor direction to %1 speed %2 set %3', ardublock_set_right_motor: 'Right motor direction to %1 speed %2 set %3', ardublock_set_servo: 'Set servo pin %1 angle as %2 %3', ardublock_set_tone: 'Play tone pin %1 on note %2 octave %3 beat %4 %5', ardublock_toggle_led: 'Digital %1 Pin %2 %3', ardublock_toggle_left_led: 'Left Light %1 Pin %2 %3', ardublock_toggle_right_led: 'Right Light %1 Pin %2 %3', mkboard_digital_pwm: 'Digital %1 Pin %2 %3', mkboard_get_analog_value: 'Analog %1 Sensor value', mkboard_get_analog_value_map: 'Map Value %1 %2 ~ %3 to %4 ~ %5', mkboard_get_digital: 'Digital %1 Sensor value', mkboard_get_ultrasonic_value: 'Read ultrasonic sensor trig pin %1 echo pin %2', mkboard_set_servo: 'Set servo pin %1 angle as %2 %3', mkboard_set_tone: 'Play tone pin %1 on note %2 octave %3 beat %4 %5', mkboard_toggle_led: 'Digital %1 Pin %2 %3', mkboard_set_lcd: '1602 LCD Row %1, Column %2 Value %3 %4', mkboard_lcd_command: '1602 LCD Command %1 execute %2', altino_analogValue: 'altino %1 sensor value', altino_dot_display: 'electronic scoreboard %1 display %2', altino_dot_display_line: '1col %1 2col %2 3col %3 4col %4 5col %5 6col %6 7col %7 8col %8 display %9', altino_light: '%1 light %2 %3', altino_rear_wheel: 'rear motor right %1 left %2 setting %3', altino_sound: '%1 octave %2 play %3', altino_steering: 'direction %1 setting %2', jdkit_altitude: '드론을 %1 높이만큼 날리기 %2', jdkit_button: '%1번 버튼 값 읽어오기', jdkit_connect: '드론 연결 상태 읽어오기', jdkit_emergency: '드론을 즉시 멈추기 %1', jdkit_gyro: '보드 %1 기울기 값 읽어오기', jdkit_joystick: '조이스틱 %1 읽기', jdkit_led: '%1 LED %2 %3', jdkit_motor: '%1 모터를 %2 세기로 돌리기 %3', jdkit_ready: '드론 비행 준비 상태 읽어오기', jdkit_rollpitch: '드론을 %1 방향 %2 세기로 움직이기 %3', jdkit_throttle: '드론 프로펠러를 %1 만큼 세기로 돌리기 %2', jdkit_tune: '%1 음을 %2 초동안 소리내기 %3', jdkit_ultrasonic: '거리(초음파)값 읽어오기', jdkit_yaw: '드론을 %1 만큼 회전하기 %2', memaker_digital_pwm: 'Digital %1 Pin %2 %3', memaker_get_analog_value: 'Analog %1 Sensor value', memaker_get_analog_value_map: 'Map Value %1 %2 ~ %3 to %4 ~ %5', memaker_get_digital: 'Digital %1 Sensor value', memaker_get_ultrasonic_value: 'Read ultrasonic sensor trig pin %1 echo pin %2', memaker_set_lcd: '1602 LCD Row %1, Column %2 Value %3 %4', memaker_set_servo: 'Set servo pin %1 angle as %3', memaker_toggle_led: 'Digital %1 Pin %2 %3', memaker_lcd_command: '1602 LCD Command %1 execute %2', edumaker_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', edumaker_get_analog_value: '아날로그 %1 번 센서값', edumaker_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', edumaker_get_digital: '디지털 %1 번 센서값', edumaker_get_ultrasonic_value: '울트라소닉 Trig %1 Echo %2 센서값', edumaker_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', edumaker_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', edumaker_toggle_led: '디지털 %1 번 핀 %2 %3', creamo_get_number_sensor_value: 'PWM_Block %1 Sensor value', creamo_get_port_number: '%1', creamo_get_pwm_port_number: '%1', creamo_motor_port_number: '%1', creamo_toggle_led: 'LED_Block %1 Pin %2 %3', creamo_toggle_motor: 'Motor_Block %1 pin %2 %3', creamo_toggle_pwm: 'Digital %1 Pin %2 %3', mechatro_get_dc_motor_current: 'Get 1%motor current', mechatro_get_digital: '%1', mechatro_get_sensor_value: 'Analog %1 Sensor value', mechatro_get_ultrasonic_value: 'Read ultrasonic sensor trig pin %1 echo pin %2', mechatro_set_blue_pw: 'Change PW of Bluetooth to %1%2%3%4 %5', mechatro_set_dc_motor: 'Set %1 motor speed to %2 %3', mechatro_set_digital: 'Digital %1 Pin %2 %3', mechatro_set_pwm: 'Digital %1 Pin %2 %3', mechatro_set_servo_position: 'Set servo pin %1 angle as %2 %3', mechatro_set_servo_speed: 'Set servo pin %1 speed %2 degree per second %3', mechatro_set_threshold: 'Set %1 threshold : %2%3', mechatro_set_tone: 'Play tone pin %1 on note %2 octave %3 %4', mechatro_set_tone_time: 'Play tone pin %1 on note %2 octave %3 beat %4 %5', funboard_buzzer_onoff: 'buzzer %1 %2', funboard_buzzer_second: 'buzzer%1%2seconds%3', funboard_buzzer_tone_simple: 'play note%1%2,%3sec of Melody Playing%4', funboard_color_led_on_pwm: '%1COLOR LED %2 % %3', funboard_color_led_onoff: '%1COLOR LED %2 %3', funboard_convert_scale: 'Convert %1 value from %2~%3 to %4~%5', funboard_dotmatrix_1column: '%1column %2set %3', funboard_dotmatrix_1row: '%1row %2set %3', funboard_dotmatrix_1row_1column: '%1%2 %3set %4', funboard_dotmatrix_64_display: '%1 (8x8)display%2', funboard_dotmatrix_big_eng: 'capital letters %1 %2', funboard_dotmatrix_char_display: 'char%1display%2', funboard_dotmatrix_extra_char: 'char %1 %2', funboard_dotmatrix_intensity: 'Intensity %1% %2', funboard_dotmatrix_kor: '∷∷ korean %1 %2', funboard_dotmatrix_num: 'number %1 %2', funboard_dotmatrix_onoff: 'turn all %1 %2', funboard_dotmatrix_scroll_option: 'scroll direction%1%2', funboard_dotmatrix_scroll_rapid: 'scroll rapid %1% %2', funboard_dotmatrix_set: '%1row %2column %3 %4', funboard_dotmatrix_small_eng: 'small letter %1 %2', funboard_dotmatrix_string_display: 'string%1display%2', funboard_dotmatrix_string_display_scroll: 'string%1display%2scroll%3', funboard_dotmatrix_symbol: 'symbol %1 %2', funboard_get_analog_sensor_2state: '%1 value %2', funboard_get_digital_button_value: '%1 button value', funboard_get_number_sensor_value: '%1 value', funboard_get_touch_button_value: '%1 touch button value', funboard_set_digital_buzzer: 'Play tone octave %1 note %2 beat %3 %4', funboard_what_button_pressed: '%1 button pressed.', funboard_what_touch_button_pressed: '%1 touch button pressed.', media_pipe_title: '%1', media_pipe_video_screen: '%1 video screen %2', media_pipe_switch_camera: 'Switch to %1 camera %2', check_connected_camera: 'Connected to camera?', media_pipe_flip_camera: 'Flip video screen %1 %2', media_pipe_set_opacity_camera: 'Set video transparency effect to %1 %2', media_pipe_motion_value: '%2 value detected on %1', pose_landmarker_title: '%1', when_pose_landmarker: '%1 When human detected', pose_landmarker: '%1 human detection %2', draw_detected_pose: '%1 detected human %2', check_detected_pose: 'Detected human?', count_detected_pose: 'Number of detected human', locate_to_pose: 'Go to %2 of %1 th human %3', locate_time_to_pose: 'For %1 secs go to %3 of %2 th human %4', axis_detected_pose: "%3 coordinate of %1 th human's %2", face_landmarker_title: '%1', when_face_landmarker: '%1 When face detected', face_landmarker: '%1 face detection %2', draw_detected_face: '%1 detected face %2', check_detected_face: 'Detected face?', count_detected_face: 'Number of detected face', locate_to_face: 'Go to %2 of %1 th face %3', locate_time_to_face: 'For %1 secs go to %3 of %2 th face %4', check_detected_gender: 'Is the gender of %1 th face %2?', check_compare_age: 'Is the age of %1 th face %2 %3?', check_detected_emotion: 'Is the emotion of %1 th face %2?', axis_detected_face: '%3 coordinate of %1 the face`s %2', get_detected_face_value: '%2 of %1 th face', object_detector_title: '%1', when_object_detector: '%1 When object detected', object_detector: '%1 object detection %2', draw_detected_object: '%1 detected object %2', check_detected_object: 'Detected object?', count_detected_object: 'Number of detected object', is_detected_among_objects: '%1 detected among the objects?', hand_detection_title: '%1', when_hand_detection: '%1 When hand detected', hand_detection: '%1 hand detection %2', draw_detected_hand: '%1 detected hand %2', check_detected_hand: 'Detected hand?', count_detected_hand: 'Number of detected hand', locate_to_hand: 'Go to %3 of %2 of in %1 th hand %4', locate_time_to_hand: 'For %1 secs go to %4 of %3 of in %2 th hand %5', axis_detected_hand: '%4 coordinate of %3 of %2 in %1 th hand', is_which_hand: 'Is %1 th hand %2?', is_which_gesture: 'Is the gesture of %1 th hand %2 ?', get_which_hand: '%1 th hand', get_which_gesture: 'The gesture of %1 th hand', function_create_value: 'Define function %1 %2 %3 Return %4', learning_title_image_str: 'Trained image classification model', learning_title_speech_str: 'Trained speech classification model', learning_title_text_str: 'Trained text classification model', learning_title_number_str: 'Trained number classification model', learning_title_regression_str: 'Trained regression model', learning_title_cluster_str: 'Trained clustering model', text_change_effect: '%2 %1 effect to text box %3', text_change_font: 'Change font to %1 %2', text_change_font_color: 'Change text color to %1 %2', text_change_bg_color: 'Change background color to %1 %2', learning_title_image: '%1', learning_title_speech: '%1', learning_title_text: '%1', learning_title_number: '%1', learning_title_regression: '%1', learning_title_cluster: '%1', insert_data_for_test: 'Classify with the trained model %1', video_capture_for_image_test: '%1 classifying camera screen with the trained model ', insert_text_block_for_test: 'Classify %1 with trained model %2', test_result: 'Classification result', accuracy_of_result: 'Reliability of %1', is_group: 'Is the classification result %1?', retrain_model: 'Retrain model %1', model_is_trained: 'Has the model trained?', set_train_visible: '%1 model %2', set_train_chart: '%1 model chart window %2', set_regression_option: 'Change %1 training condition to %2 %3', get_regression_predict_1: 'Predicted value of %1 %2', get_regression_predict_2: 'Predicted value of %1 %2 %3 %4', get_regression_predict_3: 'Predicted value of %1 %2 %3 %4 %5 %6', get_regression_predict_4: 'Predicted value of %1 %2 %3 %4 %5 %6 %7 %8', get_regression_predict_5: 'Predicted value of %1 %2 %3 %4 %5 %6 %7 %8 %9 %10', get_regression_predict_6: 'Predicted value of %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12', get_regression_accuracy: 'Coefficient of determination', set_cluster_option_k: 'Change the number of clusters to %1 %2', set_cluster_option_centroids: 'Change centroid standard to %1 %2', get_cluster_centriod_count: 'Number of clusters', get_cluster_centriod_value: 'Value of %2 of cluster %1 centroid', get_cluster_centriod_index_1: 'Cluster of %1 %2', get_cluster_centriod_index_2: 'Cluster of %1 %2 %3 %4', get_cluster_centriod_index_3: 'Cluster of %1 %2 %3 %4 %5 %6', get_cluster_centriod_index_4: 'Cluster of %1 %2 %3 %4 %5 %6 %7 %8', get_cluster_centriod_index_5: 'Cluster of %1 %2 %3 %4 %5 %6 %7 %8 %9 %10', get_cluster_centriod_index_6: 'Cluster of %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12', set_number_learning_option_k: 'Change the number of neighbors to %1 %2', get_number_learning_predict_1: 'Classification result of %1 %2', get_number_learning_predict_2: 'Classification result of %1 %2 %3 %4', get_number_learning_predict_3: 'Classification result of %1 %2 %3 %4 %5 %6', get_number_learning_predict_4: 'Classification result of %1 %2 %3 %4 %5 %6 %7 %8', get_number_learning_predict_5: 'Classification result of %1 %2 %3 %4 %5 %6 %7 %8 %9 %10', get_number_learning_predict_6: 'Classification result of %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12', get_number_learning_predict_param_1: '%4 for %3 of %1 %2', get_number_learning_predict_param_2: '%6 for %5 of %1 %2 %3 %4', get_number_learning_predict_param_3: '%8 for %5 of %1 %2 %3 %4 %5 %6', get_number_learning_predict_param_4: '%8 for %5 of %1 %2 %3 %4 %5 %6 %7 %8', get_number_learning_predict_param_5: '%8 for %5 of %1 %2 %3 %4 %5 %6 %7 %8 %9 %10', get_number_learning_predict_param_6: '%8 for %5 of %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12', is_number_learning_group_1: 'Is the classification result of %1 %2 %3?', is_number_learning_group_2: 'Is the classification result of %1 %2 %3 %4 %5?', is_number_learning_group_3: 'Is the classification result of %1 %2 %3 %4 %5 %6 %7?', is_number_learning_group_4: 'Is the classification result of %1 %2 %3 %4 %5 %6 %7 %8 %9?', is_number_learning_group_5: 'Is the classification result of %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11?', is_number_learning_group_6: 'Is the classification result of %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13?', video_change_cam: 'Switch to %1 camera %2', video_is_model_loaded: 'detected %1?', video_object_detected: 'Is %1 recognized among objects?', function_value: 'Function', }; Lang.TextCoding = { block_name: 'Block Name', title_syntax: 'Syntax Error', title_converting: 'Converting Error', message_syntax_default: 'Syntax error occured', message_syntax_unexpected_token: 'Unexpected token exist', message_syntax_reserved_token: 'Unavailable variable name.', message_syntax_reserved_token_list: 'Unavailable list name.', message_syntax_unexpected_character: 'Unexpected characters exist', message_syntax_unexpected_indent: 'Unexpected indent exist', message_conv_default: 'Unsupported code exists', message_conv_no_support: 'Unconvertable code exists', message_conv_no_variable: 'Variable did not declare', message_conv_no_list: 'List did not declare', message_conv_no_object: "Object can't convert", message_conv_no_function: "Function can't convert", message_conv_no_entry_event_function: "Entry Event Function can't exist within other functions.", message_conv_undefined_function: 'Undefined instruction. Please make sure you instruction correctly.', message_conv_is_expect1: 'Syntax error. Please make sure you type ', message_conv_is_expect2: ' correctly.', message_conv_instead: 'Syntax error. It should be %2 instead of %1.', message_conv_is_wrong1: 'Syntax error. ', message_conv_is_wrong2: ' are not allowed to be there.', message_conv_or: ' or ', subject_syntax_default: 'ETC', subject_syntax_token: 'Token', subject_syntax_character: 'Character', subject_syntax_indent: 'Indent', subject_conv_default: 'ETC', subject_conv_general: 'General', subject_conv_variable: 'Variable', subject_conv_list: 'List', subject_conv_object: 'Object', subject_conv_function: 'Function', alert_variable_empty_text: "You can't convert into the text mode if there is empty text among registered variables.", alert_list_empty_text: "You can't convert into the text mode if there is empty text among registered lists.", alert_function_name_field_multi: "You can't convert into the text mode if there is name field block over two times among registered functions.", alert_function_name_disorder: "You can't convert into the text mode if name field is behind than string/number or judgement param field among registered functions.", alert_function_has_boolean: 'If you convert into the text mode and then back to block coding, the [Judgment] used in the function is converted to [Character/Number].', alert_function_editor: "Youn can't convert into the text mode in the middle of function creation or editing.", alert_function_no_support: "Youn can't use the function creation or editing in the text mode.", alert_list_no_support: "Youn can't use the list creation or editing in the text mode.", alert_variable_no_support: "Youn can't use the variable creation or editing in the text mode.", alert_signal_no_support: "Youn can't use the signal creation or editing in the text mode.", alert_legacy_no_support: 'Mode switch is not allowed due to inconvertible blocks', alert_variable_empty_text_add_change: "The empty text can't be included in variable name.", alert_list_empty_text_add_change: "The empty text can't be included in list name.", alert_list_contains_exceed_length_value: "You can't convert into the text mode if more than 15 digits are entered in the list item.", alert_function_name_empty_text_add_change: "The empty text can't be included in function name.", alert_no_save_on_error: "The code with an error can't save.", alert_api_no_support: 'The project contains blocks \nthat are not supported by Entry-Python. \nDelete all those blocks and \nchange to Entry-Python mode?', warn_unnecessary_arguments: "&(calleeName)(); command doesn't require value within parentheses. (line:&(lineNumber))", python_code: "'s python code", eof: 'line change', newline: 'line change', indent: 'indentation', num: 'number', string: 'string', name: 'variable name', }; Lang.PythonHelper = { when_run_button_click_desc: '[시작하기]버튼을 클릭하면 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_run_button_click_exampleCode: 'def when_start():\n Entry.print("안녕!")', when_run_button_click_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕!"이라 말합니다.', when_some_key_pressed_desc: 'A키를 누르면 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_some_key_pressed_elements: 'A-- 아래 선택지 중 하나\n① 알파벳 : "A", "B" ~ "Z" 등(소문자 가능)\n② 숫자 : 1, 2, 3, 4 ~ 9, 0\n③ 특수키 : "space", "enter"\n④ 방향키 : "up", "down", "right", "left"', when_some_key_pressed_exampleCode: 'def when_press_key("W"):\n Entry.move_to_direction(10)\n\ndef when_press_key(1):\n Entry.add_size(10)', when_some_key_pressed_exampleDesc: 'W키를 누르면 오브젝트가 이동방향으로 10만큼 이동하고, 1키를 누르면 오브젝트의 크기가 10만큼 커집니다.', mouse_clicked_desc: '마우스를 클릭했을 때 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', mouse_clicked_exampleCode: 'def when_click_mouse_on():\n Entry.add_size(10)\n Entry.move_to_direction(10)', mouse_clicked_exampleDesc: '마우스를 클릭하면 오브젝트의 크기가 10만큼 커지면서 이동방향으로 10만큼 이동합니다.', mouse_click_cancled_desc: '마우스 클릭을 해제했을 때 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', mouse_click_cancled_exampleCode: 'def when_click_mouse_off():\n Entry.move_to_direction(-10)\n\ndef when_click_mouse_on():\n Entry.move_to_direction(10)', mouse_click_cancled_exampleDesc: '마우스를 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 마우스 클릭을 해제하면 오브젝트가 이동방향으로 -10만큼 이동합니다.', when_object_click_desc: '해당 오브젝트를 클릭했을 때 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_object_click_exampleCode: 'def when_click_object_on():\n Entry.print_for_sec("회전!", 0.5)\n Entry.add_rotation(90)', when_object_click_exampleDesc: '오브젝트를 클릭하면 오브젝트가 "회전!"이라 말하고, 90도 만큼 회전합니다.', when_object_click_canceled_desc: '해당 오브젝트 클릭을 해제했을 때 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_object_click_canceled_exampleCode: 'def when_click_object_on():\n Entry.add_rotation(90)\n\ndef when_click_object_off():\n Entry.add_rotation(-90)', when_object_click_canceled_exampleDesc: '오브젝트를 클릭하면 오브젝트가 90도 만큼 회전하고, 오브젝트 클릭을 해제하면 오브젝트가 -90도 만큼 회전합니다.', when_message_cast_desc: 'A 신호를 받으면 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.\n만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.', when_message_cast_elements: 'A-- "신호 이름"', when_message_cast_exampleCode: 'def when_click_mouse_on():\n Entry.send_signal("신호")\n\ndef when_get_signal("신호"):\n Entry.print_for_sec("안녕! 반가워", 0.5)', when_message_cast_exampleDesc: '마우스를 클릭하면 "신호"를 보내고, "신호"를 받았을때 "안녕! 반가워"라고 0.5초간 말합니다.', message_cast_desc: 'A에 입력된 신호를 보냅니다.\n만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.', message_cast_elements: 'A-- "신호 이름"', message_cast_exampleCode: '#"오브젝트1"의 파이선 코드\ndef when_start():\n Entry.print_for_sec("안녕! 넌 몇살이니?", 2)\n Entry.send_signal("신호")\n\n#"오브젝트2"의 파이선 코드\ndef when_get_signal("신호"):\n Entry.print_for_sec("안녕? 난 세 살이야.", 2)', message_cast_exampleDesc: '[시작하기]버튼을 클릭하면 "오브젝트1"이 "안녕! 넌 몇살이니?"라고 2초간 말하고 "신호를 보냅니다., "오브젝트2"가 "신호"를 받았을때 "안녕? 난 세 살이야."라고 2초간 말합니다.', message_cast_wait_desc: 'A에 입력된 신호를 보내고, 해당 신호를 받는 명령어들의 실행이 끝날 때까지 기다립니다.\n만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.', message_cast_wait_elements: 'A-- "신호 이름"', message_cast_wait_exampleCode: '#"오브젝트1"의 파이선 코드\ndef when_start():\n Entry.print_for_sec("숨바꼭질하자!", 2)\n Entry.send_signal_wait("신호")\n Entry.hide()\n\n#"오브젝트2"의 파이선 코드\ndef when_get_signal("신호"):\n Entry.print_for_sec("그래!", 2)', message_cast_wait_exampleDesc: '[시작하기]버튼을 클릭하면 "오브젝트1"이 "숨바꼭질하자!"라고 2초 동안 말하고 "신호"를 보낸 후 기다립니다. "오브젝트2"가 "신호"를 받으면 "그래!"를 2초 동안 말합니다. "오브젝트1"이 그 후에 모양을 숨깁니다.', when_scene_start_desc: '장면이 시작되면 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_scene_start_exampleCode: '#"장면 1"의 파이선 코드\ndef when_start():\n Entry.print_for_sec("다른 곳으로 가볼까?", 2)\n Entry.start_scene("장면 2")\n\n#"장면 2"의 파이선 코드\ndef when_start_scene():\n Entry.print("여기가 어디지?")', when_scene_start_exampleDesc: '"장면 1"에서 [시작하기]버튼을 클릭하면 "다른 곳으로 가볼까?"라고 2초간 말하고, "장면 2"가 시작됩니다. "장면 2"가 시작되면 오브젝트가 "여기가 어디지?"라고 말합니다.', start_scene_desc: 'A 장면을 시작합니다.', start_scene_elements: 'A-- "장면 이름"', start_scene_exampleCode: '#"장면 1"의 파이선 코드\ndef when_click_object_on():\n Entry.start_scene("장면 2")', start_scene_exampleDesc: '"장면 1"에서 해당 오브젝트를 클릭하면 "장면 2"가 시작됩니다.', start_neighbor_scene_desc: 'A에 입력한 다음 또는 이전 장면을 시작합니다.', start_neighbor_scene_elements: 'A-- 아래 선택지 중 하나\n① 다음 장면: "next" 또는 "다음"\n② 이전 장면: "prev" 또는 "이전"', start_neighbor_scene_exampleCode: '#"장면 1"의 파이선 코드\ndef when_press_key("right"):\n Entry.start_scene_of("next")\n\n#"장면 2"의 파이선 코드\ndef when_press_key("left"):\n Entry.start_scene_of("prev")', start_neighbor_scene_exampleDesc: '"장면 1"에서 오른쪽화살표키를 누르면 다음 장면이, "장면 2"에서 왼쪽화살표키를 누르면 이전 장면이 시작됩니다.', wait_second_desc: 'A초만큼 기다린 후 다음 블록을 실행합니다.', wait_second_elements: 'A-- 초에 해당하는 수 입력', wait_second_exampleCode: 'def when_start():\n Entry.add_effect("color", 10)\n Entry.wait_for_sec(2)\n Entry.add_size(10)', wait_second_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트에 색깔효과를 10만큼 주고, 2초동안 기다린 다음 크기를 10만큼 커지게 합니다.', repeat_basic_desc: '아래 명령어들을 A번 반복하여 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', repeat_basic_elements: 'A-- 반복할 횟수 입력', repeat_basic_exampleCode: 'def when_start():\n for i in range(10):\n Entry.move_to_direction(10)\n Entry.stamp()', repeat_basic_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 도장찍는 행동을 10번 반복합니다.', repeat_inf_desc: 'A 판단이 True인 동안 아래 명령어들을 반복 실행합니다. A에 True를 입력하면 계속 반복됩니다. \n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', repeat_inf_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', repeat_inf_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n Entry.bounce_on_edge()', repeat_inf_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 계속해서 이동방향으로 10만큼 이동하고, 벽에 닿으면 튕깁니다.', repeat_while_true_desc: 'A 판단이 True가 될 때까지 아래 명령어들을 반복 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', repeat_while_true_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', repeat_while_true_exampleCode: 'def when_start():\n while not Entry.is_key_pressed("space"):\n Entry.add_rotation(90)', repeat_while_true_exampleDesc: '[시작하기]버튼을 클릭하면 스페이스키를 누를때까지 오브젝트가 90도 만큼 회전합니다.', stop_repeat_desc: "Stops the closest block that encloses this block.\n It works with various C-shaped blocks like 'repeat' block.", stop_repeat_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n if Entry.is_key_pressed("enter"):\n break', stop_repeat_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 계속 이동합니다. 엔터키를 누르면 반복이 중단됩니다.', _if_desc: 'A 부분의 판단이 True이면 if A:아래 명령어들을 실행하고, False이면 실행하지 않습니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', _if_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', _if_exampleCode: 'def when_click_mouse_on():\n if (Entry.value_of_mouse_pointer("x") > 0):\n Entry.print_for_sec("오른쪽!", 0.5)', _if_exampleDesc: '마우스를 클릭했을 때 마우스 x좌표가 0보다 크면 오브젝트가 "오른쪽!"이라고 0.5초 동안 말합니다.', if_else_desc: 'A 부분의 판단이 True이면 if A: 아래 명령어들을 실행하고, False이면 else: 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', if_else_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', if_else_exampleCode: 'def when_click_mouse_on():\n if Entry.is_touched("mouse_pointer"):\n Entry.print("닿았다!")\n else:\n Entry.print("안 닿았다!")', if_else_exampleDesc: '마우스를 클릭했을 때 마우스포인터가 오브젝트에 닿았으면 "닿았다!"를 그렇지 않으면 "안 닿았다!"를 말합니다.', wait_until_true_desc: 'A 부분의 판단이 True가 될 때까지 코드의 실행을 멈추고 기다립니다.', wait_until_true_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', wait_until_true_exampleCode: 'def when_start():\n Entry.print("엔터를 눌러봐!")\n Entry.wait_until(Entry.is_key_pressed("enter"))\n Entry.print("잘했어!")', wait_until_true_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "엔터를 눌러봐!"라 말하고, 엔터키를 누를 때까지 기다립니다. 엔터키를 누르면 "잘했어!"라 말합니다.', stop_object_desc: 'A코드의 실행을 중지합니다.', stop_object_elements: 'A-- 아래 선택지 중 하나\n① "all": 모든 오브젝트의 모든 코드\n② "self" : 해당 오브젝트의 모든 코드\n③ "this": 이 명령어가 포함된 코드\n④ "others" : 해당 오브젝트의 코드 중 이 명령어가 포함된 코드를 제외한 모든 코드\n⑤ "ohter_objects" : 이 오브젝트를 제외한 다른 모든 오브젝트의 코드', stop_object_exampleCode: 'def when_start():\n while True:\n Entry.move_to("mouse_pointer")\n\ndef when_press_key("space"):\n Entry.stop_code("all")\n', stop_object_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 계속해서 마우스포인터 위치로 이동합니다. 스페이스키를 누르면 모든 코드의 실행이 중지됩니다.', restart_project_desc: '작품을 처음부터 다시 실행합니다.', restart_project_exampleCode: 'def when_start():\n while True:\n Entry.add_size(10)\n\ndef when_press_key("enter"):\n Entry.start_again()', restart_project_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트의 크기가 커집니다. 엔터키를 누르면 작품을 처음부터 다시 실행합니다.', when_clone_start_desc: '해당 오브젝트의 복제본이 새로 생성되었을 때 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_clone_start_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("self")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))', when_clone_start_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다.', create_clone_desc: 'A 오브젝트의 복제본을 생성합니다.', create_clone_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "self" 또는 "자신"', create_clone_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("self")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))', create_clone_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다.', delete_clone_desc: 'Entry.make_clone_of(A) 명령에 의해 생성된 복제본을 삭제합니다.', delete_clone_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("자신")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))\n\ndef when_click_object_on():\n Entry.remove_this_clone()', delete_clone_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다. 복제본을 클릭하면 클릭된 복제본을 삭제합니다.', remove_all_clones_desc: '해당 오브젝트의 모든 복제본을 삭제합니다.', remove_all_clones_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("자신")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))\n\ndef when_press_key("space"):\n Entry.remove_all_clone()', remove_all_clones_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다. 스페이스 키를 누르면 모든 복제본을 삭제합니다.', move_direction_desc: 'A만큼 오브젝트의 이동방향 화살표가 가리키는 방향으로 움직입니다.', move_direction_elements: 'A-- 이동할 거리에 해당하는 수', move_direction_exampleCode: 'def when_start():\n Entry.move_to_direction(10)', move_direction_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동합니다.', bounce_wall_desc: '오브젝트가 화면 끝에 닿으면 튕겨져 나옵니다.', bounce_wall_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n Entry.bounce_on_edge()', bounce_wall_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 계속해서 이동방향으로 10만큼 이동하고, 벽에 닿으면 튕깁니다.', move_x_desc: '오브젝트의 x좌표를 A만큼 바꿉니다.', move_x_elements: 'A-- x좌표의 변화 값\n① 양수: 오브젝트가 오른쪽으로 이동합니다.\n② 음수: 오브젝트가 왼쪽으로 이동합니다.', move_x_exampleCode: 'def when_start():\n Entry.add_x(10)\n Entry.wait_for_sec(2)\n Entry.add_x(-10)', move_x_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오른쪽으로 10만큼 이동하고 2초 동안 기다린 후 왼쪽으로 10만큼 이동합니다.', move_y_desc: '오브젝트의 y좌표를 A만큼 바꿉니다.', move_y_elements: 'A-- y좌표의 변화 값\n① 양수: 오브젝트가 위쪽으로 이동합니다.\n② 음수: 오브젝트가 아래쪽으로 이동합니다.', move_y_exampleCode: 'def when_start():\n Entry.add_y(10)\n Entry.wait_for_sec(2)\n Entry.add_y(-10)', move_y_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 위쪽으로 10만큼 이동하고 2초 동안 기다린 후 아래쪽으로 10만큼 이동합니다.', move_xy_time_desc: '오브젝트가 x와 y좌표를 각각 A와 B만큼 C초에 걸쳐 서서히 바꿉니다.', move_xy_time_elements: 'A-- x좌표의 변화 값\n① 양수: 오브젝트가 오른쪽으로 이동합니다.\n② 음수: 오브젝트가 왼쪽으로 이동합니다.%nextB-- y좌표의 변화 값\n① 양수: 오브젝트가 위쪽으로 이동합니다.\n② 음수: 오브젝트가 아래쪽으로 이동합니다.%nextC-- 이동하는 시간(초)', move_xy_time_exampleCode: 'def when_start():\n Entry.add_xy_for_sec(100, 100, 2)\n Entry.add_xy_for_sec(-100, -100, 2)', move_xy_time_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오른쪽 위로 100만큼 2초 동안 이동한 후 왼쪽 아래로 100만큼 2초 동안 이동합니다.', locate_x_desc: '오브젝트의 x좌표를 A로 정합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_x_elements: 'A-- 이동할 x좌표', locate_x_exampleCode: 'def when_press_key("right"):\n Entry.set_x(100)\n\ndef when_press_key("left"):\n Entry.set_x(-100)\n', locate_x_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 x좌표를 100으로 정하고, 왼쪽화살표키를 누르면 오브젝트의 x좌표를 -100으로 정합니다.', locate_y_desc: '오브젝트의 y좌표를 A로 정합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_y_elements: 'B-- 이동할 y좌표', locate_y_exampleCode: 'def when_press_key("up"):\n Entry.set_y(100)\n\ndef when_press_key("down"):\n Entry.set_y(-100)', locate_y_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 y좌표를 100으로 정하고, 아래쪽화살표키를 누르면 오브젝트의 y좌표를 -100으로 정합니다.', locate_xy_desc: '오브젝트가 좌표(A, B)로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_xy_elements: 'A-- 이동할 x좌표%nextB-- 이동할 y좌표', locate_xy_exampleCode: 'def when_click_mouse_on():\n Entry.set_xy(0, 0)\n\ndef when_press_key("right"):\n Entry.add_x(10)\n\ndef when_press_key("up"):\n Entry.add_y(10)', locate_xy_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 x좌표를 10만큼 바꾸고, 위쪽화살표키를 누르면 오브젝트의 y좌표를 10만큼 바꿉니다. 마우스를 클릭하면 오브젝트의 x, y좌표를 0으로 정합니다.', locate_xy_time_desc: '오브젝트가 좌표(A, B)로 C초에 걸쳐 서서히 이동합니다.(오브젝트의 중심점이 기준이 됩니다.)', locate_xy_time_elements: 'A-- 이동할 x좌표%nextB-- 이동할 y좌표%nextC-- 이동하는 시간', locate_xy_time_exampleCode: 'def when_click_mouse_on():\n Entry.set_xy_for_sec(0, 0, 2)\n\ndef when_press_key("right"):\n Entry.add_x(10)\n\ndef when_press_key("up"):\n Entry.add_y(10)', locate_xy_time_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 x좌표를 10만큼 바꾸고, 위쪽화살표키를 누르면 오브젝트의 y좌표를 10만큼 바꿉니다. 마우스를 클릭하면 2초 동안 오브젝트를 x,y 좌표 0으로 이동시킵니다.', locate_desc: '오브젝트가 A의 위치로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "mouse_pointer" 또는 "마우스포인터"', locate_exampleCode: 'def when_click_mouse_on():\n Entry.move_to("mouse_pointer")\n\ndef when_press_key("space"):\n Entry.move_to("오브젝트")', locate_exampleDesc: '마우스를 클릭하면 오브젝트가 마우스포인터 위치로 이동합니다.\n스페이스키를 누르면 오브젝트가 "오브젝트" 위치로 이동합니다.', locate_object_time_desc: '오브젝트가 A의 위치로 B초에 걸쳐 서서히 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_object_time_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "mouse_pointer" 또는 "마우스포인터" %nextB-- 이동하는 시간(초)', locate_object_time_exampleCode: 'def when_click_mouse_on():\n Entry.move_to_for_sec("mouse_pointer", 2)', locate_object_time_exampleDesc: '마우스를 클릭하면 오브젝트가 2초 동안 서서히 마우스포인터 위치로 이동합니다.', rotate_relative_desc: '오브젝트의 방향을 A도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', rotate_relative_elements: 'A-- 회전할 각도', rotate_relative_exampleCode: 'def when_click_object_on():\n Entry.add_rotation(90)\n\ndef when_click_object_off():\n Entry.add_rotation(-90)', rotate_relative_exampleDesc: '오브젝트를 클릭하면 오브젝트가 90도 만큼 회전하고, 오브젝트 클릭을 해제하면 오브젝트가 -90도 만큼 회전합니다.', direction_relative_desc: '오브젝트의 이동 방향을 A도만큼 회전합니다.', direction_relative_elements: 'A-- 회전할 각도', direction_relative_exampleCode: 'def when_start():\n Entry.move_to_direction(50)\n Entry.wait_for_sec(0.5)\n Entry.add_direction(90)\n Entry.wait_for_sec(0.5)\n Entry.move_to_direction(50)', direction_relative_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 50만큼 이동한 다음 0.5초간 기다립니다. 그 후 이동방향을 90도 만큼 회전하고 0.5초간 기다린 후 이동방향으로 50만큼 이동합니다.', rotate_by_time_desc: '오브젝트의 방향을 시계방향으로 A도만큼 B초에 걸쳐 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', rotate_by_time_elements: 'A-- 회전할 각도%nextB-- 회전할 시간(초)', rotate_by_time_exampleCode: 'def when_start():\n Entry.add_rotation_for_sec(90, 2)\n Entry.add_rotation_for_sec(-90, 2)', rotate_by_time_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 2초 동안 90도 만큼 회전하고, 다시 2초 동안 -90도 만큼 회전합니다.', direction_relative_duration_desc: '오브젝트의 이동방향을 시계방향으로 A도만큼 B초에 걸쳐 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', direction_relative_duration_elements: 'A-- 회전할 각도%nextB-- 회전할 시간(초)', direction_relative_duration_exampleCode: 'def when_start():\n Entry.add_direction_for_sec(90, 2)\n\ndef when_start():\n while True:\n Entry.move_to_direction(1)', direction_relative_duration_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트의 이동방향을 2초 동안 90도만큼 회전시킵니다. 동시에 오브젝트는 이동방향으로 1만큼 계속 이동합니다.', rotate_absolute_desc: '오브젝트의 방향을 A로 정합니다.', rotate_absolute_elements: 'A-- 설정할 방향', rotate_absolute_exampleCode: 'def when_press_key("right"):\n Entry.set_rotation(90)\n\ndef when_press_key("left"):\n Entry.set_rotation(270)', rotate_absolute_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 방향을 90으로 정하고, 왼쪽화살표키를 누르면 오브젝트의 방향을 270으로 정합니다.', direction_absolute_desc: '오브젝트의 이동방향을 A로 정합니다.', direction_absolute_elements: 'A-- 설정할 이동방향', direction_absolute_exampleCode: 'def when_press_key("right"):\n Entry.set_direction(90)\n Entry.move_to_direction(10)\n\ndef when_press_key("left"):\n Entry.set_direction(270)\n Entry.move_to_direction(10)', direction_absolute_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 이동방향을 90으로 정한 후 해당 쪽으로 10만큼 이동하고, 왼쪽화살표키를 누르면 오브젝트의 이동방향을 270으로 정하고 해당쪽으로 10만큼 이동합니다.', see_angle_object_desc: '오브젝트가 A쪽을 바라봅니다. (이동방향이 A를 향하도록 오브젝트의 방향을 회전해줍니다.)', see_angle_object_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "mouse_pointer" 또는 "마우스포인터"', see_angle_object_exampleCode: 'def when_click_mouse_on():\n Entry.look_at("mouse_pointer")\n\ndef when_press_key("space"):\n Entry.look_at("오브젝트")', see_angle_object_exampleDesc: '마우스를 클릭하면 오브젝트가 마우스포인터쪽을 바라보고, 스페이스키를 누르면 "오브젝트"쪽을 바라봅니다.', move_to_angle_desc: '오브젝트가 A만큼 B방향으로 움직입니다.', move_to_angle_elements: 'A-- 이동할 거리에 해당하는 수%nextB-- 이동할 방향(12시 방향이 0도, 시계방향으로 증가)', move_to_angle_exampleCode: 'def when_press_key("up"):\n Entry.move_to_degree(10, 0)\n\ndef when_press_key("down"):\n Entry.move_to_degree(10, 180)', move_to_angle_exampleDesc: '위쪽화살표키를 누르면 오브젝트가 0도방향으로 10만큼 이동하고, 아래쪽화살표키를 누르면 오브젝트가 180도방향으로 10만큼 이동합니다.', show_desc: '오브젝트를 화면에 나타냅니다.', show_exampleCode: 'def when_start():\n Entry.wait_for_sec(1)\n Entry.hide()\n Entry.wait_for_sec(1)\n Entry.show()', show_exampleDesc: '[시작하기]버튼을 클릭하면 1초 뒤에 오브젝트 모양이 숨겨지고, 다음 1초 뒤에 오브젝트 모양이 나타납니다.', hide_desc: '오브젝트를 화면에서 보이지 않게 합니다.', hide_exampleCode: 'def when_start():\n Entry.wait_for_sec(1)\n Entry.hide()\n Entry.wait_for_sec(1)\n Entry.show()', hide_exampleDesc: '[시작하기]버튼을 클릭하면 1초 뒤에 오브젝트 모양이 숨겨지고, 다음 1초 뒤에 오브젝트 모양이 나타납니다.', dialog_time_desc: '오브젝트가 A를 B초 동안 말풍선으로 말한 후 다음 명령어가 실행됩니다. 콘솔창에서도 실행 결과를 볼 수 있습니다.', dialog_time_elements: 'A-- 말할 내용\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등%nextB-- 말하는 시간(초)', dialog_time_exampleCode: 'def when_start():\n Entry.print_for_sec("안녕! 나는", 2)\n Entry.print_for_sec(16, 2)\n Entry.print_for_sec("살이야", 2)', dialog_time_exampleDesc: '[시작하기]버튼을 클릭하면 "안녕! 나는", 16, "살이야"를 각각 2초 동안 차례대로 말합니다.', dialog_desc: '오브젝트가 A를 말풍선으로 말합니다. 콘솔창에서도 실행 결과를 볼 수 있습니다.', dialog_elements: 'A-- 말할 내용\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', dialog_exampleCode: 'def when_start():\n Entry.print("키보드로 숫자 1,2 를 누르면 숫자를 말해볼게")\n\ndef when_press_key(1):\n Entry.print(1)\n\ndef when_press_key(2):\n Entry.print(2)\n', dialog_exampleDesc: '[시작하기]버튼을 클릭하면 "키보드로 숫자 1,2 를 누르면 숫자를 말해볼게"를 말하고, 키보드로 1, 2를 누르면 각각 1, 2라 말합니다.', remove_dialog_desc: '오브젝트가 말하고 있는 말풍선을 지웁니다.', remove_dialog_exampleCode: 'def when_start():\n Entry.print("말풍선을 지우려면 엔터를 눌러!")\n\ndef when_press_key("enter"):\n Entry.clear_print()', remove_dialog_exampleDesc: '[시작하기]버튼을 클릭하면 "말풍선을 지우려면 엔터를 눌러!"라 말하고, 엔터키를 누르면 말풍선이 사라집니다.', change_to_some_shape_desc: '오브젝트를 A 모양으로 바꿉니다.', change_to_some_shape_elements: 'A-- 아래 선택지 중 하나\n① 모양 이름 : [속성] 탭의 "모양 이름"을 적음\n② 모양 번호 : [속성] 탭의 모양 번호를 적음', change_to_some_shape_exampleCode: 'def when_start():\n Entry.wait_for_sec(0.3)\n Entry.change_shape("오브젝트모양")\n Entry.wait_for_sec(0.3)\n Entry.change_shape("오브젝트모양")', change_to_some_shape_exampleDesc: '[시작하기]버튼을 클릭하면 0.3초간 기다린 다음 "오브젝트모양"으로 모양을 바꾸고 0.3초간 기다린 다음 "오브젝트모양"모양으로 모양을 바꿉니다.', change_to_next_shape_desc: '오브젝트의 모양을 다음 또는 이전 모양으로 바꿉니다.', change_to_next_shape_elements: 'A-- 아래 선택지 중 하나\n① 다음 모양 : "next" 또는 "다음" \n② 이전 모양 : "pre" 또는 "이전"', change_to_next_shape_exampleCode: 'def when_start():\n Entry.wait_for_sec(0.3)\n Entry.change_shape_to("next")\n Entry.wait_for_sec(0.3)\n Entry.change_shape_to("pre")', change_to_next_shape_exampleDesc: '[시작하기]버튼을 클릭하면 0.3초간 기다린 다음 모양으로 오브젝트 모양을 바꾸고 0.3초간 기다린 다음 이전 모양으로 오브젝트 모양을 바꿉니다.', add_effect_amount_desc: '오브젝트에 A 효과를 B만큼 줍니다.', add_effect_amount_elements: 'A -- 아래 선택지 중 하나\n① “color” 또는 “색깔“ \n② “brightness” 또는 “밝기” \n③ “transparency” 또는 “투명도”%nextB-- 효과의 변화 정도', add_effect_amount_exampleCode: 'def when_click_mouse_on():\n Entry.add_effect("color", 50)\n Entry.wait_for_sec(1)\n Entry.add_effect("brightness", -50)\n Entry.wait_for_sec(1)\n Entry.add_effect("transparency", 50)', add_effect_amount_exampleDesc: '마우스를 클릭하면 오브젝트에 색깔 효과를 50만큼 주고 1초간 기다리고, 밝기 효과를 -50만큼 주고 1초간 기다립니다. 그 후 투명도 효과를 50만큼 줍니다.', change_effect_amount_desc: '오브젝트의 A 효과를 B로 정합니다.', change_effect_amount_elements: 'A-- 아래 선택지 중 하나\n① “color” 또는 “색깔“ \n② “brightness” 또는 “밝기” \n③ “transparency” 또는 “투명도”%nextB-- 효과의 값\n① color: 0~100 범위의 수, 100을 주기로 반복됨\n② brightness: -100~100 사이 범위의 수, -100이하는 -100 으로 100 이상은 100 으로 처리 됨\n③ transparency: 0~100 사이 범위의 수, 0 이하는 0으로, 100이상은 100으로 처리 됨', change_effect_amount_exampleCode: 'def when_click_mouse_on():\n Entry.set_effect("color", 50)\n Entry.set_effect("brightness", 50)\n Entry.set_effect("transparency", 50)\n\ndef when_click_mouse_off():\n Entry.set_effect("color", 0)\n Entry.set_effect("brightness", 0)\n Entry.set_effect("transparency", 0)', change_effect_amount_exampleDesc: '마우스를 클릭하면 오브젝트에 색깔, 밝기, 투명도 효과를 50으로 정하고, 마우스 클릭을 해제하면 각 효과를 0으로 정합니다.', erase_all_effects_desc: '오브젝트에 적용된 효과를 모두 지웁니다.', erase_all_effects_exampleCode: 'def when_click_mouse_on():\n Entry.set_effect("color", 50)\n Entry.set_effect("brightness", 50)\n Entry.set_effect("transparency", 50)\n\ndef when_click_mouse_off():\n Entry.clear_effect()\n', erase_all_effects_exampleDesc: '마우스를 클릭하면 오브젝트에 색깔, 밝기, 투명도 효과를 50으로 정하고, 마우스 클릭을 해제하면 오브젝트에 적용된 모든 효과를 지웁니다.', change_scale_size_desc: '오브젝트의 크기를 A만큼 바꿉니다.', change_scale_size_elements: 'A-- 크기 변화 값', change_scale_size_exampleCode: 'def when_press_key("up"):\n Entry.add_size(10)\n\ndef when_press_key("down"):\n Entry.add_size(-10)\n\ndef when_press_key("space"):\n Entry.set_size(100)', change_scale_size_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 크기가 10만큼 커지고, 아래쪽화살표키를 누르면 오브젝트의 크기가 10만큼 작아집니다. 스페이스키를 누르면 오브젝트의 크기를 100으로 정합니다.', set_scale_size_desc: '오브젝트의 크기를 A로 정합니다.', set_scale_size_elements: 'A-- 크기값', set_scale_size_exampleCode: 'def when_press_key("up"):\n Entry.add_size(10)\n\ndef when_press_key("down"):\n Entry.add_size(-10)\n\ndef when_press_key("space"):\n Entry.set_size(100)', set_scale_size_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 크기가 10만큼 커지고, 아래쪽화살표키를 누르면 오브젝트의 크기가 10만큼 작아집니다. 스페이스키를 누르면 오브젝트의 크기를 100으로 정합니다.', flip_x_desc: '오브젝트의 상하 모양을 뒤집습니다.', flip_x_exampleCode: 'def when_press_key("up"):\n Entry.flip_horizontal()\n\ndef when_press_key("right"):\n Entry.flip_vertical()', flip_x_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 상하 모양을 뒤집고, 오른쪽화살표키를 누르면 오브젝트의 좌우 모양을 뒤집습니다.', flip_y_desc: '오브젝트의 좌우 모양을 뒤집습니다.', flip_y_exampleCode: 'def when_press_key("up"):\n Entry.flip_horizontal()\n\ndef when_press_key("right"):\n Entry.flip_vertical()', flip_y_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 상하 모양을 뒤집고, 오른쪽화살표키를 누르면 오브젝트의 좌우 모양을 뒤집습니다.', change_object_index_desc: '오브젝트의 레이어를 A로 가져옵니다.', change_object_index_elements: 'A-- 아래 선택지 중 하나\n① “front" 또는 “맨 앞“ \n② “forward” 또는 “앞” \n③ “backward” 또는 “뒤”\n④ “back” 또는 “맨 뒤”', change_object_index_exampleCode: 'def when_start():\n Entry.send_layer_to("front")\n Entry.wait_for_sec(2)\n Entry.send_layer_to("backward")', change_object_index_exampleDesc: '오브젝트가 여러개가 겹쳐 있을 경우 [시작하기]버튼을 클릭하면 해당 오브젝트의 레이어를 가장 앞으로 가져와서 보여줍니다.', brush_stamp_desc: '오브젝트의 모양을 도장처럼 실행화면 위에 찍습니다.', brush_stamp_exampleCode: 'def when_start():\n for i in range(10):\n Entry.move_to_direction(10)\n Entry.stamp()', brush_stamp_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 도장찍는 행동을 10번 반복합니다.', start_drawing_desc: '오브젝트가 이동하는 경로를 따라 선이 그려지기 시작합니다. (오브젝트의 중심점이 기준)', start_drawing_exampleCode: 'def when_start():\n Entry.start_drawing()\n for i in range(10):\n Entry.move_to_direction(10)', start_drawing_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 오브젝트가 이동방향으로 10만큼 10번 이동할 때 오브젝트의 이동경로를 따라 선이 그려집니다.', stop_drawing_desc: '오브젝트가 선을 그리는 것을 멈춥니다.', stop_drawing_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(1)\n\ndef when_click_mouse_on():\n Entry.stop_drawing()', stop_drawing_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고 계속해서 오브젝트가 이동방향으로 10만큼 이동합니다. 마우스를 클릭하면 그리는것을 멈춥니다.', set_color_desc: '오브젝트가 그리는 선의 색을 A로 정합니다.', set_color_elements: 'A-- 아래 선택지 중 하나\n① 색상 코드 : "#FF0000", "#FFCC00", "#3333FF", "#000000" 등\n② 색깔명 : "red", "orange", "yellow", "green", "blue", "navy", "purple", "black", "white", "brown"', set_color_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_color_to("#000099")\n while True:\n Entry.move_to_direction(1)', set_color_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 색을 "#000099"로 정합니다. 오브젝트는 계속해서 이동방향으로 1만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.', set_random_color_desc: '오브젝트가 그리는 선의 색을 무작위로 정합니다.', set_random_color_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(1)\n Entry.set_brush_color_to_random()', set_random_color_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 1만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 색깔은 계속해서 무작위로 정해집니다.', change_thickness_desc: '오브젝트가 그리는 선의 굵기를 A만큼 바꿉니다.', change_thickness_elements: 'A-- 굵기 변화 값', change_thickness_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.add_brush_size(1)\n Entry.move_to_direction(10)', change_thickness_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 굵기는 계속해서 1씩 커집니다.', set_thickness_desc: '오브젝트가 그리는 선의 굵기를 A로 정합니다.', set_thickness_elements: 'A-- 굵기값(1이상의 수)', set_thickness_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n while True:\n Entry.move_to_direction(10)', set_thickness_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.', change_brush_transparency_desc: '오브젝트가 그리는 선의 투명도를 A만큼 바꿉니다.', change_brush_transparency_elements: 'A-- 투명도 변화 값', change_brush_transparency_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n while True:\n Entry.move_to_direction(10)\n Entry.add_brush_transparency(5)', change_brush_transparency_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 투명도는 계속해서 5만큼 바꿉니다.', set_brush_tranparency_desc: '오브젝트가 그리는 선의 투명도를 A로 정합니다.', set_brush_tranparency_elements: 'A-- 투명도값(0~100 의 범위)', set_brush_tranparency_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n Entry.set_brush_transparency(50)\n while True:\n Entry.move_to_direction(10)', set_brush_tranparency_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로, 선의 투명도를 50으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.', brush_erase_all_desc: '오브젝트가 그린 선과 도장을 모두 지웁니다.', brush_erase_all_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(10)\n\ndef when_click_mouse_on():\n Entry.clear_drawing()', brush_erase_all_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 마우스를 클릭하면 오브젝트가 그린 선을 모두 지웁니다.', text_read_desc: '글상자 A의 내용입니다.\n(내용 안에 개행이 있는 경우, 띄어쓰기하여 반환됩니다.)', text_read_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트(글상자) 이름" \n② 자기 자신', text_read_exampleCode: 'def when_start():\n Entry.print(Entry.contents_of_textbox("A"))', text_read_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 글상자 "A"의 내용을 말합니다.​', text_write_desc: '글상자의 내용을 A로 고쳐씁니다.', text_write_elements: 'A-- 글상자의 내용\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', text_write_exampleCode: 'def when_start():\n Entry.write_text("엔트리")', text_write_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용을 "엔트리"로 바꿉니다.', text_append_desc: '글상자의 내용 뒤에 A를 추가합니다.', text_append_elements: 'A-- 글상자의 내용\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', text_append_exampleCode: 'def when_start():\n Entry.write_text("안녕?")\n Entry.wait_for_sec(1)\n Entry.append_text("엔트리!")', text_append_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용이 "안녕?"이 되었다가 1초 뒤에 "엔트리!"가 추가되어 "안녕?엔트리!"가 됩니다.', text_prepend_desc: '글상자의 내용 앞에 A를 추가합니다.', text_prepend_elements: 'A-- 글상자의 내용\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', text_prepend_exampleCode: 'def when_start():\n Entry.write_text("반가워!")\n Entry.wait_for_sec(1)\n Entry.prepend_text("엔트리!")', text_prepend_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용이 "반가워!"가 되었다가 1초 뒤에 "엔트리!"가 앞에 추가되어 "엔트리!반가워!"가 됩니다.', text_flush_desc: '글상자에 저장된 값을 모두 지웁니다.', text_flush_exampleCode: 'def when_start():\n Entry.write_text("엔트리")\n Entry.wait_for_sec(1)\n Entry.clear_text()', text_flush_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용이 "엔트리"가 되었다가 1초 뒤에 모든 내용이 사라집니다.', sound_something_with_block_desc: '오브젝트가 A 소리를 재생합니다.', sound_something_with_block_elements: 'A-- 아래 선택지 중 하나\n① 소리 이름 : [속성] 탭의 "소리 이름"을 적음\n② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_with_block_exampleCode: 'def when_start():\n Entry.play_sound("소리")\n Entry.add_size(50)', sound_something_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 재생하면서 오브젝트의 크기가 50만큼 커집니다.', sound_something_second_with_block_desc: '오브젝트가 A소리를 B초 만큼 재생합니다.', sound_something_second_with_block_elements: 'A-- 아래 선택지 중 하나\n① 소리 이름 : [속성] 탭의 "소리 이름"을 적음\n② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_second_with_block_exampleCode: 'def when_start():\n Entry.play_sound_for_sec("소리", 1)\n Entry.add_size(50)', sound_something_second_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 1초 동안 재생하면서, 오브젝트의 크기가 50만큼 커집니다.', sound_from_to_desc: '오브젝트가 A소리를 B초부터 C초까지 재생합니다.', sound_from_to_elements: 'A-- 아래 선택지 중 하나\n① 소리 이름 : [속성] 탭의 "소리 이름"을 적음\n② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_from_to_exampleCode: 'def when_start():\n Entry.play_sound_from_to("소리", 0.5, 1)\n Entry.add_size(50)', sound_from_to_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 0.5초부터 1초 구간까지만 재생하면서, 오브젝트의 크기가 50만큼 커집니다.', sound_something_wait_with_block_desc: '오브젝트가 A 소리를 재생하고, 재생이 끝나면 다음 명령을 실행합니다.', sound_something_wait_with_block_elements: 'A-- 아래 선택지 중 하나\n① 소리 이름 : [속성] 탭의 "소리 이름"을 적음\n② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_wait_with_block_exampleCode: 'def when_start():\n Entry.play_sound_and_wait("소리")\n Entry.add_size(50)', sound_something_wait_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.', sound_something_second_wait_with_block_desc: '오브젝트가 A소리를 B초 만큼 재생하고, 재생이 끝나면 다음 명령을 실행합니다.', sound_something_second_wait_with_block_elements: 'A-- 아래 선택지 중 하나\n① 소리 이름 : [속성] 탭의 "소리 이름"을 적음\n② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_second_wait_with_block_exampleCode: 'def when_start():\n Entry.play_sound_for_sec_and_wait("소리", 1)\n Entry.add_size(50)', sound_something_second_wait_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 1초 동안 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.', sound_from_to_and_wait_desc: '오브젝트가 A소리를 B초부터 C초까지 재생하고, 재생이 끝나면 다음 명령을 실행합니다.', sound_from_to_and_wait_elements: 'A-- 아래 선택지 중 하나\n① 소리 이름 : [속성] 탭의 "소리 이름"을 적음\n② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_from_to_and_wait_exampleCode: 'def when_start():\n Entry.play_sound_from_to_and_wait("소리", 0.5, 1)\n Entry.add_size(50)', sound_from_to_and_wait_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 0.5초부터 1초 구간까지만 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.', sound_volume_change_desc: '작품에서 재생되는 모든 소리의 크기를 A퍼센트만큼 바꿉니다.', sound_volume_change_elements: 'A-- 소리 크기 변화 값', sound_volume_change_exampleCode: 'def when_press_key("up"):\n Entry.add_sound_volume(10)\n\ndef when_press_key("down"):\n Entry.add_sound_volume(-10)\n\ndef when_start():\n while True:\n Entry.play_sound_and_wait("소리")', sound_volume_change_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 계속 재생합니다. 위쪽화살표키를 누르면 소리의 크기가 10" 커지고, 아래쪽화살표키를 누르면 소리의 크기가 10"작아집니다.', sound_volume_set_desc: '작품에서 재생되는 모든 소리의 크기를 A퍼센트로 정합니다.', sound_volume_set_elements: 'A-- 소리 크기값', sound_volume_set_exampleCode: 'def when_press_key("up"):\n Entry.add_sound_volume(10)\n\ndef when_press_key("down"):\n Entry.add_sound_volume(-10)\n\ndef when_press_key("enter"):\n Entry.set_sound_volume(100)\n\ndef when_start():\n while True:\n Entry.play_sound_and_wait("소리")', sound_volume_set_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 계속 재생합니다. 위쪽화살표키를 누르면 소리의 크기가 10" 커지고, 아래쪽화살표키를 누르면 소리의 크기가 10"작아집니다. 엔터키를 누르면 소리의 크기를 100"로 정합니다.', sound_silent_all_desc: '현재 재생 중인 모든 소리를 멈춥니다.', sound_silent_all_exampleCode: 'def when_start():\n while True:\n Entry.play_sound_and_wait("소리")\n\ndef when_press_key("enter"):\n Entry.stop_sound()', sound_silent_all_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 계속 재생합니다. 엔터키를 누르면 현재 재생 중인 소리를 멈춥니다.', is_clicked_desc: '마우스를 클릭한 경우 True로 판단합니다.', is_clicked_exampleCode: 'def when_start():\n while True:\n if Entry.is_mouse_clicked():\n Entry.print_for_sec("반가워!", 0.5)', is_clicked_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 마우스를 클릭했는지 확인합니다. 만약 마우스를 클릭하면 오브젝트가 "반가워!"라고 0.5초간 말합니다.', is_press_some_key_desc: 'A 키가 눌려져 있는 경우 True로 판단합니다.', is_press_some_key_elements: 'A-- 아래 선택지 중 하나\n① 알파벳 : "A", "B" ~ "Z" 등(소문자 가능)\n② 숫자: 1, 2, 3, 4 ~ 9, 0\n③ 특수키: "space", "enter"\n④ 방향키 : "up", "down", "right", "left"', is_press_some_key_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("space"):\n Entry.move_to_direction(10)', is_press_some_key_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 선택한 키를 눌렀는지 확인합니다. 만약 스페이스 키를 누르면 오브젝트가 이동방향으로 10만큼 이동합니다.', reach_something_desc: '오브젝트가 A와 닿은 경우 True으로 판단합니다.', reach_something_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "mouse_pointer" 또는 "마우스포인터"\n③ "edge", "edge_up", "edge_down", "edge_right", "edge_left"', reach_something_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n if Entry.is_touched("edge"):\n Entry.add_rotation(150)', reach_something_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트가 이동방향으로 10만큼 이동합니다. 만약 오브젝트가 벽에 닿으면 150만큼 회전하게 됩니다.', boolean_basic_operator_desc: 'A와 B를 비교하여 True 또는 False로 판단합니다.', boolean_basic_operator_elements: 'A, B 비교하고자 하는 숫자값\n① == : A와 B의 값이 같으면 True, 아니면 False\n② != : A와 B의 값이 다르면 True, 아니면 False\n③ > : A의 값이 B의 값보다 크면 true, 아니면 False\n④ < : A의 값이 B의 값보다 작으면 true, 아니면 False\n⑤ >= : A의 값이 B의 값보다 크거나 같으면 true, 아니면 False\n⑥ <= : A의 값이 B의 값보다 작거나 같으면 true, 아니면 False', boolean_basic_operator_exampleCode: 'def when_start():\n while True:\n Entry.add_x(10)\n if Entry.value_of_object("오브젝트", "x") > 240:\n Entry.set_x(0)', boolean_basic_operator_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트 x좌표를 10만큼 바꿉니다. 만약 오브젝트 x좌표가 240보다 크면 오브젝트 x좌표를 0으로 정합니다.', boolean_and_desc: 'A와 B의 판단이 모두 True인 경우 True, 아닌 경우 False로 판단합니다.', boolean_and_elements: 'A, B-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', boolean_and_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("a") and Entry.is_key_pressed("s"):\n Entry.add_effect("color", 10)', boolean_and_exampleDesc: '[시작하기]버튼을 클릭하고 키보드의 "a" 와 "s"키를 동시에 눌렀을 때, 색깔 효과를 10만큼 줍니다.', boolean_or_desc: 'A와 B의 판단 중 하나라도 True인 경우 True, 아닌 경우 False로 판단합니다.', boolean_or_elements: 'A, B-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', boolean_or_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("a") or Entry.is_key_pressed("s"):\n Entry.add_effect("color", 10)', boolean_or_exampleDesc: '[시작하기]버튼을 클릭하면 키보드의 "a"나 "s"키 중 무엇이든 하나를 누르면 오브젝트에 색깔 효과를 10만큼 줍니다.', boolean_not_desc: 'A 판단이 True이면 False, False이면 True로 판단합니다.', boolean_not_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', boolean_not_exampleCode: 'def when_start():\n while True:\n if not Entry.is_mouse_clicked():\n Entry.add_size(1)', boolean_not_exampleDesc: '[시작하기]버튼을 클릭하면 마우스를 클릭하지 않은 동안 크기가 1씩 커집니다.', calc_basic_desc: 'A와 B의 연산값입니다.', calc_basic_elements: 'A, B-- 연산하고자 하는 숫자값\n① + : A와 B를 더한 값\n② - : A와 B를 뺀 값\n③ x : A와 B를 곱한 값\n④ / : A와 B를 나눈 값', calc_basic_exampleCode: 'def when_start():\n Entry.print_for_sec(10 + 10, 2)\n Entry.print_for_sec(10 - 10, 2)\n Entry.print_for_sec(10 * 10, 2)\n Entry.print_for_sec(10 / 10, 2)', calc_basic_exampleDesc: '[시작하기]버튼을 클릭하면 10과 10을 더한값, 뺀값, 곱한값, 나눈값을 각 2초간 말합니다.', calc_rand_desc: 'A와 B 사이에서 선택된 무작위 수의 값입니다. (두 수 모두 정수를 입력한 경우 정수로,두 수 중 하나라도 소수를 입력한 경우 소수로 무작위 수가 선택됩니다.)', calc_rand_elements: 'A, B-- 무작위 수를 추출할 범위\n① random.randint(A, B) : A, B를 정수로 입력하면 정수 범위에서 무작위 수를 추출\n② random.uniform(A, B) : A, B를 실수로 입력하면 실수 범위에서 무작위 수를 추출', calc_rand_exampleCode: 'def when_start():\n Entry.print_for_sec(random.randint(1, 10), 2)\n Entry.print_for_sec(random.uniform(0.1, 2), 2)', calc_rand_exampleDesc: '[시작하기]버튼을 클릭하면 1부터 10사이의 정수중 무작위 수를 뽑아 2초간 말합니다. 그 후 0.1부터 2사이의 실수중 무작위 수를 뽑아 2초간 말합니다.', coordinate_mouse_desc: '마우스 포인터의 A 좌표 값을 의미합니다.', coordinate_mouse_elements: 'A-- 아래 선택지 중 하나\n① "x" 또는 "X"\n② "y" 또는 "Y"', coordinate_mouse_exampleCode: 'def when_start():\n while True:\n Entry.print(Entry.value_of_mouse_pointer("x"))', coordinate_mouse_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 마우스 포인터의 x좌표를 계속해서 말합니다.', coordinate_object_desc: 'A에 대한 B정보값입니다.', coordinate_object_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "self" 또는 "자신"%nextB-- 아래 선택지 중 하나\n① "x" 또는 "X"\n② "y" 또는 "Y"\n③ "rotation" 또는 "방향"\n④ "direction" 또는 "이동 방향"\n⑤ "size" 또는 "크기"\n⑥ "shape_number" 또는 "모양 번호"\n⑦ "shape_name" 또는 "모양 이름"', coordinate_object_exampleCode: 'def when_start():\n while True:\n Entry.add_x(1)\n Entry.print(Entry.value_of_object("오브젝트", "x"))\n', coordinate_object_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트의 x좌표가 1씩 증가하며, "오브젝트"의 x좌표를 말합니다.', get_sound_volume_desc: '현재 작품에 설정된 소리의 크기값입니다.', get_sound_volume_exampleCode: 'def when_start():\n while True:\n Entry.print(Entry.value_of_sound_volume())', get_sound_volume_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 소리의 크기값을 계속해서 말합니다.', quotient_and_mod_desc: 'A와 B의 연산값입니다.', quotient_and_mod_elements: 'A, B-- 연산하고자 하는 숫자값\n① // : A / B의 몫에 해당하는 값\n② % : A / B의 나머지에 해당하는 값', quotient_and_mod_exampleCode: 'def when_start():\n Entry.print_for_sec(10 // 3, 2)\n Entry.print_for_sec(10 % 3, 2)', quotient_and_mod_exampleDesc: '[시작하기]버튼을 클릭하면 10 / 3의 몫인 3을 2초 동안 말하고, 나머지인 1을 2초 동안 말합니다.', calc_operation_desc: 'A의 연산값입니다.', calc_operation_elements: 'A, B-- 연산하고자 하는 숫자값\n① A ** 2 : A를 제곱한 값\n② math.sqrt(A): A의 루트값\n③ math.sin(A): A의 사인값\n④ math.cos(A): A의 코사인 값\n⑤ math.tan(A): A의 탄젠트값 \n⑥ math.asin(A): A의 아크사인값\n⑦ math.acos(A): A의 아크코사인값\n⑧ math.atan(): A의 아크탄젠트값\n⑨ math.log10(A): A의 로그값\n⑩ math.log(A): A의 자연로그값\n⑪ A - math.floor(A): A의 소수점 부분\n⑫ math.floor(A): A의 소수점 버림값\n⑬ math.ceil(A): A의 소수점 올림값\n⑭ math.round(A): A의 소수점 반올림값\n⑮ math.factorial(A): A의 팩토리얼 값\n⑯ math.fabs(A): A의 절댓값', calc_operation_exampleCode: 'def when_start():\n Entry.print_for_sec(10 ** 2, 2)\n Entry.print_for_sec(math.sqrt(9), 2)\n Entry.print_for_sec(math.sin(90), 2)\n Entry.print_for_sec(math.fabs(-10), 2)', calc_operation_exampleDesc: '[시작하기]버튼을 클릭하면 10의 제곱, 9의 루트값, 90의 사인값, -10의 절댓값을 각 2초 동안 말합니다.', get_project_timer_value_desc: '이 명령이 실행되는 순간 초시계에 저장된 값입니다.', get_project_timer_value_exampleCode: 'def when_start():\n Entry.timer("start")\n Entry.wait_for_sec(3)\n Entry.timer("stop")\n Entry.timer_view("hide")\n Entry.print(Entry.value_of_timer())', get_project_timer_value_exampleDesc: '[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.', choose_project_timer_action_desc: '초시계의 동작을 A로 정합니다.\n(이 명령어를 사용하면 실행화면에 ‘초시계 창’이 생성됩니다.)', choose_project_timer_action_elements: 'A-- 아래 선택지 중 하나\n① "start" : 초시계를 시작\n② "stop" : 초시계를 정지\n③ "reset" : 초시계를 초기화', choose_project_timer_action_exampleCode: 'def when_start():\n Entry.timer("start")\n Entry.wait_for_sec(3)\n Entry.timer("stop")\n Entry.timer_view("hide")\n Entry.print(Entry.value_of_timer())', choose_project_timer_action_exampleDesc: '[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.', set_visible_project_timer_desc: '실행화면의 초시계 창을 A로 설정합니다.', set_visible_project_timer_elements: 'A-- 아래 선택지 중 하나\n① "hide" : 초시계창을 숨김\n② "show" : 초시계창을 보임', set_visible_project_timer_exampleCode: 'def when_start():\n Entry.timer("start")\n Entry.wait_for_sec(3)\n Entry.timer("stop")\n Entry.timer_view("hide")\n Entry.print(Entry.value_of_timer())', set_visible_project_timer_exampleDesc: '[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.', get_date_desc: '현재 A에 대한 값입니다.', get_date_elements: 'A-- 아래 선택지 중 하나\n① "year" : 현재 연도 값\n② "month" : 현재 월 값\n③ "day" : 현재 일 값\n④ "hour" : 현재 시간 값\n⑤ "minute" : 현재 분 값\n⑥ "second" : 현재 초 값', get_date_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_current_time("year") + "년" + Entry.value_of_current_time("month") + "월")', get_date_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 현재년도와 월을 말합니다.', distance_something_desc: '자신과 A까지의 거리 값입니다.', distance_something_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "mouse_pointer" 또는 "마우스포인터"', distance_something_exampleCode: 'def when_start():\n while True:\n Entry.print(Entry.value_of_distance_to("mouse_pointer"))', distance_something_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 마우스포인터와의 거리를 계속해서 말합니다.', get_sound_duration_desc: '소리 A의 길이(초)값입니다.', get_sound_duration_elements: 'A-- "소리 이름"', get_sound_duration_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_sound_length_of("소리"))', get_sound_duration_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "소리"의 길이를 말합니다.', get_user_name_desc: 'Reports the user ID who runs the project.\nThe value is masked for privacy.', get_user_name_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_username())', get_user_name_exampleDesc: '[시작하기]버튼을 클릭하면 작품을 실행하고 있는 사용자의 이름 값을 말합니다.', get_nickname_desc: '작품을 실행하고 있는 사용자의 닉네임 값입니다.', get_nickname_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_nickname())', get_nickname_exampleDesc: '[시작하기]버튼을 클릭하면 작품을 실행하고 있는 사용자의 닉네임 값을 말합니다.', length_of_string_desc: '입력한 문자값의 공백을 포함한 글자 수입니다.', length_of_string_elements: 'A-- "문자열"', length_of_string_exampleCode: 'def when_start():\n Entry.print_for_sec(len("안녕"), 2)\n Entry.print_for_sec(len("엔트리"), 2)', length_of_string_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕"과 "엔트리"의 글자 수를 각각 2초 동안 말합니다.', combine_something_desc: 'A 문자열과 B 문자열을 결합한 값입니다. (A, B 중 하나가 숫자면 문자열로 바꾸어 처리되고, 둘 다 숫자면 덧셈 연산으로 처리됩니다.)', combine_something_elements: 'A, B-- "문자열"', combine_something_exampleCode: 'def when_start():\n Entry.print("안녕! " + "엔트리")', combine_something_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕!"과 "엔트리"를 결합한 "안녕! 엔트리"를 말합니다.', char_at_desc: 'A 문자열의 B번째의 글자 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)', char_at_elements: 'A-- "문자열"%nextB-- 찾고자 하는 문자열의 위치', char_at_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!"[0])', char_at_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"의 0번째 글자인 "안"을 말합니다.', substring_desc: 'A 문자열의 B위치부터 C-1위치까지의 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)', substring_elements: 'A-- "문자열"%nextB-- 포함할 문자열의 시작 위치\n첫 번째 글자는 0부터 시작%nextC-- 문자열을 포함하지 않는 위치', substring_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!"[1:5])', substring_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"의 1에서 4번째 글자인 "녕 엔트"를 말합니다.', index_of_string_desc: 'A문자열에서 B문자열이 처음으로 등장하는 위치의 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)', index_of_string_elements: 'A, B-- "문자열"', index_of_string_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!".find("엔트리"))', index_of_string_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"에서 "엔트리"가 처음으로 등장하는 위치인 3을 말합니다.', replace_string_desc: 'A 문자열에서 B문자열을 모두 찾아 C문자열로 바꾼 값입니다.\n(영문 입력시 대소문자를 구분합니다.)', replace_string_elements: 'A, B, C-- "문자열"', replace_string_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!".replace( "안녕", "반가워"))', replace_string_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"에서 "안녕"을 "반가워"로 바꾼 "반가워 엔트리!"를 말합니다.', change_string_case_desc: 'A의 모든 알파벳을 대문자 또는 소문자로 바꾼 문자값입니다.', change_string_case_elements: 'A-- "문자열"\n① A.upper(): A의 모든 알파벳을 대문자로 바꾼 값\n② A.lower() : A의 모든 알파벳을 소문자로 바꾼 값', change_string_case_exampleCode: 'def when_start():\n Entry.print_for_sec("Hello Entry!".upper(), 2)\n Entry.print_for_sec("Hello Entry!".lower(), 2)', change_string_case_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "Hello Entry!"를 모두 대문자로 바꾼 "HELLO ENTRY!"를 2초간 말한 다음 모두 소문자로 바꾼 "hello entry!"를 2초간 말합니다.', ask_and_wait_desc: "오브젝트가 A 내용을 말풍선으로 묻고, 대답을 입력받습니다. 대답은 실행화면 또는 콘솔창에서 입력할 수 있으며 입력된 값은 'Entry.answer()'에 저장됩니다. \n(이 명령어를 사용하면 실행화면에 ‘대답 창’이 생성됩니다.)", ask_and_wait_elements: 'A-- "문자열"', ask_and_wait_exampleCode: 'def when_start():\n Entry.input("이름을 입력해보세요.")\n Entry.print(Entry.answer() + " 반가워!")', ask_and_wait_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "이름을 입력해보세요."라고 말풍선으로 묻습니다. 이름을 입력하면 "(입력한 이름) 반가워!"라 말합니다.', get_canvas_input_value_desc: 'Entry.input(A) 명령에 의해 실행화면 또는 콘솔에서 입력받은 값입니다.', get_canvas_input_value_exampleCode: 'def when_start():\n Entry.input("이름을 입력해보세요.")\n Entry.print(Entry.answer() + " 반가워!")', get_canvas_input_value_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "이름을 입력해보세요."라고 말풍선으로 묻습니다. 이름을 입력하면 "(입력한 이름) 반가워!"라 말합니다.', set_visible_answer_desc: '실행화면의 대답 창을 A로 설정합니다.', set_visible_answer_elements: 'A-- 아래 선택지 중 하나\n① "hide" : 대답 창을 숨김\n② "show" : 대답 창을 보임', set_visible_answer_exampleCode: 'def when_start():\n Entry.answer_view("hide")\n Entry.input("나이를 입력하세요.")\n Entry.print(Entry.answer())', set_visible_answer_exampleDesc: '[시작하기]버튼을 클릭하면 대답창이 숨겨지고, 오브젝트가 "나이를 입력하세요."라고 말풍선으로 묻습니다. 나이를 입력하면 오브젝트가 입력한 나이를 말합니다.', get_variable_desc: 'A 변수에 저장된 값입니다.', get_variable_elements: 'A-- 변수명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A', get_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.print(age)', get_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 말합니다.', change_variable_desc: 'A 변수에 B만큼 더합니다.', change_variable_elements: 'A-- 변수명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 숫자값', change_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.print_for_sec(age, 2)\n age += 2\n Entry.print_for_sec(age, 2)', change_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 2초 동안 말합니다. 그 후 age변수에 2를 더하고 더한값인 "18"을 2초 동안 말합니다.', set_variable_desc: 'A 변수의 값을 B로 정합니다. 만약 A 변수가 없으면 [속성] 탭에 A 변수가 자동 생성됩니다.', set_variable_elements: 'A-- 변수명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 변수에 넣을 값\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', set_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.print(age)', set_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 말합니다.', show_variable_desc: 'A 변수 창을 실행화면에 보이게 합니다.', show_variable_elements: 'A-- "변수명"\n① 모든 오브젝트에서 사용: "A"\n② 이 오브젝트에서 사용: "self.A"', show_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.hide_variable("age")\n Entry.wait_for_sec(2)\n age = 20\n Entry.show_variable("age")', show_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 age변수창을 실행화면에서 숨깁니다. 2초 후 변수값을 17로 바꾸고 age변수창을 실행화면에 보이게 합니다.', hide_variable_desc: 'A 변수 창을 실행화면에서 숨깁니다.', hide_variable_elements: 'A-- "변수명"\n① 모든 오브젝트에서 사용: "A"\n② 이 오브젝트에서 사용: "self.A"', hide_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.hide_variable("age")\n Entry.print_for_sec(age, 2)', hide_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 age변수창을 실행화면에서 숨기고, 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 2초 동안 말합니다.', value_of_index_from_list_desc: 'A 리스트에서 B위치의 항목 값을 의미합니다. \n(첫 번째 항목의 위치는 0부터 시작합니다.)', value_of_index_from_list_elements: 'A-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치', value_of_index_from_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.print(basket[1])\n', value_of_index_from_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 오브젝트가 basket 리스트의 1번째 항목인 orange를 말합니다.', add_value_to_list_desc: 'A 리스트의 마지막 항목으로 B값이 추가됩니다.', add_value_to_list_elements: 'A-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 리스트에 넣을 항목 값\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', add_value_to_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n basket.append("juice")\n Entry.print(basket[4])', add_value_to_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 "juice"를 basket의 마지막 항목으로 추가합니다. 오브젝트는 basket의 4번째 항목인 "juice"를 말합니다.', remove_value_from_list_desc: 'A 리스트의 B위치에 있는 항목을 삭제합니다.\n(첫 번째 항목의 위치는 0부터 시작합니다.)', remove_value_from_list_elements: 'A-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치값', remove_value_from_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\ndef when_start():\n basket.pop(0)\n Entry.print(basket[0])', remove_value_from_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 0번째 항목인 apple을 삭제합니다. 오브젝트는 새롭게 basket의 0번째 항목이 된 "orange"를 말합니다.', insert_value_to_list_desc: 'A 리스트의 B위치에 C항목을 끼워 넣습니다. \n(첫 번째 항목의 위치는 0부터 시작합니다. B위치보다 뒤에 있는 항목들은 순서가 하나씩 밀려납니다.)', insert_value_to_list_elements: 'A-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치%nextC-- 리스트에 넣을 항목 값\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', insert_value_to_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n basket.insert(1, "juice")\n Entry.print(basket[2])', insert_value_to_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 1번째 위치에 항목 "juice"를 끼워 넣습니다. 오브젝트는 새롭게 basket의 2번째 항목이 된 "orange"를 말합니다.', change_value_list_index_desc: 'A 리스트에서 B위치에 있는 항목의 값을 C 값으로 바꿉니다.\n(첫 번째 항목의 위치는 0부터 시작합니다.)', change_value_list_index_elements: 'A-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치%nextC-- 리스트에 넣을 항목 값\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', change_value_list_index_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n basket[0] = "juice"\n Entry.print(basket[0])', change_value_list_index_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 0번째 위치의 항목 "apple"을 "juice"로 바꿉니다. 오브젝트는 바뀐 basket의 0번째 항목 "juice"를 말합니다.', length_of_list_desc: 'A 리스트가 보유한 항목 개수 값입니다.', length_of_list_elements: 'A-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A', length_of_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.print(len(basket))', length_of_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 오브젝트는 basket의 항목 개수인 4를 말합니다.', is_included_in_list_desc: 'A값을 가진 항목이 B리스트에 포함되어 있는지 확인합니다.', is_included_in_list_elements: 'A-- 리스트의 항목 값\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등%nextB-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A', is_included_in_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n if "apple" in basket:\n Entry.print("사과가 있어!")', is_included_in_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트에 "apple"항목이 있는지 확인합니다. "apple"항목이 있기 때문에 오브젝트는 "사과가 있어!"라 말합니다.', show_list_desc: '선택한 리스트 창을 실행화면에 보이게 합니다.', show_list_elements: 'A-- "리스트명"\n① 모든 오브젝트에서 사용: "A"\n② 이 오브젝트에서 사용: "self.A"', show_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.hide_list("basket")\n Entry.wait_for_sec(2)\n Entry.show_list("basket")', show_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트를 2초간 숨긴 다음 보여줍니다.', hide_list_desc: '선택한 리스트 창을 실행화면에서 숨깁니다.', hide_list_elements: 'A-- "리스트명"\n① 모든 오브젝트에서 사용: "A"\n② 이 오브젝트에서 사용: "self.A"', hide_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.hide_list("basket")\n Entry.wait_for_sec(2)\n Entry.show_list("basket")', hide_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트를 2초간 숨긴 다음 보여줍니다.', boolean_and_or_desc: 'A와 B의 판단값을 확인하여 True 또는 False로 판단합니다.', boolean_and_or_elements: '② or : A와 B의 판단 중 하나라도 True인 경우 True, 아닌 경우 False', boolean_and_or_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("a") and Entry.is_key_pressed("s"):\n Entry.add_effect("color", 10)', boolean_and_or_exampleDesc: '[시작하기]버튼을 클릭하고 키보드의 "a" 와 "s"키를 동시에 눌렀을 때, 색깔 효과를 10만큼 줍니다.', check_weather_desc: 'B날짜에 C지역의 날씨가 A인 경우 True로 판단합니다.', check_weather_elements: 'A-- 아래 선택지 중 하나\n①    "sunny" : 맑음\n②    "partly cloudy" : 구름조금\n③    "mostly cloudy" : 구름많음\n④    "cloudy" : 흐림\n⑤    "rainy" : 비\n⑥    "sleet" : 진눈깨비\n⑦    "snowy" : 눈%nextB-- 아래 선택지 중 하나\n①    "yesterday" : 어제\n②    "today" : 오늘\n③    "tomorrow" : 내일\n④    "After 2 days" : 모레\n⑤    "After 3 days" : 3일 후\n⑥    "After 4 days" : 4일 후\n⑦    "After 5 days" : 5일 후\n⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeonbuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북', check_weather_exampleCode: 'def when_start():\n if Weather.is_condition_sunny("today", "Seoul"):\n Entry.print("오늘 서울의 날씨는 맑습니다.")', check_weather_exampleDesc: '[시작하기]버튼을 클릭하면 오늘 서울의 날씨가 맑은지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 "오늘 서울의 날씨는 맑습니다."라고 말합니다.​', check_finedust_desc: '선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.', check_finedust_elements: 'A-- 아래 선택지 중 하나\n①    "good" : 좋음\n②    "normal" : 보통\n③    "bad" : 나쁨\n④    "very bad" : 매우나쁨%nextB-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeonbuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북', check_finedust_exampleCode: 'def when_start():\n if Weather.is_current_finedust_grade_good("Seoul"):\n Entry.print("현재 서울의 미세먼지 등급은 좋음입니다.")', check_finedust_exampleDesc: '[시작하기]버튼을 클릭하면 현재 서울의 미세먼지 등급이 좋음인지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 “오늘 서울의 미세먼지 등급은 좋음입니다.”라고 말합니다.​', get_weather_data_desc: '선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.', get_weather_data_elements: 'A-- 아래 선택지 중 하나\n①    "the lowest temperature" : 최저기온\n②    "the highest temperature" : 최고기온\n③    "humidity" : 습도\n④    "precipitation" : 강수량\n⑤    "precipitation probability" : 강수확률\n⑥    "wind speed" : 풍속%nextB-- 아래 선택지 중 하나\n①    "yesterday" : 어제\n②    "today" : 오늘\n③    "tomorrow" : 내일\n④    "After 2 days" : 모레\n⑤    "After 3 days" : 3일 후\n⑥    "After 4 days" : 4일 후\n⑦    "After 5 days" : 5일 후\n⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeonbuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북', get_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_lowest_temperature("today", "Seoul"))', get_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 최저기온을 말합니다.​', get_current_weather_data_desc: '현재 B지역의 A 날씨 정보값을 의미합니다.', get_current_weather_data_elements: 'A-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeonbuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나\n①    "temperature" : 기온\n②    "concentration of fine dust" : 미세먼지농도', get_current_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_current_temperature("Seoul"))', get_current_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 현재 서울의 기온을 말합니다.', get_today_temperature_desc: '오늘 A지역의 B 시간대 기온 정보값을 의미합니다.', get_today_temperature_elements: 'A-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeonbuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나\n①    "00" : 당일 00시 측정된 기온값\n②    "03" : 당일 03시 측정된 기온값\n③    "06" : 당일 06시 측정된 기온값\n④    "09" : 당일 09시 측정된 기온값\n⑤    "12" : 당일 12시 측정된 기온값\n⑥    "15" : 당일 15시 측정된 기온값\n⑦    "18" : 당일 18시 측정된 기온값\n⑧    "21" : 당일 21시 측정된 기온값', get_today_temperature_exampleCode: 'def when_start():\n Entry.print(Weather.get_today_temperature("Seoul", 00))', get_today_temperature_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 00시 기온을 말합니다.​', check_city_weather_desc: 'B날짜에 C지역의 날씨가 A인 경우 True로 판단합니다.', check_city_weather_elements: 'A-- 아래 선택지 중 하나\n①    "sunny" : 맑음\n②    "partly cloudy" : 구름조금\n③    "mostly cloudy" : 구름많음\n④    "cloudy" : 흐림\n⑤    "rainy" : 비\n⑥    "sleet" : 진눈깨비\n⑦    "snowy" : 눈%nextB-- 아래 선택지 중 하나\n①    "yesterday" : 어제\n②    "today" : 오늘\n③    "tomorrow" : 내일\n④    "After 2 days" : 모레\n⑤    "After 3 days" : 3일 후\n⑥    "After 4 days" : 4일 후\n⑦    "After 5 days" : 5일 후\n⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeonbuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북', check_city_weather_exampleCode: 'def when_start():\n if Weather.is_condition_sunny("today", "Seoul"):\n Entry.print("오늘 서울의 날씨는 맑습니다.")', check_city_weather_exampleDesc: '[시작하기]버튼을 클릭하면 오늘 서울의 날씨가 맑은지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 "오늘 서울의 날씨는 맑습니다."라고 말합니다.​', check_city_finedust_desc: '선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.', check_city_finedust_elements: 'A-- 아래 선택지 중 하나\n①    "good" : 좋음\n②    "normal" : 보통\n③    "bad" : 나쁨\n④    "very bad" : 매우나쁨%nextB-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeonbuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북', check_city_finedust_exampleCode: 'def when_start():\n if Weather.is_current_finedust_grade_good("Seoul"):\n Entry.print("현재 서울의 미세먼지 등급은 좋음입니다.")', check_city_finedust_exampleDesc: '[시작하기]버튼을 클릭하면 현재 서울의 미세먼지 등급이 좋음인지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 “오늘 서울의 미세먼지 등급은 좋음입니다.”라고 말합니다.​', get_city_weather_data_desc: '선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.', get_city_weather_data_elements: 'A-- 아래 선택지 중 하나\n①    "the lowest temperature" : 최저기온\n②    "the highest temperature" : 최고기온\n③    "humidity" : 습도\n④    "precipitation" : 강수량\n⑤    "precipitation probability" : 강수확률\n⑥    "wind speed" : 풍속%nextB-- 아래 선택지 중 하나\n①    "yesterday" : 어제\n②    "today" : 오늘\n③    "tomorrow" : 내일\n④    "After 2 days" : 모레\n⑤    "After 3 days" : 3일 후\n⑥    "After 4 days" : 4일 후\n⑦    "After 5 days" : 5일 후\n⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeonbuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북', get_city_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_lowest_temperature("today", "Seoul"))', get_city_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 최저기온을 말합니다.​', get_current_city_weather_data_desc: '현재 B지역의 A 날씨 정보값을 의미합니다.', get_current_city_weather_data_elements: 'A-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeonbuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나\n①    "temperature" : 기온\n②    "concentration of fine dust" : 미세먼지농도', get_current_city_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_current_temperature("Seoul"))', get_current_city_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 현재 서울의 기온을 말합니다.', get_today_city_temperature_desc: '오늘 A지역의 B 시간대 기온 정보값을 의미합니다.', get_today_city_temperature_elements: 'A-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeonbuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나\n①    "00" : 당일 00시 측정된 기온값\n②    "03" : 당일 03시 측정된 기온값\n③    "06" : 당일 06시 측정된 기온값\n④    "09" : 당일 09시 측정된 기온값\n⑤    "12" : 당일 12시 측정된 기온값\n⑥    "15" : 당일 15시 측정된 기온값\n⑦    "18" : 당일 18시 측정된 기온값\n⑧    "21" : 당일 21시 측정된 기온값', get_today_city_temperature_exampleCode: 'def when_start():\n Entry.print(Weather.get_today_city_temperature("Seoul", 00))', get_today_city_temperature_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 00시 기온을 말합니다.​', }; Lang.Painter = { select_cut: 'You can cut with a square dotted line.', thickness_of_eraser: 'Thickness of eraser', font: 'Font', font_color: 'Font color', outline_color: 'Outline color', outline_thickness: 'Outline thickness', fill_color: 'Fill', inversion: 'Inversion', font_size: 'Font size', font_family: 'Font family', fullscreen: 'Full screen', exit_fullscreen: 'Exit full screen', picture_import: 'Import a shape', edit_way: 'Convert', line: 'Line', vertex: 'Vertex', bitmap: 'Bitmap', vector: 'Vector', forward: 'forward', backward: 'backward', front: 'front', back: 'back', group: 'group', ungroup: 'ungroup', copy_picture: 'copy', delete_picture: 'delete', cut_picture: 'cut', paste_picture: 'paste', remove_all: 'clear', new_picture: 'New shape', edit: 'Edit', picture_size: 'Size', picture_rotation: 'Rotation', thickness: 'thickness', font_fill: 'Fill', painter_file_save: 'Save', painter_file_saveas: 'Save as a new shape', file: 'File', Pencil: 'Pen', Line: 'Line', Path: 'Path', Pan: 'Move', Select: 'Select', Rectangle: 'Rectangle', Ellipse: 'Ellipse', Text: 'Text box', Fill: 'Fill', Eraser: 'Eraser', get_file: 'get', copy_file: 'copy', }; Lang.DataAnalytics = { data_analysis: 'Data Analysis', create_table: 'Add Table', data: 'Data Analysis', add_table: 'Add Table', show_chart: 'Show Chart', legend: 'Legend', dashboard: 'Dashboard', table: 'Table', chart: 'Chart', attribute: 'Column', row: 'Row', average: 'Average', standard_deviation: 'Standard Deviation', maximum: 'Maximum', minimum: 'Minimum', median: 'Median', average_explain: 'The result that add all values of that property and divide the total by number of the property.', standard_deviation_explain: 'A value that tells how spread out the data are from the average.\nCloser to zero means that the values are concentrated near the average.', maximum_minimum_explain: 'Largest and Smallest values for the property', median_explain: 'The value located at the center of the whole when all the values of the property are arranged in size order.', add_row_above: 'Add row above', add_row_below: 'Add row below', delete_row: 'Delete Row', add_property_left: 'Add Property to left', add_property_right: 'Add Property to right', delete_attribute: 'Delete Attribute', data_alert: 'You can only see counts for attributes that contain non-numeric values.', save: 'Save', cancel: 'Cancel', confirm: 'OK', attribute_count: '.', row_count: 'row', cell_count: 'cell', count: 'count', add_chart_alert: 'No chart in table.\nAdd table.', enter_attribute_name: 'Please enter a column name(with less than 10 characters).', placeholder_attribute_name: 'Column name', new_attribute: 'New column', chart_title: 'Chart title', remove_chart: 'Delete chart', add_chart_first: 'No chart in table. \nAdd table.', bar: 'Bar', line: 'Line', pie: 'Pie', scatter: 'Scatter', bar_sub: 'Bar graph', line_sub: 'Line graph', pie_sub: 'Pie chart', scatter_sub: 'Scatter plot', select_x_axis: 'Select the x-axis.', x_axis: 'x-axis', y_axis: 'y-axis', select_y_axis: 'Select the y-axis.', select_y_axis_or_legend: 'Select the y-axis or legends.', select_legend: 'Select the legends.', cell: 'Cell', unable_to_express_chart: 'This cannot be expressed in charts.', edit_attribute_name: 'Change name', duplicate_attribute_name_title: 'Failed to change column name.', duplicate_attribute_name_content: 'A column with the same name exists.', fail_save_table: 'Failed to save table.', duplicate_table_name_content: 'A table with the same name exists.', saved_table_title: 'Saved successfully.', saved_table_content: 'The information of table and charts was successfully saved.', empty_table_name_content: "Table's name can't be space.", do_not_delete_row: 'The row cannot be deleted.', rows_cannot_less_one: 'Tables must have at least one row.', and: 'and', other: 'other(s)', stop: 'Project Stop', restart: 'Project Resume', pause: 'Project Pause', max_row_count_error_title: 'Caution', max_row_count_error: 'If the table has more than 5000 rows, When you edit a table or add a chart, your browser might stop.\nIf there is a problem, please adjust the number of rows.', attributes_text: '%1 and %2 other(s)', duplicate: 'Duplicate', copy: 'Copy', delete: 'Delete', paste: 'Paste', cut: 'Cut', download: 'Download', download_table: 'Download as an Excel file', confirm_content: 'Should I save the changed tables and charts?', please_add_table: 'Please add a table first.', load_data_analytics: 'Load table', summary_table_description: 'Basic statistics based on columns in the table.', not_exist_chart: 'No charts have been added.', please_add_chart: 'Please add the chart first.', chart_name: 'Chart name', remove_confirm_content: 'Should I delete the table?', not_editable_content: 'The table has more than 30,000 cells,\r\nso it cannot be edited in the entry.', limit_cell_count_title: 'Limit of rows/columns', limit_cell_count_content: 'You can no longer add rows or columns.\r\nEntry only allows editing of tables\r\nup to 30,000 cells.', must_have_one_row_content: 'The table must have more than one row and column.', number_of_bins: 'Number of bins', bin_width: 'Bin width', bin_boundary: 'Bin boundary', left_closed: 'Left closed', right_closed: 'Right closed', ascending: 'Ascending', default: 'Default', quantity: 'Quantity', in_order: 'In order', not_distinguished: 'Not distinguished', select_table: 'Click [Add Table] to add table.', select_table_title: 'How to add table', select_table_des1: "1. On the 'Select table' tab, select the default table provided by the Entry.", select_table_des2: "2. On the 'Upload files' tab, upload the CSV, XLS(X) file directly.", select_table_des3: "3. On the 'New table' tab, add an empty table and enter the data directly.", statistic: 'Representative value', provider: 'Source', description: 'Description', field_info: 'Field Info', show_all_points: 'Show All Points', coefficient: 'Coefficient', scatter_matrix: 'Scatter Matrix', show_table: 'Show Table', value: 'Value', summary: 'Summary', column_name: 'Column Name', total: 'Total', histogram: 'Histogram', select_legend2: 'Select at least 2 legends.', }; Lang.SharePolicy = { title: 'Entry Project/Post share Guide', }; Lang.pose_list = { nose: 'nose', left_eye_inner: 'left eye (inner)', left_eye: 'left eye', left_eye_outer: 'left eye (outer)', right_eye_inner: 'right eye (inner)', right_eye: 'right eye', right_eye_outer: 'right eye (outer)', left_ear: 'left ear', right_ear: 'right ear', mouth_left: 'mouth (left)', mouth_right: 'mouth (right)', left_shoulder: 'left shoulder', right_shoulder: 'right shoulder', left_elbow: 'left elbow', right_elbow: 'right elbow', left_wrist: 'left wrist', right_wrist: 'right wrist', left_pinky: 'left pinky', right_pinky: 'right pinky', left_index: 'left index', right_index: 'right index', left_thumb: 'left thumb', right_thumb: 'right thumb', left_hip: 'left hip', right_hip: 'right hip', left_knee: 'left knee', right_knee: 'right knee', left_ankle: 'left ankle', right_ankle: 'right ankle', left_heel: 'left heel', right_heel: 'right heel', left_foot_index: 'left foot index', right_foot_index: 'right foot index', }; Lang.gesture_list = { closed_fist: 'Closed Fist', open_palm: 'Open Palm', pointing_up: 'Pointing Up', thumb_down: 'Thumb Down', thumb_up: 'Thumb Up', victory: 'Victory', iloveyou: 'I Love You', none: 'Unknown', }; Lang.Support = ['ko', 'en', 'vn', 'jp']; if (typeof exports == 'object') exports.Lang = Lang; ================================================ FILE: extern/lang/jp.js ================================================ var Lang = {}; Lang.category = { "name": "en" }; Lang.type = "jp"; Lang.fallbackType = "en"; Lang.ko = "한국어"; Lang.en = "English"; Lang.jp = "日本語"; Lang.vn = "tiếng Việt"; Lang.Command = { "1": "장면 추가하기", "2": "장면 삭제하기", "3": "장면 이름 수정", "4": "장면 순서 변경", "5": "장면 선택", "101": "ブロックスレッドを追加する", "102": "ブロックスレッドを削除する", "103": "ブロックを削除する", "104": "ブロックを復旧する", "105": "ブロックを挿入する", "106": "ブロックを分離する", "107": "ブロックを移動する", "108": "ブロックをコピーする", "109": "ブロックのコピーを取り消す", "110": "スクロール", "111": "ブロックフィールド値を修正", "117": "ブロックスレッドを追加する", "118": "ブロックを挿入する", "119": "ブロックを移動する", "120": "ブロックを分離する", "121": "ブロックを移動する", "122": "ブロックを挿入する", "123": "ブロックを挿入する", "201": "オブジェクトを選択する", "202": "오브젝트 수정 버튼 클릭", "203": "오브젝트 그림 추가", "204": "오브젝트 그림 삭제", "205": "오브젝트 소리 추가", "206": "오브젝트 소리 삭제", "207": "오브젝트 이름 수정", "208": "오브젝트 추가", "209": "오브젝트 삭제", "210": "오브젝트 추가 버튼 클릭", "211": "오브젝트 x 수정", "212": "오브젝트 y 수정", "213": "오브젝트 size 수정", "214": "오브젝트 방향 수정", "215": "오브젝트 이동 방향 수정", "216": "오브젝트 회전방식 수정", "217": "엔터티 모델 동기화", "301": "do", "302": "undo", "303": "redo", "401": "図を修正する", "402": "図の修正を取り消す", "403": "図を修正する", "404": "図の修正を取り消す", "405": "글상자 수정", "501": "スタート", "502": "停止する", "601": "コンテナーオブジェクトを選択する", "701": "モード変換 ", "702": "模様追加ボタンをクリック", "703": "サウンド追加ボタンをクリック", "801": "変数属性ウィンドウフィルターを選択する", "802": "変数を追加するボタンをクリック", "803": "変数を追加する", "804": "変数を削除する", "805": "変数名設定", "806": "신호 이름 설정", "807": "신호 추가", "808": "신호 삭제", "809": "변수 스코프 정하기", "810": "변수 글로벌 체크", "811": "변수 보이기 체크", "812": "변수 기본값 설정", "813": "변수 슬라이드로 체크", "814": "변수 최솟값 정하기", "815": "변수 최댓값 정하기", "816": "리스트 추가 버튼 클릭", "817": "리스트 추가", "818": "리스트 삭제", "819": "리스트 이름 정하기", "820": "리스트 스코프 정하기", "821": "리스트 글로벌 체크", "822": "리스트 보이기 체크", "823": "리스트 길이 변경", "824": "리스트 기본값 설정", "825": "메세지 수정 enable", "826": "변수 수정 enable", "827": "리스트 수정 enable", "828": "변수 이름 정하기", "829": "리스트 이름 정하기", "900": "모달 닫기", "1001": "함수 생성 시작", "1002": "함수 수정 시작", "1003": "함수 수정 취소", "1004": "함수 생성", "1005": "함수 업데이트" }; Lang.CommandTooltip = { "101": "ブロックスレッドを追加する", "102": "ブロックスレッドを削除する", "103": "ブロックを削除する", "104": "ブロックを復旧する", "105": "コードを分離する$$コードを連結する@@このコードの一番上にあるブロックを掴んで分離しドラッグします。$$ここにコードを連結します。$$ここにブロックの左端を挿入します。", "106": "ブロックを分離する", "107": "ブロックを移動する", "108": "ブロックをコピーする", "109": "ブロックのコピーを取り消す", "110": "スクロール", "111": "ブロックフィールド値を修正@@値を入力するためここをクリックします。$$選択肢をクリックします。$$選択肢をクリックします。$$&value&を入力します。$$&value&を選択します。$$キーボード &value&を押します。", "117": "ブロックスレッドを追加する", "118": "ブロックを連結する@@ここにブロックを連結します。$$ここにブロックの左端を挿入します。", "119": "ブロックをインポートする@@空いている場所にブロックをドラッグ&ドロップします。", "120": "ブロックを分離する$$ブロックを削除する@@必要のないコードをゴミ箱にドラッグします。$$ここにコードを捨てます。", "121": "ブロックを移動する$$ブロックを削除する@@必要のないコードをゴミ箱にドラッグします。$$ここにコードを捨てます。", "122": "ブロックを連結する@@ここにブロックを連結します。$$ここにブロックの左端を挿入します。", "123": "コードを分離する$$コードを連結する@@このコードの一番上にあるブロックを掴んで分離しドラッグします。$$ここにコードを連結します。$$ここにブロックの左端を挿入します。", "201": "オブジェクトを削除する", "301": "do", "302": "undo", "303": "redo", "401": "図を修正する", "402": "図の修正を取り消す", "403": "図を修正する", "404": "図の修正を取り消す", "501": "実行する@@[スタート]を押します。", "502": "停止する@@[停止する]を押します。", "601": "コンテナーオブジェクトを削除する", "701": "モード変換 ", "702": "模様を追加する@@模様追加をクリックします。", "703": "サウンドを追加する@@サウンド追加をクリックします。", "801": "変数属性ウィンドウフィルターを選択する", "802": "変数を追加する@@[変数追加]をクリックします。", "803": "変数を追加する@@[確認]をクリックします。", "804": "変数を削除する@@このボタンを押して変数を削除します。", "805": "変数名設定", "1101": "サウンドを追加する@@サウンド追加をクリックします。" }; Lang.Blocks = { "download_guide": "• 接続ガイドをダウンロード", "dictionary": "dictionary", "ai_utilize": "AI", "date_yesterday": "昨日", "date_today": "今日", "date_tomorrow": "明日", "date_after_2_days": "明後日", "date_after_3_days": "明々後日", "date_after_4_days": "4日後", "date_after_5_days": "5日後", "date_after_6_days": "6日後", "location_entire": "全体", "location_seoul": "ソウル", "location_seoul_jongno_gu": "鍾路区", "location_seoul_jung_gu": "中区", "location_seoul_yongsan_gu": "龍山区", "location_seoul_seongdong_gu": "城東区", "location_seoul_gwangjin_gu": "広津区", "location_seoul_dongdaemun_gu": "東大門区", "location_seoul_jungnang_gu": "中浪区", "location_seoul_seongbuk_gu": "城北区", "location_seoul_gangbuk_gu": "江北区", "location_seoul_dobong_gu": "道峰区", "location_seoul_nowon_gu": "蘆原区", "location_seoul_eunpyeong_gu": "恩平区", "location_seoul_seodaemun_gu": "西大門区", "location_seoul_mapo_gu": "麻浦区", "location_seoul_yangcheon_gu": "陽川区", "location_seoul_gangseo_gu": "江西区", "location_seoul_guro_gu": "九老区", "location_seoul_geumcheon_gu": "衿川区", "location_seoul_yeongdeungpo_gu": "永登浦区", "location_seoul_dongjak_gu": "銅雀区", "location_seoul_gwanak_gu": "冠岳区", "location_seoul_seocho_gu": "瑞草区", "location_seoul_gangnam_gu": "江南区", "location_seoul_songpa_gu": "松坡区", "location_seoul_gangdong_gu": "江東区", "location_busan": "プサン", "location_busan_jung_gu": "中区", "location_busan_seo_gu": "西区", "location_busan_dong_gu": "東区", "location_busan_yeongdo_gu": "影島区", "location_busan_busanjin_gu": "鎮区", "location_busan_dongnae_gu": "東莱区", "location_busan_nam_gu": "南区", "location_busan_buk_gu": "北区", "location_busan_haeundae_gu": "海雲台区", "location_busan_saha_gu": "沙下区", "location_busan_geumjeong_gu": "金井区", "location_busan_gangseo_gu": "江西区", "location_busan_yeonje": "蓮堤区", "location_busan_suyeong_gu": "水営区", "location_busan_sasang_gu": "沙上区", "location_busan_gijang": "機張郡", "location_daegu": "テグ", "location_daegu_jung_gu": "中区", "location_daegu_dong_gu": "東区", "location_daegu_seo_gu": "西区", "location_daegu_nam_gu": "南区", "location_daegu_buk_gu": "北区", "location_daegu_suseong_gu": "寿城区", "location_daegu_dalseo_gu": "達西区", "location_daegu_dalseong": "達城郡", "location_incheon": "インチョン", "location_incheon_jung_gu": "中区", "location_incheon_dong_gu": "東区", "location_incheon_nam_gu": "南区", "location_incheon_yeonsu_gu": "延寿区", "location_incheon_namdong_gu": "南洞区", "location_incheon_bupyeong_gu": "富平区", "location_incheon_gyeyang_gu": "桂陽区", "location_incheon_seo_gu": "西区", "location_incheon_ganghwa": "江華郡", "location_incheon_ongjin_gun": "甕津郡", "location_gwangju": "クヮンジュ", "location_gwangju_dong_gu": "東区", "location_gwangju_seo_gu": "西区", "location_gwangju_nam_gu": "南区", "location_gwangju_buk_gu": "北区", "location_gwangju_gwangsan_gu": "光山区", "location_daejeon": "テジョン", "location_daejeon_dong_gu": "東区", "location_daejeon_jung_gu": "中区", "location_daejeon_seo_gu": "西区", "location_daejeon_yuseong_gu": "儒城区", "location_daejeon_daedeok_gu": "大徳区", "location_ulsan": "ウルサン", "location_ulsan_jung_gu": "中区", "location_ulsan_nam_gu": "南区", "location_ulsan_dong_gu": "東区", "location_ulsan_buk_gu": "北区", "location_ulsan_ulju": "蔚州郡", "location_sejong": "セジョン", "location_gyeonggi": "キョンギ道", "location_gyeonggi_suwon_si": "水原市", "location_gyeonggi_seongnam": "城南市", "location_gyeonggi_uijeongbu": "議政府市", "location_gyeonggi_anyang_si": "安養市", "location_gyeonggi_bucheon_si": "富川市", "location_gyeonggi_gwangmyeong_si": "光明市", "location_gyeonggi_pyeongtaek_si": "平沢市", "location_gyeonggi_dongducheon_si": "東豆川市", "location_gyeonggi_ansan_si": "安山市", "location_gyeonggi_goyang_si": "高陽市", "location_gyeonggi_gwacheon_si": "果川市", "location_gyeonggi_guri": "九里市", "location_gyeonggi_namyangju_si": "南楊州市", "location_gyeonggi_osan": "烏山市", "location_gyeonggi_siheung": "始興市", "location_gyeonggi_gunpo_si": "軍浦市", "location_gyeonggi_uiwang_si": "義王市", "location_gyeonggi_hanam": "河南市", "location_gyeonggi_yongin_si": "龍仁市", "location_gyeonggi_paju": "坡州市", "location_gyeonggi_icheon": "利川市", "location_gyeonggi_anseong_si": "安城市", "location_gyeonggi_gimpo": "金浦市", "location_gyeonggi_hwaseong_si": "華城市", "location_gyeonggi_gwangju": "光州市", "location_gyeonggi_yangju_si": "揚州市", "location_gyeonggi_pocheon": "抱川市", "location_gyeonggi_yeoju": "驪州市", "location_gyeonggi_yeoncheon_gun": "漣川郡", "location_gyeonggi_gapyeong_gun": "加平郡", "location_gyeonggi_yangpyeong": "楊平郡", "location_gangwon": "カンウォン道", "location_gangwon_chuncheon": "春川市", "location_gangwon_wonju": "原州市", "location_gangwon_gangneung_si": "江陵市", "location_gangwon_donghae": "東海市", "location_gangwon_taebaek_si": "太白市", "location_gangwon_sokcho": "束草市", "location_gangwon_samcheok_si": "三陟市", "location_gangwon_hongcheon": "洪川郡", "location_gangwon_hoengseong_gun": "横城郡", "location_gangwon_yeongwol_gun": "寧越郡", "location_gangwon_pyeongchang": "平昌郡", "location_gangwon_jeongseon": "旌善郡", "location_gangwon_cheolwon": "鉄原郡", "location_gangwon_hwacheon": "華川郡", "location_gangwon_yanggu": "楊口郡", "location_gangwon_inje": "麟蹄郡", "location_gangwon_goseong": "高城郡", "location_gangwon_yangyang": "襄陽郡", "location_chungcheongbuk": "チュンチョンブク道", "location_chungcheongbuk_cheongju": "清州市", "location_chungcheongbuk_chungju": "忠州市", "location_chungcheongbuk_jecheon": "堤川市", "location_chungcheongbuk_boeun": "報恩郡", "location_chungcheongbuk_okcheon": "沃川郡", "location_chungcheongbuk_yeongdong": "永同郡", "location_chungcheongbuk_jeungpyeong": "曽坪郡", "location_chungcheongbuk_jincheon": "鎮川郡", "location_chungcheongbuk_goesan": "槐山郡", "location_chungcheongbuk_eumseong": "陰城郡", "location_chungcheongbuk_danyang": "丹陽郡", "location_chungcheongnam": "チュンチョンナム道", "location_chungcheongnam_cheonan": "天安市", "location_chungcheongnam_gongju": "公州市", "location_chungcheongnam_boryeong": "保寧市", "location_chungcheongnam_asan": "牙山市", "location_chungcheongnam_seosan": "瑞山市", "location_chungcheongnam_nonsan": "論山市", "location_chungcheongnam_gyeryong": "鶏龍市", "location_chungcheongnam_dangjin": "唐津市", "location_chungcheongnam_geumsan": "錦山郡", "location_chungcheongnam_buyeo": "扶余郡", "location_chungcheongnam_seocheon": "舒川郡", "location_chungcheongnam_cheongyang": "青陽郡", "location_chungcheongnam_hongseong": "洪城郡", "location_chungcheongnam_yesan": "礼山郡", "location_chungcheongnam_taean": "泰安郡", "location_jeollabuk": "チョンラブク道", "location_jeollabuk_jeonju": "全州市", "location_jeollabuk_gunsan_si": "群山市", "location_jeollabuk_iksan": "益山市", "location_jeollabuk_jeongeup": "井邑市", "location_jeollabuk_namwon": "南原市", "location_jeollabuk_gimje_si": "金堤市", "location_jeollabuk_wanju": "完州郡", "location_jeollabuk_jinan": "鎮安郡", "location_jeollabuk_muju": "茂朱郡", "location_jeollabuk_jangsu": "長水郡", "location_jeollabuk_imsil": "任實郡", "location_jeollabuk_sunchang": "淳昌郡", "location_jeollabuk_gochang": "高敞郡", "location_jeollabuk_buan": "扶安郡", "location_jeollanam": "チョンラナム道", "location_jeollanam_mokpo": "木浦市", "location_jeollanam_yosu": "麗水市", "location_jeollanam_suncheon_si": "順天市", "location_jeollanam_naju": "羅州市", "location_jeollanam_gwangyang_si": "光陽市", "location_jeollanam_damyang": "潭陽郡", "location_jeollanam_gokseong": "谷城郡", "location_jeollanam_gurye": "求礼郡", "location_jeollanam_goheung": "高興郡", "location_jeollanam_boseong": "宝城郡", "location_jeollanam_hwasun": "和順郡", "location_jeollanam_jangheung": "長興郡", "location_jeollanam_gangjin": "康津郡", "location_jeollanam_haenam": "海南郡", "location_jeollanam_yeongam": "霊岩郡", "location_jeollanam_jindo": "務安郡", "location_jeollanam_muan": "咸平郡", "location_jeollanam_hampyeong": "霊光郡", "location_jeollanam_yeonggwang": "長城郡", "location_jeollanam_jangseong": "莞島郡", "location_jeollanam_wando": "珍島郡", "location_jeollanam_sinan": "新安郡", "location_gyeongsangbuk": "キョンサンブク道", "location_gyeongsangbuk_pohang_si": "浦項市", "location_gyeongsangbuk_gyeongju_si": "慶州市", "location_gyeongsangbuk_gimcheon_si": "金泉市", "location_gyeongsangbuk_andong_si": "安東市", "location_gyeongsangbuk_gumi_si": "亀尾市", "location_gyeongsangbuk_yeongju_si": "栄州市", "location_gyeongsangbuk_yeongcheon_si": "永川市", "location_gyeongsangbuk_sangju_si": "尚州市", "location_gyeongsangbuk_mungyeong_si": "聞慶市", "location_gyeongsangbuk_gyeongsan_si": "慶山市", "location_gyeongsangbuk_gunwi": "軍威郡", "location_gyeongsangbuk_uiseong": "義城郡", "location_gyeongsangbuk_cheongsong": "青松郡", "location_gyeongsangbuk_goryong": "英陽郡", "location_gyeongsangbuk_yeongdeok": "盈徳郡", "location_gyeongsangbuk_cheongdo": "清道郡", "location_gyeongsangbuk_golyeong": "高靈郡", "location_gyeongsangbuk_seongju": "星州郡", "location_gyeongsangbuk_chilgok": "漆谷郡", "location_gyeongsangbuk_yecheon": "醴泉郡", "location_gyeongsangbuk_bonghwa": "奉化郡", "location_gyeongsangbuk_uljin": "蔚珍郡", "location_gyeongsangbuk_ulleung": "鬱陵郡", "location_gyeongsangnam": "キョンサンナム道", "location_gyeongsangnam_changwon_si": "昌原市", "location_gyeongsangnam_jinju": "晋州市", "location_gyeongsangnam_tongyeong_si": "統営市", "location_gyeongsangnam_sacheon_si": "泗川市", "location_gyeongsangnam_gimhae_si": "金海市", "location_gyeongsangnam_miryang_si": "密陽市", "location_gyeongsangnam_geoje_si": "巨済市", "location_gyeongsangnam_yangsan_si": "梁山市", "location_gyeongsangnam_uiryeong": "宜寧郡", "location_gyeongsangnam_haman": "咸安郡", "location_gyeongsangnam_changnyeong": "昌寧郡", "location_gyeongsangnam_goseong": "高城郡", "location_gyeongsangnam_namhae": "南海郡", "location_gyeongsangnam_hadong": "河東郡", "location_gyeongsangnam_sancheong": "山清郡", "location_gyeongsangnam_hamyang": "咸陽郡", "location_gyeongsangnam_geochang": "居昌郡", "location_gyeongsangnam_hapcheon": "陜川郡", "location_jeju": "チェジュ", "location_jeju_jeju_si": "済州市", "location_jeju_seogwipo": "西帰浦市", "EXPANSION_WEATHER_sunny": "快晴", "EXPANSION_WEATHER_partly_cloudy": "晴れぎみ", "EXPANSION_WEATHER_mostly_cloudy": "くもりぎみ", "EXPANSION_WEATHER_cloudy": "くもり", "EXPANSION_WEATHER_rainy": "雨", "EXPANSION_WEATHER_sleet": "みぞれ", "EXPANSION_WEATHER_snowy": "雪", "EXPANSION_WEATHER_finedust_good": "良い", "EXPANSION_WEATHER_finedust_normal": "普通", "EXPANSION_WEATHER_finedust_bad": "悪い", "EXPANSION_WEATHER_finedust_very_bad": "とても悪い", "EXPANSION_WEATHER_lowest_temperature": "最低気温(℃)", "EXPANSION_WEATHER_highest_temperature": "最高気温(℃)", "EXPANSION_WEATHER_humidity": "湿度(%)", "EXPANSION_WEATHER_precipitation": "降水量(mm)", "EXPANSION_WEATHER_precipitation_probability": "降水確率(%)", "EXPANSION_WEATHER_wind_speed": "風速(m/s)", "EXPANSION_WEATHER_temperature": "気温(℃)", "EXPANSION_WEATHER_finedust": "PM10濃度(㎍)", "EXPANSION_FESTIVAL_title": "タイトル", "EXPANSION_FESTIVAL_area": "エリア", "EXPANSION_FESTIVAL_start_date": "開始日", "EXPANSION_FESTIVAL_end_date": "終了日", "EXPANSION_FESTIVAL_address": "アドレス", "EXPANSION_FESTIVAL_coordinate": "座標", "EXPANSION_FESTIVAL_overview": "概要", "EXPANSION_FESTIVAL_homepage": "ホームページ", "no_data": "情報なし", "no_sentence": "テキストなし", "sentence_over_20_charactor": "20字のみ入力できます。", "sentence_over_3000_charactor": "3000字のみ入力できます。", "sentence_over_2500_charactor": "2500文字のみ入力できます。", "unknown_sentence": "認識不可能なテキストです。", "auto": "自動", "korean": "韓国語", "english": "英語", "spanish": "スペイン語", "french": "フランス語", "german": "ドイツ語", "russian": "ロシア語", "portuguese": "ポルトガル語", "hindi": "ヒンディー語", "japan": "日本語", "thai": "タイ語", "vietnamese": "ベトナム語", "indonesian": "インドネシア語", "chinese_simplified": "簡体字中国語", "chinese_traditional": "繁体字中国語", "italian": "イタリア語", "behaviorConduct01001": "台風", "behaviorConduct01002": "洪水", "behaviorConduct01003": "豪雨", "behaviorConduct01004": "強風", "behaviorConduct01005": "大雪", "behaviorConduct01006": "寒波", "behaviorConduct01007": "波浪", "behaviorConduct01008": "黄砂", "behaviorConduct01009": "猛暑", "behaviorConduct01010": "干ばつ", "behaviorConduct01011": "地震", "behaviorConduct01013": "津波", "behaviorConduct01014": "地滑り", "behaviorConduct03002": "応急処置", "behaviorConduct03003": "心肺蘇生法", "behaviorConduct03004": "消火栓の使い方", "behaviorConduct03016": "消火器の使い方", "behaviorConduct03005": "食中毒", "behaviorConduct03006": "山の安全対策", "behaviorConduct03008": "失踪と誘拐", "behaviorConduct03009": "性暴力", "behaviorConduct03010": "学校暴力", "behaviorConduct03011": "家庭内暴力", "behaviorConduct03012": "抑留および拉致", "behaviorConduct03013": "交通事故", "behaviorConduct03014": "エレベーター事故", "behaviorConduct03015": "浮遊粒子状物質", "behaviorConduct01001001": "台風が来る前", "behaviorConduct01001002": "台風警報が出された時", "behaviorConduct01001003": "台風が通り過ぎた後", "behaviorConduct01002002": "洪水予報時", "behaviorConduct01002003": "水が押し寄せる時", "behaviorConduct01002004": "水が抜けた後", "behaviorConduct01003002": "大雨予報時", "behaviorConduct01003003": "大雨注意報∙警報が出された時", "behaviorConduct01003004": "大雨が過ぎ去った後", "behaviorConduct01004001": "強風が来る前", "behaviorConduct01004002": "強風発生時", "behaviorConduct01005002": "大雪が来る前", "behaviorConduct01005003": "大雪発生時", "behaviorConduct01005004": "大雪が通り過ぎた後", "behaviorConduct01006001": "寒波が押し寄せる前", "behaviorConduct01006002": "寒波発生時", "behaviorConduct01007001": "波浪注意報・警報時", "behaviorConduct01007002": "波浪が押し寄せる前", "behaviorConduct01008001": "黄砂予報時", "behaviorConduct01008002": "黄砂発生時", "behaviorConduct01008003": "黄砂が過ぎ去った後", "behaviorConduct01009001": "猛暑が来る前", "behaviorConduct01009002": "猛暑注意報時", "behaviorConduct01010001": "干ばつが来る前", "behaviorConduct01011009": "地震が来る前", "behaviorConduct01011010": "地震発生時", "behaviorConduct01011012": "地震避難後", "behaviorConduct01013002": "津波が来る前", "behaviorConduct01013003": "津波発生時", "behaviorConduct01014001": "地滑り注意報時", "behaviorConduct03002002": "やけどの処置", "behaviorConduct03002003": "高熱の予防", "behaviorConduct03002004": "ヘビにかまれたときの処置", "behaviorConduct03002005": "ハチにさされたときの処置", "behaviorConduct03002006": "過呼吸症候群の応急処置", "behaviorConduct03003001": "成人の心肺蘇生法", "behaviorConduct03003002": "乳幼児の心肺蘇生法", "behaviorConduct03003003": "自動体外式除細動器(AED)を使用", "behaviorConduct03004001": "粉末消火器を使用", "behaviorConduct03016001": "屋内消火栓の使用", "behaviorConduct03005001": "食中毒の対処", "behaviorConduct03006004": "登山中の注意事項", "behaviorConduct03006005": "山での安全なキャンピング", "behaviorConduct03006002": "救助要請の際に知らせること", "behaviorConduct03006003": "登山事故時の緊急措置", "behaviorConduct03008001": "失踪・誘拐の予防", "behaviorConduct03009001": "性暴力の防止", "behaviorConduct03010001": "学校暴力の予防", "behaviorConduct03011001": "家庭内暴力の予防", "behaviorConduct03012001": "抑留と拉致時の措置", "behaviorConduct03013002": "交通事故発生時の措置", "behaviorConduct03013005": "自動車での救助", "behaviorConduct03014001": "エレベーターの安全利用", "behaviorConduct03014003": "エレベーターの故障時の措置", "behaviorConduct03014004": "エスカレーターの安全利用", "behaviorConduct03015007": "浮遊粒子状物質の多い日の生活", "behaviorConduct03015003": "カテゴリー別の生活", "tts_female": "女性の", "tts_male": "男性の", "tts_kind": "やさしい", "tts_sweet": "あまい", "tts_echo": "響く", "tts_mischievous": "いたずらっぽい", "tts_dainty": "かわいらしい", "tts_veryslow": "とてもゆっくりに", "tts_slow": "ゆっくりに", "tts_normal": "普通", "tts_fast": "速く", "tts_veryfast": "とても速く", "tts_verylow": "とても低く", "tts_low": "低く", "tts_high": "高く", "tts_veryhigh": "とても高く", "ARDUINO": "Hardware", "ARDUINO_download_connector": "• 接続ソフトをダウンロード", "ARDUINO_open_connector": "接続ソフトを開く", "ARDUINO_download_source": "• ENTRYのArduinoコード", "ARDUINO_reconnect": "ハードウェアに接続する", "arduino_noti_text": "モバイル機器でのハードウェア\n 接続は今後対応予定です。", "ROBOT_reconnect": "ロボットを連結する", "ARDUINO_program": "Run the program", "ARDUINO_cloud_pc_connector": "Connect to Cloud PC", "ARDUINO_connected": "Hardware connected", "ARDUINO_connect": "* Connect hardware", "ARDUINO_arduino_get_number_1": "number result of signal", "ARDUINO_arduino_get_number_2": "", "ARDUINO_arduino_get_sensor_number_0": "0", "ARDUINO_arduino_get_sensor_number_1": "1", "ARDUINO_arduino_get_sensor_number_2": "2", "ARDUINO_arduino_get_sensor_number_3": "3", "ARDUINO_arduino_get_sensor_number_4": "4", "ARDUINO_arduino_get_sensor_number_5": "5", "arduino_lite_connected_noti": "ハードウェアを選択した状態で\n作品を保存してください。", "blacksmith_toggle_on": "on", "blacksmith_toggle_off": "off", "blacksmith_lcd_first_line": "first", "blacksmith_lcd_seconds_line": "seconds", "BITBRICK_light": "light", "BITBRICK_IR": "IR", "BITBRICK_touch": "touch", "BITBRICK_potentiometer": "potentiometer", "BITBRICK_MIC": "MIC", "BITBRICK_UserSensor": "UserSensor", "BITBRICK_UserInput": "UserInput", "BITBRICK_dc_direction_ccw": "CCW", "BITBRICK_dc_direction_cw": "CW", "chocopi_control_event_pressed": "pressed", "chocopi_control_event_released": "released", "chocopi_joystick_X": "joystick X", "chocopi_joystick_Y": "joystick Y", "chocopi_motion_photogate_event_blocked": "blocked", "chocopi_motion_photogate_event_unblocked": "unblocked", "chocopi_motion_photogate_time_blocked": "blocked", "chocopi_motion_photogate_time_unblocked": "unblocked", "chocopi_port": "P", "chocopi_pot": "potentiometer", "chocopi_touch_event_touch": "touched", "chocopi_touch_event_untouch": "untouched", "CODEino_get_sensor_number_0": "0", "CODEino_get_sensor_number_1": "1", "CODEino_get_sensor_number_2": "2", "CODEino_get_sensor_number_3": "3", "CODEino_get_sensor_number_4": "4", "CODEino_get_sensor_number_5": "5", "CODEino_get_sensor_number_6": "6", "CODEino_sensor_name_0": "Sound", "CODEino_sensor_name_1": "Light", "CODEino_sensor_name_2": "Slider", "CODEino_sensor_name_3": "resistance-A", "CODEino_sensor_name_4": "resistance-B", "CODEino_sensor_name_5": "resistance-C", "CODEino_sensor_name_6": "resistance-D", "CODEino_string_1": " Sensor value ", "CODEino_string_2": " Operation ", "CODEino_string_3": "Push button", "CODEino_string_4": "Connected A", "CODEino_string_5": "Connected B", "CODEino_string_6": "Connected C", "CODEino_string_7": "Connected D", "CODEino_string_8": " 3-AXIS Accelerometer ", "CODEino_string_9": "-axis value ", "CODEino_string_10": "Sound is ", "CODEino_string_11": "Great", "CODEino_string_12": "Small", "CODEino_string_13": "Light is ", "CODEino_string_14": "Bright", "CODEino_string_15": "Dark", "CODEino_string_16": "Left tilt", "CODEino_string_17": "Right tilt", "CODEino_string_18": "Front tilt", "CODEino_string_19": "Rear tilt", "CODEino_string_20": "Reverse", "CODEino_accelerometer_X": "X", "CODEino_accelerometer_Y": "Y", "CODEino_accelerometer_Z": "Z", "CODEino_led_red": "Red", "CODEino_led_green": "Green", "CODEino_led_blue": "Blue", "iboard_analog_number_0": "A0", "iboard_analog_number_1": "A1", "iboard_analog_number_2": "A2", "iboard_analog_number_3": "A3", "iboard_analog_number_4": "A4", "iboard_analog_number_5": "A5", "iboard_light": "Light sensor is ", "iboard_num_pin_1": "LED status", "iboard_num_pin_2": "switch", "iboard_num_pin_3": "analogue", "iboard_num_pin_4": " ", "iboard_num_pin_5": "sensor value", "iboard_string_1": "on", "iboard_string_2": "off", "iboard_string_3": "bright", "iboard_string_4": "dark", "iboard_string_5": "pressed", "iboard_string_6": "opened", "iboard_switch": "switch ", "iboard_tilt": "Slope sensor status is", "dplay_switch": "스위치 ", "dplay_light": "Light sensor is ", "dplay_tilt": "Slope sensor status is", "dplay_string_1": "켜짐", "dplay_string_2": "꺼짐", "dplay_string_3": "bright", "dplay_string_4": "dark", "dplay_string_5": "pressed", "dplay_string_6": "opened", "dplay_num_pin_1": "LED status", "dplay_num_pin_2": "switch", "dplay_num_pin_3": "analogue", "dplay_num_pin_4": "번 ", "dplay_num_pin_5": "sensor value", "dplay_analog_number_0": "A0", "dplay_analog_number_1": "A1", "dplay_analog_number_2": "A2", "dplay_analog_number_3": "A3", "dplay_analog_number_4": "A4", "dplay_analog_number_5": "A5", "ARDUINO_arduino_get_string_1": "string result of signal", "ARDUINO_arduino_get_string_2": "", "ARDUINO_arduino_send_1": "Send signal", "ARDUINO_arduino_send_2": "", "ARDUINO_num_sensor_value_1": "Analog", "ARDUINO_num_sensor_value_2": "Sensor value", "ARDUINO_get_digital_value_1": "Digital", "ARDUINO_num_pin_1": "Digital", "ARDUINO_num_pin_2": "Pin", "ARDUINO_toggle_pwm_1": "Digital", "ARDUINO_toggle_pwm_2": "Pin", "ARDUINO_toggle_pwm_3": "", "ARDUINO_on": "On", "ARDUINO_convert_scale_1": "Map Value", "ARDUINO_convert_scale_2": "", "ARDUINO_convert_scale_3": "~", "ARDUINO_convert_scale_4": "to", "ARDUINO_convert_scale_5": "~", "ARDUINO_convert_scale_6": "", "ARDUINO_off": "Off", "EXPANSION": "拡張", "brightness": "明度", "BRUSH": "筆", "BRUSH_brush_erase_all": "すべての筆のあとを消す", "BRUSH_change_opacity_1": "筆の不透明度を", "BRUSH_change_opacity_2": "%に変更", "BRUSH_change_thickness_1": "筆の太さを", "BRUSH_change_thickness_2": "変更する", "BRUSH_set_color_1": "筆の色を", "BRUSH_set_color_2": "にする", "BRUSH_set_opacity_1": "筆の不透明度を", "BRUSH_set_opacity_2": "%にする", "BRUSH_set_random_color": "筆の色をランダムにする", "BRUSH_set_thickness_1": "筆の太さを", "BRUSH_set_thickness_2": "にする", "BRUSH_stamp": "スタンプを押す", "BRUSH_start_drawing": "描画スタート", "BRUSH_stop_drawing": "描画をやめる", "CALC": "計算", "CALC_calc_mod_1": " ", "CALC_calc_mod_2": "/", "CALC_calc_mod_3": "あまり", "CALC_calc_operation_of_1": " ", "CALC_calc_operation_of_2": "の", "CALC_calc_operation_root": "ルート", "CALC_calc_operation_square": "乗", "CALC_calc_rand_1": " ", "CALC_calc_rand_2": "から", "CALC_calc_rand_3": "間の乱数", "CALC_calc_share_1": " ", "CALC_calc_share_2": "/", "CALC_calc_share_3": "の商", "CALC_coordinate_mouse_1": "マウスの", "CALC_coordinate_mouse_2": "座標", "CALC_coordinate_object_1": " ", "CALC_coordinate_object_2": "の", "CALC_coordinate_object_3": " ", "CALC_distance_something_1": " ", "CALC_distance_something_2": "までの距離", "CALC_get_angle": "角度値", "CALC_get_date_1": " 現在の", "CALC_get_date_2": " ", "CALC_get_date_day": "日", "CALC_get_date_hour": "時刻(時)", "CALC_get_date_minute": "時刻(分)", "CALC_get_date_month": "月", "CALC_get_date_second": "時刻(秒)", "CALC_get_date_year": "年度", "CALC_get_sound_duration_1": " ", "CALC_get_sound_duration_2": "音の長さ", "CALC_get_timer_value": " ストップウォッチの値", "CALC_get_x_coordinate": "X座標値", "CALC_get_y_coordinate": "Y座標値", "CALC_timer_reset": "ストップウォッチ初期化", "CALC_timer_visible_1": "ストップウォッチを", "CALC_timer_visible_2": " ", "CALC_timer_visible_show": "見せる", "CALC_timer_visible_hide": "隠す", "color": "色", "FLOW": "フロー ", "FLOW__if_1": "もし", "FLOW__if_2": "なら", "FLOW_create_clone_1": " ", "FLOW_create_clone_2": "のコピーを作る", "FLOW_delete_clone": "このコピーを削除する", "FLOW_delete_clone_all": "すべてのコピーを削除する", "FLOW_if_else_1": "もし", "FLOW_if_else_2": "なら", "FLOW_if_else_3": "そうでなければ", "FLOW_repeat_basic_1": " ", "FLOW_repeat_basic_2": "回繰り返す", "FLOW_repeat_basic_errorMsg": "反復回数は0と同じまたは大きい必要があります。", "FLOW_repeat_inf": "ずっと繰り返す", "FLOW_restart": "最初から再実行する", "FLOW_stop_object_1": " ", "FLOW_stop_object_2": "やめる", "FLOW_stop_object_all": "すべての", "FLOW_stop_object_this_object": "自分の", "FLOW_stop_object_this_thread": "この", "FLOW_stop_object_other_thread": "自分の他の", "FLOW_stop_object_other_objects": "他のオブジェクトの", "FLOW_stop_repeat": "繰り返しをやめる", "FLOW_stop_run": "プログラムを終了する", "FLOW_wait_second_1": " ", "FLOW_wait_second_2": "秒待つ", "FLOW_wait_until_true_1": " ", "FLOW_wait_until_true_2": "になるまで待つ", "FLOW_when_clone_start": "コピーが最初に作成された時", "FUNC": "関数", "ANALYSIS": "データ分析", "AI": "人工知能", "JUDGEMENT": "判断", "JUDGEMENT_boolean_and": "そして", "JUDGEMENT_boolean_not_1": " ", "JUDGEMENT_boolean_not_2": "ではない", "JUDGEMENT_boolean_or": "または", "JUDGEMENT_false": " false", "JUDGEMENT_is_clicked": "マウスをクリックしたか?", "JUDGEMENT_is_press_some_key_1": " ", "JUDGEMENT_is_press_some_key_2": "キーを押しているか?", "JUDGEMENT_reach_something_1": " ", "JUDGEMENT_reach_something_2": "に着いたか?", "JUDGEMENT_true": " true", "JUDGEMENT_is_boost_mode": "ブーストモードがオンになっているか?", "LOOKS": "見た目", "LOOKS_change_scale_percent_1": "サイズを", "LOOKS_change_scale_percent_2": "分変更する", "LOOKS_change_to_next_shape": "次の模様に変更する", "LOOKS_change_to_nth_shape_1": " ", "LOOKS_change_to_nth_shape_2": "模様に変更する", "LOOKS_change_shape_prev": "前の", "LOOKS_change_shape_next": "次の", "LOOKS_change_to_near_shape_1": " ", "LOOKS_change_to_near_shape_2": "模様に変更する", "LOOKS_dialog_1": " ", "LOOKS_dialog_2": "を", "LOOKS_dialog_3": " ", "LOOKS_dialog_time_1": " ", "LOOKS_dialog_time_2": "を", "LOOKS_dialog_time_3": "秒間", "LOOKS_dialog_time_4": " ", "LOOKS_erase_all_effects": "効果をすべて削除する", "LOOKS_flip_x": "上下の模様を入れ替える", "LOOKS_flip_y": "左右の模様を入れ替える", "LOOKS_hide": "模様非表示", "LOOKS_remove_dialog": "会話を削除する", "LOOKS_set_effect_1": " ", "LOOKS_set_effect_2": "効果を", "LOOKS_set_effect_3": "にする", "LOOKS_set_effect_volume_1": " ", "LOOKS_set_effect_volume_2": "効果を", "LOOKS_set_effect_volume_3": "加える", "LOOKS_set_object_order_1": " ", "LOOKS_set_object_order_2": "番目に上げる", "LOOKS_set_scale_percent_1": "サイズを", "LOOKS_set_scale_percent_2": " にする", "LOOKS_show": "模様表示", "mouse_pointer": "マウスポインター", "MOVING": "動き", "MOVING_bounce_wall": "壁に着いたら、跳ね返る", "MOVING_bounce_when_1": " ", "MOVING_bounce_when_2": "に到達した場合弾く", "MOVING_flip_arrow_horizontal": "矢印の方向を左右入れ替える", "MOVING_flip_arrow_vertical": "矢印の方向を上下入れ替える", "MOVING_locate_1": " ", "MOVING_locate_2": "位置に移動する", "MOVING_locate_time_1": " ", "MOVING_locate_time_2": "秒間", "MOVING_locate_time_3": "位置に移動する", "MOVING_locate_x_1": "x:", "MOVING_locate_x_2": "位置に移動する", "MOVING_locate_xy_1": "x:", "MOVING_locate_xy_2": "y:", "MOVING_locate_xy_3": "位置に移動する", "MOVING_locate_xy_time_1": " ", "MOVING_locate_xy_time_2": "秒間x:", "MOVING_locate_xy_time_3": "y:", "MOVING_locate_xy_time_4": "位置に移動する", "MOVING_locate_y_1": "y:", "MOVING_locate_y_2": "位置に移動する", "MOVING_move_direction_1": "移動方向に", "MOVING_move_direction_2": "動かす", "MOVING_move_direction_angle_1": " ", "MOVING_move_direction_angle_2": "方向に", "MOVING_move_direction_angle_3": "動かす", "MOVING_move_x_1": "x 座標を", "MOVING_move_x_2": "分変更する", "MOVING_move_xy_time_1": " ", "MOVING_move_xy_time_2": "秒間x:", "MOVING_move_xy_time_3": "y:", "MOVING_move_xy_time_4": "分動かす", "MOVING_move_y_1": "y座標を", "MOVING_move_y_2": "分変更する", "MOVING_rotate_by_angle_1": "オブジェクトを", "MOVING_rotate_by_angle_2": "回転する", "MOVING_rotate_by_angle_dropdown_1": " ", "MOVING_rotate_by_angle_dropdown_2": "回転する", "MOVING_rotate_by_angle_time_1": "オブジェクトを", "MOVING_rotate_by_angle_time_2": "秒間", "MOVING_rotate_by_angle_time_3": "分回転する", "MOVING_rotate_direction_1": "移動方向を", "MOVING_rotate_direction_2": "分回転する", "MOVING_see_angle_1": "移動方向を", "MOVING_see_angle_2": "にする", "MOVING_see_angle_direction_1": "オブジェクトを", "MOVING_see_angle_direction_2": "にする", "MOVING_see_angle_object_1": " ", "MOVING_see_angle_object_2": "側を向く", "MOVING_see_direction_1": " ", "MOVING_see_direction_2": "側にターンする", "MOVING_set_direction_by_angle_1": "方向を", "MOVING_set_direction_by_angle_2": "にする", "MOVING_add_direction_by_angle_1": "方向を", "MOVING_add_direction_by_angle_2": "回転する", "MOVING_add_direction_by_angle_time_1": "方向を", "MOVING_add_direction_by_angle_time_2": "秒間", "MOVING_add_direction_by_angle_time_3": "回転する", "no_target": "対象なし", "oneself": "自分", "opacity": "不透明度", "SCENE": "シーン", "SOUND": "音", "SOUND_sound_silent_all": "すべてのサウンドを中断する", "SOUND_sound_something_1": "サウンド", "SOUND_sound_something_2": "再生する", "SOUND_sound_something_second_1": "サウンド", "SOUND_sound_something_second_2": " ", "SOUND_sound_something_second_3": "秒再生する", "SOUND_sound_something_second_wait_1": "サウンド", "SOUND_sound_something_second_wait_2": " ", "SOUND_sound_something_second_wait_3": "秒再生して待つ", "SOUND_sound_something_wait_1": "サウンド", "SOUND_sound_something_wait_2": "再生して待つ", "SOUND_sound_volume_change_1": "音の大きさを", "SOUND_sound_volume_change_2": "%に変更", "SOUND_sound_volume_set_1": "音の大きさを", "SOUND_sound_volume_set_2": "%にする", "speak": "言う", "think": "思う", "START": "はじめ", "START_add_message": "信号を追加する", "START_delete_message": "信号を削除する", "START_message_cast": "信号を送る", "START_message_cast_1": " ", "START_message_cast_2": "信号を送る", "START_message_cast_wait": "信号を送って待機", "START_message_send_wait_1": " ", "START_message_send_wait_2": "信号を送って待機", "START_mouse_click_cancled": "マウスをクリックして離した時", "START_mouse_clicked": "マウスをクリックした時", "START_press_some_key_1": " ", "START_press_some_key_2": "キーを押した時", "START_press_some_key_down": "下矢印", "START_press_some_key_enter": "エンター", "START_press_some_key_left": "左矢印", "START_press_some_key_right": "右矢印", "START_press_some_key_space": "スペース", "START_press_some_key_up": "上矢印", "START_when_message_cast": "信号を受け取った時", "START_when_message_cast_1": " ", "START_when_message_cast_2": "信号を受け取った時", "START_when_object_click": "オブジェクトをクリックした時", "START_when_object_click_canceled": "オブジェクトをクリックして離した時", "START_when_run_button_click": "スタートボタンをクリックした時", "START_when_scene_start": "シーンが始まった時", "START_when_some_key_click": "キーを押した時", "TEXT": "テキストボックス", "TEXT_text": "エントリー", "TEXT_text_append_1": " ", "TEXT_text_append_2": "と後ろに続けて書く", "TEXT_text_flush": "テキストをすべて削除する", "TEXT_text_prepend_1": " ", "TEXT_text_prepend_2": "と前に追加する", "TEXT_text_write_1": " ", "TEXT_text_write_2": "と書く", "VARIABLE": "データ", "VARIABLE_add_value_to_list": "項目をリストに追加する", "VARIABLE_add_value_to_list_1": " ", "VARIABLE_add_value_to_list_2": "項目を", "VARIABLE_add_value_to_list_3": "に追加する", "VARIABLE_ask_and_wait_1": " ", "VARIABLE_ask_and_wait_2": "を尋ねて回答を待機", "VARIABLE_change_value_list_index": "項目を変更する", "VARIABLE_change_value_list_index_1": " ", "VARIABLE_change_value_list_index_3": "番目の項目を", "VARIABLE_change_value_list_index_2": " ", "VARIABLE_change_value_list_index_4": "に変更する", "VARIABLE_change_variable": "変数を加える", "VARIABLE_change_variable_1": " ", "VARIABLE_change_variable_2": "に", "VARIABLE_change_variable_3": "加える", "VARIABLE_change_variable_name": "変数名を変更する", "VARIABLE_combine_something_1": " ", "VARIABLE_combine_something_2": "と", "VARIABLE_combine_something_3": "をつなげる", "VARIABLE_get_canvas_input_value": "答え", "VARIABLE_get_variable": "変数", "VARIABLE_get_variable_1": "の値", "VARIABLE_get_variable_2": "値", "VARIABLE_get_y": "Y座標値", "VARIABLE_hide_list": "リスト非表示", "VARIABLE_hide_list_1": "リスト", "VARIABLE_hide_list_2": "非表示", "VARIABLE_hide_variable": "変数値非表示", "VARIABLE_hide_variable_1": "変数", "VARIABLE_hide_variable_2": "非表示", "VARIABLE_insert_value_to_list": "項目を挿入する", "VARIABLE_insert_value_to_list_1": " ", "VARIABLE_insert_value_to_list_2": "を", "VARIABLE_insert_value_to_list_3": "の", "VARIABLE_insert_value_to_list_4": "番目に入れる", "VARIABLE_length_of_list": "リストの長さ", "VARIABLE_length_of_list_1": " ", "VARIABLE_length_of_list_2": " の項目数", "VARIABLE_list": "リスト", "VARIABLE_make_variable": "変数を作成する", "VARIABLE_list_option_first": "最初", "VARIABLE_list_option_last": "最後", "VARIABLE_list_option_random": "ランダム", "VARIABLE_remove_value_from_list": "項目を削除する", "VARIABLE_remove_value_from_list_1": " ", "VARIABLE_remove_value_from_list_2": "番目の項目を", "VARIABLE_remove_value_from_list_3": "から削除する", "VARIABLE_remove_variable": "変数削除", "VARIABLE_set_variable": "変数を定める", "VARIABLE_set_variable_1": " ", "VARIABLE_set_variable_2": "を", "VARIABLE_set_variable_3": "にする", "VARIABLE_show_list": "リスト表示", "VARIABLE_show_list_1": "リスト", "VARIABLE_show_list_2": "表示", "VARIABLE_show_variable": "変数値表示", "VARIABLE_show_variable_1": "変数", "VARIABLE_show_variable_2": "表示", "VARIABLE_value_of_index_from_list": "リスト項目の値", "VARIABLE_value_of_index_from_list_1": " ", "VARIABLE_value_of_index_from_list_2": "の", "VARIABLE_value_of_index_from_list_3": "番目の項目", "HAMSTER_hand_found": "hand found?", "HAMSTER_sensor_left_proximity": "left proximity", "HAMSTER_sensor_right_proximity": "right proximity", "HAMSTER_sensor_left_floor": "left floor", "HAMSTER_sensor_right_floor": "right floor", "HAMSTER_sensor_acceleration_x": "x acceleration", "HAMSTER_sensor_acceleration_y": "y acceleration", "HAMSTER_sensor_acceleration_z": "z acceleration", "HAMSTER_sensor_light": "light", "HAMSTER_sensor_temperature": "temperature", "HAMSTER_sensor_signal_strength": "signal strength", "HAMSTER_sensor_input_a": "input A", "HAMSTER_sensor_input_b": "input B", "HAMSTER_move_forward_once": "move forward once on board", "HAMSTER_turn_once_1": "turn", "HAMSTER_turn_once_2": "once on board", "HAMSTER_turn_once_left": "left", "HAMSTER_turn_right": "right", "HAMSTER_move_forward": "move forward", "HAMSTER_move_backward": "move backward", "HAMSTER_turn_around_1": "turn", "HAMSTER_turn_around_2": "", "HAMSTER_move_forward_for_secs_1": "move forward for", "HAMSTER_move_forward_for_secs_2": "secs", "HAMSTER_move_backward_for_secs_1": "move backward", "HAMSTER_move_backward_for_secs_2": "secs", "HAMSTER_turn_for_secs_1": "turn", "HAMSTER_turn_for_secs_2": "for", "HAMSTER_turn_for_secs_3": "secs", "HAMSTER_change_both_wheels_by_1": "change wheel by left:", "HAMSTER_change_both_wheels_by_2": "right:", "HAMSTER_change_both_wheels_by_3": "", "HAMSTER_set_both_wheels_to_1": "set wheel to left:", "HAMSTER_set_both_wheels_to_2": "right:", "HAMSTER_set_both_wheels_to_3": "", "HAMSTER_change_wheel_by_1": "change", "HAMSTER_change_wheel_by_2": "wheel by", "HAMSTER_change_wheel_by_3": "", "HAMSTER_left_wheel": "left", "HAMSTER_right_wheel": "right", "HAMSTER_both_wheels": "both", "HAMSTER_set_wheel_to_1": "set", "HAMSTER_set_wheel_to_2": "wheel to", "HAMSTER_set_wheel_to_3": "", "HAMSTER_follow_line_using_1": "follow", "HAMSTER_follow_line_using_2": "line using", "HAMSTER_follow_line_using_3": "floor sensor", "HAMSTER_left_floor_sensor": "left", "HAMSTER_right_floor_sensor": "right", "HAMSTER_both_floor_sensors": "both", "HAMSTER_follow_line_until_1": "follow", "HAMSTER_follow_line_until_2": "line until", "HAMSTER_follow_line_until_3": "intersection", "HAMSTER_left_intersection": "left", "HAMSTER_right_intersection": "right", "HAMSTER_front_intersection": "front", "HAMSTER_rear_intersection": "rear", "HAMSTER_set_following_speed_to_1": "set following speed to", "HAMSTER_set_following_speed_to_2": "", "HAMSTER_front": "front", "HAMSTER_rear": "rear", "HAMSTER_stop": "stop", "HAMSTER_set_led_to_1": "set", "HAMSTER_set_led_to_2": "led to", "HAMSTER_set_led_to_3": "", "HAMSTER_left_led": "left", "HAMSTER_right_led": "right", "HAMSTER_both_leds": "both", "HAMSTER_clear_led_1": "clear", "HAMSTER_clear_led_2": "led", "HAMSTER_color_cyan": "sky blue", "HAMSTER_color_magenta": "purple", "HAMSTER_color_black": "black", "HAMSTER_color_white": "white", "HAMSTER_color_red": "red", "HAMSTER_color_yellow": "yellow", "HAMSTER_color_green": "green", "HAMSTER_color_blue": "blue", "HAMSTER_beep": "beep", "HAMSTER_change_buzzer_by_1": "change buzzer by", "HAMSTER_change_buzzer_by_2": "", "HAMSTER_set_buzzer_to_1": "set buzzer to", "HAMSTER_set_buzzer_to_2": "", "HAMSTER_clear_buzzer": "clear buzzer", "HAMSTER_play_note_for_1": "play note", "HAMSTER_play_note_for_2": "", "HAMSTER_play_note_for_3": "for", "HAMSTER_play_note_for_4": "beats", "HAMSTER_rest_for_1": "rest for", "HAMSTER_rest_for_2": "beats", "HAMSTER_change_tempo_by_1": "change tempo by", "HAMSTER_change_tempo_by_2": "", "HAMSTER_set_tempo_to_1": "set tempo to", "HAMSTER_set_tempo_to_2": "bpm", "HAMSTER_set_port_to_1": "set port", "HAMSTER_set_port_to_2": "to", "HAMSTER_set_port_to_3": "", "HAMSTER_change_output_by_1": "change output", "HAMSTER_change_output_by_2": "by", "HAMSTER_change_output_by_3": "", "HAMSTER_set_output_to_1": "set output", "HAMSTER_set_output_to_2": "to", "HAMSTER_set_output_to_3": "", "HAMSTER_port_a": "A", "HAMSTER_port_b": "B", "HAMSTER_port_ab": "A and B", "HAMSTER_analog_input": "analog input", "HAMSTER_digital_input": "digital input", "HAMSTER_servo_output": "servo output", "HAMSTER_pwm_output": "pwm output", "HAMSTER_digital_output": "digital output", "ROBOID_acceleration_x": "x軸加速度", "ROBOID_acceleration_y": "y軸加速度", "ROBOID_acceleration_z": "z軸加速度", "ROBOID_back": "後ろ", "ROBOID_both": "両側", "ROBOID_button": "ボタン", "ROBOID_buzzer": "ブザー", "ROBOID_clicked": "クリックしたか", "ROBOID_color_any": "何の色", "ROBOID_color_black": "黒", "ROBOID_color_blue": "青", "ROBOID_color_green": "緑", "ROBOID_color_number": "色番号", "ROBOID_color_orange": "オレンジ", "ROBOID_color_pattern": "色パターン", "ROBOID_color_purple": "赤紫色", "ROBOID_color_red": "赤", "ROBOID_color_sky_blue": "水色", "ROBOID_color_violet": "紫", "ROBOID_color_white": "白", "ROBOID_color_yellow": "黄色", "ROBOID_double_clicked": "ダブルクリックしたか", "ROBOID_floor": "床センサー", "ROBOID_head": "髪", "ROBOID_head_color": "髪色", "ROBOID_left": "左側", "ROBOID_left_wheel": "左車輪", "ROBOID_long_pressed": "長く~押したか", "ROBOID_note": "音符", "ROBOID_right": "右側", "ROBOID_right_wheel": "右車輪", "ROBOID_sound_beep": "ピー音", "ROBOID_sound_birthday": "誕生日", "ROBOID_sound_dibidibidip": "ディビディビディープ", "ROBOID_sound_engine": "エンジン", "ROBOID_sound_good_job": "すごいです", "ROBOID_sound_march": "行進", "ROBOID_sound_random_beep": "ランダムのピー音", "ROBOID_sound_robot": "ロボット", "ROBOID_sound_siren": "サイレン", "ROBOID_tail": "尾", "ROBOID_unit_cm": "cm", "ROBOID_unit_deg": "度", "ROBOID_unit_pulse": "パルス", "ROBOID_unit_sec": "秒", "ALBERT_hand_found": "hand found?", "ALBERT_is_oid_1": "oid is", "ALBERT_is_oid_2": "", "ALBERT_is_oid_3": "?", "ALBERT_front_oid": "front", "ALBERT_back_oid": "back", "ALBERT_sensor_left_proximity": "left proximity", "ALBERT_sensor_right_proximity": "right proximity", "ALBERT_sensor_acceleration_x": "x acceleration", "ALBERT_sensor_acceleration_y": "y acceleration", "ALBERT_sensor_acceleration_z": "z acceleration", "ALBERT_sensor_light": "light", "ALBERT_sensor_temperature": "temperature", "ALBERT_sensor_battery": "battery", "ALBERT_sensor_signal_strength": "signal strength", "ALBERT_sensor_front_oid": "front oid", "ALBERT_sensor_back_oid": "back oid", "ALBERT_sensor_position_x": "x position", "ALBERT_sensor_position_y": "y position", "ALBERT_sensor_orientation": "orientation", "ALBERT_move_forward": "move forward", "ALBERT_move_backward": "move backward", "ALBERT_turn_around_1": "turn", "ALBERT_turn_around_2": "", "ALBERT_move_forward_for_secs_1": "move forward for", "ALBERT_move_forward_for_secs_2": "secs", "ALBERT_move_backward_for_secs_1": "move backward for", "ALBERT_move_backward_for_secs_2": "secs", "ALBERT_turn_for_secs_1": "turn", "ALBERT_turn_for_secs_2": "for", "ALBERT_turn_for_secs_3": "secs", "ALBERT_turn_left": "left", "ALBERT_turn_right": "right", "ALBERT_change_both_wheels_by_1": "change wheels by left:", "ALBERT_change_both_wheels_by_2": "right:", "ALBERT_change_both_wheels_by_3": "", "ALBERT_left_wheel": "left", "ALBERT_right_wheel": "right", "ALBERT_both_wheels": "both", "ALBERT_set_both_wheels_to_1": "set wheels to left:", "ALBERT_set_both_wheels_to_2": "right:", "ALBERT_set_both_wheels_to_3": "", "ALBERT_change_wheel_by_1": "change", "ALBERT_change_wheel_by_2": "wheel by", "ALBERT_change_wheel_by_3": "", "ALBERT_set_wheel_to_1": "set", "ALBERT_set_wheel_to_2": "wheel to", "ALBERT_set_wheel_to_3": "", "ALBERT_stop": "stop", "ALBERT_set_board_size_to_1": "set board size to width:", "ALBERT_set_board_size_to_2": "height:", "ALBERT_set_board_size_to_3": "", "ALBERT_move_to_x_y_1": "move to x:", "ALBERT_move_to_x_y_2": "y:", "ALBERT_move_to_x_y_3": "on board", "ALBERT_set_orientation_to_1": "set orientation to", "ALBERT_set_orientation_to_2": "degrees on board", "ALBERT_set_eye_to_1": "set", "ALBERT_set_eye_to_2": "eye to", "ALBERT_set_eye_to_3": "", "ALBERT_left_eye": "left", "ALBERT_right_eye": "right", "ALBERT_both_eyes": "both", "ALBERT_clear_eye_1": "clear", "ALBERT_clear_eye_2": "eye", "ALBERT_body_led_1": "turn", "ALBERT_body_led_2": "body led", "ALBERT_front_led_1": "turn", "ALBERT_front_led_2": "front led", "ALBERT_color_cyan": "cyan", "ALBERT_color_magenta": "magenta", "ALBERT_color_white": "white", "ALBERT_color_red": "red", "ALBERT_color_yellow": "yellow", "ALBERT_color_green": "green", "ALBERT_color_blue": "blue", "ALBERT_note_c": "C", "ALBERT_note_d": "D", "ALBERT_note_e": "E", "ALBERT_note_f": "F", "ALBERT_note_g": "G", "ALBERT_note_a": "A", "ALBERT_note_b": "B", "ALBERT_turn_body_led_1": "turn", "ALBERT_turn_body_led_2": "body led", "ALBERT_turn_front_led_1": "turn", "ALBERT_turn_front_led_2": "front led", "ALBERT_turn_on": "on", "ALBERT_turn_off": "off", "ALBERT_beep": "beep", "ALBERT_change_buzzer_by_1": "change buzzer by", "ALBERT_change_buzzer_by_2": "", "ALBERT_set_buzzer_to_1": "set buzzer to", "ALBERT_set_buzzer_to_2": "", "ALBERT_clear_buzzer": "clear buzzer", "ALBERT_play_note_for_1": "play note", "ALBERT_play_note_for_2": "',", "ALBERT_play_note_for_3": "for", "ALBERT_play_note_for_4": "beats", "ALBERT_rest_for_1": "rest for", "ALBERT_rest_for_2": "beats", "ALBERT_change_tempo_by_1": "change tempo by", "ALBERT_change_tempo_by_2": "", "ALBERT_set_tempo_to_1": "set tempo to", "ALBERT_set_tempo_to_2": "bpm", "VARIABLE_variable": "変数", "wall": "壁", "robotis_common_case_01": "を", "robotis_common_set": "にする", "robotis_common_value": "値", "robotis_common_clockwhise": "時計方向", "robotis_common_counter_clockwhise": "反時計方向", "robotis_common_wheel_mode": "回転モード", "robotis_common_joint_mode": "関節モード", "robotis_common_red_color": "赤", "robotis_common_green_color": "緑", "robotis_common_blue_color": "青", "robotis_common_on": "ON", "robotis_common_off": "OFF", "robotis_common_cm": "コントローラー", "robotis_common_port_1": "ポート1", "robotis_common_port_2": "ポート2", "robotis_common_port_3": "ポート3", "robotis_common_port_4": "ポート4", "robotis_common_port_5": "ポート5", "robotis_common_port_6": "ポート6", "robotis_common_play_buzzer": "演奏", "robotis_common_play_motion": "実行", "robotis_common_motion": "モーション", "robotis_common_index_number": "回", "robotis_common_left": "左", "robotis_common_right": "右", "robotis_common_minute": "分", "robotis_cm_custom": "直接入力アドレス", "robotis_cm_spring_left": "左側接触センサー", "robotis_cm_spring_right": "右側接触センサー", "robotis_cm_led_left": "左側LED", "robotis_cm_led_right": "右側LED", "robotis_cm_led_both": "両側LED", "robotis_cm_switch": "選択ボタンの状態", "robotis_cm_user_button": "ユーザーボタンの状態", "robotis_cm_sound_detected": "最終サウンド検知回数", "robotis_cm_sound_detecting": "リアルタイムサウンド検知回数", "robotis_cm_ir_left": "左側赤外線センサー", "robotis_cm_ir_right": "右側赤外線センサー", "robotis_cm_calibration_left": "左側赤外線センサー較正値", "robotis_cm_calibration_right": "右側赤外線センサー較正値", "robotis_cm_clear_sound_detected": "最終サウンド検知回数初期化", "robotis_cm_buzzer_index": "音階値", "robotis_cm_buzzer_melody": "メロディ", "robotis_cm_led_1": "1番LED", "robotis_cm_led_4": "4番LED", "robotis_aux_servo_position": "サーボモーター位置", "robotis_aux_ir": "赤外線センサー", "robotis_aux_touch": "接触センサー", "robotis_aux_brightness": "照度センサー(CDS)", "robotis_aux_hydro_themo_humidity": "温湿度センサー(湿度)", "robotis_aux_hydro_themo_temper": "温湿度センサー(温度)", "robotis_aux_temperature": "温度センサー", "robotis_aux_ultrasonic": "超音波センサー", "robotis_aux_magnetic": "磁石センサー", "robotis_aux_motion_detection": "動作検知センサー", "robotis_aux_color": "カラーセンサー", "robotis_aux_custom": "ユーザー装置", "robotis_carCont_aux_motor_speed_1": "Speed of decelerating motor", "robotis_carCont_aux_motor_speed_2": ", the output value", "robotis_carCont_calibration_1": "Value of the infrared sensor calibration ", "robotis_openCM70_aux_motor_speed_1": "Speed of decelerating motor", "robotis_openCM70_aux_motor_speed_2": ", Set as", "robotis_openCM70_aux_servo_mode_1": "Servo motor mode", "robotis_openCM70_aux_servo_speed_1": "Servo motor speed", "robotis_openCM70_aux_servo_speed_2": ", the output value", "robotis_openCM70_aux_servo_position_1": "Position of servo motor", "robotis_openCM70_aux_led_module_1": "LED module", "robotis_openCM70_aux_custom_1": "User device", "XBOT_digital": "Digital", "XBOT_D2_digitalInput": "D2 Digital Input", "XBOT_D3_digitalInput": "D3 Digital Input", "XBOT_D11_digitalInput": "D11 Digital Input", "XBOT_analog": "Analog", "XBOT_CDS": "Light Sensor Value", "XBOT_MIC": "Mic Sensor Value", "XBOT_analog0": "Analog PIN0 Value", "XBOT_analog1": "Analog PIN1 Value", "XBOT_analog2": "Analog PIN2 Value", "XBOT_analog3": "Analog PIN3 Value", "XBOT_Value": "Ouput Value", "XBOT_pin_OutputValue": "PIN, Ouput Value", "XBOT_High": "HI", "XBOT_Low": "LO", "XBOT_Servo": "Servo Motor", "XBOT_Head": "Head(D8)", "XBOT_ArmR": "Right Arm(D9)", "XBOT_ArmL": "Left Arm(D10)", "XBOT_angle": ", Angle", "XBOT_DC": "Wheel(DC) Motor", "XBOT_rightWheel": "Right", "XBOT_leftWheel": "Left", "XBOT_bothWheel": "Both", "XBOT_speed": ", Speed", "XBOT_rightSpeed": "Wheel(DC) Motor Right(2) Speed:", "XBOT_leftSpeed": "Left(1) Speed:", "XBOT_RGBLED_R": "RGB LED Color from Red", "XBOT_RGBLED_G": "Green", "XBOT_RGBLED_B": "Blue", "XBOT_RGBLED_color": "RGB LED Color from", "XBOT_set": " ", "XBOT_c": "C", "XBOT_d": "D", "XBOT_e": "E", "XBOT_f": "F", "XBOT_g": "G", "XBOT_a": "A", "XBOT_b": "B", "XBOT_melody_ms": "sec of Melody Playing", "XBOT_Line": "th Line", "XBOT_outputValue": "Text", "roborobo_num_analog_value_1": "アナログ", "roborobo_num_analog_value_2": "番センサー値", "roborobo_get_digital_value_1": "デジタル", "roborobo_num_pin_1": "デジタル", "roborobo_num_pin_2": "番ピン", "roborobo_on": "ON", "roborobo_off": "OFF", "roborobo_motor1": "モーター1", "roborobo_motor2": "モーター2", "roborobo_motor_CW": "正転", "roborobo_motor_CCW": "逆回転", "roborobo_motor_stop": "停止", "roborobo_input_mode": "入力", "roborobo_output_mode": "出力", "roborobo_pwm_mode": "電流調節(pwm)", "roborobo_servo_mode": "サーボモーター", "roborobo_color": "カラーセンサー", "roborobo_color_red": " 赤色", "roborobo_color_green": " 緑 ", "roborobo_color_blue": " 青 ", "roborobo_color_yellow": " 黄色 ", "roborobo_color_detected": " 検知", "roborobo_degree": " ˚", "robotori_D2_Input": "Digital Pin 2 Input Value", "robotori_D3_Input": "Digital Pin 3 Input Value", "robotori_A0_Input": "Analog Pin 0 Input Value", "robotori_A1_Input": "Analog Pin 1 Input Value", "robotori_A2_Input": "Analog Pin 2 Input Value", "robotori_A3_Input": "Analog Pin 3 Input Value", "robotori_A4_Input": "Analog Pin 4 Input Value", "robotori_A5_Input": "Analog Pin 5 Input Value", "robotori_digital": "Digital", "robotori_D10_Output": "Pin 10", "robotori_D11_Output": "Pin 11", "robotori_D12_Output": "Pin 12", "robotori_D13_Output": "Pin 13", "robotori_pin_OutputValue": "Output Value", "robotori_On": "On", "robotori_Off": "Off", "robotori_analog": "Analog", "robotori_analog5": "Pin 5 Output Value", "robotori_analog6": "Pin 6 Output Value", "robotori_analog9": "Pin 9 Output Value", "robotori_Servo": "Servo Motor", "robotori_DC": "DC Motor", "robotori_DC_rightmotor": "Right", "robotori_DC_leftmotor": "Left", "robotori_DC_STOP": "Stop", "robotori_DC_CW": "clockwise", "robotori_DC_CCW": "anticlockwise", "robotori_DC_select": "direction", "CALC_rotation_value": "方向値", "CALC_direction_value": "移動方向値", "VARIABLE_is_included_in_list": "リストに含まれているか?", "VARIABLE_is_included_in_list_1": " ", "VARIABLE_is_included_in_list_2": "に", "VARIABLE_is_included_in_list_3": "が含まれているか?", "SCENE_when_scene_start": "シーンが始まった時", "SCENE_start_scene_1": " ", "SCENE_start_scene_2": "スタート", "SCENE_start_neighbor_scene_1": " ", "SCENE_start_neighbor_scene_2": "シーンをスタート", "SCENE_start_scene_pre": "前の", "SCENE_start_scene_next": "次の", "FUNCTION_explanation_1": "関数の名前", "FUNCTION_character_variable": "文字/数字の値", "FUNCTION_logical_variable": "判断値", "FUNCTION_function": "関数", "FUNCTION_define": "関数を定義する", "CALC_calc_operation_sin": "サイン値", "CALC_calc_operation_cos": "コサイン値", "CALC_calc_operation_tan": "タンジェント値", "CALC_calc_operation_floor": "小数点以下切り捨て値", "CALC_calc_operation_ceil": "小数点以下切り上げ値", "CALC_calc_operation_round": "四捨五入値", "CALC_calc_operation_factorial": "階乗値", "CALC_calc_operation_asin": "アークサイン値", "CALC_calc_operation_acos": "アークコサイン値", "CALC_calc_operation_atan": "アークタンジェント値", "CALC_calc_operation_log": "ログ値", "CALC_calc_operation_ln": "自然ログ値", "CALC_calc_operation_natural": "整数部分", "CALC_calc_operation_unnatural": "小数点部分", "MOVING_locate_object_time_1": " ", "MOVING_locate_object_time_2": "秒間", "MOVING_locate_object_time_3": "位置に移動する", "wall_up": "上側の壁", "wall_down": "下の壁", "wall_right": "右の壁", "wall_left": "左の壁", "CALC_coordinate_x_value": "x座標値", "CALC_coordinate_y_value": "y座標値", "CALC_coordinate_rotation_value": "方向", "CALC_coordinate_direction_value": "移動方向", "CALC_picture_index": "模様番号", "CALC_picture_name": "模様名", "FLOW_repeat_while_true_1": " ", "FLOW_repeat_while_true_2": " 繰り返す", "TUT_when_start": "プログラム実行をクリックした時", "TUT_move_once": "前に1マス移動", "TUT_rotate_left": "左側に回転", "TUT_rotate_right": "右側に回転", "TUT_jump_barrier": "障害物をジャンプする", "TUT_repeat_tutorial_1": " ", "TUT_repeat_tutorial_2": "~回繰り返す", "TUT_if_barrier_1": "もし前に", "TUT_if_barrier_2": " があるなら", "TUT_if_conical_1": "もし前に", "TUT_if_conical_2": " があるなら", "TUT_repeat_until": "パーツに到達するまで繰り返す", "TUT_repeat_until_gold": "パーツに到達するまで繰り返す", "TUT_declare_function": "関数宣言", "TUT_call_function": "関数呼び出し", "CALC_calc_operation_abs": "絶対値", "CONTEXT_COPY_option": "コードコピー", "Delete_Blocks": "コード削除", "Duplication_option": "コードをコピー&ペースト", "Paste_blocks": "ペースト", "add_my_storage": "マイボックスに追加する", "export_object": "Export Object", "Clear_all_blocks": "すべてのコードを削除する", "add_comment": "メモを追加する", "copy_paste_comment": "メモをコピー&貼り付けする", "copy_comment": "メモをコピーする", "delete_comment": "メモを削除する", "fold_comment": "メモを折りたたむ", "open_comment": "メモを展開する", "separate_comment": "メモを分ける", "hide_all_comment": "すべてのメモを非表示にする", "show_all_comment": "すべてのメモを表示する", "transparency": "透明度", "BRUSH_change_brush_transparency_1": "筆の透明度を", "BRUSH_change_brush_transparency_2": "%大きくする", "BRUSH_set_brush_transparency_1": "筆の透明度を", "BRUSH_set_brush_transparency_2": "%にする", "CALC_char_at_1": " ", "CALC_char_at_2": "の", "CALC_char_at_3": "番目の文字", "CALC_length_of_string_1": " ", "CALC_length_of_string_2": "の文字数", "CALC_substring_1": " ", "CALC_substring_2": "の", "CALC_substring_3": "番目の文字から", "length_of_string": "番目の文字から", "CALC_substring_4": "番目の文字までの文字", "CALC_replace_string_1": " ", "CALC_replace_string_2": "の", "CALC_replace_string_3": "を", "CALC_replace_string_4": "に変える", "CALC_change_string_case_1": " ", "CALC_change_string_case_2": "の", "CALC_change_string_case_3": " ", "CALC_change_string_case_sub_1": "大文字", "CALC_change_string_case_sub_2": "小文字", "CALC_index_of_string_1": " ", "CALC_index_of_string_2": "から", "CALC_index_of_string_3": "ではじまる位置", "MOVING_add_direction_by_angle_time_explain_1": " ", "MOVING_direction_relative_duration_1": " ", "MOVING_direction_relative_duration_2": "秒間移動方向", "MOVING_direction_relative_duration_3": "分回転する", "CALC_get_sound_volume": "音の値", "SOUND_sound_from_to_1": "サウンド", "SOUND_sound_from_to_2": " ", "SOUND_sound_from_to_3": "秒から", "SOUND_sound_from_to_4": "秒まで再生する", "SOUND_sound_from_to_and_wait_1": "サウンド", "SOUND_sound_from_to_and_wait_2": " ", "SOUND_sound_from_to_and_wait_3": "秒から", "SOUND_sound_from_to_and_wait_4": "秒まで再生して待つ", "CALC_quotient_and_mod_1": " ", "CALC_quotient_and_mod_2": "/", "CALC_quotient_and_mod_3": "の", "CALC_quotient_and_mod_4": " ", "CALC_quotient_and_mod_sub_1": "商", "CALC_quotient_and_mod_sub_2": "あまり", "self": "自分", "CALC_coordinate_size_value": "サイズ", "CALC_choose_project_timer_action_1": "ストップウォッチ", "CALC_choose_project_timer_action_2": " ", "CALC_choose_project_timer_action_sub_1": "スタート", "CALC_choose_project_timer_action_sub_2": "停止する", "CALC_choose_project_timer_action_sub_3": "初期化する", "LOOKS_change_object_index_1": " ", "LOOKS_change_object_index_2": "送る", "LOOKS_change_object_index_sub_1": "一番前に", "LOOKS_change_object_index_sub_2": "前に", "LOOKS_change_object_index_sub_3": "後ろに", "LOOKS_change_object_index_sub_4": "一番後ろに", "FLOW_repeat_while_true_until": "になるまで", "FLOW_repeat_while_true_while": "の間", "copy_block": "ブロックコピー", "delete_block": "ブロック削除", "tidy_up_block": "コードを整理する", "block_hi": "やあ!", "entry_bot_name": "Entrybot", "hi_entry": "やあ、エントリー!", "hi_entry_en": "Hello Entry!", "bark_dog": "犬が吠えるサウンド", "walking_entryBot": "Walking Entrybot", "doggi_bark": "Doggi's Bark", "entry": "エントリー", "hello": "やあ", "nice": "嬉しいな", "silent": "無音", "do_name": "ド", "do_sharp_name": "ド#(レ♭)", "re_name": "レ", "re_sharp_name": "レ#(ミ♭)", "mi_name": "ミ", "fa_name": "ファ", "fa_sharp_name": "ファ#(ソ♭)", "sol_name": "ソ", "sol_sharp_name": "ソ#(ラ♭)", "la_name": "ラ", "la_sharp_name": "ラ#(シ♭)", "DUMMY": "ダミー", "coconut_stop_motor": "stop motor", "coconut_move_motor": "move motor", "coconut_turn_motor": "turn", "coconut_move_outmotor": "external motor", "coconut_turn_left": "left", "coconut_turn_right": "right", "coconut_move_forward": "forward", "coconut_move_backward": "backward", "coconut_note_c": "note_c", "coconut_note_d": "note_d", "coconut_note_e": "note_e", "coconut_note_f": "note_f", "coconut_note_g": "note_g", "coconut_note_a": "note_a", "coconut_note_b": "note_b", "coconut_move_speed_1": "0", "coconut_move_speed_2": "50", "coconut_move_speed_3": "100", "coconut_move_speed_4": "150", "coconut_move_speed_5": "255", "coconut_play_buzzer_hn": "Half", "coconut_play_buzzer_qn": "Quater", "coconut_play_buzzer_en": "Eighth", "coconut_play_buzzer_sn": "Sixteenth", "coconut_play_buzzer_tn": "Thirty-second", "coconut_play_buzzer_wn": "Whole", "coconut_play_buzzer_dhn": "Dotted half", "coconut_play_buzzer_dqn": "Dotted quarter", "coconut_play_buzzer_den": "Dotted eighth", "coconut_play_buzzer_dsn": "Dotted sixteenth", "coconut_play_buzzer_dtn": "Dotted thirty-second", "coconut_rest_buzzer_hr": "Half_rest", "coconut_rest_buzzer_qr": "Quater_rest", "coconut_rest_buzzer_er": "Eighth_rest", "coconut_rest_buzzer_sr": "Sixteenth_rest", "coconut_rest_buzzer_tr": "Thirty-second rest", "coconut_rest_buzzer_wr": "Whole_rest", "coconut_play_midi_1": "Twinkle Twinkle little star", "coconut_play_midi_2": "Three bears", "coconut_play_midi_3": "Mozart's Lullaby", "coconut_play_midi_4": "Do-Re-Mi", "coconut_play_midi_5": "Butterfly", "coconut_floor_sensing_on": "detect", "coconut_floor_sensing_off": "not detect", "coconut_dotmatrix_set_on": "on", "coconut_dotmatrix_set_off": "off", "coconut_dotmatrix_row_0": "all", "coconut_dotmatrix_row_1": "1", "coconut_dotmatrix_row_2": "2", "coconut_dotmatrix_row_3": "3", "coconut_dotmatrix_row_4": "4", "coconut_dotmatrix_row_5": "5", "coconut_dotmatrix_row_6": "6", "coconut_dotmatrix_row_7": "7", "coconut_dotmatrix_row_8": "8", "coconut_dotmatrix_col_0": "all", "coconut_dotmatrix_col_1": "1", "coconut_dotmatrix_col_2": "2", "coconut_dotmatrix_col_3": "3", "coconut_dotmatrix_col_4": "4", "coconut_dotmatrix_col_5": "5", "coconut_dotmatrix_col_6": "6", "coconut_dotmatrix_col_7": "7", "coconut_dotmatrix_col_8": "8", "coconut_sensor_left_proximity": "left IR distance", "coconut_sensor_right_proximity": "right IR distance", "coconut_sensor_both_proximity": "both IR distance", "coconut_sensor_left_floor": "left line tracer", "coconut_sensor_right_floor": "right line tracer", "coconut_sensor_both_floor": "both line tracer", "coconut_sensor_acceleration_x": "X-Axis Accelerometer", "coconut_sensor_acceleration_y": "Y-Axis Accelerometer", "coconut_sensor_acceleration_z": "Z-Axis Accelerometer", "coconut_sensor_light": "light sensor", "coconut_sensor_temperature": "temperature", "coconut_left_led": "left led", "coconut_right_led": "right led", "coconut_both_leds": "both led", "coconut_color_cyan": "Cyan", "coconut_color_magenta": "Magenta", "coconut_color_black": "Black", "coconut_color_white": "White", "coconut_color_red": "Red", "coconut_color_yellow": "Yellow", "coconut_color_green": "Green", "coconut_color_blue": "Blue", "coconut_beep": "buzzer on", "coconut_clear_buzzer": "buzzer off", "coconut_x_axis": "X-Axis", "coconut_y_axis": "Y-Axis", "coconut_z_axis": "Z-Axis", "modi_enviroment_bule": "Blue", "modi_enviroment_green": "Green", "modi_enviroment_humidity": "Humidity", "modi_enviroment_illuminance": "Illuminance", "modi_enviroment_red": "Red", "modi_enviroment_temperature": "Temparature", "modi_gyroscope_xAcceleratior": "X-axis acceleration", "modi_gyroscope_yAcceleratior": "Y-axis acceleration", "modi_gyroscope_zAcceleratior": "Z-axis acceleration", "modi_motor_angle": "Angle", "modi_motor_speed": "Speed", "modi_motor_torque": "Torque", "modi_speaker_F_DO_5": "DO 5", "modi_speaker_F_DO_6": "DO 6", "modi_speaker_F_DO_7": "DO 7", "modi_speaker_F_DO_S_5": "DO #5", "modi_speaker_F_DO_S_6": "DO #6", "modi_speaker_F_DO_S_7": "DO #7", "modi_speaker_F_MI_5": "MI 5", "modi_speaker_F_MI_6": "MI 6", "modi_speaker_F_MI_7": "MI 7", "modi_speaker_F_PA_5": "FA 5", "modi_speaker_F_PA_6": "FA 6", "modi_speaker_F_PA_7": "FA 7", "modi_speaker_F_PA_S_5": "FA #5", "modi_speaker_F_PA_S_6": "FA #6", "modi_speaker_F_PA_S_7": "FA #7", "modi_speaker_F_RA_5": "LA 5", "modi_speaker_F_RA_6": "LA 6", "modi_speaker_F_RA_7": "LA 7", "modi_speaker_F_RA_S_5": "LA #5", "modi_speaker_F_RA_S_6": "LA #6", "modi_speaker_F_RA_S_7": "LA #7", "modi_speaker_F_RE_5": "RE 5", "modi_speaker_F_RE_6": "RE 6", "modi_speaker_F_RE_7": "RE 7", "modi_speaker_F_RE_S_5": "LA #5", "modi_speaker_F_RE_S_6": "RE #6", "modi_speaker_F_RE_S_7": "RE #7", "modi_speaker_F_SOL_5": "SOL 5", "modi_speaker_F_SOL_6": "SOL 6", "modi_speaker_F_SOL_7": "SOL 7", "modi_speaker_F_SOL_S_5": "SOL #5", "modi_speaker_F_SOL_S_6": "SOL #6", "modi_speaker_F_SOL_S_7": "SOL #7", "modi_speaker_F_SO_5": "TI 5", "modi_speaker_F_SO_6": "TI 6", "modi_speaker_F_SO_7": "TI 7", "si_name": "シ", "ev3_ccw": "CCW", "ev3_cw": "CW", "rokoboard_sensor_name_0": "Sound", "rokoboard_sensor_name_1": "Light", "rokoboard_sensor_name_2": "Slider", "rokoboard_sensor_name_3": "resistance-A", "rokoboard_sensor_name_4": "resistance-B", "rokoboard_sensor_name_5": "resistance-C", "rokoboard_sensor_name_6": "resistance-D", "rokoboard_string_1": "Button Pressed", "HW_MOTOR": "モーター", "HW_SENSOR": "センサー", "HW_LED": "発光ダイオード", "HW_MELODY": "メロディ", "HW_ROBOT": "ロボット", "ALTINO_ACCX": "acceleration X axis", "ALTINO_ACCY": "acceleration Y axis", "ALTINO_ACCZ": "acceleration Z axis", "ALTINO_BAT": "battery check", "ALTINO_CDS": "light", "ALTINO_GYROX": "gyro X axis", "ALTINO_GYROY": "gyro Y axis", "ALTINO_GYROZ": "gyro Z axis", "ALTINO_IR1": "1 distance", "ALTINO_IR2": "2 distance", "ALTINO_IR3": "3 distance", "ALTINO_IR4": "4 distance", "ALTINO_IR5": "5 distance", "ALTINO_IR6": "6 distance", "ALTINO_Led_Brake_Light": "brake", "ALTINO_Led_Forward_Light": "forward", "ALTINO_Led_Reverse_Light": "backward", "ALTINO_Led_Turn_Left_Light": "left direction", "ALTINO_Led_Turn_Right_Light": "right direction", "ALTINO_Line": "line", "ALTINO_MAGX": "geomagnetic X axis", "ALTINO_MAGY": "geomagnetic Y axis", "ALTINO_MAGZ": "geomagnetic Z axis", "ALTINO_REMOTE": "remote control", "ALTINO_STTOR": "steering torque", "ALTINO_STVAR": "steering potentiometer", "ALTINO_Steering_Angle_Center": "center", "ALTINO_Steering_Angle_Left10": "left10", "ALTINO_Steering_Angle_Left15": "left15", "ALTINO_Steering_Angle_Left20": "left20", "ALTINO_Steering_Angle_Left5": "left5", "ALTINO_Steering_Angle_Right10": "right10", "ALTINO_Steering_Angle_Right15": "right15", "ALTINO_Steering_Angle_Right20": "right20", "ALTINO_Steering_Angle_Right5": "right5", "ALTINO_TEM": "temperature", "ALTINO_TOR1": "right torque", "ALTINO_TOR2": "left torque", "ALTINO_Value": "output value", "ALTINO_a": "la", "ALTINO_a2": "la#", "ALTINO_b": "si", "ALTINO_c": "do", "ALTINO_c2": "do#", "ALTINO_d": "re", "ALTINO_d2": "re#", "ALTINO_dot_display_1": "one char", "ALTINO_dot_display_2": "display", "ALTINO_e": "mi", "ALTINO_f": "fa", "ALTINO_f2": "fa#", "ALTINO_g": "sol", "ALTINO_g2": "sol#", "ALTINO_h": "off", "ALTINO_h2": "on", "ALTINO_leftWheel": "left", "ALTINO_melody_ms": "play", "ALTINO_outputValue": "output", "ALTINO_rightWheel": "right", "ALTINO_set": " display", "ardublock_motor_forward": "Forward", "ardublock_motor_backward": "Backward", "jdkit_clockwise": "시계방향", "jdkit_counterclockwise": "반시계방향", "jdkit_gyro_frontrear": "앞뒤", "jdkit_gyro_leftright": "좌우", "jdkit_joystick_leftleftright": "왼쪽 좌우", "jdkit_joystick_lefttopbottom": "왼쪽 상하", "jdkit_joystick_rightleftright": "오른쪽 좌우", "jdkit_joystick_righttopbottom": "오른쪽 상하", "jdkit_led": "LED", "jdkit_led_color_green": "초록색", "jdkit_led_color_orange": "오랜지색", "jdkit_led_turnoff": "끄기", "jdkit_led_turnon": "켜기", "jdkit_motor_leftbottom": "왼쪽아래", "jdkit_motor_lefttop": "왼쪽위", "jdkit_motor_rightbottom": "오른쪽아래", "jdkit_motor_righttop": "오른쪽위", "jdkit_tune_do": "도", "jdkit_tune_fa": "파", "jdkit_tune_la": "라", "jdkit_tune_mi": "미", "jdkit_tune_re": "레", "jdkit_tune_si": "시", "jdkit_tune_sol": "솔", "FUNBOARD_bt_down": "yellow(B)", "FUNBOARD_bt_left": "green(C)", "FUNBOARD_bt_right": "blue(D)", "FUNBOARD_bt_up": "red(A)", "FUNBOARD_column_tag": "column", "FUNBOARD_do_off": "off", "FUNBOARD_do_on": "on", "FUNBOARD_led_color_all": "모두", "FUNBOARD_led_color_blue": "blue", "FUNBOARD_led_color_green": "green", "FUNBOARD_led_color_red": "red", "FUNBOARD_led_color_str": "color ", "FUNBOARD_led_color_yellow": "yellow", "FUNBOARD_led_off_str": "Turn off the LED", "FUNBOARD_led_on_str": "Turn on the LED", "FUNBOARD_row_tag": "row", "FUNBOARD_scroll_down": "downward", "FUNBOARD_scroll_left": "leftward", "FUNBOARD_scroll_no": "no", "FUNBOARD_scroll_right": "rightward", "FUNBOARD_scroll_up": "upwards", "FUNBOARD_sensor_cds": "light sensor", "FUNBOARD_sensor_mic": "microphone sensor", "FUNBOARD_sensor_slide": "potentiometer", "FUNBOARD_sensor_state_1": "low", "FUNBOARD_sensor_state_2": "high", "FUNBOARD_touchbt_down": "yellow(B)", "FUNBOARD_touchbt_enter": " F", "FUNBOARD_touchbt_escape": " G", "FUNBOARD_touchbt_left": "green(C)", "FUNBOARD_touchbt_right": "blue(D)", "FUNBOARD_touchbt_space": " E", "FUNBOARD_touchbt_up": "red(A)", "funboard_dotmatrix_set_off": "off", "funboard_dotmatrix_set_on": "on", "AI_UTILIZE": "AI", "video_show_video": "表示", "video_hide_video": "非表示", "video_brightness": "明度", "video_transparency": "透明度", "video_left_right": "右反", "video_top_bottom": "上下", "video_human": "体", "video_face": "顔", "video_object": "物", "video_start": "始める", "video_end": "止める", "video_gender": "性別", "video_age": "年齢", "video_emotion": "感情", "video_motion_onself": "自分", "video_motion_onscreen": "画面", "video_motion_scale": "モーション", "video_motion_direction_horizontal": "x 方向", "video_motion_direction_vertical": "y 方向", "table_row": "行", "table_col": "列", "table_sum": "sum", "table_max": "max", "table_min": "min", "table_avg": "average", "table_stdev": "standard deviation", "arduino_lite_reconnect": "再接続する", "arduino_lite_download_firmware": "ファームウェア", "arduino_lite_download_driver": "ドライバー", "arduino_lite_connect": "ブラウザーで接続", "arduino_lite_disconnect": "キャンセル", "arduino_lite_guide": "• connection guide", }; Lang.video_body_coord_params = { "left_eye": "左眼", "right_eye": "右眼", "nose": "鼻", "left_mouth": "左口", "right_mouth": "右口", "upper_lip": "上口", "lower_lip": "下口", "face": "顔", "neck": "首", "left_ear": "左耳", "right_ear": "右耳", "left_shoulder": "左肩", "left_elbow": "左肘", "left_wrist": "左手首", "left_hip": "左尻", "left_knee": "左膝", "left_ankle": "左足首", "right_shoulder": "右肩", "right_elbow": "右肘", "right_wrist": "右手首", "right_hip": "右尻", "right_knee": "右膝", "right_ankle": "右足首" }; Lang.video_emotion_params = { "angry": "怒り", "disgusted": "嫌悪", "fearful": "恐怖", "happy": "幸せ", "neutral": "無表情", "sad": "悲しみ", "surprised": "驚き" }; Lang.video_object_params = { "person": "人", "bicycle": "自転車", "car": "車", "motorcycle": "オートバイ", "airplane": "飛行機", "bus": "バス", "train": "列車", "truck": "トラック", "boat": "ボート", "traffic light": "信号機", "fire hydrant": "消火栓", "stop sign": "一時停止標識", "parking meter": "パーキングメーター", "bench": "ベンチ", "bird": "鳥", "cat": "ネコ", "dog": "犬", "horse": "うま", "sheep": "羊", "cow": "牛", "elephant": "象", "bear": "くま", "zebra": "シマウマ", "giraffe": "キリン", "backpack": "バックパック", "umbrella": "傘", "handbag": "ハンドバッグ", "tie": "ネクタイ", "suitcase": "スーツケース", "frisbee": "フリスビー", "skis": "スキー板", "snowboard": "snowboard", "sports ball": "スポーツボール", "kite": "カイト", "baseball bat": "野球用バット", "baseball glove": "野球グローブ", "skateboard": "スケートボード", "surfboard": "サーフボード", "tennis racket": "テニスラケット", "bottle": "ボトル", "wine glass": "ワイングラス", "cup": "カップ", "fork": "フォーク", "knife": "ナイフ", "spoon": "スプーン", "bowl": "丼鉢", "banana": "バナナ", "apple": "林檎", "sandwich": "サンドイッチ", "orange": "オレンジ", "broccoli": "ブロッコリ", "carrot": "にんじん", "hot dog": "ホットドッグ", "pizza": "ピザ", "donut": "ドーナツ", "cake": "ケーキ", "chair": "椅子", "couch": "ソファー", "potted plant": "鉢植え", "bed": "ベッド", "dining table": "食卓", "toilet": "トイレ", "tv": "テレビ", "laptop": "ラップトップ", "mouse": "マウス", "remote": "リモコン", "keyboard": "キーボード", "cell phone": "携帯電話", "microwave": "電子レンジ", "oven": "オーブン", "toaster": "トースター", "sink": "シンク", "refrigerator": "冷蔵庫", "book": "本", "clock": "時計", "vase": "花瓶", "scissors": "はさみ", "teddy bear": "テディベア", "hair drier": "ヘアドライヤー", "toothbrush": "歯ブラシ" }; Lang.Buttons = { "share_policy": "Share Guide", "write_policy": "Write Guide", "lesson_list": "講義リスト", "complete_study": "学習を完了する", "show_me": "プレビュー", "do_this_for_me": "代わりに行う", "previous": "前", "get_started": "スタート", "next_lesson": "次の内容を学習する", "course_submit": "提出する", "course_done": "確認", "mission": "ミッションを確認する", "basic_guide": "基本的な使用方法", "apply": "適用する", "add": "追加する", "cancel": "取消", "save": "確認", "start": "はじめ", "confirm": "確認", "delete": "削除", "create": "クラス作成", "done": "完了", "accept": "応答", "refuse": "拒否", "yes": "はい", "button_no": "いいえ", "quiz_retry": "もう一度解く", "discuss_upload": "読み込む", "maze_popup_guide": "利用案内", "maze_popup_mapHint": "ヒントを見る", "maze_hint_btn_guide": "利用案内", "maze_hint_btn_block": "ブロックヘルプ", "maze_hint_btn_map": "ヒントを見る", "maze_hint_btn_goal": "目標", "list_save": "保存する", "duplication": "コピーする", "export_to_excel": "ダウンロード", "single_line": "一行で書く", "multi_line": "改行して書く", "lecture_finish_popup_reset_lecture": "처음부터 다시하기", "lecture_finish_popup_show_output": "실습한 코드보기", "lecture_view_hints": "View hints", "default_hint_title": "どのように作るか", "show_only_vector": "Only Vector" }; Lang.Menus = { "nothing_to_import": "読み込みできる項目がありません。", "nothing_to_export": "書き出しできる項目がありません。", "content_copied": "内容がコピーされました。", "list_import_title": "読み込む", "list_import_placeholder": "例)\n内容1\n内容2\n内容3\n内容4\n内容5\n内容6\n内容7\n内容8", "verifying_email": "認証メール送信", "list_import_notice_1": "複数の項目の内容を一度に登録することができます。", "list_import_notice_2": "既存の内容は、新しく保存する内容に上書きされます。", "list_export_title": "リストを書き出す", "list_export_notice": "リストの項目の内容をコピーしたり、Excelでダウンロードすることができます。", "robotis_opencm70": "Robotis Open CM70", "cannnot_mark_favorite": "非公開の作品は関心作品に指定できません。", "enterPassword": "パスワードを入力してください。", "enterPassword_update": "変更を保存するためにパスワードを入力してください。", "enterNewPassword": "新しいパスワードを入力してください。", "reEnterNewPassword": "新しいパスワードを再入力してください。", "resign": "会員退会", "check_sended_email": "送信された認証メールを確認し、メールアドレスを認証してください。", "signUpEmail_1": "入力されたメールアドレスに認証メールを送信しました。", "signUpEmail_2": "メールアドレスを認証してください。", "select_email_unauthenticated_user": "The email address is registered to the IDs below.\nPlease choose the right one.", "select_user": "Please choose the ID.", "enter_password_withdraw": "会員退会手続きのため、パスワードを入力してください。", "instruction_agree": "次の内容に同意してください。", "check_instructions": "上記の内容に同意します。", "deleteAccount_2": "会員退会手続きから30日後に会員情報と作品/講義/クラス/投稿/コメント/いいね/関心情報はすべて削除され、復元できなくなります。", "deleteAccount_1": "会員退会手続きから30日以内にログインすると、会員退会を取り消すことができます。", "protect_account": "安全なパスワードであなたの情報を保護してください。", "please_verify": "認証メールを送信し、メールアドレスを認証してください。", "unverified_email": "メールアドレス認証に失敗しました。", "deleteAccount": "会員退会手続き", "corporatePersonal": "個人情報の移転に同意します。", "corporateTransferGuide": "個人情報譲受人(「エントリー」ウェブサイト運営者)について", "corporateReciever": "個人情報の移転を受ける者: 財団法人CONNECT", "corporateAddress": "CONNECTの住所及び連絡先", "corporateAddress_1": "ソウル市江南区江南大路382 メリッツタワー7階", "corporateConsent": "個人情報の移転を希望しない場合の同意撤回方法", "corporateEmail": "アカウントに登録されたメールアドレスで退会手続きのメールを送信", "corporateAddition": "併せまして、営業譲渡に伴い規約等が次のように変更になります。", "corporateApplicationDate": "適用時期 : 2017年10月29日", "corporateTargetChanges": "適用対象及び変更内容:", "corporateTarget": "適用対象", "corporateChanges": "変更内容", "corporateTerms": "エントリー利用規約", "corporateOperator": "ウェブサイト運営者の名称変更", "corporateClassroomTerms": "クラスサービス利用規約", "doAgreeWithClassroomTerms": "クラスサービス利用規約に同意します。", "doChangePassword": "他人に分かりにくいパスワードに変更してください。", "corporatePrivacyPolicy": "プライバシーポリシー", "corporateConsignment": "ウェブサイト運営者の名称変更及び個人情報委託企業を追加", "corporateEntrusted": "受諾業: NHN Technology Service(株)", "corporateConsignmentDetails": "委託業務の内容: サービス開発及び運営", "corporatePeriod": "保有期間 : 会員退会時または委託契約終了時まで", "corporateChangeDate": "変更適用日 : 2017年10月29日付", "corporateWarning": "個人情報の移転に同意してください。", "corporateConfirm": "確認", "corporateTitle": "平素よりエントリー教育研究所をご愛顧頂きまして誠にありがとうございます。
「エントリー」をご利用中の会員の皆様に心より感謝申し上げます。
エントリー教育研究所はこれまで公的な目的で運営してまいりました「エントリー」ウェブサイトの運営を
NAVERが設立した非営利財団であるCONNECT財団に譲渡することで合意いたしました。
今後、エントリーはCONNECT財団において公益目的で継続的に運営される
予定であり、会員の皆様はこれまでと同様にエントリーをご利用いただけます。
ウェブサイト提供主体がエントリー教育研究所からCONNECT財団に変更されるため、以下の
ような会員個人情報に関する移転がございますが、本合意により実際の個人情報の位置が
物理的に移動したわけではございません。", "textcoding_numberError_f": "登録された関数の中に名前の一文字目が数字の関数があるとモード変換できません。", "textcoding_bookedError_1f": "登録された関数の中に関数名が", "textcoding_bookedError_2f": "の関数があるとモード変換できません。", "textcoding_specialCharError_f": "登録された関数の中の名前に「_」を除く記号がある場合、モード変換できません。", "textcoding_numberError_v": "登録された変数の中に名前の一文字目が数字の変数があるとモード変換できません。", "textcoding_bookedError_1v": "登録された変数の中に変数名が", "textcoding_bookedError_2v": " の変数があるとモード変換できません。", "textcoding_specialCharError_v": "登録された変数の中の名前に「_」を除く記号がある場合、モード変換できません。", "textcoding_numberError_l": "登録されたリストの中に名前の一文字目が数字であるリストがあるとモード変換できません。", "textcoding_bookedError_1l": "登録されたリストの中にリスト名が", "textcoding_bookedError_2l": "のリストがあるとモード変換できません。", "textcoding_specialCharError_l": "登録されたリストの中に名前に「_」を除く記号がある場合、モード変換できません。", "no_discuss_permission": "投稿を閲覧するための権限がありません。", "delete_comment": "コメントを削除しますか?", "delete_article": "投稿を削除しますか?", "discuss_cannot_edit": "自分の投稿ではありません。", "discuss_extention": "実行ファイルは添付できません。", "delete_discuss_picture": "写真を削除しますか?", "delete_discuss_file": "ファイルを削除しますか?", "discuss_save_question": "投稿を保存しますか?", "discuss_cancle_question": "作成を取消しますか?", "discuss_saved": "が保存されました。", "discuss_no_write_permission": "現在ログイン中のアカウントでは投稿を作成できません。", "discuss_no_project_permission": "現在ログイン中のアカウントでは作品を掲示できません。", "discuss_write_abuse_detected": "短時間に複数の投稿が作成されました。\n1分後にやり直してください。", "contents_abuse_detected": "5分後にやり直してください。", "contents_abuse_detected_10": "10分後にやり直してください。", "discuss_new_write_abuse_warn": "短時間に複数のコメントを作成した場合、\nコメントの作成が制限されることがあります。\nあらかじめご注意ください。", "discuss_write_abuse_warn": "短時間に複数のコメントを作成した場合、\nコメントの作成が制限されることがあります。\nあらかじめご注意ください。", "find_not_your_email": "メールアドレスが正しくありません", "search_lang": "検索", "search_title": "タイトル", "faq_desc": "エントリー利用中に不明な点がございましたら、回答を確認してみてください。", "faq_all": "すべて表示", "faq_site": "サイトのご利用について", "faq_project": "作品を作る", "faq_hardware": "ハードウェア", "faq_offline": "オフライン", "faq_copyright": "著作権", "faq_title": "よくある質問", "faq": "よくある質問", "malicious_warning": "不健全な写真は読み込むことができません。不健全な写真でない場合は「提案と意見」に写真を添付してお知らせください。", "fword_alert_msg": "悪口や不健全な投稿は掲示できません。", "fword_alert_1": "テーマに関係のない悪口や悪意のあるコメントは掲示できません。", "fword_alert_2": "不健全な単語が含まれているため、代替テキストが掲示されます。", "fword_replace_1": "エントリーを通して、誰でも簡単に楽しくソフトウェアについて学ぶことができます。", "fword_replace_2": "ソフトウェア教育の第一歩、エントリー。", "fword_replace_3": "楽しく学べる学習スペース、エントリー!", "fword_replace_4": "エントリーで共有と協業を行い、素晴らしい作品を作りましょう。", "fword_replace_5": "エントリーは誰でも無料でソフトウェア教育を受けることができるよう開発されたソフトウェア教育プラットフォームです。", "fword_replace_6": "エントリーと一緒に健全なソフトウェア教育環境を作りましょう!", "fword_replace_7": "エントリーで学び、作り、共有しながら一緒に成長しましょう。", "solve_quiz": "クイズに挑戦する", "submit_homework_first_title": "完成! 課題を提出する", "submit_homework_first_content": "素晴らしい作品が完成しました。課題を提出してください。締切期限前まで再提出できます。", "submit_homework_again_title": "課題を再提出する", "submit_homework_again_content": "すでに提出した課題です。
課題を再提出しますか?", "submit_homework_expired_title": "課題提出締切", "submit_homework_expired_content": "課題の提出が締め切られました。", "done_study_title": "完成", "done_study_content": "作成した作品を実行してみましょう。", "featured_courses": "オススメ講義集", "follow_along": "やってみる", "follow_along_desc": "少しずつ進めながらバラエティ豊かな作品を制作します。", "do_quiz": "クイズに挑戦する", "do_quiz_desc": "学習した内容を十分理解できているか、クイズを通して確認します。", "challenge": "挑戦する", "play": "挑戦する", "challenge_desc": "与えられた問題を自ら解決し、概念を身に着けます。", "creste_freely": "自由に作る", "creste_freely_desc": "学習した内容で自分だけの作品を自由に制作します。", "entry_rc_desc": "プログラミングの原理を学習レベルに合わせて学べるエントリー講義集! 今すぐ始めてみましょう!
お手本にしながら挑戦してソフトウェアを制作すれば、難しく感じられたプログラミングの原理も楽しく簡単に身につきます!", "hw_deadline": "締切日", "rc_course_desc": "プログラミングの原理を学習レベルに合わせて学べるよう構成されたエントリー講義集です。", "rc_course": "オススメ講義集", "entry_rec_course": "エントリーオススメ講義集", "entry_rec_course_desc": "誰でも簡単に、真似をしながら楽しくバラエティ豊かなソフトウェアを制作できるエントリー講義を紹介します。", "guidance": "案内", "wait": "ストップ!", "hint": "ヒント", "concept_guide": "概念バッチリ", "group_quiz": "クラスクイズ", "fail_check_hint": "あっ…失敗! もう一度挑戦してみてください!
難しい時は[ヒント]を確認してください!", "sort_student": "学生別", "sort_lesson": "講義別", "sort_course": "講義集別", "student_progress": "クラスの進度", "my_progress": "自分の進度", "lec_in_progress": "学習中", "free_modal_asgn_over": "課題の提出が締め切られました。", "free_submission_closed": "課題提出締切", "free_modal_asgn_submit_first": "素晴らしい作品が完成しました! 課題を提出してください。
締切期限前まで再提出できます。", "asgn_submit": "完成! 課題を提出する", "free_modal_content_resubmit": "すでに提出した課題です。
課題を再提出しますか?", "asgn_resubmit": "課題を再提出する", "free_modal_content_complete": "素晴らしい作品が完成しました。", "guide_modal_content_complete": "制作した作品を実行してみましょう。", "success": "成功", "fail": "失敗", "mission_modal_content_fail": "
難しい時は[ヒント]を確認してください!", "mission_modal_content_success": "作った作品を実行してみましょう。", "in_progress": "進行中", "completed": "完了", "submitted": "提出完了", "submission_closed": "締切", "progress": "進行状況", "study_completed": "学習完了", "view_course_desc": "コースウェアの説明を見る", "main_entry_starter": "基礎から! エントリースターター", "main_entry_booster": "概念固め! エントリーブースター", "main_entry_master": "思考を広げる! エントリーマスター", "no_students_in_classroom": "まだ登録された学生がいません。
学生を直接追加するか招待してください!", "lectures": "講義", "Lectures": "講義", "studentHomeworkList": "課題", "curriculums": "講義集", "Curriculums": "講義集", "quiz": "クイズ", "no_added_group_contents_teacher": "追加された%1がありません。
クラス%1を追加してください。", "no_added_group_contents_student": "まだアップロードされた%1がありません。先生が%1をアップロードすると、学習内容を確認できます。", "side_project": "サブプロジェクト", "custom_make_course_1": "「オープン講義を作成する>講義集を作成する」で", "custom_make_course_2": "自分だけの講義集を作成してみてください。", "custom_make_lecture_1": "「オープン講義を作成する」で", "custom_make_lecture_2": "自分だけの講義を作成してみてください。", "alert_enter_info": "修正したい情報を入力してください。", "alert_enter_new_pwd": "既存のパスワードと違うパスワードを入力してください。", "alert_match_pwd": "新しいパスワードと再入力されたパスワードが一致しません。", "alert_check_pwd": "パスワードを確認してください。", "alert_update_complete": "修正が完了しました。", "no_group_contents_each_prefix": "クラス", "no_group_contents_each_suffix": " がありません。", "no_group_contents_all": "クラスにアップロードされたコンテンツがありません。
「クラスで共有する」に
自分の作品を共有してみてください!", "hw_closed": "課題締切", "tag_Lecture": "講義", "tag_Curriculum": "講義集", "tag_Discuss": "お知らせ", "count_ko": "件", "no_asgn_within_week": "1週間以内に提出する必要のある、締切間近の課題はありません。", "lecture_and_curriculum": "講義/講義集", "assignments_plural": "課題", "assignments_singular": "課題", "project_plural": "作品", "group_news": "新しいニュース", "stu_management": "学生管理", "stu_management_camel": "学生管理", "view_all": "すべて表示", "view_all_camel": "すべて表示", "view_contents_camel": "コンテンツを見る", "view_contents": "コンテンツを見る", "no_updated_news": "自分のクラスにアップロードされた新しいニュースはありません。", "homework_soon_due": "締切間近の課題", "new_homework": "最新の課題", "no_new_homework": "新しい課題はありません。", "student_plural": "学生", "discuss": "お知らせ", "basic_project": "基本作品", "no_permission": "権限がありません。", "no_comment_write_permission": "現在ログイン中のアカウントではコメントを作成できません。", "original_curriculum_deleted": "講義原本集が削除されました。", "original_curriculum": "講義原本集", "save_as_my_lecture": "コピーで保存する", "delete_confirm": "削除通知", "lecture_open_as_copied": "オープン講義ページにアップロードされたすべての講義はコピーを作成して公開されます。", "curriculum_open_as_copied": "オープン講義集ページにアップロードされたすべての講義集はコピーを作成して公開されます。", "lecture_save_as_copied_group": "クラス講義ページにアップロードされたすべての講義はコピーを作成して公開されます。", "curriculum_save_as_copied_group": "クラス講義集ページにアップロードされたすべての講義集はコピーを作成して公開されます。", "homework_save_as_copied_group": "クラス課題ページにアップロードされたすべての課題はコピーを作成して公開されます。", "lecture_save_as_copied": "自分が作った講義集内に挿入された構成講義はコピーを作成して保存されます。", "done_project_save_as_copied": "自分が作った講義案に挿入された完成作品はコピーを作成して保存されます。", "textbook_project_can_not_applied": "", "original_lecture_deleted": "講義原本が削除されました。", "original_lecture": "講義原本", "lecture_save_as_mine_alert": "保存されました。\n保存された講義は「マイページ> 自分の講義」で確認できます。", "lecture_save_as_mine": "自分の講義に保存する", "duplicate_username": "すでに入力したIDです。", "share_your_project": "あなたが作った作品を共有してみてください", "not_available_student": "クラスで発行された「クラスID」です。\n「エントリー会員ID」を入力してください。", "login_instruction": "ログインについて", "login_needed": "ログインしてからご利用いただけます。", "login_as_teacher": "教師アカウントでログインしてからご利用いただけます。", "remove_my_storage": "マイボックスから削除しますか?削除したブロック/オブジェクトは元に戻せません。", "submit_hw": "課題を提出する", "success_goal": "目標達成", "choseok_final_result": "よし、自分だけの作品を完成したぞ!", "choseok_fail_msg_timeout": "タイムオーバーだぜ。目標をよく見てもう一度チャレンジしてみようぜ!", "choseok_fail_msg_die": "ライフが0以下なのにまだゲームが終ってないぞ。\n下のブロックを使ってもう一度チャレンジしてみないか?", "grade_1": "初級", "grade_2": "中級", "grade_3": "上級", "find_sally_title": "サリーを探せ", "save_sally_title": "サリーを救え", "exit_sally_title": "サリーと脱出", "find_sally": "LINEレンジャーの力を一つに合わせて\n最強ボス・メフィストを倒し、サリーを救ってください!", "save_sally": "メフィストの基地に閉じ込められたサリー。\nLINEレンジャーが障害物を避けてサリーを探し出せる\nように手伝ってください!", "exit_sally": "爆破されたメフィストの基地から\nサリーとLINEレンジャーが無事脱出できるように\n手伝ってください!", "go_next_mission": "他のミッションに挑戦する", "share_my_project": "自分が作った作品を共有する", "share_certification": "証明書を共有する", "print_certification": "証明書を自慢しよう", "get_cparty_events": "自分が受け取った証明書を出力して自慢すると、豪華賞品を獲得できます!", "go_cparty_events": "イベントに参加する", "codingparty2016_blockHelper_1_title": "前に進む", "codingparty2016_blockHelper_1_contents": "前に進む", "codingparty2016_blockHelper_2_title": "前に進む", "codingparty2016_blockHelper_2_contents": "回転する", "codingparty2016_blockHelper_3_title": "前に進む", "codingparty2016_blockHelper_3_contents": "石を砕く", "codingparty2016_blockHelper_4_title": "前に進む", "codingparty2016_blockHelper_4_contents": "回繰り返す", "codingparty2016_blockHelper_5_title": "前に進む", "codingparty2016_blockHelper_5_contents": "花を投げる", "codingparty2016_goalHint_1": "サリーを救うためにはミネラルが必要だ!ミネラルを獲得しながら目的地まで行ってみよう!", "codingparty2016_goalHint_2": "曲がり道があるね。ターンブロックを使えば大丈夫だよ!", "codingparty2016_goalHint_3": "道が石で塞がれているね。石を砕きながら目的地まで行ってみよう!", "codingparty2016_goalHint_4": "ややこしい道だけど、これまで覚えたテクニックを使えば解決できるはずだよ!", "codingparty2016_goalHint_5": "長く続く道だね。リピートブロックを使って簡単に解決してみよう!", "codingparty2016_goalHint_6": "ミネラルを全部集めよう。リピートブロックを使えば簡単にできそうだよ!", "codingparty2016_goalHint_7": "みんながケガをしないように花を投げてクモの巣を取り除かないと!遠くにあるクモの巣を取り除いて目的地まで行ってみよう。", "codingparty2016_goalHint_8": "道にクモの巣が多いね。クモの巣を全部取り除いて目的地まで行ってみよう。", "codingparty2016_goalHint_9": "クモの巣の後ろに隠れているミネラルを全部集めよう!", "codingparty2016_guide_1_1_contents": "LINEレンジャーたちがサリーを救い出せるように手伝ってあげて! ブロックコマンドを組み合わせれば、レンジャーたちを動かすことができるよ。\n\n① まず、ミッション画面と目標を確認して、\n② ブロックリストから必要なブロックを引っ張ってきて「スタートボタンを押した時」のブロックにつなげてね。\n③ 組み合わせ終わったら「スタート」ボタンを押してみよう!ブロックコマンドが上から順に実行されて、レンジャーたちが動くはずだよ。", "codingparty2016_guide_1_1_title": "LINEレンジャーたちを動かすためには?", "codingparty2016_guide_1_2_title": "目標ブロック数", "codingparty2016_guide_1_2_contents": "① [色が塗られていない星]の数だけブロックコマンドを組み合わせてミッションを解決してみよう。目標ブロック数より多くブロックを使うと星の色が赤に代わるから、決められた数で問題を解決してみてね!\n② 要らないブロックはゴミ箱やブロックリストに戻してね。", "codingparty2016_guide_1_3_title": "「前に進む」ブロックを使う", "codingparty2016_guide_1_3_contents": "< 前に進む >は、前に1マス移動するブロックだよ。\n\nもっと移動したいときはこのブロックを必要な数だけつなげよう。", "codingparty2016_guide_1_4_title": "ミネラルを獲得する", "codingparty2016_guide_1_4_contents": "[ミネラル]があるマスを通り過ぎるとミネラルを獲得できるよ。\n\n画面にあるミネラルを全部獲得して目的地に到着しないと、次のステップに進めないからね。", "codingparty2016_guide_1_5_title": "行き詰ったときは?", "codingparty2016_guide_1_5_contents": "行き詰った時は下の3つのヘルプボタンを押してみよう。\n\n\n<案内> 今読んでいるこの利用案内をもう一度確認したいとき!\n<ブロックヘルプ> 一つ一つのブロックコマンドがどう実行されるか知りたいとき!\n<マップヒント> このステップを解決するためのヒントが必要なとき!", "codingparty2016_guide_2_1_title": "ターンブロックを使う", "codingparty2016_guide_2_1_contents": "<右に回転する>と<左に回転する>は、\nその場で方向だけ90度回転させるブロックだよ。方向だけ回転させるブロックなんだ。\nキャラクターから向かって右か左か、よく考えて使ってね!!\n", "codingparty2016_guide_3_1_title": "「ムーン」のスキルを使う", "codingparty2016_guide_3_1_contents": "LINEレンジャーたちはそれぞれ特殊なスキルを持っているんだ。\n僕、[ムーン]は<キックする>で手前にある[石]を砕くことができるよ。\n[石]を砕けば前に進めるようになるよね。\n画面にある[石]を全部取り除かないと次のステップに進めないからね。\nでも忘れないでね!何もないマスで無駄にスキルを使っちゃダメだよ!", "codingparty2016_guide_5_1_title": "「~回繰り返す」ブロックを使う", "codingparty2016_guide_5_1_contents": "同じブロックを何個もつなげるのは本当に面倒くさいよね。\nそんな時はリピートコマンドを使えばもっと簡単に解決できるんだ。\n<[ ? ] ~回繰り返す>ブロックの中に繰り返されるアクションのブロックを入れて\n[ ? ]の部分に回数を入力すれば、入力した回数だけ同じコマンドを繰り返し実行させることができるよ。", "codingparty2016_guide_5_2_title": "<~回繰り返す>ブロックを使う", "codingparty2016_guide_5_2_contents": "<[ ? ]回繰り返す>ブロックの中にはブロックを複数組み合わせて入れることもできるから、うまく活用してみてね!\n目的地に着いてからもリピートブロックの中にあるブロックコマンドは全て実行されるよ。\n上の状況だと、目的地に着いた後、左にターンしてから終わるということ!", "codingparty2016_guide_7_1_title": "(コニー)のスキルを使う", "codingparty2016_guide_7_1_contents": "私「コニー」は<花を投げる>で遠くからでも前にある[クモの巣]を取り除くことができるよ。\n[クモの巣]を取り除けば前に進めるようになるよね?\n画面にある[クモの巣]を全部取り除かないと次のステップに進めないからね。\nでも忘れないでね!何もないマスで無駄にスキルを使っちゃダメだよ!", "codingparty2016_guide_9_1_title": "条件リピートブロックを使う", "codingparty2016_guide_9_1_contents": "何回繰り返せばいいか考えなくても、特定の条件を満たすまでそのアクションを繰り返すことができるよ。\n<[目的地]に到着するまで繰り返す>ブロックの中に繰り返されるブロックを入れると[目的地]に到着するまでコマンドを繰り返し実行するよ。", "codingparty2016_guide_9_2_title": "条件リピートブロックを使う", "codingparty2016_guide_9_2_contents": "<[目的地]に到着するまで繰り返す>ブロックの中にはコマンドを複数入れることもできるからうまく活用してみて! \n目的地に着いてからもリピートブロックの中にあるブロックコマンドは全て実行されるよ。上の状況だと、目的地に着いた後、左にターンしてから終わるということ!", "find_interesting_lesson": "「クラス講義」でバラエティ豊かな講義をお楽しみください!", "find_interesting_course": "「クラス講義集」でバラエティ豊かな講義をお楽しみください!", "select_share_settings": "共有スペースを選択してください。", "faq_banner_title": "よくある質問について", "check_out_faq": "質問に答えます!", "faq_banner_content": "エントリーについて分からないことがありますか?
よくある質問でご回答させていただいています。
今すぐ確認してください!", "faq_banner_button": "よくある質問
へ移動", "major_updates": "主なアップデートのご案内", "check_new_update": "エントリーの変化を確認してください。", "major_updates_notification": "エントリーの主な変更内容はお知らせでご案内しております。", "find_out_now": "今すぐ確認してください!", "offline_hw_program": "オフライン&ハードウェア結合プログラム", "read_more": "詳しく見る", "sample_project": "例示作品", "not_supported_function": "この端末ではサポートされていない機能です。", "offline_download_confirm": "エントリーのオフラインバージョンはPCでのみご利用いただけます。ダウンロードしますか?", "hardware_download_confirm": "エントリーのハードウェアはPCでのみご利用いただけます。ダウンロードしますか?", "copy_text": "テキストをコピーしてください。", "select_openArea_space": "作品共有スペースを選択してください", "mission_guide": "「ミッションを解決する」について", "of": " の", "no_results_found": "検索結果がありません。", "upload_pdf": "PDF資料アップロード", "select_basic_project": "作品を選択する", "try_it_out": "作成してみる", "go_boardgame": "エントリーボットボードゲームに移動", "go_cardgame": "エントリーボットカードゲームに移動", "go_solve": "ミッションで学習する", "go_ws": "「エントリーを作成する」に移動", "go_arts": "「エントリーを共有する」に移動", "group_delete_alert": "クラスを削除すると、そのクラスで発行した学生用臨時アカウントを含む関連資料がすべて削除されます。\n本当に削除しますか?", "view_arts_list": "他の作品を見る", "hw_submit_confirm_alert": "課題が提出されました。", "hw_submit_alert": "課題を提出しますか? ", "hw_submit_alert2": "課題を提出しますか? 提出時に学習が完了した学習レベルまでのみ提出されます。", "hw_submit_cannot": "提出できない課題です。", "see_other_missions": "他のミッションを見る", "project": " 作品", "marked": " 関心", "group": "クラス", "lecture": "講義", "Lecture": "講義", "curriculum": "講義集", "Curriculum": "講義集", "studying": "学習中の", "open_only_shared_lecture": "オープン講義 ページに<公開>した講義のみ読み込むことができます。読み込む講義公開状況を確認してください。", "already_exist_group": "このクラスがすでに存在します。", "cannot_invite_you": "自分は招待できません。", "apply_original_image": "オリジナル画像をそのまま適用する", "draw_new_ques": "「新しく描画する」ページに\n移動しますか?", "draw_new_ques_1": "絵を描いてオブジェクトとして保存できます。", "draw_new_ques_2": "描く画面に移動しますか", "draw_new_go": "移動する", "draw_new_stay": "移動しない", "file_upload_warn_title_image": "下のような画像は、利用規約および関連の法律によって制裁を受けることがあります。", "file_upload_warn_desc_image": "暴力的で残酷な画像
性的に体の部位が露出している画像
不快感を与えたり、嫌悪感を与える画像
無断使用が禁止された画像", "file_upload_warn_title_sound": "下記のようなサウンドは、利用規約および関連の法律によって制裁措置される場合があります。", "file_upload_warn_desc_sound": "暴力的で残酷なサウンド
性的なサウンド
不快感や嫌悪感を与えるサウンド
無断使用が禁止されたサウンド", "file_upload_warn_title_table": "下のような画像は、利用規約および関連の法律によって制裁を受けることがあります。", "file_upload_warn_desc_table": "暴力的で残酷な画像
性的に体の部位が露出している画像
不快感を与えたり、嫌悪感を与える画像
無断使用が禁止された画像", "file_upload_warn_link": "著作権について", "file_upload_desc_1": "こういう画像は\nNGです!", "file_upload_desc_2": "暴力的で残酷な画像", "file_upload_desc_3": "性的に体の部位が露出している画像", "file_upload_desc_4": "不快感を与えたり、嫌悪感を与える画像", "file_upload_desc_5": "* 上のような内容は、利用規約および関連法律により制裁を受けることがあります。", "picture_upload_warn_old": "10MB以下のjpg,png,bmp形式の画像ファイルのみアップロードできます。", "sprite_upload_warn_old": "10MB以下のjpg,png,bmp形式の画像やeo形式のオブジェクトファイルのみアップロードできます。", "picture_upload_warn_1": "10MB以下のjpg,png,bmp,svg形式の画像ファイルのみアップロードできます。\njpg,png,bmp形式はビットマップモードで,svg形式はベクターモードで編集されます。", "table_upload_warn_1": "10MB以下のcsv,xls(x)形式の画像ファイルのみアップロードできます。", "sprite_upload_warn": "10MB以下のjpg,png,bmp,svg形式の画像やeo形式のオブジェクトファイルのみアップロードできます。", "sound_upload_warn_1": "10MB以下のmp3形式のファイルを追加できます。", "sound_edit_warn": "お待ちください。
ただいま、新しい音の編集機能を研究中です。", "file_upload_loading": "ローディング中", "lesson_by_teacher": "先生方が直接作成する講義です。", "delete_group_art": "「クラスで共有する」リストから削除しますか?", "elementary_short": "小学校", "middle_short": "中学校", "grade_34": "3-4学校", "grade_56": "5-6学校", "grade_78": "中学校", "share_lesson": "講義を共有する", "share_course": "講義集を共有する", "from_list_ko": "は", "comming_soon": "準備中です。", "no_class_alert": "選択されたクラスがありません。クラスがない場合、「自分のクラス」メニューでクラスを作成してください。", "students_cnt": "人", "defult_class_alert_1": " ", "defult_class_alert_2": "を\n基本クラスに設定しますか?", "default_class": "基本クラスです。", "enter_hw_name": "課題のタイトルを入力してください。", "hw_limit_20": "課題の作成上限は20件です。", "stu_example": "例)\n 山田太郎\n山田太郎\n山田太郎", "hw_description_limit_200": "作成課題に関する案内事項を入力してください。(200文字以内)", "hw_title_limit_50": "課題名を入力してください。(50文字以内)", "create_project_class_1": "「作る」>「作品を作る」で", "create_project_class_2": "クラスで共有したい作品を制作してください。", "create_lesson_assignment_1": "「作る> オープン講義を作成する」で", "create_lesson_assignment_2": "クラス課題に追加したい講義を作成してください。", "i_make_lesson": "自分が作成した講義", "lesson_to_class_1": "「学習する>オープン講義」でクラスの", "lesson_to_class_2": "課題に追加したい講義を関心講義に登録してください。", "studying_students": "学習者", "lessons_count": "講義数", "group_out": "退出する", "enter_group_code": "クラスコードを入力する", "no_group_invite": "クラス招待がありません。", "done_create_group": "開設に成功しました。", "set_default_group": "基本クラス設定", "edit_group_info": "クラス情報管理", "edit_done": "修正が完了しました。", "alert_group_out": "クラスから本当に退出しますか?", "lesson_share_cancel": "講義共有取消", "project_share_cancel": "作品共有取消", "lesson_share_cancel_alert": "続けますか?", "course_share_cancel": "講義集共有取消", "select_lesson_share": "講義共有スペース選択", "select_project_share": "作品共有選択", "select_lesson_share_policy_1": "講義を共有したい", "select_lesson_share_policyAdd": "スペースを選択してください", "select_lesson_share_project_1": "作品を共有するスペースと", "select_lesson_share_policy_2": "著作権ポリシーを確認してください。", "select_lesson_share_area": "講義共有スペースを選択してください", "select_project_share_area": "作品共有スペースを選択してください", "lesson_share_policy": "講義共有に伴うエントリーの著作権ポリシーに同意", "project_share_policy": "作品共有に伴うエントリーの著作権ポリシーに同意", "alert_agree_share": "公開するためには、エントリーの著作物ポリシーに同意する必要があります。", "alert_agree_all": "すべての項目に同意してください。", "select_course_share": "講義集共有スペースを選択", "select_course_share_policy_1": "講義集を共有する", "select_course_share_policy_2": "著作権ポリシーを確認してください。", "select_course_share_area": "講義集共有スペースを選択してください", "course_share_policy": "講義集共有に伴うエントリーの著作権ポリシーに同意", "issued": "発行", "code_expired": "コードの期限が切れました。「コード再発行」ボタンを押してください。", "accept_class_invite": "クラス招待を承認する", "welcome_class": "クラスへようこそ。", "enter_info": "あなたの情報を入力してください。", "done_group_signup": "クラスへ参加しました。", "enter_group_code_stu": "先生から受け取ったコードを入力してください。", "text_limit_50": "50文字以下で作成してください。", "enter_class_name": "クラス名を入力してください。", "enter_grade": "学年を入力してください。", "enter_class_info": "クラス紹介を入力してください。", "student_dup": "はすでにクラスに存在します。", "select_stu_print": "出力する学生を選択してください。", "class_id_not_exist": "クラスIDが存在しません。", "error_try_again": "エラー発生。もう一度やり直してください。", "error_forbidden": "権限がありません。", "code_not_available": "このコードは無効です。", "gnb_create_lessons": "オープン講義作成", "study_lessons": "講義で学習する", "lecture_help_1": "学習開始時に使用する作品を選択してください。選択した作品で学習者が学習を開始します。", "lecture_help_2": "このヘルプをもう一度確認したい時は、上のボタンをクリックしてください。", "lecture_help_3": "「オブジェクトを追加する」がない場合、新しいオブジェクトを追加または削除することができません。", "lecture_help_4": "学習途中に「PDF資料を見る」を利用して学習を手伝ってもらうことができます。", "lecture_help_5": "学習に必要なブロックのみ選択してください。選択しないブロックは非表示になります。", "lecture_help_6": "ブロックコーディングとエントリーパイソンの中から選択し、学習環境を構成できます。", "lecture_finish_popup_title": "학습 다시하기", "lecture_finish_popup_content_1": "실습완료한 단계를
처음부터 다시 실습하시겠습니까?", "lecture_finish_popup_content_2": "* 다시 실습해도 실습 완료 상태는 유지됩니다.", "lecture_start_title": "Start", "lecture_goal_title": "Goal", "lecture_goal_content": "Goal", "lecture_prepare_title": "Prepare", "lecture_summary_title": "Summary", "lecture_summary_content": "Let's summarize what we learned.", "lecture_quiz_title": "Quiz", "lecture_quiz_content": "Let's check what we learned through the verification problem.", "lecture_quiz_check_answer": "Check the answer", "default_hint_title": "どのように作るか", "only_pdf": ".pdf形式のファイルのみ入力できます。", "enter_project_video": "最低1件の作品、または映像を入力してください。", "enter_title": "タイトルを入力してください。", "enter_recommanded_grade": "推奨学年を入力してください。", "enter_level_diff": "難易度を入力してください。", "enter_time_spent": "所要時間を入力してください。", "enter_shared_area": "最低1件の共有スペースを選択してください。", "enter_goals": "学習目標を入力してください。", "enter_lecture_description": "講義説明を入力してください。", "enter_curriculum_description": "講義集説明を入力してください。", "first_page": "最初です。", "last_page": "最後です。", "alert_duplicate_lecture": "すでに登録されている講義は再登録できません。", "enter_lesson_alert": "1つ以上の講義を登録してください。", "open_edit_lessons": "編集したい講義を読み込んでください。", "saved_alert": "が保存されました。", "select_lesson_type": "どのような学習課程を作成するかを選択してください ", "create_lesson": "講義を作成する", "create_lesson_desc_1": "希望する学習目標に合わせ", "create_lesson_desc_2": "ひとつの講義を作成して", "create_lesson_desc_3": "学習に活用します。", "create_courseware": "講義集を作成する", "create_courseware_desc_1": "学習課程に合わせて複数の講義を", "create_courseware_desc_2": "ひとつのコースとして作成し", "create_courseware_desc_3": "学習に活用します。", "create_open_lesson": "オープン講義を作成する ", "enter_lesson_info": "講義情報入力", "select_lesson_feature": "学習機能選択 ", "check_info_entered": "入力情報確認 ", "enter_lefo_lesson_long": "講義を構成する情報を入力してください。", "lesson_info_desc": "学習者が「学習する」画面で使用したい機能と作品を選択することで、学習目標や内容に最適化された学習環境を構成できます。", "provide_only_used": "完成された作品で使用されたブロックだけを読み込む", "see_help": "ヘルプを見る", "select_done_project_1": "学習者が目標に設定したい", "select_done_project_2": "完成作品", "select_done_project_3": "を選択してください。", "select_project": "自分の作品または関心作品を読み込みます。", "youtube_desc": "YouTube共有リンクを利用して映像を挿入できます。", "lesson_video": "講義映像", "lesson_title": "講義タイトル", "recommended_grade": "推奨学年", "selection_ko": "選択", "selection_en": " ", "level_of_diff": "難易度", "select_level_of_diff": "難易度選択", "enter_lesson_title": "講義タイトルを入力してください(30文字以内)", "select_time_spent": "所要時間選択 ", "time_spent": "所要時間", "lesson_overview": "講義説明", "upload_materials": "学習資料アップロード", "open": "読み込む", "cancel": "取り消す", "upload_lesson_video": "講義映像アップロード", "youtube_upload_desc": "YouTube共有リンクを利用していサブ映像を挿入できます。", "cancel_select": "選択を取り消す", "select_again": "再選択する", "goal_project": "完成作品", "upload_study_data": "「学習する」画面で閲覧できる学習資料をアップロードしてください。学習者がアップロードされた学習資料の内容を確認して学習できます。", "upload_limit_20mb": "20MB以下のファイルをアップロードしてください。", "expect_time": "予想所要時間", "course_videos": "サブ映像", "enter_courseware_info": "講義集情報入力", "enter_course_info": "講義集を紹介する情報を入力してください ", "select_lessons_for_course": "講義集を構成する講義を選択してください。", "course_build_desc_1": "講義は", "course_build_desc_2": "最大30件まで", "course_build_desc_3": "登録できます。", "lseeon_list": "講義リストを見る", "open_lessons": "講義を読み込む", "course_title": "講義集タイトル", "title_limit_30": "講義集タイトルを入力してください(30文字以内) ", "course_overview": "講義集説明", "charactert_limit_200": "200文字以内で作成できます。", "edit_lesson": "講義編集", "courseware_by_teacher": "先生方が直接作成する講義集です。", "select_lessons": "構成講義選択", "check_course_info": "講義集を構成する情報が正しいか確認してください。", "select_share_area": "共有スペース選択", "upload_sub_project": "サブプロジェクトアップロード", "file_download": "添付ファイルダウンロード", "file_remove": "添付ファイル", "check_lesson_info": "講義を構成する情報が正しいか確認してください。", "share_area": "共有スペース", "enter_sub_project": "エントリーのサブプロジェクトを登録してください。", "lms_hw_title": "課題のタイトル", "lms_hw_ready": "準備", "lms_hw_progress": "進行中", "lms_hw_complete": "完了", "lms_hw_not_submit": "未提出", "lms_hw_closed": "提出締切", "submission_condition": "進行中の課題のみ提出できます。", "submit_students_only": "学生のみ課題を提出できます。", "want_submit_hw": "課題を提出しますか?", "enter_correct_id": "IDを正しく入力してください。", "id_not_exist": "IDが存在しません。", "agree_class_policy": "クラスサービスの利用規約に同意してください。", "delete_class": "クラス削除", "type_stu_name": "学生名を入力してください。", "invite_from_1": "で", "invite_from_2": "さんを招待しました。", "lms_pw_alert_1": "クラスに所属すると、先生の権限で", "lms_pw_alert_2": "パスワードを再発行することができます。", "lms_pw_alert_3": "先生の招待が正しいかもう一度確認してください。", "invitation_accepted": "招待承認が完了しました!", "cannot_issue_pw": "招待を承認していないため、パスワードを発行できません。", "start_me_1": "<月刊エントリー>と共に", "start_me_2": "SW教育をはじめましょう!", "monthly_desc_1": "<月刊エントリー>はソフトウェア教育に不慣れな先生でも簡単かつ楽しく", "monthly_desc_2": "ソフトウェア教育ができるように制作されたSW教育雑誌です。", "monthly_desc_3": "毎月楽しい学習漫画と共にお送りするSW教育コンテンツをお楽しみください!", "monthly_desc_4": "* 月刊エントリーは2015年11月~2016年5月まで発行後、中止されました。", "monthly_desc_5": "エントリーの教育資料は教育資料ページでご覧いただけます。", "monthly_entry": "月刊エントリー", "me_desc_1": "毎月発刊される無料ソフトウェア教育雑誌", "me_desc_2": "月刊エントリーをご購読ください!", "solve_desc_1": "ゲーム感覚でミッションを解決し、", "solve_desc_2": "ソフトウェアの基本原理を学んでみましょう!", "playSw_desc_1": "EBS放送映像や特別映像を通して", "playSw_desc_2": "ソフトウェアを学んでみましょう!", "recommended_lessons": "オススメ講義集", "recommended_lessons_1": "お手本にして挑戦したり、クイズも解きながら、楽しくエントリープログラミングを学んでみましょう!", "recommended_lessons_2": "オススメ講義集をご覧ください!", "offline_top_desc_1": "オフラインバージョンの保存機能が向上し、セキュリティが強化されました。", "offline_top_desc_2": "今すぐダウンロードしてください", "offline_main_desc": "エントリーのオフラインエディターアップデート!!", "art_description": "エントリーで制作された作品を共有するスペースです。作品を制作して共有に参加してみてください。", "art_description_1": "", "art_description_2": "projects created. Create your own project and share.", "study_index": "エントリーで提供するテーマ別・学年別の学習課程を通して少しずつソフトウェアを学んでいきましょう!", "study_for_beginner": "初心者のためのエントリーへの第一歩", "entrybot_desc_3": "案内に従ってブロックコマンドを並べて", "entrybot_desc_4": "エントリーボットを学校に連れていってください。", "move_entrybot": "エントリーボットを動かす", "can_change_entrybot_1": "ブロックコマンドでエントリーボットの色を変えたり", "can_change_entrybot_2": "おしゃべりさせることもできます。", "learning_process_by_topics": "テーマ別学習課程", "show_detail": "詳しく見る", "solve_mission": "ミッションを解決する", "solve_mission_desc_1": "ゲーム感覚でミッションを解決し、プログラミングの原理を身に着けてください!", "solve_mission_desc_2": "迷路の中にいるエントリーボットを目的地まで動かして、順次、反復、条件、比較演算などの概念を自然に身に着けることができます。", "learning_process_by_grades": "学年別学習課程", "learning_process_by_grades_sub1": "4つのタイプで楽しく簡単に学ぶプログラミングの原理! 今すぐ始めてみましょう!", "e3_to_e4": "小学校3-4年生", "e5_to_e6": "小学校5-6年生", "m1_to_m3": "中学生以上", "make_using_entry": "エントリーで作る", "make_using_entry_desc_1": "ブロックを積み重ねて様々なソフトウェアを制作してみてください!", "make_using_entry_desc_2": "提供される教材をダウンロードして少しずつ進めると、アニメーション、メディアアート、ゲームなどのバラエティ豊かな作品を制作できます。", "make_through_ebs_1": "EBS放送映像でソフトウェアを学習してみてください。", "make_through_ebs_2": "放送映像はもちろん、少しずつ進められる特別映像を見ながら誰でも簡単にバラエティ豊かなソフトウェアを制作できます。", "support_block_js": "ブロックコーディングとJavaScript言語すべてに対応しています。", "study_ebs_title_1": "順序通りに! 順番通りに!", "study_ebs_desc_1": "[実習] エントリーボットのおつかい", "study_ebs_title_2": "楽々簡単に!", "study_ebs_desc_2": "[実習] 花房を作る", "study_ebs_title_3": "いつ始める?", "study_ebs_desc_3": "[実習] 動物家族の紹介", "study_ebs_title_4": "異なる選択、違う結果!", "study_ebs_desc_4": "[実習] テレパシーゲーム", "study_ebs_title_5": "情報を含んだ器", "study_ebs_desc_5": "[実習] 足し算ロボットを作る", "study_ebs_title_6": "あれこれ確かめてみよう!", "study_ebs_desc_6": "[実習] ラッキールーレット", "study_ebs_title_7": "番号で呼ぶと楽です!", "study_ebs_desc_7": "[実習] 自分だけのバケットリスト", "study_ebs_title_8": "ランダムプログラムを作成せよ!", "study_ebs_desc_8": "[実習] ランダムキャラクターを作る", "study_ebs_title_9": "どうやって見つける?", "study_ebs_desc_9": "[実習] 図書館の書籍を検索する", "study_ebs_title_10": "お並びください!", "study_ebs_desc_10": "[実習] キー整列プログラム", "event": "イベント", "divide": "分岐", "condition": "条件", "random_number": "乱数", "search": "探索", "sorting": "整列", "parallel": "並列", "signal": "信号", "input_output": "入出力", "sequential": "順次", "repeat": "反復", "choice": "選択", "repeat_advanced": "反復(回数+条件)", "function": "関数", "compare_operation": "比較演算", "arithmetic": "算術演算", "entry_recommended_mission": "エントリーのオススメミッション", "more_mission": "ミッションをもっと見る", "line_rangers_title": "LINEレンジャーと\nサリーを救え", "line_rangers_content": "メフィストの基地に閉じ込められた\nサリーを救ってください!", "pinkbean_title_string_basic": "メイプルスト一リ一 初級 ヘネシス", "pinkbean_title_string_intermediate": "メイプルスト一リ一 中級 エリニア", "pinkbean_title_string_advanced": "メイプルスト一リ一 上級 エルナス", "pinkbean_title": "ピンクビーンと一緒に楽しい\nメイプルワールドへ!", "pinkbean_content": "ピンクビーンがメイプルワールドでの冒険を\n無事に終わらせられるように手伝ってください。", "entrybot_school": "エントリーボットの通学路", "entrybot_school_desc_1": "エントリーボットがカバンを持って学校に", "entrybot_school_desc_2": "到着できるように手伝ってください!", "robot_factory": "ロボット工場", "robot_factory_desc_1": "ロボット工場に閉じ込められたエントリーボット!", "robot_factory_desc_2": "脱出するためには、パーツをすべて集めなければなりません。", "electric_car": "電気自動車", "electric_car_desc_1": "エントリーボットの自動車が前に進み続けられる", "electric_car_desc_2": "よう燃料をチャージしてください。", "forest_adventure": "森の中を探検", "forest_adventure_desc_1": "エントリーボットが森の中に閉じ込められています!", "forest_adventure_desc_2": "友達を助けてください。", "town_adventure": "村を探検", "town_adventure_desc_1": "お腹が空いていいるエントリーボットのために村にある", "town_adventure_desc_2": "燃料を探してください。", "space_trip": "宇宙旅行", "space_trip_desc_1": "宇宙探査を終えたエントリーボット!", "space_trip_desc_2": "地球に戻れるように手伝ってください。", "learn_programming_mission": "ミッションを解決しながら学ぶプログラミング", "make_open_lecture": "オープン講義作成", "group_created": "作成したクラス", "group_signup": "参加したクラス", "delete_from_list": "をリストから削除しますか?", "delete_from_list_en": " ", "lecture_collection": "講義集", "edit_mypage_profile": "自己紹介情報管理", "main_image": "メイン画像", "edit_profile_success": "反映されました。", "no_project_1": "自分が作った作品がありません。", "no_project_2": "作品作りを開始してください!", "empty_project_1": "まだ作られた作品がありません。", "no_marked_project_1": "関心作品がありません。", "no_marked_group_project_1": "クラスの関心作品がありません。", "no_marked_project_2": "「作品を共有する」でたくさんの作品に触れてみてください!", "no_markedGroup_project_2": "「クラスで共有する」でたくさんの作品に触れてみてください!", "view_project_all": "作品を観覧する", "no_lecture_1": "自分が作った講義がありません。", "empty_lecture_1": "まだ作られた講義がありません。", "no_lecture_2": "「オープン講義を作成する」で講義を作成してみてください!", "no_marked_lecture_1": "関心講義がありません。", "no_marked_group_lecture_1": "クラスの関心講義がありません。", "no_marked_lecture_2": "「オープン講義」でバラエティ豊かな講義をお楽しみください!", "view_lecture": "講義を確認する", "no_studying_lecture_1": "学習中の講義がありません。", "no_studying_lecture_2": "「オープン講義」で学習をスタートしてください!", "no_lecture_collect_1": "自分が作った講義集がありません。", "empty_lecture_collect_1": "まだ作られた講義集がありません。", "no_lecture_collect_2": "「オープン講義集を作成する」で講義集を作成してみてください!", "make_lecture_collection": "講義集を作成する", "no_marked_lecture_collect_1": "関心講義 講義集がありません。", "no_marked_lecture_group_collect_1": "クラスの関心講義 講義集がありません。", "no_marked_lecture_collect_2": "「オープン講義」でバラエティ豊かな講義をお楽しみください!", "view_lecture_collection": "講義集を確認する", "no_studying_lecture_collect_1": "学習中の講義集がありません。", "no_studying_lecture_collect_2": "「オープン講義」で学習をスタートしてください!", "my_lecture": "自分の講義", "markedGroup": "クラスの関心", "markedGroup_lecture": "クラスの関心講義", "markedGroup_curriculum": "クラスの関心講義集", "marked_lecture": "関心講義", "marked_lecture_collection": "自分の関心講義集", "marked_marked_curriculum": "関心講義集", "studying_lecture": "学習中の講義", "completed_lecture": "学習完了講義", "my_lecture_collection": "自分の講義集", "my": "自分の", "studying_lecture_collection": "学習中の講義集", "completed_lecture_collection": "学習が完了した講義集", "my_curriculum": "自分の講義集", "studying_curriculum": "学習中の講義集", "completed_curriculum": "学習が完了した講義集", "materialCC": "エントリーで提供するすべての教育資料は、CC-BY 2.0ライセンスにより自由に利用できます。", "materialccby_new": "エントリーで提供するすべての教育資料は、CC-BY 2.0ライセンスにより自由に利用できます。", "entry_copyright_info": "エントリー著作権ガイド表示", "pdf": "PDF", "helper": "ヘルプ", "youtube": "映像", "tvcast": "映像", "goal": "目標", "basicproject": "開始レベル", "hw": "ハードウェア", "object": "オブジェクト", "console": "コンソール", "download_info": "すべての教育資料はそれぞれのタイトルをクリックするとダウンロードできます。", "entry_materials_all": "エントリーの教育資料集", "entry_material": "エントリーの教育資料", "recommand_grade": "推奨学年", "g3_4_grades": "3-4年生", "g5_6_grades": "5-6年生", "middle_grades": "中学生以上", "entry_go_go": "エントリーゴーゴー!", "entry_go_go_desc": "学年別・難易度別に用意された教材をぜひご活用ください!", "entry_go_go_desc2": "各課程別に教育課程・学習指導・教師用指導資料の3点セットを提供しております。", "stage_beginner": "初級", "stage_middle": "中級", "stage_high": "上級", "middle_school_short": "中等", "learn_entry_programming": "お手本にして学ぶエントリープログラミング", "entry_programming_desc": "少しずつ進めれば、いつの間にかあなたもエントリーの達人に!", "ebs": "EBS", "ebs_material_desc": "放送映像と教師用指導書を活用して授業を進めてください!", "season_1_material": "シーズン1 教師用指導書", "season_2_material": "シーズン2 教師用指導書", "season_1": "シーズン1", "playsoftware_ebs": "EBS ソフトウェア、遊ぼう!", "material_teacher_guide": "教師用指導書", "season_2": "シーズン2", "compute_think_textbook": "教科書で学ぶコンピューター的思考力", "computational_sw": "国語、数学、科学、美術…学校で学ぶ様々な教科と連携してSWを学んでください!", "python_coding_text": "エントリーパイソン", "python_coding_textbook": "テキスト·コーディングの世界へ旅立つ旅", "python_coding_desc": "エントリーファイアでテキスト言語の構造と文法を自然に学んでみてください!", "entry_x_hardware_text": "エントリーXハードウェア教育資料", "entry_x_hardware": "エントリーXハードウェア教育資料集", "e_sensor": "Eセンサーボード", "e_sensor_board": "Eセンサーボード", "e_sensor_robot": "Eセンサーロボット", "arduino": "Arduino", "arduinoext": "ArduinoExt Uno", "arduinonano": "Arduino Nano", "albert": "albert", "orange_board": "オレンジボード", "arduino_board": "Arduino", "joystick": "joystick sensor shield", "ardublock": "ardublock", "mkboard": "digital monkeyboard", "mechatro_nano": "Mechatro Nano+", "mechatro_uno": "Mechatro Uno+", "memaker": "memaker", "edumaker": "EduMaker Board", "codingtoolbox": "コーディングツールボックス", "materials_etc_all": "その他の教育資料集", "materials_teaching": "教員研修資料", "materials_etc": "その他の参考資料", "materials_etc_resource": "参考資料", "materials_teaching_etc": "教員研修資とその他の参考資", "materials_teaching_1": "SW教育の必要性と教育方法論", "materials_teaching_2": "エントリーと共に行うアンプラグド活動", "materials_teaching_3": "ゲーム感覚でアルゴリズムが学べるエントリーミッションを解決する", "materials_teaching_4": "実生活の問題解決のためのエントリープログラミング", "materials_teaching_5": "教科連携SW教育1(美術、数学、社会)", "materials_teaching_6": "教科連携SW教育2(国語、科学、音楽)", "materials_teaching_7": "フィジカルコンピューティング実習1(Eセンサーボード)", "materials_teaching_8": "フィジカルコンピューティング実習2(ハムスター)", "materials_teaching_9": "授業に必要なクラス/講義機能を調べる", "materials_etc_1": "エントリー初心者ユーザーのためのスタートガイド", "materials_etc_2": "授業にすぐ活用できるバラエティ豊かなコンテンツ集", "materials_etc_3": "月刊エントリー", "materials_etc_4": "エントリー説明書", "materials_etc_5": "エントリー紹介資料", "materials_etc_6": "エントリーブロック下敷き", "materials_etc_7": "エントリーパイソンの例題と案内", "jr_if_1": "もし", "jr_if_2": "前にあるなら", "jr_fail_no_pencil": "こんな場所に鉛筆はないよ。鉛筆がある場所で使ってみよう~", "jr_fail_forgot_pencil": "あっ! カバンに入れる鉛筆を忘れちゃった。鉛筆を集めに行こう~", "jr_fail_much_blocks": "ブロックをたくさん使いすぎたな。もう一度チャレンジしてみようか?", "cparty_jr_success_1": "やった! カバンを準備したよ!", "go_right": "右", "go_down": " 下", "go_up": " 上", "go_left": " 左", "go_forward": "前に進む", "jr_turn_left": "左に回転する", "jr_turn_right": "右に回転する", "go_slow": "ゆっくり進む", "repeat_until_reach_1": "会うまで繰り返す", "repeat_until_reach_2": " ", "pick_up_pencil": "鉛筆を拾う", "repeat_0": " ", "repeat_1": "繰り返す", "when_start_clicked": "スタートボタンを押した時", "age_0": "作品体験", "create_character": "キャラクターを作成する", "age_7_9": "小学校低学年", "going_school": "エントリー学校に行く", "age_10_12_1": "小学校高学年1", "collect_parts": "ロボット工場でパーツを集める", "age_10_12_2": "小学校高学年2", "driving_elec_car": "電気自動車を運転する", "age_13": "中学", "travel_space": "宇宙を旅行する", "people": "人", "all": "すべて", "life": "日常生活", "nature": "自然", "animal_insect": "動物/昆虫", "environment": "自然環境", "things": "事物", "vehicles": "移動手段", "others": "その他", "fantasy": "ファンタジー", "instrument": "楽器", "piano": "ピアノ", "marimba": "マリンバ", "drum": "ドラム", "janggu": "太鼓", "sound_effect": "効果音", "others_instrument": "その他の打楽器", "aboutEntryDesc_1": "エントリーは、誰でも無料で使えるプログラミング教育プラットフォームです。", "aboutEntryDesc_2": "生徒はプログラミングを簡単に楽しく学習し、", "aboutEntryDesc_3": "先生は効果的に生徒を教えることができます。", "aboutEntryDesc_4": "エントリーは公共財のように", "aboutEntryDesc_5": "非営利で運営されています。", "viewProjectTerms": "利用ポリシーを見る", "openSourceTitle": "オープンソースによる環境造成", "openSourceDesc_1": "エントリーのソースコードのほか、", "openSourceDesc_2": "すべての教育資料はCCライセンスを", "openSourceDesc_3": "適用して公開しています。", "viewOpenSource": "オープンソースを見る", "eduPlatformTitle": "教育に適したプラットフォーム", "eduPlatformDesc_1": "教育現場に適した教育ツールを", "eduPlatformDesc_2": "目指し、学校の先生方と", "eduPlatformDesc_3": "共同開発しています。", "madeWith": "諮問団", "researchTitle": "多様な研究による専門性の強化", "researchDesc_1": "大学/学会などと共に多様な研究を行い、", "researchDesc_2": "専門性を強化し続けて", "researchDesc_3": "います。", "viewResearch": "研究資料を見る", "atEntry": "エントリーでは", "entryLearnDesc_1": "楽しく学べる学習スペース", "entryLearnDesc_2": "< 学習する >には、コンピューターを活用して論理的に問題を解決できるバラエティ豊かな学習", "entryLearnDesc_3": "コンテンツが用意されています。ゲーム感覚で楽しく与えられたミッションをプログラミングで", "entryLearnDesc_4": "解決することができ、役立つ動画を通してソフトウェアの原理を学ぶことができます。", "entryMakeDesc_1": "< 作る >では、米MITで開発したScratchのようなブロック型プログラミング言語を", "entryMakeDesc_2": "使用し、初めてプログラミングに触れる人でも簡単に自分だけの創作物を制作できます。", "entryMakeDesc_3": "さらに、ブロックコーディングとテキストコーディングの橋渡し役をする「エントリーパイソン」モードでは、", "entryMakeDesc_4": "テキスト言語の構造と文法を自然に身につけることができます。", "entryMakeDesc_5": " ", "entryShareDesc_1": "< 共有する >では、エントリーを通して制作した作品を他の人と共有することができます。", "entryShareDesc_2": "また、共有された作品がどのように構成されているのかを調べることができ、これを発展させて自分だけの作品を制作", "entryShareDesc_3": "できます。共同創作もできますので、友達と力を合わせてもっと良い作品を制作することもできます。", "entryGroup": "クラス機能", "entryGroupTitle": "クラス学習スペース", "entryGroupDesc_1": "< クラス機能 >は、教師がクラスごとに学生たちを管理できる機能です。クラスの学生同士で学習して", "entryGroupDesc_2": "作品を共有することができ、課題を作り学生たちの成果物を確認できます。", "entryGroupDesc_3": "また、教師は、講義機能を活用して学生たちのレベルにあった学習環境を", "entryGroupDesc_4": "カスタマイズして提供することで、効率的かつ楽に授業を進めることができます・", "entryGroupDesc_5": " ", "unpluggedToPhysical": "アンプラグド活動から、フィジカルコンピューティングまで", "algorithmActivity": "基礎アルゴリズム", "programmignLang": "教育用プログラミング言語", "unpluggedDesc_1": "エントリーボットのボードゲームとカードゲームで、コンピューターがなくても", "unpluggedDesc_2": "ソフトウェアの基本概念と原理(順次、反復、選択、関数)を身に着けることができます。", "entryMaze": "エントリーボット迷路脱出", "entryAI": "エントリーボット宇宙旅行", "algorithmDesc_1": "ゲーム感覚でミッションを解決し、証明書を手に入れてください。", "algorithmDesc_2": "ソフトウェアの基本的な原理を簡単かつ楽しく学ぶことができます。", "programmingLangDesc_1": "エントリーではブロックを積み上げるようにプログラミングを行うため、誰でも簡単に", "programmingLangDesc_2": "自分だけのゲーム、アニメーション、メディアアートといった素晴らしい作品を制作して共有できる教育用に適合しています。", "viewSupporHwVideo": "See the hardware guide videos", "viewSupporHw": "結合されるハードウェアを見る", "supportHwDesc_1": "エントリーとフィジカルコンピューティングツールを結合すると、現実世界とインタラクションする素晴らしい作品を作り出すことができます。", "supportHwDesc_2": "国内外の様々なハードウェア結合に対応しており、今後も順次追加される予定です。", "entryEduSupport": "エントリー教育支援", "eduSupportDesc_1": "エントリーでは、ソフトウェア教育のための様々な教育資料を制作し無償で配布しています。", "eduSupportDesc_2": "資料はすべてエントリー公式サイトでダウンロードできます。", "materials_1_title": "レベル別教材", "materials_1_desc_1": "各学年のレベルに合う教材を使って、少しずつ", "materials_1_desc_2": "進めながら簡単にエントリーに慣れてください!", "materials_2_title": "EBS放送連携教案", "materials_2_desc_1": "EBS「ソフトウェア、遊ぼう」放送と共に", "materials_2_desc_2": "教師用授業指導案を提供しています。", "materials_3_title": "小・中学校用の教科連携授業資料", "materials_3_title_2": " ", "materials_3_desc_1": "様々な科目で遭遇する実生活での問題を", "materials_3_desc_2": "コンピューター的思考力で解決してみてください。", "moreMaterials": "より多くの教育資料を確認する", "moreInfoAboutEntry_1": "エントリーのニュースをもっと確認したいなら、次のリンクにアクセスしてください。", "moreInfoAboutEntry_2": "教育資料のほかにもバラエティ豊かなSW教育関連情報を共有しています。", "material_menu_type_robot": "Robot\nType", "material_menu_type_module": "Module\nType", "material_menu_type_board": "Board\nType", "blog": "ブログ", "post": "ポスト", "tvCast": "TVキャスト", "about_entry_pre": " ", "about_youtube": "Youtube", "about_facebook": "Facebook", "albertSchool": "Albert", "arduinoBoard": "Arduino certified", "arduinoCompatible": "non-certified", "bitBlock": "ビットブロック", "bitbrick": "Bitbrick", "creamo": "creamo", "playcode": "playcode", "funboard": "funboard", "truerobot": "TrueTrue", "bingle": "BINGLE", "bingles": "BINGLE · S", "codeino": "CODEino", "epor": "EPOR", "petrone_v2": "Petrone V2", "petrone_v2_drone": "flight", "petrone_v2_car": "drive", "e-sensor": "E-センサーボード", "e-sensorUsb": "E-センサーボード(有線連結)", "e-sensorBT": "E-センサーボード(無線連結)", "mechatronics_4d": "4Dメカトロニクス", "esensor_board": "E-Sensor Board", "esensor_robot": "E-Sensor Robot", "hamster": "Hamster", "hummingbird": "Hummingbird Duo", "roboid": "ロボイド", "turtle": "Turtle", "littlebits": "リトルビッツ", "orangeBoard": "OrangeBoard", "robotis_carcont": "Robotis Robot Car", "robotis_IoT": "ロボティズIoT", "robotis_IoT_Wireless": "ロボティズIoT(無線連結)", "dplay": "DPLAY", "iboard": "iboard", "nemoino": "NEMOino", "xbot_epor_edge": "XBOT(OneTouch Dongle/USB)", "XbotBT": "XBOT EPOR and EDGE Bluetooth", "robotori": "robotori", "rokoboard": "rokoboard", "neobot": "NEOBOT", "neobot_sensor_theme": "NEOBOT Senosor Theme", "mechatro": "mechatro", "about": "を調べる", "articles": "討論する", "gallery": "観覧する", "learn": "学習する", "login": "ログイン", "logout": "ログアウト", "make": "作る", "register": "登録する", "Join": "会員登録", "Edit_info": "自分の情報を修正", "Discuss": "投稿する", "Explore": "観覧する", "Load": "読み込む", "My_lesson": "オープン講義", "textbook_learning": "教科書で学習する", "Resources": "教育資料", "play_software": "ソフトウェア、遊ぼう!", "problem_solve": "エントリー学習", "learning_textbook": "教科書で学習する", "context_textbook": "初等学校の教科書のまま、先生は学校の授業を、生徒は家で予習・復習することができます。", "info_banner_textbook": " ", "banner_textbook": "もっと多彩で", "banner_textbook_2": "楽しい学習をしたいなら?", "banner_textbook_right_banner": "教師用の教育資料が必要ですか?", "banner_textbook_right_banner2": " ", "banner_textbook_right_banner_btn": "教育資料ダウンロード", "Learn": "学習する", "teaching_tools": "エントリー教具", "about_entry": "エントリー紹介", "what_entry": "エントリーは?", "create": "作る", "create_new": "新しく作る", "start_programming": "ソフトウェア教育の第一歩", "Entry": "エントリー", "intro_learning": "誰でも簡単かつ楽しくソフトウェアを学ぶことができます。", "intro_learning_anyone": "今すぐ始めてましょう! ", "start_now": "For Free, Forever.", "welcome_entry": "エントリーへようこそ。", "student": "学生", "non_menber": "一般人", "teacher": "先生", "terms_conditions": "利用規約", "personal_information": "個人情報の取り扱いに関するご案内", "limitation_liability": "責任の限界と法的告知", "entry_agree": "エントリーの利用規約に同意します。", "info_agree": "個人情報の取り扱いに同意します。", "next": "次", "enter_individual_info": "個人情報入力", "enter_id": "ID入力", "enter_password": "パスワード入力", "confirm_password": "パスワード確認", "enter_password_again": "パスワードをもう一度入力してください。", "validation_password": "5文字以上の英数字を組み合わせてください。", "validation_id": "4~20文字の英数字を組み合わせてください。", "prev": "前", "born_year": "生年", "select_born": "生年を選択してください", "year": "年", "gender": "性別", "choose_gender": "性別を選択 してください", "male": "男性", "female": "女性", "language": "言語", "best_language": "主言語を選択してください", "korean": "韓国語", "english": "英語", "viet": "ベトナム", "japan": "japan", "russia": "russia", "chinese_simplified": "Chinese(Simplified)", "chinese_traditional": "Chinese(Traditional)", "option_email": "メール(選択)", "insert_email": "メールアドレスを入力してください", "sign_up_complete": "会員登録を完了しました。", "agree_terms_conditions": "利用規約に同意してください。", "agree_personal_information": "「個人情報の取り扱いに関するご案内」に同意してください。", "insert_studying_stage": "作品を共有したいクラスを選択してください。", "insert_born_year": "生年を入力してください。", "insert_gender": "性別をオプションから選択してください。", "select_language": "言語を選択してください。", "check_email": "メール形式を確認してください。", "already_exist_id": "すでに存在するIDです。", "id_validation_id": "IDは4~20文字の英数字を組み合わせてください。", "password_validate_pwd": "パスワードは5文字以上の英数字を組み合わせてください。", "password_validate_pwd_length": "文字を5文字以上組み合わせる必要があります。", "neoid_username_same_id": "すでに使用中のIDです (NEOID)", "insert_same_pwd": "同じパスワードを入力してください。", "studying_stage_group": "作品共有クラス", "studying_stage": "作品を共有したいクラスを選択してください。", "password": "パスワード入力", "save_id": "ID保存", "auto_login": "自動ログイン", "enter_id_pw": "ID,パスワード入力", "forgot_password": "IDとパスワードを忘れましたか?", "did_not_join": "まだエントリー会員ではありませんか?", "go_join": "会員登録する", "renew_index_text_00": "教科書で学ぶ", "renew_index_text_01": "教科書でエントリーを学んでみましょう。", "renew_index_text_02": "初等学校の教科書の講義で", "renew_index_text_02_2": "エントリーを学んでみましょう!", "renew_index_text_03": "教科書で", "renew_index_text_03_2": "学習する", "renew_index_text_1": "2019年、ENTRYが変わります。", "renew_index_text_2": "新しくなった作品作り", "renew_index_text_3": "今すぐ新しい機能を確認して", "renew_index_text_3_2": "PCとタブレットで作品を作ってみましょう。", "renew_index_text_4": "詳しくはこちら", "first_step": "ソフトウェア教育の第一歩", "entry_content_one": "想像していたことをブロックで遊び感覚で1つずつ積み上げてみてください。", "entry_content_two": "ゲーム、アニメーション、メディアアートといった素晴らしい作品を完成できます!", "entry_content_three": "楽しいゲームで学び、自分だけの素晴らしい作品を制作して友達と共有できる素晴らしいエントリーの世界に皆さんをご招待します!", "funny_space": "楽しく学べる学習スペース", "in_learn_section": "< 学習する >には、", "learn_problem_solving": "コンピューターを活用して論理的に問題を解決できるバラエティ豊かな学習コンテンツが用意されています。ゲーム感覚で楽しく、与えられたミッションをプログラミングで解決したり、楽しい動画でソフトウェアの原理を学ぶことができます。", "joy_create": "創作の楽しさ", "in_make": "< 作る >では、", "make_contents": "米MITで開発したScratchのようなビジュアルプログラミング言語を使用し、初めてプログラミングに触れる人も簡単に自分だけの創作物を制作できます。また、エントリーを通して制作できるコンテンツは無限大です。科学の授業で学んだ物理の法則を実験して、好きなキャラクターでアニメーションを制作したり直接ゲームを制作することができます。", "and_content": "また、エントリーを通して制作できるコンテンツは無限大です。科学の授業で学んだ物理の法則を実験して、好きなキャラクターでアニメーションを制作したり直接ゲームを制作することができます。", "share_collaborate": "共有と協業", "explore_contents": "< 共有する >では、エントリーを通して制作した作品を他の人と共有することができます。また、共有された作品がどのように構成されているのかを調べることができ、これを発展させて自分だけのプロジェクトを制作することができます。さらに、エントリーでは共同創作も可能です。友達と協業することでより良いプロジェクトを制作することができます。", "why_software": "何故ソフトウェア教育が必要なのか?", "speak_obama_contents": "コンピューター科学を学ぶことは、単に皆さんの未来のために必要なことではありません。これは、我らがアメリカの未来のために必要なことなのです。", "obama": "バラク・オバマ", "us_president": "米国大統領", "billgates_contents": "コンピュータープログラミングは思考の範囲を広げてより優れた思考ができるようにサポートし、分野に関係なくすべての問題について新しい解決策を生み出せる力を養ってくれます。", "billgates": "ビル・ゲイツ", "chairman_micro": "Microsoft会長", "eric_contents": "現在、デジタル革命は地球上のほとんどの人々においてまだ始まっていないレベルにあります。プログラミングにより今後10年間ですべてのことが変化することでしょう。", "eric": "エリック・シュミット", "sandbug_contents": "今日、コンピューター科学に対する理解は必須となりました。我が国の競争力は、子どもたちにこれをどれだけうまく教えられるかにかかっています。", "sandbug": "シェリル・サンドバーグ", "view_entry_tools": "エントリーと一緒にできる教具を確認できます。", "solve_problem": "ミッションを解決する", "solve_problem_content": "ゲーム感覚でミッションを1つ1つ解決し、ソフトウェアの基本原理を学んでみてください!", "find_extra_title": "エントリーボットパーツ探し大作戦", "all_ages": "全年齢", "total": "合計", "step": "ステップ", "find_extra_contents": "ロボット犬を生産していたルッツ工場にある日突然起こった停電により生まれた特別な犬・エントリーボット。まだ組立が終わっていない残りのパーツを見つけて工場から脱出できるように手伝いながらソフトウェアの動作原理を身に着けよう!", "software_play_contents": "EBSで放送された番組「ソフトウェア、遊ぼう」の内容を実習することができます。", "resources_contents": "エントリーを活用したバラエティ豊かな教育資料を無料で提供しています。", "from": " 出処", "sw_camp": "未来創造科学部のSW創造力キャンプ", "elementary": "小学校", "middle": "中学校", "grades": "学年", "lesson": "回分", "sw_contents_one": "5回分の内容で小学生がエントリーとフィジカルコンピューティングを体験できる教材です。生徒たちはエントリーの使用方法を学習し、イラストボードとストーリーの作成を行います。最後にはアドイノ教具を活用してキーボードを作成する活動を行います。", "sw_camp_detail": "未来創造科学部のSW創造力キャンプ", "sw_contents_two": "5回分の内容で中学生がエントリーとフィジカルコンピューティングを体験できる教材です。学生たちはエントリーの使用方法を学習し、迷路探しゲームとクイズプログラムを制作します。最後にはアドイノ教具を活用してキーボードで自動車を操縦する活動を行います。", "sw_contents_three": "先生方が学校で始められるソフトウェア授業指導書です。バラエティ豊かなアンプラグド活動やTV番組「ソフトウェア、遊ぼう」を活用した授業指導案が入っています。", "naver_sw": "NAVER ソフトウェア、遊ぼう", "teacher_teaching": "教師用指導書 (小学校 5~6年生以上)", "funny_sw": "楽しいSW遊び教室", "sw_contents_four": "ソフトウェアを遊び感覚で楽しく学べる教材で、エントリーボードゲームをはじめバラエティ豊かなアンプラグド活動とエントリー学習モードでソフトウェアを制作する基本原理を学びます。基本原理の学習後、学生たちはエントリーでストーリー、ゲーム、芸術作品、応用プログラムを制作する方法を学び、自分が考えたソフトウェアを制作して発表することができる構成になっています。", "ct_text_5": "教科書と共に育てるコンピューター的思考力", "teacher_grade_5": "教員(小学校5年生)", "ct_text_5_content": "実生活の問題を解決しようというテーマで用意された8種類の学習コンテンツが入っている教師用指導案です。各コンテンツは改正された教育課程を反映した他教科との連携により、様々な問題に遭遇しても解決できるように設計されました。子どもたちがコンピューター的思考力を備えた融合型人材になれるよう、今すぐ適用してください!", "ct_text_6": "教科書と一緒に養うコンピューター的思考力", "teacher_grade_6": "教員(小学校6年生)", "ct_text_6_content": "実生活の問題を解決しようというテーマで用意された8種類の学習コンテンツが入っている教師用指導案です。各コンテンツは改正された教育課程を反映した他教科との連携により、様々な問題に遭遇しても解決できるように設計されました。子どもたちがコンピューター的思考力を備えた融合型人材になれるよう、今すぐ適用してください!", "sw_use": "すべての教材は、非営利目的に限り著作者を明らかにして自由に利用できます。", "title": "タイトル", "writer": "作成者", "view": "見る", "date": "登録日", "find_id_pwd": "IDとパスワードを忘れた場合", "send_email": "メールアドレスにパスワード変更のためのリンクを送信いたしました。", "user_not_exist": "存在しないメールアドレスです。", "not_signup": "まだ会員ではありませんか?", "send": "送信する", "sensorboard": "ENTRY Sensor Board", "physical_computing": "フィジカルコンピューティング", "sensorboard_contents": "Using Arduino no longer requires building a circuit using lots of wires. With ENTRY Board, you can use LED lights, temperature, sound, light sensors, a slider, and switches by simply mounting it onto an Arduino board. Now anyone can easily create their own unique projects using ENTRY Board!", "entrybot_boardgame": "エントリーボットボードゲーム", "unplugged": "アンプラグド活動", "unplugged_contents": "楽しいボードゲームでコンピューターの作動原理を学習してみてください。ロボット犬のエントリーボットが停電した工場で必要なパーツを探して脱出できるように手伝う過程で、コンピューター専門家のように問題をとらえることができるようになります。", "entrybot_cardgame": "エントリーボットカードゲーム : 爆弾大騒動", "entrybot_cardgame_contents": "エントリーシティに突如現れた12種類の爆弾! 全ての爆弾を無事に解体することはできるでしょうか? 爆弾を1つずつ解体し、エントリーブロックと一緒にソフトウェアの原理を学んでみましょう! 順次、反復、条件を通して爆弾を1つずつ解体していけば、エントリーシティを救ったヒーローになれますよ!", "basic_learn": "エントリー基本学習", "basic_learn_contents": "エントリーを活用したバラエティ豊かな教育コンテンツを提供しています。", "troubleshooting": "問題解決学習", "playsoftware": "ソフトウェア、遊ぼう", "make_own_lesson": "自分だけの授業を作成し、他の人と共有できます。", "group_lecture": "クラス講義", "group_curriculum": "クラス講義集", "group_homework": "クラス課題", "group_noproject": "展示された作品がありません。", "group_nolecture": "作成された講義がありません。", "group_nocurriculum": "作成された講義集がありません。", "lecture_contents": "必要な機能のみ選択して、自分だけの授業を作成できます。", "curriculum_contents": "複数の講義を1つの講義集としてまとめ、少しずつ進めて行ける授業を作成することができます。", "grade_info": "学年情報", "difficulty": "難易度", "usage": "使用要素", "learning_concept": "学習概念", "related_subject": "連携教科", "show_more": "もっと見る", "close": "閉じる", "latest": "最新順", "viewCount": "照会数", "viewer": "照会順", "like": "いいね順", "comment": "コメント順", "entire_period": "すべての期間", "today": "今日", "latest_week": "1週間以内", "latest_month": "1か月以内", "latest_three_month": "3か月以内", "current_password": "現在のパスワード", "change_password": "パスワード変更", "incorrect_password": "パスワードが一致しません。", "incorrect_password_login": "IDまたはパスワードが違います。", "suspension_user": "このアカウントは利用を停止されています。", "blocked_user": "承認されていないユーザーです。", "new_password": "新しいパスワード", "password_option_1": "英数字を5文字以上組み合わせる必要があります。", "again_new_password": "新しいパスワード再入力", "enter_new_pwd": "新しいパスワードを入力してください。", "confirm_new_pwd": "新しいパスワードを確認してください。", "enter_new_pwd_again": "新しいパスワードを再入力してください。", "password_match": "パスワードが一致しません。", "incorrect_email": "このメールアドレスは無効です。", "edit_button": "情報修正", "edit_profile": "管理", "my_project": "自分の作品", "my_group": "自分のクラス", "mark": "関心作品", "prev_state": "前", "profile_image": "自己紹介画像", "insert_profile_image": "プロフィール画像を登録してください。", "at_least_180": "180×180pxの画像を推奨します。", "upload_image": "画像アップロード", "about_me": "自己紹介", "save_change": "変更内容を保存", "basic_image": "デフォルト画像", "profile_condition": "自己紹介を入力してください。50文字前後", "profile_back": "戻る", "make_project": "作品を作る", "exhibit_project": "作品を展示する", "art_list_shared": "個人", "art_list_group_shared": "クラス", "gl_mode_boost": "ブーストモード", "gl_not_supported": "ブーストモードで実行できない環境です。\n確認をクリックすると基本モードで実行されます。", "view_project": "コードを見る", "code_view": "コード詳細", "noResult": "検索結果がありません。", "comment_view": "コメント", "upload_project": "コメントする", "edit": "修正", "save_complete": "保存", "just_like": "いいね!", "share": "共有", "who_likes_project": "作品にいいね!した人", "people_interest": "作品を関心に登録した人", "none_person": "なし", "inserted_date": "登録日", "last_modified": "Last Modified", "original_project": "オリジナル作品", "for_someone": "さんの", "original_project_deleted": "オリジナル作品が削除されました。", "delete_project": "削除", "delete_group_project": "リストから削除", "currnet_month_time": "月", "current_day_time": "日", "game": "ゲーム", "animation": "アニメーション", "media_art": "メディアアート", "physical": "フィジカル", "etc": "その他", "connected_contents": "連携コンテンツ", "connected_contents_content": "エントリーと一緒に進められるバラエティ豊かなコンテンツをお楽しみください。初めてソフトウェアを学ぶ人の場合、楽しく簡単なボードゲームから、アドイノのようなフィジカルコンピューティングを活用した自分だけのハイクオリティな創作物を制作することができます。", "basic_mission": "基本ミッション: エントリーボットの迷路ゲーム", "basic_mission_content": "ロボット犬を作る工場で偶然停電が起き、1人で考えることができるようになったエントリーボット! 工場を脱出して自由の身になれるよう、エントリーボットを手伝ってあげてください!", "application_mission": "応用ミッション: エントリーボットの宇宙旅行", "write_article": "投稿する", "write_contest": "Submit", "view_all_articles": "すべての投稿を見る", "view_own_articles": "自分の投稿を見る", "view_qna_articles": "レスのないスレッド一覧", "learning_materials": "教育資料", "download_materials": "教育資料ダウンロード", "download_button": "ダウンロード", "download_all": "すべてダウンロード", "ebs_software_first": "<ソフトウェア、遊ぼう>は、NAVERとEBSが共同制作した教育コンテンツです。ここではエントリーを活用して実際に簡単なプログラムを作成しながらソフトウェアの基礎原理を学ぶことができます。さらに、コンピューター科学に関する先行知識がなくても、動画を通して十分に楽しさと好奇心を感じながら進められるコンテンツが用意されています。", "go_software": "「ソフトウェア、遊ぼう」へ移動", "ebs_context": "EBS動画へ移動", "ebs_context_hello": "EBSへ移動", "category": "カテゴリー", "add_picture": "画像添付", "upload_article": "投稿をコメントする", "list": "リスト", "report": "通報する", "upload": "コメントする", "staff_picks": "スタッフのピックアップ", "popular_picks": "人気作品", "lecture_header_more": "もっと作ってみる", "lecture_header_reset": "初期化", "lecture_header_reset_exec": "初期化する", "lecture_header_save": "保存", "lecture_header_save_content": "学習内容を保存する", "lecture_header_export_project": "自分の作品に保存する", "lecture_header_undo": "取消", "lecture_header_redo": "復元", "lecture_er_bugs": "エラー報告", "lecture_container_tab_object": "オブジェクト", "lecture_container_tab_video": "講義動画", "lecture_container_tab_project": "完成された作品", "lecture_container_tab_help": "ブロックに関するヘルプ", "illigal": "違法な内容または公序良俗に違反する活動", "verbal": "暴言または個人情報を侵害する活動", "commertial": "商業的な目的のある活動", "explicit": "わいせつ物", "other": "その他", "check_one_more": "1つ以上表記してください。", "enter_content": "その他の内容を入力してください。", "report_result": "結果に対する回答をご希望の場合、メールアドレスを入力してください。", "report_success": "通報が正常に処理されました。", "etc_detail": "その他の項目を選択してから入力してください。", "lecture_play": "講義を見る", "list_view_link": "他の講義集を見る", "lecture_intro": "講義紹介を見る", "study_goal": "学習目標", "study_description": "説明", "study_created": "登録日", "study_last_updated": "最終修正日", "study_remove": "削除", "study_group_lecture_remove": "リストから削除", "study_group_curriculum_remove": "リストから削除", "study_edit": "講義集修正", "study_comments": "コメント", "study_comment_post": "コメントする", "study_comment_remove": "削除", "study_comment_edit": "修正", "study_comment_save": "保存", "study_guide_video": "案内映像", "study_basic_project": "基本作品", "study_done_project": "完成作品を選択してください。", "study_usage_element": "使用要素", "study_concept_element": "適用概念", "study_subject_element": "連携教科", "study_computing_element": "コンピューティング要素", "study_element_none": "なし", "study_label_like": "いいね!", "study_label_interest": "関心講義", "study_label_share": "共有", "study_label_like_people": "講座にいいね!した人", "study_label_interest_people": "講座を関心に登録した人", "study_related_lectures": "講義リスト", "study_expand": "すべて見る", "study_collapse": "減らす", "aftercopy": "URLがコピーされました。", "study_remove_curriculum": "講義集を削除しますか?", "content_required": "内容を入力してください", "upload_not_supported_file_msg": "このファイル形式には対応していません。", "study_remove_lecture": "講義を削除しますか?", "lecture_build": "講義を作成する", "lecture_build_step1": "1. 講義を紹介するための情報を入力してください", "lecture_build_step2": "2. 学習に使用される機能のみ選択してください", "lecture_build_step3": "3. 情報がすべて正しく入力されているか確認してください", "lecture_build_choice": "何をアップロードしますか?", "lecture_build_project": "エントリー作品", "lecture_build_video": "講義映像", "lecture_build_grade": "推奨学年", "lecture_build_goals": "学習目標", "lecture_build_add_goal": "ここをクリックして目標を追加", "lecture_build_attach": "ファイル添付", "lecture_build_attach_text": "20MB以内のファイルをアップロードしてください。", "lecture_build_assist": "サブ映像", "lecture_build_youtube_url": "Youtube共有リンクを挿入してください。", "lecture_build_project_done": "完成作品を選択してください。", "lecture_build_scene_text1": "シーン機能をOFFにすると新しいシーンを追加したり", "lecture_build_scene_text2": "削除することができません。", "lecture_build_object_text": "「オブジェクトを追加する」をOFFにすると新しいオブジェクトを追加したり削除することができません。", "lecture_build_blocks_text1": "学習に必要なブロックのみ選択してください。", "lecture_build_blocks_text2": "選択しないブロックは非表示になります。", "lecture_build_basic1": "学習を開始する際に使用したい作品を選択してください。", "lecture_build_basic2": "学習者は選択した作品で学習を進めます。", "lecture_build_help": "このヘルプをもう一度見たい時は押してください。", "lecture_build_help_never": "今後表示しない", "lecture_build_close": "閉じる", "lecture_build_scene": "シーン1", "lecture_build_add_object": "オブジェクトを追加する", "lecture_build_start": "スタート", "lecture_build_tab_code": "ブロック", "lecture_build_tab_shape": "形", "lecture_build_tab_sound": "サウンド", "lecture_build_tab_attribute": "属性", "lecture_build_tab_table": "Table", "lecture_build_block_category": "ブロックカテゴリーを選択してください。", "lecture_build_attr_all": "すべて", "lecture_build_attr_var": "変数", "lecture_build_attr_signal": "信号", "lecture_build_attr_list": "リスト", "lecture_build_attr_func": "関数", "lecture_build_edit": "講義修正", "lecture_build_remove": "削除", "curriculum_build": "講義集を作成する", "curriculum_step1": "1. 講義集を紹介する情報を入力してください。", "curriculum_step2": "2. 講義集を構成する講義を選択してください。", "curriculum_step3": "3. 講義集が正しく構成されているか確認してください。", "curriculum_lecture_upload": "講義をコメントする", "curriculum_lecture_edit": "講義編集", "curriculum_lecture_open": "読み込む", "group_lecture_add": "クラス講義を追加する", "group_curriculum_add": "クラス講義集を追加する", "group_lecture_delete": "削除", "group_curriculum_delete": "削除", "group_select": " ", "group_studentNo": "学籍番号", "group_username": "名前", "group_userId": "ID", "group_tempPassword": "パスワード修正", "group_gender": "性別", "group_studentCode": "コード", "group_viewWorks": "作品を見る", "added_group_lecture": "講義が削除されました。", "added_group_curriculum": "講義集が削除されました。", "deleted_group_lecture": "講義が削除されました。", "deleted_group_curriculum": "講義集が削除されました。", "modal_my": "自分の", "modal_interest": "関心", "modal_project": "作品", "section": "Chapter", "connect_hw": "ハードウェア結合", "connect_message": "%1に結合されました。", "connect_fail": "ハードウェアの結合に失敗しました。結合プログラムがONになっているか確認してください。", "interest_curriculum": "関心講義集", "marked_curriculum": "関心講義集", "searchword_required": "キーワードを入力してください。", "file_required": "ファイルは必須入力項目です。", "file_name_error": "正しいファイル名を入力してください。", "file_upload_max_count": "1回につき、合計10件までアップロードできます。", "image_file_only": "画像ファイルのみ登録できます。", "file_upload_max_size": "10MB以下のみアップロードできます。", "curriculum_modal_lectures": "自分の講義", "curriculum_modal_interest": "関心講義", "group_curriculum_modal_curriculums": "自分の講義集", "group_curriculum_modal_interest": "関心講義集", "picture_import": "模様インポート", "picture_select": "模様選択", "lecture_list_view": "他の講義を見る", "play_software_2": "EBS「ソフトウェア、遊ぼう2」", "play_software_2_content": "NAVERとEBSが共同制作した新たなストーリー、<ソフトウェア、遊ぼう>シーズン2をお楽しみください! 楽しい動画講義を通してソフトウェアの基本概念を学び、バラエティ豊かで興味深いテーマに沿って実生活の問題を解決することができます。放送映像と特別映像を見ながら楽しいプログラムを直接制作してみてください。ソフトウェア教育に初めてチャレンジする場合でも、簡単にソフトウェアと親しくなれますよ!", "open_project_to_all": "公開", "close_project": "非公開", "category_media_art": "メディアアート", "go_further": "さらに進む", "marked_project": "関心作品", "marked_group_project": "クラスの関心作品", "basic": "基本", "application": "応用", "the_great_escape": "脱出冒険記", "escape_guide_1": "ロボット犬を作る工場で偶然停電が起き、1人で考えることができるようになったエントリーボット! ", "escape_guide_1_2": " 工場を脱出して自由の身になれるようエントリーボットを手伝ってあげてください!", "escape_guide_2": "エントリーボットが遠くまで行くには、修理しないといけない部分がたくさんあるよ。工場を脱出しながら体を修理するために必要なパーツを探してみよう! まだ体は完全じゃないけど、歩いたり走りながら方向を変えるぐらいはできるからね!", "escape_guide_2_2": "学習目標: 順次的実行", "escape_guide_3": "やっと工場から脱出したよ! だけど、村まではまだ遠いんだ。でも、体はある程度修理できてるから、同じことを繰り返しても壊れないはずだよ! ん? あのロボットは何だろ?", "escape_guide_3_2": "学習目標: 反復文と条件文", "escape_guide_4": "とうとう村の近くまで来たよ! さっきから同じことを何度も繰り返してたから、もう覚えちゃいそうだよ! これからは使うブロックを覚えておいて使うのがよさそうだね。ここでバッテリーさえ充電しておけば、これからはずっと自由に生きられるはずだよ。", "escape_guide_4_2": "学習目標: 関数定義と呼び出し", "space_travel_log": "宇宙旅行記", "space_guide_1": "はるか遠い宇宙を探査するために旅立ったエントリーボット。ついに探査任務を終え故郷の星の地球に戻ろうとしているが、たくさんの石が地球に向かう道をふさいでいる! エントリーボットが無事に地球に戻れるように手伝ってあげてください!", "space_guide_2": "そろそろ地球に戻る時間だよ! 早く地球に帰って休みたいなあ! 前にある石がどうなっているのか確認して、どこに行けばいいのか教えてね! そしたら、僕は教えてくれた方向に動くからね!", "space_guide_2_2": "学習目標: 条件文重複と論理演算", "cfest_mission": "エントリー体験ミッション", "maze_1_intro": "やあ、僕はエントリーボットだよ。ケガをした友達を救助したいんだけど、君の助けが必要なんだ。僕をサポートして友達を救助してほしい! まず、前に進むブロックを組み立ててからスタートを押してね", "maze_1_title": "はじめ方", "maze_1_content": "エントリーボットはどうすれば動きますか?", "maze_1_detail": "1. ブロックリストからブロックを取り出して、「スタートをクリックしたとき」ブロックと繋げてみてね
2. 全部組み立てたら、スタートを押してみて
3. 僕は君が組み立てたブロックどおりに上から順番に動くからね", "maze_2_intro": "おかげで最初の友達を無事に助けることができたよ! じゃあ、次の友達を助けてみようか? あっ! 前に蜂の巣があるよ! ジャンプするブロックを使って蜂の巣を避けて友達を助けよう。", "maze_2_title_1": "障害物をジャンプする", "maze_2_content_1": "障害物がある時はどうすればいいですか?", "maze_2_detail_1": "道の途中では障害物に遭遇することがあるよ。
障害物が前にある時は、ジャンプするブロックを使う必要があるからね。", "maze_2_title_2": "はじめ方", "maze_2_content_2": "エントリーボットはどうすれば動きますか?", "maze_2_detail_2": "1. ブロックリストからブロックを取り出して、「スタートをクリックした時」ブロックと繋げてみてね
2. 全部組み立てたら、スタートを押してみて
3. 僕は君が組み立てたブロックどおりに上から順番に動くからね", "maze_3_intro": "すごいね! 今から他の友達を助けに行こう~。今度はさっき助けた友達がくれたリピートブロックを使ってみようか? 「繰り返す」を使うと、同じ動作を簡単に繰り返すことができるよ! とりあえず繰り返す数字を変えてみる?", "maze_3_title": "リピートブロック(1)", "maze_3_content": "(3)「~回繰り返す」ブロックはどうやって使いますか?", "maze_3_detail": "同じ行動を何度か繰り返すには、「~回繰り返す」ブロックを使えばいいよ。
繰り返したいブロックを「~回繰り返す」の中に入れて反復回数を入力すればOKだよ", "maze_4_intro": "やったね! もう助けなくちゃいけない友達ロボットも少なくなってきたよ。蜂の巣に触れないように「ジャンプする」を繰り返しながら友達のところに行けるようにしてね!", "maze_4_title": "リピートブロック(1)", "maze_4_content": "(3)「~回繰り返す」ブロックはどうやって使いますか?", "maze_4_detail": "同じ行動を何度か繰り返すには、「~回繰り返す」ブロックを使えばいいよ。
繰り返したいブロックを「~回繰り返す」の中に入れて反復回数を入力すればOKだよ", "maze_5_intro": "すごいね! 今からはリピートブロックともしブロックを一緒に使ってみよう~。もしブロックを使うと、前に壁がある時に壁のない方向に回転できるよ。じゃあ、友達を助けに出発しようか?", "maze_5_title_1": "もしブロック", "maze_5_content_1": "もし~ならブロックはどのように動作しますか?", "maze_5_detail_1": "「もし前に{画像}があるなら」ブロックを使うと、前に{画像}がある時にどんな行動をするのか決めることができるよ。
前に{画像}がある時だけブロックの中のブロックを実行して、
そうでない時は実行しないようになるんだ。", "maze_5_title_2": "リピートブロック(2)", "maze_5_content_2": "「~に会うまで繰り返す」ブロックはどうやって使いますか?", "maze_5_detail_2": "「~まで繰り返す」を使うと、同じ行動をいつまで繰り返すかを決められるよ。
繰り返したいブロックを「~まで繰り返す」の中に入れればOKだよ。
すると、{画像}みたいにタイルの上にいる場合、繰り返しがストップするからね。", "maze_6_intro": "もう最後の友達だよ! さっきやったみたいにやれば、うまくいくはず! じゃあ、最後の友達を助けに行こうか?", "maze_6_title_1": "もしブロック", "maze_6_content_1": "もし~ならブロックはどのように動作しますか?", "maze_6_detail_1": "「もし前に{画像}があるなら」ブロックを使うと、前に{画像}がある時にどんな行動をするのか決めることができるよ。
前に{画像}がある時だけブロックの中のブロックを実行して、
そうでない時は実行しないようになるんだ。", "maze_6_title_2": "リピートブロック(2)", "maze_6_content_2": "「~に会うまで繰り返す」ブロックはどうやって使いますか?", "maze_6_detail_2": "「~まで繰り返す」を使うと、同じ行動をいつまで繰り返すかを決められるよ。
繰り返したいブロックを「~まで繰り返す」の中に入れればOKだよ。
すると、{画像}みたいにタイルの上にいる場合、繰り返しがストップするからね。", "maze_programing_mode_0": "ブロックコーディング", "maze_programing_mode_1": "JavaScript", "maze_operation1_title": "ステップ1 – JavaScriptモードについて", "maze_operation1_1_desc": "僕はロボット犬のエントリーボットだよ。僕にコマンドしてミッションを解決できるように手伝ってね! ミッションは開始するたびに\'目標\'から確認できるよ!", "maze_operation1_2_desc": "ミッションを確認したら、コマンドをする必要があるよ \'コマンドリスト\'は、コマンドがあるスペースだよ。マウスキーボードコマンドできるよ。マウスではコマンドリストにあるコマンドをクリックしたり、コマンド\'コマンド組立所\'に引きずって、僕にコマンドできるよ!", "maze_operation1_2_textset_1": "マウスでコマンドをクリックする方法", "maze_operation1_2_textset_2": "マウスでコマンドをドラッグ&ドロップする方法", "maze_operation1_3_desc": "キーボードでコマンドするには、\'コマンドリスト\'にあるコマンドをキーボードで直接入力すればOKだよ。
コマンドを入力する時、コマンドの最後にある()と;を忘れないように注意してね!", "maze_operation1_4_desc": "ミッションを解決するためのコマンドを全部入力したら、[スタート]を押せばOKだよ。
[スタート]を押すと、僕はコマンドどおりに動くからね!
それぞれのコマンドを知りたいなら、[コマンドヘルプ]を確認してみてね!", "maze_operation7_title": "7段階 - リピートコマンドについて(回数反復)", "maze_operation7_1_desc": "同じことを繰り返すのは本当に面倒くさいよね。
そんな時は反復に関するコマンドを使えばもっと簡単にコマンドできるよ。", "maze_operation7_2_desc": "では、繰り返されるコマンドを簡単に行う方法を見てみよう。
まず、リピートコマンドをクリックしてからi<1の数字を変えて反復回数を決めてから
括弧({ })の間にリピートコマンドを挿入すればOKだよ!", "maze_operation7_3_desc": "例えば、このコマンドはmove(); を10回繰り返して実行するんだ。
コマンドと同じコマンドだよ。", "maze_operation7_4_desc": "このコマンドを使う時は{ }の中にリピートコマンドがきちんと入力されているか、
`;`が抜けてないかをちゃんと確認してね!
このコマンドに関する詳しい説明は[コマンドヘルプ]で確認できるよ。", "maze_operation7_1_textset_1": "同じコマンドを繰り返して使用する場合", "maze_operation7_1_textset_2": "リピートコマンドを使用する場合", "maze_operation7_2_textset_1": "反復回数", "maze_operation7_2_textset_2": "リピートコマンド", "maze_operation7_4_textset_1": "括弧({})がない場合", "maze_operation7_4_textset_2": "セミコロン(;)がない場合", "study_maze_operation8_title": "ステップ8 - リピートコマンドについて(回数繰り返し)", "study_maze_operation16_title": "ステップ4 - リピートコマンドについて(条件繰り返し)", "study_maze_operation1_title": "ステップ1 - リピートコマンドについて(回数繰り返し)", "maze_operation9_title": "ステップ9 - リピートコマンドについて(条件繰り返し)", "maze_operation9_1_desc": "前回は回数分繰り返すリピートコマンドについて学んだね。
今度は続けて繰り返すコマンドを見てみよう。
このコマンドを使うとミッションが終了するまで同じ行動を続けて繰り返すようになるよ。
このコマンドも同じように括弧({ })の間にリピートコマンドを入れて使えるよ!", "maze_operation9_2_desc": "例えば、このコマンドはミッションを完了する時まで繰り返してmove(); right()を実行するんだ。
コマンドと同じコマンドだよ。", "maze_operation9_3_desc": "このコマンドを使用する時も{ }の中にリピートコマンドがきちんと入力されているか、
`true`が抜けてないかをきちんと確認してね!
このコマンドに関する詳しい説明は[コマンドヘルプ]で確認できるよ。", "maze_operation9_1_textset_1": "リピートコマンド", "maze_operation9_3_textset_1": "括弧({})がない場合", "maze_operation9_3_textset_2": "セミコロン(;)がない場合", "maze_operation9_3_textset_3": "trueがない場合", "study_maze_operation3_title": "ステップ3 - リピートコマンドについて(条件繰り返し)", "study_maze_operation4_title": "ステップ4 - 条件コマンドについて", "study_ai_operation4_title": "ステップ4 - 条件コマンドとレーダーについて", "study_ai_operation6_title": "ステップ6 - 重複条件文について", "study_ai_operation7_title": "ステップ7 - 様々な比較演算について", "study_ai_operation8_title": "ステップ8 - 物体レーダーについて", "study_ai_operation9_title": "ステップ9 - アイテムを使用する", "maze_operation10_title": "ステップ10 - 条件コマンドについて", "maze_operation10_1_desc": "前回はミッションが終了するまで続けて繰り返すリピートコマンドについて学んだよね。
今度は特定の条件でのみ行動する条件コマンドを見てみよう。
で見たように、条件コマンドを使うとより効率的にコマンドすることができるよ。", "maze_operation10_2_desc": "条件コマンドは大きく「条件」「条件が発生した時に実行されるコマンド」に分かれるんだ。
まず、条件部分を見てみよう。Ifの次に出てくる( )部分が条件を入力する部分だよ。
と同じコマンドを例として見てみよう。if(front == \“wall\”)は、もし自分の前に(front) \"wall(壁)\"があるならを意味するよ", "maze_operation10_3_desc": "今から`条件が発生した時に実行されるコマンド`を見てみよう。
この部分は括弧{}でくくられていて、条件が発生した時に括弧内のコマンドを実行するようになるよ!
条件が発生しなかった場合、この部分は無視して実行しないんだ。
のコマンドを例として見てみよう。条件はもし「自分の前に壁があるとき」で、
この条件が発生した時、僕は括弧内のコマンドright();のように右側に回転するよ!", "maze_operation10_4_desc": "条件コマンドは、リピートコマンドと一緒に使われる時が多いよ。
前にまっすぐ進み続け、壁が出てきた時にだけ回転したいなら、
順序のようにコマンドできるよ!", "maze_operation10_1_textset_1": "[一般コマンド]", "maze_operation10_1_textset_2": "前に2マス進んで
右側に回転し、
前に3マス進んで
右側に回転し、前に…
", "maze_operation10_1_textset_3": "[条件コマンド]", "maze_operation10_1_textset_4": "前に進み続け、
「もし壁が出てきたら」
右側に回転するんだ~!
", "maze_operation10_2_textset_1": "条件", "maze_operation10_2_textset_2": "条件が発生した時に実行されるコマンド", "maze_operation10_3_textset_1": "条件", "maze_operation10_3_textset_2": "条件が発生した時に実行されるコマンド", "maze_operation10_4_textset_1": "ミッションが終了するまで
前に進み続ける。
", "maze_operation10_4_textset_2": "前に進み続け、
もし壁が出てきたら
", "maze_operation10_4_textset_3": "前に進み続け、
もし壁が出てきたら
右に回転する。
", "study_maze_operation18_title": "ステップ6 - 条件コマンドについて", "maze_operation15_title": "ステップ15 - 関数コマンドについて", "maze_operation15_1_desc": "よく使うコマンドを毎回入力するのは本当に面倒くさいよね。
よく使うコマンドをくくって名前を付けて、
必要な時にそのコマンドリストを読み込めばずっと楽にコマンドできるよ!
こんなコマンドリストを`関数`っていうんだ。今から関数コマンドについて詳しく見ていこう。", "maze_operation15_2_desc": "関数コマンドはコマンドをくくる「関数を作成する」過程
くくったコマンドを必要な時に使用する「関数を読み込む」過程があるんだ。
まず、関数を作成する過程を見てみよう。
関数を作るには、関数名とその関数に入るコマンドを入力する必要があるよ。
functionを入力してから関数名を決められるよ。ここではpromiseで作るよ。
関数名を作ったら、()を付けてね。その次に括弧({})を入力してね。
それからこの括弧の中に関数に入るコマンドを入力すれば関数が作られるよ!", "maze_operation15_3_desc": "このコマンドを見てみよう。僕はpromiseという関数を作ったよ。
この関数を呼び出して実行すると、括弧({})の中にある
move();
move();
left();が実行されるんだ!", "maze_operation15_4_desc": "関数を呼び出して実行するには、さっき作った関数の名前を入力して、後に`();`を付ければOKだよ。
promise という名前で関数を作ったから、promise();を入力すると前にくくっておいた
コマンドが実行されるんだ!
のようにコマンドすると、のように動作するようになるよ!
関数コマンドを使用するには、のように関数を作成して関数を読み込む必要があるんだ!", "maze_operation15_1_textset_1": "よく使うコマンドを確認する", "maze_operation15_1_textset_2": "コマンドをくくって名前を付ける", "maze_operation15_1_textset_3": "コマンドリストを読み込む", "maze_operation15_2_textset_1": "コマンドリストの名前(関数名)", "maze_operation15_2_textset_2": "くくるコマンド", "maze_operation15_3_textset_1": "コマンドリストの名前(関数名)", "maze_operation15_3_textset_2": "くくるコマンド", "maze_operation15_4_textset_1": "関数を作成する", "maze_operation15_4_textset_2": "関数を読み込む", "maze_operation15_4_textset_3": "実際の状況", "maze_object_title": "オブジェクト情報", "maze_object_parts_box": "パーツボックス", "maze_object_trap": "落とし穴", "maze_object_monster": "モンスター", "maze_object_obstacle1": "障害物", "maze_object_obstacle2": "bee", "maze_object_obstacle3": "banana", "maze_object_friend": "友達", "maze_object_wall1": "wall", "maze_object_wall2": "wall", "maze_object_wall3": "wall", "maze_object_battery": "バッテリー", "maze_command_ex": "例", "maze_command_title": "コマンドヘルプ", "maze_command_move_desc": "エントリーボットを1マス前に移動させます。", "maze_command_jump_desc": "下の画像のような障害物の前で障害物をジャンプします。
", "maze_command_jump_desc_elec": "下の画像のような障害物の前で障害物をジャンプします。
", "maze_command_right_desc": "現在位置から右側に90度回転します。", "maze_command_left_desc": "現在位置から左側に90度回転します。", "maze_command_for_desc": "括弧{}内にあるコマンドを入力した回数だけ繰り返して実行します。", "maze_command_while_desc": "ミッションが終了するまで括弧{}内にあるコマンドを続けて繰り返して実行します。", "maze_command_slow_desc": "下の画像のようなスピードバンプをジャンプします。
", "maze_command_if1_desc": "条件「目の前に壁があるとき」が発生した際、
括弧{}内にあるコマンドを実行します。", "maze_command_if2_desc": "条件「目の前に蜂の巣があるとき」が発生した際、
括弧{}内にあるコマンドを実行します。", "maze_command_if3_desc": "条件「目の前にバナナがあるとき」が発生した際、
括弧{}内にあるコマンドを実行します。", "maze_command_promise_desc": "promise という関数を作成して実行すると、括弧{}内に
あったコマンドを実行します。", "perfect": "わぁ、完璧だよ! ", "succeeded_using_blocks": " 個のブロックを使用して成功したよ!", "succeeded_using_commands": " のコマンドを使用して成功したよ!", "awesome": "すごいね!", "succeeded_go_to_next": "個のブロックだけで成功したよ!
次のステップに行こう。", "good": "よし! ", "but": "
けどね、", "try_again": " 個のブロックだけで成功させる方法もあるよ。
もう一度チャレンジしてみない?", "try_again_commands": " のコマンドだけで成功する方法もあるよ。
もう一度チャレンジしてみない?", "cfest_success": "すごいね! おかげで友達を助けることができたよ!
おそらく君は優れたプログラマーなんだね!
また後で会おう~!", "succeeded_and_cert": "個のブロックだけで成功したよ!
証明書をもらいに行こう。", "cause_msgs_1": "うわっ、前に進めない場所だったよ。やり直そう。", "cause_msgs_2": "うわーん。ただの道にはジャンプする場所がないよ。やり直そう。", "cause_msgs_3": "あいたたた、痛い。ジャンプしなくちゃいけない場所だったよ。やり直そう。", "cause_msgs_4": "残念だけど、今回のステップでは絶対に下のブロックを使わなくちゃいけないんだ。
やり直してみる?", "cause_msgs_5": "大変だ、実行するブロックが全部なくなっちゃったよ。やり直そう。", "cause_msgs_6": "大変だ、実行するコマンドが全部なくなっちゃったよ。やり直そう。", "close_experience": "体験
終了", "replay": "やり直す", "go_to_next_level": "次の段階へ", "move_forward": "前に1マス移動", "turn_left": "左側", "turn_right": "右側", "turn_en": " ", "turn_ko": "に回転", "jump_over": "ジャンプする", "when_start_is_pressed": "スタートをクリックしたとき", "repeat_until_ko": "出会うまで繰り返す", "repeat_until_en": " ", "repeat_until": "出会うまで繰り返す", "if_there_is_1": "もし前に", "if_there_is_2": "あるなら", "used_blocks": "使用ブロック", "maximum": "目標ブロック", "used_command": "使用コマンド数", "maximum_command": "目標コマンド数", "block_box": "ブロックリスト", "block_assembly": "ブロック組立所", "command_box": "コマンドリスト", "command_assembly": "コマンド組立所", "start": "スタート", "engine_running": "実行中", "engine_replay": "戻る", "goto_show": "見に行く", "make_together": "共に制作するエントリー", "make_together_content": "エントリーは学校の先生方と学生たちが一緒に考えながら作成していきます。", "project_nobody_like": "この作品が気に入ったら、「いいね!」を押してください。", "project_nobody_interest": "「関心作品」を押すと、マイページで閲覧することができます。", "lecture_nobody_like": "この講義が気に入ったら、「いいね!」を押してください。", "lecture_nobody_interest": "「関心講義」を押すと、マイページで閲覧することができます。", "course_nobody_like": "この講義集が気に入ったら、「いいね」を押してください。", "course_nobody_interest": "「関心講義集」を押すと、マイページで閲覧することができます。", "before_changed": "変更前", "after_changed": "変更後", "from_changed": "(2016年4月17日より ) ", "essential": "必須", "access_term_title": "こんにちは。エントリー教育研究所です。 
エントリーをご愛顧いただいている皆様に御礼申し上げます。
エントリー教育研究所ウェブサイトの利用規約が
2016年4月17日付で以下のように改定されましたのでご報告いたします。 ", "member_info": "会員案内", "personal_info": "個人情報の取り扱いに同意します。", "option": "選択", "news": "最新情報", "edu_material": "教育資料", "latest_news": "最近のニュース", "edu_data": "教育資料", "training_program": "研修支援", "footer_phrase": "エントリーは、誰でも無料でソフトウェア教育を受けられるように開発された非営利教育プラットフォームです。", "footer_use_free": "エントリー教育研究所のすべての著作物は、教育的目的に限り出処を明らかにして自由に利用できます。", "footer_description_1": "エントリーは非営利教育プラットフォームであり、エントリー内の著作物はすべて教育的目的に限り出処を明らかにして自由に利用できます。", "footer_description_2": " ", "nonprofit_platform": "非営利教育プラットフォーム", "this_is": "です。", "privacy": "プライバシーポリシー", "entry_addr": "京畿道 城南市 盆唐區 佛亭路 6 NAVER グリーンファクトリー16階", "entry_addr_additional_phone": "02-6202-9783", "entry_addr_additional_email": "entry@connect.or.kr", "entry_addr_additional_opensource": "Open Source License", "phone": "電話番号", "alert_agree_term": "利用規約に同意してください。", "alert_private_policy": "個人情報の取り扱い規約に同意してください。", "agree": "同意", "optional": "選択", "start_software": "ソフトウェア教育の第一歩", "analyze_procedure": "手順", "analyze_repeat": "反復", "analyze_condition": "分岐", "analyze_interaction": "相互作用", "analyze_dataRepresentation": "データ表現", "analyze_abstraction": "抽象化", "analyze_sync": "並列及び同期化", "jr_intro_1": "やあ! 僕はジュニだよ! 僕の友達のエントリーボットが右にいるんだ! 僕を友達のところに連れて行ってね!", "jr_intro_2": "エントリーボットが左にいるよ! 左に行ってみよう。", "jr_intro_3": "エントリーボットが上にいるよ! 友達に会えるように手伝って!", "jr_intro_4": "早くエントリーボットに会いに行こう! 下の方向に行ってね~ ", "jr_intro_5": "わっ! 友達が遠く離れたところにいるよ。エントリーボットがいる場所まで案内してもらえるかな? ", "jr_intro_6": "あそこにエントリーボットがいるね。早く会いに行こう。", "jr_intro_7": "きれいな花があるね。花を集めてエントリーボットのところに行こう!", "jr_intro_8": "途中に花があるね! 花を集めてエントリーボットのところに行こう!", "jr_intro_9": "エントリーボットが遠いところにいるね。一番早いルートでエントリーボットのところに行こう。", "jr_intro_10": "エントリーボットに会いに行く途中、花を全部集めながら行こう。", "jr_intro_11": "エントリーボットのところに行くには、右に5回も行かなきゃいけないよね? リピートブロックを使ってもっと簡単に行ってみよう。", "jr_intro_12": "「繰り返す」を使ってエントリーボットに会いに行こう。", "jr_intro_13": "今のブロックだと友達のところには行けないよ。繰り返す回数を変えてエントリーボットのところに行けるようにしてね。", "jr_intro_14": "リピートブロックを使ってエントリーボットのところに連れて行ってね。", "jr_intro_15": "エントリーボットがとても遠くにいるよね? でも、リピートブロックを使えば簡単にエントリーボットのところに行けるはずだよ。", "jr_whats_ur_name": "証明書に記入する、きみのお名前は?", "jr_down_cert": "証明書を受け取る", "jr_popup_prefix_1": "よし! エントリーボットに会えたよ!", "jr_popup_prefix_2": "わっ! エントリーボットに会えたよ!
でもね、もっと少ないブロックを使ってもエントリーボットに
会えるんだけど、もう一度やってみる? ", "jr_popup_prefix_3": "やった! カバンを準備したよ!", "jr_popup_prefix_4": "わっ! カバンのある場所に来たよ! でもね、もっと少ないブロックを使ってもカバンの方に行けるんだけど、もう一度やってみる?", "jr_popup_suffix_1": "ありがとう~。おかげでカバンを持って学校に行けたよ~。次に学校に行くときも一緒に行こうね~", "jr_popup_suffix": "ありがとう~。おかげでエントリーボットと楽しく遊べたよ~。
次またエントリーボットと遊ぼうね~", "jr_fail_dont_go": "わわっ、そこには行けないよ。行く道をもう一度教えて~", "jr_fail_dont_know": "ん? 今からどこに行くの? どこに行くのかもっと教えて~", "jr_fail_no_flower": "ここには花はないよ。花のある場所で使ってみよう~", "jr_fail_forgot_flower": "あっ! エントリーボットにあげる花を忘れちゃったよ。花を集めてから行こう~", "jr_fail_need_repeat": "リピートブロックがないよ! リピートブロックを使ってみよう~", "jr_hint_1": "やあ! 僕はジュニだよ! 僕の友達のエントリーボットが右にいるんだ! 僕を友達のところに連れて行ってね!", "jr_hint_2": "エントリーボットが左にいるよ! 左に行ってみよう。", "jr_hint_3": "エントリーボットが上にいるよ! 友達に会えるように手伝って!", "jr_hint_4": "早くエントリーボットに会いに行こう! 下の方向に行ってね~", "jr_hint_5": "わっ! 友達が遠く離れたところにいるよ。エントリーボットがいる場所まで案内してもらえるかな?", "jr_hint_6": "間違ったブロックのせいで友達に会いに行けないよ! 間違ったブロックを消してエントリーボットのところに行けるように手伝って!", "jr_hint_7": "きれいな花があるね。花を集めてエントリーボットのところに行こう!", "jr_hint_8": "途中に花があるね! 花を集めてエントリーボットのところに行こう!", "jr_hint_9": "エントリーボットが遠いところにいるね。一番早いルートでエントリーボットのところに行こう。", "jr_hint_10": "あっ、ブロックを間違って組み立てちゃったからうまく行けないね。途中で花を全部集めてエントリーボットに持っていけるように直してみよう。", "jr_hint_11": "エントリーボットのところに行くには、右に5回も行かなきゃいけないよね? リピートブロックを使ってもっと簡単に行ってみよう。", "jr_hint_12": "「繰り返す」を使ってエントリーボットに会いに行こう。", "jr_hint_13": "今のブロックだと友達のところには行けないよ。反復回数を変えてエントリーボットのところに行けるようにしてね。", "jr_hint_14": "リピートブロックを使ってエントリーボットのところに連れて行ってね。", "jr_hint_15": "エントリーボットがすごく遠くにいるよね? でも、リピートブロックを使えば簡単にエントリーボットのところに行けるはずだよ。", "jr_certification": "証明書", "jr_congrat": "おめでとうございます!", "jr_congrat_msg": "問題解決課程を無事修了しました。", "jr_share": "共有", "go_see_friends": "友達に会いに行きましょう~!", "junior_naver": "JUNIOR NAVER", "junior_naver_contents_1": "のオシャレなクマの「ジュニ」がエントリーに遊びにきました! ", "junior_naver_contents_2": "ですが、ジュニは道を探すのがまだ難しいみたいです。", "junior_naver_contents_3": "ジュニがエントリーボットに会えるように進む方向を教えてください~", "basic_content": "基礎", "jr_help": "ヘルプ", "help": "ヘルプ", "cparty_robot_intro_1": "やあ、僕はエントリーボットだよ。僕はパーツを手に入れて体を直さなくちゃいけないんだ。前に進むブロックでパーツを手に入れられるように手伝ってくれ!", "cparty_robot_intro_2": "よし! 前にもパーツがあるけど、今度は間違って行ってしまうと感電しちゃうみたいだね。ジャンプするブロックを使ってパーツのところまで連れて行ってくれ。", "cparty_robot_intro_3": "すごい! あそこにもパーツがあるよ! 道はちょっと曲がりくねってるけど、回転するブロックを使えば十分行けるはず! ", "cparty_robot_intro_4": "よし、もう動くのはだいぶ楽になったよ! 今度は回転とジャンプを一緒に使ってあのパーツを手に入れよう! ", "cparty_robot_intro_5": "おかげで体がすごくよくなったよ! 今度は回転とジャンプを一緒に使う必要があるよ! さあ、行ってみよう!", "cparty_robot_intro_6": "すごいね! もうかなり体がよくなったから、同じことを何回やっても大丈夫なはず! 一度繰り返すを使って進んでみよう!", "cparty_robot_intro_7": "ん? 行く途中にジャンプしなくちゃいけない場所があるね! でも、繰り返すで十分に行けるはずだよ!", "cparty_robot_intro_8": "そんな! 今度はパーツがずっと遠くにあるよ。でも、繰り返すを使えば簡単に行けるんだ! 早く手伝って!", "cparty_robot_intro_9": "わあ~、体はもうほとんど直ったみたいだよ! 今度は繰り返すを利用してパーツを手に入れに行こう!", "cparty_robot_intro_10": "すごいよ! もう最後のパーツさえあれば僕の体を完璧に直すことができるはず! 早く、繰り返すで手伝って!", "cparty_car_intro_1": "やあ! 僕はエントリーボットだよ。車に乗って移動し続けるには燃料が必要なんだ! 前にある燃料を手に入れられるように手伝ってくれないかな?", "cparty_car_intro_2": "よし! だけど、今度は道がまっすぐじゃないね! 左/右に回転するブロックでうまく運転して、一緒に燃料を手に入れに行こうか?", "cparty_car_intro_3": "うまいね! 今度の道の前にはスピードバンプがあるよ。スピードを出して運転すると事故が起こるかもしれないから、ゆっくり進むブロックを使って燃料を手に入れに行こう!", "cparty_car_intro_4": "やっほー、もう運転はだいぶ楽になったよ! この道路ではリピートブロックを使って燃料を補給しに行ってみようか?", "cparty_car_intro_5": "わぁ、今度の道路はちょっと複雑そうだけど、前に進むと左/右に回転するブロックを繰り返しながら行けばOKだよ! 落ち着いて燃料のところまで行ってみよう", "cparty_car_intro_6": "今度は道路に障害物があるから、うまく回らないといけなさそうだね。もし障害物が前にあったらどのようにすればいいか教えてね!", "cparty_car_intro_7": "うん、うまいね! もう一度もしブロックを使って障害物を避けながら燃料を手に入れに行こう!", "cparty_car_intro_8": "あっ、さっき見かけたスピードバンプが2つもあるよ。ゆっくり進むブロックを利用して安全に燃料を補給しに行こう!", "cparty_car_intro_9": "複雑そうな道だけど、前に使ったリピートブロックともしブロックをうまく利用すれば十分運転できるよ。燃料を補給できるように手伝って!", "cparty_car_intro_10": "本当にすごいね! ブロックの順序をうまく並べて、今から最後に残った燃料に向かって頑張って進んで行こう!", "cparty_car_popup_prefix_1": "よし! 燃料を手に入れたよ!", "cparty_car_popup_prefix_2": "わあ! 燃料を手に入れたよ!
でもね、もっと少ないブロックを使っても
燃料を手に入れられるんだけど、もう一度やってみる? ", "cparty_car_popup_prefix_2_text": "わあ! 燃料を手に入れたよ!
でもね、もっと少ないコマンドを使っても
燃料を手に入れられるんだけど、もう一度やってみる? ", "cparty_car_popup_suffix": "ありがとう~。おかげでバッテリーを全部手に入れることができたよ~。
また一緒に遊んでね~", "all_grade": "全学年", "grade_e3_e4": "小学校3 ~ 4年生以上", "grade_e5_e6": "小学校5 ~ 6年生以上", "grade_m1_m3": "中学校1 ~ 3年生以上", "entry_first_step": "エントリーの第一歩", "entry_monthly": "月刊エントリー", "play_sw_2": "EBS ソフトウェア、遊ぼう2", "entry_programming": "実践、プログラミング!", "entry_recommanded_course": "エントリーのオススメコース", "introduce_course": "誰でも簡単に見て真似しながら様々なソフトウェアを楽しく制作できる講義コースを紹介します。", "all_free": "*講義動画、作る、教材などをすべて無料で提供しています。", "cparty_result_fail_1": "わわっ、そこには行けないよ。道をもう一度教えて~", "cparty_result_fail_2": "あいたたた、痛い。ジャンプしなくちゃいけない場所だったよ。やり直そう。", "cparty_result_fail_3": "わあ、大変だ。下のブロックを使わなかったらとっても大変だね! 下のブロックで作り直してね。", "cparty_result_fail_4": "ん? どこに進めばいいの? どこに進めばいいのかもっと教えてよ~", "cparty_result_fail_5": "あっ! スピードバンプでは速度を落とさないといけないよ。ゆっくり進むブロックを使ってみてね~", "cparty_result_success_1": "よし! パーツを手に入れたよ!", "cparty_result_success_2": "わあ! 燃料を手に入れたよ!
でもね、もっと少ないブロックを使っても燃料を手に入れられるんだけど、もう一度やってみる? ", "cparty_result_success_2_text": "わあ! パーツを手に入れたよ!
でもねもっと少ないコマンドを使っても燃料を手に入れられるんだけど、もう一度やってみる? ", "cparty_result_success_3": "ありがとう~。おかげで体が完全に直ったよ~。また一緒に遊んでね~", "cparty_insert_name": "名前を入力してください。", "offline_file": "ファイル", "offline_edit": "編集", "offline_undo": "戻す", "offline_redo": "再実行", "offline_quit": "終了", "select_one": "選択してください。", "evaluate_challenge": "挑戦したミッションの難易度を評価してください。", "very_easy": "とても簡単", "easy": "簡単", "normal": "普通", "difficult": "難しい", "very_difficult": "とても難しい", "save_dismiss": "変更内容を保存していません。続けますか?", "entry_info": "エントリー情報", "actual_size": "実際のサイズ", "zoom_in": "拡大", "zoom_out": "縮小", "cparty_jr_intro_1": "やあ! 僕はエントリーボットだよ! 学校にカバンを持っていけるように手伝って! ", "cparty_jr_intro_2": "カバンが僕の左にあるよ! 左に行ってみよう。", "cparty_jr_intro_3": "カバンが上にあるよ! カバンを持っていけるように手伝ってね!", "cparty_jr_intro_4": "早くカバンを取りに行こう! 下に行くんだよ~", "cparty_jr_intro_5": "わっ! カバンが遠く離れた場所にあるよ。カバンがある場所まで案内してくれないかな?", "cparty_jr_intro_6": "カバンがあるよ! 早く取りに行こう~", "cparty_jr_intro_7": "道の上に鉛筆があるね。鉛筆を集めてカバンを取りに行こう!", "cparty_jr_intro_8": "学校に行く途中に鉛筆があるよ! 鉛筆を集めてカバンを取りに行こう!", "cparty_jr_intro_9": "カバンが遠く離れた場所にあるね。一番早いルートでカバンを取りに行こう。", "cparty_jr_intro_10": "途中にある鉛筆をすべて集めてカバンを持っていこう!", "cparty_jr_intro_11": "カバンを手に入れるには、右に5回も行かなくちゃいけないよね? リピートブロックを使ってもっと簡単に行ってみよう。", "cparty_jr_intro_12": "「繰り返す」を使ってカバンを取りに行こう。", "cparty_jr_intro_13": "今のブロックだと友達のところには行けないよ。反復回数を変えてエントリーボットのところに行けるようにしてね。", "cparty_jr_intro_14": "リピートブロックを使ってカバンを取りに行ってね。", "cparty_jr_intro_15": "学校がとーっても遠くにあるよね? でも、リピートブロックを使うと簡単に学校に到着できるんだ。", "make_new_project": "新しい作品を作る", "open_old_project": "保存された作品を読み込む", "offline_download": "エントリーダウンロード", "offline_release": "エントリーのオフラインエディターリリース!", "offline_description_1": "エントリーのオフラインバージョンは", "offline_description_2": "インターネットに接続されていない状態でも使用できます。", "offline_description_3": "今すぐダウンロードして始めてください!", "sw_week_2015": "2015ソフトウェア教育体験ウィーク", "cparty_desc": "ワクワクするソフトウェアとの初対面", "entry_offline_download": "エントリーオフライン\nダウンロード", "entry_download_detail": "ダウンロード\nへ移動", "offline_desc_1": "インターネットに接続せずに、エントリーを利用することができるオフラインバージョンです。", "offline_desc_2": "今すぐダウンロードして始めてください!", "download": "ダウンロード", "version": "バージョン", "file_size": "サイズ", "update": "アップデート", "use_range": "使用範囲", "offline_desc_free": "エントリーオフラインは、企業と個人の方すべてが制限なく無料でご利用いただけます。", "offline_required": "システム要件", "offline_required_detail": "ハードディスクの空き容量1GB以上、Windows7またはMac OS 10.8以上", "offline_notice": "インストールの前にお読みください", "offline_notice_1": "1. バージョン", "offline_notice_1_1": "ハードウェア接続ソフトが内蔵されています。", "offline_notice_2": "2. ウェブブラウザは別途必要ありません。", "offline_notice_3": "各バージョンの変更内容について", "offline_notice_4": "各バージョンをダウンロード", "offline_notice_5": "各バージョンの変更内容の詳細について", "hardware_online_badge": "オンライン", "hardware_title": "エントリーハードウェア接続ソフトをダウンロード", "hardware_desc": "エントリーオンラインの「作品を作る」でハードウェアを接続してエントリーを利用する場合のみ、別途インストールする必要があります。", "hardware_release": "ハードウェア接続ソフト変更内容の詳細は、次のアドレスで確認できます。", "hardware_window_download": "Windows
ダウンロード", "hardware_osx_download": "Mac
ダウンロード", "cparty_jr_result_2": "ありがとう~。おかげでカバンを持って学校に来ることができたよ~
次に学校に行くときも一緒に行こうね~", "cparty_jr_result_3": "わあ! 学校まで来れたよ!
でももっと少ないブロックを使っても学校に行けるんだけど、
もう一度やってみる?", "cparty_jr_result_4": "わっ! カバンを手に入れたよ!
でももっと少ないブロックを使ってもカバンを手に入れられるんだけど、
もう一度やってみる? ", "lms_no_class": "まだ作成したクラスがありません。", "lms_create_class": "クラスを作成してください", "lms_add_class": "クラス作成", "lms_base_class": "基本", "lms_delete_class": "削除", "lms_my_class": "自分の", "lms_grade_1": "小学校1", "lms_grade_2": "小学校2", "lms_grade_3": "小学校3", "lms_grade_4": "小学校4", "lms_grade_5": "小学校5", "lms_grade_6": "小学校6", "lms_grade_7": "中学校1", "lms_grade_8": "中学校2", "lms_grade_9": "中学校3", "lms_grade_10": "一般", "lms_add_groupId_personal": "先生から受け取ったクラスIDを入力して会員情報に追加してください。", "lms_add_groupId": "クラスIDを追加する", "lms_add_group_account": "クラスアカウント追加", "lms_enter_group_info": "発行されたクラスIDとパスワードを入力してください。", "lms_group_id": "クラスID", "lms_group_pw": "パスワード", "lms_group_name": "所属クラス名", "personal_pwd_alert": "正しいパスワード形式を入力してください", "personal_form_alert": "正しい形式で入力してください", "personal_form_alert_2": "すべての入力フォームを作成してください", "personal_no_pwd_alert": "パスワードを入力してください", "select_gender": "性別を選択してください", "enter_group_id": "クラスIDを入力してください", "enter_group_pwd": "パスワードを入力してください", "info_added": "追加されました", "no_group_id": "クラスIDが存在しません", "no_group_pwd": "パスワードが一致しません", "lms_please_choice": "選択してください。", "group_lesson": "自分のクラス講義", "lms_banner_add_group": "クラス機能導入", "lms_banner_entry_group": "エントリークラスを作成する", "lms_banner_desc_1": "クラスの学生たちをエントリーに登録してください!", "lms_banner_desc_2": "もっと簡単かつ便利にクラスの学生たちの作品を検索し、", "lms_banner_desc_3": "成長する姿を確認できます。", "lms_banner_download_manual": "マニュアルダウンロード", "lms_banner_detail": "詳細", "already_exist_email": "メールアドレスはすでに存在します。", "same_registered_email": "メールアドレスはすでに存在します。", "email_correnctly_please": "メールアドレスを正しく入力してください", "remove_project": "作品を削除しますか?", "study_lesson": "クラスで学習する", "open_project": "作品を読み込む", "make_group": "クラス作成", "project_share": "作品を共有する", "group_project_share": "クラスで共有する", "group_discuss": "クラスに投稿する", "my_profile": "マイページ", "search_updated": "最新作品", "search_recent": "照会数の多い最新作品", "search_complexity": "制作に力を入れた最新作品", "search_staffPicked": "スタッフのピックアップ作品", "search_childCnt": "コピーが多い作品", "search_likeCnt": "いいね!が多い最新作品", "search_recentLikeCnt": "いいね!が多い最新作品", "gnb_share": "共有する", "gnb_community": "コミュニティ", "lms_add_lectures": "講義をコメントする", "lms_add_course": "講義集をコメントする", "lms_add_homework": "課題をコメントする", "remove_lecture_confirm": "講義を本当に削除しますか?", "popup_delete": "削除する", "remove_course_confirm": "講義集を本当に削除しますか?", "lms_no_lecture_teacher_1": "追加された講義がありません。", "lms_no_lecture_teacher_2": "クラス講義を追加してください。", "gnb_download": "ダウンロード", "lms_no_lecture_student_1": "まだアップロードされた講義がありません。", "lms_no_lecture_student_2": "先生が講義をアップロードすると、", "lms_no_lecture_student_3": "学習内容を確認できます。", "lms_no_class_teacher": "まだ作成したクラスがありません。", "lms_no_course_teacher_1": "追加された講義集がありません。", "lms_no_course_teacher_2": "クラス講義集を追加してください。", "lms_no_course_student_1": "まだアップロードされた講義集がありません。", "lms_no_course_student_2": "先生が講義集をアップロードすると、", "lms_no_course_student_3": "学習内容を確認できます。", "lms_no_hw_teacher_1": "追加された課題がありません。", "lms_no_hw_teacher_2": "クラス課題を追加してください。", "lms_no_hw_student_1": "まだアップロードされた課題がありません。", "lms_no_hw_student_2": "先生が課題をアップロードすると、", "lms_no_hw_student_3": "学習内容を確認できます。", "modal_edit": "修正する", "modal_deadline": "締切日設定", "modal_hw_desc": "詳細説明(選択)", "desc_optional": " ", "modal_create_hw": "課題を作成する", "vol": "回目", "hw_title": "課題名", "hw_description": "内容", "deadline": "締切日", "do_homework": "課題をする", "hw_progress": "進行状況", "hw_submit": "提出", "view_list": "名簿を見る", "view_desc": "内容を見る", "do_submit": "提出する", "popup_notice": "通知", "no_selected_hw": "選択された課題がありません。", "hw_delete_confirm": "選択した課題を本当に削除しますか?", "hw_submitter": "課題提出者名簿", "hw_student_desc_1": "*「提出する」を押して提出を完了するまでは何度でも修正できます。", "hw_student_desc_2": "* 提出期限が過ぎると課題を提出できません。", "popup_create_class": "クラス作成", "class_name": "クラス名", "image": "画像", "select_class_image": "クラスの画像を選択してください。", "type_class_description": "クラス紹介を入力", "set_as_primary_group": "基本クラスに指定", "set_primary_group": "指定", "not_primary_group": "指定しない", "type_class_name": "クラス名を入力してください。", "type_class_description_long": "クラス紹介を入力してください。170文字以内", "add_students": "学生を追加する", "invite_students": "学生を招待する", "invite_with_class": "1. クラスコードで招待する", "invite_code_expiration": "コード有効期限", "generate_code_button": "コード再発行", "generate_code_desc": "学生のクラスコード入力方法", "generate_code_desc1": "エントリーのホームページでログインしてください。", "generate_code_desc2": "メニューバーで<自分のクラス>を選択してください。", "generate_code_desc3": "<クラスコードを入力する>を押してクラスコードを入力してください。", "invite_with_url": "2. クラスURLで招待する", "copy_invite_url": "コピーする", "download_as_pdf": "クラスアカウントをPDFでダウンロード", "download_as_excel": "クラスアカウントをExcelでダウンロード", "temp_password": "ワンタイムパスワード発行", "step_name": "名前入力", "step_info": "情報追加/修正", "preview": "プレビュー", "type_name_enter": "クラスに追加する学生の名前を入力してエンターキーを押してください。", "multiple_name_possible": "複数の名前を入力できます。", "id_auto_create": "学籍番号を別途修正しない場合、自動で作成されます。", "student_id_desc_1": "クラスIDは別途入力する必要なく自動で作成されます。", "student_id_desc_2": "ただし、エントリーにすでに会員登録している学生をクラスに追加する場合、学生のエントリーIDを", "student_id_desc_3": "入力してください。その学生は、ログイン後にクラス招待を承認すると追加されます。", "student_number": "学籍番号", "temp_password_desc_1": "ワンタイムパスワードでログインした後、", "temp_password_desc_2": "新規パスワードを再設定できるように案内してください。", "temp_password_desc_3": "*発行されたワンタイムパスワードは一度しか確認できません。", "temp_password_demo": "ログインできない案内用の例示アカウントです。", "temp_works": "作品を見る", "student_delete_confirm": "学生を本当に削除しますか?", "no_student_selected": "選択された学生がいません。", "class_assignment": "クラス課題", "class_list": "クラスリスト", "select_grade": "学年を選択してください。", "add_project": "作品を共有する", "no_project_display": "学生たちが展示している作品がありません。", "plz_display_project": "自分の作品を展示してください。", "refuse_confirm": "クラス招待を本当に拒否しますか?", "select_class": "クラス選択", "group_already_registered": "すでに入っているクラスです。", "my_page_entry": "ENTRY", "my_page_title": "マイページ -", "my_classGroup_title": "私のクラス", "my_classGroup_title_view": "自分のクラスを確認する", "my_space_area": "自分だけのスペース", "mon": "月", "tue": "火", "wed": "水", "thu": "木", "fri": "金", "sat": "土", "sun": "日", "jan": "1月", "feb": "2月", "mar": "3月", "apr": "4月", "may": "5月", "jun": "6月", "jul": "7月", "aug": "8月", "sep": "9月", "oct": "10月", "nov": "11月", "dec": "12月", "plz_select_lecture": "講義を選択してください。", "plz_set_deadline": "締切日を設定してください。", "hide_entry": "エントリーを表示しない", "hide_others": "その他を表示しない", "show_all": "すべて見る", "lecture_description": "先生方が直接作成するエントリーの学習スペースです。講義で作品例を見て作品を制作しながら学んでください。", "curriculum_description": "学習の順番とテーマに沿って複数の講義が集められている学習スペースです。講義集の順番に合わせて少しずつ学んでください。", "linebreak_off_desc_1": "テキストボックスのサイズが文字のサイズを決定します。", "linebreak_off_desc_2": "内容は1行のみ作成できます。", "linebreak_off_desc_3": "新しい文字が追加されると、テキストボックスの左右の長さが長くなります。", "linebreak_on_desc_1": "テキストボックスのサイズが文字を入力できるスペースを決定します。", "linebreak_on_desc_2": "内容を作成する時、エンターキーで改行できます。", "linebreak_on_desc_3": "内容を作成または新しい文字を追加する時、長さがテキストボックスの横幅を超えると自動的に改行されます。", "not_supported_text": "この書体は漢字に対応していません。", "entry_with": "一緒に作るエントリー", "ebs_season_1": "シーズン1を見に行く", "ebs_season_2": "シーズン2を見に行く", "hello_ebs": "ハロー! EBS ソフトウェア", "hello_ebs_desc": "<ハロー! EBSソフトウェア> エントリーバージョンの両方向サービスをお楽しみください! \n <ハロー! EBSソフトウェア>の動画講義を通して\n ソフトウェアコーディングの基本概念を学習した後、両方向コーディングミッションにチャレンジしてください!\n 放送では見られなかった<大.騒.動>友達の\n裏話も見ることができます!", "hello_ebs_sub_1": "EBS中学エントリーバージョンの両方向サービスを", "hello_ebs_sub_2": "お楽しみください! ", "exhibit_4th_title": "4th Anniversary of Entry", "exhibit_4th_subtitle": "Entry Project Contest", "exhibit_4th_desc1": "We hold an Entry Project Contest ", "exhibit_4th_desc2": "to celebrate the 4th anniversary of entry.", "exhibit_4th_desc3": "Show off your great project!", "exhibit_4th_button": "View Details", "visang_edu_entry": "ビサン教育 エントリーを学習する", "cmass_edu_entry": "CMAS エントリーを学習する", "chunjae_edu_entry": "天才教科書 エントリーを学習する", "kumsungemt_edu_entry": "ギムソン出版社 エントリーを学習する", "kumsungMid_edu_entry": "ギムソン出版社 エントリーを学習する", "gilbutEdu_edu_entry": "ギルバート出版社 エントリーを学習する", "miraenCoding_edu_entry": "ミライエン エントリーを学習する", "textbook_help_data": "助力資料", "textbook_teaching_activity": "授業教案&活動誌", "textbook_kyohacksa": "Kyohaksa", "textbook_kumsung": "Kumsung Publishing", "textbook_donga": "Dong-a Publishing", "textbook_chunjae": "Chunjae Education", "textbook_miraen": "Mirae-n", "textbook_visang": "Visang", "partner": "パートナー", "project_term_popup_title": "作品公開に伴うエントリー著作権ポリシーに同意", "project_term_popup_description_1": "作品公開のため", "project_term_popup_description_2": "以下のポリシーを確認してください。", "project_term_popup_description_3": " ", "project_term_popup_description_4": " ", "project_term_agree_1_1": "自分が作った作品及びそのソースコードの公開に同意します。", "project_term_agree_2_1": "他人が自分の作品を利用することを許可します。", "project_term_agree_2_2": "(コピー、配布、公衆送信を含む)", "project_term_agree_3_1": "他人が自分の作品を修正することを許可します。", "project_term_agree_3_2": "(リミックス、変形、2次著作物作成を含む)", "agree_all": "すべて同意", "select_login": "ログイン選択", "select": "選択してください", "with_login": "ログインして", "without_login": "ログインせずに", "start_challenge": "ミッションにチャレンジする", "start_challenge_2": "ミッションにチャレンジする", "if_not_save_not_login": "* ログインせずにミッションに参加すると、進行状況が保存されません。", "if_not_member_yet": "エントリー会員でない場合は?", "join_entry": "エントリー会員登録", "learned_computing": "これまでソフトウェア教育を受けたことがありますか?", "cparty_index_description_1": "ワクワクするソフトウェアとの初対面。", "cparty_index_description_2": "ソフトウェアと楽しく遊んでいるうちにソフトウェアの原理も学べる上、考える力もグンとUP!", "cparty_index_description_3": "エントリーを通してコーディングミッションにチャレンジし、証明書を受け取ってください。", "cparty_index_description_4": "2015 Online Coding Partyは", "cparty_index_description_5": "SW教育体験ウィーク", "cparty_index_description_6": "の一環として、", "cparty_index_description_7": "小学校コンピューティング教師協会", "cparty_index_description_8": "と共同制作されました。", "cparty_index_description_9": "2016 Online Coding Partyは", "cparty_index_description_10": "2017 Online Coding Partyは", "cparty_index_description_11": "「SW教育を準備する先生たちの会」", "congratulation": "おめでとうございます!", "warm_up": "体験", "beginner": "入門", "intermediate": "基本", "advanced": "発展", "applied": "応用", "cert_msg_tail": "課程が無事修了しました。", "cert_msg_head": " ", "maze_text_content_1": "やあ。僕はエントリーボットだよ。いま僕は工場から脱出しなくちゃいけないんだ! 脱出するには先に体を直さなくちゃいけなさそうだ。前にあるパーツを手に入れられるよう手伝ってくれないかな? move()", "maze_text_content_2": "うん、とっても上手だね! おかげで体がだいぶ軽くなったよ! 今度もパーツボックスまで僕を移動させてね。だけど、途中に障害物もあるよ。障害物の前ではjump()", "maze_text_content_3": "すごいよ! あそこにもパーツがあるね! 道はちょっと曲がりくねってるけど、右や左に回転できるright(); left(); コマンドを使えば十分行けるはず! ", "maze_text_content_4": "よし、もう動くのがだいぶ楽になったよ! 今度は今まで学んだコマンドを併せて使ってあのパーツボックスまで行ってみよう!", "maze_text_content_5": "わあ、パーツが2つもあるね! 2つとも手に入れて行こう! そうすれば体を早く直せると思うよ!", "maze_text_content_6": "今度が最後のパーツになるよ! あれさえあれば僕の体を完璧に直すことができるはず! 今回も手伝ってくれるよね?", "maze_text_content_7": "おかげで体がとても良くなったよ! 今から同じことを数回繰り返しても大丈夫なはず。ん? ところで、前にいるあのロボットは何だろ? 手伝ってあげる必要がありそうだよ! 助けてあげよう! for コマンドを使ってあの友達のところに僕を連れて行って!", "maze_text_content_8": "よし! おかげで友達ロボットを助け出せたよ! だけど、前にも助けが必要な友達がいるね。でも、今度は蜂の巣があるから気を付けて蜂の巣に触れないようにジャンプして行こう! できるよね? 今度もforコマンドを使って友達がいる場所まで僕を移動させてね!", "maze_text_content_9": "今度はforコマンドの代わりにミッションが終了するまで同じことを繰り返すようにするwhileコマンドを使ってみて! 僕を友達のところに連れて行けばミッション完了だよ!", "maze_text_content_10": "今度はifコマンドが出てきたね! Ifとwhileコマンドを使って僕がいつ、どの方向に回転するのか教えてね!", "maze_text_content_11": "よし、さっきみたいにやってみようか? いつ左に回転するのか教えてほしいな。", "maze_text_content_12": "今度は途中に蜂の巣(bee)があるね? いつジャンプすればいいのか教えてくれるかな?", "maze_text_content_13": "あちこちに手助けが必要な友達がたくさんいるね! 全員のところに行って助けてあげよう!", "maze_text_content_14": "わあ、今度も手助けが必要な友達がたくさんいるね。まず小さな四角形をターンするようにコマンドを作成して、作ったものを繰り返して友達全員を助けてあげよう。", "maze_text_content_15": "長い間動いていたらもう疲れちゃったよ。よく使うコマンドをfunctionコマンドを使って関数として作成しておいたよ! 関数を使って僕をバッテリーのところまで移動させてね!", "maze_text_content_16": "よし、いいね! じゃあ今度は関数に入るコマンドを挿入して僕をバッテリーのところまで移動させてね!", "maze_text_content_17": "よし、今度は関数を作ってからそれを使ってバッテリーを手に入れるように助けてね! 関数を作る時はjump();をうまく混ぜてね!", "maze_text_content_18": "今度は道が少し複雑だね。でも、いつleft();を使って、いつright();を使えばいいのかさえ教えてくれれば、バッテリーのところまで行けるはずだよ!", "maze_text_content_19": "今度は関数があらかじめ決められているよ! でも関数だけ使ってバッテリーのところに行くのは難しいと思うよ。関数と他のコマンドを混ぜ合わせてバッテリーまで移動させてね!", "maze_text_content_20": "よし! 今まで本当によく頑張ってくれたね。おかげで最後のバッテリーを補充さえすればこれからは充電する必要はなさそうだよ。関数を利用してあのバッテリーを手に入れて、僕が自由の身になれるように手伝って!", "maze_content_1": "やあ! 僕はエントリーボットだよ。いま僕は工場から脱出しようとしてるんだけど、まずは体を直す必要がありそうなんだ。前にあるパーツを手に入れたいんだけど、手伝ってくれないかな? 前に進むブロックを組み立ててからスタートを押してみて。", "maze_content_2": "うん、とっても上手だね! おかげで体がだいぶ軽くなったよ! 前にもパーツがあるけど、今度は道を間違えちゃうと感電しちゃいそうだね。障害物をジャンプするブロックを使ってパーツまで行ってみようか?", "maze_content_3": "すごいよ! あそこにもパーツがあるね! 道はちょっと曲がりくねってるけど、回転するブロックを使えば十分行けるはず! 今度も手伝ってくれるよね?", "maze_content_4": "よし、もう動くのはだいぶ楽になったよ! 今度は回転とジャンプを一緒に使ってあのパーツを手に入れよう! ", "maze_content_5": "わあ、パーツが2つもあるね! 2つとも手に入れて行こう! そうすれば体を早く直せると思うよ!", "maze_content_6": "今度が最後のパーツになるよ! あれさえあれば僕の体を完璧に直すことができるはず! 今回も手伝ってくれるよね?", "maze_content_7": "おかげで体がとても良くなったよ! 今からは同じことを数回繰り返しても大丈夫なはずだよ。ん? だけど、前にいるあのロボットは何だろ? 手伝ってあげる必要がありそうだよ! 助けてあげよう! 早く繰り返す数字を変えて、あの友達のところに僕を連れて行って!", "maze_content_8": "よし! おかげで友達ロボットを助け出せたよ! だけど、前にも手助けが必要な友達がいるね。でも、今度は蜂の巣があるから気を付けて蜂の巣に触れないようにジャンプして行こう! できるよね? じゃあ、さっきやったように繰り返すを使って友達のところに僕を連れて行ってくれるかな?", "maze_content_9": "今度は数字だけ繰り返すのではなく、友達ロボットのところに行く時まで同じことを繰り返すことができるよ! 今回も友達を助けられるよう手伝ってね!", "maze_content_10": "今度はもしブロックというのがあるね! もしブロックを使っていつ、どの方向に回転するのか教えてね!", "maze_content_11": "よし、さっきみたいにやってみようか? いつ左に回転するのか教えてほしいな。", "maze_content_12": "今度は途中に蜂の巣があるね? いつジャンプすればいいのか教えてくれるかな?", "maze_content_13": "あちこちに手助けが必要な友達がたくさんいるね! 全員のところに行って助けてあげよう!", "maze_content_14": "わあ、今回も手伝う必要のある友達がたくさんいるね。まず小さな四角をターンするようにコマンドを作成して、作ったものを繰り返して友達全員を助けてあげよう。", "maze_content_15": "繰り返すを何度も繰り返してたから、よく使うブロックは覚えられそうだよ! 約束ブロックはいま僕が覚えたブロックだよ! ひとまず、ずっと動き回って疲れちゃったから、バッテリーを補充できるように「約束呼び出し」ブロックを使ってバッテリーを補充できるようにしてね!", "maze_content_16": "よし、いいね! じゃあ今度は君がよく使うブロックを僕に教えてね! 約束定義ブロックの中によく使うブロックを入れておけばOKだよ!", "maze_content_17": "よし、今回も約束を利用してバッテリーを手に入れるように助けてくれるよね? 約束にジャンプするをうまく混ぜてね!", "maze_content_18": "今度は道が少し複雑だね。でもいつ左に回って、いつ右に回ればいいかを教えてくれれば充電できそうだよ。", "maze_content_19": "今度は約束があらかじめ決められているよ! だけどすぐに約束を使うのはダメみたいだね。僕が行く道を見て約束を使えばバッテリーを補充できるみたいだけど、手伝ってくれるよね?", "maze_content_20": "よし! 今まで本当によく頑張ってくれたね。おかげで最後のバッテリーを補充さえすればこれからは充電する必要はなさそうだよ。約束を利用してあのバッテリーを手に入れて、自由の身になれるように手伝ってくれるよね?", "maze_content_21": "やあ、僕はエントリーボットだよ。たくさんの友達が僕の助けを必要としてるんだ。繰り返すを利用して友達を助けられるよう連れていってね!", "maze_content_22": "ありがとう! 今度は蜂の巣をジャンプして友達を助けに行けるように手伝って!", "maze_content_23": "よし! 今度は友達ロボットのところに行くまで繰り返すを利用して友達を助けられるよう手伝って!", "maze_content_24": "やあ! 僕はエントリーボットだよ。動きすぎちゃってバッテリーを補充しなくちゃいけないんだ。約束を読み込むを使ってバッテリーを補充できるように手伝って!", "maze_content_25": "いいね! 今度は約束をいくつか読み込んでバッテリーがある場所まで行ってみよう!", "maze_content_26": "よし! 今から約束するブロックを僕に教えてね! 約束するブロックの中によく使われるブロックを入れればOKだよ!", "maze_content_27": "今はあらかじめ約束が決められているよ。だけど、約束を使うには僕が行く方向を見て約束を使う必要があるんだ。手伝ってくれるよね?", "maze_content_28": "ついに最後だよ! 約束を利用して最後のバッテリーを手に入れられるように手伝って!", "ai_content_1": "やあ! 僕はエントリーボットだよ。宇宙探査を終えて地球に戻ろうとしているんだけど、宇宙をさまよう石のせいでなかなか難しいね。僕が無事に家に帰れるように手伝ってくれないかな? 僕の宇宙船には僕の前と上、それと下に何がどれくらいの距離にいるのかを教えてくれるレーダーがあるんだ。君の判断に役立つはずだよ!", "ai_content_2": "ありがとう! おかげで石を簡単に避けられたよ。だけど、今度はもっとたくさんの石があるよね? ブロックを並べて石をあちこちに避けてみよう!", "ai_content_3": "いいね! 無事に石を避けられたよ。でも前を見て! さっきよりずっとたくさんの石があるよ。だけど心配する必要はないんだ。僕にはリピートブロックがあるからね。リピートブロックの中に動くブロックを入れれば目的地に到着するまで動き続けるからね!", "ai_content_4": "すごいね! リピートブロックを使ったらたくさんの石を避けるのがずっと楽になったよ! だけど、こうやっていちいち操るのは疲れるね。僕にはレーダーがあるから、前に何が出てくるか分かるんだ。前に進んでいるときに前に石があったら避けられるようにしてくれるかな?", "ai_content_5": "うまいね! ここまで来れてとっても嬉しいな。今度はレーダーが前にある物体までの距離を話してくれるよ。この機能を使って石を避けてみよう! 石までの距離が遠い時は前に進み続けて、距離が近づくと避けるようにしてくれるかな?", "ai_content_6": "わ~すごいね! レーダーを活用して石をうまく避けているよ! 今度はいくつかのレーダーを使って、石をあちこちに避けながら進めるようにしてくれるかな?", "ai_content_7": "ふ~。地球にだんだん近づいているね! 石を避ける時、できれば安全な道に行きたいな! 石がもっと遠くにある道がもっと安全なんだよね? 上方向レーダーと下方向レーダーを比較してもっと安全な方角に動くようにしてくれるかな?", "ai_content_8": "無事に飛行できてるよ。ん? ところであれは何だろ? あれは僕がとても危険な状況で使える特別なエネルギーだよ! 今度はあのアイテムをすべて集めながら進もう!", "ai_content_9": "すごいよ! 地球までもうすぐだよ。だけど、前を見ると石で道が完全に塞がれてて先に行けないよね? でも心配する必要はないよ。アイテムをゲットして使うと、前にある塞いでいる石をなくすことができるんだ!", "ai_content_10": "とうとうあそこに地球が見えたよ! そ、そんな! 飛んでくる石を前もって見ることができないじゃん! 石がどうやって飛んでくるのか分からなくても今までみたいに動けばうまく避けられるはずだよ! 地球まで行くんだ!", "maze_hints_title_1": "はじめ方", "maze_hints_content_1": "エントリーボットはどうすれば動きますか?", "maze_hints_detail_1": "1. ブロックリストからブロックを取り出して「スタートをクリックしたとき」にブロックを繋げてみてね
2. 全部組み立てたら、スタートを押してみて
3.僕は君が組み立てたブロックどおりに上から順番に動くからね", "maze_hints_title_2": "障害物をジャンプする", "maze_hints_content_2": "障害物がある時はどうすればいいですか?", "maze_hints_detail_2": "道の途中で障害物と遭遇することがあるよ。
障害物が前にある時にはジャンプするブロックを使う必要があるよ。", "maze_hints_title_3": "リピートブロック(1)", "maze_hints_content_3": "(3)回リピートブロックはどうやって使いますか?", "maze_hints_detail_3": "同じ行動を複数回繰り返すには、~回繰り返すブロックを使う必要があるよ。
繰り返したいブロックを~回繰り返すの中に入れて反復回数を入力すればOKだよ。", "maze_hints_title_4": "リピートブロック(2)", "maze_hints_content_4": "「~に会うまで繰り返す」ブロックはどうやって使いますか?", "maze_hints_detail_4": "「~まで繰り返す」を使うと、同じ行動をいつまで繰り返すのか決められるよ。
繰り返したいブロックを~まで繰り返すの中に入れればOKだよ。
そうすれば、{画像}みたいにタイルの上にいる場合、繰り返しがストップするからね。", "maze_hints_title_5": "もしブロック", "maze_hints_content_5": "もし~ならブロックはどのように動作しますか?", "maze_hints_detail_5": "「前に{画像}があるなら」ブロックを使うと、前に{画像}がある時にどんな行動をするのか決めることができるよ。
前に{画像}がある時だけブロックの中のブロックを実行して、
そうでない時は実行しないようになるんだ。", "maze_hints_title_6": "リピートブロック(3)", "maze_hints_content_6": "すべての~に会う時までブロックはどのように動作しますか?", "maze_hints_detail_6": "すべての{タイル}に一度ずつ到着するまでその中にあるブロックを繰り返して実行するよ。
すべての{タイル}に一度ずつ到着すると繰り返しがストップするからね。", "maze_hints_title_7": "特別ヒント", "maze_hints_content_7": "難しすぎます。助けてください。", "maze_hints_detail_7": "僕が行かなくちゃいけない道を詳しく見てみて。小さな四角が4つ見えるよね?
小さな四角を回るブロックを作って、繰り返すを使ってみたらどうかな?", "maze_hints_title_8": "約束", "maze_hints_content_8": "「約束する/約束を読み込む」は何ですか? どうやって使いますか?", "maze_hints_detail_8": "僕を動かすためによく使うブロックのリストを「約束する」ブロックの下に並べて約束として作成できるよ。
一度作っておいた約束は「約束を読み込む」ブロックを使って何度も取り出して使えるんだ。", "ai_hints_title_1_1": "ゲームの目標", "ai_hints_content_1_1": "石を避けて右の惑星まで無事に移動できるように手伝ってください。", "ai_hints_detail_1_1": "石を避けて右の惑星まで無事に移動できるように手伝ってください。", "ai_hints_title_1_2": "はじめ方", "ai_hints_content_1_2": "どうすれば始められますか?", "ai_hints_detail_1_2": "1. ブロックリストからブロックを取り出して「スタートをクリックしたとき」にブロックを繋げてみてね
2. 全部組み立てたら、スタートを押してみて
3.僕は君が組み立てたブロックどおりに上から順番に動くからね", "ai_hints_title_1_3": "動かす", "ai_hints_content_1_3": "エントリーボットはどうすれば動きますか?", "ai_hints_detail_1_3": "僕は上に行ったり、前や下に行ったりできるよ。
方向を決める時は、石のない方向に安全に行けるようにしてね。
僕を画面の外に行かせてしまうと宇宙の迷子になっちゃうから気を付けて!", "ai_hints_title_2_1": "ゲームの目標", "ai_hints_content_2_1": "リピートブロックで石を避けられるように手伝ってください。", "ai_hints_detail_2_1": "リピートブロックで石を避けられるように手伝ってください。", "ai_hints_title_2_2": "リピートブロック", "ai_hints_content_2_2": "リピートブロックはどんなブロックですか?", "ai_hints_detail_2_2": "ふ~。遠くまで行かなくちゃいけないのに、1つずつ組み立てるのは大変そうだね。リピートブロックを使用してみよう。
同じように繰り返されるブロックをリピートブロックでくくっておけば、とても長いブロックを短くすることができるよ!", "ai_hints_content_3_1": "もしブロックで石を避けられるように手伝ってください。", "ai_hints_title_3_2": "もしブロック(1)", "ai_hints_content_3_2": "もし~ならブロックはどのように動作しますか?", "ai_hints_detail_3_2": "もし前に~があるなら/そうでなければブロックを使うと、自分の目の前に石があるのか確認して違う動きができるよ~。
もし自分の目の前に石があるなら「もし」の下にあるブロックを実行して、石がないなら「そうでなければ」の中にあるブロックを実行するんだ。
僕の目の前に石がある時とない時でどう動くのかをちゃんと決めてね~", "ai_hints_content_4_1": "レーダーの使用方法を身に着けて石を避けてみてください。", "ai_hints_detail_4_1": "レーダーの使用方法を身に着けて石を避けてみてください。", "ai_hints_title_4_2": "レーダー(1)", "ai_hints_content_4_2": "レーダーとは何ですか? どうすれば活用できますか?", "ai_hints_detail_4_2": "レーダーは、物体と自分が今どれだけ離れているかを教えてくれる機械だよ。
もし自分の前に何かがあるなら、前方向レーダーは'1'を表示するよ。
それと、レーダーは1人でいる時、もし<true>なら/そうでなければブロック
のように使えばとっても強力な道具になるんだ。
例えば、僕の前にある物体との距離が1より大きい時は安全に前に行けるけど、そうでなければ上と下、どちらかに避けることもできるよね。", "ai_hints_title_4_3": "もしブロック(2)", "ai_hints_content_4_3": "もしならブロックはどうやって使いますか?", "ai_hints_detail_4_3": "もし<true>なら/ そうでなければブロックは<true>の中にある内容が合っていれば、「もし」の下にあるブロックを実行して、違うなら「そうでなければ」の下にあるブロックを実行するんだ。
どんな状況で違う動きをしたいのかをよく考えて、<true>の中に適切な判断条件を作成して入れてみてね。
判断条件を満たして「もし」の下にあるブロックを実行すると、「そうでなければ」の下にあるブロックは実行されないから覚えておいてね!", "ai_hints_content_5_1": "レーダーを活用して石を簡単に避けられるように手伝ってください。", "ai_hints_detail_5_1": "レーダーを活用して石を簡単に避けられるように手伝ってください。", "ai_hints_title_5_2": "もしブロック(3)", "ai_hints_content_5_2": "もしブロックが重なっている時はどのように動作しますか?", "ai_hints_detail_5_2": "もし~ / そうでなければブロックの中にも、もし~/そうでなければブロックを入れられるよ! こうすれば、様々な状況で自分がどのように行動すればいいか決めることができるんだ。
例えば、前に石が道をふさいでいる時とそうでない時の行動を決めると、石がある時の状況でも状況に応じて上と下、どちらに行くのかを選択できるようになるよ", "ai_hints_title_6_1": "レーダー(2)", "ai_hints_content_6_1": "上方向レーダーと下方向レーダーの値を比較したい時はどうすればいいですか?", "ai_hints_detail_6_1": "([上方向]レーダー)ブロックは、上の物体までの距離を意味するブロックだよ。
上と下のどちらが石からもっと遠いのかを確認する時に使えるブロックなんだ。
石を避ける道を選択する時は、遠く離れている方に避けるのが遠くまで行く時に有利なはずだよ~", "ai_hints_content_7_1": "アイテムに向かって移動し、石を避けてください。", "ai_hints_detail_7_1": "アイテムに向かって移動し、石を避けてください。", "ai_hints_title_7_2": "物体名確認", "ai_hints_content_7_2": "前に遭遇する物体の名前を確認すると何ができますか?", "ai_hints_detail_7_2": "アイテムを獲得するためには、アイテムがどこにあるのか確認する必要があるよ。
そんな時に使えるブロックが[上]の物体は[アイテム]か?ブロックだよ。
このブロックを使うとアイテムがどの位置にあるかが分かるから、アイテムのある方向に動くようにブロックを組み立てられるよ。", "ai_hints_content_8_1": "適切なアイテムを使って石を避けてみてください。", "ai_hints_detail_8_1": "適切なアイテムを使って石を避けてみてください。", "ai_hints_title_8_2": "アイテム", "ai_hints_content_8_2": "アイテムはどのように手に入れて使いますか?", "ai_hints_detail_8_2": "石をあちこちにうまく避けていても、前が石で全部ふさがれてしまっている…こんな時に抜け出す方法はないのかな? こんな時は、アイテム使用ブロックを使ってみてね。
このブロックは自分の前の石をすべて消すブロックだよ。
ただし、アイテムがなければブロックを使うことはできないよ。アイテムは画像を通過するとゲットできるんだ。", "ai_hints_content_9_1": "今まで学んできたことをすべて生かして、できる限り遠くまで行ってください。", "ai_hints_detail_9_1": "今まで学んできたことをすべて生かして、できる限り遠くまで行ってください。", "ai_hints_title_9_2": "そして", "ai_hints_content_9_2": "そしてブロックはどうやって使いますか?", "ai_hints_detail_9_2": "そしてブロックには複数の条件を入れることができるよ。入れたすべての条件がtrueの時だけtrueになって、もしブロックの中にあるブロックが実行されるよ。1つでもfalseがあるとfalseと認識してその中にあるブロックは実行しないんだ", "maze_text_goal_1": "move(); コマンドを使って、パーツボックスまで僕を移動させてね!", "maze_text_goal_2": "jump(); コマンドで障害物を避けてパーツボックスまで僕を移動させてね!", "maze_text_goal_3": "left(); right(); コマンドでパーツボックスまで僕を移動させてね!", "maze_text_goal_4": "いろんなコマンドを使って、パーツボックスまで僕を移動させてね!", "maze_text_goal_5": "2つのパーツボックス両方に行けるように僕を移動させてね!", "maze_text_goal_6": "2つのパーツボックス両方に行けるように僕を移動させてね!", "maze_text_goal_7": "for コマンドを使って、友達がいる場所まで僕を移動させてね!", "maze_text_goal_8": "for コマンドを使って、障害物を避けながら友達がいる場所まで僕を移動させてね!", "maze_text_goal_9": "whileコマンドを使って、友達がいる場所まで僕を移動させてね!", "maze_text_goal_10": "ifとwhileコマンドを使って、友達がいる場所まで僕を移動させてね!", "maze_text_goal_11": "ifとwhileコマンドを使って、友達がいる場所まで僕を移動させてね!", "maze_text_goal_12": "ifとwhileコマンドを使って、友達がいる場所まで僕を移動させてね!", "maze_text_goal_13": "whileとforコマンドを使って、友達全員に会えるように僕を移動させてね!", "maze_text_goal_14": "whileとfor コマンドを使って、友達全員に会えるように僕を移動させてね!", "maze_text_goal_15": "関数を呼び出してバッテリーまで僕を移動させてね!", "maze_text_goal_16": "関数にコマンドを入れ、関数を呼び出してバッテリーまで僕を移動させてね!", "maze_text_goal_17": "関数にコマンドを入れ、関数を呼び出してバッテリーまで僕を移動させてね!", "maze_text_goal_18": "関数にコマンドを入れ、関数を呼び出してバッテリーまで僕を移動させてね!", "maze_text_goal_19": "関数にコマンドを入れ、関数を呼び出してバッテリーまで僕を移動させてね!", "maze_text_goal_20": "関数と他のコマンドを混ぜて使って、バッテリーまで僕を移動させてね!", "maze_attack_range": "攻撃可能回数", "maze_attack": "攻撃", "maze_attack_both_sides": "両側攻撃", "above_radar": "上方向レーダー", "above_radar_text_mode": "radar_up", "bottom_radar": "下方向レーダー", "bottom_radar_text_mode": "radar_down", "front_radar": "前方向レーダー", "front_radar_text_mode": "radar_right", "above_object": "上の物体", "above_object_text_mode": "object_up", "front_object": "前の物体", "front_object_text_mode": "object_right", "below_object": "下の物体", "below_object_text_mode": "object_down", "destination": "目的地", "asteroids": "石", "item": "アイテム", "wall": "壁", "destination_text_mode": "destination", "asteroids_text_mode": "stone", "item_text_mode": "item", "wall_text_mode": "wall", "buy_now": "購入へ移動", "goals": "目標", "instructions": "利用案内", "object_info": "オブジェクト情報", "entry_basic_mission": "エントリー基本ミッション", "entry_application_mission": "エントリー応用ミッション", "maze_move_forward": "前に1マス移動", "maze_when_run": "スタートをクリックしたとき", "maze_turn_left": "左側に回転", "maze_turn_right": "右側に回転", "maze_repeat_times_1": " ", "maze_repeat_times_2": "回繰り返す", "maze_repeat_until_1": " ", "maze_repeat_until_2": "に会うまで繰り返す", "maze_call_function": "約束を読み込む", "maze_function": "約束する", "maze_repeat_until_all_1": "すべて", "maze_repeat_until_all_2": "会うまで繰り返す", "command_guide": "コマンドヘルプ", "ai_success_msg_1": "おかげで無事に地球に到着できたよ! ありがとう!", "ai_success_msg_2": "よかった! おかげで", "ai_success_msg_3": "回前に進むことができたから地球に救助信号を送ったよ! 今から地球から救助隊が来るはずだよ! ありがとう!", "ai_success_msg_4": "いいね!", "ai_cause_msg_1": "大変だ、どう動くべきなのかもっと話してもらえるかな?", "ai_cause_msg_2": "うわっ! 本当に危なかったよ! もう一度チャレンジしてみよう", "ai_cause_msg_3": "わわっ! 行くべき道から外れると宇宙の迷子になっちゃうよ。もう一度チャレンジしてみよう", "ai_cause_msg_4": "すごく複雑だね。このブロックを使って動かしてみる?", "ai_move_forward": "前に進む", "ai_move_above": "上に行く", "ai_move_under": "下に行く", "ai_repeat_until_dest": "目的地に到達するまで繰り返す", "ai_if_front_1": "もし前に", "ai_if_front_2": "があるなら", "ai_else": "そうでなければ", "ai_if_1": "もし", "ai_if_2": "なら", "ai_use_item": "アイテム使用", "ai_radar": "レーダー", "ai_above": "上方向", "ai_front": "前方向", "ai_under": "下方向", "ai_object_is_1": " ", "ai_object_is_2": "物体は", "challengeMission": "他のミッションにチャレンジする", "nextMission": "次のミッションにチャレンジする", "withTeacher": "一緒に制作した先生方", "host": "主催", "support": "後援", "subjectivity": "主管", "learnMore": " もっと学びたいです", "ai_object_is_3": "なのか?", "stage_is_not_available": "このステージはまだ進められません。順番にステージを進めてください。", "progress_not_saved": "進行状況は保存されません。", "want_refresh": "このページを更新しますか?", "monthly_entry_grade": "小学校3学年 ~ 中学校3学年", "monthly_entry_contents": "毎月発刊される月刊エントリーと共にソフトウェア教育を始めてみましょう! 少しずつ進めて行けば簡単に身に着けられるよう、ライトに構成されています。基本、応用コンテンツに加え、さらにその先まで! 毎月アップデートされる8つのコンテンツと教材をお楽しみください~", "monthly_entry_etc1": "*メインページの月刊エントリーオススメコースを活用すれば、もっと簡単に授業を進めることができます。", "monthly_entry_etc2": "*月刊エントリーは学期中にのみ発刊されます。", "group_make_lecture_1": "自分が作った講義がありません。", "group_make_lecture_2": "「作成する>オープン講義を作成する」で", "group_make_lecture_3": "クラスの学習内容に追加したい講義を作成してください。", "group_make_lecture_4": "講義を作成する", "group_add_lecture_1": "関心講義がありません。", "group_add_lecture_2": "「学習する>オープン講義>講義」でクラスの学習内容に", "group_add_lecture_3": "追加したい講義を関心講義に登録してください。", "group_add_lecture_4": "講義を見る", "group_make_course_1": "自分が作った講義集がありません。", "group_make_course_2": "「作る > オープン講義を作成する>講義集を作成する」で", "group_make_course_3": "学習内容に追加したい講義集を作成してください。", "group_make_course_4": "講義集を作成する", "group_add_course_1": "関心講義集がありません。", "group_add_course_2": "「学習する > オープン講義>講義集」でクラスの学習内容に", "group_add_course_3": "追加したい講義集を関心講義集に登録してください。", "group_add_course_4": "講義集を見る", "hw_main_title": "プログラムダウンロード", "datablock_contest_title": "データ分析ブロック", "datablock_content_head": "データを加工して表現しよう", "datablock_content_body1": "生活の中で出会う色んなデータをチャートで表現して意味を探し、", "datablock_content_body2": "実際の問題を解決してみよう!", "campaign_contest_title": "Let's make a beautiful internet world", "campaign_content_head": "Entry Project Contest", "campaign_content_body1": "Create an originative project about 'internet ethics'", "campaign_content_body2": "and apply for the contest!", "campaign_content_button": "View details", "code_management_1": "ENTRYキャンペーン#1 コードを上手に管理しよう", "code_management_2": "マイボックスとメモの活用", "code_management_3": "新しい機能と一緒にコードを管理し、", "code_management_4": "作品を作って共有する方法について知りましょう。", "code_management_5": "キャンペーンを見る", "shcoolbook_study_1": "教科書の内容をそのまま", "shcoolbook_study_2": "教科書で学ぶ", "shcoolbook_study_3": "先生は教室で授業を、", "shcoolbook_study_4": "生徒は家で復習することができます!", "shcoolbook_study_5": "学ぶ", "main_learn_1": "エントリーが初めてなら", "main_learn_2": "エントリーについて知ろう", "main_learn_3": "動画でエントリーのさまざまな機能を学び,", "main_learn_4": "ステキな作品を作って友だちと共有してみましょう!", "main_learn_5": "動画を見る", "hw_desc_wrapper": "ハードウェア結合プログラムとオフ\nラインバージョンが\より一層レベルアップしてアップグ\nレードされました。", "hw_downolad_link": "ハードウェア結合\nプログラムダウンロード", "save_as_image_all": "すべてのコードを画像で保存する", "save_as_image": "画像で保存する", "maze_perfect_success": "さすが!完璧だったね~", "maze_success_many_block_1": "よし", "maze_fail_obstacle_remain": "みんなが怪我をしないよう、すべてのをなくそう。", "maze_fail_item_remain": "サリー姫を救出できるようにミネラルを全部集めよう。サリー姫を救出できるようにミネラルを全部集めよう。", "maple_fail_item_remain": "食べ物が全部食べられなかったから力が出ないよ。食べ物を全部食べられるように手伝って。", "maze_fail_not_found_destory_object": "何もないマスで無駄にスキルを使っちゃダメだよ!", "maze_fail_not_found_destory_monster": "モンスターがいないマスでは攻撃しちゃダメだよ!", "maple_fail_not_found_destory_monster": "攻撃ブロックはモンスターがある時だけ使うんだよ!", "maze_fail_more_move": "目的地に着くには、もっと進まないと!", "maze_fail_wall_crash": "うわ! そこは突き当たりだよ!", "maze_fail_contact_brick": "あいたたた…ぶつかっちゃったよ!", "maze_fail_contact_iron1": "うわ! 障害物にぶつかっちゃったね", "maze_fail_contact_iron2": "うわ! 障害物が落ちてきてぶつかっちゃったよ。障害物が落ちてくる前に動いてね…", "maze_fail_fall_hole": "あぁ、落とし穴に落ちちゃったね…", "maze_fail_hit_unit": "モンスターにやられてしまった! 危険なモンスターをやっつける<ハートを飛ばす>ブロックを使ってね!", "maze_fail_hit_unit2": "くぅ、モンスターにやられてしまった! 2マス離れたところから攻撃してね!", "maze_fail_hit_unit_by_mushroom": "メイプルキノコにやられてしまった!
攻略するブロックを使って悪いモンスターをこやっつけよう!", "maze_fail_hit_unit_by_lupin": "ルパンにやられてしまった!
攻略するブロックを2マス離れたところで使って、悪いモンスターをやっつけよう!", "maze_fail_elnath_fail": "うわっ!悪いモンスターから攻撃されちゃった!
悪いモンスターが近づかないようにやっつけて!", "maze_fail_pepe": " ", "maze_fail_yeti": "そのモンスターはとても強いから、攻攻撃するブロックではやっつけられないよ!
攻略するブロックを使ってみよう。", "maze_fail_peti": "そのモンスターに攻略するブロックを使うと、
強いモンスターのがが現れたときにやっつけられないよ!
攻略するブロックを使ってみよう。", "maze_fail_both_side": "両隣を攻撃するブロックは両隣にモンスターがいるときしか使っちゃダメだよ!", "maze_wrong_attack_obstacle": "ここからは攻撃するブロックは使えないよ!
メイプルキノコには攻撃するブロックを使ってみよう。", "maze_fail_contact_spider": "クモの巣に引っかかって動けないぃ…", "maze_success_perfect": "さすが!完璧だったね~", "maze_success_block_excess": "よし! %1個のブロックを使って成功させたね!
でも%2個のブロックだけで成功させる方法もあるよ。もう一度チャレンジしてみない?", "maze_success_not_essential": "よし! %1個のブロックを使って成功させたね!
でもこのブロックを使えば、もっと簡単に解決できるよ。もう一度チャレンジしてみない?", "maze_success_final_perfect_basic": "よし!サリー姫の居場所が確認できたよ!これでサリー姫が救えるはず!", "maze_success_final_block_excess_basic": "よし!サリー姫の居場所が確認できたよ!これでサリー姫が救えるはず!%1個のブロックを使ったけど、%2個のブロックだけで成功させる方法もあるよ。もう一度チャレンジしてみない?", "maze_success_final_perfect_advanced": "サリー姫の居場所に着いたよ!さあ、メフィストを倒してサリーを救おう!", "maze_success_final_block_excess_advanced": "サリー姫の居場所に着いたよ!さあ、メフィストを倒してサリーを救おう!%1個のブロックを使ったけど、%2個のブロックだけで成功させる方法もあるよ。もう一度チャレンジしてみない?", "maze_success_final_distance": "よし!ついにみんなでサリー姫を無事に救出できたよ。手伝ってくれて本当にありがとう!
%1マス動いて成功させたけど、もう一度チャレンジして60マスまで行ってみない?", "maze_success_final_perfect_ai": "よし!ついにみんなでサリー姫を無事に救出できたよ。手伝ってくれて本当にありがとう! ", "maple_success_perfect": "さすが!完璧だったね~!!", "maple_success_block_excess": "よし!( )個のブロックを使って成功させたね!
でも、%2個のブロックだけで成功させる方法もあるよ。もう一度チャレンジしてみない?", "maple_success_not_essential": "よし! %1個のブロックを使って成功させたね!
でも、このブロックを使えばもっと簡単に解決できるよ。もう一度チャレンジしてみない?", "maple_success_final_perfect_henesys": "素晴らしい!見事にヘネシスの冒険を成功させたね!", "maple_success_final_perfect_excess_henesys": "素晴らしい!見事にヘネシスの冒険を成功させたね!
でも、%2個のブロックだけで成功させる方法もあるよ。もう一度チャレンジしてみない?", "maple_success_final_not_essential_henesys": "素晴らしい!見事にヘネシスの冒険を成功させたね!
でも、このブロックを使えばもっと簡単に解決できるよ。もう一度チャレンジしてみない?", "maple_success_final_perfect_ellinia": "ここでの冒険は本当に楽しかったよ!
次の冒険にも付き合ってくれるよね?", "maple_success_final_perfect_excess_ellinia": "ここでの冒険は本当に楽しかったよ!
でも、%2個のブロックだけで成功させる方法もあるよ。もう一度チャレンジしてみない?", "maple_success_final_not_essential_ellinia": "ここでの冒険は本当に楽しかったよ!
でも、このブロックを使えばもっと簡単に解決できるよ。もう一度チャレンジしてみない?", "maple_fail_fall_hole": "うわっ!落ちちゃったね…
ジャンプするブロックを使ってジャンプしてみよう。", "maple_fail_ladder_fall_hole": "うわっ!落ちちゃったね…
はしごを使うブロックを使って他の道に行ってみよう.", "maple_fail_more_move": "成功するには、目的地までもっと進まないと!", "maple_fail_not_found_ladder": "残念!ここには登れるはしごがないよ。
はしごを使うブロックははしごがある場所でしか使っちゃダメだよ。", "maple_fail_not_found_meat": "残念!ここには食べられる食べ物がないよ!
食べ物を食べるブロックは食べ物がある場所でしか使っちゃダメだよ。", "maple_cert_input_title": "証明書に記入する、きみのお名前は?", "maze_distance1": "距離1", "maze_distance2": "距離2", "maze_distance3": "距離3", "ev3": "EV3", "roborobo_roduino": "Roduino", "roborobo_schoolkit": "School Kit", "smartboard": "Sciencebox Codingboard", "smartboardbt": "Sciencebox Codingboard(Bluetooth)", "codestar": "Codestar", "cobl": "Cobl", "cobl_bt": "Cobl BT", "block_coding": "ブロック", "python_coding": "エントリーパイソン", "dadublock": "DaduBlock", "dadublock_car": "DaduBlock Car", "blacksmith": "Blacksmith Board", "course_submit_homework": "課題提出", "course_done_study": "学習完了", "course_show_list": "リスト", "modi": "MODI", "chocopi": "ChocoPi", "coconut": "coconut", "jdkit": "JDKit", "practical_course": "教科用を作成する", "entry_user_policy": "エントリー利用ポリシー", "entry_scholarship_title": "エントリー学術資料", "entry_scholarship_content": "エントリーは大学/学会などと共に多様な研究を行い、専門性を強化し続けています。エントリーで提供している研究用資料を確認してみてください。", "entry_scholarship_content_sub": "*エントリーで提供するデータは、研究及び分析に活用されるようオンラインコーディングパーティーに参加したユーザーたちがミッションを解決する一連の過程をログ形式で保存したデータです。", "entry_scholarship_download": "資料ダウンロード", "codingparty_2016_title": "2016オンラインコーディングパーティー", "codingparty_2016_content": "ミッションに参加したユーザーたちのブロック組み立て順、成功/失敗状況が学年、性別情報と共に提供されます。", "codingparty_2017_title": "2017 Online coding party", "scholarship_go_mission": "ミッションを確認する", "scholarship_guide": "資料活用方法", "scholarship_see_guide": "ガイドを見る", "scholarship_guide_desc": "研究用資料を読み、活用できる方法が書かれている開発ガイドです。", "scholarship_example": "資料活用例", "scholarship_example_desc": "研究用資料を活用して発表された論文を確認できます。", "scholarship_see_example": "論文ダウンロード", "altino": "Altino", "private_project": "非公開作品です。", "learn_programming_entry_mission": "「エントリーボット」と一緒にミッションを解決する", "learn_programming_line_mission": "「LINEレンジャー」と一緒にサリーを救え", "learn_programming_choseok": "「ココロの声」のジョソクとゲームを作る", "learn_programming_maple": "「ピンクビーン」と一緒に楽しいメイプルワールドへ!", "learn_programming_level_novice": "基礎", "learn_programming_level_inter": "中級", "learn_programming_level_advanced": "上級", "line_look_for": "サリーを探して", "line_rangers_title_string": "学習する : ライン・レンジャーズ", "online_codingparty_certificate_string": "オンラインコーディングパーティー", "online_codingparty_line_title_string": "ライン・レンジャーズ", "line_look_for_desc_1": "LINEレンジャーの力を一つに合わせ、最強ボス・メフィストを倒してサリーを救ってください!", "line_save": "サリーを救え", "line_save_desc_1": "メフィストの基地に閉じ込められたサリー。LINEレンジャーが障害物を避けてサリーを探し出せるように手伝ってください!", "line_escape": "サリーと脱出する", "line_escape_desc_1": "爆破されたメフィスト基地からサリーとLINEレンジャーが無事に脱出できるよう、手伝ってください!", "solve_choseok": "じゃんけんゲームを作ろう", "solve_choseok_desc_1": "漫画キャラクターのジョソクがじゃんけんゲームを作れるよう手伝ってください!", "solve_henesys": "ヘネシス", "solve_ellinia": "エリニア", "solve_elnath": "エルナス", "solve_henesys_desc_1": "村を冒険し、お腹をすかせたピンクビーンが食べ物をお腹いっぱい食べられるように手伝ってください!", "solve_ellinia_desc_1": "森の中を探検し、悪いモンスターたちをやっつけて友達モンスターを助けてください!", "solve_elnath_desc_1": "悪いモンスターが占領した雪山を越えて新しい冒険をスタートできるように、違うポータルを求めて旅立ってください!", "save_modified_shape": "Do you want to save the modified shape?", "save_modified_table": "修正したテーブルを保存しますか?", "attach_file": "添付", "enter_discuss_title": "タイトルを入力してください(40文字以下)", "enter_discuss_title_alert": "タイトルを入力してください", "discuss_upload_warn": "10MB以下のファイルをアップロードしてください。", "discuss_list": "リストを見る", "discuss_write_notice": "クラスのお知らせに設定し、掲示板の最上段に表示します。", "discuss_write_notice_open": "お知らせに設定し、掲示板の最上段に表示します。", "search_전체": "すべて", "search_게임": "ゲーム", "search_애니메이션": "アニメーション", "search_미디어아트": "メディアアート", "search_피지컬": "フィジカル", "search_기타": "その他", "discuss_write_textarea_placeholer": "ENTRYコミュニティは、みんなでいっしょにきずいていく空間です。\n互いに気づかう言葉で楽しいコミュニティにしましょう!", "discuss_write_textarea_placeholer_qna": "このページはQ&Aの掲示板です。\nお互い思いやる言葉を使って楽しいコミュニティにしましょう。", "discuss_write_textarea_placeholer_tips": "このページはノウハウ&ティップの掲示板です。\nお互い思いやる言葉を使って楽しいコミュニティにしましょう。", "discuss_write_textarea_placeholer_free": "このページはENTRYストーリー掲示板です。\nお互い思いやる言葉を使って楽しいコミュニティにしましょう。", "discuss_write_textarea_placeholer_report": "このページは提案&意見掲示板です。\nお互い思いやる言葉を使って楽しいコミュニティにしましょう。", "discuss_write_textarea_placeholer_contest2019": "※ 아래 양식으로 작성하여 제출해주세요.\n\n1. 학년 (예: 초등학교 5학년)\n\n2. 작품 URL (‘공유하기 > 작품 공유하기’에 작품을 공유한 다음, 작품 URL을 복사하여 적어주세요.)\n\n3. 작품 설명\n\n※ 공모전 수상자에게는 이메일이 발송될 예정입니다.\n엔트리의 ‘내 정보 수정‘에 이메일 정보를 꼭 입력해주세요!", "maze_road": "道", "account_deletion": "会員退会", "bug_report_too_many_request": "通報内容を送信しています。しばらくしてからやり直してください。", "pinkbean_index_title": "ピンクビーンと一緒に楽しいメイプルワールドへ!", "pinkbean_index_content": "退屈に耐えられなかったピンクビーンはメイプルワールドへの冒険に出ることにしました。
ピンクビーンと一緒に楽しいメイプルワールドを冒険しながら冒険日記を書いてください。
各ステージをクリアしながら自然にソフトウェアについて学ぶことができ、ミッションをすべてクリアすれば証明書ももらえます。", "rangers_index_title": "LINEレンジャーと一緒にサリーを救いに出発!", "rangers_index_content": "最強ボス・メフィストに連れ去られたサリーを救うため、LINEレンジャーが一つになりました。
プログラミングの原理で障害物を克服し、サリーを救うヒーローになってください。各ステップを
進むと自然にプログラミングを学ぶことができ、ミッションを終えたら証明書ももらえます。", "rangers_replay_button": "動画を見る", "rangers_start_button": "スタート", "lms_curriculum_intro": "", "lms_curriculum_goal": "", "lms_curriculum_prepare": "", "lms_curriculum_study": "", "lms_curriculum_summary": "", "lms_curriculum_quiz": "", "lms_curriculum_now_stage": "", "bug_report_title": "バグ報告", "bug_report_content": "利用中に発生するエラーやバグの報告のほか、エントリーのためにすばらしい意見をお寄せ下さい。", "object_import_syntax_error": "Since the object has syntax error blocks, it cannot be loaded. Please convert into block mode to load the object.", "choseok_top_wrapper_panel_title": "ジョソクと一緒にじゃんけんゲームを作ってみよう!", "choseok_top_wrapper_panel_des": "ウェブ漫画「ココロの声」がコーディングパーティーのミッションとして登場しました。
漫画の中でジョソクが(じゃんけんゲーム)を作っていく過程に参加し、
ミッションにチャレンジしてみてください。
各ステップをクリアしていくことでソフトウェアについて学ぶことができ、
ミッションを全てクリアすると
証明書と共に自分だけのゲームを手に入れることができます。", "choseok_mission_statement1": "ジョソクを動かす", "choseok_mission_statement2": "じゃんけん対決スタート", "choseok_mission_statement3": "じゃんけんで勝負を決める", "choseok_mission_statement4": "じゃんけん対決の結果を表示する", "choseok_mission_statement5": "自由に作ってみる", "choseok_mission_statement_top1": "ミッション1:ジョソクを動かす", "choseok_mission_statement_top2": "ミッション2:じゃんけん対決スタート", "choseok_mission_statement_top3": "ミッション3:じゃんけんで勝負を決める", "choseok_mission_statement_top4": "ミッション4:じゃんけん対決の結果を表示する", "choseok_mission_statement_top5": "ミッション5:自由に作ってみる", "advisory_title": "Entry Advisory Group", "advisory_sub_title": "This is an advisory group including teachers and students who make Entry together.", "data_table_column": "列", "data_table_row": "行", "data_table_provider": "提供", "data_table_modifidate": "修正日", "draw_new_table_ques_1": "データを直接入力してテーブルで保存ができます。", "draw_new_table_ques_2": "テーブルの画面に移動しますか?" }; Lang.Msgs = { "microbit_led_erase_all": "初期化", "loading_plz_wait": "読み込んでいます。しばらくお待ちください", "ai_utilize_audio_listening": "聞いている", "upload_error_title": "ファイルが拒否されました", "upload_error_content": "使用ポリシーに準拠していないファイルは除外されます。", "monthly_intro_0": "<月刊エントリー>は、ソフトウェア教育に不慣れな先生でも簡単かつ楽しくソフトウェア教育ができるように作成された ", "monthly_intro_1": "SW教育雑誌です。面白い学習漫画と共にお送りするSW教育コンテンツをお楽しみください!", "monthly_title_0": "犬を散歩させる / 線対称図形描画", "monthly_title_1": "動画の原理 / 音楽プレイヤー作成する", "monthly_title_2": "大韓民国地図パズル / 桜の花アニメーション", "monthly_title_3": "マウスゾロゾロ、魚の群れ / 太陽系惑星", "monthly_title_4": "ジャガイモ堀り / いちご牛乳の濃さ", "monthly_description_0": "キーボード入力に沿って動く犬と、信号と座標を通して図形を描く作品を制作します。", "monthly_description_1": "変数を活用して、写真映像作品や音楽プレイヤー作品を制作します。", "monthly_description_2": "~の間繰り返すを利用したパズルゲームとコピー、乱数を利用したアニメーション作品を制作します。", "monthly_description_3": "続けて繰り返すブロックと数学演算ブロックを使って、魚のメディアアート作品と太陽系を制作します。", "monthly_description_4": "信号と変数、数学演算ブロックを活用してジャガイモを堀る作品といちご牛乳を作る作品を制作します。", "save_canvas_alert": "保存中です。", "feedback_too_many_post": "通報した内容を送信しています。10秒後にもう一度やり直してください。", "feedback_duplicated": "既に通報されています", "usable_object": "使用可能オブジェクト", "shared_varaible": "共有変数", "invalid_url": "映像URLを再確認してください。", "auth_only": "認証済みのユーザーのみ利用できます。", "runtime_error": "実行エラー", "to_be_continue": "準備中です。", "warn": "警告", "error_occured": "もう一度やり直してください。同じ問題が再度発生する時は、「提案と意見」掲示板にお問い合わせください。", "error_forbidden": "ログアウト状態であるため、作品を保存することができません。\n他のタブでログアウントされているか確認してください。\nログインの確認ができても、保存ができなければ”提案と意見”にてお問い合わせください。", "list_can_not_space": "リスト名のセルを空白にすることはできません。", "sign_can_not_space": "信号の名前のセルを空白にすることはできません。", "variable_can_not_space": "変数の名前のセルを空白にすることはできません。", "training_top_title": "研修プログラム", "training_top_desc": "エントリー研修支援プログラムについてご案内いたします。", "training_main_title01": "教師のための講師紹介プログラム", "training_target01": "教育対象 l 教師", "training_sub_title01": "“うちのクラスにSWの翼をつけよう”", "training_desc01": "ソフトウェア(SW)教員研修が必要な学校ですか?\nSW教員研修が必要な学校に、SW教育専門教師(ゴートゥーティーチャー)または専門講師をご紹介いたします。", "training_etc_ment01": "*講義費などの研修費用は学校側で負担していただく必要があります。", "training_main_title02": "ソフトウェア(SW)リード校に訪問する教員研修", "training_target02": "教育対象 l SWリード、研究学校", "training_sub_title02": "“訪ねて、教えて、つないでいく”", "training_desc02": "SW教員研修にお申込みいただいたリード校を抽選でランダムに選び、上半期(4・5・6月)と\n下半期(9・10・11月)に各地域のSW教育専門教師(ゴートゥーティーチャー)が充実した内容の\n楽しいSW基礎研修実施と豊富な教育事例を共有するために訪ねます。", "training_etc_ment02": " ", "training_main_title03": "保護者と学生のための紹介プログラム", "training_target03": "教育対象 l 保護者、学生", "training_sub_title03": "“SWともっと近くで触れ合えるチャンス”", "training_desc03": "保護者と学生たちを対象に、ソフトウェア(SW)研修が必要な学校に各地域のSW教育専門教師(ゴートゥーティーチャー)または専門講師をご紹介いたします。", "training_etc_ment03": "*講義費などの研修費用は学校側で負担していただく必要があります。", "training_apply": "申し込み", "training_ready": "準備中です。", "new_version_title": "最新バージョンインストールのご案内", "new_version_text1": "ハードウェア結合プログラムがインストールされていません。", "new_version_text2": "最新バージョンではありません。", "new_version_text3": "サービスをより一層レベルアップしてアップデートされた", "new_version_text4": "最新バージョンの結合プログラムをインストールしてください。", "new_version_download": "最新バージョンダウンロード", "not_install_title": "未インストールのご案内", "hw_download_text1": "ハードウェア結合のために", "hw_download_text2": "ハードウェア結合プログラムをインストールしてください。", "hw_download_text3": "ハードウェア結合プログラムがインストールされていません。", "hw_download_text4": "最新バージョンの連結プログラムをインストールしてください。", "hw_download_btn": "連結プログラムダウンロード", "not_support_browser": "このブラウザには対応していません。", "quiz_complete1": "クイズ終了!", "quiz_complete2": "全{0}問のうち{1}問に正解しました。", "quiz_incorrect": "わわっ。もう一度考えてみよう。", "quiz_correct": "正解だよ!", "hw_connection_success": "ハードウェア結合成功", "hw_connection_success_desc": "ハードウェアアイコンをダブルクリックすると、センサー値のみ確認できます。", "hw_connection_success_desc2": "作品でハードウェアを使うことができます。", "hw_connection_termination_title": "ハードウェア接続解除", "hw_connection_termination_desc": "ハードウェアと接続が解除されました。", "hw_connection_failed_title": "ハードウェア接続失敗", "hw_connection_failed_desc": "作品で使われたハードウェアが\n接続されているか確認してください。", "ie_page_title": "このブラウザには
対応していません。", "ie_page_desc": "エントリーはIE 10以上またはchromeでご利用いただけます。
Windowsアップデートを行うか、chromeをインストールしてください。
エントリーオフラインバージョンはインターネットに接続されていない状態でも使用できます。今すぐダウンロードして始めてください!", "ie_page_chrome_download": "chrome
をダウンロード", "ie_page_windows_update": "Windowsの最新バージョン
をアップデート", "ie_page_offline_32bit_download": "エントリーオフライン32bit
をダウンロード", "ie_page_offline_64bit_download": "エントリーオフライン64bit
をダウンロード", "ie_page_offline_mac_download": "エントリーオフライン
をダウンロード", "cancel_deletion_your_account": "$1さんの
会員退会申請を取消しますか?", "account_deletion_canceled_complete": "会員退会申請が取消されました。", "journal_henesys_no1_title": "ヘネシス冒険日記 その1", "journal_henesys_no2_title": "ヘネシス冒険日記 その2", "journal_henesys_no1_content": "ヘネシスで書くはじめての冒険日記だね。今日はヘネシスで一番の古株だと言われている鍛冶屋の家に行こうと思ってジャンプしたら危うく落ちそうになったの。あのおじさん、どうして家の庭にあんなに大きな穴を作ってるんだろう?私ほど強いモンスターじゃない限り、この穴を飛び越えられるような子はあまりいないと思うんだけどね!とりあえず情報ももらえたし、おじさんがおすすめしてくれた食堂にでも行ってみようかな!", "journal_henesys_no2_content": "食べ過ぎちゃった… 特に、あの食堂のお肉がすごく美味しかったね。どうすればあんなに柔らかくできるんだろう?!でも、その隣の店のパンはイマイチだったよ。どうやらパティシエさんが食べ物の修練を言い訳に毎日遊び回ってるみたい。そういう時間があるならもっとパンを作ってみるのがいいんじゃないかな。まぁ、お腹もいっぱいになったことだし、本格的に冒険をはじめてみようかな!", "journal_ellinia_no1_title": "エリニア冒険日記 その1", "journal_ellinia_no2_title": "エリニア冒険日記 その2", "journal_ellinia_no1_content": "知らないうちにメイプルキノコを組み敷いてしまったよ… 怒られて当然だよね。 でもさ、だからといって一斉で攻撃してくることないんじゃない? 本当に怖いやつらだよ。スライムたちが苦戦するのも分かっちゃうなぁ。 でも、このピンクビーン様がやっつけたからもう心配要らないよ!スライムたちも仲間に加わったことだし、もっとテンション上げて素敵な森を冒険してみよう!", "journal_ellinia_no2_content": "冒険中に出会った友だち、ロイヤルフェアリーから最近エルナスに怖い噂が出回ってるって聞いたんだけど、なんだろう?今夜は友だちと家で遊ぶことになってるからその時に聞いてみよう。だって気になるんだもん~! しかし、何を着ていけばいいんだろう…最近太りすぎて着れる洋服がないんだよね… まぁ、私はいつでも可愛いからどんな洋服を着てもみんな喜ぶだろうけどね!", "journal_elnath_no1_title": "エルナス冒険日記 その1", "journal_elnath_no2_title": "エルナス冒険日記 その2", "journal_elnath_no1_content": "うわー! これが噂の雪ってやつかな?私が住んでいる村はいつでも春だから、雪を見るのは初めてなんだ。モンスターたちのせいでちゃんと見る余裕がなかったんだけど、今見たら世界中がこんなにも真っ白で冷たくなってるなんてビックリだよ!ふわふわでキラキラしてるから美味しそうだなぁと思ったんだけど、特に味はなかった… でもね、甘いチョコシロップをかけて食べたら美味しそうじゃない?少しだけ持っていきたいんだけど持っていける方法がなくて残念だね。", "journal_elnath_no2_content": "ペッペッペッ、間違えて石炭の粉を食べてしまったよ。あれもこれも全部悪いモンスターたちのせいだよ!逃げるなら静かに逃げればいいのに、石炭の粉を撒き散らしながら逃げるなんてね!おかげさまで私のツヤツヤで綺麗なピンク色の肌が汚れてちゃったじゃない!早くここを抜け出してお風呂に入りたい… いくら冒険が好きだと行っても、こんなに汚い格好をしたまま歩き回るのはこのピンクビーン様のプライドが許さないよ…", "bug_report_alert_msg": "貴重なご意見ありがとうございます。", "version_update_msg1": "最新バージョン(%1)を\nご利用いただけます。", "version_update_msg2": "エントリーハードウェアの最新バージョン(%1)を\nご使用いただけます。", "version_update_msg3": "いまアップデートしますか?", "select_the_hardware": "Select the hardware
that you would use in the lesson.", "select_hardware_button": "Select", "select_the_expansion_block": "Select the expansion block that you would use in the lesson.", "select_hardware_not_support_info": "ハードウェアブロックはオープンクラスに使用できない。", "select_hardware_not_support_info2": "少々お待ちください。", "select_expansion_block_button": "Select", "expansion_weather_description": "気温、降水量、PM10濃度など韓国の天気と関連したブロックをまとめたものです。", "expansion_festival_description": "国内地地方の様々な行事や祭りに関連するブロックをまとめたものです。", "expansion_translate_description": "Papagoを使って他の言語に翻訳できるブロックをまとめたものです。", "expansion_behaviorConductDisaster_description": "自然災害の発生時に国民が守らなければならない基本的な行動要領(国民安全処からの提供)", "expansion_behaviorConductLifeSafety_description": "生活安全のため、国民が守らなければならない基本的な行動要領(国民安全処からの提供)", "ai_utilize_tts_description": "nVoiceを使って色んな音声で文章を読むことができるブロックのまとめです。", "hardware_need_update_title": "ハードウエア接続ソフトアップデート", "hardware_need_update_content": "セキュリティアップデートに伴い、\nバージョン1.76以上をサポートしています。\nバージョンが1.76以下の場合は、\n「接続ソフトをダウンロード」から\nアップデートしてください。", "ai_utilize_audio_description": "マイクを利用して、音と音声を検出することができるブロックのコレクションです。", "ai_utilize_video_description": "カメラを利用して動きと方向値、そして撮影されるオブジェクトなどを認識できるブロック集です。" }; Lang.Users = { "auth_failed": "認証に失敗しました。", "birth_year": "生年", "birth_year_before_1990": "1990年以前", "edit_personal": "情報修正", "email": "メールアドレス", "email_desc": "新しいニュースや情報を得られるメールアドレス", "email_inuse": "すでに登録されたメールアドレスです", "email_match": "メールアドレスを正しく入力してください", "forgot_password": "パスワードをお忘れですか?", "job": "職業", "language": "言語", "name": "名前", "name_desc": "サイト内で表示される名前またはニックネーム", "name_not_empty": "名前を必ず入力してください", "password": "パスワード", "password_desc": "最低4文字以上の英数字、記号", "password_invalid": "パスワードが正しくありません", "password_long": "パスワードは4~20文字の英数字、記号で入力してください", "password_required": "パスワードは必須入力項目です", "project_list": "作品照会", "regist": "登録完了", "rememberme": "自動ログイン", "repeat_password": "パスワード確認", "repeat_password_desc": "パスワードをもう一度入力してください", "repeat_password_not_match": "パスワードが一致しません", "sex": "性別", "signup_required_for_save": "保存するには、ログインが必要です。", "username": "ID", "username_desc": "ログイン時に使用するID", "username_inuse": "すでに使用中のIDです", "username_long": "IDは4~20文字のアルファベットで入力してください", "username_unknown": "このユーザーは存在しません", "already_verified": "すでに認証済みのメールアドレスです。", "email_address_unavailable": "この認証メールは無効です。", "email_address_invalid_for_idpw": "無効なメールアドレスです。\n ID確認/パスワード再登録のメールを再発送してみて下さい。", "email_address_invalid_for_certification": "無効なメールアドレスです。\n 認証メールを再送して下さい。", "verification_complete": "メールアドレスの認証に成功しました。", "reset_password_mail_sent": "Email for password resetting has been sent. Please check your email.", "email_not_verified": "This email is not verified. Please verify your email to click 'Verifying email' first.", "verification_email_send_complete": "Verifying email has been sent. Please verify your email first.", "email_send_failed": "Sending email was failed. Please try again.", "email_not_exist": "This email does not exist.", "not_valid_email": "Please enter a correct type of email." }; Lang.Workspace = { "picture_rotation": "回転", "picture_size": "サイズ", "thickness": "太さ", "follow": "やってみる", "SaveWithPicture": "保存されていない図があります。保存しますか?", "RecursiveCallWarningTitle": "関数呼び出し制限", "RecursiveCallWarningContent": "一度に多くの関数が呼び出されました。関数の呼び出し回数を減らしてください。", "SelectShape": "移動", "SelectCut": "切り取り", "Pencil": "ペン", "Line": "直線", "Rectangle": "四角形", "Ellipse": "円", "Text": "テキストボックス", "Fill": "塗りつぶし", "Eraser": "クリア", "Magnifier": "拡大/縮小", "block_helper": "ブロックヘルプ", "new_project": "新しいプロジェクト", "add_object": "オブジェクトを追加する", "download_image_name": "entry_ブロック", "all": "すべて", "animal": "動物", "arduino_entry": "Program for connect to Arduino", "arduino_program": "Arduino program", "arduino_sample": "Sample code for Arduino", "arduino_driver": "Driver for arduino", "cannot_add_object": "実行中にはオブジェクトを追加できません。", "cannot_add_picture": "実行中には模様を追加できません。", "cannot_add_sound": "実行中にはサウンドを追加できません。", "cannot_add_expansion_block": "Cannot add expansion block while running a project.", "add_object_before_edit": "模様編集のために
オブジェクトを追加してください", "add_table_before_edit": "テーブルを追加してください。", "cannot_edit_click_to_stop": "実行中には修正できません。
クリックして停止する。", "cannot_open_private_project": "非公開作品は読み込めません。ホームに移動します。", "cannot_save_running_project": "実行中には保存できません。", "character_gen": "キャラクターを作成する", "check_runtime_error": "赤色で表示されたブロックを確認してください。", "check_browser_error": "IE/Safariではサポートしていないブロックです。", "check_microphone_error": "コンピューターにマイクが接続されていません", "check_webcam_error": "コンピューターにカメラが接続されていません", "context_download": "PCに保存", "context_duplicate": "コピー", "context_remove": "削除", "context_rename": "名前修正", "coordinate": "座標", "create_function": "関数を作成する", "direction": "移動方向(°)", "drawing": "直接描画", "enter_list_name": "新しいリストの名前を入力してください(10文字以下)", "enter_name": "新しい名前を入力してください", "enter_new_message": "新しい信号の名前を入力してください", "enter_variable_name": "新しい変数の名前を入力してください(10文字以下)", "family": "エントリーボットの家族", "fantasy": "ファンタジー/その他", "file_new": "新規", "file_open": "オンラインの作品を読み込む", "file_upload": "オフラインの作品を読み込む", "file_upload_login_check_msg": "オフライン作品を読み込むにはログインする必要があります。", "file_save": "保存する", "file_save_as": "コピーで保存する", "file_save_download": "マイコンピューターに保存する", "func": "関数", "function_create": "関数を作成する", "function_add": "関数追加", "interface": "インターフェイス", "landscape": "背景", "list": "リスト", "list_add_calcel": "リスト追加取消", "list_add_calcel_msg": "リスト追加を取り消しました。", "list_add_fail": "リスト追加失敗", "list_add_fail_msg1": "同名のリストがすでに存在します。", "list_add_fail_msg2": "リストの名前が適切ではありません。", "list_add_ok": "リスト追加完了", "list_add_ok_msg": "を追加しました。", "list_create": "リスト追加", "list_create_placeholder": "リスト名を入力してください。", "list_dup": "同名のリストがすでに存在します。", "list_newname": "新しい名前", "list_export": "書き出し", "list_import": "読み込み", "list_remove": "リスト削除", "list_rename": "リスト名変更", "list_rename_failed": "リスト名変更失敗", "list_rename_ok": "リストの名前の変更に成功しました。", "list_too_long": "リストの名前が長すぎます。", "message": "信号", "message_add_cancel": "信号追加取消", "message_add_cancel_msg": "信号追加を取り消しました。", "message_add_fail": "信号追加失敗", "message_add_fail_msg": "同名の信号がすでに存在します。", "message_add_ok": "信号追加完了", "message_add_ok_msg": "を追加しました。", "message_create": "信号追加", "message_create_placeholder": "信号名を入力してください。", "message_dup": "同名の信号がすでに存在します。", "message_remove": "信号削除", "message_remove_canceled": "信号削除を取り消しました。", "message_rename": "信号名を変更しました。", "message_rename_failed": "信号名の変更に失敗しました。", "message_rename_ok": "信号の名前の変更に成功しました。", "message_too_long": "信号の名前が長すぎます。", "no_message_to_remove": "削除する信号がありません。", "no_use": "使われていません。", "no_variable_to_remove": "削除する変数がありません。", "no_variable_to_rename": "変更する変数がありません。", "object_not_found": "ブロックで指定したオブジェクトが存在しません。", "object_not_found_for_paste": "ペーストするオブジェクトがありません。", "people": "一般人", "picture_add": "模様追加", "table_add": "テーブルを追加する", "draw_new_table": "新しいテーブル", "plant": "植物", "project": "作品", "project_copied": "のコピー", "PROJECTDEFAULTNAME": ['おしゃれな', '面白い', '善良な', '大きい', '立派な', 'イケメンな', '幸運の'], "remove_object": "オブジェクト削除", "remove_object_msg": "が削除されました。", "removed_msg": "の削除に成功しました。", "rotate_method": "回転方式", "rotation": "方向(°)", "run": "スタート", "saved": "保存完了", "saved_msg": "が保存されました。", "save_failed": "保存中に問題が発生しました。もう一度やり直してください。", "select_library": "オブジェクト選択", "select_sprite": "適用するスプライトを1つ以上選択してください。", "shape_remove_fail": "模様削除失敗", "shape_remove_fail_msg": "最低1つ以上の模様がなければなりません。", "shape_remove_ok": "模様が削除されました。", "shape_remove_ok_msg": "が削除されました。", "load_expansion_block": "拡張ブロック追加する", "load_ai_utilize_block": "AIブロックの読み込み", "load_ai_utilize_train_block": "鉄道模型", "select_expansion_block": "Select block", "deselect_expansion_block_warning": "The selected block cannot be deleted. \nThe specified block is currently in use.", "deselect_ai_utilize_block_warning": "The selected block cannot be deleted. \nThe specified block is currently in use.", "sound_add": "サウンド追加", "sound_remove_fail": "サウンド削除失敗", "sound_remove_ok": "サウンド削除完了", "sound_remove_ok_msg": "が削除されました。", "stop": "停止する", "pause": "一時停止", "restart": "再スタート", "speed": "速度を調節する", "tab_attribute": "属性", "tab_table": "テーブル", "tab_code": "ブロック", "tab_picture": "形", "tab_sound": "サウンド", "tab_text": "テキストボックス", "textbox": "テキストボックス", "textbox_edit": "テキストボックス編集", "textbox_input": "テキストボックスの内容を入力してください。", "things": "物", "textcoding_tooltip1": "ブロックコーディングとエントリーパイソンを
選択して自由に
コーディングに挑戦することができます。", "textcoding_tooltip2": "実際の開発環境と同様に
エントリーパイソンモードの実行結果を
確認できます。", "textcoding_tooltip3": "エントリーパイソンに対する
基本的な内容を案内しています
<エントリーパイソン利用案内>を確認してください!", "upload": "ファイルアップロード", "upload_addfile": "ファイル追加", "variable": "変数", "variable_add_calcel": "変数追加取消", "variable_add_calcel_msg": "変数追加を取り消しました。", "variable_add_fail": "変数追加失敗", "variable_add_fail_msg1": "同名の変数がすでに存在します。", "variable_add_fail_msg2": "変数の名前が適切ではありません。", "variable_add_ok": "変数追加完了", "variable_add_ok_msg": "を追加しました。", "variable_create": "変数を作成する", "variable_add": "変数追加", "variable_dup": "同名の変数がすでに存在します。", "variable_newname": "新しい名前", "variable_remove": "変数削除", "variable_remove_canceled": "変数削除を取り消しました。", "variable_rename": "変数名を変更します。", "variable_rename_failed": "変数名の変更に失敗しました。", "variable_rename_msg": "「変数の名前の変更に成功しました。」", "variable_rename_ok": "変数の名前の変更に成功しました。", "variable_select": "変数を選択してください", "variable_too_long": "変数の名前が長すぎます。", "open_analizy_data_import": "データ画面を開く", "vehicle": "乗り物", "add_object_alert_msg": "オブジェクトを追加してください", "add_object_alert": "警告", "create_variable_block": "変数を作成する", "create_list_block": "リストを作成する", "Variable_Timer": "ストップウォッチ", "Variable_placeholder_name": "変数名", "Message_placeholder_name": "Signal name", "Variable_property": "変数の属性", "Variable_placeholder_content": "変数名を入力してください。", "Variable_use_all_objects": "すべてのオブジェクトで使用", "Variable_use_this_object": "このオブジェクトで使用", "Variable_used_at_all_objects": "すべてのオブジェクトで使われている変数", "variable_create_normal": "일반 변수로 사용\n(작품에 저장)", "variable_create_cloud": "共有変数として使用\n(サーバーに保存)", "variable_create_real_time": "リアルタイム変数として使用\n(サーバーに保存)", "Variable_used_at_special_object": "特定のオブジェクトでのみ使われている変数", "Variable_used_objects": "使用されたオブジェクト", "draw_new": "新しく描画", "draw_new_ebs": "直接描画", "painter_file": "ファイル▼", "painter_file_save": "保存する", "painter_file_saveas": "新しい模様で保存", "new_picture": "新しい図", "painter_edit": "編集 ▼", "get_file": "インポート", "copy_file": "コピーする", "cut_picture": "切り取り", "paste_picture": "貼り付け", "remove_all": "すべて削除", "flip_horizontal": "左右反転", "flip_vertical": "上下反転", "regular": "普通", "bold": "太字", "font_underline": "下線", "font_tilt": "斜線", "font_cancel": "取り消し線", "font_color": "文字の色", "font_fill": "背景色", "font_family": "フォント", "align_left": "左揃え", "align_center": "中央揃え", "align_right": "右揃え", "italic": "斜体", "textStyle": "文字", "add_picture": "模様追加", "select_picture": "模様選択", "select_table": "テーブルを選択", "select_sound": "サウンド選択", "Size": "サイズ", "show_variable": "変数表示", "default_value": "基本値 ", "slide": "スライド", "min_value": "最小値", "max_value": "最大値", "number_of_list": "リスト項目数", "empty_of_list": "項目が追加されていません。", "use_all_objects": "すべてのオブジェクトに使用", "list_name": "リスト名", "list_property": "リストの属性", "list_used_specific_objects": "特定のオブジェクトでのみ使われているリスト", "List_used_all_objects": "すべてのオブジェクトで使われているリスト", "List_used_objects": "使用されたオブジェクト", "Scene_delete_error": "シーンは最低1つ以上なければなりません。", "Scene_add_error": "シーンは最大20件まで追加できます。", "replica_of_object": "のコピー", "will_you_delete_scene": "シーンは一度削除すると取り消すことができません。\n本当に削除しますか?", "will_you_delete_function": "関数は一度削除すると取り消すことができません。\n本当に削除しますか?", "duplicate_scene": "コピーする", "block_explain": "ブロック説明 ", "block_intro": "ブロックをクリックすると、ブロックに関する説明が表示されます。", "blocks_reference": "ブロック説明", "hardware_guide": "ハードウェア結合案内", "robot_guide": "ロボット連結案内", "python_guide": "エントリーパイソン利用案内", "show_list_workspace": "リスト表示", "list_create_normal": "リストとして使用\n(作品に保存)", "list_create_cloud": "共有リストとして使用\n(サーバーに保存されます)", "list_create_real_time": "リアルタイムリストとして使用\n(サーバーに保存)", "confirm_quit": "変更した内容を保存しませんでした。", "confirm_load_temporary": "保存されていない作品があります。開きますか?", "login_to_save": "ログイン後に保存してください。", "cannot_save_in_edit_func": "関数編集中には保存できません。", "new_object": "新しいオブジェクト", "arduino_connect": "", "arduino_connect_success": "", "confirm_load_header": "作品復旧", "uploading_msg": "アップロード中です。", "upload_fail_msg": "アップロードに失敗しました。
もう一度やり直してください。", "upload_not_supported_msg": "この形式には対応していません。", "upload_not_supported_file_msg": "このファイル形式には対応していません。", "file_converting_msg": "ファイル変換中です。", "file_converting_fail_msg": "ファイル変換に失敗しました。", "fail_contact_msg": "続けて問題が発生する場合は
entry@connect.or.krにお問い合わせください。", "saving_msg": "保存中です。", "saving_fail_msg": "保存に失敗しました。
もう一度やり直してください。", "loading_msg": "読み込み中です。", "loading_fail_msg": "読み込みに失敗しました。
もう一度やり直してください。", "restore_project_msg": "正常に保存されていない作品があります。この作品を復旧しますか?", "quit_stop_msg": "保存中は終了できません。", "ent_drag_and_drop": "アップロードしたいファイルをドロップしてください。", "not_supported_file_msg": "このファイル形式には対応していません。", "broken_file_msg": "ファイルが壊れているか間違ったファイルを読み込みました。", "check_audio_msg": "mp3以外のオーディオファイルはプレイできません。", "check_entry_file_msg": "ENTファイルのみ読み込むことができます。", "hardware_version_alert_text": "5月30日から旧バージョンの結合プログラムの使用が中止されます。\nハードウェア結合プログラムを最新バージョンにアップデートしてください。", "variable_name_auto_edited_title": "変数名自動変更", "variable_name_auto_edited_content": "変数名は10文字を超過できません。", "list_name_auto_edited_title": "リスト名自動変更", "list_name_auto_edited_content": "リスト名は10文字を超過できません。", "cloned_scene": "コピー_", "default_mode": "基本型", "practical_course_mode": "教科型", "practical_course": "実科", "select_mode": "モード選択", "select_mode_popup_title": "エントリーを作成する環境を選択してください。", "select_mode_popup_lable1": "基本型", "select_mode_popup_lable2": "教科型", "select_mode_popup_desc1": "エントリーのすべての機能を利用して
自由に作品を制作します。", "select_mode_popup_desc2": "実科の教科書に登場する機能のみを
利用して作品を制作します。", "practical_course_notice": "案内", "practical_course_desc": "教科用を作成する
実科の教科書でソフトウェアを学ぶ時に
必要な機能のみを提供します。", "practical_course_desc2": "*「基本型の作品を作る」を利用すると、さらに多くの機能を
使用して作品を作ることができます。", "practical_course_tooltip": "すべての機能を利用するには
基本型を選択してください。", "name_already_exists": "名前が重複しています。", "enter_the_name": "名前を入力してください。", "object_not_exist_error": "オブジェクトが存在しません。オブジェクトを追加してからやり直してください。", "workspace_tutorial_popup_desc": "作品を作るでは
クリエイティブな作品づくりができるように
いろんなブロックを用意しています。", "start_guide_tutorial": "「作る」利用案内", "language": "言語選択", "file": "ファイル", "save": "保存する", "help": "ヘルプ", "print": "印刷", "undo": "元に戻す", "redo": "やり直し", "workspace_title_tooltip": "The default project name has changed. You can\nrecognize what project is through the date you create in\nthe project name.", "workspace_object_tooltip": "You can change the order of the object by\ndragging the image of the object. (It is the same\nin the ‘Shape’ and ‘Sound’ sections.)", "workspace_comment_tooltip": "You can hide or show all the memos\nadded.", "workspace_zoom_tooltip": "You can zoom in/out the blocks. If you click ‘=’\nthe block will be back to original size.", "workspace_image_tooltip": "Create your own\nproject with new\nfunctions!", "playground_block_drop": "マイボックスのブロックを\nブロック組み立て所に追加します。", "container_object_drop": "マイボックスのオブジェクトを\nオブジェクトリストに追加します。", "my_storage_block_drop": "ブロックを\nマイボックスに\n追加します。", "my_storage_object_drop": "オブジェクトを\nマイボックスに\n追加します。", "my_storage": "マイボックス", "my_block": "マイブロック", "red": "赤(R)", "green": "緑(G)", "blue": "青(B)", "hue": "色相", "saturation": "彩度", "brightness": "明度", "spoid": "スポイト", "palette_mode": "パレットモード", "slider_mode": "スライダーモード", "toast_error_title_object_center": "注意!", "toast_error_contents_object_center": "キャラクターの中心点がキャラクターから離れすぎため、修正しました。", "blocks_comming_soon": "熱心に研究中です。\nちょっと待ってください!", "data_table": "table", "select_all": "모두", "now_loading_msg": "読み込んでいます。\nしばらくお待ちください。" }; Lang.code = "コードを見る"; Lang.EntryStatic = { "event100": "イベント", "groupProject": "クラスを共有する", "usage_parallel": "並列", "usage_expansion": "Expansion", "usage_hw": "ハードウェア", "usage_sequence": "順次", "privateProject": "自分だけ見る", "privateCurriculum": "自分だけ見る", "publicCurriculum": "講義集を共有する", "publicProject": "作品を共有する", "group": "クラスを共有する", "groupCurriculum": "クラスを共有する", "private": "自分だけ見る", "public": "講義を共有する", "lecture_is_open_true": "公開", "lecture_is_open_false": "非公開", "category_all": "すべての作品", "category_game": "ゲーム", "category_animation": "アニメーション", "category_media_art": "メディアアート", "category_physical": "フィジカル", "category_etc": "その他", "category_category_game": "ゲーム", "category_category_animation": "アニメーション", "category_category_media_art": "メディアアート", "category_category_physical": "フィジカル", "category_category_etc": "その他", "sort_created": "最新順", "sort_updated": "最新順", "sort_visit": "照会順", "sort_likeCnt": "いいね!順", "sort_comment": "コメント順", "period_all": "すべての期間", "period_1": "今日", "period_7": "1週間以内", "period_30": "1か月以内", "period_90": "3か月以内", "lecture_required_time_1": " ~ 15分", "lecture_required_time_2": "15分 ~ 30分", "lecture_required_time_3": "30分 ~ 45分", "lecture_required_time_4": "45分 ~ 60分", "lecture_required_time_5": "1時間以上", "usage_event": "イベント", "usage_signal": "信号を送る", "usage_scene": "シーン", "usage_repeat": "繰り返す", "usage_condition_repeat": "条件繰り返し", "usage_condition": "選択", "usage_clone": "コピー", "usage_rotation": "回転", "usage_coordinate": "座標移動", "usage_arrow_move": "矢印移動", "usage_shape": "模様", "usage_speak": "話す", "usage_picture_effect": "図の効果", "usage_textBox": "テキストボックス", "usage_draw": "描画", "usage_sound": "サウンド", "usage_confirm": "判断", "usage_comp_operation": "比較演算", "usage_logical_operation": "論理演算", "usage_math_operation": "数理演算", "usage_random": "乱数", "usage_timer": "ストップウォッチ", "usage_variable": "変数", "usage_list": "リスト", "usage_ask_answer": "入出力", "usage_function": "関数", "usage_arduino": "Arduino", "concept_resource_analytics": "資料収集/分析/表現", "concept_procedual": "アルゴリズムと手順", "concept_abstractive": "抽象化", "concept_individual": "問題分解", "concept_automation": "自動化", "concept_simulation": "シミュレーション", "concept_parallel": "並列化", "subject_korean": "国語", "subject_english": "英語", "subject_mathmatics": "数学", "subject_social": "社会", "subject_science": "科学", "subject_music": "音楽", "subject_paint": "美術", "subject_athletic": "体育", "subject_courtesy": "道徳", "subject_progmatic": "実科", "lecture_grade_1": "小1", "lecture_grade_2": "小2", "lecture_grade_3": "小3", "lecture_grade_4": "小4", "lecture_grade_5": "小5", "lecture_grade_6": "小6", "lecture_grade_7": "中1", "lecture_grade_8": "中2", "lecture_grade_9": "中3", "lecture_grade_10": "一般", "lecture_level_1": "簡単", "lecture_level_2": "普通", "lecture_level_3": "難しい", "listEnable": "リスト", "functionEnable": "関数", "messageEnable": "信号", "objectEditable": "オブジェクト", "pictureeditable": "模様", "sceneEditable": "シーン", "soundeditable": "サウンド", "variableEnable": "変数", "e_1": "小学校1年生", "e_2": "小学校2年生", "e_3": "小学校3年生", "e_4": "小学校4年生", "e_5": "小学校5年生", "e_6": "小学校6年生", "m_1": "中学校1年生", "m_2": "中学校2年生", "m_3": "中学校3年生", "general": "一般", "curriculum_is_open_true": "公開", "curriculum_open_false": "非公開", "contest2019": "Contest", "exhibit": "Contest", "notice": "お知らせ", "qna": "Q&A", "tips": "ノウハウ&TIP", "free": "自由掲示板", "report": "提案と意見", "art_category_all": "すべての作品", "art_category_game": "ゲーム", "art_category_animation": "アニメーション", "art_category_physical": "フィジカル", "art_category_etc": "その他", "art_category_media": "メディアアート", "art_sort_updated": "最新順", "art_sort_visit": "照会順", "art_sort_likeCnt": "いいね!順", "art_sort_comment": "コメント順", "art_period_all": "すべての期間", "art_period_day": "今日", "art_period_week": "1週間以内", "art_period_month": "1か月以内", "art_period_three_month": "3か月以内", "level_high": "上", "level_mid": "中", "level_row": "下", "discuss_sort_created": "最新順", "discuss_sort_visit": "照会順", "discuss_sort_likesLength": "いいね!順", "discuss_sort_commentsLength": "コメント順", "discuss_period_all": "すべての期間", "discuss_period_day": "今日", "discuss_period_week": "1週間以内", "discuss_period_month": "1か月以内", "discuss_period_three_month": "3か月以内" }; Lang.Helper = { "when_run_button_click": "スタートボタンをクリックすると、下に連結されたブロックを実行します。", "when_some_key_pressed": "指定されたキーを押すと、下に連結されたブロックを実行します", "mouse_clicked": "マウスをクリックした時、下に連結されたブロックを実行します。", "mouse_click_cancled": "マウスクリックを解除した時、下に連結されたブロックを実行します。", "when_object_click": "当該オブジェクトをクリックした時、下に連結されたブロックを実行します。", "when_object_click_canceled": "当該オブジェクトクリックを解除した時、下に連結されたブロックを実行します。", "when_message_cast": "当該信号を受け取ると、連結されたブロックを実行します。", "message_cast": "リストに選択された信号を送ります。", "message_cast_wait": "リストに選択された信号を送り、その信号を受け取るブロックの実行が終わるまで待機します。", "when_scene_start": "シーンが始まると下に連結されたブロックを実行します。", "start_scene": "選択したシーンを始めます。", "start_neighbor_scene": "前のシーンまたは次のシーンを始めます。", "wait_second": "設定した時間だけ待機した後、次のブロックを実行します。", "repeat_basic": "設定した回数だけ包んであるブロックを繰り返し実行します。", "repeat_inf": "包んであるブロックを続けて繰り返し実行します。", "repeat_while_true": "判断がtrueの間、包んであるブロックを繰り返し実行します。", "stop_repeat": "このブロックを包む最も近いリピートブロックの繰り返しを中断します。", "_if": "もし判断がtrueの場合、包んであるブロックを実行します。", "if_else": "判断がtrueの場合、最初の包んであるブロックを実行し、Falseなら2番目の包んであるブロックを実行します。", "restart_project": "すべてのオブジェクトを最初から再実行します。", "stop_object": "すべての: すべてのオブジェクトが直ちに実行を中断します。
自分 : 当該オブジェクトのすべてのブロックを中断します。
このコード: このブロックが含まれるコードが直ちに実行を中断します。
自分の他のコード: 当該オブジェクトのうち、このブロックが含まれるコードを除くすべてのコードが直ちに実行を中断します。
他のオブジェクトの: 他のオブジェクトのすべてのブロックを中断します。", "wait_until_true": "判断がtrueになるまで実行を中断して待機します。", "when_clone_start": "当該オブジェクトのコピーが新しく作成された時、下に連結されたブロックを実行します。", "create_clone": "選択したオブジェクトのコピーを作成します。", "delete_clone": "「コピーが最初に作成された時」ブロックを一緒に使用して作成されたコピーを削除します。", "remove_all_clones": "当該オブジェクトのすべてのコピーを削除します。", "move_direction": "設定した値だけオブジェクトの移動方向矢印が示す方向に動きます。", "move_x": "オブジェクトのX座標を設定した値だけ変更します。", "move_y": "オブジェクトのY座標を設定した値だけ変更します。", "move_xy_time": "オブジェクトが入力した時間に渡り、xとy座標を設定した値だけ変更します。", "locate_object_time": "オブジェクトが入力した時間に渡り、選択したオブジェクトまたはマウスポインターの位置に移動します。(オブジェクトの中心点が基準になります。)", "locate_x": "オブジェクトが入力したx座標に移動します。(オブジェクトの中心点が基準になります。)", "locate_y": "オブジェクトが入力したy座標に移動します。(オブジェクトの中心点が基準になります。)", "locate_xy": "オブジェクトが入力したxとy座標に移動します。(オブジェクトの中心点が基準になります。)", "locate_xy_time": "オブジェクトが入力した時間に渡り、指定したx, y座標に移動します。(オブジェクトの中心点が基準になります。)", "locate": "オブジェクトが選択したオブジェクトまたはマウスポインターの位置に移動します。(オブジェクトの中心点が基準になります。)", "rotate_absolute": "当該オブジェクトの方向を入力した角度にします。", "rotate_by_time": "オブジェクトの方向を入力した時間に渡り、入力した角度だけ時計方向に回転します。(オブジェクトの中心点を基準に回転します。)", "rotate_relative": "オブジェクトの方向を入力した角度だけ時計方向に回転します。(オブジェクトの中心点を基準に回転します。)", "direction_absolute": "当該オブジェクトの移動方向を入力した角度にします。", "direction_relative": "オブジェクトの移動方向を入力した角度だけ回転します。", "move_to_angle": "設定した角度方向に入力した値だけ動きます。(実行画面の上側が0度、時計方向に行くたびに角度増加)", "see_angle_object": "当該オブジェクトが他のオブジェクトまたはマウスポインターの方向を向きます。オブジェクトの移動方向が選択された項目を向くようにオブジェクトの方向を回転させます。", "bounce_wall": "当該オブジェクトが画面の端に到達すると弾かれます。", "show": "当該オブジェクトを画面に表示します。", "hide": "当該オブジェクトを画面から非表示にします。", "dialog_time": "オブジェクトが入力した内容を入力した時間中吹き出しで話した後、次のブロックが実行されます。", "dialog": "オブジェクトが入力した内容を吹き出しで話すと同時に次のブロックが実行されます。", "remove_dialog": "オブジェクトが話している吹き出しを消します。", "change_to_some_shape": "オブジェクトを選択した模様に変更します。(内部ブロックを分離すれば模様の番号を使用して模様を選択できます)", "change_to_next_shape": "オブジェクトの模様を次の模様に変更します。", "set_effect_volume": "当該オブジェクトで選択した効果を入力した値だけ加えます。", "set_effect_amount": "色 : オブジェクトに色効果を入力した値だけ加えます。(0~100を周期に反復)
明度 : オブジェクトに明度効果を入力した値だけ加えます。(-100~100の範囲。-100以下は-100で、100以上は100で処理)
透明度 : オブジェクトに透明度効果を入力した値だけ加えます。(0~100の範囲。0以下は0で、100以上は100で処理)", "set_effect": "当該オブジェクトの値を選択した効果を入力した値にします。", "set_entity_effect": "当該オブジェクトの値を選択した効果を入力した値にします。", "add_effect_amount": "当該オブジェクトに対し選択した効果を入力した値だけ加えます。", "change_effect_amount": "色 : オブジェクトの色効果を入力した値にします。(0~100を周期として反復)
明度 : オブジェクトの明度効果を入力した値にします。(-100~100の間の範囲。-100以下は-100で、100以上は100で処理)
透明度 : オブジェクトの透明度効果を入力した値にします。(0~100の間の範囲。0以下は0で、100以上は100で処理)", "change_scale_percent": "当該オブジェクトのサイズを入力した値だけ変更します。", "set_scale_percent": "当該オブジェクトのサイズを入力した値にします。", "change_scale_size": "当該オブジェクトのサイズを入力した値だけ変更します。", "set_scale_size": "当該オブジェクトのサイズを入力した値にします。", "flip_x": "当該オブジェクトの上下の模様を入れ替えます。", "flip_y": "当該オブジェクトの左右の模様を入れ替えます。", "change_object_index": "一番前に : 当該オブジェクトを画面の一番前に移動させます。
前に : 当該オブジェクトを1レイヤー前に移動させます。
後ろに : 当該オブジェクトを1レイヤー後ろに移動させます。
一番後ろに : 当該オブジェクトを画面の一番後ろに移動させます。", "set_object_order": "当該オブジェクトが設定した順序で上がります。", "brush_stamp": "オブジェクトの模様を実行画面上にスタンプのように押します。", "start_drawing": "オブジェクトが移動する経路に沿って線を引きます。(オブジェクトの中心点が基準)", "stop_drawing": "オブジェクトが線を描くのを中断します。", "set_color": "オブジェクトが描く線の色を選択した色にします。", "set_random_color": "オブジェクトが描く線の色をランダムにします。", "change_thickness": "オブジェクトが描く線の太さを入力した値に変更します。(1~無限の範囲。1以下は1で処理)", "set_thickness": "オブジェクトが描く線の太さを入力した値にします。(1~無限の範囲。1以下は1で処理)", "change_opacity": "当該オブジェクトが描く筆の透明度を入力した値だけ変更します。", "change_brush_transparency": "当該オブジェクトが描く筆の透明度を入力した値だけ変更します。(0~100の範囲。0以下は0、100以上は100で処理)", "set_opacity": "当該オブジェクトが描く筆の透明度を入力した値にします。", "set_brush_tranparency": "当該オブジェクトが描く筆の透明度を入力した値にします。(0~100の範囲。0以下は0、100以上は100で処理)", "brush_erase_all": "当該オブジェクトが描いた線とスタンプをすべて削除します。", "sound_something_with_block": "当該オブジェクトが選択したサウンドを再生すると同時に、次のブロックを実行します。", "sound_something_second_with_block": "当該オブジェクトが選択したサウンドを入力した時間だけ再生すると同時に、次のブロックを実行します。", "sound_something_wait_with_block": "当該オブジェクトが選択したサウンドを再生し、サウンドの再生が終わると次のブロックを実行します。", "sound_something_second_wait_with_block": "当該オブジェクトが選択したサウンドを入力した時間だけ再生し、サウンドの再生が終わると次のブロックを実行します。", "sound_volume_change": "作品で再生されるすべてのサウンドのボリュームを入力したパーセント分変更します。", "sound_volume_set": "作品で再生されるすべてのサウンドのボリュームを入力したパーセントにします。", "sound_silent_all": "現在再生中のすべてのサウンドをストップします。", "is_clicked": "マウスをクリックした場合、「true」と判断します。", "is_press_some_key": "選択したキーが押されている場合、「true」と判断します。", "reach_something": "当該オブジェクトが選択した項目に触れた場合、「true」と判断します。", "is_included_in_list": "選択したリストに入力した値を持つ項目が含まれているか確認します。", "boolean_basic_operator": "= : 左側に位置する値と右側に位置する値が同じなら「true」と判断します。
> : 左側に位置する値が右側に位置する値より大きいなら「true」と判断します。
< : 左側に位置する値が右側に位置する値より小さいなら「true」と判断します。
≥ : 左側に位置する値が右側に位置する値より大きいか同じなら「true」と判断します。
≤ : 左側に位置する値が右側に位置する値より小さいか同じなら「true」と判断します。", "function_create": "よく使うコードをこのブロック下に並べて組み立てて関数として作成します。[関数を定義する]の右側の空白セルに[名前]を並べて関数名を決めることができます。関数を実行する際に入力値が必要な場合、空白セルに[文字/数字値]、[判断値]を並べて媒介変数として使用します。", "function_field_label": "「関数を定義する」の空白セル中に組み立て、名前を入力して関数名を決定します。", "function_field_string": "当該関数を実行するにあたり文字/数字値が必要な場合、空白セルの中に並べて媒介変数として使用します。このブロック内部の[文字/数字値]を分離して関数のコードのうち必要な部分に入れて使用します。", "function_field_boolean": "当該関数を実行するにあたりtrueまたはfalseの判断が必要な場合、空白セルの中に並べて媒介変数として使用します。このブロック内部の[判断値]を分離して関数のコードのうち必要な部分に入れて使用します。", "function_general": "現在作成している関数ブロックまたは今まで作成しておいた関数ブロックです。", "boolean_and": "2つの判断がすべてtrueの場合、「true」と判断します。", "boolean_or": "2つの判断のうち1つでもtrueがある場合、「true」と判断します。", "boolean_not": "判断がTrueならfalse、Falseならtrueにします。", "is_boost_mode": "ブーストモードがオンになっている場合は「正しい」で判断します。", "calc_basic": "+ : 入力した2つの数を足した値です。
- : 入力した2つの数を引いた値です。
X : 入力した2つの数をかけた値です。
/ : 入力した2つの数を割った値です。", "calc_rand": "入力した2つの数の間から選択された乱数の値です。(2つの数とも整数を入力した場合は整数が、2つの数のうち1つでも少数を入力した場合は少数が乱数として選択されます。)", "get_x_coordinate": "当該オブジェクトのx座標値を表します。", "get_y_coordinate": "当該オブジェクトのy座標値を表します。", "coordinate_mouse": "マウスポインターのxまたはyの座標値を表します。", "coordinate_object": "選択したオブジェクトまたは自分の各種情報値(x座標、y座標、方向、移動方向、サイズ、模様番号、模様名)です。", "quotient_and_mod": "商 : 前の数で後ろの数を割って得られた商の値です。
あまり : 前の数で後ろの数を割って得られたあまりの値です。", "get_rotation_direction": "当該オブジェクトの方向値、移動方向値を表します。", "calc_share": "前の数で後ろの数を割って得られた商を表します。", "calc_mod": "前の数で後ろの数を割って得られたあまりを表します。", "calc_operation": "入力した数に関する様々な数学式の計算値です。", "get_date": "現在の年度、月、日、時刻などの時間に関する値です。", "distance_something": "自分と選択したオブジェクトまたはマウスポインター間の距離の値です。", "get_sound_duration": "選択したサウンドの長さ(秒)の値です。", "get_user_name": "作品を実行しているユーザーのIDの値です。", "get_nickname": "作品をプレーしているユーザーのニックネーム値です。", "get_project_timer_value": "このブロックが実行された瞬間、ストップウォッチに保存された値です。", "choose_project_timer_action": "スタート: ストップウォッチを始めます。
停止する: ストップウォッチを停止します。
初期化する: ストップウォッチの値を0に初期化します。
(このブロックをブロック組立所に持っていくと、実行画面に「ストップウォッチウィンドウ」が作成されます。)", "reset_project_timer": "実行されていたタイマーを0に初期化します。", "set_visible_project_timer": "ストップウォッチウィンドウを画面で表示または非表示にします。", "ask_and_wait": "当該オブジェクトが入力した文字を吹き出しで尋ね、回答の入力を受けます。(このブロックをブロック組立所に持っていくと、実行画面に「回答ウィンドウ」が作成されます。)", "get_canvas_input_value": "尋ねて待機により入力された値です。", "set_visible_answer": "実行画面にある「回答ウィンドウ」を表示または非表示にできます。", "combine_something": "入力した2つの資料を結合した値です。", "get_variable": "選択された変数に保存された値です。", "change_variable": "選択した変数に入力した値を足します。", "set_variable": "選択した変数の値を入力した値にします。", "robotis_carCont_sensor_value": "왼쪽 접속 센서 : 접촉(1), 비접촉(0) 값 입니다.
오른쪽 접촉 센서 : 접촉(1), 비접촉(0) 값 입니다.
선택 버튼 상태 : 접촉(1), 비접촉(0) 값 입니다.
최종 소리 감지 횟수 : 마지막 실시간 소리 감지 횟수 값 입니다.
실시간 소리 감지 횟수 : 약 1초 안에 다음 소리가 감지되면 1씩 증가합니다.
왼쪽 적외선 센서 : 물체와 가까울 수록 큰 값 입니다.
오른쪽 적외선 센서 : 물체와 가까울 수록 큰 값 값 입니다.
왼쪽 적외선 센서 캘리브레이션 값 : 적외선 센서의 캘리브레이션 값 입니다.
오른쪽 적외선 센서 캘리브레이션 값 : 적외선 센서의 캘리브레이션 값 입니다.
(*캘리브레이션 값 - 적외선센서 조정 값)", "robotis_carCont_cm_led": "4개의 LED 중 1번 또는 4번 LED 를 켜거나 끕니다.
LED 2번과 3번은 동작 지원하지 않습니다.", "robotis_carCont_cm_sound_detected_clear": "최종 소리 감지횟 수를 0 으로 초기화 합니다.", "robotis_carCont_aux_motor_speed": "감속모터 속도를 0 ~ 1023 의 값(으)로 정합니다.", "robotis_carCont_cm_calibration": "적외선센서 조정 값(http://support.robotis.com/ko/: 자동차로봇> 2. B. 적외선 값 조정)을 직접 정합니다.", "robotis_openCM70_sensor_value": "최종 소리 감지 횟수 : 마지막 실시간 소리 감지 횟수 값 입니다.
실시간 소리 감지 횟수 : 약 1초 안에 다음 소리가 감지되면 1씩 증가합니다.
사용자 버튼 상태 : 접촉(1), 비접촉(0) 값 입니다.최종 소리 감지 횟수 : 마지막 실시간 소리 감지 횟수 값 입니다.
실시간 소리 감지 횟수 : 약 1초 안에 다음 소리가 감지되면 1씩 증가합니다.
사용자 버튼 상태 : 접촉(1), 비접촉(0) 값 입니다.", "robotis_openCM70_aux_sensor_value": "서보모터 위치 : 0 ~ 1023, 중간 위치의 값은 512 입니다.
적외선센서 : 물체와 가까울 수록 큰 값 입니다.
접촉센서 : 접촉(1), 비접촉(0) 값 입니다.
조도센서(CDS) : 0 ~ 1023, 밝을 수록 큰 값 입니다.
온습도센서(습도) : 0 ~ 100, 습할 수록 큰 값 입니다.
온습도센서(온도) : -20 ~ 100, 온도가 높을 수록 큰 값 입니다.
온도센서 : -20 ~ 100, 온도가 높을 수록 큰 값 입니다.
초음파센서 : -
자석센서 : 접촉(1), 비접촉(0) 값 입니다.
동작감지센서 : 동작 감지(1), 동작 미감지(0) 값 입니다.
컬러센서 : 알수없음(0), 흰색(1), 검은색(2), 빨간색(3), 녹색(4), 파란색(5), 노란색(6) 값 입니다.
사용자 장치 : 사용자 센서 제작에 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.", "robotis_openCM70_cm_buzzer_index": "음계를 0.1 ~ 5 초 동안 연주 합니다.", "robotis_openCM70_cm_buzzer_melody": "멜로디를 연주 합니다.
멜로디를 연속으로 재생하는 경우, 다음 소리가 재생되지 않으면 '흐름 > X 초 기다리기' 블록을 사용하여 기다린 후 실행합니다.", "robotis_openCM70_cm_sound_detected_clear": "최종 소리 감지횟 수를 0 으로 초기화 합니다.", "robotis_openCM70_cm_led": "제어기의 빨간색, 녹색, 파란색 LED 를 켜거나 끕니다.", "robotis_openCM70_cm_motion": "제어기에 다운로드 되어있는 모션을 실행합니다.", "robotis_openCM70_cm_autodrive_motor": "자율주행 자동차의 모터 포트를 지정합니다.", "robotis_openCM70_cm_autodrive_ir": "자율주행 자동차의 적외선 센서 포트를 지정합니다.", "robotis_openCM70_cm_autodrive_speed": "지정한 속도로 자율주행을 수행합니다.", "robotis_openCM70_aux_car_move": "로봇을 지정한 속도와 방향으로 움직이도록 합니다.", "robotis_openCM70_aux_motor_speed": "감속모터 속도를 0 ~ 100% 의 값으로 정합니다.", "robotis_openCM70_aux_servo_mode": "서보모터를 회전모드 또는 관절모드로 정합니다.
한번 설정된 모드는 계속 적용됩니다.
회전모드는 서보모터 속도를 지정하여 서보모터를 회전 시킵니다.
관절모드는 지정한 서보모터 속도로 서보모터 위치를 이동 시킵니다.", "robotis_openCM70_aux_servo_speed": "서보모터 속도를 0 ~ 100% 의 값으로 정합니다.", "robotis_openCM70_aux_servo_position": "서보모터 위치를 -150도 ~ 150도 의 값(으)로 정합니다.
서보모터 속도와 같이 사용해야 합니다.", "robotis_openCM70_aux_led_module": "LED 모듈의 LED 를 켜거나 끕니다.", "robotis_openCM70_aux_custom": "사용자 센서 제작에 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.", "robotis_openCM70_cm_poweroff_timer": "제어기의 자동꺼짐 타이머를 설정합니다.
설정된 만큼의 시간동안 통신이 진행되지 않으면 제어기는 자동으로 꺼집니다.", "robotis_openCM70_cm_custom_value": "컨트롤 테이블 주소를 직접 입력하여 값을 확인 합니다.
컨트롤 테이블 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.", "robotis_openCM70_cm_custom": "컨트롤 테이블 주소를 직접 입력하여 값을 정합니다.
컨트롤 테이블 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.", "show_variable": "選択した変数ウィンドウを実行画面に表示します。", "hide_variable": "選択した変数ウィンドウを実行画面で非表示にします。", "value_of_index_from_list": "選択したリストで選択した値の順序にある項目値を表します。(内部ブロックを分離すると順序を数字で入力できます)", "add_value_to_list": "入力した値が選択したリストの最後の項目に追加されます。", "remove_value_from_list": "選択したリストの入力した順序にある項目を削除します。", "insert_value_to_list": "選択したリストの入力した順序の位置に入力した項目を挿入します。(入力した項目の後にある各項目の順番は1つずつずれます。)", "change_value_list_index": "選択したリストで入力した順序にある項目の値を入力した値に変更します。", "length_of_list": "選択したリストが保有した項目の個数の値です。", "show_list": "選択したリストを実行画面に表示します。", "hide_list": "選択したリストを実行画面で非表示にします。", "text": "当該テキストボックスが表示している文字値を表します。", "text_read": "선택한 글상자 또는 글상자 자신의 내용입니다.
(내용 안에 줄바꿈이 있는 경우, 띄어쓰기하여 반환됩니다.)", "text_write": "テキストボックスの内容を入力した値に書き換えます。", "text_append": "テキストボックスの内容の後に入力した値を追加します。", "text_prepend": "テキストボックスの内容の前に入力した値を追加します。", "text_flush": "テキストボックスに保存された値をすべて削除します。", "erase_all_effects": "当該オブジェクトに適用された効果をすべて削除します。", "char_at": "入力した文字/数字値のうち入力した数字の 番目の文字値です。", "length_of_string": "入力した文字値のスペースを含む文字数です。", "substring": "入力した文字/数字値で入力した範囲内の文字/数字値です。", "replace_string": "入力した文字/数字値で指定した文字/数字値を探し、追加入力した文字/数字値にすべて置き換えた値です。(英文字で入力する場合、大文字と小文字を区別します。)", "index_of_string": "入力した文字/数字値で指定した文字/数字値が最初に登場する位置の値です。(やあ、エントリー!でエントリーの開始位置は5)", "change_string_case": "入力した英文字のすべてのアルファベットを大文字または小文字に置き換えた文字値を表します。", "direction_relative_duration": "当該オブジェクトの移動方向を入力した時間に渡り、入力した角度だけ時計方向に回転します。", "get_sound_volume": "現在、作品に設定されているサウンドのボリューム値を表します。", "sound_from_to": "当該オブジェクトが選択したサウンドを入力した時間部分だけ再生すると同時に次のブロックを実行します。", "sound_from_to_and_wait": "当該オブジェクトが選択したサウンドを入力した時間部分だけ再生し、サウンドの再生が終わると次のブロックを実行します。", "Block_info": "ブロック説明", "Block_click_msg": "ブロックをクリックすると、ブロックに関する説明が表示されます。", "hamster_beep": "버저 소리를 짧게 냅니다.", "hamster_change_both_wheels_by": "왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "hamster_change_buzzer_by": "버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.", "hamster_change_output_by": "선택한 외부 확장 포트의 현재 출력 값에 입력한 값을 더합니다. 더한 결과는 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH", "hamster_change_tempo_by": "연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.", "hamster_change_wheel_by": "왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "hamster_clear_buzzer": "버저 소리를 끕니다.", "hamster_clear_led": "왼쪽/오른쪽/양쪽 LED를 끕니다.", "hamster_follow_line_until": "왼쪽/오른쪽/앞쪽/뒤쪽의 검은색/하얀색 선을 따라 이동하다가 교차로를 만나면 정지합니다.", "hamster_follow_line_using": "왼쪽/오른쪽/양쪽 바닥 센서를 사용하여 검은색/하얀색 선을 따라 이동합니다.", "hamster_hand_found": "근접 센서 앞에 손 또는 물체가 있으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "hamster_move_backward_for_secs": "입력한 시간(초) 동안 뒤로 이동합니다.", "hamster_move_forward_for_secs": "입력한 시간(초) 동안 앞으로 이동합니다.", "hamster_move_forward_once": "말판 위에서 한 칸 앞으로 이동합니다.", "hamster_play_note_for": "선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.", "hamster_rest_for": "입력한 박자만큼 쉽니다.", "hamster_set_both_wheels_to": "왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "hamster_set_buzzer_to": "버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 버저 소리를 끕니다.", "hamster_set_following_speed_to": "선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.", "hamster_set_led_to": "왼쪽/오른쪽/양쪽 LED를 선택한 색깔로 켭니다.", "hamster_set_output_to": "선택한 외부 확장 포트의 출력 값을 입력한 값으로 설정합니다. 입력하는 값은 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH", "hamster_set_port_to": "선택한 외부 확장 포트의 입출력 모드를 선택한 모드로 설정합니다.", "hamster_set_tempo_to": "연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.", "hamster_set_wheel_to": "왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "hamster_stop": "양쪽 바퀴를 정지합니다.", "hamster_turn_for_secs": "입력한 시간(초) 동안 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.", "hamster_turn_once": "말판 위에서 왼쪽/오른쪽 방향으로 제자리에서 90도 회전합니다.", "hamster_value": "왼쪽 근접 센서: 왼쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
오른쪽 근접 센서: 오른쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
왼쪽 바닥 센서: 왼쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
오른쪽 바닥 센서: 오른쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.
밝기: 밝기 센서의 값 (값의 범위: 0 ~ 65535, 초기값: 0) 밝을 수록 값이 커집니다.
온도: 로봇 내부의 온도 값 (값의 범위: 섭씨 -40 ~ 88도, 초기값: 0)
신호 세기: 블루투스 무선 통신의 신호 세기 (값의 범위: -128 ~ 0 dBm, 초기값: 0) 신호의 세기가 셀수록 값이 커집니다.
입력 A: 외부 확장 포트 A로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)
입력 B: 외부 확장 포트 B로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)", "roboid_hamster_beep": "버저 소리를 짧게 냅니다.", "roboid_hamster_change_both_wheels_by": "왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "roboid_hamster_change_buzzer_by": "버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.", "roboid_hamster_change_output_by": "선택한 외부 확장 포트의 현재 출력 값에 입력한 값을 더합니다. 더한 결과는 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH", "roboid_hamster_change_tempo_by": "연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.", "roboid_hamster_change_wheel_by": "왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "roboid_hamster_clear_buzzer": "버저 소리를 끕니다.", "roboid_hamster_clear_led": "왼쪽/오른쪽/양쪽 LED를 끕니다.", "roboid_hamster_follow_line_until": "왼쪽/오른쪽/앞쪽/뒤쪽의 검은색/하얀색 선을 따라 이동하다가 교차로를 만나면 정지합니다.", "roboid_hamster_follow_line_using": "왼쪽/오른쪽/양쪽 바닥 센서를 사용하여 검은색/하얀색 선을 따라 이동합니다.", "roboid_hamster_hand_found": "근접 센서 앞에 손 또는 물체가 있으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "roboid_hamster_move_backward_for_secs": "입력한 시간(초) 동안 뒤로 이동합니다.", "roboid_hamster_move_forward_for_secs": "입력한 시간(초) 동안 앞으로 이동합니다.", "roboid_hamster_move_forward_once": "말판 위에서 한 칸 앞으로 이동합니다.", "roboid_hamster_play_note_for": "선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.", "roboid_hamster_rest_for": "입력한 박자만큼 쉽니다.", "roboid_hamster_set_both_wheels_to": "왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "roboid_hamster_set_buzzer_to": "버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 버저 소리를 끕니다.", "roboid_hamster_set_following_speed_to": "선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.", "roboid_hamster_set_led_to": "왼쪽/오른쪽/양쪽 LED를 선택한 색깔로 켭니다.", "roboid_hamster_set_output_to": "선택한 외부 확장 포트의 출력 값을 입력한 값으로 설정합니다. 입력하는 값은 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH", "roboid_hamster_set_port_to": "선택한 외부 확장 포트의 입출력 모드를 선택한 모드로 설정합니다.", "roboid_hamster_set_tempo_to": "연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.", "roboid_hamster_set_wheel_to": "왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "roboid_hamster_stop": "양쪽 바퀴를 정지합니다.", "roboid_hamster_turn_for_secs": "입력한 시간(초) 동안 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.", "roboid_hamster_turn_once": "말판 위에서 왼쪽/오른쪽 방향으로 제자리에서 90도 회전합니다.", "roboid_hamster_value": "왼쪽 근접 센서: 왼쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
오른쪽 근접 센서: 오른쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
왼쪽 바닥 센서: 왼쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
오른쪽 바닥 센서: 오른쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.
밝기: 밝기 센서의 값 (값의 범위: 0 ~ 65535, 초기값: 0) 밝을 수록 값이 커집니다.
온도: 로봇 내부의 온도 값 (값의 범위: 섭씨 -40 ~ 88도, 초기값: 0)
신호 세기: 블루투스 무선 통신의 신호 세기 (값의 범위: -128 ~ 0 dBm, 초기값: 0) 신호의 세기가 셀수록 값이 커집니다.
입력 A: 외부 확장 포트 A로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)
입력 B: 외부 확장 포트 B로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)", "roboid_turtle_button_state": "등 버튼을 클릭했으면/더블클릭했으면/길게 눌렀으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "roboid_turtle_change_buzzer_by": "버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.", "roboid_turtle_change_head_led_by_rgb": "머리 LED의 현재 R, G, B 값에 입력한 값을 각각 더합니다.", "roboid_turtle_change_tempo_by": "연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.", "roboid_turtle_change_wheel_by": "왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "roboid_turtle_change_wheels_by_left_right": "왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "roboid_turtle_clear_head_led": "머리 LED를 끕니다.", "roboid_turtle_clear_sound": "소리를 끕니다.", "roboid_turtle_cross_intersection": "검은색 교차로에서 잠시 앞으로 이동한 후 검은색 선을 찾아 다시 이동합니다.", "roboid_turtle_follow_line": "하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동합니다.", "roboid_turtle_follow_line_until": "하얀색 바탕 위에서 검은색 선을 따라 이동하다가 선택한 색깔을 컬러 센서가 감지하면 정지합니다.", "roboid_turtle_follow_line_until_black": "하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동하다가 컬러 센서가 검은색을 감지하면 정지합니다.", "roboid_turtle_is_color_pattern": "선택한 색깔 패턴을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "roboid_turtle_move_backward_unit": "입력한 거리(cm)/시간(초)/펄스만큼 뒤로 이동합니다.", "roboid_turtle_move_forward_unit": "입력한 거리(cm)/시간(초)/펄스만큼 앞으로 이동합니다.", "roboid_turtle_pivot_around_wheel_unit_in_direction": "왼쪽/오른쪽 바퀴 중심으로 입력한 각도(도)/시간(초)/펄스만큼 머리/꼬리 방향으로 회전합니다.", "roboid_turtle_play_note": "선택한 계이름과 옥타브의 음을 계속 소리 냅니다.", "roboid_turtle_play_note_for_beats": "선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.", "roboid_turtle_play_sound_times": "선택한 소리를 입력한 횟수만큼 재생합니다.", "roboid_turtle_play_sound_times_until_done": "선택한 소리를 입력한 횟수만큼 재생하고, 재생이 완료될 때까지 기다립니다.", "roboid_turtle_rest_for_beats": "입력한 박자만큼 쉽니다.", "roboid_turtle_set_buzzer_to": "버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 소리를 끕니다.", "roboid_turtle_set_following_speed_to": "선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.", "roboid_turtle_set_head_led_to": "머리 LED를 선택한 색깔로 켭니다.", "roboid_turtle_set_head_led_to_rgb": "머리 LED의 R, G, B 값을 입력한 값으로 각각 설정합니다.", "roboid_turtle_set_tempo_to": "연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.", "roboid_turtle_set_wheel_to": "왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "roboid_turtle_set_wheels_to_left_right": "왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "roboid_turtle_stop": "양쪽 바퀴를 정지합니다.", "roboid_turtle_touching_color": "선택한 색깔을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "roboid_turtle_turn_at_intersection": "검은색 교차로에서 잠시 앞으로 이동한 후 제자리에서 왼쪽/오른쪽/뒤쪽으로 회전하고 검은색 선을 찾아 다시 이동합니다.", "roboid_turtle_turn_unit_in_place": "입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.", "roboid_turtle_turn_unit_with_radius_in_direction": "입력한 반지름의 원을 그리면서 입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽, 머리/꼬리 방향으로 회전합니다.", "roboid_turtle_value": "색깔 번호: 컬러 센서가 감지한 색깔의 번호 (값의 범위: -1 ~ 8, 초기값: -1)
색깔 패턴: 컬러 센서가 감지한 색깔 패턴의 값 (값의 범위: -1 ~ 88, 초기값: -1)
바닥 센서: 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
버튼: 거북이 등 버튼의 상태 값 (누르면 1, 아니면 0, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.", "turtle_button_state": "등 버튼을 클릭했으면/더블클릭했으면/길게 눌렀으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "turtle_change_buzzer_by": "버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.", "turtle_change_head_led_by_rgb": "머리 LED의 현재 R, G, B 값에 입력한 값을 각각 더합니다.", "turtle_change_tempo_by": "연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.", "turtle_change_wheel_by": "왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "turtle_change_wheels_by_left_right": "왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "turtle_clear_head_led": "머리 LED를 끕니다.", "turtle_clear_sound": "소리를 끕니다.", "turtle_cross_intersection": "검은색 교차로에서 잠시 앞으로 이동한 후 검은색 선을 찾아 다시 이동합니다.", "turtle_follow_line": "하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동합니다.", "turtle_follow_line_until": "하얀색 바탕 위에서 검은색 선을 따라 이동하다가 선택한 색깔을 컬러 센서가 감지하면 정지합니다.", "turtle_follow_line_until_black": "하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동하다가 컬러 센서가 검은색을 감지하면 정지합니다.", "turtle_is_color_pattern": "선택한 색깔 패턴을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "turtle_move_backward_unit": "입력한 거리(cm)/시간(초)/펄스만큼 뒤로 이동합니다.", "turtle_move_forward_unit": "입력한 거리(cm)/시간(초)/펄스만큼 앞으로 이동합니다.", "turtle_pivot_around_wheel_unit_in_direction": "왼쪽/오른쪽 바퀴 중심으로 입력한 각도(도)/시간(초)/펄스만큼 머리/꼬리 방향으로 회전합니다.", "turtle_play_note": "선택한 계이름과 옥타브의 음을 계속 소리 냅니다.", "turtle_play_note_for_beats": "선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.", "turtle_play_sound_times": "선택한 소리를 입력한 횟수만큼 재생합니다.", "turtle_play_sound_times_until_done": "선택한 소리를 입력한 횟수만큼 재생하고, 재생이 완료될 때까지 기다립니다.", "turtle_rest_for_beats": "입력한 박자만큼 쉽니다.", "turtle_set_buzzer_to": "버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 소리를 끕니다.", "turtle_set_following_speed_to": "선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.", "turtle_set_head_led_to": "머리 LED를 선택한 색깔로 켭니다.", "turtle_set_head_led_to_rgb": "머리 LED의 R, G, B 값을 입력한 값으로 각각 설정합니다.", "turtle_set_tempo_to": "연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.", "turtle_set_wheel_to": "왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "turtle_set_wheels_to_left_right": "왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "turtle_stop": "양쪽 바퀴를 정지합니다.", "turtle_touching_color": "선택한 색깔을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "turtle_turn_at_intersection": "검은색 교차로에서 잠시 앞으로 이동한 후 제자리에서 왼쪽/오른쪽/뒤쪽으로 회전하고 검은색 선을 찾아 다시 이동합니다.", "turtle_turn_unit_in_place": "입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.", "turtle_turn_unit_with_radius_in_direction": "입력한 반지름의 원을 그리면서 입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽, 머리/꼬리 방향으로 회전합니다.", "turtle_value": "색깔 번호: 컬러 센서가 감지한 색깔의 번호 (값의 범위: -1 ~ 8, 초기값: -1)
색깔 패턴: 컬러 센서가 감지한 색깔 패턴의 값 (값의 범위: -1 ~ 88, 초기값: -1)
바닥 센서: 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
버튼: 거북이 등 버튼의 상태 값 (누르면 1, 아니면 0, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.", "neobot_sensor_value": "IN1 ~ IN3 포트 및 리모컨에서 입력되는 값 그리고 배터리 정보를 0부터 255의 숫자로 표시합니다.", "neobot_sensor_convert_scale": "선택한 포트 입력값의 변화를 특정범위의 값으로 표현범위를 조절할 수 있습니다.", "neobot_left_motor": "L모터 포트에 연결한 모터의 회전방향 및 속도를 설정합니다.", "neobot_stop_left_motor": "L모터 포트에 연결한 모터를 정지합니다.", "neobot_right_motor": "R모터 포트에 연결한 모터의 회전방향 및 속도를 설정합니다.", "neobot_stop_right_motor": "R모터 포트에 연결한 모터를 정지합니다.", "neobot_all_motor": "L모터 및 R모터 포트에 2개 모터를 연결하여 바퀴로 활용할 때 전, 후, 좌, 우 이동 방향 및 속도, 시간을 설정할 수 있습니다.", "neobot_stop_all_motor": "L모터 및 R모터에 연결한 모터를 모두 정지합니다.", "neobot_set_servo": "OUT1 ~ OUT3에 서보모터를 연결했을 때 0도 ~ 180도 범위 내에서 각도를 조절할 수 있습니다.", "neobot_set_output": "OUT1 ~ OUT3에 라이팅블록 및 전자회로를 연결했을 때 출력 전압을 설정할 수 있습니다.
0은 0V, 1 ~ 255는 2.4 ~ 4.96V의 전압을 나타냅니다.", "neobot_set_fnd": "FND로 0~99 까지의 숫자를 표시할 수 있습니다.", "neobot_set_fnd_off": "FND에 표시한 숫자를 끌 수 있습니다.", "neobot_play_note_for": "주파수 발진 방법을 이용해 멜로디에 반음 단위의 멜로디 음을 발생시킬 수 있습니다.", "rotate_by_angle_dropdown": "オブジェクトの方向を入力した角度だけ時計方向に回転します。(オブジェクトの中心点を基準に回転します。)", "chocopi_control_button": "버튼이 눌리면 참이 됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_control_event": "버튼을 누르거나 뗄 때 처리할 엔트리 블록들을 연결합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_control_joystick": "조이스틱 좌우, 상하, 볼륨의 값은 0~4095까지 입니다.
따라서 2047 근처가 중간이 됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_dc_motor": "DC모터 모듈에는 직류전동기 두개를 연결 할 수 있습니다.
직류 전동기는 최대 5V로 동작하게 됩니다.
값은 100이 최대(100%)이고 음수를 넣으면 반대 방향으로 회전합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_led": "LED번호는 LED블록에 연결된 순서이고 1번부터 시작합니다.
RGB값은 0~255사이의 값입니다.
빨강(Red),녹색(Green), 파랑(Blue)순서로 입력합니다.
밝은 LED를 직접보면 눈이 아프니까 값을 0~5정도로 씁니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_motion_photogate_event": "포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
빛센서를 물체로 가리거나 치우면 시작되는 엔트리 블록을 연결합니다
모션 모듈에는 포토게이트 2개를 연결할 수 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_motion_photogate_status": "포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
물체가 빛센서를 가리면 참이됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_motion_photogate_time": "포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
이 블록은 물체가 빛센서를 가리거나 벗어난 시간을 가집니다.
1/10000초까지 측정할 수 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_motion_value": "모션 모듈에는 3개의 적외선 센서가 있습니다.
0~4095사이의 값을 가질 수 있는데 물체가 빛을 많이 반사할 수록 작은 값을 가집니다.
거리를 대략적으로 측정할 수 있습니다.
가속도와 각가속도 값의 범위는 -32768~32767 까지입니다.
가속도를 이용해서 센서의 기울기를 측정할 수도 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_sensor": "온도 값은 섭씨 온도입니다.
습도 값은 백분율로 나타낸 상대습도 값입니다.
빛은 로그스케일로 0~4095사이입니다.
아날로그 값은 0~4095사이입니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_servo_motor": "서보모터 모듈에는 4개의 서보모터를 연결 할 수 있습니다.
서보모터는 5V로 동작하게 됩니다.
각도는 0~200도까지 지정할 수 있습니다.
연속회전식 서보모터를 연결하면 각도에 따라 속도가 변하게됩니다.
90~100 사이가 중간값입니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_touch_event": "터치 모듈에는 1~12번의 연결 패드가 있습니다.
만지거나 뗄 때 처리할 엔트리 블록들을 연결합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_touch_status": "터치 모듈의 패드를 만지면 참이됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_touch_value": "터치패드에 연결된 물체의 전기용량이 커지면 값이 작아집니다.
여러 명이 손잡고 만지면 더 작은 값이 됩니다.
전기용량이란 물체에 전기를 띈 입자를 얼마나 가지고 있을 수 있는 지를 말합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "boolean_and_or": "そして : 2つの判断がすべてtrueの場合、「true」と判断します。
または: 2つの判断のうち1つでもtrueがある場合、「true」と判断します。", "check_weather": "
선택한 날짜와 지역의 날씨 정보를 실제 날씨 상태와 비교하여 일치하는 경우 ‘참’으로 판단합니다.
* 옵션
날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
날씨: 맑음, 구름조금, 구름많음, 흐림, 비, 진눈깨비, 눈", "check_finedust": "
선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.
* 옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
미세먼지 등급: 좋음, 보통, 나쁨, 매우나쁨", "get_weather_data": "
선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.
* 옵션
날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
정보: 최저기온(℃), 최고기온(℃), 습도(%), 강수량(mm), 강수확률(%), 풍속(m/s)", "get_current_weather_data": "
현재 선택한 지역의 날씨 정보값(기온, 미세먼지농도)입니다.
* 옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
정보: (기온(℃)), 미세먼지농도(㎍)", "get_today_temperature": "
오늘 선택한 지역과 시간대의 기온을 의미합니다.
* 옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시간대: 00, 03, 06, 09, 12, 15, 18, 21", "check_city_weather": "
선택한 날짜와 지역의 날씨 정보를 실제 날씨 상태와 비교하여 일치하는 경우 ‘참’으로 판단합니다.
* 옵션
날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후
시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시군구: 시도별로 다름
날씨: 맑음, 구름조금, 구름많음, 흐림, 비, 진눈깨비, 눈", "check_city_finedust": "
선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.
* 옵션
시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시군구: 시도별로 다름
미세먼지 등급: 좋음, 보통, 나쁨, 매우나쁨", "get_city_weather_data": "
선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.
* 옵션
날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후
시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시군구: 시도별로 다름
정보: 최저기온(℃), 최고기온(℃), 습도(%), 강수량(mm), 강수확률(%), 풍속(m/s)", "get_current_city_weather_data": "
현재 선택한 지역의 날씨 정보값(기온, 미세먼지농도)입니다.
* 옵션
시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시군구: 시도별로 다름
정보: (기온(℃)), 미세먼지농도(㎍)", "get_today_city_temperature": "
오늘 선택한 지역과 시간대의 기온을 의미합니다.
* 옵션
시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시군구: 시도별로 다름
시간대: 00, 03, 06, 09, 12, 15, 18, 21", "count_festival": "
選択した日付と地域で開催されるイベントの数です。", "get_festival_info": "
選択した日付と地域で開催されるイベントの情報です。", "get_translated_string": "
入力されたテキストを選択した言語に翻訳します。テキストは3000字まで入力可能です。", "check_language": "
入力されたテキストの言語を検出します。テキストは文章の形で、3000字まで入力可能です。", "count_disaster_behavior": "
選択した自然災害が発生した時に取るべき行動要領の数です。", "get_disaster_behavior": "
選択した自然災害が発生した時に取るべき行動要領についての情報です。", "count_lifeSafety_behavior": "
選択した、生活トラブルが生じた時に取るべき行動要領の数です。", "get_lifeSafety_behavior": "
選択した、生活トラブルが生じた時に取るべき行動要領についての情報です。", "read_text": "入力した文字列を設定した音声で読み上げます。", "set_tts_property": "選択した音声が選択した速度と選択したピッチで設定されます。", "read_text_wait_with_block": "入力した文字列を設定した音声で読み上げし、読み上げが終わると次のブロックを実行します。", "check_microphone": "コンピューターにマイクが接続されている場合、「正」と判断します。", "speech_to_text_convert": "マイクへの音声入力をテキストに変換します。", "get_microphone_volume": "マイクに入力される音の大きさです。", "speech_to_text_get_value": "音声をテキストに変換した値を報告します。 音声が入力されない場合、または音声認識中にエラーが発生した場合、値は0になります。", "video_draw_webcam": "コンピューターに接続されたカメラの撮影画面を実行画面で表示または非表示にします。", "video_check_webcam": "コンピューターにカメラが接続されている場合、「正」と判断します。", "video_set_camera_option": "撮影画面の効果を入力した値に決めます。 明度:-100~100の間の範囲で設定できます。(-100以下は-100で、100以上は100で処理されます) 透明度:0~100の間の範囲で設定できます。(0以下は0で、100以上は100で処理されます)", "video_flip_camera": "撮影画面を左右または上下に反転させます。", "video_toggle_model": "選んだ認識モデールの作動を始めたり、止めたりします。 顔を認識: 人の顔を認識して、目、鼻、口、耳の位置や人の予想性別、歳、感情を分析します。 体を認識: 人の体を認識して、それぞれの身体部位などを分析します。 物を認識: 認識された物の種類を分析します。(人や物)", "video_toggle_ind": "認識され 人 / た顔 / 物事 の位置と順番を実行画面に表示または非表示にします。", "video_number_detect": "撮影画面にオブジェクトとして認識されたオブジェクトの数です。認識できるオブジェクト:人、自転車、自動車、オートバイ、飛行機、バス、電車、トラック、ボート、信号機、消火栓、停止信号、駐車メーター、ベンチ、鳥、猫、犬、馬、羊、雌牛、ゾウ、クマ、シマウマ、キリン、リュック、傘、ハンドバック、ネクタイ、かばん、フリスビー、スキー、スノーボード、スポーツボール、凧、野球バット、野球グローブ、スケートボード、サーフボード、テニスラケット、瓶、ワイングラス、コップ、フォーク、ナイフ、スプーン、皿、バナナ、アップル、サンドイッチ、オレンジ色、ブロッコリー、にんじん、ホットドッグ、ピザ、ドーナツ、ケーキ、椅子、ソファ、鉢植え、ベッド、食事テーブル、トイレ、テレビモニター、ノートパソコン、マウス、リモコン、キーボード、携帯電話、電子レンジ、オーブン、トースター、シンク、冷蔵庫、図書、時計、花瓶、はさみ、テディベア、ヘアドライヤー、歯ブラシ", "video_detected_face_info": "入力した順番の顔に関する選択した情報の推定値です。上手く認識できない場合、必ず0で出力されます。(性別、年齢、感情)", "video_motion_value": "選択したオブジェクトまたは実行画面上で感知されるモーション、もしくは方向値です。 モーション:動きが大きく速いほど値が大きくなります。 方向:右側もしくは上側に動くときは陽数、左側もしくは下側に動くときは陰数になります。", "video_face_part_coord": "入力した順番の顔の中で、選択した顔の部位の位置値です。上手く認識できない場合、必ず0で出力されます。(左眼、右眼、鼻、左口、右口,上唇,下唇)", "video_body_part_coord": "入力した順番の人に関して選択した身体部位の位置値です。(顔、左肩、左肘、左手首、左尻、左膝、左足首、右肩、右肘、右手首、右尻、右膝、右足首)", "append_row_to_table": "Adds a row(col) to the end location of the selected table.", "insert_row_to_table": "Inserts a row(col) to the location of the input value on the selected table.", "delete_row_from_table": "Deletes the row(col) at the location of input value from the selected table.", "set_value_from_table": "Replaces value of selected attribute at the location of the input value to the input value.", "get_table_count": "Reports the number of rows or attribute on the selected table.", "get_value_from_table": "Reports the value of selected attribute at the location of the input value from the selected table.", "calc_values_from_table": "Reports calculated value of the selected attributes in the selected table. (sum, maximum, minimum, average, standard deviation)", "open_table_chart": "Open the chart of the selected table.", "close_table_chart": "Close the table chart.", "get_coefficient": "Correlation coefficient between two attributes in the selected table. The closer the correlation coefficient is to 1(-1), the stronger the positive (negative) linear correlation." }; Lang.Category = { "entrybot_friends": "エントリーボットの友達", "people": "人", "animal": "動物", "animal_flying": "空", "animal_land": "地", "animal_water": "水", "animal_others": "その他", "plant": "植物", "plant_flower": "花", "plant_grass": "草", "plant_tree": "木", "plant_others": "その他", "vehicles": "乗り物", "vehicles_flying": "空", "vehicles_land": "地", "vehicles_water": "水", "vehicles_others": "その他", "architect": "建物", "architect_building": "建築物", "architect_monument": "記念物", "architect_others": "その他", "food": "食べ物", "food_vegetables": "果物/野菜", "food_meat": "肉", "food_drink": "飲み物", "food_others": "その他", "environment": "環境", "environment_nature": "自然", "environment_space": "宇宙", "environment_others": "その他", "stuff": "物", "stuff_living": "生活", "stuff_hobby": "趣味", "stuff_others": "その他", "fantasy": "ファンタジー", "interface": "インターフェイス", "interface_website": "ウェブサイト", "interface_game": "ゲーム", "interface_others": "その他", "background": "背景", "background_outdoor": "室外", "background_indoor": "室内", "background_nature": "自然", "background_others": "その他" }; Lang.Device = { "arduino": "arduino", "hamster": "hamster", "roboid": "ロボイド", "turtle": "turtle", "albert": "albert", "robotis_carCont": "", "robotis_openCM70": "", "sensorBoard": "Entry Sensor Board", "trueRobot": "TrueTrueRobot", "CODEino": "CODEino", "bitbrick": "bitbrick", "creamo": "creamo", "playcode": "playcode", "funboard": "funboard", "bitBlock": "ビットブロック", "xbot_epor_edge": "XBOT", "dplay": "DPLAY", "iboard": "iboard", "nemoino": "NEMOino", "ev3": "EV3", "robotori": "robotori", "smartBoard": "smartBoard", "chocopi": "ChocoPi", "rokoboard": "rokoboard", "altino": "알티노", "mechatro": "mechatro" }; Lang.General = { "turn_on": "ON", "turn_off": "OFF", "left": "左側", "right": "右側", "param_string": "文字値", "both": "両側", "transparent": "透明", "black": "黒", "brown": "茶色", "red": "赤", "yellow": "黄色", "green": "緑", "skyblue": "水色", "blue": "青", "purple": "紫", "white": "白", "note_c": "ド", "note_d": "レ", "note_e": "ミ", "note_f": "ファ", "note_g": "ソ", "note_a": "ラ", "note_b": "シ", "questions": "問題", "clock": "時計", "counter_clock": "反時計", "font_size": "文字サイズ", "second": "秒", "alert_title": "通知", "confirm_title": "確認", "update_title": "アップデート通知", "recent_download": "今すぐアップデート", "recent_download2": "最新バージョンをダウンロード", "latest_version": "最新バージョンです。", "dont_show_again": "今後、この通知を表示しない" }; Lang.Fonts = { "jeju_hallasan": "漢拏山体", "gothic_coding": "コーディングゴシック体", "batang": "パタン体", "gothic": "ナヌムゴシック体", "myeongjo": "ナヌム明朝", "pen_script": "ナヌム手書き", "square_round": "ナヌム角丸体", "jalnan": "ジャルナン体", "designhouse": "デザインハウス体", "malssami815": "マルサミ815体", "dunggeunmo": "丸文字体", "hs_bombaram": "HSボムバラム体", "yisunshin": "イスンシン体", "goyang": "ゴヤン体", "flower_road": "サンサンフラワーロード体", "uhbeemysen": "アビーマイセン体", "sd_comic_stencil": "Sandoll コミックステンシル", "sd_childfundkorea": "Sandoll コドモノタメニ", "sd_cinema_theater": "Sandoll シネマゲキジョウ", "sd_mapssi": "Sandoll メッシ", "sd_shabang": "Sandoll ホシガキラキラ", "sd_woodcarving": "Sandoll キボリ", "sd_yongbi": "Sandoll ヨンビ" }; Lang.Hw = { "note": "音符", "leftWheel": "左車輪", "rightWheel": "右車輪", "leftEye": "左目", "rightEye": "右目", "led": "光", "led_en": "LED", "body": "本体", "front": "前", "port_en": " ", "port_ko": "番ポート", "sensor": "センサー", "light": "光", "temp": "温度", "switch_": "スイッチ", "right_ko": "右側", "right_en": " ", "left_ko": "左側", "left_en": " ", "up_ko": "上", "up_en": " ", "down_ko": "下", "down_en": " ", "output": "出力", "left": "左側", "right": "右側", "sub": "サーボ", "motor": "モーター", "": "", "buzzer": "ブーザー", "IR": "赤外線", "acceleration": "加速", "analog": "アナログ", "angular_acceleration": "角加速", "button": "ボタン", "humidity": "湿度", "joystick": "joystick", "port": "ポート", "potentiometer": "ポテンショメータ", "servo": "サーボ" }; Lang.template = { "albert_hand_found": "hand found?", "albert_is_oid_value": "%1 oid %2?", "albert_value": "%1", "albert_move_forward_for_secs": "move forward for %1 secs %2", "albert_move_backward_for_secs": "move backward for %1 secs %2", "albert_turn_for_secs": "turn %1 for %2 secs %3", "albert_change_both_wheels_by": "change wheels by left: %1 right: %2 %3", "albert_set_both_wheels_to": "set wheels to left: %1 right: %2 %3", "albert_change_wheel_by": "change %1 wheel by %2 %3", "albert_set_wheel_to": "set %1 wheel to %2 %3", "albert_stop": "stop %1", "albert_set_pad_size_to": "set board size to width: %1 height: %2 %3", "albert_move_to_x_y_on_board": "move to x: %1 y: %2 on board %3", "albert_set_orientation_on_board": "set orientation to %1 degrees on board %2", "albert_set_eye_to": "set %1 eye to %2 %3", "albert_clear_eye": "clear %1 eye %2", "albert_body_led": "turn %1 body led %2", "albert_front_led": "turn %1 front led %2", "albert_beep": "beep %1", "albert_change_buzzer_by": "change buzzer by %1 %2", "albert_set_buzzer_to": "set buzzer to %1 %2", "albert_clear_buzzer": "clear buzzer %1", "albert_play_note_for": "play note %1 %2 for %3 beats %4", "albert_rest_for": "rest for %1 beats %2", "albert_change_tempo_by": "change tempo by %1 %2", "albert_set_tempo_to": "set tempo to %1 bpm %2", "albert_move_forward": "move forward %1", "albert_move_backward": "move backward %1", "albert_turn_around": "turn %1 %2", "albert_set_led_to": "set %1 led %2 %3", "albert_clear_led": "clear %1 led %2", "albert_change_wheels_by": "%1 %2 %3", "albert_set_wheels_to": "%1 %2 %3", "arduino_text": "%1", "arduino_get_sensor_number": "%1 ", "arduino_get_port_number": "%1 ", "arduino_get_digital_toggle": "%1 ", "arduino_get_pwm_port_number": "%1 ", "arduino_get_number_sensor_value": "Analog %1 Sensor value ", "arduino_ext_get_analog_value": "Analog %1 Sensor value", "arduino_ext_get_analog_value_map": "Map Value %1 %2 ~ %3 to %4 ~ %5", "arduino_ext_get_ultrasonic_value": "Read ultrasonic sensor trig pin %1 echo pin %2", "arduino_ext_toggle_led": "Digital %1 Pin %2 %3", "arduino_ext_digital_pwm": "Digital %1 Pin %2 %3", "arduino_ext_set_tone": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "arduino_ext_set_servo": "Set servo pin %1 angle as %2 %3", "arduino_ext_get_digital": "Digital %1 Sensor value", "blacksmith_get_analog_value": "Read analog %1 pin sensor value", "blacksmith_get_analog_mapping": "Map analog %1 pin sensor value from %2 ~ %3 to %4 ~ %5", "blacksmith_get_digital_bluetooth": "Bluetooth RX 2 value", "blacksmith_get_digital_ultrasonic": "Read ultrasonic Trig %1 Echo %2 sensor value", "blacksmith_get_digital_toggle": "Digital %1 pin sensor value", "blacksmith_set_digital_toggle": "Digital %1 pin %2 %3", "blacksmith_set_digital_pwm": "Digital pwm %1 Pin %2 %3", "blacksmith_set_digital_servo": "Set servo pin %1 angle as %2 %3", "blacksmith_set_digital_buzzer": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "blacksmith_set_digital_lcd": "LCD %1 line %2 appear %3", "blacksmith_set_digital_bluetooth": "Bluetooth TX 3 Pin %1 data send %2", "dplay_get_number_sensor_value": "Analog %1 Sensor value ", "nemoino_get_number_sensor_value": "Analog %1 Sensor value ", "sensorBoard_get_number_sensor_value": "Analog %1 Sensor value ", "truetrue_get_accsensor": "加速度センサー%1の値", "truetrue_get_bottomcolorsensor": "床面カラーセンサー%1の値", "truetrue_get_frontcolorsensor": "全面カラーセンサー%1の値", "truetrue_get_linesensor": "ラインセンサー%1の値", "truetrue_get_proxisensor": "近接センサー%1の値", "truetrue_set_colorled": "カラーLED Red %1 Green %2 Blue %3 に設定 %4", "truetrue_set_dualmotor": "DCモーター左 %1 右 %2速度で%3秒駆動%4", "truetrue_set_led_colorsensor": "%1照明用LED %2 %3", "truetrue_set_led_linesensor": "ラインセンサー照明用LED %1 %2", "truetrue_set_led_proxi": "%1照明用LED %2 %3", "truetrue_set_linetracer": "ライントレーシングモード%1 %2", "truetrue_set_singlemotor": "DCモーター %1 速度 %2 に設定 %3", "CODEino_get_number_sensor_value": "Analog %1 Sensor value ", "ardublock_get_number_sensor_value": "Analog %1 Sensor value ", "arduino_get_digital_value": "Digital %1 Sensor value ", "dplay_get_digital_value": "Digital %1 Sensor value ", "nemoino_get_digital_value": "Digital %1 Sensor value ", "sensorBoard_get_digital_value": "Digital %1 Sensor value ", "CODEino_get_digital_value": "Digital %1 Pin value ", "CODEino_set_digital_value": "Digital %1 Pin %2 %3", "CODEino_set_pwm_value": "Digital %1 Pin %2 %3", "ardublock_get_digital_value": "Digital %1 Sensor value ", "arduino_toggle_led": "Digital %1 Pin %2 %3", "dplay_toggle_led": "Digital %1 Pin %2 %3", "nemoino_toggle_led": "Digital %1 Pin %2 %3", "sensorBoard_toggle_led": "Digital %1 Pin %2 %3", "CODEino_toggle_led": "Digital %1 Pin %2 %3", "arduino_toggle_pwm": "Digital %1 Pin %2 %3", "dplay_toggle_pwm": "Digital %1 Pin %2 %3", "nemoino_toggle_pwm": "Digital %1 Pin %2 %3", "sensorBoard_toggle_pwm": "Digital %1 Pin %2 %3", "CODEino_toggle_pwm": "Digital %1 Pin %2 %3", "ardublock_toggle_pwm": "Digital %1 Pin %2 %3", "arduino_convert_scale": "Map Value %1 %2 ~ %3 to %4 ~ %5 ", "dplay_convert_scale": "Map Value %1 %2 ~ %3 to %4 ~ %5 ", "nemoino_convert_scale": "Map Value %1 %2 ~ %3 to %4 ~ %5 ", "sensorBoard_convert_scale": "Map Value %1 %2 ~ %3 to %4 ~ %5 ", "CODEino_convert_scale": "Map Value %1 %2 ~ %3 to %4 ~ %5 ", "CODEino_set_rgb_value": "Set color LED %1 by %2 %3", "CODEino_set_rgb_add_value": "Add color LED %1 by %2 %3", "CODEino_set_rgb_off": "Turn off LED %1", "CODEino_set__led_by_rgb": "Turn on color LED, Red %1 Green %2 Blue %3 %4", "CODEino_rgb_set_color": "Select %1 for color LED %2", "CODEino_led_by_value": "Turn on LED %1", "ardublock_convert_scale": "Map Value %1 %2 ~ %3 to %4 ~ %5 ", "joystick_get_number_sensor_value": "Analog %1 Sensor value ", "joystick_get_digital_value": "Digital %1 Sensor value ", "joystick_toggle_led": "Digital %1 Pin %2 %3", "joystick_toggle_pwm": "Digital %1 Pin %2 %3", "joystick_convert_scale": "Map Value %1 %2 ~ %3 to %4 ~ %5 ", "sensorBoard_get_named_sensor_value": "%1 Sensor value", "sensorBoard_is_button_pressed": "Pressed %1 button?", "sensorBoard_led": "%1 LED %2 %3", "arduino_download_connector": "%1", "download_guide": "%1", "arduino_download_source": "%1", "arduino_connected": "%1", "arduino_connect": "%1", "arduino_reconnect": "%1", "CODEino_get_sensor_number": "%1 ", "CODEino_get_named_sensor_value": " %1 Sensor value ", "CODEino_get_sound_status": "Sound is %1 ", "CODEino_get_light_status": "Light is %1 ", "CODEino_is_button_pressed": " Operation %1 ", "CODEino_get_accelerometer_direction": " 3-AXIS Accelerometer %1 ", "CODEino_get_accelerometer_value": " 3-AXIS Accelerometer %1 -axis value ", "CODEino_get_analog_value": "Analog %1 Sensor value", "iboard_button": "Pressed %1 button?", "iboard_digital_pwm": "Digital %1 Pin %2 %3", "iboard_get_analog_value": "Analog %1 Sensor value ", "iboard_get_analog_value_map": "Map Value %1 %2 ~ %3 to %4 ~ %5 ", "iboard_get_digital": "Digital %1 Sensor value ", "iboard_led": "Digital %1 Pin %2 %3", "iboard_motor": "Digital %1 Pin %2 %3", "iboard_pwm_led": "Digital %1 Pin %2 %3", "iboard_rgb_led": " %1 LED %2 %3", "iboard_set_tone": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "iboard_toggle_led": "Digital %1 Pin %2 %3", "bitbrick_when_button_pressed": "%1 when button %2", "bitbrick_when_sensor_get_value": "%1 when %2 value %3 %4", "bitbrick_is_touch_pressed": "button %1 %2?", "bitbrick_is_sensor_value_compare": "%1 %2 %3?", "bitbrick_sensor_value": "%1 value", "bitbrick_convert_scale": "map %1 value from %2 ~ %3 to %4 ~ %5", "bitbrick_turn_on_color_led_by_rgb": "set LED color to Red %1 Green %2 Blue %3 %4", "bitbrick_turn_on_color_led_by_picker": "set LED color to %1 %2", "bitbrick_turn_on_color_led_by_value": "set LED color %1 %2", "bitbrick_turn_off_color_led": "turn off LED %1", "bitbrick_buzzer": "buzz note %1 %2", "bitbrick_servomotor_angle": "servo motor %1 degree %2 %3", "bitbrick_dc_direction_speed": "dc motor %1 direction %2 speed %3 %4", "bitbrick_dc_speed": "dc motor %1 velocity %2 %3", "bitbrick_turn_off_all_motors": "stop all motors %1", "start_drawing": "描きはじめる %1", "stop_drawing": "描きおえる %1", "set_color": "筆の色を%1にする %2", "set_random_color": "筆の色をランダムにする %1", "change_thickness": "筆の太さを %1 だけ変える %2", "set_thickness": "筆の太さを%1にする %2", "change_opacity": "筆の不透明度を%1 %大きくする %2", "set_opacity": "筆の不透明度を%1 %にする %2", "brush_erase_all": "すべての筆のあとを消す %1", "brush_stamp": "スタンプを押す %1", "change_brush_transparency": "筆の透明度を%1 %だけ変える %2", "set_brush_tranparency": "筆の透明度を%1 %にする %2", "number": "%1", "angle": "%1", "color": "%1", "get_x_coordinate": "%1", "get_y_coordinate": "%1", "get_angle": "%1", "get_rotation_direction": "%1", "distance_something": "%1 %2 %3", "coordinate_mouse": "%1 %2 %3", "coordinate_object": "%1 %2 %3 %4", "calc_basic": "%1 %2 %3", "calc_plus": "%1 %2 %3", "calc_minus": "%1 %2 %3", "calc_times": "%1 %2 %3", "calc_divide": "%1 %2 %3", "calc_mod": "%1 %2 %3 %4", "calc_share": "%1 %2 %3 %4", "calc_operation": "%1 %2 %3 %4", "calc_rand": "%1 %2 %3 %4 %5", "get_date": "%1 %2 %3", "get_sound_duration": "%1 %2 %3", "get_user_name": "ユーザーID", "get_nickname": "ニックネーム", "reset_project_timer": "%1", "set_visible_project_timer": "%1 %2 %3 %4", "timer_variable": "%1 %2", "get_project_timer_value": "%1 %2", "char_at": "%1 %2 %3 %4 %5", "length_of_string": "%1 %2 %3", "substring": "%1 %2 %3 %4 %5 %6 %7", "replace_string": "%1 %2 %3 %4 %5 %6 %7", "change_string_case": "%1 %2 %3 %4 %5", "index_of_string": "%1 %2 %3 %4 %5", "combine_something": "%1 %2 %3 %4 %5", "get_sound_volume": "%1 %2", "quotient_and_mod": "%1 %2 %3 %4 %5 %6", "choose_project_timer_action": "%1 %2 %3 %4", "wait_second": "%1 秒待つ %2", "repeat_basic": "%1回繰り返す %2", "hidden_loop": "%1回繰り返す %2", "repeat_inf": "ずっと繰り返す %1", "stop_repeat": "繰り返しをやめる %1", "wait_until_true": "%1 になるまで待つ %2", "_if": "もし%1なら %2", "if_else": "もし%1なら %2 %3でなければ", "create_clone": "%1のコピーを作る %2", "delete_clone": "このコピーを削除する %1", "when_clone_start": "%1 初めてコピーされた時", "stop_run": "プログラムを終了する %1", "repeat_while_true": "%1 %2 繰り返す %3", "stop_object": "%1 コードの実行を止める %2", "restart_project": "最初から再スタートする %1", "remove_all_clones": "すべてのコピーを削除する %1", "functionAddButton": "%1", "function_field_label": "%1%2", "function_field_string": "%1%2", "function_field_boolean": "%1%2", "function_param_string": "文字/数字の値", "function_param_boolean": "判断値", "function_create": "関数を定義する %1 %2", "function_general": "関数%1", "expansionBlockAddButton": "%1", "aiUtilizeBlockAddButton": "%1", "aiUtilizeModelTrainButton": "%1", "weather_title": "%1", "check_weather": "%1 %2の天気が%3か?", "check_finedust": "現在%1のPM10のレベルが%2か?", "get_weather_data": "%1 %2の %3", "get_current_weather_data": "現在%1の %2", "get_today_temperature": "今日%1の %2時の気温", "check_city_weather": "%1 %2 %3の天気が%4か?", "check_city_finedust": "現在%1 %2のPM10のレベルが%3か?", "get_city_weather_data": "%1 %2 %3の %4", "get_current_city_weather_data": "現在%1 %2の %3", "get_today_city_temperature": "今日%1 %2の %3時の気温", "translate_title": "%1", "get_translated_string": "%1 %2を %3に翻訳する", "check_language": "%1の言語", "festival_title": "%1", "count_festival": "%1 %2 のイベント数", "get_festival_info": "%1 %2 のイベント中 %3 番目の項目の %4", "behaviorConductDisaster_title": "%1", "count_disaster_behavior": "%1 %2 に取るべき行動要領数", "get_disaster_behavior": "自然災害の %1 %2 に取るべき行動要領で %3番目の項目", "behaviorConductLifeSafety_title": "%1", "count_lifeSafety_behavior": "%1 の中の %2方法の数", "get_lifeSafety_behavior": "%1の中の %2方法で %3番目の項目", "tts_title": "%1", "audio_title": "%1", "video_title": "%1", "read_text": "%1 を読み上げる %2", "set_tts_property": "%1 音声で速さを%2、ピッチを%3に設定する。%4", "read_text_wait_with_block": "%1 を読み上げて待つ %2", "load_expansion_block": "追加する", "load_ai_utilize_block": "AIブロックの読み込み", "load_ai_utilize_train_block": "鉄道模型", "expansion_block_descriptions": "拡張ブロックが正常に動作するには、インターネット接続が必要です。", "aiUtilize_block_descriptions": "A.I.活用ブロックは、インターネット接続が必要です。", "weather_title_text": "天気", "translate_title_text": "翻訳", "festival_title_text": "イベント", "audio_title_text": "オーディオ検出", "check_microphone": "マイクが接続されているか?", "get_microphone_volume": "マイク音量", "speech_to_text_convert": "音声の大井 %1", "speech_to_text_get_value": "音声を文字に変えた値", "video_title_text": "ビデオ検出", "video_draw_webcam": "ビデオ画面 %1 %2", "video_check_webcam": "ビデオが接続されているか?", "video_set_camera_opacity_option": "ビデオの透明度効果を %1 に決める %2", "video_flip_camera": "ビデオ画面 %1 %2", "video_toggle_model": "%1 認識を %2 %3", "video_toggle_ind": "認識された %1 %2 %3", "video_number_detect": "認識された %1 の数", "video_detected_face_info": "%1 番目の顔の %2", "video_motion_value": "%1 で感知した %2 値", "video_face_part_coord": "%1 番目の顔 %2 の %3 座標", "video_body_part_coord": "%1 番目の人の %2 の %3 座標", "behaviorConductDisaster_title_text": "自然災害", "behaviorConductLifeSafety_title_text": "生活安全", "tts_title_text": "音声読み上げ", "hamster_hand_found": "hand found?", "hamster_value": "%1", "hamster_move_forward_once": "move forward once on board %1", "hamster_turn_once": "turn %1 once on board %2", "hamster_move_forward_for_secs": "move forward for %1 secs %2", "hamster_move_backward_for_secs": "move backward for %1 secs %2", "hamster_turn_for_secs": "turn %1 for %2 secs %3", "hamster_change_both_wheels_by": "change wheels by left: %1 right: %2 %3", "hamster_set_both_wheels_to": "set wheels to left: %1 right: %2 %3", "hamster_change_wheel_by": "change %1 wheel by %2 %3", "hamster_set_wheel_to": "set %1 wheel to %2 %3", "hamster_follow_line_using": "follow %1 line using %2 floor sensor %3", "hamster_follow_line_until": "follow %1 line until %2 intersection %3", "hamster_set_following_speed_to": "set following speed to %1 %2", "hamster_stop": "stop %1", "hamster_set_led_to": "set %1 led to %2 %3", "hamster_clear_led": "clear %1 led %2", "hamster_beep": "beep %1", "hamster_change_buzzer_by": "change buzzer by %1 %2", "hamster_set_buzzer_to": "set buzzer to %1 %2", "hamster_clear_buzzer": "clear buzzer %1", "hamster_play_note_for": "play note %1 %2 for %3 beats %4", "hamster_rest_for": "rest for %1 beats %2", "hamster_change_tempo_by": "change tempo by %1 %2", "hamster_set_tempo_to": "set tempo to %1 bpm %2", "hamster_set_port_to": "set port %1 to %2 %3", "hamster_change_output_by": "change output %1 by %2 %3", "hamster_set_output_to": "set output %1 to %2 %3", "roboid_hamster_beep": "Hamster %1: beep %2", "roboid_hamster_change_both_wheels_by": "Hamster %1: change wheels by left: %2 right: %3 %4", "roboid_hamster_change_buzzer_by": "Hamster %1: change buzzer by %2 %3", "roboid_hamster_change_output_by": "Hamster %1: change output %2 by %3 %4", "roboid_hamster_change_tempo_by": "Hamster %1: change tempo by %2 %3", "roboid_hamster_change_wheel_by": "Hamster %1: change %2 wheel by %3 %4", "roboid_hamster_clear_buzzer": "Hamster %1: clear buzzer %2", "roboid_hamster_clear_led": "Hamster %1: clear %2 led %3", "roboid_hamster_follow_line_until": "Hamster %1: follow %2 line until %3 intersection %4", "roboid_hamster_follow_line_using": "Hamster %1: follow %2 line using %3 floor sensor %4", "roboid_hamster_hand_found": "Hamster %1: hand found?", "roboid_hamster_move_backward_for_secs": "Hamster %1: move backward for %2 secs %3", "roboid_hamster_move_forward_for_secs": "Hamster %1: move forward for %2 secs %3", "roboid_hamster_move_forward_once": "Hamster %1: move forward once on board %2", "roboid_hamster_play_note_for": "Hamster %1: play note %2 %3 for %4 beats %5", "roboid_hamster_rest_for": "Hamster %1: rest for %2 beats %3", "roboid_hamster_set_both_wheels_to": "Hamster %1: set wheels to left: %2 right: %3 %4", "roboid_hamster_set_buzzer_to": "Hamster %1: set buzzer to %2 %3", "roboid_hamster_set_following_speed_to": "Hamster %1: set following speed to %2 %3", "roboid_hamster_set_led_to": "Hamster %1: set %2 led to %3 %4", "roboid_hamster_set_output_to": "Hamster %1: set output %2 to %3 %4", "roboid_hamster_set_port_to": "Hamster %1: set port %2 to %3 %4", "roboid_hamster_set_tempo_to": "Hamster %1: set tempo to %2 bpm %3", "roboid_hamster_set_wheel_to": "Hamster %1: set %2 wheel to %3 %4", "roboid_hamster_stop": "Hamster %1: stop %2", "roboid_hamster_turn_for_secs": "Hamster %1: turn %2 for %3 secs %4", "roboid_hamster_turn_once": "Hamster %1: turn %2 once on board %3", "roboid_hamster_value": "Hamster %1: %2", "roboid_turtle_button_state": "Turtle %1: button %2 ?", "roboid_turtle_change_buzzer_by": "Turtle %1: change buzzer by %2 %3", "roboid_turtle_change_head_led_by_rgb": "Turtle %1: change head led by r: %2 g: %3 b: %4 %5", "roboid_turtle_change_tempo_by": "Turtle %1: change tempo by %2 %3", "roboid_turtle_change_wheel_by": "Turtle %1: change %2 wheel by %3 %4", "roboid_turtle_change_wheels_by_left_right": "Turtle %1: change wheels by left: %2 right: %3 %4", "roboid_turtle_clear_head_led": "Turtle %1: clear head led %2", "roboid_turtle_clear_sound": "Turtle %1: clear sound %2", "roboid_turtle_cross_intersection": "Turtle %1: cross black intersection %2", "roboid_turtle_follow_line": "Turtle %1: follow %2 line %3", "roboid_turtle_follow_line_until": "Turtle %1: follow black line until %2 %3", "roboid_turtle_follow_line_until_black": "Turtle %1: follow %2 line until black %3", "roboid_turtle_is_color_pattern": "Turtle %1: color pattern %2 %3 ?", "roboid_turtle_move_backward_unit": "Turtle %1: move backward %2 %3 %4", "roboid_turtle_move_forward_unit": "Turtle %1: move forward %2 %3 %4", "roboid_turtle_pivot_around_wheel_unit_in_direction": "Turtle %1: pivot around %2 wheel %3 %4 in %5 direction %6", "roboid_turtle_play_note": "Turtle %1: play note %2 %3 %4", "roboid_turtle_play_note_for_beats": "Turtle %1: play note %2 %3 for %4 beats %5", "roboid_turtle_play_sound_times": "Turtle %1: play sound %2 %3 times %4", "roboid_turtle_play_sound_times_until_done": "Turtle %1: play sound %2 %3 times until done %4", "roboid_turtle_rest_for_beats": "Turtle %1: rest for %2 beats %3", "roboid_turtle_set_buzzer_to": "Turtle %1: set buzzer to %2 %3", "roboid_turtle_set_following_speed_to": "Turtle %1: set following speed to %2 %3", "roboid_turtle_set_head_led_to": "Turtle %1: set head led to %2 %3", "roboid_turtle_set_head_led_to_rgb": "Turtle %1: set head led to r: %2 g: %3 b: %4 %5", "roboid_turtle_set_tempo_to": "Turtle %1: set tempo to %2 bpm %3", "roboid_turtle_set_wheel_to": "Turtle %1: set %2 wheel to %3 %4", "roboid_turtle_set_wheels_to_left_right": "Turtle %1: set wheels to left: %2 right: %3 %4", "roboid_turtle_stop": "Turtle %1: stop %2", "roboid_turtle_touching_color": "Turtle %1: touching %2 ?", "roboid_turtle_turn_at_intersection": "Turtle %1: turn %2 at black intersection %3", "roboid_turtle_turn_unit_in_place": "Turtle %1: turn %2 %3 %4 in place %5", "roboid_turtle_turn_unit_with_radius_in_direction": "Turtle %1: turn %2 %3 %4 with radius %5 cm in %6 direction %7", "roboid_turtle_value": "Turtle %1: %2", "turtle_button_state": "button %1 ?", "turtle_change_buzzer_by": "change buzzer by %1 %2", "turtle_change_head_led_by_rgb": "change head led by r: %1 g: %2 b: %3 %4", "turtle_change_tempo_by": "change tempo by %1 %2", "turtle_change_wheel_by": "change %1 wheel by %2 %3", "turtle_change_wheels_by_left_right": "change wheels by left: %1 right: %2 %3", "turtle_clear_head_led": "clear head led %1", "turtle_clear_sound": "clear sound %1", "turtle_cross_intersection": "cross black intersection %1", "turtle_follow_line": "follow %1 line %2", "turtle_follow_line_until": "follow black line until %1 %2", "turtle_follow_line_until_black": "follow %1 line until black %2", "turtle_is_color_pattern": "color pattern %1 %2 ?", "turtle_move_backward_unit": "move backward %1 %2 %3", "turtle_move_forward_unit": "move forward %1 %2 %3", "turtle_pivot_around_wheel_unit_in_direction": "pivot around %1 wheel %2 %3 in %4 direction %5", "turtle_play_note": "play note %1 %2 %3", "turtle_play_note_for_beats": "play note %1 %2 for %3 beats %4", "turtle_play_sound_times": "play sound %1 %2 times %3", "turtle_play_sound_times_until_done": "play sound %1 %2 times until done %3", "turtle_rest_for_beats": "rest for %1 beats %2", "turtle_set_buzzer_to": "set buzzer to %1 %2", "turtle_set_following_speed_to": "set following speed to %1 %2", "turtle_set_head_led_to": "set head led to %1 %2", "turtle_set_head_led_to_rgb": "set head led to r: %1 g: %2 b: %3 %4", "turtle_set_tempo_to": "set tempo to %1 bpm %2", "turtle_set_wheel_to": "set %1 wheel to %2 %3", "turtle_set_wheels_to_left_right": "set wheels to left: %1 right: %2 %3", "turtle_stop": "stop %1", "turtle_touching_color": "touching %1 ?", "turtle_turn_at_intersection": "turn %1 at black intersection %2", "turtle_turn_unit_in_place": "turn %1 %2 %3 in place %4", "turtle_turn_unit_with_radius_in_direction": "turn %1 %2 %3 with radius %4 cm in %5 direction %6", "turtle_value": "%1", "is_clicked": "%1", "is_press_some_key": "%1 %2", "reach_something": "%1 %2 %3", "boolean_comparison": "%1 %2 %3", "boolean_equal": "%1 %2 %3", "boolean_bigger": "%1 %2 %3", "boolean_smaller": "%1 %2 %3", "boolean_and_or": "%1 %2 %3", "boolean_and": "%1 %2 %3", "boolean_or": "%1 %2 %3", "boolean_not": "%1 %2 %3", "is_boost_mode": "%1", "true_or_false": "%1", "True": "%1", "False": "%1", "boolean_basic_operator": "%1 %2 %3", "show": "形を見せる %1", "hide": "形を隠す %1", "dialog_time": "%1を%2秒間 %3 %4", "dialog": "%1を%2 %3", "remove_dialog": "言った言葉を削除する %1", "change_to_nth_shape": "%1 の形に変える %2", "change_to_next_shape": "%1 の形に変える %2", "set_effect_volume": "%1 効果を %2 だけ加える %3", "set_effect": "%1 効果を%2 にする %3", "erase_all_effects": "効果をすべて削除する %1", "change_scale_percent": "サイズを%1だけ変更%2", "set_scale_percent": "サイズを%1 にする %2", "change_scale_size": "サイズを %1 だけ変える %2", "set_scale_size": "サイズを%1 にする %2", "flip_y": "形を左右反対にする %1", "flip_x": "形を上下反対にする %1", "set_object_order": "%1番目に上げる %2", "get_pictures": "%1", "change_to_some_shape": "%1 の形に変える %2", "add_effect_amount": "%1 効果を%2だけ加える %3", "change_effect_amount": "%1 効果を%2にする %3", "set_effect_amount": "%1 効果を%2だけ加える %3", "set_entity_effect": "%1 効果を%2にする %3", "change_object_index": "%1 送る %2", "move_direction": "移動方向に %1 だけ動く %2", "move_x": "x座標を %1 だけ変える %2", "move_y": "y座標を%1だけ変える%2", "locate_xy_time": "%1秒間 x: %2 y: %3 の位置に移動する %4", "rotate_by_angle": "オブジェクトを%1分回転する %2", "rotate_by_angle_dropdown": "%1分回転する %2", "see_angle": "移動方向を%1にする %2", "see_direction": "%1側を見る %2", "locate_xy": "x: %1 y: %2 の位置に移動する %3", "locate_x": "x: %1 の位置に移動する %2", "locate_y": "y: %1 の位置に移動する %2", "locate": "%1 の位置に移動する %2", "move_xy_time": "%1秒間 x: %2 y: %3 の分だけ動く %4", "rotate_by_angle_time": "オブジェクトを%1 秒間%2だけ回転する %3", "bounce_wall": "壁に着いたら、跳ね返る %1", "flip_arrow_horizontal": "矢印方向を左右入れ替える %1", "flip_arrow_vertical": "矢印方向を上下入れ替える %1", "see_angle_object": "%1 の方向へ向く %2", "see_angle_direction": "オブジェクトを%1にする %2", "rotate_direction": "移動方向を%1 だけ回転させる %2", "locate_object_time": "%1秒間%2 の位置に移動する %3", "rotate_absolute": "方向を%1にする %2", "rotate_relative": "向きを%1だけ回転させる %2", "direction_absolute": "移動方向を%1にする %2", "direction_relative": "移動方向を %1 だけ回転させる %2", "move_to_angle": "%1 の方向に %2 だけ動く %3", "rotate_by_time": "%1 秒間、向きを%2 だけ回転させる %3", "direction_relative_duration": "%1秒間、移動方向を %2 だけ回転させる %3", "neobot_sensor_value": "%1 값", "neobot_turn_left": "Rotate left motor %1 %2 %3", "neobot_stop_left": "Stop left motor %1", "neobot_turn_right": "Rotate right motor %1 %2 %3", "neobot_stop_right": "Stop right motor %1", "neobot_run_motor": "Run %1 motor for %2 secs", "neobot_servo_1": "Move the servo motor connected to SERVO1 to %2 with the speed of %1 %3", "neobot_servo_2": "Move the servo motor connected to SERVO2 to %2 with the speed of %1 %3", "neobot_play_note_for": "Play %1 melody to octave %2 as long as %3 %4", "neobot_set_sensor_value": "%1 value of the port to %2 %3", "robotis_openCM70_cm_custom_value": "Custom address ( %1 ) value %2", "robotis_openCM70_sensor_value": "Controller value %1", "robotis_openCM70_aux_sensor_value": "Value %1 %2", "robotis_openCM70_cm_buzzer_index": "Play %1 controller scale value for %2 seconds %3 ", "robotis_openCM70_cm_buzzer_melody": "Play controller melody %1 times %2", "robotis_openCM70_cm_sound_detected_clear": "Initialize the final number of sound detection %1", "robotis_openCM70_cm_led": "Controller %1 LED %2 %3", "robotis_openCM70_cm_motion": "Play the motion %1 times", "robotis_openCM70_cm_autodrive_motor": "Autonomous driving car %1 motor uses %2 %3", "robotis_openCM70_cm_autodrive_ir": "Autonomous driving car %1 IR sensor uses %2 %3", "robotis_openCM70_cm_autodrive_speed": "Perform autonomous driving at the speed of %1 %2", "robotis_openCM70_aux_car_move": "Make the robot %2 at a speed of %1% %3", "robotis_openCM70_aux_motor_speed": "Set the speed of decelerating motor of %1 to %2 , and the output value to %3% %4", "robotis_openCM70_aux_servo_mode": "Set the mode of %1 servo motor to %2 %3", "robotis_openCM70_aux_servo_speed": "Set the speed of servo motor of %1 to %2 , and the output value to %3% %4", "robotis_openCM70_aux_servo_position": "Set the position of %1 servo motor to %2 degree %3", "robotis_openCM70_aux_led_module": "Set the LED module of %1 as %2 %3", "robotis_openCM70_aux_custom": "Set the user device of %1 as %2 %3", "robotis_openCM70_cm_poweroff_timer": "Set auto-off timer as %1 %2", "robotis_openCM70_cm_custom": "Set the custom address ( %1 ) as %2 %3", "robotis_carCont_sensor_value": "Value %1", "robotis_carCont_cm_led": "%1 LED 4, %2 LED %3", "robotis_carCont_cm_sound_detected_clear": "Initialize the final number of sound detection %1", "robotis_carCont_aux_motor_speed": "Set the speed of decelerating motor of %1 to %2, and the output value to %3 %4", "robotis_carCont_cm_calibration": "Set %1 value of infrared sensor calibration to %2 %3", "roduino_get_analog_number": "%1", "roduino_get_port_number": "%1", "roduino_get_analog_value": "アナログ %1回センサー値 ", "roduino_get_digital_value": "デジタル %1回センサー値 ", "roduino_set_digital": "デジタル %1番ピン %2 %3", "roduino_motor": "%1 %2 %3", "roduino_set_color_pin": "カラーセンサー R : %1, G : %2, B : %3 %4", "roduino_get_color": "カラーセンサー%1 感知", "roduino_on_block": " On ", "roduino_off_block": " Off ", "schoolkit_get_in_port_number": "%1", "schoolkit_get_out_port_number": "%1", "schoolkit_get_servo_port_number": "%1", "schoolkit_get_input_value": "デジタル %1番センサー値 ", "schoolkit_set_output": "デジタル %1番ピン %2 %3", "schoolkit_motor": "%1速度%2で %3 %4", "schoolkit_set_servo_value": "サーボモーター %1番ピン %2˚ %3", "schoolkit_on_block": " On ", "schoolkit_off_block": " Off ", "when_scene_start": "%1 シーンが始まった時", "start_scene": "%1 スタート%2", "start_neighbor_scene": "%1 シーンスタート%2", "sound_something": "音 %1 を再生する %2", "sound_something_second": "音 %1 を %2秒再生する %3", "sound_something_wait": "音 %1 を再生して待つ %2", "sound_something_second_wait": "音 %1 を %2秒再生して待つ %3", "sound_volume_change": "音の大きさを %1 %大きくする %2", "sound_volume_set": "音の大きさを %1 %にする %2", "sound_silent_all": "すべての音を止める %1", "get_sounds": "%1", "sound_something_with_block": "音 %1 を再生する %2", "sound_something_second_with_block": "音 %1 を %2秒再生する %3", "sound_something_wait_with_block": "音 %1 を再生して待つ %2", "sound_something_second_wait_with_block": "音 %1 を %2 秒再生して待つ %3", "sound_from_to": "音 %1 を %2秒から%3秒まで再生する %4", "sound_from_to_and_wait": "音 %1 を %2秒から%3秒まで再生して待つ %4", "when_run_button_click": "%1 スタートボタンをクリックした時", "press_some_key": "%1 %2 キーを押した時 %3", "when_some_key_pressed": "%1 %2 キーを押した時", "mouse_clicked": "%1 マウスをクリックした時", "mouse_click_cancled": "%1 マウスをクリックして離した時", "when_object_click": "%1 オブジェクトをクリックした時", "when_object_click_canceled": "%1 オブジェクトをクリックして離した時", "when_some_key_click": "%1 キーを押した時", "when_message_cast": "%1 %2 信号を受け取った時", "message_cast": "%1 信号を送る %2", "message_cast_wait": "%1 信号を送って待つ %2", "text": "%1", "text_read": "Textbox %1’s contents", "text_write": "%1と書く %2", "text_append": "%1と後ろに続けて書く %2", "text_prepend": "%1と前に追加する %2", "text_flush": "テキストをすべて削除する %1", "analizyDataAddButton": "%1", "append_row_to_table": "Add a %2 to the table %1 %3", "insert_row_to_table": "Insert %3 to %2th row from the %1 %4", "delete_row_from_table": "Remove %2th %3 from table %1 %4", "set_value_from_table": "Change %3 in the %1 %2th row to %4 %5", "get_table_count": "length of %2 in the %1", "get_value_from_table": "value of the %3 in %2th row of the %1", "calc_values_from_table": "%3 of the %2 in the %1", "open_table_chart": "Open the chart of the %1 %2", "close_table_chart": "Close the table chart", "get_coefficient": 'Correlation coefficient between %2and %3 in table %1', "variableAddButton": "%1", "listAddButton": "%1", "change_variable": "%1 に %2 だけ足す %3", "set_variable": "%1を%2にする %3", "show_variable": "変数 %1 を見せる %2", "hide_variable": "変数 %1 を隠す %2", "get_variable": "%1 %2", "ask_and_wait": "%1 を聞いて答えを待つ %2", "get_canvas_input_value": "%1", "add_value_to_list": "%1 を %2 に追加する %3", "remove_value_from_list": "%1番目の項目を%2 から削除する %3", "insert_value_to_list": "%1を%2の%3番目に入れる %4", "change_value_list_index": "%1 の %2番目の項目を%3に変更する %4", "value_of_index_from_list": "%1 %2 %3 %4 %5", "length_of_list": "%1 %2 %3", "show_list": "リスト %1 を見せる %2", "hide_list": "リスト %1 を隠す %2", "options_for_list": "%1", "set_visible_answer": "答えを %1 %2", "is_included_in_list": "%1 %2 %3 %4 %5", "xbot_digitalInput": "%1", "xbot_analogValue": "%1", "xbot_digitalOutput": "Digital %1 PIN, Ouput Value %2 %3", "xbot_analogOutput": "Analog %1 %2 %3", "xbot_servo": "Servo Motor %1 , Angle %2 %3", "xbot_oneWheel": "Wheel(DC) Motor %1 , Speed %2 %3", "xbot_twoWheel": "Wheel(DC) Motor Right(2) Speed: %1 Left(1) Speed: %2 %3", "xbot_rgb": "RGB LED Color from Red %1 Green %2 Blue %3 %4", "xbot_rgb_picker": "RGB LED Color from %1 %2", "xbot_buzzer": "play note %1 %2 for %3 sec of Melody Playing %4", "xbot_lcd": "LCD %1 th Line , Text %2 %3", "run": " ", "mutant": "test mutant block", "jr_start": "%1", "jr_repeat": "%1 %2繰り返す", "jr_item": "花を集める %1", "cparty_jr_item": "鉛筆を拾う %1", "jr_north": " 上 %1", "jr_east": "右側%1", "jr_south": " 下 %1", "jr_west": " 左 %1", "jr_start_basic": "%1 %2", "jr_go_straight": "前に進む%1", "jr_turn_left": "左に回転する%1", "jr_turn_right": "右に回転する%1", "jr_go_slow": "ゆっくり進む %1", "jr_repeat_until_dest": "%1会うまで繰り返す %2", "jr_if_construction": "もし%1前にあるなら %2", "jr_if_speed": "もし%1前にあるなら %2", "maze_step_start": "%1 スタートをクリックした時", "maze_step_jump": "ジャンプする%1", "maze_step_jump2": "ジャンプする%1", "maze_step_jump_pinkbean": "ジャンプする%1", "maze_step_for": "%1回繰り返す%2", "test": "%1 this is test block %2", "maze_repeat_until_1": "%1 会うまで繰り返す%2", "maze_repeat_until_2": "すべての%1 会うまで繰り返す%2", "maze_step_if_1": "もし前に%1があるなら%2", "maze_step_if_2": "もし前に%1があるなら%2", "maze_call_function": "約束を読み込む%1", "maze_define_function": "約束する%1", "maze_step_if_3": "もし前に%1があるなら%2", "maze_step_if_4": "もし前に%1があるなら%2", "maze_step_move_step": "前に1マス移動%1", "maze_step_rotate_left": "左側に回転%1", "maze_step_rotate_right": "右側に回転%1", "maze_step_forward": "前に進む%1", "maze_turn_right": "右側を眺める%1", "maze_turn_left": "左側を眺める%1", "maze_ladder_climb": "はしごを使う%1", "maze_attack_lupin": "%1攻撃する%2", "maze_attack_both_side": "両隣を攻撃する%1", "maze_attack_pepe": "%1攻略する%2", "maze_attack_yeti": "%1攻略する%2", "maze_attack_mushroom": "%1攻略する%2", "maze_attack_peti": "%1攻略する%2", "maze_eat_item": "食べ物を食べる%1", "maze_step_if_mushroom": "もし1マス前に%1があるなら%2", "maze_step_if_yeti": "もし前に%1があるなら%2 %3そうでなければ", "maze_step_if_left_monster": "もし左側の攻撃範囲にモンスターがいるなら%1 %2そうでなければ", "maze_step_if_right_monster": "もし右側の攻撃範囲にモンスターがいるなら%1 %2そうでなければ", "maze_step_if_lupin": "もし2マス前に%1があるなら %2", "maze_step_if_else_road": "もし1マス前に道があるなら %1 %2ないなら", "maze_step_if_else_mushroom": "もし1マス前に%1があるなら%2 %3そうでなければ", "maze_step_if_else_lupin": "もし2マス前に%1があるなら%2 %3そうでなければ", "maze_step_if_else_ladder": "もし1マス前に%1があるなら%2 %3そうでなければ", "maze_rotate_left": "左に回転する%1", "maze_rotate_right": "右に回転する%1", "maze_moon_kick": "キックする%1", "maze_repeat_until_3": "%1に到着するまで繰り返す%2", "maze_repeat_until_4": "%1に到着するまで繰り返す%2", "maze_repeat_until_5": "%1に到着するまで繰り返す%2", "maze_repeat_until_6": "%1に到着するまで繰り返す%2", "maze_repeat_until_7": "%1に到着するまで繰り返す%2", "maze_repeat_until_goal": "目的地に到着するまで繰り返す%1", "maze_repeat_until_beat_monster": "すべてのモンスターをやっつけるまで繰り返す%1", "maze_radar_check": "%1に%2がある", "maze_cony_flower_throw": "花を投げる%1", "maze_brown_punch": "パンチを飛ばす%1", "maze_iron_switch": "障害物を動かす%1", "maze_james_heart": "ハートを飛ばす%1", "maze_step_if_5": "もし前に道がないなら%2", "maze_step_if_6": "もし前に%1がないなら%2", "maze_step_if_7": "もし前に%1があるなら%2", "maze_step_if_8": "もし%1なら%2", "maze_step_if_else": "もし%1なら%2 %3そうでなければ", "test_wrapper": "%1 this is test block %2", "basic_button": "%1", "ai_move_right": "前に進む %1", "ai_move_up": "上に行く %1", "ai_move_down": "下に行く %1", "ai_repeat_until_reach": "目的地に到達するまで繰り返す %1", "ai_if_else_1": "前に%1があるなら%2 %3そうでなければ", "ai_boolean_distance": "%1 レーダー%2 %3", "ai_distance_value": "%1 レーダー", "ai_boolean_object": "%1物体は%2か?", "ai_use_item": "アイテム使用 %1", "ai_boolean_and": "%1 %2 %3", "ai_True": "%1", "ai_if_else": "もし%1なら%2 %3そうでなければ", "smartBoard_convert_scale": "Map Value %1 %2 ~ %3 to %4 ~ %5", "smartBoard_get_named_sensor_value": "%1 Sensor value", "smartBoard_is_button_pressed": "Pressed %1 button?", "smartBoard_set_dc_motor_direction": "%1 DC Motor change direction %2 %3", "smartBoard_set_dc_motor_speed": "%1 DC Motor %2 %3", "smartBoard_set_dc_motor_pwm": "%1 DC Motor set speed %2 %3", "smartBoard_set_servo_speed": "%1 RC Servo Motor Speed %2 %3", "smartBoard_set_servo_angle": "%1 RC Servo Motor set angle %2 %3", "smartBoard_set_number_eight_pin": "%1 port %2 %3", "smartBoard_set_gs1_pwm": "GS1 port %1 %2", "robotori_digitalInput": "%1", "robotori_analogInput": "%1", "robotori_digitalOutput": "Digital %1 PIN, Output Value %2 %3", "robotori_analogOutput": "Analog %1 %2 %3", "robotori_servo": "Servo Motor Angle %1 %2", "robotori_dc_direction": "DC Motor %1 Direction %2 %3", "dadublock_get_analog_value": "Analog %1 Sensor value", "dadublock_get_analog_value_map": "Map Value %1 %2 ~ %3 to %4 ~ %5 ", "dadublock_get_ultrasonic_value": "Read ultrasonic sensor trig pin %1 echo pin %2", "dadublock_toggle_led": "Digital %1 Pin %2 %3", "dadublock_digital_pwm": "Digital %1 Pin %2 %3", "dadublock_set_tone": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "dadublock_set_servo": "Set servo pin %1 angle as %2 %3", "coconut_stop_motor": "stop motor %1", "coconut_move_motor": "move %1 %2", "coconut_turn_motor": "turn %1 %2", "coconut_move_for_secs": "move %1 for time %2 %3", "coconut_turn_for_secs": "turn %1 for %2 secs %3", "coconut_turn_to_led": "turn %1 RGB %2 %3", "coconut_move_outmotor": "external Motor %1 speed %2 %3", "coconut_set_led_to": "turn on RGB %1 %2 %3", "coconut_clear_led": "turn off RGB %1 %2", "coconut_set_led_clear": "turn off RGB %1 %2 %3", "coconut_set_led_time": "turn on RGB %1 %2 for time %3 %4", "coconut_beep": "buzzer on %1", "coconut_buzzer_time": "play buzzer for time %1 %2", "coconut_buzzer_set_hz": "play buzzer on frequency %1 Hz for time %2 %3", "coconut_clear_buzzer": "buzzer off %1", "coconut_play_buzzer": "play buzzer on note %1 octave %2 %3 beat %4 %5", "coconut_rest_buzzer": "rest beat %1 %2", "coconut_play_buzzer_led": "play buzzer on note %1 octave %2 %3 beat %4 RGB %5 %6 %7", "coconut_play_midi": "play melody %1 %2", "coconut_floor_sensor": "line tracer %1", "coconut_floor_sensing": "line tracer detect %1 %2", "coconut_following_line": "follow the line %1", "coconut_front_sensor": "IR distance sensor %1", "coconut_front_sensing": "detecting obstacle %1 %2", "coconut_obstruct_sensing": "detecting obstacle", "coconut_avoid_mode": "avoid mode %1", "coconut_dotmatrix_set": "LED Matrix %1 ( ROW %2, COL %3 ) %4", "coconut_dotmatrix_on": "turn on all LED Matrix %1", "coconut_dotmatrix_off": "LED Matrix clear all %1", "coconut_dotmatrix_num": "LED Matrix show %1 %2", "coconut_dotmatrix_small_eng": "LED Matrix show small letter %1 %2", "coconut_dotmatrix_big_eng": "LED Matrix show capital letters %1 %2", "coconut_dotmatrix_kor": "LED Matrix show Korean %1 %2", "coconut_light_sensor": "light sensor", "coconut_tem_sensor": "temperature", "coconut_ac_sensor": "3-Axis Accelerometer %1 angle", "coconut_outled_sensor": "set external LED pin %1 for time %2 %3", "coconut_outspk_sensor": "set Speaker pin %1 frequency %2 (Hz) duration %3 seconds %4", "coconut_outspk_sensor_off": "stop Speaker pin %1 %2", "coconut_outinfrared_sensor": "external IR sensor %1", "coconut_outcds_sensor": "external Cds sensor %1", "coconut_servomotor_angle": "set servo pin %1 angle as %2 %3", "chocopi_control_button": "%1 controller %2 is pressed", "chocopi_control_event": "%1 When %2 controller %3 is %4", "chocopi_control_joystick": "%1 controller %2 value", "chocopi_dc_motor": "%1 DC motor #%2 %3 % direction %4 %5", "chocopi_led": "%1 LED #%2 RGB(%3 %4 %5) %6", "chocopi_motion_photogate_event": "%1 When %2 photogate %3 is %4", "chocopi_motion_photogate_status": "%1 photogate #%2 is blocked", "chocopi_motion_photogate_time": "time when %1 photogate %2 was %3", "chocopi_motion_value": "%1 motion %2 value", "chocopi_sensor": "%1 sensor %2", "chocopi_servo_motor": "%1 set servo motor #%2 %3 degree %4", "chocopi_touch_event": "%1 When %2 touch pad%3 is %4", "chocopi_touch_status": "%1 touch pad%2 is touched", "chocopi_touch_value": "%1 touch pad%2 value", "dadublock_car_digital_pwm": "디지털 %1 번 핀을 %2 (으)로 정하기 %3", "dadublock_car_get_analog_value": "아날로그 %1 번 센서값", "dadublock_car_get_analog_value_map": "아날로그 %1번 센서값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ", "dadublock_car_get_digital": "디지털 %1 번 센서값", "dadublock_car_get_irsensor": "적외선 %1 번 센서값", "dadublock_car_get_ultrasonic_value": "울트라소닉 Trig %1번핀 Echo %2번핀 센서값", "dadublock_car_motor": "모터 %1 번을 %2 (으)로 %3 %의 속도로 움직이기 %4", "dadublock_car_motor_stop": "모터 %1 번 멈추기 %2", "dadublock_car_set_servo": "서보모터 %1 번 핀을 %2 의 각도로 정하기 %3", "dadublock_car_set_tone": "디지털 %1 번 핀 을 %2 음으로 %3의 옥타브로 %4 만큼 연주하기 %5", "dadublock_car_toggle_led": "디지털 %1 번 핀 %2 %3", "dadublock_get_digital": "디지털 %1 번 센서값", "ev3_get_sensor_value": "%1's value", "ev3_touch_sensor": "%1's touch sensor activted?", "ev3_color_sensor": "%1's %2 value", "ev3_motor_power": "%1's value print as %2 %3", "ev3_motor_power_on_time": "%1's value for %2seconds %3 printed %4", "ev3_motor_degrees": "%1's value in %2 direction turn %3 degrees %4", "rokoboard_get_sensor_value_by_name": "%1 value", "ardublock_digital_pwm": "Digital %1 Pin %2 %3", "ardublock_get_analog_value": "Analog %1 Sensor value", "ardublock_get_analog_value_map": "Map Value %1 %2 ~ %3 to %4 ~ %5", "ardublock_get_digital": "Digital %1 Sensor value", "ardublock_get_left_cds_analog_value": "Left CDS %1 Sensor value", "ardublock_get_right_cds_analog_value": "Left CDS %1 Sensor value", "ardublock_get_sound_analog_value": "Analog Sound %1 Sensor value", "ardublock_get_ultrasonic_value": "Read ultrasonic sensor trig pin %1 echo pin %2", "ardublock_set_left_motor": "Left motor direction to %1 speed %2 set %3", "ardublock_set_right_motor": "Right motor direction to %1 speed %2 set %3", "ardublock_set_servo": "Set servo pin %1 angle as %2 %3", "ardublock_set_tone": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "ardublock_toggle_led": "Digital %1 Pin %2 %3", "ardublock_toggle_left_led": "Left Light %1 Pin %2 %3", "ardublock_toggle_right_led": "Right Light %1 Pin %2 %3", "mkboard_digital_pwm": "Digital %1 Pin %2 %3", "mkboard_get_analog_value": "Analog %1 Sensor value", "mkboard_get_analog_value_map": "Map Value %1 %2 ~ %3 to %4 ~ %5", "mkboard_get_digital": "Digital %1 Sensor value", "mkboard_get_ultrasonic_value": "Read ultrasonic sensor trig pin %1 echo pin %2", "mkboard_set_servo": "Set servo pin %1 angle as %2 %3", "mkboard_set_tone": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "mkboard_toggle_led": "Digital %1 Pin %2 %3", "mkboard_set_lcd": "1602 LCD Row %1, Column %2 Value %3 %4", "mkboard_lcd_command": "1602 LCD Command %1 execute %2", "altino_analogValue": "altino %1 sensor value", "altino_dot_display": "electronic scoreboard %1 display %2", "altino_dot_display_line": "1col %1 2col %2 3col %3 4col %4 5col %5 6col %6 7col %7 8col %8 display %9", "altino_light": "%1 light %2 %3", "altino_rear_wheel": "rear motor right %1 left %2 setting %3", "altino_sound": "%1 octave %2 play %3", "altino_steering": "direction %1 setting %2", "jdkit_altitude": "드론을 %1 높이만큼 날리기 %2", "jdkit_button": "%1번 버튼 값 읽어오기", "jdkit_connect": "드론 연결 상태 읽어오기", "jdkit_emergency": "드론을 즉시 멈추기 %1", "jdkit_gyro": "보드 %1 기울기 값 읽어오기", "jdkit_joystick": "조이스틱 %1 읽기", "jdkit_led": "%1 LED %2 %3", "jdkit_motor": "%1 모터를 %2 세기로 돌리기 %3", "jdkit_ready": "드론 비행 준비 상태 읽어오기", "jdkit_rollpitch": "드론을 %1 방향 %2 세기로 움직이기 %3", "jdkit_throttle": "드론 프로펠러를 %1 만큼 세기로 돌리기 %2", "jdkit_tune": "%1 음을 %2 초동안 소리내기 %3", "jdkit_ultrasonic": "거리(초음파)값 읽어오기", "jdkit_yaw": "드론을 %1 만큼 회전하기 %2", "memaker_digital_pwm": "Digital %1 Pin %2 %3", "memaker_get_analog_value": "Analog %1 Sensor value", "memaker_get_analog_value_map": "Map Value %1 %2 ~ %3 to %4 ~ %5", "memaker_get_digital": "Digital %1 Sensor value", "memaker_get_ultrasonic_value": "Read ultrasonic sensor trig pin %1 echo pin %2", "memaker_set_lcd": "1602 LCD Row %1, Column %2 Value %3 %4", "memaker_set_servo": "Set servo pin %1 angle as %3", "memaker_toggle_led": "Digital %1 Pin %2 %3", "memaker_lcd_command": "1602 LCD Command %1 execute %2", "edumaker_digital_pwm": "디지털 %1 번 핀을 %2 (으)로 정하기 %3", "edumaker_get_analog_value": "아날로그 %1 번 센서값", "edumaker_get_analog_value_map": "%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값", "edumaker_get_digital": "디지털 %1 번 센서값", "edumaker_get_ultrasonic_value": "울트라소닉 Trig %1 Echo %2 센서값", "edumaker_set_servo": "디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3", "edumaker_set_tone": "디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5", "edumaker_toggle_led": "디지털 %1 번 핀 %2 %3", "creamo_get_number_sensor_value": "PWM_Block %1 Sensor value", "creamo_get_port_number": "%1", "creamo_get_pwm_port_number": "%1", "creamo_motor_port_number": "%1", "creamo_toggle_led": "LED_Block %1 Pin %2 %3", "creamo_toggle_motor": "Motor_Block %1 pin %2 %3", "creamo_toggle_pwm": "Digital %1 Pin %2 %3", "mechatro_get_dc_motor_current": "Get 1%motor current", "mechatro_get_digital": "%1", "mechatro_get_sensor_value": "Analog %1 Sensor value", "mechatro_get_ultrasonic_value": "Read ultrasonic sensor trig pin %1 echo pin %2", "mechatro_set_blue_pw": "Change PW of Bluetooth to %1%2%3%4 %5", "mechatro_set_dc_motor": "Set %1 motor speed to %2 %3", "mechatro_set_digital": "Digital %1 Pin %2 %3", "mechatro_set_pwm": "Digital %1 Pin %2 %3", "mechatro_set_servo_position": "Set servo pin %1 angle as %2 %3", "mechatro_set_servo_speed": "Set servo pin %1 speed %2 degree per second %3", "mechatro_set_threshold": "Set %1 threshold : %2%3", "mechatro_set_tone": "Play tone pin %1 on note %2 octave %3 %4", "mechatro_set_tone_time": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "funboard_buzzer_onoff": "buzzer %1 %2", "funboard_buzzer_second": "buzzer%1%2seconds%3", "funboard_buzzer_tone_simple": "play note%1%2,%3sec of Melody Playing%4", "funboard_color_led_on_pwm": "%1COLOR LED %2 % %3", "funboard_color_led_onoff": "%1COLOR LED %2 %3", "funboard_convert_scale": "Convert %1 value from %2~%3 to %4~%5", "funboard_dotmatrix_1column": "%1column %2set %3", "funboard_dotmatrix_1row": "%1row %2set %3", "funboard_dotmatrix_1row_1column": "%1%2 %3set %4", "funboard_dotmatrix_64_display": "%1 (8x8)display%2", "funboard_dotmatrix_big_eng": "capital letters %1 %2", "funboard_dotmatrix_char_display": "char%1display%2", "funboard_dotmatrix_extra_char": "char %1 %2", "funboard_dotmatrix_intensity": "Intensity %1% %2", "funboard_dotmatrix_kor": "∷∷ korean %1 %2", "funboard_dotmatrix_num": "number %1 %2", "funboard_dotmatrix_onoff": "turn all %1 %2", "funboard_dotmatrix_scroll_option": "scroll direction%1%2", "funboard_dotmatrix_scroll_rapid": "scroll rapid %1% %2", "funboard_dotmatrix_set": "%1row %2column %3 %4", "funboard_dotmatrix_small_eng": "small letter %1 %2", "funboard_dotmatrix_string_display": "string%1display%2", "funboard_dotmatrix_string_display_scroll": "string%1display%2scroll%3", "funboard_dotmatrix_symbol": "symbol %1 %2", "funboard_get_analog_sensor_2state": "%1 value %2", "funboard_get_digital_button_value": "%1 button value", "funboard_get_number_sensor_value": "%1 value", "funboard_get_touch_button_value": "%1 touch button value", "funboard_set_digital_buzzer": "Play tone octave %1 note %2 beat %3 %4", "funboard_what_button_pressed": "%1 button pressed.", "funboard_what_touch_button_pressed": "%1 touch button pressed." }; Lang.TextCoding = { "block_name": "ブロック名", "title_syntax": "文法エラー", "title_converting": "変換エラー", "message_syntax_default": "文法にエラーがあります", "message_syntax_unexpected_token": "文法に合わないトークンが含まれています", "message_syntax_reserved_token": "使用できない変数名です。", "message_syntax_reserved_token_list": "使用できないリスト名です。", "message_syntax_unexpected_character": "文法に合わない文字が含まれています", "message_syntax_unexpected_indent": "文法に合わない分かち書きが含まれています", "message_conv_default": "このコードには対応していません", "message_conv_no_support": "変換できないコードです", "message_conv_no_variable": "変数が宣言されませんでした", "message_conv_no_list": "リストが宣言されませんでした", "message_conv_no_object": "オブジェクトには対応していません", "message_conv_no_function": "関数は変換できません。", "message_conv_no_entry_event_function": "エントリーイベント関数は他の関数の中に存在できません。", "message_conv_undefined_function": "定義されていない命令です。命令が正しく入力されているか確認してください。", "message_conv_is_expect1": "正しくない文法です。", "message_conv_is_expect2": " が正しく入力されているか確認してください。", "message_conv_instead": "正しくない文法です。%1の代わりに%2が必要です。", "message_conv_is_wrong1": "正しくない文法です。", "message_conv_is_wrong2": "は来られない位置です。", "message_conv_or": " 私", "subject_syntax_default": "その他", "subject_syntax_token": "トークン", "subject_syntax_character": "文字", "subject_syntax_indent": "分かち書き", "subject_conv_default": "その他", "subject_conv_general": "一般", "subject_conv_variable": "変数", "subject_conv_list": "リスト", "subject_conv_object": "オブジェクト", "subject_conv_function": "関数", "alert_variable_empty_text": "登録された変数の中にスペース(分かち書き)が含まれる変数がある場合、モード変換できません。", "alert_list_empty_text": "登録されたリストの中にスペース(分かち書き)が含まれるリストがある場合、モード変換できません。", "alert_function_name_field_multi": "登録された関数の中に関数名に[名前]ブロックが2回以上含まれている場合、モード変換できません。", "alert_function_name_disorder": "登録された関数の中で[名前]ブロックが[文字/数字値]または[判断値]ブロックより後に書かれる場合、モード変換できません。", "alert_function_has_boolean": "エントリーパイソンに変換後、再びブロックモードに切り替えると関数に使われた「判断値」はすべて「文字/数字の値」に変わります。", "alert_function_editor": "関数作成及び編集中にはモード変換できません。", "alert_function_no_support": "テキストモードでは関数を作成・編集することができません。", "alert_list_no_support": "テキストモードではリストを作成・編集することができません。", "alert_variable_no_support": "テキストモードでは変数を作成・編集することができません。", "alert_signal_no_support": "テキストモードでは信号を作成・編集することができません。", "alert_legacy_no_support": "切り替えられないブロックが存在するため、モード変換できません。", "alert_variable_empty_text_add_change": "変数名にスペース(分かち書き)を含めることはできません。", "alert_list_empty_text_add_change": "リスト名にスペース(分かち書き)を含めることはできません。", "alert_list_contains_exceed_length_value": "リスト項目に15桁の以上の数が入力されている場合、モード変換できません。", "alert_function_name_empty_text_add_change": "関数名にスペース(分かち書き)を含めることはできません。", "alert_no_save_on_error": "文法エラーが存在しているため作品を保存できません。", "alert_api_no_support": "作品に拡張ブロックが使用されている場合には、エントリーパイソンモードに変更することができません。", "warn_unnecessary_arguments": "&(calleeName)();は括弧の間に値が入力される必要がないコマンドです。(line:&(lineNumber))", "python_code": " オブジェクトのパイソンコード", "eof": "改行", "newline": "改行", "indent": "インデント", "num": "数字", "string": "文字列", "name": "変数名" }; Lang.PythonHelper = { "when_run_button_click_desc": "[スタート]ボタンをクリックすると下のコマンドを実行します。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "when_run_button_click_exampleCode": "def when_start():\n Entry.print(\"やあ!\")", "when_run_button_click_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが\"やあ!\"と話します。", "when_some_key_pressed_desc": "Aキーを押すと下のコマンドを実行します。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "when_some_key_pressed_elements": "A-- 次の選択肢のうち一つ
① アルファベット : \"A\", \"B\" ~ \"Z\"など(小文字可能)
② 数字: 1, 2, 3, 4 ~ 9, 0
③ 特殊キー: \"space\", \"enter\"
④ 方向キー : \"up\", \"down\", \"right\", \"left\"", "when_some_key_pressed_exampleCode": "def when_press_key(\"W\"):\n Entry.move_to_direction(10)\n\ndef when_press_key(1):\n Entry.add_size(10)", "when_some_key_pressed_exampleDesc": "Wキーを押すとオブジェクトが移動方向に10移動し、1キーを押すとオブジェクトのサイズが10大きくなります。", "mouse_clicked_desc": "マウスをクリックした時、下のコマンドを実行します。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "mouse_clicked_exampleCode": "def when_click_mouse_on():\n Entry.add_size(10)\n Entry.move_to_direction(10)", "mouse_clicked_exampleDesc": "マウスをクリックすると、オブジェクトのサイズが10だけ大きくなり、移動方向に10移動します。", "mouse_click_cancled_desc": "マウスクリックを解除した時、下のコマンドを実行します。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "mouse_click_cancled_exampleCode": "def when_click_mouse_off():\n Entry.move_to_direction(-10)\n\ndef when_click_mouse_on():\n Entry.move_to_direction(10)", "mouse_click_cancled_exampleDesc": "マウスをクリックするとオブジェクトが移動方向に10移動し、マウスクリックを解除するとオブジェクトが移動方向に-10移動します。", "when_object_click_desc": "当該オブジェクトをクリックした時、下のコマンドを実行します。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "when_object_click_exampleCode": "def when_click_object_on():\n Entry.print_for_sec(\"回転!\", 0.5)\n Entry.add_rotation(90)", "when_object_click_exampleDesc": "オブジェクトをクリックすると、オブジェクトが\"回転!\"と話し、90度回転します。", "when_object_click_canceled_desc": "当該オブジェクトクリックを解除した時、下のコマンドを実行します。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "when_object_click_canceled_exampleCode": "def when_click_object_on():\n Entry.add_rotation(90)\n\ndef when_click_object_off():\n Entry.add_rotation(-90)", "when_object_click_canceled_exampleDesc": "オブジェクトをクリックするとオブジェクトが90度回転し、オブジェクトクリックを解除するとオブジェクトが-90度回転します。", "when_message_cast_desc": "A信号を受信すると下のコマンドを実行します。
下のコマンドは[Tab]キーを用いてインデントを作成します。
もしA信号がなければ[属性]タブにA信号が自動作成されます。", "when_message_cast_elements": "A-- \"信号名\"", "when_message_cast_exampleCode": "def when_click_mouse_on():\n Entry.send_signal(\"信号\")\n\ndef when_get_signal(\"信号\"):\n Entry.print_for_sec(\"やあ! 嬉しいな\", 0.5)", "when_message_cast_exampleDesc": "マウスをクリックすると\"信号\"を送り、\"信号\"を受信した時、\"やあ! 嬉しいな\"と0.5秒間話します。", "message_cast_desc": "Aに入力された信号を送ります。
もしA信号がなければ[属性]タブにA信号が自動作成されます。", "message_cast_elements": "A-- \"信号名\"", "message_cast_exampleCode": "#\"オブジェクト1\"のパイソンコード\ndef when_start():\n Entry.print_for_sec(\"やあ! 君は何歳なの?\", 2)\n Entry.send_signal(\"信号\")\n\n#\"オブジェクト2\"のパイソンコード\ndef when_get_signal(\"信号\"):\n Entry.print_for_sec(\"やあ。僕は3歳だよ。\", 2)", "message_cast_exampleDesc": "[スタート]ボタンをクリックすると\"オブジェクト1\"が\"やあ! 君は何歳なの?\"と2秒間話し\"信号を送ります。, \"オブジェクト2\"が\"信号\"を受信した時、\"やあ。僕は3歳だよ。\"と2秒間話します。", "message_cast_wait_desc": "Aに入力された信号を送り、その信号を受信したコマンドの実行が終了するまで待機します。
もしA信号がなければ[属性]タブにA信号が自動作成されます。", "message_cast_wait_elements": "A-- \"信号名\"", "message_cast_wait_exampleCode": "#\"オブジェクト1\"のパイソンコード\ndef when_start():\n Entry.print_for_sec(\"かくれんぼしようよ!\", 2)\n Entry.send_signal_wait(\"信号\")\n Entry.hide()\n\n#\"オブジェクト2\"のパイソンコード\ndef when_get_signal(\"信号\"):\n Entry.print_for_sec(\"いいよ!\", 2)", "message_cast_wait_exampleDesc": "[スタート]ボタンをクリックすると\"オブジェクト1\"が\"かくれんぼしようよ!\"と2秒間話して\"信号\"を送信してから待機します。\"オブジェクト2\"が\"信号\"を受信すると\"いいよ!\"を2秒間話します。\"オブジェクト1\"がその後に模様を隠します。", "when_scene_start_desc": "シーンが始まると下のコマンドを実行します。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "when_scene_start_exampleCode": "#\"シーン 1\"のパイソンコード\ndef when_start():\n Entry.print_for_sec(\"他の場所に行こうか?\", 2)\n Entry.start_scene(\"シーン 2\")\n\n#\"シーン 2\"のパイソンコード\ndef when_start_scene():\n Entry.print(\"ここはどこだろう?\")", "when_scene_start_exampleDesc": "\"シーン1\"で[スタート]ボタンをクリックすると\"他の場所に行こうか?\"と2秒間話し、\"シーン2\"が始まります。\"シーン2\"が始まるとオブジェクトが\"ここはどこだろう?\"と話します。", "start_scene_desc": "A シーンを始めます。", "start_scene_elements": "A-- \"シーン名\"", "start_scene_exampleCode": "#\"シーン1\"のパイソンコード\ndef when_click_object_on():\n Entry.start_scene(\"シーン2\")", "start_scene_exampleDesc": "\"シーン1\"で当該オブジェクトをクリックすると、\"シーン 2\"が始まります。", "start_neighbor_scene_desc": "Aに入力した次または前のシーンを始めます。", "start_neighbor_scene_elements": "A-- 次の選択肢のうち一つ
① 次のシーン: \"next\"または\"次\"
② 前のシーン: \"prev\"または\"前\"", "start_neighbor_scene_exampleCode": "#\"シーン 1\"のパイソンコード\ndef when_press_key(\"right\"):\n Entry.start_scene_of(\"next\")\n\n#\"シーン 2\"のパイソンコード\ndef when_press_key(\"left\"):\n Entry.start_scene_of(\"prev\")", "start_neighbor_scene_exampleDesc": "\"シーン 1\"で右方向キーを押すと次のシーンが、\"シーン2\"で左方向キーを押すと前のシーンが始まります。", "wait_second_desc": "A秒待機後、次のブロックを実行します。", "wait_second_elements": "A-- 秒に該当する数を入力", "wait_second_exampleCode": "def when_start():\n Entry.add_effect(\"color\", 10)\n Entry.wait_for_sec(2)\n Entry.add_size(10)", "wait_second_exampleDesc": "[スタート]ボタンをクリックするとオブジェクトに色効果を10だけ与え、2秒間待機した後にサイズを10だけ大きくします。", "repeat_basic_desc": "下のコマンドをA回繰り返して実行します。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "repeat_basic_elements": "A-- 繰り返し回数入力", "repeat_basic_exampleCode": "def when_start():\n for i in range(10):\n Entry.move_to_direction(10)\n Entry.stamp()", "repeat_basic_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが移動方向に10移動し、スタンプを押す行動を10回繰り返します。", "repeat_inf_desc": "A 判断がTrueの間、下のコマンドを繰り返し実行します。AにTrueを入力すると続けて繰り返されます。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "repeat_inf_elements": "A-- TrueまたはFalseと判断できるコマンド入力(判断カテゴリーのコマンド)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10など
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\")など", "repeat_inf_exampleCode": "def when_start():\n while True:\n Entry.move_to_direction(10)\n Entry.bounce_on_edge()", "repeat_inf_exampleDesc": "[スタート]ボタンをクリックするとオブジェクトが続けて移動方向に10移動し、壁にぶつかると弾かれます。", "repeat_while_true_desc": "A判断がTrueになるまで下のコマンドを繰り返し実行します。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "repeat_while_true_elements": "A-- TrueまたはFalseと判断できるコマンド入力(判断カテゴリーのコマンド)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10など
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\")など", "repeat_while_true_exampleCode": "def when_start():\n while not Entry.is_key_pressed(\"space\"):\n Entry.add_rotation(90)", "repeat_while_true_exampleDesc": "[スタート]ボタンをクリックすると、スペースキーを押す時までオブジェクトが90度回転します。", "stop_repeat_desc": "このコマンドと最も近いリピートコマンドの繰り返しを中断します。", "stop_repeat_exampleCode": "def when_start():\n while True:\n Entry.move_to_direction(10)\n if Entry.is_key_pressed(\"enter\"):\n break", "stop_repeat_exampleDesc": "[スタート]ボタンをクリックするとオブジェクトが移動方向に10だけ継けて移動します。エンターキーを押すと繰り返しが中断されます。", "_if_desc": "A部分の判断がTrueならif A:下のコマンドを実行し、Falseなら実行しません。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "_if_elements": "A-- TrueまたはFalseと判断できるコマンド入力(判断カテゴリーのコマンド)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10など
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\")など", "_if_exampleCode": "def when_click_mouse_on():\n if (Entry.value_of_mouse_pointer(\"x\") > 0):\n Entry.print_for_sec(\"右側!\", 0.5)", "_if_exampleDesc": "マウスをクリックした時、マウスのx座標が0より大きければオブジェクトが\"右側!\"と0.5秒間話します。", "if_else_desc": "A部分の判断がTrueならif A: 下のコマンドを実行し、Falseならelse: 下のコマンドを実行します。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "if_else_elements": "A-- TrueまたはFalseと判断できるコマンド入力(判断カテゴリーのコマンド)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10など
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\")など", "if_else_exampleCode": "def when_click_mouse_on():\n if Entry.is_touched(\"mouse_pointer\"):\n Entry.print(\"触れた!\")\n else:\n Entry.print(\"触れなかった!\")", "if_else_exampleDesc": "マウスをクリックした時マウスポインターがオブジェクトに触れると\"触れた!\"を、そうでない時は\"触れなかった!\"と話します。", "wait_until_true_desc": "A部分の判断がTrueになるまでコードの実行を中断して待機します。", "wait_until_true_elements": "A-- TrueまたはFalseと判断できるコマンド入力(判断カテゴリーのコマンド)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10など
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\")など", "wait_until_true_exampleCode": "def when_start():\n Entry.print(\"エンターを押してみて!\")\n Entry.wait_until(Entry.is_key_pressed(\"enter\"))\n Entry.print(\"うまいね!\")", "wait_until_true_exampleDesc": "[スタート]ボタンをクリックするとオブジェクトが\"エンターを押してみて!\"と話し、エンターキーを押す時まで待機します。エンターキーを押すと\"うまいね!\"と話します。", "stop_object_desc": "Aコードの実行を中断します。", "stop_object_elements": "A-- 次の選択肢のうち1つ
① \"all\": すべてのオブジェクトのすべてのコード
② \"self\" : 当該オブジェクトのすべてのコード
③ \"this\": このコマンドが含まれたコード
④ \"others\" : 当該オブジェクトのコードのうち、このコマンドが含まれたコードを除くすべてのコード
⑤ \"ohter_objects\" : このオブジェクトを除く他のすべてのオブジェクトのコード", "stop_object_exampleCode": "def when_start():\n while True:\n Entry.move_to(\"mouse_pointer\")\n\ndef when_press_key(\"space\"):\n Entry.stop_code(\"all\")\n", "stop_object_exampleDesc": "[スタート]ボタンをクリックするとオブジェクトが続けてマウスポインターの位置に移動します。スペースキーを押すと、すべてのコードの実行が中断されます。", "restart_project_desc": "作品を最初から再実行します。", "restart_project_exampleCode": "def when_start():\n while True:\n Entry.add_size(10)\n\ndef when_press_key(\"enter\"):\n Entry.start_again()", "restart_project_exampleDesc": "[スタート]ボタンをクリックするとオブジェクトのサイズが続けてアップします。エンターキーを押すと作品を最初から再実行します。", "when_clone_start_desc": "当該オブジェクトのコピーが新しく作成された時、下のコマンドを実行します。
下のコマンドは[Tab]キーを用いてインデントを作成します。", "when_clone_start_exampleCode": "def when_start():\n for i in range(5):\n Entry.make_clone_of(\"self\")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))", "when_clone_start_exampleDesc": "[スタート]ボタンをクリックすると自分のコピーを5つ作成します。コピーが新しく作成された際、コピーのx座標を-200から200の間の乱数にします。", "create_clone_desc": "A オブジェクトのコピーを作成します。", "create_clone_elements": "A-- 次の選択肢のうち一つ
① \"オブジェクト名\"
② \"self\"または\"自分\"", "create_clone_exampleCode": "def when_start():\n for i in range(5):\n Entry.make_clone_of(\"self\")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))", "create_clone_exampleDesc": "[スタート]ボタンをクリックすると、自分のコピーを5つ作成します。コピーが新しく作成された際、コピーのx座標を-200から200までの乱数にします。", "delete_clone_desc": "Entry.make_clone_of(A) コマンドにより作成されたコピーを削除します。", "delete_clone_exampleCode": "def when_start():\n for i in range(5):\n Entry.make_clone_of(\"自分\")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))\n\ndef when_click_object_on():\n Entry.remove_this_clone()", "delete_clone_exampleDesc": "[スタート]ボタンをクリックすると自分のコピーを5つ作成します。コピーが新しく作成された際、コピーのx座標を-200から200までの乱数にします。コピーをクリックするとクリックされたコピーを削除します。", "remove_all_clones_desc": "当該オブジェクトのすべてのコピーを削除します。", "remove_all_clones_exampleCode": "def when_start():\n for i in range(5):\n Entry.make_clone_of(\"自分\")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))\n\ndef when_press_key(\"space\"):\n Entry.remove_all_clone()", "remove_all_clones_exampleDesc": "[スタート]ボタンをクリックすると自分のコピーを5つ作成します。コピーが新しく作成された際、コピーのx座標を-200から200までの乱数にします。スペースキーを押すとすべてのコピーを削除します。", "move_direction_desc": "オブジェクトの移動方向矢印が示す方向にAだけ動きます。", "move_direction_elements": "A-- 移動する距離に該当する数", "move_direction_exampleCode": "def when_start():\n Entry.move_to_direction(10)", "move_direction_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが移動方向に10移動します。", "bounce_wall_desc": "オブジェクトが画面の端に到達すると弾かれます。", "bounce_wall_exampleCode": "def when_start():\n while True:\n Entry.move_to_direction(10)\n Entry.bounce_on_edge()", "bounce_wall_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが続けて移動方向に10移動し、壁にぶつかると弾かれます。", "move_x_desc": "オブジェクトのx座標をAだけ変更します。", "move_x_elements": "A-- x座標の変化値
① 正数: オブジェクトが右側に移動します。
② 負数: オブジェクトが左側に移動します。", "move_x_exampleCode": "def when_start():\n Entry.add_x(10)\n Entry.wait_for_sec(2)\n Entry.add_x(-10)", "move_x_exampleDesc": "[スタート]ボタンをクリックするとオブジェクトが右に10移動し、2秒間待機後、左に10移動します。", "move_y_desc": "オブジェクトのy座標をAだけ変更します。", "move_y_elements": "A-- y座標の変化値
① 正数: オブジェクトが上に移動します。
② 負数: オブジェクトが下に移動します。", "move_y_exampleCode": "def when_start():\n Entry.add_y(10)\n Entry.wait_for_sec(2)\n Entry.add_y(-10)", "move_y_exampleDesc": "[スタート]ボタンをクリックするとオブジェクトが上に10移動し、2秒間待機した後、下に10移動します。", "move_xy_time_desc": "オブジェクトがxとy座標をそれぞれAとBだけC秒に渡り徐々に変更します。", "move_xy_time_elements": "A-- x座標の変化値
① 正数: オブジェクトが右側に移動します。
② 負数: オブジェクトが左側に移動します。%nextB-- y座標の変化値
① 陽数: オブジェクトが上に移動します。
② 負数: オブジェクトが下に移動します。%nextC-- 移動する時間(秒)", "move_xy_time_exampleCode": "def when_start():\n Entry.add_xy_for_sec(100, 100, 2)\n Entry.add_xy_for_sec(-100, -100, 2)", "move_xy_time_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが右上に100だけ2秒間移動した後、左下に100だけ2秒間移動します。", "locate_x_desc": "オブジェクトのx座標をAにします。(オブジェクトの中心点が基準になります。)", "locate_x_elements": "A-- 移動するx座標", "locate_x_exampleCode": "def when_press_key(\"right\"):\n Entry.set_x(100)\n\ndef when_press_key(\"left\"):\n Entry.set_x(-100)\n", "locate_x_exampleDesc": "右方向キーを押すとオブジェクトのx座標を100にし、左方向キーを押すとオブジェクトのx座標を-100にします。", "locate_y_desc": "オブジェクトのy座標をAにします。(オブジェクトの中心点が基準になります。)", "locate_y_elements": "B-- 移動するy座標", "locate_y_exampleCode": "def when_press_key(\"up\"):\n Entry.set_y(100)\n\ndef when_press_key(\"down\"):\n Entry.set_y(-100)", "locate_y_exampleDesc": "上方向キーを押すとオブジェクトのy座標を100にし、下方向キーを押すとオブジェクトのy座標を-100にします。", "locate_xy_desc": "オブジェクトが座標(A, B)に移動します。(オブジェクトの中心点が基準になります。)", "locate_xy_elements": "A-- 移動するx座標%nextB-- 移動するy座標", "locate_xy_exampleCode": "def when_click_mouse_on():\n Entry.set_xy(0, 0)\n\ndef when_press_key(\"right\"):\n Entry.add_x(10)\n\ndef when_press_key(\"up\"):\n Entry.add_y(10)", "locate_xy_exampleDesc": "右方向キーを押すとオブジェクトのx座標を10だけ変更し、上方向キーを押すとオブジェクトのy座標を10だけ変更します。マウスをクリックすると、オブジェクトのx, y座標を0にします。", "locate_xy_time_desc": "オブジェクトが座標(A, B)に、C秒に渡り徐々に移動します。(オブジェクトの中心点が基準になります。)", "locate_xy_time_elements": "A-- 移動するx座標%nextB-- 移動するy座標%nextC-- 移動する時間", "locate_xy_time_exampleCode": "def when_click_mouse_on():\n Entry.set_xy_for_sec(0, 0, 2)\n\ndef when_press_key(\"right\"):\n Entry.add_x(10)\n\ndef when_press_key(\"up\"):\n Entry.add_y(10)", "locate_xy_time_exampleDesc": "右方向キーを押すとオブジェクトのx座標を10だけ変更し、上方向キーを押すとオブジェクトのy座標を10だけ変更します。マウスをクリックすると、2秒間オブジェクトをx,y 座標0に移動させます。", "locate_desc": "オブジェクトがAの位置に移動します。(オブジェクトの中心点が基準になります。)", "locate_elements": "A-- 次の選択肢のうち一つ
① \"オブジェクト名\"
② \"mouse_pointer\"または\"マウスポインター\"", "locate_exampleCode": "def when_click_mouse_on():\n Entry.move_to(\"mouse_pointer\")\n\ndef when_press_key(\"space\"):\n Entry.move_to(\"オブジェクト\")", "locate_exampleDesc": "マウスをクリックすると、オブジェクトがマウスポインターの位置に移動します。
スペースキーを押すとオブジェクトが\"オブジェクト\"位置に移動します。", "locate_object_time_desc": "オブジェクトがAの位置にB秒に渡り徐々に移動します。(オブジェクトの中心点が基準になります。)", "locate_object_time_elements": "A-- 次の選択肢のうち一つ
① \"オブジェクト名\"
② \"mouse_pointer\"または\"マウスポインター\" %nextB-- 移動する時間(秒)", "locate_object_time_exampleCode": "def when_click_mouse_on():\n Entry.move_to_for_sec(\"mouse_pointer\", 2)", "locate_object_time_exampleDesc": "マウスをクリックすると、オブジェクトが2秒間徐々にマウスポインターの位置に移動します。", "rotate_relative_desc": "オブジェクトの方向をA度だけ時計方向に回転します。(オブジェクトの中心点を基準に回転します。)", "rotate_relative_elements": "A-- 回転する角度", "rotate_relative_exampleCode": "def when_click_object_on():\n Entry.add_rotation(90)\n\ndef when_click_object_off():\n Entry.add_rotation(-90)", "rotate_relative_exampleDesc": "オブジェクトをクリックするとオブジェクトが90度だけ回転し、オブジェクトクリックを解除するとオブジェクトが-90度だけ回転します。", "direction_relative_desc": "オブジェクトの移動方向をA度だけ回転します。", "direction_relative_elements": "A-- 回転する角度", "direction_relative_exampleCode": "def when_start():\n Entry.move_to_direction(50)\n Entry.wait_for_sec(0.5)\n Entry.add_direction(90)\n Entry.wait_for_sec(0.5)\n Entry.move_to_direction(50)", "direction_relative_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが移動方向に50移動した後、0.5秒間待機します。その後、移動方向を90度だけ回転して0.5秒間待機した後、移動方向に50移動します。", "rotate_by_time_desc": "オブジェクトの方向を時計方向にA度だけB秒に渡り回転します。(オブジェクトの中心点を基準に回転します。)", "rotate_by_time_elements": "A-- 回転する角度%nextB-- 回転する時間(秒)", "rotate_by_time_exampleCode": "def when_start():\n Entry.add_rotation_for_sec(90, 2)\n Entry.add_rotation_for_sec(-90, 2)", "rotate_by_time_exampleDesc": "[スタート]ボタンをクリックするとオブジェクトが2秒間90度回転し、再び2秒間-90度回転します。", "direction_relative_duration_desc": "オブジェクトの移動方向を時計方向にA度だけB秒に渡り回転します。(オブジェクトの中心点を基準に回転します。)", "direction_relative_duration_elements": "A-- 回転する角度%nextB-- 回転する時間(秒)", "direction_relative_duration_exampleCode": "def when_start():\n Entry.add_direction_for_sec(90, 2)\n\ndef when_start():\n while True:\n Entry.move_to_direction(1)", "direction_relative_duration_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトの移動方向を2秒間90度回転させます。同時にオブジェクトは移動方向に1ずつ継続して移動します。", "rotate_absolute_desc": "オブジェクトの方向をAにします。", "rotate_absolute_elements": "A-- 設定する方向", "rotate_absolute_exampleCode": "def when_press_key(\"right\"):\n Entry.set_rotation(90)\n\ndef when_press_key(\"left\"):\n Entry.set_rotation(270)", "rotate_absolute_exampleDesc": "右方向キーを押すとオブジェクトの方向を90にし、左方向キーを押すとオブジェクトの方向を270にします。", "direction_absolute_desc": "オブジェクトの移動方向をAにします。", "direction_absolute_elements": "A-- 設定する移動方向", "direction_absolute_exampleCode": "def when_press_key(\"right\"):\n Entry.set_direction(90)\n Entry.move_to_direction(10)\n\ndef when_press_key(\"left\"):\n Entry.set_direction(270)\n Entry.move_to_direction(10)", "direction_absolute_exampleDesc": "右方向キーを押すとオブジェクトの移動方向を90にした後、その方向に10移動し、左方向キーを押すとオブジェクトの移動方向を270にしてその方向に10移動します。", "see_angle_object_desc": "オブジェクトがAの方向を向きます。(移動方向がAを向くようにオブジェクトの方向を回転させます。)", "see_angle_object_elements": "A-- 次の選択肢のうち一つ
① \"オブジェクト名\"
② \"mouse_pointer\"または\"マウスポインター\"", "see_angle_object_exampleCode": "def when_click_mouse_on():\n Entry.look_at(\"mouse_pointer\")\n\ndef when_press_key(\"space\"):\n Entry.look_at(\"オブジェクト\")", "see_angle_object_exampleDesc": "マウスをクリックするとオブジェクトがマウスポインターの方向を向き、スペースキーを押すと\"オブジェクト\"の方向を向きます。", "move_to_angle_desc": "オブジェクトがAだけB方向に動きます。", "move_to_angle_elements": "A-- 移動する距離に該当する数%nextB-- 移動する方向(12時方向が0度、時計方向に増加)", "move_to_angle_exampleCode": "def when_press_key(\"up\"):\n Entry.move_to_degree(10, 0)\n\ndef when_press_key(\"down\"):\n Entry.move_to_degree(10, 180)", "move_to_angle_exampleDesc": "上方向キーを押すとオブジェクトが0度方向に10移動し、下方向キーを押すとオブジェクトが180度方向に10移動します。", "show_desc": "オブジェクトを画面に表示します。", "show_exampleCode": "def when_start():\n Entry.wait_for_sec(1)\n Entry.hide()\n Entry.wait_for_sec(1)\n Entry.show()", "show_exampleDesc": "[スタート]ボタンをクリックすると、1秒後にオブジェクト模様が非表示になり、次の1秒後にオブジェクト模様が表示されます。", "hide_desc": "オブジェクトを画面で非表示にします。", "hide_exampleCode": "def when_start():\n Entry.wait_for_sec(1)\n Entry.hide()\n Entry.wait_for_sec(1)\n Entry.show()", "hide_exampleDesc": "[スタート]ボタンをクリックすると、1秒後にオブジェクト模様が非表示になり、次の1秒後にオブジェクト模様が表示されます。", "dialog_time_desc": "オブジェクトがAをB秒間吹き出しで話した後、次のコマンドが実行されます。コンソールウィンドウでも実行結果を確認できます。", "dialog_time_elements": "A-- 話す内容
① 文字: \"やあ!\", \"エントリー\"など
② 数字: 0, 10, 35など%nextB-- 話す時間(秒)", "dialog_time_exampleCode": "def when_start():\n Entry.print_for_sec(\"やあ! 僕は\", 2)\n Entry.print_for_sec(16, 2)\n Entry.print_for_sec(\"歳だよ\", 2)", "dialog_time_exampleDesc": "[スタート]ボタンをクリックすると、\"やあ! 僕は\", 16, \"歳だよ\"をそれぞれ2秒間順番どおりに話します。", "dialog_desc": "オブジェクトがAを吹き出しで話します。コンソールウィンドウでも実行結果を確認できます。", "dialog_elements": "A-- 話す内容
① 文字: \"やあ!\", \"エントリー\"など
② 数字: 0, 10, 35など", "dialog_exampleCode": "def when_start():\n Entry.print(\"キーボードで数字の1、2を押したら数字を言ってみるね\")\n\ndef when_press_key(1):\n Entry.print(1)\n\ndef when_press_key(2):\n Entry.print(2)\n", "dialog_exampleDesc": "[スタート]ボタンをクリックすると\"キーボードで数字の1、2を押したら、数字を言ってみるね\"と話し、キーボードで1、2を押すとそれぞれ1、2と話します。", "remove_dialog_desc": "オブジェクトが話している吹き出しを消します。", "remove_dialog_exampleCode": "def when_start():\n Entry.print(\"吹き出しを消すにはエンターを押して!\")\n\ndef when_press_key(\"enter\"):\n Entry.clear_print()", "remove_dialog_exampleDesc": "[スタート]ボタンをクリックすると、\"吹き出しを消すにはエンターを押して!\"と話し、エンターキーを押すと吹き出しが消えます。", "change_to_some_shape_desc": "オブジェクトをA模様に変更します。", "change_to_some_shape_elements": "A-- 次の選択肢のうち1つ
① 模様名 : [属性] タブの\"模様名\"を記載
② 模様番号 : [属性] タブの模様番号を記載", "change_to_some_shape_exampleCode": "def when_start():\n Entry.wait_for_sec(0.3)\n Entry.change_shape(\"オブジェクト模様\")\n Entry.wait_for_sec(0.3)\n Entry.change_shape(\"オブジェクト模様\")", "change_to_some_shape_exampleDesc": "[スタート]ボタンをクリックすると、0.3秒間待機した後に\"オブジェクト模様\"に模様を変更し、0.3秒間待機した後に\"オブジェクト模様\"模様に模様を変更します。", "change_to_next_shape_desc": "オブジェクトの模様を次または前の模様に変更します。", "change_to_next_shape_elements": "A-- 次の選択肢のうち一つ
① 次の模様: \"next\"または\"次\"
② 前の模様: \"pre\"または\"前\"", "change_to_next_shape_exampleCode": "def when_start():\n Entry.wait_for_sec(0.3)\n Entry.change_shape_to(\"next\")\n Entry.wait_for_sec(0.3)\n Entry.change_shape_to(\"pre\")", "change_to_next_shape_exampleDesc": "[スタート]ボタンをクリックすると、0.3秒間待機した後に次のオブジェクト模様に変更し、0.3秒間待機した後に前の模様にオブジェクト模様を変更します。", "add_effect_amount_desc": "オブジェクトにA効果をBだけ加えます。", "add_effect_amount_elements": "A -- 次の選択肢のうち一つ
① “color”または“色“
② “brightness”または“明度”
③ “transparency”または“透明度”%nextB-- 効果の変化の程度", "add_effect_amount_exampleCode": "def when_click_mouse_on():\n Entry.add_effect(\"color\", 50)\n Entry.wait_for_sec(1)\n Entry.add_effect(\"brightness\", -50)\n Entry.wait_for_sec(1)\n Entry.add_effect(\"transparency\", 50)", "add_effect_amount_exampleDesc": "マウスをクリックすると、オブジェクトに色効果を50与えて1秒間待機し、明度効果を-50加えて1秒間待機します。その後、透明度効果を50加えます。", "change_effect_amount_desc": "オブジェクトのA効果をBにします。", "change_effect_amount_elements": "A-- 次の選択肢のうち一つ
① “color”または“色“
② “brightness”または“明度”
③ “transparency”または“透明度”%nextB-- 効果の値
① color: 0~100範囲の数、100を周期として繰り返す
② brightness: -100~100間の範囲の数、-100以下は-100で、100以上は100で処理される
③ transparency: 0~100間の範囲の数、0以下は0に、100以上は100で処理される", "change_effect_amount_exampleCode": "def when_click_mouse_on():\n Entry.set_effect(\"color\", 50)\n Entry.set_effect(\"brightness\", 50)\n Entry.set_effect(\"transparency\", 50)\n\ndef when_click_mouse_off():\n Entry.set_effect(\"color\", 0)\n Entry.set_effect(\"brightness\", 0)\n Entry.set_effect(\"transparency\", 0)", "change_effect_amount_exampleDesc": "マウスをクリックすると、オブジェクトに色、明度、透明度効果を50にし、マウスクリックを解除するとそれぞれの効果を0にします。", "erase_all_effects_desc": "オブジェクトに適用された効果をすべて削除します。", "erase_all_effects_exampleCode": "def when_click_mouse_on():\n Entry.set_effect(\"color\", 50)\n Entry.set_effect(\"brightness\", 50)\n Entry.set_effect(\"transparency\", 50)\n\ndef when_click_mouse_off():\n Entry.clear_effect()\n", "erase_all_effects_exampleDesc": "マウスをクリックするとオブジェクトに色、明度、透明度効果を50にし、マウスクリックを解除するとオブジェクトに適用されたすべての効果を消します。", "change_scale_size_desc": "オブジェクトのサイズをAだけ変更します。", "change_scale_size_elements": "A-- サイズ変化値", "change_scale_size_exampleCode": "def when_press_key(\"up\"):\n Entry.add_size(10)\n\ndef when_press_key(\"down\"):\n Entry.add_size(-10)\n\ndef when_press_key(\"space\"):\n Entry.set_size(100)", "change_scale_size_exampleDesc": "上方向キーを押すとオブジェクトのサイズが10大きくなり、下方向キーを押すとオブジェクトのサイズが10だけ小さくなります。スペースキーを押すとオブジェクトのサイズを100にします。", "set_scale_size_desc": "オブジェクトのサイズをAにします。", "set_scale_size_elements": "A-- サイズ値", "set_scale_size_exampleCode": "def when_press_key(\"up\"):\n Entry.add_size(10)\n\ndef when_press_key(\"down\"):\n Entry.add_size(-10)\n\ndef when_press_key(\"space\"):\n Entry.set_size(100)", "set_scale_size_exampleDesc": "上方向キーを押すとオブジェクトのサイズが10だけ大きくなり、下方向キーを押すとオブジェクトのサイズが10だけ小さくなります。スペースキーを押すとオブジェクトのサイズを100にします。", "flip_x_desc": "オブジェクトの上下の模様を入れ替えます。", "flip_x_exampleCode": "def when_press_key(\"up\"):\n Entry.flip_horizontal()\n\ndef when_press_key(\"right\"):\n Entry.flip_vertical()", "flip_x_exampleDesc": "上方向キーを押すとオブジェクトの上下の模様を入れ替え、右方向キーを押すとオブジェクトの左右の模様を入れ替えます。", "flip_y_desc": "オブジェクトの左右の模様を入れ替えます。", "flip_y_exampleCode": "def when_press_key(\"up\"):\n Entry.flip_horizontal()\n\ndef when_press_key(\"right\"):\n Entry.flip_vertical()", "flip_y_exampleDesc": "上方向キーを押すとオブジェクトの上下の模様を入れ替え、右方向キーを押すとオブジェクトの左右の模様を入れ替えます。", "change_object_index_desc": "オブジェクトのレイヤーをAに移動させます。", "change_object_index_elements": "A-- 次の選択肢のうち一つ
① “front\"または“一番前“
② “forward”または“前”
③ “backward”または“後ろ”
④ “back”または“一番後ろ”", "change_object_index_exampleCode": "def when_start():\n Entry.send_layer_to(\"front\")\n Entry.wait_for_sec(2)\n Entry.send_layer_to(\"backward\")", "change_object_index_exampleDesc": "オブジェクトが複数重なっている場合、[スタート]ボタンをクリックすると当該オブジェクトのレイヤーを一番前に移動させて表示します。", "brush_stamp_desc": "オブジェクトの模様をスタンプのように実行画面上に押します。", "brush_stamp_exampleCode": "def when_start():\n for i in range(10):\n Entry.move_to_direction(10)\n Entry.stamp()", "brush_stamp_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが移動方向に10移動し、スタンプを押す行動を10回繰り返します。", "start_drawing_desc": "オブジェクトが移動する経路に沿って線を引きます。(オブジェクトの中心点が基準)", "start_drawing_exampleCode": "def when_start():\n Entry.start_drawing()\n for i in range(10):\n Entry.move_to_direction(10)", "start_drawing_exampleDesc": "[スタート]ボタンをクリックすると描画がスタートし、オブジェクトが移動方向に10だけ10回移動するとき、オブジェクトの移動経路に沿って線が引かれます。", "stop_drawing_desc": "オブジェクトが線を描くのを中断します。", "stop_drawing_exampleCode": "def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(1)\n\ndef when_click_mouse_on():\n Entry.stop_drawing()", "stop_drawing_exampleDesc": "[スタート]ボタンをクリックすると描画が始まり、続けてオブジェクトが移動方向に10移動します。マウスをクリックすると、描画を中断します。", "set_color_desc": "オブジェクトが描く線の色をAにします。", "set_color_elements": "A-- 次の選択肢のうち一つ
① カラーコード: \"#FF0000\", \"#FFCC00\", \"#3333FF\", \"#000000\"など
② 色 : \"red\", \"orange\", \"yellow\", \"green\", \"blue\", \"navy\", \"purple\", \"black\", \"white\", \"brown\"", "set_color_exampleCode": "def when_start():\n Entry.start_drawing()\n Entry.set_brush_color_to(\"#000099\")\n while True:\n Entry.move_to_direction(1)", "set_color_exampleDesc": "[スタート]ボタンをクリックすると描画がスタートし、線の色を\"#000099\"にします。オブジェクトは続けて移動方向に1だけ動き、オブジェクトの移動経路に沿って線が引かれます。", "set_random_color_desc": "オブジェクトが描く線の色をランダムにします。", "set_random_color_exampleCode": "def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(1)\n Entry.set_brush_color_to_random()", "set_random_color_exampleDesc": "[スタート]ボタンをクリックすると描画がスタートします。オブジェクトは続けて移動方向に1だけ動き、オブジェクトの移動経路に沿って線が引かれます。線の色は続けてランダムで決まります。", "change_thickness_desc": "オブジェクトが描く線の太さをAだけ変更します。", "change_thickness_elements": "A-- 太さ変化値", "change_thickness_exampleCode": "def when_start():\n Entry.start_drawing()\n while True:\n Entry.add_brush_size(1)\n Entry.move_to_direction(10)", "change_thickness_exampleDesc": "[スタート]ボタンをクリックすると描画がスタートします。オブジェクトは続けて移動方向に10だけ動き、オブジェクトの移動経路に沿って線が引かれます。線の太さは続けて1ずつ大きくなります。", "set_thickness_desc": "オブジェクトが描く線の太さをAにします。", "set_thickness_elements": "A-- 太さ値(1以上の数)", "set_thickness_exampleCode": "def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n while True:\n Entry.move_to_direction(10)", "set_thickness_exampleDesc": "[スタート]ボタンをクリックすると描画がスタートし、線の太さを10にします。オブジェクトは続けて移動方向に10動き、オブジェクトの移動経路に沿って線が引かれます。", "change_brush_transparency_desc": "オブジェクトが描く線の透明度をAだけ変更します。", "change_brush_transparency_elements": "A-- 透明度変化値", "change_brush_transparency_exampleCode": "def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n while True:\n Entry.move_to_direction(10)\n Entry.add_brush_transparency(5)", "change_brush_transparency_exampleDesc": "[スタート]ボタンをクリックすると描画がスタートし、線の太さを10にします。オブジェクトは続けて移動方向に10動き、オブジェクトの移動経路に沿って線が引かれます。線の透明度は続けて5だけ変更します。", "set_brush_tranparency_desc": "オブジェクトが描く線の透明度をAにします。", "set_brush_tranparency_elements": "A-- 透明度値(0~100の範囲)", "set_brush_tranparency_exampleCode": "def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n Entry.set_brush_transparency(50)\n while True:\n Entry.move_to_direction(10)", "set_brush_tranparency_exampleDesc": "[スタート]ボタンをクリックすると描画がスタートし、線の太さを10に、線の透明度を50にします。オブジェクトは続けて移動方向に10だけ動き、オブジェクトの移動経路に沿って線が引かれます。", "brush_erase_all_desc": "オブジェクトが描いた線とスタンプをすべて削除します。", "brush_erase_all_exampleCode": "def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(10)\n\ndef when_click_mouse_on():\n Entry.clear_drawing()", "brush_erase_all_exampleDesc": "[スタート]ボタンをクリックすると描画がスタートします。オブジェクトは続けて移動方向に10だけ動き、オブジェクトの移動経路に沿って線が引かれます。マウスをクリックするとオブジェクトが描いた線をすべて削除します。", "text_read_desc": "글상자 A의 내용입니다.
(내용 안에 개행이 있는 경우, 띄어쓰기하여 반환됩니다.)", "text_read_elements": "A-- 아래 선택지 중 하나
① \"오브젝트(글상자) 이름\"
② 자기 자신", "text_read_exampleCode": "def when_start():\n Entry.print(Entry.contents_of_textbox(\"A\"))", "text_read_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 글상자 \"A\"의 내용을 말합니다.​", "text_write_desc": "テキストボックスの内容をAに書き換えます。", "text_write_elements": "A-- テキストボックスの内容
① 文字: \"やあ!\", \"エントリー\"など
② 数字: 0, 10, 35など", "text_write_exampleCode": "def when_start():\n Entry.write_text(\"エントリー\")", "text_write_exampleDesc": "[スタート]ボタンをクリックすると、テキストボックスの内容を\"エントリー\"に変更します。", "text_append_desc": "テキストボックスの内容の後にAを追加します。", "text_append_elements": "A-- テキストボックスの内容
① 文字: \"やあ!\", \"エントリー\"など
② 数字: 0, 10, 35など", "text_append_exampleCode": "def when_start():\n Entry.write_text(\"やあ!\")\n Entry.wait_for_sec(1)\n Entry.append_text(\"エントリー!\")", "text_append_exampleDesc": "[スタート]ボタンをクリックすると、テキストボックスの内容の\"やあ!\"に1秒後に\"エントリー!\"が追加され、\"やあ!エントリー!\"になります。", "text_prepend_desc": "テキストボックスの内容の前にAを追加します。", "text_prepend_elements": "A-- テキストボックスの内容
① 文字: \"やあ!\", \"エントリー\"など
② 数字: 0, 10, 35など", "text_prepend_exampleCode": "def when_start():\n Entry.write_text(\"嬉しいな!\")\n Entry.wait_for_sec(1)\n Entry.prepend_text(\"エントリー!\")", "text_prepend_exampleDesc": "[スタート]ボタンをクリックすると、テキストボックスの内容が\"嬉しいな!\"になってから、1秒後に\"エントリー!\"が前に追加され\"エントリー!嬉しいな!\"になります。", "text_flush_desc": "テキストボックスに保存された値をすべて削除します。", "text_flush_exampleCode": "def when_start():\n Entry.write_text(\"エントリー\")\n Entry.wait_for_sec(1)\n Entry.clear_text()", "text_flush_exampleDesc": "[スタート]ボタンをクリックすると、テキストボックスの内容が\"エントリー\"になってから、1秒後にすべての内容が消えます。", "sound_something_with_block_desc": "オブジェクトがAサウンドを再生します。", "sound_something_with_block_elements": "A-- 次の選択肢のうち一つ
① サウンド名 : [属性] タブの\"サウンド名\"を記載
② サウンド番号: [属性] タブのサウンド番号を記載", "sound_something_with_block_exampleCode": "def when_start():\n Entry.play_sound(\"サウンド\")\n Entry.add_size(50)", "sound_something_with_block_exampleDesc": "[スタート]ボタンをクリックすると、\"サウンド\"を再生しながらオブジェクトのサイズが50大きくなります。", "sound_something_second_with_block_desc": "オブジェクトがAサウンドをB秒間再生します。", "sound_something_second_with_block_elements": "A-- 次の選択肢のうち一つ
① サウンド名 : [属性] タブの\"サウンド名\"を記載
② サウンド番号: [属性] タブのサウンド番号を記載", "sound_something_second_with_block_exampleCode": "def when_start():\n Entry.play_sound_for_sec(\"サウンド\", 1)\n Entry.add_size(50)", "sound_something_second_with_block_exampleDesc": "[スタート]ボタンをクリックすると\"サウンド\"を1秒間再生しながら、オブジェクトのサイズが50程度大きくなります。", "sound_from_to_desc": "オブジェクトがAサウンドをB秒からC秒まで再生します。", "sound_from_to_elements": "A-- 次の選択肢のうち1つ
① サウンド名 : [属性] タブの\"サウンド名\"を記載
② サウンド番号: [属性] タブのサウンド番号を記載", "sound_from_to_exampleCode": "def when_start():\n Entry.play_sound_from_to(\"サウンド\", 0.5, 1)\n Entry.add_size(50)", "sound_from_to_exampleDesc": "[スタート]ボタンをクリックすると、\"サウンド\"を0.5秒から1秒区間までのみ再生しながら、オブジェクトのサイズが50程度大きくなります。", "sound_something_wait_with_block_desc": "オブジェクトがAサウンドを再生し、再生が終わると次のコマンドを実行します。", "sound_something_wait_with_block_elements": "A-- 次の選択肢のうち1つ
① サウンド名 : [属性]タブの\"サウンド名\"を記載
② サウンド番号: [属性]タブのサウンド番号を記載", "sound_something_wait_with_block_exampleCode": "def when_start():\n Entry.play_sound_and_wait(\"サウンド\")\n Entry.add_size(50)", "sound_something_wait_with_block_exampleDesc": "[スタート]ボタンをクリックすると\"サウンド\"を再生し、再生が終わるとオブジェクトのサイズが50大きくなります。", "sound_something_second_wait_with_block_desc": "オブジェクトがAサウンドをB秒再生し、再生が終わると次のコマンドを実行します。", "sound_something_second_wait_with_block_elements": "A-- 次の選択肢のうち1つ
① サウンド名 : [属性]タブの\"サウンド名\"を記載
② サウンド番号: [属性]タブのサウンド番号を記載", "sound_something_second_wait_with_block_exampleCode": "def when_start():\n Entry.play_sound_for_sec_and_wait(\"サウンド\", 1)\n Entry.add_size(50)", "sound_something_second_wait_with_block_exampleDesc": "[スタート]ボタンをクリックすると、\"サウンド\"を1秒間再生し、再生が終わるとオブジェクトのサイズが50大きくなります。", "sound_from_to_and_wait_desc": "オブジェクトがAサウンドをB秒からC秒まで再生し、再生が終わると次のコマンドを実行します。", "sound_from_to_and_wait_elements": "A-- 次の選択肢のうち1つ
① サウンド名 : [属性]タブの\"サウンド名\"を記載
② サウンド番号: [属性]タブのサウンド番号を記載", "sound_from_to_and_wait_exampleCode": "def when_start():\n Entry.play_sound_from_to_and_wait(\"サウンド\", 0.5, 1)\n Entry.add_size(50)", "sound_from_to_and_wait_exampleDesc": "[スタート]ボタンをクリックすると、\"サウンド\"を0.5秒から1秒区間までのみ再生し、再生が終わるとオブジェクトのサイズが50大きくなります。", "sound_volume_change_desc": "作品で再生されるすべての サウンドのボリュームをA%分変更します。", "sound_volume_change_elements": "A-- ボリュームの大きさ変化値", "sound_volume_change_exampleCode": "def when_press_key(\"up\"):\n Entry.add_sound_volume(10)\n\ndef when_press_key(\"down\"):\n Entry.add_sound_volume(-10)\n\ndef when_start():\n while True:\n Entry.play_sound_and_wait(\"サウンド\")", "sound_volume_change_exampleDesc": "[スタート]ボタンをクリックすると、\"サウンド\"を続けて再生します。上方向キーを押すとサウンドのサイズが10\"大きくなり、下方向キーを押すとサウンドのサイズが10\"小さくなります。", "sound_volume_set_desc": "作品で再生されるすべての サウンドのボリュームをA%にします。", "sound_volume_set_elements": "A-- ボリュームの大きさ値", "sound_volume_set_exampleCode": "def when_press_key(\"up\"):\n Entry.add_sound_volume(10)\n\ndef when_press_key(\"down\"):\n Entry.add_sound_volume(-10)\n\ndef when_press_key(\"enter\"):\n Entry.set_sound_volume(100)\n\ndef when_start():\n while True:\n Entry.play_sound_and_wait(\"サウンド\")", "sound_volume_set_exampleDesc": "[スタート]ボタンをクリックすると、\"サウンド\"を続けて再生します。上方向キーを押すとサウンドのサイズが10\"大きくなり、下方向キーを押すとサウンドのサイズが10\"小さくなります。エンターキーを押すとサウンドのボリュームを100\"にします。", "sound_silent_all_desc": "現在再生中のすべてのサウンドを止めます。", "sound_silent_all_exampleCode": "def when_start():\n while True:\n Entry.play_sound_and_wait(\"サウンド\")\n\ndef when_press_key(\"enter\"):\n Entry.stop_sound()", "sound_silent_all_exampleDesc": "[スタート]ボタンをクリックすると、\"サウンド\"を続けて再生します。エンターキーを押すと現在再生中のサウンドを止めます。", "is_clicked_desc": "マウスをクリックした場合、Trueと判断します。", "is_clicked_exampleCode": "def when_start():\n while True:\n if Entry.is_mouse_clicked():\n Entry.print_for_sec(\"嬉しいな!\", 0.5)", "is_clicked_exampleDesc": "[スタート]ボタンをクリックすると、続けてマウスをクリックしたか確認します。もしマウスをクリックしたら、オブジェクトが\"嬉しいな!\"と0.5秒間話します。", "is_press_some_key_desc": "A キーが押されている場合、Trueと判断します。", "is_press_some_key_elements": "A-- 次の選択肢のうち一つ
① アルファベット : \"A\", \"B\" ~ \"Z\"など(小文字可能)
② 数字: 1, 2, 3, 4 ~ 9, 0
③ 特殊キー: \"space\", \"enter\"
④ 方向キー : \"up\", \"down\", \"right\", \"left\"", "is_press_some_key_exampleCode": "def when_start():\n while True:\n if Entry.is_key_pressed(\"space\"):\n Entry.move_to_direction(10)", "is_press_some_key_exampleDesc": "[スタート]ボタンをクリックすると、続けて選択したキーを押したか確認します。もしスペースキーを押したらオブジェクトが移動方向に10移動します。", "reach_something_desc": "オブジェクトがAに触れた場合、Trueと判断します。", "reach_something_elements": "A-- 次の選択肢のうち1つ
① \"オブジェクト名\"
② \"mouse_pointer\"または\"マウスポインター\"
③ \"edge\", \"edge_up\", \"edge_down\", \"edge_right\", \"edge_left\"", "reach_something_exampleCode": "def when_start():\n while True:\n Entry.move_to_direction(10)\n if Entry.is_touched(\"edge\"):\n Entry.add_rotation(150)", "reach_something_exampleDesc": "[スタート]ボタンをクリックすると、続けてオブジェクトが移動方向に10移動します。オブジェクトが壁に触れると150だけ回転します。", "boolean_basic_operator_desc": "AとBを比較してTrueまたはFalseと判断します。", "boolean_basic_operator_elements": "A, B-- 比較したい数字値
① == : AとBの値が同じならTrue、そうでなければFalse
② > : Aの値がBの値より大きいならtrue、そうでなければFalse
③ < : Aの値がBの値より小さいならtrue、そうでなければFalse
④ >= : Aの値がBの値より大きいか同じならtrue、そうでなければFalse
⑤ <= : Aの値がBの値より小さいか同じならtrue、そうでなければFalse", "boolean_basic_operator_exampleCode": "def when_start():\n while True:\n Entry.add_x(10)\n if Entry.value_of_object(\"オブジェクト\", \"x\") > 240:\n Entry.set_x(0)", "boolean_basic_operator_exampleDesc": "[スタート]ボタンをクリックすると、続けてオブジェクトx座標を10変更します。もしオブジェクトx座標が240より大きければオブジェクトx座標を0にします。", "boolean_and_desc": "AとBの判断がすべてTrueの場合はTrue、そうじゃない場合はFalseと判断します。", "boolean_and_elements": "A, B-- TrueまたはFalseと判断できるコマンド入力(判断カテゴリーのコマンド)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10など
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\")など", "boolean_and_exampleCode": "def when_start():\n while True:\n if Entry.is_key_pressed(\"a\") and Entry.is_key_pressed(\"s\"):\n Entry.add_effect(\"color\", 10)", "boolean_and_exampleDesc": "[スタート]ボタンをクリックしてキーボードの\"a\"と\"s\"キーを同時に押した時、色効果を10だけ加えます。", "boolean_or_desc": "AとBの判断のうち1つでもTrueの場合はTrue, そうじゃない場合はFalseと判断します。", "boolean_or_elements": "A, B-- TrueまたはFalseと判断できるコマンド入力(判断カテゴリーのコマンド)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10など
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\")など", "boolean_or_exampleCode": "def when_start():\n while True:\n if Entry.is_key_pressed(\"a\") or Entry.is_key_pressed(\"s\"):\n Entry.add_effect(\"color\", 10)", "boolean_or_exampleDesc": "[スタート]ボタンをクリックすると、キーボードの\"a\"や\"s\"キーのうち何でも1つを押した時、オブジェクトに色効果を10加えます。", "boolean_not_desc": "A 判断がTrueならFalse、FalseならTrueと判断します。", "boolean_not_elements": "A-- TrueまたはFalseと判断できるコマンド入力(判断カテゴリーのコマンド)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10など
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\")など", "boolean_not_exampleCode": "def when_start():\n while True:\n if not Entry.is_mouse_clicked():\n Entry.add_size(1)", "boolean_not_exampleDesc": "[スタート]ボタンをクリックすると、マウスをクリックしない間サイズが1ずつ大きくなります。", "calc_basic_desc": "AとBの演算値です。", "calc_basic_elements": "A, B-- 演算したい数字値
① + : AとBを加えた値
② - : AとBを引いた値
③ x : AとBをかけた値
④ / : AとBを割った値", "calc_basic_exampleCode": "def when_start():\n Entry.print_for_sec(10 + 10, 2)\n Entry.print_for_sec(10 - 10, 2)\n Entry.print_for_sec(10 * 10, 2)\n Entry.print_for_sec(10 / 10, 2)", "calc_basic_exampleDesc": "[スタート]ボタンをクリックすると、10と10を足した値、引いた値、かけた値、割った値をそれぞれ2秒間話します。", "calc_rand_desc": "AとBの間で選択された乱数の値です。(2つの数をすべて整数を入力した場合整数が、2つの数のうち1つでも少数を入力した場合は少数が乱数として選択されます。)", "calc_rand_elements": "A, B-- 乱数を抽出する範囲
① random.randint(A, B) : A, Bを整数で入力すると整数の範囲で乱数を抽出
② random.uniform(A, B) : A, Bを実数で入力すると実数範囲で乱数を抽出", "calc_rand_exampleCode": "def when_start():\n Entry.print_for_sec(random.randint(1, 10), 2)\n Entry.print_for_sec(random.uniform(0.1, 2), 2)", "calc_rand_exampleDesc": "[スタート]ボタンをクリックすると、1から10の間の整数のうち乱数を選び2秒間話します。その後、0.1から2の間の実数のうち乱数を選び2秒間話します。", "coordinate_mouse_desc": "マウスポインターのA座標値を表します。", "coordinate_mouse_elements": "A-- 次の選択肢のうち一つ
① \"x\"または\"X\"
② \"y\"または\"Y\"", "coordinate_mouse_exampleCode": "def when_start():\n while True:\n Entry.print(Entry.value_of_mouse_pointer(\"x\"))", "coordinate_mouse_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトがマウスポインターのx座標を続けて話します。", "coordinate_object_desc": "Aに関するB情報値です。", "coordinate_object_elements": "A-- 次の選択肢のうち1つ
① \"オブジェクト名\"
② \"self\"または\"自分\"%nextB-- 次の選択肢のうち一つ
① \"x\"または\"X\"
② \"y\"または\"Y\"
③ \"rotation\"または\"方向\"
④ \"direction\"または\"移動方向\"
⑤ \"size\" または\"サイズ\"
⑥ \"shape_number\"または\"模様番号\"
⑦ \"shape_name\"または\"模様名\"", "coordinate_object_exampleCode": "def when_start():\n while True:\n Entry.add_x(1)\n Entry.print(Entry.value_of_object(\"オブジェクト\", \"x\"))\n", "coordinate_object_exampleDesc": "[スタート]ボタンをクリックすると続けてオブジェクトのx座標が1ずつ増加し、\"オブジェクト\"のx座標を話します。", "get_sound_volume_desc": "現在、作品に設定されているサウンドのサイズ値です。", "get_sound_volume_exampleCode": "def when_start():\n while True:\n Entry.print(Entry.value_of_sound_volume())", "get_sound_volume_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトがサウンドのサイズ値を続けて話します。", "quotient_and_mod_desc": "AとBの演算値です。", "quotient_and_mod_elements": "A, B-- 演算したい数字値
① // : A / Bの商に該当する値
② % : A / Bのあまりに該当する値", "quotient_and_mod_exampleCode": "def when_start():\n Entry.print_for_sec(10 // 3, 2)\n Entry.print_for_sec(10 % 3, 2)", "quotient_and_mod_exampleDesc": "[スタート]ボタンをクリックすると、10 / 3の商である3を2秒間話し、あまりである1を2秒間話します。", "calc_operation_desc": "Aの演算値です。", "calc_operation_elements": "A, B-- 演算したい数字値
① A ** 2 : Aを乗じた値
② math.sqrt(A): Aのルート値
③ math.sin(A): Aのサイン値
④ math.cos(A): Aのコサイン値
⑤ math.tan(A): Aのタンジェント値
⑥ math.asin(A): Aのアークサイン値
⑦ math.acos(A): Aのアークコサイン値
⑧ math.atan(): Aのアークタンジェント値
⑨ math.log10(A): Aのログ値
⑩ math.log(A): Aの自然ログ値
⑪ A - math.floor(A): Aの小数点部分
⑫ math.floor(A): Aの小数点以下切り捨て値
⑬ math.ceil(A): Aの小数点以下切り上げ値
⑭ math.round(A): Aの四捨五入値
⑮ math.factorial(A): Aの階乗値
⑯ math.fabs(A): Aの絶対値", "calc_operation_exampleCode": "def when_start():\n Entry.print_for_sec(10 ** 2, 2)\n Entry.print_for_sec(math.sqrt(9), 2)\n Entry.print_for_sec(math.sin(90), 2)\n Entry.print_for_sec(math.fabs(-10), 2)", "calc_operation_exampleDesc": "[スタート]ボタンをクリックすると、10の乗, 9のルート値, 90のサイン値, -10の絶対値をそれぞれ2秒間話します。", "get_project_timer_value_desc": "このコマンドが実行された瞬間、ストップウォッチに保存された値です。", "get_project_timer_value_exampleCode": "def when_start():\n Entry.timer(\"start\")\n Entry.wait_for_sec(3)\n Entry.timer(\"stop\")\n Entry.timer_view(\"hide\")\n Entry.print(Entry.value_of_timer())", "get_project_timer_value_exampleDesc": "[スタート]ボタンをクリックするとストップウォッチを開始します。3秒後にストップウォッチを停止してストップウォッチウィンドウを隠します。その後、ストップウォッチ値を話します。", "choose_project_timer_action_desc": "ストップウォッチの動作をAにします。
(このコマンドを使うと実行画面に「ストップウォッチウィンドウ」が作成されます。)", "choose_project_timer_action_elements": "A-- 次の選択肢のうち一つ
① \"start\" : ストップウォッチを開始
② \"stop\" : ストップウォッチを停止
③ \"reset\" : ストップウォッチを初期化", "choose_project_timer_action_exampleCode": "def when_start():\n Entry.timer(\"start\")\n Entry.wait_for_sec(3)\n Entry.timer(\"stop\")\n Entry.timer_view(\"hide\")\n Entry.print(Entry.value_of_timer())", "choose_project_timer_action_exampleDesc": "[スタート]ボタンをクリックすると、ストップウォッチを開始します。3秒後にストップウォッチを停止してストップウォッチウィンドウを隠します。その後、ストップウォッチ値を話します。", "set_visible_project_timer_desc": "実行画面のストップウォッチウィンドウをAに設定します。", "set_visible_project_timer_elements": "A-- 次の選択肢のうち一つ
① \"hide\" : ストップウォッチウィンドウを非表示
② \"show\" : ストップウォッチウィンドウを表示", "set_visible_project_timer_exampleCode": "def when_start():\n Entry.timer(\"start\")\n Entry.wait_for_sec(3)\n Entry.timer(\"stop\")\n Entry.timer_view(\"hide\")\n Entry.print(Entry.value_of_timer())", "set_visible_project_timer_exampleDesc": "[スタート]ボタンをクリックすると、ストップウォッチを開始します。3秒後にストップウォッチを停止してストップウォッチウィンドウを隠します。その後、ストップウォッチ値を話します。", "get_date_desc": "現在のAに関する値です。", "get_date_elements": "A-- 次の選択肢のうち1つ
① \"year\" : 現在の年度値
② \"month\" : 現在の月値
③ \"day\" : 現在の日値
④ \"hour\" : 現在の時間値
⑤ \"minute\" : 現在の分値
⑥ \"second\" : 現在の秒値", "get_date_exampleCode": "def when_start():\n Entry.print(Entry.value_of_current_time(\"year\") + \"年\" + Entry.value_of_current_time(\"month\") + \"月\")", "get_date_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが現在の年度と月を話します。", "distance_something_desc": "自分とAまでの距離値です。", "distance_something_elements": "A-- 次の選択肢のうち一つ
① \"オブジェクト名\"
② \"mouse_pointer\"または\"マウスポインター\"", "distance_something_exampleCode": "def when_start():\n while True:\n Entry.print(Entry.value_of_distance_to(\"mouse_pointer\"))", "distance_something_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトがマウスポインターとの距離を続けて話します。", "get_sound_duration_desc": "サウンドAの長さ(秒)値です。", "get_sound_duration_elements": "A-- \"サウンド名\"", "get_sound_duration_exampleCode": "def when_start():\n Entry.print(Entry.value_of_sound_length_of(\"サウンド\"))", "get_sound_duration_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが\"サウンド\"の長さを話します。", "get_user_name_desc": "作品を実行しているユーザーのIDの値です。", "get_user_name_exampleCode": "def when_start():\n Entry.print(Entry.value_of_username())", "get_user_name_exampleDesc": "[スタート]ボタンをクリックすると、作品を実行しているユーザーのID値を話します。", "get_nickname_desc": "作品をプレーしているユーザーのニックネーム値です。", "get_nickname_exampleCode": "def when_start():\n Entry.print(Entry.value_of_nickname())", "get_nickname_exampleDesc": "[スタート]ボタンをクリックすると、作品をプレーしているユーザーのニックネーム値を話します。", "length_of_string_desc": "入力した文字値のスペースを含む文字数です。", "length_of_string_elements": "A-- \"文字列\"", "length_of_string_exampleCode": "def when_start():\n Entry.print_for_sec(len(\"やあ\"), 2)\n Entry.print_for_sec(len(\"エントリー\"), 2)", "length_of_string_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが\"やあ\"と\"エントリー\"の文字数をそれぞれ2秒間話します。", "combine_something_desc": "A 文字列とB 文字列を結合した値です。(A、Bのうち1つが数字なら文字列に変えて処理され、2つとも数字なら加法演算で処理されます。)", "combine_something_elements": "A, B-- \"文字列\"", "combine_something_exampleCode": "def when_start():\n Entry.print(\"やあ! \" + \"エントリー\")", "combine_something_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが\"やあ!\"と\"エントリー\"が結合した\"やあ! エントリー\"を話します。", "char_at_desc": "A 文字列のB番目の文字値です。(最初の文字の位置は0から始まります。)", "char_at_elements": "A-- \"文字列\"%nextB-- 検索したい文字列の位置", "char_at_exampleCode": "def when_start():\n Entry.print(\"やあ、エントリー!\"[0])", "char_at_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが\"やあ、エントリー!\"の0番目の文字である\"や\"を話します。", "substring_desc": "A 文字列の B位置から C-1位置までの値です。(最初の文字の位置は0から始まります。)", "substring_elements": "A-- \"文字列\"%nextB-- 含まれる文字列の開始位置
最初の文字は0から開始%nextC-- 文字列を含まない位置", "substring_exampleCode": "def when_start():\n Entry.print(\"やあ、エントリー!\"[1:5])", "substring_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが\"やあ、エントリー!\"の1から4番目の文字である\"あ、エント\"を話します。", "index_of_string_desc": "A文字列でB文字列が最初に登場する位置の値です。(最初の文字の位置は0から始まります。)", "index_of_string_elements": "A, B-- \"文字列\"", "index_of_string_exampleCode": "def when_start():\n Entry.print(\"やあ、エントリー!\".find(\"エントリー\"))", "index_of_string_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが\"やあ、エントリー!\"で \"エントリー\"が最初に登場する位置の3を話します。", "replace_string_desc": "A文字列からB文字列をすべて探し、C文字列に置き換えた値です。
(アルファベット入力時、大文字と小文字を区別します。)", "replace_string_elements": "A, B, C-- \"文字列\"", "replace_string_exampleCode": "def when_start():\n Entry.print(\"やあ、エントリー!\".replace( \"やあ\", \"嬉しいな\"))", "replace_string_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが\"やあ、エントリー!\"で\"やあ\"を\"嬉しいな\"に置き換えた\"嬉しいな、エントリー!\"を話します。", "change_string_case_desc": "Aのすべてのアルファベットを大文字または小文字に置き換えた文字値です。", "change_string_case_elements": "A-- \"文字列\"
① A.upper(): Aのすべてのアルファベットを大文字に置き換えた値
② A.lower() : Aのすべてのアルファベットを小文字に置き換えた値", "change_string_case_exampleCode": "def when_start():\n Entry.print_for_sec(\"Hello Entry!\".upper(), 2)\n Entry.print_for_sec(\"Hello Entry!\".lower(), 2)", "change_string_case_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが\"Hello Entry!\"をすべて大文字に置き換えた\"HELLO ENTRY!\"を2秒間話した後、すべて小文字に置き換えた\"hello entry!\"を2秒間話します。", "ask_and_wait_desc": "オブジェクトがAの内容を吹き出しで尋ね、回答の入力を受けます。回答は実行画面またはコンソールウィンドウで入力でき、入力された値は'Entry.answer()'に保存されます。
(このコマンドを使うと実行画面に「回答ウィンドウ」が作成されます。)", "ask_and_wait_elements": "A-- \"文字列\"", "ask_and_wait_exampleCode": "def when_start():\n Entry.input(\"名前を入力してみてください。\")\n Entry.print(Entry.answer() + \" 嬉しいな!\")", "ask_and_wait_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが\"名前を入力してみてください。\"と吹き出しで尋ねます。名前を入力すると\"(入力した名前) 嬉しいな!\"と話します。", "get_canvas_input_value_desc": "Entry.input(A) コマンドにより実行画面またはコンソールで入力された値です。", "get_canvas_input_value_exampleCode": "def when_start():\n Entry.input(\"名前を入力してみてください。\")\n Entry.print(Entry.answer() + \" 嬉しいな!\")", "get_canvas_input_value_exampleDesc": "[スタート]ボタンをクリックすると、オブジェクトが\"名前を入力してみてください。\"と吹き出しで尋ねます。名前を入力すると\"(入力した名前)嬉しいな!\"と話します。", "set_visible_answer_desc": "実行画面の回答ウィンドウをAに設定します。", "set_visible_answer_elements": "A-- 次の選択肢のうち1つ
① \"hide\" : 回答ウィンドウを非表示
② \"show\" : 回答ウィンドウを表示", "set_visible_answer_exampleCode": "def when_start():\n Entry.answer_view(\"hide\")\n Entry.input(\"年齢を入力してください。\")\n Entry.print(Entry.answer())", "set_visible_answer_exampleDesc": "[スタート]ボタンをクリックすると回答ウィンドウが非表示になり、オブジェクトが\"年齢を入力してください。\"と吹き出しで尋ねます。年齢を入力するとオブジェクトが入力した年齢を話します。", "get_variable_desc": "A 変数に保存された値です。", "get_variable_elements": "A-- 変数名
① すべてのオブジェクトで使用: A
② このオブジェクトで使用: self.A", "get_variable_exampleCode": "age = 16\n\ndef when_start():\n Entry.print(age)", "get_variable_exampleDesc": "ageという変数を作成してその値を16にします。[スタート]ボタンをクリックすると、オブジェクトがage変数に入っている値である\"16\"を話します。", "change_variable_desc": "A変数にBだけ足します。", "change_variable_elements": "A-- 変数名
① すべてのオブジェクトで使用: A
② このオブジェクトで使用: self.A%nextB-- 数字値", "change_variable_exampleCode": "age = 16\n\ndef when_start():\n Entry.print_for_sec(age, 2)\n age += 2\n Entry.print_for_sec(age, 2)", "change_variable_exampleDesc": "ageという変数を作成してその値を16にします。[スタート]ボタンをクリックすると、オブジェクトがage変数に入っている値である\"16\"を2秒間話します。その後、age変数に2を足し、足した値である\"18\"を2秒間話します。", "set_variable_desc": "A変数の値をBにします。もしA変数がない場合、[属性]タブにA変数が自動作成されます。", "set_variable_elements": "A-- 変数名
① すべてのオブジェクトで使用: A
② このオブジェクトで使用: self.A%nextB-- 変数に入れる値
① 文字: \"やあ!\", \"エントリー\"など
② 数字: 0, 10, 35など", "set_variable_exampleCode": "age = 16\n\ndef when_start():\n Entry.print(age)", "set_variable_exampleDesc": "ageという変数を作成してその値を16にします。[スタート]ボタンをクリックすると、オブジェクトがage変数に入っている値である\"16\"を話します。", "show_variable_desc": "A 変数ウィンドウを実行画面に表示させます。", "show_variable_elements": "A-- \"変数名\"
① すべてのオブジェクトで使用: \"A\"
② このオブジェクトで使用: \"self.A\"", "show_variable_exampleCode": "age = 16\n\ndef when_start():\n Entry.hide_variable(\"age\")\n Entry.wait_for_sec(2)\n age = 20\n Entry.show_variable(\"age\")", "show_variable_exampleDesc": "ageという変数を作成してその値を16にします。[スタート]ボタンをクリックすると、age変数ウィンドウを実行画面で非表示にします。2秒後に変数値を17に変更し、age変数ウィンドウを実行画面に表示させます。", "hide_variable_desc": "A 変数ウィンドウを実行画面で非表示にします。", "hide_variable_elements": "A-- \"変数名\"
① すべてのオブジェクトで使用: \"A\"
② このオブジェクトで使用: \"self.A\"", "hide_variable_exampleCode": "age = 16\n\ndef when_start():\n Entry.hide_variable(\"age\")\n Entry.print_for_sec(age, 2)", "hide_variable_exampleDesc": "ageという変数を作成してその値を16にします。[スタート]ボタンをクリックするとage変数ウィンドウを実行画面で非表示にし、オブジェクトがage変数に入っている値である\"16\"を2秒間話します。", "value_of_index_from_list_desc": "A リストでB位置の項目値を表します。
(最初の項目の位置は0から始まります。)", "value_of_index_from_list_elements": "A-- リスト名
① すべてのオブジェクトで使用: A
② このオブジェクトで使用: self.A%nextB-- リスト項目の位置", "value_of_index_from_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n Entry.print(basket[1])\n", "value_of_index_from_list_exampleDesc": "basketというリストを作成して4つの項目を挿入します。[スタート]ボタンをクリックすると、オブジェクトがbasketリストの1番目の項目であるorangeを話します。", "add_value_to_list_desc": "A リストの最後の項目にB値が追加されます。", "add_value_to_list_elements": "A-- リスト名
① すべてのオブジェクトで使用: A
② このオブジェクトで使用: self.A%nextB-- リストに入れる項目値
① 文字: \"やあ!\", \"エントリー\"など
② 数字: 0, 10, 35など", "add_value_to_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n basket.append(\"juice\")\n Entry.print(basket[4])", "add_value_to_list_exampleDesc": "basketというリストを作成して4つの項目を挿入します。[スタート]ボタンをクリックすると、\"juice\"をbasketの最後の項目に追加します。オブジェクトはbasketの4番目の項目である\"juice\"を話します。", "remove_value_from_list_desc": "A リストのB位置にある項目を削除します。
(最初の項目の位置は0から始まります。)", "remove_value_from_list_elements": "A-- リスト名
① すべてのオブジェクトで使用: A
② このオブジェクトで使用: self.A%nextB-- リスト項目の位置値", "remove_value_from_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\ndef when_start():\n basket.pop(0)\n Entry.print(basket[0])", "remove_value_from_list_exampleDesc": "basketというリストを作成して4つの項目を挿入します。[スタート]ボタンをクリックすると、basketの0番目の項目であるappleを削除します。オブジェクトは新しくbasketの0番目の項目になった\"orange\"を話します。", "insert_value_to_list_desc": "A リストのB位置にC項目を挿入します。
(最初の項目の位置は0から始まります。B位置より後にある各項目の順番は1つずつずれます。)", "insert_value_to_list_elements": "A-- リスト名
① すべてのオブジェクトで使用: A
② このオブジェクトで使用: self.A%nextB-- リスト項目の位置%nextC-- リストに入れる項目値
① 文字: \"やあ!\", \"エントリー\"など
② 数字: 0, 10, 35など", "insert_value_to_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n basket.insert(1, \"juice\")\n Entry.print(basket[2])", "insert_value_to_list_exampleDesc": "basketというリストを作成して4つの項目を挿入します。[スタート]ボタンをクリックすると、basketの最初の位置に項目 \"juice\"を入れます。オブジェクトは新しくbasketの2番目の項目になった\"orange\"を話します。", "change_value_list_index_desc": "AリストでB位置にある項目の値をC値に変更します。
(最初の項目の位置は0から始まります。)", "change_value_list_index_elements": "A-- リスト名
① すべてのオブジェクトで使用: A
② このオブジェクトで使用: self.A%nextB-- リスト項目の位置%nextC-- リストに入れる項目値
① 文字: \"やあ!\", \"エントリー\"など
② 数字: 0, 10, 35など", "change_value_list_index_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n basket[0] = \"juice\"\n Entry.print(basket[0])", "change_value_list_index_exampleDesc": "basketというリストを作成して4つの項目を挿入します。[スタート]ボタンをクリックすると、basketの0番目の位置の項目 \"apple\"を\"juice\"に変更します。オブジェクトは変更されたbasketの0番目の項目 \"juice\"を話します。", "length_of_list_desc": "A リストが保有した項目の個数値です。", "length_of_list_elements": "A-- リスト名
① すべてのオブジェクトで使用: A
② このオブジェクトで使用: self.A", "length_of_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n Entry.print(len(basket))", "length_of_list_exampleDesc": "basketというリストを作成して4つの項目を挿入します。[スタート]ボタンをクリックすると、オブジェクトは basketの項目個数である4を話します。", "is_included_in_list_desc": "A値を持つ項目がBリストに含まれているか確認します。", "is_included_in_list_elements": "A-- リストの項目値
① 文字: \"やあ!\", \"エントリー\"など
② 数字: 0, 10, 35など%nextB-- リスト名
① すべてのオブジェクトで使用: A
② このオブジェクトで使用: self.A", "is_included_in_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n if \"apple\" in basket:\n Entry.print(\"リンゴがあるよ!\")", "is_included_in_list_exampleDesc": "basketというリストを作成して4つの項目を挿入します。[スタート]ボタンをクリックすると、basket リストに\"apple\"項目があるかを確認します。\"apple\"項目があるため、オブジェクトは\"リンゴがあるよ!\"と話します。", "show_list_desc": "選択したリストウィンドウを実行画面に表示させます。", "show_list_elements": "A-- \"リスト名\"
① すべてのオブジェクトで使用: \"A\"
② このオブジェクトで使用: \"self.A\"", "show_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n Entry.hide_list(\"basket\")\n Entry.wait_for_sec(2)\n Entry.show_list(\"basket\")", "show_list_exampleDesc": "basketというリストを作成して4つの項目を挿入します。[スタート]ボタンをクリックすると、basket リストを2秒間非表示にした後で表示します。", "hide_list_desc": "選択したリストウィンドウを実行画面で非表示にします。", "hide_list_elements": "A-- \"リスト名\"
① すべてのオブジェクトで使用: \"A\"
② このオブジェクトで使用: \"self.A\"", "hide_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n Entry.hide_list(\"basket\")\n Entry.wait_for_sec(2)\n Entry.show_list(\"basket\")", "hide_list_exampleDesc": "basketというリストを作成して4つの項目を挿入します。[スタート]ボタンをクリックすると、basketリストを2秒間非表示にした後で表示します。", "boolean_and_or_desc": "AとBの判断値を確認してTrueまたはFalseと判断します。", "boolean_and_or_elements": "A, B-- TrueまたはFalseと判断できるコマンド入力(判断カテゴリーのコマンド)
① and : AとBの判断がすべてTrueの場合はTrue、そうじゃない場合はFalse
② or : AとBの判断のうち1つでもTrueの場合True、そうじゃない場合はFalse", "boolean_and_or_exampleCode": "def when_start():\n while True:\n if Entry.is_key_pressed(\"a\") and Entry.is_key_pressed(\"s\"):\n Entry.add_effect(\"color\", 10)", "boolean_and_or_exampleDesc": "[スタート]ボタンをクリックし、キーボードの\"a\"と\"s\"キーを同時に押した時に色効果を10加えます。", "check_weather_desc": "B날짜에 C지역의 날씨가 A인 경우 True로 판단합니다.", "check_weather_elements": "A-- 아래 선택지 중 하나
①    \"sunny\" : 맑음
②    \"partly cloudy\" : 구름조금
③    \"mostly cloudy\" : 구름많음
④    \"cloudy\" : 흐림
⑤    \"rainy\" : 비
⑥    \"sleet\" : 진눈깨비
⑦    \"snowy\" : 눈%nextB-- 아래 선택지 중 하나
①    \"yesterday\" : 어제
②    \"today\" : 오늘
③    \"tomorrow\" : 내일
④    \"After 2 days\" : 모레
⑤    \"After 3 days\" : 3일 후
⑥    \"After 4 days\" : 4일 후
⑦    \"After 5 days\" : 5일 후
⑧    \"After 6 days\" : 6일 후%nextC-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북", "check_weather_exampleCode": "def when_start():\n if Weather.is_condition_sunny(\"today\", \"Seoul\"):\n Entry.print(\"오늘 서울의 날씨는 맑습니다.\")", "check_weather_exampleDesc": "[시작하기]버튼을 클릭하면 오늘 서울의 날씨가 맑은지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 \"오늘 서울의 날씨는 맑습니다.\"라고 말합니다.​", "check_finedust_desc": "선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.", "check_finedust_elements": "A-- 아래 선택지 중 하나
①    \"good\" : 좋음
②    \"normal\" : 보통
③    \"bad\" : 나쁨
④    \"very bad\" : 매우나쁨%nextB-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북", "check_finedust_exampleCode": "def when_start():\n if Weather.is_current_finedust_grade_good(\"Seoul\"):\n Entry.print(\"현재 서울의 미세먼지 등급은 좋음입니다.\")", "check_finedust_exampleDesc": "[시작하기]버튼을 클릭하면 현재 서울의 미세먼지 등급이 좋음인지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 “오늘 서울의 미세먼지 등급은 좋음입니다.”라고 말합니다.​", "get_weather_data_desc": "선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.", "get_weather_data_elements": "A-- 아래 선택지 중 하나
①    \"the lowest temperature\" : 최저기온
②    \"the highest temperature\" : 최고기온
③    \"humidity\" : 습도
④    \"precipitation\" : 강수량
⑤    \"precipitation probability\" : 강수확률
⑥    \"wind speed\" : 풍속%nextB-- 아래 선택지 중 하나
①    \"yesterday\" : 어제
②    \"today\" : 오늘
③    \"tomorrow\" : 내일
④    \"After 2 days\" : 모레
⑤    \"After 3 days\" : 3일 후
⑥    \"After 4 days\" : 4일 후
⑦    \"After 5 days\" : 5일 후
⑧    \"After 6 days\" : 6일 후%nextC-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북", "get_weather_data_exampleCode": "def when_start():\n Entry.print(Weather.get_lowest_temperature(\"today\", \"Seoul\"))", "get_weather_data_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 최저기온을 말합니다.​", "get_current_weather_data_desc": "현재 B지역의 A 날씨 정보값을 의미합니다.", "get_current_weather_data_elements": "A-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북%nextB-- 아래 선택지 중 하나
①    \"temperature\" : 기온
②    \"concentration of fine dust\" : 미세먼지농도", "get_current_weather_data_exampleCode": "def when_start():\n Entry.print(Weather.get_current_temperature(\"Seoul\"))", "get_current_weather_data_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 현재 서울의 기온을 말합니다.", "get_today_temperature_desc": "오늘 A지역의 B 시간대 기온 정보값을 의미합니다.", "get_today_temperature_elements": "A-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북%nextB-- 아래 선택지 중 하나
①    \"00\" : 당일 00시 측정된 기온값
②    \"03\" : 당일 03시 측정된 기온값
③    \"06\" : 당일 06시 측정된 기온값
④    \"09\" : 당일 09시 측정된 기온값
⑤    \"12\" : 당일 12시 측정된 기온값
⑥    \"15\" : 당일 15시 측정된 기온값
⑦    \"18\" : 당일 18시 측정된 기온값
⑧    \"21\" : 당일 21시 측정된 기온값", "get_today_temperature_exampleCode": "def when_start():\n Entry.print(Weather.get_today_temperature(\"Seoul\", 00))", "get_today_temperature_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 00시 기온을 말합니다.​", "check_city_weather_desc": "B날짜에 C지역의 날씨가 A인 경우 True로 판단합니다.", "check_city_weather_elements": "A-- 아래 선택지 중 하나
①    \"sunny\" : 맑음
②    \"partly cloudy\" : 구름조금
③    \"mostly cloudy\" : 구름많음
④    \"cloudy\" : 흐림
⑤    \"rainy\" : 비
⑥    \"sleet\" : 진눈깨비
⑦    \"snowy\" : 눈%nextB-- 아래 선택지 중 하나
①    \"yesterday\" : 어제
②    \"today\" : 오늘
③    \"tomorrow\" : 내일
④    \"After 2 days\" : 모레
⑤    \"After 3 days\" : 3일 후
⑥    \"After 4 days\" : 4일 후
⑦    \"After 5 days\" : 5일 후
⑧    \"After 6 days\" : 6일 후%nextC-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북", "check_city_weather_exampleCode": "def when_start():\n if Weather.is_condition_sunny(\"today\", \"Seoul\"):\n Entry.print(\"오늘 서울의 날씨는 맑습니다.\")", "check_city_weather_exampleDesc": "[시작하기]버튼을 클릭하면 오늘 서울의 날씨가 맑은지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 \"오늘 서울의 날씨는 맑습니다.\"라고 말합니다.​", "check_city_finedust_desc": "선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.", "check_city_finedust_elements": "A-- 아래 선택지 중 하나
①    \"good\" : 좋음
②    \"normal\" : 보통
③    \"bad\" : 나쁨
④    \"very bad\" : 매우나쁨%nextB-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북", "check_city_finedust_exampleCode": "def when_start():\n if Weather.is_current_finedust_grade_good(\"Seoul\"):\n Entry.print(\"현재 서울의 미세먼지 등급은 좋음입니다.\")", "check_city_finedust_exampleDesc": "[시작하기]버튼을 클릭하면 현재 서울의 미세먼지 등급이 좋음인지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 “오늘 서울의 미세먼지 등급은 좋음입니다.”라고 말합니다.​", "get_city_weather_data_desc": "선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.", "get_city_weather_data_elements": "A-- 아래 선택지 중 하나
①    \"the lowest temperature\" : 최저기온
②    \"the highest temperature\" : 최고기온
③    \"humidity\" : 습도
④    \"precipitation\" : 강수량
⑤    \"precipitation probability\" : 강수확률
⑥    \"wind speed\" : 풍속%nextB-- 아래 선택지 중 하나
①    \"yesterday\" : 어제
②    \"today\" : 오늘
③    \"tomorrow\" : 내일
④    \"After 2 days\" : 모레
⑤    \"After 3 days\" : 3일 후
⑥    \"After 4 days\" : 4일 후
⑦    \"After 5 days\" : 5일 후
⑧    \"After 6 days\" : 6일 후%nextC-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북", "get_city_weather_data_exampleCode": "def when_start():\n Entry.print(Weather.get_lowest_temperature(\"today\", \"Seoul\"))", "get_city_weather_data_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 최저기온을 말합니다.​", "get_current_city_weather_data_desc": "현재 B지역의 A 날씨 정보값을 의미합니다.", "get_current_city_weather_data_elements": "A-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북%nextB-- 아래 선택지 중 하나
①    \"temperature\" : 기온
②    \"concentration of fine dust\" : 미세먼지농도", "get_current_city_weather_data_exampleCode": "def when_start():\n Entry.print(Weather.get_current_temperature(\"Seoul\"))", "get_current_city_weather_data_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 현재 서울의 기온을 말합니다.", "get_today_city_temperature_desc": "오늘 A지역의 B 시간대 기온 정보값을 의미합니다.", "get_today_city_temperature_elements": "A-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북%nextB-- 아래 선택지 중 하나
①    \"00\" : 당일 00시 측정된 기온값
②    \"03\" : 당일 03시 측정된 기온값
③    \"06\" : 당일 06시 측정된 기온값
④    \"09\" : 당일 09시 측정된 기온값
⑤    \"12\" : 당일 12시 측정된 기온값
⑥    \"15\" : 당일 15시 측정된 기온값
⑦    \"18\" : 당일 18시 측정된 기온값
⑧    \"21\" : 당일 21시 측정된 기온값", "get_today_city_temperature_exampleCode": "def when_start():\n Entry.print(Weather.get_today_city_temperature(\"Seoul\", 00))", "get_today_city_temperature_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 00시 기온을 말합니다.​" }; Lang.Painter = { "select_cut": "点線の四角形に沿って切り取ることができます。", "thickness_of_eraser": "消しゴムの太さ", "font": "フォント", "font_color": "文字の色", "outline_color": "輪郭線の色", "outline_thickness": "枠線の太さ", "fill_color": "塗りつぶしの色", "inversion": "反転", "font_size": "サイズ", "font_family": "スタイル", "fullscreen": "全画面", "exit_fullscreen": "全画面を終了", "picture_import": "模様インポート", "edit_way": "編集方法", "line": "直線", "vertex": "頂点", "bitmap": "ビットマップ", "vector": "ベクター", "forward": "前に", "backward": "後ろに", "front": "一番前に", "back": "一番後ろに", "group": "グループ", "ungroup": "グループ 解除", "copy_picture": "コピー", "delete_picture": "削除", "cut_picture": "切り取り", "paste_picture": "貼り付け", "remove_all": "全て削除", "new_picture": "新しい図", "edit": "編集", "picture_size": "サイズ", "picture_rotation": "回転", "thickness": "太さ", "font_fill": "背景色", "painter_file_save": "保存する", "painter_file_saveas": "新しい模様で保存", "file": "ファイル", "Pencil": "ペン", "Line": "直線", "Path": "形を変える", "Pan": "移動", "Select": "選択", "Rectangle": "四角形", "Ellipse": "円", "Text": "テキストボックス", "Fill": "塗りつぶし", "Eraser": "クリア", "get_file": "インポート", "copy_file": "コピーする" }; Lang.DataAnalytics = { "data_analysis": "データ分析", "create_table": "テーブル作成", "data": "データ", "add_table": "テーブルを追加する", "show_chart": "チャート表示", "legend": "凡例", "dashboard": "要約", "table": "テーブル", "chart": "チャート", "attribute": "列", "row": "行", "average": "平均", "standard_deviation": "標準偏差", "maximum": "最大値", "minimum": "最小値", "median": "中間値", "average_explain": "当該する列のすべての値を加えた後、列の個数分で割った値", "standard_deviation_explain": "データが平均を中心に、どれくらい広がっているか確認できる値。\n0に近いほど値が平均付近に集中しているという意味", "maximum_minimum_explain": "当該する列の最大値と最小値", "median_explain": "当該する列のすべての値を大きい順に並べ替えた場合、全体の中央に位置する値", "add_row_above": "上に行を追加する", "add_row_below": "下に行を追加する", "delete_row": "行を削除する", "add_property_left": "左に列を追加する", "add_property_right": "右に列を追加する", "delete_attribute": "列を削除する", "data_alert": "数字ではない値が含まれた列は、個数のみ確認できます。", "save": "保存する", "cancel": "キャンセル", "confirm": "確認", "attribute_count": "件", "row_count": "件", "cell_count": "件", "count": "件", "add_chart_alert": "追加されたチャートがありません。\nチャートを作成してください。", "enter_attribute_name": "列の名前を入力してください。(10文字以内)", "placeholder_attribute_name": "列の名前", "new_attribute": "新しい列", "chart_title": "チャートのタイトル", "remove_chart": "チャートを削除する", "add_chart_first": "チャートを先に作成してください。", "bar": "棒グラフ", "line": "線グラフ", "pie": "円グラフ", "scatter": "散布図", "select_x_axis": "横軸にするものを選択してください。", "x_axis": "横軸", "y_axis": "縦軸", "select_y_axis": "縦軸にするものを選択してください。", "select_y_axis_or_legend": "縦軸、または判例を選択してください。", "select_legend": "判例を選択してください。", "cell": "間", "unable_to_express_chart": "チャートで表現ができません。", "edit_attribute_name": "名前を変更する", "duplicate_attribute_name_title": "列の名前変更に失敗しました。", "duplicate_attribute_name_content": "同じ名前の列がすでにあります。", "fail_save_table": "テーブルの保存に失敗しました。", "duplicate_table_name_content": "同じ名前のテーブルがすでにあります。", "saved_table_title": "保存しました。", "saved_table_content": "テーブルとチャートの情報を保存しました。", "empty_table_name_content": "テーブルの名前で空白で設定できません。", "do_not_delete_row": "行の削除ができません。", "rows_cannot_less_one": "テーブルには一個以上の行が必須です。" }; Lang.SharePolicy = { "title": "Entry Project/Post share Guide" }; Lang.Support = ["ko", "en", "vn", "jp"]; if (typeof exports == "object") exports.Lang = Lang; ================================================ FILE: extern/lang/ko.js ================================================ var Lang = {}; Lang.category = { name: 'ko', }; Lang.type = 'ko'; Lang.fallbackType = 'ko'; Lang.ko = '한국어'; Lang.en = 'English'; Lang.jp = '日本語'; Lang.vn = 'tiếng Việt'; Lang.Command = { 1: '장면 추가하기', 2: '장면 삭제하기', 3: '장면 이름 수정', 4: '장면 순서 변경', 5: '장면 선택', 101: '블록 쓰레드 추가하기', 102: '블록 쓰레드 삭제하기', 103: '블록 삭제하기', 104: '블록 복구하기', 105: '블록 끼워넣기', 106: '블록 분리하기', 107: '블록 이동하기', 108: '블록 복제하기', 109: '블록 복제 취소하기', 110: '스크롤', 111: '블록 필드값 수정', 117: '블록 쓰레드 추가하기', 118: '블록 끼워넣기', 119: '블록 이동하기', 120: '블록 분리하기', 121: '블록 이동하기', 122: '블록 끼워넣기', 123: '블록 끼워넣기', 201: '오브젝트 선택하기', 202: '오브젝트 수정 버튼 클릭', 203: '오브젝트 그림 추가', 204: '오브젝트 그림 삭제', 205: '오브젝트 소리 추가', 206: '오브젝트 소리 삭제', 207: '오브젝트 이름 수정', 208: '오브젝트 추가', 209: '오브젝트 삭제', 210: '오브젝트 추가 버튼 클릭', 211: '오브젝트 x 수정', 212: '오브젝트 y 수정', 213: '오브젝트 size 수정', 214: '오브젝트 방향 수정', 215: '오브젝트 이동 방향 수정', 216: '오브젝트 회전방식 수정', 217: '엔터티 모델 동기화', 301: 'do', 302: 'undo', 303: 'redo', 401: '그림 수정하기', 402: '그림 수정 취소하기', 403: '그림 수정하기', 404: '그림 수정 취소하기', 405: '글상자 수정', 501: '시작하기', 502: '정지하기', 601: '컨테이너 오브젝트 선택하기', 701: '모드 바꾸기', 702: '모양 추가 버튼 클릭', 703: '소리 추가 버튼 클릭', 801: '속성 필터 선택하기', 802: '변수 추가하기 버튼 클릭', 803: '변수 추가하기', 804: '변수 삭제하기', 805: '변수 이름 설정', 806: '신호 이름 설정', 807: '신호 추가', 808: '신호 삭제', 809: '변수 스코프 정하기', 810: '변수 글로벌 체크', 811: '변수 보이기 체크', 812: '변수 기본값 설정', 813: '변수 슬라이드로 체크', 814: '변수 최솟값 정하기', 815: '변수 최댓값 정하기', 816: '리스트 추가 버튼 클릭', 817: '리스트 추가', 818: '리스트 삭제', 819: '리스트 이름 정하기', 820: '리스트 스코프 정하기', 821: '리스트 글로벌 체크', 822: '리스트 보이기 체크', 823: '리스트 길이 변경', 824: '리스트 기본값 설정', 825: '메세지 수정 enable', 826: '변수 수정 enable', 827: '리스트 수정 enable', 828: '변수 이름 정하기', 829: '리스트 이름 정하기', 900: '모달 닫기', 1001: '함수 생성 시작', 1002: '함수 수정 시작', 1003: '함수 수정 취소', 1004: '함수 생성', 1005: '함수 업데이트', }; Lang.CommandTooltip = { 101: '블록 쓰레드 추가하기', 102: '블록 쓰레드 삭제하기', 103: '블록 삭제하기', 104: '블록 복구하기', 105: '코드 분리하기$$코드 연결하기@@이 코드의 가장 위에 있는 블록을 잡고 분리하여 끌어옵니다.$$이 곳에 코드를 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 106: '블록 분리하기', 107: '블록 이동하기', 108: '블록 복제하기', 109: '블록 복제 취소하기', 110: '스크롤', 111: '블록 필드값 수정@@값을 입력하기 위해 이곳을 클릭합니다.$$선택지를 클릭합니다.$$선택지를 클릭합니다.$$&value&을 입력합니다.$$&value&를 선택합니다.$$키보드 &value&를 누릅니다.', 117: '블록 쓰레드 추가하기', 118: '블록 연결하기@@이 곳에 블록을 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 119: '블록 가져오기@@빈 곳에 블록을 끌어다 놓습니다.', 120: '블록 분리하기$$블록 삭제하기@@필요 없는 코드를 휴지통으로 끌어옵니다.$$이 곳에 코드를 버립니다.', 121: '블록 이동하기$$블록 삭제하기@@필요 없는 코드를 휴지통으로 끌어옵니다.$$이 곳에 코드를 버립니다.', 122: '블록 연결하기@@이 곳에 블록을 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 123: '코드 분리하기$$코드 연결하기@@이 코드의 가장 위에 있는 블록을 잡고 분리하여 끌어옵니다.$$이 곳에 코드를 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.', 201: '오브젝트 선택하기', 301: 'do', 302: 'undo', 303: 'redo', 401: '그림 수정하기', 402: '그림 수정 취소하기', 403: '그림 수정하기', 404: '그림 수정 취소하기', 501: '실행하기@@[시작하기]를 누릅니다.', 502: '정지하기@@[정지하기]를 누릅니다.', 601: '컨테이너 오브젝트 선택하기', 701: '모드 바꾸기', 702: '모양 추가하기@@모양추가를 클릭합니다.', 703: '소리 추가하기@@소리추가를 클릭합니다.', 801: '변수 속성창 필터 선택하기', 802: '변수 추가하기@@[변수 추가]를 클릭합니다.', 803: '변수 추가하기@@[확인]을 클릭합니다.', 804: '변수 삭제하기@@이 버튼을 눌러 변수를 삭제합니다.', 805: '변수 이름 설정', 1101: '확장 블록 추가하기@@확장 블록 블러오기를 클릭합니다.', }; Lang.Blocks = { download_guide: '• 연결 안내 다운로드', dictionary: '사전', ai_utilize: '인공지능', date_yesterday: '어제', date_today: '오늘', date_tomorrow: '내일', date_after_2_days: '모레', date_after_3_days: '3일 후', date_after_4_days: '4일 후', date_after_5_days: '5일 후', date_after_6_days: '6일 후', EXPANSION_WEATHER_sunny: '맑음', EXPANSION_WEATHER_partly_cloudy: '구름조금', EXPANSION_WEATHER_mostly_cloudy: '구름많음', EXPANSION_WEATHER_cloudy: '흐림', EXPANSION_WEATHER_rainy: '비', EXPANSION_WEATHER_sleet: '진눈깨비', EXPANSION_WEATHER_snowy: '눈', EXPANSION_WEATHER_finedust_good: '좋음', EXPANSION_WEATHER_finedust_normal: '보통', EXPANSION_WEATHER_finedust_bad: '나쁨', EXPANSION_WEATHER_finedust_very_bad: '매우나쁨', EXPANSION_WEATHER_lowest_temperature: '최저기온(℃)', EXPANSION_WEATHER_highest_temperature: '최고기온(℃)', EXPANSION_WEATHER_humidity: '습도(%)', EXPANSION_WEATHER_precipitation: '강수량(mm)', EXPANSION_WEATHER_precipitation_probability: '강수확률(%)', EXPANSION_WEATHER_wind_speed: '풍속(m/s)', EXPANSION_WEATHER_temperature: '기온(℃)', EXPANSION_WEATHER_finedust: '미세먼지농도(㎍)', EXPANSION_FESTIVAL_title: '제목', EXPANSION_FESTIVAL_area: '지역', EXPANSION_FESTIVAL_start_date: '시작일', EXPANSION_FESTIVAL_end_date: '종료일', EXPANSION_FESTIVAL_address: '주소', EXPANSION_FESTIVAL_coordinate: '위치', EXPANSION_FESTIVAL_overview: '개요', EXPANSION_FESTIVAL_homepage: '홈페이지', learn_type_image: '이미지', learn_type_sound: '사운드', learn_type_text: '글자', learn_popup_title: '데이터 입력', learn_no_result: '인식된 결과가 없습니다.', no_data: '정보없음', no_sentence: '문장이 없습니다', sentence_over_20_charactor: '20자까지만 입력할 수 있습니다.', sentence_over_3000_charactor: '3000자까지만 입력할 수 있습니다.', sentence_over_2500_charactor: '2500자까지만 입력할 수 있습니다. ', unknown_sentence: '알 수 없는 문장입니다.', auto: '자동', korean: '한국어', english: '영어', spanish: '스페인어', french: '프랑스어', german: '독일어', russian: '러시아어', korean_s: '한국어', english_s: '영어', japan_s: '일본어', portuguese: '포르투갈어', hindi: '힌디어', japan: '일본어', thai: '태국어', vietnamese: '베트남', indonesian: '인도네시아어', chinese_simplified: '중국어간체', chinese_traditional: '중국어번체', italian: '이탈리아어', behaviorConduct01001: '태풍', behaviorConduct01002: '홍수', behaviorConduct01003: '호우', behaviorConduct01004: '강풍', behaviorConduct01005: '대설', behaviorConduct01006: '한파', behaviorConduct01007: '풍랑', behaviorConduct01008: '황사', behaviorConduct01009: '폭염', behaviorConduct01010: '가뭄', behaviorConduct01011: '지진', behaviorConduct01013: '해일', behaviorConduct01014: '산사태', behaviorConduct03002: '응급처치', behaviorConduct03003: '심폐소생술', behaviorConduct03004: '소화기사용법', behaviorConduct03016: '소화전사용법', behaviorConduct03005: '식중독', behaviorConduct03006: '산행안전', behaviorConduct03008: '실종유괴', behaviorConduct03009: '성폭력', behaviorConduct03010: '학교 폭력', behaviorConduct03011: '가정 폭력', behaviorConduct03012: '억류 및 납치', behaviorConduct03013: '교통사고', behaviorConduct03014: '승강기 안전사고', behaviorConduct03015: '미세먼지', behaviorConduct01001001: '태풍이 오기 전', behaviorConduct01001002: '태풍이 왔을 때', behaviorConduct01001003: '태풍이 지나간 후', behaviorConduct01002002: '홍수가 오기 전', behaviorConduct01002003: '홍수가 났을 때', behaviorConduct01002004: '홍수가 지나간 후', behaviorConduct01003002: '큰 비가 오기 전', behaviorConduct01003003: '큰 비가 내릴 때', behaviorConduct01003004: '큰 비가 그친 후', behaviorConduct01004001: '강풍이 오기 전', behaviorConduct01004002: '강풍 발생 시', behaviorConduct01005002: '대설이 오기 전', behaviorConduct01005003: '대설 내릴 때', behaviorConduct01005004: '눈이 그친 후', behaviorConduct01006001: '한파가 오기 전', behaviorConduct01006002: '한파 왔을 때', behaviorConduct01007001: '풍랑이 험할 때', behaviorConduct01007002: '풍랑이 오기 전', behaviorConduct01008001: '황사가 오기 전', behaviorConduct01008002: '황사가 왔을 때', behaviorConduct01008003: '황사가 지나간 후', behaviorConduct01009001: '폭염이 오기 전', behaviorConduct01009002: '폭염이 왔을 때', behaviorConduct01010001: '가뭄이 왔을 때', behaviorConduct01011009: '지진이 오기 전', behaviorConduct01011010: '지진이 왔을 때', behaviorConduct01011012: '지진 대피 후', behaviorConduct01013002: '해일이 오기 전', behaviorConduct01013003: '해일이 왔을 때', behaviorConduct01014001: '산사태가 오기 전', behaviorConduct03002002: '화상 처치', behaviorConduct03002003: '고열 예방', behaviorConduct03002004: '뱀에 물렸을 때 처치', behaviorConduct03002005: '벌에 쏘였을 때 처치', behaviorConduct03002006: '과호흡증후군 응급처치', behaviorConduct03003001: '성인 심폐소생술', behaviorConduct03003002: '영유아 심폐소생술', behaviorConduct03003003: '자동제세동기 사용', behaviorConduct03004001: '분말소화기 사용', behaviorConduct03016001: '옥내소화전 사용', behaviorConduct03005001: '식중독 대처', behaviorConduct03006004: '산행 중 유의사항', behaviorConduct03006005: '산에서 안전한 캠핑', behaviorConduct03006002: '구조요청시 알리는', behaviorConduct03006003: '산행사고시 응급조치', behaviorConduct03008001: '실종유괴 예방', behaviorConduct03009001: '성폭력 예방', behaviorConduct03010001: '학교 폭력 예방', behaviorConduct03011001: '가정 폭력 예방', behaviorConduct03012001: '억류 및 납치 시 대처', behaviorConduct03013002: '교통사고 발생 시 대처', behaviorConduct03013005: '차량에서의 구조', behaviorConduct03014001: '승강기 안전 이용', behaviorConduct03014003: '승강기 고장시 대처', behaviorConduct03014004: '에스컬레이터 안전 이용', behaviorConduct03015007: '미세먼지 많은 날 생활', behaviorConduct03015003: '부문별 생활', emergencyActionGuidelines01001: '태풍', emergencyActionGuidelines01001001: '태풍 예보 시', emergencyActionGuidelines01001002: '태풍 특보 시', emergencyActionGuidelines01001003: '태풍 이후', emergencyActionGuidelines01002: '홍수', emergencyActionGuidelines01002001: '홍수 예·경보 시', emergencyActionGuidelines01002002: '홍수 우려 때', emergencyActionGuidelines01002003: '물이 밀려들 때', emergencyActionGuidelines01002004: '물이 빠진 후에', emergencyActionGuidelines01003: '호우', emergencyActionGuidelines01003001: '호우 대비', emergencyActionGuidelines01003002: '호우 예보 시', emergencyActionGuidelines01003003: '호우 특보 중', emergencyActionGuidelines01003004: '호우 이후', emergencyActionGuidelines01004: '강풍', emergencyActionGuidelines01004001: '강풍 대비', emergencyActionGuidelines01004002: '강풍 발생 시', emergencyActionGuidelines01004003: '강풍 관련', emergencyActionGuidelines01005: '대설', emergencyActionGuidelines01005001: '대설 대비', emergencyActionGuidelines01005002: '대설 예보 시', emergencyActionGuidelines01005003: '대설 특보 시', emergencyActionGuidelines01005004: '대설 이후', emergencyActionGuidelines01006: '한파', emergencyActionGuidelines01006001: '한파 대비', emergencyActionGuidelines01006002: '한파 발생 시', emergencyActionGuidelines01007: '풍랑', emergencyActionGuidelines01007001: '풍랑 특보 시', emergencyActionGuidelines01008: '황사', emergencyActionGuidelines01008001: '황사 대비', emergencyActionGuidelines01008002: '황사 발생 시', emergencyActionGuidelines01008003: '황사 이후', emergencyActionGuidelines01008003: '황사 관련', emergencyActionGuidelines01009: '폭염', emergencyActionGuidelines01009001: '폭염 대비', emergencyActionGuidelines01009002: '폭염 발생 시', emergencyActionGuidelines01009003: '폭염 관련', emergencyActionGuidelines01010: '가뭄', emergencyActionGuidelines01010001: '가뭄 시 생활', emergencyActionGuidelines01010002: '가뭄 시 농촌', emergencyActionGuidelines01011: '지진', emergencyActionGuidelines01011007: '지진 발생 시 상황별', emergencyActionGuidelines01011008: '지진 발생 시 장소별', emergencyActionGuidelines01011009: '지진 대비', emergencyActionGuidelines01011010: '지진 발생 시', emergencyActionGuidelines01011011: '지진 장소별', emergencyActionGuidelines01011012: '지진 대피 후', emergencyActionGuidelines01012: '지진해일', emergencyActionGuidelines01012005: '발생 시 (선박 위)', emergencyActionGuidelines01012006: '발생 시 (지상 대피)', emergencyActionGuidelines01013: '해일', emergencyActionGuidelines01013001: '해일 대비', emergencyActionGuidelines01013002: '해일 때', emergencyActionGuidelines01013003: '해일 발생 때', emergencyActionGuidelines01013004: '미쳐 대피 못한 때', emergencyActionGuidelines01013005: '폭풍해일', emergencyActionGuidelines01014: '산사태', emergencyActionGuidelines01014001: '산사태 취약 지역 (주의보)', emergencyActionGuidelines01014002: '산사태 취약 지역 (경보)', emergencyActionGuidelines01014003: '일반 지역 (주의보)', emergencyActionGuidelines01014004: '일반 지역 (경보)', emergencyActionGuidelines01015: '화산폭발', emergencyActionGuidelines01015001: '화산재 낙하 대비', emergencyActionGuidelines01015002: '화산재 낙하 시', emergencyActionGuidelines01015003: '화산재 제거 이유', emergencyActionGuidelines02001: '해양오염', emergencyActionGuidelines02001001: '발생 전', emergencyActionGuidelines02001002: '발생 시', emergencyActionGuidelines02001003: '조치 완료 후', emergencyActionGuidelines02002: '대규모 수질오염', emergencyActionGuidelines02002001: '사고 시', emergencyActionGuidelines02002002: '구별 방법', emergencyActionGuidelines02003: '식용수', emergencyActionGuidelines02003001: '급수중단 발령 시', emergencyActionGuidelines02003002: 'Ⅰ급상황 발생 시', emergencyActionGuidelines02003003: 'Ⅱ급상황 발생 시', emergencyActionGuidelines02004: '공동구 재난', emergencyActionGuidelines02004001: '발생 우려 시', emergencyActionGuidelines02004002: '발생 시', emergencyActionGuidelines02005: '가축질병', emergencyActionGuidelines02005001: '구제역 발생 시', emergencyActionGuidelines02005002: '조류인플루엔자(AI) 발생 시', emergencyActionGuidelines02005003: '발생 방지 대책', emergencyActionGuidelines02005004: '발생 의심 시', emergencyActionGuidelines02005005: '발생 확인 시', emergencyActionGuidelines02006: '감염병', emergencyActionGuidelines02006001: '예방 대책', emergencyActionGuidelines02006002: '증상이 나타날 때', emergencyActionGuidelines02006003: '중동호흡기증후군(MERS)', emergencyActionGuidelines02007: '철도·지하철', emergencyActionGuidelines02007001: '지하철 화재 발생 시', emergencyActionGuidelines02007002: '고속철도 화재 발생 시', emergencyActionGuidelines02007003: '사고 및 테러(독가스) 발생 시', emergencyActionGuidelines02008: '금융전산', emergencyActionGuidelines02008001: '보이스피싱 피해금 지급 정지', emergencyActionGuidelines02008002: '보이스피싱 피해 예방', emergencyActionGuidelines02009: '원전사고', emergencyActionGuidelines02009001: '국민보호조치 발표 시', emergencyActionGuidelines02009002: '방사능구름 통과 시', emergencyActionGuidelines02009003: '옥내 대피 및 소개 시', emergencyActionGuidelines02010: '화학물질', emergencyActionGuidelines02010001: '화학물질 유출 시', emergencyActionGuidelines02010002: '니트로글리세린 누출 시', emergencyActionGuidelines02010003: '트리니트로톨루엔 누출 시', emergencyActionGuidelines02010004: '화학유해물질(독성가스) 누출 시', emergencyActionGuidelines02011: '화재', emergencyActionGuidelines02011001: '일반', emergencyActionGuidelines02011002: '예방 대책', emergencyActionGuidelines02011003: '화재 발생 후', emergencyActionGuidelines02011004: '화재 시', emergencyActionGuidelines02011005: '화재 시 긴급 대피', emergencyActionGuidelines02011006: '화재 시 피해 복구', emergencyActionGuidelines02011007: '가정에서의 안전', emergencyActionGuidelines02011008: '연기 관련 정보', emergencyActionGuidelines02011009: '아파트 화재 시', emergencyActionGuidelines02011010: '아파트 화재 대비', emergencyActionGuidelines02011011: '도로 터널 화재', emergencyActionGuidelines02011012: '대형 화재', emergencyActionGuidelines02011013: '고층 건물 화재', emergencyActionGuidelines02011014: '지하상가 화재 안전수칙', emergencyActionGuidelines02011015: '지하철 화재 발생 시', emergencyActionGuidelines02012: '산불', emergencyActionGuidelines02012001: '주택가 산불 확산 시', emergencyActionGuidelines02012002: '산불 방지', emergencyActionGuidelines02012003: '봄철 산불 관련', emergencyActionGuidelines02012004: '산불 예방', emergencyActionGuidelines02012005: '산불 발생 후', emergencyActionGuidelines02012006: '산불 대피', emergencyActionGuidelines02012007: '산불 피해 지역 가축 관리', emergencyActionGuidelines02013: '건축물 붕괴', emergencyActionGuidelines02013001: '사고 발생 시', emergencyActionGuidelines02013002: '징조를 느낄 때', emergencyActionGuidelines02013003: '건물 내부에 있을 때', emergencyActionGuidelines02013004: '건물 외부에 있을 때', emergencyActionGuidelines02013005: '붕괴, 매몰된 경우', emergencyActionGuidelines02013007: '도로 공사장 붕괴', emergencyActionGuidelines02013008: '상수도 공사장 붕괴', emergencyActionGuidelines02013009: '아파트 공사장 붕괴', emergencyActionGuidelines02013010: '지하철 공사장 붕괴', emergencyActionGuidelines02014: '댐 붕괴', emergencyActionGuidelines02014001: '붕괴 우려 시', emergencyActionGuidelines02014002: '붕괴 발생 시', emergencyActionGuidelines02014003: '물이 빠진 후', emergencyActionGuidelines02015: '폭발', emergencyActionGuidelines02015001: '가스 폭발 시', emergencyActionGuidelines02015004: '폭발 현장', emergencyActionGuidelines02016: '항공기', emergencyActionGuidelines02016001: '항공기 사고 예방', emergencyActionGuidelines02017: '화생방', emergencyActionGuidelines02017001: '사고 발생 시', emergencyActionGuidelines02018: '정전 및 전력부족', emergencyActionGuidelines02018001: '정전 시', emergencyActionGuidelines02018002: '정전 발생 시', emergencyActionGuidelines02018003: '정전 상황별', emergencyActionGuidelines02019: '전기·가스', emergencyActionGuidelines02019001: '전기사고 예방', emergencyActionGuidelines02019002: '침수지역 감전 사고 예방', emergencyActionGuidelines02019003: '대피 명령 시 전기설비 조치', emergencyActionGuidelines02019004: '정전 발생 시 조치', emergencyActionGuidelines02019005: '야외 주의 사항', emergencyActionGuidelines02019006: '가스사고 예방', emergencyActionGuidelines02019007: '가스사고 발생 시', emergencyActionGuidelines02019008: 'LPG 응급조치', emergencyActionGuidelines02019009: '도시가스(LNG) 응급조치', emergencyActionGuidelines02019010: '이동식 부탄가스 안전점검', emergencyActionGuidelines02019011: '가스 사용 시 안전점검', emergencyActionGuidelines02019012: '가스 누출 발생 시 대피', emergencyActionGuidelines02019013: '배관 등에서 대량 누출 시', emergencyActionGuidelines02019014: '기타 사항', emergencyActionGuidelines02019015: '암모니아가스 인체 접촉 시', emergencyActionGuidelines02019016: '염소가스 누출 시', emergencyActionGuidelines02020: '유도선', emergencyActionGuidelines02020001: '이용객 금지 행위', emergencyActionGuidelines02020002: '사고 발생 시', emergencyActionGuidelines02021: '수난사고', emergencyActionGuidelines02021001: '하천이나 계곡물', emergencyActionGuidelines02021002: '무릎 이상의 깊은 급류', emergencyActionGuidelines02021003: '물에 빠졌을 때', emergencyActionGuidelines02021004: '파도가 높아져 위험할 때', emergencyActionGuidelines02021005: '수초에 감겼을 때', emergencyActionGuidelines02021006: '의식 없는 사고자를 구했을 때', emergencyActionGuidelines02021007: '고립 지역', emergencyActionGuidelines02021008: '계곡에서 야영지를 선택 시', emergencyActionGuidelines02021009: '보트 전복 등에 따른 대처', emergencyActionGuidelines02021010: '갯바위 등 바다낚시 사고 예방', emergencyActionGuidelines02021011: '갯벌 해루질 사고 예방', emergencyActionGuidelines02022: '테러', emergencyActionGuidelines02022007: '신고 요령', emergencyActionGuidelines02022008: '대형, 고층건물 재난 시', emergencyActionGuidelines02022009: '폭발물 발견 시', emergencyActionGuidelines02022010: '화학 테러(독가스 등) 발생 시', emergencyActionGuidelines02022011: '생물 테러 발생 시', emergencyActionGuidelines02022012: '방사능 테러 발생 시', emergencyActionGuidelines02022013: '화재 발생 시', emergencyActionGuidelines02022014: '총격 현장', emergencyActionGuidelines02022015: '매몰, 붕괴 시', emergencyActionGuidelines02022016: '억류, 납치 시', emergencyActionGuidelines02022017: '테러범·의심물체 등', emergencyActionGuidelines02023: '전력수급', emergencyActionGuidelines02023001: '단계별', emergencyActionGuidelines03002: '응급처치', emergencyActionGuidelines03002001: '일반', emergencyActionGuidelines03002002: '화상', emergencyActionGuidelines03002003: '온열질환', emergencyActionGuidelines03002004: '뱀에 물렸을 때', emergencyActionGuidelines03002005: '벌에 쏘였을 때', emergencyActionGuidelines03002006: '과호흡증후군', emergencyActionGuidelines03002007: '상비약', emergencyActionGuidelines03003: '심폐소생술', emergencyActionGuidelines03003001: '성인', emergencyActionGuidelines03003002: '영유아', emergencyActionGuidelines03003003: '자동제세동기', emergencyActionGuidelines03004: '소화기', emergencyActionGuidelines03004001: '분말 소화기', emergencyActionGuidelines03004002: '투척용 소화기', emergencyActionGuidelines03004003: '설치/취급 및 사용법', emergencyActionGuidelines03004004: '소화기의 종류', emergencyActionGuidelines03005: '식중독', emergencyActionGuidelines03005001: '일반', emergencyActionGuidelines03005002: '음식점/급식소 운영자', emergencyActionGuidelines03006: '산행', emergencyActionGuidelines03006001: '위급 상황 시', emergencyActionGuidelines03006002: '구조 요청 시', emergencyActionGuidelines03006003: '응급조치', emergencyActionGuidelines03007: '어린이 놀이시설', emergencyActionGuidelines03007001: '탑승 대기', emergencyActionGuidelines03007002: '안전 이용', emergencyActionGuidelines03007003: '탑승 제한', emergencyActionGuidelines03007004: '어린이 탑승', emergencyActionGuidelines03007005: '탑승 시 주의', emergencyActionGuidelines03007006: '운행 중 자세', emergencyActionGuidelines03007007: '탑승 완료 후 퇴장', emergencyActionGuidelines03008: '실종유괴', emergencyActionGuidelines03008001: '예방 방법', emergencyActionGuidelines03009: '성폭력', emergencyActionGuidelines03009001: '예방 방법', emergencyActionGuidelines03010: '학교폭력', emergencyActionGuidelines03010001: '예방 방법', emergencyActionGuidelines03011: '가정폭력', emergencyActionGuidelines03011001: '예방 방법', emergencyActionGuidelines03012: '억류 및 납치', emergencyActionGuidelines03012001: '대처 요령', emergencyActionGuidelines03013: '교통사고', emergencyActionGuidelines03013001: '사고 예방', emergencyActionGuidelines03013002: '발생 시', emergencyActionGuidelines03013003: '상황 판단', emergencyActionGuidelines03013004: '구출', emergencyActionGuidelines03013005: '차량에서의 구조', emergencyActionGuidelines03014: '승강기', emergencyActionGuidelines03014001: '안전 이용', emergencyActionGuidelines03014002: '안전 문화', emergencyActionGuidelines03014003: '고장 시 안전 구조', emergencyActionGuidelines03014004: '에스컬레이터 안전 수칙', emergencyActionGuidelines03014005: '엘리베이터 사고 예방', emergencyActionGuidelines03014006: '에스컬레이터 및 무빙워크 사고 예방', emergencyActionGuidelines03015: '미세먼지', emergencyActionGuidelines03015001: '특성', emergencyActionGuidelines03015002: '미세먼지 예보 등급별', emergencyActionGuidelines03015003: '부문별 생활 수칙', emergencyActionGuidelines03015004: '인체에 미치는 영향', emergencyActionGuidelines03015005: '미세먼지 정보', emergencyActionGuidelines03015006: '미세먼지 발생 시', emergencyActionGuidelines03015007: '미세먼지 많은 날', emergencyActionGuidelines03016: '소화전', emergencyActionGuidelines03016001: '옥내소화전 사용법', emergencyActionGuidelines03016002: '경보 설비', emergencyActionGuidelines03017: '가정 안전점검', emergencyActionGuidelines03017001: '안전점검의 날 준비', emergencyActionGuidelines03017002: '계절별 대비', tts_female: '여성', tts_male: '남성', tts_kind: '친절한', tts_sweet: '감미로운', tts_echo: '울리는', tts_mischievous: '장난스러운', tts_dainty: '앙증맞은', tts_veryslow: '매우 느린', tts_slow: '느린', tts_normal: '보통', tts_fast: '빠른', tts_veryfast: '매우 빠른', tts_verylow: '매우 낮은', tts_low: '낮은', tts_high: '높은', tts_veryhigh: '매우 높은', ARDUINO: '하드웨어', ARDUINO_download_connector: '• 연결 프로그램 다운로드', ARDUINO_open_connector: '연결 프로그램 열기', ARDUINO_download_source: '• 엔트리 아두이노 소스', ARDUINO_reconnect: '하드웨어 연결하기', hardware_connect_helper: '하드웨어 연결 도움말', hardware_noti_installed: '프로그램을 설치해 연결할 때', hardware_noti_not_installed: '프로그램 설치 없이 연결할 때', hardware_program_download: '연결 프로그램 다운로드', hardware_device_name_title: '연결한 하드웨어:', hardware_device_name_title_robot: '연결한 로봇:', hardware_device_name_content: '없음', hardware_connected_noti: '하드웨어 연결 프로그램을\n확인해 주세요.', arduino_noti_text: '하드웨어 연결은\n데스크톱 PC에서만 지원됩니다.\n \n태블릿 PC 연결 지원에 대해서는 \n하드웨어 제조사에 문의해 주세요.', arduino_lite_alert: '하드웨어를 찾을 수 없습니다.\n하드웨어에 펌웨어가 설치되었는지,\nPC와 하드웨어가 연결되어 있는지 \n다시 확인해 주세요.', arduino_lite_reconnect: '하드웨어 다시 연결', arduino_lite_download_firmware: '펌웨어 다운로드', arduino_lite_download_driver: '드라이버 다운로드', arduino_lite_connect: '브라우저로 연결하기', arduino_lite_disconnect: '하드웨어 선택 취소', arduino_lite_guide: '• 아두이노 연결 가이드', arduino_lite_connected_noti: '하드웨어를 선택한 상태에서\n작품을 저장해 주세요.', ARDUINO_LITE: '하드웨어 라이트', ROBOT_connect_helper: '로봇 연결 도움말', ROBOT_reconnect: '로봇 연결하기', ARDUINO_program: '프로그램 실행하기', ARDUINO_cloud_pc_connector: '클라우드 PC 연결하기', ARDUINO_connected: '하드웨어가 연결되었습니다. ', ARDUINO_connect: '* 하드웨어를 연결하세요.', ARDUINO_arduino_get_number_1: '신호', ARDUINO_arduino_get_number_2: '의 숫자 결과값', ARDUINO_arduino_get_sensor_number_0: '0', ARDUINO_arduino_get_sensor_number_1: '1', ARDUINO_arduino_get_sensor_number_2: '2', ARDUINO_arduino_get_sensor_number_3: '3', ARDUINO_arduino_get_sensor_number_4: '4', ARDUINO_arduino_get_sensor_number_5: '5', blacksmith_toggle_on: '켜기', blacksmith_toggle_off: '끄기', blacksmith_lcd_first_line: '첫 번째', blacksmith_lcd_seconds_line: '두 번째', BITBRICK_light: '밝기 센서', BITBRICK_IR: '적외선 센서', BITBRICK_touch: '버튼', BITBRICK_potentiometer: '가변저항', BITBRICK_MIC: '소리 센서', BITBRICK_UserSensor: '사용자 입력', BITBRICK_UserInput: '사용자 입력', BITBRICK_dc_direction_ccw: '반시계', BITBRICK_dc_direction_cw: '시계', chocopi_control_event_pressed: '누를 때', chocopi_control_event_released: '뗄 때', chocopi_joystick_X: '조이스틱 좌우', chocopi_joystick_Y: '조이스틱 상하', chocopi_motion_photogate_event_blocked: '막았을 때', chocopi_motion_photogate_event_unblocked: '열었을 때', chocopi_motion_photogate_time_blocked: '막은 시간', chocopi_motion_photogate_time_unblocked: '연 시간', chocopi_port: '포트', chocopi_pot: '볼륨', chocopi_touch_event_touch: '만질 때', chocopi_touch_event_untouch: '뗄 때', CODEino_get_sensor_number_0: '0', CODEino_get_sensor_number_1: '1', CODEino_get_sensor_number_2: '2', CODEino_get_sensor_number_3: '3', CODEino_get_sensor_number_4: '4', CODEino_get_sensor_number_5: '5', CODEino_get_sensor_number_6: '6', CODEino_sensor_name_0: '소리', CODEino_sensor_name_1: '빛', CODEino_sensor_name_2: '슬라이더', CODEino_sensor_name_3: '저항-A', CODEino_sensor_name_4: '저항-B', CODEino_sensor_name_5: '저항-C', CODEino_sensor_name_6: '저항-D', CODEino_string_1: ' 센서값 ', CODEino_string_2: ' 보드의 ', CODEino_string_3: '버튼누름', CODEino_string_4: 'A 연결됨', CODEino_string_5: 'B 연결됨', CODEino_string_6: 'C 연결됨', CODEino_string_7: 'D 연결됨', CODEino_string_8: ' 3축 가속도센서 ', CODEino_string_9: '축의 센서값 ', CODEino_string_10: '소리센서 ', CODEino_string_11: '소리큼', CODEino_string_12: '소리작음', CODEino_string_13: '빛센서 ', CODEino_string_14: '밝음', CODEino_string_15: '어두움', CODEino_string_16: '왼쪽 기울임', CODEino_string_17: '오른쪽 기울임', CODEino_string_18: '위쪽 기울임', CODEino_string_19: '아래쪽 기울임', CODEino_string_20: '뒤집힘', CODEino_accelerometer_X: 'X', CODEino_accelerometer_Y: 'Y', CODEino_accelerometer_Z: 'Z', CODEino_led_red: '빨강', CODEino_led_green: '초록', CODEino_led_blue: '파랑', iboard_analog_number_0: 'A0', iboard_analog_number_1: 'A1', iboard_analog_number_2: 'A2', iboard_analog_number_3: 'A3', iboard_analog_number_4: 'A4', iboard_analog_number_5: 'A5', iboard_light: '빛센서가 ', iboard_num_pin_1: 'LED 상태를', iboard_num_pin_2: '번 스위치가', iboard_num_pin_3: '아날로그', iboard_num_pin_4: '번 ', iboard_num_pin_5: '센서값', iboard_string_1: '켜짐', iboard_string_2: '꺼짐', iboard_string_3: '밝음', iboard_string_4: '어두움', iboard_string_5: '눌림', iboard_string_6: '열림', iboard_switch: '스위치 ', iboard_tilt: '기울기센서 상태가', dplay_switch: '스위치 ', dplay_light: '빛센서가 ', dplay_tilt: '기울기센서 상태가', dplay_string_1: '켜짐', dplay_string_2: '꺼짐', dplay_string_3: '밝음', dplay_string_4: '어두움', dplay_string_5: '눌림', dplay_string_6: '열림', dplay_num_pin_1: 'LED 상태를', dplay_num_pin_2: '번 스위치가', dplay_num_pin_3: '아날로그', dplay_num_pin_4: '번 ', dplay_num_pin_5: '센서값', dplay_analog_number_0: 'A0', dplay_analog_number_1: 'A1', dplay_analog_number_2: 'A2', dplay_analog_number_3: 'A3', dplay_analog_number_4: 'A4', dplay_analog_number_5: 'A5', ARDUINO_arduino_get_string_1: '신호', ARDUINO_arduino_get_string_2: '의 글자 결과값', ARDUINO_arduino_send_1: '신호', ARDUINO_arduino_send_2: '보내기', ARDUINO_num_sensor_value_1: '아날로그', ARDUINO_num_sensor_value_2: '번 센서값', ARDUINO_get_digital_value_1: '디지털', ARDUINO_num_pin_1: '디지털', ARDUINO_num_pin_2: '번 핀', ARDUINO_toggle_pwm_1: '디지털', ARDUINO_toggle_pwm_2: '번 핀을', ARDUINO_toggle_pwm_3: '(으)로 정하기', ARDUINO_on: '켜기', ARDUINO_convert_scale_1: '', ARDUINO_convert_scale_2: '값의 범위를', ARDUINO_convert_scale_3: '~', ARDUINO_convert_scale_4: '에서', ARDUINO_convert_scale_5: '~', ARDUINO_convert_scale_6: '(으)로 바꾼값', ARDUINO_off: '끄기', EXPANSION: '확장', brightness: '밝기', BRUSH: '붓', BRUSH_brush_erase_all: '모든 붓 지우기', BRUSH_change_opacity_1: '붓의 불투명도를', BRUSH_change_opacity_2: '% 만큼 바꾸기', BRUSH_change_thickness_1: '붓의 굵기를', BRUSH_change_thickness_2: '만큼 바꾸기', BRUSH_set_color_1: '붓의 색을', BRUSH_set_color_2: '(으)로 정하기', BRUSH_set_opacity_1: '붓의 불투명도를', BRUSH_set_opacity_2: '% 로 정하기', BRUSH_set_random_color: '붓의 색을 무작위로 정하기', BRUSH_set_thickness_1: '붓의 굵기를', BRUSH_set_thickness_2: '(으)로 정하기', BRUSH_stamp: '도장 찍기', BRUSH_start_drawing: '그리기 시작하기', BRUSH_stop_drawing: '그리기 멈추기', CALC: '계산', CALC_calc_mod_1: '', CALC_calc_mod_2: '/', CALC_calc_mod_3: '의 나머지', CALC_calc_operation_of_1: '', CALC_calc_operation_of_2: '의', CALC_calc_operation_root: '루트', CALC_calc_operation_square: '제곱', CALC_calc_rand_1: '', CALC_calc_rand_2: '부터', CALC_calc_rand_3: '사이의 무작위 수', CALC_calc_share_1: '', CALC_calc_share_2: '/', CALC_calc_share_3: '의 몫', CALC_coordinate_mouse_1: '마우스', CALC_coordinate_mouse_2: '좌푯값', CALC_coordinate_object_1: '', CALC_coordinate_object_2: '의', CALC_coordinate_object_3: '', CALC_distance_something_1: '', CALC_distance_something_2: '까지의 거리', CALC_get_angle: '각도값', CALC_get_date_1: ' 현재', CALC_get_date_2: '', CALC_get_date_day: '일', CALC_get_date_hour: '시각(시)', CALC_get_date_minute: '시각(분)', CALC_get_date_day_of_week: '요일', CALC_get_date_month: '월', CALC_get_date_second: '시각(초)', CALC_get_date_year: '연도', CALC_get_sound_duration_1: '', CALC_get_sound_duration_2: '소리의 길이', CALC_get_timer_value: ' 초시계 값', CALC_get_x_coordinate: 'X 좌푯값', CALC_get_y_coordinate: 'Y 좌푯값', CALC_timer_reset: '초시계 초기화', CALC_timer_visible_1: '초시계', CALC_timer_visible_2: '', CALC_timer_visible_show: '보이기', CALC_timer_visible_hide: '숨기기', color: '색깔', FLOW: '흐름', FLOW__if_1: '만일', FLOW__if_2: '이라면', FLOW_create_clone_1: '', FLOW_create_clone_2: '의 복제본 만들기', FLOW_delete_clone: '이 복제본 삭제하기', FLOW_delete_clone_all: '모든 복제본 삭제하기', FLOW_if_else_1: '만일', FLOW_if_else_2: '이라면', FLOW_if_else_3: '아니면', FLOW_repeat_basic_1: '', FLOW_repeat_basic_2: '번 반복하기', FLOW_repeat_basic_errorMsg: '반복 횟수는 0보다 같거나 커야 합니다.', FLOW_repeat_inf: '계속 반복하기', FLOW_restart: '처음부터 다시 실행하기', FLOW_stop_object_1: '', FLOW_stop_object_2: '멈추기', FLOW_stop_object_all: '모든', FLOW_stop_object_this_object: '자신의', FLOW_stop_object_this_thread: '이', FLOW_stop_object_other_thread: '자신의 다른', FLOW_stop_object_other_objects: '다른 오브젝트의', FLOW_stop_repeat: '반복 중단하기', FLOW_stop_run: '프로그램 끝내기', FLOW_wait_second_1: '', FLOW_wait_second_2: '초 기다리기', FLOW_wait_until_true_1: '', FLOW_wait_until_true_2: '이(가) 될 때까지 기다리기', FLOW_when_clone_start: '복제본이 처음 생성되었을때', FUNC: '함수', ANALYSIS: '데이터분석', AI: '인공지능', JUDGEMENT: '판단', JUDGEMENT_boolean_and: '그리고', JUDGEMENT_boolean_not_1: '', JUDGEMENT_boolean_not_2: '(이)가 아니다', JUDGEMENT_boolean_or: '또는', JUDGEMENT_false: ' 거짓 ', JUDGEMENT_is_clicked: '마우스를 클릭했는가?', JUDGEMENT_is_object_clicked: '오브젝트를 클릭했는가?', JUDGEMENT_is_press_some_key_1: '', JUDGEMENT_is_press_some_key_2: '키가 눌러져 있는가?', JUDGEMENT_reach_something_1: '', JUDGEMENT_reach_something_2: '에 닿았는가?', JUDGEMENT_is_type_1: '(이)가', JUDGEMENT_is_type_2: '인가?', JUDGEMENT_true: ' 참 ', JUDGEMENT_is_boost_mode: '부스트모드가 켜져 있는가?', is_type_number: '숫자', LOOKS: '생김새', LOOKS_change_scale_percent_1: '크기를', LOOKS_change_scale_percent_2: '만큼 바꾸기', LOOKS_change_to_next_shape: '다음 모양으로 바꾸기', LOOKS_change_to_nth_shape_1: '', LOOKS_change_to_nth_shape_2: '모양으로 바꾸기', LOOKS_change_shape_prev: '이전', LOOKS_change_shape_next: '다음', LOOKS_change_to_near_shape_1: '', LOOKS_change_to_near_shape_2: '모양으로 바꾸기', LOOKS_dialog_1: '', LOOKS_dialog_2: '을(를)', LOOKS_dialog_3: '', LOOKS_dialog_time_1: '', LOOKS_dialog_time_2: '을(를)', LOOKS_dialog_time_3: '초 동안', LOOKS_dialog_time_4: '', LOOKS_erase_all_effects: '효과 모두 지우기', LOOKS_flip_x: '상하 모양 뒤집기', LOOKS_flip_y: '좌우 모양 뒤집기', LOOKS_hide: '모양 숨기기', LOOKS_remove_dialog: '말하기 지우기', LOOKS_set_effect_1: '', LOOKS_set_effect_2: '효과를', LOOKS_set_effect_3: '(으)로 정하기', LOOKS_set_effect_volume_1: '', LOOKS_set_effect_volume_2: '효과를', LOOKS_set_effect_volume_3: '만큼 주기', LOOKS_set_object_order_1: '', LOOKS_set_object_order_2: '번째로 올라오기', LOOKS_set_scale_percent_1: '크기를', LOOKS_set_scale_percent_2: ' (으)로 정하기', LOOKS_show: '모양 보이기', mouse_pointer: '마우스포인터', MOVING: '움직임', MOVING_bounce_wall: '화면 끝에 닿으면 튕기기', MOVING_bounce_when_1: '', MOVING_bounce_when_2: '에 닿으면 튕기기', MOVING_flip_arrow_horizontal: '화살표 방향 좌우 뒤집기', MOVING_flip_arrow_vertical: '화살표 방향 상하 뒤집기', MOVING_locate_1: '', MOVING_locate_2: '위치로 이동하기', MOVING_locate_time_1: '', MOVING_locate_time_2: '초 동안', MOVING_locate_time_3: '위치로 이동하기', MOVING_locate_x_1: 'x:', MOVING_locate_x_2: '위치로 이동하기', MOVING_locate_xy_1: 'x:', MOVING_locate_xy_2: 'y:', MOVING_locate_xy_3: '위치로 이동하기', MOVING_locate_xy_time_1: '', MOVING_locate_xy_time_2: '초 동안 x:', MOVING_locate_xy_time_3: 'y:', MOVING_locate_xy_time_4: '위치로 이동하기', MOVING_locate_y_1: 'y:', MOVING_locate_y_2: '위치로 이동하기', MOVING_move_direction_1: '이동 방향으로', MOVING_move_direction_2: '만큼 움직이기', MOVING_move_direction_angle_1: '', MOVING_move_direction_angle_2: '방향으로', MOVING_move_direction_angle_3: '만큼 움직이기', MOVING_move_x_1: 'x 좌표를', MOVING_move_x_2: '만큼 바꾸기', MOVING_move_xy_time_1: '', MOVING_move_xy_time_2: '초 동안 x:', MOVING_move_xy_time_3: 'y:', MOVING_move_xy_time_4: '만큼 움직이기', MOVING_move_y_1: 'y 좌표를', MOVING_move_y_2: '만큼 바꾸기', MOVING_rotate_by_angle_1: '오브젝트를', MOVING_rotate_by_angle_2: '만큼 회전하기', MOVING_rotate_by_angle_dropdown_1: '', MOVING_rotate_by_angle_dropdown_2: '만큼 회전하기', MOVING_rotate_by_angle_time_1: '오브젝트를', MOVING_rotate_by_angle_time_2: '초 동안', MOVING_rotate_by_angle_time_3: '만큼 회전하기', MOVING_rotate_direction_1: '이동 방향을', MOVING_rotate_direction_2: '만큼 회전하기', MOVING_see_angle_1: '이동 방향을', MOVING_see_angle_2: '(으)로 정하기', MOVING_see_angle_direction_1: '오브젝트를', MOVING_see_angle_direction_2: '(으)로 정하기', MOVING_see_angle_object_1: '', MOVING_see_angle_object_2: '쪽 바라보기', MOVING_see_direction_1: '', MOVING_see_direction_2: '쪽 보기', MOVING_set_direction_by_angle_1: '방향을', MOVING_set_direction_by_angle_2: '(으)로 정하기', MOVING_add_direction_by_angle_1: '방향을', MOVING_add_direction_by_angle_2: '만큼 회전하기', MOVING_add_direction_by_angle_time_1: '방향을', MOVING_add_direction_by_angle_time_2: '초 동안', MOVING_add_direction_by_angle_time_3: '만큼 회전하기', no_target: '대상 없음', oneself: '자신', opacity: '불투명도', SCENE: '장면', SOUND: '소리', SOUND_sound_silent_all: '모든 소리 멈추기', SOUND_sound_something_1: '소리', SOUND_sound_something_2: '재생하기', SOUND_sound_something_second_1: '소리', SOUND_sound_something_second_2: '', SOUND_sound_something_second_3: '초 재생하기', SOUND_sound_something_second_wait_1: '소리', SOUND_sound_something_second_wait_2: '', SOUND_sound_something_second_wait_3: '초 재생하고 기다리기', SOUND_sound_something_wait_1: '소리 ', SOUND_sound_something_wait_2: '재생하고 기다리기', SOUND_sound_volume_change_1: '소리 크기를', SOUND_sound_volume_change_2: '% 만큼 바꾸기', SOUND_sound_volume_set_1: '소리 크기를', SOUND_sound_volume_set_2: '% 로 정하기', speak: '말하기', think: '생각하기', START: '시작', START_add_message: '신호 추가하기', START_delete_message: '신호 삭제하기', START_message_cast: '신호 보내기', START_message_cast_1: '', START_message_cast_2: '신호 보내기', START_message_cast_wait: '신호 보내고 기다리기', START_message_send_wait_1: '', START_message_send_wait_2: '신호 보내고 기다리기', START_mouse_click_cancled: '마우스 클릭을 해제했을 때', START_mouse_clicked: '마우스를 클릭했을 때', START_press_some_key_1: '', START_press_some_key_2: '키를 눌렀을 때', START_press_some_key_down: '아래쪽 화살표', START_press_some_key_enter: '엔터', START_press_some_key_left: '왼쪽 화살표', START_press_some_key_right: '오른쪽 화살표', START_press_some_key_space: '스페이스', START_press_some_key_up: '위쪽 화살표', START_press_some_key_back_space: '백스페이스', START_press_some_key_back_slash: '백슬래시', START_when_message_cast: '신호를 받았을 때', START_when_message_cast_1: '', START_when_message_cast_2: '신호를 받았을 때', START_when_object_click: '오브젝트를 클릭했을 때', START_when_object_click_canceled: '오브젝트 클릭을 해제했을 때', START_when_run_button_click: '시작하기 버튼을 클릭했을 때', START_when_scene_start: '장면이 시작했을때', START_when_some_key_click: '키를 눌렀을 때', TEXT: '글상자', TEXT_text: '엔트리', TEXT_text_append_1: '', TEXT_text_append_2: '라고 뒤에 이어쓰기', TEXT_text_flush: '텍스트 모두 지우기', TEXT_text_prepend_1: '', TEXT_text_prepend_2: '라고 앞에 추가하기', TEXT_text_write_1: '', TEXT_text_write_2: '라고 글쓰기', VARIABLE: '자료', VARIABLE_add_value_to_list: '항목을 리스트에 추가하기', VARIABLE_add_value_to_list_1: '', VARIABLE_add_value_to_list_2: '항목을', VARIABLE_add_value_to_list_3: '에 추가하기', VARIABLE_ask_and_wait_1: '', VARIABLE_ask_and_wait_2: '을(를) 묻고 대답 기다리기', VARIABLE_change_value_list_index: '항목을 바꾸기', VARIABLE_change_value_list_index_1: '', VARIABLE_change_value_list_index_3: '번째 항목을', VARIABLE_change_value_list_index_2: ' ', VARIABLE_change_value_list_index_4: '(으)로 바꾸기', VARIABLE_change_variable: '변수 더하기', VARIABLE_change_variable_1: '', VARIABLE_change_variable_2: '에', VARIABLE_change_variable_3: '만큼 더하기', VARIABLE_change_variable_name: '변수 이름 바꾸기', VARIABLE_combine_something_1: '', VARIABLE_combine_something_2: '과(와)', VARIABLE_combine_something_3: '을(를) 합친 값', VARIABLE_get_canvas_input_value: ' 대답 ', VARIABLE_get_variable: '변수', VARIABLE_get_variable_1: '값', VARIABLE_get_variable_2: '값', VARIABLE_get_y: 'Y 좌푯값', VARIABLE_hide_list: '리스트 숨기기', VARIABLE_hide_list_1: '리스트', VARIABLE_hide_list_2: '숨기기', VARIABLE_hide_variable: '변수값 숨기기', VARIABLE_hide_variable_1: '변수', VARIABLE_hide_variable_2: '숨기기', VARIABLE_insert_value_to_list: '항목을 넣기', VARIABLE_insert_value_to_list_1: '', VARIABLE_insert_value_to_list_2: '을(를)', VARIABLE_insert_value_to_list_3: '의', VARIABLE_insert_value_to_list_4: '번째에 넣기', VARIABLE_length_of_list: '리스트의 길이', VARIABLE_length_of_list_1: '', VARIABLE_length_of_list_2: ' 항목 수', VARIABLE_list: '리스트', VARIABLE_make_variable: '변수 만들기', VARIABLE_list_option_first: '첫번째', VARIABLE_list_option_last: '마지막', VARIABLE_list_option_random: '무작위', VARIABLE_remove_value_from_list: '항목을 삭제하기', VARIABLE_remove_value_from_list_1: '', VARIABLE_remove_value_from_list_2: '번째 항목을', VARIABLE_remove_value_from_list_3: '에서 삭제하기', VARIABLE_remove_variable: '변수 삭제', VARIABLE_set_variable: '변수 정하기', VARIABLE_set_variable_1: '', VARIABLE_set_variable_2: '를', VARIABLE_set_variable_3: '로 정하기', VARIABLE_show_list: '리스트 보이기', VARIABLE_show_list_1: '리스트', VARIABLE_show_list_2: '보이기', VARIABLE_show_variable: '변수값 보이기', VARIABLE_show_variable_1: '변수', VARIABLE_show_variable_2: '보이기', VARIABLE_value_of_index_from_list: '리스트 항목의 값', VARIABLE_value_of_index_from_list_1: '', VARIABLE_value_of_index_from_list_2: '의', VARIABLE_value_of_index_from_list_3: '번째 항목', HAMSTER_hand_found: '손 찾음?', HAMSTER_sensor_left_proximity: '왼쪽 근접 센서', HAMSTER_sensor_right_proximity: '오른쪽 근접 센서', HAMSTER_sensor_left_floor: '왼쪽 바닥 센서', HAMSTER_sensor_right_floor: '오른쪽 바닥 센서', HAMSTER_sensor_acceleration_x: 'x축 가속도', HAMSTER_sensor_acceleration_y: 'y축 가속도', HAMSTER_sensor_acceleration_z: 'z축 가속도', HAMSTER_sensor_light: '밝기', HAMSTER_sensor_temperature: '온도', HAMSTER_sensor_signal_strength: '신호 세기', HAMSTER_sensor_input_a: '입력 A', HAMSTER_sensor_input_b: '입력 B', HAMSTER_move_forward_once: '말판 앞으로 한 칸 이동하기', HAMSTER_turn_once_1: '말판', HAMSTER_turn_once_2: '으로 한 번 돌기', HAMSTER_turn_once_left: '왼쪽', HAMSTER_turn_right: '오른쪽', HAMSTER_move_forward: '앞으로 이동하기', HAMSTER_move_backward: '뒤로 이동하기', HAMSTER_turn_around_1: '', HAMSTER_turn_around_2: '으로 돌기', HAMSTER_move_forward_for_secs_1: '앞으로', HAMSTER_move_forward_for_secs_2: '초 이동하기', HAMSTER_move_backward_for_secs_1: '뒤로', HAMSTER_move_backward_for_secs_2: '초 이동하기', HAMSTER_turn_for_secs_1: '', HAMSTER_turn_for_secs_2: '으로', HAMSTER_turn_for_secs_3: '초 돌기', HAMSTER_change_both_wheels_by_1: '왼쪽 바퀴', HAMSTER_change_both_wheels_by_2: '오른쪽 바퀴', HAMSTER_change_both_wheels_by_3: '만큼 바꾸기', HAMSTER_set_both_wheels_to_1: '왼쪽 바퀴', HAMSTER_set_both_wheels_to_2: '오른쪽 바퀴', HAMSTER_set_both_wheels_to_3: '(으)로 정하기', HAMSTER_change_wheel_by_1: '', HAMSTER_change_wheel_by_2: '바퀴', HAMSTER_change_wheel_by_3: '만큼 바꾸기', HAMSTER_left_wheel: '왼쪽', HAMSTER_right_wheel: '오른쪽', HAMSTER_both_wheels: '양쪽', HAMSTER_set_wheel_to_1: '', HAMSTER_set_wheel_to_2: '바퀴', HAMSTER_set_wheel_to_3: '(으)로 정하기', HAMSTER_follow_line_using_1: '', HAMSTER_follow_line_using_2: '선을', HAMSTER_follow_line_using_3: '바닥 센서로 따라가기', HAMSTER_left_floor_sensor: '왼쪽', HAMSTER_right_floor_sensor: '오른쪽', HAMSTER_both_floor_sensors: '양쪽', HAMSTER_follow_line_until_1: '', HAMSTER_follow_line_until_2: '선을 따라', HAMSTER_follow_line_until_3: '교차로까지 이동하기', HAMSTER_left_intersection: '왼쪽', HAMSTER_right_intersection: '오른쪽', HAMSTER_front_intersection: '앞쪽', HAMSTER_rear_intersection: '뒤쪽', HAMSTER_set_following_speed_to_1: '선 따라가기 속도를', HAMSTER_set_following_speed_to_2: '(으)로 정하기', HAMSTER_front: '앞쪽', HAMSTER_rear: '뒤쪽', HAMSTER_stop: '정지하기', HAMSTER_set_led_to_1: '', HAMSTER_set_led_to_2: 'LED를', HAMSTER_set_led_to_3: '으로 정하기', HAMSTER_left_led: '왼쪽', HAMSTER_right_led: '오른쪽', HAMSTER_both_leds: '양쪽', HAMSTER_clear_led_1: '', HAMSTER_clear_led_2: 'LED 끄기', HAMSTER_color_cyan: '하늘색', HAMSTER_color_magenta: '자주색', HAMSTER_color_black: '검은색', HAMSTER_color_white: '하얀색', HAMSTER_color_red: '빨간색', HAMSTER_color_yellow: '노란색', HAMSTER_color_green: '초록색', HAMSTER_color_blue: '파란색', HAMSTER_beep: '삐 소리내기', HAMSTER_change_buzzer_by_1: '버저 음을', HAMSTER_change_buzzer_by_2: '만큼 바꾸기', HAMSTER_set_buzzer_to_1: '버저 음을', HAMSTER_set_buzzer_to_2: '(으)로 정하기', HAMSTER_clear_buzzer: '버저 끄기', HAMSTER_play_note_for_1: '', HAMSTER_play_note_for_2: '', HAMSTER_play_note_for_3: '음을', HAMSTER_play_note_for_4: '박자 연주하기', HAMSTER_rest_for_1: '', HAMSTER_rest_for_2: '박자 쉬기', HAMSTER_change_tempo_by_1: '연주 속도를', HAMSTER_change_tempo_by_2: '만큼 바꾸기', HAMSTER_set_tempo_to_1: '연주 속도를 분당', HAMSTER_set_tempo_to_2: '박자로 정하기', HAMSTER_set_port_to_1: '포트', HAMSTER_set_port_to_2: '를', HAMSTER_set_port_to_3: '으로 정하기', HAMSTER_change_output_by_1: '출력', HAMSTER_change_output_by_2: '를', HAMSTER_change_output_by_3: '만큼 바꾸기', HAMSTER_set_output_to_1: '출력', HAMSTER_set_output_to_2: '를', HAMSTER_set_output_to_3: '(으)로 정하기', HAMSTER_port_a: 'A', HAMSTER_port_b: 'B', HAMSTER_port_ab: 'A와 B', HAMSTER_analog_input: '아날로그 입력', HAMSTER_digital_input: '디지털 입력', HAMSTER_servo_output: '서보 출력', HAMSTER_pwm_output: 'PWM 출력', HAMSTER_digital_output: '디지털 출력', ROBOID_acceleration_x: 'x축 가속도', ROBOID_acceleration_y: 'y축 가속도', ROBOID_acceleration_z: 'z축 가속도', ROBOID_back: '뒤쪽', ROBOID_both: '양쪽', ROBOID_button: '버튼', ROBOID_buzzer: '버저', ROBOID_clicked: '클릭했는가', ROBOID_color_any: '아무 색', ROBOID_color_black: '검은색', ROBOID_color_blue: '파란색', ROBOID_color_green: '초록색', ROBOID_color_number: '색깔 번호', ROBOID_color_orange: '주황색', ROBOID_color_pattern: '색깔 패턴', ROBOID_color_purple: '자주색', ROBOID_color_red: '빨간색', ROBOID_color_sky_blue: '하늘색', ROBOID_color_violet: '보라색', ROBOID_color_white: '하얀색', ROBOID_color_yellow: '노란색', ROBOID_double_clicked: '더블클릭했는가', ROBOID_floor: '바닥 센서', ROBOID_head: '머리', ROBOID_head_color: '머리 색깔', ROBOID_left: '왼쪽', ROBOID_left_wheel: '왼쪽 바퀴', ROBOID_long_pressed: '길게~눌렀는가', ROBOID_note: '음표', ROBOID_right: '오른쪽', ROBOID_right_wheel: '오른쪽 바퀴', ROBOID_sound_beep: '삐', ROBOID_sound_birthday: '생일', ROBOID_sound_dibidibidip: '디비디비딥', ROBOID_sound_engine: '엔진', ROBOID_sound_good_job: '잘 했어요', ROBOID_sound_march: '행진', ROBOID_sound_random_beep: '무작위 삐', ROBOID_sound_robot: '로봇', ROBOID_sound_siren: '사이렌', ROBOID_tail: '꼬리', ROBOID_unit_cm: 'cm', ROBOID_unit_deg: '도', ROBOID_unit_pulse: '펄스', ROBOID_unit_sec: '초', ALBERT_hand_found: '손 찾음?', ALBERT_is_oid_1: '', ALBERT_is_oid_2: 'OID 값이', ALBERT_is_oid_3: '인가?', ALBERT_front_oid: '앞쪽', ALBERT_back_oid: '뒤쪽', ALBERT_sensor_left_proximity: '왼쪽 근접 센서', ALBERT_sensor_right_proximity: '오른쪽 근접 센서', ALBERT_sensor_acceleration_x: 'x축 가속도', ALBERT_sensor_acceleration_y: 'y축 가속도', ALBERT_sensor_acceleration_z: 'z축 가속도', ALBERT_sensor_light: '밝기', ALBERT_sensor_temperature: '온도', ALBERT_sensor_battery: '배터리', ALBERT_sensor_signal_strength: '신호 세기', ALBERT_sensor_front_oid: '앞쪽 OID', ALBERT_sensor_back_oid: '뒤쪽 OID', ALBERT_sensor_position_x: 'x 위치', ALBERT_sensor_position_y: 'y 위치', ALBERT_sensor_orientation: '방향', ALBERT_move_forward: '앞으로 이동하기', ALBERT_move_backward: '뒤로 이동하기', ALBERT_turn_around_1: '', ALBERT_turn_around_2: '으로 돌기', ALBERT_move_forward_for_secs_1: '앞으로', ALBERT_move_forward_for_secs_2: '초 이동하기', ALBERT_move_backward_for_secs_1: '뒤로', ALBERT_move_backward_for_secs_2: '초 이동하기', ALBERT_turn_for_secs_1: '', ALBERT_turn_for_secs_2: '으로', ALBERT_turn_for_secs_3: '초 돌기', ALBERT_turn_left: '왼쪽', ALBERT_turn_right: '오른쪽', ALBERT_change_both_wheels_by_1: '왼쪽 바퀴', ALBERT_change_both_wheels_by_2: '오른쪽 바퀴', ALBERT_change_both_wheels_by_3: '만큼 바꾸기', ALBERT_left_wheel: '왼쪽', ALBERT_right_wheel: '오른쪽', ALBERT_both_wheels: '양쪽', ALBERT_set_both_wheels_to_1: '왼쪽 바퀴', ALBERT_set_both_wheels_to_2: '오른쪽 바퀴', ALBERT_set_both_wheels_to_3: '(으)로 정하기', ALBERT_change_wheel_by_1: '', ALBERT_change_wheel_by_2: '바퀴', ALBERT_change_wheel_by_3: '만큼 바꾸기', ALBERT_set_wheel_to_1: '', ALBERT_set_wheel_to_2: '바퀴', ALBERT_set_wheel_to_3: '(으)로 정하기', ALBERT_stop: '정지하기', ALBERT_set_board_size_to_1: '말판 크기를 폭', ALBERT_set_board_size_to_2: '높이', ALBERT_set_board_size_to_3: '(으)로 정하기', ALBERT_move_to_x_y_1: '말판 x:', ALBERT_move_to_x_y_2: 'y:', ALBERT_move_to_x_y_3: '위치로 이동하기', ALBERT_set_orientation_to_1: '말판', ALBERT_set_orientation_to_2: '방향으로 바라보기', ALBERT_set_eye_to_1: '', ALBERT_set_eye_to_2: '눈을', ALBERT_set_eye_to_3: '으로 정하기', ALBERT_left_eye: '왼쪽', ALBERT_right_eye: '오른쪽', ALBERT_both_eyes: '양쪽', ALBERT_clear_eye_1: '', ALBERT_clear_eye_2: '눈 끄기', ALBERT_body_led_1: '몸통 LED', ALBERT_body_led_2: '', ALBERT_front_led_1: '앞쪽 LED', ALBERT_front_led_2: '', ALBERT_color_cyan: '하늘색', ALBERT_color_magenta: '보라색', ALBERT_color_white: '하얀색', ALBERT_color_red: '빨간색', ALBERT_color_yellow: '노란색', ALBERT_color_green: '초록색', ALBERT_color_blue: '파란색', ALBERT_note_c: '도', ALBERT_note_d: '레', ALBERT_note_e: '미', ALBERT_note_f: '파', ALBERT_note_g: '솔', ALBERT_note_a: '라', ALBERT_note_b: '시', ALBERT_turn_body_led_1: '몸통 LED', ALBERT_turn_body_led_2: '', ALBERT_turn_front_led_1: '앞쪽 LED', ALBERT_turn_front_led_2: '', ALBERT_turn_on: '켜기', ALBERT_turn_off: '끄기', ALBERT_beep: '삐 소리내기', ALBERT_change_buzzer_by_1: '버저 음을', ALBERT_change_buzzer_by_2: '만큼 바꾸기', ALBERT_set_buzzer_to_1: '버저 음을', ALBERT_set_buzzer_to_2: '(으)로 정하기', ALBERT_clear_buzzer: '버저 끄기', ALBERT_play_note_for_1: '', ALBERT_play_note_for_2: '', ALBERT_play_note_for_3: '음을', ALBERT_play_note_for_4: '박자 연주하기', ALBERT_rest_for_1: '', ALBERT_rest_for_2: '박자 쉬기', ALBERT_change_tempo_by_1: '연주 속도를', ALBERT_change_tempo_by_2: '만큼 바꾸기', ALBERT_set_tempo_to_1: '연주 속도를 분당', ALBERT_set_tempo_to_2: '박자로 정하기', VARIABLE_variable: '변수', wall: '벽', robotis_common_case_01: '(을)를', robotis_common_set: '(으)로 정하기', robotis_common_value: '값', robotis_common_clockwhise: '시계방향', robotis_common_counter_clockwhise: '반시계방향', robotis_common_wheel_mode: '회전모드', robotis_common_joint_mode: '관절모드', robotis_common_red_color: '빨간색', robotis_common_green_color: '녹색', robotis_common_blue_color: '파란색', robotis_common_on: '켜기', robotis_common_off: '끄기', robotis_common_cm: '제어기', robotis_common_port_1: '포트 1', robotis_common_port_2: '포트 2', robotis_common_port_3: '포트 3', robotis_common_port_4: '포트 4', robotis_common_port_5: '포트 5', robotis_common_port_6: '포트 6', robotis_common_play_buzzer: '연주', robotis_common_play_motion: '실행', robotis_common_motion: '모션', robotis_common_index_number: '번', robotis_common_left: '왼쪽', robotis_common_right: '오른쪽', robotis_common_minute: '분', robotis_cm_custom: '직접입력 주소', robotis_cm_spring_left: '왼쪽 접촉 센서', robotis_cm_spring_right: '오른쪽 접촉 센서', robotis_cm_led_left: '왼쪽 LED', robotis_cm_led_right: '오른쪽 LED', robotis_cm_led_both: '양 쪽 LED', robotis_cm_switch: '선택 버튼 상태', robotis_cm_user_button: '사용자 버튼 상태', robotis_cm_sound_detected: '최종 소리 감지 횟수', robotis_cm_sound_detecting: '실시간 소리 감지 횟수', robotis_cm_ir_left: '왼쪽 적외선 센서', robotis_cm_ir_right: '오른쪽 적외선 센서', robotis_cm_calibration_left: '왼쪽 적외선 센서 캘리브레이션 값', robotis_cm_calibration_right: '오른쪽 적외선 센서 캘리브레이션 값', robotis_cm_clear_sound_detected: '최종소리감지횟수 초기화', robotis_cm_buzzer_index: '음계값', robotis_cm_buzzer_melody: '멜로디', robotis_cm_led_1: '1번 LED', robotis_cm_led_4: '4번 LED', robotis_aux_servo_position: '서보모터 위치', robotis_aux_ir: '적외선센서', robotis_aux_touch: '접촉센서', robotis_aux_brightness: '조도센서(CDS)', robotis_aux_hydro_themo_humidity: '온습도센서(습도)', robotis_aux_hydro_themo_temper: '온습도센서(온도)', robotis_aux_temperature: '온도센서', robotis_aux_ultrasonic: '초음파센서', robotis_aux_magnetic: '자석센서', robotis_aux_motion_detection: '동작감지센서', robotis_aux_color: '컬러센서', robotis_aux_custom: '사용자 장치', robotis_carCont_aux_motor_speed_1: '감속모터 속도를', robotis_carCont_aux_motor_speed_2: ', 출력값을', robotis_carCont_calibration_1: '적외선 센서 캘리브레이션 값을', robotis_openCM70_aux_motor_speed_1: '감속모터 속도를', robotis_openCM70_aux_motor_speed_2: ', 출력값을', robotis_openCM70_aux_servo_mode_1: '서보모터 모드를', robotis_openCM70_aux_servo_speed_1: '서보모터 속도를', robotis_openCM70_aux_servo_speed_2: ', 출력값을', robotis_openCM70_aux_servo_position_1: '서보모터 위치를', robotis_openCM70_aux_led_module_1: 'LED 모듈을', robotis_openCM70_aux_custom_1: '사용자 장치를', XBOT_digital: '디지털', XBOT_D2_digitalInput: 'D2 디지털 입력', XBOT_D3_digitalInput: 'D3 디지털 입력', XBOT_D11_digitalInput: 'D11 디지털 입력', XBOT_analog: '아날로그', XBOT_CDS: '광 센서 값', XBOT_MIC: '마이크 센서 값', XBOT_analog0: '아날로그 0번 핀 값', XBOT_analog1: '아날로그 1번 핀 값', XBOT_analog2: '아날로그 2번 핀 값', XBOT_analog3: '아날로그 3번 핀 값', XBOT_Value: '출력 값', XBOT_pin_OutputValue: '핀, 출력 값', XBOT_High: '높음', XBOT_Low: '낮음', XBOT_Servo: '서보 모터', XBOT_Head: '머리(D8)', XBOT_ArmR: '오른 팔(D9)', XBOT_ArmL: '왼 팔(D10)', XBOT_angle: ', 각도', XBOT_DC: '바퀴(DC) 모터', XBOT_rightWheel: '오른쪽', XBOT_leftWheel: '왼쪽', XBOT_bothWheel: '양쪽', XBOT_speed: ', 속도', XBOT_rightSpeed: '바퀴(DC) 모터 오른쪽(2) 속도:', XBOT_leftSpeed: '왼쪽(1) 속도:', XBOT_RGBLED_R: 'RGB LED 켜기 R 값', XBOT_RGBLED_G: 'G 값', XBOT_RGBLED_B: 'B 값', XBOT_RGBLED_color: 'RGB LED 색', XBOT_set: '로 정하기', XBOT_c: '도', XBOT_d: '레', XBOT_e: '미', XBOT_f: '파', XBOT_g: '솔', XBOT_a: '라', XBOT_b: '시', XBOT_melody_ms: '초 연주하기', XBOT_Line: '번째 줄', XBOT_outputValue: '출력 값', roborobo_num_analog_value_1: '아날로그', roborobo_num_analog_value_2: '번 센서값', roborobo_get_digital_value_1: '디지털', roborobo_num_pin_1: '디지털', roborobo_num_pin_2: '번 핀', roborobo_on: '켜기', roborobo_off: '끄기', roborobo_motor1: '모터1', roborobo_motor2: '모터2', roborobo_motor_CW: '정회전', roborobo_motor_CCW: '역회전', roborobo_motor_stop: '정지', roborobo_input_mode: '입력', roborobo_output_mode: '출력', roborobo_pwm_mode: '전류조절(pwm)', roborobo_servo_mode: '서보모터', roborobo_color: '컬러센서', roborobo_color_red: ' 빨간색 ', roborobo_color_green: ' 녹색 ', roborobo_color_blue: ' 파란색 ', roborobo_color_yellow: ' 노란색 ', roborobo_color_detected: ' 감지 ', roborobo_degree: ' ˚', robotori_D2_Input: '디지털 2번 핀 입력 값', robotori_D3_Input: '디지털 3번 핀 입력 값', robotori_A0_Input: '아날로그 0번 핀 입력 값', robotori_A1_Input: '아날로그 1번 핀 입력 값', robotori_A2_Input: '아날로그 2번 핀 입력 값', robotori_A3_Input: '아날로그 3번 핀 입력 값', robotori_A4_Input: '아날로그 4번 핀 입력 값', robotori_A5_Input: '아날로그 5번 핀 입력 값', robotori_digital: '디지털', robotori_D10_Output: '10번', robotori_D11_Output: '11번', robotori_D12_Output: '12번', robotori_D13_Output: '13번', robotori_pin_OutputValue: '핀, 출력 값', robotori_On: '켜짐', robotori_Off: '꺼짐', robotori_analog: '아날로그', robotori_analog5: '5번 핀 출력 값', robotori_analog6: '6번 핀 출력 값', robotori_analog9: '9번 핀 출력 값', robotori_Servo: '서보모터', robotori_DC: 'DC모터', robotori_DC_rightmotor: '오른쪽', robotori_DC_leftmotor: '왼쪽', robotori_DC_STOP: '정지', robotori_DC_CW: '시계방향', robotori_DC_CCW: '반시계방향', robotori_DC_select: '회전', CALC_rotation_value: '방향값', CALC_direction_value: '이동 방향값', VARIABLE_is_included_in_list: '리스트에 포함되어 있는가?', VARIABLE_is_included_in_list_1: '', VARIABLE_is_included_in_list_2: '에', VARIABLE_is_included_in_list_3: '이 포함되어 있는가?', SCENE_when_scene_start: '장면이 시작되었을 때', SCENE_start_scene_1: '', SCENE_start_scene_2: '시작하기', SCENE_start_neighbor_scene_1: '', SCENE_start_neighbor_scene_2: '장면 시작하기', SCENE_start_scene_pre: '이전', SCENE_start_scene_next: '다음', FUNCTION_explanation_1: '이름', FUNCTION_character_variable: '문자/숫자값', FUNCTION_logical_variable: '판단값', FUNCTION_function: '함수', FUNCTION_define: '함수 정의하기', CALC_calc_operation_sin: '사인', CALC_calc_operation_cos: '코사인', CALC_calc_operation_tan: '탄젠트', CALC_calc_operation_asin: '아크사인', CALC_calc_operation_acos: '아크코사인', CALC_calc_operation_atan: '아크탄젠트', CALC_calc_operation_log: '로그', CALC_calc_operation_ln: '자연로그', CALC_calc_operation_natural: '정수 부분', CALC_calc_operation_unnatural: '소수점 부분', CALC_calc_operation_floor: '소수점 버림값', CALC_calc_operation_ceil: '소수점 올림값', CALC_calc_operation_round: '소수점 반올림값', CALC_calc_operation_factorial: '팩토리얼', CALC_calc_operation_abs: '절댓값', MOVING_locate_object_time_1: '', MOVING_locate_object_time_2: '초 동안', MOVING_locate_object_time_3: '위치로 이동하기', wall_up: '위쪽 벽', wall_down: '아래쪽 벽', wall_right: '오른쪽 벽', wall_left: '왼쪽 벽', CALC_coordinate_x_value: 'x 좌푯값', CALC_coordinate_y_value: 'y 좌푯값', CALC_coordinate_rotation_value: '방향', CALC_coordinate_direction_value: '이동방향', CALC_picture_index: '모양 번호', CALC_picture_name: '모양 이름', FLOW_repeat_while_true_1: '', FLOW_repeat_while_true_2: ' 반복하기', TUT_when_start: '프로그램 실행을 클릭했을때', TUT_move_once: '앞으로 한 칸 이동', TUT_rotate_left: '왼쪽으로 회전', TUT_rotate_right: '오른쪽으로 회전', TUT_jump_barrier: '장애물 뛰어넘기', TUT_repeat_tutorial_1: '', TUT_repeat_tutorial_2: '번 반복', TUT_if_barrier_1: '만약 앞에', TUT_if_barrier_2: ' 이 있다면', TUT_if_conical_1: '만약 앞에', TUT_if_conical_2: ' 이 있다면', TUT_repeat_until: '부품에 도달할 때 까지 반복', TUT_repeat_until_gold: '부품에 도달할 때 까지 반복', TUT_declare_function: '함수 선언', TUT_call_function: '함수 호출', AI_analyze_option: 'AI로 코드 분석하기', CONTEXT_COPY_option: '코드 복사하기', Delete_Blocks: '코드 삭제하기', Duplication_option: '코드 복제하기', cut_blocks: '코드 잘라내기', Paste_blocks: '붙여넣기', add_my_storage: '나의 보관함에 추가하기', export_object: '오브젝트 파일로 내보내기', Clear_all_blocks: '모든 코드 삭제하기', add_comment: '메모 추가하기', copy_paste_comment: '메모 복사 & 붙여넣기', copy_comment: '메모 복사하기', delete_comment: '메모 삭제하기', fold_comment: '메모 접기', open_comment: '메모 열기', separate_comment: '메모 분리하기', hide_all_comment: '모든 메모 숨기기', show_all_comment: '모든 메모 보이기', transparency: '투명도', BRUSH_change_brush_transparency_1: '붓의 투명도를', BRUSH_change_brush_transparency_2: '% 만큼 바꾸기', BRUSH_set_brush_transparency_1: '붓의 투명도를', BRUSH_set_brush_transparency_2: '% 로 정하기', CALC_char_at_1: '', CALC_char_at_2: '의', CALC_char_at_3: '번째 글자', CALC_length_of_string_1: '', CALC_length_of_string_2: '의 글자 수', CALC_reverse_of_string_1: '', CALC_reverse_of_string_2: '을(를) 뒤집은 값', CALC_substring_1: '', CALC_substring_2: '의', CALC_substring_3: '번째 글자부터', length_of_string: '번째 글자부터', CALC_substring_4: '번째 글자까지의 글자', CALC_replace_string_1: '', CALC_replace_string_2: '의', CALC_replace_string_3: '을(를)', CALC_replace_string_4: '(으)로 바꾼 값', CALC_change_string_case_1: '을(를)', CALC_change_string_case_2: '로 바꾼 값', CALC_change_string_case_sub_1: '대문자', CALC_change_string_case_sub_2: '소문자', CALC_count_match_string_1: '에서', CALC_count_match_string_2: '의 글자 수', CALC_index_of_string_1: '', CALC_index_of_string_2: '에서', CALC_index_of_string_3: '의 시작 위치', MOVING_add_direction_by_angle_time_explain_1: '', MOVING_direction_relative_duration_1: '', MOVING_direction_relative_duration_2: '초 동안 이동 방향', MOVING_direction_relative_duration_3: '만큼 회전하기', CALC_get_sound_volume: ' 소리 크기', SOUND_sound_from_to_1: '소리', SOUND_sound_from_to_2: '', SOUND_sound_from_to_3: '초 부터', SOUND_sound_from_to_4: '초까지 재생하기', SOUND_sound_from_to_and_wait_1: '소리', SOUND_sound_from_to_and_wait_2: '', SOUND_sound_from_to_and_wait_3: '초 부터', SOUND_sound_from_to_and_wait_4: '초까지 재생하고 기다리기', CALC_quotient_and_mod_1: '', CALC_quotient_and_mod_2: '/', CALC_quotient_and_mod_3: '의', CALC_quotient_and_mod_4: '', CALC_quotient_and_mod_sub_1: '몫', CALC_quotient_and_mod_sub_2: '나머지', self: '자신', CALC_coordinate_size_value: '크기', CALC_choose_project_timer_action_1: '초시계', CALC_choose_project_timer_action_2: '', CALC_choose_project_timer_action_sub_1: '시작하기', CALC_choose_project_timer_action_sub_2: '정지하기', CALC_choose_project_timer_action_sub_3: '초기화하기', LOOKS_change_object_index_1: '', LOOKS_change_object_index_2: '보내기', LOOKS_change_object_index_sub_1: '맨 앞으로', LOOKS_change_object_index_sub_2: '앞으로', LOOKS_change_object_index_sub_3: '뒤로', LOOKS_change_object_index_sub_4: '맨 뒤로', FLOW_repeat_while_true_until: '이 될 때까지', FLOW_repeat_while_true_while: '인 동안', copy_block: '블록 복사', delete_block: '블록 삭제', tidy_up_block: '코드 정리하기', block_hi: '안녕!', entry_bot_name: '엔트리봇', hi_entry: '안녕 엔트리!', hi_entry_en: 'Hello Entry!', bark_dog: '강아지 짖는 소리', walking_entryBot: '엔트리봇_걷기', doggi_bark: '강아지 짖는 소리', entry: '엔트리', hello: '안녕', nice: '반가워', silent: '무음', do_name: '도', do_sharp_name: '도#(레♭)', re_name: '레', re_sharp_name: '레#(미♭)', mi_name: '미', fa_name: '파', fa_sharp_name: '파#(솔♭)', sol_name: '솔', sol_sharp_name: '솔#(라♭)', la_name: '라', la_sharp_name: '라#(시♭)', DUMMY: '더미', coconut_stop_motor: '모터 정지', coconut_move_motor: '움직이기', coconut_turn_motor: '으로 돌기', coconut_move_outmotor: '외부모터', coconut_turn_left: '왼쪽', coconut_turn_right: '오른쪽', coconut_move_forward: '앞으로', coconut_move_backward: '뒤로', coconut_note_c: '도', coconut_note_d: '레', coconut_note_e: '미', coconut_note_f: '파', coconut_note_g: '솔', coconut_note_a: '라', coconut_note_b: '시', coconut_move_speed_1: '0', coconut_move_speed_2: '50', coconut_move_speed_3: '100', coconut_move_speed_4: '150', coconut_move_speed_5: '255', coconut_play_buzzer_hn: '2분음표', coconut_play_buzzer_qn: '4분음표', coconut_play_buzzer_en: '8분음표', coconut_play_buzzer_sn: '16분음표', coconut_play_buzzer_tn: '32분음표', coconut_play_buzzer_wn: '온음표', coconut_play_buzzer_dhn: '점2분음표', coconut_play_buzzer_dqn: '점4분음표', coconut_play_buzzer_den: '점8분음표', coconut_play_buzzer_dsn: '점16분음표', coconut_play_buzzer_dtn: '점32분음표', coconut_rest_buzzer_hr: '2분쉼표', coconut_rest_buzzer_qr: '4분쉼표', coconut_rest_buzzer_er: '8분쉼표', coconut_rest_buzzer_sr: '16분쉼표', coconut_rest_buzzer_tr: '32분쉼표', coconut_rest_buzzer_wr: '온쉼표', coconut_play_midi_1: '반짝반짝 작은별', coconut_play_midi_2: '곰세마리', coconut_play_midi_3: '모차르트 자장가', coconut_play_midi_4: '도레미송', coconut_play_midi_5: '나비야', coconut_floor_sensing_on: '감지', coconut_floor_sensing_off: '미감지', coconut_dotmatrix_set_on: '켜짐', coconut_dotmatrix_set_off: '꺼짐', coconut_dotmatrix_row_0: '모든', coconut_dotmatrix_row_1: '1', coconut_dotmatrix_row_2: '2', coconut_dotmatrix_row_3: '3', coconut_dotmatrix_row_4: '4', coconut_dotmatrix_row_5: '5', coconut_dotmatrix_row_6: '6', coconut_dotmatrix_row_7: '7', coconut_dotmatrix_row_8: '8', coconut_dotmatrix_col_0: '모든', coconut_dotmatrix_col_1: '1', coconut_dotmatrix_col_2: '2', coconut_dotmatrix_col_3: '3', coconut_dotmatrix_col_4: '4', coconut_dotmatrix_col_5: '5', coconut_dotmatrix_col_6: '6', coconut_dotmatrix_col_7: '7', coconut_dotmatrix_col_8: '8', coconut_sensor_left_proximity: '왼쪽 전방 센서', coconut_sensor_right_proximity: '오른쪽 전방 센서', coconut_sensor_both_proximity: '모든', coconut_sensor_left_floor: '왼쪽 바닥센서', coconut_sensor_right_floor: '오른쪽 바닥 센서', coconut_sensor_both_floor: '모든', coconut_sensor_acceleration_x: 'x축 가속도', coconut_sensor_acceleration_y: 'y축 가속도', coconut_sensor_acceleration_z: 'z축 가속도', coconut_sensor_light: '밝기', coconut_sensor_temperature: '온도', coconut_left_led: '왼쪽', coconut_right_led: '오른쪽', coconut_both_leds: '모든', coconut_color_cyan: '하늘색', coconut_color_magenta: '보라색', coconut_color_black: '검은색', coconut_color_white: '흰색', coconut_color_red: '빨간색', coconut_color_yellow: '노란색', coconut_color_green: '초록색', coconut_color_blue: '파란색', coconut_beep: '삐 소리내기', coconut_clear_buzzer: '버저 끄기', coconut_x_axis: 'X축', coconut_y_axis: 'Y축', coconut_z_axis: 'Z축', modi_enviroment_bule: '파랑', modi_enviroment_green: '초록', modi_enviroment_humidity: '습도', modi_enviroment_illuminance: '조도', modi_enviroment_red: '빨강', modi_enviroment_temperature: '온도', modi_gyroscope_xAcceleratior: 'X축 가속', modi_gyroscope_yAcceleratior: 'Y축 가속', modi_gyroscope_zAcceleratior: 'Z축 가속', modi_motor_angle: '각도', modi_motor_speed: '속도', modi_motor_torque: '회전', modi_speaker_F_DO_5: '도5', modi_speaker_F_DO_6: '도6', modi_speaker_F_DO_7: '도7', modi_speaker_F_DO_S_5: '도#5', modi_speaker_F_DO_S_6: '도#6', modi_speaker_F_DO_S_7: '도#7', modi_speaker_F_MI_5: '미5', modi_speaker_F_MI_6: '미6', modi_speaker_F_MI_7: '미7', modi_speaker_F_PA_5: '파5', modi_speaker_F_PA_6: '파6', modi_speaker_F_PA_7: '파7', modi_speaker_F_PA_S_5: '파#5', modi_speaker_F_PA_S_6: '파#6', modi_speaker_F_PA_S_7: '파#7', modi_speaker_F_RA_5: '라5', modi_speaker_F_RA_6: '라6', modi_speaker_F_RA_7: '라7', modi_speaker_F_RA_S_5: '라#5', modi_speaker_F_RA_S_6: '라#6', modi_speaker_F_RA_S_7: '라#7', modi_speaker_F_RE_5: '레5', modi_speaker_F_RE_6: '레6', modi_speaker_F_RE_7: '레7', modi_speaker_F_RE_S_5: '라#5', modi_speaker_F_RE_S_6: '레#6', modi_speaker_F_RE_S_7: '레#7', modi_speaker_F_SOL_5: '솔5', modi_speaker_F_SOL_6: '솔6', modi_speaker_F_SOL_7: '솔7', modi_speaker_F_SOL_S_5: '솔#5', modi_speaker_F_SOL_S_6: '솔#6', modi_speaker_F_SOL_S_7: '솔#7', modi_speaker_F_SO_5: '시5', modi_speaker_F_SO_6: '시6', modi_speaker_F_SO_7: '시7', si_name: '시', ev3_ccw: '반시계', ev3_cw: '시계', rokoboard_sensor_name_0: '소리', rokoboard_sensor_name_1: '빛', rokoboard_sensor_name_2: '슬라이더', rokoboard_sensor_name_3: '저항-A', rokoboard_sensor_name_4: '저항-B', rokoboard_sensor_name_5: '저항-C', rokoboard_sensor_name_6: '저항-D', rokoboard_string_1: '버튼을 눌렀는가?', HW_MOTOR: '모터', HW_SENSOR: '센서', HW_LED: '발광다이오드', HW_MELODY: '멜로디', HW_ROBOT: '로봇', ALTINO_ACCX: '가속도 X축', ALTINO_ACCY: '가속도 Y축', ALTINO_ACCZ: '가속도 Z축', ALTINO_BAT: '배터리 잔량 체크', ALTINO_CDS: '밝기', ALTINO_GYROX: '자이로 X축', ALTINO_GYROY: '자이로 Y축', ALTINO_GYROZ: '자이로 Z축', ALTINO_IR1: '1번 거리', ALTINO_IR2: '2번 거리', ALTINO_IR3: '3번 거리', ALTINO_IR4: '4번 거리', ALTINO_IR5: '5번 거리', ALTINO_IR6: '6번 거리', ALTINO_Led_Brake_Light: '브레이크', ALTINO_Led_Forward_Light: '전방', ALTINO_Led_Reverse_Light: '후방', ALTINO_Led_Turn_Left_Light: '왼쪽방향', ALTINO_Led_Turn_Right_Light: '오른쪽방향', ALTINO_Line: '번째 줄', ALTINO_MAGX: '나침판 X축', ALTINO_MAGY: '나침판 Y축', ALTINO_MAGZ: '나침판 Z축', ALTINO_REMOTE: '리모콘 수신 값', ALTINO_STTOR: '조향 토크', ALTINO_STVAR: '조향 가변저항', ALTINO_Steering_Angle_Center: '가운데', ALTINO_Steering_Angle_Left10: '왼쪽10', ALTINO_Steering_Angle_Left15: '왼쪽15', ALTINO_Steering_Angle_Left20: '왼쪽20', ALTINO_Steering_Angle_Left5: '왼쪽5', ALTINO_Steering_Angle_Right10: '오른쪽10', ALTINO_Steering_Angle_Right15: '오른쪽15', ALTINO_Steering_Angle_Right20: '오른쪽20', ALTINO_Steering_Angle_Right5: '오른쪽5', ALTINO_TEM: '온도', ALTINO_TOR1: '오른쪽 토크', ALTINO_TOR2: '왼쪽 토크', ALTINO_Value: '출력 값', ALTINO_a: '라', ALTINO_a2: '라#', ALTINO_b: '시', ALTINO_c: '도', ALTINO_c2: '도#', ALTINO_d: '레', ALTINO_d2: '레#', ALTINO_dot_display_1: '한문자', ALTINO_dot_display_2: '출력하기', ALTINO_e: '미', ALTINO_f: '파', ALTINO_f2: '파#', ALTINO_g: '솔', ALTINO_g2: '솔#', ALTINO_h: '끄기', ALTINO_h2: '켜기', ALTINO_leftWheel: '왼쪽', ALTINO_melody_ms: '연주하기', ALTINO_outputValue: '출력 값', ALTINO_rightWheel: '오른쪽', ALTINO_set: '로 정하기', ardublock_motor_forward: '앞', ardublock_motor_backward: '뒤', jdkit_clockwise: '시계방향', jdkit_counterclockwise: '반시계방향', jdkit_gyro_frontrear: '앞뒤', jdkit_gyro_leftright: '좌우', jdkit_joystick_leftleftright: '왼쪽 좌우', jdkit_joystick_lefttopbottom: '왼쪽 상하', jdkit_joystick_rightleftright: '오른쪽 좌우', jdkit_joystick_righttopbottom: '오른쪽 상하', jdkit_led: 'LED', jdkit_led_color_green: '초록색', jdkit_led_color_orange: '오랜지색', jdkit_led_turnoff: '끄기', jdkit_led_turnon: '켜기', jdkit_motor_leftbottom: '왼쪽아래', jdkit_motor_lefttop: '왼쪽위', jdkit_motor_rightbottom: '오른쪽아래', jdkit_motor_righttop: '오른쪽위', jdkit_tune_do: '도', jdkit_tune_fa: '파', jdkit_tune_la: '라', jdkit_tune_mi: '미', jdkit_tune_re: '레', jdkit_tune_si: '시', jdkit_tune_sol: '솔', FUNBOARD_bt_down: '노랑(B)', FUNBOARD_bt_left: '초록(C)', FUNBOARD_bt_right: '파랑(D)', FUNBOARD_bt_up: '빨강(A)', FUNBOARD_column_tag: '칸', FUNBOARD_do_off: '끄기', FUNBOARD_do_on: '켜기', FUNBOARD_led_color_all: '모두', FUNBOARD_led_color_blue: '파랑', FUNBOARD_led_color_green: '초록', FUNBOARD_led_color_red: '빨강', FUNBOARD_led_color_str: '색', FUNBOARD_led_color_yellow: '노랑', FUNBOARD_led_off_str: 'LED 끄기', FUNBOARD_led_on_str: 'LED 켜기', FUNBOARD_row_tag: '줄', FUNBOARD_scroll_down: '아래쪽으로', FUNBOARD_scroll_left: '왼쪽으로', FUNBOARD_scroll_no: '없음', FUNBOARD_scroll_right: '오른쪽으로', FUNBOARD_scroll_up: '위쪽으로', FUNBOARD_sensor_cds: 'Cds (밝기 감지)', FUNBOARD_sensor_mic: '마이크 (소리 감지)', FUNBOARD_sensor_slide: '슬라이드 (막대 조정)', FUNBOARD_sensor_state_1: '작다', FUNBOARD_sensor_state_2: '크다', FUNBOARD_touchbt_down: '노랑(B)', FUNBOARD_touchbt_enter: ' F', FUNBOARD_touchbt_escape: ' G', FUNBOARD_touchbt_left: '초록(C)', FUNBOARD_touchbt_right: '파랑(D)', FUNBOARD_touchbt_space: ' E', FUNBOARD_touchbt_up: '빨강(A)', funboard_dotmatrix_set_off: '끄기', funboard_dotmatrix_set_on: '켜기', AI_UTILIZE: '인공지능', video_show_video: '보이기', video_hide_video: '숨기기', video_brightness: '밝기', video_transparency: '투명도', video_left_right: '좌우', video_top_bottom: '상하', video_human: '사람', video_face: '얼굴', video_object: '사물', video_pose_model: '사람 모델', video_face_model: '얼굴 모델', video_object_model: '사물 모델', video_start: '시작하기', video_end: '중지하기', video_gender: '성별', video_age: '나이', video_emotion: '감정', video_motion_onself: '자신', video_motion_onscreen: '실행 화면', video_motion_scale: '움직임', video_motion_direction_horizontal: '좌우방향', video_motion_direction_vertical: '상하방향', table_row: '행', table_col: '열', table_sum: '합', table_max: '최대', table_min: '최소', table_avg: '평균', table_stdev: '표준편차', table_median: '중앙값', this_project: '모든', this_object: '자신', right_hand: '오른손', left_hand: '왼손', thumb: '엄지', index_finger: '검지', middle_finger: '중지', ring_finger: '약지', little_finger: '소지', wrist: '손목', tip: '끝', dip: '첫째 마디', pip: '둘째 마디', none: '없음', media_pipe_title_text: '비디오 감지', pose_landmarker_title_text: '사람 인식', face_landmarker_title_text: '얼굴 인식', object_detector_title_text: '사물 인식', hand_detection_title_text: '손 인식', unknown: '알 수 없음', CALC_timer_visible_2: '', SCENE_start_scene_1: '', SCENE_start_neighbor_scene_1: '', yell: '외치기', JUDGEMENT_reach_something_1: '', JUDGEMENT_boolean_not_1: '', is_type_en: '영문', is_type_ko: '한글', CALC_calc_rand_1: '', CALC_coordinate_object_1: '', CALC_quotient_and_mod_1: '', CALC_calc_operation_of_1: '', CALC_choose_project_timer_action_2: '', CALC_get_date_2: '', CALC_distance_something_1: '', CALC_get_sound_duration_1: '', CALC_length_of_string_1: '', CALC_reverse_of_string_1: '', VARIABLE_combine_something_1: '', CALC_char_at_1: '', CALC_substring_1: '', CALC_index_of_string_1: '', CALC_replace_string_1: '', CALC_change_string_case_1: '', VARIABLE_value_of_index_from_list_1: '', VARIABLE_length_of_list_1: '', VARIABLE_is_included_in_list_1: '', tts_sabina: '마녀', tts_mammon: '악마', tts_kitty: '야옹이', tts_doggy: '멍멍이', location_entire: '전체', location_seoul: '서울', location_seoul_jongno_gu: '종로구', location_seoul_jung_gu: '중구', location_seoul_yongsan_gu: '용산구', location_seoul_seongdong_gu: '성동구', location_seoul_gwangjin_gu: '광진구', location_seoul_dongdaemun_gu: '동대문구', location_seoul_jungnang_gu: '중랑구', location_seoul_seongbuk_gu: '성북구', location_seoul_gangbuk_gu: '강북구', location_seoul_dobong_gu: '도봉구', location_seoul_nowon_gu: '노원구', location_seoul_eunpyeong_gu: '은평구', location_seoul_seodaemun_gu: '서대문구', location_seoul_mapo_gu: '마포구', location_seoul_yangcheon_gu: '양천구', location_seoul_gangseo_gu: '강서구', location_seoul_guro_gu: '구로구', location_seoul_geumcheon_gu: '금천구', location_seoul_yeongdeungpo_gu: '영등포구', location_seoul_dongjak_gu: '동작구', location_seoul_gwanak_gu: '관악구', location_seoul_seocho_gu: '서초구', location_seoul_gangnam_gu: '강남구', location_seoul_songpa_gu: '송파구', location_seoul_gangdong_gu: '강동구', location_gangwon: '강원', location_gangwon_chuncheon: '춘천시', location_gangwon_wonju: '원주시', location_gangwon_gangneung_si: '강릉시', location_gangwon_donghae: '동해시', location_gangwon_taebaek_si: '태백시', location_gangwon_sokcho: '속초시', location_gangwon_samcheok_si: '삼척시', location_gangwon_hongcheon: '홍천군', location_gangwon_hoengseong_gun: '횡성군', location_gangwon_yeongwol_gun: '영월군', location_gangwon_pyeongchang: '평창군', location_gangwon_jeongseon: '정선군', location_gangwon_cheolwon: '철원군', location_gangwon_hwacheon: '화천군', location_gangwon_yanggu: '양구군', location_gangwon_inje: '인제군', location_gangwon_goseong: '고성군', location_gangwon_yangyang: '양양군', location_gyeonggi: '경기', location_gyeonggi_suwon_si: '수원시', location_gyeonggi_seongnam: '성남시', location_gyeonggi_uijeongbu: '의정부시', location_gyeonggi_anyang_si: '안양시', location_gyeonggi_bucheon_si: '부천시', location_gyeonggi_gwangmyeong_si: '광명시', location_gyeonggi_pyeongtaek_si: '평택시', location_gyeonggi_dongducheon_si: '동두천시', location_gyeonggi_ansan_si: '안산시', location_gyeonggi_goyang_si: '고양시', location_gyeonggi_gwacheon_si: '과천시', location_gyeonggi_guri: '구리시', location_gyeonggi_namyangju_si: '남양주시', location_gyeonggi_osan: '오산시', location_jeollanam_goheung: '고흥군', location_gyeonggi_siheung: '시흥시', location_jeollanam_boseong: '보성군', location_jeollanam_hwasun: '화순군', location_gyeonggi_gunpo_si: '군포시', location_jeollanam_jangheung: '장흥군', location_gyeonggi_uiwang_si: '의왕시', location_jeollanam_gangjin: '강진군', location_gyeonggi_hanam: '하남시', location_jeollanam_haenam: '해남군', location_gyeonggi_yongin_si: '용인시', location_jeollanam_yeongam: '영암군', location_gyeonggi_paju: '파주시', location_jeollanam_jindo: '무안군', location_gyeonggi_icheon: '이천시', location_jeollanam_muan: '함평군', location_jeollanam_hampyeong: '영광군', location_gyeonggi_anseong_si: '안성시', location_jeollanam_yeonggwang: '장성군', location_gyeonggi_gimpo: '김포시', location_jeollanam_jangseong: '완도군', location_gyeonggi_hwaseong_si: '화성시', location_jeollanam_wando: '진도군', location_gyeonggi_gwangju: '광주시', location_jeollanam_sinan: '신안군', location_jeollabuk: '전북', location_gyeonggi_yangju_si: '양주시', location_jeollabuk_jeonju: '전주시', location_gyeonggi_pocheon: '포천시', location_jeollabuk_gunsan_si: '군산시', location_gyeonggi_yeoju: '여주시', location_jeollabuk_iksan: '익산시', location_gyeonggi_yeoncheon_gun: '연천군', location_gyeonggi_gapyeong_gun: '가평군', location_jeollabuk_jeongeup: '정읍시', location_gyeonggi_yangpyeong: '양평군', location_jeollabuk_namwon: '남원시', location_gyeongsangnam: '경남', location_jeollabuk_gimje_si: '김제시', location_gyeongsangnam_changwon_si: '창원시', location_jeollabuk_wanju: '완주군', location_gyeongsangnam_jinju: '진주시', location_jeollabuk_jinan: '진안군', location_gyeongsangnam_tongyeong_si: '통영시', location_jeollabuk_muju: '무주군', location_gyeongsangnam_sacheon_si: '사천시', location_jeollabuk_jangsu: '장수군', location_gyeongsangnam_gimhae_si: '김해시', location_jeollabuk_imsil: '임실군', location_gyeongsangnam_miryang_si: '밀양시', location_jeollabuk_sunchang: '순창군', location_gyeongsangnam_geoje_si: '거제시', location_jeollabuk_gochang: '고창군', location_gyeongsangnam_yangsan_si: '양산시', location_jeollabuk_buan: '부안군', location_gyeongsangnam_uiryeong: '의령군', location_jeju: '제주', location_gyeongsangnam_haman: '함안군', location_jeju_jeju_si: '제주시', location_gyeongsangnam_changnyeong: '창녕군', location_jeju_seogwipo: '서귀포시', location_gyeongsangnam_goseong: '고성군', location_gyeongsangnam_namhae: '남해군', location_chungcheongnam: '충남', location_gyeongsangnam_hadong: '하동군', location_chungcheongnam_cheonan: '천안시', location_gyeongsangnam_sancheong: '산청군', location_chungcheongnam_gongju: '공주시', location_gyeongsangnam_hamyang: '함양군', location_gyeongsangnam_geochang: '거창군', location_chungcheongnam_boryeong: '보령시', location_gyeongsangnam_hapcheon: '합천군', location_chungcheongnam_asan: '아산시', location_gyeongsangbuk: '경북', location_chungcheongnam_seosan: '서산시', location_gyeongsangbuk_pohang_si: '포항시', location_gyeongsangbuk_gyeongju_si: '경주시', location_chungcheongnam_nonsan: '논산시', location_gyeongsangbuk_gimcheon_si: '김천시', location_chungcheongnam_gyeryong: '계룡시', location_gyeongsangbuk_andong_si: '안동시', location_chungcheongnam_dangjin: '당진시', location_gyeongsangbuk_gumi_si: '구미시', location_gyeongsangbuk_yeongju_si: '영주시', location_chungcheongnam_geumsan: '금산군', location_chungcheongnam_buyeo: '부여군', location_gyeongsangbuk_yeongcheon_si: '영천시', location_chungcheongnam_seocheon: '서천군', location_gyeongsangbuk_sangju_si: '상주시', location_chungcheongnam_cheongyang: '청양군', location_gyeongsangbuk_mungyeong_si: '문경시', location_gyeongsangbuk_gyeongsan_si: '경산시', location_chungcheongnam_hongseong: '홍성군', location_chungcheongnam_yesan: '예산군', location_gyeongsangbuk_uiseong: '의성군', location_chungcheongnam_taean: '태안군', location_gyeongsangbuk_cheongsong: '청송군', location_chungcheongbuk: '충북', location_gyeongsangbuk_goryong: '영양군', location_chungcheongbuk_cheongju: '청주시', location_gyeongsangbuk_yeongdeok: '영덕군', location_gyeongsangbuk_cheongdo: '청도군', location_chungcheongbuk_chungju: '충주시', location_gyeongsangbuk_golyeong: '고령군', location_chungcheongbuk_jecheon: '제천시', location_gyeongsangbuk_seongju: '성주군', location_chungcheongbuk_boeun: '보은군', location_gyeongsangbuk_chilgok: '칠곡군', location_chungcheongbuk_okcheon: '옥천군', location_gyeongsangbuk_yecheon: '예천군', location_chungcheongbuk_yeongdong: '영동군', location_gyeongsangbuk_bonghwa: '봉화군', location_chungcheongbuk_jeungpyeong: '증평군', location_gyeongsangbuk_uljin: '울진군', location_chungcheongbuk_jincheon: '진천군', location_gyeongsangbuk_ulleung: '울릉군', location_chungcheongbuk_goesan: '괴산군', location_gwangju: '광주', location_chungcheongbuk_eumseong: '음성군', location_gwangju_dong_gu: '동구', location_chungcheongbuk_danyang: '단양군', location_gwangju_seo_gu: '서구', location_gwangju_nam_gu: '남구', location_gwangju_buk_gu: '북구', location_gwangju_gwangsan_gu: '광산구', location_daegu: '대구', location_daegu_jung_gu: '중구', location_daegu_dong_gu: '동구', location_daegu_seo_gu: '서구', location_daegu_nam_gu: '남구', location_daegu_buk_gu: '북구', location_daegu_suseong_gu: '수성구', location_daegu_dalseo_gu: '달서구', location_daegu_dalseong: '달성군', location_daegu_gunwi: '군위군', location_daejeon: '대전', location_daejeon_dong_gu: '동구', location_daejeon_jung_gu: '중구', location_daejeon_seo_gu: '서구', location_daejeon_yuseong_gu: '유성구', location_daejeon_daedeok_gu: '대덕구', location_busan: '부산', location_busan_jung_gu: '중구', location_busan_seo_gu: '서구', location_busan_dong_gu: '동구', location_busan_yeongdo_gu: '영도구', location_busan_busanjin_gu: '부산진구', location_busan_dongnae_gu: '동래구', location_busan_nam_gu: '남구', location_busan_buk_gu: '북구', location_busan_haeundae_gu: '해운대구', location_busan_saha_gu: '사하구', location_busan_geumjeong_gu: '금정구', location_busan_gangseo_gu: '강서구', location_busan_yeonje: '연제구', location_busan_suyeong_gu: '수영구', location_busan_sasang_gu: '사상구', location_busan_gijang: '기장군', location_sejong: '세종', location_ulsan: '울산', location_ulsan_jung_gu: '중구', location_ulsan_nam_gu: '남구', location_ulsan_dong_gu: '동구', location_ulsan_buk_gu: '북구', location_ulsan_ulju: '울주군', location_incheon: '인천', location_incheon_jung_gu: '중구', location_incheon_dong_gu: '동구', location_incheon_nam_gu: '미추홀구', location_incheon_yeonsu_gu: '연수구', location_incheon_namdong_gu: '남동구', location_incheon_bupyeong_gu: '부평구', location_incheon_gyeyang_gu: '계양구', location_incheon_seo_gu: '서구', location_incheon_ganghwa: '강화군', location_incheon_ongjin_gun: '옹진군', location_jeollanam: '전남', location_jeollanam_mokpo: '목포시', location_jeollanam_yosu: '여수시', location_jeollanam_suncheon_si: '순천시', location_jeollanam_naju: '나주시', location_jeollanam_gwangyang_si: '광양시', location_jeollanam_damyang: '담양군', location_jeollanam_gokseong: '곡성군', location_jeollanam_gurye: '구례군', width: '가로', height: '세로', desktop: '데스크톱', tablet: '태블릿', smartphone: '스마트폰', }; Lang.video_body_coord_params = { left_eye: '왼쪽 눈', right_eye: '오른쪽 눈', nose: '코', left_mouth: '왼쪽 입꼬리', right_mouth: '오른쪽 입꼬리', upper_lip: '윗 입술', lower_lip: '아랫 입술', face: '얼굴', neck: '목', left_ear: '왼쪽 귀', right_ear: '오른쪽 귀', left_shoulder: '왼쪽 어깨', left_elbow: '왼쪽 팔꿈치', left_wrist: '왼쪽 손목', left_hip: '왼쪽 엉덩이', left_knee: '왼쪽 무릎', left_ankle: '왼쪽 발목', right_shoulder: '오른쪽 어깨', right_elbow: '오른쪽 팔꿈치', right_wrist: '오른쪽 손목', right_hip: '오른쪽 엉덩이', right_knee: '오른쪽 무릎', right_ankle: '오른쪽 발목', }; Lang.video_gender = { male: '남성', female: '여성', }; Lang.video_emotion_params = { angry: '분노', disgusted: '혐오', fearful: '두려움', happy: '행복', neutral: '무표정', sad: '슬픔', surprised: '놀람', disgust: '혐오', fear: '두려움', surprise: '놀람', }; Lang.video_object_params = { person: '사람', bicycle: '자전거', car: '자동차', motorcycle: '오토바이', airplane: '비행기', bus: '버스', train: '기차', truck: '트럭', boat: '보트', 'traffic light': '신호등', 'fire hydrant': '소화전', 'stop sign': '정지 표지판', 'parking meter': '주차 미터기', bench: '벤치', bird: '새', cat: '고양이', dog: '개', horse: '말', sheep: '양', cow: '소', elephant: '코끼리', bear: '곰', zebra: '얼룩말', giraffe: '기린', backpack: '배낭', umbrella: '우산', handbag: '핸드백', tie: '넥타이', suitcase: '여행 가방', frisbee: '원반', skis: '스키', snowboard: '스노우보드', 'sports ball': '공', kite: '연', 'baseball bat': '야구 배트', 'baseball glove': '야구 글러브', skateboard: '스케이트보드', surfboard: '서프보드', 'tennis racket': '테니스 라켓', bottle: '병', 'wine glass': '와인잔', cup: '컵', fork: '포크', knife: '나이프', spoon: '숟가락', bowl: '그릇', banana: '바나나', apple: '사과', sandwich: '샌드위치', orange: '오렌지', broccoli: '브로콜리', carrot: '당근', 'hot dog': '핫도그', pizza: '피자', donut: '도넛', cake: '케이크', chair: '의자', couch: '소파', 'potted plant': '화분', bed: '침대', 'dining table': '식탁', toilet: '변기', tv: 'TV', laptop: '노트북', mouse: '마우스', remote: '리모컨', keyboard: '키보드', 'cell phone': '핸드폰', microwave: '전자레인지', oven: '오븐', toaster: '토스터', sink: '싱크대', refrigerator: '냉장고', book: '책', clock: '시계', vase: '꽃병', scissors: '가위', 'teddy bear': '테디베어', 'hair drier': '헤어드라이어', toothbrush: '칫솔', }; Lang.Buttons = { share_policy: '이것만은 꼭!', write_policy: '작성 가이드', lesson_list: '강의 목록', complete_study: '학습 완료하기', show_me: '미리 보기', do_this_for_me: '대신 해주기', previous: '이전', get_started: '시작하기', next_lesson: '다음 내용 학습하기', course_submit: '제출하기', course_done: '확인', mission: '미션 확인하기', basic_guide: '기본 사용 방법', apply: '적용하기', add: '추가', cancel: '취소', save: '저장', start: '시작', confirm: '확인', delete: '삭제', create: '학급 만들기', done: '완료', accept: '수락', refuse: '거절', yes: '예', button_no: '아니오', quiz_retry: '다시 풀어보기', discuss_upload: '불러오기', maze_popup_guide: '이용안내', maze_popup_mapHint: '힌트보기', maze_hint_btn_guide: '이용 안내', maze_hint_btn_block: '블록 도움말', maze_hint_btn_map: '힌트 보기', maze_hint_btn_goal: '목표', list_save: '저장하기', duplication: '복사하기', export_to_excel: '엑셀로 내려받기', convert_table: '테이블로 만들기', single_line: '한 줄 쓰기', multi_line: '여러 줄 쓰기', lecture_finish_popup_reset_lecture: '처음부터 다시하기', lecture_finish_popup_show_output: '실습한 코드보기', lecture_view_hints: '잘 모르겠어요!', default_hint_title: '어떻게 만들까?', show_only_vector: '벡터 모아보기', sound_menu_trim: '다듬기', sound_menu_adjust: '조정하기', sound_button_reset: '원래대로', sound_button_save: '저장하기', back: '뒤로가기', add2: '추가하기', load: '불러오기', move: '이동하기', create_new_table: '테이블 새로 만들기', add_variable: '변수 추가', add_list: '리스트 추가', add_message: '신호 추가', }; Lang.Menus = { ask_captcha: '아래 이미지를 보이는 대로 입력해주세요.', refresh: '새로고침', check_image_captcha: '이미지로 보기', check_sound_captcha: '음성으로 듣기', nothing_to_import: '불러오기 할 항목이 없습니다.', nothing_to_export: '내려받기 할 항목이 없습니다.', content_copied: '내용이 복사되었습니다.', list_import_title: '리스트 불러오기', list_import_placeholder: '예)\r\n항목1\r\n항목2\r\n항목3', verifying_email: '인증 메일 발송하기', list_import_notice_1: '리스트의 항목과 내용(기본값)을 한꺼번에 작성할 수 있습니다.', list_import_notice_2: '기존 내용은 사라지고 여기서 작성한 내용만 저장됩니다.', list_export_title: '리스트 내보내기', list_export_notice1: '아래에서 리스트의 내용을 직접 복사하거나,', list_export_notice2: '파일로 내보내거나,작품의 테이블로 만들 수 있습니다.', list_export_notice: '리스트 항목의 내용을 복사하거나, 엑셀로 내려받을 수 있습니다.', robotis_opencm70: '로보티즈 IoT', cannnot_mark_favorite: '비공개 작품은 관심 작품으로 지정할 수 없습니다.', enterPassword: '비밀번호를 입력해주세요.', enterPassword_update: '변경 내용을 저장하기 위해 비밀번호를 입력해주세요.', enterNewPassword: '새로운 비밀번호를 입력하세요.', reEnterNewPassword: '새로운 비밀번호를 다시 입력하세요.', resign: '회원탈퇴', check_sended_email: '발송된 인증 메일을 확인하여 이메일 주소를 인증해 주세요.', signUpEmail_1: '입력된 이메일 주소로 인증 메일이 발송되었습니다.', signUpEmail_2: '이메일 주소를 인증해주세요.', select_email_unauthenticated_user: '해당 이메일 주소가 아래 계정에 등록되어 있습니다.\n인증을 원하는 계정을 선택해주세요.', select_user: '계정을 선택해주세요.', enter_password_withdraw: '회원탈퇴 신청을 위해 비밀번호를 입력해주세요.', instruction_agree: '안내 사항에 동의해주세요.', check_instructions: '위 안내 사항에 동의합니다.', deleteAccount_2: '회원탈퇴를 신청하신 30일 이후에는 회원정보와 작품/강의/학급/게시글/댓글/좋아요/관심 정보가 모두 삭제되며 복구가 불가능합니다.', deleteAccount_1: '회원탈퇴를 신청하신 30일 이내에 로그인하시면 회원탈퇴를 취소하실 수 있습니다.', protect_account: '안전한 비밀번호로 내정보를 보호하세요.', please_verify: '인증 메일을 발송하여 이메일 주소를 인증해 주세요.', unverified_email: '이메일 주소가 인증되지 않았습니다.', deleteAccount: '회원탈퇴 신청', corporatePersonal: '개인정보 이전에 동의 합니다', corporateTransferGuide: "개인정보 양수자('엔트리' 웹사이트 운영자) 안내", corporateReciever: '개인정보를 이전 받은 자: 재단법인 커넥트', corporateAddress: '커넥트 주소 및 연락처', corporateAddress_1: '서울시 강남구 강남대로 382 메리츠타워 7층', corporateConsent: '개인정보의 이전을 원치 않으시는 경우 ,동의 철회 방법', corporateEmail: '계정에 등록된 이메일로 탈퇴 요청 메일 발송', corporateAddition: '또한 , 영업 양도에 따라 약관 등이 아래와 같이 변경될 예정입니다.', corporateApplicationDate: '적용시기 : 2017년 10월 29일', corporateTargetChanges: '적용대상 및 변경사항 :', corporateTarget: '적용대상', corporateChanges: '변경사항', corporateTerms: '엔트리 이용약관', corporateOperator: '웹사이트 운영자의 명칭 변경', corporateClassroomTerms: '학급 서비스 이용약관', doAgreeWithClassroomTerms: '학급 서비스 이용약관에 동의합니다.', doChangePassword: '나만 알수 있는 비밀번호로 변경해주세요.', corporatePrivacyPolicy: '개인정보 처리방침', corporateConsignment: '웹사이트 운영자의 명칭 변경 및 개인정보 위탁 업체 추가', corporateEntrusted: '수탁업: NHN Technology Service(주)', corporateConsignmentDetails: '위탁업무 내용: 서비스 개발 및 운영', corporatePeriod: '보유기간 : 회원 탈퇴 시 혹은 위탁 계약 종료시 까지', corporateChangeDate: '변경 적용일 : 2017년 10월 29일 부', corporateWarning: '개인정보 이전에 동의해 주세요.', corporateConfirm: '확인', corporateTitle: '안녕하세요. 엔트리교육연구소입니다.
“엔트리”를 이용하고 계신 회원 여러분께 깊은 감사의 말씀을 드립니다.
엔트리교육연구소는 그동안 공익 목적으로 운영해오던 “엔트리” 웹사이트의 운영을
네이버가 설립한 비영리 재단인 커넥트재단에 양도하기로 합의하였습니다. 
앞으로 엔트리는 커넥트재단에서 공익 목적 하에 지속적으로 운영될 수 있도록
할 것이며, 회원 여러분께서는 기존과 동일하게 엔트리를 이용하실 수 있습니다.
 웹사이트 제공 주체가 엔트리교육연구소에서 커넥트재단으로 변경됨에 따라 아래와
같이 회원 개인 정보에 대한 이전이 있으며, 본 합의에 의해 실제 개인 정보의 위치가
물리적으로 이동한 것은 아님을 알려드립니다. ', textcoding_numberError_f: '등록된 함수 중에 이름의 첫 글자가 숫자인 함수가 있으면 모드 변환을 할 수 없습니다.', textcoding_bookedError_1f: '등록된 함수 중에 이름이 ', textcoding_bookedError_2f: '인 함수가 있으면 모드 변환을 할 수 없습니다.', textcoding_specialCharError_f: "등록된 함수 중 이름에 '_' 를 제외한 특수 문자가 있으면 모드 변환을 할 수 없습니다.", textcoding_numberError_v: '등록된 변수 중에 이름의 첫 글자가 숫자인 변수가 있으면 모드 변환을 할 수 없습니다.', textcoding_bookedError_1v: '등록된 변수 중에 변수 이름이 ', textcoding_bookedError_2v: '인 변수가 있으면 모드 변환을 할 수 없습니다.', textcoding_specialCharError_v: "등록된 변수 중 이름에 '_' 를 제외한 특수 문자가 있으면 모드 변환을 할 수 없습니다.", textcoding_numberError_l: '등록된 리스트 중에 이름의 첫 글자가 숫자인 리스트가 있으면 모드 변환을 할 수 없습니다.', textcoding_bookedError_1l: '등록된 리스트 중에 리스트 이름이 ', textcoding_bookedError_2l: '인 리스트가 있으면 모드 변환을 할 수 없습니다.', textcoding_specialCharError_l: "등록된 리스트 중 이름에 '_' 를 제외한 특수 문자가 있으면 모드 변환을 할 수 없습니다.", no_discuss_permission: '글을 읽을 권한이 없습니다', delete_comment: '댓글을 삭제하시겠습니까?', delete_article: '게시물을 삭제하시겠습니까?', discuss_cannot_edit: '본인의 게시물이 아닙니다.', discuss_extention: '실행파일은 첨부하실 수 없습니다.', delete_discuss_picture: '사진을 삭제하시겠습니까?', delete_discuss_file: '파일을 삭제하시겠습니까?', discuss_save_question: '글을 저장하시겠습니까?', discuss_cancle_question: '작성을 취소하시겠습니까?', discuss_saved: '이(가) 저장되었습니다.', discuss_no_write_permission: '현재 로그인된 계정으로는 글을 작성하실 수 없습니다.', discuss_no_project_permission: '현재 로그인된 계정으로는 작품을 게시하실 수 없습니다.', discuss_write_abuse_detected: '짧은 시간안에 여러 글이 작성되었습니다.\n1분 뒤에 다시 시도해주세요.', contents_abuse_detected: '5분 뒤에 다시 시도해주세요.', contents_abuse_detected_10: '10분 뒤에 다시 시도해주세요.', discuss_new_write_abuse_warn: '짧은 시간안에 새 글을 작성하는 경우 \n게시글 작성이 제한될 수 있습니다. \n이용에 주의하시길 바랍니다.', discuss_write_abuse_warn: '짧은 시간안에 여러 댓글을 작성하는 경우 \n댓글 작성이 제한될 수 있습니다. \n이용에 주의하시길 바랍니다.', find_not_your_email: '올바른 이메일을 입력해주세요.', search_lang: '검색', search_title: '제목', faq_desc: '엔트리를 이용하면서 궁금한 점들의 답변을 확인해보세요.', faq_all: '전체보기', faq_site: '사이트 이용', faq_project: '작품 만들기', faq_hardware: '하드웨어', faq_offline: '오프라인', faq_copyright: '저작권', faq_title: '자주하는 질문', faq: '자주하는 질문', malicious_warning: '불건전한 사진은 불러올 수 없습니다. 불건전한 사진이 아닌 경우 제안 및 건의에 해당 사진을 첨부하여 신고해주세요.', fword_alert_msg: '욕설이나 불건전한 글은 게시할 수 없습니다.', fword_alert_1: '주제와 무관한 욕설이나 악플은 게시할 수 없습니다.', fword_alert_2: '불건전한 단어가 포함되어 있어, 대체 문장으로 게시 됩니다.', fword_replace_1: '엔트리를 통해 누구나 쉽고 재미있게 소프트웨어를 배울 수 있어요.', fword_replace_2: '소프트웨어 교육의 첫걸음, 엔트리.', fword_replace_3: '재미있게 배우는 학습 공간 엔트리!', fword_replace_4: '엔트리에서 공유와 협업을 통해 멋진 작품을 만들어요.', fword_replace_5: '엔트리는 누구나 무료로 소프트웨어 교육을 받을 수 있게 개발된 소프트웨어 교육 플랫폼입니다.', fword_replace_6: '엔트리와 함께 건강한 소프트웨어 교육 생태계를 조성해요!', fword_replace_7: '엔트리에서 학습하고, 만들고, 공유하며 같이 성장해요.', solve_quiz: '퀴즈 풀기', submit_homework_first_title: '완성! 과제 제출하기', submit_homework_first_content: '멋진 작품이 완성되었습니다. 과제를 제출하세요. 마감 기한 전까지 다시 제출할 수 있습니다.', submit_homework_again_title: '과제 다시 제출하기', submit_homework_again_content: '이미 제출한 과제입니다.
과제를 다시 제출하시겠습니까?', submit_homework_expired_title: '과제 제출 마감', submit_homework_expired_content: '과제 제출이 마감되었습니다.', done_study_title: '완성', done_study_content: '만든 작품을 실행해 봅시다.', featured_courses: '추천 강의 모음', follow_along: '따라하기', follow_along_desc: '차근차근 따라하며 다양한 작품을 만듭니다.', do_quiz: '퀴즈풀기', do_quiz_desc: '학습한 내용을 잘 이해했는지 퀴즈를 통해 확인합니다.', challenge: '도전하기', play: '도전하기', challenge_desc: '주어진 문제를 스스로 해결하며 개념을 익힙니다.', creste_freely: '자유롭게 만들기', creste_freely_desc: '학습한 내용으로 나만의 작품을 자유롭게 만듭니다.', entry_rc_desc: '프로그래밍의 원리를 학습단계에 맞게 배울 수 있는 엔트리 강의 모음! 지금 시작해보세요!
따라하고, 도전하며 소프트웨어를 만들다 보면 어렵게 느껴졌던 프로그래밍의 원리도 쉽고 재미있게 다가옵니다!', hw_deadline: '마감 일자', rc_course_desc: '프로그래밍의 원리를 학습단계에 맞게 배울 수 있도록 구성된 엔트리 강의 모음입니다.', rc_course: '추천 강의 모음', entry_rec_course: '엔트리 추천 강의 모음', entry_rec_course_desc: '누구나 쉽게 보고 따라하면서 재미있고 다양한 소프트웨어를 만들 수 있는 엔트리 강의를 소개합니다.', guidance: '안내', wait: '잠깐', hint: '힌트', concept_guide: '개념 톡톡', group_quiz: '우리 반 퀴즈', fail_check_hint: '앗… 실패! 다시 한 번 도전해보세요!
어려울 땐 [힌트]를 확인해보세요!', sort_student: '학생별', sort_lesson: '강의별', sort_course: '강의 모음별', student_progress: '우리 반 진도', my_progress: '나의 진도', lec_in_progress: '학습 중', free_modal_asgn_over: '과제 제출이 마감되었습니다.', free_submission_closed: '과제 제출 마감', free_modal_asgn_submit_first: '멋진 작품이 완성되었습니다! 과제를 제출하세요.
마감 기한 전까지 다시 제출 할 수 있습니다.', asgn_submit: '완성! 과제 제출하기', free_modal_content_resubmit: '이미 제출한 과제입니다.
과제를 다시 제출하시겠습니까?', asgn_resubmit: '과제 다시 제출하기', free_modal_content_complete: '멋진 작품이 완성되었습니다.', guide_modal_content_complete: '만든 작품을 실행해 봅시다.', success: '성공', fail: '실패', mission_modal_content_fail: '
어려울 땐 [힌트]를 확인해보세요!', mission_modal_content_success: '만든 작품을 실행해 봅시다.', in_progress: '진행중', completed: '완료', basic2: '미학습', in_progress2: '학습중', submitted: '제출 완료', submission_closed: '마감', lecture_progress_describe: '강의명을 누르면 해당 강의로 이동합니다.', progress: '진행 상황', study_completed: '학습 완료', view_course_desc: '코스웨어 설명 보기', main_entry_starter: '기초부터! 엔트리 스타터', main_entry_booster: '개념탄탄! 엔트리 부스터', main_entry_master: '생각을 펼치는! 엔트리 마스터', no_students_in_classroom: '아직 등록된 학생이 없습니다.
학생을 직접 추가하거나, 초대해 보세요!', lectures: '강의', Lectures: '강의', studentHomeworkList: '과제', curriculums: '강의 모음', Curriculums: '강의 모음', quiz: '퀴즈', no_added_group_contents_teacher: '추가된 %1이(가) 없습니다.
우리 반 %1을(를) 추가해 주세요.', no_added_group_contents_student: '아직 올라온 %1이(가) 없습니다. 선생님이 %1을(를) 올려주시면, 학습 내용을 확인할 수 있습니다.', side_project: '목표 작품', custom_make_course_1: "'오픈 강의 만들기> 강의 모음 만들기'에서", custom_make_course_2: '나만의 강의 모음을 만들어 보세요.', custom_make_lecture_1: "'오픈 강의 만들기'에서", custom_make_lecture_2: '나만의 강의를 만들어 보세요', alert_enter_info: '수정할 정보를 입력해주세요.', alert_enter_new_pwd: '기존 비밀번호와 다른 비밀번호를 입력해주세요.', alert_match_pwd: '새로운 비밀번호와 재입력된 비밀번호가 일치하지 않습니다.', alert_check_pwd: '비밀번호를 확인해주세요.', alert_update_complete: '정보가 수정 되었습니다.', no_group_contents_each_prefix: '우리반 ', no_group_contents_each_suffix: ' 이(가) 없습니다.', no_group_contents_all: '학급에 올라온 컨텐츠가 없습니다.
학급 공유하기에
나만의 작품을 공유해보세요!', hw_closed: '과제 마감', tag_Lecture: '강의', tag_Curriculum: '강의모음', tag_Discuss: '공지', count_ko: '개', no_asgn_within_week: '1주일안에 제출되어야 하는 마감 임박한 과제가 없습니다.', lecture_and_curriculum: '강의 / 강의 모음', assignments_plural: '과제', assignments_singular: '과제', project_plural: '작품', group_news: '새로운 소식', stu_management: '학생 관리', stu_management_camel: '학생 관리', view_all: '전체 보기', view_all_camel: '전체 보기', view_contents_camel: '콘텐츠 보기', view_contents: '콘텐츠 보기', no_updated_news: '나의 학급에 올라온 새로운 소식이 없습니다.', homework_soon_due: '곧 마감 과제', new_homework: '최신 과제', no_new_homework: '새로운 과제가 없습니다.', student_plural: '학생', discuss: '공지', basic_project: '기본 작품', no_permission: '권한이 없습니다.', no_comment_write_permission: '현재 로그인된 계정으로는 답변을 작성하실 수 없습니다.', original_curriculum_deleted: '원본 강의 모음이 삭제되었습니다.', original_curriculum: '원본 강의 모음', save_as_my_lecture: '복사본으로 저장하기 ', delete_confirm: '삭제 알림', lecture_open_as_copied: '오픈 강의 페이지에 올라간 모든 강의는 사본으로 생성되어 공개 됩니다.', curriculum_open_as_copied: '오픈 강의 모음 페이지에 올라간 모든 강의 모음은 사본으로 생성되어 공개 됩니다.', lecture_save_as_copied_group: '우리 반 강의 페이지에 올라간 모든 강의는 사본으로 생성되어 공개 됩니다.', curriculum_save_as_copied_group: '우리 반 강의 모음 페이지에 올라간 모든 강의 모음은 사본으로 생성되어 공개 됩니다.', homework_save_as_copied_group: '우리 반 과제 페이지에 올라간 모든 과제는 사본으로 생성되어 공개 됩니다.', lecture_save_as_copied: '내가 만든 강의 모음 안에 삽입된 구성 강의는 사본으로 생성되어 저장됩니다.', done_project_save_as_copied: '내가 만든 강의 안에 삽입된 완성 작품은 사본으로 생성되어 저장됩니다.', textbook_project_can_not_applied: '교과형 만들기(실과)로 만들어진 작품은 강의로 만들 수 없습니다.', original_lecture_deleted: '원본 강의가 삭제되었습니다.', original_lecture: '원본 강의', lecture_save_as_mine_alert: "저장되었습니다.\n저장된 강의는 '마이페이지> 나의 강의'에서 확인할 수 있습니다.", lecture_save_as_mine: '내 강의로 저장하기', duplicate_username: '이미 입력한 아이디 입니다.', share_your_project: '내가 만든 작품을 공유해 보세요', not_available_student: "학급에서 발급된 '학급 아이디'입니다.\n'엔트리 회원 아이디'를 입력해주세요.", login_instruction: '로그인 안내', login_needed: '로그인 후 이용할 수 있습니다.', go_login: '로그인 하기', login_as_teacher: '선생님 계정으로 로그인 후 이용할 수 있습니다.', remove_my_storage: '나의 보관함에서 삭제하시겠습니까? 삭제한 블록/오브젝트는 복구할 수 없습니다.', submit_hw: '과제 제출하기', success_goal: '목표성공', choseok_final_result: '좋아 , 나만의 작품을 완성했어!', choseok_fail_msg_timeout: '시간이 너무 많이 지나버렸어. 목표를 잘 보고 다시 한번 도전해봐!', choseok_fail_msg_die: '생명이 0이하인데 게임이 끝나지 않았어.\n아래의 블록을 사용해서 다시 도전해 보는 건 어때?', grade_1: '초급', grade_2: '중급', grade_3: '고급', find_sally_title: '샐리를 찾아서', save_sally_title: '샐리 구하기', exit_sally_title: '샐리 탈출하기', find_sally: '라인 레인저스의 힘을 모아 \n강력한 악당 메피스토를 물리치고 샐리를 구해주세요!', save_sally: '메피스토 기지에 갇힌 샐리. \n라인 레인저스가 장애물을 피해 샐리를 찾아갈 수 있도록\n도와주세요!', exit_sally: '폭파되고 있는 메피스토 기지에서 \n샐리와 라인 레인저스가 무사히 탈출할 수 있도록\n도와주세요!', go_next_mission: '다른 미션 도전하기', share_my_project: '내가 만든 작품 공유하기', share_certification: '인증서 공유하기', print_certification: '인증서를 뽐내봐', get_cparty_events: '내가 받은 인증서를 출력해 뽐내면 푸짐한 상품을 받을 수 있어요!', go_cparty_events: '이벤트 참여하러 가기', codingparty2016_blockHelper_1_title: '앞으로 가기', codingparty2016_blockHelper_1_contents: '앞으로 가기', codingparty2016_blockHelper_2_title: '앞으로 가기', codingparty2016_blockHelper_2_contents: '회전하기', codingparty2016_blockHelper_3_title: '앞으로 가기', codingparty2016_blockHelper_3_contents: '돌 부수기', codingparty2016_blockHelper_4_title: '앞으로 가기', codingparty2016_blockHelper_4_contents: '횟수 반복하기', codingparty2016_blockHelper_5_title: '앞으로 가기', codingparty2016_blockHelper_5_contents: '꽃 던지기', codingparty2016_goalHint_1: '샐리를 구하기 위해서는 미네랄이 필요해! 미네랄을 얻으며 목적지까지 가보자!', codingparty2016_goalHint_2: '구불구불한 길이 있네. 회전 블록을 사용하면 어렵지 않을 거야!', codingparty2016_goalHint_3: '앞이 돌로 막혀있잖아? 돌을 부수며 목적지까지 가보자!', codingparty2016_goalHint_4: '복잡한 길이지만 지금까지 배운 것들로 해결할 수 있어!', codingparty2016_goalHint_5: '앞으로 쭉 가는 길이잖아? 반복 블록을 사용하여 간단하게 해결해 보자!', codingparty2016_goalHint_6: '미네랄을 모두 모아오자. 반복블록을 쓰면 쉽게 다녀올 수 있겠어!', codingparty2016_goalHint_7: '친구들이 다치지 않도록 꽃을 던져 거미집을 제거해야 해. 저 멀리 있는 거미집을 제거하고 목적지까지 가 보자.', codingparty2016_goalHint_8: '가는 길에 거미집이 많잖아? 거미집을 모두 제거하고 목적지까지 가 보자.', codingparty2016_goalHint_9: '거미집 뒤쪽에 있는 미네랄을 모두 모아오자!', codingparty2016_guide_1_1_contents: '라인 레인저스 전사들이 샐리를 구할 수 있도록 도와줘! 전사들을 움직이기 위해서는 블록 명령어를 조립해야 해.\n\n① 먼저 미션 화면과 목표를 확인하고,\n② 블록 꾸러미에서 필요한 블록을 가져와 “시작하기를 클릭했을 때“ 블록과 연결해.\n③ 다 조립되면 ‘시작하기‘ 버튼을 눌러 봐! 블록이 위에서부터 순서대로 실행되며 움직일 거야.', codingparty2016_guide_1_1_title: '라인 레인저스 전사들을 움직이려면?', codingparty2016_guide_1_2_title: '목표 블록의 개수', codingparty2016_guide_1_2_contents: '① [안 칠해진 별]의 개수만큼 블록을 조립해 미션을 해결해보자. 목표 블록보다 더 많은 블록을 사용하면 별이 빨간색으로 바뀌니 정해진 개수 안에서 문제를 해결해 봐!\n② 필요하지 않은 블록은 휴지통 또는 블록꾸러미에 넣어줘.', codingparty2016_guide_1_3_title: "'앞으로 가기' 블록을 사용하기", codingparty2016_guide_1_3_contents: '< 앞으로 가기 > 는 앞으로 한 칸 이동하는 블록이야. \n\n여러 칸을 이동하기 위해서는 이 블록을 여러 번 연결해야 해.', codingparty2016_guide_1_4_title: '미네랄 획득하기', codingparty2016_guide_1_4_contents: '[ 미네랄 ]이 있는 곳을 지나가면 미네랄을 획득할 수 있어\n\n화면에 있는 미네랄을 모두 획득하고 목적지에 도착해야만 다음 단계로 넘어갈 수 있어.', codingparty2016_guide_1_5_title: '어려울 때 도움을 받으려면?', codingparty2016_guide_1_5_contents: '미션을 수행하다가 어려울 땐 3가지 종류의 도움말 버튼을 눌러 봐.\n\n\n<안내> 지금 이 안내를 다시 보고 싶을 때!\n<블록 도움말> 블록 하나하나가 어떻게 동작하는지 궁금할 때!\n<맵 힌트> 이 단계를 해결하기 위한 힌트가 필요할 때!', codingparty2016_guide_2_1_title: '회전 블록 사용하기', codingparty2016_guide_2_1_contents: '<오른쪽으로 돌기>와 <왼쪽으로 돌기>는 \n제자리에서 90도 회전하는 블록이야. 방향만 회전하는 블록이야. \n캐릭터가 바라보고 있는 방향을 기준으로 오른쪽인지 왼쪽인지 잘 생각해 봐!\n', codingparty2016_guide_3_1_title: '(문) 능력 사용하기', codingparty2016_guide_3_1_contents: '라인 레인저스 전사들을 각자의 능력을 가지고 있어.\n나 [문] 은 <발차기하기> 로 바로 앞에 있는 [돌]을 부술 수 있어.\n[돌을] 부수고 나면 막힌 길을 지나갈 수 있겠지?\n화면에 있는 [돌]을 모두 제거해야만 다음 단계로 넘어갈 수 있어.\n그렇지만 명심해! 아무 것도 없는 곳에 능력을 낭비해서는 안 돼!', codingparty2016_guide_5_1_title: "'~번 반복하기' 블록 사용하기", codingparty2016_guide_5_1_contents: '똑같은 일을 반복해서 명령하는 건 매우 귀찮은 일이야.\n이럴 땐 명령을 사용하면 훨씬 쉽게 명령을 내릴 수 있어. \n< [ ? ] 번 반복하기> 블록 안에 반복되는 명령 블록을 넣고 \n[ ? ] 부분에 횟수를 입력하면 입력한 횟수만큼 같은 명령을 반복하게 돼.', codingparty2016_guide_5_2_title: "'~번 반복하기' 블록 사용하기", codingparty2016_guide_5_2_contents: "'< [ ? ] 번 반복하기> 블록 안에는 여러 개의 명령어를 넣을 수도 있으니 잘 활용해봐! \n도착지에 도착했더라도 반복하기 블록 안에 있는 블록이 모두 실행돼.\n 즉, 위 상황에서 목적지에 도착한 후에도 왼쪽으로 돈 다음에야 끝나는 거야!", codingparty2016_guide_7_1_title: '(코니) 능력 사용하기', codingparty2016_guide_7_1_contents: '나 ‘코니’는 <꽃 던지기>로 먼 거리에서도 앞에 있는 [거미집]을 없앨 수 있어.\n[거미집]을 없애고 나면 막힌 길을 지나갈 수 있겠지?\n화면에 있는 [거미집]을 모두 제거해야만 다음 단계로 넘어갈 수 있어.\n그렇지만 명심해! 아무것도 없는 곳에 능력을 낭비해서는 안 돼!', codingparty2016_guide_9_1_title: '조건 반복 블록 사용하기', codingparty2016_guide_9_1_contents: '반복하는 횟수를 세지 않아도, 어떤 조건을 만족할 때까지 행동을 반복할 수 있어.\n< [목적지]에 도착할 때까지 반복하기 > 블록 안에 반복되는 명령 블록을 넣으면 [목적지]에 도착할 때까지 명령을 반복해.', codingparty2016_guide_9_2_title: '조건 반복 블록 사용하기', codingparty2016_guide_9_2_contents: '<[목적지]에 도착할 때까지 반복하기> 블록 안에는 여러 개의 명령어를 넣을 수도 있으니 잘 활용해봐!\n 도착지에 도착했더라도 반복하기 블록 안에 있는 블록이 모두 실행 돼. 즉, 위 상황에서 목적지에 도착한 후에도 왼쪽으로 돈 다음에야 끝나는 거야!', find_interesting_lesson: "'우리 반 강의'에서 다양한 강의를 만나보세요!", find_interesting_course: "'우리 반 강의 모음'에서 다양한 강의를 만나보세요!", select_share_settings: '공유 공간을 선택해주세요.', faq_banner_title: '자주하는 질문 안내', check_out_faq: '궁금한 점을 확인하세요.', faq_banner_content: '엔트리에 대해 궁금하세요?
자주하는 질문을 통해 답변을 드리고 있습니다.
지금 바로 확인하세요!', faq_banner_button: '자주하는 질문
바로가기', major_updates: '주요 업데이트 안내', check_new_update: '엔트리의 변화를 확인하세요.', major_updates_notification: '엔트리의 주요 변경사항을 공지를 통해 안내해 드리고 있습니다.', find_out_now: '지금 바로 확인하세요!', offline_hw_program: '오프라인 & 하드웨어 연결 프로그램', read_more: '자세히 보기', sample_project: '예시 작품 확인하기', not_supported_function: '이 기기에서는 지원하지 않는 기능입니다.', offline_download_confirm: '엔트리 오프라인 버전은 PC에서만 이용가능합니다. 다운로드 하시겠습니까?', hardware_download_confirm: '엔트리 하드웨어는 PC에서만 이용가능합니다. 다운로드 하시겠습니까?', copy_text: '텍스트를 복사하세요.', select_openArea_space: '작품 공유 공간을 선택해 주세요', mission_guide: '미션 해결하기 안내', of: ' 의', no_results_found: '검색 결과가 없습니다.', upload_pdf: 'PDF 자료 업로드', select_basic_project: '작품 선택하기', try_it_out: '만들어 보기', go_boardgame: '엔트리봇 보드게임 바로가기', go_cardgame: '엔트리봇 카드게임 바로가기', go_solve: '미션으로 학습하기', go_ws: '엔트리 만들기 바로가기', go_arts: '엔트리 공유하기 바로가기', group_delete_alert: '학급을 삭제하면, 해당 학급에서 발급한 학생임시계정을 포함하여 관련한 모든 자료가 삭제됩니다.\n정말 삭제하시겠습니까?', view_arts_list: '다른 작품 보기', hw_submit_confirm_alert: '과제가 제출 되었습니다.', hw_submit_alert: '과제를 제출 하시겠습니까? ', hw_submit_alert2: '과제를 제출하시겠습니까? 제출 시 학습 완료한 학습 단계까지만 제출이 됩니다.', hw_submit_cannot: '제출 할 수 없는 과제입니다.', see_other_missions: '다른 미션 보기', project: ' 작품', marked: ' 관심', group: '학급', lecture: '강의', Lecture: '강의', curriculum: '강의 모음', Curriculum: '강의 모음', studying: '학습 중인', open_only_shared_lecture: '오픈 강의 페이지에 <공개> 한 강의만 불러올 수 있습니다. 불러오고자 하는 강의공개여부를 확인해 주세요.', already_exist_group: '이미 존재하는 학급 입니다.', cannot_invite_you: '자기 자신을 초대할 수 없습니다.', apply_original_image: '원본 이미지 그대로 적용하기', draw_new_ques: '새로 그리기 페이지로\n이동하시겠습니까?', draw_new_ques_1: '그림을 직접 그려서 추가할 수 있습니다.', draw_new_ques_2: '그리기 화면으로 이동할까요?', draw_new_go: '이동', draw_new_stay: '이동하지 않기', file_upload_warn_title_image: '아래와 같은 그림은 이용약관 및 관련 법률에 의해 제재를 받으실 수 있습니다.', file_upload_warn_desc_image: '폭력적이고 잔인한 그림, 선정적인 신체노출 그림, 불쾌감을 주거나 혐오감을 일으키는 그림, 무단 사용이 금지된 저작권의 그림', file_upload_warn_title_sound: '아래와 같은 소리는 이용약관 및 관련 법률에 의해 제재를 받을 수 있습니다.', file_upload_warn_desc_sound: '폭력적이고 잔인한 소리, 선정적인 내용의 소리, 불쾌감을 주거나 혐오감을 일으키는 소리, 무단 사용이 금지된 저작권의 소리', file_upload_warn_title_table: '아래와 같은 데이터는 이용약관 및 관련 법률에 의해 제재를 받을 수 있습니다.', file_upload_warn_desc_table: '폭력적이고 잔인한 데이터, 선정적인 내용의 데이터, 불쾌감을 주거나 혐오단어가 포함된 데이터,
본인 또는 타인의 개인정보를 침해할 수 있는 내용의 데이터, 무단 사용이 금지된 저작권의 데이터', file_upload_warn_link: '저작권에 대해 알아보기', file_upload_desc_1: '이런 그림은 \n 안돼요!', file_upload_desc_2: '폭력적이고 잔인한 그림', file_upload_desc_3: '선정적인 신체노출 그림', file_upload_desc_4: '불쾌감을 주거나 혐오감을 일으키는 그림', file_upload_desc_5: '* 위와 같은 내용은 이용약관 및 관련 법률에 의해 제재를 받으실 수 있습니다.', picture_upload_warn_old: '10MB 이하의 jpg, png, bmp 형식의 파일을 추가할 수 있습니다.', sprite_upload_warn_old: '10MB 이하의 jpg, png, bmp 이미지 또는 eo 형식의 오브젝트를 추가할 수 있습니다.', picture_upload_warn_1: '5MB 이하의 jpg, png, bmp, svg 형식의 파일을 추가할 수 있습니다.\njpg, png, bmp 형식은 비트맵 모드, svg 형식은 벡터 모드로 편집됩니다.', table_upload_warn_1: '10MB 이하의 CSV, XLS(X) 형식의 파일을 추가할 수 있습니다. 엑셀 파일의 경우, 함수 문장이 그대로 출력됩니다.', sprite_upload_warn: '5MB 이하의 jpg, png, bmp, svg 이미지 또는 eo 형식의 오브젝트를 추가할 수 있습니다.', sound_upload_warn_1: '10MB 이하의 mp3 형식의 파일을 추가할 수 있습니다.', sound_edit_warn: '기다려 주세요!\n새로운 소리 편집 기능을 연구 중입니다.', file_upload_loading: '로딩중', lesson_by_teacher: '선생님들이 직접 만드는 강의입니다.', delete_group_art: '학급 공유하기 목록에서 삭제 하시겠습니까?', elementary_short: '초등', middle_short: '중등', grade_34: '3-4학년', grade_56: '5-6학년', grade_78: '중등', share_lesson: '강의 공유하기', share_course: '강의 모음 공유하기', from_list_ko: '을(를)', comming_soon: '준비중입니다.', no_class_alert: "선택된 학급이 없습니다. 학급이 없는경우 '나의 학급' 메뉴에서 학급을 만들어 주세요.", students_cnt: '명', defult_class_alert_1: '', defult_class_alert_2: '을(를) \n 기본학급으로 설정하시겠습니까?', default_class: '기본학급입니다.', enter_hw_name: '과제의 제목을 입력해 주세요.', hw_limit_100: '과제는 100개 까지만 만들수 있습니다.', stu_example: '예)\n 홍길동\n 홍길동\n 홍길동', hw_description_limit_200: '생성 과제에 대한 안내 사항을 입력해 주세요. (200자 이내)', hw_title_limit_50: '과제명을 입력해 주세요. (50자 이내)', create_project_class_1: "'만들기 > 작품 만들기' 에서", create_project_class_2: '학급에 공유하고 싶은 작품을 만들어 주세요.', create_lesson_assignment_1: "'만들기> 오픈 강의 만들기'에서 ", create_lesson_assignment_2: '우리 반 과제에 추가하고 싶은 강의를 만들어 주세요.', i_make_lesson: '내가 만드는 강의', lesson_to_class_1: "'학습하기>오픈 강의'에서 우리반", lesson_to_class_2: '과제에 추가하고 싶은 강의를 관심강의로 등록해 주세요.', studying_students: '학습자', lessons_count: '강의수', group_out: '나가기', enter_group_code: '학급코드 입력하기', no_group_invite: '학급 초대가 없습니다.', done_create_group: '개설이 완료되었습니다.', set_default_group: '기본학급 설정', edit_group_info: '학급 정보 관리', edit_done: '수정 완료되었습니다.', alert_group_out: '학급을 정말 나가시겠습니까?', lesson_share_cancel: '강의 공유 취소', project_share_cancel: '작품 공유 취소', lesson_share_cancel_alert: '작품을 비공개로 하시겠습니까?', course_share_cancel: '강의 모음 공유 취소', select_lesson_share: '강의 공유 공간 선택', select_project_share: '작품 공유 선택', select_lesson_share_policy_1: '강의를 공유할', select_lesson_share_policyAdd: '공간을 선택해 주세요', select_lesson_share_project_1: '작품을 공유할 공간과', select_lesson_share_policy_2: '저작권 정책을 확인해 주세요.', select_lesson_share_area: '강의 공유 공간을 선택해 주세요', select_project_share_area: '작품 공유 공간을 선택해 주세요', lesson_share_policy: '강의 공유에 따른 엔트리 저작권 정책 동의', project_share_policy: '작품 공유에 따른 엔트리 저작권 정책 동의', alert_agree_share: '공개하려면 엔트리 저작물 정책에 동의하여야 합니다.', alert_agree_all: '모든 항목에 동의해 주세요.', select_course_share: '강의 모음 공유 공간 선택', select_course_share_policy_1: '강의 모음을 공유할', select_course_share_policy_2: '저작권 정책을 확인해 주세요.', select_course_share_area: '강의 모음 공유 공간을 선택해 주세요', course_share_policy: '강의 모음 공유에 따른 엔트리 저작권 정책 동의', issued: '발급', code_expired: "코드가 만료되었습니다. '코드재발급' 버튼를 누르세요.", accept_class_invite: '학급초대 수락하기', welcome_class: '학급에 오신것을 환영합니다.', enter_info: '자신의 정보를 입력해주세요.', done_group_signup: '학급 가입이 완료되었습니다.', enter_group_code_stu: '선생님께 받은 코드를 입력해주세요.', text_limit_50: '50글자 이하로 작성해 주세요.', enter_class_name: '학급 이름을 입력해 주세요.', enter_grade: '학년을 입력해 주세요.', enter_class_info: '학급소개를 입력해 주세요.', student_dup: '은(는) 이미 학급에 존재합니다.', select_stu_print: '출력할 학생을 선택하세요.', class_id_not_exist: '학급 ID가 존재하지 않습니다.', error_try_again: '오류 발생. 다시 한 번 시도해 주세요.', error_forbidden: '권한이 없습니다.', code_not_available: '유효하지 않은 코드입니다.', gnb_create_lessons: '오픈 강의 만들기', study_lessons: '강의 학습하기', lecture_help_1: '학습을 시작할 때, 사용할 작품을 선택해 주세요. 선택한 작품으로 학습자가 학습을 시작하게 됩니다.', lecture_help_2: '이도움말을 다시 보시려면 위 버튼을 클릭해 주세요.', lecture_help_3: '오브젝트 추가하기가 없으면새로운 오브젝트를 추가하거나 삭제 할 수 없습니다.', lecture_help_4: '학습도중에 PDF자료보기를 통해 학습에 도움을 받을 수 있습니다.', lecture_help_5: '학습에 필요한 블록들만 선택해주세요. 선택하지 않은 블록은 숨겨집니다.', lecture_help_6: '블록코딩과 엔트리파이선 중에 선택하여 학습환경을 구성할 수 있습니다.', lecture_finish_popup_title: '학습 다시하기', lecture_finish_popup_content_1: '실습완료한 단계를
처음부터 다시 실습하시겠습니까?', lecture_finish_popup_content_2: '* 다시 실습해도 실습 완료 상태는 유지됩니다.', lecture_start_title: '학습 시작', lecture_goal_title: '학습 목표', lecture_goal_content: '무엇을 배울지 알아볼까요?', lecture_prepare_title: '학습 준비', lecture_summary_title: '학습 정리', lecture_summary_content: '배운 내용을 정리해 봅시다.', lecture_quiz_title: '확인 문제', lecture_quiz_content: '확인 문제를 통해 배운 내용을 점검해 봅시다.', lecture_quiz_check_answer: '정답확인', default_hint_title: '어떻게 만들까?', only_pdf: '.pdf형식의 파일만 입력 가능합니다.', enter_project_video: '적어도 하나의 작품이나 영상을 입력하세요.', enter_title: '제목을 입력하세요.', enter_recommanded_grade: '추천 학년을 입력하세요.', enter_level_diff: '난이도를 입력하세요.', enter_time_spent: '소요시간을 입력하세요.', enter_shared_area: '적어도 하나의 공유 공간을 선택하세요.', enter_goals: '학습목표를 입력하세요.', enter_lecture_description: '강의 설명을 입력하세요.', enter_curriculum_description: '강의 모음 설명을 입력하세요.', first_page: '처음 입니다.', last_page: '마지막 입니다.', alert_duplicate_lecture: '이미 등록된 강의는 다시 등록할 수 없습니다.', enter_lesson_alert: '하나 이상의 강의를 등록해주세요.', open_edit_lessons: '편집할 강의를 불러오세요.', saved_alert: '이(가) 저장되었습니다.', select_lesson_type: '어떤 학습과정을 만들지 선택해 주세요 ', create_lesson: '강의 만들기', create_lesson_desc_1: '원하는 학습 목표에 맞춰', create_lesson_desc_2: '단일 강의를 만들어', create_lesson_desc_3: '학습에 활용합니다.', create_courseware: '강의 모음 만들기', create_courseware_desc_1: '학습 과정에 맞춰 여러개의 강의를', create_courseware_desc_2: '하나의 코스로 만들어', create_courseware_desc_3: '학습에 활용합니다.', create_open_lesson: '오픈 강의 만들기 ', enter_lesson_info: '강의 정보 입력 ', select_lesson_feature: '학습 기능 선택 ', check_info_entered: '입력 정보 확인 ', enter_lefo_lesson_long: '강의를 구성하는 정보를 입력해 주세요.', lesson_info_desc: '학습자가 학습하기 화면에서 사용할 기능과 작품을 선택함으로써, 학습 목표와 내용에 최적화된 학습환경을 구성할 수 있습니다.', provide_only_used: '완성된 작품에서 사용된 블록만 불러오기', see_help: '도움말 보기', select_done_project_1: '학습자가 목표로 설정할', select_done_project_2: '완성 작품', select_done_project_3: '을 선택해 주세요.', select_project: '나의 작품 또는 관심 작품을 불러옵니다. ', youtube_desc: '유튜브 공유 링크를 통해 원하는 영상을 넣을 수 있습니다.', lesson_video: '강의 영상', lesson_title: '강의 제목', recommended_grade: '추천학년', selection_ko: '선택', selection_en: '', level_of_diff: '난이도', select_level_of_diff: '난이도 선택', enter_lesson_title: '강의 제목을 입력해 주세요(45자 이내)', select_time_spent: '소요시간 선택 ', time_spent: '소요시간', lesson_overview: '강의설명', upload_materials: '학습 자료 업로드', open: '불러오기', cancel: '취소하기', upload_lesson_video: '강의 영상 업로드', youtube_upload_desc: '유튜브 공유링크를 통해 보조영상을 삽입할 수 있습니다. ', cancel_select: '선택 취소하기', select_again: '다시 선택하기', goal_project: '완성작품', upload_study_data: '학습하기 화면에서 볼 수 있는 학습자료를 업로드해주세요. 학습자가 업로드된 학습자료의 내용을 확인하며 학습할 수 있습니다. ', upload_limit_20mb: '20MB 이하의 파일을 올려주세요.', expect_time: '예상 소요 시간', course_videos: '보조 영상', enter_courseware_info: '강의 모음 정보 입력 ', enter_course_info: '강의 모음을 소개하는 정보를 입력해 주세요 ', select_lessons_for_course: '강의 모음을 구성하는 강의를 선택해 주세요.', course_build_desc_1: '강의는', course_build_desc_2: '최대30개', course_build_desc_3: '등록할 수 있습니다.', lseeon_list: '강의 목록 보기', open_lessons: '강의 불러오기', course_title: '강의 모음 제목', title_limit_30: '강의 모음 제목을 입력해 주세요(30자 이내) ', course_overview: '강의 모음 설명', charactert_limit_200: '200자 이내로 작성할 수 있습니다.', edit_lesson: '강의 편집', courseware_by_teacher: '선생님들이 직접 만드는 강의 모음입니다.', select_lessons: '구성 강의 선택', check_course_info: '강의 모음을 구성하는 정보가 올바른지 확인해 주세요.', select_share_area: '공유 공간 선택', upload_sub_project: '목표 작품 업로드', file_download: '첨부파일 다운로드', file_remove: '첨부파일 삭제', check_lesson_info: '강의를 구성하는 정보가 올바른지 확인해 주세요.', share_area: '공유 공간', enter_sub_project: '엔트리 보조 프로젝트를 등록해 주세요.', lms_hw_title: '과제 제목', lms_hw_ready: '준비', lms_hw_progress: '진행중', lms_hw_complete: '완료', lms_hw_not_submit: '미제출', lms_hw_closed: '제출마감', submission_condition: '진행중인 과제만 제출이 가능합니다.', submit_students_only: '학생만 과제를 제출할 수 있습니다.', want_submit_hw: '과제를 제출하시겠습니까?', enter_correct_id: '올바른 아이디를 입력해 주세요.', id_not_exist: '아이디가 존재하지 않습니다. ', agree_class_policy: '학급 서비스 이용약관에 동의해 주세요.', delete_class: '학급 삭제', type_stu_name: '학생 이름을 입력해주세요. ', invite_from_1: '에서', invite_from_2: '님을 초대하였습니다. ', lms_pw_alert_1: '님이 개설한', lms_pw_alert_2: '학급의 초대입니다.', lms_pw_alert_3: '선생님의 초대가 맞는지 한번 더 확인해주세요.', invitation_accepted: '초대 수락이 완료되었습니다!', cannot_issue_pw: '초대를 수락하지 않았으므로 비밀번호를 발급할 수 없습니다.', start_me_1: '<월간 엔트리>와 함께', start_me_2: 'SW교육을 시작해보세요!', monthly_desc_1: '<월간 엔트리>는 소프트웨어 교육에 익숙하지 않은 선생님들도 쉽고 재미있게', monthly_desc_2: '소프트웨어 교육을 하실 수 있도록 만들어진 SW교육 잡지입니다.', monthly_desc_3: '매월 재미있는 학습만화와 함께 하는 SW 교육 컨텐츠를 만나보세요!', monthly_desc_4: '* 월간엔트리는 2015년 11월 ~ 2016년 5월까지 발행 후 중단되었습니다.', monthly_desc_5: '엔트리의 교육자료는 교육자료 페이지에서 만나보세요.', monthly_entry: '월간 엔트리', me_desc_1: '매월 발간되는 무료 소프트웨어 교육잡지', me_desc_2: '월간엔트리를 만나보세요!', solve_desc_1: '게임을 하듯 미션을 해결하며', solve_desc_2: '소프트웨어의 기본 원리를 배워보세요!', playSw_desc_1: 'EBS 방송영상, 특별영상을 통해', playSw_desc_2: '소프트웨어를 배워보세요!', recommended_lessons: '추천 강의 모음', recommended_lessons_1: '따라하고, 도전하고, 퀴즈도 풀며 재미있게 엔트리 프로그래밍을 배워보세요!', recommended_lessons_2: '추천 강의 모음을 만나보세요!', offline_top_desc_1: '오프라인 버전의 저장 기능이 향상되고 보안이 강화되었습니다.', offline_top_desc_2: '지금 바로 다운받으세요', offline_main_desc: '엔트리 오프라인 에디터 업데이트!!', art_description: '엔트리로 만든 작품을 공유하는 공간입니다. 작품을 만들고 공유에 참여해 보세요.', art_description_1: '엔트리로 총 ', art_description_2: '개의 작품이 만들어졌습니다. 작품을 만들고 공유해 보세요.', study_index: '엔트리에서 제공하는 주제별, 학년별 학습과정을 통해 차근차근 소프트웨어를 배워보세요!', study_for_beginner: '처음 시작하는 사람들을 위한 엔트리 첫걸음', entrybot_desc_3: '안내에 따라 블록 명령어를 조립하여', entrybot_desc_4: '엔트리봇을 학교에 데려다 주세요.', move_entrybot: '엔트리봇 움직이기', can_change_entrybot_1: '블록 명령어로 엔트리봇의 색을 바꾸거나', can_change_entrybot_2: '말을 하게 할 수도 있어요.', learning_process_by_topics: '주제별 학습과정', show_detail: '자세히 보기', solve_mission: '미션 해결하기', solve_mission_desc_1: '게임을 하듯 미션을 해결하며 프로그래밍의 원리를 익혀보세요!', solve_mission_desc_2: '미로 속의 엔트리봇을 목적지까지 움직이며 순차, 반복, 선택, 비교연산 등의 개념을 자연스럽게 익힐 수 있어요.', learning_process_by_grades: '학년별 학습과정', learning_process_by_grades_sub1: '4가지 유형으로 쉽고 재미있게 배우는 프로그래밍의 원리! 지금 시작해보세요!', e3_to_e4: '초등 3-4 학년', e5_to_e6: '초등 5-6 학년', m1_to_m3: '중등 이상', make_using_entry: '엔트리로 만들기', make_using_entry_desc_1: '블록을 쌓아 여러 가지 소프트웨어를 만들어보세요!', make_using_entry_desc_2: '제공되는 교재를 다운받아 차근차근 따라하다보면 애니메이션, 미디어아트, 게임 등 다양한 작품을 만들 수 있어요.', make_through_ebs_1: 'EBS 방송영상으로 소프트웨어를 배워보세요.', make_through_ebs_2: '방송영상은 물론, 차근차근 따라 할 수 있는 특별영상과 함께 누구나 쉽게 다양한 소프트웨어를 만들 수 있어요.', support_block_js: '블록 코딩과 자바스크립트 언어를 모두 지원합니다.', study_ebs_title_1: '순서대로! 차례대로!', study_ebs_desc_1: '[실습] 엔트리봇의 심부름', study_ebs_title_2: '쉽고 간단하게!', study_ebs_desc_2: '[실습] 꽃송이 만들기', study_ebs_title_3: '언제 시작할까?', study_ebs_desc_3: '[실습] 동물가족 소개', study_ebs_title_4: '다른 선택, 다른 결과!', study_ebs_desc_4: '[실습] 텔레파시 게임', study_ebs_title_5: '정보를 담는 그릇', study_ebs_desc_5: '[실습] 덧셈 로봇 만들기', study_ebs_title_6: '요모조모 따져 봐!', study_ebs_desc_6: '[실습] 복불복 룰렛', study_ebs_title_7: '번호로 부르면 편해요!', study_ebs_desc_7: '[실습] 나만의 버킷리스트', study_ebs_title_8: '무작위 프로그램을 만들어라!', study_ebs_desc_8: '[실습] 무작위 캐릭터 만들기', study_ebs_title_9: '어떻게 찾을까?', study_ebs_desc_9: '[실습] 도서관 책 검색', study_ebs_title_10: '줄을 서시오!', study_ebs_desc_10: '[실습] 키 정렬 프로그램', event: '이벤트', divide: '분기', condition: '조건', random_number: '무작위수', search: '탐색', sorting: '정렬', parallel: '병렬', signal: '신호', input_output: '입출력', sequential: '순차', repeat: '반복', choice: '선택', repeat_advanced: '반복(횟수+조건)', function: '함수', compare_operation: '비교연산', arithmetic: '산술연산', entry_recommended_mission: '엔트리 추천 미션', more_mission: '더 많은 미션 보러가기', line_rangers_title: '라인레인저스와\n샐리 구하기', line_rangers_content: '메피스토 기지에 갇힌\n샐리를 구해주세요!', pinkbean_title_string_basic: '메이플스토리 초급 헤네시스', pinkbean_title_string_intermediate: '메이플스토리 중급 엘리니아', pinkbean_title_string_advanced: '메이플스토리 고급 엘나스', pinkbean_title: '핑크빈과 함께 신나는\n메이플 월드로!', pinkbean_content: '핑크빈이 메이플 월드 모험을\n무사히 마칠 수 있도록 도와주세요.', entrybot_school: '엔트리봇 학교 가는 길', entrybot_school_desc_1: '엔트리봇이 책가방을 챙겨 학교에', entrybot_school_desc_2: '도착할 수 있도록 도와주세요!', robot_factory: '로봇 공장', robot_factory_desc_1: '로봇공장에 갇힌 엔트리봇!', robot_factory_desc_2: '탈출하기 위해 부품을 모두 모아야해요.', electric_car: '전기 자동차', electric_car_desc_1: '엔트리봇 자동차가 계속 앞으로 나아갈 수', electric_car_desc_2: '있도록 연료를 충전해 주세요.', forest_adventure: '숲속 탐험', forest_adventure_desc_1: '엔트리봇 친구가 숲속에 갇혀있네요!', forest_adventure_desc_2: '친구를 도와주세요.', town_adventure: '마을 탐험', town_adventure_desc_1: '배고픈 엔트리봇을 위해 마을에 있는', town_adventure_desc_2: '연료를 찾아주세요.', space_trip: '우주 여행', space_trip_desc_1: '우주탐사를 마친 엔트리봇!', space_trip_desc_2: '지구로 돌아갈 수 있도록 도와주세요.', learn_programming_mission: '미션을 해결하며 배우는 프로그래밍', make_open_lecture: '오픈 강의 만들기', group_created: '만든 학급', group_signup: '가입한 학급', delete_from_list: '을(를) 목록에서 삭제하시겠습니까?', delete_from_list_en: '', lecture_collection: '강의 모음', edit_mypage_profile: '자기소개 정보 관리', main_image: '메인 이미지', edit_profile_success: '반영되었습니다.', no_project_1: '내가 만든 작품이 없습니다.', no_project_2: '지금 작품 만들기를 시작해보세요!', empty_project_1: '아직 만들어진 작품이 없습니다.', no_marked_project_1: '관심 작품이 없습니다.', no_marked_group_project_1: '학급 관심 작품이 없습니다.', no_marked_project_2: "'작품 공유하기'에서 다양한 작품을 만나보세요!", no_markedGroup_project_2: "'학급 공유하기'에서 다양한 작품을 만나보세요!", view_project_all: '작품 구경하기', no_lecture_1: '내가 만든 강의가 없습니다.', empty_lecture_1: '아직 만들어진 강의가 없습니다.', no_lecture_2: "'오픈 강의 만들기'에서 강의를 만들어보세요!", no_marked_lecture_1: '관심 강의가 없습니다.', no_marked_group_lecture_1: '학급 관심 강의가 없습니다.', no_marked_lecture_2: "'오픈 강의'에서 다양한 강의를 만나보세요!", view_lecture: '강의 살펴보기', no_studying_lecture_1: '학습 중인 강의가 없습니다.', no_studying_lecture_2: "'오픈 강의'에서 학습을 시작해보세요!", no_lecture_collect_1: '내가 만든 강의 모음이 없습니다.', empty_lecture_collect_1: '아직 만들어진 강의 모음이 없습니다.', no_lecture_collect_2: "'오픈 강의 모음 만들기'에서 강의 모음을 만들어보세요!", make_lecture_collection: '강의 모음 만들기', no_marked_lecture_collect_1: '관심 강의 모음이 없습니다.', no_marked_lecture_group_collect_1: '학급 관심 강의 모음이 없습니다.', no_marked_lecture_collect_2: "'오픈 강의'에서 다양한 강의를 만나보세요!", view_lecture_collection: '강의 모음 살펴보기', no_studying_lecture_collect_1: '학습 중인 강의 모음이 없습니다.', no_studying_lecture_collect_2: "'오픈 강의'에서 학습을 시작해보세요!", my_lecture: '나의 강의', markedGroup: '학급 관심', markedGroup_lecture: '학급 관심 강의', markedGroup_curriculum: '학급 관심 강의모음', marked_lecture: '관심 강의', marked_lecture_collection: '나의 관심 강의 모음', marked_marked_curriculum: '관심 강의 모음', studying_lecture: '학습 중인 강의', completed_lecture: '학습 완료 강의', my_lecture_collection: '나의 강의 모음', my: '나의', studying_lecture_collection: '학습 중인 강의 모음', completed_lecture_collection: '학습 완료한 강의 모음', my_curriculum: '나의 강의 모음', studying_curriculum: '학습 중인 강의 모음', completed_curriculum: '학습 완료한 강의 모음', materialCC: '엔트리에서 제공하는 모든 교육 자료는 CC-BY 2.0 라이선스에 따라 자유롭게 이용할 수 있습니다.', materialccby_new: '엔트리의 교육자료는 CC-BY 2.0 라이선스에 따라 출처를 밝히고 자유롭게 이용할 수 있습니다.', entry_copyright_info: '엔트리 저작권 가이드 보기', pdf: 'PDF', helper: '도움말', youtube: '영상', tvcast: '영상', goal: '목표', basicproject: '시작단계', hw: '하드웨어', object: '오브젝트', console: '콘솔', download_info: '모든 교육자료는 각각의 제목을 클릭 하시면 다운받으실 수 있습니다.', entry_materials_all: '엔트리 교육자료 모음', entry_material: '엔트리 교육자료', recommand_grade: '추천학년', g3_4_grades: '3-4 학년', g5_6_grades: '5-6 학년', middle_grades: '중학생 이상', entry_go_go: '엔트리 고고!', entry_go_go_desc: '학년별, 난이도 별로 준비된 교재를 만나보세요.', entry_go_go_desc2: '각 과정별로 교육과정, 학습지, 교사용 해설서 3종 세트가 제공됩니다.', stage_beginner: '초급', stage_middle: '중급', stage_high: '고급', middle_school_short: '중등', learn_entry_programming: '따라하며 배우는 엔트리 프로그래밍', entry_programming_desc: '차근차근 따라 하다 보면 어느새 나도 엔트리 고수!', ebs: 'EBS', ebs_material_desc: '방송 영상과 교사용 지도서를 활용하여 수업을 해보세요!', season_1_material: '시즌1 교사용 지도서', season_2_material: '시즌2 교사용 지도서', season_1: '시즌1', playsoftware_ebs: 'EBS 소프트웨어야 놀자!', material_teacher_guide: '교사용 지도서', season_2: '시즌2', compute_think_textbook: '교과서로 배우는 컴퓨팅 사고력', computational_sw: '국어, 수학, 과학, 미술... 학교에서 배우는 다양한 교과와 연계하여 SW를 배워보세요!', python_coding_text: '엔트리파이선', python_coding_textbook: '텍스트 코딩 세계로 떠나는 여행! 엔트리파이선', python_coding_desc: '엔트리파이선으로 텍스트 언어의 구조와 문법을 자연스럽게 배워보세요!', entry_x_hardware_text: '엔트리 X 하드웨어 교육자료', entry_x_hardware: '엔트리 X 하드웨어 교육자료 모음', e_sensor: 'E 센서보드', e_sensor_board: 'E 센서보드', e_sensor_robot: 'E 센서로봇', arduino: '아두이노', arduinoext: '아두이노 Uno 확장모드', arduinonano: '아두이노 Nano', albert: '알버트', orange_board: '오렌지보드', arduino_board: '아두이노', joystick: '조이스틱 센서 쉴드', ardublock: '아두블럭', mkboard: '디지털 몽키보드', mechatro_nano: '메카트로 나노+', mechatro_uno: '메카트로 우노+', memaker: '미메이커', edumaker: '에듀메이커 보드', codingtoolbox: '코딩툴박스', materials_etc_all: '기타 교육자료 모음', materials_teaching: '교원 연수 자료', materials_etc: '기타 참고 자료', materials_etc_resource: '참고 자료', materials_teaching_etc: '교원 연수 및 참고자료', materials_teaching_1: 'SW교육의 필요성과 교육 방법론', materials_teaching_2: '엔트리와 함께하는 언플러그드 활동', materials_teaching_3: '게임하듯 알고리즘을 배우는 엔트리 미션 해결하기', materials_teaching_4: '실생활 문제해결을 위한 엔트리 프로그래밍', materials_teaching_5: '교과연계 SW교육1 (미술,수학,사회)', materials_teaching_6: '교과연계 SW교육2 (국어,과학,음악)', materials_teaching_7: '피지컬 컴퓨팅 실습1(E센서보드)', materials_teaching_8: '피지컬 컴퓨팅 실습2(햄스터)', materials_teaching_9: '수업에 필요한 학급/강의 기능 알아보기', materials_etc_1: '엔트리 첫 사용자를 위한 스타트 가이드', materials_etc_2: '수업에 바로 활용할 수 있는 다양한 콘텐츠 모음집', materials_etc_3: '월간 엔트리', materials_etc_4: '엔트리 설명서', materials_etc_5: '엔트리 소개 자료', materials_etc_6: '엔트리 블록 책받침', materials_etc_7: '엔트리파이선 예제 및 안내', jr_if_1: '만약', jr_if_2: '앞에 있다면', jr_fail_no_pencil: '이런 그곳에는 연필이 없어. 연필이 있는 곳에서 사용해보자~', jr_fail_forgot_pencil: '앗! 책가방에 넣을 연필을 깜빡했어. 연필을 모아서 가자~', jr_fail_much_blocks: '너무많은 블록을 사용했어, 다시 도전해볼래?', cparty_jr_success_1: '좋아! 책가방을 챙겼어!', go_right: '오른쪽', go_down: ' 아래쪽', go_up: ' 위쪽', go_left: ' 왼쪽', go_forward: '앞으로 가기', jr_turn_left: '왼쪽으로 돌기', jr_turn_right: '오른쪽으로 돌기', go_slow: '천천히 가기', repeat_until_reach_1: '만날 때 까지 반복하기', repeat_until_reach_2: '', pick_up_pencil: '연필 줍기', repeat_0: '', repeat_1: '반복', when_start_clicked: '시작 버튼을 눌렀을 때', age_0: '작품체험', create_character: '캐릭터 만들기', age_7_9: '초등 저학년', going_school: '엔트리 학교가기', age_10_12_1: '초등 고학년1', collect_parts: '로봇공장 부품모으기', age_10_12_2: '초등 고학년2', driving_elec_car: '전기자동차 운전하기', age_13: '중등', travel_space: '우주여행하기', people: '사람', all: '전체', life: '일상생활', nature: '자연', animal_insect: '동물/곤충', environment: '자연환경', things: '사물', vehicles: '이동수단', others: '기타', fantasy: '판타지', instrument: '악기', piano: '피아노', marimba: '마림바', drum: '드럼', janggu: '장구', sound_effect: '효과음', others_instrument: '기타타악기', aboutEntryDesc_1: '엔트리는 누구나 무료로 소프트웨어 교육을 받을 수 있는 플랫폼입니다.', aboutEntryDesc_2: '학생들이 소프트웨어를 쉽고 재미있게 학습하고,', aboutEntryDesc_3: '선생님들은 효과적으로 학생들을 가르칠 수 있습니다.', aboutEntryDesc_4: '엔트리는 공공재와 같이', aboutEntryDesc_5: '비영리로 운영됩니다.', viewProjectTerms: '이용정책 보기', openSourceTitle: '오픈소스를 통한 생태계 조성', openSourceDesc_1: '엔트리의 소스코드 뿐 아니라', openSourceDesc_2: '모든 교육 자료는 CC라이센스를 ', openSourceDesc_3: '적용하여 공개합니다.', viewOpenSource: '오픈소스 보기', eduPlatformTitle: '국내교육 현장에 맞는 교육 플랫폼', eduPlatformDesc_1: '국내 교육 현장에 적합한 교육 도구가', eduPlatformDesc_2: '될 수 있도록 학교 선생님들과 함께', eduPlatformDesc_3: '개발하고 있습니다.', madeWith: '자문단', researchTitle: '다양한 연구를 통한 전문성 강화', researchDesc_1: '대학/학회 등과 함께 다양한 연구를', researchDesc_2: '진행하여 전문성을 강화해나가고', researchDesc_3: '있습니다.', viewResearch: '연구자료 보기', atEntry: '엔트리에서는', entryLearnDesc_1: '재미있게 배우는 학습공간', entryLearnDesc_2: '<학습하기>에서는 엔트리를 학습할 수 있는 콘텐츠가 준비되어 있습니다.', entryLearnDesc_3: '게임을 하듯이 주어진 미션을 프로그래밍으로 해결하고 영상을 시청하며 ', entryLearnDesc_4: '소프트웨어 제작 원리를 학습할 수 있습니다.', entryMakeDesc_1: '<만들기>에서는 미국 MIT에서 개발한 Scratch와 같은 블록형 프로그래밍 언어를', entryMakeDesc_2: '사용하여 프로그래밍을 처음 접하는 사람들도 쉽게 자신만의 창작물을 만들 수 있습니다.', entryMakeDesc_3: "또한 블록 코딩과 텍스트 코딩의 중간다리 역할을 하는 '엔트리파이선' 모드에서는", entryMakeDesc_4: '텍스트 언어의 구조와 문법을 자연스럽게 익힐 수 있습니다.', entryMakeDesc_5: '', entryShareDesc_1: '<공유하기>에서는 엔트리를 통해 제작한 작품을 다른 사람들과 공유할 수 있습니다.', entryShareDesc_2: '또한 공유된 작품이 어떻게 구성되었는지 살펴보고 발전시켜 자신만의 작품을 만들 수', entryShareDesc_3: '있습니다. 공동 창작도 가능하여 친구들과 협업해 더 멋진 작품을 만들어 볼 수 있습니다.', entryGroup: '학급기능', entryGroupTitle: '우리 반 학습 공간', entryGroupDesc_1: '<학급기능>은 선생님이 학급별로 학생들을 관리할 수 있는 기능입니다. 학급끼리 학습하고', entryGroupDesc_2: '작품을 공유할 수 있으며 과제를 만들고 학생들의 결과물을 확인할 수 있습니다.', entryGroupDesc_3: '또한 선생님은 강의 기능을 활용하여 학생들의 수준에 맞는 학습환경을', entryGroupDesc_4: '맞춤형으로 제공함으로써 효율적이고 편리하게 수업을 진행할 수 있습니다.', entryGroupDesc_5: '', unpluggedToPhysical: '언플러그드 활동부터 피지컬 컴퓨팅까지', algorithmActivity: '기초 알고리즘', programmignLang: '교육용 프로그래밍 언어', unpluggedDesc_1: '엔트리봇 보드게임과 카드게임을 통해 컴퓨터 없이도', unpluggedDesc_2: '소프트웨어의 기본 개념과 원리(순차, 반복, 선택, 함수)를 익힐 수 있습니다.', entryMaze: '엔트리봇 미로탈출', entryAI: '엔트리봇 우주여행', algorithmDesc_1: '게임을 하듯이 미션을 해결하고 인증서를 받아보세요.', algorithmDesc_2: '소프트웨어의 기본적인 원리를 쉽고 재미있게 배울 수 있습니다.', programmingLangDesc_1: '엔트리에서는 블록을 쌓듯이 프로그래밍을 하기 때문에 누구나 쉽게', programmingLangDesc_2: '자신만의 게임, 애니메이션, 미디어아트와 같은 멋진 작품을 만들고 공유할 수 있어 교육용으로 적합합니다.', viewSupporHwVideo: '하드웨어 가이드 영상 보기', viewSupporHw: '연결되는 하드웨어 보기', supportHwDesc_1: '엔트리와 피지컬 컴퓨팅 도구를 연결하면 현실세계와 상호작용하는 멋진 작품들을 만들어낼 수 있습니다.', supportHwDesc_2: '국내, 외 다양한 하드웨어 연결을 지원하며, 계속적으로 추가될 예정입니다.', entryEduSupport: '엔트리 교육 지원', eduSupportDesc_1: '엔트리에서는 소프트웨어 교육을 위한 다양한 교육 자료를 제작하여 무상으로 배포하고 있습니다.', eduSupportDesc_2: '모든 자료는 교육자료 페이지에서 다운받으실 수 있습니다.', materials_1_title: '수준별 교재', materials_1_desc_1: '학년별 수준에 맞는 교재를 통해 차근차근', materials_1_desc_2: '따라하며 쉽게 엔트리를 익혀보세요!', materials_2_title: 'EBS 방송 연계 교안', materials_2_desc_1: 'EBS 소프트웨어야 놀자 방송과 함께', materials_2_desc_2: '교사용 수업 지도안을 제공합니다.', materials_3_title: '초, 중등 교과 연계 수업자료', materials_3_title_2: '', materials_3_desc_1: '다양한 과목에서 만나는 실생활 문제를', materials_3_desc_2: '컴퓨팅 사고력으로 해결해 보세요.', moreMaterials: '더 많은 교육 자료 보러가기', moreInfoAboutEntry_1: '더 많은 엔트리의 소식들을 확인하고 싶다면 아래의 링크들로 접속해보세요.', moreInfoAboutEntry_2: '교육자료 외에도 다양한 SW 교육과 관련한 정보를 공유하고 있습니다.', material_menu_type_robot: '로봇형', material_menu_type_module: '모듈형', material_menu_type_board: '보드형', blog: '블로그', post: '포스트', tvCast: 'TV캐스트', about_entry_pre: '엔트리', about_youtube: '유튜브', about_facebook: '페이스북', albertSchool: '알버트 스쿨버전', arduinoBoard: '아두이노 정품보드', arduinoCompatible: '아두이노 호환보드', bitBlock: '비트블록', bitbrick: '비트브릭', creamo: '크리모', playcode: '플레이코드', funboard: '펀보드', truerobot: '뚜루뚜루', bingle: '빙글', bingles: '빙글S', codeino: '코드이노', epor: '에뽀', petrone_v2: '페트론V2', petrone_v2_drone: '드론', petrone_v2_car: '자동차', 'e-sensor': 'E-센서보드', 'e-sensorUsb': 'E-센서보드(유선연결)', 'e-sensorBT': 'E-센서보드(무선연결)', mechatronics_4d: '4D 메카트로닉스', esensor_board: 'E - 센서보드', esensor_robot: 'E - 센서로봇', awesomebot: '어썸봇', hamster: '햄스터', hummingbird: '허밍버드 듀오', roboid: '로보이드', turtle: '거북이', littlebits: '리틀비츠', orangeBoard: '오렌지 보드', robotis_carcont: '로보티즈 로봇자동차', robotis_IoT: '로보티즈 IoT', robotis_IoT_Wireless: '로보티즈 IoT(무선연결)', dplay: '디플레이', iboard: '아이보드', nemoino: '네모이노', xbot_epor_edge: '엑스봇(원터치 동글/USB)', XbotBT: '엑스봇 에뽀/엣지 블투투스', robotori: '로보토리', rokoboard: '로코보드', neobot: '네오봇', neobot_sensor_theme: '네오봇 센서 테마', mechatro: '메카트로', about: '알아보기', articles: '토론하기', gallery: '구경하기', learn: '학습하기', login: '로그인', logout: '로그아웃', make: '만들기', register: '가입하기', Join: '회원가입', Edit_info: '내 정보 수정', Discuss: '글 나누기', Explore: '구경하기', Load: '불러오기', My_lesson: '오픈 강의', textbook_learning: '교과서 학습하기', Resources: '교육 자료', play_software: '소프트웨어야 놀자!', problem_solve: '엔트리 학습하기', learning_textbook: '교과서 학습하기', context_textbook: '초등 교과서 그대로 선생님은 학교 수업을 학생은 집에서 예습, 복습을 할 수 있어요.', info_banner_textbook: '* 출판사는 가나다순 노출입니다.', banner_textbook: '더욱 다양하고', banner_textbook_2: '재미있는 학습을 하고 싶다면?', banner_textbook_right_banner: '학생용 활동지와 교사용', banner_textbook_right_banner2: '학습 도움 자료가 필요하신가요?', banner_textbook_right_banner_btn: '교과서별 자료 받기', Learn: '학습하기', teaching_tools: '엔트리 교구', about_entry: '엔트리 소개', what_entry: '엔트리는?', create: '만들기', create_new: '새로 만들기', start_programming: '소프트웨어 교육의 첫걸음', Entry: '엔트리', intro_learning: '누구나 쉽고 재밌게 소프트웨어를 배울 수 있어요. ', intro_learning_anyone: '지금 바로 시작해보세요! ', start_now: 'For Free, Forever.', welcome_entry: '엔트리에 오신걸 환영합니다.', student: '학생', non_menber: '일반인', teacher: '선생님', terms_conditions: '이용약관', personal_information: '개인정보 수집 및 이용에 대한 안내', limitation_liability: '책임의 한계와 법적 고지', entry_agree: '엔트리의 이용약관에 동의 합니다.', info_agree: '개인정보 수집 및 이용에 동의합니다.', next: '다음', enter_individual_info: '개인정보 입력', enter_id: '아이디 입력', enter_password: '비밀번호 입력', confirm_password: '비밀번호 확인', enter_password_again: '비밀번호를 한번 더 입력하세요.', validation_password: '5자 이상의 영문/숫자 등을 조합하세요.', validation_id: '4~20자의 영문/숫자를 조합하세요', prev: '이전', born_year: '태어난 연도', select_born: '태어난 연도를 선택 하세요', year: '년', gender: '성별', choose_gender: '성별을 선택 하세요', male: '남성', female: '여성', language: '언어', best_language: '주 언어를 선택 하세요', korean: '한국어', english: '영어', viet: '베트남', japan: '일본어', russia: '러시아어', korean_s: '한국어', english_s: '영어', japan_s: '일본어', chinese_simplified: '중국어(간체)', chinese_traditional: '중국어(번체)', option_email: '이메일(선택)', insert_email: '이메일 주소를 입력 하세요', sign_up_complete: '회원 가입이 완료 되었습니다', agree_terms_conditions: '이용약관에 동의해 주세요.', agree_personal_information: '개인정보 수집 및 이용에 대한 안내에 동의해 주세요.', insert_studying_stage: '작품을 공유하고 싶은 학급을 선택해 주세요.', insert_born_year: '태어난 연도를 입력해 주세요.', insert_gender: '성별을 선택지에서 선택해 주세요.', select_language: '언어를 선택해 주세요.', check_email: '이메일 형식을 확인해 주세요.', already_exist_id: '이미 존재하는 아이디 입니다.', id_validation_id: '아이디는 4~20자의 영문/숫자를 조합하세요', password_validate_pwd: '패스워드는 5자 이상의 영문/숫자 등을 조합하세요.', password_validate_pwd_length: '패스워드는 최소 5자 이상으로 입력해 주세요.', neoid_username_same_id: '이미 사용중인 아이디 입니다.(NEOID)', captcha_error: '자동입력 방지문자가 올바르지 않습니다.', captcha_try_after_10min: '10분뒤에 다시 시도해주세요', captcha_limit: '새로고침 제한 횟수에 도달했습니다.', insert_same_pwd: '같은 비밀번호를 입력해 주세요.', studying_stage_group: '작품 공유 학급', studying_stage: '작품을 공유하고 싶은 학급을 선택해 주세요.', password: '비밀번호 입력', save_id: '아이디 저장', auto_login: '자동 로그인', enter_id_pw: '아이디, 비밀번호 입력', forgot_password: '아이디와 비밀번호가 기억나지 않으세요 ?', did_not_join: '아직 엔트리 회원이 아니세요?', go_join: '회원가입하기 ', renew_index_text_00: '엔트리 교과서 학습하기', renew_index_text_01: '교과서로 엔트리를 배워보세요.', renew_index_text_02: '초등학교 교과서 강의를 통해', renew_index_text_02_2: '엔트리를 배워보세요!', renew_index_text_03: '교과서 학습하기', renew_index_text_03_2: '바로가기', renew_index_text_1: '2019년, 엔트리가 바뀝니다', renew_index_text_2: '확 바뀐 작품 만들기', renew_index_text_3: '지금 새로운 기능을 확인하고', renew_index_text_3_2: 'PC와 태블릿으로 작품을 만들어보세요!', renew_index_text_4: '자세히 보기', first_step: '소프트웨어 교육의 첫걸음', entry_content_one: '상상했던 것들을 블록 놀이하듯 하나씩 쌓아보세요.', entry_content_two: '게임, 애니메이션, 미디어아트와 같은 멋진 작품이 완성된답니다!', entry_content_three: '재미있는 놀이로 배우고, 나만의 멋진 작품을 만들어 친구들과 공유할 수 있는 멋진 엔트리의 세상으로 여러분을 초대합니다!', funny_space: '재미있게 배우는 학습공간', in_learn_section: '< 학습하기 > 에서는', learn_problem_solving: '컴퓨터를 활용해 논리적으로 문제를 해결할 수 있는 다양한 학습 콘텐츠가 준비되어 있습니다. 게임을 하듯이 주어진 미션들을 프로그래밍으로 해결해볼 수도 있고 재미있는 동영상으로 소프트웨어의 원리를 배울 수도 있습니다 .', joy_create: '창작의 즐거움', in_make: '< 만들기 > 는', make_contents: '미국 MIT에서 개발한 Scratch와 같은 비주얼 프로그래밍 언어를 사용하여 프로그래밍을 처음 접하는 사람들도 쉽게 나만의 창작물을 만들 수 있습니다. 또 엔트리를 통해 만들 수 있는 컨텐츠의 모습은 무궁무진합니다. 과학 시간에 배운 물리 법칙을 실험해 볼 수도 있고 좋아하는 캐릭터로 애니메이션을 만들거나 직접 게임을 만들어 볼 수 있습니다.', and_content: '또 엔트리를 통해 만들 수 있는 콘텐츠의 모습은 무궁무진합니다. 과학 시간에 배운 물리 법칙을 실험해 볼 수도 있고 좋아하는 캐릭터로 애니메이션을 만들거나 직접 게임을 만들어 볼 수 있습니다.', share_collaborate: '공유와 협업', explore_contents: '< 구경하기 > 에서는 엔트리를 통해 제작한 작품을 다른 사람들과 쉽게 공유할 수 있습니다. 또한 공유된 작품이 어떻게 구성되었는지 살펴볼 수 있고, 이를 발전시켜 자신만의 프로젝트를 만들 수 있습니다. 그리고 엔트리에서는 공동 창작도 가능합니다. 친구들과 협업하여 더 멋진 프로젝트를 만들어볼 수 있습니다.', why_software: '왜 소프트웨어 교육이 필요할까?', speak_obama_contents: '컴퓨터 과학을 배우는 것은 단지 여러분의 미래에만 중요한 일이 아닙니다. 이것은 우리 미국의 미래를 위해 중요한 일 입니다.', obama: '버락 오바마', us_president: '미국 대통령', billgates_contents: '컴퓨터 프로그래밍은 사고의 범위를 넓혀주고 더 나은 생각을 할 수 있게 만들며 분야에 상관없이 모든 문제에 대해 새로운 해결책을 생각할 수 있는 힘을 길러줍니다.', billgates: '빌게이츠', chairman_micro: 'Microsoft 회장', eric_contents: '현재 디지털 혁명은 지구상 대부분의 사람들에게 아직 시작도 안된 수준입니다. 프로그래밍을 통해 향후 10년간 모든 것이 변화할 것 입니다.', eric: '에릭 슈미츠', sandbug_contents: '오늘날 컴퓨터 과학에 대한 이해는 필수가 되었습니다. 우리의 국가 경쟁력은 우리가 아이들에게 이것을 얼마나 잘 가르칠 수 있느냐에 달려있습니다.', sandbug: '쉐릴 샌드버그', view_entry_tools: '엔트리와 함께할 수 있는 교구들을 살펴볼 수 있습니다.', solve_problem: '미션 해결하기', solve_problem_content: '게임을 하듯 미션을 하나 하나 해결하며 소프트웨어의 기본 원리를 배워보세요!', find_extra_title: '엔트리봇 부품 찾기 대작전', all_ages: '전 연령', total: '총', step: '단계', find_extra_contents: '로봇 강아지를 생산하던 루츠 공장에 어느 날 갑자기 일어난 정전 사태로 태어난 특별한 강아지 엔트리 봇. 아직 조립이 덜 된 나머지 부품들을 찾아 공장을 탈출 하도록 도와주면서 소프트웨어의 동작 원리를 익혀보자!', software_play_contents: "EBS에서 방영한 '소프트웨어야 놀자' 프로그램을 실습해볼 수 있습니다.", resources_contents: '엔트리를 활용한 다양한 교육자료들을 무료로 제공합니다.', from: ' 출처', sw_camp: '미래부 SW 창의캠프', elementary: '초등학교', middle: '중학교', grades: '학년', lesson: '차시', sw_contents_one: '5차시 분량으로 초등학생이 엔트리와 피지컬 컴퓨팅을 경험할 수 있는 교재입니다. 학생들은 엔트리 사용법을 학습하고, 그림판과 이야기 만들기를 합니다. 마지막에는 아두이노 교구를 활용하여 키보드를 만들어보는 활동을 합니다.', sw_camp_detail: '미래창조과학부 SW창의캠프', sw_contents_two: '5차시 분량으로 중학생이 엔트리와 피지컬 컴퓨팅을 경험할 수 있는 교재입니다. 학생들은 엔트리 사용법을 학습하고, 미로찾기 게임과, 퀴즈 프로그램을 만들어 봅니다. 마지막에는 아두이노 교구를 활용하여 키보드로 자동차를 조종하는 활동을 합니다.', sw_contents_three: "선생님들이 학교에서 시작할 수 있는 소프트웨어 수업 지도서입니다. 다양한 언플러그드 활동과, '소프트웨어야 놀자' 방송을 활용한 수업 지도안이 담겨 있습니다.", naver_sw: 'NAVER 소프트웨어야 놀자', teacher_teaching: '교사용지도서 (초등학교 5~6학년 이상)', funny_sw: '즐거운 SW놀이 교실', sw_contents_four: '소프트웨어를 놀이하듯 재미있게 배울 수 있는 교재로 엔트리보드게임을 비롯한 다양한 언플러그드 활동과 엔트리 학습모드로 소프트웨어를 만드는 기본 원리를 배우게 됩니다. 기본 원리를 배웠다면 학생들은 이제 엔트리로 이야기, 게임, 예술작품, 응용프로그램을 만드는 방법을 배우고, 자신이 생각한 소프트웨어를 만들고 발표할 수 있도록 교재가 구성되어 있습니다.', ct_text_5: '교과서와 함께 키우는 컴퓨팅 사고력', teacher_grade_5: '교원 (초등학교 5학년)', ct_text_5_content: '실생활의 문제를 해결하자는 테마로 준비된 총 8개의 학습콘텐츠가 담긴 교사용 지도안입니다. 각 콘텐츠는 개정된 교육과정을 반영한 타교과와의 연계를 통해 다양한 문제를 만나고 해결해볼 수 있도록 설계되었습니다. 아이들이 컴퓨팅 사고력을 갖춘 융합형 인재가 될 수 있도록 지금 적용해보세요!', ct_text_6: '교과서와 함께 키우는 컴퓨팅 사고력', teacher_grade_6: '교원 (초등학교 6학년)', ct_text_6_content: '실생활의 문제를 해결하자는 테마로 준비된 총 8개의 학습콘텐츠가 담긴 교사용 지도안입니다. 각 콘텐츠는 개정된 교육과정을 반영한 타교과와의 연계를 통해 다양한 문제를 만나고 해결해볼 수 있도록 설계되었습니다. 아이들이 컴퓨팅 사고력을 갖춘 융합형 인재가 될 수 있도록 지금 적용해보세요!', sw_use: '모든 교재들은 비영리 목적에 한하여 저작자를 밝히고 자유롭게 이용할 수 있습니다.', title: '제목', writer: '작성자', view: '보기', date: '등록일', find_id_pwd: '아이디와 비밀번호 찾기', send_email: '비밀번호를 잊은 경우 이메일로 비밀번호를 찾을 수 있습니다.', user_not_exist: '존재하지 않는 이메일 주소 입니다.', not_signup: '아직 회원이 아니세요?', send: '발송하기', sensorboard: '엔트리봇 센서보드', physical_computing: '피지컬 컴퓨팅', sensorboard_contents: '아두이노를 사용하기 위해서 더 이상 많은 케이블을 사용해 회로를 구성할 필요가 없습니다. 엔트리 보드는 아두이노 위에 끼우기만 하면 간단하게 LED, 온도센서, 소리센서, 빛, 슬라이더, 스위치를 활용할 수 있습니다. 이제 엔트리 보드를 활용해 누구라도 쉽게 자신만의 특별한 작품을 만들어보세요!', entrybot_boardgame: '엔트리봇 보드게임', unplugged: '언플러그드 활동', unplugged_contents: '재밌는 보드게임을 통해 컴퓨터의 작동 원리를 배워보세요. 로봇강아지인 엔트리봇이 정전된 공장에서 필요한 부품을 찾아 탈출하도록 돕다보면 컴퓨터 전문가처럼 문제를 바라 볼 수 있게됩니다.', entrybot_cardgame: '엔트리봇 카드게임 : 폭탄 대소동', entrybot_cardgame_contents: '갑자기 엔트리도시에 나타난 12종류의 폭탄들! 과연 폭탄들을 안전하게 해체할 수 있을까요? 폭탄들을 하나씩 해체하며 엔트리 블록과 함께 소프트웨어의 원리를 배워봐요! 순차, 반복, 조건을 통해 폭탄을 하나씩 해체하다 보면 엔트리도시를 구한 영웅이 될 수 있답니다!', basic_learn: '엔트리 기본 학습', basic_learn_contents: '엔트리를 활용한 다양한 교육 콘텐츠를 제공합니다.', troubleshooting: '문제해결 학습', playsoftware: '소프트웨어야 놀자', make_own_lesson: '나만의 수업을 만들어 다른 사람과 공유할 수 있습니다.', group_lecture: '우리 반 강의', group_curriculum: '우리 반 강의 모음', group_homework: '우리 반 과제', group_noproject: '전시된 작품이 없습니다.', group_nolecture: '생성된 강의가 없습니다.', group_nocurriculum: '생성된 강의 모음이 없습니다.', lecture_contents: '필요한 기능만 선택하여 나만의 수업을 만들어 볼 수 있습니다.', curriculum_contents: '여러개의 강의를 하나의 강의 모음으로 묶어 차근차근 따라할 수 있는 수업을 만들 수 있습니다.', grade_info: '학년 정보', difficulty: '난이도', usage: '사용요소', learning_concept: '학습개념', related_subject: '연계 교과', show_more: '더보기', close: '닫기', latest: '최신순', viewCount: '조회수', viewer: '조회순', like: '좋아요순', comment: '댓글순', entire_period: '전체기간', today: '오늘', latest_week: '최근 1주일', latest_month: '최근 1개월', latest_three_month: '최근 3개월', current_password: '현재 비밀번호', change_password: '비밀번호 변경', incorrect_password: '비밀번호가 일치하지 않습니다.', incorrect_password_login: '아이디 또는 비밀번호를 잘못 입력하셨습니다.', suspension_user: '이용 정지된 계정입니다.', blocked_user: '승인되지 않은 사용자 입니다.', new_password: '새로운 비밀번호', password_option_1: '영문과 숫자의 조합으로 5자 이상이 필요합니다.', again_new_password: '새로운 비밀번호 재입력', enter_new_pwd: '새로운 비밀번호를 입력하세요.', confirm_new_pwd: '새로운 비밀번호를 확인하세요.', enter_new_pwd_again: '새로운 비밀번호를 다시 입력하세요.', password_match: '비밀번호가 일치하지 않습니다.', incorrect_email: '유효한 이메일이 아닙니다', edit_button: '정보수정', edit_profile: '관리', my_project: '나의 작품', my_group: '나의 학급', mark: '관심 작품', prev_state: '이전', profile_image: '자기소개 이미지', insert_profile_image: '프로필 이미지를 등록해 주세요.', at_least_180: '180 x 180 픽셀의 이미지를 권장합니다.', upload_image: '이미지 업로드', about_me: '자기소개', save_change: '변경사항 저장', basic_image: '기본 이미지', profile_condition: '자기소개를 입력해 주세요. 50자 내외', profile_back: '돌아가기', make_project: '작품 만들기', exhibit_project: '작품 전시하기', art_list_shared: '개인', art_list_group_shared: '학급', gl_mode_boost: '부스트 모드', gl_not_supported: '부스트 모드로 실행할 수 없는 환경입니다.\n확인을 누르면 기본모드로 실행됩니다.', view_project: '코드 보기', code_view: '코드보기', noResult: '검색 결과가 없습니다.', comment_view: '댓글', upload_project: '올리기', edit: '수정', save_complete: '저장', just_like: '좋아요', share: '공유', who_likes_project: '작품을 좋아하는 사람', people_interest: '작품을 관심있어 하는 사람', none_person: '없음', inserted_date: '등록일', last_modified: '최종 수정일', original_project: '원본 작품', for_someone: '님의', original_project_deleted: '원본 작품이 삭제되었습니다.', delete_project: '삭제', delete_group_project: '목록에서 삭제', currnet_month_time: '월', current_day_time: '일', game: '게임', animation: '애니메이션', media_art: '미디어 아트', physical: '피지컬', etc: '기타', connected_contents: '연계되는 콘텐츠', connected_contents_content: '엔트리와 함께 할 수 있는 다양한 콘텐츠를 만나보세요. 처음 소프트웨어를 배우는 사람이라면 쉽게 즐기는 보드게임부터 아두이노와 같은 피지컬 컴퓨팅을 활용하여 자신만의 고급스러운 창작물을 만들어 볼 수 있습니다.', basic_mission: '기본 미션: 엔트리봇 미로찾기', basic_mission_content: '강아지 로봇을 만드는 공장에서 우연한 정전으로 혼자서 생각할 수 있게 된 엔트리봇! 공장을 탈출하고 자유를 찾을 수 있도록 엔트리봇을 도와주세요!', application_mission: '응용미션: 엔트리봇 우주여행', write_article: '글쓰기', write_contest: '제출하기', view_all_articles: '모든 글 보기', view_own_articles: '내가 쓴 글 보기', view_qna_articles: '답변 없는 글 보기', learning_materials: '교육자료', download_materials: '교육자료 내려받기', download_button: '내려받기', download_all: '모두 내려받기', ebs_software_first: '<소프트웨어야 놀자>는 네이버와 EBS가 함께 만든 교육 콘텐츠입니다. 여기에서는 엔트리를 활용하여 실제로 간단한 프로그램을 만들어보며 소프트웨어의 기초 원리를 배워나갈 수 있습니다. 또한 각 콘텐츠에서는 동영상을 통해 컴퓨터과학에 대한 선행지식이 없더라도 충분히 재미와 호기심을 느끼며 진행할 수 있도록 준비되어있습니다.', go_software: '소프트웨어야 놀자 가기', ebs_context: 'EBS 동영상 가기', ebs_context_hello: 'EBS 가기', category: '카테고리', add_picture: '사진첨부', upload_article: '글 올리기', list: '목록', report: '신고하기', upload: '올리기', staff_picks: '스태프 선정', popular_picks: '인기 작품', lecture_header_more: '더 만들어 보기', lecture_header_reset: '초기화', lecture_header_reset_exec: '초기화 하기', lecture_header_restart_button: '다시 시작', lecture_header_save: '저장', lecture_header_save_content: '학습내용 저장하기', lecture_header_export_project: '내 작품으로 저장하기', lecture_header_undo: '취소', lecture_header_redo: '복원', lecture_er_bugs: '버그신고', lecture_container_tab_object: '오브젝트', lecture_container_tab_video: '강의 동영상', lecture_container_tab_project: '완성된 작품', lecture_container_tab_help: '블록 도움말', illigal: '불법적인 내용 또는 사회질서를 위반하는 활동', verbal: '언어 폭력 또는 개인 정보를 침해하는 활동', commertial: '상업적인 목적을 가지고 활동', explicit: '음란물', other: '기타', check_one_more: '하나이상 표기해주세요.', enter_content: '기타의 내용을 입력해 주세요.', report_result: '결과 회신을 원하시면 메일을 입력해 주세요.', report_success: '신고하기가 정상적으로 처리 되었습니다.', etc_detail: '기타 항목 선택후 입력해주세요. 신고와 무관한 욕설 작성 시 이용이 정지될 수 있습니다.', lecture_play: '강의 보기', list_view_link: '다른 강의 모음 보기', lecture_intro: '강의 소개 보기', study_goal: '학습목표', study_description: '설명', study_created: '등록일', study_last_updated: '최종 수정일', study_remove: '삭제', study_group_lecture_remove: '목록에서 삭제', study_group_curriculum_remove: '목록에서 삭제', study_edit: '강의 모음 수정', study_comments: '댓글', study_comment_post: '올리기', study_comment_remove: '삭제', study_comment_edit: '수정', study_comment_save: '저장', study_guide_video: '안내 영상', study_basic_project: '기본 작품', study_done_project: '완성 작품을 선택하세요.', study_usage_element: '사용요소', study_concept_element: '적용개념', study_subject_element: '연계교과', study_computing_element: '컴퓨팅요소', study_element_none: '없음', study_label_like: '좋아요', study_label_interest: '관심 강의', study_label_share: '공유', study_label_like_people: '강좌를 좋아하는 사람', study_label_interest_people: '강좌를 관심있어 하는 사람', study_related_lectures: '강의 목록', study_expand: '전체보기', study_collapse: '줄이기', aftercopy: '주소가 복사되었습니다.', study_remove_curriculum: '강의 모음을 삭제하시겠습니까?', content_required: '내용을 입력하세요', upload_not_supported_file_msg: '지원하지 않는 형식의 파일입니다.', study_remove_lecture: '강의를 삭제하시겠습니까?', lecture_build: '강의 만들기', lecture_build_step1: '1. 강의를 소개하기 위한 정보를 입력해주세요', lecture_build_step2: '2. 학습에 사용되는 기능들만 선택해주세요', lecture_build_step3: '3. 모든 정보를 올바르게 입력했는지 확인해주세요', lecture_build_choice: '어떤 것을 올리시겠습니까?', lecture_build_project: '엔트리 작품', lecture_build_video: '강의 영상', lecture_build_grade: '추천학년', lecture_build_goals: '학습목표', lecture_build_add_goal: '이곳을 클릭하여 목표를 추가', lecture_build_attach: '파일 첨부', lecture_build_attach_text: '20MB 이내의 파일을 업로드해 주세요.', lecture_build_assist: '보조 영상', lecture_build_youtube_url: 'Youtube 공유 링크를 넣어주세요.', lecture_build_project_done: '완성 작품을 선택하세요.', lecture_build_scene_text1: '장면기능을 끄면 새로운 장면을 추가하거나,', lecture_build_scene_text2: '삭제할 수 없습니다.', lecture_build_object_text: '오브젝트 추가하기를 끄면 새로운 오브젝트를 추가하거나 삭제할 수 없습니다.', lecture_build_blocks_text1: '학습에 필요한 블록들만 선택해주세요.', lecture_build_blocks_text2: '선택하지 않은 블록은 숨겨집니다.', lecture_build_basic1: '학습을 시작할때 사용할 작품을 선택해 주세요.', lecture_build_basic2: '학습자는 선택한 작품을 가지고 학습을 하게 됩니다.', lecture_build_help: '이 도움말을 다시 보시려면 눌러주세요.', lecture_build_help_never: '다시보지 않기', lecture_build_close: '닫기', lecture_build_scene: '장면 1', lecture_build_add_object: '오브젝트 추가하기', lecture_build_start: '시작하기', lecture_build_tab_code: '블록', lecture_build_tab_shape: '모양', lecture_build_tab_sound: '소리', lecture_build_tab_attribute: '속성', lecture_build_tab_table: '테이블', lecture_build_block_category: '블록 카테고리를 선택하세요.', lecture_build_attr_all: '전체', lecture_build_attr_var: '변수', lecture_build_attr_signal: '신호', lecture_build_attr_list: '리스트', lecture_build_attr_func: '함수', lecture_build_edit: '강의 수정', lecture_build_remove: '삭제', curriculum_build: '강의 모음 만들기', curriculum_step1: '1. 강의 모음을 소개하는 정보를 입력해주세요.', curriculum_step2: '2. 강의 모음을 구성하는 강의를 선택해주세요.', curriculum_step3: '3. 올바르게 강의 모음이 구성되었는지 확인해주세요.', curriculum_lecture_upload: '강의 올리기', curriculum_lecture_edit: '강의 편집', curriculum_lecture_open: '불러오기', group_lecture_add: '우리 반 강의 추가하기', group_curriculum_add: '우리 반 강의 모음 추가하기', group_lecture_delete: '삭제', group_curriculum_delete: '삭제', group_select: '', group_studentNo: '학번', group_username: '이름', group_userId: '아이디', group_tempPassword: '비밀번호 수정', group_gender: '성별', group_studentCode: '코드', file_load_web_table_title: '테이블을 웹에서 가져오기', file_load_web_table_sub_title: 'Google 스프레드시트 문서로 작성된 테이블을 가져올 수 있어요.', file_input_sheet_id: '스프레드시트 문서 ID', file_input_sheet_id_require: '필수', file_input_sheet_id_placeholder: '불러올 스프레드시트 문서의 ID를 입력해 주세요.', file_input_sheet_name: '시트 이름', file_input_sheet_name_placeholder: '불러올 시트 이름을 입력해 주세요.', file_load_web_warn_title_1: "Google 스프레드시트 문서의 내용을 가져와 엔트리의 테이블로 추가할 수 있습니다.\n스프레드시트의 액세스 권한이 '링크가 있는 모든 사용자'로 설정되어 있어야 가져올 수 있습니다.", file_load_web_warn_title_2: '아래와 같은 데이터는 이용약관 및 관련 법률에 의해 제재를 받을 수 있습니다.', file_load_web_warn_desc_2_1: '폭력적이고 잔인한 데이터, 선정적인 내용의 데이터, 불쾌감을 주거나 혐오단어가 포함된 데이터, 본인 또는 타인의 개인정보를 침해할 수 있는 내용의 데이터, \n무단 사용이 금지된 저작권의 데이터', file_load_web_error_sheet_id_1: '문서 ID가 입력되지 않았습니다.', file_load_web_error_sheet_id_2: '올바르지 않은 문서 ID입니다.', group_viewWorks: '작품 보기', added_group_lecture: '강의가 삭되었습니다.', added_group_curriculum: '강의 모음이 삭제되었습니다.', deleted_group_lecture: '강의가 삭제되었습니다.', deleted_group_curriculum: '강의 모음이 삭제되었습니다.', modal_my: '나의', modal_interest: '관심', modal_project: '작품', section: '단원', connect_hw: '하드웨어 연결', connect_message: '%1에 연결되었습니다.', connect_fail: '하드웨어 연결에 실패했습니다. 연결프로그램이 켜져 있는지 확인해 주세요.', interest_curriculum: '관심 강의 모음', marked_curriculum: '관심 강의 모음', searchword_required: '검색어를 입력하세요.', file_required: '파일은 필수 입력 항목입니다.', file_name_error: '올바른 파일이름을 입력해 주세요.', file_upload_max_count: '한번에 10개까지 업로드가 가능합니다.', image_file_only: '이미지 파일만 등록이 가능합니다.', file_upload_max_size: '10MB 이하만 업로드가 가능합니다.', curriculum_modal_lectures: '나의 강의', curriculum_modal_interest: '관심 강의', group_curriculum_modal_curriculums: '나의 강의 모음', group_curriculum_modal_interest: '관심 강의 모음', picture_import: '모양 가져오기', picture_select: '모양 선택', lecture_list_view: '다른 강의보기', play_software_2: 'EBS 소프트웨어야 놀자2', play_software_2_content: '네이버와 EBS가 함께 만든 두 번째 이야기, <소프트웨어야 놀자> 시즌2를 만나보세요! 재미있는 동영상 강의를 통해 소프트웨어의 기본 개념을 배워보고, 다양하고 흥미로운 주제로 실생활 문제를 해결해 볼 수 있습니다. 방송영상과 특별영상을 보며 재미있는 프로그램들을 직접 만들어보세요. 소프트웨어 교육을 처음 접하는 친구들도 쉽게 소프트웨어와 친구가 될 수 있답니다!', open_project_to_all: '공개', close_project: '비공개', category_media_art: '미디어 아트', go_further: '더 나아가기', marked_project: '북마크 작품', marked_group_project: '학급 관심 작품', basic: '기본', application: '응용', the_great_escape: '탈출 모험기', escape_guide_1: '강아지 로봇을 만드는 공장에서 우연한 정전으로 혼자서 생각할 수 있게 된 엔트리봇! ', escape_guide_1_2: ' 공장을 탈출하고 자유를 찾을 수 있도록 엔트리봇을 도와주세요!', escape_guide_2: '엔트리봇이 먼 길을 가기엔 고쳐야 할 곳이 너무 많아 공장에서 탈출하면서 몸을 수리할 수 있는 부품들을 찾아보자! 아직 몸이 완전하지는 않지만 걷거나 뛰면서, 방향을 바꾸는 정도는 가능할 거야! ', escape_guide_2_2: '학습 목표: 순차적 실행', escape_guide_3: '드디어 공장을 탈출했어! 하지만 마을로 가기 위해서는 아직 가야 할 길이 멀어. 그래도 몸은 어느 정도 고쳐져서 똑같은 일을 많이 해도 무리는 없을 거야! 어? 근데 저 로봇은 뭐지? ', escape_guide_3_2: '학습 목표: 반복문과 조건문', escape_guide_4: '드디어 마을 근처까지 왔어! 아까부터 똑같은 일을 많이 했더니 이제 외울 지경이야! 차라리 쓰일 블록은 이제 기억해뒀다가 쓰면 좋을 것 같아. 여기서 배터리만 충전해 놓으면 이제 평생 자유롭게 살 수 있을 거야.', escape_guide_4_2: '학습 목표: 함수 정의와 호출', space_travel_log: '우주 여행기', space_guide_1: '머나먼 우주를 탐사하기 위해 떠난 엔트리봇. 드디어 탐사 임무를 마치고 고향별인 지구로 돌아오려 하는데 수많은 돌이 지구로 가는 길을 막고 있다! 엔트리봇이 안전하게 지구로 돌아올 수 있도록 도와주세요!', space_guide_2: '드디어 지구에 돌아갈 시간이야! 얼른 지구에 돌아가서 쉬고 싶어!앞에 돌들이 어떻게 되어 있는지 확인하고 언제 어디로 가야 하는지 알려줘! 그러면 내가 가르쳐준 방향으로 움직일게!', space_guide_2_2: '학습 목표: 조건문 중첩과 논리 연산', cfest_mission: '엔트리 체험 미션', maze_1_intro: '안녕 나는 엔트리봇이라고 해. 지금 나는 다친 친구들을 구하려고 하는데 너의 도움이 필요해. 나를 도와서 친구들을 구해줘! 먼저 앞으로 가기 블록을 조립하고 시작을 눌러봐', maze_1_title: '시작 방법', maze_1_content: '엔트리봇은 어떻게 움직이나요?', maze_1_detail: '1. 블록 꾸러미에서 원하는 블록을 꺼내어 “시작하기를 클릭했을 때” 블록과 연결해봐
2. 다 조립했으면, 시작을 눌러봐
3. 나는 네가 조립한 블록대로 위에서부터 순서대로 움직일게', maze_2_intro: '좋아! 덕분에 첫 번째 친구를 무사히 구할 수 있었어! 그럼 다음 친구를 구해볼까? 어! 그런데 앞에 벌집이 있어! 뛰어넘기 블록을 사용해서 벌집을 피하고 친구를 구해보자.', maze_2_title_1: '장애물 뛰어넘기', maze_2_content_1: '장애물이 있으면 어떻게 해야하나요?', maze_2_detail_1: '길을 가다보면 장애물을 만날 수 있어.
장애물이 앞에 있을 때에는 뛰어넘기 블록을 사용해야 해.', maze_2_title_2: '시작 방법', maze_2_content_2: '엔트리봇은 어떻게 움직이나요?', maze_2_detail_2: '1. 블록 꾸러미에서 원하는 블록을 꺼내어 “시작하기를 클릭했을 때” 블록과 연결해봐
2. 다 조립했으면, 시작을 눌러봐
3. 나는 네가 조립한 블록대로 위에서부터 순서대로 움직일게', maze_3_intro: '멋졌어! 이제 또 다른 친구를 구하러 가자~ 이번에는 아까 구한 친구가 준 반복하기 블록을 이용해볼까? 반복하기를 이용하면 똑같은 동작을 쉽게 여러번 할 수 있어! 한 번 반복할 숫자를 바꿔볼래?', maze_3_title: '반복 블록(1)', maze_3_content: '(3)회 반복하기 블록은 어떻게 사용하나요?', maze_3_detail: '같은 행동을 여러번 반복하려면 ~번 반복하기 블록을 사용해야 해.
반복하고 싶은 블록들을 ~번 반복하기 안에 넣고 반복 횟수를 입력하면 돼', maze_4_intro: '훌륭해! 이제 구해야 할 친구 로봇들도 별로 남지 않았어. 벌집에 닿지 않도록 뛰어넘기를 반복하면서 친구에게 갈 수 있게 해줘!', maze_4_title: '반복 블록(1)', maze_4_content: '(3)회 반복하기 블록은 어떻게 사용하나요?', maze_4_detail: '같은 행동을 여러번 반복하려면 ~번 반복하기 블록을 사용해야 해.
반복하고 싶은 블록들을 ~번 반복하기 안에 넣고 반복 횟수를 입력하면 돼', maze_5_intro: '대단해! 이제 반복하기 블록과 만약 블록을 같이 사용해보자~ 만약 블록을 사용하면 앞에 벽이 있을 때 벽이 없는 쪽으로 회전할 수 있어. 그럼 친구를 구해주러 출발해볼까?', maze_5_title_1: '만약 블록', maze_5_content_1: '만약 ~라면 블록은 어떻게 동작하나요?', maze_5_detail_1: "만약 앞에 {이미지}가 있다면' 블록을 사용하면 앞에 {이미지}가 있을 때 어떤 행동을 할 지 정해줄 수 있어.
앞에 {이미지}가 있을 때에만 블록 안의 블록들을 실행하고
그렇지 않으면 실행하지 않게 되는 거야.", maze_5_title_2: '반복 블록(2)', maze_5_content_2: '~를 만날 때 까지 반복하기 블록은 어떻게 사용하나요?', maze_5_detail_2: "~까지 반복하기'를 사용하면 같은 행동을 언제까지 반복할지를 정해줄 수 있어.
반복하고 싶은 블록들을 ~까지 반복하기안에 넣으면 돼.
그러면 {이미지}와 같은 타일 위에 있는 경우 반복이 멈추게 될 거야.", maze_6_intro: '이제 마지막 친구야! 아까 해본 것처럼만 하면 될거야! 그럼 마지막 친구를 구하러 가볼까?', maze_6_title_1: '만약 블록', maze_6_content_1: '만약 ~라면 블록은 어떻게 동작하나요?', maze_6_detail_1: "만약 앞에 {이미지}가 있다면' 블록을 사용하면 앞에 {이미지}가 있을 때 어떤 행동을 할 지 정해줄 수 있어.
앞에 {이미지}가 있을 때에만 블록 안의 블록들을 실행하고
그렇지 않으면 실행하지 않게 되는 거야.", maze_6_title_2: '반복 블록(2)', maze_6_content_2: '~를 만날 때 까지 반복하기 블록은 어떻게 사용하나요?', maze_6_detail_2: "~까지 반복하기'를 사용하면 같은 행동을 언제까지 반복할지를 정해줄 수 있어.
반복하고 싶은 블록들을 ~까지 반복하기안에 넣으면 돼.
그러면 {이미지}와 같은 타일 위에 있는 경우 반복이 멈추게 될 거야.", maze_programing_mode_0: '블록 코딩', maze_programing_mode_1: '자바스크립트', maze_operation1_title: '1단계 – 자바스크립트모드 안내', maze_operation1_1_desc: '나는 로봇강아지 엔트리봇이야. 나에게 명령을 내려서 미션을 해결할 수 있게 도와줘! 미션은 시작할 때마다 \'목표\'를 통해서 확인할 수 있어!', maze_operation1_2_desc: '미션을 확인했다면 명령을 내려야 해 \'명령어 꾸러미\'명령어가 있는 공간이야. 마우스키보드명령을 내릴 수 있어. 마우스로는 명령어 꾸러미에 있는 명령어를 클릭하거나, 명령어\'명령어 조립소\'로 끌고와서 나에게 명령을 내릴 수 있어!', maze_operation1_2_textset_1: '마우스로 명령어를 클릭하는 방법 ', maze_operation1_2_textset_2: '마우스로 명령어를 드래그앤드랍하는 방법 ', maze_operation1_3_desc: '키보드로 명령을 내리려면 \'명령어 꾸러미\' 에 있는 명령어를 키보드로 직접 입력하면 돼.
명령어를 입력할 때 명령어 끝에 있는 ()와 ; 를 빼먹지 않도록 주의해야해!', maze_operation1_4_desc: '미션을 해결하기 위한 명령어를 다 입력했다면 [시작하기]를 누르면 돼.
[시작하기]를 누르면 나는 명령을 내린대로 움직일 거야!
각 명령어가 궁금하다면 [명령어 도움말]을 확인해봐!', maze_operation7_title: '7단계 - 반복 명령 알아보기(횟수반복)', maze_operation7_1_desc: '똑같은 일을 반복해서 명령하는건 매우 귀찮은 일이야.
이럴땐 반복과 관련된 명령어를 사용하면 훨씬 쉽게 명령을 내릴 수 있어.', maze_operation7_2_desc: '그렇다면 반복되는 명령을 쉽게 내리는 방법을 알아보자.
먼저 반복하기 명령어를 클릭한 다음, i<1 의 숫자를 바꿔서 반복횟수를 정하고
괄호({ }) 사이에 반복할 명령어를 넣어주면 돼!', maze_operation7_3_desc: '예를 들어 이 명령어은 move(); 를 10번 반복해서 실행해.
명령어와 동일한 명령어지.', maze_operation7_4_desc: '이 명령어를 사용할 때는 { } 안에 반복할 명령어를 잘 입력했는지,
`;`는 빠지지 않았는지 잘 살펴봐!
이 명령어에 대한 자세한 설명은 [명령어 도움말]에서 볼 수 있어.', maze_operation7_1_textset_1: '똑같은 명령어를 반복해서 사용하는 경우', maze_operation7_1_textset_2: '반복 명령어를 사용하는 경우', maze_operation7_2_textset_1: '반복 횟수', maze_operation7_2_textset_2: '반복할 명령', maze_operation7_4_textset_1: '괄호({})가 빠진 경우', maze_operation7_4_textset_2: '세미콜론(;)이 빠진 경우', study_maze_operation8_title: '8단계 - 반복 명령 알아보기(횟수반복)', study_maze_operation16_title: '4단계 - 반복 명령 알아보기(조건반복)', study_maze_operation1_title: '1단계 - 반복 명령 알아보기(횟수반복)', maze_operation9_title: '9단계 - 반복 명령 알아보기(조건반복)', maze_operation9_1_desc: '앞에서는 몇 번을 반복하는 횟수반복 명령어에 대해 배웠어.
이번에는 계속해서 반복하는 명령어를 살펴보자.
이 명령어를 사용하면 미션이 끝날 때까지 동일한 행동을 계속 반복하게 돼.
이 명령어 역시 괄호({ }) 사이에 반복할 명령어를 넣어 사용할 수 있어!', maze_operation9_2_desc: '예를 들어 이 명령어 은 미션을 완료할때까지 반복해서 move(); right()를 실행해.
명령어와 동일한 명령어지.', maze_operation9_3_desc: '이 명령어를 사용할 때도 { } 안에 반복할 명령어를 잘 입력했는지,
`true`가 빠지지 않았는지 잘 살펴봐!
이 명령어에 대한 자세한 설명은 [명령어 도움말]에서 볼 수 있어.', maze_operation9_1_textset_1: '반복할 명령', maze_operation9_3_textset_1: '괄호({})가 빠진 경우', maze_operation9_3_textset_2: '세미콜론(;)이 빠진 경우', maze_operation9_3_textset_3: 'true가 빠진 경우', study_maze_operation3_title: '3단계 - 반복 명령 알아보기(조건반복)', study_maze_operation4_title: '4단계 - 조건 명령 알아보기', study_ai_operation4_title: '4단계 - 조건 명령과 레이더 알아보기', study_ai_operation6_title: '6단계 - 중첩조건문 알아보기', study_ai_operation7_title: '7단계 - 다양한 비교연산 알아보기', study_ai_operation8_title: '8단계 - 물체 레이더 알아보기', study_ai_operation9_title: '9단계 - 아이템 사용하기', maze_operation10_title: '10단계 - 조건 명령 알아보기', maze_operation10_1_desc: '앞에서는 미션이 끝날 때까지 계속 반복하는 반복 명령어에 대해 배웠어.
이번에는 특정한 조건에서만 행동을 하는 조건 명령어를 살펴보자.
에서 보는것처럼 조건 명령어를 사용하면 명령을 보다 효율적으로 잘 내릴 수 있어.', maze_operation10_2_desc: '조건 명령어는 크게 `조건``조건이 발생했을때 실행되는 명령`으로 나눌수 있어.
먼저 조건 부분을 살펴보자. If 다음에 나오는 ( ) 부분이 조건을 입력하는 부분이야.
과 같은 명령어를 예로 살펴보자. if(front == “wall”) 는 만약 내 앞에(front) "wall(벽)"이 있다면을 뜻해', maze_operation10_3_desc: '이제 `조건이 발생했을 때 실행되는 명령`을 살펴보자.
이 부분은 괄호{}로 묶여 있고, 조건이 발생했을때 괄호안의 명령을 실행하게 돼!
조건이 발생하지 않으면 이 부분은 무시하고 그냥 넘어가게 되지.
의 명령어를 예로 살펴보자. 조건은 만약에 `내 앞에 벽이 있을 때` 이고,
이 조건이 발생했을 때 나는 괄호안의 명령어 right(); 처럼 오른쪽으로 회전하게 돼!', maze_operation10_4_desc: '조건 명령어반복하기 명령어와 함께 쓰이는 경우가 많아.
앞으로 쭉 가다가, 벽을 만났을때만 회전하게 하려면
순서와 같이 명령을 내릴 수 있지!', maze_operation10_1_textset_1: '[일반명령]', maze_operation10_1_textset_2: '앞으로 2칸 가고
오른쪽으로 회전하고,
앞으로 3칸가고,
오른쪽으로 회전하고, 앞으로...
', maze_operation10_1_textset_3: '[조건명령]', maze_operation10_1_textset_4: '앞으로 계속 가다가
`만약에 벽을 만나면`
오른쪽으로 회전해~!
', maze_operation10_2_textset_1: '조건', maze_operation10_2_textset_2: '조건이 발생했을 때 실행되는 명령', maze_operation10_3_textset_1: '조건', maze_operation10_3_textset_2: '조건이 발생했을 때 실행되는 명령', maze_operation10_4_textset_1: '미션이 끝날때 까지
계속 앞으로 간다.
', maze_operation10_4_textset_2: '계속 앞으로 가다가,
만약에 벽을 만나면
', maze_operation10_4_textset_3: '계속 앞으로 가다가,
만약에 벽을 만나면
오른쪽으로 회전한다.
', study_maze_operation18_title: '6단계 - 조건 명령 알아보기', maze_operation15_title: '15단계 - 함수 명령 알아보기', maze_operation15_1_desc: '자주 사용하는 명령어들을 매번 입력하는건 매우 귀찮은 일이야.
자주 사용하는 명령어들을 묶어서 이름을 붙이고,
필요할 때마다 그 명령어 묶음을 불러온다면 훨씬 편리하게 명령을 내릴 수 있어!
이런 명령어 묶음을 `함수`라고 해. 이제 함수 명령에 대해 자세히 알아보자.', maze_operation15_2_desc: '함수 명령어는 명령어를 묶는 `함수만들기` 과정과,
묶은 명령어를 필요할 때 사용하는 `함수 불러오기` 과정이 있어.
먼저 함수만들기 과정을 살펴보자.
함수를 만들려면 함수의 이름과, 그 함수에 들어갈 명령어를 입력해야 해.
function을 입력한 다음 함수의 이름을 정할 수 있어. 여기서는 promise로 만들거야.
함수 이름을 만들었으면 ()를 붙여줘. 그 다음 괄호({})를 입력해.
그리고 이 괄호 안에 함수에 들어갈 명령어들을 입력하면 함수가 만들어져!', maze_operation15_3_desc: '이 명령어를 예로 살펴보자. 나는 promise 라는 함수를 만들었어.
이 함수를 불러서 실행하면 괄호({})안에 있는
move();
move();
left(); 가 실행돼!', maze_operation15_4_desc: '함수를 불러와서 실행하려면 아까 만든 함수의 이름을 입력하고 뒤에 `();`를 붙이면 돼.
promise 라는 이름으로 함수를 만들었으니 promise(); 를 입력하면 앞에서 묶어놓은
명령어들이 실행되는거지!
과 같이 명령을 내리면 처럼 동작하게 돼!
함수 명령어를 사용하려면 과 같이 함수를 만들고 함수를 불러와야해!', maze_operation15_1_textset_1: '자주 사용하는 명령어 확인하기', maze_operation15_1_textset_2: '명령어들을 묶어서 이름 붙이기', maze_operation15_1_textset_3: '명령어 묶음 불러오기', maze_operation15_2_textset_1: '명령어 묶음의 이름(함수 이름)', maze_operation15_2_textset_2: '묶을 명령어들', maze_operation15_3_textset_1: '명령어 묶음의 이름(함수 이름)', maze_operation15_3_textset_2: '묶을 명령어들', maze_operation15_4_textset_1: '함수 만들기', maze_operation15_4_textset_2: '함수 불러오기', maze_operation15_4_textset_3: '실제 상황', maze_object_title: '오브젝트 정보', maze_object_parts_box: '부품 상자', maze_object_trap: '함정', maze_object_monster: '몬스터', maze_object_obstacle1: '장애물', maze_object_obstacle2: 'bee', maze_object_obstacle3: 'banana', maze_object_friend: '친구', maze_object_wall1: 'wall', maze_object_wall2: 'wall', maze_object_wall3: 'wall', maze_object_battery: '베터리', maze_command_ex: '예시', maze_command_title: '명령어 도움말', maze_command_move_desc: '엔트리봇을 한 칸 앞으로 이동시킵니다.', maze_command_jump_desc: '아래 이미지와 같은 장애물 앞에서 장애물을 뛰어 넘습니다.
', maze_command_jump_desc_elec: '아래 이미지와 같은 장애물 앞에서 장애물을 뛰어 넘습니다.
', maze_command_right_desc: '제자리에서 오른쪽으로 90도 회전합니다.', maze_command_left_desc: '제자리에서 왼쪽으로 90도 회전합니다.', maze_command_for_desc: '괄호{} 안에 있는 명령을 입력한 횟수 만큼 반복해서 실행합니다.', maze_command_while_desc: '미션이 끝날 때가지 괄호{} 안에 있는 명령을 계속 반복해서 실행합니다.', maze_command_slow_desc: '아래 이미지와 같은 방지턱을 넘습니다.
', maze_command_if1_desc: '조건 `바로 앞에 벽이 있을때`이 발생했을 때,
괄호{} 안에 있는 명령을 실행합니다.', maze_command_if2_desc: '조건 `바로 앞에 벌집이 있을때`이 발생했을 때,
괄호{} 안에 있는 명령을 실행합니다.', maze_command_if3_desc: '조건 `바로 앞에 바나나가 있을때`이 발생했을 때,
괄호{} 안에 있는 명령을 실행합니다.', maze_command_promise_desc: 'promise 라는 함수를 만들고 실행하면 괄호{} 안에
있던 명령어가 실행합니다.', perfect: '아주 완벽해! ', succeeded_using_blocks: ' 개의 블록을 사용해서 성공했어!', succeeded_using_commands: ' 개의 명령어를 사용해서 성공했어!', awesome: '대단한 걸!', succeeded_go_to_next: '개의 블록만으로 성공했어!
다음 단계로 넘어가자.', good: '좋아! ', but: '
하지만, ', try_again: ' 개의 블록만으로 성공하는 방법도 있어.
다시 도전해 보는건 어때?', try_again_commands: ' 개의 명렁어만으로 성공하는 방법도 있어.
다시 도전해 보는건 어때?', cfest_success: '대단한걸! 덕분에 친구들을 구할 수 있었어!
아마도 너는 타고난 프로그래머 인가봐!
나중에 또 만나자~!', succeeded_and_cert: '개의 블록만으로 성공했어!
인증서를 받으러 가자.', cause_msgs_1: '에구, 앞으로 갈 수 없는 곳이였어. 다시 해보자.', cause_msgs_2: '히잉. 그냥 길에서는 뛰어 넘을 곳이 없어. 다시 해보자.', cause_msgs_3: '에고고, 아파라. 뛰어 넘었어야 했던 곳이였어. 다시 해보자.', cause_msgs_4: '아쉽지만, 이번 단계에서는 꼭 아래 블록을 써야만 해.
다시 해볼래?', cause_msgs_5: '이런, 실행할 블록들이 다 떨어졌어. 다시 해보자.', cause_msgs_6: '이런, 실행할 명령어들이 다 떨어졌어. 다시 해보자.', close_experience: '체험
종료', replay: '다시하기', go_to_next_level: '다음단계 가기', move_forward: '앞으로 한 칸 이동', turn_left: '왼쪽', turn_right: '오른쪽', turn_en: '', turn_ko: '으로 회전', jump_over: '뛰어넘기', when_start_is_pressed: '시작하기를 클릭했을 때', repeat_until_ko: '만날 때 까지 반복', repeat_until_en: '', repeat_until: '만날 때 까지 반복', if_there_is_1: '만약 앞에 ', if_there_is_2: '있다면', used_blocks: '사용 블록', maximum: '목표 블록', used_command: '사용 명령어 갯수', maximum_command: '목표 명령어 갯수', block_box: '블록 꾸러미', block_assembly: '블록 조립소', command_box: '명령어 꾸러미', command_assembly: '명령어 조립소', start: '시작하기', engine_running: '실행중', engine_replay: '돌아가기', goto_show: '보러가기', make_together: '함께 만드는 엔트리', make_together_content: '엔트리는 학교에 계신 선생님들과 학생 친구들이 함께 고민하며 만들어갑니다.', project_nobody_like: "이 작품이 마음에 든다면 '좋아요'를 눌러 주세요.", project_nobody_interest: "'관심 작품'을 누르면 마이 페이지에서 볼 수 있어요.", lecture_nobody_like: "이 강의가 마음에 든다면 '좋아요'를 눌러 주세요.", lecture_nobody_interest: "'관심 강의'을 누르면 마이 페이지에서 볼 수 있어요.", course_nobody_like: "이 강의 모음이 마음에 든다면 '좋아요'를 눌러 주세요.", course_nobody_interest: "'관심 강의 모음'을 누르면 마이 페이지에서 볼 수 있어요.", before_changed: '변경전', after_changed: '변경후', from_changed: '( 2016년 04월 17일 부터 ) ', essential: '필수', access_term_title: '안녕하세요. 엔트리 교육연구소 입니다. 
엔트리를 사랑해주시는 여러분께 감사드리며, 
엔트리 교육연구소 웹사이트 이용약관이
2016년 4월 17일 부로 다음과 같이 개정됨을 알려드립니다. ', member_info: '회원 안내', personal_info: '개인정보 수집 및 이용에 동의 합니다.', option: '선택', news: '최신소식', edu_material: '교육자료', latest_news: '최근소식', edu_data: '교육자료', training_program: '연수지원', footer_phrase: '엔트리는 누구나 무료로 소프트웨어 교육을 받을 수 있게 개발된 비영리 교육 플랫폼입니다.', footer_use_free: '모든 엔트리교육연구소의 저작물은 교육적 목적에 한하여 출처를 밝히고 자유롭게 이용할 수 있습니다.', footer_description_1: '엔트리는 비영리 교육 플랫폼으로 모든 엔트리의 저작물은 교육 목적에 한해 출처를 밝히고 자유롭게 이용할 수 있습니다.', footer_description_2: '', nonprofit_platform: '비영리 교육 플랫폼', this_is: '입니다.', privacy: '개인정보 처리방침', entry_addr: '경기도 성남시 분당구 불정로 6 NAVER 그린팩토리 16층', entry_addr_additional_phone: '1522-9182', entry_addr_additional_email: 'entry@connect.or.kr', entry_addr_additional_opensource: '오픈소스 라이선스', phone: '전화번호', alert_agree_term: '이용약관에 동의하여 주세요.', alert_private_policy: '개인정보 수집 약관에 동의하여 주세요.', agree: '동의', optional: '선택', start_software: '소프트웨어 교육의 첫걸음', analyze_procedure: '절차', analyze_repeat: '반복', analyze_condition: '분기', analyze_interaction: '상호작용', analyze_dataRepresentation: '데이터 표현', analyze_abstraction: '추상화', analyze_sync: '병렬 및 동기화', jr_intro_1: '안녕! 난 쥬니라고 해! 내 친구 엔트리봇이 오른쪽에 있어! 날 친구에게 데려다 줘!', jr_intro_2: '엔트리봇이 내 왼쪽에 있어! 왼쪽으로 가보자.', jr_intro_3: '엔트리봇이 위쪽에 있어! 친구를 만날 수 있도록 도와줘!', jr_intro_4: '어서 엔트리봇을 만나러 가자! 아래쪽으로 가보는거야~ ', jr_intro_5: '우왓! 내 친구가 멀리 떨어져있어. 엔트리봇이 있는 곳까지 안내해줄래? ', jr_intro_6: '저기 엔트리봇이 있어~ 얼른 만나러 가보자.', jr_intro_7: '예쁜 꽃이 있네. 꽃들을 모아 엔트리봇에게 가보자!', jr_intro_8: '가는 길에 꽃이 있어! 꽃을 모아 엔트리봇에게 가보자!', jr_intro_9: '엔트리봇이 멀리 떨어져 있네? 가장 빠른 길로 엔트리봇에게 가 보자.', jr_intro_10: '엔트리봇을 만나러 가는 길에 꽃을 모두 모아서 가보자.', jr_intro_11: '엔트리봇에게 가려면 오른쪽으로 다섯번이나 가야 하잖아? 반복하기 블록을 사용해서 좀 더 쉽게 가 보자.', jr_intro_12: '반복하기를 사용해서 엔트리봇을 만나러 가자.', jr_intro_13: '지금 블록으로는 친구에게 갈 수가 없어. 반복 횟수를 바꿔 엔트리봇에게 갈 수 있게 해줘.', jr_intro_14: '반복 블록을 사용하여 엔트리봇에게 데려다 줘.', jr_intro_15: '엔트리봇이 정~말 멀리 있잖아? 그래도 반복 블록을 사용하면 쉽게 엔트리봇에게 갈 수 있을 거야.', jr_whats_ur_name: '내가 받을 인증서에 적힐 이름은?', jr_down_cert: '인증서 받기', jr_popup_prefix_1: '좋아! 엔트리봇을 만났어!', jr_popup_prefix_2: '우왓! 엔트리봇을 만났어!
하지만 엔트리봇을 만나기에는 더 적은 블록을 사용해서도
만날 수 있는데 다시 해볼래? ', jr_popup_prefix_3: '좋아! 책가방을 챙겼어!', jr_popup_prefix_4: '우왓! 책가방이 있는 곳으로 왔어! 하지만 더 적은 블록을 사용해도 책가방 쪽으로 갈 수 있는데 다시 해볼래?', jr_popup_suffix_1: '고마워~ 덕분에 책가방을 챙겨서 학교에 올 수 있었어~ 다음 학교 가는 길도 함께 가자~', jr_popup_suffix: '고마워~ 덕분에 엔트리봇이랑 재밌게 놀 수 있었어~
다음에 또 엔트리봇이랑 놀자~', jr_fail_dont_go: '에궁, 그 곳으로는 갈 수 없어. 가야하는 길을 다시 알려줘~', jr_fail_dont_know: '어? 이제 어디로 가지? 어디로 가야하는 지 더 알려줘~', jr_fail_no_flower: '이런 그곳에는 꽃이 없어. 꽃이 있는 곳에서 사용해보자~', jr_fail_forgot_flower: '앗! 엔트리봇한테 줄 꽃을 깜빡했어. 꽃을 모아서 가자~', jr_fail_need_repeat: '반복 블록이 없잖아! 반복 블록을 사용해서 해보자~', jr_hint_1: '안녕! 난 쥬니라고 해! 내 친구 엔트리봇이 오른쪽에 있어! 날 친구에게 데려다 줘!', jr_hint_2: '엔트리봇이 내 왼쪽에 있어! 왼쪽으로 가보자.', jr_hint_3: '엔트리봇이 위쪽에 있어! 친구를 만날 수 있도록 도와줘!', jr_hint_4: '어서 엔트리봇을 만나러 가자! 아래쪽으로 가보는거야~', jr_hint_5: '우왓! 내 친구가 멀리 떨어져있어. 엔트리봇이 있는 곳까지 안내해줄래?', jr_hint_6: '잘못된 블록들 때문에 친구에게 가지 못하고 있어, 잘못된 블록을 지우고 엔트리봇에게 갈 수 있도록 해줘!', jr_hint_7: '예쁜 꽃이 있네. 꽃들을 모아 엔트리봇에게 가보자!', jr_hint_8: '가는 길에 꽃이 있어! 꽃을 모아 엔트리봇에게 가보자!', jr_hint_9: '엔트리봇이 멀리 떨어져 있네? 가장 빠른 길로 엔트리봇에게 가 보자.', jr_hint_10: '앗, 블록을 잘못 조립해서 제대로 갈 수가 없어. 가는 길에 꽃을 모두 모아 엔트리봇에게 가져다 줄 수 있도록 고쳐 보자.', jr_hint_11: '엔트리봇에게 가려면 오른쪽으로 다섯번이나 가야 하잖아? 반복하기 블록을 사용해서 좀 더 쉽게 가 보자.', jr_hint_12: '반복하기를 사용해서 엔트리봇을 만나러 가자.', jr_hint_13: '지금 블록으로는 친구에게 갈 수가 없어. 반복 횟수를 바꿔 엔트리봇에게 갈 수 있게 해줘.', jr_hint_14: '반복 블록을 사용하여 엔트리봇에게 데려다 줘.', jr_hint_15: '엔트리봇이 정~말 멀리 있잖아? 그래도 반복 블록을 사용하면 쉽게 엔트리봇에게 갈 수 있을 거야.', jr_certification: '인증서', jr_congrat: '축하드립니다!', jr_congrat_msg: '문제해결 과정을 성공적으로 마쳤습니다.', jr_share: '공유', go_see_friends: '친구들 만나러 가요~!', junior_naver: '쥬니어 네이버', junior_naver_contents_1: "의 멋진 곰 '쥬니'가 엔트리를 찾아 왔어요! ", junior_naver_contents_2: '그런데 쥬니는 길을 찾는 것이 아직 어렵나봐요.', junior_naver_contents_3: '쥬니가 엔트리봇을 만날 수 있도록 가야하는 방향을 알려주세요~', basic_content: '기초', jr_help: '도움말', help: '도움말', cparty_robot_intro_1: '안녕 나는 엔트리봇이야. 난 부품을 얻어서 내몸을 고쳐야해. 앞으로 가기 블록으로 부품을 얻게 도와줘!', cparty_robot_intro_2: '좋아! 앞에도 부품이 있는데 이번에는 잘못 가다간 감전되기 쉬울 것 같아. 뛰어넘기 블록을 써서 부품까지 데려다 줘.', cparty_robot_intro_3: '멋진걸! 저기에도 부품이 있어! 길이 조금 꼬여있지만 회전하기 블록을 쓰면 충분히 갈 수 있을 것 같아! ', cparty_robot_intro_4: '좋아 이제 움직이는 건 많이 편해졌어! 이번에는 회전과 뛰어넘기를 같이 써서 저 부품을 얻어보자! ', cparty_robot_intro_5: '덕분에 몸이 아주 좋아졌어! 이번에도 회전과 뛰어넘기를 같이 써야 할 거야! 어서 가보자!', cparty_robot_intro_6: '멋져! 이제 몸이 많이 좋아져서, 똑같은 일은 여러 번 해도 괜찮을 거야! 한 번 반복하기를 사용해서 가보자!', cparty_robot_intro_7: '어? 중간중간에 뛰어넘어야 할 곳이 있어! 그래도 반복하기로 충분히 갈 수 있을 거야!', cparty_robot_intro_8: '이런! 이번에는 부품이 저기 멀리 떨어져 있어. 그래도 반복하기를 사용하면 쉽게 갈수 있지! 얼른 도와줘!', cparty_robot_intro_9: '우와~ 이제 내 몸이 거의 다 고쳐진 것 같아! 이번에도 반복하기를 이용해서 부품을 구하러 가보자!', cparty_robot_intro_10: '대단해! 이제 마지막 부품만 있으면 내 몸을 완벽하게 고칠 수 있을 거야! 빨리 반복하기로 도와줘!', cparty_car_intro_1: '안녕! 나는 엔트리봇이라고 해, 자동차를 타고 계속 이동하려면 연료가 필요해! 앞에 있는 연료를 얻을 수 있게 도와줄래?', cparty_car_intro_2: '좋아! 그런데 이번에는 길이 직선이 아니네! 왼쪽/오른쪽 돌기 블록으로 잘 운전해서 함께 연료를 얻으러 가볼까?', cparty_car_intro_3: '잘했어! 이번 길 앞에는 과속방지턱이 있어. 빠르게 운전하면 사고가 날 수도 있을 것 같아, 천천히 가기 블록을 써서 연료를 얻으러 가보자!', cparty_car_intro_4: '야호, 이제 운전이 한결 편해졌어! 이 도로에서는 반복하기 블록을 사용해서 연료를 채우러 가볼까?', cparty_car_intro_5: '와 이번 도로는 조금 복잡해 보이지만, 앞으로 가기와 왼쪽/오른쪽 돌기 블록을 반복하면서 가보면 돼! 차분하게 연료까지 가보자', cparty_car_intro_6: '이번에는 도로에 장애물이 있어서 잘 돌아가야 될 것 같아, 만약에 장애물이 앞에 있다면 어떻게 해야 하는지 알려줘!', cparty_car_intro_7: '좋아 잘했어! 한번 더 만약에 블록을 사용해서 장애물을 피해 연료를 얻으러 가보자!', cparty_car_intro_8: '앗 아까 만났던 과속 방지턱이 두 개나 있네, 천천히 가기 블록을 이용해서 안전하게 연료를 채우러 가보자!', cparty_car_intro_9: '복잡해 보이는 길이지만, 앞에서 사용한 반복 블록과 만약에 블록을 잘 이용하면 충분히 운전할 수 있어, 연료를 채울 수 있도록 도와줘!', cparty_car_intro_10: '정말 멋져! 블록의 순서를 잘 나열해서 이제 마지막 남은 연료를 향해 힘을 내어 가보자!', cparty_car_popup_prefix_1: '좋아! 연료를 얻었어!', cparty_car_popup_prefix_2: '우왓! 연료를 얻었어!
하지만 연료를 얻기에는 더 적은 블록을 사용해서도
얻을 수 있는데 다시 해볼래? ', cparty_car_popup_prefix_2_text: '우왓! 연료를 얻었어!
하지만 연료를 얻기에는 더 적은 명령어 사용해서도
얻을 수 있는데 다시 해볼래? ', cparty_car_popup_suffix: '고마워~ 덕분에 모든 배터리를 얻을 수 있었어~
다음에 또 나랑 놀자~', all_grade: '모든 학년', grade_e3_e4: '초등 3 ~ 4 학년 이상', grade_e5_e6: '초등 5 ~ 6 학년 이상', grade_m1_m3: '중등 1 ~ 3 학년 이상', entry_first_step: '엔트리 첫걸음', entry_monthly: '월간 엔트리', play_sw_2: 'EBS 소프트웨어야 놀자2', entry_programming: '실전, 프로그래밍!', entry_recommanded_course: '엔트리 추천 코스', introduce_course: '누구나 쉽게 보고 따라하면서 재미있고 다양한 소프트웨어를 만들 수 있는 강의 코스를 소개합니다.', all_free: '*강의 동영상, 만들기, 교재 등이 모두 무료로 제공됩니다.', cparty_result_fail_1: '에궁, 그 곳으로는 갈 수 없어. 가야하는 길을 다시 알려줘~', cparty_result_fail_2: '에고고, 아파라. 뛰어 넘었어야 했던 곳이였어. 다시 해보자.', cparty_result_fail_3: '아이고 힘들다. 아래 블록들을 안 썼더니 너무 힘들어! 아래 블록들로 다시 만들어줘.', cparty_result_fail_4: '어? 이제 어디로 가지? 어디로 가야하는 지 더 알려줘~', cparty_result_fail_5: '앗! 과속방지턱에서는 속도를 줄여야해. 천천히 가기 블록을 사용해보자~', cparty_result_success_1: '좋아! 부품을 얻었어!', cparty_result_success_2: '우왓! 부품을 얻었어!
하지만 부품을 얻기에는 더 적은 블록을 사용해서도 얻을 수 있는데 다시 해볼래?', cparty_result_success_2_text: '우왓! 부품을 얻었어!
하지만 부품을 얻기에는 더 적은 명령어를 사용해서도 얻을 수 있는데 다시 해볼래?', cparty_result_success_3: '고마워~ 덕분에 내몸이 다 고쳐졌어~ 다음에 또 나랑 놀자~', cparty_insert_name: '이름을 입력하세요.', offline_file: '파일', offline_edit: '편집', offline_undo: '되돌리기', offline_redo: '다시실행', offline_copy: '복사', offline_paste: '붙여넣기', offline_cut: '자르기', offline_quit: '종료', select_one: '선택해 주세요.', evaluate_challenge: '도전해본 미션의 난이도를 평가해 주세요.', very_easy: '매우쉬움', easy: '쉬움', normal: '보통', difficult: '어려움', very_difficult: '매우 어려움', save_dismiss: '바꾼 내용을 저장하지 않았습니다. 계속 하시겠습니까?', entry_info: '엔트리 정보', actual_size: '실제크기', zoom_in: '확대', zoom_out: '축소', cparty_jr_intro_1: '안녕! 난 엔트리봇 이라고 해! 학교가는 길에 책가방을 챙길 수 있도록 도와줘! ', cparty_jr_intro_2: '책가방이 내 왼쪽에 있어! 왼쪽으로 가보자.', cparty_jr_intro_3: '책가방이 위쪽에 있어! 책가방을 챙길 수 있도록 도와줘!', cparty_jr_intro_4: '어서 책가방을 챙기러 가자! 아래쪽으로 가보는 거야~', cparty_jr_intro_5: '우왓! 내 책가방이 멀리 떨어져 있어. 책가방이 있는 곳까지 안내해줄래?', cparty_jr_intro_6: '책가방이 있어! 얼른 가지러 가자~', cparty_jr_intro_7: '길 위에 내 연필이 있네. 연필들을 모아 책가방을 챙기러 가보자!', cparty_jr_intro_8: '학교 가는 길에 연필이 있어! 연필을 모아 책가방을 챙기러 가보자!', cparty_jr_intro_9: '내 책가방이 멀리 떨어져 있네? 가장 빠른 길로 책가방을 챙기러 가 보자.', cparty_jr_intro_10: '가는 길에 연필을 모두 모으고 책가방을 챙기자!', cparty_jr_intro_11: '책가방을 챙기러 가려면 오른쪽으로 다섯 번이나 가야 하잖아? 반복하기 블록을 사용해서 좀 더 쉽게 가 보자.', cparty_jr_intro_12: '반복하기를 사용해서 책가방을 챙기러 가자.', cparty_jr_intro_13: '지금 블록으로는 책가방이 있는 쪽으로 갈 수가 없어. 반복 횟수를 바꿔 책가방을 챙기러 갈 수 있게 해줘.', cparty_jr_intro_14: '반복 블록을 사용하여 책가방을 챙기러 가줘.', cparty_jr_intro_15: '학교가 정~말 멀리 있잖아? 그래도 반복 블록을 사용하면 쉽게 학교에 도착 할수 있을 거야.', make_new_project: '새로운 작품 만들기', open_old_project: '저장된 작품 불러오기', offline_download: '엔트리 다운로드', offline_release: '엔트리 오프라인 에디터 출시!', offline_description_1: '엔트리 오프라인 버전은', offline_description_2: '인터넷이 연결되어 있지 않아도 사용할 수 있습니다. ', offline_description_3: '지금 다운받아서 시작해보세요!', sw_week_2015: '2015 소프트웨어교육 체험 주간', cparty_desc: '두근두근 소프트웨어와의 첫만남', entry_offline_download: '엔트리 오프라인 \n다운로드', entry_download_detail: '다운로드\n바로가기', offline_desc_1: '엔트리 오프라인 버전은 인터넷이 연결되어 있지 않아도 사용할 수 있습니다.', offline_desc_2: '지금 다운받아서 시작해보세요!', download: '다운로드', version: '버전', file_size: '크기', update: '업데이트', use_range: '사용범위', offline_desc_free: '엔트리 오프라인은 기업과 개인 모두 제한 없이 무료로 사용하실 수 있습니다.', offline_required: '최소 요구사항', offline_required_detail: '디스크 여유 공간 1GB 이상, Windows 8 이상 혹은 macOS 10.8 이상의 운영체제, 디스크 여유 공간 1GB 이상', offline_notice: '설치 전 참고사항', offline_notice_1: '1. 버전', offline_notice_1_1: '에서는 하드웨어 연결 프로그램이 내장되어 있습니다.', offline_notice_2: '2. 별도의 웹브라우져가 필요하지 않습니다.', offline_notice_3: '버전 별 변경 사항 안내', offline_notice_4: '버전별 다운로드', offline_notice_5: '버전별 자세한 변경 사항 보기', hardware_online_badge: '온라인', hardware_title: '엔트리 하드웨어 연결 프로그램 다운로드', hardware_desc: '엔트리 온라인 ‘작품 만들기’에서 하드웨어를 연결하여 엔트리를 이용하는 경우에만 별도로 설치가 필요합니다.', hardware_release: '하드웨어 연결 프로그램의 자세한 변경 사항은 아래 주소에서 확인 할 수 있습니다.', hardware_window_download: 'Windows 다운로드', hardware_osx_download: 'Mac 다운로드', cparty_jr_result_2: '고마워~ 덕분에 책가방을 챙겨서 학교에 올 수 있었어~
다음 학교 가는 길도 함께 가자~ ', cparty_jr_result_3: '우왓! 학교까지 왔어!
하지만 더 적은 블록을 사용해도 학교에 갈 수 있는데
다시 해볼래?', cparty_jr_result_4: '우왓! 책가방을 얻었어!
하지만 더 적은 블록을 사용해도 책가방을 얻을 수 있는데
다시 해볼래? ', lms_no_class: '아직 만든 학급이 없습니다.', lms_create_class: '학급을 만들어 주세요.', lms_add_class: '학급 만들기', lms_base_class: '기본', lms_delete_class: '삭제', lms_my_class: '나의 학급', lms_grade_1: '초등 1', lms_grade_2: '초등 2', lms_grade_3: '초등 3', lms_grade_4: '초등 4', lms_grade_5: '초등 5', lms_grade_6: '초등 6', lms_grade_7: '중등 1', lms_grade_8: '중등 2', lms_grade_9: '중등 3', lms_grade_10: '일반', lms_add_groupId_personal: '선생님께 받은 학급 아이디를 입력하여, 회원 정보에 추가하세요.', lms_add_groupId: '학급 아이디 추가하기', lms_add_group_account: '학급 계정 추가', lms_enter_group_info: '발급받은 학급 아이디와 비밀번호를 입력하세요.', lms_group_id: '학급 아이디', lms_group_pw: '비밀번호', lms_group_name: '소속 학급명', personal_pwd_alert: '올바른 비밀번호 양식을 입력해 주세요', personal_form_alert: '양식을 바르게 입력해 주세요', personal_form_alert_2: '모든 양식을 완성해 주세요', personal_no_pwd_alert: '비밀번호를 입력해 주세요', select_gender: '성별을 선택해 주세요', enter_group_id: '학급 아이디를 입력해 주세요', enter_group_pwd: '비밀번호를 입력해 주세요', info_added: '추가되었습니다', no_group_id: '학급 아이디가 존재하지 않습니다', no_group_pwd: '비밀번호가 일치하지 않습니다', lms_please_choice: '선택해 주세요.', group_lesson: '나의 학급 강의', lms_banner_add_group: '학급 기능 도입', lms_banner_entry_group: '엔트리 학급 만들기', lms_banner_desc_1: '우리 반 학생들을 엔트리에 등록하세요!', lms_banner_desc_2: '이제 보다 편리하고 쉽게 우리 반 학생들의 작품을 찾고,', lms_banner_desc_3: '성장하는 모습을 확인할 수 있습니다. ', lms_banner_download_manual: '메뉴얼 다운로드', lms_banner_detail: '자세히 보기', already_exist_email: '이미 존재하는 이메일 입니다.', same_registered_email: '중복된 이메일 입니다.', email_correnctly_please: '양식을 올바르게 입력해주세요.', remove_project: '작품을 삭제하시겠습니까?', study_lesson: '우리 반 학습하기', open_project: '작품 불러오기', make_group: '학급 만들기', project_share: '작품 공유하기', group_project_share: '학급 공유하기', group_discuss: '학급 글 나누기', my_profile: '마이 페이지', search_updated: '최신 작품', search_recent: '최근 조회수 높은 작품', search_complexity: '최근 제작에 공들인 작품', search_staffPicked: '스태프선정 작품 저장소', search_childCnt: '사본이 많은 작품', search_likeCnt: '최근 좋아요가 많은 작품', search_recentLikeCnt: '최근 좋아요가 많은 작품', gnb_share: '공유하기', gnb_community: '커뮤니티', lms_add_lectures: '강의 올리기', lms_add_course: '강의 모음 올리기', lms_add_homework: '과제 올리기', remove_lecture_confirm: '강의를 정말 삭제하시겠습니까?', popup_delete: '삭제하기', remove_course_confirm: '강의 모음을 정말 삭제하시겠습니까?', lms_no_lecture_teacher_1: '추가된 강의가 없습니다.', lms_no_lecture_teacher_2: '우리 반 강의를 추가해 주세요.', gnb_download: '다운로드', lms_no_lecture_student_1: '아직 올라온 강의가 없습니다.', lms_no_lecture_student_2: '선생님이 강의를 올려주시면,', lms_no_lecture_student_3: '학습 내용을 확인할 수 있습니다.', lms_no_class_teacher: '아직 만든 학급이 없습니다.', lms_no_course_teacher_1: '추가된 강의 모음이 없습니다.', lms_no_course_teacher_2: '우리 반 강의 모음을 추가해 주세요.', lms_no_course_student_1: '아직 올라온 강의 모음이 없습니다.', lms_no_course_student_2: '선생님이 강의 모음을 올려주시면,', lms_no_course_student_3: '학습 내용을 확인할 수 있습니다.', lms_no_hw_teacher_1: '추가된 과제가 없습니다.', lms_no_hw_teacher_2: '우리 반 과제를 추가해 주세요.', lms_no_hw_student_1: '아직 올라온 과제가 없습니다.', lms_no_hw_student_2: '선생님이 과제를 올려주시면,', lms_no_hw_student_3: '학습 내용을 확인할 수 있습니다.', modal_edit: '수정하기', modal_deadline: '마감일 설정', modal_hw_desc: '상세설명 (선택)', desc_optional: '', modal_create_hw: '과제 만들기', vol: '회차', hw_title: '과제명', hw_description: '내용', deadline: '마감일', do_homework: '과제하기', hw_progress: '진행 상태', hw_submit: '제출', view_list: '명단보기', view_desc: '내용보기', do_submit: '제출하기', popup_notice: '알림', no_selected_hw: '선택된 과제가 없습니다.', hw_delete_confirm: '선택한 과제를 정말 삭제하시겠습니까?', hw_submitter: '과제 제출자 명단', hw_student_desc_1: "* '제출하기'를 눌러 제출을 완료하기 전까지 얼마든지 수정이 가능합니다", hw_student_desc_2: '* 제출 기한이 지나면 과제를 제출할 수 없습니다.', popup_create_class: '학급 만들기', class_name: '학급 이름', image: '이미지', select_class_image: '학급 이미지를 선택해 주세요.', type_class_description: '학급 소개 입력', set_as_primary_group: '기본학급으로 지정', set_primary_group: '지정', not_primary_group: '지정안함', type_class_name: '학급 이름을 입력해주세요. ', type_class_description_long: '학급 소개를 입력해 주세요. 170자 이내', add_students: '학생 추가하기', invite_students: '학생 초대하기', invite_with_class: '1. 학급 코드로 초대하기', invite_code_expiration: '코드 만료시간', generate_code_button: '코드재발급', generate_code_desc: '학생의 학급 코드 입력 방법', generate_code_desc1: '엔트리 홈페이지에서 로그인을 해주세요.', generate_code_desc2: '메뉴바에서<나의 학급>을 선택해주세요.', generate_code_desc3: '<학급코드 입력하기>를 눌러 학급코드를 입력해주세요.', invite_with_url: '2. 학급 URL로 초대하기', copy_invite_url: '복사하기', download_as_pdf: '학급계정 PDF로 내려받기', download_as_excel: '학급계정 엑셀로 내려받기', temp_password: '임시 비밀번호 발급', can_not_change: '변경 불가', step_name: '이름 입력', step_info: '정보 추가/수정', preview: '미리보기', type_name_enter: '학급에 추가할 학생의 이름을 입력하고 엔터를 치세요.', multiple_name_possible: '여러명의 이름 입력이 가능합니다.', id_auto_create: '학번은 별도로 수정하지 않으면 자동으로 생성됩니다.', student_id_desc_1: '학급 아이디는 별도의 입력없이 자동으로 생성됩니다.', student_id_desc_2: '단, 엔트리에 이미 가입된 학생을 학급에 추가한다면 학생의 엔트리 아이디를', student_id_desc_3: '입력해주세요. 해당 학생은 로그인 후, 학급 초대를 수락하면 됩니다.', student_number: '학번', temp_password_desc_1: '임시 비밀번호로 로그인 후,', temp_password_desc_2: '신규 비밀번호를 다시 설정할 수 있도록 안내해주세요.', temp_password_desc_3: '*한번 발급된 임시 비밀번호는 다시 볼 수 없습니다.', temp_password_demo: '로그인 불가능한 안내 용 예시 계정입니다.', temp_works: '작품 보기', student_delete_confirm: '학생을 정말 삭제하시겠습니까?', no_student_selected: '선택된 학생이 없습니다.', class_assignment: '학급 과제', class_list: '학급 목록', select_grade: '학년을 선택 하세요.', add_project: '작품 공유하기', no_project_display: '학생들이 전시한 작품이 없습니다.', plz_display_project: '나의 작품을 전시해 주세요.', refuse_confirm: '학급 초대를 정말 거절하시겠습니까?', select_class: '학급 선택', group_already_registered: '이미 가입된 학급입니다.', my_page_entry: '엔트리', my_page_title: '마이페이지', my_classGroup_title: '나의 학급', my_classGroup_title_view: '나의 학급 보기', my_space_area: '나만의 공간', mon: '월', tue: '화', wed: '수', thu: '목', fri: '금', sat: '토', sun: '일', jan: '1월', feb: '2월', mar: '3월', apr: '4월', may: '5월', jun: '6월', jul: '7월', aug: '8월', sep: '9월', oct: '10월', nov: '11월', dec: '12월', plz_select_lecture: '강의를 선택해 주세요.', plz_set_deadline: '마감일을 설정해 주세요.', hide_entry: '엔트리 가리기', hide_others: '기타 가리기', show_all: '모두 보기', lecture_description: '선생님들이 직접 만드는 엔트리 학습 공간입니다. 강의에서 예시작품을 보고 작품을 만들며 배워 보세요.', curriculum_description: '학습 순서와 주제에 따라 여러 강의가 모아진 학습 공간입니다. 강의 모음의 순서에 맞춰 차근차근 배워보세요.', linebreak_off_desc_1: '글상자의 크기가 글자의 크기를 결정합니다.', linebreak_off_desc_2: '내용을 한 줄로만 작성할 수 있습니다.', linebreak_off_desc_3: '새로운 글자가 추가되면 글상자의 좌우 길이가 길어집니다.', linebreak_on_desc_1: '글상자의 크기가 글자가 쓰일 수 있는 영역을 결정합니다.', linebreak_on_desc_2: '내용 작성시 엔터키로 줄바꿈을 할 수 있습니다.', linebreak_on_desc_3: '새로운 글자 추가 시 문장의 길이가 글상자의 가로 영역을 넘어가면 자동으로 줄이 바뀝니다.', not_supported_text: '해당 글씨체는 한자를 지원하지 않습니다.', entry_with: '함께 만드는 엔트리', ebs_season_1: '시즌 1 보러가기', ebs_season_2: '시즌 2 보러가기', hello_ebs: '헬로! EBS 소프트웨어', hello_ebs_desc: '<헬로! EBS 소프트웨어> 엔트리 버전의 양방향 서비스를 만나보세요! \n <헬로! EBS 소프트웨어>의 동영상 강의를 통해 \n 소프트웨어 코딩의 기본 개념을 배운 후 양방향 코딩 미션에 도전하세요!\n 방송에서는 볼 수 없었던 <대.소.동> 친구들의 \n 비하인드 스토리를 볼 수 있습니다!', hello_ebs_sub_1: 'EBS 중학 엔트리 버전의 양방향 서비스를 ', hello_ebs_sub_2: '만나보세요! ', exhibit_4th_title: '엔트리 4주년 기념', exhibit_4th_subtitle: '엔트리 작품 공모전', exhibit_4th_desc1: '엔트리 탄생 4주년을 기념하여 작품 공모전을 개최합니다.', exhibit_4th_desc2: '‘우리 모두를 위한 소프트웨어’를 주제로', exhibit_4th_desc3: '여러분의 멋진 작품을 뽐내보세요!', exhibit_4th_button: '자세히 보기', visang_edu_entry: '비상교육 엔트리 학습하기', cmass_edu_entry: '씨마스 엔트리 학습하기', chunjae_edu_entry: '천재교과서 엔트리 학습하기', kumsungemt_edu_entry: '금성출판사 엔트리 학습하기', kumsungMid_edu_entry: '금성출판사 엔트리 학습하기', gilbutEdu_edu_entry: '길벗출판사 엔트리 학습하기', miraenCoding_edu_entry: '미래엔 엔트리 학습하기', textbook_help_data: '도움자료', textbook_teaching_activity: '수업 교안&활동지', textbook_kyohacksa: '교학사', textbook_kumsung: '금성출판사', textbook_donga: '동아출판', textbook_chunjae: '천재교과서', textbook_miraen: '미래엔', textbook_visang: '비상교육', partner: '파트너', project_term_popup_title: '작품 공개에 따른 엔트리 저작권 정책 동의', project_term_popup_description_1: '작품 공개를 위해', project_term_popup_description_2: '아래 정책을 확인해주세요.', project_term_popup_description_3: '', project_term_popup_description_4: '', project_term_agree_1_1: '내가 만든 작품과 그 소스코드의 공개를 동의합니다.', project_term_agree_2_1: '다른 사람이 나의 작품을 이용하는 것을 허락합니다.', project_term_agree_2_2: '( 복제 , 배포 , 공중송신 포함 )', project_term_agree_3_1: '다른 사람이 나의 작품을 수정하는 것을 허락합니다.', project_term_agree_3_2: '( 리믹스, 변형, 2차 제작물 작성 포함)', agree_all: '전체 동의', select_login: '로그인 선택', select: '선택하세요', with_login: '로그인 하고', without_login: '로그인 안하고', start_challenge: '미션 도전하기', start_challenge_2: '미션 도전하기', if_not_save_not_login: '* 로그인을 안하고 미션에 참여하시면 진행 상황이 저장되지 않습니다.', if_not_member_yet: '엔트리 회원이 아니라면?', join_entry: '엔트리 회원 가입하기', learned_computing: '기존에 소프트웨어 교육을 받아보셨나요?', cparty_index_description_1: '두근두근 소프트웨어와 첫 만남.', cparty_index_description_2: '소프트웨어랑 재미있게 놀다 보면 소프트웨어의 원리도 배우고, 생각하는 힘도 쑥쑥!', cparty_index_description_3: '엔트리를 통해 코딩 미션에 도전하고 인증서 받으세요.', cparty_index_description_4: '2015 Online Coding Party는', cparty_index_description_5: 'SW교육 체험 주간', cparty_index_description_6: '의 일환으로써,', cparty_index_description_7: '초등컴퓨팅교사협회', cparty_index_description_8: '과 함께 만들어졌습니다.', cparty_index_description_9: '2016 Online Coding Party는', cparty_index_description_10: '2017 Online Coding Party는', cparty_index_description_11: "'SW교육을 준비하는 선생님들의 모임'", congratulation: '축하 드립니다!', warm_up: '체험', beginner: '입문', intermediate: '기본', advanced: '발전', applied: '응용', cert_msg_tail: '과정을 성공적으로 마쳤습니다.', cert_msg_head: '', maze_text_content_1: '안녕? 나는 엔트리봇이야. 지금 나는 공장에서 탈출을 해야 해! 탈출하기 위해서 먼저 몸을 고쳐야 할 것 같아. 앞에 있는 부품을 얻을 수 있게 도와줄래? move()', maze_text_content_2: '좋아 아주 잘했어! 덕분에 몸이 한결 가벼워졌어! 이번에도 부품상자까지 나를 이동시켜줘. 그런데 가는길에 장애물이 있어. 장애물 앞에서는 jump()', maze_text_content_3: '멋진걸! 저기에도 부품이 있어! 길이 조금 꼬여있지만 오른쪽, 왼쪽으로 회전할 수 있는 right(); left(); 명령어를 쓰면 충분히 갈 수 있을것 같아!', maze_text_content_4: '좋아 이제 움직이는 건 많이 편해졌어! 이번에는 지금까지 배운 명령어를 같이 써서 저 부품상자까지 가보자!', maze_text_content_5: '우와 부품이 두 개나 있잖아! 두 개 다 챙겨서 가자! 그러면 몸을 빨리 고칠 수 있을 것 같아!', maze_text_content_6: '이번이 마지막 부품들이야! 저것들만 있으면 내 몸을 다 고칠 수 있을 거야! 이번에도 도와줄 거지?', maze_text_content_7: '덕분에 몸이 아주 좋아졌어! 이제 똑같은 일을 여러 번 반복해도 무리는 없을 거야. 어? 그런데 앞에 있는 저 로봇은 뭐지? 뭔가 도움이 필요한 것 같아! 도와주자! for 명령어를 사용해서 저 친구한테 나를 데려다줘!', maze_text_content_8: '좋아! 덕분에 친구 로봇을 살릴 수 있었어! 하지만 앞에도 도움이 필요한 친구가 있네, 하지만 이번에는 벌집이 있으니까 조심해서 벌집에 안 닿게 뛰어넘어가자! 할 수 있겠지? 이번에도 for 명령어를 사용해서 친구가 있는곳까지 나를 이동시켜줘!', maze_text_content_9: '이번에는 for 명령어 대신 미션이 끝날때까지 같은 일을 반복하도록 하는 while 명령어를 사용해봐! 나를 친구에게 데려다주면 미션이 끝나!', maze_text_content_10: '이번에는 if 명령어가 나왔어! if와 while 명령어를 사용해서 내가 언제 어느 쪽으로 회전해야 하는지 알려줘!', maze_text_content_11: '좋아 아까 했던 것처럼 해볼까? 언제 왼쪽으로 돌아야 하는지 알려줄 수 있겠어?', maze_text_content_12: '이번에는 중간중간 벌집(bee)이 있네? 언제 뛰어넘어가야 할지 알려줄래?', maze_text_content_13: '여기저기 도움이 필요한 친구들이 많이 있네! 모두 가서 도와주자!', maze_text_content_14: '우와 이번에도 도와줘야 할 친구들이 많네. 먼저 조그마한 사각형을 돌도록 명령어를 만들고 만든 걸 반복해서 모든 친구를 구해보자.', maze_text_content_15: '오래 움직이다 보니 벌써 지쳐버렸어. 자주 쓰는 명령어를 function 명령어를 사용해서 함수로 만들어 놓았어! 함수를 사용하여 나를 배터리 까지 이동시켜줘!', maze_text_content_16: '좋아 멋진걸! 그럼 이번에는 함수에 들어갈 명령어들을 넣어서 나를 배터리까지 이동시켜줘!', maze_text_content_17: '좋아 이번에는 함수를 만들고, 함수를 사용해서 배터리를 얻을 수 있도록 도와줘! 함수를 만들때 jump();를 잘 섞어봐!', maze_text_content_18: '이번에는 길이 좀 복잡한걸? 그래도 언제 left();를 쓰고, 언제 right();를 쓰면 되는지 알려만 주면 배터리 까지 갈 수 있겠어!.', maze_text_content_19: '이번에는 함수가 미리 정해져 있어! 그런데 함수만 써서 배터리까지 가기 힘들것 같아. 함수와 다른 명령어들을 섞어 써서 배터리 까지 이동시켜줘!', maze_text_content_20: '좋아! 지금까지 정말 멋지게 잘 해줬어. 덕분에 이제 마지막 배터리만 채우면 앞으로는 충전이 필요 없을 거야. 함수를 이용해서 저 배터리를 얻고 내가 자유롭게 살 수 있도록 도와줘!', maze_content_1: '안녕 나는 엔트리봇이라고 해. 지금 나는 공장에서 탈출하려는데 먼저 몸을 고쳐야 할 것 같아. 앞에 있는 부품을 얻을 수 있게 도와줄래? 앞으로 가기 블록을 조립하고 시작을 눌러봐.', maze_content_2: '좋아 아주 잘했어! 덕분에 몸이 한결 가벼워졌어! 앞에도 부품이 있는데 이번에는 잘못 가다간 감전되기 쉬울 것 같아. 한 번 장애물 뛰어넘기 블록을 써서 부품까지 가볼까?', maze_content_3: '멋진걸! 저기에도 부품이 있어! 길이 조금 꼬여있지만 회전하기 블록을 쓰면 충분히 갈 수 있을 것 같아! 이번에도 도와줄 거지?', maze_content_4: '좋아 이제 움직이는 건 많이 편해졌어! 이번에는 회전과 뛰어넘기를 같이 써서 저 부품을 얻어보자!', maze_content_5: '우와 부품이 두 개나 있잖아! 두 개 다 챙겨서 가자! 그러면 몸을 빨리 고칠 수 있을 것 같아!', maze_content_6: '이번이 마지막 부품들이야! 저것들만 있으면 내 몸을 다 고칠 수 있을 거야! 이번에도 도와줄 거지?', maze_content_7: '덕분에 몸이 아주 좋아졌어! 이제 똑같은 일을 여러 번 반복해도 무리는 없을 거야. 어? 그런데 앞에 있는 저 로봇은 뭐지? 뭔가 도움이 필요한 것 같아! 도와주자! 얼른 반복하기의 숫자를 바꿔서 저 친구한테 나를 데려다줘!', maze_content_8: '좋아! 덕분에 친구 로봇을 살릴 수 있었어! 하지만 앞에도 도움이 필요한 친구가 있는 것 같아, 하지만 이번에는 벌집이 있으니까 조심해서 벌집에 안 닿게 뛰어넘어가자! 할 수 있겠지? 그럼 아까 했던 것처럼 반복을 써서 친구한테 갈 수 있게 해줄래?', maze_content_9: '이번에는 숫자만큼 반복하는 게 아니라 친구 로봇한테 갈 때까지 똑같은 일을 반복할 수 있어! 이번에도 친구를 구할 수 있도록 도와줘!', maze_content_10: '이번에는 만약 블록이란 게 있어! 만약 블록을 써서 언제 어느 쪽으로 돌아야 하는지 알려줘!', maze_content_11: '좋아 아까 했던 것처럼 해볼까? 언제 왼쪽으로 돌아야 하는지 알려줄 수 있겠어?', maze_content_12: '이번에는 중간중간 벌집이 있네? 언제 뛰어넘어가야 할지 알려줄래?', maze_content_13: '여기저기 도움이 필요한 친구들이 많이 있네! 모두 도와주자!', maze_content_14: '우와 이번에도 도와줘야 할 친구들이 많네. 먼저 조그마한 사각형을 돌도록 블록을 만들고 만든 걸 반복해서 모든 친구를 구해보자.', maze_content_15: '반복을 하도 많이 했더니 자주 쓰는 블록은 외울 수 있을 것 같아! 약속 블록은 지금 내가 외운 블록들이야! 일단은 오래 움직여서 지쳤으니까 배터리를 좀 채울 수 있게 약속 호출 블록을 써서 배터리를 채울 수 있게 해줘!', maze_content_16: '좋아 멋진걸! 그럼 이번에는 네가 자주 쓰일 블록을 나한테 가르쳐줘! 약속 정의 블록 안에 자주 쓰일 블록을 넣어보면 돼!', maze_content_17: '좋아 이번에도 그러면 약속을 이용해서 배터리를 얻을 수 있도록 도와줄 거지? 약속에 뛰어넘기를 잘 섞어봐!', maze_content_18: '이번에는 길이 좀 복잡한걸? 그래도 언제 왼쪽으로 돌고, 언제 오른쪽으로 돌면 되는지 알려만 주면 충전할 수 있을 것 같아.', maze_content_19: '이번에는 약속이 미리 정해져 있어! 그런데 바로 약속을 쓰기에는 안될 것 같아. 내가 갈 길을 보고 약속을 쓰면 배터리를 채울 수 있을 것 같은데 도와줄 거지?', maze_content_20: '좋아! 지금까지 정말 멋지게 잘 해줬어. 덕분에 이제 마지막 배터리만 채우면 앞으로는 충전이 필요 없을 거야. 그러니까 약속을 이용해서 저 배터리를 얻고 내가 자유롭게 살 수 있도록 도와줄래?', maze_content_21: '안녕? 나는 엔트리 봇이야. 지금 많은 친구들이 내 도움을 필요로 하고 있어. 반복하기를 이용해서 친구들을 도울수 있게 데려다 줘!', maze_content_22: '고마워! 이번에는 벌집을 뛰어넘어서 친구를 구하러 갈 수 있게 도와줘!', maze_content_23: '좋아! 이번에는 친구 로봇한테 갈 때까지 반복하기를 이용해서 친구를 도울 수 있게 도와줘!', maze_content_24: '안녕! 나는 엔트리 봇이야. 지금 나는 너무 오래 움직여서 배터리를 채워야 해. 약속 불러오기를 써서 배터리를 채울 수 있도록 도와줘!', maze_content_25: '멋져! 이번에는 여러 약속을 불러와서 배터리가 있는 곳까지 가보자!', maze_content_26: '좋아! 이제 약속할 블록을 나한테 가르쳐줘! 약속하기 블록 안에 자주 쓰일 블록을 넣으면 돼!', maze_content_27: '지금은 미리 약속이 정해져 있어. 그런데, 약속을 쓰기위해서는 내가 갈 방향을 보고 약속을 사용해야해. 도와줄거지?', maze_content_28: '드디어 마지막이야! 약속을 이용하여 마지막 배터리를 얻을 수 있게 도와줘!', ai_content_1: '안녕? 나는 엔트리봇이라고 해. 우주 탐사를 마치고 지구로 돌아가려는데 우주를 떠다니는 돌들 때문에 쉽지 않네. 내가 안전하게 집에 갈 수 있도록 도와줄래? 나의 우주선에는 나의 앞과 위, 아래에 무엇이 어느 정도의 거리에 있는지 알려주는 레이더가 있어 너의 판단을 도와줄 거야!', ai_content_2: '고마워! 덕분에 돌을 쉽게 피할 수 있었어. 그런데 이번엔 더 많은 돌이 있잖아? 블록들을 조립하여 돌들을 이리저리 잘 피해 보자!', ai_content_3: '좋았어! 안전하게 돌을 피했어. 그런데 앞을 봐! 아까보다 더 많은 돌이 있어. 하지만 걱정하지 마. 나에게 반복하기 블록이 있거든. 반복하기 블록 안에 움직이는 블록을 넣으면 목적지에 도착할 때까지 계속 움직일게!', ai_content_4: '대단해! 반복하기 블록을 쓰니 많은 돌을 피하기가 훨씬 수월한걸! 하지만 이렇게 일일이 조종하기는 피곤하다. 나에겐 레이더가 있으니 앞으로 무엇이 나올지 알 수 있어. 앞으로 계속 가다가 앞에 돌이 있으면 피할 수 있도록 해줄래?', ai_content_5: '잘했어! 여기까지 와서 아주 기뻐. 이번에는 레이더가 앞에 있는 물체까지의 거리를 말해줄 거야. 이 기능을 사용하여 돌을 피해 보자! 돌까지의 거리가 멀 때는 앞으로 계속 가다가, 거리가 가까워지면 피할 수 있도록 해줄래?', ai_content_6: '와~ 멋진걸? 레이더를 활용하여 돌을 잘 피해 나가고 있어! 이번에는 여러 개의 레이더를 사용하여 이리저리 돌들을 피해 나갈 수 있게 만들어줄래?', ai_content_7: '휴~ 지구에 점점 가까워지고 있어! 돌을 피할 때 기왕이면 더 안전한 길로 가고 싶어! 아마도 돌이 더 멀리 있는 쪽이 더 안전한 길이겠지? 위쪽 레이더와 아래쪽 레이더를 비교하여 더 안전한 쪽으로 움직이도록 해줄래?', ai_content_8: '좋아! 덕분에 무사히 비행하고 있어. 어? 그런데 저게 뭐지? 저건 내가 아주 위급한 상황에서 사용할 수 있는 특별한 에너지야! 이번에는 저 아이템들을 모두 모으며 움직이자!', ai_content_9: '훌륭해! 이제 지구까지 얼마 안 남았어. 그런데 앞을 보니 돌들로 길이 꽉 막혀서 지나갈 수가 없잖아? 하지만 걱정하지 마. 아이템을 획득해서 사용하면 앞에 있는 꽉 막힌 돌들을 없앨 수 있다고!', ai_content_10: '좋아! 드디어 저기 지구가 보여! 이럴 수가! 이제는 날아오는 돌들을 미리 볼 수가 없잖아? 돌들이 어떻게 날아올지 알지 못해도 지금까지처럼만 움직이면 잘 피할 수 있을 것 같아! 지구까지 가보는 거야!', maze_hints_title_1: '시작 방법', maze_hints_content_1: '엔트리봇은 어떻게 움직이나요?', maze_hints_detail_1: '1. 블록 꾸러미에서 원하는 블록을 꺼내어 “시작하기를 클릭했을 때” 블록과 연결해봐
2. 다 조립했으면, 시작을 눌러봐
3. 나는 네가 조립한 블록대로 위에서부터 순서대로 움직일게', maze_hints_title_2: '장애물 뛰어넘기', maze_hints_content_2: '장애물이 있으면 어떻게 해야하나요?', maze_hints_detail_2: '길을 가다보면 장애물을 만날 수 있어.
장애물이 앞에 있을 때에는 뛰어넘기 블록을 사용해야 해.', maze_hints_title_3: '반복 블록(1)', maze_hints_content_3: '(3)회 반복하기 블록은 어떻게 사용하나요?', maze_hints_detail_3: '같은 행동을 여러번 반복하려면 ~번 반복하기 블록을 사용해야 해.
반복하고 싶은 블록들을 ~번 반복하기 안에 넣고 반복 횟수를 입력하면 돼.', maze_hints_title_4: '반복 블록(2)', maze_hints_content_4: '~를 만날 때 까지 반복하기 블록은 어떻게 사용하나요?', maze_hints_detail_4: "~까지 반복하기'를 사용하면 같은 행동을 언제까지 반복할지를 정해줄 수 있어.
반복하고 싶은 블록들을 ~까지 반복하기안에 넣으면 돼.
그러면 {이미지}와 같은 타일 위에 있는 경우 반복이 멈추게 될 거야.", maze_hints_title_5: '만약 블록', maze_hints_content_5: '만약 ~라면 블록은 어떻게 동작하나요?', maze_hints_detail_5: "만약 앞에 {이미지}가 있다면' 블록을 사용하면 앞에 {이미지}가 있을 때 어떤 행동을 할 지 정해줄 수 있어.
앞에 {이미지}가 있을 때에만 블록 안의 블록들을 실행하고
그렇지 않으면 실행하지 않게 되는 거야.", maze_hints_title_6: '반복 블록(3)', maze_hints_content_6: '모든 ~를 만날 때 까지 블록은 어떻게 동작하나요?', maze_hints_detail_6: '모든 {타일}에 한 번씩 도착할 때까지 그 안에 있는 블록을 반복해서 실행해.
모든 {타일}에 한 번씩 도착하면 반복이 멈추게 될 거야.', maze_hints_title_7: '특별 힌트', maze_hints_content_7: '너무 어려워요. 도와주세요.', maze_hints_detail_7: '내가 가야하는 길을 자세히 봐. 작은 사각형 4개가 보여?
작은 사각형을 도는 블록을 만들고, 반복하기를 사용해 보는것은 어때?', maze_hints_title_8: '약속', maze_hints_content_8: '약속하기/약속 불러오기 무엇인가요? 어떻게 사용하나요?', maze_hints_detail_8: "나를 움직이기 위해 자주 쓰는 블록들의 묶음을 '약속하기' 블록 아래에 조립하여 약속으로 만들 수 있어.
한번 만들어 놓은 약속은 '약속 불러오기' 블록을 사용하여 여러 번 꺼내 쓸 수 있다구.", ai_hints_title_1_1: '게임의 목표', ai_hints_content_1_1: '돌을 피해 오른쪽 행성까지 안전하게 이동할 수 있도록 도와주세요.', ai_hints_detail_1_1: '돌을 피해 오른쪽 행성까지 안전하게 이동할 수 있도록 도와주세요.', ai_hints_title_1_2: '시작 방법', ai_hints_content_1_2: '어떻게 시작할 수 있나요?', ai_hints_detail_1_2: '1. 블록 꾸러미에서 원하는 블록을 꺼내어 “시작하기를 클릭했을 때” 블록과 연결해봐
2. 다 조립했으면, 시작을 눌러봐
3. 나는 네가 조립한 블록대로 위에서부터 순서대로 움직일게', ai_hints_title_1_3: '움직이게 하기', ai_hints_content_1_3: '엔트리봇은 어떻게 움직이나요?', ai_hints_detail_1_3: '나는 위쪽으로 가거나 앞으로 가거나 아래쪽으로 갈 수 있어.
방향을 정할 때에는 돌이 없는 방향으로 안전하게 갈 수 있도록 해줘.
나를 화면 밖으로 내보내면 우주미아가 되어버리니 조심해!', ai_hints_title_2_1: '게임의 목표', ai_hints_content_2_1: '반복하기 블록으로 돌들을 피할 수 있도록 도와주세요.', ai_hints_detail_2_1: '반복하기 블록으로 돌들을 피할 수 있도록 도와주세요.', ai_hints_title_2_2: '반복 블록', ai_hints_content_2_2: '반복 블록은 무슨 블록인가요?', ai_hints_detail_2_2: '휴~ 이번에 가야 할 길은 너무 멀어서 하나씩 조립하기는 힘들겠는걸? 반복하기블록을 사용해봐.
똑같이 반복되는 블록들을 반복하기 블록으로 묶어주면 아주 긴 블록을 짧게 줄여줄 수 있어!', ai_hints_content_3_1: '만약 블록으로 돌을 피할 수 있도록 도와주세요.', ai_hints_title_3_2: '만약 블록(1)', ai_hints_content_3_2: '만약 ~라면 블록은 어떻게 동작하나요?', ai_hints_detail_3_2: "만약 앞에 ~가 있다면 / 아니면 블록을 사용하면 내 바로 앞에 돌이 있는지 없는지 확인해서 다르게 움직일 수 있어~
만약 내 바로 앞에 돌이 있다면 '만약' 아래에 있는 블록들을 실행하고 돌이 없으면 '아니면' 안에 있는 블록들을 실행할 거야.
내 바로 앞에 돌이 있을 때와 없을 때, 어떻게 움직일지 잘 결정해줘~", ai_hints_content_4_1: '레이더의 사용 방법을 익히고 돌을 피해보세요.', ai_hints_detail_4_1: '레이더의 사용 방법을 익히고 돌을 피해보세요.', ai_hints_title_4_2: '레이더(1)', ai_hints_content_4_2: '레이더란 무엇인가요? 어떻게 활용할 수 있나요?', ai_hints_detail_4_2: "레이더는 지금 내가 물체와 얼마나 떨어져 있는지 알려주는 기계야.
만약 바로 내 앞에 무엇인가 있다면 앞쪽 레이더는 '1'을 보여줘.
또, 레이더는 혼자 있을 때 보다 만약 <사실>이라면 / 아니면 블록과
같이 쓰이면 아주 강력하게 쓸 수 있어.
예를 들어 내 앞에 물체와의 거리가 1보다 크다면 나는 안전하게 앞으로 갈 수 있겠지만, 아니라면 위나 아래쪽으로 피하도록 할 수 있지.", ai_hints_title_4_3: '만약 블록(2)', ai_hints_content_4_3: '만약 <사실>이라면 블록은 어떻게 사용하나요?', ai_hints_detail_4_3: "만약 <사실>이라면 / 아니면 블록은 <사실> 안에 있는 내용이 맞으면 '만약' 아래에 있는 블록을 실행하고, 아니면 '아니면' 아래에 있는 블록을 실행해.
어떤 상황에서 다르게 움직이고 싶은 지를 잘 생각해서 <사실> 안에 적절한 판단 조건을 만들어 넣어봐.
판단 조건을 만족해서 '만약' 아래에 있는 블록을 실행하고 나면 '아니면' 아래에 있는 블록들은 실행되지 않는다는 걸 기억해!", ai_hints_content_5_1: '레이더를 활용해 돌을 쉽게 피할 수 있도록 도와주세요.', ai_hints_detail_5_1: '레이더를 활용해 돌을 쉽게 피할 수 있도록 도와주세요.', ai_hints_title_5_2: '만약 블록(3)', ai_hints_content_5_2: '만약 블록이 겹쳐져 있으면 어떻게 동작하나요?', ai_hints_detail_5_2: '만약 ~ / 아니면 블록안에도 만약 ~ / 아니면 블록을 넣을 수 있어! 이렇게 되면 다양한 상황에서 내가 어떻게 행동해야 할지 정할 수 있어.
예를 들어 앞에 돌이 길을 막고 있을때와 없을때의 행동을 정한다음, 돌이 있을때의 상황에서도 상황에 따라 위쪽으로 갈지 아래쪽으로 갈지 선택 할 수 있어', ai_hints_title_6_1: '레이더(2)', ai_hints_content_6_1: '위쪽 레이더와 아래쪽 레이더의 값을 비교하고 싶을 땐 어떻게 하나요?', ai_hints_detail_6_1: '([위쪽]레이더) 블록은 위쪽 물체까지의 거리를 뜻하는 블록이야.
아래쪽과 위쪽 중에서 어느 쪽에 돌이 더 멀리 있는지 확인하기 위해서 쓸 수 있는 블록이지.
돌을 피해가는 길을 선택할 때에는 돌이 멀리 떨어져 있는 쪽으로 피하는게 앞으로 멀리 가는데 유리할거야~', ai_hints_content_7_1: '아이템을 향해 이동하여 돌을 피해보세요.', ai_hints_detail_7_1: '아이템을 향해 이동하여 돌을 피해보세요.', ai_hints_title_7_2: '물체 이름 확인', ai_hints_content_7_2: '앞으로 만날 물체의 이름을 확인해서 무엇을 할 수 있나요?', ai_hints_detail_7_2: '아이템을 얻기위해서는 아이템이 어디에 있는지 확인할 필요가 있어.
그럴 때 사용할 수 있는 블록이 [위쪽] 물체는 [아이템]인가? 블록이야.
이 블록을 활용하면 아이템이 어느 위치에 있는지 알 수 있고 아이템이 있는 방향으로 움직이도록 블록을 조립할 수 있어.', ai_hints_content_8_1: '아이템을 적절하게 사용해서 돌을 피해보세요.', ai_hints_detail_8_1: '아이템을 적절하게 사용해서 돌을 피해보세요.', ai_hints_title_8_2: '아이템', ai_hints_content_8_2: '아이템은 어떻게 얻고 사용하나요?', ai_hints_detail_8_2: '돌들을 이리저리 잘 피해 나가더라도 앞이 모두 돌들로 꽉 막혀있을 땐 빠져나갈 방법이 없겠지? 그럴 때에는 아이템사용 블럭을 사용해봐.
이 블록은 내 앞의 돌들을 모두 없애는 블록이야.
단, 아이템이 있어야지만 블록을 사용할 수 있고, 아이템은 이미지를 지나면 얻을 수 있어.', ai_hints_content_9_1: '지금까지 배운 것들을 모두 활용해서 최대한 멀리 가보세요.', ai_hints_detail_9_1: '지금까지 배운 것들을 모두 활용해서 최대한 멀리 가보세요.', ai_hints_title_9_2: '그리고', ai_hints_content_9_2: '그리고 블록은 어떻게 사용하나요?', ai_hints_detail_9_2: '그리고 블록에는 여러개의 조건을 넣을 수 있어, 넣은 모든 조건이 사실일때만 사실이 되어 만약 블록 안에 있는 블록이 실행되고, 하나라도 거짓이 있으면 거짓으로 인식해서 그 안에 있는 블록을 실행하지 않아', maze_text_goal_1: 'move(); 명령어를 사용하여 부품 상자까지 나를 이동시켜줘!', maze_text_goal_2: 'jump(); 명령어로 장애물을 피해 부품 상자까지 나를 이동시켜줘!', maze_text_goal_3: 'left(); right(); 명령어로 부품상자까지 나를 이동시켜줘!', maze_text_goal_4: '여러가지 명령어를 사용하여 부품상자까지 나를 이동시켜줘!', maze_text_goal_5: '두 부품상자에 다 갈 수 있도록 나를 이동시켜줘!', maze_text_goal_6: '두 부품상자에 다 갈 수 있도록 나를 이동시켜줘!', maze_text_goal_7: 'for 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_8: 'for 명령어를 사용하고, 장애물을 피해 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_9: 'while 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_10: 'if와 while 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_11: 'if와 while 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_12: 'if와 while 명령어를 사용하여 친구가 있는 곳 까지 나를 이동시켜줘!', maze_text_goal_13: 'while과 for 명령어를 사용하여 모든 친구들을 만날 수 있도록 나를 이동시켜줘!', maze_text_goal_14: 'while과 for 명령어를 사용하여 모든 친구들을 만날 수 있도록 나를 이동시켜줘!', maze_text_goal_15: '함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_16: '함수에 명령어를 넣고 함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_17: '함수에 명령어를 넣고 함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_18: '함수에 명령어를 넣고 함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_19: '함수에 명령어를 넣고 함수를 불러와서 배터리까지 나를 이동시켜줘!', maze_text_goal_20: '함수와 다른명령어들을 섞어 사용하여 배터리까지 나를 이동시켜줘!', maze_attack_range: '공격 가능 횟수', maze_attack: '공격', maze_attack_both_sides: '양 옆 공격', above_radar: '위쪽 레이더', above_radar_text_mode: 'radar_up', bottom_radar: '아래쪽 레이더', bottom_radar_text_mode: 'radar_down', front_radar: '앞쪽 레이더', front_radar_text_mode: 'radar_right', above_object: '위쪽 물체', above_object_text_mode: 'object_up', front_object: '앞쪽 물체', front_object_text_mode: 'object_right', below_object: '아래쪽 물체', below_object_text_mode: 'object_down', destination: '목적지', asteroids: '돌', item: '아이템', wall: '벽', destination_text_mode: 'destination', asteroids_text_mode: 'stone', item_text_mode: 'item', wall_text_mode: 'wall', buy_now: '구매바로가기', goals: '목표', instructions: '이용 안내', object_info: '오브젝트 정보', entry_basic_mission: '엔트리 기본 미션', entry_application_mission: '엔트리 응용 미션', maze_move_forward: '앞으로 한 칸 이동', maze_when_run: '시작하기를 클릭했을때', maze_turn_left: '왼쪽으로 회전', maze_turn_right: '오른쪽으로 회전', maze_repeat_times_1: '', maze_repeat_times_2: '번 반복하기', maze_repeat_until_1: '', maze_repeat_until_2: '을 만날때까지 반복', maze_call_function: '약속 불러오기', maze_function: '약속하기', maze_repeat_until_all_1: '모든', maze_repeat_until_all_2: '만날 때 까지 반복', command_guide: '명령어 도움말', ai_success_msg_1: '덕분에 무사히 지구에 도착할 수 있었어! 고마워!', ai_success_msg_2: '다행이야! 덕분에', ai_success_msg_3: '번 만큼 앞쪽으로 갈 수 있어서 지구에 구조 신호를 보냈어! 이제 지구에서 구조대가 올거야! 고마워!', ai_success_msg_4: '좋았어!', ai_cause_msg_1: '이런, 어떻게 움직여야 할 지 더 말해줄래?', ai_cause_msg_2: '아이쿠! 정말로 위험했어! 다시 도전해보자', ai_cause_msg_3: '우와왓! 가야할 길에서 벗어나버리면 우주 미아가 되버릴꺼야. 다시 도전해보자', ai_cause_msg_4: '너무 복잡해, 이 블록을 써서 움직여볼래?', ai_move_forward: '앞으로 가기', ai_move_above: '위쪽으로 가기', ai_move_under: '아래쪽으로 가기', ai_repeat_until_dest: '목적지에 도달 할 때까지 반복하기', ai_if_front_1: '만약 앞에', ai_if_front_2: '가 있다면', ai_else: '아니면', ai_if_1: '만약', ai_if_2: '이라면', ai_use_item: '아이템 사용', ai_radar: '레이더', ai_above: '위쪽', ai_front: '앞쪽', ai_under: '아래쪽', ai_object_is_1: '', ai_object_is_2: '물체는', challengeMission: '다른 미션 도전하기', nextMission: '다음 미션 도전하기', withTeacher: '함께 만든 선생님들', host: '주최', support: '후원', subjectivity: '주관', learnMore: ' 더 배우고 싶어요', ai_object_is_3: '인가?', stage_is_not_available: '아직 진행할 수 없는 스테이지입니다. 순서대로 스테이지를 진행해 주세요.', progress_not_saved: '진행상황이 저장되지 않습니다.', want_refresh: '이 페이지를 새로고침 하시겠습니까?', monthly_entry_grade: '초등학교 3학년 ~ 중학교 3학년', monthly_entry_contents: '매월 발간되는 월간엔트리와 함께 소프트웨어 교육을 시작해 보세요! 차근차근 따라하며 쉽게 익힐 수 있도록 가볍게 구성되어있습니다. 기본, 응용 콘텐츠와 더 나아가기까지! 매월 업데이트되는 8개의 콘텐츠와 교재를 만나보세요~', monthly_entry_etc1: '*메인 페이지의 월간 엔트리 추천코스를 활용하면 더욱 쉽게 수업을 할 수 있습니다.', monthly_entry_etc2: '*월간엔트리는 학기 중에만 발간됩니다.', group_make_lecture_1: '내가 만든 강의가 없습니다.', group_make_lecture_2: "'만들기>오픈 강의 만들기'에서", group_make_lecture_3: '우리반 학습내용에 추가하고 싶은 강의를 만들어 주세요.', group_make_lecture_4: '강의 만들기', group_add_lecture_1: '관심 강의가 없습니다.', group_add_lecture_2: "'학습하기>오픈 강의> 강의'에서 우리반 학습내용에", group_add_lecture_3: '추가하고 싶은 강의를 관심강의로 등록해 주세요.', group_add_lecture_4: '강의 보기', group_make_course_1: '내가 만든 강의 모음이 없습니다.', group_make_course_2: "'만들기 > 오픈 강의 만들기> 강의 모음 만들기'에서", group_make_course_3: '학습내용에 추가하고 싶은 강의 모음을 만들어 주세요.', group_make_course_4: '강의 모음 만들기', group_add_course_1: '관심 강의 모음이 없습니다.', group_add_course_2: "'학습하기 > 오픈 강의 > 강의 모음'에서 우리반 학습내용에", group_add_course_3: '추가하고 싶은 강의 모음을 관심 강의 모음으로 등록해 주세요.', group_add_course_4: '강의 모음 보기', hw_main_title: '프로그램 다운로드', ai_banner_title: '인공지능 블록', ai_banner_headline1: '생활 속 인공지능 알아보기', ai_banner_headline2: ' ', ai_banner_text1: '인공지능은 우리와 가까이 있어요.', ai_banner_text2: '인공지능 활용에서 모델 학습까지 직접 만나보세요!', rv_banner_title: '실시간 변수/리스트', rv_banner_headline1: '사라져도 되는 정보,', rv_banner_headline2: '사라지면 안 되는 정보', rv_banner_text1: '변수와 리스트를 서버에 저장해', rv_banner_text2: '실시간으로 정보를 사용해보세요!', banner_default_title: '소프트웨어 교육의 첫걸음', banner_default_title_head1: '엔트리', banner_default_title_body1: '누구나 쉽고 재밌게 소프트웨어를 배울 수 있어요.', banner_default_title_body2: '지금 바로 시작해보세요!', playsw_banner_title: '소프트웨어야 놀자', rsc2020_banner_head1: 'with 엔트리 인공지능', rsc2020_banner_title: '세상을 디자인하는 RSC 2020', rsc2020_banner_body1: '내 아이디어와 인공지능으로', rsc2020_banner_body2: '세상을 행복하게 만들기 프로젝트', playswai_banner_title: '소프트웨어야 놀자 (SECC2020)', playswai_banner_head1: '소프트웨어 교육', playswai_banner_head2: '콘텐츠 콘테스트', playswai_banner_body1: '엔트리의 인공지능과 데이터 분석 기능을', playswai_banner_body2: '활용한 다양한 작품을 기다립니다!', playsw_banner_head1: 'Play with AI, Play with DATA', playsw_banner_body1: '엔트리에서 인공지능 작품을 더 잘 만들고 싶다면?', playsw_banner_body2: '다양한 인공지능 콘텐츠와 함께 작품을 업그레이드 해보세요!', privacy_contest_title: '개인정보 보호', privacy_content_head1: '우리 모두 지켜요', privacy_content_head2: '안전한 엔트리 라이프', privacy_content_body1: '개인정보에는 나의 모든 것이 담겨있어요.', privacy_content_body2: '소중한 개인정보 안전하게 지켜요!', campaign_contest_title: '코로나19 함께 이겨내보아요', campaign_content_head: '', campaign_content_body1: '모두에게 도움이 되는 작품을 만들어 공유해보세요.', campaign_content_body2: '매주 우수작품을 선정하여 많은 사람들에게', campaign_content_body3: '코로나19를 이겨낼 수 있는 힘을 전할 수 있어요!', campaign_content_button: '캠페인 보기', code_management_1: '엔트리 캠페인 #1 코드 잘 관리하기', code_management_2: '나의 보관함과 메모 활용', code_management_3: '새 기능 나의 보관함과 메모로 하는 코드 관리 비법!', code_management_4: '작품을 더 잘 만들고 쉽게 공유하는 방법을 알아보아요.', code_management_5: '캠페인 보기', shcoolbook_study_1: '교과서 내용 그대로 학습하세요.', shcoolbook_study_2: '교과서 학습하기', shcoolbook_study_3: '선생님은 교실에서 수업 진행을', shcoolbook_study_4: '학생은 집에서 복습을 할 수 있습니다!', shcoolbook_study_5: '학습하기', main_learn_1: '엔트리에 처음 오셨다면', main_learn_2: '엔트리 알아보기', main_learn_3: '영상을 통해 엔트리의 다양한 기능을 알아보고,', main_learn_4: '멋진 작품을 만들어 친구들과 공유해보세요!', main_learn_5: '영상보기', hw_desc_wrapper: '엔트리 하드웨어 연결 프로그램과 오프라인 버전이 \n서비스를 한층 더 강화해 업그레이드 되었습니다.\n업데이트 된 프로그램을 설치해주세요!', hw_downolad_link: '하드웨어 연결 \n프로그램 다운로드', save_as_image_all: '모든 코드 이미지로 저장하기', save_as_image: '이미지로 저장하기', maze_perfect_success: '멋져! 완벽하게 성공했어~', maze_success_many_block_1: '좋아', maze_fail_obstacle_remain: "친구들이 다치지 않도록 모든 을 없애줘.", maze_fail_item_remain: '샐리 공주를 구하기 위해 모든 미네랄을 모아 와줘.', maple_fail_item_remain: '음식을 다 먹지 못해서 힘이 나지 않아. 모든 음식을 다 먹을 수 있도록 도와줘.', maze_fail_not_found_destory_object: '아무것도 없는 곳에 능력을 낭비하면 안 돼!', maze_fail_not_found_destory_monster: '몬스터가 없는 곳에 공격을 하면 안 돼!', maple_fail_not_found_destory_monster: '공격 블록은 몬스터가 있을 때에만 해야 돼!', maze_fail_more_move: '목적지까지는 좀 더 움직여야 해!', maze_fail_wall_crash: '으앗! 거긴 갈 수 없는 곳이야!', maze_fail_contact_brick: '에구구… 부딪혔다!', maze_fail_contact_iron1: '으앗! 장애물에 부딪혀버렸어', maze_fail_contact_iron2: '으앗! 장애물이 떨어져서 다쳐버렸어. 장애물이 내려오기전에 움직여줘..', maze_fail_fall_hole: '앗, 함정에 빠져 버렸어...', maze_fail_hit_unit: '몬스터에게 당해버렸어! 위험한 몬스터를 물리치기 위해 하트 날리기 블록을 사용해줘!', maze_fail_hit_unit2: '윽, 몬스터에게 공격당했다! 두 칸 떨어진 곳에서 공격해줘!', maze_fail_hit_unit_by_mushroom: "주황버섯에게 당해버렸어!
공격하기 블록을 사용해서 나쁜 몬스터를 혼내줘!", maze_fail_hit_unit_by_lupin: "루팡에게 당해버렸어!
공격하기 블록을 두 칸 떨어진 곳에서 사용해서 나쁜 몬스터를 혼내줘!", maze_fail_elnath_fail: '으앗! 나쁜 몬스터가 나를 공격했어.
나쁜 몬스터가 나에게 다가오지 못하게 혼내줘!', maze_fail_pepe: '', maze_fail_yeti: "그 몬스터는 너무 강해서 공격하기 블록으로는 혼내줄 수 없어
공격하기 블록을 사용해보자.", maze_fail_peti: "그 몬스터에게 공격하기 블록을 사용하면,
강한 몬스터인 가 나왔을 때 혼내줄 수 없어
공격하기 블록을 사용해보자.", maze_fail_both_side: '양 옆 공격하기는 양쪽에 몬스터가 있을 때에만 사용해야 돼!', maze_wrong_attack_obstacle: "이 곳에서는 공격하기 블록을 사용할 수 없어
주황 버섯에게는 공격하기 블록을 사용해보자.", maze_fail_contact_spider: '거미집에 걸려 움직일 수가 없어...', maze_success_perfect: '멋져! 완벽하게 성공했어~', maze_success_block_excess: '좋아! %1개의 블록을 사용해서 성공했어!
하지만, %2개의 블록만으로 성공하는 방법도 있어. 다시 도전해 보는 건 어때?', maze_success_not_essential: '좋아! %1개의 블록을 사용해서 성공했어!
하지만 이 블록을 사용하면 더 쉽게 해결할 수 있어. 다시 도전해 보는 건 어때?', maze_success_final_perfect_basic: '좋아! 샐리 공주가 어디 있는지 찾았어! 이제 샐리 공주를 구할 수 있을 거야!', maze_success_final_block_excess_basic: '좋아! 샐리 공주가 어디 있는지 찾았어! 이제 샐리 공주를 구할 수 있을 거야!%1개의 블록을 사용했는데, %2개의 블록만으로 성공하는 방법도 있어. 다시 해볼래?', maze_success_final_perfect_advanced: '샐리 공주가 있는 곳까지 도착했어! 이제 악당 메피스토를 물리치고 샐리를 구하면 돼!', maze_success_final_block_excess_advanced: '샐리 공주가 있는 곳까지 도착했어! 이제 악당 메피스토를 물리치고 샐리를 구하면 돼!%1개의 블록을 사용했는데, %2개의 블록만으로 성공하는 방법도 있어. 다시 해볼래?', maze_success_final_distance: '좋아! 드디어 우리가 샐리 공주를 무사히 구해냈어. 구할 수 있도록 도와줘서 정말 고마워!
%1칸 움직였는데 다시 한 번 다시해서 60칸까지 가볼래?', maze_success_final_perfect_ai: '좋았어! 드디어 우리가 샐리 공주를 무사히 구해냈어. 구할 수 있도록 도와줘서 정말 고마워!', maple_success_perfect: '좋아! 완벽하게 성공했어!!', maple_success_block_excess: '좋아! %1개의 블록을 사용해서 성공했어!
그런데 %2개의 블록으로도 성공하는 방법이 있어. 다시 도전해 보는건 어때?', maple_success_not_essential: '좋아! %1개의 블록을 사용해서 성공했어!
그런데 이 블록을 사용하면 더 쉽게 해결할 수 있어. 다시 도전해 보는 건 어때?', maple_success_final_perfect_henesys: '멋져! 헤네시스 모험을 훌륭하게 해냈어.', maple_success_final_perfect_excess_henesys: '멋져! 헤네시스 모험을 잘 해냈어.
그런데 %2개의 블록으로도 성공하는 방법이 있어. 다시 도전해 보는 건 어때?', maple_success_final_not_essential_henesys: '멋져! 헤네시스 모험을 잘 해냈어.
그런데 이 블록을 사용하면 더 쉽게 해결할 수 있어. 다시 도전해 보는 건 어때?', maple_success_final_perfect_ellinia: '우와! 이 곳에서 정말 재밌는 모험을 했어!
다음 모험도 같이 할거지? ', maple_success_final_perfect_excess_ellinia: '우와! 이 곳에서 정말 재밌는 모험을 했어!
그런데 %2개의 블록으로도 성공하는 방법이 있어. 다시 도전해 보는 건 어때?', maple_success_final_not_essential_ellinia: '우와! 이 곳에서 정말 재밌는 모험을 했어!
그런데 이 블록을 사용하면 더 쉽게 해결할 수 있어. 다시 도전해 보는 건 어때?', maple_fail_fall_hole: '으앗! 빠져버렸어!
뛰어넘기 블록을 사용해서 건너가보자.', maple_fail_ladder_fall_hole: '으앗! 빠져버렸어!
사다리 타기 블록을 사용해서 다른 길로 가보자.', maple_fail_more_move: '성공하려면 목적지까지 조금 더 움직여야 해!', maple_fail_not_found_ladder: '이런, 여기엔 탈 수 있는 사다리가 없어.
사다리 타기 블록은 사다리가 있는 곳에서만 사용 해야해.', maple_fail_not_found_meat: '이런, 여기엔 먹을 수 있는 음식이 없어!
음식 먹기 블록은 음식이 있는 곳에서만 사용 해야해.', maple_cert_input_title: '내가 받을 인증서에 적힐 이름은?', maze_distance1: '거리 1', maze_distance2: '거리 2', maze_distance3: '거리 3', ev3: 'EV3', roborobo_roduino: '로두이노', roborobo_schoolkit: '스쿨키트', smartboard: '과학상자 코딩보드', smartboardbt: '과학상자 코딩보드(무선)', codestar: '코드스타', cobl: '코블', cobl_bt: '코블 블루투스', block_coding: '블록코딩', python_coding: '엔트리파이선', dadublock: '다두블럭', dadublock_car: '다두블럭 자동차', blacksmith: '대장장이 보드', course_submit_homework: '과제 제출', course_done_study: '학습 완료', course_show_list: '목록', modi: '모디', chocopi: '초코파이보드', coconut: '코코넛', jdkit: '제이디키트', practical_course: '교과용 만들기', entry_user_policy: '엔트리 이용정책', entry_scholarship_title: '엔트리 학술 자료', entry_scholarship_content: '엔트리는 대학/학회 등과 함께 다양한 연구를 진행하여 전문성을 강화해나가고 있습니다. 엔트리에서 제공하는 연구용 자료를 확인해보세요', entry_scholarship_content_sub: '*엔트리에서 제공하는 데이터는 연구 및 분석에 활용될 수 있도록 온라인코딩파티에 참여한 사용자들이 미션을 해결하는 일련의 과정을 로그 형태로 저장한 데이터 입니다.', entry_scholarship_download: '자료 다운로드', codingparty_2016_title: '2016 온라인 코딩파티', codingparty_2016_content: '미션에 참여한 사용자들의 블록 조립 순서, 성공/실패 유무가 학년, 성별 정보와 함께 제공됩니다.', codingparty_2017_title: '2017 온라인 코딩파티', scholarship_go_mission: '미션 확인하기', scholarship_guide: '자료 활용 방법', scholarship_see_guide: '가이드 보기', scholarship_guide_desc: '연구용 자료를 읽고 활용할 수 있는 방법이 담긴 개발 가이드 입니다. ', scholarship_example: '자료 활용 예시', scholarship_example_desc: '연구용 자료를 활용하여 발표된 논문을 확인 할 수 있습니다.', scholarship_see_example: '논문 다운로드', altino: '알티노', private_project: '비공개 작품입니다.', learn_programming_entry_mission: '"엔트리봇"과 함께 미션 해결하기', learn_programming_line_mission: '"라인레인저스"와 샐리구하기', learn_programming_choseok: '"마음의 소리"의 조석과 게임 만들기', learn_programming_maple: '"핑크빈"과 함께 신나는 메이플 월드로!', learn_programming_level_novice: '기초', learn_programming_level_inter: '중급', learn_programming_level_advanced: '고급', line_look_for: '샐리를 찾아서', line_rangers_title_string: '학습하기 : 라인 레인저스', online_codingparty_certificate_string: '온라인 코딩파티', online_codingparty_line_title_string: '라인 레인저스', line_look_for_desc_1: '라인 레인저스의 힘을 모아 강력한 악당 메피스토를 물리치고 샐리를 구해주세요!', line_save: '샐리 구하기', line_save_desc_1: '메피스토 기지에 갇힌 샐리. 라인 레인저스가 장애물을 피해 샐리를 찾아갈 수 있도록 도와주세요!', line_escape: '샐리와 탈출하기', line_escape_desc_1: '폭파되고 있는 메피스토 기지에서 샐리와 라인 레인저스가 무사히 탈출할 수 있도록 도와주세요!', solve_choseok: '가위바위보 만들기', solve_choseok_desc_1: '만화 속 조석이 가위바위보 게임을 만들 수 있도록 도와주세요!', solve_henesys: '헤네시스', solve_ellinia: '엘리니아', solve_elnath: '엘나스', solve_henesys_desc_1: '마을을 모험하며, 배고픈 핑크빈이 음식을 배불리 먹을 수 있도록 도와주세요!', solve_ellinia_desc_1: '숲 속을 탐험하며, 나쁜 몬스터들을 혼내주고 친구 몬스터들을 구해주세요!', solve_elnath_desc_1: '나쁜 몬스터가 점령한 설산을 지나, 새로운 모험을 시작할 수 있는 또 다른 포털을 찾아 떠나보세요 !', save_modified_shape: '저장하지 않은 변경 사항이 있습니다.\n변경 사항을 저장할까요?', save_modified_table: '테이블에서 수정한 내용을 저장하시겠습니까?', attach_file: '첨부', enter_discuss_title: '제목을 입력해 주세요(40자 이하)', enter_discuss_title_alert: '제목을 입력해 주세요', discuss_upload_warn: '10MB이하의 파일을 올려주세요.', discuss_list: '목록보기', discuss_write_notice: '우리반 공지사항으로 지정하여 게시판 최상단에 노출합니다.', discuss_write_notice_open: '공지사항으로 지정하여 게시판 최상단에 노출합니다.', search_전체: '전체', search_게임: '게임', search_애니메이션: '애니메이션', search_미디어아트: '미디어 아트', search_피지컬: '피지컬', search_기타: '기타', discuss_write_textarea_placeholer: '엔트리 커뮤니티는 우리가 함께 만들어가는 공간입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_qna: '여기는 묻고답하기 게시판입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_tips: '여기는 노하우&팁 게시판입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_free: '여기는 엔트리 이야기 게시판입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_report: '여기는 제안 및 건의 게시판입니다.\n서로 배려하는 말로 즐거운 커뮤니티를 만들어요!\n\n 욕설이나 음란물과 같은 부적절한 내용의 글을 작성할 경우 이용정지 될 수 있습니다.', discuss_write_textarea_placeholer_contest2019: '※ 아래 양식으로 작성하여 제출해주세요.\n\n1. 학년 (예: 초등학교 5학년)\n\n2. 작품 URL (‘공유하기 > 작품 공유하기’에 작품을 공유한 다음, 작품 URL을 복사하여 적어주세요.)\n\n3. 작품 설명\n\n※ 공모전 수상자에게는 이메일이 발송될 예정입니다.\n엔트리의 ‘내 정보 수정‘에 이메일 정보를 꼭 입력해주세요!', maze_road: '길', account_deletion: '회원탈퇴', bug_report_too_many_request: '신고 내용이 전송 되고 있습니다. 잠시 후에 다시 시도해주시길 바랍니다.', pinkbean_index_title: '핑크빈과 함께 신나는 메이플 월드로!', pinkbean_index_content: '심심함을 참지 못한 핑크빈이 메이플 월드로 모험을 떠났습니다.
핑크빈과 함께 신나는 메이플 월드를 탐험하여 모험일지를 채워주세요.
각 단계를 통과하면서 자연스럽게 소프트웨어를 배워볼 수 있고, 미션을 마치면 인증서도 얻을 수 있습니다.', rangers_index_title: '라인 레인저스와 함께 샐리를 구하러 출동!', rangers_index_content: '악당 메피스토에게 납치된 샐리를 구하기 위해 라인 레인저스가 뭉쳤습니다.
소프트웨어의 원리를 통해 장애물을 극복하고, 샐리를 구출하는 영웅이 되어주세요.
각 단계를 통과하면서 자연스럽게 소프트웨어를 배워볼 수 있고, 미션을 마치면 인증서도
얻을 수 있습니다.', rangers_replay_button: '영상 다시보기', rangers_start_button: '미션 시작', lms_curriculum_intro: '학습시작', lms_curriculum_goal: '학습목표', lms_curriculum_prepare: '학습준비', lms_curriculum_study: '실습활동', lms_curriculum_summary: '학습정리', lms_curriculum_quiz: '확인문제', lms_curriculum_now_stage: '현재 단계', bug_report_title: '버그 리포트', bug_report_content: '이용 시 발생하는 오류나 버그 신고 및 엔트리를 위한 좋은 제안을 해주세요. 신고나 제안과 무관한 욕설 작성 시 이용이 정지될 수 있습니다.', object_import_syntax_error: '불러오려는 오브젝트에 엔트리파이선 문법과 맞지 않는 블록이 포함되어 있습니다. 블록코딩으로 전환한 뒤 오브젝트를 불러와주세요.', choseok_top_wrapper_panel_title: '조석과 함께 가위바위보 게임을 만들어보세요!', choseok_top_wrapper_panel_des: '마음의 소리 웹툰이 코딩파티 미션으로 탄생했습니다.
만화속 조석이 (가위바위보 게임)을 만들어가는 과정에 참여하여 미션에
도전해 보세요.
각 단계를 통과하면서 자연스럽게 소프트웨어를 배워볼 수 있고, 미션을 모두 마치면
인증서와 나만의 게임을 얻을 수 있습니다.
', choseok_mission_statement1: '조석을 움직여보자', choseok_mission_statement2: '가위바위보를 시작해보자', choseok_mission_statement3: '가위바위보 승부를 가려보자', choseok_mission_statement4: '가위바위보 게임을 완성해보자', choseok_mission_statement5: '자유롭게 만들어보자', choseok_mission_statement_top1: '미션 1 : 조석을 움직이기', choseok_mission_statement_top2: '미션 2 : 가위바위보를 시작하기', choseok_mission_statement_top3: '미션 3 : 가위바위보 승패 만들기', choseok_mission_statement_top4: '미션 4 : 가위바위보 결과 보여주기', choseok_mission_statement_top5: '미션 5 : 자유롭게 만들어보기', advisory_title: '엔트리 자문단', advisory_sub_title: '엔트리를 함께 만들어가는 선생님 학생 자문단입니다.', data_table_column: '속성', data_table_row: '행', data_table_provider: '출처', data_table_modifidate: '수정일', draw_new_table_ques_1: '데이터를 직접 입력하여 테이블로 저장할 수 있습니다.', draw_new_table_ques_2: '테이블 화면으로 이동하시겠습니까?', file_upload: '파일 올리기', no_marked_project1: '북마크한 작품이 없습니다.', no_marked_project2: '친구들의 작품을 북마크로 저장해 보세요!', temp_save_project_study: '임시 저장', file_upload_table_title: '테이블 새로 만들기', file_upload_table_sub_title: '데이터를 직접 입력해 나만의 테이블을 만들 수 있어요.', file_upload_warn_desc_table_1: '폭력적이고 잔인한 데이터, 선정적인 내용의 데이터, 불쾌감을 주거나 혐오단어가 포함된 데이터,', file_upload_warn_desc_table_2: '본인 또는 타인의 개인정보를 침해할 수 있는 내용의 데이터, 무단 사용이 금지된 저작권의 데이터 ', table_drag_upload_title: '파일을 끌어다 놓거나 클릭해서 업로드', table_drag_upload_desc: 'CSV, XLS(X) 파일을 여기에 끌어다 놓거나 클릭해서 업로드 할 수 있어요.', upload_select_file: '파일 선택', file_upload_add: '추가', file_upload_max_size_image: '5MB 이하만 업로드가 가능합니다.', lecture_quiz_popup_title: '확인 문제 정답 확인', realtime: '실시간', cloud: '공유', }; Lang.Msgs = { video_model_load_success: '로딩 완료', video_model_load_completed: '이제 사람/사물/얼굴 인식을 사용할 수 있습니다.', microbit_led_erase_all: '모두 지우기', loading_plz_wait: '로딩 중입니다. 잠시만 기다려주세요.', ai_utilize_video_loading: '비디오 감지 블록을 로딩 중입니다.
최대 1분까지 걸릴 수 있어요.', ai_utilize_audio_listening: '듣고 있어요', ai_utilize_audio_progress: '인식하고 있어요', ai_utilize_audio_description: '마이크를 이용하여 음성을 인식하는 블록들의 모음입니다.', upload_error_title: '파일 업로드 안내', upload_error_content: '엔트리 이용정책을 지키지 않는 것으로 의심되는 파일이 제외되었습니다.', monthly_intro_0: '<월간 엔트리>는 소프트웨어 교육에 익숙하지 않은 선생님들도 쉽고 재미있게 소프트웨어 교육을 하실 수 있도록 만들어진 ', monthly_intro_1: 'SW교육 잡지입니다. 재미있는 학습만화와 함께 하는 SW 교육 컨텐츠를 만나보세요!', monthly_title_0: '강아지 산책시키기 / 선대칭 도형 그리기', monthly_title_1: '동영상의 원리 / 음악플레이어 만들기', monthly_title_2: '대한민국 지도 퍼즐 / 벚꽃 애니메이션', monthly_title_3: '마우스 졸졸, 물고기 떼 / 태양계 행성', monthly_title_4: '감자 캐기 / 딸기 우유의 진하기', monthly_description_0: '키보드 입력에 따라 움직이는 강아지와 신호와 좌표를 통해 도형을 그리는 작품을 만들어 봅시다.', monthly_description_1: '변수를 활용하여 사진 영상 작품과 음악 플레이어 작품을 만들어 봅시다.', monthly_description_2: '~인 동안 반복하기를 이용한 퍼즐 게임과 복제본, 무작위 수를 이용한 애니메이션 작품을 만들어 봅시다.', monthly_description_3: '계속 반복하기 블록과 수학 연산 블록을 활용하여 물고기 미디어 아트 작품과 태양계를 만들어 봅시다.', monthly_description_4: '신호와 변수, 수학 연산 블록을 활용하여 감자 캐기 작품과 딸기 우유 만들기 작품을 만들어 봅시다.', save_canvas_alert: '저장 중입니다.', feedback_too_many_post: '신고하신 내용이 전송되고 있습니다. 10초 뒤에 다시 시도해주세요.', feedback_duplicated: '이미 신고하였습니다.', usable_object: '사용가능 오브젝트', shared_varaible: '공유 변수', invalid_url: '영상 주소를 다시 확인해 주세요.', auth_only: '인증된 사용자만 이용이 가능합니다.', runtime_error: '실행 오류', to_be_continue: '준비 중입니다.', warn: '경고', error_occured: "다시 한번 시도해 주세요. 만약 같은 문제가 다시 발생 하면 '제안 및 건의' 게시판에 문의 바랍니다. ", error_forbidden: '로그아웃 상태라 저장을 할 수 없습니다.\n만약 로그인했다면 다른 창에서 로그아웃 했는지 확인해 주세요.\n로그인 확인 후 저장이 안 된다면 ‘제안 및 건의’ 게시판에 문의 하세요.', list_can_not_space: '리스트의 이름은 빈 칸이 될 수 없습니다.', sign_can_not_space: '신호의 이름은 빈 칸이 될 수 없습니다.', variable_can_not_space: '변수의 이름은 빈 칸이 될 수 없습니다.', parameter_can_not_space: '값 블록은 빈 칸이 될 수 없습니다.', training_top_title: '연수 프로그램', training_top_desc: '엔트리 연수 지원 프로그램을 안내해 드립니다.', training_main_title01: '선생님을 위한 강사 연결 프로그램', training_target01: '교육 대상 l 선생님', training_sub_title01: '“우리 교실에 SW날개를 달자”', training_desc01: '소프트웨어(SW) 교원 연수가 필요한 학교인가요?\nSW 교원 연수가 필요한 학교에 SW교육 전문 선생님(고투티처) 또는 전문 강사를 연결해드립니다.', training_etc_ment01: '* 강의비 등 연수 비용은 학교에서 지원해주셔야합니다.', training_main_title02: '소프트웨어(SW) 선도학교로 찾아가는 교원연수', training_target02: '교육 대상 l SW 선도, 연구학교', training_sub_title02: '“찾아가, 나누고, 이어가다”', training_desc02: 'SW 교원 연수를 신청한 선도학교를 무작위로 추첨하여 상반기(4,5,6월)와\n하반기(9,10,11월)에 각 지역의 SW교육 전문 선생님(고투티처)께서 알차고\n재미있는 SW 기초 연수 진행 및 풍부한 교육사례를 공유하기 위해 찾아갑니다.', training_etc_ment02: '', training_main_title03: '학부모와 학생을 위한 연결 프로그램', training_target03: '교육 대상 l 학부모, 학생', training_sub_title03: '“SW를 더 가까이 만나는 시간”', training_desc03: '학부모와 학생들을 대상으로 소프트웨어(SW) 연수가 필요한 학교에 각 지역의 SW교육 전문 선생님(고투티처) 또는 전문 강사를 연결해드립니다.', training_etc_ment03: '* 강의비 등 연수 비용은 학교에서 지원해주셔야합니다.', training_apply: '신청하기', training_ready: '준비중입니다.', new_version_title: '최신 버전 설치 안내', new_version_text1: '하드웨어 연결 프로그램이', new_version_text2: '최신 버전이 아닙니다.', new_version_text3: '서비스를 한층 더 강화해 업데이트 된', new_version_text4: '최신 버전의 연결 프로그램을 설치해 주세요.', new_version_download: "최신 버전 다운로드", not_install_title: '미설치 안내', hw_download_text1: '하드웨어 연결을 위해서', hw_download_text2: '하드웨어 연결 프로그램을 설치해 주세요.', hw_download_text3: '하드웨어 연결 프로그램이 설치되어 있지 않습니다.', hw_download_text4: '최신 버전의 연결 프로그램을 설치해 주세요.', hw_download_btn: "연결 프로그램 다운로드", not_support_browser: '지원하지 않는 브라우저입니다.', quiz_complete1: '퀴즈 풀기 완료!', quiz_complete2: '총 {0}문제 중에 {1}문제를 맞췄습니다.', quiz_incorrect: '이런 다시 한 번 생각해보자', quiz_correct: '정답이야!', hw_connection_success: '하드웨어 연결 성공', hw_connection_success_desc: '하드웨어 아이콘을 더블클릭하면, 센서값만 확인할 수 있습니다.', hw_connection_success_desc2: '작품에서 하드웨어를 사용할 수 있습니다.', hw_connection_termination_title: '하드웨어 연결 해제', hw_connection_termination_desc: '하드웨어와 연결이 해제되었습니다.', hw_connection_failed_title: '하드웨어 연결 실패', hw_connection_failed_desc: '작품에서 사용된 하드웨어가\n연결되어 있는지 확인해 주세요.', hw_module_load_fail_title: '모듈 로드 실패', hw_module_load_fail_desc: '로드에 실패했습니다. 관리자에게 문의하세요.', ie_page_title: '이 브라우저는
지원하지 않습니다.', ie_page_desc: '엔트리는 인터넷 익스플로러 11 버전 이상 또는 크롬 브라우저에서 이용하실 수 있습니다.
윈도우 업데이트를 진행하시거나, 크롬 브라우저를 설치해주세요.
엔트리 오프라인 버전은 인터넷이 연결되어 있지 않아도 사용할 수 있습니다. 지금 다운받아서 시작해보세요!', ie_page_chrome_download: '크롬 브라우저
다운로드', ie_page_windows_update: '윈도우 최신버전
업데이트', ie_page_offline_32bit_download: '엔트리 오프라인 32bit
다운로드', ie_page_offline_64bit_download: '엔트리 오프라인 64bit
다운로드', ie_page_offline_mac_download: '엔트리 오프라인
다운로드', cancel_deletion_your_account: '$1님의
회원탈퇴 신청을 취소하시겠습니까?', account_deletion_canceled_complete: '회원탈퇴 신청이 취소되었습니다.', journal_henesys_no1_title: '헤네시스 첫번째 모험일지', journal_henesys_no2_title: '헤네시스 두번째 모험일지', journal_henesys_no1_content: '헤네시스에서 첫 번째 모험 일지야. 오늘 헤네시스 터줏대감이라는 대장장이 집에 가려고 점프를 하다가 떨어질 뻔했어. 그 아저씨는 집 마당 앞에 왜 그렇게 구멍을 크게 만들어 놓는 거지? 나같이 대단한 몬스터가 아니고서야 이런 구멍을 뛰어넘을 수 있는 애들은 없을 거 같은데! 여하튼 정보도 얻었으니 아저씨가 추천한 맛 집으로 가볼까?', journal_henesys_no2_content: '진짜 과식했다. 특히 그 식당의 고기는 정말 맛있었어. 어떻게 그렇게 부드럽게 만들었을까! 그렇지만 그 옆집 빵은 별로였어. 보니까 주방장 아저씨가 요리 수련을 한답시고 맨날 놀러 다니는 거 같더라고. 그럴 시간에 빵 하나라도 더 만들어 보는 게 나을 텐데. 후 이제 배도 채웠으니 본격적인 모험을 시작해볼까!', journal_ellinia_no1_title: '엘리니아 첫번째 모험일지', journal_ellinia_no2_title: '엘리니아 두번째 모험일지', journal_ellinia_no1_content: '휴, 모르고 주황버섯을 깔고 앉아버렸지 뭐야. 걔네가 화날만 하지.. 그래도 그렇게 나에게 다같이 몰려들어 공격할 건 뭐람! 정말 무서운 놈들이야. 슬라임들이 힘들어 할만했어. 하지만 이 핑크빈님께서 다 혼내주었으니깐 걱정 없어. 이제 슬라임들이 친구가 되어주었으니 더욱 신나게 멋진 숲으로 모험을 이어가볼까.', journal_ellinia_no2_content: '모험하면서 만난 친구 로얄패어리가 요즘 엘나스에 흉흉한 소문이 돈다고 했는데, 그게 뭘까? 오늘밤에 친구들이랑 집에서 놀기로 했는데 그때 물어봐야겠어. 완전 궁금한걸! 그런데 뭘 입고 가야하나.. 살이 너무쪄서 입을만 한게 없을거같은데.. 뭐 나는 늘 귀여우니까 어떤걸 입고가도 다들 좋아해줄거라구!', journal_elnath_no1_title: '엘나스 첫번째 모험일지', journal_elnath_no2_title: '엘나스 두번째 모험일지', journal_elnath_no1_content: '세상에! 이게 말로만 듣던 눈인가? 내가 사는 마을은 항상 봄이여서 눈은 처음 봤어. 몬스터들을 혼내주느라 제대로 구경을 못했는데 지금보니 온세상이 이렇게나 하얗고 차갑다니 놀라워! 푹신 푹신하고 반짝거리는게 맛있어 보였는데 맛은 특별히 없네. 그런데 왠지 달콤한 초코 시럽을 뿌려먹으면 맛있을 거 같아. 조금 들고가고 싶은데 방법이 없다니 너무 아쉬운걸.', journal_elnath_no2_content: '에퉤퉤, 실수로 석탄가루를 먹어버렸네. 나쁜 몬스터들! 도망가려면 조용히 도망갈 것이지 석탄을 잔뜩 뿌리면서 도망가버렸어. 덕분에 내 윤기나고 포송포송한 핑크색 피부가 갈수록 더러워지고 있잖아. 어서 여기를 나가서 깨끗하게 목욕부터 해야겠어. 아무리 모험이 좋다지만 이렇게 더럽게 돌아다니는 건 이 핑크빈님 자존심이 허락하지 않지.', bug_report_alert_msg: '소중한 의견 감사합니다.', version_update_msg1: '엔트리 오프라인 새 버전(%1)을\n사용하실 수 있습니다.', version_update_msg2: '엔트리 하드웨어 새 버전(%1)을\n사용하실 수 있습니다.', version_update_msg3: '지금 업데이트 하시겠습니까?', select_the_hardware: '수업에 활용할
하드웨어를 선택하세요.', select_hardware_button: '하드웨어 선택하기', select_the_expansion_block: '수업에 활용할 확장 블록을 선택하세요.', select_hardware_not_support_info: '오픈강의에는 하드웨어 블록을 사용할 수 없습니다.', select_hardware_not_support_info2: '조금만 기다려주세요.', select_expansion_block_button: '확장 블록 선택하기', expansion_weather_description: '기온, 강수량, 미세먼지 농도 등 한국의 날씨와 관련된 블록 모음입니다. [웨더아이 제공]', expansion_festival_description: '국내 지역별 다양한 행사 및 축제와 관련된 불록 모음 입니다. [한국관광공사 제공]', expansion_translate_description: '파파고를 이용하여 다른 언어로 번역할 수 있는 블록 모음입니다.', expansion_behaviorConductDisaster_description: '자연재난 발생 시 국민이 지켜야하는 기본적인 행동요령에 대한 블록들의 모음입니다. [국민안전처 제공]', expansion_behaviorConductLifeSafety_description: '생활 속 안전을 위해 국민이 지켜야 하는 행동요령에 대한 블록 모음입니다. [국민안전처 제공]', expansion_emergencyActionGuidelines_description: '자연∙사회재난 및 생활안전 사고 발생 시 국민이 지켜야 하는 행동요령에 대한 블록 모음입니다. [행정안전부 제공]', ai_utilize_tts_description: 'nVoice 음성합성 기술로 다양한 목소리로 문장을 읽는 블록모음 입니다. (한국어 엔진 지원)', hardware_need_update_title: '업데이트 안내', hardware_need_update_content: '보안 업데이트로 인해 하드웨어 연결 프로그램은\n1.9.73 버전 이상만 사용할 수 있습니다.\n더 낮은 버전이라면 최신 버전을 다운로드 받아 주세요.', ai_utilize_video_description: '카메라를 이용하여 사람(신체), 얼굴, 사물 등을 인식하는 블록들의 모음입니다. (IE 및 iOS 미지원)', lecture_header_restart_msg: '처음부터 다시 시작하시겠습니까?', ai_utilize_train_pop_error: '작품에 적용된 모델이 비활성화 또는 삭제되었습니다.', cannot_delete_function: '이미 사용 중인 함수입니다.\n결과값 설정을 바꾸려면 함수 블록이\n사용된 오브젝트가 없어야 합니다.', local_variable_deletion_warning: '사용 중인 지역변수가 있다면\n관련 블록이 삭제될 수 있습니다.\n정말로 변경할까요?', warning_function_aleady_being_edited: "새로운 함수를 추가하려면\n먼저 '저장' 또는 '취소'를 눌러\n기존의 함수 만들기 화면에서\n빠져나와야 합니다.", ai_utilize_pose_landmarker_description: '카메라를 이용하여 사람의 신체를 인식하는 블록들의 모음입니다.', ai_utilize_face_landmarker_description: '카메라를 이용하여 얼굴을 인식하는 블록들의 모음입니다.', ai_utilize_object_detector_description: '카메라를 이용하여 사물을 인식하는 블록들의 모음입니다.', ai_utilize_gesture_recognition_description: '카메라를 이용하여 손을 인식하는 블록들의 모음입니다.', sound_empty1: '[소리 추가하기]를 눌러 소리를 추가해 주세요.', sound_empty2: '소리를 추가하는 방법', sound_empty3: "'소리 선택' 탭에서 엔트리가 제공하는 기본 소리를 선택합니다.", sound_empty4: "'파일 올리기' 탭에서 MP3 파일을 직접 업로드합니다.", sound_empty5: "추가한 소리는 '다듬기'에서 필요한 부분만 자르거나, '조정하기'에서 크기와 빠르기 등을 조정할 수 있습니다.", sound_loading: '소리를 불러오고 있어요', }; Lang.Users = { auth_failed: '인증에 실패하였습니다', birth_year: '태어난 해', birth_year_before_1990: '1990년 이전', edit_personal: '회원 정보 수정', email: '이메일', email_desc: '새 소식이나 정보를 받을 수 있 이메일 주소', email_inuse: '이미 등록된 메일주소 입니다', email_match: '이메일 주소를 올바르게 입력해 주세요', forgot_password: '암호를 잊으셨습니까?', job: '직업', language: '언어', name: '이름', name_desc: '사이트내에서 표현될 이름 또는 별명', name_not_empty: '이름을 반드시 입력하세요', password: '암호', password_desc: '최소 4자이상 영문자와 숫자, 특수문자', password_invalid: '암호가 틀렸습니다', password_long: '암호는 4~20자 사이의 영문자와 숫자, 특수문자로 입력해 주세요', password_required: '암호는 필수입력 항목입니다', project_list: '작품 조회', my_page: '마이 페이지', regist: '가입 완료', rememberme: '자동 로그인', repeat_password: '암호 확인', repeat_password_desc: '암호를 한번더 입력해 주세요', repeat_password_not_match: '암호가 일치하지 않습니다', sex: '성별', signup_required_for_save: '저장을 하려면 로그인이 필요합니다.', username: '아이디', username_desc: '로그인시 사용할 아이디', username_inuse: '이미 사용중인 아이디 입니다', username_long: '아이디는 4~20자 사이의 영문자로 입력해 주세요', username_unknown: '존재하지 않는 사용자 입니다', already_verified: '이미 인증된 메일 주소입니다.', email_address_unavailable: '유효하지 않은 인증 메일입니다.', email_address_invalid_for_idpw: '유효하지 않은 인증 메일입니다.\n [아이디와 비밀번호 찾기] 메일 발송하기를\n 다시 시도해 주세요.', email_address_invalid_for_certification: '유효하지 않은 인증 메일입니다.\n [인증 메일 발송하기]를 다시 시도해 주세요.', verification_complete: '이메일 주소가 인증되었습니다.', reset_password_mail_sent: '비밀번호 재설정 메일이 발송되었습니다. 메일을 확인해주세요.', email_not_verified: '인증되지 않은 이메일 주소입니다. 인증 메일을 발송하여, 먼저 이메일 주소를 인증해주세요.', verification_email_send_complete: '인증 메일이 발송되었습니다. 먼저 메일 주소를 인증해주세요.', email_send_failed: '전송에 실패했습니다. 다시 한번 시도해주세요.', email_not_exist: '등록되지 않은 이메일 주소입니다.', not_valid_email: '올바른 형식의 이메일 주소를 입력해주세요.', }; Lang.Workspace = { picture_rotation: '회전', picture_size: '크기', thickness: '굵기', follow: '따라해보기', SaveWithPicture: '저장되지 않은 그림이 있습니다. 저장하시겠습니까?', RecursiveCallWarningTitle: '함수 호출 제한', RecursiveCallWarningContent: '함수를 한 번에 너무 많이 호출합니다. 함수의 호출 횟수를 줄여 주세요.', SelectShape: '이동', SelectCut: '자르기', Pencil: '펜', Line: '직선', Rectangle: '사각형', Ellipse: '원', Text: '글상자', Fill: '채우기', Eraser: '지우기', Magnifier: '확대/축소', block_helper: '블록 도움말', new_project: '새 프로젝트', add_object: '오브젝트 추가하기', download_image_name: '엔트리 블록', all: '전체', animal: '동물', arduino_entry: '아두이노 연결 프로그램', arduino_program: '아두이노 프로그램', arduino_sample: '엔트리 연결블록', arduino_driver: '아두이노 드라이버', cannot_add_object: '실행중에는 오브젝트를 추가할 수 없습니다.', cannot_add_picture: '실행중에는 모양을 추가할 수 없습니다.', cannot_add_sound: '실행중에는 소리를 추가할 수 없습니다.', cannot_add_expansion_block: '실행중에는 확장 블럭을 추가할 수 없습니다.', add_object_before_edit: '모양 편집을 위해\n오브젝트를 추가해주세요.', add_table_before_edit: '테이블을 추가해주세요.', cannot_edit_click_to_stop: '실행 중에는 수정할 수 없습니다.\n클릭하여 정지하기.', cannot_open_private_project: "비공개 작품은 코드를 볼 수 없습니다. '확인'을 누르면 이전 화면으로 이동합니다.", cannot_save_running_project: '실행 중에는 저장할 수 없습니다.', character_gen: '캐릭터 만들기', check_runtime_error: '빨간색으로 표시된 블록을 확인해 주세요.', check_browser_error: '현재 브라우저에서 지원하지 않는 동작입니다.', check_browser_error_video: '현재 브라우저(IE) 또는 운영체제(iOS)에서 지원하지 않는 블록입니다.', check_microphone_error: '마이크가 연결되어 있는지 확인해주세요', check_webcam_error: '컴퓨터에 카메라가 연결되어있지 않습니다', context_download: 'PC에 저장', context_duplicate: '복제하기', context_remove: '삭제하기', context_rename: '이름 수정', coordinate: '좌표', create_function: '함수 만들기', direction: '이동 방향', drawing: '직접 그리기', enter_list_name: '새로운 리스트의 이름을 입력하세요(10글자 이하)', enter_name: '새로운 이름을 입력하세요', enter_new_message: '새로운 신호의 이름을 입력하세요.', enter_variable_name: '새로운 변수의 이름을 입력하세요(10글자 이하)', family: '엔트리봇 가족', fantasy: '판타지/기타', file_new: '새로 만들기', file_open: '온라인 작품 불러오기', file_upload: '오프라인 작품 불러오기', file_upload_login_check_msg: '오프라인 작품을 불러오기 위해서는 로그인을 해야 합니다.', file_save: '저장하기', file_save_as: '복사본으로 저장하기', file_save_download: '내 컴퓨터에 저장하기', func: '함수', function_create: '함수 만들기', function_add: '함수 추가하기', interface: '인터페이스', landscape: '배경', list: '리스트', list_add_calcel: '리스트 추가 취소', list_add_calcel_msg: '리스트 추가를 취소하였습니다.', list_add_fail: '리스트 추가 실패', list_add_fail_msg1: '같은 이름의 리스트가 이미 존재합니다.', list_add_fail_msg2: '리스트의 이름이 적절하지 않습니다.', list_add_ok: '리스트 추가 완료', list_add_ok_msg: '을(를) 추가하였습니다.', list_create: '리스트 추가하기', list_create_placeholder: '리스트의 이름을 입력해주세요.', list_dup: '같은 이름의 리스트가 이미 있어 이름이 자동으로 변경되었습니다.', list_newname: '새로운 이름', list_export: '리스트 내보내기', list_import: '리스트 불러오기', list_remove: '리스트 삭제', list_rename: '리스트 이름 변경 완료', list_rename_failed: '리스트 이름 변경 실패', list_rename_ok: '리스트의 이름이 성공적으로 변경되었습니다.', list_too_long: '리스트의 이름은 10자를 넘을 수 없습니다.', message: '신호', message_add_cancel: '신호 추가 취소', message_add_cancel_msg: '신호 추가를 취소하였습니다.', message_add_fail: '신호 추가 실패', message_add_fail_msg: '같은 이름의 신호가 이미 존재합니다.', message_add_ok: '신호 추가 완료', message_add_ok_msg: '을(를) 추가하였습니다.', message_create: '신호 만들기', message_add: '신호 추가하기', message_create_placeholder: '신호의 이름을 입력해주세요.', message_dup: '같은 이름의 신호가 이미 존재합니다.', message_remove: '신호 삭제', message_remove_canceled: '신호 삭제를 취소하였습니다.', message_rename: '신호 이름을 변경하였습니다.', message_rename_failed: '신호 이름 변경 실패', message_rename_ok: '신호의 이름이 성공적으로 변경 되었습니다.', message_too_long: '신호의 이름을 10자 이내로 작성해 주세요.', message_too_long_to_change: '신호의 이름을 10자 이내로 변경해 주세요.', no_message_to_remove: '삭제할 신호가 없습니다', no_use: '아직 오브젝트에 조립되지 않았어요.', no_variable_to_remove: '삭제할 변수가 없습니다.', no_variable_to_rename: '변경할 변수가 없습니다.', object_not_found: '블록에서 지정한 오브젝트가 존재하지 않습니다.', object_not_found_for_paste: '붙여넣기 할 오브젝트가 없습니다.', people: '일반 사람들', picture_add: '모양 추가하기', table_add: '테이블 추가하기', draw_new_table: '새로 만들기', plant: '식물', project: '작품', project_copied: '의 사본', PROJECTDEFAULTNAME: ['멋진', '재밌는', '착한', '큰', '대단한', '잘생긴', '행운의'], remove_object: '오브젝트 삭제', remove_object_msg: '(이)가 삭제되었습니다.', removed_msg: '(이)가 성공적으로 삭제 되었습니다.', rotate_method: '회전방식', rotation: '방향', run: '시작하기', saved: '저장완료', saved_msg: '(이)가 저장되었습니다.', save_failed: '저장시 문제가 발생하였습니다. 다시 시도해 주세요.', select_library: '오브젝트 선택', select_sprite: '적용할 스프라이트를 하나 이상 선택하세요.', shape_remove_fail: '모양 삭제 실패', shape_remove_fail_msg: '적어도 하나 이상의 모양이 존재하여야 합니다.', shape_remove_ok: '모양이 삭제 되었습니다. ', shape_remove_ok_msg: '이(가) 삭제 되었습니다.', load_expansion_block: '확장 블록 불러오기', load_ai_utilize_block: '인공지능 블록 불러오기', load_hardware_lite_block: '연결할 하드웨어 선택하기', load_ai_utilize_train_block: '인공지능 모델 학습하기', select_expansion_block: '확장블록 선택', deselect_expansion_block_warning: '확장 블록이 작품에 조립되어 있어 불러오기를 해제할 수 없습니다.', deselect_ai_utilize_block_warning: '인공지능 블록이 작품에 조립되어 있어 불러오기를 해제할 수 없습니다.', confirm_firmware_hwlite_block_msg: '%1 을(를)\n 엔트리에서 사용하려면\n 먼저 펌웨어를 설치해야 합니다.', confirm_firmware_hwlite_block_title: '펌웨어 설치 필요', confirm_firmware_hwlite_block_download: '펌웨어 다운로드', confirm_firmware_hwlite_block_usb_connect: 'USB 연결', confirm_firmware_hwlite_block_pass: '이미 설치함', progress_firmware_hwlite_title: '펌웨어 설치', progress_firmware_hwlite_step1_title: 'USB 연결 확인', progress_firmware_hwlite_step1_content1: 'USB로 기기와 PC를 연결하고 아래 버튼을 눌러 주세요.', progress_firmware_hwlite_step1_content2: '브라우저에서 연결할 기기를 선택해 주세요.\nUSB 통신을 기다리고 있어요.', progress_firmware_hwlite_step1_content3: 'USB와 통신을 확인했습니다.', progress_firmware_hwlite_step2_title: '펌웨어 설치', progress_firmware_hwlite_step2_content1: '펌웨어를 설치하고 있습니다.\n잠시만 기다려 주세요.', progress_firmware_hwlite_step2_content_complete: '펌웨어 설치가 완료되었습니다.', usbconnect_fail_alert: "기기 연결에 실패했습니다. 연결 상태를 확인하고 '다시 선택'을 눌러 주세요.", progress_firmware_hwlite_step2_content_fail: '펌웨어 설치에 실패했습니다.', progress_firmware_hwlite_step2_content_select: '설치할 펌웨어 버전을 선택해 주세요', select_hwlite_block_duplicated: '1개의 하드웨어만 선택해 주세요.', select_hwlite_block_none: '연결할 하드웨어를 선택해 주세요.', select_firmware_hwlite_title: '펌웨어 다운로드', select_firmware_hwlite_content: '버전에 맞는 펌웨어를 다운로드 받아\n하드웨어에 설치해 주세요.', sound_add: '소리 추가하기', sound_remove_fail: '소리 삭제 실패', sound_remove_ok: '소리 삭제 완료', sound_remove_ok_msg: '이(가) 삭제 되었습니다.', stop: '정지하기', pause: '일시정지', restart: '다시시작', speed: '속도 조절', tab_attribute: '속성', tab_table: '테이블', tab_code: '블록', tab_picture: '모양', tab_sound: '소리', tab_text: '글상자', textbox: '글상자', textbox_edit: '글상자 편집', textbox_input: '글상자의 내용을 입력해주세요.', things: '물건', textcoding_tooltip1: '블록코딩과 엔트리파이선을
선택하여 자유롭게
코딩을 해볼 수 있습니다.', textcoding_tooltip2: '실제 개발 환경과 동일하게
엔트리파이선 모드의 실행 결과를
확인할 수 있습니다.', textcoding_tooltip3: '엔트리파이선에 대한
기본사항이 안내되어 있습니다.
<엔트리파이선 이용안내>를 확인해 주세요!', upload: '파일 올리기', upload_addfile: '파일 올리기', variable: '변수', variable_add_calcel: '변수 추가 취소', variable_add_calcel_msg: '변수 추가를 취소하였습니다.', variable_add_fail: '변수 추가 실패', variable_add_fail_msg1: '같은 이름의 변수가 이미 존재합니다.', variable_add_fail_msg2: '변수의 이름이 적절하지 않습니다.', variable_add_ok: '변수 추가 완료', variable_add_ok_msg: '을(를) 추가하였습니다.', variable_create: '변수 만들기', variable_add: '변수 추가하기', variable_dup: '같은 이름의 변수가 이미 있어 이름이 자동으로 변경되었습니다.', variable_newname: '새로운 이름', variable_remove: '변수 삭제', variable_remove_canceled: '변수 삭제를 취소하였습니다.', variable_rename: '변수 이름 변경 완료', variable_rename_failed: '변수 이름 변경 실패', variable_rename_msg: "'변수의 이름이 성공적으로 변경 되었습니다.'", variable_rename_ok: '변수의 이름이 성공적으로 변경되었습니다.', variable_select: '변수를 선택하세요', variable_too_long: '변수의 이름은 10자를 넘을 수 없습니다.', open_analizy_data_import: '테이블 불러오기', vehicle: '탈것', add_object_alert_msg: '오브젝트가 하나도 없습니다. 오브젝트를 추가하고 시도해 주세요.', add_object_alert: '경고', create_variable_block: '변수 만들기', create_list_block: '리스트 만들기', Variable_Timer: '초시계', Variable_placeholder_name: '변수 이름', Message_placeholder_name: '신호 이름', Variable_property: '변수 속성', Variable_placeholder_content: '변수의 이름을 입력해주세요.', Variable_use_all_objects: '모든 오브젝트에서 사용', Variable_use_this_object: '이 오브젝트에서 사용', Variable_used_at_all_objects: '모든 오브젝트에서 사용되는 변수', variable_create_normal: '일반 변수로 사용\n(작품에 저장)', variable_create_cloud: '공유 변수로 사용\n(서버에 저장)', variable_create_real_time: '실시간 변수로 사용\n(서버에 저장)', Variable_used_at_special_object: '특정 오브젝트에서만 사용되는 변수', Variable_used_objects: '사용된 오브젝트', draw_new: '새로 그리기', draw_new_ebs: '직접 그리기', painter_file: '파일 ▼', painter_file_save: '저장하기', painter_file_saveas: '새 모양으로 저장하기', new_picture: '새그림', painter_edit: '편집 ▼', get_file: '가져오기', copy_file: '복사하기', cut_picture: '자르기', paste_picture: '붙이기', remove_all: '모두 지우기', flip_horizontal: '좌우뒤집기', flip_vertical: '상하뒤집기', regular: '보통', bold: '굵게', font_underline: '밑줄', font_textblock_strikethrough: '가로줄', font_textblock_underline: '밑줄', font_textblock_italic: '이탤릭', font_textblock_bold: '볼드', font_tilt: '기울임', font_cancel: '취소선', font_color: '글꼴 색상', font_fill: '채우기 색상', font_family: '글꼴', align_left: '왼쪽 정렬', align_center: '가운데 정렬', align_right: '오른쪽 정렬', italic: '기울임', textStyle: '글자', add_picture: '모양 추가', select_picture: '모양 선택', select_table: '테이블 선택', load_web: '웹에서 가져오기', select_sound: '소리 선택', Size: '크기', show_variable: '변수 노출', default_value: '기본값 ', slide: '슬라이드', min_value: '최솟값', max_value: '최댓값', number_of_list: '리스트 항목 수', empty_of_list: '추가된 항목이 없습니다', use_all_objects: '모든 오브젝트에 사용', list_name: '리스트 이름', list_property: '리스트 속성', list_used_specific_objects: '특정 오브젝트에서만 사용되는 리스트', List_used_all_objects: '모든 오브젝트에서 사용되는 리스트', List_used_objects: '사용된 오브젝트', Scene_delete_error: '장면은 최소 하나 이상 존재해야 합니다.', Scene_add_error: '장면은 최대 20개까지 추가 가능합니다.', replica_of_object: '의 복제본', will_you_delete_scene: '장면은 한번 삭제하면 취소가 불가능 합니다. \n정말 삭제 하시겠습니까?', will_you_delete_function: '함수는 한번 삭제하면 취소가 불가능 합니다.\n정말 삭제 하시겠습니까?', duplicate_scene: '복제하기', block_explain: '블록 설명 ', block_intro: '블록을 클릭하면 블록에 대한 설명이 나타납니다.', blocks_reference: '블록 설명', hardware_guide: '하드웨어 연결 안내', robot_guide: '로봇 연결 안내', python_guide: '엔트리파이선 이용 안내', show_list_workspace: '리스트 노출', list_create_normal: '일반 리스트로 사용\n(작품에 저장)', list_create_cloud: '공유 리스트로 사용 \n(서버에 저장)', list_create_real_time: '실시간 리스트로 사용\n(서버에 저장)', confirm_quit: '바꾼 내용을 저장하지 않았습니다.', confirm_load_temporary: '저장하지 않고 종료한 작품이 있습니다.\n저장하지 않은 작품을 먼저 열까요?', confirm_lesson_recovery_header: '강의 복구', confirm_lesson_recovery: '저장되지 않은 강의가 있습니다. 여시겠습니까?', login_to_save: '로그인후에 저장 바랍니다.', cannot_save_in_edit_func: '함수 편집중에는 저장할 수 없습니다.', new_object: '새 오브젝트', arduino_connect: '하드웨어 연결', arduino_connect_success: '하드웨어가 연결되었습니다.', confirm_load_header: '작품 복구', uploading_msg: '업로드 중입니다', file_size_exceeded: '
변수 또는 리스트의 값이 너무 많아
작품을 불러올 수 없어요.', upload_fail_msg: '업로드에 실패하였습니다. \n 다시 한번 시도해주세요.', upload_not_supported_msg: '지원하지 않는 형식입니다.', upload_not_supported_file_msg: '업로드 할 수 없는 파일 형식입니다.', file_converting_msg: '파일 변환 중입니다.', file_converting_fail_msg: '파일 변환에 실패하였습니다.', fail_contact_msg: '문제가 계속된다면
entry@connect.or.kr 로 문의해주세요.', saving_msg: '저장 중입니다', saving_fail_msg: '저장에 실패하였습니다.
다시 한번 시도해주세요.', loading_msg: '불러오는 중입니다', loading_fail_msg: '불러오기에 실패하였습니다.
다시 한번 시도해주세요.', restore_project_msg: '정상적으로 저장되지 않은 작품이 있습니다. 해당 작품을 복구하시겠습니까?', quit_stop_msg: '저장 중에는 종료하실 수 없습니다.', ent_drag_and_drop: '업로드 하려면 파일을 놓으세요', not_supported_file_msg: '지원하지 않은 형식의 파일입니다.', broken_file_msg: '파일이 깨졌거나 잘못된 파일을 불러왔습니다.', check_audio_msg: 'mp3 외 오디오 파일은 재생할 수 없습니다.', check_entry_file_msg: 'ENT 파일만 불러오기가 가능합니다.', hardware_version_alert_text: '5월 30일 부터 구버전의 연결프로그램의 사용이 중단 됩니다.\n하드웨어 연결 프로그램을 최신 버전으로 업데이트 해주시기 바랍니다.', variable_name_auto_edited_title: '변수 이름 자동 변경', variable_name_auto_edited_content: '변수의 이름은 10글자를 넘을 수 없습니다.', list_name_auto_edited_title: '리스트 이름 자동 변경', list_name_auto_edited_content: '리스트의 이름은 10글자를 넘을 수 없습니다.', list_cant_add_item: '경고', list_max_length_exceeded: '리스트 항목은 최대 5,000개까지 추가할 수 있어요.', list_truncated_on_load: '이 작품의 리스트 항목 수가 5,000개를 초과하여 일부가 표시되지 않을 수 있습니다.\n\n안정적인 이용을 위해\n리스트를 5,000개 이하로 줄여주세요.', list_truncated_on_load_title: '알림', cloned_scene: '복제본_', default_mode: '기본형', practical_course_mode: '교과형', practical_course: '실과', select_mode: '모드선택', select_mode_popup_title: '엔트리 만들기 환경을 선택해 주세요.', select_mode_popup_lable1: '기본형', select_mode_popup_lable2: '교과형', select_mode_popup_desc1: '엔트리의 모든 기능을 이용하여
자유롭게 작품을 만듭니다.', select_mode_popup_desc2: '실과 교과서에 등장하는 기능만을
이용하여 작품을 만듭니다.', practical_course_notice: '안내', practical_course_desc: "교과용 만들기
실과 교과서로 소프트웨어를 배울 때
필요한 기능만을 제공합니다.", practical_course_desc2: '*기본형 작품 만들기를 이용하면 더 많은 기능을
이용해 작품을 만들 수 있습니다.', practical_course_tooltip: '모든 기능을 이용하기 위해서는
기본형을 선택해 주세요.', name_already_exists: '이름이 중복 되었습니다.', enter_the_name: '이름을 입력하여 주세요.', object_not_exist_error: '오브젝트가 하나도 없습니다. 오브젝트를 추가하고 시도해 주세요.', project_length_error: '작품/강의명은 띄어쓰기 포함 45자까지 입력할 수 있습니다.', workspace_tutorial_popup_desc: "작품 만들기
창의적인 작품을 만들 수 있도록
다양한 블록과 기능을 제공합니다.", start_guide_tutorial: '만들기 이용 안내', language: '언어 선택', file: '파일', save: '저장하기', help: '도움말', print: '인쇄', undo: '입력 취소', redo: '다시 실행', workspace_title_tooltip: '기본작품명이 변경되었습니다.\n작품을 만든 날짜를 통해 어떤 작품인지 쉽게 알 수 있습니다.', workspace_object_tooltip: '오브젝트의 순서는 오브젝트의 대표 이미지를 잡고\n위아래로 이동하여 변경할 수 있습니다.\n(모양과 소리탭에서도 동일하게 동작합니다.)', workspace_comment_tooltip: '조립소에 추가한 메모를\n한꺼번에 숨기거나 보이게 할 수 있습니다.', workspace_zoom_tooltip: '조립소에 추가된 블록의 크기를 바꿀 수 있습니다.\n가운데 = 아이콘을 누르면 기본 크기로 돌아옵니다.', workspace_image_tooltip: '새로워진\n작품 만들기를\n소개합니다.', playground_block_drop: '나의 보관함의 블록을\n조립소에 추가합니다.', container_object_drop: '나의 보관함의 오브젝트를\n오브젝트 리스트에 추가합니다.', my_storage_block_drop: '블록을\n나의 보관함에\n추가합니다.', my_storage_object_drop: '오브젝트를\n나의 보관함에\n추가합니다.', my_storage: '나의 보관함', my_block: '나의 블록', red: '빨강(R)', green: '녹색(G)', blue: '파랑(B)', hue: '색상', saturation: '채도', brightness: '명도', spoid: '스포이드', palette_mode: '팔레트 모드', slider_mode: '슬라이더 모드', toast_error_title_object_center: '주의', toast_error_contents_object_center: '오브젝트 중심점이 오브젝트와 멀리 떨어져 실행화면 밖으로 벗어날 경우, 원위치로 돌아옵니다.', blocks_comming_soon: '열심히 연구 중입니다.\n조금만 기다려 주세요!', data_table: '테이블', select_all: '모두', now_loading_msg: '로딩 중입니다.\n잠시만 기다려주세요.', play_my_project: '만든 작품을 실행해봅시다.', goal_project: '목표작품 살펴보기', look_target_project: '작품을 실행하며 무엇을 만들지 살펴봅시다.', ai_learning_login_required: '모델 학습 기능을 사용하시려면 \n로그인이 필요합니다.', drag_to_remove: '여기로 옮겨 버리기', check_result_value: '결괏값을 가짐', check_local_variable: '지역변수를 사용', local_variable: '지역변수', local_variable_dup: '같은 이름의 지역변수가 이미 있어 이름이 자동으로 변경되었습니다.', local_variable_rename: '지역변수 이름 변경 완료', local_variable_rename_failed: '지역변수 이름 변경 실패', local_variable_rename_ok: '지역변수의 이름이 성공적으로 변경되었습니다.', use_block_objects1: '사용된 오브젝트 (블록 {0}개)', use_block_objects2: '사용된 오브젝트', use_block_function: '함수에 조립되어 있어요.', use_block_project: '블록 {0} 개', use_blocks_project: '블록 {0} 개', pose_landmarker_title_text: '사람 인식', face_landmarker_title_text: '얼굴 인식', object_detector_title_text: '사물 인식', gesture_recognition_title_text: '손 인식', sound_start_point: '시작 지점', sound_end_point: '끝 지점', sound_selection: '남길 영역', sound_volume: '크기', sound_speed: '빠르기', sound_pitch: '음높이', function_attribute: '함수 속성 보기', variable_default_value: '변수 기본값', list_default_value: '리스트 기본값', func_property: '함수 속성', bring_forward: '위로 옮기기', send_backward: '아래로 옮기기', upload_error_msg: "이용 정책을 위반하는 이미지로 의심되어\n업로드 할 수 없습니다.\n문제가 없다고 생각하시는 경우\n'문의하기'를 통해 이미지를 전달해 주세요.", upload_error_msg_contain_image: '이용 정책을 위반하는 것으로 의심되는\n이미지가 포함되어 업로드 할 수 없습니다.', upload_error_msg_exclude_image: '위 이미지를 제외하고 다시 시도해 주세요.', select_flash_firmware_hwlite_title: '설치할 펌웨어 선택', select_flash_firmware_hwlite_content: '연결하려는 마이크로비트의\n 버전을 선택해 주세요.\n 펌웨어 설치가 완료되면 메시지가 표시됩니다.', flash_firmware_success: '펌웨어 설치가 완료되었습니다.', flash_firmware_failed: '펌웨어 설치에 실패했습니다. 다시 시도해 주세요.', }; Lang.code = '코드보기'; Lang.EntryStatic = { event100: '이벤트', groupProject: '학급 공유하기', usage_parallel: '병렬', usage_expansion: '확장', usage_hw: '하드웨어', usage_sequence: '순차', privateProject: '나만보기', privateCurriculum: '나만보기', publicCurriculum: '강의 모음 공유하기', publicProject: '작품 공유하기', group: '학급 공유하기', groupCurriculum: '학급 공유하기', private: '나만보기', public: '강의 공유하기', lecture_is_open_true: '공개', lecture_is_open_false: '비공개', category_all: '모든 작품', category_game: '게임', category_animation: '애니메이션', category_media_art: '미디어 아트', category_physical: '피지컬', category_etc: '기타', category_category_game: '게임', category_category_animation: '애니메이션', category_category_media_art: '미디어 아트', category_category_physical: '피지컬', category_category_etc: '기타', sort_created: '최신순', sort_updated: '최신순', sort_visit: '조회순', sort_likeCnt: '좋아요순', sort_comment: '댓글순', period_all: '전체기간', period_1: '오늘', period_7: '최근 1주일', period_30: '최근 1개월', period_90: '최근 3개월', lecture_required_time_1: ' ~ 15분', lecture_required_time_2: '15분 ~ 30분', lecture_required_time_3: '30분 ~ 45분', lecture_required_time_4: '45 분 ~ 60분', lecture_required_time_5: '1시간 이상', usage_event: '이벤트', usage_signal: '신호보내기', usage_scene: '장면', usage_repeat: '반복', usage_condition_repeat: '조건반복', usage_condition: '선택', usage_clone: '복제본', usage_rotation: '회전', usage_coordinate: '좌표이동', usage_arrow_move: '화살표이동', usage_shape: '모양', usage_speak: '말하기', usage_picture_effect: '그림효과', usage_textBox: '글상자', usage_draw: '그리기', usage_sound: '소리', usage_confirm: '판단', usage_comp_operation: '비교연산', usage_logical_operation: '논리연산', usage_math_operation: '수리연산', usage_random: '무작위수', usage_timer: '초시계', usage_variable: '변수', usage_list: '리스트', usage_ask_answer: '입출력', usage_function: '함수', usage_arduino: '아두이노', concept_resource_analytics: '자료수집/분석/표현', concept_procedual: '알고리즘과 절차', concept_abstractive: '추상화', concept_individual: '문제분해', concept_automation: '자동화', concept_simulation: '시뮬레이션', concept_parallel: '병렬화', subject_korean: '국어', subject_english: '영어', subject_mathmatics: '수학', subject_social: '사회', subject_science: '과학', subject_music: '음악', subject_paint: '미술', subject_athletic: '체육', subject_courtesy: '도덕', subject_progmatic: '실과', lecture_grade_1: '초1', lecture_grade_2: '초2', lecture_grade_3: '초3', lecture_grade_4: '초4', lecture_grade_5: '초5', lecture_grade_6: '초6', lecture_grade_7: '중1', lecture_grade_8: '중2', lecture_grade_9: '중3', lecture_grade_10: '일반', lecture_level_1: '쉬움', lecture_level_2: '중간', lecture_level_3: '어려움', listEnable: '리스트', functionEnable: '함수', messageEnable: '신호', objectEditable: '오브젝트', pictureeditable: '모양', sceneEditable: '장면', soundeditable: '소리', variableEnable: '변수', e_1: '초등 1학년', e_2: '초등 2학년', e_3: '초등 3학년', e_4: '초등 4학년', e_5: '초등 5학년', e_6: '초등 6학년', m_1: '중등 1학년', m_2: '중등 2학년', m_3: '중등 3학년', general: '일반', curriculum_is_open_true: '공개', curriculum_open_false: '비공개', contest2019: '공모전', exhibit: '공모전', notice: '공지사항', qna: '묻고답하기', tips: '노하우&팁', free: '엔트리 이야기', report: '제안 및 건의', art_category_all: '모든 작품', art_category_game: '게임', art_category_animation: '애니메이션', art_category_physical: '피지컬', art_category_etc: '기타', art_category_media: '미디어 아트', art_sort_updated: '최신순', art_sort_visit: '조회순', art_sort_likeCnt: '좋아요순', art_sort_comment: '댓글순', art_period_all: '전체기간', art_period_day: '오늘', art_period_week: '최근 1주일', art_period_month: '최근 1개월', art_period_three_month: '최근 3개월', level_high: '상', level_mid: '중', level_row: '하', discuss_sort_created: '최신순', discuss_sort_visit: '조회순', discuss_sort_likesLength: '좋아요순', discuss_sort_commentsLength: '댓글순', discuss_period_all: '전체기간', discuss_period_day: '오늘', discuss_period_week: '최근 1주일', discuss_period_month: '최근 1개월', discuss_period_three_month: '최근 3개월', art_category_living: '생활과 도구', art_category_storytelling: '스토리텔링', art_category_arts: '예술', art_category_knowledge: '지식 공유', art_period_today: '오늘', art_period_quarter: '최근 3개월', }; Lang.Helper = { when_run_button_click: '시작하기 버튼을 클릭하면 아래에 연결된 블록들을 실행합니다.', when_some_key_pressed: '선택한 키를 누르면 아래에 연결된 블록들을 실행합니다.', mouse_clicked: '마우스를 클릭했을 때 아래에 연결된 블록들을 실행합니다.', mouse_click_cancled: '마우스 클릭을 해제했을 때 아래에 연결된 블록들을 실행합니다.', when_object_click: '오브젝트를 클릭했을 때 아래에 연결된 블록들을 실행합니다.', when_object_click_canceled: '오브젝트 클릭을 해제했을 때 아래에 연결된 블록들을 실행합니다.', when_message_cast: '선택한 신호를 받으면 아래에 연결된 블록들을 실행합니다.', message_cast: '선택한 신호를 보냅니다.', message_cast_wait: '선택한 신호를 보내고, 해당 신호를 받는 블록들의 실행이 끝날 때 까지 기다립니다.', when_scene_start: '장면이 시작되면 아래에 연결된 블록들을 실행합니다. ', start_scene: '선택한 장면을 시작합니다.', start_neighbor_scene: '이전 또는 다음 장면을 시작합니다.', wait_second: '입력한 시간만큼 기다린 후 다음 블록을 실행합니다.', repeat_basic: '입력한 횟수만큼 감싸고 있는 블록들을 반복 실행합니다.', repeat_inf: '감싸고 있는 블록들을 계속해서 반복 실행합니다.', repeat_while_true: '판단값에 따라 블록의 반복여부를 결정합니다.\n이 될 때까지: 판단이 참이 될 때까지 감싸고 있는 블록들을 반복 실행합니다.\n인 동안: 판단이 참인 동안 감싸고 있는 블록들을 반복 실행합니다.', stop_repeat: "이 블록을 감싸는 가장 가까운 블록을 멈춥니다.\n'반복하기'블록과 같이 ㄷ자 모양으로 다른 블록을 감싼 블록에 조립해 사용할 수 있습니다.", continue_repeat: '이 블록을 감싸는 가장 가까운 반복 블록의 이번 반복을 건너뛰고 다음 반복의 처음부터 실행합니다.', _if: '만일 판단이 참이라면, 감싸고 있는 블록들을 실행합니다.', if_else: '만일 판단이 참이라면 첫 번째 감싸고 있는 블록들을 실행하고, 거짓이면 두 번째 감싸고 있는 블록들을 실행합니다.', restart_project: '작품을 처음부터 다시 실행합니다.', stop_object: '블록이 실행을 멈춥니다. 현재 실행중인 동작을 멈추는 블록이며, 프로그램을 종료하지 않습니다.\n모든 : 작품의 모든 블록이 실행을 멈춥니다. \n자신 : 해당 오브젝트의 모든 블록이 실행을 멈춥니다.\n이 코드 : 이 블록이 포함된 블록들이 실행을 멈춥니다.\n자신의 다른 코드 : 해당 오브젝트 중 이 블록이 포함된 블록들을 제외한 모든 블록이 실행을 멈춥니다.\n다른 오브젝트의 : 다른 오브젝트의 모든 블록이 실행을 멈춥니다.', wait_until_true: '판단이 참이 될 때까지 실행을 멈추고 기다립니다.', when_clone_start: '해당 오브젝트의 복제본이 새로 생성되었을 때 아래에 연결된 블록들을 실행합니다.', create_clone: '선택한 오브젝트의 복제본을 생성합니다.', delete_clone: '‘복제본이 처음 생성되었을 때’ 블록과 함께 사용되며, 연결된 블록들이 실행되고 있는 복제본을 삭제합니다.', remove_all_clones: '해당 오브젝트의 모든 복제본을 삭제합니다.', move_direction: '입력한 값만큼 오브젝트의 이동 방향 화살표가 가리키는 방향으로 움직입니다.', move_x: '오브젝트의 x 좌표를 입력한 값만큼 바꿉니다. ', move_y: '오브젝트의 y 좌표를 입력한 값만큼 바꿉니다.', move_xy_time: '오브젝트가 입력한 시간에 걸쳐 x와 y 좌표를 입력한 값만큼 바꿉니다.', locate_object_time: '오브젝트가 입력한 시간에 걸쳐 선택한 오브젝트 또는 마우스 포인터의 위치로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_x: '오브젝트가 입력한 x 좌표로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_y: '오브젝트가 입력한 y 좌표로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_xy: '오브젝트가 입력한 x와 y 좌표로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_xy_time: '오브젝트가 입력한 시간에 걸쳐 입력한 x와 y 좌표로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate: '오브젝트가 선택한 오브젝트 또는 마우스 포인터의 위치로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', rotate_absolute: '오브젝트의 방향을 입력한 각도로 정합니다.', rotate_by_time: '오브젝트의 방향이 입력한 시간에 걸쳐 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', rotate_relative: '오브젝트의 방향이 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', direction_absolute: '오브젝트의 이동 방향을 입력한 각도로 정합니다.', direction_relative: '오브젝트의 이동 방향이 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', move_to_angle: '오브젝트가 입력한 각도 방향으로 입력한 값만큼 움직입니다. (실행화면 위쪽이 0도를 나타내며, 시계방향으로 갈수록 각도가 증가합니다.)', see_angle_object: '해당 오브젝트가 방향을 회전하여 선택한 오브젝트 또는 마우스 포인터 쪽을 바라봅니다. ', bounce_wall: '오브젝트가 실행화면 끝에 닿으면 튕겨 나옵니다.', show: '오브젝트를 실행화면에 보이게 합니다.', hide: '오브젝트를 실행화면에 보이지 않게 합니다.', dialog_time: '오브젝트가 입력한 내용을 입력한 시간 동안 말풍선으로 말한 후 다음 블록을 실행합니다.', dialog: '오브젝트가 입력한 내용을 말풍선으로 말하는 동시에 다음 블록을 실행합니다.', remove_dialog: '오브젝트가 말하거나 생각하고 있는 말풍선을 지웁니다.', change_to_some_shape: '오브젝트를 선택한 모양으로 바꿉니다.\n모양 이름 블록이나 모양 번호를 입력한 값 블록을 결합해 사용할 수 있습니다.', change_to_next_shape: '오브젝트의 모양을 이전 또는 다음 모양으로 바꿉니다.', set_effect_volume: '오브젝트에 선택한 효과를 입력한 값만큼 줍니다.', set_effect_amount: '오브젝트에 선택한 효과를 입력한 값만큼 줍니다.', set_effect: '오브젝트의 효과를 입력한 값으로 정합니다.\n색깔 : 0~100을 주기로 반복됩니다.\n밝기 : -100~100 사이의 범위로 설정할 수 있습니다. (-100 이하는 -100으로 100 이상은 100으로 처리됩니다.)\n투명도 : 0~100 사이의 범위로 설정할 수 있습니다. (0 이하는 0으로, 100 이상은 100으로 처리됩니다.)', set_entity_effect: '오브젝트의 효과를 입력한 값으로 정합니다.\n색깔 : 0~100을 주기로 반복됩니다.\n밝기 : -100~100 사이의 범위로 설정할 수 있습니다. (-100 이하는 -100으로 100 이상은 100으로 처리됩니다.)\n투명도 : 0~100 사이의 범위로 설정할 수 있습니다. (0 이하는 0으로, 100 이상은 100으로 처리됩니다.)', add_effect_amount: '오브젝트에 선택한 효과를 입력한 값만큼 줍니다.\n\n- 색깔 : 1~100, 입력한 숫자에 해당하는 색깔 효과를 줍니다.\n- 밝기 : -100~100, 입력한 숫자만큼 밝기 효과를 줍니다.\n- 투명도 : 0~100, 입력한 숫자만큼 투명도 효과를 줍니다.', change_effect_amount: '오브젝트의 효과를 입력한 값으로 정합니다.\n\n- 색깔 : 1~100, 입력한 숫자에 해당하는 색깔 효과를 줍니다.\n- 밝기 : -100~100, 입력한 숫자만큼 밝기 효과를 줍니다.\n- 투명도 : 0~100, 입력한 숫자만큼 투명도 효과를 줍니다.', change_scale_percent: '오브젝트의 크기를 입력한 값만큼 바꿉니다.', set_scale_percent: '오브젝트의 크기를 입력한 값으로 정합니다.', change_scale_size: '오브젝트의 크기를 입력한 값만큼 바꿉니다.', set_scale_size: '오브젝트의 크기를 입력한 값으로 정합니다.', stretch_scale_size: '오브젝트의 가로/세로 크기를 입력한 값만큼 늘입니다.', reset_scale_size: '오브젝트를 원래 크기로 되돌립니다.', flip_x: '오브젝트의 상하 모양을 뒤집습니다.', flip_y: '오브젝트의 좌우 모양을 뒤집습니다.', change_object_index: '오브젝트가 실행화면에 보이는 순서를 변경합니다.\n- 맨 앞으로 : 해당 오브젝트를 실행화면의 가장 앞쪽으로 가져옵니다.\n- 앞으로 : 해당 오브젝트를 한 층 앞쪽으로 가져옵니다.\n- 뒤로 : 해당 오브젝트를 한 층 뒤쪽으로 보냅니다.\n- 맨 뒤로 : 해당 오브젝트를 실행화면의 가장 뒤쪽으로 보냅니다.', set_object_order: '해당 오브젝트가 설정한 순서로 올라옵니다.', brush_stamp: '오브젝트의 모양을 도장처럼 실행화면 위에 찍습니다.', start_drawing: '오브젝트가 이동하는 경로를 따라 선이 그리기 시작합니다. (오브젝트의 중심점이 기준이 됩니다.)', stop_drawing: '오브젝트가 선 그리는 것을 멈춥니다.', start_fill: '오브젝트가 이동하는 경로를 따라 선을 그리고 내부를 채우기 시작합니다. (오브젝트의 중심점이 기준이 됩니다.)', stop_fill: '오브젝트가 채우는 것을 멈춥니다.', set_color: '오브젝트가 그리는 선의 색을 선택한 색으로 정합니다.', set_random_color: '오브젝트가 그리는 선의 색을 무작위로 정합니다.', set_fill_color: '오브젝트가 채우는 색을 선택한 색으로 정합니다.', change_thickness: '오브젝트가 그리는 선의 굵기를 입력한 값만큼 바꿉니다.', set_thickness: '오브젝트가 그리는 선의 굵기를 입력한 값으로 정합니다. 1~무한의 범위로 설정할 수 있습니다. (1 이하는 1로 처리합니다.)', change_opacity: '해당 오브젝트가 그리는 붓의 투명도를 입력한 값만큼 바꿉니다.', change_brush_transparency: '해당 오브젝트가 그리는 붓의 투명도를 입력한 값만큼 바꿉니다.', set_opacity: '해당 오브젝트가 그리는 붓의 투명도를 입력한 값으로 정합니다. 0~100의 범위로 설정할 수 있습니다. (0 이하는 0, 100 이상은 100으로 처리합니다.)', set_brush_tranparency: '해당 오브젝트가 그리는 붓의 투명도를 입력한 값으로 정합니다. 0~100의 범위로 설정할 수 있습니다. (0 이하는 0, 100 이상은 100으로 처리합니다.)', brush_erase_all: '해당 오브젝트가 그린 선과 도장을 모두 지웁니다.', sound_something_with_block: '오브젝트가 선택한 소리를 재생하는 동시에 다음 블록을 실행합니다.', sound_something_second_with_block: '오브젝트가 선택한 소리를 입력한 시간 만큼 재생하는 동시에 다음 블록을 실행합니다.', sound_something_wait_with_block: '오브젝트가 선택한 소리를 재생한 후 다음 블록을 실행합니다.', sound_something_second_wait_with_block: '오브젝트가 선택한 소리를 입력한 시간만큼 재생한 후 다음 블록을 실행합니다.', sound_volume_change: '작품에서 재생하는 모든 소리의 크기를 입력한 값만큼 바꿉니다.', sound_volume_set: '작품에서 재생하는 모든 소리의 크기를 입력한 값(%)으로 정합니다.', get_sound_speed: '작품에 설정된 소리의 빠르기 값입니다.', sound_speed_change: '작품에서 재생하는 모든 소리의 빠르기를 입력한 값만큼 바꿉니다.', sound_speed_set: '작품에서 재생하는 모든 소리의 빠르기를 입력한 값(배수)으로 정합니다.', sound_silent_all: '재생하는 소리 중 선택한 소리를 멈춥니다.', play_bgm: '선택한 소리를 배경음악으로 재생하는 동시에 다음 블록을 실행합니다.', stop_bgm: '재생하는 배경음악을 멈춥니다.', is_clicked: '마우스를 클릭한 경우 ‘참’으로 판단합니다.', is_object_clicked: '오브젝트를 클릭한 경우 ‘참’으로 판단합니다.', is_press_some_key: '선택한 키가 눌려져 있는 경우 ‘참’으로 판단합니다.', reach_something: '해당 오브젝트가 선택한 항목과 닿은 경우 ‘참’으로 판단합니다.', is_type: '입력한 값이 선택한 문자로 이루어져 있다면 ‘참’으로 판단합니다.', is_included_in_list: "선택한 리스트가 입력한 값을 가진 항목을 포함하는 경우 '참'으로 판단합니다.", boolean_basic_operator: "입력한 두 값을 비교합니다.\n= : 왼쪽에 위치한 값과 오른쪽에 위치한 값이 같은 경우 '참'으로 판단합니다.\n!= : 왼쪽에 위치한 값과 오른쪽에 위치한 값이 같지 않은 경우 '참'으로 판단합니다.\n> : 왼쪽에 위치한 값이 오른쪽에 위치한 값보다 큰 경우 '참'으로 판단합니다.\n< : 왼쪽에 위치한 값이 오른쪽에 위치한 값보다 작은 경우 '참'으로 판단합니다.\n≥ : 왼쪽에 위치한 값이 오른쪽에 위치한 값보다 크거나 같은 경우 '참'으로 판단합니다.\n≤ : 왼쪽에 위치한 값이 오른쪽에 위치한 값보다 작거나 같은 경우 '참'으로 판단합니다.", function_create: '자주 쓰는 코드를 이 블록 아래에 조립하여 함수로 만듭니다. [함수 정의하기]의 오른쪽 빈칸에 [이름]을 조립하여 함수의 이름을 정할 수 있습니다. 함수를 실행하는 데 입력값이 필요한 경우 빈칸에 [문자/숫자값], [판단값]을 조립하여 매개변수로 사용합니다.', function_field_label: "함수 정의하기' 블록 안에 조립하며, 함수의 이름을 정합니다. ", function_field_string: "함수 정의하기' 블록 안에 조립하며, 입력한 문자/숫자값(매개변수)에 따라 함수의 실행 결과가 달라집니다. 이 블록을 분리하여 함수의 코드 중 필요한 부분에 넣어 사용합니다.", function_field_boolean: "함수 정의하기' 블록 안에 조립하며, 참 또는 거짓의 판단값에 따라 함수의 실행 결과가 달라집니다. 이 블록을 분리하여 함수의 코드 중 필요한 부분에 넣어 사용합니다.", function_general: '현재 만들고 있는 함수 블록 또는 지금까지 만들어 둔 함수 블록입니다.', boolean_and: '두 판단이 모두 참인 경우 ‘참’으로 판단합니다.', boolean_or: '두 판단 중 하나라도 참이 있는 경우 ‘참’으로 판단합니다.', boolean_not: "해당 판단이 참이면 '거짓', 거짓이면 '참'으로 판단합니다.", is_boost_mode: '부스트모드가 켜져 있으면 ‘참’으로 판단합니다.', is_current_device_type: "작품을 실행하는 기기가 선택한 기기라면 '참'으로 판단합니다.", is_touch_supported: "작품을 실행하는 기기에서 화면을 터치할 수 있다면 '참'으로 판단합니다.", calc_basic: '입력한 두 수의 사칙연산 값입니다.\n+ : 입력한 두 수를 더한 값입니다.\n- : 입력한 두 수를 뺀 값입니다.\n* : 입력한 두 수를 곱한 값입니다.\n/ : 입력한 두 수를 나눈 값입니다.', calc_rand: '입력한 두 수 사이에서 선택된 무작위 수 값입니다. (두 수 모두 정수를 입력한 경우 정수가, 두 수 중 하나라도 소수를 입력한 경우 소숫점 둘째 자리의 소수 값이 선택됩니다.)', get_x_coordinate: '해당 오브젝트의 x 좌푯값을 의미합니다.', get_y_coordinate: '해당 오브젝트의 y 좌푯값을 의미합니다.', coordinate_mouse: '마우스 포인터의 x 또는 y 좌푯값입니다.', coordinate_object: '선택한 오브젝트의 각종 정보 값입니다. (x 좌푯값, y 좌푯값, 방향, 이동 방향, 크기, 모양 번호, 모양 이름)', quotient_and_mod: '입력한 두 수를 나눈 결괏값입니다.\n- 몫 : 앞의 수에서 뒤의 수를 나누어 생긴 몫의 값입니다.\n- 나머지 : 앞의 수에서 뒤의 수를 나누어 생긴 나머지 값입니다.', get_rotation_direction: '해당 오브젝트의 방향값, 이동 방향값을 의미합니다.', calc_share: '앞 수에서 뒤 수를 나누어 생긴 몫을 의미합니다.', calc_mod: '앞 수에서 뒤 수를 나누어 생긴 나머지를 의미합니다.', calc_operation: '입력한 수에 대한 다양한 수학식의 계산값입니다. (제곱, 루트, 사인, 코사인, 탄젠트, 아크사인, 아크코사인, 아크탄젠트, 로그, 자연로그, 소수점 부분, 소수점 버림값, 소수점 올림값, 소수점 반올림값, 팩토리얼, 절댓값)', get_date: '현재 날짜와 시각에 대한 값입니다.\n- 연도: 현재 연도를 반환합니다.\n- 월: 현재 월을 반환합니다.\n- 일: 현재 일을 반환합니다.\n- 요일: 현재 요일을 숫자로 반환합니다.\n일, 월, 화, 수, 목, 금, 토요일을 차례대로 0, 1, 2, 3, 4, 5, 6으로 반환합니다.\n- 시각: 현재 시각을 각각 시, 분, 초로 반환합니다.', distance_something: '해당 오브젝트와 선택한 오브젝트 또는 마우스 포인터 간의 거릿값입니다.', get_sound_duration: '선택한 소리의 길이(초) 값입니다.', get_user_name: '작품을 실행하고 있는 사용자의 아이디 값입니다.\n값은 개인정보 보호를 위해 마스킹 처리되어 있습니다.', get_nickname: '작품을 실행하고 있는 사용자의 닉네임 값입니다.', get_project_timer_value: '이 블록이 실행되는 순간 초시계에 저장된 값입니다.', choose_project_timer_action: '초시계의 상태를 정합니다.\n- 시작하기: 초시계를 시작합니다.\n- 정지하기: 초시계를 정지합니다.\n- 초기화하기: 초시계의 값을 0으로 초기화합니다.', reset_project_timer: '실행되고 있던 타이머를 0으로 초기화합니다.', set_visible_project_timer: '초시계 창을 실행화면에서 숨기거나 보이게 합니다.', ask_and_wait: '오브젝트가 입력한 문자를 말풍선으로 묻고, 대답을 입력받습니다. (이 블록이 실행되면 실행화면에 ‘대답 창’이 생성됩니다.)', get_canvas_input_value: "사용자가 '대답 창'에 입력한 값입니다.", set_visible_answer: "대답 창'을 실행화면에서 숨기거나 보이게 합니다.", combine_something: '입력한 두 값을 결합한 값입니다.', reverse_of_string: '입력한 값을 뒤집은 값입니다.', get_variable: '선택한 변수에 저장된 값입니다.', change_variable: '선택한 변수에 입력한 값을 더합니다.', set_variable: '선택한 변수의 값을 입력한 값으로 정합니다.', robotis_carCont_sensor_value: '왼쪽 접속 센서 : 접촉(1), 비접촉(0) 값 입니다.
오른쪽 접촉 센서 : 접촉(1), 비접촉(0) 값 입니다.
선택 버튼 상태 : 접촉(1), 비접촉(0) 값 입니다.
최종 소리 감지 횟수 : 마지막 실시간 소리 감지 횟수 값 입니다.
실시간 소리 감지 횟수 : 약 1초 안에 다음 소리가 감지되면 1씩 증가합니다.
왼쪽 적외선 센서 : 물체와 가까울 수록 큰 값 입니다.
오른쪽 적외선 센서 : 물체와 가까울 수록 큰 값 값 입니다.
왼쪽 적외선 센서 캘리브레이션 값 : 적외선 센서의 캘리브레이션 값 입니다.
오른쪽 적외선 센서 캘리브레이션 값 : 적외선 센서의 캘리브레이션 값 입니다.
(*캘리브레이션 값 - 적외선센서 조정 값)', robotis_carCont_cm_led: '4개의 LED 중 1번 또는 4번 LED 를 켜거나 끕니다.
LED 2번과 3번은 동작 지원하지 않습니다.', robotis_carCont_cm_sound_detected_clear: '최종 소리 감지횟 수를 0 으로 초기화 합니다.', robotis_carCont_aux_motor_speed: '감속모터 속도를 0 ~ 1023 의 값(으)로 정합니다.', robotis_carCont_cm_calibration: '적외선센서 조정 값(http://support.robotis.com/ko/: 자동차로봇> 2. B. 적외선 값 조정)을 직접 정합니다.', robotis_openCM70_sensor_value: '최종 소리 감지 횟수 : 마지막 실시간 소리 감지 횟수 값 입니다.
실시간 소리 감지 횟수 : 약 1초 안에 다음 소리가 감지되면 1씩 증가합니다.
사용자 버튼 상태 : 접촉(1), 비접촉(0) 값 입니다.최종 소리 감지 횟수 : 마지막 실시간 소리 감지 횟수 값 입니다.
실시간 소리 감지 횟수 : 약 1초 안에 다음 소리가 감지되면 1씩 증가합니다.
사용자 버튼 상태 : 접촉(1), 비접촉(0) 값 입니다.', robotis_openCM70_aux_sensor_value: '서보모터 위치 : 0 ~ 1023, 중간 위치의 값은 512 입니다.
적외선센서 : 물체와 가까울 수록 큰 값 입니다.
접촉센서 : 접촉(1), 비접촉(0) 값 입니다.
조도센서(CDS) : 0 ~ 1023, 밝을 수록 큰 값 입니다.
온습도센서(습도) : 0 ~ 100, 습할 수록 큰 값 입니다.
온습도센서(온도) : -20 ~ 100, 온도가 높을 수록 큰 값 입니다.
온도센서 : -20 ~ 100, 온도가 높을 수록 큰 값 입니다.
초음파센서 : -
자석센서 : 접촉(1), 비접촉(0) 값 입니다.
동작감지센서 : 동작 감지(1), 동작 미감지(0) 값 입니다.
컬러센서 : 알수없음(0), 흰색(1), 검은색(2), 빨간색(3), 녹색(4), 파란색(5), 노란색(6) 값 입니다.
사용자 장치 : 사용자 센서 제작에 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.', robotis_openCM70_cm_buzzer_index: '음계를 0.1 ~ 5 초 동안 연주 합니다.', robotis_openCM70_cm_buzzer_melody: "멜로디를 연주 합니다.
멜로디를 연속으로 재생하는 경우, 다음 소리가 재생되지 않으면 '흐름 > X 초 기다리기' 블록을 사용하여 기다린 후 실행합니다.", robotis_openCM70_cm_sound_detected_clear: '최종 소리 감지횟 수를 0 으로 초기화 합니다.', robotis_openCM70_cm_led: '제어기의 빨간색, 녹색, 파란색 LED 를 켜거나 끕니다.', robotis_openCM70_cm_motion: '제어기에 다운로드 되어있는 모션을 실행합니다.', robotis_openCM70_cm_autodrive_motor: '자율주행 자동차의 모터 포트를 지정합니다.', robotis_openCM70_cm_autodrive_ir: '자율주행 자동차의 적외선 센서 포트를 지정합니다.', robotis_openCM70_cm_autodrive_speed: '지정한 속도로 자율주행을 수행합니다.', robotis_openCM70_aux_car_move: '로봇을 지정한 속도와 방향으로 움직이도록 합니다.', robotis_openCM70_aux_motor_speed: '감속모터 속도를 0 ~ 100% 의 값으로 정합니다.', robotis_openCM70_aux_servo_mode: '서보모터를 회전모드 또는 관절모드로 정합니다.
한번 설정된 모드는 계속 적용됩니다.
회전모드는 서보모터 속도를 지정하여 서보모터를 회전 시킵니다.
관절모드는 지정한 서보모터 속도로 서보모터 위치를 이동 시킵니다.', robotis_openCM70_aux_servo_speed: '서보모터 속도를 0 ~ 100% 의 값으로 정합니다.', robotis_openCM70_aux_servo_position: '서보모터 위치를 -150도 ~ 150도 의 값(으)로 정합니다.
서보모터 속도와 같이 사용해야 합니다.', robotis_openCM70_aux_led_module: 'LED 모듈의 LED 를 켜거나 끕니다.', robotis_openCM70_aux_custom: '사용자 센서 제작에 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.', robotis_openCM70_cm_poweroff_timer: '제어기의 자동꺼짐 타이머를 설정합니다.
설정된 만큼의 시간동안 통신이 진행되지 않으면 제어기는 자동으로 꺼집니다.', robotis_openCM70_cm_custom_value: '컨트롤 테이블 주소를 직접 입력하여 값을 확인 합니다.
컨트롤 테이블 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.', robotis_openCM70_cm_custom: '컨트롤 테이블 주소를 직접 입력하여 값을 정합니다.
컨트롤 테이블 대한 설명은 ROBOTIS e-매뉴얼(http://support.robotis.com/ko/)을 참고하세요.', show_variable: "선택한 변수의 '변수 창'을 실행화면에 보이게 합니다.", hide_variable: "선택한 변수의 '변수 창'을 실행화면에서 숨깁니다.", value_of_index_from_list: '선택한 리스트에서 입력한 순서에 있는 항목 값입니다.', add_value_to_list: '입력한 값을 선택한 리스트의 마지막 항목에 추가합니다.', remove_value_from_list: '선택한 리스트의 입력한 순서에 있는 항목을 삭제합니다.', insert_value_to_list: '입력한 값을 선택한 리스트의 입력한 순서의 항목으로 추가합니다. (입력한 항목 뒤에 있는 항목들은 순서가 하나씩 밀려납니다.)', change_value_list_index: '선택한 리스트에서 입력한 순서에 있는 항목의 값을 입력한 값으로 바꿉니다.', length_of_list: '선택한 리스트가 보유한 항목의 개수입니다.', show_list: "선택한 리스트의 '리스트 창'을 실행화면에 보이게 합니다.", hide_list: "선택한 리스트의 '리스트 창'을 실행화면에서 숨깁니다.", text: '해당 글상자가 표시하고 있는 문자값을 의미합니다.', text_read: '선택한 글상자에 입력된 텍스트 값입니다. 내용에 줄바꿈이 포함되면 띄어쓰기로 반환합니다.', text_write: '글상자의 내용을 입력한 값으로 고쳐 씁니다.', text_append: '글상자의 내용 뒤에 입력한 값을 추가합니다.', text_prepend: '글상자의 내용 앞에 입력한 값을 추가합니다.', text_change_effect: '글상자에 선택한 텍스트 효과를 켜거나 끕니다.', text_change_font: '글상자를 선택한 글씨체로 변경합니다. ', text_change_font_color: '글상자를 선택한 글씨색으로 변경합니다.', text_change_bg_color: '글상자를 선택한 배경색으로 변경합니다.', text_flush: '글상자의 내용을 모두 지웁니다.', erase_all_effects: '오브젝트에 적용된 효과를 모두 지웁니다.', char_at: '입력한 값에서 입력한 숫자 번째의 글자 값입니다. (공백을 포함합니다.)', length_of_string: '입력한 값의 공백을 포함한 글자 수입니다.', substring: '입력한 값에서 입력한 범위 내의 글자 값입니다. (공백을 포함합니다.)', count_match_string: '입력한 값에서 지정한 값의 글자 수이며, 영문의 경우 대문자와 소문자를 구분하여 수를 셉니다.', replace_string: '입력한 값에서 지정한 값을 찾아 추가로 입력한 값으로 모두 바꾼 값입니다. (영문 입력 시 대소문자를 구분합니다.)', index_of_string: '입력한 값에서 지정한 값이 처음으로 등장하는 위치 값입니다. (공백을 포함합니다.)', change_string_case: '입력한 영문의 모든 알파벳을 대문자 또는 소문자로 바꾼 값입니다.', get_block_count: '선택한 항목에서 사용된 블록의 수입니다.\n시작 블록에 조립된 블록을 기준으로 수를 셉니다.\n- 모든: 작품의 모든 블록의 수를 셉니다.\n- 자신: 이 오브젝트의 블록 수를 셉니다.\n- (오브젝트 이름): 선택한 오브젝트의 블록 수를 셉니다.\n- (장면 이름): 선택한 장면의 블록 수를 셉니다.', get_boolean_value: "결합한 판단 블록의 결괏값입니다. 판단 블록이 '참'이면 'TRUE', '거짓'이면 'FALSE'를 반환합니다.", direction_relative_duration: '오브젝트의 이동 방향이 입력한 시간에 걸쳐 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', get_sound_volume: '작품에 설정된 소리의 크기 값입니다.', sound_from_to: '오브젝트가 선택한 소리의 입력한 구간을 재생하는 동시에 다음 블록을 실행합니다.', sound_from_to_and_wait: '오브젝트가 선택한 소리의 입력한 구간을 재생한 후 다음 블록을 실행합니다.', Block_info: '블록 설명', Block_click_msg: '블록을 클릭하면\n블록에 대한 설명이 나타납니다.', hamster_beep: '버저 소리를 짧게 냅니다.', hamster_change_both_wheels_by: '왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', hamster_change_buzzer_by: '버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.', hamster_change_output_by: '선택한 외부 확장 포트의 현재 출력 값에 입력한 값을 더합니다. 더한 결과는 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH', hamster_change_tempo_by: '연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.', hamster_change_wheel_by: '왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', hamster_clear_buzzer: '버저 소리를 끕니다.', hamster_clear_led: '왼쪽/오른쪽/양쪽 LED를 끕니다.', hamster_follow_line_until: '왼쪽/오른쪽/앞쪽/뒤쪽의 검은색/하얀색 선을 따라 이동하다가 교차로를 만나면 정지합니다.', hamster_follow_line_using: '왼쪽/오른쪽/양쪽 바닥 센서를 사용하여 검은색/하얀색 선을 따라 이동합니다.', hamster_hand_found: "근접 센서 앞에 손 또는 물체가 있으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", hamster_move_backward_for_secs: '입력한 시간(초) 동안 뒤로 이동합니다.', hamster_move_forward_for_secs: '입력한 시간(초) 동안 앞으로 이동합니다.', hamster_move_forward_once: '말판 위에서 한 칸 앞으로 이동합니다.', hamster_play_note_for: '선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.', hamster_rest_for: '입력한 박자만큼 쉽니다.', hamster_set_both_wheels_to: '왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', hamster_set_buzzer_to: '버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 버저 소리를 끕니다.', hamster_set_following_speed_to: '선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.', hamster_set_led_to: '왼쪽/오른쪽/양쪽 LED를 선택한 색깔로 켭니다.', hamster_set_output_to: '선택한 외부 확장 포트의 출력 값을 입력한 값으로 설정합니다. 입력하는 값은 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH', hamster_set_port_to: '선택한 외부 확장 포트의 입출력 모드를 선택한 모드로 설정합니다.', hamster_set_tempo_to: '연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.', hamster_set_wheel_to: '왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', hamster_stop: '양쪽 바퀴를 정지합니다.', hamster_turn_for_secs: '입력한 시간(초) 동안 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.', hamster_turn_once: '말판 위에서 왼쪽/오른쪽 방향으로 제자리에서 90도 회전합니다.', hamster_value: '왼쪽 근접 센서: 왼쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
오른쪽 근접 센서: 오른쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
왼쪽 바닥 센서: 왼쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
오른쪽 바닥 센서: 오른쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.
밝기: 밝기 센서의 값 (값의 범위: 0 ~ 65535, 초기값: 0) 밝을 수록 값이 커집니다.
온도: 로봇 내부의 온도 값 (값의 범위: 섭씨 -40 ~ 88도, 초기값: 0)
신호 세기: 블루투스 무선 통신의 신호 세기 (값의 범위: -128 ~ 0 dBm, 초기값: 0) 신호의 세기가 셀수록 값이 커집니다.
입력 A: 외부 확장 포트 A로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)
입력 B: 외부 확장 포트 B로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)', roboid_hamster_beep: '버저 소리를 짧게 냅니다.', roboid_hamster_change_both_wheels_by: '왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', roboid_hamster_change_buzzer_by: '버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.', roboid_hamster_change_output_by: '선택한 외부 확장 포트의 현재 출력 값에 입력한 값을 더합니다. 더한 결과는 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH', roboid_hamster_change_tempo_by: '연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.', roboid_hamster_change_wheel_by: '왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', roboid_hamster_clear_buzzer: '버저 소리를 끕니다.', roboid_hamster_clear_led: '왼쪽/오른쪽/양쪽 LED를 끕니다.', roboid_hamster_follow_line_until: '왼쪽/오른쪽/앞쪽/뒤쪽의 검은색/하얀색 선을 따라 이동하다가 교차로를 만나면 정지합니다.', roboid_hamster_follow_line_using: '왼쪽/오른쪽/양쪽 바닥 센서를 사용하여 검은색/하얀색 선을 따라 이동합니다.', roboid_hamster_hand_found: "근접 센서 앞에 손 또는 물체가 있으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", roboid_hamster_move_backward_for_secs: '입력한 시간(초) 동안 뒤로 이동합니다.', roboid_hamster_move_forward_for_secs: '입력한 시간(초) 동안 앞으로 이동합니다.', roboid_hamster_move_forward_once: '말판 위에서 한 칸 앞으로 이동합니다.', roboid_hamster_play_note_for: '선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.', roboid_hamster_rest_for: '입력한 박자만큼 쉽니다.', roboid_hamster_set_both_wheels_to: '왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', roboid_hamster_set_buzzer_to: '버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 버저 소리를 끕니다.', roboid_hamster_set_following_speed_to: '선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.', roboid_hamster_set_led_to: '왼쪽/오른쪽/양쪽 LED를 선택한 색깔로 켭니다.', roboid_hamster_set_output_to: '선택한 외부 확장 포트의 출력 값을 입력한 값으로 설정합니다. 입력하는 값은 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH', roboid_hamster_set_port_to: '선택한 외부 확장 포트의 입출력 모드를 선택한 모드로 설정합니다.', roboid_hamster_set_tempo_to: '연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.', roboid_hamster_set_wheel_to: '왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', roboid_hamster_stop: '양쪽 바퀴를 정지합니다.', roboid_hamster_turn_for_secs: '입력한 시간(초) 동안 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.', roboid_hamster_turn_once: '말판 위에서 왼쪽/오른쪽 방향으로 제자리에서 90도 회전합니다.', roboid_hamster_value: '왼쪽 근접 센서: 왼쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
오른쪽 근접 센서: 오른쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
왼쪽 바닥 센서: 왼쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
오른쪽 바닥 센서: 오른쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.
밝기: 밝기 센서의 값 (값의 범위: 0 ~ 65535, 초기값: 0) 밝을 수록 값이 커집니다.
온도: 로봇 내부의 온도 값 (값의 범위: 섭씨 -40 ~ 88도, 초기값: 0)
신호 세기: 블루투스 무선 통신의 신호 세기 (값의 범위: -128 ~ 0 dBm, 초기값: 0) 신호의 세기가 셀수록 값이 커집니다.
입력 A: 외부 확장 포트 A로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)
입력 B: 외부 확장 포트 B로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)', roboid_turtle_button_state: "등 버튼을 클릭했으면/더블클릭했으면/길게 눌렀으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", roboid_turtle_change_buzzer_by: '버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.', roboid_turtle_change_head_led_by_rgb: '머리 LED의 현재 R, G, B 값에 입력한 값을 각각 더합니다.', roboid_turtle_change_tempo_by: '연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.', roboid_turtle_change_wheel_by: '왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', roboid_turtle_change_wheels_by_left_right: '왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', roboid_turtle_clear_head_led: '머리 LED를 끕니다.', roboid_turtle_clear_sound: '소리를 끕니다.', roboid_turtle_cross_intersection: '검은색 교차로에서 잠시 앞으로 이동한 후 검은색 선을 찾아 다시 이동합니다.', roboid_turtle_follow_line: '하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동합니다.', roboid_turtle_follow_line_until: '하얀색 바탕 위에서 검은색 선을 따라 이동하다가 선택한 색깔을 컬러 센서가 감지하면 정지합니다.', roboid_turtle_follow_line_until_black: '하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동하다가 컬러 센서가 검은색을 감지하면 정지합니다.', roboid_turtle_is_color_pattern: "선택한 색깔 패턴을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", roboid_turtle_move_backward_unit: '입력한 거리(cm)/시간(초)/펄스만큼 뒤로 이동합니다.', roboid_turtle_move_forward_unit: '입력한 거리(cm)/시간(초)/펄스만큼 앞으로 이동합니다.', roboid_turtle_pivot_around_wheel_unit_in_direction: '왼쪽/오른쪽 바퀴 중심으로 입력한 각도(도)/시간(초)/펄스만큼 머리/꼬리 방향으로 회전합니다.', roboid_turtle_play_note: '선택한 계이름과 옥타브의 음을 계속 소리 냅니다.', roboid_turtle_play_note_for_beats: '선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.', roboid_turtle_play_sound_times: '선택한 소리를 입력한 횟수만큼 재생합니다.', roboid_turtle_play_sound_times_until_done: '선택한 소리를 입력한 횟수만큼 재생하고, 재생이 완료될 때까지 기다립니다.', roboid_turtle_rest_for_beats: '입력한 박자만큼 쉽니다.', roboid_turtle_set_buzzer_to: '버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 소리를 끕니다.', roboid_turtle_set_following_speed_to: '선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.', roboid_turtle_set_head_led_to: '머리 LED를 선택한 색깔로 켭니다.', roboid_turtle_set_head_led_to_rgb: '머리 LED의 R, G, B 값을 입력한 값으로 각각 설정합니다.', roboid_turtle_set_tempo_to: '연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.', roboid_turtle_set_wheel_to: '왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', roboid_turtle_set_wheels_to_left_right: '왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', roboid_turtle_stop: '양쪽 바퀴를 정지합니다.', roboid_turtle_touching_color: "선택한 색깔을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", roboid_turtle_turn_at_intersection: '검은색 교차로에서 잠시 앞으로 이동한 후 제자리에서 왼쪽/오른쪽/뒤쪽으로 회전하고 검은색 선을 찾아 다시 이동합니다.', roboid_turtle_turn_unit_in_place: '입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.', roboid_turtle_turn_unit_with_radius_in_direction: '입력한 반지름의 원을 그리면서 입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽, 머리/꼬리 방향으로 회전합니다.', roboid_turtle_value: '색깔 번호: 컬러 센서가 감지한 색깔의 번호 (값의 범위: -1 ~ 8, 초기값: -1)
색깔 패턴: 컬러 센서가 감지한 색깔 패턴의 값 (값의 범위: -1 ~ 88, 초기값: -1)
바닥 센서: 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
버튼: 거북이 등 버튼의 상태 값 (누르면 1, 아니면 0, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.', turtle_button_state: "등 버튼을 클릭했으면/더블클릭했으면/길게 눌렀으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", turtle_change_buzzer_by: '버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.', turtle_change_head_led_by_rgb: '머리 LED의 현재 R, G, B 값에 입력한 값을 각각 더합니다.', turtle_change_tempo_by: '연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.', turtle_change_wheel_by: '왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', turtle_change_wheels_by_left_right: '왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.', turtle_clear_head_led: '머리 LED를 끕니다.', turtle_clear_sound: '소리를 끕니다.', turtle_cross_intersection: '검은색 교차로에서 잠시 앞으로 이동한 후 검은색 선을 찾아 다시 이동합니다.', turtle_follow_line: '하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동합니다.', turtle_follow_line_until: '하얀색 바탕 위에서 검은색 선을 따라 이동하다가 선택한 색깔을 컬러 센서가 감지하면 정지합니다.', turtle_follow_line_until_black: '하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동하다가 컬러 센서가 검은색을 감지하면 정지합니다.', turtle_is_color_pattern: "선택한 색깔 패턴을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", turtle_move_backward_unit: '입력한 거리(cm)/시간(초)/펄스만큼 뒤로 이동합니다.', turtle_move_forward_unit: '입력한 거리(cm)/시간(초)/펄스만큼 앞으로 이동합니다.', turtle_pivot_around_wheel_unit_in_direction: '왼쪽/오른쪽 바퀴 중심으로 입력한 각도(도)/시간(초)/펄스만큼 머리/꼬리 방향으로 회전합니다.', turtle_play_note: '선택한 계이름과 옥타브의 음을 계속 소리 냅니다.', turtle_play_note_for_beats: '선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.', turtle_play_sound_times: '선택한 소리를 입력한 횟수만큼 재생합니다.', turtle_play_sound_times_until_done: '선택한 소리를 입력한 횟수만큼 재생하고, 재생이 완료될 때까지 기다립니다.', turtle_rest_for_beats: '입력한 박자만큼 쉽니다.', turtle_set_buzzer_to: '버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 소리를 끕니다.', turtle_set_following_speed_to: '선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.', turtle_set_head_led_to: '머리 LED를 선택한 색깔로 켭니다.', turtle_set_head_led_to_rgb: '머리 LED의 R, G, B 값을 입력한 값으로 각각 설정합니다.', turtle_set_tempo_to: '연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.', turtle_set_wheel_to: '왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', turtle_set_wheels_to_left_right: '왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.', turtle_stop: '양쪽 바퀴를 정지합니다.', turtle_touching_color: "선택한 색깔을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", turtle_turn_at_intersection: '검은색 교차로에서 잠시 앞으로 이동한 후 제자리에서 왼쪽/오른쪽/뒤쪽으로 회전하고 검은색 선을 찾아 다시 이동합니다.', turtle_turn_unit_in_place: '입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.', turtle_turn_unit_with_radius_in_direction: '입력한 반지름의 원을 그리면서 입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽, 머리/꼬리 방향으로 회전합니다.', turtle_value: '색깔 번호: 컬러 센서가 감지한 색깔의 번호 (값의 범위: -1 ~ 8, 초기값: -1)
색깔 패턴: 컬러 센서가 감지한 색깔 패턴의 값 (값의 범위: -1 ~ 88, 초기값: -1)
바닥 센서: 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
버튼: 거북이 등 버튼의 상태 값 (누르면 1, 아니면 0, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.', neobot_sensor_value: 'IN1 ~ IN3 포트 및 리모컨에서 입력되는 값 그리고 배터리 정보를 0부터 255의 숫자로 표시합니다.', neobot_sensor_convert_scale: '선택한 포트 입력값의 변화를 특정범위의 값으로 표현범위를 조절할 수 있습니다.', neobot_left_motor: 'L모터 포트에 연결한 모터의 회전방향 및 속도를 설정합니다.', neobot_stop_left_motor: 'L모터 포트에 연결한 모터를 정지합니다.', neobot_right_motor: 'R모터 포트에 연결한 모터의 회전방향 및 속도를 설정합니다.', neobot_stop_right_motor: 'R모터 포트에 연결한 모터를 정지합니다.', neobot_all_motor: 'L모터 및 R모터 포트에 2개 모터를 연결하여 바퀴로 활용할 때 전, 후, 좌, 우 이동 방향 및 속도, 시간을 설정할 수 있습니다.', neobot_stop_all_motor: 'L모터 및 R모터에 연결한 모터를 모두 정지합니다.', neobot_set_servo: 'OUT1 ~ OUT3에 서보모터를 연결했을 때 0도 ~ 180도 범위 내에서 각도를 조절할 수 있습니다.', neobot_set_output: 'OUT1 ~ OUT3에 라이팅블록 및 전자회로를 연결했을 때 출력 전압을 설정할 수 있습니다.
0은 0V, 1 ~ 255는 2.4 ~ 4.96V의 전압을 나타냅니다.', neobot_set_fnd: 'FND로 0~99 까지의 숫자를 표시할 수 있습니다.', neobot_set_fnd_off: 'FND에 표시한 숫자를 끌 수 있습니다.', neobot_play_note_for: '주파수 발진 방법을 이용해 멜로디에 반음 단위의 멜로디 음을 발생시킬 수 있습니다.', rotate_by_angle_dropdown: '오브젝트의 방향을 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', chocopi_control_button: '버튼이 눌리면 참이 됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_control_event: '버튼을 누르거나 뗄 때 처리할 엔트리 블록들을 연결합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_control_joystick: '조이스틱 좌우, 상하, 볼륨의 값은 0~4095까지 입니다.
따라서 2047 근처가 중간이 됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_dc_motor: 'DC모터 모듈에는 직류전동기 두개를 연결 할 수 있습니다.
직류 전동기는 최대 5V로 동작하게 됩니다.
값은 100이 최대(100%)이고 음수를 넣으면 반대 방향으로 회전합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_led: 'LED번호는 LED블록에 연결된 순서이고 1번부터 시작합니다.
RGB값은 0~255사이의 값입니다.
빨강(Red),녹색(Green), 파랑(Blue)순서로 입력합니다.
밝은 LED를 직접보면 눈이 아프니까 값을 0~5정도로 씁니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_motion_photogate_event: '포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
빛센서를 물체로 가리거나 치우면 시작되는 엔트리 블록을 연결합니다
모션 모듈에는 포토게이트 2개를 연결할 수 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_motion_photogate_status: '포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
물체가 빛센서를 가리면 참이됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_motion_photogate_time: '포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
이 블록은 물체가 빛센서를 가리거나 벗어난 시간을 가집니다.
1/10000초까지 측정할 수 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_motion_value: '모션 모듈에는 3개의 적외선 센서가 있습니다.
0~4095사이의 값을 가질 수 있는데 물체가 빛을 많이 반사할 수록 작은 값을 가집니다.
거리를 대략적으로 측정할 수 있습니다.
가속도와 각가속도 값의 범위는 -32768~32767 까지입니다.
가속도를 이용해서 센서의 기울기를 측정할 수도 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_sensor: '온도 값은 섭씨 온도입니다.
습도 값은 백분율로 나타낸 상대습도 값입니다.
빛은 로그스케일로 0~4095사이입니다.
아날로그 값은 0~4095사이입니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_servo_motor: '서보모터 모듈에는 4개의 서보모터를 연결 할 수 있습니다.
서보모터는 5V로 동작하게 됩니다.
각도는 0~200도까지 지정할 수 있습니다.
연속회전식 서보모터를 연결하면 각도에 따라 속도가 변하게됩니다.
90~100 사이가 중간값입니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_touch_event: '터치 모듈에는 1~12번의 연결 패드가 있습니다.
만지거나 뗄 때 처리할 엔트리 블록들을 연결합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_touch_status: '터치 모듈의 패드를 만지면 참이됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', chocopi_touch_value: '터치패드에 연결된 물체의 전기용량이 커지면 값이 작아집니다.
여러 명이 손잡고 만지면 더 작은 값이 됩니다.
전기용량이란 물체에 전기를 띈 입자를 얼마나 가지고 있을 수 있는 지를 말합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.', boolean_and_or: '그리고: 두 판단이 모두 참인 경우 ‘참’으로 판단합니다.\n또는: 두 판단 중 하나라도 참이 있는 경우 ‘참’으로 판단합니다.', check_weather: '\n선택한 날짜와 지역의 날씨 정보를 실제 날씨 상태와 비교하여 일치하는 경우 ‘참’으로 판단합니다.\n * 옵션\n 날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후\n 지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북\n 날씨: 맑음, 구름조금, 구름많음, 흐림, 비, 진눈깨비, 눈', check_finedust: '\n선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.\n * 옵션\n 지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북\n 미세먼지 등급: 좋음, 보통, 나쁨, 매우나쁨', get_weather_data: '\n선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.\n * 옵션\n 날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후\n 지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북\n 정보: 최저기온(℃), 최고기온(℃), 습도(%), 강수량(mm), 강수확률(%), 풍속(m/s)', get_current_weather_data: '\n현재 선택한 지역의 날씨 정보값(기온, 미세먼지농도)입니다.\n * 옵션\n 지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북\n 정보: (기온(℃)), 미세먼지농도(㎍)', get_today_temperature: '\n오늘 선택한 지역과 시간대의 기온을 의미합니다.\n * 옵션\n 지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북\n 시간대: 00, 03, 06, 09, 12, 15, 18, 21', check_city_weather: '선택한 날짜와 지역의 날씨 정보를 실제 날씨 상태와 비교하여 일치하는 경우 ‘참’으로 판단합니다.\n* 옵션\n날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후\n시도: 서울, 강원, 경기, 경남, 경북 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n날씨: 맑음, 구름조금, 구름많음, 흐림, 비, 진눈깨비, 눈', check_city_finedust: '선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.\n* 옵션\n시도: 서울, 강원, 경기, 경남, 경북,광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n미세먼지 등급: 좋음, 보통, 나쁨, 매우나쁨', get_city_weather_data: '선택한 날짜와 지역의 각종 날씨 정보입니다.\n *옵션\n날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후\n시도:서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n정보: 최저기온(℃), 최고기온(℃), 습도(%), 강수량(mm), 강수확률(%), 풍속(m/s)', get_current_city_weather_data: '현재 선택한 지역의 날씨 정보입니다.\n*옵션\n시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n정보: 기온(℃), 미세먼지농도(㎍)', get_today_city_temperature: '오늘 선택한 지역과 시간대의 기온입니다.\n*옵션\n시도: 서울, 강원, 경기, 경남, 경북 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n시군구: 시도별로 다름\n시간대: 00, 03, 06, 09, 12, 15, 18, 21', get_cur_weather: '\n선택한 지역의 현재 날씨입니다.', get_cur_wind: '\n선택한 지역의 현재 풍향입니다.', get_cur_weather_data: '\n선택한 지역의 현재 기상 정보입니다.\n- 기상 정보: 기온(℃), 미세먼지농도(PM10, ㎍)', check_cur_weather: "\n선택한 지역의 현재 날씨가 선택한 날씨와 같다면 '참'으로 판단합니다.", check_cur_finddust: '\n선택한 지역의 현재 미세먼지 등급이 선택한 미세먼지 등급과 같다면 ‘참’으로 판단합니다.', get_day_weather: '\n선택한 지역의 일별 날씨입니다.', get_day_weather_data: '\n선택한 지역의 일별 기상 정보입니다.\n- 기상 정보: 최저기온(℃), 최고기온(℃), 습도(%), 강수량(mm), 강수확률(%), 풍속(m/s)', check_day_weather: "\n선택한 지역의 일별 날씨가 선택한 날씨와 같다면 '참'으로 판단합니다.", get_time_weather: '\n선택한 지역의 시간대별(3시간) 날씨입니다.', get_time_weather_data: '\n선택한 지역의 시간대별(3시간) 기상 정보입니다.\n- 기상 정보: 기온(°c), 습도(%), 강수량(mm), 강수확률(%), 풍속(m/s)', check_time_weather: "\n선택한 지역의 시간대별(3시간) 날씨가 선택한 날씨와 같다면 '참'으로 판단합니다.", count_festival: '선택한 날짜와 지역에서 열리는 행사의 수입니다.\n* 옵션 \n지역: 서울, 강원, 경기, 경남, 경북 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n행사일: 1~12월', get_festival_info: '선택한 날짜와 지역에서 열리는 행사에 대한 정보입니다.\n* 옵션 \n지역: 서울, 강원, 경기, 경남, 경북 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북 \n행사일: 1~12월 \n정보: 제목, 지역, 시작일, 종료일, 주소, 개요, 홈페이지', get_translated_string: '입력한 문자값을 선택한 언어로 번역합니다. 입력은 3000자까지 가능합니다.\n*번역 가능한 언어 \n - 한국어 → 영어, 중국어 간체, 중국어 번체, 베트남어, 스페인어, 인도네시아어, 태국어, 프랑스어\n - 영어 → 일본어, 프랑스어, 한국어\n - 중국어 간체, 중국어 번체, 베트남어, 스페인어, 인도네시아어, 태국어, 프랑스어 → 한국어\n - 일본어 →영어 \n - 프랑스어 → 영어', check_language: '입력된 문자값의 언어를 감지합니다. 입력은 문장 형태로 3000자까지 가능합니다.', count_disaster_behavior: '선택한 자연재해가 발생했을 때 해야할 행동요령의 수입니다.\n *옵션\n 자연재해: 태풍, 홍수, 호우, 강풍, 대설, 한파, 풍랑, 황사, 폭염, 가뭄, 지진, 해일, 산사태\n 상황: 자연재해에 따라 다름 ', get_disaster_behavior: '선택한 자연재해가 발생했을 때 해야하는 행동요령에 대한 정보입니다.\n *옵션\n 자연재해: 태풍, 홍수, 호우, 강풍, 대설, 한파, 풍랑, 황사, 폭염, 가뭄, 지진, 해일, 산사태\n 상황: 자연재해에 따라 다름', count_lifeSafety_behavior: '선택한 생활 속 문제가 발생했을 때 해야할 행동요령의 수입니다.\n *옵션\n 생활 속 문제: 응급처치, 심폐소생술, 소화기·소화전 사용법, 식중독, 산행안전, 실종유괴, 성폭력, 학교폭력, 가정 폭력, 억류 및 납치, 교통사고, 승강기 안전사고, 미세먼지\n 상황: 생활 속 문제에 따라 다름 ', get_lifeSafety_behavior: '선택한 생활 속 문제가 발생했을 때 해야할 행동요령에 대한 정보입니다.\n *옵션\n 생활 속 문제: 응급처치, 심폐소생술, 소화기·소화전 사용법, 식중독, 산행안전, 실종유괴, 성폭력, 학교폭력, 가정 폭력, 억류 및 납치, 교통사고, 승강기 안전사고, 미세먼지\n 상황: 생활 속 문제에 따라 다름 ', count_disaster_guideline: '선택한 자연재난과 진행 정도에 따른 행동요령의 수입니다.\n\n- 자연재난: 태풍, 홍수, 호우, 강풍, 대설, 한파, 풍랑, 황사, 폭염, 가뭄, 지진, 지진해일, 해일, 산사태, 화산폭발', get_disaster_guideline: '선택한 자연재난과 진행 정도에 따른 행동요령의 내용입니다.\n\n- 자연재난: 태풍, 홍수, 호우, 강풍, 대설, 한파, 풍랑, 황사, 폭염, 가뭄, 지진, 지진해일, 해일, 산사태, 화산폭발', count_social_disaster_guideline: '선택한 사회재난과 진행 정도에 따른 행동요령의 수입니다.\n\n- 사회재난: 해양오염, 대규모 수질오염, 식용수, 공동구 재난, 가축질병, 감염병, 철도·지하철, 금융전산, 원전사고, 화학물질, 화재, 산불, 건축물 붕괴, 댐 붕괴, 폭발, 항공기, 화생방, 정전 및 전력부족, 전기·가스, 유도선, 수난사고, 테러, 전력수급', get_social_disaster_guideline: '선택한 사회재난과 진행 정도에 따른 행동요령의 내용입니다.\n\n- 사회재난: 해양오염, 대규모 수질오염, 식용수, 공동구 재난, 가축질병, 감염병, 철도·지하철, 금융전산, 원전사고, 화학물질, 화재, 산불, 건축물 붕괴, 댐 붕괴, 폭발, 항공기, 화생방, 정전 및 전력부족, 전기·가스, 유도선, 수난사고, 테러, 전력수급', count_safety_accident_guideline: '"선택한 생활 안전 사고가 발생했을 때 해야할 행동요령의 수입니다.\n\n- 생활안전 사고: 응급처치, 심폐소생술, 소화기, 식중독, 산행, 어린이 놀이시설, 실종유괴, 성폭력, 학교 폭력, 가정 폭력, 억류 및 납치, 교통사고, 승강기, 미세먼지, 소화전, 가정 안전점검"', get_safety_accident_guideline: '응급처치, 심폐소생술, 소화기, 식중독, 산행, 어린이 놀이시설, 실종유괴, 성폭력, 학교 폭력, 가정 폭력, 억류 및 납치, 교통사고, 승강기, 미세먼지, 소화전, 가정 안전점검', read_text: '입력한 문자값을 설정된 목소리로 읽습니다.\n입력은 2500자까지 가능합니다.\n인터넷에 연결되어 있지 않거나 인터넷 환경이 불안할 경우, 해당 블록이 실행되지 않고 다음 블록으로 넘어갈 수 있습니다.', set_tts_property: '선택한 목소리가 선택한 속도와 선택한 음높이로 설정됩니다.', read_text_wait_with_block: '입력한 문자값을 읽어준 후 다음 블록을 실행합니다.', check_microphone: "컴퓨터에 마이크가 연결되어 있는 경우 '참'으로 판단합니다.", speech_to_text_convert: '마이크를 통해 녹음된 음성을 인식합니다.', timed_speech_to_text_convert: '입력한 시간 동안 마이크를 통해 녹음된 음성을 선택한 언어로 인식합니다.', set_visible_speech_to_text: '인식한 음성을 실행 화면에 보이게 하거나 숨깁니다.', speech_to_text_get_value: '사람의 목소리를 문자로 변환한 값입니다. 목소리가 입력되지 않거나, 음성 인식 도중 오류가 발생한 경우 null 값을 반환합니다.', get_microphone_volume: '마이크에 입력되는 소리의 크기 값입니다.', video_draw_webcam: '컴퓨터에 연결된 카메라에 촬영되는 화면을 실행화면에서 보이게하거나 숨깁니다.(IE 및 iOS 미지원)', video_check_webcam: "컴퓨터에 카메라가 연결되어 있는 경우 '참'으로 판단합니다. (IE 및 iOS 미지원)", video_change_cam: '촬영하는 카메라를 변경합니다.', video_set_camera_opacity_option: '촬영되는 화면의 투명도 효과를 입력한 값으로 정합니다. 0~100 사이의 범위로 설정할 수 있습니다. (0 이하는 0으로 100 이상은 100으로 처리됩니다.) (IE 및 iOS 미지원)', video_flip_camera: '촬영되는 화면을 좌우 혹은 상하로 뒤집습니다. (IE 및 iOS 미지원)', video_toggle_model: '선택한 인식 모델을 동작시키거나 중지시킵니다. (사람 인식: 사람의 몸을 인식하여 각 신체부위의 위치 등을 알 수 있습니다. 얼굴 인식: 사람의 얼굴을 인식하여 눈, 코, 입, 귀의 위치나 예상되는 성별, 나이, 감정을 알 수 있습니다. 사물 인식: 인식된 사물의 종류를 알 수 있습니다) (IE 및 iOS 미지원)', video_toggle_ind: '인식된 사람/얼굴/사물의 위치와 순서를 실행화면에 보이게 하거나 숨깁니다. (IE 및 iOS 미지원)', video_number_detect: '인식된 사람/얼굴/사물의 개수입니다. (인식 가능 객체: 사람, 자전거, 자동차, 오토바이, 비행기, 버스, 기차, 트럭, 보트,교통 신호등, 소화전, 정지 신호, 주차 미터, 벤치, 새, 고양이, 개, 말, 양, 암소, 코끼리, 곰, 얼룩말, 기린, 책가방, 우산, 핸드백, 넥타이, 가방, 프리스비, 스키, 스노보드, 스포츠 볼, 연, 야구 방망이, 야구 글러브, 스케이트 보드, 서핑 보드, 테니스 라켓, 병, 와인 글라스, 컵, 포크, 나이프, 숟가락, 그릇, 바나나, 애플, 샌드위치, 주황색, 브로콜리, 당근, 핫도그, 피자, 도넛, 케이크, 의자, 소파, 화분, 침대, 식사테이블, 화장실, TV 모니터, 노트북, 마우스, 원격, 키보드, 휴대 전화, 전자 레인지, 오븐, 토스터기, 싱크대, 냉장고, 도서, 시계, 꽃병, 가위, 테디베어, 헤어드라이어, 칫솔) (IE 및 iOS 미지원)', video_object_detected: "선택한 사물이 인식된 경우 '참'으로 판단합니다. (IE 및 iOS 미지원)", video_is_model_loaded: "사람/얼굴/사물 인식이 된 경우 '참'으로 판단합니다. (IE 및 iOS 미지원)", video_detected_face_info: '입력한 순서의 얼굴의 성별/나이/감정의 추정값입니다. 인식이 잘 되지 않는 경우 무조건 0으로 출력됩니다. (IE 및 iOS 미지원)', video_motion_value: '선택한 오브젝트 혹은 실행화면 위에서 감지되는 움직임 혹은 방향 값입니다. (움직임: 움직임이 크고 빠를 수록 값이 커집니다. 방향: 오른쪽 혹은 위쪽으로 움직일 때 양수, 왼쪽 혹은 아래쪽으로 움직일 때 음수가 됩니다.) (IE 및 iOS 미지원)', video_face_part_coord: '입력한 순서의 얼굴 중 선택된 얼굴 부위의 위치값입니다. 인식이 잘 되지 않는 경우 무조건 0으로 출력됩니다. (왼쪽 눈, 오른쪽 눈, 코, 왼쪽 입꼬리, 오른쪽 입꼬리, 윗 입술, 아랫 입술) (IE 및 iOS 미지원)', video_body_part_coord: '입력한 순서의 사람의 선택한 신체 부위의 위치값입니다. (얼굴, 목, 왼쪽 어깨, 왼쪽 팔꿈치, 왼쪽 손목, 왼쪽 엉덩이, 왼쪽 무릎, 왼쪽 발목, 오른쪽 어깨, 오른쪽 팔꿈치, 오른쪽 손목, 오른쪽 엉덩이, 오른쪽 무릎, 오른쪽 발목) (IE 및 iOS 미지원)', append_row_to_table: '선택한 테이블의 마지막에 행(열)을 추가합니다. 추가된 행(열)의 모든 셀 값은 0입니다.', insert_row_to_table: '선택한 테이블의 입력한 순서에 행(열)을 추가합니다. 추가된 행(열)의 모든 셀 값은 0입니다. 추가된 행(열) 뒤에 있는 행(열)들은 순서가 하나씩 밀립니다.', delete_row_from_table: '선택한 테이블의 입력한 순서에 있는 행(열)을 삭제합니다.', set_value_from_table: '선택한 테이블에서 입력한 행의 속성을 입력한 값으로 바꿉니다.', save_current_table: '테이블을 현재 상태로 남깁니다. 작품을 정지해도 테이블에서 변경된 내용이 유지됩니다.', get_table_count: '선택한 테이블의 행(열) 개수입니다.', get_value_from_table: '선택한 테이블에서 입력한 행의 속성 값입니다.\n속성 값 블록 대신 (열을 의미하는) 값 블록을 결합해 사용할 수도 있습니다.', get_value_from_last_row: '선택한 테이블에서 마지막 행의 선택한 속성 값입니다.\n속성 값 블록 대신 (열을 의미하는) 값 블록을 결합해 사용할 수도 있습니다.', calc_values_from_table: '선택한 테이블에서 선택한 속성들에 대한 요약통계량입니다. (합, 최댓값, 최솟값, 평균값, 표준편차, 중앙값)', open_table: '선택한 테이블의 테이블 창을 엽니다.', open_table_wait: '입력한 시간 동안 선택한 테이블의 테이블 창을 엽니다.', open_table_chart: '선택한 테이블의 차트 창을 엽니다.', close_table_chart: '열려있는 테이블 차트 창을 닫습니다.', get_coefficient: '선택한 테이블에서 두 속성 사이의 상관계수입니다. 상관계수가 1(-1)에 가까울 수록 강한 양(음)의 선형 상관관계를 갖습니다.', set_value_from_cell: '테이블에서 선택한 셀을 입력한 값으로 바꿉니다.', get_value_from_cell: '테이블에서 선택한 셀의 값입니다.', get_value_v_lookup: '테이블에서 선택한 열이 특정한 값인 행을 찾고, 그 행의 다른 열 값을 반환합니다.', insert_data_for_test: '데이터를 입력하고 학습한 모델로 인식합니다.', insert_text_block_for_test: '데이터를 입력하고 학습한 모델로 인식합니다.', test_result: '입력한 데이터를 모델에서 인식한 결과 값입니다. 값은 모델의 클래스 이름(텍스트)으로 표현됩니다.', accuracy_of_result: '입력한 데이터의 선택한 클래스에 대한 신뢰도 값입니다. 값은 확률(숫자)로 표현됩니다.', is_group: "입력한 데이터의 인식 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", retrain_model: '모델을 다시 학습합니다. 모델 설정을 변경하거나, 입력 데이터가 되는 테이블의 내용을 수정했다면, 변경된 내용을 바탕으로 모델을 다시 학습합니다.', model_is_trained: "모델이 학습되었다면 '참'을, 학습 중이거나 학습되지 않았다면 '거짓'으로 판단합니다.", set_train_visible: '모델의 상태를 표시하는 창을 실행 화면에 보이게 하거나 숨깁니다.', set_train_chart: '입력한 데이터와 학습한 모델의 군집을 2차원 좌표평면에 나타낸 차트 창을 열거나 닫습니다. ', set_regression_option: "모델의 학습 조건을 변경합니다. 변경한 학습 조건은 '모델 다시 학습하기' 블록으로 모델을 다시 학습할 때부터 적용됩니다.", get_regression_predict_1: '입력한 핵심 속성으로 모델이 예측한 값을 반환합니다.', get_regression_predict_2: '입력한 핵심 속성으로 모델이 예측한 값을 반환합니다.', get_regression_predict_3: '입력한 핵심 속성으로 모델이 예측한 값을 반환합니다.', get_regression_predict_4: '입력한 핵심 속성으로 모델이 예측한 값을 반환합니다.', get_regression_predict_5: '입력한 핵심 속성으로 모델이 예측한 값을 반환합니다.', get_regression_predict_6: '입력한 핵심 속성으로 모델이 예측한 값을 반환합니다.', get_regression_accuracy: '모델의 결정계수를 값으로 반환합니다.', set_logistic_regression_option: "모델의 학습 조건을 변경합니다. 변경한 학습 조건은 '모델 다시 학습하기' 블록으로 모델을 다시 학습할 때부터 적용됩니다.", set_logistic_regression_optimizer: "모델의 최적화 알고리즘을 변경합니다. 변경한 최적화 알고리즘은 '모델 다시 학습하기' 블록으로 모델을 다시 학습할 때부터 적용됩니다.", get_logistic_regression_probability_1: '입력한 데이터의 선택한 클래스에 대한 확률 값입니다. 값은 숫자로 표현됩니다.', get_logistic_regression_probability_2: '입력한 데이터의 선택한 클래스에 대한 확률 값입니다. 값은 숫자로 표현됩니다.', get_logistic_regression_probability_3: '입력한 데이터의 선택한 클래스에 대한 확률 값입니다. 값은 숫자로 표현됩니다.', get_logistic_regression_probability_4: '입력한 데이터의 선택한 클래스에 대한 확률 값입니다. 값은 숫자로 표현됩니다.', get_logistic_regression_probability_5: '입력한 데이터의 선택한 클래스에 대한 확률 값입니다. 값은 숫자로 표현됩니다.', get_logistic_regression_probability_6: '입력한 데이터의 선택한 클래스에 대한 확률 값입니다. 값은 숫자로 표현됩니다.', set_decisiontree_option: "모델의 학습 조건을 변경합니다. 변경한 학습 조건은 '모델 다시 학습하기' 블록으로 모델을 다시 학습할 때부터 적용됩니다.", set_decisiontree_tree: '학습한 결정 트리를 나타낸 창을 열거나 닫습니다.', set_svm_option: "모델의 학습 조건을 변경합니다. 변경한 학습 조건은 '모델 다시 학습하기' 블록으로 모델을 다시 학습할 때부터 적용됩니다.", set_kernel_linear: "학습 조건 중 커널을 선형으로 변경합니다. 변경한 학습 조건은 '모델 다시 학습하기' 블록으로 모델을 다시 학습할 때부터 적용됩니다.", set_kernel_option: "학습 조건 중 커널을 다항식 또는 RBF로 변경합니다. 변경한 학습 조건은 '모델 다시 학습하기' 블록으로 모델을 다시 학습할 때부터 적용됩니다.", is_result_1: "입력한 데이터의 분류 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", is_result_2: "입력한 데이터의 분류 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", is_result_3: "입력한 데이터의 분류 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", is_result_4: "입력한 데이터의 분류 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", is_result_5: "입력한 데이터의 분류 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", is_result_6: "입력한 데이터의 분류 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", get_predict_1: '입력한 데이터를 모델에서 분류한 값입니다. 값은 클래스 이름(텍스트)으로 표현됩니다.', get_predict_2: '입력한 데이터를 모델에서 분류한 값입니다. 값은 클래스 이름(텍스트)으로 표현됩니다.', get_predict_3: '입력한 데이터를 모델에서 분류한 값입니다. 값은 클래스 이름(텍스트)으로 표현됩니다.', get_predict_4: '입력한 데이터를 모델에서 분류한 값입니다. 값은 클래스 이름(텍스트)으로 표현됩니다.', get_predict_5: '입력한 데이터를 모델에서 분류한 값입니다. 값은 클래스 이름(텍스트)으로 표현됩니다.', get_predict_6: '입력한 데이터를 모델에서 분류한 값입니다. 값은 클래스 이름(텍스트)으로 표현됩니다.', get_result_info: '모델의 성능 평가 지표를 값으로 반환합니다.', set_cluster_option_k: "군집의 개수를 입력한 값으로 바꾸어 설정합니다. 변경한 군집 개수는 '모델 다시 학습하기' 블록으로 모델을 다시 학습할 때부터 적용됩니다.", set_cluster_option_centroids: "군집의 최초 중심점 기준을 선택한 기준으로 바꿉니다. 변경한 중심점 기준은 '모델 다시 학습하기' 블록으로 모델을 다시 학습할 때부터 적용됩니다.", get_cluster_centriod_count: '모델의 군집 개수를 값으로 반환합니다. ', get_cluster_centriod_value: '지정한 군집의 중심점에 대한 핵심 속성을 반환합니다. 핵심 속성이 여러 개인 경우, 목록 상자에서 핵심 속성을 선택할 수 있습니다.', get_cluster_centriod_index_1: '입력한 핵심 속성이 모델이 묶은 군집 중에 어느 군집에 속하는지를 반환합니다. 값은 텍스트(군집 이름)로 표현됩니다.', get_cluster_centriod_index_2: '입력한 핵심 속성이 모델이 묶은 군집 중에 어느 군집에 속하는지를 반환합니다. 값은 텍스트(군집 이름)로 표현됩니다.', get_cluster_centriod_index_3: '입력한 핵심 속성이 모델이 묶은 군집 중에 어느 군집에 속하는지를 반환합니다. 값은 텍스트(군집 이름)로 표현됩니다.', get_cluster_centriod_index_4: '입력한 핵심 속성이 모델이 묶은 군집 중에 어느 군집에 속하는지를 반환합니다. 값은 텍스트(군집 이름)로 표현됩니다.', get_cluster_centriod_index_5: '입력한 핵심 속성이 모델이 묶은 군집 중에 어느 군집에 속하는지를 반환합니다. 값은 텍스트(군집 이름)로 표현됩니다.', get_cluster_centriod_index_6: '입력한 핵심 속성이 모델이 묶은 군집 중에 어느 군집에 속하는지를 반환합니다. 값은 텍스트(군집 이름)로 표현됩니다.', set_number_learning_option_k: "이웃 개수를 입력한 값으로 바꾸어 설정합니다. 변경한 이웃 개수는 '모델 다시 학습하기' 블록으로 모델을 다시 학습할 때부터 적용됩니다.", get_number_learning_predict_1: '입력한 데이터를 모델에서 분류한 값입니다. 값은 모델의 클래스 이름(텍스트)으로 표현됩니다.', get_number_learning_predict_2: '입력한 데이터를 모델에서 분류한 값입니다. 값은 모델의 클래스 이름(텍스트)으로 표현됩니다.', get_number_learning_predict_3: '입력한 데이터를 모델에서 분류한 값입니다. 값은 모델의 클래스 이름(텍스트)으로 표현됩니다.', get_number_learning_predict_4: '입력한 데이터를 모델에서 분류한 값입니다. 값은 모델의 클래스 이름(텍스트)으로 표현됩니다.', get_number_learning_predict_5: '입력한 데이터를 모델에서 분류한 값입니다. 값은 모델의 클래스 이름(텍스트)으로 표현됩니다.', get_number_learning_predict_6: '입력한 데이터를 모델에서 분류한 값입니다. 값은 모델의 클래스 이름(텍스트)으로 표현됩니다.', get_number_learning_predict_param_1: '입력한 데이터의 선택한 클래스에 대한 분류 신뢰도 값입니다. 값은 숫자로 표현됩니다.', get_number_learning_predict_param_2: '입력한 데이터의 선택한 클래스에 대한 분류 신뢰도 값입니다. 값은 숫자로 표현됩니다.', get_number_learning_predict_param_3: '입력한 데이터의 선택한 클래스에 대한 분류 신뢰도 값입니다. 값은 숫자로 표현됩니다.', get_number_learning_predict_param_4: '입력한 데이터의 선택한 클래스에 대한 분류 신뢰도 값입니다. 값은 숫자로 표현됩니다.', get_number_learning_predict_param_5: '입력한 데이터의 선택한 클래스에 대한 분류 신뢰도 값입니다. 값은 숫자로 표현됩니다.', get_number_learning_predict_param_6: '입력한 데이터의 선택한 클래스에 대한 분류 신뢰도 값입니다. 값은 숫자로 표현됩니다.', is_number_learning_group_1: "입력한 데이터의 분류 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", is_number_learning_group_2: "입력한 데이터의 분류 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", is_number_learning_group_3: "입력한 데이터의 분류 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", is_number_learning_group_4: "입력한 데이터의 분류 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", is_number_learning_group_5: "입력한 데이터의 분류 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", is_number_learning_group_6: "입력한 데이터의 분류 결과가 선택한 클래스인 경우 '참'으로 판단합니다.", bitbrick_when_button_pressed: '비트브릭 버튼을 누르면 아래에 연결된 블록들을 실행합니다.', bitbrick_when_sensor_get_value: '비트브릭 센서의 값과 오른쪽에 입력한 값을 비교합니다.\n< : 센서 값이 오른쪽에 위치한 값보다 작은 경우 ‘참’으로 판단합니다.\n> : 센서 값이 오른쪽에 위치한 값보다 큰 경우 ‘참으로 판단합니다.\n= : 센서 값이 오른쪽에 위치한 값과 같은 경우 ‘참으로 판단합니다.', bitbrick_sensor_value: '비트브릭 센서를 사용할 수 있는 블록입니다. 센서값의 범위는 0 ~1023입니다. 메인보드에 연결된 센서의 종류와 포트번호를 자동으로 인식합니다. 블록 안의 화살표를 눌러 사용하려고 하는 센서를 선택하세요.', bitbrick_convert_scale: '비트브릭 센서의 값의 범위를 바꿀 수 있습니다.', bitbrick_is_touch_pressed: '비트브릭 센서 중 버튼을 눌렀을 경우 ‘참’으로 판단합니다.', bitbrick_is_sensor_value_compare: '비트브릭 센서 중 버튼을 눌렀을 경우 ‘참’으로 판단합니다.', bitbrick_turn_off_color_led: '비트브릭 엘이디를 끕니다.', bitbrick_turn_on_color_led_by_rgb: '비트브릭 엘이디를 빛의 삼원색인 빨강,초록,파랑을 혼합하여 켭니다. 값의 범위는 0 ~ 255입니다.', bitbrick_turn_on_color_led_by_picker: '비트브릭 엘이디를 색상 창을 사용해 켭니다.', bitbrick_turn_on_color_led_by_value: '비트브릭 엘이디를 색상 값으로 켭니다. 값의 범위는 0 ~ 199입니다.', bitbrick_buzzer: '비트브릭 버저를 사용하여 소리를 냅니다. 값의 범위는 0 ~ 96입니다. 값이 0일 때는 버저 소리를 끕니다.', bitbrick_turn_off_all_motors: '비트브릭 모터를 모두 끕니다.', bitbrick_dc_speed: '비트브릭 디씨모터의 속도를 제어합니다. 속도 값의 범위는 –100 ~ 100입니다. 음수(-)일 때는 반시계방향으로 회전합니다. 양수(+)일 때는 시계방향으로 회전합니다. 속도가 0일 때는 회전을 멈춥니다.', bitbrick_dc_direction_speed: '비트브릭 디씨모터의 방향과 속력을 제어합니다. 방향은 시계방향과 반시계방향을 선택할 수 있습니다. 속력 값의 범위는 0 ~ 100입니다. 속력이 0일 때는 회전을 멈춥니다.', bitbrick_servomotor_angle: '비트브릭 서보모터의 각도를 제어합니다. 각도 값의 범위는 0 ~ 180입니다.', diaboard_when_button_pressed: '선택한 버튼을 누르거나 누르지 않으면 아래에 연결된 블록들을 실행합니다.', diaboard_when_color_is: '선택한 색상을 컬러센서가 감지하면 아래에 연결된 블록들을 실행합니다.', diaboard_when_sensor_is: "선택한 센서의 값과 오른쪽의 값을 비교하여 아래에 연결된 블록들을 실행합니다.\n< : 센서값이 오른쪽 값보다 작은 경우 '참'으로 판단합니다.\n> : 센서값이 오른쪽 값보다 큰 경우 '참'으로 판단합니다.\n= : 센서값이 오른쪽 값과 같은 경우 '참'으로 판단합니다.", diaboard_button_pressed: "선택한 버튼을 누르거나 누르지 않은 경우 '참'으로 판단합니다.", diaboard_color_sensor_is: "선택한 색상을 컬러센서가 감지한 경우 '참'으로 판단합니다.", diaboard_sensor_condition: "선택한 센서의 값과 오른쪽의 값을 비교합니다.\n< : 센서값이 오른쪽 값보다 작은 경우 '참'으로 판단합니다.\n> : 센서값이 오른쪽 값보다 큰 경우 '참'으로 판단합니다.\n= : 센서값이 오른쪽 값과 같은 경우 '참'으로 판단합니다.", diaboard_color_sensor_seven_hue: '컬러센서가 감지하는 색상을 7가지로 분류한 값입니다.\n7가지 색상 : 빨강, 노랑, 녹색, 청록, 파랑, 보라, 하양', diaboard_color_sensor_one_hue: '컬러센서가 감지한 색상값입니다.\n색상(hue) : 0 ~ 359 사이 범위로 설정할 수 있습니다.\n(총 360가지의 색상을 감지하며 360과 0은 같은 색으로 표현됩니다.)', diaboard_sensor_value: '선택한 센서가 감지한 값입니다. 값의 범위는 0 ~ 1023입니다. \n적외선 센서 : 물체에 반사된 적외선을 양을 측정하여 물체와의 거리를 감지합니다.\n밝기 센서 : 주변 환경이 얼마나 밝고 어두운지를 감지합니다.', diaboard_convert_scale: '선택한 센서가 감지한 값의 범위를 사용자가 임의로 바꿔서 사용합니다.\n적외선 센서 : 물체에 반사된 적외선을 양을 측정하여 물체와의 거리를 감지합니다.\n밝기 센서 : 주변 환경이 얼마나 밝고 어두운지를 감지합니다.', diaboard_led_rainbow: '엘이디를 무지개 효과로 켭니다.', diaboard_led_rainbow_time: '엘이디를 입력한 시간만큼 무지개 효과로 켭니다.\n시간 : 0 ~ 100 범위에서 0.1초 단위로 설정할 수 있습니다.', diaboard_led_effect: '엘이디를 선택한 효과와 선택한 색상으로 켭니다.', diaboard_led_effect_time: '엘이디를 입력한 시간만큼 선택한 효과와 선택한 색상으로 켭니다.\n시간 : 0 ~ 100 범위에서 0.1초 단위로 설정할 수 있습니다.', diaboard_led_six: '엘이디 1번 ~ 6번을 선택한 색상으로 각자 켭니다.', diaboard_led_one: '선택한 번호의 엘이디를 선택한 색상으로 켭니다.', diaboard_led_one_time: '선택한 번호의 엘이디를 입력한 시간만큼 선택한 색상으로 켭니다.\n시간 : 0 ~ 100 범위에서 0.1초 단위로 설정할 수 있습니다.', diaboard_led_hue: '선택한 번호의 엘이디를 색상(hue)값으로 켭니다.\n색상( hue) : 0 ~ 359 사이 범위로 설정할 수 있습니다.\n(총 360가지의 색상을 감지하며 360과 0은 같은 색으로 표현됩니다.)', diaboard_led_color: "선택한 번호의 엘이디를 현재 컬러센서가 감지한 색상(7가지)으로 켭니다. 컬러센서 색상이 '없음'일 때는 코드를 실행해도 엘이디를 켜지 않습니다.\n7가지 색상 : 빨강, 노랑, 녹색, 청록, 파랑, 보라, 하양", diaboard_led_rgb: '선택한 번호의 엘이디를 빨강, 녹색, 파랑값으로 켭니다.\n빨강, 녹색, 파랑 : 0 ~ 255의 범위로 설정할 수 있습니다.\n(0이하는 0으로, 255이상은 255로 처리됩니다. )', diaboard_led_turn_off_all: '선택한 번호의 엘이디를 끕니다.', diaboard_servomotor_angle: '선택한 포트의 서보모터의 각도를 입력한 값으로 정합니다.\n각도 : 0 ~ 180 사이 범위로 설정할 수 있습니다.\n(0이하는 0으로, 180이상은 180으로 처리됩니다.)', diaboard_servomotor_angle_time: '선택한 포트의 서보모터의 초기각도와 목표각도를 설정해 입력한 시간만큼 각도를 바꿉니다.\n각도 : 0 ~ 180 사이 범위로 설정할 수 있습니다.\n(0이하는 0으로, 180이상은 180으로 처리됩니다.)\n시간 : 0 ~ 100 범위에서 0.1초 단위로 설정할 수 있습니다.', diaboard_dc_direction_speed: '선택한 포트의 디씨모터의 방향과 속력을 정합니다.\n방향 : 시계방향과 반시계 방향을 설정할 수 있습니다.\n속력 : 0 ~ 100까지 범위로 설정할 수 있습니다.\n(0이하는 0으로, 100이상은 100으로 처리됩니다.)', diaboard_dc_direction_speed_time: '선택한 포트의 디씨모터의 방향과 속력을 정하고, 입력한 시간만큼 동작합니다.\n방향 : 시계방향과 반시계 방향을 설정할 수 있습니다.\n속력 : 0 ~ 100까지 범위로 설정할 수 있습니다.\n(0이하는 0으로, 100이상은 100으로 처리됩니다.)\n시간 : 0 ~ 100 범위에서 0.1초 단위로 설정할 수 있습니다.', diaboard_dc_speed: '선택한 포트의 디씨모터의 속도를 정합니다.\n속도 : -100 ~ 100 사이의 범위로 설정할 수 있습니다.\n(-100이하는 -100으로, 100이상은 100으로 처리됩니다.)', diaboard_dc_speed_time: '선택한 포트의 디씨모터의 속도를 정하고, 입력한 시간만큼 동작합니다.\n속도 : -100 ~ 100 사이의 범위로 설정할 수 있습니다.\n(-100이하는 -100으로, 100이상은 100으로 처리됩니다.)\n시간 : 0 ~ 100 범위에서 0.1초 단위로 설정할 수 있습니다.', diaboard_turn_off_all_motors: '선택한 포트의 모터를 멈춥니다.', diaboard_buzzer_melody_type: '선택한 멜로디를 연주합니다.', diaboard_buzzer_effect_type: '선택한 효과음을 냅니다.', diaboard_buzzer_eight_melody_bpm: '선택한 음들을 입력한 BPM으로 연주합니다.\n연주속도(BPM) : 30 ~ 300 사이의 범위로 설정할 수 있습니다.\n(30이하는 30으로, 300이상은 300으로 처리됩니다.)', diaboard_buzzer_octave: '선택한 옥타브와 음으로 연주합니다.', diaboard_buzzer_octave_rhythm: '선택한 옥타브와 음을 입력한 박자로 연주합니다.', diaboard_buzzer_hz: '입력한 주파수로 연주합니다.\n주파수 : 33 ~ 7,900 사이의 범위로 설정할 수 있습니다.\n(33이하는 33으로 7,900이상은 7,900으로 처리됩니다.)', diaboard_buzzer_hz_change: '입력한 주파수만큼 바꿔서 연주합니다.', diaboard_buzzer_speed_bpm: '입력한 BPM으로 연주 속도를 정합니다.\n연주속도(BPM) : 30 ~ 300 사이의 범위로 설정할 수 있습니다.\n(30이하는 30으로, 300이상은 300으로 처리됩니다.)', diaboard_buzzer_speed_bpm_change: '입력한 BPM만큼 연주 속도를 바꿉니다.', diaboard_buzzer_sleep_rhythm: '선택한 박자만큼 쉽니다.', diaboard_buzzer_stop: '버저음을 멈춥니다.', change_rgb_to_hex: '입력한 빨강(R), 초록(G), 파랑(B) 값을 HEX 값으로 변환한 값입니다.', change_hex_to_rgb: '입력한 HEX 값을 빨강(R), 초록(G), 파랑(B) 중 하나로 변환한 값입니다.', media_pipe_video_screen: '연결된 카메라가 촬영하는 것을 실행 화면에서 보이게 하거나 숨깁니다.\n(기본값으로 50%의 투명도가 적용되어 있습니다.)', media_pipe_switch_camera: '촬영하는 카메라를 변경합니다.', check_connected_camera: "컴퓨터에 카메라가 연결되어 있는 경우 '참'으로 판단합니다.", media_pipe_flip_camera: '촬영되는 화면을 좌우 혹은 상하로 뒤집습니다.', media_pipe_set_opacity_camera: '촬영되는 화면의 투명도 효과를 입력한 값으로 정합니다. 0~100 사이의 범위로 설정할 수 있습니다.\n(기본값은 50이며, 0 이하는 0으로 100 이상은 100으로 처리됩니다.)', media_pipe_motion_value: '선택한 오브젝트 혹은 실행 화면 위에서 감지되는 움직임 혹은 방향 값입니다.\n- 움직임: 움직임이 크고 빠를 수록 값이 커집니다.\n- 방향: 오른쪽 혹은 위쪽으로 움직일 때 양수, 왼쪽 혹은 아래쪽으로 움직일때 음수가 됩니다', when_pose_landmarker: '사람을 인식하면 아래에 연결된 블록들을 실행합니다.', pose_landmarker: '사람 인식을 시작하거나 중지합니다.\n- 사람 인식: 사람의 몸을 인식하여 각 신체 부위의 위치 등을 좌표로 반환할 수 있습니다.', draw_detected_pose: '인식한 사람의 형태를 실행 화면에 보이게 하거나 숨깁니다.', check_detected_pose: "사람이 인식된 경우 '참'으로 판단합니다.", count_detected_pose: '인식한 사람의 수입니다.', locate_to_pose: '오브젝트가 선택한 사람의 신체 부위로 이동합니다.\n(오브젝트의 중심점이 기준이 됩니다.)', locate_time_to_pose: '오브젝트가 입력한 시간에 걸쳐 선택한 사람의 신체 부위로 이동합니다.\n(오브젝트의 중심점이 기준이 됩니다.)', axis_detected_pose: '입력한 순서의 사람의 선택한 신체 부위의 위치값입니다. 인식이 되지 않은 경우 0을 반환합니다.\n(신체 부위: 코, 왼쪽 눈 안쪽, 왼쪽 눈, 왼쪽 눈 바깥쪽, 오른쪽 눈 안쪽, 오른쪽 눈, 오른쪽 눈 바깥쪽, 왼쪽 귀, 오른쪽 귀, 왼쪽 입꼬리, 오른쪽 입꼬리, 왼쪽 어깨, 오른쪽 어깨, 왼쪽 팔꿈치, 오른쪽 팔꿈치, 왼쪽 손목, 오른쪽 손목, 왼쪽 소지, 오른쪽 소지, 왼쪽 검지, 오른쪽 검지, 왼쪽 엄지, 오른쪽 엄지, 왼쪽 엉덩이, 오른쪽 엉덩이, 왼쪽 무릎, 오른쪽 무릎, 왼쪽 발목, 오른쪽 발목, 왼쪽 발꿈치, 오른쪽 발꿈치, 왼쪽 발끝, 오른쪽 발끝)', when_face_landmarker: '얼굴을 인식하면 아래에 연결된 블록들을 실행합니다.', face_landmarker: '얼굴 인식을 시작하거나 중지합니다.\n- 얼굴 인식: 사람의 얼굴을 인식하여 눈, 코, 입, 귀의 위치나 예상되는 성별, 나이, 감정을 알 수 있습니다.', draw_detected_face: '인식한 얼굴의 형태를 실행 화면에 보이게 하거나 숨깁니다.', check_detected_face: "얼굴이 인식된 경우 '참'으로 판단합니다.", count_detected_face: '인식한 얼굴의 수입니다.', locate_to_face: '오브젝트가 선택한 얼굴의 부위로 이동합니다.\n(오브젝트의 중심점이 기준이 됩니다.)', locate_time_to_face: '오브젝트가 입력한 시간에 걸쳐 선택한 얼굴의 부위로 이동합니다.\n(오브젝트의 중심점이 기준이 됩니다.)', check_detected_gender: "선택한 얼굴이 선택한 성별이면 '참'으로 판단합니다.", check_compare_age: "선택한 얼굴의 나이가 입력한 수식에 해당한다면 '참'으로 판단합니다.", check_detected_emotion: "선택한 얼굴이 선택한 감정이면 '참'으로 판단합니다.", axis_detected_face: '입력한 순서의 얼굴 중 선택된 얼굴 부위의 위치값입니다. 인식이 잘 되지 않은 경우 무조건 0으로 출력됩니다. (얼굴 부위: 왼쪽 눈, 오른쪽 눈, 코, 왼쪽 입꼬리, 오른쪽 입꼬리, 윗 입술, 아랫 입술)', get_detected_face_value: '입력한 순서의 얼굴의 성별/나이/감정의 추정값입니다. 인식이 잘 되지 않은 경우 null을 반환합니다.', when_object_detector: '사물을 인식하면 아래에 연결된 블록들을 실행합니다.', object_detector: '사물 인식을 시작하거나 중지합니다.\n- 사물 인식: 인식한 사물의 종류를 알 수 있습니다.', draw_detected_object: '인식한 사물의 위치와 순서를 실행 화면에 보이게 하거나 숨깁니다.', check_detected_object: "사물이 인식된 경우 '참'으로 판단합니다.", count_detected_object: '인식한 사물의 수입니다.', is_detected_among_objects: "선택한 사물이 인식된 경우 '참'으로 판단합니다.", when_hand_detection: '손을 인식하면 아래에 연결된 블록들을 실행합니다.', hand_detection: '손 인식을 시작하거나 중지합니다.\n- 손 인식: 사람의 손을 인식하여 오른손인지 왼손인지 또는 어떤 동작인지를 구분하거나, 각 부위를 인식해 좌표로 반환할 수 있습니다.', draw_detected_hand: '인식한 손의 형태를 실행 화면에 보이게 하거나 숨깁니다.', check_detected_hand: "손을 인식한 경우 '참'으로 판단합니다.", count_detected_hand: '인식한 손의 개수입니다.', locate_to_hand: '오브젝트가 선택한 손의 부위로 이동합니다.\n(오브젝트의 중심점이 기준이 됩니다.)\n\n가장 먼저 인식된 손이 1번째가 되며, 2개의 손이 한 번에 인식되면 왼쪽부터 1번째가 됩니다.', locate_time_to_hand: '오브젝트가 입력한 시간에 걸쳐 선택한 손의 부위로 이동합니다.\n(오브젝트의 중심점이 기준이 됩니다.)\n\n가장 먼저 인식된 손이 1번째가 되며, 2개의 손이 한 번에 인식되면 왼쪽부터 1번째가 됩니다.', axis_detected_hand: '입력한 순서의 손에서 선택한 부위의 위치 값입니다. 인식이 되지 않은 경우 0을 반환합니다.\n\n가장 먼저 인식된 손이 1번째가 되며, 2개의 손이 한 번에 인식되면 왼쪽부터 1번째가 됩니다.', is_which_hand: "입력한 순서의 손이 선택한 손이라면 '참'으로 판단합니다.", get_which_hand: '입력한 순서의 손이 오른손인지, 왼손인지를 반환합니다.', is_which_gesture: "입력한 순서의 손이 선택한 모양이라면 '참'으로 판단합니다.", get_which_gesture: '입력한 순서의 손이 어떤 모양인지를 반환합니다.', video_capture_for_image_test: '카메라를 통해 촬영된 이미지 데이터를 학습한 모델로 분류하거나 중지합니다.', train_param_kernel_polynomial: '', train_param_kernel_rbf: '', train_param_degree: '', train_param_gamma: '', target_project: '목표 작품 확인하기', study_goal: '학습 목표 확인하기', show_hint: '힌트보기', }; Lang.Category = { entrybot_friends: '엔트리봇 친구들', people: '사람', animal: '동물', animal_flying: '하늘', animal_land: '땅', animal_water: '물', animal_others: '기타', plant: '식물', plant_flower: '꽃', plant_grass: '풀', plant_tree: '나무', plant_others: '기타', vehicles: '탈것', vehicles_flying: '하늘', vehicles_land: '땅', vehicles_water: '물', vehicles_others: '기타', architect: '건물', architect_building: '건축물', architect_monument: '기념물', architect_others: '기타', food: '음식', food_vegetables: '과일/채소', food_meat: '고기', food_drink: '음료', food_others: '기타', environment: '환경', environment_nature: '자연', environment_space: '우주', environment_others: '기타', stuff: '물건', stuff_living: '생활', stuff_hobby: '취미', stuff_others: '기타', fantasy: '판타지', interface: '인터페이스', interface_website: '웹사이트', interface_game: '게임', interface_others: '기타', background: '배경', background_outdoor: '실외', background_indoor: '실내', background_nature: '자연', background_others: '기타', }; Lang.Device = { arduino: '아두이노', hamster: '햄스터', roboid: '로보이드', turtle: '거북이', albert: '알버트', robotis_carCont: '로보티즈 자동차 로봇', robotis_openCM70: '로보티즈 IoT', sensorBoard: '엔트리 센서보드', trueRobot: '뚜루뚜루', CODEino: '코드이노', bitbrick: '비트브릭', creamo: '크리모', playcode: '플레이코드', funboard: '펀보드', bitBlock: '비트블록', xbot_epor_edge: '엑스봇', dplay: '디플레이', iboard: '아이보드', nemoino: '네모이노', ev3: 'EV3', robotori: '로보토리', smartBoard: '스마트보드', chocopi: '초코파이보드', rokoboard: '로코보드', altino: '알티노', mechatro: '메카트로', }; Lang.General = { apply: '켜기', clear: ' 끄기', turn_on: '켜기', turn_off: '끄기', left: '왼쪽', right: '오른쪽', param_string: '문자값', both: '양쪽', transparent: '투명', black: '검은색', brown: '갈색', red: '빨간색', yellow: '노란색', green: '초록색', skyblue: '하늘색', blue: '파란색', purple: '보라색', white: '하얀색', note_c: '도', note_d: '레', note_e: '미', note_f: '파', note_g: '솔', note_a: '라', note_b: '시', questions: '문제', clock: '시계', counter_clock: '반시계', font_size: '글자 크기', second: '초', alert_title: '알림', confirm_title: '확인', update_title: '업데이트 알림', recent_download: '최신 버전 다운로드', recent_download2: '최신버전 다운로드', latest_version: '최신 버전입니다.', dont_show_again: '다시보지 않기', }; Lang.Fonts = { jeju_hallasan: '한라산체', gothic_coding: '코딩고딕체', batang: '바탕체', gothic: '나눔고딕', myeongjo: '나눔명조', pen_script: '나눔손글씨', square_round: '나눔스퀘어라운드', jalnan: '잘난체', designhouse: '디자인하우스체', malssami815: '말싸미815체', dunggeunmo: '둥근모꼴체', hs_bombaram: 'HS봄바람체', yisunshin: '이순신체', goyang: '고양체', flower_road: '꽃길체', uhbeemysen: '어비마이센체', sd_comic_stencil: '산돌 코믹스탠실', sd_childfundkorea: '산돌 초록우산 어린이', sd_cinema_theater: '산돌 씨네마극장', sd_mapssi: '산돌 맵씨', sd_shabang: '산돌 별이샤방샤방', sd_woodcarving: '산돌 목각', sd_yongbi: '산돌 용비어천가', maruburi: '마루 부리', nanumbarunpen: '나눔바른펜', notosans: '본고딕', d2coding: 'D2 Coding', }; Lang.Hw = { note: '음표', leftWheel: '왼쪽 바퀴', rightWheel: '오른쪽 바퀴', leftEye: '왼쪽 눈', rightEye: '오른쪽 눈', led: '불빛', led_en: 'LED', body: '몸통', front: '앞쪽', port_en: '', port_ko: '번 포트', sensor: '센서', light: '빛', temp: '온도', switch_: '스위치', right_ko: '오른쪽', right_en: '', left_ko: '왼쪽', left_en: '', up_ko: '위쪽', up_en: '', down_ko: '아래쪽', down_en: '', output: '출력', left: '왼쪽', right: '오른쪽', sub: '서보', motor: '모터', '': '', buzzer: '버저', IR: '적외선', acceleration: '가속', analog: '아날로그', angular_acceleration: '각가속', button: '버튼', humidity: '습도', joystick: '조이스틱', port: '포트', potentiometer: '포텐시오미터', servo: '서보', port_en: '', right_en: '', left_en: '', up_en: '', down_en: '', }; Lang.template = { albert_hand_found: '손 찾음?', albert_is_oid_value: ' %1 OID 값이 %2 인가? ', albert_value: '%1', albert_move_forward_for_secs: '앞으로 %1 초 이동하기 %2', albert_move_backward_for_secs: '뒤로 %1 초 이동하기 %2', albert_turn_for_secs: '%1 으로 %2 초 돌기 %3', albert_change_both_wheels_by: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 만큼 바꾸기 %3', albert_set_both_wheels_to: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 (으)로 정하기 %3', albert_change_wheel_by: '%1 바퀴 %2 만큼 바꾸기 %3', albert_set_wheel_to: '%1 바퀴 %2 (으)로 정하기 %3', albert_stop: '정지하기 %1', albert_set_pad_size_to: '말판 크기를 폭 %1 높이 %2 (으)로 정하기 %3', albert_move_to_x_y_on_board: '밑판 x: %1 y: %2 위치로 이동하기 %3', albert_set_orientation_on_board: '말판 %1도 방향으로 바라보기 %2', albert_set_eye_to: '%1 눈을 %2 으로 정하기 %3', albert_clear_eye: '%1 눈 끄기 %2', albert_body_led: '몸통 LED %1 %2', albert_front_led: '앞쪽 LED %1 %2', albert_beep: '삐 소리내기 %1', albert_change_buzzer_by: '버저 음을 %1 만큼 바꾸기 %2', albert_set_buzzer_to: '버저 음을 %1 (으)로 정하기 %2', albert_clear_buzzer: '버저 끄기 %1', albert_play_note_for: '%1 %2 음을 %3 박자 연주하기 %4', albert_rest_for: '%1 박자 쉬기 %2', albert_change_tempo_by: '연주 속도를 %1 만큼 바꾸기 %2', albert_set_tempo_to: '연주 속도를 %1 BPM으로 정하기 %2', albert_move_forward: '앞으로 이동하기 %1', albert_move_backward: '뒤로 이동하기 %1', albert_turn_around: '%1 으로 돌기 %2', albert_set_led_to: '%1 %2 으로 정하기 %3', albert_clear_led: '%1 %2', albert_change_wheels_by: '%1 %2 %3', albert_set_wheels_to: '%1 %2 %3', arduino_text: '%1', arduino_get_sensor_number: '%1 ', arduino_get_port_number: '%1 ', arduino_get_digital_toggle: '%1 ', arduino_get_pwm_port_number: '%1 ', arduino_get_number_sensor_value: '아날로그 %1 번 센서값 ', arduino_ext_get_analog_value: '아날로그 %1 번 센서값', arduino_ext_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', arduino_ext_get_ultrasonic_value: '울트라소닉 Trig %1 Echo %2 센서값', arduino_ext_toggle_led: '디지털 %1 번 핀 %2 %3', arduino_ext_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', arduino_ext_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', arduino_ext_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', arduino_ext_get_digital: '디지털 %1 번 센서값', blacksmith_get_analog_value: '아날로그 %1 번 핀 센서 값', blacksmith_get_analog_mapping: '아날로그 %1 번 핀 센서 값의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼 값', blacksmith_get_digital_bluetooth: '블루투스 RX 2 핀 데이터 값', blacksmith_get_digital_ultrasonic: '초음파 Trig %1 핀 Echo %2 핀 센서 값', blacksmith_get_digital_toggle: '디지털 %1 번 핀 센서 값', blacksmith_set_digital_toggle: '디지털 %1 번 핀 %2 %3', blacksmith_set_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', blacksmith_set_digital_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', blacksmith_set_digital_buzzer: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', blacksmith_set_digital_lcd: 'LCD화면 %1 줄에 %2 나타내기 %3', blacksmith_set_digital_bluetooth: '블루투스 TX 3 핀에 %1 데이터 보내기 %2', dplay_get_number_sensor_value: '아날로그 %1 번 센서값 ', nemoino_get_number_sensor_value: '아날로그 %1 번 센서값 ', sensorBoard_get_number_sensor_value: '아날로그 %1 번 센서값 ', truetrue_get_accsensor: '가속도센서 %1 의 값', truetrue_get_bottomcolorsensor: '바닥컬러센서 %1 의 값', truetrue_get_frontcolorsensor: '전면컬러센서 %1 의 값', truetrue_get_linesensor: '라인센서 %1 의 값', truetrue_get_proxisensor: '근접센서 %1 의 값', truetrue_set_colorled: '컬러LED Red %1 Green %2 Blue %3 로 설정 %4', truetrue_set_dualmotor: 'DC모터 좌 %1 우 %2 속도로 %3 초 구동 %4', truetrue_set_led_colorsensor: '%1 조명용 LED %2 %3', truetrue_set_led_linesensor: '라인센서 조명용 LED %1 %2', truetrue_set_led_proxi: '%1 조명용 LED %2 %3', truetrue_set_linetracer: '라인트레이싱 모드 %1 %2', truetrue_set_singlemotor: 'DC모터 %1 속도 %2 로 설정 %3', CODEino_get_number_sensor_value: '아날로그 %1 번 센서값 ', ardublock_get_number_sensor_value: '아날로그 %1 번 센서값 ', arduino_get_digital_value: '디지털 %1 번 센서값 ', dplay_get_digital_value: '디지털 %1 번 센서값 ', nemoino_get_digital_value: '디지털 %1 번 센서값 ', sensorBoard_get_digital_value: '디지털 %1 번 센서값 ', CODEino_get_digital_value: '디지털 %1 핀의 값 ', CODEino_set_digital_value: '디지털 %1 핀의 %2 %3', CODEino_set_pwm_value: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', ardublock_get_digital_value: '디지털 %1 번 센서값 ', arduino_toggle_led: '디지털 %1 번 핀 %2 %3', dplay_toggle_led: '디지털 %1 번 핀 %2 %3', nemoino_toggle_led: '디지털 %1 번 핀 %2 %3', sensorBoard_toggle_led: '디지털 %1 번 핀 %2 %3', CODEino_toggle_led: '디지털 %1 번 핀 %2 %3', arduino_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', dplay_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', nemoino_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', sensorBoard_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', CODEino_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', ardublock_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', arduino_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', dplay_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', nemoino_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', sensorBoard_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', CODEino_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', CODEino_set_rgb_value: '컬러 LED의 %1 색상을 %2 (으)로 정하기 %3', CODEino_set_rgb_add_value: '컬러 LED의 %1 색상에 %2 만큼 더하기 %3', CODEino_set_rgb_off: '컬러 LED 끄기 %1', CODEino_set__led_by_rgb: '컬러 LED 색상을 빨강 %1 초록 %2 파랑 %3 (으)로 정하기 %4', CODEino_rgb_set_color: '컬러 LED의 색상을 %1 (으)로 정하기 %2', CODEino_led_by_value: '컬러 LED 켜기 %1', ardublock_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', joystick_get_number_sensor_value: '아날로그 %1 번 센서값 ', joystick_get_digital_value: '디지털 %1 번 센서값 ', joystick_toggle_led: '디지털 %1 번 핀 %2 %3', joystick_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', joystick_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', sensorBoard_get_named_sensor_value: '%1 센서값', sensorBoard_is_button_pressed: '%1 버튼을 눌렀는가?', sensorBoard_led: '%1 LED %2 %3', arduino_download_connector: '%1', download_guide: '%1', arduino_lite_guide: '%1', arduino_download_source: '%1', arduino_connected: '%1', arduino_connect: '%1', arduino_reconnect: '%1', CODEino_get_sensor_number: '%1 ', CODEino_get_named_sensor_value: ' %1 센서값 ', CODEino_get_sound_status: '소리센서 %1 ', CODEino_get_light_status: '빛센서 %1 ', CODEino_is_button_pressed: ' 보드의 %1 ', CODEino_get_accelerometer_direction: ' 3축 가속도센서 %1 ', CODEino_get_accelerometer_value: ' 3축 가속도센서 %1 축의 센서값 ', CODEino_get_analog_value: '아날로그 %1 센서의 값', iboard_button: '%1 버튼을 눌렀는가?', iboard_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', iboard_get_analog_value: '아날로그 %1 번 센서값 ', iboard_get_analog_value_map: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', iboard_get_digital: '디지털 %1 번 센서값 ', iboard_led: 'LED %1 번을 %2 %3', iboard_motor: '모터를 %2 으로 동작하기 %3', iboard_pwm_led: 'LED %1 번의 밝기를 %2 (으)로 정하기 %3', iboard_rgb_led: 'RGB LED의 %1 LED %2 %3', iboard_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', iboard_toggle_led: '디지털 %1 번 핀 %2 %3', bitbrick_when_button_pressed: '%1 버튼 %2 눌러졌을 때', bitbrick_when_sensor_get_value: '%1 %2 값 %3 %4 일 때', bitbrick_is_touch_pressed: '버튼 %1 이(가) %2 인가?', bitbrick_is_sensor_value_compare: '%1 값 %2 %3 인가?', bitbrick_sensor_value: '%1 값', bitbrick_convert_scale: '변환 %1 값 %2 ~ %3 에서 %4 ~ %5', bitbrick_turn_on_color_led_by_rgb: '엘이디를 빨강 %1 초록 %2 파랑 %3 %4 (으)로 켜기', bitbrick_turn_on_color_led_by_picker: '엘이디를 %1 (으)로 켜기 %2', bitbrick_turn_on_color_led_by_value: '엘이디를 %1 (으)로 켜기 %2', bitbrick_turn_off_color_led: '엘이디 끄기 %1', bitbrick_buzzer: '버저음 %1 내기 %2', bitbrick_servomotor_angle: '서보모터 %1 각도 %2 %3', bitbrick_dc_direction_speed: '디씨모터 %1 방향 %2 속력 %3 %4', bitbrick_dc_speed: '디씨모터 %1 속도 %2 %3', bitbrick_turn_off_all_motors: '모든 모터 멈추기 %1', start_drawing: '그리기 시작하기 %1', stop_drawing: '그리기 멈추기 %1', start_fill: '채우기 시작하기 %1', stop_fill: '채우기 멈추기 %1', set_color: '그리기 색을 %1 (으)로 정하기 %2', set_random_color: '붓의 색을 무작위로 정하기 %1', set_fill_color: '채우기 색을 %1 (으)로 정하기 %2', change_thickness: '그리기 굵기를 %1 만큼 바꾸기 %2', set_thickness: '그리기 굵기를 %1 (으)로 정하기 %2', change_opacity: '붓의 불투명도를 %1 % 만큼 바꾸기 %2', set_opacity: '붓의 불투명도를 %1 % 로 정하기 %2', brush_erase_all: '모든 붓 지우기 %1', brush_stamp: '도장 찍기 %1', change_brush_transparency: '붓의 투명도를 %1 % 만큼 바꾸기 %2', set_brush_tranparency: '붓의 투명도를 %1 % 로 정하기 %2', number: '%1', angle: '%1', color: '%1', get_x_coordinate: '%1', get_y_coordinate: '%1', get_angle: '%1', get_rotation_direction: '%1 ', distance_something: '%1 %2 %3', coordinate_mouse: '%1 %2 %3', coordinate_object: '%1 %2 %3 %4', calc_basic: '%1 %2 %3', calc_plus: '%1 %2 %3', calc_minus: '%1 %2 %3', calc_times: '%1 %2 %3', calc_divide: '%1 %2 %3', calc_mod: '%1 %2 %3 %4', calc_share: '%1 %2 %3 %4', calc_operation: '%1 %2 %3 %4', calc_rand: '%1 %2 %3 %4 %5', get_date: '%1 %2 %3', get_sound_duration: '%1 %2 %3', get_user_name: '아이디', get_nickname: '닉네임', reset_project_timer: '%1', set_visible_project_timer: '%1 %2 %3 %4', timer_variable: '%1 %2', get_project_timer_value: '%1 %2', char_at: '%1 %2 %3 %4 %5', length_of_string: '%1 %2 %3', substring: '%1 %2 %3 %4 %5 %6 %7', replace_string: '%1 %2 %3 %4 %5 %6 %7', change_string_case: '%2 %1 %4 %3', count_match_string: '%1 %2 %3 %4', index_of_string: '%1 %2 %3 %4 %5', combine_something: '%1 %2 %3 %4 %5', get_sound_volume: '%1 %2', quotient_and_mod: '%1 %2 %3 %4 %5 %6', choose_project_timer_action: '%1 %2 %3 %4', wait_second: '%1 초 기다리기 %2', repeat_basic: '%1 번 반복하기 %2', hidden_loop: '%1 번 반복하기 %2', repeat_inf: '계속 반복하기 %1', stop_repeat: '반복 중단하기 %1', continue_repeat: '이번 반복 건너뛰기 %1', wait_until_true: '%1 이(가) 될 때까지 기다리기 %2', _if: '만일 %1 (이)라면 %2', if_else: '만일 %1 (이)라면 %2 %3 아니면', create_clone: '%1 의 복제본 만들기 %2', delete_clone: '이 복제본 삭제하기 %1', when_clone_start: '%1 복제본이 처음 생성되었을 때', stop_run: '프로그램 끝내기 %1', repeat_while_true: '%1 %2 반복하기 %3', stop_object: '%1 코드 멈추기 %2', restart_project: '처음부터 다시 실행하기 %1', remove_all_clones: '모든 복제본 삭제하기 %1', functionAddButton: '%1', function_field_label: '%1%2', function_field_string: '%1%2', function_field_boolean: '%1%2', get_block_count: '%1 의 블록 수', get_boolean_value: '%1 의 값', change_rgb_to_hex: 'R:%1G:%2B:%3의 HEX 값', change_hex_to_rgb: 'HEX%1의 %2값', function_param_string: '문자/숫자값', function_param_boolean: '판단값', function_create: '함수 정의하기 %1 %2', function_general: '함수 %1', function_value: '함수', expansionBlockAddButton: '%1', aiUtilizeBlockAddButton: '%1', aiUtilizeModelTrainButton: '%1', weather_title: '%1', check_weather: '%1 %2 의 날씨가 %3인가?', check_finedust: '현재 %1 의 미세먼지 등급이 %2인가?', get_weather_data: '%1 %2 의 %3', get_current_weather_data: '현재 %1 의 %2', get_today_temperature: '오늘 %1의 %2시 기온', check_city_weather: '%1 %2 %3의 날씨가 %4인가?', check_city_finedust: '현재 %1 %2 의 미세먼지 등급이 %3인가?', get_city_weather_data: '%1 %2 %3 의 %4', get_current_city_weather_data: '현재 %1 %2 의 %3', get_today_city_temperature: '오늘 %1 %2의 %3시 기온', get_cur_weather: '현재 %1의 날씨', get_cur_wind: '현재 %1의 풍향', get_cur_weather_data: '현재 %1의 %2', check_cur_weather: '현재 %1의 날씨가 %2인가?', check_cur_finddust: '현재 %1의 미세먼지 등급이 %2인가?', get_day_weather: '%1 %2의 날씨', get_day_weather_data: '%1 %2의 %3', check_day_weather: '%1 %2의 날씨가 %3 인가?', get_time_weather: '%1의 %2시 날씨', get_time_weather_data: '%1의 %2시 %3', check_time_weather: '%1의 %2시 날씨가 %3 인가?', translate_title: '%1', get_translated_string: '%1 %2 을(를) %3(으)로 번역한 값', check_language: '%1의 언어', festival_title: '%1', count_festival: '%1 %2 행사의 수', get_festival_info: '%1 %2 행사 %3 번째 항목의 %4', behaviorConductDisaster_title: '%1', count_disaster_behavior: '%1 %2 해야할 행동요령 수', get_disaster_behavior: '자연재난%1 %2 해야할 행동요령 %3 번째 항목', behaviorConductLifeSafety_title: '%1', count_lifeSafety_behavior: '%1 에서 %2 방법의 수', get_lifeSafety_behavior: '%1 에서 %2 방법 %3 번째 항목', tts_title: '%1', audio_title: '%1', video_title: '%1', read_text: '%1 읽어주기 %2', set_tts_property: '%1 목소리를 %2 속도 %3 음높이로 설정하기 %4', read_text_wait_with_block: '%1 읽어주고 기다리기 %2', load_expansion_block: '확장 블록 불러오기', load_ai_utilize_block: '인공지능 블록 불러오기', load_ai_utilize_train_block: '모델 학습', expansion_block_descriptions: '확장 블록은 인터넷이 연결되어 있어야 정상적으로 동작합니다.', aiUtilize_block_descriptions: '불러올 인공지능 블록을 선택해 주세요.', hardware_lite_descriptions: '하드웨어 연결/작동 시 예기치 못한 문제가 발생할 수 있습니다.\n 하드웨어 웹 연결 중 문제 발생 시 엔트리 고객센터 또는 해당 하드웨어 업체의 고객센터에 연락해 주세요.', weather_title_text: '날씨', translate_title_text: '번역', festival_title_text: '행사', learning_title_image: '%1', learning_title_speech: '%1', learning_title_text: '%1', learning_title_number: '%1', learning_title_regression: '%1', learning_title_logistic_regression: '%1', learning_title_cluster: '%1', learning_title_decisiontree: '%1', learning_title_svm: '%1', insert_data_for_test: '학습한 모델로 분류하기 %1', insert_text_block_for_test: '%1 을(를) 학습한 모델로 분류하기 %2', test_result: '분류 결과', accuracy_of_result: '%1에 대한 신뢰도', is_group: '분류 결과가 %1 인가?', retrain_model: '모델 다시 학습하기 %1', model_is_trained: '모델이 학습되었는가?', set_train_visible: '모델 %1 %2', set_train_chart: '모델 차트 창 %1 %2', set_regression_option: '학습 조건 %1 을 %2 으로 바꾸기 %3', get_regression_predict_1: '%1 %2 의 예측 값', get_regression_predict_2: '%1 %2 %3 %4 의 예측 값', get_regression_predict_3: '%1 %2 %3 %4 %5 %6 의 예측 값', get_regression_predict_4: '%1 %2 %3 %4 %5 %6 %7 %8 의 예측 값', get_regression_predict_5: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 의 예측 값', get_regression_predict_6: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 의 예측 값', get_regression_accuracy: '결정계수', set_logistic_regression_option: '학습 조건 %1 을(를) %2 (으)로 바꾸기 %3', set_logistic_regression_optimizer: '최적화 알고리즘을 %1 (으)로 바꾸기 %2', get_logistic_regression_probability_1: '%1 %2 의 %3 에 대한 확률', get_logistic_regression_probability_2: '%1 %2 %3 %4 의 %5 에 대한 확률', get_logistic_regression_probability_3: '%1 %2 %3 %4 %5 %6 의 %7 에 대한 확률', get_logistic_regression_probability_4: '%1 %2 %3 %4 %5 %6 %7 %8 의 %9 에 대한 확률', get_logistic_regression_probability_5: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 의 %11 에 대한 확률', get_logistic_regression_probability_6: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 의 %13 에 대한 확률', set_decisiontree_option: '학습 조건 %1 을 %2 으로 바꾸기 %3', set_decisiontree_tree: '학습한 트리 %1 %2', set_svm_option: '학습 조건 %1 을 %2 으로 바꾸기 %3', set_kernel_linear: '커널을 선형으로 바꾸기 %1', set_kernel_option: '커널을 %1 (으)로 바꾸고 %2 를 %3 (으)로 정하기 %4', train_param_kernel_polynomial: '다항식', train_param_kernel_rbf: 'RBF', train_param_degree: '차수', train_param_gamma: '감마', is_result_1: '%1 %2 의 분류 결과가 %3 인가?', is_result_2: '%1 %2 %3 %4 의 분류 결과가 %5 인가?', is_result_3: '%1 %2 %3 %4 %5 %6 의 분류 결과가 %7 인가?', is_result_4: '%1 %2 %3 %4 %5 %6 %7 %8 의 분류 결과가 %9 인가?', is_result_5: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 의 분류 결과가 %11 인가?', is_result_6: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 의 분류 결과가 %13 인가?', get_predict_1: '%1 %2 의 분류 결과', get_predict_2: '%1 %2 %3 %4 의 분류 결과', get_predict_3: '%1 %2 %3 %4 %5 %6 의 분류 결과', get_predict_4: '%1 %2 %3 %4 %5 %6 %7 %8 의 분류 결과', get_predict_5: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 의 분류 결과', get_predict_6: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 의 분류 결과', get_result_info: '모델의 %1', set_cluster_option_k: '군집을 %1 개로 바꾸기 %2', set_cluster_option_centroids: '중심점 기준을 %1 로 바꾸기 %2', get_cluster_centriod_count: '군집 개수', get_cluster_centriod_value: '군집 %1 중심점의 %2 값', get_cluster_centriod_index_1: '%1 %2의 군집', get_cluster_centriod_index_2: '%1 %2 %3 %4의 군집', get_cluster_centriod_index_3: '%1 %2 %3 %4 %5 %6의 군집', get_cluster_centriod_index_4: '%1 %2 %3 %4 %5 %6 %7 %8의 군집', get_cluster_centriod_index_5: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10의 군집', get_cluster_centriod_index_6: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12의 군집', set_number_learning_option_k: '이웃을 %1 개로 바꾸기 %2', get_number_learning_predict_1: '%1 %2 의 분류 결과', get_number_learning_predict_2: '%1 %2 %3 %4의 분류 결과', get_number_learning_predict_3: '%1 %2 %3 %4 %5 %6 의 분류 결과', get_number_learning_predict_4: '%1 %2 %3 %4 %5 %6 %7 %8 의 분류 결과', get_number_learning_predict_5: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 의 분류 결과', get_number_learning_predict_6: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 의 분류 결과', get_number_learning_predict_param_1: '%1 %2 의 %3 에 대한 %4', get_number_learning_predict_param_2: '%1 %2 %3 %4 의 %5 에 대한 %6', get_number_learning_predict_param_3: '%1 %2 %3 %4 %5 %6 의 %7 에 대한 %8', get_number_learning_predict_param_4: '%1 %2 %3 %4 %5 %6 %7 %8 의 %9 에 대한 %10', get_number_learning_predict_param_5: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 의 %11 에 대한 %12', get_number_learning_predict_param_6: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 의 %13 에 대한 %14', is_number_learning_group_1: '%1 %2 의 분류 결과가 %3 인가?', is_number_learning_group_2: '%1 %2 %3 %4 의 분류 결과가 %5 인가?', is_number_learning_group_3: '%1 %2 %3 %4 %5 %6 의 분류 결과가 %7 인가?', is_number_learning_group_4: '%1 %2 %3 %4 %5 %6 %7 %8 의 분류 결과가 %9 인가?', is_number_learning_group_5: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 의 분류 결과가 %11 인가?', is_number_learning_group_6: '%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 의 분류 결과가 %13 인가?', audio_title_text: '오디오 감지', voice_title_text: '음성 인식', check_microphone: '마이크가 연결되었는가?', get_microphone_volume: '마이크 소리 크기', speech_to_text_title: '%1', speech_to_text_convert: '%1 음성 인식하기 %2', timed_speech_to_text_convert: '%1 초 동안 %2 음성 인식하기 %3', set_visible_speech_to_text: '인식한 음성 %1 %2', speech_to_text_get_value: '음성을 문자로 바꾼 값', video_title_text: '비디오 감지', video_draw_webcam: '비디오 화면 %1 %2', video_check_webcam: '비디오가 연결되었는가?', video_change_cam: '%1 카메라로 바꾸기 %2', video_set_camera_opacity_option: '비디오 투명도 효과를 %1 으로 정하기 %2', video_flip_camera: '비디오 화면 %1 뒤집기 %2', video_toggle_model: '%1 인식 %2 %3', video_toggle_ind: '인식된 %1 %2 %3', video_number_detect: '인식된 %1 의 수', video_object_detected: '사물 중 %1 (이)가 인식되었는가?', video_is_model_loaded: '%1 인식이 되었는가?', video_detected_face_info: '%1 번째 얼굴의 %2', video_motion_value: '%1 에서 감지한 %2 값', video_face_part_coord: '%1 번째 얼굴의 %2 의 %3 좌표', video_body_part_coord: '%1 번째 사람의 %2 의 %3 좌표', behaviorConductDisaster_title_text: '자연재난 국민행동요령', behaviorConductLifeSafety_title_text: '생활안전 국민행동요령', emergencyActionGuidelines_title_text: '국민행동요령', count_disaster_guideline: '자연재난 %1 %2 의 행동요령 수', get_disaster_guideline: '자연재난 %1 %2 의 행동요령 %3 번째 항목', count_social_disaster_guideline: '사회재난 %1 %2 의 행동요령 수', get_social_disaster_guideline: '사회재난 %1 %2 의 행동요령 %3 번째 항목', count_safety_accident_guideline: '생활안전 %1 %2 의 행동요령 수', get_safety_accident_guideline: '생활안전 %1 %2 의 행동요령 %3 번째 항목', tts_title_text: '읽어주기', hamster_hand_found: '손 찾음?', hamster_value: '%1', hamster_move_forward_once: '말판 앞으로 한 칸 이동하기 %1', hamster_turn_once: '말판 %1 으로 한 번 돌기 %2', hamster_move_forward_for_secs: '앞으로 %1 초 이동하기 %2', hamster_move_backward_for_secs: '뒤로 %1 초 이동하기 %2', hamster_turn_for_secs: '%1 으로 %2 초 돌기 %3', hamster_change_both_wheels_by: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 만큼 바꾸기 %3', hamster_set_both_wheels_to: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 (으)로 정하기 %3', hamster_change_wheel_by: '%1 바퀴 %2 만큼 바꾸기 %3', hamster_set_wheel_to: '%1 바퀴 %2 (으)로 정하기 %3', hamster_follow_line_using: '%1 선을 %2 바닥 센서로 따라가기 %3', hamster_follow_line_until: '%1 선을 따라 %2 교차로까지 이동하기 %3', hamster_set_following_speed_to: '선 따라가기 속도를 %1 (으)로 정하기 %2', hamster_stop: '정지하기 %1', hamster_set_led_to: '%1 LED를 %2 으로 정하기 %3', hamster_clear_led: '%1 LED 끄기 %2', hamster_beep: '삐 소리내기 %1', hamster_change_buzzer_by: '버저 음을 %1 만큼 바꾸기 %2', hamster_set_buzzer_to: '버저 음을 %1 (으)로 정하기 %2', hamster_clear_buzzer: '버저 끄기 %1', hamster_play_note_for: '%1 %2 음을 %3 박자 연주하기 %4', hamster_rest_for: '%1 박자 쉬기 %2', hamster_change_tempo_by: '연주 속도를 %1 만큼 바꾸기 %2', hamster_set_tempo_to: '연주 속도를 %1 BPM으로 정하기 %2', hamster_set_port_to: '포트 %1 를 %2 으로 정하기 %3', hamster_change_output_by: '출력 %1 를 %2 만큼 바꾸기 %3', hamster_set_output_to: '출력 %1 를 %2 (으)로 정하기 %3', roboid_hamster_beep: '햄스터 %1: 삐 소리내기 %2', roboid_hamster_change_both_wheels_by: '햄스터 %1: 왼쪽 바퀴 %2 오른쪽 바퀴 %3 만큼 바꾸기 %4', roboid_hamster_change_buzzer_by: '햄스터 %1: 버저 음을 %2 만큼 바꾸기 %3', roboid_hamster_change_output_by: '햄스터 %1: 출력 %2 를 %3 만큼 바꾸기 %4', roboid_hamster_change_tempo_by: '햄스터 %1: 연주 속도를 %2 만큼 바꾸기 %3', roboid_hamster_change_wheel_by: '햄스터 %1: %2 바퀴 %3 만큼 바꾸기 %4', roboid_hamster_clear_buzzer: '햄스터 %1: 버저 끄기 %2', roboid_hamster_clear_led: '햄스터 %1: %2 LED 끄기 %3', roboid_hamster_follow_line_until: '햄스터 %1: %2 선을 따라 %3 교차로까지 이동하기 %4', roboid_hamster_follow_line_using: '햄스터 %1: %2 선을 %3 바닥 센서로 따라가기 %4', roboid_hamster_hand_found: '햄스터 %1: 손 찾음?', roboid_hamster_move_backward_for_secs: '햄스터 %1: 뒤로 %2 초 이동하기 %3', roboid_hamster_move_forward_for_secs: '햄스터 %1: 앞으로 %2 초 이동하기 %3', roboid_hamster_move_forward_once: '햄스터 %1: 말판 앞으로 한 칸 이동하기 %2', roboid_hamster_play_note_for: '햄스터 %1: %2 %3 음을 %4 박자 연주하기 %5', roboid_hamster_rest_for: '햄스터 %1: %2 박자 쉬기 %3', roboid_hamster_set_both_wheels_to: '햄스터 %1: 왼쪽 바퀴 %2 오른쪽 바퀴 %3 (으)로 정하기 %4', roboid_hamster_set_buzzer_to: '햄스터 %1: 버저 음을 %2 (으)로 정하기 %3', roboid_hamster_set_following_speed_to: '햄스터 %1: 선 따라가기 속도를 %2 (으)로 정하기 %3', roboid_hamster_set_led_to: '햄스터 %1: %2 LED를 %3 으로 정하기 %4', roboid_hamster_set_output_to: '햄스터 %1: 출력 %2 를 %3 (으)로 정하기 %4', roboid_hamster_set_port_to: '햄스터 %1: 포트 %2 를 %3 으로 정하기 %4', roboid_hamster_set_tempo_to: '햄스터 %1: 연주 속도를 %2 BPM으로 정하기 %3', roboid_hamster_set_wheel_to: '햄스터 %1: %2 바퀴 %3 (으)로 정하기 %4', roboid_hamster_stop: '햄스터 %1: 정지하기 %2', roboid_hamster_turn_for_secs: '햄스터 %1: %2 으로 %3 초 돌기 %4', roboid_hamster_turn_once: '햄스터 %1: 말판 %2 으로 한 번 돌기 %3', roboid_hamster_value: '햄스터 %1: %2', roboid_turtle_button_state: '거북이 %1: 버튼을 %2 ?', roboid_turtle_change_buzzer_by: '거북이 %1: 버저 음을 %2 만큼 바꾸기 %3', roboid_turtle_change_head_led_by_rgb: '거북이 %1: 머리 LED를 R: %2 G: %3 B: %4 만큼 바꾸기 %5', roboid_turtle_change_tempo_by: '거북이 %1: 연주 속도를 %2 만큼 바꾸기 %3', roboid_turtle_change_wheel_by: '거북이 %1: %2 바퀴 %3 만큼 바꾸기 %4', roboid_turtle_change_wheels_by_left_right: '거북이 %1: 왼쪽 바퀴 %2 오른쪽 바퀴 %3 만큼 바꾸기 %4', roboid_turtle_clear_head_led: '거북이 %1: 머리 LED 끄기 %2', roboid_turtle_clear_sound: '거북이 %1: 소리 끄기 %2', roboid_turtle_cross_intersection: '거북이 %1: 검은색 교차로 건너가기 %2', roboid_turtle_follow_line: '거북이 %1: %2 선을 따라가기 %3', roboid_turtle_follow_line_until: '거북이 %1: 검은색 선을 따라 %2 까지 이동하기 %3', roboid_turtle_follow_line_until_black: '거북이 %1: %2 선을 따라 검은색까지 이동하기 %3', roboid_turtle_is_color_pattern: '거북이 %1: 색깔 패턴이 %2 %3 인가?', roboid_turtle_move_backward_unit: '거북이 %1: 뒤로 %2 %3 이동하기 %4', roboid_turtle_move_forward_unit: '거북이 %1: 앞으로 %2 %3 이동하기 %4', roboid_turtle_pivot_around_wheel_unit_in_direction: '거북이 %1: %2 바퀴 중심으로 %3 %4 %5 방향으로 돌기 %6', roboid_turtle_play_note: '거북이 %1: %2 %3 음을 연주하기 %4', roboid_turtle_play_note_for_beats: '거북이 %1: %2 %3 음을 %4 박자 연주하기 %5', roboid_turtle_play_sound_times: '거북이 %1: %2 소리 %3 번 재생하기 %4', roboid_turtle_play_sound_times_until_done: '거북이 %1: %2 소리 %3 번 재생하고 기다리기 %4', roboid_turtle_rest_for_beats: '거북이 %1: %2 박자 쉬기 %3', roboid_turtle_set_buzzer_to: '거북이 %1: 버저 음을 %2 (으)로 정하기 %3', roboid_turtle_set_following_speed_to: '거북이 %1: 선 따라가기 속도를 %2 (으)로 정하기 %3', roboid_turtle_set_head_led_to: '거북이 %1: 머리 LED를 %2 으로 정하기 %3', roboid_turtle_set_head_led_to_rgb: '거북이 %1: 머리 LED를 R: %2 G: %3 B: %4 (으)로 정하기 %5', roboid_turtle_set_tempo_to: '거북이 %1: 연주 속도를 %2 BPM으로 정하기 %3', roboid_turtle_set_wheel_to: '거북이 %1: %2 바퀴 %3 (으)로 정하기 %4', roboid_turtle_set_wheels_to_left_right: '거북이 %1: 왼쪽 바퀴 %2 오른쪽 바퀴 %3 (으)로 정하기 %4', roboid_turtle_stop: '거북이 %1: 정지하기 %2', roboid_turtle_touching_color: '거북이 %1: %2 에 닿았는가?', roboid_turtle_turn_at_intersection: '거북이 %1: 검은색 교차로에서 %2 으로 돌기 %3', roboid_turtle_turn_unit_in_place: '거북이 %1: %2 으로 %3 %4 제자리 돌기 %5', roboid_turtle_turn_unit_with_radius_in_direction: '거북이 %1: %2 으로 %3 %4 반지름 %5 cm를 %6 방향으로 돌기 %7', roboid_turtle_value: '거북이 %1: %2', turtle_button_state: '버튼을 %1 ?', turtle_change_buzzer_by: '버저 음을 %1 만큼 바꾸기 %2', turtle_change_head_led_by_rgb: '머리 LED를 R: %1 G: %2 B: %3 만큼 바꾸기 %4', turtle_change_tempo_by: '연주 속도를 %1 만큼 바꾸기 %2', turtle_change_wheel_by: '%1 바퀴 %2 만큼 바꾸기 %3', turtle_change_wheels_by_left_right: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 만큼 바꾸기 %3', turtle_clear_head_led: '머리 LED 끄기 %1', turtle_clear_sound: '소리 끄기 %1', turtle_cross_intersection: '검은색 교차로 건너가기 %1', turtle_follow_line: '%1 선을 따라가기 %2', turtle_follow_line_until: '검은색 선을 따라 %1 까지 이동하기 %2', turtle_follow_line_until_black: '%1 선을 따라 검은색까지 이동하기 %2', turtle_is_color_pattern: '색깔 패턴이 %1 %2 인가?', turtle_move_backward_unit: '뒤로 %1 %2 이동하기 %3', turtle_move_forward_unit: '앞으로 %1 %2 이동하기 %3', turtle_pivot_around_wheel_unit_in_direction: '%1 바퀴 중심으로 %2 %3 %4 방향으로 돌기 %5', turtle_play_note: '%1 %2 음을 연주하기 %3', turtle_play_note_for_beats: '%1 %2 음을 %3 박자 연주하기 %4', turtle_play_sound_times: '%1 소리 %2 번 재생하기 %3', turtle_play_sound_times_until_done: '%1 소리 %2 번 재생하고 기다리기 %3', turtle_rest_for_beats: '%1 박자 쉬기 %2', turtle_set_buzzer_to: '버저 음을 %1 (으)로 정하기 %2', turtle_set_following_speed_to: '선 따라가기 속도를 %1 (으)로 정하기 %2', turtle_set_head_led_to: '머리 LED를 %1 으로 정하기 %2', turtle_set_head_led_to_rgb: '머리 LED를 R: %1 G: %2 B: %3 (으)로 정하기 %4', turtle_set_tempo_to: '연주 속도를 %1 BPM으로 정하기 %2', turtle_set_wheel_to: '%1 바퀴 %2 (으)로 정하기 %3', turtle_set_wheels_to_left_right: '왼쪽 바퀴 %1 오른쪽 바퀴 %2 (으)로 정하기 %3', turtle_stop: '정지하기 %1', turtle_touching_color: '%1 에 닿았는가?', turtle_turn_at_intersection: '검은색 교차로에서 %1 으로 돌기 %2', turtle_turn_unit_in_place: '%1 으로 %2 %3 제자리 돌기 %4', turtle_turn_unit_with_radius_in_direction: '%1 으로 %2 %3 반지름 %4 cm를 %5 방향으로 돌기 %6', turtle_value: '%1', is_clicked: '%1', is_object_clicked: '%1', is_press_some_key: '%1 %2', reach_something: '%1 %2 %3', is_type: '%1 %2 %3 %4', boolean_comparison: '%1 %2 %3', boolean_equal: '%1 %2 %3', boolean_bigger: '%1 %2 %3', boolean_smaller: '%1 %2 %3', boolean_and_or: '%1 %2 %3', boolean_and: '%1 %2 %3', boolean_or: '%1 %2 %3', boolean_not: '%1 %2 %3', is_boost_mode: '%1', is_current_device_type: '%1 에서 실행하는가?', is_touch_supported: '화면을 터치할 수 있는가?', true_or_false: '%1', True: '%1 ', False: '%1 ', boolean_basic_operator: '%1 %2 %3', show: '모양 보이기 %1', hide: '모양 숨기기 %1', dialog_time: '%1 을(를) %2 초 동안 %3 %4', dialog: '%1 을(를) %2 %3', remove_dialog: '말풍선 지우기 %1', change_to_nth_shape: '%1 모양으로 바꾸기 %2', change_to_next_shape: '%1 모양으로 바꾸기 %2', set_effect_volume: '%1 효과를 %2 만큼 주기 %3', set_effect: '%1 효과를 %2 (으)로 정하기 %3', erase_all_effects: '효과 모두 지우기 %1', change_scale_percent: '크기를 %1 만큼 바꾸기 %2', set_scale_percent: '크기를 %1 (으)로 정하기 %2', change_scale_size: '크기를 %1 만큼 바꾸기 %2', set_scale_size: '크기를 %1 (으)로 정하기 %2', stretch_scale_size: '%1 를 %2 만큼 늘이기 %3', reset_scale_size: '원래 크기로 되돌리기 %1', flip_y: '좌우 모양 뒤집기 %1', flip_x: '상하 모양 뒤집기 %1', set_object_order: '%1 번째로 올라오기 %2', get_pictures: '%1 ', change_to_some_shape: '%1 모양으로 바꾸기 %2', add_effect_amount: '%1 효과를 %2 만큼 주기 %3', change_effect_amount: '%1 효과를 %2 (으)로 정하기 %3', set_effect_amount: '%1 효과를 %2 만큼 주기 %3', set_entity_effect: '%1 효과를 %2 (으)로 정하기 %3', change_object_index: '%1 보내기 %2', move_direction: '이동 방향으로 %1 만큼 움직이기 %2', move_x: 'x 좌표를 %1 만큼 바꾸기 %2', move_y: 'y 좌표를 %1 만큼 바꾸기 %2', locate_xy_time: '%1 초 동안 x: %2 y: %3 위치로 이동하기 %4', rotate_by_angle: '오브젝트를 %1 만큼 회전하기 %2', rotate_by_angle_dropdown: '%1 만큼 회전하기 %2', see_angle: '이동 방향을 %1 (으)로 정하기 %2', see_direction: '%1 쪽 보기 %2', locate_xy: 'x: %1 y: %2 위치로 이동하기 %3', locate_x: 'x: %1 위치로 이동하기 %2', locate_y: 'y: %1 위치로 이동하기 %2', locate: '%1 위치로 이동하기 %2', move_xy_time: '%1 초 동안 x: %2 y: %3 만큼 움직이기 %4', rotate_by_angle_time: '오브젝트를 %1 초 동안 %2 만큼 회전하기 %3', bounce_wall: '화면 끝에 닿으면 튕기기 %1', flip_arrow_horizontal: '화살표 방향 좌우 뒤집기 %1', flip_arrow_vertical: '화살표 방향 상하 뒤집기 %1', see_angle_object: '%1 쪽 바라보기 %2', see_angle_direction: '오브젝트를 %1 (으)로 정하기 %2', rotate_direction: '이동 방향을 %1 만큼 회전하기 %2', locate_object_time: '%1 초 동안 %2 위치로 이동하기 %3', rotate_absolute: '방향을 %1 (으)로 정하기 %2', rotate_relative: '방향을 %1 만큼 회전하기 %2', direction_absolute: '이동 방향을 %1 (으)로 정하기 %2', direction_relative: '이동 방향을 %1 만큼 회전하기 %2', move_to_angle: '%1 방향으로 %2 만큼 움직이기 %3', rotate_by_time: '%1 초 동안 방향을 %2 만큼 회전하기 %3', direction_relative_duration: '%1 초 동안 이동 방향 %2 만큼 회전하기 %3', neobot_sensor_value: '%1 값', neobot_turn_left: '왼쪽모터를 %1 %2 회전 %3', neobot_stop_left: '왼쪽모터 정지 %1', neobot_turn_right: '오른쪽모터를 %1 %2 회전 %3', neobot_stop_right: '오른쪽모터 정지 %1', neobot_run_motor: '%1 모터를 %2 초간 %3 %4 %5', neobot_servo_1: 'SERVO1에 연결된 서보모터를 %1 속도로 %2 로 이동 %3', neobot_servo_2: 'SERVO2에 연결된 서보모터를 %1 속도로 %2 로 이동 %3', neobot_play_note_for: '멜로디 %1 을(를) %2 옥타브로 %3 길이만큼 소리내기 %4', neobot_set_sensor_value: '%1 번 포트의 값을 %2 %3', robotis_openCM70_cm_custom_value: '직접입력 주소 ( %1 ) %2 값', robotis_openCM70_sensor_value: '제어기 %1 값', robotis_openCM70_aux_sensor_value: '%1 %2 값', robotis_openCM70_cm_buzzer_index: '제어기 음계값 %1 을(를) %2 초 동안 연주 %3', robotis_openCM70_cm_buzzer_melody: '제어기 멜로디 %1 번 연주 %2', robotis_openCM70_cm_sound_detected_clear: '최종소리감지횟수 초기화 %1', robotis_openCM70_cm_led: '제어기 %1 LED %2 %3', robotis_openCM70_cm_motion: '모션 %1 번 실행 %2', robotis_openCM70_cm_autodrive_motor: '자율주행 자동차 %1 모터를 %2 에 연결 %3', robotis_openCM70_cm_autodrive_ir: '자율주행 자동차 %1 적외선센서를 %2 에 연결 %3', robotis_openCM70_cm_autodrive_speed: '차로를 따라 %1의 속도로 자율주행 %2', robotis_openCM70_aux_car_move: '로봇을 %1% 의 속도로 %2 %3', robotis_openCM70_aux_motor_speed: '%1 감속모터 속도를 %2 , 출력값을 %3%로 정하기 %4', robotis_openCM70_aux_servo_mode: '%1 서보모터 모드를 %2 (으)로 정하기 %3', robotis_openCM70_aux_servo_speed: '%1 서보모터 속도를 %2 , 출력값을 %3%로 정하기 %4', robotis_openCM70_aux_servo_position: '%1 서보모터 위치를 %2도로 정하기 %3', robotis_openCM70_aux_led_module: '%1 LED 모듈을 %2 (으)로 정하기 %3', robotis_openCM70_cm_poweroff_timer: '제어기 자동꺼짐 타이머 %1 %2', robotis_openCM70_aux_custom: '%1 사용자 장치를 %2 (으)로 정하기 %3', robotis_openCM70_cm_custom: '직접입력 주소 ( %1 ) (을)를 %2 (으)로 정하기 %3', robotis_carCont_sensor_value: '%1 값', robotis_carCont_cm_led: '4번 LED %1 , 1번 LED %2 %3', robotis_carCont_cm_sound_detected_clear: '최종소리감지횟수 초기화 %1', robotis_carCont_aux_motor_speed: '%1 감속모터 속도를 %2 , 출력값을 %3 (으)로 정하기 %4', robotis_carCont_cm_calibration: '%1 적외선 센서 캘리브레이션 값을 %2 (으)로 정하기 %3', roduino_get_analog_number: '%1 ', roduino_get_port_number: '%1 ', roduino_get_analog_value: '아날로그 %1 번 센서값 ', roduino_get_digital_value: '디지털 %1 번 센서값 ', roduino_set_digital: '디지털 %1 번 핀 %2 %3', roduino_motor: '%1 %2 %3', roduino_set_color_pin: '컬러센서 R : %1, G : %2, B : %3 %4', roduino_get_color: '컬러센서 %1 감지', roduino_on_block: ' On ', roduino_off_block: ' Off ', schoolkit_get_in_port_number: '%1 ', schoolkit_get_out_port_number: '%1 ', schoolkit_get_servo_port_number: '%1 ', schoolkit_get_input_value: '디지털 %1 번 센서값 ', schoolkit_set_output: '디지털 %1 번 핀 %2 %3', schoolkit_motor: '%1 속도 %2(으)로 %3 %4', schoolkit_set_servo_value: '서보모터 %1 번 핀 %2˚ %3', schoolkit_on_block: ' On ', schoolkit_off_block: ' Off ', when_scene_start: '%1 장면이 시작되었을 때', start_scene: '%1 시작하기 %2', start_neighbor_scene: '%1 장면 시작하기 %2', sound_something: '소리 %1 재생하기 %2', sound_something_second: '소리 %1 %2 초 재생하기 %3', sound_something_wait: '소리 %1 재생하고 기다리기 %2', sound_something_second_wait: '소리 %1 %2 초 재생하고 기다리기 %3', sound_volume_change: '소리 크기를 %1 만큼 바꾸기 %2', sound_volume_set: '소리 크기를 %1 % 로 정하기 %2', get_sound_speed: '소리 빠르기', sound_speed_change: '소리 빠르기를 %1 만큼 바꾸기 %2', sound_speed_set: '소리 빠르기를 %1 배로 정하기 %2', sound_silent_all: '%1 소리 멈추기 %2', play_bgm: '%1 을(를) 배경음악으로 재생하기 %2', stop_bgm: '배경음악 멈추기 %1', get_sounds: '%1 ', sound_something_with_block: '소리 %1 재생하기 %2', sound_something_second_with_block: '소리 %1 %2 초 재생하기 %3', sound_something_wait_with_block: '소리 %1 재생하고 기다리기 %2', sound_something_second_wait_with_block: '소리 %1 %2 초 재생하고 기다리기 %3', sound_from_to: '소리 %1 %2 초 부터 %3 초까지 재생하기 %4', sound_from_to_and_wait: '소리 %1 %2 초 부터 %3 초까지 재생하고 기다리기 %4', messageAddButton: '%1', when_run_button_click: '%1 시작하기 버튼을 클릭했을 때', press_some_key: '%1 %2 키를 눌렀을 때 %3', when_some_key_pressed: '%1 %2 키를 눌렀을 때', mouse_clicked: '%1 마우스를 클릭했을 때', mouse_click_cancled: '%1 마우스 클릭을 해제했을 때', when_object_click: '%1 오브젝트를 클릭했을 때', when_object_click_canceled: '%1 오브젝트 클릭을 해제했을 때', when_some_key_click: '%1 키를 눌렀을 때', when_message_cast: '%1 %2 신호를 받았을 때', message_cast: '%1 신호 보내기 %2', message_cast_wait: '%1 신호 보내고 기다리기 %2', text: '%1', text_read: '글상자 %1의 내용', text_write: '%1 (이)라고 글쓰기 %2', text_append: '%1 을(를) 뒤에 추가하기 %2', text_prepend: '%1 을(를) 앞에 추가하기 %2', text_change_effect: '텍스트에 %1 효과 %2 %3', text_change_font: '글씨체를 %1 (으)로 바꾸기 %2', text_change_font_color: '글씨색을 %1 (으)로 바꾸기 %2', text_change_bg_color: '배경색을 %1 (으)로 바꾸기 %2', text_flush: '텍스트 모두 지우기 %1', analizyDataAddButton: '%1', append_row_to_table: '테이블 %1에 %2 추가하기 %3', insert_row_to_table: '테이블 %1 %2 번째에 %3 추가하기 %4', delete_row_from_table: '테이블 %1 %2번째 %3 삭제하기 %4', set_value_from_table: '테이블 %1 %2번째 행의 %3을(를) %4(으)로 바꾸기 %5', save_current_table: '테이블 %1 을(를) 현재 상태로 남기기 %2', get_table_count: '테이블 %1의 %2 개수', get_value_from_table: '테이블 %1 %2번째 행의 %3 값', get_value_from_last_row: '테이블 %1 마지막 행의 %2 값', calc_values_from_table: '테이블 %1 %2의 %3', open_table: '테이블 %1 창 열기 %2', open_table_wait: '테이블 %1 창을 %2 초 동안 열기 %3', open_table_chart: '테이블 %1 의 %2 차트 창 열기 %3', close_table_chart: '테이블 차트 창 닫기 %1', get_coefficient: '테이블 %1 %2 과(와) %3 의 상관계수', set_value_from_cell: '테이블 %1 의 %2 셀 값을 %3 (으)로 바꾸기 %4', get_value_from_cell: '테이블 %1 의 %2 셀 값', get_value_v_lookup: '테이블 %1 의 %2 이(가) %3 인 행의 %4 값', variableAddButton: '%1', listAddButton: '%1', change_variable: '%1 에 %2 만큼 더하기 %3', set_variable: '%1 를 %2 (으)로 정하기 %3', show_variable: '변수 %1 보이기 %2', hide_variable: '변수 %1 숨기기 %2', get_variable: '%1 %2', ask_and_wait: '%1 을(를) 묻고 대답 기다리기 %2', get_canvas_input_value: '%1 ', add_value_to_list: '%1 항목을 %2 에 추가하기 %3', remove_value_from_list: '%1 번째 항목을 %2 에서 삭제하기 %3', insert_value_to_list: '%1 을(를) %2 의 %3 번째에 넣기 %4', change_value_list_index: '%1 %2 번째 항목을 %3 (으)로 바꾸기 %4', value_of_index_from_list: '%1 %2 %3 %4 %5', length_of_list: '%1 %2 %3', show_list: '리스트 %1 보이기 %2', hide_list: '리스트 %1 숨기기 %2', options_for_list: '%1 ', set_visible_answer: '대답 %1 %2', is_included_in_list: '%1 %2 %3 %4 %5', xbot_digitalInput: '%1', xbot_analogValue: '%1', xbot_digitalOutput: '디지털 %1 핀, 출력 값 %2 %3', xbot_analogOutput: '아날로그 %1 %2 %3', xbot_servo: '서보 모터 %1 , 각도 %2 %3', xbot_oneWheel: '바퀴(DC) 모터 %1 , 속도 %2 %3', xbot_twoWheel: '바퀴(DC) 모터 오른쪽(2) 속도: %1 왼쪽(1) 속도: %2 %3', xbot_rgb: 'RGB LED 켜기 R 값 %1 G 값 %2 B 값 %3 %4', xbot_rgb_picker: 'RGB LED 색 %1 로 정하기 %2', xbot_buzzer: '%1 %2 음을 %3 초 연주하기 %4', xbot_lcd: 'LCD %1 번째 줄 , 출력 값 %2 %3', run: '', mutant: 'test mutant block', jr_start: '%1', jr_repeat: '%1 %2 반복', jr_item: '꽃 모으기 %1', cparty_jr_item: '연필 줍기 %1', jr_north: ' 위쪽 %1', jr_east: '오른쪽 %1', jr_south: ' 아래쪽 %1', jr_west: ' 왼쪽 %1', jr_start_basic: '%1 %2', jr_go_straight: '앞으로 가기%1', jr_turn_left: '왼쪽으로 돌기%1', jr_turn_right: '오른쪽으로 돌기%1', jr_go_slow: '천천히 가기 %1', jr_repeat_until_dest: '%1 만날 때까지 반복하기 %2', jr_if_construction: '만약 %1 앞에 있다면 %2', jr_if_speed: '만약 %1 앞에 있다면 %2', maze_step_start: '%1 시작하기를 클릭했을 때', maze_step_jump: '뛰어넘기%1', maze_step_jump2: '뛰어넘기%1', maze_step_jump_pinkbean: '뛰어넘기%1', maze_step_for: '%1 번 반복하기%2', test: '%1 this is test block %2', maze_repeat_until_1: '%1 만날 때 까지 반복%2', maze_repeat_until_2: '모든 %1 만날 때 까지 반복%2', maze_step_if_1: '만약 앞에 %1 있다면%2', maze_step_if_2: '만약 앞에 %1 있다면%2', maze_call_function: '약속 불러오기%1', maze_define_function: '약속하기%1', maze_step_if_3: '만약 앞에 %1 있다면%2', maze_step_if_4: '만약 앞에 %1 있다면%2', maze_step_move_step: '앞으로 한 칸 이동%1', maze_step_rotate_left: '왼쪽으로 회전%1', maze_step_rotate_right: '오른쪽으로 회전%1', maze_step_forward: '앞으로 가기%1', maze_turn_right: '오른쪽 바라보기%1', maze_turn_left: '왼쪽 바라보기%1', maze_ladder_climb: '사다리 타기%1', maze_attack_lupin: '%1공격하기%2', maze_attack_both_side: '양옆 공격하기%1', maze_attack_pepe: '%1 공격하기%2', maze_attack_yeti: '%1 공격하기%2', maze_attack_mushroom: '%1 공격하기%2', maze_attack_peti: '%1 공격하기%2', maze_eat_item: '음식 먹기%1', maze_step_if_mushroom: '만약 한 칸 앞에 %1가 있다면 %2', maze_step_if_yeti: '만약 앞에 %1가 있다면 %2 %3 아니면', maze_step_if_left_monster: '만약 왼쪽 공격범위에 몬스터가 있다면 %1 %2 아니면', maze_step_if_right_monster: '만약 오른쪽 공격범위에 몬스터가 있다면 %1 %2 아니면', maze_step_if_lupin: '만약 두 칸 앞에 %1가 있다면 %2', maze_step_if_else_road: '만약 한 칸 앞에 길이 있다면 %1 %2아니면', maze_step_if_else_mushroom: '만약 한 칸 앞에 %1가 있다면 %2 %3아니면', maze_step_if_else_lupin: '만약 두 칸 앞에 %1가 있다면 %2 %3아니면', maze_step_if_else_ladder: '만약 한 칸 앞에 %1가 있다면 %2 %3아니면', maze_rotate_left: '왼쪽으로 돌기%1', maze_rotate_right: '오른쪽으로 돌기%1', maze_moon_kick: '발차기하기%1', maze_repeat_until_3: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_4: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_5: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_6: '%1에 도착할 때까지 반복하기%2', maze_repeat_until_7: '목적지에 도착할 때까지 반복하기%2', maze_repeat_until_goal: '목적지에 도착할 때까지 반복하기%1', maze_repeat_until_beat_monster: '모든 몬스터를 혼내줄 때까지 반복하기%1', maze_radar_check: '%1에 %2이 있다', maze_cony_flower_throw: '부채질하기%1', maze_brown_punch: '주먹 날리기%1', maze_iron_switch: '장애물 조종하기%1', maze_james_heart: '케이크 던지기%1', maze_step_if_5: '만약 앞에 길이 없다면%2', maze_step_if_6: '만약 앞에 %1이 없다면%2', maze_step_if_7: '만약 앞에 %1이 있다면%2', maze_step_if_8: '만약 %1이라면%2', maze_step_if_else: '만약 %1이라면%2 %3 아니면', test_wrapper: '%1 this is test block %2', basic_button: '%1', ai_move_right: '앞으로 가기 %1', ai_move_up: '위쪽으로 가기 %1', ai_move_down: '아래쪽으로 가기 %1', ai_repeat_until_reach: '목적지에 도달 할 때까지 반복하기 %1', ai_if_else_1: '만약 앞에 %1가 있다면 %2 %3 아니면', ai_boolean_distance: '%1 레이더 %2 %3', ai_distance_value: '%1 레이더', ai_boolean_object: '%1 물체는 %2 인가?', ai_use_item: '아이템 사용 %1', ai_boolean_and: '%1 %2 %3', ai_True: '%1', ai_if_else: '만일 %1 (이)라면 %2 %3 아니면', smartBoard_convert_scale: '%1 값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값', smartBoard_get_named_sensor_value: '%1 센서값', smartBoard_is_button_pressed: '%1 버튼을 눌렀는가?', smartBoard_set_dc_motor_direction: '%1 DC 모터를 %2 방향으로 정하기 %3', smartBoard_set_dc_motor_speed: '%1 DC모터를 %2 %3', smartBoard_set_dc_motor_pwm: '%1 DC모터를 %2 속도로 돌리기 %3', smartBoard_set_servo_speed: '%1 번 서보모터의 속도를 %2 %3', smartBoard_set_servo_angle: '%1 번 서보모터를 %2 도 로 움직이기 %3', smartBoard_set_number_eight_pin: '%1 포트를 %2 %3', smartBoard_set_gs1_pwm: 'GS1 포트의 PWM을 %1 로 정하기 %2', robotori_digitalInput: '%1', robotori_analogInput: '%1', robotori_digitalOutput: '디지털 %1 핀, 출력 값 %2 %3', robotori_analogOutput: '아날로그 %1 %2 %3', robotori_servo: '서보모터 각도 %1 %2', robotori_dc_direction: 'DC모터 %1 회전 %2 %3', dadublock_get_analog_value: '아날로그 %1 번 센서값', dadublock_get_analog_value_map: '아날로그 %1번 센서값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값', dadublock_get_ultrasonic_value: '울트라소닉 Trig %1번핀 Echo %2번핀 센서값', dadublock_toggle_led: '디지털 %1 번 핀 %2 %3', dadublock_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', dadublock_set_tone: '디지털 %1 번 핀을 %2 음으로 %3 옥타브로 %4 만큼 연주하기 %5', dadublock_set_servo: '서보모터 %1 번 핀을 %2 의 각도로 정하기 %3', coconut_stop_motor: '모터 정지 %1', coconut_move_motor: '%1 움직이기 %2', coconut_turn_motor: '%1 으로 돌기 %2', coconut_move_for_secs: '%1 %2 초동안 움직이기 %3', coconut_turn_for_secs: '%1 으로 %2 초동안 돌기 %3', coconut_turn_to_led: '%1 으로 회전하는 동안 %2LED 켜기 %3', coconut_move_outmotor: '외부모터 %1(으로) 움직이기 속도 %2 %3', coconut_set_led_to: '%1 LED를 %2 으로 켜기 %3', coconut_clear_led: '%1 LED 끄기 %2', coconut_set_led_clear: '%1 LED %2 끄기 %3', coconut_set_led_time: '%1 LED %2 으로 %3 초동안 켜기 %4', coconut_beep: '버저 켜기 %1', coconut_buzzer_time: '버저음을 %1 초 동안 소리내기 %2', coconut_buzzer_set_hz: '버즈음 %1 Hz를 %2초 동안 소리내기 %3', coconut_clear_buzzer: '버저 끄기 %1', coconut_play_buzzer: '%1 %2 %3 음을 %4 박자로 연주하기 %5', coconut_rest_buzzer: '%1 동안 쉬기 %2', coconut_play_buzzer_led: '%1 %2 %3 음을 %4 박자로 연주하는 동안 %5 LED %6 켜기 %7', coconut_play_midi: '%1 연주하기 %2', coconut_floor_sensor: '%1 바닥센서', coconut_floor_sensing: '%1 바닥센서 %2', coconut_following_line: '선 따라가기 %1', coconut_front_sensor: '%1 전방센서', coconut_front_sensing: '%1 전방센서 %2', coconut_obstruct_sensing: '장애물 감지', coconut_avoid_mode: '어보이드 모드 %1', coconut_dotmatrix_set: '도트매트릭스 %1 ( %2줄, %3칸 ) %4', coconut_dotmatrix_on: '도트매트릭스 모두 켜기 %1', coconut_dotmatrix_off: '도트매트릭스 모두 끄기 %1', coconut_dotmatrix_num: '도트매트릭스 숫자 %1표시 %2', coconut_dotmatrix_small_eng: '도트매트릭스 소문자 %1표시 %2', coconut_dotmatrix_big_eng: '도트매트릭스 대문자 %1표시 %2', coconut_dotmatrix_kor: '도트매트릭스 한글 %1표시 %2', coconut_light_sensor: '밝기', coconut_tem_sensor: '온도', coconut_ac_sensor: '%1 가속도', coconut_outled_sensor: '외부 LED 설정 %1 %2 초동안 켜기 %3', coconut_outspk_sensor: '외부 스피커 설정 %1 %2Hz로 %3초 동안 소리내기 %4', coconut_outspk_sensor_off: '외부 스피커 %1 끄기 %2', coconut_outinfrared_sensor: '외부 적외선센서 %1', coconut_outcds_sensor: '외부 빛센서(Cds) %1', coconut_servomotor_angle: '서보모터 연결 %1 각도 %2 %3', chocopi_control_button: '%1 컨트롤 %2번을 누름', chocopi_control_event: '%1 %2 컨트롤 %3을 %4', chocopi_control_joystick: '%1 컨트롤 %2의 값', chocopi_dc_motor: '%1 DC모터 %2 %3% 세기 %4 방향 %5', chocopi_led: '%1 LED %2 RGB(%3 %4 %5) %6', chocopi_motion_photogate_event: '%1 %2 포토게이트 %3번을 %4', chocopi_motion_photogate_status: '%1 포토게이트 %2번이 막힘', chocopi_motion_photogate_time: '%1 포토게이트%2번을 %3', chocopi_motion_value: '%1 모션 %2의 값', chocopi_sensor: '%1 센서 %2', chocopi_servo_motor: '%1 서보모터 %2번 %3도 %4', chocopi_touch_event: '%1 %2 터치 %3번을 %4', chocopi_touch_status: '%1 터치 %2번을 만짐', chocopi_touch_value: '%1 터치 %2번의 값', dadublock_car_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', dadublock_car_get_analog_value: '아날로그 %1 번 센서값', dadublock_car_get_analog_value_map: '아날로그 %1번 센서값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ', dadublock_car_get_digital: '디지털 %1 번 센서값', dadublock_car_get_irsensor: '적외선 %1 번 센서값', dadublock_car_get_ultrasonic_value: '울트라소닉 Trig %1번핀 Echo %2번핀 센서값', dadublock_car_motor: '모터 %1 번을 %2 (으)로 %3 %의 속도로 움직이기 %4', dadublock_car_motor_stop: '모터 %1 번 멈추기 %2', dadublock_car_set_servo: '서보모터 %1 번 핀을 %2 의 각도로 정하기 %3', dadublock_car_set_tone: '디지털 %1 번 핀 을 %2 음으로 %3의 옥타브로 %4 만큼 연주하기 %5', dadublock_car_toggle_led: '디지털 %1 번 핀 %2 %3', dadublock_get_digital: '디지털 %1 번 센서값', ev3_get_sensor_value: '%1 의 값', ev3_touch_sensor: '%1 의 터치센서가 작동되었는가?', ev3_color_sensor: '%1 의 %2 값', ev3_motor_power: '%1 의 값을 %2 으로 출력 %3', ev3_motor_power_on_time: '%1 의 값을 %2 초 동안 %3 으로 출력 %4', ev3_motor_degrees: '%1 의 값을 %2 으로 %3 도 만큼 회전 %4', rokoboard_get_sensor_value_by_name: '%1 의 센서값', ardublock_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', ardublock_get_analog_value: '아날로그 %1 번 센서값', ardublock_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', ardublock_get_digital: '디지털 %1 번 센서값', ardublock_get_left_cds_analog_value: '왼쪽 조도센서 %1 센서값', ardublock_get_right_cds_analog_value: '오른쪽 조도센서 %1 센서값', ardublock_get_sound_analog_value: '사운드(소리) 센서 %1 센서값', ardublock_get_ultrasonic_value: '초음파센서 Trig %1 Echo %2 센서값', ardublock_set_left_motor: '왼쪽모터를 %1 으로 %2 회전 속도로 정하기 %3', ardublock_set_right_motor: '오른쪽모터를 %1 으로 %2 회전 속도로 정하기 %3', ardublock_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', ardublock_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', ardublock_toggle_led: '디지털 %1 번 핀 %2 %3', ardublock_toggle_left_led: '왼쪽 라이트 %1 번 핀 %2 %3', ardublock_toggle_right_led: '오른쪽 라이트 %1 번 핀 %2 %3', mkboard_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', mkboard_get_analog_value: '아날로그 %1 번 센서값', mkboard_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', mkboard_get_digital: '디지털 %1 번 센서값', mkboard_get_ultrasonic_value: '초음파센서 Trig %1 Echo %2 센서값', mkboard_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', mkboard_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', mkboard_toggle_led: '디지털 %1 번 핀 %2 %3', mkboard_set_lcd: '1602 문자 LCD %1 행 , %2열에 %3 출력하기 %4', mkboard_lcd_command: '1602 문자 LCD %1 명령실행하기 %2', altino_analogValue: '알티노 %1 센서값', altino_dot_display: '전광판에 %1 글자 표시하기 %2', altino_dot_display_line: '1열 %1 2열 %2 3열 %3 4열 %4 5열 %5 6열 %6 7열 %7 8열 %8 출력하기 %9', altino_light: '%1 등을 %2 %3', altino_rear_wheel: '뒷바퀴 오른쪽 %1 왼쪽 %2 로 정하기 %3', altino_sound: '%1 옥타브 %2 음을 연주하기 %3', altino_steering: '방향을 %1 로 정하기 %2', jdkit_altitude: '드론을 %1 높이만큼 날리기 %2', jdkit_button: '%1번 버튼 값 읽어오기', jdkit_connect: '드론 연결 상태 읽어오기', jdkit_emergency: '드론을 즉시 멈추기 %1', jdkit_gyro: '보드 %1 기울기 값 읽어오기', jdkit_joystick: '조이스틱 %1 읽기', jdkit_led: '%1 LED %2 %3', jdkit_motor: '%1 모터를 %2 세기로 돌리기 %3', jdkit_ready: '드론 비행 준비 상태 읽어오기', jdkit_rollpitch: '드론을 %1 방향 %2 세기로 움직이기 %3', jdkit_throttle: '드론 프로펠러를 %1 만큼 세기로 돌리기 %2', jdkit_tune: '%1 음을 %2 초동안 소리내기 %3', jdkit_ultrasonic: '거리(초음파)값 읽어오기', jdkit_yaw: '드론을 %1 만큼 회전하기 %2', memaker_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', memaker_get_analog_value: '아날로그 %1 번 센서값', memaker_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', memaker_get_digital: '디지털 %1 번 센서값', memaker_get_ultrasonic_value: '초음파센서 Trig %1 Echo %2 센서값', memaker_set_lcd: '1602 문자 LCD %1 행 , %2열에 %3 출력하기 %4', memaker_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', memaker_toggle_led: '디지털 %1 번 핀 %2 %3', memaker_lcd_command: '1602 문자 LCD %1 명령실행하기 %2', edumaker_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', edumaker_get_analog_value: '아날로그 %1 번 센서값', edumaker_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', edumaker_get_digital: '디지털 %1 번 센서값', edumaker_get_ultrasonic_value: '울트라소닉 Trig %1 Echo %2 센서값', edumaker_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', edumaker_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', edumaker_toggle_led: '디지털 %1 번 핀 %2 %3', creamo_get_number_sensor_value: '가변저항_블록 %1 번 센서값 ', creamo_get_port_number: '%1', creamo_get_pwm_port_number: '%1 ', creamo_motor_port_number: '%1', creamo_toggle_led: 'LED_블록 %1 번 핀 %2 %3', creamo_toggle_motor: 'Motor_블록 %1 번 핀 %2 %3', creamo_toggle_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', mechatro_get_dc_motor_current: '%1모터 사용전류값', mechatro_get_digital: '%1 디지털 값', mechatro_get_sensor_value: '%1 센서값', mechatro_get_ultrasonic_value: '초음파센서 Trig %1 Echo %2 의 거리값 [cm]', mechatro_set_blue_pw: '블루투스 비밀번호 : %1%2%3%4로 정하기%5', mechatro_set_dc_motor: '%1모터 속도 %2로 정하기%3', mechatro_set_digital: '%1번 %2 %3', mechatro_set_pwm: '%1PWM을 %2%로 정하기 %3', mechatro_set_servo_position: '%1서보모터 위치 :%2도로 옮기기 %3', mechatro_set_servo_speed: '%1서보모터 속도 : 1초당 %2도로 정하기 %3', mechatro_set_threshold: '%1 센서 감도 : %2로 정하기%3', mechatro_set_tone: '%1버저 %2 %3 음으로 연주 %4', mechatro_set_tone_time: '%1버저 %2 %3 음으로 %4 초 연주 %5', funboard_buzzer_onoff: '버저 %1 %2', funboard_buzzer_second: '버저%1%2초 동안%3', funboard_buzzer_tone_simple: '%1%2음을%3초 연주하기%4', funboard_color_led_on_pwm: '%1색 LED %2 % %3', funboard_color_led_onoff: '%1색 LED %2 %3', funboard_convert_scale: '%1값 %2~%3 에서 %4~%5 으로 변환값', funboard_dotmatrix_1column: '%1칸 %2표시하기 %3', funboard_dotmatrix_1row: '%1줄 %2표시하기 %3', funboard_dotmatrix_1row_1column: '%1%2 %3표시하기 %4', funboard_dotmatrix_64_display: '%1 (8x8)표시하기%2', funboard_dotmatrix_big_eng: '대문자 %1표시하기 %2', funboard_dotmatrix_char_display: '문자%1표시하기%2', funboard_dotmatrix_extra_char: '문자 %1표시하기 %2', funboard_dotmatrix_intensity: '밝기 %1% %2', funboard_dotmatrix_kor: '▦ 한글 %1표시하기 %2', funboard_dotmatrix_num: '숫자 %1표시하기 %2', funboard_dotmatrix_onoff: '모두 %1 %2', funboard_dotmatrix_scroll_option: '스크롤 방향%1%2', funboard_dotmatrix_scroll_rapid: '스크롤 속도 %1% %2', funboard_dotmatrix_set: '%1줄 %2칸 %3 %4', funboard_dotmatrix_small_eng: '소문자 %1표시하기 %2', funboard_dotmatrix_string_display: '문자열%1표시하기%2', funboard_dotmatrix_string_display_scroll: '문자열%1표시하기%2스크롤%3', funboard_dotmatrix_symbol: '기호 %1표시하기 %2', funboard_get_analog_sensor_2state: '%1값 %2', funboard_get_digital_button_value: '%1 버튼 값', funboard_get_number_sensor_value: '%1 값', funboard_get_touch_button_value: '%1 터치 값', funboard_set_digital_buzzer: '버저를 %1옥타브 %2음 %3초 연주%4', funboard_what_button_pressed: '%1 버튼 눌림', funboard_what_touch_button_pressed: '%1 터치됨', learning_title_image_str: '분류: 이미지 모델', learning_title_speech_str: '분류: 소리 모델', learning_title_text_str: '분류: 텍스트 모델', learning_title_number_str: '분류: 숫자 (kNN) 모델', learning_title_regression_str: '예측: 숫자 모델', learning_title_cluster_str: '군집: 숫자 모델', learning_title_logistic_regression_str: '분류: 숫자 (로지스틱 회귀) 모델', learning_title_decisiontree_str: '분류: 숫자 (결정 트리) 모델', learning_title_svm_str: '분류: 숫자 (SVM) 모델', media_pipe_title: '%1', media_pipe_video_screen: '비디오 화면 %1 %2', media_pipe_switch_camera: '%1 카메라로 바꾸기 %2', check_connected_camera: '카메라가 연결되었는가?', media_pipe_flip_camera: '비디오 화면 %1 뒤집기 %2', media_pipe_set_opacity_camera: '비디오 투명도 효과를 %1 으로 정하기 %2', media_pipe_motion_value: '%1 에서 감지한 %2 값', pose_landmarker_title: '%1', when_pose_landmarker: '%1 사람을 인식했을 때', pose_landmarker: '사람 인식 %1 %2', draw_detected_pose: '인식한 사람 %1 %2', check_detected_pose: '사람을 인식했는가?', count_detected_pose: '인식한 사람의 수', locate_to_pose: '%1 번째의 사람의 %2 (으)로 이동하기 %3', locate_time_to_pose: '%1 초 동안 %2 번째의 사람의 %3 (으)로 이동하기 %4', axis_detected_pose: '%1 번째 사람의 %2 의 %3 좌표', face_landmarker_title: '%1', when_face_landmarker: '%1 얼굴을 인식했을 때', face_landmarker: '얼굴 인식 %1 %2', draw_detected_face: '인식한 얼굴 %1 %2', check_detected_face: '얼굴을 인식했는가?', count_detected_face: '인식한 얼굴의 수', locate_to_face: '%1 번째의 얼굴의 %2 (으)로 이동하기 %3', locate_time_to_face: '%1 초 동안 %2 번째의 얼굴의 %3 (으)로 이동하기 %4', check_detected_gender: '%1 번째 얼굴의 성별이 %2 인가?', check_compare_age: '%1 번째 얼굴의 나이 %2 %3 인가?', check_detected_emotion: '%1 번째 얼굴의 감정이 %2 인가?', axis_detected_face: '%1 번째 얼굴의 %2 의 %3 좌표', get_detected_face_value: '%1 번째 얼굴의 %2', object_detector_title: '%1', when_object_detector: '%1 사물을 인식했을 때', object_detector: '사물 인식 %1 %2', draw_detected_object: '인식한 사물 %1 %2', check_detected_object: '사물을 인식했는가?', count_detected_object: '인식한 사물의 수', is_detected_among_objects: '사물 중 %1 을(를) 인식했는가?', hand_detection_title: '%1', when_hand_detection: '%1 손을 인식했을 때', hand_detection: '손 인식 %1 %2', draw_detected_hand: '인식한 손 %1 %2', check_detected_hand: '손을 인식했는가?', count_detected_hand: '인식한 손의 수', locate_to_hand: '%1 번째 손의 %2 %3 (으)로 이동하기 %4', locate_time_to_hand: '%1 초 동안 %2 번째 손의 %3 %4 (으)로 이동하기 %5', axis_detected_hand: '%1 번째 손의 %2 %3 의 %4 좌표', is_which_hand: '%1 번째 손이 %2 인가?', is_which_gesture: '%1 번째 손의 모양이 %2 인가?', get_which_hand: '%1 번째 손', get_which_gesture: '%1 번째 손의 모양', function_create_value: '함수 정의하기 %1 %2 %3 결괏값을 %4 (으)로 정하기', run: '', reverse_of_string: '%1 %2 %3', video_capture_for_image_test: '비디오 화면을 학습한 모델로 분류 %1 %2', }; Lang.TextCoding = { block_name: '블록명', title_syntax: '문법오류 ', title_converting: '변환오류', message_syntax_default: '문법에 오류가 있습니다', message_syntax_unexpected_token: '문법에 맞지 않는 토큰이 포함되어 있습니다', message_syntax_reserved_token: '사용할 수 없는 변수명입니다.', message_syntax_reserved_token_list: '사용할 수 없는 리스트명입니다.', message_syntax_unexpected_character: '문법에 맞지 않는 문자가 포함되어 있습니다', message_syntax_unexpected_indent: '문법에 맞지 않는 띄어쓰기가 포함되어 있습니다', message_conv_default: '지원하지 않는 코드입니다', message_conv_no_support: '변환될 수 없는 코드입니다', message_conv_no_variable: '변수가 선언되지 않았습니다', message_conv_no_list: '리스트가 선언되지 않았습니다', message_conv_no_object: '객체는 지원되지 않습니다', message_conv_no_function: '함수가 변환될 수 없습니다', message_conv_no_entry_event_function: '엔트리 이벤트 함수는 다른 함수 안에 존재할 수 없습니다.', message_conv_undefined_function: '정의되지 않은 명령어 입니다. 명령어가 올바르게 입력되었는지 확인해주세요.', message_conv_is_expect1: '올바르지 않은 문법입니다. ', message_conv_is_expect2: ' 가 올바르게 입력되었는지 확인해주세요.', message_conv_instead: '올바르지 않은 문법입니다. %1 대신 %2 가 필요합니다.', message_conv_is_wrong1: '올바르지 않은 문법입니다. ', message_conv_is_wrong2: '(은/는) 올 수 없는 위치입니다.', message_conv_or: ' 나 ', subject_syntax_default: '기타', subject_syntax_token: '토큰', subject_syntax_character: '문자', subject_syntax_indent: '띄워쓰기', subject_conv_default: '기타', subject_conv_general: '일반', subject_conv_variable: '변수', subject_conv_list: '리스트', subject_conv_object: '객체', subject_conv_function: '함수', alert_variable_empty_text: '등록된 변수 중에 공백(띄어쓰기)이 포함된 변수가 있으면 모드 변환을 할 수 없습니다.', alert_list_empty_text: '등록된 리스트 중에 공백(띄어쓰기)이 포함된 리스트가 있으면 모드 변환을 할 수 없습니다.', alert_function_name_field_multi: '등록된 함수 중에 함수 이름에 [이름] 블록이 두번이상 포함되어 있으면 모드 변환을 할 수 없습니다.', alert_function_name_disorder: '등록된 함수 중에[이름] 블록이 [문자/숫자값] 또는 [판단값] 블록보다 뒤에 쓰이면 모드 변환을 할 수 없습니다.', alert_function_has_boolean: '엔트리파이선으로 변환 후 다시 블록코딩으로 모드로 변경하면 함수에 사용된 [판단값]은 모두 [문자/숫자형]으로 변환됩니다.', alert_function_editor: '함수 생성 및 편집 중에는 모드 변환을 할 수 없습니다.', alert_function_no_support: '텍스트모드에서는 함수 생성 및 편집을 할 수 없습니다.', alert_list_no_support: '텍스트모드에서는 리스트 생성 및 편집을 할 수 없습니다.', alert_variable_no_support: '텍스트모드에서는 변수 생성 및 편집을 할 수 없습니다.', alert_signal_no_support: '텍스트모드에서는 신호 생성 및 편집을 할 수 없습니다.', alert_legacy_no_support: '전환할 수 없는 블록이 존재하여 모드 변환을 할 수 없습니다.', alert_variable_empty_text_add_change: '변수명 공백(띄어쓰기)이 포함될 수 없습니다.', alert_list_empty_text_add_change: '리스트명에 공백(띄어쓰기)이 포함될 수 없습니다.', alert_list_contains_exceed_length_value: '리스트 항목에 15자리 이상의 수가 입력되어 있으면 모드 변환을 할 수 없습니다.', alert_function_name_empty_text_add_change: '함수명에 공백(띄어쓰기)이 포함될 수 없습니다.', alert_no_save_on_error: '문법 오류가 존재하여 작품을 저장할 수 없습니다.', alert_api_no_support: '작품에 엔트리파이썬에서 지원하지 않는 \n블록이 조립되어 있습니다. \n해당 블록을 삭제하고 만들기 모드를 변경할까요?', warn_unnecessary_arguments: '&(calleeName)(); 는 괄호 사이에 값이 입력될 필요가 없는 명령어 입니다. (line:&(lineNumber))', python_code: ' 오브젝트의 파이선 코드', eof: '줄바꿈', newline: '줄바꿈', indent: '들여쓰기', num: '숫자', string: '문자열', name: '변수명', }; Lang.PythonHelper = { when_run_button_click_desc: '[시작하기]버튼을 클릭하면 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_run_button_click_exampleCode: 'def when_start():\n Entry.print("안녕!")', when_run_button_click_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕!"이라 말합니다.', when_some_key_pressed_desc: 'A키를 누르면 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_some_key_pressed_elements: 'A-- 아래 선택지 중 하나\n① 알파벳 : "A", "B" ~ "Z" 등(소문자 가능)\n② 숫자 : 1, 2, 3, 4 ~ 9, 0\n③ 특수키 : "space", "enter"\n④ 방향키 : "up", "down", "right", "left"', when_some_key_pressed_exampleCode: 'def when_press_key("W"):\n Entry.move_to_direction(10)\n\ndef when_press_key(1):\n Entry.add_size(10)', when_some_key_pressed_exampleDesc: 'W키를 누르면 오브젝트가 이동방향으로 10만큼 이동하고, 1키를 누르면 오브젝트의 크기가 10만큼 커집니다.', mouse_clicked_desc: '마우스를 클릭했을 때 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', mouse_clicked_exampleCode: 'def when_click_mouse_on():\n Entry.add_size(10)\n Entry.move_to_direction(10)', mouse_clicked_exampleDesc: '마우스를 클릭하면 오브젝트의 크기가 10만큼 커지면서 이동방향으로 10만큼 이동합니다.', mouse_click_cancled_desc: '마우스 클릭을 해제했을 때 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', mouse_click_cancled_exampleCode: 'def when_click_mouse_off():\n Entry.move_to_direction(-10)\n\ndef when_click_mouse_on():\n Entry.move_to_direction(10)', mouse_click_cancled_exampleDesc: '마우스를 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 마우스 클릭을 해제하면 오브젝트가 이동방향으로 -10만큼 이동합니다.', when_object_click_desc: '해당 오브젝트를 클릭했을 때 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_object_click_exampleCode: 'def when_click_object_on():\n Entry.print_for_sec("회전!", 0.5)\n Entry.add_rotation(90)', when_object_click_exampleDesc: '오브젝트를 클릭하면 오브젝트가 "회전!"이라 말하고, 90도 만큼 회전합니다.', when_object_click_canceled_desc: '해당 오브젝트 클릭을 해제했을 때 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_object_click_canceled_exampleCode: 'def when_click_object_on():\n Entry.add_rotation(90)\n\ndef when_click_object_off():\n Entry.add_rotation(-90)', when_object_click_canceled_exampleDesc: '오브젝트를 클릭하면 오브젝트가 90도 만큼 회전하고, 오브젝트 클릭을 해제하면 오브젝트가 -90도 만큼 회전합니다.', when_message_cast_desc: 'A 신호를 받으면 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.\n만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.', when_message_cast_elements: 'A-- "신호 이름"', when_message_cast_exampleCode: 'def when_click_mouse_on():\n Entry.send_signal("신호")\n\ndef when_get_signal("신호"):\n Entry.print_for_sec("안녕! 반가워", 0.5)', when_message_cast_exampleDesc: '마우스를 클릭하면 "신호"를 보내고, "신호"를 받았을때 "안녕! 반가워"라고 0.5초간 말합니다.', message_cast_desc: 'A에 입력된 신호를 보냅니다.\n만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.', message_cast_elements: 'A-- "신호 이름"', message_cast_exampleCode: '#"오브젝트1"의 파이선 코드\ndef when_start():\n Entry.print_for_sec("안녕! 넌 몇살이니?", 2)\n Entry.send_signal("신호")\n\n#"오브젝트2"의 파이선 코드\ndef when_get_signal("신호"):\n Entry.print_for_sec("안녕? 난 세 살이야.", 2)', message_cast_exampleDesc: '[시작하기]버튼을 클릭하면 "오브젝트1"이 "안녕! 넌 몇살이니?"라고 2초간 말하고 "신호를 보냅니다., "오브젝트2"가 "신호"를 받았을때 "안녕? 난 세 살이야."라고 2초간 말합니다.', message_cast_wait_desc: 'A에 입력된 신호를 보내고, 해당 신호를 받는 명령어들의 실행이 끝날 때까지 기다립니다.\n만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.', message_cast_wait_elements: 'A-- "신호 이름"', message_cast_wait_exampleCode: '#"오브젝트1"의 파이선 코드\ndef when_start():\n Entry.print_for_sec("숨바꼭질하자!", 2)\n Entry.send_signal_wait("신호")\n Entry.hide()\n\n#"오브젝트2"의 파이선 코드\ndef when_get_signal("신호"):\n Entry.print_for_sec("그래!", 2)', message_cast_wait_exampleDesc: '[시작하기]버튼을 클릭하면 "오브젝트1"이 "숨바꼭질하자!"라고 2초 동안 말하고 "신호"를 보낸 후 기다립니다. "오브젝트2"가 "신호"를 받으면 "그래!"를 2초 동안 말합니다. "오브젝트1"이 그 후에 모양을 숨깁니다.', when_scene_start_desc: '장면이 시작되면 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_scene_start_exampleCode: '#"장면 1"의 파이선 코드\ndef when_start():\n Entry.print_for_sec("다른 곳으로 가볼까?", 2)\n Entry.start_scene("장면 2")\n\n#"장면 2"의 파이선 코드\ndef when_start_scene():\n Entry.print("여기가 어디지?")', when_scene_start_exampleDesc: '"장면 1"에서 [시작하기]버튼을 클릭하면 "다른 곳으로 가볼까?"라고 2초간 말하고, "장면 2"가 시작됩니다. "장면 2"가 시작되면 오브젝트가 "여기가 어디지?"라고 말합니다.', start_scene_desc: 'A 장면을 시작합니다.', start_scene_elements: 'A-- "장면 이름"', start_scene_exampleCode: '#"장면 1"의 파이선 코드\ndef when_click_object_on():\n Entry.start_scene("장면 2")', start_scene_exampleDesc: '"장면 1"에서 해당 오브젝트를 클릭하면 "장면 2"가 시작됩니다.', start_neighbor_scene_desc: 'A에 입력한 다음 또는 이전 장면을 시작합니다.', start_neighbor_scene_elements: 'A-- 아래 선택지 중 하나\n① 다음 장면: "next" 또는 "다음"\n② 이전 장면: "prev" 또는 "이전"', start_neighbor_scene_exampleCode: '#"장면 1"의 파이선 코드\ndef when_press_key("right"):\n Entry.start_scene_of("next")\n\n#"장면 2"의 파이선 코드\ndef when_press_key("left"):\n Entry.start_scene_of("prev")', start_neighbor_scene_exampleDesc: '"장면 1"에서 오른쪽화살표키를 누르면 다음 장면이, "장면 2"에서 왼쪽화살표키를 누르면 이전 장면이 시작됩니다.', wait_second_desc: 'A초만큼 기다린 후 다음 블록을 실행합니다.', wait_second_elements: 'A-- 초에 해당하는 수 입력', wait_second_exampleCode: 'def when_start():\n Entry.add_effect("color", 10)\n Entry.wait_for_sec(2)\n Entry.add_size(10)', wait_second_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트에 색깔효과를 10만큼 주고, 2초동안 기다린 다음 크기를 10만큼 커지게 합니다.', repeat_basic_desc: '아래 명령어들을 A번 반복하여 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', repeat_basic_elements: 'A-- 반복할 횟수 입력', repeat_basic_exampleCode: 'def when_start():\n for i in range(10):\n Entry.move_to_direction(10)\n Entry.stamp()', repeat_basic_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 도장찍는 행동을 10번 반복합니다.', repeat_inf_desc: 'A 판단이 True인 동안 아래 명령어들을 반복 실행합니다. A에 True를 입력하면 계속 반복됩니다. \n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', repeat_inf_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', repeat_inf_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n Entry.bounce_on_edge()', repeat_inf_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 계속해서 이동방향으로 10만큼 이동하고, 벽에 닿으면 튕깁니다.', repeat_while_true_desc: 'A 판단이 True가 될 때까지 아래 명령어들을 반복 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', repeat_while_true_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', repeat_while_true_exampleCode: 'def when_start():\n while not Entry.is_key_pressed("space"):\n Entry.add_rotation(90)', repeat_while_true_exampleDesc: '[시작하기]버튼을 클릭하면 스페이스키를 누를때까지 오브젝트가 90도 만큼 회전합니다.', stop_repeat_desc: "이 블록을 감싸는 가장 가까운 블록을 멈춥니다.\n '반복하기'블록과 같이 ㄷ자 모양으로 다른 블록을 감싼 블록에 조립해 사용할 수 있습니다.", stop_repeat_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n if Entry.is_key_pressed("enter"):\n break', stop_repeat_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 계속 이동합니다. 엔터키를 누르면 반복이 중단됩니다.', _if_desc: 'A 부분의 판단이 True이면 if A:아래 명령어들을 실행하고, False이면 실행하지 않습니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', _if_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', _if_exampleCode: 'def when_click_mouse_on():\n if (Entry.value_of_mouse_pointer("x") > 0):\n Entry.print_for_sec("오른쪽!", 0.5)', _if_exampleDesc: '마우스를 클릭했을 때 마우스 x좌표가 0보다 크면 오브젝트가 "오른쪽!"이라고 0.5초 동안 말합니다.', if_else_desc: 'A 부분의 판단이 True이면 if A: 아래 명령어들을 실행하고, False이면 else: 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', if_else_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', if_else_exampleCode: 'def when_click_mouse_on():\n if Entry.is_touched("mouse_pointer"):\n Entry.print("닿았다!")\n else:\n Entry.print("안 닿았다!")', if_else_exampleDesc: '마우스를 클릭했을 때 마우스포인터가 오브젝트에 닿았으면 "닿았다!"를 그렇지 않으면 "안 닿았다!"를 말합니다.', wait_until_true_desc: 'A 부분의 판단이 True가 될 때까지 코드의 실행을 멈추고 기다립니다.', wait_until_true_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', wait_until_true_exampleCode: 'def when_start():\n Entry.print("엔터를 눌러봐!")\n Entry.wait_until(Entry.is_key_pressed("enter"))\n Entry.print("잘했어!")', wait_until_true_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "엔터를 눌러봐!"라 말하고, 엔터키를 누를 때까지 기다립니다. 엔터키를 누르면 "잘했어!"라 말합니다.', stop_object_desc: 'A코드의 실행을 중지합니다.', stop_object_elements: 'A-- 아래 선택지 중 하나\n① "all": 모든 오브젝트의 모든 코드\n② "self" : 해당 오브젝트의 모든 코드\n③ "this": 이 명령어가 포함된 코드\n④ "others" : 해당 오브젝트의 코드 중 이 명령어가 포함된 코드를 제외한 모든 코드\n⑤ "ohter_objects" : 이 오브젝트를 제외한 다른 모든 오브젝트의 코드', stop_object_exampleCode: 'def when_start():\n while True:\n Entry.move_to("mouse_pointer")\n\ndef when_press_key("space"):\n Entry.stop_code("all")\n', stop_object_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 계속해서 마우스포인터 위치로 이동합니다. 스페이스키를 누르면 모든 코드의 실행이 중지됩니다.', restart_project_desc: '작품을 처음부터 다시 실행합니다.', restart_project_exampleCode: 'def when_start():\n while True:\n Entry.add_size(10)\n\ndef when_press_key("enter"):\n Entry.start_again()', restart_project_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트의 크기가 커집니다. 엔터키를 누르면 작품을 처음부터 다시 실행합니다.', when_clone_start_desc: '해당 오브젝트의 복제본이 새로 생성되었을 때 아래 명령어들을 실행합니다.\n아래 명령어는 [Tab]키를 통해 들여쓰기합니다.', when_clone_start_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("self")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))', when_clone_start_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다.', create_clone_desc: 'A 오브젝트의 복제본을 생성합니다.', create_clone_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "self" 또는 "자신"', create_clone_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("self")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))', create_clone_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다.', delete_clone_desc: 'Entry.make_clone_of(A) 명령에 의해 생성된 복제본을 삭제합니다.', delete_clone_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("자신")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))\n\ndef when_click_object_on():\n Entry.remove_this_clone()', delete_clone_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다. 복제본을 클릭하면 클릭된 복제본을 삭제합니다.', remove_all_clones_desc: '해당 오브젝트의 모든 복제본을 삭제합니다.', remove_all_clones_exampleCode: 'def when_start():\n for i in range(5):\n Entry.make_clone_of("자신")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))\n\ndef when_press_key("space"):\n Entry.remove_all_clone()', remove_all_clones_exampleDesc: '[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다. 스페이스 키를 누르면 모든 복제본을 삭제합니다.', move_direction_desc: 'A만큼 오브젝트의 이동방향 화살표가 가리키는 방향으로 움직입니다.', move_direction_elements: 'A-- 이동할 거리에 해당하는 수', move_direction_exampleCode: 'def when_start():\n Entry.move_to_direction(10)', move_direction_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동합니다.', bounce_wall_desc: '오브젝트가 화면 끝에 닿으면 튕겨져 나옵니다.', bounce_wall_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n Entry.bounce_on_edge()', bounce_wall_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 계속해서 이동방향으로 10만큼 이동하고, 벽에 닿으면 튕깁니다.', move_x_desc: '오브젝트의 x좌표를 A만큼 바꿉니다.', move_x_elements: 'A-- x좌표의 변화 값\n① 양수: 오브젝트가 오른쪽으로 이동합니다.\n② 음수: 오브젝트가 왼쪽으로 이동합니다.', move_x_exampleCode: 'def when_start():\n Entry.add_x(10)\n Entry.wait_for_sec(2)\n Entry.add_x(-10)', move_x_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오른쪽으로 10만큼 이동하고 2초 동안 기다린 후 왼쪽으로 10만큼 이동합니다.', move_y_desc: '오브젝트의 y좌표를 A만큼 바꿉니다.', move_y_elements: 'A-- y좌표의 변화 값\n① 양수: 오브젝트가 위쪽으로 이동합니다.\n② 음수: 오브젝트가 아래쪽으로 이동합니다.', move_y_exampleCode: 'def when_start():\n Entry.add_y(10)\n Entry.wait_for_sec(2)\n Entry.add_y(-10)', move_y_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 위쪽으로 10만큼 이동하고 2초 동안 기다린 후 아래쪽으로 10만큼 이동합니다.', move_xy_time_desc: '오브젝트가 x와 y좌표를 각각 A와 B만큼 C초에 걸쳐 서서히 바꿉니다.', move_xy_time_elements: 'A-- x좌표의 변화 값\n① 양수: 오브젝트가 오른쪽으로 이동합니다.\n② 음수: 오브젝트가 왼쪽으로 이동합니다.%nextB-- y좌표의 변화 값\n① 양수: 오브젝트가 위쪽으로 이동합니다.\n② 음수: 오브젝트가 아래쪽으로 이동합니다.%nextC-- 이동하는 시간(초)', move_xy_time_exampleCode: 'def when_start():\n Entry.add_xy_for_sec(100, 100, 2)\n Entry.add_xy_for_sec(-100, -100, 2)', move_xy_time_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오른쪽 위로 100만큼 2초 동안 이동한 후 왼쪽 아래로 100만큼 2초 동안 이동합니다.', locate_x_desc: '오브젝트의 x좌표를 A로 정합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_x_elements: 'A-- 이동할 x좌표', locate_x_exampleCode: 'def when_press_key("right"):\n Entry.set_x(100)\n\ndef when_press_key("left"):\n Entry.set_x(-100)\n', locate_x_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 x좌표를 100으로 정하고, 왼쪽화살표키를 누르면 오브젝트의 x좌표를 -100으로 정합니다.', locate_y_desc: '오브젝트의 y좌표를 A로 정합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_y_elements: 'B-- 이동할 y좌표', locate_y_exampleCode: 'def when_press_key("up"):\n Entry.set_y(100)\n\ndef when_press_key("down"):\n Entry.set_y(-100)', locate_y_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 y좌표를 100으로 정하고, 아래쪽화살표키를 누르면 오브젝트의 y좌표를 -100으로 정합니다.', locate_xy_desc: '오브젝트가 좌표(A, B)로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_xy_elements: 'A-- 이동할 x좌표%nextB-- 이동할 y좌표', locate_xy_exampleCode: 'def when_click_mouse_on():\n Entry.set_xy(0, 0)\n\ndef when_press_key("right"):\n Entry.add_x(10)\n\ndef when_press_key("up"):\n Entry.add_y(10)', locate_xy_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 x좌표를 10만큼 바꾸고, 위쪽화살표키를 누르면 오브젝트의 y좌표를 10만큼 바꿉니다. 마우스를 클릭하면 오브젝트의 x, y좌표를 0으로 정합니다.', locate_xy_time_desc: '오브젝트가 좌표(A, B)로 C초에 걸쳐 서서히 이동합니다.(오브젝트의 중심점이 기준이 됩니다.)', locate_xy_time_elements: 'A-- 이동할 x좌표%nextB-- 이동할 y좌표%nextC-- 이동하는 시간', locate_xy_time_exampleCode: 'def when_click_mouse_on():\n Entry.set_xy_for_sec(0, 0, 2)\n\ndef when_press_key("right"):\n Entry.add_x(10)\n\ndef when_press_key("up"):\n Entry.add_y(10)', locate_xy_time_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 x좌표를 10만큼 바꾸고, 위쪽화살표키를 누르면 오브젝트의 y좌표를 10만큼 바꿉니다. 마우스를 클릭하면 2초 동안 오브젝트를 x,y 좌표 0으로 이동시킵니다.', locate_desc: '오브젝트가 A의 위치로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "mouse_pointer" 또는 "마우스포인터"', locate_exampleCode: 'def when_click_mouse_on():\n Entry.move_to("mouse_pointer")\n\ndef when_press_key("space"):\n Entry.move_to("오브젝트")', locate_exampleDesc: '마우스를 클릭하면 오브젝트가 마우스포인터 위치로 이동합니다.\n스페이스키를 누르면 오브젝트가 "오브젝트" 위치로 이동합니다.', locate_object_time_desc: '오브젝트가 A의 위치로 B초에 걸쳐 서서히 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)', locate_object_time_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "mouse_pointer" 또는 "마우스포인터" %nextB-- 이동하는 시간(초)', locate_object_time_exampleCode: 'def when_click_mouse_on():\n Entry.move_to_for_sec("mouse_pointer", 2)', locate_object_time_exampleDesc: '마우스를 클릭하면 오브젝트가 2초 동안 서서히 마우스포인터 위치로 이동합니다.', rotate_relative_desc: '오브젝트의 방향을 A도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', rotate_relative_elements: 'A-- 회전할 각도', rotate_relative_exampleCode: 'def when_click_object_on():\n Entry.add_rotation(90)\n\ndef when_click_object_off():\n Entry.add_rotation(-90)', rotate_relative_exampleDesc: '오브젝트를 클릭하면 오브젝트가 90도 만큼 회전하고, 오브젝트 클릭을 해제하면 오브젝트가 -90도 만큼 회전합니다.', direction_relative_desc: '오브젝트의 이동 방향을 A도만큼 회전합니다.', direction_relative_elements: 'A-- 회전할 각도', direction_relative_exampleCode: 'def when_start():\n Entry.move_to_direction(50)\n Entry.wait_for_sec(0.5)\n Entry.add_direction(90)\n Entry.wait_for_sec(0.5)\n Entry.move_to_direction(50)', direction_relative_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 50만큼 이동한 다음 0.5초간 기다립니다. 그 후 이동방향을 90도 만큼 회전하고 0.5초간 기다린 후 이동방향으로 50만큼 이동합니다.', rotate_by_time_desc: '오브젝트의 방향을 시계방향으로 A도만큼 B초에 걸쳐 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', rotate_by_time_elements: 'A-- 회전할 각도%nextB-- 회전할 시간(초)', rotate_by_time_exampleCode: 'def when_start():\n Entry.add_rotation_for_sec(90, 2)\n Entry.add_rotation_for_sec(-90, 2)', rotate_by_time_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 2초 동안 90도 만큼 회전하고, 다시 2초 동안 -90도 만큼 회전합니다.', direction_relative_duration_desc: '오브젝트의 이동방향을 시계방향으로 A도만큼 B초에 걸쳐 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)', direction_relative_duration_elements: 'A-- 회전할 각도%nextB-- 회전할 시간(초)', direction_relative_duration_exampleCode: 'def when_start():\n Entry.add_direction_for_sec(90, 2)\n\ndef when_start():\n while True:\n Entry.move_to_direction(1)', direction_relative_duration_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트의 이동방향을 2초 동안 90도만큼 회전시킵니다. 동시에 오브젝트는 이동방향으로 1만큼 계속 이동합니다.', rotate_absolute_desc: '오브젝트의 방향을 A로 정합니다.', rotate_absolute_elements: 'A-- 설정할 방향', rotate_absolute_exampleCode: 'def when_press_key("right"):\n Entry.set_rotation(90)\n\ndef when_press_key("left"):\n Entry.set_rotation(270)', rotate_absolute_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 방향을 90으로 정하고, 왼쪽화살표키를 누르면 오브젝트의 방향을 270으로 정합니다.', direction_absolute_desc: '오브젝트의 이동방향을 A로 정합니다.', direction_absolute_elements: 'A-- 설정할 이동방향', direction_absolute_exampleCode: 'def when_press_key("right"):\n Entry.set_direction(90)\n Entry.move_to_direction(10)\n\ndef when_press_key("left"):\n Entry.set_direction(270)\n Entry.move_to_direction(10)', direction_absolute_exampleDesc: '오른쪽화살표키를 누르면 오브젝트의 이동방향을 90으로 정한 후 해당 쪽으로 10만큼 이동하고, 왼쪽화살표키를 누르면 오브젝트의 이동방향을 270으로 정하고 해당쪽으로 10만큼 이동합니다.', see_angle_object_desc: '오브젝트가 A쪽을 바라봅니다. (이동방향이 A를 향하도록 오브젝트의 방향을 회전해줍니다.)', see_angle_object_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "mouse_pointer" 또는 "마우스포인터"', see_angle_object_exampleCode: 'def when_click_mouse_on():\n Entry.look_at("mouse_pointer")\n\ndef when_press_key("space"):\n Entry.look_at("오브젝트")', see_angle_object_exampleDesc: '마우스를 클릭하면 오브젝트가 마우스포인터쪽을 바라보고, 스페이스키를 누르면 "오브젝트"쪽을 바라봅니다.', move_to_angle_desc: '오브젝트가 A만큼 B방향으로 움직입니다.', move_to_angle_elements: 'A-- 이동할 거리에 해당하는 수%nextB-- 이동할 방향(12시 방향이 0도, 시계방향으로 증가)', move_to_angle_exampleCode: 'def when_press_key("up"):\n Entry.move_to_degree(10, 0)\n\ndef when_press_key("down"):\n Entry.move_to_degree(10, 180)', move_to_angle_exampleDesc: '위쪽화살표키를 누르면 오브젝트가 0도방향으로 10만큼 이동하고, 아래쪽화살표키를 누르면 오브젝트가 180도방향으로 10만큼 이동합니다.', show_desc: '오브젝트를 화면에 나타냅니다.', show_exampleCode: 'def when_start():\n Entry.wait_for_sec(1)\n Entry.hide()\n Entry.wait_for_sec(1)\n Entry.show()', show_exampleDesc: '[시작하기]버튼을 클릭하면 1초 뒤에 오브젝트 모양이 숨겨지고, 다음 1초 뒤에 오브젝트 모양이 나타납니다.', hide_desc: '오브젝트를 화면에서 보이지 않게 합니다.', hide_exampleCode: 'def when_start():\n Entry.wait_for_sec(1)\n Entry.hide()\n Entry.wait_for_sec(1)\n Entry.show()', hide_exampleDesc: '[시작하기]버튼을 클릭하면 1초 뒤에 오브젝트 모양이 숨겨지고, 다음 1초 뒤에 오브젝트 모양이 나타납니다.', dialog_time_desc: '오브젝트가 A를 B초 동안 말풍선으로 말한 후 다음 명령어가 실행됩니다. 콘솔창에서도 실행 결과를 볼 수 있습니다.', dialog_time_elements: 'A-- 말할 내용\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등%nextB-- 말하는 시간(초)', dialog_time_exampleCode: 'def when_start():\n Entry.print_for_sec("안녕! 나는", 2)\n Entry.print_for_sec(16, 2)\n Entry.print_for_sec("살이야", 2)', dialog_time_exampleDesc: '[시작하기]버튼을 클릭하면 "안녕! 나는", 16, "살이야"를 각각 2초 동안 차례대로 말합니다.', dialog_desc: '오브젝트가 A를 말풍선으로 말합니다. 콘솔창에서도 실행 결과를 볼 수 있습니다.', dialog_elements: 'A-- 말할 내용\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', dialog_exampleCode: 'def when_start():\n Entry.print("키보드로 숫자 1,2 를 누르면 숫자를 말해볼게")\n\ndef when_press_key(1):\n Entry.print(1)\n\ndef when_press_key(2):\n Entry.print(2)\n', dialog_exampleDesc: '[시작하기]버튼을 클릭하면 "키보드로 숫자 1,2 를 누르면 숫자를 말해볼게"를 말하고, 키보드로 1, 2를 누르면 각각 1, 2라 말합니다.', remove_dialog_desc: '오브젝트가 말하고 있는 말풍선을 지웁니다.', remove_dialog_exampleCode: 'def when_start():\n Entry.print("말풍선을 지우려면 엔터를 눌러!")\n\ndef when_press_key("enter"):\n Entry.clear_print()', remove_dialog_exampleDesc: '[시작하기]버튼을 클릭하면 "말풍선을 지우려면 엔터를 눌러!"라 말하고, 엔터키를 누르면 말풍선이 사라집니다.', change_to_some_shape_desc: '오브젝트를 A 모양으로 바꿉니다.', change_to_some_shape_elements: 'A-- 아래 선택지 중 하나\n① 모양 이름 : [속성] 탭의 "모양 이름"을 적음\n② 모양 번호 : [속성] 탭의 모양 번호를 적음', change_to_some_shape_exampleCode: 'def when_start():\n Entry.wait_for_sec(0.3)\n Entry.change_shape("오브젝트모양")\n Entry.wait_for_sec(0.3)\n Entry.change_shape("오브젝트모양")', change_to_some_shape_exampleDesc: '[시작하기]버튼을 클릭하면 0.3초간 기다린 다음 "오브젝트모양"으로 모양을 바꾸고 0.3초간 기다린 다음 "오브젝트모양"모양으로 모양을 바꿉니다.', change_to_next_shape_desc: '오브젝트의 모양을 다음 또는 이전 모양으로 바꿉니다.', change_to_next_shape_elements: 'A-- 아래 선택지 중 하나\n① 다음 모양 : "next" 또는 "다음" \n② 이전 모양 : "pre" 또는 "이전"', change_to_next_shape_exampleCode: 'def when_start():\n Entry.wait_for_sec(0.3)\n Entry.change_shape_to("next")\n Entry.wait_for_sec(0.3)\n Entry.change_shape_to("pre")', change_to_next_shape_exampleDesc: '[시작하기]버튼을 클릭하면 0.3초간 기다린 다음 모양으로 오브젝트 모양을 바꾸고 0.3초간 기다린 다음 이전 모양으로 오브젝트 모양을 바꿉니다.', add_effect_amount_desc: '오브젝트에 A 효과를 B만큼 줍니다.', add_effect_amount_elements: 'A -- 아래 선택지 중 하나\n① “color” 또는 “색깔“ \n② “brightness” 또는 “밝기” \n③ “transparency” 또는 “투명도”%nextB-- 효과의 변화 정도', add_effect_amount_exampleCode: 'def when_click_mouse_on():\n Entry.add_effect("color", 50)\n Entry.wait_for_sec(1)\n Entry.add_effect("brightness", -50)\n Entry.wait_for_sec(1)\n Entry.add_effect("transparency", 50)', add_effect_amount_exampleDesc: '마우스를 클릭하면 오브젝트에 색깔 효과를 50만큼 주고 1초간 기다리고, 밝기 효과를 -50만큼 주고 1초간 기다립니다. 그 후 투명도 효과를 50만큼 줍니다.', change_effect_amount_desc: '오브젝트의 A 효과를 B로 정합니다.', change_effect_amount_elements: 'A-- 아래 선택지 중 하나\n① “color” 또는 “색깔“ \n② “brightness” 또는 “밝기” \n③ “transparency” 또는 “투명도”%nextB-- 효과의 값\n① color: 0~100 범위의 수, 100을 주기로 반복됨\n② brightness: -100~100 사이 범위의 수, -100이하는 -100 으로 100 이상은 100 으로 처리 됨\n③ transparency: 0~100 사이 범위의 수, 0 이하는 0으로, 100이상은 100으로 처리 됨', change_effect_amount_exampleCode: 'def when_click_mouse_on():\n Entry.set_effect("color", 50)\n Entry.set_effect("brightness", 50)\n Entry.set_effect("transparency", 50)\n\ndef when_click_mouse_off():\n Entry.set_effect("color", 0)\n Entry.set_effect("brightness", 0)\n Entry.set_effect("transparency", 0)', change_effect_amount_exampleDesc: '마우스를 클릭하면 오브젝트에 색깔, 밝기, 투명도 효과를 50으로 정하고, 마우스 클릭을 해제하면 각 효과를 0으로 정합니다.', erase_all_effects_desc: '오브젝트에 적용된 효과를 모두 지웁니다.', erase_all_effects_exampleCode: 'def when_click_mouse_on():\n Entry.set_effect("color", 50)\n Entry.set_effect("brightness", 50)\n Entry.set_effect("transparency", 50)\n\ndef when_click_mouse_off():\n Entry.clear_effect()\n', erase_all_effects_exampleDesc: '마우스를 클릭하면 오브젝트에 색깔, 밝기, 투명도 효과를 50으로 정하고, 마우스 클릭을 해제하면 오브젝트에 적용된 모든 효과를 지웁니다.', change_scale_size_desc: '오브젝트의 크기를 A만큼 바꿉니다.', change_scale_size_elements: 'A-- 크기 변화 값', change_scale_size_exampleCode: 'def when_press_key("up"):\n Entry.add_size(10)\n\ndef when_press_key("down"):\n Entry.add_size(-10)\n\ndef when_press_key("space"):\n Entry.set_size(100)', change_scale_size_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 크기가 10만큼 커지고, 아래쪽화살표키를 누르면 오브젝트의 크기가 10만큼 작아집니다. 스페이스키를 누르면 오브젝트의 크기를 100으로 정합니다.', set_scale_size_desc: '오브젝트의 크기를 A로 정합니다.', set_scale_size_elements: 'A-- 크기값', set_scale_size_exampleCode: 'def when_press_key("up"):\n Entry.add_size(10)\n\ndef when_press_key("down"):\n Entry.add_size(-10)\n\ndef when_press_key("space"):\n Entry.set_size(100)', set_scale_size_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 크기가 10만큼 커지고, 아래쪽화살표키를 누르면 오브젝트의 크기가 10만큼 작아집니다. 스페이스키를 누르면 오브젝트의 크기를 100으로 정합니다.', flip_x_desc: '오브젝트의 상하 모양을 뒤집습니다.', flip_x_exampleCode: 'def when_press_key("up"):\n Entry.flip_horizontal()\n\ndef when_press_key("right"):\n Entry.flip_vertical()', flip_x_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 상하 모양을 뒤집고, 오른쪽화살표키를 누르면 오브젝트의 좌우 모양을 뒤집습니다.', flip_y_desc: '오브젝트의 좌우 모양을 뒤집습니다.', flip_y_exampleCode: 'def when_press_key("up"):\n Entry.flip_horizontal()\n\ndef when_press_key("right"):\n Entry.flip_vertical()', flip_y_exampleDesc: '위쪽화살표키를 누르면 오브젝트의 상하 모양을 뒤집고, 오른쪽화살표키를 누르면 오브젝트의 좌우 모양을 뒤집습니다.', change_object_index_desc: '오브젝트의 레이어를 A로 가져옵니다.', change_object_index_elements: 'A-- 아래 선택지 중 하나\n① “front" 또는 “맨 앞“ \n② “forward” 또는 “앞” \n③ “backward” 또는 “뒤”\n④ “back” 또는 “맨 뒤”', change_object_index_exampleCode: 'def when_start():\n Entry.send_layer_to("front")\n Entry.wait_for_sec(2)\n Entry.send_layer_to("backward")', change_object_index_exampleDesc: '오브젝트가 여러개가 겹쳐 있을 경우 [시작하기]버튼을 클릭하면 해당 오브젝트의 레이어를 가장 앞으로 가져와서 보여줍니다.', brush_stamp_desc: '오브젝트의 모양을 도장처럼 실행화면 위에 찍습니다.', brush_stamp_exampleCode: 'def when_start():\n for i in range(10):\n Entry.move_to_direction(10)\n Entry.stamp()', brush_stamp_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 도장찍는 행동을 10번 반복합니다.', start_drawing_desc: '오브젝트가 이동하는 경로를 따라 선이 그려지기 시작합니다. (오브젝트의 중심점이 기준)', start_drawing_exampleCode: 'def when_start():\n Entry.start_drawing()\n for i in range(10):\n Entry.move_to_direction(10)', start_drawing_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 오브젝트가 이동방향으로 10만큼 10번 이동할 때 오브젝트의 이동경로를 따라 선이 그려집니다.', stop_drawing_desc: '오브젝트가 선을 그리는 것을 멈춥니다.', stop_drawing_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(1)\n\ndef when_click_mouse_on():\n Entry.stop_drawing()', stop_drawing_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고 계속해서 오브젝트가 이동방향으로 10만큼 이동합니다. 마우스를 클릭하면 그리는것을 멈춥니다.', set_color_desc: '오브젝트가 그리는 선의 색을 A로 정합니다.', set_color_elements: 'A-- 아래 선택지 중 하나\n① 색상 코드 : "#FF0000", "#FFCC00", "#3333FF", "#000000" 등\n② 색깔명 : "red", "orange", "yellow", "green", "blue", "navy", "purple", "black", "white", "brown"', set_color_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_color_to("#000099")\n while True:\n Entry.move_to_direction(1)', set_color_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 색을 "#000099"로 정합니다. 오브젝트는 계속해서 이동방향으로 1만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.', set_random_color_desc: '오브젝트가 그리는 선의 색을 무작위로 정합니다.', set_random_color_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(1)\n Entry.set_brush_color_to_random()', set_random_color_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 1만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 색깔은 계속해서 무작위로 정해집니다.', change_thickness_desc: '오브젝트가 그리는 선의 굵기를 A만큼 바꿉니다.', change_thickness_elements: 'A-- 굵기 변화 값', change_thickness_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.add_brush_size(1)\n Entry.move_to_direction(10)', change_thickness_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 굵기는 계속해서 1씩 커집니다.', set_thickness_desc: '오브젝트가 그리는 선의 굵기를 A로 정합니다.', set_thickness_elements: 'A-- 굵기값(1이상의 수)', set_thickness_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n while True:\n Entry.move_to_direction(10)', set_thickness_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.', change_brush_transparency_desc: '오브젝트가 그리는 선의 투명도를 A만큼 바꿉니다.', change_brush_transparency_elements: 'A-- 투명도 변화 값', change_brush_transparency_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n while True:\n Entry.move_to_direction(10)\n Entry.add_brush_transparency(5)', change_brush_transparency_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 투명도는 계속해서 5만큼 바꿉니다.', set_brush_tranparency_desc: '오브젝트가 그리는 선의 투명도를 A로 정합니다.', set_brush_tranparency_elements: 'A-- 투명도값(0~100 의 범위)', set_brush_tranparency_exampleCode: 'def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n Entry.set_brush_transparency(50)\n while True:\n Entry.move_to_direction(10)', set_brush_tranparency_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로, 선의 투명도를 50으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.', brush_erase_all_desc: '오브젝트가 그린 선과 도장을 모두 지웁니다.', brush_erase_all_exampleCode: 'def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(10)\n\ndef when_click_mouse_on():\n Entry.clear_drawing()', brush_erase_all_exampleDesc: '[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 마우스를 클릭하면 오브젝트가 그린 선을 모두 지웁니다.', text_read_desc: '글상자 A의 내용입니다.\n(내용 안에 개행이 있는 경우, 띄어쓰기하여 반환됩니다.)', text_read_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트(글상자) 이름" \n② 자기 자신', text_read_exampleCode: 'def when_start():\n Entry.print(Entry.contents_of_textbox("A"))', text_read_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 글상자 "A"의 내용을 말합니다.​', text_write_desc: '글상자의 내용을 A로 고쳐씁니다.', text_write_elements: 'A-- 글상자의 내용\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', text_write_exampleCode: 'def when_start():\n Entry.write_text("엔트리")', text_write_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용을 "엔트리"로 바꿉니다.', text_append_desc: '글상자의 내용 뒤에 A를 추가합니다.', text_append_elements: 'A-- 글상자의 내용\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', text_append_exampleCode: 'def when_start():\n Entry.write_text("안녕?")\n Entry.wait_for_sec(1)\n Entry.append_text("엔트리!")', text_append_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용이 "안녕?"이 되었다가 1초 뒤에 "엔트리!"가 추가되어 "안녕?엔트리!"가 됩니다.', text_prepend_desc: '글상자의 내용 앞에 A를 추가합니다.', text_prepend_elements: 'A-- 글상자의 내용\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', text_prepend_exampleCode: 'def when_start():\n Entry.write_text("반가워!")\n Entry.wait_for_sec(1)\n Entry.prepend_text("엔트리!")', text_prepend_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용이 "반가워!"가 되었다가 1초 뒤에 "엔트리!"가 앞에 추가되어 "엔트리!반가워!"가 됩니다.', text_flush_desc: '글상자에 저장된 값을 모두 지웁니다.', text_flush_exampleCode: 'def when_start():\n Entry.write_text("엔트리")\n Entry.wait_for_sec(1)\n Entry.clear_text()', text_flush_exampleDesc: '[시작하기]버튼을 클릭하면 글상자의 내용이 "엔트리"가 되었다가 1초 뒤에 모든 내용이 사라집니다.', sound_something_with_block_desc: '오브젝트가 A 소리를 재생합니다.', sound_something_with_block_elements: 'A-- 아래 선택지 중 하나\n① 소리 이름 : [속성] 탭의 "소리 이름"을 적음\n② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_with_block_exampleCode: 'def when_start():\n Entry.play_sound("소리")\n Entry.add_size(50)', sound_something_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 재생하면서 오브젝트의 크기가 50만큼 커집니다.', sound_something_second_with_block_desc: '오브젝트가 A소리를 B초 만큼 재생합니다.', sound_something_second_with_block_elements: 'A-- 아래 선택지 중 하나\n① 소리 이름 : [속성] 탭의 "소리 이름"을 적음\n② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_second_with_block_exampleCode: 'def when_start():\n Entry.play_sound_for_sec("소리", 1)\n Entry.add_size(50)', sound_something_second_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 1초 동안 재생하면서, 오브젝트의 크기가 50만큼 커집니다.', sound_from_to_desc: '오브젝트가 A소리를 B초부터 C초까지 재생합니다.', sound_from_to_elements: 'A-- 아래 선택지 중 하나\n① 소리 이름 : [속성] 탭의 "소리 이름"을 적음\n② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_from_to_exampleCode: 'def when_start():\n Entry.play_sound_from_to("소리", 0.5, 1)\n Entry.add_size(50)', sound_from_to_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 0.5초부터 1초 구간까지만 재생하면서, 오브젝트의 크기가 50만큼 커집니다.', sound_something_wait_with_block_desc: '오브젝트가 A 소리를 재생하고, 재생이 끝나면 다음 명령을 실행합니다.', sound_something_wait_with_block_elements: 'A-- 아래 선택지 중 하나\n① 소리 이름 : [속성] 탭의 "소리 이름"을 적음\n② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_wait_with_block_exampleCode: 'def when_start():\n Entry.play_sound_and_wait("소리")\n Entry.add_size(50)', sound_something_wait_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.', sound_something_second_wait_with_block_desc: '오브젝트가 A소리를 B초 만큼 재생하고, 재생이 끝나면 다음 명령을 실행합니다.', sound_something_second_wait_with_block_elements: 'A-- 아래 선택지 중 하나\n① 소리 이름 : [속성] 탭의 "소리 이름"을 적음\n② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_something_second_wait_with_block_exampleCode: 'def when_start():\n Entry.play_sound_for_sec_and_wait("소리", 1)\n Entry.add_size(50)', sound_something_second_wait_with_block_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 1초 동안 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.', sound_from_to_and_wait_desc: '오브젝트가 A소리를 B초부터 C초까지 재생하고, 재생이 끝나면 다음 명령을 실행합니다.', sound_from_to_and_wait_elements: 'A-- 아래 선택지 중 하나\n① 소리 이름 : [속성] 탭의 "소리 이름"을 적음\n② 소리 번호: [속성] 탭의 소리 번호를 적음', sound_from_to_and_wait_exampleCode: 'def when_start():\n Entry.play_sound_from_to_and_wait("소리", 0.5, 1)\n Entry.add_size(50)', sound_from_to_and_wait_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 0.5초부터 1초 구간까지만 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.', sound_volume_change_desc: '작품에서 재생되는 모든 소리의 크기를 A퍼센트만큼 바꿉니다.', sound_volume_change_elements: 'A-- 소리 크기 변화 값', sound_volume_change_exampleCode: 'def when_press_key("up"):\n Entry.add_sound_volume(10)\n\ndef when_press_key("down"):\n Entry.add_sound_volume(-10)\n\ndef when_start():\n while True:\n Entry.play_sound_and_wait("소리")', sound_volume_change_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 계속 재생합니다. 위쪽화살표키를 누르면 소리의 크기가 10" 커지고, 아래쪽화살표키를 누르면 소리의 크기가 10"작아집니다.', sound_volume_set_desc: '작품에서 재생되는 모든 소리의 크기를 A퍼센트로 정합니다.', sound_volume_set_elements: 'A-- 소리 크기값', sound_volume_set_exampleCode: 'def when_press_key("up"):\n Entry.add_sound_volume(10)\n\ndef when_press_key("down"):\n Entry.add_sound_volume(-10)\n\ndef when_press_key("enter"):\n Entry.set_sound_volume(100)\n\ndef when_start():\n while True:\n Entry.play_sound_and_wait("소리")', sound_volume_set_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 계속 재생합니다. 위쪽화살표키를 누르면 소리의 크기가 10" 커지고, 아래쪽화살표키를 누르면 소리의 크기가 10"작아집니다. 엔터키를 누르면 소리의 크기를 100"로 정합니다.', sound_silent_all_desc: '현재 재생 중인 모든 소리를 멈춥니다.', sound_silent_all_exampleCode: 'def when_start():\n while True:\n Entry.play_sound_and_wait("소리")\n\ndef when_press_key("enter"):\n Entry.stop_sound()', sound_silent_all_exampleDesc: '[시작하기]버튼을 클릭하면 "소리"를 계속 재생합니다. 엔터키를 누르면 현재 재생 중인 소리를 멈춥니다.', is_clicked_desc: '마우스를 클릭한 경우 True로 판단합니다.', is_clicked_exampleCode: 'def when_start():\n while True:\n if Entry.is_mouse_clicked():\n Entry.print_for_sec("반가워!", 0.5)', is_clicked_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 마우스를 클릭했는지 확인합니다. 만약 마우스를 클릭하면 오브젝트가 "반가워!"라고 0.5초간 말합니다.', is_press_some_key_desc: 'A 키가 눌려져 있는 경우 True로 판단합니다.', is_press_some_key_elements: 'A-- 아래 선택지 중 하나\n① 알파벳 : "A", "B" ~ "Z" 등(소문자 가능)\n② 숫자: 1, 2, 3, 4 ~ 9, 0\n③ 특수키: "space", "enter"\n④ 방향키 : "up", "down", "right", "left"', is_press_some_key_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("space"):\n Entry.move_to_direction(10)', is_press_some_key_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 선택한 키를 눌렀는지 확인합니다. 만약 스페이스 키를 누르면 오브젝트가 이동방향으로 10만큼 이동합니다.', reach_something_desc: '오브젝트가 A와 닿은 경우 True으로 판단합니다.', reach_something_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "mouse_pointer" 또는 "마우스포인터"\n③ "edge", "edge_up", "edge_down", "edge_right", "edge_left"', reach_something_exampleCode: 'def when_start():\n while True:\n Entry.move_to_direction(10)\n if Entry.is_touched("edge"):\n Entry.add_rotation(150)', reach_something_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트가 이동방향으로 10만큼 이동합니다. 만약 오브젝트가 벽에 닿으면 150만큼 회전하게 됩니다.', boolean_basic_operator_desc: 'A와 B를 비교하여 True 또는 False로 판단합니다.', boolean_basic_operator_elements: 'A, B 비교하고자 하는 숫자값\n① == : A와 B의 값이 같으면 True, 아니면 False\n② != : A와 B의 값이 다르면 True, 아니면 False\n③ > : A의 값이 B의 값보다 크면 true, 아니면 False\n④ < : A의 값이 B의 값보다 작으면 true, 아니면 False\n⑤ >= : A의 값이 B의 값보다 크거나 같으면 true, 아니면 False\n⑥ <= : A의 값이 B의 값보다 작거나 같으면 true, 아니면 False', boolean_basic_operator_exampleCode: 'def when_start():\n while True:\n Entry.add_x(10)\n if Entry.value_of_object("오브젝트", "x") > 240:\n Entry.set_x(0)', boolean_basic_operator_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트 x좌표를 10만큼 바꿉니다. 만약 오브젝트 x좌표가 240보다 크면 오브젝트 x좌표를 0으로 정합니다.', boolean_and_desc: 'A와 B의 판단이 모두 True인 경우 True, 아닌 경우 False로 판단합니다.', boolean_and_elements: 'A, B-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', boolean_and_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("a") and Entry.is_key_pressed("s"):\n Entry.add_effect("color", 10)', boolean_and_exampleDesc: '[시작하기]버튼을 클릭하고 키보드의 "a" 와 "s"키를 동시에 눌렀을 때, 색깔 효과를 10만큼 줍니다.', boolean_or_desc: 'A와 B의 판단 중 하나라도 True인 경우 True, 아닌 경우 False로 판단합니다.', boolean_or_elements: 'A, B-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', boolean_or_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("a") or Entry.is_key_pressed("s"):\n Entry.add_effect("color", 10)', boolean_or_exampleDesc: '[시작하기]버튼을 클릭하면 키보드의 "a"나 "s"키 중 무엇이든 하나를 누르면 오브젝트에 색깔 효과를 10만큼 줍니다.', boolean_not_desc: 'A 판단이 True이면 False, False이면 True로 판단합니다.', boolean_not_elements: 'A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① True, False\n② 10 == 10 , 10 > 10 , 10 <= 10 등\n③ Entry.is_mouse_clicked(), Entry.is_key_pressed("Q") 등', boolean_not_exampleCode: 'def when_start():\n while True:\n if not Entry.is_mouse_clicked():\n Entry.add_size(1)', boolean_not_exampleDesc: '[시작하기]버튼을 클릭하면 마우스를 클릭하지 않은 동안 크기가 1씩 커집니다.', calc_basic_desc: 'A와 B의 연산값입니다.', calc_basic_elements: 'A, B-- 연산하고자 하는 숫자값\n① + : A와 B를 더한 값\n② - : A와 B를 뺀 값\n③ x : A와 B를 곱한 값\n④ / : A와 B를 나눈 값', calc_basic_exampleCode: 'def when_start():\n Entry.print_for_sec(10 + 10, 2)\n Entry.print_for_sec(10 - 10, 2)\n Entry.print_for_sec(10 * 10, 2)\n Entry.print_for_sec(10 / 10, 2)', calc_basic_exampleDesc: '[시작하기]버튼을 클릭하면 10과 10을 더한값, 뺀값, 곱한값, 나눈값을 각 2초간 말합니다.', calc_rand_desc: 'A와 B 사이에서 선택된 무작위 수의 값입니다. (두 수 모두 정수를 입력한 경우 정수로,두 수 중 하나라도 소수를 입력한 경우 소수로 무작위 수가 선택됩니다.)', calc_rand_elements: 'A, B-- 무작위 수를 추출할 범위\n① random.randint(A, B) : A, B를 정수로 입력하면 정수 범위에서 무작위 수를 추출\n② random.uniform(A, B) : A, B를 실수로 입력하면 실수 범위에서 무작위 수를 추출', calc_rand_exampleCode: 'def when_start():\n Entry.print_for_sec(random.randint(1, 10), 2)\n Entry.print_for_sec(random.uniform(0.1, 2), 2)', calc_rand_exampleDesc: '[시작하기]버튼을 클릭하면 1부터 10사이의 정수중 무작위 수를 뽑아 2초간 말합니다. 그 후 0.1부터 2사이의 실수중 무작위 수를 뽑아 2초간 말합니다.', coordinate_mouse_desc: '마우스 포인터의 A 좌표 값을 의미합니다.', coordinate_mouse_elements: 'A-- 아래 선택지 중 하나\n① "x" 또는 "X"\n② "y" 또는 "Y"', coordinate_mouse_exampleCode: 'def when_start():\n while True:\n Entry.print(Entry.value_of_mouse_pointer("x"))', coordinate_mouse_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 마우스 포인터의 x좌표를 계속해서 말합니다.', coordinate_object_desc: 'A에 대한 B정보값입니다.', coordinate_object_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "self" 또는 "자신"%nextB-- 아래 선택지 중 하나\n① "x" 또는 "X"\n② "y" 또는 "Y"\n③ "rotation" 또는 "방향"\n④ "direction" 또는 "이동 방향"\n⑤ "size" 또는 "크기"\n⑥ "shape_number" 또는 "모양 번호"\n⑦ "shape_name" 또는 "모양 이름"', coordinate_object_exampleCode: 'def when_start():\n while True:\n Entry.add_x(1)\n Entry.print(Entry.value_of_object("오브젝트", "x"))\n', coordinate_object_exampleDesc: '[시작하기]버튼을 클릭하면 계속해서 오브젝트의 x좌표가 1씩 증가하며, "오브젝트"의 x좌표를 말합니다.', get_sound_volume_desc: '현재 작품에 설정된 소리의 크기값입니다.', get_sound_volume_exampleCode: 'def when_start():\n while True:\n Entry.print(Entry.value_of_sound_volume())', get_sound_volume_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 소리의 크기값을 계속해서 말합니다.', quotient_and_mod_desc: 'A와 B의 연산값입니다.', quotient_and_mod_elements: 'A, B-- 연산하고자 하는 숫자값\n① // : A / B의 몫에 해당하는 값\n② % : A / B의 나머지에 해당하는 값', quotient_and_mod_exampleCode: 'def when_start():\n Entry.print_for_sec(10 // 3, 2)\n Entry.print_for_sec(10 % 3, 2)', quotient_and_mod_exampleDesc: '[시작하기]버튼을 클릭하면 10 / 3의 몫인 3을 2초 동안 말하고, 나머지인 1을 2초 동안 말합니다.', calc_operation_desc: 'A의 연산값입니다.', calc_operation_elements: 'A, B-- 연산하고자 하는 숫자값\n① A ** 2 : A를 제곱한 값\n② math.sqrt(A): A의 루트값\n③ math.sin(A): A의 사인값\n④ math.cos(A): A의 코사인 값\n⑤ math.tan(A): A의 탄젠트값 \n⑥ math.asin(A): A의 아크사인값\n⑦ math.acos(A): A의 아크코사인값\n⑧ math.atan(): A의 아크탄젠트값\n⑨ math.log10(A): A의 로그값\n⑩ math.log(A): A의 자연로그값\n⑪ A - math.floor(A): A의 소수점 부분\n⑫ math.floor(A): A의 소수점 버림값\n⑬ math.ceil(A): A의 소수점 올림값\n⑭ math.round(A): A의 소수점 반올림값\n⑮ math.factorial(A): A의 팩토리얼 값\n⑯ math.fabs(A): A의 절댓값', calc_operation_exampleCode: 'def when_start():\n Entry.print_for_sec(10 ** 2, 2)\n Entry.print_for_sec(math.sqrt(9), 2)\n Entry.print_for_sec(math.sin(90), 2)\n Entry.print_for_sec(math.fabs(-10), 2)', calc_operation_exampleDesc: '[시작하기]버튼을 클릭하면 10의 제곱, 9의 루트값, 90의 사인값, -10의 절댓값을 각 2초 동안 말합니다.', get_project_timer_value_desc: '이 명령이 실행되는 순간 초시계에 저장된 값입니다.', get_project_timer_value_exampleCode: 'def when_start():\n Entry.timer("start")\n Entry.wait_for_sec(3)\n Entry.timer("stop")\n Entry.timer_view("hide")\n Entry.print(Entry.value_of_timer())', get_project_timer_value_exampleDesc: '[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.', choose_project_timer_action_desc: '초시계의 동작을 A로 정합니다.\n(이 명령어를 사용하면 실행화면에 ‘초시계 창’이 생성됩니다.)', choose_project_timer_action_elements: 'A-- 아래 선택지 중 하나\n① "start" : 초시계를 시작\n② "stop" : 초시계를 정지\n③ "reset" : 초시계를 초기화', choose_project_timer_action_exampleCode: 'def when_start():\n Entry.timer("start")\n Entry.wait_for_sec(3)\n Entry.timer("stop")\n Entry.timer_view("hide")\n Entry.print(Entry.value_of_timer())', choose_project_timer_action_exampleDesc: '[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.', set_visible_project_timer_desc: '실행화면의 초시계 창을 A로 설정합니다.', set_visible_project_timer_elements: 'A-- 아래 선택지 중 하나\n① "hide" : 초시계창을 숨김\n② "show" : 초시계창을 보임', set_visible_project_timer_exampleCode: 'def when_start():\n Entry.timer("start")\n Entry.wait_for_sec(3)\n Entry.timer("stop")\n Entry.timer_view("hide")\n Entry.print(Entry.value_of_timer())', set_visible_project_timer_exampleDesc: '[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.', get_date_desc: '현재 A에 대한 값입니다.', get_date_elements: 'A-- 아래 선택지 중 하나\n① "year" : 현재 연도 값\n② "month" : 현재 월 값\n③ "day" : 현재 일 값\n④ "hour" : 현재 시간 값\n⑤ "minute" : 현재 분 값\n⑥ "second" : 현재 초 값', get_date_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_current_time("year") + "년" + Entry.value_of_current_time("month") + "월")', get_date_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 현재년도와 월을 말합니다.', distance_something_desc: '자신과 A까지의 거리 값입니다.', distance_something_elements: 'A-- 아래 선택지 중 하나\n① "오브젝트 이름"\n② "mouse_pointer" 또는 "마우스포인터"', distance_something_exampleCode: 'def when_start():\n while True:\n Entry.print(Entry.value_of_distance_to("mouse_pointer"))', distance_something_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 마우스포인터와의 거리를 계속해서 말합니다.', get_sound_duration_desc: '소리 A의 길이(초)값입니다.', get_sound_duration_elements: 'A-- "소리 이름"', get_sound_duration_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_sound_length_of("소리"))', get_sound_duration_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "소리"의 길이를 말합니다.', get_user_name_desc: '작품을 실행하고 있는 사용자의 아이디 값입니다.\n값은 개인정보 보호를 위해 마스킹 처리되어 있습니다.', get_user_name_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_username())', get_user_name_exampleDesc: '[시작하기]버튼을 클릭하면 작품을 실행하고 있는 사용자의 아이디 값을 말합니다.', get_nickname_desc: '작품을 실행하고 있는 사용자의 닉네임 값입니다.', get_nickname_exampleCode: 'def when_start():\n Entry.print(Entry.value_of_nickname())', get_nickname_exampleDesc: '[시작하기]버튼을 클릭하면 작품을 실행하고 있는 사용자의 닉네임 값을 말합니다.', length_of_string_desc: '입력한 문자값의 공백을 포함한 글자 수입니다.', length_of_string_elements: 'A-- "문자열"', length_of_string_exampleCode: 'def when_start():\n Entry.print_for_sec(len("안녕"), 2)\n Entry.print_for_sec(len("엔트리"), 2)', length_of_string_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕"과 "엔트리"의 글자 수를 각각 2초 동안 말합니다.', combine_something_desc: 'A 문자열과 B 문자열을 결합한 값입니다. (A, B 중 하나가 숫자면 문자열로 바꾸어 처리되고, 둘 다 숫자면 덧셈 연산으로 처리됩니다.)', combine_something_elements: 'A, B-- "문자열"', combine_something_exampleCode: 'def when_start():\n Entry.print("안녕! " + "엔트리")', combine_something_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕!"과 "엔트리"를 결합한 "안녕! 엔트리"를 말합니다.', char_at_desc: 'A 문자열의 B번째의 글자 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)', char_at_elements: 'A-- "문자열"%nextB-- 찾고자 하는 문자열의 위치', char_at_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!"[0])', char_at_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"의 0번째 글자인 "안"을 말합니다.', substring_desc: 'A 문자열의 B위치부터 C-1위치까지의 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)', substring_elements: 'A-- "문자열"%nextB-- 포함할 문자열의 시작 위치\n첫 번째 글자는 0부터 시작%nextC-- 문자열을 포함하지 않는 위치', substring_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!"[1:5])', substring_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"의 1에서 4번째 글자인 "녕 엔트"를 말합니다.', index_of_string_desc: 'A문자열에서 B문자열이 처음으로 등장하는 위치의 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)', index_of_string_elements: 'A, B-- "문자열"', index_of_string_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!".find("엔트리"))', index_of_string_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"에서 "엔트리"가 처음으로 등장하는 위치인 3을 말합니다.', replace_string_desc: 'A 문자열에서 B문자열을 모두 찾아 C문자열로 바꾼 값입니다.\n(영문 입력시 대소문자를 구분합니다.)', replace_string_elements: 'A, B, C-- "문자열"', replace_string_exampleCode: 'def when_start():\n Entry.print("안녕 엔트리!".replace( "안녕", "반가워"))', replace_string_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "안녕 엔트리!"에서 "안녕"을 "반가워"로 바꾼 "반가워 엔트리!"를 말합니다.', change_string_case_desc: 'A의 모든 알파벳을 대문자 또는 소문자로 바꾼 문자값입니다.', change_string_case_elements: 'A-- "문자열"\n① A.upper(): A의 모든 알파벳을 대문자로 바꾼 값\n② A.lower() : A의 모든 알파벳을 소문자로 바꾼 값', change_string_case_exampleCode: 'def when_start():\n Entry.print_for_sec("Hello Entry!".upper(), 2)\n Entry.print_for_sec("Hello Entry!".lower(), 2)', change_string_case_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "Hello Entry!"를 모두 대문자로 바꾼 "HELLO ENTRY!"를 2초간 말한 다음 모두 소문자로 바꾼 "hello entry!"를 2초간 말합니다.', ask_and_wait_desc: "오브젝트가 A 내용을 말풍선으로 묻고, 대답을 입력받습니다. 대답은 실행화면 또는 콘솔창에서 입력할 수 있으며 입력된 값은 'Entry.answer()'에 저장됩니다. \n(이 명령어를 사용하면 실행화면에 ‘대답 창’이 생성됩니다.)", ask_and_wait_elements: 'A-- "문자열"', ask_and_wait_exampleCode: 'def when_start():\n Entry.input("이름을 입력해보세요.")\n Entry.print(Entry.answer() + " 반가워!")', ask_and_wait_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "이름을 입력해보세요."라고 말풍선으로 묻습니다. 이름을 입력하면 "(입력한 이름) 반가워!"라 말합니다.', get_canvas_input_value_desc: 'Entry.input(A) 명령에 의해 실행화면 또는 콘솔에서 입력받은 값입니다.', get_canvas_input_value_exampleCode: 'def when_start():\n Entry.input("이름을 입력해보세요.")\n Entry.print(Entry.answer() + " 반가워!")', get_canvas_input_value_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 "이름을 입력해보세요."라고 말풍선으로 묻습니다. 이름을 입력하면 "(입력한 이름) 반가워!"라 말합니다.', set_visible_answer_desc: '실행화면의 대답 창을 A로 설정합니다.', set_visible_answer_elements: 'A-- 아래 선택지 중 하나\n① "hide" : 대답 창을 숨김\n② "show" : 대답 창을 보임', set_visible_answer_exampleCode: 'def when_start():\n Entry.answer_view("hide")\n Entry.input("나이를 입력하세요.")\n Entry.print(Entry.answer())', set_visible_answer_exampleDesc: '[시작하기]버튼을 클릭하면 대답창이 숨겨지고, 오브젝트가 "나이를 입력하세요."라고 말풍선으로 묻습니다. 나이를 입력하면 오브젝트가 입력한 나이를 말합니다.', get_variable_desc: 'A 변수에 저장된 값입니다.', get_variable_elements: 'A-- 변수명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A', get_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.print(age)', get_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 말합니다.', change_variable_desc: 'A 변수에 B만큼 더합니다.', change_variable_elements: 'A-- 변수명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 숫자값', change_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.print_for_sec(age, 2)\n age += 2\n Entry.print_for_sec(age, 2)', change_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 2초 동안 말합니다. 그 후 age변수에 2를 더하고 더한값인 "18"을 2초 동안 말합니다.', set_variable_desc: 'A 변수의 값을 B로 정합니다. 만약 A 변수가 없으면 [속성] 탭에 A 변수가 자동 생성됩니다.', set_variable_elements: 'A-- 변수명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 변수에 넣을 값\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', set_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.print(age)', set_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 말합니다.', show_variable_desc: 'A 변수 창을 실행화면에 보이게 합니다.', show_variable_elements: 'A-- "변수명"\n① 모든 오브젝트에서 사용: "A"\n② 이 오브젝트에서 사용: "self.A"', show_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.hide_variable("age")\n Entry.wait_for_sec(2)\n age = 20\n Entry.show_variable("age")', show_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 age변수창을 실행화면에서 숨깁니다. 2초 후 변수값을 17로 바꾸고 age변수창을 실행화면에 보이게 합니다.', hide_variable_desc: 'A 변수 창을 실행화면에서 숨깁니다.', hide_variable_elements: 'A-- "변수명"\n① 모든 오브젝트에서 사용: "A"\n② 이 오브젝트에서 사용: "self.A"', hide_variable_exampleCode: 'age = 16\n\ndef when_start():\n Entry.hide_variable("age")\n Entry.print_for_sec(age, 2)', hide_variable_exampleDesc: 'age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 age변수창을 실행화면에서 숨기고, 오브젝트가 age 변수에 들어 가 있는 값인 "16"을 2초 동안 말합니다.', value_of_index_from_list_desc: 'A 리스트에서 B위치의 항목 값을 의미합니다. \n(첫 번째 항목의 위치는 0부터 시작합니다.)', value_of_index_from_list_elements: 'A-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치', value_of_index_from_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.print(basket[1])\n', value_of_index_from_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 오브젝트가 basket 리스트의 1번째 항목인 orange를 말합니다.', add_value_to_list_desc: 'A 리스트의 마지막 항목으로 B값이 추가됩니다.', add_value_to_list_elements: 'A-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 리스트에 넣을 항목 값\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', add_value_to_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n basket.append("juice")\n Entry.print(basket[4])', add_value_to_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 "juice"를 basket의 마지막 항목으로 추가합니다. 오브젝트는 basket의 4번째 항목인 "juice"를 말합니다.', remove_value_from_list_desc: 'A 리스트의 B위치에 있는 항목을 삭제합니다.\n(첫 번째 항목의 위치는 0부터 시작합니다.)', remove_value_from_list_elements: 'A-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치값', remove_value_from_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\ndef when_start():\n basket.pop(0)\n Entry.print(basket[0])', remove_value_from_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 0번째 항목인 apple을 삭제합니다. 오브젝트는 새롭게 basket의 0번째 항목이 된 "orange"를 말합니다.', insert_value_to_list_desc: 'A 리스트의 B위치에 C항목을 끼워 넣습니다. \n(첫 번째 항목의 위치는 0부터 시작합니다. B위치보다 뒤에 있는 항목들은 순서가 하나씩 밀려납니다.)', insert_value_to_list_elements: 'A-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치%nextC-- 리스트에 넣을 항목 값\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', insert_value_to_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n basket.insert(1, "juice")\n Entry.print(basket[2])', insert_value_to_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 1번째 위치에 항목 "juice"를 끼워 넣습니다. 오브젝트는 새롭게 basket의 2번째 항목이 된 "orange"를 말합니다.', change_value_list_index_desc: 'A 리스트에서 B위치에 있는 항목의 값을 C 값으로 바꿉니다.\n(첫 번째 항목의 위치는 0부터 시작합니다.)', change_value_list_index_elements: 'A-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치%nextC-- 리스트에 넣을 항목 값\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등', change_value_list_index_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n basket[0] = "juice"\n Entry.print(basket[0])', change_value_list_index_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 0번째 위치의 항목 "apple"을 "juice"로 바꿉니다. 오브젝트는 바뀐 basket의 0번째 항목 "juice"를 말합니다.', length_of_list_desc: 'A 리스트가 보유한 항목 개수 값입니다.', length_of_list_elements: 'A-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A', length_of_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.print(len(basket))', length_of_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 오브젝트는 basket의 항목 개수인 4를 말합니다.', is_included_in_list_desc: 'A값을 가진 항목이 B리스트에 포함되어 있는지 확인합니다.', is_included_in_list_elements: 'A-- 리스트의 항목 값\n① 문자 : "안녕!", "엔트리" 등 \n② 숫자 : 0, 10, 35 등%nextB-- 리스트명\n① 모든 오브젝트에서 사용: A\n② 이 오브젝트에서 사용: self.A', is_included_in_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n if "apple" in basket:\n Entry.print("사과가 있어!")', is_included_in_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트에 "apple"항목이 있는지 확인합니다. "apple"항목이 있기 때문에 오브젝트는 "사과가 있어!"라 말합니다.', show_list_desc: '선택한 리스트 창을 실행화면에 보이게 합니다.', show_list_elements: 'A-- "리스트명"\n① 모든 오브젝트에서 사용: "A"\n② 이 오브젝트에서 사용: "self.A"', show_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.hide_list("basket")\n Entry.wait_for_sec(2)\n Entry.show_list("basket")', show_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트를 2초간 숨긴 다음 보여줍니다.', hide_list_desc: '선택한 리스트 창을 실행화면에서 숨깁니다.', hide_list_elements: 'A-- "리스트명"\n① 모든 오브젝트에서 사용: "A"\n② 이 오브젝트에서 사용: "self.A"', hide_list_exampleCode: 'basket = ["apple", "orange", "pear", "grape"]\n\ndef when_start():\n Entry.hide_list("basket")\n Entry.wait_for_sec(2)\n Entry.show_list("basket")', hide_list_exampleDesc: 'basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트를 2초간 숨긴 다음 보여줍니다.', boolean_and_or_desc: 'A와 B의 판단값을 확인하여 True 또는 False로 판단합니다.', boolean_and_or_elements: 'A, B-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)\n① and : A와 B의 판단이 모두 True인 경우 True, 아닌 경우 False\n② or : A와 B의 판단 중 하나라도 True인 경우 True, 아닌 경우 False', boolean_and_or_exampleCode: 'def when_start():\n while True:\n if Entry.is_key_pressed("a") and Entry.is_key_pressed("s"):\n Entry.add_effect("color", 10)', boolean_and_or_exampleDesc: '[시작하기]버튼을 클릭하고 키보드의 "a" 와 "s"키를 동시에 눌렀을 때, 색깔 효과를 10만큼 줍니다.', check_weather_desc: 'B날짜에 C지역의 날씨가 A인 경우 True로 판단합니다.', check_weather_elements: 'A-- 아래 선택지 중 하나\n①    "sunny" : 맑음\n②    "partly cloudy" : 구름조금\n③    "mostly cloudy" : 구름많음\n④    "cloudy" : 흐림\n⑤    "rainy" : 비\n⑥    "sleet" : 진눈깨비\n⑦    "snowy" : 눈%nextB-- 아래 선택지 중 하나\n①    "yesterday" : 어제\n②    "today" : 오늘\n③    "tomorrow" : 내일\n④    "After 2 days" : 모레\n⑤    "After 3 days" : 3일 후\n⑥    "After 4 days" : 4일 후\n⑦    "After 5 days" : 5일 후\n⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeollabuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북', check_weather_exampleCode: 'def when_start():\n if Weather.is_condition_sunny("today", "Seoul"):\n Entry.print("오늘 서울의 날씨는 맑습니다.")', check_weather_exampleDesc: '[시작하기]버튼을 클릭하면 오늘 서울의 날씨가 맑은지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 "오늘 서울의 날씨는 맑습니다."라고 말합니다.​', check_finedust_desc: '선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.', check_finedust_elements: 'A-- 아래 선택지 중 하나\n①    "good" : 좋음\n②    "normal" : 보통\n③    "bad" : 나쁨\n④    "very bad" : 매우나쁨%nextB-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeollabuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북', check_finedust_exampleCode: 'def when_start():\n if Weather.is_current_finedust_grade_good("Seoul"):\n Entry.print("현재 서울의 미세먼지 등급은 좋음입니다.")', check_finedust_exampleDesc: '[시작하기]버튼을 클릭하면 현재 서울의 미세먼지 등급이 좋음인지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 “오늘 서울의 미세먼지 등급은 좋음입니다.”라고 말합니다.​', get_weather_data_desc: '선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.', get_weather_data_elements: 'A-- 아래 선택지 중 하나\n①    "the lowest temperature" : 최저기온\n②    "the highest temperature" : 최고기온\n③    "humidity" : 습도\n④    "precipitation" : 강수량\n⑤    "precipitation probability" : 강수확률\n⑥    "wind speed" : 풍속%nextB-- 아래 선택지 중 하나\n①    "yesterday" : 어제\n②    "today" : 오늘\n③    "tomorrow" : 내일\n④    "After 2 days" : 모레\n⑤    "After 3 days" : 3일 후\n⑥    "After 4 days" : 4일 후\n⑦    "After 5 days" : 5일 후\n⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeollabuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북', get_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_lowest_temperature("today", "Seoul"))', get_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 최저기온을 말합니다.​', get_current_weather_data_desc: '현재 B지역의 A 날씨 정보값을 의미합니다.', get_current_weather_data_elements: 'A-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeollabuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나\n①    "temperature" : 기온\n②    "concentration of fine dust" : 미세먼지농도', get_current_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_current_temperature("Seoul"))', get_current_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 현재 서울의 기온을 말합니다.', get_today_temperature_desc: '오늘 A지역의 B 시간대 기온 정보값을 의미합니다.', get_today_temperature_elements: 'A-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeollabuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나\n①    "00" : 당일 00시 측정된 기온값\n②    "03" : 당일 03시 측정된 기온값\n③    "06" : 당일 06시 측정된 기온값\n④    "09" : 당일 09시 측정된 기온값\n⑤    "12" : 당일 12시 측정된 기온값\n⑥    "15" : 당일 15시 측정된 기온값\n⑦    "18" : 당일 18시 측정된 기온값\n⑧    "21" : 당일 21시 측정된 기온값', get_today_temperature_exampleCode: 'def when_start():\n Entry.print(Weather.get_today_temperature("Seoul", 00))', get_today_temperature_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 00시 기온을 말합니다.​', check_city_weather_desc: 'B날짜에 C지역의 날씨가 A인 경우 True로 판단합니다.', check_city_weather_elements: 'A-- 아래 선택지 중 하나\n①    "sunny" : 맑음\n②    "partly cloudy" : 구름조금\n③    "mostly cloudy" : 구름많음\n④    "cloudy" : 흐림\n⑤    "rainy" : 비\n⑥    "sleet" : 진눈깨비\n⑦    "snowy" : 눈%nextB-- 아래 선택지 중 하나\n①    "yesterday" : 어제\n②    "today" : 오늘\n③    "tomorrow" : 내일\n④    "After 2 days" : 모레\n⑤    "After 3 days" : 3일 후\n⑥    "After 4 days" : 4일 후\n⑦    "After 5 days" : 5일 후\n⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeollabuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북', check_city_weather_exampleCode: 'def when_start():\n if Weather.is_condition_sunny("today", "Seoul"):\n Entry.print("오늘 서울의 날씨는 맑습니다.")', check_city_weather_exampleDesc: '[시작하기]버튼을 클릭하면 오늘 서울의 날씨가 맑은지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 "오늘 서울의 날씨는 맑습니다."라고 말합니다.​', check_city_finedust_desc: '선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.', check_city_finedust_elements: 'A-- 아래 선택지 중 하나\n①    "good" : 좋음\n②    "normal" : 보통\n③    "bad" : 나쁨\n④    "very bad" : 매우나쁨%nextB-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeollabuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북', check_city_finedust_exampleCode: 'def when_start():\n if Weather.is_current_finedust_grade_good("Seoul"):\n Entry.print("현재 서울의 미세먼지 등급은 좋음입니다.")', check_city_finedust_exampleDesc: '[시작하기]버튼을 클릭하면 현재 서울의 미세먼지 등급이 좋음인지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 “오늘 서울의 미세먼지 등급은 좋음입니다.”라고 말합니다.​', get_city_weather_data_desc: '선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.', get_city_weather_data_elements: 'A-- 아래 선택지 중 하나\n①    "the lowest temperature" : 최저기온\n②    "the highest temperature" : 최고기온\n③    "humidity" : 습도\n④    "precipitation" : 강수량\n⑤    "precipitation probability" : 강수확률\n⑥    "wind speed" : 풍속%nextB-- 아래 선택지 중 하나\n①    "yesterday" : 어제\n②    "today" : 오늘\n③    "tomorrow" : 내일\n④    "After 2 days" : 모레\n⑤    "After 3 days" : 3일 후\n⑥    "After 4 days" : 4일 후\n⑦    "After 5 days" : 5일 후\n⑧    "After 6 days" : 6일 후%nextC-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeollabuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북', get_city_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_lowest_temperature("today", "Seoul"))', get_city_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 최저기온을 말합니다.​', get_current_city_weather_data_desc: '현재 B지역의 A 날씨 정보값을 의미합니다.', get_current_city_weather_data_elements: 'A-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeollabuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나\n①    "temperature" : 기온\n②    "concentration of fine dust" : 미세먼지농도', get_current_city_weather_data_exampleCode: 'def when_start():\n Entry.print(Weather.get_current_temperature("Seoul"))', get_current_city_weather_data_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 현재 서울의 기온을 말합니다.', get_today_city_temperature_desc: '오늘 A지역의 B 시간대 기온 정보값을 의미합니다.', get_today_city_temperature_elements: 'A-- 아래 선택지 중 하나\n①    "Seoul" : 서울\n②    "Gangwon-do" : 강원\n③    "Gyeonggi-do" : 경기\n④    "Gyeongsangnam-do" : 경남\n⑤    "Gyeongsangbuk-do" : 경북\n⑥    "Gwangju" : 광주\n⑦    "Daegu" : 대구\n⑧    "Daejeon" : 대전\n⑨    "Busan" : 부산\n⑩    "Sejong" : 세종\n⑪    "Ulsan" : 울산\n⑫    "Incheon" : 인천\n⑬    "Jeollanam-do" : 전남\n⑭    "Jeollabuk-do" : 전북\n⑮    "Jeju" : 제주\nⒶ "Chungcheongnam-do" : 충남\nⒷ "Chungcheongbuk-do": 충북%nextB-- 아래 선택지 중 하나\n①    "00" : 당일 00시 측정된 기온값\n②    "03" : 당일 03시 측정된 기온값\n③    "06" : 당일 06시 측정된 기온값\n④    "09" : 당일 09시 측정된 기온값\n⑤    "12" : 당일 12시 측정된 기온값\n⑥    "15" : 당일 15시 측정된 기온값\n⑦    "18" : 당일 18시 측정된 기온값\n⑧    "21" : 당일 21시 측정된 기온값', get_today_city_temperature_exampleCode: 'def when_start():\n Entry.print(Weather.get_today_city_temperature("Seoul", 00))', get_today_city_temperature_exampleDesc: '[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 00시 기온을 말합니다.​', }; Lang.Painter = { select_cut: '사각 점선 모양으로 오릴 수 있어요.', thickness_of_eraser: '지우개 굵기', font: '글꼴', font_color: '글꼴 색상', outline_color: '윤곽선 색상', outline_thickness: '윤곽선 굵기', fill_color: '채우기 색상', inversion: '반전', font_size: '글꼴 크기', font_family: '글꼴 스타일', fullscreen: '전체화면', exit_fullscreen: '전체화면 해제', picture_import: '모양 가져오기', edit_way: '편집 방법', line: '직선', vertex: '꼭지점', bitmap: '비트맵', vector: '벡터', forward: '앞으로', backward: '뒤로', front: '맨 앞으로', back: '맨 뒤로', group: '그룹화', ungroup: '그룹 해제', copy_picture: '복사', delete_picture: '삭제', cut_picture: '자르기', paste_picture: '붙여넣기', remove_all: '모두 삭제', new_picture: '새그림', edit: '편집', picture_size: '크기', picture_rotation: '회전', thickness: '굵기', font_fill: '채우기 색상', painter_file_save: '저장하기', painter_file_saveas: '새 모양으로 저장하기', file: '파일', Pencil: '펜', Line: '직선', Path: '형태', Pan: '이동', Select: '선택', Rectangle: '사각형', Ellipse: '원', Text: '글상자', Fill: '채우기', Eraser: '지우기', get_file: '가져오기', copy_file: '복사하기', }; Lang.DataAnalytics = { data_analysis: '데이터분석', create_table: '테이블 만들기', data: '데이터', add_table: '테이블 추가하기', show_chart: '차트 보기', legend: '계열', value: '값', summary: '요약', column_name: '열 이름', total: '총합', dashboard: '정보', table: '테이블', chart: '차트', attribute: '열', row: '행', average: '평균', standard_deviation: '표준 편차', maximum: '최댓값', minimum: '최솟값', median: '중앙값', average_explain: '해당 열의 모든 값을 더한 후 열의 개수 만큼 나눈 값', standard_deviation_explain: '데이터가 평균을 중심으로 얼마나 퍼져있는지 알려주는 값.\\n0에 가까울 수록 값들이 평균 근처에 집중되어 있다는 것을 의미', maximum_minimum_explain: '해당 열의 가장 큰 값과 가장 작은 값', median_explain: '해당 열의 모든 값을 크기순으로 배열했을 때\\n전체의 중앙에 위치하는 값', add_row_above: '위쪽에 행 추가하기', add_row_below: '아래쪽에 행 추가하기', delete_row: '행 삭제', add_property_left: '왼쪽에 열 추가하기', add_property_right: '오른쪽에 열 추가하기', delete_attribute: '열 삭제', data_alert: '숫자가 아닌 값이 포함된 열은 개수만 확인할 수 있습니다.', save: '저장하기', cancel: '취소', confirm: '확인', attribute_count: '개', row_count: '행', cell_count: '개', count: '개수', add_chart_alert: '추가된 차트가 없습니다.\\n차트를 생성해주세요.', enter_attribute_name: '열 이름을 입력해 주세요.(10자 이내)', placeholder_attribute_name: '열 이름', new_attribute: '새로운 열', chart_title: '차트 제목', remove_chart: '차트 삭제', add_chart_first: '차트를 먼저 추가해주세요.', bar: '막대', line: '선', pie: '원', scatter: '점', select_x_axis: '가로축을 선택해주세요.', x_axis: '가로축', y_axis: '세로축', select_y_axis: '세로축을 선택해주세요.', select_y_axis_or_legend: '세로축 혹은 계열을 선택해주세요.', select_legend: '계열을 선택해주세요', cell: '셀', unable_to_express_chart: '차트로 표현할 수 없습니다.', edit_attribute_name: '이름 바꾸기', duplicate_attribute_name_title: '열 이름 변경에 실패하였습니다.', duplicate_attribute_name_content: '같은 이름의 열이 존재합니다.', fail_save_table: '테이블 저장에 실패하였습니다.', duplicate_table_name_content: '같은 이름의 테이블이 존재합니다.', saved_table_title: '저장되었습니다.', saved_table_content: '테이블과 차트의 정보가 저장되었습니다.', empty_table_name_content: '테이블 이름은 빈 칸이 될 수 없습니다', do_not_delete_row: '행을 삭제할 수 없습니다.', rows_cannot_less_one: '테이블에는 한 개 이상의 행이 있어야합니다.', and: '외', other: '건', stop: '작품 정지하기', restart: '작품 다시 시작', pause: '작품 일시정지', max_row_count_error_title: '너무 큰 테이블', max_row_count_error: '테이블의 셀이 30,000개 이상이면\r\n테이블을 불러올 수는 있지만, 편집할 수는 없습니다.\r\n큰 테이블의 편집은 별도 프로그램을 사용해 주세요.', attributes_text: '%1 외 %2개의 속성', copy: '복사', delete: '삭제', download: 'PC에 저장', confirm_content: '변경된 테이블과 차트를 저장할까요?', please_add_table: '테이블을 먼저 추가해 주세요.', load_data_analytics: '테이블 불러오기', summary_table_description: '테이블에서 열을 기준으로 한 기초 통계량입니다.', not_exist_chart: '추가한 차트가 없습니다.', please_add_chart: '차트를 먼저 추가해 주세요.', chart_name: '차트 이름', remove_confirm_content: '테이블을 삭제할까요?', not_editable_content: '테이블의 셀이 30,000개 이상이라서\r\n엔트리에서 편집할 수 없어요.', limit_cell_count_title: '행/열 개수 제한', limit_cell_count_content: '행 또는 열을 더 이상 추가할 수 없습니다.\r\n엔트리에서는 최대 30,000개의 셀까지의 \r\n테이블만 편집할 수 있습니다.', must_have_one_row_content: '테이블에 행과 열이 하나는 있어야 합니다.', number_of_bins: '계급 수', bin_width: '계급 폭', bin_boundary: '계급 경계', left_closed: '왼쪽 닫힘', right_closed: '오른쪽 닫힘', ascending: '오름차순', default: '원래대로', quantity: '개수', in_order: '순서', not_distinguished: '구분하지 않음', select_table: '[테이블 추가하기]를 눌러 테이블을 추가해 주세요.', select_table_title: '테이블을 추가하는 방법', select_table_des1: "1. 테이블 추가하기의 '테이블 선택' 탭에서 엔트리가 제공하는 기본 테이블을 선택해 추가합니다.", select_table_des2: "2. 테이블 추가하기의 '파일 올리기' 탭에서 CSV, XLS(X) 파일을 직접 업로드해 추가합니다.", select_table_des3: "3. 테이블 추가하기의 '새로 만들기' 탭에서 빈 테이블을 추가하고 데이터를 직접 입력합니다.", statistic: '대푯값', provider: '출처', description: '상세', field_info: '속성 정보', show_all_points: '모든 점 표시', coefficient: '상관계수', scatter_matrix: '산점도 행렬', show_table: '테이블 보기', bar_sub: '바 그래프', line_sub: '라인 그래프', pie_sub: '파이 차트', scatter_sub: '산점도', histogram: '히스토그램', select_legend2: '계열을 2개 이상 선택해주세요', duplicate: '복사', paste: '붙여넣기', cut: '잘라내기', download_table: '테이블을 엑셀 파일로 다운로드', }; Lang.AiLearning = { equation: '회귀식', predict: '예측 속성', cluster_number: '군집', centriod: '중심점', class: '클래스', show: '보이기', hide: '숨기기', open: '열기', close: '닫기', probability: '신뢰도', accuracy: '정확도', f1: 'F1', precision: '정밀도', recall: '재현율', train_param_optimizer_adam: 'Adam', train_param_optimizer_sgd: 'SGD', neighbor_count: '이웃 개수', cluster_option_centroids_kmpp: '가장 먼 거리', cluster_option_centroids_random: '무작위', model_attr_str: '핵심 속성', model_status_0: '상태: 준비', model_status_1: '상태: 학습중', model_status_2: '상태: 학습완료', model_status_3: '상태: 모델없음', train_param_learningRate: '학습률', train_param_epochs: '에포크', train_param_validationRate: '검증 데이터 비율', train_param_C: 'C', train_param_kernel_polynomial: '다항식', train_param_kernel_rbf: 'RBF', train_param_degree: '차수', train_param_gamma: '감마', start: '시작하기', stop: '중지하기', train_param_maxDepth: '트리의 최대 깊이', train_param_minNumSamples: '노드의 최소 데이터 수', chart_title: '모델 차트 창', tree_title: '학습한 트리 창', trained_table_postfix: '학습완료', train_param_error: '테이블 열 정보가 변경된 경우에는 재 학습이 불가능 합니다.', }; Lang.SharePolicy = { title: '엔트리 작품/게시물 공유 가이드', }; Lang.Support = ['ko', 'en', 'vn', 'jp']; Lang.pose_list = { nose: '코', left_eye_inner: '왼쪽 눈 안쪽', left_eye: '왼쪽 눈', left_eye_outer: '왼쪽 눈 바깥쪽', right_eye_inner: '오른쪽 눈 안쪽', right_eye: '오른쪽 눈', right_eye_outer: '오른쪽 눈 바깥쪽', left_ear: '왼쪽 귀', right_ear: '오른쪽 귀', mouth_left: '왼쪽 입꼬리', mouth_right: '오른쪽 입꼬리', left_shoulder: '왼쪽 어깨', right_shoulder: '오른쪽 어깨', left_elbow: '왼쪽 팔꿈치', right_elbow: '오른쪽 팔꿈치', left_wrist: '왼쪽 손목', right_wrist: '오른쪽 손목', left_pinky: '왼쪽 소지', right_pinky: '오른쪽 소지', left_index: '왼쪽 검지', right_index: '오른쪽 검지', left_thumb: '왼쪽 엄지', right_thumb: '오른쪽 엄지', left_hip: '왼쪽 엉덩이', right_hip: '오른쪽 엉덩이', left_knee: '왼쪽 무릎', right_knee: '오른쪽 무릎', left_ankle: '왼쪽 발목', right_ankle: '오른쪽 발목', left_heel: '왼쪽 발꿈치', right_heel: '오른쪽 발꿈치', left_foot_index: '왼쪽 발끝 ', right_foot_index: '오른쪽 발끝', }; Lang.gesture_list = { closed_fist: '쥔 손', open_palm: '편 손', pointing_up: '가리킨 손', thumb_down: '엄지 아래로', thumb_up: '엄지 위로', victory: '브이 사인', iloveyou: '사랑해', none: '알 수 없음', }; if (typeof exports == 'object') exports.Lang = Lang; ================================================ FILE: extern/lang/vn.js ================================================ var Lang = {}; Lang.category = { "name": "en" }; Lang.type = "vn"; Lang.fallbackType = "en"; Lang.ko = "한국어"; Lang.en = "English"; Lang.jp = "日本語"; Lang.vn = "tiếng Việt"; Lang.Command = { "1": "장면 추가하기", "2": "장면 삭제하기", "3": "장면 이름 수정", "4": "장면 순서 변경", "5": "장면 선택", "101": "블록 쓰레드 추가하기", "102": "블록 쓰레드 삭제하기", "103": "블록 삭제하기", "104": "블록 복구하기", "105": "블록 끼워넣기", "106": "블록 분리하기", "107": "블록 이동하기", "108": "블록 복제하기", "109": "블록 복제 취소하기", "110": "스크롤", "111": "블록 필드값 수정", "117": "블록 쓰레드 추가하기", "118": "블록 끼워넣기", "119": "블록 이동하기", "120": "블록 분리하기", "121": "블록 이동하기", "122": "블록 끼워넣기", "123": "블록 끼워넣기", "201": "오브젝트 선택하기", "202": "오브젝트 수정 버튼 클릭", "203": "오브젝트 그림 추가", "204": "오브젝트 그림 삭제", "205": "오브젝트 소리 추가", "206": "오브젝트 소리 삭제", "207": "오브젝트 이름 수정", "208": "오브젝트 추가", "209": "오브젝트 삭제", "210": "오브젝트 추가 버튼 클릭", "211": "오브젝트 x 수정", "212": "오브젝트 y 수정", "213": "오브젝트 size 수정", "214": "오브젝트 방향 수정", "215": "오브젝트 이동 방향 수정", "216": "오브젝트 회전방식 수정", "217": "엔터티 모델 동기화", "301": "do", "302": "undo", "303": "redo", "401": "그림 수정하기", "402": "그림 수정 취소하기", "403": "그림 수정하기", "404": "그림 수정 취소하기", "405": "글상자 수정", "501": "시작하기", "502": "정지하기", "601": "컨테이너 오브젝트 선택하기", "701": "모드 바꾸기", "702": "모양 추가 버튼 클릭", "703": "소리 추가 버튼 클릭", "801": "속성 필터 선택하기", "802": "변수 추가하기 버튼 클릭", "803": "변수 추가하기", "804": "변수 삭제하기", "805": "변수 이름 설정", "806": "신호 이름 설정", "807": "신호 추가", "808": "신호 삭제", "809": "변수 스코프 정하기", "810": "변수 글로벌 체크", "811": "변수 보이기 체크", "812": "변수 기본값 설정", "813": "변수 슬라이드로 체크", "814": "변수 최솟값 정하기", "815": "변수 최댓값 정하기", "816": "리스트 추가 버튼 클릭", "817": "리스트 추가", "818": "리스트 삭제", "819": "리스트 이름 정하기", "820": "리스트 스코프 정하기", "821": "리스트 글로벌 체크", "822": "리스트 보이기 체크", "823": "리스트 길이 변경", "824": "리스트 기본값 설정", "825": "메세지 수정 enable", "826": "변수 수정 enable", "827": "리스트 수정 enable", "828": "변수 이름 정하기", "829": "리스트 이름 정하기", "900": "모달 닫기", "1001": "함수 생성 시작", "1002": "함수 수정 시작", "1003": "함수 수정 취소", "1004": "함수 생성", "1005": "함수 업데이트" }; Lang.CommandTooltip = { "101": "블록 쓰레드 추가하기", "102": "블록 쓰레드 삭제하기", "103": "블록 삭제하기", "104": "블록 복구하기", "105": "코드 분리하기$$코드 연결하기@@이 코드의 가장 위에 있는 블록을 잡고 분리하여 끌어옵니다.$$이 곳에 코드를 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.", "106": "블록 분리하기", "107": "블록 이동하기", "108": "블록 복제하기", "109": "블록 복제 취소하기", "110": "스크롤", "111": "블록 필드값 수정@@값을 입력하기 위해 이곳을 클릭합니다.$$선택지를 클릭합니다.$$선택지를 클릭합니다.$$&value&을 입력합니다.$$&value&를 선택합니다.$$키보드 &value&를 누릅니다.", "117": "블록 쓰레드 추가하기", "118": "블록 연결하기@@이 곳에 블록을 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.", "119": "블록 가져오기@@빈 곳에 블록을 끌어다 놓습니다.", "120": "블록 분리하기$$블록 삭제하기@@필요 없는 코드를 휴지통으로 끌어옵니다.$$이 곳에 코드를 버립니다.", "121": "블록 이동하기$$블록 삭제하기@@필요 없는 코드를 휴지통으로 끌어옵니다.$$이 곳에 코드를 버립니다.", "122": "블록 연결하기@@이 곳에 블록을 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.", "123": "코드 분리하기$$코드 연결하기@@이 코드의 가장 위에 있는 블록을 잡고 분리하여 끌어옵니다.$$이 곳에 코드를 연결합니다.$$이 곳에 블록의 왼쪽 끝을 끼워 넣습니다.", "201": "오브젝트 선택하기", "301": "do", "302": "undo", "303": "redo", "401": "그림 수정하기", "402": "그림 수정 취소하기", "403": "그림 수정하기", "404": "그림 수정 취소하기", "501": "실행하기@@[시작하기]를 누릅니다.", "502": "정지하기@@[정지하기]를 누릅니다.", "601": "컨테이너 오브젝트 선택하기", "701": "모드 바꾸기", "702": "모양 추가하기@@모양추가를 클릭합니다.", "703": "소리 추가하기@@소리추가를 클릭합니다.", "801": "변수 속성창 필터 선택하기", "802": "변수 추가하기@@[변수 추가]를 클릭합니다.", "803": "변수 추가하기@@[확인]을 클릭합니다.", "804": "변수 삭제하기@@이 버튼을 눌러 변수를 삭제합니다.", "805": "변수 이름 설정", "1101": "확장 블록 추가하기@@확장 블록 블러오기를 클릭합니다." }; Lang.Blocks = { "download_guide": "• tải kết Hướng dẫn", "dictionary": "dictionary", "ai_utilize": "AI", "date_yesterday": "yesterday", "date_today": "today", "date_tomorrow": "tomorrow", "date_after_2_days": "After 2 days", "date_after_3_days": "After 3 days", "date_after_4_days": "After 4 days", "date_after_5_days": "After 5 days", "date_after_6_days": "After 6 days", "location_entire": "all", "location_seoul": "Seoul", "location_seoul_jongno_gu": "Jongno-gu", "location_seoul_jung_gu": "Jung-gu", "location_seoul_yongsan_gu": "Yongsan-gu", "location_seoul_seongdong_gu": "Seongdong-gu", "location_seoul_gwangjin_gu": "Gwangjin-gu", "location_seoul_dongdaemun_gu": "Dongdaemun-gu", "location_seoul_jungnang_gu": "Jungrang-gu", "location_seoul_seongbuk_gu": "Seongbuk-gu", "location_seoul_gangbuk_gu": "Gangbuk-gu", "location_seoul_dobong_gu": "Dobong-gu", "location_seoul_nowon_gu": "Nowon-gu", "location_seoul_eunpyeong_gu": "Eunpyeong-gu", "location_seoul_seodaemun_gu": "Seodaemun-gu", "location_seoul_mapo_gu": "Mapo-gu", "location_seoul_yangcheon_gu": "Yangcheon-gu", "location_seoul_gangseo_gu": "Gangseo-gu", "location_seoul_guro_gu": "Guro-gu", "location_seoul_geumcheon_gu": "Geumcheon-gu", "location_seoul_yeongdeungpo_gu": "Yeongdeungpo-gu", "location_seoul_dongjak_gu": "Dongjak-gu", "location_seoul_gwanak_gu": "Gwanak-gu", "location_seoul_seocho_gu": "Seocho-gu", "location_seoul_gangnam_gu": "Gangnam-gu", "location_seoul_songpa_gu": "Songpa-gu", "location_seoul_gangdong_gu": "Gangdong-gu", "location_busan": "Busan", "location_busan_jung_gu": "Jung-gu", "location_busan_seo_gu": "Seo-gu", "location_busan_dong_gu": "Dong-gu", "location_busan_yeongdo_gu": "Yeongdo-gu", "location_busan_busanjin_gu": "Busanjin-gu", "location_busan_dongnae_gu": "Dongnae-gu", "location_busan_nam_gu": "Nam-gu", "location_busan_buk_gu": "Buk-gu", "location_busan_haeundae_gu": "Haeundae-gu", "location_busan_saha_gu": "Saha-gu", "location_busan_geumjeong_gu": "Geumjeong-gu", "location_busan_gangseo_gu": "Gangseo-gu", "location_busan_yeonje": "Yeonje-gu", "location_busan_suyeong_gu": "Suyoung-gu", "location_busan_sasang_gu": "Sasang-gu", "location_busan_gijang": "Gijang-gun", "location_daegu": "Daegu", "location_daegu_jung_gu": "Jung-gu", "location_daegu_dong_gu": "Dong-gu", "location_daegu_seo_gu": "Seo-gu", "location_daegu_nam_gu": "Nam-gu", "location_daegu_buk_gu": "Buk-gu", "location_daegu_suseong_gu": "Suseong-gu", "location_daegu_dalseo_gu": "Dalseo-gu", "location_daegu_dalseong": "Dalseong-gu", "location_incheon": "Incheon", "location_incheon_jung_gu": "Jung-gu", "location_incheon_dong_gu": "Dong-gu", "location_incheon_nam_gu": "Nam-gu", "location_incheon_yeonsu_gu": "Yeonsu-gu", "location_incheon_namdong_gu": "Namdong-gu", "location_incheon_bupyeong_gu": "Bupyeong-gu", "location_incheon_gyeyang_gu": "Gyeyang-gu", "location_incheon_seo_gu": "Seo-gu", "location_incheon_ganghwa": "Ganghwa-gun", "location_incheon_ongjin_gun": "Ongjin-gun", "location_gwangju": "Gwangju", "location_gwangju_dong_gu": "Dong-gu", "location_gwangju_seo_gu": "Seo-gu", "location_gwangju_nam_gu": "Nam-gu", "location_gwangju_buk_gu": "Buk-gu", "location_gwangju_gwangsan_gu": "Gwangsan-gu", "location_daejeon": "Daejeon", "location_daejeon_dong_gu": "Dong-gu", "location_daejeon_jung_gu": "Jung-gu", "location_daejeon_seo_gu": "Seo-gu", "location_daejeon_yuseong_gu": "Yuseong-gu", "location_daejeon_daedeok_gu": "Daedeok-gu", "location_ulsan": "Ulsan", "location_ulsan_jung_gu": "Jung-gu", "location_ulsan_nam_gu": "Nam-gu", "location_ulsan_dong_gu": "Dong-gu", "location_ulsan_buk_gu": "Buk-gu", "location_ulsan_ulju": "Ulju-gun", "location_sejong": "Sejong", "location_gyeonggi": "Gyeonggi-do", "location_gyeonggi_suwon_si": "Suwon", "location_gyeonggi_seongnam": "Seongnam", "location_gyeonggi_uijeongbu": "Uijeongbu", "location_gyeonggi_anyang_si": "Anyang", "location_gyeonggi_bucheon_si": "Bucheon", "location_gyeonggi_gwangmyeong_si": "Gwangmyeong", "location_gyeonggi_pyeongtaek_si": "Pyeongtaek", "location_gyeonggi_dongducheon_si": "Dongducheon", "location_gyeonggi_ansan_si": "Ansan", "location_gyeonggi_goyang_si": "Goyang", "location_gyeonggi_gwacheon_si": "Gwacheon", "location_gyeonggi_guri": "Guri", "location_gyeonggi_namyangju_si": "Namyangju", "location_gyeonggi_osan": "Osan", "location_gyeonggi_siheung": "Siheung", "location_gyeonggi_gunpo_si": "Gunpo", "location_gyeonggi_uiwang_si": "Uiwang", "location_gyeonggi_hanam": "Hanam", "location_gyeonggi_yongin_si": "Yongin", "location_gyeonggi_paju": "Paju", "location_gyeonggi_icheon": "Icheon", "location_gyeonggi_anseong_si": "Anseong", "location_gyeonggi_gimpo": "Gimpo", "location_gyeonggi_hwaseong_si": "Hwaseong", "location_gyeonggi_gwangju": "Guangju", "location_gyeonggi_yangju_si": "Yangju", "location_gyeonggi_pocheon": "Pocheon", "location_gyeonggi_yeoju": "Yeoju", "location_gyeonggi_yeoncheon_gun": "Yeoncheon-gun", "location_gyeonggi_gapyeong_gun": "Gapyeong-gun", "location_gyeonggi_yangpyeong": "Yangpyeong-gun", "location_gangwon": "Gangwon-do", "location_gangwon_chuncheon": "Chuncheon", "location_gangwon_wonju": "Wonju", "location_gangwon_gangneung_si": "Gangneung", "location_gangwon_donghae": "Donghae", "location_gangwon_taebaek_si": "Taebaek", "location_gangwon_sokcho": "Sokcho", "location_gangwon_samcheok_si": "Samcheok", "location_gangwon_hongcheon": "Hongcheon-gun", "location_gangwon_hoengseong_gun": "Hoengseong-gun", "location_gangwon_yeongwol_gun": "Yeongwol-gun", "location_gangwon_pyeongchang": "Pyeongchang-gun", "location_gangwon_jeongseon": "Jeongseon-gun", "location_gangwon_cheolwon": "Cheorwon-gun", "location_gangwon_hwacheon": "Hwacheon-gun", "location_gangwon_yanggu": "Yanggu-gun", "location_gangwon_inje": "Inje-gun", "location_gangwon_goseong": "Goseong-gun", "location_gangwon_yangyang": "Yangyang-gun", "location_chungcheongbuk": "Chungcheongbuk-do", "location_chungcheongbuk_cheongju": "Cheongju", "location_chungcheongbuk_chungju": "Chungju", "location_chungcheongbuk_jecheon": "Jecheon", "location_chungcheongbuk_boeun": "Boeun-gun", "location_chungcheongbuk_okcheon": "Okcheon-gun", "location_chungcheongbuk_yeongdong": "Yeongdong-gun", "location_chungcheongbuk_jeungpyeong": "Jeungpyeong-gun", "location_chungcheongbuk_jincheon": "Jincheon-gun", "location_chungcheongbuk_goesan": "Goesan-gun", "location_chungcheongbuk_eumseong": "Negative-gun", "location_chungcheongbuk_danyang": "Danyang-gun", "location_chungcheongnam": "Chungcheongnam-do", "location_chungcheongnam_cheonan": "Cheonan", "location_chungcheongnam_gongju": "Gongju", "location_chungcheongnam_boryeong": "Boryeong", "location_chungcheongnam_asan": "Asan", "location_chungcheongnam_seosan": "Seosan", "location_chungcheongnam_nonsan": "Nonsan", "location_chungcheongnam_gyeryong": "Gyeryong", "location_chungcheongnam_dangjin": "Dangjin", "location_chungcheongnam_geumsan": "Geumsan-gun", "location_chungcheongnam_buyeo": "Buyeo-gun", "location_chungcheongnam_seocheon": "Seocheon-gun", "location_chungcheongnam_cheongyang": "Cheongyang-gun", "location_chungcheongnam_hongseong": "Hongseong-gun", "location_chungcheongnam_yesan": "Yesan-gun", "location_chungcheongnam_taean": "Taean-gun", "location_jeollabuk": "Jeollabuk-do", "location_jeollabuk_jeonju": "Jeonju", "location_jeollabuk_gunsan_si": "Gunsan", "location_jeollabuk_iksan": "Iksan", "location_jeollabuk_jeongeup": "Jeongeup", "location_jeollabuk_namwon": "Namwon", "location_jeollabuk_gimje_si": "Gimje", "location_jeollabuk_wanju": "Wanju-gun", "location_jeollabuk_jinan": "Jinan-gun", "location_jeollabuk_muju": "Muju-gun", "location_jeollabuk_jangsu": "Jangsu-gun", "location_jeollabuk_imsil": "Imsil-gun", "location_jeollabuk_sunchang": "Sunchang-gun", "location_jeollabuk_gochang": "Gochang-gun", "location_jeollabuk_buan": "Buan-gun", "location_jeollanam": "Jeollanam-do", "location_jeollanam_mokpo": "Mokpo", "location_jeollanam_yosu": "Yeosu", "location_jeollanam_suncheon_si": "Suncheon", "location_jeollanam_naju": "Naju", "location_jeollanam_gwangyang_si": "Gwangyang", "location_jeollanam_damyang": "Damyang-gun", "location_jeollanam_gokseong": "Gokseong-gun", "location_jeollanam_gurye": "Gurye-gun", "location_jeollanam_goheung": "Goheung-gun", "location_jeollanam_boseong": "Boseong-gun", "location_jeollanam_hwasun": "Hwasun-gun", "location_jeollanam_jangheung": "Jangheung-gun", "location_jeollanam_gangjin": "Gangjin-gun", "location_jeollanam_haenam": "Haenam-gun", "location_jeollanam_yeongam": "Yeongam-gun", "location_jeollanam_jindo": "Muan-gun", "location_jeollanam_muan": "Hampyeong-gun", "location_jeollanam_hampyeong": "Yeonggwang-gun", "location_jeollanam_yeonggwang": "Jangseong-gun", "location_jeollanam_jangseong": "Wando-gun", "location_jeollanam_wando": "Jindo-gun", "location_jeollanam_sinan": "Shinan-gun", "location_gyeongsangbuk": "Gyeongsangbuk-do", "location_gyeongsangbuk_pohang_si": "Pohang", "location_gyeongsangbuk_gyeongju_si": "Gyeongju", "location_gyeongsangbuk_gimcheon_si": "Gimcheon", "location_gyeongsangbuk_andong_si": "Andong", "location_gyeongsangbuk_gumi_si": "Gumi", "location_gyeongsangbuk_yeongju_si": "Yeongju", "location_gyeongsangbuk_yeongcheon_si": "Yeongcheon", "location_gyeongsangbuk_sangju_si": "Changzhou", "location_gyeongsangbuk_mungyeong_si": "Mungyeong", "location_gyeongsangbuk_gyeongsan_si": "Gyeongsan", "location_gyeongsangbuk_gunwi": "Gunwi-gun", "location_gyeongsangbuk_uiseong": "Uiseong-gun", "location_gyeongsangbuk_cheongsong": "Cheongsong-gun", "location_gyeongsangbuk_goryong": "Yeongyang-gun", "location_gyeongsangbuk_yeongdeok": "Yeongdeok-gun", "location_gyeongsangbuk_cheongdo": "Cheongdo-gun", "location_gyeongsangbuk_golyeong": "Goryeong-gun", "location_gyeongsangbuk_seongju": "Seongju-gun", "location_gyeongsangbuk_chilgok": "Chilgok-gun", "location_gyeongsangbuk_yecheon": "Yecheon-gun", "location_gyeongsangbuk_bonghwa": "Bonghwa-gun", "location_gyeongsangbuk_uljin": "Uljin-gun", "location_gyeongsangbuk_ulleung": "Ulleung-gun", "location_gyeongsangnam": "Gyeongsangnam-do", "location_gyeongsangnam_changwon_si": "Changwon", "location_gyeongsangnam_jinju": "Jinju", "location_gyeongsangnam_tongyeong_si": "Tongyeong", "location_gyeongsangnam_sacheon_si": "Sacheon", "location_gyeongsangnam_gimhae_si": "Gimhae", "location_gyeongsangnam_miryang_si": "Miryang", "location_gyeongsangnam_geoje_si": "Geoje", "location_gyeongsangnam_yangsan_si": "Yangsan", "location_gyeongsangnam_uiryeong": "Uiryeong-gun", "location_gyeongsangnam_haman": "Haman-gun", "location_gyeongsangnam_changnyeong": "Changnyeong-gun", "location_gyeongsangnam_goseong": "Goseong-gun", "location_gyeongsangnam_namhae": "Namhae-gun", "location_gyeongsangnam_hadong": "Hadong-gun", "location_gyeongsangnam_sancheong": "Sancheong-gun", "location_gyeongsangnam_hamyang": "Hamyang-gun", "location_gyeongsangnam_geochang": "Geochang-gun", "location_gyeongsangnam_hapcheon": "Hapcheon-gun", "location_jeju": "Jeju", "location_jeju_jeju_si": "Jeju", "location_jeju_seogwipo": "Seogwipo", "EXPANSION_WEATHER_sunny": "sunny", "EXPANSION_WEATHER_partly_cloudy": "partly cloudy", "EXPANSION_WEATHER_mostly_cloudy": "mostly cloudy", "EXPANSION_WEATHER_cloudy": "cloudy", "EXPANSION_WEATHER_rainy": "rainy", "EXPANSION_WEATHER_sleet": "sleet", "EXPANSION_WEATHER_snowy": "snowy", "EXPANSION_WEATHER_finedust_good": "good", "EXPANSION_WEATHER_finedust_normal": "normal", "EXPANSION_WEATHER_finedust_bad": "bad", "EXPANSION_WEATHER_finedust_very_bad": "very bad", "EXPANSION_WEATHER_lowest_temperature": "the lowest temperature(℃)", "EXPANSION_WEATHER_highest_temperature": "the highest temperature(℃)", "EXPANSION_WEATHER_humidity": "humidity(%)", "EXPANSION_WEATHER_precipitation": "precipitation(mm)", "EXPANSION_WEATHER_precipitation_probability": "precipitation probability(%)", "EXPANSION_WEATHER_wind_speed": "wind speed(m/s)", "EXPANSION_WEATHER_temperature": "temperature(℃)", "EXPANSION_WEATHER_finedust": "concentration of fine dust(㎍)", "EXPANSION_FESTIVAL_title": "Title", "EXPANSION_FESTIVAL_area": "area", "EXPANSION_FESTIVAL_start_date": "start date", "EXPANSION_FESTIVAL_end_date": "end date", "EXPANSION_FESTIVAL_address": "address", "EXPANSION_FESTIVAL_coordinate": "coordinate", "EXPANSION_FESTIVAL_overview": "overview", "EXPANSION_FESTIVAL_homepage": "homepage", "no_data": "No Information", "no_sentence": "No sentence", "sentence_over_20_charactor": "Only 20 characters can be entered.", "sentence_over_3000_charactor": "Only 3000 characters can be entered.", "sentence_over_2500_charactor": "Only 2500 characters can be entered.", "unknown_sentence": "Unknown sentence", "auto": "auto", "korean": "Korean", "english": "English", "spanish": "Spanish", "french": "French", "german": "German", "russian": "Russian", "portuguese": "Portuguese", "hindi": "Hindi", "japan": "japan", "thai": "Thai", "vietnamese": "Vietnamese", "indonesian": "Indonesian", "chinese_simplified": "Simplified Chinese", "chinese_traditional": "Traditional Chinese", "italian": "Italian", "behaviorConduct01001": "Typhoon", "behaviorConduct01002": "Flood", "behaviorConduct01003": "Heavy rain", "behaviorConduct01004": "Gale", "behaviorConduct01005": "Heavy snow", "behaviorConduct01006": "Cold wave", "behaviorConduct01007": "Storm", "behaviorConduct01008": "Dust storm", "behaviorConduct01009": "Heatwave", "behaviorConduct01010": "Drought", "behaviorConduct01011": "Earthquake", "behaviorConduct01013": "Tsunami", "behaviorConduct01014": "Landslide", "behaviorConduct03002": "First aid", "behaviorConduct03003": "CPR", "behaviorConduct03004": "Fire extinguishers use", "behaviorConduct03016": "Fireplug use", "behaviorConduct03005": "Food poisoning", "behaviorConduct03006": "Climbing safety", "behaviorConduct03008": "Kidnapping·Missing", "behaviorConduct03009": "SAE", "behaviorConduct03010": "School violence", "behaviorConduct03011": "Domestic Violence", "behaviorConduct03012": "Detention and abduction", "behaviorConduct03013": "Traffic Accident", "behaviorConduct03014": "Elevator accident", "behaviorConduct03015": "Fine dust", "behaviorConduct01001001": "Before the typhoon comes", "behaviorConduct01001002": "When the typhoon warning occurs", "behaviorConduct01001003": "After the typhoon has passed", "behaviorConduct01002002": "When the flood forecast occurs", "behaviorConduct01002003": "When the water is pushed", "behaviorConduct01002004": "After the water ir removed", "behaviorConduct01003002": "When the heavy rain forecast occurs", "behaviorConduct01003003": "When the heavy rain warning occurs", "behaviorConduct01003004": "After the heavy rain has passed", "behaviorConduct01004001": "Before the gale comes", "behaviorConduct01004002": "When the gale occurs", "behaviorConduct01005002": "Before the heavy snow comes", "behaviorConduct01005003": "When the heavy snow occurs", "behaviorConduct01005004": "After the heavy snow has passed", "behaviorConduct01006001": "Before the cold wave comes", "behaviorConduct01006002": "When the cold wave occurs", "behaviorConduct01007001": "When the storm warning occurs", "behaviorConduct01007002": "Before the storm comes", "behaviorConduct01008001": "When the dust storm forecast occurs", "behaviorConduct01008002": "When the dust storm occurs", "behaviorConduct01008003": "After the dust storm has passed", "behaviorConduct01009001": "Before the heatwave comes", "behaviorConduct01009002": "When the heatwave watch occurs", "behaviorConduct01010001": "When the drought occurs", "behaviorConduct01011009": "Before the earthquakes comes", "behaviorConduct01011010": "When the earthquake occurs", "behaviorConduct01011012": "After the earthquake evacuation", "behaviorConduct01013002": "Before the tsunami comes", "behaviorConduct01013003": "When the tsunami occurs", "behaviorConduct01014001": "When the landslide watch occurs", "behaviorConduct03002002": "treat burns", "behaviorConduct03002003": "prevate fever", "behaviorConduct03002004": "treat when bitten by a snake", "behaviorConduct03002005": "treat when shot by bee", "behaviorConduct03002006": "do first aid hyperventilation syndrome", "behaviorConduct03003001": "do adult CPR", "behaviorConduct03003002": "do infant CPR", "behaviorConduct03003003": "use an automatic defibrillator", "behaviorConduct03004001": "use a powder fire extinguisher", "behaviorConduct03016001": "use a indoor fire hydrants", "behaviorConduct03005001": "treat food poisoning", "behaviorConduct03006004": "climb the mountain safely", "behaviorConduct03006005": "In the mountain safe camping", "behaviorConduct03006002": "notify information on a rescue request", "behaviorConduct03006003": "do first aid in mountain accident", "behaviorConduct03008001": "prevate kidnapping∙missing", "behaviorConduct03009001": "prevate harassment", "behaviorConduct03010001": "prevate school violence", "behaviorConduct03011001": "prevate domestic violence", "behaviorConduct03012001": "handle detention∙abduction", "behaviorConduct03013002": "handle traffic accidents", "behaviorConduct03013005": "rescue from a vehicle", "behaviorConduct03014001": "use elevator safely", "behaviorConduct03014003": "handle elevator malfunction", "behaviorConduct03014004": "use escalator safely", "behaviorConduct03015007": "live on fine dusty day", "behaviorConduct03015003": "live by sector", "tts_female": "female", "tts_male": "male", "tts_kind": "kind", "tts_sweet": "sweet", "tts_echo": "echo", "tts_mischievous": "mischievous", "tts_dainty": "dainty", "tts_veryslow": "very slow", "tts_slow": "slow", "tts_normal": "normal", "tts_fast": "fast", "tts_veryfast": "very fast", "tts_verylow": "very low", "tts_low": "low", "tts_high": "high", "tts_veryhigh": "very high", "ARDUINO": "phần cứng", "ARDUINO_download_connector": "• Download Connector", "ARDUINO_open_connector": "Open Connector", "ARDUINO_download_source": "• đăng nhập mã Arduino", "ARDUINO_reconnect": "kết nối phần cứng", "arduino_noti_text": "Mobile devices will be\n supported later on.", "ROBOT_reconnect": "Connect Robot", "ARDUINO_program": "Run the program", "ARDUINO_cloud_pc_connector": "Connect to Cloud PC", "ARDUINO_connected": "phần cứng được kết nối", "ARDUINO_connect": "* Connect hardware", "ARDUINO_arduino_get_number_1": "Số kết quả của tín hiệu", "ARDUINO_arduino_get_number_2": "", "ARDUINO_arduino_get_sensor_number_0": "0", "ARDUINO_arduino_get_sensor_number_1": "1", "ARDUINO_arduino_get_sensor_number_2": "2", "ARDUINO_arduino_get_sensor_number_3": "3", "ARDUINO_arduino_get_sensor_number_4": "4", "ARDUINO_arduino_get_sensor_number_5": "5", "blacksmith_toggle_on": "on", "blacksmith_toggle_off": "off", "blacksmith_lcd_first_line": "first", "blacksmith_lcd_seconds_line": "seconds", "BITBRICK_light": "light", "BITBRICK_IR": "IR", "BITBRICK_touch": "Chạm", "BITBRICK_potentiometer": "potentiometer", "BITBRICK_MIC": "MIC", "BITBRICK_UserSensor": "UserSensor", "BITBRICK_UserInput": "UserInput", "BITBRICK_dc_direction_ccw": "CCW", "BITBRICK_dc_direction_cw": "CW", "chocopi_control_event_pressed": "pressed", "chocopi_control_event_released": "released", "chocopi_joystick_X": "joystick X", "chocopi_joystick_Y": "joystick Y", "chocopi_motion_photogate_event_blocked": "blocked", "chocopi_motion_photogate_event_unblocked": "unblocked", "chocopi_motion_photogate_time_blocked": "blocked", "chocopi_motion_photogate_time_unblocked": "unblocked", "chocopi_port": "P", "chocopi_pot": "potentiometer", "chocopi_touch_event_touch": "touched", "chocopi_touch_event_untouch": "untouched", "CODEino_get_sensor_number_0": "0", "CODEino_get_sensor_number_1": "1", "CODEino_get_sensor_number_2": "2", "CODEino_get_sensor_number_3": "3", "CODEino_get_sensor_number_4": "4", "CODEino_get_sensor_number_5": "5", "CODEino_get_sensor_number_6": "6", "CODEino_sensor_name_0": "Âm thanh", "CODEino_sensor_name_1": "Ánh sáng", "CODEino_sensor_name_2": "Slide", "CODEino_sensor_name_3": "Điện trở -A", "CODEino_sensor_name_4": "Điện trở -B", "CODEino_sensor_name_5": "Điện trở -C", "CODEino_sensor_name_6": "Điện trở -D", "CODEino_string_1": "Giá trị cảm biến", "CODEino_string_2": " Vận hành", "CODEino_string_3": "Nhấn nút", "CODEino_string_4": "Kết nối A", "CODEino_string_5": "Kết nối B", "CODEino_string_6": "Kết nối C", "CODEino_string_7": "Kết nối D", "CODEino_string_8": " Cảm biến gia tốc 3-trục", "CODEino_string_9": " Trục giá trị", "CODEino_string_10": "Âm thanh", "CODEino_string_11": "Âm thanh lớn", "CODEino_string_12": "Âm thanh nhỏ", "CODEino_string_13": "Ánh sáng", "CODEino_string_14": "Sáng", "CODEino_string_15": "Tối", "CODEino_string_16": "Nghiêng trái", "CODEino_string_17": "Nghiêng phải", "CODEino_string_18": "Nghiêng ra trước", "CODEino_string_19": "Nghiêng ra sau", "CODEino_string_20": "Đảo ngược", "CODEino_accelerometer_X": "X", "CODEino_accelerometer_Y": "Y", "CODEino_accelerometer_Z": "Z", "CODEino_led_red": "Red", "CODEino_led_green": "Green", "CODEino_led_blue": "Blue", "iboard_analog_number_0": "A0", "iboard_analog_number_1": "A1", "iboard_analog_number_2": "A2", "iboard_analog_number_3": "A3", "iboard_analog_number_4": "A4", "iboard_analog_number_5": "A5", "iboard_light": "Light sensor is ", "iboard_num_pin_1": "LED status", "iboard_num_pin_2": "switch", "iboard_num_pin_3": "analogue", "iboard_num_pin_4": " ", "iboard_num_pin_5": "sensor value", "iboard_string_1": "on", "iboard_string_2": "off", "iboard_string_3": "bright", "iboard_string_4": "dark", "iboard_string_5": "pressed", "iboard_string_6": "opened", "iboard_switch": "switch ", "iboard_tilt": "Slope sensor status is", "dplay_switch": "스위치 ", "dplay_light": "Cảm biến ánh sáng", "dplay_tilt": "Tình trạng cảm biến độ dốc là", "dplay_string_1": "켜짐", "dplay_string_2": "꺼짐", "dplay_string_3": "Sáng", "dplay_string_4": "Tối", "dplay_string_5": "Bị nén", "dplay_string_6": "Bị mở", "dplay_num_pin_1": "Trạng thái LED", "dplay_num_pin_2": "Công tắc", "dplay_num_pin_3": "Analog", "dplay_num_pin_4": "번 ", "dplay_num_pin_5": "Giá trị cảm biến", "dplay_analog_number_0": "A0", "dplay_analog_number_1": "A1", "dplay_analog_number_2": "A2", "dplay_analog_number_3": "A3", "dplay_analog_number_4": "A4", "dplay_analog_number_5": "A5", "ARDUINO_arduino_get_string_1": "Chuỗi kết quả của tín hiệu", "ARDUINO_arduino_get_string_2": "", "ARDUINO_arduino_send_1": "Gửi tín hiệu", "ARDUINO_arduino_send_2": "", "ARDUINO_num_sensor_value_1": "Analog", "ARDUINO_num_sensor_value_2": "Giá trị cảm biến", "ARDUINO_get_digital_value_1": "Kỹ thuật số", "ARDUINO_num_pin_1": "Kỹ thuật số", "ARDUINO_num_pin_2": "Ghim", "ARDUINO_toggle_pwm_1": "Kỹ thuật số", "ARDUINO_toggle_pwm_2": "Ghim", "ARDUINO_toggle_pwm_3": "", "ARDUINO_on": "Mở", "ARDUINO_convert_scale_1": "Map Value", "ARDUINO_convert_scale_2": "", "ARDUINO_convert_scale_3": "~", "ARDUINO_convert_scale_4": "từ", "ARDUINO_convert_scale_5": "~", "ARDUINO_convert_scale_6": "", "ARDUINO_off": "Tắt", "EXPANSION": "Tính năng", "brightness": "độ sáng", "BRUSH": "Chải", "BRUSH_brush_erase_all": "Xóa hết cọ", "BRUSH_change_opacity_1": "Thay đổi độ mờ của cọ bằng", "BRUSH_change_opacity_2": "%", "BRUSH_change_thickness_1": "Thay đổi độ dày của cọ", "BRUSH_change_thickness_2": "", "BRUSH_set_color_1": "Thiết lập màu cọ", "BRUSH_set_color_2": "", "BRUSH_set_opacity_1": "Thiết lập độ mờ của cọ thành ", "BRUSH_set_opacity_2": "%", "BRUSH_set_random_color": "Thiết lập màu cọ ngẫu nhiên", "BRUSH_set_thickness_1": "Thiết lập độ dày của cọ", "BRUSH_set_thickness_2": "", "BRUSH_stamp": "đóng dấu", "BRUSH_start_drawing": "Bắt đầu vẽ", "BRUSH_stop_drawing": "Dừng vẽ", "CALC": "tính toán", "CALC_calc_mod_1": "Rest of", "CALC_calc_mod_2": "", "CALC_calc_mod_3": "", "CALC_calc_operation_of_1": "", "CALC_calc_operation_of_2": "của~", "CALC_calc_operation_root": "căn số", "CALC_calc_operation_square": "bình phương", "CALC_calc_rand_1": "Số ngẫu nhiên giữa", "CALC_calc_rand_2": "và", "CALC_calc_rand_3": "", "CALC_calc_share_1": "Quotient of", "CALC_calc_share_2": "", "CALC_calc_share_3": "", "CALC_coordinate_mouse_1": "con chuột", "CALC_coordinate_mouse_2": "tọa độ", "CALC_coordinate_object_1": "", "CALC_coordinate_object_2": "của~", "CALC_coordinate_object_3": "Coordinate", "CALC_distance_something_1": "Khoảng cách đến", "CALC_distance_something_2": "", "CALC_get_angle": "giá trị góc", "CALC_get_date_1": "ngày", "CALC_get_date_2": "", "CALC_get_date_day": "thứ", "CALC_get_date_hour": "thời gian(giờ)", "CALC_get_date_minute": "thời gian(phút)", "CALC_get_date_month": "tháng", "CALC_get_date_second": "thời gian(giây)", "CALC_get_date_year": "năm", "CALC_get_sound_duration_1": "Chiều dài của", "CALC_get_sound_duration_2": "âm thanh", "CALC_get_timer_value": "giá trị đồng hồ bấm giờ", "CALC_get_x_coordinate": "tọa độ X", "CALC_get_y_coordinate": "tọa độ Y", "CALC_timer_reset": "bắt đầu bấm giờ", "CALC_timer_visible_1": "", "CALC_timer_visible_2": "bộ đếm thời gian", "CALC_timer_visible_show": "hiển thị", "CALC_timer_visible_hide": "ẩn", "color": "màu", "FLOW": "Dòng chảy", "FLOW__if_1": "nếu", "FLOW__if_2": "thì", "FLOW_create_clone_1": "Create", "FLOW_create_clone_2": "bản sao của ", "FLOW_delete_clone": "xóa bản sao", "FLOW_delete_clone_all": "xóa tất cả bản sao", "FLOW_if_else_1": "nếu", "FLOW_if_else_2": "thì", "FLOW_if_else_3": "nếu không", "FLOW_repeat_basic_1": "Repeat ", "FLOW_repeat_basic_2": "lần", "FLOW_repeat_basic_errorMsg": "lặp lại số lớn hơn 0 hoặc tương đương", "FLOW_repeat_inf": "lặp lại liên tục", "FLOW_restart": "khởi động lại dự án", "FLOW_stop_object_1": "Stop", "FLOW_stop_object_2": "", "FLOW_stop_object_all": "tất cả đối tượng", "FLOW_stop_object_this_object": "cái này", "FLOW_stop_object_this_thread": "mã này", "FLOW_stop_object_other_thread": "khối khác của đối tượng này", "FLOW_stop_object_other_objects": "Other object", "FLOW_stop_repeat": "dừng lặp lại", "FLOW_stop_run": "đóng chương trình", "FLOW_wait_second_1": "Wait", "FLOW_wait_second_2": "giây", "FLOW_wait_until_true_1": "Wait until", "FLOW_wait_until_true_2": "", "FLOW_when_clone_start": "khi bản sao được tạo", "FUNC": "Tính năng", "ANALYSIS": "Phân tích dữ liệu", "AI": "Trí tuệ nhân tạo", "JUDGEMENT": "Phán quyết", "JUDGEMENT_boolean_and": "và", "JUDGEMENT_boolean_not_1": "không phải là", "JUDGEMENT_boolean_not_2": "", "JUDGEMENT_boolean_or": "hoặc", "JUDGEMENT_false": "sai", "JUDGEMENT_is_clicked": "nhấn chuột?", "JUDGEMENT_is_press_some_key_1": "Key", "JUDGEMENT_is_press_some_key_2": "ấn phím?", "JUDGEMENT_reach_something_1": "Chạm", "JUDGEMENT_reach_something_2": "?", "JUDGEMENT_true": "đúng", "JUDGEMENT_is_boost_mode": "Is the boost mode on?", "LOOKS": "nhìn", "LOOKS_change_scale_percent_1": "thay đổi kích cỡ bằng", "LOOKS_change_scale_percent_2": "", "LOOKS_change_to_next_shape": "Change to next", "LOOKS_change_to_nth_shape_1": "Change shape to", "LOOKS_change_to_nth_shape_2": "", "LOOKS_change_shape_prev": "trước", "LOOKS_change_shape_next": "kế tiếp", "LOOKS_change_to_near_shape_1": "Change to", "LOOKS_change_to_near_shape_2": "hình dạng", "LOOKS_dialog_1": "Say", "LOOKS_dialog_2": "", "LOOKS_dialog_3": "", "LOOKS_dialog_time_1": "Say", "LOOKS_dialog_time_2": "trong", "LOOKS_dialog_time_3": "giây", "LOOKS_dialog_time_4": "", "LOOKS_erase_all_effects": "xóa tất cả hiệu ứng", "LOOKS_flip_x": "lật dọc", "LOOKS_flip_y": "lật ngang", "LOOKS_hide": "ẩn", "LOOKS_remove_dialog": "xóa bài nói", "LOOKS_set_effect_1": "Set", "LOOKS_set_effect_2": "thiết lập hiệu ứng", "LOOKS_set_effect_3": "", "LOOKS_set_effect_volume_1": "Change", "LOOKS_set_effect_volume_2": "cho hiệu ứng", "LOOKS_set_effect_volume_3": "", "LOOKS_set_object_order_1": "go to", "LOOKS_set_object_order_2": "lớp thứ", "LOOKS_set_scale_percent_1": "thiết lập kích cỡ thành", "LOOKS_set_scale_percent_2": "", "LOOKS_show": "cho xem", "mouse_pointer": "con trỏ chuột", "MOVING": "động", "MOVING_bounce_wall": "nếu ở cuối màn hình, bật ra", "MOVING_bounce_when_1": "Bounce if reach to the", "MOVING_bounce_when_2": "", "MOVING_flip_arrow_horizontal": "lật ngang theo hướng mũi tên", "MOVING_flip_arrow_vertical": "lật dọc theo hướng mũi tên", "MOVING_locate_1": "Move to", "MOVING_locate_2": "", "MOVING_locate_time_1": "Moving while", "MOVING_locate_time_2": "di chuyển trong ~ giây đến", "MOVING_locate_time_3": "", "MOVING_locate_x_1": "di chuyển đến X:", "MOVING_locate_x_2": "", "MOVING_locate_xy_1": "di chuyển đến X:", "MOVING_locate_xy_2": "Y:", "MOVING_locate_xy_3": "", "MOVING_locate_xy_time_1": "Moving while", "MOVING_locate_xy_time_2": "trong ~ giây x:", "MOVING_locate_xy_time_3": "y:", "MOVING_locate_xy_time_4": "", "MOVING_locate_y_1": "di chuyển đến Y:", "MOVING_locate_y_2": "", "MOVING_move_direction_1": "di chuyển", "MOVING_move_direction_2": "đằng trước", "MOVING_move_direction_angle_1": "Rotate", "MOVING_move_direction_angle_2": "và di chuyển", "MOVING_move_direction_angle_3": "", "MOVING_move_x_1": "thay đổi X bằng", "MOVING_move_x_2": "", "MOVING_move_xy_time_1": "For", "MOVING_move_xy_time_2": "giây di chuyển đến X:", "MOVING_move_xy_time_3": "Y:", "MOVING_move_xy_time_4": "", "MOVING_move_y_1": "thay đổi Y bằng", "MOVING_move_y_2": "", "MOVING_rotate_by_angle_1": "xoay bằng", "MOVING_rotate_by_angle_2": "độ", "MOVING_rotate_by_angle_dropdown_1": "Rotate by", "MOVING_rotate_by_angle_dropdown_2": "độ", "MOVING_rotate_by_angle_time_1": "xoay trong suốt", "MOVING_rotate_by_angle_time_2": "~giây", "MOVING_rotate_by_angle_time_3": "~độ", "MOVING_rotate_direction_1": "thay đổi phương hướng", "MOVING_rotate_direction_2": "", "MOVING_see_angle_1": "thiết lập phương hướng", "MOVING_see_angle_2": "", "MOVING_see_angle_direction_1": "thiết lập góc", "MOVING_see_angle_direction_2": "độ", "MOVING_see_angle_object_1": "Turn towards", "MOVING_see_angle_object_2": "", "MOVING_see_direction_1": "Rotate to the", "MOVING_see_direction_2": "", "MOVING_set_direction_by_angle_1": "thiết lập xoay vòng", "MOVING_set_direction_by_angle_2": "", "MOVING_add_direction_by_angle_1": "xoay", "MOVING_add_direction_by_angle_2": "", "MOVING_add_direction_by_angle_time_1": "", "MOVING_add_direction_by_angle_time_2": "xoay trong ~giây", "MOVING_add_direction_by_angle_time_3": "", "no_target": "Không có mục tiêu", "oneself": "bản thân", "opacity": "độ mờ", "SCENE": "cảnh", "SOUND": "âm thanh", "SOUND_sound_silent_all": "dừng tất cả âm thanh", "SOUND_sound_something_1": "mở", "SOUND_sound_something_2": "âm thanh", "SOUND_sound_something_second_1": "mở", "SOUND_sound_something_second_2": "sound for", "SOUND_sound_something_second_3": "giây", "SOUND_sound_something_second_wait_1": "mở", "SOUND_sound_something_second_wait_2": "Sound for", "SOUND_sound_something_second_wait_3": "chờ trong~ giây", "SOUND_sound_something_wait_1": "mở", "SOUND_sound_something_wait_2": "mở và chờ", "SOUND_sound_volume_change_1": "thay đổi âm lượng bằng", "SOUND_sound_volume_change_2": "%", "SOUND_sound_volume_set_1": "thiết lập âm lượng bằng", "SOUND_sound_volume_set_2": "%", "speak": "nói", "think": "Think", "START": "bắt đầu", "START_add_message": "Add a message", "START_delete_message": "Remove a message", "START_message_cast": "Send message", "START_message_cast_1": "Send", "START_message_cast_2": "tin nhắn", "START_message_cast_wait": "message and wait", "START_message_send_wait_1": "Send", "START_message_send_wait_2": "gửi tin nhắn và chờ", "START_mouse_click_cancled": "khi thả nhấp chuột", "START_mouse_clicked": "khi nhấp chuột", "START_press_some_key_1": "When key", "START_press_some_key_2": "ấn phím", "START_press_some_key_down": "xuống", "START_press_some_key_enter": "bắt đầu", "START_press_some_key_left": "trái", "START_press_some_key_right": "phải", "START_press_some_key_space": "thanh cách chữ", "START_press_some_key_up": "lên", "START_when_message_cast": "When message received", "START_when_message_cast_1": "When", "START_when_message_cast_2": "nhận tin nhắn", "START_when_object_click": "khi nhấp chuột vào đối tượng", "START_when_object_click_canceled": "khi nhấp chuột ra khỏi đối tượng", "START_when_run_button_click": "khi chạy", "START_when_scene_start": "When scene was started", "START_when_some_key_click": "khi ấn phím", "TEXT": "Text", "TEXT_text": "Entry", "TEXT_text_append_1": "After writing that", "TEXT_text_append_2": "", "TEXT_text_flush": "loại bỏ tất cả văn bản", "TEXT_text_prepend_1": "Add", "TEXT_text_prepend_2": "trước đó", "TEXT_text_write_1": "Writing that", "TEXT_text_write_2": "", "VARIABLE": "biến số", "VARIABLE_add_value_to_list": "", "VARIABLE_add_value_to_list_1": "add", "VARIABLE_add_value_to_list_2": "danh sách", "VARIABLE_add_value_to_list_3": "", "VARIABLE_ask_and_wait_1": "Ask", "VARIABLE_ask_and_wait_2": "và chờ", "VARIABLE_change_value_list_index": "", "VARIABLE_change_value_list_index_1": "change", "VARIABLE_change_value_list_index_3": "hạng mục thứ ~", "VARIABLE_change_value_list_index_2": "", "VARIABLE_change_value_list_index_4": "", "VARIABLE_change_variable": "Adding variable", "VARIABLE_change_variable_1": "Plus to", "VARIABLE_change_variable_2": "bằng", "VARIABLE_change_variable_3": "", "VARIABLE_change_variable_name": "Rename variable", "VARIABLE_combine_something_1": "Tham gia", "VARIABLE_combine_something_2": "", "VARIABLE_combine_something_3": "", "VARIABLE_get_canvas_input_value": "trả lời", "VARIABLE_get_variable": "Value of variable", "VARIABLE_get_variable_1": "giá trị", "VARIABLE_get_variable_2": "", "VARIABLE_get_y": "tọa độ Y", "VARIABLE_hide_list": "", "VARIABLE_hide_list_1": "ẩn danh sách", "VARIABLE_hide_list_2": "", "VARIABLE_hide_variable": "Hide variable", "VARIABLE_hide_variable_1": "ẩn biến số", "VARIABLE_hide_variable_2": "giá trị", "VARIABLE_insert_value_to_list": "", "VARIABLE_insert_value_to_list_1": "insert", "VARIABLE_insert_value_to_list_2": "đến", "VARIABLE_insert_value_to_list_3": "", "VARIABLE_insert_value_to_list_4": "vị trí thứ ~", "VARIABLE_length_of_list": "", "VARIABLE_length_of_list_1": "Chiều dài của", "VARIABLE_length_of_list_2": "", "VARIABLE_list": "", "VARIABLE_make_variable": "Make variable", "VARIABLE_list_option_first": "đầu tiên", "VARIABLE_list_option_last": "cuối cùng", "VARIABLE_list_option_random": "ngẫu nhiên", "VARIABLE_remove_value_from_list": "", "VARIABLE_remove_value_from_list_1": "remove", "VARIABLE_remove_value_from_list_2": "từ hạng mục thứ ~", "VARIABLE_remove_value_from_list_3": "", "VARIABLE_remove_variable": "Remove variable", "VARIABLE_set_variable": "Set variable", "VARIABLE_set_variable_1": "Set", "VARIABLE_set_variable_2": "để", "VARIABLE_set_variable_3": "", "VARIABLE_show_list": "", "VARIABLE_show_list_1": "hiển thị danh sách", "VARIABLE_show_list_2": "", "VARIABLE_show_variable": "Show variable", "VARIABLE_show_variable_1": "hiển thị biến số", "VARIABLE_show_variable_2": "giá trị", "VARIABLE_value_of_index_from_list": "", "VARIABLE_value_of_index_from_list_1": "value of", "VARIABLE_value_of_index_from_list_2": "", "VARIABLE_value_of_index_from_list_3": "hạng mục thứ ~", "HAMSTER_hand_found": "tìm tay?", "HAMSTER_sensor_left_proximity": "left proximity", "HAMSTER_sensor_right_proximity": "right proximity", "HAMSTER_sensor_left_floor": "left floor", "HAMSTER_sensor_right_floor": "right floor", "HAMSTER_sensor_acceleration_x": "x acceleration", "HAMSTER_sensor_acceleration_y": "y acceleration", "HAMSTER_sensor_acceleration_z": "z acceleration", "HAMSTER_sensor_light": "độ sáng", "HAMSTER_sensor_temperature": "nhiệt độ", "HAMSTER_sensor_signal_strength": "signal strength", "HAMSTER_sensor_input_a": "input A", "HAMSTER_sensor_input_b": "input B", "HAMSTER_move_forward_once": "di chuyển một lần về phía trước trên bảng", "HAMSTER_turn_once_1": "mở", "HAMSTER_turn_once_2": "một lần trên bảng", "HAMSTER_turn_once_left": "left", "HAMSTER_turn_right": "right", "HAMSTER_move_forward": "Di chuyển về phía trước", "HAMSTER_move_backward": "Di chuyển về phía sau", "HAMSTER_turn_around_1": "turn", "HAMSTER_turn_around_2": "", "HAMSTER_move_forward_for_secs_1": "di chuyển về phía trước", "HAMSTER_move_forward_for_secs_2": "giây", "HAMSTER_move_backward_for_secs_1": "di chuyển về phía sau", "HAMSTER_move_backward_for_secs_2": "giây", "HAMSTER_turn_for_secs_1": "turn", "HAMSTER_turn_for_secs_2": "cho", "HAMSTER_turn_for_secs_3": "giây", "HAMSTER_change_both_wheels_by_1": "thay đổi bánh xe bên trái", "HAMSTER_change_both_wheels_by_2": "phải:", "HAMSTER_change_both_wheels_by_3": "", "HAMSTER_set_both_wheels_to_1": "thiết lập bánh xe bên trái", "HAMSTER_set_both_wheels_to_2": "phải:", "HAMSTER_set_both_wheels_to_3": "", "HAMSTER_change_wheel_by_1": "change", "HAMSTER_change_wheel_by_2": "bánh xe bằng", "HAMSTER_change_wheel_by_3": "", "HAMSTER_left_wheel": "left", "HAMSTER_right_wheel": "right", "HAMSTER_both_wheels": "both", "HAMSTER_set_wheel_to_1": "set", "HAMSTER_set_wheel_to_2": "bánh xe để", "HAMSTER_set_wheel_to_3": "", "HAMSTER_follow_line_using_1": "follow", "HAMSTER_follow_line_using_2": "sử dụng dây", "HAMSTER_follow_line_using_3": "cảm biến sàn", "HAMSTER_left_floor_sensor": "left", "HAMSTER_right_floor_sensor": "right", "HAMSTER_both_floor_sensors": "both", "HAMSTER_follow_line_until_1": "follow", "HAMSTER_follow_line_until_2": "đến con đường", "HAMSTER_follow_line_until_3": "chỗ giao nhau", "HAMSTER_left_intersection": "left", "HAMSTER_right_intersection": "right", "HAMSTER_front_intersection": "front", "HAMSTER_rear_intersection": "rear", "HAMSTER_set_following_speed_to_1": "thiết lập tốc độ sau", "HAMSTER_set_following_speed_to_2": "", "HAMSTER_front": "phía trước", "HAMSTER_rear": "phía sau", "HAMSTER_stop": "dừng lại", "HAMSTER_set_led_to_1": "set", "HAMSTER_set_led_to_2": "đèn Led", "HAMSTER_set_led_to_3": "", "HAMSTER_left_led": "left", "HAMSTER_right_led": "right", "HAMSTER_both_leds": "both", "HAMSTER_clear_led_1": "clear", "HAMSTER_clear_led_2": "led", "HAMSTER_color_cyan": "xanh da trời", "HAMSTER_color_magenta": "tím", "HAMSTER_color_black": "màu đen", "HAMSTER_color_white": "white", "HAMSTER_color_red": "red", "HAMSTER_color_yellow": "yellow", "HAMSTER_color_green": "green", "HAMSTER_color_blue": "blue", "HAMSTER_beep": "tiếng bíp bíp", "HAMSTER_change_buzzer_by_1": "thay đổi tiếng chuông bằng", "HAMSTER_change_buzzer_by_2": "", "HAMSTER_set_buzzer_to_1": "thiết lập tiếng chuông bằng", "HAMSTER_set_buzzer_to_2": "", "HAMSTER_clear_buzzer": "xóa chuông", "HAMSTER_play_note_for_1": "play note", "HAMSTER_play_note_for_2": "", "HAMSTER_play_note_for_3": "cho", "HAMSTER_play_note_for_4": "nhịp điệu", "HAMSTER_rest_for_1": "rest for", "HAMSTER_rest_for_2": "nhịp điệu", "HAMSTER_change_tempo_by_1": "thay đổi nhịp độ bằng", "HAMSTER_change_tempo_by_2": "", "HAMSTER_set_tempo_to_1": "thiết lập nhịp độ bằng", "HAMSTER_set_tempo_to_2": "bpm", "HAMSTER_set_port_to_1": "thiết lập cổng", "HAMSTER_set_port_to_2": "đến", "HAMSTER_set_port_to_3": "", "HAMSTER_change_output_by_1": "thay đổi đầu ra", "HAMSTER_change_output_by_2": "bằng", "HAMSTER_change_output_by_3": "", "HAMSTER_set_output_to_1": "thiết lập đầu ra", "HAMSTER_set_output_to_2": "bằng", "HAMSTER_set_output_to_3": "", "HAMSTER_port_a": "A", "HAMSTER_port_b": "B", "HAMSTER_port_ab": "A và B", "HAMSTER_analog_input": "đầu vào analog", "HAMSTER_digital_input": "đầu vào kỹ thuật số", "HAMSTER_servo_output": "đầu ra servo", "HAMSTER_pwm_output": "đầu ra PWM", "HAMSTER_digital_output": "đầu ra kỹ thuật số", "ROBOID_acceleration_x": "x acceleration", "ROBOID_acceleration_y": "y acceleration", "ROBOID_acceleration_z": "z acceleration", "ROBOID_back": "back", "ROBOID_both": "both", "ROBOID_button": "button", "ROBOID_buzzer": "buzzer", "ROBOID_clicked": "clicked", "ROBOID_color_any": "any color", "ROBOID_color_black": "black", "ROBOID_color_blue": "blue", "ROBOID_color_green": "green", "ROBOID_color_number": "color number", "ROBOID_color_orange": "orange", "ROBOID_color_pattern": "color pattern", "ROBOID_color_purple": "purple", "ROBOID_color_red": "red", "ROBOID_color_sky_blue": "sky blue", "ROBOID_color_violet": "violet", "ROBOID_color_white": "white", "ROBOID_color_yellow": "yellow", "ROBOID_double_clicked": "double-clicked", "ROBOID_floor": "floor", "ROBOID_head": "head", "ROBOID_head_color": "head color", "ROBOID_left": "left", "ROBOID_left_wheel": "left wheel", "ROBOID_long_pressed": "long-pressed", "ROBOID_note": "note", "ROBOID_right": "right", "ROBOID_right_wheel": "right wheel", "ROBOID_sound_beep": "beep", "ROBOID_sound_birthday": "birthday", "ROBOID_sound_dibidibidip": "dibidibidip", "ROBOID_sound_engine": "engine", "ROBOID_sound_good_job": "good job", "ROBOID_sound_march": "march", "ROBOID_sound_random_beep": "random beep", "ROBOID_sound_robot": "robot", "ROBOID_sound_siren": "siren", "ROBOID_tail": "tail", "ROBOID_unit_cm": "cm", "ROBOID_unit_deg": "degrees", "ROBOID_unit_pulse": "pulses", "ROBOID_unit_sec": "seconds", "ALBERT_hand_found": "Tìm tay?", "ALBERT_is_oid_1": "oid is", "ALBERT_is_oid_2": "", "ALBERT_is_oid_3": "?", "ALBERT_front_oid": "front", "ALBERT_back_oid": "back", "ALBERT_sensor_left_proximity": "left proximity", "ALBERT_sensor_right_proximity": "right proximity", "ALBERT_sensor_acceleration_x": "x acceleration", "ALBERT_sensor_acceleration_y": "y acceleration", "ALBERT_sensor_acceleration_z": "z acceleration", "ALBERT_sensor_light": "Độ sáng", "ALBERT_sensor_temperature": "temperature", "ALBERT_sensor_battery": "Pin", "ALBERT_sensor_signal_strength": "signal strength", "ALBERT_sensor_front_oid": "front oid", "ALBERT_sensor_back_oid": "back oid", "ALBERT_sensor_position_x": "x position", "ALBERT_sensor_position_y": "y position", "ALBERT_sensor_orientation": "Phương hướng", "ALBERT_move_forward": "move forward", "ALBERT_move_backward": "move backward", "ALBERT_turn_around_1": "turn", "ALBERT_turn_around_2": "", "ALBERT_move_forward_for_secs_1": "Di chuyển về phía trước trong ", "ALBERT_move_forward_for_secs_2": "Giây", "ALBERT_move_backward_for_secs_1": "Di chuyển về phía sau trong ", "ALBERT_move_backward_for_secs_2": "Giây", "ALBERT_turn_for_secs_1": "turn", "ALBERT_turn_for_secs_2": "Quay sang", "ALBERT_turn_for_secs_3": "Giây", "ALBERT_turn_left": "left", "ALBERT_turn_right": "right", "ALBERT_change_both_wheels_by_1": "Thay thế bằng bánh xe bên trái:", "ALBERT_change_both_wheels_by_2": "Bên phải:", "ALBERT_change_both_wheels_by_3": "", "ALBERT_left_wheel": "left", "ALBERT_right_wheel": "right", "ALBERT_both_wheels": "both", "ALBERT_set_both_wheels_to_1": "Thiết lập bánh xe bên trái:", "ALBERT_set_both_wheels_to_2": "Bên phải:", "ALBERT_set_both_wheels_to_3": "", "ALBERT_change_wheel_by_1": "change", "ALBERT_change_wheel_by_2": "Thay thế bánh xe bằng", "ALBERT_change_wheel_by_3": "", "ALBERT_set_wheel_to_1": "set", "ALBERT_set_wheel_to_2": "Thiết lập bánh xe", "ALBERT_set_wheel_to_3": "", "ALBERT_stop": "Dừng lại", "ALBERT_set_board_size_to_1": "set board size to width:", "ALBERT_set_board_size_to_2": "height:", "ALBERT_set_board_size_to_3": "", "ALBERT_move_to_x_y_1": "move to x:", "ALBERT_move_to_x_y_2": "y:", "ALBERT_move_to_x_y_3": "on board", "ALBERT_set_orientation_to_1": "set orientation to", "ALBERT_set_orientation_to_2": "degrees on board", "ALBERT_set_eye_to_1": "set", "ALBERT_set_eye_to_2": "Mắt", "ALBERT_set_eye_to_3": "", "ALBERT_left_eye": "left", "ALBERT_right_eye": "right", "ALBERT_both_eyes": "both", "ALBERT_clear_eye_1": "clear", "ALBERT_clear_eye_2": "Mắt", "ALBERT_body_led_1": "", "ALBERT_body_led_2": "body led", "ALBERT_front_led_1": "", "ALBERT_front_led_2": "front led", "ALBERT_color_cyan": "Xanh da trời", "ALBERT_color_magenta": "Tím", "ALBERT_color_white": "white", "ALBERT_color_red": "red", "ALBERT_color_yellow": "yellow", "ALBERT_color_green": "green", "ALBERT_color_blue": "blue", "ALBERT_note_c": "C", "ALBERT_note_d": "D", "ALBERT_note_e": "E", "ALBERT_note_f": "F", "ALBERT_note_g": "G", "ALBERT_note_a": "A", "ALBERT_note_b": "B", "ALBERT_turn_body_led_1": "turn", "ALBERT_turn_body_led_2": "body led", "ALBERT_turn_front_led_1": "turn", "ALBERT_turn_front_led_2": "front led", "ALBERT_turn_on": "on", "ALBERT_turn_off": "off", "ALBERT_beep": "Tiếng bíp bíp", "ALBERT_change_buzzer_by_1": "Đổi tiếng chuông bằng", "ALBERT_change_buzzer_by_2": "", "ALBERT_set_buzzer_to_1": "Thiết lập tiếng chuông", "ALBERT_set_buzzer_to_2": "", "ALBERT_clear_buzzer": "Tắt chuông", "ALBERT_play_note_for_1": "play note", "ALBERT_play_note_for_2": "',", "ALBERT_play_note_for_3": "Nốt", "ALBERT_play_note_for_4": "Nhịp", "ALBERT_rest_for_1": "rest for", "ALBERT_rest_for_2": "Nhịp", "ALBERT_change_tempo_by_1": "Thay đổi nhịp độ bằng ~", "ALBERT_change_tempo_by_2": "", "ALBERT_set_tempo_to_1": "Thiết lập nhịp độ thành", "ALBERT_set_tempo_to_2": "bpm", "VARIABLE_variable": "biến số", "wall": "tường", "robotis_common_case_01": "-", "robotis_common_set": "dữ liệu đầu ra", "robotis_common_value": "giá trị", "robotis_common_clockwhise": "chiều kim đồng hồ", "robotis_common_counter_clockwhise": "ngược chiều kim đồng hồ", "robotis_common_wheel_mode": "chế độ bánh xe", "robotis_common_joint_mode": "chế độ khớp", "robotis_common_red_color": "đỏ", "robotis_common_green_color": "xanh lá cây", "robotis_common_blue_color": "xanh dương", "robotis_common_on": "bật", "robotis_common_off": "tắt", "robotis_common_cm": "bộ điều khiển", "robotis_common_port_1": "cổng 1", "robotis_common_port_2": "cổng 2", "robotis_common_port_3": "cổng 3", "robotis_common_port_4": "cổng 4", "robotis_common_port_5": "cổng 5", "robotis_common_port_6": "cổng 6", "robotis_common_play_buzzer": "biểu diễn", "robotis_common_play_motion": "thực hiện", "robotis_common_motion": "chuyển động ", "robotis_common_index_number": "số", "robotis_common_left": "Bên trái", "robotis_common_right": "Phải", "robotis_common_minute": "phút", "robotis_cm_custom": "nhập địa chỉ", "robotis_cm_spring_left": "cảm biến tiếp xúc trái", "robotis_cm_spring_right": "cảm biến tiếp xúc phải", "robotis_cm_led_left": "LED trái", "robotis_cm_led_right": "LED phải", "robotis_cm_led_both": "LED hai bên", "robotis_cm_switch": "trạng thái nút chọn", "robotis_cm_user_button": "tình trạng nút của người sử dụng", "robotis_cm_sound_detected": "số cuối cùng phát hiện âm thanh", "robotis_cm_sound_detecting": "số thời gian thực phát hiện âm thanh", "robotis_cm_ir_left": "cảm biến hồng ngoại trái", "robotis_cm_ir_right": "cảm biến hồng ngoại phải", "robotis_cm_calibration_left": "giá trị định chuẩn cảm biến hồng ngoại trái", "robotis_cm_calibration_right": "giá trị định chuẩn cảm biến hồng ngoại phải", "robotis_cm_clear_sound_detected": "khởi tạo số cuối cùng phát hiện âm thanh", "robotis_cm_buzzer_index": "chỉ số thang âm", "robotis_cm_buzzer_melody": "giai điệu", "robotis_cm_led_1": "LED 1", "robotis_cm_led_4": "LED 4", "robotis_aux_servo_position": "vị trí động cơ servo", "robotis_aux_ir": "cảm biến hồng ngoại", "robotis_aux_touch": "liên hệ cảm biến", "robotis_aux_brightness": "CDS", "robotis_aux_hydro_themo_humidity": "cảm biến nhiệt độ-độ ẩm (độ ẩm)", "robotis_aux_hydro_themo_temper": "cảm biến nhiệt độ-độ ẩm (nhiệt độ)", "robotis_aux_temperature": "cảm biến nhiệt độ", "robotis_aux_ultrasonic": "cảm biến siêu âm", "robotis_aux_magnetic": "cảm biến từ trường", "robotis_aux_motion_detection": "bộ dò chuyển động", "robotis_aux_color": "cảm biến màu sắc", "robotis_aux_custom": "thiết bị người dùng", "robotis_carCont_aux_motor_speed_1": "tốc độ của động cơ giảm tốc", "robotis_carCont_aux_motor_speed_2": "giá trị đầu ra", "robotis_carCont_calibration_1": "giá trị định chuẩn cảm biến hồng ngoại ", "robotis_openCM70_aux_motor_speed_1": "tốc độ của động cơ giảm tốc", "robotis_openCM70_aux_motor_speed_2": "thiết lập", "robotis_openCM70_aux_servo_mode_1": "chế độ động cơ servo", "robotis_openCM70_aux_servo_speed_1": "tốc độ động cơ servo", "robotis_openCM70_aux_servo_speed_2": "dữ liệu đầu ra", "robotis_openCM70_aux_servo_position_1": "vị trí động cơ servo", "robotis_openCM70_aux_led_module_1": "mô-đun LED", "robotis_openCM70_aux_custom_1": "thiết bị người dùng", "XBOT_digital": "kỹ thuật số", "XBOT_D2_digitalInput": "đầu vào kỹ thuật số D2", "XBOT_D3_digitalInput": "đầu vào kỹ thuật số D3", "XBOT_D11_digitalInput": "đầu vào kỹ thuật số D11", "XBOT_analog": "Analog", "XBOT_CDS": "giá trị cảm biến ánh sáng", "XBOT_MIC": "giá trị cảm biến Mic", "XBOT_analog0": "giá trị Analog PIN0", "XBOT_analog1": "giá trị Analog PIN1", "XBOT_analog2": "giá trị Analog PIN2", "XBOT_analog3": "giá trị Analog PIN3", "XBOT_Value": "Ouput Value", "XBOT_pin_OutputValue": "PIN, giá trị đầu ra", "XBOT_High": "cao", "XBOT_Low": "thấp", "XBOT_Servo": "động cơ Servo", "XBOT_Head": "đầu (D8)", "XBOT_ArmR": "tay phải(D9)", "XBOT_ArmL": "tay trái(D10)", "XBOT_angle": "góc độ", "XBOT_DC": "động cơ bánh xe (DC)", "XBOT_rightWheel": "phải", "XBOT_leftWheel": "trái", "XBOT_bothWheel": "hai bên", "XBOT_speed": "tốc độ", "XBOT_rightSpeed": "tốc độ bên phải động cơ(2) bánh xe(DC):", "XBOT_leftSpeed": "tốc độ bên trái(1):", "XBOT_RGBLED_R": "màu LED RBG từ màu đỏ", "XBOT_RGBLED_G": "xanh lá cây", "XBOT_RGBLED_B": "xanh dương", "XBOT_RGBLED_color": "màu LED RBG từ", "XBOT_set": "", "XBOT_c": "Đô", "XBOT_d": "Rê", "XBOT_e": "Mi", "XBOT_f": "Pha", "XBOT_g": "Son", "XBOT_a": "La", "XBOT_b": "Si", "XBOT_melody_ms": "phát nhạc trong~giây", "XBOT_Line": "dòng thứ ~", "XBOT_outputValue": "kiểm tra", "roborobo_num_analog_value_1": "Analog", "roborobo_num_analog_value_2": "Sensor Value", "roborobo_get_digital_value_1": "Digital", "roborobo_num_pin_1": "Digital", "roborobo_num_pin_2": "Pin", "roborobo_on": "On", "roborobo_off": "Off", "roborobo_motor1": "motor1", "roborobo_motor2": "motor2", "roborobo_motor_CW": "ClockWise", "roborobo_motor_CCW": "CounterClockWise", "roborobo_motor_stop": "Stop", "roborobo_input_mode": "Input", "roborobo_output_mode": "Output", "roborobo_pwm_mode": "PWM", "roborobo_servo_mode": "Servo", "roborobo_color": "Color Sensor ", "roborobo_color_red": " Red ", "roborobo_color_green": " Green ", "roborobo_color_blue": " Blue ", "roborobo_color_yellow": " Yellow ", "roborobo_color_detected": " Detected ", "roborobo_degree": " ˚", "robotori_D2_Input": "Digital Pin 2 Input Value", "robotori_D3_Input": "Digital Pin 3 Input Value", "robotori_A0_Input": "Analog Pin 0 Input Value", "robotori_A1_Input": "Analog Pin 1 Input Value", "robotori_A2_Input": "Analog Pin 2 Input Value", "robotori_A3_Input": "Analog Pin 3 Input Value", "robotori_A4_Input": "Analog Pin 4 Input Value", "robotori_A5_Input": "Analog Pin 5 Input Value", "robotori_digital": "Digital", "robotori_D10_Output": "Pin 10", "robotori_D11_Output": "Pin 11", "robotori_D12_Output": "Pin 12", "robotori_D13_Output": "Pin 13", "robotori_pin_OutputValue": "Output Value", "robotori_On": "On", "robotori_Off": "Off", "robotori_analog": "Analog", "robotori_analog5": "Pin 5 Output Value", "robotori_analog6": "Pin 6 Output Value", "robotori_analog9": "Pin 9 Output Value", "robotori_Servo": "Servo Motor", "robotori_DC": "DC Motor", "robotori_DC_rightmotor": "Right", "robotori_DC_leftmotor": "Left", "robotori_DC_STOP": "Stop", "robotori_DC_CW": "clockwise", "robotori_DC_CCW": "anticlockwise", "robotori_DC_select": "direction", "CALC_rotation_value": "giá trị vòng quay", "CALC_direction_value": "giá trị phương hướng", "VARIABLE_is_included_in_list": "", "VARIABLE_is_included_in_list_1": "is included in", "VARIABLE_is_included_in_list_2": "giá trị", "VARIABLE_is_included_in_list_3": "", "SCENE_when_scene_start": "khi cảnh bắt đầu", "SCENE_start_scene_1": "Start", "SCENE_start_scene_2": "cảnh", "SCENE_start_neighbor_scene_1": "Start", "SCENE_start_neighbor_scene_2": "cảnh", "SCENE_start_scene_pre": "trước", "SCENE_start_scene_next": "tiếp theo", "FUNCTION_explanation_1": "tên", "FUNCTION_character_variable": "chuỗi/số", "FUNCTION_logical_variable": "biến logic", "FUNCTION_function": "Tính năng", "FUNCTION_define": "xác định chức năng", "CALC_calc_operation_sin": "giá trị sin", "CALC_calc_operation_cos": "giá trị cos", "CALC_calc_operation_tan": "giá trị tan", "CALC_calc_operation_floor": "giá trị làm tròn số xuống", "CALC_calc_operation_ceil": "giá trị làm tròn số lên", "CALC_calc_operation_round": "giá trị làm tròn", "CALC_calc_operation_factorial": "giá trị giai thừa", "CALC_calc_operation_asin": "giá trị asin", "CALC_calc_operation_acos": "giá trị acos", "CALC_calc_operation_atan": "giá trị atan", "CALC_calc_operation_log": "giá trị log", "CALC_calc_operation_ln": "giá trị log tự nhiên", "CALC_calc_operation_natural": "integer value", "CALC_calc_operation_unnatural": "giá trị thập phân", "MOVING_locate_object_time_1": "factorial value", "MOVING_locate_object_time_2": "trong ~giây", "MOVING_locate_object_time_3": "", "wall_up": "phía trên tường", "wall_down": "phía dưới tường", "wall_right": "bên phải tường", "wall_left": "bên trái tường", "CALC_coordinate_x_value": "tọa độ x", "CALC_coordinate_y_value": "tọa độ y", "CALC_coordinate_rotation_value": "Vòng xoay", "CALC_coordinate_direction_value": "hướng", "CALC_picture_index": "chỉ số hình ảnh", "CALC_picture_name": "tên hình ảnh", "FLOW_repeat_while_true_1": "Repeat", "FLOW_repeat_while_true_2": "", "TUT_when_start": "", "TUT_move_once": "", "TUT_rotate_left": "", "TUT_rotate_right": "", "TUT_jump_barrier": "", "TUT_repeat_tutorial_1": "", "TUT_repeat_tutorial_2": "", "TUT_if_barrier_1": "", "TUT_if_barrier_2": "", "TUT_if_conical_1": "", "TUT_if_conical_2": "", "TUT_repeat_until": "", "TUT_repeat_until_gold": "", "TUT_declare_function": "", "TUT_call_function": "", "CALC_calc_operation_abs": "giá trị tuyệt đối", "CONTEXT_COPY_option": "chép mã", "Delete_Blocks": "xóa mã", "Duplication_option": "sao chép & dán", "Paste_blocks": "dán mã", "add_my_storage": "add to my storage", "export_object": "Export Object", "Clear_all_blocks": "xóa tất cả các mã", "add_comment": "add a memo", "copy_paste_comment": "copy & paste the memo", "copy_comment": "copy the memo", "delete_comment": "delete the memo", "fold_comment": "fold the memo", "open_comment": "open the memo", "separate_comment": "take the memo off", "hide_all_comment": "hide all memos", "show_all_comment": "show all memos", "transparency": "độ trong suốt", "BRUSH_change_brush_transparency_1": "thay đổi độ trong suốt của cọ bằng", "BRUSH_change_brush_transparency_2": "%", "BRUSH_set_brush_transparency_1": "thiết lập độ trong suốt của cọ bằng", "BRUSH_set_brush_transparency_2": "%", "CALC_char_at_1": "Ký tự", "CALC_char_at_2": "của", "CALC_char_at_3": "", "CALC_length_of_string_1": "Chiều dài của", "CALC_length_of_string_2": "", "CALC_substring_1": "Chuỗi của", "CALC_substring_2": "từ", "CALC_substring_3": "đến", "length_of_string": "to", "CALC_substring_4": "", "CALC_replace_string_1": "Thay thế ", "CALC_replace_string_2": "trong", "CALC_replace_string_3": "với", "CALC_replace_string_4": "", "CALC_change_string_case_1": "", "CALC_change_string_case_2": "của", "CALC_change_string_case_3": "", "CALC_change_string_case_sub_1": "chữ hoa", "CALC_change_string_case_sub_2": "chữ thường", "CALC_index_of_string_1": "Danh mục của", "CALC_index_of_string_2": "trong", "CALC_index_of_string_3": "", "MOVING_add_direction_by_angle_time_explain_1": "For", "MOVING_direction_relative_duration_1": "For", "MOVING_direction_relative_duration_2": "thiết lập phương hướng trong~giây ", "MOVING_direction_relative_duration_3": "", "CALC_get_sound_volume": "âm lượng", "SOUND_sound_from_to_1": "mở", "SOUND_sound_from_to_2": "sound from", "SOUND_sound_from_to_3": "từ ~giây", "SOUND_sound_from_to_4": "đến ~giây", "SOUND_sound_from_to_and_wait_1": "mở", "SOUND_sound_from_to_and_wait_2": "sound from", "SOUND_sound_from_to_and_wait_3": "từ ~giây", "SOUND_sound_from_to_and_wait_4": "đến ~giây và chờ", "CALC_quotient_and_mod_1": "", "CALC_quotient_and_mod_2": "của", "CALC_quotient_and_mod_3": "/", "CALC_quotient_and_mod_4": " ", "CALC_quotient_and_mod_sub_1": "thương số", "CALC_quotient_and_mod_sub_2": "phần còn lại", "self": "bản thân", "CALC_coordinate_size_value": "kích cỡ", "CALC_choose_project_timer_action_1": "", "CALC_choose_project_timer_action_2": "bộ đếm thời gian", "CALC_choose_project_timer_action_sub_1": "bắt đầu", "CALC_choose_project_timer_action_sub_2": "dừng lại", "CALC_choose_project_timer_action_sub_3": "khởi động", "LOOKS_change_object_index_1": "bring to", "LOOKS_change_object_index_2": "", "LOOKS_change_object_index_sub_1": "phía trước", "LOOKS_change_object_index_sub_2": "đằng trước", "LOOKS_change_object_index_sub_3": "đằng sau", "LOOKS_change_object_index_sub_4": "phía sau", "FLOW_repeat_while_true_until": "cho đến", "FLOW_repeat_while_true_while": "trong khi", "copy_block": "copy block(s)", "delete_block": "delete block(s)", "tidy_up_block": "sắp xếp các khối", "block_hi": "xin chào", "entry_bot_name": "Entrybot", "hi_entry": "Xin chào Entry!", "hi_entry_en": "Hello Entry!", "bark_dog": "dog barking", "walking_entryBot": "Walking Entrybot", "doggi_bark": "Doggi's Bark", "entry": "Entry", "hello": "xin chào ", "nice": "rất vui được gặp bạn", "silent": "Silent", "do_name": "Do", "do_sharp_name": "Do#(Re♭)", "re_name": "Re", "re_sharp_name": "Re(Mi♭)", "mi_name": "Mi", "fa_name": "Fa", "fa_sharp_name": "Fa#(Sol♭)", "sol_name": "Sol", "sol_sharp_name": "Sol#(La♭)", "la_name": "La", "la_sharp_name": "La#(Si♭)", "DUMMY": "더미", "coconut_stop_motor": "stop motor", "coconut_move_motor": "move motor", "coconut_turn_motor": "turn", "coconut_move_outmotor": "external motor", "coconut_turn_left": "left", "coconut_turn_right": "right", "coconut_move_forward": "forward", "coconut_move_backward": "backward", "coconut_note_c": "note_c", "coconut_note_d": "note_d", "coconut_note_e": "note_e", "coconut_note_f": "note_f", "coconut_note_g": "note_g", "coconut_note_a": "note_a", "coconut_note_b": "note_b", "coconut_move_speed_1": "0", "coconut_move_speed_2": "50", "coconut_move_speed_3": "100", "coconut_move_speed_4": "150", "coconut_move_speed_5": "255", "coconut_play_buzzer_hn": "Half", "coconut_play_buzzer_qn": "Quater", "coconut_play_buzzer_en": "Eighth", "coconut_play_buzzer_sn": "Sixteenth", "coconut_play_buzzer_tn": "Thirty-second", "coconut_play_buzzer_wn": "Whole", "coconut_play_buzzer_dhn": "Dotted half", "coconut_play_buzzer_dqn": "Dotted quarter", "coconut_play_buzzer_den": "Dotted eighth", "coconut_play_buzzer_dsn": "Dotted sixteenth", "coconut_play_buzzer_dtn": "Dotted thirty-second", "coconut_rest_buzzer_hr": "Half_rest", "coconut_rest_buzzer_qr": "Quater_rest", "coconut_rest_buzzer_er": "Eighth_rest", "coconut_rest_buzzer_sr": "Sixteenth_rest", "coconut_rest_buzzer_tr": "Thirty-second rest", "coconut_rest_buzzer_wr": "Whole_rest", "coconut_play_midi_1": "Twinkle Twinkle little star", "coconut_play_midi_2": "Three bears", "coconut_play_midi_3": "Mozart's Lullaby", "coconut_play_midi_4": "Do-Re-Mi", "coconut_play_midi_5": "Butterfly", "coconut_floor_sensing_on": "detect", "coconut_floor_sensing_off": "not detect", "coconut_dotmatrix_set_on": "on", "coconut_dotmatrix_set_off": "off", "coconut_dotmatrix_row_0": "all", "coconut_dotmatrix_row_1": "1", "coconut_dotmatrix_row_2": "2", "coconut_dotmatrix_row_3": "3", "coconut_dotmatrix_row_4": "4", "coconut_dotmatrix_row_5": "5", "coconut_dotmatrix_row_6": "6", "coconut_dotmatrix_row_7": "7", "coconut_dotmatrix_row_8": "8", "coconut_dotmatrix_col_0": "all", "coconut_dotmatrix_col_1": "1", "coconut_dotmatrix_col_2": "2", "coconut_dotmatrix_col_3": "3", "coconut_dotmatrix_col_4": "4", "coconut_dotmatrix_col_5": "5", "coconut_dotmatrix_col_6": "6", "coconut_dotmatrix_col_7": "7", "coconut_dotmatrix_col_8": "8", "coconut_sensor_left_proximity": "left IR distance", "coconut_sensor_right_proximity": "right IR distance", "coconut_sensor_both_proximity": "both IR distance", "coconut_sensor_left_floor": "left line tracer", "coconut_sensor_right_floor": "right line tracer", "coconut_sensor_both_floor": "both line tracer", "coconut_sensor_acceleration_x": "X-Axis Accelerometer", "coconut_sensor_acceleration_y": "Y-Axis Accelerometer", "coconut_sensor_acceleration_z": "Z-Axis Accelerometer", "coconut_sensor_light": "light sensor", "coconut_sensor_temperature": "temperature", "coconut_left_led": "left led", "coconut_right_led": "right led", "coconut_both_leds": "both led", "coconut_color_cyan": "Cyan", "coconut_color_magenta": "Magenta", "coconut_color_black": "Black", "coconut_color_white": "White", "coconut_color_red": "Red", "coconut_color_yellow": "Yellow", "coconut_color_green": "Green", "coconut_color_blue": "Blue", "coconut_beep": "buzzer on", "coconut_clear_buzzer": "buzzer off", "coconut_x_axis": "X-Axis", "coconut_y_axis": "Y-Axis", "coconut_z_axis": "Z-Axis", "modi_enviroment_bule": "Blue", "modi_enviroment_green": "Green", "modi_enviroment_humidity": "Humidity", "modi_enviroment_illuminance": "Illuminance", "modi_enviroment_red": "Red", "modi_enviroment_temperature": "Temparature", "modi_gyroscope_xAcceleratior": "X-axis acceleration", "modi_gyroscope_yAcceleratior": "Y-axis acceleration", "modi_gyroscope_zAcceleratior": "Z-axis acceleration", "modi_motor_angle": "Angle", "modi_motor_speed": "Speed", "modi_motor_torque": "Torque", "modi_speaker_F_DO_5": "DO 5", "modi_speaker_F_DO_6": "DO 6", "modi_speaker_F_DO_7": "DO 7", "modi_speaker_F_DO_S_5": "DO #5", "modi_speaker_F_DO_S_6": "DO #6", "modi_speaker_F_DO_S_7": "DO #7", "modi_speaker_F_MI_5": "MI 5", "modi_speaker_F_MI_6": "MI 6", "modi_speaker_F_MI_7": "MI 7", "modi_speaker_F_PA_5": "FA 5", "modi_speaker_F_PA_6": "FA 6", "modi_speaker_F_PA_7": "FA 7", "modi_speaker_F_PA_S_5": "FA #5", "modi_speaker_F_PA_S_6": "FA #6", "modi_speaker_F_PA_S_7": "FA #7", "modi_speaker_F_RA_5": "LA 5", "modi_speaker_F_RA_6": "LA 6", "modi_speaker_F_RA_7": "LA 7", "modi_speaker_F_RA_S_5": "LA #5", "modi_speaker_F_RA_S_6": "LA #6", "modi_speaker_F_RA_S_7": "LA #7", "modi_speaker_F_RE_5": "RE 5", "modi_speaker_F_RE_6": "RE 6", "modi_speaker_F_RE_7": "RE 7", "modi_speaker_F_RE_S_5": "LA #5", "modi_speaker_F_RE_S_6": "RE #6", "modi_speaker_F_RE_S_7": "RE #7", "modi_speaker_F_SOL_5": "SOL 5", "modi_speaker_F_SOL_6": "SOL 6", "modi_speaker_F_SOL_7": "SOL 7", "modi_speaker_F_SOL_S_5": "SOL #5", "modi_speaker_F_SOL_S_6": "SOL #6", "modi_speaker_F_SOL_S_7": "SOL #7", "modi_speaker_F_SO_5": "TI 5", "modi_speaker_F_SO_6": "TI 6", "modi_speaker_F_SO_7": "TI 7", "si_name": "Si", "ev3_ccw": "CCW", "ev3_cw": "CW", "rokoboard_sensor_name_0": "Sound", "rokoboard_sensor_name_1": "Light", "rokoboard_sensor_name_2": "Slider", "rokoboard_sensor_name_3": "resistance-A", "rokoboard_sensor_name_4": "resistance-B", "rokoboard_sensor_name_5": "resistance-C", "rokoboard_sensor_name_6": "resistance-D", "rokoboard_string_1": "Button Pressed", "HW_MOTOR": "Motor", "HW_SENSOR": "Sensor", "HW_LED": "Led", "HW_MELODY": "Melody", "HW_ROBOT": "Robot", "ALTINO_ACCX": "acceleration X axis", "ALTINO_ACCY": "acceleration Y axis", "ALTINO_ACCZ": "acceleration Z axis", "ALTINO_BAT": "battery check", "ALTINO_CDS": "light", "ALTINO_GYROX": "gyro X axis", "ALTINO_GYROY": "gyro Y axis", "ALTINO_GYROZ": "gyro Z axis", "ALTINO_IR1": "1 distance", "ALTINO_IR2": "2 distance", "ALTINO_IR3": "3 distance", "ALTINO_IR4": "4 distance", "ALTINO_IR5": "5 distance", "ALTINO_IR6": "6 distance", "ALTINO_Led_Brake_Light": "brake", "ALTINO_Led_Forward_Light": "forward", "ALTINO_Led_Reverse_Light": "backward", "ALTINO_Led_Turn_Left_Light": "left direction", "ALTINO_Led_Turn_Right_Light": "right direction", "ALTINO_Line": "line", "ALTINO_MAGX": "geomagnetic X axis", "ALTINO_MAGY": "geomagnetic Y axis", "ALTINO_MAGZ": "geomagnetic Z axis", "ALTINO_REMOTE": "remote control", "ALTINO_STTOR": "steering torque", "ALTINO_STVAR": "steering potentiometer", "ALTINO_Steering_Angle_Center": "center", "ALTINO_Steering_Angle_Left10": "left10", "ALTINO_Steering_Angle_Left15": "left15", "ALTINO_Steering_Angle_Left20": "left20", "ALTINO_Steering_Angle_Left5": "left5", "ALTINO_Steering_Angle_Right10": "right10", "ALTINO_Steering_Angle_Right15": "right15", "ALTINO_Steering_Angle_Right20": "right20", "ALTINO_Steering_Angle_Right5": "right5", "ALTINO_TEM": "temperature", "ALTINO_TOR1": "right torque", "ALTINO_TOR2": "left torque", "ALTINO_Value": "output value", "ALTINO_a": "la", "ALTINO_a2": "la#", "ALTINO_b": "si", "ALTINO_c": "do", "ALTINO_c2": "do#", "ALTINO_d": "re", "ALTINO_d2": "re#", "ALTINO_dot_display_1": "one char", "ALTINO_dot_display_2": "display", "ALTINO_e": "mi", "ALTINO_f": "fa", "ALTINO_f2": "fa#", "ALTINO_g": "sol", "ALTINO_g2": "sol#", "ALTINO_h": "off", "ALTINO_h2": "on", "ALTINO_leftWheel": "left", "ALTINO_melody_ms": "play", "ALTINO_outputValue": "output", "ALTINO_rightWheel": "right", "ALTINO_set": " display", "ardublock_motor_forward": "Forward", "ardublock_motor_backward": "Backward", "jdkit_clockwise": "시계방향", "jdkit_counterclockwise": "반시계방향", "jdkit_gyro_frontrear": "앞뒤", "jdkit_gyro_leftright": "좌우", "jdkit_joystick_leftleftright": "왼쪽 좌우", "jdkit_joystick_lefttopbottom": "왼쪽 상하", "jdkit_joystick_rightleftright": "오른쪽 좌우", "jdkit_joystick_righttopbottom": "오른쪽 상하", "jdkit_led": "LED", "jdkit_led_color_green": "초록색", "jdkit_led_color_orange": "오랜지색", "jdkit_led_turnoff": "끄기", "jdkit_led_turnon": "켜기", "jdkit_motor_leftbottom": "왼쪽아래", "jdkit_motor_lefttop": "왼쪽위", "jdkit_motor_rightbottom": "오른쪽아래", "jdkit_motor_righttop": "오른쪽위", "jdkit_tune_do": "도", "jdkit_tune_fa": "파", "jdkit_tune_la": "라", "jdkit_tune_mi": "미", "jdkit_tune_re": "레", "jdkit_tune_si": "시", "jdkit_tune_sol": "솔", "FUNBOARD_bt_down": "yellow(B)", "FUNBOARD_bt_left": "green(C)", "FUNBOARD_bt_right": "blue(D)", "FUNBOARD_bt_up": "red(A)", "FUNBOARD_column_tag": "column", "FUNBOARD_do_off": "off", "FUNBOARD_do_on": "on", "FUNBOARD_led_color_all": "모두", "FUNBOARD_led_color_blue": "blue", "FUNBOARD_led_color_green": "green", "FUNBOARD_led_color_red": "red", "FUNBOARD_led_color_str": "color ", "FUNBOARD_led_color_yellow": "yellow", "FUNBOARD_led_off_str": "Turn off the LED", "FUNBOARD_led_on_str": "Turn on the LED", "FUNBOARD_row_tag": "row", "FUNBOARD_scroll_down": "downward", "FUNBOARD_scroll_left": "leftward", "FUNBOARD_scroll_no": "no", "FUNBOARD_scroll_right": "rightward", "FUNBOARD_scroll_up": "upwards", "FUNBOARD_sensor_cds": "light sensor", "FUNBOARD_sensor_mic": "microphone sensor", "FUNBOARD_sensor_slide": "potentiometer", "FUNBOARD_sensor_state_1": "low", "FUNBOARD_sensor_state_2": "high", "FUNBOARD_touchbt_down": "yellow(B)", "FUNBOARD_touchbt_enter": " F", "FUNBOARD_touchbt_escape": " G", "FUNBOARD_touchbt_left": "green(C)", "FUNBOARD_touchbt_right": "blue(D)", "FUNBOARD_touchbt_space": " E", "FUNBOARD_touchbt_up": "red(A)", "funboard_dotmatrix_set_off": "off", "funboard_dotmatrix_set_on": "on", "AI_UTILIZE": "AI", "video_show_video": "Show", "video_hide_video": "Hide", "video_brightness": "brightness", "video_transparency": "transparency", "video_left_right": "horizontally", "video_top_bottom": "vertically", "video_human": "people", "video_face": "face", "video_object": "object", "video_start": "Start", "video_end": "Stop", "video_gender": "gender", "video_age": "age", "video_emotion": "emotion", "video_motion_onself": "itself", "video_motion_onscreen": "screen", "video_motion_scale": "motion", "video_motion_direction_horizontal": "x direction", "video_motion_direction_vertical": "y direction", "table_row": "row", "table_col": "column", "table_sum": "sum", "table_max": "max", "table_min": "min", "table_avg": "average", "table_stdev": "standard deviation", "arduino_lite_reconnect": "Retry", "arduino_lite_download_firmware": "Download Firmware", "arduino_lite_download_driver": "Download Driver", "arduino_lite_connect": "Web Connection", "arduino_lite_disconnect": "Cancel", "arduino_lite_guide": "• connection guide", }; Lang.video_body_coord_params = { "left_eye": "Left Eye", "right_eye": "Right Eye", "nose": "Nose", "left_mouth": "Left Mouth", "right_mouth": "Right Mouth", "upper_lip": "Upper Lip", "lower_lip": "Lower Lip", "face": "face", "neck": "face", "left_ear": "left ear", "right_ear": "right ear", "left_shoulder": "left shoulder", "left_elbow": "left elbow", "left_wrist": "left wrist", "left_hip": "left hip", "left_knee": "left knee", "left_ankle": "left ankle", "right_shoulder": "right shoulder", "right_elbow": "right elbow", "right_wrist": "right wrist", "right_hip": "right hip", "right_knee": "right knee", "right_ankle": "right ankle" }; Lang.video_emotion_params = { "angry": "Anger", "disgusted": "Disgust", "fearful": "Fearful", "happy": "Happiness", "neutral": "Neutral", "sad": "Sadness", "surprised": "Surprised" }; Lang.video_object_params = { "person": "person", "bicycle": "bicycle", "car": "car", "motorcycle": "motorcycle", "airplane": "airplane", "bus": "bus", "train": "train", "truck": "truck", "boat": "boat", "traffic light": "traffic light", "fire hydrant": "fire hydrant", "stop sign": "stop sign", "parking meter": "parking meter", "bench": "bench", "bird": "bird", "cat": "cat", "dog": "dog", "horse": "horse", "sheep": "sheep", "cow": "cow", "elephant": "elephant", "bear": "bear", "zebra": "zebra", "giraffe": "giraffe", "backpack": "backpack", "umbrella": "umbrella", "handbag": "handbag", "tie": "tie", "suitcase": "suitcase", "frisbee": "frisbee", "skis": "skis", "snowboard": "snowboard", "sports ball": "sports ball", "kite": "kite", "baseball bat": "baseball bat", "baseball glove": "baseball glove", "skateboard": "skateboard", "surfboard": "surfboard", "tennis racket": "tennis racket", "bottle": "bottle", "wine glass": "wine glass", "cup": "cup", "fork": "fork", "knife": "knife", "spoon": "spoon", "bowl": "bowl", "banana": "banana", "apple": "apple", "sandwich": "sandwich", "orange": "orange", "broccoli": "broccoli", "carrot": "carrot", "hot dog": "hot dog", "pizza": "pizza", "donut": "donut", "cake": "cake", "chair": "chair", "couch": "couch", "potted plant": "potted plant", "bed": "bed", "dining table": "dining table", "toilet": "toilet", "tv": "tv", "laptop": "laptop", "mouse": "mouse", "remote": "remote", "keyboard": "keyboard", "cell phone": "cell phone", "microwave": "microwave", "oven": "oven", "toaster": "toaster", "sink": "sink", "refrigerator": "refrigerator", "book": "book", "clock": "clock", "vase": "vase", "scissors": "scissors", "teddy bear": "teddy bear", "hair drier": "hair dryer", "toothbrush": "toothbrush" }; Lang.Buttons = { "share_policy": "Share Guide", "write_policy": "Write Guide", "lesson_list": "List", "complete_study": "Complete", "show_me": "Show Me", "do_this_for_me": "Do This For Me", "previous": "Previous ", "get_started": "Get Started", "next_lesson": "Next lesson", "course_submit": "Submit", "course_done": "Done", "mission": "Introduction ", "basic_guide": "User Guide", "apply": "ứng dụng", "add": "Add", "cancel": "hủy bỏ", "save": "OK", "start": "Start", "confirm": "OK", "delete": "Delete", "create": "Create Class", "done": "Done", "accept": "Accept", "refuse": "Refuse", "yes": "Yes", "button_no": "No", "quiz_retry": "Try Again", "discuss_upload": "Upload", "maze_popup_guide": "User Guide", "maze_popup_mapHint": "Hint", "maze_hint_btn_guide": "User Guide", "maze_hint_btn_block": "Block Help", "maze_hint_btn_map": "Map Hint", "maze_hint_btn_goal": "goal", "list_save": "Upload", "duplication": "Copy", "export_to_excel": "Download", "single_line": "Single line", "multi_line": "Multiline", "lecture_finish_popup_reset_lecture": "Do it again", "lecture_finish_popup_show_output": "See the exercised", "lecture_view_hints": "View hints", "default_hint_title": "How do you make it?", "show_only_vector": "Only Vector" }; Lang.Menus = { "nothing_to_import": "There is no content to upload.", "nothing_to_export": "There is no content to download.", "content_copied": "The data is copied.", "list_import_title": "Import", "list_import_placeholder": "Example)\nData1\nData2\nData3\nData4\nData5\nData6\nData7\nData8", "verifying_email": "Verifying email", "list_import_notice_1": "You can upload the data in the list.", "list_import_notice_2": "The original data will be changed into the newly uploaded data.", "list_export_title": "Export", "list_export_notice": "You can copy or download the data in the list.", "robotis_opencm70": "Robotis Open CM70", "cannnot_mark_favorite": "Private project cannot be marked as a favorite.", "enterPassword": "Enter password.", "enterPassword_update": "Please enter your password to save your changes.", "enterNewPassword": "Enter new password.", "reEnterNewPassword": "Re-enter new password.", "resign": "Account deletion", "check_sended_email": "Please check your inbox to verify your email.", "signUpEmail_1": "Verification mail has been sent. ", "signUpEmail_2": "Please verify your email.", "select_email_unauthenticated_user": "The email address is registered to the IDs below.\nPlease choose the right one.", "select_user": "Please choose the ID.", "enter_password_withdraw": "Enter password to delete your account", "instruction_agree": "Please check instruction and agree.", "check_instructions": "I check instructions and agree.", "deleteAccount_2": "After 30 days, every data that you created in Entry such as project/lecture/class/post/comment/like/favourite will be deleted and cannot be restored.", "deleteAccount_1": "If you sign in again within 30 days, you can withdraw account deletion.", "protect_account": "Protect your account with a safe password.", "please_verify": "Please verify your email to click 'Verifying email'", "unverified_email": "Unverified email", "deleteAccount": "Delete account", "corporatePersonal": "Agree to the transfer of personal information.", "corporateTransferGuide": "Personal Information transfer guide", "corporateReciever": "Information reciever : Connect Foundation", "corporateAddress": "Connect Foundation Address&Contact", "corporateAddress_1": "Meritz Tower 7, Seoul Gangnam-gu Gangnam-daero 382, Seoul, Korea", "corporateConsent": "If you do not want to transfer your information, you may withdraw the consent.", "corporateEmail": "For withdraw the consent, send an email to", "corporateAddition": "In addition, the terms and conditions of the agreement will be changed, depending on the transfer.", "corporateApplicationDate": "Application date : From October 29, 2017", "corporateTargetChanges": "Application Targets and Changes : ", "corporateTarget": "Targets", "corporateChanges": "Changes", "corporateTerms": "Terms", "corporateOperator": "The name of the ‘Entry’ operator", "corporateClassroomTerms": "Classroom Service Terms of Use", "doAgreeWithClassroomTerms": "Agree to the Classroom Service Terms of Use.", "doChangePassword": "Please change the password into the one that only you can know.", "corporatePrivacyPolicy": "Privacy Policy", "corporateConsignment": "The name of the ‘Entry’ operator. And consignment of personal information", "corporateEntrusted": "Entrusted Company : NHN Technology Services Corporation.", "corporateConsignmentDetails": "Details of Consignment : Service operation.", "corporatePeriod": "Consignment Period : Until the member cancels membership or the consignment contract ends.", "corporateChangeDate": "Date of change : October 29, 2017", "corporateWarning": "Please Agree to the transfer of personal information.", "corporateConfirm": "Confirm", "corporateTitle": "Hello. This is EntryLabs.
We are very grateful to you who are using 'Entry'. 
Recently we have agreed to transfer the ownership of Entry web site, which has been operated for public interest purposes, to the 'Connect Foundation'.
Connect Foundation is a non-profit foundation founded by Naver. 'Entry' will be continuously operated under public interest purpose by 'Connect Foundation'. Therefore, All of “Entry” users will be guaranteed to use the entry exactly as same as before.
Since the website provider has changed from the 'EntryLabs' to the 'Connect Foundation', there is a transfer of personal information as below. However, this doesn’t mean that your information will be physically moved.
", "textcoding_numberError_f": "You can't convert into the text mode if there is function names start with a number.", "textcoding_bookedError_1f": "You can't convert into the text mode if there is function named", "textcoding_bookedError_2f": ".", "textcoding_specialCharError_f": "You can't convert into the text mode if there is function names include special character except for underscore.", "textcoding_numberError_v": "You can't convert into the text mode if there is variable names start with a number.", "textcoding_bookedError_1v": "You can't convert into the text mode if there is variable named ", "textcoding_bookedError_2v": ".", "textcoding_specialCharError_v": "You can't convert into the text mode if there is variable names include special character except for underscore.", "textcoding_numberError_l": "You can't convert into the text mode if there is list names start with a number.", "textcoding_bookedError_1l": "You can't convert into the text mode if there is list named ", "textcoding_bookedError_2l": ".", "textcoding_specialCharError_l": "You can't convert into the text mode if there is list names include special character except for underscore.", "no_discuss_permission": "You don't have permission to view this post.", "delete_comment": "Are you sure you want to delete commnet", "delete_article": "Are you sure you want to delete article", "discuss_cannot_edit": "You cannot edit this post", "discuss_extention": "You cannot upload files with that extension", "delete_discuss_picture": "Do you want to delete the photo?", "delete_discuss_file": "Do you want to delete the file?", "discuss_save_question": "Do you want save your post?", "discuss_cancle_question": "Do you want to leave without saving?", "discuss_saved": "is saved", "discuss_no_write_permission": "Cannot be saved with the current login account.", "discuss_no_project_permission": "Cannot be saved with the current login account.", "discuss_write_abuse_detected": "Several articles have been written within a \nshort period of time. \nPlease try again in 1 minutes.", "contents_abuse_detected": "Please try again in 5 minutes.", "contents_abuse_detected_10": "Please try again in 10 minutes.", "discuss_new_write_abuse_warn": "Posting multiple comments within a \nshort period of time may limit the post \nof comments.\nBe careful of your use.", "discuss_write_abuse_warn": "Posting multiple comments within a \nshort period of time may limit the post \nof comments.\nBe careful of your use.", "find_not_your_email": "Please enter a valid email.", "search_lang": "search", "search_title": "title", "faq_desc": "Check the answers for the questions you had while using the Entry.", "faq_all": "Total", "faq_site": "Site guide", "faq_project": "Project", "faq_hardware": "Hardware", "faq_offline": "Offline editor", "faq_copyright": "Copyright", "faq_title": "FAQ", "faq": "FAQ", "malicious_warning": "You cannot attach an unwholesome image. If the image doesn't unwholesome, please report it.", "fword_alert_msg": "You can not post abusive or malicious sentences.", "fword_alert_1": "You can not post abusive comments or malicious comments", "fword_alert_2": "Your post will be replaced alternative sentence because it contains unhealthy words.", "fword_replace_1": "Entry is an education platform created to help anyone learn to code.", "fword_replace_2": "Entry is an education platform created to help anyone learn to code.", "fword_replace_3": "Entry is an education platform created to help anyone learn to code.", "fword_replace_4": "Entry is an education platform created to help anyone learn to code.", "fword_replace_5": "Entry is an education platform created to help anyone learn to code.", "fword_replace_6": "Entry is an education platform created to help anyone learn to code.", "fword_replace_7": "Entry is an education platform created to help anyone learn to code.", "solve_quiz": "Quiz", "submit_homework_first_title": "Complete! Submit an assignment", "submit_homework_first_content": "Great work is done! Submit your assignment.
You may resubmit your assignment before the deadline.", "submit_homework_again_title": "Resubmit", "submit_homework_again_content": "This project has been submitted already.
Would you like to resubmit?", "submit_homework_expired_title": "Submission Closed", "submit_homework_expired_content": "Assignment deadline is over.", "done_study_title": "Complete", "done_study_content": "Fabulous project is complete", "featured_courses": "Featured Courses", "follow_along": "Follow Along", "follow_along_desc": "Create various projects as you follow along step by step.", "do_quiz": "Quiz", "do_quiz_desc": "Check your knowledge through quizzes.", "challenge": "Challenge", "play": "Play", "challenge_desc": "Learn programming concepts by solving problems.", "creste_freely": "Create freely", "creste_freely_desc": "Create your projects using what you've learned.", "entry_rc_desc": "Learn programming concepts in steps with Entry lectures! Start now!", "hw_deadline": "Deadline", "rc_course_desc": "Lecture collection created for learning programming concepts level by level", "rc_course": "Entry Recommended Courses", "entry_rec_course": "Entry Recommended Courses", "entry_rec_course_desc": "Anyone can follow along and easily create projects with Entry Lectures.", "guidance": "Guidance", "wait": "Wait", "hint": "Hint", "concept_guide": "Concept Guide", "group_quiz": "Quiz", "fail_check_hint": "Oh no! Try again!
Check [Hint] if you are stuck!", "sort_student": "Student", "sort_lesson": "Lesson", "sort_course": "Course", "student_progress": "Student Progress", "my_progress": "Progress", "lec_in_progress": "in progress", "free_modal_asgn_over": "Assignment deadline is over.", "free_submission_closed": "Submission Closed", "free_modal_asgn_submit_first": "Great work is done! Submit your assignment.
You may resubmit your assignment before the deadline.", "asgn_submit": "Complete! Submit an assignment.", "free_modal_content_resubmit": "This project has been submitted already.
Would you like to resubmit?", "asgn_resubmit": "Resubmit", "free_modal_content_complete": "Fabulous Project is complete.", "guide_modal_content_complete": "Let's run the program", "success": "Success", "fail": "Fail", "mission_modal_content_fail": "
Check [Hint] if you are stuck!", "mission_modal_content_success": "Let's run the program", "in_progress": "in progress", "completed": "Completed", "submitted": "submitted", "submission_closed": "Submission Closed", "progress": "Progress", "study_completed": "completed", "view_course_desc": "View Description", "main_entry_starter": "From basics! Entry Starter", "main_entry_booster": "Concepts! Entry Booster", "main_entry_master": "Ideas unfold! Entry Master", "no_students_in_classroom": "No students yet.
Please add or invite students.", "lectures": "lessons", "Lectures": "Lessons", "studentHomeworkList": "assignment", "curriculums": "courseware", "Curriculums": "Courseware", "quiz": "quiz", "no_added_group_contents_teacher": "There is no %1.
Please create a %1.", "no_added_group_contents_student": "There is no %1.", "side_project": "Goal project", "custom_make_course_1": "Create courseware from", "custom_make_course_2": "'Create lessons > Create Courseware'", "custom_make_lecture_1": "Create lessons from 'open lessons'", "custom_make_lecture_2": "", "alert_enter_info": "Please enter your information", "alert_enter_new_pwd": "Enter new password", "alert_match_pwd": "Password doesn't match the confirmation", "alert_check_pwd": "Please check your password", "alert_update_complete": "Edit complete", "no_group_contents_each_prefix": "There is no ", "no_group_contents_each_suffix": " in our classroom.", "no_group_contents_all": "There is no new content.
Share projects in My Classroom gallery.", "hw_closed": "submission closed", "tag_Lecture": "Lessons", "tag_Curriculum": "Courseware", "tag_Discuss": "Discuss", "count_ko": ".", "no_asgn_within_week": "There is no assignment due within a week", "lecture_and_curriculum": "Open Lessons", "assignments_plural": "Assignments", "assignments_singular": "Assignment", "project_plural": "Projects", "group_news": "News", "stu_management": "Student management", "stu_management_camel": "Student Management", "view_all": "View all", "view_all_camel": "View All", "view_contents_camel": "View All", "view_contents": "Contents", "no_updated_news": "There is no update", "homework_soon_due": "Assignment soon due", "new_homework": "New Assignment", "no_new_homework": "There is no new Assignment", "student_plural": "Students", "discuss": "notice", "basic_project": "Basic Project", "no_permission": "You have no permission.", "no_comment_write_permission": "Cannot write comments with the currently logged in account.", "original_curriculum_deleted": "The original courseware was deleted", "original_curriculum": "Original courseware", "save_as_my_lecture": "Save as My Lecture", "delete_confirm": "Confirm", "lecture_open_as_copied": "All lectures in Open Lesson are saved as copy and open to public view", "curriculum_open_as_copied": "All Courseware listed under Open Lesson are saved as copy and open to public view", "lecture_save_as_copied_group": "All lectures in My Class Lecture are saved as copy and open to public view", "curriculum_save_as_copied_group": "All Lecture Collection listed under My Class Lecture Collection are saved as copy and open to public view", "homework_save_as_copied_group": "All Assignments listed under Class Assignment page are saved as copy and open to public view", "lecture_save_as_copied": "Lecture inserted in the Lecture collection is saved as a copy.", "done_project_save_as_copied": "Completed project inserted in the Lecture is saved as a copy.", "textbook_project_can_not_applied": "", "original_lecture_deleted": "The original lecture was deleted", "original_lecture": "Original lecture", "lecture_save_as_mine_alert": "Saved.\nnSaved Lecture is listed under 'My Page > My Lecture'", "lecture_save_as_mine": "Save as My Lecture", "duplicate_username": "The ID you entered is already in use", "share_your_project": "", "not_available_student": "ID entered is class issued 'Class ID'. \nPlease enter 'Entry Member ID'.", "login_instruction": "Log-in instructions", "login_needed": "Service is available after log-in", "login_as_teacher": "Log in as Teacher to use the service", "remove_my_storage": "Are you sure to remove it from my storage? Deleted blocks/objects cannot be recovered.", "submit_hw": "submit", "success_goal": "Success", "choseok_final_result": "Great! I completed my own project!", "choseok_fail_msg_timeout": "시간이 너무 많이 지나버렸어. 목표를 잘 보고 다시 한번 도전해봐!", "choseok_fail_msg_die": "생명이 0이하인데 게임이 끝나지 않았어.\n아래의 블록을 사용해서 다시 도전해 보는 건 어때?", "grade_1": "Basic", "grade_2": "Intermediate", "grade_3": "Advanced", "find_sally_title": "Finding Sally", "save_sally_title": "Saving Sally", "exit_sally_title": "Escaping", "find_sally": "Combine the power of the LINE Rangers\nand defeat the powerful villain Mephisto\nand save Sally!", "save_sally": "Sally is trapped at Mephisto's base.\nHelp the LINE Rangers get to Sally by avoiding\nobstacles!", "exit_sally": "Help Sally and LINE Rangers escape safely\nfrom the exploding Mephisto base!", "go_next_mission": "다른 미션 도전하기", "share_my_project": "내가 만든 작품 공유하기", "share_certification": "인증서 공유하기", "print_certification": "인증서를 뽐내봐", "get_cparty_events": "내가 받은 인증서를 출력해 뽐내면 푸짐한 상품을 받을 수 있어요!", "go_cparty_events": "이벤트 참여하러 가기", "codingparty2016_blockHelper_1_title": "", "codingparty2016_blockHelper_1_contents": "", "codingparty2016_blockHelper_2_title": "", "codingparty2016_blockHelper_2_contents": "", "codingparty2016_blockHelper_3_title": "", "codingparty2016_blockHelper_3_contents": "", "codingparty2016_blockHelper_4_title": "", "codingparty2016_blockHelper_4_contents": "", "codingparty2016_blockHelper_5_title": "", "codingparty2016_blockHelper_5_contents": "", "codingparty2016_goalHint_1": "", "codingparty2016_goalHint_2": "", "codingparty2016_goalHint_3": "", "codingparty2016_goalHint_4": "", "codingparty2016_goalHint_5": "", "codingparty2016_goalHint_6": "", "codingparty2016_goalHint_7": "", "codingparty2016_goalHint_8": "", "codingparty2016_goalHint_9": "", "codingparty2016_guide_1_1_contents": "", "codingparty2016_guide_1_1_title": "", "codingparty2016_guide_1_2_title": "", "codingparty2016_guide_1_2_contents": "", "codingparty2016_guide_1_3_title": "", "codingparty2016_guide_1_3_contents": "", "codingparty2016_guide_1_4_title": "", "codingparty2016_guide_1_4_contents": "", "codingparty2016_guide_1_5_title": "", "codingparty2016_guide_1_5_contents": "", "codingparty2016_guide_2_1_title": "", "codingparty2016_guide_2_1_contents": "", "codingparty2016_guide_3_1_title": "", "codingparty2016_guide_3_1_contents": "", "codingparty2016_guide_5_1_title": "", "codingparty2016_guide_5_1_contents": "", "codingparty2016_guide_5_2_title": "", "codingparty2016_guide_5_2_contents": "", "codingparty2016_guide_7_1_title": "", "codingparty2016_guide_7_1_contents": "", "codingparty2016_guide_9_1_title": "", "codingparty2016_guide_9_1_contents": "", "codingparty2016_guide_9_2_title": "", "codingparty2016_guide_9_2_contents": "", "find_interesting_lesson": "Browse through 'Class lessons’ section to find interesting lessons!", "find_interesting_course": "Browse through 'Class courseware’ section to find interesting courseware!", "select_share_settings": "Select share settings", "faq_banner_title": "FAQ", "check_out_faq": "Check out Entry’s FAQ", "faq_banner_content": "Do you have any question about Entry?
We give you the answer in FAQ.
Find out now!", "faq_banner_button": "Go to FAQ", "major_updates": "Major updates", "check_new_update": "Check out\nEntry's new updates", "major_updates_notification": "Entry's major updates are announced by notification. ", "find_out_now": "Find out now!", "offline_hw_program": "Offline and Hardware Connection Program", "read_more": "read more", "sample_project": "Sample Project", "not_supported_function": "thiết bị này không được hỗ trợ", "offline_download_confirm": "Entry Offline Editor is available for PC. Would you like to download?", "hardware_download_confirm": "Entry Hardware Program is available for PC. Would you like to download?", "copy_text": "Copy text.", "select_openArea_space": "Select share settings", "mission_guide": "Mission guide", "of": " 's ", "no_results_found": "No results found", "upload_pdf": "Upload PDF materials", "select_basic_project": "Select Project", "try_it_out": "TRY IT OUT", "go_boardgame": "ENTRY-Bot Board Game", "go_cardgame": "ENTRY Bot Card game", "go_solve": "Learn programming", "go_ws": "Entry Create", "go_arts": "Entry Share", "group_delete_alert": "Once you delete this class, all data including temporary student accounts will be deleted.\nAre you sure you want to delete?", "view_arts_list": "list", "hw_submit_confirm_alert": "Assignment submitted", "hw_submit_alert": "Would you like to submit your assignment?", "hw_submit_alert2": "Would you like to submit your assignment? Submission will only submit what you've completed.", "hw_submit_cannot": "You cannot submit this assignment", "see_other_missions": "See other missions", "project": "Project", "marked": "favorite", "group": "group", "lecture": "Lessons", "Lecture": "Lessons", "curriculum": "Courseware", "Curriculum": "Courseware", "studying": "studying", "open_only_shared_lecture": "오픈 강의 페이지에 <공개> 한 강의만 불러올 수 있습니다. 불러오고자 하는 강의공개여부를 확인해 주세요.", "already_exist_group": "group already exists", "cannot_invite_you": "Can't invite by yourself", "apply_original_image": "Save original image", "draw_new_ques": "Are you sure you want to go to \n'Draw new object' page?", "draw_new_ques_1": "You can draw an object and save it.", "draw_new_ques_2": "do you want to move to draw?", "draw_new_go": "Move", "draw_new_stay": "No, Stay", "file_upload_warn_title_image": "The following pictures are subject to the Terms of Use and related laws.", "file_upload_warn_desc_image": "Violent and brutal picture
Sacred body exposure picture
Offensive or disgusting picture
Picture of copyright prohibited from unauthorized use", "file_upload_warn_title_sound": "The following sounds are subject to the Terms of Use and related laws.", "file_upload_warn_desc_sound": "Violent and cruel sound
Suggestive sound
Offensive or disgusting sound
Sound of copyright prohibited from unauthorized use", "file_upload_warn_title_table": "The following datas are subject to the Terms of Use and related laws.", "file_upload_warn_desc_table": "Violent and brutal data
Sacred body exposure data
Offensive or disgusting data
Data of copyright prohibited from unauthorized use", "file_upload_warn_link": "Learn about copyright", "file_upload_desc_1": "Make sure you don't upload", "file_upload_desc_2": "Violent and brutal picture", "file_upload_desc_3": "Sacred body exposure picture", "file_upload_desc_4": "Offensive or disgusting picture", "file_upload_desc_5": "* Uploading of above contents may be restricted under user policy and related laws.", "picture_upload_warn_old": "You can only upload jpg, png, bmp files that are less than 10MB.", "sprite_upload_warn_old": "You can only upload images in jpg, png, bmp format or objects in eo format that are less than 10MB.", "picture_upload_warn_1": "You can only upload jpg, png, bmp, svg files that are less than 10MB.\nThe jpg, png, and bmp images are edited in bitmap mode and the svg image is in vector mode.", "table_upload_warn_1": "You can only upload csv, xls(x) files that are less than 10MB.", "sprite_upload_warn": "You can only upload images in jpg, png, bmp, svg format or objects in eo format that are less than 10MB.", "sound_upload_warn_1": "You can only upload mp3 files that are less than 10MB.", "sound_edit_warn": "Please wait!
We're working on the Sound Editing function.", "file_upload_loading": "Loading", "lesson_by_teacher": "Teacher created lesson", "delete_group_art": "from the list?", "elementary_short": "elementary", "middle_short": "middle school", "grade_34": "3-4th", "grade_56": "5-6th", "grade_78": "7+", "share_lesson": "sharing lesson", "share_course": "sharing courseware", "from_list_ko": "", "comming_soon": "Coming soon", "no_class_alert": "Class selected does not exist. To create a class, go to 'My Class' to create a class.", "students_cnt": "", "defult_class_alert_1": "Do you want to set ", "defult_class_alert_2": "\n as default class?", "default_class": "Default classroom", "enter_hw_name": "Enter Assignment name.", "hw_limit_20": "You can created up to 20 assignments", "stu_example": "Example)\n John Doe\n John Doe\n John Doe", "hw_description_limit_200": "Add assignment description. (within 200 characters)", "hw_title_limit_50": "Enter Assignment name. (within 50 characters)", "create_project_class_1": "Create projects you want to share ", "create_project_class_2": "with the class from 'Create> Create Project'", "create_lesson_assignment_1": "Create lessons you want to add as", "create_lesson_assignment_2": "course assignment from 'Create > Create lessons'", "i_make_lesson": "Create lessons", "lesson_to_class_1": "'Favorite lessons you want to add as", "lesson_to_class_2": "course assignment from 'Learn > Open lessons'", "studying_students": "Student", "lessons_count": "Number of Lessons", "group_out": "Leave", "enter_group_code": "Enter class code", "no_group_invite": "There is no class invitation", "done_create_group": "Class is created", "set_default_group": "Set as default classroom", "edit_group_info": "Modify class information", "edit_done": "Edit complete", "alert_group_out": "Do you want to leave the class?", "lesson_share_cancel": "Cancel Sharing Lesson", "project_share_cancel": "Cancel Sharing Project", "lesson_share_cancel_alert": "Are you sure to change it?", "course_share_cancel": "Cancel Sharing Courseware", "select_lesson_share": "Select lesson to share", "select_project_share": "Select project to share", "select_lesson_share_policy_1": "Please check share settings", "select_lesson_share_policyAdd": "Please check share settings", "select_lesson_share_project_1": "Please check share settings", "select_lesson_share_policy_2": "and copyright policies", "select_lesson_share_area": "Select share settings", "select_project_share_area": "Select share settings", "lesson_share_policy": "I agree to Entry's Copyright Policies.", "project_share_policy": "I agree to Entry's Copyright Policies.", "alert_agree_share": "To share publicly, you must agree to Entry's copyright policies", "alert_agree_all": "Agree to all items", "select_course_share": "Select courseware to share", "select_course_share_policy_1": "Please check share settings", "select_course_share_policy_2": "and copyright policies", "select_course_share_area": "Select share settings", "course_share_policy": "I agree to Entry's Copyright Policies.", "issued": "Issued", "code_expired": "Code has expired. Press 'Reissue Code' button", "accept_class_invite": "Accept class invitation", "welcome_class": "Welcome to the class.", "enter_info": "Please enter your information.", "done_group_signup": "You have successfully enrolled to this class", "enter_group_code_stu": "Enter the class code sent from your teacher", "text_limit_50": "Enter 50 characters or less.", "enter_class_name": "Please enter your class name", "enter_grade": "Please enter your grade", "enter_class_info": "Please enter your class introduction", "student_dup": "exits in this class already.", "select_stu_print": "Select student to print", "class_id_not_exist": "The class ID does not exist", "error_try_again": "Error occured. Please try again", "error_forbidden": "You have no permission", "code_not_available": "The code is not valid", "gnb_create_lessons": "Create lessons", "study_lessons": "Learn Lesson", "lecture_help_1": "Select the base project that the learner will start building his/her project on.", "lecture_help_2": "To see this help message again, click the button above.", "lecture_help_3": "If 'add object' is not shown, adding or deleting object is not possible.", "lecture_help_4": "See PDF attachment to get help", "lecture_help_5": "Select blocks needed to create project. Unselected blocks will be hidden.", "lecture_help_6": "choose between block Coding and Entry Python to organize your learning environment.", "lecture_finish_popup_title": "re-learn", "lecture_finish_popup_content_1": "Practice Completion Do you want to practice one step from the beginning?", "lecture_finish_popup_content_2": "* The practice completion status is maintained", "lecture_start_title": "Start", "lecture_goal_title": "Goal", "lecture_goal_content": "Goal", "lecture_prepare_title": "Prepare", "lecture_summary_title": "Summary", "lecture_summary_content": "Let's summarize what we learned.", "lecture_quiz_title": "Quiz", "lecture_quiz_content": "Let's check what we learned through the verification problem.", "lecture_quiz_check_answer": "Check the answer", "default_hint_title": "How do you make it?", "only_pdf": "Only pdf file is uploadable", "enter_project_video": "Enter at least one project or video", "enter_title": "Enter title.", "enter_recommanded_grade": "Enter recommanded grade.", "enter_level_diff": "Enter level of difficulty.", "enter_time_spent": "Enter time spent.", "enter_shared_area": "Select at least one sharing space", "enter_goals": "Enter goals", "enter_lecture_description": "Enter lecture information", "enter_curriculum_description": "Enter courseware information", "first_page": "처음 입니다.", "last_page": "마지막 입니다.", "alert_duplicate_lecture": "The lesson is already registered", "enter_lesson_alert": "Register one or more lessons", "open_edit_lessons": "Open lesson to be edited", "saved_alert": "was successfully saved.", "select_lesson_type": "Select type of lesson you want to create.", "create_lesson": "create lesson", "create_lesson_desc_1": "create a lesson", "create_lesson_desc_2": "according to learning objectives", "create_lesson_desc_3": "for your course.", "create_courseware": "Create courseware", "create_courseware_desc_1": "put multiple lessons together", "create_courseware_desc_2": "to create a courseware", "create_courseware_desc_3": "", "create_open_lesson": "Create open lesson", "enter_lesson_info": "Enter lesson information", "select_lesson_feature": "Select lesson feature", "check_info_entered": "Check information entered", "enter_lefo_lesson_long": "Enter information about the lesson.", "lesson_info_desc": "Select features and projects that learners will use to create optimal learning environment.", "provide_only_used": "Only provide blocks used in the goal project", "see_help": "See help", "select_done_project_1": "Select", "select_done_project_2": "the goal project", "select_done_project_3": "that the learner is to create", "select_project": "Select my project or my favorite project", "youtube_desc": "Enter Youtube links", "lesson_video": "Lesson video", "lesson_title": "Lesson title", "recommended_grade": "grade level", "selection_ko": "", "selection_en": "Select", "level_of_diff": "difficulty", "select_level_of_diff": "Select difficulty", "enter_lesson_title": "enter lesson title (in 30 characters or less)", "select_time_spent": "Select time", "time_spent": "time", "lesson_overview": "Lesson Overview", "upload_materials": "Upload course materials", "open": "Open", "cancel": "Cancel", "upload_lesson_video": "Upload lesson video", "youtube_upload_desc": "Insert Youtube link for course videos", "cancel_select": "Undo select", "select_again": "Select again", "goal_project": "Goal", "upload_study_data": "Upload learning materials that learners can view while building the project.", "upload_limit_20mb": "Upload up to 20MB", "expect_time": "Time spent", "course_videos": "course videos", "enter_courseware_info": "Enter courseware information", "enter_course_info": "Enter courseware information", "select_lessons_for_course": "Select lessons to create a courseware.", "course_build_desc_1": "", "course_build_desc_2": "Up to 30 lessons", "course_build_desc_3": "allowed.", "lseeon_list": "show lesson List", "open_lessons": "Open lessons", "course_title": "Courseware title", "title_limit_30": "Enter courseware title(within 30 characters)", "course_overview": "Courseware Overview", "charactert_limit_200": "Enter within 200 characters", "edit_lesson": "Edit lesson", "courseware_by_teacher": "Teacher created lesson collections", "select_lessons": "Select lessons", "check_course_info": "Check if the lesson collection information is correct", "select_share_area": "Select sharing space", "upload_sub_project": "Goal project upload", "file_download": "Download file", "file_remove": "Remove file", "check_lesson_info": "Check if the lesson information is correct", "share_area": "Sharing space", "enter_sub_project": "Register side project", "lms_hw_title": "Title", "lms_hw_ready": "Ready", "lms_hw_progress": "In progress", "lms_hw_complete": "Complete", "lms_hw_not_submit": "Unfinished", "lms_hw_closed": "Closed", "submission_condition": "Submission is allowed only for assignments in progress", "submit_students_only": "Only students are allowed to submit assignments", "want_submit_hw": "Are you sure you want to submit your assignment?", "enter_correct_id": "Enter correct ID", "id_not_exist": "The ID does not exist.", "agree_class_policy": "Agree to class service usage policy.", "delete_class": "Delete classs", "type_stu_name": "Please enter the student name.", "invite_from_1": "is invited to", "invite_from_2": "", "lms_pw_alert_1": "Once you enter class,", "lms_pw_alert_2": "teacher is allowed to reissue your login password.", "lms_pw_alert_3": "Make sure that the invitation is from your teacher.", "invitation_accepted": "Invitation Accepted!", "cannot_issue_pw": "Password cannot be issued because invitation has not been accepted", "start_me_1": "Start coding education", "start_me_2": "with !", "monthly_desc_1": "Monthly Entry is a monthly distributed magazine created ", "monthly_desc_2": "to help teachers learn to teach programming in fun and easy way.", "monthly_desc_3": "Check out the fun cartoons and programming contents every month!", "monthly_desc_4": "* The Monthly Entry has ceased publication.", "monthly_desc_5": "Download educational materials from the Educational Materials page.", "monthly_entry": "Monthly Entry", "me_desc_1": "Meet Monthly Entry magazine distributed monthly!", "me_desc_2": "", "solve_desc_1": "Learn the basics of", "solve_desc_2": "software programming by solving", "playSw_desc_1": "Learn to code by watching EBS TV Series and special tutorial videos!", "playSw_desc_2": "", "recommended_lessons": "Recommendations", "recommended_lessons_1": "Follow along, challenge, solve quizzes and learn to program with Entry!", "recommended_lessons_2": "", "offline_top_desc_1": "Offline Editor's Save Feature has improved as well as security.", "offline_top_desc_2": "Download now", "offline_main_desc": "Update Entry Offline Editor", "art_description": "This is a project sharing space. Create your own project and share.", "art_description_1": "", "art_description_2": "projects created. Create your own project and share.", "study_index": "Learn to code with Entry's coursewares by topic and grade levels", "study_for_beginner": "Entry First Steps for Starters", "entrybot_desc_3": "Take Entrybot to school", "entrybot_desc_4": "by assembling command blocks", "move_entrybot": "Control Entrybot", "can_change_entrybot_1": "Change Entrybot's color, make it talk", "can_change_entrybot_2": "using block commands", "learning_process_by_topics": "Courseware by topic", "show_detail": "See Details", "solve_mission": "Solve Mission", "solve_mission_desc_1": "Learn to code while playing games and solving missions!", "solve_mission_desc_2": "Control Entrybot move through the maze so it can reach its destination while learning the concepts of sequence, repeat, select and comparison.", "learning_process_by_grades": "Courseware by grade levels", "learning_process_by_grades_sub1": "Learn programming concepts in steps with Entry lectures! Start now!", "e3_to_e4": "Elementary 3-4th grade", "e5_to_e6": "Elementary 5-6th grade", "m1_to_m3": "7th+ and above", "make_using_entry": "Create projects with Entry", "make_using_entry_desc_1": "Assemble block to create your own program!", "make_using_entry_desc_2": "Download and follow along the learning materials to create animation, media art, game and other fun programs.", "make_through_ebs_1": "Learn to code by watching EBS TV Series.", "make_through_ebs_2": "The fun TV Series are accompanied by step-by-step tutorial videos so anyone can easily create programs.", "support_block_js": "Block code and javascript are supported", "study_ebs_title_1": "순서대로! 차례대로!", "study_ebs_desc_1": "[실습] 엔트리봇의 심부름", "study_ebs_title_2": "쉽고 간단하게!", "study_ebs_desc_2": "[실습] 꽃송이 만들기", "study_ebs_title_3": "언제 시작할까?", "study_ebs_desc_3": "[실습] 동물가족 소개", "study_ebs_title_4": "다른 선택, 다른 결과!", "study_ebs_desc_4": "[실습] 텔레파시 게임", "study_ebs_title_5": "정보를 담는 그릇", "study_ebs_desc_5": "[실습] 덧셈 로봇 만들기", "study_ebs_title_6": "요모조 따져 봐!", "study_ebs_desc_6": "[실습] 복불복 룰렛", "study_ebs_title_7": "번호로 부르면 편해요!", "study_ebs_desc_7": "[실습] 나만의 버킷리스트", "study_ebs_title_8": "무작위 프로그램을 만들어라!", "study_ebs_desc_8": "[실습] 무작위 캐릭터 만들기", "study_ebs_title_9": "어떻게 찾을까?", "study_ebs_desc_9": "[실습] 도서관 책 검색", "study_ebs_title_10": "줄을 서시오!", "study_ebs_desc_10": "[실습] 키 정렬 프로그램", "event": "이벤트", "divide": "분기", "condition": "conditionals", "random_number": "무작위수", "search": "탐색", "sorting": "정렬", "parallel": "병렬", "signal": "신호", "input_output": "입출력", "sequential": "sequence", "repeat": "repeat", "choice": "selection", "repeat_advanced": "repeat(sequence+condition)", "function": "function", "compare_operation": "comparison", "arithmetic": "산술연산", "entry_recommended_mission": "Entry Recommended Mission", "more_mission": "More Mission", "line_rangers_title": "Saving Sally with\nLINE Rangers", "line_rangers_content": "Save Sally trapped\nin the Mepisto base.", "pinkbean_title_string_basic": "Maple Story Basic Henesys", "pinkbean_title_string_intermediate": "Maple Story Intermediate Ellinia", "pinkbean_title_string_advanced": "Maple Story Advanced Elnath", "pinkbean_title": "To the Maple World\nwith PINK BEAN!", "pinkbean_content": "Help Pinkbean to finish\nhis Maple World adventure.", "entrybot_school": "Go to school", "entrybot_school_desc_1": "Help Entrybot to get backpack and go to school", "entrybot_school_desc_2": "", "robot_factory": "Robot Factory", "robot_factory_desc_1": "Entrybot is trapped in a robot factory!", "robot_factory_desc_2": "Collect all parts to escape the factory.", "electric_car": "Electric Car", "electric_car_desc_1": "Help Entrybot's car move forward ", "electric_car_desc_2": "by making sure it has enough fuel.", "forest_adventure": "Forest Adventures", "forest_adventure_desc_1": "Entrybot's friends are trapped in the forest!", "forest_adventure_desc_2": "Help Entrybot's friends escape.", "town_adventure": "Village Adventures", "town_adventure_desc_1": "Help Entrybot find fuel", "town_adventure_desc_2": "in the village.", "space_trip": "Space Travels", "space_trip_desc_1": "Entrybot just completed its space exploration.", "space_trip_desc_2": "Help Entrybot return to Earth.", "learn_programming_mission": "Learn programming by playing challenges", "make_open_lecture": "Create open lessons", "group_created": "Class created", "group_signup": "Class enrolled", "delete_from_list": "from the list?", "delete_from_list_en": "Are you sure you want to delete", "lecture_collection": "Courseware", "edit_mypage_profile": "Managae my info", "main_image": "Main image", "edit_profile_success": "Applied.", "no_project_1": "There are no projects to show.", "no_project_2": "How about creating your project now?", "empty_project_1": "There is no work made yet.", "no_marked_project_1": "There is no favorite project at this moment.", "no_marked_group_project_1": "There is no favorite class project at this moment.", "no_marked_project_2": "'Browse through 'Share' section to find interesting projects! ", "no_markedGroup_project_2": "Browse through 'Class share' section to find interesting projects!", "view_project_all": "Browse project", "no_lecture_1": "There are no lessons to show.", "empty_lecture_1": "There is no lecture made yet.", "no_lecture_2": "Create lessons from 'open lessons'", "no_marked_lecture_1": "There is no favorite lesson to show.", "no_marked_group_lecture_1": "There is no favorite class lesson to show.", "no_marked_lecture_2": "Browse through 'Open lessons' to see various lessons!", "view_lecture": "Browse lessons", "no_studying_lecture_1": "There are no lessons to show.", "no_studying_lecture_2": "Start learning from 'Open lessons' section!", "no_lecture_collect_1": "There are no courseware to show.", "empty_lecture_collect_1": "There is no courseware made yet.", "no_lecture_collect_2": "Create courseware from 'Create open courseware'", "make_lecture_collection": "Create courseware", "no_marked_lecture_collect_1": "There is no favorite courseware to show.", "no_marked_lecture_group_collect_1": "There is no favorite class courseware to show.", "no_marked_lecture_collect_2": "Browse through 'Open lessons' to see various lessons!", "view_lecture_collection": "Browse courseware", "no_studying_lecture_collect_1": "There are no courseware to show.", "no_studying_lecture_collect_2": "Start learning from 'Open lessons' section!", "my_lecture": "My lessons", "markedGroup": "Favorite group", "markedGroup_lecture": "Favorite group lessons", "markedGroup_curriculum": "Favorite group curriculum", "marked_lecture": "Favorite lessons", "marked_lecture_collection": "My courseware", "marked_marked_curriculum": "My courseware", "studying_lecture": "Lessons in progress", "completed_lecture": "Lessons completed", "my_lecture_collection": "My courseware", "my": "My", "studying_lecture_collection": "Courseware in progress", "completed_lecture_collection": "Courseware completed", "my_curriculum": "My Courses", "studying_curriculum": "Courseware in progress", "completed_curriculum": "Courseware completed", "materialCC": "All contents provided are released under Creative Commons CC-BY 2.0 License.", "materialccby_new": "All contents provided are released under Creative Commons CC-BY 2.0 License.", "entry_copyright_info": "ENTRY copyright guide", "pdf": "PDF", "helper": "helper", "youtube": "vedio", "tvcast": "vedio", "goal": "goal", "basicproject": "basic", "hw": "phần cứng", "object": "object", "console": "console", "download_info": "Click on the title to download resource", "entry_materials_all": "Entry Educational Materials", "entry_material": "Learning Entry", "recommand_grade": "Grade levels", "g3_4_grades": "3-4th", "g5_6_grades": "5-6th", "middle_grades": "7th+", "entry_go_go": "Entry Go Go!", "entry_go_go_desc": "Explore a set of courseware, student activity book and teacher's guide", "entry_go_go_desc2": "ndevided by grade and difficulty.", "stage_beginner": "Basic", "stage_middle": "Advanced", "stage_high": "Expert", "middle_school_short": "7th+", "learn_entry_programming": "Follow along step by step.", "entry_programming_desc": "Entry Programming: Become an Entry expert!", "ebs": "", "ebs_material_desc": "Teach using the EBS TV Series and Teacher's Guide!", "season_1_material": "Season 1 Teacher's Guide", "season_2_material": "Season 2 Teacher's Guide", "season_1": "Season 1", "playsoftware_ebs": "EBS Let’s play, SW!", "material_teacher_guide": "Teacher's Guide", "season_2": "Season 2", "compute_think_textbook": "Improve computational thinking skills", "computational_sw": "Learn to code for subjects such as language arts, math, science, fine arts!", "python_coding_text": "Entry Python", "python_coding_textbook": "Travel to the text coding world! Entry Python", "python_coding_desc": "Learn the structure and grammar of text coding with Entry Python!", "entry_x_hardware_text": "Entry X Hardware", "entry_x_hardware": "Entry Hardware Educational Materials", "e_sensor": "E Sensorboard", "e_sensor_board": "E Sensor-board", "e_sensor_robot": "E Sensor-robot", "arduino": "Arduino", "arduinoext": "ArduinoExt Uno", "arduinonano": "Arduino Nano", "albert": "albert", "orange_board": "orangeBoard", "arduino_board": "Arduino", "joystick": "joystick sensor shield", "ardublock": "ardublock", "mkboard": "digital monkeyboard", "mechatro_nano": "Mechatro Nano+", "mechatro_uno": "Mechatro Uno+", "memaker": "memaker", "edumaker": "EduMaker Board", "codingtoolbox": "codingtoolbox", "materials_etc_all": "Other Educational Materials", "materials_teaching": "For Teacher Education", "materials_etc": "Other Resources", "materials_etc_resource": "Resources", "materials_teaching_etc": "Teacher training", "materials_teaching_1": "Why Coding?", "materials_teaching_2": "Unplugged Acitivies with Entry", "materials_teaching_3": "Learn by playing in Entry Coding Missions", "materials_teaching_4": "Entry for Real World Problem Solving", "materials_teaching_5": "Interdisciplinary Coding(Art,Math,Social)", "materials_teaching_6": "Interdisciplinary Coding(Korean,Science,Music)", "materials_teaching_7": "Physical Computing 1 (E-Sensorboard)", "materials_teaching_8": "Physical Computing 2 (Hamster Robot)", "materials_teaching_9": "Learn to use Entry LMS effectively ", "materials_etc_1": "Getting Started Guide", "materials_etc_2": "Contents for Classroom Use", "materials_etc_3": "Monthly Entry", "materials_etc_4": "About Entry", "materials_etc_5": "Introducing Entry", "materials_etc_6": "Entry Block Catalogue", "materials_etc_7": "Entry Python Guide", "jr_if_1": "nếu", "jr_if_2": "đằng trước", "jr_fail_no_pencil": "There is no pencil. Use 'pencil block' at the pencil!", "jr_fail_forgot_pencil": "Oh no! I forgot my pencil. Let's pick up the pencil.", "jr_fail_much_blocks": "너무많은 블록을 사용했어, 다시 도전해볼래?", "cparty_jr_success_1": "Hooray! I got my backpack!", "go_right": "đi sang bên phải", "go_down": "đi xuống", "go_up": "đi lên", "go_left": "đi sang bên trái", "go_forward": "tiến về phía trước", "jr_turn_left": "quẹo trái", "jr_turn_right": "quẹo phải", "go_slow": "đi chậm", "repeat_until_reach_1": "", "repeat_until_reach_2": "Repeat until reach", "pick_up_pencil": "nhấc", "repeat_0": "Repeat", "repeat_1": "", "when_start_clicked": "When start button clicked", "age_0": "Age 0+", "create_character": "Creating Character", "age_7_9": "Age 7~9", "going_school": "Going to School", "age_10_12_1": "Age 10~12", "collect_parts": "Collecting Parts", "age_10_12_2": "Age 10~12", "driving_elec_car": "Driving Electric Car", "age_13": "Age 13+", "travel_space": "Traveling Space", "people": "People", "all": "All", "life": "Life", "nature": "Nature", "animal_insect": "Animal/Insect", "environment": "Environment", "things": "Things", "vehicles": "Vehicles", "others": "Others", "fantasy": "Fantasy", "instrument": "Instrument", "piano": "Piano", "marimba": "Marimba", "drum": "Drum", "janggu": "Janggu", "sound_effect": "Sound", "others_instrument": "Others", "aboutEntryDesc_1": "Entry is an education platform created to help anyone learn to code.", "aboutEntryDesc_2": "Students are able to learn to code while playing,", "aboutEntryDesc_3": "teachers are able to teach effectively.", "aboutEntryDesc_4": "Entry is a non-profit service.", "aboutEntryDesc_5": "", "viewProjectTerms": "See usage policy", "openSourceTitle": "Promoting open source culture", "openSourceDesc_1": "Entry's source code and ", "openSourceDesc_2": "all educational materials", "openSourceDesc_3": "are open to public", "viewOpenSource": "See open source code", "eduPlatformTitle": "Entry for Classroom Use", "eduPlatformDesc_1": "Entry is developed with teachers ", "eduPlatformDesc_2": "to promote learning", "eduPlatformDesc_3": "in classroom settings.", "madeWith": "Advisory group", "researchTitle": "Continuous improvement through research", "researchDesc_1": "Entry collaborates with researchers to strengthen learning effectiveness", "researchDesc_2": "", "researchDesc_3": "", "viewResearch": "See research materials", "atEntry": "Entry provides", "entryLearnDesc_1": "learn while playing", "entryLearnDesc_2": "< Learn > section provides various coursewares and learning materials.", "entryLearnDesc_3": "Watch videos, solve problems and learn while playing.", "entryLearnDesc_4": "", "entryMakeDesc_1": " section provides block-based coding tool which enables", "entryMakeDesc_2": "even first time learners to easily create programs.", "entryMakeDesc_3": "And also provides ‘entry phython’ mode which is between block-based coding", "entryMakeDesc_4": "and text-based coding to help you understand the structure and grammar", "entryMakeDesc_5": "of programming languages.", "entryShareDesc_1": " section allows users to share his or her project with others.", "entryShareDesc_2": "Explore how the shared projects are created, make improvements,", "entryShareDesc_3": "collaborate with friends to make even cooler projects.", "entryGroup": "Learning Management Tool", "entryGroupTitle": "My Class", "entryGroupDesc_1": " is created to help teachers easily manage students.", "entryGroupDesc_2": "Create your own class, assign homework,", "entryGroupDesc_3": "share project within the class, and check student progress.", "entryGroupDesc_4": "And teacher can lead the class effectively by providing more suitable coursewares", "entryGroupDesc_5": "according to the students’ level.", "unpluggedToPhysical": "From Unplugged Activity to Physical Computing", "algorithmActivity": "Basic Algorithm", "programmignLang": "Block-based Coding", "unpluggedDesc_1": "Learn the basics of programming such as sequence, repetition,", "unpluggedDesc_2": "selection and function by playing Entry Boardgame and Cardgame.", "entryMaze": "Entrybot Maze Escape", "entryAI": "Space Travels", "algorithmDesc_1": "Earn a certificate by completing the coding missions.", "algorithmDesc_2": "Learn to code while playing.", "programmingLangDesc_1": "Coding is made easy with Entry.", "programmingLangDesc_2": "Create your own games, animation, media art and much more.", "viewSupporHwVideo": "See the hardware guide videos", "viewSupporHw": "see which hardware connects", "supportHwDesc_1": "Entry connects to many physical computing devices to create awesome projects", "supportHwDesc_2": "that interacts with the physical world. More devices are continuously added!", "entryEduSupport": "Entry Education Support", "eduSupportDesc_1": "Entry Labs provides educational materials for free.", "eduSupportDesc_2": "Download educational materials from the Educational Materials page.", "materials_1_title": "Textbook by grade levels", "materials_1_desc_1": "Improve coding skills step by step", "materials_1_desc_2": "", "materials_2_title": "EBS TV program and teacher's guide", "materials_2_desc_1": "EBS TV series are accompanied", "materials_2_desc_2": "by teacher's guide", "materials_3_title": "Educational materials", "materials_3_title_2": "for elementary and mid to high school", "materials_3_desc_1": "Improve computational thinking skills.", "materials_3_desc_2": "", "moreMaterials": "See more educational materials", "moreInfoAboutEntry_1": "Click on the links below to get Entry's latest updates.", "moreInfoAboutEntry_2": "Educational materials as well as exciting news are shared.", "material_menu_type_robot": "Robot\nType", "material_menu_type_module": "Module\nType", "material_menu_type_board": "Board\nType", "blog": "Blog", "post": "Post", "tvCast": "TVCast", "about_entry_pre": "Entry", "about_youtube": "Youtube", "about_facebook": "Facebook", "albertSchool": "Albert", "arduinoBoard": "Arduino certified", "arduinoCompatible": "non-certified", "bitBlock": "BitBlock", "bitbrick": "Bitbrick", "creamo": "creamo", "playcode": "playcode", "funboard": "funboard", "truerobot": "TrueTrue", "bingle": "BINGLE", "bingles": "BINGLE · S", "codeino": "CODEino", "epor": "EPOR", "petrone_v2": "Petrone V2", "petrone_v2_drone": "flight", "petrone_v2_car": "drive", "e-sensor": "E-Sensorboard", "e-sensorUsb": "E-Sensor board", "e-sensorBT": "E-Sensor board(Bluetooth)", "mechatronics_4d": "4D Mechatronics", "esensor_board": "E-Sensor Board", "esensor_robot": "E-Sensor Robot", "hamster": "Hamster", "hummingbird": "Hummingbird Duo", "roboid": "Roboid", "turtle": "Turtle", "littlebits": "Littlebits", "orangeBoard": "OrangeBoard", "robotis_carcont": "Robotis Robot Car", "robotis_IoT": "Robotis IoT", "robotis_IoT_Wireless": "Robotis IoT(Wireless)", "dplay": "DPLAY", "iboard": "iboard", "nemoino": "NEMOino", "xbot_epor_edge": "XBOT(OneTouch Dongle/USB)", "XbotBT": "XBOT EPOR and EDGE Bluetooth", "robotori": "robotori", "rokoboard": "rokoboard", "neobot": "NEOBOT", "neobot_sensor_theme": "NEOBOT Senosor Theme", "mechatro": "mechatro", "about": "About", "articles": "Articles", "gallery": "Gallery", "learn": "Learn", "login": "Đăng nhập", "logout": "Đăng xuất", "make": "Create", "register": "Sign Up", "Join": "Tham gia", "Edit_info": "Edit Info", "Discuss": "Discuss", "Explore": "Explore", "Load": "Load", "My_lesson": "Open Lessons", "textbook_learning": "Learning Text book", "Resources": "Resources", "play_software": "EBS Let’s play, SW!", "problem_solve": "Entry Learn", "learning_textbook": "Learning Text book", "context_textbook": "Teachers can teach the school class and students can prepare and review at home with the same content as their textbooks.", "info_banner_textbook": " ", "banner_textbook": "Do you want to learn more", "banner_textbook_2": "diverse and interesting things?", "banner_textbook_right_banner": "Do you need educational ", "banner_textbook_right_banner2": "materials for teachers?", "banner_textbook_right_banner_btn": "Download material", "Learn": "Learn", "teaching_tools": "Teaching Tools", "about_entry": "About ENTRY", "what_entry": "What is Entry?", "create": "Create", "create_new": "Create new", "start_programming": "First Step for Software Education", "Entry": "Entry", "intro_learning": "Learn to code in fun and easy way.", "intro_learning_anyone": "Start now with Entry!", "start_now": "For Free, Forever.", "welcome_entry": "Welcome to ENTRY", "student": "Student", "non_menber": "General", "teacher": "Teacher", "terms_conditions": "Terms and Conditions", "personal_information": "Information about the collection and use of personal information ", "limitation_liability": "Limitation of Liability", "entry_agree": "Agree to ENTRY’s Terms of Use", "info_agree": "", "next": "Next", "enter_individual_info": "Enter personal information", "enter_id": "Enter ID", "enter_password": "Enter Password", "confirm_password": "Confirm Password", "enter_password_again": "Enter your password again", "validation_password": "Please use at least 5 letters and/or numbers", "validation_id": "Please use 4-20 letters and/or numbers.", "prev": "Back", "born_year": "Year born ", "select_born": "Select the year you were born.", "year": "years", "gender": "Gender", "choose_gender": "Choose gender", "male": "Male", "female": "Female", "language": "Language", "best_language": "Select your best language", "korean": "Korean", "english": "English", "viet": "Vietnamese", "japan": "japan", "russia": "russia", "chinese_simplified": "Chinese(Simplified)", "chinese_traditional": "Chinese(Traditional)", "option_email": "Email (optional)", "insert_email": "Enter your email address", "sign_up_complete": "Sign up complete!", "agree_terms_conditions": "Please agree Terms and Conditions", "agree_personal_information": "Please agree to the collection and use of personal information.", "insert_studying_stage": "Please select the group you want to share your project .", "insert_born_year": "Insert the year you were born", "insert_gender": "Please select gender from the options.", "select_language": "select language", "check_email": "Check email's format", "already_exist_id": "ID already exists", "id_validation_id": "ID use 4-20 letters and/or numbers.", "password_validate_pwd": "Password use at least 5 letters and/or numbers", "password_validate_pwd_length": "Please use at least 5 numbers.", "neoid_username_same_id": "Username already taken (NEOID)", "insert_same_pwd": "Insert same password", "studying_stage_group": "Sharing class", "studying_stage": "Please select the group you want to share.", "password": "Password", "save_id": "Save ID", "auto_login": "Keep me sign in", "enter_id_pw": "Entry ID, Password", "forgot_password": "Forgot your ID or password?", "did_not_join": "Haven’t signed up yet?", "go_join": "Go to join", "renew_index_text_00": "Learn textbook", "renew_index_text_01": "Let's learn Entry with textbook.", "renew_index_text_02": "Through elementry textbook lectures,", "renew_index_text_02_2": "learn Entry!", "renew_index_text_03": "Go to", "renew_index_text_03_2": "learn textbook", "renew_index_text_1": "2019, Meet the changed Entry", "renew_index_text_2": "The brand new 'Create Project'", "renew_index_text_3": "Go to the 'Create Project'", "renew_index_text_3_2": "and find out the new functions!", "renew_index_text_4": "View Details", "first_step": "First Step for Software Education", "entry_content_one": "Bring your imagination to life with ENTRY.", "entry_content_two": "Create games, animations, media art, and other cool projects!", "entry_content_three": "Create projects and share with your friends. Enter the exciting world of ENTRY!", "funny_space": "A Fun Learning Space", "in_learn_section": "In < Learn > section,", "learn_problem_solving": "Various learning contents and mini challenges are available for you in the < Learn > section. Solve mini challenges by coding. Watch fun videos and learn to program.", "joy_create": "A Creative Space", "in_make": "In < Create > section", "make_contents": "In the section, create your own program with block-based programming language. Create simulation programs to test laws of Physics. Create animation program with your favorite characters. Bring your imagination to life with Entry. ", "and_content": "There is no limit to what you can create. You can experiment physical laws you’ve learned in science class, create animations featuring your favorite characters, and even make your own games. ", "share_collaborate": "A Sharing Space", "explore_contents": "The section, showcases thousands of projects created and shared by the Entry community. Try out the fun and creative projects, see how they are coded, and improve them. You can also cooperate with your peers to create exciting projects.", "why_software": "Why is learning to code important?", "speak_obama_contents": "Learning these skills isn’t just important for your future. It’s important for our country’s future.", "obama": "Barack Obama", "us_president": "U.S President", "billgates_contents": "Learning to write programs stretches your mind, and helps you think better, creates a way of thinking about things that I think is helpful in all domains.", "billgates": "Bill Gates", "chairman_micro": "Chairman, Microsoft", "eric_contents": "For most people on Earth, the digital revolution hasn't even started yet. Within the next 10 years, all that will change. Let's get the whole world coding!", "eric": "Eric Schmidt", "sandbug_contents": "An understanding of computer science is becoming increasingly essential in today’s world. Our national competitiveness depends upon our ability to educate our children—and that includes our girls—in this critical field.", "sandbug": "sheryl Sandberg", "view_entry_tools": "Introducing Entry’s unplugged games for teaching programming.", "solve_problem": "Solve Mission", "solve_problem_content": "Mini challenges will help you learn the basics of programming.", "find_extra_title": "ENTRY Bot part finding extravaganza", "all_ages": "For all ages", "total": "Total", "step": "steps", "find_extra_contents": "Entry bot is special robot created one day at the Rutz Robot Toy Factory during a blackout. Help him find his missing parts and escape the factory while learning to code.", "software_play_contents": "Watch ‘Let’s Play Software’ , follow along the tutorials and learn to create fun programs.", "resources_contents": "Get various Entry educational materials for free", "from": "From", "sw_camp": "Software Creativity Camp, Ministry of Science, ICT and Future Planning", "elementary": "Elementary", "middle": "Middle school", "grades": "Grades", "lesson": "Lessons", "sw_contents_one": "This guidebook is for elementary students learn physical computing over a 5-lesson course. Students learn to use Entry and create images and stoires. In the final section, students use Arduino to create a musical keyboard", "sw_camp_detail": "Ministry of Science, ICT and Future Planning Software Creation Camp", "sw_contents_two": "This textbook allows middle school students to experience ENTRY and physical computing over a 5-lesson course. Students learn how to use ENTRY, and create a maze game and quiz program. In the final section, students use Arduino and keyboard to steer a car.", "sw_contents_three": "This is a teacher’s guide for starting computing classes in schools. It contains a variety of unplugged activities and lesson plans using clips from ‘Let’s play, Software!’broadcasts. ", "naver_sw": "NAVER Let’s play, Software!", "teacher_teaching": "Teacher’s Guide (for elementary grades 5-6 and above)", "funny_sw": "Have Fun with Software", "sw_contents_four": "This textbook allows students to learn about computing in a fun and playful way through a variety of unplugged activities such as ENTRY Board, and teaches students the basic principles of programming via ENTRY Course Mode. Once they have got down the basics, students learn how to create stories, games, artistic works, and applications using ENTRY. The textbook allows students to create and present their own software. ", "ct_text_5": "Grow computational thinking with skills.", "teacher_grade_5": "교원 (초등학교 5학년)", "ct_text_5_content": "This teacher's guide contains 8 problem solving tasks. Each task is designed to reflect the revised National Curriculum and contains interdisciplinary themes. Cultivate computational thinking skills.", "ct_text_6": "교과서와 함께 키우는 컴퓨팅 사고력", "teacher_grade_6": "교원 (초등학교 6학년)", "ct_text_6_content": "실생활의 문제를 해결하자는 테마로 준비된 총 8개의 학습콘텐츠가 담긴 교사용 지도안입니다. 각 콘텐츠는 개정된 교육과정을 반영한 타교과와의 연계를 통해 다양한 문제를 만나고 해결해볼 수 있도록 설계되었습니다. 아이들이 컴퓨팅 사고력을 갖춘 융합형 인재가 될 수 있도록 지금 적용해보세요!", "sw_use": "All textbooks are for non-commercial use only, and can be used freely so long as the author is credited. ", "title": "Title", "writer": "By", "view": "View", "date": "Date", "find_id_pwd": "Find ID or Password", "send_email": "A link to change your password has been sent to you by email.", "user_not_exist": "This email does not exist.", "not_signup": "Haven't signed up yet?", "send": "Send", "sensorboard": "ENTRY Sensor Board", "physical_computing": "Physical Computing", "sensorboard_contents": "Using Arduino no longer requires building a circuit using lots of wires. With ENTRY Board, you can use LED lights, temperature, sound, light sensors, a slider, and switches by simply mounting it onto an Arduino board. Now anyone can easily create their own unique projects using ENTRY Board!", "entrybot_boardgame": "ENTRY-Bot Board Game", "unplugged": "Unplugged Activities", "unplugged_contents": "Learn the principles of programming through Entry-bot Board Game. By helping Entrybot escape the factory, you can learn to think like a computer scientist.", "entrybot_cardgame": "ENTRY Bot Cardgame : Bomb Tempest", "entrybot_cardgame_contents": "12 different types of bombs appear at the city of Entry! Dismantle the bombs one at a time and learn the basics of programming. By using the concepts of sequence, repetition and conditionals, save the City and become a hero!", "basic_learn": "Entry Basics", "basic_learn_contents": "Learn to program with Entry’s coursewares", "troubleshooting": "Problem Solving", "playsoftware": "Let's play, Software!", "make_own_lesson": "Create your own lessons and share them with everyone.", "group_lecture": "Lessons", "group_curriculum": "Courseware", "group_homework": "Assignment", "group_noproject": "No Project", "group_nolecture": "No Lessons", "group_nocurriculum": "No Courseware", "lecture_contents": "Create customized lessons with limited blocks.", "curriculum_contents": "Create a course by putting together series of lessons.", "grade_info": "Grades information", "difficulty": "Difficulty", "usage": "Usages", "learning_concept": "Learning concepts", "related_subject": "Related subjects", "show_more": "Show more", "close": "Close", "latest": "By Latest", "viewCount": "view count", "viewer": "By Viewers", "like": "By Likes", "comment": "By Comments", "entire_period": "Entire period", "today": "Today", "latest_week": "Latest 1 week", "latest_month": "Latest 1 month", "latest_three_month": "Latest 3 months", "current_password": "Current password", "change_password": "Change password", "incorrect_password": "Incorrect! Try again.", "incorrect_password_login": "The Username or Password you entered is incorrect.", "suspension_user": "The login of the account is prohibited.", "blocked_user": "Blocked!!", "new_password": "New password", "password_option_1": "Please use at least 5 letters and/or numbers.", "again_new_password": "Confirm new password", "enter_new_pwd": "Enter new password.", "confirm_new_pwd": "Confirm new password.", "enter_new_pwd_again": "Enter new password again.", "password_match": "Passwords do not match.", "incorrect_email": "Incorrect email. Try again.", "edit_button": "Edit info", "edit_profile": "Edit", "my_project": "My projects", "my_group": "My Class", "mark": "Marking", "prev_state": "Back", "profile_image": "Profile image", "insert_profile_image": "Please upload a profile image.", "at_least_180": "At least 180x180 pixels is recommended.", "upload_image": "Upload image", "about_me": "About me", "save_change": "Save changes", "basic_image": "Basic Image", "profile_condition": "Enter something about yourself. (in 50 characters)", "profile_back": "Go back", "make_project": "Create Project", "exhibit_project": "Exhibit Project", "art_list_shared": "Shared", "art_list_group_shared": "Group", "gl_mode_boost": "Boost Mode", "gl_not_supported": "Can not run in boost mode.\nClick OK to run in default mode.", "view_project": "View Code", "code_view": "View Code", "noResult": "No results found", "comment_view": "Comment", "upload_project": "Upload", "edit": "Edit", "save_complete": "Save", "just_like": "Like", "share": "Share", "who_likes_project": "Who likes the projects", "people_interest": "People interested projects", "none_person": "Nobody", "inserted_date": "Date", "last_modified": "Last Modified", "original_project": "Original project", "for_someone": "'s", "original_project_deleted": "The original project was deleted", "delete_project": "Delete", "delete_group_project": "Delete From List", "currnet_month_time": "months", "current_day_time": "days", "game": "Game", "animation": "Animation", "media_art": "Media Arts", "physical": "Physical", "etc": "ETC", "connected_contents": "Linking content", "connected_contents_content": "Discover the variety of content that can be done with the entry . If you're new software to learn easily from person to enjoy board games , you can take advantage of the Arduino and physical computing , such as creating a luxurious view of your own creation .", "basic_mission": "Basic mission : Entry bot Maze", "basic_mission_content": "A power outage at a toy robot factory magically enabled Entrybot to come to life. Help Entrybot escape the factory and find freedom!", "application_mission": "Application mission: Entry bot's Space Odyssey", "write_article": "Write", "write_contest": "Submit", "view_all_articles": "View all posts", "view_own_articles": "View my posts", "view_qna_articles": "View no answered posts", "learning_materials": "Learning materials", "download_materials": "Learning materials download", "download_button": "download", "download_all": "download all", "ebs_software_first": " is a TV series created by Naver, EBS and Entry Labs. Learn the basic principles of programming. Watch the show, follow along the video tutorials, and learn to code!", "go_software": "Visit Let's play software!", "ebs_context": "Visit EBS", "ebs_context_hello": "Visit EBS", "category": "Category", "add_picture": "Add Picture", "upload_article": "Upload article", "list": "List", "report": "Report", "upload": "Upload", "staff_picks": "Staff Picks", "popular_picks": "Popular Projects", "lecture_header_more": "More Projects", "lecture_header_reset": "Reset", "lecture_header_reset_exec": "Reset to basic project", "lecture_header_save": "Save", "lecture_header_save_content": "Save current lecture", "lecture_header_export_project": "Export to my project", "lecture_header_undo": "Undo", "lecture_header_redo": "Redo", "lecture_er_bugs": "Feedback", "lecture_container_tab_object": "các đối tượng", "lecture_container_tab_video": "video", "lecture_container_tab_project": "công trình hoàn thành", "lecture_container_tab_help": "giúp đỡ", "illigal": "Illegal or inappropriate behavior", "verbal": "Verbal abuse or posting personal information", "commertial": "Posting for commercial purposes", "explicit": "Explicit content", "other": "Other", "check_one_more": "Please select the reason more than one.", "enter_content": "Please enter the reason for your report.", "report_result": "Please enter email address to be informed of report results. ", "report_success": "Your report was submitted successfully.", "etc_detail": "Please give details", "lecture_play": "Play", "list_view_link": "List", "lecture_intro": "Introduction Lessons", "study_goal": "Goals", "study_description": "Description", "study_created": "Created", "study_last_updated": "Updated", "study_remove": "Remove", "study_group_lecture_remove": "Remove From List", "study_group_curriculum_remove": "Remove From List", "study_edit": "Edit", "study_comments": "Comments", "study_comment_post": "Post", "study_comment_remove": "Remove", "study_comment_edit": "Edit", "study_comment_save": "Save", "study_guide_video": "Guide Video", "study_basic_project": "Initial Project", "study_done_project": "Complete Project", "study_usage_element": "Usage", "study_concept_element": "Concept", "study_subject_element": "Related", "study_computing_element": "Computational Thinking", "study_element_none": "None", "study_label_like": "Like", "study_label_interest": "Interest", "study_label_share": "Share", "study_label_like_people": "People who liked this lecture", "study_label_interest_people": "People who interested this lecture", "study_related_lectures": "Related lectures", "study_expand": "Show all", "study_collapse": "Collapse", "aftercopy": "Copied to clipboard", "study_remove_curriculum": "Are you sure to remove this course?", "content_required": " Please enter the contents.", "upload_not_supported_file_msg": "Not supported file type.", "study_remove_lecture": "Are you sure to remove this lesson?", "lecture_build": "Make a lesson", "lecture_build_step1": "1. Enter basic lesson information", "lecture_build_step2": "2. Selecte required functions", "lecture_build_step3": "3. Confirm all of information correctly.", "lecture_build_choice": "What is main content?", "lecture_build_project": "Entry Project", "lecture_build_video": "Lessons Video", "lecture_build_grade": "Grades", "lecture_build_goals": "Goals", "lecture_build_add_goal": "Add a goal", "lecture_build_attach": "Attachment", "lecture_build_attach_text": "Less than 20MB", "lecture_build_assist": "Additional", "lecture_build_youtube_url": "Paste a Youtube share link", "lecture_build_project_done": "Select a completed project.", "lecture_build_scene_text1": "Using scene function or not", "lecture_build_scene_text2": "", "lecture_build_object_text": "Using Object add function or not", "lecture_build_blocks_text1": "Select required blocks only.", "lecture_build_blocks_text2": "", "lecture_build_basic1": "Select a project.", "lecture_build_basic2": "User start with this project.", "lecture_build_help": "", "lecture_build_help_never": "Close permanently", "lecture_build_close": "Close", "lecture_build_scene": "Scene 1", "lecture_build_add_object": "Add Object", "lecture_build_start": "Start", "lecture_build_tab_code": "Block", "lecture_build_tab_shape": "Shape", "lecture_build_tab_sound": "Sound", "lecture_build_tab_attribute": "Attribute", "lecture_build_tab_table": "Table", "lecture_build_block_category": "Select block category.", "lecture_build_attr_all": "All", "lecture_build_attr_var": "biến số", "lecture_build_attr_signal": "Signal", "lecture_build_attr_list": "List", "lecture_build_attr_func": "Function", "lecture_build_edit": "Edit", "lecture_build_remove": "Remove", "curriculum_build": "Create a courseware", "curriculum_step1": "Fill information about this course.", "curriculum_step2": "Select lessons for this course.", "curriculum_step3": "Confirm information.", "curriculum_lecture_upload": "Upload", "curriculum_lecture_edit": "Edit", "curriculum_lecture_open": "Open", "group_lecture_add": "Add my group lessons", "group_curriculum_add": "Add my group curriculum", "group_lecture_delete": "Delete", "group_curriculum_delete": "Delete", "group_select": "", "group_studentNo": "Student No", "group_username": "Name", "group_userId": "ID", "group_tempPassword": "Modify PW", "group_gender": "Gender", "group_studentCode": "Code", "group_viewWorks": "View Works", "added_group_lecture": "lessons deleted", "added_group_curriculum": "Course deleted", "deleted_group_lecture": "lessons deleted", "deleted_group_curriculum": "Course deleted", "modal_my": "My", "modal_interest": "Marked", "modal_project": "Project", "section": "Sections", "connect_hw": "kết nối phần cứng", "connect_message": "Connected to %1", "connect_fail": "kết nối thất bại", "interest_curriculum": "Interest", "marked_curriculum": "Interest Curriculum", "searchword_required": "Please enter your search keyword.", "file_required": "File is required.", "file_name_error": "please insert correct file name", "file_upload_max_count": "You can only upload 10 files at a time.", "image_file_only": "You can only upload jpg, png, bmp files.", "file_upload_max_size": "You can only upload less than 10MB in file size.", "curriculum_modal_lectures": "My Lessons", "curriculum_modal_interest": "Interest", "group_curriculum_modal_curriculums": "My Courses", "group_curriculum_modal_interest": "Interest", "picture_import": "Import a picture", "picture_select": "Select a picture", "lecture_list_view": "list", "play_software_2": "Let’s play, Software2!", "play_software_2_content": " is a TV series created by Naver, EBS and Entry Labs. Learn the basic principles of programming. Watch the show, follow along the video tutorials, and learn to code!", "open_project_to_all": "Open", "close_project": "Close", "category_media_art": "Media Art", "go_further": "Go further", "marked_project": "Favorite Project", "marked_group_project": "Favorite group project", "basic": "Basic", "application": "Application", "the_great_escape": "The Great Escape", "escape_guide_1": "ENTRY Bot suddenly began to think for himself during a power failure at the robot dog factory! ", "escape_guide_1_2": " Help ENTRY Bot escape the factory and find his freedom!", "escape_guide_2": "ENTRY Bot is missing too many parts to make it far. Help him find his parts as he makes his way out the factory!", "escape_guide_2_2": "Objectives: Sequential Execution", "escape_guide_3": "I’ve finally escaped the factory! But it’s still a long way to the village. I think I’m fixed up enough to make it there without too much difficulty. Hey, what’s that robot?", "escape_guide_3_2": "Objectives: Repetitive and Conditional Statements", "escape_guide_4": "We’re finally getting close to the village! I’m starting to really get the hang of this! I think it might be better to just use the blocks from memory. If I just recharge my battery here, I’ll be able to live free forever.", "escape_guide_4_2": "Objectives: Definitions of Function and Function Call", "space_travel_log": "Space Travel Log", "space_guide_1": "ENTRY Bot has finally completed his exploration of distant space. He’s trying to make his way back home to Earth, but his path is being blocked by a bunch of space rocks! Help ENTRY Bot make it back to Earth safely!", "space_guide_2": "It’s finally time to return to Earth! I can’t wait to get back and rest! Tell me the positions of the rocks ahead so I can navigate through them! I’ll go the way you tell me to!", "space_guide_2_2": "Objective: Reiterating IF Statements and Logical Operation", "cfest_mission": "ENTRY Experiential Mission", "maze_1_intro": "Hi. I’m ENTRY Bot. I’m about to save my injured friends and I need your help. Help me save my friends! First, set up the ‘Move forward one space’ block and press ‘Start’.", "maze_1_title": "How to Start", "maze_1_content": "How do I move ENTRY Bot?", "maze_1_detail": "1. Take a block from the Block Box and connect it with the ‘When Start is pressed’ block.
2. Press Start once you have finished assembling.
3. I will move in the order of your assembled blocks from top to bottom. ", "maze_2_intro": "Alright! You’ve saved the first of my friends! Now let’s save my next friend. Oh! There’s a beehive in the way! Use the Jump Over block to avoid the beehive and save my friend!", "maze_2_title_1": "Jump Over", "maze_2_content_1": "How do I get around obstacles?", "maze_2_detail_1": "Sometimes your path may be blocked by an obstacle.
When there’s an obstacle in your path, you need to use the ‘Jump Over’ block.", "maze_2_title_2": "How to Start", "maze_2_content_2": "How do I move ENTRY Bot?", "maze_2_detail_2": "1. Take a block from the Block Box and connect it with the ‘When Start is pressed’ block.
2. Press Start once you have finished assembling.
3. I will move in the order of your assembled blocks from top to bottom. ", "maze_3_intro": "Awesome! Now let’s go save another friend! How about we use the ‘Repeat’ block that my other friend gave use? You can easily repeat the same movements over again using the ‘Repeat’ block! Try changing the number of times to repeat. ", "maze_3_title": "Repeat Block (1)", "maze_3_content": "How do I use the ‘Repeat (3)’ block?", "maze_3_detail": "To perform the same action/s more than once, you need to use the ‘Repeat’ block.
Put the blocks that you want to repeat inside the Repeat box and select the number of times you want to repeat.", "maze_4_intro": "Super! Not too many robot friends left to save now. Take us to my friend by using the ‘Jump Over’ block on repeat while also evading the beehive!", "maze_4_title": "Repeat Block (1)", "maze_4_content": "How do I use the ‘Repeat (3)’ block?", "maze_4_detail": "To perform the same action/s more than once, you need to use the ‘Repeat’ block.
Put the blocks that you want to repeat inside the Repeat box and select the number of times you want to repeat.", "maze_5_intro": "Cool! Now let’s try using the ‘Repeat’ block and ‘IF’ block together! Using the ‘IF’ block, you can turn in a direction where there are no walls when you come across a wall. Well then, shall we set off to save my friend?", "maze_5_title_1": "IF block", "maze_5_content_1": "How does the ‘IF’ block work?", "maze_5_detail_1": "You can determine what action to take when you come across a {IMAGE}.
The blocks are used only when you come across a {IMAGE}.
If there is none, the block is not used.", "maze_5_title_2": "Repeat Block (2)", "maze_5_content_2": "How do I use the ‘Repeat until’block?", "maze_5_detail_2": "Using the ‘Repeat until’block, you can determine until when a specified action is repeated.
Just put the blocks you want to repeat inside the ‘Repeat until’ block.
Then, the repetition will stop when you reach the space where the {IMAGE} is located. ", "maze_6_intro": "Only one friend left! Just do as we’ve practiced and you’ll succeed! Now, let’s go save him!", "maze_6_title_1": "IF block", "maze_6_content_1": "How does the ‘IF’ block work?", "maze_6_detail_1": "You can determine what action to take when you come across a {IMAGE}.
The blocks are used only when you come across a {IMAGE}.
If there is none, the block is not used.", "maze_6_title_2": "Repeat Block (2)", "maze_6_content_2": "How do I use the ‘Repeat until’block?", "maze_6_detail_2": "Using the ‘Repeat until’block, you can determine until when a specified action is repeated.
Just put the blocks you want to repeat inside the ‘Repeat until’ block.
Then, the repetition will stop when you reach the space where the {IMAGE} is located. ", "maze_programing_mode_0": "Block Coding", "maze_programing_mode_1": "Javascript", "maze_operation1_title": "STEP 1 – Javascript mode guide", "maze_operation1_1_desc": "Hi, I'm Entrybot, the robot dog. Give me commands to reach the mission goals. You can learn about the mission when you begin under \'Goals.\'", "maze_operation1_2_desc": "Once you learn your goal, you need to give me commands. \’Command Box\’ is where the commands reside. You can create commands using mouse and keyboard. With the mouse, you can click or drag the commands to create instructions.", "maze_operation1_2_textset_1": "How to click on the commands", "maze_operation1_2_textset_2": "How to drag and drop commands", "maze_operation1_3_desc": "If you want to use the keyboard to give commands, type in the commands in the \’Command Box.\’
When you type in the commands, be careful not to ommit () and ;", "maze_operation1_4_desc": "Once you have finished inputting the commands, click [Run.]
I will move according to your code once you click [Run.]
If you want to know more about each command, check out the [Command guide.]", "maze_operation7_title": "STEP 7 - How repeat works (repeat number of times)", "maze_operation7_1_desc": "Repeating the same command over and over is a cumbersome task.
Simplify the command using the repeat commands.", "maze_operation7_2_desc": "Then let's look at how we can simplify commands that repeat.
First, click the repeat command. Then change the number ini<1
Then insert the commands to repeat within { }", "maze_operation7_3_desc": "For example, this command executes move(); 10 times.
It is the same as command ", "maze_operation7_4_desc": "When using commands, make sure to spell the commands correctly within { }
and that you don't forget ’;'.
Learn more about the commands in the 'command guide'", "maze_operation7_1_textset_1": "When using commands repeatedly", "maze_operation7_1_textset_2": "When using repeat command", "maze_operation7_2_textset_1": "Number of times to repeat", "maze_operation7_2_textset_2": "Commands to repeat", "maze_operation7_4_textset_1": "When ({}) is missing", "maze_operation7_4_textset_2": "When semicolon(;) is missing", "study_maze_operation8_title": "STEP 4 - How repeat works (repeat number of times)", "study_maze_operation16_title": "STEP 4 - How repeat works (repeat number of times)", "study_maze_operation1_title": "STEP 1 - How repeat works (repeat number of times)", "maze_operation9_title": "STEP 9 - How repeat works(Conditional loop)", "maze_operation9_1_desc": "We learned about repeating for set number of times.
This time, let's explore commands for repeating continuously.
When you use this command, the action will be executed until end of the mission.
Insert commands to be repeated within ({ }).", "maze_operation9_2_desc": " move(); right(); until end of mission.
It is the same as command ", "maze_operation9_3_desc": "Make sure to spell the commands correctly within { }
and make sure ‘true' isn't missing!
You can learn more about this command in the 'command guide'", "maze_operation9_1_textset_1": "Commands to repeat", "maze_operation9_3_textset_1": "When ({}) is missing", "maze_operation9_3_textset_2": "When semicolon(;) is missing", "maze_operation9_3_textset_3": "When semicolon(;) is missing", "study_maze_operation3_title": "STEP 3 - How repeat works(Conditional loop)", "study_maze_operation4_title": "STEP 4 – How condition works", "study_ai_operation4_title": "STEP 4 – How condition works", "study_ai_operation6_title": "STEP 6 – How condition works", "study_ai_operation7_title": "STEP 7 – How condition works", "study_ai_operation8_title": "STEP 8 – How condition works", "study_ai_operation9_title": "STEP 9 – How condition works", "maze_operation10_title": "STEP 10 – How condition works", "maze_operation10_1_desc": "We learned about repeating commands until end of the mission.
This time, let's explore the commands that are only executed under certain conditions.
As you can see in , using conditional statement can make commands more efficient.", "maze_operation10_2_desc": "conditional statement can be split into condition and commands to be executed when met with the condition.
First, let's look at the conditions. Insert the condition within ( ) that follows ‘if'.
For example if(front == ‘wall') means, \’if there is a wall in front of me.\’", "maze_operation10_3_desc": "Now let's explore commands to execute when met with the condition. These commands are tied within curly braces {} and are executed when met with the given condition.When condition is not met, the commands are ignored.Let's look at an example . If the condition is 'when a wall is in front of me', and the condition is met, then I execute the commands within the braces and turn right following the command right();", "maze_operation10_4_desc": "The conditional statements are often used with repeat commands.
Go straight and turn only when met with a wall.
I can create commands in the order of ", "maze_operation10_1_textset_1": "[commands]", "maze_operation10_1_textset_2": "move 2 forward
turn right,
move 3 forward
turn right, move forward…
", "maze_operation10_1_textset_3": "[conditional statements]", "maze_operation10_1_textset_4": "Go forward
'when met with a wall’
turn right!
", "maze_operation10_2_textset_1": "condition", "maze_operation10_2_textset_2": "commands to execute when condition is met", "maze_operation10_3_textset_1": "condition", "maze_operation10_3_textset_2": "commands to execute when condition is met", "maze_operation10_4_textset_1": "Go forward
until end of mission
", "maze_operation10_4_textset_2": "Go forward
until met with a wall
", "maze_operation10_4_textset_3": "Go forward
until met with a wall
then turn right
", "study_maze_operation18_title": "STEP 6 – How condition works", "maze_operation15_title": "STEP 15 – How function works", "maze_operation15_1_desc": "It is a cumbersome task to type out the commands that are used often.
Give a name to the set of commands that are used often.
Then call the set of commands by its name to create commands conveniently.
These sets commands are called 'functions'. Now let's explore what functions are.", "maze_operation15_2_desc": "Using a function involves process of creating a function by grouping a set of functions, and calling the set of commands by 'call function’.
Let's take a look at the process of defining a function.To define a function, give a function name and set of commands to execute.
First input ‘function' and then give the function name. This time, I'll call it promise.
Once you've given it a name, insert (). Then type in ({ }).Once you insert the commands within these brackets, you have finished defining a function!", "maze_operation15_3_desc": "Take a look at this command. I created a function called promise
When I call this function, then the commands within the brackets({}) will execute
move();
move();
left();
", "maze_operation15_4_desc": "To call and execute functions, input the name of the functions, then add '();' behind it.
So to call a function called 'promise', I need to type promise();
to execute the function.
When I make commands like , the program will execute as that of
To use the function, define function as and call it.", "maze_operation15_1_textset_1": "Checking the commands that are used often", "maze_operation15_1_textset_2": "Giving a name for set of commands", "maze_operation15_1_textset_3": "Calling a set of commands", "maze_operation15_2_textset_1": "Name of the command set (function name)", "maze_operation15_2_textset_2": "commads to group as a set", "maze_operation15_3_textset_1": "Name of the command set (function name)", "maze_operation15_3_textset_2": "commads to group as a set", "maze_operation15_4_textset_1": "Defining function", "maze_operation15_4_textset_2": "Calling function", "maze_operation15_4_textset_3": "Real situation", "maze_object_title": "Object info", "maze_object_parts_box": "Tool box", "maze_object_trap": "trap", "maze_object_monster": "monster", "maze_object_obstacle1": "obstacle", "maze_object_obstacle2": "bee", "maze_object_obstacle3": "banana", "maze_object_friend": "friend", "maze_object_wall1": "wall", "maze_object_wall2": "wall", "maze_object_wall3": "wall", "maze_object_battery": "battery", "maze_command_ex": "example", "maze_command_title": "command guide", "maze_command_move_desc": "moves entrybot one forward", "maze_command_jump_desc": "jumps over obstacles like the image below.
", "maze_command_jump_desc_elec": "jumps over obstacles like the image below.
", "maze_command_right_desc": "turn 90 degrees right in place.", "maze_command_left_desc": "turn 90 degrees left in place.", "maze_command_for_desc": "repeat commands within curly braces {} for given number of times.", "maze_command_while_desc": "repeat commands within curly braces {} until end of mission", "maze_command_slow_desc": "When condition 'when met with a wall’ is fulfilled,
execute commands within curly braces {}", "maze_command_if1_desc": "When condition 'when met with a wall’ is fulfilled,
execute commands within curly braces {}", "maze_command_if2_desc": "When condition 'when met with a beehive’ is fulfilled,
execute commands within curly braces {}", "maze_command_if3_desc": "When condition 'when met with a banana’ is fulfilled,
execute commands within curly braces {}", "maze_command_promise_desc": "when a function called 'promise' is defined and executed,
then the functions within the curly braces {} will execute. ", "perfect": "Perfect! You succeeded using ", "succeeded_using_blocks": " blocks!", "succeeded_using_commands": " commands!", "awesome": "Awesome! You succeeded using just", "succeeded_go_to_next": " blocks!", "good": "Good!", "but": "
But, there is a way to succeed using just ", "try_again": " blocks.
Why don’t you try again?", "try_again_commands": " commands.
Why don’t you try again?", "cfest_success": "Awesome! You helped save my friends!
Looks like you’re a natural born programmer!
See you again soon!", "succeeded_and_cert": "blocks!
My certificate of completion is ready!", "cause_msgs_1": "Oh dear, it’s a dead end. Try again.", "cause_msgs_2": "Oops. There’s nothing to jump over. Try again.", "cause_msgs_3": "Ouch! That hurt. You should have jumped over this. Try again.", "cause_msgs_4": "Sorry, but you need to use the below blocks in this level.
Do you want to try again?", "cause_msgs_5": "Uh oh… You’ve run out of blocks. Try again.", "cause_msgs_6": "Uh oh… You’ve run out of commands. Try again.", "close_experience": "The
End", "replay": "Replay", "go_to_next_level": "Next", "move_forward": "Move forward", "turn_left": "Left", "turn_right": "Right", "turn_en": "Turn ", "turn_ko": "", "jump_over": "Jump Over", "when_start_is_pressed": "When Start is pressed", "repeat_until_ko": "", "repeat_until_en": "Repeat until", "repeat_until": "Repeat until", "if_there_is_1": "If there is a ", "if_there_is_2": "", "used_blocks": "Blocks used", "maximum": "Maximum", "used_command": "Command used", "maximum_command": "Maximum command", "block_box": "Block Box", "block_assembly": "Block Assembly", "command_box": "Command Box", "command_assembly": "Command Assembly", "start": "Start", "engine_running": "Play", "engine_replay": "Replay", "goto_show": "Learn more", "make_together": "Let's build together!", "make_together_content": "Entry is created with teachers and students", "project_nobody_like": "Click 'Like', if you like it!", "project_nobody_interest": "Click 'Mark' to keep it on your blog.", "lecture_nobody_like": "Click 'Like', if you like it!", "lecture_nobody_interest": "Click 'Mark' to keep it on your blog.", "course_nobody_like": "Click 'Like', if you like it!", "course_nobody_interest": "Click 'Mark' to keep it on your blog.", "before_changed": "before changed", "after_changed": "after changed", "from_changed": "( From 17 Apr 2016 ) ", "essential": "essential", "access_term_title": "Hello we are an educational institute Entry .
Thank you for loving your entry
From April 17, 2016 Entry Training Institute Website Terms and Conditions
is amended to read as follows:", "member_info": "Member information", "personal_info": "Agree to the transfer of personal information.", "option": "select one", "news": "news", "edu_material": "materials", "latest_news": "Latest news", "edu_data": "Educational", "training_program": "Training", "footer_phrase": "Entry is a nonprofit education platform powered by Naver and CONNECT Foundation", "footer_use_free": "All materials created by Entry Labs may be used freely for educational purposes as long as the original source is credited.", "footer_description_1": "Entry is a nonprofit education platform.", "footer_description_2": "All materials created by Entry Labs may be used freely for educational purposes as long as the original source is credited.", "nonprofit_platform": "nonprofit educational platform", "this_is": "powered by Naver and CONNECT Foundation", "privacy": "Privacy policy", "entry_addr": "16F, 6, Buljeong-ro, Bundang-gu, Seongnam-si, Gyeonggi-do", "entry_addr_additional_phone": "1522-9182", "entry_addr_additional_email": "entry@connect.or.kr", "entry_addr_additional_opensource": "Open Source License", "phone": "phone", "alert_agree_term": "Please agree to ENTRY’s Terms of Use", "alert_private_policy": "Please agree to the collection and use of personal information.", "agree": "Agree", "optional": "option", "start_software": "first step of software education", "analyze_procedure": "절차", "analyze_repeat": "반복", "analyze_condition": "분기", "analyze_interaction": "상호작용", "analyze_dataRepresentation": "데이터 표현", "analyze_abstraction": "추상화", "analyze_sync": "병렬 및 동기화", "jr_intro_1": "Hi! My name is Juny! My friend Entry-Bot is by my right side. Please take me to him! ", "jr_intro_2": "Entry-Bot is by my left! Let's go the left side. ", "jr_intro_3": "Entry-Bot is by my top side. Please help me meet my friend. ", "jr_intro_4": "Come on! Let's meet Entry-Bot! He is by my bottom side. ", "jr_intro_5": "Wow! My friend is far away from me. Can you guide me so I can meet Entry-Bot ", "jr_intro_6": "Entry-Bot is really far away from here! But It's okay. If we use repeat block, we could reach the Entry-Bot easily.", "jr_intro_7": "There are beautiful flowers here! Let's give it to my friend!", "jr_intro_8": "On a way to my friend, you can see the flower. Let's give it to my friend.", "jr_intro_9": "Oh, my friend is far away from me. Let's find a fastest way to him!", "jr_intro_10": "There are flowers! Let's pick it up! ", "jr_intro_11": "We should go right side exactly 5 times! Let's use repeat block so we can reach there more easily", "jr_intro_12": "Let's meet my friend Entry-Bot using repeat block.", "jr_intro_13": "With this misplaced block, I can't reach my friend. Please change the input number of repeat block.", "jr_intro_14": "Please take me to my friend Entry-Bot using repeat block.", "jr_intro_15": "Entry-Bot is really far away from here! But It's okay. If we use repeat block, we could reach the Entry-Bot easily.", "jr_whats_ur_name": "What is your name to be showned on certification.", "jr_down_cert": "Certification", "jr_popup_prefix_1": "Hooray! I met Entry-Bot!", "jr_popup_prefix_2": "Nice! I met Entry-Bot! But we can make it with fewer blocks. How about try again?", "jr_popup_prefix_3": "Hooray! I got my backpack!", "jr_popup_prefix_4": "Great! I have my backpack! But we can make it with fewer blocks. How about we try again?", "jr_popup_suffix_1": "Thank you! I had so much fun with you. See you around!", "jr_popup_suffix": "Thanks to you! I had fun time with Entry-Bot. See you around~", "jr_fail_dont_go": "Oops, I can't go there. Please guide me again~", "jr_fail_dont_know": "Hmm. Where should I go? Please guide me more~", "jr_fail_no_flower": "There is no flower. Use 'flower block' at the flower!", "jr_fail_forgot_flower": "I need more flowers for Entry-Bot. Let's try again.", "jr_fail_need_repeat": "Uh? I should use 'repeat block' ! Let's try again with the block~", "jr_hint_1": "Hi! My name is Juny! My friend Entry-Bot is by my right side. Please take me to him!", "jr_hint_2": "Entry-Bot is by my left! Let's go the left side.", "jr_hint_3": "Entry-Bot is by my top side. Please help me meet my friend.", "jr_hint_4": "Come on! Let's meet Entry-Bot! He is by my bottom side.", "jr_hint_5": "Wow! My friend is far away from me. Can you guide me so I can meet Entry-Bot?", "jr_hint_6": "Because of the blocks that put together by mistake, I can't reach my friend. Please fix it for me so I can reach my friend Entry-Bot!", "jr_hint_7": "There are beautiful flowers here! Let's give it to my friend!", "jr_hint_8": "On a way to my friend, you can see the flower. Let's give it to my friend.", "jr_hint_9": "Oh, my friend is far away from me. Let's find a fastest way to him!", "jr_hint_10": "Oops, I can't reach to my friend because of misplaced blocks. Please fix it so I can give all of flowers to my friend.", "jr_hint_11": "We should go right side exactly 5 times! Let's use repeat block so we can reach there more easily.", "jr_hint_12": "Let's meet my friend Entry-Bot using repeat block.", "jr_hint_13": "With this misplaced block, I can't reach my friend. Please change the input number of repeat block.", "jr_hint_14": "Please take me to my friend Entry-Bot using repeat block.", "jr_hint_15": "Entry-Bot is really far away from here! But It's okay. If we use repeat block, we could reach the Entry-Bot easily.", "jr_certification": "Certification", "jr_congrat": "Congratulation!", "jr_congrat_msg": "Successfully completed for problem solving courses.", "jr_share": "Share", "go_see_friends": "Let us see your friends~!", "junior_naver": "Junior Naver", "junior_naver_contents_1": "'s cool bear , Juni came looking for entries! ", "junior_naver_contents_2": "But Juni' is difficult to find a way yet. ", "junior_naver_contents_3": "Please tell Juni to go , so he can meet entrybot.", "basic_content": "Basic", "jr_help": "Help", "help": "Help", "cparty_robot_intro_1": "Hi, My name is Entry-bot. I need to to fix myself. Please help me get my parts with 'move forward' block.", "cparty_robot_intro_2": "Great! My part is right in front of me but I need to be careful not to get electrocuted. Use 'jump over' block to get to the part.", "cparty_robot_intro_3": "Great! There's my part! The path is challenging but using the 'turn' block I can get there easily! Will you help?", "cparty_robot_intro_4": "Nice! I feel a lot better! Try using the 'turn' block and 'jump over' block to get the parts!", "cparty_robot_intro_5": "Thanks to you, I'm feeling great! Make sure to use 'turn' and 'jump over' to get the part!", "cparty_robot_intro_6": "Great! I feel like I can repeat! Use repeat to get to the part!", "cparty_robot_intro_7": "Watch out! There are dangerous holes to jump over but no worries! Let's use repeat to get to the part.", "cparty_robot_intro_8": "Oh no! The part is far from here. Using repeat can get me there easily. Help me! ", "cparty_robot_intro_9": "Wow~ I'm almost complete! Let's use 'repeat' to get to the part!", "cparty_robot_intro_10": "Cool! The last part will make me complete! Let's use 'repeat' to get to my last part! ", "cparty_car_intro_1": "Hi, My name is Entry-bot. I need battery pack to travel! Can you me get to the battery pack?", "cparty_car_intro_2": "Good! We can't go straight this time! Let's use the 'turn left/right' block to get to the battery pack.", "cparty_car_intro_3": "Great! There's a speed bump on our way. It'll be dangerous to drive fast. Let's use the 'go slow' block to get to the battery pack.", "cparty_car_intro_4": "Yeah! The drive doesn't look easy but using the move forward, 'turn left/ right' block", "cparty_car_intro_5": "The road looks challenging but we can safely get to the battery pack by repeating 'turn left/ right' blocks", "cparty_car_intro_6": "There are obstacles on our way so let me know how to get around one!", "cparty_car_intro_7": "Great! Let's use the 'if' block to get around obastacles and get to the battery pack.", "cparty_car_intro_8": "There are two speed bumps this time! Use 'go slow' block to safely travel to the battery pack.", "cparty_car_intro_9": "The road looks challenging but using the 'repeat' block and 'if' block, we can make it! Help me get to the battery pack!", "cparty_car_intro_10": "Awesome! We're almost there. Let's get that last battery pack!", "cparty_car_popup_prefix_1": "Hooray! I got a battery!", "cparty_car_popup_prefix_2": "Nice! I got a battery! But we can make it with fewer blocks. How about try again?", "cparty_car_popup_prefix_2_text": "Nice! I got a battery! But we can make it with fewer commands How about try again?", "cparty_car_popup_suffix": "Thanks to you! I've got all the battery. See you around~", "all_grade": "All grades", "grade_e3_e4": "Elementary 3~4th grade & up", "grade_e5_e6": "Elementary 5~6th grade & up", "grade_m1_m3": "Middle School 1~3rd grade & up", "entry_first_step": "Entry First Steps", "entry_monthly": "Monthly Entry", "play_sw_2": "Let's Play Software 2", "entry_programming": "Let's Program!", "entry_recommanded_course": "Entry Recommended Courses", "introduce_course": "Follow along and create various projects made easy and fun for everyone!", "all_free": "*Course videos, customized projects, and resources are provided for free.  ", "cparty_result_fail_1": "Oops, I can't go there. Please guide me again~", "cparty_result_fail_2": "Ouch! That hurt. You should have jumped over this. Try again.", "cparty_result_fail_3": "I'm worn out! Try using the blocks below and make the travel easier.", "cparty_result_fail_4": "Hmm... Where should I go? Please give me further instructions.", "cparty_result_fail_5": "Oh no! You need to slow down at the speed bump. Try using the 'go slow' block.", "cparty_result_success_1": "Hooray! I got a parts", "cparty_result_success_2": "Nice! I got a parts! But we can make it with fewer blocks. How about we try again?", "cparty_result_success_2_text": "Nice! I got a parts! But we can make it with fewer commands How about we try again?", "cparty_result_success_3": "Thanks to you! I've fixed all~ See you around~", "cparty_insert_name": "insert your name", "offline_file": "File", "offline_edit": "Edit", "offline_undo": "Un-do", "offline_redo": "Re-do", "offline_quit": "Quit", "select_one": "Please select one.", "evaluate_challenge": "please evaluate the level of difficulty of the mission challenged.", "very_easy": "very easy", "easy": "easy", "normal": "normal", "difficult": "difficult", "very_difficult": "very difficult", "save_dismiss": "bạn đã không lưu thay đổi. Bạn có chắc chắn muốn tiếp tục không?", "entry_info": "About Entry", "actual_size": "Actual Size", "zoom_in": "Zoom In", "zoom_out": "Zoom Out", "cparty_jr_intro_1": "Hi! My name is Entry-Bot! Please help me get my backpack on my way to school.", "cparty_jr_intro_2": "My backpack to my left! Let's go left.", "cparty_jr_intro_3": "My backpack is located above. Please help me to get my backpack.", "cparty_jr_intro_4": "Come on! Let's pick up the backpack by going downwards.", "cparty_jr_intro_5": "Wow! My backpack is far away from me. Could you take me to my backpack?", "cparty_jr_intro_6": "There is backpack! Let's pick it up!", "cparty_jr_intro_7": "There are pencils along the way. Let's pick them up on our way to the backpack.", "cparty_jr_intro_8": "A pencil on our way to school! Let's pick up the pencil on our way to the backpack.", "cparty_jr_intro_9": "Oh, my backpack is far away. Let's find the fastest path to it!", "cparty_jr_intro_10": "Let's pick up the pencils on my way to the backpack!", "cparty_jr_intro_11": "We should go right exactly 5 times! Let's use the repeat block so we can get there more easily", "cparty_jr_intro_12": "Let's pick up the backpack using the repeat block.", "cparty_jr_intro_13": "I can't reach my backpack with this misplaced block. Please change the number of repeats.", "cparty_jr_intro_14": "Please take me to my backpack using the repeat blocks.", "cparty_jr_intro_15": "School is really far from here! But that's okay. If we use the repeat block, we can get to school easily.", "make_new_project": "Create New Project", "open_old_project": "Open Project", "offline_download": "Entry Download", "offline_release": "Download Entry Offline Editor!", "offline_description_1": "Install and use Entry Offline Editor", "offline_description_2": "without internet connection.", "offline_description_3": "Download and try it out!", "sw_week_2015": "2015 소프트웨어교육 체험 주간", "cparty_desc": "두근두근 소프트웨어와의 첫만남", "entry_offline_download": "Download \nOffline Editor", "entry_download_detail": "Download\nVeiw Details", "offline_desc_1": "Install and use Entry Offline Editor without internet connection.", "offline_desc_2": "Download and try it out!", "download": "download", "version": "version", "file_size": "size", "update": "update", "use_range": "Scope of use", "offline_desc_free": "Entry Offline Editor is free for both individual and corporate use.", "offline_required": "System Requirement", "offline_required_detail": "Minimum 1GB disk space is required, Windows7 and above or, Mac OS 10.8 and above", "offline_notice": "Side notes", "offline_notice_1": "1. Version", "offline_notice_1_1": "does not support installation of all-in-one hardware connection program", "offline_notice_2": "2. Web browser is not needed.", "offline_notice_3": "Release note", "offline_notice_4": "Download by version", "offline_notice_5": "Release note", "hardware_online_badge": "Online", "hardware_title": "Entry Hardware Connector Program Download", "hardware_desc": "In order to connect to hardware projects and 'Create Project' online, download and install Entry Hardware Connector Program.", "hardware_release": "Details on Hardware Connector Program updates are available in the link below.", "hardware_window_download": "Windows Download", "hardware_osx_download": "Mac Download", "cparty_jr_result_2": "Thank you! I had so much fun with you.
See you around!", "cparty_jr_result_3": "Great! I've arrived school! But we can make it with fewer blocks.
How about we try again? ", "cparty_jr_result_4": "", "lms_no_class": "There is no class.", "lms_create_class": "Please create a class.", "lms_add_class": "Create class", "lms_base_class": "Default", "lms_delete_class": "Delete", "lms_my_class": "My Class", "lms_grade_1": "elementary school 1", "lms_grade_2": "elementary school 2", "lms_grade_3": "elementary school 3", "lms_grade_4": "elementary school 4", "lms_grade_5": "elementary school 5", "lms_grade_6": "elementary school 6", "lms_grade_7": "middle school 1", "lms_grade_8": "middle school 2", "lms_grade_9": "middle school 3", "lms_grade_10": "general", "lms_add_groupId_personal": "Add classroom ID to your member profile.", "lms_add_groupId": "Add Classroom ID", "lms_add_group_account": "Add Classroom ID", "lms_enter_group_info": "Enter classroom ID and password", "lms_group_id": "Classroom ID", "lms_group_pw": "Password", "lms_group_name": "Class Name", "personal_pwd_alert": "Enter correct password", "personal_form_alert": "양식을 바르게 입력해 주세요", "personal_form_alert_2": "모든 양식을 완성해 주세요", "personal_no_pwd_alert": "Enter password", "select_gender": "Please enter your gender", "enter_group_id": "Enter classroom ID", "enter_group_pwd": "Enter password", "info_added": "추가되었습니다", "no_group_id": "The Class ID does not exist", "no_group_pwd": "비밀번호가 일치하지 않습니다", "lms_please_choice": "Choose", "group_lesson": "나의 학급 강의", "lms_banner_add_group": "Learning Management System is now available", "lms_banner_entry_group": "Create Entry class ", "lms_banner_desc_1": "Add your students", "lms_banner_desc_2": "Manage your student's projects", "lms_banner_desc_3": "and track their growth.", "lms_banner_download_manual": "Manual Download", "lms_banner_detail": "Try it out!", "already_exist_email": "email already exists", "same_registered_email": "Registered email.", "email_correnctly_please": "Please enter a valid email", "remove_project": "Are you sure to remove this project?", "study_lesson": "Class Lessons", "open_project": "Open Project", "make_group": "Create Class", "project_share": "Project share", "group_project_share": "Class Share", "group_discuss": "Class Discuss", "my_profile": "My page", "search_updated": "Recent Project", "search_recent": "Project with most views", "search_complexity": "Project with most effort", "search_staffPicked": "Staff pick project save area", "search_childCnt": "Project with most copies", "search_likeCnt": "Project with most likes", "search_recentLikeCnt": "Project with most likes", "gnb_share": "Share", "gnb_community": "Community", "lms_add_lectures": "Add Lessons", "lms_add_course": "Add Courseware", "lms_add_homework": "Add Assignment", "remove_lecture_confirm": "Are you sure you want to delete?", "popup_delete": "Delete", "remove_course_confirm": "Are you sure you want to delete?", "lms_no_lecture_teacher_1": "There is no lessons.", "lms_no_lecture_teacher_2": "Please create a lessons.", "gnb_download": "Download", "lms_no_lecture_student_1": "", "lms_no_lecture_student_2": "There is no lessons.", "lms_no_lecture_student_3": "", "lms_no_class_teacher": "There is no class.", "lms_no_course_teacher_1": "There is no courseware.", "lms_no_course_teacher_2": "Please create a courseware.", "lms_no_course_student_1": "", "lms_no_course_student_2": "There is no courseware.", "lms_no_course_student_3": "", "lms_no_hw_teacher_1": "There is no assignment.", "lms_no_hw_teacher_2": "Please create a assignment.", "lms_no_hw_student_1": "", "lms_no_hw_student_2": "There is no assignment.", "lms_no_hw_student_3": "", "modal_edit": "edit", "modal_deadline": "Deadline", "modal_hw_desc": "Description", "desc_optional": "(optional)", "modal_create_hw": "Create Assignment", "vol": "Vol.", "hw_title": "Title", "hw_description": "Description", "deadline": "Deadline", "do_homework": "Do Assignment", "hw_progress": "Progress", "hw_submit": "submit", "view_list": "Submitter", "view_desc": "content", "do_submit": "submit", "popup_notice": "Alert", "no_selected_hw": "No Assignment is selected", "hw_delete_confirm": "Are you sure you want to delete?", "hw_submitter": "List of Assignment submissions", "hw_student_desc_1": "* You may edit the project until 'Submit' button completes the submission process.", "hw_student_desc_2": "* Once submission period is over, project cannot be submitted.", "popup_create_class": "Create Class", "class_name": "Class name", "image": "Image", "select_class_image": "Please select a class image.", "type_class_description": "Class Introduction.", "set_as_primary_group": "Set as default classroom", "set_primary_group": "assign", "not_primary_group": "not assigned", "type_class_name": "Please enter the class name.", "type_class_description_long": "Please enter the class introduction.", "add_students": "Add students", "invite_students": "Invite students", "invite_with_class": "1. Invite with class code", "invite_code_expiration": "Code expiration time", "generate_code_button": "reissue code", "generate_code_desc": "Student instructions for entering class code", "generate_code_desc1": "Log in at playentry.org", "generate_code_desc2": "Select from the menu.", "generate_code_desc3": "Click then paste in the class code.", "invite_with_url": "2. Invite using class URL", "copy_invite_url": "Copy", "download_as_pdf": "Download code as PDF file", "download_as_excel": "Download code as Excel file", "temp_password": "Temporary password", "step_name": "Name", "step_info": "Additional Information", "preview": "Preview", "type_name_enter": "To add student, type in the student name and hit enter. ", "multiple_name_possible": "Adding multiple student names is possible.", "id_auto_create": "Student number is automatically created if not edited", "student_id_desc_1": "Class ID is created automatically without manual input", "student_id_desc_2": "If student account already exists, add student information. When the student logs in,", "student_id_desc_3": "class invitation is sent. No extra step for sharing account information is necessary.", "student_number": "Student number", "temp_password_desc_1": "After logging in with temporary password,", "temp_password_desc_2": "guide the students to reset the password.", "temp_password_desc_3": "*You cannot see temporary password once issued", "temp_password_demo": "This is an informational account that can not log in.", "temp_works": "View works", "student_delete_confirm": "Are you sure you want to delete?", "no_student_selected": "No student is selected", "class_assignment": "Class Assignments", "class_list": "Class List", "select_grade": "Please select the grade.", "add_project": "sharing Project", "no_project_display": "There is no project to display.", "plz_display_project": "Please display a project.", "refuse_confirm": "Are you sure you want to refuse?", "select_class": "학급 선택", "group_already_registered": "Already registered.", "my_page_entry": "Entry", "my_page_title": "My Page", "my_classGroup_title": "My Class", "my_classGroup_title_view": "view my class", "my_space_area": "my own space", "mon": "MON", "tue": "TUE", "wed": "WED", "thu": "THU", "fri": "FRI", "sat": "SAT", "sun": "SUN", "jan": "Jan", "feb": "Feb", "mar": "Mar", "apr": "Apr", "may": "May", "jun": "Jun", "jul": "Jul", "aug": "Aug", "sep": "Sep", "oct": "Oct", "nov": "Nov", "dec": "Dec", "plz_select_lecture": "Please select a lessons.", "plz_set_deadline": "Please set the deadline.", "hide_entry": "Hide Entry", "hide_others": "Hide Others", "show_all": "Show All", "lecture_description": "Lessons are listed by topics and levels. Follow along in step-by-step order.", "curriculum_description": "Teacher created Entry learning space. See example projects and try creating them.", "linebreak_off_desc_1": "Kích thước của hộp văn bản xác định kích thước phông chữ", "linebreak_off_desc_2": "Nội dung của bạn chỉ có thể được viết trong một dòng", "linebreak_off_desc_3": " bên trái và bên phải của hộp sẽ kéo dài khi bạn thêm từ ", "linebreak_on_desc_1": "kích thước của hộp văn bản xác định phạm vi mà bạn có thể viết", "linebreak_on_desc_2": "Bạn có thể thay đổi dòng bằng cách nhấn phím 'Enter'", "linebreak_on_desc_3": "Nội dung của bạn sẽ tự động đi đến dòng kế tiếp nếu chiều dài vượt quá chiều rộng của hộp văn bản, khi viết hoặc thêm từ mới.", "not_supported_text": "Current font does not support Chinese characters", "entry_with": "Entry is Created With Teachers", "ebs_season_1": "Visit Season 1", "ebs_season_2": "Visit Season 2", "hello_ebs": "Hello! EBS software", "hello_ebs_desc": "Learn the basic principles of programming. \n Watch the show, follow along the video tutorials, \n and learn to code!", "hello_ebs_sub_1": "Meet EBS's interactive middle ", "hello_ebs_sub_2": "school age program.", "exhibit_4th_title": "4th Anniversary of Entry", "exhibit_4th_subtitle": "Entry Project Contest", "exhibit_4th_desc1": "We hold an Entry Project Contest ", "exhibit_4th_desc2": "to celebrate the 4th anniversary of entry.", "exhibit_4th_desc3": "Show off your great project!", "exhibit_4th_button": "View Details", "visang_edu_entry": "비상교육 엔트리 학습하기", "cmass_edu_entry": "씨마스 엔트리 학습하기", "chunjae_edu_entry": "천재교과서 엔트리 학습하기", "kumsungemt_edu_entry": "금성출판사 엔트리 학습하기", "kumsungMid_edu_entry": "금성출판사 엔트리 학습하기", "gilbutEdu_edu_entry": "길벗출판사 엔트리 학습하기", "miraenCoding_edu_entry": "미래엔 엔트리 학습하기", "textbook_help_data": "Help data", "textbook_teaching_activity": "teaching and activity", "textbook_kyohacksa": "Kyohaksa", "textbook_kumsung": "Kumsung Publishing", "textbook_donga": "Dong-a Publishing", "textbook_chunjae": "Chunjae Education", "textbook_miraen": "Mirae-n", "textbook_visang": "Visang", "partner": "Our Partners", "project_term_popup_title": "Copyright policy", "project_term_popup_description_1": "Please review the Entry ", "project_term_popup_description_2": "copyright policy ", "project_term_popup_description_3": "to allow public viewing ", "project_term_popup_description_4": "of the project.", "project_term_agree_1_1": "I agree to the release of my work itself and its source code.", "project_term_agree_2_1": "I permit others to use it.", "project_term_agree_2_2": "(includes copy, distribution, and transmission through airwaves)", "project_term_agree_3_1": "I permit others to make modifications to it.", "project_term_agree_3_2": "(includes remixes, modifications, and derivative works)", "agree_all": "I agree to all conditions.", "select_login": "Log in", "select": "Please select", "with_login": "Log in and", "without_login": "Start Challenge", "start_challenge": "Start Challenge", "start_challenge_2": "without Logging in", "if_not_save_not_login": "* Your progress will not be saved if not logged in.", "if_not_member_yet": "If you aren't a member yet,", "join_entry": "Join Entry", "learned_computing": "Have you learned computing before?", "cparty_index_description_1": "My first computing.", "cparty_index_description_2": "Learn programming concepts and develop your thinking skills while playing Entry. ", "cparty_index_description_3": "Challenge yourself to exciting mission stages and earn certificates.", "cparty_index_description_4": "2015 Online Coding Party is part of", "cparty_index_description_5": "Software Programming Experience Week", "cparty_index_description_6": "prepared with", "cparty_index_description_7": "Association of Teachers for Computing.", "cparty_index_description_8": "", "cparty_index_description_9": "2016 Online Coding Party is part of", "cparty_index_description_10": "2017 Online Coding Party is part of", "cparty_index_description_11": "Association of Teachers for Computing.", "congratulation": "Congratulation!", "warm_up": "warm-up", "beginner": "beginner", "intermediate": "intermediate", "advanced": "advanced", "applied": "applied", "cert_msg_tail": "track.", "cert_msg_head": "You have successfully completed the", "maze_text_content_1": " 명령어를 사용해서 나를 부품 상자까지 이동시켜줘!", "maze_text_content_2": " 명령어를 사용해서 장애물을 뛰어넘어야해!", "maze_text_content_3": "Nice! I see another part over there. The path is twisted but I can get there using the 'right();', 'left();' commands. ", "maze_text_content_4": "I can move smoothly now. Take me to my parts using the commands we've learned so far.", "maze_text_content_5": "Wow! Two parts! Let's collect them both so I can recover faster.", "maze_text_content_6": "Last part! I'll recover fully with that last piece. You'll help me, right?", "maze_text_content_7": "I'm feeling great! I can repeat tasks without stress now. Oh no! What is that robot in front of us? I think it needs help! Use 'for' command to get to the friend!", "maze_text_content_8": "Excellent! I was able to rescue my robot friend thanks to you. I see another friend over there. Be careful. There are beehives to avoid. You can do it! Let's use the 'for' command to get to my friend.", "maze_text_content_9": "Use 'while' instead of 'for' to repeat until we've accomplished our goal. Take me to my friend.", "maze_text_content_10": "Now we have 'if' command. Use 'if' and 'while' to let me know which way to turn.", "maze_text_content_11": "Great! Let's do this once more. Tell me when to turn left.", "maze_text_content_12": "There are beehives scattered in the pathway. Tell me when to jump over.", "maze_text_content_13": "So many friends need help! Let's go help them", "maze_text_content_14": "More friends to rescue! Let's first try going around those square blocks and repeat to get to all of my friends.", "maze_text_content_15": "I'm tired from moving so much. I've grouped the commands that are often used into 'functions'. Use functions to get me to my battery!", "maze_text_content_16": "Excellent! Create functions and take me to my battery!", "maze_text_content_17": "Great job! Let's create functions with 'jump()", "maze_text_content_18": "The pathway is complex this time. But no worries! Just tell me when to use 'left()", "maze_text_content_19": "The functions are already defined! However, it seems difficult to get to the battery using only the functions. Let's try mixing functions and commands to get to the battery.", "maze_text_content_20": "You've done a fantastic job so far! After I retrieve that last battery, I will no longer need charging. Help me get to the battery using the functions so I can live free forever!", "maze_content_1": "Hi, I'm Entrybot. I'm trying to escape from this factory but first, I have to fix myself. Will you help me fetch my parts? Assemble 'Move forward' block and press Start. ", "maze_content_2": "Very good! I'm feeling much better! I see my part over there but I might get electrocuted if I don't be careful. Let's use 'jump over obstacle' block to get to the part.", "maze_content_3": "Great! My part is right over there. The path is a bit twisted but I can get there using 'rotate' blocks. You'll help me, right?", "maze_content_4": "Nice! I can almost move freely now. Let's get the part using 'rotate' and 'jump' blocks.", "maze_content_5": "Wow! Two parts! Let's get them both so I can restore my health faster.", "maze_content_6": "Thanks to you I'm feeling much better! I'm able to get better with those parts. You'll help me, right?", "maze_content_7": "I'm feeling great! I can repeat the same task without trouble now. Oh! Do you see the robot over there? I think she might need help. Let's go help her out. Bring me to her by changing the number of 'repeat's", "maze_content_8": "Excellent! I was able to rescue my pal! It looks like another one of my friends need help. Be careful there are beehives. Be sure to jump over the beehives! Can you do it? Help me reach her using the 'repeat' block. ", "maze_content_9": "Instead of repeating a task for set number of times, I can repeat until I reach my robot pal instead! Help me save my friend!", "maze_content_10": "Now we can use the 'if' block. Help me use the 'if' block to turn at right timing.", "maze_content_11": "Let's try it again! Let me know when to turn left.", "maze_content_12": "There are beehives all over the place. Tell me when to jump!", "maze_content_13": "My friends need help! Let's go help them!", "maze_content_14": "More friends need rescue! Let's first go around the small square and repeat it to rescue all my friends.", "maze_content_15": "Now I can memorize blocks that are used repeatedly. Promise blocks are the ones that I was able to memorize. I'm a bit tired from moving so much. Help me refill my battery using the Promise feature!", "maze_content_16": "Great! Tell me which blocks are used often and put them under the Promise block!", "maze_content_17": "Nice! Use Promise blocks to help me get my battery. Make sure to insert 'Jump' blocks in the Promise block.", "maze_content_18": "The path looks complex! We can get through this if we turn left and right at the right time.", "maze_content_19": "The 'Promise' if already set for us! However, we can't use the Promise blocks as is. I'll need to use the Promise blocks at the right timing to get the battery.", "maze_content_20": "Excellent! You've done great so far! After the final battery, I won't need to charge any more. So help me get the last battery using the Promise so I can live forever free!", "maze_content_21": "안녕? 나는 엔트리 봇이야. 지금 많은 친구들이 내 도움을 필요로 하고 있어. 반복하기를 이용해서 친구들을 도울수 있게 데려다 줘!", "maze_content_22": "고마워! 이번에는 벌집을 뛰어넘어서 친구를 구하러 갈 수 있게 도와줘!", "maze_content_23": "좋아! 이번에는 친구 로봇한테 갈 때까지 반복하기를 이용해서 친구를 도울 수 있게 도와줘!", "maze_content_24": "안녕! 나는 엔트리 봇이야. 지금 나는 너무 오래 움직여서 배터리를 채워야 해. 약속 불러오기를 써서 배터리를 채울 수 있도록 도와줘!", "maze_content_25": "멋져! 이번에는 여러 약속을 불러와서 배터리가 있는 곳까지 가보자!", "maze_content_26": "좋아! 이제 약속할 블록을 나한테 가르쳐줘! 약속하기 블록 안에 자주 쓰일 블록을 넣으면 돼!", "maze_content_27": "지금은 미리 약속이 정해져 있어. 그런데, 약속을 쓰기위해서는 내가 갈 방향을 보고 약속을 사용해야해. 도와줄거지?", "maze_content_28": "드디어 마지막이야! 약속을 이용하여 마지막 배터리를 얻을 수 있게 도와줘!", "ai_content_1": "Hi! I'm Entrybot. I just completed the space exploration mission and I need to return to Earth but it's not easy because of the asteroids. Could you help me return home? I have radars on top, front and back of the spaceship to detect how far an obstacle exists. It'll help you make smart decisions.", "ai_content_2": "Thank you! I was able to avoid the asteroids without trouble. There are more asteroids this time. Let's try avoiding them!", "ai_content_3": "Great! I was able to safely avoid the asteroids! There are more asteroids now! Don't worry though! I have the 'repeat' block. Place blocks in the 'repeat' block so we can get to the destination!", "ai_content_4": "Excellent! It's so much more easier to avoid the asteroids using the repeat blocks! However, it's tiring driving the spaceship at all times! I can use the radar to sense what's coming. Help avoid the asteroids using the radar.", "ai_content_5": "Nice! I'm so glad we've come this far. The radar will tell how far an object exists. Let's use the radar to avoid the asteroids! Move forward until we come close to an asteroid then avoid!", "ai_content_6": "Great job! You're using radar to avoid tha asteroids. Use multiple radars to avoid the asteroids.", "ai_content_7": "We're getting close to Earth! I want to go in a safer path if possible. It must be safer to move farther from the asteroids, right? Compare the distance to the obstacle using the radar on the top and bottom of the spaceship to move to a safer direction.", "ai_content_8": "Excellent! We're safely cruising through space. Oh! What is that? That's looks like my special energy! Let's collect the special energy on our way!", "ai_content_9": "Very good! We're almost there. The path is filled with asteroid. But don’t worry! We can get rid of the obstacles using the special item.", "ai_content_10": "Good! I can see Earth! But now it's impossible to see the asteroids ahead! I'm not worried though. We can avoid the asteroids with more caution. Let's go home!", "maze_hints_title_1": "How to start", "maze_hints_content_1": "How do I move Entrybot?", "maze_hints_detail_1": "1. Drag the block you want to use and place it under 'When Run'
2. Once finished, click 'Run'
3. I will follow the block instructions step by step, reading them from top to bottom", "maze_hints_title_2": "Jumping over obstacles", "maze_hints_content_2": "What do I do when I come across an obstacle?", "maze_hints_detail_2": "On your pathway, you might come across obstacles.
Use 'jump over' block to jump over the obstacle. ", "maze_hints_title_3": "Repeat block(1)", "maze_hints_content_3": "How do I use repeat (3) times block?", "maze_hints_detail_3": "If you want to repeat an action multiple times, use 'repeat ~times' block.
Place the blocks you want to repeat within the 'repeat ~times' block and input how many times to repeat.", "maze_hints_title_4": "Repeat block(2)", "maze_hints_content_4": "How do I use 'repeat until ~' block?", "maze_hints_detail_4": "Use 'repeat until~do' block to set until when an action should be performed.
Place the blocks you want to repeat within 'repeat until~' block.
Then once met with {image}, repeat will stop.", "maze_hints_title_5": "If block", "maze_hints_content_5": "How do I use 'if~' block?", "maze_hints_detail_5": "Using 'If {image}' block, you can designate what action should follow when met with {image}.
Blocks within the 'If {image}' will only execute when met with {image}.", "maze_hints_title_6": "Repeat block(3)", "maze_hints_content_6": "How does 'Until met with all ~' block work?", "maze_hints_detail_6": "Repeat blocks within 'Until met with all ~' block until met with all {tile}.
Once met with all {tile} repeat will stop.", "maze_hints_title_7": "Special Hint", "maze_hints_content_7": "It's too difficult. Help!", "maze_hints_detail_7": "Look at the path that I should travel. See the 4 small squares?
First create blocks that will take me around the square and repeat.", "maze_hints_title_8": "Function", "maze_hints_content_8": "What is 'Functions/ Call Functions'? How do I use them?", "maze_hints_detail_8": "Put the most often used sets of blocks under 'Function'.
Once you create functions, use 'Call Function' to use it as often as needed.", "ai_hints_title_1_1": "Goal of the game", "ai_hints_content_1_1": "Avoid asteroids and help me get to Earth", "ai_hints_detail_1_1": "Avoid asteroids and help me get to Earth", "ai_hints_title_1_2": "Instructions", "ai_hints_content_1_2": "How do I begin?", "ai_hints_detail_1_2": "1. Drag out blocks from the block box and connect is with the 'when run' block
2. Once finished assembling blocks, click 'Run'
3. I'll move according to your block instructions.", "ai_hints_title_1_3": "To move", "ai_hints_content_1_3": "How do I move the entrybot?", "ai_hints_detail_1_3": "I can move up, forward or below.
When creating instructions, make sure I avoid the asteroids.
If you send me out of the screen, I can be lost in space forever! So be careful.", "ai_hints_title_2_1": "Goal of the game", "ai_hints_content_2_1": "Use repeat blocks to avoid the asteroids.", "ai_hints_detail_2_1": "Use repeat blocks to avoid the asteroids.", "ai_hints_title_2_2": "Repeat block", "ai_hints_content_2_2": "What is a repeat block?", "ai_hints_detail_2_2": "Geez! It's a long way home so putting blocks together one by one is too tiresome. Let's try using the repeat block.
Once you group the blocks under the repeat block, you can shorten the length of the blocks!", "ai_hints_content_3_1": "Help me avoid the asteroids using the 'if' block", "ai_hints_title_3_2": "if block(1)", "ai_hints_content_3_2": "How does 'if ~' block work? ", "ai_hints_detail_3_2": "Using 'if~ in front/ else' block can help me check if there are asteroids in front of me and help me avoid them.
If there's an asteroid in front of me, then blocks under 'if' will execute or if there isn't an asteroid, the blocks under 'else' will execute.
Tell me which way to go depending on whether there's an asteroid to avoid or not.", "ai_hints_content_4_1": "Learn to use the radar to avoid the asteroids.", "ai_hints_detail_4_1": "Learn to use the radar to avoid the asteroids.", "ai_hints_title_4_2": "radar(1)", "ai_hints_content_4_2": "What is a radar and how can I use it?", "ai_hints_detail_4_2": "Radar tells me how far an object exists from where I am located.
If there is an object in front of me, the front radar will show '1'.
Also, radar can become a powerful tool when used with 'if <true>/else' block.
For example, when the distance to an object in front of me shows value greater than 1, then I am able to move forward safely.
However, if not, then I can go above or under to avoid it.", "ai_hints_title_4_3": "if block(2)", "ai_hints_content_4_3": "How do I use 'if ' block?", "ai_hints_detail_4_3": "if <true> block/ else' block executes blocks under 'if' when condition is met and executes blocks under 'else' when condition is not met.
Think about how you want to move at different situations and create a condition within <true> block.
Remember that when condition is met and blocks under 'if' are executed, then the blocks under 'else' will be ignored.", "ai_hints_content_5_1": "Use the radar to help me avoid the asteroids.", "ai_hints_detail_5_1": "Use the radar to help me avoid the asteroids.", "ai_hints_title_5_2": "if block(3)", "ai_hints_content_5_2": "How does nested if blocks work?", "ai_hints_detail_5_2": "I can nest 'if ~/else' block within 'if ~/else' block. This will help me make smart decisions in various situations.
For example, I can act according to whether an asteroid is in my path or not, then when I'm met with and asteroid, I can decide whether to go under or above.", "ai_hints_title_6_1": "Radar(2)", "ai_hints_content_6_1": "How do I compare the values given by radar above and radar below?", "ai_hints_detail_6_1": "([above]radar) block shows distance to an object above.
You can use this block to check which asteroid above or below exist further away.
When deciding which way to avoid the asteroid, it'll be a smarter move to go in the direction where the asteroid is further away.", "ai_hints_content_7_1": "Use the item to avoid the asteroids.", "ai_hints_detail_7_1": "Use the item to avoid the asteroids.", "ai_hints_title_7_2": "Checking object name", "ai_hints_content_7_2": "What can I do by checking the object name in front of me?", "ai_hints_detail_7_2": "To gain a special item, you need to check where the item is located.
Use 'object [above] is [item]' block.
By using this block, you can figure out where the item is located and move towards it.", "ai_hints_content_8_1": "Use the item to help me avoid the asteroids.", "ai_hints_detail_8_1": "Use the item to help me avoid the asteroids.", "ai_hints_title_8_2": "Item", "ai_hints_content_8_2": "How do I gain special item and use it?", "ai_hints_detail_8_2": "Even though you succeed in avoiding the asteroids, when the pathway is lined with asteroids, there is no way to avoid them. In this case, use the 'use item' block.
It will get rid of all blocks in front.
However, you can only use this block when you've gained the item by passing through the item.", "ai_hints_content_9_1": "Use all your skills and knowledge to go as far as you can.", "ai_hints_detail_9_1": "Use all your skills and knowledge to go as far as you can.", "ai_hints_title_9_2": "and", "ai_hints_content_9_2": "How do I use the 'and' block?", "ai_hints_detail_9_2": "and' block can fit in many conditions. When all conditions in the 'and' block is met, then the blocks will be executed. If one of them is false, the whole 'and' statement will be false and the blocks will not be executed.", "maze_text_goal_1": "Use move(); command to move me to the part box!", "maze_text_goal_2": "Use jump(); command to avoid obstacles.", "maze_text_goal_3": "Use left(); right(); command to take me to my parts.", "maze_text_goal_4": "Use various commands to take me to my parts.", "maze_text_goal_5": "Move me so I can collect both of my part boxes.", "maze_text_goal_6": "Move me so I can collect both of my part boxes.", "maze_text_goal_7": "Use for command to take me to my friend!", "maze_text_goal_8": "Use for command and avoid obstacles to take me to my friend!", "maze_text_goal_9": "Use while command to take me to my friend.", "maze_text_goal_10": "Use if and while commands to take me to all my friends.", "maze_text_goal_11": "Use if and while commands to take me to all my friends.", "maze_text_goal_12": "Use if and while commands to take me to all my friends.", "maze_text_goal_13": "Call function to take me to my battery", "maze_text_goal_14": "Call function to take me to my battery", "maze_text_goal_15": "Insert commands within function. Then call the function to take me to my battery", "maze_text_goal_16": "Insert commands under a function. Then call the function to move me to the battery!", "maze_text_goal_17": "Insert commands under a function. Then call the function to move me to the battery!", "maze_text_goal_18": "Insert commands under a function. Then call the function to move me to the battery!", "maze_text_goal_19": "Insert commands under a function. Then call the function to move me to the battery!", "maze_text_goal_20": "Call the function and mix it with other commands and take me to my battery.", "maze_attack_range": "Attack range", "maze_attack": "Attack", "maze_attack_both_sides": "Attack both sides", "above_radar": "above radar", "above_radar_text_mode": "radar_up", "bottom_radar": "bottom radar", "bottom_radar_text_mode": "radar_down", "front_radar": "front radar", "front_radar_text_mode": "radar_right", "above_object": "object above", "above_object_text_mode": "object_up", "front_object": "object in front", "front_object_text_mode": "object_right", "below_object": "object below", "below_object_text_mode": "object_down", "destination": "destination", "asteroids": "asteroids", "item": "item", "wall": "wall", "destination_text_mode": "destination", "asteroids_text_mode": "stone", "item_text_mode": "item", "wall_text_mode": "wall", "buy_now": "Buy now", "goals": "Goal", "instructions": "Instructions", "object_info": "Object info", "entry_basic_mission": "Entry basic mission", "entry_application_mission": "Entry application mission", "maze_move_forward": "move one forward", "maze_when_run": "khi chạy", "maze_turn_left": "turn left", "maze_turn_right": "turn right", "maze_repeat_times_1": "repeat", "maze_repeat_times_2": "times", "maze_repeat_until_1": "repeat until", "maze_repeat_until_2": "", "maze_call_function": "call function", "maze_function": "function", "maze_repeat_until_all_1": "repeat until all of", "maze_repeat_until_all_2": "", "command_guide": "Command guide", "ai_success_msg_1": "Thanks to you I've safely arrived home!", "ai_success_msg_2": "Phew! I was able to travel ", "ai_success_msg_3": "distance enough to send a rescue signal to Earth! The rescue crew is on its way! Thank you!", "ai_success_msg_4": "Great! You succeeded using ", "ai_cause_msg_1": "Oh no. Tell me which way to go.", "ai_cause_msg_2": "Yikes! That was close! Let's try again.", "ai_cause_msg_3": "Yikes! I might get lost in space if I go off the path. Let's try again.", "ai_cause_msg_4": "It's too complicated. Try this block to move.", "ai_move_forward": "move forward", "ai_move_above": "go above", "ai_move_under": "go under", "ai_repeat_until_dest": "repeat until destination", "ai_if_front_1": "if", "ai_if_front_2": "in front", "ai_else": "else", "ai_if_1": "if", "ai_if_2": "", "ai_use_item": "use item", "ai_radar": "radar", "ai_above": "above", "ai_front": "front", "ai_under": "under", "ai_object_is_1": "is", "ai_object_is_2": "object", "challengeMission": "back", "nextMission": "next", "withTeacher": "Advisory teachers", "host": "Host", "support": "Support", "subjectivity": "Subjectivity", "learnMore": "Learn more ", "ai_object_is_3": "?", "stage_is_not_available": "The stage isn't available yet. Please enter the stages in the given order.", "progress_not_saved": "Your progress will not be saved.", "want_refresh": "Do you still want to refresh the page?", "monthly_entry_grade": "Elementary 3rd - Middle school 3rd grade", "monthly_entry_contents": "Learn to program with Monthly Entry. This monthly digest provides project tutorials, tips and tricks and fun comics. ", "monthly_entry_etc1": "*The Monthly Entry project templates are provided in the main page's recommended course", "monthly_entry_etc2": "* Monthly Entry is published during school semesters only", "group_make_lecture_1": "There are no lessons to show.", "group_make_lecture_2": " Create lessons for your class from ", "group_make_lecture_3": "'Create > Create lessons'", "group_make_lecture_4": "Create a lessons", "group_add_lecture_1": "Favorite Lesson does not exist.", "group_add_lecture_2": "'학습하기>오픈 강의> 강의'에서 우리반 학습내용에", "group_add_lecture_3": "추가하고 싶은 강의를 관심강의로 등록해 주세요.", "group_add_lecture_4": "See Lesson", "group_make_course_1": "My courseware is not exist.", "group_make_course_2": "Create courseware for your class from", "group_make_course_3": "'Create > Create lessons > Create Courseware'", "group_make_course_4": "Create courseware", "group_add_course_1": "Favorite Courseware does not exist.", "group_add_course_2": "Favorite lessons you want to add as course assignment from", "group_add_course_3": "'Learn > Open Lessons > Courseware", "group_add_course_4": "Browse courseware", "hw_main_title": "Download Program", "datablock_contest_title": "Data Analysis Block", "datablock_content_head": "Process and Represent the Data", "datablock_content_body1": "Find meaning by charting various data in your life", "datablock_content_body2": "and solve real-life problems with it!", "campaign_contest_title": "Let's make a beautiful internet world", "campaign_content_head": "Entry Project Contest", "campaign_content_body1": "Create an originative project about 'internet ethics'", "campaign_content_body2": "and apply for the contest!", "campaign_content_button": "View details", "code_management_1": "Entry campaign #1 How to manage code", "code_management_2": "My Storage and Memo", "code_management_3": "Code management secret using my storage and memo!", "code_management_4": "Learn how to make your project better and share it easily.", "code_management_5": "View Campaigns", "shcoolbook_study_1": "Learn the contents of the textbook in entry.", "shcoolbook_study_2": "Learning Textbook", "shcoolbook_study_3": "Teachers can teach in the classroom", "shcoolbook_study_4": "and students can review at home!", "shcoolbook_study_5": "Learn now", "main_learn_1": "If you are new to Entry", "main_learn_2": "Learn about Entry", "main_learn_3": "Watch the video to learn about the various functions of Entry,", "main_learn_4": "create and share your project!", "main_learn_5": "Watch the video", "hw_desc_wrapper": "Install the Upgraded \nEntry Hardware Connection Program\nand Offline Editor", "hw_downolad_link": "Download Hardware Connection Program", "save_as_image_all": "Save code as image", "save_as_image": "Save as image", "maze_perfect_success": "Awesome! That is perfect!", "maze_success_many_block_1": "좋아", "maze_fail_obstacle_remain": "Get rid of all obstacles to keep your friends from getting hurt.", "maze_fail_item_remain": "Collect all the Minerals to save Princess Sally.", "maple_fail_item_remain": "I can't use my strength because I didn’t take all the food.
Help me to take all the food.", "maze_fail_not_found_destory_object": "Don't waste your power on an empty space!", "maze_fail_not_found_destory_monster": "Don't attack an empty space!", "maple_fail_not_found_destory_monster": "You should use the attack blocks only when there are monsters!", "maze_fail_more_move": "You have to move to the destination a little bit more!", "maze_fail_wall_crash": "Ow! You can't go there!", "maze_fail_contact_brick": "Ouch... you ran into something!", "maze_fail_contact_iron1": "Ow! I hit an obstacle", "maze_fail_contact_iron2": "Ow! I was hurt because an obstacle fell on me. Move before an obstacle falls down.", "maze_fail_fall_hole": "I fell into a trap...", "maze_fail_hit_unit": "몬스터에게 당해버렸어! 위험한 몬스터를 물리치기 위해 하트 날리기 블록을 사용해줘!", "maze_fail_hit_unit2": "Ow, I was attacked by a monster! You have to attack from two cells away!", "maze_fail_hit_unit_by_mushroom": "The Orange Mushroom got me!
Use the Attack block to defeat the bad monsters!", "maze_fail_hit_unit_by_lupin": "I got hit by Lupin!
Use the Attack block two spaces away to defeat the bad monster!", "maze_fail_elnath_fail": "Oww! A bad monster attacked me.
Defeat the bad monsters to keep them from reaching me!", "maze_fail_pepe": "", "maze_fail_yeti": "That monster is so strong that you can't defeat it with the Attack block.
Let's use the Attack block.", "maze_fail_peti": "If you use the Attack block to attack that monster, you can't defeat the strong monsters when they spawn.
Let's use the Attack block.", "maze_fail_both_side": "You should only use the Attack on both sides if there are monsters on both sides! ", "maze_wrong_attack_obstacle": "You can't use the Attack block here.
Let's use the Attack block for Orange Mushrooms.", "maze_fail_contact_spider": "You're caught on a cobweb and can't move...", "maze_success_perfect": "Awesome! That is perfect!", "maze_success_block_excess": "Great! You succeeded using %1 blocks!
But you can actually get there by only using %2 blocks! How about another go at it?", "maze_success_not_essential": "Great! You succeeded using %1 blocks!
But using this block makes it easier to solve. How about another go at it?", "maze_success_final_perfect_basic": "Okay, we found where Princess Sally is! Now you can save Princess Sally!", "maze_success_final_block_excess_basic": "Great! We found where Princess Sally is! Now you can save Princess Sally! You used %1 blocks, but you can actually succeed by only using %2 blocks! Wanna try again?", "maze_success_final_perfect_advanced": "You've reached the place where Princess Sally is! Now defeat the villain Mephisto and save Sally!", "maze_success_final_block_excess_advanced": "You've reached the place where Princess Sally is! Now defeat the villain Mephisto and save Sally! You used %1 blocks, but you can actually succeed by only using %2 blocks! Wanna try again?", "maze_success_final_distance": "Great! We finally saved Princess Sally safe and sound. Thank you so much for helping!
You moved %1 cells. Wanna try again and aim for 60 cells?", "maze_success_final_perfect_ai": "There you go! We finally saved Princess Sally safe and sound. Thank you so much for helping!", "maple_success_perfect": "Great! That was perfect!", "maple_success_block_excess": "Great! You’ve succeeded using %1 blocks!
But there is a way to succeed with %2 blocks. Why don’t you try again?", "maple_success_not_essential": "Great! You’ve succeeded using %1 blocks!
But using this block will make it easier. Why don't you try again?", "maple_success_final_perfect_henesys": "Awesome! You’ve completed the Henesys Adventure.", "maple_success_final_perfect_excess_henesys": "Awesome! You’ve completed the Henesys Adventure.
But there is a way to succeed with %2 blocks. Would you like to try again?", "maple_success_final_not_essential_henesys": "Awesome! You’ve completed the Henesys Adventure.
But using this block will make it easier. Would you like to try again?", "maple_success_final_perfect_ellinia": "Wow! That was a really fun adventure!
You're going to come back for another adventure, right?", "maple_success_final_perfect_excess_ellinia": "Wow! That was a really fun adventure!
But there is a way to succeed with %2 blocks. Would you like to try again?", "maple_success_final_not_essential_ellinia": "Wow! That was a really fun adventure!
But using this block will make it easier. Would you like to try again?", "maple_fail_fall_hole": "Oww! You’ve fallen down!
Let's skip using the Jump block.", "maple_fail_ladder_fall_hole": "Oww! You’ve fallen down!
Let's go the other way using the Climb ladder block.", "maple_fail_more_move": "To succeed, we have to move a little bit further to the destination!", "maple_fail_not_found_ladder": "Oh, there's no ladder to climb here.
You should only use the Climb ladder block where there is a ladder.", "maple_fail_not_found_meat": "Oh, there's no food to take here.
You should only use Take food block where there is food.", "maple_cert_input_title": "What name do you want in the certificate?", "maze_distance1": "distance 1", "maze_distance2": "distance 2", "maze_distance3": "distance 3", "ev3": "EV3", "roborobo_roduino": "Roduino", "roborobo_schoolkit": "School Kit", "smartboard": "Sciencebox Codingboard", "smartboardbt": "Sciencebox Codingboard(Bluetooth)", "codestar": "Codestar", "cobl": "Cobl", "cobl_bt": "Cobl BT", "block_coding": "Block Coding", "python_coding": "Entry Python", "dadublock": "DaduBlock", "dadublock_car": "DaduBlock Car", "blacksmith": "Blacksmith Board", "course_submit_homework": "Submit", "course_done_study": "Complete", "course_show_list": "List", "modi": "MODI", "chocopi": "ChocoPi", "coconut": "coconut", "jdkit": "JDKit", "practical_course": "Textbook", "entry_user_policy": "Entry usage policy", "entry_scholarship_title": "Entry scholarly data", "entry_scholarship_content": "Entry collaborates with researchers to strengthen learning effectiveness. Check out our data.", "entry_scholarship_content_sub": "*We provide data which is saved in the form of a sequence of processes by users participating in the Online coding party to assist in study and analysis.", "entry_scholarship_download": "Data download", "codingparty_2016_title": "2016 Online coding party", "codingparty_2016_content": "We provide user's active log, who played a coding mission, with whether he/she has succeeded or not, and user age, gender", "codingparty_2017_title": "2017 Online coding party", "scholarship_go_mission": "Coding mission", "scholarship_guide": "Guide", "scholarship_see_guide": "Guide", "scholarship_guide_desc": "It's a guide for how to read and use data.", "scholarship_example": "Example", "scholarship_example_desc": "Check out our paper by using scholarly data.", "scholarship_see_example": "Download", "altino": "Altino", "private_project": "This is a private project", "learn_programming_entry_mission": "Solving missions with EntryBot", "learn_programming_line_mission": "Saving Sally with LINE Rangers", "learn_programming_choseok": "Making a game with Cho Seok, author of \"The Sound of Your Heart\"", "learn_programming_maple": "Going to the Maple World with \"PINK BEAN\"", "learn_programming_level_novice": "easy", "learn_programming_level_inter": "normal", "learn_programming_level_advanced": "hard", "line_look_for": "Finding Sally", "line_rangers_title_string": "Learning: Line Rangers", "online_codingparty_certificate_string": "Online coding party", "online_codingparty_line_title_string": "Line Rangers", "line_look_for_desc_1": "Combine the power of the LINE Rangers and defeat the powerful villain Mephisto and save Sally!", "line_save": "Saving Sally", "line_save_desc_1": "Sally is trapped at Mephisto's base. Help the LINE Rangers get to Sally by avoiding obstacles!", "line_escape": "Escaping with Sally", "line_escape_desc_1": "Help Sally and LINE Rangers escape safely from the exploding Mephisto base!", "solve_choseok": "rock-paper-scissors", "solve_choseok_desc_1": "Help Cho Seok create a rock-paper-scissors game!", "solve_henesys": "HENESYS", "solve_ellinia": "ELLINIA", "solve_elnath": "ELNATH", "solve_henesys_desc_1": "Venture into the town, and help PINK BEAN to have enough food!", "solve_ellinia_desc_1": "Venture into the forest, and fight against the bad monsters to save the good monsters!", "solve_elnath_desc_1": "Passing through the snow mountain occupied by bad monsters, go find another portal to start a new adventure!", "save_modified_shape": "Do you want to save the modified shape?", "save_modified_table": "Do you want to save the modified table?", "attach_file": "File", "enter_discuss_title": "Please enter the title(in 40 characters or less)", "enter_discuss_title_alert": "Please enter the title", "discuss_upload_warn": "You can only upload less than 10MB in file size", "discuss_list": "list", "discuss_write_notice": "Select this post as a notice and show it first.", "discuss_write_notice_open": "Select this post as a notice and show it first.", "search_전체": "All", "search_게임": "Game", "search_애니메이션": "Animation", "search_미디어아트": "Media Art", "search_피지컬": "Physical", "search_기타": "ETC", "discuss_write_textarea_placeholer": "Entry community is a space we make together.\nLet's make a fun community with consideration for each other.", "discuss_write_textarea_placeholer_qna": "This community is for Q&A.\nLet's make a fun community with consideration for each other!", "discuss_write_textarea_placeholer_tips": "This community is for Tips&Tricks.\nLet's make a fun community with consideration for each other!", "discuss_write_textarea_placeholer_free": "This community is for Discussion.\nLet's make a fun community with consideration for each other!", "discuss_write_textarea_placeholer_report": "This community is for Suggestions.\nLet's make a fun community with consideration for each other!", "discuss_write_textarea_placeholer_contest2019": "※ 아래 양식으로 작성하여 제출해주세요.\n\n1. 학년 (예: 초등학교 5학년)\n\n2. 작품 URL (‘공유하기 > 작품 공유하기’에 작품을 공유한 다음, 작품 URL을 복사하여 적어주세요.)\n\n3. 작품 설명\n\n※ 공모전 수상자에게는 이메일이 발송될 예정입니다.\n엔트리의 ‘내 정보 수정‘에 이메일 정보를 꼭 입력해주세요!", "maze_road": "road", "account_deletion": "Account deletion", "bug_report_too_many_request": "Your report is being sent. Please try again later.", "pinkbean_index_title": "Let’s head to the exciting Maple World with Pink Bean!", "pinkbean_index_content": "Pink Bean, who couldn’t stand boredom, has ventured into Maple World.
Explore the exciting Maple World with Pink Bean and fill the adventure journal.
You can learn the software while passing through each step, and you can get a certificate after you complete the mission.", "rangers_index_title": "Saving Sally with LINE Rangers!", "rangers_index_content": "LINE Rangers are combined to defeat the powerful villain Mephisto and save Sally.
Be the hero by avoiding obstacles and saving Sally through the principle of software.
You can learn about software passing through each steps and get the licence
after finishing the mission.", "rangers_replay_button": "Replay", "rangers_start_button": "Start", "lms_curriculum_intro": "", "lms_curriculum_goal": "", "lms_curriculum_prepare": "", "lms_curriculum_study": "", "lms_curriculum_summary": "", "lms_curriculum_quiz": "", "lms_curriculum_now_stage": "", "bug_report_title": "Bug Report", "bug_report_content": "Please tell us about errors or good suggestions that you find when you use Entry.", "object_import_syntax_error": "Since the object has syntax error blocks, it cannot be loaded. Please convert into block mode to load the object.", "choseok_top_wrapper_panel_title": "조석과 함께 가위바위보 게임을 만들어보세요!", "choseok_top_wrapper_panel_des": "마음의 소리 웹툰이 코딩파티 미션으로 탄생했습니다.
만화속 조석이 (가위바위보 게임)을 만들어가는 과정에 참여하여 미션에
도전해 보세요.
각 단계를 통과하면서 자연스럽게 소프트웨어를 배워볼 수 있고, 미션을 모두 마치면
인증서와 나만의 게임을 얻을 수 있습니다.
", "choseok_mission_statement1": "조석을 움직여보자", "choseok_mission_statement2": "가위바위보를 시작해보자", "choseok_mission_statement3": "가위바위보 승부를 가려보자", "choseok_mission_statement4": "가위바위보 게임을 완성해보자", "choseok_mission_statement5": "자유롭게 만들어보자", "choseok_mission_statement_top1": "미션 1 : 조석을 움직이기", "choseok_mission_statement_top2": "미션 2 : 가위바위보를 시작하기", "choseok_mission_statement_top3": "미션 3 : 가위바위보 승패 만들기", "choseok_mission_statement_top4": "미션 4 : 가위바위보 결과 보여주기", "choseok_mission_statement_top5": "미션 5 : 자유롭게 만들어보기", "advisory_title": "Entry Advisory Group", "advisory_sub_title": "This is an advisory group including teachers and students who make Entry together.", "data_table_column": "column", "data_table_row": "row", "data_table_provider": "provider", "data_table_modifidate": "modify", "draw_new_table_ques_1": "You can enter data and save to table.", "draw_new_table_ques_2": "Do you want to move to enter data?" }; Lang.Msgs = { "microbit_led_erase_all": "Reset", "loading_plz_wait": "Now Loading. Please Wait", "ai_utilize_audio_listening": "Listening", "upload_error_title": "File rejected", "upload_error_content": "Files not complying with the entry usage policy are excluded", "monthly_intro_0": "Monthly entry is an SW training magazine designed to help teachers who are unfamiliar with SW.", "monthly_intro_1": "Meet the Learning contents with fun learning cartoon!", "monthly_title_0": "Taking a dog walk / Drawing diagram", "monthly_title_1": "Create a video / Music player", "monthly_title_2": "South Korea map puzzle / Cosmos animation", "monthly_title_3": "Following fishes / Planets", "monthly_title_4": "Harvesting potatoes / Strawberry milk", "monthly_description_0": "Let's make the dog that moved by your keyboard, and paint drawing project using signal and coordinate.", "monthly_description_1": "Let's make the photo-movie project and music player using variable.", "monthly_description_2": "Let's make the puzzle game that made of 'while' statement, and animation project using clone and random.", "monthly_description_3": "Let's make fish-art and solar system using loop, math calculation blocks.", "monthly_description_4": "Let's make the potato-digging and strawberry milk project using signal, variable and math calculation blocks.", "save_canvas_alert": "Currently saving.", "feedback_too_many_post": "Message sending. Please try after 10 seconds.", "feedback_duplicated": "It is already reported.", "usable_object": "Usable Object", "shared_varaible": "Shared Variable", "invalid_url": "Video URL is invalid.", "auth_only": "Authenticated users only", "runtime_error": "lỗi thực hiện", "to_be_continue": "Still not working", "warn": "cảnh báo", "error_occured": "Oops, something went wrong. Why don't you try again? If you see this more than once, please let us know by Proposal board!", "error_forbidden": "Can not save because you are not signed in.\nPlease make sure if you haven’t signed out in another tab.\nIf you still can not save after sign in, please leave a message via ‘Suggestion’.", "list_can_not_space": "tên danh sách không thể để trống", "sign_can_not_space": "tên tín hiệu không thể để trống", "variable_can_not_space": "Variable's name can't be space", "training_top_title": "Programs", "training_top_desc": "Introducing Professional Development Programs", "training_main_title01": "Instructors for your Professional Development Seminar", "training_target01": "For l Teachers", "training_sub_title01": "“Give a Boost to your Classroom”", "training_desc01": "Are you looking for instructors to train your teachers?\nWe will match you with excellent instructors with knowledge and experience.", "training_etc_ment01": "* Seminar are hosted and paid for by the requesting schools", "training_main_title02": "Teacher Development Program for Lead Schools", "training_target02": "For l Lead and Research Schools", "training_sub_title02": "“Go, Share, and Connect”", "training_desc02": "We randomly select schools from the Lead and Research schools and provide Development Seminars for free.\nSeminars are taught by Go-to-Teacher Program teachers.", "training_etc_ment02": "", "training_main_title03": "Experienced Instructors for Parent and Student seminars", "training_target03": "For l Parents, Students", "training_sub_title03": "“Time to Explore Software Education”", "training_desc03": "Need instructors to introduce coding to parents and students?\nWe will match you with our instructors with knowledge and experience. ", "training_etc_ment03": "* Seminar are hosted and paid for by the requesting schools", "training_apply": "Apply", "training_ready": "Ready", "new_version_title": "Install the latest version", "new_version_text1": "Current Hardware Connection Program", "new_version_text2": "is not the most updated version.", "new_version_text3": "Please install the latest version.", "new_version_text4": "", "new_version_download": "Download", "not_install_title": "Uninstalled", "hw_download_text1": "Install to connect hardware.", "hw_download_text2": "", "hw_download_text3": "Hardware Connector Program is not installed.", "hw_download_text4": "Please install the latest version.", "hw_download_btn": "Download", "not_support_browser": "Your browser is not supported.", "quiz_complete1": "Quiz is finished", "quiz_complete2": "You've got {1} correct out of {0} problems", "quiz_incorrect": "Let's think again", "quiz_correct": "That's the answer", "hw_connection_success": "Hardware connection success", "hw_connection_success_desc": "Double click the hardware icon to check sensor values", "hw_connection_success_desc2": "Hardware connection is successful", "hw_connection_termination_title": "Disconnected", "hw_connection_termination_desc": "The device has been disconnected.", "hw_connection_failed_title": "Connection Failed", "hw_connection_failed_desc": "Please make sure that\nthe device used in the project is connected.", "ie_page_title": "This browser is not supported", "ie_page_desc": "Entry is available in Internet Explorer 10 or higher or in Chrome browser.
Please update the Windows or install a Chrome browser.
Offline versions are available even though the internet is not connected. Get download now!", "ie_page_chrome_download": "Chrome
download", "ie_page_windows_update": "Windows
update", "ie_page_offline_32bit_download": "Windows 32bit
download", "ie_page_offline_64bit_download": "Windows 64bit
download", "ie_page_offline_mac_download": "Mac
download", "cancel_deletion_your_account": "Do you want to cancel the deletion of your account?", "account_deletion_canceled_complete": "Account deletion has been canceled.", "journal_henesys_no1_title": "Henesys Adventure Journal No. 1", "journal_henesys_no2_title": "Henesys Adventure Journal No. 2", "journal_henesys_no1_content": "This is the first journal for Henesys. Today, I almost fell trying to jump on the way to the blacksmith’s house. He’s important in Henesys. Why did he make such a big hole in front of his yard? I don't think there’s anyone who can jump through these holes unless it's a great monster like me! let’s go to that restaurant. It’s supposed to be good!", "journal_henesys_no2_content": "I really did eat too much. The meat in that restaurant was really delicious. How could it be so tender? But the bread next door wasn’t great. The chef seemed to be always playing around, saying he’s “learning how to cook better.” He should use that time to get some more practice. Now that I’ve filled my belly, time to start a full-scale adventure!", "journal_ellinia_no1_title": "Ellinia Adventure Journal No. 1", "journal_ellinia_no2_title": "Ellinia Adventure Journal No. 2", "journal_ellinia_no1_content": "Phew, I sat on an Orange Mushroom without even knowing. I guess that’s a good reason to get mad... But piling on me was too much! They’re a scary bunch. No wonder the slimes had a hard time. No need to worry, though! Yours truly took care of it! Now that the slimes are my friends, I’m gonna continue the adventure into this gorgeous forest.", "journal_ellinia_no2_content": "My adventurous friend, Royal Fairy, told me there are some scary rumors going on around Elnath. I wonder what that is? I’m supposed to play with my friends at home tonight, so I’ll ask then. I can’t wait! But what should I wear ... I don’t think anything is going to fit because I got bigger... Well, I’m always cute, so no matter what I wear, everyone will love it!", "journal_elnath_no1_title": "Elnath Adventure Journal No. 1", "journal_elnath_no2_title": "Elnath Adventure Journal No. 2", "journal_elnath_no1_content": "Oh, my gosh! So this is \"snow\" I heard so much about, huh? It's always spring where I live, so this is my first snow. I wasn't paying much attention because I was busy fighting the monsters, but now I see the whole world is so white and cold! I thought it’d be tasty, but it's flavorless. I wish I can bring some back, but there's no way. Oh, too bad.", "journal_elnath_no2_content": "Eww, I accidentally ate coal dust! Those bad monsters! Least they could do is run away quietly, but they just had to spread coal all over. Thanks to them, my shiny, fluffy pink skin is getting dirtier. I need to get out of here and take a clean bath. Adventure is nice, but no self-respecting monster should walk around looking this dirty.", "bug_report_alert_msg": "Thank you for the report.", "version_update_msg1": "You can use the latest Entry Offline version(%1).", "version_update_msg2": "You can use the latest Entry Hardware version(%1).", "version_update_msg3": "Do you want to update now?", "select_the_hardware": "Select the hardware
that you would use in the lesson.", "select_hardware_button": "Select", "select_the_expansion_block": "Select the expansion block that you would use in the lesson.", "select_hardware_not_support_info": "Hardware blocks are not available for open classes.", "select_hardware_not_support_info2": "Please wait a little bit.", "select_expansion_block_button": "Select", "expansion_weather_description": "It is a collection of blocks related to weather in Korea such as temperature, precipitation, and fine dust concentration.", "expansion_festival_description": "It is a collection of blocks related to various events and festivals by local area.", "expansion_translate_description": "It is a collection of blocks that can translate into other languages using the Papago.", "expansion_behaviorConductDisaster_description": "It is a collection of blocks about behavior-guidelines that the public should follow when natural disasters occur. (Provided by MPSS)", "expansion_behaviorConductLifeSafety_description": "It is a collection of blocks about basic behavior-guidelines that the public should follow for safty in life. (Provided by MPSS)", "ai_utilize_tts_description": "It is a collection of blocks that can read text in a variety of voice using the Clova.", "hardware_need_update_title": "Entry HW update", "hardware_need_update_content": "Please update to the latest version,\nif you are using below version.\nEntry website only supported v1.9.0 or later.\nPlease remove the web browser cache,\nif any block doesn't appear after updating.", "ai_utilize_audio_description": "It is a collection of blocks related to speech to text functionalities.", "ai_utilize_video_description": "It is a collection of blocks that can recognize movement, direction and object to be shot by using camera." }; Lang.Users = { "auth_failed": "Authentication failed", "birth_year": "Birth Year", "birth_year_before_1990": "Before 1990s", "edit_personal": "Chỉnh sửa cá nhân", "email": "Email", "email_desc": "Enter your Email address to receive newsletters", "email_inuse": "E-mail address is already in-use", "email_match": "Please enter a valid email", "forgot_password": "Forgot your password?", "job": "Job", "language": "Language", "name": "Full Name", "name_desc": "Enter your name", "name_not_empty": "You must enter your name", "password": "Password", "password_desc": "", "password_invalid": "Invalid Password", "password_long": "Password must be between 4-20 characters long", "password_required": "Password can not be blank", "project_list": "Danh sách dự án", "regist": "Signup Complete", "rememberme": "Remember me", "repeat_password": "Repeat Password", "repeat_password_desc": "Repeat Password", "repeat_password_not_match": "Passwords do not match", "sex": "Sex", "signup_required_for_save": "Signin required for saving a project.", "username": "Username", "username_desc": "Enter your unique name for signin", "username_inuse": "Username already taken", "username_long": "Username must be between 4-20 characters long", "username_unknown": "Unknown user", "already_verified": "Already verified", "email_address_unavailable": "The email address is unavailable.", "email_address_invalid_for_idpw": "The email address is not available.\n Please try 'Find ID or Password' again to resend. ", "email_address_invalid_for_certification": "The email address is not available.\n Please verify your email again.", "verification_complete": "Verification has been completed.", "reset_password_mail_sent": "Email for password resetting has been sent. Please check your email.", "email_not_verified": "This email is not verified. Please verify your email to click 'Verifying email' first.", "verification_email_send_complete": "Verifying email has been sent. Please verify your email first.", "email_send_failed": "Sending email was failed. Please try again.", "email_not_exist": "This email does not exist.", "not_valid_email": "Please enter a correct type of email." }; Lang.Workspace = { "picture_rotation": "xoay vòng", "picture_size": "kích cỡ", "thickness": "độ dày", "follow": "Follow", "SaveWithPicture": "You have a unsaved drawing. Do you want to save it?", "RecursiveCallWarningTitle": "Limitation of function call", "RecursiveCallWarningContent": "Too many functions were called at once. Please reduce the function calls.", "SelectShape": "chuyển động", "SelectCut": "đoạn bỏ", "Pencil": "Cây bút", "Line": "Hàng", "Rectangle": "Hình chữ nhật", "Ellipse": "hình bầu dục", "Text": "Hộp văn bản", "Fill": "Lấp đầy", "Eraser": "Cục tẩy", "Magnifier": "kiếng hiển vi", "block_helper": "Khối giúp đỡ", "new_project": "New Project", "add_object": "thêm đối tượng", "download_image_name": "entry block", "all": "Tất cả", "animal": "Animal", "arduino_entry": "Program for connect to Arduino", "arduino_program": "Arduino program", "arduino_sample": "Sample code for Arduino", "arduino_driver": "Driver for arduino", "cannot_add_object": "Cannot add objects while running a project.", "cannot_add_picture": "Cannot add picture while running a project.", "cannot_add_sound": "Cannot add sound while running a project.", "cannot_add_expansion_block": "Cannot add expansion block while running a project.", "add_object_before_edit": "Add object firstly,
to edit the shape.", "add_table_before_edit": "Add table.", "cannot_edit_click_to_stop": "không thể sửa đổi đề án.
Nhấn n để dừng lại", "cannot_open_private_project": "Can not load private project. Move to home.", "cannot_save_running_project": "Can not save while running a project.", "character_gen": "Make an avarta", "check_runtime_error": "vui lòng kiểm tra khối được đánh dấu màu đỏ", "check_browser_error": "This block is not compatible to IE/Safari", "check_microphone_error": "There is no microphone connected to the computer", "check_webcam_error": "There is no camera connected to the computer", "context_download": "tải về máy tính", "context_duplicate": "lặp lại", "context_remove": "loại bỏ", "context_rename": "đổi tên", "coordinate": "Coord", "create_function": "Create Function", "direction": "hướng(°)", "drawing": "Paint", "enter_list_name": "", "enter_name": "Enter a new name", "enter_new_message": "Enter new message name.", "enter_variable_name": "Enter the new variable name (less than 10)", "family": "Family", "fantasy": "Fantasy/etc", "file_new": "Dự án mới", "file_open": "Dự án mở", "file_upload": "Tải lên dự án của tôi", "file_upload_login_check_msg": "bạn cần phải đăng nhập để tải dự án", "file_save": "Lưu", "file_save_as": "Lưu bản sao", "file_save_download": "Tải dự án về", "func": "Function", "function_create": "thêm chức năng", "function_add": "thêm chức năng", "interface": "Interface", "landscape": "Landscape", "list": "danh sách", "list_add_calcel": "", "list_add_calcel_msg": "", "list_add_fail": "", "list_add_fail_msg1": "", "list_add_fail_msg2": "", "list_add_ok": "", "list_add_ok_msg": "", "list_create": "thêm danh sách", "list_create_placeholder": "Input the name of the list.", "list_dup": "", "list_newname": "New name", "list_export": "Export", "list_import": "Import", "list_remove": "Remove list", "list_rename": "đổi tên danh sách", "list_rename_failed": "", "list_rename_ok": "", "list_too_long": "", "message": "tín hiệu", "message_add_cancel": "Canceled", "message_add_cancel_msg": "Add a message was canceled.", "message_add_fail": "Failed", "message_add_fail_msg": "Message name conflicted.", "message_add_ok": "Message added", "message_add_ok_msg": "was successfully added.", "message_create": "thêm tín hiệu", "message_create_placeholder": "Input the name of the signal", "message_dup": "tên thư đã tồn tại", "message_remove": "Remove a message", "message_remove_canceled": "Remove a message was canceled", "message_rename": "đổi tên thư ", "message_rename_failed": "đổi tên thư thất bại", "message_rename_ok": "đổi tên thư thành công", "message_too_long": "tên thư quá dài", "no_message_to_remove": "There is no message to remove.", "no_use": "không sử dụng", "no_variable_to_remove": "", "no_variable_to_rename": "There is no varibale to remove", "object_not_found": "không có đối tượng được quy định trong khối", "object_not_found_for_paste": "không có đối tượng để dán", "people": "People", "picture_add": "thêm hình dạng", "table_add": "Add Table", "draw_new_table": "New Table", "plant": "Plant", "project": "Project", "project_copied": "Copy", "PROJECTDEFAULTNAME": ['Cool', 'Funny', 'Nice', 'Huge', 'Great', 'Handsome', 'Lucky'], "remove_object": "xóa đối tượng", "remove_object_msg": "xóa hoàn thành thành công", "removed_msg": "was successfully removed", "rotate_method": "xoay vòng", "rotation": "Vòng xoay(°)", "run": "bắt đầu", "saved": "Saved", "saved_msg": "was successfully saved.", "save_failed": "Problem occurred while saving a project. Please try again.", "select_library": "Select Object", "select_sprite": "Please select at least one sprite to apply.", "shape_remove_fail": "xoá hình dạng thất bại", "shape_remove_fail_msg": "phải có ít nhất 1 hoặc vài hình dạng tồn tại", "shape_remove_ok": "xóa hình dạng", "shape_remove_ok_msg": "đã được xóa", "load_expansion_block": "Load Expansion Block", "load_ai_utilize_block": "Load AI Block", "load_ai_utilize_train_block": "Train Model", "select_expansion_block": "Select block", "deselect_expansion_block_warning": "The selected block cannot be deleted. \nThe specified block is currently in use.", "deselect_ai_utilize_block_warning": "The selected block cannot be deleted. \nThe specified block is currently in use.", "sound_add": "thêm âm thanh", "sound_remove_fail": "xóa âm thanh thất bại", "sound_remove_ok": "âm thanh được xóa", "sound_remove_ok_msg": "đã được xóa", "stop": "dừng lại", "pause": "tạm ngừng", "restart": "khởi động lại", "speed": "tốc độ", "tab_attribute": "thuộc tính", "tab_table": "Table", "tab_code": "khối", "tab_picture": "hình dạng", "tab_sound": "âm thanh", "tab_text": "hộp văn bản", "textbox": "Textbox", "textbox_edit": "Edit Textbox", "textbox_input": "Please input text for apply.", "things": "Things", "textcoding_tooltip1": "Instructions for 'Entry Python'
is available. Check out !", "textcoding_tooltip2": "Code with blocks or by Python
whichever you prefer.", "textcoding_tooltip3": "See Python code execution results.", "upload": "Upload files", "upload_addfile": "Add a file", "variable": "biến số", "variable_add_calcel": "Canceled", "variable_add_calcel_msg": "Add a variable was canceled.", "variable_add_fail": "Failed", "variable_add_fail_msg1": "Variable name conflicted.", "variable_add_fail_msg2": "Variable name is not proper.", "variable_add_ok": "Variable added", "variable_add_ok_msg": "was successfully added.", "variable_create": "thêm biến số", "variable_add": "thêm biến số", "variable_dup": "tên biến số đã tồn tại", "variable_newname": "New Name", "variable_remove": "Remove variable", "variable_remove_canceled": "Remove a variable was canceled", "variable_rename": "đổi tên biến số", "variable_rename_failed": "thất bại", "variable_rename_msg": "'Rename variable was successfully completed.'", "variable_rename_ok": "đổi tên biến số thành công", "variable_select": "Select a variable", "variable_too_long": "tên biến số quá dài", "open_analizy_data_import": "Open Data Import", "vehicle": "Vehicles", "add_object_alert_msg": "thêm đối tượng thứ nhất", "add_object_alert": "cảnh báo", "create_variable_block": "Create variable", "create_list_block": "tạo danh sách", "Variable_Timer": "bộ đếm thời gian", "Variable_placeholder_name": "tên biến số", "Message_placeholder_name": "Signal name", "Variable_property": "Attribute of the variable", "Variable_placeholder_content": "Input the name of the variable.", "Variable_use_all_objects": "sử dụng cho tất cả các đối tượng", "Variable_use_this_object": "sử dụng cho đối tượng này", "Variable_used_at_all_objects": "biến số được sử dụng trên tất cả các đối tượng", "variable_create_normal": "Use for variable\n(Stored in Project)", "variable_create_cloud": "Cần biến số chia sẻ. \n(Đã được lưu trên máy chủ)", "variable_create_real_time": "Use for real-time variable\n(Stored in Server)", "Variable_used_at_special_object": "biến số được sử dụng trên đối tượng đặc biệt", "Variable_used_objects": "Object used for the variable", "draw_new": "Draw new", "draw_new_ebs": "Draw new", "painter_file": "tập tin▼", "painter_file_save": "lưu", "painter_file_saveas": "lưu thành hình ảnh mới", "new_picture": "hình ảnh mới", "painter_edit": "biên soạn▼", "get_file": "nhận được", "copy_file": "sao chép", "cut_picture": "cắt", "paste_picture": "dán", "remove_all": "xoá tất cả", "flip_horizontal": "flip horizontal", "flip_vertical": "flip vertical", "regular": "Regular", "bold": "Bold", "font_underline": "underline", "font_tilt": "tilt", "font_cancel": "cancel", "font_color": "font color", "font_fill": "Fill", "font_family": "font", "align_left": "left align ", "align_center": "center align", "align_right": "right align", "italic": "Italic", "textStyle": "chữ", "add_picture": "Add Shape", "select_picture": "Select Library", "select_table": "Select Table", "select_sound": "Select sound", "Size": "kích cỡ", "show_variable": "hiển thị các biến ", "default_value": "Mặc định", "slide": "slide", "min_value": "giá trị nhỏ nhất", "max_value": "giá trị lớn nhất", "number_of_list": "số lượng hạng mục trong danh sách", "empty_of_list": "No items added.", "use_all_objects": "sử dụng cho tất cả các đối tượng", "list_name": "tên danh sách", "list_property": "Attribute of the list", "list_used_specific_objects": "danh sách được sử dụng cho đối tượng đặc biệt", "List_used_all_objects": "danh sách được sử dụng cho tất cả các đối tượng", "List_used_objects": "Object used for the list", "Scene_delete_error": "cảnh tượng phải có ít nhất 1 cái", "Scene_add_error": "cảnh lên đến 10", "replica_of_object": "bản sao của", "will_you_delete_scene": "Nếu xóa cảnh sẽ không phục hồi được. Bạn có chắc chắn muốn xóa cảnh?", "will_you_delete_function": "Deleting function can not be restored.\nAre you sure you want to delete function?", "duplicate_scene": "lặp lại", "block_explain": "Block description ", "block_intro": "Clicking on the block comes the description of the block . ", "blocks_reference": "Khối tài liệu tham khảo", "hardware_guide": "Hướng dẫn phần cứng", "robot_guide": "Robot Guide", "python_guide": "Entry Python Guide", "show_list_workspace": "hiển thị danh sách", "list_create_normal": "Use for list\n(Stored in Project)", "list_create_cloud": "sử dụng cho danh sách chia sẻ \n(được lưu trữ trong máy chủ)", "list_create_real_time": "Use for real-time list\n(Stored in Server)", "confirm_quit": "You didn't saved your changes.", "confirm_load_temporary": "Bạn chưa lưu dự án. Bạn có muốn mở không?", "login_to_save": "Try to save after login.", "cannot_save_in_edit_func": "Can not save while editing function.", "new_object": "New Object", "arduino_connect": "", "arduino_connect_success": "", "confirm_load_header": "Dự án khôi phục", "uploading_msg": "đang tải lên", "upload_fail_msg": "tải lên thất bại. Vui lòng thử lại", "upload_not_supported_msg": "Not supported file type.", "upload_not_supported_file_msg": "Not supported file type.", "file_converting_msg": "​File converting in process", "file_converting_fail_msg": "​File conversion has failed", "fail_contact_msg": "If the problem persists,
contact entry@connect.or.kr", "saving_msg": "Saving", "saving_fail_msg": "Save failed. Please try again.", "loading_msg": "Loading", "loading_fail_msg": "Load failed. Please try again.", "restore_project_msg": "Project is not saved properly. Would you like to restore this project?", "quit_stop_msg": "Program cannot be closed during save.", "ent_drag_and_drop": "Drag and drop the file to upload", "not_supported_file_msg": "This file format is not supported", "broken_file_msg": "File is corrupt or wrong file is loaded", "check_audio_msg": "Not supported file type.", "check_entry_file_msg": "Only ENT files are loadable", "hardware_version_alert_text": "Please update your hardware connector to the latest version.", "variable_name_auto_edited_title": "variable name auto-edited", "variable_name_auto_edited_content": "variable name cannot exceed 10 characters", "list_name_auto_edited_title": "list name auto-edited", "list_name_auto_edited_content": "list name cannot exceed 10 characters", "cloned_scene": "Cloned_", "default_mode": "Standard", "practical_course_mode": "Textbook", "practical_course": "practical course", "select_mode": "Mode", "select_mode_popup_title": "Choose 'Create' option", "select_mode_popup_lable1": "Standard", "select_mode_popup_lable2": "Textbook(Practical Course)", "select_mode_popup_desc1": "Create projects with
unlimited Entry features", "select_mode_popup_desc2": "Create projects using
'Practical Course' features", "practical_course_notice": "Notice", "practical_course_desc": "교과용 만들기
실과 교과서로 소프트웨어를 배울 때
필요한 기능만을 제공합니다.", "practical_course_desc2": "*기본형 작품 만들기를 이용하면 더 많은 기능을
이용해 작품을 만들 수 있습니다.", "practical_course_tooltip": "모든 기능을 이용하기 위해서는
기본형을 선택해 주세요.", "name_already_exists": "The name already exists.", "enter_the_name": "Please enter the name.", "object_not_exist_error": "Object does not exist. Please add object and try again.", "workspace_tutorial_popup_desc": "작품 만들기
창의적인 작품을 만들 수 있도록
다양한 블록과 기능을 제공합니다.", "start_guide_tutorial": "Creating Guide", "language": "language", "file": "file", "save": "save", "help": "help", "print": "print", "undo": "undo", "redo": "redo", "workspace_title_tooltip": "The default project name has changed. You can\nrecognize what project is through the date you create in\nthe project name.", "workspace_object_tooltip": "You can change the order of the object by\ndragging the image of the object. (It is the same\nin the ‘Shape’ and ‘Sound’ sections.)", "workspace_comment_tooltip": "You can hide or show all the memos\nadded.", "workspace_zoom_tooltip": "You can zoom in/out the blocks. If you click ‘=’\nthe block will be back to original size.", "workspace_image_tooltip": "Create your own\nproject with new\nfunctions!", "playground_block_drop": "Add the blocks in my storage\nto assembly station", "container_object_drop": "Add the object in my storage\nto object list", "my_storage_block_drop": "Add\nthe blocks\nto my storage", "my_storage_object_drop": "Add\nthe object\nto my storage", "my_storage": "my storage", "my_block": "My Block", "red": "Red", "green": "Green", "blue": "Blue", "hue": "Hue", "saturation": "Saturation", "brightness": "Brightness", "spoid": "Spoid", "palette_mode": "Palette mode", "slider_mode": "Slider mode", "toast_error_title_object_center": "Caution", "toast_error_contents_object_center": "If the center point is far from the object and goes out of the canvas, it returns to its original position.", "blocks_comming_soon": "I'm working hard.\nPlease wait a little longer!", "data_table": "table", "select_all": "모두", "now_loading_msg": "Now Loading.\nPlease Wait." }; Lang.code = "view code"; Lang.EntryStatic = { "event100": "Event", "groupProject": "open group", "usage_parallel": "Parallel", "usage_expansion": "Expansion", "usage_hw": "Hardware", "usage_sequence": "Sequence", "privateProject": "only owner", "privateCurriculum": "only owner", "publicCurriculum": "curriculum share", "publicProject": "project share", "group": "open group", "groupCurriculum": "open group", "private": "only owner", "public": "open lessons", "lecture_is_open_true": "open", "lecture_is_open_false": "closed", "category_all": "All Categories", "category_game": "Game", "category_animation": "Animation", "category_media_art": "Media Art", "category_physical": "Physical", "category_etc": "etc", "category_category_game": "Game", "category_category_animation": "Animation", "category_category_media_art": "Media Art", "category_category_physical": "Physical", "category_category_etc": "etc", "sort_created": "By Latest", "sort_updated": "By Latest", "sort_visit": "By Viewers", "sort_likeCnt": "By Likes", "sort_comment": "By Comments", "period_all": "Entire period", "period_1": "Today", "period_7": "Latest 1 week", "period_30": "Latest 1 month", "period_90": "Latest 3 months", "lecture_required_time_1": "Less than 15 min.", "lecture_required_time_2": "15 to 30 min.", "lecture_required_time_3": "30 to 45 min.", "lecture_required_time_4": "45 to 60 min", "lecture_required_time_5": "over 1 hour", "usage_event": "Event", "usage_signal": "Signal", "usage_scene": "Scene", "usage_repeat": "Repeat", "usage_condition_repeat": "Condition repeat", "usage_condition": "Condition", "usage_clone": "Cloned Object", "usage_rotation": "Rotation", "usage_coordinate": "Coordinate", "usage_arrow_move": "Arrow move", "usage_shape": "Shape", "usage_speak": "Speak", "usage_picture_effect": "Effect", "usage_textBox": "Textbox", "usage_draw": "Draw", "usage_sound": "Sound", "usage_confirm": "Confirm", "usage_comp_operation": "Compare operation", "usage_logical_operation": "Logical operation", "usage_math_operation": "Math operation", "usage_random": "Random", "usage_timer": "bộ đếm thời gian", "usage_variable": "biến số", "usage_list": "List", "usage_ask_answer": " Input/Output", "usage_function": "Function", "usage_arduino": "Arduino", "concept_resource_analytics": "Procedual Thinking", "concept_procedual": "Abstractive Thinking", "concept_abstractive": "Korean", "concept_individual": "English", "concept_automation": "Automation", "concept_simulation": "Simulation", "concept_parallel": "Parallel", "subject_korean": "Korean", "subject_english": "English", "subject_mathmatics": "Mathmatics", "subject_social": "Social", "subject_science": "Science", "subject_music": "Music", "subject_paint": "Paint", "subject_athletic": "Athletics", "subject_courtesy": "Courtesy", "subject_progmatic": "Progmatic", "lecture_grade_1": "1 th", "lecture_grade_2": "2 th", "lecture_grade_3": "3 th", "lecture_grade_4": "4 th", "lecture_grade_5": "5 th", "lecture_grade_6": "6 th", "lecture_grade_7": "7 th", "lecture_grade_8": "8 th", "lecture_grade_9": "9 th", "lecture_grade_10": "Graduated", "lecture_level_1": "Low", "lecture_level_2": "Middle", "lecture_level_3": "High", "listEnable": "list", "functionEnable": "function", "messageEnable": "message", "objectEditable": "object", "pictureeditable": "shape", "sceneEditable": "scene", "soundeditable": "sound", "variableEnable": "biến số", "e_1": "elementary school 1", "e_2": "elementary school 2", "e_3": "elementary school 3", "e_4": "elementary school 4", "e_5": "elementary school 5", "e_6": "elementary school 6", "m_1": "middle school 1", "m_2": "middle school 2", "m_3": "middle school 3", "general": "general", "curriculum_is_open_true": "open", "curriculum_open_false": "closed", "contest2019": "Contest", "exhibit": "Contest", "notice": "Notice", "qna": "Q&A", "tips": "Tips & Tricks", "free": "Discussions", "report": "Suggestions", "art_category_all": "All projects", "art_category_game": "Game", "art_category_animation": "Animation", "art_category_physical": "Physical", "art_category_etc": "etc", "art_category_media": "media art", "art_sort_updated": "Most Recent", "art_sort_visit": "Views", "art_sort_likeCnt": "Likes", "art_sort_comment": "Comments", "art_period_all": "All", "art_period_day": "Today", "art_period_week": "Recent week", "art_period_month": "Recent month", "art_period_three_month": "Recent three month", "level_high": "Row", "level_mid": "Middle", "level_row": "High", "discuss_sort_created": "Most Recent", "discuss_sort_visit": "Views", "discuss_sort_likesLength": "Likes", "discuss_sort_commentsLength": "Comments", "discuss_period_all": "All", "discuss_period_day": "Today", "discuss_period_week": "Recent week", "discuss_period_month": "Recent month", "discuss_period_three_month": "Recent three month" }; Lang.Helper = { "when_run_button_click": "Khi nút Bắt đầu được nhấp, khối đòn kết nối sẽ chạy.", "when_some_key_pressed": "Khi một phím đã gán được nhấn, các khối kết nối dưới đây sẽ chạy. ", "mouse_clicked": "Khi chuột được nhấn, các khối kết nối dưới đây sẽ chạy. ", "mouse_click_cancled": "Khi chuột được thả ra, các khối kết nối dưới đây sẽ chạy. ", "when_object_click": "Khi một đối tượng liên quan được nhấn vào, các khối kết nối dưới đây sẽ chạy. ", "when_object_click_canceled": "Khi bỏ nhấn vào đối tượng, các khối kết nối dưới đây sẽ chạy.", "when_message_cast": "Khi nhận được một dấu hiệu có liên quan, các khối kết nối dưới đây sẽ chạy. ", "message_cast": "Gửi tín hiệu được lựa chọn từ danh sách. ", "message_cast_wait": "Gửi tín hiệu được lựa chọn từ danh sách, và chờ đợi cho các khối kết thúc hoạt động. ", "when_scene_start": "Khi cảnh bắt đầu, các đòn nối khối sẽ chạy. ", "start_scene": "Bắt đầu chọn cảnh. ", "start_neighbor_scene": "Bắt đầu cảnh trước hoặc sau. ", "wait_second": "Chạy khối tiếp theo sau khi chờ đợi một khoảng thời gian. ", "repeat_basic": "Lặp đi lặp lại các khối bên trong để thiết lập số lượng thời gian. ", "repeat_inf": "Lặp đi lặp lại các khối bên trong trong khoảng thời gian không giới hạn.", "repeat_while_true": "Lặp lại các khối cho đến khi các điều kiện thiết lập được đáp ứng. ", "stop_repeat": "dừng lặp lại các khối gần nhất", "_if": "Nếu điều kiện là đúng, chạy các khối bên trong. ", "if_else": "Nếu điều kiện là đúng, chạy các khối trong phần 'nếu'. Nếu không, chạy các khối bên trong phần 'khác'. ", "restart_project": "Khởi động lại tất cả các đối tượng ", "stop_object": "Tất cả các đối tượng: dừng tất cả các đối tượng
Khối này: Dừng tất cả các khối trong đối tượng này.
Đối tượng này: dừng tất cả các khối trong đối tượng này. Khối khác của đối tượng này: ngừng các khối không kết nối với các khối của đối tượng này. ", "wait_until_true": "Dừng chạy và đợi đến khi giá trị điều kiện là đúng.", "when_clone_start": "Khi một bản sao mới của đối tượng được tạo ra, các khối kết nối dưới đây sẽ chạy. ", "create_clone": "Tạo ra một bản sao của đối tượng. ", "delete_clone": "Xoá các đối tượng. ", "remove_all_clones": "Xóa tất cả các bản sao của đối tượng.", "move_direction": "Di chuyển theo hướng mũi tên bằng cách thiết lập giá trị. ", "move_x": "Thay đổi x-vị trí của giá trị không phụ thuộc vào hướng của đối tượng.", "move_y": "Thay đổi y-vị trí của giá trị không phụ thuộc vào hướng của đối tượng.", "move_xy_time": "Thay đổi x và y-vị trí của giá trị không phụ thuộc vào hướng của đối tượng ", "locate_object_time": "Di chuyển các đối tượng đến vị trí con trỏ chuột hoặc vị trí của các đối tượng khác trong khoảng thời gian, đầu vào. ", "locate_x": "Di chuyển đối tượng đến các giá trị đầu vào x-vị trí. ", "locate_y": "Di chuyển đối tượng đến các giá trị đầu vào y-vị trí. ", "locate_xy": "Di chuyển đối tượng đến các giá trị đầu vào x và y-vị trí. ", "locate_xy_time": "Di chuyển các đối tượng với các giá trị được xác định x và y-vị trí trong khoảng thời gian đầu vào", "locate": "Di chuyển đối tượng đến vị trí của con trỏ chuột hoặc đến vị trí của một đối tượng khác. ", "rotate_absolute": "Thiết lập hướng của đối tượng bằng số đầu vào của độ. ", "rotate_by_time": "Xoay đối tượng bằng số đầu vào của độ trong khoảng thời gian đầu vào", "rotate_relative": "Xoay đối tượng bằng số lượng đầu vào của độ. ", "direction_absolute": "Thiết lập hướng của đối tượng bằng số lượng đầu vào của độ. ", "direction_relative": "Thay đổi hướng của đối tượng bằng số lượng đầu vào của độ. ", "move_to_angle": "Di chuyển đối tượng bằng các giá trị đầu vào theo hướng số lượng đầu vào của độ. ", "see_angle_object": "Làm cho các đối tượng phải đối mặt với một đối tượng hoặc con trỏ chuột. ", "bounce_wall": "Khi đối tượng chạm vào cạnh của màn hình, nó bị bật lại.", "show": "Tạo đối tượng hiển thị trên màn hình.", "hide": "Ẩn đối tượng từ màn hình. ", "dialog_time": "Chạy khối tiếp theo sau khi nội dung đầu vào được nói bởi các đối tượng trong khoảng thời gian đầu vào. ", "dialog": "Chạy khối tiếp theo trong khi nội dung đầu vào được nói bởi các đối tượng.", "remove_dialog": "Xóa hộp thoại đã tạo (sử dụng khối hộp thoại) của các đối tượng. ", "change_to_some_shape": "Thay đổi đối tượng thành hình dạng được lựa chọn. ", "change_to_next_shape": "Thay đổi các đối tượng vào các hình tiếp theo. ", "set_effect_volume": "Áp dụng các hiệu ứng đã chọn vào đối tượng bằng các giá trị đầu vào. ", "set_effect_amount": "Áp dụng các hiệu ứng đã chọn vào đối tượng bằng các giá trị đầu vào.", "set_effect": "Thiết lập hiệu ứng đã chọn vào đối tượng bằng các giá trị đầu vào. ", "set_entity_effect": "Thiết lập hiệu ứng đã chọn vào đối tượng bằng các giá trị đầu vào. ", "add_effect_amount": "Áp dụng các hiệu ứng đã chọn vào đối tượng bằng các giá trị đầu vào.", "change_effect_amount": "Thiết lập hiệu ứng đã chọn vào đối tượng bằng các giá trị đầu vào. ", "change_scale_percent": "Thay đổi kích thước của đối tượng bằng giá trị đầu vào. ", "set_scale_percent": "Thiết lập kích thước của các đối tượng với giá trị đầu vào. ", "change_scale_size": "Thay đổi kích thước của đối tượng bằng giá trị đầu vào. ", "set_scale_size": "Thiết lập kích thước của các đối tượng với giá trị đầu vào. ", "flip_x": "Lật đối tượng theo chiều dọc. ", "flip_y": "Lật đối tượng theo chiều ngang. ", "change_object_index": "Mang đến phia trước: đưa đối tượng đến phía trước.
Mang theo một mặt đến phía trước: mang theo đối tượng một lớp đến phía trước.
Gửi một mặt trở lại: gửi đối tượng một lớp trở lại.
Gửi trở lại: gửi đối tượng trở lại", "set_object_order": "Hiển thị các đối tượng theo thứ tự thiết lập. ", "brush_stamp": "Bản sao của đối tượng trên màn hinh giống như con dấu", "start_drawing": "Sơn được quét dọc theo con đường của các đối tượng. ", "stop_drawing": "dừng việc vẽ của đối tượng", "set_color": "Thiết lập màu sắc cọ vẽ của đối tượng bằng màu được chọn.", "set_random_color": "Thiết lập màu sắc cọ vẽ của đối tượng ngẫu nhiên.", "change_thickness": "Thay đổi độ dày cọ vẽ của đối tượng bằng giá trị đầu vào.", "set_thickness": "Thiết lập độ dày cọ vẽ của đối tượng bằng giá trị đầu vào.", "change_opacity": "Thay đổi độ trong suốt của cọ bằng giá trị đầu vào.", "change_brush_transparency": "Thay đổi độ trong suốt cọ vẽ của đối tượng bằng giá trị đầu vào.", "set_opacity": "Thiết lập độ trong suốt cọ vẽ của đối tượng bằng giá trị đầu vào.", "set_brush_tranparency": "Thiết lập độ trong suốt cọ vẽ của đối tượng bằng giá trị đầu vào.", "brush_erase_all": "Xóa tất cả cọ vẽ và các con dấu của đối tượng", "sound_something_with_block": "Phát âm thanh đã chọn của đối tượng trong khi khối tiếp theo chạy. ", "sound_something_second_with_block": "Phát âm thanh đã chọn của đối tượng trong khoảng thời gian đầu vào đồng thời chạy khối tiếp theo.", "sound_something_wait_with_block": "Phát âm thanh đã chọn của đối tượng sau đó khi âm thanh đã phát xong thì chạy các khối tiếp theo.", "sound_something_second_wait_with_block": "Phát âm thanh đã chọn của đối tượng trong khoảng thời gian đầu vào sau đó chạy khối tiếp theo.", "sound_volume_change": "Thay đổi âm lượng của tất cả âm thanh được phát bằng phần trăm đầu vào.", "sound_volume_set": "Thiết lập âm lượng của tất cả âm thanh được phát bằng phần trăm đầu vào.", "sound_silent_all": "Dừng tất cả âm thanh hiện đang phát. ", "is_clicked": "Kiểm tra xem chuột được nhấp hay không.", "is_press_some_key": "Kiểm tra xem một phím đã gán được nhấn hay không.", "reach_something": "Kiểm tra xem đối tượng đạt đến điểm được chọn hay chưa.", "is_included_in_list": "Kiểm tra xem danh sách chọn có chứa các giá trị đầu vào hay không.", "boolean_basic_operator": "Err:501", "function_create": "Xác định một chức năng bằng cách đặt các khối thường xuyên sử dụng dưới đây. Vị trí [tên] bên cạnh [xác định chức năng] để đặt tên cho chức năng.Vượt qua số lượng các giá trị văn bản bằng cách đặt khối[số / giá trị văn bản]. Vượt qua các giá trị boolean true hoặc false bằng cách đặt các khối [giá trị boolean].", "function_field_label": "Đặt bên cạnh [xác định chức năng] để đặt tên cho chức năng.", "function_field_string": "Vượt qua giá trị số/văn bản bằng cách đặt các khối này bên cạnh khối [xác định chức năng] .Grab /copy khối [số / giá trị văn] trong khối [Xác định chức năng] và sử dụng giá trị của nó trong chức năng.", "function_field_boolean": "Sử dụng các khối này để vượt qua các giá trị boolean true hoặc false. Grab/copy khối [giá trị boolean] trong khối [xác định chức năng] và sử dụng các giá trị chức năng.", "function_general": "Đây là khối chức năng hiện tại hoặc khối chức năng đã tạo ra từ lâu.", "boolean_and": "Kiểm tra xem cả hai điều kiện là đúng hay không.", "boolean_or": "Kiểm tra xem ít nhất một trong hai điều kiện là đúng hay không.", "boolean_not": "Thay đổi điều kiện đầu vào để đối lập nó.", "is_boost_mode": 'Checks whether the boost mode is turned on or not.\nIf the boost mode is on, it is judged as "true".', "calc_basic": "+: 'Thêm hai số.
-: Trừ hai số.
X: nhân hai số.
/: chia hai số.", "calc_rand": "Chọn một giá trị ngẫu nhiên giữa hai số đầu vào.", "get_x_coordinate": "Báo cáo giá trị x-vị trí của đối tượng. ", "get_y_coordinate": "Báo cáo giá trị y-vị trí của đối tượng. ", "coordinate_mouse": "Báo cáo của một trong hai giá trị x hoặc y vị trí của chuột. ", "coordinate_object": "Báo cáo x/y-vị trí của các đối tượng và các thông tin khác nhau (hướng, hình dạng tên, vv).", "quotient_and_mod": " Thương số: câu trả lời sau khi bạn chia số đầu tiên của số thứ hai.
Số dư: phần còn lại sau khi chia", "get_rotation_direction": "Báo cáo giá trị định hướng, hướng di chuyển giá trị của đối tượng.", "calc_share": "Báo cáo thương số nhận được khi số đầu tiên chia cho số thứ hai.", "calc_mod": "Báo cáo số dư nhận được khi số đầu tiên chia cho số thứ hai. ", "calc_operation": "Báo cáo giá trị tính toán của một loạt các phương trình liên quan đến các số đầu vào . ", "get_date": "Báo cáo các giá trị về năm hiện tại, tháng, ngày và thời gian. ", "distance_something": "Báo cáo khoảng cách giữa đối tượng và đối tượng được chọn. ", "get_sound_duration": "Báo cáo độ dài thời gian của âm thanh được lựa chọn.", "get_user_name": "작품을 실행하고 있는 사용자의 아이디 값입니다.", "get_nickname": "작품을 실행하고 있는 사용자의 닉네임 값입니다.", "get_project_timer_value": "Báo cáo có bao nhiêu giây đã trôi qua kể từ khi dự án bắt đầu. ", "choose_project_timer_action": "Star: Bắt đầu đếm thời gian.
Stop: Ngừng hẹn giờ.
Reset: Đặt lại bộ đếm thời gian về 0.
(Khi khối này ở workspace, chương trình sẽ hiển thị cửa sổ bộ đếm thời gian khi chạy.) ", "reset_project_timer": "Đặt lại bộ đếm thời gian về 0.", "set_visible_project_timer": "Hiện hoặc ẩn bộ đếm thời gian. ", "ask_and_wait": "Các đối tượng yêu cầu các văn bản đầu vào, và sau đó nhận được một câu trả lời như một sự giải đáp.", "get_canvas_input_value": "Báo cáo các nội dung đầu vào diễn ra sau khi các đối tượng yêu cầu.", "set_visible_answer": "Ẩn hoặc hiển thị ' cửa sổ trả lời'. ", "combine_something": "Kết hợp hai văn bản đầu vào. ", "get_variable": "Báo cáo giá trị của biến chọn.", "change_variable": "Thêm giá trị đầu vào cho các biến được chọn. ", "set_variable": "Đặt giá trị của biến được chọn vào giá trị đầu vào", "robotis_carCont_sensor_value": "Cảm biến kết nối bên trái: giá trị của số liên lạc (1), không tiếp xúc (0).
Cảm biến liên lạc bên phải: giá trị của số liên lạc (1), không tiếp xúc (0).
Số cuối cùng của việc phát hiện âm thanh: giá trị của số cuối cùng phát hiện sống âm thanh.
Số lượng các phát hiện âm thanh trực tiếp: tăng 1 khi nó phát hiện ra những âm thanh tiếp theo trong vòng 1 giây.
Cảm biến hồng ngoại bên phải: giá trị là lớn hơn khi nó gần hơn với một đối tượng.
Giá trị của trái cảm biến hồng ngoại hiệu chỉnh bên trái: giá trị hiệu chuẩn của cảm biến hồng ngoại.
Giá trị của cảm biến hồng ngoại phải hiệu chỉnh bên phải: giá trị hiệu chuẩn của cảm biến hồng ngoại. (*Giá trị hiệu chuẩn - kiểm soát giá trị của cảm biến hồng ngoại)", "robotis_carCont_cm_led": "Chỉ có LED 1 hoặc LED 4 trong số 4 đèn LED được bật hoặc tắt.
Không áp dụng cho LED 2 và LED 3.", "robotis_carCont_cm_sound_detected_clear": "Khởi tạo số cuối cùng của âm thanh được phát hiện đến 0.", "robotis_carCont_aux_motor_speed": "Thiết lập tốc độ của động cơ giảm tốc độ với giá trị 0-1023.", "robotis_carCont_cm_calibration": "Thiết lập giá trị kiểm soát của cảm biến hồng ngoại (http://support.robotis.com/ko/: automobile robot> 2. B. kiểm soát giá trị hồng ngoại).", "robotis_openCM70_sensor_value": "Số cuối cùng phát hiện âm thanh: giá trị của số lần âm thanh được phát hiện cuối cùng.
Số phát hiện âm thanh sống: tăng 1 khi nó phát hiện một âm tiếp theo trong vòng 1 giây.
Tình trạng của nút sử dụng: giá trị của số liên lạc (1), không tiếp xúc (0).
Số cuối cùng của âm thanh phát hiện: giá trị của số cuối cùng phát hiện âm thanh trực tiếp.
Số lượng các phát hiện âm thanh trực tiếp: tăng 1 khi nó phát hiện ra những âm thanh tiếp theo trong vòng 1 giây.
Tình trạng của người sử dụng nút: giá trị của số liên lạc (1), không tiếp xúc (0).", "robotis_openCM70_aux_sensor_value": "Vị trí của động cơ servo: 0-1023, giá trị giữa là 512.
cảm biến hồng ngoại: giá trị là lớn hơn khi nó gần với một đối tượng.
Cảm biến Liên hệ:. Các giá trị của liên hệ (1), không tiếp xúc (0)
CDS : 0-1023, giá trị là lớn hơn khi nó sáng hơn.
cảm biến nhiệt độ, độ ẩm (độ ẩm): 0-100, giá trị là lớn hơn khi nó ẩm ướt hơn.
cảm biến nhiệt độ, độ ẩm (nhiệt độ): -20 - 100, giá trị là lớn hơn khi nó cao hơn nhiệt độ.
cảm biến nhiệt độ: -20 - 100, giá trị là lớn hơn khi nó cao hơn nhiệt độ.
cảm biến siêu âm: - cảm biến từ tính:. các giá trị của hệ (1), không tiếp xúc (0)
Nhận diện chuyển động: giá trị của phát hiện chuyển động (1), không phát hiện chuyển động (0).
Màu sắc cảm biến: giá trị không rõ (0), trắng (1), đen (2), đỏ (3), màu xanh lá cây (4), màu xanh ( 5), vàng (6).
Thiết bị người dùng: xin vui lòng tham khảo sách hướng dẫn ROBOTIS e-manual (http://support.robotis.com/ko/) để giải thích về sản xuất cảm biến cho người dùng.", "robotis_openCM70_cm_buzzer_index": "Phát âm từ 0.1 đến 5 giây.", "robotis_openCM70_cm_buzzer_melody": "Phát nhịp điệu.
Nếu âm thanh không phát liên tục khi lặp lại những giai điệu này thì sử dụng khối 'dòng chảy> chờ X giây' và thực hiện nó một lần nữa.", "robotis_openCM70_cm_sound_detected_clear": "Số cuối cùng phát hiện âm thanh ", "robotis_openCM70_cm_led": "Bật hoặc tắt đèn LED màu đỏ, màu xanh lá cây, màu xanh dương của thiết bị.", "robotis_openCM70_cm_motion": "Thực hiện chuyển động tải về thiết bị. ", "robotis_openCM70_cm_autodrive_motor": "Chỉ định cổng động cơ của ô tô lái tự động.", "robotis_openCM70_cm_autodrive_ir": "Chỉ định cổng cảm biến hồng ngoại của xe lái tự động.", "robotis_openCM70_cm_autodrive_speed": "Lái xe tự động được thực hiện ở tốc độ quy định dọc theo làn đường.", "robotis_openCM70_aux_car_move": "Làm cho robot di chuyển với tốc độ và hướng xác định.", "robotis_openCM70_aux_motor_speed": "Thiết lập tốc độ của động cơ giảm tốc với giá trị 0-100%.", "robotis_openCM70_aux_servo_mode": "Thiết lập động cơ servo như chế độ bánh xe hoặc chế độ chung.
Các chế độ tương tự vẫn tiếp tục áp dụng một khi đã cài đặt.
Chế độ bánh xe chỉ định tốc độ động cơ servo, và quay động cơ servo.
Chọn chế độ di chuyển vị trí của động cơ servo và tốc độ động cơ servo.", "robotis_openCM70_aux_servo_speed": "Cài đặt tốc độ của động cơ servo với giá trị từ 0 - 100%. ", "robotis_openCM70_aux_servo_position": "Cài đặt vị trí của động cơ servo với giá trị từ -150 - 150 độ.
Sử dụng như tốc độ động cơ servo", "robotis_openCM70_aux_led_module": "Bật hoặc tắt các mô-đun LED của LED.", "robotis_openCM70_aux_custom": "Vui lòng tham khảo ROBOTIS e-manual (http://support.robotis.com/ko/) để được giải thích về người sử dụng cảm biến sản xuất.", "robotis_openCM70_cm_poweroff_timer": "Đặt bộ hẹn giờ tự động tắt của bộ điều khiển.
Nếu giao tiếp không diễn ra trong khoảng thời gian đã đặt, bộ điều khiển sẽ tự động tắt.", "robotis_openCM70_cm_custom_value": "Kiểm tra các giá trị bằng cách nhập trực tiếp địa chỉ bảng điều khiển.
Vui lòng tham khảo ROBOTIS e-manual (http://support.robotis.com/ko/)để được giải thích về bảng điều khiển.", "robotis_openCM70_cm_custom": "Kiểm tra các giá trị bằng cách nhập trực tiếp địa chỉ bảng điều khiển.
Vui lòng tham khảo ROBOTIS e-manual (http://support.robotis.com/ko/)để được giải thích về bảng điều khiển.", "show_variable": "Hiển thị giá trị của biến đã chọn trên màn hình.", "hide_variable": "Ẩn giá trị của biến đã chọn trên màn hình.", "value_of_index_from_list": "Báo cáo mục tại vị trí của giá trị nhập trong danh sách đã chọn. ", "add_value_to_list": "Thêm mục vào vị trí cuối cùng trong danh sách đã chọn. ", "remove_value_from_list": "Xóa mục tại vị trí của các giá trị đầu vào trong danh sách đã chọn. ", "insert_value_to_list": "Chèn mục đầu vào tại vị trí của giá trị đầu vào trong danh sách đã chọn. ", "change_value_list_index": "Thay thế mục tại vị trí của các giá trị đầu vào cho văn bản đầu vào ", "length_of_list": "Báo cáo số lượng các mục được chứa trong danh sách đã chọn. ", "show_list": "Hiển thị danh sách đã chọn trên màn hình.", "hide_list": "Ẩn danh sách đã chọn trên màn hình.", "text": "Báo cáo văn bản trong hộp văn bản. ", "text_read": "선택한 글상자 또는 글상자 자신의 내용입니다.
(내용 안에 줄바꿈이 있는 경우, 띄어쓰기하여 반환됩니다.)", "text_write": "Thay đổi nội dung của hộp văn bản để nhập văn bản.", "text_append": "Thêm các văn bản đầu vào phía sau hộp văn bản. ", "text_prepend": "Thêm văn bản đầu vào ở phía trước của hộp văn bản. ", "text_flush": "Xóa tất cả các văn bản được lưu trong hộp văn bản. ", "erase_all_effects": "Xóa tất cả các hiệu ứng về đối tượng này. ", "char_at": "Báo cáo thư của văn bản đầu vào. ", "length_of_string": "Báo cáo độ dài của văn bản đầu vào bao gồm khoảng cách ", "substring": "Báo cáo văn bản trích từ văn bản đầu vào giữa hai chỉ số quy định ", "replace_string": "Báo cáo văn bản mà đã được thay thế tất cả các văn bản đầu vào bằng một văn bản đầu vào khác", "index_of_string": "Báo cáo chỉ số của văn bản đầu vào đầu tiên trong văn bản đầu vào thứ hai ", "change_string_case": "Báo cáo văn bản đã được chuyển đổi sang chữ hoa hoặc chữ thường ", "direction_relative_duration": "Xoay hướng của đối tượng này bằng số đầu vào của góc độ trong một khoảng thời gian. ", "get_sound_volume": "Báo cáo âm lượng âm thanh", "sound_from_to": "해당 오브젝트가 선택한 소리를 입력한 시간 부분만을 재생하는 동시에 다음 블록을 실행합니다.", "sound_from_to_and_wait": "해당 오브젝트가 선택한 소리를 입력한 시간 부분만을 재생하고, 소리 재생이 끝나면 다음 블록을 실행합니다.", "Block_info": "Thông tin khối", "Block_click_msg": "Nhấp vào các khối đi kèm các mô tả của khối. ", "hamster_beep": "버저 소리를 짧게 냅니다.", "hamster_change_both_wheels_by": "왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "hamster_change_buzzer_by": "버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.", "hamster_change_output_by": "선택한 외부 확장 포트의 현재 출력 값에 입력한 값을 더합니다. 더한 결과는 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH", "hamster_change_tempo_by": "연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.", "hamster_change_wheel_by": "왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "hamster_clear_buzzer": "버저 소리를 끕니다.", "hamster_clear_led": "왼쪽/오른쪽/양쪽 LED를 끕니다.", "hamster_follow_line_until": "왼쪽/오른쪽/앞쪽/뒤쪽의 검은색/하얀색 선을 따라 이동하다가 교차로를 만나면 정지합니다.", "hamster_follow_line_using": "왼쪽/오른쪽/양쪽 바닥 센서를 사용하여 검은색/하얀색 선을 따라 이동합니다.", "hamster_hand_found": "근접 센서 앞에 손 또는 물체가 있으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "hamster_move_backward_for_secs": "입력한 시간(초) 동안 뒤로 이동합니다.", "hamster_move_forward_for_secs": "입력한 시간(초) 동안 앞으로 이동합니다.", "hamster_move_forward_once": "말판 위에서 한 칸 앞으로 이동합니다.", "hamster_play_note_for": "선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.", "hamster_rest_for": "입력한 박자만큼 쉽니다.", "hamster_set_both_wheels_to": "왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "hamster_set_buzzer_to": "버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 버저 소리를 끕니다.", "hamster_set_following_speed_to": "선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.", "hamster_set_led_to": "왼쪽/오른쪽/양쪽 LED를 선택한 색깔로 켭니다.", "hamster_set_output_to": "선택한 외부 확장 포트의 출력 값을 입력한 값으로 설정합니다. 입력하는 값은 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH", "hamster_set_port_to": "선택한 외부 확장 포트의 입출력 모드를 선택한 모드로 설정합니다.", "hamster_set_tempo_to": "연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.", "hamster_set_wheel_to": "왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "hamster_stop": "양쪽 바퀴를 정지합니다.", "hamster_turn_for_secs": "입력한 시간(초) 동안 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.", "hamster_turn_once": "말판 위에서 왼쪽/오른쪽 방향으로 제자리에서 90도 회전합니다.", "hamster_value": "왼쪽 근접 센서: 왼쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
오른쪽 근접 센서: 오른쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
왼쪽 바닥 센서: 왼쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
오른쪽 바닥 센서: 오른쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.
밝기: 밝기 센서의 값 (값의 범위: 0 ~ 65535, 초기값: 0) 밝을 수록 값이 커집니다.
온도: 로봇 내부의 온도 값 (값의 범위: 섭씨 -40 ~ 88도, 초기값: 0)
신호 세기: 블루투스 무선 통신의 신호 세기 (값의 범위: -128 ~ 0 dBm, 초기값: 0) 신호의 세기가 셀수록 값이 커집니다.
입력 A: 외부 확장 포트 A로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)
입력 B: 외부 확장 포트 B로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)", "roboid_hamster_beep": "버저 소리를 짧게 냅니다.", "roboid_hamster_change_both_wheels_by": "왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "roboid_hamster_change_buzzer_by": "버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.", "roboid_hamster_change_output_by": "선택한 외부 확장 포트의 현재 출력 값에 입력한 값을 더합니다. 더한 결과는 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH", "roboid_hamster_change_tempo_by": "연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.", "roboid_hamster_change_wheel_by": "왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "roboid_hamster_clear_buzzer": "버저 소리를 끕니다.", "roboid_hamster_clear_led": "왼쪽/오른쪽/양쪽 LED를 끕니다.", "roboid_hamster_follow_line_until": "왼쪽/오른쪽/앞쪽/뒤쪽의 검은색/하얀색 선을 따라 이동하다가 교차로를 만나면 정지합니다.", "roboid_hamster_follow_line_using": "왼쪽/오른쪽/양쪽 바닥 센서를 사용하여 검은색/하얀색 선을 따라 이동합니다.", "roboid_hamster_hand_found": "근접 센서 앞에 손 또는 물체가 있으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "roboid_hamster_move_backward_for_secs": "입력한 시간(초) 동안 뒤로 이동합니다.", "roboid_hamster_move_forward_for_secs": "입력한 시간(초) 동안 앞으로 이동합니다.", "roboid_hamster_move_forward_once": "말판 위에서 한 칸 앞으로 이동합니다.", "roboid_hamster_play_note_for": "선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.", "roboid_hamster_rest_for": "입력한 박자만큼 쉽니다.", "roboid_hamster_set_both_wheels_to": "왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "roboid_hamster_set_buzzer_to": "버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 버저 소리를 끕니다.", "roboid_hamster_set_following_speed_to": "선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.", "roboid_hamster_set_led_to": "왼쪽/오른쪽/양쪽 LED를 선택한 색깔로 켭니다.", "roboid_hamster_set_output_to": "선택한 외부 확장 포트의 출력 값을 입력한 값으로 설정합니다. 입력하는 값은 외부 확장 포트의 모드에 따라 다음의 범위를 가집니다.
서보 출력: 유효한 값의 범위는 1 ~ 180도, 0이면 PWM 펄스 없이 항상 0을 출력
PWM 출력: 0 ~ 100%, PWM 파형에서 ON 상태의 듀티비(%)
디지털 출력: 0이면 LOW, 0이 아니면 HIGH", "roboid_hamster_set_port_to": "선택한 외부 확장 포트의 입출력 모드를 선택한 모드로 설정합니다.", "roboid_hamster_set_tempo_to": "연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.", "roboid_hamster_set_wheel_to": "왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-100 ~ 100%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "roboid_hamster_stop": "양쪽 바퀴를 정지합니다.", "roboid_hamster_turn_for_secs": "입력한 시간(초) 동안 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.", "roboid_hamster_turn_once": "말판 위에서 왼쪽/오른쪽 방향으로 제자리에서 90도 회전합니다.", "roboid_hamster_value": "왼쪽 근접 센서: 왼쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
오른쪽 근접 센서: 오른쪽 근접 센서의 값 (값의 범위: 0 ~ 255, 초기값: 0)
왼쪽 바닥 센서: 왼쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
오른쪽 바닥 센서: 오른쪽 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.
밝기: 밝기 센서의 값 (값의 범위: 0 ~ 65535, 초기값: 0) 밝을 수록 값이 커집니다.
온도: 로봇 내부의 온도 값 (값의 범위: 섭씨 -40 ~ 88도, 초기값: 0)
신호 세기: 블루투스 무선 통신의 신호 세기 (값의 범위: -128 ~ 0 dBm, 초기값: 0) 신호의 세기가 셀수록 값이 커집니다.
입력 A: 외부 확장 포트 A로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)
입력 B: 외부 확장 포트 B로 입력되는 신호의 값 (값의 범위: 아날로그 입력 0 ~ 255, 디지털 입력 0 또는 1, 초기값: 0)", "roboid_turtle_button_state": "등 버튼을 클릭했으면/더블클릭했으면/길게 눌렀으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "roboid_turtle_change_buzzer_by": "버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.", "roboid_turtle_change_head_led_by_rgb": "머리 LED의 현재 R, G, B 값에 입력한 값을 각각 더합니다.", "roboid_turtle_change_tempo_by": "연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.", "roboid_turtle_change_wheel_by": "왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "roboid_turtle_change_wheels_by_left_right": "왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "roboid_turtle_clear_head_led": "머리 LED를 끕니다.", "roboid_turtle_clear_sound": "소리를 끕니다.", "roboid_turtle_cross_intersection": "검은색 교차로에서 잠시 앞으로 이동한 후 검은색 선을 찾아 다시 이동합니다.", "roboid_turtle_follow_line": "하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동합니다.", "roboid_turtle_follow_line_until": "하얀색 바탕 위에서 검은색 선을 따라 이동하다가 선택한 색깔을 컬러 센서가 감지하면 정지합니다.", "roboid_turtle_follow_line_until_black": "하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동하다가 컬러 센서가 검은색을 감지하면 정지합니다.", "roboid_turtle_is_color_pattern": "선택한 색깔 패턴을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "roboid_turtle_move_backward_unit": "입력한 거리(cm)/시간(초)/펄스만큼 뒤로 이동합니다.", "roboid_turtle_move_forward_unit": "입력한 거리(cm)/시간(초)/펄스만큼 앞으로 이동합니다.", "roboid_turtle_pivot_around_wheel_unit_in_direction": "왼쪽/오른쪽 바퀴 중심으로 입력한 각도(도)/시간(초)/펄스만큼 머리/꼬리 방향으로 회전합니다.", "roboid_turtle_play_note": "선택한 계이름과 옥타브의 음을 계속 소리 냅니다.", "roboid_turtle_play_note_for_beats": "선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.", "roboid_turtle_play_sound_times": "선택한 소리를 입력한 횟수만큼 재생합니다.", "roboid_turtle_play_sound_times_until_done": "선택한 소리를 입력한 횟수만큼 재생하고, 재생이 완료될 때까지 기다립니다.", "roboid_turtle_rest_for_beats": "입력한 박자만큼 쉽니다.", "roboid_turtle_set_buzzer_to": "버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 소리를 끕니다.", "roboid_turtle_set_following_speed_to": "선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.", "roboid_turtle_set_head_led_to": "머리 LED를 선택한 색깔로 켭니다.", "roboid_turtle_set_head_led_to_rgb": "머리 LED의 R, G, B 값을 입력한 값으로 각각 설정합니다.", "roboid_turtle_set_tempo_to": "연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.", "roboid_turtle_set_wheel_to": "왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "roboid_turtle_set_wheels_to_left_right": "왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "roboid_turtle_stop": "양쪽 바퀴를 정지합니다.", "roboid_turtle_touching_color": "선택한 색깔을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "roboid_turtle_turn_at_intersection": "검은색 교차로에서 잠시 앞으로 이동한 후 제자리에서 왼쪽/오른쪽/뒤쪽으로 회전하고 검은색 선을 찾아 다시 이동합니다.", "roboid_turtle_turn_unit_in_place": "입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.", "roboid_turtle_turn_unit_with_radius_in_direction": "입력한 반지름의 원을 그리면서 입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽, 머리/꼬리 방향으로 회전합니다.", "roboid_turtle_value": "색깔 번호: 컬러 센서가 감지한 색깔의 번호 (값의 범위: -1 ~ 8, 초기값: -1)
색깔 패턴: 컬러 센서가 감지한 색깔 패턴의 값 (값의 범위: -1 ~ 88, 초기값: -1)
바닥 센서: 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
버튼: 거북이 등 버튼의 상태 값 (누르면 1, 아니면 0, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.", "turtle_button_state": "등 버튼을 클릭했으면/더블클릭했으면/길게 눌렀으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "turtle_change_buzzer_by": "버저 소리의 현재 음 높이(Hz)에 입력한 값을 더합니다. 소수점 둘째 자리까지 입력할 수 있습니다.", "turtle_change_head_led_by_rgb": "머리 LED의 현재 R, G, B 값에 입력한 값을 각각 더합니다.", "turtle_change_tempo_by": "연주하거나 쉬는 속도의 현재 BPM(분당 박자 수)에 입력한 값을 더합니다.", "turtle_change_wheel_by": "왼쪽/오른쪽/양쪽 바퀴의 현재 속도 값(%)에 입력한 값을 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "turtle_change_wheels_by_left_right": "왼쪽과 오른쪽 바퀴의 현재 속도 값(%)에 입력한 값을 각각 더합니다. 더한 결과가 양수 값이면 바퀴가 앞으로 회전하고, 음수 값이면 뒤로 회전합니다.", "turtle_clear_head_led": "머리 LED를 끕니다.", "turtle_clear_sound": "소리를 끕니다.", "turtle_cross_intersection": "검은색 교차로에서 잠시 앞으로 이동한 후 검은색 선을 찾아 다시 이동합니다.", "turtle_follow_line": "하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동합니다.", "turtle_follow_line_until": "하얀색 바탕 위에서 검은색 선을 따라 이동하다가 선택한 색깔을 컬러 센서가 감지하면 정지합니다.", "turtle_follow_line_until_black": "하얀색 바탕 위에서 선택한 색깔의 선을 따라 이동하다가 컬러 센서가 검은색을 감지하면 정지합니다.", "turtle_is_color_pattern": "선택한 색깔 패턴을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "turtle_move_backward_unit": "입력한 거리(cm)/시간(초)/펄스만큼 뒤로 이동합니다.", "turtle_move_forward_unit": "입력한 거리(cm)/시간(초)/펄스만큼 앞으로 이동합니다.", "turtle_pivot_around_wheel_unit_in_direction": "왼쪽/오른쪽 바퀴 중심으로 입력한 각도(도)/시간(초)/펄스만큼 머리/꼬리 방향으로 회전합니다.", "turtle_play_note": "선택한 계이름과 옥타브의 음을 계속 소리 냅니다.", "turtle_play_note_for_beats": "선택한 계이름과 옥타브의 음을 입력한 박자만큼 소리 냅니다.", "turtle_play_sound_times": "선택한 소리를 입력한 횟수만큼 재생합니다.", "turtle_play_sound_times_until_done": "선택한 소리를 입력한 횟수만큼 재생하고, 재생이 완료될 때까지 기다립니다.", "turtle_rest_for_beats": "입력한 박자만큼 쉽니다.", "turtle_set_buzzer_to": "버저 소리의 음 높이를 입력한 값(Hz)으로 설정합니다. 소수점 둘째 자리까지 입력할 수 있습니다. 숫자 0을 입력하면 소리를 끕니다.", "turtle_set_following_speed_to": "선을 따라 이동하는 속도(1 ~ 8)를 설정합니다. 숫자가 클수록 이동하는 속도가 빠릅니다.", "turtle_set_head_led_to": "머리 LED를 선택한 색깔로 켭니다.", "turtle_set_head_led_to_rgb": "머리 LED의 R, G, B 값을 입력한 값으로 각각 설정합니다.", "turtle_set_tempo_to": "연주하거나 쉬는 속도를 입력한 BPM(분당 박자 수)으로 설정합니다.", "turtle_set_wheel_to": "왼쪽/오른쪽/양쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "turtle_set_wheels_to_left_right": "왼쪽과 오른쪽 바퀴의 속도를 입력한 값(-400 ~ 400%)으로 각각 설정합니다. 양수 값을 입력하면 바퀴가 앞으로 회전하고, 음수 값을 입력하면 뒤로 회전합니다. 숫자 0을 입력하면 정지합니다.", "turtle_stop": "양쪽 바퀴를 정지합니다.", "turtle_touching_color": "선택한 색깔을 컬러 센서가 감지하였으면 '참'으로 판단하고, 아니면 '거짓'으로 판단합니다.", "turtle_turn_at_intersection": "검은색 교차로에서 잠시 앞으로 이동한 후 제자리에서 왼쪽/오른쪽/뒤쪽으로 회전하고 검은색 선을 찾아 다시 이동합니다.", "turtle_turn_unit_in_place": "입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽 방향으로 제자리에서 회전합니다.", "turtle_turn_unit_with_radius_in_direction": "입력한 반지름의 원을 그리면서 입력한 각도(도)/시간(초)/펄스만큼 왼쪽/오른쪽, 머리/꼬리 방향으로 회전합니다.", "turtle_value": "색깔 번호: 컬러 센서가 감지한 색깔의 번호 (값의 범위: -1 ~ 8, 초기값: -1)
색깔 패턴: 컬러 센서가 감지한 색깔 패턴의 값 (값의 범위: -1 ~ 88, 초기값: -1)
바닥 센서: 바닥 센서의 값 (값의 범위: 0 ~ 100, 초기값: 0)
버튼: 거북이 등 버튼의 상태 값 (누르면 1, 아니면 0, 초기값: 0)
x축 가속도: 가속도 센서의 X축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇이 전진하는 방향이 X축의 양수 방향입니다.
y축 가속도: 가속도 센서의 Y축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 왼쪽 방향이 Y축의 양수 방향입니다.
z축 가속도: 가속도 센서의 Z축 값 (값의 범위: -32768 ~ 32767, 초기값: 0) 로봇의 위쪽 방향이 Z축의 양수 방향입니다.", "neobot_sensor_value": "Chỉ ra các giá trị đầu vào từ cổng IN1 - IN3 và các thông tin của pin như số từ 0 đến 255. ", "neobot_sensor_convert_scale": "Quy mô thể hiện sự thay đổi các cổng được lựa chọn của các giá trị đầu vào như giá trị của một quy mô cụ thể có thể được điều chỉnh. ", "neobot_left_motor": "Thiết lập hướng bánh xe và tốc độ của động cơ kết nối với cổng động cơ L. ", "neobot_stop_left_motor": "Dừng động cơ kết nối với cổng động cơ L.", "neobot_right_motor": "Thiết lập hướng bánh xe và tốc độ của động cơ kết nối với cổng động cơ R. ", "neobot_stop_right_motor": "Dừng động cơ kết nối với cổng động cơ R.", "neobot_all_motor": "Tốc độ, thời gian, và hướng về phía trước, sau, trái và phải, khi kết nối 2 động cơ đến cổng động cơ L và R có thể được thiết lập và sử dụng như bánh xe.", "neobot_stop_all_motor": "Dừng động cơ kết nối với cả động cơ L và R.", "neobot_set_servo": "Các góc trong vòng 0 - 180 độ khi kết nối động cơ servo đến OUT1 - OUT3 có thể được điều chỉnh", "neobot_set_output": "Điện áp đầu ra khi kết nối khối ánh sáng và mạch điện tử đến OUT1 -. OUT3 có thể được thiết lập.
0 chỉ 0V, và 1 ~ 255 chỉ 2.4 ~ 4.96V.", "neobot_set_fnd": "Số từ 0 đến 99 với FND có thể được chỉ định.", "neobot_set_fnd_off": "Số ghi trên FND có thể được tắt. ", "neobot_play_note_for": "Ghi chú trong đơn vị nửa cung của giai điệu có thể được chơi bằng cách sử dụng dao động tần số.", "rotate_by_angle_dropdown": "오브젝트의 방향을 입력한 각도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)", "chocopi_control_button": "버튼이 눌리면 참이 됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_control_event": "버튼을 누르거나 뗄 때 처리할 엔트리 블록들을 연결합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_control_joystick": "조이스틱 좌우, 상하, 볼륨의 값은 0~4095까지 입니다.
따라서 2047 근처가 중간이 됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_dc_motor": "DC모터 모듈에는 직류전동기 두개를 연결 할 수 있습니다.
직류 전동기는 최대 5V로 동작하게 됩니다.
값은 100이 최대(100%)이고 음수를 넣으면 반대 방향으로 회전합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_led": "LED번호는 LED블록에 연결된 순서이고 1번부터 시작합니다.
RGB값은 0~255사이의 값입니다.
빨강(Red),녹색(Green), 파랑(Blue)순서로 입력합니다.
밝은 LED를 직접보면 눈이 아프니까 값을 0~5정도로 씁니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_motion_photogate_event": "포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
빛센서를 물체로 가리거나 치우면 시작되는 엔트리 블록을 연결합니다
모션 모듈에는 포토게이트 2개를 연결할 수 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_motion_photogate_status": "포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
물체가 빛센서를 가리면 참이됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_motion_photogate_time": "포토게이트는 모션블록에 연결합니다.
포토게이트는 한쪽에서 나온 빛을 맞은 편의 센서가 감지하는 장치입니다.
이 블록은 물체가 빛센서를 가리거나 벗어난 시간을 가집니다.
1/10000초까지 측정할 수 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_motion_value": "모션 모듈에는 3개의 적외선 센서가 있습니다.
0~4095사이의 값을 가질 수 있는데 물체가 빛을 많이 반사할 수록 작은 값을 가집니다.
거리를 대략적으로 측정할 수 있습니다.
가속도와 각가속도 값의 범위는 -32768~32767 까지입니다.
가속도를 이용해서 센서의 기울기를 측정할 수도 있습니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_sensor": "온도 값은 섭씨 온도입니다.
습도 값은 백분율로 나타낸 상대습도 값입니다.
빛은 로그스케일로 0~4095사이입니다.
아날로그 값은 0~4095사이입니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_servo_motor": "서보모터 모듈에는 4개의 서보모터를 연결 할 수 있습니다.
서보모터는 5V로 동작하게 됩니다.
각도는 0~200도까지 지정할 수 있습니다.
연속회전식 서보모터를 연결하면 각도에 따라 속도가 변하게됩니다.
90~100 사이가 중간값입니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_touch_event": "터치 모듈에는 1~12번의 연결 패드가 있습니다.
만지거나 뗄 때 처리할 엔트리 블록들을 연결합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_touch_status": "터치 모듈의 패드를 만지면 참이됩니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "chocopi_touch_value": "터치패드에 연결된 물체의 전기용량이 커지면 값이 작아집니다.
여러 명이 손잡고 만지면 더 작은 값이 됩니다.
전기용량이란 물체에 전기를 띈 입자를 얼마나 가지고 있을 수 있는 지를 말합니다.

포트번호는 맞추지 않아도 됩니다.
단, 같은 종류의 모듈을 여러 개 연결하는 경우에만 포트를 지정하면 됩니다.", "boolean_and_or": "그리고 : 두 판단이 모두 참인 경우 ‘참’으로 판단합니다.
또는 : 두 판단 중 하나라도 참이 있는 경우 ‘참’으로 판단합니다.", "check_weather": "
선택한 날짜와 지역의 날씨 정보를 실제 날씨 상태와 비교하여 일치하는 경우 ‘참’으로 판단합니다.
* 옵션
날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
날씨: 맑음, 구름조금, 구름많음, 흐림, 비, 진눈깨비, 눈", "check_finedust": "
선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.
* 옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
미세먼지 등급: 좋음, 보통, 나쁨, 매우나쁨", "get_weather_data": "
선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.
* 옵션
날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
정보: 최저기온(℃), 최고기온(℃), 습도(%), 강수량(mm), 강수확률(%), 풍속(m/s)", "get_current_weather_data": "
현재 선택한 지역의 날씨 정보값(기온, 미세먼지농도)입니다.
* 옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
정보: (기온(℃)), 미세먼지농도(㎍)", "get_today_temperature": "
오늘 선택한 지역과 시간대의 기온을 의미합니다.
* 옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시간대: 00, 03, 06, 09, 12, 15, 18, 21", "check_city_weather": "
선택한 날짜와 지역의 날씨 정보를 실제 날씨 상태와 비교하여 일치하는 경우 ‘참’으로 판단합니다.
* 옵션
날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후
시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시군구: 시도별로 다름
날씨: 맑음, 구름조금, 구름많음, 흐림, 비, 진눈깨비, 눈", "check_city_finedust": "
선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.
* 옵션
시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시군구: 시도별로 다름
미세먼지 등급: 좋음, 보통, 나쁨, 매우나쁨", "get_city_weather_data": "
선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.
* 옵션
날짜: 어제, 오늘, 내일, 모레, 3일 후, 4일 후, 5일 후, 6일 후
시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시군구: 시도별로 다름
정보: 최저기온(℃), 최고기온(℃), 습도(%), 강수량(mm), 강수확률(%), 풍속(m/s)", "get_current_city_weather_data": "
현재 선택한 지역의 날씨 정보값(기온, 미세먼지농도)입니다.
* 옵션
시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시군구: 시도별로 다름
정보: (기온(℃)), 미세먼지농도(㎍)", "get_today_city_temperature": "
오늘 선택한 지역과 시간대의 기온을 의미합니다.
* 옵션
시도: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
시군구: 시도별로 다름
시간대: 00, 03, 06, 09, 12, 15, 18, 21", "count_festival": "
선택한 날짜와 지역에서 열리는 행사의 수입니다.
*옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
행사일: 1월~12월", "get_festival_info": "
선택한 날짜와 지역에서 열리는 행사에 대한 정보입니다.
*옵션
지역: 서울, 강원, 경기, 경남, 경북, 광주, 대구, 대전, 부산, 세종, 울산, 인천, 전남, 전북, 제주, 충남, 충북
행사일: 1월~12월
정보: 제목, 지역, 시작일, 종료일, 주소, 개요, 홈페이지", "get_translated_string": "The number of events held on the selected date and region.", "check_language": "Reports the information(Title, area, start date, end date, address, overview, homepage) about events held on the selected date and region.", "count_disaster_behavior": "
The number of behavior-guideline's when selected natural disaster occurs.", "get_disaster_behavior": "
Reports the information about behavior-guidelines when selected natural disaster occurs.", "count_lifeSafety_behavior": "
The number of behavior-guideline's when selected life problem occurs.", "get_lifeSafety_behavior": "
Reports the information about behavior-guidelines when selected life problem occurs.", "read_text": "Read the entered text in setted voice.", "set_tts_property": "Set the selected voice to selected speed and selected pitch.
The selected voice will be set up to selected speed and selected pitch.", "read_text_wait_with_block": "Read the entered text in setted voice then the next block runs after the reading finished.", "check_microphone": "Check whether microphone is connected with the computer.", "speech_to_text_convert": "Converts voice input into the microphone into text.", "get_microphone_volume": "Reports the volume of sound input to the microphone.", "speech_to_text_get_value": "Reports the value that converted speech to text. If no voice is input or an error occurs during voice recognition, it will have 0 value.", "video_draw_webcam": "Show or hide the video screen.", "video_check_webcam": "Check whether video is connected with the computer.", "video_set_camera_option": "Set the selected effect to the video screen by the input value.", "video_flip_camera": "Flips the video screen horizontally or vertically.", "video_toggle_model": "Start or stop the selected recognition model. Face Recognition: Recognizes a person's face to know where the eyes, nose, mouth, and ear are located, or the expected gender, age, and emotion. Human Recognition: Recognizes a person's body to know where each part is located Object Recognition: Shows the recognized object type. (Person or thing)", "video_toggle_ind": "Show location and index of the detected humans / faces / objects on the screen.", "video_number_detect": "Reports number of people / faces /objects detected on the video screen.", "video_detected_face_info": "Reports the estimated value of the selected face area among the faces in the input order. If it is not recognized, it is outputted as 0 unconditionally. (Gender, Age, Emotion)", "video_motion_value": "Reports the motion or direction value detected on the selected object or screen.", "video_face_part_coord": "Reports the position value of the selected face area among the faces in the input order. If it is not recognized, it is outputted as 0 unconditionally. (Left eye, Right eye, Nose, Left mouse, Right mouse, Upper Lip, Lower Lip)", "video_body_part_coord": "Reports number of human detected on the video screen. (Face, Right shoulder, Right elbow, Right wrist, Left shoulder, Left elbow, Left wrist, Right hip, Right knee, Right ankle, Left hip, Left knee, Left ankle)", "append_row_to_table": "Adds a row(col) to the end location of the selected table.", "insert_row_to_table": "Inserts a row(col) to the location of the input value on the selected table.", "delete_row_from_table": "Deletes the row(col) at the location of input value from the selected table.", "set_value_from_table": "Replaces value of selected attribute at the location of the input value to the input value.", "get_table_count": "Reports the number of rows or attribute on the selected table.", "get_value_from_table": "Reports the value of selected attribute at the location of the input value from the selected table.", "calc_values_from_table": "Reports calculated value of the selected attributes in the selected table. (sum, maximum, minimum, average, standard deviation)", "open_table_chart": "Open the chart of the selected table.", "close_table_chart": "Close the table chart.", "get_coefficient": "Correlation coefficient between two attributes in the selected table. The closer the correlation coefficient is to 1(-1), the stronger the positive (negative) linear correlation." }; Lang.Category = { "entrybot_friends": "Entrybot friends", "people": "People", "animal": "Animal", "animal_flying": "Flying", "animal_land": "Land", "animal_water": "Water", "animal_others": "Others", "plant": "Plant", "plant_flower": "Flowers", "plant_grass": "Grass", "plant_tree": "Tree", "plant_others": "Others", "vehicles": "Vehicles", "vehicles_flying": "Flying", "vehicles_land": "Land", "vehicles_water": "Water", "vehicles_others": "Others", "architect": "Building", "architect_building": "Structure", "architect_monument": "Monument", "architect_others": "Others", "food": "Food", "food_vegetables": "Fruits/Vegetables", "food_meat": "Meat", "food_drink": "Drink", "food_others": "Others", "environment": "Environment", "environment_nature": "Nature", "environment_space": "Space", "environment_others": "Others", "stuff": "Things", "stuff_living": "Living", "stuff_hobby": "Hobby", "stuff_others": "Others", "fantasy": "Fantasy", "interface": "Interface", "interface_website": "Website", "interface_game": "Game", "interface_others": "Others", "background": "Background", "background_outdoor": "Outdoor", "background_indoor": "Indoor", "background_nature": "Nature", "background_others": "Others" }; Lang.Device = { "arduino": "arduino", "hamster": "hamster", "roboid": "roboid", "turtle": "turtle", "albert": "albert", "robotis_carCont": "", "robotis_openCM70": "", "sensorBoard": "Entry Sensor Board", "trueRobot": "TrueTrueRobot", "CODEino": "CODEino", "bitbrick": "bitbrick", "creamo": "creamo", "playcode": "playcode", "funboard": "funboard", "bitBlock": "bitBlock", "xbot_epor_edge": "XBOT", "dplay": "DPLAY", "iboard": "iboard", "nemoino": "NEMOino", "ev3": "EV3", "robotori": "robotori", "smartBoard": "smartBoard", "chocopi": "ChocoPi", "rokoboard": "rokoboard", "altino": "알티노", "mechatro": "mechatro" }; Lang.General = { "turn_on": "Bật", "turn_off": "Tắt", "left": "Bên trái", "right": "Bên phải", "param_string": "chuỗi", "both": "Hai bên", "transparent": "transparent", "black": "black", "brown": "brown", "red": "Đỏ", "yellow": "Vàng", "green": "Xanh lá cây", "skyblue": "Xanh da trời", "blue": "Xanh dương", "purple": "Tím", "white": "Trắng", "note_c": "Đô", "note_d": "Rê", "note_e": "Mi", "note_f": "Pha", "note_g": "Son", "note_a": "La", "note_b": "Si", "questions": "Question", "clock": "clock", "counter_clock": "counterclock", "font_size": "font size", "second": """, "alert_title": "Alert", "confirm_title": "Confirm", "update_title": "Alert", "recent_download": "Download", "recent_download2": "Download the latest version", "latest_version": "You are running the latest version.", "dont_show_again": "Do not show this again" }; Lang.Fonts = { "jeju_hallasan": "Jeju Hallasan", "gothic_coding": "Gothic Coding", "batang": "Batang", "gothic": "Nanum Gothic", "myeongjo": "Nanum Myeongjo", "pen_script": "Nanum Pen Script", "square_round": "Nanum SquareRound", "jalnan": "jalnan", "designhouse": "designhouse", "malssami815": "Malssami815", "dunggeunmo": "DungGeunMo", "hs_bombaram": "HS Bombaram", "yisunshin": "YiSunShin", "goyang": "Goyang", "flower_road": "SangSangFlowerRoad", "uhbeemysen": "UhBeemysen", "sd_comic_stencil": "Sandoll Comicstencil", "sd_childfundkorea": "Sandoll Childfundkorea", "sd_cinema_theater": "Sandoll Cinema Theater", "sd_mapssi": "Sandoll Mapssi", "sd_shabang": "Sandoll Shabang", "sd_woodcarving": "Sandoll Woodcarving", "sd_yongbi": "Sandoll Yongbi" }; Lang.Hw = { "note": "Nốt nhạc", "leftWheel": "Bánh xe trái", "rightWheel": "Bánh xe phải", "leftEye": "Mắt trái", "rightEye": "Mắt phải", "led": "Đèn LED", "led_en": "LED", "body": "Cơ thể", "front": "Phía trước", "port_en": "port", "port_ko": "", "sensor": "cảm biến", "light": "ánh sáng", "temp": "temp", "switch_": "sw_", "right_ko": "", "right_en": "R", "left_ko": "", "left_en": "L", "up_ko": "", "up_en": "U", "down_ko": "", "down_en": "D", "output": "đầu ra", "left": "bên trái", "right": "bên phải", "sub": "servo", "motor": "motor", "": "", "buzzer": "Chuông", "IR": "infrared", "acceleration": "acceleration", "analog": "analog", "angular_acceleration": "angular acceleration", "button": "button", "humidity": "humidity", "joystick": "joystick", "port": "port", "potentiometer": "potentiometer", "servo": "servo" }; Lang.template = { "albert_hand_found": "tìm tay?", "albert_is_oid_value": "giá trị %1 là oid %2", "albert_value": "%1", "albert_move_forward_for_secs": "di chuyển về phía trước %1 giây %2", "albert_move_backward_for_secs": "di chuyển về phía sau %1 giây %2", "albert_turn_for_secs": "quay lại %1 %2 giây %3", "albert_change_both_wheels_by": "thay đổi bánh xe bên trái:%1 phải: %2 %3", "albert_set_both_wheels_to": "thiết lập bánh xe bên trái:%1 phải: %2 %3", "albert_change_wheel_by": "thay đổi %1 bằng %2 %3", "albert_set_wheel_to": "thiết lập %1 thành %2 %3", "albert_stop": "dừng lại %1", "albert_set_pad_size_to": "thiết lập kích thước pad chiều rộng %1 chiều cao: %2 %3", "albert_move_to_x_y_on_board": "di chuyển đến x: %1 y: %2 trên bảng %3 ", "albert_set_orientation_on_board": "thiết lập định hướng để %1 trên bảng %2", "albert_set_eye_to": "thiết lập %1 thành %2 %3", "albert_clear_eye": "xóa %1 %2", "albert_body_led": "thân LED %1 %2", "albert_front_led": "phía trước LED %1 %2", "albert_beep": "tiếng bíp bíp %1", "albert_change_buzzer_by": "thay đổi chuông bằng %1 %2", "albert_set_buzzer_to": "thiết lập chuông bằng %1 %2", "albert_clear_buzzer": "xóa chuông %1", "albert_play_note_for": "phát âm %1 %2 cho %3 nhịp %4", "albert_rest_for": "nghỉ %1 nhịp %2", "albert_change_tempo_by": "thay đổi nhịp độ bằng %1 %2", "albert_set_tempo_to": "thiết lập nhịp độ bằng %1 bpm %2", "albert_move_forward": "di chuyển về phía trước %1", "albert_move_backward": "di chuyển về phía sau %1", "albert_turn_around": "quay về %1 %2", "albert_set_led_to": "thiết lập %1 %2 %3", "albert_clear_led": "xóa %1 %2", "albert_change_wheels_by": "%1 %2 %3", "albert_set_wheels_to": "%1 %2 %3", "arduino_text": "%1", "arduino_get_sensor_number": "%1 ", "arduino_get_port_number": "%1 ", "arduino_get_digital_toggle": "%1 ", "arduino_get_pwm_port_number": "%1 ", "arduino_get_number_sensor_value": "giá trị biến số Analog %1", "arduino_ext_get_analog_value": "giá trị biến số Analog %1", "arduino_ext_get_analog_value_map": "Map Value %1 %2 ~ %3 to %4 ~ %5", "arduino_ext_get_ultrasonic_value": "Read ultrasonic sensor trig pin %1 echo pin %2", "arduino_ext_toggle_led": "kỹ thuật số %1 Pin %2 %3", "arduino_ext_digital_pwm": "kỹ thuật số %1 Pin %2 %3", "arduino_ext_set_tone": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "arduino_ext_set_servo": "Set servo pin %1 angle as %2 %3", "arduino_ext_get_digital": "giá trị cảm biến kỹ thuật số %1", "blacksmith_get_analog_value": "Read analog %1 pin sensor value", "blacksmith_get_analog_mapping": "Map analog %1 pin sensor value from %2 ~ %3 to %4 ~ %5", "blacksmith_get_digital_bluetooth": "Bluetooth RX 2 value", "blacksmith_get_digital_ultrasonic": "Read ultrasonic Trig %1 Echo %2 sensor value", "blacksmith_get_digital_toggle": "Digital %1 pin sensor value", "blacksmith_set_digital_toggle": "Digital %1 pin %2 %3", "blacksmith_set_digital_pwm": "Digital pwm %1 Pin %2 %3", "blacksmith_set_digital_servo": "Set servo pin %1 angle as %2 %3", "blacksmith_set_digital_buzzer": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "blacksmith_set_digital_lcd": "LCD %1 line %2 appear %3", "blacksmith_set_digital_bluetooth": "Bluetooth TX 3 Pin %1 data send %2", "dplay_get_number_sensor_value": "giá trị cảm biến Analog %1", "nemoino_get_number_sensor_value": "giá trị cảm biến Analog %1", "sensorBoard_get_number_sensor_value": "giá trị cảm biến Analog %1", "truetrue_get_accsensor": "3-AXIS Accelerometer %1 Sensor value", "truetrue_get_bottomcolorsensor": "Bottom Color %1 Sensor value", "truetrue_get_frontcolorsensor": "Front Color %1 Sensor value", "truetrue_get_linesensor": "Line %1 Sensor value", "truetrue_get_proxisensor": "Proximity %1 Sensor value", "truetrue_set_colorled": "Set Color LED Red %1 Green %2 Blue %3 %4", "truetrue_set_dualmotor": "Set DC motor left %1 right %2 during %3 seconds %4", "truetrue_set_led_colorsensor": "LED for %1 color sensor %2 %3", "truetrue_set_led_linesensor": "LED for line sensor %1 %2", "truetrue_set_led_proxi": "LED for %1 proximity sensor %2 %3", "truetrue_set_linetracer": "Line tracing mode %1 %2", "truetrue_set_singlemotor": "Set DC motor %1 speed %2 %3", "CODEino_get_number_sensor_value": "giá trị cảm biến Analog %1", "ardublock_get_number_sensor_value": "giá trị cảm biến Analog %1", "arduino_get_digital_value": "giá trị cảm biến kỹ thuật số %1", "dplay_get_digital_value": "giá trị cảm biến kỹ thuật số %1", "nemoino_get_digital_value": "giá trị cảm biến kỹ thuật số %1", "sensorBoard_get_digital_value": "giá trị cảm biến kỹ thuật số %1", "CODEino_get_digital_value": "giá trị cảm biến kỹ thuật số %1", "CODEino_set_digital_value": "Digital %1 Pin %2 %3", "CODEino_set_pwm_value": "Digital %1 Pin %2 %3", "ardublock_get_digital_value": "giá trị cảm biến kỹ thuật số %1", "arduino_toggle_led": "kỹ thuật số %1 Pin %2 %3", "dplay_toggle_led": "kỹ thuật số %1 Pin %2 %3", "nemoino_toggle_led": "kỹ thuật số %1 Pin %2 %3", "sensorBoard_toggle_led": "kỹ thuật số %1 Pin %2 %3", "CODEino_toggle_led": "kỹ thuật số %1 Pin %2 %3", "arduino_toggle_pwm": "kỹ thuật số %1 Pin %2 %3", "dplay_toggle_pwm": "kỹ thuật số %1 Pin %2 %3", "nemoino_toggle_pwm": "kỹ thuật số %1 Pin %2 %3", "sensorBoard_toggle_pwm": "kỹ thuật số %1 Pin %2 %3", "CODEino_toggle_pwm": "kỹ thuật số %1 Pin %2 %3", "ardublock_toggle_pwm": "kỹ thuật số %1 Pin %2 %3", "arduino_convert_scale": "bản đồ giá trị từ %1 %2 ~ %3 đến %4 %5", "dplay_convert_scale": "bản đồ giá trị từ %1 %2 ~ %3 đến %4 %5", "nemoino_convert_scale": "bản đồ giá trị từ %1 %2 ~ %3 đến %4 %5", "sensorBoard_convert_scale": "bản đồ giá trị từ %1 %2 ~ %3 đến %4 %5", "CODEino_convert_scale": "bản đồ giá trị từ %1 %2 ~ %3 đến %4 %5", "CODEino_set_rgb_value": "Set color LED %1 by %2 %3", "CODEino_set_rgb_add_value": "Add color LED %1 by %2 %3", "CODEino_set_rgb_off": "Turn off LED %1", "CODEino_set__led_by_rgb": "Turn on color LED, Red %1 Green %2 Blue %3 %4", "CODEino_rgb_set_color": "Select %1 for color LED %2", "CODEino_led_by_value": "Turn on LED %1", "ardublock_convert_scale": "bản đồ giá trị từ %1 %2 ~ %3 đến %4 %5", "joystick_get_number_sensor_value": "giá trị cảm biến Analog %1", "joystick_get_digital_value": "giá trị cảm biến kỹ thuật số %1", "joystick_toggle_led": "kỹ thuật số %1 Pin %2 %3", "joystick_toggle_pwm": "kỹ thuật số %1 Pin %2 %3", "joystick_convert_scale": "bản đồ giá trị từ %1 %2 ~ %3 đến %4 %5", "sensorBoard_get_named_sensor_value": "giá trị cảm biến %1", "sensorBoard_is_button_pressed": "nhấn nút %1?", "sensorBoard_led": "%1 LED %2 %3", "arduino_download_connector": "%1", "download_guide": "%1", "arduino_download_source": "%1", "arduino_connected": "%1", "arduino_connect": "%1", "arduino_reconnect": "%1", "CODEino_get_sensor_number": "%1", "CODEino_get_named_sensor_value": "giá trị biến số %1", "CODEino_get_sound_status": "âm thanh %1", "CODEino_get_light_status": "ánh sáng %1", "CODEino_is_button_pressed": "vận hành %1", "CODEino_get_accelerometer_direction": "cảm biến gia tốc 3 trục %1", "CODEino_get_accelerometer_value": "cảm biến gia tốc 3 trục %1-giá trị trục", "CODEino_get_analog_value": "Analog %1 Sensor value", "iboard_button": "Pressed %1 button?", "iboard_digital_pwm": "Digital %1 Pin %2 %3", "iboard_get_analog_value": "Analog %1 Sensor value ", "iboard_get_analog_value_map": "Map Value %1 %2 ~ %3 to %4 ~ %5 ", "iboard_get_digital": "Digital %1 Sensor value ", "iboard_led": "Digital %1 Pin %2 %3", "iboard_motor": "Digital %1 Pin %2 %3", "iboard_pwm_led": "Digital %1 Pin %2 %3", "iboard_rgb_led": " %1 LED %2 %3", "iboard_set_tone": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "iboard_toggle_led": "Digital %1 Pin %2 %3", "bitbrick_is_touch_pressed": "nhấn nút %1 %2?", "bitbrick_is_sensor_value_compare": "nhấn nút %1 %2 %3?", "bitbrick_sensor_value": "giá trị %1", "bitbrick_convert_scale": "đổi giá trị %1 từ %2~%3 đến %4~%5", "bitbrick_turn_on_color_led_by_rgb": "mở màu LED R%1 G %2 B %3 %4", "bitbrick_turn_on_color_led_by_picker": "chọn %1 cho màu LED %2", "bitbrick_turn_on_color_led_by_value": "mở màu LED, chọn %1 %2", "bitbrick_turn_off_color_led": "tắt màu LED %1", "bitbrick_buzzer": "âm buzz %1 giây %2", "bitbrick_servomotor_angle": "động cơ servo %1 góc độ %2 %3", "bitbrick_dc_direction_speed": "động cơ DC %1 %2 tốc độ phương hướng %3 %4", "bitbrick_dc_speed": "động cơ DC %1 tốc độ %2 %3", "bitbrick_turn_off_all_motors": "tắt tất cả các động cơ %1", "start_drawing": "bắt đầu vẽ %1", "stop_drawing": "ngừng vẽ %1", "set_color": "thiết lập màu cọ bằng %1 %2", "set_random_color": "thiết lập màu cọ ngẫu nhiên %1", "change_thickness": "Thay đổi độ dày bằng %1 %2", "set_thickness": "thiết lập độ dày %1 %2", "change_opacity": "thay đổi độ mờ bằng %1 % %2", "set_opacity": "thiết lập độ mờ bằng %1 % %2", "brush_erase_all": "xóa hết cọ %1", "brush_stamp": "đóng dấu %1", "change_brush_transparency": "thay đổi độ trong suốt bằng %1 % %2", "set_brush_tranparency": "thiết lập độ trong suốt của cọ bằng %1 % %2", "number": "%1", "angle": "%1", "color": "%1", "get_x_coordinate": "%1", "get_y_coordinate": "%1", "get_angle": "%1", "get_rotation_direction": "%1 ", "distance_something": "%1 %2 %3", "coordinate_mouse": "%1 %2 %3", "coordinate_object": "%1 %2 %3 %4", "calc_basic": "%1 %2 %3", "calc_plus": "%1 %2 %3", "calc_minus": "%1 %2 %3", "calc_times": "%1 %2 %3", "calc_divide": "%1 %2 %3", "calc_mod": "%1 %2 %3", "calc_share": "%1 %2 %3", "calc_operation": "%1 %2 %3 %4", "calc_rand": "%1 %2 %3 %4 %5", "get_date": "%1 %2 %3", "get_sound_duration": "%1 %2 %3", "get_user_name": "User ID", "get_nickname": "Nickname", "reset_project_timer": "%1", "set_visible_project_timer": "%1 %2 %3 %4", "timer_variable": "%1 %2", "get_project_timer_value": "%1 %2", "char_at": "%1 %2 %3 %4 %5", "length_of_string": "%1 %2 %3", "substring": "%1 %2 %3 %4 %5 %6 %7", "replace_string": "%1 %2 %3 %4 %5 %6 %7", "change_string_case": "%1 %2 %3 %4 %5 ", "index_of_string": "%1 %2 %3 %4 %5", "combine_something": "%1 %2 %3 %4 %5", "get_sound_volume": "%1 %2", "quotient_and_mod": "%1 %6 %3 %2 %5 %4", "choose_project_timer_action": "%1 %2 %3 %4 ", "wait_second": "chờ %1 giây %2", "repeat_basic": "lặp lại %1 lần %2", "hidden_loop": "lặp lại %1 lần %2", "repeat_inf": "lặp lại liên tục %1", "stop_repeat": "ngừng lặp lại %1", "wait_until_true": "chờ đến %1 %2", "_if": "nếu %1 thì %2", "if_else": "nếu %1 thì %2 %3 hoặc", "create_clone": "tạo bản sao %1 của %2", "delete_clone": "Loại bỏ bản sao này %1", "when_clone_start": "%1 khi bản sao được loại bỏ", "stop_run": "đóng chương trình %1", "repeat_while_true": "lặp lại %2 %1 %3", "stop_object": "dừng lại %1 %2", "restart_project": "khởi động lại dự án %1", "remove_all_clones": "xóa tất cả các bản sao %1", "functionAddButton": "%1", "function_field_label": "%1%2", "function_field_string": "%1%2", "function_field_boolean": "%1%2", "function_param_string": "ký tự/số", "function_param_boolean": "giá trị đánh giá", "function_create": "xác định chức năng %1 %2", "function_general": "chức năng %1", "expansionBlockAddButton": "%1", "aiUtilizeBlockAddButton": "%1", "aiUtilizeModelTrainButton": "%1", "weather_title": "%1", "check_weather": "%1 %2's weather is %3?", "check_finedust": "Current %1's fine dust grade is %2?", "get_weather_data": "%1 %2's %3", "get_current_weather_data": "Current %1's %2", "get_today_temperature": "Today %1's %2h temperature(℃)", "check_city_weather": "%1 %2 %3's weather is %4?", "check_city_finedust": "Current %1 %2's fine dust grade is %3?", "get_city_weather_data": "%1 %2 %3's %4", "get_current_city_weather_data": "Current %1 %2's %3", "get_today_city_temperature": "Today %1 %2's %3h temperature(℃)", "translate_title": "%1", "get_translated_string": "Translate %1 %2 into %3", "check_language": "language of %1", "festival_title": "%1", "count_festival": "%1 %2's number of events", "get_festival_info": "%4 of item %3 of event in %1 %2", "behaviorConductDisaster_title": "%1", "count_disaster_behavior": "%1 %2 behavior-guidelines's number", "get_disaster_behavior": "value of item %3 of %1 %2 behavior-guidelines", "behaviorConductLifeSafety_title": "%1", "count_lifeSafety_behavior": "%1 %2 behavior-guidelines's number", "get_lifeSafety_behavior": "value of item %3 of %1 how to %2", "tts_title": "%1", "audio_title": "%1", "video_title": "%1", "read_text": "read %1 %2", "set_tts_property": "set in a %1 voice at %2 speed and %3 pitch %4", "read_text_wait_with_block": "read %1 and wait %2", "load_expansion_block": "add", "load_ai_utilize_block": "Load AI Block", "load_ai_utilize_train_block": "Train Model", "expansion_block_descriptions": "The expansion block works normally when the Internet is connected.", "aiUtilize_block_descriptions": "The A.I. Utilization block works normally when the Internet is connected.", "weather_title_text": "weather", "translate_title_text": "translate", "festival_title_text": "festival", "audio_title_text": "Audio Sensing", "check_microphone": "Connected with microphone?", "get_microphone_volume": "Microphone volume", "speech_to_text_convert": "Recognize the voice %1", "speech_to_text_get_value": "Text Value Converted from Speech", "video_title_text": "Video Detection", "video_draw_webcam": "%1 the video screen", "video_check_webcam": "connected with video?", "video_set_camera_opacity_option": "Set video transparency effect to %1 %2", "video_flip_camera": "Flip video screen %1 %2", "video_toggle_model": "%1 recognition %2 %3", "video_toggle_ind": "%2 detected %1 %3", "video_number_detect": "Number of detected %1", "video_detected_face_info": "%2 of %1 th face", "video_motion_value": "Video %2 value on %1", "video_face_part_coord": "%3 coordinate of %2 in %1 th face", "video_body_part_coord": "%3 coordinate of %1 th human's %2", "behaviorConductDisaster_title_text": "desaster", "behaviorConductLifeSafety_title_text": "lifeSafety", "tts_title_text": "read", "hamster_hand_found": "tìm tay?", "hamster_value": "%1", "hamster_move_forward_once": "di chuyển về phía trước một lần trên bảng %1", "hamster_turn_once": "quay lại một lần %1 trên bảng", "hamster_move_forward_for_secs": "di chuyển về phía trước %1 giây %2", "hamster_move_backward_for_secs": "di chuyển về phía sau %1 giây %2", "hamster_turn_for_secs": "quay lại %1 %2 giây %3", "hamster_change_both_wheels_by": "thay đổi bánh xe bên trái: %1 phải: %2 %3", "hamster_set_both_wheels_to": "thiết lập bánh xe bên trái: %1 phải: %2 %3", "hamster_change_wheel_by": "thay đổi %1 bằng %2 %3", "hamster_set_wheel_to": "thiết lập %1 bằng %2 %3", "hamster_follow_line_using": "theo dòng %1 bằng cách sử dụng %2 cảm biến sàn %3", "hamster_follow_line_until": "theo dòng %1 cho đến %2 giao lộ %3", "hamster_set_following_speed_to": "thiết lập theo dõi tốc độ %1 %2", "hamster_stop": "dừng lại %1 ", "hamster_set_led_to": "thiết lập %1 thành %2 %3", "hamster_clear_led": "xóa %1 %2", "hamster_beep": "tiếng bíp bíp %1", "hamster_change_buzzer_by": "thay đổi chuông bằng %1 %2", "hamster_set_buzzer_to": "thiết lập chuông bằng %1 %2", "hamster_clear_buzzer": "xóa chuông %1", "hamster_play_note_for": "phát âm %1 %2 cho %3 nhịp %4", "hamster_rest_for": "nghỉ %1 nhịp %2", "hamster_change_tempo_by": "thay đổi nhịp độ bằng %1 %2", "hamster_set_tempo_to": "thiết lập nhịp độ bằng %1 bpm %2", "hamster_set_port_to": "thiết lập cổng %1 bằng %2 %3", "hamster_change_output_by": "thay đổi đầu ra %1 bằng %2 %3", "hamster_set_output_to": "thiết lập đầu ra %1 thành %2 %3", "roboid_hamster_beep": "Hamster %1: beep %2", "roboid_hamster_change_both_wheels_by": "Hamster %1: change wheels by left: %2 right: %3 %4", "roboid_hamster_change_buzzer_by": "Hamster %1: change buzzer by %2 %3", "roboid_hamster_change_output_by": "Hamster %1: change output %2 by %3 %4", "roboid_hamster_change_tempo_by": "Hamster %1: change tempo by %2 %3", "roboid_hamster_change_wheel_by": "Hamster %1: change %2 wheel by %3 %4", "roboid_hamster_clear_buzzer": "Hamster %1: clear buzzer %2", "roboid_hamster_clear_led": "Hamster %1: clear %2 led %3", "roboid_hamster_follow_line_until": "Hamster %1: follow %2 line until %3 intersection %4", "roboid_hamster_follow_line_using": "Hamster %1: follow %2 line using %3 floor sensor %4", "roboid_hamster_hand_found": "Hamster %1: hand found?", "roboid_hamster_move_backward_for_secs": "Hamster %1: move backward for %2 secs %3", "roboid_hamster_move_forward_for_secs": "Hamster %1: move forward for %2 secs %3", "roboid_hamster_move_forward_once": "Hamster %1: move forward once on board %2", "roboid_hamster_play_note_for": "Hamster %1: play note %2 %3 for %4 beats %5", "roboid_hamster_rest_for": "Hamster %1: rest for %2 beats %3", "roboid_hamster_set_both_wheels_to": "Hamster %1: set wheels to left: %2 right: %3 %4", "roboid_hamster_set_buzzer_to": "Hamster %1: set buzzer to %2 %3", "roboid_hamster_set_following_speed_to": "Hamster %1: set following speed to %2 %3", "roboid_hamster_set_led_to": "Hamster %1: set %2 led to %3 %4", "roboid_hamster_set_output_to": "Hamster %1: set output %2 to %3 %4", "roboid_hamster_set_port_to": "Hamster %1: set port %2 to %3 %4", "roboid_hamster_set_tempo_to": "Hamster %1: set tempo to %2 bpm %3", "roboid_hamster_set_wheel_to": "Hamster %1: set %2 wheel to %3 %4", "roboid_hamster_stop": "Hamster %1: stop %2", "roboid_hamster_turn_for_secs": "Hamster %1: turn %2 for %3 secs %4", "roboid_hamster_turn_once": "Hamster %1: turn %2 once on board %3", "roboid_hamster_value": "Hamster %1: %2", "roboid_turtle_button_state": "Turtle %1: button %2 ?", "roboid_turtle_change_buzzer_by": "Turtle %1: change buzzer by %2 %3", "roboid_turtle_change_head_led_by_rgb": "Turtle %1: change head led by r: %2 g: %3 b: %4 %5", "roboid_turtle_change_tempo_by": "Turtle %1: change tempo by %2 %3", "roboid_turtle_change_wheel_by": "Turtle %1: change %2 wheel by %3 %4", "roboid_turtle_change_wheels_by_left_right": "Turtle %1: change wheels by left: %2 right: %3 %4", "roboid_turtle_clear_head_led": "Turtle %1: clear head led %2", "roboid_turtle_clear_sound": "Turtle %1: clear sound %2", "roboid_turtle_cross_intersection": "Turtle %1: cross black intersection %2", "roboid_turtle_follow_line": "Turtle %1: follow %2 line %3", "roboid_turtle_follow_line_until": "Turtle %1: follow black line until %2 %3", "roboid_turtle_follow_line_until_black": "Turtle %1: follow %2 line until black %3", "roboid_turtle_is_color_pattern": "Turtle %1: color pattern %2 %3 ?", "roboid_turtle_move_backward_unit": "Turtle %1: move backward %2 %3 %4", "roboid_turtle_move_forward_unit": "Turtle %1: move forward %2 %3 %4", "roboid_turtle_pivot_around_wheel_unit_in_direction": "Turtle %1: pivot around %2 wheel %3 %4 in %5 direction %6", "roboid_turtle_play_note": "Turtle %1: play note %2 %3 %4", "roboid_turtle_play_note_for_beats": "Turtle %1: play note %2 %3 for %4 beats %5", "roboid_turtle_play_sound_times": "Turtle %1: play sound %2 %3 times %4", "roboid_turtle_play_sound_times_until_done": "Turtle %1: play sound %2 %3 times until done %4", "roboid_turtle_rest_for_beats": "Turtle %1: rest for %2 beats %3", "roboid_turtle_set_buzzer_to": "Turtle %1: set buzzer to %2 %3", "roboid_turtle_set_following_speed_to": "Turtle %1: set following speed to %2 %3", "roboid_turtle_set_head_led_to": "Turtle %1: set head led to %2 %3", "roboid_turtle_set_head_led_to_rgb": "Turtle %1: set head led to r: %2 g: %3 b: %4 %5", "roboid_turtle_set_tempo_to": "Turtle %1: set tempo to %2 bpm %3", "roboid_turtle_set_wheel_to": "Turtle %1: set %2 wheel to %3 %4", "roboid_turtle_set_wheels_to_left_right": "Turtle %1: set wheels to left: %2 right: %3 %4", "roboid_turtle_stop": "Turtle %1: stop %2", "roboid_turtle_touching_color": "Turtle %1: touching %2 ?", "roboid_turtle_turn_at_intersection": "Turtle %1: turn %2 at black intersection %3", "roboid_turtle_turn_unit_in_place": "Turtle %1: turn %2 %3 %4 in place %5", "roboid_turtle_turn_unit_with_radius_in_direction": "Turtle %1: turn %2 %3 %4 with radius %5 cm in %6 direction %7", "roboid_turtle_value": "Turtle %1: %2", "turtle_button_state": "button %1 ?", "turtle_change_buzzer_by": "change buzzer by %1 %2", "turtle_change_head_led_by_rgb": "change head led by r: %1 g: %2 b: %3 %4", "turtle_change_tempo_by": "change tempo by %1 %2", "turtle_change_wheel_by": "change %1 wheel by %2 %3", "turtle_change_wheels_by_left_right": "change wheels by left: %1 right: %2 %3", "turtle_clear_head_led": "clear head led %1", "turtle_clear_sound": "clear sound %1", "turtle_cross_intersection": "cross black intersection %1", "turtle_follow_line": "follow %1 line %2", "turtle_follow_line_until": "follow black line until %1 %2", "turtle_follow_line_until_black": "follow %1 line until black %2", "turtle_is_color_pattern": "color pattern %1 %2 ?", "turtle_move_backward_unit": "move backward %1 %2 %3", "turtle_move_forward_unit": "move forward %1 %2 %3", "turtle_pivot_around_wheel_unit_in_direction": "pivot around %1 wheel %2 %3 in %4 direction %5", "turtle_play_note": "play note %1 %2 %3", "turtle_play_note_for_beats": "play note %1 %2 for %3 beats %4", "turtle_play_sound_times": "play sound %1 %2 times %3", "turtle_play_sound_times_until_done": "play sound %1 %2 times until done %3", "turtle_rest_for_beats": "rest for %1 beats %2", "turtle_set_buzzer_to": "set buzzer to %1 %2", "turtle_set_following_speed_to": "set following speed to %1 %2", "turtle_set_head_led_to": "set head led to %1 %2", "turtle_set_head_led_to_rgb": "set head led to r: %1 g: %2 b: %3 %4", "turtle_set_tempo_to": "set tempo to %1 bpm %2", "turtle_set_wheel_to": "set %1 wheel to %2 %3", "turtle_set_wheels_to_left_right": "set wheels to left: %1 right: %2 %3", "turtle_stop": "stop %1", "turtle_touching_color": "touching %1 ?", "turtle_turn_at_intersection": "turn %1 at black intersection %2", "turtle_turn_unit_in_place": "turn %1 %2 %3 in place %4", "turtle_turn_unit_with_radius_in_direction": "turn %1 %2 %3 with radius %4 cm in %5 direction %6", "turtle_value": "%1", "is_clicked": "%1", "is_press_some_key": "%1 %2", "reach_something": "%1 %2 %3", "boolean_comparison": "%1 %2 %3", "boolean_equal": "%1 %2 %3", "boolean_bigger": "%1 %2 %3", "boolean_smaller": "%1 %2 %3", "boolean_and_or": "%1 %2 %3", "boolean_and": "%1 %2 %3", "boolean_or": "%1 %2 %3", "boolean_not": "%1 %2 %3", "is_boost_mode": "%1", "true_or_false": "%1", "True": "%1", "False": "%1", "boolean_basic_operator": "%1 %2 %3", "show": "hiển thị %1", "hide": "ẩn %1", "dialog_time": "nói %1 cho %2 giây %3 %4", "dialog": "nói %1 %2 %3", "remove_dialog": "xóa bài nói %1", "change_to_nth_shape": "thay đổi bằng hình dạng %1 %2", "change_to_next_shape": "thay đổi bằng hình dạng %1 %2", "set_effect_volume": "thay đổi %1 hiệu ứng bằng %2 %3", "set_effect": "thiết lập %1 hiệu ứng bằng %2 %3", "erase_all_effects": "xóa tất cả các hiệu ứng %1", "change_scale_percent": "thay đổi kích cỡ bằng %1 %2", "set_scale_percent": "thiết lập kích cỡ thành %1 %2", "change_scale_size": "thay đổi kích cỡ bằng %1 %2", "set_scale_size": "thiết lập kích cỡ thành %1 %2", "flip_y": "lật ngang %1", "flip_x": "lật dọc %1", "set_object_order": "đi đến lớp thứ %1 %2", "get_pictures": "%1 ", "change_to_some_shape": "thay đổi bằng hình dạng %1 %2", "add_effect_amount": "thay đổi %1 hiệu ứng bằng %2 %3", "change_effect_amount": "thiết lập %1 hiệu ứng bằng %2 %3", "set_effect_amount": "thay đổi %1 hiệu ứng bằng %2 %3", "set_entity_effect": "thiết lập %1 hiệu ứng bằng %2 %3", "change_object_index": "mang đến cho %1 %2", "move_direction": "di chuyển %1 về phía trước %2", "move_x": "thay đổi X bằng %1 %2", "move_y": "thay đổi Y bằng %1 %2", "locate_xy_time": "di chuyển trong %1 giây đến x: %2, y: %3 %4", "rotate_by_angle": "xoay %1 độ %2", "rotate_by_angle_dropdown": "xoay %1 độ %2", "see_angle": "thiết lập phương hướng bằng %1 %2", "see_direction": "xoay thành %1 %2", "locate_xy": "di chuyển đến X: %1 Y: %2 %3", "locate_x": "di chuyển đến X: %1 %2", "locate_y": "di chuyển đến Y: %1 %2", "locate": "di chuyển đến %1 %2", "move_xy_time": "trong %1 giây di chuyển đến X: %2 Y: %3 %4", "rotate_by_angle_time": "xoay trong %1 giây bằng %2 độ %3", "bounce_wall": "nếu ở cạnh màn hình thì bật ra %1", "flip_arrow_horizontal": "lật ngang theo hướng mũi tên %1", "flip_arrow_vertical": "lật dọc theo hướng mũi tên %1", "see_angle_object": "chuyển hướng tới %1 %2", "see_angle_direction": "thiết lập góc độ bằng %1 độ %2", "rotate_direction": "thay đổi phương hướng bằng %1 %2", "locate_object_time": "trong %1 giây di chuyển đến %2 %3", "rotate_absolute": "thiết lập hướng bằng %1 %2", "rotate_relative": "xoay hướng %1 %2", "direction_absolute": "thiết lập phương hướng bằng %1 %2", "direction_relative": "thay đổi phương hướng bằng %1 %2", "move_to_angle": "theo hướng %1 và di chuyển %2 %3", "rotate_by_time": "trong %1 giây xoay hướng %2 %3", "direction_relative_duration": "trong %1 giây thiết lập phương hướng bằng %2 %3", "neobot_sensor_value": "giá trị %1", "neobot_turn_left": "xoay hướng %1 %2 %3", "neobot_stop_left": "dừng động cơ bên trái %1", "neobot_turn_right": "xoay hướng động cơ bên phải %1 %2 %3", "neobot_stop_right": "dừng động cơ bên phải %1", "neobot_run_motor": "chạy động cơ %1 trong %2 giây", "neobot_servo_1": "Di chuyển động cơ được kết nối đến SERVO1 %2 với tốc độ %1 %3", "neobot_servo_2": "Di chuyển động cơ được kết nối đến SERVO2 %2 với tốc độ %1 %3", "neobot_play_note_for": "phát giai điệu %1 đến quãng tám %2, âm thanh phát ra %3 %4", "neobot_set_sensor_value": "%1 giá trị cổng đến %2 %3", "robotis_openCM70_cm_custom_value": "địa chỉ tùy chỉnh ( %1 ) giá trị %2", "robotis_openCM70_sensor_value": "giá trị điều khiển %1", "robotis_openCM70_aux_sensor_value": "giá trị %1 %2", "robotis_openCM70_cm_buzzer_index": "phát %1 giá trị bộ điều khiển thanh âm trong %2 giây %3", "robotis_openCM70_cm_buzzer_melody": "phát bộ điều khiển giai điệu %1 lần %2", "robotis_openCM70_cm_sound_detected_clear": "phát bộ điều khiển giai điệu %1 lần %2", "robotis_openCM70_cm_led": "bộ điều khiển %1 LED %2 %3", "robotis_openCM70_cm_motion": "mở chuyển động %1 lần", "robotis_openCM70_cm_autodrive_motor": "Ô tô lái tự động %1 sử dụng động cơ %2 %3", "robotis_openCM70_cm_autodrive_ir": "Ô tô tự lái %1 sử dụng cảm biến hồng ngoại %2 %3", "robotis_openCM70_cm_autodrive_speed": "Thực hiện lái xe tự trị ở tốc độ %1 %2", "robotis_openCM70_aux_car_move": "Làm cho robot đi %2 với tốc độ %1% %3", "robotis_openCM70_aux_motor_speed": "Thiết lập tốc độ giảm tốc động cơ của %1 tới %2 , và giá trị đầu ra đến %3% %4", "robotis_openCM70_aux_servo_mode": "Thiết lập chế độ của %1 động cơ servo bằng %2 %3", "robotis_openCM70_aux_servo_speed": "Thiết lập tốc độ tốc động cơ servo của %1 tới %2, và giá trị đầu ra đến %3% %4", "robotis_openCM70_aux_servo_position": "Thiết lập vị trí của %1 động cơ servo bằng %2 độ %3", "robotis_openCM70_aux_led_module": "thiết lập %1 mô-đun LED như %2 %3", "robotis_openCM70_aux_custom": "thiết lập %1 thiết bị người dùng như %2 %3", "robotis_openCM70_cm_poweroff_timer": "Bộ hẹn giờ tự động tắt bộ điều khiển %1 %2", "robotis_openCM70_cm_custom": "thiết lập địa chỉ tùy chỉnh ( %1 ) như %2 %3", "robotis_carCont_sensor_value": "giá trị %1", "robotis_carCont_cm_led": "%1 LED 4, %2 LED %3", "robotis_carCont_cm_sound_detected_clear": "khởi tạo số cuối cùng phát hiện âm thanh %1", "robotis_carCont_aux_motor_speed": "Thiết lập tốc độ giảm tốc động cơ của %1 tới %2, và giá trị đầu ra đến %3 %4", "robotis_carCont_cm_calibration": "Thiết lập %1 giá trị của cảm biến hồng ngoại hiệu chuẩn bằng %2 %3", "roduino_get_analog_number": "%1 ", "roduino_get_port_number": "%1 ", "roduino_get_analog_value": "Analog %1 Sensor value ", "roduino_get_digital_value": "Digital %1 Sensor value ", "roduino_set_digital": "Digital %1 Pin %2 %3", "roduino_motor": "%1 %2 %3", "roduino_set_color_pin": "Color Sensor R : %1, G : %2, B : %3 %4", "roduino_get_color": "Color Sensor %1 Detected ", "roduino_on_block": " On ", "roduino_off_block": " Off ", "schoolkit_get_in_port_number": "%1 ", "schoolkit_get_out_port_number": "%1 ", "schoolkit_get_servo_port_number": "%1 ", "schoolkit_get_input_value": "Digital %1 Sensor value ", "schoolkit_set_output": "Digital %1 Pin %2 %3", "schoolkit_motor": "%1 Speed %2 %3 %4", "schoolkit_set_servo_value": "Servo %1 Pin %2˚ %3", "schoolkit_on_block": " On ", "schoolkit_off_block": " Off ", "when_scene_start": "%1 khi cảnh tượng bắt đầu", "start_scene": "bắt đầu %1 cảnh %2", "start_neighbor_scene": "bắt đầu %1 cảnh %2", "sound_something": "phát %1 âm thanh %2", "sound_something_second": "phát %1 âm thanh trong %2 giây %3", "sound_something_wait": "phát %1 âm thanh và chờ %2", "sound_something_second_wait": "phát %1 âm thanh trong %2 giây và chờ %3", "sound_volume_change": "thay đổi âm lượng bằng %1 % %2", "sound_volume_set": "thiết lập âm lượng bằng %1 % %2", "sound_silent_all": "dừng tất cả âm thanh %1", "get_sounds": "%1 ", "sound_something_with_block": "phát %1 âm thanh %2", "sound_something_second_with_block": "phát %1 âm thanh trong %2 giây %3", "sound_something_wait_with_block": "phát %1 âm thanh và chờ %2", "sound_something_second_wait_with_block": "phát %1 âm thanh trong %2 giây và chờ %3", "sound_from_to": "phát %1 âm thanh từ %2 đến %3 giây %4", "sound_from_to_and_wait": "phát %1 âm thanh từ %2 đến %3 giây và chờ %4", "when_run_button_click": "%1 khi chạy", "press_some_key": "%1 khi phím %2 được nhấn %3", "when_some_key_pressed": "%1 khi phím %2 được nhấn", "mouse_clicked": "%1 khi nhấp chuột", "mouse_click_cancled": "%1 khi thả nhấp chuột", "when_object_click": "%1 khi nhấp vào đối tượng", "when_object_click_canceled": "%1 khi thả nhấp chuột trên đối tượng", "when_some_key_click": "%1 khi nhấn phím", "when_message_cast": "%1 khi nhận được %2 tin nhắn", "message_cast": "gửi %1 tin nhắn %2", "message_cast_wait": "gửi %1 tin nhắn và chờ %2", "text": "%1", "text_read": "Textbox %1’s contents", "text_write": "viết là %1 %2", "text_append": "sau khi viết là %1 %2", "text_prepend": "thêm %1 trước %2", "text_flush": "xóa hết văn bản %1", "analizyDataAddButton": "%1", "append_row_to_table": "Add a %2 to the table %1 %3", "insert_row_to_table": "Insert %3 to %2th row from the %1 %4", "delete_row_from_table": "Remove %2th %3 from table %1 %4", "set_value_from_table": "Change %3 in the %1 %2th row to %4 %5", "get_table_count": "length of %2 in the %1", "get_value_from_table": "value of the %3 in %2th row of the %1", "calc_values_from_table": "%3 of the %2 in the %1", "open_table_chart": "Open the chart of the %1 %2", "close_table_chart": "Close the table chart", "get_coefficient": 'Correlation coefficient between %2and %3 in table %1', "variableAddButton": "%1", "listAddButton": "%1", "change_variable": "thêm vào %1 bằng %2 %3", "set_variable": "thiết lập %1 bằng %2 %3", "show_variable": "hiển thị biến số %1 giá trị %2", "hide_variable": "ẩn biến số %1 giá trị %2", "get_variable": "%2 %1", "ask_and_wait": "hỏi %1 và trả lời %2", "get_canvas_input_value": "%1 ", "add_value_to_list": "thêm %1 vào danh sách %2 %3", "remove_value_from_list": "xóa hạng mục thứ %1 từ %2 %3", "insert_value_to_list": "chèn %1 đến vị trí thứ %3 của %2 %4", "change_value_list_index": "thay đổi hạng mục thứ %1 %2 đến %3 %4", "value_of_index_from_list": "thay đổi hạng mục thứ %1 %2 đến %3 %4", "length_of_list": "%1 %2 %3", "show_list": "hiển thị danh sách %1 %2", "hide_list": "ẩn danh sách %1 %2", "options_for_list": "%1 ", "set_visible_answer": "trả lời %1 %2", "is_included_in_list": "%1 %2 %3 %4 %5", "xbot_digitalInput": "%1", "xbot_analogValue": "%1", "xbot_digitalOutput": "kỹ thuật số %1 Pin, dữ liệu đầu ra %2 %3", "xbot_analogOutput": "Analog %1 %2 %3", "xbot_servo": "động cơ servo %1 góc độ %2 %3", "xbot_oneWheel": "động cơ bánh xe (DC) %1, tốc độ %2 %3", "xbot_twoWheel": "động cơ bánh xe (DC) tốc độ bên phải (2): %1 tốc độ bên trái(1): %2 %3", "xbot_rgb": "màu RGB LED từ màu đỏ %1 xanh lá cây %2 xanh dương %3 %4", "xbot_rgb_picker": "màu RGB LED từ %1 %2", "xbot_buzzer": "phát âm %1 %2 trong %3 giây phát giai điệu %4", "xbot_lcd": "LCD dòng thứ %1, văn bản %2 %3", "run": "", "mutant": "kiểm tra đột biến khối", "jr_start": "%1", "jr_repeat": "lần %1 %2", "jr_item": "thu thập hoa %1", "cparty_jr_item": "nhấc %1", "jr_north": "lên %1", "jr_east": "Bên phải %1", "jr_south": "xuống %1", "jr_west": "Bên trái %1", "jr_start_basic": "%1 %2", "jr_go_straight": "tiến về phía trước %1", "jr_turn_left": "quay sang trái %1", "jr_turn_right": "quay sang phải %1", "jr_go_slow": "đi chậm %1", "jr_repeat_until_dest": "Lặp lại cho đến khi gặp %1 %2", "jr_if_construction": "nếu phía trước là %1 thì %2", "jr_if_speed": "nếu phía trước là %1 thì %2", "maze_step_start": "%1 khi chạy", "maze_step_jump": "bỏ qua %1", "maze_step_jump2": "Jump%1", "maze_step_jump_pinkbean": "Jump%1", "maze_step_for": "lặp lại %1 lần %2", "test": "%1 đây là khối văn bản %2 ", "maze_repeat_until_1": "Lặp lại cho đến khi gặp %1 %2 ", "maze_repeat_until_2": "Lặp lại cho đến khi gặp tất cả %1 %2 ", "maze_step_if_1": "nếu phía trước có %1 thì %2", "maze_step_if_2": "nếu phía trước có %1 thì %2", "maze_call_function": "nhập cuộc hẹn %1", "maze_define_function": "cuộc hẹn %1", "maze_step_if_3": "nếu phía trước có %1 thì %2", "maze_step_if_4": "nếu phía trước có %1 thì %2", "maze_step_move_step": "di chuyển về phía trước 1 bước %1", "maze_step_rotate_left": "quẹo trái %1", "maze_step_rotate_right": "quẹo phải %1", "maze_step_forward": "tiến về phía trước %1", "maze_turn_right": "tiến về phía trước %1", "maze_turn_left": "tiến về phía trước %1", "maze_ladder_climb": "Climb ladder%1", "maze_attack_lupin": "Attack %1 %2", "maze_attack_both_side": "Attack both sides%1", "maze_attack_pepe": "Attack %1 %2", "maze_attack_yeti": "Attack %1 %2", "maze_attack_mushroom": "Attack %1 %2", "maze_attack_peti": "Attack %1 %2", "maze_eat_item": "Take food%1", "maze_step_if_mushroom": "If there is %1 one space forward %2", "maze_step_if_yeti": "If there is %1 in front %2 %3 else", "maze_step_if_left_monster": "If there is a monster in the left side attack range %1 %2 else", "maze_step_if_right_monster": "If there is a monster in the right side attack range %1 %2 else", "maze_step_if_lupin": "If there is %1 two spaces forward %2", "maze_step_if_else_road": "If there is road one space forward %1 %2else", "maze_step_if_else_mushroom": "If there is %1 one space forward %2 %3 else", "maze_step_if_else_lupin": "If there is %1 two spaces forward %2 %3 else", "maze_step_if_else_ladder": "If there is %1 one space forward %2 %3 else", "maze_rotate_left": "quay sang trái %1", "maze_rotate_right": "quay sang phải %1", "maze_moon_kick": "đá %1", "maze_repeat_until_3": "Lặp lại cho đến khi gặp %1 %2 ", "maze_repeat_until_4": "Lặp lại cho đến khi gặp %1 %2 ", "maze_repeat_until_5": "Lặp lại cho đến khi gặp %1 %2 ", "maze_repeat_until_6": "Lặp lại cho đến khi đến nơi %1 %2 ", "maze_repeat_until_7": "Repeat until reaching %1 %2", "maze_repeat_until_goal": "Repeat until arrival to destination%1", "maze_repeat_until_beat_monster": "Repeat until all monsters are defeated %1", "maze_radar_check": "trong %1 có %2", "maze_cony_flower_throw": "ném hoa %1", "maze_brown_punch": "đấm %1", "maze_iron_switch": "điều khiển chướng ngại vật %1", "maze_james_heart": "gửi tim %1", "maze_step_if_5": "nếu phía trước không có con đường thì %2", "maze_step_if_6": "nếu phía trước không có %1 thì %2", "maze_step_if_7": "nếu phía trước không có %1 thì %2", "maze_step_if_8": "nếu là %1 thì %2", "maze_step_if_else": "nếu là %1 thì %2 %3 hoặc", "test_wrapper": "%1 đây là khối văn bản %2 ", "basic_button": "%1", "ai_move_right": "di chuyển về phía trước %1", "ai_move_up": "đi lên trên %1", "ai_move_down": "đi xuống dưới %1", "ai_repeat_until_reach": "lặp lại cho đến khi đến đích %1 ", "ai_if_else_1": "nếu phía trước có %1 thì %2 %3 còn không thì", "ai_boolean_distance": "%1 ra-đa %2 %3", "ai_distance_value": "%1 ra-đa", "ai_boolean_object": "đối tượng %1 có phải là %2 không?", "ai_use_item": "sử dụng hệ thống %1", "ai_boolean_and": "%1 %2 %3", "ai_True": "%1", "ai_if_else": "nếu là %1 thì %2 %3 còn không thì", "smartBoard_convert_scale": "Map Value %1 %2 ~ %3 to %4 ~ %5", "smartBoard_get_named_sensor_value": "%1 Sensor value", "smartBoard_is_button_pressed": "Pressed %1 button?", "smartBoard_set_dc_motor_direction": "%1 DC Motor change direction %2 %3", "smartBoard_set_dc_motor_speed": "%1 DC Motor %2 %3", "smartBoard_set_dc_motor_pwm": "%1 DC Motor set speed %2 %3", "smartBoard_set_servo_speed": "%1 RC Servo Motor Speed %2 %3", "smartBoard_set_servo_angle": "%1 RC Servo Motor set angle %2 %3", "smartBoard_set_number_eight_pin": "%1 port %2 %3", "smartBoard_set_gs1_pwm": "GS1 port %1 %2", "robotori_digitalInput": "%1", "robotori_analogInput": "%1", "robotori_digitalOutput": "Digital %1 PIN, Output Value %2 %3", "robotori_analogOutput": "Analog %1 %2 %3", "robotori_servo": "Servo Motor Angle %1 %2", "robotori_dc_direction": "DC Motor %1 Direction %2 %3", "dadublock_get_analog_value": "Analog %1 Sensor value", "dadublock_get_analog_value_map": "Map Value %1 %2 ~ %3 to %4 ~ %5 ", "dadublock_get_ultrasonic_value": "Read ultrasonic sensor trig pin %1 echo pin %2", "dadublock_toggle_led": "Digital %1 Pin %2 %3", "dadublock_digital_pwm": "Digital %1 Pin %2 %3", "dadublock_set_tone": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "dadublock_set_servo": "Set servo pin %1 angle as %2 %3", "coconut_stop_motor": "stop motor %1", "coconut_move_motor": "move %1 %2", "coconut_turn_motor": "turn %1 %2", "coconut_move_for_secs": "move %1 for time %2 %3", "coconut_turn_for_secs": "turn %1 for %2 secs %3", "coconut_turn_to_led": "turn %1 RGB %2 %3", "coconut_move_outmotor": "external Motor %1 speed %2 %3", "coconut_set_led_to": "turn on RGB %1 %2 %3", "coconut_clear_led": "turn off RGB %1 %2", "coconut_set_led_clear": "turn off RGB %1 %2 %3", "coconut_set_led_time": "turn on RGB %1 %2 for time %3 %4", "coconut_beep": "buzzer on %1", "coconut_buzzer_time": "play buzzer for time %1 %2", "coconut_buzzer_set_hz": "play buzzer on frequency %1 Hz for time %2 %3", "coconut_clear_buzzer": "buzzer off %1", "coconut_play_buzzer": "play buzzer on note %1 octave %2 %3 beat %4 %5", "coconut_rest_buzzer": "rest beat %1 %2", "coconut_play_buzzer_led": "play buzzer on note %1 octave %2 %3 beat %4 RGB %5 %6 %7", "coconut_play_midi": "play melody %1 %2", "coconut_floor_sensor": "line tracer %1", "coconut_floor_sensing": "line tracer detect %1 %2", "coconut_following_line": "follow the line %1", "coconut_front_sensor": "IR distance sensor %1", "coconut_front_sensing": "detecting obstacle %1 %2", "coconut_obstruct_sensing": "detecting obstacle", "coconut_avoid_mode": "avoid mode %1", "coconut_dotmatrix_set": "LED Matrix %1 ( ROW %2, COL %3 ) %4", "coconut_dotmatrix_on": "turn on all LED Matrix %1", "coconut_dotmatrix_off": "LED Matrix clear all %1", "coconut_dotmatrix_num": "LED Matrix show %1 %2", "coconut_dotmatrix_small_eng": "LED Matrix show small letter %1 %2", "coconut_dotmatrix_big_eng": "LED Matrix show capital letters %1 %2", "coconut_dotmatrix_kor": "LED Matrix show Korean %1 %2", "coconut_light_sensor": "light sensor", "coconut_tem_sensor": "temperature", "coconut_ac_sensor": "3-Axis Accelerometer %1 angle", "coconut_outled_sensor": "set external LED pin %1 for time %2 %3", "coconut_outspk_sensor": "set Speaker pin %1 frequency %2 (Hz) duration %3 seconds %4", "coconut_outspk_sensor_off": "stop Speaker pin %1 %2", "coconut_outinfrared_sensor": "external IR sensor %1", "coconut_outcds_sensor": "external Cds sensor %1", "coconut_servomotor_angle": "set servo pin %1 angle as %2 %3", "chocopi_control_button": "%1 controller %2 is pressed", "chocopi_control_event": "%1 When %2 controller %3 is %4", "chocopi_control_joystick": "%1 controller %2 value", "chocopi_dc_motor": "%1 DC motor #%2 %3 % direction %4 %5", "chocopi_led": "%1 LED #%2 RGB(%3 %4 %5) %6", "chocopi_motion_photogate_event": "%1 When %2 photogate %3 is %4", "chocopi_motion_photogate_status": "%1 photogate #%2 is blocked", "chocopi_motion_photogate_time": "time when %1 photogate %2 was %3", "chocopi_motion_value": "%1 motion %2 value", "chocopi_sensor": "%1 sensor %2", "chocopi_servo_motor": "%1 set servo motor #%2 %3 degree %4", "chocopi_touch_event": "%1 When %2 touch pad%3 is %4", "chocopi_touch_status": "%1 touch pad%2 is touched", "chocopi_touch_value": "%1 touch pad%2 value", "dadublock_car_digital_pwm": "디지털 %1 번 핀을 %2 (으)로 정하기 %3", "dadublock_car_get_analog_value": "아날로그 %1 번 센서값", "dadublock_car_get_analog_value_map": "아날로그 %1번 센서값의 범위를 %2 ~ %3 에서 %4 ~ %5 (으)로 바꾼값 ", "dadublock_car_get_digital": "디지털 %1 번 센서값", "dadublock_car_get_irsensor": "적외선 %1 번 센서값", "dadublock_car_get_ultrasonic_value": "울트라소닉 Trig %1번핀 Echo %2번핀 센서값", "dadublock_car_motor": "모터 %1 번을 %2 (으)로 %3 %의 속도로 움직이기 %4", "dadublock_car_motor_stop": "모터 %1 번 멈추기 %2", "dadublock_car_set_servo": "서보모터 %1 번 핀을 %2 의 각도로 정하기 %3", "dadublock_car_set_tone": "디지털 %1 번 핀 을 %2 음으로 %3의 옥타브로 %4 만큼 연주하기 %5", "dadublock_car_toggle_led": "디지털 %1 번 핀 %2 %3", "dadublock_get_digital": "디지털 %1 번 센서값", "ev3_get_sensor_value": "%1's value", "ev3_touch_sensor": "%1's touch sensor activted?", "ev3_color_sensor": "%1's %2 value", "ev3_motor_power": "%1's value print as %2 %3", "ev3_motor_power_on_time": "%1's value for %2seconds %3 printed %4", "ev3_motor_degrees": "%1's value in %2 direction turn %3 degrees %4", "rokoboard_get_sensor_value_by_name": "%1 value", "ardublock_digital_pwm": "Digital %1 Pin %2 %3", "ardublock_get_analog_value": "Analog %1 Sensor value", "ardublock_get_analog_value_map": "Map Value %1 %2 ~ %3 to %4 ~ %5", "ardublock_get_digital": "Digital %1 Sensor value", "ardublock_get_left_cds_analog_value": "Left CDS %1 Sensor value", "ardublock_get_right_cds_analog_value": "Left CDS %1 Sensor value", "ardublock_get_sound_analog_value": "Analog Sound %1 Sensor value", "ardublock_get_ultrasonic_value": "Read ultrasonic sensor trig pin %1 echo pin %2", "ardublock_set_left_motor": "Left motor direction to %1 speed %2 set %3", "ardublock_set_right_motor": "Right motor direction to %1 speed %2 set %3", "ardublock_set_servo": "Set servo pin %1 angle as %2 %3", "ardublock_set_tone": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "ardublock_toggle_led": "Digital %1 Pin %2 %3", "ardublock_toggle_left_led": "Left Light %1 Pin %2 %3", "ardublock_toggle_right_led": "Right Light %1 Pin %2 %3", "mkboard_digital_pwm": "Digital %1 Pin %2 %3", "mkboard_get_analog_value": "Analog %1 Sensor value", "mkboard_get_analog_value_map": "Map Value %1 %2 ~ %3 to %4 ~ %5", "mkboard_get_digital": "Digital %1 Sensor value", "mkboard_get_ultrasonic_value": "Read ultrasonic sensor trig pin %1 echo pin %2", "mkboard_set_servo": "Set servo pin %1 angle as %2 %3", "mkboard_set_tone": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "mkboard_toggle_led": "Digital %1 Pin %2 %3", "mkboard_set_lcd": "1602 LCD Row %1, Column %2 Value %3 %4", "mkboard_lcd_command": "1602 LCD Command %1 execute %2", "altino_analogValue": "altino %1 sensor value", "altino_dot_display": "electronic scoreboard %1 display %2", "altino_dot_display_line": "1col %1 2col %2 3col %3 4col %4 5col %5 6col %6 7col %7 8col %8 display %9", "altino_light": "%1 light %2 %3", "altino_rear_wheel": "rear motor right %1 left %2 setting %3", "altino_sound": "%1 octave %2 play %3", "altino_steering": "direction %1 setting %2", "jdkit_altitude": "드론을 %1 높이만큼 날리기 %2", "jdkit_button": "%1번 버튼 값 읽어오기", "jdkit_connect": "드론 연결 상태 읽어오기", "jdkit_emergency": "드론을 즉시 멈추기 %1", "jdkit_gyro": "보드 %1 기울기 값 읽어오기", "jdkit_joystick": "조이스틱 %1 읽기", "jdkit_led": "%1 LED %2 %3", "jdkit_motor": "%1 모터를 %2 세기로 돌리기 %3", "jdkit_ready": "드론 비행 준비 상태 읽어오기", "jdkit_rollpitch": "드론을 %1 방향 %2 세기로 움직이기 %3", "jdkit_throttle": "드론 프로펠러를 %1 만큼 세기로 돌리기 %2", "jdkit_tune": "%1 음을 %2 초동안 소리내기 %3", "jdkit_ultrasonic": "거리(초음파)값 읽어오기", "jdkit_yaw": "드론을 %1 만큼 회전하기 %2", "memaker_digital_pwm": "Digital %1 Pin %2 %3", "memaker_get_analog_value": "Analog %1 Sensor value", "memaker_get_analog_value_map": "Map Value %1 %2 ~ %3 to %4 ~ %5", "memaker_get_digital": "Digital %1 Sensor value", "memaker_get_ultrasonic_value": "Read ultrasonic sensor trig pin %1 echo pin %2", "memaker_set_lcd": "1602 LCD Row %1, Column %2 Value %3 %4", "memaker_set_servo": "Set servo pin %1 angle as %3", "memaker_toggle_led": "Digital %1 Pin %2 %3", "memaker_lcd_command": "1602 LCD Command %1 execute %2", "edumaker_digital_pwm": "디지털 %1 번 핀을 %2 (으)로 정하기 %3", "edumaker_get_analog_value": "아날로그 %1 번 센서값", "edumaker_get_analog_value_map": "%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값", "edumaker_get_digital": "디지털 %1 번 센서값", "edumaker_get_ultrasonic_value": "울트라소닉 Trig %1 Echo %2 센서값", "edumaker_set_servo": "디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3", "edumaker_set_tone": "디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5", "edumaker_toggle_led": "디지털 %1 번 핀 %2 %3", "creamo_get_number_sensor_value": "PWM_Block %1 Sensor value", "creamo_get_port_number": "%1", "creamo_get_pwm_port_number": "%1", "creamo_motor_port_number": "%1", "creamo_toggle_led": "LED_Block %1 Pin %2 %3", "creamo_toggle_motor": "Motor_Block %1 pin %2 %3", "creamo_toggle_pwm": "Digital %1 Pin %2 %3", "mechatro_get_dc_motor_current": "Get 1%motor current", "mechatro_get_digital": "%1", "mechatro_get_sensor_value": "Analog %1 Sensor value", "mechatro_get_ultrasonic_value": "Read ultrasonic sensor trig pin %1 echo pin %2", "mechatro_set_blue_pw": "Change PW of Bluetooth to %1%2%3%4 %5", "mechatro_set_dc_motor": "Set %1 motor speed to %2 %3", "mechatro_set_digital": "Digital %1 Pin %2 %3", "mechatro_set_pwm": "Digital %1 Pin %2 %3", "mechatro_set_servo_position": "Set servo pin %1 angle as %2 %3", "mechatro_set_servo_speed": "Set servo pin %1 speed %2 degree per second %3", "mechatro_set_threshold": "Set %1 threshold : %2%3", "mechatro_set_tone": "Play tone pin %1 on note %2 octave %3 %4", "mechatro_set_tone_time": "Play tone pin %1 on note %2 octave %3 beat %4 %5", "funboard_buzzer_onoff": "buzzer %1 %2", "funboard_buzzer_second": "buzzer%1%2seconds%3", "funboard_buzzer_tone_simple": "play note%1%2,%3sec of Melody Playing%4", "funboard_color_led_on_pwm": "%1COLOR LED %2 % %3", "funboard_color_led_onoff": "%1COLOR LED %2 %3", "funboard_convert_scale": "Convert %1 value from %2~%3 to %4~%5", "funboard_dotmatrix_1column": "%1column %2set %3", "funboard_dotmatrix_1row": "%1row %2set %3", "funboard_dotmatrix_1row_1column": "%1%2 %3set %4", "funboard_dotmatrix_64_display": "%1 (8x8)display%2", "funboard_dotmatrix_big_eng": "capital letters %1 %2", "funboard_dotmatrix_char_display": "char%1display%2", "funboard_dotmatrix_extra_char": "char %1 %2", "funboard_dotmatrix_intensity": "Intensity %1% %2", "funboard_dotmatrix_kor": "∷∷ korean %1 %2", "funboard_dotmatrix_num": "number %1 %2", "funboard_dotmatrix_onoff": "turn all %1 %2", "funboard_dotmatrix_scroll_option": "scroll direction%1%2", "funboard_dotmatrix_scroll_rapid": "scroll rapid %1% %2", "funboard_dotmatrix_set": "%1row %2column %3 %4", "funboard_dotmatrix_small_eng": "small letter %1 %2", "funboard_dotmatrix_string_display": "string%1display%2", "funboard_dotmatrix_string_display_scroll": "string%1display%2scroll%3", "funboard_dotmatrix_symbol": "symbol %1 %2", "funboard_get_analog_sensor_2state": "%1 value %2", "funboard_get_digital_button_value": "%1 button value", "funboard_get_number_sensor_value": "%1 value", "funboard_get_touch_button_value": "%1 touch button value", "funboard_set_digital_buzzer": "Play tone octave %1 note %2 beat %3 %4", "funboard_what_button_pressed": "%1 button pressed.", "funboard_what_touch_button_pressed": "%1 touch button pressed." }; Lang.TextCoding = { "block_name": "Block Name", "title_syntax": "Syntax Error", "title_converting": "Converting Error", "message_syntax_default": "Syntax error occured", "message_syntax_unexpected_token": "Unexpected token exist", "message_syntax_reserved_token": "Unavailable variable name.", "message_syntax_reserved_token_list": "Unavailable list name.", "message_syntax_unexpected_character": "Unexpected characters exist", "message_syntax_unexpected_indent": "Unexpected indent exist", "message_conv_default": "Unsupported code exists", "message_conv_no_support": "Unconvertable code exists", "message_conv_no_variable": "Variable did not declare", "message_conv_no_list": "List did not declare", "message_conv_no_object": "Object can't convert", "message_conv_no_function": "Function can't convert", "message_conv_no_entry_event_function": "Entry Event Function can't exist within other functions.", "message_conv_undefined_function": "Undefined instruction. Please make sure you instruction correctly.", "message_conv_is_expect1": "Syntax error. Please make sure you type ", "message_conv_is_expect2": " correctly.", "message_conv_instead": "Syntax error. It should be %2 instead of %1.", "message_conv_is_wrong1": "Syntax error. ", "message_conv_is_wrong2": " are not allowed to be there.", "message_conv_or": " or ", "subject_syntax_default": "ETC", "subject_syntax_token": "Token", "subject_syntax_character": "Character", "subject_syntax_indent": "Indent", "subject_conv_default": "ETC", "subject_conv_general": "General", "subject_conv_variable": "Variable", "subject_conv_list": "List", "subject_conv_object": "Object", "subject_conv_function": "Function", "alert_variable_empty_text": "You can't convert into the text mode if there is empty text among registered variables.", "alert_list_empty_text": "You can't convert into the text mode if there is empty text among registered lists.", "alert_function_name_field_multi": "You can't convert into the text mode if there is name field block over two times among registered functions.", "alert_function_name_disorder": "You can't convert into the text mode if name field is behind than string/number or judgement param field among registered functions.", "alert_function_has_boolean": "If you convert into the text mode and then back to block coding, the [Judgment] used in the function is converted to [Character/Number].", "alert_function_editor": "Youn can't convert into the text mode in the middle of function creation or editing.", "alert_function_no_support": "Youn can't use the function creation or editing in the text mode.", "alert_list_no_support": "Youn can't use the list creation or editing in the text mode.", "alert_variable_no_support": "Youn can't use the variable creation or editing in the text mode.", "alert_signal_no_support": "Youn can't use the signal creation or editing in the text mode.", "alert_legacy_no_support": "Mode switch is not allowed due to inconvertible blocks", "alert_variable_empty_text_add_change": "The empty text can't be included in variable name.", "alert_list_empty_text_add_change": "The empty text can't be included in list name.", "alert_list_contains_exceed_length_value": "You can't convert into the text mode if more than 15 digits are entered in the list item.", "alert_function_name_empty_text_add_change": "The empty text can't be included in function name.", "alert_no_save_on_error": "The code with an error can't save.", "alert_api_no_support": "The project contains blocks \nthat are not supported by Entry-Python. \nDelete all those blocks and \nchange to Entry-Python mode?", "warn_unnecessary_arguments": "&(calleeName)(); command doesn't require value within parentheses. (line:&(lineNumber))", "python_code": "'s python code", "eof": "line change", "newline": "line change", "indent": "indentation", "num": "number", "string": "string", "name": "variable name" }; Lang.PythonHelper = { "when_run_button_click_desc": "[시작하기]버튼을 클릭하면 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "when_run_button_click_exampleCode": "def when_start():\n Entry.print(\"안녕!\")", "when_run_button_click_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 \"안녕!\"이라 말합니다.", "when_some_key_pressed_desc": "A키를 누르면 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "when_some_key_pressed_elements": "A-- 아래 선택지 중 하나
① 알파벳 : \"A\", \"B\" ~ \"Z\" 등(소문자 가능)
② 숫자 : 1, 2, 3, 4 ~ 9, 0
③ 특수키 : \"space\", \"enter\"
④ 방향키 : \"up\", \"down\", \"right\", \"left\"", "when_some_key_pressed_exampleCode": "def when_press_key(\"W\"):\n Entry.move_to_direction(10)\n\ndef when_press_key(1):\n Entry.add_size(10)", "when_some_key_pressed_exampleDesc": "W키를 누르면 오브젝트가 이동방향으로 10만큼 이동하고, 1키를 누르면 오브젝트의 크기가 10만큼 커집니다.", "mouse_clicked_desc": "마우스를 클릭했을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "mouse_clicked_exampleCode": "def when_click_mouse_on():\n Entry.add_size(10)\n Entry.move_to_direction(10)", "mouse_clicked_exampleDesc": "마우스를 클릭하면 오브젝트의 크기가 10만큼 커지면서 이동방향으로 10만큼 이동합니다.", "mouse_click_cancled_desc": "마우스 클릭을 해제했을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "mouse_click_cancled_exampleCode": "def when_click_mouse_off():\n Entry.move_to_direction(-10)\n\ndef when_click_mouse_on():\n Entry.move_to_direction(10)", "mouse_click_cancled_exampleDesc": "마우스를 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 마우스 클릭을 해제하면 오브젝트가 이동방향으로 -10만큼 이동합니다.", "when_object_click_desc": "해당 오브젝트를 클릭했을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "when_object_click_exampleCode": "def when_click_object_on():\n Entry.print_for_sec(\"회전!\", 0.5)\n Entry.add_rotation(90)", "when_object_click_exampleDesc": "오브젝트를 클릭하면 오브젝트가 \"회전!\"이라 말하고, 90도 만큼 회전합니다.", "when_object_click_canceled_desc": "해당 오브젝트 클릭을 해제했을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "when_object_click_canceled_exampleCode": "def when_click_object_on():\n Entry.add_rotation(90)\n\ndef when_click_object_off():\n Entry.add_rotation(-90)", "when_object_click_canceled_exampleDesc": "오브젝트를 클릭하면 오브젝트가 90도 만큼 회전하고, 오브젝트 클릭을 해제하면 오브젝트가 -90도 만큼 회전합니다.", "when_message_cast_desc": "A 신호를 받으면 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.
만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.", "when_message_cast_elements": "A-- \"신호 이름\"", "when_message_cast_exampleCode": "def when_click_mouse_on():\n Entry.send_signal(\"신호\")\n\ndef when_get_signal(\"신호\"):\n Entry.print_for_sec(\"안녕! 반가워\", 0.5)", "when_message_cast_exampleDesc": "마우스를 클릭하면 \"신호\"를 보내고, \"신호\"를 받았을때 \"안녕! 반가워\"라고 0.5초간 말합니다.", "message_cast_desc": "A에 입력된 신호를 보냅니다.
만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.", "message_cast_elements": "A-- \"신호 이름\"", "message_cast_exampleCode": "#\"오브젝트1\"의 파이선 코드\ndef when_start():\n Entry.print_for_sec(\"안녕! 넌 몇살이니?\", 2)\n Entry.send_signal(\"신호\")\n\n#\"오브젝트2\"의 파이선 코드\ndef when_get_signal(\"신호\"):\n Entry.print_for_sec(\"안녕? 난 세 살이야.\", 2)", "message_cast_exampleDesc": "[시작하기]버튼을 클릭하면 \"오브젝트1\"이 \"안녕! 넌 몇살이니?\"라고 2초간 말하고 \"신호를 보냅니다., \"오브젝트2\"가 \"신호\"를 받았을때 \"안녕? 난 세 살이야.\"라고 2초간 말합니다.", "message_cast_wait_desc": "A에 입력된 신호를 보내고, 해당 신호를 받는 명령어들의 실행이 끝날 때까지 기다립니다.
만약 A 신호가 없으면 [속성] 탭에 A 신호가 자동 생성됩니다.", "message_cast_wait_elements": "A-- \"신호 이름\"", "message_cast_wait_exampleCode": "#\"오브젝트1\"의 파이선 코드\ndef when_start():\n Entry.print_for_sec(\"숨바꼭질하자!\", 2)\n Entry.send_signal_wait(\"신호\")\n Entry.hide()\n\n#\"오브젝트2\"의 파이선 코드\ndef when_get_signal(\"신호\"):\n Entry.print_for_sec(\"그래!\", 2)", "message_cast_wait_exampleDesc": "[시작하기]버튼을 클릭하면 \"오브젝트1\"이 \"숨바꼭질하자!\"라고 2초 동안 말하고 \"신호\"를 보낸 후 기다립니다. \"오브젝트2\"가 \"신호\"를 받으면 \"그래!\"를 2초 동안 말합니다. \"오브젝트1\"이 그 후에 모양을 숨깁니다.", "when_scene_start_desc": "장면이 시작되면 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "when_scene_start_exampleCode": "#\"장면 1\"의 파이선 코드\ndef when_start():\n Entry.print_for_sec(\"다른 곳으로 가볼까?\", 2)\n Entry.start_scene(\"장면 2\")\n\n#\"장면 2\"의 파이선 코드\ndef when_start_scene():\n Entry.print(\"여기가 어디지?\")", "when_scene_start_exampleDesc": "\"장면 1\"에서 [시작하기]버튼을 클릭하면 \"다른 곳으로 가볼까?\"라고 2초간 말하고, \"장면 2\"가 시작됩니다. \"장면 2\"가 시작되면 오브젝트가 \"여기가 어디지?\"라고 말합니다.", "start_scene_desc": "A 장면을 시작합니다.", "start_scene_elements": "A-- \"장면 이름\"", "start_scene_exampleCode": "#\"장면 1\"의 파이선 코드\ndef when_click_object_on():\n Entry.start_scene(\"장면 2\")", "start_scene_exampleDesc": "\"장면 1\"에서 해당 오브젝트를 클릭하면 \"장면 2\"가 시작됩니다.", "start_neighbor_scene_desc": "A에 입력한 다음 또는 이전 장면을 시작합니다.", "start_neighbor_scene_elements": "A-- 아래 선택지 중 하나
① 다음 장면: \"next\" 또는 \"다음\"
② 이전 장면: \"prev\" 또는 \"이전\"", "start_neighbor_scene_exampleCode": "#\"장면 1\"의 파이선 코드\ndef when_press_key(\"right\"):\n Entry.start_scene_of(\"next\")\n\n#\"장면 2\"의 파이선 코드\ndef when_press_key(\"left\"):\n Entry.start_scene_of(\"prev\")", "start_neighbor_scene_exampleDesc": "\"장면 1\"에서 오른쪽화살표키를 누르면 다음 장면이, \"장면 2\"에서 왼쪽화살표키를 누르면 이전 장면이 시작됩니다.", "wait_second_desc": "A초만큼 기다린 후 다음 블록을 실행합니다.", "wait_second_elements": "A-- 초에 해당하는 수 입력", "wait_second_exampleCode": "def when_start():\n Entry.add_effect(\"color\", 10)\n Entry.wait_for_sec(2)\n Entry.add_size(10)", "wait_second_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트에 색깔효과를 10만큼 주고, 2초동안 기다린 다음 크기를 10만큼 커지게 합니다.", "repeat_basic_desc": "아래 명령어들을 A번 반복하여 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "repeat_basic_elements": "A-- 반복할 횟수 입력", "repeat_basic_exampleCode": "def when_start():\n for i in range(10):\n Entry.move_to_direction(10)\n Entry.stamp()", "repeat_basic_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 도장찍는 행동을 10번 반복합니다.", "repeat_inf_desc": "A 판단이 True인 동안 아래 명령어들을 반복 실행합니다. A에 True를 입력하면 계속 반복됩니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "repeat_inf_elements": "A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\") 등", "repeat_inf_exampleCode": "def when_start():\n while True:\n Entry.move_to_direction(10)\n Entry.bounce_on_edge()", "repeat_inf_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 계속해서 이동방향으로 10만큼 이동하고, 벽에 닿으면 튕깁니다.", "repeat_while_true_desc": "A 판단이 True가 될 때까지 아래 명령어들을 반복 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "repeat_while_true_elements": "A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\") 등", "repeat_while_true_exampleCode": "def when_start():\n while not Entry.is_key_pressed(\"space\"):\n Entry.add_rotation(90)", "repeat_while_true_exampleDesc": "[시작하기]버튼을 클릭하면 스페이스키를 누를때까지 오브젝트가 90도 만큼 회전합니다.", "stop_repeat_desc": "이 명령어와 가장 가까운 반복 명령어의 반복을 중단합니다.", "stop_repeat_exampleCode": "def when_start():\n while True:\n Entry.move_to_direction(10)\n if Entry.is_key_pressed(\"enter\"):\n break", "stop_repeat_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 계속 이동합니다. 엔터키를 누르면 반복이 중단됩니다.", "_if_desc": "A 부분의 판단이 True이면 if A:아래 명령어들을 실행하고, False이면 실행하지 않습니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "_if_elements": "A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\") 등", "_if_exampleCode": "def when_click_mouse_on():\n if (Entry.value_of_mouse_pointer(\"x\") > 0):\n Entry.print_for_sec(\"오른쪽!\", 0.5)", "_if_exampleDesc": "마우스를 클릭했을 때 마우스 x좌표가 0보다 크면 오브젝트가 \"오른쪽!\"이라고 0.5초 동안 말합니다.", "if_else_desc": "A 부분의 판단이 True이면 if A: 아래 명령어들을 실행하고, False이면 else: 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "if_else_elements": "A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\") 등", "if_else_exampleCode": "def when_click_mouse_on():\n if Entry.is_touched(\"mouse_pointer\"):\n Entry.print(\"닿았다!\")\n else:\n Entry.print(\"안 닿았다!\")", "if_else_exampleDesc": "마우스를 클릭했을 때 마우스포인터가 오브젝트에 닿았으면 \"닿았다!\"를 그렇지 않으면 \"안 닿았다!\"를 말합니다.", "wait_until_true_desc": "A 부분의 판단이 True가 될 때까지 코드의 실행을 멈추고 기다립니다.", "wait_until_true_elements": "A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\") 등", "wait_until_true_exampleCode": "def when_start():\n Entry.print(\"엔터를 눌러봐!\")\n Entry.wait_until(Entry.is_key_pressed(\"enter\"))\n Entry.print(\"잘했어!\")", "wait_until_true_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 \"엔터를 눌러봐!\"라 말하고, 엔터키를 누를 때까지 기다립니다. 엔터키를 누르면 \"잘했어!\"라 말합니다.", "stop_object_desc": "A코드의 실행을 중지합니다.", "stop_object_elements": "A-- 아래 선택지 중 하나
① \"all\": 모든 오브젝트의 모든 코드
② \"self\" : 해당 오브젝트의 모든 코드
③ \"this\": 이 명령어가 포함된 코드
④ \"others\" : 해당 오브젝트의 코드 중 이 명령어가 포함된 코드를 제외한 모든 코드
⑤ \"ohter_objects\" : 이 오브젝트를 제외한 다른 모든 오브젝트의 코드", "stop_object_exampleCode": "def when_start():\n while True:\n Entry.move_to(\"mouse_pointer\")\n\ndef when_press_key(\"space\"):\n Entry.stop_code(\"all\")\n", "stop_object_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 계속해서 마우스포인터 위치로 이동합니다. 스페이스키를 누르면 모든 코드의 실행이 중지됩니다.", "restart_project_desc": "작품을 처음부터 다시 실행합니다.", "restart_project_exampleCode": "def when_start():\n while True:\n Entry.add_size(10)\n\ndef when_press_key(\"enter\"):\n Entry.start_again()", "restart_project_exampleDesc": "[시작하기]버튼을 클릭하면 계속해서 오브젝트의 크기가 커집니다. 엔터키를 누르면 작품을 처음부터 다시 실행합니다.", "when_clone_start_desc": "해당 오브젝트의 복제본이 새로 생성되었을 때 아래 명령어들을 실행합니다.
아래 명령어는 [Tab]키를 통해 들여쓰기합니다.", "when_clone_start_exampleCode": "def when_start():\n for i in range(5):\n Entry.make_clone_of(\"self\")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))", "when_clone_start_exampleDesc": "[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다.", "create_clone_desc": "A 오브젝트의 복제본을 생성합니다.", "create_clone_elements": "A-- 아래 선택지 중 하나
① \"오브젝트 이름\"
② \"self\" 또는 \"자신\"", "create_clone_exampleCode": "def when_start():\n for i in range(5):\n Entry.make_clone_of(\"self\")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))", "create_clone_exampleDesc": "[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다.", "delete_clone_desc": "Entry.make_clone_of(A) 명령에 의해 생성된 복제본을 삭제합니다.", "delete_clone_exampleCode": "def when_start():\n for i in range(5):\n Entry.make_clone_of(\"자신\")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))\n\ndef when_click_object_on():\n Entry.remove_this_clone()", "delete_clone_exampleDesc": "[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다. 복제본을 클릭하면 클릭된 복제본을 삭제합니다.", "remove_all_clones_desc": "해당 오브젝트의 모든 복제본을 삭제합니다.", "remove_all_clones_exampleCode": "def when_start():\n for i in range(5):\n Entry.make_clone_of(\"자신\")\n\ndef when_make_clone():\n Entry.set_x(random.randint(-200, 200))\n\ndef when_press_key(\"space\"):\n Entry.remove_all_clone()", "remove_all_clones_exampleDesc": "[시작하기]버튼을 클릭하면 자신의 복제본 5개를 만듭니다. 복제본이 새로 생성되었을때 복제본의 x좌표를 -200에서 200사이의 무작위수로 정합니다. 스페이스 키를 누르면 모든 복제본을 삭제합니다.", "move_direction_desc": "A만큼 오브젝트의 이동방향 화살표가 가리키는 방향으로 움직입니다.", "move_direction_elements": "A-- 이동할 거리에 해당하는 수", "move_direction_exampleCode": "def when_start():\n Entry.move_to_direction(10)", "move_direction_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동합니다.", "bounce_wall_desc": "오브젝트가 화면 끝에 닿으면 튕겨져 나옵니다.", "bounce_wall_exampleCode": "def when_start():\n while True:\n Entry.move_to_direction(10)\n Entry.bounce_on_edge()", "bounce_wall_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 계속해서 이동방향으로 10만큼 이동하고, 벽에 닿으면 튕깁니다.", "move_x_desc": "오브젝트의 x좌표를 A만큼 바꿉니다.", "move_x_elements": "A-- x좌표의 변화 값
① 양수: 오브젝트가 오른쪽으로 이동합니다.
② 음수: 오브젝트가 왼쪽으로 이동합니다.", "move_x_exampleCode": "def when_start():\n Entry.add_x(10)\n Entry.wait_for_sec(2)\n Entry.add_x(-10)", "move_x_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 오른쪽으로 10만큼 이동하고 2초 동안 기다린 후 왼쪽으로 10만큼 이동합니다.", "move_y_desc": "오브젝트의 y좌표를 A만큼 바꿉니다.", "move_y_elements": "A-- y좌표의 변화 값
① 양수: 오브젝트가 위쪽으로 이동합니다.
② 음수: 오브젝트가 아래쪽으로 이동합니다.", "move_y_exampleCode": "def when_start():\n Entry.add_y(10)\n Entry.wait_for_sec(2)\n Entry.add_y(-10)", "move_y_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 위쪽으로 10만큼 이동하고 2초 동안 기다린 후 아래쪽으로 10만큼 이동합니다.", "move_xy_time_desc": "오브젝트가 x와 y좌표를 각각 A와 B만큼 C초에 걸쳐 서서히 바꿉니다.", "move_xy_time_elements": "A-- x좌표의 변화 값
① 양수: 오브젝트가 오른쪽으로 이동합니다.
② 음수: 오브젝트가 왼쪽으로 이동합니다.%nextB-- y좌표의 변화 값
① 양수: 오브젝트가 위쪽으로 이동합니다.
② 음수: 오브젝트가 아래쪽으로 이동합니다.%nextC-- 이동하는 시간(초)", "move_xy_time_exampleCode": "def when_start():\n Entry.add_xy_for_sec(100, 100, 2)\n Entry.add_xy_for_sec(-100, -100, 2)", "move_xy_time_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 오른쪽 위로 100만큼 2초 동안 이동한 후 왼쪽 아래로 100만큼 2초 동안 이동합니다.", "locate_x_desc": "오브젝트의 x좌표를 A로 정합니다. (오브젝트의 중심점이 기준이 됩니다.)", "locate_x_elements": "A-- 이동할 x좌표", "locate_x_exampleCode": "def when_press_key(\"right\"):\n Entry.set_x(100)\n\ndef when_press_key(\"left\"):\n Entry.set_x(-100)\n", "locate_x_exampleDesc": "오른쪽화살표키를 누르면 오브젝트의 x좌표를 100으로 정하고, 왼쪽화살표키를 누르면 오브젝트의 x좌표를 -100으로 정합니다.", "locate_y_desc": "오브젝트의 y좌표를 A로 정합니다. (오브젝트의 중심점이 기준이 됩니다.)", "locate_y_elements": "B-- 이동할 y좌표", "locate_y_exampleCode": "def when_press_key(\"up\"):\n Entry.set_y(100)\n\ndef when_press_key(\"down\"):\n Entry.set_y(-100)", "locate_y_exampleDesc": "위쪽화살표키를 누르면 오브젝트의 y좌표를 100으로 정하고, 아래쪽화살표키를 누르면 오브젝트의 y좌표를 -100으로 정합니다.", "locate_xy_desc": "오브젝트가 좌표(A, B)로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)", "locate_xy_elements": "A-- 이동할 x좌표%nextB-- 이동할 y좌표", "locate_xy_exampleCode": "def when_click_mouse_on():\n Entry.set_xy(0, 0)\n\ndef when_press_key(\"right\"):\n Entry.add_x(10)\n\ndef when_press_key(\"up\"):\n Entry.add_y(10)", "locate_xy_exampleDesc": "오른쪽화살표키를 누르면 오브젝트의 x좌표를 10만큼 바꾸고, 위쪽화살표키를 누르면 오브젝트의 y좌표를 10만큼 바꿉니다. 마우스를 클릭하면 오브젝트의 x, y좌표를 0으로 정합니다.", "locate_xy_time_desc": "오브젝트가 좌표(A, B)로 C초에 걸쳐 서서히 이동합니다.(오브젝트의 중심점이 기준이 됩니다.)", "locate_xy_time_elements": "A-- 이동할 x좌표%nextB-- 이동할 y좌표%nextC-- 이동하는 시간", "locate_xy_time_exampleCode": "def when_click_mouse_on():\n Entry.set_xy_for_sec(0, 0, 2)\n\ndef when_press_key(\"right\"):\n Entry.add_x(10)\n\ndef when_press_key(\"up\"):\n Entry.add_y(10)", "locate_xy_time_exampleDesc": "오른쪽화살표키를 누르면 오브젝트의 x좌표를 10만큼 바꾸고, 위쪽화살표키를 누르면 오브젝트의 y좌표를 10만큼 바꿉니다. 마우스를 클릭하면 2초 동안 오브젝트를 x,y 좌표 0으로 이동시킵니다.", "locate_desc": "오브젝트가 A의 위치로 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)", "locate_elements": "A-- 아래 선택지 중 하나
① \"오브젝트 이름\"
② \"mouse_pointer\" 또는 \"마우스포인터\"", "locate_exampleCode": "def when_click_mouse_on():\n Entry.move_to(\"mouse_pointer\")\n\ndef when_press_key(\"space\"):\n Entry.move_to(\"오브젝트\")", "locate_exampleDesc": "마우스를 클릭하면 오브젝트가 마우스포인터 위치로 이동합니다.
스페이스키를 누르면 오브젝트가 \"오브젝트\" 위치로 이동합니다.", "locate_object_time_desc": "오브젝트가 A의 위치로 B초에 걸쳐 서서히 이동합니다. (오브젝트의 중심점이 기준이 됩니다.)", "locate_object_time_elements": "A-- 아래 선택지 중 하나
① \"오브젝트 이름\"
② \"mouse_pointer\" 또는 \"마우스포인터\" %nextB-- 이동하는 시간(초)", "locate_object_time_exampleCode": "def when_click_mouse_on():\n Entry.move_to_for_sec(\"mouse_pointer\", 2)", "locate_object_time_exampleDesc": "마우스를 클릭하면 오브젝트가 2초 동안 서서히 마우스포인터 위치로 이동합니다.", "rotate_relative_desc": "오브젝트의 방향을 A도만큼 시계방향으로 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)", "rotate_relative_elements": "A-- 회전할 각도", "rotate_relative_exampleCode": "def when_click_object_on():\n Entry.add_rotation(90)\n\ndef when_click_object_off():\n Entry.add_rotation(-90)", "rotate_relative_exampleDesc": "오브젝트를 클릭하면 오브젝트가 90도 만큼 회전하고, 오브젝트 클릭을 해제하면 오브젝트가 -90도 만큼 회전합니다.", "direction_relative_desc": "오브젝트의 이동 방향을 A도만큼 회전합니다.", "direction_relative_elements": "A-- 회전할 각도", "direction_relative_exampleCode": "def when_start():\n Entry.move_to_direction(50)\n Entry.wait_for_sec(0.5)\n Entry.add_direction(90)\n Entry.wait_for_sec(0.5)\n Entry.move_to_direction(50)", "direction_relative_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 50만큼 이동한 다음 0.5초간 기다립니다. 그 후 이동방향을 90도 만큼 회전하고 0.5초간 기다린 후 이동방향으로 50만큼 이동합니다.", "rotate_by_time_desc": "오브젝트의 방향을 시계방향으로 A도만큼 B초에 걸쳐 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)", "rotate_by_time_elements": "A-- 회전할 각도%nextB-- 회전할 시간(초)", "rotate_by_time_exampleCode": "def when_start():\n Entry.add_rotation_for_sec(90, 2)\n Entry.add_rotation_for_sec(-90, 2)", "rotate_by_time_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 2초 동안 90도 만큼 회전하고, 다시 2초 동안 -90도 만큼 회전합니다.", "direction_relative_duration_desc": "오브젝트의 이동방향을 시계방향으로 A도만큼 B초에 걸쳐 회전합니다. (오브젝트의 중심점을 기준으로 회전합니다.)", "direction_relative_duration_elements": "A-- 회전할 각도%nextB-- 회전할 시간(초)", "direction_relative_duration_exampleCode": "def when_start():\n Entry.add_direction_for_sec(90, 2)\n\ndef when_start():\n while True:\n Entry.move_to_direction(1)", "direction_relative_duration_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트의 이동방향을 2초 동안 90도만큼 회전시킵니다. 동시에 오브젝트는 이동방향으로 1만큼 계속 이동합니다.", "rotate_absolute_desc": "오브젝트의 방향을 A로 정합니다.", "rotate_absolute_elements": "A-- 설정할 방향", "rotate_absolute_exampleCode": "def when_press_key(\"right\"):\n Entry.set_rotation(90)\n\ndef when_press_key(\"left\"):\n Entry.set_rotation(270)", "rotate_absolute_exampleDesc": "오른쪽화살표키를 누르면 오브젝트의 방향을 90으로 정하고, 왼쪽화살표키를 누르면 오브젝트의 방향을 270으로 정합니다.", "direction_absolute_desc": "오브젝트의 이동방향을 A로 정합니다.", "direction_absolute_elements": "A-- 설정할 이동방향", "direction_absolute_exampleCode": "def when_press_key(\"right\"):\n Entry.set_direction(90)\n Entry.move_to_direction(10)\n\ndef when_press_key(\"left\"):\n Entry.set_direction(270)\n Entry.move_to_direction(10)", "direction_absolute_exampleDesc": "오른쪽화살표키를 누르면 오브젝트의 이동방향을 90으로 정한 후 해당 쪽으로 10만큼 이동하고, 왼쪽화살표키를 누르면 오브젝트의 이동방향을 270으로 정하고 해당쪽으로 10만큼 이동합니다.", "see_angle_object_desc": "오브젝트가 A쪽을 바라봅니다. (이동방향이 A를 향하도록 오브젝트의 방향을 회전해줍니다.)", "see_angle_object_elements": "A-- 아래 선택지 중 하나
① \"오브젝트 이름\"
② \"mouse_pointer\" 또는 \"마우스포인터\"", "see_angle_object_exampleCode": "def when_click_mouse_on():\n Entry.look_at(\"mouse_pointer\")\n\ndef when_press_key(\"space\"):\n Entry.look_at(\"오브젝트\")", "see_angle_object_exampleDesc": "마우스를 클릭하면 오브젝트가 마우스포인터쪽을 바라보고, 스페이스키를 누르면 \"오브젝트\"쪽을 바라봅니다.", "move_to_angle_desc": "오브젝트가 A만큼 B방향으로 움직입니다.", "move_to_angle_elements": "A-- 이동할 거리에 해당하는 수%nextB-- 이동할 방향(12시 방향이 0도, 시계방향으로 증가)", "move_to_angle_exampleCode": "def when_press_key(\"up\"):\n Entry.move_to_degree(10, 0)\n\ndef when_press_key(\"down\"):\n Entry.move_to_degree(10, 180)", "move_to_angle_exampleDesc": "위쪽화살표키를 누르면 오브젝트가 0도방향으로 10만큼 이동하고, 아래쪽화살표키를 누르면 오브젝트가 180도방향으로 10만큼 이동합니다.", "show_desc": "오브젝트를 화면에 나타냅니다.", "show_exampleCode": "def when_start():\n Entry.wait_for_sec(1)\n Entry.hide()\n Entry.wait_for_sec(1)\n Entry.show()", "show_exampleDesc": "[시작하기]버튼을 클릭하면 1초 뒤에 오브젝트 모양이 숨겨지고, 다음 1초 뒤에 오브젝트 모양이 나타납니다.", "hide_desc": "오브젝트를 화면에서 보이지 않게 합니다.", "hide_exampleCode": "def when_start():\n Entry.wait_for_sec(1)\n Entry.hide()\n Entry.wait_for_sec(1)\n Entry.show()", "hide_exampleDesc": "[시작하기]버튼을 클릭하면 1초 뒤에 오브젝트 모양이 숨겨지고, 다음 1초 뒤에 오브젝트 모양이 나타납니다.", "dialog_time_desc": "오브젝트가 A를 B초 동안 말풍선으로 말한 후 다음 명령어가 실행됩니다. 콘솔창에서도 실행 결과를 볼 수 있습니다.", "dialog_time_elements": "A-- 말할 내용
① 문자 : \"안녕!\", \"엔트리\" 등
② 숫자 : 0, 10, 35 등%nextB-- 말하는 시간(초)", "dialog_time_exampleCode": "def when_start():\n Entry.print_for_sec(\"안녕! 나는\", 2)\n Entry.print_for_sec(16, 2)\n Entry.print_for_sec(\"살이야\", 2)", "dialog_time_exampleDesc": "[시작하기]버튼을 클릭하면 \"안녕! 나는\", 16, \"살이야\"를 각각 2초 동안 차례대로 말합니다.", "dialog_desc": "오브젝트가 A를 말풍선으로 말합니다. 콘솔창에서도 실행 결과를 볼 수 있습니다.", "dialog_elements": "A-- 말할 내용
① 문자 : \"안녕!\", \"엔트리\" 등
② 숫자 : 0, 10, 35 등", "dialog_exampleCode": "def when_start():\n Entry.print(\"키보드로 숫자 1,2 를 누르면 숫자를 말해볼게\")\n\ndef when_press_key(1):\n Entry.print(1)\n\ndef when_press_key(2):\n Entry.print(2)\n", "dialog_exampleDesc": "[시작하기]버튼을 클릭하면 \"키보드로 숫자 1,2 를 누르면 숫자를 말해볼게\"를 말하고, 키보드로 1, 2를 누르면 각각 1, 2라 말합니다.", "remove_dialog_desc": "오브젝트가 말하고 있는 말풍선을 지웁니다.", "remove_dialog_exampleCode": "def when_start():\n Entry.print(\"말풍선을 지우려면 엔터를 눌러!\")\n\ndef when_press_key(\"enter\"):\n Entry.clear_print()", "remove_dialog_exampleDesc": "[시작하기]버튼을 클릭하면 \"말풍선을 지우려면 엔터를 눌러!\"라 말하고, 엔터키를 누르면 말풍선이 사라집니다.", "change_to_some_shape_desc": "오브젝트를 A 모양으로 바꿉니다.", "change_to_some_shape_elements": "A-- 아래 선택지 중 하나
① 모양 이름 : [속성] 탭의 \"모양 이름\"을 적음
② 모양 번호 : [속성] 탭의 모양 번호를 적음", "change_to_some_shape_exampleCode": "def when_start():\n Entry.wait_for_sec(0.3)\n Entry.change_shape(\"오브젝트모양\")\n Entry.wait_for_sec(0.3)\n Entry.change_shape(\"오브젝트모양\")", "change_to_some_shape_exampleDesc": "[시작하기]버튼을 클릭하면 0.3초간 기다린 다음 \"오브젝트모양\"으로 모양을 바꾸고 0.3초간 기다린 다음 \"오브젝트모양\"모양으로 모양을 바꿉니다.", "change_to_next_shape_desc": "오브젝트의 모양을 다음 또는 이전 모양으로 바꿉니다.", "change_to_next_shape_elements": "A-- 아래 선택지 중 하나
① 다음 모양 : \"next\" 또는 \"다음\"
② 이전 모양 : \"pre\" 또는 \"이전\"", "change_to_next_shape_exampleCode": "def when_start():\n Entry.wait_for_sec(0.3)\n Entry.change_shape_to(\"next\")\n Entry.wait_for_sec(0.3)\n Entry.change_shape_to(\"pre\")", "change_to_next_shape_exampleDesc": "[시작하기]버튼을 클릭하면 0.3초간 기다린 다음 모양으로 오브젝트 모양을 바꾸고 0.3초간 기다린 다음 이전 모양으로 오브젝트 모양을 바꿉니다.", "add_effect_amount_desc": "오브젝트에 A 효과를 B만큼 줍니다.", "add_effect_amount_elements": "A -- 아래 선택지 중 하나
① “color” 또는 “색깔“
② “brightness” 또는 “밝기”
③ “transparency” 또는 “투명도”%nextB-- 효과의 변화 정도", "add_effect_amount_exampleCode": "def when_click_mouse_on():\n Entry.add_effect(\"color\", 50)\n Entry.wait_for_sec(1)\n Entry.add_effect(\"brightness\", -50)\n Entry.wait_for_sec(1)\n Entry.add_effect(\"transparency\", 50)", "add_effect_amount_exampleDesc": "마우스를 클릭하면 오브젝트에 색깔 효과를 50만큼 주고 1초간 기다리고, 밝기 효과를 -50만큼 주고 1초간 기다립니다. 그 후 투명도 효과를 50만큼 줍니다.", "change_effect_amount_desc": "오브젝트의 A 효과를 B로 정합니다.", "change_effect_amount_elements": "A-- 아래 선택지 중 하나
① “color” 또는 “색깔“
② “brightness” 또는 “밝기”
③ “transparency” 또는 “투명도”%nextB-- 효과의 값
① color: 0~100 범위의 수, 100을 주기로 반복됨
② brightness: -100~100 사이 범위의 수, -100이하는 -100 으로 100 이상은 100 으로 처리 됨
③ transparency: 0~100 사이 범위의 수, 0 이하는 0으로, 100이상은 100으로 처리 됨", "change_effect_amount_exampleCode": "def when_click_mouse_on():\n Entry.set_effect(\"color\", 50)\n Entry.set_effect(\"brightness\", 50)\n Entry.set_effect(\"transparency\", 50)\n\ndef when_click_mouse_off():\n Entry.set_effect(\"color\", 0)\n Entry.set_effect(\"brightness\", 0)\n Entry.set_effect(\"transparency\", 0)", "change_effect_amount_exampleDesc": "마우스를 클릭하면 오브젝트에 색깔, 밝기, 투명도 효과를 50으로 정하고, 마우스 클릭을 해제하면 각 효과를 0으로 정합니다.", "erase_all_effects_desc": "오브젝트에 적용된 효과를 모두 지웁니다.", "erase_all_effects_exampleCode": "def when_click_mouse_on():\n Entry.set_effect(\"color\", 50)\n Entry.set_effect(\"brightness\", 50)\n Entry.set_effect(\"transparency\", 50)\n\ndef when_click_mouse_off():\n Entry.clear_effect()\n", "erase_all_effects_exampleDesc": "마우스를 클릭하면 오브젝트에 색깔, 밝기, 투명도 효과를 50으로 정하고, 마우스 클릭을 해제하면 오브젝트에 적용된 모든 효과를 지웁니다.", "change_scale_size_desc": "오브젝트의 크기를 A만큼 바꿉니다.", "change_scale_size_elements": "A-- 크기 변화 값", "change_scale_size_exampleCode": "def when_press_key(\"up\"):\n Entry.add_size(10)\n\ndef when_press_key(\"down\"):\n Entry.add_size(-10)\n\ndef when_press_key(\"space\"):\n Entry.set_size(100)", "change_scale_size_exampleDesc": "위쪽화살표키를 누르면 오브젝트의 크기가 10만큼 커지고, 아래쪽화살표키를 누르면 오브젝트의 크기가 10만큼 작아집니다. 스페이스키를 누르면 오브젝트의 크기를 100으로 정합니다.", "set_scale_size_desc": "오브젝트의 크기를 A로 정합니다.", "set_scale_size_elements": "A-- 크기값", "set_scale_size_exampleCode": "def when_press_key(\"up\"):\n Entry.add_size(10)\n\ndef when_press_key(\"down\"):\n Entry.add_size(-10)\n\ndef when_press_key(\"space\"):\n Entry.set_size(100)", "set_scale_size_exampleDesc": "위쪽화살표키를 누르면 오브젝트의 크기가 10만큼 커지고, 아래쪽화살표키를 누르면 오브젝트의 크기가 10만큼 작아집니다. 스페이스키를 누르면 오브젝트의 크기를 100으로 정합니다.", "flip_x_desc": "오브젝트의 상하 모양을 뒤집습니다.", "flip_x_exampleCode": "def when_press_key(\"up\"):\n Entry.flip_horizontal()\n\ndef when_press_key(\"right\"):\n Entry.flip_vertical()", "flip_x_exampleDesc": "위쪽화살표키를 누르면 오브젝트의 상하 모양을 뒤집고, 오른쪽화살표키를 누르면 오브젝트의 좌우 모양을 뒤집습니다.", "flip_y_desc": "오브젝트의 좌우 모양을 뒤집습니다.", "flip_y_exampleCode": "def when_press_key(\"up\"):\n Entry.flip_horizontal()\n\ndef when_press_key(\"right\"):\n Entry.flip_vertical()", "flip_y_exampleDesc": "위쪽화살표키를 누르면 오브젝트의 상하 모양을 뒤집고, 오른쪽화살표키를 누르면 오브젝트의 좌우 모양을 뒤집습니다.", "change_object_index_desc": "오브젝트의 레이어를 A로 가져옵니다.", "change_object_index_elements": "A-- 아래 선택지 중 하나
① “front\" 또는 “맨 앞“
② “forward” 또는 “앞”
③ “backward” 또는 “뒤”
④ “back” 또는 “맨 뒤”", "change_object_index_exampleCode": "def when_start():\n Entry.send_layer_to(\"front\")\n Entry.wait_for_sec(2)\n Entry.send_layer_to(\"backward\")", "change_object_index_exampleDesc": "오브젝트가 여러개가 겹쳐 있을 경우 [시작하기]버튼을 클릭하면 해당 오브젝트의 레이어를 가장 앞으로 가져와서 보여줍니다.", "brush_stamp_desc": "오브젝트의 모양을 도장처럼 실행화면 위에 찍습니다.", "brush_stamp_exampleCode": "def when_start():\n for i in range(10):\n Entry.move_to_direction(10)\n Entry.stamp()", "brush_stamp_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 이동방향으로 10만큼 이동하고, 도장찍는 행동을 10번 반복합니다.", "start_drawing_desc": "오브젝트가 이동하는 경로를 따라 선이 그려지기 시작합니다. (오브젝트의 중심점이 기준)", "start_drawing_exampleCode": "def when_start():\n Entry.start_drawing()\n for i in range(10):\n Entry.move_to_direction(10)", "start_drawing_exampleDesc": "[시작하기]버튼을 클릭하면 그리기가 시작되고, 오브젝트가 이동방향으로 10만큼 10번 이동할 때 오브젝트의 이동경로를 따라 선이 그려집니다.", "stop_drawing_desc": "오브젝트가 선을 그리는 것을 멈춥니다.", "stop_drawing_exampleCode": "def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(1)\n\ndef when_click_mouse_on():\n Entry.stop_drawing()", "stop_drawing_exampleDesc": "[시작하기]버튼을 클릭하면 그리기가 시작되고 계속해서 오브젝트가 이동방향으로 10만큼 이동합니다. 마우스를 클릭하면 그리는것을 멈춥니다.", "set_color_desc": "오브젝트가 그리는 선의 색을 A로 정합니다.", "set_color_elements": "A-- 아래 선택지 중 하나
① 색상 코드 : \"#FF0000\", \"#FFCC00\", \"#3333FF\", \"#000000\" 등
② 색깔명 : \"red\", \"orange\", \"yellow\", \"green\", \"blue\", \"navy\", \"purple\", \"black\", \"white\", \"brown\"", "set_color_exampleCode": "def when_start():\n Entry.start_drawing()\n Entry.set_brush_color_to(\"#000099\")\n while True:\n Entry.move_to_direction(1)", "set_color_exampleDesc": "[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 색을 \"#000099\"로 정합니다. 오브젝트는 계속해서 이동방향으로 1만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.", "set_random_color_desc": "오브젝트가 그리는 선의 색을 무작위로 정합니다.", "set_random_color_exampleCode": "def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(1)\n Entry.set_brush_color_to_random()", "set_random_color_exampleDesc": "[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 1만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 색깔은 계속해서 무작위로 정해집니다.", "change_thickness_desc": "오브젝트가 그리는 선의 굵기를 A만큼 바꿉니다.", "change_thickness_elements": "A-- 굵기 변화 값", "change_thickness_exampleCode": "def when_start():\n Entry.start_drawing()\n while True:\n Entry.add_brush_size(1)\n Entry.move_to_direction(10)", "change_thickness_exampleDesc": "[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 굵기는 계속해서 1씩 커집니다.", "set_thickness_desc": "오브젝트가 그리는 선의 굵기를 A로 정합니다.", "set_thickness_elements": "A-- 굵기값(1이상의 수)", "set_thickness_exampleCode": "def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n while True:\n Entry.move_to_direction(10)", "set_thickness_exampleDesc": "[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.", "change_brush_transparency_desc": "오브젝트가 그리는 선의 투명도를 A만큼 바꿉니다.", "change_brush_transparency_elements": "A-- 투명도 변화 값", "change_brush_transparency_exampleCode": "def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n while True:\n Entry.move_to_direction(10)\n Entry.add_brush_transparency(5)", "change_brush_transparency_exampleDesc": "[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 선의 투명도는 계속해서 5만큼 바꿉니다.", "set_brush_tranparency_desc": "오브젝트가 그리는 선의 투명도를 A로 정합니다.", "set_brush_tranparency_elements": "A-- 투명도값(0~100 의 범위)", "set_brush_tranparency_exampleCode": "def when_start():\n Entry.start_drawing()\n Entry.set_brush_size(10)\n Entry.set_brush_transparency(50)\n while True:\n Entry.move_to_direction(10)", "set_brush_tranparency_exampleDesc": "[시작하기]버튼을 클릭하면 그리기가 시작되고, 선의 굵기를 10으로, 선의 투명도를 50으로 정합니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다.", "brush_erase_all_desc": "오브젝트가 그린 선과 도장을 모두 지웁니다.", "brush_erase_all_exampleCode": "def when_start():\n Entry.start_drawing()\n while True:\n Entry.move_to_direction(10)\n\ndef when_click_mouse_on():\n Entry.clear_drawing()", "brush_erase_all_exampleDesc": "[시작하기]버튼을 클릭하면 그리기가 시작됩니다. 오브젝트는 계속해서 이동방향으로 10만큼 움직이고, 오브젝트의 이동경로를 따라 선이 그려집니다. 마우스를 클릭하면 오브젝트가 그린 선을 모두 지웁니다.", "text_read_desc": "글상자 A의 내용입니다.
(내용 안에 개행이 있는 경우, 띄어쓰기하여 반환됩니다.)", "text_read_elements": "A-- 아래 선택지 중 하나
① \"오브젝트(글상자) 이름\"
② 자기 자신", "text_read_exampleCode": "def when_start():\n Entry.print(Entry.contents_of_textbox(\"A\"))", "text_read_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 글상자 \"A\"의 내용을 말합니다.​", "text_write_desc": "글상자의 내용을 A로 고쳐씁니다.", "text_write_elements": "A-- 글상자의 내용
① 문자 : \"안녕!\", \"엔트리\" 등
② 숫자 : 0, 10, 35 등", "text_write_exampleCode": "def when_start():\n Entry.write_text(\"엔트리\")", "text_write_exampleDesc": "[시작하기]버튼을 클릭하면 글상자의 내용을 \"엔트리\"로 바꿉니다.", "text_append_desc": "글상자의 내용 뒤에 A를 추가합니다.", "text_append_elements": "A-- 글상자의 내용
① 문자 : \"안녕!\", \"엔트리\" 등
② 숫자 : 0, 10, 35 등", "text_append_exampleCode": "def when_start():\n Entry.write_text(\"안녕?\")\n Entry.wait_for_sec(1)\n Entry.append_text(\"엔트리!\")", "text_append_exampleDesc": "[시작하기]버튼을 클릭하면 글상자의 내용이 \"안녕?\"이 되었다가 1초 뒤에 \"엔트리!\"가 추가되어 \"안녕?엔트리!\"가 됩니다.", "text_prepend_desc": "글상자의 내용 앞에 A를 추가합니다.", "text_prepend_elements": "A-- 글상자의 내용
① 문자 : \"안녕!\", \"엔트리\" 등
② 숫자 : 0, 10, 35 등", "text_prepend_exampleCode": "def when_start():\n Entry.write_text(\"반가워!\")\n Entry.wait_for_sec(1)\n Entry.prepend_text(\"엔트리!\")", "text_prepend_exampleDesc": "[시작하기]버튼을 클릭하면 글상자의 내용이 \"반가워!\"가 되었다가 1초 뒤에 \"엔트리!\"가 앞에 추가되어 \"엔트리!반가워!\"가 됩니다.", "text_flush_desc": "글상자에 저장된 값을 모두 지웁니다.", "text_flush_exampleCode": "def when_start():\n Entry.write_text(\"엔트리\")\n Entry.wait_for_sec(1)\n Entry.clear_text()", "text_flush_exampleDesc": "[시작하기]버튼을 클릭하면 글상자의 내용이 \"엔트리\"가 되었다가 1초 뒤에 모든 내용이 사라집니다.", "sound_something_with_block_desc": "오브젝트가 A 소리를 재생합니다.", "sound_something_with_block_elements": "A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 \"소리 이름\"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음", "sound_something_with_block_exampleCode": "def when_start():\n Entry.play_sound(\"소리\")\n Entry.add_size(50)", "sound_something_with_block_exampleDesc": "[시작하기]버튼을 클릭하면 \"소리\"를 재생하면서 오브젝트의 크기가 50만큼 커집니다.", "sound_something_second_with_block_desc": "오브젝트가 A소리를 B초 만큼 재생합니다.", "sound_something_second_with_block_elements": "A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 \"소리 이름\"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음", "sound_something_second_with_block_exampleCode": "def when_start():\n Entry.play_sound_for_sec(\"소리\", 1)\n Entry.add_size(50)", "sound_something_second_with_block_exampleDesc": "[시작하기]버튼을 클릭하면 \"소리\"를 1초 동안 재생하면서, 오브젝트의 크기가 50만큼 커집니다.", "sound_from_to_desc": "오브젝트가 A소리를 B초부터 C초까지 재생합니다.", "sound_from_to_elements": "A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 \"소리 이름\"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음", "sound_from_to_exampleCode": "def when_start():\n Entry.play_sound_from_to(\"소리\", 0.5, 1)\n Entry.add_size(50)", "sound_from_to_exampleDesc": "[시작하기]버튼을 클릭하면 \"소리\"를 0.5초부터 1초 구간까지만 재생하면서, 오브젝트의 크기가 50만큼 커집니다.", "sound_something_wait_with_block_desc": "오브젝트가 A 소리를 재생하고, 재생이 끝나면 다음 명령을 실행합니다.", "sound_something_wait_with_block_elements": "A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 \"소리 이름\"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음", "sound_something_wait_with_block_exampleCode": "def when_start():\n Entry.play_sound_and_wait(\"소리\")\n Entry.add_size(50)", "sound_something_wait_with_block_exampleDesc": "[시작하기]버튼을 클릭하면 \"소리\"를 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.", "sound_something_second_wait_with_block_desc": "오브젝트가 A소리를 B초 만큼 재생하고, 재생이 끝나면 다음 명령을 실행합니다.", "sound_something_second_wait_with_block_elements": "A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 \"소리 이름\"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음", "sound_something_second_wait_with_block_exampleCode": "def when_start():\n Entry.play_sound_for_sec_and_wait(\"소리\", 1)\n Entry.add_size(50)", "sound_something_second_wait_with_block_exampleDesc": "[시작하기]버튼을 클릭하면 \"소리\"를 1초 동안 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.", "sound_from_to_and_wait_desc": "오브젝트가 A소리를 B초부터 C초까지 재생하고, 재생이 끝나면 다음 명령을 실행합니다.", "sound_from_to_and_wait_elements": "A-- 아래 선택지 중 하나
① 소리 이름 : [속성] 탭의 \"소리 이름\"을 적음
② 소리 번호: [속성] 탭의 소리 번호를 적음", "sound_from_to_and_wait_exampleCode": "def when_start():\n Entry.play_sound_from_to_and_wait(\"소리\", 0.5, 1)\n Entry.add_size(50)", "sound_from_to_and_wait_exampleDesc": "[시작하기]버튼을 클릭하면 \"소리\"를 0.5초부터 1초 구간까지만 재생하고, 재생이 끝나면 오브젝트의 크기가 50만큼 커집니다.", "sound_volume_change_desc": "작품에서 재생되는 모든 소리의 크기를 A퍼센트만큼 바꿉니다.", "sound_volume_change_elements": "A-- 소리 크기 변화 값", "sound_volume_change_exampleCode": "def when_press_key(\"up\"):\n Entry.add_sound_volume(10)\n\ndef when_press_key(\"down\"):\n Entry.add_sound_volume(-10)\n\ndef when_start():\n while True:\n Entry.play_sound_and_wait(\"소리\")", "sound_volume_change_exampleDesc": "[시작하기]버튼을 클릭하면 \"소리\"를 계속 재생합니다. 위쪽화살표키를 누르면 소리의 크기가 10\" 커지고, 아래쪽화살표키를 누르면 소리의 크기가 10\"작아집니다.", "sound_volume_set_desc": "작품에서 재생되는 모든 소리의 크기를 A퍼센트로 정합니다.", "sound_volume_set_elements": "A-- 소리 크기값", "sound_volume_set_exampleCode": "def when_press_key(\"up\"):\n Entry.add_sound_volume(10)\n\ndef when_press_key(\"down\"):\n Entry.add_sound_volume(-10)\n\ndef when_press_key(\"enter\"):\n Entry.set_sound_volume(100)\n\ndef when_start():\n while True:\n Entry.play_sound_and_wait(\"소리\")", "sound_volume_set_exampleDesc": "[시작하기]버튼을 클릭하면 \"소리\"를 계속 재생합니다. 위쪽화살표키를 누르면 소리의 크기가 10\" 커지고, 아래쪽화살표키를 누르면 소리의 크기가 10\"작아집니다. 엔터키를 누르면 소리의 크기를 100\"로 정합니다.", "sound_silent_all_desc": "현재 재생 중인 모든 소리를 멈춥니다.", "sound_silent_all_exampleCode": "def when_start():\n while True:\n Entry.play_sound_and_wait(\"소리\")\n\ndef when_press_key(\"enter\"):\n Entry.stop_sound()", "sound_silent_all_exampleDesc": "[시작하기]버튼을 클릭하면 \"소리\"를 계속 재생합니다. 엔터키를 누르면 현재 재생 중인 소리를 멈춥니다.", "is_clicked_desc": "마우스를 클릭한 경우 True로 판단합니다.", "is_clicked_exampleCode": "def when_start():\n while True:\n if Entry.is_mouse_clicked():\n Entry.print_for_sec(\"반가워!\", 0.5)", "is_clicked_exampleDesc": "[시작하기]버튼을 클릭하면 계속해서 마우스를 클릭했는지 확인합니다. 만약 마우스를 클릭하면 오브젝트가 \"반가워!\"라고 0.5초간 말합니다.", "is_press_some_key_desc": "A 키가 눌려져 있는 경우 True로 판단합니다.", "is_press_some_key_elements": "A-- 아래 선택지 중 하나
① 알파벳 : \"A\", \"B\" ~ \"Z\" 등(소문자 가능)
② 숫자: 1, 2, 3, 4 ~ 9, 0
③ 특수키: \"space\", \"enter\"
④ 방향키 : \"up\", \"down\", \"right\", \"left\"", "is_press_some_key_exampleCode": "def when_start():\n while True:\n if Entry.is_key_pressed(\"space\"):\n Entry.move_to_direction(10)", "is_press_some_key_exampleDesc": "[시작하기]버튼을 클릭하면 계속해서 선택한 키를 눌렀는지 확인합니다. 만약 스페이스 키를 누르면 오브젝트가 이동방향으로 10만큼 이동합니다.", "reach_something_desc": "오브젝트가 A와 닿은 경우 True으로 판단합니다.", "reach_something_elements": "A-- 아래 선택지 중 하나
① \"오브젝트 이름\"
② \"mouse_pointer\" 또는 \"마우스포인터\"
③ \"edge\", \"edge_up\", \"edge_down\", \"edge_right\", \"edge_left\"", "reach_something_exampleCode": "def when_start():\n while True:\n Entry.move_to_direction(10)\n if Entry.is_touched(\"edge\"):\n Entry.add_rotation(150)", "reach_something_exampleDesc": "[시작하기]버튼을 클릭하면 계속해서 오브젝트가 이동방향으로 10만큼 이동합니다. 만약 오브젝트가 벽에 닿으면 150만큼 회전하게 됩니다.", "boolean_basic_operator_desc": "A와 B를 비교하여 True 또는 False로 판단합니다.", "boolean_basic_operator_elements": "A, B-- 비교하고자 하는 숫자값
① == : A와 B의 값이 같으면 True, 아니면 False
② > : A의 값이 B의 값보다 크면 true, 아니면 False
③ < : A의 값이 B의 값보다 작으면 true, 아니면 False
④ >= : A의 값이 B의 값보다 크거나 같으면 true, 아니면 False
⑤ <= : A의 값이 B의 값보다 작거나 같으면 true, 아니면 False", "boolean_basic_operator_exampleCode": "def when_start():\n while True:\n Entry.add_x(10)\n if Entry.value_of_object(\"오브젝트\", \"x\") > 240:\n Entry.set_x(0)", "boolean_basic_operator_exampleDesc": "[시작하기]버튼을 클릭하면 계속해서 오브젝트 x좌표를 10만큼 바꿉니다. 만약 오브젝트 x좌표가 240보다 크면 오브젝트 x좌표를 0으로 정합니다.", "boolean_and_desc": "A와 B의 판단이 모두 True인 경우 True, 아닌 경우 False로 판단합니다.", "boolean_and_elements": "A, B-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\") 등", "boolean_and_exampleCode": "def when_start():\n while True:\n if Entry.is_key_pressed(\"a\") and Entry.is_key_pressed(\"s\"):\n Entry.add_effect(\"color\", 10)", "boolean_and_exampleDesc": "[시작하기]버튼을 클릭하고 키보드의 \"a\" 와 \"s\"키를 동시에 눌렀을 때, 색깔 효과를 10만큼 줍니다.", "boolean_or_desc": "A와 B의 판단 중 하나라도 True인 경우 True, 아닌 경우 False로 판단합니다.", "boolean_or_elements": "A, B-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\") 등", "boolean_or_exampleCode": "def when_start():\n while True:\n if Entry.is_key_pressed(\"a\") or Entry.is_key_pressed(\"s\"):\n Entry.add_effect(\"color\", 10)", "boolean_or_exampleDesc": "[시작하기]버튼을 클릭하면 키보드의 \"a\"나 \"s\"키 중 무엇이든 하나를 누르면 오브젝트에 색깔 효과를 10만큼 줍니다.", "boolean_not_desc": "A 판단이 True이면 False, False이면 True로 판단합니다.", "boolean_not_elements": "A-- True 또는 False로 판단할 수 있는 명령어 입력(판단 카테고리의 명령어)
① True, False
② 10 == 10 , 10 > 10 , 10 <= 10 등
③ Entry.is_mouse_clicked(), Entry.is_key_pressed(\"Q\") 등", "boolean_not_exampleCode": "def when_start():\n while True:\n if not Entry.is_mouse_clicked():\n Entry.add_size(1)", "boolean_not_exampleDesc": "[시작하기]버튼을 클릭하면 마우스를 클릭하지 않은 동안 크기가 1씩 커집니다.", "calc_basic_desc": "A와 B의 연산값입니다.", "calc_basic_elements": "A, B-- 연산하고자 하는 숫자값
① + : A와 B를 더한 값
② - : A와 B를 뺀 값
③ x : A와 B를 곱한 값
④ / : A와 B를 나눈 값", "calc_basic_exampleCode": "def when_start():\n Entry.print_for_sec(10 + 10, 2)\n Entry.print_for_sec(10 - 10, 2)\n Entry.print_for_sec(10 * 10, 2)\n Entry.print_for_sec(10 / 10, 2)", "calc_basic_exampleDesc": "[시작하기]버튼을 클릭하면 10과 10을 더한값, 뺀값, 곱한값, 나눈값을 각 2초간 말합니다.", "calc_rand_desc": "A와 B 사이에서 선택된 무작위 수의 값입니다. (두 수 모두 정수를 입력한 경우 정수로,두 수 중 하나라도 소수를 입력한 경우 소수로 무작위 수가 선택됩니다.)", "calc_rand_elements": "A, B-- 무작위 수를 추출할 범위
① random.randint(A, B) : A, B를 정수로 입력하면 정수 범위에서 무작위 수를 추출
② random.uniform(A, B) : A, B를 실수로 입력하면 실수 범위에서 무작위 수를 추출", "calc_rand_exampleCode": "def when_start():\n Entry.print_for_sec(random.randint(1, 10), 2)\n Entry.print_for_sec(random.uniform(0.1, 2), 2)", "calc_rand_exampleDesc": "[시작하기]버튼을 클릭하면 1부터 10사이의 정수중 무작위 수를 뽑아 2초간 말합니다. 그 후 0.1부터 2사이의 실수중 무작위 수를 뽑아 2초간 말합니다.", "coordinate_mouse_desc": "마우스 포인터의 A 좌표 값을 의미합니다.", "coordinate_mouse_elements": "A-- 아래 선택지 중 하나
① \"x\" 또는 \"X\"
② \"y\" 또는 \"Y\"", "coordinate_mouse_exampleCode": "def when_start():\n while True:\n Entry.print(Entry.value_of_mouse_pointer(\"x\"))", "coordinate_mouse_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 마우스 포인터의 x좌표를 계속해서 말합니다.", "coordinate_object_desc": "A에 대한 B정보값입니다.", "coordinate_object_elements": "A-- 아래 선택지 중 하나
① \"오브젝트 이름\"
② \"self\" 또는 \"자신\"%nextB-- 아래 선택지 중 하나
① \"x\" 또는 \"X\"
② \"y\" 또는 \"Y\"
③ \"rotation\" 또는 \"방향\"
④ \"direction\" 또는 \"이동 방향\"
⑤ \"size\" 또는 \"크기\"
⑥ \"shape_number\" 또는 \"모양 번호\"
⑦ \"shape_name\" 또는 \"모양 이름\"", "coordinate_object_exampleCode": "def when_start():\n while True:\n Entry.add_x(1)\n Entry.print(Entry.value_of_object(\"오브젝트\", \"x\"))\n", "coordinate_object_exampleDesc": "[시작하기]버튼을 클릭하면 계속해서 오브젝트의 x좌표가 1씩 증가하며, \"오브젝트\"의 x좌표를 말합니다.", "get_sound_volume_desc": "현재 작품에 설정된 소리의 크기값입니다.", "get_sound_volume_exampleCode": "def when_start():\n while True:\n Entry.print(Entry.value_of_sound_volume())", "get_sound_volume_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 소리의 크기값을 계속해서 말합니다.", "quotient_and_mod_desc": "A와 B의 연산값입니다.", "quotient_and_mod_elements": "A, B-- 연산하고자 하는 숫자값
① // : A / B의 몫에 해당하는 값
② % : A / B의 나머지에 해당하는 값", "quotient_and_mod_exampleCode": "def when_start():\n Entry.print_for_sec(10 // 3, 2)\n Entry.print_for_sec(10 % 3, 2)", "quotient_and_mod_exampleDesc": "[시작하기]버튼을 클릭하면 10 / 3의 몫인 3을 2초 동안 말하고, 나머지인 1을 2초 동안 말합니다.", "calc_operation_desc": "A의 연산값입니다.", "calc_operation_elements": "A, B-- 연산하고자 하는 숫자값
① A ** 2 : A를 제곱한 값
② math.sqrt(A): A의 루트값
③ math.sin(A): A의 사인값
④ math.cos(A): A의 코사인 값
⑤ math.tan(A): A의 탄젠트값
⑥ math.asin(A): A의 아크사인값
⑦ math.acos(A): A의 아크코사인값
⑧ math.atan(): A의 아크탄젠트값
⑨ math.log10(A): A의 로그값
⑩ math.log(A): A의 자연로그값
⑪ A - math.floor(A): A의 소수점 부분
⑫ math.floor(A): A의 소수점 버림값
⑬ math.ceil(A): A의 소수점 올림값
⑭ math.round(A): A의 소수점 반올림값
⑮ math.factorial(A): A의 팩토리얼 값
⑯ math.fabs(A): A의 절댓값", "calc_operation_exampleCode": "def when_start():\n Entry.print_for_sec(10 ** 2, 2)\n Entry.print_for_sec(math.sqrt(9), 2)\n Entry.print_for_sec(math.sin(90), 2)\n Entry.print_for_sec(math.fabs(-10), 2)", "calc_operation_exampleDesc": "[시작하기]버튼을 클릭하면 10의 제곱, 9의 루트값, 90의 사인값, -10의 절댓값을 각 2초 동안 말합니다.", "get_project_timer_value_desc": "이 명령이 실행되는 순간 초시계에 저장된 값입니다.", "get_project_timer_value_exampleCode": "def when_start():\n Entry.timer(\"start\")\n Entry.wait_for_sec(3)\n Entry.timer(\"stop\")\n Entry.timer_view(\"hide\")\n Entry.print(Entry.value_of_timer())", "get_project_timer_value_exampleDesc": "[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.", "choose_project_timer_action_desc": "초시계의 동작을 A로 정합니다.
(이 명령어를 사용하면 실행화면에 ‘초시계 창’이 생성됩니다.)", "choose_project_timer_action_elements": "A-- 아래 선택지 중 하나
① \"start\" : 초시계를 시작
② \"stop\" : 초시계를 정지
③ \"reset\" : 초시계를 초기화", "choose_project_timer_action_exampleCode": "def when_start():\n Entry.timer(\"start\")\n Entry.wait_for_sec(3)\n Entry.timer(\"stop\")\n Entry.timer_view(\"hide\")\n Entry.print(Entry.value_of_timer())", "choose_project_timer_action_exampleDesc": "[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.", "set_visible_project_timer_desc": "실행화면의 초시계 창을 A로 설정합니다.", "set_visible_project_timer_elements": "A-- 아래 선택지 중 하나
① \"hide\" : 초시계창을 숨김
② \"show\" : 초시계창을 보임", "set_visible_project_timer_exampleCode": "def when_start():\n Entry.timer(\"start\")\n Entry.wait_for_sec(3)\n Entry.timer(\"stop\")\n Entry.timer_view(\"hide\")\n Entry.print(Entry.value_of_timer())", "set_visible_project_timer_exampleDesc": "[시작하기]버튼을 클릭하면 초시계를 시작합니다. 3초 뒤에는 초시계를 정지하고 초시계창을 숨깁니다. 그 후 초시계값을 말합니다.", "get_date_desc": "현재 A에 대한 값입니다.", "get_date_elements": "A-- 아래 선택지 중 하나
① \"year\" : 현재 연도 값
② \"month\" : 현재 월 값
③ \"day\" : 현재 일 값
④ \"hour\" : 현재 시간 값
⑤ \"minute\" : 현재 분 값
⑥ \"second\" : 현재 초 값", "get_date_exampleCode": "def when_start():\n Entry.print(Entry.value_of_current_time(\"year\") + \"년\" + Entry.value_of_current_time(\"month\") + \"월\")", "get_date_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 현재년도와 월을 말합니다.", "distance_something_desc": "자신과 A까지의 거리 값입니다.", "distance_something_elements": "A-- 아래 선택지 중 하나
① \"오브젝트 이름\"
② \"mouse_pointer\" 또는 \"마우스포인터\"", "distance_something_exampleCode": "def when_start():\n while True:\n Entry.print(Entry.value_of_distance_to(\"mouse_pointer\"))", "distance_something_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 마우스포인터와의 거리를 계속해서 말합니다.", "get_sound_duration_desc": "소리 A의 길이(초)값입니다.", "get_sound_duration_elements": "A-- \"소리 이름\"", "get_sound_duration_exampleCode": "def when_start():\n Entry.print(Entry.value_of_sound_length_of(\"소리\"))", "get_sound_duration_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 \"소리\"의 길이를 말합니다.", "get_user_name_desc": "작품을 실행하고 있는 사용자의 아이디 값입니다.", "get_user_name_exampleCode": "def when_start():\n Entry.print(Entry.value_of_username())", "get_user_name_exampleDesc": "[시작하기]버튼을 클릭하면 작품을 실행하고 있는 사용자의 아이디 값을 말합니다.", "get_nickname_desc": "작품을 실행하고 있는 사용자의 닉네임 값입니다.", "get_nickname_exampleCode": "def when_start():\n Entry.print(Entry.value_of_nickname())", "get_nickname_exampleDesc": "[시작하기]버튼을 클릭하면 작품을 실행하고 있는 사용자의 닉네임 값을 말합니다.", "length_of_string_desc": "입력한 문자값의 공백을 포함한 글자 수입니다.", "length_of_string_elements": "A-- \"문자열\"", "length_of_string_exampleCode": "def when_start():\n Entry.print_for_sec(len(\"안녕\"), 2)\n Entry.print_for_sec(len(\"엔트리\"), 2)", "length_of_string_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 \"안녕\"과 \"엔트리\"의 글자 수를 각각 2초 동안 말합니다.", "combine_something_desc": "A 문자열과 B 문자열을 결합한 값입니다. (A, B 중 하나가 숫자면 문자열로 바꾸어 처리되고, 둘 다 숫자면 덧셈 연산으로 처리됩니다.)", "combine_something_elements": "A, B-- \"문자열\"", "combine_something_exampleCode": "def when_start():\n Entry.print(\"안녕! \" + \"엔트리\")", "combine_something_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 \"안녕!\"과 \"엔트리\"를 결합한 \"안녕! 엔트리\"를 말합니다.", "char_at_desc": "A 문자열의 B번째의 글자 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)", "char_at_elements": "A-- \"문자열\"%nextB-- 찾고자 하는 문자열의 위치", "char_at_exampleCode": "def when_start():\n Entry.print(\"안녕 엔트리!\"[0])", "char_at_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 \"안녕 엔트리!\"의 0번째 글자인 \"안\"을 말합니다.", "substring_desc": "A 문자열의 B위치부터 C-1위치까지의 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)", "substring_elements": "A-- \"문자열\"%nextB-- 포함할 문자열의 시작 위치
첫 번째 글자는 0부터 시작%nextC-- 문자열을 포함하지 않는 위치", "substring_exampleCode": "def when_start():\n Entry.print(\"안녕 엔트리!\"[1:5])", "substring_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 \"안녕 엔트리!\"의 1에서 4번째 글자인 \"녕 엔트\"를 말합니다.", "index_of_string_desc": "A문자열에서 B문자열이 처음으로 등장하는 위치의 값입니다. (첫 번째 글자의 위치는 0부터 시작합니다.)", "index_of_string_elements": "A, B-- \"문자열\"", "index_of_string_exampleCode": "def when_start():\n Entry.print(\"안녕 엔트리!\".find(\"엔트리\"))", "index_of_string_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 \"안녕 엔트리!\"에서 \"엔트리\"가 처음으로 등장하는 위치인 3을 말합니다.", "replace_string_desc": "A 문자열에서 B문자열을 모두 찾아 C문자열로 바꾼 값입니다.
(영문 입력시 대소문자를 구분합니다.)", "replace_string_elements": "A, B, C-- \"문자열\"", "replace_string_exampleCode": "def when_start():\n Entry.print(\"안녕 엔트리!\".replace( \"안녕\", \"반가워\"))", "replace_string_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 \"안녕 엔트리!\"에서 \"안녕\"을 \"반가워\"로 바꾼 \"반가워 엔트리!\"를 말합니다.", "change_string_case_desc": "A의 모든 알파벳을 대문자 또는 소문자로 바꾼 문자값입니다.", "change_string_case_elements": "A-- \"문자열\"
① A.upper(): A의 모든 알파벳을 대문자로 바꾼 값
② A.lower() : A의 모든 알파벳을 소문자로 바꾼 값", "change_string_case_exampleCode": "def when_start():\n Entry.print_for_sec(\"Hello Entry!\".upper(), 2)\n Entry.print_for_sec(\"Hello Entry!\".lower(), 2)", "change_string_case_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 \"Hello Entry!\"를 모두 대문자로 바꾼 \"HELLO ENTRY!\"를 2초간 말한 다음 모두 소문자로 바꾼 \"hello entry!\"를 2초간 말합니다.", "ask_and_wait_desc": "오브젝트가 A 내용을 말풍선으로 묻고, 대답을 입력받습니다. 대답은 실행화면 또는 콘솔창에서 입력할 수 있으며 입력된 값은 'Entry.answer()'에 저장됩니다.
(이 명령어를 사용하면 실행화면에 ‘대답 창’이 생성됩니다.)", "ask_and_wait_elements": "A-- \"문자열\"", "ask_and_wait_exampleCode": "def when_start():\n Entry.input(\"이름을 입력해보세요.\")\n Entry.print(Entry.answer() + \" 반가워!\")", "ask_and_wait_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 \"이름을 입력해보세요.\"라고 말풍선으로 묻습니다. 이름을 입력하면 \"(입력한 이름) 반가워!\"라 말합니다.", "get_canvas_input_value_desc": "Entry.input(A) 명령에 의해 실행화면 또는 콘솔에서 입력받은 값입니다.", "get_canvas_input_value_exampleCode": "def when_start():\n Entry.input(\"이름을 입력해보세요.\")\n Entry.print(Entry.answer() + \" 반가워!\")", "get_canvas_input_value_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 \"이름을 입력해보세요.\"라고 말풍선으로 묻습니다. 이름을 입력하면 \"(입력한 이름) 반가워!\"라 말합니다.", "set_visible_answer_desc": "실행화면의 대답 창을 A로 설정합니다.", "set_visible_answer_elements": "A-- 아래 선택지 중 하나
① \"hide\" : 대답 창을 숨김
② \"show\" : 대답 창을 보임", "set_visible_answer_exampleCode": "def when_start():\n Entry.answer_view(\"hide\")\n Entry.input(\"나이를 입력하세요.\")\n Entry.print(Entry.answer())", "set_visible_answer_exampleDesc": "[시작하기]버튼을 클릭하면 대답창이 숨겨지고, 오브젝트가 \"나이를 입력하세요.\"라고 말풍선으로 묻습니다. 나이를 입력하면 오브젝트가 입력한 나이를 말합니다.", "get_variable_desc": "A 변수에 저장된 값입니다.", "get_variable_elements": "A-- 변수명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A", "get_variable_exampleCode": "age = 16\n\ndef when_start():\n Entry.print(age)", "get_variable_exampleDesc": "age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 \"16\"을 말합니다.", "change_variable_desc": "A 변수에 B만큼 더합니다.", "change_variable_elements": "A-- 변수명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 숫자값", "change_variable_exampleCode": "age = 16\n\ndef when_start():\n Entry.print_for_sec(age, 2)\n age += 2\n Entry.print_for_sec(age, 2)", "change_variable_exampleDesc": "age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 \"16\"을 2초 동안 말합니다. 그 후 age변수에 2를 더하고 더한값인 \"18\"을 2초 동안 말합니다.", "set_variable_desc": "A 변수의 값을 B로 정합니다. 만약 A 변수가 없으면 [속성] 탭에 A 변수가 자동 생성됩니다.", "set_variable_elements": "A-- 변수명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 변수에 넣을 값
① 문자 : \"안녕!\", \"엔트리\" 등
② 숫자 : 0, 10, 35 등", "set_variable_exampleCode": "age = 16\n\ndef when_start():\n Entry.print(age)", "set_variable_exampleDesc": "age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 오브젝트가 age 변수에 들어 가 있는 값인 \"16\"을 말합니다.", "show_variable_desc": "A 변수 창을 실행화면에 보이게 합니다.", "show_variable_elements": "A-- \"변수명\"
① 모든 오브젝트에서 사용: \"A\"
② 이 오브젝트에서 사용: \"self.A\"", "show_variable_exampleCode": "age = 16\n\ndef when_start():\n Entry.hide_variable(\"age\")\n Entry.wait_for_sec(2)\n age = 20\n Entry.show_variable(\"age\")", "show_variable_exampleDesc": "age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 age변수창을 실행화면에서 숨깁니다. 2초 후 변수값을 17로 바꾸고 age변수창을 실행화면에 보이게 합니다.", "hide_variable_desc": "A 변수 창을 실행화면에서 숨깁니다.", "hide_variable_elements": "A-- \"변수명\"
① 모든 오브젝트에서 사용: \"A\"
② 이 오브젝트에서 사용: \"self.A\"", "hide_variable_exampleCode": "age = 16\n\ndef when_start():\n Entry.hide_variable(\"age\")\n Entry.print_for_sec(age, 2)", "hide_variable_exampleDesc": "age라는 변수를 만들고 그 값을 16으로 정합니다. [시작하기]버튼을 클릭하면 age변수창을 실행화면에서 숨기고, 오브젝트가 age 변수에 들어 가 있는 값인 \"16\"을 2초 동안 말합니다.", "value_of_index_from_list_desc": "A 리스트에서 B위치의 항목 값을 의미합니다.
(첫 번째 항목의 위치는 0부터 시작합니다.)", "value_of_index_from_list_elements": "A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치", "value_of_index_from_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n Entry.print(basket[1])\n", "value_of_index_from_list_exampleDesc": "basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 오브젝트가 basket 리스트의 1번째 항목인 orange를 말합니다.", "add_value_to_list_desc": "A 리스트의 마지막 항목으로 B값이 추가됩니다.", "add_value_to_list_elements": "A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트에 넣을 항목 값
① 문자 : \"안녕!\", \"엔트리\" 등
② 숫자 : 0, 10, 35 등", "add_value_to_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n basket.append(\"juice\")\n Entry.print(basket[4])", "add_value_to_list_exampleDesc": "basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 \"juice\"를 basket의 마지막 항목으로 추가합니다. 오브젝트는 basket의 4번째 항목인 \"juice\"를 말합니다.", "remove_value_from_list_desc": "A 리스트의 B위치에 있는 항목을 삭제합니다.
(첫 번째 항목의 위치는 0부터 시작합니다.)", "remove_value_from_list_elements": "A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치값", "remove_value_from_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\ndef when_start():\n basket.pop(0)\n Entry.print(basket[0])", "remove_value_from_list_exampleDesc": "basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 0번째 항목인 apple을 삭제합니다. 오브젝트는 새롭게 basket의 0번째 항목이 된 \"orange\"를 말합니다.", "insert_value_to_list_desc": "A 리스트의 B위치에 C항목을 끼워 넣습니다.
(첫 번째 항목의 위치는 0부터 시작합니다. B위치보다 뒤에 있는 항목들은 순서가 하나씩 밀려납니다.)", "insert_value_to_list_elements": "A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치%nextC-- 리스트에 넣을 항목 값
① 문자 : \"안녕!\", \"엔트리\" 등
② 숫자 : 0, 10, 35 등", "insert_value_to_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n basket.insert(1, \"juice\")\n Entry.print(basket[2])", "insert_value_to_list_exampleDesc": "basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 1번째 위치에 항목 \"juice\"를 끼워 넣습니다. 오브젝트는 새롭게 basket의 2번째 항목이 된 \"orange\"를 말합니다.", "change_value_list_index_desc": "A 리스트에서 B위치에 있는 항목의 값을 C 값으로 바꿉니다.
(첫 번째 항목의 위치는 0부터 시작합니다.)", "change_value_list_index_elements": "A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A%nextB-- 리스트 항목의 위치%nextC-- 리스트에 넣을 항목 값
① 문자 : \"안녕!\", \"엔트리\" 등
② 숫자 : 0, 10, 35 등", "change_value_list_index_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n basket[0] = \"juice\"\n Entry.print(basket[0])", "change_value_list_index_exampleDesc": "basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket의 0번째 위치의 항목 \"apple\"을 \"juice\"로 바꿉니다. 오브젝트는 바뀐 basket의 0번째 항목 \"juice\"를 말합니다.", "length_of_list_desc": "A 리스트가 보유한 항목 개수 값입니다.", "length_of_list_elements": "A-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A", "length_of_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n Entry.print(len(basket))", "length_of_list_exampleDesc": "basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 오브젝트는 basket의 항목 개수인 4를 말합니다.", "is_included_in_list_desc": "A값을 가진 항목이 B리스트에 포함되어 있는지 확인합니다.", "is_included_in_list_elements": "A-- 리스트의 항목 값
① 문자 : \"안녕!\", \"엔트리\" 등
② 숫자 : 0, 10, 35 등%nextB-- 리스트명
① 모든 오브젝트에서 사용: A
② 이 오브젝트에서 사용: self.A", "is_included_in_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n if \"apple\" in basket:\n Entry.print(\"사과가 있어!\")", "is_included_in_list_exampleDesc": "basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트에 \"apple\"항목이 있는지 확인합니다. \"apple\"항목이 있기 때문에 오브젝트는 \"사과가 있어!\"라 말합니다.", "show_list_desc": "선택한 리스트 창을 실행화면에 보이게 합니다.", "show_list_elements": "A-- \"리스트명\"
① 모든 오브젝트에서 사용: \"A\"
② 이 오브젝트에서 사용: \"self.A\"", "show_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n Entry.hide_list(\"basket\")\n Entry.wait_for_sec(2)\n Entry.show_list(\"basket\")", "show_list_exampleDesc": "basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트를 2초간 숨긴 다음 보여줍니다.", "hide_list_desc": "선택한 리스트 창을 실행화면에서 숨깁니다.", "hide_list_elements": "A-- \"리스트명\"
① 모든 오브젝트에서 사용: \"A\"
② 이 오브젝트에서 사용: \"self.A\"", "hide_list_exampleCode": "basket = [\"apple\", \"orange\", \"pear\", \"grape\"]\n\ndef when_start():\n Entry.hide_list(\"basket\")\n Entry.wait_for_sec(2)\n Entry.show_list(\"basket\")", "hide_list_exampleDesc": "basket이라는 리스트를 만들고 4개의 항목을 넣습니다. [시작하기]버튼을 클릭하면 basket 리스트를 2초간 숨긴 다음 보여줍니다.", "boolean_and_or_desc": "A와 B의 판단값을 확인하여 True 또는 False로 판단합니다.", "boolean_and_or_elements": "② or : A와 B의 판단 중 하나라도 True인 경우 True, 아닌 경우 False", "boolean_and_or_exampleCode": "def when_start():\n while True:\n if Entry.is_key_pressed(\"a\") and Entry.is_key_pressed(\"s\"):\n Entry.add_effect(\"color\", 10)", "boolean_and_or_exampleDesc": "[시작하기]버튼을 클릭하고 키보드의 \"a\" 와 \"s\"키를 동시에 눌렀을 때, 색깔 효과를 10만큼 줍니다.", "check_weather_desc": "B날짜에 C지역의 날씨가 A인 경우 True로 판단합니다.", "check_weather_elements": "A-- 아래 선택지 중 하나
①    \"sunny\" : 맑음
②    \"partly cloudy\" : 구름조금
③    \"mostly cloudy\" : 구름많음
④    \"cloudy\" : 흐림
⑤    \"rainy\" : 비
⑥    \"sleet\" : 진눈깨비
⑦    \"snowy\" : 눈%nextB-- 아래 선택지 중 하나
①    \"yesterday\" : 어제
②    \"today\" : 오늘
③    \"tomorrow\" : 내일
④    \"After 2 days\" : 모레
⑤    \"After 3 days\" : 3일 후
⑥    \"After 4 days\" : 4일 후
⑦    \"After 5 days\" : 5일 후
⑧    \"After 6 days\" : 6일 후%nextC-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북", "check_weather_exampleCode": "def when_start():\n if Weather.is_condition_sunny(\"today\", \"Seoul\"):\n Entry.print(\"오늘 서울의 날씨는 맑습니다.\")", "check_weather_exampleDesc": "[시작하기]버튼을 클릭하면 오늘 서울의 날씨가 맑은지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 \"오늘 서울의 날씨는 맑습니다.\"라고 말합니다.​", "check_finedust_desc": "선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.", "check_finedust_elements": "A-- 아래 선택지 중 하나
①    \"good\" : 좋음
②    \"normal\" : 보통
③    \"bad\" : 나쁨
④    \"very bad\" : 매우나쁨%nextB-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북", "check_finedust_exampleCode": "def when_start():\n if Weather.is_current_finedust_grade_good(\"Seoul\"):\n Entry.print(\"현재 서울의 미세먼지 등급은 좋음입니다.\")", "check_finedust_exampleDesc": "[시작하기]버튼을 클릭하면 현재 서울의 미세먼지 등급이 좋음인지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 “오늘 서울의 미세먼지 등급은 좋음입니다.”라고 말합니다.​", "get_weather_data_desc": "선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.", "get_weather_data_elements": "A-- 아래 선택지 중 하나
①    \"the lowest temperature\" : 최저기온
②    \"the highest temperature\" : 최고기온
③    \"humidity\" : 습도
④    \"precipitation\" : 강수량
⑤    \"precipitation probability\" : 강수확률
⑥    \"wind speed\" : 풍속%nextB-- 아래 선택지 중 하나
①    \"yesterday\" : 어제
②    \"today\" : 오늘
③    \"tomorrow\" : 내일
④    \"After 2 days\" : 모레
⑤    \"After 3 days\" : 3일 후
⑥    \"After 4 days\" : 4일 후
⑦    \"After 5 days\" : 5일 후
⑧    \"After 6 days\" : 6일 후%nextC-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북", "get_weather_data_exampleCode": "def when_start():\n Entry.print(Weather.get_lowest_temperature(\"today\", \"Seoul\"))", "get_weather_data_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 최저기온을 말합니다.​", "get_current_weather_data_desc": "현재 B지역의 A 날씨 정보값을 의미합니다.", "get_current_weather_data_elements": "A-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북%nextB-- 아래 선택지 중 하나
①    \"temperature\" : 기온
②    \"concentration of fine dust\" : 미세먼지농도", "get_current_weather_data_exampleCode": "def when_start():\n Entry.print(Weather.get_current_temperature(\"Seoul\"))", "get_current_weather_data_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 현재 서울의 기온을 말합니다.", "get_today_temperature_desc": "오늘 A지역의 B 시간대 기온 정보값을 의미합니다.", "get_today_temperature_elements": "A-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북%nextB-- 아래 선택지 중 하나
①    \"00\" : 당일 00시 측정된 기온값
②    \"03\" : 당일 03시 측정된 기온값
③    \"06\" : 당일 06시 측정된 기온값
④    \"09\" : 당일 09시 측정된 기온값
⑤    \"12\" : 당일 12시 측정된 기온값
⑥    \"15\" : 당일 15시 측정된 기온값
⑦    \"18\" : 당일 18시 측정된 기온값
⑧    \"21\" : 당일 21시 측정된 기온값", "get_today_temperature_exampleCode": "def when_start():\n Entry.print(Weather.get_today_temperature(\"Seoul\", 00))", "get_today_temperature_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 00시 기온을 말합니다.​", "check_city_weather_desc": "B날짜에 C지역의 날씨가 A인 경우 True로 판단합니다.", "check_city_weather_elements": "A-- 아래 선택지 중 하나
①    \"sunny\" : 맑음
②    \"partly cloudy\" : 구름조금
③    \"mostly cloudy\" : 구름많음
④    \"cloudy\" : 흐림
⑤    \"rainy\" : 비
⑥    \"sleet\" : 진눈깨비
⑦    \"snowy\" : 눈%nextB-- 아래 선택지 중 하나
①    \"yesterday\" : 어제
②    \"today\" : 오늘
③    \"tomorrow\" : 내일
④    \"After 2 days\" : 모레
⑤    \"After 3 days\" : 3일 후
⑥    \"After 4 days\" : 4일 후
⑦    \"After 5 days\" : 5일 후
⑧    \"After 6 days\" : 6일 후%nextC-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북", "check_city_weather_exampleCode": "def when_start():\n if Weather.is_condition_sunny(\"today\", \"Seoul\"):\n Entry.print(\"오늘 서울의 날씨는 맑습니다.\")", "check_city_weather_exampleDesc": "[시작하기]버튼을 클릭하면 오늘 서울의 날씨가 맑은지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 \"오늘 서울의 날씨는 맑습니다.\"라고 말합니다.​", "check_city_finedust_desc": "선택한 지역의 현재 미세먼지 정보를 실제 미세먼지 등급과 비교하여 일치하는 경우 ‘참’으로 판단합니다.", "check_city_finedust_elements": "A-- 아래 선택지 중 하나
①    \"good\" : 좋음
②    \"normal\" : 보통
③    \"bad\" : 나쁨
④    \"very bad\" : 매우나쁨%nextB-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북", "check_city_finedust_exampleCode": "def when_start():\n if Weather.is_current_finedust_grade_good(\"Seoul\"):\n Entry.print(\"현재 서울의 미세먼지 등급은 좋음입니다.\")", "check_city_finedust_exampleDesc": "[시작하기]버튼을 클릭하면 현재 서울의 미세먼지 등급이 좋음인지 확인합니다. 만약 서울의 날씨가 맑다면 오브젝트가 “오늘 서울의 미세먼지 등급은 좋음입니다.”라고 말합니다.​", "get_city_weather_data_desc": "선택한 날짜와 지역의 각종 날씨 정보값(최저기온, 최고기온, 습도, 강수량, 강수확률, 풍속)입니다.", "get_city_weather_data_elements": "A-- 아래 선택지 중 하나
①    \"the lowest temperature\" : 최저기온
②    \"the highest temperature\" : 최고기온
③    \"humidity\" : 습도
④    \"precipitation\" : 강수량
⑤    \"precipitation probability\" : 강수확률
⑥    \"wind speed\" : 풍속%nextB-- 아래 선택지 중 하나
①    \"yesterday\" : 어제
②    \"today\" : 오늘
③    \"tomorrow\" : 내일
④    \"After 2 days\" : 모레
⑤    \"After 3 days\" : 3일 후
⑥    \"After 4 days\" : 4일 후
⑦    \"After 5 days\" : 5일 후
⑧    \"After 6 days\" : 6일 후%nextC-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북", "get_city_weather_data_exampleCode": "def when_start():\n Entry.print(Weather.get_lowest_temperature(\"today\", \"Seoul\"))", "get_city_weather_data_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 최저기온을 말합니다.​", "get_current_city_weather_data_desc": "현재 B지역의 A 날씨 정보값을 의미합니다.", "get_current_city_weather_data_elements": "A-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북%nextB-- 아래 선택지 중 하나
①    \"temperature\" : 기온
②    \"concentration of fine dust\" : 미세먼지농도", "get_current_city_weather_data_exampleCode": "def when_start():\n Entry.print(Weather.get_current_temperature(\"Seoul\"))", "get_current_city_weather_data_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 현재 서울의 기온을 말합니다.", "get_today_city_temperature_desc": "오늘 A지역의 B 시간대 기온 정보값을 의미합니다.", "get_today_city_temperature_elements": "A-- 아래 선택지 중 하나
①    \"Seoul\" : 서울
②    \"Gangwon-do\" : 강원
③    \"Gyeonggi-do\" : 경기
④    \"Gyeongsangnam-do\" : 경남
⑤    \"Gyeongsangbuk-do\" : 경북
⑥    \"Gwangju\" : 광주
⑦    \"Daegu\" : 대구
⑧    \"Daejeon\" : 대전
⑨    \"Busan\" : 부산
⑩    \"Sejong\" : 세종
⑪    \"Ulsan\" : 울산
⑫    \"Incheon\" : 인천
⑬    \"Jeollanam-do\" : 전남
⑭    \"Jeollabuk-do\" : 전북
⑮    \"Jeju\" : 제주
Ⓐ \"Chungcheongnam-do\" : 충남
Ⓑ \"Chungcheongbuk-do\": 충북%nextB-- 아래 선택지 중 하나
①    \"00\" : 당일 00시 측정된 기온값
②    \"03\" : 당일 03시 측정된 기온값
③    \"06\" : 당일 06시 측정된 기온값
④    \"09\" : 당일 09시 측정된 기온값
⑤    \"12\" : 당일 12시 측정된 기온값
⑥    \"15\" : 당일 15시 측정된 기온값
⑦    \"18\" : 당일 18시 측정된 기온값
⑧    \"21\" : 당일 21시 측정된 기온값", "get_today_city_temperature_exampleCode": "def when_start():\n Entry.print(Weather.get_today_city_temperature(\"Seoul\", 00))", "get_today_city_temperature_exampleDesc": "[시작하기]버튼을 클릭하면 오브젝트가 오늘 서울의 00시 기온을 말합니다.​" }; Lang.Painter = { "select_cut": "You can cut with a square dotted line.", "thickness_of_eraser": "Thickness of eraser", "font": "Font", "font_color": "Font color", "outline_color": "Outline color", "outline_thickness": "Outline thickness", "fill_color": "Fill", "inversion": "Inversion", "font_size": "Font size", "font_family": "Font family", "fullscreen": "Full screen", "exit_fullscreen": "Exit full screen", "picture_import": "Import a picture", "edit_way": "Edit way", "line": "Hàng", "vertex": "Vertex", "bitmap": "Bitmap", "vector": "Vector", "forward": "đằng trước", "backward": "đằng sau", "front": "phía trước", "back": "phía sau", "group": "group", "ungroup": "ungroup", "copy_picture": "sao chép", "delete_picture": "delete", "cut_picture": "cắt", "paste_picture": "dán", "remove_all": "xoá tất cả", "new_picture": "hình ảnh mới", "edit": "Edit", "picture_size": "kích cỡ", "picture_rotation": "xoay vòng", "thickness": "độ dày", "font_fill": "Fill", "painter_file_save": "lưu", "painter_file_saveas": "lưu thành hình ảnh mới", "file": "File", "Pencil": "Cây bút", "Line": "Hàng", "Path": "Path", "Pan": "Move", "Select": "Select", "Rectangle": "Hình chữ nhật", "Ellipse": "hình bầu dục", "Text": "Hộp văn bản", "Fill": "Lấp đầy", "Eraser": "Cục tẩy", "get_file": "nhận được", "copy_file": "sao chép" }; Lang.DataAnalytics = { "data_analysis": "Data Analysis", "create_table": "Add Table", "data": "Data Analysis", "add_table": "Add Table", "show_chart": "Show Chart", "legend": "Legend", "dashboard": "Dashboard", "table": "Table", "chart": "Chart", "attribute": "Column", "row": "Row", "average": "Average", "standard_deviation": "Standard Deviation", "maximum": "Maximum", "minimum": "Minimum", "median": "Median", "average_explain": "The result that add all values of that property and divide the total by number of the property.", "standard_deviation_explain": "A value that tells how spread out the data are from the average.\nCloser to zero means that the values are concentrated near the average.", "maximum_minimum_explain": "Largest and Smallest values for the property", "median_explain": "The value located at the center of the whole when all the values of the property are arranged in size order.", "add_row_above": "Add row above", "add_row_below": "Add row below", "delete_row": "Delete Row", "add_property_left": "Add Property to left", "add_property_right": "Add Property to right", "delete_attribute": "Delete Attribute", "data_alert": "You can only see counts for attributes that contain non-numeric values.", "save": "lưu", "cancel": "hủy bỏ", "confirm": "OK", "attribute_count": ".", "row_count": "row", "cell_count": "cell", "count": "count", "add_chart_alert": "No chart in table.\nAdd table.", "enter_attribute_name": "Please enter a column name(with less than 10 characters).", "placeholder_attribute_name": "Column name", "new_attribute": "New column", "chart_title": "Chart title", "remove_chart": "Delete chart", "add_chart_first": "No chart in table. \nAdd table.", "bar": "bar", "line": "line", "pie": "pie", "scatter": "scatter", "select_x_axis": "Select the horizontal axis.", "x_axis": "Horiz. axis", "y_axis": "Ver. axis", "select_y_axis": "Select the vertical axis.", "select_y_axis_or_legend": "Select the vertical axis or legends.", "select_legend": "Select the legends.", "cell": "Cell", "unable_to_express_chart": "This cannot be expressed in charts.", "edit_attribute_name": "Change name", "duplicate_attribute_name_title": "Failed to change column name.", "duplicate_attribute_name_content": "A column with the same name exists.", "fail_save_table": "Failed to save table.", "duplicate_table_name_content": "A table with the same name exists.", "saved_table_title": "Saved successfully.", "saved_table_content": "The information of table and charts was successfully saved.", "empty_table_name_content": "Table's name can't be space.", "do_not_delete_row": "The row cannot be deleted.", "rows_cannot_less_one": "Tables must have at least one row." }; Lang.SharePolicy = { "title": "Entry Project/Post share Guide" }; Lang.Support = ["ko", "en", "vn", "jp"]; if (typeof exports == "object") exports.Lang = Lang; ================================================ FILE: extern/model/object_detector_lite.tflite ================================================ [File too large to display: 13.2 MB] ================================================ FILE: extern/object-detector.worker.js ================================================ self.importScripts(`${self.location.pathname}/../vision_bundle.js`); let flipState; let isRun = false; self.onmessage = async ({ data }) => { if (data.action === 'object_detector_init') { initializeObjectDetector(data); } else if (data.action === 'object_detector_restart') { isRun = true; } else if (data.action === 'object_detector_change_option') { changeObjectDetectorOption(data.option); } else if (data.action === 'object_detector') { flipState = data.flipState; predictObjectDetector(data.imageBitmap); } else if (data.action === 'clear_object_detector') { clearPredictObjectDetector(); } }; let objectNameList; let workerContext; let drawingUtils; let objectDetector; let isPrevObjectDetector = false; let countDetectedObject = 0; let isDrawDetectedObjectDetector = false; const initializeObjectDetector = async (data) => { const { canvas, lang, option } = data; isRun = true; objectNameList = lang.objectNameList; isDrawDetectedObjectDetector = option.isDrawDetectedObjectDetector; workerContext = canvas.getContext('2d'); workerContext.font = '20px Arial'; workerContext.lineWidth = 5; drawingUtils = new DrawingUtils(workerContext); const vision = await FilesetResolver.forVisionTasks(`${self.location.pathname}/../wasm`); objectDetector = await ObjectDetector.createFromOptions(vision, { baseOptions: { modelAssetPath: `${self.location.pathname}/../model/object_detector_lite.tflite`, delegate: 'GPU', }, runningMode: 'VIDEO', scoreThreshold: 0.5, maxResults: 8, }); self.postMessage({ action: 'next_object_detector' }); }; const changeObjectDetectorOption = (option) => { isDrawDetectedObjectDetector = option.isDrawDetectedObjectDetector; }; const YX = (a) => { return Math.max(1, Math.min(10, 10 * (1 - (a - -0.15) / 0.25) + (1 - (0.1 - a) / 0.25))); }; const predictObjectDetector = (imageBitmap) => { try { if (!workerContext || !objectDetector || !isRun) { return; } const startTimeMs = performance.now(); const results = objectDetector.detectForVideo(imageBitmap, startTimeMs); workerContext.save(); workerContext.clearRect(0, 0, 640, 360); const { detections } = results; self.postMessage({ action: 'object_detector_data', objectDetectorResult: results, }); if (detections.length) { if (!isPrevObjectDetector) { isPrevObjectDetector = true; self.postMessage({ action: 'start_object_detector' }); } if (detections.length !== countDetectedObject) { countDetectedObject = detections.length; self.postMessage({ action: 'count_detected_object_detector', count: countDetectedObject, }); } if (!isDrawDetectedObjectDetector) { return; } detections.forEach((detect, i) => { drawObjectDetections(detect, i); }); } else if (isPrevObjectDetector) { isPrevObjectDetector = false; countDetectedObject = 0; self.postMessage({ action: 'stop_object_detector' }); } } catch (e) { console.error(e); } finally { workerContext.restore(); requestAnimationFrame(() => { self.postMessage({ action: 'next_object_detector' }); }); } }; const colors = [ 'rgb(66, 133, 244)', 'rgb(36, 193, 224)', 'rgb(52, 168, 83)', 'rgb(161, 66, 244)', 'rgb(244, 57, 160)', 'rgb(234, 67, 53)', 'rgb(250, 123, 23)', 'rgb(252, 201, 52)', ]; const contextFlip = (context, axis) => { if (flipState === 0) { context.scale(-1, 1); return { x: -axis.x - axis.offsetX, y: axis.y - axis.offsetY, }; } else if (flipState === 1) { context.scale(1, 1); return { x: axis.x + 3, y: axis.y - axis.offsetY, }; } else if (flipState === 2) { context.scale(-1, -1); return { x: -axis.x - axis.offsetX, y: -(axis.y - axis.offsetY - 6), }; } else if (flipState === 3) { context.scale(1, -1); return { x: axis.x + 3, y: -(axis.y - axis.offsetY - 6), }; } }; let offset = 0; function drawObjectDetections(detect, i) { try { const { boundingBox, categories } = detect; const [category] = categories; const displayName = category.displayName || category.categoryName; const text = objectNameList[displayName] || displayName; const x = boundingBox.originX; const y = boundingBox.originY; const w = boundingBox.width; const h = boundingBox.height; const e = (640 / 600) * 4; const measureText = workerContext.measureText(text); const l = measureText.width + 6; const measureSize = measureText.fontBoundingBoxAscent + measureText.fontBoundingBoxDescent + 2 * e; const m = x + w - l; workerContext.strokeStyle = colors[i]; workerContext.beginPath(); workerContext.moveTo(x, y); workerContext.lineTo(x + w, y); workerContext.lineTo(x + w, y + h); workerContext.lineTo(x, y + h); workerContext.lineTo(x, y); workerContext.stroke(); workerContext.fillStyle = colors[i]; workerContext.fillRect(m, y, l, measureSize); const { x: axisX, y: axisY } = contextFlip(workerContext, { offsetX: l - 3, offsetY: 3 * e, x: m, y: y + measureSize, }); workerContext.fillStyle = 'white'; workerContext.fillText(text, axisX, axisY); contextFlip(workerContext, { offsetX: 0, offsetY: 0, x: 0, y: 0 }); } catch (e) { console.error(e.stack); } } const clearPredictObjectDetector = () => { console.log('clearPredictObjectDetector'); isRun = false; isPrevObjectDetector = false; countDetectedObject = 0; workerContext.clearRect(0, 0, 640, 360); }; ================================================ FILE: extern/pose-landmarker.worker.js ================================================ self.importScripts(`${self.location.pathname}/../vision_bundle.js`); let flipState; let isRun = false; self.onmessage = async ({ data }) => { if (data.action === 'pose_landmarker_init') { initializePoseLandmarker(data); } else if (data.action === 'pose_landmarker_restart') { isRun = true; } else if (data.action === 'pose_landmarker_change_option') { changePoseLandmarkerOption(data.option); } else if (data.action === 'pose_landmarker') { flipState = data.flipState; predictPoseLandmarker(data.imageBitmap); } else if (data.action === 'clear_pose_landmarker') { clearPredictPoseLandmarker(); } }; let person; let workerContext; let drawingUtils; let poseLandmarker; let isPrevPoseLandmarker = false; let countDetectedPose = 0; let isDrawDetectedPoseLandmarker = false; const initializePoseLandmarker = async (data) => { const { canvas, lang, option } = data; isRun = true; person = lang.person; isDrawDetectedPoseLandmarker = option.isDrawDetectedPoseLandmarker; workerContext = canvas.getContext('2d'); workerContext.font = '20px Arial'; drawingUtils = new DrawingUtils(workerContext); const vision = await FilesetResolver.forVisionTasks(`${self.location.pathname}/../wasm`); poseLandmarker = await PoseLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: `${self.location.pathname}/../model/pose_landmarker_lite.task`, delegate: 'GPU', }, runningMode: 'VIDEO', numPoses: 4, }); self.postMessage({ action: 'next_pose_landmarker' }); }; const changePoseLandmarkerOption = (option) => { isDrawDetectedPoseLandmarker = option.isDrawDetectedPoseLandmarker; }; const contextFlip = (context, axis) => { if (flipState === 0) { context.scale(-1, 1); return { x: -axis.x * 640, y: axis.y * 360 - 20, }; } else if (flipState === 1) { context.scale(1, 1); return { x: axis.x * 640, y: axis.y * 360 - 20, }; } else if (flipState === 2) { context.scale(-1, -1); return { x: -axis.x * 640, y: -axis.y * 360 + 20, }; } else if (flipState === 3) { context.scale(1, -1); return { x: axis.x * 640, y: -axis.y * 360 + 20, }; } }; const predictPoseLandmarker = async (imageBitmap) => { try { if (!workerContext || !poseLandmarker) { return; } const startTimeMs = performance.now(); const results = await poseLandmarker.detectForVideo(imageBitmap, startTimeMs); if (!isRun) { return; } workerContext.save(); workerContext.clearRect(0, 0, 640, 360); const { landmarks } = results; self.postMessage({ action: 'pose_landmarker_data', poseLandmarkerResult: results, }); if (landmarks.length) { if (!isPrevPoseLandmarker) { isPrevPoseLandmarker = true; self.postMessage({ action: 'start_pose_landmarker' }); } if (landmarks.length !== countDetectedPose) { countDetectedPose = landmarks.length; self.postMessage({ action: 'count_detected_pose_landmarker', count: countDetectedPose, }); } if (!isDrawDetectedPoseLandmarker) { return; } landmarks.forEach((landmark, i) => { const mark7 = landmark[7]; const { x, y } = contextFlip(workerContext, mark7); workerContext.fillStyle = '#FF0000'; workerContext.fillText(`${i + 1}-${person}`, x, y); contextFlip(workerContext, mark7); drawingUtils.drawLandmarks(landmark, { radius: (data) => DrawingUtils.lerp(data.from.z, -0.15, 0.1, 5, 1), }); drawingUtils.drawConnectors(landmark, PoseLandmarker.POSE_CONNECTIONS); }); } else if (isPrevPoseLandmarker) { isPrevPoseLandmarker = false; countDetectedPose = 0; self.postMessage({ action: 'stop_pose_landmarker' }); } } catch (e) { console.error(e); } finally { workerContext.restore(); requestAnimationFrame(() => { self.postMessage({ action: 'next_pose_landmarker' }); }); } }; const clearPredictPoseLandmarker = () => { console.log('clearPredictPoseLandmarker'); isRun = false; isPrevPoseLandmarker = false; countDetectedPose = 0; workerContext.clearRect(0, 0, 640, 360); }; ================================================ FILE: extern/util/CanvasInput.js ================================================ 'use strict'; /*! * CanvasInput v1.1.5 * http://goldfirestudios.com/blog/108/CanvasInput-HTML5-Canvas-Text-Input * * (c) 2013-2014, James Simpson of GoldFire Studios * goldfirestudios.com * * MIT License */ (function() { // create a buffer that stores all inputs so that tabbing // between them is made possible. var inputs = []; // initialize the Canvas Input var CanvasInput = function CanvasInput(o) { var self = this; o = o ? o : {}; // setup the defaults self._canvas = o.canvas || null; self._isHidden = true; self._ctx = self._canvas ? self._canvas.getContext('2d') : null; self._x = o.x || 0; self._y = o.y || 0; self._extraX = o.extraX || 0; self._extraY = o.extraY || 0; self._fontSize = o.fontSize || 14; self._fontFamily = o.fontFamily || 'Arial'; self._fontColor = o.fontColor || '#000'; self._placeHolderColor = o.placeHolderColor || '#bfbebd'; self._fontWeight = o.fontWeight || 'normal'; self._fontStyle = o.fontStyle || 'normal'; self._readonly = o.readonly || false; self._maxlength = o.maxlength || null; self._width = o.width || 150; self._height = o.height || self._fontSize; self._padding = o.padding >= 0 ? o.padding : 5; self._borderWidth = o.borderWidth >= 0 ? o.borderWidth : 1; self._borderColor = o.borderColor || '#959595'; self._borderRadius = o.borderRadius >= 0 ? o.borderRadius : 3; self._backgroundImage = o.backgroundImage || ''; self._boxShadow = o.boxShadow || '1px 1px 0px rgba(255, 255, 255, 1)'; self._innerShadow = o.innerShadow || '0px 0px 4px rgba(0, 0, 0, 0.4)'; self._selectionColor = o.selectionColor || 'rgba(179, 212, 253, 0.8)'; self._placeHolder = o.placeHolder || ''; self._value = o.value || self._placeHolder; self._onsubmit = o.onsubmit || function() {}; self._onkeydown = o.onkeydown || function() {}; self._onkeyup = o.onkeyup || function() {}; self._onfocus = o.onfocus || function() {}; self._onblur = o.onblur || function() {}; self._cursor = false; self._cursorPos = 0; self._hasFocus = false; self._selection = [0, 0]; self._wasOver = false; self._topPosition = o.topPosition; // parse box shadow self.boxShadow(self._boxShadow, true); // calculate the full width and height with padding, borders and shadows self._calcWH(); // setup the off-DOM canvas self._renderCanvas = document.createElement('canvas'); self._renderCanvas.setAttribute('width', self.outerW); self._renderCanvas.setAttribute('height', self.outerH); self._renderCtx = self._renderCanvas.getContext('2d'); // setup another off-DOM canvas for inner-shadows self._shadowCanvas = document.createElement('canvas'); self._shadowCanvas.setAttribute('width', self._width + self._padding * 2); self._shadowCanvas.setAttribute('height', self._height + self._padding * 2); self._shadowCtx = self._shadowCanvas.getContext('2d'); // setup the background color if (typeof o.backgroundGradient !== 'undefined') { self._backgroundColor = self._renderCtx.createLinearGradient(0, 0, 0, self.outerH); self._backgroundColor.addColorStop(0, o.backgroundGradient[0]); self._backgroundColor.addColorStop(1, o.backgroundGradient[1]); } else { self._backgroundColor = o.backgroundColor || '#fff'; } // setup main canvas events if (self._canvas) { self._canvas.addEventListener( 'mousemove', function(e) { e = e || window.event; self.mousemove(e, self); }, false ); self._canvas.addEventListener( 'mousedown', function(e) { e = e || window.event; self.mousedown(e, self); }, false ); self._canvas.addEventListener( 'touchstart', function(e) { e = e || window.event; self.mousedown(e, self); }, false ); self._canvas.addEventListener( 'mouseup', function(e) { e = e || window.event; self.mouseup(e, self); }, false ); } // setup a global mouseup to blur the input outside of the canvas window.addEventListener( 'mouseup', function(e) { //e = e || window.event; //if (self._hasFocus && !self._mouseDown) { //self.blur(); //} }, true ); // create the hidden input element self._hiddenInput = document.createElement('input'); self._hiddenInput.className = 'entryCanvasHiddenInput'; self._hiddenInput.type = 'text'; self._hiddenInput.style.position = 'absolute'; self._hiddenInput.style.opacity = 0; self._hiddenInput.style.pointerEvents = 'none'; self._hiddenInput.style.left = '-500px'; self._hiddenInput.style.top = '0px'; self._hiddenInput.style.width = ''.concat(self._width, 'px'); self._hiddenInput.style.height = ''.concat(self._height, 'px'); self._hiddenInput.style.zIndex = -999; if (self._maxlength) { self._hiddenInput.maxLength = self._maxlength; } document.body.appendChild(self._hiddenInput); self._hiddenInput.value = self._value; // setup the keydown listener self._hiddenInput.addEventListener('keydown', function(e) { e = e || window.event; if (self._hasFocus) { self.keydown(e, self); } }); // setup the keyup listener self._hiddenInput.addEventListener('keyup', function(e) { e = e || window.event; // update the canvas input state information from the hidden input self._value = self._hiddenInput.value; self._cursorPos = self._hiddenInput.selectionStart; self.render(); if (self._hasFocus) { self._onkeyup(e, self); } }); // add this to the buffer inputs.push(self); self._inputsIndex = inputs.length - 1; // draw the text box self.render(); }; window.CanvasInput = CanvasInput; // setup the prototype CanvasInput.prototype = { /** * Get/set the main canvas. * @param {Object} data Canvas reference. * @return {Mixed} CanvasInput or current canvas. */ canvas: function canvas(data) { var self = this; if (typeof data !== 'undefined') { self._canvas = data; self._ctx = self._canvas.getContext('2d'); return self.render(); } else { return self._canvas; } }, /** * Get/set the x-position. * @param {Number} data The pixel position along the x-coordinate. * @return {Mixed} CanvasInput or current x-value. */ x: function x(data) { var self = this; if (typeof data !== 'undefined') { self._x = data; return self.render(); } else { return self._x; } }, /** * Get/set the y-position. * @param {Number} data The pixel position along the y-coordinate. * @return {Mixed} CanvasInput or current y-value. */ y: function y(data) { var self = this; if (typeof data !== 'undefined') { self._y = data; return self.render(); } else { return self._y; } }, /** * Get/set the extra x-position (generally used when no canvas is specified). * @param {Number} data The pixel position along the x-coordinate. * @return {Mixed} CanvasInput or current x-value. */ extraX: function extraX(data) { var self = this; if (typeof data !== 'undefined') { self._extraX = data; return self.render(); } else { return self._extraX; } }, /** * Get/set the extra y-position (generally used when no canvas is specified). * @param {Number} data The pixel position along the y-coordinate. * @return {Mixed} CanvasInput or current y-value. */ extraY: function extraY(data) { var self = this; if (typeof data !== 'undefined') { self._extraY = data; return self.render(); } else { return self._extraY; } }, /** * Get/set the font size. * @param {Number} data Font size. * @return {Mixed} CanvasInput or current font size. */ fontSize: function fontSize(data) { var self = this; if (typeof data !== 'undefined') { self._fontSize = data; return self.render(); } else { return self._fontSize; } }, /** * Get/set the font family. * @param {String} data Font family. * @return {Mixed} CanvasInput or current font family. */ fontFamily: function fontFamily(data) { var self = this; if (typeof data !== 'undefined') { self._fontFamily = data; return self.render(); } else { return self._fontFamily; } }, /** * Get/set the font color. * @param {String} data Font color. * @return {Mixed} CanvasInput or current font color. */ fontColor: function fontColor(data) { var self = this; if (typeof data !== 'undefined') { self._fontColor = data; return self.render(); } else { return self._fontColor; } }, /** * Get/set the place holder font color. * @param {String} data Font color. * @return {Mixed} CanvasInput or current place holder font color. */ placeHolderColor: function placeHolderColor(data) { var self = this; if (typeof data !== 'undefined') { self._placeHolderColor = data; return self.render(); } else { return self._placeHolderColor; } }, /** * Get/set the font weight. * @param {String} data Font weight. * @return {Mixed} CanvasInput or current font weight. */ fontWeight: function fontWeight(data) { var self = this; if (typeof data !== 'undefined') { self._fontWeight = data; return self.render(); } else { return self._fontWeight; } }, /** * Get/set the font style. * @param {String} data Font style. * @return {Mixed} CanvasInput or current font style. */ fontStyle: function fontStyle(data) { var self = this; if (typeof data !== 'undefined') { self._fontStyle = data; return self.render(); } else { return self._fontStyle; } }, /** * Get/set the width of the text box. * @param {Number} data Width in pixels. * @return {Mixed} CanvasInput or current width. */ width: function width(data) { var self = this; if (typeof data !== 'undefined') { self._width = data; self._calcWH(); self._updateCanvasWH(); return self.render(); } else { return self._width; } }, /** * Get/set the height of the text box. * @param {Number} data Height in pixels. * @return {Mixed} CanvasInput or current height. */ height: function height(data) { var self = this; if (typeof data !== 'undefined') { self._height = data; self._calcWH(); self._updateCanvasWH(); return self.render(); } else { return self._height; } }, /** * Get/set the padding of the text box. * @param {Number} data Padding in pixels. * @return {Mixed} CanvasInput or current padding. */ padding: function padding(data) { var self = this; if (typeof data !== 'undefined') { self._padding = data; self._calcWH(); self._updateCanvasWH(); return self.render(); } else { return self._padding; } }, /** * Get/set the border width. * @param {Number} data Border width. * @return {Mixed} CanvasInput or current border width. */ borderWidth: function borderWidth(data) { var self = this; if (typeof data !== 'undefined') { self._borderWidth = data; self._calcWH(); self._updateCanvasWH(); return self.render(); } else { return self._borderWidth; } }, /** * Get/set the border color. * @param {String} data Border color. * @return {Mixed} CanvasInput or current border color. */ borderColor: function borderColor(data) { var self = this; if (typeof data !== 'undefined') { self._borderColor = data; return self.render(); } else { return self._borderColor; } }, /** * Get/set the border radius. * @param {Number} data Border radius. * @return {Mixed} CanvasInput or current border radius. */ borderRadius: function borderRadius(data) { var self = this; if (typeof data !== 'undefined') { self._borderRadius = data; return self.render(); } else { return self._borderRadius; } }, /** * Get/set the background color. * @param {Number} data Background color. * @return {Mixed} CanvasInput or current background color. */ backgroundColor: function backgroundColor(data) { var self = this; if (typeof data !== 'undefined') { self._backgroundColor = data; return self.render(); } else { return self._backgroundColor; } }, /** * Get/set the background gradient. * @param {Number} data Background gradient. * @return {Mixed} CanvasInput or current background gradient. */ backgroundGradient: function backgroundGradient(data) { var self = this; if (typeof data !== 'undefined') { self._backgroundColor = self._renderCtx.createLinearGradient(0, 0, 0, self.outerH); self._backgroundColor.addColorStop(0, data[0]); self._backgroundColor.addColorStop(1, data[1]); return self.render(); } else { return self._backgroundColor; } }, /** * Get/set the box shadow. * @param {String} data Box shadow in CSS format (1px 1px 1px rgba(0, 0, 0.5)). * @param {Boolean} doReturn (optional) True to prevent a premature render. * @return {Mixed} CanvasInput or current box shadow. */ boxShadow: function boxShadow(data, doReturn) { var self = this; if (typeof data !== 'undefined') { // parse box shadow var boxShadow = data.split('px '); self._boxShadow = { x: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[0], 10), y: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[1], 10), blur: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[2], 10), color: self._boxShadow === 'none' ? '' : boxShadow[3], }; // take into account the shadow and its direction if (self._boxShadow.x < 0) { self.shadowL = Math.abs(self._boxShadow.x) + self._boxShadow.blur; self.shadowR = self._boxShadow.blur + self._boxShadow.x; } else { self.shadowL = Math.abs(self._boxShadow.blur - self._boxShadow.x); self.shadowR = self._boxShadow.blur + self._boxShadow.x; } if (self._boxShadow.y < 0) { self.shadowT = Math.abs(self._boxShadow.y) + self._boxShadow.blur; self.shadowB = self._boxShadow.blur + self._boxShadow.y; } else { self.shadowT = Math.abs(self._boxShadow.blur - self._boxShadow.y); self.shadowB = self._boxShadow.blur + self._boxShadow.y; } self.shadowW = self.shadowL + self.shadowR; self.shadowH = self.shadowT + self.shadowB; self._calcWH(); if (!doReturn) { self._updateCanvasWH(); return self.render(); } } else { return self._boxShadow; } }, /** * Get/set the inner shadow. * @param {String} data In the format of a CSS box shadow (1px 1px 1px rgba(0, 0, 0.5)). * @return {Mixed} CanvasInput or current inner shadow. */ innerShadow: function innerShadow(data) { var self = this; if (typeof data !== 'undefined') { self._innerShadow = data; return self.render(); } else { return self._innerShadow; } }, /** * Get/set the text selection color. * @param {String} data Color. * @return {Mixed} CanvasInput or current selection color. */ selectionColor: function selectionColor(data) { var self = this; if (typeof data !== 'undefined') { self._selectionColor = data; return self.render(); } else { return self._selectionColor; } }, /** * Get/set the place holder text. * @param {String} data Place holder text. * @return {Mixed} CanvasInput or current place holder text. */ placeHolder: function placeHolder(data) { var self = this; if (typeof data !== 'undefined') { self._placeHolder = data; return self.render(); } else { return self._placeHolder; } }, /** * Get/set the current text box value. * @param {String} data Text value. * @return {Mixed} CanvasInput or current text value. */ value: function value(data) { var self = this; if (typeof data !== 'undefined') { self._value = ''.concat(data); self._hiddenInput.value = ''.concat(data); // update the cursor position self._cursorPos = self._clipText().length; self.render(); return self; } else { return self._value === self._placeHolder ? '' : self._value; } }, /** * Set or fire the onsubmit event. * @param {Function} fn Custom callback. */ onsubmit: function onsubmit(fn) { var self = this; if (typeof fn !== 'undefined') { self._onsubmit = fn; return self; } else { self._onsubmit(); } }, /** * Set or fire the onkeydown event. * @param {Function} fn Custom callback. */ onkeydown: function onkeydown(fn) { var self = this; if (typeof fn !== 'undefined') { self._onkeydown = fn; return self; } else { self._onkeydown(); } }, /** * Set or fire the onkeyup event. * @param {Function} fn Custom callback. */ onkeyup: function onkeyup(fn) { var self = this; if (typeof fn !== 'undefined') { self._onkeyup = fn; return self; } else { self._onkeyup(); } }, /** * Place focus on the CanvasInput box, placing the cursor * either at the end of the text or where the user clicked. * @param {Number} pos (optional) The position to place the cursor. * @return {CanvasInput} */ focus: function focus(pos) { var self = this; var input; // if this is readonly, don't allow it to get focus if (self._readonly) { return; } // only fire the focus event when going from unfocussed if (!self._hasFocus) { self._onfocus(self); // remove focus from all other inputs for (var i = 0; i < inputs.length; i++) { if (inputs[i]._hasFocus) { inputs[i].blur(); } } } // remove selection if (!self._selectionUpdated) { self._selection = [0, 0]; } else { delete self._selectionUpdated; } // update the cursor position self._cursorPos = typeof pos === 'number' ? pos : self._clipText().length; // clear the place holder if (self._placeHolder === self._value) { self._value = ''; self._hiddenInput.value = ''; } self._hasFocus = true; self._cursor = true; // setup cursor interval if (self._cursorInterval) { clearInterval(self._cursorInterval); } requestAnimationFrame(function() { self._cursorInterval = setInterval(function() { self._cursor = !self._cursor; self.render(); }, 500); // check if this is Chrome for Android (there is a bug with returning incorrect character key codes) }); var nav = navigator.userAgent.toLowerCase(); var isChromeMobile = nav.indexOf('chrome') >= 0 && nav.indexOf('mobile') >= 0 && nav.indexOf('android') >= 0; // add support for mobile var isMobile = typeof window.orientation !== 'undefined'; var hasHiddenFocus = false; if ( isMobile && !isChromeMobile && document && document.createElement && (input = document.createElement('input')) ) { input.type = 'text'; input.style.opacity = 0; input.style.position = 'absolute'; input.style.left = ''.concat( self._x + self._extraX + (self._canvas ? self._canvas.offsetLeft : 0), 'px' ); input.style.top = ''.concat( self._y + self._extraY + (self._canvas ? self._canvas.offsetTop : 0), 'px' ); input.style.width = self._width; input.style.height = 0; const form = document.createElement('form'); form.appendChild(input); document.body.appendChild(form); input.focus(); input.addEventListener( 'blur', function() { if (!hasHiddenFocus) { self.blur(self); } }, false ); input.addEventListener( 'focus', () => { self.focus(); }, false ); } else if (isMobile) { self.value(prompt(self._placeHolder) || ''); } // move the real focus to the hidden input var hasSelection = self._selection[0] > 0 || self._selection[1] > 0; hasHiddenFocus = true; self._hiddenInput.focus(); hasHiddenFocus = false; self._hiddenInput.selectionStart = hasSelection ? self._selection[0] : self._cursorPos; self._hiddenInput.selectionEnd = hasSelection ? self._selection[1] : self._cursorPos; return self.render(); }, /** * Removes focus from the CanvasInput box. * @param {Object} _this Reference to this. * @return {CanvasInput} */ blur: function blur(_this) { var self = _this || this; self._onblur(self); if (self._cursorInterval) { clearInterval(self._cursorInterval); } self._hasFocus = false; self._cursor = false; self._selection = [0, 0]; self._hiddenInput.blur(); // fill the place holder if (self._value === '') { self._value = self._placeHolder; } if (self._isHidden) { return; } return self.render(); }, /** * Fired with the keydown event to draw the typed characters. * @param {Event} e The keydown event. * @param {CanvasInput} self * @return {CanvasInput} */ keydown: function keydown(e, self) { var keyCode = e.which; var isShift = e.shiftKey; var key = null; var startText; var endText; // make sure the correct text field is being updated if (!self._hasFocus) { return; } // fire custom user event self._onkeydown(e, self); // add support for Ctrl/Cmd+A selection if (keyCode === 65 && (e.ctrlKey || e.metaKey)) { self._selection = [0, self._value.length]; self._hiddenInput.selectionStart = 0; self._hiddenInput.selectionEnd = self._value.length; e.preventDefault(); return self.render(); } // block keys that shouldn't be processed if (keyCode === 17 || e.metaKey || e.ctrlKey) { return self; } if (keyCode === 13) { // enter key e.preventDefault(); self._onsubmit(e, self); //Entry.dispatchEvent('canvasInputComplete'); } else if (keyCode === 9) { // tab key e.preventDefault(); if (inputs.length > 1) { var next = inputs[self._inputsIndex + 1] ? self._inputsIndex + 1 : 0; self.blur(); setTimeout(function() { inputs[next].focus(); }, 5); } } // update the canvas input state information from the hidden input self._value = self._hiddenInput.value; self._cursorPos = self._hiddenInput.selectionStart; self._selection = [0, 0]; if (!self._isHidden) { return self.render(); } }, /** * Fired with the click event on the canvas, and puts focus on/off * based on where the user clicks. * @param {Event} e The click event. * @param {CanvasInput} self * @return {CanvasInput} */ click: function click(e, self) { //var mouse = self._mousePos(e), //x = mouse.x, //y = mouse.y; if (this._isFirstClick) { delete this._isFirstClick; return; } var roundRect = Entry.stage.canvas.canvas.getBoundingClientRect(); var x = ((e.x - roundRect.left) / roundRect.width - 0.5) * 480; var y = ((e.y - roundRect.top) / roundRect.height - 0.5) * -270; if (self._endSelection) { delete self._endSelection; delete self._selectionUpdated; return; } if ((self._canvas && self._overInput(x, y)) || !self._canvas) { if (self._isHidden) { return; } if (self._mouseDown) { self._mouseDown = false; self.click(e, self); return self.focus(self._clickPos(x, y)); } } else { return self.blur(); } }, /** * Fired with the mousemove event to update the default cursor. * @param {Event} e The mousemove event. * @param {CanvasInput} self * @return {CanvasInput} */ mousemove: function mousemove(e, self) { var mouse = self._mousePos(e); var x = mouse.x; var y = mouse.y; var isOver = self._overInput(x, y); if (isOver && self._canvas) { self._canvas.style.cursor = 'text'; self._wasOver = true; } else if (self._wasOver && self._canvas) { self._canvas.style.cursor = 'default'; self._wasOver = false; } if (self._hasFocus && self._selectionStart >= 0) { var curPos = self._clickPos(x, y); var start = Math.min(self._selectionStart, curPos); var end = Math.max(self._selectionStart, curPos); if (!isOver) { self._selectionUpdated = true; self._endSelection = true; delete self._selectionStart; self.render(); return; } if (self._selection[0] !== start || self._selection[1] !== end) { self._selection = [start, end]; self.render(); } } }, /** * Fired with the mousedown event to start a selection drag. * @param {Event} e The mousedown event. * @param {CanvasInput} self */ mousedown: function mousedown(e, self) { e = Entry.Utils.convertMouseEvent(e); var roundRect = Entry.stage.getBoundRect(); var offsetX = e.offsetX || e.clientX - roundRect.left; var offsetY = e.offsetY || e.clientY - roundRect.top; var x = (offsetX / roundRect.width - 0.5) * 480; var y = (offsetY / roundRect.height - 0.5) * -270; var isOver = self._overInput(x, y); // setup the 'click' event self._mouseDown = isOver; var inputField = Entry.stage.inputField; if (isOver && !inputField._isHidden) { self._hasFocus = true; inputField.focus(); } else if (!isOver && inputField) { self._hasFocus = false; inputField.blur(); } // start the selection drag if inside the input if (self._hasFocus && isOver) { self._selectionStart = self._clickPos(x, y); } }, /** * Fired with the mouseup event to end a selection drag. * @param {Event} e The mouseup event. * @param {CanvasInput} self */ mouseup: function mouseup(e, self) { //var mouse = self._mousePos(e), //x = mouse.x, //y = mouse.y; //// update selection if a drag has happened //var isSelection = self._clickPos(x, y) !== self._selectionStart; //if (self._hasFocus && self._selectionStart >= 0 && self._overInput(x, y) && isSelection) { //self._selectionUpdated = true; //delete self._selectionStart; //self.render(); //} else { //delete self._selectionStart; //} //self.click(e, self); // if (self._isHidden) // return; // self.render(); // self.click(e,self); // var roundRect = Entry.stage.canvas.canvas.getBoundingClientRect(); // var x = ((e.clientX - roundRect.left) / roundRect.width - 0.5) * 480; // var y = ((e.clientY - roundRect.top) / roundRect.height - 0.5) * -270; }, /** * Helper method to get the off-DOM canvas. * @return {Object} Reference to the canvas. */ renderCanvas: function renderCanvas() { return this._renderCanvas; }, show: function show() { var self = this; self._isHidden = false; self._isFirstClick = true; self.value(''); self.focus(); }, hide: function hide() { var self = this; self._isHidden = true; self.blur(); }, setPosition: function setPosition(x, y) { var self = this; self._isHidden = false; self._isFirstClick = true; self._x = x || 0; self._y = y || 0; self.value(''); self.focus(); }, /** * Clears and redraws the CanvasInput on an off-DOM canvas, * and if a main canvas is provided, draws it all onto that. * @return {CanvasInput} */ render: function render() { var self = this; var ctx = self._renderCtx; var w = self.outerW; var h = self.outerH; var br = self._borderRadius; var bw = self._borderWidth; var sw = self.shadowW; var sh = self.shadowH; // clear the canvas ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // setup the box shadow ctx.shadowOffsetX = self._boxShadow.x; ctx.shadowOffsetY = self._boxShadow.y; ctx.shadowBlur = self._boxShadow.blur; ctx.shadowColor = self._boxShadow.color; // draw the border if (self._borderWidth > 0) { ctx.fillStyle = self._borderColor; // self._roundedRect(ctx, self.shadowL, self.shadowT, w - sw, h - sh, br); self._roundedRect(ctx, self.shadowL, self.shadowT, w - sw, h - sh, br); ctx.fill(); ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; ctx.shadowBlur = 0; } // draw the text box background self._drawTextBox(function() { // make sure all shadows are reset ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; ctx.shadowBlur = 0; // clip the text so that it fits within the box var text = self._clipText(); // draw the selection var paddingBorder = self._padding + self._borderWidth + self.shadowT; if (self._selection[1] > 0) { var selectOffset = self._textWidth(text.substring(0, self._selection[0])); var selectWidth = self._textWidth( text.substring(self._selection[0], self._selection[1]) ); ctx.fillStyle = self._selectionColor; ctx.fillRect( paddingBorder + selectOffset, paddingBorder, selectWidth, self._height ); } // draw the cursor if (self._cursor) { var cursorOffset = self._textWidth(text.substring(0, self._cursorPos)); ctx.fillStyle = self._fontColor; ctx.fillRect(paddingBorder + cursorOffset, paddingBorder, 1, self._height); } // draw the text var textX = self._padding + self._borderWidth + self.shadowL; var textY = Math.round(paddingBorder + self._height / 2); // only remove the placeholder text if they have typed something text = text === '' && self._placeHolder ? self._placeHolder : text; ctx.fillStyle = self._value !== '' && self._value !== self._placeHolder ? self._fontColor : self._placeHolderColor; ctx.font = '' .concat(self._fontStyle, ' ') .concat(self._fontWeight, ' ') .concat(self._fontSize, 'px ') .concat(self._fontFamily); ctx.textAlign = 'left'; ctx.textBaseline = 'middle'; ctx.fillText(text, textX, textY); // parse inner shadow var innerShadow = self._innerShadow.split('px '); var isOffsetX = self._innerShadow === 'none' ? 0 : parseInt(innerShadow[0], 10); var isOffsetY = self._innerShadow === 'none' ? 0 : parseInt(innerShadow[1], 10); var isBlur = self._innerShadow === 'none' ? 0 : parseInt(innerShadow[2], 10); var isColor = self._innerShadow === 'none' ? '' : innerShadow[3]; // draw the inner-shadow (damn you canvas, this should be easier than this...) if (isBlur > 0) { var shadowCtx = self._shadowCtx; var scw = shadowCtx.canvas.width; var sch = shadowCtx.canvas.height; shadowCtx.clearRect(0, 0, scw, sch); shadowCtx.shadowBlur = isBlur; shadowCtx.shadowColor = isColor; // top shadow shadowCtx.shadowOffsetX = 0; shadowCtx.shadowOffsetY = isOffsetY; shadowCtx.fillRect(-1 * w, -100, 3 * w, 100); // right shadow shadowCtx.shadowOffsetX = isOffsetX; shadowCtx.shadowOffsetY = 0; shadowCtx.fillRect(scw, -1 * h, 100, 3 * h); // bottom shadow shadowCtx.shadowOffsetX = 0; shadowCtx.shadowOffsetY = isOffsetY; shadowCtx.fillRect(-1 * w, sch, 3 * w, 100); // left shadow shadowCtx.shadowOffsetX = isOffsetX; shadowCtx.shadowOffsetY = 0; shadowCtx.fillRect(-100, -1 * h, 100, 3 * h); // create a clipping mask on the main canvas self._roundedRect( ctx, bw + self.shadowL, bw + self.shadowT, w - bw * 2 - sw, h - bw * 2 - sh, br ); ctx.clip(); // draw the inner-shadow from the off-DOM canvas ctx.drawImage( self._shadowCanvas, 0, 0, scw, sch, bw + self.shadowL, bw + self.shadowT, scw, sch ); } // draw to the visible canvas if (self._ctx) { // self._ctx.clearRect(self._x, self._y, ctx.canvas.width, ctx.canvas.height); self._ctx.drawImage(self._renderCanvas, self._x, self._y); } return self; }); }, /** * Draw the text box area with either an image or background color. * @param {Function} fn Callback. */ _drawTextBox: function _drawTextBox(fn) { var self = this; var ctx = self._renderCtx; var w = self.outerW; var h = self.outerH; var br = self._borderRadius; var bw = self._borderWidth; var sw = self.shadowW; var sh = self.shadowH; // only draw the background shape if no image is being used if (self._backgroundImage === '') { ctx.fillStyle = self._backgroundColor; self._roundedRect( ctx, bw + self.shadowL, bw + self.shadowT, w - bw * 2 - sw, h - bw * 2 - sh, br ); ctx.fill(); fn(); } else { var img = new Image(); img.src = self._backgroundImage; img.onload = function() { ctx.drawImage( img, 0, 0, img.width, img.height, bw + self.shadowL, bw + self.shadowT, w, h ); fn(); }; } }, /** * Deletes selected text in selection range and repositions cursor. * @return {Boolean} true if text removed. */ _clearSelection: function _clearSelection() { var self = this; if (self._selection[1] > 0) { // clear the selected contents var start = self._selection[0]; var end = self._selection[1]; self._value = self._value.substr(0, start) + self._value.substr(end); self._cursorPos = start; self._cursorPos = self._cursorPos < 0 ? 0 : self._cursorPos; self._selection = [0, 0]; return true; } return false; }, /** * Clip the text string to only return what fits in the visible text box. * @param {String} value The text to clip. * @return {String} The clipped text. */ _clipText: function _clipText(value) { var self = this; value = typeof value === 'undefined' ? self._value : value; var textWidth = self._textWidth(value); var fillPer = textWidth / (self._width - self._padding); var text = fillPer > 1 ? value.substr(-1 * Math.floor(value.length / fillPer)) : value; return ''.concat(text); }, /** * Gets the pixel with of passed text. * @param {String} text The text to measure. * @return {Number} The measured width. */ _textWidth: function _textWidth(text) { var self = this; var ctx = self._renderCtx; ctx.font = '' .concat(self._fontStyle, ' ') .concat(self._fontWeight, ' ') .concat(self._fontSize, 'px ') .concat(self._fontFamily); ctx.textAlign = 'left'; return ctx.measureText(text).width; }, /** * Recalculate the outer with and height of the text box. */ _calcWH: function _calcWH() { var self = this; // calculate the full width and height with padding, borders and shadows self.outerW = self._width + self._padding * 2 + self._borderWidth * 2 + self.shadowW; self.outerH = self._height + self._padding * 2 + self._borderWidth * 2 + self.shadowH; }, /** * Update the width and height of the off-DOM canvas when attributes are changed. */ _updateCanvasWH: function _updateCanvasWH() { var self = this; var oldW = self._renderCanvas.width; var oldH = self._renderCanvas.height; // update off-DOM canvas self._renderCanvas.setAttribute('width', self.outerW); self._renderCanvas.setAttribute('height', self.outerH); self._shadowCanvas.setAttribute('width', self._width + self._padding * 2); self._shadowCanvas.setAttribute('height', self._height + self._padding * 2); // clear the main canvas if (self._ctx) { self._ctx.clearRect(self._x, self._y, oldW, oldH); } }, /** * Creates the path for a rectangle with rounded corners. * Must call ctx.fill() after calling this to draw the rectangle. * @param {Object} ctx Canvas context. * @param {Number} x x-coordinate to draw from. * @param {Number} y y-coordinate to draw from. * @param {Number} w Width of rectangle. * @param {Number} h Height of rectangle. * @param {Number} r Border radius. */ _roundedRect: function _roundedRect(ctx, x, y, w, h, r) { if (w < 2 * r) { r = w / 2; } if (h < 2 * r) { r = h / 2; } ctx.beginPath(); ctx.moveTo(x + r, y); ctx.lineTo(x + w - r, y); ctx.quadraticCurveTo(x + w, y, x + w, y + r); ctx.lineTo(x + w, y + h - r); ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h); ctx.lineTo(x + r, y + h); ctx.quadraticCurveTo(x, y + h, x, y + h - r); ctx.lineTo(x, y + r); ctx.quadraticCurveTo(x, y, x + r, y); ctx.closePath(); }, /** * Checks if a coordinate point is over the input box. * @param {Number} x x-coordinate position. * @param {Number} y y-coordinate position. * @return {Boolean} True if it is over the input box. */ _overInput: function _overInput(x, y) { return x >= -226 && x <= 183 && y >= -110 && y <= -73; }, /** * Use the mouse's x & y coordinates to determine * the position clicked in the text. * @param {Number} x X-coordinate. * @param {Number} y Y-coordinate. * @return {Number} Cursor position. */ _clickPos: function _clickPos(x, y) { var self = this; var value = self._value; // don't count placeholder text in this if (self._value === self._placeHolder) { value = ''; } // determine where the click was made along the string var text = self._clipText(value); var totalW = 0; var pos = text.length; if (x - (self._x + self._extraX) < self._textWidth(text)) { // loop through each character to identify the position for (var i = 0; i < text.length; i++) { totalW += self._textWidth(text[i]); if (totalW >= x - (self._x + self._extraX)) { pos = i; break; } } } return pos; }, /** * Calculate the mouse position based on the event callback and the elements on the page. * @param {Event} e * @return {Object} x & y values */ _mousePos: function _mousePos(e) { var elm = e.target; var style = document.defaultView.getComputedStyle(elm, undefined); var paddingLeft = parseInt(style.paddingLeft, 10) || 0; var paddingTop = parseInt(style.paddingLeft, 10) || 0; var borderLeft = parseInt(style.borderLeftWidth, 10) || 0; var borderTop = parseInt(style.borderLeftWidth, 10) || 0; var htmlTop = document.body.parentNode.offsetTop || 0; var htmlLeft = document.body.parentNode.offsetLeft || 0; var offsetX = 0; var offsetY = 0; var x; var y; // calculate the total offset if (typeof elm.offsetParent !== 'undefined') { do { offsetX += elm.offsetLeft; offsetY += elm.offsetTop; } while ((elm = elm.offsetParent)); } // take into account borders and padding offsetX += paddingLeft + borderLeft + htmlLeft; offsetY += paddingTop + borderTop + htmlTop; return { x: e.pageX - offsetX, y: e.pageY - offsetY, }; }, hasFocus: function hasFocus() { return this._hasFocus; }, }; })(); ================================================ FILE: extern/util/CanvasInputOrg.js ================================================ /*! * CanvasInput v1.1.5 * http://goldfirestudios.com/blog/108/CanvasInput-HTML5-Canvas-Text-Input * * (c) 2013-2014, James Simpson of GoldFire Studios * goldfirestudios.com * * MIT License */ (function() { // create a buffer that stores all inputs so that tabbing // between them is made possible. const inputs = []; // initialize the Canvas Input const CanvasInput = function(o) { const self = this; o = o ? o : {}; // setup the defaults self._canvas = o.canvas || null; self._isHidden = true; self._ctx = self._canvas ? self._canvas.getContext('2d') : null; self._x = o.x || 0; self._y = o.y || 0; self._extraX = o.extraX || 0; self._extraY = o.extraY || 0; self._fontSize = o.fontSize || 14; self._fontFamily = o.fontFamily || 'Arial'; self._fontColor = o.fontColor || '#000'; self._placeHolderColor = o.placeHolderColor || '#bfbebd'; self._fontWeight = o.fontWeight || 'normal'; self._fontStyle = o.fontStyle || 'normal'; self._readonly = o.readonly || false; self._maxlength = o.maxlength || null; self._width = o.width || 150; self._height = o.height || self._fontSize; self._padding = o.padding >= 0 ? o.padding : 5; self._borderWidth = o.borderWidth >= 0 ? o.borderWidth : 1; self._borderColor = o.borderColor || '#959595'; self._borderRadius = o.borderRadius >= 0 ? o.borderRadius : 3; self._backgroundImage = o.backgroundImage || ''; self._boxShadow = o.boxShadow || '1px 1px 0px rgba(255, 255, 255, 1)'; self._innerShadow = o.innerShadow || '0px 0px 4px rgba(0, 0, 0, 0.4)'; self._selectionColor = o.selectionColor || 'rgba(179, 212, 253, 0.8)'; self._placeHolder = o.placeHolder || ''; self._value = o.value || self._placeHolder; self._onsubmit = o.onsubmit || function() {}; self._onkeydown = o.onkeydown || function() {}; self._onkeyup = o.onkeyup || function() {}; self._onfocus = o.onfocus || function() {}; self._onblur = o.onblur || function() {}; self._cursor = false; self._cursorPos = 0; self._hasFocus = false; self._selection = [0, 0]; self._wasOver = false; self._topPosition = o.topPosition; // parse box shadow self.boxShadow(self._boxShadow, true); // calculate the full width and height with padding, borders and shadows self._calcWH(); // setup the off-DOM canvas self._renderCanvas = document.createElement('canvas'); self._renderCanvas.setAttribute('width', self.outerW); self._renderCanvas.setAttribute('height', self.outerH); self._renderCtx = self._renderCanvas.getContext('2d'); // setup another off-DOM canvas for inner-shadows self._shadowCanvas = document.createElement('canvas'); self._shadowCanvas.setAttribute('width', self._width + self._padding * 2); self._shadowCanvas.setAttribute('height', self._height + self._padding * 2); self._shadowCtx = self._shadowCanvas.getContext('2d'); // setup the background color if (typeof o.backgroundGradient !== 'undefined') { self._backgroundColor = self._renderCtx.createLinearGradient(0, 0, 0, self.outerH); self._backgroundColor.addColorStop(0, o.backgroundGradient[0]); self._backgroundColor.addColorStop(1, o.backgroundGradient[1]); } else { self._backgroundColor = o.backgroundColor || '#fff'; } // setup main canvas events if (self._canvas) { self._canvas.addEventListener( 'mousemove', (e) => { e = e || window.event; self.mousemove(e, self); }, false ); self._canvas.addEventListener( 'mousedown', (e) => { e = e || window.event; self.mousedown(e, self); }, false ); self._canvas.addEventListener( 'touchstart', (e) => { e = e || window.event; self.mousedown(e, self); }, false ); self._canvas.addEventListener( 'mouseup', (e) => { e = e || window.event; self.mouseup(e, self); }, false ); } // setup a global mouseup to blur the input outside of the canvas window.addEventListener( 'mouseup', (e) => { //e = e || window.event; //if (self._hasFocus && !self._mouseDown) { //self.blur(); //} }, true ); // create the hidden input element self._hiddenInput = document.createElement('input'); self._hiddenInput.className = 'entryCanvasHiddenInput'; self._hiddenInput.type = 'text'; self._hiddenInput.style.position = 'absolute'; self._hiddenInput.style.opacity = 0; self._hiddenInput.style.pointerEvents = 'none'; self._hiddenInput.style.left = '-500px'; self._hiddenInput.style.top = '0px'; self._hiddenInput.style.width = `${self._width}px`; self._hiddenInput.style.height = `${self._height}px`; self._hiddenInput.style.zIndex = -999; if (self._maxlength) { self._hiddenInput.maxLength = self._maxlength; } document.body.appendChild(self._hiddenInput); self._hiddenInput.value = self._value; // setup the keydown listener self._hiddenInput.addEventListener('keydown', (e) => { e = e || window.event; if (self._hasFocus) { self.keydown(e, self); } }); // setup the keyup listener self._hiddenInput.addEventListener('keyup', (e) => { e = e || window.event; // update the canvas input state information from the hidden input self._value = self._hiddenInput.value; self._cursorPos = self._hiddenInput.selectionStart; self.render(); if (self._hasFocus) { self._onkeyup(e, self); } }); // add this to the buffer inputs.push(self); self._inputsIndex = inputs.length - 1; // draw the text box self.render(); }; window.CanvasInput = CanvasInput; // setup the prototype CanvasInput.prototype = { /** * Get/set the main canvas. * @param {Object} data Canvas reference. * @return {Mixed} CanvasInput or current canvas. */ canvas(data) { const self = this; if (typeof data !== 'undefined') { self._canvas = data; self._ctx = self._canvas.getContext('2d'); return self.render(); } else { return self._canvas; } }, /** * Get/set the x-position. * @param {Number} data The pixel position along the x-coordinate. * @return {Mixed} CanvasInput or current x-value. */ x(data) { const self = this; if (typeof data !== 'undefined') { self._x = data; return self.render(); } else { return self._x; } }, /** * Get/set the y-position. * @param {Number} data The pixel position along the y-coordinate. * @return {Mixed} CanvasInput or current y-value. */ y(data) { const self = this; if (typeof data !== 'undefined') { self._y = data; return self.render(); } else { return self._y; } }, /** * Get/set the extra x-position (generally used when no canvas is specified). * @param {Number} data The pixel position along the x-coordinate. * @return {Mixed} CanvasInput or current x-value. */ extraX(data) { const self = this; if (typeof data !== 'undefined') { self._extraX = data; return self.render(); } else { return self._extraX; } }, /** * Get/set the extra y-position (generally used when no canvas is specified). * @param {Number} data The pixel position along the y-coordinate. * @return {Mixed} CanvasInput or current y-value. */ extraY(data) { const self = this; if (typeof data !== 'undefined') { self._extraY = data; return self.render(); } else { return self._extraY; } }, /** * Get/set the font size. * @param {Number} data Font size. * @return {Mixed} CanvasInput or current font size. */ fontSize(data) { const self = this; if (typeof data !== 'undefined') { self._fontSize = data; return self.render(); } else { return self._fontSize; } }, /** * Get/set the font family. * @param {String} data Font family. * @return {Mixed} CanvasInput or current font family. */ fontFamily(data) { const self = this; if (typeof data !== 'undefined') { self._fontFamily = data; return self.render(); } else { return self._fontFamily; } }, /** * Get/set the font color. * @param {String} data Font color. * @return {Mixed} CanvasInput or current font color. */ fontColor(data) { const self = this; if (typeof data !== 'undefined') { self._fontColor = data; return self.render(); } else { return self._fontColor; } }, /** * Get/set the place holder font color. * @param {String} data Font color. * @return {Mixed} CanvasInput or current place holder font color. */ placeHolderColor(data) { const self = this; if (typeof data !== 'undefined') { self._placeHolderColor = data; return self.render(); } else { return self._placeHolderColor; } }, /** * Get/set the font weight. * @param {String} data Font weight. * @return {Mixed} CanvasInput or current font weight. */ fontWeight(data) { const self = this; if (typeof data !== 'undefined') { self._fontWeight = data; return self.render(); } else { return self._fontWeight; } }, /** * Get/set the font style. * @param {String} data Font style. * @return {Mixed} CanvasInput or current font style. */ fontStyle(data) { const self = this; if (typeof data !== 'undefined') { self._fontStyle = data; return self.render(); } else { return self._fontStyle; } }, /** * Get/set the width of the text box. * @param {Number} data Width in pixels. * @return {Mixed} CanvasInput or current width. */ width(data) { const self = this; if (typeof data !== 'undefined') { self._width = data; self._calcWH(); self._updateCanvasWH(); return self.render(); } else { return self._width; } }, /** * Get/set the height of the text box. * @param {Number} data Height in pixels. * @return {Mixed} CanvasInput or current height. */ height(data) { const self = this; if (typeof data !== 'undefined') { self._height = data; self._calcWH(); self._updateCanvasWH(); return self.render(); } else { return self._height; } }, /** * Get/set the padding of the text box. * @param {Number} data Padding in pixels. * @return {Mixed} CanvasInput or current padding. */ padding(data) { const self = this; if (typeof data !== 'undefined') { self._padding = data; self._calcWH(); self._updateCanvasWH(); return self.render(); } else { return self._padding; } }, /** * Get/set the border width. * @param {Number} data Border width. * @return {Mixed} CanvasInput or current border width. */ borderWidth(data) { const self = this; if (typeof data !== 'undefined') { self._borderWidth = data; self._calcWH(); self._updateCanvasWH(); return self.render(); } else { return self._borderWidth; } }, /** * Get/set the border color. * @param {String} data Border color. * @return {Mixed} CanvasInput or current border color. */ borderColor(data) { const self = this; if (typeof data !== 'undefined') { self._borderColor = data; return self.render(); } else { return self._borderColor; } }, /** * Get/set the border radius. * @param {Number} data Border radius. * @return {Mixed} CanvasInput or current border radius. */ borderRadius(data) { const self = this; if (typeof data !== 'undefined') { self._borderRadius = data; return self.render(); } else { return self._borderRadius; } }, /** * Get/set the background color. * @param {Number} data Background color. * @return {Mixed} CanvasInput or current background color. */ backgroundColor(data) { const self = this; if (typeof data !== 'undefined') { self._backgroundColor = data; return self.render(); } else { return self._backgroundColor; } }, /** * Get/set the background gradient. * @param {Number} data Background gradient. * @return {Mixed} CanvasInput or current background gradient. */ backgroundGradient(data) { const self = this; if (typeof data !== 'undefined') { self._backgroundColor = self._renderCtx.createLinearGradient(0, 0, 0, self.outerH); self._backgroundColor.addColorStop(0, data[0]); self._backgroundColor.addColorStop(1, data[1]); return self.render(); } else { return self._backgroundColor; } }, /** * Get/set the box shadow. * @param {String} data Box shadow in CSS format (1px 1px 1px rgba(0, 0, 0.5)). * @param {Boolean} doReturn (optional) True to prevent a premature render. * @return {Mixed} CanvasInput or current box shadow. */ boxShadow(data, doReturn) { const self = this; if (typeof data !== 'undefined') { // parse box shadow const boxShadow = data.split('px '); self._boxShadow = { x: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[0], 10), y: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[1], 10), blur: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[2], 10), color: self._boxShadow === 'none' ? '' : boxShadow[3], }; // take into account the shadow and its direction if (self._boxShadow.x < 0) { self.shadowL = Math.abs(self._boxShadow.x) + self._boxShadow.blur; self.shadowR = self._boxShadow.blur + self._boxShadow.x; } else { self.shadowL = Math.abs(self._boxShadow.blur - self._boxShadow.x); self.shadowR = self._boxShadow.blur + self._boxShadow.x; } if (self._boxShadow.y < 0) { self.shadowT = Math.abs(self._boxShadow.y) + self._boxShadow.blur; self.shadowB = self._boxShadow.blur + self._boxShadow.y; } else { self.shadowT = Math.abs(self._boxShadow.blur - self._boxShadow.y); self.shadowB = self._boxShadow.blur + self._boxShadow.y; } self.shadowW = self.shadowL + self.shadowR; self.shadowH = self.shadowT + self.shadowB; self._calcWH(); if (!doReturn) { self._updateCanvasWH(); return self.render(); } } else { return self._boxShadow; } }, /** * Get/set the inner shadow. * @param {String} data In the format of a CSS box shadow (1px 1px 1px rgba(0, 0, 0.5)). * @return {Mixed} CanvasInput or current inner shadow. */ innerShadow(data) { const self = this; if (typeof data !== 'undefined') { self._innerShadow = data; return self.render(); } else { return self._innerShadow; } }, /** * Get/set the text selection color. * @param {String} data Color. * @return {Mixed} CanvasInput or current selection color. */ selectionColor(data) { const self = this; if (typeof data !== 'undefined') { self._selectionColor = data; return self.render(); } else { return self._selectionColor; } }, /** * Get/set the place holder text. * @param {String} data Place holder text. * @return {Mixed} CanvasInput or current place holder text. */ placeHolder(data) { const self = this; if (typeof data !== 'undefined') { self._placeHolder = data; return self.render(); } else { return self._placeHolder; } }, /** * Get/set the current text box value. * @param {String} data Text value. * @return {Mixed} CanvasInput or current text value. */ value(data) { const self = this; if (typeof data !== 'undefined') { self._value = `${data}`; self._hiddenInput.value = `${data}`; // update the cursor position self._cursorPos = self._clipText().length; self.render(); return self; } else { return self._value === self._placeHolder ? '' : self._value; } }, /** * Set or fire the onsubmit event. * @param {Function} fn Custom callback. */ onsubmit(fn) { const self = this; if (typeof fn !== 'undefined') { self._onsubmit = fn; return self; } else { self._onsubmit(); } }, /** * Set or fire the onkeydown event. * @param {Function} fn Custom callback. */ onkeydown(fn) { const self = this; if (typeof fn !== 'undefined') { self._onkeydown = fn; return self; } else { self._onkeydown(); } }, /** * Set or fire the onkeyup event. * @param {Function} fn Custom callback. */ onkeyup(fn) { const self = this; if (typeof fn !== 'undefined') { self._onkeyup = fn; return self; } else { self._onkeyup(); } }, /** * Place focus on the CanvasInput box, placing the cursor * either at the end of the text or where the user clicked. * @param {Number} pos (optional) The position to place the cursor. * @return {CanvasInput} */ focus(pos) { const self = this; let input; // if this is readonly, don't allow it to get focus if (self._readonly) { return; } // only fire the focus event when going from unfocussed if (!self._hasFocus) { self._onfocus(self); // remove focus from all other inputs for (let i = 0; i < inputs.length; i++) { if (inputs[i]._hasFocus) { inputs[i].blur(); } } } // remove selection if (!self._selectionUpdated) { self._selection = [0, 0]; } else { delete self._selectionUpdated; } // update the cursor position self._cursorPos = typeof pos === 'number' ? pos : self._clipText().length; // clear the place holder if (self._placeHolder === self._value) { self._value = ''; self._hiddenInput.value = ''; } self._hasFocus = true; self._cursor = true; // setup cursor interval if (self._cursorInterval) { clearInterval(self._cursorInterval); } self._cursorInterval = setInterval(() => { self._cursor = !self._cursor; self.render(); }, 500); // check if this is Chrome for Android (there is a bug with returning incorrect character key codes) const nav = navigator.userAgent.toLowerCase(); const isChromeMobile = nav.indexOf('chrome') >= 0 && nav.indexOf('mobile') >= 0 && nav.indexOf('android') >= 0; // add support for mobile const isMobile = typeof window.orientation !== 'undefined'; if ( isMobile && !isChromeMobile && document && document.createElement && (input = document.createElement('input')) ) { input.type = 'text'; input.style.opacity = 0; input.style.position = 'absolute'; input.style.left = `${self._x + self._extraX + (self._canvas ? self._canvas.offsetLeft : 0)}px`; input.style.top = `${self._y + self._extraY + (self._canvas ? self._canvas.offsetTop : 0)}px`; input.style.width = self._width; input.style.height = 0; document.body.appendChild(input); input.focus(); input.addEventListener( 'blur', () => { self.blur(self); }, false ); } else if (isMobile) { self.value(prompt(self._placeHolder) || ''); } // move the real focus to the hidden input const hasSelection = self._selection[0] > 0 || self._selection[1] > 0; self._hiddenInput.focus(); self._hiddenInput.selectionStart = hasSelection ? self._selection[0] : self._cursorPos; self._hiddenInput.selectionEnd = hasSelection ? self._selection[1] : self._cursorPos; return self.render(); }, /** * Removes focus from the CanvasInput box. * @param {Object} _this Reference to this. * @return {CanvasInput} */ blur(_this) { const self = _this || this; self._onblur(self); if (self._cursorInterval) { clearInterval(self._cursorInterval); } self._hasFocus = false; self._cursor = false; self._selection = [0, 0]; self._hiddenInput.blur(); // fill the place holder if (self._value === '') { self._value = self._placeHolder; } if (self._isHidden) { return; } return self.render(); }, /** * Fired with the keydown event to draw the typed characters. * @param {Event} e The keydown event. * @param {CanvasInput} self * @return {CanvasInput} */ keydown(e, self) { const keyCode = e.which; const isShift = e.shiftKey; const key = null; let startText; let endText; // make sure the correct text field is being updated if (!self._hasFocus) { return; } // fire custom user event self._onkeydown(e, self); // add support for Ctrl/Cmd+A selection if (keyCode === 65 && (e.ctrlKey || e.metaKey)) { self._selection = [0, self._value.length]; self._hiddenInput.selectionStart = 0; self._hiddenInput.selectionEnd = self._value.length; e.preventDefault(); return self.render(); } // block keys that shouldn't be processed if (keyCode === 17 || e.metaKey || e.ctrlKey) { return self; } if (keyCode === 13) { // enter key e.preventDefault(); self._onsubmit(e, self); //Entry.dispatchEvent('canvasInputComplete'); } else if (keyCode === 9) { // tab key e.preventDefault(); if (inputs.length > 1) { const next = inputs[self._inputsIndex + 1] ? self._inputsIndex + 1 : 0; self.blur(); setTimeout(() => { inputs[next].focus(); }, 5); } } // update the canvas input state information from the hidden input self._value = self._hiddenInput.value; self._cursorPos = self._hiddenInput.selectionStart; self._selection = [0, 0]; if (!self._isHidden) { return self.render(); } }, /** * Fired with the click event on the canvas, and puts focus on/off * based on where the user clicks. * @param {Event} e The click event. * @param {CanvasInput} self * @return {CanvasInput} */ click(e, self) { //var mouse = self._mousePos(e), //x = mouse.x, //y = mouse.y; if (this._isFirstClick) { delete this._isFirstClick; return; } const roundRect = Entry.stage.canvas.canvas.getBoundingClientRect(); const x = ((e.x - roundRect.left) / roundRect.width - 0.5) * 480; const y = ((e.y - roundRect.top) / roundRect.height - 0.5) * -270; if (self._endSelection) { delete self._endSelection; delete self._selectionUpdated; return; } if ((self._canvas && self._overInput(x, y)) || !self._canvas) { if (self._isHidden) { return; } if (self._mouseDown) { self._mouseDown = false; self.click(e, self); return self.focus(self._clickPos(x, y)); } } else { return self.blur(); } }, /** * Fired with the mousemove event to update the default cursor. * @param {Event} e The mousemove event. * @param {CanvasInput} self * @return {CanvasInput} */ mousemove(e, self) { const mouse = self._mousePos(e); const x = mouse.x; const y = mouse.y; const isOver = self._overInput(x, y); if (isOver && self._canvas) { self._canvas.style.cursor = 'text'; self._wasOver = true; } else if (self._wasOver && self._canvas) { self._canvas.style.cursor = 'default'; self._wasOver = false; } if (self._hasFocus && self._selectionStart >= 0) { const curPos = self._clickPos(x, y); const start = Math.min(self._selectionStart, curPos); const end = Math.max(self._selectionStart, curPos); if (!isOver) { self._selectionUpdated = true; self._endSelection = true; delete self._selectionStart; self.render(); return; } if (self._selection[0] !== start || self._selection[1] !== end) { self._selection = [start, end]; self.render(); } } }, /** * Fired with the mousedown event to start a selection drag. * @param {Event} e The mousedown event. * @param {CanvasInput} self */ mousedown(e, self) { e = Entry.Utils.convertMouseEvent(e); const roundRect = Entry.stage.getBoundRect(); const scrollPos = Entry.Utils.getScrollPos(); const x = ((e.pageX - roundRect.left - scrollPos.left) / roundRect.width - 0.5) * 480; const y = ((e.pageY - roundRect.top - scrollPos.top) / roundRect.height - 0.5) * -270; const mouse = self._mousePos(e); const isOver = self._overInput(x, y); // setup the 'click' event self._mouseDown = isOver; const inputField = Entry.stage.inputField; if (isOver && !inputField._isHidden) { self._hasFocus = true; inputField.focus(); } else if (!isOver && inputField) { self._hasFocus = false; inputField.blur(); } // start the selection drag if inside the input if (self._hasFocus && isOver) { self._selectionStart = self._clickPos(x, y); } }, /** * Fired with the mouseup event to end a selection drag. * @param {Event} e The mouseup event. * @param {CanvasInput} self */ mouseup(e, self) { //var mouse = self._mousePos(e), //x = mouse.x, //y = mouse.y; //// update selection if a drag has happened //var isSelection = self._clickPos(x, y) !== self._selectionStart; //if (self._hasFocus && self._selectionStart >= 0 && self._overInput(x, y) && isSelection) { //self._selectionUpdated = true; //delete self._selectionStart; //self.render(); //} else { //delete self._selectionStart; //} //self.click(e, self); // if (self._isHidden) // return; // self.render(); // self.click(e,self); // var roundRect = Entry.stage.canvas.canvas.getBoundingClientRect(); // var x = ((e.clientX - roundRect.left) / roundRect.width - 0.5) * 480; // var y = ((e.clientY - roundRect.top) / roundRect.height - 0.5) * -270; }, /** * Helper method to get the off-DOM canvas. * @return {Object} Reference to the canvas. */ renderCanvas() { return this._renderCanvas; }, show() { const self = this; self._isHidden = false; self._isFirstClick = true; self.value(''); self.focus(); }, hide() { const self = this; self._isHidden = true; self.blur(); }, setPosition(x, y) { const self = this; self._isHidden = false; self._isFirstClick = true; self._x = x || 0; self._y = y || 0; self.value(''); self.focus(); }, /** * Clears and redraws the CanvasInput on an off-DOM canvas, * and if a main canvas is provided, draws it all onto that. * @return {CanvasInput} */ render() { const self = this; const ctx = self._renderCtx; const w = self.outerW; const h = self.outerH; const br = self._borderRadius; const bw = self._borderWidth; const sw = self.shadowW; const sh = self.shadowH; // clear the canvas ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // setup the box shadow ctx.shadowOffsetX = self._boxShadow.x; ctx.shadowOffsetY = self._boxShadow.y; ctx.shadowBlur = self._boxShadow.blur; ctx.shadowColor = self._boxShadow.color; // draw the border if (self._borderWidth > 0) { ctx.fillStyle = self._borderColor; // self._roundedRect(ctx, self.shadowL, self.shadowT, w - sw, h - sh, br); self._roundedRect(ctx, self.shadowL, self.shadowT, w - sw, h - sh, br); ctx.fill(); ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; ctx.shadowBlur = 0; } // draw the text box background self._drawTextBox(() => { // make sure all shadows are reset ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; ctx.shadowBlur = 0; // clip the text so that it fits within the box let text = self._clipText(); // draw the selection const paddingBorder = self._padding + self._borderWidth + self.shadowT; if (self._selection[1] > 0) { const selectOffset = self._textWidth(text.substring(0, self._selection[0])); const selectWidth = self._textWidth( text.substring(self._selection[0], self._selection[1]) ); ctx.fillStyle = self._selectionColor; ctx.fillRect( paddingBorder + selectOffset, paddingBorder, selectWidth, self._height ); } // draw the cursor if (self._cursor) { const cursorOffset = self._textWidth(text.substring(0, self._cursorPos)); ctx.fillStyle = self._fontColor; ctx.fillRect(paddingBorder + cursorOffset, paddingBorder, 1, self._height); } // draw the text const textX = self._padding + self._borderWidth + self.shadowL; const textY = Math.round(paddingBorder + self._height / 2); // only remove the placeholder text if they have typed something text = text === '' && self._placeHolder ? self._placeHolder : text; ctx.fillStyle = self._value !== '' && self._value !== self._placeHolder ? self._fontColor : self._placeHolderColor; ctx.font = `${self._fontStyle} ${self._fontWeight} ${self._fontSize}px ${self._fontFamily}`; ctx.textAlign = 'left'; ctx.textBaseline = 'middle'; ctx.fillText(text, textX, textY); // parse inner shadow const innerShadow = self._innerShadow.split('px '); const isOffsetX = self._innerShadow === 'none' ? 0 : parseInt(innerShadow[0], 10); const isOffsetY = self._innerShadow === 'none' ? 0 : parseInt(innerShadow[1], 10); const isBlur = self._innerShadow === 'none' ? 0 : parseInt(innerShadow[2], 10); const isColor = self._innerShadow === 'none' ? '' : innerShadow[3]; // draw the inner-shadow (damn you canvas, this should be easier than this...) if (isBlur > 0) { const shadowCtx = self._shadowCtx; const scw = shadowCtx.canvas.width; const sch = shadowCtx.canvas.height; shadowCtx.clearRect(0, 0, scw, sch); shadowCtx.shadowBlur = isBlur; shadowCtx.shadowColor = isColor; // top shadow shadowCtx.shadowOffsetX = 0; shadowCtx.shadowOffsetY = isOffsetY; shadowCtx.fillRect(-1 * w, -100, 3 * w, 100); // right shadow shadowCtx.shadowOffsetX = isOffsetX; shadowCtx.shadowOffsetY = 0; shadowCtx.fillRect(scw, -1 * h, 100, 3 * h); // bottom shadow shadowCtx.shadowOffsetX = 0; shadowCtx.shadowOffsetY = isOffsetY; shadowCtx.fillRect(-1 * w, sch, 3 * w, 100); // left shadow shadowCtx.shadowOffsetX = isOffsetX; shadowCtx.shadowOffsetY = 0; shadowCtx.fillRect(-100, -1 * h, 100, 3 * h); // create a clipping mask on the main canvas self._roundedRect( ctx, bw + self.shadowL, bw + self.shadowT, w - bw * 2 - sw, h - bw * 2 - sh, br ); ctx.clip(); // draw the inner-shadow from the off-DOM canvas ctx.drawImage( self._shadowCanvas, 0, 0, scw, sch, bw + self.shadowL, bw + self.shadowT, scw, sch ); } // draw to the visible canvas if (self._ctx) { // self._ctx.clearRect(self._x, self._y, ctx.canvas.width, ctx.canvas.height); self._ctx.drawImage(self._renderCanvas, self._x, self._y); } return self; }); }, /** * Draw the text box area with either an image or background color. * @param {Function} fn Callback. */ _drawTextBox(fn) { const self = this; const ctx = self._renderCtx; const w = self.outerW; const h = self.outerH; const br = self._borderRadius; const bw = self._borderWidth; const sw = self.shadowW; const sh = self.shadowH; // only draw the background shape if no image is being used if (self._backgroundImage === '') { ctx.fillStyle = self._backgroundColor; self._roundedRect( ctx, bw + self.shadowL, bw + self.shadowT, w - bw * 2 - sw, h - bw * 2 - sh, br ); ctx.fill(); fn(); } else { const img = new Image(); img.src = self._backgroundImage; img.onload = function() { ctx.drawImage( img, 0, 0, img.width, img.height, bw + self.shadowL, bw + self.shadowT, w, h ); fn(); }; } }, /** * Deletes selected text in selection range and repositions cursor. * @return {Boolean} true if text removed. */ _clearSelection() { const self = this; if (self._selection[1] > 0) { // clear the selected contents const start = self._selection[0]; const end = self._selection[1]; self._value = self._value.substr(0, start) + self._value.substr(end); self._cursorPos = start; self._cursorPos = self._cursorPos < 0 ? 0 : self._cursorPos; self._selection = [0, 0]; return true; } return false; }, /** * Clip the text string to only return what fits in the visible text box. * @param {String} value The text to clip. * @return {String} The clipped text. */ _clipText(value) { const self = this; value = typeof value === 'undefined' ? self._value : value; const textWidth = self._textWidth(value); const fillPer = textWidth / (self._width - self._padding); const text = fillPer > 1 ? value.substr(-1 * Math.floor(value.length / fillPer)) : value; return `${text}`; }, /** * Gets the pixel with of passed text. * @param {String} text The text to measure. * @return {Number} The measured width. */ _textWidth(text) { const self = this; const ctx = self._renderCtx; ctx.font = `${self._fontStyle} ${self._fontWeight} ${self._fontSize}px ${self._fontFamily}`; ctx.textAlign = 'left'; return ctx.measureText(text).width; }, /** * Recalculate the outer with and height of the text box. */ _calcWH() { const self = this; // calculate the full width and height with padding, borders and shadows self.outerW = self._width + self._padding * 2 + self._borderWidth * 2 + self.shadowW; self.outerH = self._height + self._padding * 2 + self._borderWidth * 2 + self.shadowH; }, /** * Update the width and height of the off-DOM canvas when attributes are changed. */ _updateCanvasWH() { const self = this; const oldW = self._renderCanvas.width; const oldH = self._renderCanvas.height; // update off-DOM canvas self._renderCanvas.setAttribute('width', self.outerW); self._renderCanvas.setAttribute('height', self.outerH); self._shadowCanvas.setAttribute('width', self._width + self._padding * 2); self._shadowCanvas.setAttribute('height', self._height + self._padding * 2); // clear the main canvas if (self._ctx) { self._ctx.clearRect(self._x, self._y, oldW, oldH); } }, /** * Creates the path for a rectangle with rounded corners. * Must call ctx.fill() after calling this to draw the rectangle. * @param {Object} ctx Canvas context. * @param {Number} x x-coordinate to draw from. * @param {Number} y y-coordinate to draw from. * @param {Number} w Width of rectangle. * @param {Number} h Height of rectangle. * @param {Number} r Border radius. */ _roundedRect(ctx, x, y, w, h, r) { if (w < 2 * r) { r = w / 2; } if (h < 2 * r) { r = h / 2; } ctx.beginPath(); ctx.moveTo(x + r, y); ctx.lineTo(x + w - r, y); ctx.quadraticCurveTo(x + w, y, x + w, y + r); ctx.lineTo(x + w, y + h - r); ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h); ctx.lineTo(x + r, y + h); ctx.quadraticCurveTo(x, y + h, x, y + h - r); ctx.lineTo(x, y + r); ctx.quadraticCurveTo(x, y, x + r, y); ctx.closePath(); }, /** * Checks if a coordinate point is over the input box. * @param {Number} x x-coordinate position. * @param {Number} y y-coordinate position. * @return {Boolean} True if it is over the input box. */ _overInput(x, y) { const self = this; return x >= -138 && x <= 148 && y >= -112 && y <= -91; }, /** * Use the mouse's x & y coordinates to determine * the position clicked in the text. * @param {Number} x X-coordinate. * @param {Number} y Y-coordinate. * @return {Number} Cursor position. */ _clickPos(x, y) { const self = this; let value = self._value; // don't count placeholder text in this if (self._value === self._placeHolder) { value = ''; } // determine where the click was made along the string const text = self._clipText(value); let totalW = 0; let pos = text.length; if (x - (self._x + self._extraX) < self._textWidth(text)) { // loop through each character to identify the position for (let i = 0; i < text.length; i++) { totalW += self._textWidth(text[i]); if (totalW >= x - (self._x + self._extraX)) { pos = i; break; } } } return pos; }, /** * Calculate the mouse position based on the event callback and the elements on the page. * @param {Event} e * @return {Object} x & y values */ _mousePos(e) { let elm = e.target; const style = document.defaultView.getComputedStyle(elm, undefined); const paddingLeft = parseInt(style.paddingLeft, 10) || 0; const paddingTop = parseInt(style.paddingLeft, 10) || 0; const borderLeft = parseInt(style.borderLeftWidth, 10) || 0; const borderTop = parseInt(style.borderLeftWidth, 10) || 0; const htmlTop = document.body.parentNode.offsetTop || 0; const htmlLeft = document.body.parentNode.offsetLeft || 0; let offsetX = 0; let offsetY = 0; let x; let y; // calculate the total offset if (typeof elm.offsetParent !== 'undefined') { do { offsetX += elm.offsetLeft; offsetY += elm.offsetTop; } while ((elm = elm.offsetParent)); } // take into account borders and padding offsetX += paddingLeft + borderLeft + htmlLeft; offsetY += paddingTop + borderTop + htmlTop; return { x: e.pageX - offsetX, y: e.pageY - offsetY, }; }, hasFocus() { return this._hasFocus; }, }; })(); ================================================ FILE: extern/util/DragDropTouch.js ================================================ let DragDropTouch; (function(DragDropTouch_1) { 'use strict'; /** * Object used to hold the data that is being dragged during drag and drop operations. * * It may hold one or more data items of different types. For more information about * drag and drop operations and data transfer objects, see * HTML Drag and Drop API. * * This object is created automatically by the @see:DragDropTouch singleton and is * accessible through the @see:dataTransfer property of all drag events. */ const DataTransfer = (function() { function DataTransfer() { this._dropEffect = 'move'; this._effectAllowed = 'all'; this._data = {}; } Object.defineProperty(DataTransfer.prototype, 'dropEffect', { /** * Gets or sets the type of drag-and-drop operation currently selected. * The value must be 'none', 'copy', 'link', or 'move'. */ get() { return this._dropEffect; }, set(value) { this._dropEffect = value; }, enumerable: true, configurable: true, }); Object.defineProperty(DataTransfer.prototype, 'effectAllowed', { /** * Gets or sets the types of operations that are possible. * Must be one of 'none', 'copy', 'copyLink', 'copyMove', 'link', * 'linkMove', 'move', 'all' or 'uninitialized'. */ get() { return this._effectAllowed; }, set(value) { this._effectAllowed = value; }, enumerable: true, configurable: true, }); Object.defineProperty(DataTransfer.prototype, 'types', { /** * Gets an array of strings giving the formats that were set in the @see:dragstart event. */ get() { return Object.keys(this._data); }, enumerable: true, configurable: true, }); /** * Removes the data associated with a given type. * * The type argument is optional. If the type is empty or not specified, the data * associated with all types is removed. If data for the specified type does not exist, * or the data transfer contains no data, this method will have no effect. * * @param type Type of data to remove. */ DataTransfer.prototype.clearData = function(type) { if (type != null) { delete this._data[type]; } else { this._data = null; } }; /** * Retrieves the data for a given type, or an empty string if data for that type does * not exist or the data transfer contains no data. * * @param type Type of data to retrieve. */ DataTransfer.prototype.getData = function(type) { return this._data[type] || ''; }; /** * Set the data for a given type. * * For a list of recommended drag types, please see * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Recommended_Drag_Types. * * @param type Type of data to add. * @param value Data to add. */ DataTransfer.prototype.setData = function(type, value) { this._data[type] = value; }; /** * Set the image to be used for dragging if a custom one is desired. * * @param img An image element to use as the drag feedback image. * @param offsetX The horizontal offset within the image. * @param offsetY The vertical offset within the image. */ DataTransfer.prototype.setDragImage = function(img, offsetX, offsetY) { const ddt = DragDropTouch._instance; ddt._imgCustom = img; ddt._imgOffset = { x: offsetX, y: offsetY }; }; return DataTransfer; })(); DragDropTouch_1.DataTransfer = DataTransfer; /** * Defines a class that adds support for touch-based HTML5 drag/drop operations. * * The @see:DragDropTouch class listens to touch events and raises the * appropriate HTML5 drag/drop events as if the events had been caused * by mouse actions. * * The purpose of this class is to enable using existing, standard HTML5 * drag/drop code on mobile devices running IOS or Android. * * To use, include the DragDropTouch.js file on the page. The class will * automatically start monitoring touch events and will raise the HTML5 * drag drop events (dragstart, dragenter, dragleave, drop, dragend) which * should be handled by the application. * * For details and examples on HTML drag and drop, see * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_operations. */ var DragDropTouch = (function() { /** * Initializes the single instance of the @see:DragDropTouch class. */ function DragDropTouch() { this._lastClick = 0; // enforce singleton pattern if (DragDropTouch._instance) { throw 'DragDropTouch instance already created.'; } // detect passive event support // https://github.com/Modernizr/Modernizr/issues/1894 let supportsPassive = false; document.addEventListener('test', () => {}, { get passive() { supportsPassive = true; return true; }, }); // listen to touch events if ('ontouchstart' in document) { let d = document, ts = this._touchstart.bind(this), tm = this._touchmove.bind(this), te = this._touchend.bind(this), opt = supportsPassive ? { passive: false, capture: false } : false; d.addEventListener('touchstart', ts, opt); d.addEventListener('touchmove', tm, opt); d.addEventListener('touchend', te); d.addEventListener('touchcancel', te); } } /** * Gets a reference to the @see:DragDropTouch singleton. */ DragDropTouch.getInstance = function() { return DragDropTouch._instance; }; // ** event handlers DragDropTouch.prototype._touchstart = function(e) { const _this = this; if (this._shouldHandle(e)) { // raise double-click and prevent zooming if (Date.now() - this._lastClick < DragDropTouch._DBLCLICK) { if (this._dispatchEvent(e, 'dblclick', e.target)) { e.preventDefault(); this._reset(); return; } } // clear all variables this._reset(); // get nearest draggable element const src = this._closestDraggable(e.target); if (src) { // give caller a chance to handle the hover/move events if ( !this._dispatchEvent(e, 'mousemove', e.target) && !this._dispatchEvent(e, 'mousedown', e.target) ) { // get ready to start dragging this._dragSource = src; this._ptDown = this._getPoint(e); this._lastTouch = e; e.preventDefault(); // show context menu if the user hasn't started dragging after a while setTimeout(() => { if (_this._dragSource == src && _this._img == null) { if (_this._dispatchEvent(e, 'contextmenu', src)) { _this._reset(); } } }, DragDropTouch._CTXMENU); if (DragDropTouch._ISPRESSHOLDMODE) { this._pressHoldInterval = setTimeout(() => { _this._isDragEnabled = true; _this._touchmove(e); }, DragDropTouch._PRESSHOLDAWAIT); } } } } }; DragDropTouch.prototype._touchmove = function(e) { if (this._shouldCancelPressHoldMove(e)) { this._reset(); return; } if (this._shouldHandleMove(e) || this._shouldHandlePressHoldMove(e)) { // see if target wants to handle move const target = this._getTarget(e); if (this._dispatchEvent(e, 'mousemove', target)) { this._lastTouch = e; e.preventDefault(); return; } // start dragging if (this._dragSource && !this._img && this._shouldStartDragging(e)) { this._dispatchEvent(e, 'dragstart', this._dragSource); this._createImage(e); this._dispatchEvent(e, 'dragenter', target); } // continue dragging if (this._img) { this._lastTouch = e; e.preventDefault(); // prevent scrolling if (target != this._lastTarget) { this._dispatchEvent(this._lastTouch, 'dragleave', this._lastTarget); this._dispatchEvent(e, 'dragenter', target); this._lastTarget = target; } this._moveImage(e); this._dispatchEvent(e, 'dragover', target); } } }; DragDropTouch.prototype._touchend = function(e) { if (this._shouldHandle(e)) { // see if target wants to handle up if (this._dispatchEvent(this._lastTouch, 'mouseup', e.target)) { e.preventDefault(); return; } // user clicked the element but didn't drag, so clear the source and simulate a click if (!this._img) { this._dragSource = null; this._dispatchEvent(this._lastTouch, 'click', e.target); this._lastClick = Date.now(); } // finish dragging this._destroyImage(); if (this._dragSource) { if (e.type.indexOf('cancel') < 0) { this._dispatchEvent(this._lastTouch, 'drop', this._lastTarget); } this._dispatchEvent(this._lastTouch, 'dragend', this._dragSource); this._reset(); } } }; // ** utilities // ignore events that have been handled or that involve more than one touch DragDropTouch.prototype._shouldHandle = function(e) { return e && !e.defaultPrevented && e.touches && e.touches.length < 2; }; // use regular condition outside of press & hold mode DragDropTouch.prototype._shouldHandleMove = function(e) { return !DragDropTouch._ISPRESSHOLDMODE && this._shouldHandle(e); }; // allow to handle moves that involve many touches for press & hold DragDropTouch.prototype._shouldHandlePressHoldMove = function(e) { return ( DragDropTouch._ISPRESSHOLDMODE && this._isDragEnabled && e && e.touches && e.touches.length ); }; // reset data if user drags without pressing & holding DragDropTouch.prototype._shouldCancelPressHoldMove = function(e) { return ( DragDropTouch._ISPRESSHOLDMODE && !this._isDragEnabled && this._getDelta(e) > DragDropTouch._PRESSHOLDMARGIN ); }; // start dragging when specified delta is detected DragDropTouch.prototype._shouldStartDragging = function(e) { const delta = this._getDelta(e); return ( delta > DragDropTouch._THRESHOLD || (DragDropTouch._ISPRESSHOLDMODE && delta >= DragDropTouch._PRESSHOLDTHRESHOLD) ); }; // clear all members DragDropTouch.prototype._reset = function() { this._destroyImage(); this._dragSource = null; this._lastTouch = null; this._lastTarget = null; this._ptDown = null; this._dataTransfer = new DataTransfer(); this._isDragEnabled = false; clearInterval(this._pressHoldInterval); }; // get point for a touch event DragDropTouch.prototype._getPoint = function(e, page) { if (e && e.touches) { e = e.touches[0]; } return { x: page ? e.pageX : e.clientX, y: page ? e.pageY : e.clientY }; }; // get distance between the current touch event and the first one DragDropTouch.prototype._getDelta = function(e) { if (DragDropTouch._ISPRESSHOLDMODE && !this._ptDown) { return 0; } const p = this._getPoint(e); return Math.abs(p.x - this._ptDown.x) + Math.abs(p.y - this._ptDown.y); }; // get the element at a given touch event DragDropTouch.prototype._getTarget = function(e) { let pt = this._getPoint(e), el = document.elementFromPoint(pt.x, pt.y); while (el && getComputedStyle(el).pointerEvents == 'none') { el = el.parentElement; } return el; }; // create drag image from source element DragDropTouch.prototype._createImage = function(e) { // just in case... if (this._img) { this._destroyImage(); } // create drag image from custom element or drag source const src = this._imgCustom || this._dragSource; this._img = src.cloneNode(true); this._copyStyle(src, this._img); this._img.style.top = this._img.style.left = '-9999px'; // if creating from drag source, apply offset and opacity if (!this._imgCustom) { let rc = src.getBoundingClientRect(), pt = this._getPoint(e); this._imgOffset = { x: pt.x - rc.left, y: pt.y - rc.top }; this._img.style.opacity = DragDropTouch._OPACITY.toString(); } // add image to document this._moveImage(e); document.body.appendChild(this._img); }; // dispose of drag image element DragDropTouch.prototype._destroyImage = function() { if (this._img && this._img.parentElement) { this._img.parentElement.removeChild(this._img); } this._img = null; this._imgCustom = null; }; // move the drag image element DragDropTouch.prototype._moveImage = function(e) { const _this = this; requestAnimationFrame(() => { if (_this._img) { let pt = _this._getPoint(e, true), s = _this._img.style; s.position = 'absolute'; s.pointerEvents = 'none'; s.zIndex = '999999'; s.left = `${Math.round(pt.x - _this._imgOffset.x) }px`; s.top = `${Math.round(pt.y - _this._imgOffset.y) }px`; } }); }; // copy properties from an object to another DragDropTouch.prototype._copyProps = function(dst, src, props) { for (let i = 0; i < props.length; i++) { const p = props[i]; dst[p] = src[p]; } }; DragDropTouch.prototype._copyStyle = function(src, dst) { // remove potentially troublesome attributes DragDropTouch._rmvAtts.forEach((att) => { dst.removeAttribute(att); }); // copy canvas content if (src instanceof HTMLCanvasElement) { let cSrc = src, cDst = dst; cDst.width = cSrc.width; cDst.height = cSrc.height; cDst.getContext('2d').drawImage(cSrc, 0, 0); } // copy style (without transitions) const cs = getComputedStyle(src); for (var i = 0; i < cs.length; i++) { const key = cs[i]; if (key.indexOf('transition') < 0) { dst.style[key] = cs[key]; } } dst.style.pointerEvents = 'none'; // and repeat for all children for (var i = 0; i < src.children.length; i++) { this._copyStyle(src.children[i], dst.children[i]); } }; DragDropTouch.prototype._dispatchEvent = function(e, type, target) { if (e && target) { let evt = document.createEvent('Event'), t = e.touches ? e.touches[0] : e; evt.initEvent(type, true, true); evt.button = 0; evt.which = evt.buttons = 1; this._copyProps(evt, e, DragDropTouch._kbdProps); this._copyProps(evt, t, DragDropTouch._ptProps); evt.dataTransfer = this._dataTransfer; target.dispatchEvent(evt); return evt.defaultPrevented; } return false; }; // gets an element's closest draggable ancestor DragDropTouch.prototype._closestDraggable = function(e) { for (; e; e = e.parentElement) { if (e.hasAttribute('draggable') && e.draggable) { return e; } } return null; }; return DragDropTouch; })(); /*private*/ DragDropTouch._instance = new DragDropTouch(); // singleton // constants DragDropTouch._THRESHOLD = 5; // pixels to move before drag starts DragDropTouch._OPACITY = 0.5; // drag image opacity DragDropTouch._DBLCLICK = 500; // max ms between clicks in a double click DragDropTouch._CTXMENU = 900; // ms to hold before raising 'contextmenu' event DragDropTouch._ISPRESSHOLDMODE = false; // decides of press & hold mode presence DragDropTouch._PRESSHOLDAWAIT = 400; // ms to wait before press & hold is detected DragDropTouch._PRESSHOLDMARGIN = 25; // pixels that finger might shiver while pressing DragDropTouch._PRESSHOLDTHRESHOLD = 0; // pixels to move before drag starts // copy styles/attributes from drag source to drag image element DragDropTouch._rmvAtts = 'id,class,style,draggable'.split(','); // synthesize and dispatch an event // returns true if the event has been handled (e.preventDefault == true) DragDropTouch._kbdProps = 'altKey,ctrlKey,metaKey,shiftKey'.split(','); DragDropTouch._ptProps = 'pageX,pageY,clientX,clientY,screenX,screenY'.split(','); DragDropTouch_1.DragDropTouch = DragDropTouch; })(DragDropTouch || (DragDropTouch = {})); ================================================ FILE: extern/util/filbert.js ================================================ // Filbert is a Python parser written in JavaScript. // // Filbert was written by Matt Lott and released under an MIT // license. It was adatped from [Acorn](https://github.com/marijnh/acorn.git) // by Marijn Haverbeke. // // Git repository for Filbert are available at // // https://github.com/differentmatt/filbert.git // // Please use the [github bug tracker][ghbt] to report issues. // // [ghbt]: https://github.com/differentmatt/filbert/issues (function(root, mod) { if (typeof exports == 'object' && typeof module == 'object') return mod(exports); // CommonJS if (typeof define == 'function' && define.amd) return define(['exports'], mod); // AMD mod(root.filbert || (root.filbert = {})); // Plain browser env })(this, function(exports) { 'use strict'; exports.version = '0.5.1'; // The main exported interface (under `self.filbert` when in the // browser) is a `parse` function that takes a code string and // returns an abstract syntax tree as specified by [Mozilla parser // API][api]. // // [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API var options, input, inputLen, sourceFile, nc; exports.parse = function(inpt, opts) { input = String(inpt); inputLen = input.length; setOptions(opts); initTokenState(); nc = getNodeCreator(startNode, startNodeFrom, finishNode, unpackTuple); return parseTopLevel(options.program); }; // A second optional argument can be given to further configure // the parser process. These options are recognized: var defaultOptions = exports.defaultOptions = { // `languageVersion` indicates the Python version to parse. It // is not currently in use, but will support 2 or 3 eventually. languageVersion: 3, // When `allowTrailingCommas` is false, the parser will not allow // trailing commas in array and object literals. allowTrailingCommas: true, // When enabled, a return at the top level is not considered an // error. allowReturnOutsideFunction: true, // When `locations` is on, `loc` properties holding objects with // `start` and `end` properties in `{line, column}` form (with // line being 1-based and column 0-based) will be attached to the // nodes. locations: true, // A function can be passed as `onComment` option, which will // cause Filbert to call that function with `(text, start, // end)` parameters whenever a comment is skipped. // `text` is the content of the comment, and `start` and `end` are // character offsets that denote the start and end of the comment. // When the `locations` option is on, two more parameters are // passed, the full `{line, column}` locations of the start and // end of the comments. Note that you are not allowed to call the // parser from the callback-that will corrupt its internal state. onComment: null, // [semi-standardized][range] `range` property holding a `[start, // end]` array with the same numbers, set the `ranges` option to // `true`. // // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678 ranges: false, // It is possible to parse multiple files into a single AST by // passing the tree produced by parsing the first file as // `program` option in subsequent parses. This will add the // toplevel forms of the parsed file to the `Program` (top) node // of an existing parse tree. program: null, // When `locations` is on, you can pass this to record the source // file in every node's `loc` object. sourceFile: null, // This value, if given, is stored in every node, whether // `locations` is on or off. directSourceFile: null, // Python runtime library object name runtimeParamName: '__pythonRuntime', }; function setOptions(opts) { options = opts || {}; for (var opt in defaultOptions) if (!Object.prototype.hasOwnProperty.call(options, opt)) options[opt] = defaultOptions[opt]; sourceFile = options.sourceFile || null; } // The `getLineInfo` function is mostly useful when the // `locations` option is off (for performance reasons) and you // want to find the line/column position for a given character // offset. `input` should be the code string that the offset refers // into. var getLineInfo = exports.getLineInfo = function(input, offset) { for (var line = 1, cur = 0; ;) { lineBreak.lastIndex = cur; var match = lineBreak.exec(input); if (match && match.index < offset) { ++line; cur = match.index + match[0].length; } else break; } return { line: line, column: offset - cur }; }; // Filbert is organized as a tokenizer and a recursive-descent parser. // The `tokenize` export provides an interface to the tokenizer. // Because the tokenizer is optimized for being efficiently used by // the Filbert parser itself, this interface is somewhat crude and not // very modular. Performing another parse or call to `tokenize` will // reset the internal state, and invalidate existing tokenizers. exports.tokenize = function(inpt, opts) { input = String(inpt); inputLen = input.length; setOptions(opts); initTokenState(); var t = {}; function getToken(forceRegexp) { lastEnd = tokEnd; readToken(forceRegexp); t.start = tokStart; t.end = tokEnd; t.startLoc = tokStartLoc; t.endLoc = tokEndLoc; t.type = tokType; t.value = tokVal; return t; } getToken.jumpTo = function(pos, reAllowed) { tokPos = pos; if (options.locations) { tokCurLine = 1; tokLineStart = lineBreak.lastIndex = 0; var match; while ((match = lineBreak.exec(input)) && match.index < pos) { ++tokCurLine; tokLineStart = match.index + match[0].length; } } tokRegexpAllowed = reAllowed; skipSpace(); }; return getToken; }; // State is kept in (closure-)global variables. We already saw the // `options`, `input`, and `inputLen` variables above. // The current position of the tokenizer in the input. var tokPos; // The start and end offsets of the current token. var tokStart, tokEnd; // When `options.locations` is true, these hold objects // containing the tokens start and end line/column pairs. var tokStartLoc, tokEndLoc; // The type and value of the current token. Token types are objects, // named by variables against which they can be compared, and // holding properties that describe them (indicating, for example, // the precedence of an infix operator, and the original name of a // keyword token). The kind of value that's held in `tokVal` depends // on the type of the token. For literals, it is the literal value, // for operators, the operator name, and so on. var tokType, tokVal; // Interal state for the tokenizer. To distinguish between division // operators and regular expressions, it remembers whether the last // token was one that is allowed to be followed by an expression. // (If it is, a slash is probably a regexp, if it isn't it's a // division operator. See the `parseStatement` function for a // caveat.) var tokRegexpAllowed; // When `options.locations` is true, these are used to keep // track of the current line, and know when a new line has been // entered. var tokCurLine, tokLineStart; // These store the position of the previous token, which is useful // when finishing a node and assigning its `end` position. var lastStart, lastEnd, lastEndLoc; // This is the parser's state. `inFunction` is used to reject // `return` statements outside of functions, `strict` indicates // whether strict mode is on, and `bracketNesting` tracks the level // of nesting within brackets for implicit lint continuation. var inFunction, strict, bracketNesting; // This function is used to raise exceptions on parse errors. It // takes an offset integer (into the current `input`) to indicate // the location of the error, attaches the position to the end // of the error message, and then raises a `SyntaxError` with that // message. function raise(pos, message, readType, expectedType) { var loc = getLineInfo(input, pos); var err = new SyntaxError(message); err.pos = pos; err.loc = loc; err.raisedAt = tokPos; err.tokLen = tokEnd - tokStart + 1; err.tokType = readType; err.expectedType = expectedType; throw err; } // Reused empty array added for node fields that are always empty. var empty = []; // Used for name collision avoidance whend adding extra AST identifiers var newAstIdCount = 0; var indentHist = exports.indentHist = { // Current indentation stack indent: [], // Number of dedent tokens left (i.e. if tokType == _dedent, dedentCount > 0) // Multiple dedent tokens are read in at once, but processed individually in readToken() dedentCount: 0, init: function() { this.indent = []; this.dedentCount = 0; }, count: function() { return this.indent.length; }, len: function(i) { if (typeof i === 'undefined' || i >= this.indent.length) i = this.indent.length - 1; return this.indent[i].length; }, isIndent: function(s) { return this.indent.length === 0 || s.length > this.len(); }, isDedent: function(s) { return this.indent.length > 0 && s.length < this.len(); }, addIndent: function(s) { this.indent.push(s); }, addDedent: function(s) { this.dedentCount = 0; for (var i = this.indent.length - 1; i >= 0 && s.length < this.indent[i].length; --i) ++this.dedentCount; }, updateDedent: function() { this.dedentCount = this.count(); }, pop: function() { --this.dedentCount; this.indent.pop(); }, undoIndent: function() { this.pop(); }, }; // ## Scope // Collection of namespaces saved as a stack // A namespace is a mapping of identifiers to 3 types: variables, functions, classes // A namespace also knows whether it is for global, class, or function // A new namespace is pushed at function and class start, and popped at their end // Starts with a global namespace on the stack // E.g. scope.namespaces ~ [{type: 'g', map:{x: 'v', MyClass: 'c'} }, ...] // TODO: Not tracking built-in namespace var scope = exports.scope = { namespaces: [], init: function() { this.namespaces = [{ type: 'g', map: {} }]; }, current: function(offset) { offset = offset || 0; return this.namespaces[this.namespaces.length - offset - 1]; }, startClass: function(id) { this.current().map[id] = 'c'; this.namespaces.push({ type: 'c', map: {}, className: id }); }, startFn: function(id) { this.current().map[id] = 'f'; this.namespaces.push({ type: 'f', map: {}, fnName: id }); }, end: function() { this.namespaces.pop(); }, addVar: function(id) { this.current().map[id] = 'v'; }, exists: function(id) { return this.current().map.hasOwnProperty(id); }, isClass: function() { return this.current().type === 'c'; }, isUserFunction: function(name) { // Loose match (i.e. order ignored) // TODO: does not identify user-defined class methods for (var i = this.namespaces.length - 1; i >= 0; i--) for (var key in this.namespaces[i].map) if (key === name && this.namespaces[i].map[key] === 'f') return true; return false; }, isParentClass: function() { return this.current(1).type === 'c'; }, isNewObj: function(id) { for (var i = this.namespaces.length - 1; i >= 0; i--) if (this.namespaces[i].map[id] === 'c') return true; else if (this.namespaces[i].map[id] === 'f') break; return false; }, getParentClassName: function() { return this.current(1).className; }, getThisReplace: function() { return this.current().thisReplace; }, setThisReplace: function(s) { this.current().thisReplace = s; }, }; // ## Token types // The assignment of fine-grained, information-carrying type objects // allows the tokenizer to store the information it has about a // token in a way that is very cheap for the parser to look up. // All token type variables start with an underscore, to make them // easy to recognize. // These are the general types. The `type` property is only used to // make them recognizeable when debugging. var _num = { type: 'num' }, _regexp = { type: 'regexp' }, _string = { type: 'string' }; var _name = { type: 'name' }, _eof = { type: 'eof' }; var _newline = { type: 'newline' }, _indent = { type: 'indent' }, _dedent = { type: 'dedent' }; // Keyword tokens. The `keyword` property (also used in keyword-like // operators) indicates that the token originated from an // identifier-like word, which is used when parsing property names. // // The `beforeExpr` property is used to disambiguate between regular // expressions and divisions. It is set on all token types that can // be followed by an expression (thus, a slash after them would be a // regular expression). var _dict = { keyword: 'dict' }; // TODO: not a keyword var _as = { keyword: 'as' }, _assert = { keyword: 'assert' }, _break = { keyword: 'break' }; var _class = { keyword: 'class' }, _continue = { keyword: 'continue' }; var _def = { keyword: 'def' }, _del = { keyword: 'del' }; var _elif = { keyword: 'elif', beforeExpr: true }, _else = { keyword: 'else', beforeExpr: true }; var _except = { keyword: 'except', beforeExpr: true }, _finally = { keyword: 'finally' }; var _for = { keyword: 'for' }, _from = { keyword: 'from' }, _global = { keyword: 'global' }; var _if = { keyword: 'if' }, _import = { keyword: 'import' }; var _lambda = { keyword: 'lambda' }, _nonlocal = { keyword: 'nonlocal' }; var _pass = { keyword: 'pass' }, _raise = { keyword: 'raise' }; var _return = { keyword: 'return', beforeExpr: true }, _try = { keyword: 'try' }; var _while = { keyword: 'while' }, _with = { keyword: 'with' }, _yield = { keyword: 'yield' }; // The keywords that denote values. var _none = { keyword: 'None', atomValue: null }, _true = { keyword: 'True', atomValue: true }; var _false = { keyword: 'False', atomValue: false }; // Some keywords are treated as regular operators. `in` sometimes // (when parsing `for`) needs to be tested against specifically, so // we assign a variable name to it for quick comparing. // 'prec' is the operator precedence' var _or = { keyword: 'or', prec: 1, beforeExpr: true, rep: '||' }; var _and = { keyword: 'and', prec: 2, beforeExpr: true, rep: '&&' }; var _not = { keyword: 'not', prec: 3, prefix: true, beforeExpr: true, rep: '!' }; var _in = { keyword: 'in', prec: 4, beforeExpr: true }; var _is = { keyword: 'is', prec: 4, beforeExpr: true }; // Map keyword names to token types. var keywordTypes = { 'dict': _dict, 'False': _false, 'None': _none, 'True': _true, 'and': _and, 'as': _as, 'break': _break, 'class': _class, 'continue': _continue, 'def': _def, 'del': _del, 'elif': _elif, 'else': _else, 'except': _except, 'finally': _finally, 'for': _for, 'from': _from, 'global': _global, 'if': _if, 'import': _import, 'in': _in, 'is': _is, 'lambda': _lambda, 'nonlocal': _nonlocal, 'not': _not, 'or': _or, 'pass': _pass, 'raise': _raise, 'return': _return, 'try': _try, 'while': _while, 'with': _with, 'yield': _yield, }; // Punctuation token types. Again, the `type` property is purely for debugging. var _bracketL = { type: '[', beforeExpr: true }, _bracketR = { type: ']' }, _braceL = { type: '{', beforeExpr: true }; var _braceR = { type: '}' }, _parenL = { type: '(', beforeExpr: true }, _parenR = { type: ')' }; var _comma = { type: ',', beforeExpr: true }, _semi = { type: ';', beforeExpr: true }; var _colon = { type: ':', beforeExpr: true }, _dot = { type: '.' }, _question = { type: '?', beforeExpr: true }; const _comment = { type: '#' }; // Operators. These carry several kinds of properties to help the // parser use them properly (the presence of these properties is // what categorizes them as operators). // // `prec` specifies the precedence of this operator. // // `prefix` marks the operator as a prefix unary operator. // // `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as // binary operators with a very low precedence, that should result // in AssignmentExpression nodes. var _slash = { prec: 10, beforeExpr: true }, _eq = { isAssign: true, beforeExpr: true }; var _assign = { isAssign: true, beforeExpr: true }; var _equality = { prec: 4, beforeExpr: true }; var _relational = { prec: 4, beforeExpr: true }; var _bitwiseOR = { prec: 5, beforeExpr: true }; var _bitwiseXOR = { prec: 6, beforeExpr: true }; var _bitwiseAND = { prec: 7, beforeExpr: true }; var _bitShift = { prec: 8, beforeExpr: true }; var _plusMin = { prec: 9, beforeExpr: true }; var _multiplyModulo = { prec: 10, beforeExpr: true }; var _floorDiv = { prec: 10, beforeExpr: true }; var _posNegNot = { prec: 11, prefix: true, beforeExpr: true }; var _bitwiseNOT = { prec: 11, prefix: true, beforeExpr: true }; var _exponentiation = { prec: 12, beforeExpr: true }; // Provide access to the token types for external users of the // tokenizer. exports.tokTypes = { bracketL: _bracketL, bracketR: _bracketR, braceL: _braceL, braceR: _braceR, parenL: _parenL, parenR: _parenR, comma: _comma, semi: _semi, colon: _colon, dot: _dot, question: _question, slash: _slash, eq: _eq, name: _name, eof: _eof, num: _num, regexp: _regexp, string: _string, newline: _newline, indent: _indent, dedent: _dedent, exponentiation: _exponentiation, floorDiv: _floorDiv, plusMin: _plusMin, posNegNot: _posNegNot, multiplyModulo: _multiplyModulo, }; for (var kw in keywordTypes) exports.tokTypes['_' + kw] = keywordTypes[kw]; // This is a trick taken from Esprima. It turns out that, on // non-Chrome browsers, to check whether a string is in a set, a // predicate containing a big ugly `switch` statement is faster than // a regular expression, and on Chrome the two are about on par. // This function uses `eval` (non-lexical) to produce such a // predicate from a space-separated string of words. // // It starts by sorting the words by length. function makePredicate(words) { words = words.split(' '); var f = '', cats = []; out: for (var i = 0; i < words.length; ++i) { for (var j = 0; j < cats.length; ++j) if (cats[j][0].length == words[i].length) { cats[j].push(words[i]); continue out; } cats.push([words[i]]); } function compareTo(arr) { if (arr.length == 1) return f += 'return str === ' + JSON.stringify(arr[0]) + ';'; f += 'switch(str){'; for (var i = 0; i < arr.length; ++i) f += 'case ' + JSON.stringify(arr[i]) + ':'; f += 'return true}return false;'; } // When there are more than three length categories, an outer // switch first dispatches on the lengths, to save on comparisons. if (cats.length > 3) { cats.sort(function(a, b) { return b.length - a.length; }); f += 'switch(str.length){'; for (var i = 0; i < cats.length; ++i) { var cat = cats[i]; f += 'case ' + cat[0].length + ':'; compareTo(cat); } f += '}'; // Otherwise, simply generate a flat `switch` statement. } else { compareTo(words); } return new Function('str', f); } // The forbidden variable names var isStrictBadIdWord = makePredicate('eval arguments'); // Keywords // TODO: dict isn't a keyword, it's a builtin var isKeyword = makePredicate('dict False None True and as assert break class continue def del elif else except finally for from global if import in is lambda nonlocal not or pass raise return try while with yield exec'); // ## Character categories // Big ugly regular expressions that match characters in the // whitespace, identifier, and identifier-start categories. These // are only applied when a character is found to actually have a // code point above 128. var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/; var nonASCIIidentifierStartChars = '\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc'; var nonASCIIidentifierChars = '\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u0620-\u0649\u0672-\u06d3\u06e7-\u06e8\u06fb-\u06fc\u0730-\u074a\u0800-\u0814\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0840-\u0857\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962-\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09d7\u09df-\u09e0\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5f-\u0b60\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2-\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d46-\u0d48\u0d57\u0d62-\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e34-\u0e3a\u0e40-\u0e45\u0e50-\u0e59\u0eb4-\u0eb9\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f41-\u0f47\u0f71-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1029\u1040-\u1049\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u170e-\u1710\u1720-\u1730\u1740-\u1750\u1772\u1773\u1780-\u17b2\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1920-\u192b\u1930-\u193b\u1951-\u196d\u19b0-\u19c0\u19c8-\u19c9\u19d0-\u19d9\u1a00-\u1a15\u1a20-\u1a53\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b46-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1bb0-\u1bb9\u1be6-\u1bf3\u1c00-\u1c22\u1c40-\u1c49\u1c5b-\u1c7d\u1cd0-\u1cd2\u1d00-\u1dbe\u1e01-\u1f15\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2d81-\u2d96\u2de0-\u2dff\u3021-\u3028\u3099\u309a\ua640-\ua66d\ua674-\ua67d\ua69f\ua6f0-\ua6f1\ua7f8-\ua800\ua806\ua80b\ua823-\ua827\ua880-\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8f3-\ua8f7\ua900-\ua909\ua926-\ua92d\ua930-\ua945\ua980-\ua983\ua9b3-\ua9c0\uaa00-\uaa27\uaa40-\uaa41\uaa4c-\uaa4d\uaa50-\uaa59\uaa7b\uaae0-\uaae9\uaaf2-\uaaf3\uabc0-\uabe1\uabec\uabed\uabf0-\uabf9\ufb20-\ufb28\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f'; var nonASCIIidentifierStart = new RegExp('[' + nonASCIIidentifierStartChars + ']'); var nonASCIIidentifier = new RegExp('[' + nonASCIIidentifierStartChars + nonASCIIidentifierChars + ']'); // Whether a single character denotes a newline. var newline = /[\n\r\u2028\u2029]/; // Matches a whole line break (where CRLF is considered a single // line break). Used to count lines. var lineBreak = /\r\n|[\n\r\u2028\u2029]/g; // Test whether a given character code starts an identifier. var isIdentifierStart = exports.isIdentifierStart = function(code) { if (code < 65) return code === 36; if (code < 91) return true; if (code < 97) return code === 95; if (code < 123) return true; return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code)); }; // Test whether a given character is part of an identifier. var isIdentifierChar = exports.isIdentifierChar = function(code) { if (code < 48) return code === 36; if (code < 58) return true; if (code < 65) return false; if (code < 91) return true; if (code < 97) return code === 95; if (code < 123) return true; return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code)); }; // ## Tokenizer // These are used when `options.locations` is on, for the // `tokStartLoc` and `tokEndLoc` properties. function Position() { this.line = tokCurLine; this.column = tokPos - tokLineStart; } // Reset the token state. Used at the start of a parse. function initTokenState() { tokCurLine = 1; tokPos = tokLineStart = 0; tokRegexpAllowed = true; indentHist.init(); newAstIdCount = 0; scope.init(); } // Called at the end of every token. Sets `tokEnd`, `tokVal`, and // `tokRegexpAllowed`, and skips the space after the token, so that // the next one's `tokStart` will point at the right position. function finishToken(type, val) { tokEnd = tokPos; if (options.locations) tokEndLoc = new Position; tokType = type; if (type === _parenL || type === _braceL || type === _bracketL) ++bracketNesting; if (type === _parenR || type === _braceR || type === _bracketR) --bracketNesting; if (type !== _newline) skipSpace(); tokVal = val; tokRegexpAllowed = type.beforeExpr; } function skipLine() { var ch = input.charCodeAt(++tokPos); while (tokPos < inputLen && !isNewline(ch)) { ++tokPos; ch = input.charCodeAt(tokPos); } } function skipLineComment() { var start = tokPos; var startLoc = options.onComment && options.locations && new Position; skipLine(); if (options.onComment) options.onComment(input.slice(start + 1, tokPos), start, tokPos, startLoc, options.locations && new Position); } // Called at the start of the parse and after every token. Skips // whitespace and comments, and. function skipSpace() { while (tokPos < inputLen) { var ch = input.charCodeAt(tokPos); if (ch === 92) { ++tokPos; if (isNewline(input.charCodeAt(tokPos))) { if (input.charCodeAt(tokPos) === 13 && input.charCodeAt(tokPos + 1) === 10) ++tokPos; ++tokPos; if (options.location) { tokLineStart = tokPos; ++tokCurLine; } } else { raise(tokPos, 'Unexpected character after line continuation character'); } } else if (isSpace(ch)) ++tokPos; else if (bracketNesting > 0 && isNewline(ch)) { if (ch === 13 && input.charCodeAt(tokPos + 1) === 10) ++tokPos; ++tokPos; if (options.location) { tokLineStart = tokPos; ++tokCurLine; } } else break; } } function isSpace(ch) { if (ch === 32 || // ' ' ch === 9 || ch === 11 || ch === 12 || ch === 160 || // '\xa0' ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) { return true; } return false; } function isNewline(ch) { if (ch === 10 || ch === 13 || ch === 8232 || ch === 8233) { return true; } return false; } // ### Token reading // This is the function that is called to fetch the next token. It // is somewhat obscure, because it works in character codes rather // than characters, and because operator parsing has been inlined // into it. // // All in the name of speed. // // The `forceRegexp` parameter is used in the one case where the // `tokRegexpAllowed` trick does not work. See `parseStatement`. function readToken_singleLineComment() { ++tokPos; skipSpace(); let out = ''; let ch = input.charCodeAt(tokPos); while (!isNewline(ch)) { out += String.fromCharCode(ch); ch = input.charCodeAt(++tokPos); } return finishToken(_comment, out); } function readToken_dot() { var next = input.charCodeAt(tokPos + 1); if (next >= 48 && next <= 57) return readNumber(true); ++tokPos; return finishToken(_dot); } function readToken_slash() { // '/' if (tokRegexpAllowed) { ++tokPos; return readRegexp(); } var next = input.charCodeAt(tokPos + 1); if (next === 47) return finishOp(_floorDiv, 2); if (next === 61) return finishOp(_assign, 2); return finishOp(_slash, 1); } function readToken_mult_modulo(code) { // '*%' var next = input.charCodeAt(tokPos + 1); if (next === 42 && next === code) return finishOp(_exponentiation, 2); if (next === 61) return finishOp(_assign, 2); return finishOp(_multiplyModulo, 1); } function readToken_pipe_amp(code) { // '|&' var next = input.charCodeAt(tokPos + 1); if (next === 61) return finishOp(_assign, 2); return finishOp(code === 124 ? _bitwiseOR : _bitwiseAND, 1); } function readToken_caret() { // '^' var next = input.charCodeAt(tokPos + 1); if (next === 61) return finishOp(_assign, 2); return finishOp(_bitwiseXOR, 1); } function readToken_plus_min(code) { // '+-' var next = input.charCodeAt(tokPos + 1); if (next === 61) return finishOp(_assign, 2); return finishOp(_plusMin, 1); } function readToken_lt_gt(code) { // '<>' var next = input.charCodeAt(tokPos + 1); var size = 1; if (next === code) { size = 2; if (input.charCodeAt(tokPos + size) === 61) return finishOp(_assign, size + 1); return finishOp(_bitShift, size); } if (next === 61) size = 2; return finishOp(_relational, size); } function readToken_eq_excl(code) { // '=!' var next = input.charCodeAt(tokPos + 1); if (next === 61) return finishOp(_equality, 2); return finishOp(_eq, 1); } // Parse indentation // Possible output: _indent, _dedent, _eof, readToken() // TODO: disallow unequal indents of same length (e.g. nested if/else block) function readToken_indent() { // Read indent, skip empty lines and comments var indent = ''; var indentPos = tokPos; var ch, next; while (indentPos < inputLen) { ch = input.charCodeAt(indentPos); if (isSpace(ch)) { indent += String.fromCharCode(ch); ++indentPos; } else if (isNewline(ch)) { // newline indent = ''; if (ch === 13 && input.charCodeAt(indentPos + 1) === 10) ++indentPos; ++indentPos; tokPos = indentPos; if (options.locations) { tokLineStart = indentPos; ++tokCurLine; } } else { break; } } // Determine token type based on indent found versus indentation history var type; if (indent.length > 0) { if (indentHist.isIndent(indent)) { type = _indent; if (indentHist.count() >= 1) tokStart += indentHist.len(indentHist.count() - 1); indentHist.addIndent(indent); } else if (indentHist.isDedent(indent)) { type = _dedent; indentHist.addDedent(indent); var nextDedent = indentHist.count() - indentHist.dedentCount; if (nextDedent >= 2) { tokStart += indentHist.len(nextDedent) - indentHist.len(nextDedent - 1); } } else { tokPos += indent.length; } } else if (indentPos >= inputLen) { type = _eof; } else if (indentHist.count() > 0) { type = _dedent; indentHist.updateDedent(); } switch (type) { case _indent: case _dedent: return finishOp(type, indentPos - ++tokPos); case _eof: tokPos = inputLen; if (options.locations) tokStartLoc = new Position; return finishOp(type, 0); default: tokType = null; return readToken(); } } function getTokenFromCode(code) { switch (code) { case 13: case 10: case 8232: case 8233: ++tokPos; if (code === 13 && input.charCodeAt(tokPos) === 10) ++tokPos; if (options.locations) { ++tokCurLine; tokLineStart = tokPos; } return finishToken(_newline); case 35: // '#' return readToken_singleLineComment(); // The interpretation of a dot depends on whether it is followed // by a digit. case 46: // '.' return readToken_dot(); // Punctuation tokens. case 40: ++tokPos; return finishToken(_parenL); case 41: ++tokPos; return finishToken(_parenR); case 59: ++tokPos; return finishToken(_semi); case 44: ++tokPos; return finishToken(_comma); case 91: ++tokPos; return finishToken(_bracketL); case 93: ++tokPos; return finishToken(_bracketR); case 123: ++tokPos; return finishToken(_braceL); case 125: ++tokPos; return finishToken(_braceR); case 58: ++tokPos; return finishToken(_colon); case 63: ++tokPos; return finishToken(_question); // Anything else beginning with a digit is an integer, octal // number, or float. case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: // 1-9 return readNumber(false); // Quotes produce strings. case 34: case 39: // '"', "'" return readString(code); // Operators are parsed inline in tiny state machines. '=' (61) is // often referred to. `finishOp` simply skips the amount of // characters it is given as second argument, and returns a token // of the type given by its first argument. case 47: // '/' return readToken_slash(code); case 42: case 37: // '*%' return readToken_mult_modulo(code); case 124: case 38: // '|&' return readToken_pipe_amp(code); case 94: // '^' return readToken_caret(); case 43: case 45: // '+-' return readToken_plus_min(code); case 60: case 62: // '<>' return readToken_lt_gt(code); case 61: case 33: // '=!' return readToken_eq_excl(code); case 126: // '~' return finishOp(_bitwiseNOT, 1); } return false; } function readZero() { var val = ''; for (var i = tokPos; i < inputLen; i++) { var ch = input.charCodeAt(tokPos); if (isNewline(ch)) break; val += input[i]; tokPos = i; } return finishToken(_string, String(val)); } function readToken(forceRegexp) { if (tokType === _dedent) { indentHist.pop(); if (indentHist.dedentCount > 0) return; } if (!forceRegexp) tokStart = tokPos; else tokPos = tokStart + 1; if (options.locations) tokStartLoc = new Position; if (forceRegexp) return readRegexp(); if (tokPos >= inputLen) return finishToken(_eof); if (tokType === _newline) return readToken_indent(); if (input.split('=').length > 1 && isKeyword(input.split('=')[0].trim())) { tokPos = input.split(/\r|\n/g).length - 1 + 3; if (input.split('=')[1].trim()[0] == '[') { raise(tokPos, 'Reserved list word'); } else { raise(tokPos, 'Reserved variable word'); } } var code = input.charCodeAt(tokPos); // Identifier or keyword. '\uXXXX' sequences are allowed in // identifiers, so '\' also dispatches to that. if (isIdentifierStart(code) || code === 92 /* '\' */) return readWord(); var tok = getTokenFromCode(code); if (tok === false) { // If we are here, we either found a non-ASCII identifier // character, or something that's entirely disallowed. var ch = String.fromCharCode(code); if (ch === '\\' || nonASCIIidentifierStart.test(ch)) return readWord(); raise(tokPos + 3, 'Unexpected character \'' + ch + '\''); } return tok; } function finishOp(type, size) { var str = input.slice(tokPos, tokPos + size); tokPos += size; finishToken(type, str); } // Parse a regular expression. Some context-awareness is necessary, // since a '/' inside a '[]' set does not end the expression. function readRegexp() { var content = '', escaped, inClass, start = tokPos, value; for (; ;) { if (tokPos >= inputLen) raise(start, 'Unterminated regular expression'); var ch = input.charAt(tokPos); if (newline.test(ch)) raise(start, 'Unterminated regular expression'); if (!escaped) { if (ch === '[') inClass = true; else if (ch === ']' && inClass) inClass = false; else if (ch === '/' && !inClass) break; escaped = ch === '\\'; } else escaped = false; ++tokPos; } content = input.slice(start, tokPos); ++tokPos; // Need to use `readWord1` because '\uXXXX' sequences are allowed // here (don't ask). var mods = readWord1(); if (mods && !/^[gmsiy]*$/.test(mods)) raise(start, 'Invalid regular expression flag'); try { value = new RegExp(content, mods); } catch (e) { if (e instanceof SyntaxError) raise(start, 'Error parsing regular expression: ' + e.message); raise(e); } return finishToken(_regexp, value); } // Read an integer in the given radix. Return null if zero digits // were read, the integer value otherwise. When `len` is given, this // will return `null` unless the integer has exactly `len` digits. function readInt(radix, len) { var start = tokPos, total = 0; for (var i = 0, e = len == null ? Infinity : len; i < e; ++i) { var code = input.charCodeAt(tokPos), val; if (code >= 97) val = code - 97 + 10; // a else if (code >= 65) val = code - 65 + 10; // A else if (code >= 48 && code <= 57) val = code - 48; // 0-9 else val = Infinity; if (val >= radix) break; ++tokPos; total = total * radix + val; } if (tokPos === start || len != null && tokPos - start !== len) return null; return total; } function readHexNumber() { tokPos += 2; // 0x var val = readInt(16); if (val == null) raise(tokStart + 2, 'Expected hexadecimal number'); if (isIdentifierStart(input.charCodeAt(tokPos))) raise(tokPos, 'Identifier directly after number'); return finishToken(_num, val); } // Read an integer, octal integer, or floating-point number. function readNumber(startsWithDot) { var start = tokPos, isFloat = false, octal = input.charCodeAt(tokPos) === 48; if (!startsWithDot && readInt(10) === null) raise(start, 'Invalid number'); if (input.charCodeAt(tokPos) === 46) { ++tokPos; readInt(10); isFloat = true; } var next = input.charCodeAt(tokPos); if (next === 69 || next === 101) { // 'eE' next = input.charCodeAt(++tokPos); if (next === 43 || next === 45) ++tokPos; // '+-' if (readInt(10) === null) raise(start, 'Invalid number'); isFloat = true; } if (isIdentifierStart(input.charCodeAt(tokPos))) raise(tokPos, 'Identifier directly after number'); var str = input.slice(start, tokPos), val; if (isFloat) val = parseFloat(str); else if (!octal || str.length === 1) val = parseInt(str, 10); else if (/[89]/.test(str) || strict) raise(start, 'Invalid number'); else val = str; return finishToken(_num, val); } // Read a string value, interpreting backslash-escapes. function readString(quote) { tokPos++; var ch = input.charCodeAt(tokPos); var tripleQuoted = false; if (ch === quote && input.charCodeAt(tokPos + 1) === quote) { tripleQuoted = true; tokPos += 2; } var out = ''; for (; ;) { if (tokPos >= inputLen) raise(tokStart, 'Unterminated string constant'); var ch = input.charCodeAt(tokPos); if (ch === quote) { if (tripleQuoted) { if (input.charCodeAt(tokPos + 1) === quote && input.charCodeAt(tokPos + 2) === quote) { tokPos += 3; return finishToken(_string, out); } } else { ++tokPos; return finishToken(_string, out); } } if (ch === 92) { // '\' ch = input.charCodeAt(++tokPos); var octal = /^[0-7]+/.exec(input.slice(tokPos, tokPos + 3)); if (octal) octal = octal[0]; while (octal && parseInt(octal, 8) > 255) octal = octal.slice(0, -1); if (octal === '0') octal = null; ++tokPos; if (octal) { if (strict) raise(tokPos - 2, 'Octal literal in strict mode'); out += String.fromCharCode(parseInt(octal, 8)); tokPos += octal.length - 1; } else { switch (ch) { case 110: out += '\n'; break; // 'n' -> '\n' case 114: out += '\r'; break; // 'r' -> '\r' // case 120: out += String.fromCharCode(readHexChar(2)); break; // 'x' // case 117: out += String.fromCharCode(readHexChar(4)); break; // 'u' // case 85: // 'U' // ch = readHexChar(8); // if (ch < 0xFFFF && (ch < 0xD800 || 0xDBFF < ch)) out += String.fromCharCode(ch); // If it's UTF-16 // else { // If we need UCS-2 // ch -= 0x10000; // out += String.fromCharCode((ch>>10)+0xd800)+String.fromCharCode((ch%0x400)+0xdc00); // } // break; case 116: out += '\t'; break; // 't' -> '\t' case 98: out += '\b'; break; // 'b' -> '\b' case 118: out += '\u000b'; break; // 'v' -> '\u000b' case 102: out += '\f'; break; // 'f' -> '\f' case 48: out += '\0'; break; // 0 -> '\0' case 13: if (input.charCodeAt(tokPos) === 10) ++tokPos; // '\r\n' case 10: // ' \n' if (options.locations) { tokLineStart = tokPos; ++tokCurLine; } break; default: out += '\\' + String.fromCharCode(ch); break; // Python doesn't remove slashes on failed escapes } } } else { if (isNewline(ch)) { if (tripleQuoted) { out += String.fromCharCode(ch); ++tokPos; if (ch === 13 && input.charCodeAt(tokPos) === 10) { ++tokPos; out += '\n'; } if (options.location) { tokLineStart = tokPos; ++tokCurLine; } } else raise(tokStart, 'Unterminated string constant'); } else { out += String.fromCharCode(ch); // '\' ++tokPos; } } } } // Used to read character escape sequences ('\x', '\u', '\U'). function readHexChar(len) { var n = readInt(16, len); if (n === null) raise(tokStart, 'Bad character escape sequence'); return n; } // Used to signal to callers of `readWord1` whether the word // contained any escape sequences. This is needed because words with // escape sequences must not be interpreted as keywords. var containsEsc; // Read an identifier, and return it as a string. Sets `containsEsc` // to whether the word contained a '\u' escape. // // Only builds up the word character-by-character when it actually // containeds an escape, as a micro-optimization. function readWord1() { containsEsc = false; var word, first = true, start = tokPos; for (; ;) { var ch = input.charCodeAt(tokPos); if (isIdentifierChar(ch)) { if (containsEsc) word += input.charAt(tokPos); ++tokPos; } else if (ch === 92) { // "\" if (!containsEsc) word = input.slice(start, tokPos); containsEsc = true; if (input.charCodeAt(++tokPos) != 117) // "u" raise(tokPos, 'Expecting Unicode escape sequence \\uXXXX'); ++tokPos; var esc = readHexChar(4); var escStr = String.fromCharCode(esc); if (!escStr) raise(tokPos - 1, 'Invalid Unicode escape'); if (!(first ? isIdentifierStart(esc) : isIdentifierChar(esc))) raise(tokPos - 4, 'Invalid Unicode escape'); word += escStr; } else { break; } first = false; } return containsEsc ? word : input.slice(start, tokPos); } // Read an identifier or keyword token. Will check for reserved // words when necessary. function readWord() { var word = readWord1(); var type = _name; if (!containsEsc && isKeyword(word)) type = keywordTypes[word]; return finishToken(type, word); } // ## Parser // A recursive descent parser operates by defining functions for all // syntactic elements, and recursively calling those, each function // advancing the input stream and returning an AST node. Precedence // of constructs (for example, the fact that `!x[1]` means `!(x[1])` // instead of `(!x)[1]` is handled by the fact that the parser // function that parses unary prefix operators is called first, and // in turn calls the function that parses `[]` subscripts - that // way, it'll receive the node for `x[1]` already parsed, and wraps // *that* in the unary operator node. // // Acorn uses an [operator precedence parser][opp] to handle binary // operator precedence, because it is much more compact than using // the technique outlined above, which uses different, nesting // functions to specify precedence, for all of the ten binary // precedence levels that JavaScript defines. // // [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser // ### Parser utilities // Continue to the next token. function next() { lastStart = tokStart; lastEnd = tokEnd; lastEndLoc = tokEndLoc; readToken(); } // Enter strict mode. Re-reads the next token to please pedantic // tests ("use strict"; 010; -- should fail). function setStrict(strct) { strict = strct; tokPos = tokStart; if (options.locations) { while (tokPos < tokLineStart) { tokLineStart = input.lastIndexOf('\n', tokLineStart - 2) + 1; --tokCurLine; } } skipSpace(); readToken(); } // Start an AST node, attaching a start offset. function Node() { this.type = null; } exports.Node = Node; function SourceLocation() { this.start = tokStartLoc; this.end = null; if (sourceFile !== null) this.source = sourceFile; } function startNode() { var node = new Node(); if (options.locations) node.loc = new SourceLocation(); if (options.directSourceFile) node.sourceFile = options.directSourceFile; if (options.ranges) node.range = [tokStart, 0]; return node; } // Finish an AST node, adding `type` and `end` properties. function finishNode(node, type) { node.type = type; if (options.locations) node.loc.end = lastEndLoc; if (options.ranges) node.range[1] = lastEnd; return node; } // Start a node whose start offset information should be based on // the start of another node. For example, a binary operator node is // only started after its left-hand side has already been parsed. function startNodeFrom(other) { var node = new Node(); if (options.locations) { node.loc = new SourceLocation(); node.loc.start = other.loc.start; } if (options.ranges) node.range = [other.range[0], 0]; return node; } // ## Node creation utilities var getNodeCreator = exports.getNodeCreator = function(startNode, startNodeFrom, finishNode, unpackTuple) { return { // Finish a node whose end offset information should be based on // the end of another node. For example, createNode* functions // are used to create extra AST nodes which may be based on a single // parsed user code node. finishNodeFrom: function(endNode, node, type) { node.type = type; if (options.locations) node.loc.end = endNode.loc.end; if (options.ranges) node.range[1] = endNode.range[1]; return node; }, // Create an AST node using start offsets createNodeFrom: function(startNode, type, props) { var node = startNodeFrom(startNode); for (var prop in props) node[prop] = props[prop]; return finishNode(node, type); }, // Create an AST node using start and end offsets createNodeSpan: function(startNode, endNode, type, props) { var node = startNodeFrom(startNode); for (var prop in props) node[prop] = props[prop]; return this.finishNodeFrom(endNode, node, type); }, createGeneratedNodeSpan: function(startNode, endNode, type, props) { var node = startNodeFrom(startNode); for (var prop in props) node[prop] = props[prop]; node.userCode = false; return this.finishNodeFrom(endNode, node, type); }, // while (__formalsIndex < __params.formals.length) { // .push(__params.formals[__formalsIndex++]); } createNodeArgsWhileConsequent: function(argsId, s) { var __paramsFormals = this.createNodeMembIds(argsId, '__params' + s, 'formals'); var __formalsIndexId = this.createGeneratedNodeSpan(argsId, argsId, 'Identifier', { name: '__formalsIndex' + s }); return this.createGeneratedNodeSpan(argsId, argsId, 'WhileStatement', { test: this.createGeneratedNodeSpan(argsId, argsId, 'BinaryExpression', { operator: '<', left: __formalsIndexId, right: this.createGeneratedNodeSpan(argsId, argsId, 'MemberExpression', { computed: false, object: __paramsFormals, property: this.createGeneratedNodeSpan(argsId, argsId, 'Identifier', { name: 'length' }), }), }), body: this.createGeneratedNodeSpan(argsId, argsId, 'BlockStatement', { body: [this.createGeneratedNodeSpan(argsId, argsId, 'ExpressionStatement', { expression: this.createGeneratedNodeSpan(argsId, argsId, 'CallExpression', { callee: this.createNodeMembIds(argsId, argsId.name, 'push'), arguments: [this.createGeneratedNodeSpan(argsId, argsId, 'MemberExpression', { computed: true, object: __paramsFormals, property: this.createGeneratedNodeSpan(argsId, argsId, 'UpdateExpression', { operator: '++', prefix: false, argument: __formalsIndexId, }), })], }), })], }), }); }, // { while (__formalsIndex < __args.length) { // .push(__args[__formalsIndex++]); }} createNodeArgsAlternate: function(argsId, s) { var __args = '__args' + s; var __formalsIndexId = this.createGeneratedNodeSpan(argsId, argsId, 'Identifier', { name: '__formalsIndex' + s }); return this.createGeneratedNodeSpan(argsId, argsId, 'BlockStatement', { body: [this.createGeneratedNodeSpan(argsId, argsId, 'WhileStatement', { test: this.createGeneratedNodeSpan(argsId, argsId, 'BinaryExpression', { operator: '<', left: __formalsIndexId, right: this.createNodeMembIds(argsId, __args, 'length'), }), body: this.createGeneratedNodeSpan(argsId, argsId, 'BlockStatement', { body: [this.createGeneratedNodeSpan(argsId, argsId, 'ExpressionStatement', { expression: this.createGeneratedNodeSpan(argsId, argsId, 'CallExpression', { callee: this.createNodeMembIds(argsId, argsId.name, 'push'), arguments: [this.createGeneratedNodeSpan(argsId, argsId, 'MemberExpression', { computed: true, object: this.createGeneratedNodeSpan(argsId, argsId, 'Identifier', { name: __args }), property: this.createGeneratedNodeSpan(argsId, argsId, 'UpdateExpression', { operator: '++', prefix: false, argument: __formalsIndexId, }), })], }), })], }), })], }); }, // return (function() {}).call(this); createNodeFnBodyIife: function(body) { var iifeBody = this.createGeneratedNodeSpan(body, body, 'FunctionExpression', { params: [], defaults: [], body: body, generator: false, expression: false, }); var iifeCall = this.createGeneratedNodeSpan(body, body, 'CallExpression', { callee: this.createGeneratedNodeSpan(body, body, 'MemberExpression', { computed: false, object: iifeBody, property: this.createGeneratedNodeSpan(body, body, 'Identifier', { name: 'call' }), }), arguments: [this.createGeneratedNodeSpan(body, body, 'ThisExpression')], }); return this.createGeneratedNodeSpan(body, body, 'ReturnStatement', { argument: iifeCall }); }, // E.g. Math.pow(2, 3) createNodeMemberCall: function(node, object, property, args) { var objId = this.createNodeFrom(node, 'Identifier', { name: object }); var propId = this.createNodeFrom(node, 'Identifier', { name: property }); var member = this.createNodeFrom(node, 'MemberExpression', { object: objId, property: propId, computed: false, }); node.callee = member; node.arguments = args; return finishNode(node, 'CallExpression'); }, // o.p createNodeMembIds: function(r, o, p) { return this.createNodeSpan(r, r, 'MemberExpression', { computed: false, object: this.createNodeSpan(r, r, 'Identifier', { name: o }), property: this.createNodeSpan(r, r, 'Identifier', { name: p }), }); }, // o[p] createNodeMembIdLit: function(r, o, p) { return this.createNodeSpan(r, r, 'MemberExpression', { computed: true, object: this.createNodeSpan(r, r, 'Identifier', { name: o }), property: this.createNodeSpan(r, r, 'Literal', { value: p }), }); }, // E.g. pyRuntime.ops.add createNodeOpsCallee: function(node, fnName) { var runtimeId = this.createGeneratedNodeSpan(node, node, 'Identifier', { name: options.runtimeParamName }); var opsId = this.createGeneratedNodeSpan(node, node, 'Identifier', { name: 'ops' }); var addId = this.createGeneratedNodeSpan(node, node, 'Identifier', { name: fnName }); var opsMember = this.createGeneratedNodeSpan(node, node, 'MemberExpression', { object: runtimeId, property: opsId, computed: false, }); return this.createGeneratedNodeSpan(node, node, 'MemberExpression', { object: opsMember, property: addId, computed: false, }); }, // var __params = arguments.length === 1 && arguments[0].formals && arguments[0].keywords ? arguments[0] : null; createNodeParamsCheck: function(r, s) { var __paramsId = this.createNodeSpan(r, r, 'Identifier', { name: '__params' + s }); var arguments0 = this.createNodeMembIdLit(r, 'arguments', 0); var checks = this.createNodeSpan(r, r, 'ConditionalExpression', { test: this.createNodeSpan(r, r, 'LogicalExpression', { operator: '&&', left: this.createNodeSpan(r, r, 'LogicalExpression', { operator: '&&', left: this.createNodeSpan(r, r, 'BinaryExpression', { operator: '===', left: this.createNodeMembIds(r, 'arguments', 'length'), right: this.createNodeSpan(r, r, 'Literal', { value: 1 }), }), right: this.createNodeSpan(r, r, 'MemberExpression', { computed: false, object: arguments0, property: this.createNodeSpan(r, r, 'Identifier', { name: 'formals' }), }), }), right: this.createNodeSpan(r, r, 'MemberExpression', { computed: false, object: arguments0, property: this.createNodeSpan(r, r, 'Identifier', { name: 'keywords' }), }), }), consequent: arguments0, alternate: this.createNodeSpan(r, r, 'Literal', { value: null }), }); return this.createGeneratedVarDeclFromId(r, __paramsId, checks); }, // function __getParam(v, d) { // var r = d; // if (__params) { // if (__formalsIndex < __params.formals.length) { // r = __params.formals[__formalsIndex++]; // } else if (v in __params.keywords) { // r = __params.keywords[v]; // delete __params.keywords[v]; // } // } else if (__formalsIndex < __args.length) { // r = __args[__formalsIndex++]; // } // return r; // } createNodeGetParamFn: function(r, s) { var dId = this.createNodeSpan(r, r, 'Identifier', { name: 'd' }); var vId = this.createNodeSpan(r, r, 'Identifier', { name: 'v' }); var rId = this.createNodeSpan(r, r, 'Identifier', { name: 'r' }); var __formalsIndexId = this.createNodeSpan(r, r, 'Identifier', { name: '__formalsIndex' + s }); var __params = '__params' + s; var __getParam = '__getParam' + s; var __args = '__args' + s; var __paramsFormals = this.createNodeMembIds(r, __params, 'formals'); var __paramsKeywords = this.createNodeMembIds(r, __params, 'keywords'); var __paramsKeywordsV = this.createNodeSpan(r, r, 'MemberExpression', { computed: true, property: vId, object: __paramsKeywords, }); return this.createGeneratedNodeSpan(r, r, 'FunctionDeclaration', { id: this.createNodeSpan(r, r, 'Identifier', { name: __getParam }), params: [vId, dId], defaults: [], body: this.createNodeSpan(r, r, 'BlockStatement', { body: [this.createGeneratedVarDeclFromId(r, rId, dId), this.createGeneratedNodeSpan(r, r, 'IfStatement', { test: this.createNodeSpan(r, r, 'Identifier', { name: __params }), consequent: this.createNodeSpan(r, r, 'BlockStatement', { body: [this.createGeneratedNodeSpan(r, r, 'IfStatement', { test: this.createNodeSpan(r, r, 'BinaryExpression', { operator: '<', left: __formalsIndexId, right: this.createNodeSpan(r, r, 'MemberExpression', { computed: false, object: __paramsFormals, property: this.createNodeSpan(r, r, 'Identifier', { name: 'length' }), }), }), consequent: this.createNodeSpan(r, r, 'BlockStatement', { body: [this.createGeneratedNodeSpan(r, r, 'ExpressionStatement', { expression: this.createGeneratedNodeSpan(r, r, 'AssignmentExpression', { operator: '=', left: rId, right: this.createNodeSpan(r, r, 'MemberExpression', { computed: true, object: __paramsFormals, property: this.createNodeSpan(r, r, 'UpdateExpression', { operator: '++', argument: __formalsIndexId, prefix: false, }), }), }), })], }), alternate: this.createGeneratedNodeSpan(r, r, 'IfStatement', { test: this.createNodeSpan(r, r, 'BinaryExpression', { operator: 'in', left: vId, right: __paramsKeywords, }), consequent: this.createNodeSpan(r, r, 'BlockStatement', { body: [this.createGeneratedNodeSpan(r, r, 'ExpressionStatement', { expression: this.createGeneratedNodeSpan(r, r, 'AssignmentExpression', { operator: '=', left: rId, right: __paramsKeywordsV, }), }), this.createGeneratedNodeSpan(r, r, 'ExpressionStatement', { expression: this.createNodeSpan(r, r, 'UnaryExpression', { operator: 'delete', prefix: true, argument: __paramsKeywordsV, }), })], }), alternate: null, }), })], }), alternate: this.createGeneratedNodeSpan(r, r, 'IfStatement', { test: this.createGeneratedNodeSpan(r, r, 'BinaryExpression', { operator: '<', left: __formalsIndexId, right: this.createNodeMembIds(r, __args, 'length'), }), consequent: this.createGeneratedNodeSpan(r, r, 'BlockStatement', { body: [this.createGeneratedNodeSpan(r, r, 'ExpressionStatement', { expression: this.createGeneratedNodeSpan(r, r, 'AssignmentExpression', { operator: '=', left: rId, right: this.createGeneratedNodeSpan(r, r, 'MemberExpression', { computed: true, object: this.createGeneratedNodeSpan(r, r, 'Identifier', { name: __args }), property: this.createGeneratedNodeSpan(r, r, 'UpdateExpression', { operator: '++', argument: __formalsIndexId, prefix: false, }), }), }), })], }), alternate: null, }), }), this.createGeneratedNodeSpan(r, r, 'ReturnStatement', { argument: rId })], }), rest: null, generator: false, expression: false, }); }, // E.g. pyRuntime.utils.add createNodeRuntimeCall: function(r, mod, fn, args) { return this.createNodeSpan(r, r, 'CallExpression', { callee: this.createNodeSpan(r, r, 'MemberExpression', { computed: false, object: this.createNodeMembIds(r, options.runtimeParamName, mod), property: this.createNodeSpan(r, r, 'Identifier', { name: fn }), }), arguments: args, }); }, // Used to convert 'id = init' to 'var id = init' createVarDeclFromId: function(refNode, id, init) { var decl = startNodeFrom(refNode); decl.id = id; decl.init = init; this.finishNodeFrom(refNode, decl, 'VariableDeclarator'); var declDecl = startNodeFrom(refNode); declDecl.kind = 'var'; declDecl.declarations = [decl]; return this.finishNodeFrom(refNode, declDecl, 'VariableDeclaration'); }, createGeneratedVarDeclFromId: function(refNode, id, init) { var decl = startNodeFrom(refNode); decl.id = id; decl.init = init; this.finishNodeFrom(refNode, decl, 'VariableDeclarator'); var declDecl = startNodeFrom(refNode); declDecl.kind = 'var'; declDecl.declarations = [decl]; declDecl.userCode = false; return this.finishNodeFrom(refNode, declDecl, 'VariableDeclaration'); }, createClass: function(container, ctorNode, classParams, classBodyRefNode, classBlock) { // Helper to identify class methods which were parsed onto the class prototype function getPrototype(stmt) { if (stmt.expression && stmt.expression.left && stmt.expression.left.object && stmt.expression.left.object.property && stmt.expression.left.object.property.name === 'prototype') return stmt.expression.left.property.name; return null; } // Start building class constructor var ctorBlock = startNodeFrom(classBlock); ctorBlock.body = []; // Add parent class constructor call if (classParams.length === 1) { var objId = this.createNodeSpan(classBodyRefNode, classBodyRefNode, 'Identifier', { name: classParams[0].name }); var propertyId = this.createNodeSpan(classBodyRefNode, classBodyRefNode, 'Identifier', { name: 'call' }); var calleeMember = this.createNodeSpan(classBodyRefNode, classBodyRefNode, 'MemberExpression', { object: objId, property: propertyId, computed: false, }); var thisExpr = this.createNodeSpan(classBodyRefNode, classBodyRefNode, 'ThisExpression'); var callExpr = this.createNodeSpan(classBodyRefNode, classBodyRefNode, 'CallExpression', { callee: calleeMember, arguments: [thisExpr], }); var superExpr = this.createNodeSpan(classBodyRefNode, classBodyRefNode, 'ExpressionStatement', { expression: callExpr }); ctorBlock.body.push(superExpr); } // Add non-function statements and contents of special '__init__' method for (var i in classBlock.body) { var stmt = classBlock.body[i]; var prototype = getPrototype(stmt); if (!prototype) { ctorBlock.body.push(stmt); } else if (prototype === '__init__') { for (var j in stmt.expression.right.body.body) ctorBlock.body.push(stmt.expression.right.body.body[j]); ctorNode.params = stmt.expression.right.params; } } // Finish class constructor ctorNode.body = finishNode(ctorBlock, 'BlockStatement'); finishNode(ctorNode, 'ClassDeclaration'); container.body.push(ctorNode); // Add inheritance via 'MyClass.prototype = Object.create(ParentClass.prototype)' if (classParams.length === 1) { var childClassId = this.createNodeSpan(ctorNode, ctorNode, 'Identifier', { name: ctorNode.id.name }); var childPrototypeId = this.createNodeSpan(ctorNode, ctorNode, 'Identifier', { name: 'prototype' }); var childPrototypeMember = this.createNodeSpan(ctorNode, ctorNode, 'MemberExpression', { object: childClassId, property: childPrototypeId, computed: false, }); var parentClassId = this.createNodeSpan(ctorNode, ctorNode, 'Identifier', { name: classParams[0].name }); var parentPrototypeId = this.createNodeSpan(ctorNode, ctorNode, 'Identifier', { name: 'prototype' }); var parentPrototypeMember = this.createNodeSpan(ctorNode, ctorNode, 'MemberExpression', { object: parentClassId, property: parentPrototypeId, computed: false, }); var objClassId = this.createNodeSpan(ctorNode, ctorNode, 'Identifier', { name: 'Object' }); var objCreateId = this.createNodeSpan(ctorNode, ctorNode, 'Identifier', { name: 'create' }); var objPropertyMember = this.createNodeSpan(ctorNode, ctorNode, 'MemberExpression', { object: objClassId, property: objCreateId, computed: false, }); var callExpr = this.createNodeSpan(ctorNode, ctorNode, 'CallExpression', { callee: objPropertyMember, arguments: [parentPrototypeMember], }); var assignExpr = this.createNodeSpan(ctorNode, ctorNode, 'AssignmentExpression', { left: childPrototypeMember, operator: '=', right: callExpr, }); var inheritanceExpr = this.createNodeSpan(ctorNode, ctorNode, 'ExpressionStatement', { expression: assignExpr }); container.body.push(inheritanceExpr); } // Add class methods, which are already prototype assignments for (var i in classBlock.body) { var stmt = classBlock.body[i]; var prototype = getPrototype(stmt); if (prototype && prototype !== '__init__') container.body.push(stmt); } return finishNode(container, 'BlockStatement'); }, // Create for loop // // Problem: // 1. JavaScript for/in loop iterates on properties, which are the indexes for an Array // Python iterates on the list items themselves, not indexes // 2. JavaScript for/in does not necessarily iterate in order // Solution: // Generate extra AST to do the right thing at runtime // JavaScript for/in is used for dictionaries // If iterating through an ordered sequence, return something like: // { var __right = right; // if (__right instanceof Array) { // for(var __index=0; __index < __right.length; __index++) { // i = __right[__index]; // ... // } // } else { // for(i in __right){...} // } // } // When the loop target is a Tuple, it is unpacked into each for body in the example above. // E.g. 'for k, v in __right: total += v' becomes: // for (var __tmp in __right) { // k = __tmp[0]; // v = __tmp[1]; // total += v; // } // TODO: for/in on a string should go through items, not indexes. String obj and string literal. createFor: function(node, init, tupleArgs, right, body) { var forOrderedBody = body; var forInBody = JSON.parse(JSON.stringify(forOrderedBody)); var tmpVarSuffix = newAstIdCount++; var arrayId = this.createNodeSpan(node, node, 'Identifier', { name: 'Array' }); var lengthId = this.createNodeSpan(init, init, 'Identifier', { name: 'length' }); var zeroLit = this.createNodeSpan(init, init, 'Literal', { value: 0 }); // var __rightN = right var rightId = this.createNodeSpan(right, right, 'Identifier', { name: '__filbertRight' + tmpVarSuffix }); var rightAssign = this.createVarDeclFromId(right, rightId, right); // for(;;) and for(in) loops var forRightId = this.createNodeSpan(init, init, 'Identifier', { name: '__filbertRight' + tmpVarSuffix }); // for (var __indexN; __indexN < __rightN.length; ++__indexN) var forOrderedIndexId = this.createNodeSpan(init, init, 'Identifier', { name: '__filbertIndex' + tmpVarSuffix }); var forOrderedIndexDeclr = this.createNodeSpan(init, init, 'VariableDeclarator', { id: forOrderedIndexId, init: zeroLit, }); var forOrderedIndexDecln = this.createNodeSpan(init, init, 'VariableDeclaration', { declarations: [forOrderedIndexDeclr], kind: 'var', }); var forOrderedTestMember = this.createNodeSpan(init, init, 'MemberExpression', { object: forRightId, property: lengthId, computed: false, }); var forOrderedTestBinop = this.createNodeSpan(init, init, 'BinaryExpression', { left: forOrderedIndexId, operator: '<', right: forOrderedTestMember, }); var forOrderedUpdate = this.createNodeSpan(init, init, 'UpdateExpression', { operator: '++', prefix: true, argument: forOrderedIndexId, }); var forOrderedMember = this.createNodeSpan(init, init, 'MemberExpression', { object: forRightId, property: forOrderedIndexId, computed: true, }); if (tupleArgs) { var varStmts = unpackTuple(tupleArgs, forOrderedMember); for (var i = varStmts.length - 1; i >= 0; i--) forOrderedBody.body.unshift(varStmts[i]); } else { if (init.type === 'Identifier' && !scope.exists(init.name)) { scope.addVar(init.name); forOrderedBody.body.unshift(this.createVarDeclFromId(init, init, forOrderedMember)); } else { var forOrderedInit = this.createNodeSpan(init, init, 'AssignmentExpression', { operator: '=', left: init, right: forOrderedMember, }); var forOrderedInitStmt = this.createNodeSpan(init, init, 'ExpressionStatement', { expression: forOrderedInit }); forOrderedBody.body.unshift(forOrderedInitStmt); } } var forOrdered = this.createNodeSpan(node, node, 'ForStatement', { init: forOrderedIndexDecln, test: forOrderedTestBinop, update: forOrderedUpdate, body: forOrderedBody, }); var forOrderedBlock = this.createNodeSpan(node, node, 'BlockStatement', { body: [forOrdered] }); // for (init in __rightN) var forInLeft = init; if (tupleArgs) { var varStmts = unpackTuple(tupleArgs, right); forInLeft = varStmts[0]; for (var i = varStmts.length - 1; i > 0; i--) forInBody.body.unshift(varStmts[i]); } else if (init.type === 'Identifier' && !scope.exists(init.name)) { scope.addVar(init.name); forInLeft = this.createVarDeclFromId(init, init, null); } var forIn = this.createNodeSpan(node, node, 'ForInStatement', { left: forInLeft, right: forRightId, body: forInBody, }); var forInBlock = this.createNodeSpan(node, node, 'BlockStatement', { body: [forIn] }); // if ordered sequence then forOrdered else forIn var ifRightId = this.createNodeSpan(node, node, 'Identifier', { name: '__filbertRight' + tmpVarSuffix }); var ifTest = this.createNodeSpan(node, node, 'BinaryExpression', { left: ifRightId, operator: 'instanceof', right: arrayId, }); var ifStmt = this.createNodeSpan(node, node, 'IfStatement', { test: ifTest, consequent: forOrderedBlock, alternate: forInBlock, }); node.body = [rightAssign, ifStmt]; return node; }, // expr => __tmpList.push(expr); createListCompPush: function(expr, tmpVarSuffix) { var exprPushTmpListId = this.createNodeSpan(expr, expr, 'Identifier', { name: '__tmpList' + tmpVarSuffix }); var exprPushId = this.createNodeSpan(expr, expr, 'Identifier', { name: 'push' }); var exprMember = this.createNodeSpan(expr, expr, 'MemberExpression', { object: exprPushTmpListId, property: exprPushId, computed: false, }); var exprCall = this.createNodeSpan(expr, expr, 'CallExpression', { callee: exprMember, arguments: [expr], }); return this.createNodeSpan(expr, expr, 'ExpressionStatement', { expression: exprCall }); }, // (function() { // var _list = []; // ... // body // return _list; // }()); createListCompIife: function(node, body, tmpVarSuffix) { var iifeRuntimeId = this.createNodeSpan(node, node, 'Identifier', { name: options.runtimeParamName }); var iifeObjectsId = this.createNodeSpan(node, node, 'Identifier', { name: 'objects' }); var iifeObjMember = this.createNodeSpan(node, node, 'MemberExpression', { object: iifeRuntimeId, property: iifeObjectsId, computed: false, }); var iifeListId = this.createNodeSpan(node, node, 'Identifier', { name: 'list' }); var iifeListMember = this.createNodeSpan(node, node, 'MemberExpression', { object: iifeObjMember, property: iifeListId, computed: false, }); var iifeNewExpr = this.createNodeSpan(node, node, 'NewExpression', { callee: iifeListMember, arguments: [], }); var iifeListId = this.createNodeSpan(node, node, 'Identifier', { name: '__tmpList' + tmpVarSuffix }); var iifeListDecl = this.createVarDeclFromId(node, iifeListId, iifeNewExpr); var iifeReturnListId = this.createNodeSpan(node, node, 'Identifier', { name: '__tmpList' + tmpVarSuffix }); var iifeReturn = this.createNodeSpan(node, node, 'ReturnStatement', { argument: iifeReturnListId }); var iifeBlock = this.createNodeSpan(node, node, 'BlockStatement', { body: [iifeListDecl, body, iifeReturn] }); var fnExpr = this.createNodeSpan(node, node, 'FunctionExpression', { params: [], defaults: [], body: iifeBlock, generator: false, expression: false, }); return this.createNodeSpan(node, node, 'CallExpression', { callee: fnExpr, arguments: [] }); }, }; }; // Predicate that tests whether the next token is of the given // type, and if yes, consumes it as a side effect. function eat(type) { if (tokType === type) { next(); return true; } } // Expect a token of a given type. If found, consume it, otherwise, // raise an unexpected token error. function expect(type) { if (tokType === type) next(); else { var args = Array.prototype.slice.call(arguments); if (args.length > 1) unexpected({ type: args.map(function(t) { return t.type; }), }); else unexpected(type); } } // Raise an unexpected token error. function unexpected(expectedType) { raise(tokStart, 'Unexpected token', tokType && tokType.type, expectedType && expectedType.type); } // Verify that a node is an lval - somethin g that can be assigned // to. function checkLVal(expr) { if (expr.type !== 'Identifier' && expr.type !== 'MemberExpression') raise(expr.start, 'Assigning to rvalue'); if (strict && expr.type === 'Identifier' && isStrictBadIdWord(expr.name)) raise(expr.start, 'Assigning to ' + expr.name + ' in strict mode'); } // Get args for a new tuple expression function getTupleArgs(expr) { if (expr.callee && expr.callee.object && expr.callee.object.object && expr.callee.object.object.name === options.runtimeParamName && expr.callee.property && expr.callee.property.name === 'tuple') return expr.arguments; return null; } // Unpack an lvalue tuple into indivual variable assignments // 'arg0, arg1 = right' becomes: // var tmp = right // arg0 = tmp[0] // arg1 = tmp[1] // ... function unpackTuple(tupleArgs, right) { if (!tupleArgs || tupleArgs.length < 1) unexpected(); var varStmts = []; // var tmp = right var tmpId = nc.createNodeSpan(right, right, 'Identifier', { name: '__filbertTmp' + newAstIdCount++ }); var tmpDecl = nc.createVarDeclFromId(right, tmpId, right); varStmts.push(tmpDecl); // argN = tmp[N] for (var i = 0; i < tupleArgs.length; i++) { var lval = tupleArgs[i]; var subTupleArgs = getTupleArgs(lval); if (subTupleArgs) { var subLit = nc.createNodeSpan(right, right, 'Literal', { value: i }); var subRight = nc.createNodeSpan(right, right, 'MemberExpression', { object: tmpId, property: subLit, computed: true, }); var subStmts = unpackTuple(subTupleArgs, subRight); for (var j = 0; j < subStmts.length; j++) varStmts.push(subStmts[j]); } else { checkLVal(lval); var indexId = nc.createNodeSpan(right, right, 'Literal', { value: i }); var init = nc.createNodeSpan(right, right, 'MemberExpression', { object: tmpId, property: indexId, computed: true, }); if (lval.type === 'Identifier' && !scope.exists(lval.name)) { scope.addVar(lval.name); var varDecl = nc.createVarDeclFromId(lval, lval, init); varStmts.push(varDecl); } else { var node = startNodeFrom(lval); node.left = lval; node.operator = '='; node.right = init; finishNode(node, 'AssignmentExpression'); varStmts.push(nc.createNodeFrom(node, 'ExpressionStatement', { expression: node })); } } } return varStmts; } // ### Statement parsing // Parse a program. Initializes the parser, reads any number of // statements, and wraps them in a Program node. Optionally takes a // `program` argument. If present, the statements will be appended // to its body instead of creating a new node. function parseTopLevel(program) { lastStart = lastEnd = tokPos; if (options.locations) lastEndLoc = new Position; inFunction = strict = null; bracketNesting = 0; readToken(); var node = program || startNode(); if (!program) node.body = []; while (tokType !== _eof) { var stmt = parseStatement(); if (stmt) node.body.push(stmt); } return finishNode(node, 'Program'); } // Parse a single statement. // // If expecting a statement and finding a slash operator, parse a // regular expression literal. This is to handle cases like // `if (foo) /blah/.exec(foo);`, where looking at the previous token // does not help. function parseStatement() { if (tokType === _slash || tokType === _assign && tokVal == '/=') readToken(true); var starttype = tokType, node = startNode(); // Most types of statements are recognized by the keyword they // start with. Many are trivial to parse, some require a bit of // complexity. switch (starttype) { case _break: next(); return finishNode(node, 'BreakStatement'); case _continue: next(); return finishNode(node, 'ContinueStatement'); case _class: next(); return parseClass(node); case _def: next(); return parseFunction(node); case _for: next(); return parseFor(node); case _from: // Skipping from and import statements for now skipLine(); next(); return parseStatement(); case _if: case _elif: next(); if (tokType === _parenL) node.test = parseParenExpression(); else node.test = parseExpression(); expect(_colon); node.consequent = parseSuite(); if (tokType === _elif) node.alternate = parseStatement(); else node.alternate = eat(_else) && eat(_colon) ? parseSuite() : null; return finishNode(node, 'IfStatement'); case _import: // Skipping from and import statements for now skipLine(); next(); return parseStatement(); case _newline: // TODO: parseStatement() should probably eat it's own newline next(); return null; case _pass: next(); return finishNode(node, 'EmptyStatement'); case _return: if (!inFunction && !options.allowReturnOutsideFunction) raise(tokStart, '\'return\' outside of function'); next(); if (tokType === _newline || tokType === _eof) node.argument = null; else { node.argument = parseExpression(); } return finishNode(node, 'ReturnStatement'); case _try: // TODO, and remove parseBlock next(); node.block = parseBlock(); node.handler = null; if (tokType === _catch) { var clause = startNode(); next(); expect(_parenL); clause.param = parseIdent(); if (strict && isStrictBadIdWord(clause.param.name)) raise(clause.param.start, 'Binding ' + clause.param.name + ' in strict mode'); expect(_parenR); clause.guard = null; clause.body = parseBlock(); node.handler = finishNode(clause, 'CatchClause'); } node.guardedHandlers = empty; node.finalizer = eat(_finally) ? parseBlock() : null; if (!node.handler && !node.finalizer) raise(node.start, 'Missing catch or finally clause'); return finishNode(node, 'TryStatement'); case _while: next(); if (tokType === _parenL) node.test = parseParenExpression(); else node.test = parseExpression(); expect(_colon); node.body = parseSuite(); return finishNode(node, 'WhileStatement'); case _with: // TODO if (strict) raise(tokStart, '\'with\' in strict mode'); next(); node.object = parseParenExpression(); node.body = parseStatement(); return finishNode(node, 'WithStatement'); case _semi: next(); return finishNode(node, 'EmptyStatement'); case _comment: node.value = tokVal; next(); return finishNode(node, 'Comment'); // Assume it's an ExpressionStatement. If an assign has been // converted to a variable declaration, pass it up as is. default: var expr = parseExpression(); if (tokType !== _semi && tokType !== _newline && tokType !== _eof) unexpected(); if (expr.type === 'VariableDeclaration' || expr.type === 'BlockStatement') { return expr; } else { node.expression = expr; return finishNode(node, 'ExpressionStatement'); } } } // Parse indent-enclosed block of statements function parseBlock() { var node = startNode(); node.body = []; while (tokType !== _dedent && tokType !== _eof) { var stmt = parseStatement(); if (stmt) node.body.push(stmt); } if (tokType === _dedent) next(); return finishNode(node, 'BlockStatement'); } // Parse 'suite' from Python grammar spec // Will replace parseBlock eventually function parseSuite() { // NOTE: This is not strictly valid Python for this to be an empty block var node = startNode(); node.body = []; if (tokType === _comment) { node.comment = { value: tokVal }; next(); } if (eat(_newline)) { if (tokType === _indent) { expect(_indent); while (!eat(_dedent) && !eat(_eof)) { var stmt = parseStatement(); if (stmt) node.body.push(stmt); } } } else if (tokType !== _eof) { node.body.push(parseStatement()); next(); } return finishNode(node, 'BlockStatement'); } // Parse for/in loop function parseFor(node) { var init = parseExpression(false, true); var tupleArgs = getTupleArgs(init); if (!tupleArgs) checkLVal(init); expect(_in); var right = parseExpression(); expect(_colon); var body = parseSuite(); finishNode(node, 'BlockStatement'); return nc.createFor(node, init, tupleArgs, right, body); } // ### Expression parsing // These nest, from the most general expression type at the top to // 'atomic', nondivisible expression types at the bottom. Most of // the functions will simply let the function(s) below them parse, // and, *if* the syntactic construct they handle is present, wrap // the AST node that the inner parser gave them in another node. // Parse a full expression. The arguments are used to forbid comma // sequences (in argument lists, array literals, or object literals) // or the `in` operator (in for loops initalization expressions). function parseExpression(noComma, noIn) { return parseMaybeAssign(noIn); } // Used for constructs like `switch` and `if` that insist on // parentheses around their expression. function parseParenExpression() { expect(_parenL); var val = parseExpression(); expect(_parenR); return val; } // Parse an assignment expression. This includes applications of // operators like `+=`. // Add 'this.' to assignments in a class constructor. // Convert identifier assignment to variable declaration if the // identifier doesn't exist in this namespace yet. function parseMaybeAssign(noIn) { var left = parseMaybeTuple(noIn); if (!tokType.isAssign) return left; var node; while (tokType.isAssign) { if (!node) { var tupleArgs = getTupleArgs(left); if (tupleArgs) { next(); var right = parseMaybeTuple(noIn); var blockNode = startNodeFrom(left); blockNode.body = unpackTuple(tupleArgs, right); return finishNode(blockNode, 'BlockStatement'); } if (scope.isClass()) { var thisExpr = nc.createNodeFrom(left, 'ThisExpression'); left = nc.createNodeFrom(left, 'MemberExpression', { object: thisExpr, property: left }); } node = startNodeFrom(left); node.operator = tokVal; checkLVal(left); node.left = left; } if (node.right) { if (!node.left.length) node.left = [node.left]; node.left.push(node.right); left = node.right; } next(); node.right = parseMaybeTuple(noIn); if (left.type === 'Identifier' && !scope.exists(left.name)) { if (!node.operator || node.length > 1) unexpected(); scope.addVar(left.name); // return nc.createVarDeclFromId(node.left, node.left, node.right); // customized variable must be assign } } return finishNode(node, 'AssignmentExpression'); } // Parse a tuple function parseMaybeTuple(noIn) { var expr = parseExprOps(noIn); if (tokType === _comma) { return parseTuple(noIn, expr); } return expr; } // Start the precedence parser. function parseExprOps(noIn) { return parseExprOp(parseMaybeUnary(noIn), -1, noIn); } // Parse binary operators with the operator precedence parsing // algorithm. `left` is the left-hand side of the operator. // `minPrec` provides context that allows the function to stop and // defer further parser to one of its callers when it encounters an // operator that has a lower precedence than the set it is parsing. // Exponentiation is evaluated right-to-left, so 'prec >= minPrec' // Exponentiation operator 'x**y' is replaced with 'Math.pow(x, y)' // Floor division operator 'x//y' is replaced with 'Math.floor(x/y)' // 'in' and 'not in' implemented via indexOf() function parseExprOp(left, minPrec, noIn) { var node, exprNode, right, op = tokType, val = tokVal; var prec = op === _not ? _in.prec : op.prec; if (false) { node = startNodeFrom(left); next(); right = parseExprOp(parseMaybeUnary(noIn), prec, noIn); exprNode = nc.createNodeMemberCall(node, 'math', 'pow', [left, right]); return parseExprOp(exprNode, minPrec, noIn); } else if (prec != null && (!noIn || op !== _in)) { if (prec > minPrec) { next(); node = startNodeFrom(left); if (op === _floorDiv) { right = parseExprOp(parseMaybeUnary(noIn), prec, noIn); finishNode(node); exprNode = nc.createNodeSpan(node, node, 'BinaryExpression', { left: left, operator: '//', right: right, }); } else if (op === _in || op === _not) { if (op === _in || eat(_in)) { right = parseExprOp(parseMaybeUnary(noIn), prec, noIn); finishNode(node); var notLit = nc.createNodeSpan(node, node, 'Literal', { value: op === _not }); exprNode = nc.createNodeRuntimeCall(node, 'ops', 'in', [left, right, notLit]); } else raise(tokPos, 'Expected \'not in\' comparison operator'); } else { if (op === _is) { if (eat(_not)) node.operator = '!=='; else node.operator = '==='; } else node.operator = op.rep != null ? op.rep : val; node.left = left; node.right = parseExprOp(parseMaybeUnary(noIn), prec, noIn); exprNode = finishNode(node, (op === _or || op === _and) ? 'LogicalExpression' : 'BinaryExpression'); } return parseExprOp(exprNode, minPrec, noIn); } } return left; } // Parse unary operators. // '-+' are prefixes here, with different precedence. function parseMaybeUnary(noIn) { if (tokType.prefix || tokType === _plusMin) { var prec = tokType === _plusMin ? _posNegNot.prec : tokType.prec; var node = startNode(); node.operator = tokType.rep != null ? tokType.rep : tokVal; node.prefix = true; tokRegexpAllowed = true; next(); node.argument = parseExprOp(parseMaybeUnary(noIn), prec, noIn); return finishNode(node, 'UnaryExpression'); } return parseSubscripts(parseExprAtom()); } // Parse call, dot, and `[]`-subscript expressions. function parseSubscripts(base, noCalls) { var node = startNodeFrom(base); if (eat(_dot)) { var id = parseIdent(true); if (pythonRuntime.imports[base.name] && pythonRuntime.imports[base.name][id.name]) { // Calling a Python import function // TODO: Unpack parameters into JavaScript-friendly parameters var runtimeId = nc.createNodeSpan(base, base, 'Identifier', { name: options.runtimeParamName }); var importsId = nc.createNodeSpan(base, base, 'Identifier', { name: 'imports' }); var runtimeMember = nc.createNodeSpan(base, base, 'MemberExpression', { object: runtimeId, property: importsId, computed: false, }); node.object = nc.createNodeSpan(base, base, 'MemberExpression', { object: runtimeMember, property: base, computed: false, }); } else if (base.name && base.name === scope.getThisReplace()) { node.object = nc.createNodeSpan(base, base, 'ThisExpression'); } else node.object = base; node.property = id; node.computed = false; return parseSubscripts(finishNode(node, 'MemberExpression'), noCalls); } else if (eat(_bracketL)) { var expr, isSlice = false; if (eat(_colon)) isSlice = true; else expr = parseExpression(); if (!isSlice && eat(_colon)) isSlice = true; if (isSlice) return parseSlice(node, base, expr, noCalls); var subscriptCall = nc.createNodeSpan(expr, expr, 'CallExpression'); subscriptCall.callee = nc.createNodeOpsCallee(expr, 'subscriptIndex'); subscriptCall.arguments = [base, expr]; node.object = base; node.property = subscriptCall; node.computed = true; expect(_bracketR); return parseSubscripts(finishNode(node, 'MemberExpression'), noCalls); } else if (!noCalls && eat(_parenL)) { node.arguments = parseExprList(_parenR, false); if (scope.isNewObj(base.name)) finishNode(node, 'NewExpression'); else finishNode(node, 'CallExpression'); if (pythonRuntime.functions[base.name]) { // Calling a Python built-in function // TODO: Unpack parameters into JavaScript-friendly parameters if (base.type !== 'Identifier') unexpected(); var runtimeId = nc.createNodeSpan(base, base, 'Identifier', { name: options.runtimeParamName }); var functionsId = nc.createNodeSpan(base, base, 'Identifier', { name: 'functions' }); var runtimeMember = nc.createNodeSpan(base, base, 'MemberExpression', { object: runtimeId, property: functionsId, computed: false, }); node.callee = nc.createNodeSpan(base, base, 'MemberExpression', { object: runtimeMember, property: base, computed: false, }); } else node.callee = base; if (tokType === _comment) { node.comment = { value: tokVal }; next(); } return parseSubscripts(node, noCalls); } return base; } function parseSlice(node, base, start, noCalls) { var end, step; if (!start) start = nc.createNodeFrom(node, 'Literal', { value: null }); if (tokType === _bracketR || eat(_colon)) { end = nc.createNodeFrom(node, 'Literal', { value: null }); } else { end = parseExpression(); if (tokType !== _bracketR) expect(_colon); } if (tokType === _bracketR) step = nc.createNodeFrom(node, 'Literal', { value: null }); else step = parseExpression(); expect(_bracketR); node.arguments = [start, end, step]; var sliceId = nc.createNodeFrom(base, 'Identifier', { name: '_pySlice' }); var memberExpr = nc.createNodeSpan(base, base, 'MemberExpression', { object: base, property: sliceId, computed: false, }); node.callee = memberExpr; return parseSubscripts(finishNode(node, 'CallExpression'), noCalls); } // Parse an atomic expression - either a single token that is an // expression, an expression started by a keyword like `function` or // `new`, or an expression wrapped in punctuation like `()`, `[]`, // or `{}`. function parseExprAtom() { switch (tokType) { case _dict: next(); return parseDict(_parenR); case _name: return parseIdent(); case _num: case _string: case _regexp: var node = startNode(); node.value = tokVal; node.raw = input.slice(tokStart, tokEnd); next(); return finishNode(node, 'Literal'); case _none: case _true: case _false: var node = startNode(); node.value = tokType.atomValue; node.raw = tokType.keyword; next(); return finishNode(node, 'Literal'); case _parenL: var tokStartLoc1 = tokStartLoc, tokStart1 = tokStart; next(); if (tokType === _parenR) { // Empty tuple var node = parseTuple(false); eat(_parenR); return node; } var val = parseMaybeTuple(false); if (options.locations) { val.loc.start = tokStartLoc1; val.loc.end = tokEndLoc; } if (options.ranges) val.range = [tokStart1, tokEnd]; expect(_parenR); return val; case _bracketL: return parseList(); case _braceL: return parseDict(_braceR); case _indent: raise(tokStart, 'Unexpected indent'); default: unexpected(); } } // Parse list // Custom list object is used to simulate native Python list // E.g. Python '[]' becomes JavaScript 'new __pythonRuntime.objects.list();' // If list comprehension, build something like this: //(function() { // var _list = []; // ... // _list.push(expr); // return _list; //}()); function parseList() { var node = startNode(); node.arguments = []; next(); if (!eat(_bracketR)) { var expr = parseExprOps(false); if (tokType === _for || tokType === _if) { // List comprehension var tmpVarSuffix = newAstIdCount++; expr = nc.createListCompPush(expr, tmpVarSuffix); var body = parseCompIter(expr, true); finishNode(node); return nc.createListCompIife(node, body, tmpVarSuffix); } else if (eat(_comma)) { node.arguments = [expr].concat(parseExprList(_bracketR, true, false)); } else { expect(_bracketR); node.arguments = [expr]; } } finishNode(node, 'NewExpression'); var runtimeId = nc.createNodeSpan(node, node, 'Identifier', { name: options.runtimeParamName }); var objectsId = nc.createNodeSpan(node, node, 'Identifier', { name: 'objects' }); var runtimeMember = nc.createNodeSpan(node, node, 'MemberExpression', { object: runtimeId, property: objectsId, computed: false, }); var listId = nc.createNodeSpan(node, node, 'Identifier', { name: 'list' }); node.callee = nc.createNodeSpan(node, node, 'MemberExpression', { object: runtimeMember, property: listId, computed: false, }); return node; } // Parse a comp_iter from Python language grammar // Used to build list comprehensions // 'expr' is the body to be used after unrolling the ifs and fors function parseCompIter(expr, first) { if (first && tokType !== _for) unexpected(); if (eat(_bracketR)) return expr; var node = startNode(); if (eat(_for)) { var init = parseExpression(false, true); var tupleArgs = getTupleArgs(init); if (!tupleArgs) checkLVal(init); expect(_in); var right = parseExpression(); var body = parseCompIter(expr, false); var block = nc.createNodeSpan(body, body, 'BlockStatement', { body: [body] }); finishNode(node, 'BlockStatement'); return nc.createFor(node, init, tupleArgs, right, block); } else if (eat(_if)) { if (tokType === _parenL) node.test = parseParenExpression(); else node.test = parseExpression(); node.consequent = parseCompIter(expr, false); return finishNode(node, 'IfStatement'); } else unexpected(); } // Parse class function parseClass(ctorNode) { // Container for class constructor and prototype functions var container = startNodeFrom(ctorNode); container.body = []; // Parse class signature ctorNode.id = parseIdent(); ctorNode.params = []; var classParams = []; if (eat(_parenL)) { var first = true; while (!eat(_parenR)) { if (!first) expect(_comma); else first = false; classParams.push(parseIdent()); } } if (classParams.length > 1) raise(tokPos, 'Multiple inheritance not supported'); expect(_colon); // Start new namespace for class body scope.startClass(ctorNode.id.name); // Save a reference for source ranges var classBodyRefNode = finishNode(startNode()); // Parse class body var classBlock = parseSuite(); // Generate additional AST to implement class var classStmt = nc.createClass(container, ctorNode, classParams, classBodyRefNode, classBlock); scope.end(); return classStmt; } // Parse dictionary // Custom dict object used to simulate native Python dict // E.g. "{'k1':'v1', 'k2':'v2'}" becomes "new __pythonRuntime.objects.dict(['k1', 'v1'], ['k2', 'v2']);" function parseDict(tokClose) { var node = startNode(), first = true, key, value; node.arguments = []; next(); while (!eat(tokClose)) { if (!first) { expect(_comma); } else first = false; if (tokClose === _braceR) { key = parsePropertyName(); expect(_colon); value = parseExprOps(false); } else if (tokClose === _parenR) { var keyId = parseIdent(true); key = startNodeFrom(keyId); key.value = keyId.name; finishNode(key, 'Literal'); expect(_eq); value = parseExprOps(false); } else unexpected(); node.arguments.push(nc.createNodeSpan(key, value, 'ArrayExpression', { elements: [key, value] })); } finishNode(node, 'NewExpression'); var runtimeId = nc.createNodeSpan(node, node, 'Identifier', { name: options.runtimeParamName }); var objectsId = nc.createNodeSpan(node, node, 'Identifier', { name: 'objects' }); var runtimeMember = nc.createNodeSpan(node, node, 'MemberExpression', { object: runtimeId, property: objectsId, computed: false, }); var listId = nc.createNodeSpan(node, node, 'Identifier', { name: 'dict' }); node.callee = nc.createNodeSpan(node, node, 'MemberExpression', { object: runtimeMember, property: listId, computed: false, }); return node; } function parsePropertyName() { if (tokType === _num || tokType === _string) return parseExprAtom(); return parseIdent(true); } function parseFunction(node) { // TODO: The node creation utilities used here are tightly coupled (e.g. variable names) var suffix = newAstIdCount++; node.id = parseIdent(); node.params = []; // Parse parameters var formals = []; // In order, maybe with default value var argsId = null; // *args var kwargsId = null; // **kwargs var defaultsFound = false; var first = true; expect(_parenL); while (!eat(_parenR)) { if (!first) expect(_comma); else first = false; if (tokVal === '*') { if (kwargsId) raise(tokPos, 'invalid syntax'); next(); argsId = parseIdent(); } else if (tokVal === '**') { next(); kwargsId = parseIdent(); } else { if (kwargsId) raise(tokPos, 'invalid syntax'); var paramId = parseIdent(null, true); if (eat(_eq)) { formals.push({ id: paramId, expr: parseExprOps(false) }); defaultsFound = true; } else { if (defaultsFound) raise(tokPos, 'non-default argument follows default argument'); if (argsId) raise(tokPos, 'missing required keyword-only argument'); formals.push({ id: paramId, expr: null }); } } } expect(_colon); // Start a new scope with regard to the `inFunction` // flag (restore them to their old value afterwards). // `inFunction` used to throw syntax error for stray `return` var oldInFunc = inFunction = true; scope.startFn(node.id.name); // If class method, remove class instance var from params and save for 'this' replacement if (scope.isParentClass()) { var selfId = formals.shift(); scope.setThisReplace(selfId.id.name); } var body = parseSuite(); node.body = nc.createNodeSpan(body, body, 'BlockStatement', { body: [] }); // Add runtime parameter processing // The caller may pass a complex parameter object as a single parameter like this: // {formals:[, , ...], keywords:{:, :, ...}} /* if (formals.length > 0 || argsId || kwargsId) { // var __params = arguments.length === 1 && arguments[0].formals && arguments[0].keywords ? arguments[0] : null; node.body.body.push(nc.createNodeParamsCheck(node.id, suffix)); // var __formalsIndex = 0; node.body.body.push(nc.createGeneratedVarDeclFromId(node.id, nc.createNodeSpan(node.id, node.id, "Identifier", { name: '__formalsIndex' + suffix }), nc.createNodeSpan(node.id, node.id, "Literal", { value: 0 }))); // var __args = arguments; node.body.body.push(nc.createGeneratedVarDeclFromId(node.id, nc.createNodeSpan(node.id, node.id, "Identifier", { name: '__args' + suffix }), nc.createNodeSpan(node.id, node.id, "Identifier", { name: 'arguments' }))); } */ if (formals.length > 0) { // function __getParam(v, d) { // var r = d; // if (__params) { // if (__formalsIndex < __params.formals.length) { // r = __params.formals[__formalsIndex++]; // } else if (v in __params.keywords) { // r = __params.keywords[v]; // delete __params.keywords[v]; // } // } else if (__formalsIndex < __args.length) { // r = __args[__formalsIndex++]; // } // return r; // } //node.body.body.push(nc.createNodeGetParamFn(node.id, suffix)); node.arguments = []; for (var i = 0; i < formals.length; i++) { // var = __getParam('', ); node.arguments.push(nc.createNodeSpan(formals[i].id, formals[i].id, 'Identifier', { name: formals[i].id.name })); } } var refNode = argsId || kwargsId; if (refNode) { if (argsId) { // var = []; var argsAssign = nc.createGeneratedVarDeclFromId(argsId, argsId, nc.createNodeSpan(argsId, argsId, 'ArrayExpression', { elements: [] })); node.body.body.push(argsAssign); } if (kwargsId) { // var = {}; var kwargsAssign = nc.createGeneratedVarDeclFromId(kwargsId, kwargsId, nc.createNodeSpan(kwargsId, kwargsId, 'ObjectExpression', { properties: [] })); node.body.body.push(kwargsAssign); } // if (__params) {} var argsIf = nc.createNodeSpan(refNode, refNode, 'IfStatement', { test: nc.createNodeSpan(refNode, refNode, 'Identifier', { name: '__params' + suffix }), consequent: nc.createNodeSpan(refNode, refNode, 'BlockStatement', { body: [] }), }); if (argsId) { // while (__formalsIndex < __params.formals.length) { // .push(__params.formals[__formalsIndex++]); } argsIf.consequent.body.push(nc.createNodeArgsWhileConsequent(argsId, suffix)); // { while (__formalsIndex < __args.length) { // .push(__args[__formalsIndex++]); }} argsIf.alternate = nc.createNodeArgsAlternate(argsId, suffix); } if (kwargsId) { // = __params.keywords argsIf.consequent.body.push(nc.createNodeSpan(kwargsId, kwargsId, 'ExpressionStatement', { expression: nc.createNodeSpan(kwargsId, kwargsId, 'AssignmentExpression', { operator: '=', left: kwargsId, right: nc.createNodeMembIds(kwargsId, '__params' + suffix, 'keywords'), }), })); } node.body.body.push(argsIf); } // Convert original body to 'return (function() {}).call(this);' node.body.body.push(nc.createNodeFnBodyIife(body)); inFunction = oldInFunc; // Verify that argument names are not repeated for (var i = 0; i < formals.length; ++i) { for (var j = 0; j < i; ++j) if (formals[i].id.name === formals[j].id.name) raise(formals[i].id.start, 'Argument name clash'); } // If class method, replace with prototype function literals var retNode; if (scope.isParentClass()) { finishNode(node); var classId = nc.createNodeSpan(node, node, 'Identifier', { name: scope.getParentClassName() }); var prototypeId = nc.createNodeSpan(node, node, 'Identifier', { name: 'prototype' }); var functionId = node.id; var prototypeMember = nc.createNodeSpan(node, node, 'MemberExpression', { object: classId, property: prototypeId, computed: false, }); var functionMember = nc.createNodeSpan(node, node, 'MemberExpression', { object: prototypeMember, property: functionId, computed: false, }); var functionExpr = nc.createNodeSpan(node, node, 'FunctionExpression', { body: node.body, params: node.params, }); var assignExpr = nc.createNodeSpan(node, node, 'AssignmentExpression', { left: functionMember, operator: '=', right: functionExpr, }); retNode = nc.createNodeSpan(node, node, 'ExpressionStatement', { expression: assignExpr }); } else retNode = finishNode(node, 'FunctionDeclaration'); scope.end(); return retNode; } // Parses a comma-separated list of expressions, and returns them as // an array. `close` is the token type that ends the list, and // `allowEmpty` can be turned on to allow subsequent commas with // nothing in between them to be parsed as `null` (which is needed // for array literals). function parseExprList(close, allowTrailingComma, allowEmpty) { var elts = [], first = true; while (!eat(close)) { if (!first) { expect(_comma, close); if (allowTrailingComma && options.allowTrailingCommas && eat(close)) break; } else first = false; if (allowEmpty && tokType === _comma) elts.push(null); else elts.push(parseExprOps(false)); } return elts; } function parseParamsList() { // In: expr, expr, ..., id=expr, id=expr, ... // Out: expr, expr, ..., {id:expr, __kwp:true}, {id:expr, __kwp:true}, ... var elts = [], first = true; while (!eat(_parenR)) { if (!first) expect(_comma); else first = false; var expr = parseExprOps(false); if (eat(_eq)) { var right = parseExprOps(false); var kwId = nc.createNodeSpan(expr, right, 'Identifier', { name: '__kwp' }); var kwLit = nc.createNodeSpan(expr, right, 'Literal', { value: true }); var left = nc.createNodeSpan(expr, right, 'ObjectExpression', { properties: [] }); left.properties.push({ type: 'Property', key: expr, value: right, kind: 'init' }); left.properties.push({ type: 'Property', key: kwId, value: kwLit, kind: 'init' }); expr = left; } elts.push(expr); } return elts; } // Parse the next token as an identifier. If `liberal` is true (used // when parsing properties), it will also convert keywords into // identifiers. // `isString` is use for Entry Python start block // TODO: liberal? function parseIdent(liberal, isString) { var node = startNode(); if (liberal) liberal = false; if (tokType === _name || (isString && ((tokType === _string) || (tokType === _num)))) { if (!liberal && strict && input.slice(tokStart, tokEnd).indexOf('\\') == -1) raise(tokStart, 'The keyword \'' + tokVal + '\' is reserved'); node.name = tokVal; } else if (liberal && tokType.keyword) { node.name = tokType.keyword; } else { unexpected(); } tokRegexpAllowed = false; next(); return finishNode(node, 'Identifier'); } function parseTuple(noIn, expr) { var node = expr ? startNodeFrom(expr) : startNode(); node.arguments = expr ? [expr] : []; // Tuple with single element has special trailing comma: t = 'hi', // Look ahead and eat comma in this scenario if (tokType === _comma) { var oldPos = tokPos; skipSpace(); var newPos = tokPos; tokPos = oldPos; if (newPos >= inputLen || input[newPos] === ';' || input[newPos] === ')' || newline.test(input[newPos])) eat(_comma); } while (eat(_comma)) { node.arguments.push(parseExprOps(noIn)); } finishNode(node, 'NewExpression'); var runtimeId = nc.createNodeSpan(node, node, 'Identifier', { name: options.runtimeParamName }); var objectsId = nc.createNodeSpan(node, node, 'Identifier', { name: 'objects' }); var runtimeMember = nc.createNodeSpan(node, node, 'MemberExpression', { object: runtimeId, property: objectsId, computed: false, }); var listId = nc.createNodeSpan(node, node, 'Identifier', { name: 'tuple' }); node.callee = nc.createNodeSpan(node, node, 'MemberExpression', { object: runtimeMember, property: listId, computed: false, }); return node; } // ## Python runtime library var pythonRuntime = exports.pythonRuntime = { // Shim JavaScript objects that impersonate Python equivalents // TODO: use 'type' or isSequence instead of 'instanceof Array' to id these internal: { // Only used within runtime isSeq: function(a) { return a && (a._type === 'list' || a._type === 'tuple'); }, slice: function(obj, start, end, step) { if (step == null || step === 0) step = 1; // TODO: step === 0 is a runtime error if (start == null) { if (step < 0) start = obj.length - 1; else start = 0; } else if (start < 0) start += obj.length; if (end == null) { if (step < 0) end = -1; else end = obj.length; } else if (end < 0) end += obj.length; var ret = new pythonRuntime.objects.list(), tmp, i; if (step < 0) { tmp = obj.slice(end + 1, start + 1); for (i = tmp.length - 1; i >= 0; i += step) ret.append(tmp[i]); } else { tmp = obj.slice(start, end); if (step === 1) ret = pythonRuntime.utils.createList(tmp); else for (i = 0; i < tmp.length; i += step) ret.append(tmp[i]); } return ret; }, isJSArray: Array.isArray || function(obj) { return toString.call(obj) === '[object Array]'; }, }, utils: { convertToDict: function(dict) { if (!dict.hasOwnProperty('_type')) { Object.defineProperty(dict, '_type', { get: function() { return 'dict'; }, enumerable: false, }); } if (!dict.hasOwnProperty('_isPython')) { Object.defineProperty(dict, '_isPython', { get: function() { return true; }, enumerable: false, }); } if (!dict.hasOwnProperty('items')) { Object.defineProperty(dict, 'items', { value: function() { var items = new pythonRuntime.objects.list(); for (var k in this) items.append(new pythonRuntime.objects.tuple(k, this[k])); return items; }, enumerable: false, }); } if (!dict.hasOwnProperty('length')) { Object.defineProperty(dict, 'length', { get: function() { return Object.keys(this).length; }, enumerable: false, }); } if (!dict.hasOwnProperty('clear')) { Object.defineProperty(dict, 'clear', { value: function() { for (var i in this) delete this[i]; }, enumerable: false, }); } if (!dict.hasOwnProperty('get')) { Object.defineProperty(dict, 'get', { value: function(key, def) { if (key in this) return this[key]; else if (def !== undefined) return def; return null; }, enumerable: false, }); } if (!dict.hasOwnProperty('keys')) { Object.defineProperty(dict, 'keys', { value: function() { return Object.keys(this); }, enumerable: false, }); } if (!dict.hasOwnProperty('pop')) { Object.defineProperty(dict, 'pop', { value: function(key, def) { var value; if (key in this) { value = this[key]; delete this[key]; } else if (def !== undefined) value = def; else return new Error('KeyError'); return value; }, enumerable: false, }); } if (!dict.hasOwnProperty('values')) { Object.defineProperty(dict, 'values', { value: function() { var values = new pythonRuntime.objects.list(); for (var key in this) values.append(this[key]); return values; }, enumerable: false, }); } }, createDict: function() { var ret = new pythonRuntime.objects.dict(); if (arguments.length === 1 && arguments[0] instanceof Object) for (var k in arguments[0]) ret[k] = arguments[0][k]; else throw TypeError('createDict expects a single JavaScript object'); return ret; }, createParamsObj: function() { // In: expr, expr, ..., {id:expr, __kwp:true}, {id:expr, __kwp:true}, ... // Out: {formals:[expr, expr, ...], keywords:{id:expr, id:expr, ...}} var params = { formals: new pythonRuntime.objects.list(), keywords: new pythonRuntime.objects.dict() }; for (var i = 0; i < arguments.length; i++) { if (arguments[i] && arguments[i].__kwp === true) { for (var k in arguments[i]) if (k !== '__kwp') params.keywords[k] = arguments[i][k]; } else params.formals.push(arguments[i]); } return params; }, convertToList: function(list) { if (!list.hasOwnProperty('_type')) { Object.defineProperty(list, '_type', { get: function() { return 'list'; }, enumerable: false, }); } if (!list.hasOwnProperty('_isPython')) { Object.defineProperty(list, '_isPython', { get: function() { return true; }, enumerable: false, }); } if (!list.hasOwnProperty('append')) { Object.defineProperty(list, 'append', { value: function(x) { this.push(x); }, enumerable: false, }); } if (!list.hasOwnProperty('clear')) { Object.defineProperty(list, 'clear', { value: function() { this.splice(0, this.length); }, enumerable: false, }); } if (!list.hasOwnProperty('copy')) { Object.defineProperty(list, 'copy', { value: function() { return this.slice(0); }, enumerable: false, }); } if (!list.hasOwnProperty('count')) { Object.defineProperty(list, 'count', { value: function(x) { var c = 0; for (var i = 0; i < this.length; i++) if (this[i] === x) c++; return c; }, enumerable: false, }); } if (!list.hasOwnProperty('equals')) { Object.defineProperty(list, 'equals', { value: function(x) { try { if (this.length !== x.length) return false; for (var i = 0; i < this.length; i++) { if (this[i].hasOwnProperty('equals')) { if (!this[i].equals(x[i])) return false; } else if (this[i] !== x[i]) return false; } return true; } catch (e) { } return false; }, enumerable: false, }); } if (!list.hasOwnProperty('extend')) { Object.defineProperty(list, 'extend', { value: function(L) { for (var i = 0; i < L.length; i++) this.push(L[i]); }, enumerable: false, }); } if (!list.hasOwnProperty('index')) { Object.defineProperty(list, 'index', { value: function(x) { return this.indexOf(x); }, enumerable: false, }); } if (!list.hasOwnProperty('indexOf')) { Object.defineProperty(list, 'indexOf', { value: function(x, fromIndex) { try { for (var i = fromIndex ? fromIndex : 0; i < this.length; i++) { if (this[i].hasOwnProperty('equals')) { if (this[i].equals(x)) return i; } else if (this[i] === x) return i; } } catch (e) { } return -1; }, enumerable: false, }); } if (!list.hasOwnProperty('insert')) { Object.defineProperty(list, 'insert', { value: function(i, x) { this.splice(i, 0, x); }, enumerable: false, }); } if (!list.hasOwnProperty('pop')) { Object.defineProperty(list, 'pop', { value: function(i) { if (!i) i = this.length - 1; var item = this[i]; this.splice(i, 1); return item; }, enumerable: false, }); } if (!list.hasOwnProperty('_pySlice')) { Object.defineProperty(list, '_pySlice', { value: function(start, end, step) { return pythonRuntime.internal.slice(this, start, end, step); }, enumerable: false, }); } if (!list.hasOwnProperty('remove')) { Object.defineProperty(list, 'remove', { value: function(x) { this.splice(this.indexOf(x), 1); }, enumerable: false, }); } if (!list.hasOwnProperty('sort')) { Object.defineProperty(list, 'sort', { value: function(x, reverse) { var list2 = this.slice(0); var apply_key = function(a, numerical) { var list3 = list2.map(x); // construct a dict that maps the listay before and after the map var mapping = {}; for (var i in list3) mapping[list3[i]] = list2[i]; if (numerical) list3.sort(function(a, b) { return a - b; }); else list3.sort(); for (var i in a) a[i] = mapping[list3[i]]; }; for (var i in this) { if (typeof this[i] !== 'number' || !isFinite(this[i])) { if (typeof x != 'undefined') { apply_key(this, false); } else { list2.sort(); for (var j in this) this[j] = list2[j]; } if (reverse) this.reverse(); return; } } if (typeof x != 'undefined') { apply_key(this, true); } else { list2.sort(function(a, b) { return a - b; }); for (var i in this) this[i] = list2[i]; } if (reverse) this.reverse(); }, enumerable: false, }); } if (!list.hasOwnProperty('toString')) { Object.defineProperty(list, 'toString', { value: function() { return '[' + this.join(', ') + ']'; }, enumerable: false, }); } }, createList: function() { var ret = new pythonRuntime.objects.list(); if (arguments.length === 1 && arguments[0] instanceof Array) for (var i in arguments[0]) ret.push(arguments[0][i]); else for (var i in arguments) ret.push(arguments[i]); return ret; }, }, ops: { add: function(a, b) { if (pythonRuntime.internal.isSeq(a) && pythonRuntime.internal.isSeq(b)) { if (a._type !== b._type) throw TypeError('can only concatenate ' + a._type + ' (not \'' + b._type + '\') to ' + a._type); var ret; if (a._type === 'list') ret = new pythonRuntime.objects.list(); else if (a._type === 'tuple') ret = new pythonRuntime.objects.tuple(); if (ret) { for (var i = 0; i < a.length; i++) ret.push(a[i]); for (var i = 0; i < b.length; i++) ret.push(b[i]); return ret; } } return a + b; }, in: function(a, b, n) { var r = b.hasOwnProperty('indexOf') ? b.indexOf(a) >= 0 : a in b; return n ? !r : r; }, multiply: function(a, b) { // TODO: non-sequence operand must be an integer if (pythonRuntime.internal.isSeq(a) && !isNaN(parseInt(b))) { var ret; if (a._type === 'list') ret = new pythonRuntime.objects.list(); else if (a._type === 'tuple') ret = new pythonRuntime.objects.tuple(); if (ret) { for (var i = 0; i < b; i++) for (var j = 0; j < a.length; j++) ret.push(a[j]); return ret; } } else if (pythonRuntime.internal.isSeq(b) && !isNaN(parseInt(a))) { var ret; if (b._type === 'list') ret = new pythonRuntime.objects.list(); else if (b._type === 'tuple') ret = new pythonRuntime.objects.tuple(); if (ret) { for (var i = 0; i < a; i++) for (var j = 0; j < b.length; j++) ret.push(b[j]); return ret; } } return a * b; }, subscriptIndex: function(o, i) { if (pythonRuntime.internal.isSeq(o) && i < 0) return o.length + i; if (pythonRuntime.internal.isJSArray(o) && i < 0) return o.length + i; if (typeof o === 'string' && i < 0) return o.length + i; return i; }, }, objects: { dict: function() { var obj = {}; for (var i in arguments) obj[arguments[i][0]] = arguments[i][1]; pythonRuntime.utils.convertToDict(obj); return obj; }, list: function() { var arr = []; arr.push.apply(arr, arguments); pythonRuntime.utils.convertToList(arr); return arr; }, tuple: function() { var arr = []; arr.push.apply(arr, arguments); Object.defineProperty(arr, '_type', { get: function() { return 'tuple'; }, enumerable: false, }); Object.defineProperty(arr, '_isPython', { get: function() { return true; }, enumerable: false, }); Object.defineProperty(arr, 'count', { value: function(x) { var c = 0; for (var i = 0; i < this.length; i++) if (this[i] === x) c++; return c; }, enumerable: false, }); Object.defineProperty(arr, 'equals', { value: function(x) { try { if (this.length !== x.length) return false; for (var i = 0; i < this.length; i++) { if (this[i].hasOwnProperty('equals')) { if (!this[i].equals(x[i])) return false; } else if (this[i] !== x[i]) return false; } return true; } catch (e) { } return false; }, enumerable: false, }); Object.defineProperty(arr, 'index', { value: function(x) { return this.indexOf(x); }, enumerable: false, }); Object.defineProperty(arr, 'indexOf', { value: function(x, fromIndex) { try { for (var i = fromIndex ? fromIndex : 0; i < this.length; i++) { if (this[i].hasOwnProperty('equals')) { if (this[i].equals(x)) return i; } else if (this[i] === x) return i; } } catch (e) { } return -1; }, enumerable: false, }); Object.defineProperty(arr, '_pySlice', { value: function(start, end, step) { return pythonRuntime.internal.slice(this, start, end, step); }, enumerable: false, }); Object.defineProperty(arr, 'toString', { value: function() { var s = '(' + this.join(', '); if (this.length === 1) s += ','; s += ')'; return s; }, enumerable: false, }); return arr; }, }, // Python built-in functions functions: { /* abs: function(x) { return Math.abs(x); }, all: function(iterable) { for (var i in iterable) if (pythonRuntime.functions.bool(iterable[i]) !== true) return false; return true; }, any: function(iterable) { for (var i in iterable) if (pythonRuntime.functions.bool(iterable[i]) === true) return true; return false; }, ascii: function(obj) { var s = pythonRuntime.functions.repr(obj), asc = "", code; for (var i = 0; i < s.length; i++) { code = s.charCodeAt(i); if (code <= 127) asc += s[i]; else if (code <= 0xFF) asc += "\\x" + code.toString(16); else if (0xD800 <= code && code <= 0xDBFF) { // UCS-2 for the astral chars // if (i+1 >= s.length) throw "High surrogate not followed by low surrogate"; // Is this needed? code = ((code-0xD800)*0x400)+(s.charCodeAt(++i)-0xDC00)+0x10000; asc += "\\U" + ("000"+code.toString(16)).slice(-8); } else if (code <= 0xFFFF) asc += "\\u" + ("0"+code.toString(16)).slice(-4); else if (code <= 0x10FFFF) asc += "\\U" + ("000"+code.toString(16)).slice(-8); else; // Invalid value, should probably throw something. It should never get here though as strings shouldn't contain them in the first place } return asc; }, bool: function(x) { return !(x === undefined || // No argument x === null || // None x === false || // False x === 0 || // Zero x.length === 0 || // Empty Sequence // TODO: Empty Mapping, needs more support for python mappings first (x.__bool__ !== undefined && x.__bool__() === false) || // If it has bool conversion defined (x.__len__ !== undefined && (x.__len__() === false || x.__len__() === 0))); // If it has length conversion defined }, chr: function(i) { return String.fromCharCode(i); // TODO: Error code for not 0 <= i <= 1114111 }, divmod: function(a, b) { return pythonRuntime.objects.tuple(Math.floor(a/b), a%b); }, enumerate: function(iterable, start) { start = start || 0; var ret = new pythonRuntime.objects.list(); for (var i in iterable) ret.push(new pythonRuntime.objects.tuple(start++, iterable[i])); return ret; }, filter: function(fn, iterable) { fn = fn || function () { return true; }; var ret = new pythonRuntime.objects.list(); for (var i in iterable) if (fn(iterable[i])) ret.push(iterable[i]); return ret; }, float: function(x) { if (x === undefined) return 0.0; else if (typeof x == "string") { // TODO: Fix type check x = x.trim().toLowerCase(); if ((/^[+-]?inf(inity)?$/i).exec(x) !== null) return Infinity*(x[0]==="-"?-1:1); else if ((/^nan$/i).exec(x) !== null) return NaN; else return parseFloat(x); } else if (typeof x == "number") { // TODO: Fix type check return x; // TODO: Get python types working right so we can return an actual float } else { if (x.__float__ !== undefined) return x.__float__(); else return null; // TODO: Throw TypeError: float() argument must be a string or a number, not '' } }, hex: function(x) { return x.toString(16); }, int: function (s) { return parseInt(s); }, len: function (o) { return o.length; }, list: function (iterable) { var ret = new pythonRuntime.objects.list(); if (iterable instanceof Array) for (var i in iterable) ret.push(iterable[i]); else for (var i in iterable) ret.push(i); return ret; }, map: function(fn, iterable) { // TODO: support additional iterables passed var ret = new pythonRuntime.objects.list(); for (var i in iterable) ret.push(fn(iterable[i])); return ret; }, max: function(arg1, arg2) { // TODO: support optional keyword-only arguments // TODO: empty iterable raises Python ValueError if (!arg2) { // iterable var max = null; for (var i in arg1) if (max === null || arg1[i] > max) max = arg1[i]; return max; } else return arg1 >= arg2 ? arg1 : arg2; }, min: function(arg1, arg2) { // TODO: support optional keyword-only arguments // TODO: empty iterable raises Python ValueError if (!arg2) { // iterable var max = null; for (var i in arg1) if (max === null || arg1[i] < max) max = arg1[i]; return max; } else return arg1 <= arg2 ? arg1 : arg2; }, oct: function(x) { return x.toString(8); }, ord: function(c) { return c.charCodeAt(0); }, pow: function(x, y, z) { return z ? Math.pow(x, y) % z : Math.pow(x, y); }, print: function () { var s = ""; for (var i = 0; i < arguments.length; i++) s += i === 0 ? arguments[i] : " " + arguments[i]; console.log(s); }, */ range: function(start, stop, step) { if (stop === undefined) { stop = start; start = 0; step = 1; } else if (step === undefined) step = 1; var r = new pythonRuntime.objects.list(); if (start < stop && step > 0 || start > stop && step < 0) { var i = start; while (i < stop && step > 0 || i > stop && step < 0) { r.append(i); i += step; } } return r; }, /* repr: function (obj) { if (typeof obj === 'string') return "'" + obj + "'"; // TODO: Patch until typesystem comes up. if (obj.__repr__ !== undefined) return obj.__repr__(); else if (obj.__class__ !== undefined && obj.__class__.module !== undefined && obj.__class__.__name__) { return '<'+obj.__class__.__module__+'.'+obj.__class__.__name__+' object>'; } else return obj.toString(); // Raise a please report warning here, we should never reach this piece of code }, reversed: function (seq) { var ret = new pythonRuntime.objects.list(); for (var i in seq) ret.push(seq[i]); return ret.reverse(); }, round: function (num, ndigits) { if (ndigits) { var scale = Math.pow(10, ndigits); return Math.round(num * scale) / scale; } return Math.round(num); }, sorted: function (iterable, key, reverse) { var ret = new pythonRuntime.objects.list(); for (var i in iterable) ret.push(iterable[i]); if(key) ret.sort(key); else ret.sort(); if (reverse) ret.reverse(); return ret; }, str: function (obj) { return obj.toString(); }, sum: function (iterable, start) { // TODO: start can't be a string var ret = start || 0; for (var i in iterable) ret += iterable[i]; return ret; }, tuple: function (iterable) { var ret = new pythonRuntime.objects.tuple(); for (var i in iterable) ret.push(iterable[i]); return ret; } */ }, // Python imports // TODO: from x import y, z imports: { random: { random: function() { return Math.random(); }, }, }, }; }); ================================================ FILE: extern/util/handle.js ================================================ /** * Resize handle on Easel.js */ 'use strict'; var EaselHandle = function(canvas) { if (typeof createjs != 'object') { throw 'createjs is not founded'; } this.canvas = canvas; this.color = '#c1c7cd'; //this.color = "#6BD5FF"; this.arrowColor = '#E79040'; this.centerColor = '#93440F'; this.rotateKnobColor = '#6B6B6B'; this.x = 0; this.y = 0; this.rotation = 0; this.direction = 0; this.width = 100; this.height = 100; this.flipX = false; this.flipY = false; this.visible = false; this.draggable = true; this.centerEditable = true; this.rotationEditable = true; this.directionEditable = true; this.resizeEnable = true; this.onChangeFunction = null; this.callerObject = null; this.createHandle(); this.render(); this.selectedObject = null; }; (function(p) { p.setChangeListener = function(object, func) { this.onChangeFunction = func; this.callerObject = object; return this; }; /** * for undo and redo */ p.setEditStartListener = function(object, func) { this.onEditStartFunction = func; this.editStartCallerObject = object; return this; }; p.setEditEndListener = function(object, func) { this.onEditEndFunction = func; this.editEndCallerObject = object; return this; }; p.toggleCenter = function(isEnable) { this.centerEditable = isEnable; this.centerPoint.visible = isEnable; }; p.toggleRotation = function(isEnable) { this.rotationEditable = isEnable; this.rotateKnob.visible = isEnable; }; p.toggleDirection = function(isEnable) { this.directionEditable = isEnable; this.directionArrow.visible = isEnable; }; p.toggleResize = function(isEnable) { this.resizeEditable = isEnable; for (var i = 0; i < 8; i++) { this.knobs[i].visible = isEnable; } }; p.toggleFont = function(isEnable) { this.fontEditable = isEnable; this.fontKnob.visible = isEnable; }; p.setX = function(xPos) { this.x = xPos; this.container.x = xPos; this.background.x = xPos; }; p.setY = function(yPos) { this.y = yPos; this.container.y = yPos; this.background.y = yPos; }; p.setWidth = function(width) { this.width = width; this.background.scaleX = width / 100; }; p.setHeight = function(height) { this.height = height; this.background.scaleY = height / 100; }; p.setRegX = function(regX) { this.regX = regX; this.centerPoint.x = regX; }; p.setRegY = function(regY) { this.regY = regY; this.centerPoint.y = regY; }; p.setRotation = function(rotation) { rotation = (rotation + 360) % 360; this.rotation = rotation; this.container.rotation = rotation; this.background.rotation = rotation; this.updateKnobCursor(); }; p.setDirection = function(direction) { direction = (direction + 360) % 360; this.direction = direction; this.directionArrow.rotation = direction; }; p.setVisible = function(visible) { this.visible = visible; this.container.visible = visible; this.background.visible = visible; }; p.setFont = function(fontSize) { this.font = fontSize; this.fontKnob.y = fontSize - this.height / 2; }; p.createHandle = function() { var handle = this; var container = new createjs.Container(); //border var border = new createjs.Shape(); container.addChild(border); this.border = border; //edge var edge = new createjs.Shape(); edge.cursor = 'move'; edge.on('mousedown', function(e) { var offset = handle.getEventCoordinate(e); offset.x -= handle.x; offset.y -= handle.y; this.offset = offset; handle.dispatchEditStartEvent(); }); edge.on('pressmove', function(e) { if (handle.getDraggable()) { var pos = handle.getEventCoordinate(e); pos.x -= this.offset.x; pos.y -= this.offset.y; handle.setX(pos.x); handle.setY(pos.y); handle.dispatchOnChangeEvent(); } }); edge.on('pressup', function(e) { handle.dispatchEditEndEvent(); }); container.addChild(edge); this.edge = edge; //rotate knob var rotateKnob = new createjs.Shape(); rotateKnob.cursor = 'crosshair'; rotateKnob.on('mousedown', function(e) { handle.dispatchEditStartEvent(); }); rotateKnob.on('pressmove', function(e) { var pos = handle.getEventCoordinate(e); pos.x -= handle.x; pos.y -= handle.y; var rotation = (-Math.atan2(pos.x, pos.y) / Math.PI) * 180 - 180; handle.setRotation(rotation); handle.dispatchOnChangeEvent(); }); rotateKnob.on('pressup', function(e) { handle.dispatchEditEndEvent(); }); container.addChild(rotateKnob); container.setChildIndex(rotateKnob, 1); this.rotateKnob = rotateKnob; var directionArrow = new createjs.Shape(); directionArrow.graphics .ss(4, 1, 1) .s(this.arrowColor) .f(this.arrowColor) .dc(0, 0, this.DHANDLE_RADIUS) .mt(0, 0) .lt(0, -40) .lt(7, -32) .lt(-7, -32) .lt(0, -40) .es(); directionArrow.on('mousedown', function(e) { handle.dispatchEditStartEvent(); }); directionArrow.on('pressmove', function(e) { var pos = handle.getLocalCoordinate(handle.getEventCoordinate(e)); var rotation = (-Math.atan2(pos.x, pos.y) / Math.PI) * 180 - 180; handle.setDirection(rotation); handle.dispatchOnChangeEvent(); }); directionArrow.on('pressup', function(e) { handle.dispatchEditEndEvent(); }); container.addChild(directionArrow); container.setChildIndex(directionArrow, 0); this.directionArrow = directionArrow; // center var centerPoint = new createjs.Shape(); centerPoint.graphics .beginFill(this.centerColor) .ss(1, 2, 0) .s(this.centerColor) .dc(0, 0, 5, 5); centerPoint.on('mousedown', function(e) { handle.dispatchEditStartEvent(); }); centerPoint.on('pressmove', function(e) { var pos = handle.getEventCoordinate(e); pos = handle.getLocalCoordinate(pos); handle.setRegX(pos.x); handle.setRegY(pos.y); handle.dispatchOnChangeEvent(); }); centerPoint.on('pressup', function(e) { handle.dispatchEditEndEvent(); }); container.addChild(centerPoint); this.centerPoint = centerPoint; //resize knobs this.knobs = []; for (var i = 0; i < 8; i++) { var knob = new createjs.Shape(); knob.graphics .beginFill(this.color) .ss(1, 2, 0) .s(this.color) .dr(-3, -3, 6, 6); knob.knobIndex = i; //knob.cursor = "move"; knob.on('mousedown', function(e) { var otherKnobIndex = this.knobIndex + 4 > 7 ? this.knobIndex + 4 - 8 : this.knobIndex + 4; var otherKnob = handle.knobs[otherKnobIndex]; var otherKnobPos = handle.getGlobalCoordinate(otherKnob); this.otherKnobPos = otherKnobPos; handle.dispatchEditStartEvent(); }); knob.on('pressmove', function(e) { var pos = handle.getEventCoordinate(e); if (handle.checkCenterPointState(handle.regX, handle.regY)) { handle.setRegX(0); handle.setRegY(0); handle.dispatchOnChangeEvent(); } handle.adjust(this.knobIndex, this.otherKnobPos, pos); }); knob.on('pressup', function(e) { handle.dispatchEditEndEvent(); }); container.addChild(knob); this.knobs.push(knob); } var background = new createjs.Shape(); background.graphics .ss(1, 2, 0) .s('rgba(254,254,254,0.01)') .beginFill('rgba(254,254,254,1)') .dr(-50, -50, 100, 100); background.on('mousedown', function(e) { var offset = handle.getEventCoordinate(e); offset.x -= handle.x; offset.y -= handle.y; this.offset = offset; handle.dispatchEditStartEvent(); }); background.on('pressmove', function(e) { if (handle.getDraggable()) { var pos = handle.getEventCoordinate(e); pos.x -= this.offset.x; pos.y -= this.offset.y; handle.setX(pos.x); handle.setY(pos.y); handle.dispatchOnChangeEvent(); } }); background.on('pressup', function(e) { handle.dispatchEditEndEvent(); }); this.canvas.addChildAt(background, 0); this.background = background; this.container = container; this.canvas.addChild(this.container); }; p.checkCenterPointState = function(x, y) { var standard = 718; var res = Math.sqrt(x * x + y * y); if (res > standard && Entry.engine.isState('stop')) { Entry.toast.warning( Lang.Workspace.toast_error_title_object_center, Lang.Workspace.toast_error_contents_object_center ); return true; } return false; }; p.render = function() { this.renderBorder(); this.renderEdge(); this.renderRotateKnob(); this.renderKnobs(); }; p.renderEdge = function() { var width = this.width; var height = this.height; this.edge.graphics .clear() .ss(10, 2, 0) .s('rgba(254,254,254,0.01)') .lt(-width / 2, -height / 2) .lt(0, -height / 2) .lt(0, -height / 2) .lt(+width / 2, -height / 2) .lt(+width / 2, +height / 2) .lt(-width / 2, +height / 2) .cp(); }; p.renderRotateKnob = function() { var width = this.width; var height = this.height; this.rotateKnob.graphics .clear() .ss(1, 2, 0) .s(this.rotateKnobColor) .mt(0, -height / 2) .lt(0, -height / 2) .lt(0, -height / 2 - 20) .cp() .beginFill(this.rotateKnobColor) .dc(0, -height / 2 - 20, 4); }; p.renderBorder = function() { var width = this.width; var height = this.height; this.border.graphics .clear() .ss(1, 2, 0) .s(this.color) .lt(-width / 2, -height / 2) .lt(0, -height / 2) .lt(0, -height / 2) .lt(+width / 2, -height / 2) .lt(+width / 2, +height / 2) .lt(-width / 2, +height / 2) .cp(); }; p.renderKnobs = function() { var width = this.width / 2; var height = this.height / 2; this.knobs.forEach(function(knob, i) { knob.x = Math.round(Math.sin((i / 4) * Math.PI)) * width; knob.y = Math.round(Math.cos((i / 4) * Math.PI)) * height; }); }; p.getEventCoordinate = function(e) { return { x: e.stageX * 0.75 - 240, y: e.stageY * 0.75 - 135, }; }; p.getGlobalCoordinate = function(childObject) { var container = this.container; var rotation = -((this.container.rotation * Math.PI) / 180); return { x: this.x + childObject.x * Math.cos(rotation) + childObject.y * Math.sin(rotation), y: this.y + childObject.y * Math.cos(rotation) - childObject.x * Math.sin(rotation), }; }; p.getLocalCoordinate = function(pos) { var container = this.container; var rotation = (this.container.rotation * Math.PI) / 180; pos.x -= this.x; pos.y -= this.y; return { x: pos.x * Math.cos(rotation) + pos.y * Math.sin(rotation), y: pos.y * Math.cos(rotation) - pos.x * Math.sin(rotation), }; }; p.adjust = function(knobIndex, otherKnobPos, pos) { var newPoint = this.calcPos({ x: this.x, y: this.y }, otherKnobPos, pos); var newCenter = { x: (otherKnobPos.x + newPoint.x) / 2, y: (otherKnobPos.y + newPoint.y) / 2, }; var newLength = Math.sqrt( Math.pow(newPoint.x - otherKnobPos.x, 2) + Math.pow(newPoint.y - otherKnobPos.y, 2) ); if (knobIndex % 4 == 0) { var ratio = newLength / this.height; this.height = newLength; this.setRegY(this.regY * ratio); } else if (knobIndex % 4 == 2) { var ratio = newLength / this.width; this.width = newLength; this.setRegX(this.regX * ratio); } else { var oldLength = 2 * Math.sqrt( Math.pow(this.x - otherKnobPos.x, 2) + Math.pow(this.y - otherKnobPos.y, 2) ); var newWidth = (this.width * newLength) / oldLength; var ratio = newWidth / this.width; this.setWidth(newWidth); this.setRegX(this.regX * ratio); var newHeight = (this.height * newLength) / oldLength; ratio = newHeight / this.height; this.setHeight((this.height * newLength) / oldLength); this.setRegY(this.regY * ratio); } this.setX(newCenter.x); this.setY(newCenter.y); this.render(); this.dispatchOnChangeEvent(); }; p.updateKnobCursor = function() { var rotation = this.rotation; var cursorList = ['ns-resize', 'nwse-resize', 'ew-resize', 'nesw-resize']; var iter = Math.round(rotation / 45); for (var i = 0; i < iter; i++) { cursorList.unshift(cursorList.pop()); } for (var i = 0; i < 8; i++) { this.knobs[i].cursor = cursorList[i % 4]; } }; p.calcPos = function(pos1, pos2, targetPos) { if (pos1.x == pos2.x) { return { x: pos1.x, y: targetPos.y, }; } else if (pos1.y == pos2.y) { return { x: targetPos.x, y: pos1.y, }; } else { var a = pos1.y - pos2.y; var b = pos2.x - pos1.x; var c = pos1.x * pos2.y - pos2.x * pos1.y; var k = -(a * targetPos.x + b * targetPos.y + c) / (a * a + b * b); return { x: targetPos.x + a * k, y: targetPos.y + b * k, }; } }; p.dispatchOnChangeEvent = function() { if (this.onChangeFunction) this.onChangeFunction.call(this.callerObject, this); }; p.dispatchEditStartEvent = function() { if (this.onEditStartFunction) this.onEditStartFunction.call(this.editStartCallerObject, this); }; p.dispatchEditEndEvent = function() { if (this.onEditEndFunction) this.onEditEndFunction.call(this.editEndCallerObject, this); }; p.setDraggable = function(bool) { this.draggable = bool; }; p.getDraggable = function() { return this.draggable; }; })(EaselHandle.prototype); ================================================ FILE: extern/util/ndgmr.Collision.js ================================================ /* The MIT License Copyright (c) 2012 Olaf Horstmann, indiegamr.com 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. */ /** * A Pixel Perfect Collision Detection for EaselJS Bitmap-Objects * @author olsn, indiegamr.com **/ this.ndgmr = this.ndgmr || {}; (function() { var threshold = 2; var collisionCanvas = document.createElement('canvas'); var collisionCtx = collisionCanvas.getContext('2d'); //collisionCtx.globalCompositeOperation = 'source-in'; collisionCtx.save(); var collisionCanvas2 = document.createElement('canvas'); var collisionCtx2 = collisionCanvas2.getContext('2d'); collisionCtx2.save(); var cachedBAFrames = []; var checkRectCollision = function(bitmap1,bitmap2) { var b1, b2; if (bitmap1 instanceof createjs.Container || bitmap2 instanceof createjs.Container) { b1 = bitmap1.getTransformedBounds(); b2 = bitmap2.getTransformedBounds(); } else { b1 = getBounds(bitmap1); b2 = getBounds(bitmap2); } if (Math.min(b1.width, b1.height, b2.width, b2.height) < 2) threshold = 1; else threshold = 1; return calculateIntersection(b1,b2); } ndgmr.checkRectCollision = checkRectCollision; var checkPixelCollision = function(bitmap1, bitmap2, alphaThreshold, getRect) { //display the intersecting canvases for debugging if ( ndgmr.DEBUG || ndgmr.DEBUG_COLLISION ) { document.body.appendChild(collisionCanvas); document.body.appendChild(collisionCanvas2); } getRect = getRect || false; var areObjectsCloseEnough, intersetion, imageData1, imageData2, pixelIntersection; areObjectsCloseEnough = _collisionDistancePrecheck(bitmap1,bitmap2); if ( !areObjectsCloseEnough ) { return false; } intersection = checkRectCollision(bitmap1,bitmap2); if ( !intersection ) { return false; } if (bitmap1 instanceof createjs.Container || bitmap2 instanceof createjs.Container) { return intersection; } if (intersection.width === 0 || intersection.height === 0) return false; //chrome float point number bug if (intersection.width/threshold < 1 || intersection.height/threshold < 1) return false; alphaThreshold = alphaThreshold || 0; alphaThreshold = Math.min(0.99999,alphaThreshold); //setting the canvas size collisionCanvas.width = intersection.width / threshold; collisionCanvas.height = intersection.height / threshold; collisionCanvas2.width = intersection.width / threshold; collisionCanvas2.height = intersection.height / threshold; imageData1 = _intersectingImagePart(intersection,bitmap1,collisionCtx,1); imageData2 = _intersectingImagePart(intersection,bitmap2,collisionCtx2,2); //compare the alpha values to the threshold and return the result // = true if pixels are both > alphaThreshold at one coordinate pixelIntersection = _compareAlphaValues(imageData1,imageData2,intersection.width / threshold,intersection.height,alphaThreshold / threshold, getRect); if ( pixelIntersection ) { pixelIntersection.x += intersection.x; pixelIntersection.x2 += intersection.x; pixelIntersection.y += intersection.y; pixelIntersection.y2 += intersection.y; } else { return false; } return pixelIntersection; } ndgmr.checkPixelCollision = checkPixelCollision; var _collisionDistancePrecheck = function(bitmap1,bitmap2) { var ir1, ir2; ir1 = bitmap1.getTransformedBounds(); ir2 = bitmap2.getTransformedBounds(); //precheck if objects are even close enough return ( Math.abs(ir2.x-ir1.x) < (ir1.x < ir2.x ? ir1.width : ir2.width) && Math.abs(ir2.y-ir1.y) < (ir1.y < ir2.y ? ir1.height : ir2.height )) } var _intersectingImagePart = function(intersetion,bitmap,ctx,i) { var bl, image, frameName, sr; if ( bitmap instanceof createjs.Bitmap ) { image = bitmap.image; } else if ( bitmap instanceof createjs.Sprite ) { frame = bitmap.spriteSheet.getFrame( bitmap.currentFrame ) frameName = frame.image.src + ':' + frame.rect.x + ':' + frame.rect.y + ':' + frame.rect.width + ':' + frame.rect.height;// + ':' + frame.rect.regX + ':' + frame.rect.regY if ( cachedBAFrames[frameName] ) { image = cachedBAFrames[frameName]; } else { cachedBAFrames[frameName] = image = createjs.SpriteSheetUtils.extractFrame(bitmap.spriteSheet,bitmap.currentFrame); } } bl = bitmap.globalToLocal(intersetion.x,intersetion.y); ctx.restore(); ctx.save(); //ctx.clearRect(0,0,intersetion.width,intersetion.height); ctx.rotate(_getParentalCumulatedProperty(bitmap,'rotation')*(Math.PI/181)); ctx.scale(_getParentalCumulatedProperty(bitmap,'scaleX','*') / threshold,_getParentalCumulatedProperty(bitmap,'scaleY','*') / threshold); ctx.translate((-bl.x-intersetion['rect'+i].regX) / threshold,( -bl.y-intersetion['rect'+i].regY) / threshold); if ( (sr = bitmap.sourceRect) != undefined ) { ctx.drawImage(image,sr.x,sr.y,sr.width,sr.height,0,0,sr.width,sr.height); } else { ctx.drawImage(image,0,0,image.width / threshold,image.height / threshold); } return ctx.getImageData(0, 0, intersetion.width / threshold, intersetion.height / threshold).data; } var _compareAlphaValues = function(imageData1,imageData2,width,height,alphaThreshold,getRect) { var alpha1, alpha2, x, y, offset = 3, pixelRect = {x:Infinity,y:Infinity,x2:-Infinity,y2:-Infinity}; // parsing through the pixels checking for an alpha match // TODO: intelligent parsing, not just from 0 to end! for ( y = 0; y < height; ++y) { for ( x = 0; x < width; ++x) { alpha1 = imageData1.length > offset+1 ? imageData1[offset] / 255 : 0; alpha2 = imageData2.length > offset+1 ? imageData2[offset] / 255 : 0; if ( alpha1 > alphaThreshold && alpha2 > alphaThreshold ) { if ( getRect ) { if ( x < pixelRect.x ) pixelRect.x = x; if ( x > pixelRect.x2 ) pixelRect.x2 = x; if ( y < pixelRect.y ) pixelRect.y = y; if ( y > pixelRect.y2 ) pixelRect.y2 = y; } else { return {x:x,y:y,width:1,height:1}; } } offset += 4; } } if ( pixelRect.x != Infinity ) { pixelRect.width = pixelRect.x2 - pixelRect.x + 1; pixelRect.height = pixelRect.y2 - pixelRect.y + 1; return pixelRect; } return null; } // this is needed to paint the intersection part correctly, // if the tested bitmap is a child to a rotated/scaled parent // this was not painted correctly before var _getParentalCumulatedProperty = function(child,propName,operation) { operation = operation || '+'; if ( child.parent && child.parent[propName] ) { var cp = child[propName]; var pp = _getParentalCumulatedProperty(child.parent,propName,operation); if ( operation == '*' ) { return cp * pp; } else { return cp + pp; } } return child[propName]; } var calculateIntersection = function(rect1, rect2) { // first we have to calculate the // center of each rectangle and half of // width and height var dx, dy, r1={}, r2={}; r1.cx = rect1.x + (r1.hw = (rect1.width /2)); r1.cy = rect1.y + (r1.hh = (rect1.height/2)); r2.cx = rect2.x + (r2.hw = (rect2.width /2)); r2.cy = rect2.y + (r2.hh = (rect2.height/2)); dx = Math.abs(r1.cx-r2.cx) - (r1.hw + r2.hw); dy = Math.abs(r1.cy-r2.cy) - (r1.hh + r2.hh); if (dx < 0 && dy < 0) { dx = Math.min(Math.min(rect1.width,rect2.width),-dx); dy = Math.min(Math.min(rect1.height,rect2.height),-dy); return {x:Math.max(rect1.x,rect2.x), y:Math.max(rect1.y,rect2.y), width:dx, height:dy, rect1: rect1, rect2: rect2}; } else { return null; } } ndgmr.calculateIntersection = calculateIntersection; var getBounds = function(obj) { var bounds={x:Infinity,y:Infinity,width:0,height:0}; if ( obj instanceof createjs.Container ) { bounds.x2 = -Infinity; bounds.y2 = -Infinity; var children = obj.children, l=children.length, cbounds, c; for ( c = 0; c < l; c++ ) { cbounds = getBounds(children[c]); if ( cbounds.x < bounds.x ) bounds.x = cbounds.x; if ( cbounds.y < bounds.y ) bounds.y = cbounds.y; if ( cbounds.x + cbounds.width > bounds.x2 ) bounds.x2 = cbounds.x + cbounds.width; if ( cbounds.y + cbounds.height > bounds.y2 ) bounds.y2 = cbounds.y + cbounds.height; //if ( cbounds.x - bounds.x + cbounds.width > bounds.width ) bounds.width = cbounds.x - bounds.x + cbounds.width; //if ( cbounds.y - bounds.y + cbounds.height > bounds.height ) bounds.height = cbounds.y - bounds.y + cbounds.height; } if ( bounds.x == Infinity ) bounds.x = 0; if ( bounds.y == Infinity ) bounds.y = 0; if ( bounds.x2 == Infinity ) bounds.x2 = 0; if ( bounds.y2 == Infinity ) bounds.y2 = 0; bounds.width = bounds.x2 - bounds.x; bounds.height = bounds.y2 - bounds.y; delete bounds.x2; delete bounds.y2; } else { var gp,gp2,gp3,gp4,imgr={},sr; if ( obj instanceof createjs.Bitmap ) { sr = obj.sourceRect || obj.image; imgr.width = sr.width; imgr.height = sr.height; } else if ( obj instanceof createjs.Sprite ) { if ( obj.spriteSheet._frames && obj.spriteSheet._frames[obj.currentFrame] && obj.spriteSheet._frames[obj.currentFrame].image ) { var cframe = obj.spriteSheet.getFrame(obj.currentFrame); imgr.width = cframe.rect.width; imgr.height = cframe.rect.height; imgr.regX = cframe.regX; imgr.regY = cframe.regY; } else { bounds.x = obj.x || 0; bounds.y = obj.y || 0; } } else { bounds.x = obj.x || 0; bounds.y = obj.y || 0; } imgr.regX = imgr.regX || 0; imgr.width = imgr.width || 0; imgr.regY = imgr.regY || 0; imgr.height = imgr.height || 0; bounds.regX = imgr.regX; bounds.regY = imgr.regY; gp = obj.localToGlobal(0 -imgr.regX,0 -imgr.regY); gp2 = obj.localToGlobal(imgr.width-imgr.regX,imgr.height-imgr.regY); gp3 = obj.localToGlobal(imgr.width-imgr.regX,0 -imgr.regY); gp4 = obj.localToGlobal(0 -imgr.regX,imgr.height-imgr.regY); bounds.x = Math.min(Math.min(Math.min(gp.x,gp2.x),gp3.x),gp4.x); bounds.y = Math.min(Math.min(Math.min(gp.y,gp2.y),gp3.y),gp4.y); bounds.width = Math.max(Math.max(Math.max(gp.x,gp2.x),gp3.x),gp4.x) - bounds.x; bounds.height = Math.max(Math.max(Math.max(gp.y,gp2.y),gp3.y),gp4.y) - bounds.y; } return bounds; } ndgmr.getBounds = getBounds; }()); ================================================ FILE: extern/util/static.js ================================================ 'use strict'; /* eslint-disable */ var EntryStatic = { fontFamily: "NanumGothic, 'Nanum Gothic'", fontOffsetY: -2.5, heightLetter: 'M', messageMaxLength: 10, }; EntryStatic.variableBlockList = [ 'get_variable', 'change_variable', 'set_variable', 'show_variable', 'hide_variable', 'value_of_index_from_list', 'add_value_to_list', 'remove_value_from_list', 'insert_value_to_list', 'change_value_list_index', 'length_of_list', 'is_included_in_list', 'show_list', 'hide_list', ]; EntryStatic.messageBlockList = ['when_message_cast', 'message_cast', 'message_cast_wait']; EntryStatic.getAllBlocks = function () { return [ { category: 'start', blocks: [ 'messageAddButton', 'when_run_button_click', 'when_some_key_pressed', 'mouse_clicked', 'mouse_click_cancled', 'when_object_click', 'when_object_click_canceled', 'when_message_cast', 'message_cast', 'message_cast_wait', 'when_scene_start', 'start_scene', 'start_neighbor_scene', 'check_object_property', 'check_block_execution', 'switch_scope', 'is_answer_submited', 'check_lecture_goal', 'check_variable_by_name', 'show_prompt', 'check_goal_success', 'positive_number', 'negative_number', 'wildcard_string', 'wildcard_boolean', 'register_score', ], }, { category: 'flow', blocks: [ 'wait_second', 'repeat_basic', 'repeat_inf', 'repeat_while_true', 'stop_repeat', 'continue_repeat', '_if', 'if_else', 'wait_until_true', 'stop_object', 'restart_project', 'when_clone_start', 'create_clone', 'delete_clone', 'remove_all_clones', ], }, { category: 'moving', blocks: [ 'move_direction', 'bounce_wall', 'move_x', 'move_y', 'move_xy_time', 'locate_x', 'locate_y', 'locate_xy', 'locate_xy_time', 'locate', 'locate_object_time', 'rotate_relative', 'direction_relative', 'rotate_by_time', 'direction_relative_duration', 'rotate_absolute', 'direction_absolute', 'see_angle_object', 'move_to_angle', ], }, { category: 'looks', blocks: [ 'show', 'hide', 'dialog_time', 'dialog', 'remove_dialog', 'change_to_some_shape', 'change_to_next_shape', 'add_effect_amount', 'change_effect_amount', 'erase_all_effects', 'change_scale_size', 'set_scale_size', 'stretch_scale_size', 'reset_scale_size', 'flip_x', 'flip_y', 'change_object_index', ], }, { category: 'brush', blocks: [ 'brush_stamp', 'start_drawing', 'stop_drawing', 'set_color', 'change_thickness', 'set_thickness', 'start_fill', 'stop_fill', 'set_fill_color', 'set_random_color', 'change_brush_transparency', 'set_brush_tranparency', 'brush_erase_all', ], }, { category: 'text', blocks: [ 'text_read', 'text_write', 'text_append', 'text_prepend', 'text_change_effect', 'text_change_font', 'text_change_font_color', 'text_change_bg_color', 'text_flush', ], }, { category: 'sound', blocks: [ 'sound_something_with_block', 'sound_something_second_with_block', 'sound_from_to', 'sound_something_wait_with_block', 'sound_something_second_wait_with_block', 'sound_from_to_and_wait', 'get_sound_duration', 'get_sound_volume', 'sound_volume_change', 'sound_volume_set', 'get_sound_speed', 'sound_speed_change', 'sound_speed_set', 'sound_silent_all', 'play_bgm', 'stop_bgm', ], }, { category: 'judgement', blocks: [ 'is_clicked', 'is_object_clicked', 'is_press_some_key', 'reach_something', 'is_type', 'boolean_basic_operator', 'boolean_and_or', 'boolean_not', 'is_boost_mode', 'is_current_device_type', 'is_touch_supported', ], }, { category: 'calc', blocks: [ 'calc_basic', 'calc_rand', 'coordinate_mouse', 'coordinate_object', 'quotient_and_mod', 'calc_operation', 'get_project_timer_value', 'choose_project_timer_action', 'set_visible_project_timer', 'get_date', 'distance_something', 'get_user_name', 'get_nickname', 'length_of_string', 'count_match_string', 'combine_something', 'char_at', 'substring', 'index_of_string', 'replace_string', 'reverse_of_string', 'change_string_case', 'get_block_count', 'change_rgb_to_hex', 'change_hex_to_rgb', 'get_boolean_value', ], }, { category: 'variable', blocks: [ 'variableAddButton', 'listAddButton', 'ask_and_wait', 'get_canvas_input_value', 'set_visible_answer', 'get_variable', 'change_variable', 'set_variable', 'show_variable', 'hide_variable', 'value_of_index_from_list', 'add_value_to_list', 'remove_value_from_list', 'insert_value_to_list', 'change_value_list_index', 'length_of_list', 'is_included_in_list', 'show_list', 'hide_list', ], }, { category: 'func', blocks: [ 'functionAddButton', 'function_name', 'showFunctionPropsButton', 'set_func_variable', 'get_func_variable', ], }, { category: 'analysis', blocks: [ 'analizyDataAddButton', 'append_row_to_table', 'insert_row_to_table', 'delete_row_from_table', 'set_value_from_table', 'save_current_table', 'get_table_count', 'get_value_from_table', 'get_value_from_last_row', 'calc_values_from_table', 'open_table', 'open_table_wait', 'open_table_chart', 'close_table_chart', 'get_coefficient', 'set_value_from_cell', 'get_value_from_cell', 'get_value_v_lookup', ], }, { category: 'ai_utilize', blocks: [ 'aiUtilizeBlockAddButton', 'aiUtilizeModelTrainButton', 'learning_title_image', 'learning_title_speech', 'learning_title_text', 'learning_title_number', 'learning_title_regression', 'learning_title_cluster', 'learning_title_logistic_regression', 'learning_title_decisiontree', 'learning_title_svm', 'retrain_model', 'model_is_trained', 'set_train_visible', 'set_train_chart', 'set_regression_option', 'get_regression_predict_1', 'get_regression_predict_2', 'get_regression_predict_3', 'get_regression_predict_4', 'get_regression_predict_5', 'get_regression_predict_6', 'get_regression_accuracy', 'set_logistic_regression_option', 'set_logistic_regression_optimizer', 'get_logistic_regression_probability_1', 'get_logistic_regression_probability_2', 'get_logistic_regression_probability_3', 'get_logistic_regression_probability_4', 'get_logistic_regression_probability_5', 'get_logistic_regression_probability_6', 'set_decisiontree_option', 'set_decisiontree_tree', 'set_svm_option', 'set_kernel_linear', 'set_kernel_option', 'is_result_1', 'is_result_2', 'is_result_3', 'is_result_4', 'is_result_5', 'is_result_6', 'get_predict_1', 'get_predict_2', 'get_predict_3', 'get_predict_4', 'get_predict_5', 'get_predict_6', 'get_result_info', 'set_cluster_option_k', 'set_cluster_option_centroids', 'get_cluster_centriod_count', 'get_cluster_centriod_value', 'get_cluster_centriod_index_1', 'get_cluster_centriod_index_2', 'get_cluster_centriod_index_3', 'get_cluster_centriod_index_4', 'get_cluster_centriod_index_5', 'get_cluster_centriod_index_6', 'set_number_learning_option_k', 'get_number_learning_predict_1', 'get_number_learning_predict_2', 'get_number_learning_predict_3', 'get_number_learning_predict_4', 'get_number_learning_predict_5', 'get_number_learning_predict_6', 'get_number_learning_predict_param_1', 'get_number_learning_predict_param_2', 'get_number_learning_predict_param_3', 'get_number_learning_predict_param_4', 'get_number_learning_predict_param_5', 'get_number_learning_predict_param_6', 'is_number_learning_group_1', 'is_number_learning_group_2', 'is_number_learning_group_3', 'is_number_learning_group_4', 'is_number_learning_group_5', 'is_number_learning_group_6', 'insert_data_for_test', 'video_capture_for_image_test', 'insert_text_block_for_test', 'test_result', 'accuracy_of_result', 'is_group', 'audio_title', 'check_microphone', 'get_microphone_volume', 'speech_to_text_title', 'speech_to_text_convert', 'timed_speech_to_text_convert', 'set_visible_speech_to_text', 'speech_to_text_get_value', 'tts_title', 'read_text', 'read_text_wait_with_block', 'set_tts_property', 'translate_title', 'get_translated_string', 'check_language', 'video_title', 'video_draw_webcam', 'video_change_cam', 'video_check_webcam', 'video_flip_camera', 'video_set_camera_opacity_option', 'video_motion_value', 'video_toggle_model', 'video_is_model_loaded', 'video_object_detected', 'video_number_detect', 'video_toggle_ind', 'video_body_part_coord', 'video_face_part_coord', 'video_detected_face_info', 'media_pipe_title', 'media_pipe_video_screen', 'media_pipe_switch_camera', 'check_connected_camera', 'media_pipe_flip_camera', 'media_pipe_set_opacity_camera', 'media_pipe_motion_value', 'hand_detection_title', 'when_hand_detection', 'hand_detection', 'draw_detected_hand', 'check_detected_hand', 'count_detected_hand', 'locate_to_hand', 'locate_time_to_hand', 'axis_detected_hand', 'is_which_hand', 'get_which_hand', 'is_which_gesture', 'get_which_gesture', 'pose_landmarker_title', 'when_pose_landmarker', 'pose_landmarker', 'draw_detected_pose', 'check_detected_pose', 'count_detected_pose', 'locate_to_pose', 'locate_time_to_pose', 'axis_detected_pose', 'face_landmarker_title', 'when_face_landmarker', 'face_landmarker', 'draw_detected_face', 'check_detected_face', 'count_detected_face', 'locate_to_face', 'locate_time_to_face', 'check_detected_gender', 'check_compare_age', 'check_detected_emotion', 'axis_detected_face', 'get_detected_face_value', 'object_detector_title', 'when_object_detector', 'object_detector', 'draw_detected_object', 'check_detected_object', 'count_detected_object', 'is_detected_among_objects', ], }, { category: 'expansion', blocks: [ 'expansionBlockAddButton', 'weather_title', 'get_cur_weather', 'get_cur_wind', 'get_cur_weather_data', 'check_cur_weather', 'check_cur_finddust', 'get_day_weather', 'get_day_weather_data', 'check_day_weather', 'get_time_weather', 'get_time_weather_data', 'check_time_weather', 'check_weather', 'check_finedust', 'get_weather_data', 'get_current_weather_data', 'get_today_temperature', 'check_city_weather', 'check_city_finedust', 'get_city_weather_data', 'get_current_city_weather_data', 'get_today_city_temperature', 'festival_title', 'count_festival', 'get_festival_info', 'emergencyActionGuidelines_title', 'count_disaster_guideline', 'get_disaster_guideline', 'count_social_disaster_guideline', 'get_social_disaster_guideline', 'count_safety_accident_guideline', 'get_safety_accident_guideline', 'disaster_alert_title', 'count_disaster_alert', 'get_disaster_alert', 'check_disaster_alert', ], }, { category: 'arduino', blocks: [ 'hardware_connect_helper', 'hardware_noti_installed', 'arduino_reconnect', 'arduino_open', 'hardware_program_download', 'arduino_cloud_pc_open', 'arduino_lite_disconnect', 'hardware_device_name_title', 'hardware_device_name_content', 'hardware_connected_noti', 'arduino_lite_connected_noti', 'arduino_lite_reconnect', 'hardware_noti_not_installed', 'arduino_lite_download_firmware', 'arduino_lite_connect', 'arduino_lite_guide', 'arduino_noti', 'arduino_lite_alert', ].concat(EntryStatic.DynamicHardwareBlocks), }, ]; }; /* eslint-disable */ Object.defineProperty(EntryStatic, 'fonts', { get: function () { return [ { name: Lang.Fonts.batang, family: 'KoPub Batang', url: '/css/kopubbatang.css', visible: false, }, { name: Lang.Fonts.jeju_hallasan, family: 'Jeju Hallasan', url: '/css/jejuhallasan.css', visible: false, }, { name: Lang.Fonts.gothic, family: 'Nanum Gothic', url: '/css/nanumgothic.css', visible: true, }, { name: Lang.Fonts.myeongjo, family: 'Nanum Myeongjo', url: '/css/nanummyeongjo.css', visible: true, }, { name: Lang.Fonts.nanumbarunpen, family: 'Nanum Barun Pen', url: '/css/nanumbarunpen.css', visible: true, }, { name: Lang.Fonts.pen_script, family: 'Nanum Pen Script', url: '/css/nanumpenscript.css', visible: true, }, { name: Lang.Fonts.square_round, family: 'NanumSquareRound', url: '/css/square_round.css', visible: true, }, { name: Lang.Fonts.maruburi, family: 'MaruBuri', url: '/css/maruburi.css', visible: true, }, { name: Lang.Fonts.notosans, family: 'NotoSans', url: '/css/notosans.css', visible: true, }, { name: Lang.Fonts.d2coding, family: 'D2 Coding', url: '/css/d2coding.css', visible: true, }, { name: Lang.Fonts.jalnan, family: 'yg-jalnan', url: '/css/jalnan.css', visible: true, }, { name: Lang.Fonts.designhouse, family: 'designhouseOTFLight00', url: '/css/designhouse.css', visible: true, }, { name: Lang.Fonts.dunggeunmo, family: 'DungGeunMo', url: '/css/dunggeunmo.css', visible: true, }, { name: Lang.Fonts.uhbeemysen, family: 'UhBeemysen', url: '/css/uhbeemysen.css', visible: true, }, { name: Lang.Fonts.sd_comic_stencil, family: 'SDComicStencil', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDComicStencil.css', visible: true, }, { name: Lang.Fonts.sd_childfundkorea, family: 'SDChildfundkorea', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDChildfundkorea.css', visible: true, }, { name: Lang.Fonts.sd_cinema_theater, family: 'SDCinemaTheater', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDCinemaTheater.css', visible: true, }, { name: Lang.Fonts.sd_mapssi, family: 'SDMapssi', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDMapssi.css', visible: true, }, { name: Lang.Fonts.sd_shabang, family: 'SDShabang', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDShabang.css', visible: true, }, { name: Lang.Fonts.sd_woodcarving, family: 'SDWoodcarving', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDWoodcarving.css', visible: true, }, { name: Lang.Fonts.sd_yongbi, family: 'SDYongbi', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDYongbi.css', visible: true, }, ]; }, }); EntryStatic.colorSet = { arrow: { default: { DEFAULT: '#FFFFFF', START: '#FFFFFF', FLOW: '#3A71BC', MOVING: '#8641B6', LOOKS: '#FFFFFF', TEXT: '#DC9C32', SOUND: '#83A617', JUDGE: '#89A1F7', CALC: '#E8B349', VARIABLE: '#CE38CE', HARDWARE: '#FFFFFF', EXPANSION: '#FF8888', AI_UTILIZE: '#FF8888', HIDDEN: '#FFFFFF', }, }, block: { default: { START: '#00b400', FLOW: '#19baea', MOVING: '#ad3efb', LOOKS: '#ff3a61', BRUSH: '#ff9b00', TEXT: '#e43500', SOUND: '#67b100', JUDGE: '#4562f5', CALC: '#f4af18', VARIABLE: '#dd47d8', ANALYSIS: '#25aeff', FUNC: '#de5c04', HARDWARE: '#00b6b1', EXPANSION: '#ef6d6d', AI_UTILIZE: '#8222ff', HIDDEN: '#8aa3b2', AI_LEARNING: '#8222ff', }, lighten: { START: '#3bce3b', FLOW: '#6dddfe', MOVING: '#bd65fb', LOOKS: '#ff5577', BRUSH: '#ffb250', TEXT: '#ff6739', SOUND: '#7ecc12', JUDGE: '#99adff', CALC: '#ffde82', VARIABLE: '#f778f3', ANALYSIS: '#d6e9f4', FUNC: '#ff7b22', HARDWARE: '#78d5d3', EXPANSION: '#ffaeae', AI_UTILIZE: '#ffaeae', HIDDEN: '#ffaeae', AI_LEARNING: '#8222ff', }, darken: { START: '#009400', FLOW: '#1498c0', MOVING: '#8b19db', LOOKS: '#c72042', BRUSH: '#fc6500', TEXT: '#ad2800', SOUND: '#508a00', JUDGE: '#1b3ad8', CALC: '#ff7f00', VARIABLE: '#b819b3', ANALYSIS: '#1592ff', FUNC: '#a14100', HARDWARE: '#008380', EXPANSION: '#c63f3f', AI_UTILIZE: '#670bdd', HIDDEN: '#728997', AI_LEARNING: '#670bdd', }, emphasize: { '#00b400': '#5BC982', //START '#19baea': '#62A5F4', //FLOW '#ad3efb': '#C08FF7', //MOVING '#ff3a61': '#F46487', //LOOKS '#fc7e01': '#FFB05A', //BRUSH '#e43500': '#F2C670', //TEXT '#67b100': '#C4DD31', //SOUND '#4562f5': '#C0CBFF', //JUDGE '#f4af18': '#FCDA90', //CALC '#dd47d8': '#F279F2', //VARIABLE '#de5c04': '#DD884E', //FUNC '#00b6b1': '#09BAB5', //HARDWARE //Not guided emphasize color for EXPANSION }, }, common: { WHITE: '#FFFFFF', DARK: '#000000', GRAY: '#6c8696', TRANSPARENT: 'transparent', BUTTON: '#4f80ff', BUTTON_BACKGROUND: '#eee', TEXT: '#333', BUTTON_BACKGROUND_DISABLED: '#f9f9f9', BUTTON_DISABLED: '#cbcbcb', ALERT: '#FB2729', }, }; EntryStatic.getDefaultFontFamily = function () { const localLang = Lang || {}; const type = localLang.type; const fallbackType = localLang.fallbackType; const langType = type || fallbackType || 'en'; switch (langType) { default: return "NanumGothic, 'Nanum Gothic', 나눔고딕, NanumGothicWeb, '맑은 고딕', 'Malgun Gothic', Dotum"; } }; EntryStatic.getCategoryByBlock = function (blockName) { if (!blockName) { return false; } const allBlocks = EntryStatic.getAllBlocks(); for (let i = 0, len = allBlocks.length; i < len; i++) { const blocks = allBlocks[i].blocks; if (blocks.indexOf(blockName) > -1) { return allBlocks[i].category; } } return false; }; // for server node js code if (typeof exports === 'object') { exports.blockInfo = EntryStatic.blockInfo; exports.getAllBlocks = EntryStatic.getAllBlocks; exports.getCategoryByBlock = EntryStatic.getCategoryByBlock; exports.EntryStatic = EntryStatic; } ================================================ FILE: extern/util/static_mini.js ================================================ 'use strict'; /* eslint-disable */ var EntryStatic = { isPracticalCourse: true, fontFamily: "NanumGothic, 'Nanum Gothic'", exportBlockFontFamily: "NanumGothic, 'Nanum Gothic', 'NanumGothic', '나눔고딕','NanumGothicWeb', '맑은 고딕', 'Malgun Gothic', Dotum", fontOffsetY: -2.5, heightLetter: 'M', objectTypes: ['sprite', 'textBox'], }; EntryStatic.usageList = [ 'usage_event', 'usage_signal', 'usage_scene', 'usage_repeat', 'usage_condition_repeat', 'usage_condition', 'usage_clone', 'usage_arrow_move', 'usage_rotation', 'usage_coordinate', 'usage_shape', 'usage_speak', 'usage_picture_effect', 'usage_textBox', 'usage_draw', 'usage_sound', 'usage_confirm', 'usage_comp_operation', 'usage_logical_operation', 'usage_math_operation', 'usage_random', 'usage_timer', 'usage_variable', 'usage_list', 'usage_ask_answer', 'usage_function', 'usage_arduino', ]; EntryStatic.conceptList = [ 'concept_resource_analytics', 'concept_individual', 'concept_abstractive', 'concept_procedual', 'concept_automation', 'concept_simulation', 'concept_parallel', ]; EntryStatic.subjectList = [ 'subject_korean', 'subject_mathmatics', 'subject_social', 'subject_science', 'subject_english', 'subject_courtesy', 'subject_music', 'subject_paint', 'subject_athletic', 'subject_progmatic', ]; EntryStatic.lectureLevels = [1, 2, 3]; // EntryStatic.lectureLevels = ['level_high', 'level_mid','level_row']; EntryStatic.lectureGrades = [ 'e_1', 'e_2', 'e_3', 'e_4', 'e_5', 'e_6', 'm_1', 'm_2', 'm_3', 'general', ]; EntryStatic.categoryList = [ 'category_game', 'category_animation', 'category_media_art', 'category_physical', 'category_etc', ]; EntryStatic.requiredTimes = [1, 2, 3, 4, 5]; EntryStatic.searchProjectOption = [ { key: 'search_updated', lang: 'search_updated', value: 'updated', }, { key: 'search_recent', lang: 'search_recent', value: 'recent', }, { key: 'search_complexity', lang: 'search_complexity', value: 'complexity', }, { key: 'search_staffPicked', lang: 'search_staffPicked', value: 'staffPicked', }, { key: 'search_childCnt', lang: 'search_childCnt', value: 'childCnt', }, { key: 'search_likeCnt', lang: 'search_likeCnt', value: 'recentLikeCnt', }, ]; EntryStatic.variableBlockList = [ 'get_variable', 'change_variable', 'set_variable', 'show_variable', 'hide_variable', ]; EntryStatic.messageBlockList = ['when_message_cast', 'message_cast', 'message_cast_wait']; EntryStatic.getAllBlocks = function () { return [ { category: 'start', blocks: [ 'when_run_button_click', 'when_some_key_pressed', 'mouse_clicked', 'mouse_click_cancled', 'when_object_click', 'when_object_click_canceled', 'when_message_cast', 'message_cast', 'message_cast_wait', ], }, { category: 'flow', blocks: [ 'wait_second', 'repeat_basic', 'repeat_inf', 'repeat_while_true', 'stop_repeat', 'continue_repeat', '_if', 'if_else', 'wait_until_true', 'stop_object', ], }, { category: 'moving', blocks: [ 'move_direction', 'bounce_wall', 'move_x', 'move_y', 'move_xy_time', 'locate_xy', 'locate_xy_time', 'locate', 'locate_object_time', 'rotate_relative', 'direction_relative', 'rotate_absolute', 'direction_absolute', 'see_angle_object', ], }, { category: 'looks', blocks: [ 'show', 'hide', 'dialog_time', 'dialog', 'change_to_some_shape', 'change_to_next_shape', 'add_effect_amount', 'change_effect_amount', 'erase_all_effects', 'change_scale_size', 'set_scale_size', 'change_object_index', ], }, { category: 'brush', blocks: [ 'brush_stamp', 'start_drawing', 'stop_drawing', 'set_color', 'change_thickness', 'set_thickness', 'brush_erase_all', ], }, { category: 'text', blocks: [ 'text_write', 'text_append', 'text_prepend', 'text_change_effect', 'text_change_font', 'text_change_font_color', 'text_change_bg_color', 'text_flush', ], }, { category: 'sound', blocks: [ 'sound_something_with_block', 'sound_something_wait_with_block', 'sound_volume_change', 'sound_volume_set', ], }, { category: 'judgement', blocks: [ 'is_clicked', 'is_press_some_key', 'reach_something', 'boolean_basic_operator', 'boolean_and_or', 'boolean_not', ], }, { category: 'calc', blocks: [ 'calc_basic', 'calc_rand', 'coordinate_object', 'quotient_and_mod', 'calc_operation', 'get_project_timer_value', 'choose_project_timer_action', 'set_visible_project_timer', 'length_of_string', 'combine_something', 'char_at', 'substring', 'replace_string', ], }, { category: 'variable', blocks: [ 'variableAddButton', 'ask_and_wait', 'get_canvas_input_value', 'set_visible_answer', 'get_variable', 'change_variable', 'set_variable', 'show_variable', 'hide_variable', ], }, { category: 'ai_utilize', blocks: [ 'aiUtilizeBlockAddButton', 'aiUtilizeModelTrainButton', 'learning_title_image', 'learning_title_speech', 'learning_title_text', 'learning_title_number', 'learning_title_regression', 'learning_title_cluster', 'learning_title_logistic_regression', 'learning_title_decisiontree', 'learning_title_svm', 'retrain_model', 'model_is_trained', 'set_train_visible', 'set_train_chart', 'set_regression_option', 'get_regression_predict_1', 'get_regression_predict_2', 'get_regression_predict_3', 'get_regression_predict_4', 'get_regression_predict_5', 'get_regression_predict_6', 'get_regression_accuracy', 'set_logistic_regression_option', 'set_logistic_regression_optimizer', 'get_logistic_regression_probability_1', 'get_logistic_regression_probability_2', 'get_logistic_regression_probability_3', 'get_logistic_regression_probability_4', 'get_logistic_regression_probability_5', 'get_logistic_regression_probability_6', 'set_decisiontree_option', 'set_decisiontree_tree', 'set_svm_option', 'set_kernel_linear', 'set_kernel_option', 'is_result_1', 'is_result_2', 'is_result_3', 'is_result_4', 'is_result_5', 'is_result_6', 'get_predict_1', 'get_predict_2', 'get_predict_3', 'get_predict_4', 'get_predict_5', 'get_predict_6', 'get_result_info', 'set_cluster_option_k', 'set_cluster_option_centroids', 'get_cluster_centriod_count', 'get_cluster_centriod_value', 'get_cluster_centriod_index_1', 'get_cluster_centriod_index_2', 'get_cluster_centriod_index_3', 'get_cluster_centriod_index_4', 'get_cluster_centriod_index_5', 'get_cluster_centriod_index_6', 'set_number_learning_option_k', 'get_number_learning_predict_1', 'get_number_learning_predict_2', 'get_number_learning_predict_3', 'get_number_learning_predict_4', 'get_number_learning_predict_5', 'get_number_learning_predict_6', 'get_number_learning_predict_param_1', 'get_number_learning_predict_param_2', 'get_number_learning_predict_param_3', 'get_number_learning_predict_param_4', 'get_number_learning_predict_param_5', 'get_number_learning_predict_param_6', 'is_number_learning_group_1', 'is_number_learning_group_2', 'is_number_learning_group_3', 'is_number_learning_group_4', 'is_number_learning_group_5', 'is_number_learning_group_6', 'insert_data_for_test', 'video_capture_for_image_test', 'insert_text_block_for_test', 'test_result', 'accuracy_of_result', 'is_group', 'audio_title', 'check_microphone', 'get_microphone_volume', 'speech_to_text_title', 'speech_to_text_convert', 'timed_speech_to_text_convert', 'set_visible_speech_to_text', 'speech_to_text_get_value', 'tts_title', 'read_text', 'read_text_wait_with_block', 'set_tts_property', 'translate_title', 'get_translated_string', 'check_language', 'video_title', 'video_draw_webcam', 'video_change_cam', 'video_check_webcam', 'video_flip_camera', 'video_set_camera_opacity_option', 'video_motion_value', 'video_toggle_model', 'video_is_model_loaded', 'video_object_detected', 'video_number_detect', 'video_toggle_ind', 'video_body_part_coord', 'video_face_part_coord', 'video_detected_face_info', 'media_pipe_title', 'media_pipe_video_screen', 'media_pipe_switch_camera', 'check_connected_camera', 'media_pipe_flip_camera', 'media_pipe_set_opacity_camera', 'media_pipe_motion_value', 'hand_detection_title', 'when_hand_detection', 'hand_detection', 'draw_detected_hand', 'check_detected_hand', 'count_detected_hand', 'locate_to_hand', 'locate_time_to_hand', 'axis_detected_hand', 'is_which_hand', 'get_which_hand', 'is_which_gesture', 'get_which_gesture', 'pose_landmarker_title', 'when_pose_landmarker', 'pose_landmarker', 'draw_detected_pose', 'check_detected_pose', 'count_detected_pose', 'locate_to_pose', 'locate_time_to_pose', 'axis_detected_pose', 'face_landmarker_title', 'when_face_landmarker', 'face_landmarker', 'draw_detected_face', 'check_detected_face', 'count_detected_face', 'locate_to_face', 'locate_time_to_face', 'check_detected_gender', 'check_compare_age', 'check_detected_emotion', 'axis_detected_face', 'get_detected_face_value', 'object_detector_title', 'when_object_detector', 'object_detector', 'draw_detected_object', 'check_detected_object', 'count_detected_object', 'is_detected_among_objects', ], }, { category: 'hw_sensor', visible: false, blocks: [ 'practical_course_dummy', 'hardware_device_name_title_sensor', 'hardware_device_name_content_sensor', ].concat(EntryStatic.DynamicPracticalHardwareBlocks['hw_sensor']), }, { category: 'hw_motor', visible: false, blocks: [ 'practical_course_dummy', 'hardware_device_name_title_motor', 'hardware_device_name_content_motor', ].concat(EntryStatic.DynamicPracticalHardwareBlocks['hw_motor']), }, { category: 'hw_led', visible: false, blocks: [ 'practical_course_dummy', 'hardware_device_name_title_led', 'hardware_device_name_content_led', ].concat(EntryStatic.DynamicPracticalHardwareBlocks['hw_led']), }, { category: 'hw_melody', visible: false, blocks: [ 'practical_course_dummy', 'hardware_device_name_title_melody', 'hardware_device_name_content_melody', ].concat(EntryStatic.DynamicPracticalHardwareBlocks['hw_melody']), }, { category: 'hw_robot', blocks: [ 'robot_connect_helper', 'robot_reconnect', 'arduino_open', 'arduino_connect', 'hardware_program_download', 'arduino_connected', 'hardware_device_name_title_robot', 'hardware_device_name_content', 'hardware_connected_noti', 'robot_noti', ], }, { category: 'arduino', visible: false, blocks: EntryStatic.DynamicHardwareBlocks, }, ]; }; EntryStatic.DynamicHardwareBlocks = []; EntryStatic.discussCategories = [ // 'notice', 'qna', 'tips', 'free', 'report', 'notice', ]; EntryStatic.artCategories = [ { key: 'art_category_', lang: 'art_category_all', value: '', }, { key: 'art_category_게임', lang: 'art_category_game', value: '게임', }, { key: 'art_category_애니메이션', lang: 'art_category_animation', value: '애니메이션', }, { key: 'art_category_미디어아트', lang: 'art_category_media', value: '미디어아트', }, { key: 'art_category_피지컬', lang: 'art_category_physical', value: '피지컬', }, { key: 'art_category_기타', lang: 'art_category_etc', value: '기타', }, ]; EntryStatic.artSortOptions = [ { key: 'art_sort_updated', lang: 'art_sort_updated', value: 'updated', }, { key: 'art_sort_visit', lang: 'art_sort_visit', value: 'visit', }, { key: 'art_sort_likeCnt', lang: 'art_sort_likeCnt', value: 'likeCnt', }, { key: 'art_sort_comment', lang: 'art_sort_comment', value: 'comment', }, ]; EntryStatic.discussSortOptions = [ { lang: 'discuss_sort_created', value: 'created', }, { lang: 'discuss_sort_visit', value: 'visit', }, { lang: 'discuss_sort_likesLength', value: 'likesLength', }, { lang: 'discuss_sort_commentsLength', value: 'commentsLength', }, ]; EntryStatic.discussPeriodOptions = [ { key: 'discuss_period_', lang: 'discuss_period_all', value: '', }, { key: 'discuss_period_1', lang: 'discuss_period_day', value: '1', }, { key: 'discuss_period_7', lang: 'discuss_period_week', value: '7', }, { key: 'discuss_period_30', lang: 'discuss_period_month', value: '30', }, { key: 'discuss_period_90', lang: 'discuss_period_three_month', value: '90', }, ]; EntryStatic.artPeriodOptions = [ { key: 'art_period_', lang: 'art_period_all', value: '', }, { key: 'art_period_1', lang: 'art_period_day', value: '1', }, { key: 'art_period_7', lang: 'art_period_week', value: '7', }, { key: 'art_period_30', lang: 'art_period_month', value: '30', }, { key: 'art_period_90', lang: 'art_period_three_month', value: '90', }, ]; EntryStatic.getCategoryByBlock = function (blockName) { if (!blockName) { return false; } let allBlocks = EntryStatic.getAllBlocks(); for (let i = 0, len = allBlocks.length; i < len; i++) { let blocks = allBlocks[i].blocks; if (blocks.indexOf(blockName) > -1) { return allBlocks[i].category; } } return false; }; EntryStatic.objectMainCategories = [ 'entrybot_friends', 'people', 'animal', 'plant', 'vehicles', 'architect', 'food', 'environment', 'stuff', 'fantasy', 'interface', 'background', ]; EntryStatic.objectSubCategories = { entrybot_friends: [], people: [], animal: ['animal_flying', 'animal_land', 'animal_water', 'animal_others'], plant: ['plant_flower', 'plant_grass', 'plant_tree', 'plant_others'], vehicles: ['vehicles_flying', 'vehicles_land', 'vehicles_water', 'vehicles_others'], architect: ['architect_building', 'architect_monument', 'architect_others'], food: ['food_vegetables', 'food_meat', 'food_drink', 'food_others'], environment: ['environment_nature', 'environment_space', 'environment_others'], stuff: ['stuff_living', 'stuff_hobby', 'stuff_others'], fantasy: [], interface: ['interface_website', 'interface_game', 'interface_others'], background: [ 'background_outdoor', 'background_indoor', 'background_nature', 'background_others', ], }; EntryStatic.fonts = [ { name: Lang.Fonts.batang, family: 'KoPub Batang', url: '/css/kopubbatang.css', visible: false, }, { name: Lang.Fonts.jeju_hallasan, family: 'Jeju Hallasan', url: '/css/jejuhallasan.css', visible: false, }, { name: Lang.Fonts.gothic, family: 'Nanum Gothic', url: '/css/nanumgothic.css', visible: true, }, { name: Lang.Fonts.myeongjo, family: 'Nanum Myeongjo', url: '/css/nanummyeongjo.css', visible: true, }, { name: Lang.Fonts.nanumbarunpen, family: 'Nanum Barun Pen', url: '/css/nanumbarunpen.css', visible: true, }, { name: Lang.Fonts.pen_script, family: 'Nanum Pen Script', url: '/css/nanumpenscript.css', visible: true, }, { name: Lang.Fonts.square_round, family: 'NanumSquareRound', url: '/css/square_round.css', visible: true, }, { name: Lang.Fonts.maruburi, family: 'MaruBuri', url: '/css/maruburi.css', visible: true, }, { name: Lang.Fonts.notosans, family: 'NotoSans', url: '/css/notosans.css', visible: true, }, { name: Lang.Fonts.d2coding, family: 'D2 Coding', url: '/css/d2coding.css', visible: true, }, { name: Lang.Fonts.jalnan, family: 'yg-jalnan', url: '/css/jalnan.css', visible: true, }, { name: Lang.Fonts.designhouse, family: 'designhouseOTFLight00', url: '/css/designhouse.css', visible: true, }, { name: Lang.Fonts.dunggeunmo, family: 'DungGeunMo', url: '/css/dunggeunmo.css', visible: true, }, { name: Lang.Fonts.uhbeemysen, family: 'UhBeemysen', url: '/css/uhbeemysen.css', visible: true, }, { name: Lang.Fonts.sd_comic_stencil, family: 'SDComicStencil', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDComicStencil.css', visible: true, }, { name: Lang.Fonts.sd_childfundkorea, family: 'SDChildfundkorea', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDChildfundkorea.css', visible: true, }, { name: Lang.Fonts.sd_cinema_theater, family: 'SDCinemaTheater', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDCinemaTheater.css', visible: true, }, { name: Lang.Fonts.sd_mapssi, family: 'SDMapssi', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDMapssi.css', visible: true, }, { name: Lang.Fonts.sd_shabang, family: 'SDShabang', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDShabang.css', visible: true, }, { name: Lang.Fonts.sd_woodcarving, family: 'SDWoodcarving', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDWoodcarving.css', visible: true, }, { name: Lang.Fonts.sd_yongbi, family: 'SDYongbi', style: { backgroundColor: '#f7fcff', padding: '17px 22px 14px 16px', margin: '0px', borderTop: 'solid 1px #d6e9f4', }, url: '/css/SDYongbi.css', visible: true, }, ]; EntryStatic.colorSet = { arrow: { default: { DEFAULT: '#FFFFFF', START: '#FFFFFF', FLOW: '#3A71BC', MOVING: '#8641B6', LOOKS: '#FFFFFF', TEXT: '#DC9C32', SOUND: '#83A617', JUDGE: '#89A1F7', CALC: '#E8B349', VARIABLE: '#CE38CE', HARDWARE: '#FFFFFF', EXPANSION: '#FF8888', AI_UTILIZE: '#FF8888', }, }, block: { default: { START: '#00b400', FLOW: '#19baea', MOVING: '#ad3efb', LOOKS: '#ff3a61', BRUSH: '#ff9b00', TEXT: '#e43500', SOUND: '#67b100', JUDGE: '#4562f5', CALC: '#f4af18', VARIABLE: '#dd47d8', ANALYSIS: '#25aeff', FUNC: '#de5c04', HARDWARE: '#00b6b1', EXPANSION: '#ef6d6d', AI_UTILIZE: '#8222ff', HIDDEN: '#8aa3b2', AI_LEARNING: '#8222ff', }, lighten: { START: '#3bce3b', FLOW: '#6dddfe', MOVING: '#bd65fb', LOOKS: '#ff5577', BRUSH: '#ffb250', TEXT: '#ff6739', SOUND: '#7ecc12', JUDGE: '#99adff', CALC: '#ffde82', VARIABLE: '#f778f3', ANALYSIS: '#d6e9f4', FUNC: '#ff7b22', HARDWARE: '#78d5d3', EXPANSION: '#ffaeae', AI_UTILIZE: '#ffaeae', HIDDEN: '#ffaeae', AI_LEARNING: '#8222ff', }, darken: { START: '#009400', FLOW: '#1498c0', MOVING: '#8b19db', LOOKS: '#c72042', BRUSH: '#fc6500', TEXT: '#ad2800', SOUND: '#508a00', JUDGE: '#1b3ad8', CALC: '#ff7f00', VARIABLE: '#b819b3', ANALYSIS: '#1592ff', FUNC: '#a14100', HARDWARE: '#008380', EXPANSION: '#c63f3f', AI_UTILIZE: '#670bdd', HIDDEN: '#728997', AI_LEARNING: '#670bdd', }, emphasize: { '#00b400': '#5BC982', //START '#19baea': '#62A5F4', //FLOW '#ad3efb': '#C08FF7', //MOVING '#ff3a61': '#F46487', //LOOKS '#fc7e01': '#FFB05A', //BRUSH '#e43500': '#F2C670', //TEXT '#67b100': '#C4DD31', //SOUND '#4562f5': '#C0CBFF', //JUDGE '#f4af18': '#FCDA90', //CALC '#dd47d8': '#F279F2', //VARIABLE '#de5c04': '#DD884E', //FUNC '#00b6b1': '#09BAB5', //HARDWARE //Not guided emphasize color for EXPANSION }, }, common: { WHITE: '#FFFFFF', DARK: '#000000', GRAY: '#6c8696', TRANSPARENT: 'transparent', BUTTON: '#4f80ff', BUTTON_BACKGROUND: '#eee', TEXT: '#333', ALERT: '#FB2729', }, }; EntryStatic.initOptions = { listEnable: false, functionEnable: false, sceneEditable: false, }; EntryStatic.hwCategoryList = ['hw_sensor', 'hw_motor', 'hw_led', 'hw_melody']; EntryStatic.DynamicPracticalHardwareBlocks = {}; EntryStatic.hwCategoryList.forEach((category) => { EntryStatic.DynamicPracticalHardwareBlocks[category] = []; }); EntryStatic.hwMiniSupportList = [ 'neobot', 'roborobo_schoolkit', 'robotis_openCM70', 'robotis_openCM70EDU', 'robotis_Dream', ]; EntryStatic.COMMAND_TYPES = { addThread: 101, destroyThread: 102, destroyBlock: 103, recoverBlock: 104, insertBlock: 105, separateBlock: 106, moveBlock: 107, cloneBlock: 108, uncloneBlock: 109, scrollBoard: 110, setFieldValue: 111, selectObject: 201, do: 301, undo: 302, redo: 303, }; EntryStatic.getDefaultFontFamily = function () { const localLang = Lang || {}; const type = localLang.type; const fallbackType = localLang.fallbackType; const langType = type || fallbackType || 'en'; switch (langType) { default: return "NanumGothic, 'Nanum Gothic', 나눔고딕, NanumGothicWeb, '맑은 고딕', 'Malgun Gothic', Dotum"; } }; // for server node js code if (typeof exports == 'object') { exports.blockInfo = EntryStatic.blockInfo; exports.getAllBlocks = EntryStatic.getAllBlocks; exports.getCategoryByBlock = EntryStatic.getCategoryByBlock; exports.EntryStatic = EntryStatic; } ================================================ FILE: extern/vision.worker.js ================================================ self.importScripts(`${self.location.pathname}/../vision_bundle.js`); self.onmessage = async ({ data }) => { if (data.action === 'pose_landmarker_init') { initializePoseLandmarker(data); } else if (data.action === 'gesture_recognizer_change_option') { changeGestureOption(data.option); } else if (data.action === 'pose_landmarker') { predictPoseLandmarker(data.imageBitmap); } else if (data.action === 'clear_pose_landmarker') { clearPredictPoseLandmarker(); } }; let workerContext; let drawingUtils; let gestureRecognizer; let poseLandmarker; let isPrevHandDetected = false; let isPrevPoseLandmarker = false; let countDetectedHand = 0; let isDrawDetectedHand = false; let isDrawDetectedPoseLandmarker = false; const initializePoseLandmarker = async (data) => { const { canvas } = data; isDrawDetectedPoseLandmarker = data.isDrawDetectedPoseLandmarker; workerContext = canvas.getContext('2d'); workerContext.font = '20px Arial'; drawingUtils = new DrawingUtils(workerContext); const vision = await FilesetResolver.forVisionTasks(`${self.location.pathname}/../wasm`); poseLandmarker = await PoseLandmarker.createFromOptions(vision, { baseOptions: { modelAssetPath: `${self.location.pathname}/../model/pose_landmarker_lite.task`, delegate: 'GPU', }, runningMode: 'VIDEO', numPoses: 1, }); self.postMessage({ action: 'next_pose_landmarker' }); }; const YX = (a) => { return Math.max(1, Math.min(10, 10 * (1 - (a - -0.15) / 0.25) + (1 - (0.1 - a) / 0.25))); }; const predictPoseLandmarker = async (imageBitmap) => { try { if (!workerContext || !poseLandmarker) { return; } const startTimeMs = performance.now(); const results = await poseLandmarker.detectForVideo(imageBitmap, startTimeMs); workerContext.save(); workerContext.clearRect(0, 0, 640, 360); const { landmarks } = results; self.postMessage({ action: 'pose_landmaker_data', poseLandmarkerResult: results, }); if (landmarks.length) { if (!isPrevPoseLandmarker) { isPrevPoseLandmarker = true; self.postMessage({ action: 'start_pose_landmarker' }); } // if (landmarks.length !== countDetectedHand) { // countDetectedHand = landmarks.length; // self.postMessage({ // action: 'count_detected_hand_gesture_recognizer', // count: countDetectedHand, // }); // } // if (!isDrawDetectedPoseLandmarker) { // return; // } landmarks.forEach((landmark, i) => { drawingUtils.drawLandmarks(landmark, { radius: (data) => DrawingUtils.lerp(data.from.z, -0.15, 0.1, 5, 1), }); drawingUtils.drawConnectors(landmark, PoseLandmarker.POSE_CONNECTIONS); }); } else if (isPrevPoseLandmarker) { isPrevPoseLandmarker = false; // countDetectedHand = 0; self.postMessage({ action: 'stop_pose_landmarker' }); } } catch (e) { console.error(e); } finally { workerContext.restore(); requestAnimationFrame(() => { self.postMessage({ action: 'next_pose_landmarker' }); }); } }; const clearPredictPoseLandmarker = () => { console.log('clearPredictPoseLandmarker'); workerContext.clearRect(0, 0, 640, 360); }; ================================================ FILE: extern/vision_bundle.js ================================================ var commonjsGlobal = 'undefined' != typeof globalThis ? globalThis : 'undefined' != typeof window ? window : 'undefined' != typeof global ? global : 'undefined' != typeof self ? self : {}, vision = {}, fileset_resolver = {}; let supportsSimd; Object.defineProperty(fileset_resolver, '__esModule', { value: !0 }), (fileset_resolver.FilesetResolver = void 0); const WASM_SIMD_CHECK = new Uint8Array([ 0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 123, 3, 2, 1, 0, 10, 10, 1, 8, 0, 65, 0, 253, 15, 253, 98, 11, ]); async function isSimdSupported() { if (void 0 === supportsSimd) try { await WebAssembly.instantiate(WASM_SIMD_CHECK), (supportsSimd = !0); } catch (e) { supportsSimd = !1; } return supportsSimd; } async function createFileset(e, t = '') { const r = (await isSimdSupported()) ? 'wasm_internal' : 'wasm_nosimd_internal'; return { wasmLoaderPath: `${t}/${e}_${r}.js`, wasmBinaryPath: `${t}/${e}_${r}.wasm` }; } class FilesetResolver$1 { static isSimdSupported() { return isSimdSupported(); } static forAudioTasks(e) { return createFileset('audio', e); } static forTextTasks(e) { return createFileset('text', e); } static forVisionTasks(e) { return createFileset('vision', e); } } fileset_resolver.FilesetResolver = FilesetResolver$1; var drawing_utils = {}; Object.defineProperty(drawing_utils, '__esModule', { value: !0 }), (drawing_utils.DrawingUtils = void 0); const DEFAULT_OPTIONS = { color: 'white', lineWidth: 4, radius: 6 }; function addDefaultOptions(e) { return ( (e = e || {}), Object.assign(Object.assign(Object.assign({}, DEFAULT_OPTIONS), { fillColor: e.color }), e) ); } function resolve(e, t) { return e instanceof Function ? e(t) : e; } class DrawingUtils$1 { constructor(e) { this.ctx = e; } static clamp(e, t, r) { const o = Math.min(t, r), i = Math.max(t, r); return Math.max(o, Math.min(i, e)); } static lerp(e, t, r, o, i) { const a = o * (1 - (e - t) / (r - t)) + i * (1 - (r - e) / (r - t)); return DrawingUtils$1.clamp(a, o, i); } drawLandmarks(e, t) { if (!e) return; const r = this.ctx, o = addDefaultOptions(t); r.save(); const i = r.canvas; let a = 0; for (const t of e) { (r.fillStyle = resolve(o.fillColor, { index: a, from: t })), (r.strokeStyle = resolve(o.color, { index: a, from: t })), (r.lineWidth = resolve(o.lineWidth, { index: a, from: t })); const e = new Path2D(); e.arc( t.x * i.width, t.y * i.height, resolve(o.radius, { index: a, from: t }), 0, 2 * Math.PI ), r.fill(e), r.stroke(e), ++a; } r.restore(); } drawConnectors(e, t, r) { if (!e || !t) return; const o = this.ctx, i = addDefaultOptions(r); o.save(); const a = o.canvas; let n = 0; for (const r of t) { o.beginPath(); const t = e[r.start], s = e[r.end]; t && s && ((o.strokeStyle = resolve(i.color, { index: n, from: t, to: s })), (o.lineWidth = resolve(i.lineWidth, { index: n, from: t, to: s })), o.moveTo(t.x * a.width, t.y * a.height), o.lineTo(s.x * a.width, s.y * a.height)), ++n, o.stroke(); } o.restore(); } drawBoundingBox(e, t) { const r = this.ctx, o = addDefaultOptions(t); r.save(), r.beginPath(), (r.lineWidth = resolve(o.lineWidth, {})), (r.strokeStyle = resolve(o.color, {})), (r.fillStyle = resolve(o.fillColor, {})), r.moveTo(e.originX, e.originY), r.lineTo(e.originX + e.width, e.originY), r.lineTo(e.originX + e.width, e.originY + e.height), r.lineTo(e.originX, e.originY + e.height), r.lineTo(e.originX, e.originY), r.stroke(), r.fill(), r.restore(); } } drawing_utils.DrawingUtils = DrawingUtils$1; var image = {}, image_shader_context = {}; Object.defineProperty(image_shader_context, '__esModule', { value: !0 }), (image_shader_context.MPImageShaderContext = image_shader_context.assertNotNull = void 0); const VERTEX_SHADER = '\n attribute vec2 aVertex;\n attribute vec2 aTex;\n varying vec2 vTex;\n void main(void) {\n gl_Position = vec4(aVertex, 0.0, 1.0);\n vTex = aTex;\n }', FRAGMENT_SHADER = '\n precision mediump float;\n varying vec2 vTex;\n uniform sampler2D inputTexture;\n void main() {\n gl_FragColor = texture2D(inputTexture, vTex);\n }\n '; function assertNotNull(e, t) { if (null === e) throw new Error(`Unable to obtain required WebGL resource: ${t}`); return e; } image_shader_context.assertNotNull = assertNotNull; class MPImageShaderBuffers { constructor(e, t, r, o) { (this.gl = e), (this.vertexArrayObject = t), (this.vertexBuffer = r), (this.textureBuffer = o); } bind() { this.gl.bindVertexArray(this.vertexArrayObject); } unbind() { this.gl.bindVertexArray(null); } close() { this.gl.deleteVertexArray(this.vertexArrayObject), this.gl.deleteBuffer(this.vertexBuffer), this.gl.deleteBuffer(this.textureBuffer); } } class MPImageShaderContext { compileShader(e, t) { const r = this.gl, o = assertNotNull(r.createShader(t), 'Failed to create WebGL shader'); if ( (r.shaderSource(o, e), r.compileShader(o), !r.getShaderParameter(o, r.COMPILE_STATUS)) ) { const e = r.getShaderInfoLog(o); throw new Error(`Could not compile WebGL shader: ${e}`); } return r.attachShader(this.program, o), o; } setupShaders() { const e = this.gl; (this.program = assertNotNull(e.createProgram(), 'Failed to create WebGL program')), (this.vertexShader = this.compileShader(VERTEX_SHADER, e.VERTEX_SHADER)), (this.fragmentShader = this.compileShader(FRAGMENT_SHADER, e.FRAGMENT_SHADER)), e.linkProgram(this.program); if (!e.getProgramParameter(this.program, e.LINK_STATUS)) { const t = e.getProgramInfoLog(this.program); throw new Error(`Error during program linking: ${t}`); } (this.aVertex = e.getAttribLocation(this.program, 'aVertex')), (this.aTex = e.getAttribLocation(this.program, 'aTex')); } createBuffers(e) { const t = this.gl, r = assertNotNull(t.createVertexArray(), 'Failed to create vertex array'); t.bindVertexArray(r); const o = assertNotNull(t.createBuffer(), 'Failed to create buffer'); t.bindBuffer(t.ARRAY_BUFFER, o), t.enableVertexAttribArray(this.aVertex), t.vertexAttribPointer(this.aVertex, 2, t.FLOAT, !1, 0, 0), t.bufferData( t.ARRAY_BUFFER, new Float32Array([-1, -1, -1, 1, 1, 1, 1, -1]), t.STATIC_DRAW ); const i = assertNotNull(t.createBuffer(), 'Failed to create buffer'); t.bindBuffer(t.ARRAY_BUFFER, i), t.enableVertexAttribArray(this.aTex), t.vertexAttribPointer(this.aTex, 2, t.FLOAT, !1, 0, 0); const a = e ? [0, 1, 0, 0, 1, 0, 1, 1] : [0, 0, 0, 1, 1, 1, 1, 0]; return ( t.bufferData(t.ARRAY_BUFFER, new Float32Array(a), t.STATIC_DRAW), t.bindBuffer(t.ARRAY_BUFFER, null), t.bindVertexArray(null), new MPImageShaderBuffers(t, r, o, i) ); } getShaderBuffers(e) { return e ? (this.shaderBuffersFlipVertically || (this.shaderBuffersFlipVertically = this.createBuffers(!0)), this.shaderBuffersFlipVertically) : (this.shaderBuffersPassthrough || (this.shaderBuffersPassthrough = this.createBuffers(!1)), this.shaderBuffersPassthrough); } maybeInitGL(e) { if (this.gl) { if (e !== this.gl) throw new Error('Cannot change GL context once initialized'); } else this.gl = e; } run(e, t, r) { this.maybeInitGL(e), this.program || this.setupShaders(); const o = this.getShaderBuffers(t); e.useProgram(this.program), o.bind(); const i = r(); return o.unbind(), i; } bindFramebuffer(e, t) { this.maybeInitGL(e), this.framebuffer || (this.framebuffer = assertNotNull( e.createFramebuffer(), 'Failed to create framebuffe.' )), e.bindFramebuffer(e.FRAMEBUFFER, this.framebuffer), e.framebufferTexture2D(e.FRAMEBUFFER, e.COLOR_ATTACHMENT0, e.TEXTURE_2D, t, 0); } unbindFramebuffer() { var e; null === (e = this.gl) || void 0 === e || e.bindFramebuffer(this.gl.FRAMEBUFFER, null); } close() { if (this.program) { const e = this.gl; e.deleteProgram(this.program), e.deleteShader(this.vertexShader), e.deleteShader(this.fragmentShader); } this.framebuffer && this.gl.deleteFramebuffer(this.framebuffer), this.shaderBuffersPassthrough && this.shaderBuffersPassthrough.close(), this.shaderBuffersFlipVertically && this.shaderBuffersFlipVertically.close(); } } (image_shader_context.MPImageShaderContext = MPImageShaderContext), Object.defineProperty(image, '__esModule', { value: !0 }), (image.MPImage = void 0); const image_shader_context_1$2 = image_shader_context, INSTANCE_COUNT_WARNING_THRESHOLD$1 = 250; var MPImageType; !(function(e) { (e[(e.IMAGE_DATA = 0)] = 'IMAGE_DATA'), (e[(e.IMAGE_BITMAP = 1)] = 'IMAGE_BITMAP'), (e[(e.WEBGL_TEXTURE = 2)] = 'WEBGL_TEXTURE'); })(MPImageType || (MPImageType = {})); class MPImage$1 { constructor(e, t, r, o, i, a, n) { (this.containers = e), (this.ownsImageBitmap = t), (this.ownsWebGLTexture = r), (this.canvas = o), (this.shaderContext = i), (this.width = a), (this.height = n), (this.ownsImageBitmap || this.ownsWebGLTexture) && (--MPImage$1.instancesBeforeWarning, 0 === MPImage$1.instancesBeforeWarning && console.error( 'You seem to be creating MPImage instances without invoking .close(). This leaks resources.' )); } hasImageData() { return !!this.getContainer(MPImageType.IMAGE_DATA); } hasImageBitmap() { return !!this.getContainer(MPImageType.IMAGE_BITMAP); } hasWebGLTexture() { return !!this.getContainer(MPImageType.WEBGL_TEXTURE); } getAsImageData() { return this.convertToImageData(); } getAsImageBitmap() { return this.convertToImageBitmap(); } getAsWebGLTexture() { return this.convertToWebGLTexture(); } getContainer(e) { switch (e) { case MPImageType.IMAGE_DATA: return this.containers.find((e) => e instanceof ImageData); case MPImageType.IMAGE_BITMAP: return this.containers.find( (e) => 'undefined' != typeof ImageBitmap && e instanceof ImageBitmap ); case MPImageType.WEBGL_TEXTURE: return this.containers.find( (e) => 'undefined' != typeof WebGLTexture && e instanceof WebGLTexture ); default: throw new Error(`Type is not supported: ${e}`); } } clone() { const e = []; for (const t of this.containers) { let r; if (t instanceof ImageData) r = new ImageData(t.data, this.width, this.height); else if (t instanceof WebGLTexture) { const e = this.getGL(), t = this.getShaderContext(); e.activeTexture(e.TEXTURE1), (r = (0, image_shader_context_1$2.assertNotNull)( e.createTexture(), 'Failed to create texture' )), e.bindTexture(e.TEXTURE_2D, r), this.configureTextureParams(), e.texImage2D( e.TEXTURE_2D, 0, e.RGBA, this.width, this.height, 0, e.RGBA, e.UNSIGNED_BYTE, null ), e.bindTexture(e.TEXTURE_2D, null), t.bindFramebuffer(e, r), t.run(e, !1, () => { this.bindTexture(), e.clearColor(0, 0, 0, 0), e.clear(e.COLOR_BUFFER_BIT), e.drawArrays(e.TRIANGLE_FAN, 0, 4), this.unbindTexture(); }), t.unbindFramebuffer(), this.unbindTexture(); } else { if (!(t instanceof ImageBitmap)) throw new Error(`Type is not supported: ${t}`); this.convertToWebGLTexture(), this.bindTexture(), (r = this.copyTextureToBitmap()), this.unbindTexture(); } e.push(r); } return new MPImage$1( e, this.hasImageBitmap(), this.hasWebGLTexture(), this.canvas, this.shaderContext, this.width, this.height ); } getOffscreenCanvas() { if (!(this.canvas instanceof OffscreenCanvas)) throw new Error( 'Conversion to ImageBitmap requires that the MediaPipe Tasks is initialized with an OffscreenCanvas' ); return this.canvas; } getGL() { if (!this.canvas) throw new Error( 'Conversion to different image formats require that a canvas is passed when iniitializing the image.' ); return ( this.gl || (this.gl = (0, image_shader_context_1$2.assertNotNull)( this.canvas.getContext('webgl2'), 'You cannot use a canvas that is already bound to a different type of rendering context.' )), this.gl ); } getShaderContext() { return ( this.shaderContext || (this.shaderContext = new image_shader_context_1$2.MPImageShaderContext()), this.shaderContext ); } convertToImageBitmap() { let e = this.getContainer(MPImageType.IMAGE_BITMAP); return ( e || (this.convertToWebGLTexture(), (e = this.convertWebGLTextureToImageBitmap()), this.containers.push(e), (this.ownsImageBitmap = !0)), e ); } convertToImageData() { let e = this.getContainer(MPImageType.IMAGE_DATA); if (!e) { const t = this.getGL(), r = this.getShaderContext(), o = new Uint8Array(this.width * this.height * 4), i = this.convertToWebGLTexture(); r.bindFramebuffer(t, i), t.readPixels(0, 0, this.width, this.height, t.RGBA, t.UNSIGNED_BYTE, o), r.unbindFramebuffer(), (e = new ImageData(new Uint8ClampedArray(o.buffer), this.width, this.height)), this.containers.push(e); } return e; } convertToWebGLTexture() { let e = this.getContainer(MPImageType.WEBGL_TEXTURE); if (!e) { const t = this.getGL(); e = this.bindTexture(); const r = this.getContainer(MPImageType.IMAGE_BITMAP) || this.convertToImageData(); t.texImage2D(t.TEXTURE_2D, 0, t.RGBA, t.RGBA, t.UNSIGNED_BYTE, r), this.unbindTexture(); } return e; } configureTextureParams() { const e = this.getGL(); e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.LINEAR), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.LINEAR); } bindTexture() { const e = this.getGL(); e.viewport(0, 0, this.width, this.height), e.activeTexture(e.TEXTURE0); let t = this.getContainer(MPImageType.WEBGL_TEXTURE); return ( t ? e.bindTexture(e.TEXTURE_2D, t) : ((t = (0, image_shader_context_1$2.assertNotNull)( e.createTexture(), 'Failed to create texture' )), this.containers.push(t), (this.ownsWebGLTexture = !0), e.bindTexture(e.TEXTURE_2D, t), this.configureTextureParams()), t ); } unbindTexture() { this.gl.bindTexture(this.gl.TEXTURE_2D, null); } copyTextureToBitmap() { const e = this.getGL(); return this.getShaderContext().run(e, !0, () => this.runWithResizedCanvas( () => ( e.bindFramebuffer(e.FRAMEBUFFER, null), e.clearColor(0, 0, 0, 0), e.clear(e.COLOR_BUFFER_BIT), e.drawArrays(e.TRIANGLE_FAN, 0, 4), this.getOffscreenCanvas().transferToImageBitmap() ) ) ); } convertWebGLTextureToImageBitmap() { this.bindTexture(); const e = this.copyTextureToBitmap(); return this.unbindTexture(), e; } runWithResizedCanvas(e) { const t = this.canvas; if (t.width === this.width && t.height === this.height) return e(); const r = t.width, o = t.height; (t.width = this.width), (t.height = this.height); const i = e(); return (t.width = r), (t.height = o), i; } close() { if ( (this.ownsImageBitmap && this.getContainer(MPImageType.IMAGE_BITMAP).close(), this.ownsWebGLTexture) ) { this.getGL().deleteTexture(this.getContainer(MPImageType.WEBGL_TEXTURE)); } MPImage$1.instancesBeforeWarning = -1; } } (image.MPImage = MPImage$1), (MPImage$1.instancesBeforeWarning = INSTANCE_COUNT_WARNING_THRESHOLD$1); var mask = {}, platform_utils = {}; function isWebKit(e = navigator) { const t = e.userAgent; return t.includes('Safari') && !t.includes('Chrome'); } function isIOS() { return ( ['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes( navigator.platform ) || (navigator.userAgent.includes('Mac') && 'ontouchend' in document) ); } Object.defineProperty(platform_utils, '__esModule', { value: !0 }), (platform_utils.isIOS = platform_utils.isWebKit = void 0), (platform_utils.isWebKit = isWebKit), (platform_utils.isIOS = isIOS), Object.defineProperty(mask, '__esModule', { value: !0 }), (mask.MPMask = void 0); const image_shader_context_1$1 = image_shader_context, platform_utils_1$1 = platform_utils, INSTANCE_COUNT_WARNING_THRESHOLD = 250; var MPMaskType; !(function(e) { (e[(e.UINT8_ARRAY = 0)] = 'UINT8_ARRAY'), (e[(e.FLOAT32_ARRAY = 1)] = 'FLOAT32_ARRAY'), (e[(e.WEBGL_TEXTURE = 2)] = 'WEBGL_TEXTURE'); })(MPMaskType || (MPMaskType = {})); class MPMask$1 { constructor(e, t, r, o, i, a) { (this.containers = e), (this.ownsWebGLTexture = t), (this.canvas = r), (this.shaderContext = o), (this.width = i), (this.height = a), this.ownsWebGLTexture && (--MPMask$1.instancesBeforeWarning, 0 === MPMask$1.instancesBeforeWarning && console.error( 'You seem to be creating MPMask instances without invoking .close(). This leaks resources.' )); } hasUint8Array() { return !!this.getContainer(MPMaskType.UINT8_ARRAY); } hasFloat32Array() { return !!this.getContainer(MPMaskType.FLOAT32_ARRAY); } hasWebGLTexture() { return !!this.getContainer(MPMaskType.WEBGL_TEXTURE); } getAsUint8Array() { return this.convertToUint8Array(); } getAsFloat32Array() { return this.convertToFloat32Array(); } getAsWebGLTexture() { return this.convertToWebGLTexture(); } getTexImage2DFormat() { const e = this.getGL(); if (!MPMask$1.texImage2DFormat) if ( e.getExtension('EXT_color_buffer_float') && e.getExtension('OES_texture_float_linear') && e.getExtension('EXT_float_blend') ) MPMask$1.texImage2DFormat = e.R32F; else { if (!e.getExtension('EXT_color_buffer_half_float')) throw new Error( 'GPU does not fully support 4-channel float32 or float16 formats' ); MPMask$1.texImage2DFormat = e.R16F; } return MPMask$1.texImage2DFormat; } getContainer(e) { switch (e) { case MPMaskType.UINT8_ARRAY: return this.containers.find((e) => e instanceof Uint8Array); case MPMaskType.FLOAT32_ARRAY: return this.containers.find((e) => e instanceof Float32Array); case MPMaskType.WEBGL_TEXTURE: return this.containers.find( (e) => 'undefined' != typeof WebGLTexture && e instanceof WebGLTexture ); default: throw new Error(`Type is not supported: ${e}`); } } clone() { const e = []; for (const t of this.containers) { let r; if (t instanceof Uint8Array) r = new Uint8Array(t); else if (t instanceof Float32Array) r = new Float32Array(t); else { if (!(t instanceof WebGLTexture)) throw new Error(`Type is not supported: ${t}`); { const e = this.getGL(), t = this.getShaderContext(); e.activeTexture(e.TEXTURE1), (r = (0, image_shader_context_1$1.assertNotNull)( e.createTexture(), 'Failed to create texture' )), e.bindTexture(e.TEXTURE_2D, r), this.configureTextureParams(); const o = this.getTexImage2DFormat(); e.texImage2D( e.TEXTURE_2D, 0, o, this.width, this.height, 0, e.RED, e.FLOAT, null ), e.bindTexture(e.TEXTURE_2D, null), t.bindFramebuffer(e, r), t.run(e, !1, () => { this.bindTexture(), e.clearColor(0, 0, 0, 0), e.clear(e.COLOR_BUFFER_BIT), e.drawArrays(e.TRIANGLE_FAN, 0, 4), this.unbindTexture(); }), t.unbindFramebuffer(), this.unbindTexture(); } } e.push(r); } return new MPMask$1( e, this.hasWebGLTexture(), this.canvas, this.shaderContext, this.width, this.height ); } getGL() { if (!this.canvas) throw new Error( 'Conversion to different image formats require that a canvas is passed when initializing the image.' ); return ( this.gl || (this.gl = (0, image_shader_context_1$1.assertNotNull)( this.canvas.getContext('webgl2'), 'You cannot use a canvas that is already bound to a different type of rendering context.' )), this.gl ); } getShaderContext() { return ( this.shaderContext || (this.shaderContext = new image_shader_context_1$1.MPImageShaderContext()), this.shaderContext ); } convertToFloat32Array() { let e = this.getContainer(MPMaskType.FLOAT32_ARRAY); if (!e) { const t = this.getContainer(MPMaskType.UINT8_ARRAY); if (t) e = new Float32Array(t).map((e) => e / 255); else { e = new Float32Array(this.width * this.height); const t = this.getGL(), r = this.getShaderContext(), o = this.convertToWebGLTexture(); if ((r.bindFramebuffer(t, o), (0, platform_utils_1$1.isIOS)())) { const r = new Float32Array(this.width * this.height * 4); t.readPixels(0, 0, this.width, this.height, t.RGBA, t.FLOAT, r); for (let t = 0, o = 0; t < e.length; ++t, o += 4) e[t] = r[o]; } else t.readPixels(0, 0, this.width, this.height, t.RED, t.FLOAT, e); } this.containers.push(e); } return e; } convertToUint8Array() { let e = this.getContainer(MPMaskType.UINT8_ARRAY); if (!e) { const t = this.convertToFloat32Array(); (e = new Uint8Array(t.map((e) => 255 * e))), this.containers.push(e); } return e; } convertToWebGLTexture() { let e = this.getContainer(MPMaskType.WEBGL_TEXTURE); if (!e) { const t = this.getGL(); e = this.bindTexture(); const r = this.convertToFloat32Array(), o = this.getTexImage2DFormat(); t.texImage2D(t.TEXTURE_2D, 0, o, this.width, this.height, 0, t.RED, t.FLOAT, r), this.unbindTexture(); } return e; } configureTextureParams() { const e = this.getGL(); e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_S, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_WRAP_T, e.CLAMP_TO_EDGE), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.NEAREST), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.NEAREST); } bindTexture() { const e = this.getGL(); e.viewport(0, 0, this.width, this.height), e.activeTexture(e.TEXTURE0); let t = this.getContainer(MPMaskType.WEBGL_TEXTURE); return ( t ? e.bindTexture(e.TEXTURE_2D, t) : ((t = (0, image_shader_context_1$1.assertNotNull)( e.createTexture(), 'Failed to create texture' )), this.containers.push(t), (this.ownsWebGLTexture = !0), e.bindTexture(e.TEXTURE_2D, t), this.configureTextureParams()), t ); } unbindTexture() { this.gl.bindTexture(this.gl.TEXTURE_2D, null); } close() { if (this.ownsWebGLTexture) { this.getGL().deleteTexture(this.getContainer(MPMaskType.WEBGL_TEXTURE)); } MPMask$1.instancesBeforeWarning = -1; } } (mask.MPMask = MPMask$1), (MPMask$1.instancesBeforeWarning = INSTANCE_COUNT_WARNING_THRESHOLD); var face_detector = {}, calculator_pb = {}, googleProtobuf = {}; (function(exports) { var $jscomp = $jscomp || {}; ($jscomp.scope = {}), ($jscomp.findInternal = function(e, t, r) { e instanceof String && (e = String(e)); for (var o = e.length, i = 0; i < o; i++) { var a = e[i]; if (t.call(r, a, i, e)) return { i: i, v: a }; } return { i: -1, v: void 0 }; }), ($jscomp.ASSUME_ES5 = !1), ($jscomp.ASSUME_NO_NATIVE_MAP = !1), ($jscomp.ASSUME_NO_NATIVE_SET = !1), ($jscomp.SIMPLE_FROUND_POLYFILL = !1), ($jscomp.defineProperty = $jscomp.ASSUME_ES5 || 'function' == typeof Object.defineProperties ? Object.defineProperty : function(e, t, r) { e != Array.prototype && e != Object.prototype && (e[t] = r.value); }), ($jscomp.getGlobal = function(e) { return 'undefined' != typeof window && window === e ? e : void 0 !== commonjsGlobal && null != commonjsGlobal ? commonjsGlobal : e; }), ($jscomp.global = $jscomp.getGlobal(commonjsGlobal)), ($jscomp.polyfill = function(e, t, r, o) { if (t) { for (r = $jscomp.global, e = e.split('.'), o = 0; o < e.length - 1; o++) { var i = e[o]; i in r || (r[i] = {}), (r = r[i]); } (t = t((o = r[(e = e[e.length - 1])]))) != o && null != t && $jscomp.defineProperty(r, e, { configurable: !0, writable: !0, value: t }); } }), $jscomp.polyfill( 'Array.prototype.findIndex', function(e) { return ( e || function(e, t) { return $jscomp.findInternal(this, e, t).i; } ); }, 'es6', 'es3' ), ($jscomp.checkStringArgs = function(e, t, r) { if (null == e) throw new TypeError( "The 'this' value for String.prototype." + r + ' must not be null or undefined' ); if (t instanceof RegExp) throw new TypeError( 'First argument to String.prototype.' + r + ' must not be a regular expression' ); return e + ''; }), $jscomp.polyfill( 'String.prototype.endsWith', function(e) { return ( e || function(e, t) { var r = $jscomp.checkStringArgs(this, e, 'endsWith'); (e += ''), void 0 === t && (t = r.length), (t = Math.max(0, Math.min(0 | t, r.length))); for (var o = e.length; 0 < o && 0 < t; ) if (r[--t] != e[--o]) return !1; return 0 >= o; } ); }, 'es6', 'es3' ), $jscomp.polyfill( 'Array.prototype.find', function(e) { return ( e || function(e, t) { return $jscomp.findInternal(this, e, t).v; } ); }, 'es6', 'es3' ), $jscomp.polyfill( 'String.prototype.startsWith', function(e) { return ( e || function(e, t) { var r = $jscomp.checkStringArgs(this, e, 'startsWith'); e += ''; var o = r.length, i = e.length; t = Math.max(0, Math.min(0 | t, r.length)); for (var a = 0; a < i && t < o; ) if (r[t++] != e[a++]) return !1; return a >= i; } ); }, 'es6', 'es3' ), $jscomp.polyfill( 'String.prototype.repeat', function(e) { return ( e || function(e) { var t = $jscomp.checkStringArgs(this, null, 'repeat'); if (0 > e || 1342177279 < e) throw new RangeError('Invalid count value'); e |= 0; for (var r = ''; e; ) 1 & e && (r += t), (e >>>= 1) && (t += t); return r; } ); }, 'es6', 'es3' ); var COMPILED = !0, goog = goog || {}; (goog.global = commonjsGlobal || self), (goog.exportPath_ = function(e, t, r) { (e = e.split('.')), (r = r || goog.global), e[0] in r || void 0 === r.execScript || r.execScript('var ' + e[0]); for (var o; e.length && (o = e.shift()); ) e.length || void 0 === t ? (r = r[o] && r[o] !== Object.prototype[o] ? r[o] : (r[o] = {})) : (r[o] = t); }), (goog.define = function(e, t) { return t; }), (goog.FEATURESET_YEAR = 2012), (goog.DEBUG = !0), (goog.LOCALE = 'en'), (goog.TRUSTED_SITE = !0), (goog.STRICT_MODE_COMPATIBLE = !1), (goog.DISALLOW_TEST_ONLY_CODE = !goog.DEBUG), (goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING = !1), (goog.provide = function(e) { if (goog.isInModuleLoader_()) throw Error('goog.provide cannot be used within a module.'); goog.constructNamespace_(e); }), (goog.constructNamespace_ = function(e, t) { goog.exportPath_(e, t); }), (goog.getScriptNonce = function(e) { return e && e != goog.global ? goog.getScriptNonce_(e.document) : (null === goog.cspNonce_ && (goog.cspNonce_ = goog.getScriptNonce_(goog.global.document)), goog.cspNonce_); }), (goog.NONCE_PATTERN_ = /^[\w+/_-]+[=]{0,2}$/), (goog.cspNonce_ = null), (goog.getScriptNonce_ = function(e) { return (e = e.querySelector && e.querySelector('script[nonce]')) && (e = e.nonce || e.getAttribute('nonce')) && goog.NONCE_PATTERN_.test(e) ? e : ''; }), (goog.VALID_MODULE_RE_ = /^[a-zA-Z_$][a-zA-Z0-9._$]*$/), (goog.module = function(e) { if ('string' != typeof e || !e || -1 == e.search(goog.VALID_MODULE_RE_)) throw Error('Invalid module identifier'); if (!goog.isInGoogModuleLoader_()) throw Error( 'Module ' + e + " has been loaded incorrectly. Note, modules cannot be loaded as normal scripts. They require some kind of pre-processing step. You're likely trying to load a module via a script tag or as a part of a concatenated bundle without rewriting the module. For more info see: https://github.com/google/closure-library/wiki/goog.module:-an-ES6-module-like-alternative-to-goog.provide." ); if (goog.moduleLoaderState_.moduleName) throw Error('goog.module may only be called once per module.'); goog.moduleLoaderState_.moduleName = e; }), (goog.module.get = function(e) { return goog.module.getInternal_(e); }), (goog.module.getInternal_ = function(e) { return null; }), (goog.ModuleType = { ES6: 'es6', GOOG: 'goog' }), (goog.moduleLoaderState_ = null), (goog.isInModuleLoader_ = function() { return goog.isInGoogModuleLoader_() || goog.isInEs6ModuleLoader_(); }), (goog.isInGoogModuleLoader_ = function() { return ( !!goog.moduleLoaderState_ && goog.moduleLoaderState_.type == goog.ModuleType.GOOG ); }), (goog.isInEs6ModuleLoader_ = function() { if (goog.moduleLoaderState_ && goog.moduleLoaderState_.type == goog.ModuleType.ES6) return !0; var e = goog.global.$jscomp; return !!e && 'function' == typeof e.getCurrentModulePath && !!e.getCurrentModulePath(); }), (goog.module.declareLegacyNamespace = function() { goog.moduleLoaderState_.declareLegacyNamespace = !0; }), (goog.declareModuleId = function(e) { if (goog.moduleLoaderState_) goog.moduleLoaderState_.moduleName = e; else { var t = goog.global.$jscomp; if (!t || 'function' != typeof t.getCurrentModulePath) throw Error('Module with namespace "' + e + '" has been loaded incorrectly.'); (t = t.require(t.getCurrentModulePath())), (goog.loadedModules_[e] = { exports: t, type: goog.ModuleType.ES6, moduleId: e, }); } }), (goog.setTestOnly = function(e) { if (goog.DISALLOW_TEST_ONLY_CODE) throw ((e = e || ''), Error( 'Importing test-only code into non-debug environment' + (e ? ': ' + e : '.') )); }), (goog.forwardDeclare = function(e) {}), (goog.getObjectByName = function(e, t) { (e = e.split('.')), (t = t || goog.global); for (var r = 0; r < e.length; r++) if (null == (t = t[e[r]])) return null; return t; }), (goog.globalize = function(e, t) { for (var r in ((t = t || goog.global), e)) t[r] = e[r]; }), (goog.addDependency = function(e, t, r, o) {}), (goog.ENABLE_DEBUG_LOADER = !0), (goog.logToConsole_ = function(e) { goog.global.console && goog.global.console.error(e); }), (goog.require = function(e) {}), (goog.requireType = function(e) { return {}; }), (goog.basePath = ''), (goog.nullFunction = function() {}), (goog.abstractMethod = function() { throw Error('unimplemented abstract method'); }), (goog.addSingletonGetter = function(e) { (e.instance_ = void 0), (e.getInstance = function() { return e.instance_ ? e.instance_ : (goog.DEBUG && (goog.instantiatedSingletons_[ goog.instantiatedSingletons_.length ] = e), (e.instance_ = new e())); }); }), (goog.instantiatedSingletons_ = []), (goog.LOAD_MODULE_USING_EVAL = !0), (goog.SEAL_MODULE_EXPORTS = goog.DEBUG), (goog.loadedModules_ = {}), (goog.DEPENDENCIES_ENABLED = !COMPILED), (goog.TRANSPILE = 'detect'), (goog.ASSUME_ES_MODULES_TRANSPILED = !1), (goog.TRANSPILE_TO_LANGUAGE = ''), (goog.TRANSPILER = 'transpile.js'), (goog.hasBadLetScoping = null), (goog.useSafari10Workaround = function() { if (null == goog.hasBadLetScoping) { try { var a = !eval( '"use strict";let x = 1; function f() { return typeof x; };f() == "number";' ); } catch (e) { a = !1; } goog.hasBadLetScoping = a; } return goog.hasBadLetScoping; }), (goog.workaroundSafari10EvalBug = function(e) { return '(function(){' + e + '\n;})();\n'; }), (goog.loadModule = function(e) { var t = goog.moduleLoaderState_; try { if ( ((goog.moduleLoaderState_ = { moduleName: '', declareLegacyNamespace: !1, type: goog.ModuleType.GOOG, }), goog.isFunction(e)) ) var r = e.call(void 0, {}); else { if ('string' != typeof e) throw Error('Invalid module definition'); goog.useSafari10Workaround() && (e = goog.workaroundSafari10EvalBug(e)), (r = goog.loadModuleFromSource_.call(void 0, e)); } var o = goog.moduleLoaderState_.moduleName; if ('string' != typeof o || !o) throw Error('Invalid module name "' + o + '"'); goog.moduleLoaderState_.declareLegacyNamespace ? goog.constructNamespace_(o, r) : goog.SEAL_MODULE_EXPORTS && Object.seal && 'object' == typeof r && null != r && Object.seal(r), (goog.loadedModules_[o] = { exports: r, type: goog.ModuleType.GOOG, moduleId: goog.moduleLoaderState_.moduleName, }); } finally { goog.moduleLoaderState_ = t; } }), (goog.loadModuleFromSource_ = function(a) { return eval(a), {}; }), (goog.normalizePath_ = function(e) { e = e.split('/'); for (var t = 0; t < e.length; ) '.' == e[t] ? e.splice(t, 1) : t && '..' == e[t] && e[t - 1] && '..' != e[t - 1] ? e.splice(--t, 2) : t++; return e.join('/'); }), (goog.loadFileSync_ = function(e) { if (goog.global.CLOSURE_LOAD_FILE_SYNC) return goog.global.CLOSURE_LOAD_FILE_SYNC(e); try { var t = new goog.global.XMLHttpRequest(); return ( t.open('get', e, !1), t.send(), 0 == t.status || 200 == t.status ? t.responseText : null ); } catch (e) { return null; } }), (goog.transpile_ = function(e, t, r) { var o = goog.global.$jscomp; o || (goog.global.$jscomp = o = {}); var i = o.transpile; if (!i) { var a = goog.basePath + goog.TRANSPILER, n = goog.loadFileSync_(a); if (n) { if ( (function() { (0, eval)(n + '\n//# sourceURL=' + a); }.call(goog.global), goog.global.$gwtExport && goog.global.$gwtExport.$jscomp && !goog.global.$gwtExport.$jscomp.transpile) ) throw Error( 'The transpiler did not properly export the "transpile" method. $gwtExport: ' + JSON.stringify(goog.global.$gwtExport) ); (goog.global.$jscomp.transpile = goog.global.$gwtExport.$jscomp.transpile), (i = (o = goog.global.$jscomp).transpile); } } return ( i || (i = o.transpile = function(e, t) { return ( goog.logToConsole_( t + ' requires transpilation but no transpiler was found.' ), e ); }), i(e, t, r) ); }), (goog.typeOf = function(e) { var t = typeof e; if ('object' == t) { if (!e) return 'null'; if (e instanceof Array) return 'array'; if (e instanceof Object) return t; var r = Object.prototype.toString.call(e); if ('[object Window]' == r) return 'object'; if ( '[object Array]' == r || ('number' == typeof e.length && void 0 !== e.splice && void 0 !== e.propertyIsEnumerable && !e.propertyIsEnumerable('splice')) ) return 'array'; if ( '[object Function]' == r || (void 0 !== e.call && void 0 !== e.propertyIsEnumerable && !e.propertyIsEnumerable('call')) ) return 'function'; } else if ('function' == t && void 0 === e.call) return 'object'; return t; }), (goog.isArray = function(e) { return 'array' == goog.typeOf(e); }), (goog.isArrayLike = function(e) { var t = goog.typeOf(e); return 'array' == t || ('object' == t && 'number' == typeof e.length); }), (goog.isDateLike = function(e) { return goog.isObject(e) && 'function' == typeof e.getFullYear; }), (goog.isFunction = function(e) { return 'function' == goog.typeOf(e); }), (goog.isObject = function(e) { var t = typeof e; return ('object' == t && null != e) || 'function' == t; }), (goog.getUid = function(e) { return ( (Object.prototype.hasOwnProperty.call(e, goog.UID_PROPERTY_) && e[goog.UID_PROPERTY_]) || (e[goog.UID_PROPERTY_] = ++goog.uidCounter_) ); }), (goog.hasUid = function(e) { return !!e[goog.UID_PROPERTY_]; }), (goog.removeUid = function(e) { null !== e && 'removeAttribute' in e && e.removeAttribute(goog.UID_PROPERTY_); try { delete e[goog.UID_PROPERTY_]; } catch (e) {} }), (goog.UID_PROPERTY_ = 'closure_uid_' + ((1e9 * Math.random()) >>> 0)), (goog.uidCounter_ = 0), (goog.getHashCode = goog.getUid), (goog.removeHashCode = goog.removeUid), (goog.cloneObject = function(e) { var t = goog.typeOf(e); if ('object' == t || 'array' == t) { if ('function' == typeof e.clone) return e.clone(); for (var r in ((t = 'array' == t ? [] : {}), e)) t[r] = goog.cloneObject(e[r]); return t; } return e; }), (goog.bindNative_ = function(e, t, r) { return e.call.apply(e.bind, arguments); }), (goog.bindJs_ = function(e, t, r) { if (!e) throw Error(); if (2 < arguments.length) { var o = Array.prototype.slice.call(arguments, 2); return function() { var r = Array.prototype.slice.call(arguments); return Array.prototype.unshift.apply(r, o), e.apply(t, r); }; } return function() { return e.apply(t, arguments); }; }), (goog.bind = function(e, t, r) { return ( Function.prototype.bind && -1 != Function.prototype.bind.toString().indexOf('native code') ? (goog.bind = goog.bindNative_) : (goog.bind = goog.bindJs_), goog.bind.apply(null, arguments) ); }), (goog.partial = function(e, t) { var r = Array.prototype.slice.call(arguments, 1); return function() { var t = r.slice(); return t.push.apply(t, arguments), e.apply(this, t); }; }), (goog.mixin = function(e, t) { for (var r in t) e[r] = t[r]; }), (goog.now = (goog.TRUSTED_SITE && Date.now) || function() { return +new Date(); }), (goog.globalEval = function(e) { if (goog.global.execScript) goog.global.execScript(e, 'JavaScript'); else { if (!goog.global.eval) throw Error('goog.globalEval not available'); if (null == goog.evalWorksForGlobals_) { try { goog.global.eval('var _evalTest_ = 1;'); } catch (e) {} if (void 0 !== goog.global._evalTest_) { try { delete goog.global._evalTest_; } catch (e) {} goog.evalWorksForGlobals_ = !0; } else goog.evalWorksForGlobals_ = !1; } if (goog.evalWorksForGlobals_) goog.global.eval(e); else { var t = goog.global.document, r = t.createElement('script'); (r.type = 'text/javascript'), (r.defer = !1), r.appendChild(t.createTextNode(e)), t.head.appendChild(r), t.head.removeChild(r); } } }), (goog.evalWorksForGlobals_ = null), (goog.getCssName = function(e, t) { if ('.' == String(e).charAt(0)) throw Error( 'className passed in goog.getCssName must not start with ".". You passed: ' + e ); var r = function(e) { return goog.cssNameMapping_[e] || e; }, o = function(e) { e = e.split('-'); for (var t = [], o = 0; o < e.length; o++) t.push(r(e[o])); return t.join('-'); }; return ( (o = goog.cssNameMapping_ ? 'BY_WHOLE' == goog.cssNameMappingStyle_ ? r : o : function(e) { return e; }), (e = t ? e + '-' + o(t) : o(e)), goog.global.CLOSURE_CSS_NAME_MAP_FN ? goog.global.CLOSURE_CSS_NAME_MAP_FN(e) : e ); }), (goog.setCssNameMapping = function(e, t) { (goog.cssNameMapping_ = e), (goog.cssNameMappingStyle_ = t); }), (goog.getMsg = function(e, t, r) { return ( r && r.html && (e = e.replace(/ r ? Math.max(0, e.length + r) : r), 'string' == typeof e) ) return 'string' != typeof t || 1 != t.length ? -1 : e.indexOf(t, r); for (; r < e.length; r++) if (r in e && e[r] === t) return r; return -1; }), (goog.array.lastIndexOf = goog.NATIVE_ARRAY_PROTOTYPES && (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.lastIndexOf) ? function(e, t, r) { return ( goog.asserts.assert(null != e.length), Array.prototype.lastIndexOf.call(e, t, null == r ? e.length - 1 : r) ); } : function(e, t, r) { if ( (0 > (r = null == r ? e.length - 1 : r) && (r = Math.max(0, e.length + r)), 'string' == typeof e) ) return 'string' != typeof t || 1 != t.length ? -1 : e.lastIndexOf(t, r); for (; 0 <= r; r--) if (r in e && e[r] === t) return r; return -1; }), (goog.array.forEach = goog.NATIVE_ARRAY_PROTOTYPES && (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.forEach) ? function(e, t, r) { goog.asserts.assert(null != e.length), Array.prototype.forEach.call(e, t, r); } : function(e, t, r) { for ( var o = e.length, i = 'string' == typeof e ? e.split('') : e, a = 0; a < o; a++ ) a in i && t.call(r, i[a], a, e); }), (goog.array.forEachRight = function(e, t, r) { var o = e.length, i = 'string' == typeof e ? e.split('') : e; for (--o; 0 <= o; --o) o in i && t.call(r, i[o], o, e); }), (goog.array.filter = goog.NATIVE_ARRAY_PROTOTYPES && (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.filter) ? function(e, t, r) { return ( goog.asserts.assert(null != e.length), Array.prototype.filter.call(e, t, r) ); } : function(e, t, r) { for ( var o = e.length, i = [], a = 0, n = 'string' == typeof e ? e.split('') : e, s = 0; s < o; s++ ) if (s in n) { var p = n[s]; t.call(r, p, s, e) && (i[a++] = p); } return i; }), (goog.array.map = goog.NATIVE_ARRAY_PROTOTYPES && (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.map) ? function(e, t, r) { return ( goog.asserts.assert(null != e.length), Array.prototype.map.call(e, t, r) ); } : function(e, t, r) { for ( var o = e.length, i = Array(o), a = 'string' == typeof e ? e.split('') : e, n = 0; n < o; n++ ) n in a && (i[n] = t.call(r, a[n], n, e)); return i; }), (goog.array.reduce = goog.NATIVE_ARRAY_PROTOTYPES && (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.reduce) ? function(e, t, r, o) { return ( goog.asserts.assert(null != e.length), o && (t = goog.bind(t, o)), Array.prototype.reduce.call(e, t, r) ); } : function(e, t, r, o) { var i = r; return ( goog.array.forEach(e, function(r, a) { i = t.call(o, i, r, a, e); }), i ); }), (goog.array.reduceRight = goog.NATIVE_ARRAY_PROTOTYPES && (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.reduceRight) ? function(e, t, r, o) { return ( goog.asserts.assert(null != e.length), goog.asserts.assert(null != t), o && (t = goog.bind(t, o)), Array.prototype.reduceRight.call(e, t, r) ); } : function(e, t, r, o) { var i = r; return ( goog.array.forEachRight(e, function(r, a) { i = t.call(o, i, r, a, e); }), i ); }), (goog.array.some = goog.NATIVE_ARRAY_PROTOTYPES && (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.some) ? function(e, t, r) { return ( goog.asserts.assert(null != e.length), Array.prototype.some.call(e, t, r) ); } : function(e, t, r) { for ( var o = e.length, i = 'string' == typeof e ? e.split('') : e, a = 0; a < o; a++ ) if (a in i && t.call(r, i[a], a, e)) return !0; return !1; }), (goog.array.every = goog.NATIVE_ARRAY_PROTOTYPES && (goog.array.ASSUME_NATIVE_FUNCTIONS || Array.prototype.every) ? function(e, t, r) { return ( goog.asserts.assert(null != e.length), Array.prototype.every.call(e, t, r) ); } : function(e, t, r) { for ( var o = e.length, i = 'string' == typeof e ? e.split('') : e, a = 0; a < o; a++ ) if (a in i && !t.call(r, i[a], a, e)) return !1; return !0; }), (goog.array.count = function(e, t, r) { var o = 0; return ( goog.array.forEach( e, function(e, i, a) { t.call(r, e, i, a) && ++o; }, r ), o ); }), (goog.array.find = function(e, t, r) { return 0 > (t = goog.array.findIndex(e, t, r)) ? null : 'string' == typeof e ? e.charAt(t) : e[t]; }), (goog.array.findIndex = function(e, t, r) { for (var o = e.length, i = 'string' == typeof e ? e.split('') : e, a = 0; a < o; a++) if (a in i && t.call(r, i[a], a, e)) return a; return -1; }), (goog.array.findRight = function(e, t, r) { return 0 > (t = goog.array.findIndexRight(e, t, r)) ? null : 'string' == typeof e ? e.charAt(t) : e[t]; }), (goog.array.findIndexRight = function(e, t, r) { var o = e.length, i = 'string' == typeof e ? e.split('') : e; for (--o; 0 <= o; o--) if (o in i && t.call(r, i[o], o, e)) return o; return -1; }), (goog.array.contains = function(e, t) { return 0 <= goog.array.indexOf(e, t); }), (goog.array.isEmpty = function(e) { return 0 == e.length; }), (goog.array.clear = function(e) { if (!Array.isArray(e)) for (var t = e.length - 1; 0 <= t; t--) delete e[t]; e.length = 0; }), (goog.array.insert = function(e, t) { goog.array.contains(e, t) || e.push(t); }), (goog.array.insertAt = function(e, t, r) { goog.array.splice(e, r, 0, t); }), (goog.array.insertArrayAt = function(e, t, r) { goog.partial(goog.array.splice, e, r, 0).apply(null, t); }), (goog.array.insertBefore = function(e, t, r) { var o; 2 == arguments.length || 0 > (o = goog.array.indexOf(e, r)) ? e.push(t) : goog.array.insertAt(e, t, o); }), (goog.array.remove = function(e, t) { var r; return (r = 0 <= (t = goog.array.indexOf(e, t))) && goog.array.removeAt(e, t), r; }), (goog.array.removeLast = function(e, t) { return 0 <= (t = goog.array.lastIndexOf(e, t)) && (goog.array.removeAt(e, t), !0); }), (goog.array.removeAt = function(e, t) { return ( goog.asserts.assert(null != e.length), 1 == Array.prototype.splice.call(e, t, 1).length ); }), (goog.array.removeIf = function(e, t, r) { return 0 <= (t = goog.array.findIndex(e, t, r)) && (goog.array.removeAt(e, t), !0); }), (goog.array.removeAllIf = function(e, t, r) { var o = 0; return ( goog.array.forEachRight(e, function(i, a) { t.call(r, i, a, e) && goog.array.removeAt(e, a) && o++; }), o ); }), (goog.array.concat = function(e) { return Array.prototype.concat.apply([], arguments); }), (goog.array.join = function(e) { return Array.prototype.concat.apply([], arguments); }), (goog.array.toArray = function(e) { var t = e.length; if (0 < t) { for (var r = Array(t), o = 0; o < t; o++) r[o] = e[o]; return r; } return []; }), (goog.array.clone = goog.array.toArray), (goog.array.extend = function(e, t) { for (var r = 1; r < arguments.length; r++) { var o = arguments[r]; if (goog.isArrayLike(o)) { var i = e.length || 0, a = o.length || 0; e.length = i + a; for (var n = 0; n < a; n++) e[i + n] = o[n]; } else e.push(o); } }), (goog.array.splice = function(e, t, r, o) { return ( goog.asserts.assert(null != e.length), Array.prototype.splice.apply(e, goog.array.slice(arguments, 1)) ); }), (goog.array.slice = function(e, t, r) { return ( goog.asserts.assert(null != e.length), 2 >= arguments.length ? Array.prototype.slice.call(e, t) : Array.prototype.slice.call(e, t, r) ); }), (goog.array.removeDuplicates = function(e, t, r) { t = t || e; var o = function(e) { return goog.isObject(e) ? 'o' + goog.getUid(e) : (typeof e).charAt(0) + e; }; (r = r || o), (o = {}); for (var i = 0, a = 0; a < e.length; ) { var n = e[a++], s = r(n); Object.prototype.hasOwnProperty.call(o, s) || ((o[s] = !0), (t[i++] = n)); } t.length = i; }), (goog.array.binarySearch = function(e, t, r) { return goog.array.binarySearch_(e, r || goog.array.defaultCompare, !1, t); }), (goog.array.binarySelect = function(e, t, r) { return goog.array.binarySearch_(e, t, !0, void 0, r); }), (goog.array.binarySearch_ = function(e, t, r, o, i) { for (var a, n = 0, s = e.length; n < s; ) { var p = n + ((s - n) >>> 1), d = r ? t.call(i, e[p], p, e) : t(o, e[p]); 0 < d ? (n = p + 1) : ((s = p), (a = !d)); } return a ? n : -n - 1; }), (goog.array.sort = function(e, t) { e.sort(t || goog.array.defaultCompare); }), (goog.array.stableSort = function(e, t) { for (var r = Array(e.length), o = 0; o < e.length; o++) r[o] = { index: o, value: e[o] }; var i = t || goog.array.defaultCompare; for ( goog.array.sort(r, function(e, t) { return i(e.value, t.value) || e.index - t.index; }), o = 0; o < e.length; o++ ) e[o] = r[o].value; }), (goog.array.sortByKey = function(e, t, r) { var o = r || goog.array.defaultCompare; goog.array.sort(e, function(e, r) { return o(t(e), t(r)); }); }), (goog.array.sortObjectsByKey = function(e, t, r) { goog.array.sortByKey( e, function(e) { return e[t]; }, r ); }), (goog.array.isSorted = function(e, t, r) { t = t || goog.array.defaultCompare; for (var o = 1; o < e.length; o++) { var i = t(e[o - 1], e[o]); if (0 < i || (0 == i && r)) return !1; } return !0; }), (goog.array.equals = function(e, t, r) { if (!goog.isArrayLike(e) || !goog.isArrayLike(t) || e.length != t.length) return !1; var o = e.length; r = r || goog.array.defaultCompareEquality; for (var i = 0; i < o; i++) if (!r(e[i], t[i])) return !1; return !0; }), (goog.array.compare3 = function(e, t, r) { r = r || goog.array.defaultCompare; for (var o = Math.min(e.length, t.length), i = 0; i < o; i++) { var a = r(e[i], t[i]); if (0 != a) return a; } return goog.array.defaultCompare(e.length, t.length); }), (goog.array.defaultCompare = function(e, t) { return e > t ? 1 : e < t ? -1 : 0; }), (goog.array.inverseDefaultCompare = function(e, t) { return -goog.array.defaultCompare(e, t); }), (goog.array.defaultCompareEquality = function(e, t) { return e === t; }), (goog.array.binaryInsert = function(e, t, r) { return ( 0 > (r = goog.array.binarySearch(e, t, r)) && (goog.array.insertAt(e, t, -(r + 1)), !0) ); }), (goog.array.binaryRemove = function(e, t, r) { return 0 <= (t = goog.array.binarySearch(e, t, r)) && goog.array.removeAt(e, t); }), (goog.array.bucket = function(e, t, r) { for (var o = {}, i = 0; i < e.length; i++) { var a = e[i], n = t.call(r, a, i, e); void 0 !== n && (o[n] || (o[n] = [])).push(a); } return o; }), (goog.array.toObject = function(e, t, r) { var o = {}; return ( goog.array.forEach(e, function(i, a) { o[t.call(r, i, a, e)] = i; }), o ); }), (goog.array.range = function(e, t, r) { var o = [], i = 0, a = e; if ((void 0 !== t && ((i = e), (a = t)), 0 > (r = r || 1) * (a - i))) return []; if (0 < r) for (e = i; e < a; e += r) o.push(e); else for (e = i; e > a; e += r) o.push(e); return o; }), (goog.array.repeat = function(e, t) { for (var r = [], o = 0; o < t; o++) r[o] = e; return r; }), (goog.array.flatten = function(e) { for (var t = [], r = 0; r < arguments.length; r++) { var o = arguments[r]; if (Array.isArray(o)) for (var i = 0; i < o.length; i += 8192) { var a = goog.array.slice(o, i, i + 8192); a = goog.array.flatten.apply(null, a); for (var n = 0; n < a.length; n++) t.push(a[n]); } else t.push(o); } return t; }), (goog.array.rotate = function(e, t) { return ( goog.asserts.assert(null != e.length), e.length && (0 < (t %= e.length) ? Array.prototype.unshift.apply(e, e.splice(-t, t)) : 0 > t && Array.prototype.push.apply(e, e.splice(0, -t))), e ); }), (goog.array.moveItem = function(e, t, r) { goog.asserts.assert(0 <= t && t < e.length), goog.asserts.assert(0 <= r && r < e.length), (t = Array.prototype.splice.call(e, t, 1)), Array.prototype.splice.call(e, r, 0, t[0]); }), (goog.array.zip = function(e) { if (!arguments.length) return []; for (var t = [], r = arguments[0].length, o = 1; o < arguments.length; o++) arguments[o].length < r && (r = arguments[o].length); for (o = 0; o < r; o++) { for (var i = [], a = 0; a < arguments.length; a++) i.push(arguments[a][o]); t.push(i); } return t; }), (goog.array.shuffle = function(e, t) { t = t || Math.random; for (var r = e.length - 1; 0 < r; r--) { var o = Math.floor(t() * (r + 1)), i = e[r]; (e[r] = e[o]), (e[o] = i); } }), (goog.array.copyByIndex = function(e, t) { var r = []; return ( goog.array.forEach(t, function(t) { r.push(e[t]); }), r ); }), (goog.array.concatMap = function(e, t, r) { return goog.array.concat.apply([], goog.array.map(e, t, r)); }), (goog.crypt = {}), (goog.crypt.stringToByteArray = function(e) { for (var t = [], r = 0, o = 0; o < e.length; o++) { var i = e.charCodeAt(o); 255 < i && ((t[r++] = 255 & i), (i >>= 8)), (t[r++] = i); } return t; }), (goog.crypt.byteArrayToString = function(e) { if (8192 >= e.length) return String.fromCharCode.apply(null, e); for (var t = '', r = 0; r < e.length; r += 8192) { var o = goog.array.slice(e, r, r + 8192); t += String.fromCharCode.apply(null, o); } return t; }), (goog.crypt.byteArrayToHex = function(e, t) { return goog.array .map(e, function(e) { return 1 < (e = e.toString(16)).length ? e : '0' + e; }) .join(t || ''); }), (goog.crypt.hexToByteArray = function(e) { goog.asserts.assert(0 == e.length % 2, 'Key string length must be multiple of 2'); for (var t = [], r = 0; r < e.length; r += 2) t.push(parseInt(e.substring(r, r + 2), 16)); return t; }), (goog.crypt.stringToUtf8ByteArray = function(e) { for (var t = [], r = 0, o = 0; o < e.length; o++) { var i = e.charCodeAt(o); 128 > i ? (t[r++] = i) : (2048 > i ? (t[r++] = (i >> 6) | 192) : (55296 == (64512 & i) && o + 1 < e.length && 56320 == (64512 & e.charCodeAt(o + 1)) ? ((i = 65536 + ((1023 & i) << 10) + (1023 & e.charCodeAt(++o))), (t[r++] = (i >> 18) | 240), (t[r++] = ((i >> 12) & 63) | 128)) : (t[r++] = (i >> 12) | 224), (t[r++] = ((i >> 6) & 63) | 128)), (t[r++] = (63 & i) | 128)); } return t; }), (goog.crypt.utf8ByteArrayToString = function(e) { for (var t = [], r = 0, o = 0; r < e.length; ) { var i = e[r++]; if (128 > i) t[o++] = String.fromCharCode(i); else if (191 < i && 224 > i) { var a = e[r++]; t[o++] = String.fromCharCode(((31 & i) << 6) | (63 & a)); } else if (239 < i && 365 > i) { a = e[r++]; var n = e[r++]; (i = (((7 & i) << 18) | ((63 & a) << 12) | ((63 & n) << 6) | (63 & e[r++])) - 65536), (t[o++] = String.fromCharCode(55296 + (i >> 10))), (t[o++] = String.fromCharCode(56320 + (1023 & i))); } else (a = e[r++]), (n = e[r++]), (t[o++] = String.fromCharCode( ((15 & i) << 12) | ((63 & a) << 6) | (63 & n) )); } return t.join(''); }), (goog.crypt.xorByteArray = function(e, t) { goog.asserts.assert(e.length == t.length, 'XOR array lengths must match'); for (var r = [], o = 0; o < e.length; o++) r.push(e[o] ^ t[o]); return r; }), (goog.dom.asserts = {}), (goog.dom.asserts.assertIsLocation = function(e) { if (goog.asserts.ENABLE_ASSERTS) { var t = goog.dom.asserts.getWindow_(e); t && (!e || (!(e instanceof t.Location) && e instanceof t.Element)) && goog.asserts.fail( 'Argument is not a Location (or a non-Element mock); got: %s', goog.dom.asserts.debugStringForType_(e) ); } return e; }), (goog.dom.asserts.assertIsElementType_ = function(e, t) { if (goog.asserts.ENABLE_ASSERTS) { var r = goog.dom.asserts.getWindow_(e); r && void 0 !== r[t] && ((e && (e instanceof r[t] || !(e instanceof r.Location || e instanceof r.Element))) || goog.asserts.fail( 'Argument is not a %s (or a non-Element, non-Location mock); got: %s', t, goog.dom.asserts.debugStringForType_(e) )); } return e; }), (goog.dom.asserts.assertIsHTMLAnchorElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLAnchorElement'); }), (goog.dom.asserts.assertIsHTMLButtonElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLButtonElement'); }), (goog.dom.asserts.assertIsHTMLLinkElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLLinkElement'); }), (goog.dom.asserts.assertIsHTMLImageElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLImageElement'); }), (goog.dom.asserts.assertIsHTMLAudioElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLAudioElement'); }), (goog.dom.asserts.assertIsHTMLVideoElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLVideoElement'); }), (goog.dom.asserts.assertIsHTMLInputElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLInputElement'); }), (goog.dom.asserts.assertIsHTMLTextAreaElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLTextAreaElement'); }), (goog.dom.asserts.assertIsHTMLCanvasElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLCanvasElement'); }), (goog.dom.asserts.assertIsHTMLEmbedElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLEmbedElement'); }), (goog.dom.asserts.assertIsHTMLFormElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLFormElement'); }), (goog.dom.asserts.assertIsHTMLFrameElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLFrameElement'); }), (goog.dom.asserts.assertIsHTMLIFrameElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLIFrameElement'); }), (goog.dom.asserts.assertIsHTMLObjectElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLObjectElement'); }), (goog.dom.asserts.assertIsHTMLScriptElement = function(e) { return goog.dom.asserts.assertIsElementType_(e, 'HTMLScriptElement'); }), (goog.dom.asserts.debugStringForType_ = function(e) { if (!goog.isObject(e)) return void 0 === e ? 'undefined' : null === e ? 'null' : typeof e; try { return ( e.constructor.displayName || e.constructor.name || Object.prototype.toString.call(e) ); } catch (e) { return ''; } }), (goog.dom.asserts.getWindow_ = function(e) { try { var t = e && e.ownerDocument, r = t && (t.defaultView || t.parentWindow); if ((r = r || goog.global).Element && r.Location) return r; } catch (e) {} return null; }), (goog.functions = {}), (goog.functions.constant = function(e) { return function() { return e; }; }), (goog.functions.FALSE = function() { return !1; }), (goog.functions.TRUE = function() { return !0; }), (goog.functions.NULL = function() { return null; }), (goog.functions.identity = function(e, t) { return e; }), (goog.functions.error = function(e) { return function() { throw Error(e); }; }), (goog.functions.fail = function(e) { return function() { throw e; }; }), (goog.functions.lock = function(e, t) { return ( (t = t || 0), function() { return e.apply(this, Array.prototype.slice.call(arguments, 0, t)); } ); }), (goog.functions.nth = function(e) { return function() { return arguments[e]; }; }), (goog.functions.partialRight = function(e, t) { var r = Array.prototype.slice.call(arguments, 1); return function() { var t = Array.prototype.slice.call(arguments); return t.push.apply(t, r), e.apply(this, t); }; }), (goog.functions.withReturnValue = function(e, t) { return goog.functions.sequence(e, goog.functions.constant(t)); }), (goog.functions.equalTo = function(e, t) { return function(r) { return t ? e == r : e === r; }; }), (goog.functions.compose = function(e, t) { var r = arguments, o = r.length; return function() { var e; o && (e = r[o - 1].apply(this, arguments)); for (var t = o - 2; 0 <= t; t--) e = r[t].call(this, e); return e; }; }), (goog.functions.sequence = function(e) { var t = arguments, r = t.length; return function() { for (var e, o = 0; o < r; o++) e = t[o].apply(this, arguments); return e; }; }), (goog.functions.and = function(e) { var t = arguments, r = t.length; return function() { for (var e = 0; e < r; e++) if (!t[e].apply(this, arguments)) return !1; return !0; }; }), (goog.functions.or = function(e) { var t = arguments, r = t.length; return function() { for (var e = 0; e < r; e++) if (t[e].apply(this, arguments)) return !0; return !1; }; }), (goog.functions.not = function(e) { return function() { return !e.apply(this, arguments); }; }), (goog.functions.create = function(e, t) { var r = function() {}; return ( (r.prototype = e.prototype), (r = new r()), e.apply(r, Array.prototype.slice.call(arguments, 1)), r ); }), (goog.functions.CACHE_RETURN_VALUE = !0), (goog.functions.cacheReturnValue = function(e) { var t, r = !1; return function() { return goog.functions.CACHE_RETURN_VALUE ? (r || ((t = e()), (r = !0)), t) : e(); }; }), (goog.functions.once = function(e) { var t = e; return function() { if (t) { var e = t; (t = null), e(); } }; }), (goog.functions.debounce = function(e, t, r) { var o = 0; return function(i) { goog.global.clearTimeout(o); var a = arguments; o = goog.global.setTimeout(function() { e.apply(r, a); }, t); }; }), (goog.functions.throttle = function(e, t, r) { var o = 0, i = !1, a = [], n = function() { (o = 0), i && ((i = !1), s()); }, s = function() { (o = goog.global.setTimeout(n, t)), e.apply(r, a); }; return function(e) { (a = arguments), o ? (i = !0) : s(); }; }), (goog.functions.rateLimit = function(e, t, r) { var o = 0, i = function() { o = 0; }; return function(a) { o || ((o = goog.global.setTimeout(i, t)), e.apply(r, arguments)); }; }), (goog.dom.HtmlElement = function() {}), (goog.dom.TagName = function(e) { this.tagName_ = e; }), (goog.dom.TagName.prototype.toString = function() { return this.tagName_; }), (goog.dom.TagName.A = new goog.dom.TagName('A')), (goog.dom.TagName.ABBR = new goog.dom.TagName('ABBR')), (goog.dom.TagName.ACRONYM = new goog.dom.TagName('ACRONYM')), (goog.dom.TagName.ADDRESS = new goog.dom.TagName('ADDRESS')), (goog.dom.TagName.APPLET = new goog.dom.TagName('APPLET')), (goog.dom.TagName.AREA = new goog.dom.TagName('AREA')), (goog.dom.TagName.ARTICLE = new goog.dom.TagName('ARTICLE')), (goog.dom.TagName.ASIDE = new goog.dom.TagName('ASIDE')), (goog.dom.TagName.AUDIO = new goog.dom.TagName('AUDIO')), (goog.dom.TagName.B = new goog.dom.TagName('B')), (goog.dom.TagName.BASE = new goog.dom.TagName('BASE')), (goog.dom.TagName.BASEFONT = new goog.dom.TagName('BASEFONT')), (goog.dom.TagName.BDI = new goog.dom.TagName('BDI')), (goog.dom.TagName.BDO = new goog.dom.TagName('BDO')), (goog.dom.TagName.BIG = new goog.dom.TagName('BIG')), (goog.dom.TagName.BLOCKQUOTE = new goog.dom.TagName('BLOCKQUOTE')), (goog.dom.TagName.BODY = new goog.dom.TagName('BODY')), (goog.dom.TagName.BR = new goog.dom.TagName('BR')), (goog.dom.TagName.BUTTON = new goog.dom.TagName('BUTTON')), (goog.dom.TagName.CANVAS = new goog.dom.TagName('CANVAS')), (goog.dom.TagName.CAPTION = new goog.dom.TagName('CAPTION')), (goog.dom.TagName.CENTER = new goog.dom.TagName('CENTER')), (goog.dom.TagName.CITE = new goog.dom.TagName('CITE')), (goog.dom.TagName.CODE = new goog.dom.TagName('CODE')), (goog.dom.TagName.COL = new goog.dom.TagName('COL')), (goog.dom.TagName.COLGROUP = new goog.dom.TagName('COLGROUP')), (goog.dom.TagName.COMMAND = new goog.dom.TagName('COMMAND')), (goog.dom.TagName.DATA = new goog.dom.TagName('DATA')), (goog.dom.TagName.DATALIST = new goog.dom.TagName('DATALIST')), (goog.dom.TagName.DD = new goog.dom.TagName('DD')), (goog.dom.TagName.DEL = new goog.dom.TagName('DEL')), (goog.dom.TagName.DETAILS = new goog.dom.TagName('DETAILS')), (goog.dom.TagName.DFN = new goog.dom.TagName('DFN')), (goog.dom.TagName.DIALOG = new goog.dom.TagName('DIALOG')), (goog.dom.TagName.DIR = new goog.dom.TagName('DIR')), (goog.dom.TagName.DIV = new goog.dom.TagName('DIV')), (goog.dom.TagName.DL = new goog.dom.TagName('DL')), (goog.dom.TagName.DT = new goog.dom.TagName('DT')), (goog.dom.TagName.EM = new goog.dom.TagName('EM')), (goog.dom.TagName.EMBED = new goog.dom.TagName('EMBED')), (goog.dom.TagName.FIELDSET = new goog.dom.TagName('FIELDSET')), (goog.dom.TagName.FIGCAPTION = new goog.dom.TagName('FIGCAPTION')), (goog.dom.TagName.FIGURE = new goog.dom.TagName('FIGURE')), (goog.dom.TagName.FONT = new goog.dom.TagName('FONT')), (goog.dom.TagName.FOOTER = new goog.dom.TagName('FOOTER')), (goog.dom.TagName.FORM = new goog.dom.TagName('FORM')), (goog.dom.TagName.FRAME = new goog.dom.TagName('FRAME')), (goog.dom.TagName.FRAMESET = new goog.dom.TagName('FRAMESET')), (goog.dom.TagName.H1 = new goog.dom.TagName('H1')), (goog.dom.TagName.H2 = new goog.dom.TagName('H2')), (goog.dom.TagName.H3 = new goog.dom.TagName('H3')), (goog.dom.TagName.H4 = new goog.dom.TagName('H4')), (goog.dom.TagName.H5 = new goog.dom.TagName('H5')), (goog.dom.TagName.H6 = new goog.dom.TagName('H6')), (goog.dom.TagName.HEAD = new goog.dom.TagName('HEAD')), (goog.dom.TagName.HEADER = new goog.dom.TagName('HEADER')), (goog.dom.TagName.HGROUP = new goog.dom.TagName('HGROUP')), (goog.dom.TagName.HR = new goog.dom.TagName('HR')), (goog.dom.TagName.HTML = new goog.dom.TagName('HTML')), (goog.dom.TagName.I = new goog.dom.TagName('I')), (goog.dom.TagName.IFRAME = new goog.dom.TagName('IFRAME')), (goog.dom.TagName.IMG = new goog.dom.TagName('IMG')), (goog.dom.TagName.INPUT = new goog.dom.TagName('INPUT')), (goog.dom.TagName.INS = new goog.dom.TagName('INS')), (goog.dom.TagName.ISINDEX = new goog.dom.TagName('ISINDEX')), (goog.dom.TagName.KBD = new goog.dom.TagName('KBD')), (goog.dom.TagName.KEYGEN = new goog.dom.TagName('KEYGEN')), (goog.dom.TagName.LABEL = new goog.dom.TagName('LABEL')), (goog.dom.TagName.LEGEND = new goog.dom.TagName('LEGEND')), (goog.dom.TagName.LI = new goog.dom.TagName('LI')), (goog.dom.TagName.LINK = new goog.dom.TagName('LINK')), (goog.dom.TagName.MAIN = new goog.dom.TagName('MAIN')), (goog.dom.TagName.MAP = new goog.dom.TagName('MAP')), (goog.dom.TagName.MARK = new goog.dom.TagName('MARK')), (goog.dom.TagName.MATH = new goog.dom.TagName('MATH')), (goog.dom.TagName.MENU = new goog.dom.TagName('MENU')), (goog.dom.TagName.MENUITEM = new goog.dom.TagName('MENUITEM')), (goog.dom.TagName.META = new goog.dom.TagName('META')), (goog.dom.TagName.METER = new goog.dom.TagName('METER')), (goog.dom.TagName.NAV = new goog.dom.TagName('NAV')), (goog.dom.TagName.NOFRAMES = new goog.dom.TagName('NOFRAMES')), (goog.dom.TagName.NOSCRIPT = new goog.dom.TagName('NOSCRIPT')), (goog.dom.TagName.OBJECT = new goog.dom.TagName('OBJECT')), (goog.dom.TagName.OL = new goog.dom.TagName('OL')), (goog.dom.TagName.OPTGROUP = new goog.dom.TagName('OPTGROUP')), (goog.dom.TagName.OPTION = new goog.dom.TagName('OPTION')), (goog.dom.TagName.OUTPUT = new goog.dom.TagName('OUTPUT')), (goog.dom.TagName.P = new goog.dom.TagName('P')), (goog.dom.TagName.PARAM = new goog.dom.TagName('PARAM')), (goog.dom.TagName.PICTURE = new goog.dom.TagName('PICTURE')), (goog.dom.TagName.PRE = new goog.dom.TagName('PRE')), (goog.dom.TagName.PROGRESS = new goog.dom.TagName('PROGRESS')), (goog.dom.TagName.Q = new goog.dom.TagName('Q')), (goog.dom.TagName.RP = new goog.dom.TagName('RP')), (goog.dom.TagName.RT = new goog.dom.TagName('RT')), (goog.dom.TagName.RTC = new goog.dom.TagName('RTC')), (goog.dom.TagName.RUBY = new goog.dom.TagName('RUBY')), (goog.dom.TagName.S = new goog.dom.TagName('S')), (goog.dom.TagName.SAMP = new goog.dom.TagName('SAMP')), (goog.dom.TagName.SCRIPT = new goog.dom.TagName('SCRIPT')), (goog.dom.TagName.SECTION = new goog.dom.TagName('SECTION')), (goog.dom.TagName.SELECT = new goog.dom.TagName('SELECT')), (goog.dom.TagName.SMALL = new goog.dom.TagName('SMALL')), (goog.dom.TagName.SOURCE = new goog.dom.TagName('SOURCE')), (goog.dom.TagName.SPAN = new goog.dom.TagName('SPAN')), (goog.dom.TagName.STRIKE = new goog.dom.TagName('STRIKE')), (goog.dom.TagName.STRONG = new goog.dom.TagName('STRONG')), (goog.dom.TagName.STYLE = new goog.dom.TagName('STYLE')), (goog.dom.TagName.SUB = new goog.dom.TagName('SUB')), (goog.dom.TagName.SUMMARY = new goog.dom.TagName('SUMMARY')), (goog.dom.TagName.SUP = new goog.dom.TagName('SUP')), (goog.dom.TagName.SVG = new goog.dom.TagName('SVG')), (goog.dom.TagName.TABLE = new goog.dom.TagName('TABLE')), (goog.dom.TagName.TBODY = new goog.dom.TagName('TBODY')), (goog.dom.TagName.TD = new goog.dom.TagName('TD')), (goog.dom.TagName.TEMPLATE = new goog.dom.TagName('TEMPLATE')), (goog.dom.TagName.TEXTAREA = new goog.dom.TagName('TEXTAREA')), (goog.dom.TagName.TFOOT = new goog.dom.TagName('TFOOT')), (goog.dom.TagName.TH = new goog.dom.TagName('TH')), (goog.dom.TagName.THEAD = new goog.dom.TagName('THEAD')), (goog.dom.TagName.TIME = new goog.dom.TagName('TIME')), (goog.dom.TagName.TITLE = new goog.dom.TagName('TITLE')), (goog.dom.TagName.TR = new goog.dom.TagName('TR')), (goog.dom.TagName.TRACK = new goog.dom.TagName('TRACK')), (goog.dom.TagName.TT = new goog.dom.TagName('TT')), (goog.dom.TagName.U = new goog.dom.TagName('U')), (goog.dom.TagName.UL = new goog.dom.TagName('UL')), (goog.dom.TagName.VAR = new goog.dom.TagName('VAR')), (goog.dom.TagName.VIDEO = new goog.dom.TagName('VIDEO')), (goog.dom.TagName.WBR = new goog.dom.TagName('WBR')), (goog.dom.tags = {}), (goog.dom.tags.VOID_TAGS_ = { area: !0, base: !0, br: !0, col: !0, command: !0, embed: !0, hr: !0, img: !0, input: !0, keygen: !0, link: !0, meta: !0, param: !0, source: !0, track: !0, wbr: !0, }), (goog.dom.tags.isVoidTag = function(e) { return !0 === goog.dom.tags.VOID_TAGS_[e]; }), (goog.html = {}), (goog.html.trustedtypes = {}), (goog.html.trustedtypes.PRIVATE_DO_NOT_ACCESS_OR_ELSE_POLICY = goog.TRUSTED_TYPES_POLICY_NAME ? goog.createTrustedTypesPolicy(goog.TRUSTED_TYPES_POLICY_NAME + '#html') : null), (goog.string = {}), (goog.string.TypedString = function() {}), (goog.string.Const = function(e, t) { (this.stringConstValueWithSecurityContract__googStringSecurityPrivate_ = (e === goog.string.Const.GOOG_STRING_CONSTRUCTOR_TOKEN_PRIVATE_ && t) || ''), (this.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ = goog.string.Const.TYPE_MARKER_); }), (goog.string.Const.prototype.implementsGoogStringTypedString = !0), (goog.string.Const.prototype.getTypedStringValue = function() { return this.stringConstValueWithSecurityContract__googStringSecurityPrivate_; }), goog.DEBUG && (goog.string.Const.prototype.toString = function() { return ( 'Const{' + this.stringConstValueWithSecurityContract__googStringSecurityPrivate_ + '}' ); }), (goog.string.Const.unwrap = function(e) { return e instanceof goog.string.Const && e.constructor === goog.string.Const && e.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ === goog.string.Const.TYPE_MARKER_ ? e.stringConstValueWithSecurityContract__googStringSecurityPrivate_ : (goog.asserts.fail("expected object of type Const, got '" + e + "'"), 'type_error:Const'); }), (goog.string.Const.from = function(e) { return new goog.string.Const( goog.string.Const.GOOG_STRING_CONSTRUCTOR_TOKEN_PRIVATE_, e ); }), (goog.string.Const.TYPE_MARKER_ = {}), (goog.string.Const.GOOG_STRING_CONSTRUCTOR_TOKEN_PRIVATE_ = {}), (goog.string.Const.EMPTY = goog.string.Const.from('')), (goog.html.SafeScript = function() { (this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = ''), (this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_); }), (goog.html.SafeScript.prototype.implementsGoogStringTypedString = !0), (goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}), (goog.html.SafeScript.fromConstant = function(e) { return 0 === (e = goog.string.Const.unwrap(e)).length ? goog.html.SafeScript.EMPTY : goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(e); }), (goog.html.SafeScript.fromConstantAndArgs = function(e, t) { for (var r = [], o = 1; o < arguments.length; o++) r.push(goog.html.SafeScript.stringify_(arguments[o])); return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse( '(' + goog.string.Const.unwrap(e) + ')(' + r.join(', ') + ');' ); }), (goog.html.SafeScript.fromJson = function(e) { return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse( goog.html.SafeScript.stringify_(e) ); }), (goog.html.SafeScript.prototype.getTypedStringValue = function() { return this.privateDoNotAccessOrElseSafeScriptWrappedValue_.toString(); }), goog.DEBUG && (goog.html.SafeScript.prototype.toString = function() { return 'SafeScript{' + this.privateDoNotAccessOrElseSafeScriptWrappedValue_ + '}'; }), (goog.html.SafeScript.unwrap = function(e) { return goog.html.SafeScript.unwrapTrustedScript(e).toString(); }), (goog.html.SafeScript.unwrapTrustedScript = function(e) { return e instanceof goog.html.SafeScript && e.constructor === goog.html.SafeScript && e.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ? e.privateDoNotAccessOrElseSafeScriptWrappedValue_ : (goog.asserts.fail( "expected object of type SafeScript, got '" + e + "' of type " + goog.typeOf(e) ), 'type_error:SafeScript'); }), (goog.html.SafeScript.stringify_ = function(e) { return JSON.stringify(e).replace(/ e ? goog.i18n.bidi.Dir.RTL : t ? null : goog.i18n.bidi.Dir.NEUTRAL : null == e ? null : e ? goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR; }), (goog.i18n.bidi.ltrChars_ = 'A-Za-zÀ-ÖØ-öø-ʸ̀-֐ऀ-῿‎Ⰰ-\ud801\ud804-\ud839\ud83c-\udbff豈-﬜︀-﹯﻽-￿'), (goog.i18n.bidi.rtlChars_ = '֑-ۯۺ-ࣿ‏\ud802-\ud803\ud83a-\ud83bיִ-﷿ﹰ-ﻼ'), (goog.i18n.bidi.htmlSkipReg_ = /<[^>]*>|&[^;]+;/g), (goog.i18n.bidi.stripHtmlIfNeeded_ = function(e, t) { return t ? e.replace(goog.i18n.bidi.htmlSkipReg_, '') : e; }), (goog.i18n.bidi.rtlCharReg_ = new RegExp('[' + goog.i18n.bidi.rtlChars_ + ']')), (goog.i18n.bidi.ltrCharReg_ = new RegExp('[' + goog.i18n.bidi.ltrChars_ + ']')), (goog.i18n.bidi.hasAnyRtl = function(e, t) { return goog.i18n.bidi.rtlCharReg_.test(goog.i18n.bidi.stripHtmlIfNeeded_(e, t)); }), (goog.i18n.bidi.hasRtlChar = goog.i18n.bidi.hasAnyRtl), (goog.i18n.bidi.hasAnyLtr = function(e, t) { return goog.i18n.bidi.ltrCharReg_.test(goog.i18n.bidi.stripHtmlIfNeeded_(e, t)); }), (goog.i18n.bidi.ltrRe_ = new RegExp('^[' + goog.i18n.bidi.ltrChars_ + ']')), (goog.i18n.bidi.rtlRe_ = new RegExp('^[' + goog.i18n.bidi.rtlChars_ + ']')), (goog.i18n.bidi.isRtlChar = function(e) { return goog.i18n.bidi.rtlRe_.test(e); }), (goog.i18n.bidi.isLtrChar = function(e) { return goog.i18n.bidi.ltrRe_.test(e); }), (goog.i18n.bidi.isNeutralChar = function(e) { return !goog.i18n.bidi.isLtrChar(e) && !goog.i18n.bidi.isRtlChar(e); }), (goog.i18n.bidi.ltrDirCheckRe_ = new RegExp( '^[^' + goog.i18n.bidi.rtlChars_ + ']*[' + goog.i18n.bidi.ltrChars_ + ']' )), (goog.i18n.bidi.rtlDirCheckRe_ = new RegExp( '^[^' + goog.i18n.bidi.ltrChars_ + ']*[' + goog.i18n.bidi.rtlChars_ + ']' )), (goog.i18n.bidi.startsWithRtl = function(e, t) { return goog.i18n.bidi.rtlDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(e, t)); }), (goog.i18n.bidi.isRtlText = goog.i18n.bidi.startsWithRtl), (goog.i18n.bidi.startsWithLtr = function(e, t) { return goog.i18n.bidi.ltrDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(e, t)); }), (goog.i18n.bidi.isLtrText = goog.i18n.bidi.startsWithLtr), (goog.i18n.bidi.isRequiredLtrRe_ = /^http:\/\/.*/), (goog.i18n.bidi.isNeutralText = function(e, t) { return ( (e = goog.i18n.bidi.stripHtmlIfNeeded_(e, t)), goog.i18n.bidi.isRequiredLtrRe_.test(e) || (!goog.i18n.bidi.hasAnyLtr(e) && !goog.i18n.bidi.hasAnyRtl(e)) ); }), (goog.i18n.bidi.ltrExitDirCheckRe_ = new RegExp( '[' + goog.i18n.bidi.ltrChars_ + '][^' + goog.i18n.bidi.rtlChars_ + ']*$' )), (goog.i18n.bidi.rtlExitDirCheckRe_ = new RegExp( '[' + goog.i18n.bidi.rtlChars_ + '][^' + goog.i18n.bidi.ltrChars_ + ']*$' )), (goog.i18n.bidi.endsWithLtr = function(e, t) { return goog.i18n.bidi.ltrExitDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(e, t)); }), (goog.i18n.bidi.isLtrExitText = goog.i18n.bidi.endsWithLtr), (goog.i18n.bidi.endsWithRtl = function(e, t) { return goog.i18n.bidi.rtlExitDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(e, t)); }), (goog.i18n.bidi.isRtlExitText = goog.i18n.bidi.endsWithRtl), (goog.i18n.bidi.rtlLocalesRe_ = /^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_](Adlm|Arab|Hebr|Nkoo|Rohg|Thaa))(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)/i), (goog.i18n.bidi.isRtlLanguage = function(e) { return goog.i18n.bidi.rtlLocalesRe_.test(e); }), (goog.i18n.bidi.bracketGuardTextRe_ = /(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)/g), (goog.i18n.bidi.guardBracketInText = function(e, t) { return ( (t = (void 0 === t ? goog.i18n.bidi.hasAnyRtl(e) : t) ? goog.i18n.bidi.Format.RLM : goog.i18n.bidi.Format.LRM), e.replace(goog.i18n.bidi.bracketGuardTextRe_, t + '$&' + t) ); }), (goog.i18n.bidi.enforceRtlInHtml = function(e) { return '<' == e.charAt(0) ? e.replace(/<\w+/, '$& dir=rtl') : '\n' + e + ''; }), (goog.i18n.bidi.enforceRtlInText = function(e) { return goog.i18n.bidi.Format.RLE + e + goog.i18n.bidi.Format.PDF; }), (goog.i18n.bidi.enforceLtrInHtml = function(e) { return '<' == e.charAt(0) ? e.replace(/<\w+/, '$& dir=ltr') : '\n' + e + ''; }), (goog.i18n.bidi.enforceLtrInText = function(e) { return goog.i18n.bidi.Format.LRE + e + goog.i18n.bidi.Format.PDF; }), (goog.i18n.bidi.dimensionsRe_ = /:\s*([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)/g), (goog.i18n.bidi.leftRe_ = /left/gi), (goog.i18n.bidi.rightRe_ = /right/gi), (goog.i18n.bidi.tempRe_ = /%%%%/g), (goog.i18n.bidi.mirrorCSS = function(e) { return e .replace(goog.i18n.bidi.dimensionsRe_, ':$1 $4 $3 $2') .replace(goog.i18n.bidi.leftRe_, '%%%%') .replace(goog.i18n.bidi.rightRe_, goog.i18n.bidi.LEFT) .replace(goog.i18n.bidi.tempRe_, goog.i18n.bidi.RIGHT); }), (goog.i18n.bidi.doubleQuoteSubstituteRe_ = /([\u0591-\u05f2])"/g), (goog.i18n.bidi.singleQuoteSubstituteRe_ = /([\u0591-\u05f2])'/g), (goog.i18n.bidi.normalizeHebrewQuote = function(e) { return e .replace(goog.i18n.bidi.doubleQuoteSubstituteRe_, '$1״') .replace(goog.i18n.bidi.singleQuoteSubstituteRe_, '$1׳'); }), (goog.i18n.bidi.wordSeparatorRe_ = /\s+/), (goog.i18n.bidi.hasNumeralsRe_ = /[\d\u06f0-\u06f9]/), (goog.i18n.bidi.rtlDetectionThreshold_ = 0.4), (goog.i18n.bidi.estimateDirection = function(e, t) { var r = 0, o = 0, i = !1; for ( e = goog.i18n.bidi.stripHtmlIfNeeded_(e, t).split(goog.i18n.bidi.wordSeparatorRe_), t = 0; t < e.length; t++ ) { var a = e[t]; goog.i18n.bidi.startsWithRtl(a) ? (r++, o++) : goog.i18n.bidi.isRequiredLtrRe_.test(a) ? (i = !0) : goog.i18n.bidi.hasAnyLtr(a) ? o++ : goog.i18n.bidi.hasNumeralsRe_.test(a) && (i = !0); } return 0 == o ? i ? goog.i18n.bidi.Dir.LTR : goog.i18n.bidi.Dir.NEUTRAL : r / o > goog.i18n.bidi.rtlDetectionThreshold_ ? goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR; }), (goog.i18n.bidi.detectRtlDirectionality = function(e, t) { return goog.i18n.bidi.estimateDirection(e, t) == goog.i18n.bidi.Dir.RTL; }), (goog.i18n.bidi.setElementDirAndAlign = function(e, t) { e && (t = goog.i18n.bidi.toDir(t)) && ((e.style.textAlign = t == goog.i18n.bidi.Dir.RTL ? goog.i18n.bidi.RIGHT : goog.i18n.bidi.LEFT), (e.dir = t == goog.i18n.bidi.Dir.RTL ? 'rtl' : 'ltr')); }), (goog.i18n.bidi.setElementDirByTextDirectionality = function(e, t) { switch (goog.i18n.bidi.estimateDirection(t)) { case goog.i18n.bidi.Dir.LTR: e.dir = 'ltr'; break; case goog.i18n.bidi.Dir.RTL: e.dir = 'rtl'; break; default: e.removeAttribute('dir'); } }), (goog.i18n.bidi.DirectionalString = function() {}), (goog.html.TrustedResourceUrl = function(e, t) { (this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ = (e === goog.html.TrustedResourceUrl.CONSTRUCTOR_TOKEN_PRIVATE_ && t) || ''), (this.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_); }), (goog.html.TrustedResourceUrl.prototype.implementsGoogStringTypedString = !0), (goog.html.TrustedResourceUrl.prototype.getTypedStringValue = function() { return this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_.toString(); }), (goog.html.TrustedResourceUrl.prototype.implementsGoogI18nBidiDirectionalString = !0), (goog.html.TrustedResourceUrl.prototype.getDirection = function() { return goog.i18n.bidi.Dir.LTR; }), (goog.html.TrustedResourceUrl.prototype.cloneWithParams = function(e, t) { var r = goog.html.TrustedResourceUrl.unwrap(this), o = (r = goog.html.TrustedResourceUrl.URL_PARAM_PARSER_.exec(r))[3] || ''; return goog.html.TrustedResourceUrl.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse( r[1] + goog.html.TrustedResourceUrl.stringifyParams_('?', r[2] || '', e) + goog.html.TrustedResourceUrl.stringifyParams_('#', o, t) ); }), goog.DEBUG && (goog.html.TrustedResourceUrl.prototype.toString = function() { return ( 'TrustedResourceUrl{' + this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ + '}' ); }), (goog.html.TrustedResourceUrl.unwrap = function(e) { return goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(e).toString(); }), (goog.html.TrustedResourceUrl.unwrapTrustedScriptURL = function(e) { return e instanceof goog.html.TrustedResourceUrl && e.constructor === goog.html.TrustedResourceUrl && e.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ? e.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ : (goog.asserts.fail( "expected object of type TrustedResourceUrl, got '" + e + "' of type " + goog.typeOf(e) ), 'type_error:TrustedResourceUrl'); }), (goog.html.TrustedResourceUrl.format = function(e, t) { var r = goog.string.Const.unwrap(e); if (!goog.html.TrustedResourceUrl.BASE_URL_.test(r)) throw Error('Invalid TrustedResourceUrl format: ' + r); return ( (e = r.replace(goog.html.TrustedResourceUrl.FORMAT_MARKER_, function(e, o) { if (!Object.prototype.hasOwnProperty.call(t, o)) throw Error( 'Found marker, "' + o + '", in format string, "' + r + '", but no valid label mapping found in args: ' + JSON.stringify(t) ); return (e = t[o]) instanceof goog.string.Const ? goog.string.Const.unwrap(e) : encodeURIComponent(String(e)); })), goog.html.TrustedResourceUrl.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse( e ) ); }), (goog.html.TrustedResourceUrl.FORMAT_MARKER_ = /%{(\w+)}/g), (goog.html.TrustedResourceUrl.BASE_URL_ = /^((https:)?\/\/[0-9a-z.:[\]-]+\/|\/[^/\\]|[^:/\\%]+\/|[^:/\\%]*[?#]|about:blank#)/i), (goog.html.TrustedResourceUrl.URL_PARAM_PARSER_ = /^([^?#]*)(\?[^#]*)?(#[\s\S]*)?/), (goog.html.TrustedResourceUrl.formatWithParams = function(e, t, r, o) { return goog.html.TrustedResourceUrl.format(e, t).cloneWithParams(r, o); }), (goog.html.TrustedResourceUrl.fromConstant = function(e) { return goog.html.TrustedResourceUrl.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse( goog.string.Const.unwrap(e) ); }), (goog.html.TrustedResourceUrl.fromConstants = function(e) { for (var t = '', r = 0; r < e.length; r++) t += goog.string.Const.unwrap(e[r]); return goog.html.TrustedResourceUrl.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse( t ); }), (goog.html.TrustedResourceUrl.fromSafeScript = function(e) { return ( (e = goog.fs.blob.getBlobWithProperties( [goog.html.SafeScript.unwrap(e)], 'text/javascript' )), (e = goog.fs.url.createObjectUrl(e)), goog.html.TrustedResourceUrl.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse( e ) ); }), (goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}), (goog.html.TrustedResourceUrl.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse = function( e ) { return ( (e = goog.html.trustedtypes.PRIVATE_DO_NOT_ACCESS_OR_ELSE_POLICY ? goog.html.trustedtypes.PRIVATE_DO_NOT_ACCESS_OR_ELSE_POLICY.createScriptURL(e) : e), new goog.html.TrustedResourceUrl( goog.html.TrustedResourceUrl.CONSTRUCTOR_TOKEN_PRIVATE_, e ) ); }), (goog.html.TrustedResourceUrl.stringifyParams_ = function(e, t, r) { if (null == r) return t; if ('string' == typeof r) return r ? e + encodeURIComponent(r) : ''; for (var o in r) { var i = r[o]; i = Array.isArray(i) ? i : [i]; for (var a = 0; a < i.length; a++) { var n = i[a]; null != n && (t || (t = e), (t += (t.length > e.length ? '&' : '') + encodeURIComponent(o) + '=' + encodeURIComponent(String(n)))); } } return t; }), (goog.html.TrustedResourceUrl.CONSTRUCTOR_TOKEN_PRIVATE_ = {}), (goog.string.internal = {}), (goog.string.internal.startsWith = function(e, t) { return 0 == e.lastIndexOf(t, 0); }), (goog.string.internal.endsWith = function(e, t) { var r = e.length - t.length; return 0 <= r && e.indexOf(t, r) == r; }), (goog.string.internal.caseInsensitiveStartsWith = function(e, t) { return 0 == goog.string.internal.caseInsensitiveCompare(t, e.substr(0, t.length)); }), (goog.string.internal.caseInsensitiveEndsWith = function(e, t) { return ( 0 == goog.string.internal.caseInsensitiveCompare( t, e.substr(e.length - t.length, t.length) ) ); }), (goog.string.internal.caseInsensitiveEquals = function(e, t) { return e.toLowerCase() == t.toLowerCase(); }), (goog.string.internal.isEmptyOrWhitespace = function(e) { return /^[\s\xa0]*$/.test(e); }), (goog.string.internal.trim = goog.TRUSTED_SITE && String.prototype.trim ? function(e) { return e.trim(); } : function(e) { return /^[\s\xa0]*([\s\S]*?)[\s\xa0]*$/.exec(e)[1]; }), (goog.string.internal.caseInsensitiveCompare = function(e, t) { return (e = String(e).toLowerCase()) < (t = String(t).toLowerCase()) ? -1 : e == t ? 0 : 1; }), (goog.string.internal.newLineToBr = function(e, t) { return e.replace(/(\r\n|\r|\n)/g, t ? '
' : '
'); }), (goog.string.internal.htmlEscape = function(e, t) { if (t) e = e .replace(goog.string.internal.AMP_RE_, '&') .replace(goog.string.internal.LT_RE_, '<') .replace(goog.string.internal.GT_RE_, '>') .replace(goog.string.internal.QUOT_RE_, '"') .replace(goog.string.internal.SINGLE_QUOTE_RE_, ''') .replace(goog.string.internal.NULL_RE_, '�'); else { if (!goog.string.internal.ALL_RE_.test(e)) return e; -1 != e.indexOf('&') && (e = e.replace(goog.string.internal.AMP_RE_, '&')), -1 != e.indexOf('<') && (e = e.replace(goog.string.internal.LT_RE_, '<')), -1 != e.indexOf('>') && (e = e.replace(goog.string.internal.GT_RE_, '>')), -1 != e.indexOf('"') && (e = e.replace(goog.string.internal.QUOT_RE_, '"')), -1 != e.indexOf("'") && (e = e.replace(goog.string.internal.SINGLE_QUOTE_RE_, ''')), -1 != e.indexOf('\0') && (e = e.replace(goog.string.internal.NULL_RE_, '�')); } return e; }), (goog.string.internal.AMP_RE_ = /&/g), (goog.string.internal.LT_RE_ = //g), (goog.string.internal.QUOT_RE_ = /"/g), (goog.string.internal.SINGLE_QUOTE_RE_ = /'/g), (goog.string.internal.NULL_RE_ = /\x00/g), (goog.string.internal.ALL_RE_ = /[\x00&<>"']/), (goog.string.internal.whitespaceEscape = function(e, t) { return goog.string.internal.newLineToBr(e.replace(/ /g, '  '), t); }), (goog.string.internal.contains = function(e, t) { return -1 != e.indexOf(t); }), (goog.string.internal.caseInsensitiveContains = function(e, t) { return goog.string.internal.contains(e.toLowerCase(), t.toLowerCase()); }), (goog.string.internal.compareVersions = function(e, t) { var r = 0; (e = goog.string.internal.trim(String(e)).split('.')), (t = goog.string.internal.trim(String(t)).split('.')); for (var o = Math.max(e.length, t.length), i = 0; 0 == r && i < o; i++) { var a = e[i] || '', n = t[i] || ''; do { if ( ((a = /(\d*)(\D*)(.*)/.exec(a) || ['', '', '', '']), (n = /(\d*)(\D*)(.*)/.exec(n) || ['', '', '', '']), 0 == a[0].length && 0 == n[0].length) ) break; r = 0 == a[1].length ? 0 : parseInt(a[1], 10); var s = 0 == n[1].length ? 0 : parseInt(n[1], 10); (r = goog.string.internal.compareElements_(r, s) || goog.string.internal.compareElements_(0 == a[2].length, 0 == n[2].length) || goog.string.internal.compareElements_(a[2], n[2])), (a = a[3]), (n = n[3]); } while (0 == r); } return r; }), (goog.string.internal.compareElements_ = function(e, t) { return e < t ? -1 : e > t ? 1 : 0; }), (goog.html.SafeUrl = function(e, t) { (this.privateDoNotAccessOrElseSafeUrlWrappedValue_ = (e === goog.html.SafeUrl.CONSTRUCTOR_TOKEN_PRIVATE_ && t) || ''), (this.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_); }), (goog.html.SafeUrl.INNOCUOUS_STRING = 'about:invalid#zClosurez'), (goog.html.SafeUrl.prototype.implementsGoogStringTypedString = !0), (goog.html.SafeUrl.prototype.getTypedStringValue = function() { return this.privateDoNotAccessOrElseSafeUrlWrappedValue_.toString(); }), (goog.html.SafeUrl.prototype.implementsGoogI18nBidiDirectionalString = !0), (goog.html.SafeUrl.prototype.getDirection = function() { return goog.i18n.bidi.Dir.LTR; }), goog.DEBUG && (goog.html.SafeUrl.prototype.toString = function() { return 'SafeUrl{' + this.privateDoNotAccessOrElseSafeUrlWrappedValue_ + '}'; }), (goog.html.SafeUrl.unwrap = function(e) { return e instanceof goog.html.SafeUrl && e.constructor === goog.html.SafeUrl && e.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ? e.privateDoNotAccessOrElseSafeUrlWrappedValue_ : (goog.asserts.fail( "expected object of type SafeUrl, got '" + e + "' of type " + goog.typeOf(e) ), 'type_error:SafeUrl'); }), (goog.html.SafeUrl.fromConstant = function(e) { return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse( goog.string.Const.unwrap(e) ); }), (goog.html.SAFE_MIME_TYPE_PATTERN_ = /^(?:audio\/(?:3gpp2|3gpp|aac|L16|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-matroska|x-wav|wav|webm)|image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp|x-icon)|text\/csv|video\/(?:mpeg|mp4|ogg|webm|quicktime|x-matroska))(?:;\w+=(?:\w+|"[\w;,= ]+"))*$/i), (goog.html.SafeUrl.isSafeMimeType = function(e) { return goog.html.SAFE_MIME_TYPE_PATTERN_.test(e); }), (goog.html.SafeUrl.fromBlob = function(e) { return ( (e = goog.html.SafeUrl.isSafeMimeType(e.type) ? goog.fs.url.createObjectUrl(e) : goog.html.SafeUrl.INNOCUOUS_STRING), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(e) ); }), (goog.html.SafeUrl.fromMediaSource = function(e) { return ( goog.asserts.assert('MediaSource' in goog.global, 'No support for MediaSource'), (e = e instanceof MediaSource ? goog.fs.url.createObjectUrl(e) : goog.html.SafeUrl.INNOCUOUS_STRING), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(e) ); }), (goog.html.DATA_URL_PATTERN_ = /^data:(.*);base64,[a-z0-9+\/]+=*$/i), (goog.html.SafeUrl.fromDataUrl = function(e) { var t = (e = e.replace(/(%0A|%0D)/g, '')).match(goog.html.DATA_URL_PATTERN_); return ( (t = t && goog.html.SafeUrl.isSafeMimeType(t[1])), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse( t ? e : goog.html.SafeUrl.INNOCUOUS_STRING ) ); }), (goog.html.SafeUrl.fromTelUrl = function(e) { return ( goog.string.internal.caseInsensitiveStartsWith(e, 'tel:') || (e = goog.html.SafeUrl.INNOCUOUS_STRING), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(e) ); }), (goog.html.SIP_URL_PATTERN_ = /^sip[s]?:[+a-z0-9_.!$%&'*\/=^`{|}~-]+@([a-z0-9-]+\.)+[a-z0-9]{2,63}$/i), (goog.html.SafeUrl.fromSipUrl = function(e) { return ( goog.html.SIP_URL_PATTERN_.test(decodeURIComponent(e)) || (e = goog.html.SafeUrl.INNOCUOUS_STRING), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(e) ); }), (goog.html.SafeUrl.fromFacebookMessengerUrl = function(e) { return ( goog.string.internal.caseInsensitiveStartsWith(e, 'fb-messenger://share') || (e = goog.html.SafeUrl.INNOCUOUS_STRING), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(e) ); }), (goog.html.SafeUrl.fromWhatsAppUrl = function(e) { return ( goog.string.internal.caseInsensitiveStartsWith(e, 'whatsapp://send') || (e = goog.html.SafeUrl.INNOCUOUS_STRING), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(e) ); }), (goog.html.SafeUrl.fromSmsUrl = function(e) { return ( (goog.string.internal.caseInsensitiveStartsWith(e, 'sms:') && goog.html.SafeUrl.isSmsUrlBodyValid_(e)) || (e = goog.html.SafeUrl.INNOCUOUS_STRING), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(e) ); }), (goog.html.SafeUrl.isSmsUrlBodyValid_ = function(e) { var t = e.indexOf('#'); if ((0 < t && (e = e.substring(0, t)), !(t = e.match(/[?&]body=/gi)))) return !0; if (1 < t.length) return !1; if (!(e = e.match(/[?&]body=([^&]*)/)[1])) return !0; try { decodeURIComponent(e); } catch (e) { return !1; } return /^(?:[a-z0-9\-_.~]|%[0-9a-f]{2})+$/i.test(e); }), (goog.html.SafeUrl.fromSshUrl = function(e) { return ( goog.string.internal.caseInsensitiveStartsWith(e, 'ssh://') || (e = goog.html.SafeUrl.INNOCUOUS_STRING), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(e) ); }), (goog.html.SafeUrl.sanitizeChromeExtensionUrl = function(e, t) { return goog.html.SafeUrl.sanitizeExtensionUrl_( /^chrome-extension:\/\/([^\/]+)\//, e, t ); }), (goog.html.SafeUrl.sanitizeFirefoxExtensionUrl = function(e, t) { return goog.html.SafeUrl.sanitizeExtensionUrl_(/^moz-extension:\/\/([^\/]+)\//, e, t); }), (goog.html.SafeUrl.sanitizeEdgeExtensionUrl = function(e, t) { return goog.html.SafeUrl.sanitizeExtensionUrl_( /^ms-browser-extension:\/\/([^\/]+)\//, e, t ); }), (goog.html.SafeUrl.sanitizeExtensionUrl_ = function(e, t, r) { return ( (e = e.exec(t)) ? ((e = e[1]), -1 == (r instanceof goog.string.Const ? [goog.string.Const.unwrap(r)] : r.map(function(e) { return goog.string.Const.unwrap(e); }) ).indexOf(e) && (t = goog.html.SafeUrl.INNOCUOUS_STRING)) : (t = goog.html.SafeUrl.INNOCUOUS_STRING), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(t) ); }), (goog.html.SafeUrl.fromTrustedResourceUrl = function(e) { return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse( goog.html.TrustedResourceUrl.unwrap(e) ); }), (goog.html.SAFE_URL_PATTERN_ = /^(?:(?:https?|mailto|ftp):|[^:/?#]*(?:[/?#]|$))/i), (goog.html.SafeUrl.SAFE_URL_PATTERN = goog.html.SAFE_URL_PATTERN_), (goog.html.SafeUrl.sanitize = function(e) { return e instanceof goog.html.SafeUrl ? e : ((e = 'object' == typeof e && e.implementsGoogStringTypedString ? e.getTypedStringValue() : String(e)), goog.html.SAFE_URL_PATTERN_.test(e) || (e = goog.html.SafeUrl.INNOCUOUS_STRING), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(e)); }), (goog.html.SafeUrl.sanitizeAssertUnchanged = function(e, t) { return e instanceof goog.html.SafeUrl ? e : ((e = 'object' == typeof e && e.implementsGoogStringTypedString ? e.getTypedStringValue() : String(e)), t && /^data:/i.test(e) && (t = goog.html.SafeUrl.fromDataUrl(e)).getTypedStringValue() == e ? t : (goog.asserts.assert( goog.html.SAFE_URL_PATTERN_.test(e), '%s does not match the safe URL pattern', e ) || (e = goog.html.SafeUrl.INNOCUOUS_STRING), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(e))); }), (goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}), (goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse = function(e) { return new goog.html.SafeUrl(goog.html.SafeUrl.CONSTRUCTOR_TOKEN_PRIVATE_, e); }), (goog.html.SafeUrl.ABOUT_BLANK = goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse( 'about:blank' )), (goog.html.SafeUrl.CONSTRUCTOR_TOKEN_PRIVATE_ = {}), (goog.html.SafeStyle = function() { (this.privateDoNotAccessOrElseSafeStyleWrappedValue_ = ''), (this.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_); }), (goog.html.SafeStyle.prototype.implementsGoogStringTypedString = !0), (goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}), (goog.html.SafeStyle.fromConstant = function(e) { return 0 === (e = goog.string.Const.unwrap(e)).length ? goog.html.SafeStyle.EMPTY : (goog.asserts.assert( goog.string.internal.endsWith(e, ';'), "Last character of style string is not ';': " + e ), goog.asserts.assert( goog.string.internal.contains(e, ':'), 'Style string must contain at least one \':\', to specify a "name: value" pair: ' + e ), goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(e)); }), (goog.html.SafeStyle.prototype.getTypedStringValue = function() { return this.privateDoNotAccessOrElseSafeStyleWrappedValue_; }), goog.DEBUG && (goog.html.SafeStyle.prototype.toString = function() { return 'SafeStyle{' + this.privateDoNotAccessOrElseSafeStyleWrappedValue_ + '}'; }), (goog.html.SafeStyle.unwrap = function(e) { return e instanceof goog.html.SafeStyle && e.constructor === goog.html.SafeStyle && e.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ === goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ? e.privateDoNotAccessOrElseSafeStyleWrappedValue_ : (goog.asserts.fail( "expected object of type SafeStyle, got '" + e + "' of type " + goog.typeOf(e) ), 'type_error:SafeStyle'); }), (goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse = function(e) { return new goog.html.SafeStyle().initSecurityPrivateDoNotAccessOrElse_(e); }), (goog.html.SafeStyle.prototype.initSecurityPrivateDoNotAccessOrElse_ = function(e) { return (this.privateDoNotAccessOrElseSafeStyleWrappedValue_ = e), this; }), (goog.html.SafeStyle.EMPTY = goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse( '' )), (goog.html.SafeStyle.INNOCUOUS_STRING = 'zClosurez'), (goog.html.SafeStyle.create = function(e) { var t, r = ''; for (t in e) { if (!/^[-_a-zA-Z0-9]+$/.test(t)) throw Error('Name allows only [-_a-zA-Z0-9], got: ' + t); var o = e[t]; null != o && (r += t + ':' + (o = Array.isArray(o) ? goog.array .map(o, goog.html.SafeStyle.sanitizePropertyValue_) .join(' ') : goog.html.SafeStyle.sanitizePropertyValue_(o)) + ';'); } return r ? goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(r) : goog.html.SafeStyle.EMPTY; }), (goog.html.SafeStyle.sanitizePropertyValue_ = function(e) { if (e instanceof goog.html.SafeUrl) return ( 'url("' + goog.html.SafeUrl.unwrap(e) .replace(/+~[\]()=^$|]+$/.test(r)) throw Error( 'Selector allows only [-_a-zA-Z0-9#.:* ,>+~[\\]()=^$|] and strings, got: ' + e ); if (!goog.html.SafeStyleSheet.hasBalancedBrackets_(r)) throw Error('() and [] in selector must be balanced, got: ' + e); return ( t instanceof goog.html.SafeStyle || (t = goog.html.SafeStyle.create(t)), (e = e + '{' + goog.html.SafeStyle.unwrap(t).replace(/.' : '' ); if (e.toUpperCase() in goog.html.SafeHtml.NOT_ALLOWED_TAG_NAMES_) throw Error( goog.html.SafeHtml.ENABLE_ERROR_MESSAGES ? 'Tag name <' + e + '> is not allowed for SafeHtml.' : '' ); }), (goog.html.SafeHtml.createIframe = function(e, t, r, o) { e && goog.html.TrustedResourceUrl.unwrap(e); var i = {}; return ( (i.src = e || null), (i.srcdoc = t && goog.html.SafeHtml.unwrap(t)), (e = goog.html.SafeHtml.combineAttributes(i, { sandbox: '' }, r)), goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse('iframe', e, o) ); }), (goog.html.SafeHtml.createSandboxIframe = function(e, t, r, o) { if (!goog.html.SafeHtml.canUseSandboxIframe()) throw Error( goog.html.SafeHtml.ENABLE_ERROR_MESSAGES ? 'The browser does not support sandboxed iframes.' : '' ); var i = {}; return ( (i.src = e ? goog.html.SafeUrl.unwrap(goog.html.SafeUrl.sanitize(e)) : null), (i.srcdoc = t || null), (i.sandbox = ''), (e = goog.html.SafeHtml.combineAttributes(i, {}, r)), goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse('iframe', e, o) ); }), (goog.html.SafeHtml.canUseSandboxIframe = function() { return ( goog.global.HTMLIFrameElement && 'sandbox' in goog.global.HTMLIFrameElement.prototype ); }), (goog.html.SafeHtml.createScriptSrc = function(e, t) { return ( goog.html.TrustedResourceUrl.unwrap(e), (e = goog.html.SafeHtml.combineAttributes({ src: e }, {}, t)), goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse('script', e) ); }), (goog.html.SafeHtml.createScript = function(e, t) { for (var r in t) { var o = r.toLowerCase(); if ('language' == o || 'src' == o || 'text' == o || 'type' == o) throw Error( goog.html.SafeHtml.ENABLE_ERROR_MESSAGES ? 'Cannot set "' + o + '" attribute' : '' ); } for (r = '', e = goog.array.concat(e), o = 0; o < e.length; o++) r += goog.html.SafeScript.unwrap(e[o]); return ( (e = goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( r, goog.i18n.bidi.Dir.NEUTRAL )), goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse('script', t, e) ); }), (goog.html.SafeHtml.createStyle = function(e, t) { t = goog.html.SafeHtml.combineAttributes({ type: 'text/css' }, {}, t); var r = ''; e = goog.array.concat(e); for (var o = 0; o < e.length; o++) r += goog.html.SafeStyleSheet.unwrap(e[o]); return ( (e = goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( r, goog.i18n.bidi.Dir.NEUTRAL )), goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse('style', t, e) ); }), (goog.html.SafeHtml.createMetaRefresh = function(e, t) { return ( (e = goog.html.SafeUrl.unwrap(goog.html.SafeUrl.sanitize(e))), (goog.labs.userAgent.browser.isIE() || goog.labs.userAgent.browser.isEdge()) && goog.string.internal.contains(e, ';') && (e = "'" + e.replace(/'/g, '%27') + "'"), goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse('meta', { 'http-equiv': 'refresh', content: (t || 0) + '; url=' + e, }) ); }), (goog.html.SafeHtml.getAttrNameAndValue_ = function(e, t, r) { if (r instanceof goog.string.Const) r = goog.string.Const.unwrap(r); else if ('style' == t.toLowerCase()) { if (!goog.html.SafeHtml.SUPPORT_STYLE_ATTRIBUTE) throw Error( goog.html.SafeHtml.ENABLE_ERROR_MESSAGES ? 'Attribute "style" not supported.' : '' ); r = goog.html.SafeHtml.getStyleValue_(r); } else { if (/^on/i.test(t)) throw Error( goog.html.SafeHtml.ENABLE_ERROR_MESSAGES ? 'Attribute "' + t + '" requires goog.string.Const value, "' + r + '" given.' : '' ); if (t.toLowerCase() in goog.html.SafeHtml.URL_ATTRIBUTES_) if (r instanceof goog.html.TrustedResourceUrl) r = goog.html.TrustedResourceUrl.unwrap(r); else if (r instanceof goog.html.SafeUrl) r = goog.html.SafeUrl.unwrap(r); else { if ('string' != typeof r) throw Error( goog.html.SafeHtml.ENABLE_ERROR_MESSAGES ? 'Attribute "' + t + '" on tag "' + e + '" requires goog.html.SafeUrl, goog.string.Const, or string, value "' + r + '" given.' : '' ); r = goog.html.SafeUrl.sanitize(r).getTypedStringValue(); } } return ( r.implementsGoogStringTypedString && (r = r.getTypedStringValue()), goog.asserts.assert( 'string' == typeof r || 'number' == typeof r, 'String or number value expected, got ' + typeof r + ' with value: ' + r ), t + '="' + goog.string.internal.htmlEscape(String(r)) + '"' ); }), (goog.html.SafeHtml.getStyleValue_ = function(e) { if (!goog.isObject(e)) throw Error( goog.html.SafeHtml.ENABLE_ERROR_MESSAGES ? 'The "style" attribute requires goog.html.SafeStyle or map of style properties, ' + typeof e + ' given: ' + e : '' ); return ( e instanceof goog.html.SafeStyle || (e = goog.html.SafeStyle.create(e)), goog.html.SafeStyle.unwrap(e) ); }), (goog.html.SafeHtml.createWithDir = function(e, t, r, o) { return ((t = goog.html.SafeHtml.create(t, r, o)).dir_ = e), t; }), (goog.html.SafeHtml.join = function(e, t) { var r = (e = goog.html.SafeHtml.htmlEscape(e)).getDirection(), o = [], i = function(e) { Array.isArray(e) ? goog.array.forEach(e, i) : ((e = goog.html.SafeHtml.htmlEscape(e)), o.push(goog.html.SafeHtml.unwrap(e)), (e = e.getDirection()), r == goog.i18n.bidi.Dir.NEUTRAL ? (r = e) : e != goog.i18n.bidi.Dir.NEUTRAL && r != e && (r = null)); }; return ( goog.array.forEach(t, i), goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( o.join(goog.html.SafeHtml.unwrap(e)), r ) ); }), (goog.html.SafeHtml.concat = function(e) { return goog.html.SafeHtml.join( goog.html.SafeHtml.EMPTY, Array.prototype.slice.call(arguments) ); }), (goog.html.SafeHtml.concatWithDir = function(e, t) { var r = goog.html.SafeHtml.concat(goog.array.slice(arguments, 1)); return (r.dir_ = e), r; }), (goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {}), (goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse = function(e, t) { return new goog.html.SafeHtml().initSecurityPrivateDoNotAccessOrElse_(e, t); }), (goog.html.SafeHtml.prototype.initSecurityPrivateDoNotAccessOrElse_ = function(e, t) { return ( (this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = goog.html.trustedtypes .PRIVATE_DO_NOT_ACCESS_OR_ELSE_POLICY ? goog.html.trustedtypes.PRIVATE_DO_NOT_ACCESS_OR_ELSE_POLICY.createHTML(e) : e), (this.dir_ = t), this ); }), (goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse = function(e, t, r) { var o = null, i = '<' + e + goog.html.SafeHtml.stringifyAttributes(e, t); return ( null == r ? (r = []) : Array.isArray(r) || (r = [r]), goog.dom.tags.isVoidTag(e.toLowerCase()) ? (goog.asserts.assert( !r.length, 'Void tag <' + e + '> does not allow content.' ), (i += '>')) : ((o = goog.html.SafeHtml.concat(r)), (i += '>' + goog.html.SafeHtml.unwrap(o) + ''), (o = o.getDirection())), (e = t && t.dir) && (o = /^(ltr|rtl|auto)$/i.test(e) ? goog.i18n.bidi.Dir.NEUTRAL : null), goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(i, o) ); }), (goog.html.SafeHtml.stringifyAttributes = function(e, t) { var r = ''; if (t) for (var o in t) { if (!goog.html.SafeHtml.VALID_NAMES_IN_TAG_.test(o)) throw Error( goog.html.SafeHtml.ENABLE_ERROR_MESSAGES ? 'Invalid attribute name "' + o + '".' : '' ); var i = t[o]; null != i && (r += ' ' + goog.html.SafeHtml.getAttrNameAndValue_(e, o, i)); } return r; }), (goog.html.SafeHtml.combineAttributes = function(e, t, r) { var o, i = {}; for (o in e) goog.asserts.assert(o.toLowerCase() == o, 'Must be lower case'), (i[o] = e[o]); for (o in t) goog.asserts.assert(o.toLowerCase() == o, 'Must be lower case'), (i[o] = t[o]); if (r) for (o in r) { var a = o.toLowerCase(); if (a in e) throw Error( goog.html.SafeHtml.ENABLE_ERROR_MESSAGES ? 'Cannot override "' + a + '" attribute, got "' + o + '" with value "' + r[o] + '"' : '' ); a in t && delete i[a], (i[o] = r[o]); } return i; }), (goog.html.SafeHtml.DOCTYPE_HTML = goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( '', goog.i18n.bidi.Dir.NEUTRAL )), (goog.html.SafeHtml.EMPTY = goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( '', goog.i18n.bidi.Dir.NEUTRAL )), (goog.html.SafeHtml.BR = goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse( '
', goog.i18n.bidi.Dir.NEUTRAL )), (goog.html.uncheckedconversions = {}), (goog.html.uncheckedconversions.safeHtmlFromStringKnownToSatisfyTypeContract = function( e, t, r ) { return ( goog.asserts.assertString( goog.string.Const.unwrap(e), 'must provide justification' ), goog.asserts.assert( !goog.string.internal.isEmptyOrWhitespace(goog.string.Const.unwrap(e)), 'must provide non-empty justification' ), goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(t, r || null) ); }), (goog.html.uncheckedconversions.safeScriptFromStringKnownToSatisfyTypeContract = function( e, t ) { return ( goog.asserts.assertString( goog.string.Const.unwrap(e), 'must provide justification' ), goog.asserts.assert( !goog.string.internal.isEmptyOrWhitespace(goog.string.Const.unwrap(e)), 'must provide non-empty justification' ), goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(t) ); }), (goog.html.uncheckedconversions.safeStyleFromStringKnownToSatisfyTypeContract = function( e, t ) { return ( goog.asserts.assertString( goog.string.Const.unwrap(e), 'must provide justification' ), goog.asserts.assert( !goog.string.internal.isEmptyOrWhitespace(goog.string.Const.unwrap(e)), 'must provide non-empty justification' ), goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(t) ); }), (goog.html.uncheckedconversions.safeStyleSheetFromStringKnownToSatisfyTypeContract = function( e, t ) { return ( goog.asserts.assertString( goog.string.Const.unwrap(e), 'must provide justification' ), goog.asserts.assert( !goog.string.internal.isEmptyOrWhitespace(goog.string.Const.unwrap(e)), 'must provide non-empty justification' ), goog.html.SafeStyleSheet.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(t) ); }), (goog.html.uncheckedconversions.safeUrlFromStringKnownToSatisfyTypeContract = function( e, t ) { return ( goog.asserts.assertString( goog.string.Const.unwrap(e), 'must provide justification' ), goog.asserts.assert( !goog.string.internal.isEmptyOrWhitespace(goog.string.Const.unwrap(e)), 'must provide non-empty justification' ), goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(t) ); }), (goog.html.uncheckedconversions.trustedResourceUrlFromStringKnownToSatisfyTypeContract = function( e, t ) { return ( goog.asserts.assertString( goog.string.Const.unwrap(e), 'must provide justification' ), goog.asserts.assert( !goog.string.internal.isEmptyOrWhitespace(goog.string.Const.unwrap(e)), 'must provide non-empty justification' ), goog.html.TrustedResourceUrl.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse( t ) ); }), (goog.dom.safe = {}), (goog.dom.safe.InsertAdjacentHtmlPosition = { AFTERBEGIN: 'afterbegin', AFTEREND: 'afterend', BEFOREBEGIN: 'beforebegin', BEFOREEND: 'beforeend', }), (goog.dom.safe.insertAdjacentHtml = function(e, t, r) { e.insertAdjacentHTML(t, goog.html.SafeHtml.unwrapTrustedHTML(r)); }), (goog.dom.safe.SET_INNER_HTML_DISALLOWED_TAGS_ = { MATH: !0, SCRIPT: !0, STYLE: !0, SVG: !0, TEMPLATE: !0, }), (goog.dom.safe.isInnerHtmlCleanupRecursive_ = goog.functions.cacheReturnValue(function() { if (goog.DEBUG && 'undefined' == typeof document) return !1; var e = document.createElement('div'), t = document.createElement('div'); return ( t.appendChild(document.createElement('div')), e.appendChild(t), !(goog.DEBUG && !e.firstChild) && ((t = e.firstChild.firstChild), (e.innerHTML = goog.html.SafeHtml.unwrapTrustedHTML(goog.html.SafeHtml.EMPTY)), !t.parentElement) ); })), (goog.dom.safe.unsafeSetInnerHtmlDoNotUseOrElse = function(e, t) { if (goog.dom.safe.isInnerHtmlCleanupRecursive_()) for (; e.lastChild; ) e.removeChild(e.lastChild); e.innerHTML = goog.html.SafeHtml.unwrapTrustedHTML(t); }), (goog.dom.safe.setInnerHtml = function(e, t) { if (goog.asserts.ENABLE_ASSERTS) { var r = e.tagName.toUpperCase(); if (goog.dom.safe.SET_INNER_HTML_DISALLOWED_TAGS_[r]) throw Error( 'goog.dom.safe.setInnerHtml cannot be used to set content of ' + e.tagName + '.' ); } goog.dom.safe.unsafeSetInnerHtmlDoNotUseOrElse(e, t); }), (goog.dom.safe.setOuterHtml = function(e, t) { e.outerHTML = goog.html.SafeHtml.unwrapTrustedHTML(t); }), (goog.dom.safe.setFormElementAction = function(e, t) { (t = t instanceof goog.html.SafeUrl ? t : goog.html.SafeUrl.sanitizeAssertUnchanged(t)), (goog.dom.asserts.assertIsHTMLFormElement(e).action = goog.html.SafeUrl.unwrap(t)); }), (goog.dom.safe.setButtonFormAction = function(e, t) { (t = t instanceof goog.html.SafeUrl ? t : goog.html.SafeUrl.sanitizeAssertUnchanged(t)), (goog.dom.asserts.assertIsHTMLButtonElement( e ).formAction = goog.html.SafeUrl.unwrap(t)); }), (goog.dom.safe.setInputFormAction = function(e, t) { (t = t instanceof goog.html.SafeUrl ? t : goog.html.SafeUrl.sanitizeAssertUnchanged(t)), (goog.dom.asserts.assertIsHTMLInputElement(e).formAction = goog.html.SafeUrl.unwrap( t )); }), (goog.dom.safe.setStyle = function(e, t) { e.style.cssText = goog.html.SafeStyle.unwrap(t); }), (goog.dom.safe.documentWrite = function(e, t) { e.write(goog.html.SafeHtml.unwrapTrustedHTML(t)); }), (goog.dom.safe.setAnchorHref = function(e, t) { goog.dom.asserts.assertIsHTMLAnchorElement(e), (t = t instanceof goog.html.SafeUrl ? t : goog.html.SafeUrl.sanitizeAssertUnchanged(t)), (e.href = goog.html.SafeUrl.unwrap(t)); }), (goog.dom.safe.setImageSrc = function(e, t) { if ((goog.dom.asserts.assertIsHTMLImageElement(e), !(t instanceof goog.html.SafeUrl))) { var r = /^data:image\//i.test(t); t = goog.html.SafeUrl.sanitizeAssertUnchanged(t, r); } e.src = goog.html.SafeUrl.unwrap(t); }), (goog.dom.safe.setAudioSrc = function(e, t) { if ((goog.dom.asserts.assertIsHTMLAudioElement(e), !(t instanceof goog.html.SafeUrl))) { var r = /^data:audio\//i.test(t); t = goog.html.SafeUrl.sanitizeAssertUnchanged(t, r); } e.src = goog.html.SafeUrl.unwrap(t); }), (goog.dom.safe.setVideoSrc = function(e, t) { if ((goog.dom.asserts.assertIsHTMLVideoElement(e), !(t instanceof goog.html.SafeUrl))) { var r = /^data:video\//i.test(t); t = goog.html.SafeUrl.sanitizeAssertUnchanged(t, r); } e.src = goog.html.SafeUrl.unwrap(t); }), (goog.dom.safe.setEmbedSrc = function(e, t) { goog.dom.asserts.assertIsHTMLEmbedElement(e), (e.src = goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(t)); }), (goog.dom.safe.setFrameSrc = function(e, t) { goog.dom.asserts.assertIsHTMLFrameElement(e), (e.src = goog.html.TrustedResourceUrl.unwrap(t)); }), (goog.dom.safe.setIframeSrc = function(e, t) { goog.dom.asserts.assertIsHTMLIFrameElement(e), (e.src = goog.html.TrustedResourceUrl.unwrap(t)); }), (goog.dom.safe.setIframeSrcdoc = function(e, t) { goog.dom.asserts.assertIsHTMLIFrameElement(e), (e.srcdoc = goog.html.SafeHtml.unwrapTrustedHTML(t)); }), (goog.dom.safe.setLinkHrefAndRel = function(e, t, r) { goog.dom.asserts.assertIsHTMLLinkElement(e), (e.rel = r), goog.string.internal.caseInsensitiveContains(r, 'stylesheet') ? (goog.asserts.assert( t instanceof goog.html.TrustedResourceUrl, 'URL must be TrustedResourceUrl because "rel" contains "stylesheet"' ), (e.href = goog.html.TrustedResourceUrl.unwrap(t))) : (e.href = t instanceof goog.html.TrustedResourceUrl ? goog.html.TrustedResourceUrl.unwrap(t) : t instanceof goog.html.SafeUrl ? goog.html.SafeUrl.unwrap(t) : goog.html.SafeUrl.unwrap( goog.html.SafeUrl.sanitizeAssertUnchanged(t) )); }), (goog.dom.safe.setObjectData = function(e, t) { goog.dom.asserts.assertIsHTMLObjectElement(e), (e.data = goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(t)); }), (goog.dom.safe.setScriptSrc = function(e, t) { goog.dom.asserts.assertIsHTMLScriptElement(e), (e.src = goog.html.TrustedResourceUrl.unwrapTrustedScriptURL(t)), (t = goog.getScriptNonce()) && e.setAttribute('nonce', t); }), (goog.dom.safe.setScriptContent = function(e, t) { goog.dom.asserts.assertIsHTMLScriptElement(e), (e.text = goog.html.SafeScript.unwrapTrustedScript(t)), (t = goog.getScriptNonce()) && e.setAttribute('nonce', t); }), (goog.dom.safe.setLocationHref = function(e, t) { goog.dom.asserts.assertIsLocation(e), (t = t instanceof goog.html.SafeUrl ? t : goog.html.SafeUrl.sanitizeAssertUnchanged(t)), (e.href = goog.html.SafeUrl.unwrap(t)); }), (goog.dom.safe.assignLocation = function(e, t) { goog.dom.asserts.assertIsLocation(e), (t = t instanceof goog.html.SafeUrl ? t : goog.html.SafeUrl.sanitizeAssertUnchanged(t)), e.assign(goog.html.SafeUrl.unwrap(t)); }), (goog.dom.safe.replaceLocation = function(e, t) { (t = t instanceof goog.html.SafeUrl ? t : goog.html.SafeUrl.sanitizeAssertUnchanged(t)), e.replace(goog.html.SafeUrl.unwrap(t)); }), (goog.dom.safe.openInWindow = function(e, t, r, o, i) { return ( (e = e instanceof goog.html.SafeUrl ? e : goog.html.SafeUrl.sanitizeAssertUnchanged(e)), (t = t || goog.global), (r = r instanceof goog.string.Const ? goog.string.Const.unwrap(r) : r || ''), t.open(goog.html.SafeUrl.unwrap(e), r, o, i) ); }), (goog.dom.safe.parseFromStringHtml = function(e, t) { return goog.dom.safe.parseFromString(e, t, 'text/html'); }), (goog.dom.safe.parseFromString = function(e, t, r) { return e.parseFromString(goog.html.SafeHtml.unwrapTrustedHTML(t), r); }), (goog.dom.safe.createImageFromBlob = function(e) { if (!/^image\/.*/g.test(e.type)) throw Error('goog.dom.safe.createImageFromBlob only accepts MIME type image/.*.'); var t = goog.global.URL.createObjectURL(e); return ( ((e = new goog.global.Image()).onload = function() { goog.global.URL.revokeObjectURL(t); }), goog.dom.safe.setImageSrc( e, goog.html.uncheckedconversions.safeUrlFromStringKnownToSatisfyTypeContract( goog.string.Const.from('Image blob URL.'), t ) ), e ); }), (goog.string.DETECT_DOUBLE_ESCAPING = !1), (goog.string.FORCE_NON_DOM_HTML_UNESCAPING = !1), (goog.string.Unicode = { NBSP: ' ' }), (goog.string.startsWith = goog.string.internal.startsWith), (goog.string.endsWith = goog.string.internal.endsWith), (goog.string.caseInsensitiveStartsWith = goog.string.internal.caseInsensitiveStartsWith), (goog.string.caseInsensitiveEndsWith = goog.string.internal.caseInsensitiveEndsWith), (goog.string.caseInsensitiveEquals = goog.string.internal.caseInsensitiveEquals), (goog.string.subs = function(e, t) { for ( var r = e.split('%s'), o = '', i = Array.prototype.slice.call(arguments, 1); i.length && 1 < r.length; ) o += r.shift() + i.shift(); return o + r.join('%s'); }), (goog.string.collapseWhitespace = function(e) { return e.replace(/[\s\xa0]+/g, ' ').replace(/^\s+|\s+$/g, ''); }), (goog.string.isEmptyOrWhitespace = goog.string.internal.isEmptyOrWhitespace), (goog.string.isEmptyString = function(e) { return 0 == e.length; }), (goog.string.isEmpty = goog.string.isEmptyOrWhitespace), (goog.string.isEmptyOrWhitespaceSafe = function(e) { return goog.string.isEmptyOrWhitespace(goog.string.makeSafe(e)); }), (goog.string.isEmptySafe = goog.string.isEmptyOrWhitespaceSafe), (goog.string.isBreakingWhitespace = function(e) { return !/[^\t\n\r ]/.test(e); }), (goog.string.isAlpha = function(e) { return !/[^a-zA-Z]/.test(e); }), (goog.string.isNumeric = function(e) { return !/[^0-9]/.test(e); }), (goog.string.isAlphaNumeric = function(e) { return !/[^a-zA-Z0-9]/.test(e); }), (goog.string.isSpace = function(e) { return ' ' == e; }), (goog.string.isUnicodeChar = function(e) { return (1 == e.length && ' ' <= e && '~' >= e) || ('€' <= e && '�' >= e); }), (goog.string.stripNewlines = function(e) { return e.replace(/(\r\n|\r|\n)+/g, ' '); }), (goog.string.canonicalizeNewlines = function(e) { return e.replace(/(\r\n|\r|\n)/g, '\n'); }), (goog.string.normalizeWhitespace = function(e) { return e.replace(/\xa0|\s/g, ' '); }), (goog.string.normalizeSpaces = function(e) { return e.replace(/\xa0|[ \t]+/g, ' '); }), (goog.string.collapseBreakingSpaces = function(e) { return e.replace(/[\t\r\n ]+/g, ' ').replace(/^[\t\r\n ]+|[\t\r\n ]+$/g, ''); }), (goog.string.trim = goog.string.internal.trim), (goog.string.trimLeft = function(e) { return e.replace(/^[\s\xa0]+/, ''); }), (goog.string.trimRight = function(e) { return e.replace(/[\s\xa0]+$/, ''); }), (goog.string.caseInsensitiveCompare = goog.string.internal.caseInsensitiveCompare), (goog.string.numberAwareCompare_ = function(e, t, r) { if (e == t) return 0; if (!e) return -1; if (!t) return 1; for ( var o = e.toLowerCase().match(r), i = t.toLowerCase().match(r), a = Math.min(o.length, i.length), n = 0; n < a; n++ ) { r = o[n]; var s = i[n]; if (r != s) return ( (e = parseInt(r, 10)), !isNaN(e) && ((t = parseInt(s, 10)), !isNaN(t) && e - t) ? e - t : r < s ? -1 : 1 ); } return o.length != i.length ? o.length - i.length : e < t ? -1 : 1; }), (goog.string.intAwareCompare = function(e, t) { return goog.string.numberAwareCompare_(e, t, /\d+|\D+/g); }), (goog.string.floatAwareCompare = function(e, t) { return goog.string.numberAwareCompare_(e, t, /\d+|\.\d+|\D+/g); }), (goog.string.numerateCompare = goog.string.floatAwareCompare), (goog.string.urlEncode = function(e) { return encodeURIComponent(String(e)); }), (goog.string.urlDecode = function(e) { return decodeURIComponent(e.replace(/\+/g, ' ')); }), (goog.string.newLineToBr = goog.string.internal.newLineToBr), (goog.string.htmlEscape = function(e, t) { return ( (e = goog.string.internal.htmlEscape(e, t)), goog.string.DETECT_DOUBLE_ESCAPING && (e = e.replace(goog.string.E_RE_, 'e')), e ); }), (goog.string.E_RE_ = /e/g), (goog.string.unescapeEntities = function(e) { return goog.string.contains(e, '&') ? !goog.string.FORCE_NON_DOM_HTML_UNESCAPING && 'document' in goog.global ? goog.string.unescapeEntitiesUsingDom_(e) : goog.string.unescapePureXmlEntities_(e) : e; }), (goog.string.unescapeEntitiesWithDocument = function(e, t) { return goog.string.contains(e, '&') ? goog.string.unescapeEntitiesUsingDom_(e, t) : e; }), (goog.string.unescapeEntitiesUsingDom_ = function(e, t) { var r = { '&': '&', '<': '<', '>': '>', '"': '"' }, o = t ? t.createElement('div') : goog.global.document.createElement('div'); return e.replace(goog.string.HTML_ENTITY_PATTERN_, function(e, t) { var i = r[e]; return ( i || ('#' == t.charAt(0) && ((t = Number('0' + t.substr(1))), isNaN(t) || (i = String.fromCharCode(t))), i || (goog.dom.safe.setInnerHtml( o, goog.html.uncheckedconversions.safeHtmlFromStringKnownToSatisfyTypeContract( goog.string.Const.from('Single HTML entity.'), e + ' ' ) ), (i = o.firstChild.nodeValue.slice(0, -1))), (r[e] = i)) ); }); }), (goog.string.unescapePureXmlEntities_ = function(e) { return e.replace(/&([^;]+);/g, function(e, t) { switch (t) { case 'amp': return '&'; case 'lt': return '<'; case 'gt': return '>'; case 'quot': return '"'; default: return '#' != t.charAt(0) || ((t = Number('0' + t.substr(1))), isNaN(t)) ? e : String.fromCharCode(t); } }); }), (goog.string.HTML_ENTITY_PATTERN_ = /&([^;\s<&]+);?/g), (goog.string.whitespaceEscape = function(e, t) { return goog.string.newLineToBr(e.replace(/ /g, '  '), t); }), (goog.string.preserveSpaces = function(e) { return e.replace(/(^|[\n ]) /g, '$1' + goog.string.Unicode.NBSP); }), (goog.string.stripQuotes = function(e, t) { for (var r = t.length, o = 0; o < r; o++) { var i = 1 == r ? t : t.charAt(o); if (e.charAt(0) == i && e.charAt(e.length - 1) == i) return e.substring(1, e.length - 1); } return e; }), (goog.string.truncate = function(e, t, r) { return ( r && (e = goog.string.unescapeEntities(e)), e.length > t && (e = e.substring(0, t - 3) + '...'), r && (e = goog.string.htmlEscape(e)), e ); }), (goog.string.truncateMiddle = function(e, t, r, o) { if ((r && (e = goog.string.unescapeEntities(e)), o && e.length > t)) { o > t && (o = t); var i = e.length - o; e = e.substring(0, t - o) + '...' + e.substring(i); } else e.length > t && ((o = Math.floor(t / 2)), (i = e.length - o), (e = e.substring(0, o + (t % 2)) + '...' + e.substring(i))); return r && (e = goog.string.htmlEscape(e)), e; }), (goog.string.specialEscapeChars_ = { '\0': '\\0', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t', '\v': '\\x0B', '"': '\\"', '\\': '\\\\', '<': '\\u003C', }), (goog.string.jsEscapeCache_ = { "'": "\\'" }), (goog.string.quote = function(e) { e = String(e); for (var t = ['"'], r = 0; r < e.length; r++) { var o = e.charAt(r), i = o.charCodeAt(0); t[r + 1] = goog.string.specialEscapeChars_[o] || (31 < i && 127 > i ? o : goog.string.escapeChar(o)); } return t.push('"'), t.join(''); }), (goog.string.escapeString = function(e) { for (var t = [], r = 0; r < e.length; r++) t[r] = goog.string.escapeChar(e.charAt(r)); return t.join(''); }), (goog.string.escapeChar = function(e) { if (e in goog.string.jsEscapeCache_) return goog.string.jsEscapeCache_[e]; if (e in goog.string.specialEscapeChars_) return (goog.string.jsEscapeCache_[e] = goog.string.specialEscapeChars_[e]); var t = e.charCodeAt(0); if (31 < t && 127 > t) var r = e; else 256 > t ? ((r = '\\x'), (16 > t || 256 < t) && (r += '0')) : ((r = '\\u'), 4096 > t && (r += '0')), (r += t.toString(16).toUpperCase()); return (goog.string.jsEscapeCache_[e] = r); }), (goog.string.contains = goog.string.internal.contains), (goog.string.caseInsensitiveContains = goog.string.internal.caseInsensitiveContains), (goog.string.countOf = function(e, t) { return e && t ? e.split(t).length - 1 : 0; }), (goog.string.removeAt = function(e, t, r) { var o = e; return ( 0 <= t && t < e.length && 0 < r && (o = e.substr(0, t) + e.substr(t + r, e.length - t - r)), o ); }), (goog.string.remove = function(e, t) { return e.replace(t, ''); }), (goog.string.removeAll = function(e, t) { return (t = new RegExp(goog.string.regExpEscape(t), 'g')), e.replace(t, ''); }), (goog.string.replaceAll = function(e, t, r) { return ( (t = new RegExp(goog.string.regExpEscape(t), 'g')), e.replace(t, r.replace(/\$/g, '$$$$')) ); }), (goog.string.regExpEscape = function(e) { return String(e) .replace(/([-()\[\]{}+?*.$\^|,:#>> 0; return t; }), (goog.string.uniqueStringCounter_ = (2147483648 * Math.random()) | 0), (goog.string.createUniqueString = function() { return 'goog_' + goog.string.uniqueStringCounter_++; }), (goog.string.toNumber = function(e) { var t = Number(e); return 0 == t && goog.string.isEmptyOrWhitespace(e) ? NaN : t; }), (goog.string.isLowerCamelCase = function(e) { return /^[a-z]+([A-Z][a-z]*)*$/.test(e); }), (goog.string.isUpperCamelCase = function(e) { return /^([A-Z][a-z]*)+$/.test(e); }), (goog.string.toCamelCase = function(e) { return String(e).replace(/\-([a-z])/g, function(e, t) { return t.toUpperCase(); }); }), (goog.string.toSelectorCase = function(e) { return String(e) .replace(/([A-Z])/g, '-$1') .toLowerCase(); }), (goog.string.toTitleCase = function(e, t) { return ( (t = 'string' == typeof t ? goog.string.regExpEscape(t) : '\\s'), e.replace(new RegExp('(^' + (t ? '|[' + t + ']+' : '') + ')([a-z])', 'g'), function( e, t, r ) { return t + r.toUpperCase(); }) ); }), (goog.string.capitalize = function(e) { return String(e.charAt(0)).toUpperCase() + String(e.substr(1)).toLowerCase(); }), (goog.string.parseInt = function(e) { return ( isFinite(e) && (e = String(e)), 'string' == typeof e ? /^\s*-?0x/i.test(e) ? parseInt(e, 16) : parseInt(e, 10) : NaN ); }), (goog.string.splitLimit = function(e, t, r) { e = e.split(t); for (var o = []; 0 < r && e.length; ) o.push(e.shift()), r--; return e.length && o.push(e.join(t)), o; }), (goog.string.lastComponent = function(e, t) { if (!t) return e; 'string' == typeof t && (t = [t]); for (var r = -1, o = 0; o < t.length; o++) if ('' != t[o]) { var i = e.lastIndexOf(t[o]); i > r && (r = i); } return -1 == r ? e : e.slice(r + 1); }), (goog.string.editDistance = function(e, t) { var r = [], o = []; if (e == t) return 0; if (!e.length || !t.length) return Math.max(e.length, t.length); for (var i = 0; i < t.length + 1; i++) r[i] = i; for (i = 0; i < e.length; i++) { o[0] = i + 1; for (var a = 0; a < t.length; a++) o[a + 1] = Math.min(o[a] + 1, r[a + 1] + 1, r[a] + Number(e[i] != t[a])); for (a = 0; a < r.length; a++) r[a] = o[a]; } return o[t.length]; }), (goog.labs.userAgent.engine = {}), (goog.labs.userAgent.engine.isPresto = function() { return goog.labs.userAgent.util.matchUserAgent('Presto'); }), (goog.labs.userAgent.engine.isTrident = function() { return ( goog.labs.userAgent.util.matchUserAgent('Trident') || goog.labs.userAgent.util.matchUserAgent('MSIE') ); }), (goog.labs.userAgent.engine.isEdge = function() { return goog.labs.userAgent.util.matchUserAgent('Edge'); }), (goog.labs.userAgent.engine.isWebKit = function() { return ( goog.labs.userAgent.util.matchUserAgentIgnoreCase('WebKit') && !goog.labs.userAgent.engine.isEdge() ); }), (goog.labs.userAgent.engine.isGecko = function() { return ( goog.labs.userAgent.util.matchUserAgent('Gecko') && !goog.labs.userAgent.engine.isWebKit() && !goog.labs.userAgent.engine.isTrident() && !goog.labs.userAgent.engine.isEdge() ); }), (goog.labs.userAgent.engine.getVersion = function() { var e = goog.labs.userAgent.util.getUserAgent(); if (e) { e = goog.labs.userAgent.util.extractVersionTuples(e); var t, r = goog.labs.userAgent.engine.getEngineTuple_(e); if (r) return 'Gecko' == r[0] ? goog.labs.userAgent.engine.getVersionForKey_(e, 'Firefox') : r[1]; if ((e = e[0]) && (t = e[2]) && (t = /Trident\/([^\s;]+)/.exec(t))) return t[1]; } return ''; }), (goog.labs.userAgent.engine.getEngineTuple_ = function(e) { if (!goog.labs.userAgent.engine.isEdge()) return e[1]; for (var t = 0; t < e.length; t++) { var r = e[t]; if ('Edge' == r[0]) return r; } }), (goog.labs.userAgent.engine.isVersionOrHigher = function(e) { return 0 <= goog.string.compareVersions(goog.labs.userAgent.engine.getVersion(), e); }), (goog.labs.userAgent.engine.getVersionForKey_ = function(e, t) { return ( ((e = goog.array.find(e, function(e) { return t == e[0]; })) && e[1]) || '' ); }), (goog.labs.userAgent.platform = {}), (goog.labs.userAgent.platform.isAndroid = function() { return goog.labs.userAgent.util.matchUserAgent('Android'); }), (goog.labs.userAgent.platform.isIpod = function() { return goog.labs.userAgent.util.matchUserAgent('iPod'); }), (goog.labs.userAgent.platform.isIphone = function() { return ( goog.labs.userAgent.util.matchUserAgent('iPhone') && !goog.labs.userAgent.util.matchUserAgent('iPod') && !goog.labs.userAgent.util.matchUserAgent('iPad') ); }), (goog.labs.userAgent.platform.isIpad = function() { return goog.labs.userAgent.util.matchUserAgent('iPad'); }), (goog.labs.userAgent.platform.isIos = function() { return ( goog.labs.userAgent.platform.isIphone() || goog.labs.userAgent.platform.isIpad() || goog.labs.userAgent.platform.isIpod() ); }), (goog.labs.userAgent.platform.isMacintosh = function() { return goog.labs.userAgent.util.matchUserAgent('Macintosh'); }), (goog.labs.userAgent.platform.isLinux = function() { return goog.labs.userAgent.util.matchUserAgent('Linux'); }), (goog.labs.userAgent.platform.isWindows = function() { return goog.labs.userAgent.util.matchUserAgent('Windows'); }), (goog.labs.userAgent.platform.isChromeOS = function() { return goog.labs.userAgent.util.matchUserAgent('CrOS'); }), (goog.labs.userAgent.platform.isChromecast = function() { return goog.labs.userAgent.util.matchUserAgent('CrKey'); }), (goog.labs.userAgent.platform.isKaiOS = function() { return goog.labs.userAgent.util.matchUserAgentIgnoreCase('KaiOS'); }), (goog.labs.userAgent.platform.getVersion = function() { var e = goog.labs.userAgent.util.getUserAgent(), t = ''; return ( goog.labs.userAgent.platform.isWindows() ? (t = (e = (t = /Windows (?:NT|Phone) ([0-9.]+)/).exec(e)) ? e[1] : '0.0') : goog.labs.userAgent.platform.isIos() ? (t = (e = (t = /(?:iPhone|iPod|iPad|CPU)\s+OS\s+(\S+)/).exec(e)) && e[1].replace(/_/g, '.')) : goog.labs.userAgent.platform.isMacintosh() ? (t = (e = (t = /Mac OS X ([0-9_.]+)/).exec(e)) ? e[1].replace(/_/g, '.') : '10') : goog.labs.userAgent.platform.isKaiOS() ? (t = (e = (t = /(?:KaiOS)\/(\S+)/i).exec(e)) && e[1]) : goog.labs.userAgent.platform.isAndroid() ? (t = (e = (t = /Android\s+([^\);]+)(\)|;)/).exec(e)) && e[1]) : goog.labs.userAgent.platform.isChromeOS() && (t = (e = (t = /(?:CrOS\s+(?:i686|x86_64)\s+([0-9.]+))/).exec(e)) && e[1]), t || '' ); }), (goog.labs.userAgent.platform.isVersionOrHigher = function(e) { return 0 <= goog.string.compareVersions(goog.labs.userAgent.platform.getVersion(), e); }), (goog.reflect = {}), (goog.reflect.object = function(e, t) { return t; }), (goog.reflect.objectProperty = function(e, t) { return e; }), (goog.reflect.sinkValue = function(e) { return goog.reflect.sinkValue[' '](e), e; }), (goog.reflect.sinkValue[' '] = goog.nullFunction), (goog.reflect.canAccessProperty = function(e, t) { try { return goog.reflect.sinkValue(e[t]), !0; } catch (e) {} return !1; }), (goog.reflect.cache = function(e, t, r, o) { return ( (o = o ? o(t) : t), Object.prototype.hasOwnProperty.call(e, o) ? e[o] : (e[o] = r(t)) ); }), (goog.userAgent = {}), (goog.userAgent.ASSUME_IE = !1), (goog.userAgent.ASSUME_EDGE = !1), (goog.userAgent.ASSUME_GECKO = !1), (goog.userAgent.ASSUME_WEBKIT = !1), (goog.userAgent.ASSUME_MOBILE_WEBKIT = !1), (goog.userAgent.ASSUME_OPERA = !1), (goog.userAgent.ASSUME_ANY_VERSION = !1), (goog.userAgent.BROWSER_KNOWN_ = goog.userAgent.ASSUME_IE || goog.userAgent.ASSUME_EDGE || goog.userAgent.ASSUME_GECKO || goog.userAgent.ASSUME_MOBILE_WEBKIT || goog.userAgent.ASSUME_WEBKIT || goog.userAgent.ASSUME_OPERA), (goog.userAgent.getUserAgentString = function() { return goog.labs.userAgent.util.getUserAgent(); }), (goog.userAgent.getNavigatorTyped = function() { return goog.global.navigator || null; }), (goog.userAgent.getNavigator = function() { return goog.userAgent.getNavigatorTyped(); }), (goog.userAgent.OPERA = goog.userAgent.BROWSER_KNOWN_ ? goog.userAgent.ASSUME_OPERA : goog.labs.userAgent.browser.isOpera()), (goog.userAgent.IE = goog.userAgent.BROWSER_KNOWN_ ? goog.userAgent.ASSUME_IE : goog.labs.userAgent.browser.isIE()), (goog.userAgent.EDGE = goog.userAgent.BROWSER_KNOWN_ ? goog.userAgent.ASSUME_EDGE : goog.labs.userAgent.engine.isEdge()), (goog.userAgent.EDGE_OR_IE = goog.userAgent.EDGE || goog.userAgent.IE), (goog.userAgent.GECKO = goog.userAgent.BROWSER_KNOWN_ ? goog.userAgent.ASSUME_GECKO : goog.labs.userAgent.engine.isGecko()), (goog.userAgent.WEBKIT = goog.userAgent.BROWSER_KNOWN_ ? goog.userAgent.ASSUME_WEBKIT || goog.userAgent.ASSUME_MOBILE_WEBKIT : goog.labs.userAgent.engine.isWebKit()), (goog.userAgent.isMobile_ = function() { return goog.userAgent.WEBKIT && goog.labs.userAgent.util.matchUserAgent('Mobile'); }), (goog.userAgent.MOBILE = goog.userAgent.ASSUME_MOBILE_WEBKIT || goog.userAgent.isMobile_()), (goog.userAgent.SAFARI = goog.userAgent.WEBKIT), (goog.userAgent.determinePlatform_ = function() { var e = goog.userAgent.getNavigatorTyped(); return (e && e.platform) || ''; }), (goog.userAgent.PLATFORM = goog.userAgent.determinePlatform_()), (goog.userAgent.ASSUME_MAC = !1), (goog.userAgent.ASSUME_WINDOWS = !1), (goog.userAgent.ASSUME_LINUX = !1), (goog.userAgent.ASSUME_X11 = !1), (goog.userAgent.ASSUME_ANDROID = !1), (goog.userAgent.ASSUME_IPHONE = !1), (goog.userAgent.ASSUME_IPAD = !1), (goog.userAgent.ASSUME_IPOD = !1), (goog.userAgent.ASSUME_KAIOS = !1), (goog.userAgent.PLATFORM_KNOWN_ = goog.userAgent.ASSUME_MAC || goog.userAgent.ASSUME_WINDOWS || goog.userAgent.ASSUME_LINUX || goog.userAgent.ASSUME_X11 || goog.userAgent.ASSUME_ANDROID || goog.userAgent.ASSUME_IPHONE || goog.userAgent.ASSUME_IPAD || goog.userAgent.ASSUME_IPOD), (goog.userAgent.MAC = goog.userAgent.PLATFORM_KNOWN_ ? goog.userAgent.ASSUME_MAC : goog.labs.userAgent.platform.isMacintosh()); (goog.userAgent.WINDOWS = goog.userAgent.PLATFORM_KNOWN_ ? goog.userAgent.ASSUME_WINDOWS : goog.labs.userAgent.platform.isWindows()), (goog.userAgent.isLegacyLinux_ = function() { return ( goog.labs.userAgent.platform.isLinux() || goog.labs.userAgent.platform.isChromeOS() ); }), (goog.userAgent.LINUX = goog.userAgent.PLATFORM_KNOWN_ ? goog.userAgent.ASSUME_LINUX : goog.userAgent.isLegacyLinux_()), (goog.userAgent.isX11_ = function() { var e = goog.userAgent.getNavigatorTyped(); return !!e && goog.string.contains(e.appVersion || '', 'X11'); }), (goog.userAgent.X11 = goog.userAgent.PLATFORM_KNOWN_ ? goog.userAgent.ASSUME_X11 : goog.userAgent.isX11_()), (goog.userAgent.ANDROID = goog.userAgent.PLATFORM_KNOWN_ ? goog.userAgent.ASSUME_ANDROID : goog.labs.userAgent.platform.isAndroid()), (goog.userAgent.IPHONE = goog.userAgent.PLATFORM_KNOWN_ ? goog.userAgent.ASSUME_IPHONE : goog.labs.userAgent.platform.isIphone()), (goog.userAgent.IPAD = goog.userAgent.PLATFORM_KNOWN_ ? goog.userAgent.ASSUME_IPAD : goog.labs.userAgent.platform.isIpad()), (goog.userAgent.IPOD = goog.userAgent.PLATFORM_KNOWN_ ? goog.userAgent.ASSUME_IPOD : goog.labs.userAgent.platform.isIpod()), (goog.userAgent.IOS = goog.userAgent.PLATFORM_KNOWN_ ? goog.userAgent.ASSUME_IPHONE || goog.userAgent.ASSUME_IPAD || goog.userAgent.ASSUME_IPOD : goog.labs.userAgent.platform.isIos()), (goog.userAgent.KAIOS = goog.userAgent.PLATFORM_KNOWN_ ? goog.userAgent.ASSUME_KAIOS : goog.labs.userAgent.platform.isKaiOS()), (goog.userAgent.determineVersion_ = function() { var e = '', t = goog.userAgent.getVersionRegexResult_(); return ( t && (e = t ? t[1] : ''), goog.userAgent.IE && null != (t = goog.userAgent.getDocumentMode_()) && t > parseFloat(e) ? String(t) : e ); }), (goog.userAgent.getVersionRegexResult_ = function() { var e = goog.userAgent.getUserAgentString(); return goog.userAgent.GECKO ? /rv:([^\);]+)(\)|;)/.exec(e) : goog.userAgent.EDGE ? /Edge\/([\d\.]+)/.exec(e) : goog.userAgent.IE ? /\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(e) : goog.userAgent.WEBKIT ? /WebKit\/(\S+)/.exec(e) : goog.userAgent.OPERA ? /(?:Version)[ \/]?(\S+)/.exec(e) : void 0; }), (goog.userAgent.getDocumentMode_ = function() { var e = goog.global.document; return e ? e.documentMode : void 0; }), (goog.userAgent.VERSION = goog.userAgent.determineVersion_()), (goog.userAgent.compare = function(e, t) { return goog.string.compareVersions(e, t); }), (goog.userAgent.isVersionOrHigherCache_ = {}), (goog.userAgent.isVersionOrHigher = function(e) { return ( goog.userAgent.ASSUME_ANY_VERSION || goog.reflect.cache(goog.userAgent.isVersionOrHigherCache_, e, function() { return 0 <= goog.string.compareVersions(goog.userAgent.VERSION, e); }) ); }), (goog.userAgent.isVersion = goog.userAgent.isVersionOrHigher), (goog.userAgent.isDocumentModeOrHigher = function(e) { return Number(goog.userAgent.DOCUMENT_MODE) >= e; }), (goog.userAgent.isDocumentMode = goog.userAgent.isDocumentModeOrHigher), (goog.userAgent.DOCUMENT_MODE = (function() { if (goog.global.document && goog.userAgent.IE) { var e = goog.userAgent.getDocumentMode_(); return e || parseInt(goog.userAgent.VERSION, 10) || void 0; } })()), (goog.userAgent.product = {}), (goog.userAgent.product.ASSUME_FIREFOX = !1), (goog.userAgent.product.ASSUME_IPHONE = !1), (goog.userAgent.product.ASSUME_IPAD = !1), (goog.userAgent.product.ASSUME_ANDROID = !1), (goog.userAgent.product.ASSUME_CHROME = !1), (goog.userAgent.product.ASSUME_SAFARI = !1), (goog.userAgent.product.PRODUCT_KNOWN_ = goog.userAgent.ASSUME_IE || goog.userAgent.ASSUME_EDGE || goog.userAgent.ASSUME_OPERA || goog.userAgent.product.ASSUME_FIREFOX || goog.userAgent.product.ASSUME_IPHONE || goog.userAgent.product.ASSUME_IPAD || goog.userAgent.product.ASSUME_ANDROID || goog.userAgent.product.ASSUME_CHROME || goog.userAgent.product.ASSUME_SAFARI), (goog.userAgent.product.OPERA = goog.userAgent.OPERA), (goog.userAgent.product.IE = goog.userAgent.IE), (goog.userAgent.product.EDGE = goog.userAgent.EDGE), (goog.userAgent.product.FIREFOX = goog.userAgent.product.PRODUCT_KNOWN_ ? goog.userAgent.product.ASSUME_FIREFOX : goog.labs.userAgent.browser.isFirefox()), (goog.userAgent.product.isIphoneOrIpod_ = function() { return goog.labs.userAgent.platform.isIphone() || goog.labs.userAgent.platform.isIpod(); }), (goog.userAgent.product.IPHONE = goog.userAgent.product.PRODUCT_KNOWN_ ? goog.userAgent.product.ASSUME_IPHONE : goog.userAgent.product.isIphoneOrIpod_()), (goog.userAgent.product.IPAD = goog.userAgent.product.PRODUCT_KNOWN_ ? goog.userAgent.product.ASSUME_IPAD : goog.labs.userAgent.platform.isIpad()), (goog.userAgent.product.ANDROID = goog.userAgent.product.PRODUCT_KNOWN_ ? goog.userAgent.product.ASSUME_ANDROID : goog.labs.userAgent.browser.isAndroidBrowser()), (goog.userAgent.product.CHROME = goog.userAgent.product.PRODUCT_KNOWN_ ? goog.userAgent.product.ASSUME_CHROME : goog.labs.userAgent.browser.isChrome()), (goog.userAgent.product.isSafariDesktop_ = function() { return goog.labs.userAgent.browser.isSafari() && !goog.labs.userAgent.platform.isIos(); }), (goog.userAgent.product.SAFARI = goog.userAgent.product.PRODUCT_KNOWN_ ? goog.userAgent.product.ASSUME_SAFARI : goog.userAgent.product.isSafariDesktop_()), (goog.crypt.base64 = {}), (goog.crypt.base64.DEFAULT_ALPHABET_COMMON_ = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'), (goog.crypt.base64.ENCODED_VALS = goog.crypt.base64.DEFAULT_ALPHABET_COMMON_ + '+/='), (goog.crypt.base64.ENCODED_VALS_WEBSAFE = goog.crypt.base64.DEFAULT_ALPHABET_COMMON_ + '-_.'), (goog.crypt.base64.Alphabet = { DEFAULT: 0, NO_PADDING: 1, WEBSAFE: 2, WEBSAFE_DOT_PADDING: 3, WEBSAFE_NO_PADDING: 4, }), (goog.crypt.base64.paddingChars_ = '=.'), (goog.crypt.base64.isPadding_ = function(e) { return goog.string.contains(goog.crypt.base64.paddingChars_, e); }), (goog.crypt.base64.byteToCharMaps_ = {}), (goog.crypt.base64.charToByteMap_ = null), (goog.crypt.base64.ASSUME_NATIVE_SUPPORT_ = goog.userAgent.GECKO || (goog.userAgent.WEBKIT && !goog.userAgent.product.SAFARI) || goog.userAgent.OPERA), (goog.crypt.base64.HAS_NATIVE_ENCODE_ = goog.crypt.base64.ASSUME_NATIVE_SUPPORT_ || 'function' == typeof goog.global.btoa), (goog.crypt.base64.HAS_NATIVE_DECODE_ = goog.crypt.base64.ASSUME_NATIVE_SUPPORT_ || (!goog.userAgent.product.SAFARI && !goog.userAgent.IE && 'function' == typeof goog.global.atob)), (goog.crypt.base64.encodeByteArray = function(e, t) { goog.asserts.assert( goog.isArrayLike(e), 'encodeByteArray takes an array as a parameter' ), void 0 === t && (t = goog.crypt.base64.Alphabet.DEFAULT), goog.crypt.base64.init_(), (t = goog.crypt.base64.byteToCharMaps_[t]); for (var r = [], o = 0; o < e.length; o += 3) { var i = e[o], a = o + 1 < e.length, n = a ? e[o + 1] : 0, s = o + 2 < e.length, p = s ? e[o + 2] : 0, d = i >> 2; (i = ((3 & i) << 4) | (n >> 4)), (n = ((15 & n) << 2) | (p >> 6)), (p &= 63), s || ((p = 64), a || (n = 64)), r.push(t[d], t[i], t[n] || '', t[p] || ''); } return r.join(''); }), (goog.crypt.base64.encodeString = function(e, t) { return goog.crypt.base64.HAS_NATIVE_ENCODE_ && !t ? goog.global.btoa(e) : goog.crypt.base64.encodeByteArray(goog.crypt.stringToByteArray(e), t); }), (goog.crypt.base64.decodeString = function(e, t) { if (goog.crypt.base64.HAS_NATIVE_DECODE_ && !t) return goog.global.atob(e); var r = ''; return ( goog.crypt.base64.decodeStringInternal_(e, function(e) { r += String.fromCharCode(e); }), r ); }), (goog.crypt.base64.decodeStringToByteArray = function(e, t) { var r = []; return ( goog.crypt.base64.decodeStringInternal_(e, function(e) { r.push(e); }), r ); }), (goog.crypt.base64.decodeStringToUint8Array = function(e) { goog.asserts.assert( !goog.userAgent.IE || goog.userAgent.isVersionOrHigher('10'), 'Browser does not support typed arrays' ); var t = e.length, r = (3 * t) / 4; r % 3 ? (r = Math.floor(r)) : goog.crypt.base64.isPadding_(e[t - 1]) && (r = goog.crypt.base64.isPadding_(e[t - 2]) ? r - 2 : r - 1); var o = new Uint8Array(r), i = 0; return ( goog.crypt.base64.decodeStringInternal_(e, function(e) { o[i++] = e; }), o.subarray(0, i) ); }), (goog.crypt.base64.decodeStringInternal_ = function(e, t) { function r(t) { for (; o < e.length; ) { var r = e.charAt(o++), i = goog.crypt.base64.charToByteMap_[r]; if (null != i) return i; if (!goog.string.isEmptyOrWhitespace(r)) throw Error('Unknown base64 encoding at char: ' + r); } return t; } goog.crypt.base64.init_(); for (var o = 0; ; ) { var i = r(-1), a = r(0), n = r(64), s = r(64); if (64 === s && -1 === i) break; t((i << 2) | (a >> 4)), 64 != n && (t(((a << 4) & 240) | (n >> 2)), 64 != s && t(((n << 6) & 192) | s)); } }), (goog.crypt.base64.init_ = function() { if (!goog.crypt.base64.charToByteMap_) { goog.crypt.base64.charToByteMap_ = {}; for ( var e = goog.crypt.base64.DEFAULT_ALPHABET_COMMON_.split(''), t = ['+/=', '+/', '-_=', '-_.', '-_'], r = 0; 5 > r; r++ ) { var o = e.concat(t[r].split('')); goog.crypt.base64.byteToCharMaps_[r] = o; for (var i = 0; i < o.length; i++) { var a = o[i], n = goog.crypt.base64.charToByteMap_[a]; void 0 === n ? (goog.crypt.base64.charToByteMap_[a] = i) : goog.asserts.assert(n === i); } } } }), (jspb.utils = {}), (jspb.utils.split64Low = 0), (jspb.utils.split64High = 0), (jspb.utils.splitUint64 = function(e) { var t = e >>> 0; (e = Math.floor((e - t) / jspb.BinaryConstants.TWO_TO_32) >>> 0), (jspb.utils.split64Low = t), (jspb.utils.split64High = e); }), (jspb.utils.splitInt64 = function(e) { var t = 0 > e, r = (e = Math.abs(e)) >>> 0; (e = Math.floor((e - r) / jspb.BinaryConstants.TWO_TO_32)), (e >>>= 0), t && ((e = ~e >>> 0), 4294967295 < (r = 1 + (~r >>> 0)) && ((r = 0), 4294967295 < ++e && (e = 0))), (jspb.utils.split64Low = r), (jspb.utils.split64High = e); }), (jspb.utils.splitZigzag64 = function(e) { var t = 0 > e; (e = 2 * Math.abs(e)), jspb.utils.splitUint64(e), (e = jspb.utils.split64Low); var r = jspb.utils.split64High; t && (0 == e ? (0 == r ? (r = e = 4294967295) : (r--, (e = 4294967295))) : e--), (jspb.utils.split64Low = e), (jspb.utils.split64High = r); }), (jspb.utils.splitFloat32 = function(e) { var t = 0 > e ? 1 : 0; if (0 === (e = t ? -e : e)) 0 < 1 / e ? ((jspb.utils.split64High = 0), (jspb.utils.split64Low = 0)) : ((jspb.utils.split64High = 0), (jspb.utils.split64Low = 2147483648)); else if (isNaN(e)) (jspb.utils.split64High = 0), (jspb.utils.split64Low = 2147483647); else if (e > jspb.BinaryConstants.FLOAT32_MAX) (jspb.utils.split64High = 0), (jspb.utils.split64Low = ((t << 31) | 2139095040) >>> 0); else if (e < jspb.BinaryConstants.FLOAT32_MIN) (e = Math.round(e / Math.pow(2, -149))), (jspb.utils.split64High = 0), (jspb.utils.split64Low = ((t << 31) | e) >>> 0); else { var r = Math.floor(Math.log(e) / Math.LN2); (e *= Math.pow(2, -r)), 16777216 <= (e = Math.round(e * jspb.BinaryConstants.TWO_TO_23)) && ++r, (jspb.utils.split64High = 0), (jspb.utils.split64Low = ((t << 31) | ((r + 127) << 23) | (8388607 & e)) >>> 0); } }), (jspb.utils.splitFloat64 = function(e) { var t = 0 > e ? 1 : 0; if (0 === (e = t ? -e : e)) (jspb.utils.split64High = 0 < 1 / e ? 0 : 2147483648), (jspb.utils.split64Low = 0); else if (isNaN(e)) (jspb.utils.split64High = 2147483647), (jspb.utils.split64Low = 4294967295); else if (e > jspb.BinaryConstants.FLOAT64_MAX) (jspb.utils.split64High = ((t << 31) | 2146435072) >>> 0), (jspb.utils.split64Low = 0); else if (e < jspb.BinaryConstants.FLOAT64_MIN) { var r = e / Math.pow(2, -1074); (e = r / jspb.BinaryConstants.TWO_TO_32), (jspb.utils.split64High = ((t << 31) | e) >>> 0), (jspb.utils.split64Low = r >>> 0); } else { var o = 0; if (2 <= (r = e)) for (; 2 <= r && 1023 > o; ) o++, (r /= 2); else for (; 1 > r && -1022 < o; ) (r *= 2), o--; (e = ((r = e * Math.pow(2, -o)) * jspb.BinaryConstants.TWO_TO_20) & 1048575), (r = (r * jspb.BinaryConstants.TWO_TO_52) >>> 0), (jspb.utils.split64High = ((t << 31) | ((o + 1023) << 20) | e) >>> 0), (jspb.utils.split64Low = r); } }), (jspb.utils.splitHash64 = function(e) { var t = e.charCodeAt(0), r = e.charCodeAt(1), o = e.charCodeAt(2), i = e.charCodeAt(3), a = e.charCodeAt(4), n = e.charCodeAt(5), s = e.charCodeAt(6); (e = e.charCodeAt(7)), (jspb.utils.split64Low = (t + (r << 8) + (o << 16) + (i << 24)) >>> 0), (jspb.utils.split64High = (a + (n << 8) + (s << 16) + (e << 24)) >>> 0); }), (jspb.utils.joinUint64 = function(e, t) { return t * jspb.BinaryConstants.TWO_TO_32 + (e >>> 0); }), (jspb.utils.joinInt64 = function(e, t) { var r = 2147483648 & t; return ( r && ((t = ~t >>> 0), 0 == (e = (1 + ~e) >>> 0) && (t = (t + 1) >>> 0)), (e = jspb.utils.joinUint64(e, t)), r ? -e : e ); }), (jspb.utils.toZigzag64 = function(e, t, r) { var o = t >> 31; return r((e << 1) ^ o, ((t << 1) | (e >>> 31)) ^ o); }), (jspb.utils.joinZigzag64 = function(e, t) { return jspb.utils.fromZigzag64(e, t, jspb.utils.joinInt64); }), (jspb.utils.fromZigzag64 = function(e, t, r) { var o = -(1 & e); return r(((e >>> 1) | (t << 31)) ^ o, (t >>> 1) ^ o); }), (jspb.utils.joinFloat32 = function(e, t) { t = 2 * (e >> 31) + 1; var r = (e >>> 23) & 255; return ( (e &= 8388607), 255 == r ? e ? NaN : (1 / 0) * t : 0 == r ? t * Math.pow(2, -149) * e : t * Math.pow(2, r - 150) * (e + Math.pow(2, 23)) ); }), (jspb.utils.joinFloat64 = function(e, t) { var r = 2 * (t >> 31) + 1, o = (t >>> 20) & 2047; return ( (e = jspb.BinaryConstants.TWO_TO_32 * (1048575 & t) + e), 2047 == o ? e ? NaN : (1 / 0) * r : 0 == o ? r * Math.pow(2, -1074) * e : r * Math.pow(2, o - 1075) * (e + jspb.BinaryConstants.TWO_TO_52) ); }), (jspb.utils.joinHash64 = function(e, t) { return String.fromCharCode( (e >>> 0) & 255, (e >>> 8) & 255, (e >>> 16) & 255, (e >>> 24) & 255, (t >>> 0) & 255, (t >>> 8) & 255, (t >>> 16) & 255, (t >>> 24) & 255 ); }), (jspb.utils.DIGITS = '0123456789abcdef'.split('')), (jspb.utils.ZERO_CHAR_CODE_ = 48), (jspb.utils.A_CHAR_CODE_ = 97), (jspb.utils.joinUnsignedDecimalString = function(e, t) { function r(e, t) { return (e = e ? String(e) : ''), t ? '0000000'.slice(e.length) + e : e; } if (2097151 >= t) return '' + jspb.utils.joinUint64(e, t); var o = (((e >>> 24) | (t << 8)) >>> 0) & 16777215; return ( (e = (16777215 & e) + 6777216 * o + 6710656 * (t = (t >> 16) & 65535)), (o += 8147497 * t), (t *= 2), 1e7 <= e && ((o += Math.floor(e / 1e7)), (e %= 1e7)), 1e7 <= o && ((t += Math.floor(o / 1e7)), (o %= 1e7)), r(t, 0) + r(o, t) + r(e, 1) ); }), (jspb.utils.joinSignedDecimalString = function(e, t) { var r = 2147483648 & t; return ( r && (t = (~t + (0 == (e = (1 + ~e) >>> 0) ? 1 : 0)) >>> 0), (e = jspb.utils.joinUnsignedDecimalString(e, t)), r ? '-' + e : e ); }), (jspb.utils.hash64ToDecimalString = function(e, t) { jspb.utils.splitHash64(e), (e = jspb.utils.split64Low); var r = jspb.utils.split64High; return t ? jspb.utils.joinSignedDecimalString(e, r) : jspb.utils.joinUnsignedDecimalString(e, r); }), (jspb.utils.hash64ArrayToDecimalStrings = function(e, t) { for (var r = Array(e.length), o = 0; o < e.length; o++) r[o] = jspb.utils.hash64ToDecimalString(e[o], t); return r; }), (jspb.utils.decimalStringToHash64 = function(e) { function t(e, t) { for (var r = 0; 8 > r && (1 !== e || 0 < t); r++) (t = e * o[r] + t), (o[r] = 255 & t), (t >>>= 8); } jspb.asserts.assert(0 < e.length); var r = !1; '-' === e[0] && ((r = !0), (e = e.slice(1))); for (var o = [0, 0, 0, 0, 0, 0, 0, 0], i = 0; i < e.length; i++) t(10, e.charCodeAt(i) - jspb.utils.ZERO_CHAR_CODE_); return ( r && ((function() { for (var e = 0; 8 > e; e++) o[e] = 255 & ~o[e]; })(), t(1, 1)), goog.crypt.byteArrayToString(o) ); }), (jspb.utils.splitDecimalString = function(e) { jspb.utils.splitHash64(jspb.utils.decimalStringToHash64(e)); }), (jspb.utils.toHexDigit_ = function(e) { return String.fromCharCode( 10 > e ? jspb.utils.ZERO_CHAR_CODE_ + e : jspb.utils.A_CHAR_CODE_ - 10 + e ); }), (jspb.utils.fromHexCharCode_ = function(e) { return e >= jspb.utils.A_CHAR_CODE_ ? e - jspb.utils.A_CHAR_CODE_ + 10 : e - jspb.utils.ZERO_CHAR_CODE_; }), (jspb.utils.hash64ToHexString = function(e) { var t = Array(18); (t[0] = '0'), (t[1] = 'x'); for (var r = 0; 8 > r; r++) { var o = e.charCodeAt(7 - r); (t[2 * r + 2] = jspb.utils.toHexDigit_(o >> 4)), (t[2 * r + 3] = jspb.utils.toHexDigit_(15 & o)); } return t.join(''); }), (jspb.utils.hexStringToHash64 = function(e) { (e = e.toLowerCase()), jspb.asserts.assert(18 == e.length), jspb.asserts.assert('0' == e[0]), jspb.asserts.assert('x' == e[1]); for (var t = '', r = 0; 8 > r; r++) { var o = jspb.utils.fromHexCharCode_(e.charCodeAt(2 * r + 2)), i = jspb.utils.fromHexCharCode_(e.charCodeAt(2 * r + 3)); t = String.fromCharCode(16 * o + i) + t; } return t; }), (jspb.utils.hash64ToNumber = function(e, t) { jspb.utils.splitHash64(e), (e = jspb.utils.split64Low); var r = jspb.utils.split64High; return t ? jspb.utils.joinInt64(e, r) : jspb.utils.joinUint64(e, r); }), (jspb.utils.numberToHash64 = function(e) { return ( jspb.utils.splitInt64(e), jspb.utils.joinHash64(jspb.utils.split64Low, jspb.utils.split64High) ); }), (jspb.utils.countVarints = function(e, t, r) { for (var o = 0, i = t; i < r; i++) o += e[i] >> 7; return r - t - o; }), (jspb.utils.countVarintFields = function(e, t, r, o) { var i = 0; if (128 > (o = 8 * o + jspb.BinaryConstants.WireType.VARINT)) for (; t < r && e[t++] == o; ) for (i++; ; ) { var a = e[t++]; if (0 == (128 & a)) break; } else for (; t < r; ) { for (a = o; 128 < a; ) { if (e[t] != ((127 & a) | 128)) return i; t++, (a >>= 7); } if (e[t++] != a) break; for (i++; 0 != (128 & (a = e[t++])); ); } return i; }), (jspb.utils.countFixedFields_ = function(e, t, r, o, i) { var a = 0; if (128 > o) for (; t < r && e[t++] == o; ) a++, (t += i); else for (; t < r; ) { for (var n = o; 128 < n; ) { if (e[t++] != ((127 & n) | 128)) return a; n >>= 7; } if (e[t++] != n) break; a++, (t += i); } return a; }), (jspb.utils.countFixed32Fields = function(e, t, r, o) { return jspb.utils.countFixedFields_( e, t, r, 8 * o + jspb.BinaryConstants.WireType.FIXED32, 4 ); }), (jspb.utils.countFixed64Fields = function(e, t, r, o) { return jspb.utils.countFixedFields_( e, t, r, 8 * o + jspb.BinaryConstants.WireType.FIXED64, 8 ); }), (jspb.utils.countDelimitedFields = function(e, t, r, o) { var i = 0; for (o = 8 * o + jspb.BinaryConstants.WireType.DELIMITED; t < r; ) { for (var a = o; 128 < a; ) { if (e[t++] != ((127 & a) | 128)) return i; a >>= 7; } if (e[t++] != a) break; i++; for ( var n = 0, s = 1; (n += (127 & (a = e[t++])) * s), (s *= 128), 0 != (128 & a); ); t += n; } return i; }), (jspb.utils.debugBytesToTextFormat = function(e) { var t = '"'; if (e) { e = jspb.utils.byteSourceToUint8Array(e); for (var r = 0; r < e.length; r++) (t += '\\x'), 16 > e[r] && (t += '0'), (t += e[r].toString(16)); } return t + '"'; }), (jspb.utils.debugScalarToTextFormat = function(e) { return 'string' == typeof e ? goog.string.quote(e) : e.toString(); }), (jspb.utils.stringToByteArray = function(e) { for (var t = new Uint8Array(e.length), r = 0; r < e.length; r++) { var o = e.charCodeAt(r); if (255 < o) throw Error( 'Conversion error: string contains codepoint outside of byte range' ); t[r] = o; } return t; }), (jspb.utils.byteSourceToUint8Array = function(e) { return e.constructor === Uint8Array ? e : e.constructor === ArrayBuffer || e.constructor === Array ? new Uint8Array(e) : e.constructor === String ? goog.crypt.base64.decodeStringToUint8Array(e) : e instanceof Uint8Array ? new Uint8Array(e.buffer, e.byteOffset, e.byteLength) : (jspb.asserts.fail('Type not convertible to Uint8Array.'), new Uint8Array(0)); }), (jspb.BinaryDecoder = function(e, t, r) { (this.bytes_ = null), (this.cursor_ = this.end_ = this.start_ = 0), (this.error_ = !1), e && this.setBlock(e, t, r); }), (jspb.BinaryDecoder.instanceCache_ = []), (jspb.BinaryDecoder.alloc = function(e, t, r) { if (jspb.BinaryDecoder.instanceCache_.length) { var o = jspb.BinaryDecoder.instanceCache_.pop(); return e && o.setBlock(e, t, r), o; } return new jspb.BinaryDecoder(e, t, r); }), (jspb.BinaryDecoder.prototype.free = function() { this.clear(), 100 > jspb.BinaryDecoder.instanceCache_.length && jspb.BinaryDecoder.instanceCache_.push(this); }), (jspb.BinaryDecoder.prototype.clone = function() { return jspb.BinaryDecoder.alloc(this.bytes_, this.start_, this.end_ - this.start_); }), (jspb.BinaryDecoder.prototype.clear = function() { (this.bytes_ = null), (this.cursor_ = this.end_ = this.start_ = 0), (this.error_ = !1); }), (jspb.BinaryDecoder.prototype.getBuffer = function() { return this.bytes_; }), (jspb.BinaryDecoder.prototype.setBlock = function(e, t, r) { (this.bytes_ = jspb.utils.byteSourceToUint8Array(e)), (this.start_ = void 0 !== t ? t : 0), (this.end_ = void 0 !== r ? this.start_ + r : this.bytes_.length), (this.cursor_ = this.start_); }), (jspb.BinaryDecoder.prototype.getEnd = function() { return this.end_; }), (jspb.BinaryDecoder.prototype.setEnd = function(e) { this.end_ = e; }), (jspb.BinaryDecoder.prototype.reset = function() { this.cursor_ = this.start_; }), (jspb.BinaryDecoder.prototype.getCursor = function() { return this.cursor_; }), (jspb.BinaryDecoder.prototype.setCursor = function(e) { this.cursor_ = e; }), (jspb.BinaryDecoder.prototype.advance = function(e) { (this.cursor_ += e), jspb.asserts.assert(this.cursor_ <= this.end_); }), (jspb.BinaryDecoder.prototype.atEnd = function() { return this.cursor_ == this.end_; }), (jspb.BinaryDecoder.prototype.pastEnd = function() { return this.cursor_ > this.end_; }), (jspb.BinaryDecoder.prototype.getError = function() { return this.error_ || 0 > this.cursor_ || this.cursor_ > this.end_; }), (jspb.BinaryDecoder.prototype.readSplitVarint64 = function(e) { for (var t = 128, r = 0, o = 0, i = 0; 4 > i && 128 <= t; i++) r |= (127 & (t = this.bytes_[this.cursor_++])) << (7 * i); if ( (128 <= t && ((r |= (127 & (t = this.bytes_[this.cursor_++])) << 28), (o |= (127 & t) >> 4)), 128 <= t) ) for (i = 0; 5 > i && 128 <= t; i++) o |= (127 & (t = this.bytes_[this.cursor_++])) << (7 * i + 3); if (128 > t) return e(r >>> 0, o >>> 0); jspb.asserts.fail('Failed to read varint, encoding is invalid.'), (this.error_ = !0); }), (jspb.BinaryDecoder.prototype.readSplitZigzagVarint64 = function(e) { return this.readSplitVarint64(function(t, r) { return jspb.utils.fromZigzag64(t, r, e); }); }), (jspb.BinaryDecoder.prototype.readSplitFixed64 = function(e) { var t = this.bytes_, r = this.cursor_; this.cursor_ += 8; for (var o = 0, i = 0, a = r + 7; a >= r; a--) (o = (o << 8) | t[a]), (i = (i << 8) | t[a + 4]); return e(o, i); }), (jspb.BinaryDecoder.prototype.skipVarint = function() { for (; 128 & this.bytes_[this.cursor_]; ) this.cursor_++; this.cursor_++; }), (jspb.BinaryDecoder.prototype.unskipVarint = function(e) { for (; 128 < e; ) this.cursor_--, (e >>>= 7); this.cursor_--; }), (jspb.BinaryDecoder.prototype.readUnsignedVarint32 = function() { var e = this.bytes_, t = e[this.cursor_ + 0], r = 127 & t; return 128 > t ? ((this.cursor_ += 1), jspb.asserts.assert(this.cursor_ <= this.end_), r) : ((r |= (127 & (t = e[this.cursor_ + 1])) << 7), 128 > t ? ((this.cursor_ += 2), jspb.asserts.assert(this.cursor_ <= this.end_), r) : ((r |= (127 & (t = e[this.cursor_ + 2])) << 14), 128 > t ? ((this.cursor_ += 3), jspb.asserts.assert(this.cursor_ <= this.end_), r) : ((r |= (127 & (t = e[this.cursor_ + 3])) << 21), 128 > t ? ((this.cursor_ += 4), jspb.asserts.assert(this.cursor_ <= this.end_), r) : ((r |= (15 & (t = e[this.cursor_ + 4])) << 28), 128 > t ? ((this.cursor_ += 5), jspb.asserts.assert(this.cursor_ <= this.end_), r >>> 0) : ((this.cursor_ += 5), 128 <= e[this.cursor_++] && 128 <= e[this.cursor_++] && 128 <= e[this.cursor_++] && 128 <= e[this.cursor_++] && 128 <= e[this.cursor_++] && jspb.asserts.assert(!1), jspb.asserts.assert(this.cursor_ <= this.end_), r))))); }), (jspb.BinaryDecoder.prototype.readSignedVarint32 = function() { return ~~this.readUnsignedVarint32(); }), (jspb.BinaryDecoder.prototype.readUnsignedVarint32String = function() { return this.readUnsignedVarint32().toString(); }), (jspb.BinaryDecoder.prototype.readSignedVarint32String = function() { return this.readSignedVarint32().toString(); }), (jspb.BinaryDecoder.prototype.readZigzagVarint32 = function() { var e = this.readUnsignedVarint32(); return (e >>> 1) ^ -(1 & e); }), (jspb.BinaryDecoder.prototype.readUnsignedVarint64 = function() { return this.readSplitVarint64(jspb.utils.joinUint64); }), (jspb.BinaryDecoder.prototype.readUnsignedVarint64String = function() { return this.readSplitVarint64(jspb.utils.joinUnsignedDecimalString); }), (jspb.BinaryDecoder.prototype.readSignedVarint64 = function() { return this.readSplitVarint64(jspb.utils.joinInt64); }), (jspb.BinaryDecoder.prototype.readSignedVarint64String = function() { return this.readSplitVarint64(jspb.utils.joinSignedDecimalString); }), (jspb.BinaryDecoder.prototype.readZigzagVarint64 = function() { return this.readSplitVarint64(jspb.utils.joinZigzag64); }), (jspb.BinaryDecoder.prototype.readZigzagVarintHash64 = function() { return this.readSplitZigzagVarint64(jspb.utils.joinHash64); }), (jspb.BinaryDecoder.prototype.readZigzagVarint64String = function() { return this.readSplitZigzagVarint64(jspb.utils.joinSignedDecimalString); }), (jspb.BinaryDecoder.prototype.readUint8 = function() { var e = this.bytes_[this.cursor_ + 0]; return (this.cursor_ += 1), jspb.asserts.assert(this.cursor_ <= this.end_), e; }), (jspb.BinaryDecoder.prototype.readUint16 = function() { var e = this.bytes_[this.cursor_ + 0], t = this.bytes_[this.cursor_ + 1]; return ( (this.cursor_ += 2), jspb.asserts.assert(this.cursor_ <= this.end_), (e << 0) | (t << 8) ); }), (jspb.BinaryDecoder.prototype.readUint32 = function() { var e = this.bytes_[this.cursor_ + 0], t = this.bytes_[this.cursor_ + 1], r = this.bytes_[this.cursor_ + 2], o = this.bytes_[this.cursor_ + 3]; return ( (this.cursor_ += 4), jspb.asserts.assert(this.cursor_ <= this.end_), ((e << 0) | (t << 8) | (r << 16) | (o << 24)) >>> 0 ); }), (jspb.BinaryDecoder.prototype.readUint64 = function() { var e = this.readUint32(), t = this.readUint32(); return jspb.utils.joinUint64(e, t); }), (jspb.BinaryDecoder.prototype.readUint64String = function() { var e = this.readUint32(), t = this.readUint32(); return jspb.utils.joinUnsignedDecimalString(e, t); }), (jspb.BinaryDecoder.prototype.readInt8 = function() { var e = this.bytes_[this.cursor_ + 0]; return ( (this.cursor_ += 1), jspb.asserts.assert(this.cursor_ <= this.end_), (e << 24) >> 24 ); }), (jspb.BinaryDecoder.prototype.readInt16 = function() { var e = this.bytes_[this.cursor_ + 0], t = this.bytes_[this.cursor_ + 1]; return ( (this.cursor_ += 2), jspb.asserts.assert(this.cursor_ <= this.end_), (((e << 0) | (t << 8)) << 16) >> 16 ); }), (jspb.BinaryDecoder.prototype.readInt32 = function() { var e = this.bytes_[this.cursor_ + 0], t = this.bytes_[this.cursor_ + 1], r = this.bytes_[this.cursor_ + 2], o = this.bytes_[this.cursor_ + 3]; return ( (this.cursor_ += 4), jspb.asserts.assert(this.cursor_ <= this.end_), (e << 0) | (t << 8) | (r << 16) | (o << 24) ); }), (jspb.BinaryDecoder.prototype.readInt64 = function() { var e = this.readUint32(), t = this.readUint32(); return jspb.utils.joinInt64(e, t); }), (jspb.BinaryDecoder.prototype.readInt64String = function() { var e = this.readUint32(), t = this.readUint32(); return jspb.utils.joinSignedDecimalString(e, t); }), (jspb.BinaryDecoder.prototype.readFloat = function() { var e = this.readUint32(); return jspb.utils.joinFloat32(e, 0); }), (jspb.BinaryDecoder.prototype.readDouble = function() { var e = this.readUint32(), t = this.readUint32(); return jspb.utils.joinFloat64(e, t); }), (jspb.BinaryDecoder.prototype.readBool = function() { return !!this.bytes_[this.cursor_++]; }), (jspb.BinaryDecoder.prototype.readEnum = function() { return this.readSignedVarint32(); }), (jspb.BinaryDecoder.prototype.readString = function(e) { var t = this.bytes_, r = this.cursor_; e = r + e; for (var o = [], i = ''; r < e; ) { var a = t[r++]; if (128 > a) o.push(a); else { if (192 > a) continue; if (224 > a) { var n = t[r++]; o.push(((31 & a) << 6) | (63 & n)); } else if (240 > a) { n = t[r++]; var s = t[r++]; o.push(((15 & a) << 12) | ((63 & n) << 6) | (63 & s)); } else if (248 > a) { (a = ((7 & a) << 18) | ((63 & (n = t[r++])) << 12) | ((63 & (s = t[r++])) << 6) | (63 & t[r++])), (a -= 65536), o.push(55296 + ((a >> 10) & 1023), 56320 + (1023 & a)); } } 8192 <= o.length && ((i += String.fromCharCode.apply(null, o)), (o.length = 0)); } return (i += goog.crypt.byteArrayToString(o)), (this.cursor_ = r), i; }), (jspb.BinaryDecoder.prototype.readStringWithLength = function() { var e = this.readUnsignedVarint32(); return this.readString(e); }), (jspb.BinaryDecoder.prototype.readBytes = function(e) { if (0 > e || this.cursor_ + e > this.bytes_.length) return ( (this.error_ = !0), jspb.asserts.fail('Invalid byte length!'), new Uint8Array(0) ); var t = this.bytes_.subarray(this.cursor_, this.cursor_ + e); return (this.cursor_ += e), jspb.asserts.assert(this.cursor_ <= this.end_), t; }), (jspb.BinaryDecoder.prototype.readVarintHash64 = function() { return this.readSplitVarint64(jspb.utils.joinHash64); }), (jspb.BinaryDecoder.prototype.readFixedHash64 = function() { var e = this.bytes_, t = this.cursor_, r = e[t + 0], o = e[t + 1], i = e[t + 2], a = e[t + 3], n = e[t + 4], s = e[t + 5], p = e[t + 6]; return (e = e[t + 7]), (this.cursor_ += 8), String.fromCharCode(r, o, i, a, n, s, p, e); }), (jspb.BinaryReader = function(e, t, r) { (this.decoder_ = jspb.BinaryDecoder.alloc(e, t, r)), (this.fieldCursor_ = this.decoder_.getCursor()), (this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER), (this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID), (this.error_ = !1), (this.readCallbacks_ = null); }), (jspb.BinaryReader.instanceCache_ = []), (jspb.BinaryReader.alloc = function(e, t, r) { if (jspb.BinaryReader.instanceCache_.length) { var o = jspb.BinaryReader.instanceCache_.pop(); return e && o.decoder_.setBlock(e, t, r), o; } return new jspb.BinaryReader(e, t, r); }), (jspb.BinaryReader.prototype.alloc = jspb.BinaryReader.alloc), (jspb.BinaryReader.prototype.free = function() { this.decoder_.clear(), (this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER), (this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID), (this.error_ = !1), (this.readCallbacks_ = null), 100 > jspb.BinaryReader.instanceCache_.length && jspb.BinaryReader.instanceCache_.push(this); }), (jspb.BinaryReader.prototype.getFieldCursor = function() { return this.fieldCursor_; }), (jspb.BinaryReader.prototype.getCursor = function() { return this.decoder_.getCursor(); }), (jspb.BinaryReader.prototype.getBuffer = function() { return this.decoder_.getBuffer(); }), (jspb.BinaryReader.prototype.getFieldNumber = function() { return this.nextField_; }), goog.exportProperty( jspb.BinaryReader.prototype, 'getFieldNumber', jspb.BinaryReader.prototype.getFieldNumber ), (jspb.BinaryReader.prototype.getWireType = function() { return this.nextWireType_; }), (jspb.BinaryReader.prototype.isDelimited = function() { return this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED; }), goog.exportProperty( jspb.BinaryReader.prototype, 'isDelimited', jspb.BinaryReader.prototype.isDelimited ), (jspb.BinaryReader.prototype.isEndGroup = function() { return this.nextWireType_ == jspb.BinaryConstants.WireType.END_GROUP; }), goog.exportProperty( jspb.BinaryReader.prototype, 'isEndGroup', jspb.BinaryReader.prototype.isEndGroup ), (jspb.BinaryReader.prototype.getError = function() { return this.error_ || this.decoder_.getError(); }), (jspb.BinaryReader.prototype.setBlock = function(e, t, r) { this.decoder_.setBlock(e, t, r), (this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER), (this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID); }), (jspb.BinaryReader.prototype.reset = function() { this.decoder_.reset(), (this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER), (this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID); }), (jspb.BinaryReader.prototype.advance = function(e) { this.decoder_.advance(e); }), (jspb.BinaryReader.prototype.nextField = function() { if (this.decoder_.atEnd()) return !1; if (this.getError()) return jspb.asserts.fail('Decoder hit an error'), !1; this.fieldCursor_ = this.decoder_.getCursor(); var e = this.decoder_.readUnsignedVarint32(), t = e >>> 3; return (e &= 7) != jspb.BinaryConstants.WireType.VARINT && e != jspb.BinaryConstants.WireType.FIXED32 && e != jspb.BinaryConstants.WireType.FIXED64 && e != jspb.BinaryConstants.WireType.DELIMITED && e != jspb.BinaryConstants.WireType.START_GROUP && e != jspb.BinaryConstants.WireType.END_GROUP ? (jspb.asserts.fail( 'Invalid wire type: %s (at position %s)', e, this.fieldCursor_ ), (this.error_ = !0), !1) : ((this.nextField_ = t), (this.nextWireType_ = e), !0); }), goog.exportProperty( jspb.BinaryReader.prototype, 'nextField', jspb.BinaryReader.prototype.nextField ), (jspb.BinaryReader.prototype.unskipHeader = function() { this.decoder_.unskipVarint((this.nextField_ << 3) | this.nextWireType_); }), (jspb.BinaryReader.prototype.skipMatchingFields = function() { var e = this.nextField_; for (this.unskipHeader(); this.nextField() && this.getFieldNumber() == e; ) this.skipField(); this.decoder_.atEnd() || this.unskipHeader(); }), (jspb.BinaryReader.prototype.skipVarintField = function() { this.nextWireType_ != jspb.BinaryConstants.WireType.VARINT ? (jspb.asserts.fail('Invalid wire type for skipVarintField'), this.skipField()) : this.decoder_.skipVarint(); }), (jspb.BinaryReader.prototype.skipDelimitedField = function() { if (this.nextWireType_ != jspb.BinaryConstants.WireType.DELIMITED) jspb.asserts.fail('Invalid wire type for skipDelimitedField'), this.skipField(); else { var e = this.decoder_.readUnsignedVarint32(); this.decoder_.advance(e); } }), (jspb.BinaryReader.prototype.skipFixed32Field = function() { this.nextWireType_ != jspb.BinaryConstants.WireType.FIXED32 ? (jspb.asserts.fail('Invalid wire type for skipFixed32Field'), this.skipField()) : this.decoder_.advance(4); }), (jspb.BinaryReader.prototype.skipFixed64Field = function() { this.nextWireType_ != jspb.BinaryConstants.WireType.FIXED64 ? (jspb.asserts.fail('Invalid wire type for skipFixed64Field'), this.skipField()) : this.decoder_.advance(8); }), (jspb.BinaryReader.prototype.skipGroup = function() { for (var e = this.nextField_; ; ) { if (!this.nextField()) { jspb.asserts.fail('Unmatched start-group tag: stream EOF'), (this.error_ = !0); break; } if (this.nextWireType_ == jspb.BinaryConstants.WireType.END_GROUP) { this.nextField_ != e && (jspb.asserts.fail('Unmatched end-group tag'), (this.error_ = !0)); break; } this.skipField(); } }), (jspb.BinaryReader.prototype.skipField = function() { switch (this.nextWireType_) { case jspb.BinaryConstants.WireType.VARINT: this.skipVarintField(); break; case jspb.BinaryConstants.WireType.FIXED64: this.skipFixed64Field(); break; case jspb.BinaryConstants.WireType.DELIMITED: this.skipDelimitedField(); break; case jspb.BinaryConstants.WireType.FIXED32: this.skipFixed32Field(); break; case jspb.BinaryConstants.WireType.START_GROUP: this.skipGroup(); break; default: jspb.asserts.fail('Invalid wire encoding for field.'); } }), (jspb.BinaryReader.prototype.registerReadCallback = function(e, t) { null === this.readCallbacks_ && (this.readCallbacks_ = {}), jspb.asserts.assert(!this.readCallbacks_[e]), (this.readCallbacks_[e] = t); }), (jspb.BinaryReader.prototype.runReadCallback = function(e) { return ( jspb.asserts.assert(null !== this.readCallbacks_), (e = this.readCallbacks_[e]), jspb.asserts.assert(e), e(this) ); }), (jspb.BinaryReader.prototype.readAny = function(e) { this.nextWireType_ = jspb.BinaryConstants.FieldTypeToWireType(e); var t = jspb.BinaryConstants.FieldType; switch (e) { case t.DOUBLE: return this.readDouble(); case t.FLOAT: return this.readFloat(); case t.INT64: return this.readInt64(); case t.UINT64: return this.readUint64(); case t.INT32: return this.readInt32(); case t.FIXED64: return this.readFixed64(); case t.FIXED32: return this.readFixed32(); case t.BOOL: return this.readBool(); case t.STRING: return this.readString(); case t.GROUP: jspb.asserts.fail('Group field type not supported in readAny()'); case t.MESSAGE: jspb.asserts.fail('Message field type not supported in readAny()'); case t.BYTES: return this.readBytes(); case t.UINT32: return this.readUint32(); case t.ENUM: return this.readEnum(); case t.SFIXED32: return this.readSfixed32(); case t.SFIXED64: return this.readSfixed64(); case t.SINT32: return this.readSint32(); case t.SINT64: return this.readSint64(); case t.FHASH64: return this.readFixedHash64(); case t.VHASH64: return this.readVarintHash64(); default: jspb.asserts.fail('Invalid field type in readAny()'); } return 0; }), (jspb.BinaryReader.prototype.readMessage = function(e, t) { jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED); var r = this.decoder_.getEnd(), o = this.decoder_.readUnsignedVarint32(); (o = this.decoder_.getCursor() + o), this.decoder_.setEnd(o), t(e, this), this.decoder_.setCursor(o), this.decoder_.setEnd(r); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readMessage', jspb.BinaryReader.prototype.readMessage ), (jspb.BinaryReader.prototype.readGroup = function(e, t, r) { jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.START_GROUP), jspb.asserts.assert(this.nextField_ == e), r(t, this), this.error_ || this.nextWireType_ == jspb.BinaryConstants.WireType.END_GROUP || (jspb.asserts.fail('Group submessage did not end with an END_GROUP tag'), (this.error_ = !0)); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readGroup', jspb.BinaryReader.prototype.readGroup ), (jspb.BinaryReader.prototype.getFieldDecoder = function() { jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED); var e = this.decoder_.readUnsignedVarint32(), t = this.decoder_.getCursor(), r = t + e; return ( (e = jspb.BinaryDecoder.alloc(this.decoder_.getBuffer(), t, e)), this.decoder_.setCursor(r), e ); }), (jspb.BinaryReader.prototype.readInt32 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readSignedVarint32() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readInt32', jspb.BinaryReader.prototype.readInt32 ), (jspb.BinaryReader.prototype.readInt32String = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readSignedVarint32String() ); }), (jspb.BinaryReader.prototype.readInt64 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readSignedVarint64() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readInt64', jspb.BinaryReader.prototype.readInt64 ), (jspb.BinaryReader.prototype.readInt64String = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readSignedVarint64String() ); }), (jspb.BinaryReader.prototype.readUint32 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readUnsignedVarint32() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readUint32', jspb.BinaryReader.prototype.readUint32 ), (jspb.BinaryReader.prototype.readUint32String = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readUnsignedVarint32String() ); }), (jspb.BinaryReader.prototype.readUint64 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readUnsignedVarint64() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readUint64', jspb.BinaryReader.prototype.readUint64 ), (jspb.BinaryReader.prototype.readUint64String = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readUnsignedVarint64String() ); }), (jspb.BinaryReader.prototype.readSint32 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readZigzagVarint32() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readSint32', jspb.BinaryReader.prototype.readSint32 ), (jspb.BinaryReader.prototype.readSint64 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readZigzagVarint64() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readSint64', jspb.BinaryReader.prototype.readSint64 ), (jspb.BinaryReader.prototype.readSint64String = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readZigzagVarint64String() ); }), (jspb.BinaryReader.prototype.readFixed32 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32), this.decoder_.readUint32() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readFixed32', jspb.BinaryReader.prototype.readFixed32 ), (jspb.BinaryReader.prototype.readFixed64 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64), this.decoder_.readUint64() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readFixed64', jspb.BinaryReader.prototype.readFixed64 ), (jspb.BinaryReader.prototype.readFixed64String = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64), this.decoder_.readUint64String() ); }), (jspb.BinaryReader.prototype.readSfixed32 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32), this.decoder_.readInt32() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readSfixed32', jspb.BinaryReader.prototype.readSfixed32 ), (jspb.BinaryReader.prototype.readSfixed32String = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32), this.decoder_.readInt32().toString() ); }), (jspb.BinaryReader.prototype.readSfixed64 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64), this.decoder_.readInt64() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readSfixed64', jspb.BinaryReader.prototype.readSfixed64 ), (jspb.BinaryReader.prototype.readSfixed64String = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64), this.decoder_.readInt64String() ); }), (jspb.BinaryReader.prototype.readFloat = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32), this.decoder_.readFloat() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readFloat', jspb.BinaryReader.prototype.readFloat ), (jspb.BinaryReader.prototype.readDouble = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64), this.decoder_.readDouble() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readDouble', jspb.BinaryReader.prototype.readDouble ), (jspb.BinaryReader.prototype.readBool = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), !!this.decoder_.readUnsignedVarint32() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readBool', jspb.BinaryReader.prototype.readBool ), (jspb.BinaryReader.prototype.readEnum = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readSignedVarint64() ); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readEnum', jspb.BinaryReader.prototype.readEnum ), (jspb.BinaryReader.prototype.readString = function() { jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED); var e = this.decoder_.readUnsignedVarint32(); return this.decoder_.readString(e); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readString', jspb.BinaryReader.prototype.readString ), (jspb.BinaryReader.prototype.readBytes = function() { jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED); var e = this.decoder_.readUnsignedVarint32(); return this.decoder_.readBytes(e); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readBytes', jspb.BinaryReader.prototype.readBytes ), (jspb.BinaryReader.prototype.readVarintHash64 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readVarintHash64() ); }), (jspb.BinaryReader.prototype.readSintHash64 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readZigzagVarintHash64() ); }), (jspb.BinaryReader.prototype.readSplitVarint64 = function(e) { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readSplitVarint64(e) ); }), (jspb.BinaryReader.prototype.readSplitZigzagVarint64 = function(e) { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT), this.decoder_.readSplitVarint64(function(t, r) { return jspb.utils.fromZigzag64(t, r, e); }) ); }), (jspb.BinaryReader.prototype.readFixedHash64 = function() { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64), this.decoder_.readFixedHash64() ); }), (jspb.BinaryReader.prototype.readSplitFixed64 = function(e) { return ( jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64), this.decoder_.readSplitFixed64(e) ); }), (jspb.BinaryReader.prototype.readPackedField_ = function(e) { jspb.asserts.assert(this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED); var t = this.decoder_.readUnsignedVarint32(); t = this.decoder_.getCursor() + t; for (var r = []; this.decoder_.getCursor() < t; ) r.push(e.call(this.decoder_)); return r; }), (jspb.BinaryReader.prototype.readPackedInt32 = function() { return this.readPackedField_(this.decoder_.readSignedVarint32); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedInt32', jspb.BinaryReader.prototype.readPackedInt32 ), (jspb.BinaryReader.prototype.readPackedInt32String = function() { return this.readPackedField_(this.decoder_.readSignedVarint32String); }), (jspb.BinaryReader.prototype.readPackedInt64 = function() { return this.readPackedField_(this.decoder_.readSignedVarint64); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedInt64', jspb.BinaryReader.prototype.readPackedInt64 ), (jspb.BinaryReader.prototype.readPackedInt64String = function() { return this.readPackedField_(this.decoder_.readSignedVarint64String); }), (jspb.BinaryReader.prototype.readPackedUint32 = function() { return this.readPackedField_(this.decoder_.readUnsignedVarint32); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedUint32', jspb.BinaryReader.prototype.readPackedUint32 ), (jspb.BinaryReader.prototype.readPackedUint32String = function() { return this.readPackedField_(this.decoder_.readUnsignedVarint32String); }), (jspb.BinaryReader.prototype.readPackedUint64 = function() { return this.readPackedField_(this.decoder_.readUnsignedVarint64); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedUint64', jspb.BinaryReader.prototype.readPackedUint64 ), (jspb.BinaryReader.prototype.readPackedUint64String = function() { return this.readPackedField_(this.decoder_.readUnsignedVarint64String); }), (jspb.BinaryReader.prototype.readPackedSint32 = function() { return this.readPackedField_(this.decoder_.readZigzagVarint32); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedSint32', jspb.BinaryReader.prototype.readPackedSint32 ), (jspb.BinaryReader.prototype.readPackedSint64 = function() { return this.readPackedField_(this.decoder_.readZigzagVarint64); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedSint64', jspb.BinaryReader.prototype.readPackedSint64 ), (jspb.BinaryReader.prototype.readPackedSint64String = function() { return this.readPackedField_(this.decoder_.readZigzagVarint64String); }), (jspb.BinaryReader.prototype.readPackedFixed32 = function() { return this.readPackedField_(this.decoder_.readUint32); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedFixed32', jspb.BinaryReader.prototype.readPackedFixed32 ), (jspb.BinaryReader.prototype.readPackedFixed64 = function() { return this.readPackedField_(this.decoder_.readUint64); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedFixed64', jspb.BinaryReader.prototype.readPackedFixed64 ), (jspb.BinaryReader.prototype.readPackedFixed64String = function() { return this.readPackedField_(this.decoder_.readUint64String); }), (jspb.BinaryReader.prototype.readPackedSfixed32 = function() { return this.readPackedField_(this.decoder_.readInt32); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedSfixed32', jspb.BinaryReader.prototype.readPackedSfixed32 ), (jspb.BinaryReader.prototype.readPackedSfixed64 = function() { return this.readPackedField_(this.decoder_.readInt64); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedSfixed64', jspb.BinaryReader.prototype.readPackedSfixed64 ), (jspb.BinaryReader.prototype.readPackedSfixed64String = function() { return this.readPackedField_(this.decoder_.readInt64String); }), (jspb.BinaryReader.prototype.readPackedFloat = function() { return this.readPackedField_(this.decoder_.readFloat); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedFloat', jspb.BinaryReader.prototype.readPackedFloat ), (jspb.BinaryReader.prototype.readPackedDouble = function() { return this.readPackedField_(this.decoder_.readDouble); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedDouble', jspb.BinaryReader.prototype.readPackedDouble ), (jspb.BinaryReader.prototype.readPackedBool = function() { return this.readPackedField_(this.decoder_.readBool); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedBool', jspb.BinaryReader.prototype.readPackedBool ), (jspb.BinaryReader.prototype.readPackedEnum = function() { return this.readPackedField_(this.decoder_.readEnum); }), goog.exportProperty( jspb.BinaryReader.prototype, 'readPackedEnum', jspb.BinaryReader.prototype.readPackedEnum ), (jspb.BinaryReader.prototype.readPackedVarintHash64 = function() { return this.readPackedField_(this.decoder_.readVarintHash64); }), (jspb.BinaryReader.prototype.readPackedFixedHash64 = function() { return this.readPackedField_(this.decoder_.readFixedHash64); }), (jspb.BinaryEncoder = function() { this.buffer_ = []; }), (jspb.BinaryEncoder.prototype.length = function() { return this.buffer_.length; }), (jspb.BinaryEncoder.prototype.end = function() { var e = this.buffer_; return (this.buffer_ = []), e; }), (jspb.BinaryEncoder.prototype.writeSplitVarint64 = function(e, t) { for ( jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert(t == Math.floor(t)), jspb.asserts.assert(0 <= e && e < jspb.BinaryConstants.TWO_TO_32), jspb.asserts.assert(0 <= t && t < jspb.BinaryConstants.TWO_TO_32); 0 < t || 127 < e; ) this.buffer_.push((127 & e) | 128), (e = ((e >>> 7) | (t << 25)) >>> 0), (t >>>= 7); this.buffer_.push(e); }), (jspb.BinaryEncoder.prototype.writeSplitFixed64 = function(e, t) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert(t == Math.floor(t)), jspb.asserts.assert(0 <= e && e < jspb.BinaryConstants.TWO_TO_32), jspb.asserts.assert(0 <= t && t < jspb.BinaryConstants.TWO_TO_32), this.writeUint32(e), this.writeUint32(t); }), (jspb.BinaryEncoder.prototype.writeUnsignedVarint32 = function(e) { for ( jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert(0 <= e && e < jspb.BinaryConstants.TWO_TO_32); 127 < e; ) this.buffer_.push((127 & e) | 128), (e >>>= 7); this.buffer_.push(e); }), (jspb.BinaryEncoder.prototype.writeSignedVarint32 = function(e) { if ( (jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert( e >= -jspb.BinaryConstants.TWO_TO_31 && e < jspb.BinaryConstants.TWO_TO_31 ), 0 <= e) ) this.writeUnsignedVarint32(e); else { for (var t = 0; 9 > t; t++) this.buffer_.push((127 & e) | 128), (e >>= 7); this.buffer_.push(1); } }), (jspb.BinaryEncoder.prototype.writeUnsignedVarint64 = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert(0 <= e && e < jspb.BinaryConstants.TWO_TO_64), jspb.utils.splitInt64(e), this.writeSplitVarint64(jspb.utils.split64Low, jspb.utils.split64High); }), (jspb.BinaryEncoder.prototype.writeSignedVarint64 = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert( e >= -jspb.BinaryConstants.TWO_TO_63 && e < jspb.BinaryConstants.TWO_TO_63 ), jspb.utils.splitInt64(e), this.writeSplitVarint64(jspb.utils.split64Low, jspb.utils.split64High); }), (jspb.BinaryEncoder.prototype.writeZigzagVarint32 = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert( e >= -jspb.BinaryConstants.TWO_TO_31 && e < jspb.BinaryConstants.TWO_TO_31 ), this.writeUnsignedVarint32(((e << 1) ^ (e >> 31)) >>> 0); }), (jspb.BinaryEncoder.prototype.writeZigzagVarint64 = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert( e >= -jspb.BinaryConstants.TWO_TO_63 && e < jspb.BinaryConstants.TWO_TO_63 ), jspb.utils.splitZigzag64(e), this.writeSplitVarint64(jspb.utils.split64Low, jspb.utils.split64High); }), (jspb.BinaryEncoder.prototype.writeZigzagVarint64String = function(e) { this.writeZigzagVarintHash64(jspb.utils.decimalStringToHash64(e)); }), (jspb.BinaryEncoder.prototype.writeZigzagVarintHash64 = function(e) { var t = this; jspb.utils.splitHash64(e), jspb.utils.toZigzag64(jspb.utils.split64Low, jspb.utils.split64High, function( e, r ) { t.writeSplitVarint64(e >>> 0, r >>> 0); }); }), (jspb.BinaryEncoder.prototype.writeUint8 = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert(0 <= e && 256 > e), this.buffer_.push((e >>> 0) & 255); }), (jspb.BinaryEncoder.prototype.writeUint16 = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert(0 <= e && 65536 > e), this.buffer_.push((e >>> 0) & 255), this.buffer_.push((e >>> 8) & 255); }), (jspb.BinaryEncoder.prototype.writeUint32 = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert(0 <= e && e < jspb.BinaryConstants.TWO_TO_32), this.buffer_.push((e >>> 0) & 255), this.buffer_.push((e >>> 8) & 255), this.buffer_.push((e >>> 16) & 255), this.buffer_.push((e >>> 24) & 255); }), (jspb.BinaryEncoder.prototype.writeUint64 = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert(0 <= e && e < jspb.BinaryConstants.TWO_TO_64), jspb.utils.splitUint64(e), this.writeUint32(jspb.utils.split64Low), this.writeUint32(jspb.utils.split64High); }), (jspb.BinaryEncoder.prototype.writeInt8 = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert(-128 <= e && 128 > e), this.buffer_.push((e >>> 0) & 255); }), (jspb.BinaryEncoder.prototype.writeInt16 = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert(-32768 <= e && 32768 > e), this.buffer_.push((e >>> 0) & 255), this.buffer_.push((e >>> 8) & 255); }), (jspb.BinaryEncoder.prototype.writeInt32 = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert( e >= -jspb.BinaryConstants.TWO_TO_31 && e < jspb.BinaryConstants.TWO_TO_31 ), this.buffer_.push((e >>> 0) & 255), this.buffer_.push((e >>> 8) & 255), this.buffer_.push((e >>> 16) & 255), this.buffer_.push((e >>> 24) & 255); }), (jspb.BinaryEncoder.prototype.writeInt64 = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert( e >= -jspb.BinaryConstants.TWO_TO_63 && e < jspb.BinaryConstants.TWO_TO_63 ), jspb.utils.splitInt64(e), this.writeSplitFixed64(jspb.utils.split64Low, jspb.utils.split64High); }), (jspb.BinaryEncoder.prototype.writeInt64String = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert( +e >= -jspb.BinaryConstants.TWO_TO_63 && +e < jspb.BinaryConstants.TWO_TO_63 ), jspb.utils.splitHash64(jspb.utils.decimalStringToHash64(e)), this.writeSplitFixed64(jspb.utils.split64Low, jspb.utils.split64High); }), (jspb.BinaryEncoder.prototype.writeFloat = function(e) { jspb.asserts.assert( 1 / 0 === e || -1 / 0 === e || isNaN(e) || (e >= -jspb.BinaryConstants.FLOAT32_MAX && e <= jspb.BinaryConstants.FLOAT32_MAX) ), jspb.utils.splitFloat32(e), this.writeUint32(jspb.utils.split64Low); }), (jspb.BinaryEncoder.prototype.writeDouble = function(e) { jspb.asserts.assert( 1 / 0 === e || -1 / 0 === e || isNaN(e) || (e >= -jspb.BinaryConstants.FLOAT64_MAX && e <= jspb.BinaryConstants.FLOAT64_MAX) ), jspb.utils.splitFloat64(e), this.writeUint32(jspb.utils.split64Low), this.writeUint32(jspb.utils.split64High); }), (jspb.BinaryEncoder.prototype.writeBool = function(e) { jspb.asserts.assert('boolean' == typeof e || 'number' == typeof e), this.buffer_.push(e ? 1 : 0); }), (jspb.BinaryEncoder.prototype.writeEnum = function(e) { jspb.asserts.assert(e == Math.floor(e)), jspb.asserts.assert( e >= -jspb.BinaryConstants.TWO_TO_31 && e < jspb.BinaryConstants.TWO_TO_31 ), this.writeSignedVarint32(e); }), (jspb.BinaryEncoder.prototype.writeBytes = function(e) { this.buffer_.push.apply(this.buffer_, e); }), (jspb.BinaryEncoder.prototype.writeVarintHash64 = function(e) { jspb.utils.splitHash64(e), this.writeSplitVarint64(jspb.utils.split64Low, jspb.utils.split64High); }), (jspb.BinaryEncoder.prototype.writeFixedHash64 = function(e) { jspb.utils.splitHash64(e), this.writeUint32(jspb.utils.split64Low), this.writeUint32(jspb.utils.split64High); }), (jspb.BinaryEncoder.prototype.writeString = function(e) { var t = this.buffer_.length; jspb.asserts.assertString(e); for (var r = 0; r < e.length; r++) { var o = e.charCodeAt(r); if (128 > o) this.buffer_.push(o); else if (2048 > o) this.buffer_.push((o >> 6) | 192), this.buffer_.push((63 & o) | 128); else if (65536 > o) if (55296 <= o && 56319 >= o && r + 1 < e.length) { var i = e.charCodeAt(r + 1); 56320 <= i && 57343 >= i && ((o = 1024 * (o - 55296) + i - 56320 + 65536), this.buffer_.push((o >> 18) | 240), this.buffer_.push(((o >> 12) & 63) | 128), this.buffer_.push(((o >> 6) & 63) | 128), this.buffer_.push((63 & o) | 128), r++); } else this.buffer_.push((o >> 12) | 224), this.buffer_.push(((o >> 6) & 63) | 128), this.buffer_.push((63 & o) | 128); } return this.buffer_.length - t; }), (jspb.arith = {}), (jspb.arith.UInt64 = function(e, t) { (this.lo = e), (this.hi = t); }), (jspb.arith.UInt64.prototype.cmp = function(e) { return this.hi < e.hi || (this.hi == e.hi && this.lo < e.lo) ? -1 : this.hi == e.hi && this.lo == e.lo ? 0 : 1; }), (jspb.arith.UInt64.prototype.rightShift = function() { return new jspb.arith.UInt64( ((this.lo >>> 1) | ((1 & this.hi) << 31)) >>> 0, (this.hi >>> 1) >>> 0 ); }), (jspb.arith.UInt64.prototype.leftShift = function() { return new jspb.arith.UInt64( (this.lo << 1) >>> 0, ((this.hi << 1) | (this.lo >>> 31)) >>> 0 ); }), (jspb.arith.UInt64.prototype.msb = function() { return !!(2147483648 & this.hi); }), (jspb.arith.UInt64.prototype.lsb = function() { return !!(1 & this.lo); }), (jspb.arith.UInt64.prototype.zero = function() { return 0 == this.lo && 0 == this.hi; }), (jspb.arith.UInt64.prototype.add = function(e) { return new jspb.arith.UInt64( (((this.lo + e.lo) & 4294967295) >>> 0) >>> 0, ((((this.hi + e.hi) & 4294967295) >>> 0) + (4294967296 <= this.lo + e.lo ? 1 : 0)) >>> 0 ); }), (jspb.arith.UInt64.prototype.sub = function(e) { return new jspb.arith.UInt64( (((this.lo - e.lo) & 4294967295) >>> 0) >>> 0, ((((this.hi - e.hi) & 4294967295) >>> 0) - (0 > this.lo - e.lo ? 1 : 0)) >>> 0 ); }), (jspb.arith.UInt64.mul32x32 = function(e, t) { var r = 65535 & e, o = 65535 & t, i = t >>> 16; for ( t = r * o + 65536 * ((r * i) & 65535) + 65536 * (((e >>>= 16) * o) & 65535), r = e * i + ((r * i) >>> 16) + ((e * o) >>> 16); 4294967296 <= t; ) (t -= 4294967296), (r += 1); return new jspb.arith.UInt64(t >>> 0, r >>> 0); }), (jspb.arith.UInt64.prototype.mul = function(e) { var t = jspb.arith.UInt64.mul32x32(this.lo, e); return ((e = jspb.arith.UInt64.mul32x32(this.hi, e)).hi = e.lo), (e.lo = 0), t.add(e); }), (jspb.arith.UInt64.prototype.div = function(e) { if (0 == e) return []; var t = new jspb.arith.UInt64(0, 0), r = new jspb.arith.UInt64(this.lo, this.hi); e = new jspb.arith.UInt64(e, 0); for (var o = new jspb.arith.UInt64(1, 0); !e.msb(); ) (e = e.leftShift()), (o = o.leftShift()); for (; !o.zero(); ) 0 >= e.cmp(r) && ((t = t.add(o)), (r = r.sub(e))), (e = e.rightShift()), (o = o.rightShift()); return [t, r]; }), (jspb.arith.UInt64.prototype.toString = function() { for (var e = '', t = this; !t.zero(); ) { var r = (t = t.div(10))[0]; (e = t[1].lo + e), (t = r); } return '' == e && (e = '0'), e; }), (jspb.arith.UInt64.fromString = function(e) { for ( var t = new jspb.arith.UInt64(0, 0), r = new jspb.arith.UInt64(0, 0), o = 0; o < e.length; o++ ) { if ('0' > e[o] || '9' < e[o]) return null; var i = parseInt(e[o], 10); (r.lo = i), (t = t.mul(10).add(r)); } return t; }), (jspb.arith.UInt64.prototype.clone = function() { return new jspb.arith.UInt64(this.lo, this.hi); }), (jspb.arith.Int64 = function(e, t) { (this.lo = e), (this.hi = t); }), (jspb.arith.Int64.prototype.add = function(e) { return new jspb.arith.Int64( (((this.lo + e.lo) & 4294967295) >>> 0) >>> 0, ((((this.hi + e.hi) & 4294967295) >>> 0) + (4294967296 <= this.lo + e.lo ? 1 : 0)) >>> 0 ); }), (jspb.arith.Int64.prototype.sub = function(e) { return new jspb.arith.Int64( (((this.lo - e.lo) & 4294967295) >>> 0) >>> 0, ((((this.hi - e.hi) & 4294967295) >>> 0) - (0 > this.lo - e.lo ? 1 : 0)) >>> 0 ); }), (jspb.arith.Int64.prototype.clone = function() { return new jspb.arith.Int64(this.lo, this.hi); }), (jspb.arith.Int64.prototype.toString = function() { var e = 0 != (2147483648 & this.hi), t = new jspb.arith.UInt64(this.lo, this.hi); return e && (t = new jspb.arith.UInt64(0, 0).sub(t)), (e ? '-' : '') + t.toString(); }), (jspb.arith.Int64.fromString = function(e) { var t = 0 < e.length && '-' == e[0]; return ( t && (e = e.substring(1)), null === (e = jspb.arith.UInt64.fromString(e)) ? null : (t && (e = new jspb.arith.UInt64(0, 0).sub(e)), new jspb.arith.Int64(e.lo, e.hi)) ); }), (jspb.BinaryWriter = function() { (this.blocks_ = []), (this.totalLength_ = 0), (this.encoder_ = new jspb.BinaryEncoder()), (this.bookmarks_ = []); }), (jspb.BinaryWriter.prototype.appendUint8Array_ = function(e) { var t = this.encoder_.end(); this.blocks_.push(t), this.blocks_.push(e), (this.totalLength_ += t.length + e.length); }), (jspb.BinaryWriter.prototype.beginDelimited_ = function(e) { return ( this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.DELIMITED), (e = this.encoder_.end()), this.blocks_.push(e), (this.totalLength_ += e.length), e.push(this.totalLength_), e ); }), (jspb.BinaryWriter.prototype.endDelimited_ = function(e) { var t = e.pop(); for ( t = this.totalLength_ + this.encoder_.length() - t, jspb.asserts.assert(0 <= t); 127 < t; ) e.push((127 & t) | 128), (t >>>= 7), this.totalLength_++; e.push(t), this.totalLength_++; }), (jspb.BinaryWriter.prototype.writeSerializedMessage = function(e, t, r) { this.appendUint8Array_(e.subarray(t, r)); }), (jspb.BinaryWriter.prototype.maybeWriteSerializedMessage = function(e, t, r) { null != e && null != t && null != r && this.writeSerializedMessage(e, t, r); }), (jspb.BinaryWriter.prototype.reset = function() { (this.blocks_ = []), this.encoder_.end(), (this.totalLength_ = 0), (this.bookmarks_ = []); }), (jspb.BinaryWriter.prototype.getResultBuffer = function() { jspb.asserts.assert(0 == this.bookmarks_.length); for ( var e = new Uint8Array(this.totalLength_ + this.encoder_.length()), t = this.blocks_, r = t.length, o = 0, i = 0; i < r; i++ ) { var a = t[i]; e.set(a, o), (o += a.length); } return ( (t = this.encoder_.end()), e.set(t, o), (o += t.length), jspb.asserts.assert(o == e.length), (this.blocks_ = [e]), e ); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'getResultBuffer', jspb.BinaryWriter.prototype.getResultBuffer ), (jspb.BinaryWriter.prototype.getResultBase64String = function(e) { return goog.crypt.base64.encodeByteArray(this.getResultBuffer(), e); }), (jspb.BinaryWriter.prototype.beginSubMessage = function(e) { this.bookmarks_.push(this.beginDelimited_(e)); }), (jspb.BinaryWriter.prototype.endSubMessage = function() { jspb.asserts.assert(0 <= this.bookmarks_.length), this.endDelimited_(this.bookmarks_.pop()); }), (jspb.BinaryWriter.prototype.writeFieldHeader_ = function(e, t) { jspb.asserts.assert(1 <= e && e == Math.floor(e)), this.encoder_.writeUnsignedVarint32(8 * e + t); }), (jspb.BinaryWriter.prototype.writeAny = function(e, t, r) { var o = jspb.BinaryConstants.FieldType; switch (e) { case o.DOUBLE: this.writeDouble(t, r); break; case o.FLOAT: this.writeFloat(t, r); break; case o.INT64: this.writeInt64(t, r); break; case o.UINT64: this.writeUint64(t, r); break; case o.INT32: this.writeInt32(t, r); break; case o.FIXED64: this.writeFixed64(t, r); break; case o.FIXED32: this.writeFixed32(t, r); break; case o.BOOL: this.writeBool(t, r); break; case o.STRING: this.writeString(t, r); break; case o.GROUP: jspb.asserts.fail('Group field type not supported in writeAny()'); break; case o.MESSAGE: jspb.asserts.fail('Message field type not supported in writeAny()'); break; case o.BYTES: this.writeBytes(t, r); break; case o.UINT32: this.writeUint32(t, r); break; case o.ENUM: this.writeEnum(t, r); break; case o.SFIXED32: this.writeSfixed32(t, r); break; case o.SFIXED64: this.writeSfixed64(t, r); break; case o.SINT32: this.writeSint32(t, r); break; case o.SINT64: this.writeSint64(t, r); break; case o.FHASH64: this.writeFixedHash64(t, r); break; case o.VHASH64: this.writeVarintHash64(t, r); break; default: jspb.asserts.fail('Invalid field type in writeAny()'); } }), (jspb.BinaryWriter.prototype.writeUnsignedVarint32_ = function(e, t) { null != t && (this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeUnsignedVarint32(t)); }), (jspb.BinaryWriter.prototype.writeSignedVarint32_ = function(e, t) { null != t && (this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeSignedVarint32(t)); }), (jspb.BinaryWriter.prototype.writeUnsignedVarint64_ = function(e, t) { null != t && (this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeUnsignedVarint64(t)); }), (jspb.BinaryWriter.prototype.writeSignedVarint64_ = function(e, t) { null != t && (this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeSignedVarint64(t)); }), (jspb.BinaryWriter.prototype.writeZigzagVarint32_ = function(e, t) { null != t && (this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeZigzagVarint32(t)); }), (jspb.BinaryWriter.prototype.writeZigzagVarint64_ = function(e, t) { null != t && (this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeZigzagVarint64(t)); }), (jspb.BinaryWriter.prototype.writeZigzagVarint64String_ = function(e, t) { null != t && (this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeZigzagVarint64String(t)); }), (jspb.BinaryWriter.prototype.writeZigzagVarintHash64_ = function(e, t) { null != t && (this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeZigzagVarintHash64(t)); }), (jspb.BinaryWriter.prototype.writeInt32 = function(e, t) { null != t && (jspb.asserts.assert( t >= -jspb.BinaryConstants.TWO_TO_31 && t < jspb.BinaryConstants.TWO_TO_31 ), this.writeSignedVarint32_(e, t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeInt32', jspb.BinaryWriter.prototype.writeInt32 ), (jspb.BinaryWriter.prototype.writeInt32String = function(e, t) { null != t && ((t = parseInt(t, 10)), jspb.asserts.assert( t >= -jspb.BinaryConstants.TWO_TO_31 && t < jspb.BinaryConstants.TWO_TO_31 ), this.writeSignedVarint32_(e, t)); }), (jspb.BinaryWriter.prototype.writeInt64 = function(e, t) { null != t && (jspb.asserts.assert( t >= -jspb.BinaryConstants.TWO_TO_63 && t < jspb.BinaryConstants.TWO_TO_63 ), this.writeSignedVarint64_(e, t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeInt64', jspb.BinaryWriter.prototype.writeInt64 ), (jspb.BinaryWriter.prototype.writeInt64String = function(e, t) { null != t && ((t = jspb.arith.Int64.fromString(t)), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeSplitVarint64(t.lo, t.hi)); }), (jspb.BinaryWriter.prototype.writeUint32 = function(e, t) { null != t && (jspb.asserts.assert(0 <= t && t < jspb.BinaryConstants.TWO_TO_32), this.writeUnsignedVarint32_(e, t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeUint32', jspb.BinaryWriter.prototype.writeUint32 ), (jspb.BinaryWriter.prototype.writeUint32String = function(e, t) { null != t && ((t = parseInt(t, 10)), jspb.asserts.assert(0 <= t && t < jspb.BinaryConstants.TWO_TO_32), this.writeUnsignedVarint32_(e, t)); }), (jspb.BinaryWriter.prototype.writeUint64 = function(e, t) { null != t && (jspb.asserts.assert(0 <= t && t < jspb.BinaryConstants.TWO_TO_64), this.writeUnsignedVarint64_(e, t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeUint64', jspb.BinaryWriter.prototype.writeUint64 ), (jspb.BinaryWriter.prototype.writeUint64String = function(e, t) { null != t && ((t = jspb.arith.UInt64.fromString(t)), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeSplitVarint64(t.lo, t.hi)); }), (jspb.BinaryWriter.prototype.writeSint32 = function(e, t) { null != t && (jspb.asserts.assert( t >= -jspb.BinaryConstants.TWO_TO_31 && t < jspb.BinaryConstants.TWO_TO_31 ), this.writeZigzagVarint32_(e, t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeSint32', jspb.BinaryWriter.prototype.writeSint32 ), (jspb.BinaryWriter.prototype.writeSint64 = function(e, t) { null != t && (jspb.asserts.assert( t >= -jspb.BinaryConstants.TWO_TO_63 && t < jspb.BinaryConstants.TWO_TO_63 ), this.writeZigzagVarint64_(e, t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeSint64', jspb.BinaryWriter.prototype.writeSint64 ), (jspb.BinaryWriter.prototype.writeSintHash64 = function(e, t) { null != t && this.writeZigzagVarintHash64_(e, t); }), (jspb.BinaryWriter.prototype.writeSint64String = function(e, t) { null != t && this.writeZigzagVarint64String_(e, t); }), (jspb.BinaryWriter.prototype.writeFixed32 = function(e, t) { null != t && (jspb.asserts.assert(0 <= t && t < jspb.BinaryConstants.TWO_TO_32), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.FIXED32), this.encoder_.writeUint32(t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeFixed32', jspb.BinaryWriter.prototype.writeFixed32 ), (jspb.BinaryWriter.prototype.writeFixed64 = function(e, t) { null != t && (jspb.asserts.assert(0 <= t && t < jspb.BinaryConstants.TWO_TO_64), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.FIXED64), this.encoder_.writeUint64(t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeFixed64', jspb.BinaryWriter.prototype.writeFixed64 ), (jspb.BinaryWriter.prototype.writeFixed64String = function(e, t) { null != t && ((t = jspb.arith.UInt64.fromString(t)), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.FIXED64), this.encoder_.writeSplitFixed64(t.lo, t.hi)); }), (jspb.BinaryWriter.prototype.writeSfixed32 = function(e, t) { null != t && (jspb.asserts.assert( t >= -jspb.BinaryConstants.TWO_TO_31 && t < jspb.BinaryConstants.TWO_TO_31 ), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.FIXED32), this.encoder_.writeInt32(t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeSfixed32', jspb.BinaryWriter.prototype.writeSfixed32 ), (jspb.BinaryWriter.prototype.writeSfixed64 = function(e, t) { null != t && (jspb.asserts.assert( t >= -jspb.BinaryConstants.TWO_TO_63 && t < jspb.BinaryConstants.TWO_TO_63 ), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.FIXED64), this.encoder_.writeInt64(t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeSfixed64', jspb.BinaryWriter.prototype.writeSfixed64 ), (jspb.BinaryWriter.prototype.writeSfixed64String = function(e, t) { null != t && ((t = jspb.arith.Int64.fromString(t)), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.FIXED64), this.encoder_.writeSplitFixed64(t.lo, t.hi)); }), (jspb.BinaryWriter.prototype.writeFloat = function(e, t) { null != t && (this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.FIXED32), this.encoder_.writeFloat(t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeFloat', jspb.BinaryWriter.prototype.writeFloat ), (jspb.BinaryWriter.prototype.writeDouble = function(e, t) { null != t && (this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.FIXED64), this.encoder_.writeDouble(t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeDouble', jspb.BinaryWriter.prototype.writeDouble ), (jspb.BinaryWriter.prototype.writeBool = function(e, t) { null != t && (jspb.asserts.assert('boolean' == typeof t || 'number' == typeof t), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeBool(t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeBool', jspb.BinaryWriter.prototype.writeBool ), (jspb.BinaryWriter.prototype.writeEnum = function(e, t) { null != t && (jspb.asserts.assert( t >= -jspb.BinaryConstants.TWO_TO_31 && t < jspb.BinaryConstants.TWO_TO_31 ), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeSignedVarint32(t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeEnum', jspb.BinaryWriter.prototype.writeEnum ), (jspb.BinaryWriter.prototype.writeString = function(e, t) { null != t && ((e = this.beginDelimited_(e)), this.encoder_.writeString(t), this.endDelimited_(e)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeString', jspb.BinaryWriter.prototype.writeString ), (jspb.BinaryWriter.prototype.writeBytes = function(e, t) { null != t && ((t = jspb.utils.byteSourceToUint8Array(t)), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.DELIMITED), this.encoder_.writeUnsignedVarint32(t.length), this.appendUint8Array_(t)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeBytes', jspb.BinaryWriter.prototype.writeBytes ), (jspb.BinaryWriter.prototype.writeMessage = function(e, t, r) { null != t && ((e = this.beginDelimited_(e)), r(t, this), this.endDelimited_(e)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeMessage', jspb.BinaryWriter.prototype.writeMessage ), (jspb.BinaryWriter.prototype.writeMessageSet = function(e, t, r) { null != t && (this.writeFieldHeader_(1, jspb.BinaryConstants.WireType.START_GROUP), this.writeFieldHeader_(2, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeSignedVarint32(e), (e = this.beginDelimited_(3)), r(t, this), this.endDelimited_(e), this.writeFieldHeader_(1, jspb.BinaryConstants.WireType.END_GROUP)); }), (jspb.BinaryWriter.prototype.writeGroup = function(e, t, r) { null != t && (this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.START_GROUP), r(t, this), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.END_GROUP)); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeGroup', jspb.BinaryWriter.prototype.writeGroup ), (jspb.BinaryWriter.prototype.writeFixedHash64 = function(e, t) { null != t && (jspb.asserts.assert(8 == t.length), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.FIXED64), this.encoder_.writeFixedHash64(t)); }), (jspb.BinaryWriter.prototype.writeVarintHash64 = function(e, t) { null != t && (jspb.asserts.assert(8 == t.length), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeVarintHash64(t)); }), (jspb.BinaryWriter.prototype.writeSplitFixed64 = function(e, t, r) { this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.FIXED64), this.encoder_.writeSplitFixed64(t, r); }), (jspb.BinaryWriter.prototype.writeSplitVarint64 = function(e, t, r) { this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT), this.encoder_.writeSplitVarint64(t, r); }), (jspb.BinaryWriter.prototype.writeSplitZigzagVarint64 = function(e, t, r) { this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.VARINT); var o = this.encoder_; jspb.utils.toZigzag64(t, r, function(e, t) { o.writeSplitVarint64(e >>> 0, t >>> 0); }); }), (jspb.BinaryWriter.prototype.writeRepeatedInt32 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeSignedVarint32_(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedInt32', jspb.BinaryWriter.prototype.writeRepeatedInt32 ), (jspb.BinaryWriter.prototype.writeRepeatedInt32String = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeInt32String(e, t[r]); }), (jspb.BinaryWriter.prototype.writeRepeatedInt64 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeSignedVarint64_(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedInt64', jspb.BinaryWriter.prototype.writeRepeatedInt64 ), (jspb.BinaryWriter.prototype.writeRepeatedSplitFixed64 = function(e, t, r, o) { if (null != t) for (var i = 0; i < t.length; i++) this.writeSplitFixed64(e, r(t[i]), o(t[i])); }), (jspb.BinaryWriter.prototype.writeRepeatedSplitVarint64 = function(e, t, r, o) { if (null != t) for (var i = 0; i < t.length; i++) this.writeSplitVarint64(e, r(t[i]), o(t[i])); }), (jspb.BinaryWriter.prototype.writeRepeatedSplitZigzagVarint64 = function(e, t, r, o) { if (null != t) for (var i = 0; i < t.length; i++) this.writeSplitZigzagVarint64(e, r(t[i]), o(t[i])); }), (jspb.BinaryWriter.prototype.writeRepeatedInt64String = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeInt64String(e, t[r]); }), (jspb.BinaryWriter.prototype.writeRepeatedUint32 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeUnsignedVarint32_(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedUint32', jspb.BinaryWriter.prototype.writeRepeatedUint32 ), (jspb.BinaryWriter.prototype.writeRepeatedUint32String = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeUint32String(e, t[r]); }), (jspb.BinaryWriter.prototype.writeRepeatedUint64 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeUnsignedVarint64_(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedUint64', jspb.BinaryWriter.prototype.writeRepeatedUint64 ), (jspb.BinaryWriter.prototype.writeRepeatedUint64String = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeUint64String(e, t[r]); }), (jspb.BinaryWriter.prototype.writeRepeatedSint32 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeZigzagVarint32_(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedSint32', jspb.BinaryWriter.prototype.writeRepeatedSint32 ), (jspb.BinaryWriter.prototype.writeRepeatedSint64 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeZigzagVarint64_(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedSint64', jspb.BinaryWriter.prototype.writeRepeatedSint64 ), (jspb.BinaryWriter.prototype.writeRepeatedSint64String = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeZigzagVarint64String_(e, t[r]); }), (jspb.BinaryWriter.prototype.writeRepeatedSintHash64 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeZigzagVarintHash64_(e, t[r]); }), (jspb.BinaryWriter.prototype.writeRepeatedFixed32 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeFixed32(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedFixed32', jspb.BinaryWriter.prototype.writeRepeatedFixed32 ), (jspb.BinaryWriter.prototype.writeRepeatedFixed64 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeFixed64(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedFixed64', jspb.BinaryWriter.prototype.writeRepeatedFixed64 ), (jspb.BinaryWriter.prototype.writeRepeatedFixed64String = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeFixed64String(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedFixed64String', jspb.BinaryWriter.prototype.writeRepeatedFixed64String ), (jspb.BinaryWriter.prototype.writeRepeatedSfixed32 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeSfixed32(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedSfixed32', jspb.BinaryWriter.prototype.writeRepeatedSfixed32 ), (jspb.BinaryWriter.prototype.writeRepeatedSfixed64 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeSfixed64(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedSfixed64', jspb.BinaryWriter.prototype.writeRepeatedSfixed64 ), (jspb.BinaryWriter.prototype.writeRepeatedSfixed64String = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeSfixed64String(e, t[r]); }), (jspb.BinaryWriter.prototype.writeRepeatedFloat = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeFloat(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedFloat', jspb.BinaryWriter.prototype.writeRepeatedFloat ), (jspb.BinaryWriter.prototype.writeRepeatedDouble = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeDouble(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedDouble', jspb.BinaryWriter.prototype.writeRepeatedDouble ), (jspb.BinaryWriter.prototype.writeRepeatedBool = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeBool(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedBool', jspb.BinaryWriter.prototype.writeRepeatedBool ), (jspb.BinaryWriter.prototype.writeRepeatedEnum = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeEnum(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedEnum', jspb.BinaryWriter.prototype.writeRepeatedEnum ), (jspb.BinaryWriter.prototype.writeRepeatedString = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeString(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedString', jspb.BinaryWriter.prototype.writeRepeatedString ), (jspb.BinaryWriter.prototype.writeRepeatedBytes = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeBytes(e, t[r]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedBytes', jspb.BinaryWriter.prototype.writeRepeatedBytes ), (jspb.BinaryWriter.prototype.writeRepeatedMessage = function(e, t, r) { if (null != t) for (var o = 0; o < t.length; o++) { var i = this.beginDelimited_(e); r(t[o], this), this.endDelimited_(i); } }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedMessage', jspb.BinaryWriter.prototype.writeRepeatedMessage ), (jspb.BinaryWriter.prototype.writeRepeatedGroup = function(e, t, r) { if (null != t) for (var o = 0; o < t.length; o++) this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.START_GROUP), r(t[o], this), this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.END_GROUP); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writeRepeatedGroup', jspb.BinaryWriter.prototype.writeRepeatedGroup ), (jspb.BinaryWriter.prototype.writeRepeatedFixedHash64 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeFixedHash64(e, t[r]); }), (jspb.BinaryWriter.prototype.writeRepeatedVarintHash64 = function(e, t) { if (null != t) for (var r = 0; r < t.length; r++) this.writeVarintHash64(e, t[r]); }), (jspb.BinaryWriter.prototype.writePackedInt32 = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) this.encoder_.writeSignedVarint32(t[r]); this.endDelimited_(e); } }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedInt32', jspb.BinaryWriter.prototype.writePackedInt32 ), (jspb.BinaryWriter.prototype.writePackedInt32String = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) this.encoder_.writeSignedVarint32(parseInt(t[r], 10)); this.endDelimited_(e); } }), (jspb.BinaryWriter.prototype.writePackedInt64 = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) this.encoder_.writeSignedVarint64(t[r]); this.endDelimited_(e); } }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedInt64', jspb.BinaryWriter.prototype.writePackedInt64 ), (jspb.BinaryWriter.prototype.writePackedSplitFixed64 = function(e, t, r, o) { if (null != t) { e = this.beginDelimited_(e); for (var i = 0; i < t.length; i++) this.encoder_.writeSplitFixed64(r(t[i]), o(t[i])); this.endDelimited_(e); } }), (jspb.BinaryWriter.prototype.writePackedSplitVarint64 = function(e, t, r, o) { if (null != t) { e = this.beginDelimited_(e); for (var i = 0; i < t.length; i++) this.encoder_.writeSplitVarint64(r(t[i]), o(t[i])); this.endDelimited_(e); } }), (jspb.BinaryWriter.prototype.writePackedSplitZigzagVarint64 = function(e, t, r, o) { if (null != t) { e = this.beginDelimited_(e); for (var i = this.encoder_, a = 0; a < t.length; a++) jspb.utils.toZigzag64(r(t[a]), o(t[a]), function(e, t) { i.writeSplitVarint64(e >>> 0, t >>> 0); }); this.endDelimited_(e); } }), (jspb.BinaryWriter.prototype.writePackedInt64String = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) { var o = jspb.arith.Int64.fromString(t[r]); this.encoder_.writeSplitVarint64(o.lo, o.hi); } this.endDelimited_(e); } }), (jspb.BinaryWriter.prototype.writePackedUint32 = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) this.encoder_.writeUnsignedVarint32(t[r]); this.endDelimited_(e); } }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedUint32', jspb.BinaryWriter.prototype.writePackedUint32 ), (jspb.BinaryWriter.prototype.writePackedUint32String = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) this.encoder_.writeUnsignedVarint32(parseInt(t[r], 10)); this.endDelimited_(e); } }), (jspb.BinaryWriter.prototype.writePackedUint64 = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) this.encoder_.writeUnsignedVarint64(t[r]); this.endDelimited_(e); } }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedUint64', jspb.BinaryWriter.prototype.writePackedUint64 ), (jspb.BinaryWriter.prototype.writePackedUint64String = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) { var o = jspb.arith.UInt64.fromString(t[r]); this.encoder_.writeSplitVarint64(o.lo, o.hi); } this.endDelimited_(e); } }), (jspb.BinaryWriter.prototype.writePackedSint32 = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) this.encoder_.writeZigzagVarint32(t[r]); this.endDelimited_(e); } }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedSint32', jspb.BinaryWriter.prototype.writePackedSint32 ), (jspb.BinaryWriter.prototype.writePackedSint64 = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) this.encoder_.writeZigzagVarint64(t[r]); this.endDelimited_(e); } }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedSint64', jspb.BinaryWriter.prototype.writePackedSint64 ), (jspb.BinaryWriter.prototype.writePackedSint64String = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) this.encoder_.writeZigzagVarintHash64(jspb.utils.decimalStringToHash64(t[r])); this.endDelimited_(e); } }), (jspb.BinaryWriter.prototype.writePackedSintHash64 = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) this.encoder_.writeZigzagVarintHash64(t[r]); this.endDelimited_(e); } }), (jspb.BinaryWriter.prototype.writePackedFixed32 = function(e, t) { if (null != t && t.length) for ( this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.DELIMITED), this.encoder_.writeUnsignedVarint32(4 * t.length), e = 0; e < t.length; e++ ) this.encoder_.writeUint32(t[e]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedFixed32', jspb.BinaryWriter.prototype.writePackedFixed32 ), (jspb.BinaryWriter.prototype.writePackedFixed64 = function(e, t) { if (null != t && t.length) for ( this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.DELIMITED), this.encoder_.writeUnsignedVarint32(8 * t.length), e = 0; e < t.length; e++ ) this.encoder_.writeUint64(t[e]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedFixed64', jspb.BinaryWriter.prototype.writePackedFixed64 ), (jspb.BinaryWriter.prototype.writePackedFixed64String = function(e, t) { if (null != t && t.length) for ( this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.DELIMITED), this.encoder_.writeUnsignedVarint32(8 * t.length), e = 0; e < t.length; e++ ) { var r = jspb.arith.UInt64.fromString(t[e]); this.encoder_.writeSplitFixed64(r.lo, r.hi); } }), (jspb.BinaryWriter.prototype.writePackedSfixed32 = function(e, t) { if (null != t && t.length) for ( this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.DELIMITED), this.encoder_.writeUnsignedVarint32(4 * t.length), e = 0; e < t.length; e++ ) this.encoder_.writeInt32(t[e]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedSfixed32', jspb.BinaryWriter.prototype.writePackedSfixed32 ), (jspb.BinaryWriter.prototype.writePackedSfixed64 = function(e, t) { if (null != t && t.length) for ( this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.DELIMITED), this.encoder_.writeUnsignedVarint32(8 * t.length), e = 0; e < t.length; e++ ) this.encoder_.writeInt64(t[e]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedSfixed64', jspb.BinaryWriter.prototype.writePackedSfixed64 ), (jspb.BinaryWriter.prototype.writePackedSfixed64String = function(e, t) { if (null != t && t.length) for ( this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.DELIMITED), this.encoder_.writeUnsignedVarint32(8 * t.length), e = 0; e < t.length; e++ ) this.encoder_.writeInt64String(t[e]); }), (jspb.BinaryWriter.prototype.writePackedFloat = function(e, t) { if (null != t && t.length) for ( this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.DELIMITED), this.encoder_.writeUnsignedVarint32(4 * t.length), e = 0; e < t.length; e++ ) this.encoder_.writeFloat(t[e]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedFloat', jspb.BinaryWriter.prototype.writePackedFloat ), (jspb.BinaryWriter.prototype.writePackedDouble = function(e, t) { if (null != t && t.length) for ( this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.DELIMITED), this.encoder_.writeUnsignedVarint32(8 * t.length), e = 0; e < t.length; e++ ) this.encoder_.writeDouble(t[e]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedDouble', jspb.BinaryWriter.prototype.writePackedDouble ), (jspb.BinaryWriter.prototype.writePackedBool = function(e, t) { if (null != t && t.length) for ( this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.DELIMITED), this.encoder_.writeUnsignedVarint32(t.length), e = 0; e < t.length; e++ ) this.encoder_.writeBool(t[e]); }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedBool', jspb.BinaryWriter.prototype.writePackedBool ), (jspb.BinaryWriter.prototype.writePackedEnum = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) this.encoder_.writeEnum(t[r]); this.endDelimited_(e); } }), goog.exportProperty( jspb.BinaryWriter.prototype, 'writePackedEnum', jspb.BinaryWriter.prototype.writePackedEnum ), (jspb.BinaryWriter.prototype.writePackedFixedHash64 = function(e, t) { if (null != t && t.length) for ( this.writeFieldHeader_(e, jspb.BinaryConstants.WireType.DELIMITED), this.encoder_.writeUnsignedVarint32(8 * t.length), e = 0; e < t.length; e++ ) this.encoder_.writeFixedHash64(t[e]); }), (jspb.BinaryWriter.prototype.writePackedVarintHash64 = function(e, t) { if (null != t && t.length) { e = this.beginDelimited_(e); for (var r = 0; r < t.length; r++) this.encoder_.writeVarintHash64(t[r]); this.endDelimited_(e); } }), (jspb.Map = function(e, t) { (this.arr_ = e), (this.valueCtor_ = t), (this.map_ = {}), (this.arrClean = !0), 0 < this.arr_.length && this.loadFromArray_(); }), goog.exportSymbol('jspb.Map', jspb.Map), (jspb.Map.prototype.loadFromArray_ = function() { for (var e = 0; e < this.arr_.length; e++) { var t = this.arr_[e], r = t[0]; this.map_[r.toString()] = new jspb.Map.Entry_(r, t[1]); } this.arrClean = !0; }), (jspb.Map.prototype.toArray = function() { if (this.arrClean) { if (this.valueCtor_) { var e, t = this.map_; for (e in t) if (Object.prototype.hasOwnProperty.call(t, e)) { var r = t[e].valueWrapper; r && r.toArray(); } } } else { for ( this.arr_.length = 0, (t = this.stringKeys_()).sort(), e = 0; e < t.length; e++ ) { var o = this.map_[t[e]]; (r = o.valueWrapper) && r.toArray(), this.arr_.push([o.key, o.value]); } this.arrClean = !0; } return this.arr_; }), goog.exportProperty(jspb.Map.prototype, 'toArray', jspb.Map.prototype.toArray), (jspb.Map.prototype.toObject = function(e, t) { for (var r = this.toArray(), o = [], i = 0; i < r.length; i++) { var a = this.map_[r[i][0].toString()]; this.wrapEntry_(a); var n = a.valueWrapper; n ? (jspb.asserts.assert(t), o.push([a.key, t(e, n)])) : o.push([a.key, a.value]); } return o; }), goog.exportProperty(jspb.Map.prototype, 'toObject', jspb.Map.prototype.toObject), (jspb.Map.fromObject = function(e, t, r) { t = new jspb.Map([], t); for (var o = 0; o < e.length; o++) { var i = e[o][0], a = r(e[o][1]); t.set(i, a); } return t; }), goog.exportProperty(jspb.Map, 'fromObject', jspb.Map.fromObject), (jspb.Map.ArrayIteratorIterable_ = function(e) { (this.idx_ = 0), (this.arr_ = e); }), (jspb.Map.ArrayIteratorIterable_.prototype.next = function() { return this.idx_ < this.arr_.length ? { done: !1, value: this.arr_[this.idx_++] } : { done: !0, value: void 0 }; }), 'undefined' != typeof Symbol && (jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] = function() { return this; }), (jspb.Map.prototype.getLength = function() { return this.stringKeys_().length; }), goog.exportProperty(jspb.Map.prototype, 'getLength', jspb.Map.prototype.getLength), (jspb.Map.prototype.clear = function() { (this.map_ = {}), (this.arrClean = !1); }), goog.exportProperty(jspb.Map.prototype, 'clear', jspb.Map.prototype.clear), (jspb.Map.prototype.del = function(e) { e = e.toString(); var t = this.map_.hasOwnProperty(e); return delete this.map_[e], (this.arrClean = !1), t; }), goog.exportProperty(jspb.Map.prototype, 'del', jspb.Map.prototype.del), (jspb.Map.prototype.getEntryList = function() { var e = [], t = this.stringKeys_(); t.sort(); for (var r = 0; r < t.length; r++) { var o = this.map_[t[r]]; e.push([o.key, o.value]); } return e; }), goog.exportProperty(jspb.Map.prototype, 'getEntryList', jspb.Map.prototype.getEntryList), (jspb.Map.prototype.entries = function() { var e = [], t = this.stringKeys_(); t.sort(); for (var r = 0; r < t.length; r++) { var o = this.map_[t[r]]; e.push([o.key, this.wrapEntry_(o)]); } return new jspb.Map.ArrayIteratorIterable_(e); }), goog.exportProperty(jspb.Map.prototype, 'entries', jspb.Map.prototype.entries), (jspb.Map.prototype.keys = function() { var e = [], t = this.stringKeys_(); t.sort(); for (var r = 0; r < t.length; r++) e.push(this.map_[t[r]].key); return new jspb.Map.ArrayIteratorIterable_(e); }), goog.exportProperty(jspb.Map.prototype, 'keys', jspb.Map.prototype.keys), (jspb.Map.prototype.values = function() { var e = [], t = this.stringKeys_(); t.sort(); for (var r = 0; r < t.length; r++) e.push(this.wrapEntry_(this.map_[t[r]])); return new jspb.Map.ArrayIteratorIterable_(e); }), goog.exportProperty(jspb.Map.prototype, 'values', jspb.Map.prototype.values), (jspb.Map.prototype.forEach = function(e, t) { var r = this.stringKeys_(); r.sort(); for (var o = 0; o < r.length; o++) { var i = this.map_[r[o]]; e.call(t, this.wrapEntry_(i), i.key, this); } }), goog.exportProperty(jspb.Map.prototype, 'forEach', jspb.Map.prototype.forEach), (jspb.Map.prototype.set = function(e, t) { var r = new jspb.Map.Entry_(e); return ( this.valueCtor_ ? ((r.valueWrapper = t), (r.value = t.toArray())) : (r.value = t), (this.map_[e.toString()] = r), (this.arrClean = !1), this ); }), goog.exportProperty(jspb.Map.prototype, 'set', jspb.Map.prototype.set), (jspb.Map.prototype.wrapEntry_ = function(e) { return this.valueCtor_ ? (e.valueWrapper || (e.valueWrapper = new this.valueCtor_(e.value)), e.valueWrapper) : e.value; }), (jspb.Map.prototype.get = function(e) { if ((e = this.map_[e.toString()])) return this.wrapEntry_(e); }), goog.exportProperty(jspb.Map.prototype, 'get', jspb.Map.prototype.get), (jspb.Map.prototype.has = function(e) { return e.toString() in this.map_; }), goog.exportProperty(jspb.Map.prototype, 'has', jspb.Map.prototype.has), (jspb.Map.prototype.serializeBinary = function(e, t, r, o, i) { var a = this.stringKeys_(); a.sort(); for (var n = 0; n < a.length; n++) { var s = this.map_[a[n]]; t.beginSubMessage(e), r.call(t, 1, s.key), this.valueCtor_ ? o.call(t, 2, this.wrapEntry_(s), i) : o.call(t, 2, s.value), t.endSubMessage(); } }), goog.exportProperty( jspb.Map.prototype, 'serializeBinary', jspb.Map.prototype.serializeBinary ), (jspb.Map.deserializeBinary = function(e, t, r, o, i, a, n) { for (; t.nextField() && !t.isEndGroup(); ) { var s = t.getFieldNumber(); 1 == s ? (a = r.call(t)) : 2 == s && (e.valueCtor_ ? (jspb.asserts.assert(i), n || (n = new e.valueCtor_()), o.call(t, n, i)) : (n = o.call(t))); } jspb.asserts.assert(null != a), jspb.asserts.assert(null != n), e.set(a, n); }), goog.exportProperty(jspb.Map, 'deserializeBinary', jspb.Map.deserializeBinary), (jspb.Map.prototype.stringKeys_ = function() { var e, t = this.map_, r = []; for (e in t) Object.prototype.hasOwnProperty.call(t, e) && r.push(e); return r; }), (jspb.Map.Entry_ = function(e, t) { (this.key = e), (this.value = t), (this.valueWrapper = void 0); }), (jspb.ExtensionFieldInfo = function(e, t, r, o, i) { (this.fieldIndex = e), (this.fieldName = t), (this.ctor = r), (this.toObjectFn = o), (this.isRepeated = i); }), goog.exportSymbol('jspb.ExtensionFieldInfo', jspb.ExtensionFieldInfo), (jspb.ExtensionFieldBinaryInfo = function(e, t, r, o, i, a) { (this.fieldInfo = e), (this.binaryReaderFn = t), (this.binaryWriterFn = r), (this.binaryMessageSerializeFn = o), (this.binaryMessageDeserializeFn = i), (this.isPacked = a); }), goog.exportSymbol('jspb.ExtensionFieldBinaryInfo', jspb.ExtensionFieldBinaryInfo), (jspb.ExtensionFieldInfo.prototype.isMessageType = function() { return !!this.ctor; }), goog.exportProperty( jspb.ExtensionFieldInfo.prototype, 'isMessageType', jspb.ExtensionFieldInfo.prototype.isMessageType ), (jspb.Message = function() {}), goog.exportSymbol('jspb.Message', jspb.Message), (jspb.Message.GENERATE_TO_OBJECT = !0), goog.exportProperty(jspb.Message, 'GENERATE_TO_OBJECT', jspb.Message.GENERATE_TO_OBJECT), (jspb.Message.GENERATE_FROM_OBJECT = !goog.DISALLOW_TEST_ONLY_CODE), goog.exportProperty( jspb.Message, 'GENERATE_FROM_OBJECT', jspb.Message.GENERATE_FROM_OBJECT ), (jspb.Message.GENERATE_TO_STRING = !0), (jspb.Message.ASSUME_LOCAL_ARRAYS = !1), (jspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS = !0), (jspb.Message.SUPPORTS_UINT8ARRAY_ = 'function' == typeof Uint8Array), (jspb.Message.prototype.getJsPbMessageId = function() { return this.messageId_; }), goog.exportProperty( jspb.Message.prototype, 'getJsPbMessageId', jspb.Message.prototype.getJsPbMessageId ), (jspb.Message.getIndex_ = function(e, t) { return t + e.arrayIndexOffset_; }), (jspb.Message.hiddenES6Property_ = function() {}), (jspb.Message.getFieldNumber_ = function(e, t) { return t - e.arrayIndexOffset_; }), (jspb.Message.initialize = function(e, t, r, o, i, a) { if ( ((e.wrappers_ = null), t || (t = r ? [r] : []), (e.messageId_ = r ? String(r) : void 0), (e.arrayIndexOffset_ = 0 === r ? -1 : 0), (e.array = t), jspb.Message.initPivotAndExtensionObject_(e, o), (e.convertedPrimitiveFields_ = {}), jspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS || (e.repeatedFields = i), i) ) for (t = 0; t < i.length; t++) (r = i[t]) < e.pivot_ ? ((r = jspb.Message.getIndex_(e, r)), (e.array[r] = e.array[r] || jspb.Message.EMPTY_LIST_SENTINEL_)) : (jspb.Message.maybeInitEmptyExtensionObject_(e), (e.extensionObject_[r] = e.extensionObject_[r] || jspb.Message.EMPTY_LIST_SENTINEL_)); if (a && a.length) for (t = 0; t < a.length; t++) jspb.Message.computeOneofCase(e, a[t]); }), goog.exportProperty(jspb.Message, 'initialize', jspb.Message.initialize), (jspb.Message.EMPTY_LIST_SENTINEL_ = goog.DEBUG && Object.freeze ? Object.freeze([]) : []), (jspb.Message.isArray_ = function(e) { return jspb.Message.ASSUME_LOCAL_ARRAYS ? e instanceof Array : Array.isArray(e); }), (jspb.Message.isExtensionObject_ = function(e) { return !( null === e || 'object' != typeof e || jspb.Message.isArray_(e) || (jspb.Message.SUPPORTS_UINT8ARRAY_ && e instanceof Uint8Array) ); }), (jspb.Message.initPivotAndExtensionObject_ = function(e, t) { var r = e.array.length, o = -1; if (r && ((o = r - 1), (r = e.array[o]), jspb.Message.isExtensionObject_(r))) return ( (e.pivot_ = jspb.Message.getFieldNumber_(e, o)), void (e.extensionObject_ = r) ); -1 < t ? ((e.pivot_ = Math.max(t, jspb.Message.getFieldNumber_(e, o + 1))), (e.extensionObject_ = null)) : (e.pivot_ = Number.MAX_VALUE); }), (jspb.Message.maybeInitEmptyExtensionObject_ = function(e) { var t = jspb.Message.getIndex_(e, e.pivot_); e.array[t] || (e.extensionObject_ = e.array[t] = {}); }), (jspb.Message.toObjectList = function(e, t, r) { for (var o = [], i = 0; i < e.length; i++) o[i] = t.call(e[i], r, e[i]); return o; }), goog.exportProperty(jspb.Message, 'toObjectList', jspb.Message.toObjectList), (jspb.Message.toObjectExtension = function(e, t, r, o, i) { for (var a in r) { var n = r[a], s = o.call(e, n); if (null != s) { for (var p in n.fieldName) if (n.fieldName.hasOwnProperty(p)) break; t[p] = n.toObjectFn ? n.isRepeated ? jspb.Message.toObjectList(s, n.toObjectFn, i) : n.toObjectFn(i, s) : s; } } }), goog.exportProperty(jspb.Message, 'toObjectExtension', jspb.Message.toObjectExtension), (jspb.Message.serializeBinaryExtensions = function(e, t, r, o) { for (var i in r) { var a = r[i], n = a.fieldInfo; if (!a.binaryWriterFn) throw Error( 'Message extension present that was generated without binary serialization support' ); var s = o.call(e, n); if (null != s) if (n.isMessageType()) { if (!a.binaryMessageSerializeFn) throw Error( 'Message extension present holding submessage without binary support enabled, and message is being serialized to binary format' ); a.binaryWriterFn.call(t, n.fieldIndex, s, a.binaryMessageSerializeFn); } else a.binaryWriterFn.call(t, n.fieldIndex, s); } }), goog.exportProperty( jspb.Message, 'serializeBinaryExtensions', jspb.Message.serializeBinaryExtensions ), (jspb.Message.readBinaryExtension = function(e, t, r, o, i) { var a = r[t.getFieldNumber()]; if (a) { if (((r = a.fieldInfo), !a.binaryReaderFn)) throw Error( 'Deserializing extension whose generated code does not support binary format' ); if (r.isMessageType()) { var n = new r.ctor(); a.binaryReaderFn.call(t, n, a.binaryMessageDeserializeFn); } else n = a.binaryReaderFn.call(t); r.isRepeated && !a.isPacked ? (t = o.call(e, r)) ? t.push(n) : i.call(e, r, [n]) : i.call(e, r, n); } else t.skipField(); }), goog.exportProperty(jspb.Message, 'readBinaryExtension', jspb.Message.readBinaryExtension), (jspb.Message.getField = function(e, t) { if (t < e.pivot_) { t = jspb.Message.getIndex_(e, t); var r = e.array[t]; return r === jspb.Message.EMPTY_LIST_SENTINEL_ ? (e.array[t] = []) : r; } if (e.extensionObject_) return (r = e.extensionObject_[t]) === jspb.Message.EMPTY_LIST_SENTINEL_ ? (e.extensionObject_[t] = []) : r; }), goog.exportProperty(jspb.Message, 'getField', jspb.Message.getField), (jspb.Message.getRepeatedField = function(e, t) { return jspb.Message.getField(e, t); }), goog.exportProperty(jspb.Message, 'getRepeatedField', jspb.Message.getRepeatedField), (jspb.Message.getOptionalFloatingPointField = function(e, t) { return null == (e = jspb.Message.getField(e, t)) ? e : +e; }), goog.exportProperty( jspb.Message, 'getOptionalFloatingPointField', jspb.Message.getOptionalFloatingPointField ), (jspb.Message.getBooleanField = function(e, t) { return null == (e = jspb.Message.getField(e, t)) ? e : !!e; }), goog.exportProperty(jspb.Message, 'getBooleanField', jspb.Message.getBooleanField), (jspb.Message.getRepeatedFloatingPointField = function(e, t) { var r = jspb.Message.getRepeatedField(e, t); if ( (e.convertedPrimitiveFields_ || (e.convertedPrimitiveFields_ = {}), !e.convertedPrimitiveFields_[t]) ) { for (var o = 0; o < r.length; o++) r[o] = +r[o]; e.convertedPrimitiveFields_[t] = !0; } return r; }), goog.exportProperty( jspb.Message, 'getRepeatedFloatingPointField', jspb.Message.getRepeatedFloatingPointField ), (jspb.Message.getRepeatedBooleanField = function(e, t) { var r = jspb.Message.getRepeatedField(e, t); if ( (e.convertedPrimitiveFields_ || (e.convertedPrimitiveFields_ = {}), !e.convertedPrimitiveFields_[t]) ) { for (var o = 0; o < r.length; o++) r[o] = !!r[o]; e.convertedPrimitiveFields_[t] = !0; } return r; }), goog.exportProperty( jspb.Message, 'getRepeatedBooleanField', jspb.Message.getRepeatedBooleanField ), (jspb.Message.bytesAsB64 = function(e) { return null == e || 'string' == typeof e ? e : jspb.Message.SUPPORTS_UINT8ARRAY_ && e instanceof Uint8Array ? goog.crypt.base64.encodeByteArray(e) : (jspb.asserts.fail('Cannot coerce to b64 string: ' + goog.typeOf(e)), null); }), goog.exportProperty(jspb.Message, 'bytesAsB64', jspb.Message.bytesAsB64), (jspb.Message.bytesAsU8 = function(e) { return null == e || e instanceof Uint8Array ? e : 'string' == typeof e ? goog.crypt.base64.decodeStringToUint8Array(e) : (jspb.asserts.fail('Cannot coerce to Uint8Array: ' + goog.typeOf(e)), null); }), goog.exportProperty(jspb.Message, 'bytesAsU8', jspb.Message.bytesAsU8), (jspb.Message.bytesListAsB64 = function(e) { return ( jspb.Message.assertConsistentTypes_(e), e.length && 'string' != typeof e[0] ? goog.array.map(e, jspb.Message.bytesAsB64) : e ); }), goog.exportProperty(jspb.Message, 'bytesListAsB64', jspb.Message.bytesListAsB64), (jspb.Message.bytesListAsU8 = function(e) { return ( jspb.Message.assertConsistentTypes_(e), !e.length || e[0] instanceof Uint8Array ? e : goog.array.map(e, jspb.Message.bytesAsU8) ); }), goog.exportProperty(jspb.Message, 'bytesListAsU8', jspb.Message.bytesListAsU8), (jspb.Message.assertConsistentTypes_ = function(e) { if (goog.DEBUG && e && 1 < e.length) { var t = goog.typeOf(e[0]); goog.array.forEach(e, function(e) { goog.typeOf(e) != t && jspb.asserts.fail( 'Inconsistent type in JSPB repeated field array. Got ' + goog.typeOf(e) + ' expected ' + t ); }); } }), (jspb.Message.getFieldWithDefault = function(e, t, r) { return null == (e = jspb.Message.getField(e, t)) ? r : e; }), goog.exportProperty(jspb.Message, 'getFieldWithDefault', jspb.Message.getFieldWithDefault), (jspb.Message.getBooleanFieldWithDefault = function(e, t, r) { return null == (e = jspb.Message.getBooleanField(e, t)) ? r : e; }), goog.exportProperty( jspb.Message, 'getBooleanFieldWithDefault', jspb.Message.getBooleanFieldWithDefault ), (jspb.Message.getFloatingPointFieldWithDefault = function(e, t, r) { return null == (e = jspb.Message.getOptionalFloatingPointField(e, t)) ? r : e; }), goog.exportProperty( jspb.Message, 'getFloatingPointFieldWithDefault', jspb.Message.getFloatingPointFieldWithDefault ), (jspb.Message.getFieldProto3 = jspb.Message.getFieldWithDefault), goog.exportProperty(jspb.Message, 'getFieldProto3', jspb.Message.getFieldProto3), (jspb.Message.getMapField = function(e, t, r, o) { if ((e.wrappers_ || (e.wrappers_ = {}), t in e.wrappers_)) return e.wrappers_[t]; var i = jspb.Message.getField(e, t); if (!i) { if (r) return; (i = []), jspb.Message.setField(e, t, i); } return (e.wrappers_[t] = new jspb.Map(i, o)); }), goog.exportProperty(jspb.Message, 'getMapField', jspb.Message.getMapField), (jspb.Message.setField = function(e, t, r) { return ( jspb.asserts.assertInstanceof(e, jspb.Message), t < e.pivot_ ? (e.array[jspb.Message.getIndex_(e, t)] = r) : (jspb.Message.maybeInitEmptyExtensionObject_(e), (e.extensionObject_[t] = r)), e ); }), goog.exportProperty(jspb.Message, 'setField', jspb.Message.setField), (jspb.Message.setProto3IntField = function(e, t, r) { return jspb.Message.setFieldIgnoringDefault_(e, t, r, 0); }), goog.exportProperty(jspb.Message, 'setProto3IntField', jspb.Message.setProto3IntField), (jspb.Message.setProto3FloatField = function(e, t, r) { return jspb.Message.setFieldIgnoringDefault_(e, t, r, 0); }), goog.exportProperty(jspb.Message, 'setProto3FloatField', jspb.Message.setProto3FloatField), (jspb.Message.setProto3BooleanField = function(e, t, r) { return jspb.Message.setFieldIgnoringDefault_(e, t, r, !1); }), goog.exportProperty( jspb.Message, 'setProto3BooleanField', jspb.Message.setProto3BooleanField ), (jspb.Message.setProto3StringField = function(e, t, r) { return jspb.Message.setFieldIgnoringDefault_(e, t, r, ''); }), goog.exportProperty( jspb.Message, 'setProto3StringField', jspb.Message.setProto3StringField ), (jspb.Message.setProto3BytesField = function(e, t, r) { return jspb.Message.setFieldIgnoringDefault_(e, t, r, ''); }), goog.exportProperty(jspb.Message, 'setProto3BytesField', jspb.Message.setProto3BytesField), (jspb.Message.setProto3EnumField = function(e, t, r) { return jspb.Message.setFieldIgnoringDefault_(e, t, r, 0); }), goog.exportProperty(jspb.Message, 'setProto3EnumField', jspb.Message.setProto3EnumField), (jspb.Message.setProto3StringIntField = function(e, t, r) { return jspb.Message.setFieldIgnoringDefault_(e, t, r, '0'); }), goog.exportProperty( jspb.Message, 'setProto3StringIntField', jspb.Message.setProto3StringIntField ), (jspb.Message.setFieldIgnoringDefault_ = function(e, t, r, o) { return ( jspb.asserts.assertInstanceof(e, jspb.Message), r !== o ? jspb.Message.setField(e, t, r) : t < e.pivot_ ? (e.array[jspb.Message.getIndex_(e, t)] = null) : (jspb.Message.maybeInitEmptyExtensionObject_(e), delete e.extensionObject_[t]), e ); }), (jspb.Message.addToRepeatedField = function(e, t, r, o) { return ( jspb.asserts.assertInstanceof(e, jspb.Message), (t = jspb.Message.getRepeatedField(e, t)), null != o ? t.splice(o, 0, r) : t.push(r), e ); }), goog.exportProperty(jspb.Message, 'addToRepeatedField', jspb.Message.addToRepeatedField), (jspb.Message.setOneofField = function(e, t, r, o) { return ( jspb.asserts.assertInstanceof(e, jspb.Message), (r = jspb.Message.computeOneofCase(e, r)) && r !== t && void 0 !== o && (e.wrappers_ && r in e.wrappers_ && (e.wrappers_[r] = void 0), jspb.Message.setField(e, r, void 0)), jspb.Message.setField(e, t, o) ); }), goog.exportProperty(jspb.Message, 'setOneofField', jspb.Message.setOneofField), (jspb.Message.computeOneofCase = function(e, t) { for (var r, o, i = 0; i < t.length; i++) { var a = t[i], n = jspb.Message.getField(e, a); null != n && ((r = a), (o = n), jspb.Message.setField(e, a, void 0)); } return r ? (jspb.Message.setField(e, r, o), r) : 0; }), goog.exportProperty(jspb.Message, 'computeOneofCase', jspb.Message.computeOneofCase), (jspb.Message.getWrapperField = function(e, t, r, o) { if ((e.wrappers_ || (e.wrappers_ = {}), !e.wrappers_[r])) { var i = jspb.Message.getField(e, r); (o || i) && (e.wrappers_[r] = new t(i)); } return e.wrappers_[r]; }), goog.exportProperty(jspb.Message, 'getWrapperField', jspb.Message.getWrapperField), (jspb.Message.getRepeatedWrapperField = function(e, t, r) { return ( jspb.Message.wrapRepeatedField_(e, t, r), (t = e.wrappers_[r]) == jspb.Message.EMPTY_LIST_SENTINEL_ && (t = e.wrappers_[r] = []), t ); }), goog.exportProperty( jspb.Message, 'getRepeatedWrapperField', jspb.Message.getRepeatedWrapperField ), (jspb.Message.wrapRepeatedField_ = function(e, t, r) { if ((e.wrappers_ || (e.wrappers_ = {}), !e.wrappers_[r])) { for (var o = jspb.Message.getRepeatedField(e, r), i = [], a = 0; a < o.length; a++) i[a] = new t(o[a]); e.wrappers_[r] = i; } }), (jspb.Message.setWrapperField = function(e, t, r) { jspb.asserts.assertInstanceof(e, jspb.Message), e.wrappers_ || (e.wrappers_ = {}); var o = r ? r.toArray() : r; return (e.wrappers_[t] = r), jspb.Message.setField(e, t, o); }), goog.exportProperty(jspb.Message, 'setWrapperField', jspb.Message.setWrapperField), (jspb.Message.setOneofWrapperField = function(e, t, r, o) { jspb.asserts.assertInstanceof(e, jspb.Message), e.wrappers_ || (e.wrappers_ = {}); var i = o ? o.toArray() : o; return (e.wrappers_[t] = o), jspb.Message.setOneofField(e, t, r, i); }), goog.exportProperty( jspb.Message, 'setOneofWrapperField', jspb.Message.setOneofWrapperField ), (jspb.Message.setRepeatedWrapperField = function(e, t, r) { jspb.asserts.assertInstanceof(e, jspb.Message), e.wrappers_ || (e.wrappers_ = {}), (r = r || []); for (var o = [], i = 0; i < r.length; i++) o[i] = r[i].toArray(); return (e.wrappers_[t] = r), jspb.Message.setField(e, t, o); }), goog.exportProperty( jspb.Message, 'setRepeatedWrapperField', jspb.Message.setRepeatedWrapperField ), (jspb.Message.addToRepeatedWrapperField = function(e, t, r, o, i) { jspb.Message.wrapRepeatedField_(e, o, t); var a = e.wrappers_[t]; return ( a || (a = e.wrappers_[t] = []), (r = r || new o()), (e = jspb.Message.getRepeatedField(e, t)), null != i ? (a.splice(i, 0, r), e.splice(i, 0, r.toArray())) : (a.push(r), e.push(r.toArray())), r ); }), goog.exportProperty( jspb.Message, 'addToRepeatedWrapperField', jspb.Message.addToRepeatedWrapperField ), (jspb.Message.toMap = function(e, t, r, o) { for (var i = {}, a = 0; a < e.length; a++) i[t.call(e[a])] = r ? r.call(e[a], o, e[a]) : e[a]; return i; }), goog.exportProperty(jspb.Message, 'toMap', jspb.Message.toMap), (jspb.Message.prototype.syncMapFields_ = function() { if (this.wrappers_) for (var e in this.wrappers_) { var t = this.wrappers_[e]; if (Array.isArray(t)) for (var r = 0; r < t.length; r++) t[r] && t[r].toArray(); else t && t.toArray(); } }), (jspb.Message.prototype.toArray = function() { return this.syncMapFields_(), this.array; }), goog.exportProperty(jspb.Message.prototype, 'toArray', jspb.Message.prototype.toArray), jspb.Message.GENERATE_TO_STRING && (jspb.Message.prototype.toString = function() { return this.syncMapFields_(), this.array.toString(); }), (jspb.Message.prototype.getExtension = function(e) { if (this.extensionObject_) { this.wrappers_ || (this.wrappers_ = {}); var t = e.fieldIndex; if (e.isRepeated) { if (e.isMessageType()) return ( this.wrappers_[t] || (this.wrappers_[t] = goog.array.map( this.extensionObject_[t] || [], function(t) { return new e.ctor(t); } )), this.wrappers_[t] ); } else if (e.isMessageType()) return ( !this.wrappers_[t] && this.extensionObject_[t] && (this.wrappers_[t] = new e.ctor(this.extensionObject_[t])), this.wrappers_[t] ); return this.extensionObject_[t]; } }), goog.exportProperty( jspb.Message.prototype, 'getExtension', jspb.Message.prototype.getExtension ), (jspb.Message.prototype.setExtension = function(e, t) { this.wrappers_ || (this.wrappers_ = {}), jspb.Message.maybeInitEmptyExtensionObject_(this); var r = e.fieldIndex; return ( e.isRepeated ? ((t = t || []), e.isMessageType() ? ((this.wrappers_[r] = t), (this.extensionObject_[r] = goog.array.map(t, function(e) { return e.toArray(); }))) : (this.extensionObject_[r] = t)) : e.isMessageType() ? ((this.wrappers_[r] = t), (this.extensionObject_[r] = t ? t.toArray() : t)) : (this.extensionObject_[r] = t), this ); }), goog.exportProperty( jspb.Message.prototype, 'setExtension', jspb.Message.prototype.setExtension ), (jspb.Message.difference = function(e, t) { if (!(e instanceof t.constructor)) throw Error('Messages have different types.'); var r = e.toArray(); t = t.toArray(); var o = [], i = 0, a = r.length > t.length ? r.length : t.length; for (e.getJsPbMessageId() && ((o[0] = e.getJsPbMessageId()), (i = 1)); i < a; i++) jspb.Message.compareFields(r[i], t[i]) || (o[i] = t[i]); return new e.constructor(o); }), goog.exportProperty(jspb.Message, 'difference', jspb.Message.difference), (jspb.Message.equals = function(e, t) { return ( e == t || (!(!e || !t) && e instanceof t.constructor && jspb.Message.compareFields(e.toArray(), t.toArray())) ); }), goog.exportProperty(jspb.Message, 'equals', jspb.Message.equals), (jspb.Message.compareExtensions = function(e, t) { (e = e || {}), (t = t || {}); var r, o = {}; for (r in e) o[r] = 0; for (r in t) o[r] = 0; for (r in o) if (!jspb.Message.compareFields(e[r], t[r])) return !1; return !0; }), goog.exportProperty(jspb.Message, 'compareExtensions', jspb.Message.compareExtensions), (jspb.Message.compareFields = function(e, t) { if (e == t) return !0; if (!goog.isObject(e) || !goog.isObject(t)) return ( !!(('number' == typeof e && isNaN(e)) || ('number' == typeof t && isNaN(t))) && String(e) == String(t) ); if (e.constructor != t.constructor) return !1; if (jspb.Message.SUPPORTS_UINT8ARRAY_ && e.constructor === Uint8Array) { if (e.length != t.length) return !1; for (var r = 0; r < e.length; r++) if (e[r] != t[r]) return !1; return !0; } if (e.constructor === Array) { var o = void 0, i = void 0, a = Math.max(e.length, t.length); for (r = 0; r < a; r++) { var n = e[r], s = t[r]; if ( (n && n.constructor == Object && (jspb.asserts.assert(void 0 === o), jspb.asserts.assert(r === e.length - 1), (o = n), (n = void 0)), s && s.constructor == Object && (jspb.asserts.assert(void 0 === i), jspb.asserts.assert(r === t.length - 1), (i = s), (s = void 0)), !jspb.Message.compareFields(n, s)) ) return !1; } return ( (!o && !i) || ((o = o || {}), (i = i || {}), jspb.Message.compareExtensions(o, i)) ); } if (e.constructor === Object) return jspb.Message.compareExtensions(e, t); throw Error('Invalid type in JSPB array'); }), goog.exportProperty(jspb.Message, 'compareFields', jspb.Message.compareFields), (jspb.Message.prototype.cloneMessage = function() { return jspb.Message.cloneMessage(this); }), goog.exportProperty( jspb.Message.prototype, 'cloneMessage', jspb.Message.prototype.cloneMessage ), (jspb.Message.prototype.clone = function() { return jspb.Message.cloneMessage(this); }), goog.exportProperty(jspb.Message.prototype, 'clone', jspb.Message.prototype.clone), (jspb.Message.clone = function(e) { return jspb.Message.cloneMessage(e); }), goog.exportProperty(jspb.Message, 'clone', jspb.Message.clone), (jspb.Message.cloneMessage = function(e) { return new e.constructor(jspb.Message.clone_(e.toArray())); }), (jspb.Message.copyInto = function(e, t) { jspb.asserts.assertInstanceof(e, jspb.Message), jspb.asserts.assertInstanceof(t, jspb.Message), jspb.asserts.assert( e.constructor == t.constructor, 'Copy source and target message should have the same type.' ), (e = jspb.Message.clone(e)); for (var r = t.toArray(), o = e.toArray(), i = (r.length = 0); i < o.length; i++) r[i] = o[i]; (t.wrappers_ = e.wrappers_), (t.extensionObject_ = e.extensionObject_); }), goog.exportProperty(jspb.Message, 'copyInto', jspb.Message.copyInto), (jspb.Message.clone_ = function(e) { if (Array.isArray(e)) { for (var t = Array(e.length), r = 0; r < e.length; r++) { var o = e[r]; null != o && (t[r] = 'object' == typeof o ? jspb.Message.clone_(jspb.asserts.assert(o)) : o); } return t; } if (jspb.Message.SUPPORTS_UINT8ARRAY_ && e instanceof Uint8Array) return new Uint8Array(e); for (r in ((t = {}), e)) null != (o = e[r]) && (t[r] = 'object' == typeof o ? jspb.Message.clone_(jspb.asserts.assert(o)) : o); return t; }), (jspb.Message.registerMessageType = function(e, t) { t.messageId = e; }), goog.exportProperty(jspb.Message, 'registerMessageType', jspb.Message.registerMessageType), (jspb.Message.messageSetExtensions = {}), (jspb.Message.messageSetExtensionsBinary = {}), (jspb.Export = {}), (exports.Map = jspb.Map), (exports.Message = jspb.Message), (exports.BinaryReader = jspb.BinaryReader), (exports.BinaryWriter = jspb.BinaryWriter), (exports.ExtensionFieldInfo = jspb.ExtensionFieldInfo), (exports.ExtensionFieldBinaryInfo = jspb.ExtensionFieldBinaryInfo), (exports.exportSymbol = goog.exportSymbol), (exports.inherits = goog.inherits), (exports.object = { extend: goog.object.extend }), (exports.typeOf = goog.typeOf); })(googleProtobuf); var calculator_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.CalculatorOptions', null, o), (proto.mediapipe.CalculatorOptions = function(e) { t.Message.initialize(this, e, 0, 2, null, null); }), r.inherits(proto.mediapipe.CalculatorOptions, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.CalculatorOptions.displayName = 'proto.mediapipe.CalculatorOptions'), (proto.mediapipe.CalculatorOptions.extensions = {}), (proto.mediapipe.CalculatorOptions.extensionsBinary = {}), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.CalculatorOptions.prototype.toObject = function(e) { return proto.mediapipe.CalculatorOptions.toObject(e, this); }), (proto.mediapipe.CalculatorOptions.toObject = function(e, r) { var o, i = { mergeFields: null == (o = t.Message.getBooleanField(r, 1)) ? void 0 : o }; return ( t.Message.toObjectExtension( r, i, proto.mediapipe.CalculatorOptions.extensions, proto.mediapipe.CalculatorOptions.prototype.getExtension, e ), e && (i.$jspbMessageInstance = r), i ); })), (proto.mediapipe.CalculatorOptions.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.CalculatorOptions(); return proto.mediapipe.CalculatorOptions.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.CalculatorOptions.deserializeBinaryFromReader = function(e, r) { for (; r.nextField() && !r.isEndGroup(); ) { if (1 === r.getFieldNumber()) { var o = r.readBool(); e.setMergeFields(o); } else t.Message.readBinaryExtension( e, r, proto.mediapipe.CalculatorOptions.extensionsBinary, proto.mediapipe.CalculatorOptions.prototype.getExtension, proto.mediapipe.CalculatorOptions.prototype.setExtension ); } return e; }), (proto.mediapipe.CalculatorOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.CalculatorOptions.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.CalculatorOptions.serializeBinaryToWriter = function(e, r) { var o; null != (o = t.Message.getField(e, 1)) && r.writeBool(1, o), t.Message.serializeBinaryExtensions( e, r, proto.mediapipe.CalculatorOptions.extensionsBinary, proto.mediapipe.CalculatorOptions.prototype.getExtension ); }), (proto.mediapipe.CalculatorOptions.prototype.getMergeFields = function() { return t.Message.getBooleanFieldWithDefault(this, 1, !1); }), (proto.mediapipe.CalculatorOptions.prototype.setMergeFields = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.CalculatorOptions.prototype.clearMergeFields = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.CalculatorOptions.prototype.hasMergeFields = function() { return null != t.Message.getField(this, 1); }), r.object.extend(e, proto.mediapipe); })(calculator_options_pb); var any_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.google.protobuf.Any', null, o), (proto.google.protobuf.Any = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.google.protobuf.Any, t.Message), r.DEBUG && !COMPILED && (proto.google.protobuf.Any.displayName = 'proto.google.protobuf.Any'), t.Message.GENERATE_TO_OBJECT && ((proto.google.protobuf.Any.prototype.toObject = function(e) { return proto.google.protobuf.Any.toObject(e, this); }), (proto.google.protobuf.Any.toObject = function(e, r) { var o = { typeUrl: t.Message.getFieldWithDefault(r, 1, ''), value: r.getValue_asB64(), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.google.protobuf.Any.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.google.protobuf.Any(); return proto.google.protobuf.Any.deserializeBinaryFromReader(o, r); }), (proto.google.protobuf.Any.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setTypeUrl(r); break; case 2: r = t.readBytes(); e.setValue(r); break; default: t.skipField(); } } return e; }), (proto.google.protobuf.Any.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return proto.google.protobuf.Any.serializeBinaryToWriter(this, e), e.getResultBuffer(); }), (proto.google.protobuf.Any.serializeBinaryToWriter = function(e, t) { var r = void 0; (r = e.getTypeUrl()).length > 0 && t.writeString(1, r), (r = e.getValue_asU8()).length > 0 && t.writeBytes(2, r); }), (proto.google.protobuf.Any.prototype.getTypeUrl = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.google.protobuf.Any.prototype.setTypeUrl = function(e) { return t.Message.setProto3StringField(this, 1, e); }), (proto.google.protobuf.Any.prototype.getValue = function() { return t.Message.getFieldWithDefault(this, 2, ''); }), (proto.google.protobuf.Any.prototype.getValue_asB64 = function() { return t.Message.bytesAsB64(this.getValue()); }), (proto.google.protobuf.Any.prototype.getValue_asU8 = function() { return t.Message.bytesAsU8(this.getValue()); }), (proto.google.protobuf.Any.prototype.setValue = function(e) { return t.Message.setProto3BytesField(this, 2, e); }), r.object.extend(e, proto.google.protobuf), (proto.google.protobuf.Any.prototype.getTypeName = function() { return this.getTypeUrl() .split('/') .pop(); }), (proto.google.protobuf.Any.prototype.pack = function(e, t, r) { r || (r = 'type.googleapis.com/'), '/' != r.substr(-1) ? this.setTypeUrl(r + '/' + t) : this.setTypeUrl(r + t), this.setValue(e); }), (proto.google.protobuf.Any.prototype.unpack = function(e, t) { return this.getTypeName() == t ? e(this.getValue_asU8()) : null; }); })(any_pb); var mediapipe_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.MediaPipeOptions', null, o), (proto.mediapipe.MediaPipeOptions = function(e) { t.Message.initialize(this, e, 0, 1, null, null); }), r.inherits(proto.mediapipe.MediaPipeOptions, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.MediaPipeOptions.displayName = 'proto.mediapipe.MediaPipeOptions'), (proto.mediapipe.MediaPipeOptions.extensions = {}), (proto.mediapipe.MediaPipeOptions.extensionsBinary = {}), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.MediaPipeOptions.prototype.toObject = function(e) { return proto.mediapipe.MediaPipeOptions.toObject(e, this); }), (proto.mediapipe.MediaPipeOptions.toObject = function(e, r) { var o = {}; return ( t.Message.toObjectExtension( r, o, proto.mediapipe.MediaPipeOptions.extensions, proto.mediapipe.MediaPipeOptions.prototype.getExtension, e ), e && (o.$jspbMessageInstance = r), o ); })), (proto.mediapipe.MediaPipeOptions.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.MediaPipeOptions(); return proto.mediapipe.MediaPipeOptions.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.MediaPipeOptions.deserializeBinaryFromReader = function(e, r) { for (; r.nextField() && !r.isEndGroup(); ) { r.getFieldNumber(); t.Message.readBinaryExtension( e, r, proto.mediapipe.MediaPipeOptions.extensionsBinary, proto.mediapipe.MediaPipeOptions.prototype.getExtension, proto.mediapipe.MediaPipeOptions.prototype.setExtension ); } return e; }), (proto.mediapipe.MediaPipeOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.MediaPipeOptions.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.MediaPipeOptions.serializeBinaryToWriter = function(e, r) { t.Message.serializeBinaryExtensions( e, r, proto.mediapipe.MediaPipeOptions.extensionsBinary, proto.mediapipe.MediaPipeOptions.prototype.getExtension ); }), r.object.extend(e, proto.mediapipe); })(mediapipe_options_pb); var packet_factory_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.PacketFactoryConfig', null, o), r.exportSymbol('proto.mediapipe.PacketFactoryOptions', null, o), r.exportSymbol('proto.mediapipe.PacketManagerConfig', null, o), (proto.mediapipe.PacketFactoryOptions = function(e) { t.Message.initialize(this, e, 0, 1, null, null); }), r.inherits(proto.mediapipe.PacketFactoryOptions, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.PacketFactoryOptions.displayName = 'proto.mediapipe.PacketFactoryOptions'), (proto.mediapipe.PacketFactoryOptions.extensions = {}), (proto.mediapipe.PacketFactoryOptions.extensionsBinary = {}), (proto.mediapipe.PacketFactoryConfig = function(e) { t.Message.initialize(this, e, 0, 500, null, null); }), r.inherits(proto.mediapipe.PacketFactoryConfig, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.PacketFactoryConfig.displayName = 'proto.mediapipe.PacketFactoryConfig'), (proto.mediapipe.PacketManagerConfig = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.PacketManagerConfig.repeatedFields_, null ); }), r.inherits(proto.mediapipe.PacketManagerConfig, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.PacketManagerConfig.displayName = 'proto.mediapipe.PacketManagerConfig'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.PacketFactoryOptions.prototype.toObject = function(e) { return proto.mediapipe.PacketFactoryOptions.toObject(e, this); }), (proto.mediapipe.PacketFactoryOptions.toObject = function(e, r) { var o = {}; return ( t.Message.toObjectExtension( r, o, proto.mediapipe.PacketFactoryOptions.extensions, proto.mediapipe.PacketFactoryOptions.prototype.getExtension, e ), e && (o.$jspbMessageInstance = r), o ); })), (proto.mediapipe.PacketFactoryOptions.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.PacketFactoryOptions(); return proto.mediapipe.PacketFactoryOptions.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.PacketFactoryOptions.deserializeBinaryFromReader = function(e, r) { for (; r.nextField() && !r.isEndGroup(); ) { r.getFieldNumber(); t.Message.readBinaryExtension( e, r, proto.mediapipe.PacketFactoryOptions.extensionsBinary, proto.mediapipe.PacketFactoryOptions.prototype.getExtension, proto.mediapipe.PacketFactoryOptions.prototype.setExtension ); } return e; }), (proto.mediapipe.PacketFactoryOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.PacketFactoryOptions.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.PacketFactoryOptions.serializeBinaryToWriter = function(e, r) { t.Message.serializeBinaryExtensions( e, r, proto.mediapipe.PacketFactoryOptions.extensionsBinary, proto.mediapipe.PacketFactoryOptions.prototype.getExtension ); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.PacketFactoryConfig.prototype.toObject = function(e) { return proto.mediapipe.PacketFactoryConfig.toObject(e, this); }), (proto.mediapipe.PacketFactoryConfig.toObject = function(e, r) { var o, i = { packetFactory: null == (o = t.Message.getField(r, 1)) ? void 0 : o, outputSidePacket: null == (o = t.Message.getField(r, 2)) ? void 0 : o, externalOutput: null == (o = t.Message.getField(r, 1002)) ? void 0 : o, options: (o = r.getOptions()) && proto.mediapipe.PacketFactoryOptions.toObject(e, o), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.PacketFactoryConfig.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.PacketFactoryConfig(); return proto.mediapipe.PacketFactoryConfig.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.PacketFactoryConfig.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setPacketFactory(r); break; case 2: r = t.readString(); e.setOutputSidePacket(r); break; case 1002: r = t.readString(); e.setExternalOutput(r); break; case 3: r = new proto.mediapipe.PacketFactoryOptions(); t.readMessage( r, proto.mediapipe.PacketFactoryOptions.deserializeBinaryFromReader ), e.setOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.PacketFactoryConfig.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.PacketFactoryConfig.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.PacketFactoryConfig.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeString(1, o), null != (o = t.Message.getField(e, 2)) && r.writeString(2, o), null != (o = t.Message.getField(e, 1002)) && r.writeString(1002, o), null != (o = e.getOptions()) && r.writeMessage( 3, o, proto.mediapipe.PacketFactoryOptions.serializeBinaryToWriter ); }), (proto.mediapipe.PacketFactoryConfig.prototype.getPacketFactory = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.PacketFactoryConfig.prototype.setPacketFactory = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.PacketFactoryConfig.prototype.clearPacketFactory = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.PacketFactoryConfig.prototype.hasPacketFactory = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.PacketFactoryConfig.prototype.getOutputSidePacket = function() { return t.Message.getFieldWithDefault(this, 2, ''); }), (proto.mediapipe.PacketFactoryConfig.prototype.setOutputSidePacket = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.PacketFactoryConfig.prototype.clearOutputSidePacket = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.PacketFactoryConfig.prototype.hasOutputSidePacket = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.PacketFactoryConfig.prototype.getExternalOutput = function() { return t.Message.getFieldWithDefault(this, 1002, ''); }), (proto.mediapipe.PacketFactoryConfig.prototype.setExternalOutput = function(e) { return t.Message.setField(this, 1002, e); }), (proto.mediapipe.PacketFactoryConfig.prototype.clearExternalOutput = function() { return t.Message.setField(this, 1002, void 0); }), (proto.mediapipe.PacketFactoryConfig.prototype.hasExternalOutput = function() { return null != t.Message.getField(this, 1002); }), (proto.mediapipe.PacketFactoryConfig.prototype.getOptions = function() { return t.Message.getWrapperField(this, proto.mediapipe.PacketFactoryOptions, 3); }), (proto.mediapipe.PacketFactoryConfig.prototype.setOptions = function(e) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.PacketFactoryConfig.prototype.clearOptions = function() { return this.setOptions(void 0); }), (proto.mediapipe.PacketFactoryConfig.prototype.hasOptions = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.PacketManagerConfig.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.PacketManagerConfig.prototype.toObject = function(e) { return proto.mediapipe.PacketManagerConfig.toObject(e, this); }), (proto.mediapipe.PacketManagerConfig.toObject = function(e, r) { var o = { packetList: t.Message.toObjectList( r.getPacketList(), proto.mediapipe.PacketFactoryConfig.toObject, e ), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.PacketManagerConfig.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.PacketManagerConfig(); return proto.mediapipe.PacketManagerConfig.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.PacketManagerConfig.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new proto.mediapipe.PacketFactoryConfig(); t.readMessage( r, proto.mediapipe.PacketFactoryConfig.deserializeBinaryFromReader ), e.addPacket(r); } else t.skipField(); } return e; }), (proto.mediapipe.PacketManagerConfig.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.PacketManagerConfig.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.PacketManagerConfig.serializeBinaryToWriter = function(e, t) { var r; (r = e.getPacketList()).length > 0 && t.writeRepeatedMessage( 1, r, proto.mediapipe.PacketFactoryConfig.serializeBinaryToWriter ); }), (proto.mediapipe.PacketManagerConfig.prototype.getPacketList = function() { return t.Message.getRepeatedWrapperField(this, proto.mediapipe.PacketFactoryConfig, 1); }), (proto.mediapipe.PacketManagerConfig.prototype.setPacketList = function(e) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.PacketManagerConfig.prototype.addPacket = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.PacketFactoryConfig, r ); }), (proto.mediapipe.PacketManagerConfig.prototype.clearPacketList = function() { return this.setPacketList([]); }), r.object.extend(e, proto.mediapipe); })(packet_factory_pb); var packet_generator_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.PacketGeneratorConfig', null, o), r.exportSymbol('proto.mediapipe.PacketGeneratorOptions', null, o), (proto.mediapipe.PacketGeneratorOptions = function(e) { t.Message.initialize(this, e, 0, 2, null, null); }), r.inherits(proto.mediapipe.PacketGeneratorOptions, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.PacketGeneratorOptions.displayName = 'proto.mediapipe.PacketGeneratorOptions'), (proto.mediapipe.PacketGeneratorOptions.extensions = {}), (proto.mediapipe.PacketGeneratorOptions.extensionsBinary = {}), (proto.mediapipe.PacketGeneratorConfig = function(e) { t.Message.initialize( this, e, 0, 500, proto.mediapipe.PacketGeneratorConfig.repeatedFields_, null ); }), r.inherits(proto.mediapipe.PacketGeneratorConfig, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.PacketGeneratorConfig.displayName = 'proto.mediapipe.PacketGeneratorConfig'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.PacketGeneratorOptions.prototype.toObject = function(e) { return proto.mediapipe.PacketGeneratorOptions.toObject(e, this); }), (proto.mediapipe.PacketGeneratorOptions.toObject = function(e, r) { var o = { mergeFields: t.Message.getBooleanFieldWithDefault(r, 1, !0) }; return ( t.Message.toObjectExtension( r, o, proto.mediapipe.PacketGeneratorOptions.extensions, proto.mediapipe.PacketGeneratorOptions.prototype.getExtension, e ), e && (o.$jspbMessageInstance = r), o ); })), (proto.mediapipe.PacketGeneratorOptions.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.PacketGeneratorOptions(); return proto.mediapipe.PacketGeneratorOptions.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.PacketGeneratorOptions.deserializeBinaryFromReader = function(e, r) { for (; r.nextField() && !r.isEndGroup(); ) { if (1 === r.getFieldNumber()) { var o = r.readBool(); e.setMergeFields(o); } else t.Message.readBinaryExtension( e, r, proto.mediapipe.PacketGeneratorOptions.extensionsBinary, proto.mediapipe.PacketGeneratorOptions.prototype.getExtension, proto.mediapipe.PacketGeneratorOptions.prototype.setExtension ); } return e; }), (proto.mediapipe.PacketGeneratorOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.PacketGeneratorOptions.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.PacketGeneratorOptions.serializeBinaryToWriter = function(e, r) { var o; null != (o = t.Message.getField(e, 1)) && r.writeBool(1, o), t.Message.serializeBinaryExtensions( e, r, proto.mediapipe.PacketGeneratorOptions.extensionsBinary, proto.mediapipe.PacketGeneratorOptions.prototype.getExtension ); }), (proto.mediapipe.PacketGeneratorOptions.prototype.getMergeFields = function() { return t.Message.getBooleanFieldWithDefault(this, 1, !0); }), (proto.mediapipe.PacketGeneratorOptions.prototype.setMergeFields = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.PacketGeneratorOptions.prototype.clearMergeFields = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.PacketGeneratorOptions.prototype.hasMergeFields = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.PacketGeneratorConfig.repeatedFields_ = [2, 1002, 3, 1003]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.PacketGeneratorConfig.prototype.toObject = function(e) { return proto.mediapipe.PacketGeneratorConfig.toObject(e, this); }), (proto.mediapipe.PacketGeneratorConfig.toObject = function(e, r) { var o, i = { packetGenerator: null == (o = t.Message.getField(r, 1)) ? void 0 : o, inputSidePacketList: null == (o = t.Message.getRepeatedField(r, 2)) ? void 0 : o, externalInputList: null == (o = t.Message.getRepeatedField(r, 1002)) ? void 0 : o, outputSidePacketList: null == (o = t.Message.getRepeatedField(r, 3)) ? void 0 : o, externalOutputList: null == (o = t.Message.getRepeatedField(r, 1003)) ? void 0 : o, options: (o = r.getOptions()) && proto.mediapipe.PacketGeneratorOptions.toObject(e, o), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.PacketGeneratorConfig.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.PacketGeneratorConfig(); return proto.mediapipe.PacketGeneratorConfig.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.PacketGeneratorConfig.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setPacketGenerator(r); break; case 2: r = t.readString(); e.addInputSidePacket(r); break; case 1002: r = t.readString(); e.addExternalInput(r); break; case 3: r = t.readString(); e.addOutputSidePacket(r); break; case 1003: r = t.readString(); e.addExternalOutput(r); break; case 4: r = new proto.mediapipe.PacketGeneratorOptions(); t.readMessage( r, proto.mediapipe.PacketGeneratorOptions.deserializeBinaryFromReader ), e.setOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.PacketGeneratorConfig.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.PacketGeneratorConfig.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.PacketGeneratorConfig.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeString(1, o), (o = e.getInputSidePacketList()).length > 0 && r.writeRepeatedString(2, o), (o = e.getExternalInputList()).length > 0 && r.writeRepeatedString(1002, o), (o = e.getOutputSidePacketList()).length > 0 && r.writeRepeatedString(3, o), (o = e.getExternalOutputList()).length > 0 && r.writeRepeatedString(1003, o), null != (o = e.getOptions()) && r.writeMessage( 4, o, proto.mediapipe.PacketGeneratorOptions.serializeBinaryToWriter ); }), (proto.mediapipe.PacketGeneratorConfig.prototype.getPacketGenerator = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.PacketGeneratorConfig.prototype.setPacketGenerator = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.PacketGeneratorConfig.prototype.clearPacketGenerator = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.PacketGeneratorConfig.prototype.hasPacketGenerator = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.PacketGeneratorConfig.prototype.getInputSidePacketList = function() { return t.Message.getRepeatedField(this, 2); }), (proto.mediapipe.PacketGeneratorConfig.prototype.setInputSidePacketList = function(e) { return t.Message.setField(this, 2, e || []); }), (proto.mediapipe.PacketGeneratorConfig.prototype.addInputSidePacket = function(e, r) { return t.Message.addToRepeatedField(this, 2, e, r); }), (proto.mediapipe.PacketGeneratorConfig.prototype.clearInputSidePacketList = function() { return this.setInputSidePacketList([]); }), (proto.mediapipe.PacketGeneratorConfig.prototype.getExternalInputList = function() { return t.Message.getRepeatedField(this, 1002); }), (proto.mediapipe.PacketGeneratorConfig.prototype.setExternalInputList = function(e) { return t.Message.setField(this, 1002, e || []); }), (proto.mediapipe.PacketGeneratorConfig.prototype.addExternalInput = function(e, r) { return t.Message.addToRepeatedField(this, 1002, e, r); }), (proto.mediapipe.PacketGeneratorConfig.prototype.clearExternalInputList = function() { return this.setExternalInputList([]); }), (proto.mediapipe.PacketGeneratorConfig.prototype.getOutputSidePacketList = function() { return t.Message.getRepeatedField(this, 3); }), (proto.mediapipe.PacketGeneratorConfig.prototype.setOutputSidePacketList = function(e) { return t.Message.setField(this, 3, e || []); }), (proto.mediapipe.PacketGeneratorConfig.prototype.addOutputSidePacket = function(e, r) { return t.Message.addToRepeatedField(this, 3, e, r); }), (proto.mediapipe.PacketGeneratorConfig.prototype.clearOutputSidePacketList = function() { return this.setOutputSidePacketList([]); }), (proto.mediapipe.PacketGeneratorConfig.prototype.getExternalOutputList = function() { return t.Message.getRepeatedField(this, 1003); }), (proto.mediapipe.PacketGeneratorConfig.prototype.setExternalOutputList = function(e) { return t.Message.setField(this, 1003, e || []); }), (proto.mediapipe.PacketGeneratorConfig.prototype.addExternalOutput = function(e, r) { return t.Message.addToRepeatedField(this, 1003, e, r); }), (proto.mediapipe.PacketGeneratorConfig.prototype.clearExternalOutputList = function() { return this.setExternalOutputList([]); }), (proto.mediapipe.PacketGeneratorConfig.prototype.getOptions = function() { return t.Message.getWrapperField(this, proto.mediapipe.PacketGeneratorOptions, 4); }), (proto.mediapipe.PacketGeneratorConfig.prototype.setOptions = function(e) { return t.Message.setWrapperField(this, 4, e); }), (proto.mediapipe.PacketGeneratorConfig.prototype.clearOptions = function() { return this.setOptions(void 0); }), (proto.mediapipe.PacketGeneratorConfig.prototype.hasOptions = function() { return null != t.Message.getField(this, 4); }), r.object.extend(e, proto.mediapipe); })(packet_generator_pb); var status_handler_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = mediapipe_options_pb; r.object.extend(proto, i), r.exportSymbol('proto.mediapipe.StatusHandlerConfig', null, o), (proto.mediapipe.StatusHandlerConfig = function(e) { t.Message.initialize( this, e, 0, 500, proto.mediapipe.StatusHandlerConfig.repeatedFields_, null ); }), r.inherits(proto.mediapipe.StatusHandlerConfig, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.StatusHandlerConfig.displayName = 'proto.mediapipe.StatusHandlerConfig'), (proto.mediapipe.StatusHandlerConfig.repeatedFields_ = [2, 1002]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.StatusHandlerConfig.prototype.toObject = function(e) { return proto.mediapipe.StatusHandlerConfig.toObject(e, this); }), (proto.mediapipe.StatusHandlerConfig.toObject = function(e, r) { var o, a = { statusHandler: null == (o = t.Message.getField(r, 1)) ? void 0 : o, inputSidePacketList: null == (o = t.Message.getRepeatedField(r, 2)) ? void 0 : o, externalInputList: null == (o = t.Message.getRepeatedField(r, 1002)) ? void 0 : o, options: (o = r.getOptions()) && i.MediaPipeOptions.toObject(e, o), }; return e && (a.$jspbMessageInstance = r), a; })), (proto.mediapipe.StatusHandlerConfig.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.StatusHandlerConfig(); return proto.mediapipe.StatusHandlerConfig.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.StatusHandlerConfig.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setStatusHandler(r); break; case 2: r = t.readString(); e.addInputSidePacket(r); break; case 1002: r = t.readString(); e.addExternalInput(r); break; case 3: r = new i.MediaPipeOptions(); t.readMessage(r, i.MediaPipeOptions.deserializeBinaryFromReader), e.setOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.StatusHandlerConfig.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.StatusHandlerConfig.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.StatusHandlerConfig.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeString(1, o), (o = e.getInputSidePacketList()).length > 0 && r.writeRepeatedString(2, o), (o = e.getExternalInputList()).length > 0 && r.writeRepeatedString(1002, o), null != (o = e.getOptions()) && r.writeMessage(3, o, i.MediaPipeOptions.serializeBinaryToWriter); }), (proto.mediapipe.StatusHandlerConfig.prototype.getStatusHandler = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.StatusHandlerConfig.prototype.setStatusHandler = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.StatusHandlerConfig.prototype.clearStatusHandler = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.StatusHandlerConfig.prototype.hasStatusHandler = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.StatusHandlerConfig.prototype.getInputSidePacketList = function() { return t.Message.getRepeatedField(this, 2); }), (proto.mediapipe.StatusHandlerConfig.prototype.setInputSidePacketList = function(e) { return t.Message.setField(this, 2, e || []); }), (proto.mediapipe.StatusHandlerConfig.prototype.addInputSidePacket = function(e, r) { return t.Message.addToRepeatedField(this, 2, e, r); }), (proto.mediapipe.StatusHandlerConfig.prototype.clearInputSidePacketList = function() { return this.setInputSidePacketList([]); }), (proto.mediapipe.StatusHandlerConfig.prototype.getExternalInputList = function() { return t.Message.getRepeatedField(this, 1002); }), (proto.mediapipe.StatusHandlerConfig.prototype.setExternalInputList = function(e) { return t.Message.setField(this, 1002, e || []); }), (proto.mediapipe.StatusHandlerConfig.prototype.addExternalInput = function(e, r) { return t.Message.addToRepeatedField(this, 1002, e, r); }), (proto.mediapipe.StatusHandlerConfig.prototype.clearExternalInputList = function() { return this.setExternalInputList([]); }), (proto.mediapipe.StatusHandlerConfig.prototype.getOptions = function() { return t.Message.getWrapperField(this, i.MediaPipeOptions, 3); }), (proto.mediapipe.StatusHandlerConfig.prototype.setOptions = function(e) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.StatusHandlerConfig.prototype.clearOptions = function() { return this.setOptions(void 0); }), (proto.mediapipe.StatusHandlerConfig.prototype.hasOptions = function() { return null != t.Message.getField(this, 3); }), r.object.extend(e, proto.mediapipe); })(status_handler_pb); var stream_handler_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = mediapipe_options_pb; r.object.extend(proto, i), r.exportSymbol('proto.mediapipe.InputStreamHandlerConfig', null, o), r.exportSymbol('proto.mediapipe.OutputStreamHandlerConfig', null, o), (proto.mediapipe.InputStreamHandlerConfig = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.InputStreamHandlerConfig, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.InputStreamHandlerConfig.displayName = 'proto.mediapipe.InputStreamHandlerConfig'), (proto.mediapipe.OutputStreamHandlerConfig = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.OutputStreamHandlerConfig.repeatedFields_, null ); }), r.inherits(proto.mediapipe.OutputStreamHandlerConfig, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.OutputStreamHandlerConfig.displayName = 'proto.mediapipe.OutputStreamHandlerConfig'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.InputStreamHandlerConfig.prototype.toObject = function(e) { return proto.mediapipe.InputStreamHandlerConfig.toObject(e, this); }), (proto.mediapipe.InputStreamHandlerConfig.toObject = function(e, r) { var o, a = { inputStreamHandler: t.Message.getFieldWithDefault( r, 1, 'DefaultInputStreamHandler' ), options: (o = r.getOptions()) && i.MediaPipeOptions.toObject(e, o), }; return e && (a.$jspbMessageInstance = r), a; })), (proto.mediapipe.InputStreamHandlerConfig.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.InputStreamHandlerConfig(); return proto.mediapipe.InputStreamHandlerConfig.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.InputStreamHandlerConfig.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setInputStreamHandler(r); break; case 3: r = new i.MediaPipeOptions(); t.readMessage(r, i.MediaPipeOptions.deserializeBinaryFromReader), e.setOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.InputStreamHandlerConfig.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.InputStreamHandlerConfig.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.InputStreamHandlerConfig.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeString(1, o), null != (o = e.getOptions()) && r.writeMessage(3, o, i.MediaPipeOptions.serializeBinaryToWriter); }), (proto.mediapipe.InputStreamHandlerConfig.prototype.getInputStreamHandler = function() { return t.Message.getFieldWithDefault(this, 1, 'DefaultInputStreamHandler'); }), (proto.mediapipe.InputStreamHandlerConfig.prototype.setInputStreamHandler = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.InputStreamHandlerConfig.prototype.clearInputStreamHandler = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.InputStreamHandlerConfig.prototype.hasInputStreamHandler = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.InputStreamHandlerConfig.prototype.getOptions = function() { return t.Message.getWrapperField(this, i.MediaPipeOptions, 3); }), (proto.mediapipe.InputStreamHandlerConfig.prototype.setOptions = function(e) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.InputStreamHandlerConfig.prototype.clearOptions = function() { return this.setOptions(void 0); }), (proto.mediapipe.InputStreamHandlerConfig.prototype.hasOptions = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.OutputStreamHandlerConfig.repeatedFields_ = [2]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.OutputStreamHandlerConfig.prototype.toObject = function(e) { return proto.mediapipe.OutputStreamHandlerConfig.toObject(e, this); }), (proto.mediapipe.OutputStreamHandlerConfig.toObject = function(e, r) { var o, a = { outputStreamHandler: t.Message.getFieldWithDefault( r, 1, 'InOrderOutputStreamHandler' ), inputSidePacketList: null == (o = t.Message.getRepeatedField(r, 2)) ? void 0 : o, options: (o = r.getOptions()) && i.MediaPipeOptions.toObject(e, o), }; return e && (a.$jspbMessageInstance = r), a; })), (proto.mediapipe.OutputStreamHandlerConfig.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.OutputStreamHandlerConfig(); return proto.mediapipe.OutputStreamHandlerConfig.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.OutputStreamHandlerConfig.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setOutputStreamHandler(r); break; case 2: r = t.readString(); e.addInputSidePacket(r); break; case 3: r = new i.MediaPipeOptions(); t.readMessage(r, i.MediaPipeOptions.deserializeBinaryFromReader), e.setOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.OutputStreamHandlerConfig.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.OutputStreamHandlerConfig.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeString(1, o), (o = e.getInputSidePacketList()).length > 0 && r.writeRepeatedString(2, o), null != (o = e.getOptions()) && r.writeMessage(3, o, i.MediaPipeOptions.serializeBinaryToWriter); }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.getOutputStreamHandler = function() { return t.Message.getFieldWithDefault(this, 1, 'InOrderOutputStreamHandler'); }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.setOutputStreamHandler = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.clearOutputStreamHandler = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.hasOutputStreamHandler = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.getInputSidePacketList = function() { return t.Message.getRepeatedField(this, 2); }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.setInputSidePacketList = function(e) { return t.Message.setField(this, 2, e || []); }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.addInputSidePacket = function(e, r) { return t.Message.addToRepeatedField(this, 2, e, r); }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.clearInputSidePacketList = function() { return this.setInputSidePacketList([]); }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.getOptions = function() { return t.Message.getWrapperField(this, i.MediaPipeOptions, 3); }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.setOptions = function(e) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.clearOptions = function() { return this.setOptions(void 0); }), (proto.mediapipe.OutputStreamHandlerConfig.prototype.hasOptions = function() { return null != t.Message.getField(this, 3); }), r.object.extend(e, proto.mediapipe); })(stream_handler_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_options_pb; r.object.extend(proto, i); var a = any_pb; r.object.extend(proto, a); var n = mediapipe_options_pb; r.object.extend(proto, n); var s = packet_factory_pb; r.object.extend(proto, s); var p = packet_generator_pb; r.object.extend(proto, p); var d = status_handler_pb; r.object.extend(proto, d); var l = stream_handler_pb; r.object.extend(proto, l), r.exportSymbol('proto.mediapipe.CalculatorGraphConfig', null, o), r.exportSymbol('proto.mediapipe.CalculatorGraphConfig.Node', null, o), r.exportSymbol('proto.mediapipe.ExecutorConfig', null, o), r.exportSymbol('proto.mediapipe.InputCollection', null, o), r.exportSymbol('proto.mediapipe.InputCollection.InputType', null, o), r.exportSymbol('proto.mediapipe.InputCollectionSet', null, o), r.exportSymbol('proto.mediapipe.InputStreamInfo', null, o), r.exportSymbol('proto.mediapipe.ProfilerConfig', null, o), (proto.mediapipe.ExecutorConfig = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.ExecutorConfig, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.ExecutorConfig.displayName = 'proto.mediapipe.ExecutorConfig'), (proto.mediapipe.InputCollection = function(e) { t.Message.initialize( this, e, 0, 500, proto.mediapipe.InputCollection.repeatedFields_, null ); }), r.inherits(proto.mediapipe.InputCollection, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.InputCollection.displayName = 'proto.mediapipe.InputCollection'), (proto.mediapipe.InputCollectionSet = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.InputCollectionSet.repeatedFields_, null ); }), r.inherits(proto.mediapipe.InputCollectionSet, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.InputCollectionSet.displayName = 'proto.mediapipe.InputCollectionSet'), (proto.mediapipe.InputStreamInfo = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.InputStreamInfo, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.InputStreamInfo.displayName = 'proto.mediapipe.InputStreamInfo'), (proto.mediapipe.ProfilerConfig = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.ProfilerConfig.repeatedFields_, null ); }), r.inherits(proto.mediapipe.ProfilerConfig, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.ProfilerConfig.displayName = 'proto.mediapipe.ProfilerConfig'), (proto.mediapipe.CalculatorGraphConfig = function(e) { t.Message.initialize( this, e, 0, 500, proto.mediapipe.CalculatorGraphConfig.repeatedFields_, null ); }), r.inherits(proto.mediapipe.CalculatorGraphConfig, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.CalculatorGraphConfig.displayName = 'proto.mediapipe.CalculatorGraphConfig'), (proto.mediapipe.CalculatorGraphConfig.Node = function(e) { t.Message.initialize( this, e, 0, 500, proto.mediapipe.CalculatorGraphConfig.Node.repeatedFields_, null ); }), r.inherits(proto.mediapipe.CalculatorGraphConfig.Node, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.CalculatorGraphConfig.Node.displayName = 'proto.mediapipe.CalculatorGraphConfig.Node'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.ExecutorConfig.prototype.toObject = function(e) { return proto.mediapipe.ExecutorConfig.toObject(e, this); }), (proto.mediapipe.ExecutorConfig.toObject = function(e, r) { var o, i = { name: t.Message.getFieldWithDefault(r, 1, ''), type: t.Message.getFieldWithDefault(r, 2, ''), options: (o = r.getOptions()) && n.MediaPipeOptions.toObject(e, o), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.ExecutorConfig.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.ExecutorConfig(); return proto.mediapipe.ExecutorConfig.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.ExecutorConfig.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setName(r); break; case 2: r = t.readString(); e.setType(r); break; case 3: r = new n.MediaPipeOptions(); t.readMessage(r, n.MediaPipeOptions.deserializeBinaryFromReader), e.setOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.ExecutorConfig.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.ExecutorConfig.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.ExecutorConfig.serializeBinaryToWriter = function(e, t) { var r = void 0; (r = e.getName()).length > 0 && t.writeString(1, r), (r = e.getType()).length > 0 && t.writeString(2, r), null != (r = e.getOptions()) && t.writeMessage(3, r, n.MediaPipeOptions.serializeBinaryToWriter); }), (proto.mediapipe.ExecutorConfig.prototype.getName = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.ExecutorConfig.prototype.setName = function(e) { return t.Message.setProto3StringField(this, 1, e); }), (proto.mediapipe.ExecutorConfig.prototype.getType = function() { return t.Message.getFieldWithDefault(this, 2, ''); }), (proto.mediapipe.ExecutorConfig.prototype.setType = function(e) { return t.Message.setProto3StringField(this, 2, e); }), (proto.mediapipe.ExecutorConfig.prototype.getOptions = function() { return t.Message.getWrapperField(this, n.MediaPipeOptions, 3); }), (proto.mediapipe.ExecutorConfig.prototype.setOptions = function(e) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.ExecutorConfig.prototype.clearOptions = function() { return this.setOptions(void 0); }), (proto.mediapipe.ExecutorConfig.prototype.hasOptions = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.InputCollection.repeatedFields_ = [2, 1002]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.InputCollection.prototype.toObject = function(e) { return proto.mediapipe.InputCollection.toObject(e, this); }), (proto.mediapipe.InputCollection.toObject = function(e, r) { var o, i = { name: t.Message.getFieldWithDefault(r, 1, ''), sidePacketNameList: null == (o = t.Message.getRepeatedField(r, 2)) ? void 0 : o, externalInputNameList: null == (o = t.Message.getRepeatedField(r, 1002)) ? void 0 : o, inputType: t.Message.getFieldWithDefault(r, 3, 0), fileName: t.Message.getFieldWithDefault(r, 4, ''), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.InputCollection.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.InputCollection(); return proto.mediapipe.InputCollection.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.InputCollection.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setName(r); break; case 2: r = t.readString(); e.addSidePacketName(r); break; case 1002: r = t.readString(); e.addExternalInputName(r); break; case 3: r = t.readEnum(); e.setInputType(r); break; case 4: r = t.readString(); e.setFileName(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.InputCollection.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.InputCollection.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.InputCollection.serializeBinaryToWriter = function(e, t) { var r = void 0; (r = e.getName()).length > 0 && t.writeString(1, r), (r = e.getSidePacketNameList()).length > 0 && t.writeRepeatedString(2, r), (r = e.getExternalInputNameList()).length > 0 && t.writeRepeatedString(1002, r), 0 !== (r = e.getInputType()) && t.writeEnum(3, r), (r = e.getFileName()).length > 0 && t.writeString(4, r); }), (proto.mediapipe.InputCollection.InputType = { UNKNOWN: 0, RECORDIO: 1, FOREIGN_RECORDIO: 2, FOREIGN_CSV_TEXT: 3, INVALID_UPPER_BOUND: 4, }), (proto.mediapipe.InputCollection.prototype.getName = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.InputCollection.prototype.setName = function(e) { return t.Message.setProto3StringField(this, 1, e); }), (proto.mediapipe.InputCollection.prototype.getSidePacketNameList = function() { return t.Message.getRepeatedField(this, 2); }), (proto.mediapipe.InputCollection.prototype.setSidePacketNameList = function(e) { return t.Message.setField(this, 2, e || []); }), (proto.mediapipe.InputCollection.prototype.addSidePacketName = function(e, r) { return t.Message.addToRepeatedField(this, 2, e, r); }), (proto.mediapipe.InputCollection.prototype.clearSidePacketNameList = function() { return this.setSidePacketNameList([]); }), (proto.mediapipe.InputCollection.prototype.getExternalInputNameList = function() { return t.Message.getRepeatedField(this, 1002); }), (proto.mediapipe.InputCollection.prototype.setExternalInputNameList = function(e) { return t.Message.setField(this, 1002, e || []); }), (proto.mediapipe.InputCollection.prototype.addExternalInputName = function(e, r) { return t.Message.addToRepeatedField(this, 1002, e, r); }), (proto.mediapipe.InputCollection.prototype.clearExternalInputNameList = function() { return this.setExternalInputNameList([]); }), (proto.mediapipe.InputCollection.prototype.getInputType = function() { return t.Message.getFieldWithDefault(this, 3, 0); }), (proto.mediapipe.InputCollection.prototype.setInputType = function(e) { return t.Message.setProto3EnumField(this, 3, e); }), (proto.mediapipe.InputCollection.prototype.getFileName = function() { return t.Message.getFieldWithDefault(this, 4, ''); }), (proto.mediapipe.InputCollection.prototype.setFileName = function(e) { return t.Message.setProto3StringField(this, 4, e); }), (proto.mediapipe.InputCollectionSet.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.InputCollectionSet.prototype.toObject = function(e) { return proto.mediapipe.InputCollectionSet.toObject(e, this); }), (proto.mediapipe.InputCollectionSet.toObject = function(e, r) { var o = { inputCollectionList: t.Message.toObjectList( r.getInputCollectionList(), proto.mediapipe.InputCollection.toObject, e ), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.InputCollectionSet.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.InputCollectionSet(); return proto.mediapipe.InputCollectionSet.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.InputCollectionSet.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new proto.mediapipe.InputCollection(); t.readMessage( r, proto.mediapipe.InputCollection.deserializeBinaryFromReader ), e.addInputCollection(r); } else t.skipField(); } return e; }), (proto.mediapipe.InputCollectionSet.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.InputCollectionSet.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.InputCollectionSet.serializeBinaryToWriter = function(e, t) { var r; (r = e.getInputCollectionList()).length > 0 && t.writeRepeatedMessage( 1, r, proto.mediapipe.InputCollection.serializeBinaryToWriter ); }), (proto.mediapipe.InputCollectionSet.prototype.getInputCollectionList = function() { return t.Message.getRepeatedWrapperField(this, proto.mediapipe.InputCollection, 1); }), (proto.mediapipe.InputCollectionSet.prototype.setInputCollectionList = function(e) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.InputCollectionSet.prototype.addInputCollection = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.InputCollection, r ); }), (proto.mediapipe.InputCollectionSet.prototype.clearInputCollectionList = function() { return this.setInputCollectionList([]); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.InputStreamInfo.prototype.toObject = function(e) { return proto.mediapipe.InputStreamInfo.toObject(e, this); }), (proto.mediapipe.InputStreamInfo.toObject = function(e, r) { var o = { tagIndex: t.Message.getFieldWithDefault(r, 1, ''), backEdge: t.Message.getBooleanFieldWithDefault(r, 2, !1), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.InputStreamInfo.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.InputStreamInfo(); return proto.mediapipe.InputStreamInfo.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.InputStreamInfo.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setTagIndex(r); break; case 2: r = t.readBool(); e.setBackEdge(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.InputStreamInfo.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.InputStreamInfo.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.InputStreamInfo.serializeBinaryToWriter = function(e, t) { var r = void 0; (r = e.getTagIndex()).length > 0 && t.writeString(1, r), (r = e.getBackEdge()) && t.writeBool(2, r); }), (proto.mediapipe.InputStreamInfo.prototype.getTagIndex = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.InputStreamInfo.prototype.setTagIndex = function(e) { return t.Message.setProto3StringField(this, 1, e); }), (proto.mediapipe.InputStreamInfo.prototype.getBackEdge = function() { return t.Message.getBooleanFieldWithDefault(this, 2, !1); }), (proto.mediapipe.InputStreamInfo.prototype.setBackEdge = function(e) { return t.Message.setProto3BooleanField(this, 2, e); }), (proto.mediapipe.ProfilerConfig.repeatedFields_ = [8]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.ProfilerConfig.prototype.toObject = function(e) { return proto.mediapipe.ProfilerConfig.toObject(e, this); }), (proto.mediapipe.ProfilerConfig.toObject = function(e, r) { var o, i = { histogramIntervalSizeUsec: t.Message.getFieldWithDefault(r, 1, 0), numHistogramIntervals: t.Message.getFieldWithDefault(r, 2, 0), enableInputOutputLatency: t.Message.getBooleanFieldWithDefault( r, 3, !1 ), enableProfiler: t.Message.getBooleanFieldWithDefault(r, 4, !1), enableStreamLatency: t.Message.getBooleanFieldWithDefault(r, 5, !1), usePacketTimestampForAddedPacket: t.Message.getBooleanFieldWithDefault( r, 6, !1 ), traceLogCapacity: t.Message.getFieldWithDefault(r, 7, 0), traceEventTypesDisabledList: null == (o = t.Message.getRepeatedField(r, 8)) ? void 0 : o, traceLogPath: t.Message.getFieldWithDefault(r, 9, ''), traceLogCount: t.Message.getFieldWithDefault(r, 10, 0), traceLogIntervalUsec: t.Message.getFieldWithDefault(r, 11, 0), traceLogMarginUsec: t.Message.getFieldWithDefault(r, 12, 0), traceLogDurationEvents: t.Message.getBooleanFieldWithDefault(r, 13, !1), traceLogIntervalCount: t.Message.getFieldWithDefault(r, 14, 0), traceLogDisabled: t.Message.getBooleanFieldWithDefault(r, 15, !1), traceEnabled: t.Message.getBooleanFieldWithDefault(r, 16, !1), traceLogInstantEvents: t.Message.getBooleanFieldWithDefault(r, 17, !1), calculatorFilter: t.Message.getFieldWithDefault(r, 18, ''), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.ProfilerConfig.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.ProfilerConfig(); return proto.mediapipe.ProfilerConfig.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.ProfilerConfig.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readInt64(); e.setHistogramIntervalSizeUsec(r); break; case 2: r = t.readInt64(); e.setNumHistogramIntervals(r); break; case 3: r = t.readBool(); e.setEnableInputOutputLatency(r); break; case 4: r = t.readBool(); e.setEnableProfiler(r); break; case 5: r = t.readBool(); e.setEnableStreamLatency(r); break; case 6: r = t.readBool(); e.setUsePacketTimestampForAddedPacket(r); break; case 7: r = t.readInt64(); e.setTraceLogCapacity(r); break; case 8: for ( var o = t.isDelimited() ? t.readPackedInt32() : [t.readInt32()], i = 0; i < o.length; i++ ) e.addTraceEventTypesDisabled(o[i]); break; case 9: r = t.readString(); e.setTraceLogPath(r); break; case 10: r = t.readInt32(); e.setTraceLogCount(r); break; case 11: r = t.readInt64(); e.setTraceLogIntervalUsec(r); break; case 12: r = t.readInt64(); e.setTraceLogMarginUsec(r); break; case 13: r = t.readBool(); e.setTraceLogDurationEvents(r); break; case 14: r = t.readInt32(); e.setTraceLogIntervalCount(r); break; case 15: r = t.readBool(); e.setTraceLogDisabled(r); break; case 16: r = t.readBool(); e.setTraceEnabled(r); break; case 17: r = t.readBool(); e.setTraceLogInstantEvents(r); break; case 18: r = t.readString(); e.setCalculatorFilter(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.ProfilerConfig.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.ProfilerConfig.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.ProfilerConfig.serializeBinaryToWriter = function(e, t) { var r = void 0; 0 !== (r = e.getHistogramIntervalSizeUsec()) && t.writeInt64(1, r), 0 !== (r = e.getNumHistogramIntervals()) && t.writeInt64(2, r), (r = e.getEnableInputOutputLatency()) && t.writeBool(3, r), (r = e.getEnableProfiler()) && t.writeBool(4, r), (r = e.getEnableStreamLatency()) && t.writeBool(5, r), (r = e.getUsePacketTimestampForAddedPacket()) && t.writeBool(6, r), 0 !== (r = e.getTraceLogCapacity()) && t.writeInt64(7, r), (r = e.getTraceEventTypesDisabledList()).length > 0 && t.writePackedInt32(8, r), (r = e.getTraceLogPath()).length > 0 && t.writeString(9, r), 0 !== (r = e.getTraceLogCount()) && t.writeInt32(10, r), 0 !== (r = e.getTraceLogIntervalUsec()) && t.writeInt64(11, r), 0 !== (r = e.getTraceLogMarginUsec()) && t.writeInt64(12, r), (r = e.getTraceLogDurationEvents()) && t.writeBool(13, r), 0 !== (r = e.getTraceLogIntervalCount()) && t.writeInt32(14, r), (r = e.getTraceLogDisabled()) && t.writeBool(15, r), (r = e.getTraceEnabled()) && t.writeBool(16, r), (r = e.getTraceLogInstantEvents()) && t.writeBool(17, r), (r = e.getCalculatorFilter()).length > 0 && t.writeString(18, r); }), (proto.mediapipe.ProfilerConfig.prototype.getHistogramIntervalSizeUsec = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.ProfilerConfig.prototype.setHistogramIntervalSizeUsec = function(e) { return t.Message.setProto3IntField(this, 1, e); }), (proto.mediapipe.ProfilerConfig.prototype.getNumHistogramIntervals = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.ProfilerConfig.prototype.setNumHistogramIntervals = function(e) { return t.Message.setProto3IntField(this, 2, e); }), (proto.mediapipe.ProfilerConfig.prototype.getEnableInputOutputLatency = function() { return t.Message.getBooleanFieldWithDefault(this, 3, !1); }), (proto.mediapipe.ProfilerConfig.prototype.setEnableInputOutputLatency = function(e) { return t.Message.setProto3BooleanField(this, 3, e); }), (proto.mediapipe.ProfilerConfig.prototype.getEnableProfiler = function() { return t.Message.getBooleanFieldWithDefault(this, 4, !1); }), (proto.mediapipe.ProfilerConfig.prototype.setEnableProfiler = function(e) { return t.Message.setProto3BooleanField(this, 4, e); }), (proto.mediapipe.ProfilerConfig.prototype.getEnableStreamLatency = function() { return t.Message.getBooleanFieldWithDefault(this, 5, !1); }), (proto.mediapipe.ProfilerConfig.prototype.setEnableStreamLatency = function(e) { return t.Message.setProto3BooleanField(this, 5, e); }), (proto.mediapipe.ProfilerConfig.prototype.getUsePacketTimestampForAddedPacket = function() { return t.Message.getBooleanFieldWithDefault(this, 6, !1); }), (proto.mediapipe.ProfilerConfig.prototype.setUsePacketTimestampForAddedPacket = function( e ) { return t.Message.setProto3BooleanField(this, 6, e); }), (proto.mediapipe.ProfilerConfig.prototype.getTraceLogCapacity = function() { return t.Message.getFieldWithDefault(this, 7, 0); }), (proto.mediapipe.ProfilerConfig.prototype.setTraceLogCapacity = function(e) { return t.Message.setProto3IntField(this, 7, e); }), (proto.mediapipe.ProfilerConfig.prototype.getTraceEventTypesDisabledList = function() { return t.Message.getRepeatedField(this, 8); }), (proto.mediapipe.ProfilerConfig.prototype.setTraceEventTypesDisabledList = function(e) { return t.Message.setField(this, 8, e || []); }), (proto.mediapipe.ProfilerConfig.prototype.addTraceEventTypesDisabled = function(e, r) { return t.Message.addToRepeatedField(this, 8, e, r); }), (proto.mediapipe.ProfilerConfig.prototype.clearTraceEventTypesDisabledList = function() { return this.setTraceEventTypesDisabledList([]); }), (proto.mediapipe.ProfilerConfig.prototype.getTraceLogPath = function() { return t.Message.getFieldWithDefault(this, 9, ''); }), (proto.mediapipe.ProfilerConfig.prototype.setTraceLogPath = function(e) { return t.Message.setProto3StringField(this, 9, e); }), (proto.mediapipe.ProfilerConfig.prototype.getTraceLogCount = function() { return t.Message.getFieldWithDefault(this, 10, 0); }), (proto.mediapipe.ProfilerConfig.prototype.setTraceLogCount = function(e) { return t.Message.setProto3IntField(this, 10, e); }), (proto.mediapipe.ProfilerConfig.prototype.getTraceLogIntervalUsec = function() { return t.Message.getFieldWithDefault(this, 11, 0); }), (proto.mediapipe.ProfilerConfig.prototype.setTraceLogIntervalUsec = function(e) { return t.Message.setProto3IntField(this, 11, e); }), (proto.mediapipe.ProfilerConfig.prototype.getTraceLogMarginUsec = function() { return t.Message.getFieldWithDefault(this, 12, 0); }), (proto.mediapipe.ProfilerConfig.prototype.setTraceLogMarginUsec = function(e) { return t.Message.setProto3IntField(this, 12, e); }), (proto.mediapipe.ProfilerConfig.prototype.getTraceLogDurationEvents = function() { return t.Message.getBooleanFieldWithDefault(this, 13, !1); }), (proto.mediapipe.ProfilerConfig.prototype.setTraceLogDurationEvents = function(e) { return t.Message.setProto3BooleanField(this, 13, e); }), (proto.mediapipe.ProfilerConfig.prototype.getTraceLogIntervalCount = function() { return t.Message.getFieldWithDefault(this, 14, 0); }), (proto.mediapipe.ProfilerConfig.prototype.setTraceLogIntervalCount = function(e) { return t.Message.setProto3IntField(this, 14, e); }), (proto.mediapipe.ProfilerConfig.prototype.getTraceLogDisabled = function() { return t.Message.getBooleanFieldWithDefault(this, 15, !1); }), (proto.mediapipe.ProfilerConfig.prototype.setTraceLogDisabled = function(e) { return t.Message.setProto3BooleanField(this, 15, e); }), (proto.mediapipe.ProfilerConfig.prototype.getTraceEnabled = function() { return t.Message.getBooleanFieldWithDefault(this, 16, !1); }), (proto.mediapipe.ProfilerConfig.prototype.setTraceEnabled = function(e) { return t.Message.setProto3BooleanField(this, 16, e); }), (proto.mediapipe.ProfilerConfig.prototype.getTraceLogInstantEvents = function() { return t.Message.getBooleanFieldWithDefault(this, 17, !1); }), (proto.mediapipe.ProfilerConfig.prototype.setTraceLogInstantEvents = function(e) { return t.Message.setProto3BooleanField(this, 17, e); }), (proto.mediapipe.ProfilerConfig.prototype.getCalculatorFilter = function() { return t.Message.getFieldWithDefault(this, 18, ''); }), (proto.mediapipe.ProfilerConfig.prototype.setCalculatorFilter = function(e) { return t.Message.setProto3StringField(this, 18, e); }), (proto.mediapipe.CalculatorGraphConfig.repeatedFields_ = [ 1, 6, 7, 9, 10, 15, 16, 17, 14, 1002, ]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.CalculatorGraphConfig.prototype.toObject = function(e) { return proto.mediapipe.CalculatorGraphConfig.toObject(e, this); }), (proto.mediapipe.CalculatorGraphConfig.toObject = function(e, r) { var o, i = { nodeList: t.Message.toObjectList( r.getNodeList(), proto.mediapipe.CalculatorGraphConfig.Node.toObject, e ), packetFactoryList: t.Message.toObjectList( r.getPacketFactoryList(), s.PacketFactoryConfig.toObject, e ), packetGeneratorList: t.Message.toObjectList( r.getPacketGeneratorList(), p.PacketGeneratorConfig.toObject, e ), numThreads: t.Message.getFieldWithDefault(r, 8, 0), statusHandlerList: t.Message.toObjectList( r.getStatusHandlerList(), d.StatusHandlerConfig.toObject, e ), inputStreamList: null == (o = t.Message.getRepeatedField(r, 10)) ? void 0 : o, outputStreamList: null == (o = t.Message.getRepeatedField(r, 15)) ? void 0 : o, inputSidePacketList: null == (o = t.Message.getRepeatedField(r, 16)) ? void 0 : o, outputSidePacketList: null == (o = t.Message.getRepeatedField(r, 17)) ? void 0 : o, maxQueueSize: t.Message.getFieldWithDefault(r, 11, 0), reportDeadlock: t.Message.getBooleanFieldWithDefault(r, 21, !1), inputStreamHandler: (o = r.getInputStreamHandler()) && l.InputStreamHandlerConfig.toObject(e, o), outputStreamHandler: (o = r.getOutputStreamHandler()) && l.OutputStreamHandlerConfig.toObject(e, o), executorList: t.Message.toObjectList( r.getExecutorList(), proto.mediapipe.ExecutorConfig.toObject, e ), profilerConfig: (o = r.getProfilerConfig()) && proto.mediapipe.ProfilerConfig.toObject(e, o), pb_package: t.Message.getFieldWithDefault(r, 19, ''), type: t.Message.getFieldWithDefault(r, 20, ''), options: (o = r.getOptions()) && n.MediaPipeOptions.toObject(e, o), graphOptionsList: t.Message.toObjectList( r.getGraphOptionsList(), a.Any.toObject, e ), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.CalculatorGraphConfig.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.CalculatorGraphConfig(); return proto.mediapipe.CalculatorGraphConfig.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.CalculatorGraphConfig.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new proto.mediapipe.CalculatorGraphConfig.Node(); t.readMessage( r, proto.mediapipe.CalculatorGraphConfig.Node .deserializeBinaryFromReader ), e.addNode(r); break; case 6: r = new s.PacketFactoryConfig(); t.readMessage(r, s.PacketFactoryConfig.deserializeBinaryFromReader), e.addPacketFactory(r); break; case 7: r = new p.PacketGeneratorConfig(); t.readMessage(r, p.PacketGeneratorConfig.deserializeBinaryFromReader), e.addPacketGenerator(r); break; case 8: r = t.readInt32(); e.setNumThreads(r); break; case 9: r = new d.StatusHandlerConfig(); t.readMessage(r, d.StatusHandlerConfig.deserializeBinaryFromReader), e.addStatusHandler(r); break; case 10: r = t.readString(); e.addInputStream(r); break; case 15: r = t.readString(); e.addOutputStream(r); break; case 16: r = t.readString(); e.addInputSidePacket(r); break; case 17: r = t.readString(); e.addOutputSidePacket(r); break; case 11: r = t.readInt32(); e.setMaxQueueSize(r); break; case 21: r = t.readBool(); e.setReportDeadlock(r); break; case 12: r = new l.InputStreamHandlerConfig(); t.readMessage( r, l.InputStreamHandlerConfig.deserializeBinaryFromReader ), e.setInputStreamHandler(r); break; case 13: r = new l.OutputStreamHandlerConfig(); t.readMessage( r, l.OutputStreamHandlerConfig.deserializeBinaryFromReader ), e.setOutputStreamHandler(r); break; case 14: r = new proto.mediapipe.ExecutorConfig(); t.readMessage( r, proto.mediapipe.ExecutorConfig.deserializeBinaryFromReader ), e.addExecutor(r); break; case 18: r = new proto.mediapipe.ProfilerConfig(); t.readMessage( r, proto.mediapipe.ProfilerConfig.deserializeBinaryFromReader ), e.setProfilerConfig(r); break; case 19: r = t.readString(); e.setPackage(r); break; case 20: r = t.readString(); e.setType(r); break; case 1001: r = new n.MediaPipeOptions(); t.readMessage(r, n.MediaPipeOptions.deserializeBinaryFromReader), e.setOptions(r); break; case 1002: r = new a.Any(); t.readMessage(r, a.Any.deserializeBinaryFromReader), e.addGraphOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.CalculatorGraphConfig.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.CalculatorGraphConfig.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.CalculatorGraphConfig.serializeBinaryToWriter = function(e, t) { var r = void 0; (r = e.getNodeList()).length > 0 && t.writeRepeatedMessage( 1, r, proto.mediapipe.CalculatorGraphConfig.Node.serializeBinaryToWriter ), (r = e.getPacketFactoryList()).length > 0 && t.writeRepeatedMessage(6, r, s.PacketFactoryConfig.serializeBinaryToWriter), (r = e.getPacketGeneratorList()).length > 0 && t.writeRepeatedMessage( 7, r, p.PacketGeneratorConfig.serializeBinaryToWriter ), 0 !== (r = e.getNumThreads()) && t.writeInt32(8, r), (r = e.getStatusHandlerList()).length > 0 && t.writeRepeatedMessage(9, r, d.StatusHandlerConfig.serializeBinaryToWriter), (r = e.getInputStreamList()).length > 0 && t.writeRepeatedString(10, r), (r = e.getOutputStreamList()).length > 0 && t.writeRepeatedString(15, r), (r = e.getInputSidePacketList()).length > 0 && t.writeRepeatedString(16, r), (r = e.getOutputSidePacketList()).length > 0 && t.writeRepeatedString(17, r), 0 !== (r = e.getMaxQueueSize()) && t.writeInt32(11, r), (r = e.getReportDeadlock()) && t.writeBool(21, r), null != (r = e.getInputStreamHandler()) && t.writeMessage(12, r, l.InputStreamHandlerConfig.serializeBinaryToWriter), null != (r = e.getOutputStreamHandler()) && t.writeMessage(13, r, l.OutputStreamHandlerConfig.serializeBinaryToWriter), (r = e.getExecutorList()).length > 0 && t.writeRepeatedMessage( 14, r, proto.mediapipe.ExecutorConfig.serializeBinaryToWriter ), null != (r = e.getProfilerConfig()) && t.writeMessage( 18, r, proto.mediapipe.ProfilerConfig.serializeBinaryToWriter ), (r = e.getPackage()).length > 0 && t.writeString(19, r), (r = e.getType()).length > 0 && t.writeString(20, r), null != (r = e.getOptions()) && t.writeMessage(1001, r, n.MediaPipeOptions.serializeBinaryToWriter), (r = e.getGraphOptionsList()).length > 0 && t.writeRepeatedMessage(1002, r, a.Any.serializeBinaryToWriter); }), (proto.mediapipe.CalculatorGraphConfig.Node.repeatedFields_ = [ 3, 4, 5, 6, 8, 13, 17, 1005, ]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.CalculatorGraphConfig.Node.prototype.toObject = function(e) { return proto.mediapipe.CalculatorGraphConfig.Node.toObject(e, this); }), (proto.mediapipe.CalculatorGraphConfig.Node.toObject = function(e, r) { var o, n = { name: t.Message.getFieldWithDefault(r, 1, ''), calculator: t.Message.getFieldWithDefault(r, 2, ''), inputStreamList: null == (o = t.Message.getRepeatedField(r, 3)) ? void 0 : o, outputStreamList: null == (o = t.Message.getRepeatedField(r, 4)) ? void 0 : o, inputSidePacketList: null == (o = t.Message.getRepeatedField(r, 5)) ? void 0 : o, outputSidePacketList: null == (o = t.Message.getRepeatedField(r, 6)) ? void 0 : o, options: (o = r.getOptions()) && i.CalculatorOptions.toObject(e, o), nodeOptionsList: t.Message.toObjectList( r.getNodeOptionsList(), a.Any.toObject, e ), sourceLayer: t.Message.getFieldWithDefault(r, 9, 0), bufferSizeHint: t.Message.getFieldWithDefault(r, 10, 0), inputStreamHandler: (o = r.getInputStreamHandler()) && l.InputStreamHandlerConfig.toObject(e, o), outputStreamHandler: (o = r.getOutputStreamHandler()) && l.OutputStreamHandlerConfig.toObject(e, o), inputStreamInfoList: t.Message.toObjectList( r.getInputStreamInfoList(), proto.mediapipe.InputStreamInfo.toObject, e ), executor: t.Message.getFieldWithDefault(r, 14, ''), profilerConfig: (o = r.getProfilerConfig()) && proto.mediapipe.ProfilerConfig.toObject(e, o), maxInFlight: t.Message.getFieldWithDefault(r, 16, 0), optionValueList: null == (o = t.Message.getRepeatedField(r, 17)) ? void 0 : o, externalInputList: null == (o = t.Message.getRepeatedField(r, 1005)) ? void 0 : o, }; return e && (n.$jspbMessageInstance = r), n; })), (proto.mediapipe.CalculatorGraphConfig.Node.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.CalculatorGraphConfig.Node(); return proto.mediapipe.CalculatorGraphConfig.Node.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.CalculatorGraphConfig.Node.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setName(r); break; case 2: r = t.readString(); e.setCalculator(r); break; case 3: r = t.readString(); e.addInputStream(r); break; case 4: r = t.readString(); e.addOutputStream(r); break; case 5: r = t.readString(); e.addInputSidePacket(r); break; case 6: r = t.readString(); e.addOutputSidePacket(r); break; case 7: r = new i.CalculatorOptions(); t.readMessage(r, i.CalculatorOptions.deserializeBinaryFromReader), e.setOptions(r); break; case 8: r = new a.Any(); t.readMessage(r, a.Any.deserializeBinaryFromReader), e.addNodeOptions(r); break; case 9: r = t.readInt32(); e.setSourceLayer(r); break; case 10: r = t.readInt32(); e.setBufferSizeHint(r); break; case 11: r = new l.InputStreamHandlerConfig(); t.readMessage( r, l.InputStreamHandlerConfig.deserializeBinaryFromReader ), e.setInputStreamHandler(r); break; case 12: r = new l.OutputStreamHandlerConfig(); t.readMessage( r, l.OutputStreamHandlerConfig.deserializeBinaryFromReader ), e.setOutputStreamHandler(r); break; case 13: r = new proto.mediapipe.InputStreamInfo(); t.readMessage( r, proto.mediapipe.InputStreamInfo.deserializeBinaryFromReader ), e.addInputStreamInfo(r); break; case 14: r = t.readString(); e.setExecutor(r); break; case 15: r = new proto.mediapipe.ProfilerConfig(); t.readMessage( r, proto.mediapipe.ProfilerConfig.deserializeBinaryFromReader ), e.setProfilerConfig(r); break; case 16: r = t.readInt32(); e.setMaxInFlight(r); break; case 17: r = t.readString(); e.addOptionValue(r); break; case 1005: r = t.readString(); e.addExternalInput(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.CalculatorGraphConfig.Node.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.CalculatorGraphConfig.Node.serializeBinaryToWriter = function(e, t) { var r = void 0; (r = e.getName()).length > 0 && t.writeString(1, r), (r = e.getCalculator()).length > 0 && t.writeString(2, r), (r = e.getInputStreamList()).length > 0 && t.writeRepeatedString(3, r), (r = e.getOutputStreamList()).length > 0 && t.writeRepeatedString(4, r), (r = e.getInputSidePacketList()).length > 0 && t.writeRepeatedString(5, r), (r = e.getOutputSidePacketList()).length > 0 && t.writeRepeatedString(6, r), null != (r = e.getOptions()) && t.writeMessage(7, r, i.CalculatorOptions.serializeBinaryToWriter), (r = e.getNodeOptionsList()).length > 0 && t.writeRepeatedMessage(8, r, a.Any.serializeBinaryToWriter), 0 !== (r = e.getSourceLayer()) && t.writeInt32(9, r), 0 !== (r = e.getBufferSizeHint()) && t.writeInt32(10, r), null != (r = e.getInputStreamHandler()) && t.writeMessage(11, r, l.InputStreamHandlerConfig.serializeBinaryToWriter), null != (r = e.getOutputStreamHandler()) && t.writeMessage(12, r, l.OutputStreamHandlerConfig.serializeBinaryToWriter), (r = e.getInputStreamInfoList()).length > 0 && t.writeRepeatedMessage( 13, r, proto.mediapipe.InputStreamInfo.serializeBinaryToWriter ), (r = e.getExecutor()).length > 0 && t.writeString(14, r), null != (r = e.getProfilerConfig()) && t.writeMessage( 15, r, proto.mediapipe.ProfilerConfig.serializeBinaryToWriter ), 0 !== (r = e.getMaxInFlight()) && t.writeInt32(16, r), (r = e.getOptionValueList()).length > 0 && t.writeRepeatedString(17, r), (r = e.getExternalInputList()).length > 0 && t.writeRepeatedString(1005, r); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getName = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setName = function(e) { return t.Message.setProto3StringField(this, 1, e); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getCalculator = function() { return t.Message.getFieldWithDefault(this, 2, ''); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setCalculator = function(e) { return t.Message.setProto3StringField(this, 2, e); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getInputStreamList = function() { return t.Message.getRepeatedField(this, 3); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setInputStreamList = function(e) { return t.Message.setField(this, 3, e || []); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.addInputStream = function(e, r) { return t.Message.addToRepeatedField(this, 3, e, r); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.clearInputStreamList = function() { return this.setInputStreamList([]); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getOutputStreamList = function() { return t.Message.getRepeatedField(this, 4); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setOutputStreamList = function( e ) { return t.Message.setField(this, 4, e || []); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.addOutputStream = function(e, r) { return t.Message.addToRepeatedField(this, 4, e, r); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.clearOutputStreamList = function() { return this.setOutputStreamList([]); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getInputSidePacketList = function() { return t.Message.getRepeatedField(this, 5); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setInputSidePacketList = function( e ) { return t.Message.setField(this, 5, e || []); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.addInputSidePacket = function( e, r ) { return t.Message.addToRepeatedField(this, 5, e, r); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.clearInputSidePacketList = function() { return this.setInputSidePacketList([]); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getOutputSidePacketList = function() { return t.Message.getRepeatedField(this, 6); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setOutputSidePacketList = function( e ) { return t.Message.setField(this, 6, e || []); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.addOutputSidePacket = function( e, r ) { return t.Message.addToRepeatedField(this, 6, e, r); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.clearOutputSidePacketList = function() { return this.setOutputSidePacketList([]); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getOptions = function() { return t.Message.getWrapperField(this, i.CalculatorOptions, 7); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setOptions = function(e) { return t.Message.setWrapperField(this, 7, e); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.clearOptions = function() { return this.setOptions(void 0); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.hasOptions = function() { return null != t.Message.getField(this, 7); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getNodeOptionsList = function() { return t.Message.getRepeatedWrapperField(this, a.Any, 8); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setNodeOptionsList = function(e) { return t.Message.setRepeatedWrapperField(this, 8, e); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.addNodeOptions = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 8, e, proto.google.protobuf.Any, r ); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.clearNodeOptionsList = function() { return this.setNodeOptionsList([]); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getSourceLayer = function() { return t.Message.getFieldWithDefault(this, 9, 0); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setSourceLayer = function(e) { return t.Message.setProto3IntField(this, 9, e); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getBufferSizeHint = function() { return t.Message.getFieldWithDefault(this, 10, 0); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setBufferSizeHint = function(e) { return t.Message.setProto3IntField(this, 10, e); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getInputStreamHandler = function() { return t.Message.getWrapperField(this, l.InputStreamHandlerConfig, 11); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setInputStreamHandler = function( e ) { return t.Message.setWrapperField(this, 11, e); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.clearInputStreamHandler = function() { return this.setInputStreamHandler(void 0); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.hasInputStreamHandler = function() { return null != t.Message.getField(this, 11); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getOutputStreamHandler = function() { return t.Message.getWrapperField(this, l.OutputStreamHandlerConfig, 12); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setOutputStreamHandler = function( e ) { return t.Message.setWrapperField(this, 12, e); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.clearOutputStreamHandler = function() { return this.setOutputStreamHandler(void 0); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.hasOutputStreamHandler = function() { return null != t.Message.getField(this, 12); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getInputStreamInfoList = function() { return t.Message.getRepeatedWrapperField(this, proto.mediapipe.InputStreamInfo, 13); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setInputStreamInfoList = function( e ) { return t.Message.setRepeatedWrapperField(this, 13, e); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.addInputStreamInfo = function( e, r ) { return t.Message.addToRepeatedWrapperField( this, 13, e, proto.mediapipe.InputStreamInfo, r ); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.clearInputStreamInfoList = function() { return this.setInputStreamInfoList([]); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getExecutor = function() { return t.Message.getFieldWithDefault(this, 14, ''); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setExecutor = function(e) { return t.Message.setProto3StringField(this, 14, e); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getProfilerConfig = function() { return t.Message.getWrapperField(this, proto.mediapipe.ProfilerConfig, 15); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setProfilerConfig = function(e) { return t.Message.setWrapperField(this, 15, e); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.clearProfilerConfig = function() { return this.setProfilerConfig(void 0); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.hasProfilerConfig = function() { return null != t.Message.getField(this, 15); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getMaxInFlight = function() { return t.Message.getFieldWithDefault(this, 16, 0); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setMaxInFlight = function(e) { return t.Message.setProto3IntField(this, 16, e); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getOptionValueList = function() { return t.Message.getRepeatedField(this, 17); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setOptionValueList = function(e) { return t.Message.setField(this, 17, e || []); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.addOptionValue = function(e, r) { return t.Message.addToRepeatedField(this, 17, e, r); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.clearOptionValueList = function() { return this.setOptionValueList([]); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.getExternalInputList = function() { return t.Message.getRepeatedField(this, 1005); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.setExternalInputList = function( e ) { return t.Message.setField(this, 1005, e || []); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.addExternalInput = function( e, r ) { return t.Message.addToRepeatedField(this, 1005, e, r); }), (proto.mediapipe.CalculatorGraphConfig.Node.prototype.clearExternalInputList = function() { return this.setExternalInputList([]); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getNodeList = function() { return t.Message.getRepeatedWrapperField( this, proto.mediapipe.CalculatorGraphConfig.Node, 1 ); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setNodeList = function(e) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.addNode = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.CalculatorGraphConfig.Node, r ); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearNodeList = function() { return this.setNodeList([]); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getPacketFactoryList = function() { return t.Message.getRepeatedWrapperField(this, s.PacketFactoryConfig, 6); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setPacketFactoryList = function(e) { return t.Message.setRepeatedWrapperField(this, 6, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.addPacketFactory = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 6, e, proto.mediapipe.PacketFactoryConfig, r ); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearPacketFactoryList = function() { return this.setPacketFactoryList([]); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getPacketGeneratorList = function() { return t.Message.getRepeatedWrapperField(this, p.PacketGeneratorConfig, 7); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setPacketGeneratorList = function(e) { return t.Message.setRepeatedWrapperField(this, 7, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.addPacketGenerator = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 7, e, proto.mediapipe.PacketGeneratorConfig, r ); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearPacketGeneratorList = function() { return this.setPacketGeneratorList([]); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getNumThreads = function() { return t.Message.getFieldWithDefault(this, 8, 0); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setNumThreads = function(e) { return t.Message.setProto3IntField(this, 8, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getStatusHandlerList = function() { return t.Message.getRepeatedWrapperField(this, d.StatusHandlerConfig, 9); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setStatusHandlerList = function(e) { return t.Message.setRepeatedWrapperField(this, 9, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.addStatusHandler = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 9, e, proto.mediapipe.StatusHandlerConfig, r ); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearStatusHandlerList = function() { return this.setStatusHandlerList([]); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getInputStreamList = function() { return t.Message.getRepeatedField(this, 10); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setInputStreamList = function(e) { return t.Message.setField(this, 10, e || []); }), (proto.mediapipe.CalculatorGraphConfig.prototype.addInputStream = function(e, r) { return t.Message.addToRepeatedField(this, 10, e, r); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearInputStreamList = function() { return this.setInputStreamList([]); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getOutputStreamList = function() { return t.Message.getRepeatedField(this, 15); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setOutputStreamList = function(e) { return t.Message.setField(this, 15, e || []); }), (proto.mediapipe.CalculatorGraphConfig.prototype.addOutputStream = function(e, r) { return t.Message.addToRepeatedField(this, 15, e, r); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearOutputStreamList = function() { return this.setOutputStreamList([]); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getInputSidePacketList = function() { return t.Message.getRepeatedField(this, 16); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setInputSidePacketList = function(e) { return t.Message.setField(this, 16, e || []); }), (proto.mediapipe.CalculatorGraphConfig.prototype.addInputSidePacket = function(e, r) { return t.Message.addToRepeatedField(this, 16, e, r); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearInputSidePacketList = function() { return this.setInputSidePacketList([]); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getOutputSidePacketList = function() { return t.Message.getRepeatedField(this, 17); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setOutputSidePacketList = function(e) { return t.Message.setField(this, 17, e || []); }), (proto.mediapipe.CalculatorGraphConfig.prototype.addOutputSidePacket = function(e, r) { return t.Message.addToRepeatedField(this, 17, e, r); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearOutputSidePacketList = function() { return this.setOutputSidePacketList([]); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getMaxQueueSize = function() { return t.Message.getFieldWithDefault(this, 11, 0); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setMaxQueueSize = function(e) { return t.Message.setProto3IntField(this, 11, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getReportDeadlock = function() { return t.Message.getBooleanFieldWithDefault(this, 21, !1); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setReportDeadlock = function(e) { return t.Message.setProto3BooleanField(this, 21, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getInputStreamHandler = function() { return t.Message.getWrapperField(this, l.InputStreamHandlerConfig, 12); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setInputStreamHandler = function(e) { return t.Message.setWrapperField(this, 12, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearInputStreamHandler = function() { return this.setInputStreamHandler(void 0); }), (proto.mediapipe.CalculatorGraphConfig.prototype.hasInputStreamHandler = function() { return null != t.Message.getField(this, 12); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getOutputStreamHandler = function() { return t.Message.getWrapperField(this, l.OutputStreamHandlerConfig, 13); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setOutputStreamHandler = function(e) { return t.Message.setWrapperField(this, 13, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearOutputStreamHandler = function() { return this.setOutputStreamHandler(void 0); }), (proto.mediapipe.CalculatorGraphConfig.prototype.hasOutputStreamHandler = function() { return null != t.Message.getField(this, 13); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getExecutorList = function() { return t.Message.getRepeatedWrapperField(this, proto.mediapipe.ExecutorConfig, 14); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setExecutorList = function(e) { return t.Message.setRepeatedWrapperField(this, 14, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.addExecutor = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 14, e, proto.mediapipe.ExecutorConfig, r ); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearExecutorList = function() { return this.setExecutorList([]); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getProfilerConfig = function() { return t.Message.getWrapperField(this, proto.mediapipe.ProfilerConfig, 18); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setProfilerConfig = function(e) { return t.Message.setWrapperField(this, 18, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearProfilerConfig = function() { return this.setProfilerConfig(void 0); }), (proto.mediapipe.CalculatorGraphConfig.prototype.hasProfilerConfig = function() { return null != t.Message.getField(this, 18); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getPackage = function() { return t.Message.getFieldWithDefault(this, 19, ''); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setPackage = function(e) { return t.Message.setProto3StringField(this, 19, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getType = function() { return t.Message.getFieldWithDefault(this, 20, ''); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setType = function(e) { return t.Message.setProto3StringField(this, 20, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getOptions = function() { return t.Message.getWrapperField(this, n.MediaPipeOptions, 1001); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setOptions = function(e) { return t.Message.setWrapperField(this, 1001, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearOptions = function() { return this.setOptions(void 0); }), (proto.mediapipe.CalculatorGraphConfig.prototype.hasOptions = function() { return null != t.Message.getField(this, 1001); }), (proto.mediapipe.CalculatorGraphConfig.prototype.getGraphOptionsList = function() { return t.Message.getRepeatedWrapperField(this, a.Any, 1002); }), (proto.mediapipe.CalculatorGraphConfig.prototype.setGraphOptionsList = function(e) { return t.Message.setRepeatedWrapperField(this, 1002, e); }), (proto.mediapipe.CalculatorGraphConfig.prototype.addGraphOptions = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 1002, e, proto.google.protobuf.Any, r ); }), (proto.mediapipe.CalculatorGraphConfig.prototype.clearGraphOptionsList = function() { return this.setGraphOptionsList([]); }), r.object.extend(e, proto.mediapipe); })(calculator_pb); var detection_pb = {}, location_data_pb = {}, rasterization_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.Rasterization', null, o), r.exportSymbol('proto.mediapipe.Rasterization.Interval', null, o), (proto.mediapipe.Rasterization = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.Rasterization.repeatedFields_, null ); }), r.inherits(proto.mediapipe.Rasterization, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.Rasterization.displayName = 'proto.mediapipe.Rasterization'), (proto.mediapipe.Rasterization.Interval = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.Rasterization.Interval, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.Rasterization.Interval.displayName = 'proto.mediapipe.Rasterization.Interval'), (proto.mediapipe.Rasterization.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.Rasterization.prototype.toObject = function(e) { return proto.mediapipe.Rasterization.toObject(e, this); }), (proto.mediapipe.Rasterization.toObject = function(e, r) { var o = { intervalList: t.Message.toObjectList( r.getIntervalList(), proto.mediapipe.Rasterization.Interval.toObject, e ), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.Rasterization.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.Rasterization(); return proto.mediapipe.Rasterization.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.Rasterization.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new proto.mediapipe.Rasterization.Interval(); t.readMessage( r, proto.mediapipe.Rasterization.Interval.deserializeBinaryFromReader ), e.addInterval(r); } else t.skipField(); } return e; }), (proto.mediapipe.Rasterization.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.Rasterization.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.Rasterization.serializeBinaryToWriter = function(e, t) { var r; (r = e.getIntervalList()).length > 0 && t.writeRepeatedMessage( 1, r, proto.mediapipe.Rasterization.Interval.serializeBinaryToWriter ); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.Rasterization.Interval.prototype.toObject = function(e) { return proto.mediapipe.Rasterization.Interval.toObject(e, this); }), (proto.mediapipe.Rasterization.Interval.toObject = function(e, r) { var o, i = { y: null == (o = t.Message.getField(r, 1)) ? void 0 : o, leftX: null == (o = t.Message.getField(r, 2)) ? void 0 : o, rightX: null == (o = t.Message.getField(r, 3)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.Rasterization.Interval.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.Rasterization.Interval(); return proto.mediapipe.Rasterization.Interval.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.Rasterization.Interval.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readInt32(); e.setY(r); break; case 2: r = t.readInt32(); e.setLeftX(r); break; case 3: r = t.readInt32(); e.setRightX(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.Rasterization.Interval.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.Rasterization.Interval.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.Rasterization.Interval.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeInt32(1, o), null != (o = t.Message.getField(e, 2)) && r.writeInt32(2, o), null != (o = t.Message.getField(e, 3)) && r.writeInt32(3, o); }), (proto.mediapipe.Rasterization.Interval.prototype.getY = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.Rasterization.Interval.prototype.setY = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.Rasterization.Interval.prototype.clearY = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.Rasterization.Interval.prototype.hasY = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.Rasterization.Interval.prototype.getLeftX = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.Rasterization.Interval.prototype.setLeftX = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.Rasterization.Interval.prototype.clearLeftX = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.Rasterization.Interval.prototype.hasLeftX = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.Rasterization.Interval.prototype.getRightX = function() { return t.Message.getFieldWithDefault(this, 3, 0); }), (proto.mediapipe.Rasterization.Interval.prototype.setRightX = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.Rasterization.Interval.prototype.clearRightX = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.Rasterization.Interval.prototype.hasRightX = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.Rasterization.prototype.getIntervalList = function() { return t.Message.getRepeatedWrapperField( this, proto.mediapipe.Rasterization.Interval, 1 ); }), (proto.mediapipe.Rasterization.prototype.setIntervalList = function(e) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.Rasterization.prototype.addInterval = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.Rasterization.Interval, r ); }), (proto.mediapipe.Rasterization.prototype.clearIntervalList = function() { return this.setIntervalList([]); }), r.object.extend(e, proto.mediapipe); })(rasterization_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = rasterization_pb; r.object.extend(proto, i), r.exportSymbol('proto.mediapipe.LocationData', null, o), r.exportSymbol('proto.mediapipe.LocationData.BinaryMask', null, o), r.exportSymbol('proto.mediapipe.LocationData.BoundingBox', null, o), r.exportSymbol('proto.mediapipe.LocationData.Format', null, o), r.exportSymbol('proto.mediapipe.LocationData.RelativeBoundingBox', null, o), r.exportSymbol('proto.mediapipe.LocationData.RelativeKeypoint', null, o), (proto.mediapipe.LocationData = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.LocationData.repeatedFields_, null ); }), r.inherits(proto.mediapipe.LocationData, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.LocationData.displayName = 'proto.mediapipe.LocationData'), (proto.mediapipe.LocationData.BoundingBox = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.LocationData.BoundingBox, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.LocationData.BoundingBox.displayName = 'proto.mediapipe.LocationData.BoundingBox'), (proto.mediapipe.LocationData.RelativeBoundingBox = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.LocationData.RelativeBoundingBox, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.LocationData.RelativeBoundingBox.displayName = 'proto.mediapipe.LocationData.RelativeBoundingBox'), (proto.mediapipe.LocationData.BinaryMask = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.LocationData.BinaryMask, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.LocationData.BinaryMask.displayName = 'proto.mediapipe.LocationData.BinaryMask'), (proto.mediapipe.LocationData.RelativeKeypoint = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.LocationData.RelativeKeypoint, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.LocationData.RelativeKeypoint.displayName = 'proto.mediapipe.LocationData.RelativeKeypoint'), (proto.mediapipe.LocationData.repeatedFields_ = [5]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.LocationData.prototype.toObject = function(e) { return proto.mediapipe.LocationData.toObject(e, this); }), (proto.mediapipe.LocationData.toObject = function(e, r) { var o, i = { format: null == (o = t.Message.getField(r, 1)) ? void 0 : o, boundingBox: (o = r.getBoundingBox()) && proto.mediapipe.LocationData.BoundingBox.toObject(e, o), relativeBoundingBox: (o = r.getRelativeBoundingBox()) && proto.mediapipe.LocationData.RelativeBoundingBox.toObject(e, o), mask: (o = r.getMask()) && proto.mediapipe.LocationData.BinaryMask.toObject(e, o), relativeKeypointsList: t.Message.toObjectList( r.getRelativeKeypointsList(), proto.mediapipe.LocationData.RelativeKeypoint.toObject, e ), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.LocationData.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.LocationData(); return proto.mediapipe.LocationData.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.LocationData.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readEnum(); e.setFormat(r); break; case 2: r = new proto.mediapipe.LocationData.BoundingBox(); t.readMessage( r, proto.mediapipe.LocationData.BoundingBox.deserializeBinaryFromReader ), e.setBoundingBox(r); break; case 3: r = new proto.mediapipe.LocationData.RelativeBoundingBox(); t.readMessage( r, proto.mediapipe.LocationData.RelativeBoundingBox .deserializeBinaryFromReader ), e.setRelativeBoundingBox(r); break; case 4: r = new proto.mediapipe.LocationData.BinaryMask(); t.readMessage( r, proto.mediapipe.LocationData.BinaryMask.deserializeBinaryFromReader ), e.setMask(r); break; case 5: r = new proto.mediapipe.LocationData.RelativeKeypoint(); t.readMessage( r, proto.mediapipe.LocationData.RelativeKeypoint .deserializeBinaryFromReader ), e.addRelativeKeypoints(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.LocationData.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.LocationData.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.LocationData.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeEnum(1, o), null != (o = e.getBoundingBox()) && r.writeMessage( 2, o, proto.mediapipe.LocationData.BoundingBox.serializeBinaryToWriter ), null != (o = e.getRelativeBoundingBox()) && r.writeMessage( 3, o, proto.mediapipe.LocationData.RelativeBoundingBox.serializeBinaryToWriter ), null != (o = e.getMask()) && r.writeMessage( 4, o, proto.mediapipe.LocationData.BinaryMask.serializeBinaryToWriter ), (o = e.getRelativeKeypointsList()).length > 0 && r.writeRepeatedMessage( 5, o, proto.mediapipe.LocationData.RelativeKeypoint.serializeBinaryToWriter ); }), (proto.mediapipe.LocationData.Format = { GLOBAL: 0, BOUNDING_BOX: 1, RELATIVE_BOUNDING_BOX: 2, MASK: 3, }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.LocationData.BoundingBox.prototype.toObject = function(e) { return proto.mediapipe.LocationData.BoundingBox.toObject(e, this); }), (proto.mediapipe.LocationData.BoundingBox.toObject = function(e, r) { var o, i = { xmin: null == (o = t.Message.getField(r, 1)) ? void 0 : o, ymin: null == (o = t.Message.getField(r, 2)) ? void 0 : o, width: null == (o = t.Message.getField(r, 3)) ? void 0 : o, height: null == (o = t.Message.getField(r, 4)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.LocationData.BoundingBox.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.LocationData.BoundingBox(); return proto.mediapipe.LocationData.BoundingBox.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.LocationData.BoundingBox.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readInt32(); e.setXmin(r); break; case 2: r = t.readInt32(); e.setYmin(r); break; case 3: r = t.readInt32(); e.setWidth(r); break; case 4: r = t.readInt32(); e.setHeight(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.LocationData.BoundingBox.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.LocationData.BoundingBox.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.LocationData.BoundingBox.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeInt32(1, o), null != (o = t.Message.getField(e, 2)) && r.writeInt32(2, o), null != (o = t.Message.getField(e, 3)) && r.writeInt32(3, o), null != (o = t.Message.getField(e, 4)) && r.writeInt32(4, o); }), (proto.mediapipe.LocationData.BoundingBox.prototype.getXmin = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.LocationData.BoundingBox.prototype.setXmin = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.LocationData.BoundingBox.prototype.clearXmin = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.LocationData.BoundingBox.prototype.hasXmin = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.LocationData.BoundingBox.prototype.getYmin = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.LocationData.BoundingBox.prototype.setYmin = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.LocationData.BoundingBox.prototype.clearYmin = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.LocationData.BoundingBox.prototype.hasYmin = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.LocationData.BoundingBox.prototype.getWidth = function() { return t.Message.getFieldWithDefault(this, 3, 0); }), (proto.mediapipe.LocationData.BoundingBox.prototype.setWidth = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.LocationData.BoundingBox.prototype.clearWidth = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.LocationData.BoundingBox.prototype.hasWidth = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.LocationData.BoundingBox.prototype.getHeight = function() { return t.Message.getFieldWithDefault(this, 4, 0); }), (proto.mediapipe.LocationData.BoundingBox.prototype.setHeight = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.LocationData.BoundingBox.prototype.clearHeight = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.LocationData.BoundingBox.prototype.hasHeight = function() { return null != t.Message.getField(this, 4); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.LocationData.RelativeBoundingBox.prototype.toObject = function( e ) { return proto.mediapipe.LocationData.RelativeBoundingBox.toObject(e, this); }), (proto.mediapipe.LocationData.RelativeBoundingBox.toObject = function(e, r) { var o, i = { xmin: null == (o = t.Message.getOptionalFloatingPointField(r, 1)) ? void 0 : o, ymin: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, width: null == (o = t.Message.getOptionalFloatingPointField(r, 3)) ? void 0 : o, height: null == (o = t.Message.getOptionalFloatingPointField(r, 4)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.LocationData.RelativeBoundingBox.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.LocationData.RelativeBoundingBox(); return proto.mediapipe.LocationData.RelativeBoundingBox.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.LocationData.RelativeBoundingBox.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readFloat(); e.setXmin(r); break; case 2: r = t.readFloat(); e.setYmin(r); break; case 3: r = t.readFloat(); e.setWidth(r); break; case 4: r = t.readFloat(); e.setHeight(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.LocationData.RelativeBoundingBox.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.LocationData.RelativeBoundingBox.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeFloat(1, o), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o), null != (o = t.Message.getField(e, 3)) && r.writeFloat(3, o), null != (o = t.Message.getField(e, 4)) && r.writeFloat(4, o); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.getXmin = function() { return t.Message.getFloatingPointFieldWithDefault(this, 1, 0); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.setXmin = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.clearXmin = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.hasXmin = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.getYmin = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.setYmin = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.clearYmin = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.hasYmin = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.getWidth = function() { return t.Message.getFloatingPointFieldWithDefault(this, 3, 0); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.setWidth = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.clearWidth = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.hasWidth = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.getHeight = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.setHeight = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.clearHeight = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.LocationData.RelativeBoundingBox.prototype.hasHeight = function() { return null != t.Message.getField(this, 4); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.LocationData.BinaryMask.prototype.toObject = function(e) { return proto.mediapipe.LocationData.BinaryMask.toObject(e, this); }), (proto.mediapipe.LocationData.BinaryMask.toObject = function(e, r) { var o, a = { width: null == (o = t.Message.getField(r, 1)) ? void 0 : o, height: null == (o = t.Message.getField(r, 2)) ? void 0 : o, rasterization: (o = r.getRasterization()) && i.Rasterization.toObject(e, o), }; return e && (a.$jspbMessageInstance = r), a; })), (proto.mediapipe.LocationData.BinaryMask.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.LocationData.BinaryMask(); return proto.mediapipe.LocationData.BinaryMask.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.LocationData.BinaryMask.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readInt32(); e.setWidth(r); break; case 2: r = t.readInt32(); e.setHeight(r); break; case 3: r = new i.Rasterization(); t.readMessage(r, i.Rasterization.deserializeBinaryFromReader), e.setRasterization(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.LocationData.BinaryMask.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.LocationData.BinaryMask.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.LocationData.BinaryMask.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeInt32(1, o), null != (o = t.Message.getField(e, 2)) && r.writeInt32(2, o), null != (o = e.getRasterization()) && r.writeMessage(3, o, i.Rasterization.serializeBinaryToWriter); }), (proto.mediapipe.LocationData.BinaryMask.prototype.getWidth = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.LocationData.BinaryMask.prototype.setWidth = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.LocationData.BinaryMask.prototype.clearWidth = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.LocationData.BinaryMask.prototype.hasWidth = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.LocationData.BinaryMask.prototype.getHeight = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.LocationData.BinaryMask.prototype.setHeight = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.LocationData.BinaryMask.prototype.clearHeight = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.LocationData.BinaryMask.prototype.hasHeight = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.LocationData.BinaryMask.prototype.getRasterization = function() { return t.Message.getWrapperField(this, i.Rasterization, 3); }), (proto.mediapipe.LocationData.BinaryMask.prototype.setRasterization = function(e) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.LocationData.BinaryMask.prototype.clearRasterization = function() { return this.setRasterization(void 0); }), (proto.mediapipe.LocationData.BinaryMask.prototype.hasRasterization = function() { return null != t.Message.getField(this, 3); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.LocationData.RelativeKeypoint.prototype.toObject = function(e) { return proto.mediapipe.LocationData.RelativeKeypoint.toObject(e, this); }), (proto.mediapipe.LocationData.RelativeKeypoint.toObject = function(e, r) { var o, i = { x: null == (o = t.Message.getOptionalFloatingPointField(r, 1)) ? void 0 : o, y: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, keypointLabel: null == (o = t.Message.getField(r, 3)) ? void 0 : o, score: null == (o = t.Message.getOptionalFloatingPointField(r, 4)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.LocationData.RelativeKeypoint.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.LocationData.RelativeKeypoint(); return proto.mediapipe.LocationData.RelativeKeypoint.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.LocationData.RelativeKeypoint.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readFloat(); e.setX(r); break; case 2: r = t.readFloat(); e.setY(r); break; case 3: r = t.readString(); e.setKeypointLabel(r); break; case 4: r = t.readFloat(); e.setScore(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.LocationData.RelativeKeypoint.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.LocationData.RelativeKeypoint.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeFloat(1, o), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o), null != (o = t.Message.getField(e, 3)) && r.writeString(3, o), null != (o = t.Message.getField(e, 4)) && r.writeFloat(4, o); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.getX = function() { return t.Message.getFloatingPointFieldWithDefault(this, 1, 0); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.setX = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.clearX = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.hasX = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.getY = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.setY = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.clearY = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.hasY = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.getKeypointLabel = function() { return t.Message.getFieldWithDefault(this, 3, ''); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.setKeypointLabel = function( e ) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.clearKeypointLabel = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.hasKeypointLabel = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.getScore = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.setScore = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.clearScore = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.LocationData.RelativeKeypoint.prototype.hasScore = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.LocationData.prototype.getFormat = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.LocationData.prototype.setFormat = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.LocationData.prototype.clearFormat = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.LocationData.prototype.hasFormat = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.LocationData.prototype.getBoundingBox = function() { return t.Message.getWrapperField(this, proto.mediapipe.LocationData.BoundingBox, 2); }), (proto.mediapipe.LocationData.prototype.setBoundingBox = function(e) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.LocationData.prototype.clearBoundingBox = function() { return this.setBoundingBox(void 0); }), (proto.mediapipe.LocationData.prototype.hasBoundingBox = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.LocationData.prototype.getRelativeBoundingBox = function() { return t.Message.getWrapperField( this, proto.mediapipe.LocationData.RelativeBoundingBox, 3 ); }), (proto.mediapipe.LocationData.prototype.setRelativeBoundingBox = function(e) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.LocationData.prototype.clearRelativeBoundingBox = function() { return this.setRelativeBoundingBox(void 0); }), (proto.mediapipe.LocationData.prototype.hasRelativeBoundingBox = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.LocationData.prototype.getMask = function() { return t.Message.getWrapperField(this, proto.mediapipe.LocationData.BinaryMask, 4); }), (proto.mediapipe.LocationData.prototype.setMask = function(e) { return t.Message.setWrapperField(this, 4, e); }), (proto.mediapipe.LocationData.prototype.clearMask = function() { return this.setMask(void 0); }), (proto.mediapipe.LocationData.prototype.hasMask = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.LocationData.prototype.getRelativeKeypointsList = function() { return t.Message.getRepeatedWrapperField( this, proto.mediapipe.LocationData.RelativeKeypoint, 5 ); }), (proto.mediapipe.LocationData.prototype.setRelativeKeypointsList = function(e) { return t.Message.setRepeatedWrapperField(this, 5, e); }), (proto.mediapipe.LocationData.prototype.addRelativeKeypoints = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 5, e, proto.mediapipe.LocationData.RelativeKeypoint, r ); }), (proto.mediapipe.LocationData.prototype.clearRelativeKeypointsList = function() { return this.setRelativeKeypointsList([]); }), r.object.extend(e, proto.mediapipe); })(location_data_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = location_data_pb; r.object.extend(proto, i), r.exportSymbol('proto.mediapipe.Detection', null, o), r.exportSymbol('proto.mediapipe.Detection.AssociatedDetection', null, o), r.exportSymbol('proto.mediapipe.DetectionList', null, o), (proto.mediapipe.Detection = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.Detection.repeatedFields_, null ); }), r.inherits(proto.mediapipe.Detection, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.Detection.displayName = 'proto.mediapipe.Detection'), (proto.mediapipe.Detection.AssociatedDetection = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.Detection.AssociatedDetection, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.Detection.AssociatedDetection.displayName = 'proto.mediapipe.Detection.AssociatedDetection'), (proto.mediapipe.DetectionList = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.DetectionList.repeatedFields_, null ); }), r.inherits(proto.mediapipe.DetectionList, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.DetectionList.displayName = 'proto.mediapipe.DetectionList'), (proto.mediapipe.Detection.repeatedFields_ = [1, 2, 3, 8, 9]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.Detection.prototype.toObject = function(e) { return proto.mediapipe.Detection.toObject(e, this); }), (proto.mediapipe.Detection.toObject = function(e, r) { var o, a = { labelList: null == (o = t.Message.getRepeatedField(r, 1)) ? void 0 : o, labelIdList: null == (o = t.Message.getRepeatedField(r, 2)) ? void 0 : o, scoreList: null == (o = t.Message.getRepeatedFloatingPointField(r, 3)) ? void 0 : o, locationData: (o = r.getLocationData()) && i.LocationData.toObject(e, o), featureTag: null == (o = t.Message.getField(r, 5)) ? void 0 : o, trackId: null == (o = t.Message.getField(r, 6)) ? void 0 : o, detectionId: null == (o = t.Message.getField(r, 7)) ? void 0 : o, associatedDetectionsList: t.Message.toObjectList( r.getAssociatedDetectionsList(), proto.mediapipe.Detection.AssociatedDetection.toObject, e ), displayNameList: null == (o = t.Message.getRepeatedField(r, 9)) ? void 0 : o, timestampUsec: null == (o = t.Message.getField(r, 10)) ? void 0 : o, }; return e && (a.$jspbMessageInstance = r), a; })), (proto.mediapipe.Detection.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.Detection(); return proto.mediapipe.Detection.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.Detection.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.addLabel(r); break; case 2: for ( var o = t.isDelimited() ? t.readPackedInt32() : [t.readInt32()], a = 0; a < o.length; a++ ) e.addLabelId(o[a]); break; case 3: for ( o = t.isDelimited() ? t.readPackedFloat() : [t.readFloat()], a = 0; a < o.length; a++ ) e.addScore(o[a]); break; case 4: r = new i.LocationData(); t.readMessage(r, i.LocationData.deserializeBinaryFromReader), e.setLocationData(r); break; case 5: r = t.readString(); e.setFeatureTag(r); break; case 6: r = t.readString(); e.setTrackId(r); break; case 7: r = t.readInt64(); e.setDetectionId(r); break; case 8: r = new proto.mediapipe.Detection.AssociatedDetection(); t.readMessage( r, proto.mediapipe.Detection.AssociatedDetection .deserializeBinaryFromReader ), e.addAssociatedDetections(r); break; case 9: r = t.readString(); e.addDisplayName(r); break; case 10: r = t.readInt64(); e.setTimestampUsec(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.Detection.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.Detection.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.Detection.serializeBinaryToWriter = function(e, r) { var o = void 0; (o = e.getLabelList()).length > 0 && r.writeRepeatedString(1, o), (o = e.getLabelIdList()).length > 0 && r.writePackedInt32(2, o), (o = e.getScoreList()).length > 0 && r.writePackedFloat(3, o), null != (o = e.getLocationData()) && r.writeMessage(4, o, i.LocationData.serializeBinaryToWriter), null != (o = t.Message.getField(e, 5)) && r.writeString(5, o), null != (o = t.Message.getField(e, 6)) && r.writeString(6, o), null != (o = t.Message.getField(e, 7)) && r.writeInt64(7, o), (o = e.getAssociatedDetectionsList()).length > 0 && r.writeRepeatedMessage( 8, o, proto.mediapipe.Detection.AssociatedDetection.serializeBinaryToWriter ), (o = e.getDisplayNameList()).length > 0 && r.writeRepeatedString(9, o), null != (o = t.Message.getField(e, 10)) && r.writeInt64(10, o); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.Detection.AssociatedDetection.prototype.toObject = function(e) { return proto.mediapipe.Detection.AssociatedDetection.toObject(e, this); }), (proto.mediapipe.Detection.AssociatedDetection.toObject = function(e, r) { var o, i = { id: null == (o = t.Message.getField(r, 1)) ? void 0 : o, confidence: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.Detection.AssociatedDetection.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.Detection.AssociatedDetection(); return proto.mediapipe.Detection.AssociatedDetection.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.Detection.AssociatedDetection.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readInt32(); e.setId(r); break; case 2: r = t.readFloat(); e.setConfidence(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.Detection.AssociatedDetection.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.Detection.AssociatedDetection.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.Detection.AssociatedDetection.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeInt32(1, o), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o); }), (proto.mediapipe.Detection.AssociatedDetection.prototype.getId = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.Detection.AssociatedDetection.prototype.setId = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.Detection.AssociatedDetection.prototype.clearId = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.Detection.AssociatedDetection.prototype.hasId = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.Detection.AssociatedDetection.prototype.getConfidence = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.Detection.AssociatedDetection.prototype.setConfidence = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.Detection.AssociatedDetection.prototype.clearConfidence = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.Detection.AssociatedDetection.prototype.hasConfidence = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.Detection.prototype.getLabelList = function() { return t.Message.getRepeatedField(this, 1); }), (proto.mediapipe.Detection.prototype.setLabelList = function(e) { return t.Message.setField(this, 1, e || []); }), (proto.mediapipe.Detection.prototype.addLabel = function(e, r) { return t.Message.addToRepeatedField(this, 1, e, r); }), (proto.mediapipe.Detection.prototype.clearLabelList = function() { return this.setLabelList([]); }), (proto.mediapipe.Detection.prototype.getLabelIdList = function() { return t.Message.getRepeatedField(this, 2); }), (proto.mediapipe.Detection.prototype.setLabelIdList = function(e) { return t.Message.setField(this, 2, e || []); }), (proto.mediapipe.Detection.prototype.addLabelId = function(e, r) { return t.Message.addToRepeatedField(this, 2, e, r); }), (proto.mediapipe.Detection.prototype.clearLabelIdList = function() { return this.setLabelIdList([]); }), (proto.mediapipe.Detection.prototype.getScoreList = function() { return t.Message.getRepeatedFloatingPointField(this, 3); }), (proto.mediapipe.Detection.prototype.setScoreList = function(e) { return t.Message.setField(this, 3, e || []); }), (proto.mediapipe.Detection.prototype.addScore = function(e, r) { return t.Message.addToRepeatedField(this, 3, e, r); }), (proto.mediapipe.Detection.prototype.clearScoreList = function() { return this.setScoreList([]); }), (proto.mediapipe.Detection.prototype.getLocationData = function() { return t.Message.getWrapperField(this, i.LocationData, 4); }), (proto.mediapipe.Detection.prototype.setLocationData = function(e) { return t.Message.setWrapperField(this, 4, e); }), (proto.mediapipe.Detection.prototype.clearLocationData = function() { return this.setLocationData(void 0); }), (proto.mediapipe.Detection.prototype.hasLocationData = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.Detection.prototype.getFeatureTag = function() { return t.Message.getFieldWithDefault(this, 5, ''); }), (proto.mediapipe.Detection.prototype.setFeatureTag = function(e) { return t.Message.setField(this, 5, e); }), (proto.mediapipe.Detection.prototype.clearFeatureTag = function() { return t.Message.setField(this, 5, void 0); }), (proto.mediapipe.Detection.prototype.hasFeatureTag = function() { return null != t.Message.getField(this, 5); }), (proto.mediapipe.Detection.prototype.getTrackId = function() { return t.Message.getFieldWithDefault(this, 6, ''); }), (proto.mediapipe.Detection.prototype.setTrackId = function(e) { return t.Message.setField(this, 6, e); }), (proto.mediapipe.Detection.prototype.clearTrackId = function() { return t.Message.setField(this, 6, void 0); }), (proto.mediapipe.Detection.prototype.hasTrackId = function() { return null != t.Message.getField(this, 6); }), (proto.mediapipe.Detection.prototype.getDetectionId = function() { return t.Message.getFieldWithDefault(this, 7, 0); }), (proto.mediapipe.Detection.prototype.setDetectionId = function(e) { return t.Message.setField(this, 7, e); }), (proto.mediapipe.Detection.prototype.clearDetectionId = function() { return t.Message.setField(this, 7, void 0); }), (proto.mediapipe.Detection.prototype.hasDetectionId = function() { return null != t.Message.getField(this, 7); }), (proto.mediapipe.Detection.prototype.getAssociatedDetectionsList = function() { return t.Message.getRepeatedWrapperField( this, proto.mediapipe.Detection.AssociatedDetection, 8 ); }), (proto.mediapipe.Detection.prototype.setAssociatedDetectionsList = function(e) { return t.Message.setRepeatedWrapperField(this, 8, e); }), (proto.mediapipe.Detection.prototype.addAssociatedDetections = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 8, e, proto.mediapipe.Detection.AssociatedDetection, r ); }), (proto.mediapipe.Detection.prototype.clearAssociatedDetectionsList = function() { return this.setAssociatedDetectionsList([]); }), (proto.mediapipe.Detection.prototype.getDisplayNameList = function() { return t.Message.getRepeatedField(this, 9); }), (proto.mediapipe.Detection.prototype.setDisplayNameList = function(e) { return t.Message.setField(this, 9, e || []); }), (proto.mediapipe.Detection.prototype.addDisplayName = function(e, r) { return t.Message.addToRepeatedField(this, 9, e, r); }), (proto.mediapipe.Detection.prototype.clearDisplayNameList = function() { return this.setDisplayNameList([]); }), (proto.mediapipe.Detection.prototype.getTimestampUsec = function() { return t.Message.getFieldWithDefault(this, 10, 0); }), (proto.mediapipe.Detection.prototype.setTimestampUsec = function(e) { return t.Message.setField(this, 10, e); }), (proto.mediapipe.Detection.prototype.clearTimestampUsec = function() { return t.Message.setField(this, 10, void 0); }), (proto.mediapipe.Detection.prototype.hasTimestampUsec = function() { return null != t.Message.getField(this, 10); }), (proto.mediapipe.DetectionList.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.DetectionList.prototype.toObject = function(e) { return proto.mediapipe.DetectionList.toObject(e, this); }), (proto.mediapipe.DetectionList.toObject = function(e, r) { var o = { detectionList: t.Message.toObjectList( r.getDetectionList(), proto.mediapipe.Detection.toObject, e ), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.DetectionList.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.DetectionList(); return proto.mediapipe.DetectionList.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.DetectionList.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new proto.mediapipe.Detection(); t.readMessage(r, proto.mediapipe.Detection.deserializeBinaryFromReader), e.addDetection(r); } else t.skipField(); } return e; }), (proto.mediapipe.DetectionList.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.DetectionList.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.DetectionList.serializeBinaryToWriter = function(e, t) { var r; (r = e.getDetectionList()).length > 0 && t.writeRepeatedMessage(1, r, proto.mediapipe.Detection.serializeBinaryToWriter); }), (proto.mediapipe.DetectionList.prototype.getDetectionList = function() { return t.Message.getRepeatedWrapperField(this, proto.mediapipe.Detection, 1); }), (proto.mediapipe.DetectionList.prototype.setDetectionList = function(e) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.DetectionList.prototype.addDetection = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.Detection, r ); }), (proto.mediapipe.DetectionList.prototype.clearDetectionList = function() { return this.setDetectionList([]); }), r.object.extend(e, proto.mediapipe); })(detection_pb); var base_options_pb = {}, acceleration_pb = {}, inference_calculator_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a), r.exportSymbol('proto.mediapipe.InferenceCalculatorOptions', null, o), r.exportSymbol('proto.mediapipe.InferenceCalculatorOptions.Delegate', null, o), r.exportSymbol('proto.mediapipe.InferenceCalculatorOptions.Delegate.DelegateCase', null, o), r.exportSymbol('proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu', null, o), r.exportSymbol('proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.Api', null, o), r.exportSymbol( 'proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.InferenceUsage', null, o ), r.exportSymbol('proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi', null, o), r.exportSymbol('proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite', null, o), r.exportSymbol('proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack', null, o), (proto.mediapipe.InferenceCalculatorOptions = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.InferenceCalculatorOptions, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.InferenceCalculatorOptions.displayName = 'proto.mediapipe.InferenceCalculatorOptions'), (proto.mediapipe.InferenceCalculatorOptions.Delegate = function(e) { t.Message.initialize( this, e, 0, -1, null, proto.mediapipe.InferenceCalculatorOptions.Delegate.oneofGroups_ ); }), r.inherits(proto.mediapipe.InferenceCalculatorOptions.Delegate, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.InferenceCalculatorOptions.Delegate.displayName = 'proto.mediapipe.InferenceCalculatorOptions.Delegate'), (proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite.displayName = 'proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite'), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.displayName = 'proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu'), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.displayName = 'proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi'), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.displayName = 'proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.InferenceCalculatorOptions.prototype.toObject = function(e) { return proto.mediapipe.InferenceCalculatorOptions.toObject(e, this); }), (proto.mediapipe.InferenceCalculatorOptions.toObject = function(e, r) { var o, i = { modelPath: null == (o = t.Message.getField(r, 1)) ? void 0 : o, useGpu: t.Message.getBooleanFieldWithDefault(r, 2, !1), useNnapi: t.Message.getBooleanFieldWithDefault(r, 3, !1), cpuNumThread: t.Message.getFieldWithDefault(r, 4, -1), delegate: (o = r.getDelegate()) && proto.mediapipe.InferenceCalculatorOptions.Delegate.toObject(e, o), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.InferenceCalculatorOptions.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.InferenceCalculatorOptions(); return proto.mediapipe.InferenceCalculatorOptions.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.InferenceCalculatorOptions.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setModelPath(r); break; case 2: r = t.readBool(); e.setUseGpu(r); break; case 3: r = t.readBool(); e.setUseNnapi(r); break; case 4: r = t.readInt32(); e.setCpuNumThread(r); break; case 5: r = new proto.mediapipe.InferenceCalculatorOptions.Delegate(); t.readMessage( r, proto.mediapipe.InferenceCalculatorOptions.Delegate .deserializeBinaryFromReader ), e.setDelegate(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.InferenceCalculatorOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.InferenceCalculatorOptions.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.InferenceCalculatorOptions.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeString(1, o), null != (o = t.Message.getField(e, 2)) && r.writeBool(2, o), null != (o = t.Message.getField(e, 3)) && r.writeBool(3, o), null != (o = t.Message.getField(e, 4)) && r.writeInt32(4, o), null != (o = e.getDelegate()) && r.writeMessage( 5, o, proto.mediapipe.InferenceCalculatorOptions.Delegate.serializeBinaryToWriter ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.oneofGroups_ = [[1, 2, 3, 4]]), (proto.mediapipe.InferenceCalculatorOptions.Delegate.DelegateCase = { DELEGATE_NOT_SET: 0, TFLITE: 1, GPU: 2, NNAPI: 3, XNNPACK: 4, }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.getDelegateCase = function() { return t.Message.computeOneofCase( this, proto.mediapipe.InferenceCalculatorOptions.Delegate.oneofGroups_[0] ); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.toObject = function(e) { return proto.mediapipe.InferenceCalculatorOptions.Delegate.toObject(e, this); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.toObject = function(e, t) { var r, o = { tflite: (r = t.getTflite()) && proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite.toObject( e, r ), gpu: (r = t.getGpu()) && proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.toObject(e, r), nnapi: (r = t.getNnapi()) && proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.toObject( e, r ), xnnpack: (r = t.getXnnpack()) && proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.toObject( e, r ), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.InferenceCalculatorOptions.Delegate.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.InferenceCalculatorOptions.Delegate(); return proto.mediapipe.InferenceCalculatorOptions.Delegate.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite(); t.readMessage( r, proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite .deserializeBinaryFromReader ), e.setTflite(r); break; case 2: r = new proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu(); t.readMessage( r, proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu .deserializeBinaryFromReader ), e.setGpu(r); break; case 3: r = new proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi(); t.readMessage( r, proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi .deserializeBinaryFromReader ), e.setNnapi(r); break; case 4: r = new proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack(); t.readMessage( r, proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack .deserializeBinaryFromReader ), e.setXnnpack(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.InferenceCalculatorOptions.Delegate.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.serializeBinaryToWriter = function( e, t ) { var r = void 0; null != (r = e.getTflite()) && t.writeMessage( 1, r, proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite .serializeBinaryToWriter ), null != (r = e.getGpu()) && t.writeMessage( 2, r, proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu .serializeBinaryToWriter ), null != (r = e.getNnapi()) && t.writeMessage( 3, r, proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi .serializeBinaryToWriter ), null != (r = e.getXnnpack()) && t.writeMessage( 4, r, proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack .serializeBinaryToWriter ); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite.prototype.toObject = function( e ) { return proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite.toObject(e, this); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite.toObject = function(e, t) { var r = {}; return e && (r.$jspbMessageInstance = t), r; })), (proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite(); return proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { t.getFieldNumber(); t.skipField(); } return e; }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite.serializeBinaryToWriter = function( e, t ) {}), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.toObject = function( e ) { return proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.toObject(e, this); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.toObject = function(e, r) { var o, i = { useAdvancedGpuApi: t.Message.getBooleanFieldWithDefault(r, 1, !1), api: t.Message.getFieldWithDefault(r, 4, 0), allowPrecisionLoss: t.Message.getBooleanFieldWithDefault(r, 3, !0), cachedKernelPath: null == (o = t.Message.getField(r, 2)) ? void 0 : o, serializedModelDir: null == (o = t.Message.getField(r, 7)) ? void 0 : o, modelToken: null == (o = t.Message.getField(r, 8)) ? void 0 : o, usage: t.Message.getFieldWithDefault(r, 5, 2), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu(); return proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readBool(); e.setUseAdvancedGpuApi(r); break; case 4: r = t.readEnum(); e.setApi(r); break; case 3: r = t.readBool(); e.setAllowPrecisionLoss(r); break; case 2: r = t.readString(); e.setCachedKernelPath(r); break; case 7: r = t.readString(); e.setSerializedModelDir(r); break; case 8: r = t.readString(); e.setModelToken(r); break; case 5: r = t.readEnum(); e.setUsage(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeBool(1, o), null != (o = t.Message.getField(e, 4)) && r.writeEnum(4, o), null != (o = t.Message.getField(e, 3)) && r.writeBool(3, o), null != (o = t.Message.getField(e, 2)) && r.writeString(2, o), null != (o = t.Message.getField(e, 7)) && r.writeString(7, o), null != (o = t.Message.getField(e, 8)) && r.writeString(8, o), null != (o = t.Message.getField(e, 5)) && r.writeEnum(5, o); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.Api = { ANY: 0, OPENGL: 1, OPENCL: 2, }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.InferenceUsage = { UNSPECIFIED: 0, FAST_SINGLE_ANSWER: 1, SUSTAINED_SPEED: 2, }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.getUseAdvancedGpuApi = function() { return t.Message.getBooleanFieldWithDefault(this, 1, !1); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.setUseAdvancedGpuApi = function( e ) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.clearUseAdvancedGpuApi = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.hasUseAdvancedGpuApi = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.getApi = function() { return t.Message.getFieldWithDefault(this, 4, 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.setApi = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.clearApi = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.hasApi = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.getAllowPrecisionLoss = function() { return t.Message.getBooleanFieldWithDefault(this, 3, !0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.setAllowPrecisionLoss = function( e ) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.clearAllowPrecisionLoss = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.hasAllowPrecisionLoss = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.getCachedKernelPath = function() { return t.Message.getFieldWithDefault(this, 2, ''); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.setCachedKernelPath = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.clearCachedKernelPath = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.hasCachedKernelPath = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.getSerializedModelDir = function() { return t.Message.getFieldWithDefault(this, 7, ''); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.setSerializedModelDir = function( e ) { return t.Message.setField(this, 7, e); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.clearSerializedModelDir = function() { return t.Message.setField(this, 7, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.hasSerializedModelDir = function() { return null != t.Message.getField(this, 7); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.getModelToken = function() { return t.Message.getFieldWithDefault(this, 8, ''); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.setModelToken = function( e ) { return t.Message.setField(this, 8, e); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.clearModelToken = function() { return t.Message.setField(this, 8, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.hasModelToken = function() { return null != t.Message.getField(this, 8); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.getUsage = function() { return t.Message.getFieldWithDefault(this, 5, 2); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.setUsage = function(e) { return t.Message.setField(this, 5, e); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.clearUsage = function() { return t.Message.setField(this, 5, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu.prototype.hasUsage = function() { return null != t.Message.getField(this, 5); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.toObject = function( e ) { return proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.toObject(e, this); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.toObject = function(e, r) { var o, i = { cacheDir: null == (o = t.Message.getField(r, 1)) ? void 0 : o, modelToken: null == (o = t.Message.getField(r, 2)) ? void 0 : o, acceleratorName: null == (o = t.Message.getField(r, 3)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi(); return proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setCacheDir(r); break; case 2: r = t.readString(); e.setModelToken(r); break; case 3: r = t.readString(); e.setAcceleratorName(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeString(1, o), null != (o = t.Message.getField(e, 2)) && r.writeString(2, o), null != (o = t.Message.getField(e, 3)) && r.writeString(3, o); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.getCacheDir = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.setCacheDir = function( e ) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.clearCacheDir = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.hasCacheDir = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.getModelToken = function() { return t.Message.getFieldWithDefault(this, 2, ''); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.setModelToken = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.clearModelToken = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.hasModelToken = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.getAcceleratorName = function() { return t.Message.getFieldWithDefault(this, 3, ''); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.setAcceleratorName = function( e ) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.clearAcceleratorName = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi.prototype.hasAcceleratorName = function() { return null != t.Message.getField(this, 3); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.prototype.toObject = function( e ) { return proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.toObject( e, this ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.toObject = function(e, r) { var o = { numThreads: t.Message.getFieldWithDefault(r, 1, -1) }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack(); return proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = t.readInt32(); e.setNumThreads(r); } else t.skipField(); } return e; }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.serializeBinaryToWriter = function( e, r ) { var o; null != (o = t.Message.getField(e, 1)) && r.writeInt32(1, o); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.prototype.getNumThreads = function() { return t.Message.getFieldWithDefault(this, 1, -1); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.prototype.setNumThreads = function( e ) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.prototype.clearNumThreads = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack.prototype.hasNumThreads = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.getTflite = function() { return t.Message.getWrapperField( this, proto.mediapipe.InferenceCalculatorOptions.Delegate.TfLite, 1 ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.setTflite = function(e) { return t.Message.setOneofWrapperField( this, 1, proto.mediapipe.InferenceCalculatorOptions.Delegate.oneofGroups_[0], e ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.clearTflite = function() { return this.setTflite(void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.hasTflite = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.getGpu = function() { return t.Message.getWrapperField( this, proto.mediapipe.InferenceCalculatorOptions.Delegate.Gpu, 2 ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.setGpu = function(e) { return t.Message.setOneofWrapperField( this, 2, proto.mediapipe.InferenceCalculatorOptions.Delegate.oneofGroups_[0], e ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.clearGpu = function() { return this.setGpu(void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.hasGpu = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.getNnapi = function() { return t.Message.getWrapperField( this, proto.mediapipe.InferenceCalculatorOptions.Delegate.Nnapi, 3 ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.setNnapi = function(e) { return t.Message.setOneofWrapperField( this, 3, proto.mediapipe.InferenceCalculatorOptions.Delegate.oneofGroups_[0], e ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.clearNnapi = function() { return this.setNnapi(void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.hasNnapi = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.getXnnpack = function() { return t.Message.getWrapperField( this, proto.mediapipe.InferenceCalculatorOptions.Delegate.Xnnpack, 4 ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.setXnnpack = function(e) { return t.Message.setOneofWrapperField( this, 4, proto.mediapipe.InferenceCalculatorOptions.Delegate.oneofGroups_[0], e ); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.clearXnnpack = function() { return this.setXnnpack(void 0); }), (proto.mediapipe.InferenceCalculatorOptions.Delegate.prototype.hasXnnpack = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.InferenceCalculatorOptions.ext = new t.ExtensionFieldInfo( 336783863, { ext: 0 }, proto.mediapipe.InferenceCalculatorOptions, proto.mediapipe.InferenceCalculatorOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[336783863] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.InferenceCalculatorOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.InferenceCalculatorOptions.serializeBinaryToWriter, proto.mediapipe.InferenceCalculatorOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[336783863] = proto.mediapipe.InferenceCalculatorOptions.ext), (proto.mediapipe.InferenceCalculatorOptions.prototype.getModelPath = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.setModelPath = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.clearModelPath = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.hasModelPath = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.getUseGpu = function() { return t.Message.getBooleanFieldWithDefault(this, 2, !1); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.setUseGpu = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.clearUseGpu = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.hasUseGpu = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.getUseNnapi = function() { return t.Message.getBooleanFieldWithDefault(this, 3, !1); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.setUseNnapi = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.clearUseNnapi = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.hasUseNnapi = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.getCpuNumThread = function() { return t.Message.getFieldWithDefault(this, 4, -1); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.setCpuNumThread = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.clearCpuNumThread = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.hasCpuNumThread = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.getDelegate = function() { return t.Message.getWrapperField( this, proto.mediapipe.InferenceCalculatorOptions.Delegate, 5 ); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.setDelegate = function(e) { return t.Message.setWrapperField(this, 5, e); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.clearDelegate = function() { return this.setDelegate(void 0); }), (proto.mediapipe.InferenceCalculatorOptions.prototype.hasDelegate = function() { return null != t.Message.getField(this, 5); }), (proto.mediapipe.InferenceCalculatorOptions.ext = new t.ExtensionFieldInfo( 336783863, { ext: 0 }, proto.mediapipe.InferenceCalculatorOptions, proto.mediapipe.InferenceCalculatorOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[336783863] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.InferenceCalculatorOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.InferenceCalculatorOptions.serializeBinaryToWriter, proto.mediapipe.InferenceCalculatorOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[336783863] = proto.mediapipe.InferenceCalculatorOptions.ext), r.object.extend(e, proto.mediapipe); })(inference_calculator_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = inference_calculator_pb; r.object.extend(proto, i), r.exportSymbol('proto.mediapipe.tasks.core.proto.Acceleration', null, o), r.exportSymbol('proto.mediapipe.tasks.core.proto.Acceleration.DelegateCase', null, o), (proto.mediapipe.tasks.core.proto.Acceleration = function(e) { t.Message.initialize( this, e, 0, -1, null, proto.mediapipe.tasks.core.proto.Acceleration.oneofGroups_ ); }), r.inherits(proto.mediapipe.tasks.core.proto.Acceleration, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.core.proto.Acceleration.displayName = 'proto.mediapipe.tasks.core.proto.Acceleration'), (proto.mediapipe.tasks.core.proto.Acceleration.oneofGroups_ = [[1, 2, 4, 5]]), (proto.mediapipe.tasks.core.proto.Acceleration.DelegateCase = { DELEGATE_NOT_SET: 0, XNNPACK: 1, GPU: 2, TFLITE: 4, NNAPI: 5, }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.getDelegateCase = function() { return t.Message.computeOneofCase( this, proto.mediapipe.tasks.core.proto.Acceleration.oneofGroups_[0] ); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.core.proto.Acceleration.prototype.toObject = function(e) { return proto.mediapipe.tasks.core.proto.Acceleration.toObject(e, this); }), (proto.mediapipe.tasks.core.proto.Acceleration.toObject = function(e, t) { var r, o = { xnnpack: (r = t.getXnnpack()) && i.InferenceCalculatorOptions.Delegate.Xnnpack.toObject(e, r), gpu: (r = t.getGpu()) && i.InferenceCalculatorOptions.Delegate.Gpu.toObject(e, r), tflite: (r = t.getTflite()) && i.InferenceCalculatorOptions.Delegate.TfLite.toObject(e, r), nnapi: (r = t.getNnapi()) && i.InferenceCalculatorOptions.Delegate.Nnapi.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.tasks.core.proto.Acceleration.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.core.proto.Acceleration(); return proto.mediapipe.tasks.core.proto.Acceleration.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.core.proto.Acceleration.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new i.InferenceCalculatorOptions.Delegate.Xnnpack(); t.readMessage( r, i.InferenceCalculatorOptions.Delegate.Xnnpack .deserializeBinaryFromReader ), e.setXnnpack(r); break; case 2: r = new i.InferenceCalculatorOptions.Delegate.Gpu(); t.readMessage( r, i.InferenceCalculatorOptions.Delegate.Gpu .deserializeBinaryFromReader ), e.setGpu(r); break; case 4: r = new i.InferenceCalculatorOptions.Delegate.TfLite(); t.readMessage( r, i.InferenceCalculatorOptions.Delegate.TfLite .deserializeBinaryFromReader ), e.setTflite(r); break; case 5: r = new i.InferenceCalculatorOptions.Delegate.Nnapi(); t.readMessage( r, i.InferenceCalculatorOptions.Delegate.Nnapi .deserializeBinaryFromReader ), e.setNnapi(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.core.proto.Acceleration.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.tasks.core.proto.Acceleration.serializeBinaryToWriter = function( e, t ) { var r = void 0; null != (r = e.getXnnpack()) && t.writeMessage( 1, r, i.InferenceCalculatorOptions.Delegate.Xnnpack.serializeBinaryToWriter ), null != (r = e.getGpu()) && t.writeMessage( 2, r, i.InferenceCalculatorOptions.Delegate.Gpu.serializeBinaryToWriter ), null != (r = e.getTflite()) && t.writeMessage( 4, r, i.InferenceCalculatorOptions.Delegate.TfLite.serializeBinaryToWriter ), null != (r = e.getNnapi()) && t.writeMessage( 5, r, i.InferenceCalculatorOptions.Delegate.Nnapi.serializeBinaryToWriter ); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.getXnnpack = function() { return t.Message.getWrapperField( this, i.InferenceCalculatorOptions.Delegate.Xnnpack, 1 ); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.setXnnpack = function(e) { return t.Message.setOneofWrapperField( this, 1, proto.mediapipe.tasks.core.proto.Acceleration.oneofGroups_[0], e ); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.clearXnnpack = function() { return this.setXnnpack(void 0); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.hasXnnpack = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.getGpu = function() { return t.Message.getWrapperField( this, i.InferenceCalculatorOptions.Delegate.Gpu, 2 ); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.setGpu = function(e) { return t.Message.setOneofWrapperField( this, 2, proto.mediapipe.tasks.core.proto.Acceleration.oneofGroups_[0], e ); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.clearGpu = function() { return this.setGpu(void 0); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.hasGpu = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.getTflite = function() { return t.Message.getWrapperField( this, i.InferenceCalculatorOptions.Delegate.TfLite, 4 ); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.setTflite = function(e) { return t.Message.setOneofWrapperField( this, 4, proto.mediapipe.tasks.core.proto.Acceleration.oneofGroups_[0], e ); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.clearTflite = function() { return this.setTflite(void 0); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.hasTflite = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.getNnapi = function() { return t.Message.getWrapperField( this, i.InferenceCalculatorOptions.Delegate.Nnapi, 5 ); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.setNnapi = function(e) { return t.Message.setOneofWrapperField( this, 5, proto.mediapipe.tasks.core.proto.Acceleration.oneofGroups_[0], e ); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.clearNnapi = function() { return this.setNnapi(void 0); }), (proto.mediapipe.tasks.core.proto.Acceleration.prototype.hasNnapi = function() { return null != t.Message.getField(this, 5); }), r.object.extend(e, proto.mediapipe.tasks.core.proto); })(acceleration_pb); var external_file_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.tasks.core.proto.ExternalFile', null, o), r.exportSymbol('proto.mediapipe.tasks.core.proto.FileDescriptorMeta', null, o), r.exportSymbol('proto.mediapipe.tasks.core.proto.FilePointerMeta', null, o), (proto.mediapipe.tasks.core.proto.ExternalFile = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.tasks.core.proto.ExternalFile, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.core.proto.ExternalFile.displayName = 'proto.mediapipe.tasks.core.proto.ExternalFile'), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.tasks.core.proto.FileDescriptorMeta, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.displayName = 'proto.mediapipe.tasks.core.proto.FileDescriptorMeta'), (proto.mediapipe.tasks.core.proto.FilePointerMeta = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.tasks.core.proto.FilePointerMeta, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.core.proto.FilePointerMeta.displayName = 'proto.mediapipe.tasks.core.proto.FilePointerMeta'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.core.proto.ExternalFile.prototype.toObject = function(e) { return proto.mediapipe.tasks.core.proto.ExternalFile.toObject(e, this); }), (proto.mediapipe.tasks.core.proto.ExternalFile.toObject = function(e, r) { var o, i = { fileContent: r.getFileContent_asB64(), fileName: null == (o = t.Message.getField(r, 2)) ? void 0 : o, fileDescriptorMeta: (o = r.getFileDescriptorMeta()) && proto.mediapipe.tasks.core.proto.FileDescriptorMeta.toObject(e, o), filePointerMeta: (o = r.getFilePointerMeta()) && proto.mediapipe.tasks.core.proto.FilePointerMeta.toObject(e, o), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.core.proto.ExternalFile.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.core.proto.ExternalFile(); return proto.mediapipe.tasks.core.proto.ExternalFile.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.tasks.core.proto.ExternalFile.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readBytes(); e.setFileContent(r); break; case 2: r = t.readString(); e.setFileName(r); break; case 3: r = new proto.mediapipe.tasks.core.proto.FileDescriptorMeta(); t.readMessage( r, proto.mediapipe.tasks.core.proto.FileDescriptorMeta .deserializeBinaryFromReader ), e.setFileDescriptorMeta(r); break; case 4: r = new proto.mediapipe.tasks.core.proto.FilePointerMeta(); t.readMessage( r, proto.mediapipe.tasks.core.proto.FilePointerMeta .deserializeBinaryFromReader ), e.setFilePointerMeta(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.core.proto.ExternalFile.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.tasks.core.proto.ExternalFile.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeBytes(1, o), null != (o = t.Message.getField(e, 2)) && r.writeString(2, o), null != (o = e.getFileDescriptorMeta()) && r.writeMessage( 3, o, proto.mediapipe.tasks.core.proto.FileDescriptorMeta.serializeBinaryToWriter ), null != (o = e.getFilePointerMeta()) && r.writeMessage( 4, o, proto.mediapipe.tasks.core.proto.FilePointerMeta.serializeBinaryToWriter ); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.getFileContent = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.getFileContent_asB64 = function() { return t.Message.bytesAsB64(this.getFileContent()); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.getFileContent_asU8 = function() { return t.Message.bytesAsU8(this.getFileContent()); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.setFileContent = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.clearFileContent = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.hasFileContent = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.getFileName = function() { return t.Message.getFieldWithDefault(this, 2, ''); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.setFileName = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.clearFileName = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.hasFileName = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.getFileDescriptorMeta = function() { return t.Message.getWrapperField( this, proto.mediapipe.tasks.core.proto.FileDescriptorMeta, 3 ); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.setFileDescriptorMeta = function( e ) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.clearFileDescriptorMeta = function() { return this.setFileDescriptorMeta(void 0); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.hasFileDescriptorMeta = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.getFilePointerMeta = function() { return t.Message.getWrapperField( this, proto.mediapipe.tasks.core.proto.FilePointerMeta, 4 ); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.setFilePointerMeta = function(e) { return t.Message.setWrapperField(this, 4, e); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.clearFilePointerMeta = function() { return this.setFilePointerMeta(void 0); }), (proto.mediapipe.tasks.core.proto.ExternalFile.prototype.hasFilePointerMeta = function() { return null != t.Message.getField(this, 4); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.toObject = function(e) { return proto.mediapipe.tasks.core.proto.FileDescriptorMeta.toObject(e, this); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.toObject = function(e, r) { var o, i = { fd: null == (o = t.Message.getField(r, 1)) ? void 0 : o, length: null == (o = t.Message.getField(r, 2)) ? void 0 : o, offset: null == (o = t.Message.getField(r, 3)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.core.proto.FileDescriptorMeta(); return proto.mediapipe.tasks.core.proto.FileDescriptorMeta.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readInt32(); e.setFd(r); break; case 2: r = t.readInt64(); e.setLength(r); break; case 3: r = t.readInt64(); e.setOffset(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.core.proto.FileDescriptorMeta.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeInt32(1, o), null != (o = t.Message.getField(e, 2)) && r.writeInt64(2, o), null != (o = t.Message.getField(e, 3)) && r.writeInt64(3, o); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.getFd = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.setFd = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.clearFd = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.hasFd = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.getLength = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.setLength = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.clearLength = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.hasLength = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.getOffset = function() { return t.Message.getFieldWithDefault(this, 3, 0); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.setOffset = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.clearOffset = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.tasks.core.proto.FileDescriptorMeta.prototype.hasOffset = function() { return null != t.Message.getField(this, 3); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.core.proto.FilePointerMeta.prototype.toObject = function(e) { return proto.mediapipe.tasks.core.proto.FilePointerMeta.toObject(e, this); }), (proto.mediapipe.tasks.core.proto.FilePointerMeta.toObject = function(e, r) { var o, i = { pointer: null == (o = t.Message.getField(r, 1)) ? void 0 : o, length: null == (o = t.Message.getField(r, 2)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.core.proto.FilePointerMeta.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.core.proto.FilePointerMeta(); return proto.mediapipe.tasks.core.proto.FilePointerMeta.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.core.proto.FilePointerMeta.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readUint64(); e.setPointer(r); break; case 2: r = t.readInt64(); e.setLength(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.core.proto.FilePointerMeta.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.core.proto.FilePointerMeta.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.tasks.core.proto.FilePointerMeta.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeUint64(1, o), null != (o = t.Message.getField(e, 2)) && r.writeInt64(2, o); }), (proto.mediapipe.tasks.core.proto.FilePointerMeta.prototype.getPointer = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.tasks.core.proto.FilePointerMeta.prototype.setPointer = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.tasks.core.proto.FilePointerMeta.prototype.clearPointer = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.tasks.core.proto.FilePointerMeta.prototype.hasPointer = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.core.proto.FilePointerMeta.prototype.getLength = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.tasks.core.proto.FilePointerMeta.prototype.setLength = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.core.proto.FilePointerMeta.prototype.clearLength = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.core.proto.FilePointerMeta.prototype.hasLength = function() { return null != t.Message.getField(this, 2); }), r.object.extend(e, proto.mediapipe.tasks.core.proto); })(external_file_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = acceleration_pb; r.object.extend(proto, i); var a = external_file_pb; r.object.extend(proto, a), r.exportSymbol('proto.mediapipe.tasks.core.proto.BaseOptions', null, o), (proto.mediapipe.tasks.core.proto.BaseOptions = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.tasks.core.proto.BaseOptions, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.core.proto.BaseOptions.displayName = 'proto.mediapipe.tasks.core.proto.BaseOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.core.proto.BaseOptions.prototype.toObject = function(e) { return proto.mediapipe.tasks.core.proto.BaseOptions.toObject(e, this); }), (proto.mediapipe.tasks.core.proto.BaseOptions.toObject = function(e, r) { var o, n = { modelAsset: (o = r.getModelAsset()) && a.ExternalFile.toObject(e, o), useStreamMode: t.Message.getBooleanFieldWithDefault(r, 2, !1), acceleration: (o = r.getAcceleration()) && i.Acceleration.toObject(e, o), }; return e && (n.$jspbMessageInstance = r), n; })), (proto.mediapipe.tasks.core.proto.BaseOptions.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.core.proto.BaseOptions(); return proto.mediapipe.tasks.core.proto.BaseOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.core.proto.BaseOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new a.ExternalFile(); t.readMessage(r, a.ExternalFile.deserializeBinaryFromReader), e.setModelAsset(r); break; case 2: r = t.readBool(); e.setUseStreamMode(r); break; case 3: r = new i.Acceleration(); t.readMessage(r, i.Acceleration.deserializeBinaryFromReader), e.setAcceleration(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.core.proto.BaseOptions.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.tasks.core.proto.BaseOptions.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = e.getModelAsset()) && r.writeMessage(1, o, a.ExternalFile.serializeBinaryToWriter), null != (o = t.Message.getField(e, 2)) && r.writeBool(2, o), null != (o = e.getAcceleration()) && r.writeMessage(3, o, i.Acceleration.serializeBinaryToWriter); }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.getModelAsset = function() { return t.Message.getWrapperField(this, a.ExternalFile, 1); }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.setModelAsset = function(e) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.clearModelAsset = function() { return this.setModelAsset(void 0); }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.hasModelAsset = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.getUseStreamMode = function() { return t.Message.getBooleanFieldWithDefault(this, 2, !1); }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.setUseStreamMode = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.clearUseStreamMode = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.hasUseStreamMode = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.getAcceleration = function() { return t.Message.getWrapperField(this, i.Acceleration, 3); }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.setAcceleration = function(e) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.clearAcceleration = function() { return this.setAcceleration(void 0); }), (proto.mediapipe.tasks.core.proto.BaseOptions.prototype.hasAcceleration = function() { return null != t.Message.getField(this, 3); }), r.object.extend(e, proto.mediapipe.tasks.core.proto); })(base_options_pb); var face_detector_graph_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n), r.exportSymbol( 'proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions', null, o ), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.displayName = 'proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.toObject = function( e, r ) { var o, i = { baseOptions: (o = r.getBaseOptions()) && n.BaseOptions.toObject(e, o), minDetectionConfidence: t.Message.getFloatingPointFieldWithDefault( r, 2, 0.5 ), minSuppressionThreshold: t.Message.getFloatingPointFieldWithDefault( r, 3, 0.5 ), numFaces: null == (o = t.Message.getField(r, 4)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions(); return proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = t.readFloat(); e.setMinDetectionConfidence(r); break; case 3: r = t.readFloat(); e.setMinSuppressionThreshold(r); break; case 4: r = t.readInt32(); e.setNumFaces(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getBaseOptions()) && r.writeMessage(1, o, n.BaseOptions.serializeBinaryToWriter), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o), null != (o = t.Message.getField(e, 3)) && r.writeFloat(3, o), null != (o = t.Message.getField(e, 4)) && r.writeInt32(4, o); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.ext = new t.ExtensionFieldInfo( 502141897, { ext: 0 }, proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions, proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[502141897] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[502141897] = proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.ext), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.getMinDetectionConfidence = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0.5); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.setMinDetectionConfidence = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.clearMinDetectionConfidence = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.hasMinDetectionConfidence = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.getMinSuppressionThreshold = function() { return t.Message.getFloatingPointFieldWithDefault(this, 3, 0.5); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.setMinSuppressionThreshold = function( e ) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.clearMinSuppressionThreshold = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.hasMinSuppressionThreshold = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.getNumFaces = function() { return t.Message.getFieldWithDefault(this, 4, 0); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.setNumFaces = function( e ) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.clearNumFaces = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.prototype.hasNumFaces = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.ext = new t.ExtensionFieldInfo( 502141897, { ext: 0 }, proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions, proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[502141897] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[502141897] = proto.mediapipe.tasks.vision.face_detector.proto.FaceDetectorGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.face_detector.proto); })(face_detector_graph_options_pb); var detection_result = {}; Object.defineProperty(detection_result, '__esModule', { value: !0 }), (detection_result.convertFromDetectionProto = void 0); const DEFAULT_CATEGORY_INDEX = -1; function convertFromDetectionProto(e) { var t, r, o, i, a, n, s, p, d, l, g, c, u; const m = e.getScoreList(), f = e.getLabelIdList(), h = e.getLabelList(), y = e.getDisplayNameList(), b = { categories: [], keypoints: [] }; for (let e = 0; e < m.length; e++) b.categories.push({ score: m[e], index: null !== (t = f[e]) && void 0 !== t ? t : DEFAULT_CATEGORY_INDEX, categoryName: null !== (r = h[e]) && void 0 !== r ? r : '', displayName: null !== (o = y[e]) && void 0 !== o ? o : '', }); const _ = null === (i = e.getLocationData()) || void 0 === i ? void 0 : i.getBoundingBox(); if ( (_ && (b.boundingBox = { originX: null !== (a = _.getXmin()) && void 0 !== a ? a : 0, originY: null !== (n = _.getYmin()) && void 0 !== n ? n : 0, width: null !== (s = _.getWidth()) && void 0 !== s ? s : 0, height: null !== (p = _.getHeight()) && void 0 !== p ? p : 0, }), null === (d = e.getLocationData()) || void 0 === d ? void 0 : d.getRelativeKeypointsList().length) ) for (const t of e.getLocationData().getRelativeKeypointsList()) b.keypoints.push({ x: null !== (l = t.getX()) && void 0 !== l ? l : 0, y: null !== (g = t.getY()) && void 0 !== g ? g : 0, score: null !== (c = t.getScore()) && void 0 !== c ? c : 0, label: null !== (u = t.getKeypointLabel()) && void 0 !== u ? u : '', }); return b; } detection_result.convertFromDetectionProto = convertFromDetectionProto; var vision_task_runner = {}, rect_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.NormalizedRect', null, o), r.exportSymbol('proto.mediapipe.Rect', null, o), (proto.mediapipe.Rect = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.Rect, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.Rect.displayName = 'proto.mediapipe.Rect'), (proto.mediapipe.NormalizedRect = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.NormalizedRect, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.NormalizedRect.displayName = 'proto.mediapipe.NormalizedRect'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.Rect.prototype.toObject = function(e) { return proto.mediapipe.Rect.toObject(e, this); }), (proto.mediapipe.Rect.toObject = function(e, r) { var o, i = { xCenter: null == (o = t.Message.getField(r, 1)) ? void 0 : o, yCenter: null == (o = t.Message.getField(r, 2)) ? void 0 : o, height: null == (o = t.Message.getField(r, 3)) ? void 0 : o, width: null == (o = t.Message.getField(r, 4)) ? void 0 : o, rotation: t.Message.getFloatingPointFieldWithDefault(r, 5, 0), rectId: null == (o = t.Message.getField(r, 6)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.Rect.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.Rect(); return proto.mediapipe.Rect.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.Rect.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readInt32(); e.setXCenter(r); break; case 2: r = t.readInt32(); e.setYCenter(r); break; case 3: r = t.readInt32(); e.setHeight(r); break; case 4: r = t.readInt32(); e.setWidth(r); break; case 5: r = t.readFloat(); e.setRotation(r); break; case 6: r = t.readInt64(); e.setRectId(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.Rect.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return proto.mediapipe.Rect.serializeBinaryToWriter(this, e), e.getResultBuffer(); }), (proto.mediapipe.Rect.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeInt32(1, o), null != (o = t.Message.getField(e, 2)) && r.writeInt32(2, o), null != (o = t.Message.getField(e, 3)) && r.writeInt32(3, o), null != (o = t.Message.getField(e, 4)) && r.writeInt32(4, o), null != (o = t.Message.getField(e, 5)) && r.writeFloat(5, o), null != (o = t.Message.getField(e, 6)) && r.writeInt64(6, o); }), (proto.mediapipe.Rect.prototype.getXCenter = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.Rect.prototype.setXCenter = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.Rect.prototype.clearXCenter = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.Rect.prototype.hasXCenter = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.Rect.prototype.getYCenter = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.Rect.prototype.setYCenter = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.Rect.prototype.clearYCenter = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.Rect.prototype.hasYCenter = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.Rect.prototype.getHeight = function() { return t.Message.getFieldWithDefault(this, 3, 0); }), (proto.mediapipe.Rect.prototype.setHeight = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.Rect.prototype.clearHeight = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.Rect.prototype.hasHeight = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.Rect.prototype.getWidth = function() { return t.Message.getFieldWithDefault(this, 4, 0); }), (proto.mediapipe.Rect.prototype.setWidth = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.Rect.prototype.clearWidth = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.Rect.prototype.hasWidth = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.Rect.prototype.getRotation = function() { return t.Message.getFloatingPointFieldWithDefault(this, 5, 0); }), (proto.mediapipe.Rect.prototype.setRotation = function(e) { return t.Message.setField(this, 5, e); }), (proto.mediapipe.Rect.prototype.clearRotation = function() { return t.Message.setField(this, 5, void 0); }), (proto.mediapipe.Rect.prototype.hasRotation = function() { return null != t.Message.getField(this, 5); }), (proto.mediapipe.Rect.prototype.getRectId = function() { return t.Message.getFieldWithDefault(this, 6, 0); }), (proto.mediapipe.Rect.prototype.setRectId = function(e) { return t.Message.setField(this, 6, e); }), (proto.mediapipe.Rect.prototype.clearRectId = function() { return t.Message.setField(this, 6, void 0); }), (proto.mediapipe.Rect.prototype.hasRectId = function() { return null != t.Message.getField(this, 6); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.NormalizedRect.prototype.toObject = function(e) { return proto.mediapipe.NormalizedRect.toObject(e, this); }), (proto.mediapipe.NormalizedRect.toObject = function(e, r) { var o, i = { xCenter: null == (o = t.Message.getOptionalFloatingPointField(r, 1)) ? void 0 : o, yCenter: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, height: null == (o = t.Message.getOptionalFloatingPointField(r, 3)) ? void 0 : o, width: null == (o = t.Message.getOptionalFloatingPointField(r, 4)) ? void 0 : o, rotation: t.Message.getFloatingPointFieldWithDefault(r, 5, 0), rectId: null == (o = t.Message.getField(r, 6)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.NormalizedRect.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.NormalizedRect(); return proto.mediapipe.NormalizedRect.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.NormalizedRect.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readFloat(); e.setXCenter(r); break; case 2: r = t.readFloat(); e.setYCenter(r); break; case 3: r = t.readFloat(); e.setHeight(r); break; case 4: r = t.readFloat(); e.setWidth(r); break; case 5: r = t.readFloat(); e.setRotation(r); break; case 6: r = t.readInt64(); e.setRectId(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.NormalizedRect.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.NormalizedRect.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.NormalizedRect.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeFloat(1, o), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o), null != (o = t.Message.getField(e, 3)) && r.writeFloat(3, o), null != (o = t.Message.getField(e, 4)) && r.writeFloat(4, o), null != (o = t.Message.getField(e, 5)) && r.writeFloat(5, o), null != (o = t.Message.getField(e, 6)) && r.writeInt64(6, o); }), (proto.mediapipe.NormalizedRect.prototype.getXCenter = function() { return t.Message.getFloatingPointFieldWithDefault(this, 1, 0); }), (proto.mediapipe.NormalizedRect.prototype.setXCenter = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.NormalizedRect.prototype.clearXCenter = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.NormalizedRect.prototype.hasXCenter = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.NormalizedRect.prototype.getYCenter = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.NormalizedRect.prototype.setYCenter = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.NormalizedRect.prototype.clearYCenter = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.NormalizedRect.prototype.hasYCenter = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.NormalizedRect.prototype.getHeight = function() { return t.Message.getFloatingPointFieldWithDefault(this, 3, 0); }), (proto.mediapipe.NormalizedRect.prototype.setHeight = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.NormalizedRect.prototype.clearHeight = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.NormalizedRect.prototype.hasHeight = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.NormalizedRect.prototype.getWidth = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0); }), (proto.mediapipe.NormalizedRect.prototype.setWidth = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.NormalizedRect.prototype.clearWidth = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.NormalizedRect.prototype.hasWidth = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.NormalizedRect.prototype.getRotation = function() { return t.Message.getFloatingPointFieldWithDefault(this, 5, 0); }), (proto.mediapipe.NormalizedRect.prototype.setRotation = function(e) { return t.Message.setField(this, 5, e); }), (proto.mediapipe.NormalizedRect.prototype.clearRotation = function() { return t.Message.setField(this, 5, void 0); }), (proto.mediapipe.NormalizedRect.prototype.hasRotation = function() { return null != t.Message.getField(this, 5); }), (proto.mediapipe.NormalizedRect.prototype.getRectId = function() { return t.Message.getFieldWithDefault(this, 6, 0); }), (proto.mediapipe.NormalizedRect.prototype.setRectId = function(e) { return t.Message.setField(this, 6, e); }), (proto.mediapipe.NormalizedRect.prototype.clearRectId = function() { return t.Message.setField(this, 6, void 0); }), (proto.mediapipe.NormalizedRect.prototype.hasRectId = function() { return null != t.Message.getField(this, 6); }), r.object.extend(e, proto.mediapipe); })(rect_pb); var task_runner = {}, graph_runner = {}; !(function(e) { Object.defineProperty(e, '__esModule', { value: !0 }), (e.createGraphRunner = e.createMediaPipeLib = e.GraphRunner = e.CALCULATOR_GRAPH_CONFIG_LISTENER_NAME = void 0); const t = platform_utils; e.CALCULATOR_GRAPH_CONFIG_LISTENER_NAME = '__graph_config__'; class r { constructor(e, r) { (this.autoResizeCanvas = !0), (this.wasmModule = e), (this.audioPtr = null), (this.audioSize = 0), (this.hasMultiStreamSupport = 'function' == typeof this.wasmModule._addIntToInputStream), void 0 !== r ? (this.wasmModule.canvas = r) : 'undefined' == typeof OffscreenCanvas || (0, t.isWebKit)() ? (console.warn( 'OffscreenCanvas not supported and GraphRunner constructor glCanvas parameter is undefined. Creating backup canvas.' ), (this.wasmModule.canvas = document.createElement('canvas'))) : (this.wasmModule.canvas = new OffscreenCanvas(1, 1)); } async initializeGraph(e) { const t = await fetch(e), r = await t.arrayBuffer(), o = !(e.endsWith('.pbtxt') || e.endsWith('.textproto')); this.setGraph(new Uint8Array(r), o); } setGraphFromString(e) { this.setGraph(new TextEncoder().encode(e), !1); } setGraph(e, t) { const r = e.length, o = this.wasmModule._malloc(r); this.wasmModule.HEAPU8.set(e, o), t ? this.wasmModule._changeBinaryGraph(r, o) : this.wasmModule._changeTextGraph(r, o), this.wasmModule._free(o); } configureAudio(e, t, r, o, i) { this.wasmModule._configureAudio || console.warn( 'Attempting to use configureAudio without support for input audio. Is build dep ":gl_graph_runner_audio" missing?' ), (o = o || 'input_audio'), this.wrapStringPtr(o, (o) => { (i = i || 'audio_header'), this.wrapStringPtr(i, (i) => { this.wasmModule._configureAudio(o, i, e, t, r); }); }); } setAutoResizeCanvas(e) { this.autoResizeCanvas = e; } setAutoRenderToScreen(e) { this.wasmModule._setAutoRenderToScreen(e); } bindTextureToStream(e, t) { if (!this.wasmModule.canvas) throw new Error('No OpenGL canvas configured.'); t ? this.wasmModule._bindTextureToStream(t) : console.assert(this.wasmModule._bindTextureToCanvas()); const r = this.wasmModule.canvas.getContext('webgl2') || this.wasmModule.canvas.getContext('webgl'); if (!r) throw new Error( 'Failed to obtain WebGL context from the provided canvas. `getContext()` should only be invoked with `webgl` or `webgl2`.' ); let o, i; return ( r.texImage2D(r.TEXTURE_2D, 0, r.RGBA, r.RGBA, r.UNSIGNED_BYTE, e), e.videoWidth ? ((o = e.videoWidth), (i = e.videoHeight)) : e.naturalWidth ? ((o = e.naturalWidth), (i = e.naturalHeight)) : ((o = e.width), (i = e.height)), !this.autoResizeCanvas || (o === this.wasmModule.canvas.width && i === this.wasmModule.canvas.height) || ((this.wasmModule.canvas.width = o), (this.wasmModule.canvas.height = i)), [o, i] ); } processGl(e, t) { const [r, o] = this.bindTextureToStream(e), i = this.wasmModule._malloc(16); (this.wasmModule.HEAPU32[i / 4] = r), (this.wasmModule.HEAPU32[i / 4 + 1] = o), (this.wasmModule.HEAPF64[i / 8 + 1] = t), this.wasmModule._processGl(i), this.wasmModule._free(i); } wrapStringPtr(e, t) { this.hasMultiStreamSupport || console.error( 'No wasm multistream support detected: ensure dependency inclusion of :gl_graph_runner_internal_multi_input target' ); const r = this.wasmModule.stringToNewUTF8(e); t(r), this.wasmModule._free(r); } wrapStringPtrPtr(e, t) { this.hasMultiStreamSupport || console.error( 'No wasm multistream support detected: ensure dependency inclusion of :gl_graph_runner_internal_multi_input target' ); const r = new Uint32Array(e.length); for (let t = 0; t < e.length; t++) r[t] = this.wasmModule.stringToNewUTF8(e[t]); const o = this.wasmModule._malloc(4 * r.length); this.wasmModule.HEAPU32.set(r, o >> 2), t(o); for (const e of r) this.wasmModule._free(e); this.wasmModule._free(o); } getCalculatorGraphConfig(t, r) { const o = e.CALCULATOR_GRAPH_CONFIG_LISTENER_NAME; this.setListener(o, (e) => { t(e); }), this.wrapStringPtr(o, (e) => { this.wasmModule._getGraphConfig(e, r); }), delete this.wasmModule.simpleListeners[o]; } setListener(e, t) { (this.wasmModule.simpleListeners = this.wasmModule.simpleListeners || {}), (this.wasmModule.simpleListeners[e] = t); } setVectorListener(e, t) { let r = []; (this.wasmModule.simpleListeners = this.wasmModule.simpleListeners || {}), (this.wasmModule.simpleListeners[e] = (e, o, i) => { o ? (t(r, i), (r = [])) : r.push(e); }); } attachErrorListener(e) { this.wasmModule.errorListener = e; } attachEmptyPacketListener(e, t) { (this.wasmModule.emptyPacketListeners = this.wasmModule.emptyPacketListeners || {}), (this.wasmModule.emptyPacketListeners[e] = t); } addAudioToStream(e, t, r) { this.addAudioToStreamWithShape(e, 0, 0, t, r); } addAudioToStreamWithShape(e, t, r, o, i) { const a = 4 * e.length; this.audioSize !== a && (this.audioPtr && this.wasmModule._free(this.audioPtr), (this.audioPtr = this.wasmModule._malloc(a)), (this.audioSize = a)), this.wasmModule.HEAPF32.set(e, this.audioPtr / 4), this.wrapStringPtr(o, (e) => { this.wasmModule._addAudioToInputStream(this.audioPtr, t, r, e, i); }); } addGpuBufferToStream(e, t, r) { this.wrapStringPtr(t, (t) => { const [o, i] = this.bindTextureToStream(e, t); this.wasmModule._addBoundTextureToStream(t, o, i, r); }); } addBoolToStream(e, t, r) { this.wrapStringPtr(t, (t) => { this.wasmModule._addBoolToInputStream(e, t, r); }); } addDoubleToStream(e, t, r) { this.wrapStringPtr(t, (t) => { this.wasmModule._addDoubleToInputStream(e, t, r); }); } addFloatToStream(e, t, r) { this.wrapStringPtr(t, (t) => { this.wasmModule._addFloatToInputStream(e, t, r); }); } addIntToStream(e, t, r) { this.wrapStringPtr(t, (t) => { this.wasmModule._addIntToInputStream(e, t, r); }); } addStringToStream(e, t, r) { this.wrapStringPtr(t, (t) => { this.wrapStringPtr(e, (e) => { this.wasmModule._addStringToInputStream(e, t, r); }); }); } addStringRecordToStream(e, t, r) { this.wrapStringPtr(t, (t) => { this.wrapStringPtrPtr(Object.keys(e), (o) => { this.wrapStringPtrPtr(Object.values(e), (i) => { this.wasmModule._addFlatHashMapToInputStream( o, i, Object.keys(e).length, t, r ); }); }); }); } addProtoToStream(e, t, r, o) { this.wrapStringPtr(r, (r) => { this.wrapStringPtr(t, (t) => { const i = this.wasmModule._malloc(e.length); this.wasmModule.HEAPU8.set(e, i), this.wasmModule._addProtoToInputStream(i, e.length, t, r, o), this.wasmModule._free(i); }); }); } addEmptyPacketToStream(e, t) { this.wrapStringPtr(e, (e) => { this.wasmModule._addEmptyPacketToInputStream(e, t); }); } addBoolToInputSidePacket(e, t) { this.wrapStringPtr(t, (t) => { this.wasmModule._addBoolToInputSidePacket(e, t); }); } addDoubleToInputSidePacket(e, t) { this.wrapStringPtr(t, (t) => { this.wasmModule._addDoubleToInputSidePacket(e, t); }); } addFloatToInputSidePacket(e, t) { this.wrapStringPtr(t, (t) => { this.wasmModule._addFloatToInputSidePacket(e, t); }); } addIntToInputSidePacket(e, t) { this.wrapStringPtr(t, (t) => { this.wasmModule._addIntToInputSidePacket(e, t); }); } addStringToInputSidePacket(e, t) { this.wrapStringPtr(t, (t) => { this.wrapStringPtr(e, (e) => { this.wasmModule._addStringToInputSidePacket(e, t); }); }); } addProtoToInputSidePacket(e, t, r) { this.wrapStringPtr(r, (r) => { this.wrapStringPtr(t, (t) => { const o = this.wasmModule._malloc(e.length); this.wasmModule.HEAPU8.set(e, o), this.wasmModule._addProtoToInputSidePacket(o, e.length, t, r), this.wasmModule._free(o); }); }); } attachBoolListener(e, t) { this.setListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmModule._attachBoolListener(e); }); } attachBoolVectorListener(e, t) { this.setVectorListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmModule._attachBoolVectorListener(e); }); } attachIntListener(e, t) { this.setListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmModule._attachIntListener(e); }); } attachIntVectorListener(e, t) { this.setVectorListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmModule._attachIntVectorListener(e); }); } attachDoubleListener(e, t) { this.setListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmModule._attachDoubleListener(e); }); } attachDoubleVectorListener(e, t) { this.setVectorListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmModule._attachDoubleVectorListener(e); }); } attachFloatListener(e, t) { this.setListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmModule._attachFloatListener(e); }); } attachFloatVectorListener(e, t) { this.setVectorListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmModule._attachFloatVectorListener(e); }); } attachStringListener(e, t) { this.setListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmModule._attachStringListener(e); }); } attachStringVectorListener(e, t) { this.setVectorListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmModule._attachStringVectorListener(e); }); } attachProtoListener(e, t, r) { this.setListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmModule._attachProtoListener(e, r || !1); }); } attachProtoVectorListener(e, t, r) { this.setVectorListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmModule._attachProtoVectorListener(e, r || !1); }); } attachAudioListener(e, t, r) { this.wasmModule._attachAudioListener || console.warn( 'Attempting to use attachAudioListener without support for output audio. Is build dep ":gl_graph_runner_audio_out" missing?' ), this.setListener(e, (e, r) => { const o = new Float32Array(e.buffer, e.byteOffset, e.length / 4); t(o, r); }), this.wrapStringPtr(e, (e) => { this.wasmModule._attachAudioListener(e, r || !1); }); } finishProcessing() { this.wasmModule._waitUntilIdle(); } closeGraph() { this.wasmModule._closeGraph(), (this.wasmModule.simpleListeners = void 0), (this.wasmModule.emptyPacketListeners = void 0); } } async function o(e) { if ('function' != typeof importScripts) { const t = document.createElement('script'); return ( t.setAttribute('src', e), t.setAttribute('crossorigin', 'anonymous'), new Promise((e) => { t.addEventListener( 'load', () => { e(); }, !1 ), t.addEventListener( 'error', () => { e(); }, !1 ), document.body.appendChild(t); }) ); } importScripts(e.toString()); } async function i(e, t, r, i, a) { const n = []; if ( (t && n.push(t), r && n.push(r), n.length && (await Promise.all(n.map(o))), !self.ModuleFactory) ) throw new Error('ModuleFactory not set.'); if (self.Module && a) { const e = self.Module; (e.locateFile = a.locateFile), a.mainScriptUrlOrBlob && (e.mainScriptUrlOrBlob = a.mainScriptUrlOrBlob); } const s = await self.ModuleFactory(self.Module || a); return (self.ModuleFactory = self.Module = void 0), new e(s, i); } (e.GraphRunner = r), (e.createMediaPipeLib = i), (e.createGraphRunner = async function(e, t, o, a) { return i(r, e, t, o, a); }); })(graph_runner); var register_model_resources_graph_service = {}; function SupportModelResourcesGraphService(e) { return class extends e { registerModelResourcesGraphService() { this.wasmModule._registerModelResourcesGraphService(); } }; } Object.defineProperty(register_model_resources_graph_service, '__esModule', { value: !0 }), (register_model_resources_graph_service.SupportModelResourcesGraphService = void 0), (register_model_resources_graph_service.SupportModelResourcesGraphService = SupportModelResourcesGraphService), Object.defineProperty(task_runner, '__esModule', { value: !0 }), (task_runner.TaskRunner = task_runner.createTaskRunner = task_runner.CachedGraphRunner = void 0); const inference_calculator_pb_1 = inference_calculator_pb, calculator_pb_1 = calculator_pb, acceleration_pb_1 = acceleration_pb, external_file_pb_1 = external_file_pb, graph_runner_1$1 = graph_runner, register_model_resources_graph_service_1$1 = register_model_resources_graph_service, NO_ASSETS = void 0, FREE_MEMORY_STREAM = 'free_memory', UNUSED_STREAM_SUFFIX = '_unused_out', CachedGraphRunnerType = (0, register_model_resources_graph_service_1$1.SupportModelResourcesGraphService)( graph_runner_1$1.GraphRunner ); class CachedGraphRunner extends CachedGraphRunnerType {} async function createTaskRunner(e, t, r, o) { const i = { locateFile: () => r.wasmBinaryPath.toString() }, a = await (0, graph_runner_1$1.createMediaPipeLib)(e, r.wasmLoaderPath, NO_ASSETS, t, i); return await a.setOptions(o), a; } (task_runner.CachedGraphRunner = CachedGraphRunner), (task_runner.createTaskRunner = createTaskRunner); class TaskRunner { static async createInstance(e, t, r, o) { return createTaskRunner(e, t, r, o); } constructor(e) { (this.graphRunner = e), (this.processingErrors = []), (this.latestOutputTimestamp = 0), this.graphRunner.setAutoRenderToScreen(!1); } applyOptions(e) { var t, r, o, i, a, n; const s = e.baseOptions || {}; if ( (null === (t = e.baseOptions) || void 0 === t ? void 0 : t.modelAssetBuffer) && (null === (r = e.baseOptions) || void 0 === r ? void 0 : r.modelAssetPath) ) throw new Error( 'Cannot set both baseOptions.modelAssetPath and baseOptions.modelAssetBuffer' ); if ( !( (null === (o = this.baseOptions.getModelAsset()) || void 0 === o ? void 0 : o.hasFileContent()) || (null === (i = this.baseOptions.getModelAsset()) || void 0 === i ? void 0 : i.hasFileName()) || (null === (a = e.baseOptions) || void 0 === a ? void 0 : a.modelAssetBuffer) || (null === (n = e.baseOptions) || void 0 === n ? void 0 : n.modelAssetPath) ) ) throw new Error( 'Either baseOptions.modelAssetPath or baseOptions.modelAssetBuffer must be set' ); return ( this.setAcceleration(s), s.modelAssetPath ? fetch(s.modelAssetPath.toString()) .then((e) => { if (e.ok) return e.arrayBuffer(); throw new Error( `Failed to fetch model: ${s.modelAssetPath} (${e.status})` ); }) .then((e) => { try { this.graphRunner.wasmModule.FS_unlink('/model.dat'); } catch (e) {} this.graphRunner.wasmModule.FS_createDataFile( '/', 'model.dat', new Uint8Array(e), !0, !1, !1 ), this.setExternalFile('/model.dat'), this.refreshGraph(), this.onGraphRefreshed(); }) : (this.setExternalFile(s.modelAssetBuffer), this.refreshGraph(), this.onGraphRefreshed(), Promise.resolve()) ); } onGraphRefreshed() {} getCalculatorGraphConfig() { let e; if ( (this.graphRunner.getCalculatorGraphConfig((t) => { e = calculator_pb_1.CalculatorGraphConfig.deserializeBinary(t); }), !e) ) throw new Error('Failed to retrieve CalculatorGraphConfig'); return e; } setGraph(e, t) { this.graphRunner.attachErrorListener((e, t) => { this.processingErrors.push(new Error(t)); }), this.graphRunner.registerModelResourcesGraphService(), this.graphRunner.setGraph(e, t), (this.keepaliveNode = void 0), this.handleErrors(); } finishProcessing() { this.graphRunner.finishProcessing(), this.handleErrors(); } setLatestOutputTimestamp(e) { this.latestOutputTimestamp = Math.max(this.latestOutputTimestamp, e); } getSynctheticTimestamp() { return this.latestOutputTimestamp + 1; } handleErrors() { try { const e = this.processingErrors.length; if (1 === e) throw new Error(this.processingErrors[0].message); if (e > 1) throw new Error( 'Encountered multiple errors: ' + this.processingErrors.map((e) => e.message).join(', ') ); } finally { this.processingErrors = []; } } setExternalFile(e) { const t = this.baseOptions.getModelAsset() || new external_file_pb_1.ExternalFile(); 'string' == typeof e ? (t.setFileName(e), t.clearFileContent()) : e instanceof Uint8Array && (t.setFileContent(e), t.clearFileName()), this.baseOptions.setModelAsset(t); } setAcceleration(e) { let t = this.baseOptions.getAcceleration(); t || ((t = new acceleration_pb_1.Acceleration()), t.setTflite( new inference_calculator_pb_1.InferenceCalculatorOptions.Delegate.TfLite() )), 'delegate' in e && ('GPU' === e.delegate ? t.setGpu( new inference_calculator_pb_1.InferenceCalculatorOptions.Delegate.Gpu() ) : t.setTflite( new inference_calculator_pb_1.InferenceCalculatorOptions.Delegate.TfLite() )), this.baseOptions.setAcceleration(t); } addKeepaliveNode(e) { (this.keepaliveNode = new calculator_pb_1.CalculatorGraphConfig.Node()), this.keepaliveNode.setCalculator('PassThroughCalculator'), this.keepaliveNode.addInputStream(FREE_MEMORY_STREAM), this.keepaliveNode.addOutputStream(FREE_MEMORY_STREAM + UNUSED_STREAM_SUFFIX), e.addInputStream(FREE_MEMORY_STREAM), e.addNode(this.keepaliveNode); } keepStreamAlive(e) { this.keepaliveNode.addInputStream(e), this.keepaliveNode.addOutputStream(e + UNUSED_STREAM_SUFFIX); } freeKeepaliveStreams() { this.graphRunner.addBoolToStream(!0, FREE_MEMORY_STREAM, this.latestOutputTimestamp); } close() { (this.keepaliveNode = void 0), this.graphRunner.closeGraph(); } } task_runner.TaskRunner = TaskRunner; var graph_runner_image_lib = {}; function SupportImage(e) { return class extends e { get wasmImageModule() { return this.wasmModule; } addGpuBufferAsImageToStream(e, t, r) { this.wrapStringPtr(t, (t) => { const [o, i] = this.bindTextureToStream(e, t); this.wasmImageModule._addBoundTextureAsImageToStream(t, o, i, r); }); } attachImageListener(e, t) { this.setListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmImageModule._attachImageListener(e); }); } attachImageVectorListener(e, t) { this.setVectorListener(e, t), this.wrapStringPtr(e, (e) => { this.wasmImageModule._attachImageVectorListener(e); }); } }; } Object.defineProperty(graph_runner_image_lib, '__esModule', { value: !0 }), (graph_runner_image_lib.SupportImage = void 0), (graph_runner_image_lib.SupportImage = SupportImage), Object.defineProperty(vision_task_runner, '__esModule', { value: !0 }), (vision_task_runner.VisionTaskRunner = vision_task_runner.VisionGraphRunner = void 0); const rect_pb_1 = rect_pb, task_runner_1 = task_runner, image_1$1 = image, image_shader_context_1 = image_shader_context, mask_1$1 = mask, graph_runner_1 = graph_runner, graph_runner_image_lib_1 = graph_runner_image_lib, platform_utils_1 = platform_utils, register_model_resources_graph_service_1 = register_model_resources_graph_service, GraphRunnerVisionType = (0, register_model_resources_graph_service_1.SupportModelResourcesGraphService)( (0, graph_runner_image_lib_1.SupportImage)(graph_runner_1.GraphRunner) ); class VisionGraphRunner extends GraphRunnerVisionType {} function createCanvas() { return 'undefined' != typeof OffscreenCanvas && !(0, platform_utils_1.isWebKit)() ? void 0 : document.createElement('canvas'); } vision_task_runner.VisionGraphRunner = VisionGraphRunner; class VisionTaskRunner extends task_runner_1.TaskRunner { static async createVisionInstance(e, t, r) { var o; const i = null !== (o = r.canvas) && void 0 !== o ? o : createCanvas(); return task_runner_1.TaskRunner.createInstance(e, i, t, r); } constructor(e, t, r, o) { super(e), (this.graphRunner = e), (this.imageStreamName = t), (this.normRectStreamName = r), (this.roiAllowed = o), (this.shaderContext = new image_shader_context_1.MPImageShaderContext()); } applyOptions(e) { if ('runningMode' in e) { const t = !!e.runningMode && 'IMAGE' !== e.runningMode; this.baseOptions.setUseStreamMode(t); } if (void 0 !== e.canvas && this.graphRunner.wasmModule.canvas !== e.canvas) throw new Error('You must create a new task to reset the canvas.'); return super.applyOptions(e); } processImageData(e, t) { var r; if (null === (r = this.baseOptions) || void 0 === r ? void 0 : r.getUseStreamMode()) throw new Error( "Task is not initialized with image mode. 'runningMode' must be set to 'IMAGE'." ); this.process(e, t, this.getSynctheticTimestamp()); } processVideoData(e, t, r) { var o; if (!(null === (o = this.baseOptions) || void 0 === o ? void 0 : o.getUseStreamMode())) throw new Error( "Task is not initialized with video mode. 'runningMode' must be set to 'VIDEO'." ); this.process(e, t, r); } getImageSourceSize(e) { return void 0 !== e.videoWidth ? [e.videoWidth, e.videoHeight] : void 0 !== e.naturalWidth ? [e.naturalWidth, e.naturalHeight] : [e.width, e.height]; } convertToNormalizedRect(e, t) { const r = new rect_pb_1.NormalizedRect(); if (null == t ? void 0 : t.regionOfInterest) { if (!this.roiAllowed) throw new Error("This task doesn't support region-of-interest."); const e = t.regionOfInterest; if (e.left >= e.right || e.top >= e.bottom) throw new Error('Expected RectF with left < right and top < bottom.'); if (e.left < 0 || e.top < 0 || e.right > 1 || e.bottom > 1) throw new Error('Expected RectF values to be in [0,1].'); r.setXCenter((e.left + e.right) / 2), r.setYCenter((e.top + e.bottom) / 2), r.setWidth(e.right - e.left), r.setHeight(e.bottom - e.top); } else r.setXCenter(0.5), r.setYCenter(0.5), r.setWidth(1), r.setHeight(1); if (null == t ? void 0 : t.rotationDegrees) { if ((null == t ? void 0 : t.rotationDegrees) % 90 != 0) throw new Error('Expected rotation to be a multiple of 90°.'); if ( (r.setRotation((-Math.PI * t.rotationDegrees) / 180), (null == t ? void 0 : t.rotationDegrees) % 180 != 0) ) { const [t, o] = this.getImageSourceSize(e), i = (r.getHeight() * o) / t, a = (r.getWidth() * t) / o; r.setWidth(i), r.setHeight(a); } } return r; } process(e, t, r) { const o = this.convertToNormalizedRect(e, t); this.graphRunner.addProtoToStream( o.serializeBinary(), 'mediapipe.NormalizedRect', this.normRectStreamName, r ), this.graphRunner.addGpuBufferAsImageToStream( e, this.imageStreamName, null != r ? r : performance.now() ), this.finishProcessing(); } convertToMPImage(e, t) { const { data: r, width: o, height: i } = e, a = o * i; let n; if (r instanceof Uint8Array) if (r.length === 3 * a) { const e = new Uint8ClampedArray(4 * a); for (let t = 0; t < a; ++t) (e[4 * t] = r[3 * t]), (e[4 * t + 1] = r[3 * t + 1]), (e[4 * t + 2] = r[3 * t + 2]), (e[4 * t + 3] = 255); n = new ImageData(e, o, i); } else { if (r.length !== 4 * a) throw new Error('Unsupported channel count: ' + r.length / a); n = new ImageData(new Uint8ClampedArray(r.buffer, r.byteOffset, r.length), o, i); } else { if (!(r instanceof WebGLTexture)) throw new Error(`Unsupported format: ${r.constructor.name}`); n = r; } const s = new image_1$1.MPImage( [n], !1, !1, this.graphRunner.wasmModule.canvas, this.shaderContext, o, i ); return t ? s.clone() : s; } convertToMPMask(e, t) { const { data: r, width: o, height: i } = e, a = o * i; let n; if (r instanceof Uint8Array || r instanceof Float32Array) { if (r.length !== a) throw new Error('Unsupported channel count: ' + r.length / a); n = r; } else n = r; const s = new mask_1$1.MPMask( [n], !1, this.graphRunner.wasmModule.canvas, this.shaderContext, o, i ); return t ? s.clone() : s; } close() { this.shaderContext.close(), super.close(); } } vision_task_runner.VisionTaskRunner = VisionTaskRunner; var face_detector_options = {}; Object.defineProperty(face_detector_options, '__esModule', { value: !0 }); var face_detector_result = {}; Object.defineProperty(face_detector_result, '__esModule', { value: !0 }), (function(e) { var t = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? function(e, t, r, o) { void 0 === o && (o = r); var i = Object.getOwnPropertyDescriptor(t, r); (i && !('get' in i ? !t.__esModule : i.writable || i.configurable)) || (i = { enumerable: !0, get: function() { return t[r]; }, }), Object.defineProperty(e, o, i); } : function(e, t, r, o) { void 0 === o && (o = r), (e[o] = t[r]); }), r = (commonjsGlobal && commonjsGlobal.__exportStar) || function(e, r) { for (var o in e) 'default' === o || Object.prototype.hasOwnProperty.call(r, o) || t(r, e, o); }; Object.defineProperty(e, '__esModule', { value: !0 }), (e.FaceDetector = void 0); const o = calculator_pb, i = calculator_options_pb, a = detection_pb, n = base_options_pb, s = face_detector_graph_options_pb, p = detection_result, d = vision_task_runner, l = 'image_in', g = 'norm_rect_in', c = 'detections'; r(face_detector_options, e), r(face_detector_result, e); class u extends d.VisionTaskRunner { static createFromOptions(e, t) { return d.VisionTaskRunner.createVisionInstance(u, e, t); } static createFromModelBuffer(e, t) { return d.VisionTaskRunner.createVisionInstance(u, e, { baseOptions: { modelAssetBuffer: t }, }); } static async createFromModelPath(e, t) { return d.VisionTaskRunner.createVisionInstance(u, e, { baseOptions: { modelAssetPath: t }, }); } constructor(e, t) { super(new d.VisionGraphRunner(e, t), l, g, !1), (this.result = { detections: [] }), (this.options = new s.FaceDetectorGraphOptions()), this.options.setBaseOptions(new n.BaseOptions()), this.options.setMinDetectionConfidence(0.5), this.options.setMinSuppressionThreshold(0.3); } get baseOptions() { return this.options.getBaseOptions(); } set baseOptions(e) { this.options.setBaseOptions(e); } setOptions(e) { var t, r; return ( 'minDetectionConfidence' in e && this.options.setMinDetectionConfidence( null !== (t = e.minDetectionConfidence) && void 0 !== t ? t : 0.5 ), 'minSuppressionThreshold' in e && this.options.setMinSuppressionThreshold( null !== (r = e.minSuppressionThreshold) && void 0 !== r ? r : 0.3 ), this.applyOptions(e) ); } detect(e, t) { return (this.result = { detections: [] }), this.processImageData(e, t), this.result; } detectForVideo(e, t, r) { return ( (this.result = { detections: [] }), this.processVideoData(e, r, t), this.result ); } addJsFaceDetections(e) { for (const t of e) { const e = a.Detection.deserializeBinary(t); this.result.detections.push((0, p.convertFromDetectionProto)(e)); } } refreshGraph() { const e = new o.CalculatorGraphConfig(); e.addInputStream(l), e.addInputStream(g), e.addOutputStream(c); const t = new i.CalculatorOptions(); t.setExtension(s.FaceDetectorGraphOptions.ext, this.options); const r = new o.CalculatorGraphConfig.Node(); r.setCalculator('mediapipe.tasks.vision.face_detector.FaceDetectorGraph'), r.addInputStream('IMAGE:' + l), r.addInputStream('NORM_RECT:' + g), r.addOutputStream('DETECTIONS:' + c), r.setOptions(t), e.addNode(r), this.graphRunner.attachProtoVectorListener(c, (e, t) => { this.addJsFaceDetections(e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(c, (e) => { this.setLatestOutputTimestamp(e); }); const a = e.serializeBinary(); this.setGraph(new Uint8Array(a), !0); } } e.FaceDetector = u; })(face_detector); var face_landmarker = {}, classification_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.Classification', null, o), r.exportSymbol('proto.mediapipe.ClassificationList', null, o), r.exportSymbol('proto.mediapipe.ClassificationListCollection', null, o), (proto.mediapipe.Classification = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.Classification, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.Classification.displayName = 'proto.mediapipe.Classification'), (proto.mediapipe.ClassificationList = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.ClassificationList.repeatedFields_, null ); }), r.inherits(proto.mediapipe.ClassificationList, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.ClassificationList.displayName = 'proto.mediapipe.ClassificationList'), (proto.mediapipe.ClassificationListCollection = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.ClassificationListCollection.repeatedFields_, null ); }), r.inherits(proto.mediapipe.ClassificationListCollection, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.ClassificationListCollection.displayName = 'proto.mediapipe.ClassificationListCollection'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.Classification.prototype.toObject = function(e) { return proto.mediapipe.Classification.toObject(e, this); }), (proto.mediapipe.Classification.toObject = function(e, r) { var o, i = { index: null == (o = t.Message.getField(r, 1)) ? void 0 : o, score: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, label: null == (o = t.Message.getField(r, 3)) ? void 0 : o, displayName: null == (o = t.Message.getField(r, 4)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.Classification.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.Classification(); return proto.mediapipe.Classification.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.Classification.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readInt32(); e.setIndex(r); break; case 2: r = t.readFloat(); e.setScore(r); break; case 3: r = t.readString(); e.setLabel(r); break; case 4: r = t.readString(); e.setDisplayName(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.Classification.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.Classification.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.Classification.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeInt32(1, o), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o), null != (o = t.Message.getField(e, 3)) && r.writeString(3, o), null != (o = t.Message.getField(e, 4)) && r.writeString(4, o); }), (proto.mediapipe.Classification.prototype.getIndex = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.Classification.prototype.setIndex = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.Classification.prototype.clearIndex = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.Classification.prototype.hasIndex = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.Classification.prototype.getScore = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.Classification.prototype.setScore = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.Classification.prototype.clearScore = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.Classification.prototype.hasScore = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.Classification.prototype.getLabel = function() { return t.Message.getFieldWithDefault(this, 3, ''); }), (proto.mediapipe.Classification.prototype.setLabel = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.Classification.prototype.clearLabel = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.Classification.prototype.hasLabel = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.Classification.prototype.getDisplayName = function() { return t.Message.getFieldWithDefault(this, 4, ''); }), (proto.mediapipe.Classification.prototype.setDisplayName = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.Classification.prototype.clearDisplayName = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.Classification.prototype.hasDisplayName = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.ClassificationList.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.ClassificationList.prototype.toObject = function(e) { return proto.mediapipe.ClassificationList.toObject(e, this); }), (proto.mediapipe.ClassificationList.toObject = function(e, r) { var o = { classificationList: t.Message.toObjectList( r.getClassificationList(), proto.mediapipe.Classification.toObject, e ), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.ClassificationList.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.ClassificationList(); return proto.mediapipe.ClassificationList.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.ClassificationList.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new proto.mediapipe.Classification(); t.readMessage(r, proto.mediapipe.Classification.deserializeBinaryFromReader), e.addClassification(r); } else t.skipField(); } return e; }), (proto.mediapipe.ClassificationList.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.ClassificationList.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.ClassificationList.serializeBinaryToWriter = function(e, t) { var r; (r = e.getClassificationList()).length > 0 && t.writeRepeatedMessage( 1, r, proto.mediapipe.Classification.serializeBinaryToWriter ); }), (proto.mediapipe.ClassificationList.prototype.getClassificationList = function() { return t.Message.getRepeatedWrapperField(this, proto.mediapipe.Classification, 1); }), (proto.mediapipe.ClassificationList.prototype.setClassificationList = function(e) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.ClassificationList.prototype.addClassification = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.Classification, r ); }), (proto.mediapipe.ClassificationList.prototype.clearClassificationList = function() { return this.setClassificationList([]); }), (proto.mediapipe.ClassificationListCollection.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.ClassificationListCollection.prototype.toObject = function(e) { return proto.mediapipe.ClassificationListCollection.toObject(e, this); }), (proto.mediapipe.ClassificationListCollection.toObject = function(e, r) { var o = { classificationListList: t.Message.toObjectList( r.getClassificationListList(), proto.mediapipe.ClassificationList.toObject, e ), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.ClassificationListCollection.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.ClassificationListCollection(); return proto.mediapipe.ClassificationListCollection.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.ClassificationListCollection.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new proto.mediapipe.ClassificationList(); t.readMessage( r, proto.mediapipe.ClassificationList.deserializeBinaryFromReader ), e.addClassificationList(r); } else t.skipField(); } return e; }), (proto.mediapipe.ClassificationListCollection.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.ClassificationListCollection.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.ClassificationListCollection.serializeBinaryToWriter = function(e, t) { var r; (r = e.getClassificationListList()).length > 0 && t.writeRepeatedMessage( 1, r, proto.mediapipe.ClassificationList.serializeBinaryToWriter ); }), (proto.mediapipe.ClassificationListCollection.prototype.getClassificationListList = function() { return t.Message.getRepeatedWrapperField(this, proto.mediapipe.ClassificationList, 1); }), (proto.mediapipe.ClassificationListCollection.prototype.setClassificationListList = function( e ) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.ClassificationListCollection.prototype.addClassificationList = function( e, r ) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.ClassificationList, r ); }), (proto.mediapipe.ClassificationListCollection.prototype.clearClassificationListList = function() { return this.setClassificationListList([]); }), r.object.extend(e, proto.mediapipe); })(classification_pb); var landmark_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.Landmark', null, o), r.exportSymbol('proto.mediapipe.LandmarkList', null, o), r.exportSymbol('proto.mediapipe.LandmarkListCollection', null, o), r.exportSymbol('proto.mediapipe.NormalizedLandmark', null, o), r.exportSymbol('proto.mediapipe.NormalizedLandmarkList', null, o), r.exportSymbol('proto.mediapipe.NormalizedLandmarkListCollection', null, o), (proto.mediapipe.Landmark = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.Landmark, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.Landmark.displayName = 'proto.mediapipe.Landmark'), (proto.mediapipe.LandmarkList = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.LandmarkList.repeatedFields_, null ); }), r.inherits(proto.mediapipe.LandmarkList, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.LandmarkList.displayName = 'proto.mediapipe.LandmarkList'), (proto.mediapipe.LandmarkListCollection = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.LandmarkListCollection.repeatedFields_, null ); }), r.inherits(proto.mediapipe.LandmarkListCollection, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.LandmarkListCollection.displayName = 'proto.mediapipe.LandmarkListCollection'), (proto.mediapipe.NormalizedLandmark = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.NormalizedLandmark, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.NormalizedLandmark.displayName = 'proto.mediapipe.NormalizedLandmark'), (proto.mediapipe.NormalizedLandmarkList = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.NormalizedLandmarkList.repeatedFields_, null ); }), r.inherits(proto.mediapipe.NormalizedLandmarkList, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.NormalizedLandmarkList.displayName = 'proto.mediapipe.NormalizedLandmarkList'), (proto.mediapipe.NormalizedLandmarkListCollection = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.NormalizedLandmarkListCollection.repeatedFields_, null ); }), r.inherits(proto.mediapipe.NormalizedLandmarkListCollection, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.NormalizedLandmarkListCollection.displayName = 'proto.mediapipe.NormalizedLandmarkListCollection'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.Landmark.prototype.toObject = function(e) { return proto.mediapipe.Landmark.toObject(e, this); }), (proto.mediapipe.Landmark.toObject = function(e, r) { var o, i = { x: null == (o = t.Message.getOptionalFloatingPointField(r, 1)) ? void 0 : o, y: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, z: null == (o = t.Message.getOptionalFloatingPointField(r, 3)) ? void 0 : o, visibility: null == (o = t.Message.getOptionalFloatingPointField(r, 4)) ? void 0 : o, presence: null == (o = t.Message.getOptionalFloatingPointField(r, 5)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.Landmark.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.Landmark(); return proto.mediapipe.Landmark.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.Landmark.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readFloat(); e.setX(r); break; case 2: r = t.readFloat(); e.setY(r); break; case 3: r = t.readFloat(); e.setZ(r); break; case 4: r = t.readFloat(); e.setVisibility(r); break; case 5: r = t.readFloat(); e.setPresence(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.Landmark.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return proto.mediapipe.Landmark.serializeBinaryToWriter(this, e), e.getResultBuffer(); }), (proto.mediapipe.Landmark.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeFloat(1, o), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o), null != (o = t.Message.getField(e, 3)) && r.writeFloat(3, o), null != (o = t.Message.getField(e, 4)) && r.writeFloat(4, o), null != (o = t.Message.getField(e, 5)) && r.writeFloat(5, o); }), (proto.mediapipe.Landmark.prototype.getX = function() { return t.Message.getFloatingPointFieldWithDefault(this, 1, 0); }), (proto.mediapipe.Landmark.prototype.setX = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.Landmark.prototype.clearX = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.Landmark.prototype.hasX = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.Landmark.prototype.getY = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.Landmark.prototype.setY = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.Landmark.prototype.clearY = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.Landmark.prototype.hasY = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.Landmark.prototype.getZ = function() { return t.Message.getFloatingPointFieldWithDefault(this, 3, 0); }), (proto.mediapipe.Landmark.prototype.setZ = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.Landmark.prototype.clearZ = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.Landmark.prototype.hasZ = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.Landmark.prototype.getVisibility = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0); }), (proto.mediapipe.Landmark.prototype.setVisibility = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.Landmark.prototype.clearVisibility = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.Landmark.prototype.hasVisibility = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.Landmark.prototype.getPresence = function() { return t.Message.getFloatingPointFieldWithDefault(this, 5, 0); }), (proto.mediapipe.Landmark.prototype.setPresence = function(e) { return t.Message.setField(this, 5, e); }), (proto.mediapipe.Landmark.prototype.clearPresence = function() { return t.Message.setField(this, 5, void 0); }), (proto.mediapipe.Landmark.prototype.hasPresence = function() { return null != t.Message.getField(this, 5); }), (proto.mediapipe.LandmarkList.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.LandmarkList.prototype.toObject = function(e) { return proto.mediapipe.LandmarkList.toObject(e, this); }), (proto.mediapipe.LandmarkList.toObject = function(e, r) { var o = { landmarkList: t.Message.toObjectList( r.getLandmarkList(), proto.mediapipe.Landmark.toObject, e ), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.LandmarkList.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.LandmarkList(); return proto.mediapipe.LandmarkList.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.LandmarkList.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new proto.mediapipe.Landmark(); t.readMessage(r, proto.mediapipe.Landmark.deserializeBinaryFromReader), e.addLandmark(r); } else t.skipField(); } return e; }), (proto.mediapipe.LandmarkList.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.LandmarkList.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.LandmarkList.serializeBinaryToWriter = function(e, t) { var r; (r = e.getLandmarkList()).length > 0 && t.writeRepeatedMessage(1, r, proto.mediapipe.Landmark.serializeBinaryToWriter); }), (proto.mediapipe.LandmarkList.prototype.getLandmarkList = function() { return t.Message.getRepeatedWrapperField(this, proto.mediapipe.Landmark, 1); }), (proto.mediapipe.LandmarkList.prototype.setLandmarkList = function(e) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.LandmarkList.prototype.addLandmark = function(e, r) { return t.Message.addToRepeatedWrapperField(this, 1, e, proto.mediapipe.Landmark, r); }), (proto.mediapipe.LandmarkList.prototype.clearLandmarkList = function() { return this.setLandmarkList([]); }), (proto.mediapipe.LandmarkListCollection.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.LandmarkListCollection.prototype.toObject = function(e) { return proto.mediapipe.LandmarkListCollection.toObject(e, this); }), (proto.mediapipe.LandmarkListCollection.toObject = function(e, r) { var o = { landmarkListList: t.Message.toObjectList( r.getLandmarkListList(), proto.mediapipe.LandmarkList.toObject, e ), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.LandmarkListCollection.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.LandmarkListCollection(); return proto.mediapipe.LandmarkListCollection.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.LandmarkListCollection.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new proto.mediapipe.LandmarkList(); t.readMessage(r, proto.mediapipe.LandmarkList.deserializeBinaryFromReader), e.addLandmarkList(r); } else t.skipField(); } return e; }), (proto.mediapipe.LandmarkListCollection.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.LandmarkListCollection.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.LandmarkListCollection.serializeBinaryToWriter = function(e, t) { var r; (r = e.getLandmarkListList()).length > 0 && t.writeRepeatedMessage(1, r, proto.mediapipe.LandmarkList.serializeBinaryToWriter); }), (proto.mediapipe.LandmarkListCollection.prototype.getLandmarkListList = function() { return t.Message.getRepeatedWrapperField(this, proto.mediapipe.LandmarkList, 1); }), (proto.mediapipe.LandmarkListCollection.prototype.setLandmarkListList = function(e) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.LandmarkListCollection.prototype.addLandmarkList = function(e, r) { return t.Message.addToRepeatedWrapperField(this, 1, e, proto.mediapipe.LandmarkList, r); }), (proto.mediapipe.LandmarkListCollection.prototype.clearLandmarkListList = function() { return this.setLandmarkListList([]); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.NormalizedLandmark.prototype.toObject = function(e) { return proto.mediapipe.NormalizedLandmark.toObject(e, this); }), (proto.mediapipe.NormalizedLandmark.toObject = function(e, r) { var o, i = { x: null == (o = t.Message.getOptionalFloatingPointField(r, 1)) ? void 0 : o, y: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, z: null == (o = t.Message.getOptionalFloatingPointField(r, 3)) ? void 0 : o, visibility: null == (o = t.Message.getOptionalFloatingPointField(r, 4)) ? void 0 : o, presence: null == (o = t.Message.getOptionalFloatingPointField(r, 5)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.NormalizedLandmark.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.NormalizedLandmark(); return proto.mediapipe.NormalizedLandmark.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.NormalizedLandmark.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readFloat(); e.setX(r); break; case 2: r = t.readFloat(); e.setY(r); break; case 3: r = t.readFloat(); e.setZ(r); break; case 4: r = t.readFloat(); e.setVisibility(r); break; case 5: r = t.readFloat(); e.setPresence(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.NormalizedLandmark.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.NormalizedLandmark.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.NormalizedLandmark.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeFloat(1, o), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o), null != (o = t.Message.getField(e, 3)) && r.writeFloat(3, o), null != (o = t.Message.getField(e, 4)) && r.writeFloat(4, o), null != (o = t.Message.getField(e, 5)) && r.writeFloat(5, o); }), (proto.mediapipe.NormalizedLandmark.prototype.getX = function() { return t.Message.getFloatingPointFieldWithDefault(this, 1, 0); }), (proto.mediapipe.NormalizedLandmark.prototype.setX = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.NormalizedLandmark.prototype.clearX = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.NormalizedLandmark.prototype.hasX = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.NormalizedLandmark.prototype.getY = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.NormalizedLandmark.prototype.setY = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.NormalizedLandmark.prototype.clearY = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.NormalizedLandmark.prototype.hasY = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.NormalizedLandmark.prototype.getZ = function() { return t.Message.getFloatingPointFieldWithDefault(this, 3, 0); }), (proto.mediapipe.NormalizedLandmark.prototype.setZ = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.NormalizedLandmark.prototype.clearZ = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.NormalizedLandmark.prototype.hasZ = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.NormalizedLandmark.prototype.getVisibility = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0); }), (proto.mediapipe.NormalizedLandmark.prototype.setVisibility = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.NormalizedLandmark.prototype.clearVisibility = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.NormalizedLandmark.prototype.hasVisibility = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.NormalizedLandmark.prototype.getPresence = function() { return t.Message.getFloatingPointFieldWithDefault(this, 5, 0); }), (proto.mediapipe.NormalizedLandmark.prototype.setPresence = function(e) { return t.Message.setField(this, 5, e); }), (proto.mediapipe.NormalizedLandmark.prototype.clearPresence = function() { return t.Message.setField(this, 5, void 0); }), (proto.mediapipe.NormalizedLandmark.prototype.hasPresence = function() { return null != t.Message.getField(this, 5); }), (proto.mediapipe.NormalizedLandmarkList.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.NormalizedLandmarkList.prototype.toObject = function(e) { return proto.mediapipe.NormalizedLandmarkList.toObject(e, this); }), (proto.mediapipe.NormalizedLandmarkList.toObject = function(e, r) { var o = { landmarkList: t.Message.toObjectList( r.getLandmarkList(), proto.mediapipe.NormalizedLandmark.toObject, e ), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.NormalizedLandmarkList.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.NormalizedLandmarkList(); return proto.mediapipe.NormalizedLandmarkList.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.NormalizedLandmarkList.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new proto.mediapipe.NormalizedLandmark(); t.readMessage( r, proto.mediapipe.NormalizedLandmark.deserializeBinaryFromReader ), e.addLandmark(r); } else t.skipField(); } return e; }), (proto.mediapipe.NormalizedLandmarkList.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.NormalizedLandmarkList.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.NormalizedLandmarkList.serializeBinaryToWriter = function(e, t) { var r; (r = e.getLandmarkList()).length > 0 && t.writeRepeatedMessage( 1, r, proto.mediapipe.NormalizedLandmark.serializeBinaryToWriter ); }), (proto.mediapipe.NormalizedLandmarkList.prototype.getLandmarkList = function() { return t.Message.getRepeatedWrapperField(this, proto.mediapipe.NormalizedLandmark, 1); }), (proto.mediapipe.NormalizedLandmarkList.prototype.setLandmarkList = function(e) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.NormalizedLandmarkList.prototype.addLandmark = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.NormalizedLandmark, r ); }), (proto.mediapipe.NormalizedLandmarkList.prototype.clearLandmarkList = function() { return this.setLandmarkList([]); }), (proto.mediapipe.NormalizedLandmarkListCollection.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.NormalizedLandmarkListCollection.prototype.toObject = function(e) { return proto.mediapipe.NormalizedLandmarkListCollection.toObject(e, this); }), (proto.mediapipe.NormalizedLandmarkListCollection.toObject = function(e, r) { var o = { landmarkListList: t.Message.toObjectList( r.getLandmarkListList(), proto.mediapipe.NormalizedLandmarkList.toObject, e ), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.NormalizedLandmarkListCollection.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.NormalizedLandmarkListCollection(); return proto.mediapipe.NormalizedLandmarkListCollection.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.NormalizedLandmarkListCollection.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new proto.mediapipe.NormalizedLandmarkList(); t.readMessage( r, proto.mediapipe.NormalizedLandmarkList.deserializeBinaryFromReader ), e.addLandmarkList(r); } else t.skipField(); } return e; }), (proto.mediapipe.NormalizedLandmarkListCollection.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.NormalizedLandmarkListCollection.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.NormalizedLandmarkListCollection.serializeBinaryToWriter = function(e, t) { var r; (r = e.getLandmarkListList()).length > 0 && t.writeRepeatedMessage( 1, r, proto.mediapipe.NormalizedLandmarkList.serializeBinaryToWriter ); }), (proto.mediapipe.NormalizedLandmarkListCollection.prototype.getLandmarkListList = function() { return t.Message.getRepeatedWrapperField( this, proto.mediapipe.NormalizedLandmarkList, 1 ); }), (proto.mediapipe.NormalizedLandmarkListCollection.prototype.setLandmarkListList = function( e ) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.NormalizedLandmarkListCollection.prototype.addLandmarkList = function( e, r ) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.NormalizedLandmarkList, r ); }), (proto.mediapipe.NormalizedLandmarkListCollection.prototype.clearLandmarkListList = function() { return this.setLandmarkListList([]); }), r.object.extend(e, proto.mediapipe); })(landmark_pb); var face_geometry_pb = {}, matrix_data_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.MatrixData', null, o), r.exportSymbol('proto.mediapipe.MatrixData.Layout', null, o), (proto.mediapipe.MatrixData = function(e) { t.Message.initialize(this, e, 0, -1, proto.mediapipe.MatrixData.repeatedFields_, null); }), r.inherits(proto.mediapipe.MatrixData, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.MatrixData.displayName = 'proto.mediapipe.MatrixData'), (proto.mediapipe.MatrixData.repeatedFields_ = [3]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.MatrixData.prototype.toObject = function(e) { return proto.mediapipe.MatrixData.toObject(e, this); }), (proto.mediapipe.MatrixData.toObject = function(e, r) { var o, i = { rows: null == (o = t.Message.getField(r, 1)) ? void 0 : o, cols: null == (o = t.Message.getField(r, 2)) ? void 0 : o, packedDataList: null == (o = t.Message.getRepeatedFloatingPointField(r, 3)) ? void 0 : o, layout: t.Message.getFieldWithDefault(r, 4, 0), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.MatrixData.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.MatrixData(); return proto.mediapipe.MatrixData.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.MatrixData.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readInt32(); e.setRows(r); break; case 2: r = t.readInt32(); e.setCols(r); break; case 3: for ( var o = t.isDelimited() ? t.readPackedFloat() : [t.readFloat()], i = 0; i < o.length; i++ ) e.addPackedData(o[i]); break; case 4: r = t.readEnum(); e.setLayout(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.MatrixData.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return proto.mediapipe.MatrixData.serializeBinaryToWriter(this, e), e.getResultBuffer(); }), (proto.mediapipe.MatrixData.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeInt32(1, o), null != (o = t.Message.getField(e, 2)) && r.writeInt32(2, o), (o = e.getPackedDataList()).length > 0 && r.writePackedFloat(3, o), null != (o = t.Message.getField(e, 4)) && r.writeEnum(4, o); }), (proto.mediapipe.MatrixData.Layout = { COLUMN_MAJOR: 0, ROW_MAJOR: 1 }), (proto.mediapipe.MatrixData.prototype.getRows = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.MatrixData.prototype.setRows = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.MatrixData.prototype.clearRows = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.MatrixData.prototype.hasRows = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.MatrixData.prototype.getCols = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.MatrixData.prototype.setCols = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.MatrixData.prototype.clearCols = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.MatrixData.prototype.hasCols = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.MatrixData.prototype.getPackedDataList = function() { return t.Message.getRepeatedFloatingPointField(this, 3); }), (proto.mediapipe.MatrixData.prototype.setPackedDataList = function(e) { return t.Message.setField(this, 3, e || []); }), (proto.mediapipe.MatrixData.prototype.addPackedData = function(e, r) { return t.Message.addToRepeatedField(this, 3, e, r); }), (proto.mediapipe.MatrixData.prototype.clearPackedDataList = function() { return this.setPackedDataList([]); }), (proto.mediapipe.MatrixData.prototype.getLayout = function() { return t.Message.getFieldWithDefault(this, 4, 0); }), (proto.mediapipe.MatrixData.prototype.setLayout = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.MatrixData.prototype.clearLayout = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.MatrixData.prototype.hasLayout = function() { return null != t.Message.getField(this, 4); }), r.object.extend(e, proto.mediapipe); })(matrix_data_pb); var mesh_3d_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d', null, o), r.exportSymbol( 'proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.PrimitiveType', null, o ), r.exportSymbol( 'proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.VertexType', null, o ), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.repeatedFields_, null ); }), r.inherits(proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.displayName = 'proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d'), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.repeatedFields_ = [3, 4]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.toObject(e, this); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.toObject = function(e, r) { var o, i = { vertexType: null == (o = t.Message.getField(r, 1)) ? void 0 : o, primitiveType: null == (o = t.Message.getField(r, 2)) ? void 0 : o, vertexBufferList: null == (o = t.Message.getRepeatedFloatingPointField(r, 3)) ? void 0 : o, indexBufferList: null == (o = t.Message.getRepeatedField(r, 4)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d(); return proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readEnum(); e.setVertexType(r); break; case 2: r = t.readEnum(); e.setPrimitiveType(r); break; case 3: for ( var o = t.isDelimited() ? t.readPackedFloat() : [t.readFloat()], i = 0; i < o.length; i++ ) e.addVertexBuffer(o[i]); break; case 4: for ( o = t.isDelimited() ? t.readPackedUint32() : [t.readUint32()], i = 0; i < o.length; i++ ) e.addIndexBuffer(o[i]); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeEnum(1, o), null != (o = t.Message.getField(e, 2)) && r.writeEnum(2, o), (o = e.getVertexBufferList()).length > 0 && r.writeRepeatedFloat(3, o), (o = e.getIndexBufferList()).length > 0 && r.writeRepeatedUint32(4, o); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.VertexType = { VERTEX_PT: 0 }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.PrimitiveType = { TRIANGLE: 0 }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.getVertexType = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.setVertexType = function( e ) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.clearVertexType = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.hasVertexType = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.getPrimitiveType = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.setPrimitiveType = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.clearPrimitiveType = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.hasPrimitiveType = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.getVertexBufferList = function() { return t.Message.getRepeatedFloatingPointField(this, 3); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.setVertexBufferList = function( e ) { return t.Message.setField(this, 3, e || []); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.addVertexBuffer = function( e, r ) { return t.Message.addToRepeatedField(this, 3, e, r); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.clearVertexBufferList = function() { return this.setVertexBufferList([]); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.getIndexBufferList = function() { return t.Message.getRepeatedField(this, 4); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.setIndexBufferList = function( e ) { return t.Message.setField(this, 4, e || []); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.addIndexBuffer = function( e, r ) { return t.Message.addToRepeatedField(this, 4, e, r); }), (proto.mediapipe.tasks.vision.face_geometry.proto.Mesh3d.prototype.clearIndexBufferList = function() { return this.setIndexBufferList([]); }), r.object.extend(e, proto.mediapipe.tasks.vision.face_geometry.proto); })(mesh_3d_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = matrix_data_pb; r.object.extend(proto, i); var a = mesh_3d_pb; r.object.extend(proto, a), r.exportSymbol( 'proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry', null, o ), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.displayName = 'proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.toObject( e, this ); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.toObject = function( e, t ) { var r, o = { mesh: (r = t.getMesh()) && a.Mesh3d.toObject(e, r), poseTransformMatrix: (r = t.getPoseTransformMatrix()) && i.MatrixData.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry(); return proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new a.Mesh3d(); t.readMessage(r, a.Mesh3d.deserializeBinaryFromReader), e.setMesh(r); break; case 2: r = new i.MatrixData(); t.readMessage(r, i.MatrixData.deserializeBinaryFromReader), e.setPoseTransformMatrix(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.serializeBinaryToWriter = function( e, t ) { var r = void 0; null != (r = e.getMesh()) && t.writeMessage(1, r, a.Mesh3d.serializeBinaryToWriter), null != (r = e.getPoseTransformMatrix()) && t.writeMessage(2, r, i.MatrixData.serializeBinaryToWriter); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.prototype.getMesh = function() { return t.Message.getWrapperField(this, a.Mesh3d, 1); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.prototype.setMesh = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.prototype.clearMesh = function() { return this.setMesh(void 0); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.prototype.hasMesh = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.prototype.getPoseTransformMatrix = function() { return t.Message.getWrapperField(this, i.MatrixData, 2); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.prototype.setPoseTransformMatrix = function( e ) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.prototype.clearPoseTransformMatrix = function() { return this.setPoseTransformMatrix(void 0); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometry.prototype.hasPoseTransformMatrix = function() { return null != t.Message.getField(this, 2); }), r.object.extend(e, proto.mediapipe.tasks.vision.face_geometry.proto); })(face_geometry_pb); var face_landmarker_graph_options_pb = {}, face_geometry_graph_options_pb = {}, geometry_pipeline_calculator_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_options_pb; r.object.extend(proto, i); var a = external_file_pb; r.object.extend(proto, a), r.exportSymbol( 'proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions', null, o ), (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.displayName = 'proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.toObject = function( e, t ) { var r, o = { metadataFile: (r = t.getMetadataFile()) && a.ExternalFile.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions(); return proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new a.ExternalFile(); t.readMessage(r, a.ExternalFile.deserializeBinaryFromReader), e.setMetadataFile(r); } else t.skipField(); } return e; }), (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.serializeBinaryToWriter = function( e, t ) { var r; null != (r = e.getMetadataFile()) && t.writeMessage(1, r, a.ExternalFile.serializeBinaryToWriter); }), (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.ext = new t.ExtensionFieldInfo( 512499200, { ext: 0 }, proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions, proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.toObject, 0 )), (i.CalculatorOptions.extensionsBinary[512499200] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.deserializeBinaryFromReader, !1 )), (i.CalculatorOptions.extensions[512499200] = proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.ext), (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.prototype.getMetadataFile = function() { return t.Message.getWrapperField(this, a.ExternalFile, 1); }), (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.prototype.setMetadataFile = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.prototype.clearMetadataFile = function() { return this.setMetadataFile(void 0); }), (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.prototype.hasMetadataFile = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.ext = new t.ExtensionFieldInfo( 512499200, { ext: 0 }, proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions, proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.toObject, 0 )), (i.CalculatorOptions.extensionsBinary[512499200] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.deserializeBinaryFromReader, !1 )), (i.CalculatorOptions.extensions[512499200] = proto.mediapipe.tasks.vision.face_geometry.FaceGeometryPipelineCalculatorOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.face_geometry); })(geometry_pipeline_calculator_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_options_pb; r.object.extend(proto, i); var a = geometry_pipeline_calculator_pb; r.object.extend(proto, a), r.exportSymbol( 'proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions', null, o ), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.displayName = 'proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.toObject = function( e, t ) { var r, o = { geometryPipelineOptions: (r = t.getGeometryPipelineOptions()) && a.FaceGeometryPipelineCalculatorOptions.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions(); return proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new a.FaceGeometryPipelineCalculatorOptions(); t.readMessage( r, a.FaceGeometryPipelineCalculatorOptions.deserializeBinaryFromReader ), e.setGeometryPipelineOptions(r); } else t.skipField(); } return e; }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.serializeBinaryToWriter = function( e, t ) { var r; null != (r = e.getGeometryPipelineOptions()) && t.writeMessage( 1, r, a.FaceGeometryPipelineCalculatorOptions.serializeBinaryToWriter ); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.ext = new t.ExtensionFieldInfo( 515723506, { ext: 0 }, proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions, proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.toObject, 0 )), (i.CalculatorOptions.extensionsBinary[515723506] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.deserializeBinaryFromReader, !1 )), (i.CalculatorOptions.extensions[515723506] = proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.ext), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.prototype.getGeometryPipelineOptions = function() { return t.Message.getWrapperField(this, a.FaceGeometryPipelineCalculatorOptions, 1); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.prototype.setGeometryPipelineOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.prototype.clearGeometryPipelineOptions = function() { return this.setGeometryPipelineOptions(void 0); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.prototype.hasGeometryPipelineOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.ext = new t.ExtensionFieldInfo( 515723506, { ext: 0 }, proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions, proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.toObject, 0 )), (i.CalculatorOptions.extensionsBinary[515723506] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.deserializeBinaryFromReader, !1 )), (i.CalculatorOptions.extensions[515723506] = proto.mediapipe.tasks.vision.face_geometry.proto.FaceGeometryGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.face_geometry.proto); })(face_geometry_graph_options_pb); var face_landmarks_detector_graph_options_pb = {}, face_blendshapes_graph_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n), r.exportSymbol( 'proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions', null, o ), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.displayName = 'proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.toObject = function( e, t ) { var r, o = { baseOptions: (r = t.getBaseOptions()) && n.BaseOptions.toObject(e, r) }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions(); return proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); } else t.skipField(); } return e; }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.serializeBinaryToWriter = function( e, t ) { var r; null != (r = e.getBaseOptions()) && t.writeMessage(1, r, n.BaseOptions.serializeBinaryToWriter); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.ext = new t.ExtensionFieldInfo( 508981768, { ext: 0 }, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[508981768] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[508981768] = proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.ext), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.ext = new t.ExtensionFieldInfo( 508981768, { ext: 0 }, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[508981768] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[508981768] = proto.mediapipe.tasks.vision.face_landmarker.proto.FaceBlendshapesGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.face_landmarker.proto); })(face_blendshapes_graph_options_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n); var s = face_blendshapes_graph_options_pb; r.object.extend(proto, s), r.exportSymbol( 'proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions', null, o ), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.face_landmarker.proto .FaceLandmarksDetectorGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.displayName = 'proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.toObject = function( e, r ) { var o, i = { baseOptions: (o = r.getBaseOptions()) && n.BaseOptions.toObject(e, o), minDetectionConfidence: t.Message.getFloatingPointFieldWithDefault( r, 2, 0.5 ), smoothLandmarks: null == (o = t.Message.getBooleanField(r, 4)) ? void 0 : o, faceBlendshapesGraphOptions: (o = r.getFaceBlendshapesGraphOptions()) && s.FaceBlendshapesGraphOptions.toObject(e, o), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions(); return proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = t.readFloat(); e.setMinDetectionConfidence(r); break; case 4: r = t.readBool(); e.setSmoothLandmarks(r); break; case 3: r = new s.FaceBlendshapesGraphOptions(); t.readMessage( r, s.FaceBlendshapesGraphOptions.deserializeBinaryFromReader ), e.setFaceBlendshapesGraphOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getBaseOptions()) && r.writeMessage(1, o, n.BaseOptions.serializeBinaryToWriter), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o), null != (o = t.Message.getField(e, 4)) && r.writeBool(4, o), null != (o = e.getFaceBlendshapesGraphOptions()) && r.writeMessage(3, o, s.FaceBlendshapesGraphOptions.serializeBinaryToWriter); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.ext = new t.ExtensionFieldInfo( 508968149, { ext: 0 }, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[508968149] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[508968149] = proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.ext), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.getMinDetectionConfidence = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0.5); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.setMinDetectionConfidence = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.clearMinDetectionConfidence = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.hasMinDetectionConfidence = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.getSmoothLandmarks = function() { return t.Message.getBooleanFieldWithDefault(this, 4, !1); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.setSmoothLandmarks = function( e ) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.clearSmoothLandmarks = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.hasSmoothLandmarks = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.getFaceBlendshapesGraphOptions = function() { return t.Message.getWrapperField(this, s.FaceBlendshapesGraphOptions, 3); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.setFaceBlendshapesGraphOptions = function( e ) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.clearFaceBlendshapesGraphOptions = function() { return this.setFaceBlendshapesGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.prototype.hasFaceBlendshapesGraphOptions = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.ext = new t.ExtensionFieldInfo( 508968149, { ext: 0 }, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[508968149] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[508968149] = proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarksDetectorGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.face_landmarker.proto); })(face_landmarks_detector_graph_options_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n); var s = face_detector_graph_options_pb; r.object.extend(proto, s); var p = face_geometry_graph_options_pb; r.object.extend(proto, p); var d = face_landmarks_detector_graph_options_pb; r.object.extend(proto, d), r.exportSymbol( 'proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions', null, o ), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.displayName = 'proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.toObject = function( e, r ) { var o, i = { baseOptions: (o = r.getBaseOptions()) && n.BaseOptions.toObject(e, o), faceDetectorGraphOptions: (o = r.getFaceDetectorGraphOptions()) && s.FaceDetectorGraphOptions.toObject(e, o), faceLandmarksDetectorGraphOptions: (o = r.getFaceLandmarksDetectorGraphOptions()) && d.FaceLandmarksDetectorGraphOptions.toObject(e, o), minTrackingConfidence: t.Message.getFloatingPointFieldWithDefault( r, 4, 0.5 ), faceGeometryGraphOptions: (o = r.getFaceGeometryGraphOptions()) && p.FaceGeometryGraphOptions.toObject(e, o), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions(); return proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = new s.FaceDetectorGraphOptions(); t.readMessage( r, s.FaceDetectorGraphOptions.deserializeBinaryFromReader ), e.setFaceDetectorGraphOptions(r); break; case 3: r = new d.FaceLandmarksDetectorGraphOptions(); t.readMessage( r, d.FaceLandmarksDetectorGraphOptions.deserializeBinaryFromReader ), e.setFaceLandmarksDetectorGraphOptions(r); break; case 4: r = t.readFloat(); e.setMinTrackingConfidence(r); break; case 5: r = new p.FaceGeometryGraphOptions(); t.readMessage( r, p.FaceGeometryGraphOptions.deserializeBinaryFromReader ), e.setFaceGeometryGraphOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getBaseOptions()) && r.writeMessage(1, o, n.BaseOptions.serializeBinaryToWriter), null != (o = e.getFaceDetectorGraphOptions()) && r.writeMessage(2, o, s.FaceDetectorGraphOptions.serializeBinaryToWriter), null != (o = e.getFaceLandmarksDetectorGraphOptions()) && r.writeMessage( 3, o, d.FaceLandmarksDetectorGraphOptions.serializeBinaryToWriter ), null != (o = t.Message.getField(e, 4)) && r.writeFloat(4, o), null != (o = e.getFaceGeometryGraphOptions()) && r.writeMessage(5, o, p.FaceGeometryGraphOptions.serializeBinaryToWriter); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.ext = new t.ExtensionFieldInfo( 508968150, { ext: 0 }, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[508968150] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[508968150] = proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.ext), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.getFaceDetectorGraphOptions = function() { return t.Message.getWrapperField(this, s.FaceDetectorGraphOptions, 2); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.setFaceDetectorGraphOptions = function( e ) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.clearFaceDetectorGraphOptions = function() { return this.setFaceDetectorGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.hasFaceDetectorGraphOptions = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.getFaceLandmarksDetectorGraphOptions = function() { return t.Message.getWrapperField(this, d.FaceLandmarksDetectorGraphOptions, 3); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.setFaceLandmarksDetectorGraphOptions = function( e ) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.clearFaceLandmarksDetectorGraphOptions = function() { return this.setFaceLandmarksDetectorGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.hasFaceLandmarksDetectorGraphOptions = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.getMinTrackingConfidence = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0.5); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.setMinTrackingConfidence = function( e ) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.clearMinTrackingConfidence = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.hasMinTrackingConfidence = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.getFaceGeometryGraphOptions = function() { return t.Message.getWrapperField(this, p.FaceGeometryGraphOptions, 5); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.setFaceGeometryGraphOptions = function( e ) { return t.Message.setWrapperField(this, 5, e); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.clearFaceGeometryGraphOptions = function() { return this.setFaceGeometryGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.prototype.hasFaceGeometryGraphOptions = function() { return null != t.Message.getField(this, 5); }), (proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.ext = new t.ExtensionFieldInfo( 508968150, { ext: 0 }, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[508968150] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[508968150] = proto.mediapipe.tasks.vision.face_landmarker.proto.FaceLandmarkerGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.face_landmarker.proto); })(face_landmarker_graph_options_pb); var classifier_result = {}; Object.defineProperty(classifier_result, '__esModule', { value: !0 }), (classifier_result.convertFromClassificationResultProto = classifier_result.convertFromClassifications = void 0); const DEFAULT_INDEX$1 = -1, DEFAULT_SCORE = 0; function convertFromClassifications(e, t = DEFAULT_INDEX$1, r = '') { return { categories: e.map((e) => { var t, r, o, i; return { index: null !== (t = e.getIndex()) && void 0 !== t ? t : DEFAULT_INDEX$1, score: null !== (r = e.getScore()) && void 0 !== r ? r : DEFAULT_SCORE, categoryName: null !== (o = e.getLabel()) && void 0 !== o ? o : '', displayName: null !== (i = e.getDisplayName()) && void 0 !== i ? i : '', }; }), headIndex: t, headName: r, }; } function convertFromClassificationsProto(e) { var t, r; return convertFromClassifications( null !== (r = null === (t = e.getClassificationList()) || void 0 === t ? void 0 : t.getClassificationList()) && void 0 !== r ? r : [], e.getHeadIndex(), e.getHeadName() ); } function convertFromClassificationResultProto(e) { const t = { classifications: e.getClassificationsList().map((e) => convertFromClassificationsProto(e)), }; return e.hasTimestampMs() && (t.timestampMs = e.getTimestampMs()), t; } (classifier_result.convertFromClassifications = convertFromClassifications), (classifier_result.convertFromClassificationResultProto = convertFromClassificationResultProto); var landmark_result = {}; function convertToLandmarks(e) { var t, r, o; const i = []; for (const a of e.getLandmarkList()) i.push({ x: null !== (t = a.getX()) && void 0 !== t ? t : 0, y: null !== (r = a.getY()) && void 0 !== r ? r : 0, z: null !== (o = a.getZ()) && void 0 !== o ? o : 0, }); return i; } function convertToWorldLandmarks(e) { var t, r, o; const i = []; for (const a of e.getLandmarkList()) i.push({ x: null !== (t = a.getX()) && void 0 !== t ? t : 0, y: null !== (r = a.getY()) && void 0 !== r ? r : 0, z: null !== (o = a.getZ()) && void 0 !== o ? o : 0, }); return i; } Object.defineProperty(landmark_result, '__esModule', { value: !0 }), (landmark_result.convertToWorldLandmarks = landmark_result.convertToLandmarks = void 0), (landmark_result.convertToLandmarks = convertToLandmarks), (landmark_result.convertToWorldLandmarks = convertToWorldLandmarks); var face_landmarks_connections = {}, exports; (exports = face_landmarks_connections), Object.defineProperty(exports, '__esModule', { value: !0 }), (exports.FACE_LANDMARKS_TESSELATION = exports.FACE_LANDMARKS_CONTOURS = exports.FACE_LANDMARKS_FACE_OVAL = exports.FACE_LANDMARKS_RIGHT_IRIS = exports.FACE_LANDMARKS_RIGHT_EYEBROW = exports.FACE_LANDMARKS_RIGHT_EYE = exports.FACE_LANDMARKS_LEFT_IRIS = exports.FACE_LANDMARKS_LEFT_EYEBROW = exports.FACE_LANDMARKS_LEFT_EYE = exports.FACE_LANDMARKS_LIPS = void 0), (exports.FACE_LANDMARKS_LIPS = [ { start: 61, end: 146 }, { start: 146, end: 91 }, { start: 91, end: 181 }, { start: 181, end: 84 }, { start: 84, end: 17 }, { start: 17, end: 314 }, { start: 314, end: 405 }, { start: 405, end: 321 }, { start: 321, end: 375 }, { start: 375, end: 291 }, { start: 61, end: 185 }, { start: 185, end: 40 }, { start: 40, end: 39 }, { start: 39, end: 37 }, { start: 37, end: 0 }, { start: 0, end: 267 }, { start: 267, end: 269 }, { start: 269, end: 270 }, { start: 270, end: 409 }, { start: 409, end: 291 }, { start: 78, end: 95 }, { start: 95, end: 88 }, { start: 88, end: 178 }, { start: 178, end: 87 }, { start: 87, end: 14 }, { start: 14, end: 317 }, { start: 317, end: 402 }, { start: 402, end: 318 }, { start: 318, end: 324 }, { start: 324, end: 308 }, { start: 78, end: 191 }, { start: 191, end: 80 }, { start: 80, end: 81 }, { start: 81, end: 82 }, { start: 82, end: 13 }, { start: 13, end: 312 }, { start: 312, end: 311 }, { start: 311, end: 310 }, { start: 310, end: 415 }, { start: 415, end: 308 }, ]), (exports.FACE_LANDMARKS_LEFT_EYE = [ { start: 263, end: 249 }, { start: 249, end: 390 }, { start: 390, end: 373 }, { start: 373, end: 374 }, { start: 374, end: 380 }, { start: 380, end: 381 }, { start: 381, end: 382 }, { start: 382, end: 362 }, { start: 263, end: 466 }, { start: 466, end: 388 }, { start: 388, end: 387 }, { start: 387, end: 386 }, { start: 386, end: 385 }, { start: 385, end: 384 }, { start: 384, end: 398 }, { start: 398, end: 362 }, ]), (exports.FACE_LANDMARKS_LEFT_EYEBROW = [ { start: 276, end: 283 }, { start: 283, end: 282 }, { start: 282, end: 295 }, { start: 295, end: 285 }, { start: 300, end: 293 }, { start: 293, end: 334 }, { start: 334, end: 296 }, { start: 296, end: 336 }, ]), (exports.FACE_LANDMARKS_LEFT_IRIS = [ { start: 474, end: 475 }, { start: 475, end: 476 }, { start: 476, end: 477 }, { start: 477, end: 474 }, ]), (exports.FACE_LANDMARKS_RIGHT_EYE = [ { start: 33, end: 7 }, { start: 7, end: 163 }, { start: 163, end: 144 }, { start: 144, end: 145 }, { start: 145, end: 153 }, { start: 153, end: 154 }, { start: 154, end: 155 }, { start: 155, end: 133 }, { start: 33, end: 246 }, { start: 246, end: 161 }, { start: 161, end: 160 }, { start: 160, end: 159 }, { start: 159, end: 158 }, { start: 158, end: 157 }, { start: 157, end: 173 }, { start: 173, end: 133 }, ]), (exports.FACE_LANDMARKS_RIGHT_EYEBROW = [ { start: 46, end: 53 }, { start: 53, end: 52 }, { start: 52, end: 65 }, { start: 65, end: 55 }, { start: 70, end: 63 }, { start: 63, end: 105 }, { start: 105, end: 66 }, { start: 66, end: 107 }, ]), (exports.FACE_LANDMARKS_RIGHT_IRIS = [ { start: 469, end: 470 }, { start: 470, end: 471 }, { start: 471, end: 472 }, { start: 472, end: 469 }, ]), (exports.FACE_LANDMARKS_FACE_OVAL = [ { start: 10, end: 338 }, { start: 338, end: 297 }, { start: 297, end: 332 }, { start: 332, end: 284 }, { start: 284, end: 251 }, { start: 251, end: 389 }, { start: 389, end: 356 }, { start: 356, end: 454 }, { start: 454, end: 323 }, { start: 323, end: 361 }, { start: 361, end: 288 }, { start: 288, end: 397 }, { start: 397, end: 365 }, { start: 365, end: 379 }, { start: 379, end: 378 }, { start: 378, end: 400 }, { start: 400, end: 377 }, { start: 377, end: 152 }, { start: 152, end: 148 }, { start: 148, end: 176 }, { start: 176, end: 149 }, { start: 149, end: 150 }, { start: 150, end: 136 }, { start: 136, end: 172 }, { start: 172, end: 58 }, { start: 58, end: 132 }, { start: 132, end: 93 }, { start: 93, end: 234 }, { start: 234, end: 127 }, { start: 127, end: 162 }, { start: 162, end: 21 }, { start: 21, end: 54 }, { start: 54, end: 103 }, { start: 103, end: 67 }, { start: 67, end: 109 }, { start: 109, end: 10 }, ]), (exports.FACE_LANDMARKS_CONTOURS = [ ...exports.FACE_LANDMARKS_LIPS, ...exports.FACE_LANDMARKS_LEFT_EYE, ...exports.FACE_LANDMARKS_LEFT_EYEBROW, ...exports.FACE_LANDMARKS_RIGHT_EYE, ...exports.FACE_LANDMARKS_RIGHT_EYEBROW, ...exports.FACE_LANDMARKS_FACE_OVAL, ]), (exports.FACE_LANDMARKS_TESSELATION = [ { start: 127, end: 34 }, { start: 34, end: 139 }, { start: 139, end: 127 }, { start: 11, end: 0 }, { start: 0, end: 37 }, { start: 37, end: 11 }, { start: 232, end: 231 }, { start: 231, end: 120 }, { start: 120, end: 232 }, { start: 72, end: 37 }, { start: 37, end: 39 }, { start: 39, end: 72 }, { start: 128, end: 121 }, { start: 121, end: 47 }, { start: 47, end: 128 }, { start: 232, end: 121 }, { start: 121, end: 128 }, { start: 128, end: 232 }, { start: 104, end: 69 }, { start: 69, end: 67 }, { start: 67, end: 104 }, { start: 175, end: 171 }, { start: 171, end: 148 }, { start: 148, end: 175 }, { start: 118, end: 50 }, { start: 50, end: 101 }, { start: 101, end: 118 }, { start: 73, end: 39 }, { start: 39, end: 40 }, { start: 40, end: 73 }, { start: 9, end: 151 }, { start: 151, end: 108 }, { start: 108, end: 9 }, { start: 48, end: 115 }, { start: 115, end: 131 }, { start: 131, end: 48 }, { start: 194, end: 204 }, { start: 204, end: 211 }, { start: 211, end: 194 }, { start: 74, end: 40 }, { start: 40, end: 185 }, { start: 185, end: 74 }, { start: 80, end: 42 }, { start: 42, end: 183 }, { start: 183, end: 80 }, { start: 40, end: 92 }, { start: 92, end: 186 }, { start: 186, end: 40 }, { start: 230, end: 229 }, { start: 229, end: 118 }, { start: 118, end: 230 }, { start: 202, end: 212 }, { start: 212, end: 214 }, { start: 214, end: 202 }, { start: 83, end: 18 }, { start: 18, end: 17 }, { start: 17, end: 83 }, { start: 76, end: 61 }, { start: 61, end: 146 }, { start: 146, end: 76 }, { start: 160, end: 29 }, { start: 29, end: 30 }, { start: 30, end: 160 }, { start: 56, end: 157 }, { start: 157, end: 173 }, { start: 173, end: 56 }, { start: 106, end: 204 }, { start: 204, end: 194 }, { start: 194, end: 106 }, { start: 135, end: 214 }, { start: 214, end: 192 }, { start: 192, end: 135 }, { start: 203, end: 165 }, { start: 165, end: 98 }, { start: 98, end: 203 }, { start: 21, end: 71 }, { start: 71, end: 68 }, { start: 68, end: 21 }, { start: 51, end: 45 }, { start: 45, end: 4 }, { start: 4, end: 51 }, { start: 144, end: 24 }, { start: 24, end: 23 }, { start: 23, end: 144 }, { start: 77, end: 146 }, { start: 146, end: 91 }, { start: 91, end: 77 }, { start: 205, end: 50 }, { start: 50, end: 187 }, { start: 187, end: 205 }, { start: 201, end: 200 }, { start: 200, end: 18 }, { start: 18, end: 201 }, { start: 91, end: 106 }, { start: 106, end: 182 }, { start: 182, end: 91 }, { start: 90, end: 91 }, { start: 91, end: 181 }, { start: 181, end: 90 }, { start: 85, end: 84 }, { start: 84, end: 17 }, { start: 17, end: 85 }, { start: 206, end: 203 }, { start: 203, end: 36 }, { start: 36, end: 206 }, { start: 148, end: 171 }, { start: 171, end: 140 }, { start: 140, end: 148 }, { start: 92, end: 40 }, { start: 40, end: 39 }, { start: 39, end: 92 }, { start: 193, end: 189 }, { start: 189, end: 244 }, { start: 244, end: 193 }, { start: 159, end: 158 }, { start: 158, end: 28 }, { start: 28, end: 159 }, { start: 247, end: 246 }, { start: 246, end: 161 }, { start: 161, end: 247 }, { start: 236, end: 3 }, { start: 3, end: 196 }, { start: 196, end: 236 }, { start: 54, end: 68 }, { start: 68, end: 104 }, { start: 104, end: 54 }, { start: 193, end: 168 }, { start: 168, end: 8 }, { start: 8, end: 193 }, { start: 117, end: 228 }, { start: 228, end: 31 }, { start: 31, end: 117 }, { start: 189, end: 193 }, { start: 193, end: 55 }, { start: 55, end: 189 }, { start: 98, end: 97 }, { start: 97, end: 99 }, { start: 99, end: 98 }, { start: 126, end: 47 }, { start: 47, end: 100 }, { start: 100, end: 126 }, { start: 166, end: 79 }, { start: 79, end: 218 }, { start: 218, end: 166 }, { start: 155, end: 154 }, { start: 154, end: 26 }, { start: 26, end: 155 }, { start: 209, end: 49 }, { start: 49, end: 131 }, { start: 131, end: 209 }, { start: 135, end: 136 }, { start: 136, end: 150 }, { start: 150, end: 135 }, { start: 47, end: 126 }, { start: 126, end: 217 }, { start: 217, end: 47 }, { start: 223, end: 52 }, { start: 52, end: 53 }, { start: 53, end: 223 }, { start: 45, end: 51 }, { start: 51, end: 134 }, { start: 134, end: 45 }, { start: 211, end: 170 }, { start: 170, end: 140 }, { start: 140, end: 211 }, { start: 67, end: 69 }, { start: 69, end: 108 }, { start: 108, end: 67 }, { start: 43, end: 106 }, { start: 106, end: 91 }, { start: 91, end: 43 }, { start: 230, end: 119 }, { start: 119, end: 120 }, { start: 120, end: 230 }, { start: 226, end: 130 }, { start: 130, end: 247 }, { start: 247, end: 226 }, { start: 63, end: 53 }, { start: 53, end: 52 }, { start: 52, end: 63 }, { start: 238, end: 20 }, { start: 20, end: 242 }, { start: 242, end: 238 }, { start: 46, end: 70 }, { start: 70, end: 156 }, { start: 156, end: 46 }, { start: 78, end: 62 }, { start: 62, end: 96 }, { start: 96, end: 78 }, { start: 46, end: 53 }, { start: 53, end: 63 }, { start: 63, end: 46 }, { start: 143, end: 34 }, { start: 34, end: 227 }, { start: 227, end: 143 }, { start: 123, end: 117 }, { start: 117, end: 111 }, { start: 111, end: 123 }, { start: 44, end: 125 }, { start: 125, end: 19 }, { start: 19, end: 44 }, { start: 236, end: 134 }, { start: 134, end: 51 }, { start: 51, end: 236 }, { start: 216, end: 206 }, { start: 206, end: 205 }, { start: 205, end: 216 }, { start: 154, end: 153 }, { start: 153, end: 22 }, { start: 22, end: 154 }, { start: 39, end: 37 }, { start: 37, end: 167 }, { start: 167, end: 39 }, { start: 200, end: 201 }, { start: 201, end: 208 }, { start: 208, end: 200 }, { start: 36, end: 142 }, { start: 142, end: 100 }, { start: 100, end: 36 }, { start: 57, end: 212 }, { start: 212, end: 202 }, { start: 202, end: 57 }, { start: 20, end: 60 }, { start: 60, end: 99 }, { start: 99, end: 20 }, { start: 28, end: 158 }, { start: 158, end: 157 }, { start: 157, end: 28 }, { start: 35, end: 226 }, { start: 226, end: 113 }, { start: 113, end: 35 }, { start: 160, end: 159 }, { start: 159, end: 27 }, { start: 27, end: 160 }, { start: 204, end: 202 }, { start: 202, end: 210 }, { start: 210, end: 204 }, { start: 113, end: 225 }, { start: 225, end: 46 }, { start: 46, end: 113 }, { start: 43, end: 202 }, { start: 202, end: 204 }, { start: 204, end: 43 }, { start: 62, end: 76 }, { start: 76, end: 77 }, { start: 77, end: 62 }, { start: 137, end: 123 }, { start: 123, end: 116 }, { start: 116, end: 137 }, { start: 41, end: 38 }, { start: 38, end: 72 }, { start: 72, end: 41 }, { start: 203, end: 129 }, { start: 129, end: 142 }, { start: 142, end: 203 }, { start: 64, end: 98 }, { start: 98, end: 240 }, { start: 240, end: 64 }, { start: 49, end: 102 }, { start: 102, end: 64 }, { start: 64, end: 49 }, { start: 41, end: 73 }, { start: 73, end: 74 }, { start: 74, end: 41 }, { start: 212, end: 216 }, { start: 216, end: 207 }, { start: 207, end: 212 }, { start: 42, end: 74 }, { start: 74, end: 184 }, { start: 184, end: 42 }, { start: 169, end: 170 }, { start: 170, end: 211 }, { start: 211, end: 169 }, { start: 170, end: 149 }, { start: 149, end: 176 }, { start: 176, end: 170 }, { start: 105, end: 66 }, { start: 66, end: 69 }, { start: 69, end: 105 }, { start: 122, end: 6 }, { start: 6, end: 168 }, { start: 168, end: 122 }, { start: 123, end: 147 }, { start: 147, end: 187 }, { start: 187, end: 123 }, { start: 96, end: 77 }, { start: 77, end: 90 }, { start: 90, end: 96 }, { start: 65, end: 55 }, { start: 55, end: 107 }, { start: 107, end: 65 }, { start: 89, end: 90 }, { start: 90, end: 180 }, { start: 180, end: 89 }, { start: 101, end: 100 }, { start: 100, end: 120 }, { start: 120, end: 101 }, { start: 63, end: 105 }, { start: 105, end: 104 }, { start: 104, end: 63 }, { start: 93, end: 137 }, { start: 137, end: 227 }, { start: 227, end: 93 }, { start: 15, end: 86 }, { start: 86, end: 85 }, { start: 85, end: 15 }, { start: 129, end: 102 }, { start: 102, end: 49 }, { start: 49, end: 129 }, { start: 14, end: 87 }, { start: 87, end: 86 }, { start: 86, end: 14 }, { start: 55, end: 8 }, { start: 8, end: 9 }, { start: 9, end: 55 }, { start: 100, end: 47 }, { start: 47, end: 121 }, { start: 121, end: 100 }, { start: 145, end: 23 }, { start: 23, end: 22 }, { start: 22, end: 145 }, { start: 88, end: 89 }, { start: 89, end: 179 }, { start: 179, end: 88 }, { start: 6, end: 122 }, { start: 122, end: 196 }, { start: 196, end: 6 }, { start: 88, end: 95 }, { start: 95, end: 96 }, { start: 96, end: 88 }, { start: 138, end: 172 }, { start: 172, end: 136 }, { start: 136, end: 138 }, { start: 215, end: 58 }, { start: 58, end: 172 }, { start: 172, end: 215 }, { start: 115, end: 48 }, { start: 48, end: 219 }, { start: 219, end: 115 }, { start: 42, end: 80 }, { start: 80, end: 81 }, { start: 81, end: 42 }, { start: 195, end: 3 }, { start: 3, end: 51 }, { start: 51, end: 195 }, { start: 43, end: 146 }, { start: 146, end: 61 }, { start: 61, end: 43 }, { start: 171, end: 175 }, { start: 175, end: 199 }, { start: 199, end: 171 }, { start: 81, end: 82 }, { start: 82, end: 38 }, { start: 38, end: 81 }, { start: 53, end: 46 }, { start: 46, end: 225 }, { start: 225, end: 53 }, { start: 144, end: 163 }, { start: 163, end: 110 }, { start: 110, end: 144 }, { start: 52, end: 65 }, { start: 65, end: 66 }, { start: 66, end: 52 }, { start: 229, end: 228 }, { start: 228, end: 117 }, { start: 117, end: 229 }, { start: 34, end: 127 }, { start: 127, end: 234 }, { start: 234, end: 34 }, { start: 107, end: 108 }, { start: 108, end: 69 }, { start: 69, end: 107 }, { start: 109, end: 108 }, { start: 108, end: 151 }, { start: 151, end: 109 }, { start: 48, end: 64 }, { start: 64, end: 235 }, { start: 235, end: 48 }, { start: 62, end: 78 }, { start: 78, end: 191 }, { start: 191, end: 62 }, { start: 129, end: 209 }, { start: 209, end: 126 }, { start: 126, end: 129 }, { start: 111, end: 35 }, { start: 35, end: 143 }, { start: 143, end: 111 }, { start: 117, end: 123 }, { start: 123, end: 50 }, { start: 50, end: 117 }, { start: 222, end: 65 }, { start: 65, end: 52 }, { start: 52, end: 222 }, { start: 19, end: 125 }, { start: 125, end: 141 }, { start: 141, end: 19 }, { start: 221, end: 55 }, { start: 55, end: 65 }, { start: 65, end: 221 }, { start: 3, end: 195 }, { start: 195, end: 197 }, { start: 197, end: 3 }, { start: 25, end: 7 }, { start: 7, end: 33 }, { start: 33, end: 25 }, { start: 220, end: 237 }, { start: 237, end: 44 }, { start: 44, end: 220 }, { start: 70, end: 71 }, { start: 71, end: 139 }, { start: 139, end: 70 }, { start: 122, end: 193 }, { start: 193, end: 245 }, { start: 245, end: 122 }, { start: 247, end: 130 }, { start: 130, end: 33 }, { start: 33, end: 247 }, { start: 71, end: 21 }, { start: 21, end: 162 }, { start: 162, end: 71 }, { start: 170, end: 169 }, { start: 169, end: 150 }, { start: 150, end: 170 }, { start: 188, end: 174 }, { start: 174, end: 196 }, { start: 196, end: 188 }, { start: 216, end: 186 }, { start: 186, end: 92 }, { start: 92, end: 216 }, { start: 2, end: 97 }, { start: 97, end: 167 }, { start: 167, end: 2 }, { start: 141, end: 125 }, { start: 125, end: 241 }, { start: 241, end: 141 }, { start: 164, end: 167 }, { start: 167, end: 37 }, { start: 37, end: 164 }, { start: 72, end: 38 }, { start: 38, end: 12 }, { start: 12, end: 72 }, { start: 38, end: 82 }, { start: 82, end: 13 }, { start: 13, end: 38 }, { start: 63, end: 68 }, { start: 68, end: 71 }, { start: 71, end: 63 }, { start: 226, end: 35 }, { start: 35, end: 111 }, { start: 111, end: 226 }, { start: 101, end: 50 }, { start: 50, end: 205 }, { start: 205, end: 101 }, { start: 206, end: 92 }, { start: 92, end: 165 }, { start: 165, end: 206 }, { start: 209, end: 198 }, { start: 198, end: 217 }, { start: 217, end: 209 }, { start: 165, end: 167 }, { start: 167, end: 97 }, { start: 97, end: 165 }, { start: 220, end: 115 }, { start: 115, end: 218 }, { start: 218, end: 220 }, { start: 133, end: 112 }, { start: 112, end: 243 }, { start: 243, end: 133 }, { start: 239, end: 238 }, { start: 238, end: 241 }, { start: 241, end: 239 }, { start: 214, end: 135 }, { start: 135, end: 169 }, { start: 169, end: 214 }, { start: 190, end: 173 }, { start: 173, end: 133 }, { start: 133, end: 190 }, { start: 171, end: 208 }, { start: 208, end: 32 }, { start: 32, end: 171 }, { start: 125, end: 44 }, { start: 44, end: 237 }, { start: 237, end: 125 }, { start: 86, end: 87 }, { start: 87, end: 178 }, { start: 178, end: 86 }, { start: 85, end: 86 }, { start: 86, end: 179 }, { start: 179, end: 85 }, { start: 84, end: 85 }, { start: 85, end: 180 }, { start: 180, end: 84 }, { start: 83, end: 84 }, { start: 84, end: 181 }, { start: 181, end: 83 }, { start: 201, end: 83 }, { start: 83, end: 182 }, { start: 182, end: 201 }, { start: 137, end: 93 }, { start: 93, end: 132 }, { start: 132, end: 137 }, { start: 76, end: 62 }, { start: 62, end: 183 }, { start: 183, end: 76 }, { start: 61, end: 76 }, { start: 76, end: 184 }, { start: 184, end: 61 }, { start: 57, end: 61 }, { start: 61, end: 185 }, { start: 185, end: 57 }, { start: 212, end: 57 }, { start: 57, end: 186 }, { start: 186, end: 212 }, { start: 214, end: 207 }, { start: 207, end: 187 }, { start: 187, end: 214 }, { start: 34, end: 143 }, { start: 143, end: 156 }, { start: 156, end: 34 }, { start: 79, end: 239 }, { start: 239, end: 237 }, { start: 237, end: 79 }, { start: 123, end: 137 }, { start: 137, end: 177 }, { start: 177, end: 123 }, { start: 44, end: 1 }, { start: 1, end: 4 }, { start: 4, end: 44 }, { start: 201, end: 194 }, { start: 194, end: 32 }, { start: 32, end: 201 }, { start: 64, end: 102 }, { start: 102, end: 129 }, { start: 129, end: 64 }, { start: 213, end: 215 }, { start: 215, end: 138 }, { start: 138, end: 213 }, { start: 59, end: 166 }, { start: 166, end: 219 }, { start: 219, end: 59 }, { start: 242, end: 99 }, { start: 99, end: 97 }, { start: 97, end: 242 }, { start: 2, end: 94 }, { start: 94, end: 141 }, { start: 141, end: 2 }, { start: 75, end: 59 }, { start: 59, end: 235 }, { start: 235, end: 75 }, { start: 24, end: 110 }, { start: 110, end: 228 }, { start: 228, end: 24 }, { start: 25, end: 130 }, { start: 130, end: 226 }, { start: 226, end: 25 }, { start: 23, end: 24 }, { start: 24, end: 229 }, { start: 229, end: 23 }, { start: 22, end: 23 }, { start: 23, end: 230 }, { start: 230, end: 22 }, { start: 26, end: 22 }, { start: 22, end: 231 }, { start: 231, end: 26 }, { start: 112, end: 26 }, { start: 26, end: 232 }, { start: 232, end: 112 }, { start: 189, end: 190 }, { start: 190, end: 243 }, { start: 243, end: 189 }, { start: 221, end: 56 }, { start: 56, end: 190 }, { start: 190, end: 221 }, { start: 28, end: 56 }, { start: 56, end: 221 }, { start: 221, end: 28 }, { start: 27, end: 28 }, { start: 28, end: 222 }, { start: 222, end: 27 }, { start: 29, end: 27 }, { start: 27, end: 223 }, { start: 223, end: 29 }, { start: 30, end: 29 }, { start: 29, end: 224 }, { start: 224, end: 30 }, { start: 247, end: 30 }, { start: 30, end: 225 }, { start: 225, end: 247 }, { start: 238, end: 79 }, { start: 79, end: 20 }, { start: 20, end: 238 }, { start: 166, end: 59 }, { start: 59, end: 75 }, { start: 75, end: 166 }, { start: 60, end: 75 }, { start: 75, end: 240 }, { start: 240, end: 60 }, { start: 147, end: 177 }, { start: 177, end: 215 }, { start: 215, end: 147 }, { start: 20, end: 79 }, { start: 79, end: 166 }, { start: 166, end: 20 }, { start: 187, end: 147 }, { start: 147, end: 213 }, { start: 213, end: 187 }, { start: 112, end: 233 }, { start: 233, end: 244 }, { start: 244, end: 112 }, { start: 233, end: 128 }, { start: 128, end: 245 }, { start: 245, end: 233 }, { start: 128, end: 114 }, { start: 114, end: 188 }, { start: 188, end: 128 }, { start: 114, end: 217 }, { start: 217, end: 174 }, { start: 174, end: 114 }, { start: 131, end: 115 }, { start: 115, end: 220 }, { start: 220, end: 131 }, { start: 217, end: 198 }, { start: 198, end: 236 }, { start: 236, end: 217 }, { start: 198, end: 131 }, { start: 131, end: 134 }, { start: 134, end: 198 }, { start: 177, end: 132 }, { start: 132, end: 58 }, { start: 58, end: 177 }, { start: 143, end: 35 }, { start: 35, end: 124 }, { start: 124, end: 143 }, { start: 110, end: 163 }, { start: 163, end: 7 }, { start: 7, end: 110 }, { start: 228, end: 110 }, { start: 110, end: 25 }, { start: 25, end: 228 }, { start: 356, end: 389 }, { start: 389, end: 368 }, { start: 368, end: 356 }, { start: 11, end: 302 }, { start: 302, end: 267 }, { start: 267, end: 11 }, { start: 452, end: 350 }, { start: 350, end: 349 }, { start: 349, end: 452 }, { start: 302, end: 303 }, { start: 303, end: 269 }, { start: 269, end: 302 }, { start: 357, end: 343 }, { start: 343, end: 277 }, { start: 277, end: 357 }, { start: 452, end: 453 }, { start: 453, end: 357 }, { start: 357, end: 452 }, { start: 333, end: 332 }, { start: 332, end: 297 }, { start: 297, end: 333 }, { start: 175, end: 152 }, { start: 152, end: 377 }, { start: 377, end: 175 }, { start: 347, end: 348 }, { start: 348, end: 330 }, { start: 330, end: 347 }, { start: 303, end: 304 }, { start: 304, end: 270 }, { start: 270, end: 303 }, { start: 9, end: 336 }, { start: 336, end: 337 }, { start: 337, end: 9 }, { start: 278, end: 279 }, { start: 279, end: 360 }, { start: 360, end: 278 }, { start: 418, end: 262 }, { start: 262, end: 431 }, { start: 431, end: 418 }, { start: 304, end: 408 }, { start: 408, end: 409 }, { start: 409, end: 304 }, { start: 310, end: 415 }, { start: 415, end: 407 }, { start: 407, end: 310 }, { start: 270, end: 409 }, { start: 409, end: 410 }, { start: 410, end: 270 }, { start: 450, end: 348 }, { start: 348, end: 347 }, { start: 347, end: 450 }, { start: 422, end: 430 }, { start: 430, end: 434 }, { start: 434, end: 422 }, { start: 313, end: 314 }, { start: 314, end: 17 }, { start: 17, end: 313 }, { start: 306, end: 307 }, { start: 307, end: 375 }, { start: 375, end: 306 }, { start: 387, end: 388 }, { start: 388, end: 260 }, { start: 260, end: 387 }, { start: 286, end: 414 }, { start: 414, end: 398 }, { start: 398, end: 286 }, { start: 335, end: 406 }, { start: 406, end: 418 }, { start: 418, end: 335 }, { start: 364, end: 367 }, { start: 367, end: 416 }, { start: 416, end: 364 }, { start: 423, end: 358 }, { start: 358, end: 327 }, { start: 327, end: 423 }, { start: 251, end: 284 }, { start: 284, end: 298 }, { start: 298, end: 251 }, { start: 281, end: 5 }, { start: 5, end: 4 }, { start: 4, end: 281 }, { start: 373, end: 374 }, { start: 374, end: 253 }, { start: 253, end: 373 }, { start: 307, end: 320 }, { start: 320, end: 321 }, { start: 321, end: 307 }, { start: 425, end: 427 }, { start: 427, end: 411 }, { start: 411, end: 425 }, { start: 421, end: 313 }, { start: 313, end: 18 }, { start: 18, end: 421 }, { start: 321, end: 405 }, { start: 405, end: 406 }, { start: 406, end: 321 }, { start: 320, end: 404 }, { start: 404, end: 405 }, { start: 405, end: 320 }, { start: 315, end: 16 }, { start: 16, end: 17 }, { start: 17, end: 315 }, { start: 426, end: 425 }, { start: 425, end: 266 }, { start: 266, end: 426 }, { start: 377, end: 400 }, { start: 400, end: 369 }, { start: 369, end: 377 }, { start: 322, end: 391 }, { start: 391, end: 269 }, { start: 269, end: 322 }, { start: 417, end: 465 }, { start: 465, end: 464 }, { start: 464, end: 417 }, { start: 386, end: 257 }, { start: 257, end: 258 }, { start: 258, end: 386 }, { start: 466, end: 260 }, { start: 260, end: 388 }, { start: 388, end: 466 }, { start: 456, end: 399 }, { start: 399, end: 419 }, { start: 419, end: 456 }, { start: 284, end: 332 }, { start: 332, end: 333 }, { start: 333, end: 284 }, { start: 417, end: 285 }, { start: 285, end: 8 }, { start: 8, end: 417 }, { start: 346, end: 340 }, { start: 340, end: 261 }, { start: 261, end: 346 }, { start: 413, end: 441 }, { start: 441, end: 285 }, { start: 285, end: 413 }, { start: 327, end: 460 }, { start: 460, end: 328 }, { start: 328, end: 327 }, { start: 355, end: 371 }, { start: 371, end: 329 }, { start: 329, end: 355 }, { start: 392, end: 439 }, { start: 439, end: 438 }, { start: 438, end: 392 }, { start: 382, end: 341 }, { start: 341, end: 256 }, { start: 256, end: 382 }, { start: 429, end: 420 }, { start: 420, end: 360 }, { start: 360, end: 429 }, { start: 364, end: 394 }, { start: 394, end: 379 }, { start: 379, end: 364 }, { start: 277, end: 343 }, { start: 343, end: 437 }, { start: 437, end: 277 }, { start: 443, end: 444 }, { start: 444, end: 283 }, { start: 283, end: 443 }, { start: 275, end: 440 }, { start: 440, end: 363 }, { start: 363, end: 275 }, { start: 431, end: 262 }, { start: 262, end: 369 }, { start: 369, end: 431 }, { start: 297, end: 338 }, { start: 338, end: 337 }, { start: 337, end: 297 }, { start: 273, end: 375 }, { start: 375, end: 321 }, { start: 321, end: 273 }, { start: 450, end: 451 }, { start: 451, end: 349 }, { start: 349, end: 450 }, { start: 446, end: 342 }, { start: 342, end: 467 }, { start: 467, end: 446 }, { start: 293, end: 334 }, { start: 334, end: 282 }, { start: 282, end: 293 }, { start: 458, end: 461 }, { start: 461, end: 462 }, { start: 462, end: 458 }, { start: 276, end: 353 }, { start: 353, end: 383 }, { start: 383, end: 276 }, { start: 308, end: 324 }, { start: 324, end: 325 }, { start: 325, end: 308 }, { start: 276, end: 300 }, { start: 300, end: 293 }, { start: 293, end: 276 }, { start: 372, end: 345 }, { start: 345, end: 447 }, { start: 447, end: 372 }, { start: 352, end: 345 }, { start: 345, end: 340 }, { start: 340, end: 352 }, { start: 274, end: 1 }, { start: 1, end: 19 }, { start: 19, end: 274 }, { start: 456, end: 248 }, { start: 248, end: 281 }, { start: 281, end: 456 }, { start: 436, end: 427 }, { start: 427, end: 425 }, { start: 425, end: 436 }, { start: 381, end: 256 }, { start: 256, end: 252 }, { start: 252, end: 381 }, { start: 269, end: 391 }, { start: 391, end: 393 }, { start: 393, end: 269 }, { start: 200, end: 199 }, { start: 199, end: 428 }, { start: 428, end: 200 }, { start: 266, end: 330 }, { start: 330, end: 329 }, { start: 329, end: 266 }, { start: 287, end: 273 }, { start: 273, end: 422 }, { start: 422, end: 287 }, { start: 250, end: 462 }, { start: 462, end: 328 }, { start: 328, end: 250 }, { start: 258, end: 286 }, { start: 286, end: 384 }, { start: 384, end: 258 }, { start: 265, end: 353 }, { start: 353, end: 342 }, { start: 342, end: 265 }, { start: 387, end: 259 }, { start: 259, end: 257 }, { start: 257, end: 387 }, { start: 424, end: 431 }, { start: 431, end: 430 }, { start: 430, end: 424 }, { start: 342, end: 353 }, { start: 353, end: 276 }, { start: 276, end: 342 }, { start: 273, end: 335 }, { start: 335, end: 424 }, { start: 424, end: 273 }, { start: 292, end: 325 }, { start: 325, end: 307 }, { start: 307, end: 292 }, { start: 366, end: 447 }, { start: 447, end: 345 }, { start: 345, end: 366 }, { start: 271, end: 303 }, { start: 303, end: 302 }, { start: 302, end: 271 }, { start: 423, end: 266 }, { start: 266, end: 371 }, { start: 371, end: 423 }, { start: 294, end: 455 }, { start: 455, end: 460 }, { start: 460, end: 294 }, { start: 279, end: 278 }, { start: 278, end: 294 }, { start: 294, end: 279 }, { start: 271, end: 272 }, { start: 272, end: 304 }, { start: 304, end: 271 }, { start: 432, end: 434 }, { start: 434, end: 427 }, { start: 427, end: 432 }, { start: 272, end: 407 }, { start: 407, end: 408 }, { start: 408, end: 272 }, { start: 394, end: 430 }, { start: 430, end: 431 }, { start: 431, end: 394 }, { start: 395, end: 369 }, { start: 369, end: 400 }, { start: 400, end: 395 }, { start: 334, end: 333 }, { start: 333, end: 299 }, { start: 299, end: 334 }, { start: 351, end: 417 }, { start: 417, end: 168 }, { start: 168, end: 351 }, { start: 352, end: 280 }, { start: 280, end: 411 }, { start: 411, end: 352 }, { start: 325, end: 319 }, { start: 319, end: 320 }, { start: 320, end: 325 }, { start: 295, end: 296 }, { start: 296, end: 336 }, { start: 336, end: 295 }, { start: 319, end: 403 }, { start: 403, end: 404 }, { start: 404, end: 319 }, { start: 330, end: 348 }, { start: 348, end: 349 }, { start: 349, end: 330 }, { start: 293, end: 298 }, { start: 298, end: 333 }, { start: 333, end: 293 }, { start: 323, end: 454 }, { start: 454, end: 447 }, { start: 447, end: 323 }, { start: 15, end: 16 }, { start: 16, end: 315 }, { start: 315, end: 15 }, { start: 358, end: 429 }, { start: 429, end: 279 }, { start: 279, end: 358 }, { start: 14, end: 15 }, { start: 15, end: 316 }, { start: 316, end: 14 }, { start: 285, end: 336 }, { start: 336, end: 9 }, { start: 9, end: 285 }, { start: 329, end: 349 }, { start: 349, end: 350 }, { start: 350, end: 329 }, { start: 374, end: 380 }, { start: 380, end: 252 }, { start: 252, end: 374 }, { start: 318, end: 402 }, { start: 402, end: 403 }, { start: 403, end: 318 }, { start: 6, end: 197 }, { start: 197, end: 419 }, { start: 419, end: 6 }, { start: 318, end: 319 }, { start: 319, end: 325 }, { start: 325, end: 318 }, { start: 367, end: 364 }, { start: 364, end: 365 }, { start: 365, end: 367 }, { start: 435, end: 367 }, { start: 367, end: 397 }, { start: 397, end: 435 }, { start: 344, end: 438 }, { start: 438, end: 439 }, { start: 439, end: 344 }, { start: 272, end: 271 }, { start: 271, end: 311 }, { start: 311, end: 272 }, { start: 195, end: 5 }, { start: 5, end: 281 }, { start: 281, end: 195 }, { start: 273, end: 287 }, { start: 287, end: 291 }, { start: 291, end: 273 }, { start: 396, end: 428 }, { start: 428, end: 199 }, { start: 199, end: 396 }, { start: 311, end: 271 }, { start: 271, end: 268 }, { start: 268, end: 311 }, { start: 283, end: 444 }, { start: 444, end: 445 }, { start: 445, end: 283 }, { start: 373, end: 254 }, { start: 254, end: 339 }, { start: 339, end: 373 }, { start: 282, end: 334 }, { start: 334, end: 296 }, { start: 296, end: 282 }, { start: 449, end: 347 }, { start: 347, end: 346 }, { start: 346, end: 449 }, { start: 264, end: 447 }, { start: 447, end: 454 }, { start: 454, end: 264 }, { start: 336, end: 296 }, { start: 296, end: 299 }, { start: 299, end: 336 }, { start: 338, end: 10 }, { start: 10, end: 151 }, { start: 151, end: 338 }, { start: 278, end: 439 }, { start: 439, end: 455 }, { start: 455, end: 278 }, { start: 292, end: 407 }, { start: 407, end: 415 }, { start: 415, end: 292 }, { start: 358, end: 371 }, { start: 371, end: 355 }, { start: 355, end: 358 }, { start: 340, end: 345 }, { start: 345, end: 372 }, { start: 372, end: 340 }, { start: 346, end: 347 }, { start: 347, end: 280 }, { start: 280, end: 346 }, { start: 442, end: 443 }, { start: 443, end: 282 }, { start: 282, end: 442 }, { start: 19, end: 94 }, { start: 94, end: 370 }, { start: 370, end: 19 }, { start: 441, end: 442 }, { start: 442, end: 295 }, { start: 295, end: 441 }, { start: 248, end: 419 }, { start: 419, end: 197 }, { start: 197, end: 248 }, { start: 263, end: 255 }, { start: 255, end: 359 }, { start: 359, end: 263 }, { start: 440, end: 275 }, { start: 275, end: 274 }, { start: 274, end: 440 }, { start: 300, end: 383 }, { start: 383, end: 368 }, { start: 368, end: 300 }, { start: 351, end: 412 }, { start: 412, end: 465 }, { start: 465, end: 351 }, { start: 263, end: 467 }, { start: 467, end: 466 }, { start: 466, end: 263 }, { start: 301, end: 368 }, { start: 368, end: 389 }, { start: 389, end: 301 }, { start: 395, end: 378 }, { start: 378, end: 379 }, { start: 379, end: 395 }, { start: 412, end: 351 }, { start: 351, end: 419 }, { start: 419, end: 412 }, { start: 436, end: 426 }, { start: 426, end: 322 }, { start: 322, end: 436 }, { start: 2, end: 164 }, { start: 164, end: 393 }, { start: 393, end: 2 }, { start: 370, end: 462 }, { start: 462, end: 461 }, { start: 461, end: 370 }, { start: 164, end: 0 }, { start: 0, end: 267 }, { start: 267, end: 164 }, { start: 302, end: 11 }, { start: 11, end: 12 }, { start: 12, end: 302 }, { start: 268, end: 12 }, { start: 12, end: 13 }, { start: 13, end: 268 }, { start: 293, end: 300 }, { start: 300, end: 301 }, { start: 301, end: 293 }, { start: 446, end: 261 }, { start: 261, end: 340 }, { start: 340, end: 446 }, { start: 330, end: 266 }, { start: 266, end: 425 }, { start: 425, end: 330 }, { start: 426, end: 423 }, { start: 423, end: 391 }, { start: 391, end: 426 }, { start: 429, end: 355 }, { start: 355, end: 437 }, { start: 437, end: 429 }, { start: 391, end: 327 }, { start: 327, end: 326 }, { start: 326, end: 391 }, { start: 440, end: 457 }, { start: 457, end: 438 }, { start: 438, end: 440 }, { start: 341, end: 382 }, { start: 382, end: 362 }, { start: 362, end: 341 }, { start: 459, end: 457 }, { start: 457, end: 461 }, { start: 461, end: 459 }, { start: 434, end: 430 }, { start: 430, end: 394 }, { start: 394, end: 434 }, { start: 414, end: 463 }, { start: 463, end: 362 }, { start: 362, end: 414 }, { start: 396, end: 369 }, { start: 369, end: 262 }, { start: 262, end: 396 }, { start: 354, end: 461 }, { start: 461, end: 457 }, { start: 457, end: 354 }, { start: 316, end: 403 }, { start: 403, end: 402 }, { start: 402, end: 316 }, { start: 315, end: 404 }, { start: 404, end: 403 }, { start: 403, end: 315 }, { start: 314, end: 405 }, { start: 405, end: 404 }, { start: 404, end: 314 }, { start: 313, end: 406 }, { start: 406, end: 405 }, { start: 405, end: 313 }, { start: 421, end: 418 }, { start: 418, end: 406 }, { start: 406, end: 421 }, { start: 366, end: 401 }, { start: 401, end: 361 }, { start: 361, end: 366 }, { start: 306, end: 408 }, { start: 408, end: 407 }, { start: 407, end: 306 }, { start: 291, end: 409 }, { start: 409, end: 408 }, { start: 408, end: 291 }, { start: 287, end: 410 }, { start: 410, end: 409 }, { start: 409, end: 287 }, { start: 432, end: 436 }, { start: 436, end: 410 }, { start: 410, end: 432 }, { start: 434, end: 416 }, { start: 416, end: 411 }, { start: 411, end: 434 }, { start: 264, end: 368 }, { start: 368, end: 383 }, { start: 383, end: 264 }, { start: 309, end: 438 }, { start: 438, end: 457 }, { start: 457, end: 309 }, { start: 352, end: 376 }, { start: 376, end: 401 }, { start: 401, end: 352 }, { start: 274, end: 275 }, { start: 275, end: 4 }, { start: 4, end: 274 }, { start: 421, end: 428 }, { start: 428, end: 262 }, { start: 262, end: 421 }, { start: 294, end: 327 }, { start: 327, end: 358 }, { start: 358, end: 294 }, { start: 433, end: 416 }, { start: 416, end: 367 }, { start: 367, end: 433 }, { start: 289, end: 455 }, { start: 455, end: 439 }, { start: 439, end: 289 }, { start: 462, end: 370 }, { start: 370, end: 326 }, { start: 326, end: 462 }, { start: 2, end: 326 }, { start: 326, end: 370 }, { start: 370, end: 2 }, { start: 305, end: 460 }, { start: 460, end: 455 }, { start: 455, end: 305 }, { start: 254, end: 449 }, { start: 449, end: 448 }, { start: 448, end: 254 }, { start: 255, end: 261 }, { start: 261, end: 446 }, { start: 446, end: 255 }, { start: 253, end: 450 }, { start: 450, end: 449 }, { start: 449, end: 253 }, { start: 252, end: 451 }, { start: 451, end: 450 }, { start: 450, end: 252 }, { start: 256, end: 452 }, { start: 452, end: 451 }, { start: 451, end: 256 }, { start: 341, end: 453 }, { start: 453, end: 452 }, { start: 452, end: 341 }, { start: 413, end: 464 }, { start: 464, end: 463 }, { start: 463, end: 413 }, { start: 441, end: 413 }, { start: 413, end: 414 }, { start: 414, end: 441 }, { start: 258, end: 442 }, { start: 442, end: 441 }, { start: 441, end: 258 }, { start: 257, end: 443 }, { start: 443, end: 442 }, { start: 442, end: 257 }, { start: 259, end: 444 }, { start: 444, end: 443 }, { start: 443, end: 259 }, { start: 260, end: 445 }, { start: 445, end: 444 }, { start: 444, end: 260 }, { start: 467, end: 342 }, { start: 342, end: 445 }, { start: 445, end: 467 }, { start: 459, end: 458 }, { start: 458, end: 250 }, { start: 250, end: 459 }, { start: 289, end: 392 }, { start: 392, end: 290 }, { start: 290, end: 289 }, { start: 290, end: 328 }, { start: 328, end: 460 }, { start: 460, end: 290 }, { start: 376, end: 433 }, { start: 433, end: 435 }, { start: 435, end: 376 }, { start: 250, end: 290 }, { start: 290, end: 392 }, { start: 392, end: 250 }, { start: 411, end: 416 }, { start: 416, end: 433 }, { start: 433, end: 411 }, { start: 341, end: 463 }, { start: 463, end: 464 }, { start: 464, end: 341 }, { start: 453, end: 464 }, { start: 464, end: 465 }, { start: 465, end: 453 }, { start: 357, end: 465 }, { start: 465, end: 412 }, { start: 412, end: 357 }, { start: 343, end: 412 }, { start: 412, end: 399 }, { start: 399, end: 343 }, { start: 360, end: 363 }, { start: 363, end: 440 }, { start: 440, end: 360 }, { start: 437, end: 399 }, { start: 399, end: 456 }, { start: 456, end: 437 }, { start: 420, end: 456 }, { start: 456, end: 363 }, { start: 363, end: 420 }, { start: 401, end: 435 }, { start: 435, end: 288 }, { start: 288, end: 401 }, { start: 372, end: 383 }, { start: 383, end: 353 }, { start: 353, end: 372 }, { start: 339, end: 255 }, { start: 255, end: 249 }, { start: 249, end: 339 }, { start: 448, end: 261 }, { start: 261, end: 255 }, { start: 255, end: 448 }, { start: 133, end: 243 }, { start: 243, end: 190 }, { start: 190, end: 133 }, { start: 133, end: 155 }, { start: 155, end: 112 }, { start: 112, end: 133 }, { start: 33, end: 246 }, { start: 246, end: 247 }, { start: 247, end: 33 }, { start: 33, end: 130 }, { start: 130, end: 25 }, { start: 25, end: 33 }, { start: 398, end: 384 }, { start: 384, end: 286 }, { start: 286, end: 398 }, { start: 362, end: 398 }, { start: 398, end: 414 }, { start: 414, end: 362 }, { start: 362, end: 463 }, { start: 463, end: 341 }, { start: 341, end: 362 }, { start: 263, end: 359 }, { start: 359, end: 467 }, { start: 467, end: 263 }, { start: 263, end: 249 }, { start: 249, end: 255 }, { start: 255, end: 263 }, { start: 466, end: 467 }, { start: 467, end: 260 }, { start: 260, end: 466 }, { start: 75, end: 60 }, { start: 60, end: 166 }, { start: 166, end: 75 }, { start: 238, end: 239 }, { start: 239, end: 79 }, { start: 79, end: 238 }, { start: 162, end: 127 }, { start: 127, end: 139 }, { start: 139, end: 162 }, { start: 72, end: 11 }, { start: 11, end: 37 }, { start: 37, end: 72 }, { start: 121, end: 232 }, { start: 232, end: 120 }, { start: 120, end: 121 }, { start: 73, end: 72 }, { start: 72, end: 39 }, { start: 39, end: 73 }, { start: 114, end: 128 }, { start: 128, end: 47 }, { start: 47, end: 114 }, { start: 233, end: 232 }, { start: 232, end: 128 }, { start: 128, end: 233 }, { start: 103, end: 104 }, { start: 104, end: 67 }, { start: 67, end: 103 }, { start: 152, end: 175 }, { start: 175, end: 148 }, { start: 148, end: 152 }, { start: 119, end: 118 }, { start: 118, end: 101 }, { start: 101, end: 119 }, { start: 74, end: 73 }, { start: 73, end: 40 }, { start: 40, end: 74 }, { start: 107, end: 9 }, { start: 9, end: 108 }, { start: 108, end: 107 }, { start: 49, end: 48 }, { start: 48, end: 131 }, { start: 131, end: 49 }, { start: 32, end: 194 }, { start: 194, end: 211 }, { start: 211, end: 32 }, { start: 184, end: 74 }, { start: 74, end: 185 }, { start: 185, end: 184 }, { start: 191, end: 80 }, { start: 80, end: 183 }, { start: 183, end: 191 }, { start: 185, end: 40 }, { start: 40, end: 186 }, { start: 186, end: 185 }, { start: 119, end: 230 }, { start: 230, end: 118 }, { start: 118, end: 119 }, { start: 210, end: 202 }, { start: 202, end: 214 }, { start: 214, end: 210 }, { start: 84, end: 83 }, { start: 83, end: 17 }, { start: 17, end: 84 }, { start: 77, end: 76 }, { start: 76, end: 146 }, { start: 146, end: 77 }, { start: 161, end: 160 }, { start: 160, end: 30 }, { start: 30, end: 161 }, { start: 190, end: 56 }, { start: 56, end: 173 }, { start: 173, end: 190 }, { start: 182, end: 106 }, { start: 106, end: 194 }, { start: 194, end: 182 }, { start: 138, end: 135 }, { start: 135, end: 192 }, { start: 192, end: 138 }, { start: 129, end: 203 }, { start: 203, end: 98 }, { start: 98, end: 129 }, { start: 54, end: 21 }, { start: 21, end: 68 }, { start: 68, end: 54 }, { start: 5, end: 51 }, { start: 51, end: 4 }, { start: 4, end: 5 }, { start: 145, end: 144 }, { start: 144, end: 23 }, { start: 23, end: 145 }, { start: 90, end: 77 }, { start: 77, end: 91 }, { start: 91, end: 90 }, { start: 207, end: 205 }, { start: 205, end: 187 }, { start: 187, end: 207 }, { start: 83, end: 201 }, { start: 201, end: 18 }, { start: 18, end: 83 }, { start: 181, end: 91 }, { start: 91, end: 182 }, { start: 182, end: 181 }, { start: 180, end: 90 }, { start: 90, end: 181 }, { start: 181, end: 180 }, { start: 16, end: 85 }, { start: 85, end: 17 }, { start: 17, end: 16 }, { start: 205, end: 206 }, { start: 206, end: 36 }, { start: 36, end: 205 }, { start: 176, end: 148 }, { start: 148, end: 140 }, { start: 140, end: 176 }, { start: 165, end: 92 }, { start: 92, end: 39 }, { start: 39, end: 165 }, { start: 245, end: 193 }, { start: 193, end: 244 }, { start: 244, end: 245 }, { start: 27, end: 159 }, { start: 159, end: 28 }, { start: 28, end: 27 }, { start: 30, end: 247 }, { start: 247, end: 161 }, { start: 161, end: 30 }, { start: 174, end: 236 }, { start: 236, end: 196 }, { start: 196, end: 174 }, { start: 103, end: 54 }, { start: 54, end: 104 }, { start: 104, end: 103 }, { start: 55, end: 193 }, { start: 193, end: 8 }, { start: 8, end: 55 }, { start: 111, end: 117 }, { start: 117, end: 31 }, { start: 31, end: 111 }, { start: 221, end: 189 }, { start: 189, end: 55 }, { start: 55, end: 221 }, { start: 240, end: 98 }, { start: 98, end: 99 }, { start: 99, end: 240 }, { start: 142, end: 126 }, { start: 126, end: 100 }, { start: 100, end: 142 }, { start: 219, end: 166 }, { start: 166, end: 218 }, { start: 218, end: 219 }, { start: 112, end: 155 }, { start: 155, end: 26 }, { start: 26, end: 112 }, { start: 198, end: 209 }, { start: 209, end: 131 }, { start: 131, end: 198 }, { start: 169, end: 135 }, { start: 135, end: 150 }, { start: 150, end: 169 }, { start: 114, end: 47 }, { start: 47, end: 217 }, { start: 217, end: 114 }, { start: 224, end: 223 }, { start: 223, end: 53 }, { start: 53, end: 224 }, { start: 220, end: 45 }, { start: 45, end: 134 }, { start: 134, end: 220 }, { start: 32, end: 211 }, { start: 211, end: 140 }, { start: 140, end: 32 }, { start: 109, end: 67 }, { start: 67, end: 108 }, { start: 108, end: 109 }, { start: 146, end: 43 }, { start: 43, end: 91 }, { start: 91, end: 146 }, { start: 231, end: 230 }, { start: 230, end: 120 }, { start: 120, end: 231 }, { start: 113, end: 226 }, { start: 226, end: 247 }, { start: 247, end: 113 }, { start: 105, end: 63 }, { start: 63, end: 52 }, { start: 52, end: 105 }, { start: 241, end: 238 }, { start: 238, end: 242 }, { start: 242, end: 241 }, { start: 124, end: 46 }, { start: 46, end: 156 }, { start: 156, end: 124 }, { start: 95, end: 78 }, { start: 78, end: 96 }, { start: 96, end: 95 }, { start: 70, end: 46 }, { start: 46, end: 63 }, { start: 63, end: 70 }, { start: 116, end: 143 }, { start: 143, end: 227 }, { start: 227, end: 116 }, { start: 116, end: 123 }, { start: 123, end: 111 }, { start: 111, end: 116 }, { start: 1, end: 44 }, { start: 44, end: 19 }, { start: 19, end: 1 }, { start: 3, end: 236 }, { start: 236, end: 51 }, { start: 51, end: 3 }, { start: 207, end: 216 }, { start: 216, end: 205 }, { start: 205, end: 207 }, { start: 26, end: 154 }, { start: 154, end: 22 }, { start: 22, end: 26 }, { start: 165, end: 39 }, { start: 39, end: 167 }, { start: 167, end: 165 }, { start: 199, end: 200 }, { start: 200, end: 208 }, { start: 208, end: 199 }, { start: 101, end: 36 }, { start: 36, end: 100 }, { start: 100, end: 101 }, { start: 43, end: 57 }, { start: 57, end: 202 }, { start: 202, end: 43 }, { start: 242, end: 20 }, { start: 20, end: 99 }, { start: 99, end: 242 }, { start: 56, end: 28 }, { start: 28, end: 157 }, { start: 157, end: 56 }, { start: 124, end: 35 }, { start: 35, end: 113 }, { start: 113, end: 124 }, { start: 29, end: 160 }, { start: 160, end: 27 }, { start: 27, end: 29 }, { start: 211, end: 204 }, { start: 204, end: 210 }, { start: 210, end: 211 }, { start: 124, end: 113 }, { start: 113, end: 46 }, { start: 46, end: 124 }, { start: 106, end: 43 }, { start: 43, end: 204 }, { start: 204, end: 106 }, { start: 96, end: 62 }, { start: 62, end: 77 }, { start: 77, end: 96 }, { start: 227, end: 137 }, { start: 137, end: 116 }, { start: 116, end: 227 }, { start: 73, end: 41 }, { start: 41, end: 72 }, { start: 72, end: 73 }, { start: 36, end: 203 }, { start: 203, end: 142 }, { start: 142, end: 36 }, { start: 235, end: 64 }, { start: 64, end: 240 }, { start: 240, end: 235 }, { start: 48, end: 49 }, { start: 49, end: 64 }, { start: 64, end: 48 }, { start: 42, end: 41 }, { start: 41, end: 74 }, { start: 74, end: 42 }, { start: 214, end: 212 }, { start: 212, end: 207 }, { start: 207, end: 214 }, { start: 183, end: 42 }, { start: 42, end: 184 }, { start: 184, end: 183 }, { start: 210, end: 169 }, { start: 169, end: 211 }, { start: 211, end: 210 }, { start: 140, end: 170 }, { start: 170, end: 176 }, { start: 176, end: 140 }, { start: 104, end: 105 }, { start: 105, end: 69 }, { start: 69, end: 104 }, { start: 193, end: 122 }, { start: 122, end: 168 }, { start: 168, end: 193 }, { start: 50, end: 123 }, { start: 123, end: 187 }, { start: 187, end: 50 }, { start: 89, end: 96 }, { start: 96, end: 90 }, { start: 90, end: 89 }, { start: 66, end: 65 }, { start: 65, end: 107 }, { start: 107, end: 66 }, { start: 179, end: 89 }, { start: 89, end: 180 }, { start: 180, end: 179 }, { start: 119, end: 101 }, { start: 101, end: 120 }, { start: 120, end: 119 }, { start: 68, end: 63 }, { start: 63, end: 104 }, { start: 104, end: 68 }, { start: 234, end: 93 }, { start: 93, end: 227 }, { start: 227, end: 234 }, { start: 16, end: 15 }, { start: 15, end: 85 }, { start: 85, end: 16 }, { start: 209, end: 129 }, { start: 129, end: 49 }, { start: 49, end: 209 }, { start: 15, end: 14 }, { start: 14, end: 86 }, { start: 86, end: 15 }, { start: 107, end: 55 }, { start: 55, end: 9 }, { start: 9, end: 107 }, { start: 120, end: 100 }, { start: 100, end: 121 }, { start: 121, end: 120 }, { start: 153, end: 145 }, { start: 145, end: 22 }, { start: 22, end: 153 }, { start: 178, end: 88 }, { start: 88, end: 179 }, { start: 179, end: 178 }, { start: 197, end: 6 }, { start: 6, end: 196 }, { start: 196, end: 197 }, { start: 89, end: 88 }, { start: 88, end: 96 }, { start: 96, end: 89 }, { start: 135, end: 138 }, { start: 138, end: 136 }, { start: 136, end: 135 }, { start: 138, end: 215 }, { start: 215, end: 172 }, { start: 172, end: 138 }, { start: 218, end: 115 }, { start: 115, end: 219 }, { start: 219, end: 218 }, { start: 41, end: 42 }, { start: 42, end: 81 }, { start: 81, end: 41 }, { start: 5, end: 195 }, { start: 195, end: 51 }, { start: 51, end: 5 }, { start: 57, end: 43 }, { start: 43, end: 61 }, { start: 61, end: 57 }, { start: 208, end: 171 }, { start: 171, end: 199 }, { start: 199, end: 208 }, { start: 41, end: 81 }, { start: 81, end: 38 }, { start: 38, end: 41 }, { start: 224, end: 53 }, { start: 53, end: 225 }, { start: 225, end: 224 }, { start: 24, end: 144 }, { start: 144, end: 110 }, { start: 110, end: 24 }, { start: 105, end: 52 }, { start: 52, end: 66 }, { start: 66, end: 105 }, { start: 118, end: 229 }, { start: 229, end: 117 }, { start: 117, end: 118 }, { start: 227, end: 34 }, { start: 34, end: 234 }, { start: 234, end: 227 }, { start: 66, end: 107 }, { start: 107, end: 69 }, { start: 69, end: 66 }, { start: 10, end: 109 }, { start: 109, end: 151 }, { start: 151, end: 10 }, { start: 219, end: 48 }, { start: 48, end: 235 }, { start: 235, end: 219 }, { start: 183, end: 62 }, { start: 62, end: 191 }, { start: 191, end: 183 }, { start: 142, end: 129 }, { start: 129, end: 126 }, { start: 126, end: 142 }, { start: 116, end: 111 }, { start: 111, end: 143 }, { start: 143, end: 116 }, { start: 118, end: 117 }, { start: 117, end: 50 }, { start: 50, end: 118 }, { start: 223, end: 222 }, { start: 222, end: 52 }, { start: 52, end: 223 }, { start: 94, end: 19 }, { start: 19, end: 141 }, { start: 141, end: 94 }, { start: 222, end: 221 }, { start: 221, end: 65 }, { start: 65, end: 222 }, { start: 196, end: 3 }, { start: 3, end: 197 }, { start: 197, end: 196 }, { start: 45, end: 220 }, { start: 220, end: 44 }, { start: 44, end: 45 }, { start: 156, end: 70 }, { start: 70, end: 139 }, { start: 139, end: 156 }, { start: 188, end: 122 }, { start: 122, end: 245 }, { start: 245, end: 188 }, { start: 139, end: 71 }, { start: 71, end: 162 }, { start: 162, end: 139 }, { start: 149, end: 170 }, { start: 170, end: 150 }, { start: 150, end: 149 }, { start: 122, end: 188 }, { start: 188, end: 196 }, { start: 196, end: 122 }, { start: 206, end: 216 }, { start: 216, end: 92 }, { start: 92, end: 206 }, { start: 164, end: 2 }, { start: 2, end: 167 }, { start: 167, end: 164 }, { start: 242, end: 141 }, { start: 141, end: 241 }, { start: 241, end: 242 }, { start: 0, end: 164 }, { start: 164, end: 37 }, { start: 37, end: 0 }, { start: 11, end: 72 }, { start: 72, end: 12 }, { start: 12, end: 11 }, { start: 12, end: 38 }, { start: 38, end: 13 }, { start: 13, end: 12 }, { start: 70, end: 63 }, { start: 63, end: 71 }, { start: 71, end: 70 }, { start: 31, end: 226 }, { start: 226, end: 111 }, { start: 111, end: 31 }, { start: 36, end: 101 }, { start: 101, end: 205 }, { start: 205, end: 36 }, { start: 203, end: 206 }, { start: 206, end: 165 }, { start: 165, end: 203 }, { start: 126, end: 209 }, { start: 209, end: 217 }, { start: 217, end: 126 }, { start: 98, end: 165 }, { start: 165, end: 97 }, { start: 97, end: 98 }, { start: 237, end: 220 }, { start: 220, end: 218 }, { start: 218, end: 237 }, { start: 237, end: 239 }, { start: 239, end: 241 }, { start: 241, end: 237 }, { start: 210, end: 214 }, { start: 214, end: 169 }, { start: 169, end: 210 }, { start: 140, end: 171 }, { start: 171, end: 32 }, { start: 32, end: 140 }, { start: 241, end: 125 }, { start: 125, end: 237 }, { start: 237, end: 241 }, { start: 179, end: 86 }, { start: 86, end: 178 }, { start: 178, end: 179 }, { start: 180, end: 85 }, { start: 85, end: 179 }, { start: 179, end: 180 }, { start: 181, end: 84 }, { start: 84, end: 180 }, { start: 180, end: 181 }, { start: 182, end: 83 }, { start: 83, end: 181 }, { start: 181, end: 182 }, { start: 194, end: 201 }, { start: 201, end: 182 }, { start: 182, end: 194 }, { start: 177, end: 137 }, { start: 137, end: 132 }, { start: 132, end: 177 }, { start: 184, end: 76 }, { start: 76, end: 183 }, { start: 183, end: 184 }, { start: 185, end: 61 }, { start: 61, end: 184 }, { start: 184, end: 185 }, { start: 186, end: 57 }, { start: 57, end: 185 }, { start: 185, end: 186 }, { start: 216, end: 212 }, { start: 212, end: 186 }, { start: 186, end: 216 }, { start: 192, end: 214 }, { start: 214, end: 187 }, { start: 187, end: 192 }, { start: 139, end: 34 }, { start: 34, end: 156 }, { start: 156, end: 139 }, { start: 218, end: 79 }, { start: 79, end: 237 }, { start: 237, end: 218 }, { start: 147, end: 123 }, { start: 123, end: 177 }, { start: 177, end: 147 }, { start: 45, end: 44 }, { start: 44, end: 4 }, { start: 4, end: 45 }, { start: 208, end: 201 }, { start: 201, end: 32 }, { start: 32, end: 208 }, { start: 98, end: 64 }, { start: 64, end: 129 }, { start: 129, end: 98 }, { start: 192, end: 213 }, { start: 213, end: 138 }, { start: 138, end: 192 }, { start: 235, end: 59 }, { start: 59, end: 219 }, { start: 219, end: 235 }, { start: 141, end: 242 }, { start: 242, end: 97 }, { start: 97, end: 141 }, { start: 97, end: 2 }, { start: 2, end: 141 }, { start: 141, end: 97 }, { start: 240, end: 75 }, { start: 75, end: 235 }, { start: 235, end: 240 }, { start: 229, end: 24 }, { start: 24, end: 228 }, { start: 228, end: 229 }, { start: 31, end: 25 }, { start: 25, end: 226 }, { start: 226, end: 31 }, { start: 230, end: 23 }, { start: 23, end: 229 }, { start: 229, end: 230 }, { start: 231, end: 22 }, { start: 22, end: 230 }, { start: 230, end: 231 }, { start: 232, end: 26 }, { start: 26, end: 231 }, { start: 231, end: 232 }, { start: 233, end: 112 }, { start: 112, end: 232 }, { start: 232, end: 233 }, { start: 244, end: 189 }, { start: 189, end: 243 }, { start: 243, end: 244 }, { start: 189, end: 221 }, { start: 221, end: 190 }, { start: 190, end: 189 }, { start: 222, end: 28 }, { start: 28, end: 221 }, { start: 221, end: 222 }, { start: 223, end: 27 }, { start: 27, end: 222 }, { start: 222, end: 223 }, { start: 224, end: 29 }, { start: 29, end: 223 }, { start: 223, end: 224 }, { start: 225, end: 30 }, { start: 30, end: 224 }, { start: 224, end: 225 }, { start: 113, end: 247 }, { start: 247, end: 225 }, { start: 225, end: 113 }, { start: 99, end: 60 }, { start: 60, end: 240 }, { start: 240, end: 99 }, { start: 213, end: 147 }, { start: 147, end: 215 }, { start: 215, end: 213 }, { start: 60, end: 20 }, { start: 20, end: 166 }, { start: 166, end: 60 }, { start: 192, end: 187 }, { start: 187, end: 213 }, { start: 213, end: 192 }, { start: 243, end: 112 }, { start: 112, end: 244 }, { start: 244, end: 243 }, { start: 244, end: 233 }, { start: 233, end: 245 }, { start: 245, end: 244 }, { start: 245, end: 128 }, { start: 128, end: 188 }, { start: 188, end: 245 }, { start: 188, end: 114 }, { start: 114, end: 174 }, { start: 174, end: 188 }, { start: 134, end: 131 }, { start: 131, end: 220 }, { start: 220, end: 134 }, { start: 174, end: 217 }, { start: 217, end: 236 }, { start: 236, end: 174 }, { start: 236, end: 198 }, { start: 198, end: 134 }, { start: 134, end: 236 }, { start: 215, end: 177 }, { start: 177, end: 58 }, { start: 58, end: 215 }, { start: 156, end: 143 }, { start: 143, end: 124 }, { start: 124, end: 156 }, { start: 25, end: 110 }, { start: 110, end: 7 }, { start: 7, end: 25 }, { start: 31, end: 228 }, { start: 228, end: 25 }, { start: 25, end: 31 }, { start: 264, end: 356 }, { start: 356, end: 368 }, { start: 368, end: 264 }, { start: 0, end: 11 }, { start: 11, end: 267 }, { start: 267, end: 0 }, { start: 451, end: 452 }, { start: 452, end: 349 }, { start: 349, end: 451 }, { start: 267, end: 302 }, { start: 302, end: 269 }, { start: 269, end: 267 }, { start: 350, end: 357 }, { start: 357, end: 277 }, { start: 277, end: 350 }, { start: 350, end: 452 }, { start: 452, end: 357 }, { start: 357, end: 350 }, { start: 299, end: 333 }, { start: 333, end: 297 }, { start: 297, end: 299 }, { start: 396, end: 175 }, { start: 175, end: 377 }, { start: 377, end: 396 }, { start: 280, end: 347 }, { start: 347, end: 330 }, { start: 330, end: 280 }, { start: 269, end: 303 }, { start: 303, end: 270 }, { start: 270, end: 269 }, { start: 151, end: 9 }, { start: 9, end: 337 }, { start: 337, end: 151 }, { start: 344, end: 278 }, { start: 278, end: 360 }, { start: 360, end: 344 }, { start: 424, end: 418 }, { start: 418, end: 431 }, { start: 431, end: 424 }, { start: 270, end: 304 }, { start: 304, end: 409 }, { start: 409, end: 270 }, { start: 272, end: 310 }, { start: 310, end: 407 }, { start: 407, end: 272 }, { start: 322, end: 270 }, { start: 270, end: 410 }, { start: 410, end: 322 }, { start: 449, end: 450 }, { start: 450, end: 347 }, { start: 347, end: 449 }, { start: 432, end: 422 }, { start: 422, end: 434 }, { start: 434, end: 432 }, { start: 18, end: 313 }, { start: 313, end: 17 }, { start: 17, end: 18 }, { start: 291, end: 306 }, { start: 306, end: 375 }, { start: 375, end: 291 }, { start: 259, end: 387 }, { start: 387, end: 260 }, { start: 260, end: 259 }, { start: 424, end: 335 }, { start: 335, end: 418 }, { start: 418, end: 424 }, { start: 434, end: 364 }, { start: 364, end: 416 }, { start: 416, end: 434 }, { start: 391, end: 423 }, { start: 423, end: 327 }, { start: 327, end: 391 }, { start: 301, end: 251 }, { start: 251, end: 298 }, { start: 298, end: 301 }, { start: 275, end: 281 }, { start: 281, end: 4 }, { start: 4, end: 275 }, { start: 254, end: 373 }, { start: 373, end: 253 }, { start: 253, end: 254 }, { start: 375, end: 307 }, { start: 307, end: 321 }, { start: 321, end: 375 }, { start: 280, end: 425 }, { start: 425, end: 411 }, { start: 411, end: 280 }, { start: 200, end: 421 }, { start: 421, end: 18 }, { start: 18, end: 200 }, { start: 335, end: 321 }, { start: 321, end: 406 }, { start: 406, end: 335 }, { start: 321, end: 320 }, { start: 320, end: 405 }, { start: 405, end: 321 }, { start: 314, end: 315 }, { start: 315, end: 17 }, { start: 17, end: 314 }, { start: 423, end: 426 }, { start: 426, end: 266 }, { start: 266, end: 423 }, { start: 396, end: 377 }, { start: 377, end: 369 }, { start: 369, end: 396 }, { start: 270, end: 322 }, { start: 322, end: 269 }, { start: 269, end: 270 }, { start: 413, end: 417 }, { start: 417, end: 464 }, { start: 464, end: 413 }, { start: 385, end: 386 }, { start: 386, end: 258 }, { start: 258, end: 385 }, { start: 248, end: 456 }, { start: 456, end: 419 }, { start: 419, end: 248 }, { start: 298, end: 284 }, { start: 284, end: 333 }, { start: 333, end: 298 }, { start: 168, end: 417 }, { start: 417, end: 8 }, { start: 8, end: 168 }, { start: 448, end: 346 }, { start: 346, end: 261 }, { start: 261, end: 448 }, { start: 417, end: 413 }, { start: 413, end: 285 }, { start: 285, end: 417 }, { start: 326, end: 327 }, { start: 327, end: 328 }, { start: 328, end: 326 }, { start: 277, end: 355 }, { start: 355, end: 329 }, { start: 329, end: 277 }, { start: 309, end: 392 }, { start: 392, end: 438 }, { start: 438, end: 309 }, { start: 381, end: 382 }, { start: 382, end: 256 }, { start: 256, end: 381 }, { start: 279, end: 429 }, { start: 429, end: 360 }, { start: 360, end: 279 }, { start: 365, end: 364 }, { start: 364, end: 379 }, { start: 379, end: 365 }, { start: 355, end: 277 }, { start: 277, end: 437 }, { start: 437, end: 355 }, { start: 282, end: 443 }, { start: 443, end: 283 }, { start: 283, end: 282 }, { start: 281, end: 275 }, { start: 275, end: 363 }, { start: 363, end: 281 }, { start: 395, end: 431 }, { start: 431, end: 369 }, { start: 369, end: 395 }, { start: 299, end: 297 }, { start: 297, end: 337 }, { start: 337, end: 299 }, { start: 335, end: 273 }, { start: 273, end: 321 }, { start: 321, end: 335 }, { start: 348, end: 450 }, { start: 450, end: 349 }, { start: 349, end: 348 }, { start: 359, end: 446 }, { start: 446, end: 467 }, { start: 467, end: 359 }, { start: 283, end: 293 }, { start: 293, end: 282 }, { start: 282, end: 283 }, { start: 250, end: 458 }, { start: 458, end: 462 }, { start: 462, end: 250 }, { start: 300, end: 276 }, { start: 276, end: 383 }, { start: 383, end: 300 }, { start: 292, end: 308 }, { start: 308, end: 325 }, { start: 325, end: 292 }, { start: 283, end: 276 }, { start: 276, end: 293 }, { start: 293, end: 283 }, { start: 264, end: 372 }, { start: 372, end: 447 }, { start: 447, end: 264 }, { start: 346, end: 352 }, { start: 352, end: 340 }, { start: 340, end: 346 }, { start: 354, end: 274 }, { start: 274, end: 19 }, { start: 19, end: 354 }, { start: 363, end: 456 }, { start: 456, end: 281 }, { start: 281, end: 363 }, { start: 426, end: 436 }, { start: 436, end: 425 }, { start: 425, end: 426 }, { start: 380, end: 381 }, { start: 381, end: 252 }, { start: 252, end: 380 }, { start: 267, end: 269 }, { start: 269, end: 393 }, { start: 393, end: 267 }, { start: 421, end: 200 }, { start: 200, end: 428 }, { start: 428, end: 421 }, { start: 371, end: 266 }, { start: 266, end: 329 }, { start: 329, end: 371 }, { start: 432, end: 287 }, { start: 287, end: 422 }, { start: 422, end: 432 }, { start: 290, end: 250 }, { start: 250, end: 328 }, { start: 328, end: 290 }, { start: 385, end: 258 }, { start: 258, end: 384 }, { start: 384, end: 385 }, { start: 446, end: 265 }, { start: 265, end: 342 }, { start: 342, end: 446 }, { start: 386, end: 387 }, { start: 387, end: 257 }, { start: 257, end: 386 }, { start: 422, end: 424 }, { start: 424, end: 430 }, { start: 430, end: 422 }, { start: 445, end: 342 }, { start: 342, end: 276 }, { start: 276, end: 445 }, { start: 422, end: 273 }, { start: 273, end: 424 }, { start: 424, end: 422 }, { start: 306, end: 292 }, { start: 292, end: 307 }, { start: 307, end: 306 }, { start: 352, end: 366 }, { start: 366, end: 345 }, { start: 345, end: 352 }, { start: 268, end: 271 }, { start: 271, end: 302 }, { start: 302, end: 268 }, { start: 358, end: 423 }, { start: 423, end: 371 }, { start: 371, end: 358 }, { start: 327, end: 294 }, { start: 294, end: 460 }, { start: 460, end: 327 }, { start: 331, end: 279 }, { start: 279, end: 294 }, { start: 294, end: 331 }, { start: 303, end: 271 }, { start: 271, end: 304 }, { start: 304, end: 303 }, { start: 436, end: 432 }, { start: 432, end: 427 }, { start: 427, end: 436 }, { start: 304, end: 272 }, { start: 272, end: 408 }, { start: 408, end: 304 }, { start: 395, end: 394 }, { start: 394, end: 431 }, { start: 431, end: 395 }, { start: 378, end: 395 }, { start: 395, end: 400 }, { start: 400, end: 378 }, { start: 296, end: 334 }, { start: 334, end: 299 }, { start: 299, end: 296 }, { start: 6, end: 351 }, { start: 351, end: 168 }, { start: 168, end: 6 }, { start: 376, end: 352 }, { start: 352, end: 411 }, { start: 411, end: 376 }, { start: 307, end: 325 }, { start: 325, end: 320 }, { start: 320, end: 307 }, { start: 285, end: 295 }, { start: 295, end: 336 }, { start: 336, end: 285 }, { start: 320, end: 319 }, { start: 319, end: 404 }, { start: 404, end: 320 }, { start: 329, end: 330 }, { start: 330, end: 349 }, { start: 349, end: 329 }, { start: 334, end: 293 }, { start: 293, end: 333 }, { start: 333, end: 334 }, { start: 366, end: 323 }, { start: 323, end: 447 }, { start: 447, end: 366 }, { start: 316, end: 15 }, { start: 15, end: 315 }, { start: 315, end: 316 }, { start: 331, end: 358 }, { start: 358, end: 279 }, { start: 279, end: 331 }, { start: 317, end: 14 }, { start: 14, end: 316 }, { start: 316, end: 317 }, { start: 8, end: 285 }, { start: 285, end: 9 }, { start: 9, end: 8 }, { start: 277, end: 329 }, { start: 329, end: 350 }, { start: 350, end: 277 }, { start: 253, end: 374 }, { start: 374, end: 252 }, { start: 252, end: 253 }, { start: 319, end: 318 }, { start: 318, end: 403 }, { start: 403, end: 319 }, { start: 351, end: 6 }, { start: 6, end: 419 }, { start: 419, end: 351 }, { start: 324, end: 318 }, { start: 318, end: 325 }, { start: 325, end: 324 }, { start: 397, end: 367 }, { start: 367, end: 365 }, { start: 365, end: 397 }, { start: 288, end: 435 }, { start: 435, end: 397 }, { start: 397, end: 288 }, { start: 278, end: 344 }, { start: 344, end: 439 }, { start: 439, end: 278 }, { start: 310, end: 272 }, { start: 272, end: 311 }, { start: 311, end: 310 }, { start: 248, end: 195 }, { start: 195, end: 281 }, { start: 281, end: 248 }, { start: 375, end: 273 }, { start: 273, end: 291 }, { start: 291, end: 375 }, { start: 175, end: 396 }, { start: 396, end: 199 }, { start: 199, end: 175 }, { start: 312, end: 311 }, { start: 311, end: 268 }, { start: 268, end: 312 }, { start: 276, end: 283 }, { start: 283, end: 445 }, { start: 445, end: 276 }, { start: 390, end: 373 }, { start: 373, end: 339 }, { start: 339, end: 390 }, { start: 295, end: 282 }, { start: 282, end: 296 }, { start: 296, end: 295 }, { start: 448, end: 449 }, { start: 449, end: 346 }, { start: 346, end: 448 }, { start: 356, end: 264 }, { start: 264, end: 454 }, { start: 454, end: 356 }, { start: 337, end: 336 }, { start: 336, end: 299 }, { start: 299, end: 337 }, { start: 337, end: 338 }, { start: 338, end: 151 }, { start: 151, end: 337 }, { start: 294, end: 278 }, { start: 278, end: 455 }, { start: 455, end: 294 }, { start: 308, end: 292 }, { start: 292, end: 415 }, { start: 415, end: 308 }, { start: 429, end: 358 }, { start: 358, end: 355 }, { start: 355, end: 429 }, { start: 265, end: 340 }, { start: 340, end: 372 }, { start: 372, end: 265 }, { start: 352, end: 346 }, { start: 346, end: 280 }, { start: 280, end: 352 }, { start: 295, end: 442 }, { start: 442, end: 282 }, { start: 282, end: 295 }, { start: 354, end: 19 }, { start: 19, end: 370 }, { start: 370, end: 354 }, { start: 285, end: 441 }, { start: 441, end: 295 }, { start: 295, end: 285 }, { start: 195, end: 248 }, { start: 248, end: 197 }, { start: 197, end: 195 }, { start: 457, end: 440 }, { start: 440, end: 274 }, { start: 274, end: 457 }, { start: 301, end: 300 }, { start: 300, end: 368 }, { start: 368, end: 301 }, { start: 417, end: 351 }, { start: 351, end: 465 }, { start: 465, end: 417 }, { start: 251, end: 301 }, { start: 301, end: 389 }, { start: 389, end: 251 }, { start: 394, end: 395 }, { start: 395, end: 379 }, { start: 379, end: 394 }, { start: 399, end: 412 }, { start: 412, end: 419 }, { start: 419, end: 399 }, { start: 410, end: 436 }, { start: 436, end: 322 }, { start: 322, end: 410 }, { start: 326, end: 2 }, { start: 2, end: 393 }, { start: 393, end: 326 }, { start: 354, end: 370 }, { start: 370, end: 461 }, { start: 461, end: 354 }, { start: 393, end: 164 }, { start: 164, end: 267 }, { start: 267, end: 393 }, { start: 268, end: 302 }, { start: 302, end: 12 }, { start: 12, end: 268 }, { start: 312, end: 268 }, { start: 268, end: 13 }, { start: 13, end: 312 }, { start: 298, end: 293 }, { start: 293, end: 301 }, { start: 301, end: 298 }, { start: 265, end: 446 }, { start: 446, end: 340 }, { start: 340, end: 265 }, { start: 280, end: 330 }, { start: 330, end: 425 }, { start: 425, end: 280 }, { start: 322, end: 426 }, { start: 426, end: 391 }, { start: 391, end: 322 }, { start: 420, end: 429 }, { start: 429, end: 437 }, { start: 437, end: 420 }, { start: 393, end: 391 }, { start: 391, end: 326 }, { start: 326, end: 393 }, { start: 344, end: 440 }, { start: 440, end: 438 }, { start: 438, end: 344 }, { start: 458, end: 459 }, { start: 459, end: 461 }, { start: 461, end: 458 }, { start: 364, end: 434 }, { start: 434, end: 394 }, { start: 394, end: 364 }, { start: 428, end: 396 }, { start: 396, end: 262 }, { start: 262, end: 428 }, { start: 274, end: 354 }, { start: 354, end: 457 }, { start: 457, end: 274 }, { start: 317, end: 316 }, { start: 316, end: 402 }, { start: 402, end: 317 }, { start: 316, end: 315 }, { start: 315, end: 403 }, { start: 403, end: 316 }, { start: 315, end: 314 }, { start: 314, end: 404 }, { start: 404, end: 315 }, { start: 314, end: 313 }, { start: 313, end: 405 }, { start: 405, end: 314 }, { start: 313, end: 421 }, { start: 421, end: 406 }, { start: 406, end: 313 }, { start: 323, end: 366 }, { start: 366, end: 361 }, { start: 361, end: 323 }, { start: 292, end: 306 }, { start: 306, end: 407 }, { start: 407, end: 292 }, { start: 306, end: 291 }, { start: 291, end: 408 }, { start: 408, end: 306 }, { start: 291, end: 287 }, { start: 287, end: 409 }, { start: 409, end: 291 }, { start: 287, end: 432 }, { start: 432, end: 410 }, { start: 410, end: 287 }, { start: 427, end: 434 }, { start: 434, end: 411 }, { start: 411, end: 427 }, { start: 372, end: 264 }, { start: 264, end: 383 }, { start: 383, end: 372 }, { start: 459, end: 309 }, { start: 309, end: 457 }, { start: 457, end: 459 }, { start: 366, end: 352 }, { start: 352, end: 401 }, { start: 401, end: 366 }, { start: 1, end: 274 }, { start: 274, end: 4 }, { start: 4, end: 1 }, { start: 418, end: 421 }, { start: 421, end: 262 }, { start: 262, end: 418 }, { start: 331, end: 294 }, { start: 294, end: 358 }, { start: 358, end: 331 }, { start: 435, end: 433 }, { start: 433, end: 367 }, { start: 367, end: 435 }, { start: 392, end: 289 }, { start: 289, end: 439 }, { start: 439, end: 392 }, { start: 328, end: 462 }, { start: 462, end: 326 }, { start: 326, end: 328 }, { start: 94, end: 2 }, { start: 2, end: 370 }, { start: 370, end: 94 }, { start: 289, end: 305 }, { start: 305, end: 455 }, { start: 455, end: 289 }, { start: 339, end: 254 }, { start: 254, end: 448 }, { start: 448, end: 339 }, { start: 359, end: 255 }, { start: 255, end: 446 }, { start: 446, end: 359 }, { start: 254, end: 253 }, { start: 253, end: 449 }, { start: 449, end: 254 }, { start: 253, end: 252 }, { start: 252, end: 450 }, { start: 450, end: 253 }, { start: 252, end: 256 }, { start: 256, end: 451 }, { start: 451, end: 252 }, { start: 256, end: 341 }, { start: 341, end: 452 }, { start: 452, end: 256 }, { start: 414, end: 413 }, { start: 413, end: 463 }, { start: 463, end: 414 }, { start: 286, end: 441 }, { start: 441, end: 414 }, { start: 414, end: 286 }, { start: 286, end: 258 }, { start: 258, end: 441 }, { start: 441, end: 286 }, { start: 258, end: 257 }, { start: 257, end: 442 }, { start: 442, end: 258 }, { start: 257, end: 259 }, { start: 259, end: 443 }, { start: 443, end: 257 }, { start: 259, end: 260 }, { start: 260, end: 444 }, { start: 444, end: 259 }, { start: 260, end: 467 }, { start: 467, end: 445 }, { start: 445, end: 260 }, { start: 309, end: 459 }, { start: 459, end: 250 }, { start: 250, end: 309 }, { start: 305, end: 289 }, { start: 289, end: 290 }, { start: 290, end: 305 }, { start: 305, end: 290 }, { start: 290, end: 460 }, { start: 460, end: 305 }, { start: 401, end: 376 }, { start: 376, end: 435 }, { start: 435, end: 401 }, { start: 309, end: 250 }, { start: 250, end: 392 }, { start: 392, end: 309 }, { start: 376, end: 411 }, { start: 411, end: 433 }, { start: 433, end: 376 }, { start: 453, end: 341 }, { start: 341, end: 464 }, { start: 464, end: 453 }, { start: 357, end: 453 }, { start: 453, end: 465 }, { start: 465, end: 357 }, { start: 343, end: 357 }, { start: 357, end: 412 }, { start: 412, end: 343 }, { start: 437, end: 343 }, { start: 343, end: 399 }, { start: 399, end: 437 }, { start: 344, end: 360 }, { start: 360, end: 440 }, { start: 440, end: 344 }, { start: 420, end: 437 }, { start: 437, end: 456 }, { start: 456, end: 420 }, { start: 360, end: 420 }, { start: 420, end: 363 }, { start: 363, end: 360 }, { start: 361, end: 401 }, { start: 401, end: 288 }, { start: 288, end: 361 }, { start: 265, end: 372 }, { start: 372, end: 353 }, { start: 353, end: 265 }, { start: 390, end: 339 }, { start: 339, end: 249 }, { start: 249, end: 390 }, { start: 339, end: 448 }, { start: 448, end: 255 }, { start: 255, end: 339 }, ]); var face_landmarker_options = {}; Object.defineProperty(face_landmarker_options, '__esModule', { value: !0 }); var face_landmarker_result = {}; Object.defineProperty(face_landmarker_result, '__esModule', { value: !0 }), (function(e) { var t = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? function(e, t, r, o) { void 0 === o && (o = r); var i = Object.getOwnPropertyDescriptor(t, r); (i && !('get' in i ? !t.__esModule : i.writable || i.configurable)) || (i = { enumerable: !0, get: function() { return t[r]; }, }), Object.defineProperty(e, o, i); } : function(e, t, r, o) { void 0 === o && (o = r), (e[o] = t[r]); }), r = (commonjsGlobal && commonjsGlobal.__exportStar) || function(e, r) { for (var o in e) 'default' === o || Object.prototype.hasOwnProperty.call(r, o) || t(r, e, o); }; Object.defineProperty(e, '__esModule', { value: !0 }), (e.FaceLandmarker = void 0); const o = calculator_pb, i = calculator_options_pb, a = classification_pb, n = landmark_pb, s = base_options_pb, p = face_detector_graph_options_pb, d = face_geometry_pb, l = face_landmarker_graph_options_pb, g = face_landmarks_detector_graph_options_pb, c = classifier_result, u = landmark_result, m = vision_task_runner, f = face_landmarks_connections; r(face_landmarker_options, e), r(face_landmarker_result, e); const h = 'image_in', y = 'norm_rect', b = 'face_landmarks', _ = 'blendshapes', O = 'face_geometry', F = 0.5; class M extends m.VisionTaskRunner { static createFromOptions(e, t) { return m.VisionTaskRunner.createVisionInstance(M, e, t); } static createFromModelBuffer(e, t) { return m.VisionTaskRunner.createVisionInstance(M, e, { baseOptions: { modelAssetBuffer: t }, }); } static createFromModelPath(e, t) { return m.VisionTaskRunner.createVisionInstance(M, e, { baseOptions: { modelAssetPath: t }, }); } constructor(e, t) { super(new m.VisionGraphRunner(e, t), h, y, !1), (this.result = { faceLandmarks: [], faceBlendshapes: [], facialTransformationMatrixes: [], }), (this.outputFaceBlendshapes = !1), (this.outputFacialTransformationMatrixes = !1), (this.options = new l.FaceLandmarkerGraphOptions()), this.options.setBaseOptions(new s.BaseOptions()), (this.faceLandmarksDetectorGraphOptions = new g.FaceLandmarksDetectorGraphOptions()), this.options.setFaceLandmarksDetectorGraphOptions( this.faceLandmarksDetectorGraphOptions ), (this.faceDetectorGraphOptions = new p.FaceDetectorGraphOptions()), this.options.setFaceDetectorGraphOptions(this.faceDetectorGraphOptions), this.initDefaults(); } get baseOptions() { return this.options.getBaseOptions(); } set baseOptions(e) { this.options.setBaseOptions(e); } setOptions(e) { var t, r, o, i; return ( 'numFaces' in e && this.faceDetectorGraphOptions.setNumFaces( null !== (t = e.numFaces) && void 0 !== t ? t : 1 ), 'minFaceDetectionConfidence' in e && this.faceDetectorGraphOptions.setMinDetectionConfidence( null !== (r = e.minFaceDetectionConfidence) && void 0 !== r ? r : F ), 'minTrackingConfidence' in e && this.options.setMinTrackingConfidence( null !== (o = e.minTrackingConfidence) && void 0 !== o ? o : F ), 'minFacePresenceConfidence' in e && this.faceLandmarksDetectorGraphOptions.setMinDetectionConfidence( null !== (i = e.minFacePresenceConfidence) && void 0 !== i ? i : F ), 'outputFaceBlendshapes' in e && (this.outputFaceBlendshapes = !!e.outputFaceBlendshapes), 'outputFacialTransformationMatrixes' in e && (this.outputFacialTransformationMatrixes = !!e.outputFacialTransformationMatrixes), this.applyOptions(e) ); } detect(e, t) { return this.resetResults(), this.processImageData(e, t), this.result; } detectForVideo(e, t, r) { return this.resetResults(), this.processVideoData(e, r, t), this.result; } resetResults() { this.result = { faceLandmarks: [], faceBlendshapes: [], facialTransformationMatrixes: [], }; } initDefaults() { this.faceDetectorGraphOptions.setNumFaces(1), this.faceDetectorGraphOptions.setMinDetectionConfidence(F), this.faceLandmarksDetectorGraphOptions.setMinDetectionConfidence(F), this.options.setMinTrackingConfidence(F); } addJsLandmarks(e) { for (const t of e) { const e = n.NormalizedLandmarkList.deserializeBinary(t); this.result.faceLandmarks.push((0, u.convertToLandmarks)(e)); } } addBlenshape(e) { var t; if (this.outputFaceBlendshapes) for (const r of e) { const e = a.ClassificationList.deserializeBinary(r); this.result.faceBlendshapes.push( (0, c.convertFromClassifications)( null !== (t = e.getClassificationList()) && void 0 !== t ? t : [] ) ); } } addFacialTransformationMatrixes(e) { var t, r, o; if (this.outputFacialTransformationMatrixes) for (const i of e) { const e = d.FaceGeometry.deserializeBinary(i).getPoseTransformMatrix(); e && this.result.facialTransformationMatrixes.push({ rows: null !== (t = e.getRows()) && void 0 !== t ? t : 0, columns: null !== (r = e.getCols()) && void 0 !== r ? r : 0, data: null !== (o = e.getPackedDataList()) && void 0 !== o ? o : [], }); } } refreshGraph() { const e = new o.CalculatorGraphConfig(); e.addInputStream(h), e.addInputStream(y), e.addOutputStream(b); const t = new i.CalculatorOptions(); t.setExtension(l.FaceLandmarkerGraphOptions.ext, this.options); const r = new o.CalculatorGraphConfig.Node(); r.setCalculator('mediapipe.tasks.vision.face_landmarker.FaceLandmarkerGraph'), r.addInputStream('IMAGE:' + h), r.addInputStream('NORM_RECT:' + y), r.addOutputStream('NORM_LANDMARKS:' + b), r.setOptions(t), e.addNode(r), this.graphRunner.attachProtoVectorListener(b, (e, t) => { this.addJsLandmarks(e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(b, (e) => { this.setLatestOutputTimestamp(e); }), this.outputFaceBlendshapes && (e.addOutputStream(_), r.addOutputStream('BLENDSHAPES:' + _), this.graphRunner.attachProtoVectorListener(_, (e, t) => { this.addBlenshape(e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(_, (e) => { this.setLatestOutputTimestamp(e); })), this.outputFacialTransformationMatrixes && (e.addOutputStream(O), r.addOutputStream('FACE_GEOMETRY:' + O), this.graphRunner.attachProtoVectorListener(O, (e, t) => { this.addFacialTransformationMatrixes(e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(O, (e) => { this.setLatestOutputTimestamp(e); })); const a = e.serializeBinary(); this.setGraph(new Uint8Array(a), !0); } } (e.FaceLandmarker = M), (M.FACE_LANDMARKS_LIPS = f.FACE_LANDMARKS_LIPS), (M.FACE_LANDMARKS_LEFT_EYE = f.FACE_LANDMARKS_LEFT_EYE), (M.FACE_LANDMARKS_LEFT_EYEBROW = f.FACE_LANDMARKS_LEFT_EYEBROW), (M.FACE_LANDMARKS_LEFT_IRIS = f.FACE_LANDMARKS_LEFT_IRIS), (M.FACE_LANDMARKS_RIGHT_EYE = f.FACE_LANDMARKS_RIGHT_EYE), (M.FACE_LANDMARKS_RIGHT_EYEBROW = f.FACE_LANDMARKS_RIGHT_EYEBROW), (M.FACE_LANDMARKS_RIGHT_IRIS = f.FACE_LANDMARKS_RIGHT_IRIS), (M.FACE_LANDMARKS_FACE_OVAL = f.FACE_LANDMARKS_FACE_OVAL), (M.FACE_LANDMARKS_CONTOURS = f.FACE_LANDMARKS_CONTOURS), (M.FACE_LANDMARKS_TESSELATION = f.FACE_LANDMARKS_TESSELATION); })(face_landmarker); var face_stylizer = {}, face_stylizer_graph_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n); var s = face_landmarker_graph_options_pb; r.object.extend(proto, s), r.exportSymbol( 'proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions', null, o ), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.displayName = 'proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.toObject = function( e, r ) { var o, i = { baseOptions: (o = r.getBaseOptions()) && n.BaseOptions.toObject(e, o), faceLandmarkerGraphOptions: (o = r.getFaceLandmarkerGraphOptions()) && s.FaceLandmarkerGraphOptions.toObject(e, o), faceAlignmentSize: t.Message.getFieldWithDefault(r, 3, 256), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions(); return proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = new s.FaceLandmarkerGraphOptions(); t.readMessage(r, s.FaceLandmarkerGraphOptions.deserializeBinaryFromReader), e.setFaceLandmarkerGraphOptions(r); break; case 3: r = t.readInt32(); e.setFaceAlignmentSize(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getBaseOptions()) && r.writeMessage(1, o, n.BaseOptions.serializeBinaryToWriter), null != (o = e.getFaceLandmarkerGraphOptions()) && r.writeMessage(2, o, s.FaceLandmarkerGraphOptions.serializeBinaryToWriter), null != (o = t.Message.getField(e, 3)) && r.writeInt32(3, o); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.ext = new t.ExtensionFieldInfo( 513916220, { ext: 0 }, proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions, proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[513916220] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[513916220] = proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.ext), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.getFaceLandmarkerGraphOptions = function() { return t.Message.getWrapperField(this, s.FaceLandmarkerGraphOptions, 2); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.setFaceLandmarkerGraphOptions = function( e ) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.clearFaceLandmarkerGraphOptions = function() { return this.setFaceLandmarkerGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.hasFaceLandmarkerGraphOptions = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.getFaceAlignmentSize = function() { return t.Message.getFieldWithDefault(this, 3, 256); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.setFaceAlignmentSize = function( e ) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.clearFaceAlignmentSize = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.prototype.hasFaceAlignmentSize = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.ext = new t.ExtensionFieldInfo( 513916220, { ext: 0 }, proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions, proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[513916220] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[513916220] = proto.mediapipe.tasks.vision.face_stylizer.proto.FaceStylizerGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.face_stylizer.proto); })(face_stylizer_graph_options_pb); var face_stylizer_options = {}; Object.defineProperty(face_stylizer_options, '__esModule', { value: !0 }), (function(e) { var t = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? function(e, t, r, o) { void 0 === o && (o = r); var i = Object.getOwnPropertyDescriptor(t, r); (i && !('get' in i ? !t.__esModule : i.writable || i.configurable)) || (i = { enumerable: !0, get: function() { return t[r]; }, }), Object.defineProperty(e, o, i); } : function(e, t, r, o) { void 0 === o && (o = r), (e[o] = t[r]); }), r = (commonjsGlobal && commonjsGlobal.__exportStar) || function(e, r) { for (var o in e) 'default' === o || Object.prototype.hasOwnProperty.call(r, o) || t(r, e, o); }; Object.defineProperty(e, '__esModule', { value: !0 }), (e.FaceStylizer = void 0); const o = calculator_pb, i = calculator_options_pb, a = base_options_pb, n = face_stylizer_graph_options_pb, s = vision_task_runner; r(face_stylizer_options, e); const p = 'image_in', d = 'norm_rect', l = 'stylized_image'; class g extends s.VisionTaskRunner { static createFromOptions(e, t) { return s.VisionTaskRunner.createVisionInstance(g, e, t); } static createFromModelBuffer(e, t) { return s.VisionTaskRunner.createVisionInstance(g, e, { baseOptions: { modelAssetBuffer: t }, }); } static createFromModelPath(e, t) { return s.VisionTaskRunner.createVisionInstance(g, e, { baseOptions: { modelAssetPath: t }, }); } constructor(e, t) { super(new s.VisionGraphRunner(e, t), p, d, !0), (this.options = new n.FaceStylizerGraphOptions()), this.options.setBaseOptions(new a.BaseOptions()); } get baseOptions() { return this.options.getBaseOptions(); } set baseOptions(e) { this.options.setBaseOptions(e); } setOptions(e) { return super.applyOptions(e); } stylize(e, t, r) { const o = 'function' != typeof t ? t : {}; if ( ((this.userCallback = 'function' == typeof t ? t : r), this.processImageData(e, null != o ? o : {}), !this.userCallback) ) return this.result; } stylizeForVideo(e, t, r, o) { const i = 'function' != typeof r ? r : {}; if ( ((this.userCallback = 'function' == typeof r ? r : o), this.processVideoData(e, i, t), (this.userCallback = void 0), !this.userCallback) ) return this.result; } refreshGraph() { const e = new o.CalculatorGraphConfig(); e.addInputStream(p), e.addInputStream(d), e.addOutputStream(l); const t = new i.CalculatorOptions(); t.setExtension(n.FaceStylizerGraphOptions.ext, this.options); const r = new o.CalculatorGraphConfig.Node(); r.setCalculator('mediapipe.tasks.vision.face_stylizer.FaceStylizerGraph'), r.addInputStream('IMAGE:' + p), r.addInputStream('NORM_RECT:' + d), r.addOutputStream('STYLIZED_IMAGE:' + l), r.setOptions(t), e.addNode(r), this.graphRunner.attachImageListener(l, (e, t) => { const r = this.convertToMPImage(e, !this.userCallback); (this.result = r), this.userCallback && this.userCallback(r), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(l, (e) => { (this.result = null), this.userCallback && this.userCallback(null), this.setLatestOutputTimestamp(e); }); const a = e.serializeBinary(); this.setGraph(new Uint8Array(a), !0); } } e.FaceStylizer = g; })(face_stylizer); var gesture_recognizer = {}, gesture_classifier_graph_options_pb = {}, classifier_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.tasks.components.processors.proto.ClassifierOptions', null, o), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.repeatedFields_, null ); }), r.inherits(proto.mediapipe.tasks.components.processors.proto.ClassifierOptions, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.displayName = 'proto.mediapipe.tasks.components.processors.proto.ClassifierOptions'), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.repeatedFields_ = [ 4, 5, ]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.toObject( e, this ); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.toObject = function( e, r ) { var o, i = { displayNamesLocale: t.Message.getFieldWithDefault(r, 1, 'en'), maxResults: t.Message.getFieldWithDefault(r, 2, -1), scoreThreshold: null == (o = t.Message.getOptionalFloatingPointField(r, 3)) ? void 0 : o, categoryAllowlistList: null == (o = t.Message.getRepeatedField(r, 4)) ? void 0 : o, categoryDenylistList: null == (o = t.Message.getRepeatedField(r, 5)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.components.processors.proto.ClassifierOptions(); return proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setDisplayNamesLocale(r); break; case 2: r = t.readInt32(); e.setMaxResults(r); break; case 3: r = t.readFloat(); e.setScoreThreshold(r); break; case 4: r = t.readString(); e.addCategoryAllowlist(r); break; case 5: r = t.readString(); e.addCategoryDenylist(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeString(1, o), null != (o = t.Message.getField(e, 2)) && r.writeInt32(2, o), null != (o = t.Message.getField(e, 3)) && r.writeFloat(3, o), (o = e.getCategoryAllowlistList()).length > 0 && r.writeRepeatedString(4, o), (o = e.getCategoryDenylistList()).length > 0 && r.writeRepeatedString(5, o); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.getDisplayNamesLocale = function() { return t.Message.getFieldWithDefault(this, 1, 'en'); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.setDisplayNamesLocale = function( e ) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.clearDisplayNamesLocale = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.hasDisplayNamesLocale = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.getMaxResults = function() { return t.Message.getFieldWithDefault(this, 2, -1); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.setMaxResults = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.clearMaxResults = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.hasMaxResults = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.getScoreThreshold = function() { return t.Message.getFloatingPointFieldWithDefault(this, 3, 0); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.setScoreThreshold = function( e ) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.clearScoreThreshold = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.hasScoreThreshold = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.getCategoryAllowlistList = function() { return t.Message.getRepeatedField(this, 4); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.setCategoryAllowlistList = function( e ) { return t.Message.setField(this, 4, e || []); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.addCategoryAllowlist = function( e, r ) { return t.Message.addToRepeatedField(this, 4, e, r); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.clearCategoryAllowlistList = function() { return this.setCategoryAllowlistList([]); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.getCategoryDenylistList = function() { return t.Message.getRepeatedField(this, 5); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.setCategoryDenylistList = function( e ) { return t.Message.setField(this, 5, e || []); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.addCategoryDenylist = function( e, r ) { return t.Message.addToRepeatedField(this, 5, e, r); }), (proto.mediapipe.tasks.components.processors.proto.ClassifierOptions.prototype.clearCategoryDenylistList = function() { return this.setCategoryDenylistList([]); }), r.object.extend(e, proto.mediapipe.tasks.components.processors.proto); })(classifier_options_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = classifier_options_pb; r.object.extend(proto, n); var s = base_options_pb; r.object.extend(proto, s), r.exportSymbol( 'proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions', null, o ), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.displayName = 'proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.toObject = function( e, t ) { var r, o = { baseOptions: (r = t.getBaseOptions()) && s.BaseOptions.toObject(e, r), classifierOptions: (r = t.getClassifierOptions()) && n.ClassifierOptions.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions(); return proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new s.BaseOptions(); t.readMessage(r, s.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = new n.ClassifierOptions(); t.readMessage(r, n.ClassifierOptions.deserializeBinaryFromReader), e.setClassifierOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.serializeBinaryToWriter = function( e, t ) { var r = void 0; null != (r = e.getBaseOptions()) && t.writeMessage(1, r, s.BaseOptions.serializeBinaryToWriter), null != (r = e.getClassifierOptions()) && t.writeMessage(2, r, n.ClassifierOptions.serializeBinaryToWriter); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.ext = new t.ExtensionFieldInfo( 478825465, { ext: 0 }, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[478825465] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[478825465] = proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.ext), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, s.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.prototype.getClassifierOptions = function() { return t.Message.getWrapperField(this, n.ClassifierOptions, 2); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.prototype.setClassifierOptions = function( e ) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.prototype.clearClassifierOptions = function() { return this.setClassifierOptions(void 0); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.prototype.hasClassifierOptions = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.ext = new t.ExtensionFieldInfo( 478825465, { ext: 0 }, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[478825465] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[478825465] = proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureClassifierGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.gesture_recognizer.proto); })(gesture_classifier_graph_options_pb); var gesture_recognizer_graph_options_pb = {}, hand_gesture_recognizer_graph_options_pb = {}, gesture_embedder_graph_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n), r.exportSymbol( 'proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions', null, o ), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.displayName = 'proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.toObject = function( e, t ) { var r, o = { baseOptions: (r = t.getBaseOptions()) && n.BaseOptions.toObject(e, r) }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions(); return proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); } else t.skipField(); } return e; }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.serializeBinaryToWriter = function( e, t ) { var r; null != (r = e.getBaseOptions()) && t.writeMessage(1, r, n.BaseOptions.serializeBinaryToWriter); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.ext = new t.ExtensionFieldInfo( 478825422, { ext: 0 }, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[478825422] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[478825422] = proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.ext), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.ext = new t.ExtensionFieldInfo( 478825422, { ext: 0 }, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[478825422] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[478825422] = proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureEmbedderGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.gesture_recognizer.proto); })(gesture_embedder_graph_options_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n); var s = gesture_classifier_graph_options_pb; r.object.extend(proto, s); var p = gesture_embedder_graph_options_pb; r.object.extend(proto, p), r.exportSymbol( 'proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions', null, o ), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.gesture_recognizer.proto .HandGestureRecognizerGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.displayName = 'proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.toObject = function( e, t ) { var r, o = { baseOptions: (r = t.getBaseOptions()) && n.BaseOptions.toObject(e, r), gestureEmbedderGraphOptions: (r = t.getGestureEmbedderGraphOptions()) && p.GestureEmbedderGraphOptions.toObject(e, r), cannedGestureClassifierGraphOptions: (r = t.getCannedGestureClassifierGraphOptions()) && s.GestureClassifierGraphOptions.toObject(e, r), customGestureClassifierGraphOptions: (r = t.getCustomGestureClassifierGraphOptions()) && s.GestureClassifierGraphOptions.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions(); return proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = new p.GestureEmbedderGraphOptions(); t.readMessage( r, p.GestureEmbedderGraphOptions.deserializeBinaryFromReader ), e.setGestureEmbedderGraphOptions(r); break; case 3: r = new s.GestureClassifierGraphOptions(); t.readMessage( r, s.GestureClassifierGraphOptions.deserializeBinaryFromReader ), e.setCannedGestureClassifierGraphOptions(r); break; case 4: r = new s.GestureClassifierGraphOptions(); t.readMessage( r, s.GestureClassifierGraphOptions.deserializeBinaryFromReader ), e.setCustomGestureClassifierGraphOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.serializeBinaryToWriter = function( e, t ) { var r = void 0; null != (r = e.getBaseOptions()) && t.writeMessage(1, r, n.BaseOptions.serializeBinaryToWriter), null != (r = e.getGestureEmbedderGraphOptions()) && t.writeMessage(2, r, p.GestureEmbedderGraphOptions.serializeBinaryToWriter), null != (r = e.getCannedGestureClassifierGraphOptions()) && t.writeMessage( 3, r, s.GestureClassifierGraphOptions.serializeBinaryToWriter ), null != (r = e.getCustomGestureClassifierGraphOptions()) && t.writeMessage( 4, r, s.GestureClassifierGraphOptions.serializeBinaryToWriter ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.ext = new t.ExtensionFieldInfo( 463370452, { ext: 0 }, proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions, proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[463370452] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[463370452] = proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.ext), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.getGestureEmbedderGraphOptions = function() { return t.Message.getWrapperField(this, p.GestureEmbedderGraphOptions, 2); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.setGestureEmbedderGraphOptions = function( e ) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.clearGestureEmbedderGraphOptions = function() { return this.setGestureEmbedderGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.hasGestureEmbedderGraphOptions = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.getCannedGestureClassifierGraphOptions = function() { return t.Message.getWrapperField(this, s.GestureClassifierGraphOptions, 3); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.setCannedGestureClassifierGraphOptions = function( e ) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.clearCannedGestureClassifierGraphOptions = function() { return this.setCannedGestureClassifierGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.hasCannedGestureClassifierGraphOptions = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.getCustomGestureClassifierGraphOptions = function() { return t.Message.getWrapperField(this, s.GestureClassifierGraphOptions, 4); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.setCustomGestureClassifierGraphOptions = function( e ) { return t.Message.setWrapperField(this, 4, e); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.clearCustomGestureClassifierGraphOptions = function() { return this.setCustomGestureClassifierGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.prototype.hasCustomGestureClassifierGraphOptions = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.ext = new t.ExtensionFieldInfo( 463370452, { ext: 0 }, proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions, proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[463370452] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[463370452] = proto.mediapipe.tasks.vision.gesture_recognizer.proto.HandGestureRecognizerGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.gesture_recognizer.proto); })(hand_gesture_recognizer_graph_options_pb); var hand_landmarker_graph_options_pb = {}, hand_detector_graph_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n), r.exportSymbol( 'proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions', null, o ), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.displayName = 'proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.toObject = function( e, r ) { var o, i = { baseOptions: (o = r.getBaseOptions()) && n.BaseOptions.toObject(e, o), minDetectionConfidence: t.Message.getFloatingPointFieldWithDefault( r, 2, 0.5 ), numHands: null == (o = t.Message.getField(r, 3)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions(); return proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = t.readFloat(); e.setMinDetectionConfidence(r); break; case 3: r = t.readInt32(); e.setNumHands(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getBaseOptions()) && r.writeMessage(1, o, n.BaseOptions.serializeBinaryToWriter), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o), null != (o = t.Message.getField(e, 3)) && r.writeInt32(3, o); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.ext = new t.ExtensionFieldInfo( 464864288, { ext: 0 }, proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions, proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[464864288] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[464864288] = proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.ext), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.getMinDetectionConfidence = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0.5); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.setMinDetectionConfidence = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.clearMinDetectionConfidence = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.hasMinDetectionConfidence = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.getNumHands = function() { return t.Message.getFieldWithDefault(this, 3, 0); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.setNumHands = function( e ) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.clearNumHands = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.prototype.hasNumHands = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.ext = new t.ExtensionFieldInfo( 464864288, { ext: 0 }, proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions, proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[464864288] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[464864288] = proto.mediapipe.tasks.vision.hand_detector.proto.HandDetectorGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.hand_detector.proto); })(hand_detector_graph_options_pb); var hand_landmarks_detector_graph_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n), r.exportSymbol( 'proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions', null, o ), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.displayName = 'proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.toObject = function( e, r ) { var o, i = { baseOptions: (o = r.getBaseOptions()) && n.BaseOptions.toObject(e, o), minDetectionConfidence: t.Message.getFloatingPointFieldWithDefault( r, 2, 0.5 ), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions(); return proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = t.readFloat(); e.setMinDetectionConfidence(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getBaseOptions()) && r.writeMessage(1, o, n.BaseOptions.serializeBinaryToWriter), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.ext = new t.ExtensionFieldInfo( 474472470, { ext: 0 }, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[474472470] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[474472470] = proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.ext), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.prototype.getMinDetectionConfidence = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0.5); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.prototype.setMinDetectionConfidence = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.prototype.clearMinDetectionConfidence = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.prototype.hasMinDetectionConfidence = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.ext = new t.ExtensionFieldInfo( 474472470, { ext: 0 }, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[474472470] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[474472470] = proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarksDetectorGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.hand_landmarker.proto); })(hand_landmarks_detector_graph_options_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n); var s = hand_detector_graph_options_pb; r.object.extend(proto, s); var p = hand_landmarks_detector_graph_options_pb; r.object.extend(proto, p), r.exportSymbol( 'proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions', null, o ), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.displayName = 'proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.toObject = function( e, r ) { var o, i = { baseOptions: (o = r.getBaseOptions()) && n.BaseOptions.toObject(e, o), handDetectorGraphOptions: (o = r.getHandDetectorGraphOptions()) && s.HandDetectorGraphOptions.toObject(e, o), handLandmarksDetectorGraphOptions: (o = r.getHandLandmarksDetectorGraphOptions()) && p.HandLandmarksDetectorGraphOptions.toObject(e, o), minTrackingConfidence: t.Message.getFloatingPointFieldWithDefault( r, 4, 0.5 ), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions(); return proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = new s.HandDetectorGraphOptions(); t.readMessage( r, s.HandDetectorGraphOptions.deserializeBinaryFromReader ), e.setHandDetectorGraphOptions(r); break; case 3: r = new p.HandLandmarksDetectorGraphOptions(); t.readMessage( r, p.HandLandmarksDetectorGraphOptions.deserializeBinaryFromReader ), e.setHandLandmarksDetectorGraphOptions(r); break; case 4: r = t.readFloat(); e.setMinTrackingConfidence(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getBaseOptions()) && r.writeMessage(1, o, n.BaseOptions.serializeBinaryToWriter), null != (o = e.getHandDetectorGraphOptions()) && r.writeMessage(2, o, s.HandDetectorGraphOptions.serializeBinaryToWriter), null != (o = e.getHandLandmarksDetectorGraphOptions()) && r.writeMessage( 3, o, p.HandLandmarksDetectorGraphOptions.serializeBinaryToWriter ), null != (o = t.Message.getField(e, 4)) && r.writeFloat(4, o); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.ext = new t.ExtensionFieldInfo( 462713202, { ext: 0 }, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[462713202] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[462713202] = proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.ext), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.getHandDetectorGraphOptions = function() { return t.Message.getWrapperField(this, s.HandDetectorGraphOptions, 2); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.setHandDetectorGraphOptions = function( e ) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.clearHandDetectorGraphOptions = function() { return this.setHandDetectorGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.hasHandDetectorGraphOptions = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.getHandLandmarksDetectorGraphOptions = function() { return t.Message.getWrapperField(this, p.HandLandmarksDetectorGraphOptions, 3); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.setHandLandmarksDetectorGraphOptions = function( e ) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.clearHandLandmarksDetectorGraphOptions = function() { return this.setHandLandmarksDetectorGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.hasHandLandmarksDetectorGraphOptions = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.getMinTrackingConfidence = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0.5); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.setMinTrackingConfidence = function( e ) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.clearMinTrackingConfidence = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.prototype.hasMinTrackingConfidence = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.ext = new t.ExtensionFieldInfo( 462713202, { ext: 0 }, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[462713202] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[462713202] = proto.mediapipe.tasks.vision.hand_landmarker.proto.HandLandmarkerGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.hand_landmarker.proto); })(hand_landmarker_graph_options_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n); var s = hand_gesture_recognizer_graph_options_pb; r.object.extend(proto, s); var p = hand_landmarker_graph_options_pb; r.object.extend(proto, p), r.exportSymbol( 'proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions', null, o ), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.displayName = 'proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.toObject = function( e, t ) { var r, o = { baseOptions: (r = t.getBaseOptions()) && n.BaseOptions.toObject(e, r), handLandmarkerGraphOptions: (r = t.getHandLandmarkerGraphOptions()) && p.HandLandmarkerGraphOptions.toObject(e, r), handGestureRecognizerGraphOptions: (r = t.getHandGestureRecognizerGraphOptions()) && s.HandGestureRecognizerGraphOptions.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions(); return proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = new p.HandLandmarkerGraphOptions(); t.readMessage( r, p.HandLandmarkerGraphOptions.deserializeBinaryFromReader ), e.setHandLandmarkerGraphOptions(r); break; case 3: r = new s.HandGestureRecognizerGraphOptions(); t.readMessage( r, s.HandGestureRecognizerGraphOptions.deserializeBinaryFromReader ), e.setHandGestureRecognizerGraphOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.serializeBinaryToWriter = function( e, t ) { var r = void 0; null != (r = e.getBaseOptions()) && t.writeMessage(1, r, n.BaseOptions.serializeBinaryToWriter), null != (r = e.getHandLandmarkerGraphOptions()) && t.writeMessage(2, r, p.HandLandmarkerGraphOptions.serializeBinaryToWriter), null != (r = e.getHandGestureRecognizerGraphOptions()) && t.writeMessage( 3, r, s.HandGestureRecognizerGraphOptions.serializeBinaryToWriter ); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.ext = new t.ExtensionFieldInfo( 479097054, { ext: 0 }, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[479097054] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[479097054] = proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.ext), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.getHandLandmarkerGraphOptions = function() { return t.Message.getWrapperField(this, p.HandLandmarkerGraphOptions, 2); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.setHandLandmarkerGraphOptions = function( e ) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.clearHandLandmarkerGraphOptions = function() { return this.setHandLandmarkerGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.hasHandLandmarkerGraphOptions = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.getHandGestureRecognizerGraphOptions = function() { return t.Message.getWrapperField(this, s.HandGestureRecognizerGraphOptions, 3); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.setHandGestureRecognizerGraphOptions = function( e ) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.clearHandGestureRecognizerGraphOptions = function() { return this.setHandGestureRecognizerGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.prototype.hasHandGestureRecognizerGraphOptions = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.ext = new t.ExtensionFieldInfo( 479097054, { ext: 0 }, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[479097054] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[479097054] = proto.mediapipe.tasks.vision.gesture_recognizer.proto.GestureRecognizerGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.gesture_recognizer.proto); })(gesture_recognizer_graph_options_pb); var classifier_options = {}; Object.defineProperty(classifier_options, '__esModule', { value: !0 }), (classifier_options.convertClassifierOptionsToProto = void 0); const classifier_options_pb_1 = classifier_options_pb; function convertClassifierOptionsToProto(e, t) { const r = t ? t.clone() : new classifier_options_pb_1.ClassifierOptions(); return ( void 0 !== e.displayNamesLocale ? r.setDisplayNamesLocale(e.displayNamesLocale) : void 0 === e.displayNamesLocale && r.clearDisplayNamesLocale(), void 0 !== e.maxResults ? r.setMaxResults(e.maxResults) : 'maxResults' in e && r.clearMaxResults(), void 0 !== e.scoreThreshold ? r.setScoreThreshold(e.scoreThreshold) : 'scoreThreshold' in e && r.clearScoreThreshold(), void 0 !== e.categoryAllowlist ? r.setCategoryAllowlistList(e.categoryAllowlist) : 'categoryAllowlist' in e && r.clearCategoryAllowlistList(), void 0 !== e.categoryDenylist ? r.setCategoryDenylistList(e.categoryDenylist) : 'categoryDenylist' in e && r.clearCategoryDenylistList(), r ); } classifier_options.convertClassifierOptionsToProto = convertClassifierOptionsToProto; var hand_landmarks_connections = {}; Object.defineProperty(hand_landmarks_connections, '__esModule', { value: !0 }), (hand_landmarks_connections.HAND_CONNECTIONS = void 0), (hand_landmarks_connections.HAND_CONNECTIONS = [ { start: 0, end: 1 }, { start: 1, end: 2 }, { start: 2, end: 3 }, { start: 3, end: 4 }, { start: 0, end: 5 }, { start: 5, end: 6 }, { start: 6, end: 7 }, { start: 7, end: 8 }, { start: 5, end: 9 }, { start: 9, end: 10 }, { start: 10, end: 11 }, { start: 11, end: 12 }, { start: 9, end: 13 }, { start: 13, end: 14 }, { start: 14, end: 15 }, { start: 15, end: 16 }, { start: 13, end: 17 }, { start: 0, end: 17 }, { start: 17, end: 18 }, { start: 18, end: 19 }, { start: 19, end: 20 }, ]); var gesture_recognizer_options = {}; Object.defineProperty(gesture_recognizer_options, '__esModule', { value: !0 }); var gesture_recognizer_result = {}; Object.defineProperty(gesture_recognizer_result, '__esModule', { value: !0 }), (function(e) { var t = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? function(e, t, r, o) { void 0 === o && (o = r); var i = Object.getOwnPropertyDescriptor(t, r); (i && !('get' in i ? !t.__esModule : i.writable || i.configurable)) || (i = { enumerable: !0, get: function() { return t[r]; }, }), Object.defineProperty(e, o, i); } : function(e, t, r, o) { void 0 === o && (o = r), (e[o] = t[r]); }), r = (commonjsGlobal && commonjsGlobal.__exportStar) || function(e, r) { for (var o in e) 'default' === o || Object.prototype.hasOwnProperty.call(r, o) || t(r, e, o); }; Object.defineProperty(e, '__esModule', { value: !0 }), (e.GestureRecognizer = void 0); const o = calculator_pb, i = calculator_options_pb, a = classification_pb, n = landmark_pb, s = base_options_pb, p = gesture_classifier_graph_options_pb, d = gesture_recognizer_graph_options_pb, l = hand_gesture_recognizer_graph_options_pb, g = hand_detector_graph_options_pb, c = hand_landmarker_graph_options_pb, u = hand_landmarks_detector_graph_options_pb, m = classifier_options, f = vision_task_runner, h = hand_landmarks_connections; r(gesture_recognizer_options, e), r(gesture_recognizer_result, e); const y = 'image_in', b = 'norm_rect', _ = 'hand_gestures', O = 'hand_landmarks', F = 'world_hand_landmarks', M = 'handedness', R = 0.5; class v extends f.VisionTaskRunner { static createFromOptions(e, t) { return f.VisionTaskRunner.createVisionInstance(v, e, t); } static createFromModelBuffer(e, t) { return f.VisionTaskRunner.createVisionInstance(v, e, { baseOptions: { modelAssetBuffer: t }, }); } static createFromModelPath(e, t) { return f.VisionTaskRunner.createVisionInstance(v, e, { baseOptions: { modelAssetPath: t }, }); } constructor(e, t) { super(new f.VisionGraphRunner(e, t), y, b, !1), (this.gestures = []), (this.landmarks = []), (this.worldLandmarks = []), (this.handednesses = []), (this.options = new d.GestureRecognizerGraphOptions()), this.options.setBaseOptions(new s.BaseOptions()), (this.handLandmarkerGraphOptions = new c.HandLandmarkerGraphOptions()), this.options.setHandLandmarkerGraphOptions(this.handLandmarkerGraphOptions), (this.handLandmarksDetectorGraphOptions = new u.HandLandmarksDetectorGraphOptions()), this.handLandmarkerGraphOptions.setHandLandmarksDetectorGraphOptions( this.handLandmarksDetectorGraphOptions ), (this.handDetectorGraphOptions = new g.HandDetectorGraphOptions()), this.handLandmarkerGraphOptions.setHandDetectorGraphOptions( this.handDetectorGraphOptions ), (this.handGestureRecognizerGraphOptions = new l.HandGestureRecognizerGraphOptions()), this.options.setHandGestureRecognizerGraphOptions( this.handGestureRecognizerGraphOptions ), this.handDetectorGraphOptions.setMinDetectionConfidence(R), this.handLandmarkerGraphOptions.setMinTrackingConfidence(R), this.handLandmarksDetectorGraphOptions.setMinDetectionConfidence(R); } get baseOptions() { return this.options.getBaseOptions(); } set baseOptions(e) { this.options.setBaseOptions(e); } setOptions(e) { var t, r, o, i, a, n, s, d; if ( (this.handDetectorGraphOptions.setNumHands( null !== (t = e.numHands) && void 0 !== t ? t : 1 ), 'minHandDetectionConfidence' in e && this.handDetectorGraphOptions.setMinDetectionConfidence( null !== (r = e.minHandDetectionConfidence) && void 0 !== r ? r : R ), 'minTrackingConfidence' in e && this.handLandmarkerGraphOptions.setMinTrackingConfidence( null !== (o = e.minTrackingConfidence) && void 0 !== o ? o : R ), 'minHandPresenceConfidence' in e && this.handLandmarksDetectorGraphOptions.setMinDetectionConfidence( null !== (i = e.minHandPresenceConfidence) && void 0 !== i ? i : R ), e.cannedGesturesClassifierOptions) ) { const t = new p.GestureClassifierGraphOptions(); t.setClassifierOptions( (0, m.convertClassifierOptionsToProto)( e.cannedGesturesClassifierOptions, null === (a = this.handGestureRecognizerGraphOptions.getCannedGestureClassifierGraphOptions()) || void 0 === a ? void 0 : a.getClassifierOptions() ) ), this.handGestureRecognizerGraphOptions.setCannedGestureClassifierGraphOptions( t ); } else void 0 === e.cannedGesturesClassifierOptions && (null === (n = this.handGestureRecognizerGraphOptions.getCannedGestureClassifierGraphOptions()) || void 0 === n || n.clearClassifierOptions()); if (e.customGesturesClassifierOptions) { const t = new p.GestureClassifierGraphOptions(); t.setClassifierOptions( (0, m.convertClassifierOptionsToProto)( e.customGesturesClassifierOptions, null === (s = this.handGestureRecognizerGraphOptions.getCustomGestureClassifierGraphOptions()) || void 0 === s ? void 0 : s.getClassifierOptions() ) ), this.handGestureRecognizerGraphOptions.setCustomGestureClassifierGraphOptions( t ); } else void 0 === e.customGesturesClassifierOptions && (null === (d = this.handGestureRecognizerGraphOptions.getCustomGestureClassifierGraphOptions()) || void 0 === d || d.clearClassifierOptions()); return this.applyOptions(e); } recognize(e, t) { return this.resetResults(), this.processImageData(e, t), this.processResults(); } recognizeForVideo(e, t, r) { return this.resetResults(), this.processVideoData(e, r, t), this.processResults(); } resetResults() { (this.gestures = []), (this.landmarks = []), (this.worldLandmarks = []), (this.handednesses = []); } processResults() { return 0 === this.gestures.length ? { gestures: [], landmarks: [], worldLandmarks: [], handednesses: [] } : { gestures: this.gestures, landmarks: this.landmarks, worldLandmarks: this.worldLandmarks, handednesses: this.handednesses, }; } toJsCategories(e, t = !0) { var r, o, i; const n = []; for (const s of e) { const e = a.ClassificationList.deserializeBinary(s), p = []; for (const a of e.getClassificationList()) { const e = t && a.hasIndex() ? a.getIndex() : -1; p.push({ score: null !== (r = a.getScore()) && void 0 !== r ? r : 0, index: e, categoryName: null !== (o = a.getLabel()) && void 0 !== o ? o : '', displayName: null !== (i = a.getDisplayName()) && void 0 !== i ? i : '', }); } n.push(p); } return n; } addJsLandmarks(e) { var t, r, o; for (const i of e) { const e = n.NormalizedLandmarkList.deserializeBinary(i), a = []; for (const i of e.getLandmarkList()) a.push({ x: null !== (t = i.getX()) && void 0 !== t ? t : 0, y: null !== (r = i.getY()) && void 0 !== r ? r : 0, z: null !== (o = i.getZ()) && void 0 !== o ? o : 0, }); this.landmarks.push(a); } } adddJsWorldLandmarks(e) { var t, r, o; for (const i of e) { const e = n.LandmarkList.deserializeBinary(i), a = []; for (const i of e.getLandmarkList()) a.push({ x: null !== (t = i.getX()) && void 0 !== t ? t : 0, y: null !== (r = i.getY()) && void 0 !== r ? r : 0, z: null !== (o = i.getZ()) && void 0 !== o ? o : 0, }); this.worldLandmarks.push(a); } } refreshGraph() { const e = new o.CalculatorGraphConfig(); e.addInputStream(y), e.addInputStream(b), e.addOutputStream(_), e.addOutputStream(O), e.addOutputStream(F), e.addOutputStream(M); const t = new i.CalculatorOptions(); t.setExtension(d.GestureRecognizerGraphOptions.ext, this.options); const r = new o.CalculatorGraphConfig.Node(); r.setCalculator('mediapipe.tasks.vision.gesture_recognizer.GestureRecognizerGraph'), r.addInputStream('IMAGE:' + y), r.addInputStream('NORM_RECT:' + b), r.addOutputStream('HAND_GESTURES:' + _), r.addOutputStream('LANDMARKS:' + O), r.addOutputStream('WORLD_LANDMARKS:' + F), r.addOutputStream('HANDEDNESS:' + M), r.setOptions(t), e.addNode(r), this.graphRunner.attachProtoVectorListener(O, (e, t) => { this.addJsLandmarks(e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(O, (e) => { this.setLatestOutputTimestamp(e); }), this.graphRunner.attachProtoVectorListener(F, (e, t) => { this.adddJsWorldLandmarks(e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(F, (e) => { this.setLatestOutputTimestamp(e); }), this.graphRunner.attachProtoVectorListener(_, (e, t) => { this.gestures.push(...this.toJsCategories(e, !1)), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(_, (e) => { this.setLatestOutputTimestamp(e); }), this.graphRunner.attachProtoVectorListener(M, (e, t) => { this.handednesses.push(...this.toJsCategories(e)), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(M, (e) => { this.setLatestOutputTimestamp(e); }); const a = e.serializeBinary(); this.setGraph(new Uint8Array(a), !0); } } (e.GestureRecognizer = v), (v.HAND_CONNECTIONS = h.HAND_CONNECTIONS); })(gesture_recognizer); var hand_landmarker = {}, hand_landmarker_options = {}; Object.defineProperty(hand_landmarker_options, '__esModule', { value: !0 }); var hand_landmarker_result = {}; Object.defineProperty(hand_landmarker_result, '__esModule', { value: !0 }), (function(e) { var t = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? function(e, t, r, o) { void 0 === o && (o = r); var i = Object.getOwnPropertyDescriptor(t, r); (i && !('get' in i ? !t.__esModule : i.writable || i.configurable)) || (i = { enumerable: !0, get: function() { return t[r]; }, }), Object.defineProperty(e, o, i); } : function(e, t, r, o) { void 0 === o && (o = r), (e[o] = t[r]); }), r = (commonjsGlobal && commonjsGlobal.__exportStar) || function(e, r) { for (var o in e) 'default' === o || Object.prototype.hasOwnProperty.call(r, o) || t(r, e, o); }; Object.defineProperty(e, '__esModule', { value: !0 }), (e.HandLandmarker = void 0); const o = calculator_pb, i = calculator_options_pb, a = classification_pb, n = landmark_pb, s = base_options_pb, p = hand_detector_graph_options_pb, d = hand_landmarker_graph_options_pb, l = hand_landmarks_detector_graph_options_pb, g = landmark_result, c = vision_task_runner, u = hand_landmarks_connections; r(hand_landmarker_options, e), r(hand_landmarker_result, e); const m = 'image_in', f = 'norm_rect', h = 'hand_landmarks', y = 'world_hand_landmarks', b = 'handedness', _ = 0.5; class O extends c.VisionTaskRunner { static createFromOptions(e, t) { return c.VisionTaskRunner.createVisionInstance(O, e, t); } static createFromModelBuffer(e, t) { return c.VisionTaskRunner.createVisionInstance(O, e, { baseOptions: { modelAssetBuffer: t }, }); } static createFromModelPath(e, t) { return c.VisionTaskRunner.createVisionInstance(O, e, { baseOptions: { modelAssetPath: t }, }); } constructor(e, t) { super(new c.VisionGraphRunner(e, t), m, f, !1), (this.landmarks = []), (this.worldLandmarks = []), (this.handednesses = []), (this.options = new d.HandLandmarkerGraphOptions()), this.options.setBaseOptions(new s.BaseOptions()), (this.handLandmarksDetectorGraphOptions = new l.HandLandmarksDetectorGraphOptions()), this.options.setHandLandmarksDetectorGraphOptions( this.handLandmarksDetectorGraphOptions ), (this.handDetectorGraphOptions = new p.HandDetectorGraphOptions()), this.options.setHandDetectorGraphOptions(this.handDetectorGraphOptions), this.initDefaults(); } get baseOptions() { return this.options.getBaseOptions(); } set baseOptions(e) { this.options.setBaseOptions(e); } setOptions(e) { var t, r, o, i; return ( 'numHands' in e && this.handDetectorGraphOptions.setNumHands( null !== (t = e.numHands) && void 0 !== t ? t : 1 ), 'minHandDetectionConfidence' in e && this.handDetectorGraphOptions.setMinDetectionConfidence( null !== (r = e.minHandDetectionConfidence) && void 0 !== r ? r : _ ), 'minTrackingConfidence' in e && this.options.setMinTrackingConfidence( null !== (o = e.minTrackingConfidence) && void 0 !== o ? o : _ ), 'minHandPresenceConfidence' in e && this.handLandmarksDetectorGraphOptions.setMinDetectionConfidence( null !== (i = e.minHandPresenceConfidence) && void 0 !== i ? i : _ ), this.applyOptions(e) ); } detect(e, t) { return this.resetResults(), this.processImageData(e, t), this.processResults(); } detectForVideo(e, t, r) { return this.resetResults(), this.processVideoData(e, r, t), this.processResults(); } resetResults() { (this.landmarks = []), (this.worldLandmarks = []), (this.handednesses = []); } processResults() { return { landmarks: this.landmarks, worldLandmarks: this.worldLandmarks, handednesses: this.handednesses, }; } initDefaults() { this.handDetectorGraphOptions.setNumHands(1), this.handDetectorGraphOptions.setMinDetectionConfidence(_), this.handLandmarksDetectorGraphOptions.setMinDetectionConfidence(_), this.options.setMinTrackingConfidence(_); } toJsCategories(e) { var t, r, o, i; const n = []; for (const s of e) { const e = a.ClassificationList.deserializeBinary(s), p = []; for (const a of e.getClassificationList()) p.push({ score: null !== (t = a.getScore()) && void 0 !== t ? t : 0, index: null !== (r = a.getIndex()) && void 0 !== r ? r : -1, categoryName: null !== (o = a.getLabel()) && void 0 !== o ? o : '', displayName: null !== (i = a.getDisplayName()) && void 0 !== i ? i : '', }); n.push(p); } return n; } addJsLandmarks(e) { for (const t of e) { const e = n.NormalizedLandmarkList.deserializeBinary(t); this.landmarks.push((0, g.convertToLandmarks)(e)); } } adddJsWorldLandmarks(e) { for (const t of e) { const e = n.LandmarkList.deserializeBinary(t); this.worldLandmarks.push((0, g.convertToWorldLandmarks)(e)); } } refreshGraph() { const e = new o.CalculatorGraphConfig(); e.addInputStream(m), e.addInputStream(f), e.addOutputStream(h), e.addOutputStream(y), e.addOutputStream(b); const t = new i.CalculatorOptions(); t.setExtension(d.HandLandmarkerGraphOptions.ext, this.options); const r = new o.CalculatorGraphConfig.Node(); r.setCalculator('mediapipe.tasks.vision.hand_landmarker.HandLandmarkerGraph'), r.addInputStream('IMAGE:' + m), r.addInputStream('NORM_RECT:' + f), r.addOutputStream('LANDMARKS:' + h), r.addOutputStream('WORLD_LANDMARKS:' + y), r.addOutputStream('HANDEDNESS:' + b), r.setOptions(t), e.addNode(r), this.graphRunner.attachProtoVectorListener(h, (e, t) => { this.addJsLandmarks(e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(h, (e) => { this.setLatestOutputTimestamp(e); }), this.graphRunner.attachProtoVectorListener(y, (e, t) => { this.adddJsWorldLandmarks(e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(y, (e) => { this.setLatestOutputTimestamp(e); }), this.graphRunner.attachProtoVectorListener(b, (e, t) => { this.handednesses.push(...this.toJsCategories(e)), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(b, (e) => { this.setLatestOutputTimestamp(e); }); const a = e.serializeBinary(); this.setGraph(new Uint8Array(a), !0); } } (e.HandLandmarker = O), (O.HAND_CONNECTIONS = u.HAND_CONNECTIONS); })(hand_landmarker); var image_classifier = {}, classifications_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = classification_pb; r.object.extend(proto, i), r.exportSymbol( 'proto.mediapipe.tasks.components.containers.proto.ClassificationResult', null, o ), r.exportSymbol( 'proto.mediapipe.tasks.components.containers.proto.Classifications', null, o ), (proto.mediapipe.tasks.components.containers.proto.Classifications = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.tasks.components.containers.proto.Classifications, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.components.containers.proto.Classifications.displayName = 'proto.mediapipe.tasks.components.containers.proto.Classifications'), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.tasks.components.containers.proto.ClassificationResult .repeatedFields_, null ); }), r.inherits( proto.mediapipe.tasks.components.containers.proto.ClassificationResult, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.displayName = 'proto.mediapipe.tasks.components.containers.proto.ClassificationResult'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.toObject = function( e ) { return proto.mediapipe.tasks.components.containers.proto.Classifications.toObject( e, this ); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.toObject = function( e, r ) { var o, a = { classificationList: (o = r.getClassificationList()) && i.ClassificationList.toObject(e, o), headIndex: null == (o = t.Message.getField(r, 2)) ? void 0 : o, headName: null == (o = t.Message.getField(r, 3)) ? void 0 : o, }; return e && (a.$jspbMessageInstance = r), a; })), (proto.mediapipe.tasks.components.containers.proto.Classifications.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.components.containers.proto.Classifications(); return proto.mediapipe.tasks.components.containers.proto.Classifications.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 4: var r = new i.ClassificationList(); t.readMessage(r, i.ClassificationList.deserializeBinaryFromReader), e.setClassificationList(r); break; case 2: r = t.readInt32(); e.setHeadIndex(r); break; case 3: r = t.readString(); e.setHeadName(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.components.containers.proto.Classifications.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getClassificationList()) && r.writeMessage(4, o, i.ClassificationList.serializeBinaryToWriter), null != (o = t.Message.getField(e, 2)) && r.writeInt32(2, o), null != (o = t.Message.getField(e, 3)) && r.writeString(3, o); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.getClassificationList = function() { return t.Message.getWrapperField(this, i.ClassificationList, 4); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.setClassificationList = function( e ) { return t.Message.setWrapperField(this, 4, e); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.clearClassificationList = function() { return this.setClassificationList(void 0); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.hasClassificationList = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.getHeadIndex = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.setHeadIndex = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.clearHeadIndex = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.hasHeadIndex = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.getHeadName = function() { return t.Message.getFieldWithDefault(this, 3, ''); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.setHeadName = function( e ) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.clearHeadName = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.tasks.components.containers.proto.Classifications.prototype.hasHeadName = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.repeatedFields_ = [ 1, ]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.components.containers.proto.ClassificationResult.prototype.toObject = function( e ) { return proto.mediapipe.tasks.components.containers.proto.ClassificationResult.toObject( e, this ); }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.toObject = function( e, r ) { var o, i = { classificationsList: t.Message.toObjectList( r.getClassificationsList(), proto.mediapipe.tasks.components.containers.proto.Classifications .toObject, e ), timestampMs: null == (o = t.Message.getField(r, 2)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.components.containers.proto.ClassificationResult(); return proto.mediapipe.tasks.components.containers.proto.ClassificationResult.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new proto.mediapipe.tasks.components.containers.proto.Classifications(); t.readMessage( r, proto.mediapipe.tasks.components.containers.proto.Classifications .deserializeBinaryFromReader ), e.addClassifications(r); break; case 2: r = t.readInt64(); e.setTimestampMs(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.components.containers.proto.ClassificationResult.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.serializeBinaryToWriter = function( e, r ) { var o = void 0; (o = e.getClassificationsList()).length > 0 && r.writeRepeatedMessage( 1, o, proto.mediapipe.tasks.components.containers.proto.Classifications .serializeBinaryToWriter ), null != (o = t.Message.getField(e, 2)) && r.writeInt64(2, o); }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.prototype.getClassificationsList = function() { return t.Message.getRepeatedWrapperField( this, proto.mediapipe.tasks.components.containers.proto.Classifications, 1 ); }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.prototype.setClassificationsList = function( e ) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.prototype.addClassifications = function( e, r ) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.tasks.components.containers.proto.Classifications, r ); }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.prototype.clearClassificationsList = function() { return this.setClassificationsList([]); }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.prototype.getTimestampMs = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.prototype.setTimestampMs = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.prototype.clearTimestampMs = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.components.containers.proto.ClassificationResult.prototype.hasTimestampMs = function() { return null != t.Message.getField(this, 2); }), r.object.extend(e, proto.mediapipe.tasks.components.containers.proto); })(classifications_pb); var image_classifier_graph_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = classifier_options_pb; r.object.extend(proto, n); var s = base_options_pb; r.object.extend(proto, s), r.exportSymbol( 'proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions', null, o ), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.displayName = 'proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.toObject = function( e, t ) { var r, o = { baseOptions: (r = t.getBaseOptions()) && s.BaseOptions.toObject(e, r), classifierOptions: (r = t.getClassifierOptions()) && n.ClassifierOptions.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions(); return proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new s.BaseOptions(); t.readMessage(r, s.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = new n.ClassifierOptions(); t.readMessage(r, n.ClassifierOptions.deserializeBinaryFromReader), e.setClassifierOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.serializeBinaryToWriter = function( e, t ) { var r = void 0; null != (r = e.getBaseOptions()) && t.writeMessage(1, r, s.BaseOptions.serializeBinaryToWriter), null != (r = e.getClassifierOptions()) && t.writeMessage(2, r, n.ClassifierOptions.serializeBinaryToWriter); }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.ext = new t.ExtensionFieldInfo( 456383383, { ext: 0 }, proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions, proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[456383383] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[456383383] = proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.ext), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, s.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.prototype.getClassifierOptions = function() { return t.Message.getWrapperField(this, n.ClassifierOptions, 2); }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.prototype.setClassifierOptions = function( e ) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.prototype.clearClassifierOptions = function() { return this.setClassifierOptions(void 0); }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.prototype.hasClassifierOptions = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.ext = new t.ExtensionFieldInfo( 456383383, { ext: 0 }, proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions, proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[456383383] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[456383383] = proto.mediapipe.tasks.vision.image_classifier.proto.ImageClassifierGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.image_classifier.proto); })(image_classifier_graph_options_pb); var image_classifier_options = {}; Object.defineProperty(image_classifier_options, '__esModule', { value: !0 }); var image_classifier_result = {}; Object.defineProperty(image_classifier_result, '__esModule', { value: !0 }), (function(e) { var t = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? function(e, t, r, o) { void 0 === o && (o = r); var i = Object.getOwnPropertyDescriptor(t, r); (i && !('get' in i ? !t.__esModule : i.writable || i.configurable)) || (i = { enumerable: !0, get: function() { return t[r]; }, }), Object.defineProperty(e, o, i); } : function(e, t, r, o) { void 0 === o && (o = r), (e[o] = t[r]); }), r = (commonjsGlobal && commonjsGlobal.__exportStar) || function(e, r) { for (var o in e) 'default' === o || Object.prototype.hasOwnProperty.call(r, o) || t(r, e, o); }; Object.defineProperty(e, '__esModule', { value: !0 }), (e.ImageClassifier = void 0); const o = calculator_pb, i = calculator_options_pb, a = classifications_pb, n = base_options_pb, s = image_classifier_graph_options_pb, p = classifier_options, d = classifier_result, l = vision_task_runner, g = 'input_image', c = 'norm_rect', u = 'classifications'; r(image_classifier_options, e), r(image_classifier_result, e); class m extends l.VisionTaskRunner { static createFromOptions(e, t) { return l.VisionTaskRunner.createVisionInstance(m, e, t); } static createFromModelBuffer(e, t) { return l.VisionTaskRunner.createVisionInstance(m, e, { baseOptions: { modelAssetBuffer: t }, }); } static createFromModelPath(e, t) { return l.VisionTaskRunner.createVisionInstance(m, e, { baseOptions: { modelAssetPath: t }, }); } constructor(e, t) { super(new l.VisionGraphRunner(e, t), g, c, !0), (this.classificationResult = { classifications: [] }), (this.options = new s.ImageClassifierGraphOptions()), this.options.setBaseOptions(new n.BaseOptions()); } get baseOptions() { return this.options.getBaseOptions(); } set baseOptions(e) { this.options.setBaseOptions(e); } setOptions(e) { return ( this.options.setClassifierOptions( (0, p.convertClassifierOptionsToProto)( e, this.options.getClassifierOptions() ) ), this.applyOptions(e) ); } classify(e, t) { return ( (this.classificationResult = { classifications: [] }), this.processImageData(e, t), this.classificationResult ); } classifyForVideo(e, t, r) { return ( (this.classificationResult = { classifications: [] }), this.processVideoData(e, r, t), this.classificationResult ); } refreshGraph() { const e = new o.CalculatorGraphConfig(); e.addInputStream(g), e.addInputStream(c), e.addOutputStream(u); const t = new i.CalculatorOptions(); t.setExtension(s.ImageClassifierGraphOptions.ext, this.options); const r = new o.CalculatorGraphConfig.Node(); r.setCalculator('mediapipe.tasks.vision.image_classifier.ImageClassifierGraph'), r.addInputStream('IMAGE:' + g), r.addInputStream('NORM_RECT:' + c), r.addOutputStream('CLASSIFICATIONS:' + u), r.setOptions(t), e.addNode(r), this.graphRunner.attachProtoListener(u, (e, t) => { (this.classificationResult = (0, d.convertFromClassificationResultProto)( a.ClassificationResult.deserializeBinary(e) )), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(u, (e) => { this.setLatestOutputTimestamp(e); }); const n = e.serializeBinary(); this.setGraph(new Uint8Array(n), !0); } } e.ImageClassifier = m; })(image_classifier); var image_embedder = {}, embeddings_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.tasks.components.containers.proto.Embedding', null, o), r.exportSymbol( 'proto.mediapipe.tasks.components.containers.proto.Embedding.EmbeddingCase', null, o ), r.exportSymbol( 'proto.mediapipe.tasks.components.containers.proto.EmbeddingResult', null, o ), r.exportSymbol('proto.mediapipe.tasks.components.containers.proto.FloatEmbedding', null, o), r.exportSymbol( 'proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding', null, o ), (proto.mediapipe.tasks.components.containers.proto.FloatEmbedding = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.repeatedFields_, null ); }), r.inherits(proto.mediapipe.tasks.components.containers.proto.FloatEmbedding, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.displayName = 'proto.mediapipe.tasks.components.containers.proto.FloatEmbedding'), (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.displayName = 'proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding'), (proto.mediapipe.tasks.components.containers.proto.Embedding = function(e) { t.Message.initialize( this, e, 0, -1, null, proto.mediapipe.tasks.components.containers.proto.Embedding.oneofGroups_ ); }), r.inherits(proto.mediapipe.tasks.components.containers.proto.Embedding, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.components.containers.proto.Embedding.displayName = 'proto.mediapipe.tasks.components.containers.proto.Embedding'), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.repeatedFields_, null ); }), r.inherits(proto.mediapipe.tasks.components.containers.proto.EmbeddingResult, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.displayName = 'proto.mediapipe.tasks.components.containers.proto.EmbeddingResult'), (proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.prototype.toObject = function( e ) { return proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.toObject( e, this ); }), (proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.toObject = function( e, r ) { var o, i = { valuesList: null == (o = t.Message.getRepeatedFloatingPointField(r, 1)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.components.containers.proto.FloatEmbedding(); return proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) for ( var r = t.isDelimited() ? t.readPackedFloat() : [t.readFloat()], o = 0; o < r.length; o++ ) e.addValues(r[o]); else t.skipField(); } return e; }), (proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.serializeBinaryToWriter = function( e, t ) { var r; (r = e.getValuesList()).length > 0 && t.writePackedFloat(1, r); }), (proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.prototype.getValuesList = function() { return t.Message.getRepeatedFloatingPointField(this, 1); }), (proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.prototype.setValuesList = function( e ) { return t.Message.setField(this, 1, e || []); }), (proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.prototype.addValues = function( e, r ) { return t.Message.addToRepeatedField(this, 1, e, r); }), (proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.prototype.clearValuesList = function() { return this.setValuesList([]); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.prototype.toObject = function( e ) { return proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.toObject( e, this ); }), (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.toObject = function( e, t ) { var r = { values: t.getValues_asB64() }; return e && (r.$jspbMessageInstance = t), r; })), (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding(); return proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = t.readBytes(); e.setValues(r); } else t.skipField(); } return e; }), (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.serializeBinaryToWriter = function( e, r ) { var o; null != (o = t.Message.getField(e, 1)) && r.writeBytes(1, o); }), (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.prototype.getValues = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.prototype.getValues_asB64 = function() { return t.Message.bytesAsB64(this.getValues()); }), (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.prototype.getValues_asU8 = function() { return t.Message.bytesAsU8(this.getValues()); }), (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.prototype.setValues = function( e ) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.prototype.clearValues = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.prototype.hasValues = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.oneofGroups_ = [[1, 2]]), (proto.mediapipe.tasks.components.containers.proto.Embedding.EmbeddingCase = { EMBEDDING_NOT_SET: 0, FLOAT_EMBEDDING: 1, QUANTIZED_EMBEDDING: 2, }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.getEmbeddingCase = function() { return t.Message.computeOneofCase( this, proto.mediapipe.tasks.components.containers.proto.Embedding.oneofGroups_[0] ); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.toObject = function( e ) { return proto.mediapipe.tasks.components.containers.proto.Embedding.toObject( e, this ); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.toObject = function(e, r) { var o, i = { floatEmbedding: (o = r.getFloatEmbedding()) && proto.mediapipe.tasks.components.containers.proto.FloatEmbedding.toObject( e, o ), quantizedEmbedding: (o = r.getQuantizedEmbedding()) && proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding.toObject( e, o ), headIndex: null == (o = t.Message.getField(r, 3)) ? void 0 : o, headName: null == (o = t.Message.getField(r, 4)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.components.containers.proto.Embedding.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.components.containers.proto.Embedding(); return proto.mediapipe.tasks.components.containers.proto.Embedding.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new proto.mediapipe.tasks.components.containers.proto.FloatEmbedding(); t.readMessage( r, proto.mediapipe.tasks.components.containers.proto.FloatEmbedding .deserializeBinaryFromReader ), e.setFloatEmbedding(r); break; case 2: r = new proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding(); t.readMessage( r, proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding .deserializeBinaryFromReader ), e.setQuantizedEmbedding(r); break; case 3: r = t.readInt32(); e.setHeadIndex(r); break; case 4: r = t.readString(); e.setHeadName(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.components.containers.proto.Embedding.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getFloatEmbedding()) && r.writeMessage( 1, o, proto.mediapipe.tasks.components.containers.proto.FloatEmbedding .serializeBinaryToWriter ), null != (o = e.getQuantizedEmbedding()) && r.writeMessage( 2, o, proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding .serializeBinaryToWriter ), null != (o = t.Message.getField(e, 3)) && r.writeInt32(3, o), null != (o = t.Message.getField(e, 4)) && r.writeString(4, o); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.getFloatEmbedding = function() { return t.Message.getWrapperField( this, proto.mediapipe.tasks.components.containers.proto.FloatEmbedding, 1 ); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.setFloatEmbedding = function( e ) { return t.Message.setOneofWrapperField( this, 1, proto.mediapipe.tasks.components.containers.proto.Embedding.oneofGroups_[0], e ); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.clearFloatEmbedding = function() { return this.setFloatEmbedding(void 0); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.hasFloatEmbedding = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.getQuantizedEmbedding = function() { return t.Message.getWrapperField( this, proto.mediapipe.tasks.components.containers.proto.QuantizedEmbedding, 2 ); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.setQuantizedEmbedding = function( e ) { return t.Message.setOneofWrapperField( this, 2, proto.mediapipe.tasks.components.containers.proto.Embedding.oneofGroups_[0], e ); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.clearQuantizedEmbedding = function() { return this.setQuantizedEmbedding(void 0); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.hasQuantizedEmbedding = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.getHeadIndex = function() { return t.Message.getFieldWithDefault(this, 3, 0); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.setHeadIndex = function( e ) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.clearHeadIndex = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.hasHeadIndex = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.getHeadName = function() { return t.Message.getFieldWithDefault(this, 4, ''); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.setHeadName = function( e ) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.clearHeadName = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.tasks.components.containers.proto.Embedding.prototype.hasHeadName = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.prototype.toObject = function( e ) { return proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.toObject( e, this ); }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.toObject = function( e, r ) { var o, i = { embeddingsList: t.Message.toObjectList( r.getEmbeddingsList(), proto.mediapipe.tasks.components.containers.proto.Embedding.toObject, e ), timestampMs: null == (o = t.Message.getField(r, 2)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.components.containers.proto.EmbeddingResult(); return proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new proto.mediapipe.tasks.components.containers.proto.Embedding(); t.readMessage( r, proto.mediapipe.tasks.components.containers.proto.Embedding .deserializeBinaryFromReader ), e.addEmbeddings(r); break; case 2: r = t.readInt64(); e.setTimestampMs(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.serializeBinaryToWriter = function( e, r ) { var o = void 0; (o = e.getEmbeddingsList()).length > 0 && r.writeRepeatedMessage( 1, o, proto.mediapipe.tasks.components.containers.proto.Embedding .serializeBinaryToWriter ), null != (o = t.Message.getField(e, 2)) && r.writeInt64(2, o); }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.prototype.getEmbeddingsList = function() { return t.Message.getRepeatedWrapperField( this, proto.mediapipe.tasks.components.containers.proto.Embedding, 1 ); }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.prototype.setEmbeddingsList = function( e ) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.prototype.addEmbeddings = function( e, r ) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.tasks.components.containers.proto.Embedding, r ); }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.prototype.clearEmbeddingsList = function() { return this.setEmbeddingsList([]); }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.prototype.getTimestampMs = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.prototype.setTimestampMs = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.prototype.clearTimestampMs = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.components.containers.proto.EmbeddingResult.prototype.hasTimestampMs = function() { return null != t.Message.getField(this, 2); }), r.object.extend(e, proto.mediapipe.tasks.components.containers.proto); })(embeddings_pb); var image_embedder_graph_options_pb = {}, embedder_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.tasks.components.processors.proto.EmbedderOptions', null, o), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.tasks.components.processors.proto.EmbedderOptions, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.displayName = 'proto.mediapipe.tasks.components.processors.proto.EmbedderOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.toObject( e, this ); }), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.toObject = function( e, r ) { var o, i = { l2Normalize: null == (o = t.Message.getBooleanField(r, 1)) ? void 0 : o, quantize: null == (o = t.Message.getBooleanField(r, 2)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.components.processors.proto.EmbedderOptions(); return proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readBool(); e.setL2Normalize(r); break; case 2: r = t.readBool(); e.setQuantize(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeBool(1, o), null != (o = t.Message.getField(e, 2)) && r.writeBool(2, o); }), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.prototype.getL2Normalize = function() { return t.Message.getBooleanFieldWithDefault(this, 1, !1); }), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.prototype.setL2Normalize = function( e ) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.prototype.clearL2Normalize = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.prototype.hasL2Normalize = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.prototype.getQuantize = function() { return t.Message.getBooleanFieldWithDefault(this, 2, !1); }), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.prototype.setQuantize = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.prototype.clearQuantize = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.components.processors.proto.EmbedderOptions.prototype.hasQuantize = function() { return null != t.Message.getField(this, 2); }), r.object.extend(e, proto.mediapipe.tasks.components.processors.proto); })(embedder_options_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = embedder_options_pb; r.object.extend(proto, n); var s = base_options_pb; r.object.extend(proto, s), r.exportSymbol( 'proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions', null, o ), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.displayName = 'proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.toObject = function( e, t ) { var r, o = { baseOptions: (r = t.getBaseOptions()) && s.BaseOptions.toObject(e, r), embedderOptions: (r = t.getEmbedderOptions()) && n.EmbedderOptions.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions(); return proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new s.BaseOptions(); t.readMessage(r, s.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = new n.EmbedderOptions(); t.readMessage(r, n.EmbedderOptions.deserializeBinaryFromReader), e.setEmbedderOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.serializeBinaryToWriter = function( e, t ) { var r = void 0; null != (r = e.getBaseOptions()) && t.writeMessage(1, r, s.BaseOptions.serializeBinaryToWriter), null != (r = e.getEmbedderOptions()) && t.writeMessage(2, r, n.EmbedderOptions.serializeBinaryToWriter); }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.ext = new t.ExtensionFieldInfo( 476348187, { ext: 0 }, proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions, proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[476348187] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[476348187] = proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.ext), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, s.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.prototype.getEmbedderOptions = function() { return t.Message.getWrapperField(this, n.EmbedderOptions, 2); }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.prototype.setEmbedderOptions = function( e ) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.prototype.clearEmbedderOptions = function() { return this.setEmbedderOptions(void 0); }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.prototype.hasEmbedderOptions = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.ext = new t.ExtensionFieldInfo( 476348187, { ext: 0 }, proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions, proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[476348187] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[476348187] = proto.mediapipe.tasks.vision.image_embedder.proto.ImageEmbedderGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.image_embedder.proto); })(image_embedder_graph_options_pb); var embedder_options = {}; Object.defineProperty(embedder_options, '__esModule', { value: !0 }), (embedder_options.convertEmbedderOptionsToProto = void 0); const embedder_options_pb_1 = embedder_options_pb; function convertEmbedderOptionsToProto(e, t) { const r = t ? t.clone() : new embedder_options_pb_1.EmbedderOptions(); return ( void 0 !== e.l2Normalize ? r.setL2Normalize(e.l2Normalize) : 'l2Normalize' in e && r.clearL2Normalize(), void 0 !== e.quantize ? r.setQuantize(e.quantize) : 'quantize' in e && r.clearQuantize(), r ); } embedder_options.convertEmbedderOptionsToProto = convertEmbedderOptionsToProto; var embedder_result = {}; Object.defineProperty(embedder_result, '__esModule', { value: !0 }), (embedder_result.convertFromEmbeddingResultProto = void 0); const DEFAULT_INDEX = -1; function convertFromEmbeddingsProto(e) { var t, r, o, i; const a = { headIndex: null !== (t = e.getHeadIndex()) && void 0 !== t ? t : DEFAULT_INDEX, headName: null !== (r = e.getHeadName()) && void 0 !== r ? r : '', }; if (e.hasFloatEmbedding()) a.floatEmbedding = e.getFloatEmbedding().getValuesList(); else { const t = null !== (i = null === (o = e.getQuantizedEmbedding()) || void 0 === o ? void 0 : o.getValues()) && void 0 !== i ? i : ''; a.quantizedEmbedding = 'string' == typeof t ? Uint8Array.from(atob(t), (e) => e.charCodeAt(0)) : t; } return a; } function convertFromEmbeddingResultProto(e) { return { embeddings: e.getEmbeddingsList().map((e) => convertFromEmbeddingsProto(e)), timestampMs: e.getTimestampMs(), }; } embedder_result.convertFromEmbeddingResultProto = convertFromEmbeddingResultProto; var cosine_similarity = {}; function computeCosineSimilarity(e, t) { if (e.floatEmbedding && t.floatEmbedding) return compute(e.floatEmbedding, t.floatEmbedding); if (e.quantizedEmbedding && t.quantizedEmbedding) return compute(convertToBytes(e.quantizedEmbedding), convertToBytes(t.quantizedEmbedding)); throw new Error('Cannot compute cosine similarity between quantized and float embeddings.'); } function convertToBytes(e) { return Array.from(e, (e) => (e > 127 ? e - 256 : e)); } function compute(e, t) { if (e.length !== t.length) throw new Error( `Cannot compute cosine similarity between embeddings of different sizes (${e.length} vs. ${t.length}).` ); let r = 0, o = 0, i = 0; for (let a = 0; a < e.length; a++) (r += e[a] * t[a]), (o += e[a] * e[a]), (i += t[a] * t[a]); if (o <= 0 || i <= 0) throw new Error('Cannot compute cosine similarity on embedding with 0 norm.'); return r / Math.sqrt(o * i); } Object.defineProperty(cosine_similarity, '__esModule', { value: !0 }), (cosine_similarity.computeCosineSimilarity = void 0), (cosine_similarity.computeCosineSimilarity = computeCosineSimilarity); var image_embedder_options = {}; Object.defineProperty(image_embedder_options, '__esModule', { value: !0 }); var image_embedder_result = {}; Object.defineProperty(image_embedder_result, '__esModule', { value: !0 }), (function(e) { var t = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? function(e, t, r, o) { void 0 === o && (o = r); var i = Object.getOwnPropertyDescriptor(t, r); (i && !('get' in i ? !t.__esModule : i.writable || i.configurable)) || (i = { enumerable: !0, get: function() { return t[r]; }, }), Object.defineProperty(e, o, i); } : function(e, t, r, o) { void 0 === o && (o = r), (e[o] = t[r]); }), r = (commonjsGlobal && commonjsGlobal.__exportStar) || function(e, r) { for (var o in e) 'default' === o || Object.prototype.hasOwnProperty.call(r, o) || t(r, e, o); }; Object.defineProperty(e, '__esModule', { value: !0 }), (e.ImageEmbedder = void 0); const o = calculator_pb, i = calculator_options_pb, a = embeddings_pb, n = base_options_pb, s = image_embedder_graph_options_pb, p = embedder_options, d = embedder_result, l = cosine_similarity, g = vision_task_runner, c = 'image_in', u = 'norm_rect', m = 'embeddings_out'; r(image_embedder_options, e), r(image_embedder_result, e); class f extends g.VisionTaskRunner { static createFromOptions(e, t) { return g.VisionTaskRunner.createVisionInstance(f, e, t); } static createFromModelBuffer(e, t) { return g.VisionTaskRunner.createVisionInstance(f, e, { baseOptions: { modelAssetBuffer: t }, }); } static createFromModelPath(e, t) { return g.VisionTaskRunner.createVisionInstance(f, e, { baseOptions: { modelAssetPath: t }, }); } constructor(e, t) { super(new g.VisionGraphRunner(e, t), c, u, !0), (this.options = new s.ImageEmbedderGraphOptions()), (this.embeddings = { embeddings: [] }), this.options.setBaseOptions(new n.BaseOptions()); } get baseOptions() { return this.options.getBaseOptions(); } set baseOptions(e) { this.options.setBaseOptions(e); } setOptions(e) { return ( this.options.setEmbedderOptions( (0, p.convertEmbedderOptionsToProto)(e, this.options.getEmbedderOptions()) ), this.applyOptions(e) ); } embed(e, t) { return this.processImageData(e, t), this.embeddings; } embedForVideo(e, t, r) { return this.processVideoData(e, r, t), this.embeddings; } static cosineSimilarity(e, t) { return (0, l.computeCosineSimilarity)(e, t); } addJsImageEmdedding(e) { const t = a.EmbeddingResult.deserializeBinary(e); this.embeddings = (0, d.convertFromEmbeddingResultProto)(t); } refreshGraph() { const e = new o.CalculatorGraphConfig(); e.addInputStream(c), e.addInputStream(u), e.addOutputStream(m); const t = new i.CalculatorOptions(); t.setExtension(s.ImageEmbedderGraphOptions.ext, this.options); const r = new o.CalculatorGraphConfig.Node(); r.setCalculator('mediapipe.tasks.vision.image_embedder.ImageEmbedderGraph'), r.addInputStream('IMAGE:' + c), r.addInputStream('NORM_RECT:' + u), r.addOutputStream('EMBEDDINGS:' + m), r.setOptions(t), e.addNode(r), this.graphRunner.attachProtoListener(m, (e, t) => { this.addJsImageEmdedding(e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(m, (e) => { this.setLatestOutputTimestamp(e); }); const a = e.serializeBinary(); this.setGraph(new Uint8Array(a), !0); } } e.ImageEmbedder = f; })(image_embedder); var image_segmenter = {}, tensors_to_segmentation_calculator_pb = {}, segmenter_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions', null, o), r.exportSymbol( 'proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.Activation', null, o ), r.exportSymbol( 'proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.OutputType', null, o ), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.displayName = 'proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.toObject = function( e, r ) { var o, i = { outputType: null == (o = t.Message.getField(r, 1)) ? void 0 : o, activation: t.Message.getFieldWithDefault(r, 2, 0), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions(); return proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readEnum(); e.setOutputType(r); break; case 2: r = t.readEnum(); e.setActivation(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeEnum(1, o), null != (o = t.Message.getField(e, 2)) && r.writeEnum(2, o); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.OutputType = { UNSPECIFIED: 0, CATEGORY_MASK: 1, CONFIDENCE_MASK: 2, }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.Activation = { NONE: 0, SIGMOID: 1, SOFTMAX: 2, }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.prototype.getOutputType = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.prototype.setOutputType = function( e ) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.prototype.clearOutputType = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.prototype.hasOutputType = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.prototype.getActivation = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.prototype.setActivation = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.prototype.clearActivation = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.SegmenterOptions.prototype.hasActivation = function() { return null != t.Message.getField(this, 2); }), r.object.extend(e, proto.mediapipe.tasks.vision.image_segmenter.proto); })(segmenter_options_pb); var label_map_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.LabelMapItem', null, o), (proto.mediapipe.LabelMapItem = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.LabelMapItem.repeatedFields_, null ); }), r.inherits(proto.mediapipe.LabelMapItem, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.LabelMapItem.displayName = 'proto.mediapipe.LabelMapItem'), (proto.mediapipe.LabelMapItem.repeatedFields_ = [3]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.LabelMapItem.prototype.toObject = function(e) { return proto.mediapipe.LabelMapItem.toObject(e, this); }), (proto.mediapipe.LabelMapItem.toObject = function(e, r) { var o, i = { name: null == (o = t.Message.getField(r, 1)) ? void 0 : o, displayName: null == (o = t.Message.getField(r, 2)) ? void 0 : o, childNameList: null == (o = t.Message.getRepeatedField(r, 3)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.LabelMapItem.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.LabelMapItem(); return proto.mediapipe.LabelMapItem.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.LabelMapItem.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setName(r); break; case 2: r = t.readString(); e.setDisplayName(r); break; case 3: r = t.readString(); e.addChildName(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.LabelMapItem.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.LabelMapItem.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.LabelMapItem.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeString(1, o), null != (o = t.Message.getField(e, 2)) && r.writeString(2, o), (o = e.getChildNameList()).length > 0 && r.writeRepeatedString(3, o); }), (proto.mediapipe.LabelMapItem.prototype.getName = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.LabelMapItem.prototype.setName = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.LabelMapItem.prototype.clearName = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.LabelMapItem.prototype.hasName = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.LabelMapItem.prototype.getDisplayName = function() { return t.Message.getFieldWithDefault(this, 2, ''); }), (proto.mediapipe.LabelMapItem.prototype.setDisplayName = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.LabelMapItem.prototype.clearDisplayName = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.LabelMapItem.prototype.hasDisplayName = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.LabelMapItem.prototype.getChildNameList = function() { return t.Message.getRepeatedField(this, 3); }), (proto.mediapipe.LabelMapItem.prototype.setChildNameList = function(e) { return t.Message.setField(this, 3, e || []); }), (proto.mediapipe.LabelMapItem.prototype.addChildName = function(e, r) { return t.Message.addToRepeatedField(this, 3, e, r); }), (proto.mediapipe.LabelMapItem.prototype.clearChildNameList = function() { return this.setChildNameList([]); }), r.object.extend(e, proto.mediapipe); })(label_map_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_options_pb; r.object.extend(proto, i); var a = segmenter_options_pb; r.object.extend(proto, a); var n = label_map_pb; r.object.extend(proto, n), r.exportSymbol('proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions', null, o), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.displayName = 'proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.toObject( e, this ); }), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.toObject = function( e, t ) { var r, o = { segmenterOptions: (r = t.getSegmenterOptions()) && a.SegmenterOptions.toObject(e, r), labelItemsMap: (r = t.getLabelItemsMap()) ? r.toObject(e, proto.mediapipe.LabelMapItem.toObject) : [], }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions(); return proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.deserializeBinaryFromReader = function( e, r ) { for (; r.nextField() && !r.isEndGroup(); ) { switch (r.getFieldNumber()) { case 1: var o = new a.SegmenterOptions(); r.readMessage(o, a.SegmenterOptions.deserializeBinaryFromReader), e.setSegmenterOptions(o); break; case 2: o = e.getLabelItemsMap(); r.readMessage(o, function(e, r) { t.Map.deserializeBinary( e, r, t.BinaryReader.prototype.readInt64, t.BinaryReader.prototype.readMessage, proto.mediapipe.LabelMapItem.deserializeBinaryFromReader, 0, new proto.mediapipe.LabelMapItem() ); }); break; default: r.skipField(); } } return e; }), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getSegmenterOptions()) && r.writeMessage(1, o, a.SegmenterOptions.serializeBinaryToWriter), (o = e.getLabelItemsMap(!0)) && o.getLength() > 0 && o.serializeBinary( 2, r, t.BinaryWriter.prototype.writeInt64, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.LabelMapItem.serializeBinaryToWriter ); }), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.ext = new t.ExtensionFieldInfo( 458105876, { ext: 0 }, proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions, proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.toObject, 0 )), (i.CalculatorOptions.extensionsBinary[458105876] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.serializeBinaryToWriter, proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.deserializeBinaryFromReader, !1 )), (i.CalculatorOptions.extensions[458105876] = proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.ext), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.prototype.getSegmenterOptions = function() { return t.Message.getWrapperField(this, a.SegmenterOptions, 1); }), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.prototype.setSegmenterOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.prototype.clearSegmenterOptions = function() { return this.setSegmenterOptions(void 0); }), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.prototype.hasSegmenterOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.prototype.getLabelItemsMap = function( e ) { return t.Message.getMapField(this, 2, e, proto.mediapipe.LabelMapItem); }), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.prototype.clearLabelItemsMap = function() { return this.getLabelItemsMap().clear(), this; }), (proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.ext = new t.ExtensionFieldInfo( 458105876, { ext: 0 }, proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions, proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.toObject, 0 )), (i.CalculatorOptions.extensionsBinary[458105876] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.serializeBinaryToWriter, proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.deserializeBinaryFromReader, !1 )), (i.CalculatorOptions.extensions[458105876] = proto.mediapipe.tasks.TensorsToSegmentationCalculatorOptions.ext), r.object.extend(e, proto.mediapipe.tasks); })(tensors_to_segmentation_calculator_pb); var image_segmenter_graph_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n); var s = segmenter_options_pb; r.object.extend(proto, s), r.exportSymbol( 'proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions', null, o ), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.displayName = 'proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.toObject = function( e, r ) { var o, i = { baseOptions: (o = r.getBaseOptions()) && n.BaseOptions.toObject(e, o), displayNamesLocale: t.Message.getFieldWithDefault(r, 2, 'en'), segmenterOptions: (o = r.getSegmenterOptions()) && s.SegmenterOptions.toObject(e, o), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions(); return proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = t.readString(); e.setDisplayNamesLocale(r); break; case 3: r = new s.SegmenterOptions(); t.readMessage(r, s.SegmenterOptions.deserializeBinaryFromReader), e.setSegmenterOptions(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getBaseOptions()) && r.writeMessage(1, o, n.BaseOptions.serializeBinaryToWriter), null != (o = t.Message.getField(e, 2)) && r.writeString(2, o), null != (o = e.getSegmenterOptions()) && r.writeMessage(3, o, s.SegmenterOptions.serializeBinaryToWriter); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.ext = new t.ExtensionFieldInfo( 458105758, { ext: 0 }, proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions, proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[458105758] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[458105758] = proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.ext), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.getDisplayNamesLocale = function() { return t.Message.getFieldWithDefault(this, 2, 'en'); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.setDisplayNamesLocale = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.clearDisplayNamesLocale = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.hasDisplayNamesLocale = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.getSegmenterOptions = function() { return t.Message.getWrapperField(this, s.SegmenterOptions, 3); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.setSegmenterOptions = function( e ) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.clearSegmenterOptions = function() { return this.setSegmenterOptions(void 0); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.prototype.hasSegmenterOptions = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.ext = new t.ExtensionFieldInfo( 458105758, { ext: 0 }, proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions, proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[458105758] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[458105758] = proto.mediapipe.tasks.vision.image_segmenter.proto.ImageSegmenterGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.image_segmenter.proto); })(image_segmenter_graph_options_pb); var image_segmenter_result = {}; Object.defineProperty(image_segmenter_result, '__esModule', { value: !0 }), (image_segmenter_result.ImageSegmenterResult = void 0); class ImageSegmenterResult { constructor(e, t, r) { (this.confidenceMasks = e), (this.categoryMask = t), (this.qualityScores = r); } close() { var e, t; null === (e = this.confidenceMasks) || void 0 === e || e.forEach((e) => { e.close(); }), null === (t = this.categoryMask) || void 0 === t || t.close(); } } image_segmenter_result.ImageSegmenterResult = ImageSegmenterResult; var image_segmenter_options = {}; Object.defineProperty(image_segmenter_options, '__esModule', { value: !0 }), (function(e) { var t = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? function(e, t, r, o) { void 0 === o && (o = r); var i = Object.getOwnPropertyDescriptor(t, r); (i && !('get' in i ? !t.__esModule : i.writable || i.configurable)) || (i = { enumerable: !0, get: function() { return t[r]; }, }), Object.defineProperty(e, o, i); } : function(e, t, r, o) { void 0 === o && (o = r), (e[o] = t[r]); }), r = (commonjsGlobal && commonjsGlobal.__exportStar) || function(e, r) { for (var o in e) 'default' === o || Object.prototype.hasOwnProperty.call(r, o) || t(r, e, o); }; Object.defineProperty(e, '__esModule', { value: !0 }), (e.ImageSegmenter = void 0); const o = calculator_pb, i = calculator_options_pb, a = base_options_pb, n = tensors_to_segmentation_calculator_pb, s = image_segmenter_graph_options_pb, p = segmenter_options_pb, d = vision_task_runner, l = image_segmenter_result; r(image_segmenter_options, e), r(image_segmenter_result, e); const g = 'image_in', c = 'norm_rect', u = 'confidence_masks', m = 'category_mask', f = 'quality_scores', h = 'mediapipe.tasks.TensorsToSegmentationCalculator'; class y extends d.VisionTaskRunner { static createFromOptions(e, t) { return d.VisionTaskRunner.createVisionInstance(y, e, t); } static createFromModelBuffer(e, t) { return d.VisionTaskRunner.createVisionInstance(y, e, { baseOptions: { modelAssetBuffer: t }, }); } static createFromModelPath(e, t) { return d.VisionTaskRunner.createVisionInstance(y, e, { baseOptions: { modelAssetPath: t }, }); } constructor(e, t) { super(new d.VisionGraphRunner(e, t), g, c, !1), (this.labels = []), (this.outputCategoryMask = false), (this.outputConfidenceMasks = true), (this.options = new s.ImageSegmenterGraphOptions()), (this.segmenterOptions = new p.SegmenterOptions()), this.options.setSegmenterOptions(this.segmenterOptions), this.options.setBaseOptions(new a.BaseOptions()); } get baseOptions() { return this.options.getBaseOptions(); } set baseOptions(e) { this.options.setBaseOptions(e); } setOptions(e) { var t, r; return ( void 0 !== e.displayNamesLocale ? this.options.setDisplayNamesLocale(e.displayNamesLocale) : 'displayNamesLocale' in e && this.options.clearDisplayNamesLocale(), 'outputCategoryMask' in e && (this.outputCategoryMask = null !== (t = e.outputCategoryMask) && void 0 !== t && t), 'outputConfidenceMasks' in e && (this.outputConfidenceMasks = null === (r = e.outputConfidenceMasks) || void 0 === r || r), super.applyOptions(e) ); } onGraphRefreshed() { this.populateLabels(); } populateLabels() { var e, t, r; const o = this.getCalculatorGraphConfig() .getNodeList() .filter((e) => e.getName().includes(h)); if (((this.labels = []), o.length > 1)) throw new Error(`The graph has more than one ${h}.`); if (1 === o.length) { (null !== (r = null === (t = null === (e = o[0].getOptions()) || void 0 === e ? void 0 : e.getExtension( n.TensorsToSegmentationCalculatorOptions.ext )) || void 0 === t ? void 0 : t.getLabelItemsMap()) && void 0 !== r ? r : new Map() ).forEach((e, t) => { this.labels[Number(t)] = e.getName(); }); } } segment(e, t, r) { const o = 'function' != typeof t ? t : {}; return ( (this.userCallback = 'function' == typeof t ? t : r), this.reset(), this.processImageData(e, o), this.processResults() ); } segmentForVideo(e, t, r, o) { const i = 'function' != typeof r ? r : {}; return ( (this.userCallback = 'function' == typeof r ? r : o), this.reset(), this.processVideoData(e, i, t), this.processResults() ); } getLabels() { return this.labels; } reset() { (this.categoryMask = void 0), (this.confidenceMasks = void 0), (this.qualityScores = void 0); } processResults() { try { const e = new l.ImageSegmenterResult( this.confidenceMasks, this.categoryMask, this.qualityScores ); if (!this.userCallback) return e; this.userCallback(e); } finally { this.freeKeepaliveStreams(); } } refreshGraph() { const e = new o.CalculatorGraphConfig(); e.addInputStream(g), e.addInputStream(c); const t = new i.CalculatorOptions(); t.setExtension(s.ImageSegmenterGraphOptions.ext, this.options); const r = new o.CalculatorGraphConfig.Node(); r.setCalculator('mediapipe.tasks.vision.image_segmenter.ImageSegmenterGraph'), r.addInputStream('IMAGE:' + g), r.addInputStream('NORM_RECT:' + c), r.setOptions(t), e.addNode(r), this.addKeepaliveNode(e), this.outputConfidenceMasks && (e.addOutputStream(u), r.addOutputStream('CONFIDENCE_MASKS:' + u), this.keepStreamAlive(u), this.graphRunner.attachImageVectorListener(u, (e, t) => { (this.confidenceMasks = e.map((e) => this.convertToMPMask(e, !this.userCallback) )), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(u, (e) => { (this.confidenceMasks = []), this.setLatestOutputTimestamp(e); })), this.outputCategoryMask && (e.addOutputStream(m), r.addOutputStream('CATEGORY_MASK:' + m), this.keepStreamAlive(m), this.graphRunner.attachImageListener(m, (e, t) => { (this.categoryMask = this.convertToMPMask(e, !this.userCallback)), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(m, (e) => { (this.categoryMask = void 0), this.setLatestOutputTimestamp(e); })), e.addOutputStream(f), r.addOutputStream('QUALITY_SCORES:' + f), this.graphRunner.attachFloatVectorListener(f, (e, t) => { (this.qualityScores = e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(f, (e) => { (this.categoryMask = void 0), this.setLatestOutputTimestamp(e); }); const a = e.serializeBinary(); this.setGraph(new Uint8Array(a), !0); } } e.ImageSegmenter = y; })(image_segmenter); var interactive_segmenter = {}, color_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(); r.exportSymbol('proto.mediapipe.Color', null, o), r.exportSymbol('proto.mediapipe.ColorMap', null, o), (proto.mediapipe.Color = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.Color, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.Color.displayName = 'proto.mediapipe.Color'), (proto.mediapipe.ColorMap = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.ColorMap, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.ColorMap.displayName = 'proto.mediapipe.ColorMap'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.Color.prototype.toObject = function(e) { return proto.mediapipe.Color.toObject(e, this); }), (proto.mediapipe.Color.toObject = function(e, r) { var o, i = { r: null == (o = t.Message.getField(r, 1)) ? void 0 : o, g: null == (o = t.Message.getField(r, 2)) ? void 0 : o, b: null == (o = t.Message.getField(r, 3)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.Color.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.Color(); return proto.mediapipe.Color.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.Color.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readInt32(); e.setR(r); break; case 2: r = t.readInt32(); e.setG(r); break; case 3: r = t.readInt32(); e.setB(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.Color.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return proto.mediapipe.Color.serializeBinaryToWriter(this, e), e.getResultBuffer(); }), (proto.mediapipe.Color.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeInt32(1, o), null != (o = t.Message.getField(e, 2)) && r.writeInt32(2, o), null != (o = t.Message.getField(e, 3)) && r.writeInt32(3, o); }), (proto.mediapipe.Color.prototype.getR = function() { return t.Message.getFieldWithDefault(this, 1, 0); }), (proto.mediapipe.Color.prototype.setR = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.Color.prototype.clearR = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.Color.prototype.hasR = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.Color.prototype.getG = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.Color.prototype.setG = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.Color.prototype.clearG = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.Color.prototype.hasG = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.Color.prototype.getB = function() { return t.Message.getFieldWithDefault(this, 3, 0); }), (proto.mediapipe.Color.prototype.setB = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.Color.prototype.clearB = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.Color.prototype.hasB = function() { return null != t.Message.getField(this, 3); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.ColorMap.prototype.toObject = function(e) { return proto.mediapipe.ColorMap.toObject(e, this); }), (proto.mediapipe.ColorMap.toObject = function(e, t) { var r, o = { labelToColorMap: (r = t.getLabelToColorMap()) ? r.toObject(e, proto.mediapipe.Color.toObject) : [], }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.ColorMap.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.ColorMap(); return proto.mediapipe.ColorMap.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.ColorMap.deserializeBinaryFromReader = function(e, r) { for (; r.nextField() && !r.isEndGroup(); ) { if (1 === r.getFieldNumber()) { var o = e.getLabelToColorMap(); r.readMessage(o, function(e, r) { t.Map.deserializeBinary( e, r, t.BinaryReader.prototype.readString, t.BinaryReader.prototype.readMessage, proto.mediapipe.Color.deserializeBinaryFromReader, '', new proto.mediapipe.Color() ); }); } else r.skipField(); } return e; }), (proto.mediapipe.ColorMap.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return proto.mediapipe.ColorMap.serializeBinaryToWriter(this, e), e.getResultBuffer(); }), (proto.mediapipe.ColorMap.serializeBinaryToWriter = function(e, r) { var o = void 0; (o = e.getLabelToColorMap(!0)) && o.getLength() > 0 && o.serializeBinary( 1, r, t.BinaryWriter.prototype.writeString, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.Color.serializeBinaryToWriter ); }), (proto.mediapipe.ColorMap.prototype.getLabelToColorMap = function(e) { return t.Message.getMapField(this, 1, e, proto.mediapipe.Color); }), (proto.mediapipe.ColorMap.prototype.clearLabelToColorMap = function() { return this.getLabelToColorMap().clear(), this; }), r.object.extend(e, proto.mediapipe); })(color_pb); var render_data_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = color_pb; r.object.extend(proto, i), r.exportSymbol('proto.mediapipe.RenderAnnotation', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.Arrow', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.DataCase', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.FilledOval', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.FilledRectangle', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.FilledRoundedRectangle', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.GradientLine', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.Line', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.Line.LineType', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.Oval', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.Point', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.Rectangle', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.RoundedRectangle', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.Scribble', null, o), r.exportSymbol('proto.mediapipe.RenderAnnotation.Text', null, o), r.exportSymbol('proto.mediapipe.RenderData', null, o), r.exportSymbol('proto.mediapipe.RenderViewport', null, o), (proto.mediapipe.RenderData = function(e) { t.Message.initialize(this, e, 0, -1, proto.mediapipe.RenderData.repeatedFields_, null); }), r.inherits(proto.mediapipe.RenderData, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderData.displayName = 'proto.mediapipe.RenderData'), (proto.mediapipe.RenderAnnotation = function(e) { t.Message.initialize( this, e, 0, -1, null, proto.mediapipe.RenderAnnotation.oneofGroups_ ); }), r.inherits(proto.mediapipe.RenderAnnotation, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.displayName = 'proto.mediapipe.RenderAnnotation'), (proto.mediapipe.RenderAnnotation.Rectangle = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.RenderAnnotation.Rectangle, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.Rectangle.displayName = 'proto.mediapipe.RenderAnnotation.Rectangle'), (proto.mediapipe.RenderAnnotation.FilledRectangle = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.RenderAnnotation.FilledRectangle, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.FilledRectangle.displayName = 'proto.mediapipe.RenderAnnotation.FilledRectangle'), (proto.mediapipe.RenderAnnotation.RoundedRectangle = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.RenderAnnotation.RoundedRectangle, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.RoundedRectangle.displayName = 'proto.mediapipe.RenderAnnotation.RoundedRectangle'), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.RenderAnnotation.FilledRoundedRectangle, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.displayName = 'proto.mediapipe.RenderAnnotation.FilledRoundedRectangle'), (proto.mediapipe.RenderAnnotation.Oval = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.RenderAnnotation.Oval, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.Oval.displayName = 'proto.mediapipe.RenderAnnotation.Oval'), (proto.mediapipe.RenderAnnotation.FilledOval = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.RenderAnnotation.FilledOval, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.FilledOval.displayName = 'proto.mediapipe.RenderAnnotation.FilledOval'), (proto.mediapipe.RenderAnnotation.Point = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.RenderAnnotation.Point, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.Point.displayName = 'proto.mediapipe.RenderAnnotation.Point'), (proto.mediapipe.RenderAnnotation.Line = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.RenderAnnotation.Line, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.Line.displayName = 'proto.mediapipe.RenderAnnotation.Line'), (proto.mediapipe.RenderAnnotation.GradientLine = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.RenderAnnotation.GradientLine, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.GradientLine.displayName = 'proto.mediapipe.RenderAnnotation.GradientLine'), (proto.mediapipe.RenderAnnotation.Scribble = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.RenderAnnotation.Scribble.repeatedFields_, null ); }), r.inherits(proto.mediapipe.RenderAnnotation.Scribble, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.Scribble.displayName = 'proto.mediapipe.RenderAnnotation.Scribble'), (proto.mediapipe.RenderAnnotation.Arrow = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.RenderAnnotation.Arrow, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.Arrow.displayName = 'proto.mediapipe.RenderAnnotation.Arrow'), (proto.mediapipe.RenderAnnotation.Text = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.RenderAnnotation.Text, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderAnnotation.Text.displayName = 'proto.mediapipe.RenderAnnotation.Text'), (proto.mediapipe.RenderViewport = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits(proto.mediapipe.RenderViewport, t.Message), r.DEBUG && !COMPILED && (proto.mediapipe.RenderViewport.displayName = 'proto.mediapipe.RenderViewport'), (proto.mediapipe.RenderData.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderData.prototype.toObject = function(e) { return proto.mediapipe.RenderData.toObject(e, this); }), (proto.mediapipe.RenderData.toObject = function(e, r) { var o, i = { renderAnnotationsList: t.Message.toObjectList( r.getRenderAnnotationsList(), proto.mediapipe.RenderAnnotation.toObject, e ), sceneClass: null == (o = t.Message.getField(r, 2)) ? void 0 : o, sceneViewport: (o = r.getSceneViewport()) && proto.mediapipe.RenderViewport.toObject(e, o), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.RenderData.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderData(); return proto.mediapipe.RenderData.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.RenderData.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new proto.mediapipe.RenderAnnotation(); t.readMessage( r, proto.mediapipe.RenderAnnotation.deserializeBinaryFromReader ), e.addRenderAnnotations(r); break; case 2: r = t.readString(); e.setSceneClass(r); break; case 3: r = new proto.mediapipe.RenderViewport(); t.readMessage( r, proto.mediapipe.RenderViewport.deserializeBinaryFromReader ), e.setSceneViewport(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderData.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return proto.mediapipe.RenderData.serializeBinaryToWriter(this, e), e.getResultBuffer(); }), (proto.mediapipe.RenderData.serializeBinaryToWriter = function(e, r) { var o = void 0; (o = e.getRenderAnnotationsList()).length > 0 && r.writeRepeatedMessage( 1, o, proto.mediapipe.RenderAnnotation.serializeBinaryToWriter ), null != (o = t.Message.getField(e, 2)) && r.writeString(2, o), null != (o = e.getSceneViewport()) && r.writeMessage(3, o, proto.mediapipe.RenderViewport.serializeBinaryToWriter); }), (proto.mediapipe.RenderData.prototype.getRenderAnnotationsList = function() { return t.Message.getRepeatedWrapperField(this, proto.mediapipe.RenderAnnotation, 1); }), (proto.mediapipe.RenderData.prototype.setRenderAnnotationsList = function(e) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.RenderData.prototype.addRenderAnnotations = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.RenderAnnotation, r ); }), (proto.mediapipe.RenderData.prototype.clearRenderAnnotationsList = function() { return this.setRenderAnnotationsList([]); }), (proto.mediapipe.RenderData.prototype.getSceneClass = function() { return t.Message.getFieldWithDefault(this, 2, ''); }), (proto.mediapipe.RenderData.prototype.setSceneClass = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.RenderData.prototype.clearSceneClass = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.RenderData.prototype.hasSceneClass = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.RenderData.prototype.getSceneViewport = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderViewport, 3); }), (proto.mediapipe.RenderData.prototype.setSceneViewport = function(e) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.RenderData.prototype.clearSceneViewport = function() { return this.setSceneViewport(void 0); }), (proto.mediapipe.RenderData.prototype.hasSceneViewport = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.RenderAnnotation.oneofGroups_ = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 15]]), (proto.mediapipe.RenderAnnotation.DataCase = { DATA_NOT_SET: 0, RECTANGLE: 1, FILLED_RECTANGLE: 2, OVAL: 3, FILLED_OVAL: 4, POINT: 5, LINE: 6, ARROW: 7, TEXT: 8, ROUNDED_RECTANGLE: 9, FILLED_ROUNDED_RECTANGLE: 10, GRADIENT_LINE: 14, SCRIBBLE: 15, }), (proto.mediapipe.RenderAnnotation.prototype.getDataCase = function() { return t.Message.computeOneofCase( this, proto.mediapipe.RenderAnnotation.oneofGroups_[0] ); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.prototype.toObject = function(e) { return proto.mediapipe.RenderAnnotation.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.toObject = function(e, r) { var o, a = { rectangle: (o = r.getRectangle()) && proto.mediapipe.RenderAnnotation.Rectangle.toObject(e, o), filledRectangle: (o = r.getFilledRectangle()) && proto.mediapipe.RenderAnnotation.FilledRectangle.toObject(e, o), oval: (o = r.getOval()) && proto.mediapipe.RenderAnnotation.Oval.toObject(e, o), filledOval: (o = r.getFilledOval()) && proto.mediapipe.RenderAnnotation.FilledOval.toObject(e, o), point: (o = r.getPoint()) && proto.mediapipe.RenderAnnotation.Point.toObject(e, o), line: (o = r.getLine()) && proto.mediapipe.RenderAnnotation.Line.toObject(e, o), arrow: (o = r.getArrow()) && proto.mediapipe.RenderAnnotation.Arrow.toObject(e, o), text: (o = r.getText()) && proto.mediapipe.RenderAnnotation.Text.toObject(e, o), roundedRectangle: (o = r.getRoundedRectangle()) && proto.mediapipe.RenderAnnotation.RoundedRectangle.toObject(e, o), filledRoundedRectangle: (o = r.getFilledRoundedRectangle()) && proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.toObject(e, o), gradientLine: (o = r.getGradientLine()) && proto.mediapipe.RenderAnnotation.GradientLine.toObject(e, o), scribble: (o = r.getScribble()) && proto.mediapipe.RenderAnnotation.Scribble.toObject(e, o), thickness: t.Message.getFloatingPointFieldWithDefault(r, 11, 1), color: (o = r.getColor()) && i.Color.toObject(e, o), sceneTag: null == (o = t.Message.getField(r, 13)) ? void 0 : o, }; return e && (a.$jspbMessageInstance = r), a; })), (proto.mediapipe.RenderAnnotation.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation(); return proto.mediapipe.RenderAnnotation.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.RenderAnnotation.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new proto.mediapipe.RenderAnnotation.Rectangle(); t.readMessage( r, proto.mediapipe.RenderAnnotation.Rectangle.deserializeBinaryFromReader ), e.setRectangle(r); break; case 2: r = new proto.mediapipe.RenderAnnotation.FilledRectangle(); t.readMessage( r, proto.mediapipe.RenderAnnotation.FilledRectangle .deserializeBinaryFromReader ), e.setFilledRectangle(r); break; case 3: r = new proto.mediapipe.RenderAnnotation.Oval(); t.readMessage( r, proto.mediapipe.RenderAnnotation.Oval.deserializeBinaryFromReader ), e.setOval(r); break; case 4: r = new proto.mediapipe.RenderAnnotation.FilledOval(); t.readMessage( r, proto.mediapipe.RenderAnnotation.FilledOval.deserializeBinaryFromReader ), e.setFilledOval(r); break; case 5: r = new proto.mediapipe.RenderAnnotation.Point(); t.readMessage( r, proto.mediapipe.RenderAnnotation.Point.deserializeBinaryFromReader ), e.setPoint(r); break; case 6: r = new proto.mediapipe.RenderAnnotation.Line(); t.readMessage( r, proto.mediapipe.RenderAnnotation.Line.deserializeBinaryFromReader ), e.setLine(r); break; case 7: r = new proto.mediapipe.RenderAnnotation.Arrow(); t.readMessage( r, proto.mediapipe.RenderAnnotation.Arrow.deserializeBinaryFromReader ), e.setArrow(r); break; case 8: r = new proto.mediapipe.RenderAnnotation.Text(); t.readMessage( r, proto.mediapipe.RenderAnnotation.Text.deserializeBinaryFromReader ), e.setText(r); break; case 9: r = new proto.mediapipe.RenderAnnotation.RoundedRectangle(); t.readMessage( r, proto.mediapipe.RenderAnnotation.RoundedRectangle .deserializeBinaryFromReader ), e.setRoundedRectangle(r); break; case 10: r = new proto.mediapipe.RenderAnnotation.FilledRoundedRectangle(); t.readMessage( r, proto.mediapipe.RenderAnnotation.FilledRoundedRectangle .deserializeBinaryFromReader ), e.setFilledRoundedRectangle(r); break; case 14: r = new proto.mediapipe.RenderAnnotation.GradientLine(); t.readMessage( r, proto.mediapipe.RenderAnnotation.GradientLine .deserializeBinaryFromReader ), e.setGradientLine(r); break; case 15: r = new proto.mediapipe.RenderAnnotation.Scribble(); t.readMessage( r, proto.mediapipe.RenderAnnotation.Scribble.deserializeBinaryFromReader ), e.setScribble(r); break; case 11: r = t.readDouble(); e.setThickness(r); break; case 12: r = new i.Color(); t.readMessage(r, i.Color.deserializeBinaryFromReader), e.setColor(r); break; case 13: r = t.readString(); e.setSceneTag(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderAnnotation.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = e.getRectangle()) && r.writeMessage( 1, o, proto.mediapipe.RenderAnnotation.Rectangle.serializeBinaryToWriter ), null != (o = e.getFilledRectangle()) && r.writeMessage( 2, o, proto.mediapipe.RenderAnnotation.FilledRectangle.serializeBinaryToWriter ), null != (o = e.getOval()) && r.writeMessage( 3, o, proto.mediapipe.RenderAnnotation.Oval.serializeBinaryToWriter ), null != (o = e.getFilledOval()) && r.writeMessage( 4, o, proto.mediapipe.RenderAnnotation.FilledOval.serializeBinaryToWriter ), null != (o = e.getPoint()) && r.writeMessage( 5, o, proto.mediapipe.RenderAnnotation.Point.serializeBinaryToWriter ), null != (o = e.getLine()) && r.writeMessage( 6, o, proto.mediapipe.RenderAnnotation.Line.serializeBinaryToWriter ), null != (o = e.getArrow()) && r.writeMessage( 7, o, proto.mediapipe.RenderAnnotation.Arrow.serializeBinaryToWriter ), null != (o = e.getText()) && r.writeMessage( 8, o, proto.mediapipe.RenderAnnotation.Text.serializeBinaryToWriter ), null != (o = e.getRoundedRectangle()) && r.writeMessage( 9, o, proto.mediapipe.RenderAnnotation.RoundedRectangle.serializeBinaryToWriter ), null != (o = e.getFilledRoundedRectangle()) && r.writeMessage( 10, o, proto.mediapipe.RenderAnnotation.FilledRoundedRectangle .serializeBinaryToWriter ), null != (o = e.getGradientLine()) && r.writeMessage( 14, o, proto.mediapipe.RenderAnnotation.GradientLine.serializeBinaryToWriter ), null != (o = e.getScribble()) && r.writeMessage( 15, o, proto.mediapipe.RenderAnnotation.Scribble.serializeBinaryToWriter ), null != (o = t.Message.getField(e, 11)) && r.writeDouble(11, o), null != (o = e.getColor()) && r.writeMessage(12, o, i.Color.serializeBinaryToWriter), null != (o = t.Message.getField(e, 13)) && r.writeString(13, o); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.Rectangle.prototype.toObject = function(e) { return proto.mediapipe.RenderAnnotation.Rectangle.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.Rectangle.toObject = function(e, r) { var o, i = { left: null == (o = t.Message.getOptionalFloatingPointField(r, 1)) ? void 0 : o, top: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, right: null == (o = t.Message.getOptionalFloatingPointField(r, 3)) ? void 0 : o, bottom: null == (o = t.Message.getOptionalFloatingPointField(r, 4)) ? void 0 : o, normalized: t.Message.getBooleanFieldWithDefault(r, 5, !1), rotation: null == (o = t.Message.getOptionalFloatingPointField(r, 6)) ? void 0 : o, topLeftThickness: null == (o = t.Message.getOptionalFloatingPointField(r, 7)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.RenderAnnotation.Rectangle.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation.Rectangle(); return proto.mediapipe.RenderAnnotation.Rectangle.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.RenderAnnotation.Rectangle.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readDouble(); e.setLeft(r); break; case 2: r = t.readDouble(); e.setTop(r); break; case 3: r = t.readDouble(); e.setRight(r); break; case 4: r = t.readDouble(); e.setBottom(r); break; case 5: r = t.readBool(); e.setNormalized(r); break; case 6: r = t.readDouble(); e.setRotation(r); break; case 7: r = t.readDouble(); e.setTopLeftThickness(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.Rectangle.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.Rectangle.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeDouble(1, o), null != (o = t.Message.getField(e, 2)) && r.writeDouble(2, o), null != (o = t.Message.getField(e, 3)) && r.writeDouble(3, o), null != (o = t.Message.getField(e, 4)) && r.writeDouble(4, o), null != (o = t.Message.getField(e, 5)) && r.writeBool(5, o), null != (o = t.Message.getField(e, 6)) && r.writeDouble(6, o), null != (o = t.Message.getField(e, 7)) && r.writeDouble(7, o); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.getLeft = function() { return t.Message.getFloatingPointFieldWithDefault(this, 1, 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.setLeft = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.clearLeft = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.hasLeft = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.getTop = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.setTop = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.clearTop = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.hasTop = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.getRight = function() { return t.Message.getFloatingPointFieldWithDefault(this, 3, 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.setRight = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.clearRight = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.hasRight = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.getBottom = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.setBottom = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.clearBottom = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.hasBottom = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.getNormalized = function() { return t.Message.getBooleanFieldWithDefault(this, 5, !1); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.setNormalized = function(e) { return t.Message.setField(this, 5, e); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.clearNormalized = function() { return t.Message.setField(this, 5, void 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.hasNormalized = function() { return null != t.Message.getField(this, 5); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.getRotation = function() { return t.Message.getFloatingPointFieldWithDefault(this, 6, 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.setRotation = function(e) { return t.Message.setField(this, 6, e); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.clearRotation = function() { return t.Message.setField(this, 6, void 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.hasRotation = function() { return null != t.Message.getField(this, 6); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.getTopLeftThickness = function() { return t.Message.getFloatingPointFieldWithDefault(this, 7, 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.setTopLeftThickness = function(e) { return t.Message.setField(this, 7, e); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.clearTopLeftThickness = function() { return t.Message.setField(this, 7, void 0); }), (proto.mediapipe.RenderAnnotation.Rectangle.prototype.hasTopLeftThickness = function() { return null != t.Message.getField(this, 7); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.FilledRectangle.prototype.toObject = function(e) { return proto.mediapipe.RenderAnnotation.FilledRectangle.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.FilledRectangle.toObject = function(e, t) { var r, o = { rectangle: (r = t.getRectangle()) && proto.mediapipe.RenderAnnotation.Rectangle.toObject(e, r), fillColor: (r = t.getFillColor()) && i.Color.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.RenderAnnotation.FilledRectangle.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation.FilledRectangle(); return proto.mediapipe.RenderAnnotation.FilledRectangle.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.RenderAnnotation.FilledRectangle.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new proto.mediapipe.RenderAnnotation.Rectangle(); t.readMessage( r, proto.mediapipe.RenderAnnotation.Rectangle.deserializeBinaryFromReader ), e.setRectangle(r); break; case 2: r = new i.Color(); t.readMessage(r, i.Color.deserializeBinaryFromReader), e.setFillColor(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderAnnotation.FilledRectangle.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.FilledRectangle.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.FilledRectangle.serializeBinaryToWriter = function(e, t) { var r = void 0; null != (r = e.getRectangle()) && t.writeMessage( 1, r, proto.mediapipe.RenderAnnotation.Rectangle.serializeBinaryToWriter ), null != (r = e.getFillColor()) && t.writeMessage(2, r, i.Color.serializeBinaryToWriter); }), (proto.mediapipe.RenderAnnotation.FilledRectangle.prototype.getRectangle = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderAnnotation.Rectangle, 1); }), (proto.mediapipe.RenderAnnotation.FilledRectangle.prototype.setRectangle = function(e) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.RenderAnnotation.FilledRectangle.prototype.clearRectangle = function() { return this.setRectangle(void 0); }), (proto.mediapipe.RenderAnnotation.FilledRectangle.prototype.hasRectangle = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.RenderAnnotation.FilledRectangle.prototype.getFillColor = function() { return t.Message.getWrapperField(this, i.Color, 2); }), (proto.mediapipe.RenderAnnotation.FilledRectangle.prototype.setFillColor = function(e) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.RenderAnnotation.FilledRectangle.prototype.clearFillColor = function() { return this.setFillColor(void 0); }), (proto.mediapipe.RenderAnnotation.FilledRectangle.prototype.hasFillColor = function() { return null != t.Message.getField(this, 2); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.toObject = function(e) { return proto.mediapipe.RenderAnnotation.RoundedRectangle.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.toObject = function(e, r) { var o, i = { rectangle: (o = r.getRectangle()) && proto.mediapipe.RenderAnnotation.Rectangle.toObject(e, o), cornerRadius: t.Message.getFieldWithDefault(r, 2, 0), lineType: t.Message.getFieldWithDefault(r, 3, 4), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.RenderAnnotation.RoundedRectangle.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation.RoundedRectangle(); return proto.mediapipe.RenderAnnotation.RoundedRectangle.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new proto.mediapipe.RenderAnnotation.Rectangle(); t.readMessage( r, proto.mediapipe.RenderAnnotation.Rectangle.deserializeBinaryFromReader ), e.setRectangle(r); break; case 2: r = t.readInt32(); e.setCornerRadius(r); break; case 3: r = t.readInt32(); e.setLineType(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.RoundedRectangle.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getRectangle()) && r.writeMessage( 1, o, proto.mediapipe.RenderAnnotation.Rectangle.serializeBinaryToWriter ), null != (o = t.Message.getField(e, 2)) && r.writeInt32(2, o), null != (o = t.Message.getField(e, 3)) && r.writeInt32(3, o); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.getRectangle = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderAnnotation.Rectangle, 1); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.setRectangle = function(e) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.clearRectangle = function() { return this.setRectangle(void 0); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.hasRectangle = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.getCornerRadius = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.setCornerRadius = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.clearCornerRadius = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.hasCornerRadius = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.getLineType = function() { return t.Message.getFieldWithDefault(this, 3, 4); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.setLineType = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.clearLineType = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.RenderAnnotation.RoundedRectangle.prototype.hasLineType = function() { return null != t.Message.getField(this, 3); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.prototype.toObject = function( e ) { return proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.toObject = function(e, t) { var r, o = { roundedRectangle: (r = t.getRoundedRectangle()) && proto.mediapipe.RenderAnnotation.RoundedRectangle.toObject(e, r), fillColor: (r = t.getFillColor()) && i.Color.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation.FilledRoundedRectangle(); return proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new proto.mediapipe.RenderAnnotation.RoundedRectangle(); t.readMessage( r, proto.mediapipe.RenderAnnotation.RoundedRectangle .deserializeBinaryFromReader ), e.setRoundedRectangle(r); break; case 2: r = new i.Color(); t.readMessage(r, i.Color.deserializeBinaryFromReader), e.setFillColor(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.serializeBinaryToWriter = function( e, t ) { var r = void 0; null != (r = e.getRoundedRectangle()) && t.writeMessage( 1, r, proto.mediapipe.RenderAnnotation.RoundedRectangle.serializeBinaryToWriter ), null != (r = e.getFillColor()) && t.writeMessage(2, r, i.Color.serializeBinaryToWriter); }), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.prototype.getRoundedRectangle = function() { return t.Message.getWrapperField( this, proto.mediapipe.RenderAnnotation.RoundedRectangle, 1 ); }), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.prototype.setRoundedRectangle = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.prototype.clearRoundedRectangle = function() { return this.setRoundedRectangle(void 0); }), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.prototype.hasRoundedRectangle = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.prototype.getFillColor = function() { return t.Message.getWrapperField(this, i.Color, 2); }), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.prototype.setFillColor = function( e ) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.prototype.clearFillColor = function() { return this.setFillColor(void 0); }), (proto.mediapipe.RenderAnnotation.FilledRoundedRectangle.prototype.hasFillColor = function() { return null != t.Message.getField(this, 2); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.Oval.prototype.toObject = function(e) { return proto.mediapipe.RenderAnnotation.Oval.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.Oval.toObject = function(e, t) { var r, o = { rectangle: (r = t.getRectangle()) && proto.mediapipe.RenderAnnotation.Rectangle.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.RenderAnnotation.Oval.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation.Oval(); return proto.mediapipe.RenderAnnotation.Oval.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.RenderAnnotation.Oval.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new proto.mediapipe.RenderAnnotation.Rectangle(); t.readMessage( r, proto.mediapipe.RenderAnnotation.Rectangle.deserializeBinaryFromReader ), e.setRectangle(r); } else t.skipField(); } return e; }), (proto.mediapipe.RenderAnnotation.Oval.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.Oval.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.Oval.serializeBinaryToWriter = function(e, t) { var r; null != (r = e.getRectangle()) && t.writeMessage( 1, r, proto.mediapipe.RenderAnnotation.Rectangle.serializeBinaryToWriter ); }), (proto.mediapipe.RenderAnnotation.Oval.prototype.getRectangle = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderAnnotation.Rectangle, 1); }), (proto.mediapipe.RenderAnnotation.Oval.prototype.setRectangle = function(e) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.RenderAnnotation.Oval.prototype.clearRectangle = function() { return this.setRectangle(void 0); }), (proto.mediapipe.RenderAnnotation.Oval.prototype.hasRectangle = function() { return null != t.Message.getField(this, 1); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.FilledOval.prototype.toObject = function(e) { return proto.mediapipe.RenderAnnotation.FilledOval.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.FilledOval.toObject = function(e, t) { var r, o = { oval: (r = t.getOval()) && proto.mediapipe.RenderAnnotation.Oval.toObject(e, r), fillColor: (r = t.getFillColor()) && i.Color.toObject(e, r), }; return e && (o.$jspbMessageInstance = t), o; })), (proto.mediapipe.RenderAnnotation.FilledOval.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation.FilledOval(); return proto.mediapipe.RenderAnnotation.FilledOval.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.RenderAnnotation.FilledOval.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new proto.mediapipe.RenderAnnotation.Oval(); t.readMessage( r, proto.mediapipe.RenderAnnotation.Oval.deserializeBinaryFromReader ), e.setOval(r); break; case 2: r = new i.Color(); t.readMessage(r, i.Color.deserializeBinaryFromReader), e.setFillColor(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderAnnotation.FilledOval.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.FilledOval.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.FilledOval.serializeBinaryToWriter = function(e, t) { var r = void 0; null != (r = e.getOval()) && t.writeMessage(1, r, proto.mediapipe.RenderAnnotation.Oval.serializeBinaryToWriter), null != (r = e.getFillColor()) && t.writeMessage(2, r, i.Color.serializeBinaryToWriter); }), (proto.mediapipe.RenderAnnotation.FilledOval.prototype.getOval = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderAnnotation.Oval, 1); }), (proto.mediapipe.RenderAnnotation.FilledOval.prototype.setOval = function(e) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.RenderAnnotation.FilledOval.prototype.clearOval = function() { return this.setOval(void 0); }), (proto.mediapipe.RenderAnnotation.FilledOval.prototype.hasOval = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.RenderAnnotation.FilledOval.prototype.getFillColor = function() { return t.Message.getWrapperField(this, i.Color, 2); }), (proto.mediapipe.RenderAnnotation.FilledOval.prototype.setFillColor = function(e) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.RenderAnnotation.FilledOval.prototype.clearFillColor = function() { return this.setFillColor(void 0); }), (proto.mediapipe.RenderAnnotation.FilledOval.prototype.hasFillColor = function() { return null != t.Message.getField(this, 2); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.Point.prototype.toObject = function(e) { return proto.mediapipe.RenderAnnotation.Point.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.Point.toObject = function(e, r) { var o, i = { x: null == (o = t.Message.getOptionalFloatingPointField(r, 1)) ? void 0 : o, y: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, normalized: t.Message.getBooleanFieldWithDefault(r, 3, !1), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.RenderAnnotation.Point.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation.Point(); return proto.mediapipe.RenderAnnotation.Point.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.RenderAnnotation.Point.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readDouble(); e.setX(r); break; case 2: r = t.readDouble(); e.setY(r); break; case 3: r = t.readBool(); e.setNormalized(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderAnnotation.Point.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.Point.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.Point.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeDouble(1, o), null != (o = t.Message.getField(e, 2)) && r.writeDouble(2, o), null != (o = t.Message.getField(e, 3)) && r.writeBool(3, o); }), (proto.mediapipe.RenderAnnotation.Point.prototype.getX = function() { return t.Message.getFloatingPointFieldWithDefault(this, 1, 0); }), (proto.mediapipe.RenderAnnotation.Point.prototype.setX = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.RenderAnnotation.Point.prototype.clearX = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.RenderAnnotation.Point.prototype.hasX = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.RenderAnnotation.Point.prototype.getY = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.RenderAnnotation.Point.prototype.setY = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.RenderAnnotation.Point.prototype.clearY = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.RenderAnnotation.Point.prototype.hasY = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.RenderAnnotation.Point.prototype.getNormalized = function() { return t.Message.getBooleanFieldWithDefault(this, 3, !1); }), (proto.mediapipe.RenderAnnotation.Point.prototype.setNormalized = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.RenderAnnotation.Point.prototype.clearNormalized = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.RenderAnnotation.Point.prototype.hasNormalized = function() { return null != t.Message.getField(this, 3); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.Line.prototype.toObject = function(e) { return proto.mediapipe.RenderAnnotation.Line.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.Line.toObject = function(e, r) { var o, i = { xStart: null == (o = t.Message.getOptionalFloatingPointField(r, 1)) ? void 0 : o, yStart: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, xEnd: null == (o = t.Message.getOptionalFloatingPointField(r, 3)) ? void 0 : o, yEnd: null == (o = t.Message.getOptionalFloatingPointField(r, 4)) ? void 0 : o, normalized: t.Message.getBooleanFieldWithDefault(r, 5, !1), lineType: t.Message.getFieldWithDefault(r, 6, 1), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.RenderAnnotation.Line.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation.Line(); return proto.mediapipe.RenderAnnotation.Line.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.RenderAnnotation.Line.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readDouble(); e.setXStart(r); break; case 2: r = t.readDouble(); e.setYStart(r); break; case 3: r = t.readDouble(); e.setXEnd(r); break; case 4: r = t.readDouble(); e.setYEnd(r); break; case 5: r = t.readBool(); e.setNormalized(r); break; case 6: r = t.readEnum(); e.setLineType(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderAnnotation.Line.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.Line.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.Line.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeDouble(1, o), null != (o = t.Message.getField(e, 2)) && r.writeDouble(2, o), null != (o = t.Message.getField(e, 3)) && r.writeDouble(3, o), null != (o = t.Message.getField(e, 4)) && r.writeDouble(4, o), null != (o = t.Message.getField(e, 5)) && r.writeBool(5, o), null != (o = t.Message.getField(e, 6)) && r.writeEnum(6, o); }), (proto.mediapipe.RenderAnnotation.Line.LineType = { UNKNOWN: 0, SOLID: 1, DASHED: 2 }), (proto.mediapipe.RenderAnnotation.Line.prototype.getXStart = function() { return t.Message.getFloatingPointFieldWithDefault(this, 1, 0); }), (proto.mediapipe.RenderAnnotation.Line.prototype.setXStart = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.RenderAnnotation.Line.prototype.clearXStart = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.RenderAnnotation.Line.prototype.hasXStart = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.RenderAnnotation.Line.prototype.getYStart = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.RenderAnnotation.Line.prototype.setYStart = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.RenderAnnotation.Line.prototype.clearYStart = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.RenderAnnotation.Line.prototype.hasYStart = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.RenderAnnotation.Line.prototype.getXEnd = function() { return t.Message.getFloatingPointFieldWithDefault(this, 3, 0); }), (proto.mediapipe.RenderAnnotation.Line.prototype.setXEnd = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.RenderAnnotation.Line.prototype.clearXEnd = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.RenderAnnotation.Line.prototype.hasXEnd = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.RenderAnnotation.Line.prototype.getYEnd = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0); }), (proto.mediapipe.RenderAnnotation.Line.prototype.setYEnd = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.RenderAnnotation.Line.prototype.clearYEnd = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.RenderAnnotation.Line.prototype.hasYEnd = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.RenderAnnotation.Line.prototype.getNormalized = function() { return t.Message.getBooleanFieldWithDefault(this, 5, !1); }), (proto.mediapipe.RenderAnnotation.Line.prototype.setNormalized = function(e) { return t.Message.setField(this, 5, e); }), (proto.mediapipe.RenderAnnotation.Line.prototype.clearNormalized = function() { return t.Message.setField(this, 5, void 0); }), (proto.mediapipe.RenderAnnotation.Line.prototype.hasNormalized = function() { return null != t.Message.getField(this, 5); }), (proto.mediapipe.RenderAnnotation.Line.prototype.getLineType = function() { return t.Message.getFieldWithDefault(this, 6, 1); }), (proto.mediapipe.RenderAnnotation.Line.prototype.setLineType = function(e) { return t.Message.setField(this, 6, e); }), (proto.mediapipe.RenderAnnotation.Line.prototype.clearLineType = function() { return t.Message.setField(this, 6, void 0); }), (proto.mediapipe.RenderAnnotation.Line.prototype.hasLineType = function() { return null != t.Message.getField(this, 6); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.GradientLine.prototype.toObject = function(e) { return proto.mediapipe.RenderAnnotation.GradientLine.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.GradientLine.toObject = function(e, r) { var o, a = { xStart: null == (o = t.Message.getOptionalFloatingPointField(r, 1)) ? void 0 : o, yStart: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, xEnd: null == (o = t.Message.getOptionalFloatingPointField(r, 3)) ? void 0 : o, yEnd: null == (o = t.Message.getOptionalFloatingPointField(r, 4)) ? void 0 : o, normalized: t.Message.getBooleanFieldWithDefault(r, 5, !1), color1: (o = r.getColor1()) && i.Color.toObject(e, o), color2: (o = r.getColor2()) && i.Color.toObject(e, o), }; return e && (a.$jspbMessageInstance = r), a; })), (proto.mediapipe.RenderAnnotation.GradientLine.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation.GradientLine(); return proto.mediapipe.RenderAnnotation.GradientLine.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.RenderAnnotation.GradientLine.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readDouble(); e.setXStart(r); break; case 2: r = t.readDouble(); e.setYStart(r); break; case 3: r = t.readDouble(); e.setXEnd(r); break; case 4: r = t.readDouble(); e.setYEnd(r); break; case 5: r = t.readBool(); e.setNormalized(r); break; case 6: r = new i.Color(); t.readMessage(r, i.Color.deserializeBinaryFromReader), e.setColor1(r); break; case 7: r = new i.Color(); t.readMessage(r, i.Color.deserializeBinaryFromReader), e.setColor2(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.GradientLine.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.GradientLine.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeDouble(1, o), null != (o = t.Message.getField(e, 2)) && r.writeDouble(2, o), null != (o = t.Message.getField(e, 3)) && r.writeDouble(3, o), null != (o = t.Message.getField(e, 4)) && r.writeDouble(4, o), null != (o = t.Message.getField(e, 5)) && r.writeBool(5, o), null != (o = e.getColor1()) && r.writeMessage(6, o, i.Color.serializeBinaryToWriter), null != (o = e.getColor2()) && r.writeMessage(7, o, i.Color.serializeBinaryToWriter); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.getXStart = function() { return t.Message.getFloatingPointFieldWithDefault(this, 1, 0); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.setXStart = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.clearXStart = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.hasXStart = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.getYStart = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.setYStart = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.clearYStart = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.hasYStart = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.getXEnd = function() { return t.Message.getFloatingPointFieldWithDefault(this, 3, 0); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.setXEnd = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.clearXEnd = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.hasXEnd = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.getYEnd = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.setYEnd = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.clearYEnd = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.hasYEnd = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.getNormalized = function() { return t.Message.getBooleanFieldWithDefault(this, 5, !1); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.setNormalized = function(e) { return t.Message.setField(this, 5, e); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.clearNormalized = function() { return t.Message.setField(this, 5, void 0); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.hasNormalized = function() { return null != t.Message.getField(this, 5); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.getColor1 = function() { return t.Message.getWrapperField(this, i.Color, 6); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.setColor1 = function(e) { return t.Message.setWrapperField(this, 6, e); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.clearColor1 = function() { return this.setColor1(void 0); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.hasColor1 = function() { return null != t.Message.getField(this, 6); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.getColor2 = function() { return t.Message.getWrapperField(this, i.Color, 7); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.setColor2 = function(e) { return t.Message.setWrapperField(this, 7, e); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.clearColor2 = function() { return this.setColor2(void 0); }), (proto.mediapipe.RenderAnnotation.GradientLine.prototype.hasColor2 = function() { return null != t.Message.getField(this, 7); }), (proto.mediapipe.RenderAnnotation.Scribble.repeatedFields_ = [1]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.Scribble.prototype.toObject = function(e) { return proto.mediapipe.RenderAnnotation.Scribble.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.Scribble.toObject = function(e, r) { var o = { pointList: t.Message.toObjectList( r.getPointList(), proto.mediapipe.RenderAnnotation.Point.toObject, e ), }; return e && (o.$jspbMessageInstance = r), o; })), (proto.mediapipe.RenderAnnotation.Scribble.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation.Scribble(); return proto.mediapipe.RenderAnnotation.Scribble.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.RenderAnnotation.Scribble.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { if (1 === t.getFieldNumber()) { var r = new proto.mediapipe.RenderAnnotation.Point(); t.readMessage( r, proto.mediapipe.RenderAnnotation.Point.deserializeBinaryFromReader ), e.addPoint(r); } else t.skipField(); } return e; }), (proto.mediapipe.RenderAnnotation.Scribble.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.Scribble.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.Scribble.serializeBinaryToWriter = function(e, t) { var r; (r = e.getPointList()).length > 0 && t.writeRepeatedMessage( 1, r, proto.mediapipe.RenderAnnotation.Point.serializeBinaryToWriter ); }), (proto.mediapipe.RenderAnnotation.Scribble.prototype.getPointList = function() { return t.Message.getRepeatedWrapperField( this, proto.mediapipe.RenderAnnotation.Point, 1 ); }), (proto.mediapipe.RenderAnnotation.Scribble.prototype.setPointList = function(e) { return t.Message.setRepeatedWrapperField(this, 1, e); }), (proto.mediapipe.RenderAnnotation.Scribble.prototype.addPoint = function(e, r) { return t.Message.addToRepeatedWrapperField( this, 1, e, proto.mediapipe.RenderAnnotation.Point, r ); }), (proto.mediapipe.RenderAnnotation.Scribble.prototype.clearPointList = function() { return this.setPointList([]); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.Arrow.prototype.toObject = function(e) { return proto.mediapipe.RenderAnnotation.Arrow.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.Arrow.toObject = function(e, r) { var o, i = { xStart: null == (o = t.Message.getOptionalFloatingPointField(r, 1)) ? void 0 : o, yStart: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, xEnd: null == (o = t.Message.getOptionalFloatingPointField(r, 3)) ? void 0 : o, yEnd: null == (o = t.Message.getOptionalFloatingPointField(r, 4)) ? void 0 : o, normalized: t.Message.getBooleanFieldWithDefault(r, 5, !1), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.RenderAnnotation.Arrow.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation.Arrow(); return proto.mediapipe.RenderAnnotation.Arrow.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.RenderAnnotation.Arrow.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readDouble(); e.setXStart(r); break; case 2: r = t.readDouble(); e.setYStart(r); break; case 3: r = t.readDouble(); e.setXEnd(r); break; case 4: r = t.readDouble(); e.setYEnd(r); break; case 5: r = t.readBool(); e.setNormalized(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.Arrow.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.Arrow.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeDouble(1, o), null != (o = t.Message.getField(e, 2)) && r.writeDouble(2, o), null != (o = t.Message.getField(e, 3)) && r.writeDouble(3, o), null != (o = t.Message.getField(e, 4)) && r.writeDouble(4, o), null != (o = t.Message.getField(e, 5)) && r.writeBool(5, o); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.getXStart = function() { return t.Message.getFloatingPointFieldWithDefault(this, 1, 0); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.setXStart = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.clearXStart = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.hasXStart = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.getYStart = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.setYStart = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.clearYStart = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.hasYStart = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.getXEnd = function() { return t.Message.getFloatingPointFieldWithDefault(this, 3, 0); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.setXEnd = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.clearXEnd = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.hasXEnd = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.getYEnd = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.setYEnd = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.clearYEnd = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.hasYEnd = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.getNormalized = function() { return t.Message.getBooleanFieldWithDefault(this, 5, !1); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.setNormalized = function(e) { return t.Message.setField(this, 5, e); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.clearNormalized = function() { return t.Message.setField(this, 5, void 0); }), (proto.mediapipe.RenderAnnotation.Arrow.prototype.hasNormalized = function() { return null != t.Message.getField(this, 5); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderAnnotation.Text.prototype.toObject = function(e) { return proto.mediapipe.RenderAnnotation.Text.toObject(e, this); }), (proto.mediapipe.RenderAnnotation.Text.toObject = function(e, r) { var o, a = { displayText: null == (o = t.Message.getField(r, 1)) ? void 0 : o, left: null == (o = t.Message.getOptionalFloatingPointField(r, 2)) ? void 0 : o, baseline: null == (o = t.Message.getOptionalFloatingPointField(r, 3)) ? void 0 : o, fontHeight: t.Message.getFloatingPointFieldWithDefault(r, 4, 8), normalized: t.Message.getBooleanFieldWithDefault(r, 5, !1), fontFace: t.Message.getFieldWithDefault(r, 6, 0), centerHorizontally: t.Message.getBooleanFieldWithDefault(r, 7, !1), centerVertically: t.Message.getBooleanFieldWithDefault(r, 8, !1), outlineThickness: t.Message.getFloatingPointFieldWithDefault(r, 11, 0), outlineColor: (o = r.getOutlineColor()) && i.Color.toObject(e, o), }; return e && (a.$jspbMessageInstance = r), a; })), (proto.mediapipe.RenderAnnotation.Text.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderAnnotation.Text(); return proto.mediapipe.RenderAnnotation.Text.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.RenderAnnotation.Text.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setDisplayText(r); break; case 2: r = t.readDouble(); e.setLeft(r); break; case 3: r = t.readDouble(); e.setBaseline(r); break; case 4: r = t.readDouble(); e.setFontHeight(r); break; case 5: r = t.readBool(); e.setNormalized(r); break; case 6: r = t.readInt32(); e.setFontFace(r); break; case 7: r = t.readBool(); e.setCenterHorizontally(r); break; case 8: r = t.readBool(); e.setCenterVertically(r); break; case 11: r = t.readDouble(); e.setOutlineThickness(r); break; case 12: r = new i.Color(); t.readMessage(r, i.Color.deserializeBinaryFromReader), e.setOutlineColor(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderAnnotation.Text.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderAnnotation.Text.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderAnnotation.Text.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeString(1, o), null != (o = t.Message.getField(e, 2)) && r.writeDouble(2, o), null != (o = t.Message.getField(e, 3)) && r.writeDouble(3, o), null != (o = t.Message.getField(e, 4)) && r.writeDouble(4, o), null != (o = t.Message.getField(e, 5)) && r.writeBool(5, o), null != (o = t.Message.getField(e, 6)) && r.writeInt32(6, o), null != (o = t.Message.getField(e, 7)) && r.writeBool(7, o), null != (o = t.Message.getField(e, 8)) && r.writeBool(8, o), null != (o = t.Message.getField(e, 11)) && r.writeDouble(11, o), null != (o = e.getOutlineColor()) && r.writeMessage(12, o, i.Color.serializeBinaryToWriter); }), (proto.mediapipe.RenderAnnotation.Text.prototype.getDisplayText = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.RenderAnnotation.Text.prototype.setDisplayText = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.RenderAnnotation.Text.prototype.clearDisplayText = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.hasDisplayText = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.RenderAnnotation.Text.prototype.getLeft = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.setLeft = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.RenderAnnotation.Text.prototype.clearLeft = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.hasLeft = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.RenderAnnotation.Text.prototype.getBaseline = function() { return t.Message.getFloatingPointFieldWithDefault(this, 3, 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.setBaseline = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.RenderAnnotation.Text.prototype.clearBaseline = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.hasBaseline = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.RenderAnnotation.Text.prototype.getFontHeight = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 8); }), (proto.mediapipe.RenderAnnotation.Text.prototype.setFontHeight = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.RenderAnnotation.Text.prototype.clearFontHeight = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.hasFontHeight = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.RenderAnnotation.Text.prototype.getNormalized = function() { return t.Message.getBooleanFieldWithDefault(this, 5, !1); }), (proto.mediapipe.RenderAnnotation.Text.prototype.setNormalized = function(e) { return t.Message.setField(this, 5, e); }), (proto.mediapipe.RenderAnnotation.Text.prototype.clearNormalized = function() { return t.Message.setField(this, 5, void 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.hasNormalized = function() { return null != t.Message.getField(this, 5); }), (proto.mediapipe.RenderAnnotation.Text.prototype.getFontFace = function() { return t.Message.getFieldWithDefault(this, 6, 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.setFontFace = function(e) { return t.Message.setField(this, 6, e); }), (proto.mediapipe.RenderAnnotation.Text.prototype.clearFontFace = function() { return t.Message.setField(this, 6, void 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.hasFontFace = function() { return null != t.Message.getField(this, 6); }), (proto.mediapipe.RenderAnnotation.Text.prototype.getCenterHorizontally = function() { return t.Message.getBooleanFieldWithDefault(this, 7, !1); }), (proto.mediapipe.RenderAnnotation.Text.prototype.setCenterHorizontally = function(e) { return t.Message.setField(this, 7, e); }), (proto.mediapipe.RenderAnnotation.Text.prototype.clearCenterHorizontally = function() { return t.Message.setField(this, 7, void 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.hasCenterHorizontally = function() { return null != t.Message.getField(this, 7); }), (proto.mediapipe.RenderAnnotation.Text.prototype.getCenterVertically = function() { return t.Message.getBooleanFieldWithDefault(this, 8, !1); }), (proto.mediapipe.RenderAnnotation.Text.prototype.setCenterVertically = function(e) { return t.Message.setField(this, 8, e); }), (proto.mediapipe.RenderAnnotation.Text.prototype.clearCenterVertically = function() { return t.Message.setField(this, 8, void 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.hasCenterVertically = function() { return null != t.Message.getField(this, 8); }), (proto.mediapipe.RenderAnnotation.Text.prototype.getOutlineThickness = function() { return t.Message.getFloatingPointFieldWithDefault(this, 11, 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.setOutlineThickness = function(e) { return t.Message.setField(this, 11, e); }), (proto.mediapipe.RenderAnnotation.Text.prototype.clearOutlineThickness = function() { return t.Message.setField(this, 11, void 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.hasOutlineThickness = function() { return null != t.Message.getField(this, 11); }), (proto.mediapipe.RenderAnnotation.Text.prototype.getOutlineColor = function() { return t.Message.getWrapperField(this, i.Color, 12); }), (proto.mediapipe.RenderAnnotation.Text.prototype.setOutlineColor = function(e) { return t.Message.setWrapperField(this, 12, e); }), (proto.mediapipe.RenderAnnotation.Text.prototype.clearOutlineColor = function() { return this.setOutlineColor(void 0); }), (proto.mediapipe.RenderAnnotation.Text.prototype.hasOutlineColor = function() { return null != t.Message.getField(this, 12); }), (proto.mediapipe.RenderAnnotation.prototype.getRectangle = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderAnnotation.Rectangle, 1); }), (proto.mediapipe.RenderAnnotation.prototype.setRectangle = function(e) { return t.Message.setOneofWrapperField( this, 1, proto.mediapipe.RenderAnnotation.oneofGroups_[0], e ); }), (proto.mediapipe.RenderAnnotation.prototype.clearRectangle = function() { return this.setRectangle(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasRectangle = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.RenderAnnotation.prototype.getFilledRectangle = function() { return t.Message.getWrapperField( this, proto.mediapipe.RenderAnnotation.FilledRectangle, 2 ); }), (proto.mediapipe.RenderAnnotation.prototype.setFilledRectangle = function(e) { return t.Message.setOneofWrapperField( this, 2, proto.mediapipe.RenderAnnotation.oneofGroups_[0], e ); }), (proto.mediapipe.RenderAnnotation.prototype.clearFilledRectangle = function() { return this.setFilledRectangle(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasFilledRectangle = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.RenderAnnotation.prototype.getOval = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderAnnotation.Oval, 3); }), (proto.mediapipe.RenderAnnotation.prototype.setOval = function(e) { return t.Message.setOneofWrapperField( this, 3, proto.mediapipe.RenderAnnotation.oneofGroups_[0], e ); }), (proto.mediapipe.RenderAnnotation.prototype.clearOval = function() { return this.setOval(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasOval = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.RenderAnnotation.prototype.getFilledOval = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderAnnotation.FilledOval, 4); }), (proto.mediapipe.RenderAnnotation.prototype.setFilledOval = function(e) { return t.Message.setOneofWrapperField( this, 4, proto.mediapipe.RenderAnnotation.oneofGroups_[0], e ); }), (proto.mediapipe.RenderAnnotation.prototype.clearFilledOval = function() { return this.setFilledOval(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasFilledOval = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.RenderAnnotation.prototype.getPoint = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderAnnotation.Point, 5); }), (proto.mediapipe.RenderAnnotation.prototype.setPoint = function(e) { return t.Message.setOneofWrapperField( this, 5, proto.mediapipe.RenderAnnotation.oneofGroups_[0], e ); }), (proto.mediapipe.RenderAnnotation.prototype.clearPoint = function() { return this.setPoint(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasPoint = function() { return null != t.Message.getField(this, 5); }), (proto.mediapipe.RenderAnnotation.prototype.getLine = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderAnnotation.Line, 6); }), (proto.mediapipe.RenderAnnotation.prototype.setLine = function(e) { return t.Message.setOneofWrapperField( this, 6, proto.mediapipe.RenderAnnotation.oneofGroups_[0], e ); }), (proto.mediapipe.RenderAnnotation.prototype.clearLine = function() { return this.setLine(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasLine = function() { return null != t.Message.getField(this, 6); }), (proto.mediapipe.RenderAnnotation.prototype.getArrow = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderAnnotation.Arrow, 7); }), (proto.mediapipe.RenderAnnotation.prototype.setArrow = function(e) { return t.Message.setOneofWrapperField( this, 7, proto.mediapipe.RenderAnnotation.oneofGroups_[0], e ); }), (proto.mediapipe.RenderAnnotation.prototype.clearArrow = function() { return this.setArrow(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasArrow = function() { return null != t.Message.getField(this, 7); }), (proto.mediapipe.RenderAnnotation.prototype.getText = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderAnnotation.Text, 8); }), (proto.mediapipe.RenderAnnotation.prototype.setText = function(e) { return t.Message.setOneofWrapperField( this, 8, proto.mediapipe.RenderAnnotation.oneofGroups_[0], e ); }), (proto.mediapipe.RenderAnnotation.prototype.clearText = function() { return this.setText(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasText = function() { return null != t.Message.getField(this, 8); }), (proto.mediapipe.RenderAnnotation.prototype.getRoundedRectangle = function() { return t.Message.getWrapperField( this, proto.mediapipe.RenderAnnotation.RoundedRectangle, 9 ); }), (proto.mediapipe.RenderAnnotation.prototype.setRoundedRectangle = function(e) { return t.Message.setOneofWrapperField( this, 9, proto.mediapipe.RenderAnnotation.oneofGroups_[0], e ); }), (proto.mediapipe.RenderAnnotation.prototype.clearRoundedRectangle = function() { return this.setRoundedRectangle(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasRoundedRectangle = function() { return null != t.Message.getField(this, 9); }), (proto.mediapipe.RenderAnnotation.prototype.getFilledRoundedRectangle = function() { return t.Message.getWrapperField( this, proto.mediapipe.RenderAnnotation.FilledRoundedRectangle, 10 ); }), (proto.mediapipe.RenderAnnotation.prototype.setFilledRoundedRectangle = function(e) { return t.Message.setOneofWrapperField( this, 10, proto.mediapipe.RenderAnnotation.oneofGroups_[0], e ); }), (proto.mediapipe.RenderAnnotation.prototype.clearFilledRoundedRectangle = function() { return this.setFilledRoundedRectangle(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasFilledRoundedRectangle = function() { return null != t.Message.getField(this, 10); }), (proto.mediapipe.RenderAnnotation.prototype.getGradientLine = function() { return t.Message.getWrapperField( this, proto.mediapipe.RenderAnnotation.GradientLine, 14 ); }), (proto.mediapipe.RenderAnnotation.prototype.setGradientLine = function(e) { return t.Message.setOneofWrapperField( this, 14, proto.mediapipe.RenderAnnotation.oneofGroups_[0], e ); }), (proto.mediapipe.RenderAnnotation.prototype.clearGradientLine = function() { return this.setGradientLine(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasGradientLine = function() { return null != t.Message.getField(this, 14); }), (proto.mediapipe.RenderAnnotation.prototype.getScribble = function() { return t.Message.getWrapperField(this, proto.mediapipe.RenderAnnotation.Scribble, 15); }), (proto.mediapipe.RenderAnnotation.prototype.setScribble = function(e) { return t.Message.setOneofWrapperField( this, 15, proto.mediapipe.RenderAnnotation.oneofGroups_[0], e ); }), (proto.mediapipe.RenderAnnotation.prototype.clearScribble = function() { return this.setScribble(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasScribble = function() { return null != t.Message.getField(this, 15); }), (proto.mediapipe.RenderAnnotation.prototype.getThickness = function() { return t.Message.getFloatingPointFieldWithDefault(this, 11, 1); }), (proto.mediapipe.RenderAnnotation.prototype.setThickness = function(e) { return t.Message.setField(this, 11, e); }), (proto.mediapipe.RenderAnnotation.prototype.clearThickness = function() { return t.Message.setField(this, 11, void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasThickness = function() { return null != t.Message.getField(this, 11); }), (proto.mediapipe.RenderAnnotation.prototype.getColor = function() { return t.Message.getWrapperField(this, i.Color, 12); }), (proto.mediapipe.RenderAnnotation.prototype.setColor = function(e) { return t.Message.setWrapperField(this, 12, e); }), (proto.mediapipe.RenderAnnotation.prototype.clearColor = function() { return this.setColor(void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasColor = function() { return null != t.Message.getField(this, 12); }), (proto.mediapipe.RenderAnnotation.prototype.getSceneTag = function() { return t.Message.getFieldWithDefault(this, 13, ''); }), (proto.mediapipe.RenderAnnotation.prototype.setSceneTag = function(e) { return t.Message.setField(this, 13, e); }), (proto.mediapipe.RenderAnnotation.prototype.clearSceneTag = function() { return t.Message.setField(this, 13, void 0); }), (proto.mediapipe.RenderAnnotation.prototype.hasSceneTag = function() { return null != t.Message.getField(this, 13); }), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.RenderViewport.prototype.toObject = function(e) { return proto.mediapipe.RenderViewport.toObject(e, this); }), (proto.mediapipe.RenderViewport.toObject = function(e, r) { var o, i = { id: null == (o = t.Message.getField(r, 1)) ? void 0 : o, widthPx: null == (o = t.Message.getField(r, 2)) ? void 0 : o, heightPx: null == (o = t.Message.getField(r, 3)) ? void 0 : o, composeOnVideo: null == (o = t.Message.getBooleanField(r, 4)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.RenderViewport.deserializeBinary = function(e) { var r = new t.BinaryReader(e), o = new proto.mediapipe.RenderViewport(); return proto.mediapipe.RenderViewport.deserializeBinaryFromReader(o, r); }), (proto.mediapipe.RenderViewport.deserializeBinaryFromReader = function(e, t) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = t.readString(); e.setId(r); break; case 2: r = t.readInt32(); e.setWidthPx(r); break; case 3: r = t.readInt32(); e.setHeightPx(r); break; case 4: r = t.readBool(); e.setComposeOnVideo(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.RenderViewport.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.RenderViewport.serializeBinaryToWriter(this, e), e.getResultBuffer() ); }), (proto.mediapipe.RenderViewport.serializeBinaryToWriter = function(e, r) { var o = void 0; null != (o = t.Message.getField(e, 1)) && r.writeString(1, o), null != (o = t.Message.getField(e, 2)) && r.writeInt32(2, o), null != (o = t.Message.getField(e, 3)) && r.writeInt32(3, o), null != (o = t.Message.getField(e, 4)) && r.writeBool(4, o); }), (proto.mediapipe.RenderViewport.prototype.getId = function() { return t.Message.getFieldWithDefault(this, 1, ''); }), (proto.mediapipe.RenderViewport.prototype.setId = function(e) { return t.Message.setField(this, 1, e); }), (proto.mediapipe.RenderViewport.prototype.clearId = function() { return t.Message.setField(this, 1, void 0); }), (proto.mediapipe.RenderViewport.prototype.hasId = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.RenderViewport.prototype.getWidthPx = function() { return t.Message.getFieldWithDefault(this, 2, 0); }), (proto.mediapipe.RenderViewport.prototype.setWidthPx = function(e) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.RenderViewport.prototype.clearWidthPx = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.RenderViewport.prototype.hasWidthPx = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.RenderViewport.prototype.getHeightPx = function() { return t.Message.getFieldWithDefault(this, 3, 0); }), (proto.mediapipe.RenderViewport.prototype.setHeightPx = function(e) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.RenderViewport.prototype.clearHeightPx = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.RenderViewport.prototype.hasHeightPx = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.RenderViewport.prototype.getComposeOnVideo = function() { return t.Message.getBooleanFieldWithDefault(this, 4, !1); }), (proto.mediapipe.RenderViewport.prototype.setComposeOnVideo = function(e) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.RenderViewport.prototype.clearComposeOnVideo = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.RenderViewport.prototype.hasComposeOnVideo = function() { return null != t.Message.getField(this, 4); }), r.object.extend(e, proto.mediapipe); })(render_data_pb); var interactive_segmenter_result = {}; Object.defineProperty(interactive_segmenter_result, '__esModule', { value: !0 }), (interactive_segmenter_result.InteractiveSegmenterResult = void 0); class InteractiveSegmenterResult { constructor(e, t, r) { (this.confidenceMasks = e), (this.categoryMask = t), (this.qualityScores = r); } close() { var e, t; null === (e = this.confidenceMasks) || void 0 === e || e.forEach((e) => { e.close(); }), null === (t = this.categoryMask) || void 0 === t || t.close(); } } interactive_segmenter_result.InteractiveSegmenterResult = InteractiveSegmenterResult; var interactive_segmenter_options = {}; Object.defineProperty(interactive_segmenter_options, '__esModule', { value: !0 }), (function(e) { var t = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? function(e, t, r, o) { void 0 === o && (o = r); var i = Object.getOwnPropertyDescriptor(t, r); (i && !('get' in i ? !t.__esModule : i.writable || i.configurable)) || (i = { enumerable: !0, get: function() { return t[r]; }, }), Object.defineProperty(e, o, i); } : function(e, t, r, o) { void 0 === o && (o = r), (e[o] = t[r]); }), r = (commonjsGlobal && commonjsGlobal.__exportStar) || function(e, r) { for (var o in e) 'default' === o || Object.prototype.hasOwnProperty.call(r, o) || t(r, e, o); }; Object.defineProperty(e, '__esModule', { value: !0 }), (e.InteractiveSegmenter = void 0); const o = calculator_pb, i = calculator_options_pb, a = base_options_pb, n = image_segmenter_graph_options_pb, s = segmenter_options_pb, p = vision_task_runner, d = color_pb, l = render_data_pb, g = interactive_segmenter_result; r(interactive_segmenter_options, e), r(interactive_segmenter_result, e); const c = 'image_in', u = 'norm_rect_in', m = 'roi_in', f = 'confidence_masks', h = 'category_mask', y = 'quality_scores'; class b extends p.VisionTaskRunner { static createFromOptions(e, t) { return p.VisionTaskRunner.createVisionInstance(b, e, t); } static createFromModelBuffer(e, t) { return p.VisionTaskRunner.createVisionInstance(b, e, { baseOptions: { modelAssetBuffer: t }, }); } static createFromModelPath(e, t) { return p.VisionTaskRunner.createVisionInstance(b, e, { baseOptions: { modelAssetPath: t }, }); } constructor(e, t) { super(new p.VisionGraphRunner(e, t), c, u, !1), (this.outputCategoryMask = false), (this.outputConfidenceMasks = true), (this.options = new n.ImageSegmenterGraphOptions()), (this.segmenterOptions = new s.SegmenterOptions()), this.options.setSegmenterOptions(this.segmenterOptions), this.options.setBaseOptions(new a.BaseOptions()); } get baseOptions() { return this.options.getBaseOptions(); } set baseOptions(e) { this.options.setBaseOptions(e); } setOptions(e) { var t, r; return ( 'outputCategoryMask' in e && (this.outputCategoryMask = null !== (t = e.outputCategoryMask) && void 0 !== t && t), 'outputConfidenceMasks' in e && (this.outputConfidenceMasks = null === (r = e.outputConfidenceMasks) || void 0 === r || r), super.applyOptions(e) ); } segment(e, t, r, o) { const i = 'function' != typeof r ? r : {}; return ( (this.userCallback = 'function' == typeof r ? r : o), this.reset(), this.processRenderData(t, this.getSynctheticTimestamp()), this.processImageData(e, i), this.processResults() ); } reset() { (this.confidenceMasks = void 0), (this.categoryMask = void 0), (this.qualityScores = void 0); } processResults() { try { const e = new g.InteractiveSegmenterResult( this.confidenceMasks, this.categoryMask, this.qualityScores ); if (!this.userCallback) return e; this.userCallback(e); } finally { this.freeKeepaliveStreams(); } } refreshGraph() { const e = new o.CalculatorGraphConfig(); e.addInputStream(c), e.addInputStream(m), e.addInputStream(u); const t = new i.CalculatorOptions(); t.setExtension(n.ImageSegmenterGraphOptions.ext, this.options); const r = new o.CalculatorGraphConfig.Node(); r.setCalculator( 'mediapipe.tasks.vision.interactive_segmenter.InteractiveSegmenterGraph' ), r.addInputStream('IMAGE:' + c), r.addInputStream('ROI:' + m), r.addInputStream('NORM_RECT:' + u), r.setOptions(t), e.addNode(r), this.addKeepaliveNode(e), this.outputConfidenceMasks && (e.addOutputStream(f), r.addOutputStream('CONFIDENCE_MASKS:' + f), this.keepStreamAlive(f), this.graphRunner.attachImageVectorListener(f, (e, t) => { (this.confidenceMasks = e.map((e) => this.convertToMPMask(e, !this.userCallback) )), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(f, (e) => { (this.confidenceMasks = []), this.setLatestOutputTimestamp(e); })), this.outputCategoryMask && (e.addOutputStream(h), r.addOutputStream('CATEGORY_MASK:' + h), this.keepStreamAlive(h), this.graphRunner.attachImageListener(h, (e, t) => { (this.categoryMask = this.convertToMPMask(e, !this.userCallback)), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(h, (e) => { (this.categoryMask = void 0), this.setLatestOutputTimestamp(e); })), e.addOutputStream(y), r.addOutputStream('QUALITY_SCORES:' + y), this.graphRunner.attachFloatVectorListener(y, (e, t) => { (this.qualityScores = e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(y, (e) => { (this.categoryMask = void 0), this.setLatestOutputTimestamp(e); }); const a = e.serializeBinary(); this.setGraph(new Uint8Array(a), !0); } processRenderData(e, t) { const r = new l.RenderData(), o = new l.RenderAnnotation(), i = new d.Color(); if ((i.setR(255), o.setColor(i), e.keypoint && e.scribble)) throw new Error('Cannot provide both keypoint and scribble.'); if (e.keypoint) { const t = new l.RenderAnnotation.Point(); t.setNormalized(!0), t.setX(e.keypoint.x), t.setY(e.keypoint.y), o.setPoint(t); } else { if (!e.scribble) throw new Error('Must provide either a keypoint or a scribble.'); { const t = new l.RenderAnnotation.Scribble(); for (const r of e.scribble) { const e = new l.RenderAnnotation.Point(); e.setNormalized(!0), e.setX(r.x), e.setY(r.y), t.addPoint(e); } o.setScribble(t); } } r.addRenderAnnotations(o), this.graphRunner.addProtoToStream( r.serializeBinary(), 'drishti.RenderData', m, t ); } } e.InteractiveSegmenter = b; })(interactive_segmenter); var object_detector = {}, object_detector_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n), r.exportSymbol( 'proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions', null, o ), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions = function(e) { t.Message.initialize( this, e, 0, -1, proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions .repeatedFields_, null ); }), r.inherits( proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.displayName = 'proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions'), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.repeatedFields_ = [ 5, 6, ]), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.toObject = function( e, r ) { var o, i = { baseOptions: (o = r.getBaseOptions()) && n.BaseOptions.toObject(e, o), displayNamesLocale: t.Message.getFieldWithDefault(r, 2, 'en'), maxResults: t.Message.getFieldWithDefault(r, 3, -1), scoreThreshold: null == (o = t.Message.getOptionalFloatingPointField(r, 4)) ? void 0 : o, categoryAllowlistList: null == (o = t.Message.getRepeatedField(r, 5)) ? void 0 : o, categoryDenylistList: null == (o = t.Message.getRepeatedField(r, 6)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions(); return proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = t.readString(); e.setDisplayNamesLocale(r); break; case 3: r = t.readInt32(); e.setMaxResults(r); break; case 4: r = t.readFloat(); e.setScoreThreshold(r); break; case 5: r = t.readString(); e.addCategoryAllowlist(r); break; case 6: r = t.readString(); e.addCategoryDenylist(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getBaseOptions()) && r.writeMessage(1, o, n.BaseOptions.serializeBinaryToWriter), null != (o = t.Message.getField(e, 2)) && r.writeString(2, o), null != (o = t.Message.getField(e, 3)) && r.writeInt32(3, o), null != (o = t.Message.getField(e, 4)) && r.writeFloat(4, o), (o = e.getCategoryAllowlistList()).length > 0 && r.writeRepeatedString(5, o), (o = e.getCategoryDenylistList()).length > 0 && r.writeRepeatedString(6, o); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.ext = new t.ExtensionFieldInfo( 443442058, { ext: 0 }, proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions, proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[443442058] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[443442058] = proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.ext), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.getDisplayNamesLocale = function() { return t.Message.getFieldWithDefault(this, 2, 'en'); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.setDisplayNamesLocale = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.clearDisplayNamesLocale = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.hasDisplayNamesLocale = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.getMaxResults = function() { return t.Message.getFieldWithDefault(this, 3, -1); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.setMaxResults = function( e ) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.clearMaxResults = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.hasMaxResults = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.getScoreThreshold = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.setScoreThreshold = function( e ) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.clearScoreThreshold = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.hasScoreThreshold = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.getCategoryAllowlistList = function() { return t.Message.getRepeatedField(this, 5); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.setCategoryAllowlistList = function( e ) { return t.Message.setField(this, 5, e || []); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.addCategoryAllowlist = function( e, r ) { return t.Message.addToRepeatedField(this, 5, e, r); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.clearCategoryAllowlistList = function() { return this.setCategoryAllowlistList([]); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.getCategoryDenylistList = function() { return t.Message.getRepeatedField(this, 6); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.setCategoryDenylistList = function( e ) { return t.Message.setField(this, 6, e || []); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.addCategoryDenylist = function( e, r ) { return t.Message.addToRepeatedField(this, 6, e, r); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.prototype.clearCategoryDenylistList = function() { return this.setCategoryDenylistList([]); }), (proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.ext = new t.ExtensionFieldInfo( 443442058, { ext: 0 }, proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions, proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[443442058] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[443442058] = proto.mediapipe.tasks.vision.object_detector.proto.ObjectDetectorOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.object_detector.proto); })(object_detector_options_pb); var object_detector_options = {}; Object.defineProperty(object_detector_options, '__esModule', { value: !0 }); var object_detector_result = {}; Object.defineProperty(object_detector_result, '__esModule', { value: !0 }), (function(e) { var t = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? function(e, t, r, o) { void 0 === o && (o = r); var i = Object.getOwnPropertyDescriptor(t, r); (i && !('get' in i ? !t.__esModule : i.writable || i.configurable)) || (i = { enumerable: !0, get: function() { return t[r]; }, }), Object.defineProperty(e, o, i); } : function(e, t, r, o) { void 0 === o && (o = r), (e[o] = t[r]); }), r = (commonjsGlobal && commonjsGlobal.__exportStar) || function(e, r) { for (var o in e) 'default' === o || Object.prototype.hasOwnProperty.call(r, o) || t(r, e, o); }; Object.defineProperty(e, '__esModule', { value: !0 }), (e.ObjectDetector = void 0); const o = calculator_pb, i = calculator_options_pb, a = detection_pb, n = base_options_pb, s = object_detector_options_pb, p = detection_result, d = vision_task_runner, l = 'input_frame_gpu', g = 'norm_rect', c = 'detections'; r(object_detector_options, e), r(object_detector_result, e); class u extends d.VisionTaskRunner { static createFromOptions(e, t) { return d.VisionTaskRunner.createVisionInstance(u, e, t); } static createFromModelBuffer(e, t) { return d.VisionTaskRunner.createVisionInstance(u, e, { baseOptions: { modelAssetBuffer: t }, }); } static async createFromModelPath(e, t) { return d.VisionTaskRunner.createVisionInstance(u, e, { baseOptions: { modelAssetPath: t }, }); } constructor(e, t) { super(new d.VisionGraphRunner(e, t), l, g, !1), (this.result = { detections: [] }), (this.options = new s.ObjectDetectorOptions()), this.options.setBaseOptions(new n.BaseOptions()); } get baseOptions() { return this.options.getBaseOptions(); } set baseOptions(e) { this.options.setBaseOptions(e); } setOptions(e) { return ( void 0 !== e.displayNamesLocale ? this.options.setDisplayNamesLocale(e.displayNamesLocale) : 'displayNamesLocale' in e && this.options.clearDisplayNamesLocale(), void 0 !== e.maxResults ? this.options.setMaxResults(e.maxResults) : 'maxResults' in e && this.options.clearMaxResults(), void 0 !== e.scoreThreshold ? this.options.setScoreThreshold(e.scoreThreshold) : 'scoreThreshold' in e && this.options.clearScoreThreshold(), void 0 !== e.categoryAllowlist ? this.options.setCategoryAllowlistList(e.categoryAllowlist) : 'categoryAllowlist' in e && this.options.clearCategoryAllowlistList(), void 0 !== e.categoryDenylist ? this.options.setCategoryDenylistList(e.categoryDenylist) : 'categoryDenylist' in e && this.options.clearCategoryDenylistList(), this.applyOptions(e) ); } detect(e, t) { return (this.result = { detections: [] }), this.processImageData(e, t), this.result; } detectForVideo(e, t, r) { return ( (this.result = { detections: [] }), this.processVideoData(e, r, t), this.result ); } addJsObjectDetections(e) { for (const t of e) { const e = a.Detection.deserializeBinary(t); this.result.detections.push((0, p.convertFromDetectionProto)(e)); } } refreshGraph() { const e = new o.CalculatorGraphConfig(); e.addInputStream(l), e.addInputStream(g), e.addOutputStream(c); const t = new i.CalculatorOptions(); t.setExtension(s.ObjectDetectorOptions.ext, this.options); const r = new o.CalculatorGraphConfig.Node(); r.setCalculator('mediapipe.tasks.vision.ObjectDetectorGraph'), r.addInputStream('IMAGE:' + l), r.addInputStream('NORM_RECT:' + g), r.addOutputStream('DETECTIONS:' + c), r.setOptions(t), e.addNode(r), this.graphRunner.attachProtoVectorListener(c, (e, t) => { this.addJsObjectDetections(e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(c, (e) => { this.setLatestOutputTimestamp(e); }); const a = e.serializeBinary(); this.setGraph(new Uint8Array(a), !0); } } e.ObjectDetector = u; })(object_detector); var pose_landmarker = {}, pose_detector_graph_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n), r.exportSymbol( 'proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions', null, o ), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions = function(e) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.displayName = 'proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.toObject = function( e, r ) { var o, i = { baseOptions: (o = r.getBaseOptions()) && n.BaseOptions.toObject(e, o), minDetectionConfidence: t.Message.getFloatingPointFieldWithDefault( r, 2, 0.5 ), minSuppressionThreshold: t.Message.getFloatingPointFieldWithDefault( r, 3, 0.5 ), numPoses: null == (o = t.Message.getField(r, 4)) ? void 0 : o, }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions(); return proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = t.readFloat(); e.setMinDetectionConfidence(r); break; case 3: r = t.readFloat(); e.setMinSuppressionThreshold(r); break; case 4: r = t.readInt32(); e.setNumPoses(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getBaseOptions()) && r.writeMessage(1, o, n.BaseOptions.serializeBinaryToWriter), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o), null != (o = t.Message.getField(e, 3)) && r.writeFloat(3, o), null != (o = t.Message.getField(e, 4)) && r.writeInt32(4, o); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.ext = new t.ExtensionFieldInfo( 514774813, { ext: 0 }, proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions, proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[514774813] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[514774813] = proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.ext), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.getMinDetectionConfidence = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0.5); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.setMinDetectionConfidence = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.clearMinDetectionConfidence = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.hasMinDetectionConfidence = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.getMinSuppressionThreshold = function() { return t.Message.getFloatingPointFieldWithDefault(this, 3, 0.5); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.setMinSuppressionThreshold = function( e ) { return t.Message.setField(this, 3, e); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.clearMinSuppressionThreshold = function() { return t.Message.setField(this, 3, void 0); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.hasMinSuppressionThreshold = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.getNumPoses = function() { return t.Message.getFieldWithDefault(this, 4, 0); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.setNumPoses = function( e ) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.clearNumPoses = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.prototype.hasNumPoses = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.ext = new t.ExtensionFieldInfo( 514774813, { ext: 0 }, proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions, proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[514774813] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[514774813] = proto.mediapipe.tasks.vision.pose_detector.proto.PoseDetectorGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.pose_detector.proto); })(pose_detector_graph_options_pb); var pose_landmarker_graph_options_pb = {}, pose_landmarks_detector_graph_options_pb = {}; !(function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n), r.exportSymbol( 'proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions', null, o ), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.displayName = 'proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.toObject = function( e, r ) { var o, i = { baseOptions: (o = r.getBaseOptions()) && n.BaseOptions.toObject(e, o), minDetectionConfidence: t.Message.getFloatingPointFieldWithDefault( r, 2, 0.5 ), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions(); return proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = t.readFloat(); e.setMinDetectionConfidence(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getBaseOptions()) && r.writeMessage(1, o, n.BaseOptions.serializeBinaryToWriter), null != (o = t.Message.getField(e, 2)) && r.writeFloat(2, o); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.ext = new t.ExtensionFieldInfo( 518928384, { ext: 0 }, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[518928384] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[518928384] = proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.ext), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.prototype.getMinDetectionConfidence = function() { return t.Message.getFloatingPointFieldWithDefault(this, 2, 0.5); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.prototype.setMinDetectionConfidence = function( e ) { return t.Message.setField(this, 2, e); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.prototype.clearMinDetectionConfidence = function() { return t.Message.setField(this, 2, void 0); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.prototype.hasMinDetectionConfidence = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.ext = new t.ExtensionFieldInfo( 518928384, { ext: 0 }, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[518928384] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[518928384] = proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarksDetectorGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.pose_landmarker.proto); })(pose_landmarks_detector_graph_options_pb), (function(e) { var t = googleProtobuf, r = t, o = ('undefined' != typeof globalThis && globalThis) || ('undefined' != typeof window && window) || (void 0 !== o && o) || ('undefined' != typeof self && self) || function() { return this; }.call(null) || Function('return this')(), i = calculator_pb; r.object.extend(proto, i); var a = calculator_options_pb; r.object.extend(proto, a); var n = base_options_pb; r.object.extend(proto, n); var s = pose_detector_graph_options_pb; r.object.extend(proto, s); var p = pose_landmarks_detector_graph_options_pb; r.object.extend(proto, p), r.exportSymbol( 'proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions', null, o ), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions = function( e ) { t.Message.initialize(this, e, 0, -1, null, null); }), r.inherits( proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions, t.Message ), r.DEBUG && !COMPILED && (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.displayName = 'proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions'), t.Message.GENERATE_TO_OBJECT && ((proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.toObject = function( e ) { return proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.toObject( e, this ); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.toObject = function( e, r ) { var o, i = { baseOptions: (o = r.getBaseOptions()) && n.BaseOptions.toObject(e, o), poseDetectorGraphOptions: (o = r.getPoseDetectorGraphOptions()) && s.PoseDetectorGraphOptions.toObject(e, o), poseLandmarksDetectorGraphOptions: (o = r.getPoseLandmarksDetectorGraphOptions()) && p.PoseLandmarksDetectorGraphOptions.toObject(e, o), minTrackingConfidence: t.Message.getFloatingPointFieldWithDefault( r, 4, 0.5 ), }; return e && (i.$jspbMessageInstance = r), i; })), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.deserializeBinary = function( e ) { var r = new t.BinaryReader(e), o = new proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions(); return proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.deserializeBinaryFromReader( o, r ); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.deserializeBinaryFromReader = function( e, t ) { for (; t.nextField() && !t.isEndGroup(); ) { switch (t.getFieldNumber()) { case 1: var r = new n.BaseOptions(); t.readMessage(r, n.BaseOptions.deserializeBinaryFromReader), e.setBaseOptions(r); break; case 2: r = new s.PoseDetectorGraphOptions(); t.readMessage( r, s.PoseDetectorGraphOptions.deserializeBinaryFromReader ), e.setPoseDetectorGraphOptions(r); break; case 3: r = new p.PoseLandmarksDetectorGraphOptions(); t.readMessage( r, p.PoseLandmarksDetectorGraphOptions.deserializeBinaryFromReader ), e.setPoseLandmarksDetectorGraphOptions(r); break; case 4: r = t.readFloat(); e.setMinTrackingConfidence(r); break; default: t.skipField(); } } return e; }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.serializeBinary = function() { var e = new t.BinaryWriter(); return ( proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.serializeBinaryToWriter( this, e ), e.getResultBuffer() ); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.serializeBinaryToWriter = function( e, r ) { var o = void 0; null != (o = e.getBaseOptions()) && r.writeMessage(1, o, n.BaseOptions.serializeBinaryToWriter), null != (o = e.getPoseDetectorGraphOptions()) && r.writeMessage(2, o, s.PoseDetectorGraphOptions.serializeBinaryToWriter), null != (o = e.getPoseLandmarksDetectorGraphOptions()) && r.writeMessage( 3, o, p.PoseLandmarksDetectorGraphOptions.serializeBinaryToWriter ), null != (o = t.Message.getField(e, 4)) && r.writeFloat(4, o); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.ext = new t.ExtensionFieldInfo( 516587230, { ext: 0 }, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[516587230] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[516587230] = proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.ext), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.getBaseOptions = function() { return t.Message.getWrapperField(this, n.BaseOptions, 1); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.setBaseOptions = function( e ) { return t.Message.setWrapperField(this, 1, e); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.clearBaseOptions = function() { return this.setBaseOptions(void 0); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.hasBaseOptions = function() { return null != t.Message.getField(this, 1); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.getPoseDetectorGraphOptions = function() { return t.Message.getWrapperField(this, s.PoseDetectorGraphOptions, 2); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.setPoseDetectorGraphOptions = function( e ) { return t.Message.setWrapperField(this, 2, e); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.clearPoseDetectorGraphOptions = function() { return this.setPoseDetectorGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.hasPoseDetectorGraphOptions = function() { return null != t.Message.getField(this, 2); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.getPoseLandmarksDetectorGraphOptions = function() { return t.Message.getWrapperField(this, p.PoseLandmarksDetectorGraphOptions, 3); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.setPoseLandmarksDetectorGraphOptions = function( e ) { return t.Message.setWrapperField(this, 3, e); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.clearPoseLandmarksDetectorGraphOptions = function() { return this.setPoseLandmarksDetectorGraphOptions(void 0); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.hasPoseLandmarksDetectorGraphOptions = function() { return null != t.Message.getField(this, 3); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.getMinTrackingConfidence = function() { return t.Message.getFloatingPointFieldWithDefault(this, 4, 0.5); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.setMinTrackingConfidence = function( e ) { return t.Message.setField(this, 4, e); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.clearMinTrackingConfidence = function() { return t.Message.setField(this, 4, void 0); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.prototype.hasMinTrackingConfidence = function() { return null != t.Message.getField(this, 4); }), (proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.ext = new t.ExtensionFieldInfo( 516587230, { ext: 0 }, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.toObject, 0 )), (a.CalculatorOptions.extensionsBinary[516587230] = new t.ExtensionFieldBinaryInfo( proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.ext, t.BinaryReader.prototype.readMessage, t.BinaryWriter.prototype.writeMessage, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.serializeBinaryToWriter, proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.deserializeBinaryFromReader, !1 )), (a.CalculatorOptions.extensions[516587230] = proto.mediapipe.tasks.vision.pose_landmarker.proto.PoseLandmarkerGraphOptions.ext), r.object.extend(e, proto.mediapipe.tasks.vision.pose_landmarker.proto); })(pose_landmarker_graph_options_pb); var pose_landmarker_result = {}; Object.defineProperty(pose_landmarker_result, '__esModule', { value: !0 }), (pose_landmarker_result.PoseLandmarkerResult = void 0); class PoseLandmarkerResult { constructor(e, t, r) { (this.landmarks = e), (this.worldLandmarks = t), (this.segmentationMasks = r); } close() { var e; null === (e = this.segmentationMasks) || void 0 === e || e.forEach((e) => { e.close(); }); } } pose_landmarker_result.PoseLandmarkerResult = PoseLandmarkerResult; var pose_landmarker_options = {}; Object.defineProperty(pose_landmarker_options, '__esModule', { value: !0 }), (function(e) { var t = (commonjsGlobal && commonjsGlobal.__createBinding) || (Object.create ? function(e, t, r, o) { void 0 === o && (o = r); var i = Object.getOwnPropertyDescriptor(t, r); (i && !('get' in i ? !t.__esModule : i.writable || i.configurable)) || (i = { enumerable: !0, get: function() { return t[r]; }, }), Object.defineProperty(e, o, i); } : function(e, t, r, o) { void 0 === o && (o = r), (e[o] = t[r]); }), r = (commonjsGlobal && commonjsGlobal.__exportStar) || function(e, r) { for (var o in e) 'default' === o || Object.prototype.hasOwnProperty.call(r, o) || t(r, e, o); }; Object.defineProperty(e, '__esModule', { value: !0 }), (e.PoseLandmarker = void 0); const o = calculator_pb, i = calculator_options_pb, a = landmark_pb, n = base_options_pb, s = pose_detector_graph_options_pb, p = pose_landmarker_graph_options_pb, d = pose_landmarks_detector_graph_options_pb, l = landmark_result, g = vision_task_runner, c = pose_landmarker_result; r(pose_landmarker_options, e), r(pose_landmarker_result, e); const u = 'image_in', m = 'norm_rect', f = 'normalized_landmarks', h = 'world_landmarks', y = 'segmentation_masks', b = 0.5; class _ extends g.VisionTaskRunner { static createFromOptions(e, t) { return g.VisionTaskRunner.createVisionInstance(_, e, t); } static createFromModelBuffer(e, t) { return g.VisionTaskRunner.createVisionInstance(_, e, { baseOptions: { modelAssetBuffer: t }, }); } static createFromModelPath(e, t) { return g.VisionTaskRunner.createVisionInstance(_, e, { baseOptions: { modelAssetPath: t }, }); } constructor(e, t) { super(new g.VisionGraphRunner(e, t), u, m, !1), (this.landmarks = []), (this.worldLandmarks = []), (this.outputSegmentationMasks = !1), (this.options = new p.PoseLandmarkerGraphOptions()), this.options.setBaseOptions(new n.BaseOptions()), (this.poseLandmarksDetectorGraphOptions = new d.PoseLandmarksDetectorGraphOptions()), this.options.setPoseLandmarksDetectorGraphOptions( this.poseLandmarksDetectorGraphOptions ), (this.poseDetectorGraphOptions = new s.PoseDetectorGraphOptions()), this.options.setPoseDetectorGraphOptions(this.poseDetectorGraphOptions), this.initDefaults(); } get baseOptions() { return this.options.getBaseOptions(); } set baseOptions(e) { this.options.setBaseOptions(e); } setOptions(e) { var t, r, o, i, a; return ( 'numPoses' in e && this.poseDetectorGraphOptions.setNumPoses( null !== (t = e.numPoses) && void 0 !== t ? t : 1 ), 'minPoseDetectionConfidence' in e && this.poseDetectorGraphOptions.setMinDetectionConfidence( null !== (r = e.minPoseDetectionConfidence) && void 0 !== r ? r : b ), 'minTrackingConfidence' in e && this.options.setMinTrackingConfidence( null !== (o = e.minTrackingConfidence) && void 0 !== o ? o : b ), 'minPosePresenceConfidence' in e && this.poseLandmarksDetectorGraphOptions.setMinDetectionConfidence( null !== (i = e.minPosePresenceConfidence) && void 0 !== i ? i : b ), 'outputSegmentationMasks' in e && (this.outputSegmentationMasks = null !== (a = e.outputSegmentationMasks) && void 0 !== a && a), this.applyOptions(e) ); } detect(e, t, r) { const o = 'function' != typeof t ? t : {}; return ( (this.userCallback = 'function' == typeof t ? t : r), this.resetResults(), this.processImageData(e, o), this.processResults() ); } detectForVideo(e, t, r, o) { const i = 'function' != typeof r ? r : {}; return ( (this.userCallback = 'function' == typeof r ? r : o), this.resetResults(), this.processVideoData(e, i, t), this.processResults() ); } resetResults() { (this.landmarks = []), (this.worldLandmarks = []), (this.segmentationMasks = void 0); } processResults() { try { const e = new c.PoseLandmarkerResult( this.landmarks, this.worldLandmarks, this.segmentationMasks ); if (!this.userCallback) return e; this.userCallback(e); } finally { this.freeKeepaliveStreams(); } } initDefaults() { this.poseDetectorGraphOptions.setNumPoses(1), this.poseDetectorGraphOptions.setMinDetectionConfidence(b), this.poseLandmarksDetectorGraphOptions.setMinDetectionConfidence(b), this.options.setMinTrackingConfidence(b); } addJsLandmarks(e) { this.landmarks = []; for (const t of e) { const e = a.NormalizedLandmarkList.deserializeBinary(t); this.landmarks.push((0, l.convertToLandmarks)(e)); } } adddJsWorldLandmarks(e) { this.worldLandmarks = []; for (const t of e) { const e = a.LandmarkList.deserializeBinary(t); this.worldLandmarks.push((0, l.convertToWorldLandmarks)(e)); } } refreshGraph() { const e = new o.CalculatorGraphConfig(); e.addInputStream(u), e.addInputStream(m), e.addOutputStream(f), e.addOutputStream(h), e.addOutputStream(y); const t = new i.CalculatorOptions(); t.setExtension(p.PoseLandmarkerGraphOptions.ext, this.options); const r = new o.CalculatorGraphConfig.Node(); r.setCalculator('mediapipe.tasks.vision.pose_landmarker.PoseLandmarkerGraph'), r.addInputStream('IMAGE:' + u), r.addInputStream('NORM_RECT:' + m), r.addOutputStream('NORM_LANDMARKS:' + f), r.addOutputStream('WORLD_LANDMARKS:' + h), r.setOptions(t), e.addNode(r), this.addKeepaliveNode(e), this.graphRunner.attachProtoVectorListener(f, (e, t) => { this.addJsLandmarks(e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(f, (e) => { (this.landmarks = []), this.setLatestOutputTimestamp(e); }), this.graphRunner.attachProtoVectorListener(h, (e, t) => { this.adddJsWorldLandmarks(e), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(h, (e) => { (this.worldLandmarks = []), this.setLatestOutputTimestamp(e); }), this.outputSegmentationMasks && (r.addOutputStream('SEGMENTATION_MASK:' + y), this.keepStreamAlive(y), this.graphRunner.attachImageVectorListener(y, (e, t) => { (this.segmentationMasks = e.map((e) => this.convertToMPMask(e, !this.userCallback) )), this.setLatestOutputTimestamp(t); }), this.graphRunner.attachEmptyPacketListener(y, (e) => { (this.segmentationMasks = []), this.setLatestOutputTimestamp(e); })); const a = e.serializeBinary(); this.setGraph(new Uint8Array(a), !0); } } (e.PoseLandmarker = _), (_.POSE_CONNECTIONS = [ { start: 0, end: 1 }, { start: 1, end: 2 }, { start: 2, end: 3 }, { start: 3, end: 7 }, { start: 0, end: 4 }, { start: 4, end: 5 }, { start: 5, end: 6 }, { start: 6, end: 8 }, { start: 9, end: 10 }, { start: 11, end: 12 }, { start: 11, end: 13 }, { start: 13, end: 15 }, { start: 15, end: 17 }, { start: 15, end: 19 }, { start: 15, end: 21 }, { start: 17, end: 19 }, { start: 12, end: 14 }, { start: 14, end: 16 }, { start: 16, end: 18 }, { start: 16, end: 20 }, { start: 16, end: 22 }, { start: 18, end: 20 }, { start: 11, end: 23 }, { start: 12, end: 24 }, { start: 23, end: 24 }, { start: 23, end: 25 }, { start: 24, end: 26 }, { start: 25, end: 27 }, { start: 26, end: 28 }, { start: 27, end: 29 }, { start: 28, end: 30 }, { start: 29, end: 31 }, { start: 30, end: 32 }, { start: 27, end: 31 }, { start: 28, end: 32 }, ]); })(pose_landmarker), Object.defineProperty(vision, '__esModule', { value: !0 }); var PoseLandmarker_1 = (vision.PoseLandmarker = ObjectDetector_1 = vision.ObjectDetector = InteractiveSegmenter_1 = vision.InteractiveSegmenter = ImageSegmenter_1 = vision.ImageSegmenter = ImageEmbedder_1 = vision.ImageEmbedder = ImageClassifier_1 = vision.ImageClassifier = HandLandmarker_1 = vision.HandLandmarker = GestureRecognizer_1 = vision.GestureRecognizer = FaceStylizer_1 = vision.FaceStylizer = FaceLandmarker_1 = vision.FaceLandmarker = FaceDetector_1 = vision.FaceDetector = MPMask_1 = vision.MPMask = MPImage_1 = vision.MPImage = FilesetResolver_1 = vision.FilesetResolver = DrawingUtils_1 = vision.DrawingUtils = void 0); const fileset_resolver_1 = fileset_resolver, drawing_utils_1 = drawing_utils, image_1 = image, mask_1 = mask, face_detector_1 = face_detector, face_landmarker_1 = face_landmarker, face_stylizer_1 = face_stylizer, gesture_recognizer_1 = gesture_recognizer, hand_landmarker_1 = hand_landmarker, image_classifier_1 = image_classifier, image_embedder_1 = image_embedder, image_segmenter_1 = image_segmenter, interactive_segmenter_1 = interactive_segmenter, object_detector_1 = object_detector, pose_landmarker_1 = pose_landmarker, DrawingUtils = drawing_utils_1.DrawingUtils; var DrawingUtils_1 = (vision.DrawingUtils = DrawingUtils); const FilesetResolver = fileset_resolver_1.FilesetResolver; var FilesetResolver_1 = (vision.FilesetResolver = FilesetResolver); const MPImage = image_1.MPImage; var MPImage_1 = (vision.MPImage = MPImage); const MPMask = mask_1.MPMask; var MPMask_1 = (vision.MPMask = MPMask); const FaceDetector = face_detector_1.FaceDetector; var FaceDetector_1 = (vision.FaceDetector = FaceDetector); const FaceLandmarker = face_landmarker_1.FaceLandmarker; var FaceLandmarker_1 = (vision.FaceLandmarker = FaceLandmarker); const FaceStylizer = face_stylizer_1.FaceStylizer; var FaceStylizer_1 = (vision.FaceStylizer = FaceStylizer); const GestureRecognizer = gesture_recognizer_1.GestureRecognizer; var GestureRecognizer_1 = (vision.GestureRecognizer = GestureRecognizer); const HandLandmarker = hand_landmarker_1.HandLandmarker; var HandLandmarker_1 = (vision.HandLandmarker = HandLandmarker); const ImageClassifier = image_classifier_1.ImageClassifier; var ImageClassifier_1 = (vision.ImageClassifier = ImageClassifier); const ImageEmbedder = image_embedder_1.ImageEmbedder; var ImageEmbedder_1 = (vision.ImageEmbedder = ImageEmbedder); const ImageSegmenter = image_segmenter_1.ImageSegmenter; var ImageSegmenter_1 = (vision.ImageSegmenter = ImageSegmenter); const InteractiveSegmenter = interactive_segmenter_1.InteractiveSegmenter; var InteractiveSegmenter_1 = (vision.InteractiveSegmenter = InteractiveSegmenter); const ObjectDetector = object_detector_1.ObjectDetector; var ObjectDetector_1 = (vision.ObjectDetector = ObjectDetector); const PoseLandmarker = pose_landmarker_1.PoseLandmarker; PoseLandmarker_1 = vision.PoseLandmarker = PoseLandmarker; ================================================ FILE: extern/wasm/vision_wasm_internal.js ================================================ // Build 551939664 var ModuleFactory = (() => { var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; return ( function(ModuleFactory = {}) { var Module=typeof ModuleFactory!="undefined"?ModuleFactory:{};var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");if(ENVIRONMENT_IS_WORKER){scriptDirectory=nodePath.dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)onerror(err);else onload(binary?data.buffer:data)})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow};Module["inspect"]=()=>"[Emscripten Module object]"}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=title=>document.title=title}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||true;if(typeof WebAssembly!="object"){abort("no native wasm support detected")}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeKeepaliveCounter=0;function keepRuntimeAlive(){return noExitRuntime||runtimeKeepaliveCounter>0}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}function isFileURI(filename){return filename.startsWith("file://")}var wasmBinaryFile;wasmBinaryFile="vision_wasm_internal.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(file){try{if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}catch(err){abort(err)}}function getBinaryPromise(binaryFile){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"&&!isFileURI(binaryFile)){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{if(!response["ok"]){throw"failed to load wasm binary file at '"+binaryFile+"'"}return response["arrayBuffer"]()}).catch(()=>getBinary(binaryFile))}else{if(readAsync){return new Promise((resolve,reject)=>{readAsync(binaryFile,response=>resolve(new Uint8Array(response)),reject)})}}}return Promise.resolve().then(()=>getBinary(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>{return WebAssembly.instantiate(binary,imports)}).then(instance=>{return instance}).then(receiver,reason=>{err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}else{return instantiateArrayBuffer(binaryFile,imports,callback)}}function createWasm(){var info={"a":wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;wasmMemory=Module["asm"]["od"];updateMemoryViews();wasmTable=Module["asm"]["qd"];addOnInit(Module["asm"]["pd"]);removeRunDependency("wasm-instantiate");return exports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err("Module.instantiateWasm callback failed with error: "+e);readyPromiseReject(e)}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var tempDouble;var tempI64;var ASM_CONSTS={1188066:$0=>{const canvas=Emval.toValue($0);const context=canvas.getContext("webgpu");return JsValStore.add(context.getCurrentTexture())},1188201:($0,$1,$2,$3,$4)=>{const drawable=Emval.toValue($0);const device=JsValStore.get($1);const texture=JsValStore.get($2);const width=$3;const height=$4;device.queue.copyExternalImageToTexture({source:drawable},{texture:texture},[width,height])},1188452:($0,$1,$2,$3)=>{const sourceExtTex=Emval.toValue($0);const device=JsValStore.get($1);const sampler=JsValStore.get($2);const bgLayout=JsValStore.get($3);const bindGroup=device.createBindGroup({layout:bgLayout,entries:[{binding:0,resource:sampler},{binding:1,resource:sourceExtTex}]});return JsValStore.add(bindGroup)},1188800:($0,$1)=>{const inputArray=Emval.toValue($0);const output=Emval.toValue($1);const ctx=output.getContext("2d");const image_data=new ImageData(inputArray,output.width,output.height);ctx.putImageData(image_data,0,0)},1189024:($0,$1)=>{const input=Emval.toValue($0);const outputArray=Emval.toValue($1);const ctx=input.getContext("2d");const data=ctx.getImageData(0,0,input.width,input.height);outputArray.set(data.data)},1189228:($0,$1)=>{const input=Emval.toValue($0);const output=Emval.toValue($1);const ctx=output.getContext("2d");ctx.drawImage(input,0,0)},1189364:()=>{return typeof HTMLCanvasElement!=="undefined"},1189419:()=>{return!!Module["preinitializedWebGPUDevice"]},1189470:()=>{specialHTMLTargets["#canvas"]=Module.canvas},1189521:()=>{return typeof wasmOffsetConverter!=="undefined"}};function JsWrapImageConverter(){if(!Module._imageConverter){Module._imageConverter=(binaryPtr,binarySize,width,height,numChannels,makeDeepCopy,outputType)=>{const imageData=new outputType(makeDeepCopy?Module.HEAPU8.slice(binaryPtr,binaryPtr+binarySize).buffer:Module.HEAPU8.buffer,binaryPtr,width*height*numChannels);return{data:imageData,width:width,height:height}}}}function JsOnUint8ArrayImageListener(output_stream_name,binary_ptr,binary_size,width,height,num_channels,make_deep_copy,timestamp_ms){const image=Module._imageConverter(binary_ptr,binary_size,width,height,num_channels,make_deep_copy,Uint8Array);Module._wrapSimpleListenerOutput(output_stream_name,image,timestamp_ms)}function JsOnFloat32ArrayImageListener(output_stream_name,binary_ptr,binary_size,width,height,num_channels,make_deep_copy,timestamp_ms){const image=Module._imageConverter(binary_ptr,binary_size,width,height,num_channels,make_deep_copy,Float32Array);Module._wrapSimpleListenerOutput(output_stream_name,image,timestamp_ms)}function JsOnWebGLTextureListener(output_stream_name,name,width,height,timestamp_ms){Module._wrapSimpleListenerOutput(output_stream_name,{data:GL.textures[name],width:width,height:height},timestamp_ms)}function JsOnUint8ArrayImageVectorListener(output_stream_name,binary_ptr,binary_size,width,height,num_channels,make_deep_copy,timestamp_ms){const image=Module._imageConverter(binary_ptr,binary_size,width,height,num_channels,make_deep_copy,Uint8Array);Module._wrapSimpleListenerOutput(output_stream_name,image,false,timestamp_ms)}function JsOnFloat32ArrayImageVectorListener(output_stream_name,binary_ptr,binary_size,width,height,num_channels,make_deep_copy,timestamp_ms){const image=Module._imageConverter(binary_ptr,binary_size,width,height,num_channels,make_deep_copy,Float32Array);Module._wrapSimpleListenerOutput(output_stream_name,image,false,timestamp_ms)}function JsOnWebGLTextureVectorListener(output_stream_name,name,width,height,timestamp_ms){Module._wrapSimpleListenerOutput(output_stream_name,{data:GL.textures[name],width:width,height:height},false,timestamp_ms)}function JsOnEmptyPacketListener(output_stream_name,timestamp){Module._wrapEmptyPacketListenerOutput(output_stream_name,timestamp)}function JsOnVectorFinishedListener(output_stream_name,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,undefined,true,timestamp)}function JsOnSimpleListenerBool(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,timestamp)}function JsOnVectorListenerBool(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,false,timestamp)}function JsOnSimpleListenerInt(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,timestamp)}function JsOnVectorListenerInt(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,false,timestamp)}function JsOnSimpleListenerDouble(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,timestamp)}function JsOnVectorListenerDouble(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,false,timestamp)}function JsOnSimpleListenerFloat(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,timestamp)}function JsOnVectorListenerFloat(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,false,timestamp)}function JsOnSimpleListenerString(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,UTF8ToString(out_data),timestamp)}function JsOnVectorListenerString(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,UTF8ToString(out_data),false,timestamp)}function JsOnVectorListenerProto(output_stream_name,proto_ptr,proto_size,make_deep_copy,timestamp){const newProtoArray=make_deep_copy?Module.HEAPU8.slice(proto_ptr,proto_ptr+proto_size):new Uint8Array(Module.HEAPU8.buffer,proto_ptr,proto_size);Module._wrapSimpleListenerOutput(output_stream_name,newProtoArray,false,timestamp)}function JsWrapSimpleListeners(){if(!Module._wrapSimpleListenerOutput){Module._wrapSimpleListenerOutput=(outputStreamName,...args)=>{if(Module.simpleListeners){const streamName=UTF8ToString(outputStreamName);if(Module.simpleListeners[streamName]){Module.simpleListeners[streamName](...args)}}}}if(!Module._wrapEmptyPacketListenerOutput){Module._wrapEmptyPacketListenerOutput=(outputStreamName,timestamp)=>{if(Module.emptyPacketListeners){const streamName=UTF8ToString(outputStreamName);if(Module.emptyPacketListeners[streamName]){Module.emptyPacketListeners[streamName](timestamp)}}}}}function JsOnSimpleListenerBinaryArray(output_stream_name,binary_ptr,binary_size,make_deep_copy,timestamp){const newProtoArray=make_deep_copy?Module.HEAPU8.slice(binary_ptr,binary_ptr+binary_size):new Uint8Array(Module.HEAPU8.buffer,binary_ptr,binary_size);Module._wrapSimpleListenerOutput(output_stream_name,newProtoArray,timestamp)}function mediapipe_import_external_texture(device_handle,source_handle){const device=WebGPU.mgrDevice.get(device_handle);const source=Emval.toValue(source_handle);const externalTexture=device.importExternalTexture({source:source});return Emval.toHandle(externalTexture)}function mediapipe_create_utility_canvas2d(){let canvas;if(typeof OffscreenCanvas!=="undefined"){canvas=new OffscreenCanvas(0,0)}else{canvas=document.createElement("canvas");canvas.style.display="none";canvas.id="canvas_2d";document.body.appendChild(canvas)}return Emval.toHandle(canvas)}function xnnLoadWasmModuleJS(code,offset,offset_end,invalid_function_index){const tableOriginalSize=wasmTable.length;const binary=new Uint8Array(HEAPU8.slice(code+offset,code+offset_end));try{var module=new WebAssembly.Module(binary);var instance=new WebAssembly.Instance(module,{env:{memory:wasmMemory}});for(var symName in instance.exports){var value=instance.exports[symName];addFunction(value)}if(tableOriginalSize{if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",Browser_setImmediate_messageHandler,true);setImmediate=function Browser_emulated_setImmediate(func){setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){if(Module["setImmediates"]===undefined)Module["setImmediates"]=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setImmediate(){setImmediate(Browser.mainLoop.runner)};Browser.mainLoop.method="immediate"}return 0}var _emscripten_get_now;if(ENVIRONMENT_IS_NODE){global.performance=require("perf_hooks").performance}_emscripten_get_now=()=>performance.now();function setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop,arg,noSetTiming){assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.");Browser.mainLoop.func=browserIterationFunc;Browser.mainLoop.arg=arg;var thisMainLoopId=Browser.mainLoop.currentlyRunningMainloop;function checkIsRunning(){if(thisMainLoopId0){var start=Date.now();var blocker=Browser.mainLoop.queue.shift();blocker.func(blocker.arg);if(Browser.mainLoop.remainingBlockers){var remaining=Browser.mainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){Browser.mainLoop.remainingBlockers=next}else{next=next+.5;Browser.mainLoop.remainingBlockers=(8*remaining+next)/9}}out('main loop blocker "'+blocker.name+'" took '+(Date.now()-start)+" ms");Browser.mainLoop.updateStatus();if(!checkIsRunning())return;setTimeout(Browser.mainLoop.runner,0);return}if(!checkIsRunning())return;Browser.mainLoop.currentFrameNumber=Browser.mainLoop.currentFrameNumber+1|0;if(Browser.mainLoop.timingMode==1&&Browser.mainLoop.timingValue>1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else if(Browser.mainLoop.timingMode==0){Browser.mainLoop.tickStartTime=_emscripten_get_now()}GL.newRenderingFrameStarted();Browser.mainLoop.runIter(browserIterationFunc);if(!checkIsRunning())return;if(typeof SDL=="object"&&SDL.audio&&SDL.audio.queueNewAudioData)SDL.audio.queueNewAudioData();Browser.mainLoop.scheduler()};if(!noSetTiming){if(fps&&fps>0){_emscripten_set_main_loop_timing(0,1e3/fps)}else{_emscripten_set_main_loop_timing(1,1)}Browser.mainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}}function handleException(e){if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)}function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:function(){var paths=Array.prototype.slice.call(arguments);return PATH.normalize(paths.join("/"))},join2:(l,r)=>{return PATH.normalize(l+"/"+r)}};function initRandomFill(){if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")}function randomFill(view){return(randomFill=initRandomFill())(view)}var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(heapOrArray,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str}var TTY={ttys:[],init:function(){},shutdown:function(){},register:function(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open:function(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close:function(stream){stream.tty.ops.fsync(stream.tty)},fsync:function(stream){stream.tty.ops.fsync(stream.tty)},read:function(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};function zeroMemory(address,size){HEAPU8.fill(0,address,address+size);return address}function alignMemory(size,alignment){return Math.ceil(size/alignment)*alignment}function mmapAlloc(size){size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(!ptr)return 0;return zeroMemory(ptr,size)}var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray:function(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage:function(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr:function(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr:function(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup:function(parent,name){throw FS.genericErrors[44]},mknod:function(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename:function(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink:function(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir:function(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir:function(node){var entries=[".",".."];for(var key in node.contents){if(!node.contents.hasOwnProperty(key)){continue}entries.push(key)}return entries},symlink:function(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink:function(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read:function(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{assert(arrayBuffer,`Loading data file "${url}" failed (no arrayBuffer).`);onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},event=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)}var preloadPlugins=Module["preloadPlugins"]||[];function FS_handledByPreloadPlugin(byteArray,fullname,finish,onerror){if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(function(plugin){if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled}function FS_createPreloadedFile(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish){var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){if(preFinish)preFinish();if(!dontCreateFile){FS.createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}if(onload)onload();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{if(onerror)onerror();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,byteArray=>processData(byteArray),onerror)}else{processData(url)}}function FS_modeStringToFlags(str){var flagModes={"r":0,"r+":2,"w":512|64|1,"w+":512|64|2,"a":1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags}function FS_getMode(canRead,canWrite){var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode}var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath:(path,opts={})=>{path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:node=>{var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName:(parentid,name)=>{var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:node=>{var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:node=>{var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode:(parent,name)=>{var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode:(parent,name,mode,rdev)=>{var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:node=>{FS.hashRemoveNode(node)},isRoot:node=>{return node===node.parent},isMountpoint:node=>{return!!node.mounted},isFile:mode=>{return(mode&61440)===32768},isDir:mode=>{return(mode&61440)===16384},isLink:mode=>{return(mode&61440)===40960},isChrdev:mode=>{return(mode&61440)===8192},isBlkdev:mode=>{return(mode&61440)===24576},isFIFO:mode=>{return(mode&61440)===4096},isSocket:mode=>{return(mode&49152)===49152},flagsToPermissionString:flag=>{var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:(node,perms)=>{if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup:dir=>{var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:(dir,name)=>{try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:(dir,name,isdir)=>{var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:(node,flags)=>{if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:()=>{for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:fd=>FS.streams[fd],createStream:(stream,fd=-1)=>{if(!FS.FSStream){FS.FSStream=function(){this.shared={}};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}},flags:{get:function(){return this.shared.flags},set:function(val){this.shared.flags=val}},position:{get:function(){return this.shared.position},set:function(val){this.shared.position=val}}})}stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:fd=>{FS.streams[fd]=null},chrdev_stream_ops:{open:stream=>{var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:()=>{throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice:(dev,ops)=>{FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts:mount=>{var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:(populate,callback)=>{if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:(type,opts,mountpoint)=>{var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:mountpoint=>{var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:(parent,name)=>{return parent.node_ops.lookup(parent,name)},mknod:(path,mode,dev)=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:(path,mode)=>{mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:(path,mode)=>{mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:(path,mode)=>{var dirs=path.split("/");var d="";for(var i=0;i{if(typeof dev=="undefined"){dev=mode;mode=438}mode|=8192;return FS.mknod(path,mode,dev)},symlink:(oldpath,newpath)=>{if(!PATH_FS.resolve(oldpath)){throw new FS.ErrnoError(44)}var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.symlink){throw new FS.ErrnoError(63)}return parent.node_ops.symlink(parent,newname,oldpath)},rename:(old_path,new_path)=>{var old_dirname=PATH.dirname(old_path);var new_dirname=PATH.dirname(new_path);var old_name=PATH.basename(old_path);var new_name=PATH.basename(new_path);var lookup,old_dir,new_dir;lookup=FS.lookupPath(old_path,{parent:true});old_dir=lookup.node;lookup=FS.lookupPath(new_path,{parent:true});new_dir=lookup.node;if(!old_dir||!new_dir)throw new FS.ErrnoError(44);if(old_dir.mount!==new_dir.mount){throw new FS.ErrnoError(75)}var old_node=FS.lookupNode(old_dir,old_name);var relative=PATH_FS.relative(old_path,new_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(28)}relative=PATH_FS.relative(new_path,old_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(55)}var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(old_node===new_node){return}var isdir=FS.isDir(old_node.mode);var errCode=FS.mayDelete(old_dir,old_name,isdir);if(errCode){throw new FS.ErrnoError(errCode)}errCode=new_node?FS.mayDelete(new_dir,new_name,isdir):FS.mayCreate(new_dir,new_name);if(errCode){throw new FS.ErrnoError(errCode)}if(!old_dir.node_ops.rename){throw new FS.ErrnoError(63)}if(FS.isMountpoint(old_node)||new_node&&FS.isMountpoint(new_node)){throw new FS.ErrnoError(10)}if(new_dir!==old_dir){errCode=FS.nodePermissions(old_dir,"w");if(errCode){throw new FS.ErrnoError(errCode)}}FS.hashRemoveNode(old_node);try{old_dir.node_ops.rename(old_node,new_dir,new_name)}catch(e){throw e}finally{FS.hashAddNode(old_node)}},rmdir:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,true);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.rmdir){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.rmdir(parent,name);FS.destroyNode(node)},readdir:path=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node.node_ops.readdir){throw new FS.ErrnoError(54)}return node.node_ops.readdir(node)},unlink:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,false);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.unlink){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.unlink(parent,name);FS.destroyNode(node)},readlink:path=>{var lookup=FS.lookupPath(path);var link=lookup.node;if(!link){throw new FS.ErrnoError(44)}if(!link.node_ops.readlink){throw new FS.ErrnoError(28)}return PATH_FS.resolve(FS.getPath(link.parent),link.node_ops.readlink(link))},stat:(path,dontFollow)=>{var lookup=FS.lookupPath(path,{follow:!dontFollow});var node=lookup.node;if(!node){throw new FS.ErrnoError(44)}if(!node.node_ops.getattr){throw new FS.ErrnoError(63)}return node.node_ops.getattr(node)},lstat:path=>{return FS.stat(path,true)},chmod:(path,mode,dontFollow)=>{var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}node.node_ops.setattr(node,{mode:mode&4095|node.mode&~4095,timestamp:Date.now()})},lchmod:(path,mode)=>{FS.chmod(path,mode,true)},fchmod:(fd,mode)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chmod(stream.node,mode)},chown:(path,uid,gid,dontFollow)=>{var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}node.node_ops.setattr(node,{timestamp:Date.now()})},lchown:(path,uid,gid)=>{FS.chown(path,uid,gid,true)},fchown:(fd,uid,gid)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chown(stream.node,uid,gid)},truncate:(path,len)=>{if(len<0){throw new FS.ErrnoError(28)}var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:true});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}if(FS.isDir(node.mode)){throw new FS.ErrnoError(31)}if(!FS.isFile(node.mode)){throw new FS.ErrnoError(28)}var errCode=FS.nodePermissions(node,"w");if(errCode){throw new FS.ErrnoError(errCode)}node.node_ops.setattr(node,{size:len,timestamp:Date.now()})},ftruncate:(fd,len)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(28)}FS.truncate(stream.node,len)},utime:(path,atime,mtime)=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;node.node_ops.setattr(node,{timestamp:Math.max(atime,mtime)})},open:(path,flags,mode)=>{if(path===""){throw new FS.ErrnoError(44)}flags=typeof flags=="string"?FS_modeStringToFlags(flags):flags;mode=typeof mode=="undefined"?438:mode;if(flags&64){mode=mode&4095|32768}else{mode=0}var node;if(typeof path=="object"){node=path}else{path=PATH.normalize(path);try{var lookup=FS.lookupPath(path,{follow:!(flags&131072)});node=lookup.node}catch(e){}}var created=false;if(flags&64){if(node){if(flags&128){throw new FS.ErrnoError(20)}}else{node=FS.mknod(path,mode,0);created=true}}if(!node){throw new FS.ErrnoError(44)}if(FS.isChrdev(node.mode)){flags&=~512}if(flags&65536&&!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}if(!created){var errCode=FS.mayOpen(node,flags);if(errCode){throw new FS.ErrnoError(errCode)}}if(flags&512&&!created){FS.truncate(node,0)}flags&=~(128|512|131072);var stream=FS.createStream({node:node,path:FS.getPath(node),flags:flags,seekable:true,position:0,stream_ops:node.stream_ops,ungotten:[],error:false});if(stream.stream_ops.open){stream.stream_ops.open(stream)}if(Module["logReadFiles"]&&!(flags&1)){if(!FS.readFiles)FS.readFiles={};if(!(path in FS.readFiles)){FS.readFiles[path]=1}}return stream},close:stream=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(stream.getdents)stream.getdents=null;try{if(stream.stream_ops.close){stream.stream_ops.close(stream)}}catch(e){throw e}finally{FS.closeStream(stream.fd)}stream.fd=null},isClosed:stream=>{return stream.fd===null},llseek:(stream,offset,whence)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(!stream.seekable||!stream.stream_ops.llseek){throw new FS.ErrnoError(70)}if(whence!=0&&whence!=1&&whence!=2){throw new FS.ErrnoError(28)}stream.position=stream.stream_ops.llseek(stream,offset,whence);stream.ungotten=[];return stream.position},read:(stream,buffer,offset,length,position)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.read){throw new FS.ErrnoError(28)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesRead=stream.stream_ops.read(stream,buffer,offset,length,position);if(!seeking)stream.position+=bytesRead;return bytesRead},write:(stream,buffer,offset,length,position,canOwn)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.write){throw new FS.ErrnoError(28)}if(stream.seekable&&stream.flags&1024){FS.llseek(stream,0,2)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesWritten=stream.stream_ops.write(stream,buffer,offset,length,position,canOwn);if(!seeking)stream.position+=bytesWritten;return bytesWritten},allocate:(stream,offset,length)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(offset<0||length<=0){throw new FS.ErrnoError(28)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(!FS.isFile(stream.node.mode)&&!FS.isDir(stream.node.mode)){throw new FS.ErrnoError(43)}if(!stream.stream_ops.allocate){throw new FS.ErrnoError(138)}stream.stream_ops.allocate(stream,offset,length)},mmap:(stream,length,position,prot,flags)=>{if((prot&2)!==0&&(flags&2)===0&&(stream.flags&2097155)!==2){throw new FS.ErrnoError(2)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(2)}if(!stream.stream_ops.mmap){throw new FS.ErrnoError(43)}return stream.stream_ops.mmap(stream,length,position,prot,flags)},msync:(stream,buffer,offset,length,mmapFlags)=>{if(!stream.stream_ops.msync){return 0}return stream.stream_ops.msync(stream,buffer,offset,length,mmapFlags)},munmap:stream=>0,ioctl:(stream,cmd,arg)=>{if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile:(path,opts={})=>{opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){throw new Error(`Invalid encoding type "${opts.encoding}"`)}var ret;var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){ret=UTF8ArrayToString(buf,0)}else if(opts.encoding==="binary"){ret=buf}FS.close(stream);return ret},writeFile:(path,data,opts={})=>{opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn)}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn)}else{throw new Error("Unsupported data type")}FS.close(stream)},cwd:()=>FS.currentPath,chdir:path=>{var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories:()=>{FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices:()=>{FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories:()=>{FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount:()=>{var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup:(parent,name)=>{var fd=+name;var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams:()=>{if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},ensureErrnoError:()=>{if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.name="ErrnoError";this.node=node;this.setErrno=function(errno){this.errno=errno};this.setErrno(errno);this.message="FS error"};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""})},staticInit:()=>{FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS}},init:(input,output,error)=>{FS.init.initialized=true;FS.ensureErrnoError();Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit:()=>{FS.init.initialized=false;for(var i=0;i{var ret=FS.analyzePath(path,dontResolveLastLink);if(!ret.exists){return null}return ret.object},analyzePath:(path,dontResolveLastLink)=>{try{var lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});path=lookup.path}catch(e){}var ret={isRoot:false,exists:false,error:0,name:null,path:null,object:null,parentExists:false,parentPath:null,parentObject:null};try{var lookup=FS.lookupPath(path,{parent:true});ret.parentExists=true;ret.parentPath=lookup.path;ret.parentObject=lookup.node;ret.name=PATH.basename(path);lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});ret.exists=true;ret.path=lookup.path;ret.object=lookup.node;ret.name=lookup.node.name;ret.isRoot=lookup.path==="/"}catch(e){ret.error=e.errno}return ret},createPath:(parent,path,canRead,canWrite)=>{parent=typeof parent=="string"?parent:FS.getPath(parent);var parts=path.split("/").reverse();while(parts.length){var part=parts.pop();if(!part)continue;var current=PATH.join2(parent,part);try{FS.mkdir(current)}catch(e){}parent=current}return current},createFile:(parent,name,properties,canRead,canWrite)=>{var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS_getMode(canRead,canWrite);return FS.create(path,mode)},createDataFile:(parent,name,data,canRead,canWrite,canOwn)=>{var path=name;if(parent){parent=typeof parent=="string"?parent:FS.getPath(parent);path=name?PATH.join2(parent,name):parent}var mode=FS_getMode(canRead,canWrite);var node=FS.create(path,mode);if(data){if(typeof data=="string"){var arr=new Array(data.length);for(var i=0,len=data.length;i{var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS_getMode(!!input,!!output);if(!FS.createDevice.major)FS.createDevice.major=64;var dev=FS.makedev(FS.createDevice.major++,0);FS.registerDevice(dev,{open:stream=>{stream.seekable=false},close:stream=>{if(output&&output.buffer&&output.buffer.length){output(10)}},read:(stream,buffer,offset,length,pos)=>{var bytesRead=0;for(var i=0;i{for(var i=0;i{if(obj.isDevice||obj.isFolder||obj.link||obj.contents)return true;if(typeof XMLHttpRequest!="undefined"){throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.")}else if(read_){try{obj.contents=intArrayFromString(read_(obj.url),true);obj.usedBytes=obj.contents.length}catch(e){throw new FS.ErrnoError(29)}}else{throw new Error("Cannot load without read() or XMLHttpRequest.")}},createLazyFile:(parent,name,url,canRead,canWrite)=>{function LazyUint8Array(){this.lengthKnown=false;this.chunks=[]}LazyUint8Array.prototype.get=function LazyUint8Array_get(idx){if(idx>this.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt:function(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat:function(func,path,buf){try{var stat=func(path)}catch(e){if(e&&e.node&&PATH.normalize(path)!==PATH.normalize(FS.getPath(e.node))){return-54}throw e}HEAP32[buf>>2]=stat.dev;HEAP32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAP32[buf+12>>2]=stat.uid;HEAP32[buf+16>>2]=stat.gid;HEAP32[buf+20>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>2]=tempI64[0],HEAP32[buf+28>>2]=tempI64[1];HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAPU32[buf+48>>2]=atime%1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>2]=tempI64[0],HEAP32[buf+60>>2]=tempI64[1];HEAPU32[buf+64>>2]=mtime%1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>2]=tempI64[0],HEAP32[buf+76>>2]=tempI64[1];HEAPU32[buf+80>>2]=ctime%1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>2]=tempI64[0],HEAP32[buf+92>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},varargs:undefined,get:function(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream}};function _proc_exit(code){EXITSTATUS=code;if(!keepRuntimeAlive()){if(Module["onExit"])Module["onExit"](code);ABORT=true}quit_(code,new ExitStatus(code))}function exitJS(status,implicit){EXITSTATUS=status;_proc_exit(status)}var _exit=exitJS;function maybeExit(){if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}}function callUserCallback(func){if(ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}}function safeSetTimeout(func,timeout){return setTimeout(()=>{callUserCallback(func)},timeout)}function warnOnce(text){if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;if(ENVIRONMENT_IS_NODE)text="warning: "+text;err(text)}}var Browser={mainLoop:{running:false,scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null;Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var timingMode=Browser.mainLoop.timingMode;var timingValue=Browser.mainLoop.timingValue;var func=Browser.mainLoop.func;Browser.mainLoop.func=null;setMainLoop(func,0,false,Browser.mainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);Browser.mainLoop.scheduler()},updateStatus:function(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=Browser.mainLoop.remainingBlockers;var expected=Browser.mainLoop.expectedBlockers;if(remaining){if(remaining{assert(img.complete,"Image "+name+" could not be decoded");var canvas=document.createElement("canvas");canvas.width=img.width;canvas.height=img.height;var ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);preloadedImages[name]=canvas;URL.revokeObjectURL(url);if(onload)onload(byteArray)};img.onerror=event=>{out("Image "+url+" could not be decoded");if(onerror)onerror()};img.src=url};preloadPlugins.push(imagePlugin);var audioPlugin={};audioPlugin["canHandle"]=function audioPlugin_canHandle(name){return!Module.noAudioDecoding&&name.substr(-4)in{".ogg":1,".wav":1,".mp3":1}};audioPlugin["handle"]=function audioPlugin_handle(byteArray,name,onload,onerror){var done=false;function finish(audio){if(done)return;done=true;preloadedAudios[name]=audio;if(onload)onload(byteArray)}var b=new Blob([byteArray],{type:Browser.getMimetype(name)});var url=URL.createObjectURL(b);var audio=new Audio;audio.addEventListener("canplaythrough",()=>finish(audio),false);audio.onerror=function audio_onerror(event){if(done)return;err("warning: browser could not fully decode audio "+name+", trying slower base64 approach");function encode64(data){var BASE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var PAD="=";var ret="";var leftchar=0;var leftbits=0;for(var i=0;i=6){var curr=leftchar>>leftbits-6&63;leftbits-=6;ret+=BASE[curr]}}if(leftbits==2){ret+=BASE[(leftchar&3)<<4];ret+=PAD+PAD}else if(leftbits==4){ret+=BASE[(leftchar&15)<<2];ret+=PAD}return ret}audio.src="data:audio/x-"+name.substr(-3)+";base64,"+encode64(byteArray);finish(audio)};audio.src=url;safeSetTimeout(()=>{finish(audio)},1e4)};preloadPlugins.push(audioPlugin);function pointerLockChange(){Browser.pointerLock=document["pointerLockElement"]===Module["canvas"]||document["mozPointerLockElement"]===Module["canvas"]||document["webkitPointerLockElement"]===Module["canvas"]||document["msPointerLockElement"]===Module["canvas"]}var canvas=Module["canvas"];if(canvas){canvas.requestPointerLock=canvas["requestPointerLock"]||canvas["mozRequestPointerLock"]||canvas["webkitRequestPointerLock"]||canvas["msRequestPointerLock"]||(()=>{});canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||(()=>{});canvas.exitPointerLock=canvas.exitPointerLock.bind(document);document.addEventListener("pointerlockchange",pointerLockChange,false);document.addEventListener("mozpointerlockchange",pointerLockChange,false);document.addEventListener("webkitpointerlockchange",pointerLockChange,false);document.addEventListener("mspointerlockchange",pointerLockChange,false);if(Module["elementPointerLock"]){canvas.addEventListener("click",ev=>{if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},createContext:function(canvas,useWebGL,setInModule,webGLContextAttributes){if(useWebGL&&Module.ctx&&canvas==Module.canvas)return Module.ctx;var ctx;var contextHandle;if(useWebGL){var contextAttributes={antialias:false,alpha:false,majorVersion:typeof WebGL2RenderingContext!="undefined"?2:1};if(webGLContextAttributes){for(var attribute in webGLContextAttributes){contextAttributes[attribute]=webGLContextAttributes[attribute]}}if(typeof GL!="undefined"){contextHandle=GL.createContext(canvas,contextAttributes);if(contextHandle){ctx=GL.getContext(contextHandle).GLctx}}}else{ctx=canvas.getContext("2d")}if(!ctx)return null;if(setInModule){if(!useWebGL)assert(typeof GLctx=="undefined","cannot set in module if GLctx is used, but we are a non-GL context that would replace it");Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Module.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(callback=>callback());Browser.init()}return ctx},destroyContext:function(canvas,useWebGL,setInModule){},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen:function(lockPointer,resizeCanvas){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;if(typeof Browser.lockPointer=="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas=="undefined")Browser.resizeCanvas=false;var canvas=Module["canvas"];function fullscreenChange(){Browser.isFullscreen=false;var canvasContainer=canvas.parentNode;if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvasContainer){canvas.exitFullscreen=Browser.exitFullscreen;if(Browser.lockPointer)canvas.requestPointerLock();Browser.isFullscreen=true;if(Browser.resizeCanvas){Browser.setFullscreenCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}else{canvasContainer.parentNode.insertBefore(canvas,canvasContainer);canvasContainer.parentNode.removeChild(canvasContainer);if(Browser.resizeCanvas){Browser.setWindowedCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}if(Module["onFullScreen"])Module["onFullScreen"](Browser.isFullscreen);if(Module["onFullscreen"])Module["onFullscreen"](Browser.isFullscreen)}if(!Browser.fullscreenHandlersInstalled){Browser.fullscreenHandlersInstalled=true;document.addEventListener("fullscreenchange",fullscreenChange,false);document.addEventListener("mozfullscreenchange",fullscreenChange,false);document.addEventListener("webkitfullscreenchange",fullscreenChange,false);document.addEventListener("MSFullscreenChange",fullscreenChange,false)}var canvasContainer=document.createElement("div");canvas.parentNode.insertBefore(canvasContainer,canvas);canvasContainer.appendChild(canvas);canvasContainer.requestFullscreen=canvasContainer["requestFullscreen"]||canvasContainer["mozRequestFullScreen"]||canvasContainer["msRequestFullscreen"]||(canvasContainer["webkitRequestFullscreen"]?()=>canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"]):null)||(canvasContainer["webkitRequestFullScreen"]?()=>canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"]):null);canvasContainer.requestFullscreen()},exitFullscreen:function(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||(()=>{});CFS.apply(document,[]);return true},nextRAF:0,fakeRequestAnimationFrame:function(func){var now=Date.now();if(Browser.nextRAF===0){Browser.nextRAF=now+1e3/60}else{while(now+2>=Browser.nextRAF){Browser.nextRAF+=1e3/60}}var delay=Math.max(Browser.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame:function(func){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(func);return}var RAF=Browser.fakeRequestAnimationFrame;RAF(func)},safeSetTimeout:function(func,timeout){return safeSetTimeout(func,timeout)},safeRequestAnimationFrame:function(func){return Browser.requestAnimationFrame(()=>{callUserCallback(func)})},getMimetype:function(name){return{"jpg":"image/jpeg","jpeg":"image/jpeg","png":"image/png","bmp":"image/bmp","ogg":"audio/ogg","wav":"audio/wav","mp3":"audio/mpeg"}[name.substr(name.lastIndexOf(".")+1)]},getUserMedia:function(func){if(!window.getUserMedia){window.getUserMedia=navigator["getUserMedia"]||navigator["mozGetUserMedia"]}window.getUserMedia(func)},getMovementX:function(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY:function(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta:function(event){var delta=0;switch(event.type){case"DOMMouseScroll":delta=event.detail/3;break;case"mousewheel":delta=event.wheelDelta/120;break;case"wheel":delta=event.deltaY;switch(event.deltaMode){case 0:delta/=100;break;case 1:delta/=3;break;case 2:delta*=80;break;default:throw"unrecognized mouse wheel delta mode: "+event.deltaMode}break;default:throw"unrecognized mouse wheel event: "+event.type}return delta},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(event){if(Browser.pointerLock){if(event.type!="mousemove"&&"mozMovementX"in event){Browser.mouseMovementX=Browser.mouseMovementY=0}else{Browser.mouseMovementX=Browser.getMovementX(event);Browser.mouseMovementY=Browser.getMovementY(event)}if(typeof SDL!="undefined"){Browser.mouseX=SDL.mouseX+Browser.mouseMovementX;Browser.mouseY=SDL.mouseY+Browser.mouseMovementY}else{Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}}else{var rect=Module["canvas"].getBoundingClientRect();var cw=Module["canvas"].width;var ch=Module["canvas"].height;var scrollX=typeof window.scrollX!="undefined"?window.scrollX:window.pageXOffset;var scrollY=typeof window.scrollY!="undefined"?window.scrollY:window.pageYOffset;if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var adjustedX=touch.pageX-(scrollX+rect.left);var adjustedY=touch.pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);var coords={x:adjustedX,y:adjustedY};if(event.type==="touchstart"){Browser.lastTouches[touch.identifier]=coords;Browser.touches[touch.identifier]=coords}else if(event.type==="touchend"||event.type==="touchmove"){var last=Browser.touches[touch.identifier];if(!last)last=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}var x=event.pageX-(scrollX+rect.left);var y=event.pageY-(scrollY+rect.top);x=x*(cw/rect.width);y=y*(ch/rect.height);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y}},resizeListeners:[],updateResizeListeners:function(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(listener=>listener(canvas.width,canvas.height))},setCanvasSize:function(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags|8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags&~8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions:function(canvas,wNative,hNative){if(wNative&&hNative){canvas.widthNative=wNative;canvas.heightNative=hNative}else{wNative=canvas.widthNative;hNative=canvas.heightNative}var w=wNative;var h=hNative;if(Module["forcedAspectRatio"]&&Module["forcedAspectRatio"]>0){if(w/h0){callbacks.shift()(Module)}}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24;this.set_type=function(type){HEAPU32[this.ptr+4>>2]=type};this.get_type=function(){return HEAPU32[this.ptr+4>>2]};this.set_destructor=function(destructor){HEAPU32[this.ptr+8>>2]=destructor};this.get_destructor=function(){return HEAPU32[this.ptr+8>>2]};this.set_caught=function(caught){caught=caught?1:0;HEAP8[this.ptr+12>>0]=caught};this.get_caught=function(){return HEAP8[this.ptr+12>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>0]=rethrown};this.get_rethrown=function(){return HEAP8[this.ptr+13>>0]!=0};this.init=function(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)};this.set_adjusted_ptr=function(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr};this.get_adjusted_ptr=function(){return HEAPU32[this.ptr+16>>2]};this.get_exception_ptr=function(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return HEAPU32[this.excPtr>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}var exceptionLast=0;var uncaughtExceptionCount=0;function ___cxa_throw(ptr,type,destructor){var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast}function setErrNo(value){HEAP32[___errno_location()>>2]=value;return value}function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}var newStream;newStream=FS.createStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 5:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 6:case 7:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fstat64(fd,buf){try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:case 21505:{if(!stream.tty)return-59;return 0}case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:{if(!stream.tty)return-59;return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.get();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.get();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;return 0}case 21524:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_lstat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_newfstatat(dirfd,path,buf,flags){try{path=SYSCALLS.getStr(path);var nofollow=flags&256;var allowEmpty=flags&4096;flags=flags&~6400;path=SYSCALLS.calculateAt(dirfd,path,allowEmpty);return SYSCALLS.doStat(nofollow?FS.lstat:FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?SYSCALLS.get():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_stat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var dlopenMissingError="To use dlopen, you need enable dynamic linking, see https://emscripten.org/docs/compiling/Dynamic-Linking.html";function __dlopen_js(handle){abort(dlopenMissingError)}function __dlsym_js(handle,symbol){abort(dlopenMissingError)}function __embind_register_bigint(primitiveType,name,size,minRange,maxRange){}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError(`Unknown type size: ${size}`)}}function embind_init_charCodes(){var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes}var embind_charCodes=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return`_${name}`}return name}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return{[name]:function(){return body.apply(this,arguments)}}[name]}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return`${this.name}: ${this.message}`}};return errorClass}var BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function registerType(rawType,registeredInstance,options={}){if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function __embind_register_bool(rawType,name,size,trueValue,falseValue){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(wt){return!!wt},"toWireType":function(destructors,o){return o?trueValue:falseValue},"argPackAdvance":8,"readValueFromPointer":function(pointer){var heap;if(size===1){heap=HEAP8}else if(size===2){heap=HEAP16}else if(size===4){heap=HEAP32}else{throw new TypeError("Unknown boolean type size: "+name)}return this["fromWireType"](heap[pointer>>shift])},destructorFunction:null})}function HandleAllocator(){this.allocated=[undefined];this.freelist=[];this.get=function(id){return this.allocated[id]};this.has=function(id){return this.allocated[id]!==undefined};this.allocate=function(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id};this.free=function(id){this.allocated[id]=undefined;this.freelist.push(id)}}var emval_handles=new HandleAllocator;function __emval_decref(handle){if(handle>=emval_handles.reserved&&0===--emval_handles.get(handle).refcount){emval_handles.free(handle)}}function count_emval_handles(){var count=0;for(var i=emval_handles.reserved;i{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles.get(handle).value},toHandle:value=>{switch(value){case undefined:return 1;case null:return 2;case true:return 3;case false:return 4;default:{return emval_handles.allocate({refcount:1,value:value})}}}};function simpleReadValueFromPointer(pointer){return this["fromWireType"](HEAP32[pointer>>2])}function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=Emval.toValue(handle);__emval_decref(handle);return rv},"toWireType":function(destructors,value){return Emval.toHandle(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function integerReadValueFromPointer(name,shift,signed){switch(shift){case 0:return signed?function readS8FromPointer(pointer){return HEAP8[pointer]}:function readU8FromPointer(pointer){return HEAPU8[pointer]};case 1:return signed?function readS16FromPointer(pointer){return HEAP16[pointer>>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":toWireType,"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(heap.buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||HEAPU8[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+i]=charCode}}else{for(var i=0;i>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str}function stringToUTF16(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}function lengthBytesUTF16(str){return str.length*2}function UTF32ToString(ptr,maxBytesToRead){var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str}function stringToUTF32(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}function lengthBytesUTF32(str){var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len}function __embind_register_std_wstring(rawType,charSize,name){name=readLatin1String(name);var decodeString,encodeString,getHeap,lengthBytesUTF,shift;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;getHeap=()=>HEAPU16;shift=1}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;getHeap=()=>HEAPU32;shift=2}registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var HEAP=getHeap();var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||HEAP[currentBytePtr>>shift]==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},"toWireType":function(destructors,value){if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}var nowIsMonotonic=true;function __emscripten_get_now_is_monotonic(){return nowIsMonotonic}function getTypeName(type){var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv}function requireRegisteredType(rawType,humanName){var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl}function __emval_as(handle,returnType,destructorsRef){handle=Emval.toValue(handle);returnType=requireRegisteredType(returnType,"emval::as");var destructors=[];var rd=Emval.toHandle(destructors);HEAPU32[destructorsRef>>2]=rd;return returnType["toWireType"](destructors,handle)}var emval_symbols={};function getStringOrSymbol(address){var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}return symbol}function emval_get_global(){if(typeof globalThis=="object"){return globalThis}function testGlobal(obj){obj["$$$embind_global$$$"]=obj;var success=typeof $$$embind_global$$$=="object"&&obj["$$$embind_global$$$"]==obj;if(!success){delete obj["$$$embind_global$$$"]}return success}if(typeof $$$embind_global$$$=="object"){return $$$embind_global$$$}if(typeof global=="object"&&testGlobal(global)){$$$embind_global$$$=global}else if(typeof self=="object"&&testGlobal(self)){$$$embind_global$$$=self}if(typeof $$$embind_global$$$=="object"){return $$$embind_global$$$}throw Error("unable to get global object.")}function __emval_get_global(name){if(name===0){return Emval.toHandle(emval_get_global())}else{name=getStringOrSymbol(name);return Emval.toHandle(emval_get_global()[name])}}function __emval_get_property(handle,key){handle=Emval.toValue(handle);key=Emval.toValue(key);return Emval.toHandle(handle[key])}function __emval_incref(handle){if(handle>4){emval_handles.get(handle).refcount+=1}}function __emval_instanceof(object,constructor){object=Emval.toValue(object);constructor=Emval.toValue(constructor);return object instanceof constructor}function __emval_new_cstring(v){return Emval.toHandle(getStringOrSymbol(v))}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function __emval_run_destructors(handle){var destructors=Emval.toValue(handle);runDestructors(destructors);__emval_decref(handle)}function __emval_set_property(handle,key,value){handle=Emval.toValue(handle);key=Emval.toValue(key);value=Emval.toValue(value);handle[key]=value}function __emval_take_value(type,arg){type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](arg);return Emval.toHandle(v)}function __emval_typeof(handle){handle=Emval.toValue(handle);return Emval.toHandle(typeof handle)}function readI53FromI64(ptr){return HEAPU32[ptr>>2]+HEAP32[ptr+4>>2]*4294967296}function __gmtime_js(time,tmPtr){var date=new Date(readI53FromI64(time)*1e3);HEAP32[tmPtr>>2]=date.getUTCSeconds();HEAP32[tmPtr+4>>2]=date.getUTCMinutes();HEAP32[tmPtr+8>>2]=date.getUTCHours();HEAP32[tmPtr+12>>2]=date.getUTCDate();HEAP32[tmPtr+16>>2]=date.getUTCMonth();HEAP32[tmPtr+20>>2]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday}function isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];function ydayFromDate(date){var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday}function __localtime_js(time,tmPtr){var date=new Date(readI53FromI64(time)*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst}function __mktime_js(tmPtr){var date=new Date(HEAP32[tmPtr+20>>2]+1900,HEAP32[tmPtr+16>>2],HEAP32[tmPtr+12>>2],HEAP32[tmPtr+8>>2],HEAP32[tmPtr+4>>2],HEAP32[tmPtr>>2],0);var dst=HEAP32[tmPtr+32>>2];var guessedOffset=date.getTimezoneOffset();var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dstOffset=Math.min(winterOffset,summerOffset);if(dst<0){HEAP32[tmPtr+32>>2]=Number(summerOffset!=winterOffset&&dstOffset==guessedOffset)}else if(dst>0!=(dstOffset==guessedOffset)){var nonDstOffset=Math.max(winterOffset,summerOffset);var trueOffset=dst>0?dstOffset:nonDstOffset;date.setTime(date.getTime()+(trueOffset-guessedOffset)*6e4)}HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getYear();return date.getTime()/1e3|0}function __mmap_js(len,prot,flags,fd,off,allocated,addr){try{var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,off,prot,flags);var ptr=res.ptr;HEAP32[allocated>>2]=res.allocated;HEAPU32[addr>>2]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function __munmap_js(addr,len,prot,flags,fd,offset){try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset)}FS.munmap(stream)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function stringToNewUTF8(str){var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8(str,ret,size);return ret}function __tzset_js(timezone,daylight,tzname){var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>2]=stdTimezoneOffset*60;HEAP32[daylight>>2]=Number(winterOffset!=summerOffset);function extractZone(date){var match=date.toTimeString().match(/\(([A-Za-z ]+)\)$/);return match?match[1]:"GMT"}var winterName=extractZone(winter);var summerName=extractZone(summer);var winterNamePtr=stringToNewUTF8(winterName);var summerNamePtr=stringToNewUTF8(summerName);if(summerOffset>2]=winterNamePtr;HEAPU32[tzname+4>>2]=summerNamePtr}else{HEAPU32[tzname>>2]=summerNamePtr;HEAPU32[tzname+4>>2]=winterNamePtr}}function _abort(){abort("")}var readEmAsmArgsArray=[];function readEmAsmArgs(sigPtr,buf){readEmAsmArgsArray.length=0;var ch;buf>>=2;while(ch=HEAPU8[sigPtr++]){buf+=ch!=105&buf;readEmAsmArgsArray.push(ch==105?HEAP32[buf]:HEAPF64[buf++>>1]);++buf}return readEmAsmArgsArray}function runEmAsmFunction(code,sigPtr,argbuf){var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[code].apply(null,args)}function _emscripten_asm_const_int(code,sigPtr,argbuf){return runEmAsmFunction(code,sigPtr,argbuf)}function _emscripten_date_now(){return Date.now()}function _emscripten_err(str){err(UTF8ToString(str))}function _emscripten_errn(str,len){err(UTF8ToString(str,len))}function getHeapMax(){return 2147483648}function _emscripten_get_heap_max(){return getHeapMax()}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function _emscripten_outn(str,len){out(UTF8ToString(str,len))}function _emscripten_pc_get_function(pc){abort("Cannot use emscripten_pc_get_function without -sUSE_OFFSET_CONVERTER")}function emscripten_realloc_buffer(size){var b=wasmMemory.buffer;var pages=size-b.byteLength+65535>>>16;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){var oldSize=HEAPU8.length;requestedSize=requestedSize>>>0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}function convertFrameToPC(frame){abort("Cannot use convertFrameToPC (needed by __builtin_return_address) without -sUSE_OFFSET_CONVERTER");return 0}var UNWIND_CACHE={};function saveInUnwindCache(callstack){callstack.forEach(frame=>{var pc=convertFrameToPC(frame);if(pc){UNWIND_CACHE[pc]=frame}})}function jsStackTrace(){var error=new Error;if(!error.stack){try{throw new Error}catch(e){error=e}if(!error.stack){return"(no stack trace available)"}}return error.stack.toString()}function _emscripten_stack_snapshot(){var callstack=jsStackTrace().split("\n");if(callstack[0]=="Error"){callstack.shift()}saveInUnwindCache(callstack);UNWIND_CACHE.last_addr=convertFrameToPC(callstack[3]);UNWIND_CACHE.last_stack=callstack;return UNWIND_CACHE.last_addr}function _emscripten_stack_unwind_buffer(addr,buffer,count){var stack;if(UNWIND_CACHE.last_addr==addr){stack=UNWIND_CACHE.last_stack}else{stack=jsStackTrace().split("\n");if(stack[0]=="Error"){stack.shift()}saveInUnwindCache(stack)}var offset=3;while(stack[offset]&&convertFrameToPC(stack[offset])!=addr){++offset}for(var i=0;i>2]=convertFrameToPC(stack[i+offset])}return i}function webgl_enable_ANGLE_instanced_arrays(ctx){var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=function(index,divisor){ext["vertexAttribDivisorANGLE"](index,divisor)};ctx["drawArraysInstanced"]=function(mode,first,count,primcount){ext["drawArraysInstancedANGLE"](mode,first,count,primcount)};ctx["drawElementsInstanced"]=function(mode,count,type,indices,primcount){ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount)};return 1}}function webgl_enable_OES_vertex_array_object(ctx){var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=function(){return ext["createVertexArrayOES"]()};ctx["deleteVertexArray"]=function(vao){ext["deleteVertexArrayOES"](vao)};ctx["bindVertexArray"]=function(vao){ext["bindVertexArrayOES"](vao)};ctx["isVertexArray"]=function(vao){return ext["isVertexArrayOES"](vao)};return 1}}function webgl_enable_WEBGL_draw_buffers(ctx){var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=function(n,bufs){ext["drawBuffersWEBGL"](n,bufs)};return 1}}function webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(ctx){return!!(ctx.dibvbi=ctx.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"))}function webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(ctx){return!!(ctx.mdibvbi=ctx.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance"))}function webgl_enable_WEBGL_multi_draw(ctx){return!!(ctx.multiDrawWebgl=ctx.getExtension("WEBGL_multi_draw"))}var GL={counter:1,buffers:[],mappedBuffers:{},programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],samplers:[],transformFeedbacks:[],syncs:[],byteSizeByTypeRoot:5120,byteSizeByType:[1,1,2,2,4,4,4,2,3,4,8],stringCache:{},stringiCache:{},unpackAlignment:4,recordError:function recordError(errorCode){if(!GL.lastError){GL.lastError=errorCode}},getNewId:function(table){var ret=GL.counter++;for(var i=table.length;i>1;var quadIndexes=new Uint16Array(numIndexes);var i=0,v=0;while(1){quadIndexes[i++]=v;if(i>=numIndexes)break;quadIndexes[i++]=v+1;if(i>=numIndexes)break;quadIndexes[i++]=v+2;if(i>=numIndexes)break;quadIndexes[i++]=v;if(i>=numIndexes)break;quadIndexes[i++]=v+2;if(i>=numIndexes)break;quadIndexes[i++]=v+3;if(i>=numIndexes)break;v+=4}context.GLctx.bufferData(34963,quadIndexes,35044);context.GLctx.bindBuffer(34963,null)}},getTempVertexBuffer:function getTempVertexBuffer(sizeBytes){var idx=GL.log2ceilLookup(sizeBytes);var ringbuffer=GL.currentContext.tempVertexBuffers1[idx];var nextFreeBufferIndex=GL.currentContext.tempVertexBufferCounters1[idx];GL.currentContext.tempVertexBufferCounters1[idx]=GL.currentContext.tempVertexBufferCounters1[idx]+1&GL.numTempVertexBuffersPerSize-1;var vbo=ringbuffer[nextFreeBufferIndex];if(vbo){return vbo}var prevVBO=GLctx.getParameter(34964);ringbuffer[nextFreeBufferIndex]=GLctx.createBuffer();GLctx.bindBuffer(34962,ringbuffer[nextFreeBufferIndex]);GLctx.bufferData(34962,1<>2]:-1;source+=UTF8ToString(HEAP32[string+i*4>>2],len<0?undefined:len)}return source},calcBufLength:function calcBufLength(size,type,stride,count){if(stride>0){return count*stride}var typeSize=GL.byteSizeByType[type-GL.byteSizeByTypeRoot];return size*typeSize*count},usedTempBuffers:[],preDrawHandleClientVertexAttribBindings:function preDrawHandleClientVertexAttribBindings(count){GL.resetBufferBinding=false;for(var i=0;i1?canvas.getContext("webgl2",webGLContextAttributes):canvas.getContext("webgl",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);return handle},registerContext:function(ctx,webGLContextAttributes){var handle=GL.getNewId(GL.contexts);var context={handle:handle,attributes:webGLContextAttributes,version:webGLContextAttributes.majorVersion,GLctx:ctx};if(ctx.canvas)ctx.canvas.GLctxObject=context;GL.contexts[handle]=context;if(typeof webGLContextAttributes.enableExtensionsByDefault=="undefined"||webGLContextAttributes.enableExtensionsByDefault){GL.initExtensions(context)}context.maxVertexAttribs=context.GLctx.getParameter(34921);context.clientBuffers=[];for(var i=0;i=2){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query_webgl2")}if(context.version<2||!GLctx.disjointTimerQueryExt){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query")}webgl_enable_WEBGL_multi_draw(GLctx);var exts=GLctx.getSupportedExtensions()||[];exts.forEach(function(ext){if(!ext.includes("lose_context")&&!ext.includes("debug")){GLctx.getExtension(ext)}})}};function withStackSave(f){var stack=stackSave();var ret=f();stackRestore(stack);return ret}var JSEvents={inEventHandler:0,removeAllEventListeners:function(){for(var i=JSEvents.eventHandlers.length-1;i>=0;--i){JSEvents._removeHandler(i)}JSEvents.eventHandlers=[];JSEvents.deferredCalls=[]},registerRemoveEventListeners:function(){if(!JSEvents.removeEventListenersRegistered){__ATEXIT__.push(JSEvents.removeAllEventListeners);JSEvents.removeEventListenersRegistered=true}},deferredCalls:[],deferCall:function(targetFunction,precedence,argsList){function arraysHaveEqualContent(arrA,arrB){if(arrA.length!=arrB.length)return false;for(var i in arrA){if(arrA[i]!=arrB[i])return false}return true}for(var i in JSEvents.deferredCalls){var call=JSEvents.deferredCalls[i];if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction:targetFunction,precedence:precedence,argsList:argsList});JSEvents.deferredCalls.sort(function(x,y){return x.precedence>2;var powerPreference=HEAP32[a+(24>>2)];var contextAttributes={"alpha":!!HEAP32[a+(0>>2)],"depth":!!HEAP32[a+(4>>2)],"stencil":!!HEAP32[a+(8>>2)],"antialias":!!HEAP32[a+(12>>2)],"premultipliedAlpha":!!HEAP32[a+(16>>2)],"preserveDrawingBuffer":!!HEAP32[a+(20>>2)],"powerPreference":emscripten_webgl_power_preferences[powerPreference],"failIfMajorPerformanceCaveat":!!HEAP32[a+(28>>2)],majorVersion:HEAP32[a+(32>>2)],minorVersion:HEAP32[a+(36>>2)],enableExtensionsByDefault:HEAP32[a+(40>>2)],explicitSwapControl:HEAP32[a+(44>>2)],proxyContextToMainThread:HEAP32[a+(48>>2)],renderViaOffscreenBackBuffer:HEAP32[a+(52>>2)]};var canvas=findCanvasEventTarget(target);if(!canvas){return 0}if(contextAttributes.explicitSwapControl){return 0}var contextHandle=GL.createContext(canvas,contextAttributes);return contextHandle}var _emscripten_webgl_create_context=_emscripten_webgl_do_create_context;function _emscripten_webgl_destroy_context(contextHandle){if(GL.currentContext==contextHandle)GL.currentContext=0;GL.deleteContext(contextHandle)}function _emscripten_webgl_get_context_attributes(c,a){if(!a)return-5;c=GL.contexts[c];if(!c)return-3;var t=c.GLctx;if(!t)return-3;t=t.getContextAttributes();HEAP32[a>>2]=t.alpha;HEAP32[a+4>>2]=t.depth;HEAP32[a+8>>2]=t.stencil;HEAP32[a+12>>2]=t.antialias;HEAP32[a+16>>2]=t.premultipliedAlpha;HEAP32[a+20>>2]=t.preserveDrawingBuffer;var power=t["powerPreference"]&&emscripten_webgl_power_preferences.indexOf(t["powerPreference"]);HEAP32[a+24>>2]=power;HEAP32[a+28>>2]=t.failIfMajorPerformanceCaveat;HEAP32[a+32>>2]=c.version;HEAP32[a+36>>2]=0;HEAP32[a+40>>2]=c.attributes.enableExtensionsByDefault;return 0}function _emscripten_webgl_do_get_current_context(){return GL.currentContext?GL.currentContext.handle:0}var _emscripten_webgl_get_current_context=_emscripten_webgl_do_get_current_context;function _emscripten_webgl_init_context_attributes(attributes){var a=attributes>>2;for(var i=0;i<56>>2;++i){HEAP32[a+i]=0}HEAP32[a+(0>>2)]=HEAP32[a+(4>>2)]=HEAP32[a+(12>>2)]=HEAP32[a+(16>>2)]=HEAP32[a+(32>>2)]=HEAP32[a+(40>>2)]=1}function _emscripten_webgl_make_context_current(contextHandle){var success=GL.makeContextCurrent(contextHandle);return success?0:-5}function stringToUTF8OnStack(str){var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret}function convertI32PairToI53(lo,hi){return(lo>>>0)+hi*4294967296}var wasmTableMirror=[];function getWasmTableEntry(funcPtr){var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func}var WebGPU={errorCallback:function(callback,type,message,userdata){withStackSave(()=>{var messagePtr=stringToUTF8OnStack(message);getWasmTableEntry(callback)(type,messagePtr,userdata)})},initManagers:function(){if(WebGPU.mgrDevice)return;function Manager(){this.objects={};this.nextId=1;this.create=function(object,wrapper={}){var id=this.nextId++;wrapper.refcount=1;wrapper.object=object;this.objects[id]=wrapper;return id};this.get=function(id){if(!id)return undefined;var o=this.objects[id];return o.object};this.reference=function(id){var o=this.objects[id];o.refcount++};this.release=function(id){var o=this.objects[id];o.refcount--;if(o.refcount<=0){delete this.objects[id]}}}WebGPU.mgrSurface=WebGPU.mgrSurface||new Manager;WebGPU.mgrSwapChain=WebGPU.mgrSwapChain||new Manager;WebGPU.mgrAdapter=WebGPU.mgrAdapter||new Manager;WebGPU.mgrDevice=WebGPU.mgrDevice||new Manager;WebGPU.mgrQueue=WebGPU.mgrQueue||new Manager;WebGPU.mgrCommandBuffer=WebGPU.mgrCommandBuffer||new Manager;WebGPU.mgrCommandEncoder=WebGPU.mgrCommandEncoder||new Manager;WebGPU.mgrRenderPassEncoder=WebGPU.mgrRenderPassEncoder||new Manager;WebGPU.mgrComputePassEncoder=WebGPU.mgrComputePassEncoder||new Manager;WebGPU.mgrBindGroup=WebGPU.mgrBindGroup||new Manager;WebGPU.mgrBuffer=WebGPU.mgrBuffer||new Manager;WebGPU.mgrSampler=WebGPU.mgrSampler||new Manager;WebGPU.mgrTexture=WebGPU.mgrTexture||new Manager;WebGPU.mgrTextureView=WebGPU.mgrTextureView||new Manager;WebGPU.mgrQuerySet=WebGPU.mgrQuerySet||new Manager;WebGPU.mgrBindGroupLayout=WebGPU.mgrBindGroupLayout||new Manager;WebGPU.mgrPipelineLayout=WebGPU.mgrPipelineLayout||new Manager;WebGPU.mgrRenderPipeline=WebGPU.mgrRenderPipeline||new Manager;WebGPU.mgrComputePipeline=WebGPU.mgrComputePipeline||new Manager;WebGPU.mgrShaderModule=WebGPU.mgrShaderModule||new Manager;WebGPU.mgrRenderBundleEncoder=WebGPU.mgrRenderBundleEncoder||new Manager;WebGPU.mgrRenderBundle=WebGPU.mgrRenderBundle||new Manager},makeColor:function(ptr){return{"r":HEAPF64[ptr>>3],"g":HEAPF64[ptr+8>>3],"b":HEAPF64[ptr+16>>3],"a":HEAPF64[ptr+24>>3]}},makeExtent3D:function(ptr){return{"width":HEAPU32[ptr>>2],"height":HEAPU32[ptr+4>>2],"depthOrArrayLayers":HEAPU32[ptr+8>>2]}},makeOrigin3D:function(ptr){return{"x":HEAPU32[ptr>>2],"y":HEAPU32[ptr+4>>2],"z":HEAPU32[ptr+8>>2]}},makeImageCopyTexture:function(ptr){return{"texture":WebGPU.mgrTexture.get(HEAPU32[ptr+4>>2]),"mipLevel":HEAPU32[ptr+8>>2],"origin":WebGPU.makeOrigin3D(ptr+12),"aspect":WebGPU.TextureAspect[HEAPU32[ptr+24>>2]]}},makeTextureDataLayout:function(ptr){var bytesPerRow=HEAPU32[ptr+16>>2];var rowsPerImage=HEAPU32[ptr+20>>2];return{"offset":HEAPU32[ptr+4+8>>2]*4294967296+HEAPU32[ptr+8>>2],"bytesPerRow":bytesPerRow===4294967295?undefined:bytesPerRow,"rowsPerImage":rowsPerImage===4294967295?undefined:rowsPerImage}},makeImageCopyBuffer:function(ptr){var layoutPtr=ptr+8;var bufferCopyView=WebGPU.makeTextureDataLayout(layoutPtr);bufferCopyView["buffer"]=WebGPU.mgrBuffer.get(HEAPU32[ptr+32>>2]);return bufferCopyView},makePipelineConstants:function(constantCount,constantsPtr){if(!constantCount)return;var constants={};for(var i=0;i>2]);constants[key]=HEAPF64[entryPtr+8>>3]}return constants},makePipelineLayout:function(layoutPtr){if(!layoutPtr)return"auto";return WebGPU.mgrPipelineLayout.get(layoutPtr)},makeProgrammableStageDescriptor:function(ptr){if(!ptr)return undefined;return{"module":WebGPU.mgrShaderModule.get(HEAPU32[ptr+4>>2]),"entryPoint":UTF8ToString(HEAPU32[ptr+8>>2]),"constants":WebGPU.makePipelineConstants(HEAPU32[ptr+12>>2],HEAPU32[ptr+16>>2])}},DeviceLostReason:{undefined:0,destroyed:1},PreferredFormat:{rgba8unorm:18,bgra8unorm:23},AddressMode:["repeat","mirror-repeat","clamp-to-edge"],BlendFactor:["zero","one","src","one-minus-src","src-alpha","one-minus-src-alpha","dst","one-minus-dst","dst-alpha","one-minus-dst-alpha","src-alpha-saturated","constant","one-minus-constant"],BlendOperation:["add","subtract","reverse-subtract","min","max"],BufferBindingType:[,"uniform","storage","read-only-storage"],CompareFunction:[,"never","less","less-equal","greater","greater-equal","equal","not-equal","always"],CompilationInfoRequestStatus:["success","error","device-lost","unknown"],ComputePassTimestampLocation:["beginning","end"],CullMode:["none","front","back"],ErrorFilter:["validation","out-of-memory"],FeatureName:[,"depth-clip-control","depth32float-stencil8","timestamp-query","pipeline-statistics-query","texture-compression-bc","texture-compression-etc2","texture-compression-astc","indirect-first-instance"],FilterMode:["nearest","linear"],FrontFace:["ccw","cw"],IndexFormat:[,"uint16","uint32"],LoadOp:[,"clear","load"],PipelineStatisticName:["vertex-shader-invocations","clipper-invocations","clipper-primitives-out","fragment-shader-invocations","compute-shader-invocations"],PowerPreference:[,"low-power","high-performance"],PrimitiveTopology:["point-list","line-list","line-strip","triangle-list","triangle-strip"],QueryType:["occlusion","pipeline-statistics","timestamp"],RenderPassTimestampLocation:["beginning","end"],SamplerBindingType:[,"filtering","non-filtering","comparison"],StencilOperation:["keep","zero","replace","invert","increment-clamp","decrement-clamp","increment-wrap","decrement-wrap"],StorageTextureAccess:[,"write-only"],StoreOp:[,"store","discard"],TextureAspect:["all","stencil-only","depth-only"],TextureComponentType:["float","sint","uint","depth-comparison"],TextureDimension:["1d","2d","3d"],TextureFormat:[,"r8unorm","r8snorm","r8uint","r8sint","r16uint","r16sint","r16float","rg8unorm","rg8snorm","rg8uint","rg8sint","r32float","r32uint","r32sint","rg16uint","rg16sint","rg16float","rgba8unorm","rgba8unorm-srgb","rgba8snorm","rgba8uint","rgba8sint","bgra8unorm","bgra8unorm-srgb","rgb10a2unorm","rg11b10ufloat","rgb9e5ufloat","rg32float","rg32uint","rg32sint","rgba16uint","rgba16sint","rgba16float","rgba32float","rgba32uint","rgba32sint","stencil8","depth16unorm","depth24plus","depth24plus-stencil8","depth32float","depth32float-stencil8","bc1-rgba-unorm","bc1-rgba-unorm-srgb","bc2-rgba-unorm","bc2-rgba-unorm-srgb","bc3-rgba-unorm","bc3-rgba-unorm-srgb","bc4-r-unorm","bc4-r-snorm","bc5-rg-unorm","bc5-rg-snorm","bc6h-rgb-ufloat","bc6h-rgb-float","bc7-rgba-unorm","bc7-rgba-unorm-srgb","etc2-rgb8unorm","etc2-rgb8unorm-srgb","etc2-rgb8a1unorm","etc2-rgb8a1unorm-srgb","etc2-rgba8unorm","etc2-rgba8unorm-srgb","eac-r11unorm","eac-r11snorm","eac-rg11unorm","eac-rg11snorm","astc-4x4-unorm","astc-4x4-unorm-srgb","astc-5x4-unorm","astc-5x4-unorm-srgb","astc-5x5-unorm","astc-5x5-unorm-srgb","astc-6x5-unorm","astc-6x5-unorm-srgb","astc-6x6-unorm","astc-6x6-unorm-srgb","astc-8x5-unorm","astc-8x5-unorm-srgb","astc-8x6-unorm","astc-8x6-unorm-srgb","astc-8x8-unorm","astc-8x8-unorm-srgb","astc-10x5-unorm","astc-10x5-unorm-srgb","astc-10x6-unorm","astc-10x6-unorm-srgb","astc-10x8-unorm","astc-10x8-unorm-srgb","astc-10x10-unorm","astc-10x10-unorm-srgb","astc-12x10-unorm","astc-12x10-unorm-srgb","astc-12x12-unorm","astc-12x12-unorm-srgb"],TextureSampleType:[,"float","unfilterable-float","depth","sint","uint"],TextureViewDimension:[,"1d","2d","2d-array","cube","cube-array","3d"],VertexFormat:[,"uint8x2","uint8x4","sint8x2","sint8x4","unorm8x2","unorm8x4","snorm8x2","snorm8x4","uint16x2","uint16x4","sint16x2","sint16x4","unorm16x2","unorm16x4","snorm16x2","snorm16x4","float16x2","float16x4","float32","float32x2","float32x3","float32x4","uint32","uint32x2","uint32x3","uint32x4","sint32","sint32x2","sint32x3","sint32x4"],VertexStepMode:["vertex","instance"],FeatureNameString2Enum:{undefined:"0","depth-clip-control":"1","depth32float-stencil8":"2","timestamp-query":"3","pipeline-statistics-query":"4","texture-compression-bc":"5","texture-compression-etc2":"6","texture-compression-astc":"7","indirect-first-instance":"8"}};var JsValStore={values:{},next_id:1,add:function(js_val){var id;do{id=JsValStore.next_id++;if(JsValStore.next_id>2147483647)JsValStore.next_id=1}while(id in JsValStore.values);JsValStore.values[id]=js_val;return id},remove:function(id){delete JsValStore.values[id]},get:function(id){return JsValStore.values[id]}};function _emscripten_webgpu_export_bind_group_layout(handle){return JsValStore.add(WebGPU.mgrBindGroupLayout.get(handle))}function _emscripten_webgpu_export_device(handle){return JsValStore.add(WebGPU.mgrDevice.get(handle))}function _emscripten_webgpu_export_sampler(handle){return JsValStore.add(WebGPU.mgrSampler.get(handle))}function _emscripten_webgpu_export_texture(handle){return JsValStore.add(WebGPU.mgrTexture.get(handle))}function _emscripten_webgpu_get_device(){if(WebGPU.preinitializedDeviceId===undefined){var device=Module["preinitializedWebGPUDevice"];var deviceWrapper={queueId:WebGPU.mgrQueue.create(device["queue"])};WebGPU.preinitializedDeviceId=WebGPU.mgrDevice.create(device,deviceWrapper)}WebGPU.mgrDevice.reference(WebGPU.preinitializedDeviceId);return WebGPU.preinitializedDeviceId}function _emscripten_webgpu_import_bind_group(handle){return WebGPU.mgrBindGroup.create(JsValStore.get(handle))}function _emscripten_webgpu_import_texture(handle){return WebGPU.mgrTexture.create(JsValStore.get(handle))}function _emscripten_webgpu_release_js_handle(id){JsValStore.remove(id)}var ENV={};function getExecutableName(){return thisProgram||"./this.program"}function getEnvStrings(){if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings}function stringToAscii(str,buffer){for(var i=0;i>0]=str.charCodeAt(i)}HEAP8[buffer>>0]=0}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAPU32[penviron_buf_size>>2]=bufSize;return 0}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function doReadv(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function convertI32PairToI53Checked(lo,hi){return hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var offset=convertI32PairToI53Checked(offset_low,offset_high);if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function doWritev(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(typeof offset!=="undefined"){offset+=curr}}return ret}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _getentropy(buffer,size){randomFill(HEAPU8.subarray(buffer,buffer+size));return 0}function _glActiveTexture(x0){GLctx.activeTexture(x0)}function _glAttachShader(program,shader){GLctx.attachShader(GL.programs[program],GL.shaders[shader])}function _glBindAttribLocation(program,index,name){GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}function _glBindBuffer(target,buffer){if(target==34962){GLctx.currentArrayBufferBinding=buffer}else if(target==34963){GLctx.currentElementArrayBufferBinding=buffer}if(target==35051){GLctx.currentPixelPackBufferBinding=buffer}else if(target==35052){GLctx.currentPixelUnpackBufferBinding=buffer}GLctx.bindBuffer(target,GL.buffers[buffer])}function _glBindBufferBase(target,index,buffer){GLctx.bindBufferBase(target,index,GL.buffers[buffer])}function _glBindFramebuffer(target,framebuffer){GLctx.bindFramebuffer(target,GL.framebuffers[framebuffer])}function _glBindTexture(target,texture){GLctx.bindTexture(target,GL.textures[texture])}function _glBindVertexArray(vao){GLctx.bindVertexArray(GL.vaos[vao]);var ibo=GLctx.getParameter(34965);GLctx.currentElementArrayBufferBinding=ibo?ibo.name|0:0}function _glBlendEquation(x0){GLctx.blendEquation(x0)}function _glBlendFunc(x0,x1){GLctx.blendFunc(x0,x1)}function _glBufferData(target,size,data,usage){if(GL.currentContext.version>=2){if(data&&size){GLctx.bufferData(target,HEAPU8,usage,data,size)}else{GLctx.bufferData(target,size,usage)}}else{GLctx.bufferData(target,data?HEAPU8.subarray(data,data+size):size,usage)}}function _glClear(x0){GLctx.clear(x0)}function _glClearColor(x0,x1,x2,x3){GLctx.clearColor(x0,x1,x2,x3)}function _glClientWaitSync(sync,flags,timeout_low,timeout_high){var timeout=convertI32PairToI53(timeout_low,timeout_high);return GLctx.clientWaitSync(GL.syncs[sync],flags,timeout)}function _glCompileShader(shader){GLctx.compileShader(GL.shaders[shader])}function _glCreateProgram(){var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;program.maxUniformLength=program.maxAttributeLength=program.maxUniformBlockNameLength=0;program.uniformIdCounter=1;GL.programs[id]=program;return id}function _glCreateShader(shaderType){var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id}function _glDeleteBuffers(n,buffers){for(var i=0;i>2];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null;if(id==GLctx.currentArrayBufferBinding)GLctx.currentArrayBufferBinding=0;if(id==GLctx.currentElementArrayBufferBinding)GLctx.currentElementArrayBufferBinding=0;if(id==GLctx.currentPixelPackBufferBinding)GLctx.currentPixelPackBufferBinding=0;if(id==GLctx.currentPixelUnpackBufferBinding)GLctx.currentPixelUnpackBufferBinding=0}}function _glDeleteFramebuffers(n,framebuffers){for(var i=0;i>2];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}function _glDeleteProgram(id){if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null}function _glDeleteShader(id){if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null}function _glDeleteSync(id){if(!id)return;var sync=GL.syncs[id];if(!sync){GL.recordError(1281);return}GLctx.deleteSync(sync);sync.name=0;GL.syncs[id]=null}function _glDeleteTextures(n,textures){for(var i=0;i>2];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}function _glDeleteVertexArrays(n,vaos){for(var i=0;i>2];GLctx.deleteVertexArray(GL.vaos[id]);GL.vaos[id]=null}}function _glDisable(x0){GLctx.disable(x0)}function _glDisableVertexAttribArray(index){var cb=GL.currentContext.clientBuffers[index];cb.enabled=false;GLctx.disableVertexAttribArray(index)}function _glDrawArrays(mode,first,count){GL.preDrawHandleClientVertexAttribBindings(first+count);GLctx.drawArrays(mode,first,count);GL.postDrawHandleClientVertexAttribBindings()}var tempFixedLengthArray=[];function _glDrawBuffers(n,bufs){var bufArray=tempFixedLengthArray[n];for(var i=0;i>2]}GLctx.drawBuffers(bufArray)}function _glEnable(x0){GLctx.enable(x0)}function _glEnableVertexAttribArray(index){var cb=GL.currentContext.clientBuffers[index];cb.enabled=true;GLctx.enableVertexAttribArray(index)}function _glFenceSync(condition,flags){var sync=GLctx.fenceSync(condition,flags);if(sync){var id=GL.getNewId(GL.syncs);sync.name=id;GL.syncs[id]=sync;return id}return 0}function _glFinish(){GLctx.finish()}function _glFlush(){GLctx.flush()}function _glFramebufferTexture2D(target,attachment,textarget,texture,level){GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)}function _glFramebufferTextureLayer(target,attachment,texture,level,layer){GLctx.framebufferTextureLayer(target,attachment,GL.textures[texture],level,layer)}function __glGenObject(n,buffers,createFunction,objectTable){for(var i=0;i>2]=id}}function _glGenBuffers(n,buffers){__glGenObject(n,buffers,"createBuffer",GL.buffers)}function _glGenFramebuffers(n,ids){__glGenObject(n,ids,"createFramebuffer",GL.framebuffers)}function _glGenTextures(n,textures){__glGenObject(n,textures,"createTexture",GL.textures)}function _glGenVertexArrays(n,arrays){__glGenObject(n,arrays,"createVertexArray",GL.vaos)}function _glGetAttribLocation(program,name){return GLctx.getAttribLocation(GL.programs[program],UTF8ToString(name))}function _glGetError(){var error=GLctx.getError()||GL.lastError;GL.lastError=0;return error}function writeI53ToI64(ptr,num){HEAPU32[ptr>>2]=num;HEAPU32[ptr+4>>2]=(num-HEAPU32[ptr>>2])/4294967296}function emscriptenWebGLGet(name_,p,type){if(!p){GL.recordError(1281);return}var ret=undefined;switch(name_){case 36346:ret=1;break;case 36344:if(type!=0&&type!=1){GL.recordError(1280)}return;case 34814:case 36345:ret=0;break;case 34466:var formats=GLctx.getParameter(34467);ret=formats?formats.length:0;break;case 33309:if(GL.currentContext.version<2){GL.recordError(1282);return}var exts=GLctx.getSupportedExtensions()||[];ret=2*exts.length;break;case 33307:case 33308:if(GL.currentContext.version<2){GL.recordError(1280);return}ret=name_==33307?3:0;break}if(ret===undefined){var result=GLctx.getParameter(name_);switch(typeof result){case"number":ret=result;break;case"boolean":ret=result?1:0;break;case"string":GL.recordError(1280);return;case"object":if(result===null){switch(name_){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:{ret=0;break}default:{GL.recordError(1280);return}}}else if(result instanceof Float32Array||result instanceof Uint32Array||result instanceof Int32Array||result instanceof Array){for(var i=0;i>2]=result[i];break;case 2:HEAPF32[p+i*4>>2]=result[i];break;case 4:HEAP8[p+i>>0]=result[i]?1:0;break}}return}else{try{ret=result.name|0}catch(e){GL.recordError(1280);err("GL_INVALID_ENUM in glGet"+type+"v: Unknown object returned from WebGL getParameter("+name_+")! (error: "+e+")");return}}break;default:GL.recordError(1280);err("GL_INVALID_ENUM in glGet"+type+"v: Native code calling glGet"+type+"v("+name_+") and it returns "+result+" of type "+typeof result+"!");return}}switch(type){case 1:writeI53ToI64(p,ret);break;case 0:HEAP32[p>>2]=ret;break;case 2:HEAPF32[p>>2]=ret;break;case 4:HEAP8[p>>0]=ret?1:0;break}}function _glGetIntegerv(name_,p){emscriptenWebGLGet(name_,p,0)}function _glGetProgramiv(program,pname,p){if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}program=GL.programs[program];if(pname==35716){var log=GLctx.getProgramInfoLog(program);if(log===null)log="(unknown error)";HEAP32[p>>2]=log.length+1}else if(pname==35719){if(!program.maxUniformLength){for(var i=0;i>2]=program.maxUniformLength}else if(pname==35722){if(!program.maxAttributeLength){for(var i=0;i>2]=program.maxAttributeLength}else if(pname==35381){if(!program.maxUniformBlockNameLength){for(var i=0;i>2]=program.maxUniformBlockNameLength}else{HEAP32[p>>2]=GLctx.getProgramParameter(program,pname)}}function _glGetShaderInfoLog(shader,maxLength,length,infoLog){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _glGetShaderiv(shader,pname,p){if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>2]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>2]=sourceLength}else{HEAP32[p>>2]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}function _glGetString(name_){var ret=GL.stringCache[name_];if(!ret){switch(name_){case 7939:var exts=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));ret=stringToNewUTF8(exts.join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=s&&stringToNewUTF8(s);break;case 7938:var glVersion=GLctx.getParameter(7938);if(GL.currentContext.version>=2)glVersion="OpenGL ES 3.0 ("+glVersion+")";else{glVersion="OpenGL ES 2.0 ("+glVersion+")"}ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion="OpenGL ES GLSL ES "+ver_num[1]+" ("+glslVersion+")"}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280)}GL.stringCache[name_]=ret}return ret}function _glGetUniformBlockIndex(program,uniformBlockName){return GLctx.getUniformBlockIndex(GL.programs[program],UTF8ToString(uniformBlockName))}function jstoi_q(str){return parseInt(str)}function webglGetLeftBracePos(name){return name.slice(-1)=="]"&&name.lastIndexOf("[")}function webglPrepareUniformLocationsBeforeFirstUse(program){var uniformLocsById=program.uniformLocsById,uniformSizeAndIdsByName=program.uniformSizeAndIdsByName,i,j;if(!uniformLocsById){program.uniformLocsById=uniformLocsById={};program.uniformArrayNamesById={};for(i=0;i0?nm.slice(0,lb):nm;var id=program.uniformIdCounter;program.uniformIdCounter+=sz;uniformSizeAndIdsByName[arrayName]=[sz,id];for(j=0;j0){arrayIndex=jstoi_q(name.slice(leftBrace+1))>>>0;uniformBaseName=name.slice(0,leftBrace)}var sizeAndId=program.uniformSizeAndIdsByName[uniformBaseName];if(sizeAndId&&arrayIndex>shift,pixels+bytes>>shift)}function _glReadPixels(x,y,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelPackBufferBinding){GLctx.readPixels(x,y,width,height,format,type,pixels)}else{var heap=heapObjectForWebGLType(type);GLctx.readPixels(x,y,width,height,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}return}var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}function _glShaderSource(shader,count,string,length){var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}function _glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,null)}return}GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null)}function _glTexParameterf(x0,x1,x2){GLctx.texParameterf(x0,x1,x2)}function _glTexParameterfv(target,pname,params){var param=HEAPF32[params>>2];GLctx.texParameterf(target,pname,param)}function _glTexParameteri(x0,x1,x2){GLctx.texParameteri(x0,x1,x2)}function _glTexStorage2D(x0,x1,x2,x3,x4){GLctx.texStorage2D(x0,x1,x2,x3,x4)}function _glTexStorage3D(x0,x1,x2,x3,x4,x5){GLctx.texStorage3D(x0,x1,x2,x3,x4,x5)}function _glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,null)}return}var pixelData=null;if(pixels)pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}function _glTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx.texSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,null)}}function webglGetUniformLocation(location){var p=GLctx.currentProgram;if(p){var webglLoc=p.uniformLocsById[location];if(typeof webglLoc=="number"){p.uniformLocsById[location]=webglLoc=GLctx.getUniformLocation(p,p.uniformArrayNamesById[location]+(webglLoc>0?"["+webglLoc+"]":""))}return webglLoc}else{GL.recordError(1282)}}function _glUniform1f(location,v0){GLctx.uniform1f(webglGetUniformLocation(location),v0)}function _glUniform1i(location,v0){GLctx.uniform1i(webglGetUniformLocation(location),v0)}function _glUniform2f(location,v0,v1){GLctx.uniform2f(webglGetUniformLocation(location),v0,v1)}var miniTempWebGLFloatBuffers=[];function _glUniform2fv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform2fv(webglGetUniformLocation(location),HEAPF32,value>>2,count*2);return}if(count<=144){var view=miniTempWebGLFloatBuffers[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2fv(webglGetUniformLocation(location),view)}function _glUniform3f(location,v0,v1,v2){GLctx.uniform3f(webglGetUniformLocation(location),v0,v1,v2)}function _glUniform4fv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform4fv(webglGetUniformLocation(location),HEAPF32,value>>2,count*4);return}if(count<=72){var view=miniTempWebGLFloatBuffers[4*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<4*count;i+=4){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4fv(webglGetUniformLocation(location),view)}var miniTempWebGLIntBuffers=[];function _glUniform4iv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform4iv(webglGetUniformLocation(location),HEAP32,value>>2,count*4);return}if(count<=72){var view=miniTempWebGLIntBuffers[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2];view[i+3]=HEAP32[value+(4*i+12)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4iv(webglGetUniformLocation(location),view)}function _glUniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding){program=GL.programs[program];GLctx.uniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding)}function _glUniformMatrix4fv(location,count,transpose,value){if(GL.currentContext.version>=2){count&&GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*16);return}if(count<=18){var view=miniTempWebGLFloatBuffers[16*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<16*count;i+=16){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3];view[i+4]=heap[dst+4];view[i+5]=heap[dst+5];view[i+6]=heap[dst+6];view[i+7]=heap[dst+7];view[i+8]=heap[dst+8];view[i+9]=heap[dst+9];view[i+10]=heap[dst+10];view[i+11]=heap[dst+11];view[i+12]=heap[dst+12];view[i+13]=heap[dst+13];view[i+14]=heap[dst+14];view[i+15]=heap[dst+15]}}else{var view=HEAPF32.subarray(value>>2,value+count*64>>2)}GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,view)}function _glUseProgram(program){program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program}function _glVertexAttribPointer(index,size,type,normalized,stride,ptr){var cb=GL.currentContext.clientBuffers[index];if(!GLctx.currentArrayBufferBinding){cb.size=size;cb.type=type;cb.normalized=normalized;cb.stride=stride;cb.ptr=ptr;cb.clientside=true;cb.vertexAttribPointerAdaptor=function(index,size,type,normalized,stride,ptr){this.vertexAttribPointer(index,size,type,normalized,stride,ptr)};return}cb.clientside=false;GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}function _glViewport(x0,x1,x2,x3){GLctx.viewport(x0,x1,x2,x3)}function _mediapipe_find_canvas_event_target(canvasSelector){let target=findCanvasEventTarget(canvasSelector);if(Module&&!target){target=Module.canvasWebGpu}return Emval.toHandle(target)}function _mediapipe_webgl_tex_image_drawable(drawableHandle){const drawable=Emval.toValue(drawableHandle);GLctx.texImage2D(GLctx.TEXTURE_2D,0,GLctx.RGBA,GLctx.RGBA,GLctx.UNSIGNED_BYTE,drawable)}function arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum}var MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value=="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}return thisDate.getFullYear()}return thisDate.getFullYear()-1}var EXPANSION_RULES_2={"%a":function(date){return WEEKDAYS[date.tm_wday].substring(0,3)},"%A":function(date){return WEEKDAYS[date.tm_wday]},"%b":function(date){return MONTHS[date.tm_mon].substring(0,3)},"%B":function(date){return MONTHS[date.tm_mon]},"%C":function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":function(date){return leadingNulls(date.tm_mday,2)},"%e":function(date){return leadingSomething(date.tm_mday,2," ")},"%g":function(date){return getWeekBasedYear(date).toString().substring(2)},"%G":function(date){return getWeekBasedYear(date)},"%H":function(date){return leadingNulls(date.tm_hour,2)},"%I":function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":function(date){return leadingNulls(date.tm_mday+arraySum(isLeapYear(date.tm_year+1900)?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,date.tm_mon-1),3)},"%m":function(date){return leadingNulls(date.tm_mon+1,2)},"%M":function(date){return leadingNulls(date.tm_min,2)},"%n":function(){return"\n"},"%p":function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}return"PM"},"%S":function(date){return leadingNulls(date.tm_sec,2)},"%t":function(){return"\t"},"%u":function(date){return date.tm_wday||7},"%U":function(date){var days=date.tm_yday+7-date.tm_wday;return leadingNulls(Math.floor(days/7),2)},"%V":function(date){var val=Math.floor((date.tm_yday+7-(date.tm_wday+6)%7)/7);if((date.tm_wday+371-date.tm_yday-2)%7<=2){val++}if(!val){val=52;var dec31=(date.tm_wday+7-date.tm_yday-1)%7;if(dec31==4||dec31==5&&isLeapYear(date.tm_year%400-1)){val++}}else if(val==53){var jan1=(date.tm_wday+371-date.tm_yday)%7;if(jan1!=4&&(jan1!=3||!isLeapYear(date.tm_year)))val=1}return leadingNulls(val,2)},"%w":function(date){return date.tm_wday},"%W":function(date){var days=date.tm_yday+7-(date.tm_wday+6)%7;return leadingNulls(Math.floor(days/7),2)},"%y":function(date){return(date.tm_year+1900).toString().substring(2)},"%Y":function(date){return date.tm_year+1900},"%z":function(date){var off=date.tm_gmtoff;var ahead=off>=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":function(date){return date.tm_zone},"%%":function(){return"%"}};pattern=pattern.replace(/%%/g,"\0\0");for(var rule in EXPANSION_RULES_2){if(pattern.includes(rule)){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}pattern=pattern.replace(/\0\0/g,"%");var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm,loc){return _strftime(s,maxsize,format,tm)}function _wgpuBindGroupLayoutRelease(id){WebGPU.mgrBindGroupLayout.release(id)}function _wgpuBindGroupRelease(id){WebGPU.mgrBindGroup.release(id)}function _wgpuBufferGetMappedRange(bufferId,offset,size){var bufferWrapper=WebGPU.mgrBuffer.objects[bufferId];if(size===0)warnOnce("getMappedRange size=0 no longer means WGPU_WHOLE_MAP_SIZE");size=size>>>0;if(size===4294967295)size=undefined;if(bufferWrapper.mapMode!==2){return 0}var mapped;try{mapped=bufferWrapper.object["getMappedRange"](offset,size)}catch(ex){return 0}var data=_memalign(16,mapped.byteLength);HEAPU8.fill(0,data,mapped.byteLength);bufferWrapper.onUnmap.push(()=>{new Uint8Array(mapped).set(HEAPU8.subarray(data,data+mapped.byteLength));_free(data)});return data}function _wgpuBufferReference(id){WebGPU.mgrBuffer.reference(id)}function _wgpuBufferRelease(id){WebGPU.mgrBuffer.release(id)}function _wgpuBufferUnmap(bufferId){var bufferWrapper=WebGPU.mgrBuffer.objects[bufferId];if(!bufferWrapper.onUnmap){return}for(var i=0;i>2]),"queryIndex":HEAPU32[twPtr+4>>2],"location":WebGPU.ComputePassTimestampLocation[HEAPU32[twPtr+8>>2]]}}function makeComputePassTimestampWrites(count,twPtr){var timestampWrites=[];for(var i=0;i>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var timestampWriteCount=HEAPU32[descriptor+8>>2];if(timestampWriteCount){desc["timestampWrites"]=makeComputePassTimestampWrites(timestampWriteCount,HEAPU32[descriptor+12>>2])}}var commandEncoder=WebGPU.mgrCommandEncoder.get(encoderId);return WebGPU.mgrComputePassEncoder.create(commandEncoder["beginComputePass"](desc))}function _wgpuCommandEncoderBeginRenderPass(encoderId,descriptor){function makeColorAttachment(caPtr){var viewPtr=HEAPU32[caPtr>>2];if(viewPtr===0){return undefined}var loadOpInt=HEAPU32[caPtr+8>>2];var storeOpInt=HEAPU32[caPtr+12>>2];var clearValue=WebGPU.makeColor(caPtr+16);return{"view":WebGPU.mgrTextureView.get(viewPtr),"resolveTarget":WebGPU.mgrTextureView.get(HEAPU32[caPtr+4>>2]),"clearValue":clearValue,"loadOp":WebGPU.LoadOp[loadOpInt],"storeOp":WebGPU.StoreOp[storeOpInt]}}function makeColorAttachments(count,caPtr){var attachments=[];for(var i=0;i>2]),"depthClearValue":HEAPF32[dsaPtr+12>>2],"depthLoadOp":WebGPU.LoadOp[HEAPU32[dsaPtr+4>>2]],"depthStoreOp":WebGPU.StoreOp[HEAPU32[dsaPtr+8>>2]],"depthReadOnly":HEAP8[dsaPtr+16>>0]!==0,"stencilClearValue":HEAPU32[dsaPtr+28>>2],"stencilLoadOp":WebGPU.LoadOp[HEAPU32[dsaPtr+20>>2]],"stencilStoreOp":WebGPU.StoreOp[HEAPU32[dsaPtr+24>>2]],"stencilReadOnly":HEAP8[dsaPtr+32>>0]!==0}}function makeRenderPassTimestampWrite(twPtr){return{"querySet":WebGPU.mgrQuerySet.get(HEAPU32[twPtr>>2]),"queryIndex":HEAPU32[twPtr+4>>2],"location":WebGPU.RenderPassTimestampLocation[HEAPU32[twPtr+8>>2]]}}function makeRenderPassTimestampWrites(count,twPtr){var timestampWrites=[];for(var i=0;i>2];var maxDrawCount=undefined;if(nextInChainPtr!==0){var sType=HEAPU32[nextInChainPtr+4>>2];var renderPassDescriptorMaxDrawCount=nextInChainPtr;maxDrawCount=HEAPU32[renderPassDescriptorMaxDrawCount+4+8>>2]*4294967296+HEAPU32[renderPassDescriptorMaxDrawCount+8>>2]}var desc={"label":undefined,"colorAttachments":makeColorAttachments(HEAPU32[descriptor+8>>2],HEAPU32[descriptor+12>>2]),"depthStencilAttachment":makeDepthStencilAttachment(HEAPU32[descriptor+16>>2]),"occlusionQuerySet":WebGPU.mgrQuerySet.get(HEAPU32[descriptor+20>>2]),"maxDrawCount":maxDrawCount};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var timestampWriteCount=HEAPU32[descriptor+24>>2];if(timestampWriteCount){desc["timestampWrites"]=makeRenderPassTimestampWrites(timestampWriteCount,HEAPU32[descriptor+28>>2])}return desc}var desc=makeRenderPassDescriptor(descriptor);var commandEncoder=WebGPU.mgrCommandEncoder.get(encoderId);return WebGPU.mgrRenderPassEncoder.create(commandEncoder["beginRenderPass"](desc))}function _wgpuCommandEncoderCopyBufferToTexture(encoderId,srcPtr,dstPtr,copySizePtr){var commandEncoder=WebGPU.mgrCommandEncoder.get(encoderId);var copySize=WebGPU.makeExtent3D(copySizePtr);commandEncoder["copyBufferToTexture"](WebGPU.makeImageCopyBuffer(srcPtr),WebGPU.makeImageCopyTexture(dstPtr),copySize)}function _wgpuCommandEncoderCopyTextureToTexture(encoderId,srcPtr,dstPtr,copySizePtr){var commandEncoder=WebGPU.mgrCommandEncoder.get(encoderId);var copySize=WebGPU.makeExtent3D(copySizePtr);commandEncoder["copyTextureToTexture"](WebGPU.makeImageCopyTexture(srcPtr),WebGPU.makeImageCopyTexture(dstPtr),copySize)}function _wgpuCommandEncoderFinish(encoderId){var commandEncoder=WebGPU.mgrCommandEncoder.get(encoderId);return WebGPU.mgrCommandBuffer.create(commandEncoder["finish"]())}function _wgpuCommandEncoderRelease(id){WebGPU.mgrCommandEncoder.release(id)}function _wgpuComputePassEncoderDispatchWorkgroups(passId,x,y,z){var pass=WebGPU.mgrComputePassEncoder.get(passId);pass["dispatchWorkgroups"](x,y,z)}function _wgpuComputePassEncoderEnd(passId){var pass=WebGPU.mgrComputePassEncoder.get(passId);pass["end"]()}function _wgpuComputePassEncoderRelease(id){WebGPU.mgrComputePassEncoder.release(id)}function _wgpuComputePassEncoderSetBindGroup(passId,groupIndex,groupId,dynamicOffsetCount,dynamicOffsetsPtr){var pass=WebGPU.mgrComputePassEncoder.get(passId);var group=WebGPU.mgrBindGroup.get(groupId);if(dynamicOffsetCount==0){pass["setBindGroup"](groupIndex,group)}else{var offsets=[];for(var i=0;i>2])}pass["setBindGroup"](groupIndex,group,offsets)}}function _wgpuComputePassEncoderSetPipeline(passId,pipelineId){var pass=WebGPU.mgrComputePassEncoder.get(passId);var pipeline=WebGPU.mgrComputePipeline.get(pipelineId);pass["setPipeline"](pipeline)}function _wgpuComputePipelineGetBindGroupLayout(pipelineId,groupIndex){var pipeline=WebGPU.mgrComputePipeline.get(pipelineId);return WebGPU.mgrBindGroupLayout.create(pipeline["getBindGroupLayout"](groupIndex))}function _wgpuComputePipelineRelease(id){WebGPU.mgrComputePipeline.release(id)}function _wgpuDeviceCreateBindGroup(deviceId,descriptor){function makeEntry(entryPtr){var bufferId=HEAPU32[entryPtr+8>>2];var samplerId=HEAPU32[entryPtr+32>>2];var textureViewId=HEAPU32[entryPtr+36>>2];var binding=HEAPU32[entryPtr+4>>2];if(bufferId){var size_low=HEAP32[entryPtr+24>>2];var size_high=HEAP32[entryPtr+28>>2];var size=size_high===-1&&size_low===-1?undefined:convertI32PairToI53(size_low,size_high);return{"binding":binding,"resource":{"buffer":WebGPU.mgrBuffer.get(bufferId),"offset":HEAPU32[entryPtr+4+16>>2]*4294967296+HEAPU32[entryPtr+16>>2],"size":size}}}else if(samplerId){return{"binding":binding,"resource":WebGPU.mgrSampler.get(samplerId)}}else{return{"binding":binding,"resource":WebGPU.mgrTextureView.get(textureViewId)}}}function makeEntries(count,entriesPtrs){var entries=[];for(var i=0;i>2]),"entries":makeEntries(HEAPU32[descriptor+12>>2],HEAPU32[descriptor+16>>2])};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrBindGroup.create(device["createBindGroup"](desc))}function _wgpuDeviceCreateBuffer(deviceId,descriptor){var mappedAtCreation=HEAP8[descriptor+24>>0]!==0;var desc={"label":undefined,"usage":HEAPU32[descriptor+8>>2],"size":HEAPU32[descriptor+4+16>>2]*4294967296+HEAPU32[descriptor+16>>2],"mappedAtCreation":mappedAtCreation};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var device=WebGPU.mgrDevice.get(deviceId);var bufferWrapper={};var id=WebGPU.mgrBuffer.create(device["createBuffer"](desc),bufferWrapper);if(mappedAtCreation){bufferWrapper.mapMode=2;bufferWrapper.onUnmap=[]}return id}function _wgpuDeviceCreateCommandEncoder(deviceId,descriptor){var desc;if(descriptor){desc={"label":undefined};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr)}var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrCommandEncoder.create(device["createCommandEncoder"](desc))}function _wgpuDeviceCreateComputePipeline(deviceId,descriptor){var desc={"label":undefined,"layout":WebGPU.makePipelineLayout(HEAPU32[descriptor+8>>2]),"compute":WebGPU.makeProgrammableStageDescriptor(descriptor+12)};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrComputePipeline.create(device["createComputePipeline"](desc))}function _wgpuDeviceCreateRenderPipeline(deviceId,descriptor){function makePrimitiveState(rsPtr){if(!rsPtr)return undefined;return{"topology":WebGPU.PrimitiveTopology[HEAPU32[rsPtr+4>>2]],"stripIndexFormat":WebGPU.IndexFormat[HEAPU32[rsPtr+8>>2]],"frontFace":WebGPU.FrontFace[HEAPU32[rsPtr+12>>2]],"cullMode":WebGPU.CullMode[HEAPU32[rsPtr+16>>2]]}}function makeBlendComponent(bdPtr){if(!bdPtr)return undefined;return{"operation":WebGPU.BlendOperation[HEAPU32[bdPtr>>2]],"srcFactor":WebGPU.BlendFactor[HEAPU32[bdPtr+4>>2]],"dstFactor":WebGPU.BlendFactor[HEAPU32[bdPtr+8>>2]]}}function makeBlendState(bsPtr){if(!bsPtr)return undefined;return{"alpha":makeBlendComponent(bsPtr+12),"color":makeBlendComponent(bsPtr+0)}}function makeColorState(csPtr){var formatInt=HEAPU32[csPtr+4>>2];return formatInt===0?undefined:{"format":WebGPU.TextureFormat[formatInt],"blend":makeBlendState(HEAPU32[csPtr+8>>2]),"writeMask":HEAPU32[csPtr+12>>2]}}function makeColorStates(count,csArrayPtr){var states=[];for(var i=0;i>2]],"failOp":WebGPU.StencilOperation[HEAPU32[ssfPtr+4>>2]],"depthFailOp":WebGPU.StencilOperation[HEAPU32[ssfPtr+8>>2]],"passOp":WebGPU.StencilOperation[HEAPU32[ssfPtr+12>>2]]}}function makeDepthStencilState(dssPtr){if(!dssPtr)return undefined;return{"format":WebGPU.TextureFormat[HEAPU32[dssPtr+4>>2]],"depthWriteEnabled":HEAP8[dssPtr+8>>0]!==0,"depthCompare":WebGPU.CompareFunction[HEAPU32[dssPtr+12>>2]],"stencilFront":makeStencilStateFace(dssPtr+16),"stencilBack":makeStencilStateFace(dssPtr+32),"stencilReadMask":HEAPU32[dssPtr+48>>2],"stencilWriteMask":HEAPU32[dssPtr+52>>2],"depthBias":HEAPU32[dssPtr+56>>2],"depthBiasSlopeScale":HEAPF32[dssPtr+60>>2],"depthBiasClamp":HEAPF32[dssPtr+64>>2]}}function makeVertexAttribute(vaPtr){return{"format":WebGPU.VertexFormat[HEAPU32[vaPtr>>2]],"offset":HEAPU32[vaPtr+4+8>>2]*4294967296+HEAPU32[vaPtr+8>>2],"shaderLocation":HEAPU32[vaPtr+16>>2]}}function makeVertexAttributes(count,vaArrayPtr){var vas=[];for(var i=0;i>2];return stepModeInt===2?null:{"arrayStride":HEAPU32[vbPtr+4>>2]*4294967296+HEAPU32[vbPtr>>2],"stepMode":WebGPU.VertexStepMode[stepModeInt],"attributes":makeVertexAttributes(HEAPU32[vbPtr+12>>2],HEAPU32[vbPtr+16>>2])}}function makeVertexBuffers(count,vbArrayPtr){if(!count)return undefined;var vbs=[];for(var i=0;i>2]),"entryPoint":UTF8ToString(HEAPU32[viPtr+8>>2]),"constants":WebGPU.makePipelineConstants(HEAPU32[viPtr+12>>2],HEAPU32[viPtr+16>>2]),"buffers":makeVertexBuffers(HEAPU32[viPtr+20>>2],HEAPU32[viPtr+24>>2])}}function makeMultisampleState(msPtr){if(!msPtr)return undefined;return{"count":HEAPU32[msPtr+4>>2],"mask":HEAPU32[msPtr+8>>2],"alphaToCoverageEnabled":HEAP8[msPtr+12>>0]!==0}}function makeFragmentState(fsPtr){if(!fsPtr)return undefined;return{"module":WebGPU.mgrShaderModule.get(HEAPU32[fsPtr+4>>2]),"entryPoint":UTF8ToString(HEAPU32[fsPtr+8>>2]),"constants":WebGPU.makePipelineConstants(HEAPU32[fsPtr+12>>2],HEAPU32[fsPtr+16>>2]),"targets":makeColorStates(HEAPU32[fsPtr+20>>2],HEAPU32[fsPtr+24>>2])}}var desc={"label":undefined,"layout":WebGPU.makePipelineLayout(HEAPU32[descriptor+8>>2]),"vertex":makeVertexState(descriptor+12),"primitive":makePrimitiveState(descriptor+40),"depthStencil":makeDepthStencilState(HEAPU32[descriptor+60>>2]),"multisample":makeMultisampleState(descriptor+64),"fragment":makeFragmentState(HEAPU32[descriptor+80>>2])};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrRenderPipeline.create(device["createRenderPipeline"](desc))}function _wgpuDeviceCreateSampler(deviceId,descriptor){var desc={"label":undefined,"addressModeU":WebGPU.AddressMode[HEAPU32[descriptor+8>>2]],"addressModeV":WebGPU.AddressMode[HEAPU32[descriptor+12>>2]],"addressModeW":WebGPU.AddressMode[HEAPU32[descriptor+16>>2]],"magFilter":WebGPU.FilterMode[HEAPU32[descriptor+20>>2]],"minFilter":WebGPU.FilterMode[HEAPU32[descriptor+24>>2]],"mipmapFilter":WebGPU.FilterMode[HEAPU32[descriptor+28>>2]],"lodMinClamp":HEAPF32[descriptor+32>>2],"lodMaxClamp":HEAPF32[descriptor+36>>2],"compare":WebGPU.CompareFunction[HEAPU32[descriptor+40>>2]]};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrSampler.create(device["createSampler"](desc))}function _wgpuDeviceCreateShaderModule(deviceId,descriptor){var nextInChainPtr=HEAPU32[descriptor>>2];var sType=HEAPU32[nextInChainPtr+4>>2];var desc={"label":undefined,"code":""};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);switch(sType){case 5:{var count=HEAPU32[nextInChainPtr+8>>2];var start=HEAPU32[nextInChainPtr+12>>2];desc["code"]=HEAPU32.subarray(start>>2,(start>>2)+count);break}case 6:{var sourcePtr=HEAPU32[nextInChainPtr+8>>2];if(sourcePtr){desc["code"]=UTF8ToString(sourcePtr)}break}}var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrShaderModule.create(device["createShaderModule"](desc))}function _wgpuDeviceCreateTexture(deviceId,descriptor){var desc={"label":undefined,"size":WebGPU.makeExtent3D(descriptor+16),"mipLevelCount":HEAPU32[descriptor+32>>2],"sampleCount":HEAPU32[descriptor+36>>2],"dimension":WebGPU.TextureDimension[HEAPU32[descriptor+12>>2]],"format":WebGPU.TextureFormat[HEAPU32[descriptor+28>>2]],"usage":HEAPU32[descriptor+8>>2]};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var viewFormatCount=HEAPU32[descriptor+40>>2];if(viewFormatCount){var viewFormatsPtr=HEAPU32[descriptor+44>>2];desc["viewFormats"]=Array.from(HEAP32.subarray(viewFormatsPtr>>2,(viewFormatsPtr>>2)+viewFormatCount),function(format){return WebGPU.TextureFormat[format]})}var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrTexture.create(device["createTexture"](desc))}function _wgpuDeviceGetQueue(deviceId){var queueId=WebGPU.mgrDevice.objects[deviceId].queueId;WebGPU.mgrQueue.reference(queueId);return queueId}function _wgpuDeviceReference(id){WebGPU.mgrDevice.reference(id)}function _wgpuDeviceRelease(id){WebGPU.mgrDevice.release(id)}function _wgpuPipelineLayoutRelease(id){WebGPU.mgrPipelineLayout.release(id)}function _wgpuQuerySetRelease(id){WebGPU.mgrQuerySet.release(id)}function _wgpuQueueRelease(id){WebGPU.mgrQueue.release(id)}function _wgpuQueueSubmit(queueId,commandCount,commands){var queue=WebGPU.mgrQueue.get(queueId);var cmds=Array.from(HEAP32.subarray(commands>>2,(commands>>2)+commandCount),function(id){return WebGPU.mgrCommandBuffer.get(id)});queue["submit"](cmds)}function _wgpuQueueWriteBuffer(queueId,bufferId,bufferOffset_low,bufferOffset_high,data,size){var bufferOffset=convertI32PairToI53Checked(bufferOffset_low,bufferOffset_high);if(isNaN(bufferOffset))return undefined;var queue=WebGPU.mgrQueue.get(queueId);var buffer=WebGPU.mgrBuffer.get(bufferId);var subarray=HEAPU8.subarray(data,data+size);queue["writeBuffer"](buffer,bufferOffset,subarray,0,size)}function _wgpuRenderPassEncoderDraw(passId,vertexCount,instanceCount,firstVertex,firstInstance){var pass=WebGPU.mgrRenderPassEncoder.get(passId);pass["draw"](vertexCount,instanceCount,firstVertex,firstInstance)}function _wgpuRenderPassEncoderEnd(passId){var pass=WebGPU.mgrRenderPassEncoder.get(passId);pass["end"]()}function _wgpuRenderPassEncoderRelease(id){WebGPU.mgrRenderPassEncoder.release(id)}function _wgpuRenderPassEncoderSetBindGroup(passId,groupIndex,groupId,dynamicOffsetCount,dynamicOffsetsPtr){var pass=WebGPU.mgrRenderPassEncoder.get(passId);var group=WebGPU.mgrBindGroup.get(groupId);if(dynamicOffsetCount==0){pass["setBindGroup"](groupIndex,group)}else{var offsets=[];for(var i=0;i>2])}pass["setBindGroup"](groupIndex,group,offsets)}}function _wgpuRenderPassEncoderSetPipeline(passId,pipelineId){var pass=WebGPU.mgrRenderPassEncoder.get(passId);var pipeline=WebGPU.mgrRenderPipeline.get(pipelineId);pass["setPipeline"](pipeline)}function _wgpuRenderPipelineGetBindGroupLayout(pipelineId,groupIndex){var pipeline=WebGPU.mgrRenderPipeline.get(pipelineId);return WebGPU.mgrBindGroupLayout.create(pipeline["getBindGroupLayout"](groupIndex))}function _wgpuRenderPipelineRelease(id){WebGPU.mgrRenderPipeline.release(id)}function _wgpuSamplerReference(id){WebGPU.mgrSampler.reference(id)}function _wgpuSamplerRelease(id){WebGPU.mgrSampler.release(id)}function _wgpuShaderModuleReference(id){WebGPU.mgrShaderModule.reference(id)}function _wgpuShaderModuleRelease(id){WebGPU.mgrShaderModule.release(id)}function _wgpuTextureCreateView(textureId,descriptor){var desc;if(descriptor){var mipLevelCount=HEAPU32[descriptor+20>>2];var arrayLayerCount=HEAPU32[descriptor+28>>2];desc={"format":WebGPU.TextureFormat[HEAPU32[descriptor+8>>2]],"dimension":WebGPU.TextureViewDimension[HEAPU32[descriptor+12>>2]],"baseMipLevel":HEAPU32[descriptor+16>>2],"mipLevelCount":mipLevelCount===4294967295?undefined:mipLevelCount,"baseArrayLayer":HEAPU32[descriptor+24>>2],"arrayLayerCount":arrayLayerCount===4294967295?undefined:arrayLayerCount,"aspect":WebGPU.TextureAspect[HEAPU32[descriptor+32>>2]]};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr)}var texture=WebGPU.mgrTexture.get(textureId);return WebGPU.mgrTextureView.create(texture["createView"](desc))}function _wgpuTextureDestroy(textureId){WebGPU.mgrTexture.get(textureId)["destroy"]()}function _wgpuTextureReference(id){WebGPU.mgrTexture.reference(id)}function _wgpuTextureRelease(id){WebGPU.mgrTexture.release(id)}function _wgpuTextureViewReference(id){WebGPU.mgrTextureView.reference(id)}function _wgpuTextureViewRelease(id){WebGPU.mgrTextureView.release(id)}function getCFunc(ident){var func=Module["_"+ident];return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},"array":arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run(); return ModuleFactory.ready } ); })(); if (typeof exports === 'object' && typeof module === 'object') module.exports = ModuleFactory; else if (typeof define === 'function' && define['amd']) define([], function() { return ModuleFactory; }); else if (typeof exports === 'object') exports["ModuleFactory"] = ModuleFactory; ================================================ FILE: extern/wasm/vision_wasm_nosimd_internal.js ================================================ // Build 551939664 var ModuleFactory = (() => { var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; return ( function(ModuleFactory = {}) { var Module=typeof ModuleFactory!="undefined"?ModuleFactory:{};var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");if(ENVIRONMENT_IS_WORKER){scriptDirectory=nodePath.dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)onerror(err);else onload(binary?data.buffer:data)})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow};Module["inspect"]=()=>"[Emscripten Module object]"}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=title=>document.title=title}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||true;if(typeof WebAssembly!="object"){abort("no native wasm support detected")}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeKeepaliveCounter=0;function keepRuntimeAlive(){return noExitRuntime||runtimeKeepaliveCounter>0}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}function isFileURI(filename){return filename.startsWith("file://")}var wasmBinaryFile;wasmBinaryFile="vision_wasm_nosimd_internal.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(file){try{if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}catch(err){abort(err)}}function getBinaryPromise(binaryFile){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"&&!isFileURI(binaryFile)){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{if(!response["ok"]){throw"failed to load wasm binary file at '"+binaryFile+"'"}return response["arrayBuffer"]()}).catch(()=>getBinary(binaryFile))}else{if(readAsync){return new Promise((resolve,reject)=>{readAsync(binaryFile,response=>resolve(new Uint8Array(response)),reject)})}}}return Promise.resolve().then(()=>getBinary(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>{return WebAssembly.instantiate(binary,imports)}).then(instance=>{return instance}).then(receiver,reason=>{err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}else{return instantiateArrayBuffer(binaryFile,imports,callback)}}function createWasm(){var info={"a":wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;wasmMemory=Module["asm"]["od"];updateMemoryViews();wasmTable=Module["asm"]["qd"];addOnInit(Module["asm"]["pd"]);removeRunDependency("wasm-instantiate");return exports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err("Module.instantiateWasm callback failed with error: "+e);readyPromiseReject(e)}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var tempDouble;var tempI64;var ASM_CONSTS={1188450:$0=>{const canvas=Emval.toValue($0);const context=canvas.getContext("webgpu");return JsValStore.add(context.getCurrentTexture())},1188585:($0,$1,$2,$3,$4)=>{const drawable=Emval.toValue($0);const device=JsValStore.get($1);const texture=JsValStore.get($2);const width=$3;const height=$4;device.queue.copyExternalImageToTexture({source:drawable},{texture:texture},[width,height])},1188836:($0,$1,$2,$3)=>{const sourceExtTex=Emval.toValue($0);const device=JsValStore.get($1);const sampler=JsValStore.get($2);const bgLayout=JsValStore.get($3);const bindGroup=device.createBindGroup({layout:bgLayout,entries:[{binding:0,resource:sampler},{binding:1,resource:sourceExtTex}]});return JsValStore.add(bindGroup)},1189184:($0,$1)=>{const inputArray=Emval.toValue($0);const output=Emval.toValue($1);const ctx=output.getContext("2d");const image_data=new ImageData(inputArray,output.width,output.height);ctx.putImageData(image_data,0,0)},1189408:($0,$1)=>{const input=Emval.toValue($0);const outputArray=Emval.toValue($1);const ctx=input.getContext("2d");const data=ctx.getImageData(0,0,input.width,input.height);outputArray.set(data.data)},1189612:($0,$1)=>{const input=Emval.toValue($0);const output=Emval.toValue($1);const ctx=output.getContext("2d");ctx.drawImage(input,0,0)},1189748:()=>{return typeof HTMLCanvasElement!=="undefined"},1189803:()=>{return!!Module["preinitializedWebGPUDevice"]},1189854:()=>{specialHTMLTargets["#canvas"]=Module.canvas},1189905:()=>{return typeof wasmOffsetConverter!=="undefined"}};function JsWrapImageConverter(){if(!Module._imageConverter){Module._imageConverter=(binaryPtr,binarySize,width,height,numChannels,makeDeepCopy,outputType)=>{const imageData=new outputType(makeDeepCopy?Module.HEAPU8.slice(binaryPtr,binaryPtr+binarySize).buffer:Module.HEAPU8.buffer,binaryPtr,width*height*numChannels);return{data:imageData,width:width,height:height}}}}function JsOnUint8ArrayImageListener(output_stream_name,binary_ptr,binary_size,width,height,num_channels,make_deep_copy,timestamp_ms){const image=Module._imageConverter(binary_ptr,binary_size,width,height,num_channels,make_deep_copy,Uint8Array);Module._wrapSimpleListenerOutput(output_stream_name,image,timestamp_ms)}function JsOnFloat32ArrayImageListener(output_stream_name,binary_ptr,binary_size,width,height,num_channels,make_deep_copy,timestamp_ms){const image=Module._imageConverter(binary_ptr,binary_size,width,height,num_channels,make_deep_copy,Float32Array);Module._wrapSimpleListenerOutput(output_stream_name,image,timestamp_ms)}function JsOnWebGLTextureListener(output_stream_name,name,width,height,timestamp_ms){Module._wrapSimpleListenerOutput(output_stream_name,{data:GL.textures[name],width:width,height:height},timestamp_ms)}function JsOnUint8ArrayImageVectorListener(output_stream_name,binary_ptr,binary_size,width,height,num_channels,make_deep_copy,timestamp_ms){const image=Module._imageConverter(binary_ptr,binary_size,width,height,num_channels,make_deep_copy,Uint8Array);Module._wrapSimpleListenerOutput(output_stream_name,image,false,timestamp_ms)}function JsOnFloat32ArrayImageVectorListener(output_stream_name,binary_ptr,binary_size,width,height,num_channels,make_deep_copy,timestamp_ms){const image=Module._imageConverter(binary_ptr,binary_size,width,height,num_channels,make_deep_copy,Float32Array);Module._wrapSimpleListenerOutput(output_stream_name,image,false,timestamp_ms)}function JsOnWebGLTextureVectorListener(output_stream_name,name,width,height,timestamp_ms){Module._wrapSimpleListenerOutput(output_stream_name,{data:GL.textures[name],width:width,height:height},false,timestamp_ms)}function JsOnEmptyPacketListener(output_stream_name,timestamp){Module._wrapEmptyPacketListenerOutput(output_stream_name,timestamp)}function JsOnVectorFinishedListener(output_stream_name,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,undefined,true,timestamp)}function JsOnSimpleListenerBool(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,timestamp)}function JsOnVectorListenerBool(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,false,timestamp)}function JsOnSimpleListenerInt(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,timestamp)}function JsOnVectorListenerInt(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,false,timestamp)}function JsOnSimpleListenerDouble(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,timestamp)}function JsOnVectorListenerDouble(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,false,timestamp)}function JsOnSimpleListenerFloat(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,timestamp)}function JsOnVectorListenerFloat(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,out_data,false,timestamp)}function JsOnSimpleListenerString(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,UTF8ToString(out_data),timestamp)}function JsOnVectorListenerString(output_stream_name,out_data,timestamp){Module._wrapSimpleListenerOutput(output_stream_name,UTF8ToString(out_data),false,timestamp)}function JsOnVectorListenerProto(output_stream_name,proto_ptr,proto_size,make_deep_copy,timestamp){const newProtoArray=make_deep_copy?Module.HEAPU8.slice(proto_ptr,proto_ptr+proto_size):new Uint8Array(Module.HEAPU8.buffer,proto_ptr,proto_size);Module._wrapSimpleListenerOutput(output_stream_name,newProtoArray,false,timestamp)}function JsWrapSimpleListeners(){if(!Module._wrapSimpleListenerOutput){Module._wrapSimpleListenerOutput=(outputStreamName,...args)=>{if(Module.simpleListeners){const streamName=UTF8ToString(outputStreamName);if(Module.simpleListeners[streamName]){Module.simpleListeners[streamName](...args)}}}}if(!Module._wrapEmptyPacketListenerOutput){Module._wrapEmptyPacketListenerOutput=(outputStreamName,timestamp)=>{if(Module.emptyPacketListeners){const streamName=UTF8ToString(outputStreamName);if(Module.emptyPacketListeners[streamName]){Module.emptyPacketListeners[streamName](timestamp)}}}}}function JsOnSimpleListenerBinaryArray(output_stream_name,binary_ptr,binary_size,make_deep_copy,timestamp){const newProtoArray=make_deep_copy?Module.HEAPU8.slice(binary_ptr,binary_ptr+binary_size):new Uint8Array(Module.HEAPU8.buffer,binary_ptr,binary_size);Module._wrapSimpleListenerOutput(output_stream_name,newProtoArray,timestamp)}function mediapipe_import_external_texture(device_handle,source_handle){const device=WebGPU.mgrDevice.get(device_handle);const source=Emval.toValue(source_handle);const externalTexture=device.importExternalTexture({source:source});return Emval.toHandle(externalTexture)}function mediapipe_create_utility_canvas2d(){let canvas;if(typeof OffscreenCanvas!=="undefined"){canvas=new OffscreenCanvas(0,0)}else{canvas=document.createElement("canvas");canvas.style.display="none";canvas.id="canvas_2d";document.body.appendChild(canvas)}return Emval.toHandle(canvas)}function xnnLoadWasmModuleJS(code,offset,offset_end,invalid_function_index){const tableOriginalSize=wasmTable.length;const binary=new Uint8Array(HEAPU8.slice(code+offset,code+offset_end));try{var module=new WebAssembly.Module(binary);var instance=new WebAssembly.Instance(module,{env:{memory:wasmMemory}});for(var symName in instance.exports){var value=instance.exports[symName];addFunction(value)}if(tableOriginalSize{if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",Browser_setImmediate_messageHandler,true);setImmediate=function Browser_emulated_setImmediate(func){setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){if(Module["setImmediates"]===undefined)Module["setImmediates"]=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setImmediate(){setImmediate(Browser.mainLoop.runner)};Browser.mainLoop.method="immediate"}return 0}var _emscripten_get_now;if(ENVIRONMENT_IS_NODE){global.performance=require("perf_hooks").performance}_emscripten_get_now=()=>performance.now();function setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop,arg,noSetTiming){assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.");Browser.mainLoop.func=browserIterationFunc;Browser.mainLoop.arg=arg;var thisMainLoopId=Browser.mainLoop.currentlyRunningMainloop;function checkIsRunning(){if(thisMainLoopId0){var start=Date.now();var blocker=Browser.mainLoop.queue.shift();blocker.func(blocker.arg);if(Browser.mainLoop.remainingBlockers){var remaining=Browser.mainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){Browser.mainLoop.remainingBlockers=next}else{next=next+.5;Browser.mainLoop.remainingBlockers=(8*remaining+next)/9}}out('main loop blocker "'+blocker.name+'" took '+(Date.now()-start)+" ms");Browser.mainLoop.updateStatus();if(!checkIsRunning())return;setTimeout(Browser.mainLoop.runner,0);return}if(!checkIsRunning())return;Browser.mainLoop.currentFrameNumber=Browser.mainLoop.currentFrameNumber+1|0;if(Browser.mainLoop.timingMode==1&&Browser.mainLoop.timingValue>1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else if(Browser.mainLoop.timingMode==0){Browser.mainLoop.tickStartTime=_emscripten_get_now()}GL.newRenderingFrameStarted();Browser.mainLoop.runIter(browserIterationFunc);if(!checkIsRunning())return;if(typeof SDL=="object"&&SDL.audio&&SDL.audio.queueNewAudioData)SDL.audio.queueNewAudioData();Browser.mainLoop.scheduler()};if(!noSetTiming){if(fps&&fps>0){_emscripten_set_main_loop_timing(0,1e3/fps)}else{_emscripten_set_main_loop_timing(1,1)}Browser.mainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}}function handleException(e){if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)}function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:function(){var paths=Array.prototype.slice.call(arguments);return PATH.normalize(paths.join("/"))},join2:(l,r)=>{return PATH.normalize(l+"/"+r)}};function initRandomFill(){if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")}function randomFill(view){return(randomFill=initRandomFill())(view)}var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(heapOrArray,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str}var TTY={ttys:[],init:function(){},shutdown:function(){},register:function(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open:function(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close:function(stream){stream.tty.ops.fsync(stream.tty)},fsync:function(stream){stream.tty.ops.fsync(stream.tty)},read:function(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};function zeroMemory(address,size){HEAPU8.fill(0,address,address+size);return address}function alignMemory(size,alignment){return Math.ceil(size/alignment)*alignment}function mmapAlloc(size){size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(!ptr)return 0;return zeroMemory(ptr,size)}var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray:function(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage:function(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr:function(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr:function(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup:function(parent,name){throw FS.genericErrors[44]},mknod:function(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename:function(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink:function(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir:function(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir:function(node){var entries=[".",".."];for(var key in node.contents){if(!node.contents.hasOwnProperty(key)){continue}entries.push(key)}return entries},symlink:function(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink:function(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read:function(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{assert(arrayBuffer,`Loading data file "${url}" failed (no arrayBuffer).`);onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},event=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)}var preloadPlugins=Module["preloadPlugins"]||[];function FS_handledByPreloadPlugin(byteArray,fullname,finish,onerror){if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(function(plugin){if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled}function FS_createPreloadedFile(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish){var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){if(preFinish)preFinish();if(!dontCreateFile){FS.createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}if(onload)onload();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{if(onerror)onerror();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,byteArray=>processData(byteArray),onerror)}else{processData(url)}}function FS_modeStringToFlags(str){var flagModes={"r":0,"r+":2,"w":512|64|1,"w+":512|64|2,"a":1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags}function FS_getMode(canRead,canWrite){var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode}var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath:(path,opts={})=>{path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:node=>{var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName:(parentid,name)=>{var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:node=>{var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:node=>{var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode:(parent,name)=>{var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode:(parent,name,mode,rdev)=>{var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:node=>{FS.hashRemoveNode(node)},isRoot:node=>{return node===node.parent},isMountpoint:node=>{return!!node.mounted},isFile:mode=>{return(mode&61440)===32768},isDir:mode=>{return(mode&61440)===16384},isLink:mode=>{return(mode&61440)===40960},isChrdev:mode=>{return(mode&61440)===8192},isBlkdev:mode=>{return(mode&61440)===24576},isFIFO:mode=>{return(mode&61440)===4096},isSocket:mode=>{return(mode&49152)===49152},flagsToPermissionString:flag=>{var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:(node,perms)=>{if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup:dir=>{var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:(dir,name)=>{try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:(dir,name,isdir)=>{var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:(node,flags)=>{if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:()=>{for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:fd=>FS.streams[fd],createStream:(stream,fd=-1)=>{if(!FS.FSStream){FS.FSStream=function(){this.shared={}};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}},flags:{get:function(){return this.shared.flags},set:function(val){this.shared.flags=val}},position:{get:function(){return this.shared.position},set:function(val){this.shared.position=val}}})}stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:fd=>{FS.streams[fd]=null},chrdev_stream_ops:{open:stream=>{var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:()=>{throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice:(dev,ops)=>{FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts:mount=>{var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:(populate,callback)=>{if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:(type,opts,mountpoint)=>{var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:mountpoint=>{var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:(parent,name)=>{return parent.node_ops.lookup(parent,name)},mknod:(path,mode,dev)=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:(path,mode)=>{mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:(path,mode)=>{mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:(path,mode)=>{var dirs=path.split("/");var d="";for(var i=0;i{if(typeof dev=="undefined"){dev=mode;mode=438}mode|=8192;return FS.mknod(path,mode,dev)},symlink:(oldpath,newpath)=>{if(!PATH_FS.resolve(oldpath)){throw new FS.ErrnoError(44)}var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.symlink){throw new FS.ErrnoError(63)}return parent.node_ops.symlink(parent,newname,oldpath)},rename:(old_path,new_path)=>{var old_dirname=PATH.dirname(old_path);var new_dirname=PATH.dirname(new_path);var old_name=PATH.basename(old_path);var new_name=PATH.basename(new_path);var lookup,old_dir,new_dir;lookup=FS.lookupPath(old_path,{parent:true});old_dir=lookup.node;lookup=FS.lookupPath(new_path,{parent:true});new_dir=lookup.node;if(!old_dir||!new_dir)throw new FS.ErrnoError(44);if(old_dir.mount!==new_dir.mount){throw new FS.ErrnoError(75)}var old_node=FS.lookupNode(old_dir,old_name);var relative=PATH_FS.relative(old_path,new_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(28)}relative=PATH_FS.relative(new_path,old_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(55)}var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(old_node===new_node){return}var isdir=FS.isDir(old_node.mode);var errCode=FS.mayDelete(old_dir,old_name,isdir);if(errCode){throw new FS.ErrnoError(errCode)}errCode=new_node?FS.mayDelete(new_dir,new_name,isdir):FS.mayCreate(new_dir,new_name);if(errCode){throw new FS.ErrnoError(errCode)}if(!old_dir.node_ops.rename){throw new FS.ErrnoError(63)}if(FS.isMountpoint(old_node)||new_node&&FS.isMountpoint(new_node)){throw new FS.ErrnoError(10)}if(new_dir!==old_dir){errCode=FS.nodePermissions(old_dir,"w");if(errCode){throw new FS.ErrnoError(errCode)}}FS.hashRemoveNode(old_node);try{old_dir.node_ops.rename(old_node,new_dir,new_name)}catch(e){throw e}finally{FS.hashAddNode(old_node)}},rmdir:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,true);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.rmdir){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.rmdir(parent,name);FS.destroyNode(node)},readdir:path=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node.node_ops.readdir){throw new FS.ErrnoError(54)}return node.node_ops.readdir(node)},unlink:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,false);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.unlink){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.unlink(parent,name);FS.destroyNode(node)},readlink:path=>{var lookup=FS.lookupPath(path);var link=lookup.node;if(!link){throw new FS.ErrnoError(44)}if(!link.node_ops.readlink){throw new FS.ErrnoError(28)}return PATH_FS.resolve(FS.getPath(link.parent),link.node_ops.readlink(link))},stat:(path,dontFollow)=>{var lookup=FS.lookupPath(path,{follow:!dontFollow});var node=lookup.node;if(!node){throw new FS.ErrnoError(44)}if(!node.node_ops.getattr){throw new FS.ErrnoError(63)}return node.node_ops.getattr(node)},lstat:path=>{return FS.stat(path,true)},chmod:(path,mode,dontFollow)=>{var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}node.node_ops.setattr(node,{mode:mode&4095|node.mode&~4095,timestamp:Date.now()})},lchmod:(path,mode)=>{FS.chmod(path,mode,true)},fchmod:(fd,mode)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chmod(stream.node,mode)},chown:(path,uid,gid,dontFollow)=>{var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}node.node_ops.setattr(node,{timestamp:Date.now()})},lchown:(path,uid,gid)=>{FS.chown(path,uid,gid,true)},fchown:(fd,uid,gid)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chown(stream.node,uid,gid)},truncate:(path,len)=>{if(len<0){throw new FS.ErrnoError(28)}var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:true});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}if(FS.isDir(node.mode)){throw new FS.ErrnoError(31)}if(!FS.isFile(node.mode)){throw new FS.ErrnoError(28)}var errCode=FS.nodePermissions(node,"w");if(errCode){throw new FS.ErrnoError(errCode)}node.node_ops.setattr(node,{size:len,timestamp:Date.now()})},ftruncate:(fd,len)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(28)}FS.truncate(stream.node,len)},utime:(path,atime,mtime)=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;node.node_ops.setattr(node,{timestamp:Math.max(atime,mtime)})},open:(path,flags,mode)=>{if(path===""){throw new FS.ErrnoError(44)}flags=typeof flags=="string"?FS_modeStringToFlags(flags):flags;mode=typeof mode=="undefined"?438:mode;if(flags&64){mode=mode&4095|32768}else{mode=0}var node;if(typeof path=="object"){node=path}else{path=PATH.normalize(path);try{var lookup=FS.lookupPath(path,{follow:!(flags&131072)});node=lookup.node}catch(e){}}var created=false;if(flags&64){if(node){if(flags&128){throw new FS.ErrnoError(20)}}else{node=FS.mknod(path,mode,0);created=true}}if(!node){throw new FS.ErrnoError(44)}if(FS.isChrdev(node.mode)){flags&=~512}if(flags&65536&&!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}if(!created){var errCode=FS.mayOpen(node,flags);if(errCode){throw new FS.ErrnoError(errCode)}}if(flags&512&&!created){FS.truncate(node,0)}flags&=~(128|512|131072);var stream=FS.createStream({node:node,path:FS.getPath(node),flags:flags,seekable:true,position:0,stream_ops:node.stream_ops,ungotten:[],error:false});if(stream.stream_ops.open){stream.stream_ops.open(stream)}if(Module["logReadFiles"]&&!(flags&1)){if(!FS.readFiles)FS.readFiles={};if(!(path in FS.readFiles)){FS.readFiles[path]=1}}return stream},close:stream=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(stream.getdents)stream.getdents=null;try{if(stream.stream_ops.close){stream.stream_ops.close(stream)}}catch(e){throw e}finally{FS.closeStream(stream.fd)}stream.fd=null},isClosed:stream=>{return stream.fd===null},llseek:(stream,offset,whence)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(!stream.seekable||!stream.stream_ops.llseek){throw new FS.ErrnoError(70)}if(whence!=0&&whence!=1&&whence!=2){throw new FS.ErrnoError(28)}stream.position=stream.stream_ops.llseek(stream,offset,whence);stream.ungotten=[];return stream.position},read:(stream,buffer,offset,length,position)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.read){throw new FS.ErrnoError(28)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesRead=stream.stream_ops.read(stream,buffer,offset,length,position);if(!seeking)stream.position+=bytesRead;return bytesRead},write:(stream,buffer,offset,length,position,canOwn)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.write){throw new FS.ErrnoError(28)}if(stream.seekable&&stream.flags&1024){FS.llseek(stream,0,2)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesWritten=stream.stream_ops.write(stream,buffer,offset,length,position,canOwn);if(!seeking)stream.position+=bytesWritten;return bytesWritten},allocate:(stream,offset,length)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(offset<0||length<=0){throw new FS.ErrnoError(28)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(!FS.isFile(stream.node.mode)&&!FS.isDir(stream.node.mode)){throw new FS.ErrnoError(43)}if(!stream.stream_ops.allocate){throw new FS.ErrnoError(138)}stream.stream_ops.allocate(stream,offset,length)},mmap:(stream,length,position,prot,flags)=>{if((prot&2)!==0&&(flags&2)===0&&(stream.flags&2097155)!==2){throw new FS.ErrnoError(2)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(2)}if(!stream.stream_ops.mmap){throw new FS.ErrnoError(43)}return stream.stream_ops.mmap(stream,length,position,prot,flags)},msync:(stream,buffer,offset,length,mmapFlags)=>{if(!stream.stream_ops.msync){return 0}return stream.stream_ops.msync(stream,buffer,offset,length,mmapFlags)},munmap:stream=>0,ioctl:(stream,cmd,arg)=>{if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile:(path,opts={})=>{opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){throw new Error(`Invalid encoding type "${opts.encoding}"`)}var ret;var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){ret=UTF8ArrayToString(buf,0)}else if(opts.encoding==="binary"){ret=buf}FS.close(stream);return ret},writeFile:(path,data,opts={})=>{opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn)}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn)}else{throw new Error("Unsupported data type")}FS.close(stream)},cwd:()=>FS.currentPath,chdir:path=>{var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories:()=>{FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices:()=>{FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories:()=>{FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount:()=>{var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup:(parent,name)=>{var fd=+name;var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams:()=>{if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},ensureErrnoError:()=>{if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.name="ErrnoError";this.node=node;this.setErrno=function(errno){this.errno=errno};this.setErrno(errno);this.message="FS error"};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""})},staticInit:()=>{FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS}},init:(input,output,error)=>{FS.init.initialized=true;FS.ensureErrnoError();Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit:()=>{FS.init.initialized=false;for(var i=0;i{var ret=FS.analyzePath(path,dontResolveLastLink);if(!ret.exists){return null}return ret.object},analyzePath:(path,dontResolveLastLink)=>{try{var lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});path=lookup.path}catch(e){}var ret={isRoot:false,exists:false,error:0,name:null,path:null,object:null,parentExists:false,parentPath:null,parentObject:null};try{var lookup=FS.lookupPath(path,{parent:true});ret.parentExists=true;ret.parentPath=lookup.path;ret.parentObject=lookup.node;ret.name=PATH.basename(path);lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});ret.exists=true;ret.path=lookup.path;ret.object=lookup.node;ret.name=lookup.node.name;ret.isRoot=lookup.path==="/"}catch(e){ret.error=e.errno}return ret},createPath:(parent,path,canRead,canWrite)=>{parent=typeof parent=="string"?parent:FS.getPath(parent);var parts=path.split("/").reverse();while(parts.length){var part=parts.pop();if(!part)continue;var current=PATH.join2(parent,part);try{FS.mkdir(current)}catch(e){}parent=current}return current},createFile:(parent,name,properties,canRead,canWrite)=>{var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS_getMode(canRead,canWrite);return FS.create(path,mode)},createDataFile:(parent,name,data,canRead,canWrite,canOwn)=>{var path=name;if(parent){parent=typeof parent=="string"?parent:FS.getPath(parent);path=name?PATH.join2(parent,name):parent}var mode=FS_getMode(canRead,canWrite);var node=FS.create(path,mode);if(data){if(typeof data=="string"){var arr=new Array(data.length);for(var i=0,len=data.length;i{var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS_getMode(!!input,!!output);if(!FS.createDevice.major)FS.createDevice.major=64;var dev=FS.makedev(FS.createDevice.major++,0);FS.registerDevice(dev,{open:stream=>{stream.seekable=false},close:stream=>{if(output&&output.buffer&&output.buffer.length){output(10)}},read:(stream,buffer,offset,length,pos)=>{var bytesRead=0;for(var i=0;i{for(var i=0;i{if(obj.isDevice||obj.isFolder||obj.link||obj.contents)return true;if(typeof XMLHttpRequest!="undefined"){throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.")}else if(read_){try{obj.contents=intArrayFromString(read_(obj.url),true);obj.usedBytes=obj.contents.length}catch(e){throw new FS.ErrnoError(29)}}else{throw new Error("Cannot load without read() or XMLHttpRequest.")}},createLazyFile:(parent,name,url,canRead,canWrite)=>{function LazyUint8Array(){this.lengthKnown=false;this.chunks=[]}LazyUint8Array.prototype.get=function LazyUint8Array_get(idx){if(idx>this.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt:function(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat:function(func,path,buf){try{var stat=func(path)}catch(e){if(e&&e.node&&PATH.normalize(path)!==PATH.normalize(FS.getPath(e.node))){return-54}throw e}HEAP32[buf>>2]=stat.dev;HEAP32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAP32[buf+12>>2]=stat.uid;HEAP32[buf+16>>2]=stat.gid;HEAP32[buf+20>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>2]=tempI64[0],HEAP32[buf+28>>2]=tempI64[1];HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAPU32[buf+48>>2]=atime%1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>2]=tempI64[0],HEAP32[buf+60>>2]=tempI64[1];HEAPU32[buf+64>>2]=mtime%1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>2]=tempI64[0],HEAP32[buf+76>>2]=tempI64[1];HEAPU32[buf+80>>2]=ctime%1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>2]=tempI64[0],HEAP32[buf+92>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},varargs:undefined,get:function(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream}};function _proc_exit(code){EXITSTATUS=code;if(!keepRuntimeAlive()){if(Module["onExit"])Module["onExit"](code);ABORT=true}quit_(code,new ExitStatus(code))}function exitJS(status,implicit){EXITSTATUS=status;_proc_exit(status)}var _exit=exitJS;function maybeExit(){if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}}function callUserCallback(func){if(ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}}function safeSetTimeout(func,timeout){return setTimeout(()=>{callUserCallback(func)},timeout)}function warnOnce(text){if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;if(ENVIRONMENT_IS_NODE)text="warning: "+text;err(text)}}var Browser={mainLoop:{running:false,scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null;Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var timingMode=Browser.mainLoop.timingMode;var timingValue=Browser.mainLoop.timingValue;var func=Browser.mainLoop.func;Browser.mainLoop.func=null;setMainLoop(func,0,false,Browser.mainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);Browser.mainLoop.scheduler()},updateStatus:function(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=Browser.mainLoop.remainingBlockers;var expected=Browser.mainLoop.expectedBlockers;if(remaining){if(remaining{assert(img.complete,"Image "+name+" could not be decoded");var canvas=document.createElement("canvas");canvas.width=img.width;canvas.height=img.height;var ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);preloadedImages[name]=canvas;URL.revokeObjectURL(url);if(onload)onload(byteArray)};img.onerror=event=>{out("Image "+url+" could not be decoded");if(onerror)onerror()};img.src=url};preloadPlugins.push(imagePlugin);var audioPlugin={};audioPlugin["canHandle"]=function audioPlugin_canHandle(name){return!Module.noAudioDecoding&&name.substr(-4)in{".ogg":1,".wav":1,".mp3":1}};audioPlugin["handle"]=function audioPlugin_handle(byteArray,name,onload,onerror){var done=false;function finish(audio){if(done)return;done=true;preloadedAudios[name]=audio;if(onload)onload(byteArray)}var b=new Blob([byteArray],{type:Browser.getMimetype(name)});var url=URL.createObjectURL(b);var audio=new Audio;audio.addEventListener("canplaythrough",()=>finish(audio),false);audio.onerror=function audio_onerror(event){if(done)return;err("warning: browser could not fully decode audio "+name+", trying slower base64 approach");function encode64(data){var BASE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var PAD="=";var ret="";var leftchar=0;var leftbits=0;for(var i=0;i=6){var curr=leftchar>>leftbits-6&63;leftbits-=6;ret+=BASE[curr]}}if(leftbits==2){ret+=BASE[(leftchar&3)<<4];ret+=PAD+PAD}else if(leftbits==4){ret+=BASE[(leftchar&15)<<2];ret+=PAD}return ret}audio.src="data:audio/x-"+name.substr(-3)+";base64,"+encode64(byteArray);finish(audio)};audio.src=url;safeSetTimeout(()=>{finish(audio)},1e4)};preloadPlugins.push(audioPlugin);function pointerLockChange(){Browser.pointerLock=document["pointerLockElement"]===Module["canvas"]||document["mozPointerLockElement"]===Module["canvas"]||document["webkitPointerLockElement"]===Module["canvas"]||document["msPointerLockElement"]===Module["canvas"]}var canvas=Module["canvas"];if(canvas){canvas.requestPointerLock=canvas["requestPointerLock"]||canvas["mozRequestPointerLock"]||canvas["webkitRequestPointerLock"]||canvas["msRequestPointerLock"]||(()=>{});canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||(()=>{});canvas.exitPointerLock=canvas.exitPointerLock.bind(document);document.addEventListener("pointerlockchange",pointerLockChange,false);document.addEventListener("mozpointerlockchange",pointerLockChange,false);document.addEventListener("webkitpointerlockchange",pointerLockChange,false);document.addEventListener("mspointerlockchange",pointerLockChange,false);if(Module["elementPointerLock"]){canvas.addEventListener("click",ev=>{if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},createContext:function(canvas,useWebGL,setInModule,webGLContextAttributes){if(useWebGL&&Module.ctx&&canvas==Module.canvas)return Module.ctx;var ctx;var contextHandle;if(useWebGL){var contextAttributes={antialias:false,alpha:false,majorVersion:typeof WebGL2RenderingContext!="undefined"?2:1};if(webGLContextAttributes){for(var attribute in webGLContextAttributes){contextAttributes[attribute]=webGLContextAttributes[attribute]}}if(typeof GL!="undefined"){contextHandle=GL.createContext(canvas,contextAttributes);if(contextHandle){ctx=GL.getContext(contextHandle).GLctx}}}else{ctx=canvas.getContext("2d")}if(!ctx)return null;if(setInModule){if(!useWebGL)assert(typeof GLctx=="undefined","cannot set in module if GLctx is used, but we are a non-GL context that would replace it");Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Module.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(callback=>callback());Browser.init()}return ctx},destroyContext:function(canvas,useWebGL,setInModule){},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen:function(lockPointer,resizeCanvas){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;if(typeof Browser.lockPointer=="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas=="undefined")Browser.resizeCanvas=false;var canvas=Module["canvas"];function fullscreenChange(){Browser.isFullscreen=false;var canvasContainer=canvas.parentNode;if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvasContainer){canvas.exitFullscreen=Browser.exitFullscreen;if(Browser.lockPointer)canvas.requestPointerLock();Browser.isFullscreen=true;if(Browser.resizeCanvas){Browser.setFullscreenCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}else{canvasContainer.parentNode.insertBefore(canvas,canvasContainer);canvasContainer.parentNode.removeChild(canvasContainer);if(Browser.resizeCanvas){Browser.setWindowedCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}if(Module["onFullScreen"])Module["onFullScreen"](Browser.isFullscreen);if(Module["onFullscreen"])Module["onFullscreen"](Browser.isFullscreen)}if(!Browser.fullscreenHandlersInstalled){Browser.fullscreenHandlersInstalled=true;document.addEventListener("fullscreenchange",fullscreenChange,false);document.addEventListener("mozfullscreenchange",fullscreenChange,false);document.addEventListener("webkitfullscreenchange",fullscreenChange,false);document.addEventListener("MSFullscreenChange",fullscreenChange,false)}var canvasContainer=document.createElement("div");canvas.parentNode.insertBefore(canvasContainer,canvas);canvasContainer.appendChild(canvas);canvasContainer.requestFullscreen=canvasContainer["requestFullscreen"]||canvasContainer["mozRequestFullScreen"]||canvasContainer["msRequestFullscreen"]||(canvasContainer["webkitRequestFullscreen"]?()=>canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"]):null)||(canvasContainer["webkitRequestFullScreen"]?()=>canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"]):null);canvasContainer.requestFullscreen()},exitFullscreen:function(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||(()=>{});CFS.apply(document,[]);return true},nextRAF:0,fakeRequestAnimationFrame:function(func){var now=Date.now();if(Browser.nextRAF===0){Browser.nextRAF=now+1e3/60}else{while(now+2>=Browser.nextRAF){Browser.nextRAF+=1e3/60}}var delay=Math.max(Browser.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame:function(func){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(func);return}var RAF=Browser.fakeRequestAnimationFrame;RAF(func)},safeSetTimeout:function(func,timeout){return safeSetTimeout(func,timeout)},safeRequestAnimationFrame:function(func){return Browser.requestAnimationFrame(()=>{callUserCallback(func)})},getMimetype:function(name){return{"jpg":"image/jpeg","jpeg":"image/jpeg","png":"image/png","bmp":"image/bmp","ogg":"audio/ogg","wav":"audio/wav","mp3":"audio/mpeg"}[name.substr(name.lastIndexOf(".")+1)]},getUserMedia:function(func){if(!window.getUserMedia){window.getUserMedia=navigator["getUserMedia"]||navigator["mozGetUserMedia"]}window.getUserMedia(func)},getMovementX:function(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY:function(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta:function(event){var delta=0;switch(event.type){case"DOMMouseScroll":delta=event.detail/3;break;case"mousewheel":delta=event.wheelDelta/120;break;case"wheel":delta=event.deltaY;switch(event.deltaMode){case 0:delta/=100;break;case 1:delta/=3;break;case 2:delta*=80;break;default:throw"unrecognized mouse wheel delta mode: "+event.deltaMode}break;default:throw"unrecognized mouse wheel event: "+event.type}return delta},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(event){if(Browser.pointerLock){if(event.type!="mousemove"&&"mozMovementX"in event){Browser.mouseMovementX=Browser.mouseMovementY=0}else{Browser.mouseMovementX=Browser.getMovementX(event);Browser.mouseMovementY=Browser.getMovementY(event)}if(typeof SDL!="undefined"){Browser.mouseX=SDL.mouseX+Browser.mouseMovementX;Browser.mouseY=SDL.mouseY+Browser.mouseMovementY}else{Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}}else{var rect=Module["canvas"].getBoundingClientRect();var cw=Module["canvas"].width;var ch=Module["canvas"].height;var scrollX=typeof window.scrollX!="undefined"?window.scrollX:window.pageXOffset;var scrollY=typeof window.scrollY!="undefined"?window.scrollY:window.pageYOffset;if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var adjustedX=touch.pageX-(scrollX+rect.left);var adjustedY=touch.pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);var coords={x:adjustedX,y:adjustedY};if(event.type==="touchstart"){Browser.lastTouches[touch.identifier]=coords;Browser.touches[touch.identifier]=coords}else if(event.type==="touchend"||event.type==="touchmove"){var last=Browser.touches[touch.identifier];if(!last)last=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}var x=event.pageX-(scrollX+rect.left);var y=event.pageY-(scrollY+rect.top);x=x*(cw/rect.width);y=y*(ch/rect.height);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y}},resizeListeners:[],updateResizeListeners:function(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(listener=>listener(canvas.width,canvas.height))},setCanvasSize:function(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags|8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags&~8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions:function(canvas,wNative,hNative){if(wNative&&hNative){canvas.widthNative=wNative;canvas.heightNative=hNative}else{wNative=canvas.widthNative;hNative=canvas.heightNative}var w=wNative;var h=hNative;if(Module["forcedAspectRatio"]&&Module["forcedAspectRatio"]>0){if(w/h0){callbacks.shift()(Module)}}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24;this.set_type=function(type){HEAPU32[this.ptr+4>>2]=type};this.get_type=function(){return HEAPU32[this.ptr+4>>2]};this.set_destructor=function(destructor){HEAPU32[this.ptr+8>>2]=destructor};this.get_destructor=function(){return HEAPU32[this.ptr+8>>2]};this.set_caught=function(caught){caught=caught?1:0;HEAP8[this.ptr+12>>0]=caught};this.get_caught=function(){return HEAP8[this.ptr+12>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>0]=rethrown};this.get_rethrown=function(){return HEAP8[this.ptr+13>>0]!=0};this.init=function(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)};this.set_adjusted_ptr=function(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr};this.get_adjusted_ptr=function(){return HEAPU32[this.ptr+16>>2]};this.get_exception_ptr=function(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return HEAPU32[this.excPtr>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}var exceptionLast=0;var uncaughtExceptionCount=0;function ___cxa_throw(ptr,type,destructor){var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast}function setErrNo(value){HEAP32[___errno_location()>>2]=value;return value}function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}var newStream;newStream=FS.createStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 5:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 6:case 7:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fstat64(fd,buf){try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:case 21505:{if(!stream.tty)return-59;return 0}case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:{if(!stream.tty)return-59;return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.get();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.get();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;return 0}case 21524:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_lstat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_newfstatat(dirfd,path,buf,flags){try{path=SYSCALLS.getStr(path);var nofollow=flags&256;var allowEmpty=flags&4096;flags=flags&~6400;path=SYSCALLS.calculateAt(dirfd,path,allowEmpty);return SYSCALLS.doStat(nofollow?FS.lstat:FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?SYSCALLS.get():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_stat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var dlopenMissingError="To use dlopen, you need enable dynamic linking, see https://emscripten.org/docs/compiling/Dynamic-Linking.html";function __dlopen_js(handle){abort(dlopenMissingError)}function __dlsym_js(handle,symbol){abort(dlopenMissingError)}function __embind_register_bigint(primitiveType,name,size,minRange,maxRange){}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError(`Unknown type size: ${size}`)}}function embind_init_charCodes(){var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes}var embind_charCodes=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return`_${name}`}return name}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return{[name]:function(){return body.apply(this,arguments)}}[name]}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return`${this.name}: ${this.message}`}};return errorClass}var BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function registerType(rawType,registeredInstance,options={}){if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function __embind_register_bool(rawType,name,size,trueValue,falseValue){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(wt){return!!wt},"toWireType":function(destructors,o){return o?trueValue:falseValue},"argPackAdvance":8,"readValueFromPointer":function(pointer){var heap;if(size===1){heap=HEAP8}else if(size===2){heap=HEAP16}else if(size===4){heap=HEAP32}else{throw new TypeError("Unknown boolean type size: "+name)}return this["fromWireType"](heap[pointer>>shift])},destructorFunction:null})}function HandleAllocator(){this.allocated=[undefined];this.freelist=[];this.get=function(id){return this.allocated[id]};this.has=function(id){return this.allocated[id]!==undefined};this.allocate=function(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id};this.free=function(id){this.allocated[id]=undefined;this.freelist.push(id)}}var emval_handles=new HandleAllocator;function __emval_decref(handle){if(handle>=emval_handles.reserved&&0===--emval_handles.get(handle).refcount){emval_handles.free(handle)}}function count_emval_handles(){var count=0;for(var i=emval_handles.reserved;i{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles.get(handle).value},toHandle:value=>{switch(value){case undefined:return 1;case null:return 2;case true:return 3;case false:return 4;default:{return emval_handles.allocate({refcount:1,value:value})}}}};function simpleReadValueFromPointer(pointer){return this["fromWireType"](HEAP32[pointer>>2])}function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=Emval.toValue(handle);__emval_decref(handle);return rv},"toWireType":function(destructors,value){return Emval.toHandle(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function integerReadValueFromPointer(name,shift,signed){switch(shift){case 0:return signed?function readS8FromPointer(pointer){return HEAP8[pointer]}:function readU8FromPointer(pointer){return HEAPU8[pointer]};case 1:return signed?function readS16FromPointer(pointer){return HEAP16[pointer>>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":toWireType,"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(heap.buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||HEAPU8[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+i]=charCode}}else{for(var i=0;i>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str}function stringToUTF16(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}function lengthBytesUTF16(str){return str.length*2}function UTF32ToString(ptr,maxBytesToRead){var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str}function stringToUTF32(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}function lengthBytesUTF32(str){var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len}function __embind_register_std_wstring(rawType,charSize,name){name=readLatin1String(name);var decodeString,encodeString,getHeap,lengthBytesUTF,shift;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;getHeap=()=>HEAPU16;shift=1}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;getHeap=()=>HEAPU32;shift=2}registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var HEAP=getHeap();var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||HEAP[currentBytePtr>>shift]==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},"toWireType":function(destructors,value){if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}var nowIsMonotonic=true;function __emscripten_get_now_is_monotonic(){return nowIsMonotonic}function getTypeName(type){var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv}function requireRegisteredType(rawType,humanName){var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl}function __emval_as(handle,returnType,destructorsRef){handle=Emval.toValue(handle);returnType=requireRegisteredType(returnType,"emval::as");var destructors=[];var rd=Emval.toHandle(destructors);HEAPU32[destructorsRef>>2]=rd;return returnType["toWireType"](destructors,handle)}var emval_symbols={};function getStringOrSymbol(address){var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}return symbol}function emval_get_global(){if(typeof globalThis=="object"){return globalThis}function testGlobal(obj){obj["$$$embind_global$$$"]=obj;var success=typeof $$$embind_global$$$=="object"&&obj["$$$embind_global$$$"]==obj;if(!success){delete obj["$$$embind_global$$$"]}return success}if(typeof $$$embind_global$$$=="object"){return $$$embind_global$$$}if(typeof global=="object"&&testGlobal(global)){$$$embind_global$$$=global}else if(typeof self=="object"&&testGlobal(self)){$$$embind_global$$$=self}if(typeof $$$embind_global$$$=="object"){return $$$embind_global$$$}throw Error("unable to get global object.")}function __emval_get_global(name){if(name===0){return Emval.toHandle(emval_get_global())}else{name=getStringOrSymbol(name);return Emval.toHandle(emval_get_global()[name])}}function __emval_get_property(handle,key){handle=Emval.toValue(handle);key=Emval.toValue(key);return Emval.toHandle(handle[key])}function __emval_incref(handle){if(handle>4){emval_handles.get(handle).refcount+=1}}function __emval_instanceof(object,constructor){object=Emval.toValue(object);constructor=Emval.toValue(constructor);return object instanceof constructor}function __emval_new_cstring(v){return Emval.toHandle(getStringOrSymbol(v))}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function __emval_run_destructors(handle){var destructors=Emval.toValue(handle);runDestructors(destructors);__emval_decref(handle)}function __emval_set_property(handle,key,value){handle=Emval.toValue(handle);key=Emval.toValue(key);value=Emval.toValue(value);handle[key]=value}function __emval_take_value(type,arg){type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](arg);return Emval.toHandle(v)}function __emval_typeof(handle){handle=Emval.toValue(handle);return Emval.toHandle(typeof handle)}function readI53FromI64(ptr){return HEAPU32[ptr>>2]+HEAP32[ptr+4>>2]*4294967296}function __gmtime_js(time,tmPtr){var date=new Date(readI53FromI64(time)*1e3);HEAP32[tmPtr>>2]=date.getUTCSeconds();HEAP32[tmPtr+4>>2]=date.getUTCMinutes();HEAP32[tmPtr+8>>2]=date.getUTCHours();HEAP32[tmPtr+12>>2]=date.getUTCDate();HEAP32[tmPtr+16>>2]=date.getUTCMonth();HEAP32[tmPtr+20>>2]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday}function isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];function ydayFromDate(date){var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday}function __localtime_js(time,tmPtr){var date=new Date(readI53FromI64(time)*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst}function __mktime_js(tmPtr){var date=new Date(HEAP32[tmPtr+20>>2]+1900,HEAP32[tmPtr+16>>2],HEAP32[tmPtr+12>>2],HEAP32[tmPtr+8>>2],HEAP32[tmPtr+4>>2],HEAP32[tmPtr>>2],0);var dst=HEAP32[tmPtr+32>>2];var guessedOffset=date.getTimezoneOffset();var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dstOffset=Math.min(winterOffset,summerOffset);if(dst<0){HEAP32[tmPtr+32>>2]=Number(summerOffset!=winterOffset&&dstOffset==guessedOffset)}else if(dst>0!=(dstOffset==guessedOffset)){var nonDstOffset=Math.max(winterOffset,summerOffset);var trueOffset=dst>0?dstOffset:nonDstOffset;date.setTime(date.getTime()+(trueOffset-guessedOffset)*6e4)}HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getYear();return date.getTime()/1e3|0}function __mmap_js(len,prot,flags,fd,off,allocated,addr){try{var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,off,prot,flags);var ptr=res.ptr;HEAP32[allocated>>2]=res.allocated;HEAPU32[addr>>2]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function __munmap_js(addr,len,prot,flags,fd,offset){try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset)}FS.munmap(stream)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function stringToNewUTF8(str){var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8(str,ret,size);return ret}function __tzset_js(timezone,daylight,tzname){var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>2]=stdTimezoneOffset*60;HEAP32[daylight>>2]=Number(winterOffset!=summerOffset);function extractZone(date){var match=date.toTimeString().match(/\(([A-Za-z ]+)\)$/);return match?match[1]:"GMT"}var winterName=extractZone(winter);var summerName=extractZone(summer);var winterNamePtr=stringToNewUTF8(winterName);var summerNamePtr=stringToNewUTF8(summerName);if(summerOffset>2]=winterNamePtr;HEAPU32[tzname+4>>2]=summerNamePtr}else{HEAPU32[tzname>>2]=summerNamePtr;HEAPU32[tzname+4>>2]=winterNamePtr}}function _abort(){abort("")}var readEmAsmArgsArray=[];function readEmAsmArgs(sigPtr,buf){readEmAsmArgsArray.length=0;var ch;buf>>=2;while(ch=HEAPU8[sigPtr++]){buf+=ch!=105&buf;readEmAsmArgsArray.push(ch==105?HEAP32[buf]:HEAPF64[buf++>>1]);++buf}return readEmAsmArgsArray}function runEmAsmFunction(code,sigPtr,argbuf){var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[code].apply(null,args)}function _emscripten_asm_const_int(code,sigPtr,argbuf){return runEmAsmFunction(code,sigPtr,argbuf)}function _emscripten_date_now(){return Date.now()}function _emscripten_err(str){err(UTF8ToString(str))}function _emscripten_errn(str,len){err(UTF8ToString(str,len))}function getHeapMax(){return 2147483648}function _emscripten_get_heap_max(){return getHeapMax()}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function _emscripten_outn(str,len){out(UTF8ToString(str,len))}function _emscripten_pc_get_function(pc){abort("Cannot use emscripten_pc_get_function without -sUSE_OFFSET_CONVERTER")}function emscripten_realloc_buffer(size){var b=wasmMemory.buffer;var pages=size-b.byteLength+65535>>>16;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){var oldSize=HEAPU8.length;requestedSize=requestedSize>>>0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}function convertFrameToPC(frame){abort("Cannot use convertFrameToPC (needed by __builtin_return_address) without -sUSE_OFFSET_CONVERTER");return 0}var UNWIND_CACHE={};function saveInUnwindCache(callstack){callstack.forEach(frame=>{var pc=convertFrameToPC(frame);if(pc){UNWIND_CACHE[pc]=frame}})}function jsStackTrace(){var error=new Error;if(!error.stack){try{throw new Error}catch(e){error=e}if(!error.stack){return"(no stack trace available)"}}return error.stack.toString()}function _emscripten_stack_snapshot(){var callstack=jsStackTrace().split("\n");if(callstack[0]=="Error"){callstack.shift()}saveInUnwindCache(callstack);UNWIND_CACHE.last_addr=convertFrameToPC(callstack[3]);UNWIND_CACHE.last_stack=callstack;return UNWIND_CACHE.last_addr}function _emscripten_stack_unwind_buffer(addr,buffer,count){var stack;if(UNWIND_CACHE.last_addr==addr){stack=UNWIND_CACHE.last_stack}else{stack=jsStackTrace().split("\n");if(stack[0]=="Error"){stack.shift()}saveInUnwindCache(stack)}var offset=3;while(stack[offset]&&convertFrameToPC(stack[offset])!=addr){++offset}for(var i=0;i>2]=convertFrameToPC(stack[i+offset])}return i}function webgl_enable_ANGLE_instanced_arrays(ctx){var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=function(index,divisor){ext["vertexAttribDivisorANGLE"](index,divisor)};ctx["drawArraysInstanced"]=function(mode,first,count,primcount){ext["drawArraysInstancedANGLE"](mode,first,count,primcount)};ctx["drawElementsInstanced"]=function(mode,count,type,indices,primcount){ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount)};return 1}}function webgl_enable_OES_vertex_array_object(ctx){var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=function(){return ext["createVertexArrayOES"]()};ctx["deleteVertexArray"]=function(vao){ext["deleteVertexArrayOES"](vao)};ctx["bindVertexArray"]=function(vao){ext["bindVertexArrayOES"](vao)};ctx["isVertexArray"]=function(vao){return ext["isVertexArrayOES"](vao)};return 1}}function webgl_enable_WEBGL_draw_buffers(ctx){var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=function(n,bufs){ext["drawBuffersWEBGL"](n,bufs)};return 1}}function webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(ctx){return!!(ctx.dibvbi=ctx.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"))}function webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(ctx){return!!(ctx.mdibvbi=ctx.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance"))}function webgl_enable_WEBGL_multi_draw(ctx){return!!(ctx.multiDrawWebgl=ctx.getExtension("WEBGL_multi_draw"))}var GL={counter:1,buffers:[],mappedBuffers:{},programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],samplers:[],transformFeedbacks:[],syncs:[],byteSizeByTypeRoot:5120,byteSizeByType:[1,1,2,2,4,4,4,2,3,4,8],stringCache:{},stringiCache:{},unpackAlignment:4,recordError:function recordError(errorCode){if(!GL.lastError){GL.lastError=errorCode}},getNewId:function(table){var ret=GL.counter++;for(var i=table.length;i>1;var quadIndexes=new Uint16Array(numIndexes);var i=0,v=0;while(1){quadIndexes[i++]=v;if(i>=numIndexes)break;quadIndexes[i++]=v+1;if(i>=numIndexes)break;quadIndexes[i++]=v+2;if(i>=numIndexes)break;quadIndexes[i++]=v;if(i>=numIndexes)break;quadIndexes[i++]=v+2;if(i>=numIndexes)break;quadIndexes[i++]=v+3;if(i>=numIndexes)break;v+=4}context.GLctx.bufferData(34963,quadIndexes,35044);context.GLctx.bindBuffer(34963,null)}},getTempVertexBuffer:function getTempVertexBuffer(sizeBytes){var idx=GL.log2ceilLookup(sizeBytes);var ringbuffer=GL.currentContext.tempVertexBuffers1[idx];var nextFreeBufferIndex=GL.currentContext.tempVertexBufferCounters1[idx];GL.currentContext.tempVertexBufferCounters1[idx]=GL.currentContext.tempVertexBufferCounters1[idx]+1&GL.numTempVertexBuffersPerSize-1;var vbo=ringbuffer[nextFreeBufferIndex];if(vbo){return vbo}var prevVBO=GLctx.getParameter(34964);ringbuffer[nextFreeBufferIndex]=GLctx.createBuffer();GLctx.bindBuffer(34962,ringbuffer[nextFreeBufferIndex]);GLctx.bufferData(34962,1<>2]:-1;source+=UTF8ToString(HEAP32[string+i*4>>2],len<0?undefined:len)}return source},calcBufLength:function calcBufLength(size,type,stride,count){if(stride>0){return count*stride}var typeSize=GL.byteSizeByType[type-GL.byteSizeByTypeRoot];return size*typeSize*count},usedTempBuffers:[],preDrawHandleClientVertexAttribBindings:function preDrawHandleClientVertexAttribBindings(count){GL.resetBufferBinding=false;for(var i=0;i1?canvas.getContext("webgl2",webGLContextAttributes):canvas.getContext("webgl",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);return handle},registerContext:function(ctx,webGLContextAttributes){var handle=GL.getNewId(GL.contexts);var context={handle:handle,attributes:webGLContextAttributes,version:webGLContextAttributes.majorVersion,GLctx:ctx};if(ctx.canvas)ctx.canvas.GLctxObject=context;GL.contexts[handle]=context;if(typeof webGLContextAttributes.enableExtensionsByDefault=="undefined"||webGLContextAttributes.enableExtensionsByDefault){GL.initExtensions(context)}context.maxVertexAttribs=context.GLctx.getParameter(34921);context.clientBuffers=[];for(var i=0;i=2){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query_webgl2")}if(context.version<2||!GLctx.disjointTimerQueryExt){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query")}webgl_enable_WEBGL_multi_draw(GLctx);var exts=GLctx.getSupportedExtensions()||[];exts.forEach(function(ext){if(!ext.includes("lose_context")&&!ext.includes("debug")){GLctx.getExtension(ext)}})}};function withStackSave(f){var stack=stackSave();var ret=f();stackRestore(stack);return ret}var JSEvents={inEventHandler:0,removeAllEventListeners:function(){for(var i=JSEvents.eventHandlers.length-1;i>=0;--i){JSEvents._removeHandler(i)}JSEvents.eventHandlers=[];JSEvents.deferredCalls=[]},registerRemoveEventListeners:function(){if(!JSEvents.removeEventListenersRegistered){__ATEXIT__.push(JSEvents.removeAllEventListeners);JSEvents.removeEventListenersRegistered=true}},deferredCalls:[],deferCall:function(targetFunction,precedence,argsList){function arraysHaveEqualContent(arrA,arrB){if(arrA.length!=arrB.length)return false;for(var i in arrA){if(arrA[i]!=arrB[i])return false}return true}for(var i in JSEvents.deferredCalls){var call=JSEvents.deferredCalls[i];if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction:targetFunction,precedence:precedence,argsList:argsList});JSEvents.deferredCalls.sort(function(x,y){return x.precedence>2;var powerPreference=HEAP32[a+(24>>2)];var contextAttributes={"alpha":!!HEAP32[a+(0>>2)],"depth":!!HEAP32[a+(4>>2)],"stencil":!!HEAP32[a+(8>>2)],"antialias":!!HEAP32[a+(12>>2)],"premultipliedAlpha":!!HEAP32[a+(16>>2)],"preserveDrawingBuffer":!!HEAP32[a+(20>>2)],"powerPreference":emscripten_webgl_power_preferences[powerPreference],"failIfMajorPerformanceCaveat":!!HEAP32[a+(28>>2)],majorVersion:HEAP32[a+(32>>2)],minorVersion:HEAP32[a+(36>>2)],enableExtensionsByDefault:HEAP32[a+(40>>2)],explicitSwapControl:HEAP32[a+(44>>2)],proxyContextToMainThread:HEAP32[a+(48>>2)],renderViaOffscreenBackBuffer:HEAP32[a+(52>>2)]};var canvas=findCanvasEventTarget(target);if(!canvas){return 0}if(contextAttributes.explicitSwapControl){return 0}var contextHandle=GL.createContext(canvas,contextAttributes);return contextHandle}var _emscripten_webgl_create_context=_emscripten_webgl_do_create_context;function _emscripten_webgl_destroy_context(contextHandle){if(GL.currentContext==contextHandle)GL.currentContext=0;GL.deleteContext(contextHandle)}function _emscripten_webgl_get_context_attributes(c,a){if(!a)return-5;c=GL.contexts[c];if(!c)return-3;var t=c.GLctx;if(!t)return-3;t=t.getContextAttributes();HEAP32[a>>2]=t.alpha;HEAP32[a+4>>2]=t.depth;HEAP32[a+8>>2]=t.stencil;HEAP32[a+12>>2]=t.antialias;HEAP32[a+16>>2]=t.premultipliedAlpha;HEAP32[a+20>>2]=t.preserveDrawingBuffer;var power=t["powerPreference"]&&emscripten_webgl_power_preferences.indexOf(t["powerPreference"]);HEAP32[a+24>>2]=power;HEAP32[a+28>>2]=t.failIfMajorPerformanceCaveat;HEAP32[a+32>>2]=c.version;HEAP32[a+36>>2]=0;HEAP32[a+40>>2]=c.attributes.enableExtensionsByDefault;return 0}function _emscripten_webgl_do_get_current_context(){return GL.currentContext?GL.currentContext.handle:0}var _emscripten_webgl_get_current_context=_emscripten_webgl_do_get_current_context;function _emscripten_webgl_init_context_attributes(attributes){var a=attributes>>2;for(var i=0;i<56>>2;++i){HEAP32[a+i]=0}HEAP32[a+(0>>2)]=HEAP32[a+(4>>2)]=HEAP32[a+(12>>2)]=HEAP32[a+(16>>2)]=HEAP32[a+(32>>2)]=HEAP32[a+(40>>2)]=1}function _emscripten_webgl_make_context_current(contextHandle){var success=GL.makeContextCurrent(contextHandle);return success?0:-5}function stringToUTF8OnStack(str){var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret}function convertI32PairToI53(lo,hi){return(lo>>>0)+hi*4294967296}var wasmTableMirror=[];function getWasmTableEntry(funcPtr){var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func}var WebGPU={errorCallback:function(callback,type,message,userdata){withStackSave(()=>{var messagePtr=stringToUTF8OnStack(message);getWasmTableEntry(callback)(type,messagePtr,userdata)})},initManagers:function(){if(WebGPU.mgrDevice)return;function Manager(){this.objects={};this.nextId=1;this.create=function(object,wrapper={}){var id=this.nextId++;wrapper.refcount=1;wrapper.object=object;this.objects[id]=wrapper;return id};this.get=function(id){if(!id)return undefined;var o=this.objects[id];return o.object};this.reference=function(id){var o=this.objects[id];o.refcount++};this.release=function(id){var o=this.objects[id];o.refcount--;if(o.refcount<=0){delete this.objects[id]}}}WebGPU.mgrSurface=WebGPU.mgrSurface||new Manager;WebGPU.mgrSwapChain=WebGPU.mgrSwapChain||new Manager;WebGPU.mgrAdapter=WebGPU.mgrAdapter||new Manager;WebGPU.mgrDevice=WebGPU.mgrDevice||new Manager;WebGPU.mgrQueue=WebGPU.mgrQueue||new Manager;WebGPU.mgrCommandBuffer=WebGPU.mgrCommandBuffer||new Manager;WebGPU.mgrCommandEncoder=WebGPU.mgrCommandEncoder||new Manager;WebGPU.mgrRenderPassEncoder=WebGPU.mgrRenderPassEncoder||new Manager;WebGPU.mgrComputePassEncoder=WebGPU.mgrComputePassEncoder||new Manager;WebGPU.mgrBindGroup=WebGPU.mgrBindGroup||new Manager;WebGPU.mgrBuffer=WebGPU.mgrBuffer||new Manager;WebGPU.mgrSampler=WebGPU.mgrSampler||new Manager;WebGPU.mgrTexture=WebGPU.mgrTexture||new Manager;WebGPU.mgrTextureView=WebGPU.mgrTextureView||new Manager;WebGPU.mgrQuerySet=WebGPU.mgrQuerySet||new Manager;WebGPU.mgrBindGroupLayout=WebGPU.mgrBindGroupLayout||new Manager;WebGPU.mgrPipelineLayout=WebGPU.mgrPipelineLayout||new Manager;WebGPU.mgrRenderPipeline=WebGPU.mgrRenderPipeline||new Manager;WebGPU.mgrComputePipeline=WebGPU.mgrComputePipeline||new Manager;WebGPU.mgrShaderModule=WebGPU.mgrShaderModule||new Manager;WebGPU.mgrRenderBundleEncoder=WebGPU.mgrRenderBundleEncoder||new Manager;WebGPU.mgrRenderBundle=WebGPU.mgrRenderBundle||new Manager},makeColor:function(ptr){return{"r":HEAPF64[ptr>>3],"g":HEAPF64[ptr+8>>3],"b":HEAPF64[ptr+16>>3],"a":HEAPF64[ptr+24>>3]}},makeExtent3D:function(ptr){return{"width":HEAPU32[ptr>>2],"height":HEAPU32[ptr+4>>2],"depthOrArrayLayers":HEAPU32[ptr+8>>2]}},makeOrigin3D:function(ptr){return{"x":HEAPU32[ptr>>2],"y":HEAPU32[ptr+4>>2],"z":HEAPU32[ptr+8>>2]}},makeImageCopyTexture:function(ptr){return{"texture":WebGPU.mgrTexture.get(HEAPU32[ptr+4>>2]),"mipLevel":HEAPU32[ptr+8>>2],"origin":WebGPU.makeOrigin3D(ptr+12),"aspect":WebGPU.TextureAspect[HEAPU32[ptr+24>>2]]}},makeTextureDataLayout:function(ptr){var bytesPerRow=HEAPU32[ptr+16>>2];var rowsPerImage=HEAPU32[ptr+20>>2];return{"offset":HEAPU32[ptr+4+8>>2]*4294967296+HEAPU32[ptr+8>>2],"bytesPerRow":bytesPerRow===4294967295?undefined:bytesPerRow,"rowsPerImage":rowsPerImage===4294967295?undefined:rowsPerImage}},makeImageCopyBuffer:function(ptr){var layoutPtr=ptr+8;var bufferCopyView=WebGPU.makeTextureDataLayout(layoutPtr);bufferCopyView["buffer"]=WebGPU.mgrBuffer.get(HEAPU32[ptr+32>>2]);return bufferCopyView},makePipelineConstants:function(constantCount,constantsPtr){if(!constantCount)return;var constants={};for(var i=0;i>2]);constants[key]=HEAPF64[entryPtr+8>>3]}return constants},makePipelineLayout:function(layoutPtr){if(!layoutPtr)return"auto";return WebGPU.mgrPipelineLayout.get(layoutPtr)},makeProgrammableStageDescriptor:function(ptr){if(!ptr)return undefined;return{"module":WebGPU.mgrShaderModule.get(HEAPU32[ptr+4>>2]),"entryPoint":UTF8ToString(HEAPU32[ptr+8>>2]),"constants":WebGPU.makePipelineConstants(HEAPU32[ptr+12>>2],HEAPU32[ptr+16>>2])}},DeviceLostReason:{undefined:0,destroyed:1},PreferredFormat:{rgba8unorm:18,bgra8unorm:23},AddressMode:["repeat","mirror-repeat","clamp-to-edge"],BlendFactor:["zero","one","src","one-minus-src","src-alpha","one-minus-src-alpha","dst","one-minus-dst","dst-alpha","one-minus-dst-alpha","src-alpha-saturated","constant","one-minus-constant"],BlendOperation:["add","subtract","reverse-subtract","min","max"],BufferBindingType:[,"uniform","storage","read-only-storage"],CompareFunction:[,"never","less","less-equal","greater","greater-equal","equal","not-equal","always"],CompilationInfoRequestStatus:["success","error","device-lost","unknown"],ComputePassTimestampLocation:["beginning","end"],CullMode:["none","front","back"],ErrorFilter:["validation","out-of-memory"],FeatureName:[,"depth-clip-control","depth32float-stencil8","timestamp-query","pipeline-statistics-query","texture-compression-bc","texture-compression-etc2","texture-compression-astc","indirect-first-instance"],FilterMode:["nearest","linear"],FrontFace:["ccw","cw"],IndexFormat:[,"uint16","uint32"],LoadOp:[,"clear","load"],PipelineStatisticName:["vertex-shader-invocations","clipper-invocations","clipper-primitives-out","fragment-shader-invocations","compute-shader-invocations"],PowerPreference:[,"low-power","high-performance"],PrimitiveTopology:["point-list","line-list","line-strip","triangle-list","triangle-strip"],QueryType:["occlusion","pipeline-statistics","timestamp"],RenderPassTimestampLocation:["beginning","end"],SamplerBindingType:[,"filtering","non-filtering","comparison"],StencilOperation:["keep","zero","replace","invert","increment-clamp","decrement-clamp","increment-wrap","decrement-wrap"],StorageTextureAccess:[,"write-only"],StoreOp:[,"store","discard"],TextureAspect:["all","stencil-only","depth-only"],TextureComponentType:["float","sint","uint","depth-comparison"],TextureDimension:["1d","2d","3d"],TextureFormat:[,"r8unorm","r8snorm","r8uint","r8sint","r16uint","r16sint","r16float","rg8unorm","rg8snorm","rg8uint","rg8sint","r32float","r32uint","r32sint","rg16uint","rg16sint","rg16float","rgba8unorm","rgba8unorm-srgb","rgba8snorm","rgba8uint","rgba8sint","bgra8unorm","bgra8unorm-srgb","rgb10a2unorm","rg11b10ufloat","rgb9e5ufloat","rg32float","rg32uint","rg32sint","rgba16uint","rgba16sint","rgba16float","rgba32float","rgba32uint","rgba32sint","stencil8","depth16unorm","depth24plus","depth24plus-stencil8","depth32float","depth32float-stencil8","bc1-rgba-unorm","bc1-rgba-unorm-srgb","bc2-rgba-unorm","bc2-rgba-unorm-srgb","bc3-rgba-unorm","bc3-rgba-unorm-srgb","bc4-r-unorm","bc4-r-snorm","bc5-rg-unorm","bc5-rg-snorm","bc6h-rgb-ufloat","bc6h-rgb-float","bc7-rgba-unorm","bc7-rgba-unorm-srgb","etc2-rgb8unorm","etc2-rgb8unorm-srgb","etc2-rgb8a1unorm","etc2-rgb8a1unorm-srgb","etc2-rgba8unorm","etc2-rgba8unorm-srgb","eac-r11unorm","eac-r11snorm","eac-rg11unorm","eac-rg11snorm","astc-4x4-unorm","astc-4x4-unorm-srgb","astc-5x4-unorm","astc-5x4-unorm-srgb","astc-5x5-unorm","astc-5x5-unorm-srgb","astc-6x5-unorm","astc-6x5-unorm-srgb","astc-6x6-unorm","astc-6x6-unorm-srgb","astc-8x5-unorm","astc-8x5-unorm-srgb","astc-8x6-unorm","astc-8x6-unorm-srgb","astc-8x8-unorm","astc-8x8-unorm-srgb","astc-10x5-unorm","astc-10x5-unorm-srgb","astc-10x6-unorm","astc-10x6-unorm-srgb","astc-10x8-unorm","astc-10x8-unorm-srgb","astc-10x10-unorm","astc-10x10-unorm-srgb","astc-12x10-unorm","astc-12x10-unorm-srgb","astc-12x12-unorm","astc-12x12-unorm-srgb"],TextureSampleType:[,"float","unfilterable-float","depth","sint","uint"],TextureViewDimension:[,"1d","2d","2d-array","cube","cube-array","3d"],VertexFormat:[,"uint8x2","uint8x4","sint8x2","sint8x4","unorm8x2","unorm8x4","snorm8x2","snorm8x4","uint16x2","uint16x4","sint16x2","sint16x4","unorm16x2","unorm16x4","snorm16x2","snorm16x4","float16x2","float16x4","float32","float32x2","float32x3","float32x4","uint32","uint32x2","uint32x3","uint32x4","sint32","sint32x2","sint32x3","sint32x4"],VertexStepMode:["vertex","instance"],FeatureNameString2Enum:{undefined:"0","depth-clip-control":"1","depth32float-stencil8":"2","timestamp-query":"3","pipeline-statistics-query":"4","texture-compression-bc":"5","texture-compression-etc2":"6","texture-compression-astc":"7","indirect-first-instance":"8"}};var JsValStore={values:{},next_id:1,add:function(js_val){var id;do{id=JsValStore.next_id++;if(JsValStore.next_id>2147483647)JsValStore.next_id=1}while(id in JsValStore.values);JsValStore.values[id]=js_val;return id},remove:function(id){delete JsValStore.values[id]},get:function(id){return JsValStore.values[id]}};function _emscripten_webgpu_export_bind_group_layout(handle){return JsValStore.add(WebGPU.mgrBindGroupLayout.get(handle))}function _emscripten_webgpu_export_device(handle){return JsValStore.add(WebGPU.mgrDevice.get(handle))}function _emscripten_webgpu_export_sampler(handle){return JsValStore.add(WebGPU.mgrSampler.get(handle))}function _emscripten_webgpu_export_texture(handle){return JsValStore.add(WebGPU.mgrTexture.get(handle))}function _emscripten_webgpu_get_device(){if(WebGPU.preinitializedDeviceId===undefined){var device=Module["preinitializedWebGPUDevice"];var deviceWrapper={queueId:WebGPU.mgrQueue.create(device["queue"])};WebGPU.preinitializedDeviceId=WebGPU.mgrDevice.create(device,deviceWrapper)}WebGPU.mgrDevice.reference(WebGPU.preinitializedDeviceId);return WebGPU.preinitializedDeviceId}function _emscripten_webgpu_import_bind_group(handle){return WebGPU.mgrBindGroup.create(JsValStore.get(handle))}function _emscripten_webgpu_import_texture(handle){return WebGPU.mgrTexture.create(JsValStore.get(handle))}function _emscripten_webgpu_release_js_handle(id){JsValStore.remove(id)}var ENV={};function getExecutableName(){return thisProgram||"./this.program"}function getEnvStrings(){if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings}function stringToAscii(str,buffer){for(var i=0;i>0]=str.charCodeAt(i)}HEAP8[buffer>>0]=0}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAPU32[penviron_buf_size>>2]=bufSize;return 0}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function doReadv(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function convertI32PairToI53Checked(lo,hi){return hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var offset=convertI32PairToI53Checked(offset_low,offset_high);if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function doWritev(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(typeof offset!=="undefined"){offset+=curr}}return ret}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _getentropy(buffer,size){randomFill(HEAPU8.subarray(buffer,buffer+size));return 0}function _glActiveTexture(x0){GLctx.activeTexture(x0)}function _glAttachShader(program,shader){GLctx.attachShader(GL.programs[program],GL.shaders[shader])}function _glBindAttribLocation(program,index,name){GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}function _glBindBuffer(target,buffer){if(target==34962){GLctx.currentArrayBufferBinding=buffer}else if(target==34963){GLctx.currentElementArrayBufferBinding=buffer}if(target==35051){GLctx.currentPixelPackBufferBinding=buffer}else if(target==35052){GLctx.currentPixelUnpackBufferBinding=buffer}GLctx.bindBuffer(target,GL.buffers[buffer])}function _glBindBufferBase(target,index,buffer){GLctx.bindBufferBase(target,index,GL.buffers[buffer])}function _glBindFramebuffer(target,framebuffer){GLctx.bindFramebuffer(target,GL.framebuffers[framebuffer])}function _glBindTexture(target,texture){GLctx.bindTexture(target,GL.textures[texture])}function _glBindVertexArray(vao){GLctx.bindVertexArray(GL.vaos[vao]);var ibo=GLctx.getParameter(34965);GLctx.currentElementArrayBufferBinding=ibo?ibo.name|0:0}function _glBlendEquation(x0){GLctx.blendEquation(x0)}function _glBlendFunc(x0,x1){GLctx.blendFunc(x0,x1)}function _glBufferData(target,size,data,usage){if(GL.currentContext.version>=2){if(data&&size){GLctx.bufferData(target,HEAPU8,usage,data,size)}else{GLctx.bufferData(target,size,usage)}}else{GLctx.bufferData(target,data?HEAPU8.subarray(data,data+size):size,usage)}}function _glClear(x0){GLctx.clear(x0)}function _glClearColor(x0,x1,x2,x3){GLctx.clearColor(x0,x1,x2,x3)}function _glClientWaitSync(sync,flags,timeout_low,timeout_high){var timeout=convertI32PairToI53(timeout_low,timeout_high);return GLctx.clientWaitSync(GL.syncs[sync],flags,timeout)}function _glCompileShader(shader){GLctx.compileShader(GL.shaders[shader])}function _glCreateProgram(){var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;program.maxUniformLength=program.maxAttributeLength=program.maxUniformBlockNameLength=0;program.uniformIdCounter=1;GL.programs[id]=program;return id}function _glCreateShader(shaderType){var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id}function _glDeleteBuffers(n,buffers){for(var i=0;i>2];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null;if(id==GLctx.currentArrayBufferBinding)GLctx.currentArrayBufferBinding=0;if(id==GLctx.currentElementArrayBufferBinding)GLctx.currentElementArrayBufferBinding=0;if(id==GLctx.currentPixelPackBufferBinding)GLctx.currentPixelPackBufferBinding=0;if(id==GLctx.currentPixelUnpackBufferBinding)GLctx.currentPixelUnpackBufferBinding=0}}function _glDeleteFramebuffers(n,framebuffers){for(var i=0;i>2];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}function _glDeleteProgram(id){if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null}function _glDeleteShader(id){if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null}function _glDeleteSync(id){if(!id)return;var sync=GL.syncs[id];if(!sync){GL.recordError(1281);return}GLctx.deleteSync(sync);sync.name=0;GL.syncs[id]=null}function _glDeleteTextures(n,textures){for(var i=0;i>2];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}function _glDeleteVertexArrays(n,vaos){for(var i=0;i>2];GLctx.deleteVertexArray(GL.vaos[id]);GL.vaos[id]=null}}function _glDisable(x0){GLctx.disable(x0)}function _glDisableVertexAttribArray(index){var cb=GL.currentContext.clientBuffers[index];cb.enabled=false;GLctx.disableVertexAttribArray(index)}function _glDrawArrays(mode,first,count){GL.preDrawHandleClientVertexAttribBindings(first+count);GLctx.drawArrays(mode,first,count);GL.postDrawHandleClientVertexAttribBindings()}var tempFixedLengthArray=[];function _glDrawBuffers(n,bufs){var bufArray=tempFixedLengthArray[n];for(var i=0;i>2]}GLctx.drawBuffers(bufArray)}function _glEnable(x0){GLctx.enable(x0)}function _glEnableVertexAttribArray(index){var cb=GL.currentContext.clientBuffers[index];cb.enabled=true;GLctx.enableVertexAttribArray(index)}function _glFenceSync(condition,flags){var sync=GLctx.fenceSync(condition,flags);if(sync){var id=GL.getNewId(GL.syncs);sync.name=id;GL.syncs[id]=sync;return id}return 0}function _glFinish(){GLctx.finish()}function _glFlush(){GLctx.flush()}function _glFramebufferTexture2D(target,attachment,textarget,texture,level){GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)}function _glFramebufferTextureLayer(target,attachment,texture,level,layer){GLctx.framebufferTextureLayer(target,attachment,GL.textures[texture],level,layer)}function __glGenObject(n,buffers,createFunction,objectTable){for(var i=0;i>2]=id}}function _glGenBuffers(n,buffers){__glGenObject(n,buffers,"createBuffer",GL.buffers)}function _glGenFramebuffers(n,ids){__glGenObject(n,ids,"createFramebuffer",GL.framebuffers)}function _glGenTextures(n,textures){__glGenObject(n,textures,"createTexture",GL.textures)}function _glGenVertexArrays(n,arrays){__glGenObject(n,arrays,"createVertexArray",GL.vaos)}function _glGetAttribLocation(program,name){return GLctx.getAttribLocation(GL.programs[program],UTF8ToString(name))}function _glGetError(){var error=GLctx.getError()||GL.lastError;GL.lastError=0;return error}function writeI53ToI64(ptr,num){HEAPU32[ptr>>2]=num;HEAPU32[ptr+4>>2]=(num-HEAPU32[ptr>>2])/4294967296}function emscriptenWebGLGet(name_,p,type){if(!p){GL.recordError(1281);return}var ret=undefined;switch(name_){case 36346:ret=1;break;case 36344:if(type!=0&&type!=1){GL.recordError(1280)}return;case 34814:case 36345:ret=0;break;case 34466:var formats=GLctx.getParameter(34467);ret=formats?formats.length:0;break;case 33309:if(GL.currentContext.version<2){GL.recordError(1282);return}var exts=GLctx.getSupportedExtensions()||[];ret=2*exts.length;break;case 33307:case 33308:if(GL.currentContext.version<2){GL.recordError(1280);return}ret=name_==33307?3:0;break}if(ret===undefined){var result=GLctx.getParameter(name_);switch(typeof result){case"number":ret=result;break;case"boolean":ret=result?1:0;break;case"string":GL.recordError(1280);return;case"object":if(result===null){switch(name_){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:{ret=0;break}default:{GL.recordError(1280);return}}}else if(result instanceof Float32Array||result instanceof Uint32Array||result instanceof Int32Array||result instanceof Array){for(var i=0;i>2]=result[i];break;case 2:HEAPF32[p+i*4>>2]=result[i];break;case 4:HEAP8[p+i>>0]=result[i]?1:0;break}}return}else{try{ret=result.name|0}catch(e){GL.recordError(1280);err("GL_INVALID_ENUM in glGet"+type+"v: Unknown object returned from WebGL getParameter("+name_+")! (error: "+e+")");return}}break;default:GL.recordError(1280);err("GL_INVALID_ENUM in glGet"+type+"v: Native code calling glGet"+type+"v("+name_+") and it returns "+result+" of type "+typeof result+"!");return}}switch(type){case 1:writeI53ToI64(p,ret);break;case 0:HEAP32[p>>2]=ret;break;case 2:HEAPF32[p>>2]=ret;break;case 4:HEAP8[p>>0]=ret?1:0;break}}function _glGetIntegerv(name_,p){emscriptenWebGLGet(name_,p,0)}function _glGetProgramiv(program,pname,p){if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}program=GL.programs[program];if(pname==35716){var log=GLctx.getProgramInfoLog(program);if(log===null)log="(unknown error)";HEAP32[p>>2]=log.length+1}else if(pname==35719){if(!program.maxUniformLength){for(var i=0;i>2]=program.maxUniformLength}else if(pname==35722){if(!program.maxAttributeLength){for(var i=0;i>2]=program.maxAttributeLength}else if(pname==35381){if(!program.maxUniformBlockNameLength){for(var i=0;i>2]=program.maxUniformBlockNameLength}else{HEAP32[p>>2]=GLctx.getProgramParameter(program,pname)}}function _glGetShaderInfoLog(shader,maxLength,length,infoLog){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _glGetShaderiv(shader,pname,p){if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>2]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>2]=sourceLength}else{HEAP32[p>>2]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}function _glGetString(name_){var ret=GL.stringCache[name_];if(!ret){switch(name_){case 7939:var exts=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));ret=stringToNewUTF8(exts.join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=s&&stringToNewUTF8(s);break;case 7938:var glVersion=GLctx.getParameter(7938);if(GL.currentContext.version>=2)glVersion="OpenGL ES 3.0 ("+glVersion+")";else{glVersion="OpenGL ES 2.0 ("+glVersion+")"}ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion="OpenGL ES GLSL ES "+ver_num[1]+" ("+glslVersion+")"}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280)}GL.stringCache[name_]=ret}return ret}function _glGetUniformBlockIndex(program,uniformBlockName){return GLctx.getUniformBlockIndex(GL.programs[program],UTF8ToString(uniformBlockName))}function jstoi_q(str){return parseInt(str)}function webglGetLeftBracePos(name){return name.slice(-1)=="]"&&name.lastIndexOf("[")}function webglPrepareUniformLocationsBeforeFirstUse(program){var uniformLocsById=program.uniformLocsById,uniformSizeAndIdsByName=program.uniformSizeAndIdsByName,i,j;if(!uniformLocsById){program.uniformLocsById=uniformLocsById={};program.uniformArrayNamesById={};for(i=0;i0?nm.slice(0,lb):nm;var id=program.uniformIdCounter;program.uniformIdCounter+=sz;uniformSizeAndIdsByName[arrayName]=[sz,id];for(j=0;j0){arrayIndex=jstoi_q(name.slice(leftBrace+1))>>>0;uniformBaseName=name.slice(0,leftBrace)}var sizeAndId=program.uniformSizeAndIdsByName[uniformBaseName];if(sizeAndId&&arrayIndex>shift,pixels+bytes>>shift)}function _glReadPixels(x,y,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelPackBufferBinding){GLctx.readPixels(x,y,width,height,format,type,pixels)}else{var heap=heapObjectForWebGLType(type);GLctx.readPixels(x,y,width,height,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}return}var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}function _glShaderSource(shader,count,string,length){var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}function _glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,null)}return}GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null)}function _glTexParameterf(x0,x1,x2){GLctx.texParameterf(x0,x1,x2)}function _glTexParameterfv(target,pname,params){var param=HEAPF32[params>>2];GLctx.texParameterf(target,pname,param)}function _glTexParameteri(x0,x1,x2){GLctx.texParameteri(x0,x1,x2)}function _glTexStorage2D(x0,x1,x2,x3,x4){GLctx.texStorage2D(x0,x1,x2,x3,x4)}function _glTexStorage3D(x0,x1,x2,x3,x4,x5){GLctx.texStorage3D(x0,x1,x2,x3,x4,x5)}function _glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,null)}return}var pixelData=null;if(pixels)pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}function _glTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx.texSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,null)}}function webglGetUniformLocation(location){var p=GLctx.currentProgram;if(p){var webglLoc=p.uniformLocsById[location];if(typeof webglLoc=="number"){p.uniformLocsById[location]=webglLoc=GLctx.getUniformLocation(p,p.uniformArrayNamesById[location]+(webglLoc>0?"["+webglLoc+"]":""))}return webglLoc}else{GL.recordError(1282)}}function _glUniform1f(location,v0){GLctx.uniform1f(webglGetUniformLocation(location),v0)}function _glUniform1i(location,v0){GLctx.uniform1i(webglGetUniformLocation(location),v0)}function _glUniform2f(location,v0,v1){GLctx.uniform2f(webglGetUniformLocation(location),v0,v1)}var miniTempWebGLFloatBuffers=[];function _glUniform2fv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform2fv(webglGetUniformLocation(location),HEAPF32,value>>2,count*2);return}if(count<=144){var view=miniTempWebGLFloatBuffers[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2fv(webglGetUniformLocation(location),view)}function _glUniform3f(location,v0,v1,v2){GLctx.uniform3f(webglGetUniformLocation(location),v0,v1,v2)}function _glUniform4fv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform4fv(webglGetUniformLocation(location),HEAPF32,value>>2,count*4);return}if(count<=72){var view=miniTempWebGLFloatBuffers[4*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<4*count;i+=4){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4fv(webglGetUniformLocation(location),view)}var miniTempWebGLIntBuffers=[];function _glUniform4iv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform4iv(webglGetUniformLocation(location),HEAP32,value>>2,count*4);return}if(count<=72){var view=miniTempWebGLIntBuffers[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2];view[i+3]=HEAP32[value+(4*i+12)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4iv(webglGetUniformLocation(location),view)}function _glUniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding){program=GL.programs[program];GLctx.uniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding)}function _glUniformMatrix4fv(location,count,transpose,value){if(GL.currentContext.version>=2){count&&GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*16);return}if(count<=18){var view=miniTempWebGLFloatBuffers[16*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<16*count;i+=16){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3];view[i+4]=heap[dst+4];view[i+5]=heap[dst+5];view[i+6]=heap[dst+6];view[i+7]=heap[dst+7];view[i+8]=heap[dst+8];view[i+9]=heap[dst+9];view[i+10]=heap[dst+10];view[i+11]=heap[dst+11];view[i+12]=heap[dst+12];view[i+13]=heap[dst+13];view[i+14]=heap[dst+14];view[i+15]=heap[dst+15]}}else{var view=HEAPF32.subarray(value>>2,value+count*64>>2)}GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,view)}function _glUseProgram(program){program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program}function _glVertexAttribPointer(index,size,type,normalized,stride,ptr){var cb=GL.currentContext.clientBuffers[index];if(!GLctx.currentArrayBufferBinding){cb.size=size;cb.type=type;cb.normalized=normalized;cb.stride=stride;cb.ptr=ptr;cb.clientside=true;cb.vertexAttribPointerAdaptor=function(index,size,type,normalized,stride,ptr){this.vertexAttribPointer(index,size,type,normalized,stride,ptr)};return}cb.clientside=false;GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}function _glViewport(x0,x1,x2,x3){GLctx.viewport(x0,x1,x2,x3)}function _mediapipe_find_canvas_event_target(canvasSelector){let target=findCanvasEventTarget(canvasSelector);if(Module&&!target){target=Module.canvasWebGpu}return Emval.toHandle(target)}function _mediapipe_webgl_tex_image_drawable(drawableHandle){const drawable=Emval.toValue(drawableHandle);GLctx.texImage2D(GLctx.TEXTURE_2D,0,GLctx.RGBA,GLctx.RGBA,GLctx.UNSIGNED_BYTE,drawable)}function arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum}var MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value=="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}return thisDate.getFullYear()}return thisDate.getFullYear()-1}var EXPANSION_RULES_2={"%a":function(date){return WEEKDAYS[date.tm_wday].substring(0,3)},"%A":function(date){return WEEKDAYS[date.tm_wday]},"%b":function(date){return MONTHS[date.tm_mon].substring(0,3)},"%B":function(date){return MONTHS[date.tm_mon]},"%C":function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":function(date){return leadingNulls(date.tm_mday,2)},"%e":function(date){return leadingSomething(date.tm_mday,2," ")},"%g":function(date){return getWeekBasedYear(date).toString().substring(2)},"%G":function(date){return getWeekBasedYear(date)},"%H":function(date){return leadingNulls(date.tm_hour,2)},"%I":function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":function(date){return leadingNulls(date.tm_mday+arraySum(isLeapYear(date.tm_year+1900)?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,date.tm_mon-1),3)},"%m":function(date){return leadingNulls(date.tm_mon+1,2)},"%M":function(date){return leadingNulls(date.tm_min,2)},"%n":function(){return"\n"},"%p":function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}return"PM"},"%S":function(date){return leadingNulls(date.tm_sec,2)},"%t":function(){return"\t"},"%u":function(date){return date.tm_wday||7},"%U":function(date){var days=date.tm_yday+7-date.tm_wday;return leadingNulls(Math.floor(days/7),2)},"%V":function(date){var val=Math.floor((date.tm_yday+7-(date.tm_wday+6)%7)/7);if((date.tm_wday+371-date.tm_yday-2)%7<=2){val++}if(!val){val=52;var dec31=(date.tm_wday+7-date.tm_yday-1)%7;if(dec31==4||dec31==5&&isLeapYear(date.tm_year%400-1)){val++}}else if(val==53){var jan1=(date.tm_wday+371-date.tm_yday)%7;if(jan1!=4&&(jan1!=3||!isLeapYear(date.tm_year)))val=1}return leadingNulls(val,2)},"%w":function(date){return date.tm_wday},"%W":function(date){var days=date.tm_yday+7-(date.tm_wday+6)%7;return leadingNulls(Math.floor(days/7),2)},"%y":function(date){return(date.tm_year+1900).toString().substring(2)},"%Y":function(date){return date.tm_year+1900},"%z":function(date){var off=date.tm_gmtoff;var ahead=off>=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":function(date){return date.tm_zone},"%%":function(){return"%"}};pattern=pattern.replace(/%%/g,"\0\0");for(var rule in EXPANSION_RULES_2){if(pattern.includes(rule)){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}pattern=pattern.replace(/\0\0/g,"%");var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm,loc){return _strftime(s,maxsize,format,tm)}function _wgpuBindGroupLayoutRelease(id){WebGPU.mgrBindGroupLayout.release(id)}function _wgpuBindGroupRelease(id){WebGPU.mgrBindGroup.release(id)}function _wgpuBufferGetMappedRange(bufferId,offset,size){var bufferWrapper=WebGPU.mgrBuffer.objects[bufferId];if(size===0)warnOnce("getMappedRange size=0 no longer means WGPU_WHOLE_MAP_SIZE");size=size>>>0;if(size===4294967295)size=undefined;if(bufferWrapper.mapMode!==2){return 0}var mapped;try{mapped=bufferWrapper.object["getMappedRange"](offset,size)}catch(ex){return 0}var data=_memalign(16,mapped.byteLength);HEAPU8.fill(0,data,mapped.byteLength);bufferWrapper.onUnmap.push(()=>{new Uint8Array(mapped).set(HEAPU8.subarray(data,data+mapped.byteLength));_free(data)});return data}function _wgpuBufferReference(id){WebGPU.mgrBuffer.reference(id)}function _wgpuBufferRelease(id){WebGPU.mgrBuffer.release(id)}function _wgpuBufferUnmap(bufferId){var bufferWrapper=WebGPU.mgrBuffer.objects[bufferId];if(!bufferWrapper.onUnmap){return}for(var i=0;i>2]),"queryIndex":HEAPU32[twPtr+4>>2],"location":WebGPU.ComputePassTimestampLocation[HEAPU32[twPtr+8>>2]]}}function makeComputePassTimestampWrites(count,twPtr){var timestampWrites=[];for(var i=0;i>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var timestampWriteCount=HEAPU32[descriptor+8>>2];if(timestampWriteCount){desc["timestampWrites"]=makeComputePassTimestampWrites(timestampWriteCount,HEAPU32[descriptor+12>>2])}}var commandEncoder=WebGPU.mgrCommandEncoder.get(encoderId);return WebGPU.mgrComputePassEncoder.create(commandEncoder["beginComputePass"](desc))}function _wgpuCommandEncoderBeginRenderPass(encoderId,descriptor){function makeColorAttachment(caPtr){var viewPtr=HEAPU32[caPtr>>2];if(viewPtr===0){return undefined}var loadOpInt=HEAPU32[caPtr+8>>2];var storeOpInt=HEAPU32[caPtr+12>>2];var clearValue=WebGPU.makeColor(caPtr+16);return{"view":WebGPU.mgrTextureView.get(viewPtr),"resolveTarget":WebGPU.mgrTextureView.get(HEAPU32[caPtr+4>>2]),"clearValue":clearValue,"loadOp":WebGPU.LoadOp[loadOpInt],"storeOp":WebGPU.StoreOp[storeOpInt]}}function makeColorAttachments(count,caPtr){var attachments=[];for(var i=0;i>2]),"depthClearValue":HEAPF32[dsaPtr+12>>2],"depthLoadOp":WebGPU.LoadOp[HEAPU32[dsaPtr+4>>2]],"depthStoreOp":WebGPU.StoreOp[HEAPU32[dsaPtr+8>>2]],"depthReadOnly":HEAP8[dsaPtr+16>>0]!==0,"stencilClearValue":HEAPU32[dsaPtr+28>>2],"stencilLoadOp":WebGPU.LoadOp[HEAPU32[dsaPtr+20>>2]],"stencilStoreOp":WebGPU.StoreOp[HEAPU32[dsaPtr+24>>2]],"stencilReadOnly":HEAP8[dsaPtr+32>>0]!==0}}function makeRenderPassTimestampWrite(twPtr){return{"querySet":WebGPU.mgrQuerySet.get(HEAPU32[twPtr>>2]),"queryIndex":HEAPU32[twPtr+4>>2],"location":WebGPU.RenderPassTimestampLocation[HEAPU32[twPtr+8>>2]]}}function makeRenderPassTimestampWrites(count,twPtr){var timestampWrites=[];for(var i=0;i>2];var maxDrawCount=undefined;if(nextInChainPtr!==0){var sType=HEAPU32[nextInChainPtr+4>>2];var renderPassDescriptorMaxDrawCount=nextInChainPtr;maxDrawCount=HEAPU32[renderPassDescriptorMaxDrawCount+4+8>>2]*4294967296+HEAPU32[renderPassDescriptorMaxDrawCount+8>>2]}var desc={"label":undefined,"colorAttachments":makeColorAttachments(HEAPU32[descriptor+8>>2],HEAPU32[descriptor+12>>2]),"depthStencilAttachment":makeDepthStencilAttachment(HEAPU32[descriptor+16>>2]),"occlusionQuerySet":WebGPU.mgrQuerySet.get(HEAPU32[descriptor+20>>2]),"maxDrawCount":maxDrawCount};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var timestampWriteCount=HEAPU32[descriptor+24>>2];if(timestampWriteCount){desc["timestampWrites"]=makeRenderPassTimestampWrites(timestampWriteCount,HEAPU32[descriptor+28>>2])}return desc}var desc=makeRenderPassDescriptor(descriptor);var commandEncoder=WebGPU.mgrCommandEncoder.get(encoderId);return WebGPU.mgrRenderPassEncoder.create(commandEncoder["beginRenderPass"](desc))}function _wgpuCommandEncoderCopyBufferToTexture(encoderId,srcPtr,dstPtr,copySizePtr){var commandEncoder=WebGPU.mgrCommandEncoder.get(encoderId);var copySize=WebGPU.makeExtent3D(copySizePtr);commandEncoder["copyBufferToTexture"](WebGPU.makeImageCopyBuffer(srcPtr),WebGPU.makeImageCopyTexture(dstPtr),copySize)}function _wgpuCommandEncoderCopyTextureToTexture(encoderId,srcPtr,dstPtr,copySizePtr){var commandEncoder=WebGPU.mgrCommandEncoder.get(encoderId);var copySize=WebGPU.makeExtent3D(copySizePtr);commandEncoder["copyTextureToTexture"](WebGPU.makeImageCopyTexture(srcPtr),WebGPU.makeImageCopyTexture(dstPtr),copySize)}function _wgpuCommandEncoderFinish(encoderId){var commandEncoder=WebGPU.mgrCommandEncoder.get(encoderId);return WebGPU.mgrCommandBuffer.create(commandEncoder["finish"]())}function _wgpuCommandEncoderRelease(id){WebGPU.mgrCommandEncoder.release(id)}function _wgpuComputePassEncoderDispatchWorkgroups(passId,x,y,z){var pass=WebGPU.mgrComputePassEncoder.get(passId);pass["dispatchWorkgroups"](x,y,z)}function _wgpuComputePassEncoderEnd(passId){var pass=WebGPU.mgrComputePassEncoder.get(passId);pass["end"]()}function _wgpuComputePassEncoderRelease(id){WebGPU.mgrComputePassEncoder.release(id)}function _wgpuComputePassEncoderSetBindGroup(passId,groupIndex,groupId,dynamicOffsetCount,dynamicOffsetsPtr){var pass=WebGPU.mgrComputePassEncoder.get(passId);var group=WebGPU.mgrBindGroup.get(groupId);if(dynamicOffsetCount==0){pass["setBindGroup"](groupIndex,group)}else{var offsets=[];for(var i=0;i>2])}pass["setBindGroup"](groupIndex,group,offsets)}}function _wgpuComputePassEncoderSetPipeline(passId,pipelineId){var pass=WebGPU.mgrComputePassEncoder.get(passId);var pipeline=WebGPU.mgrComputePipeline.get(pipelineId);pass["setPipeline"](pipeline)}function _wgpuComputePipelineGetBindGroupLayout(pipelineId,groupIndex){var pipeline=WebGPU.mgrComputePipeline.get(pipelineId);return WebGPU.mgrBindGroupLayout.create(pipeline["getBindGroupLayout"](groupIndex))}function _wgpuComputePipelineRelease(id){WebGPU.mgrComputePipeline.release(id)}function _wgpuDeviceCreateBindGroup(deviceId,descriptor){function makeEntry(entryPtr){var bufferId=HEAPU32[entryPtr+8>>2];var samplerId=HEAPU32[entryPtr+32>>2];var textureViewId=HEAPU32[entryPtr+36>>2];var binding=HEAPU32[entryPtr+4>>2];if(bufferId){var size_low=HEAP32[entryPtr+24>>2];var size_high=HEAP32[entryPtr+28>>2];var size=size_high===-1&&size_low===-1?undefined:convertI32PairToI53(size_low,size_high);return{"binding":binding,"resource":{"buffer":WebGPU.mgrBuffer.get(bufferId),"offset":HEAPU32[entryPtr+4+16>>2]*4294967296+HEAPU32[entryPtr+16>>2],"size":size}}}else if(samplerId){return{"binding":binding,"resource":WebGPU.mgrSampler.get(samplerId)}}else{return{"binding":binding,"resource":WebGPU.mgrTextureView.get(textureViewId)}}}function makeEntries(count,entriesPtrs){var entries=[];for(var i=0;i>2]),"entries":makeEntries(HEAPU32[descriptor+12>>2],HEAPU32[descriptor+16>>2])};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrBindGroup.create(device["createBindGroup"](desc))}function _wgpuDeviceCreateBuffer(deviceId,descriptor){var mappedAtCreation=HEAP8[descriptor+24>>0]!==0;var desc={"label":undefined,"usage":HEAPU32[descriptor+8>>2],"size":HEAPU32[descriptor+4+16>>2]*4294967296+HEAPU32[descriptor+16>>2],"mappedAtCreation":mappedAtCreation};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var device=WebGPU.mgrDevice.get(deviceId);var bufferWrapper={};var id=WebGPU.mgrBuffer.create(device["createBuffer"](desc),bufferWrapper);if(mappedAtCreation){bufferWrapper.mapMode=2;bufferWrapper.onUnmap=[]}return id}function _wgpuDeviceCreateCommandEncoder(deviceId,descriptor){var desc;if(descriptor){desc={"label":undefined};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr)}var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrCommandEncoder.create(device["createCommandEncoder"](desc))}function _wgpuDeviceCreateComputePipeline(deviceId,descriptor){var desc={"label":undefined,"layout":WebGPU.makePipelineLayout(HEAPU32[descriptor+8>>2]),"compute":WebGPU.makeProgrammableStageDescriptor(descriptor+12)};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrComputePipeline.create(device["createComputePipeline"](desc))}function _wgpuDeviceCreateRenderPipeline(deviceId,descriptor){function makePrimitiveState(rsPtr){if(!rsPtr)return undefined;return{"topology":WebGPU.PrimitiveTopology[HEAPU32[rsPtr+4>>2]],"stripIndexFormat":WebGPU.IndexFormat[HEAPU32[rsPtr+8>>2]],"frontFace":WebGPU.FrontFace[HEAPU32[rsPtr+12>>2]],"cullMode":WebGPU.CullMode[HEAPU32[rsPtr+16>>2]]}}function makeBlendComponent(bdPtr){if(!bdPtr)return undefined;return{"operation":WebGPU.BlendOperation[HEAPU32[bdPtr>>2]],"srcFactor":WebGPU.BlendFactor[HEAPU32[bdPtr+4>>2]],"dstFactor":WebGPU.BlendFactor[HEAPU32[bdPtr+8>>2]]}}function makeBlendState(bsPtr){if(!bsPtr)return undefined;return{"alpha":makeBlendComponent(bsPtr+12),"color":makeBlendComponent(bsPtr+0)}}function makeColorState(csPtr){var formatInt=HEAPU32[csPtr+4>>2];return formatInt===0?undefined:{"format":WebGPU.TextureFormat[formatInt],"blend":makeBlendState(HEAPU32[csPtr+8>>2]),"writeMask":HEAPU32[csPtr+12>>2]}}function makeColorStates(count,csArrayPtr){var states=[];for(var i=0;i>2]],"failOp":WebGPU.StencilOperation[HEAPU32[ssfPtr+4>>2]],"depthFailOp":WebGPU.StencilOperation[HEAPU32[ssfPtr+8>>2]],"passOp":WebGPU.StencilOperation[HEAPU32[ssfPtr+12>>2]]}}function makeDepthStencilState(dssPtr){if(!dssPtr)return undefined;return{"format":WebGPU.TextureFormat[HEAPU32[dssPtr+4>>2]],"depthWriteEnabled":HEAP8[dssPtr+8>>0]!==0,"depthCompare":WebGPU.CompareFunction[HEAPU32[dssPtr+12>>2]],"stencilFront":makeStencilStateFace(dssPtr+16),"stencilBack":makeStencilStateFace(dssPtr+32),"stencilReadMask":HEAPU32[dssPtr+48>>2],"stencilWriteMask":HEAPU32[dssPtr+52>>2],"depthBias":HEAPU32[dssPtr+56>>2],"depthBiasSlopeScale":HEAPF32[dssPtr+60>>2],"depthBiasClamp":HEAPF32[dssPtr+64>>2]}}function makeVertexAttribute(vaPtr){return{"format":WebGPU.VertexFormat[HEAPU32[vaPtr>>2]],"offset":HEAPU32[vaPtr+4+8>>2]*4294967296+HEAPU32[vaPtr+8>>2],"shaderLocation":HEAPU32[vaPtr+16>>2]}}function makeVertexAttributes(count,vaArrayPtr){var vas=[];for(var i=0;i>2];return stepModeInt===2?null:{"arrayStride":HEAPU32[vbPtr+4>>2]*4294967296+HEAPU32[vbPtr>>2],"stepMode":WebGPU.VertexStepMode[stepModeInt],"attributes":makeVertexAttributes(HEAPU32[vbPtr+12>>2],HEAPU32[vbPtr+16>>2])}}function makeVertexBuffers(count,vbArrayPtr){if(!count)return undefined;var vbs=[];for(var i=0;i>2]),"entryPoint":UTF8ToString(HEAPU32[viPtr+8>>2]),"constants":WebGPU.makePipelineConstants(HEAPU32[viPtr+12>>2],HEAPU32[viPtr+16>>2]),"buffers":makeVertexBuffers(HEAPU32[viPtr+20>>2],HEAPU32[viPtr+24>>2])}}function makeMultisampleState(msPtr){if(!msPtr)return undefined;return{"count":HEAPU32[msPtr+4>>2],"mask":HEAPU32[msPtr+8>>2],"alphaToCoverageEnabled":HEAP8[msPtr+12>>0]!==0}}function makeFragmentState(fsPtr){if(!fsPtr)return undefined;return{"module":WebGPU.mgrShaderModule.get(HEAPU32[fsPtr+4>>2]),"entryPoint":UTF8ToString(HEAPU32[fsPtr+8>>2]),"constants":WebGPU.makePipelineConstants(HEAPU32[fsPtr+12>>2],HEAPU32[fsPtr+16>>2]),"targets":makeColorStates(HEAPU32[fsPtr+20>>2],HEAPU32[fsPtr+24>>2])}}var desc={"label":undefined,"layout":WebGPU.makePipelineLayout(HEAPU32[descriptor+8>>2]),"vertex":makeVertexState(descriptor+12),"primitive":makePrimitiveState(descriptor+40),"depthStencil":makeDepthStencilState(HEAPU32[descriptor+60>>2]),"multisample":makeMultisampleState(descriptor+64),"fragment":makeFragmentState(HEAPU32[descriptor+80>>2])};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrRenderPipeline.create(device["createRenderPipeline"](desc))}function _wgpuDeviceCreateSampler(deviceId,descriptor){var desc={"label":undefined,"addressModeU":WebGPU.AddressMode[HEAPU32[descriptor+8>>2]],"addressModeV":WebGPU.AddressMode[HEAPU32[descriptor+12>>2]],"addressModeW":WebGPU.AddressMode[HEAPU32[descriptor+16>>2]],"magFilter":WebGPU.FilterMode[HEAPU32[descriptor+20>>2]],"minFilter":WebGPU.FilterMode[HEAPU32[descriptor+24>>2]],"mipmapFilter":WebGPU.FilterMode[HEAPU32[descriptor+28>>2]],"lodMinClamp":HEAPF32[descriptor+32>>2],"lodMaxClamp":HEAPF32[descriptor+36>>2],"compare":WebGPU.CompareFunction[HEAPU32[descriptor+40>>2]]};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrSampler.create(device["createSampler"](desc))}function _wgpuDeviceCreateShaderModule(deviceId,descriptor){var nextInChainPtr=HEAPU32[descriptor>>2];var sType=HEAPU32[nextInChainPtr+4>>2];var desc={"label":undefined,"code":""};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);switch(sType){case 5:{var count=HEAPU32[nextInChainPtr+8>>2];var start=HEAPU32[nextInChainPtr+12>>2];desc["code"]=HEAPU32.subarray(start>>2,(start>>2)+count);break}case 6:{var sourcePtr=HEAPU32[nextInChainPtr+8>>2];if(sourcePtr){desc["code"]=UTF8ToString(sourcePtr)}break}}var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrShaderModule.create(device["createShaderModule"](desc))}function _wgpuDeviceCreateTexture(deviceId,descriptor){var desc={"label":undefined,"size":WebGPU.makeExtent3D(descriptor+16),"mipLevelCount":HEAPU32[descriptor+32>>2],"sampleCount":HEAPU32[descriptor+36>>2],"dimension":WebGPU.TextureDimension[HEAPU32[descriptor+12>>2]],"format":WebGPU.TextureFormat[HEAPU32[descriptor+28>>2]],"usage":HEAPU32[descriptor+8>>2]};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr);var viewFormatCount=HEAPU32[descriptor+40>>2];if(viewFormatCount){var viewFormatsPtr=HEAPU32[descriptor+44>>2];desc["viewFormats"]=Array.from(HEAP32.subarray(viewFormatsPtr>>2,(viewFormatsPtr>>2)+viewFormatCount),function(format){return WebGPU.TextureFormat[format]})}var device=WebGPU.mgrDevice.get(deviceId);return WebGPU.mgrTexture.create(device["createTexture"](desc))}function _wgpuDeviceGetQueue(deviceId){var queueId=WebGPU.mgrDevice.objects[deviceId].queueId;WebGPU.mgrQueue.reference(queueId);return queueId}function _wgpuDeviceReference(id){WebGPU.mgrDevice.reference(id)}function _wgpuDeviceRelease(id){WebGPU.mgrDevice.release(id)}function _wgpuPipelineLayoutRelease(id){WebGPU.mgrPipelineLayout.release(id)}function _wgpuQuerySetRelease(id){WebGPU.mgrQuerySet.release(id)}function _wgpuQueueRelease(id){WebGPU.mgrQueue.release(id)}function _wgpuQueueSubmit(queueId,commandCount,commands){var queue=WebGPU.mgrQueue.get(queueId);var cmds=Array.from(HEAP32.subarray(commands>>2,(commands>>2)+commandCount),function(id){return WebGPU.mgrCommandBuffer.get(id)});queue["submit"](cmds)}function _wgpuQueueWriteBuffer(queueId,bufferId,bufferOffset_low,bufferOffset_high,data,size){var bufferOffset=convertI32PairToI53Checked(bufferOffset_low,bufferOffset_high);if(isNaN(bufferOffset))return undefined;var queue=WebGPU.mgrQueue.get(queueId);var buffer=WebGPU.mgrBuffer.get(bufferId);var subarray=HEAPU8.subarray(data,data+size);queue["writeBuffer"](buffer,bufferOffset,subarray,0,size)}function _wgpuRenderPassEncoderDraw(passId,vertexCount,instanceCount,firstVertex,firstInstance){var pass=WebGPU.mgrRenderPassEncoder.get(passId);pass["draw"](vertexCount,instanceCount,firstVertex,firstInstance)}function _wgpuRenderPassEncoderEnd(passId){var pass=WebGPU.mgrRenderPassEncoder.get(passId);pass["end"]()}function _wgpuRenderPassEncoderRelease(id){WebGPU.mgrRenderPassEncoder.release(id)}function _wgpuRenderPassEncoderSetBindGroup(passId,groupIndex,groupId,dynamicOffsetCount,dynamicOffsetsPtr){var pass=WebGPU.mgrRenderPassEncoder.get(passId);var group=WebGPU.mgrBindGroup.get(groupId);if(dynamicOffsetCount==0){pass["setBindGroup"](groupIndex,group)}else{var offsets=[];for(var i=0;i>2])}pass["setBindGroup"](groupIndex,group,offsets)}}function _wgpuRenderPassEncoderSetPipeline(passId,pipelineId){var pass=WebGPU.mgrRenderPassEncoder.get(passId);var pipeline=WebGPU.mgrRenderPipeline.get(pipelineId);pass["setPipeline"](pipeline)}function _wgpuRenderPipelineGetBindGroupLayout(pipelineId,groupIndex){var pipeline=WebGPU.mgrRenderPipeline.get(pipelineId);return WebGPU.mgrBindGroupLayout.create(pipeline["getBindGroupLayout"](groupIndex))}function _wgpuRenderPipelineRelease(id){WebGPU.mgrRenderPipeline.release(id)}function _wgpuSamplerReference(id){WebGPU.mgrSampler.reference(id)}function _wgpuSamplerRelease(id){WebGPU.mgrSampler.release(id)}function _wgpuShaderModuleReference(id){WebGPU.mgrShaderModule.reference(id)}function _wgpuShaderModuleRelease(id){WebGPU.mgrShaderModule.release(id)}function _wgpuTextureCreateView(textureId,descriptor){var desc;if(descriptor){var mipLevelCount=HEAPU32[descriptor+20>>2];var arrayLayerCount=HEAPU32[descriptor+28>>2];desc={"format":WebGPU.TextureFormat[HEAPU32[descriptor+8>>2]],"dimension":WebGPU.TextureViewDimension[HEAPU32[descriptor+12>>2]],"baseMipLevel":HEAPU32[descriptor+16>>2],"mipLevelCount":mipLevelCount===4294967295?undefined:mipLevelCount,"baseArrayLayer":HEAPU32[descriptor+24>>2],"arrayLayerCount":arrayLayerCount===4294967295?undefined:arrayLayerCount,"aspect":WebGPU.TextureAspect[HEAPU32[descriptor+32>>2]]};var labelPtr=HEAPU32[descriptor+4>>2];if(labelPtr)desc["label"]=UTF8ToString(labelPtr)}var texture=WebGPU.mgrTexture.get(textureId);return WebGPU.mgrTextureView.create(texture["createView"](desc))}function _wgpuTextureDestroy(textureId){WebGPU.mgrTexture.get(textureId)["destroy"]()}function _wgpuTextureReference(id){WebGPU.mgrTexture.reference(id)}function _wgpuTextureRelease(id){WebGPU.mgrTexture.release(id)}function _wgpuTextureViewReference(id){WebGPU.mgrTextureView.reference(id)}function _wgpuTextureViewRelease(id){WebGPU.mgrTextureView.release(id)}function getCFunc(ident){var func=Module["_"+ident];return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},"array":arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run(); return ModuleFactory.ready } ); })(); if (typeof exports === 'object' && typeof module === 'object') module.exports = ModuleFactory; else if (typeof define === 'function' && define['amd']) define([], function() { return ModuleFactory; }); else if (typeof exports === 'object') exports["ModuleFactory"] = ModuleFactory; ================================================ FILE: jsconfig.json ================================================ { "compilerOptions": { "target": "ES6" }, "exclude": [ "test", "test_util", "scripts", "images", "extern/blockly", "node_modules", "**/node_modules/*" ] } ================================================ FILE: karma.conf.js ================================================ // Karma configuration // Generated on Tue Jun 23 2015 15:42:45 GMT+0900 (KST) module.exports = function(config) { config.set({ // base path that will be used to resolve all patterns (eg. files, exclude) basePath: '', // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter frameworks: ['mocha'], // list of files / patterns to load in the browser files: ['test/**/*.js'], // list of files to exclude exclude: [], // preprocess matching files before serving them to the browser // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: {}, // test results reporter to use // possible values: 'dots', 'progress' // available reporters: https://npmjs.org/browse/keyword/karma-reporter reporters: ['progress'], // web server port port: 9876, // enable / disable colors in the output (reporters and logs) colors: true, // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_ERROR, // enable / disable watching file and executing tests whenever any file changes autoWatch: true, // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher browsers: ['Chrome'], // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits singleRun: true, }); }; ================================================ FILE: package.json ================================================ { "name": "@entrylabs/entry", "title": "EntryJS", "description": "JavaScript library for visual programming", "version": "4.0.22", "main": "dist/entry.min.js", "homepage": "https://playentry.org", "author": { "name": "Entry Korea corp and other contributors" }, "repository": { "type": "git", "url": "git+https://github.com/entrylabs/entryjs.git" }, "keywords": [ "entry", "entryjs", "javascript" ], "bugs": { "url": "https://github.com/entrylabs/entryjs/issues" }, "scripts": { "lint": "cross-env NODE_ENV=lint webpack -w", "serve:webgl": "cross-env NODE_ENV=serve webpack-dev-server --open --hot --host 127.0.0.1 --webgl=true", "serve": "cross-env NODE_ENV=serve webpack-dev-server --open --hot --host 127.0.0.1", "serve:mini": "cross-env NODE_ENV=serve-mini webpack-dev-server --open --hot --host 127.0.0.1", "prod": "cross-env NODE_ENV=production webpack", "dev": "webpack -w", "test": "jest --colors", "clean": "rimraf ./dist", "dist": "webpack" }, "license": "Apache-2.0", "dependencies": { "@entrylabs/event": "^1.0.3", "@mediapipe/tasks-vision": "^0.10.3", "@tensorflow/tfjs": "^4.17.0", "@types/crypto-js": "^4.0.1", "@types/hammerjs": "^2.0.41", "@types/isomorphic-fetch": "^0.0.35", "autoprefixer": "^9.4.3", "buffer": "^6.0.3", "copy-webpack-plugin": "^12.0.2", "core-js": "^3.6.4", "crypto-js": "^4.0.0", "cuid": "^2.1.6", "events": "^3.0.0", "file-saver": "^2.0.2", "fontfaceonload": "^1.0.2", "hammerjs": "^2.0.8", "html-webpack-plugin": "^5.5.3", "html-webpack-template": "^6.2.0", "isomorphic-fetch": "^2.2.1", "jest": "^24.9.0", "khaiii": "^0.0.2", "libsvm-js": "^0.2.1", "lodash": "^4.17.15", "mathjs": "^7.1.0", "ml-cart": "^2.1.1", "pixi.js": "5.3.12", "postcss-flexbugs-fixes": "^4.1.0", "simplebar": "^5.3.0", "skmeans": "^0.11.3", "socket.io-client": "^2.3.0", "ua-parser-js": "^1.0.38", "uid": "^0.0.2", "webpack": "^5.85.0", "worker-loader": "^3.0.8", "xss-filters": "^1.2.7" }, "devDependencies": { "@babel/core": "^7.22.1", "@babel/eslint-parser": "^7.11.0", "@babel/eslint-plugin": "^7.11.0", "@babel/plugin-proposal-class-properties": "^7.8.3", "@babel/plugin-proposal-object-rest-spread": "^7.8.3", "@babel/plugin-proposal-private-methods": "^7.8.3", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-transform-modules-commonjs": "^7.8.3", "@babel/plugin-transform-object-assign": "^7.8.3", "@babel/plugin-transform-runtime": "^7.8.3", "@babel/preset-env": "^7.10.2", "@babel/runtime": "^7.8.4", "@egjs/visible": "^2.1.0", "@types/createjs": "^0.0.29", "@types/jquery": "^3.3.38", "@types/lodash": "^4.14.155", "@types/node": "^14.0.11", "@types/pixi.js": "5.0.0", "@types/w3c-web-usb": "^1.0.8", "@types/web-bluetooth": "^0.0.18", "@types/webpack-env": "^1.15.2", "@typescript-eslint/parser": "^3.1.0", "audiobuffer-to-wav": "^1.0.0", "babel-loader": "^8.0.6", "babel-plugin-dynamic-import-node": "^2.3.0", "chai": "^3.2.0", "clean-webpack-plugin": "^1.0.1", "cross-env": "^5.1.4", "css-loader": "^3.2.0", "cssnano": "^4.1.10", "eslint": "7.32.0", "eslint-config-prettier": "^9.1.0", "eslint-loader": "^4.0.2", "eslint-plugin-prettier": "^5.1.3", "extract-text-webpack-plugin": "^4.0.0-beta.0", "file-loader": "^4.2.0", "karma": "^4.2.0", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^3.1.0", "karma-mocha": "^1.3.0", "less": "^3.10.1", "less-loader": "^5.0.0", "mini-css-extract-plugin": "^2.7.6", "mocha": "^6.2.0", "postcss-loader": "^3.0.0", "prettier": "^3.2.5", "prettier-eslint": "^16.3.0", "style-loader": "^0.20.2", "terser-webpack-plugin": "^5.3.9", "ts-loader": "^9.4.3", "typescript": "^4.7.4", "url-loader": "^1.0.1", "webpack-cli": "^5.1.1", "webpack-dev-server": "^4.15.0", "webpack-manifest-plugin": "^5.0.0", "webpack-merge": "^5.9.0", "webpack-strip-block": "^0.3.0" }, "resolutions": { "pixi.js": "5.3.7" }, "publishConfig": { "access": "public" }, "files": [ "dist/", "extern/", "images/", "weights/", "src/playground/blocks/", "src/playground/block_entry.js", "src/playground/block_entry_mini.js", "package.json", "LICENSE", "NOTICE", "COPYING", "README.md", "README-en.md" ] } ================================================ FILE: scripts/build.sh ================================================ #!/usr/bin/env bash set -e # 에러 발생 시 스크립트 중단 git config --global user.name "Entry Dev"; git config --global user.email "entrydev@nts-corp.com"; export NODE_ENV=production git clone -b build "https://github.com/$GITHUB_REPOSITORY" build rm -rf build/**/* || exit 0 cp -r dist build/ cp -r extern build/ cp -r images build/ cp -r weights build/ rsync -R package.json build rsync -R LICENSE build rsync -R NOTICE build rsync -R COPYING build rsync -R README.md build rsync -R README-en.md build rsync -R src/playground/block_entry.js build rsync -R src/playground/block_entry_mini.js build rsync -r -R src/playground/blocks/ build ls -al ls -al build ================================================ FILE: scripts/build_action.sh ================================================ #!/usr/bin/env bash set -e # 에러 발생 시 스크립트 중단 git config --global user.name "Entry Dev"; git config --global user.email "entrydev@nts-corp.com"; branchName=${GITHUB_REF##*/} deployName="dist/$branchName" export NODE_ENV=production #if [ "$branchName" = "master" ] #then #git clone -b build "https://github.com/$GITHUB_REPOSITORY" build #else #git clone "https://github.com/$GITHUB_REPOSITORY" build #if git show-ref --quiet refs/remotes/origin/"$deployName"; then # git clone -b "$deployName" "https://github.com/$GITHUB_REPOSITORY" build #else # git clone "https://github.com/$GITHUB_REPOSITORY" build # git checkout -b "$deployName" #fi #fi git clone -b build "https://github.com/$GITHUB_REPOSITORY" build rm -rf build/**/* || exit 0 cp -r dist build/ cp -r extern build/ cp -r images build/ cp -r weights build/ rsync -R src/playground/block_entry.js build rsync -R src/playground/block_entry_mini.js build rsync -r -R src/playground/blocks/ build ls -al ls -al build ================================================ FILE: scripts/deploy.sh ================================================ #!/usr/bin/env bash set -e # 에러 발생 시 스크립트 중단 git config --local user.email "entrydev@nts-corp.com" git config --local user.name "Entry Dev" rm .gitignore branchName=${GITHUB_REF##*/} deployName="dist/$branchName" DATEFMT=`date "+%Y%m%d"` # echo "$DATEFMT: My message" cd build git config user.name "Entry Dev" git config user.email "entrydev@nts-corp.com" echo "target branch's name is $branchName" if [ "$branchName" = "master" ] then echo "deploy to build branch" git add . git commit -m "Entry Js PUBLISH by v3.$DATEFMT.${GITHUB_RUN_NUMBER}" git tag -a "v3.$DATEFMT.${GITHUB_RUN_NUMBER}" -m "build v3.$DATEFMT.${TRAVIS_BUILD_NUMBER}" # git push --force --quiet "https://${GH_TOKEN}@${GH_REF}" build --tags else echo "deploy branch's name is $deployName" git checkout -b "$deployName" echo "Entry Js deploy $deployName" > ${GITHUB_RUN_NUMBER} # git push --delete "https://${GH_TOKEN}@${GH_REF}" "$deployName" git add . git commit -m "Entry Js deploy $deployName" # git push --force --quiet "https://${GH_TOKEN}@${GH_REF}" "$deployName" fi #curl -d '{"tag_name": "v$DATEFMT","target_commitish": "build","name": "v$DATEFMT","body": "Description of the release","draft": false,"prerelease": false}' -X POST "https://developer.github.com/v3/repos/kimokim/entryjs/releases" ================================================ FILE: scripts/deploy_action.sh ================================================ #!/usr/bin/env bash set -e # 에러 발생 시 스크립트 중단 git config --local user.email "entrydev@nts-corp.com" git config --local user.name "Entry Dev" rm .gitignore branchName=${GITHUB_REF##*/} deployName="dist/$branchName" DATEFMT=`date "+%Y%m%d"` # echo "$DATEFMT: My message" cd build git config user.name "Entry Dev" git config user.email "entrydev@nts-corp.com" echo "target branch's name is $branchName" echo "https://${TEST}@github.com/$GITHUB_REPOSITORY" if [ "$branchName" = "master" ] then echo "deploy to build branch" git add . git commit -m "Entry Js PUBLISH by v3.$DATEFMT.${GITHUB_RUN_NUMBER}" git tag -a "v3.$DATEFMT.${GITHUB_RUN_NUMBER}" -m "build v3.$DATEFMT.${TRAVIS_BUILD_NUMBER}" # git push --force --quiet "https://${GH_TOKEN}@${GH_REF}" build --tags else echo "deploy branch's name is $deployName" if git show-ref --quiet refs/remotes/origin/"$deployName"; then git push --delete "https://${github_token}@github.com/$GITHUB_REPOSITORY" "$deployName" fi git add . git commit -m "Entry Js deploy $deployName" #git push --force --quiet "https://${GH_TOKEN}@${GH_REF}" "$deployName" fi #curl -d '{"tag_name": "v$DATEFMT","target_commitish": "build","name": "v$DATEFMT","body": "Description of the release","draft": false,"prerelease": false}' -X POST "https://developer.github.com/v3/repos/kimokim/entryjs/releases" ================================================ FILE: src/class/AILearning.js ================================================ import TextLearning, { classes as TextClasses } from './learning/TextLearning'; import Cluster, { classes as ClusterClasses } from './learning/Cluster'; import Regression, { classes as RegressionClasses } from './learning/Regression'; import ImageLearning, { classes as ImageClasses } from './learning/ImageLearning'; import SpeechClassification, { classes as SpeechClasses } from './learning/SpeechClassification'; import NumberClassification, { classes as NumberClassificationClasses, } from './learning/NumberClassification'; import DecisionTree, { classes as DecisionTreeClasses } from './learning/DecisionTree'; import LogisticRegression, { classes as LogisticRegressionClasses, } from './learning/LogisticRegression'; import Svm, { classes as SvmClasses } from './learning/Svm'; import DataTable from './DataTable'; import blockAiLearning from '../playground/blocks/block_ai_learning'; import blockAiLearningKnn from '../playground/blocks/block_ai_learning_knn'; import blockAiLearningCluster from '../playground/blocks/block_ai_learning_cluster'; import blockAiLearningRegression from '../playground/blocks/block_ai_learning_regression'; // eslint-disable-next-line max-len import blockAiLearningLogisticRegression from '../playground/blocks/block_ai_learning_logistic_regression'; import blockAiLearningDecisiontree from '../playground/blocks/block_ai_learning_decisiontree'; import blockAiLearningSvm from '../playground/blocks/block_ai_learning_svm'; import blockAiUtilizeMediaPipe from '../playground/blocks/block_ai_utilize_media_pipe'; import InputPopup from './learning/InputPopup'; import _isEmpty from 'lodash/isEmpty'; Entry.MlPopup = InputPopup; const basicBlockList = [ blockAiLearning, blockAiLearningKnn, blockAiLearningCluster, blockAiLearningRegression, blockAiLearningLogisticRegression, blockAiLearningDecisiontree, blockAiLearningSvm, blockAiUtilizeMediaPipe, ]; const banClasses = [ ...ClusterClasses, ...RegressionClasses, ...TextClasses, ...ImageClasses, ...SpeechClasses, ...NumberClassificationClasses, ...DecisionTreeClasses, ...LogisticRegressionClasses, ...SvmClasses, ]; export default class AILearning { #playground; #categoryName = 'ai_learning'; #labels = []; #url; #type; #oid; #modelId; isLoaded = false; isLoading = false; result = []; isEnable; #recordTime = 2000; #module = null; #tableData = null; #dataApi = undefined; constructor(playground, isEnable = true) { this.#playground = playground; this.isEnable = isEnable; } get labels() { return this.#labels; } init() { const blockObject = {}; basicBlockList.forEach((value) => { if ('getBlocks' in value) { Object.assign(blockObject, value.getBlocks()); } }); Entry.block = Object.assign(Entry.block, blockObject); } setDataApi(api) { this.#dataApi = api; } removeAllBlocks() { const utilizeBlock = []; Object.values(Entry.ALL_AI_UTILIZE_BLOCK_LIST) .map((x) => Object.keys(x.getBlocks())) .forEach((category) => { category.forEach((block) => { utilizeBlock.push(block); }); }); const { blocks } = EntryStatic.getAllBlocks().find( ({ category }) => category === 'ai_utilize' ); blocks .filter((x) => !utilizeBlock.includes(x)) .forEach((blockType) => { Entry.Utils.removeBlockByType(blockType); }); this.banBlocks(); this.destroy(); } removeLearningBlocks() { if (!this.isLoaded) { return; } this.#modelId = undefined; const { blocks } = EntryStatic.getAllBlocks().find( ({ category }) => category === 'ai_utilize' ); blocks .filter((x) => Entry.block?.[x]?.class === 'ai_learning') .forEach((blockType) => { Entry.Utils.removeBlockByType(blockType); }); this.banBlocks(); this.destroy(); } async loadModel({ url, trainParam, tableData, isActive, classes }) { const modelPath = await this.#dataApi?.getModelDownloadUrl(url); if (!modelPath || !this.isEnable || !isActive) { return; } const type = this.#type; const name = this.name; const recordTime = this.#recordTime; if (type === 'text') { this.#module = new TextLearning({ url: modelPath, labels: this.#labels, type, modelId: this.#modelId, loadModel: this.#dataApi?.loadModel, }); } else if (type === 'number') { this.#tableData = tableData || createDataTable(classes, name); this.#module = new NumberClassification({ name, result: this.result, url: modelPath, trainParam, table: this.#tableData, modelId: this.#modelId, loadModel: this.#dataApi?.loadModel, }); this.#labels = this.#module.getLabels(); } else if (type === 'cluster') { this.#tableData = tableData || createDataTable(classes, name); this.#module = new Cluster({ name, result: this.result, trainParam, table: this.#tableData, }); } else if (type === 'regression') { this.#tableData = tableData || createDataTable(classes, name); this.#module = new Regression({ name, result: this.result, url: modelPath, trainParam, table: this.#tableData, }); } else if (type === 'image') { this.#module = new ImageLearning({ url: modelPath, labels: this.#labels, type, }); } else if (type === 'speech') { this.#module = new SpeechClassification({ url: modelPath, labels: this.#labels, type, recordTime, }); } else if (type === 'logisticRegression') { this.#tableData = tableData || createDataTable(classes, name); this.#module = new LogisticRegression({ name, result: this.result, url: modelPath, trainParam, table: this.#tableData, }); } else if (type === 'decisionTree') { this.#tableData = tableData || createDataTable(classes, name); this.#module = new DecisionTree({ name, result: this.result, url: modelPath, trainParam, table: this.#tableData, modelId: this.#modelId, loadModel: this.#dataApi?.loadModel, }); } else if (type === 'svm') { this.#tableData = tableData || createDataTable(classes, name); this.#module = new Svm({ name, result: this.result, url: modelPath, trainParam, table: this.#tableData, modelId: this.#modelId, loadModel: this.#dataApi?.loadModel, }); } if (this.#module) { this.unbanBlocks(); this.isLoaded = true; } } async load(modelInfo) { const { labels, type, classes = [], model, id, url, _id, isActive = true, name, recordTime, trainParam, tableData, result, } = modelInfo || {}; if (!this.#dataApi) { console.log('there is no dataApi'); return; } else if (_isEmpty(modelInfo)) { console.log('empty modelInfo'); return; } this.destroy(); if (!labels) { const parsed = classes.length === 1 && typeof classes[0] === 'string' ? JSON.parse(classes[0]) : classes; this.#labels = parsed.map(({ name }) => name); } else { this.#labels = labels; } this.#type = type; this.#url = url; this.#oid = _id; this.name = name; this.#modelId = model || id; this.#recordTime = recordTime; this.result = result; if (this.#playground) { this.#playground.reloadPlayground(); } this.loadModel({ url, trainParam, tableData, isActive, classes }); } async reload(url) { await this.#module?.reload?.(url); } openInputPopup() { this.#module?.openInputPopup?.(); } train() { this.#module?.train?.(); } isTrained() { return this.#module?.isTrained?.(); } setTrainOption(type, value) { this.#module?.setTrainOption?.(type, value); } getTrainOption() { return this.#module?.getTrainOption?.(); } getTableData() { return this.#tableData; } getTrainResult() { return this.#module?.getTrainResult?.(); } getPredictResult(index) { return this.#module?.getResult?.(index); } getId() { return this.#modelId; } setVisible(visible) { this.#module?.setVisible?.(visible); } setChartVisible(visible) { if (visible) { this.#module?.openChart?.(); } else { this.#module?.closeChart?.(); } } openManager() { if (this.isEnable) { Entry.dispatchEvent('openAIUtilizeTrainManager'); } else { console.log('Disabled learning for offline'); } } async predict(obj) { if (this.#module && this.#module.predict) { this.result = await this.#module.predict(obj); } return []; } startPredict() { if (this.#module && this.#module.startPredict) { this.#module.startPredict(); } } stopPredict() { if (this.#module && this.#module.stopPredict) { this.#module.stopPredict(); } } unbanBlocks() { this.banBlocks(); const blockMenu = getBlockMenu(this.#playground); if (blockMenu) { this.#module?.unbanBlocks?.(blockMenu); } } banBlocks() { const blockMenu = getBlockMenu(this.#playground); if (blockMenu) { banClasses.forEach((clazz) => { blockMenu.banClass(clazz); }); } } destroy() { this.#labels = []; this.#url = null; this.#type = null; this.isLoading = false; this.result = []; this.isLoaded = false; this.#recordTime = 2000; this.#tableData = null; if (this.#module) { this.#module?.destroy?.(); this.#module = null; } } toJSON() { if (!this.isLoaded) { return; } return { labels: this.#labels, url: this.#url, type: this.#type, id: this.#modelId, _id: this.#oid, recordTime: this.#recordTime, trainParam: this.getTrainOption(), result: this.getTrainResult(), tableData: this.#tableData, }; } } function getBlockMenu(playground) { const { mainWorkspace } = playground; if (!mainWorkspace) { return; } const blockMenu = _.result(mainWorkspace, 'blockMenu'); if (!blockMenu) { return; } return blockMenu; } function createDataTable(classes, name) { if (!classes.length) { return; } try { const [{ samples }] = classes; const [sample = {}] = samples || []; let data = sample.data; data.id = data.id || data._id; if (typeof data === 'string') { data = JSON.parse(data); } if (data && data?.id && !DataTable.getSource(data?.id)) { DataTable.addSource(data, false); } return data; } catch (e) { console.log('set table error', e); } } ================================================ FILE: src/class/AIUtilize.js ================================================ import ExtraBlockUtils from '../util/extrablockUtils'; import '../playground/blocks/block_ai_utilize_audio'; import '../playground/blocks/block_ai_utilize_tts'; import '../playground/blocks/block_ai_utilize_translate'; import '../playground/blocks/block_ai_utilize_video'; import '../playground/blocks/block_ai_utilize_gesture_recognition'; import '../playground/blocks/block_ai_utilize_pose_landmarker'; import '../playground/blocks/block_ai_utilize_face_landmarker'; import '../playground/blocks/block_ai_utilize_object_detector'; export default class AIUtilize { constructor(playground) { this.playground = playground; } init() { const blockObject = {}; Object.entries(Entry.AI_UTILIZE_BLOCK).forEach(([key, value]) => { if (key === 'video') { Entry.AI_UTILIZE_BLOCK_LIST_DEPRECATED.video = value; } else { Entry.AI_UTILIZE_BLOCK_LIST[key] = value; } Entry.ALL_AI_UTILIZE_BLOCK_LIST[key] = value; if ('getBlocks' in value) { Object.assign(blockObject, value.getBlocks()); } }); Entry.block = Object.assign(Entry.block, blockObject); } banAllAIUtilizeBlock() { ExtraBlockUtils.banAllBlocks(this.playground, Entry.ALL_AI_UTILIZE_BLOCK_LIST); } banAIUtilizeBlocks(aiUtilizeNames = []) { ExtraBlockUtils.banBlocks( aiUtilizeNames, Entry.ALL_AI_UTILIZE_BLOCK_LIST, (aiUtilizeTypes) => Entry.do('objectRemoveAIUtilizeBlocks', aiUtilizeTypes).isPass(true) ); } isActive(aiUtilizeName) { return ExtraBlockUtils.isActive(aiUtilizeName, Entry.ALL_AI_UTILIZE_BLOCK_LIST); } addAIUtilizeBlocks(blockNames) { Entry.do('objectAddAIUtilizeBlocks', blockNames); } getAIUtilizes(blockList) { return ExtraBlockUtils.getExtras(blockList, 'category_ai_utilize'); } destroy() { // 우선 interface 만 정의함. } } ================================================ FILE: src/class/DataTable.js ================================================ import _map from 'lodash/map'; import _sum from 'lodash/sum'; import _find from 'lodash/find'; import _uniq from 'lodash/uniq'; import _every from 'lodash/every'; import _filter from 'lodash/filter'; import _flatten from 'lodash/flatten'; import _cloneDeep from 'lodash/cloneDeep'; import _findIndex from 'lodash/findIndex'; import _isEmpty from 'lodash/isEmpty'; import DataTableSource from './source/DataTableSource'; import { DataAnalytics, ModalChart, ModalTable } from '@entrylabs/tool'; class DataTable { #tables = []; #view; modals = []; selected; get tables() { return this.#tables; } get dataTables() { return _map( this.#tables, ({ id, fields, chart, name, origin, summary, provider, description, fieldInfos }) => ({ id, name, provider, description, fieldInfos, summary, chart: _cloneDeep(chart), table: [[...fields], ..._cloneDeep(origin)], }) ); } constructor() { this.#generateView(); } removeAllBlocks() { const { blocks } = EntryStatic.getAllBlocks().find( ({ category }) => category === 'analysis' ); blocks.forEach((blockType) => { Entry.Utils.removeBlockByType(blockType); }); this.banAllBlock(); this.clear(); } banAllBlock() { Entry.playground.blockMenu.banClass('analysis'); } unbanBlock() { Entry.playground.blockMenu.unbanClass('analysis'); } getTables(blockList = []) { return _uniq( _flatten( blockList .filter((block) => { const { _schema = {}, data = {} } = block || {}; if (!data.type) { return false; } const { isFor, isNotFor = [] } = _schema; const [key] = isNotFor; return key && isFor && key === 'analysis'; }) .map((block) => { const { params = [] } = block.data || {}; return params.filter((param) => { if (typeof param !== 'string') { return false; } return _find(this.#tables, { id: param }); }); }) ) ).map((tableId) => { const table = this.getSource(tableId); return table.toJSON(); }); } getSource(id) { if (!id) { console.warn('empty argument'); return null; } return _find(this.#tables, { id }) || _find(this.#tables, { _id: id }); } getIndex({ id }) { if (!id) { console.warn('empty argument'); return null; } return _findIndex(this.#tables, { id }); } addSource(table, view = true) { const data = table || { name: Lang.Workspace.data_table }; data.name = Entry.getOrderedName(data.name, this.#tables, 'name'); this.#tables.push(table instanceof DataTableSource ? table : new DataTableSource(table)); this.hide(); if (view) { this.show({ list: this.dataTables, selectedIndex: this.dataTables.length - 1 }); } } addSources(tables = []) { const dataTableSources = _map(tables, (table) => table instanceof DataTableSource ? table : new DataTableSource(table) ); this.#tables.push(...dataTableSources); this.hide(); this.show({ list: this.dataTables, selectedIndex: this.dataTables.length - 1 }); } changeItemPosition(start, end) { if (this.#tables.length) { this.#tables.splice(end, 0, this.#tables.splice(start, 1)[0]); } } setSource(selected) { const { chart, table, name, id } = selected; const source = this.getSource(id); if (source) { source.modal = null; source.setArray({ name, chart, fields: table[0], data: table.slice(1), }); source.updated = new Date(); } else { const newSource = new DataTableSource({ chart, data: table.slice(1), fields: table[0], name, }); this.#tables.push(newSource); selected.id = newSource.id; } } saveTable = ({ selected }) => { this.setSource(selected); Entry.playground.reloadPlayground(); Entry.creationChangedEvent?.notify(); }; removeTable = (index) => { this.#tables = _filter(this.#tables, (__, tIndex) => index !== tIndex); Entry.creationChangedEvent?.notify(); }; show(data) { if (!this.dataAnalytics) { this.#generateView(); } this.dataAnalytics.show( data || { selectedIndex: this.#tables.legnth - 1, list: this.dataTables } ); } hide() { this.dataAnalytics && this.dataAnalytics.hide(); if (this.#tables.length) { this.unbanBlock(); } else { this.banAllBlock(); } Entry.playground.reloadPlayground(); Entry.playground.refreshPlayground(); Entry.dispatchEvent('dismissModal'); } getColumnIndex(col) { if (Entry.Utils.isNumber(col)) { return parseFloat(col); } if (/[^A-Za-z]|\s/.test(col)) { return 0; } // return _.chain(col) // .toUpper() // .reduce((prev, curr) => prev * 26 + curr.charCodeAt() - 64, 0) // .value(); return _sum( _map( col, (cn, i) => (cn.toUpperCase().charCodeAt(0) - 64) * Math.pow(26, col.length - i - 1) ) ); } #generateView() { const view = document.createElement('div'); view.className = 'table-modal'; document.body.appendChild(view); this.dataAnalytics = new DataAnalytics({ container: view, data: {}, isShow: false }) .on('submit', this.saveTable) .on('alert', ({ message, title = Lang.DataAnalytics.max_row_count_error_title }) => Entry.modal.alert(message, title) ) .on('toast', (message) => { const { title, content } = message; Entry.toast.alert(title, content); }) .on('close', async () => { this.hide(); }) .on('addTable', () => { Entry.dispatchEvent('openTableManager'); }) .on('removeTable', this.removeTable); } getTableJSON() { return this.tables.filter(_.identity).map((v) => (v.toJSON ? v.toJSON() : v)); } setTables(tables = []) { if (_isEmpty(tables)) { return; } tables.forEach((table) => { const data = table || { name: Lang.Workspace.data_table }; data.name = Entry.getOrderedName(data.name, this.#tables, 'name'); const isDataTableSource = data instanceof DataTableSource; this.#tables.push(isDataTableSource ? data : new DataTableSource(data)); }); tables.length && this.refreshPlayground(); } refreshPlayground() { const isWorkspace = Entry.type === 'workspace'; if (isWorkspace) { this.unbanBlock(); Entry.playground.reloadPlayground(); Entry.playground.refreshPlayground(); } } showChart(tableId, chartIndex = 0) { this.closeModal(); const source = this.getSource(tableId); if (!source) { console.log(`not exist souce, table id: ${tableId}`); return; } let chart = source.modals.find((m) => m.name === 'chart'); if (!chart) { chart = this.createChart(source, chartIndex); source.modals.push(chart); this.modals.push(chart); } source.forceApply(); chart.show(undefined, { chartIndex }); } showTable(tableId) { this.closeModal(); const source = this.getSource(tableId); if (!source) { console.log(`not exist souce, table id: ${tableId}`); return; } let table = source.modals.find((m) => m.name === 'table'); if (!table) { table = this.createTable(source); source.modals.push(table); this.modals.push(table); } source.forceApply(); table.show(); } closeModal() { this.modals.forEach((m) => { m.hide(); }); } createChart(source, chartIndex = 0) { const { chart = [], fields, rows } = source; const container = Entry.Dom('div', { class: 'entry-table-chart', parent: $(Entry.modalContainer), })[0]; const modal = new ModalChart({ data: { chartIndex, source: { fields, origin: rows, chart }, togglePause: () => Entry.engine.togglePause(), stop: () => Entry.engine.toggleStop(), isIframe: self !== top, }, container, }); modal.name = 'chart'; return modal; } createTable(source) { const container = Entry.Dom('div', { class: 'entry-table-modal', parent: $(Entry.modalContainer), })[0]; const modal = new ModalTable({ data: { table: source, tables: this.tables, stop: () => Entry.engine.toggleStop(), isIframe: self !== top, togglePause: () => Entry.engine.togglePause(), }, container, }); modal.name = 'table'; return modal; } clear() { this.#tables = []; this.modals = []; } } Entry.DataTable = new DataTable(); export default Entry.DataTable; ================================================ FILE: src/class/Expansion.js ================================================ import ExtraBlockUtils from '../util/extrablockUtils'; import '../playground/blocks/block_expansion_weather'; import '../playground/blocks/block_expansion_festival'; import '../playground/blocks/block_expansion_behaviorconduct_disaster'; import '../playground/blocks/block_expansion_behaviorconduct_lifesafety'; import '../playground/blocks/block_expansion_emergencyActionGuidelines'; import '../playground/blocks/block_expansion_disasterAlert'; export default class Expansion { constructor(playground) { this.playground = playground; } async init() { const blockObject = {}; Object.entries(Entry.EXPANSION_BLOCK).forEach(([key, value]) => { if (!value.disabled) { Entry.EXPANSION_BLOCK_LIST[key] = value; } if ('getBlocks' in value) { Object.assign(blockObject, value.getBlocks()); } }); Entry.block = Object.assign(Entry.block, blockObject); } banAllExpansionBlock() { ExtraBlockUtils.banAllBlocks(this.playground, Entry.EXPANSION_BLOCK_LIST); } banExpansionBlocks(expansionNames) { ExtraBlockUtils.banBlocks(expansionNames, Entry.EXPANSION_BLOCK_LIST, (expansionTypes) => Entry.do('objectRemoveExpansionBlocks', expansionTypes).isPass(true) ); } isActive(expansionName) { return ExtraBlockUtils.isActive(expansionName, Entry.EXPANSION_BLOCK_LIST); } addExpansionBlocks(blockNames) { Entry.do('objectAddExpansionBlocks', blockNames); } getExpansions(blockList) { return ExtraBlockUtils.getExtras(blockList, 'category_expansion'); } destroy() { // 우선 interface 만 정의함. } } ================================================ FILE: src/class/LiterallycanvasPainter.js ================================================ 'use strict'; Entry.LiterallycanvasPainter = class LiterallycanvasPainter { constructor(view) { this.view = view; this.baseUrl = Entry.painterBaseUrl; this.file = { id: Entry.generateHash(), name: '새그림', modified: false, mode: 'new', // new or edit }; this._keyboardEvents = []; Entry.addEventListener('pictureImport', this.addPicture.bind(this)); Entry.addEventListener('run', this.detachKeyboardEvents.bind(this)); Entry.addEventListener('stop', this.attachKeyboardEvents.bind(this)); //dropdown header dispose $('body').on('mouseup', '.active li', () => { $('.painterTopHeader.active').removeClass('active'); }); this.clipboard = null; } initialize() { if (this.lc) { return; } const that = this; const imgURL = that.baseUrl; const bgImage = new Image(); bgImage.src = `${imgURL}/transparent-pattern.png`; const WIDTH = 960; const HEIGHT = 540; that.lc = LC.init(that.view, { imageURLPrefix: imgURL, zoomMax: 3.0, zoomMin: 0.5, toolbarPosition: 'bottom', imageSize: { width: WIDTH, height: HEIGHT }, backgroundShapes: [ LC.createShape('Rectangle', { x: 0, y: 0, width: WIDTH, height: HEIGHT, strokeWidth: 0, strokeColor: 'transparent', }), ], }); //that.lc.respondToSizeChange(); bgImage.onload = function () { that.lc.repaintLayer('background'); }; const watchFunc = function (e) { if (e && ((e.shape && !e.opts && e.shape.isPass) || (e.opts && e.opts.isPass))) { Entry.do('processPicture', e, that.lc); } else { Entry.do('editPicture', e, that.lc); } if (Entry.stage.selectedObject) { that.file.modified = true; } }; that.lc.on('clear', watchFunc); that.lc.on('remove', watchFunc); that.lc.on('shapeEdit', watchFunc); that.lc.on('shapeSave', watchFunc); that.lc.on('toolChange', that.updateEditMenu.bind(that)); that.lc.on('lc-pointerdrag', that.stagemousemove.bind(that)); that.lc.on('lc-pointermove', that.stagemousemove.bind(that)); that.initTopBar(); that.updateEditMenu(); that.attachKeyboardEvents(); } show() { if (!this.lc) { this.initialize(); } this.isShow = true; } hide() { this.isShow = false; } changePicture(picture = {}) { if (this.file && this.file.id === picture.id) { if (!this.file.isUpdate) { Entry.stage.updateObject(); this.file.isUpdate = true; } return; } else if (!this.file.modified) { this.afterModified(picture); } else { if (this.isConfirm) { return; } this.isConfirm = true; let wasRun = false; if (Entry.engine.state === 'run') { Entry.engine.toggleStop(); wasRun = true; } Entry.modal.confirm(Lang.Menus.save_modified_shape).then((result) => { this.isConfirm = false; if (result === true) { this.fileSave(true); } else { this.file.modified = false; } if (!wasRun) { this.afterModified(picture); } else { Entry.playground.injectPicture(); } }); } Entry.stage.updateObject(); this.file.isUpdate = true; } afterModified(picture) { const file = this.file; file.modified = false; this.lc.clear(false); if (picture.id) { file.id = picture.id || Entry.generateHash(); file.name = picture.name; file.mode = 'edit'; file.objectId = picture.objectId; this.addPicture(picture, true); } else { file.id = Entry.generateHash(); } // INFO: picture 변경시마다 undoStack 리셋 this.lc.undoStack = []; Entry.stateManager.removeAllPictureCommand(); } getImageSrc(picture) { const { fileurl } = picture || {}; if (fileurl) { return fileurl; } const { imageType = 'png', filename } = picture || {}; return `${Entry.defaultPath}/uploads/${filename.substring(0, 2)}/${filename.substring( 2, 4 )}/image/${filename}.${imageType}`; } addPicture(picture, isOriginal) { const image = new Image(); if (picture.fileurl) { image.src = picture.fileurl; } else { // deprecated image.src = `${Entry.defaultPath}/uploads/${picture.filename.substring( 0, 2 )}/${picture.filename.substring(2, 4)}/image/${picture.filename}.png`; } const dimension = picture.dimension; const shape = LC.createShape('Image', { x: 480, y: 270, width: dimension.width, height: dimension.height, image, }); this.lc.saveShape(shape, !isOriginal); image.onload = function () { this.lc.setTool(this.lc.tools.SelectShape); this.lc.tool.setShape(this.lc, shape); }.bind(this); } copy() { if (this.lc.tool.name !== 'SelectShape' || !this.lc.tool.selectedShape) { return; } const shape = this.lc.tool.selectedShape; this.clipboard = { className: shape.className, data: shape.toJSON(), }; this.updateEditMenu(); } cut() { if (this.lc.tool.name !== 'SelectShape' || !this.lc.tool.selectedShape) { return; } this.copy(); const shape = this.lc.tool.selectedShape; this.lc.removeShape(shape); this.lc.tool.setShape(this.lc, null); } paste() { if (!this.clipboard) { return; } const shape = this.lc.addShape(this.clipboard); this.lc.setTool(this.lc.tools.SelectShape); this.lc.tool.setShape(this.lc, shape); } updateEditMenu() { const isSelected = this.lc.tool.name === 'SelectShape' ? 'block' : 'none'; // this._cutButton.style.display = isSelected; // this._copyButton.style.display = isSelected; // this._pasteButton.style.display = this.clipboard ? "block" : "none"; } fileSave(taskParam) { if (!Entry.stage.selectedObject) { return; } this.lc.trigger('dispose'); const dataURL = this.lc.getImage().toDataURL(); this.file_ = JSON.parse(JSON.stringify(this.file)); Entry.dispatchEvent('saveCanvasImage', { file: this.file_, image: dataURL, task: taskParam, }); this.file.isUpdate = false; this.file.modified = false; } newPicture() { if (!Entry.stage.selectedObject) { return; } const newPicture = { dimension: { height: 1, width: 1, }, //filename: "_1x1", fileurl: `${Entry.mediaFilePath}_1x1.png`, thumbUrl: `${Entry.mediaFilePath}_1x1.png`, name: Lang.Painter.new_picture, }; newPicture.id = Entry.generateHash(); if (this.file && this.file.objectId) { newPicture.objectId = this.file.objectId; } Entry.playground.addPicture(newPicture, true); } _keyboardPressControl(e) { if (!this.isShow || Entry.Utils.isInInput(e)) { return; } const keyCode = e.keyCode || e.which; const ctrlKey = e.ctrlKey; if (keyCode == 8 || keyCode == 46) { //destroy this.cut(); e.preventDefault(); } else if (ctrlKey) { if (keyCode == 67) { //copy this.copy(); } else if (keyCode == 88) { //cut this.cut(); } } if (ctrlKey && keyCode == 86) { //paste this.paste(); } this.lc.trigger('keyDown', e); } _keyboardUpControl(e) { if (!this.isShow || Entry.Utils.isInInput(e)) { return; } this.lc.trigger('keyUp', e); } toggleFullscreen(isFullscreen) { const { painter = {}, pictureView_ } = Entry.playground; const { view = {} } = painter; const $view = $(view); if ((isFullscreen !== true && $view.hasClass('fullscreen')) || isFullscreen === false) { pictureView_.appendChild(view); $(view).removeClass('fullscreen'); if (this.fullscreenButton) { this.fullscreenButton.setAttribute('title', Lang.Painter.fullscreen); this.fullscreenButton.setAttribute('alt', Lang.Painter.fullscreen); } } else { document.body.appendChild(view); $(view).addClass('fullscreen'); if (this.fullscreenButton) { this.fullscreenButton.setAttribute('title', Lang.Painter.exit_fullscreen); this.fullscreenButton.setAttribute('alt', Lang.Painter.exit_fullscreen); } } $(view).find('.lc-drawing.with-gui').trigger('resize'); } initTopBar() { const painter = this; const ce = Entry.createElement; const painterTop = ce(document.getElementById('canvas-top-menu')); painterTop.addClass('entryPlaygroundPainterTop'); painterTop.addClass('entryPainterTop'); const painterTopFullscreenButton = ce('div', 'entryPainterTopFullscreenButton'); painterTopFullscreenButton.setAttribute('title', Lang.Painter.fullscreen); painterTopFullscreenButton.setAttribute('alt', Lang.Painter.fullscreen); painterTopFullscreenButton.addClass('entryPlaygroundPainterFullscreenButton'); painterTopFullscreenButton.bindOnClick(() => { this.toggleFullscreen(); }); this.fullscreenButton = painterTopFullscreenButton; painterTop.appendChild(painterTopFullscreenButton); const painterTopMenu = ce('nav', 'entryPainterTopMenu'); painterTopMenu.addClass('entryPlaygroundPainterTopMenu'); painterTop.appendChild(painterTopMenu); const painterTopMenuFileNew = ce('div', 'entryPainterTopMenuFileNew'); painterTopMenuFileNew.bindOnClick(painter.newPicture.bind(this)); painterTopMenuFileNew.addClass('entryPlaygroundPainterTopMenuFileNew'); painterTopMenuFileNew.innerHTML = Lang.Painter.new_picture; painterTopMenu.appendChild(painterTopMenuFileNew); const painterTopMenuFile = ce('div', 'entryPainterTopMenuFile'); painterTopMenuFile.addClass('entryPlaygroundPainterTopMenuFile painterTopHeader'); painterTopMenuFile.innerHTML = Lang.Painter.file; const painterTopMenuFileDropdown = ce('div'); painterTopMenuFileDropdown.addClass('entryPlaygroundPainterTopMenuFileDropdown'); painterTopMenu.appendChild(painterTopMenuFile); painterTopMenuFile.appendChild(painterTopMenuFileDropdown); const painterTopMenuEdit = ce('div', 'entryPainterTopMenuEdit'); painterTopMenuEdit.addClass('entryPlaygroundPainterTopMenuEdit painterTopHeader'); painterTopMenuEdit.innerHTML = Lang.Painter.edit; painterTopMenu.appendChild(painterTopMenuEdit); const painterTopMenuFileSave = ce('div', 'entryPainterTopMenuFileSave'); painterTopMenuFileSave.bindOnClick(() => { painter.fileSave(false); }); painterTopMenuFileSave.addClass('entryPainterTopMenuFileSave'); painterTopMenuFileSave.innerHTML = Lang.Painter.painter_file_save; painterTopMenuFileDropdown.appendChild(painterTopMenuFileSave); const painterTopMenuFileSaveAsLink = ce('div', 'entryPainterTopMenuFileSaveAs'); painterTopMenuFileSaveAsLink.bindOnClick(() => { painter.file.mode = 'new'; painter.fileSave(false); }); painterTopMenuFileSaveAsLink.addClass('entryPlaygroundPainterTopMenuFileSaveAs'); painterTopMenuFileSaveAsLink.innerHTML = Lang.Painter.painter_file_saveas; painterTopMenuFileDropdown.appendChild(painterTopMenuFileSaveAsLink); const painterTopMenuEditDropdown = ce('div'); painterTopMenuEditDropdown.addClass('entryPlaygroundPainterTopMenuEditDropdown'); painterTopMenuEdit.appendChild(painterTopMenuEditDropdown); const painterTopMenuEditImport = ce('div', 'entryPainterTopMenuEditImport'); painterTopMenuEditImport.bindOnClick(() => { Entry.dispatchEvent('openPictureImport'); }); painterTopMenuEditImport.addClass('entryPainterTopMenuEditImport'); painterTopMenuEditImport.innerHTML = Lang.Painter.get_file; painterTopMenuEditDropdown.appendChild(painterTopMenuEditImport); const painterTopMenuEditCopy = ce('div', 'entryPainterTopMenuEditCopy'); painterTopMenuEditCopy.bindOnClick(() => { painter.copy(); }); painterTopMenuEditCopy.addClass('entryPlaygroundPainterTopMenuEditCopy'); painterTopMenuEditCopy.innerHTML = Lang.Painter.copy_file; painterTopMenuEditDropdown.appendChild(painterTopMenuEditCopy); const painterTopMenuEditCut = ce('div', 'entryPainterTopMenuEditCut'); painterTopMenuEditCut.bindOnClick(() => { painter.cut(); }); painterTopMenuEditCut.addClass('entryPlaygroundPainterTopMenuEditCut'); painterTopMenuEditCut.innerHTML = Lang.Painter.cut_picture; painterTopMenuEditDropdown.appendChild(painterTopMenuEditCut); const painterTopMenuEditPaste = ce('div', 'entryPainterTopMenuEditPaste'); painterTopMenuEditPaste.bindOnClick(() => { painter.paste(); }); painterTopMenuEditPaste.addClass('entryPlaygroundPainterTopMenuEditPaste'); painterTopMenuEditPaste.innerHTML = Lang.Painter.paste_picture; painterTopMenuEditDropdown.appendChild(painterTopMenuEditPaste); const painterTopMenuEditEraseAll = ce('div', 'entryPainterTopMenuEditEraseAll'); painterTopMenuEditEraseAll.addClass('entryPlaygroundPainterTopMenuEditEraseAll'); painterTopMenuEditEraseAll.innerHTML = Lang.Painter.remove_all; painterTopMenuEditEraseAll.bindOnClick(() => { painter.lc.clear(); }); painterTopMenuEditDropdown.appendChild(painterTopMenuEditEraseAll); $(painterTopMenuFile).on('click tab', menuClickEvent); $(painterTopMenuEdit).on('click tab', menuClickEvent); $(document).on('click tap', (e) => { e.stopPropagation(); $(painterTopMenuFile).removeClass('active'); $(painterTopMenuEdit).removeClass('active'); }); const painterTopStageXY = ce('div', 'entryPainterTopStageXY'); const entryPainterTopStageXYLabel = ce('span', 'entryPainterTopStageXYLabel'); this.painterTopStageXY = entryPainterTopStageXYLabel; painterTopStageXY.addClass('entryPlaygroundPainterTopStageXY'); entryPainterTopStageXYLabel.addClass('entryPainterTopStageXYLabel'); painterTopStageXY.appendChild(entryPainterTopStageXYLabel); painterTop.appendChild(painterTopStageXY); Entry.addEventListener('pictureSelected', this.changePicture.bind(this)); function menuClickEvent(e) { $(painterTopMenuFile).removeClass('active'); $(painterTopMenuEdit).removeClass('active'); if (e.target === this) { e.stopImmediatePropagation(); $(this).addClass('active'); } } } stagemousemove(event) { this.painterTopStageXY.textContent = `x:${event.x.toFixed(1)}, y:${event.y.toFixed(1)}`; } attachKeyboardEvents() { this.detachKeyboardEvents(); const events = this._keyboardEvents; let evt = Entry.keyPressed; evt && events.push(evt.attach(this, this._keyboardPressControl)); evt = Entry.keyUpped; evt && events.push(evt.attach(this, this._keyboardUpControl)); } detachKeyboardEvents() { const events = this._keyboardEvents; if (!events || !events.length) { return; } while (events.length) { const evt = events.pop(); evt.destroy && evt.destroy(); } } clear() { this.toggleFullscreen(false); } undo() { this.lc.undo(); } redo() { if (this.lc.canRedo()) { this.lc.redo(); } } }; ================================================ FILE: src/class/blockCountViewer.js ================================================ import _get from 'lodash/get'; Entry.BlockCountViewer = class { constructor() { if (!Entry.codeChangedEvent) { Entry.codeChangedEvent = new Entry.Event(window); } const updateView = () => { Entry.Utils.clearObjectsBlocksForEventThread(); this.updateView(); }; Entry.codeChangedEvent.attach(this, updateView); Entry.addEventListener('loadComplete', updateView); } generateView(sceneView, option) { this.view_ = sceneView; if (!option || option === 'workspace' || option === 'playground') { const blockCountView = Entry.createElement('span').addClass('blockCountView'); this.view_.appendChild(blockCountView); this.blockCountView = blockCountView; this.updateView(); } } async updateView() { if (this.blockCountView) { const blocks = await Entry.Utils.getObjectsBlocksForEventThread(); const count = _get(blocks, 'length', 0); let langText = Lang.Workspace.use_blocks_project; if (count === 1) { langText = Lang.Workspace.use_block_project; } this.blockCountView.innerHTML = Entry.Utils.stringFormat( langText, `${Entry.Utils.shortenNumber(count)}` ); } } destroy() { // 우선 interface 만 정의함. } }; ================================================ FILE: src/class/container.js ================================================ /** * @fileoverview Container handle all object in entry. */ 'use strict'; import { Draggable } from '@entrylabs/tool'; import { GEHelper } from '../graphicEngine/GEHelper'; import DataTable from './DataTable'; import { getInputList } from '@entrylabs/legacy-video'; /** * Class for a container. * This have view for objects. * @constructor */ Entry.Container = class Container { constructor() { /** * Array for entry objects * @type {Array.} */ this.objects_ = []; /** * Dictionary for caching images * @type {Dictionary.} */ this.currentObjects_ = null; this._extensionObjects = []; Entry.addEventListener('workspaceChangeMode', () => { const ws = Entry.getMainWS(); if (ws && ws.getMode() === Entry.Workspace.MODE_VIMBOARD) { this.objects_.forEach(({ script }) => { script && script.destroyView(); }); } }); Entry.addEventListener('run', this.disableSort.bind(this)); Entry.addEventListener('stop', this.enableSort.bind(this)); } /** * Control bar view generator. * @param {!Element} containerView containerView from Entry. */ generateView(containerView) { this._view = containerView; this._view.addClass('entryContainer'); this._view.addClass('entryContainerWorkspace'); this._view.setAttribute('id', 'entryContainerWorkspaceId'); const addButton = Entry.createElement('div') .addClass('entryAddObjectWorkspace') .bindOnClick(() => { Entry.dispatchEvent('openSpriteManager'); }); addButton.textContent = Lang.Workspace.add_object; const ulWrapper = Entry.createElement('div'); this._view.appendChild(ulWrapper); // const scroll = new Simplebar(ulWrapper, { autoHide: false }); const scrollWrapper = ulWrapper; let baseClass = 'entryContainerListWorkspaceWrapper'; if (Entry.isForLecture) { baseClass += ' lecture'; } scrollWrapper.addClass(baseClass); Entry.Utils.disableContextmenu(scrollWrapper); const longPressEvent = (e) => { let longPressTimer = null; const doc = $(document); longPressTimer = setTimeout(() => { if (longPressTimer) { longPressTimer = null; this._rightClick(e); } }, 1000); const event = Entry.Utils.convertMouseEvent(e); const mouseDownCoordinate = { x: event.clientX, y: event.clientY }; // 움직임 포착된 경우 타이머 종료 doc.bind('mousemove.container touchmove.container', (e) => { const event = Entry.Utils.convertMouseEvent(e); const moveThreshold = 5; if (!mouseDownCoordinate) { return; } const diff = Math.sqrt( Math.pow(event.pageX - mouseDownCoordinate.x, 2) + Math.pow(event.pageY - mouseDownCoordinate.y, 2) ); if (diff > moveThreshold && longPressTimer) { clearTimeout(longPressTimer); longPressTimer = null; } }); // 터치가 끝난 경우 타이머 종료 doc.bind('mouseup.container touchend.container', () => { doc.unbind('.container'); if (longPressTimer) { clearTimeout(longPressTimer); longPressTimer = null; } }); }; /* * 오른쪽 버튼 클릭 시 컨텍스트메뉴 발생 */ scrollWrapper.addEventListener('mousedown', (e) => { if (Entry.Utils.isRightButton(e)) { e.stopPropagation(); this._rightClick(e); } if (Entry.isMobile()) { e.stopPropagation(); longPressEvent(e); } }); /* * 터치 디바이스의 롱클릭 대응. touch 1초간 유지시 컨텍스트메뉴 발생. * 현재위치에서 일정 범위 이상 벗어난 경우취소 */ scrollWrapper.addEventListener('touchstart', (e) => { if (e.eventFromEntryObject) { return; } longPressEvent(e); }); const extensionListView = Entry.createElement('ul'); scrollWrapper.appendChild(extensionListView); this._extensionListView = Entry.Dom(extensionListView, { class: 'entryContainerExtensions', }); const listView = Entry.createElement('ul').addClass('entryContainerListWorkspace'); scrollWrapper.appendChild(listView); this.listView_ = listView; this.enableSort(); } enableSort() { if (this.sortableListViewWidget) { this.sortableListViewWidget.setData({ disabled: false, }); } else { const draggableOption = {}; if (Entry.isMobile()) { draggableOption.lockAxis = 'y'; draggableOption.distance = 50; } this.sortableListViewWidget = new Draggable({ data: { ...draggableOption, canSortable: true, sortableTarget: ['entryObjectThumbnailWorkspace'], items: this._getSortableObjectList(), itemShadowStyle: { position: 'absolute', height: '100%', width: '100%', backgroundColor: '#8aa3b2', border: 'solid 1px #728997', }, onDragActionChange: (isDragging, key) => { if (!Entry.objectEditable) { return; } Entry.ContextMenu.hide(); if (isDragging) { this.selectedObject.setObjectFold(isDragging, true); } else { this.selectedObject.resetObjectFold(); } Entry.playground.setBackpackPointEvent(isDragging); this.dragObjectKey = key; this.isObjectDragging = isDragging; }, onChangeList: (newIndex, oldIndex) => { if (!Entry.objectEditable) { return; } if (newIndex !== oldIndex) { Entry.do('objectReorder', newIndex, oldIndex); } }, }, container: this.listView_, }); } } updateSortableObjectList(objects) { this.sortableListViewWidget.setData({ items: this._getSortableObjectList(objects), }); } _getSortableObjectList(objects) { const targetObjects = objects || this.currentObjects_ || []; return targetObjects.map((value) => { const { id, view_, thumbUrl } = value; return { key: id, item: view_, image: thumbUrl, }; }); } /** * disable sort. */ disableSort() { const view = this.listView_; if (!view) { return; } this.sortableListViewWidget.setData({ disabled: true }); } /** * update list view to sort item. */ updateListView() { const view = this.listView_; if (!view) { return; } let objs = this.getCurrentObjects().slice(); const ret = objs.filter(({ index }) => index !== undefined); if (ret.length === objs.length) { objs = objs.sort((a, b) => a.index - b.index); } objs.forEach((obj) => { !obj.view_ && obj.generateView(); }); Entry.stage.sortZorder(); this.updateSortableObjectList(objs); return true; } setObjects(objectModels) { objectModels.forEach((model) => { if (model) { const object = new Entry.EntryObject(model); this.objects_.push(object); } }); this.updateObjectsOrder(); this.updateListView(); Entry.variableContainer.updateViews(); const type = Entry.type; if (type === 'workspace' || type === 'phone' || type === 'playground') { const target = this.getCurrentObjects()[0]; target && this.selectObject(target.id); } } /** * get Pictures element * @param {!String} pictureId */ getPictureElement(pictureId, objectId) { const object = this.getObject(objectId); const picture = object.getPicture(pictureId); if (picture) { return picture.view; } else { throw new Error('No picture found'); } } /** * Set Pictures * @param {!Object picture} picture */ setPicture(picture) { const pictures = this.getObject(picture.objectId).pictures; const index = _.findIndex(pictures, ({ id }) => id === picture.id); if (!~index) { throw new Error('No picture found'); } pictures[index] = Object.assign( _.pick(picture, [ 'dimension', 'id', 'filename', 'fileurl', 'thumbUrl', 'name', 'imageType', ]), { view: pictures[index].view } ); } /** * Set Pictures * @param {!String} pictureId */ selectPicture(pictureId, objectId) { const object = this.getObject(objectId); const picture_ = object.getPicture(pictureId); if (picture_) { object.selectedPicture = picture_; object.entity.setImage(picture_); object.updateThumbnailView(); this.sortableListViewWidget.setData({ items: this._getSortableObjectList(), }); return object.id; } throw new Error('No picture found'); } selectSound(soundId, objectId) { const object = this.getObject(objectId); const sound = object.getSound(soundId); if (sound) { object.selectedSound = sound; return object.id; } throw new Error('No sound found'); } /** * Add object * @param {!object model} objectModel * @param {?number} index exist when user add object * @return {Entry.EntryObject} */ addObject(objectModel, ...rest) { let target; if ('name' in objectModel.sprite) { target = objectModel.sprite; } else { target = objectModel; if (!target.name) { target.name = 'untitled'; } } target.name = Entry.getOrderedName(target.name, this.objects_); objectModel.id = objectModel.id || Entry.generateHash(); return Entry.do('addObject', objectModel, ...rest); } addObjectFunc(objectModel, index, isNotRender) { delete objectModel.scene; const object = new Entry.EntryObject(objectModel); object.scene = Entry.scene.selectedScene; let isBackground = objectModel.sprite.category || {}; isBackground = isBackground.main === 'background'; if (typeof index === 'number') { if (isBackground) { object.setLock(true); this.objects_.push(object); } else { this.objects_.splice(index, 0, object); } } else if (isBackground) { this.objects_.push(object); } else { this.objects_.unshift(object); } if (!isNotRender) { object.generateView(); this.setCurrentObjects(); this.selectObject(object.id); this.updateObjectsOrder(); this.updateListView(); Entry.variableContainer.updateViews(); Entry.variableContainer.updateList(); } } renderObject(object) { object.generateView(); this.setCurrentObjects(); this.selectObject(object.id); Entry.variableContainer.updateViews(); } addExtension(obj) { this._extensionObjects.push(obj); if (this._extensionListView) { this._extensionListView.append(obj.renderView()); } return obj; } removeExtension(obj) { if (!obj) { return; } const extensions = this._extensionObjects; const index = extensions.indexOf(obj); if (~index) { extensions.splice(index, 1); } obj.destroy && obj.destroy(); } /** * Add Clone object * @param {!Entry.EntryObject} object */ addCloneObject(object, scene, isNotRender) { const json = object.toJSON(true); json.script = change('sounds', object, json); json.script = change('pictures', object, json); Entry.variableContainer.addCloneLocalVariables({ objectId: object.id, newObjectId: json.id, json, }); json.scene = scene || Entry.scene.selectedScene; this.addObject(json, null, isNotRender); return this.getObject(json.id); function change(keyName, object, jsonData) { const target = jsonData.sprite[keyName]; let script = jsonData.script; (object[keyName] || []).forEach((value, index) => { script = script.replace(new RegExp(value.id, 'g'), target[index].id); }); return script; } } removeObject(id, isPass) { const objects = this.objects_; const object = this.getObject(id); const index = objects.indexOf(object); object.destroy(); objects.splice(index, 1); Entry.variableContainer.removeLocalVariables(object.id); Entry.engine.hideProjectTimer(); if (isPass === true) { return; } this.setCurrentObjects(); Entry.stage.sortZorder(); const [first] = this.getCurrentObjects(); if (first) { this.selectObject(first.id); } else { Entry.stage.selectObject(null); Entry.playground.flushPlayground(); } this.updateListView(); Entry.playground.reloadPlayground(); GEHelper.resManager.imageRemoved('container::removeObject'); } /** * Select object * @param {string} objectId */ selectObject(objectId, changeScene) { if (!objectId) { return; } const object = this.getObject(objectId); const workspace = Entry.getMainWS(); const isSelected = object && object.isSelected(); if (changeScene && object) { Entry.scene.selectScene(object.scene); } const className = 'selectedObject'; this.mapObjectOnScene((o) => { !o.view_ && _.result(o, 'generateView'); const selected = o === object; const view = o.view_; if (view) { if (selected) { view.addClass(className); } else { view.removeClass(className); o.setObjectFold(false); } } o.isSelected_ = selected; }); if (object) { if (workspace && workspace.vimBoard && Entry.isTextMode) { const sObject = workspace.vimBoard._currentObject; const parser = workspace.vimBoard._parser; if (sObject && !this.getObject(sObject.id)) { } else if (parser && parser._onError) { if (sObject && object.id != sObject.id) { if (!Entry.scene.isSceneCloning) { try { workspace._syncTextCode(); } catch (e) {} if (parser && !parser._onError) { this.selectObject(object.id, true); return; } else { this.selectObject(sObject.id, true); return; } } else { this.selectObject(sObject.id); return; } } } else { if (sObject && object.id != sObject.id) { if (!Entry.scene.isSceneCloning) { try { workspace._syncTextCode(); } catch (e) {} if (parser && parser._onError) { this.selectObject(sObject.id, true); return; } } else { this.selectObject(sObject.id); return; } } } } } else { workspace && workspace.vimBoard && workspace.vimBoard.clearText(); } if (Entry.playground) { object ? Entry.playground.injectObject(object) : Entry.playground.injectEmptyObject(); } if (Entry.type !== 'minimize' && Entry.engine.isState('stop')) { Entry.stage.selectObject(object); } this.selectedObject = object; !isSelected && object && object.updateCoordinateView(); } /** * Get all objects */ getAllObjects() { return this.objects_; } /** * Object Getter * @param {string} objectId * @return {Entry.EntryObject} */ getObject(objectId) { const playground = Entry.playground; if (!objectId && playground && playground.object) { objectId = playground.object.id; } else if (objectId instanceof Entry.EntryObject) { return objectId; } return _.find(this.objects_, { id: objectId }); } /** * Entity Getter * @param {string} objectId * @return {Entry.EntityObject} */ getEntity(objectId) { const object = this.getObject(objectId); if (!object) { return Entry.toast.alert( Lang.Msgs.runtime_error, Lang.Workspace.object_not_found, true ); } return object.entity; } /** * get variable on canvas * @return {Entry.Variable} */ getVariable(variableId) { for (let i = 0; i < this.variables_.length; i++) { const variable = this.variables_[i]; if (variable.getId() == variableId) { return variable; } if (variable.getName() == variableId) { return variable; } } } /** * Move object in objects_ * this method is for sortable * @param {number!} start * @param {number!} end * @param {boolean?} isCallFromState * @return {Entry.State} */ moveElement(end, start) { const objs = this.getCurrentObjects(); const startIndex = this.getAllObjects().indexOf(objs[start]); const endIndex = this.getAllObjects().indexOf(objs[end]); this.objects_.splice(endIndex, 0, this.objects_.splice(startIndex, 1)[0]); this.setCurrentObjects(); this.updateListView(); Entry.requestUpdate = true; } /** * generate list for dropdown dynamic * obj param for renderview.changeCode * @param {string} menuName * @param {string} obj */ async getDropdownList(menuName, obj) { let result = []; switch (menuName) { case 'sprites': result = this.getCurrentObjects().map(({ name, id }) => [name, id]); break; case 'allSprites': result = this.getAllObjects().map(({ name, id, scene = {} }) => { const { name: sceneName } = scene; return [`${sceneName} - ${name}`, id]; }); break; case 'spritesWithMouse': result = this.getCurrentObjects().map(({ name, id }) => [name, id]); result.push([Lang.Blocks.mouse_pointer, 'mouse']); break; case 'spritesWithSelf': result = this.getCurrentObjects().map(({ name, id }) => [name, id]); result.push([Lang.Blocks.self, 'self']); break; case 'textBoxWithSelf': { result = [ ...this.getCurrentObjects().reduce((acc, { objectType, name, id }) => { if (objectType === 'textBox') { acc.push([name, id]); } return acc; }, result), [Lang.Blocks.self, 'self'], ]; break; } case 'collision': result = [ [Lang.Blocks.mouse_pointer, 'mouse'], ...this.getCurrentObjects().map(({ name, id }) => [name, id]), [Lang.Blocks.wall, 'wall'], [Lang.Blocks.wall_up, 'wall_up'], [Lang.Blocks.wall_down, 'wall_down'], [Lang.Blocks.wall_right, 'wall_right'], [Lang.Blocks.wall_left, 'wall_left'], ]; break; case 'pictures': { const object = Entry.playground.object || obj; if (!object) { break; } result = (object.pictures || []).map(({ name, id }) => [name, id]); break; } case 'messages': result = Entry.variableContainer.messages_.map(({ name, id }) => [name, id]); break; case 'variables': { const object = Entry.playground.object || obj; if (!object) { break; } Entry.variableContainer.variables_.forEach((variable) => { if ( variable.object_ && object && (variable.object_ != object.id || Entry.Func.isEdit) ) { return; } result.push([variable.getName(), variable.getId()]); }); if (!result || result.length === 0) { // result.push([Lang.Blocks.VARIABLE_variable, 'null']); result = []; } break; } case 'lists': { const object = Entry.playground.object || obj; if (!object) { break; } Entry.variableContainer.lists_.forEach((list) => { if ( list.object_ && object && (list.object_ != object.id || Entry.Func.isEdit) ) { return; } result.push([list.getName(), list.getId()]); }); if (!result || result.length === 0) { // result.push([Lang.Blocks.VARIABLE_list, 'null']); result = []; } break; } case 'tables': { const { tables } = DataTable; if (tables) { result = tables.map((table) => [table.name, table.id]); } break; } case 'scenes': result = Entry.scene.getScenes().map(({ name, id }) => [name, id]); break; case 'sounds': { const object = Entry.playground.object || obj; if (!object) { break; } result = (object.sounds || []).map(({ name, id }) => [name, id]); break; } case 'clone': result = [ [Lang.Blocks.oneself, 'self'], ...this.getCurrentObjects().map(({ name, id }) => [name, id]), ]; break; case 'objectSequence': for (let i = 0; i < this.getCurrentObjects().length; i++) { result.push([(i + 1).toString(), i.toString()]); } break; case 'fonts': result = EntryStatic.fonts .filter((x) => x.visible) .map((font) => [font.name, font.family]); break; case 'connectedCameras': { const inputList = await getInputList(); result = [].concat( inputList .filter((input) => input.kind === 'videoinput') .map((item, index) => [ item.label || `Unspecified Device-${index + 1}`, index, ]) ); break; } case 'blockCount': result = [ [Lang.Blocks.this_project, 'all'], [Lang.Blocks.this_object, 'self'], ...this.getCurrentObjects().map(({ name, id }) => [name, `object-${id}`]), ...Entry.scene.getScenes().map(({ name, id }) => [name, `scene-${id}`]), ]; } if (!result.length) { result = [[Lang.Blocks.no_target, 'null']]; } return result; } /** * Initialize entities to state before run */ clearRunningState() { this.mapObject((object) => { object.clearExecutor(); }); } clearRunningStateOnScene() { this.mapObjectOnScene((object) => { if (object instanceof Entry.TargetChecker) { return; } object.clearExecutor(); }); } /** * Apply map function to objects. But this not replace object with returned one. * So giving map function don't have to return object. * And this support another arguments. * @param {!function} mapFunction * @param {} param */ mapObject(mapFunction, param) { return [...this._extensionObjects, ...this.objects_].map((object) => mapFunction(object, param) ); } mapObjectOnScene(mapFunction, param) { return [...this._extensionObjects, ...this.getCurrentObjects()].map((object) => mapFunction(object, param) ); } /** * Apply map function to objects. But this not replace object with returned one. * So giving map function don't have to return object. * And this support another arguments. * @param {!function} mapFunction * @param {} param */ mapEntity(mapFunction, param) { return this.objects_.map(({ entity }) => mapFunction(entity, param)); } mapEntityOnScene(mapFunction, param) { return this.getCurrentObjects().map(({ entity }) => mapFunction(entity, param)); } /** * Apply map function to objects. But this not replace object with returned one. * So giving map function don't have to return object. * And this support another arguments. * This also apply to cloned entities. * @param {!function} mapFunction * @param {} param */ mapEntityIncludeClone(mapFunction, param) { const objects = this.objects_; const length = objects.length; const output = []; for (let i = 0; i < length; i++) { const object = objects[i]; const lenx = object.clonedEntities.length; output.push(mapFunction(object.entity, param)); for (let j = 0; j < lenx; j++) { const entity = object.clonedEntities[j]; if (entity && !entity.isStamp) { output.push(mapFunction(entity, param)); } } } return output; } mapEntityIncludeCloneOnScene(mapFunction, param) { const objects = this.getCurrentObjects(); const length = objects.length; const output = []; for (let i = 0; i < this._extensionObjects.length; i++) { const object = this._extensionObjects[i]; output.push(mapFunction(object.entity, param)); } for (let i = 0; i < length; i++) { const object = objects[i]; output.push(mapFunction(object.entity, param)); object.getClonedEntities().forEach((entity) => { output.push(mapFunction(entity, param)); }); } return output; } /** * @deprecated 새로운 리소스 관리자 생겨서 이제 사용안함 * Get cached picture * @param {!string} pictureId * @return {?createjs.Image} */ getCachedPicture(pictureId) { Entry.assert(typeof pictureId === 'string', 'pictureId must be string'); return this.cachedPicture[pictureId]; } /** * @deprecated 새로운 리소스 관리자 생겨서 이제 사용안함 * cache picture * @param {!picture object} pictureModel */ cachePicture(pictureId, image) { this.cachedPicture[pictureId] = image; } /** * @deprecated 새로운 리소스 관리자 생겨서 이제 사용안함 * @param entity * @param pictures * @param isClone */ unCachePictures(entity, pictures, isClone) { if (!entity || !pictures) { return; } let entityId; if (pictures.constructor !== Array) { pictures = [pictures]; } if (entity.constructor === Entry.EntityObject) { entityId = entity.id; } else { entityId = entity; } pictures.forEach(({ id }) => { delete this.cachedPicture[id + (isClone ? '' : entityId)]; }); } /** * convert this object's data to JSON. * @return {JSON} */ toJSON() { return this.objects_.map((object) => object.toJSON()); } /** * take snapshot of current objects sequence */ takeSequenceSnapshot() { const length = this.objects_.length; const objects = this.objects_; for (let i = 0; i < length; i++) { objects[i].index = i; } } /** * load snapshot of original objects sequence */ loadSequenceSnapshot() { const length = this.objects_.length; const arr = new Array(length); for (let i = 0; i < length; i++) { const object = this.objects_[i]; const _index = object.index !== undefined ? object.index : i; arr[_index] = object; delete object.index; } this.objects_ = arr; this.setCurrentObjects(); Entry.stage.sortZorder(); this.updateListView(); } /** * return canvas inputValue * @return {String} */ getInputValue() { return this.inputValue.getValue(); } getSttValue() { return this.sttValue.getValue(); } /** * set canvas inputValue * @param {String} inputValue from canvas */ setInputValue(inputValue) { if (this.inputValue.complete) { return; } if (!inputValue) { this.inputValue.setValue(0); } else { this.inputValue.setValue(inputValue); } Entry.stage.hideInputField(); Entry.dispatchEvent('answerSubmitted'); if (Entry.console) { Entry.console.stopInput(inputValue); } this.inputValue.complete = true; } setSttValue(inputValue) { if (this.sttValue.complete) { return; } if (!inputValue) { this.sttValue.setValue(''); } else { this.sttValue.setValue(inputValue); } Entry.dispatchEvent('sttSubmitted'); this.sttValue.complete = true; } enableSttValue() { this.sttValue.complete = false; } resetSceneDuringRun() { if (!Entry.engine.isState('run')) { return; } this.mapEntityOnScene((entity) => { entity.reset(); }); this.clearRunningStateOnScene(); Entry.stage.hideInputField(); } setCopiedObject(object) { this.copiedObject = object; } updateObjectsOrder() { this.objects_ = Entry.scene .getScenes() .reduce((objs, scene) => [...objs, ...this.getSceneObjects(scene)], []); } /** * get objects list belonged to specific scene * @param {scene model} scene * @return {Array} */ getSceneObjects(scene) { scene = scene || Entry.scene.selectedScene; if (!scene) { return []; } const sceneId = scene.id; return this.getAllObjects().filter(({ scene: { id } }) => id === sceneId); } /** * set objects list belonged to specific scene */ setCurrentObjects() { this.currentObjects_ = this.getSceneObjects(); if (this.currentObjects_.length) { Entry.playground.hidePictureCurtain(); } else { Entry.playground.showPictureCurtain(); } } /** * get objects list belonged to current scene */ getCurrentObjects() { if (_.isEmpty(this.currentObjects_)) { this.setCurrentObjects(); } return this.currentObjects_ || []; } /** * get project jsons in art_view for saving especially for art_viewcontroller * @param {!resource project} project * @return {entry project} project */ getProjectWithJSON(project) { project.objects = this.toJSON(); project.variables = Entry.variableContainer.getVariableJSON(); project.messages = Entry.variableContainer.getMessageJSON(); project.scenes = Entry.scene.toJSON(); return project; } blurAllInputs() { this.getSceneObjects().map(({ view_ }) => { $(view_).find('input').blur(); }); } showProjectAnswer() { const answer = this.inputValue; if (!answer) { return; } answer.setVisible(true); } showSttAnswer() { const answer = this.sttValue; if (!answer) { return; } answer.setVisible(true); } hideProjectAnswer(removeBlock, notIncludeSelf) { const answer = this.inputValue; if (!answer || !answer.isVisible() || Entry.engine.isState('run')) { return; } const objects = this.getAllObjects(); const answerTypes = ['ask_and_wait', 'get_canvas_input_value', 'set_visible_answer']; for (let i = 0, len = objects.length; i < len; i++) { const code = objects[i].script; for (let j = 0; j < answerTypes.length; j++) { const blocks = code.getBlockList(false, answerTypes[j]); if (notIncludeSelf) { const index = blocks.indexOf(removeBlock); if (~index) { blocks.splice(index, 1); } } if (blocks.length) { return; } } } //answer related blocks not found //hide canvas answer view answer.setVisible(false); } hideSttAnswer(removeBlock, notIncludeSelf) { const answer = this.sttValue; if (!answer || !answer.isVisible() || Entry.engine.isState('run')) { return; } const objects = this.getAllObjects(); const answerTypes = ['ask_and_wait', 'get_canvas_input_value', 'set_visible_answer']; for (let i = 0, len = objects.length; i < len; i++) { const code = objects[i].script; for (let j = 0; j < answerTypes.length; j++) { const blocks = code.getBlockList(false, answerTypes[j]); if (notIncludeSelf) { const index = blocks.indexOf(removeBlock); if (~index) { blocks.splice(index, 1); } } if (blocks.length) { return; } } } //answer related blocks not found //hide canvas answer view answer.setVisible(false); } getView() { return this._view; } // dummy resize() { return; } _rightClick = (e) => { e.stopPropagation(); const touchEvent = Entry.Utils.convertMouseEvent(e); const options = [ { text: Lang.Blocks.Paste_blocks, enable: !Entry.engine.isState('run') && !!this.copiedObject, callback: () => { if (this.copiedObject) { this.addCloneObject(this.copiedObject); } else { Entry.toast.alert( Lang.Workspace.add_object_alert, Lang.Workspace.object_not_found_for_paste ); } }, }, ]; Entry.ContextMenu.show(options, 'workspace-contextmenu', { x: touchEvent.clientX, y: touchEvent.clientY, }); }; removeFuncBlocks(functionType) { this.objects_.forEach(({ script }) => { script.removeBlocksByType(functionType); }); } clear() { [...this.objects_, ...this._extensionObjects].forEach((o) => o.destroy()); this.objects_ = []; // INFO : clear 시도할때 _extensionObjects 초기화 this._extensionObjects = []; // TODO: clear 때 this._extensionListView 도 비워 줘야 하는지 확인 필요. Entry.playground.clear(); } selectNeighborObject(option) { const objects = this.getCurrentObjects(); if (!objects || objects.length === 0) { return; } let currentIndex = objects.indexOf(Entry.playground.object); const maxLen = objects.length; switch (option) { case 'prev': if (--currentIndex < 0) { currentIndex = objects.length - 1; } break; case 'next': currentIndex = ++currentIndex % maxLen; break; } const object = objects[currentIndex]; if (!object) { return; } this.selectObject(object.id); } getObjectIndex(objectId) { return this.objects_.indexOf(this.getObject(objectId)); } getDom(query) { if (query.length >= 1) { switch (query.shift()) { case 'objectIndex': return this.objects_[query.shift()].getDom(query); case 'objectId': return this.getObject(query.shift()).getDom(query); } } else { } } isSceneObjectsExist() { return !_.isEmpty(this.getSceneObjects()); } adjustClonedValues(oldIds, newIds) { if (!(oldIds && newIds)) { return; } const that = this; newIds.forEach((newId) => { that.getObject(newId) .script.getBlockList() .forEach((b) => { if (!b || !b.params) { return; } let changed = false; const ret = b.params.map((p) => { if (typeof p !== 'string') { return p; } const index = oldIds.indexOf(p); if (index < 0) { return p; } changed = true; return newIds[index]; }); changed && b.set({ params: ret }); }); }); } getBlockList() { return _.flatten(this.objects_.map(({ script }) => script.getBlockList())); } scrollToObject(ObjectId) { const { view_ } = this.getObject(ObjectId); view_ && view_.scrollIntoView(); document.body.scrollIntoView(); } setSound(sound) { const sounds = this.getObject(sound.objectId).sounds; const index = _.findIndex(sounds, ({ id }) => id === sound.id); if (!~index) { throw new Error('No sound found'); } const path = sound.fileurl || `${Entry.defaultPath}/uploads/${sound.filename.substring( 0, 2 )}/${sound.filename.substring(2, 4)}/${Entry.soundPath}${sound.filename}${ sound.ext || '.mp3' }`; sounds[index] = Object.assign( _.pick(sound, [ 'duration', 'ext', 'fileurl', 'filename', 'id', 'label', 'name', 'path', ]), { view: sounds[index].view, path, } ); return sounds[index]; } destroy() { // 우선 interface 만 정의함. } }; ================================================ FILE: src/class/dialog.ts ================================================ 'use strict'; import * as PIXI from 'pixi.js'; import { GEHelper } from '../graphicEngine/GEHelper'; type EntryObjectEntity = any; type NotchType = 'ne' | 'nw' | 'se' | 'sw'; const _cache = new Map(); class EntryDialog { private parent: EntryObjectEntity; private padding = 10; private border = 2; private width: number; private height: number; private notch: any; private _isNoContentTried: boolean; private readonly message_: string; private readonly mode_: 'speak' | 'ask' | 'yell' | 'think'; public object: any; constructor( entity: EntryObjectEntity, message: string | number, mode: 'speak' | 'ask' | 'yell' | 'think', isStamp: boolean ) { if (entity.isEngineStop) { return; } if (entity.dialog) { entity.dialog.remove(true); } entity.dialog = this; this.parent = entity; let messageString = typeof message == 'number' ? String(message) : message; if (Entry.console) { Entry.console.print(message, mode); } messageString = messageString.match(/.{1,15}/g).join('\n'); this.message_ = messageString; this.mode_ = mode; if (mode === 'speak' || mode === 'ask' || mode === 'think' || mode === 'yell') { this.generateSpeak(mode); } if (!isStamp) { Entry.stage.loadDialog(this); } } private getNotchType(bound: any) { const parentObj = this.parent.object; const entity = parentObj.entity; const cache = _cache.get(parentObj.id) || {}; const { x, y } = cache; let notchType = cache.notchType; if (entity.x != x || entity.y != y) { if (bound.y - 20 - this.border > -135) { notchType = 'n'; } else { notchType = 's'; } if (bound.x + bound.width / 2 < 0) { notchType += 'e'; } else { notchType += 'w'; } _cache.set(parentObj.id, { notchType, x: entity.x, y: entity.y, }); } return notchType; } private setNotchPositionForPixi(bound: any) { const notchType = this.getNotchType(bound); if (notchType.includes('n')) { this.object.y = Math.max( bound.y - this.height / 2 - 20 - this.padding, -135 + this.height / 2 + this.padding ); } else { this.object.y = Math.min( bound.y + bound.height + this.height / 2 + 20 + this.padding, 135 - this.height / 2 - this.padding ); } if (notchType.includes('e')) { this.object.x = Math.min( bound.x + bound.width + this.width / 2, 240 - this.width / 2 - this.padding ); } else { this.object.x = Math.max( bound.x - this.width / 2, -240 + this.width / 2 + this.padding ); } return notchType; } private setNotchPositionForCreateJs(bound: any) { let notchType = ''; if (bound.y - 20 - this.border > -135) { this.object.y = Math.max( bound.y - this.height / 2 - 20 - this.padding, -135 + this.height / 2 + this.padding ); notchType += 'n'; } else { this.object.y = Math.min( bound.y + bound.height + this.height / 2 + 20 + this.padding, 135 - this.height / 2 - this.padding ); notchType += 's'; } if (bound.x + bound.width / 2 < 0) { this.object.x = Math.min( bound.x + bound.width + this.width / 2, 240 - this.width / 2 - this.padding ); notchType += 'e'; } else { this.object.x = Math.max( bound.x - this.width / 2, -240 + this.width / 2 + this.padding ); notchType += 'w'; } return notchType; } /** * Set position */ update() { const parentObj = this.parent.object; let bound = GEHelper.calcParentBound(parentObj); if (!bound && this.parent.type === 'textBox') { if (!this._isNoContentTried) { this.parent.setText(' '); bound = GEHelper.calcParentBound(parentObj); this._isNoContentTried = true; } else { delete this._isNoContentTried; return; } } if (!this.object) { return; } let notchType = ''; if (GEHelper.isWebGL) { notchType = this.setNotchPositionForPixi(bound); } else { notchType = this.setNotchPositionForCreateJs(bound); } if (this.notch && this.notch.type != notchType) { this.object.removeChild(this.notch); if (this.mode_ === 'think') { this.notch = this.createThinkkNotch(notchType as NotchType); this.object.addChild(this.notch); } else if (this.mode_ === 'speak' || this.mode_ === 'ask') { this.notch = this.createSpeakNotch(notchType as NotchType); this.object.addChild(this.notch); } } this._isNoContentTried && this.parent.setText(''); Entry.requestUpdate = true; } remove(saveCache: boolean) { if (!saveCache) { _cache.clear(); } Entry.stage.unloadDialog(this); this.parent.dialog = null; Entry.requestUpdate = true; } private createSpeakNotch(type: NotchType) { const notch = GEHelper.newGraphic(); notch.type = type; const colorSet = EntryStatic.colorSet.canvas || {}; const height = this.height + this.padding; const padding = this.padding; const width = this.width; if (type === 'ne') { notch.graphics .f('#ffffff') .ss(3, 2) .s('#ffffff') .mt(3, height) .lt(11, height) .ss(2, 1, 1) .s(colorSet.dialog || '#4f80ff') .mt(2, height) .lt(2, height + 9) .lt(12, height); } else if (type === 'nw') { notch.graphics .f('#ffffff') .ss(3, 2) .s('#ffffff') .mt(width - 3, height) .lt(width - 11, height) .ss(2, 1, 1) .s(colorSet.dialog || '#4f80ff') .mt(width - 2, height) .lt(width - 2, height + 9) .lt(width - 12, height); } else if (type === 'se') { notch.graphics .f('#ffffff') .ss(3, 2) .s('#ffffff') .mt(3, -padding) .lt(11, -padding) .ss(2, 1, 1) .s(colorSet.dialog || '#4f80ff') .mt(2, -padding) .lt(2, -padding - 9) .lt(12, -padding); } else if (type === 'sw') { notch.graphics .f('#ffffff') .ss(3, 2) .s('#ffffff') .mt(width - 3, -padding) .lt(width - 11, -padding) .ss(2, 1, 1) .s(colorSet.dialog || '#4f80ff') .mt(this.width - 2, -padding) .lt(width - 2, -padding - 9) .lt(width - 12, -padding); } return notch; } private createThinkkNotch(type: NotchType) { const notch = GEHelper.newGraphic(); notch.type = type; const colorSet = EntryStatic.colorSet.canvas || {}; const height = this.height + this.padding; const padding = this.padding; const width = this.width; if (type === 'ne') { notch.graphics .f('#ffffff') .ss(3, 2) .s('#ffffff') .mt(3, height) .lt(11, height) .ss(2, 1, 1) .s(colorSet.dialog || '#4f80ff') .mt(2, height) .qt(2, height + 9, 12, height) .de(2, height + 9, 5, 4); } else if (type === 'nw') { notch.graphics .f('#ffffff') .ss(3, 2) .s('#ffffff') .mt(width - 3, height) .lt(width - 11, height) .ss(2, 1, 1) .s(colorSet.dialog || '#4f80ff') .mt(width, height) .qt(width, height + 9, width - 12, height) .de(width - 3, height + 9, 5, 4); } else if (type === 'se') { notch.graphics .f('#ffffff') .ss(3, 2) .s('#ffffff') .mt(3, -padding) .lt(11, -padding) .ss(2, 1, 1) .s(colorSet.dialog || '#4f80ff') .mt(2, -padding) .qt(2, -padding - 9, 12, -padding) .de(0, -padding - 12, 5, 4); } else if (type === 'sw') { notch.graphics .f('#ffffff') .ss(3, 2) .s('#ffffff') .mt(width - 3, -padding) .lt(width - 11, -padding) .ss(2, 1, 1) .s(colorSet.dialog || '#4f80ff') .mt(this.width - 2, -padding) .qt(width - 2, -padding - 9, width - 12, -padding) .de(width - 6, -padding - 12, 5, 4); } return notch; } private drawZigZagLineX({ ctx, x1, y1, x2, y2, padding, zigzagSpacing, oneZigZagLength }: any) { let zx = 0; ctx.moveTo(x1 + padding, y1); for (let n = 0; zx < x2 - padding; n++) { zx = (n + 1) * zigzagSpacing + x1 + padding; const zy = (n % 2 == 0 ? -oneZigZagLength : oneZigZagLength) + y1; ctx.lineTo(zx, zy); } ctx.lineTo(x2 - padding, y2); } private drawZigZagLineY({ ctx, x1, y1, x2, y2, padding, zigzagSpacing, oneZigZagLength }: any) { let zy = 0; ctx.moveTo(x1, y1 + padding); for (let n = 0; zy < y2 - padding; n++) { zy = (n + 1) * zigzagSpacing + y1 + padding; const zx = (n % 2 !== 0 ? -oneZigZagLength : oneZigZagLength) + x1; ctx.lineTo(zx, zy); } ctx.lineTo(x2, y2 - padding); } private drawZigZagRect({ x, y, w, h, borderColor, fillColor }: any) { const rect = GEHelper.newGraphic(); const zigzagSpacing = 3; const oneZigZagLength = 5; const ctx = rect.graphics; ctx.setStrokeStyle(1); ctx.beginStroke(borderColor); ctx.beginFill(fillColor); const padding = 10; this.drawZigZagLineX({ ctx, x1: x, y1: y, x2: x + w, y2: y, padding, zigzagSpacing, oneZigZagLength, }); ctx.lineTo(x + w, y + padding); this.drawZigZagLineY({ ctx, x1: x + w, y1: y, x2: x + w, y2: y + h, padding, zigzagSpacing, oneZigZagLength, }); ctx.lineTo(x + w - padding, y + h); this.drawZigZagLineX({ ctx, x1: x, y1: y + h, x2: x + w, y2: y + h, padding, zigzagSpacing, oneZigZagLength, }); ctx.moveTo(x + padding, y + h); ctx.lineTo(x, y + h - padding); this.drawZigZagLineY({ ctx, x1: x, y1: y, x2: x, y2: y + h, padding, zigzagSpacing, oneZigZagLength, }); ctx.moveTo(x + padding, y); ctx.lineTo(x, y + padding); return rect; } private drawYellStart({ x, y, w, h, fillColor, borderColor }: any) { const star = GEHelper.newGraphic(); const pointSize = 0.2; const radius = Math.sqrt(w * w + h * h) / 2; const sides = 30; const angle = -90; star.graphics .f(fillColor) .ss(2, 'round') .s(borderColor) .drawPolyStar(x + radius / 2, y + radius / 2, radius, sides, pointSize, angle); return star; } private generateSpeak(mode: 'speak' | 'ask' | 'yell' | 'think') { this.object = GEHelper.newContainer('[dialog] container'); const fontFamily = EntryStatic.fontFamily || "NanumGothic, 'Nanum Gothic'"; const text = GEHelper.textHelper.newText( this.message_, `15px ${fontFamily}`, '#000000', 'top', 'left' ); let bound; if (GEHelper.isWebGL) { bound = text; } else { bound = text.getTransformedBounds(); } const height = bound.height; const width = bound.width >= 10 ? bound.width : 17; const colorSet = EntryStatic.colorSet.canvas || {}; if (mode === 'yell') { const rect = this.drawZigZagRect({ x: -this.padding, y: -this.padding, w: width + 2 * this.padding, h: height + 2 * this.padding, fillColor: colorSet.dialogBG || '#ffffff', borderColor: colorSet.dialog || '#4f80ff', }); this.object.addChild(rect); } else { const rect = GEHelper.newGraphic(); rect.graphics .f(colorSet.dialogBG || '#ffffff') .ss(2, 'round') .s(colorSet.dialog || '#4f80ff') .rr( -this.padding, -this.padding, width + 2 * this.padding, height + 2 * this.padding, this.padding ); this.object.addChild(rect); } this.object.regX = width / 2; this.object.regY = height / 2; this.width = width; this.height = height; if (mode === 'think') { this.notch = this.createThinkkNotch('nw'); this.object.addChild(this.notch); } else if (mode === 'speak' || mode === 'ask') { this.notch = this.createSpeakNotch('nw'); this.object.addChild(this.notch); } this.update(); this.object.addChild(text); Entry.requestUpdate = true; } } export default EntryDialog; Entry.Dialog = EntryDialog; ================================================ FILE: src/class/doneProject.js ================================================ 'use strict'; require('../util/static'); Entry.DoneProject = class DoneProject { constructor(id) { this.generateView(id); } init(projectId) { this.projectId = projectId; } generateView(doneProject) { // this.youtubeTab.removeClass('entryRemove'); const doneContainer = Entry.createElement('div'); doneContainer.addClass('entryContainerDoneWorkspace'); // var parentcontainer = document.getElementById('entryContainerWorkspaceId'); this.doneContainer = doneContainer; const view = this.doneContainer; // var width = parentcontainer.offsetWidth; const url = '/api/iframe/project/'; const iframe = Entry.createElement('iframe'); iframe.setAttribute('id', 'doneProjectframe'); iframe.setAttribute('frameborder', 0); iframe.setAttribute('src', url + doneProject); this.doneProjectFrame = iframe; this.doneContainer.appendChild(iframe); doneContainer.addClass('entryRemove'); } getView() { return this.doneContainer; } resize() { const iframe = document.getElementById('doneProjectframe'); const w = this.doneContainer.offsetWidth; iframe.width = `${w}px`; iframe.height = `${(w * 9) / 16}px`; } }; ================================================ FILE: src/class/engine.js ================================================ import { GEHelper } from '../graphicEngine/GEHelper'; import audioUtils from '../util/audioUtils'; const EntryEngineState = { stop: 'stop', stopping: 'stopping', pause: 'pause', run: 'run', }; Entry.Engine = class Engine { constructor() { this.execPromises = []; this.state = EntryEngineState.stop; this.popup = null; this.isUpdating = true; this.speeds = [1, 15, 30, 45, 60]; this.engineTimer = { isInit: false, isPaused: false, start: 0, pauseStart: 0, pausedTime: 0, }; this._engineTimeouts = []; this._engineTimeoutSeq = 0; this.attachKeyboardCapture(); const _addEventListener = Entry.addEventListener.bind(Entry); _addEventListener('canvasClick', () => this.fireEvent('mouse_clicked')); _addEventListener('canvasClickCanceled', () => this.fireEvent('mouse_click_cancled')); _addEventListener('entityClick', (entity) => { const objId = entity.id; Entry.stage.clickedObjectId = objId; this.fireEventOnEntity('when_object_click', entity); }); _addEventListener('entityClickCanceled', (entity) => { delete Entry.stage.clickedObjectId; this.fireEventOnEntity('when_object_click_canceled', entity); }); if (Entry.type !== 'phone' && Entry.type !== 'playground') { _addEventListener( 'stageMouseMove', _.throttle(this.updateMouseView.bind(this), 100, { leading: false, }) ); _addEventListener('stageMouseOut', this.hideMouseView.bind(this)); } const $win = $(window); _addEventListener('run', () => $win.bind('keydown', arrowHandler)); _addEventListener('stop', () => $win.unbind('keydown', arrowHandler)); function arrowHandler(e) { const code = e.keyCode || e.which; const input = Entry.stage.inputField; if (code === 32 && input && input.hasFocus()) { return; } if (_.includes([37, 38, 39, 40, 32], code)) { e.preventDefault(); } } Entry.message = new Entry.Event(window); } /** * Control bar view generator. * @param {!Element} controlView controlView from Entry. * @param {?string} option for choose type of view. */ generateView(controlView, option = 'workspace') { this.option = option; if (option === 'workspace') { /** @type {!Element} */ this.view_ = controlView; this.view_.addClass('entryEngine_w').addClass('entryEngineWorkspace_w'); this.view_.addClass('test'); this.speedButton = Entry.createElement('button') .addClass( 'entrySpeedButtonWorkspace', 'entryEngineTopWorkspace', 'entryEngineButtonWorkspace_w' ) .appendTo(this.view_) .bindOnClick(function (e) { Entry.engine.toggleSpeedPanel(); this.blur(); }); this.maximizeButton = Entry.createElement('button') .addClass( 'entryEngineButtonWorkspace_w', 'entryEngineTopWorkspace', 'entryMaximizeButtonWorkspace_w' ) .appendTo(this.view_) .bindOnClick(function (e) { Entry.engine.toggleFullScreen(); this.blur(); }); this.coordinateButton = Entry.createElement('button') .addClass( 'entryEngineButtonWorkspace_w', 'entryEngineTopWorkspace', 'entryCoordinateButtonWorkspace_w' ) .appendTo(this.view_) .bindOnClick(function (e) { if (this.hasClass('toggleOn')) { this.removeClass('toggleOn'); } else { this.addClass('toggleOn'); } this.blur(); Entry.stage.toggleCoordinator(); }); this.mouseView = Entry.createElement('div') .addClass('entryMouseViewWorkspace_w') .addClass('entryHide') .appendTo(this.view_); this.mouseViewInput = Entry.createElement('input').appendTo(this.mouseView); $(this.mouseViewInput).attr('readonly', 'readonly'); this.buttonWrapper = Entry.createElement('div').addClass('entryEngineButtonWrapper'); this.view_.after(this.buttonWrapper); /* TODO markup 오브젝트 추가하기, 시작하기, 미사용버튼, 기본 일시정지/다시시작, 전체화면 일시정지/다시시작, 기본/전체화면 정지 순서 */ this.addButton = Entry.createElement('button') .addClass('entryEngineButtonWorkspace_w') .addClass('entryAddButtonWorkspace_w') .bindOnClick(function () { Entry.do('addObjectButtonClick'); this.blur(); }) .appendTo(this.buttonWrapper); this.addButton.textContent = Lang.Workspace.add_object; if (!Entry.objectAddable) { this.addButton.addClass('entryRemove'); } this.runButton = Entry.createElement('button') .addClass('entryEngineButtonWorkspace_w') .addClass('entryRunButtonWorkspace_w') .bindOnClick(() => Entry.do('toggleRun', 'runButton')) .appendTo(this.buttonWrapper); this.runButton.textContent = Lang.Workspace.run; this.runButton2 = Entry.createElement('button') .addClass('entryEngineButtonWorkspace_w') .addClass('entryRunButtonWorkspace_w2') .appendTo(this.buttonWrapper) .bindOnClick(() => Entry.engine.toggleRun()); this.pauseButton = Entry.createElement('button') .addClass('entryEngineButtonWorkspace_w') .addClass('entryPauseButtonWorkspace_w') .addClass('entryRemove') .appendTo(this.buttonWrapper) .bindOnClick(function (e) { this.blur(); Entry.engine.togglePause(); }); this.pauseButtonFull = Entry.createElement('button') .addClass('entryEngineButtonWorkspace_w') .addClass('entryPauseButtonWorkspace_full') .addClass('entryRemove') .appendTo(this.buttonWrapper) .bindOnClick(function () { this.blur(); Entry.engine.togglePause(); }); this.stopButton = Entry.createElement('button') .addClass('entryEngineButtonWorkspace_w') .addClass('entryStopButtonWorkspace_w') .addClass('entryRemove') .bindOnClick(() => Entry.do('toggleStop', 'stopButton')) .appendTo(this.buttonWrapper); this.stopButton.textContent = Lang.Workspace.stop; this.stopButton2 = Entry.createElement('button') .addClass('entryEngineButtonWorkspace_w') .addClass('entryStopButtonWorkspace_w2') .addClass('entryRemove') .bindOnClick(function () { this.blur(); Entry.engine.toggleStop(); }) .appendTo(this.buttonWrapper); this.stopButton2.textContent = Lang.Workspace.stop; } else if (option == 'minimize') { /** @type {!Element} */ this.view_ = controlView; this.view_.addClass('entryEngine'); this.view_.addClass('entryEngineMinimize'); this.maximizeButton = Entry.createElement('button'); this.maximizeButton.addClass('entryEngineButtonMinimize'); this.maximizeButton.addClass('entryMaximizeButtonMinimize'); this.view_.appendChild(this.maximizeButton); this.maximizeButton.bindOnClick((e) => { Entry.engine.toggleFullScreen(); }); this.coordinateButton = Entry.createElement('button'); this.coordinateButton.addClass('entryEngineButtonMinimize'); this.coordinateButton.addClass('entryCoordinateButtonMinimize'); this.view_.appendChild(this.coordinateButton); this.coordinateButton.bindOnClick(function (e) { if (this.hasClass('toggleOn')) { this.removeClass('toggleOn'); } else { this.addClass('toggleOn'); } Entry.stage.toggleCoordinator(); }); this.stopButton = Entry.createElement('button'); this.stopButton.addClass('entryEngineButtonMinimize'); this.stopButton.addClass('entryStopButtonMinimize'); this.stopButton.addClass('entryRemove'); this.stopButton.textContent = Lang.Workspace.stop; this.view_.appendChild(this.stopButton); this.stopButton.bindOnClick(function (e) { this.blur(); Entry.engine.toggleStop(); }); this.pauseButton = Entry.createElement('button'); this.pauseButton.textContent = Lang.Workspace.pause; this.pauseButton.addClass('entryEngineButtonMinimize'); this.pauseButton.addClass('entryPauseButtonMinimize'); this.pauseButton.addClass('entryRemove'); this.view_.appendChild(this.pauseButton); this.pauseButton.bindOnClick(function (e) { this.blur(); Entry.engine.togglePause(); }); this.mouseView = Entry.createElement('div'); this.mouseView.addClass('entryMouseViewMinimize'); this.mouseView.addClass('entryHide'); this.mouseViewInput = Entry.createElement('input').appendTo(this.mouseView); $(this.mouseViewInput).attr('readonly', 'readonly'); $(this.mouseViewInput).attr( 'style', 'border: none;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;line-height: normal' ); this.view_.appendChild(this.mouseView); const setRunButton = (isLoaded) => { if (!isLoaded) { return; } this.isLoaded = true; const isSoundEmpty = Entry.soundQueue.urls.size < 1; if (isSoundEmpty || Entry.soundQueue.loadComplete) { if (!this.runButtonCurtain) { this.runButtonCurtain = Entry.Dom('div', { class: 'entryRunButtonBigMinimizeCurtain', parent: $('#entryCanvasWrapper'), }); } if (!this.runButton) { this.runButton = Entry.Dom('div', { class: 'entryRunButtonBigMinimize', parent: this.runButtonCurtain, }); this.runButton.bindOnClick(() => Entry.engine.toggleRun()); } if (Entry.options.isStartOnLoaded && Entry.engine.state === 'stop') { Entry.engine.toggleRun(); } } }; Entry.addEventListener('loadComplete', () => setRunButton(true)); Entry.addEventListener('soundLoaded', () => setRunButton(this.isLoaded)); } else if (option == 'phone') { this.view_ = controlView; this.view_.addClass('entryEngine', 'entryEnginePhone'); this.headerView_ = Entry.createElement('div', 'entryEngineHeader'); this.headerView_.addClass('entryEngineHeaderPhone'); this.view_.appendChild(this.headerView_); this.maximizeButton = Entry.createElement('button'); this.maximizeButton.addClass('entryEngineButtonPhone', 'entryMaximizeButtonPhone'); this.headerView_.appendChild(this.maximizeButton); this.maximizeButton.bindOnClick((e) => { Entry.engine.footerView_.addClass('entryRemove'); Entry.engine.headerView_.addClass('entryRemove'); Entry.launchFullScreen(Entry.engine.view_); }); document.addEventListener('fullscreenchange', (e) => { Entry.engine.exitFullScreen(); }); document.addEventListener('webkitfullscreenchange', (e) => { Entry.engine.exitFullScreen(); }); document.addEventListener('mozfullscreenchange', (e) => { Entry.engine.exitFullScreen(); }); this.footerView_ = Entry.createElement('div', 'entryEngineFooter'); this.footerView_.addClass('entryEngineFooterPhone'); this.view_.appendChild(this.footerView_); this.runButton = Entry.createElement('button'); this.runButton.addClass('entryEngineButtonPhone', 'entryRunButtonPhone'); if (Entry.objectAddable) { this.runButton.addClass('small'); } this.runButton.textContent = Lang.Workspace.run; this.footerView_.appendChild(this.runButton); this.runButton.bindOnClick((e) => { Entry.engine.toggleRun(); }); this.stopButton = Entry.createElement('button'); this.stopButton.addClass( 'entryEngineButtonPhone', 'entryStopButtonPhone', 'entryRemove' ); if (Entry.objectAddable) { this.stopButton.addClass('small'); } this.stopButton.textContent = Lang.Workspace.stop; this.footerView_.appendChild(this.stopButton); this.stopButton.bindOnClick((e) => { Entry.engine.toggleStop(); }); } } toggleAudioShadePanel() { if (this.audioShadePanelOn) { this.audioShadePanelOn = false; $(this.audioShadePanel_).remove(); delete this.audioShadePanel_; } else if (Entry.engine.isState('run')) { this.audioShadePanelOn = true; this.audioShadePanel_ = Entry.createElement('div', 'audioShadeCirclebox'); this.audioShadePanel_.addClass('audioShadeCirclebox'); const audioShadeMainCircle = Entry.createElement('div', 'audioShadeCircle').addClass( 'audioShadeCircle' ); audioShadeMainCircle.appendChild( Entry.createElement('div', 'audioShadeInner').addClass('audioShadeInner') ); audioShadeMainCircle.appendChild( Entry.createElement('div', 'audioShadeInner').addClass('audioShadeInner') ); audioShadeMainCircle.appendChild( Entry.createElement('div', 'audioShadeInner').addClass('audioShadeInner') ); this.audioShadePanel_.appendChild(audioShadeMainCircle); const micImage = Entry.createElement('img', 'audioShadeImg').addClass('audioShadeImg'); micImage.src = `${Entry.mediaFilePath}ic-audio-sensing-mic.svg`; audioShadeMainCircle.appendChild(micImage); const audioShadeText = Entry.createElement('div', 'audioShadeText').addClass( 'audioShadeText' ); audioShadeText.textContent = Lang.Msgs.ai_utilize_audio_listening; this.audioShadePanel_.appendChild(audioShadeText); this.minimizedView_ = document.querySelector('#entryCanvasWrapper'); if (this.view_.classList[0] === 'entryEngine') { this.minimizedView_.insertBefore(this.audioShadePanel_, Entry.stage.canvas.canvas); } else { this.view_.insertBefore(this.audioShadePanel_, Entry.stage.canvas.canvas); } } } toggleAudioProgressPanel() { if (this.audioShadePanelOn) { Entry.engine.toggleAudioShadePanel(); } if (this.audioProgressPanelOn) { this.audioProgressPanelOn = false; $(this.audioProgressPanel_).remove(); delete this.audioProgressPanel_; } else if (Entry.engine.isState('run')) { this.audioProgressPanelOn = true; this.audioProgressPanel_ = Entry.createElement('div', 'audioShadeCirclebox'); this.audioProgressPanel_.addClass('audioShadeCirclebox'); const audioShadeMainCircle = Entry.createElement('div', 'audioShadeCircle').addClass( 'audioShadeCircle' ); const audioProgressSpinner = Entry.createElement( 'canvas', 'audioProgressCanvas' ).addClass('audioProgress'); const ctx = audioProgressSpinner.getContext('2d'); const circlesRotate = [0, 15, 30, 45, 60]; audioProgressSpinner.width = 100; audioProgressSpinner.height = 100; function fnDraw() { audioProgressSpinner.width = audioProgressSpinner.width; fnCircle(); window.requestAnimationFrame(fnDraw); } fnDraw(); function fnReturnDeg(deg) { return (deg * Math.PI) / 180; } function fnCircle() { ctx.fillStyle = 'white'; for (let i = 0; i < circlesRotate.length; i++) { ctx.beginPath(); ctx.save(); ctx.translate(audioProgressSpinner.width / 2, audioProgressSpinner.height / 2); ctx.rotate(fnReturnDeg(circlesRotate[i])); ctx.arc(0, -audioProgressSpinner.height / 3, 7, Math.PI, 10); ctx.fill(); ctx.restore(); if (circlesRotate[i] < 60 || circlesRotate[i] > 300) { circlesRotate[i] += 3; } else { circlesRotate[i] += 7; } if (circlesRotate[i] > 360) { circlesRotate[i] -= 360; } } } audioShadeMainCircle.appendChild(audioProgressSpinner); this.audioProgressPanel_.appendChild(audioShadeMainCircle); const audioShadeText = Entry.createElement('div', 'audioShadeText').addClass( 'audioShadeText' ); audioShadeText.innerHTML = Lang.Msgs.ai_utilize_audio_progress; this.audioProgressPanel_.appendChild(audioShadeText); this.minimizedView_ = document.querySelector('#entryCanvasWrapper'); if (this.view_.classList[0] === 'entryEngine') { this.minimizedView_.insertBefore( this.audioProgressPanel_, Entry.stage.canvas.canvas ); } else { this.view_.insertBefore(this.audioProgressPanel_, Entry.stage.canvas.canvas); } } } hideAllAudioPanel() { if (this.audioShadePanelOn) { this.audioShadePanelOn = false; $(this.audioShadePanel_).remove(); delete this.audioShadePanel_; } if (this.audioProgressPanelOn) { this.audioProgressPanelOn = false; $(this.audioProgressPanel_).remove(); delete this.audioProgressPanel_; } } toggleSpeedPanel() { if (this.speedPanelOn) { this.speedPanelOn = false; this.speedButton.removeClass('on'); $(this.speedLabel_).parent().remove(); delete this.speedLabel_; $(this.speedProgress_).fadeOut(null, function (e) { $(this).remove(); delete this.speedProgress_; }); $(this.speedHandle_).remove(); delete this.speedHandle_; } else { this.speedPanelOn = true; this.speedButton.addClass('on'); const speedBox = Entry.createElement('div', 'entrySpeedBox'); speedBox.addClass('entrySpeedBox'); this.view_.insertBefore(speedBox, Entry.stage.canvas.canvas); this.speedLabel_ = Entry.createElement('div', 'entrySpeedLabelWorkspace'); this.speedLabel_.textContent = Lang.Workspace.speed; speedBox.appendChild(this.speedLabel_); this.speedProgress_ = Entry.createElement('table', 'entrySpeedProgressWorkspace'); const tr = Entry.createElement('tr').appendTo(this.speedProgress_); this.speeds.forEach((speed, i) => { Entry.createElement('td', `progressCell${i}`) .addClass('progressCell') .bindOnClick(() => { this.setSpeedMeter(speed); }) .appendTo(tr); }); speedBox.appendChild(this.speedProgress_); this.setSpeedMeter(Entry.FPS); } } setSpeedMeter(FPS) { let level = this.speeds.indexOf(FPS); if (level < 0) { return; } level = Math.min(4, level); level = Math.max(0, level); if (this.speedPanelOn) { const elements = document.querySelectorAll(`.progressCell`); Array.from(elements).forEach((element, i) => { if (level === i) { element.className = 'progressCell on'; } else if (element.className.indexOf('on') > -1) { element.className = 'progressCell'; } }); } if (Entry.FPS == FPS) { return; } clearInterval(this.ticker); Entry.tickTime = Math.floor(1000 / FPS); this.ticker = setInterval(this.update, Entry.tickTime); Entry.FPS = FPS; } start() { GEHelper.Ticker.setFPS(Entry.FPS); if (!this.ticker) { Entry.tickTime = Math.floor(1000 / Entry.FPS); this.ticker = setInterval(this.update, Entry.tickTime); } } stop() { GEHelper.Ticker.reset(); audioUtils.stopRecord(); clearInterval(this.ticker); this.ticker = null; this._stopEngineTimer(); this._clearEngineTimeouts(); } /** * 매 틱당 실행되며, canvas, object 를 업데이트한다. * 추가로, 하드웨어의 데이터도 업데이트한다. */ update = () => { if (Entry.engine.isState('run')) { Entry.container.mapObjectOnScene(this.computeFunction); if (Entry.hw.communicationType !== 'manual') { Entry.hw.update(); } this._processEngineTimeouts(); } }; /** * Compute function for map. (Ntry 에 동일한 명칭의 함수가 있어 그대로 둠) */ computeFunction({ script }) { script.tick(); } /** * Check this state is same with argument * @param {string} state * @return {boolean} */ isState(state) { return this.state.indexOf(state) > -1; } /** * Execute this function when click start button */ run() { if (this.isState('run')) { this.toggleStop(); } else if (this.isState('stop') || this.isState('pause')) { this.toggleRun(); } } /** * toggle this engine state run */ toggleRun(disableAchieve) { const isSupportWebAudio = window.AudioContext || window.webkitAudioContext; if (isSupportWebAudio && !this.isSoundInitialized) { createjs.WebAudioPlugin.playEmptySound(); this.isSoundInitialized = true; } Entry.Utils.forceStopSounds(); const variableContainer = Entry.variableContainer; const container = Entry.container; const WS = Entry.getMainWS(); if (this.state === EntryEngineState.pause) { return this.togglePause(); } Entry.Utils.blur(); WS && WS.syncCode(); Entry.addActivity('run'); if (this.state === EntryEngineState.stop) { container.mapEntity((entity) => { entity.takeSnapshot(); }); variableContainer.mapVariable((variable) => { variable.takeSnapshot(); }); variableContainer.mapList((variable) => { variable.takeSnapshot(); }); variableContainer.mapFunc((func) => { func.takeSnapshot(); }); if (Entry.container.sttValue) { Entry.container.sttValue.takeSnapshot(); } this.projectTimer.takeSnapshot(); container.inputValue.takeSnapshot(); container.takeSequenceSnapshot(); Entry.scene.takeStartSceneSnapshot(); this.state = EntryEngineState.run; this._resetEngineTimer(); this.fireEvent('start'); this.achieveEnabled = !(disableAchieve === false); } this.state = EntryEngineState.run; if (Entry.type === 'mobile') { this.view_.addClass('entryEngineBlueWorkspace'); } if (this.runButton) { this.setPauseButton(this.option); this.runButton.addClass('run'); this.runButton.addClass('entryRemove'); if (this.runButtonCurtain) { this.runButtonCurtain.addClass('entryRemove'); } this.stopButton.removeClass('entryRemove'); if (this.addButton) { this.addButton.addClass('entryRemove'); if (Entry.objectAddable) { this.pauseButton.removeClass('entryRemove'); } } if (this.pauseButton && (Entry.type === 'minimize' || Entry.objectAddable)) { this.pauseButton.removeClass('entryRemove'); } if (this.runButton2) { this.runButton2.addClass('entryRemove'); } if (this.stopButton2) { this.stopButton2.removeClass('entryRemove'); } if (this.pauseButtonFull) { this.pauseButtonFull.removeClass('entryRemove'); } } if (!this.isUpdating) { this.update(); this.isUpdating = true; } this.setEnableInputField(true); this.selectedObject = Entry.stage.selectedObject; Entry.stage.selectObject(); Entry.dispatchEvent('closeBackPack'); Entry.dispatchEvent('run'); } /** * toggle this engine state stop */ async toggleStop() { this.state = EntryEngineState.stopping; Entry.dispatchEvent('beforeStop'); try { await Promise.all(this.execPromises); } catch (e) {} const container = Entry.container; const variableContainer = Entry.variableContainer; Entry.Utils.blur(); audioUtils.stopRecord(); Entry.addActivity('stop'); container.mapEntity((entity) => { entity.loadSnapshot(); entity.object.filters = []; entity.resetFilter(); if (entity.dialog) { entity.dialog.remove(); } if (entity.brush) { entity.removeBrush(); } if (entity.paint) { entity.removePaint(); } }); variableContainer.mapVariable((variable) => { variable.loadSnapshot(); }); variableContainer.mapList((variable) => { variable.loadSnapshot(); }); variableContainer.mapFunc((func) => { func.loadSnapshot(); }); this.stopProjectTimer(); if (Entry.timerInstances) { Entry.timerInstances.forEach((instance) => { instance.destroy(); }); } if (Entry.container.sttValue) { Entry.container.sttValue.loadSnapshot(); } container.clearRunningState(); container.loadSequenceSnapshot(); this.projectTimer.loadSnapshot(); container.inputValue.loadSnapshot(); Entry.scene.loadStartSceneSnapshot(); Entry.Func.clearThreads(); Entry.Utils.setVolume(1); if (Entry.hwLite.getStatus() === 'connected') { Entry.hwLite.setZero(); } createjs.Sound.setVolume(1); createjs.Sound.stop(); Entry.soundInstances.clear(); Entry.bgmInstances.clear(); Entry.playbackRateValue = 1; Entry.targetChecker && Entry.targetChecker.clearListener(); this.view_.removeClass('entryEngineBlueWorkspace'); if (this.runButton) { this.runButton.removeClass('entryRemove'); if (this.runButtonCurtain) { this.runButtonCurtain.removeClass('entryRemove'); } this.stopButton.addClass('entryRemove'); if (this.pauseButton) { this.pauseButton.addClass('entryRemove'); } if (this.pauseButtonFull) { this.pauseButtonFull.addClass('entryRemove'); } if (this.addButton && Entry.objectAddable) { this.addButton.removeClass('entryRemove'); } if (this.runButton2) { this.runButton2.removeClass('entryRemove'); } if (this.stopButton2) { this.stopButton2.addClass('entryRemove'); } } this.state = EntryEngineState.stop; this._stopEngineTimer(); this._clearEngineTimeouts(); this.setEnableInputField(false); Entry.dispatchEvent('stop'); Entry.stage.hideInputField(); (function (w) { w && w.getMode() === Entry.Workspace.MODE_VIMBOARD && w.codeToText(); })(Entry.getMainWS()); Entry.dispatchEvent('dispatchEventDidToggleStop'); Entry.stage.selectObject(this.selectedObject); } setEnableInputField(on) { const inputField = Entry.stage.inputField; if (inputField) { inputField._readonly = !on; if (!inputField._isHidden) { on ? inputField.focus() : inputField.blur(); } } } /** * toggle this engine state pause */ togglePause({ visible = true } = {}) { const timer = Entry.engine.projectTimer; if (this.state === EntryEngineState.pause) { this.setEnableInputField(true); timer.pausedTime += new Date().getTime() - timer.pauseStart; if (timer.isPaused) { timer.pauseStart = new Date().getTime(); } else { delete timer.pauseStart; } this.state = EntryEngineState.run; this._resumeEngineTimer(); Entry.Utils.recoverSoundInstances(); if (visible && this.runButton) { this.setPauseButton(this.option); if (this.runButton2) { this.runButton2.addClass('entryRemove'); } else { this.runButton.addClass('entryRemove'); if (this.runButtonCurtain) { this.runButtonCurtain.addClass('entryRemove'); } } } if (Entry.timerInstances) { Entry.timerInstances.forEach((instance) => { instance.resume(); }); } } else { this.state = EntryEngineState.pause; this.setEnableInputField(false); if (!timer.isPaused) { timer.pauseStart = new Date().getTime(); } else { timer.pausedTime += new Date().getTime() - timer.pauseStart; timer.pauseStart = new Date().getTime(); } this._pauseEngineTimer(); Entry.Utils.pauseSoundInstances(); if (visible && this.runButton) { this.setPauseButton(this.option); this.stopButton.removeClass('entryRemove'); if (this.runButton2) { this.runButton2.removeClass('entryRemove'); } else { this.runButton.removeClass('entryRemove'); if (this.runButtonCurtain) { this.runButtonCurtain.removeClass('entryRemove'); } } } if (Entry.timerInstances) { Entry.timerInstances.forEach((instance) => { instance.pause(); }); } } Entry.dispatchEvent('dispatchEventDidTogglePause'); } setPauseButton() { if (this.state === EntryEngineState.pause) { if (this.pauseButton) { this.pauseButton.textContent = Lang.Workspace.restart; if (this.option !== 'minimize') { this.pauseButton.removeClass('entryPauseButtonWorkspace_w'); this.pauseButton.addClass('entryRestartButtonWorkspace_w'); } } if (this.pauseButtonFull) { this.pauseButtonFull.textContent = Lang.Workspace.restart; if (this.option !== 'minimize') { // workspace && buttonWrapper check if (this.buttonWrapper) { this.pauseButtonFull.addClass('entryPauseButtonWorkspace_full'); } else { this.pauseButtonFull.removeClass('entryPauseButtonWorkspace_full'); } this.pauseButtonFull.addClass('entryRestartButtonWorkspace_full'); } } } else { if (this.pauseButton) { this.pauseButton.textContent = Lang.Workspace.pause; if (this.option !== 'minimize') { this.pauseButton.addClass('entryPauseButtonWorkspace_w'); this.pauseButton.removeClass('entryRestartButtonWorkspace_w'); } } if (this.pauseButtonFull) { this.pauseButtonFull.textContent = Lang.Workspace.pause; if (this.option !== 'minimize') { this.pauseButtonFull.addClass('entryPauseButtonWorkspace_full'); this.pauseButtonFull.removeClass('entryRestartButtonWorkspace_full'); } } } } /** * @param {string} eventName */ fireEvent(eventName) { if (this.state !== EntryEngineState.run) { return; } Entry.container.mapEntityIncludeCloneOnScene(this.raiseEvent, eventName); } /** * @param {string} eventName * @param {string} value */ fireEventWithValue(eventName, value) { if (this.state !== EntryEngineState.run) { return; } return Entry.container.mapEntityIncludeCloneOnScene(this.raiseKeyEvent, [eventName, value]); } /** * this is callback function for map. * @param {Entry.EntryObject} object * @param {string} eventName */ raiseEvent = (entity, eventName) => { entity.parent.script.raiseEvent(eventName, entity); }; /** * @param {string} eventName * @param {Entry.EntityObject} entity */ fireEventOnEntity(eventName, entity) { if (this.state === EntryEngineState.run) { Entry.container.mapEntityIncludeCloneOnScene(this.raiseEventOnEntity, [ entity, eventName, ]); } } /** * this is callback function for map. * @param {Entry.EntryObject} object * @param {Array} param */ raiseEventOnEntity(entity, param) { if (entity !== param[0]) { return; } const eventName = param[1]; entity.parent.script.raiseEvent(eventName, entity); } /** * @param {KeyboardEvent} e * @param {boolean} isForce */ captureKeyEvent(e, isForce) { const keyCode = Entry.Utils.inputToKeycode(e); if (!keyCode) { return; } const isWorkspace = Entry.type === 'workspace'; if (Entry.Utils.isInInput(e) && !isForce) { return; } //mouse shortcuts if (keyCode !== 17 && e.ctrlKey && isWorkspace) { if (keyCode === 83) { e.preventDefault(); Entry.dispatchEvent(e.shiftKey ? 'saveAsWorkspace' : 'saveWorkspace'); } else if (keyCode === 82) { e.preventDefault(); Entry.engine.run(); } else if (keyCode === 90) { e.preventDefault(); Entry.dispatchEvent(e.shiftKey ? 'redo' : 'undo'); } } else if (Entry.engine.isState('run')) { e.preventDefault && e.preventDefault(); Entry.container.mapEntityIncludeCloneOnScene(Entry.engine.raiseKeyEvent, [ 'keyPress', keyCode, ]); } if (Entry.engine.isState('stop')) { if (isWorkspace && keyCode >= 37 && keyCode <= 40) { Entry.stage.moveSprite(e); } } } raiseKeyEvent(entity, [eventName, keyCode]) { return entity.parent.script.raiseEvent(eventName, entity, String(keyCode)); } updateMouseView() { const { x, y } = Entry.stage.mouseCoordinate; this.mouseViewInput.value = `X : ${x}, Y : ${y}`; this.mouseView.removeClass('entryHide'); } hideMouseView() { this.mouseView.addClass('entryHide'); } toggleFullScreen(popupClassName) { Entry.dispatchEvent('toggleFullScreen'); if (!Entry.fullScreenEnable) { return; } if (!this.popup) { Entry.view_.addClass('fullscreen'); this.popup = new Entry.Popup(popupClassName); if (Entry.engine.speedPanelOn) { Entry.engine.toggleSpeedPanel(); } if (Entry.type !== 'workspace') { const $doc = $(document); const body = $(this.popup.body_); body.css('top', $doc.scrollTop()); $('body').css('overflow', 'hidden'); popup.window_.appendChild(Entry.stage.canvas.canvas); popup.window_.appendChild(Entry.engine.runButton[0]); } popup.window_.appendChild(Entry.engine.view_); if (Entry.type === 'workspace') { Entry.engine.view_.appendChild(this.buttonWrapper); if (Entry.targetChecker) { popup.window_.appendChild(Entry.targetChecker.getStatusView()[0]); } } if (window.top !== window.self) { if (Entry.iframeDomAccess === 'direct') { window.top.addEventListener('pointermove', this.copyEvent); window.top.addEventListener('pointerdown', this.copyEvent); window.top.addEventListener('pointerup', this.copyEvent); window.top.addEventListener('pointerupoutside', this.copyEvent); window.top.addEventListener('pointercancel', this.copyEvent); window.top.addEventListener('mouseup', this.copyEvent); window.top.addEventListener('mousemove', this.copyEvent); } else if (Entry.iframeDomAccess === 'message') { window.top.postMessage({ type: 'toggleFullScreen', value: 'addEvent' }, '*'); } } } else { if (window.top !== window.self) { if (Entry.iframeDomAccess === 'direct') { window.top.removeEventListener('pointermove', this.copyEvent); window.top.removeEventListener('pointerdown', this.copyEvent); window.top.removeEventListener('pointerup', this.copyEvent); window.top.removeEventListener('pointerupoutside', this.copyEvent); window.top.removeEventListener('pointercancel', this.copyEvent); window.top.removeEventListener('mouseup', this.copyEvent); window.top.removeEventListener('mousemove', this.copyEvent); } else if (Entry.iframeDomAccess === 'message') { window.top.postMessage({ type: 'toggleFullScreen', value: 'removeEvent' }, '*'); } } this.popup.remove(); this.popup = null; } Entry.windowResized.notify(); } copyEvent(event) { const eventClone = new event.constructor(event.type, event); window.self.dispatchEvent(eventClone); if (GEHelper.isWebGL && ['mousemove', 'pointermove'].includes(event.type)) { window.document.dispatchEvent(eventClone); } } closeFullScreen() { if (this.popup) { this.popup.remove(); this.popup = null; } Entry.windowResized.notify(); } exitFullScreen() { if (document.webkitIsFullScreen || document.mozIsFullScreen || document.isFullScreen) { } else { Entry.engine.footerView_.removeClass('entryRemove'); Entry.engine.headerView_.removeClass('entryRemove'); } Entry.windowResized.notify(); } showProjectTimer() { const timer = Entry.engine.projectTimer; if (!timer) { return; } this.projectTimer.setVisible(true); } hideProjectTimer(removeBlock, notIncludeSelf) { const timer = this.projectTimer; if (!timer || !timer.isVisible() || this.isState('run')) { return; } const objects = Entry.container.getAllObjects(); const timerTypes = [ 'get_project_timer_value', 'reset_project_timer', 'set_visible_project_timer', 'choose_project_timer_action', ]; for (let i = 0, len = objects.length; i < len; i++) { const code = objects[i].script; for (let j = 0; j < timerTypes.length; j++) { const blocks = code.getBlockList(false, timerTypes[j]); if (notIncludeSelf) { const index = blocks.indexOf(removeBlock); if (index > -1) { blocks.splice(index, 1); } } if (blocks.length > 0) { return; } } } timer.setVisible(false); } clearTimer() { clearInterval(this.ticker); clearInterval(this.projectTimer.tick); } startProjectTimer() { const timer = this.projectTimer; if (!timer) { return; } timer.start = new Date().getTime(); timer.isInit = true; timer.isPaused = false; timer.pausedTime = 0; timer.tick = setInterval((e) => { Entry.engine.updateProjectTimer(); }, 1000 / 60); } stopProjectTimer() { const timer = this.projectTimer; if (!timer) { return; } this.updateProjectTimer(0); timer.isPaused = false; timer.isInit = false; timer.pausedTime = 0; clearInterval(timer.tick); } resetTimer() { const timer = this.projectTimer; if (!timer.isInit) { return; } const isPaused = timer.isPaused; delete timer.pauseStart; this.updateProjectTimer(0); timer.pausedTime = 0; timer.isPaused = isPaused; if (!isPaused) { return; } clearInterval(timer.tick); timer.isInit = false; delete timer.start; } updateProjectTimer(value) { const engine = Entry.engine; const timer = engine.projectTimer; if (!timer) { return; } const current = new Date().getTime(); if (typeof value == 'undefined') { if (!timer.isPaused && !engine.isState('pause')) { timer.setValue( Math.max((current - (timer.start || current) - timer.pausedTime) / 1000, 0) ); } } else { timer.setValue(value); timer.pausedTime = 0; timer.start = current; } } raiseMessage(value) { Entry.message.notify(Entry.variableContainer.getMessage(value)); return Entry.container.mapEntityIncludeCloneOnScene(this.raiseKeyEvent, [ 'when_message_cast', value, ]); } getDom(query) { if (query.length >= 1) { switch (query.shift()) { case 'runButton': return this.runButton; case 'stopButton': return this.stopButton; case 'objectAddButton': return this.addButton; } } else { } } attachKeyboardCapture() { if (Entry.keyPressed) { this._keyboardEvent && this.detachKeyboardCapture(); this._keyboardEvent = Entry.keyPressed.attach(this, this.captureKeyEvent); } } detachKeyboardCapture() { if (Entry.keyPressed && this._keyboardEvent) { this._keyboardEvent.destroy(); delete this._keyboardEvent; } } applyOption() { const SMALL = 'small'; if (Entry.objectAddable) { this.runButton.addClass(SMALL); this.stopButton.addClass(SMALL); this.addButton.removeClass('entryRemove'); } else { this.runButton.removeClass(SMALL); this.stopButton.removeClass(SMALL); this.addButton.addClass('entryRemove'); } } destroy() { // 우선 interface 만 정의함. } trimPromiseExecutor() { return this.execPromises.filter((promise) => promise instanceof Promise); } addPromiseExecutor(promises) { this.execPromises = this.trimPromiseExecutor(); const index = this.execPromises.length; promises.forEach((promise, i) => { const execPromise = (async function () { const result = await promise; const j = Entry.engine.execPromises.indexOf(execPromise); Entry.engine.execPromises[j] = result; })(); this.execPromises[index + i] = execPromise; }); } _resetEngineTimer() { const timer = this.engineTimer; timer.start = new Date().getTime(); timer.pausedTime = 0; timer.pauseStart = 0; timer.isPaused = false; timer.isInit = true; } _pauseEngineTimer() { const timer = this.engineTimer; if (!timer.isInit || timer.isPaused) { return; } timer.isPaused = true; timer.pauseStart = new Date().getTime(); } _resumeEngineTimer() { const timer = this.engineTimer; if (!timer.isInit || !timer.isPaused) { return; } if (timer.pauseStart) { timer.pausedTime += new Date().getTime() - timer.pauseStart; } timer.pauseStart = 0; timer.isPaused = false; } _stopEngineTimer() { const timer = this.engineTimer; timer.isInit = false; timer.isPaused = false; timer.start = 0; timer.pauseStart = 0; timer.pausedTime = 0; } _getEngineTimeMs() { const timer = this.engineTimer; if (!timer.isInit) { return 0; } const now = timer.isPaused && timer.pauseStart ? timer.pauseStart : new Date().getTime(); return Math.max(now - timer.start - timer.pausedTime, 0); } _processEngineTimeouts() { if (!this._engineTimeouts.length) { return; } const nowMs = this._getEngineTimeMs(); const timeouts = this._engineTimeouts; let writeIndex = 0; for (let i = 0; i < timeouts.length; i++) { const item = timeouts[i]; if (item.targetTimeMs <= nowMs) { try { item.callback(); } catch (e) { console.error('Engine setTimeout callback error', e); } } else { timeouts[writeIndex++] = item; } } if (writeIndex !== timeouts.length) { timeouts.length = writeIndex; } } _clearEngineTimeouts() { this._engineTimeouts = []; } setTimeout(callback, delay) { if (typeof callback !== 'function') { return null; } const id = ++this._engineTimeoutSeq; const targetTimeMs = this._getEngineTimeMs() + Math.max(Number(delay) || 0, 0); this._engineTimeouts.push({ id, callback, targetTimeMs, }); return id; } clearTimeout(id) { this._engineTimeouts = this._engineTimeouts.filter((item) => item.id !== id); } }; ================================================ FILE: src/class/entity.js ================================================ /** * @fileoverview entity object is class for entry object canvas view. */ 'use strict'; import { GEHelper } from '../graphicEngine/GEHelper'; import { GEDragHelper } from '../graphicEngine/GEDragHelper'; const FONT_PADDING_TOP_EXCEPTIONS = ['Nanum Gothic Coding', 'SDMapssi']; const TEXT_BOX_REPOSITION_THRESHOLD = 10; const TEXT_BOX_REPOSITION_OFFSET = 10; const TEXT_BOX_WEBGL_OFFSET = 5.9; /** * Construct entity class * @param {!Entry.EntryObject} object * @constructor */ Entry.EntityObject = class EntityObject { constructor(object) { /** @type {!string} */ this.parent = object; this.type = object.objectType; /** @type {Array} */ this.flip = false; this.collision = Entry.Utils.COLLISION.NONE; this.id = Entry.generateHash(); this.removed = false; this.stamps = []; this.shapes = []; this.paintShapes = []; this._rndPosX = 0; this._rndPosY = 0; this.scaleOriginX = 0; this.scaleOriginY = 0; this.voice = { speed: 0, pitch: 0, speaker: 'kyuri', volume: 1 }; this.defaultLog = { textEffect: {}, }; if (this.type === 'sprite') { this._rndPosX = GEHelper.rndPosition(); this._rndPosY = GEHelper.rndPosition(); this.object = GEHelper.newEmptySprite(); this.object.pixelPerfect = true; this._scaleAdaptor = GEHelper.newAScaleAdaptor(this.object); this.setInitialEffectValue(); } else if (this.type === 'textBox') { this.object = GEHelper.newContainer(); this._scaleAdaptor = GEHelper.newAScaleAdaptor(this.object); this.textObject = GEHelper.textHelper.newText( '', '20px Nanum Gothic', '', 'middle', 'center' ); /* bgObject 가 transparent 인 경우에도 textObject 가 hit 처리되어서 container on event 가 동작해버리는 이슈가 있었음. (issues/10463) textObject 를 정확히 그려진 부분만 interactive 하도록 플래그 수정 */ this.textObject.pixelPerfect = true; if (GEHelper.isWebGL) { this.textObject.anchor.set(0.5, 0.5); } this.bgObject = GEHelper.newGraphic(); this.bgObject.graphics.beginFill('#ffffff').drawRect(0, 0, 100, 100); this.object.addChild(this.bgObject); this.object.addChild(this.textObject); this.fontType = 'Nanum Gothic'; this.fontSize = 20; this.fontBold = false; this.fontItalic = false; this.underLine = false; this.strike = false; } this.object.entity = this; this.object.cursor = 'pointer'; this.object.mouseEnabled = true; GEDragHelper.handleDrag(this.object); this.object.on(GEDragHelper.types.DOWN, function ({ stageX, stageY }) { const id = this.entity.parent.id; Entry.dispatchEvent('entityClick', this.entity); Entry.stage.isObjectClick = true; if (Entry.type !== 'minimize' && Entry.stage.isEntitySelectable()) { if (Entry.objectEditable) { this.offset = { x: -this.parent.x + this.entity.getX() - (stageX * 0.75 - 240), y: -this.parent.y - this.entity.getY() - (stageY * 0.75 - 135), }; this.cursor = 'move'; this.entity.initCommand(); } Entry.container.selectObject(id); } }); this.object.on(GEDragHelper.types.UP, function () { Entry.dispatchEvent('entityClickCanceled', this.entity); this.cursor = 'pointer'; this.entity.checkCommand(); }); if (Entry.type !== 'minimize' && Entry.objectEditable) { this.object.on(GEDragHelper.types.MOVE, function ({ stageX, stageY }) { if (Entry.stage.isEntitySelectable()) { const entity = this.entity; if (entity.parent.getLock()) { return; } if (this.offset) { entity.setX(stageX * 0.75 - 240 + this.offset.x); entity.setY(-(stageY * 0.75 - 135) - this.offset.y); } Entry.stage.updateObject(); } }); } } /** * Construct entity class * @param {?picture model} pictureModel * @param {?entity model} entityModel * @constructor */ injectModel(pictureModel, entityModel) { const type = this.type; if (type === 'sprite') { this.setImage(pictureModel); } else if (type === 'textBox') { const parent = this.parent; entityModel.text = entityModel.text || parent.text || parent.name; this.setFont(entityModel.font); this.setBGColour(entityModel.bgColor); this.setColour(entityModel.colour); this.setUnderLine(entityModel.underLine); this.setStrike(entityModel.strike); this.setText(entityModel.text); } //entity if (entityModel) { this.syncModel_(entityModel); } } /** * sync this model with parameter * @param {!entity model} entityModel * @private */ syncModel_({ x, y, regX, regY, scaleX, scaleY, rotation, direction, lineBreak, width, height, text, textAlign, fontSize, visible, }) { this.setX(x); this.setY(y); this.setRegX(regX); this.setRegY(regY); this.setScaleX(scaleX); this.setScaleY(scaleY); this.scaleOriginX = scaleX; this.scaleOriginY = scaleY; this.setRotation(rotation); this.setDirection(direction, true); this.setLineBreak(lineBreak); this.setWidth(width); this.setHeight(height); this.setText(text); this.setTextAlign(textAlign); this.setFontSize(fontSize || this.getFontSize()); this.setVisible(visible); } initCommand() { if (!Entry.engine.isState('stop')) { return; } this._entityModelBefore = this.toJSON(); } checkCommand() { if (!Entry.engine.isState('stop')) { return; } const oldModel = this._entityModelBefore; delete this._entityModelBefore; const json = this.toJSON(); if (_.isEqual(json, oldModel)) { return; } Entry.do('entitySetModel', this.parent.id, json, oldModel); } /** * for redo and undo * @param {!entity model} entityModel * @return {Entry.State} capture current state */ setModel(entityModel) { this.syncModel_(entityModel); Entry.dispatchEvent('updateObject'); Entry.stage.updateObject(); } /** * X coordinate setter * @param {number} x */ setX(x) { if (typeof x !== 'number') { return; } /** @type {number} */ this.x = x; this.object.x = this.x + this._rndPosX; !this.isClone && this.parent.updateCoordinateView(); this.updateDialog(); Entry.requestUpdate = true; } /** * X coordinate getter * @return {number} */ getX(toFixedValue) { if (toFixedValue) { return Entry.Utils.toFixed(this.x, toFixedValue); } else { return this.x; } } /** * Y coordinate setter * @param {number} y */ setY(y) { if (typeof y !== 'number') { return; } /** @type {number} */ this.y = y; this.object.y = -this.y + this._rndPosY; !this.isClone && this.parent.updateCoordinateView(); this.updateDialog(); Entry.requestUpdate = true; } /** * Y coordinate getter * @return {number} */ getY(toFixedValue) { if (toFixedValue) { return Entry.Utils.toFixed(this.y, toFixedValue); } else { return this.y; } } /** * direction getter * @return {number} */ getDirection(toFixedValue) { if (toFixedValue) { return Entry.Utils.toFixed(this.direction, toFixedValue); } else { return this.direction; } } /** * direction setter * @param {number} direction * @param {boolean} flippable */ setDirection(dir = 0, flippable) { const direction = dir.mod(360); const parent = this.parent; if (parent.getRotateMethod() === 'vertical' && !flippable) { const previousIsRight = this.direction >= 0 && this.direction < 180; const afterIsRight = direction >= 0 && direction < 180; if (previousIsRight != afterIsRight) { this.setScaleX(-this.getScaleX()); Entry.stage.updateObject(); this.flip = !this.flip; } } /** @type {number} */ this.direction = direction; this.object.direction = this.direction * GEHelper.rotateWrite; !this.isClone && parent.updateRotationView(); Entry.dispatchEvent('updateObject'); Entry.requestUpdate = true; } /** * rotation setter * @param {number} rotation * */ setRotation(rotation) { /** @type {number} */ if (this.parent.getRotateMethod() !== 'free') { rotation = 0; } this.rotation = rotation.mod(360); this.object.rotation = this.rotation * GEHelper.rotateWrite; this.updateDialog(); !this.isClone && this.parent.updateRotationView(); Entry.dispatchEvent('updateObject'); Entry.requestUpdate = true; } /** * rotation getter * @return {number} */ getRotation(toFixedValue) { if (toFixedValue) { return Entry.Utils.toFixed(this.rotation, toFixedValue); } else { return this.rotation; } } /** * regX coordinate setter * @param {number} regX */ setRegX(regX) { if (this.type === 'textBox') { regX = 0; } /** @type {number} */ this.regX = regX; if (GEHelper.isWebGL) { this._scaleAdaptor.pivot.setX(regX); } else { this.object.regX = this.regX; } Entry.requestUpdate = true; } /** * regX coordinate getter * @return {number} */ getRegX() { return this.regX; } /** * regY coordinate setter * @param {number} regY */ setRegY(regY) { if (this.type === 'textBox') { regY = 0; } /** @type {number} */ this.regY = regY; if (GEHelper.isWebGL) { this._scaleAdaptor.pivot.setY(regY); } else { this.object.regY = this.regY; } Entry.requestUpdate = true; } /** * regY coordinate getter * @return {number} */ getRegY() { return this.regY; } /** * scaleX coordinate setter * @param {number} scaleX */ setScaleX(scaleX) { /** @type {number} */ this.scaleX = scaleX; if (Entry.engine.isState('stop')) { this.scaleOriginX = scaleX; } if (GEHelper.isWebGL) { this._scaleAdaptor.scale.setX(scaleX); if (this.textObject) { this.textObject.setFontScaleX(scaleX); } } else { this.object.scaleX = this.scaleX; } this.parent.updateCoordinateView(); this.updateDialog(); Entry.requestUpdate = true; } /** * scaleX coordinate getter * @return {number} */ getScaleX() { return this.scaleX; } /** * scaleY coordinate setter * @param {number} scaleY */ setScaleY(scaleY) { /** @type {number} */ this.scaleY = scaleY; if (Entry.engine.isState('stop')) { this.scaleOriginY = scaleY; } if (GEHelper.isWebGL) { this._scaleAdaptor.scale.setY(scaleY); if (this.textObject) { this.textObject.setFontScaleY(scaleY); } } else { this.object.scaleY = this.scaleY; } this.parent.updateCoordinateView(); this.updateDialog(); Entry.requestUpdate = true; } /** * scaleY coordinate getter * @return {number} */ getScaleY() { return this.scaleY; } /** * object size setter * @param {number} size */ setSize(size) { const scale = Math.max(1, size) / this.getSize(); this.setScaleX(this.getScaleX() * scale); this.setScaleY(this.getScaleY() * scale); !this.isClone && this.parent.updateCoordinateView(); Entry.requestUpdate = true; } resetSize() { this.setScaleX(this.scaleOriginX); this.setScaleY(this.scaleOriginY); !this.isClone && this.parent.updateCoordinateView(); Entry.requestUpdate = true; } setXSize(size) { const scale = Math.max(1, size) / this.getSize(); this.setScaleX(this.getScaleX() * scale); !this.isClone && this.parent.updateCoordinateView(); Entry.requestUpdate = true; } setYSize(size) { const scale = Math.max(1, size) / this.getSize(); this.setScaleY(this.getScaleY() * scale); !this.isClone && this.parent.updateCoordinateView(); Entry.requestUpdate = true; } /** * get object size * @return {number} */ getSize(toFixedValue) { const value = (this.getWidth() * Math.abs(this.getScaleX()) + this.getHeight() * Math.abs(this.getScaleY())) / 2; if (toFixedValue) { return Entry.Utils.toFixed(value, toFixedValue); } return value; } /** * width coordinate setter * @param {number} width */ setWidth(width) { /** @type {number} */ this.width = width; //todo [박봉배] object.width -> object.$width 로 변경 this.object.$width = this.width; if (this.textObject && this.getLineBreak()) { if (GEHelper.isWebGL) { this.textObject.style.wordWrapWidth = this.width; } else { this.textObject.lineWidth = this.width; } } this.updateDialog(); this.updateBG(); Entry.requestUpdate = true; } /** * width coordinate getter * @return {number} */ getWidth() { return this.width; } /** * height coordinate setter * @param {number} height */ setHeight(height) { /** @type {number} */ //todo [박봉배] object.height -> object.$height 로 변경 this.height = height; if (this.textObject) { this.object.$height = this.height; this.alignTextBox(); } this.updateDialog(); this.updateBG(); Entry.requestUpdate = true; } /** * height coordinate getter * @return {number} */ getHeight() { return this.height; } setColorWithLog(colour) { if (!this.defaultLog.textColor) { this.defaultLog.textColor = this.colour || '#000000'; } this.setColour(colour); } /** * colour setter * @param {?string} colour */ setColour(colour = '#000000') { /** @type {string} */ this.colour = colour; if (this.textObject) { GEHelper.textHelper.setColor(this.textObject, this.colour); } Entry.requestUpdate = true; } /** * colour getter * @return {colour} */ getColour() { return this.colour; } /** * NT11576 BGcolor with log #3513 * @param {*} colour */ setBGColourWithLog(colour = 'transparent') { if (!this.defaultLog.textBGColor) { this.defaultLog.textBGColor = this.bgColor || 'transparent'; } this.setBGColour(colour); } /** * BG colour setter, for textBox object * @param {?string} colour */ setBGColour(colour = 'transparent') { /** @type {string} */ this.bgColor = colour; this.updateBG(); //this.object.color = this.colour; Entry.requestUpdate = true; } /** * BG colour getter, for textBox object * @return {colour} */ getBGColour() { return this.bgColor; } setUnderLine(underLine = false) { this.underLine = underLine; if (GEHelper.isWebGL) { this.textObject.style.underLine = underLine; } else { this.textObject.underLine = underLine; } Entry.requestUpdate = true; } getUnderLine() { return this.underLine; } setStrike(strike = false) { this.strike = strike; if (GEHelper.isWebGL) { this.textObject.style.cancelLine = strike; } else { this.textObject.strike = strike; } Entry.requestUpdate = true; } getStrike() { return this.strike; } /** * font getter */ getFont() { const fontArray = []; if (this.fontBold) { fontArray.push('bold'); } if (this.fontItalic) { fontArray.push('italic'); } fontArray.push(`${this.getFontSize()}px`); fontArray.push(this.fontType); return fontArray.join(' '); } setFontWithLog(font, shouldUpdateWidth) { if (!this.defaultLog.textFont) { this.defaultLog.textFont = `${this.getFontSize()} ${this.fontType}`; } this.setFont(font, shouldUpdateWidth); } /** * font setter */ setFont(font = '20 Nanum Gothic', shouldUpdateWidth = true) { if (this.parent.objectType !== 'textBox') { return; } if (this.textObject.font === font) { return; } const fontArray = font.split(' '); let i = 0; // NT11576 wodnjs6512 // #3513 글씨체 변경시에 기존 bold 와 italic을 받아와서 사용하도록 if ((i = fontArray.indexOf('bold') > -1)) { fontArray.splice(i - 1, 1); this.setFontBold(true); } else if (this.fontBold) { this.setFontBold(true); } if ((i = fontArray.indexOf('italic') > -1)) { fontArray.splice(i - 1, 1); this.setFontItalic(true); } else if (this.fontItalic) { this.setFontItalic(true); } if (this.getLineBreak()) { this.setLineBreak(this.getLineBreak()); } this.setFontSize(parseFloat(fontArray.shift())); this.setFontType(fontArray.join(' ')); this._syncFontStyle(); Entry.stage.update(); // NT11576 wodnjs6512 // #3513 기존의 텍스트 상자 리사이즈가 필요없는 경우에는 disable 할수 있도록 옵션으로 실행 default = 실행 if (shouldUpdateWidth) { this.setWidth(this.textObject.getMeasuredWidth()); } this.updateBG(); Entry.stage.update(); Entry.stage.updateObject(); } setLineHeight() { const lineHeight = this.fontSize + 2; if (GEHelper.isWebGL) { this.textObject.style.lineHeight = lineHeight; } else { this.textObject.lineHeight = lineHeight; } } syncFont() { const textObject = this.textObject; this._syncFontStyle(); this.setLineHeight(); Entry.stage.update(); if (this.getLineBreak()) { if (this.fontType === 'Nanum Gothic Coding') { textObject.y = textObject.getMeasuredLineHeight() / 2 - this.getHeight() / 2 + 10; } } else { this.setWidth(textObject.getMeasuredWidth()); this.setHeight(textObject.getMeasuredHeight()); } Entry.stage.updateObject(); Entry.requestUpdate = true; } /** * font type getter */ getFontType() { return this.fontType; } /** * font type setter */ setFontType(fontType = 'Nanum Gothic') { if (this.parent.objectType !== 'textBox') { return; } this.fontType = fontType; this.syncFont(); } /** * font size getter */ getFontSize() { return this.fontSize; } /** * font size setter */ setFontSize(fontSize = 20) { if (this.parent.objectType !== 'textBox') { return; } if (this.fontSize === fontSize) { return; } this.fontSize = fontSize; this.syncFont(); this.alignTextBox(); } /** * set font bold state */ setFontBold(isFontBold = false) { this.fontBold = isFontBold; this.syncFont(); Entry.requestUpdate = true; } /** * toggle bold on,off and return current */ toggleFontBold() { this.fontBold = !this.fontBold; this.syncFont(); return this.fontBold; } /** * set font italic state */ setFontItalic(isFontItalic = false) { this.fontItalic = isFontItalic; this.syncFont(); Entry.requestUpdate = true; } /** * toggle italic on,off and return current */ toggleFontItalic() { this.fontItalic = !this.fontItalic; this.syncFont(); return this.fontItalic; } getFontName() { if (this.type !== 'textBox') { return; } const font = this.textObject.font; if (!font) { return ''; } return font .split(' ') .filter((font) => !/^(bold|italic)$/.test(font) && !~font.indexOf('px')) .join(' ') .trim(); } /** * NT11576 wodnjs6512 * #3513 text effect setter * @param {string} effect */ setTextEffect(effect, mode) { if (this.parent.objectType !== 'textBox') { return; } // remember default if (this.defaultLog.textEffect[effect] == undefined) { this.defaultLog.textEffect[effect] = this[effect]; } this.textObject.text = this.text; this.applyEffectByNameAndValue(effect, mode == 'on'); } /** * NT11576 wodnjs6512 * #3513 reset text effect accroding to the log left with setTextEffect() */ resetTextEffect() { for (const effect of Object.keys(this.defaultLog.textEffect)) { const value = this.defaultLog.textEffect[effect]; this.applyEffectByNameAndValue(effect, value); } if (this.defaultLog.textColor) { this.setColour(this.defaultLog.textColor); } if (this.defaultLog.textFont) { this.setFont(this.defaultLog.textFont); } if (this.defaultLog.textBGColor) { this.setBGColour(this.defaultLog.textBGColor); } this.defaultLog = { textEffect: {}, }; } /** * NT11576 wodnjs6512 * #3513 change font style and update stage * @param {*} effect * @param {*} mode */ applyEffectByNameAndValue(effect, mode) { switch (effect) { case 'fontBold': this.setFontBold(mode); break; case 'fontItalic': this.setFontItalic(mode); break; case 'underLine': this.setUnderLine(mode); break; case 'strike': this.setStrike(mode); break; } this.updateTextbox(); } updateTextbox() { if (!this.lineBreak) { this.setWidth(this.textObject.getMeasuredWidth()); this.parent.updateCoordinateView(); } this.updateBG(); Entry.stage.updateObject(); } /** * text setter * @param {string} text */ setText(text = '') { if (this.parent.objectType !== 'textBox') { return; } /** @type {string} */ this.text = text; this.textObject.text = this.text; this.updateTextbox(); } /** * text getter * @return {string} */ getText() { return this.text; } /** * textAlign setter * @param {number} textAlign */ setTextAlign(textAlign = Entry.TEXT_ALIGN_CENTER) { if (this.parent.objectType !== 'textBox') { return; } this.textAlign = textAlign; const textObj = this.textObject; const alignValue = Entry.TEXT_ALIGNS[textAlign]; if (GEHelper.isWebGL) { const anchorX = [0.5, 0, 1]; textObj.anchor.x = anchorX[textAlign]; textObj.style.align = alignValue; } else { textObj.textAlign = alignValue; } this.alignTextBox(); this.updateBG(); Entry.stage.updateObject(); /* this.setWidth(this.textObject.getMeasuredWidth()); this.updateBG(); */ } /** * textAlign getter * @return {number} */ getTextAlign() { return this.textAlign; } /** * lineBreak setter * @param {boolean} lineBreak */ setLineBreak(lineBreak = false) { if (this.parent.objectType !== 'textBox') { return; } const isWebGL = GEHelper.isWebGL; const previousState = this.lineBreak; this.lineBreak = lineBreak; if (previousState && !this.lineBreak) { if (isWebGL) { this.textObject.style.wordWrap = false; } else { this.textObject.lineWidth = null; } this.setHeight(this.textObject.getMeasuredLineHeight()); this.setText(this.getText().replace(/\n/g, '')); if (isWebGL) { this.textObject.anchor.y = 0.5; } } else if (this.lineBreak) { if (previousState === false) { this.setFontSize(this.getFontSize() * this.getScaleX()); this.setHeight(this.textObject.getMeasuredLineHeight() * 3); this.setWidth(this.getWidth() * this.getScaleX()); this.setScaleX(1); this.setScaleY(1); } if (isWebGL) { this.textObject.anchor.y = 0; this.textObject.style.wordWrap = true; this.textObject.style.breakWords = true; this.textObject.style.wordWrapWidth = Math.ceil(this.getWidth()); } else { this.textObject.lineWidth = Math.ceil(this.getWidth()); } this.alignTextBox(); if (this.fontType === 'Nanum Gothic Coding') { const textObjectHeight = this.textObject.getMeasuredLineHeight(); this.textObject.y = textObjectHeight / 2 - this.getHeight() / 2 + 10; } } Entry.stage.updateObject(); } /** * lineBreak getter * @return {number} */ getLineBreak() { return this.lineBreak; } /** * visible setter * @param {boolean} visible */ setVisible(visible = true) { /** @type {string} */ this.visible = visible; this.object.visible = this.visible; if (this.dialog) { this.syncDialogVisible(); } Entry.requestUpdate = true; return this.visible; } /** * visible getter * @return {boolean} */ getVisible() { return this.visible; } /** * Change picture * @param {?picture model} pictureModel */ setImage(pictureModel) { if (!pictureModel) { return; } const that = this; delete pictureModel._id; Entry.assert(this.type === 'sprite', 'Set image is only for sprite object'); if (!pictureModel.id) { pictureModel.id = Entry.generateHash(); } this.picture = pictureModel; const dimension = this.picture.dimension; const entityWidth = this.getWidth(); const entityHeight = this.getHeight(); const absoluteRegX = this.getRegX() - entityWidth / 2; const absoluteRegY = this.getRegY() - entityHeight / 2; this.setWidth(dimension.width); this.setHeight(dimension.height); if (!dimension.scaleX) { dimension.scaleX = this.getScaleX(); dimension.scaleY = this.getScaleY(); } this.setScaleX(this.scaleX); this.setScaleY(this.scaleY); this.setRegX(this.width / 2 + absoluteRegX); this.setRegY(this.height / 2 + absoluteRegY); /** * //이 코드는 createjs 일때만 호출 됨. * @param {AtlasImageLoadingInfo} info */ const onImageLoad = GEHelper.isWebGL ? null : (info) => { if (this.removed) { return; } const isResizedImage = info.source() !== this.object.image; if (isResizedImage) { this.object.image = info.source(); } const hasFilter = !_.isEmpty(that.object.filters); GEHelper.colorFilter.setCache(this, hasFilter); Entry.requestUpdate = true; }; GEHelper.resManager.reqResource( this.object, this.parent.scene.id, pictureModel, onImageLoad ); if (GEHelper.isWebGL) { this._scaleAdaptor.updateScaleFactor(); this.object.refreshFilter(); } Entry.dispatchEvent('updateObject'); } /** * Apply easel filter */ applyFilter(isForce, forceEffects) { const effects = this.effect; const object = this.object; let diffEffects = isEqualEffects(effects, this.getInitialEffectValue()); if (!isForce && diffEffects.length === 0) { return; } if (Array.isArray(forceEffects)) { diffEffects = diffEffects.concat(forceEffects); } (function (e, obj) { const f = []; const adjust = Entry.adjustValueWithMaxMin; if (~diffEffects.indexOf('brightness')) { const brightness = adjust(e.brightness, -100, 100); f.push(GEHelper.colorFilter.brightness(brightness)); } if (~diffEffects.indexOf('hue')) { f.push(GEHelper.colorFilter.hue(e.hue.mod(360))); } if (~diffEffects.indexOf('hsv')) { /* eslint-disable */ let matrixValue = [ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, ]; /* eslint-enable */ const degrees = e.hsv * 3.6; const r = (degrees * 3 * Math.PI) / 180; const cosVal = Math.cos(r); const sinVal = Math.sin(r); let v = Math.abs(e.hsv / 100); if (v > 1) { v = v - Math.floor(v); } if (v > 0 && v <= 0.33) { /* eslint-disable */ matrixValue = [ 1, 0, 0, 0, 0, 0, cosVal, sinVal, 0, 0, 0, -1 * sinVal, cosVal, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, ]; } else if (v <= 0.66) { matrixValue = [ cosVal, 0, sinVal, 0, 0, 1, 0, 0, 0, 0, sinVal, 0, cosVal, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, ]; } else if (v <= 0.99) { matrixValue = [ cosVal, sinVal, 0, 0, 0, -1 * sinVal, cosVal, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, ]; } /* eslint-enable */ const colorFilter = GEHelper.colorFilter.newColorMatrixFilter(matrixValue); f.push(colorFilter); } if (~diffEffects.indexOf('alpha')) { e.alpha = adjust(e.alpha, 0, 1); obj.alpha = e.alpha; if (obj.alpha < 0.001) { obj.interactive = false; } else { obj.interactive = true; } } if (GEHelper.isWebGL) { obj.setFilterAndCache(f); } else { obj.filters = f; } })(effects, object); this.cache(); function isEqualEffects(effectsA, effectsB) { const diffEffects = []; for (const key in effectsA) { if (effectsA[key] !== effectsB[key]) { diffEffects.push(key); } } return diffEffects; } } /** * Remove all filter */ resetFilter() { if (this.parent.objectType !== 'sprite') { return; } const object = this.object; if (GEHelper.isWebGL) { object.setFilterAndCache(null); } else { object.filters = []; } this.setInitialEffectValue(); object.alpha = this.effect.alpha; if (object.alpha < 0.001) { object.interactive = false; } else { object.interactive = true; } GEHelper.colorFilter.setCache(this, false); } /** * update dialog position if exist */ updateDialog() { if (this.dialog) { this.dialog.update(); } Entry.requestUpdate = true; } /** * save current state data to 'snapshot_' */ takeSnapshot() { this.snapshot_ = this.toJSON(); this.collision = Entry.Utils.COLLISION.NONE; } /** * load snapshot to current entity */ loadSnapshot() { if (this.snapshot_) { this.syncModel_(this.snapshot_); } if (this.parent.objectType === 'sprite') { this.setImage(this.parent.getPicture()); } Entry.requestUpdate = true; } /** * Remove itself when this is clone */ removeClone(isLast) { if (!this.isClone) { return; } const clonedEntities = this.parent.clonedEntities; if (isLast !== true) { const index = clonedEntities.indexOf(this); if (index > -1) { clonedEntities.splice(index, 1); } } else { clonedEntities.pop(); } _.result(this, 'clearExecutor'); this.destroy(true); } clearExecutor() { this.parent.script.clearExecutorsByEntity(this); } /** * convert this entity's data to JSON. * @return {JSON} */ toJSON() { const _cut = Entry.cutDecimal; const json = {}; json.x = _cut(this.getX()); json.y = _cut(this.getY()); json.regX = _cut(this.getRegX()); json.regY = _cut(this.getRegY()); json.scaleX = this.getScaleX(); json.scaleY = this.getScaleY(); json.rotation = _cut(this.getRotation()); json.direction = _cut(this.getDirection()); json.width = _cut(this.getWidth()); json.height = _cut(this.getHeight()); json.font = this.getFont(); json.visible = this.getVisible(); if (this.parent.objectType === 'textBox') { json.colour = this.getColour(); json.text = this.getText(); json.textAlign = this.getTextAlign(); json.lineBreak = this.getLineBreak(); json.bgColor = this.getBGColour(); json.underLine = this.getUnderLine(); json.strike = this.getStrike(); json.fontSize = this.getFontSize(); } return json; } /* * Return initial effect value * @return {effect} */ setInitialEffectValue() { this.effect = this.getInitialEffectValue(); Entry.requestUpdate = true; } /* * Return initial effect value * @return {effect} */ getInitialEffectValue() { return { blur: 0, hue: 0, hsv: 0, brightness: 0, contrast: 0, saturation: 0, alpha: 1, }; } /* * Return initial effect value * @return {effect} */ setVoiceProp(prop) { const { speed = 0, pitch = 0, speaker = 'kyuri', volume = 1 } = prop; this.voice = { speed, pitch, speaker, volume }; } /* * Return initial effect value * @return {effect} */ getVoiceProp() { return this.voice; } /* * remove brush */ removeBrush() { this._removeShapes(); this.brush = null; } removePaint() { this._removePaintShapes(); this.paint = null; } eraseBrush() { const brush = this.brush; if (brush) { // WebGL 인경우 createjs와 같은 코드로 동작하지 않아서 코드 분기생성 (#11626) const isWebGL = GEHelper.isWebGL; if (isWebGL) { const { r, g, b } = brush.rgb; const thickness = brush.thickness; const opacity = 1 - brush.opacity / 100; brush.clear(); brush.setStrokeStyle(thickness); brush.beginStrokeFast(Entry.rgb2Number(r, g, b), opacity); } else { // 기존 스펙으로 롤백(#11434) const stroke = brush._stroke.style; const thickness = brush._strokeStyle.width; brush.clear().setStrokeStyle(thickness).beginStroke(stroke); } } Entry.requestUpdate = true; } erasePaint() { const paint = this.paint; if (paint) { paint.clear(); } Entry.requestUpdate = true; } _removeShapes() { const container = Entry.stage.selectedObjectContainer; const shapes = this.shapes; const LEN = shapes.length; let s; for (let i = 0; i < LEN; i++) { s = shapes[i]; container.removeChild(s); s.destroy && s.destroy(true); //pixi 일때만 호출 } this.shapes = []; } _removePaintShapes() { const container = Entry.stage.selectedObjectContainer; const shapes = this.paintShapes; const LEN = shapes.length; let s; for (let i = 0; i < LEN; i++) { s = shapes[i]; container.removeChild(s); s.destroy && s.destroy(true); //pixi 일때만 호출 } this.paintShapes = []; } updateBG() { if (!this.bgObject) { return; } this.bgObject.graphics.clear(); const width = this.getWidth(); const height = this.getHeight(); const bgColor = this.getBGColour(); const hasColor = (bgColor || '').indexOf('#') === 0; this.bgObject.alpha = hasColor ? 1 : 0; this.bgObject.graphics.beginFill(bgColor).drawRect(-width / 2, -height / 2, width, height); if (this.getLineBreak()) { this.bgObject.x = 0; } else { const fontAlign = this.getTextAlign(); switch (fontAlign) { case Entry.TEXT_ALIGN_LEFT: this.bgObject.x = width / 2; break; case Entry.TEXT_ALIGN_CENTER: this.bgObject.x = 0; break; case Entry.TEXT_ALIGN_RIGHT: this.bgObject.x = -width / 2; break; } } } // 통상적 높이 계산을 위한 Method getMeasuredLineHeight() { if (!this.invisibleCanvas) { if (this.textObject.canvas) { this.invisibleCanvas = this.textObject.canvas; } else { this.invisibleCanvas = Entry.Dom($(''))[0]; } } const fontCanvas = this.invisibleCanvas; const context = fontCanvas.getContext('2d'); context.font = this.textObject.font; return Math.round(context.measureText('M').width * 100) / 100; } alignTextBox() { if (this.type !== 'textBox') { return; } const textObject = this.textObject; const isWebGL = GEHelper.isWebGL; if (this.lineBreak) { if (isWebGL) { textObject.y = -this.getHeight() / 2 + TEXT_BOX_REPOSITION_OFFSET - TEXT_BOX_WEBGL_OFFSET; } else { const desiredValue = textObject.getMeasuredLineHeight() / 2 - this.getHeight() / 2 + TEXT_BOX_REPOSITION_OFFSET / 2; // 가끔씩 계산의 값이 달라지는 경우가 있어서 확인하여서 기존과 차이가 거의 없다면 그대로, if (Math.abs(desiredValue - textObject.y) > TEXT_BOX_REPOSITION_THRESHOLD) { textObject.y = FONT_PADDING_TOP_EXCEPTIONS.indexOf(this.fontType) > -1 ? desiredValue + TEXT_BOX_REPOSITION_OFFSET : desiredValue; } } switch (this.textAlign) { case Entry.TEXT_ALIGN_CENTER: textObject.x = 0; break; case Entry.TEXT_ALIGN_LEFT: textObject.x = -this.getWidth() / 2; break; case Entry.TEXT_ALIGN_RIGHT: textObject.x = this.getWidth() / 2; break; } if (isWebGL) { textObject.style.maxHeight = this.getHeight(); } else { textObject.maxHeight = this.getHeight(); } } else { textObject.x = 0; textObject.y = 0; } } syncDialogVisible() { if (this.dialog?.object) { this.dialog.object.visible = this.visible; } } addStamp() { const stampEntity = new Entry.StampEntity(this.parent, this); const stage = Entry.stage; stage.loadEntity(stampEntity, stage.selectedObjectContainer.getChildIndex(this.object)); this.stamps.push(stampEntity); Entry.requestUpdate = true; } removeStamps() { this.stamps.forEach((s) => s.destroy()); this.stamps = []; Entry.requestUpdate = true; } destroy(isClone) { if (this.removed) { return; } this.removed = true; const object = this.object; if (object) { GEHelper.colorFilter.setCache(this, false); object.removeAllEventListeners && object.removeAllEventListeners(); delete object.image; delete object.entity; } if (this._scaleAdaptor) { this._scaleAdaptor.destroy(); this._scaleAdaptor = null; } if (this.stamps && this.stamps.length) { this.removeStamps(); } _.result(this.dialog, 'remove'); this.brush && this.removeBrush(); this.paint && this.removePaint(); Entry.stage.unloadEntity(this); //pixi 전용 코드 object && object.destroy && object.destroy({ children: true }); } cache() { const { object } = this; if (object) { if (!GEHelper.isWebGL) { object.cache(0, 0, this.getWidth(), this.getHeight()); } Entry.requestUpdate = true; } } reset() { this.resetTextEffect(); this.loadSnapshot(); this.resetFilter(); _.result(this.dialog, 'remove'); this.shapes.length && this.removeBrush(); this.paintShapes.length && this.removePaint(); } _syncFontStyle() { this.textObject.font = this.getFont(); if (!GEHelper.isWebGL) { return; } const style = this.textObject.style; style.fontSize = `${this.getFontSize()}px`; style.fontStyle = this.fontItalic ? 'italic' : 'normal'; style.fontWeight = this.fontBold ? 'bold' : 'normal'; style.fontFamily = this.fontType; } }; ================================================ FILE: src/class/entryModuleLoader.ts ================================================ import fetch from 'isomorphic-fetch'; import cryptojs from 'crypto-js'; import { EntryBlock, EntryBlockModule, EntryHardwareBlockModule } from '../../types/index'; type EntryBlockRegisterSchema = { blockName: string; block: EntryBlock; isBlockShowBlockMenu?: boolean; }; class EntryModuleLoader { public moduleList: string[] = []; public moduleListLite: string[] = []; /** * @deprecated * 해당 url 을 동적으로 로드한다. * 해당 함수는 굉장히 위험하므로 추가적인 방어로직이 필요하다. * key는 로컬에서 파일을 암호화 하여 entry-hw 에서 전달, 해당 파일을 로컬에 있는 키로 1차 검증, 서버로 2차 검증을 통한 무결성/보안 확보 * 오프라인의 경우, 오픈소스임으로, 로컬상태에서의 비정상적인 사용에 대한 제약이 힘든 부분이 있음. 다만, 온라인이 되는 경우 서버 검증을 사용 할 수 있음 */ // bl.loadModule(moduleName: string) bl.loadBlock(blockName, block)... async loadModule(moduleInfo: { name: string; file: string }): Promise { if (!moduleInfo.file || !moduleInfo.name) { return; } let blockFile = moduleInfo.file; if (Entry.offlineModulePath) { if (window.sendSync) { blockFile = window.sendSync('decryptBlock', blockFile); } } const key = cryptojs.SHA1(blockFile); // sha1 key를 이용한 블럭 파일 검증. if (window.navigator.onLine) { try { const sha1Result = await fetch( `${Entry.moduleBaseUrl}key/${moduleInfo.name}/${key}` ); if (sha1Result.status != 200) { throw new Error('MODULE NOT VERIFIED'); } } catch (e) { throw new Error('MODULE NOT VERIFIED'); } } if (!moduleInfo) { return; } await this.loadScript(moduleInfo.name, blockFile); } async loadModuleFromLocalOrOnline(name: string, isLite?: boolean) { const lowerCaseName = isLite ? name : name.toLowerCase(); const baseUrl = isLite ? Entry.moduleliteBaseUrl : Entry.moduleBaseUrl; let path = `${baseUrl}${name}/files/block`; if (Entry.offlineModulePath) { path = `file://${Entry.offlineModulePath}/${lowerCaseName}/block`; } const response = await fetch(path); if (response.status != 200) { throw new Error('MODULE NOT EXIST'); } let result = await response.text(); const key = cryptojs.SHA1(result).toString(); const isValid = Entry.HARDWARE_LITE_LIST.some( (item: any) => item.name == name && item.sha1 == key ); if (!isValid) { return alert('NOT VALID MODULE'); } if (Entry.offlineModulePath) { if (window.sendSync) { result = window.sendSync('decryptBlock', result); } } await this.loadScript(name, result, isLite); } async loadScript(name: string, code: string, isLite?: boolean) { return await new Promise(async (resolve, reject) => { const scriptElementId = `entryModuleScript${Date.now()}`; const scriptElement = document.createElement('script'); scriptElement.id = scriptElementId; scriptElement.onload = () => { this.moduleListLite = [name]; scriptElement.remove(); resolve(); }; scriptElement.onerror = (e) => { scriptElement.remove(); reject(e); }; const blobedBlock = new Blob([code], { type: 'text/javascript', }); const blobUrl = URL.createObjectURL(blobedBlock); scriptElement.src = blobUrl; // noinspection JSCheckFunctionSignatures document.body.appendChild(scriptElement); URL.revokeObjectURL(blobUrl); }); } // noinspection JSUnusedGlobalSymbols /** * [!] 외부에서 사용하는 함수입니다. 모듈화된 블록이 엔트리 등록을 위해 사용하는 함수임 * 각 블록정보가 존재해야할 위치에 모든 데이터를 뿌려준다. 위치는 아래와 같다 * - Entry.HARDWARE_LIST * - Entry.block : 실제 블록 정보를 담는다. * * 워크스페이스 리로드시 정보가 저장되지 않는다. * 이 후 블록메뉴에 블록들을 실시간으로 추가한 뒤 reDraw 한다. * @param moduleObject 하드웨어 모듈. 여타 하드웨어 모듈 파일 참조 */ registerHardwareModule(moduleObject: EntryHardwareBlockModule) { if (!moduleObject.getBlocks || !moduleObject.blockMenuBlocks) { return; } if (typeof moduleObject.id === 'string') { const prevModuleBlocks = Entry.HARDWARE_LIST[moduleObject.id] && Entry.HARDWARE_LIST[moduleObject.id].blockMenuBlocks; if (prevModuleBlocks) { this.removePrevModuleBlock(prevModuleBlocks); } Entry.HARDWARE_LIST[moduleObject.id] = moduleObject; } else if (moduleObject.id instanceof Array) { moduleObject.id.forEach((id) => { const prevModuleBlocks = Entry.HARDWARE_LIST[id] && Entry.HARDWARE_LIST[id].blockMenuBlocks; if (prevModuleBlocks) { this.removePrevModuleBlock(prevModuleBlocks); } Entry.HARDWARE_LIST[id] = moduleObject; }); } this.setLanguageTemplates(moduleObject); const blockObjects = moduleObject.getBlocks(); const blockMenuBlocks = moduleObject.blockMenuBlocks; this.loadBlocks({ categoryName: 'arduino', blockSchemas: Object.entries(blockObjects).map(([blockName, block]) => ({ blockName, block, isBlockShowBlockMenu: blockMenuBlocks.indexOf(blockName) > -1, })), }); Entry.hw.setExternalModule(moduleObject); Entry.dispatchEvent('hwChanged'); } // clear prevModule if present removePrevModuleBlock(prevModuleBlocks: Array) { let removedCnt = 0; for (const key of Object.keys(Entry.block)) { if (prevModuleBlocks.indexOf(key) > -1) { delete Entry.block[key]; removedCnt++; } if (removedCnt == prevModuleBlocks.length) { break; } } } // 모듈화 적용시, 팝업이벤트로부터 모듈name값만 받아서 동적으로 로드한다. async registerHardwareLiteModule(moduleObject: EntryHardwareBlockModule) { if (!moduleObject.getBlocks || !moduleObject.blockMenuBlocks) { return; } Entry.hwLite.banClassAllHardwareLite(); this.setLanguageTemplates(moduleObject); const blockObjects = moduleObject.getBlocks(); const blockMenuBlocks = moduleObject.blockMenuBlocks; this.loadBlocks({ categoryName: 'arduino', blockSchemas: Object.entries(blockObjects).map(([blockName, block]) => ({ blockName, block, isBlockShowBlockMenu: blockMenuBlocks.indexOf(blockName) > -1, })), }); Entry.hwLite.setExternalModule(moduleObject); } /** * 이 함수는 외부 블록 모듈 URL 의 코드가 호출한다. * 엔트리 내 '확장' 카테고리에 블록을 추가한다. * 블록은 moduleObject 의 정보에 따라 타이틀, 설명 TextBlock 이 같이 추가된다. * @param moduleObject */ registerBlockModule(moduleObject: EntryBlockModule) { const { name, title, description, getBlocks } = moduleObject; const blockSchemas: EntryBlockRegisterSchema[] = []; title && blockSchemas.push(this.createTextBlock(name, title.ko)); description && blockSchemas.push(this.createTextBlock(name, description)); getBlocks && blockSchemas.push( ...Object.entries(getBlocks()).map(([blockName, block]) => ({ blockName, block, isBlockShowBlockMenu: true, })) ); this.loadBlocks({ categoryName: 'expansion', blockSchemas, }); } loadBlocks({ categoryName, blockSchemas, }: { categoryName: string; blockSchemas: EntryBlockRegisterSchema[]; }) { const blockMenu = Entry.getMainWS()?.blockMenu; blockSchemas.forEach((blockSchema) => { this.applyDefaultProperties(blockSchema); const { blockName, block, isBlockShowBlockMenu } = blockSchema; // 블록의 카테고리를 정의할때 사용 if (!block.category) { block.category = categoryName; } Entry.block[blockName] = block; if (isBlockShowBlockMenu && blockMenu) { blockMenu.addCategoryData(categoryName, blockName); } }); if (!blockMenu) { return; } blockMenu.reDraw(); } private createTextBlock(moduleName: string, content: string): EntryBlockRegisterSchema { const blockName = `${moduleName}_${Math.random()}`; const block: EntryBlock = { color: EntryStatic.colorSet.common.TRANSPARENT, skeleton: 'basic_text', class: moduleName, template: '%1', params: [ { type: 'Text', text: content, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: blockName, }, isNotFor: [moduleName], events: {}, }; return { blockName, block }; } /** * TODO 리로드 되는 경우 다시 불러오지 않기 때문에 템플릿정보 저장이 필요함 */ private setLanguageTemplates(moduleObject: EntryHardwareBlockModule) { if (moduleObject.setLanguage) { const langTemplate = moduleObject.setLanguage(); const data = langTemplate[Lang.type] || langTemplate[Lang.fallbackType]; for (const key in data) { Object.assign(Lang[key], data[key]); } } } /** * 블록 모델이 블록객체로서 구현되기 전에 불충분한 프로퍼티나 잘못된 값이 있는 경우 이쪽에서 수정한다. */ private applyDefaultProperties({ blockName, block }: EntryBlockRegisterSchema) { if (!block.color) { block.color = EntryStatic.colorSet.block.default.EXPANSION; block.outerLine = EntryStatic.colorSet.block.darken.EXPANSION; } if (!block.type) { block.type = blockName; } } } const instance = new EntryModuleLoader(); export default instance; Entry.moduleManager = instance; /** * 프로젝트 가 외부 모듈이 사용되었는지 확인하고, 로드한다 * @param {*} project 엔트리 프로젝트 * @return Promise */ Entry.loadExternalModules = async (project = {}) => { const { externalModules = [] } = project; await Promise.all(externalModules.map(instance.loadModuleFromLocalOrOnline.bind(instance))); }; Entry.loadLiteExternalModules = async (project = {}) => { const { externalModulesLite = [] } = project; Entry.externalModulesLite = externalModulesLite; await Promise.all(externalModulesLite.map(instance.registerHardwareLiteModule.bind(instance))); }; /** * 개발용 코드, path를 통해서 블럭을 로딩할수 있음. * @param path */ Entry.loadLiteTestModule = async (file: File, name: string) => { const result = await file.text(); await Entry.moduleManager.loadScript(name, result, true); // Entry.moduleManager.registerHardwareLiteModule(name); }; Entry.loadLiteTestModuleUploader = () => { const headerBtns = document.querySelector('section'); const fileInput = document.createElement('input'); fileInput.type = 'file'; const nameInput = document.createElement('input'); nameInput.type = 'text'; const loadButton = document.createElement('button'); loadButton.innerText = '적용'; const handleUpdate = async () => { const file = fileInput.files[0]; fileInput.value = null; await Entry.loadLiteTestModule(file, nameInput.value); }; loadButton.onclick = handleUpdate; headerBtns.prepend(loadButton); headerBtns.prepend(fileInput); headerBtns.prepend(nameInput); }; ================================================ FILE: src/class/function.js ================================================ import _truncate from 'lodash/truncate'; import _trim from 'lodash/trim'; import _cloneDeep from 'lodash/cloneDeep'; import _find from 'lodash/find'; class EntryFunc { static isEdit = false; static threads = {}; constructor(func = {}) { const { type = 'normal', id = Entry.generateHash(), localVariables = [], useLocalVariables = false, } = func; this.id = id; this.type = type; this.localVariables = localVariables; this.useLocalVariables = useLocalVariables; let content; //inspect empty content if (func && func.content && func.content.length > 4) { content = func.content; } let codeType = 'function_create'; if (type === 'value') { codeType = 'function_create_value'; } this.content = content ? new Entry.Code(content) : new Entry.Code([ [ { type: codeType, copyable: false, deletable: false, x: 40, y: 40, }, ], ]); this.block = null; this.blockMenuBlock = null; this.hashMap = {}; this.paramMap = {}; EntryFunc._generateFunctionSchema(this.id, type); if (func && func.content) { const blockMap = this.content._blockMap; for (const key in blockMap) { EntryFunc.registerParamBlock(blockMap[key].type); } EntryFunc.generateWsBlock(this); } EntryFunc.registerFunction(this); EntryFunc.updateMenu(); } destroy() { this.blockMenuBlock && this.blockMenuBlock.destroy(); } edit() { if (EntryFunc.isEdit) { return; } EntryFunc.isEdit = true; Entry.getMainWS().blockMenu.deleteRendered('variable'); if (!EntryFunc.svg) { EntryFunc.isEdit = EntryFunc.initEditView(); } else { this.parentView.appendChild(this.svg); } } generateBlock() { const generatedInfo = EntryFunc.generateBlock(this); this.block = generatedInfo.block; this.description = generatedInfo.description; } defaultLocalVariable(isForce) { return { name: this.makeLocalVariableName(isForce), value: 0, }; } setLocalVariableLength(length) { if (!this.localVariables) { this.localVariables = []; } if (this.localVariables.length >= length) { this.localVariables.splice(length, this.localVariables.length - length); } else { const max = length - this.localVariables.length; for (let i = 0; i < max; i++) { this.localVariables.push(this.defaultLocalVariable(true)); } } Entry.variableContainer && Entry.variableContainer.updateFuncScrollBar(this); } appendLocalVariable(value) { if (!this.localVariables) { this.localVariables = []; } this.localVariables.push(value); Entry.variableContainer && Entry.variableContainer.updateFuncScrollBar(this); } insertFuncLocalVariable(value, index) { if (!this.localVariables) { this.localVariables = []; } this.localVariables.splice(index, 0, value); Entry.variableContainer && Entry.variableContainer.updateFuncScrollBar(this); } removeLocalVariable(idx) { if (!Array.isArray(this.localVariables)) { return; } if (this.localVariables.length >= idx) { this.localVariables.splice(idx, 1); } Entry.variableContainer && Entry.variableContainer.updateFuncScrollBar(this); } removeLastLocalVariable() { this.removeLocalVariable(this.localVariables.length - 1); } toggleFunctionUseLocalVariables() { this.useLocalVariables = !this.useLocalVariables; Entry.variableContainer && Entry.variableContainer.updateFuncSettingView(this); EntryFunc.updateMenu(); } getLocalVariables() { return this.localVariables; } makeLocalVariableName(isForce) { let name = Lang.Workspace.local_variable; if (this.checkLocalVariableName(name)) { name = Entry.getOrderedName(name, this.localVariables, 'name'); if (!isForce) { Entry.toast.warning( Lang.Workspace.local_variable_rename, Lang.Workspace.local_variable_dup ); } } return name; } checkLocalVariableName(name) { return this.localVariables.some((localVariable) => localVariable.name === name); } changeNameLocalVariable(name, index) { const localVariable = this.localVariables[index]; localVariable.name = name; const { playground } = Entry; if (playground) { playground.blockMenu.deleteRendered('func'); playground.reloadPlayground(); } } getValue(variableId, localVariables) { const localVariable = _find( localVariables || this.localVariables, (localVariable) => localVariable.id === variableId ); return localVariable?.value || 0; } setValue(value, variableId, localVariables) { const localVariable = _find( localVariables || this.localVariables, (localVariable) => localVariable.id === variableId ); localVariable.value = value; } getBlockById(blockId) { return this?.content?.findById(blockId); } getFuncBlockByFuncId(funcId) { return this?.content?.findByType(funcId); } getBlockByParamId(paramId) { return this?.content?.findByParamId(paramId); } static changeFunctionName(name) { Entry.Mutator.mutate( 'function_name', { template: `${Lang.Workspace.func}: ${_trim( _truncate(name, { length: 20, }) )}`, }, { type: 'noChange', isRestore: undefined } ); } static initBlock(blockMenu) { blockMenu.banClass('functionEdit', true); blockMenu.banClass('useLocalVariables', true); this.changeFunctionName(''); } static registerFunction(func) { const workspace = Entry && Entry.getMainWS(); if (!workspace) { return; } const blockMenu = workspace.getBlockMenu(); const menuCode = blockMenu.code; let index = undefined; if (this._fieldLabel) { index = menuCode.getThreadIndex(this._fieldLabel.thread); } this._targetFuncBlock = menuCode.createThread( [ { type: `func_${func.id}`, category: 'func', x: -9999, }, ], index ); func.blockMenuBlock = this._targetFuncBlock; } static clearThreads() { this.threads = {}; } static edit(func) { let funcElement = func; if (typeof func === 'string') { funcElement = Entry.variableContainer.getFunction(/(func_)?(.*)/.exec(func)[2]); } if (!funcElement) { console.error('no function'); return; } this.unbindFuncChangeEvent(); this.unbindWorkspaceStateChangeEvent(); this.cancelEdit(); this.targetFunc = funcElement; EntryFunc.isEdit = true; Entry.getMainWS().blockMenu.deleteRendered('variable'); if (this.initEditView(funcElement.content) === false) { EntryFunc.isEdit = false; return; } // edit fail this.bindFuncChangeEvent(funcElement); this.updateMenu(); requestAnimationFrame(() => { const schema = Entry.block[`func_${funcElement.id}`]; if (schema && schema.paramsBackupEvent) { schema.paramsBackupEvent.notify(); } this._backupContent = funcElement.content.stringify(); this._backupOption = { type: funcElement.type, useLocalVariables: funcElement.useLocalVariables, localVariables: _cloneDeep(funcElement.localVariables), }; Entry.getMainWS().overlayBoard.reDraw(); }); } static initEditView(content) { if (this.targetFunc) { const defBlock = this.targetFunc.content.getEventMap('funcDef')[0]; if (defBlock) { let outputBlock = defBlock.params[0]; let functionNmaeTemplate = ''; let booleanIndex = 0; let stringIndex = 0; while (outputBlock) { const value = outputBlock.params[0]; const valueType = value.type; switch (outputBlock.type) { case 'function_field_label': functionNmaeTemplate = `${functionNmaeTemplate} ${value}`; break; case 'function_field_boolean': booleanIndex++; // eslint-disable-next-line max-len functionNmaeTemplate += ` <${Lang.Blocks.FUNCTION_logical_variable} ${booleanIndex}>`; break; case 'function_field_string': stringIndex++; // eslint-disable-next-line max-len functionNmaeTemplate += ` (${Lang.Blocks.FUNCTION_character_variable} ${stringIndex})`; break; } outputBlock = outputBlock.getOutputBlock(); } this.changeFunctionName(functionNmaeTemplate); } } if (!this.menuCode) { this.setupMenuCode(); } const workspace = Entry.getMainWS(); if (workspace.setMode(Entry.Workspace.MODE_OVERLAYBOARD) === false) { this.endEdit('cancelEdit'); return false; } workspace.changeOverlayBoardCode(content); this._workspaceStateEvent = workspace.changeEvent.attach(this, (message = 'cancelEdit') => { this.endEdit(message); if (workspace.getMode() === Entry.Workspace.MODE_VIMBOARD) { workspace.blockMenu.banClass('functionInit'); } }); content.board.alignThreads(); return true; } static endEdit(message) { this.unbindFuncChangeEvent(); this.unbindWorkspaceStateChangeEvent(); const targetFuncId = this.targetFunc.id; if (this.targetFunc && this.targetFunc.content) { this.targetFunc.content.destroyView(); } switch (message) { case 'save': this.save(); break; case 'cancelEdit': this.cancelEdit(); break; } this._backupContent = null; this._backupOption = null; delete this.targetFunc; EntryFunc.isEdit = false; const workspace = Entry.getMainWS(); const blockMenu = workspace.getBlockMenu(); blockMenu.deleteRendered('variable'); const blockSchema = Entry.block[`func_${targetFuncId}`]; if (blockSchema && blockSchema.destroyParamsBackupEvent) { blockSchema.destroyParamsBackupEvent.notify(); } this.updateMenu(); } static save() { this.targetFunc.generateBlock(true); Entry.variableContainer.saveFunction(this.targetFunc); this._restoreBoardToVimBoard(); } static cancelEdit() { if (!this.targetFunc) { return; } if (!this.targetFunc.block) { this._targetFuncBlock.destroy(); delete Entry.variableContainer.functions_[this.targetFunc.id]; delete Entry.variableContainer.selected; } else { if (this._backupContent) { this.targetFunc.content.load(this._backupContent); this.targetFunc.useLocalVariables = this._backupOption.useLocalVariables; this.targetFunc.localVariables = this._backupOption.localVariables; this.changeType(this.targetFunc, this._backupOption.type); this._generateFunctionSchema(this.targetFunc.id); this.generateWsBlock(this.targetFunc); } } Entry.variableContainer.updateList(); this._restoreBoardToVimBoard(); } static setupMenuCode() { const workspace = Entry.getMainWS(); if (!workspace) { return; } const blockMenu = workspace.getBlockMenu(); const menuCode = blockMenu.code; const CATEGORY = 'func'; this._fieldLabel = menuCode .createThread([ { type: 'function_field_label', copyable: false, category: CATEGORY, x: -9999, }, ]) .getFirstBlock(); this._fieldString = menuCode .createThread([ { type: 'function_field_string', category: CATEGORY, x: -9999, copyable: false, assemble: false, params: [{ type: this.requestParamBlock('string') }], }, ]) .getFirstBlock(); this._fieldBoolean = menuCode .createThread([ { type: 'function_field_boolean', copyable: false, assemble: false, category: CATEGORY, x: -9999, params: [{ type: this.requestParamBlock('boolean') }], }, ]) .getFirstBlock(); this.menuCode = menuCode; // TODO Destroy 혹은 cleanProject 같은 로직이 동작했을때 삭제 필요 blockMenu.align(); } static refreshMenuCode() { if (!Entry.playground.mainWorkspace) { return; } if (!this.menuCode) { this.setupMenuCode(); } this._fieldString.params[0].changeType(this.requestParamBlock('string')); this._fieldBoolean.params[0].changeType(this.requestParamBlock('boolean')); } static requestParamBlock(type) { let blockPrototype; switch (type) { case 'string': blockPrototype = Entry.block.function_param_string; break; case 'boolean': blockPrototype = Entry.block.function_param_boolean; break; default: return null; } const blockType = `${type}Param_${Entry.generateHash()}`; Entry.block[blockType] = EntryFunc.createParamBlock(blockType, blockPrototype, type); return blockType; } static registerParamBlock(type) { if (!type) { return; } let blockPrototype; if (type.indexOf('stringParam') > -1) { blockPrototype = Entry.block.function_param_string; } else if (type.indexOf('booleanParam') > -1) { blockPrototype = Entry.block.function_param_boolean; } //not a function param block if (!blockPrototype) { return; } EntryFunc.createParamBlock(type, blockPrototype, type); } static createParamBlock(type, blockPrototype, originalType) { const originalTypeFullName = /string/gi.test(originalType) ? 'function_param_string' : 'function_param_boolean'; let BlockSchema = function () {}; BlockSchema.prototype = blockPrototype; BlockSchema = new BlockSchema(); BlockSchema.changeEvent = new Entry.Event(); BlockSchema.template = Lang.template[originalTypeFullName]; BlockSchema.fontColor = blockPrototype.fontColor || '#FFF'; Entry.block[type] = BlockSchema; return BlockSchema; } static updateMenu() { const workspace = Entry.getMainWS(); if (!workspace) { return; } const blockMenu = workspace.getBlockMenu(); if (this.targetFunc) { !this.menuCode && this.setupMenuCode(); blockMenu.banClass('functionInit', true); blockMenu.unbanClass('functionEdit', true); if (this.targetFunc && this.targetFunc.useLocalVariables) { blockMenu.unbanClass('useLocalVariables', true); } else { blockMenu.banClass('useLocalVariables', true); } Entry.variableContainer && Entry.variableContainer.updateFuncSettingView(this.targetFunc); } else { !workspace.isVimMode() && blockMenu.unbanClass('functionInit', true); blockMenu.banClass('functionEdit', true); blockMenu.banClass('useLocalVariables', true); } blockMenu.lastSelector === 'func' && blockMenu.align(); } static generateBlock(func) { const blockSchema = Entry.block[`func_${func.id}`]; const block = { template: blockSchema.template, params: blockSchema.params, }; const reg = /(%\d)/im; const templateParams = blockSchema.template.split(reg); let description = ''; let booleanIndex = 0; let stringIndex = 0; for (const i in templateParams) { const templateChunk = templateParams[i]; if (reg.test(templateChunk)) { const paramIndex = Number(templateChunk.split('%')[1]) - 1; const param = blockSchema.params[paramIndex]; if (param.accept === 'boolean') { description += Lang.template.function_param_boolean + (booleanIndex ? booleanIndex : ''); booleanIndex++; } else if (param.type !== 'Indicator') { description += Lang.template.function_param_string + (stringIndex ? stringIndex : ''); stringIndex++; } } else { description += templateChunk; } } return { block, description }; } static generateWsBlock(target, isRestore) { this.unbindFuncChangeEvent(); const targetFunc = target ? target : this.targetFunc; const defBlock = targetFunc.content.getEventMap('funcDef')[0]; if (!defBlock) { return; } let outputBlock = defBlock.params[0]; let booleanIndex = 0; let stringIndex = 0; const schemaParams = []; let schemaTemplate = ''; let functionNmaeTemplate = ''; const hashMap = targetFunc.hashMap; const paramMap = targetFunc.paramMap; const blockIds = []; while (outputBlock) { const value = outputBlock.params[0]; const valueType = value.type; switch (outputBlock.type) { case 'function_field_label': schemaTemplate = `${schemaTemplate} ${value}`; functionNmaeTemplate = `${functionNmaeTemplate} ${value}`; break; case 'function_field_boolean': Entry.Mutator.mutate(valueType, { template: `${Lang.Blocks.FUNCTION_logical_variable} ${booleanIndex + 1}`, }); hashMap[valueType] = false; paramMap[valueType] = booleanIndex + stringIndex; booleanIndex++; schemaParams.push({ type: 'Block', accept: 'boolean', }); schemaTemplate += ` %${booleanIndex + stringIndex}`; // eslint-disable-next-line max-len functionNmaeTemplate += ` <${Lang.Blocks.FUNCTION_logical_variable} ${booleanIndex}>`; blockIds.push(outputBlock.id); break; case 'function_field_string': Entry.Mutator.mutate(valueType, { template: `${Lang.Blocks.FUNCTION_character_variable} ${stringIndex + 1}`, }); hashMap[valueType] = false; paramMap[valueType] = booleanIndex + stringIndex; stringIndex++; schemaTemplate += ` %${booleanIndex + stringIndex}`; // eslint-disable-next-line max-len functionNmaeTemplate += ` (${Lang.Blocks.FUNCTION_character_variable} ${stringIndex})`; schemaParams.push({ type: 'Block', accept: 'string', }); blockIds.push(outputBlock.id); break; } outputBlock = outputBlock.getOutputBlock(); } this.changeFunctionName(functionNmaeTemplate); if (targetFunc.type !== 'value') { schemaTemplate += ` %${booleanIndex + stringIndex + 1}`; schemaParams.push({ type: 'Indicator', img: 'block_icon/func_icon.svg', size: 12, }); } const funcName = `func_${targetFunc.id}`; const block = Entry.block[funcName]; const originParams = block.params.slice(0, block.params.length - 1); const newParams = schemaParams.slice(0, schemaParams.length - 1); const originParamsLength = originParams.length; const newParamsLength = newParams.length; let changeData = {}; if (newParamsLength > originParamsLength) { const outputBlockIds = targetFunc.outputBlockIds; if (outputBlockIds) { let startPos = 0; while (outputBlockIds[startPos] === blockIds[startPos]) { if (!outputBlockIds[startPos]) { break; } startPos++; } let endPos = 0; while ( outputBlockIds[outputBlockIds.length - endPos - 1] === blockIds[blockIds.length - endPos - 1] ) { if (!outputBlockIds[outputBlockIds.length - endPos - 1]) { break; } endPos++; } endPos = blockIds.length - endPos - 1; changeData = { type: 'insert', startPos, endPos, }; } } else if (newParamsLength < originParamsLength) { changeData = { type: 'cut', pos: newParamsLength, }; } else { changeData = { type: 'noChange' }; } changeData.isRestore = isRestore; targetFunc.outputBlockIds = blockIds; Entry.Mutator.mutate( funcName, { params: schemaParams, template: schemaTemplate, }, changeData ); for (const key in hashMap) { const state = hashMap[key]; if (state) { const text = /string/.test(key) ? Lang.Blocks.FUNCTION_character_variable : Lang.Blocks.FUNCTION_logical_variable; Entry.Mutator.mutate(key, { template: text }); } else { hashMap[key] = true; } } this.bindFuncChangeEvent(targetFunc); } static bindFuncChangeEvent(targetFunc) { const selectedTargetFunc = targetFunc ? targetFunc : this.targetFunc; if (!this._funcChangeEvent && selectedTargetFunc.content.getEventMap('funcDef')[0].view) { this._funcChangeEvent = selectedTargetFunc.content .getEventMap('funcDef')[0] .view._contents[1].changeEvent.attach(this, this.generateWsBlock); } } static unbindFuncChangeEvent() { if (!this._funcChangeEvent) { return; } this._funcChangeEvent.destroy(); delete this._funcChangeEvent; } static unbindWorkspaceStateChangeEvent() { const event = this._workspaceStateEvent; if (!event) { return; } event.destroy(); delete this._workspaceStateEvent; } static reset() { if (this.isEdit) { this.endEdit(); } this.menuCode = undefined; } static changeType(func, type = 'normal') { func.destroy(); func.type = type; delete func.block; delete func.blockMenuBlock; EntryFunc._generateFunctionSchema(func.id, type, true); const tempContent = func.content.toJSON(); if (func && func.content) { const blockMap = func.content._blockMap; for (const key in blockMap) { EntryFunc.registerParamBlock(blockMap[key].type); } } const blockType = type === 'normal' ? 'function_create' : 'function_create_value'; let block; func.content.getThreads().some((thread, idx) => { const target = thread.getFirstBlock(); if ( target instanceof Entry.Block && ['function_create_value', 'function_create'].includes(target?.type) ) { tempContent[idx][0].type = blockType; block = target; return true; } }); block.changeType(blockType); func.content = new Entry.Code(tempContent); const workspace = Entry.getMainWS(); workspace.changeOverlayBoardCode(func.content); func.block = block; Entry.variableContainer.updateList(); EntryFunc.registerFunction(func); EntryFunc.generateWsBlock(func, true); EntryFunc.updateMenu(); // reDrawVariableContainer() // b = Entry.variableContainer.getFunction(/(func_)?(.*)/.exec('0q91')[2]); // Entry.Func.changeType(b, 'value') } static _generateFunctionSchema(functionId, type = 'normal', isUpdate) { const prefixedFunctionId = `func_${functionId}`; if (!isUpdate && Entry.block[prefixedFunctionId]) { return; } let BlockSchema = function () {}; BlockSchema.prototype = Entry.block.function_general; if (type === 'value') { BlockSchema.prototype = Entry.block.function_value; } BlockSchema = new BlockSchema(); BlockSchema.changeEvent = new Entry.Event(); BlockSchema.template = Lang.template.function_general; if (type === 'value') { BlockSchema.template = Lang.template.function_value; } Entry.block[prefixedFunctionId] = BlockSchema; } /** * 이전 워크스페이스 보드 형태가 VIMBOARD 였던 경우면 VIMBOARD 로 돌린다. * @private */ static _restoreBoardToVimBoard() { const ws = Entry.getMainWS(); if (ws && ws.overlayModefrom === Entry.Workspace.MODE_VIMBOARD) { ws.setMode({ boardType: Entry.Workspace.MODE_VIMBOARD, textType: Entry.Vim.TEXT_TYPE_PY, runType: Entry.Vim.WORKSPACE_MODE, }); Entry.variableContainer.functionAddButton_.addClass('disable'); } } takeSnapshot() { this.snapshot_ = { localVariables: _cloneDeep(this.localVariables), }; } loadSnapshot() { if (!this.snapshot_) { return; } const { localVariables } = this.snapshot_; this.localVariables = localVariables; delete this.snapshot_; } } Entry.Func = EntryFunc; ================================================ FILE: src/class/hardware/bluetoothServices/event-dispatcher.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ import { EventEmitter } from 'events'; /** * @hidden */ export interface TypedDispatcher { addEventListener( type: K, listener: (event: CustomEvent) => void ): void; removeEventListener( type: K, callback: (event: CustomEvent) => void ): void; dispatchEvent(event: CustomEvent): boolean; dispatchEvent(type: K, detail: T[K]): boolean; addListener(event: K, listener: (data: T[K]) => void): this; on(event: K, listener: (data: T[K]) => void): this; once(event: K, listener: (data: T[K]) => void): this; prependListener(event: K, listener: (data: T[K]) => void): this; prependOnceListener(event: K, listener: (data: T[K]) => void): this; removeListener(event: K, listener: (data: T[K]) => void): this; removeAllListeners(event?: K): this; // tslint:disable-next-line:ban-types listeners(event: K): Function[]; emit(event: K, data: T[K]): boolean; // tslint:disable-next-line:array-type eventNames(): Array; listenerCount(type: K): number; setMaxListeners(n: number): this; getMaxListeners(): number; } /** * @hidden */ export class EventDispatcher extends EventEmitter implements EventTarget { private isEventListenerObject = ( listener: EventListenerOrEventListenerObject ): listener is EventListenerObject => (listener as EventListenerObject).handleEvent !== undefined; public addEventListener(type: string, listener: EventListenerOrEventListenerObject | null) { if (listener) { const handler = this.isEventListenerObject(listener) ? listener.handleEvent : listener; super.addListener(type, handler); } } public removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null) { if (callback) { const handler = this.isEventListenerObject(callback) ? callback.handleEvent : callback; super.removeListener(type, handler); } } public dispatchEvent(event: Event): boolean; public dispatchEvent(type: string, detail: T): boolean; public dispatchEvent(eventOrType: Event | string, detail?: T): boolean { let event: Event; if (typeof eventOrType === 'string') { event = new CustomEvent(eventOrType, { detail, }); } else { event = eventOrType; } return super.emit(event.type, event); } } ================================================ FILE: src/class/hardware/bluetoothServices/index.ts ================================================ // 사용하는 서비스 정리 import { AccelerometerService } from './services/accelerometer'; import { ButtonService } from './services/button'; import { DeviceInformationService } from './services/device-information'; import { DfuControlService } from './services/dfu-control'; import { EventService } from './services/event'; import { IoPinService } from './services/io-pin'; import { LedService } from './services/led'; import { MagnetometerService } from './services/magnetometer'; import { TemperatureService } from './services/temperature'; import { UartService } from './services/uart'; export const getServiceClassesByModuleId = (moduleId: string) => { switch (moduleId) { case '220302': { // INFO : entryjs minify 과정에서 function.name 값이 uglify되는 이슈 대응 return [ DeviceInformationService, ButtonService, LedService, TemperatureService, AccelerometerService, MagnetometerService, UartService, EventService, DfuControlService, IoPinService, ]; } break; } }; ================================================ FILE: src/class/hardware/bluetoothServices/promise-queue.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ /** * @hidden */ interface QueuedPromise { fn: () => Promise; resolve: (value?: any | PromiseLike | undefined) => void; reject: (reason?: any) => void; } /** * @hidden */ export class PromiseQueue { private queue: QueuedPromise[] = []; private running = 0; constructor(private concurrent = 1) {} private async pump(): Promise { if (this.running >= this.concurrent) { return; } const promise = this.queue.shift(); if (!promise) { return; } this.running++; try { const result = await promise.fn(); promise.resolve(result); } catch (error) { promise.reject(error); } this.running--; return this.pump(); } public add(fn: () => Promise): Promise { return new Promise((resolve, reject) => { this.queue.push({ fn, resolve, reject, }); return this.pump(); }); } } ================================================ FILE: src/class/hardware/bluetoothServices/service-helper.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ import { EventEmitter } from 'events'; import { PromiseQueue } from './promise-queue'; /** * @hidden */ export interface ServiceEventHandler { characteristic: BluetoothCharacteristicUUID; handler: (event: Event) => void; } /** * @hidden */ export class ServiceHelper { private static queue = new PromiseQueue(); private characteristics?: BluetoothRemoteGATTCharacteristic[]; constructor(private service: BluetoothRemoteGATTService, private emitter?: EventEmitter) {} private async getCharacteristic( uuid: BluetoothCharacteristicUUID ): Promise { if (!this.characteristics) { this.characteristics = await this.service.getCharacteristics(); } return this.characteristics.find((characteristic) => characteristic.uuid === uuid); } public async getCharacteristicValue(uuid: BluetoothCharacteristicUUID): Promise { const characteristic = await this.getCharacteristic(uuid); if (!characteristic) { throw new Error('Unable to locate characteristic'); } return await ServiceHelper.queue.add(async () => characteristic.readValue()); } public async setCharacteristicValue( uuid: BluetoothCharacteristicUUID, value: BufferSource ): Promise { const characteristic = await this.getCharacteristic(uuid); if (!characteristic) { throw new Error('Unable to locate characteristic'); } await ServiceHelper.queue.add(async () => characteristic.writeValue(value)); } public async handleListener( event: string, uuid: BluetoothCharacteristicUUID, handler: (event: Event) => void ) { const characteristic = await this.getCharacteristic(uuid); if (!characteristic) { return; } await ServiceHelper.queue.add(async () => characteristic.startNotifications()); this.emitter!.on('newListener', (emitterEvent: string) => { if (emitterEvent !== event || this.emitter!.listenerCount(event) > 0) { return; } return ServiceHelper.queue.add(async () => characteristic.addEventListener('characteristicvaluechanged', handler) ); }); this.emitter!.on('removeListener', (emitterEvent: string) => { if (emitterEvent !== event || this.emitter!.listenerCount(event) > 0) { return; } return ServiceHelper.queue.add(async () => characteristic.removeEventListener('characteristicvaluechanged', handler) ); }); } } ================================================ FILE: src/class/hardware/bluetoothServices/services/accelerometer.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ import { EventDispatcher, TypedDispatcher } from '../event-dispatcher'; import { ServiceHelper } from '../service-helper'; /** * @hidden */ export enum AccelerometerCharacteristic { accelerometerData = 'e95dca4b-251d-470a-a062-fa1922dfa9a8', accelerometerPeriod = 'e95dfb24-251d-470a-a062-fa1922dfa9a8', } /** * Data received from the accelerometer */ export interface AccelerometerData { /** * Force in direction X */ x: number; /** * Force in direction Y */ y: number; /** * Force in direction Z */ z: number; } /** * The sample period to read accelerometer data (milliseconds) */ export type AccelerometerPeriod = 1 | 2 | 5 | 10 | 20 | 80 | 160 | 640; /** * Events raised by the accelerometer service */ export interface AccelerometerEvents { /** * @hidden */ newListener: keyof AccelerometerEvents; /** * @hidden */ removeListener: keyof AccelerometerEvents; /** * Accelerometer data changed event */ accelerometerdatachanged: AccelerometerData; } /** * Accelerometer Service */ export class AccelerometerService extends (EventDispatcher as new () => TypedDispatcher< AccelerometerEvents >) { public static serviceName = 'AccelerometerService'; /** * @hidden */ public static uuid = 'e95d0753-251d-470a-a062-fa1922dfa9a8'; /** * @hidden */ public static async create(service: BluetoothRemoteGATTService): Promise { const bluetoothService = new AccelerometerService(service); await bluetoothService.init(); return bluetoothService; } private helper: ServiceHelper; /** * @hidden */ constructor(service: BluetoothRemoteGATTService) { super(); //@ts-ignore this.helper = new ServiceHelper(service, this); } private async init() { await this.helper.handleListener( 'accelerometerdatachanged', AccelerometerCharacteristic.accelerometerData, this.accelerometerDataChangedHandler.bind(this) ); } /** * Read acceleromter data */ public async readAccelerometerData(): Promise { const view = await this.helper.getCharacteristicValue( AccelerometerCharacteristic.accelerometerData ); return this.dataViewToAccelerometerData(view); } /** * Get accelerometer sample period */ public async getAccelerometerPeriod(): Promise { const view = await this.helper.getCharacteristicValue( AccelerometerCharacteristic.accelerometerPeriod ); return view.getUint16(0, true) as AccelerometerPeriod; } /** * Set accelerometer sample period * @param frequency The frequency interval to use */ public async setAccelerometerPeriod(frequency: AccelerometerPeriod): Promise { const view = new DataView(new ArrayBuffer(2)); view.setUint16(0, frequency, true); return this.helper.setCharacteristicValue( AccelerometerCharacteristic.accelerometerPeriod, view ); } private accelerometerDataChangedHandler(event: Event) { const view = (event.target as BluetoothRemoteGATTCharacteristic).value!; const value = this.dataViewToAccelerometerData(view); this.dispatchEvent('accelerometerdatachanged', value); } private dataViewToAccelerometerData(view: DataView): AccelerometerData { return { x: view.getInt16(0, true) / 1000.0, y: view.getInt16(2, true) / 1000.0, z: view.getInt16(4, true) / 1000.0, }; } } ================================================ FILE: src/class/hardware/bluetoothServices/services/button.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ import { EventDispatcher, TypedDispatcher } from '../event-dispatcher'; import { ServiceHelper } from '../service-helper'; /** * @hidden */ export enum ButtonCharacteristic { buttonAState = 'e95dda90-251d-470a-a062-fa1922dfa9a8', buttonBState = 'e95dda91-251d-470a-a062-fa1922dfa9a8', } /** * Button state enum */ export enum ButtonState { /** * Button released */ Release = 0, /** * Button pressed - short */ ShortPress = 1, /** * Button pressed - long */ LongPress = 2, } /** * Events raised by the button service */ export interface ButtonEvents { /** * @hidden */ newListener: keyof ButtonEvents; /** * @hidden */ removeListener: keyof ButtonEvents; /** * Button A state changed event */ buttonastatechanged: ButtonState; /** * Button B state changed event */ buttonbstatechanged: ButtonState; } /** * Button Service */ export class ButtonService extends (EventDispatcher as new () => TypedDispatcher) { public static serviceName = 'ButtonService'; /** * @hidden */ public static uuid = 'e95d9882-251d-470a-a062-fa1922dfa9a8'; /** * @hidden */ public static async create(service: BluetoothRemoteGATTService): Promise { const bluetoothService = new ButtonService(service); await bluetoothService.init(); return bluetoothService; } private helper: ServiceHelper; /** * @hidden */ constructor(service: BluetoothRemoteGATTService) { super(); //@ts-ignore this.helper = new ServiceHelper(service, this); } private async init() { await this.helper.handleListener( 'buttonastatechanged', ButtonCharacteristic.buttonAState, this.buttonAStateChangedHandler.bind(this) ); await this.helper.handleListener( 'buttonbstatechanged', ButtonCharacteristic.buttonBState, this.buttonBStateChangedHandler.bind(this) ); } /** * Read state of button A */ public async readButtonAState(): Promise { const view = await this.helper.getCharacteristicValue(ButtonCharacteristic.buttonAState); return view.getUint8(0); } /** * Read state of button B */ public async readButtonBState(): Promise { const view = await this.helper.getCharacteristicValue(ButtonCharacteristic.buttonBState); return view.getUint8(0); } private buttonAStateChangedHandler(event: Event) { const view = (event.target as BluetoothRemoteGATTCharacteristic).value!; this.dispatchEvent('buttonastatechanged', view.getUint8(0)); } private buttonBStateChangedHandler(event: Event) { const view = (event.target as BluetoothRemoteGATTCharacteristic).value!; this.dispatchEvent('buttonbstatechanged', view.getUint8(0)); } } ================================================ FILE: src/class/hardware/bluetoothServices/services/device-information.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ import { ServiceHelper } from '../service-helper'; /** * @hidden */ export enum DeviceInformationCharacteristic { modelNumber = '00002a24-0000-1000-8000-00805f9b34fb', serialNumber = '00002a25-0000-1000-8000-00805f9b34fb', firmwareRevision = '00002a26-0000-1000-8000-00805f9b34fb', hardwareRevision = '00002a27-0000-1000-8000-00805f9b34fb', manufacturer = '00002a29-0000-1000-8000-00805f9b34fb', } /** * Device information structure */ export interface DeviceInformation { /** * Model Number */ modelNumber?: string; /** * Serial Number */ serialNumber?: string; /** * Firmware Revision */ firmwareRevision?: string; /** * Hardware Revision */ hardwareRevision?: string; /** * Manufacturer Name */ manufacturer?: string; } /** * Device Information Service */ export class DeviceInformationService { public static serviceName = 'DeviceInformationService'; /** * @hidden */ public static uuid = '0000180a-0000-1000-8000-00805f9b34fb'; /** * @hidden */ public static async create( service: BluetoothRemoteGATTService ): Promise { return new DeviceInformationService(service); } private helper: ServiceHelper; /** * @hidden */ constructor(service: BluetoothRemoteGATTService) { this.helper = new ServiceHelper(service); } /** * Read device information */ public async readDeviceInformation(): Promise { const info: DeviceInformation = {}; const modelNumber = await this.readStringCharacteristic( DeviceInformationCharacteristic.modelNumber ); if (modelNumber) info.modelNumber = modelNumber; const serialNumber = await this.readStringCharacteristic( DeviceInformationCharacteristic.serialNumber ); if (serialNumber) info.serialNumber = serialNumber; const firmwareRevision = await this.readStringCharacteristic( DeviceInformationCharacteristic.firmwareRevision ); if (firmwareRevision) info.firmwareRevision = firmwareRevision; const hardwareRevision = await this.readStringCharacteristic( DeviceInformationCharacteristic.hardwareRevision ); if (hardwareRevision) info.hardwareRevision = hardwareRevision; const manufacturer = await this.readStringCharacteristic( DeviceInformationCharacteristic.manufacturer ); if (manufacturer) info.manufacturer = manufacturer; return info; } private async readStringCharacteristic( uuid: BluetoothCharacteristicUUID ): Promise { try { const view = await this.helper.getCharacteristicValue(uuid); const buffer = view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength); return String.fromCharCode.apply(null, Array.from(new Uint8Array(buffer))); } catch (_e) { return undefined; } } } ================================================ FILE: src/class/hardware/bluetoothServices/services/dfu-control.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ import { ServiceHelper } from '../service-helper'; /** * @hidden */ export enum DfuCharacteristic { dfuControl = 'e95d93b1-251d-470a-a062-fa1922dfa9a8', } /** * @hidden */ export class DfuControlService { public static serviceName = 'DfuControlService'; /** * @hidden */ public static uuid = 'e95d93b0-251d-470a-a062-fa1922dfa9a8'; /** * @hidden */ public static async create(service: BluetoothRemoteGATTService): Promise { return new DfuControlService(service); } /** * @hidden */ public helper: ServiceHelper; /** * @hidden */ constructor(service: BluetoothRemoteGATTService) { this.helper = new ServiceHelper(service); } /** * Request device switches to DFU mode */ public requestDfu(): Promise { return this.helper.setCharacteristicValue( DfuCharacteristic.dfuControl, new Uint8Array([1]) ); } /** * Request flash code */ public requestFlashCode(): Promise { return this.helper.setCharacteristicValue( DfuCharacteristic.dfuControl, new Uint8Array([2]) ); } } ================================================ FILE: src/class/hardware/bluetoothServices/services/event.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ import { EventDispatcher, TypedDispatcher } from '../event-dispatcher'; import { ServiceHelper } from '../service-helper'; /** * @hidden */ export enum EventCharacteristic { microBitRequirements = 'e95db84c-251d-470a-a062-fa1922dfa9a8', microBitEvent = 'e95d9775-251d-470a-a062-fa1922dfa9a8', clientRequirements = 'e95d23c4-251d-470a-a062-fa1922dfa9a8', clientEvent = 'e95d5404-251d-470a-a062-fa1922dfa9a8', } /** * micro:bit event */ export interface MicrobitEvent { /** * The type of event */ type: number; /** * The value for the event */ value: number; } /** * Events raised by the event service */ export interface MicrobitEvents { /** * @hidden */ newListener: keyof MicrobitEvents; /** * @hidden */ removeListener: keyof MicrobitEvents; /** * micro:bit requirements changed event */ microbitrequirementschanged: MicrobitEvent; /** * micro:bit event event */ microbitevent: MicrobitEvent; } /** * Event Service */ export class EventService extends (EventDispatcher as new () => TypedDispatcher) { public static serviceName = 'EventService'; /** * @hidden */ public static uuid = 'e95d93af-251d-470a-a062-fa1922dfa9a8'; /** * @hidden */ public static async create(service: BluetoothRemoteGATTService): Promise { const bluetoothService = new EventService(service); await bluetoothService.init(); return bluetoothService; } private helper: ServiceHelper; /** * @hidden */ constructor(service: BluetoothRemoteGATTService) { super(); //@ts-ignore this.helper = new ServiceHelper(service, this); } private async init() { await this.helper.handleListener( 'microbitevent', EventCharacteristic.microBitEvent, this.eventHandler.bind(this) ); await this.helper.handleListener( 'microbitrequirementschanged', EventCharacteristic.microBitRequirements, this.microbitRequirementsChangedHandler.bind(this) ); } /** * Get micro:bit event requirements */ public async getMicrobitRequirements(): Promise { const view = await this.helper.getCharacteristicValue( EventCharacteristic.microBitRequirements ); return this.viewToMicrobitEvent(view); } /** * Set client event requirements * @param type The type of event to set * @param value The value to set */ public async setClientRequirements(type: number, value: number): Promise { const view = new DataView(new ArrayBuffer(4)); view.setUint16(0, type, true); view.setUint16(1, value, true); return await this.helper.setCharacteristicValue( EventCharacteristic.clientRequirements, view ); } /** * Read micro:bit event */ public async readMicrobitEvent(): Promise { const view = await this.helper.getCharacteristicValue(EventCharacteristic.microBitEvent); return this.viewToMicrobitEvent(view); } /** * Write client event * @param type The event type * @param value The event value */ public async writeClientEvent(type: number, value: number): Promise { const view = new DataView(new ArrayBuffer(4)); view.setUint16(0, type, true); view.setUint16(1, value, true); return await this.helper.setCharacteristicValue(EventCharacteristic.clientEvent, view); } private microbitRequirementsChangedHandler(event: Event) { const view = (event.target as BluetoothRemoteGATTCharacteristic).value!; const microbitEvent = this.viewToMicrobitEvent(view); this.dispatchEvent('microbitrequirementschanged', microbitEvent); } private eventHandler(event: Event) { const view = (event.target as BluetoothRemoteGATTCharacteristic).value!; const microbitEvent = this.viewToMicrobitEvent(view); this.dispatchEvent('microbitevent', microbitEvent); } private viewToMicrobitEvent(view: DataView): MicrobitEvent { const type = view.getUint16(0, true); const value = view.getUint16(1, true); return { type, value, }; } } ================================================ FILE: src/class/hardware/bluetoothServices/services/io-pin.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ import { ServiceHelper } from '../service-helper'; import { EventDispatcher, TypedDispatcher } from '../event-dispatcher'; /** * @hidden */ export enum IoPinCharacteristic { pinData = 'e95d8d00-251d-470a-a062-fa1922dfa9a8', pinAdConfiguration = 'e95d5899-251d-470a-a062-fa1922dfa9a8', pinIoConfiguration = 'e95db9fe-251d-470a-a062-fa1922dfa9a8', pwmControl = 'e95dd822-251d-470a-a062-fa1922dfa9a8', } const littleEndian = true; /** * Pin data */ export interface PinData { /** * Pin number */ pin: number; /** * Pin value */ value: number; } /** * PWM control data */ export interface PwmControlData { /** * Pin number */ pin: number; /** * Pin value */ value: number; /** * Period (in microseconds) */ period: number; } /** * Analogue/Digital Enum */ export enum AD { Digital = 0, Analogue = 1, } /** * Input/Output Enum */ export enum IO { Output = 0, Input = 1, } /** * Events raised by the magnetometer service */ export interface IoPinEvents { /** * @hidden */ newListener: keyof IoPinEvents; /** * @hidden */ removeListener: keyof IoPinEvents; /** * Pin data changed event */ pindatachanged: PinData[]; } /** * @hidden */ export class IoPinService extends (EventDispatcher as new () => TypedDispatcher) { public static serviceName = 'IoPinService'; /** * @hidden */ public static uuid = 'e95d127b-251d-470a-a062-fa1922dfa9a8'; /** * @hidden */ public static async create(service: BluetoothRemoteGATTService): Promise { const bluetoothService = new IoPinService(service); await bluetoothService.init(); return bluetoothService; } /** * @hidden */ public helper: ServiceHelper; /** * @hidden */ constructor(service: BluetoothRemoteGATTService) { super(); //@ts-ignore this.helper = new ServiceHelper(service, this); } private async init() { await this.helper.handleListener( 'pindatachanged', IoPinCharacteristic.pinData, this.pinDataChangedHandler.bind(this) ); } /** * Read pin data */ public async readPinData(): Promise { const view = await this.helper.getCharacteristicValue(IoPinCharacteristic.pinData); return this.dataViewToPinData(view); } /** * Write pin data * @param data The pin data to write */ public async writePinData(data: PinData[]): Promise { const view = this.pinDataToDataView(data); return this.helper.setCharacteristicValue(IoPinCharacteristic.pinData, view); } /** * Get pin analogue/digital configuration */ public async getAdConfiguration(): Promise { const view = await this.helper.getCharacteristicValue( IoPinCharacteristic.pinAdConfiguration ); return this.dataViewToConfig(view); } /** * Set pin analogue/digital configuration * @param config The analogue/digital configuration to set */ public async setAdConfiguration(config: AD[]): Promise { const view = this.configToDataView(config); return this.helper.setCharacteristicValue(IoPinCharacteristic.pinAdConfiguration, view); } /** * Get pin input/output configuration */ public async getIoConfiguration(): Promise { const view = await this.helper.getCharacteristicValue( IoPinCharacteristic.pinIoConfiguration ); return this.dataViewToConfig(view); } /** * Set pin input/output configuration * @param config The input/output configuration to set */ public async setIoConfiguration(config: IO[]): Promise { const view = this.configToDataView(config); return this.helper.setCharacteristicValue(IoPinCharacteristic.pinIoConfiguration, view); } /** * Set pin PWM control * @param data The PWM control data to set */ public async setPwmControl(data: PwmControlData): Promise { const view = this.pwmControlDataToDataView(data); return this.helper.setCharacteristicValue(IoPinCharacteristic.pwmControl, view); } private pinDataChangedHandler(event: Event) { const view = (event.target as BluetoothRemoteGATTCharacteristic).value!; const value = this.dataViewToPinData(view); this.dispatchEvent('pindatachanged', value); } private dataViewToPinData(view: DataView): PinData[] { const data = []; for (let i = 0; i < view.byteLength; i += 2) { data.push({ pin: view.getUint8(i), value: view.getUint8(i + 1), }); } return data; } private pinDataToDataView(data: PinData[]): DataView { const view = new DataView(new ArrayBuffer(data.length * 2)); data.forEach((pinData, index) => { view.setUint8(index * 2, pinData.pin); view.setUint8(index * 2 + 1, pinData.value); }); return view; } private dataViewToConfig(view: DataView): number[] { const result: number[] = []; const value = (view.getUint16(0) << 8) + view.getUint8(2); for (let i = 0; i < 24; i++) { result.push(value >> i); } return result; } private configToDataView(config: number[]): DataView { const view = new DataView(new ArrayBuffer(3)); let value = 0; // tslint:disable-next-line:prefer-for-of for (let i = 0; i < config.length; i++) { value &= 1 << config[i]; } view.setUint16(0, value >> 8, littleEndian); view.setUint8(2, value & 0xff); return view; } private pwmControlDataToDataView(data: PwmControlData): DataView { const view = new DataView(new ArrayBuffer(7)); view.setUint8(0, data.pin); view.setUint16(1, data.value, littleEndian); view.setUint32(3, data.period, littleEndian); return view; } } ================================================ FILE: src/class/hardware/bluetoothServices/services/led.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ import { ServiceHelper } from '../service-helper'; /** * @hidden */ export enum LedCharacteristic { ledMatrixState = 'e95d7b77-251d-470a-a062-fa1922dfa9a8', ledText = 'e95d93ee-251d-470a-a062-fa1922dfa9a8', scrollingDelay = 'e95d0d2d-251d-470a-a062-fa1922dfa9a8', } /** * LED matrix structure */ export type LedMatrix = [ [boolean, boolean, boolean, boolean, boolean], [boolean, boolean, boolean, boolean, boolean], [boolean, boolean, boolean, boolean, boolean], [boolean, boolean, boolean, boolean, boolean], [boolean, boolean, boolean, boolean, boolean] ]; /** * LED Service */ export class LedService { public static serviceName = 'LedService'; /** * @hidden */ public static uuid = 'e95dd91d-251d-470a-a062-fa1922dfa9a8'; /** * @hidden */ public static async create(service: BluetoothRemoteGATTService): Promise { return new LedService(service); } private helper: ServiceHelper; /** * @hidden */ constructor(service: BluetoothRemoteGATTService) { this.helper = new ServiceHelper(service); } /** * Write text to the LED matrix * @param text Te text to display */ public async writeText(text: string): Promise { const encoded = this.encodeString(text); return this.helper.setCharacteristicValue(LedCharacteristic.ledText, encoded); } /** * Read matrix state */ public async readMatrixState(): Promise { const view = await this.helper.getCharacteristicValue(LedCharacteristic.ledMatrixState); return this.viewToLedMatrix(view); } /** * Write matrix state * @param state The matrix data to set */ public async writeMatrixState(state: LedMatrix): Promise { const view = this.ledMatrixToView(state); return this.helper.setCharacteristicValue(LedCharacteristic.ledMatrixState, view); } /** * Get scrolling delay */ public async getScrollingDelay(): Promise { const view = await this.helper.getCharacteristicValue(LedCharacteristic.scrollingDelay); return view.getUint16(0, true); } /** * Set scrolling delay * @param delay The delay to set (milliseconds) */ public async setScrollingDelay(delay: number): Promise { const view = new DataView(new ArrayBuffer(2)); view.setUint16(0, delay, true); return this.helper.setCharacteristicValue(LedCharacteristic.scrollingDelay, view); } private encodeString(text: string): ArrayBuffer { const buffer = new ArrayBuffer(text.length); const view = new Uint8Array(buffer); for (let i = 0; i < text.length; i++) { view[i] = text.charCodeAt(i); } return buffer; } private viewToLedMatrix(view: DataView): LedMatrix { const matrix: boolean[][] = []; for (let i = 0; i < 5; i++) { matrix[i] = this.byteToBoolArray(view.getUint8(i)); } return matrix as LedMatrix; } private byteToBoolArray(byte: number): boolean[] { const bools = [false, false, false, false, false]; for (let i = 0; i < bools.length; i++) { bools[i] = (byte & 1) === 1; byte >>= 1; } return bools.reverse(); } private ledMatrixToView(matrix: LedMatrix): DataView { const view = new DataView(new ArrayBuffer(5)); for (let i = 0; i < 5; i++) { view.setUint8(i, this.boolArrayToByte(matrix[i])); } return view; } private boolArrayToByte(bools: boolean[]): number { return bools.reduce((byte, bool) => (byte << 1) | (bool ? 1 : 0), 0); } } ================================================ FILE: src/class/hardware/bluetoothServices/services/magnetometer.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ import { EventDispatcher, TypedDispatcher } from '../event-dispatcher'; import { ServiceHelper } from '../service-helper'; /** * @hidden */ export enum MagnetometerCharacteristic { magnetometerData = 'e95dfb11-251d-470a-a062-fa1922dfa9a8', magnetometerPeriod = 'e95d386c-251d-470a-a062-fa1922dfa9a8', magnetometerBearing = 'e95d9715-251d-470a-a062-fa1922dfa9a8', magnetometerCalibration = 'e95db358-251d-470a-a062-fa1922dfa9a8', } /** * Data received from the magnetometer */ export interface MagnetometerData { /** * Force in direction X */ x: number; /** * Force in direction Y */ y: number; /** * Force in direction Z */ z: number; } /** * Magnetometer calibation state */ export enum MagnetometerCalibration { /** * Unknown state */ unknown = 0, /** * Calibration has been requestes */ requested = 1, /** * Calibration completed */ completed = 2, /** * Calibration had an error */ errored = 3, } /** * The sample period to read magnetometer data (milliseconds) */ export type MagnetometerPeriod = 1 | 2 | 5 | 10 | 20 | 80 | 160 | 640; /** * Events raised by the magnetometer service */ export interface MagnetometerEvents { /** * @hidden */ newListener: keyof MagnetometerEvents; /** * @hidden */ removeListener: keyof MagnetometerEvents; /** * Magnetometer data changed event */ magnetometerdatachanged: MagnetometerData; /** * Magnetometer bearing changed event */ magnetometerbearingchanged: number; /** * Magnetometer calibration changed event */ magnetometercalibrationchanged: MagnetometerCalibration; } /** * Magnetometer Service */ export class MagnetometerService extends (EventDispatcher as new () => TypedDispatcher< MagnetometerEvents >) { public static serviceName = 'MagnetometerService'; /** * @hidden */ public static uuid = 'e95df2d8-251d-470a-a062-fa1922dfa9a8'; /** * @hidden */ public static async create(service: BluetoothRemoteGATTService): Promise { const bluetoothService = new MagnetometerService(service); await bluetoothService.init(); return bluetoothService; } private helper: ServiceHelper; /** * @hidden */ constructor(service: BluetoothRemoteGATTService) { super(); //@ts-ignore this.helper = new ServiceHelper(service, this); } private async init() { await this.helper.handleListener( 'magnetometerdatachanged', MagnetometerCharacteristic.magnetometerData, this.magnetometerDataChangedHandler.bind(this) ); await this.helper.handleListener( 'magnetometerbearingchanged', MagnetometerCharacteristic.magnetometerBearing, this.magnetometerBearingChangedHandler.bind(this) ); await this.helper.handleListener( 'magnetometercalibrationchanged', MagnetometerCharacteristic.magnetometerCalibration, this.magnetometerCalibrationChangedHandler.bind(this) ); } /** * Request magnetometer calibration */ public async calibrate() { return this.helper.setCharacteristicValue( MagnetometerCharacteristic.magnetometerCalibration, new Uint8Array([1]) ); } /** * Read magnetometer data */ public async readMagnetometerData(): Promise { const view = await this.helper.getCharacteristicValue( MagnetometerCharacteristic.magnetometerData ); return this.dataViewToMagnetometerData(view); } /** * Read magnetometer bearing */ public async readMagnetometerBearing(): Promise { const view = await this.helper.getCharacteristicValue( MagnetometerCharacteristic.magnetometerBearing ); if (view.byteLength === 2) { return view.getUint16(0, true); } return undefined; } /** * Get magnetometer sample period */ public async getMagnetometerPeriod(): Promise { const view = await this.helper.getCharacteristicValue( MagnetometerCharacteristic.magnetometerPeriod ); return view.getUint16(0, true) as MagnetometerPeriod; } /** * Set magnetometer sample period * @param frequency The frequency interval to use */ public async setMagnetometerPeriod(frequency: MagnetometerPeriod): Promise { const view = new DataView(new ArrayBuffer(2)); view.setUint16(0, frequency, true); return this.helper.setCharacteristicValue( MagnetometerCharacteristic.magnetometerPeriod, view ); } private magnetometerDataChangedHandler(event: Event) { const view = (event.target as BluetoothRemoteGATTCharacteristic).value!; const value = this.dataViewToMagnetometerData(view); this.dispatchEvent('magnetometerdatachanged', value); } private magnetometerBearingChangedHandler(event: Event) { const view = (event.target as BluetoothRemoteGATTCharacteristic).value!; if (view.byteLength === 2) { this.dispatchEvent('magnetometerbearingchanged', view.getUint16(0, true)); } } private magnetometerCalibrationChangedHandler(event: Event) { const view = (event.target as BluetoothRemoteGATTCharacteristic).value!; if (view.byteLength === 1) { this.dispatchEvent('magnetometercalibrationchanged', view.getUint8( 0 ) as MagnetometerCalibration); } } private dataViewToMagnetometerData(view: DataView): MagnetometerData { return { x: view.getInt16(0, true), y: view.getInt16(1, true), z: view.getInt16(2, true), }; } } ================================================ FILE: src/class/hardware/bluetoothServices/services/temperature.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ import { TypedDispatcher, EventDispatcher } from '../event-dispatcher'; import { ServiceHelper } from '../service-helper'; /** * @hidden */ export enum TemperatureCharacteristic { temperature = 'e95d9250-251d-470a-a062-fa1922dfa9a8', temperaturePeriod = 'e95d1b25-251d-470a-a062-fa1922dfa9a8', } /** * Events raised by the temperature service */ export interface TemperatureEvents { /** * @hidden */ newListener: keyof TemperatureEvents; /** * @hidden */ removeListener: keyof TemperatureEvents; /** * Temperature changed event */ temperaturechanged: number; } /** * Temperature Service */ export class TemperatureService extends (EventDispatcher as new () => TypedDispatcher< TemperatureEvents >) { public static serviceName = 'TemperatureService'; /** * @hidden */ public static uuid = 'e95d6100-251d-470a-a062-fa1922dfa9a8'; /** * @hidden */ public static async create(service: BluetoothRemoteGATTService): Promise { const bluetoothService = new TemperatureService(service); await bluetoothService.init(); return bluetoothService; } private helper: ServiceHelper; /** * @hidden */ constructor(service: BluetoothRemoteGATTService) { super(); //@ts-ignore this.helper = new ServiceHelper(service, this); } private async init() { await this.helper.handleListener( 'temperaturechanged', TemperatureCharacteristic.temperature, this.temperatureChangedHandler.bind(this) ); } /** * Read temperature */ public async readTemperature(): Promise { const view = await this.helper.getCharacteristicValue( TemperatureCharacteristic.temperature ); return view.getInt8(0); } /** * Get temperature sample period */ public async getTemperaturePeriod(): Promise { const view = await this.helper.getCharacteristicValue( TemperatureCharacteristic.temperaturePeriod ); return view.getUint16(0, true); } /** * Set temperature sample period * @param frequency The frequency to use (milliseconds) */ public async setTemperaturePeriod(frequency: number): Promise { const view = new DataView(new ArrayBuffer(2)); view.setUint16(0, frequency, true); return await this.helper.setCharacteristicValue( TemperatureCharacteristic.temperaturePeriod, view ); } private temperatureChangedHandler(event: Event) { const view = (event.target as BluetoothRemoteGATTCharacteristic).value!; this.dispatchEvent('temperaturechanged', view.getInt8(0)); } } ================================================ FILE: src/class/hardware/bluetoothServices/services/uart.ts ================================================ /* * micro:bit Web Bluetooth * Copyright (c) 2019 Rob Moran * * The MIT License (MIT) * * 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. */ import { EventDispatcher, TypedDispatcher } from '../event-dispatcher'; import { ServiceHelper } from '../service-helper'; /** * @hidden */ export enum UartCharacteristic { tx = '6e400002-b5a3-f393-e0a9-e50e24dcca9e', rx = '6e400003-b5a3-f393-e0a9-e50e24dcca9e', } /** * Events raised by the UART service */ export interface UartEvents { /** * @hidden */ newListener: keyof UartEvents; /** * @hidden */ removeListener: keyof UartEvents; /** * Serial data received event */ receive: Uint8Array; /** * Serial received text event */ receiveText: string; } /** * UART Service */ export class UartService extends (EventDispatcher as new () => TypedDispatcher) { public static serviceName = 'UartService'; /** * @hidden */ public static uuid = '6e400001-b5a3-f393-e0a9-e50e24dcca9e'; /** * @hidden */ public static async create(service: BluetoothRemoteGATTService): Promise { const bluetoothService = new UartService(service); await bluetoothService.init(); return bluetoothService; } private helper: ServiceHelper; /** * @hidden */ constructor(service: BluetoothRemoteGATTService) { super(); //@ts-ignore this.helper = new ServiceHelper(service, this); } private async init() { await this.helper.handleListener( 'receive', UartCharacteristic.tx, this.receiveHandler.bind(this) ); await this.helper.handleListener( 'receiveText', UartCharacteristic.tx, this.receiveTextHandler.bind(this) ); } /** * Send serial data * @param value The buffer to send */ public async send(value: BufferSource): Promise { return this.helper.setCharacteristicValue(UartCharacteristic.rx, value); } /** * Send serial text * @param value The text to send */ public async sendText(value: string): Promise { const arrayData = value.split('').map((e: string) => e.charCodeAt(0)); return this.helper.setCharacteristicValue( UartCharacteristic.rx, new Uint8Array(arrayData).buffer ); } private receiveHandler(event: Event) { const view = (event.target as BluetoothRemoteGATTCharacteristic).value!; const value = new Uint8Array(view.buffer); this.dispatchEvent('receive', value); } private receiveTextHandler(event: Event) { const view = (event.target as BluetoothRemoteGATTCharacteristic).value!; const numberArray = Array.prototype.slice.call(new Uint8Array(view.buffer)); const value = String.fromCharCode.apply(null, numberArray); this.dispatchEvent('receiveText', value); } } ================================================ FILE: src/class/hardware/externalProgramLauncher.ts ================================================ class ExternalProgramLauncher { public programNotInstalled = false; private loadingView: Window; public executeUrl(schemeUrl: string, notInstalledCallback: () => void) { if (navigator.userAgent.indexOf('MSIE') > 0 || navigator.userAgent.indexOf('Trident') > 0) { if (navigator.msLaunchUri !== undefined) { executeIe(schemeUrl); } else { let ieVersion; // @ts-ignore IE 에 실제 있는 프로퍼티이다. if (document.documentMode > 0) { // @ts-ignore IE 에 실제 있는 프로퍼티이다. ieVersion = document.documentMode; } else { ieVersion = navigator.userAgent.match(/(?:MSIE) ([0-9.]+)/)[1]; } if (ieVersion < 9) { alert(Lang.msgs.not_support_browser); } else { this.init(schemeUrl, (programInstalled) => { if (programInstalled === false) { notInstalledCallback(); } }); } } } else if (navigator.userAgent.indexOf('Firefox') > 0) { executeFirefox(schemeUrl); } else if (navigator.userAgent.indexOf('Chrome') > 0) { executeChrome(schemeUrl); } else if (navigator.userAgent.indexOf('Safari') > 0) { executeSafari(schemeUrl); } else { alert(Lang.msgs.not_support_browser); } function executeIe(customUrl: string) { navigator.msLaunchUri( customUrl, () => {}, () => { notInstalledCallback(); } ); } function executeFirefox(customUrl: string) { const iFrame = document.createElement('iframe'); iFrame.src = 'about:blank'; iFrame.setAttribute('style', 'display:none'); document.getElementsByTagName('body')[0].appendChild(iFrame); const fnTimeout = setTimeout(() => { let isInstalled = false; try { iFrame.contentWindow.location.href = customUrl; isInstalled = true; } catch (e) { if (e.name === 'NS_ERROR_UNKNOWN_PROTOCOL') { isInstalled = false; } } if (!isInstalled) { notInstalledCallback(); } document.getElementsByTagName('body')[0].removeChild(iFrame); clearTimeout(fnTimeout); }, 500); } function executeChrome(customUrl: string) { let isInstalled = false; window.focus(); $(window).one('blur', () => { isInstalled = true; }); Entry.dispatchEvent('workspaceUnbindUnload', true); location.assign(encodeURI(customUrl)); setTimeout(() => { Entry.dispatchEvent('workspaceBindUnload', true); }, 100); setTimeout(() => { if (isInstalled === false) { notInstalledCallback(); } window.onblur = null; }, 3000); } /** * safari 브라우저에서 ${customUrl} 인식하여 페이지 이동 처리되서 분기처리(미설치 안내팝업) * * @param customUrl */ function executeSafari(customUrl: string) { const iFrame = document.createElement('iframe'); iFrame.src = 'about:blank'; iFrame.setAttribute('style', 'display:none'); document.getElementsByTagName('body')[0].appendChild(iFrame); let isInstalled; try { iFrame.contentWindow.location.href = customUrl; isInstalled = true; } catch (err) { isInstalled = false; } if (!isInstalled) { notInstalledCallback(); } setTimeout(() => { document.getElementsByTagName('body')[0].removeChild(iFrame); }, 500); } } public set() { this.programNotInstalled = true; } private init(schemeUrl: string, callback: (programInstalled: boolean) => void) { const settings = this.getLoadingViewStyle(); this.loadingView = window.open('/views/hwLoading.html', 'entry_hw_launcher', settings); let fnInterval: NodeJS.Timeout = undefined; fnInterval = setTimeout(() => { this.runViewer(schemeUrl, callback); clearInterval(fnInterval); }, 1000); } private runViewer(schemeUrl: string, callback: (programInstalled: boolean) => void) { this.loadingView.document.write( // eslint-disable-next-line max-len `` ); let tryCounter = 0; const programNotInstalled = false; let tryExecutionTimeout: NodeJS.Timeout = undefined; tryExecutionTimeout = setInterval(() => { try { this.loadingView.location.href; } catch (e) { this.programNotInstalled = true; } if (programNotInstalled || tryCounter > 10) { clearInterval(tryExecutionTimeout); let nCloseCounter = 0; let nCloseInterval: NodeJS.Timeout = undefined; nCloseInterval = setInterval(() => { nCloseCounter++; if (this.loadingView.closed || nCloseCounter > 2) { clearInterval(nCloseInterval); } else { this.loadingView.close(); } this.programNotInstalled = false; tryCounter = 0; }, 5000); callback(!this.programNotInstalled); } tryCounter++; }, 100); } private getLoadingViewStyle() { const width = 220; const height = 225; const left = window.screenLeft; const top = window.screenTop; return `width=${width}, height=${height}, top=${top}, left=${left}`; } } export default ExternalProgramLauncher; ================================================ FILE: src/class/hardware/functions/createHardwarePopup.ts ================================================ import PopupHelper from '../../popup_helper'; export default function createHardwarePopup(onOkButtonClicked?: () => void) { const popupHelper = window.popupHelper || new PopupHelper(true); popupHelper.addPopup('hwDownload', { type: 'confirm', title: Lang.Msgs.not_install_title, setPopupLayout(popup: any) { const content = Entry.Dom('div', { class: 'contentArea', }); const text = Entry.Dom('div', { class: 'textArea', parent: content, }); const text1 = Entry.Dom('div', { class: 'text1', parent: text, }); const text2 = Entry.Dom('div', { class: 'text2', parent: text, }); const text3 = Entry.Dom('div', { class: 'text3', parent: text, }); const text4 = Entry.Dom('div', { class: 'text4', parent: text, }); const cancel = Entry.Dom('div', { classes: ['popupCancelBtn', 'popupDefaultBtn'], parent: content, }); const ok = Entry.Dom('div', { classes: ['popupOkBtn', 'popupDefaultBtn'], parent: content, }); (text1 as any).text(Lang.Msgs.hw_download_text1); (text2 as any).html(Lang.Msgs.hw_download_text2); (text3 as any).text(Lang.Msgs.hw_download_text3); (text4 as any).text(Lang.Msgs.hw_download_text4); (cancel as any).text(Lang.Buttons.cancel); (ok as any).html(Lang.Msgs.hw_download_btn); (content as any).bindOnClick('.popupDefaultBtn', function() { const $this = $(this); if ($this.hasClass('popupOkBtn')) { onOkButtonClicked(); } popupHelper.hide(/*'hwDownload'*/); }); popup.append(content); }, }); return popupHelper; } ================================================ FILE: src/class/hardware/hardwareMonitor.ts ================================================ import { EntryHardwareBlockModule } from '../../../types/index'; const hwMonitorSvgTemplate = ''; export default class HardwareMonitor { private _hwModule: EntryHardwareBlockModule; private snap: any; private _svgGroup: any; private _portMap: any; private _portViews: any; private hwView: any; private pathGroup: any; private _template: any; private _svglistGroup: any; private _pathGroup: any; private _portMapList: any; private listsnap: any; private _rect: any; private svgDom = Entry.Dom($(hwMonitorSvgTemplate)); private changeOffset = 0; // 0 : off 1: on private scale = 0.5; private _listPortViews: any = {}; constructor(hwModule: EntryHardwareBlockModule) { this._hwModule = hwModule; Entry.addEventListener('windowResized', () => { const mode = this._hwModule.monitorTemplate.mode; if (mode == 'both') { this.resize(); this.resizeList(); } if (mode == 'list') { this.resizeList(); } else { this.resize(); } }); Entry.addEventListener('hwModeChange', () => { this.changeMode(); }); } initView() { this.svgDom = Entry.Dom($(hwMonitorSvgTemplate)); } generateViewByMode() { this._template = typeof this._hwModule.monitorTemplate === 'function' ? this._hwModule.monitorTemplate() : this._hwModule.monitorTemplate; const monitorTemplate = this._template; if (monitorTemplate.mode === 'both') { this.generateListView(); this.generateView(); } else if (monitorTemplate.mode === 'list') { this.generateListView(); } else { this.generateView(); } } generateView() { this.snap = Entry.SVG('hwMonitor'); this._svgGroup = this.snap.elem('g'); this._portMap = { n: [], e: [], s: [], w: [], }; const monitorTemplate = this._template; const imgObj = { href: monitorTemplate.imgPath ? Entry.mediaFilePath + monitorTemplate.imgPath : undefined, x: -monitorTemplate.width / 2, y: -monitorTemplate.height / 2, width: monitorTemplate.width, height: monitorTemplate.height, }; this._portViews = {}; if (imgObj.href) { this.hwView = this._svgGroup.elem('image'); this.hwView = this.hwView.attr(imgObj); } const ports = monitorTemplate.ports; this.pathGroup = null; this.pathGroup = this._svgGroup.elem('g'); const portsTemp = []; for (const key in ports) { const port = ports[key]; const portView = this.generatePortView(port, '_svgGroup'); this._portViews[key] = portView; portsTemp.push(portView); } portsTemp.sort((a, b) => a.box.x - b.box.x); const portMap = this._portMap; portsTemp.map((v) => { const degree = (Math.atan2(-v.box.y, v.box.x) / Math.PI + 2) % 2; let map; if (degree < 1) { map = portMap.n; } else { map = portMap.s; } map.push(v); }); this.resize(); } toggleMode(mode: string) { const monitorTemplate = this._hwModule.monitorTemplate; if (mode === 'list') { monitorTemplate.TempPort = null; if (this._hwModule.monitorTemplate.ports) { this._hwModule.monitorTemplate.TempPort = this._hwModule.monitorTemplate.ports; this._hwModule.monitorTemplate.listPorts = this.addPortEle( this._hwModule.monitorTemplate.listPorts, this._hwModule.monitorTemplate.ports ); } $(this._svglistGroup).remove(); if (this._svgGroup) { $(this._svgGroup).remove(); } $(this._pathGroup).remove(); this._hwModule.monitorTemplate.mode = 'list'; this.generateListView(); } else { if (this._hwModule.monitorTemplate.TempPort) { this._hwModule.monitorTemplate.ports = this._hwModule.monitorTemplate.TempPort; this._hwModule.monitorTemplate.listPorts = this.removePortEle( this._hwModule.monitorTemplate.listPorts, this._hwModule.monitorTemplate.ports ); } $(this._svglistGroup).remove(); this._hwModule.monitorTemplate.mode = 'both'; this.generateListView(); this.generateView(); } } setHwModule(hwModule: EntryHardwareBlockModule) { this._hwModule = hwModule; } changeMode() { if (this._hwModule.monitorTemplate.mode === 'both') { this.toggleMode('list'); } else if (this._hwModule.monitorTemplate.mode === 'list') { this.toggleMode('both'); } } addPortEle(listPort: any, ports: any) { if (typeof ports != 'object') { return listPort; } for (const item in ports) { listPort[item] = ports[item]; } return listPort; } removePortEle(listPort: any, ports: any) { if (typeof ports != 'object') { return listPort; } for (const item in ports) { delete listPort[item]; } return listPort; } generateListView() { this._portMapList = { n: [], }; this._svglistGroup = null; this.listsnap = Entry.SVG('hwMonitor'); this._svglistGroup = this.listsnap.elem('g'); const monitorTemplate = this._template; const ports = monitorTemplate.listPorts; this.pathGroup = this._svglistGroup.elem('g'); const portsTempList = []; for (const key in ports) { const port = ports[key]; const portView = this.generatePortView(port, '_svglistGroup'); this._listPortViews[key] = portView; portsTempList.push(portView); } const portMapList = this._portMapList; portsTempList.map((v) => { portMapList.n.push(v); }); this.resizeList(); } generatePortView(port: any, target: string) { // @ts-ignore const svgGroup = this[target].elem('g'); svgGroup.addClass('hwComponent'); let path = null; path = this.pathGroup.elem('path').attr({ d: 'm0,0', fill: 'none', stroke: port.type === 'input' ? '#00CFCA' : '#CA7DFF', 'stroke-width': 3, }); const wrapperRect = svgGroup.elem('rect').attr({ x: 0, y: 0, width: 150, height: 22, rx: 4, ry: 4, fill: '#fff', stroke: '#a0a1a1', }); const nameView = svgGroup.elem('text').attr({ x: 4, y: 12, fill: '#000', class: 'hwComponentName', 'alignment-baseline': 'central', }); nameView.textContent = port.name; let width = nameView.getComputedTextLength(); const valueRect = svgGroup.elem('rect').attr({ x: width + 8, y: 2, width: 30, height: 18, rx: 9, ry: 9, fill: port.type === 'input' ? '#00CFCA' : '#CA7DFF', }); const valueView = svgGroup.elem('text').attr({ x: width + 13, y: 12, fill: '#fff', class: 'hwComponentValue', 'alignment-baseline': 'central', }); valueView.textContent = 0; width += 40; wrapperRect.attr({ width, }); const returnObj = { group: svgGroup, value: valueView, type: port.type, path, box: { x: port.pos.x - this._template.width / 2, y: port.pos.y - this._template.height / 2, width, }, width, }; return returnObj; } getView() { return this.svgDom; } update(portData: any, sendQueue: any) { const mode = this._template.mode; const objectKeys = this._template.keys || []; let portView = []; if (mode == 'list') { portView = this._listPortViews; } else if (mode == 'both' && this._portViews) { portView = this._listPortViews; for (const elem in this._portViews) { portView[elem] = this._portViews[elem]; } } else { portView = this._portViews; } if (sendQueue) { for (const elem in sendQueue) { if (sendQueue[elem] != 0 && portView[elem]) { portView[elem].type = 'output'; } } } for (const key in portView) { const port = portView[key]; if (port.type == 'input') { let value = portData[key]; if (objectKeys.length > 0) { $.each(objectKeys, (idx, valueKey) => { if ($.isPlainObject(value)) { value = value[valueKey] || 0; } else { return false; } }); port.value.textContent = value ? value : 0; port.group.getElementsByTagName('rect')[1].attr({ fill: '#00CFCA' }); } else { port.value.textContent = value ? value : 0; port.group.getElementsByTagName('rect')[1].attr({ fill: '#00CFCA' }); } } else { let value = sendQueue ? sendQueue[key] : portData[key]; if (objectKeys.length > 0) { $.each(objectKeys, (idx, valueKey) => { if ($.isPlainObject(value)) { value = value[valueKey] || 0; } else { return false; } }); port.value.textContent = value ? value : 0; port.group.getElementsByTagName('rect')[1].attr({ fill: '#CA7DFF' }); } else { port.value.textContent = value ? value : 0; port.group.getElementsByTagName('rect')[1].attr({ fill: '#CA7DFF' }); } } } } resize() { if (!this.svgDom) { return; } const bRect = this.svgDom.get(0).getBoundingClientRect(); this._svgGroup.attr({ transform: `translate(${bRect.width / 2},${bRect.height / 1.8})`, }); this._rect = bRect; if (this._template.height <= 0 || bRect.height <= 0) { return; } this.scale = (this._template.height * (bRect.height / this._template.height)) / 1000; if (this.hwView && this.scale) { this.hwView.attr({ transform: `scale(${this.scale})`, }); } this.align(); } resizeList() { const bRect = this.svgDom.get(0).getBoundingClientRect(); this._svglistGroup.attr({ transform: `translate(${bRect.width / 2},${bRect.height / 2})`, }); this._rect = bRect; this.alignList(); } align() { this._alignNS(this._portMap.s.concat(), this._template.height * (this.scale / 3) + 5, 27); this._alignNS( this._portMap.n.concat(), (-this._template.height * this.scale) / 3 - 32, -27 ); } alignList() { let ports = this._hwModule.monitorTemplate.listPorts || {}; const length = ports.length; for (let i = 0; i < ports.length; i++) { const port = ports[i]; port.group.attr({ transform: `translate(${this._template.width * (i / length - 0.5)},${-this._template .width / 2 - 30})`, }); } ports = this._portMapList.n.concat(); this._alignNSList(ports, (-this._template.width * this.scale) / 2 - 32 /*, -27*/); } _alignNS(ports: any, yCursor: any, gap: any) { const length = ports.length; const mid = (length - 1) / 2; let lP = -this._rect.width / 2; let rP = this._rect.width / 2; const width = this._rect.width; let wholeWidth = 0; const listLine = 0; const mode = this._hwModule.monitorTemplate.mode; for (let i = 0; i < ports.length; i++) { wholeWidth += ports[i].width + 5; } if (wholeWidth < rP - lP) { rP = wholeWidth / 2 + 3; lP = -wholeWidth / 2 - 3; } while (ports.length > 1) { const lPort = ports.shift(); const rPort = ports.pop(); const prevLP = lP; const prevRP = rP; let gapTemp = gap; if (wholeWidth <= rP - lP) { lP += lPort.width + 5; rP -= rPort.width + 5; gapTemp = 0; } else if (ports.length === 0) { lP = (lP + rP) / 2 - 3; rP = lP + 6; } else { lP = Math.max(lP, -width / 2 + lPort.width) + 15; rP = Math.min(rP, width / 2 - rPort.width) - 15; } this._movePort(lPort, lP, yCursor, prevLP); this._movePort(rPort, rP, yCursor, prevRP); wholeWidth -= lPort.width + rPort.width + 10; yCursor += gapTemp; } if (ports.length) { this._movePort(ports[0], (rP + lP - ports[0].width) / 2, yCursor, 100); } } _alignNSList(ports: any, yCursor: any) { const length = ports.length; const width = this._rect.width; const height = this._rect.height; let initX = -this._rect.width / 2 + 10; const initY = -this._rect.height / 2 + 10; let wholeWidth = 0; const listLine = 0; for (var i = 0; i < ports.length; i++) { wholeWidth += ports[i].width; // 전체 width } let lineIndent = 0; let currentWidth = 0; const tempXpos = initX; let Yval = 0; let cPort: any = 0; let nPort: any = 0; for (var i = 0; i < ports.length; i++) { cPort = ports[i]; if (i != ports.length - 1) { nPort = ports[i + 1]; } currentWidth += cPort.width; const lP = initX; Yval = initY + lineIndent * 30; cPort.group.attr({ transform: `translate(${lP},${Yval})`, }); initX += cPort.width + 10; if (currentWidth > width - (cPort.width + nPort.width / 2.2)) { lineIndent += 1; initX = tempXpos; currentWidth = 0; } } } _movePort(port: any, x: any, y: any, prevPointer: any) { let groupX = x; let path; const portX = port.box.x * this.scale; const portY = port.box.y * this.scale; if (x > prevPointer) { // left side groupX = x - port.width; if (x > portX && portX > prevPointer) { path = `M${portX},${y}L${portX},${portY}`; } else { path = `M${(x + prevPointer) / 2},${y}l0,${ portY > y ? 28 : -3 }H${portX}L${portX},${portY}`; } } else if (x < portX && portX < prevPointer) { // right side path = `m${portX},${y}L${portX},${portY}`; } else { path = `m${(prevPointer + x) / 2},${y}l0,${ portY > y ? 28 : -3 }H${portX}L${portX},${portY}`; } port.group.attr({ transform: `translate(${groupX},${y})` }); port.path.attr({ d: path }); } } ================================================ FILE: src/class/hardware/hardwareSocketMessageHandler.ts ================================================ import isObject from 'lodash/isObject'; /** * 엔트리 하드웨어 -> 엔트리 워크스페이스간 통신을 정리한 클래스 * action, data(payload) 를 메세지로 받는다. * action * - state { statement: String } : 현재 상태를 정의한다. 하드웨어의 연결 상태 체크용 * - init { name: String } : 현재 연결된 하드웨어의 모듈명을 전달 받고, 서버에서 블록데이터를 받아온다. * - default { anyObject for data handle }: 이전의 hw.js 에 있는 로직을 그대로 복사. 과거 코드 대응 * - disconnect : 이전 disconnectHardware 와 동일 */ type EntryHardwareSocketMessage = { action: string; data: any; }; export default class { private socket: SocketIOClient.Socket; private readonly listeners: { [type: string]: any }; constructor(socket: SocketIOClient.Socket) { this.socket = socket; this.listeners = []; socket.on('message', this._onAction.bind(this)); } _onAction(message: EntryHardwareSocketMessage) { // 객체 구조가 이모양인건 기존 호환성때문. // 정리해서 이쁘게 만들도록 하자 (entry-hw-server 수정필요) const { data } = message; const { action, data: payload } = data; switch (action) { case 'state': this._onStateAction(payload); break; case 'init': this._onInitAction(payload); break; default: this._onDefaultAction(data); } } /** * 현재 하드웨어 연결 상태를 표기한다. * connected 의 경우 어떤 하드웨어와 연결되었는지 표기된다. * @param payload {*} payload * @private */ _onStateAction(payload: any) { const { statement, name } = payload; this.dispatchEvent('state', statement, name); } _onInitAction({ name }: any) { this.dispatchEvent('init', name); } /** * 1.7.0 이전 하드웨어 버전의 원활한 통신을 위해 남겨두어야 한다. * @param data * @private */ _onDefaultAction(data: any) { if (data) { let portData = {}; if (typeof data === 'string') { switch (data) { case 'disconnectHardware': { this.dispatchEvent('disconnect'); return; } default: { portData = JSON.parse(data); break; } } } else if (isObject(data)) { portData = data; } this.dispatchEvent('data', portData); } } addEventListener(type: string, callback: (...args: any[]) => void) { if (!(type in this.listeners)) { this.listeners[type] = []; } this.listeners[type].push(callback); } removeEventListener(type: string, callback: () => void) { if (!(type in this.listeners)) { return; } const stack = this.listeners[type]; for (let i = 0, l = stack.length; i < l; i++) { if (stack[i] === callback) { stack.splice(i, 1); return; } } } dispatchEvent(eventName: string, ...args: any[]) { if (!(eventName in this.listeners)) { return true; } const stack = this.listeners[eventName].slice(); for (let i = 0, l = stack.length; i < l; i++) { stack[i].call(this, ...args); } } } ================================================ FILE: src/class/hardware/webApiConnector.ts ================================================ // INFO : 웹연결 api의 라이프사이클 함수를 모아놓은 추상 클래스 export default class WebApiConnector { connect() {} disconnect() {} initialDevice() {} } ================================================ FILE: src/class/hardware/webBluetoothConnector.ts ================================================ import { EntryHWLiteBaseModule } from 'types'; import HardwareLite from '../hw_lite'; import WebApiConnector from './webApiConnector'; import { getServiceClassesByModuleId } from './bluetoothServices'; export default class WebBluetoothConnector extends WebApiConnector { private hwModule: EntryHWLiteBaseModule; private hwLite: HardwareLite; private device: BluetoothDevice; private services: any; // TODO: 타입할당 private serviceClasses: any[]; constructor(hwModule: EntryHWLiteBaseModule, hwLite: HardwareLite) { super(); this.hwModule = hwModule; this.setServiceClasses(); } async connect() { await this.setDevice(); await this.setServices(); } async disconnect() { await this.device.gatt.disconnect(); this.hwModule = undefined; this.device = undefined; this.services = undefined; this.serviceClasses = undefined; } async initialDevice() { if (this.hwModule?.initialHandshake) { this.hwModule?.initialHandshake(); } } async setDevice() { const filters = this.hwModule.bluetoothInfo.filters; const optionalServices = this.serviceClasses.map((serviceClass) => serviceClass.uuid); this.device = await navigator.bluetooth.requestDevice({ filters, optionalServices }); } setServiceClasses() { this.serviceClasses = getServiceClassesByModuleId(this.hwModule.id); } async setServices() { if (!this.device || !this.device.gatt) { this.hwLite.getConnectFailedMenu(); return; } if (!this.device.gatt.connected) { await this.device.gatt.connect(); } this.services = {}; const primaryServices = await this.device.gatt.getPrimaryServices(); for (const primaryService of primaryServices) { for (const serviceClass of this.serviceClasses) { if (primaryService.uuid === serviceClass.uuid) { this.services[serviceClass.serviceName] = await serviceClass.create(primaryService); } } } } } ================================================ FILE: src/class/hardware/webSerialConnector.ts ================================================ import { EntryHWLiteBaseModule } from 'types'; import HardwareLite from '../hw_lite'; import WebApiConnector from './webApiConnector'; import throttle from 'lodash/throttle'; const Buffer = require('buffer/').Buffer; class LineBreakTransformer { private container: string; constructor() { this.container = ''; } transform(chunk: string, controller: any) { try { this.container += chunk; // @ts-ignore const lines = this.container.split(Entry.hwLite?.hwModule?.delimeter || '\r\n'); this.container = lines.pop(); lines.forEach((line) => controller.enqueue(line)); } catch (e) { controller.enqueue(chunk); } } flush(controller: any) { controller.enqueue(this.container); } } export default class WebSerialConnector extends WebApiConnector { private writer: any; // SerialPort.writer; private reader: any; //SerialPort.reader; private hwModule: EntryHWLiteBaseModule; // > 추후 전용 타입으로 변경 private port: any; private connectionType: 'ascii' | 'bytestream' | undefined; private writableStream: any; private isSendAsyncRun: boolean; private hwLite: HardwareLite; private sendAsyncWithThrottle: any; constructor(hwModule: EntryHWLiteBaseModule, hwLite: HardwareLite) { super(); this.hwLite = hwLite; this.hwModule = hwModule; this.isSendAsyncRun = false; this.hwLite.setStatus('disconnected'); Entry.addEventListener('beforeStop', this.checkConditionBeforeStop.bind(this)); this.sendAsyncWithThrottle = throttle(this.sendAsync, this.hwModule.duration); } async connect() { // @ts-ignore const port = await navigator.serial.requestPort(); const { portData } = this.hwModule || {}; await port.open( portData || { baudRate: 9600, dataBits: 8, parity: 'none', bufferSize: 256, stopBits: 1, } ); this.port = port; const encoder = new TextEncoderStream(); const writable = port.writable; this.connectionType = portData?.connectionType; if (portData?.writeAscii || portData?.connectionType === 'ascii') { const writableStream = encoder.readable.pipeTo(writable); this.writableStream = writableStream; this.writer = encoder.writable.getWriter(); } else { this.writer = port.writable.getWriter(); } let readable = this.port.readable; if (portData?.readAscii || this.connectionType === 'ascii') { readable = readable.pipeThrough(new TextDecoderStream()); } if (this.hwModule?.delimeter || this.connectionType === 'ascii') { readable = readable.pipeThrough(new TransformStream(new LineBreakTransformer())); } this.reader = readable.getReader(); } async disconnect() { // INFO: 디바이스가 제거되었을 때, reader만 단독 예외처리 try { await this.reader?.cancel().catch((error: any) => { console.error(error); }); await this.writer?.close(); if (this.connectionType === 'ascii' && this.writableStream) { await this.writableStream; } } catch (err) { console.error(err); } finally { await this.port?.close(); this.port = null; this.reader = null; this.writer = null; this.writableStream = null; this.hwModule = null; } } async initialDevice() { if (this.hwModule.initialHandshake) { const result = await this.hwModule.initialHandshake(); if (!result) { throw new Error('Handshake Error : 디바이스와 연결에 실패하였습니다.'); } } if (this.hwModule.portData?.constantServing) { this.constantServing(); } } /** * 디바이스와 1회성 통신 * @param data * @returns Promise resolves to resulting message */ async sendAsync(data?: Buffer | string, isResetReq?: boolean, callback?: Function) { if (this.isSendAsyncRun) { return; } else { this.isSendAsyncRun = true; } if (!data || this.hwLite.getStatus() !== 'connected') { return; } // @ts-ignore const encodedData = typeof data === 'string' ? data : Buffer.from(data, 'utf8'); try { if (this.hwLite.getStatus() !== 'connected') { Entry.toast.alert( Lang.Msgs.hw_connection_failed_title, Lang.Msgs.hw_connection_failed_desc, false ); throw new Error('HARDWARE LITE NOT CONNECTED'); } await this.writer.write(encodedData); if (isResetReq) { this.isSendAsyncRun = false; return; } const { value, done } = await this.reader.read(); if (callback) { return callback(value); } this.hwLite._updatePortData(); return value; } catch (err) { console.error(err); this.hwLite.getConnectFailedMenu(); } finally { this.isSendAsyncRun = false; } } async constantServing() { try { if (this.hwLite.getStatus() === 'disconnected') { return; } if (this.hwModule?.portData?.constantServing !== 'ReadOnly') { const reqLocal = this.hwModule?.requestLocalData(); if (reqLocal && this.hwLite.getStatus() === 'connected') { if (Entry.engine.isState('run')) { this.writer.write(Buffer.from(reqLocal)); } } } const { value, done } = await this.reader.read(); if (done) { this.hwLite.getConnectFailedMenu(); return; } this.hwModule?.handleLocalData(value); this.hwLite._updatePortData(); setTimeout(() => { this.constantServing(); }, this.hwModule.duration || 0); } catch (error) { console.error(error); this.hwLite.getConnectFailedMenu(); return; } } async readPortData() { try { if (this.hwLite.getStatus() === 'connected' && Entry.engine.isState('run')) { const { value, done } = await this.reader.read(); if (!value) { this.reader.cancel(); throw new Error("reader's value is undefined. check device"); } return value; } } catch (error) { console.error(error); this.hwLite.getConnectFailedMenu(); } } async writePortData(data: string) { if (data && this.hwLite.getStatus() === 'connected') { const result = await this.writer.write(Buffer.from(data)); } } async removeSerialPort() { try { // INFO: 디바이스가 제거되었을 때, reader만 단독 예외처리 await this.reader?.cancel().catch((error: any) => { console.error(error); }); await this.writer?.close(); if (this.connectionType === 'ascii' && this.writableStream) { await this.writableStream; } } catch (error) { console.error(error); } finally { await this.port?.close(); this.port = null; this.reader = null; this.writer = null; this.writableStream = null; } } // engine 동작중 에러 발생시 호출, 디바이스에 read, write가 모두 안되는 것이 전제 async handleConnectErrorInEngineRun() { // INFO: Engin.toggleStop에서 setZero가 실행되지 않도록 상태변경 if (this.hwLite.getStatus() === 'willDisconnect') { return; } this.hwLite.setStatus('willDisconnect'); if (Entry.engine.isState('run')) { await Entry.engine.toggleStop(); } await this.removeSerialPort(); this.hwLite.getConnectFailedMenu(); Entry.toast.alert( Lang.Msgs.hw_connection_failed_title, Lang.Msgs.hw_connection_failed_desc, false ); } update() { if (this.hwLite.getStatus() !== 'connected') { console.error('Cannot update hwLite queue. Check connection status.'); return; } if (this.hwModule?.portData?.constantServing) { const reqLocal = this.hwModule?.requestLocalData(); if (reqLocal) { this.writer.write(Buffer.from(reqLocal)); } } } sendAsciiAsBuffer(asciiStr: string) { this.writer.write(Buffer.from(asciiStr, 'utf8')); } checkConditionBeforeStop() { this.isSendAsyncRun = false; } } ================================================ FILE: src/class/hardware/webUsbFlasher.ts ================================================ import { stringToUint8Array } from '../../util/hardwareUtils'; const filters = [ { vendorId: 3368, productId: 516, classCode: 255, subclassCode: 3, }, { vendorId: 3368, productId: 516, classCode: 255, subclassCode: 0, }, ]; export default class WebUsbFlasher { private device: USBDevice; private isTransfer: boolean; private claimInterface: number; private endpointNumber: number; private flashingPercent: number; private flashState: string; constructor() { this.isTransfer = false; this.claimInterface = -1; this.endpointNumber = -1; } // INFO: 연결된 기기에 파라미터로 넘어온 펌웨어를 플래싱 // TODO: 현재 유일한 지원기종인 microbitble에 맞춰져있음, 추후 지원기기가 늘어나면 로직수정 필요 async flashFirmware(firmwareUrl: string, percentCallback: Function) { try { if (!this.device) { throw Error('device undefined'); } const response = await fetch(firmwareUrl); const hexData = await response.text(); const data = stringToUint8Array(hexData); this.flashState = 'start'; let chunkSize = 62; let offset = 0; let sentPages = 0; this.flashState = 'flashing'; while (offset < data.length) { const end = Math.min(data.length, offset + chunkSize); const nextPageData = data.slice(offset, end); const cmdData = new Uint8Array(2 + nextPageData.length); cmdData[0] = 0x8c; cmdData[1] = nextPageData.length; cmdData.set(nextPageData, 2); // TODO: 퍼센트 로직도 분리 if (sentPages % 128 == 0) { this.flashingPercent = (offset / data.length) * 100; percentCallback && percentCallback(this.flashingPercent); } await this.writeBuffer(cmdData); sentPages++; offset = end; } this.flashingPercent = (offset / data.length) * 100; percentCallback && percentCallback(this.flashingPercent); this.flashState = 'end'; // INFO: close const flashResult = await this.writeData([0x8b]); if (flashResult[1] !== 0) { throw Error('flash failed'); } // INFO: reset await this.writeData([0x89]); } finally { this.flashState = 'idle'; } } // INFO: 펌웨어 플래시전 webUsb로 기기와 브라우저를 연결 async connectUsb() { // TODO: 지원기기가 늘어나면 vendorId 변수값으로 변경 this.device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x0d28 }], }); await this.device.open(); await this.device.selectConfiguration(1); this.findInterface(); await this.device.claimInterface(this.claimInterface); const result = await this.writeData([0x8a, 1]); if (result[1] !== 0) { throw Error('device open failed'); } } findInterface() { const filteredInterfaces = this.device.configurations[0].interfaces.filter( (interfaceItem) => { const alternateInterface = interfaceItem.alternates[0]; for (const filter of filters) { if ( (filter.classCode === null || alternateInterface.interfaceClass === filter.classCode) && !( filter.subclassCode !== null && alternateInterface.interfaceSubclass !== filter.subclassCode ) ) { if (alternateInterface.endpoints.length === 0) { return true; } if ( alternateInterface.endpoints.length === 2 && alternateInterface.endpoints.every( (endpoint) => endpoint.packetSize === 64 ) ) { return true; } } } return false; } ); const iface = filteredInterfaces[filteredInterfaces.length - 1]; const altIface = iface.alternates[0]; if (altIface.endpoints.length) { // study: endpoints 역할 this.isTransfer = true; const epIn = altIface.endpoints.filter((e) => 'in' == e.direction)[0]; this.endpointNumber = epIn.endpointNumber; } this.claimInterface = iface.interfaceNumber; } async transfer(data: Uint8Array) { if (this.isTransfer) { await this.device.transferOut(this.endpointNumber, new Uint8Array(data)); return await this.device.transferIn(this.endpointNumber, 64); } else { await this.device.controlTransferOut( { requestType: 'class', recipient: 'interface', request: 9, value: 512, index: this.claimInterface, }, data ); return await this.device.controlTransferIn( { requestType: 'class', recipient: 'interface', request: 1, value: 256, index: this.claimInterface, }, 64 ); } } // TODO: buffer랑 합치기 async writeData(data: Array): Promise { const response = await this.transfer(new Uint8Array(data)); if (!response.data?.buffer) { throw Error('writeData failed'); } return new Uint8Array(response.data.buffer); } async writeBuffer(buffer: Uint8Array): Promise { const response = await this.transfer(buffer); if (!response.data?.buffer) { throw Error('writeData failed'); } return new Uint8Array(response.data.buffer); } } ================================================ FILE: src/class/helper.js ================================================ import debounce from 'lodash/debounce'; class EntryBlockHelper { constructor() { this.visible = false; Entry.addEventListener('workspaceChangeMode', () => { if (this._blockView) { this.renderBlock(this._blockView.type); } }); this.resize = debounce(this.resize, 300); } generateView(parentView) { if (this.parentView_) { return; } /** @type {!Element} parent view */ this.parentView_ = parentView; const helper = this; helper.blockHelpData = EntryStatic.blockInfo; const blockHelperWrapper = Entry.createElement('div', 'entryBlockHelperWorkspaceWrapper'); const blockHelperView = Entry.createElement('div', 'entryBlockHelperWorkspace'); blockHelperWrapper.appendChild(blockHelperView); this.view = blockHelperWrapper; if (Entry.isForLecture) { blockHelperView.addClass('lecture'); } helper.parentView_.appendChild(blockHelperWrapper); const blockHelperContent = Entry.createElement('div', 'entryBlockHelperContentWorkspace'); this._contentView = blockHelperContent; const commandTitle = Entry.createElement('div'); commandTitle.addClass('entryBlockHelperTitle textModeElem'); commandTitle.textContent = 'Command'; blockHelperContent.appendChild(commandTitle); blockHelperContent.addClass('entryBlockHelperIntro'); if (Entry.isForLecture) { blockHelperContent.addClass('lecture'); } blockHelperView.appendChild(blockHelperContent); helper.blockHelperContent_ = blockHelperContent; helper.blockHelperView_ = blockHelperView; const blockHelperBlock = Entry.createElement('div', 'entryBlockHelperBlockWorkspace'); helper.blockHelperContent_.appendChild(blockHelperBlock); const descTitle = Entry.createElement('div'); descTitle.addClass('entryBlockHelperTitle textModeElem'); descTitle.textContent = 'Explanation'; blockHelperContent.appendChild(descTitle); const blockHelperDescription = Entry.createElement( 'div', 'entryBlockHelperDescriptionWorkspace' ); blockHelperDescription.addClass('entryBlockHelperContent selectAble'); helper.blockHelperContent_.appendChild(blockHelperDescription); blockHelperDescription.textContent = Lang.Helper.Block_click_msg; this.blockHelperDescription_ = blockHelperDescription; const elementsTitle = Entry.createElement('div'); elementsTitle.addClass('entryBlockHelperTitle textModeElem'); elementsTitle.textContent = 'Element'; blockHelperContent.appendChild(elementsTitle); this._elementsTitle = elementsTitle; this._elementsContainer = Entry.createElement('div', 'entryBlockHelperElementsContainer'); this._elementsContainer.addClass('entryBlockHelperContent textModeElem selectAble'); blockHelperContent.appendChild(this._elementsContainer); const blockHelperLink = Entry.createElement( 'div', 'entryBlockHelperLinkWorkspace' ); blockHelperLink.addClass('blockHelperLink'); const helperLink = Entry.createElement('a', 'entryBlockHelperLink'); helperLink.addClass('linkTextElem'); helperLink.setAttribute('target' ,'_blank'); blockHelperLink.appendChild(helperLink); blockHelperContent.appendChild(blockHelperLink); this.blockHelperLink_ = helperLink; if (typeof CodeMirror !== 'undefined') { const codeMirrorTitle = Entry.createElement('div'); codeMirrorTitle.addClass('entryBlockHelperTitle textModeElem'); codeMirrorTitle.textContent = 'Example Code'; blockHelperContent.appendChild(codeMirrorTitle); const codeMirrorView = Entry.createElement( 'div', 'entryBlockHelperCodeMirrorContainer' ); codeMirrorView.addClass('textModeElem'); blockHelperContent.appendChild(codeMirrorView); this.codeMirror = CodeMirror(codeMirrorView, { lineNumbers: true, value: '', mode: { name: 'python' }, indentUnit: 4, theme: 'default', viewportMargin: 10, styleActiveLine: false, readOnly: true, }); this._doc = this.codeMirror.getDoc(); this._codeMirror = this.codeMirror; const codeMirrorDescTitle = Entry.createElement('div'); codeMirrorDescTitle.addClass('entryBlockHelperTitle textModeElem'); codeMirrorDescTitle.textContent = 'Example Explanation'; blockHelperContent.appendChild(codeMirrorDescTitle); this._codeMirrorDesc = Entry.createElement('div'); this._codeMirrorDesc.addClass('entryBlockHelperContent textModeElem selectAble'); blockHelperContent.appendChild(this._codeMirrorDesc); } this._renderView = new Entry.RenderView($(blockHelperBlock), 'LEFT_MOST'); this.code = new Entry.Code([]); this.code.isFor = 'blockHelper'; this._renderView.changeCode(this.code); this.first = true; } bindWorkspace(workspace) { if (!workspace) { return; } if (this._blockViewObserver) { this._blockViewObserver.destroy(); } this.workspace = workspace; if (this._renderView) { this._renderView.workspace = workspace; } this._blockViewObserver = workspace.observe(this, '_updateSelectedBlock', [ 'selectedBlockView', ]); } renderBlock(type) { const description = Lang.Helper[type]; if (!type || !this.visible || !description || Entry.block[type].isPrimitive) { return; } if (this.first) { this.blockHelperContent_.removeClass('entryBlockHelperIntro'); this.first = false; } const code = this.code; code.clear(); let def = Entry.block[type].def || { type }; if (this.workspace.getMode() === Entry.Workspace.MODE_VIMBOARD) { this._contentView.addClass('textMode'); this.blockHelperDescription_.textContent = Lang.PythonHelper[`${type}_desc`]; let elements = Lang.PythonHelper[`${type}_elements`]; this._elementsContainer.textContent = ''; if (elements) { this._elementsTitle.removeClass('entryRemove'); elements = elements.split('%next'); while (elements.length) { (function(elems) { const contents = elems.split('-- '); const box = Entry.createElement('div'); box.addClass('entryBlockHelperElementsContainer'); const left = Entry.createElement('div'); left.textContent = contents[0]; left.addClass('elementLeft'); const right = Entry.createElement('div'); right.addClass('elementRight'); right.textContent = contents[1]; box.appendChild(left); box.appendChild(right); this._elementsContainer.appendChild(box); }.bind(this)(elements.shift())); } } else { this._elementsTitle.addClass('entryRemove'); } this._codeMirrorDesc.textContent = Lang.PythonHelper[`${type}_exampleDesc`]; const exampleCode = Lang.PythonHelper[`${type}_exampleCode`]; this._codeMirror.setValue(exampleCode); this.codeMirror.refresh(); def = Entry.block[type].pyHelpDef || def; } else { this._contentView.removeClass('textMode'); this.blockHelperDescription_.textContent = description; const category = Entry.block[type].wikiClass || Entry.Utils.getBlockCategory(type); if (category) { this.blockHelperLink_.textContent = Lang.Helper.link_to_entry_wiki; this.blockHelperLink_.href = Lang.Helper[`wiki_link_${category}`]; } else { this.blockHelperLink_.textContent = ''; this.blockHelperLink_.href = ''; } } code.createThread([def]); code.board.align(); code.board.resize(); this._renderView.align(); this._renderView.setDomSize(); } getView() { return this.view; } resize() { this.codeMirror && this.codeMirror.refresh(); } _updateSelectedBlock() { const blockView = this.workspace.selectedBlockView; // noinspection EqualityComparisonWithCoercionJS if (!blockView || !this.visible || blockView == this._blockView) { return; } const type = blockView.block.type; this._blockView = blockView; this.renderBlock(type); } } export default EntryBlockHelper; ================================================ FILE: src/class/hw.ts ================================================ import HardwareSocketMessageHandler from './hardware/hardwareSocketMessageHandler'; import HardwareMonitor from './hardware/hardwareMonitor'; import createHardwarePopup from './hardware/functions/createHardwarePopup'; import ExternalProgramLauncher from './hardware/externalProgramLauncher'; // eslint-disable-next-line prettier/prettier import PopupHelper from './popup_helper'; import { HardwareMessageData, WebSocketMessage, EntryHardwareBlockModule, UnknownAny, } from '../../types/index'; enum HardwareModuleType { builtIn = 'builtin', module = 'module', } enum HardwareStatement { disconnected = 'disconnected', socketConnected = 'socketConnected', hardwareConnected = 'hardwareConnected', } export default class Hardware { get httpsServerAddress() { return 'https://hw.playentry.org:23518'; } // 하드웨어 프로그램 접속용 주소 get httpsServerAddress2() { return 'https://hardware.playentry.org:23518'; } // legacy get httpServerAddress() { return 'http://127.0.0.1:23518'; } // http 인 오프라인 접속용 주소 get cloudRoomIdKey() { return 'entryhwRoomId'; } private get socketConnectOption() { return { transports: ['websocket', 'polling'], query: { client: true, roomId: this.sessionRoomId, }, }; } // socketIO 및 하드웨어 커넥션용 private readonly sessionRoomId: string; private readonly socketConnectionRetryCount = 3; private reconnectionTimeout: NodeJS.Timeout; private programConnected: boolean; private socket: SocketIOClient.Socket; // 실제 연결된 소켓 private socketMode: number; // entryjs 내 하드웨어모듈 통신용 public portData: UnknownAny; public sendQueue: UnknownAny; // 현재 연결된 모듈 컨트롤용 public hwModule?: EntryHardwareBlockModule; public communicationType: string; // 'manual' || 'auto' private currentDeviceKey?: string; private hwModuleType: HardwareModuleType; private hwMonitor?: HardwareMonitor; // 하드웨어 설치여부 확인용 // public programLauncher 는 ExternalProgramLauncher 만든 iframe view 에서 onload 로 호출한다 public programLauncher: ExternalProgramLauncher; private popupHelper?: PopupHelper; constructor() { const prevRoomId = localStorage.getItem(this.cloudRoomIdKey); this.sessionRoomId = prevRoomId || this._createRandomRoomId(); if (!prevRoomId) { localStorage.setItem(this.cloudRoomIdKey, this.sessionRoomId); } this.programConnected = false; this.communicationType = 'auto'; this.portData = {}; this.sendQueue = {}; this.hwModuleType = HardwareModuleType.builtIn; this._initHardwareObject(); this._addEntryEventListener(); } async _loadExternalHardwareBlock(moduleinfo: { name: string; file: any }) { try { await Entry.moduleManager.loadModuleFromLocalOrOnline(moduleinfo.name); } catch (e) { console.log(e); Entry.toast.alert( Lang.Msgs.hw_module_load_fail_title, `${moduleinfo.name} ${Lang.Msgs.hw_module_load_fail_desc}` ); } } retryConnect() { this._initSocket(); } openHardwareProgram(args?: { [key: string]: string }) { this._alertUnderVersionUsed().then(() => { this._executeHardware(args); if (!this.socket || !this.socket.connected) { setTimeout(() => { this._initSocket(); }, 1000); } }); } /** * 외부 하드웨어 모듈을 등록한다. * 이때 기존 외부 하드웨어 모듈이 추가되어있는 경우를 대비하여, * 현재 보여지고 있는 하드웨어 블록들을 전부 숨김처리한다. * @param moduleObject */ setExternalModule(moduleObject: EntryHardwareBlockModule) { this.hwModule = moduleObject; this.hwModuleType = HardwareModuleType.module; this._banClassAllHardware(); Entry.dispatchEvent('hwChanged'); } /** * 하드웨어 블록메뉴의 노출상태를 변경한다. * 최초 실행시 모든 하드웨어 블록 숨김 / 미연결 상태 버튼 출력 * 현재 하드웨어 로드가 외부 모듈에 의한 것인 경우는 연결이 해제되어도 블록숨김을 실행하지 않는다. */ refreshHardwareBlockMenu() { if (Entry.hwLite.getStatus() !== 'disconnected') { console.log('canel refreshHardwareBlockMenu() for HwLITE'); return; } const workspace = Entry.getMainWS(); const blockMenu = workspace && workspace.blockMenu; if (!blockMenu) { return; } if (!this.hwModule) { // NOTE 이 코드는 하드웨어 블록 초기화 작업도 겸하므로 삭제금지 this._banClassAllHardware(); } const { disconnected, socketConnected, hardwareConnected } = HardwareStatement; if (this.programConnected) { if (this.hwModule) { blockMenu.unbanClass(this.hwModule.name); this._setHardwareDefaultMenu(hardwareConnected); } else { this._setHardwareDefaultMenu(socketConnected); } } else { this._setHardwareDefaultMenu(disconnected); } blockMenu.hwCodeOutdated = true; blockMenu._generateHwCode(true); blockMenu.reDraw(); } disconnectSocket() { if (this.programConnected) { Entry.propertyPanel && Entry.propertyPanel.removeMode('hw'); this.programConnected = false; this.currentDeviceKey = undefined; /* entryjs 내에 존재하던 기존 하드웨어의 경우 원래 프로세스에 따라 연결 종료시 보여주지 않는다. 만약 외부모듈인 경우, 하드웨어가 연결종료 되더라도 블록은 남는다. */ if (this.hwModuleType === HardwareModuleType.builtIn) { this.hwModule = undefined; } this.socket && this.socket.close(); this.socket = undefined; Entry.dispatchEvent('hwChanged'); Entry.toast.alert( Lang.Msgs.hw_connection_termination_title, Lang.Msgs.hw_connection_termination_desc, false ); } } /** * @deprecated */ setDigitalPortValue(port: any, value: any) { console.warn('this function will be deprecated. please use Entry.hw.sendQueue directly.'); this.sendQueue[port] = value; this.removePortReadable(port); } /** * @deprecated */ getAnalogPortValue(port: any) { console.warn('this function will be deprecated. please use Entry.hw.portData directly.'); if (!this.programConnected || !this.hwModule) { return 0; } return this.portData[`a${port}`]; } /** * @deprecated */ getDigitalPortValue(port: any) { console.warn('this function will be deprecated. please use Entry.hw.portData directly.'); if (!this.programConnected || !this.hwModule) { return 0; } this.setPortReadable(port); if (this.portData[port] !== undefined) { return this.portData[port]; } else { return 0; } } /** * @deprecated */ setPortReadable(port: any) { console.warn('this function will be deprecated. please control port state directly.'); if (!this.sendQueue.readablePorts) { this.sendQueue.readablePorts = []; } let isPass = false; for (const i in this.sendQueue.readablePorts) { if (this.sendQueue.readablePorts[i] == port) { isPass = true; break; } } if (!isPass) { this.sendQueue.readablePorts.push(port); } } /** * @deprecated */ removePortReadable(port: any) { console.warn('this function will be deprecated. please use Entry.hw.sendQueue directly.'); if (!this.sendQueue.readablePorts && !Array.isArray(this.sendQueue.readablePorts)) { return; } let target; for (const i in this.sendQueue.readablePorts) { if (this.sendQueue.readablePorts[i] == port) { target = Number(i); break; } } if (target != undefined) { this.sendQueue.readablePorts = this.sendQueue.readablePorts .slice(0, target) .concat( this.sendQueue.readablePorts.slice( target + 1, this.sendQueue.readablePorts.length ) ); } } update() { if (!this.socket || this.socket.disconnected) { return; } if (this.hwModule && this.hwModule.sendMessage) { this.hwModule.sendMessage(this); } else { this._sendSocketMessage({ data: JSON.stringify(this.sendQueue), mode: this.socketMode, type: 'utf8', }); } this.hwModule && this.hwModule.afterSend && this.hwModule.afterSend(this.sendQueue); } closeConnection() { this.socket?.close(); } downloadConnector() { Entry.dispatchEvent('hwDownload', 'hardware'); } downloadGuide() { Entry.dispatchEvent('hwDownload', 'manual'); } downloadSource() { Entry.dispatchEvent('hwDownload', 'ino'); } setZero() { this.hwModule?.setZero(); } /** * 디바이스의 연결상태를 체크한다. * 만약 이미 바로 직전에 동일한 하드웨어와 연결된 경우는 dataHandler 로 데이터를 전송하기만 한다. * 새로운 하드웨어의 연결인 경우는 연결 하드웨어를 치환하고 엔트리에 상태변경을 요청한다. * @param data */ checkDevice(data: HardwareMessageData) { if (data.company === undefined) { return; } const key = `${this._convertHexToString(data.company)}.${this._convertHexToString( data.model )}`; if (this.currentDeviceKey && key === this.currentDeviceKey) { if (this.hwModule && this.hwModule.dataHandler) { this.hwModule.dataHandler(data); } return; } this.currentDeviceKey = key; this.hwModule = Entry.HARDWARE_LIST[key]; if (!this.hwModule) { return; } this.communicationType = this.hwModule.communicationType || 'auto'; this.setDeviceNameContent(true); this._banClassAllHardware(); Entry.dispatchEvent('hwChanged'); if (Entry.propertyPanel && this.hwModule.monitorTemplate) { this._setHardwareMonitorTemplate(); } Entry.toast.success(Lang.Msgs.hw_connection_success, Lang.Msgs.hw_connection_success_desc2); } openHardwareDownloadPopup() { if (Entry.events_.openHardWareDownloadModal) { Entry.dispatchEvent('openHardWareDownloadModal'); } else { this.popupHelper.show('hwDownload', true); } } // INFO: 블록메뉴의 '연결한 하드웨어:' 블럭의 값을 세팅하는 함수. // setName이 true이면 연결된 하드웨어명을, false이면 기본값(없음)으로 세팅한다. setDeviceNameContent(setName: boolean) { const deviceName = setName ? this.hwModule.title[Lang.type] : Lang.Blocks.hardware_device_name_content; if (this.hwModule?.hasPracticalCourse && EntryStatic.isPracticalCourse) { Entry.block.changeBlockText('hardware_device_name_content_sensor', deviceName); Entry.block.changeBlockText('hardware_device_name_content_motor', deviceName); Entry.block.changeBlockText('hardware_device_name_content_led', deviceName); Entry.block.changeBlockText('hardware_device_name_content_melody', deviceName); } else { Entry.block.changeBlockText('hardware_device_name_content', deviceName); } } private _initHardwareObject() { const { hardwareEnable } = Entry; this.popupHelper = createHardwarePopup(() => { this.downloadConnector(); }); hardwareEnable && this._initSocket(); } private _addEntryEventListener() { // hwChanged 에 걸려있는 다른 이벤트 함수와 동일선상에 두기위함 Entry.addEventListener('hwChanged', this.refreshHardwareBlockMenu.bind(this)); Entry.addEventListener('stop', this.setZero.bind(this)); } private _createRandomRoomId() { return 'xxxxxxxxyx'.replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0; const v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); } private _trySocketConnect(url: string) { return new Promise((resolve, reject) => { const socket = io.connect(url, this.socketConnectOption); socket.io.reconnectionAttempts(this.socketConnectionRetryCount); socket.io.reconnectionDelayMax(1000); socket.io.timeout(1000); socket.on('connect', () => { this._handleSocketConnected(socket); resolve(); }); socket.on('reconnect_failed', () => { reject(); }); }); } private _handleSocketConnected(socket: SocketIOClient.Socket) { socket.removeEventListener('reconnect_failed'); socket.removeEventListener('connect'); // this._initHardware(socket); this.socket = socket; this._setSocketConnected(); if (Entry.playground && Entry.playground.object) { Entry.playground.setMenu(Entry.playground.object.objectType); } socket.on('connect', () => { this._setSocketConnected(); }); socket.on('mode', (mode: number) => { if (this.socketMode === 0 && mode === 1) { this._disconnectHardware(); } this.socketMode = mode; }); const messageHandler = new HardwareSocketMessageHandler(socket); messageHandler.addEventListener('init', this._loadExternalHardwareBlock.bind(this)); messageHandler.addEventListener('state', async (statement, name) => { /* statement 로는 before_connect, connected 등 하드웨어 프로그램의 상태 전부가 오지만 WS 에서는 connected 외에 전부 socketConnected 상태로 머무르게 된다. */ switch (statement) { case 'disconnectHardware': this._disconnectHardware(); break; case 'connected': // init action 과 동일동작 await this._loadExternalHardwareBlock(name); break; default: break; } }); // 1.7.0 버전 이전 하드웨어 프로그램 종료로직 대응으로 남겨두어야 한다. messageHandler.addEventListener('disconnect', this._disconnectHardware.bind(this)); messageHandler.addEventListener('data', (portData: HardwareMessageData) => { this.portData = portData; this.checkDevice(portData); this._updatePortData(portData); if (this.hwModule && this.hwModule.afterReceive) { this.hwModule.afterReceive(portData); } }); socket.on('disconnect', () => { // cloud PC 연결 클릭시 순간 disconnect 되고 재연결을 시도하기 위한 로직 this._setSocketClosed(); this.reconnectionTimeout = setTimeout(() => { this._initSocket(); }, 1500); }); socket.on('reconnect_failed', () => { this._setSocketClosed(); }); } private _setSocketConnected() { this.programConnected = true; console.log('Hardware Program Connected'); // 하드웨어 프로그램 연결 성공, 스테이터스 변화 필요 Entry.dispatchEvent('hwChanged'); } private _setSocketClosed(needRedraw: boolean = true) { this.programConnected = false; this.hwModule = undefined; this.currentDeviceKey = undefined; needRedraw && Entry.dispatchEvent('hwChanged'); } /** * 이미 연결했던 소켓이 존재한다면 재연결을 시도한다. * 연결성공했던 소켓이 없다면 전체 리스트를 순회하며 연결을 시도한다. * @private */ private _initSocket() { if (this.socket) { if (this.reconnectionTimeout) { clearTimeout(this.reconnectionTimeout); this.reconnectionTimeout = undefined; } this.socket.io.reconnection(true); this.socket.connect(); } else { const connectionTries = [this.httpsServerAddress, this.httpsServerAddress2]; // http 혹은 파일시스템 프로토콜에서 동작하는 경우, 로컬호스트 를 최우선 연결시도 한다. if (['http:', 'file:'].indexOf(location.protocol) > -1) { connectionTries.unshift(this.httpServerAddress); } else { connectionTries.push(this.httpServerAddress); } // 주소에 담겨져있는 순서대로 소켓 연결을 요청한다. connectionTries .reduce>(async (prevPromise, address) => { const prevResult = await prevPromise; if (prevResult) { return true; } // NOTE : 하드웨어 웹연결과 충돌을 방지 if (Entry.hwLite.getStatus() !== 'disconnected') { console.log('canel connectionTry for HwLITE'); return; } try { await this._trySocketConnect(address); return true; } catch (e) { return !!(this.programConnected || this.socket); } }, undefined) .then((result) => { // 하드웨어 소켓 연결 시도 결과 반환 로직 if (!result) { console.warn('All hardware socket connection failed'); this._setSocketClosed(); } }) .catch(() => { console.error('Error occurred while try to connect hardware socket'); }); } } /** * 하드웨어 버튼 노출상태를 변경한다. * @param statement {HardwareStatement} * @private */ private _setHardwareDefaultMenu(statement: HardwareStatement) { const workspace = Entry.getMainWS(); const blockMenu = workspace && workspace.blockMenu; if (!blockMenu) { return; } const { disconnected, socketConnected, hardwareConnected } = HardwareStatement; switch (statement) { case disconnected: blockMenu.unbanClass('arduinoDisconnected', true); blockMenu.banClass('arduinoConnected', true); blockMenu.banClass('arduinoConnect', true); Entry.hwLite?.isHwLiteSupportAgent() ? blockMenu.unbanClass('arduinoLiteSupported', true) : blockMenu.banClass('arduinoLiteSupported', true); break; case socketConnected: blockMenu.banClass('arduinoLiteSupported', true); blockMenu.banClass('arduinoDisconnected', true); blockMenu.banClass('arduinoConnected', true); blockMenu.unbanClass('arduinoConnect', true); break; case hardwareConnected: blockMenu.banClass('arduinoLiteSupported', true); blockMenu.banClass('arduinoDisconnected', true); blockMenu.unbanClass('arduinoConnected', true); blockMenu.banClass('arduinoConnect', true); break; } } /** * 모든 하드웨어를 숨김처리한다. 현재 연결된 하드웨어도 예외는 없다. * @private */ private _banClassAllHardware() { const workspace = Entry.getMainWS(); const blockMenu = workspace && workspace.blockMenu; if (!blockMenu) { return; } Object.values(Entry.HARDWARE_LIST || {}).forEach((hardware: any) => { blockMenu.banClass(hardware.name, true); }); } private _disconnectHardware() { if (this.hwModule) { Entry.propertyPanel && Entry.propertyPanel.removeMode('hw'); this.currentDeviceKey = undefined; this.hwModule = undefined; this.setDeviceNameContent(false); Entry.dispatchEvent('hwChanged'); Entry.toast.alert( Lang.Msgs.hw_connection_termination_title, Lang.Msgs.hw_connection_termination_desc, false ); } } private _sendSocketMessage(message: WebSocketMessage) { if (this.programConnected && this.socket && !this.socket.disconnected) { this.socket.emit('message', message); } } private _updatePortData(data: HardwareMessageData) { if (this.hwMonitor && Entry.propertyPanel && Entry.propertyPanel.selected === 'hw') { this.hwMonitor.update(data, this.sendQueue); } } private _setHardwareMonitorTemplate() { if (!this.hwMonitor) { this.hwMonitor = new HardwareMonitor(this.hwModule); } else { this.hwMonitor.setHwModule(this.hwModule); this.hwMonitor.initView(); } Entry.propertyPanel.addMode('hw', this.hwMonitor); this.hwMonitor.generateViewByMode(); } /** * 버전 공지용 함수. * 1.9.0 버전으로 올라가면서 SSL 인증서 문제로 과거버전은 소켓연결에 문제가 있음. * 그에 따른 조치이기 때문에 추후 유저들이 1.9.0 버전의 사용비중이 높아진다면 삭제해도 무방하다. * @returns {Promise} * @private */ private _alertUnderVersionUsed() { return new Promise((resolve) => { const dontShowChecked = localStorage.getItem('skipNoticeHWOldVersion'); if (!dontShowChecked) { const title = Lang.Msgs.hardware_need_update_title; const content = Lang.Msgs.hardware_need_update_content; Entry.modal .alert(content, title, { withDontShowAgain: true, }) .then((data: { dontShowChecked: boolean }) => { const { dontShowChecked } = data || {}; if (dontShowChecked) { localStorage.setItem('skipNoticeHWOldVersion', 'true'); } resolve(null); }); } else { resolve(null); } }); } private _executeHardware(args?: { [key: string]: string }) { this.programLauncher = new ExternalProgramLauncher(); const customSchemaArgsString = Object.entries({ roomId: this.sessionRoomId, ...args, }).reduce( (result, [key, value]) => result === '' ? `${key}:${value}` : `${result}&${key}:${value}`, '' ); const entryHardwareUrl = `entryhw://?${customSchemaArgsString}`; console.log('request Hardware using url custom schema.. : ', entryHardwareUrl); this.programLauncher.executeUrl(entryHardwareUrl, () => this.openHardwareDownloadPopup()); } private _convertHexToString(num: number | string) { if (typeof num === 'string') { return num.toUpperCase(); } return num.toString(16).toUpperCase(); } } Entry.HW = Hardware; ================================================ FILE: src/class/hw_lite.ts ================================================ import { EntryHWLiteBaseModule, HWLiteStatus } from '../../types/index'; import ExtraBlockUtils from '../util/extrablockUtils'; import HardwareMonitor from './hardware/hardwareMonitor'; import WebUsbFlasher from './hardware/webUsbFlasher'; import WebSerialConnector from './hardware/webSerialConnector'; import WebApiConnector from './hardware/webApiConnector'; import WebBluetoothConnector from './hardware/webBluetoothConnector'; const ARDUINO_BOARD_IDS: string[] = ['010101', '040201', '080101']; export default class HardwareLite { private status: HWLiteStatus; private webConnector: WebApiConnector; private serial: WebSerialConnector; private bluetooth: WebBluetoothConnector; private flasher: WebUsbFlasher; hwModule: EntryHWLiteBaseModule; static setExternalModule: any; static refreshHardwareLiteBlockMenu: any; static banClassAllHardwareLite: any; static isHwLiteSupportAgent: any; private playground: any; private hwMonitor?: HardwareMonitor; static getStatus: any; private customPromptPayload: String; constructor(playground: any) { this.playground = playground; this.hwModule = null; this.status = 'disconnected'; Entry.addEventListener('hwLiteChanged', this.refreshHardwareLiteBlockMenu.bind(this)); this.setExternalModule.bind(this); } setZero() { this.hwModule?.setZero(); } isActive(name: string) { if (this.hwModule) { const data = {}; // @ts-ignore data[name] = this.hwModule; return ExtraBlockUtils.isActive(name, data); } return false; } /** * 모든 하드웨어를 숨김처리한다. 현재 연결된 하드웨어도 예외는 없다. * @private */ banClassAllHardwareLite() { const workspace = Entry.getMainWS(); const blockMenu = workspace && workspace.blockMenu; if (!blockMenu) { return; } Object.values(Entry.HARDWARE_LITE_LIST || {}).forEach((hardware: any) => { blockMenu.banClass(hardware.name, true); }); ExtraBlockUtils.banAllBlocks(this.playground, Entry.HARDWARE_LITE_LIST); blockMenu.reDraw(); } setExternalModule(moduleObject: EntryHWLiteBaseModule) { this.hwModule = moduleObject; this.banClassAllHardwareLite(); Entry.block.changeBlockText('hardware_device_name_content', this.hwModule.title.ko); Entry.dispatchEvent('hwLiteChanged'); this.setWebConnector(); this.setFlasher(); if (Entry.propertyPanel && this.hwModule.monitorTemplate) { this._setHardwareMonitorTemplate(); } } getConnectFailedMenu() { this.status = 'connectFailed'; this.refreshHardwareLiteBlockMenu(); } setFirmwareDownloadButton(callback: Function) { const workspace = Entry.getMainWS(); const blockMenu = workspace && workspace.blockMenu; if (!blockMenu) { return; } Entry.block.changeBlockEvent('arduino_lite_download_firmware', 'mousedown', async () => { await callback(); }); blockMenu.changeTypeThreadByBlockKey('arduino_lite_download_firmware'); } private _setHardwareMonitorTemplate() { if (!this.hwMonitor) { this.hwMonitor = new HardwareMonitor(this.hwModule); } else { this.hwMonitor.setHwModule(this.hwModule); this.hwMonitor.initView(); } Entry.propertyPanel.addMode('hw', this.hwMonitor); this.hwMonitor.generateViewByMode(); } _updatePortData() { if (this.hwMonitor && Entry.propertyPanel && Entry.propertyPanel.selected === 'hw') { this.hwMonitor.update(this.hwModule.getMonitorPort(), null); } } isHwLiteSupportAgent() { const userAgentString = navigator.userAgent.toLowerCase(); // INFO: 디바이스가 모바일이거나 일렉트론이면 1차적으로 제외 if (userAgentString.includes('mobile') || userAgentString.includes('electron')) { return false; } else if ( userAgentString.includes('whale') || userAgentString.includes('edge') || userAgentString.includes('chrome') ) { return true; } else { return false; } } refreshHardwareLiteBlockMenu() { const blockMenu = Entry.getMainWS()?.blockMenu; if (!blockMenu) { return; } switch (this.status) { case 'disconnected': { blockMenu.banClass('arduinoLiteConnected', true); blockMenu.banClass('arduinoLiteConnectFailed', true); blockMenu.banClass('arduinoLiteGuide', true); blockMenu.unbanClass('arduinoLiteDisconnected', true); blockMenu.unbanClass('arduinoDisconnected', true); this.isHwLiteSupportAgent() ? blockMenu.unbanClass('arduinoLiteSupported', true) : blockMenu.banClass('arduinoLiteSupported', true); this.banClassAllHardwareLite(); break; } case 'connected': blockMenu.banClass('arduinoLiteConnectFailed', true); blockMenu.banClass('arduinoLiteDisconnected', true); blockMenu.banClass('arduinoDisconnected', true); blockMenu.banClass('arduinoLiteSupported', true); blockMenu.banClass('arduinoLiteGuide', true); blockMenu.unbanClass('arduinoLiteConnected', true); blockMenu.unbanClass(this.hwModule?.name, true); break; case 'connectFailed': blockMenu.banClass('arduinoLiteDisconnected', true); blockMenu.banClass('arduinoLiteConnected', true); blockMenu.banClass('arduinoDisconnected', true); blockMenu.banClass('arduinoLiteSupported', true); blockMenu.unbanClass('arduinoLiteConnectFailed', true); if (typeof this.hwModule?.id === 'string') { if (ARDUINO_BOARD_IDS.includes(this.hwModule.id)) { blockMenu.unbanClass('arduinoLiteGuide', true); } } // else if (this.hwModule?.id instanceof Array) { // for (const id in this.hwModule.id) { // if (ARDUINO_BOARD_IDS.includes(this.hwModule.id[id])) { // blockMenu.unbanClass('arduinoLiteGuide', true); // break; // } // } // } this.banClassAllHardwareLite(); break; } blockMenu.hwCodeOutdated = true; blockMenu._generateHwCode(true); blockMenu.reDraw(); } async connect() { if (this.status === 'connected') { return; } try { await this.webConnector.connect(); this.setStatus('connected'); this.refreshHardwareLiteBlockMenu(); await this.webConnector.initialDevice(); Entry.toast.success( Lang.Msgs.hw_connection_success, Lang.Msgs.hw_connection_success_desc2 ); } catch (error) { console.error(error); Entry.toast.alert( Lang.Msgs.hw_connection_failed_title, Lang.Msgs.hw_connection_failed_desc, false ); this.getConnectFailedMenu(); } } async disconnect() { try { Entry.hardwareLiteBlocks = []; this.status = 'willDisconnect'; await this.webConnector?.disconnect(); } catch (err) { console.error(err); } finally { this.hwModule = null; this.customPromptPayload = null; this.status = 'disconnected'; this.removeWebConnector(); this.removeFlasher(); Entry.dispatchEvent('hwLiteChanged'); Entry.toast.alert( Lang.Msgs.hw_connection_termination_title, Lang.Msgs.hw_connection_termination_desc, false ); } } addHardwareLiteModule(module: EntryHWLiteBaseModule) { Entry.do('objectAddHardwareLiteBlocks', module); } removeHardwareLiteModule() { Entry.do('objectRemoveHardwareLiteBlocks', this.hwModule); } setWebConnector() { const webapiType = this.hwModule.webapiType; switch (webapiType) { case 'ble': { if (!this.hwModule.bluetoothInfo) { console.error('Invalid bluetooth hwModule'); this.getConnectFailedMenu(); return; } this.bluetooth = new WebBluetoothConnector(this.hwModule, this); this.webConnector = this.bluetooth; break; } case 'serial': case undefined: { if (!this.hwModule.portData) { console.error('Invalid serial hwModule'); this.getConnectFailedMenu(); return; } this.serial = new WebSerialConnector(this.hwModule, this); this.webConnector = this.serial; } } } removeWebConnector() { this.webConnector = undefined; this.serial = undefined; this.bluetooth = undefined; } setFlasher() { if (this.hwModule.supportFirmwareFlash) { this.flasher = new WebUsbFlasher(); } } removeFlasher() { this.flasher = undefined; } getStatus() { return this.status; } setStatus(state: HWLiteStatus) { this.status = state; } getCustomPromptPayload() { return this.customPromptPayload; } setCustomPromptPayload(payload: String) { this.customPromptPayload = payload; } // INFO: customPrompt 테스트용. entryjs 단독으로 테스트하는 경우 아래 함수를 사용 testCustomPromptPayload() { if (!this.hwModule) { window.alert('"Entry.hwLite.hwModule" is not set. use "addHardwareLiteModule" first.'); return; } if (!this.hwModule.customPrompt) { window.alert( 'Entry.hwLite.hwModule.customPrompt is not set. check your hardware module.' ); return; } const payload = window.prompt( `${this.hwModule.customPrompt.title} \n ${this.hwModule.customPrompt.description}`, this.hwModule.customPrompt.defaultValue || '' ); this.setCustomPromptPayload(payload); console.log('Entry.hwLite.customPromptPayload : ', this.customPromptPayload); } } Entry.HWLite = HardwareLite; ================================================ FILE: src/class/intro.ts ================================================ /** * 프로퍼티 패널쪽에서 프로젝트의 속성을 보여주는 뷰를 담당 * @use entry-lms */ import { IEntry } from '../../types/index'; class EntryIntro implements IEntry.Intro { public modes: any = {}; public selected: any = undefined; private view_?: any; generateView(introView: any) { this.view_ = introView; this.view_.addClass('entryPlaygroundIntro'); } setView(view: any) { if (this.view_.firstChild) { this.view_.removeChild(this.view_.firstChild); } this.view_.addClass('active'); view.appendTo(this.view_); Entry.windowResized.notify(); } removeView() { if (this.view_.firstChild) { this.view_.removeChild(this.view_.firstChild); } this.view_.removeClass('active'); } } export default EntryIntro; Entry.Intro = EntryIntro; ================================================ FILE: src/class/learning/Chart.js ================================================ import { BillBoard, Tree } from '@entrylabs/tool'; export default class LearningChart { constructor(modalData, type = 'chart') { if (type === 'tree') { this.modal = this.createTree(modalData); } else { this.modal = this.createChart(modalData); } this.modal.show(); } show() { this.modal.show(); } hide() { this.modal.hide(); } destroy() { this.modal.hide(); this.modal = null; } load(data) { this.modal.setData(data); } createChart({ title = '', description = '', source }) { const container = Entry.Dom('div', { class: 'entry-learning-chart', parent: $(Entry.modalContainer), })[0]; return new BillBoard({ data: { source, title, description, togglePause: () => Entry.engine.togglePause(), stop: () => Entry.engine.toggleStop(), isIframe: self !== top, }, container, }); } createTree({ title = '', source }) { const container = Entry.Dom('div', { class: 'entry-learning-chart', parent: $(Entry.modalContainer), })[0]; return new Tree({ data: { source, title, togglePause: () => Entry.engine.togglePause(), stop: () => Entry.engine.toggleStop(), isIframe: self !== top, }, container, }); } } ================================================ FILE: src/class/learning/Cluster.js ================================================ import { kmpp } from 'skmeans/kinit'; // import { kmpp } from 'skmeans/dist/node/kinit'; import floor from 'lodash/floor'; import _toNumber from 'lodash/toNumber'; import _isNaN from 'lodash/isNaN'; import LearningView from './LearningView'; import Chart from './Chart'; import DataTable from '../DataTable'; const GRAPH_COLOR = [ '#4f80ff', '#f16670', '#6e5ae6', '#00b6b1', '#9fbaff', '#fcad93', '#c5b4ff', '#b3c3cd', '#2d51ac', '#a23941', '#423496', '#2a7d7f', ]; export const classes = [ 'ai_learning_train', 'ai_learning_cluster', 'cluster_attr_1', 'cluster_attr_2', 'cluster_attr_3', 'cluster_attr_4', 'cluster_attr_5', 'cluster_attr_6', 'ai_learning_train_chart', ]; class Cluster { #attrLength = 0; #trainParam = null; #result = {}; #table = {}; #trainCallback; #chart = null; #isTrained = false; #chartEnable = false; #view = null; #predictResult = null; #fields = []; #name = ''; constructor(params = {}) { this.#view = new LearningView({ name: params.name || '', status: 0 }); // 정지시 data 초기화. Entry.addEventListener('stop', () => { this.init({ ...params }); }); this.init({ ...params }); } init({ name, result, table, trainParam }) { this.#name = name; this.#trainParam = trainParam; this.#result = result; this.#table = table; this.#trainCallback = (value) => { this.#view.setValue(value); }; this.#isTrained = true; this.#attrLength = table?.select?.[0]?.length || 0; if (this.#attrLength === 2) { this.#chartEnable = true; } this.#fields = table?.select?.[0]?.map((index) => table?.fields[index]); } setTable() { const tableSource = DataTable.getSource(this.#table.id); if (this.#table?.fieldsInfo?.length !== tableSource?.fields?.length) { Entry.toast.alert(Lang.Msgs.warn, Lang.AiLearning.train_param_error); throw Error(Lang.AiLearning.train_param_error); } this.#table.data = tableSource.rows; } destroy() { this.#view.destroy(); if (this.#chart) { this.#chart.destroy(); this.#chart = null; } } setVisible(visible) { this.#view.setVisible(visible); } unbanBlocks(blockMenu) { blockMenu.unbanClass(`ai_learning_train`); blockMenu.unbanClass(`ai_learning_cluster`); blockMenu.unbanClass(`cluster_attr_${this.#attrLength}`); if (this.#chartEnable) { blockMenu.unbanClass('ai_learning_train_chart'); } } isTrained() { return this.#isTrained; } openChart() { if (!this.#chartEnable) { return; } if (!this.#chart) { const { k } = this.#trainParam; this.#chart = new Chart({ source: this.chartData, title: Lang.AiLearning.chart_title, description: ` ${Lang.AiLearning.cluster_number} ${k} ${this.#fields.map( (field, index) => `${Lang.AiLearning.model_attr_str} ${index + 1}${field}` )} `, }); } else { this.#chart.show(); } } closeChart() { this.#chart?.hide(); } setTrainOption(type, value) { this.#trainParam = { ...this.#trainParam, [type]: value, }; } getTrainOption() { return this.#trainParam; } getTrainResult() { return this.#result; } getResult() { return this.#predictResult; } train() { this.setTable(); this.#trainCallback(1); this.#isTrained = false; const { data, select } = this.#table; const filtered = data.filter( (row) => !select.flat().some((selected) => _isNaN(_toNumber(row[selected]))) ); const [attr] = select; const { centroids, indexes } = kmeans( filtered.map((row) => attr.map((i) => parseFloat(row[i]) || 0)), this.#trainParam ); this.#result = { graphData: convertGraphData(filtered, centroids, indexes, attr), centroids, }; this.#isTrained = true; const { k } = this.#trainParam; this.#chart?.load({ source: this.chartData, description: ` ${Lang.AiLearning.cluster_number} ${k} ${this.#fields.map( (field, index) => `${Lang.AiLearning.model_attr_str} ${index + 1}${field}` )} `, }); this.#trainCallback(100); } predict(arr = []) { if (!this.isTrained) { return; } const { k } = this.#trainParam; const { centroids } = this.#result; this.#predictResult = predictCluster(arr, k, centroids) + 1; return this.#predictResult; } findColor(id, a, b) { const { centroids, graphData } = this.#result; if (id === 'y') { const { type = 0 } = graphData?.find(({ x, y }) => String(x) === String(a) && String(y) === String(b)) || {}; return GRAPH_COLOR[type]; } else if (id === 'centroid' && b) { const type = centroids?.findIndex(([x]) => String(x) === String(a)) || 0; return GRAPH_COLOR[type]; } return undefined; } get chartData() { return { data: { type: 'scatter', json: this.#result.graphData, keys: { value: ['y', 'centroid'], x: 'x' }, color: (color, d) => this.findColor(d.id, d.x, d.value) || color, labels: false, }, options: { point: { pattern: [ 'circle', // eslint-disable-next-line max-len "", ], }, legend: { show: false, }, tooltip: { contents: (data) => { const [{ x, value, id }] = data; if (id === 'centroid' && value) { const { centroids } = this.#result; const type = centroids?.findIndex(([a, b]) => x === a && value === b); return `
${Lang.AiLearning.centriod} ${type + 1}| ${ this.#fields[0] }: ${x}, ${this.#fields[1]}: ${value}
`; } return `
${this.#fields[0]}: ${x}, ${this.#fields[1]}: ${value}
`; }, }, axis: { x: { tick: { fit: false, count: 5, }, }, }, grid: { x: { show: true, }, y: { show: true, }, }, }, }; } } export default Cluster; function convertGraphData(data, centroids, indexes, attr) { return data .map((cur, index) => cur.reduce( (acc, cur, idx) => { if (idx === attr[0]) { acc.x = cur; } else if (idx === attr[1]) { acc.y = cur; } return acc; }, { index, type: indexes[index] } ) ) .concat( centroids.map(([x = 0, centroid = 0], type) => ({ x, centroid, type, })) ); } function eudist(a, b) { let sum = 0; for (let i = 0; i < a.length; i++) { const d = (a[i] || 0) - (b[i] || 0); sum += d * d; } return sum; } function predictCluster(arr, k, centroids) { let min = Infinity; let closestCentroidIndex = 0; for (let i = 0; i < k; i++) { const dist = eudist(arr, centroids[i]); if (dist < min) { min = dist; closestCentroidIndex = i; } } return closestCentroidIndex; } function kmeans(inputs, trainParam) { const dim = inputs[0].length; let centroids = []; if (!trainParam.initialCentroids) { const _idxs = {}; while (centroids.length < trainParam.k) { const idx = Math.floor(Math.random() * inputs.length); if (!_idxs[idx]) { _idxs[idx] = true; centroids.push(inputs[idx].slice()); } } } else if (trainParam.initialCentroids === 'random') { const maxs = new Array(dim).fill(-Infinity); const mins = new Array(dim).fill(Infinity); for (let i = 0; i < dim; i++) { for (let j = 0; j < inputs.length; j++) { if (inputs[j][i] < mins[i]) { mins[i] = inputs[j][i]; } if (inputs[j][i] > maxs[i]) { maxs[i] = inputs[j][i]; } } } for (let i = 0; i < trainParam.k; i++) { const temp = []; for (let j = 0; j < dim; j++) { temp.push(Math.random() * (maxs[j] - mins[j]) + mins[j]); } centroids.push(temp); } } else if (trainParam.initialCentroids === 'kmpp') { centroids = kmpp( inputs.map((e) => e.slice()), trainParam.k ); } else { centroids = trainParam.initialCentroids; } let indexes = new Array(inputs.length).fill(0); let iter = 0; let maxIter = trainParam.maxIter || 10000; let conv = false; while (!conv && iter < maxIter) { // copy old centroids let oldCentroids = centroids.map((e) => e.slice()); // set inputs idx (closest centroid index) for (let i = 0; i < inputs.length; i++) { indexes[i] = predictCluster(inputs[i], trainParam.k, centroids); } // move centroid to avg inputs let sums = Array.from(new Array(trainParam.k), () => new Array(dim).fill(0)); let counts = new Array(trainParam.k).fill(0); for (let i = 0; i < inputs.length; i++) { counts[indexes[i]]++; for (let j = 0; j < dim; j++) { sums[indexes[i]][j] += inputs[i][j]; } } for (let i = 0; i < trainParam.k; i++) { for (let j = 0; j < dim; j++) { centroids[i][j] = floor(sums[i][j] / counts[i], 2); } } // check conv let centroidsUpdateDistance = 0; centroids.forEach((e, i) => { centroidsUpdateDistance += eudist(e, oldCentroids[i]); }); if (centroidsUpdateDistance === 0) { conv = true; } if (trainParam.onIterEnd) { trainParam.onIterEnd( oldCentroids.map((e) => e.slice()), centroids.map((e) => e.slice()) ); } iter++; } return { iter, indexes, centroids, }; } ================================================ FILE: src/class/learning/DecisionTree.js ================================================ import * as tf from '@tensorflow/tfjs'; import _floor from 'lodash/floor'; import _max from 'lodash/max'; import _sum from 'lodash/sum'; import _mean from 'lodash/mean'; import _toNumber from 'lodash/toNumber'; import _isNaN from 'lodash/isNaN'; import LearningBase from './LearningBase'; import { DecisionTreeClassifier as DTClassifier } from 'ml-cart'; import Utils from './Utils'; import Chart from './Chart'; export const classes = [ 'ai_learning_train', 'ai_learning_decisiontree', 'decisiontree_attr_1', 'decisiontree_attr_2', 'decisiontree_attr_3', 'decisiontree_attr_4', 'decisiontree_attr_5', 'decisiontree_attr_6', ]; class DecisionTree extends LearningBase { type = 'decisiontree'; init({ name, url, result, table, trainParam, modelId, loadModel }) { this.name = name; this.trainParam = trainParam; this.result = result; this.table = table; this.loadModel = loadModel; this.trainCallback = (value) => { this.view.setValue(value); }; this.trained = true; this.attrLength = table?.select?.[0]?.length || 0; this.fields = table?.select?.[0]?.map((index) => table?.fields[index]); this.predictFields = table?.select?.[1]?.map((index) => table?.fields[index]); if (this.url !== url || this.modelId !== modelId) { this.load(url, modelId); this.url = url; this.modelId = modelId; } if (!Utils.isWebGlSupport()) { tf.setBackend('cpu'); } } generateTree() { const { graphData, fields, valueMap } = this.result; this.tree = new Chart( { source: { graphData, fields, valueMap, }, title: Lang.AiLearning.tree_title, }, 'tree' ); } openChart() { if (!this.tree) { this.generateTree(); } else { this.tree.show(); } } closeChart() { this.tree?.hide(); } destroy() { if (this.tree) { this.tree.destroy(); this.tree = null; } super.destroy(); } async train() { this.setTable(); this.trained = false; if (this.tree) { this.tree.destroy(); this.tree = null; } this.trainCallback(1); const { testRate = 0.2, maxDepth = 3, minNumSamples = 3, epochs = 1, batchSize = 1, } = this.trainParam; const { trainX, trainY, testArr, select, fields, valueMap, numClass } = getData( testRate, this.table ); this.valueMap = Object.fromEntries( Object.entries(valueMap).map(([key, value]) => [value, key]) ); this.model = createModel(maxDepth, minNumSamples); this.model?.train(trainX, trainY); const { confusionMatrix, score } = evaluate(this.model, testArr, numClass); this.trained = true; this.trainCallback(100); const { accuracy, f1, precision, recall } = score; this.result = { graphData: this.model.toJSON().root, select, fields, confusionMatrix, accuracy, f1, valueMap: this.valueMap, precision, recall, }; } async load(url, modelId) { const data = await this.loadModel({ url, modelId }); if (!data) { return; } const { model, result } = data; this.model = DTClassifier.load(model); this.valueMap = result?.valueMap; this.result = { ...result, graphData: this.model?.toJSON().root, }; } async predict(array) { if (!this.model) { throw new Error("can't predict: no model"); } const xs = [array]; const preds = this.model.predict(xs); this.predictResult = preds.map((target) => ({ className: this.valueMap[target + 1], probability: 1, })); } } export default DecisionTree; function createModel(maxDepth, minNumSamples) { return new DTClassifier({ gainFunction: 'gini', // 'gini' Only maxDepth, minNumSamples, }); } function getData(testRate = 0.2, data) { const tempMap = {}; const tempMapCount = {}; const { select = [[0], [1]], data: table, fields } = data; const [attr, predict] = select; const filtered = table.filter( (row) => !select[0].some((selected) => _isNaN(_toNumber(row[selected]))) ); const dataArray = filtered .map((row) => ({ x: attr.map((i) => parseFloat(row[i]) || 0), y: Utils.stringToNumber(predict[0], row[predict[0]], tempMap, tempMapCount), })) .map((row) => ({ x: row.x, y: row.y - 1, })); const [train, test] = sliceArray(dataArray, testRate); return { trainX: train.map((v) => v.x), trainY: train.map((v) => v.y), testArr: test, select, fields, valueMap: { ...tempMap[predict[0]] }, numClass: tempMapCount[predict[0]] || 1, }; } function sliceArray(dataArray, testRate) { Utils.shuffle(dataArray); const testNum = Math.floor(dataArray.length * testRate); const testArr = dataArray.slice(0, testNum); const trainArr = dataArray.slice(testNum, dataArray.length); return [trainArr, testArr]; } function evaluate(model, validateData = [{ x: 0, y: 0 }], numClass) { const xs = validateData.map((data) => data.x); const ys = validateData.map((data) => data.y); const predictYs = model.predict(xs); const length = predictYs.length; // Confusion Matrix 생성 const confusionMatrix = Array(numClass) .fill(0) .map(() => Array(numClass).fill(0)); for (let idx = 0; idx < length; idx++) { confusionMatrix[ys[idx]][predictYs[idx]]++; } const score = Utils.getScores(confusionMatrix, numClass); return { confusionMatrix, score }; } ================================================ FILE: src/class/learning/ImageLearning.js ================================================ import * as tf from '@tensorflow/tfjs'; import VideoUtils from '@entrylabs/legacy-video'; import MediaPipeUtils from '../../util/mediaPipeUtils'; const mediaPipeUtils = MediaPipeUtils.getInstance(); export const classes = [ 'ai_learning_image' ]; const SCALAR_VALUE = 127.5; const SIZE = 224; class ImageLearning { #type = null; #url = ''; #labels = []; #popup = null; #result = []; #axis = 0; #isPredicting = false; #captureCanvas; #captureTimeoutClear; constructor({ url, labels, type }) { this.#type = type; this.#url = url; this.#labels = labels; this.load(url); Entry.addEventListener('stop', () => { this.#result = []; this.#isPredicting = false; }); if (!isWebGlSupport()) { tf.setBackend('cpu'); } } get labels() { return this.#labels; } getResult(index) { const result = this.#result.length ? this.#result : this.#popup?.result || []; const defaultResult = { probability: 0, className: '' }; if (index !== undefined && index > -1) { return ( result.find(({ className }) => className === this.#labels[index]) || defaultResult ); } return result[0] || defaultResult; } unbanBlocks(blockMenu) { blockMenu.unbanClass(`ai_learning_classification`); if (this.#type) { blockMenu.unbanClass(`ai_learning_${this.#type}`); } } openInputPopup() { Entry.dispatchEvent('openMLInputPopup', { type: 'image', predict: async (canvas) => { this.#result = await this.predict(canvas); }, url: this.#url, labels: this.#labels, setResult: (result) => { this.#result = result; }, }); } getVideo() { if (VideoUtils.isInitialized) { return VideoUtils.video; } if (mediaPipeUtils.isInitialized) { return mediaPipeUtils.video; } return null; } async startPredict() { if (!this.isLoaded || this.#isPredicting) { return false; } this.#isPredicting = true; if (!this.captureCanvas) { this.#captureCanvas = document.createElement('canvas'); this.#captureCanvas.width = SIZE; this.#captureCanvas.height = SIZE; } this.#captureTimeoutClear = Entry.Utils.asyncAnimationFrame(async () => { const video = this.getVideo(); if (!video) { return; } const context = this.#captureCanvas.getContext('2d'); context.drawImage(video, 0, 0, SIZE, SIZE); this.#result = await this.predict(this.#captureCanvas); }); return this.#result; } async predict(canvas) { tf.engine().startScope(); const tensor = await this.preprocess(canvas); const logits = this.model.predict(tensor); const result = await this.namePredictions(logits); logits.dispose(); tf.engine().endScope(); return result; } stopPredict() { this.#result = []; this.#isPredicting = false; this.#captureTimeoutClear && this.#captureTimeoutClear(); } async namePredictions(logits) { const values = Array.from(await logits.data()); return values .map((probability, index) => ({ className: this.#labels[index] || index, probability, })) .sort((a, b) => a.probability > b.probability ? -1 : a.probability < b.probability ? 1 : 0); } async preprocess(canvas) { return tf.tidy(() => { const offset = tf.scalar(SCALAR_VALUE); return tf.browser .fromPixels(canvas) .toFloat() .sub(offset) .div(offset) .expandDims(this.#axis); }); } async load(url) { this.model = await tf.loadLayersModel(url); this.isLoaded = true; } async reload(url) { this.model = await tf.loadLayersModel(url || this.#url); this.isLoaded = true; } } export default ImageLearning; function isWebGlSupport() { try { const currentCanvas = document.createElement('canvas'); return !!currentCanvas.getContext('webgl', { premultipliedalpha: false }); } catch (e) { console.log('error', e); return false; } } ================================================ FILE: src/class/learning/InputPopup.js ================================================ import PopupHelper from '../popup_helper'; const MlPopup = class InputPopup { #popupKey = 'ai_learning'; constructor(source) { this.generatePopupView(source); } open() { this.popupHelper.show(this.#popupKey); } generatePopupView({ url, labels, type, recordTime, setResult }) { if (!this.popupHelper) { if (window.popupHelper) { this.popupHelper = window.popupHelper; } else { this.popupHelper = new PopupHelper(true); } } let isPauseClicked = false; this.popupHelper.addPopup(this.#popupKey, { type: 'confirm', title: Lang.Blocks.learn_popup_title, onShow: () => { this.popupHelper.addClass('learning_popup'); isPauseClicked = false; localStorage.setItem( this.#popupKey, JSON.stringify({ url, labels, type, recordTime }) ); this.isLoading = true; setResult && setResult([]); if (Entry.engine.state == 'run') { Entry.engine.togglePause({ visible: false }); } }, closeEvent: () => { this.isLoading = false; if (Entry.engine.state == 'pause' && !isPauseClicked) { Entry.engine.togglePause({ visible: false }); } }, setPopupLayout: (popup) => { const content = Entry.Dom('div', { class: 'contentArea', }); const iframe = Entry.Dom('iframe', { class: `learningInputPopup ${type}`, src: `/learning/popup/${type}` }); $(iframe).on('load', ({ target }) => { target.contentWindow.addEventListener( 'message', ({ data: eventData = {} }) => { if (typeof eventData !== 'string') { return; } const { key, data } = JSON.parse(eventData); if (key === 'predict') { setResult && setResult(data); this.popupHelper.hide(); } if (key === 'stop') { this.popupHelper.hide(); Entry.engine.toggleStop(); } if (key === 'pause') { if (!isPauseClicked) { isPauseClicked = true; Entry.engine.togglePause({ visible: false }); } Entry.engine.togglePause(); } if (key === 'error') { this.popupHelper.hide(); this.toastError(); } }, false ); }); content.append(iframe); popup.append(content); }, }); } toastError() { Entry.toast.alert(Lang.Msgs.warn, Lang.Msgs.ai_utilize_train_pop_error, true); } }; export default MlPopup; ================================================ FILE: src/class/learning/LearningBase.ts ================================================ import LearningView from './LearningView'; import DataTable from '../DataTable'; type Table = { id: string; fieldsInfo: Array; data: Array; }; class LearningBase { type = 'base'; attrLength = 0; name: string = ''; view?: LearningView = null; trained: boolean = false; chartEnable: boolean = false; fields: Array = []; predictFields: Array = []; result = {}; loadModel: () => {}; table: Table; trainParam: any = null; trainCallback: (value: any) => void; chart: any = null; predictResult: any = null; constructor(params: any = {}) { this.view = new LearningView({ name: params.name || '', status: 0 }); // 정지시 data 초기화. Entry.addEventListener('stop', () => { this.init({ ...params }); }); this.init({ ...params }); } init({ name, result, table, trainParam }: any) { this.name = name; this.trainParam = trainParam; this.result = result; this.table = table; this.trainCallback = (value: any) => { this.view.setValue(value); }; this.trained = true; this.attrLength = table?.select?.[0]?.length || 0; if (this.attrLength === 2) { this.chartEnable = true; } this.fields = table?.select?.[0]?.map((index: number) => table?.fields[index]); } isTrained() { return this.trained; } setTable() { const tableSource = DataTable.getSource(this.table.id); if (this.table?.fieldsInfo?.length !== tableSource?.fields?.length) { Entry.toast.alert(Lang.Msgs.warn, Lang.AiLearning.train_param_error); throw Error(Lang.AiLearning.train_param_error); } this.table.data = tableSource.rows; } destroy() { this.view.destroy(); if (this.chart) { this.chart.destroy(); this.chart = null; } } setVisible(visible: boolean) { this.view.setVisible(visible); } unbanBlocks(blockMenu: any) { blockMenu.unbanClass(`ai_learning_train`); blockMenu.unbanClass(`ai_learning_${this.type}`); blockMenu.unbanClass(`${this.type}_attr_${this.attrLength}`); if (this.chartEnable) { blockMenu.unbanClass('ai_learning_train_chart'); } } openChart() { if (!this.chartEnable) { return; } if (!this.chart) { this.generateChart(); } else { this.chart.show(); } } closeChart() { this.chart?.hide(); } setTrainOption(type: string, value: any) { this.trainParam = { ...this.trainParam, [type]: value, }; } getTrainOption() { return this.trainParam; } getTrainResult() { return this.result; } getResult() { return this.predictResult; } generateChart() { throw new Error('Method not implemented.'); } train() { throw new Error('Method not implemented.'); } load() { throw new Error('Method not implemented.'); } predict() { throw new Error('Method not implemented.'); } } export default LearningBase; ================================================ FILE: src/class/learning/LearningView.js ================================================ import { GEHelper } from '../../graphicEngine/GEHelper'; import { GEDragHelper } from '../../graphicEngine/GEDragHelper'; const GL_VAR_POS = { VALUE_Y: -8.5, LABEL_Y: -8, STATUS_Y: 8, }; const STATUS = { READY: 0, LEARNING: 1, DONE: 2, NO_MODEL: 3, }; export default class LearningView { constructor({ name = 'model name', status = STATUS.NO_MODEL, value = 0 } = {}) { this.id = Entry.generateHash(); this.visible = true; this.value = value; const fontFamily = EntryStatic.fontFamily || "NanumGothic, 'Nanum Gothic'"; this.BORDER = 6; this.FONT = `10pt ${fontFamily}`; this.VALUE_FONT = `9pt ${fontFamily}`; this.name = name; this.status = status; this.generateView(); Entry.addEventListener('stop', () => { this.view_.visible = true; this.visible = true; this.setValue(0); }); } setX(x) { this.x_ = x; this.updateView(); } getX() { return this.x_; } setY(y) { this.y_ = y; this.updateView(); } getY() { return this.y_; } isVisible() { return this.visible; } setVisible(visibleState) { this.view_.visible = visibleState; this.visible = visibleState; this.updateView(); } setValue(value) { this.value = value; if (value == 0) { this.status = STATUS.READY; } else if (value === 100) { this.status = STATUS.DONE; } else if (value < 100) { this.status = STATUS.LEARNING; } this.updateView(); } getValue() { return this.value; } destroy() { Entry.stage.removeVariable(this); } setStatus(status) { this.status = status; this.updateView(); } generateView(variableIndex = 0) { this.view_ = GEHelper.newContainer(); this.rect_ = GEHelper.newGraphic(); this.view_.addChild(this.rect_); this.view_.variable = this; this.view_.visible = this.visible; this.view_.mouseEnabled = true; GEDragHelper.handleDrag(this.view_); this.wrapper_ = GEHelper.newGraphic(); this.view_.addChild(this.wrapper_); this.textView_ = GEHelper.textHelper.newText(this.name, this.FONT, '#000000', 'alphabetic'); this.textView_.x = 4; if (GEHelper.isWebGL) { this.textView_.y = GL_VAR_POS.LABEL_Y; } else { this.textView_.y = 1; } this.view_.addChild(this.textView_); this.statusView = GEHelper.textHelper.newText( Lang.AiLearning[`model_status_${this.status}`], this.FONT, '#000000', 'alphabetic' ); this.statusView.x = 4; if (GEHelper.isWebGL) { this.statusView.y = GL_VAR_POS.STATUS_Y; } else { this.statusView.y = 15; } this.view_.addChild(this.statusView); this.view_.on(GEDragHelper.types.DOWN, function(evt) { if (Entry.type !== 'workspace') { return; } this.offset = { x: this.x - (evt.stageX * 0.75 - 240), y: this.y - (evt.stageY * 0.75 - 135), }; }); this.view_.on(GEDragHelper.types.MOVE, function(evt) { if (Entry.type !== 'workspace') { return; } this.variable.setX(evt.stageX * 0.75 - 240 + this.offset.x); this.variable.setY(evt.stageY * 0.75 - 135 + this.offset.y); this.variable.updateView(); }); let width = this.textView_.getMeasuredWidth() + 26; width = Math.max(width, 90); this.maxWidth = width - 20; this.slideBar_ = GEHelper.newGraphic(); this.slideBar_.graphics .beginFill('#d8d8d8') .s('#d8d8d8') .ss(1) .rr(6, 28, this.maxWidth, 5, 2); this.view_.addChild(this.slideBar_); const visibleValue = (this.value / 100) * this.maxWidth; this.valueBar = GEHelper.newGraphic(); if (visibleValue > 0) { this.valueBar.graphics .beginFill('#4f80ff') .s('#4f80ff') .ss(1) .rr(6, 28, visibleValue, 5, 2); } this.view_.addChild(this.valueBar); const variableLength = Entry.variableContainer.variables_.length; if (this.getX() && this.getY()) { this.setX(this.getX()); this.setY(this.getY()); } else { this.setX(10 - 240 + Math.floor(variableLength / 11) * 80); this.setY(variableIndex * 24 + 20 - 135 - Math.floor(variableLength / 11) * 264); } this.setVisible(this.isVisible()); Entry.stage.loadVariable(this); } updateView() { if (!this.view_) { return; } if (this.isVisible()) { this._adjustSingleViewPosition(); const oldContent = this.textView_.text; let newContent = this.name; if (oldContent !== newContent) { this.textView_.text = newContent; this._nameWidth = null; } if (!this._nameWidth) { this._nameWidth = this.textView_.getMeasuredWidth(); } const oldStatus = this.statusView.text; let newStatus = Lang.AiLearning[`model_status_${this.status}`]; if (oldStatus !== newStatus) { this.statusView.text = newStatus; } let width = this._nameWidth + 35; const colorSet = EntryStatic.colorSet.canvas || {}; width = Math.max(width, 90); this.rect_.graphics .clear() .f('#ffffff') .ss(1, 2, 0) .s(colorSet.border || '#aac5d5') .rr(0, -14, width, 54, 4); width = this._nameWidth + 26; width = Math.max(width, 90); this.maxWidth = width - 16; const visibleValue = (this.value / 100) * this.maxWidth; this.slideBar_.graphics .clear() .beginFill('#d8d8d8') .s('#d8d8d8') .ss(1) .rr(6, 28, this.maxWidth + 4, 5, 2); if (visibleValue > 0) { this.valueBar.graphics .clear() .beginFill('#4f80ff') .s('#4f80ff') .ss(1) .rr(6, 28, visibleValue, 5, 2); } } Entry.requestUpdate = true; } _adjustSingleViewPosition() { this.view_.x = this.getX(); this.view_.y = this.getY(); } } ================================================ FILE: src/class/learning/LogisticRegression.js ================================================ import * as tf from '@tensorflow/tfjs'; import _floor from 'lodash/floor'; import _max from 'lodash/max'; import _sum from 'lodash/sum'; import _mean from 'lodash/mean'; import _toNumber from 'lodash/toNumber'; import _isNaN from 'lodash/isNaN'; import LearningBase from './LearningBase'; import Utils from './Utils'; export const classes = [ 'ai_learning_train', 'ai_learning_logistic_regression', 'logistic_regression_attr_1', 'logistic_regression_attr_2', 'logistic_regression_attr_3', 'logistic_regression_attr_4', 'logistic_regression_attr_5', 'logistic_regression_attr_6', ]; class LogisticRegression extends LearningBase { type = 'logistic_regression'; init({ name, url, result, table, trainParam }) { this.name = name; this.trainParam = trainParam; this.result = result; this.table = table; this.trainCallback = (value) => { this.view.setValue(value); }; this.trained = true; this.attrLength = table?.select?.[0]?.length || 0; if (this.attrLength === 1) { this.chartEnable = true; } if (this.url !== url) { this.load(url); this.url = url; } this.fields = table?.select?.[0]?.map((index) => table?.fields[index]); this.predictFields = table?.select?.[1]?.map((index) => table?.fields[index]); if (!Utils.isWebGlSupport()) { tf.setBackend('cpu'); } } async load(url) { const model = await tf.loadLayersModel(url); const modelData = new Promise((resolve) => model.save({ save: (data) => { const layers = data?.modelTopology?.config?.layers; if (Array.isArray(layers)) { data.modelTopology.config.layers.forEach((layer) => { if (layer?.config?.name) { layer.config.name = `${layer.config.name}_ws`; } }); } if (Array.isArray(data.weightSpecs)) { data.weightSpecs.forEach((spec) => { const splits = spec.name.split('/'); splits[0] = `${splits[0]}_ws`; spec.name = splits.join('/'); }); } resolve(data); }, }) ); this.model = await tf.loadLayersModel({ load: () => modelData }); model.dispose(); } async reload(url) { this.model = await tf.loadLayersModel(url || this.url); this.isLoaded = true; } async train() { this.setTable(); this.trained = false; let currentEpoch = 0; let percent = 0; this.trainCallback(1); const { validationRate = 0.25, testRate = 0.2 } = this.trainParam; const { trainData, validateData, testArr, select, fields, valueMap, dataLength, numClass, } = getData(validationRate, testRate, this.table, this.trainParam); this.valueMap = Object.fromEntries( Object.entries(valueMap).map(([key, value]) => [value, key]) ); this.model = createModel(dataLength, numClass); this.lastHistory = await trainModel( this.model, trainData, validateData, this.trainParam, () => { currentEpoch = currentEpoch + 1; percent = _floor((currentEpoch / this.trainParam.epochs) * 100); this.trainCallback(Math.min(percent, 100)); } ); const { score, confusionMatrix } = await this.evaluate( this.model, testArr, valueMap, numClass ); const { accuracy, f1, precision, recall } = score; this.trained = true; this.result = { select, fields, confusionMatrix, accuracy, f1, valueMap: this.valueMap, precision, recall, }; } async predict(array) { if (!this.model) { throw new Error("can't predict: no model"); } const xs = tf.tensor([array]); const preds = this.model.predict(xs); const resultArray = preds.arraySync(); const valueMap = this.result?.valueMap || {}; this.predictResult = resultArray .map((arr) => arr.map((probability, index) => ({ probability: _floor(probability, 3), className: valueMap[index + 1], })) ) .flat(); } async evaluate(model, validateData = [{ x: 0, y: 0 }], classMap, numClass) { const evalData = validateData; const xs = tf.tensor(Array.from(evalData, (evalData) => evalData.x)); const ys = tf.tensor(Array.from(evalData, (evalData) => evalData.y)).argMax(-1); const preds = model.predict(xs); const pred = preds.argMax(-1); const confusionMatrixZip = await tf.math.confusionMatrix(ys, pred, numClass); const matrixArray = Array.from(confusionMatrixZip.dataSync()); const confusionMatrix = Utils.arrayToMatrix(matrixArray, numClass); const score = Utils.getScores(confusionMatrix, numClass); return { score, confusionMatrix, }; } } export default LogisticRegression; function createModel(inputShape, numClasses = 1) { const model = tf.sequential({ layers: [ tf.layers.dense({ name: 'log_dense_ws', inputShape: [inputShape], units: numClasses, activation: numClasses === 2 ? 'sigmoid' : 'softmax', useBias: false, kernelInitializer: tf.initializers.varianceScaling({}), }), ], }); return model; } async function trainModel(model, inputs, outputs, trainParam, onEpochEnd) { const { batchSize = 0, epochs = 0, optimizer: optimizerStr = 'adm', learningRate = 0.1, } = trainParam; const optimizer = optimizerStr === 'adm' ? tf.train.adam(learningRate * 1) : tf.train.sgd(learningRate * 1); model.compile({ optimizer, loss: tf.losses.meanSquaredError, metrics: ['acc', 'ce'], }); return await model.fitDataset(inputs.batch(batchSize * 1), { epochs: epochs * 1, validationData: outputs.batch(batchSize * 1), callbacks: { onEpochEnd, }, }); } function getData(validationRate, testRate, data, trainParam) { const tempMap = {}; const tempMapCount = {}; const { select = [[0], [1]], data: table, fields } = data; const [attr, predict] = select; const filtered = table.filter( (row) => !select[0].some((selected) => _isNaN(_toNumber(row[selected]))) ); const dataArray = filtered .map((row) => ({ x: attr.map((i) => parseFloat(row[i]) || 0), y: Utils.stringToNumber(predict[0], row[predict[0]], tempMap, tempMapCount), })) .map((row) => { const yRow = Array(tempMapCount[predict[0]]).fill(0); yRow[row.y - 1] = 1; return { x: row.x, y: yRow, }; }); const [train, validate, test] = sliceArray(dataArray, validationRate, testRate); return { trainData: arrayToZip(train), validateData: arrayToZip(validate), testArr: test, select, fields, valueMap: { ...tempMap[predict[0]] }, dataLength: attr.length, numClass: tempMapCount[predict[0]], }; } function sliceArray(dataArray, validationRate = 0.25, testRate = 0.2) { Utils.shuffle(dataArray); const testNum = dataArray.length - Math.floor(dataArray.length * testRate); const validateNum = Math.floor(testNum * validationRate); const validateArr = dataArray.slice(0, validateNum); const trainArr = dataArray.slice(validateNum, testNum); const testArr = dataArray.slice(testNum, dataArray.length); return [trainArr, validateArr, testArr]; } function arrayToZip(array) { const xs = tf.data.array(array.map((v) => v.x)); const ys = tf.data.array(array.map((v) => v.y)); return tf.data.zip({ xs, ys }); } ================================================ FILE: src/class/learning/NumberClassification.js ================================================ import LearningView from './LearningView'; import Chart from './Chart'; import _uniq from 'lodash/uniq'; import _floor from 'lodash/floor'; import _sum from 'lodash/sum'; import _mean from 'lodash/mean'; import _toNumber from 'lodash/toNumber'; import _isNaN from 'lodash/isNaN'; import DataTable from '../DataTable'; export const classes = [ 'ai_learning_train', 'ai_learning_number', 'number_learning_attr_1', 'number_learning_attr_2', 'number_learning_attr_3', 'number_learning_attr_4', 'number_learning_attr_5', 'number_learning_attr_6', ]; class NumberClassification { #attrLength = 0; #trainParam = null; #table = {}; #trainCallback; #chart = null; #isTrained = false; #chartEnable = false; #view = null; #predictResult = null; #name = ''; #fields = []; #predictField = []; #loadModel; constructor(params = {}) { this.#view = new LearningView({ name: params.name || '', status: 0 }); // 정지시 data 초기화. Entry.addEventListener('stop', () => { this.init({ ...params }); }); this.init({ ...params }); } init({ name, url, table, trainParam, modelId, loadModel, result }) { this.#name = name; this.#table = table; this.result = result; this.#trainCallback = (value) => { this.#view.setValue(value); }; this.#isTrained = true; this.#loadModel = loadModel; this.#attrLength = table?.select?.[0]?.length || 0; this.#fields = table?.select?.[0]?.map((index) => table?.fields[index]); this.#predictField = table?.select?.[1]?.map((index) => table?.fields[index]); if (this.#attrLength === 2) { this.#chartEnable = true; } if (this.url !== url || this.modelId !== modelId) { // load시 trainParam에 추가되는 파라미터가 있어서 로드 직전 추가. this.#trainParam = trainParam; this.load(url, modelId); this.url = url; this.modelId = modelId; } } setTable() { const tableSource = DataTable.getSource(this.#table.id); if (this.#table?.fieldsInfo?.length !== tableSource?.fields?.length) { Entry.toast.alert(Lang.Msgs.warn, Lang.AiLearning.train_param_error); throw Error(Lang.AiLearning.train_param_error); } this.#table.data = tableSource.rows; } destroy() { this.#view.destroy(); if (this.#chart) { this.#chart.destroy(); this.#chart = null; } } createColor() { return this.#trainParam.labels.reduce( (acc, cur, idx, arr) => ({ ...acc, [cur]: Entry.Utils.randomColor(), }), {} ); } setVisible(visible) { this.#view.setVisible(visible); } unbanBlocks(blockMenu) { blockMenu.unbanClass(`ai_learning_train`); blockMenu.unbanClass(`ai_learning_number`); blockMenu.unbanClass(`number_learning_attr_${this.#attrLength}`); if (this.#chartEnable) { blockMenu.unbanClass('ai_learning_train_chart'); } } isTrained() { return this.#isTrained; } openChart() { if (!this.#chartEnable) { return; } if (!this.#chart) { this.#chart = new Chart({ title: Lang.AiLearning.chart_title, description: `${Lang.AiLearning.class} ${this.#predictField[0]}${ Lang.AiLearning.model_attr_str } 1${this.#fields[0]}${Lang.AiLearning.model_attr_str} 2${ this.#fields[1] }`, source: this.chartData, }); } else { this.#chart.show(); } } closeChart() { this.#chart?.hide(); } setTrainOption(type, value) { this.trainParam = { ...this.trainParam, [type]: value, }; } getTrainOption() { return this.#trainParam; } getResult() { return this.#predictResult; } getTrainResult() { return this.result; } getLabels() { const { data: trainData, labels } = convertTableToKnnData(this.#table); return _uniq(labels[0]).sort((a, b) => String(a).localeCompare(String(b))); } train() { this.setTable(); this.#trainCallback(1); this.#isTrained = false; const { data: trainData, labels } = convertTableToKnnData(this.#table); const trainLabels = labels[0]; const uniqLabels = _uniq(labels[0]).sort((a, b) => String(a).localeCompare(String(b))); const numLabels = uniqLabels.length; const maxVector = new Array(trainData[0].length).fill(-Infinity); trainData.forEach((e) => { for (let i = 0; i < maxVector.length; i++) { maxVector[i] = maxVector[i] > e[i] ? maxVector[i] : e[i]; } }); const minVector = new Array(trainData[0].length).fill(Infinity); trainData.forEach((e) => { for (let i = 0; i < minVector.length; i++) { minVector[i] = minVector[i] < e[i] ? minVector[i] : e[i]; } }); this.#trainParam = { ...this.#trainParam, trainData, trainLabels, labels: uniqLabels, numLabels, maxVector, minVector, }; this.#isTrained = true; this.colors = this.createColor(); this.#chart?.load({ source: this.chartData, }); this.#trainCallback(100); } async load(url, modelId) { const savedData = await this.#loadModel({ url, modelId }); if (!savedData) { return; } this.#trainParam = { ...this.#trainParam, trainData: savedData.data, trainLabels: savedData.labels, labels: _uniq(savedData.labels).sort((a, b) => String(a).localeCompare(String(b)) ), maxVector: savedData.maxVector, minVector: savedData.minVector, numLabels: savedData.numLabels, neighbors: savedData.neighbors, isLoaded: true, }; this.colors = this.createColor(); } normalize(data = []) { const normData = []; const { minVector, maxVector } = this.#trainParam; for (let i = 0; i < data.length; i++) { normData.push((data[i] - minVector[i]) / (maxVector[i] - minVector[i])); } return normData; } predict(data) { const distData = []; const { trainData, trainLabels, neighbors } = this.#trainParam; for (let i = 0; i < trainData.length; i++) { const dist = eudist(this.normalize(data), this.normalize(trainData[i])); distData.push({ index: i, dist, label: trainLabels[i], }); } distData.sort((a, b) => a.dist - b.dist); const counts = {}; for (let i = 0; i < neighbors; i++) { const { label, dist } = distData[i]; if (!counts[label]) { counts[label] = []; } counts[label].push(dist); } const totalDistance = _sum(Object.values(counts).flat()); this.#predictResult = Object.keys(counts) .map((className) => { const dist = _mean(counts[className]); const count = counts[className].length; const distProbability = totalDistance === 0 ? 1 : (totalDistance - dist) / totalDistance; const probability = (count / neighbors) * 99 + distProbability; return { className, count, probability, }; }) .sort((a, b) => b.probability - a.probability); return this.#predictResult; } findLabel(x, y) { const strX = String(x); const strY = String(y); const index = this.#trainParam.trainData.findIndex( (row) => String(row[0]) === strX && String(row[1]) === strY ); return this.#trainParam.trainLabels[index]; } findColor(id, a, b) { if (id === 'y') { return this.colors[this.findLabel(a, b)]; } return undefined; } get chartData() { const json = this.#trainParam.trainData.map((row, idx) => ({ x: row[0], y: row[1], index: this.#trainParam.trainLabels[idx], })); return { data: { type: 'scatter', json, keys: { value: ['y'], x: 'x' }, color: (color, d) => this.findColor(d.id, d.x, d.value) || color, labels: false, }, options: { point: { pattern: ['circle'], }, legend: { show: false, }, tooltip: { contents: (data) => { const [{ x, value }] = data; const label = this.findLabel(x, value); return `
${Lang.AiLearning.class}: ${label}, ${this.#fields[0]}: ${x}, ${ this.#fields[1] }: ${value}
`; }, }, axis: { x: { tick: { fit: false, count: 10, }, }, }, grid: { x: { show: true, }, y: { show: true, }, }, }, }; } } export default NumberClassification; function eudist(a, b) { let sum = 0; for (let i = 0; i < a.length; i++) { const d = (a[i] || 0) - (b[i] || 0); sum += d * d; } return sum; } function convertTableToKnnData(tableData = {}) { const { select = [[0], [1]], data: table = [] } = tableData; const [attr, predict] = select; const filtered = table.filter( (row) => !select[0].some((selected) => _isNaN(_toNumber(row[selected]))) ); return filtered.reduce( (accumulator, row) => { const { data = [], labels = [] } = accumulator; return { data: [...data, row.filter((data, index) => attr.includes(index))], labels: predict.map((i, idx) => { const arr = labels[idx] || []; return [...arr, row[i]]; }), }; }, { data: [], labels: [] } ); } ================================================ FILE: src/class/learning/Regression.js ================================================ import * as tf from '@tensorflow/tfjs'; import _floor from 'lodash/floor'; import _max from 'lodash/max'; import Chart from './Chart'; import _sum from 'lodash/sum'; import _mean from 'lodash/mean'; import _toNumber from 'lodash/toNumber'; import _isNaN from 'lodash/isNaN'; import LearningBase from './LearningBase'; import Utils from './Utils'; export const classes = [ 'ai_learning_train', 'ai_learning_regression', 'regression_attr_1', 'regression_attr_2', 'regression_attr_3', 'regression_attr_4', 'regression_attr_5', 'regression_attr_6', 'ai_learning_train_chart', ]; class Regression extends LearningBase { type = 'regression'; init({ name, url, result, table, trainParam }) { this.name = name; this.trainParam = trainParam; this.result = result; this.table = table; this.trainCallback = (value) => { this.view.setValue(value); }; this.trained = true; this.attrLength = table?.select?.[0]?.length || 0; if (this.attrLength === 1) { this.chartEnable = true; } if (this.url !== url) { this.load(url); this.url = url; } this.fields = table?.select?.[0]?.map((index) => table?.fields[index]); this.predictFields = table?.select?.[1]?.map((index) => table?.fields[index]); if (!Utils.isWebGlSupport()) { tf.setBackend('cpu'); } } generateChart() { this.chart = new Chart({ source: this.chartData, title: Lang.AiLearning.chart_title, description: ` ${this.fields.map( (field, index) => `${Lang.AiLearning.model_attr_str} ${index + 1}: ${field}` )} ${Lang.AiLearning.predict}${this.predictFields[0]}${ Lang.AiLearning.equation }${this.result.equation} `, }); } async train() { try { this.setTable(); this.trained = false; let currentEpoch = 0; let percent = 0; this.trainCallback(1); const { inputs, outputs } = convertToTfData(this.table, this.trainParam); const { model, trainHistory, a, b, graphData = [], rsquared, normResult } = await train( inputs, outputs, this.trainParam, undefined, () => { currentEpoch = currentEpoch + 1; percent = _floor((currentEpoch / this.trainParam.epochs) * 100); this.trainCallback(Math.min(percent, 100)); } ); this.model = model; const { acc = [] } = trainHistory?.history || {}; const accuracy = _max(acc) || 0; const graphPoints = (graphData.originalPoints || []).slice(0, 1000); if (inputs.length == 1) { graphData.predictedPoints.map(({ x, y }, i) => { let index = graphPoints.sort((a, b) => a.x - b.x).findIndex((p) => p.x >= x); if (index < 0 && i > 0) { index = graphPoints.length - 1; } if (graphPoints[index]) { graphPoints[index].equation = y; } }); } this.result = { graphData: graphPoints, accuracy, normResult, rsquared, equation: `Y = ${a .map((a, i) => `${addSign(a)}X${i + 1}`) .join('')} ${addSign(b)}`, }; this.trained = true; this.chart?.load({ source: this.chartData, description: ` ${this.fields.map( (field, index) => `${Lang.AiLearning.model_attr_str} ${index + 1} ${field}` )} ${Lang.AiLearning.predict} ${this.predictFields[0]}${ Lang.AiLearning.equation }${this.result.equation} `, }); } catch (e) { console.log('train error', e); } } async load(url) { const model = await tf.loadLayersModel(url); const modelData = new Promise((resolve) => model.save({ save: (data) => { const layers = data?.modelTopology?.config?.layers; if (Array.isArray(layers)) { data.modelTopology.config.layers.forEach((layer) => { if (layer?.config?.name) { layer.config.name = `${layer.config.name}_ws`; } }); } if (Array.isArray(data.weightSpecs)) { data.weightSpecs.forEach((spec) => { const splits = spec.name.split('/'); splits[0] = `${splits[0]}_ws`; spec.name = splits.join('/'); }); } resolve(data); }, }) ); this.model = await tf.loadLayersModel({ load: () => modelData }); model.dispose(); } convertNomalResult() { const { inputMin, inputMax, outputMax, outputMin } = this.result.normResult; if (!Array.isArray(inputMin)) { return this.result.normResult; } return { inputMin: tf.tensor1d(inputMin), inputMax: tf.tensor1d(inputMax), outputMax: tf.tensor1d(outputMax), outputMin: tf.tensor1d(outputMin), }; } async predict(data) { tf.engine().startScope(); const { inputMin, inputMax, outputMax, outputMin } = this.convertNomalResult(); const result = tf.tidy(() => { let convertedData; if (Array.isArray(data)) { convertedData = tf.tensor2d([data]); } else { convertedData = tf.tensor1d([data]); } convertedData = convertedData.sub(inputMin).div(inputMax.sub(inputMin)); const preds = this.model .predict(convertedData) .mul(outputMax.sub(outputMin)) .add(outputMin); const [result] = preds.dataSync(); this.predictResult = _floor(result, 2); preds.dispose(); return this.predictResult; }); tf.engine().endScope(); return result; } get chartData() { return { data: { json: this.result.graphData, keys: { value: ['equation', 'y'], x: 'x' }, types: { y: 'scatter', equation: 'line', }, }, options: { legend: { show: false, }, tooltip: { contents: (data) => { const [{ x, value, id }] = data; return `
${this.fields[0]}: ${x}, ${this.predictFields[0]}: ${value}
`; }, }, line: { connectNull: true, point: false, }, axis: { x: { tick: { fit: false, count: 15, }, }, }, grid: { x: { show: true, }, y: { show: true, }, }, }, }; } } export default Regression; function addSign(x) { return x < 0 ? x : `+${x}`; } function convertToTfData(data, trainParam) { const { select = [[0], [1]], data: table } = data; const [attr, predict] = select; const { epochs = 1, batchSize = 1 } = trainParam; const filtered = table.filter( (row) => !select.flat().some((selected) => _isNaN(_toNumber(row[selected]))) ); const totalDataSize = Math.ceil(filtered.length / batchSize) * epochs; return filtered.reduce( (accumulator, row) => { const { inputs = [], outputs = [] } = accumulator; return { inputs: attr.map((i, idx) => { const arr = inputs[idx] || []; return [...arr, parseFloat(row[i]) || 0]; }), outputs: predict.map((i, idx) => { const arr = outputs[idx] || []; return [...arr, parseFloat(row[i]) || 0]; }), totalDataSize, }; }, { inputs: [], outputs: [] } ); } function convertToTensor(inputs, outputs) { return tf.tidy(() => { const inputTensor = tf.tensor2d(inputs).transpose(); const outputTensor = tf.tensor2d(outputs).transpose(); const inputMax = inputTensor.max(0); const inputMin = inputTensor.min(0); const outputMax = outputTensor.max(0); const outputMin = outputTensor.min(0); // (d - min) / (max - min) const normalizedInputs = inputTensor.sub(inputMin).div(inputMax.sub(inputMin)); const normalizedOutputs = outputTensor.sub(outputMin).div(outputMax.sub(outputMin)); return { inputs: normalizedInputs, outputs: normalizedOutputs, inputMax, inputMin, outputMax, outputMin, }; }); } function createModel(inputShape) { const model = tf.sequential(); model.add(tf.layers.dense({ inputShape: [inputShape], units: 1, name: 'reg_dense_ws' })); return model; } async function trainModel(model, inputs, outputs, trainParam, onBatchEnd, onEpochEnd) { model.compile({ optimizer: tf.train.adam(trainParam.learningRate), loss: tf.losses.meanSquaredError, metrics: ['mse', 'acc', 'ce'], }); return await model.fit(inputs, outputs, { batchSize: trainParam.batchSize, epochs: trainParam.epochs, shuffle: trainParam.shuffle, validationSplit: trainParam.validationRate, callbacks: { onBatchEnd, onEpochEnd, }, }); } const TEST_POINT_COUNT = 2; function testModel(model, normalizationData) { const { inputMin, inputMax, outputMin, outputMax } = normalizationData; const [xs, preds] = tf.tidy(() => { const xs = tf.linspace(0, 1, TEST_POINT_COUNT); const preds = model.predict(xs.reshape([TEST_POINT_COUNT, 1])); // d * (max - min) + min const unNormXs = xs.mul(inputMax.sub(inputMin)).add(inputMin); // @ts-ignore const unNormPreds = preds.mul(outputMax.sub(outputMin)).add(outputMin); return [unNormXs.dataSync(), unNormPreds.dataSync()]; }); return Array.from(xs).map((val, i) => ({ x: val, y: preds[i], })); } function getR2Score(model, normResult, y) { const yData = y[0]; const yHat = model .predict(normResult.inputs) .mul(normResult.outputMax.sub(normResult.outputMin)) .add(normResult.outputMin) .dataSync(); const yMean = yData.reduce((acc, cur) => acc + cur) / yData.length; const ssr = yHat .map((e, index) => (e - yData[index]) * (e - yData[index])) .reduce((acc, cur) => acc + cur); const sst = yData.map((e) => (e - yMean) * (e - yMean)).reduce((acc, cur) => acc + cur); const r2 = 1 - ssr / sst; return Math.max(r2, 0); } async function train(inputs, outputs, trainParam, onBatchEnd, onEpochEnd) { const normResult = convertToTensor(inputs, outputs); const model = createModel(inputs.length); const history = await trainModel( model, normResult.inputs, normResult.outputs, trainParam, onBatchEnd, onEpochEnd ); // @ts-ignore const weight = model.layers[0].weights[0].val; // @ts-ignore const bias = model.layers[0].weights[1].val; const inputMin = normResult.inputMin; const inputMax = normResult.inputMax; const outputMin = normResult.outputMin; const outputMax = normResult.outputMax; const o = outputMax.sub(outputMin); const oi = o.div(inputMax.sub(inputMin)); const a = oi.mul(weight.transpose()); const b = bias .mul(o) .add(outputMin) .sub(a.matMul(inputMin.expandDims(0).transpose())); const r2 = getR2Score(model, normResult, outputs); const graphData = { originalPoints: [], predictedPoints: [], }; if (inputs.length === 1) { graphData.originalPoints = inputs[0].map((e, i) => ({ x: e, y: outputs[0][i], })); graphData.predictedPoints = testModel(model, normResult); } return { model, normResult, trainHistory: history, a: Array.from(a.dataSync()).map((x) => _floor(x, 2)), b: _floor(b.dataSync()[0], 2), rsquared: _floor(r2, 2), graphData, }; } ================================================ FILE: src/class/learning/SpeechClassification.js ================================================ import * as tf from '@tensorflow/tfjs'; export const classes = ['ai_learning_speech']; class Classification { #type = null; #url = ''; #labels = []; #recordTime = 2000; #result = []; constructor({ url, labels, type, recordTime }) { this.#type = type; this.#url = url; this.#labels = labels; this.#recordTime = recordTime; this.load(url); } get labels() { return this.#labels; } getResult(index) { const result = this.#result || []; const defaultResult = { probability: 0, className: '' }; if (index !== undefined && index > -1) { return ( result.find(({ className }) => className === this.#labels[index]) || defaultResult ); } return result[0] || defaultResult; } unbanBlocks(blockMenu) { blockMenu.unbanClass(`ai_learning_classification`); if (this.#type) { blockMenu.unbanClass(`ai_learning_${this.#type}`); } } openInputPopup() { Entry.dispatchEvent('openMLInputPopup', { type: this.#type, recordTime: this.#recordTime, predict: async (data) => { this.#result = await this.predict(data); }, url: this.#url, labels: this.#labels, setResult: (result) => { this.#result = result; }, }); } async namePredictions(logits) { const values = Array.from(await logits.data()); return values .map((probability, index) => ({ className: this.#labels[index] || index, probability, })) .sort((a, b) => a.probability > b.probability ? -1 : a.probability < b.probability ? 1 : 0); } async predict(tensor) { const logits = this.model.predict(tensor); return await this.namePredictions(logits); } async load(url) { this.model = await tf.loadLayersModel(url); } async reload(url) { this.model = await tf.loadLayersModel(url || this.#url); this.isLoaded = true; } } export default Classification; ================================================ FILE: src/class/learning/Svm.js ================================================ import LearningBase from './LearningBase'; import _floor from 'lodash/floor'; import _max from 'lodash/max'; import _sum from 'lodash/sum'; import _mean from 'lodash/mean'; import _toNumber from 'lodash/toNumber'; import _isNaN from 'lodash/isNaN'; import Utils from './Utils'; const SVM = require('libsvm-js/asm'); export const classes = [ 'ai_learning_train', 'ai_learning_svm', 'svm_attr_1', 'svm_attr_2', 'svm_attr_3', 'svm_attr_4', 'svm_attr_5', 'svm_attr_6', ]; export const KERNEL_STRING_TYPE = { LINEAR: 'linear', POLYNOMIAL: 'polynomial', RBF: 'rbf', }; export const OPTION_DEFAULT_VALUE = { epochs: 30, batchSize: 16, k: 4, initialCentroids: 'kmpp', neighbors: 10, validationRate: 0.25, C: 0.00001, degree: 3, gamma: 1, }; class Svm extends LearningBase { type = 'svm'; init({ name, url, result, table, trainParam, modelId, loadModel }) { this.name = name; this.trainParam = trainParam; this.result = result; this.table = table; this.loadModel = loadModel; this.trainCallback = (value) => { this.view.setValue(value); }; // train 확인 필요 this.trained = true; this.chartEnable = false; this.attrLength = table?.select?.[0]?.length || 0; this.fields = table?.select?.[0]?.map((index) => table?.fields[index]); this.predictFields = table?.select?.[1]?.map((index) => table?.fields[index]); if (this.url !== url || this.modelId !== modelId) { this.load(url, modelId); this.url = url; this.modelId = modelId; } } checkTrainOptionValidation() { const { kernel, C, degree, gamma } = this.trainParam; if (!kernel || !C || !degree || !gamma) { throw new Error("can't train: trainOptions contain undefined"); } switch (kernel) { case KERNEL_STRING_TYPE.LINEAR: if ( degree !== OPTION_DEFAULT_VALUE.degree || gamma !== OPTION_DEFAULT_VALUE.gamma ) { throw new Error( `can't train: invalid kernelOption. kernel type ${KERNEL_STRING_TYPE.LINEAR}` ); } break; case KERNEL_STRING_TYPE.POLYNOMIAL: if (gamma !== OPTION_DEFAULT_VALUE.gamma) { throw new Error( `can't train: invalid kernelOption. kernel type ${KERNEL_STRING_TYPE.POLYNOMIAL}` ); } break; case KERNEL_STRING_TYPE.RBF: if (degree !== OPTION_DEFAULT_VALUE.degree) { throw new Error( `can't train: invalid kernelOption. kernel type ${KERNEL_STRING_TYPE.RBF}` ); } break; default: } } async train() { this.trained = false; this.setTable(); this.trainCallback(1); this.checkTrainOptionValidation(); const { testRate = 0.2, C, kernel, degree, gamma } = this.trainParam; const { trainX, trainY, testArr, select, fields, PREDICT_STR2NUM_MAP, numClass, } = this.getData(testRate, this.table); const svmTrainOption = { kernel, C, degree, gamma, }; this.predictValueMap = Object.fromEntries( Object.entries(PREDICT_STR2NUM_MAP).map(([key, value]) => [value, key]) ); this.trainCallback(30); this.model = createModel(); trainModel(this.model, trainX, trainY, svmTrainOption); this.trainCallback(80); const { confusionMatrix, score } = this.evaluate(this.model, testArr, numClass); const { accuracy, f1, precision, recall } = score; this.trainCallback(100); this.trained = true; this.result = { select, fields, confusionMatrix, accuracy, f1, valueMap: this.predictValueMap, precision, recall, }; } async load(url, modelId) { const data = await this.loadModel({ url, modelId }); if (!data) { return; } const { serializeModel, result } = data; this.model = SVM.load(serializeModel); this.valueMap = result?.valueMap; this.result = result; } // INFO: 예상치 전체를 가져옴. Deeplearning 레포의 predictArrays와 동일 async predict(array) { if (!this.model) { throw new Error("can't predict: no model"); } const xs = [array]; const preds = this.model.predict(xs); this.predictResult = preds.map((target) => ({ className: this.valueMap[target + 1], probability: 1, })); } getData(testRate, data) { const STR2NUM_MAP = {}; const STR2NUM_MAP_COUNT = {}; const { select = [[0], [1]], data: table, fields } = data; const [attr, predict] = select; const filtered = table.filter( (row) => !select[0].some((selected) => _isNaN(_toNumber(row[selected]))) ); const dataArray = filtered .map((row) => ({ x: attr.map((i) => parseFloat(row[i]) || 0), y: Utils.stringToNumber( predict[0], row[predict[0]], STR2NUM_MAP, STR2NUM_MAP_COUNT ), })) .map((row) => ({ x: row.x, y: row.y - 1, })); const { trainArr, testArr } = this.sliceArray(dataArray, testRate); return { trainX: trainArr.map((v) => v.x), trainY: trainArr.map((v) => v.y), testArr, select, fields, PREDICT_STR2NUM_MAP: { ...STR2NUM_MAP[predict[0]] }, numClass: STR2NUM_MAP_COUNT[predict[0]], }; } sliceArray(dataArray, testRate) { Utils.shuffle(dataArray); const testNum = Math.floor(dataArray.length * testRate); const testArr = dataArray.slice(0, testNum); const trainArr = dataArray.slice(testNum, dataArray.length); return { trainArr, testArr }; } evaluate(model, validateData, numClass) { const xs = validateData.map((data) => data.x); const ys = validateData.map((data) => data.y); const predictYs = model.predict(xs); const length = predictYs.length; const confusionMatrix = Array(numClass) .fill(0) .map(() => Array(numClass).fill(0)); for (let idx = 0; idx < length; idx++) { confusionMatrix[ys[idx]][predictYs[idx]]++; } const score = Utils.getScores(confusionMatrix, numClass); return { confusionMatrix, score }; } } export default Svm; function createModel() { return new SVM({ type: SVM.SVM_TYPES.C_SVC, probabilityEstimates: true }); } function trainModel(model, samples, labels, svmTrainOption) { let kernelType; if (svmTrainOption.kernel === KERNEL_STRING_TYPE.LINEAR) { kernelType = SVM.KERNEL_TYPES.LINEAR; } else if (svmTrainOption.kernel === KERNEL_STRING_TYPE.POLYNOMIAL) { kernelType = SVM.KERNEL_TYPES.POLYNOMIAL; } else if (svmTrainOption.kernel === KERNEL_STRING_TYPE.RBF) { kernelType = SVM.KERNEL_TYPES.RBF; } else { throw new Error("can't create model: unexpected kernel type"); } model.free(); model.kernel = kernelType; model.cost = svmTrainOption.C; model.degree = svmTrainOption.degree; model.gamma = svmTrainOption.gamma; model.train(samples, labels); } ================================================ FILE: src/class/learning/TextLearning.js ================================================ import Bayes, { fromJson } from './bayes'; import * as Khaiii from 'khaiii'; export const classes = [ 'ai_learning_classification', 'ai_learning_text' ]; const KhaiiModule = { isInitialized: false, module: undefined, async load(resourceRoot = `${Entry.Utils.getEntryjsPath()}/extern/khaiii`) { if (this.isInitialized) { return; } this.module = await Khaiii.initialize({ resourceProvider: 'webfs', resourceRoot, }); this.isInitialized = true; }, }; class TextNaiveBaye { #type = 'text'; #url = ''; #labels = []; #popup = null; #result = []; #loadModel; constructor({ url, labels, modelId, loadModel }) { this.#url = url; this.#labels = labels; this.#loadModel = loadModel; this.classifier = new Bayes({ tokenizer: this.tokenizer, }); this.load(url, modelId); } get labels() { return this.#labels; } unbanBlocks(blockMenu) { blockMenu.unbanClass(`ai_learning_classification`); blockMenu.unbanClass(`ai_learning_text`); } isAvailable() { if (!this.isLoaded) { throw new Error('ai learning text model load error'); } return true; } getResult(index) { const result = this.#result?.length ? this.#result : this.#popup?.result || []; const defaultResult = { probability: 0, className: '' }; if (index !== undefined && index > -1) { return ( result.find(({ className }) => className === this.#labels[index]) || defaultResult ); } return result[0] || defaultResult; } openInputPopup() { const isAvailable = this.isAvailable(); if (!isAvailable) { return; } this.#result = []; Entry.dispatchEvent('openMLInputPopup', { type: 'text', predict: async (text) => { this.#result = await this.predict(text); }, url: this.#url, labels: this.#labels, setResult: (result) => { this.#result = result; }, }); } tokenizer = async (text) => { if (!KhaiiModule.module) { throw new Error('module not loaded'); } if (!text) { return []; } const analized = KhaiiModule.module.analyze(text); // 형태소 분석 진행 const filtered = analized .map((wordInfo) => wordInfo.morphs .filter((morph) => { const category = morph.tag.charAt(0); return category === 'V' || category === 'N' || category === 'S'; }) .map((morph) => morph.lex) ) .flat(); return filtered; }; async predict(textData) { await KhaiiModule.load(); this.#result = await this.classifier.categorize(textData); return this.#result; } async load(url, modelId) { const data = await this.#loadModel({ url, modelId }); if (!data) { return; } this.classifier = fromJson(JSON.stringify(data)); this.classifier.tokenizer = this.tokenizer; this.isLoaded = true; } } export default TextNaiveBaye; ================================================ FILE: src/class/learning/Utils.ts ================================================ const toFixed = (num: number) => parseFloat(num.toFixed(2)); export const CommonUtil = { isWebGlSupport: () => { try { const currentCanvas = document.createElement('canvas'); return !!currentCanvas.getContext('webgl', { premultipliedalpha: false }); } catch (e) { console.log('error', e); return false; } }, stringToNumber: ( i: number, value: string, tempMap: { [key: number]: { [key: string]: number; }; }, tempMapCount: { [key: string]: number; } ) => { // if (!isNaN(parseFloat(value))) { // return parseFloat(value); // } if (!tempMap[i]) { tempMap[i] = {}; } if (!tempMap[i]?.[value]) { if (!tempMapCount[i]) { tempMapCount[i] = 0; } tempMapCount[i] = tempMapCount[i] + 1; tempMap[i][value] = tempMapCount[i]; } return tempMap[i][value]; }, shuffle: (arr: Array) => { let j; let x; let i; for (i = arr.length; i; i -= 1) { j = Math.floor(Math.random() * i); x = arr[i - 1]; arr[i - 1] = arr[j]; arr[j] = x; } }, getScores: (confusionMatrix: any, numClasses: number) => { let total = 0; let acc = 0; const precisions = []; const recalls = []; for (let i = 0; i < numClasses; i++) { let rowSum = 0; let colSum = 0; for (let j = 0; j < numClasses; j++) { rowSum += confusionMatrix[i][j]; colSum += confusionMatrix[j][i]; } const matrixValue = confusionMatrix?.[i]?.[i] || 0; precisions.push(confusionMatrix[i][i] / rowSum || 0); recalls.push(confusionMatrix[i][i] / colSum || 0); total += rowSum; acc += matrixValue; } const precision = precisions.reduce((a, b) => a + b, 0) / precisions.length; const recall = recalls.reduce((a, b) => a + b, 0) / recalls.length; return { accuracy: toFixed(acc / total), precision: toFixed(precision), recall: toFixed(recall), f1: toFixed(2 / (1 / precision + 1 / recall)), }; }, arrayToMatrix(array: Array, columns: number) { return Array(Math.ceil(array.length / columns)) .fill('') .reduce((acc, cur, index) => [...acc, [...array].splice(index * columns, columns)], []); }, }; export default CommonUtil; ================================================ FILE: src/class/learning/bayes.ts ================================================ import sortBy from 'lodash/sortBy'; const defaultTokenizer = function(text: string) { const rgxPunctuation = /[^(a-zA-ZA-Яa-я0-9_)+\s]/g; const sanitized = text.replace(rgxPunctuation, ' '); return sanitized.split(/\s+/); }; class Naivebayes { static STATE_KEYS: Array = [ 'categories', 'docCount', 'totalDocuments', 'vocabulary', 'vocabularySize', 'wordCount', 'wordFrequencyCount', 'options' ]; public options: { tokenizer?: Function; } = {}; public vocabulary: {[key: string]: boolean} = {}; public tokenizer: Function; public vocabularySize= 0; public totalDocuments= 0; public docCount: {[key: string]: number} = {}; public wordCount: {[key: string]: number} = {}; public wordFrequencyCount: {[key: string]: any}= {}; public categories: {[key: string]: boolean} = {}; constructor(options: any) { if (typeof options !== 'undefined') { if (!options || typeof options !== 'object' || Array.isArray(options)) { throw TypeError(`NaiveBayes got invalid options: ${options}. Pass in an object.`); } this.options = options; } this.tokenizer = this.options.tokenizer || defaultTokenizer; } public frequencyTable(tokens: Array) { return tokens.reduce((acc: {[key: string]: number}, cur: string) => { if (!acc[cur]) { acc[cur] = 0; } acc[cur] = acc[cur] + 1; return acc; }, {}); } public initializeCategory(categoryName: string) { if (!this.categories[categoryName]) { this.docCount[categoryName] = 0; this.wordCount[categoryName] = 0; this.wordFrequencyCount[categoryName] = {}; this.categories[categoryName] = true; } return this; } public async learn(text: string, category: string) { this.initializeCategory(category); this.docCount[category]++; this.totalDocuments++; const tokens = await this.tokenizer(text); const frequencyTable = this.frequencyTable(tokens); Object .keys(frequencyTable) .forEach((token) => { if (!this.vocabulary[token]) { this.vocabulary[token] = true; this.vocabularySize++; } const frequencyInText = frequencyTable[token]; if (!this.wordFrequencyCount[category][token]) { this.wordFrequencyCount[category][token] = frequencyInText; } else { this.wordFrequencyCount[category][token] += frequencyInText; } this.wordCount[category] += frequencyInText; }); return this; } public async categorize(text: string) { // let maxProbability = -Infinity; // let chosenCategory = null; let totalProbabilities = 0; const categoryProbabilities: {[key: string]: number} = {}; const tokens = await this.tokenizer(text); const frequencyTable = this.frequencyTable(tokens); Object .keys(this.categories) .forEach((category) => { const categoryProbability = this.docCount[category] / this.totalDocuments; let logProbability = Math.log(categoryProbability); Object .keys(frequencyTable) .forEach((token) => { const frequencyInText = frequencyTable[token]; const tokenProbability = this.tokenProbability(token, category); logProbability += frequencyInText * Math.log(tokenProbability); }); // if (logProbability > maxProbability) { // maxProbability = logProbability; // chosenCategory = category; // } const expected = Math.exp(logProbability); totalProbabilities = totalProbabilities + expected; categoryProbabilities[category] = expected; }); const probabilities = Object .keys(categoryProbabilities) .map((category) => ({ className: category, probability: categoryProbabilities[category] /= totalProbabilities })); return sortBy(probabilities,['probability']).reverse(); } private tokenProbability(token: string, category: string) { const wordFrequencyCount = this.wordFrequencyCount[category][token] || 0; const wordCount = this.wordCount[category]; return (wordFrequencyCount + 1) / (wordCount + this.vocabularySize); } public toJson() { const state = Naivebayes.STATE_KEYS.reduce( (acc: {[key: string]: any}, cur: keyof Naivebayes) => { acc[cur] = this[cur]; return acc; }, {}); return JSON.stringify(state); } } export function fromJson(jsonStr: string) { try { const parsed = JSON.parse(jsonStr); const classifier = new Naivebayes(parsed.options); Naivebayes.STATE_KEYS.forEach((k: keyof Naivebayes) => { if (typeof parsed[k] === 'undefined' || parsed[k] === null) { throw new Error(`FromJson: JSON string is missing an expected property: ${k}.`); } classifier[k] = parsed[k]; }); return classifier; } catch (e) { throw new Error('Naivebayes.fromJson expects a valid JSON string.') } } export default Naivebayes; ================================================ FILE: src/class/maxrect-packer/abstract_bin.ts ================================================ import { IRectangle } from "./geom/Rectangle"; import { IOption } from "./maxrects_packer"; import { ImageRect } from './geom/ImageRect'; export interface IBin { width: number; height: number; maxWidth: number; maxHeight: number; index:number; freeRects: IRectangle[]; rects: ImageRect[]; options: IOption; } export abstract class Bin implements IBin { public width: number; public height: number; public maxWidth: number; public maxHeight: number; public index:number; public freeRects: IRectangle[]; public rects: ImageRect[]; public options: IOption; public abstract add (rect:ImageRect): boolean; protected pushRect(rect:ImageRect, oversized:boolean) { rect.binIndex = this.index; rect.oversized = oversized; this.rects.push(rect); } } ================================================ FILE: src/class/maxrect-packer/geom/ImageRect.ts ================================================ import { Rectangle } from './Rectangle'; import { AtlasTexture } from '../../pixi/atlas/texture/AtlasTexture'; export class ImageRect extends Rectangle { constructor(public x: number = 0, public y: number = 0, public width: number = 0, public height: number = 0) { super(...arguments); this.dataWidth = width; this.dataHeight = height; } /** @deprecated */ scaleFactor:number = 1; scaleFactorX:number = 1; scaleFactorY:number = 1; binIndex:number = -1; /** * 이 값은 bin-packer 에서 할당하는데데, packing 하기 전에 AtlasImageLoadingInfo 에서 resize 를 하기 때문에 true가 될 일이 없음. */ oversized:boolean; data:{path:string, tex:AtlasTexture}; dataWidth:number = 0; dataHeight:number = 0; } ================================================ FILE: src/class/maxrect-packer/geom/Rectangle.ts ================================================ export interface IRectangle { x: number; y: number; width: number; height: number; } export class Rectangle implements IRectangle { constructor (public x: number = 0, public y: number = 0, public width: number = 0, public height: number = 0) { } public static Collide (first: Rectangle, second: Rectangle) { return first.collide(second); } public static Contain (first: Rectangle, second: Rectangle) { return first.contain(second); } public area (): number { return this.width * this.height; } public collide (rect: Rectangle): boolean { return !(rect.x >= this.x + this.width || rect.x + rect.width <= this.x || rect.y >= this.y + this.height || rect.y + rect.height <= this.y); } public contain (rect: Rectangle): boolean { return (rect.x >= this.x && rect.y >= this.y && rect.x + rect.width <= this.x + this.width && rect.y + rect.height <= this.y + this.height); } } ================================================ FILE: src/class/maxrect-packer/maxrects_bin.ts ================================================ import { EDGE_MAX_VALUE, IOption } from "./maxrects_packer"; import { Rectangle, IRectangle } from "./geom/Rectangle"; import { Bin } from "./abstract_bin"; import { ImageRect } from './geom/ImageRect'; export class MaxRectsBin extends Bin { public width: number; public height: number; public freeRects: Rectangle[] = []; public rects: ImageRect[] = []; private verticalExpand: boolean = false; private stage: Rectangle; constructor ( public index:number, public maxWidth: number = EDGE_MAX_VALUE, public maxHeight: number = EDGE_MAX_VALUE, public border: number = 0, public padding: number = 0, public options: IOption = { smart: true, pot: true, square: true } ) { super(); this.width = this.options.smart ? 0 : maxWidth; this.height = this.options.smart ? 0 : maxHeight; this.freeRects.push(new Rectangle(border, border, this.maxWidth + this.padding*2 - this.border, this.maxHeight + this.padding*2 - this.border)); this.stage = new Rectangle(0, 0, this.width, this.height); } public add (rect:ImageRect): boolean { var PAD = this.padding * 2; var width:number = rect.width; var height:number = rect.height; let node: Rectangle | undefined = this.findNode(width + PAD, height + PAD); if (node) { this.updateBinSize(node); let numRectToProcess = this.freeRects.length; let i: number = 0; while (i < numRectToProcess) { if (this.splitNode(this.freeRects[i], node)) { this.freeRects.splice(i, 1); numRectToProcess--; i--; } i++; } this.pruneFreeList(); this.verticalExpand = this.width > this.height ? true : false; rect.x = node.x; rect.y = node.y; this.pushRect(rect, false); return true; } else if (!this.verticalExpand) { if (this.updateBinSize(new Rectangle(this.width + PAD, 0, width + this.padding, height + PAD)) || this.updateBinSize(new Rectangle(0, this.height + PAD, width + PAD, height + PAD))) { return this.add(rect); } } else { if (this.updateBinSize(new Rectangle( 0, this.height + PAD, width + PAD, height + PAD )) || this.updateBinSize(new Rectangle( this.width + PAD, 0, width + PAD, height + PAD ))) { return this.add(rect); } } return undefined; } /* public add (width: number, height: number, data: any): Rectangle | undefined { let node: Rectangle | undefined = this.findNode(width + this.padding, height + this.padding); if (node) { this.updateBinSize(node); let numRectToProcess = this.freeRects.length; let i: number = 0; while (i < numRectToProcess) { if (this.splitNode(this.freeRects[i], node)) { this.freeRects.splice(i, 1); numRectToProcess--; i--; } i++; } this.pruneFreeList(); this.verticalExpand = this.width > this.height ? true : false; let rect: Rectangle = new Rectangle(node.x, node.y, width, height); rect.data = data; this.rects.push(rect); return rect; } else if (!this.verticalExpand) { if (this.updateBinSize(new Rectangle(this.width + this.padding, 0, width + this.padding, height + this.padding)) || this.updateBinSize(new Rectangle(0, this.height + this.padding, width + this.padding, height + this.padding))) { return this.add(width, height, data); } } else { if (this.updateBinSize(new Rectangle( 0, this.height + this.padding, width + this.padding, height + this.padding )) || this.updateBinSize(new Rectangle( this.width + this.padding, 0, width + this.padding, height + this.padding ))) { return this.add(width, height, data); } } return undefined; } */ private findNode (width: number, height: number): Rectangle | undefined { let score: number = Number.MAX_VALUE; let areaFit: number; let r: Rectangle; let bestNode: Rectangle | undefined; for (let i in this.freeRects) { r = this.freeRects[i]; if (r.width >= width && r.height >= height) { areaFit = r.width * r.height - width * height; if (areaFit < score) { // bestNode.x = r.x; // bestNode.y = r.y; // bestNode.width = width; // bestNode.height = height; bestNode = new Rectangle(r.x, r.y, width, height); score = areaFit; } } } return bestNode; } private splitNode (freeRect: Rectangle, usedNode: Rectangle): boolean { // Test if usedNode intersect with freeRect if (!freeRect.collide(usedNode)) return false; // Do vertical split if (usedNode.x < freeRect.x + freeRect.width && usedNode.x + usedNode.width > freeRect.x) { // New node at the top side of the used node if (usedNode.y > freeRect.y && usedNode.y < freeRect.y + freeRect.height) { let newNode: Rectangle = new Rectangle(freeRect.x, freeRect.y, freeRect.width, usedNode.y - freeRect.y); this.freeRects.push(newNode); } // New node at the bottom side of the used node if (usedNode.y + usedNode.height < freeRect.y + freeRect.height) { let newNode = new Rectangle( freeRect.x, usedNode.y + usedNode.height, freeRect.width, freeRect.y + freeRect.height - (usedNode.y + usedNode.height) ); this.freeRects.push(newNode); } } // Do Horizontal split if (usedNode.y < freeRect.y + freeRect.height && usedNode.y + usedNode.height > freeRect.y) { // New node at the left side of the used node. if (usedNode.x > freeRect.x && usedNode.x < freeRect.x + freeRect.width) { let newNode = new Rectangle(freeRect.x, freeRect.y, usedNode.x - freeRect.x, freeRect.height); this.freeRects.push(newNode); } // New node at the right side of the used node. if (usedNode.x + usedNode.width < freeRect.x + freeRect.width) { let newNode = new Rectangle( usedNode.x + usedNode.width, freeRect.y, freeRect.x + freeRect.width - (usedNode.x + usedNode.width), freeRect.height ); this.freeRects.push(newNode); } } return true; } private pruneFreeList () { // Go through each pair of freeRects and remove any rects that is redundant let i: number = 0; let j: number = 0; let len: number = this.freeRects.length; while (i < len) { j = i + 1; let tmpRect1 = this.freeRects[i]; while (j < len) { let tmpRect2 = this.freeRects[j]; if (tmpRect2.contain(tmpRect1)) { this.freeRects.splice(i, 1); i--; len--; break; } if (tmpRect1.contain(tmpRect2)) { this.freeRects.splice(j, 1); j--; len--; } j++; } i++; } } private updateBinSize (node: Rectangle): boolean { if (!this.options.smart) return false; if (this.stage.contain(node)) return false; var PAD = this.padding * 2; let tmpWidth: number = Math.max(this.width, node.x + node.width - PAD); let tmpHeight: number = Math.max(this.height, node.y + node.height - PAD); if (this.options.pot) { tmpWidth = Math.pow(2, Math.ceil(Math.log(tmpWidth) * Math.LOG2E)); tmpHeight = Math.pow(2, Math.ceil(Math.log(tmpHeight) * Math.LOG2E)); } if (this.options.square) { tmpWidth = tmpHeight = Math.max(tmpWidth, tmpHeight); } if (tmpWidth > this.maxWidth + PAD || tmpHeight > this.maxHeight + PAD) { return false; } this.expandFreeRects(tmpWidth + PAD, tmpHeight + PAD); this.width = this.stage.width = tmpWidth; this.height = this.stage.height = tmpHeight; return true; } private expandFreeRects (width: number, height: number) { var PAD = this.padding * 2; this.freeRects.forEach((freeRect, index) => { if (freeRect.x + freeRect.width >= Math.min(this.width + PAD, width)) { freeRect.width = width - freeRect.x; } if (freeRect.y + freeRect.height >= Math.min(this.height + PAD, height)) { freeRect.height = height - freeRect.y; } }, this); this.freeRects.push(new Rectangle(this.width + PAD, 0, width - this.width - PAD, height)); this.freeRects.push(new Rectangle(0, this.height + PAD, width, height - this.height - PAD)); this.freeRects.forEach((freeRect, index) => { if (freeRect.width <= 0 || freeRect.height <= 0) { this.freeRects.splice(index, 1); } }, this); this.pruneFreeList(); } } ================================================ FILE: src/class/maxrect-packer/maxrects_packer.ts ================================================ import { Rectangle, IRectangle } from "./geom/Rectangle"; import { MaxRectsBin } from "./maxrects_bin"; import { OversizedElementBin } from "./oversized_element_bin"; import { Bin, IBin } from "./abstract_bin"; import { ImageRect } from './geom/ImageRect'; export const EDGE_MAX_VALUE: number = 4096; export const EDGE_MIN_VALUE: number = 128; /** * Options for MaxRect Packer * @property {boolean} options.smart Smart sizing packer (default is true) * @property {boolean} options.pot use power of 2 sizing (default is true) * @property {boolean} options.square use square size (default is false) * @export * @interface Option */ export interface IOption { smart?: boolean; pot?: boolean; square?: boolean; } export class MaxRectsPacker { public bins: Bin[]; /** * Creates an instance of MaxRectsPacker. * @param {number} width of the output atlas (default is 4096) * @param {number} height of the output atlas (default is 4096) * @param {number} border of bin-texture (default is 0) * @param {number} padding between glyphs/images (default is 0) * @param {IOption} [options={}] (Optional) packing options * @memberof MaxRectsPacker */ constructor ( public width: number = EDGE_MAX_VALUE, public height: number = EDGE_MAX_VALUE, public border: number = 0, public padding: number = 0, public options: IOption = { smart: true, pot: true, square: true } ) { this.bins = []; } public add(rect:ImageRect) { var width = rect.width; var height = rect.height; var binIndex:number = this.bins.length; if (width > this.width || height > this.height) { this.bins.push(new OversizedElementBin(binIndex, rect)); } else { let added = this.bins.find(bin => bin.add(rect)); if (!added) { let bin = new MaxRectsBin(binIndex, this.width, this.height, this.border, this.padding, this.options); bin.add(rect); this.bins.push(bin); } } } /** * Add an Array of bins/rectangles to the packer. * Object structure: { width, height, data } * @param {IRectangle[]} rects Array of bin/rectangles * @memberof MaxRectsPacker */ public addArray (rects: ImageRect[]) { this.sort(rects).forEach((r:ImageRect) => this.add(r)); } private sort (rects: IRectangle[]) { return rects.slice().sort((a, b) => Math.max(b.width, b.height) - Math.max(a.width, a.height)); } public empty() { this.bins.length = 0; } } ================================================ FILE: src/class/maxrect-packer/oversized_element_bin.ts ================================================ import { IOption } from "./maxrects_packer"; import { Bin } from "./abstract_bin"; import { ImageRect } from './geom/ImageRect'; export class OversizedElementBin extends Bin { public maxWidth: number; public maxHeight: number; public options: IOption; constructor (public index:number, rect:ImageRect) { super(); this.rects = []; this.freeRects = []; this.maxWidth = rect.width; this.maxHeight = rect.height; this.options = { smart: false, pot: false, square: false }; this.pushRect(rect, true); } add (rect:ImageRect): boolean { return false; } } ================================================ FILE: src/class/object.js ================================================ /**; * @fileoverview Object for Entry. */ 'use strict'; import DomUtils from '../../src/util/domUtils'; import { GEHelper } from '../graphicEngine/GEHelper'; const _findIndex = require('lodash/findIndex'); /** * Class for entry object. * @param {?object model} model for object * @constructor */ Entry.EntryObject = class { constructor(model) { if (model) { this.id = model.id; this.name = model.name || model.sprite.name; this.text = model.text || this.name; this.objectType = model.objectType || 'sprite'; this.script = new Entry.Code(model.script || [], this); this.pictures = Entry.Utils.copy(model.sprite.pictures || []); this.sounds = Entry.Utils.copy(model.sprite.sounds || []); this._setFocused = Entry.Utils.setFocused; this._setBlurredTimer = Entry.Utils.setBlurredTimer; this.editObjectValueWhenEnterPress = Entry.Utils.whenEnter(() => { this.editObjectValues(false); }); this.sounds.forEach((s) => { if (!s.id) { s.id = Entry.generateHash(); } Entry.initSound(s); }); this.lock = model.lock ? model.lock : false; this.isEditing = false; if (this.objectType === 'sprite') { this.selectedPicture = !model.selectedPictureId ? this.pictures[0] : this.getPicture(model.selectedPictureId); } if (this.sounds?.length) { this.selectedSound = this.sounds[0]; } this.scene = Entry.scene.getSceneById(model.scene) || Entry.scene.selectedScene; this.setRotateMethod(model.rotateMethod); //entity this.entity = new Entry.EntityObject(this); this.entity.injectModel( this.selectedPicture ? this.selectedPicture : null, model.entity ? model.entity : this.initEntity(model) ); this.clonedEntities = []; Entry.stage.loadObject(this); const pictures = this.pictures; for (const i in pictures) { const picture = pictures[i]; picture.objectId = this.id; if (!picture.id) { picture.id = Entry.generateHash(); } GEHelper.resManager.reqResource(null, this.scene.id, picture); } Entry.requestUpdate = true; } this._isContextMenuEnabled = true; this.isFolded = false; } /** * View generator for workspace or others. * Entry.type === 'phone' 관련 뷰 삭제 * @return {!Element} */ generateView() { return this.generateWorkspaceView(); } /** * Object name setter * @param {!string} name */ setName(name) { Entry.assert(typeof name === 'string', 'object name must be string'); this.name = name; if (this.nameView_) { this.nameView_.value = name; } } getName() { return this.name; } /** * Object text setter * @param {!string} name */ setText(text) { Entry.assert(typeof text === 'string', 'object text must be string'); this.text = text; } /** * Object script setter * @param {!xml script} script */ setScript(script) { this.script = script; } /** * Object script getter * @return {!xml script} script */ getScriptText() { return this.script.stringify(); } /** * Initialize entity model if not exist * @param {!object model} model for object * @return {entity model} */ initEntity(model) { const json = {}; json.rotation = json.x = json.y = 0; json.direction = 90; if (this.objectType == 'sprite') { const dimension = model.sprite.pictures[0].dimension; json.regX = dimension.width / 2; json.regY = dimension.height / 2; let scale; const mainCategory = model.sprite.category.main; if (mainCategory == 'background' || mainCategory == 'new') { scale = Math.max(270 / dimension.height, 480 / dimension.width); } else if (mainCategory == 'new') { scale = 1; } else { scale = 200 / (dimension.width + dimension.height); } json.scaleX = json.scaleY = scale; json.width = dimension.width; json.height = dimension.height; } else if (this.objectType == 'textBox') { json.regX = 25; json.regY = 12; json.scaleX = json.scaleY = 1.5; json.width = 50; json.height = 24; json.text = model.text; if (model.options) { const options = model.options; let fontStyle = ''; const { fontSize = 20, textAlign = 0, scaleX = 1.5, regX, regY, width, height, } = options; if (options.bold) { fontStyle += 'bold '; } if (options.italic) { fontStyle += 'italic '; } json.underLine = options.underLine; json.strike = options.strike; if (typeof options.font === 'string') { json.font = options.font; } else { json.font = `${fontStyle}${fontSize}px ${options.font.family}`; } json.colour = options.colour; json.bgColor = options.bgColor || options.background; json.lineBreak = options.lineBreak; json.textAlign = textAlign; json.scaleX = json.scaleY = scaleX; if (options.lineBreak) { json.width = width || 256; json.height = height || json.width * 0.5625; json.regX = regX || json.width / 2; json.regY = regY || json.height / 2; } } else { json.underLine = false; json.strike = false; json.font = '20px Nanum Gothic'; json.colour = '#000000'; json.bgColor = '#ffffff'; } } return json; } /** * Update thumbnail view; */ updateThumbnailView() { const thumb = this.thumbnailView_; const picture = this.entity.picture; const objectType = this.objectType; this.thumbUrl = ''; if (objectType === 'sprite') { if (picture.thumbUrl || picture.fileurl) { this.thumbUrl = picture.thumbUrl || picture.fileurl; } else { const fileName = picture.filename; this.thumbUrl = `${Entry.defaultPath}/uploads/${fileName.substring( 0, 2 )}/${fileName.substring(2, 4)}/thumb/${fileName}.png`; } thumb.style.backgroundImage = `url(${encodeURI(this.thumbUrl)})`; } else if (objectType === 'textBox') { const { type } = Lang || {}; const filename = type === 'ko' ? 'text_icon_ko.svg' : 'text_icon.svg'; this.thumbUrl = `${Entry.mediaFilePath}${filename}`; $(thumb).addClass('entryObjectTextBox'); } } /** * Update coordinate view; */ updateCoordinateView(isForced) { if (!this.isSelected() && !isForced) { return; } const view = this.coordinateView_; if (view && view.xInput_ && view.yInput_) { const originX = view.xInput_.value; const originY = view.yInput_.value; const size = view.sizeInput_.value; const entity = this.entity; const newX = entity.getX(1); const newY = entity.getY(1); const newSize = entity.getSize(1); if (originX != newX) { view.xInput_.value = newX; } if (originY != newY) { view.yInput_.value = newY; } if (size != newSize) { view.sizeInput_.value = newSize; } } } /** * Update rotation view; */ updateRotationView(isForced) { if ((!this.isSelected() || !this.view_) && !isForced) { return; } const rotateMethod = this.getRotateMethod(); const entity = this.entity; const className = 'entryRemove'; if (rotateMethod === 'free') { this.rotateWrapper_.removeClass(className); this.rotateInput_.value = `${entity.getRotation(1)}`; this.directionInput_.value = `${entity.getDirection(1)}`; } else { this.rotateWrapper_.addClass(className); this.directionInput_.value = `${entity.getDirection(1)}`; } } /** * Add picture object by picture model. * @param {picture model} picture */ addPicture(picture, index) { picture.objectId = this.id; if (typeof index === 'undefined') { this.pictures.push(picture); } else { this.pictures.splice(index, 0, picture); } Entry.playground.injectPicture(this); } /** * Remove picture object. * @param {string} pictureId * @return {boolean} return true if success */ removePicture(pictureId) { const pictures = this.pictures; if (pictures.length < 2) { return; } const playground = Entry.playground; const picture = this.getPicture(pictureId); pictures.splice(pictures.indexOf(picture), 1); if (picture === this.selectedPicture) { playground.selectPicture(pictures[0], true); } GEHelper.resManager.imageRemoved('EntityObject::removePicture'); playground.injectPicture(this); playground.reloadPlayground(); } /** * Get picture object by Id. * @param {?string} pictureId * @return {picture object} */ getPicture(value) { //priority //1. pictureId //2. pictureName //3. index if (!value) { return this.selectedPicture; } value = `${value}`.trim(); const pictures = this.pictures; const len = pictures.length; for (let i = 0; i < len; i++) { if (pictures[i].id == value) { return pictures[i]; } } for (let i = 0; i < len; i++) { if (pictures[i].name == value) { return pictures[i]; } } const checker = Entry.parseNumber(value); if (!(checker === false && typeof checker === 'boolean') && len >= checker && checker > 0) { return pictures[checker - 1]; } return null; } getPictureIndex(value) { return this.pictures.indexOf(this.getPicture(value)); } /** * Get previous picture object by Id. * @param {?string} pictureId * @return {picture object} */ getPrevPicture(pictureId) { const pictures = this.pictures; let idx = this.getPictureIndex(pictureId); return pictures[idx === 0 ? pictures.length - 1 : --idx]; } /** * Get next picture object by Id. * @param {?string} pictureId * @return {picture object} */ getNextPicture(pictureId) { const pictures = this.pictures; const len = pictures.length; let idx = this.getPictureIndex(pictureId); return pictures[idx == len - 1 ? 0 : ++idx]; } /** * Select picture object by Id. * @param {!string} pictureId * @return {picture object} */ selectPicture(pictureId) { const picture = this.getPicture(pictureId); if (!picture) { throw new Error(`No picture with pictureId : ${pictureId}`); } this.selectedPicture = picture; this.entity.setImage(picture); this.updateThumbnailView(); } selectSound(soundId) { const sound = this.getSound(soundId); if (!sound) { throw new Error(`No sound with soundId : ${soundId}`); } this.selectedSound = sound; } /** * Add sound to object * @param {sound model} sound */ addSound(sound, index) { if (!sound.id) { sound.id = Entry.generateHash(); } Entry.initSound(sound, index); if (typeof index === 'undefined') { this.sounds.push(sound); } else { this.sounds.splice(index, 0, sound); } Entry.playground.injectSound(this); } /** * Remove sound object. * @param {string} soundId */ removeSound(soundId) { const playground = Entry.playground; const sound = this.getSound(soundId); const index = _findIndex(this.sounds, (sound) => sound.id === soundId); this.sounds.splice(index, 1); if (sound === this.selectedSound) { if (this.sounds?.length) { playground.selectSound(this.sounds[0], true); } else { this.selectedSound = undefined; } } Entry.playground.injectSound(); Entry.playground.reloadPlayground(); } /** * rotate method getter * @return {string} */ getRotateMethod() { if (!this.rotateMethod) { this.rotateMethod = 'free'; } return this.rotateMethod; } /** * rotate method setter * @param {string} rotateMethod */ setRotateMethod(rotateMethod = 'free') { /** @type {string} */ this.rotateMethod = rotateMethod; this.updateRotateMethodView(); const stage = Entry.stage; const entity = stage.selectedObject && stage.selectedObject.entity; if (entity) { stage.updateObject(); stage.updateHandle(); } } initRotateValue(rotateMethod) { if (this.rotateMethod === rotateMethod) { return; } const entity = this.entity; const direction = entity.direction; entity.direction = direction !== undefined ? direction : 90.0; entity.rotation = 0.0; entity.flip = false; } updateRotateMethodView() { if (!this.rotateModeAView_) { return; } const SELECTED = 'selected'; this.rotateModeAView_.removeClass(SELECTED); this.rotateModeBView_.removeClass(SELECTED); this.rotateModeCView_.removeClass(SELECTED); const rotateMethod = this.rotateMethod; if (rotateMethod === 'free') { this.rotateModeAView_.addClass(SELECTED); } else if (rotateMethod === 'vertical') { this.rotateModeBView_.addClass(SELECTED); } else { this.rotateModeCView_.addClass(SELECTED); } this.updateRotationView(); } /** * Add clone entity for clone block * If parameter given, this clone the parameter entity itself. * Otherwise, this clone this object's entity. * @param {?Entry.EntryObject} object * @param {?Entry.EntityObject} entity * @param {?xml block} script */ addCloneEntity(object, entity, script) { if (this.clonedEntities.length > Entry.maxCloneLimit) { return; } const clonedEntity = new Entry.EntityObject(this); clonedEntity.isClone = true; entity = entity || this.entity; clonedEntity.injectModel(entity.picture || null, entity.toJSON()); clonedEntity.snapshot_ = entity.snapshot_; if (entity.effect) { clonedEntity.effect = _.clone(entity.effect); clonedEntity.applyFilter(); } Entry.engine.raiseEventOnEntity(clonedEntity, [clonedEntity, 'when_clone_start']); clonedEntity.isStarted = true; this.addCloneVariables( this, clonedEntity, entity ? entity.variables : null, entity ? entity.lists : null ); this.clonedEntities.push(clonedEntity); let targetIndex = Entry.stage.selectedObjectContainer.getChildIndex(entity.object); const offsetCount = (entity.shapes.length ? 1 : 0) + (entity.paintShapes.length ? 1 : 0); targetIndex -= offsetCount + entity.stamps.length; Entry.stage.loadEntity(clonedEntity, targetIndex); if (entity.brush) { Entry.setCloneBrush(clonedEntity, entity.brush); } } /** * return true when object is selected * @return {Boolean} */ isSelected() { return this.isSelected_; } /** * convert this object's data to JSON. * @return {JSON} */ toJSON(isClone) { const json = {}; json.id = isClone ? Entry.generateHash() : this.id; json.name = this.name; json.script = this.getScriptText(); json.objectType = this.objectType; json.rotateMethod = this.getRotateMethod(); json.scene = this.scene.id; json.sprite = { pictures: Entry.getPicturesJSON(this.pictures, isClone), sounds: Entry.getSoundsJSON(this.sounds, isClone), }; if (this.objectType === 'textBox') { json.text = this.text; } else { json.selectedPictureId = json.sprite.pictures[this.pictures.indexOf(this.selectedPicture)].id; } json.lock = this.lock; json.entity = this.entity.toJSON(); return json; } /** * destroy this object */ destroy() { this.entity && this.entity.destroy(); Entry.removeElement(this.view_); } /** * Get sound object by Id. * @param {?string} soundId * @return {sound object} */ getSound(value) { //priority //1. soundId //2. soundName //3. index if (!value) { return this.selectedSound; } value = String(value).trim(); const sounds = this.sounds; const len = sounds.length; for (let i = 0; i < len; i++) { if (sounds[i].id == value) { return sounds[i]; } } for (let i = 0; i < len; i++) { if (sounds[i].name == value) { return sounds[i]; } } const checker = Entry.parseNumber(value); if (!(checker === false && typeof checker === 'boolean') && len >= checker && checker > 0) { return sounds[checker - 1]; } return null; } addCloneVariables({ id }, entity, variables, lists) { const _whereFunc = _.partial(_.filter, _, { object_: id }); const _cloneFunc = (v) => v.clone(); const { variables_, lists_ } = Entry.variableContainer; entity.variables = (variables || _whereFunc(variables_)).map(_cloneFunc); entity.lists = (lists || _whereFunc(lists_)).map(_cloneFunc); } getLock() { return this.lock; } setLock(bool) { this.lock = bool; Entry.stage.updateObject(); return bool; } updateInputViews(isLocked) { isLocked = isLocked || this.getLock(); const inputs = [ this.nameView_, this.coordinateView_.xInput_, this.coordinateView_.yInput_, this.rotateInput_, this.directionInput_, this.coordinateView_.sizeInput_, ]; if (isLocked) { inputs.forEach((input) => { input.setAttribute('disabled', 'disabled'); }); } else { inputs.forEach((input) => { input.removeAttribute('disabled'); }); } this.isEditing = !isLocked; } editObjectValues(activate) { const inputs = [ this.nameView_, this.coordinateView_.xInput_, this.coordinateView_.yInput_, this.rotateInput_, this.directionInput_, this.coordinateView_.sizeInput_, ]; if (activate && !this.isEditing) { this.isEditing = true; } else { inputs.forEach((input) => { input.blur(true); }); this.isEditing = false; } } /** * get only clonedEntities among clonedEntities except for stamp entity * @return {Array } entities */ getClonedEntities() { return this.clonedEntities.concat(); } clearExecutor() { this.script.clearExecutors(); const clonedEntities = this.clonedEntities; for (let j = clonedEntities.length - 1; j >= 0; j--) { clonedEntities[j].removeClone(true); } this.entity.removeStamps(); } _rightClick(e) { if (!this.isContextMenuEnabled()) { return; } e.stopPropagation(); const object = this; const container = Entry.container; const objects = container._getSortableObjectList(); const objectIndex = objects.findIndex((item) => item.key == this.id); const contextMenus = [ { text: Lang.Workspace.context_duplicate, enable: !Entry.engine.isState('run'), callback() { container.addCloneObject(object); }, }, { text: Lang.Workspace.copy_file, callback() { container.setCopiedObject(object); }, }, { text: Lang.Blocks.Paste_blocks, enable: !Entry.engine.isState('run') && !!container.copiedObject, callback() { if (container.copiedObject) { container.addCloneObject(container.copiedObject); } else { Entry.toast.alert( Lang.Workspace.add_object_alert, Lang.Workspace.object_not_found_for_paste ); } }, }, { text: Lang.Workspace.context_remove, enable: !Entry.engine.isState('run') && !this.getLock(), callback: () => { if (this.getLock()) { return true; } Entry.dispatchEvent('removeObject', object); const { id } = object; Entry.do('removeObject', id); Entry.Utils.forceStopSounds(); }, }, { text: Lang.Workspace.bring_forward, enable: objectIndex > 0, callback() { Entry.do('objectReorder', objectIndex - 1, objectIndex); }, }, { text: Lang.Workspace.send_backward, enable: objectIndex < objects.length - 1, callback() { Entry.do('objectReorder', objectIndex + 1, objectIndex); }, }, ]; if (!Entry.backpackDisable) { contextMenus.push({ text: Lang.Blocks.add_my_storage, enable: !Entry.engine.isState('run') && !!window.user, callback: () => { this.addStorage(); }, }); } if (Entry.exportObjectEnable) { contextMenus.push({ text: Lang.Blocks.export_object, callback() { Entry.dispatchEvent('exportObject', object); }, }); } const { clientX: x, clientY: y } = Entry.Utils.convertMouseEvent(e); Entry.ContextMenu.show(contextMenus, 'workspace-contextmenu', { x, y }); } addStorage() { Entry.dispatchEvent('addStorage', { type: 'object', data: this, }); } enableContextMenu() { this._isContextMenuEnabled = true; } disableContextMenu() { this._isContextMenuEnabled = false; } isContextMenuEnabled() { return this._isContextMenuEnabled && Entry.objectEditable; } toggleEditObject() { if (this.isEditing || Entry.engine.isState('run')) { return; } this.editObjectValues(true); if (Entry.playground.object !== this) { Entry.container.selectObject(this.id); } } getDom(query) { if (_.isEmpty(query)) { return this.view_; } switch (query.shift()) { case 'editButton': return this.editView_; case 'nameInput': return this.nameView_; case 'removeButton': return this.deleteView_; case 'xInput': return this.coordinateView_.xInput_; case 'yInput': return this.coordinateView_.yInput_; case 'sizeInput': return this.coordinateView_.sizeInput_; case 'directionInput': return this.directionInput_; case 'rotationInput': return this.rotateInput_; case 'rotationMethod': return this._getRotateView(query.shift()); } } setInputBlurred(...target) { target = this.getDom(target); if (!target) { return; } target._focused = false; } generateWorkspaceView() { const exceptionsForMouseDown = []; const that = this; const objectId = this.id; this.view_ = this.createObjectView(objectId, exceptionsForMouseDown); // container if (!Entry.objectEditable) { this.view_.addClass('entryDisabled'); } this.view_.appendChild(this.createObjectInfoView()); // visible, lock const thumbnailView = this.createThumbnailView(objectId); // thumbnail this.thumbnailView_ = thumbnailView; this.view_.appendChild(thumbnailView); this.view_.appendChild(this.createWrapperView()); // name space const informationView = this.createInformationView(); this.informationView_ = informationView; this.view_.appendChild(informationView); const deleteView = this.createDeleteView(exceptionsForMouseDown, that); // delete this.deleteView_ = deleteView; this.view_.appendChild(deleteView); const rotationWrapperView = this.createRotationWrapperView(); this.view_.appendChild(rotationWrapperView); this.updateThumbnailView(); this.updateRotateMethodView(); this.updateInputViews(); this.updateCoordinateView(true); this.updateRotationView(true); if (!Entry.objectEditable) { this.setDisabled(); } else { Entry.addEventListener('run', this.setDisabled); Entry.addEventListener('dispatchEventDidToggleStop', this.setEnabled); } return this.view_; } createRotationMethodWrapperView() { const rotationMethodWrapper = Entry.createElement('div').addClass('rotationMethodWrapper'); const rotateMethodLabelView = Entry.createElement('span').addClass( 'entryObjectRotateMethodLabelWorkspace' ); rotationMethodWrapper.appendChild(rotateMethodLabelView); rotateMethodLabelView.textContent = `${Lang.Workspace.rotate_method}`; const rotateModeAView = Entry.createElement('span').addClass( 'entryObjectRotateModeWorkspace entryObjectRotateModeAWorkspace' ); this.rotateModeAView_ = rotateModeAView; rotationMethodWrapper.appendChild(rotateModeAView); rotationMethodWrapper.appendChild(rotateModeAView); if (Entry.objectEditable) { rotateModeAView.bindOnClick( this._whenRotateEditable(() => { Entry.do('objectUpdateRotateMethod', this.id, 'free'); }, this) ); } const rotateModeBView = Entry.createElement('span').addClass( 'entryObjectRotateModeWorkspace entryObjectRotateModeBWorkspace' ); this.rotateModeBView_ = rotateModeBView; rotationMethodWrapper.appendChild(rotateModeBView); if (Entry.objectEditable) { rotateModeBView.bindOnClick( this._whenRotateEditable(() => { Entry.do('objectUpdateRotateMethod', this.id, 'vertical'); }, this) ); } const rotateModeCView = Entry.createElement('span').addClass( 'entryObjectRotateModeWorkspace entryObjectRotateModeCWorkspace' ); this.rotateModeCView_ = rotateModeCView; rotationMethodWrapper.appendChild(rotateModeCView); if (Entry.objectEditable) { rotateModeCView.bindOnClick( this._whenRotateEditable(() => { Entry.do('objectUpdateRotateMethod', this.id, 'none'); }, this) ); } return rotationMethodWrapper; } createRotateLabelWrapperView() { const rotateLabelWrapperView = Entry.createElement('div').addClass( 'entryObjectRotateLabelWrapperWorkspace' ); const rotateWrapper = Entry.createElement('span').addClass( 'entryObjectRotateWorkspaceWrapper' ); const rotateSpan = Entry.createElement('span').addClass('entryObjectRotateSpanWorkspace'); rotateSpan.textContent = `${Lang.Workspace.rotation}`; const RotateDegCoordi = Entry.createElement('span').addClass( 'entryObjectCoordinateSpanWorkspace degree' ); const rotateInput = Entry.createElement('input').addClass( 'entryObjectRotateInputWorkspace' ); rotateInput.setAttribute('type', 'text'); rotateInput.onkeypress = this.editObjectValueWhenEnterPress; rotateInput.onfocus = this._setFocused; rotateInput.onblur = this._setBlurredTimer(() => { const object = Entry.container.getObject(this.id); if (!object) { return; } let value = rotateInput.value; const idx = value.indexOf('˚'); if (~idx) { value = value.substring(0, idx); } Entry.do( 'objectUpdateRotationValue', this.id, Entry.Utils.isNumber(value) ? value : this.entity.getRotation() ); }); this.rotateWrapper_ = rotateWrapper; this.rotateSpan_ = rotateSpan; this.rotateInput_ = rotateInput; const directionWrapper = Entry.createElement('span').addClass( 'entryObjectDirectionWorkspaceWrapper' ); const directionSpan = Entry.createElement('span').addClass( 'entryObjectDirectionSpanWorkspace' ); directionSpan.textContent = `${Lang.Workspace.direction}`; const DirectionDegCoordi = Entry.createElement('span').addClass( 'entryObjectCoordinateSpanWorkspace degree' ); const directionInput = Entry.createElement('input').addClass( 'entryObjectDirectionInputWorkspace' ); directionInput.setAttribute('type', 'text'); directionInput.onkeypress = this.editObjectValueWhenEnterPress; directionInput.onfocus = this._setFocused; directionInput.onblur = this._setBlurredTimer(() => { const object = Entry.container.getObject(this.id); if (!object) { return; } let value = directionInput.value; const idx = value.indexOf('˚'); if (~idx) { value = value.substring(0, idx); } Entry.do( 'objectUpdateDirectionValue', this.id, Entry.Utils.isNumber(value) ? value : this.entity.getDirection() ); }); this.directionInput_ = directionInput; rotateWrapper.appendChild(rotateSpan); rotateWrapper.appendChild(rotateInput); rotateWrapper.appendChild(RotateDegCoordi); directionWrapper.appendChild(directionSpan); directionWrapper.appendChild(directionInput); directionWrapper.appendChild(DirectionDegCoordi); rotateLabelWrapperView.appendChild(rotateWrapper); rotateLabelWrapperView.appendChild(directionWrapper); rotateLabelWrapperView.rotateInput_ = rotateInput; rotateLabelWrapperView.directionInput_ = directionInput; return rotateLabelWrapperView; } createCoordinationView() { const coordinationView = Entry.createElement('div').addClass( 'entryObjectCoordinateWorkspace' ); const xCoordiWrapper = Entry.createElement('span').addClass( 'entryObjectCoordinateWorkspaceWrapper' ); const xCoordi = Entry.createElement('span').addClass('entryObjectCoordinateSpanWorkspace'); xCoordi.textContent = 'X'; const xInput = Entry.createElement('input').addClass('entryObjectCoordinateInputWorkspace'); xInput.setAttribute('type', 'text'); xInput.onkeypress = this.editObjectValueWhenEnterPress; xInput.onfocus = this._setFocused; xInput.onblur = this._setBlurredTimer(() => { const object = Entry.container.getObject(this.id); if (!object) { return; } const value = xInput.value; Entry.do( 'objectUpdatePosX', this.id, Entry.Utils.isNumber(value) ? value : this.entity.getX() ); }); const yCoordiWrapper = Entry.createElement('span').addClass( 'entryObjectCoordinateWorkspaceWrapper' ); const yCoordi = Entry.createElement('span').addClass('entryObjectCoordinateSpanWorkspace'); yCoordi.textContent = 'Y'; const PerCoordi = Entry.createElement('span').addClass( 'entryObjectCoordinateSpanWorkspace' ); PerCoordi.textContent = '%'; const yInput = Entry.createElement('input').addClass( 'entryObjectCoordinateInputWorkspace entryObjectCoordinateInputWorkspace_right' ); yInput.setAttribute('type', 'text'); yInput.onkeypress = this.editObjectValueWhenEnterPress; yInput.onfocus = this._setFocused; yInput.onblur = this._setBlurredTimer(() => { const object = Entry.container.getObject(this.id); if (!object) { return; } const value = yInput.value; Entry.do( 'objectUpdatePosY', this.id, Entry.Utils.isNumber(value) ? value : this.entity.getY() ); }); const sizeWrapper = Entry.createElement('span').addClass( 'entryObjectCoordinateSizeWrapper' ); const sizeSpan = Entry.createElement('span').addClass('entryObjectCoordinateSizeWorkspace'); sizeSpan.textContent = `${Lang.Workspace.Size}`; const sizeInput = Entry.createElement('input').addClass( 'entryObjectCoordinateInputWorkspace', 'entryObjectCoordinateInputWorkspace_size' ); sizeInput.setAttribute('type', 'text'); sizeInput.onkeypress = this.editObjectValueWhenEnterPress; sizeInput.onfocus = this._setFocused; sizeInput.onblur = this._setBlurredTimer(() => { const object = Entry.container.getObject(this.id); if (!object) { return; } const value = sizeInput.value; Entry.do( 'objectUpdateSize', this.id, Entry.Utils.isNumber(value) ? value : this.entity.getSize() ); }); xCoordiWrapper.appendChild(xCoordi); xCoordiWrapper.appendChild(xInput); yCoordiWrapper.appendChild(yCoordi); yCoordiWrapper.appendChild(yInput); sizeWrapper.appendChild(sizeSpan); sizeWrapper.appendChild(sizeInput); sizeWrapper.appendChild(PerCoordi); coordinationView.appendChild(xCoordiWrapper); coordinationView.appendChild(yCoordiWrapper); coordinationView.appendChild(sizeWrapper); coordinationView.xInput_ = xInput; coordinationView.yInput_ = yInput; coordinationView.sizeInput_ = sizeInput; return coordinationView; } createRotationWrapperView() { const rotationWrapperView = Entry.createElement('div').addClass( 'entryObjectRotationWrapperWorkspace' ); const coordinationView = this.createCoordinationView(); this.coordinateView_ = coordinationView; rotationWrapperView.appendChild(coordinationView); const rotateLabelWrapperView = this.createRotateLabelWrapperView(); rotationWrapperView.appendChild(rotateLabelWrapperView); const rotationMethodWrapperView = this.createRotationMethodWrapperView(); rotateLabelWrapperView.appendChild(rotationMethodWrapperView); this.rotationMethodWrapper_ = rotationMethodWrapperView; return rotationWrapperView; } setObjectFold(isFold, isPass) { const $view = $(this.view_); if (isFold) { $view.addClass('fold'); } else { $view.removeClass('fold'); } if (!isPass) { this.isFolded = isFold; } } resetObjectFold() { this.setObjectFold(this.isFolded); } createInformationView() { const informationView = Entry.createElement('div').addClass( 'entryObjectInformationWorkspace' ); informationView.bindOnClick(() => { const $view = $(this.view_); if ($view.hasClass('selectedObject')) { this.setObjectFold(!this.isFolded); } }); return informationView; } createDeleteView(exceptionsForMouseDown) { const deleteView = Entry.createElement('div').addClass('entryObjectDeleteWorkspace'); exceptionsForMouseDown.push(deleteView); if (Entry.objectEditable && Entry.objectDeletable) { deleteView.bindOnClick((e) => { e.stopPropagation(); if (this.getLock() || Entry.engine.isState('run')) { return; } Entry.do('removeObject', this.id); Entry.removeEventListener('run', this.setDisabled); Entry.removeEventListener('dispatchEventDidToggleStop', this.setEnabled); }); } return deleteView; } createNameView() { const nameView = Entry.createElement('input').addClass('entryObjectNameWorkspace'); nameView.addEventListener('click', (e) => { if (!_.includes(this.view_.classList, 'selectedObject')) { e.preventDefault(); } }); nameView.addEventListener('contextmenu', (e) => { e.preventDefault(); if (!_.includes(this.view_.classList, 'selectedObject')) { this._rightClick(e); } }); nameView.addEventListener('focus', () => { if (!_.includes(this.view_.classList, 'selectedObject')) { nameView.blur(); } }); const onKeyPressed = Entry.Utils.whenEnter(() => { this.editObjectValues(false); }); nameView.onkeypress = onKeyPressed; nameView.onfocus = Entry.Utils.setFocused; const nameViewBlur = this._setBlurredTimer(() => { const object = Entry.container.getObject(this.id); if (!object) { return; } else if (nameView.value.trim() === '') { return Entry.modal.alert(Lang.Workspace.enter_the_name).then(() => { nameView.focus(); }); } Entry.do('objectNameEdit', this.id, nameView.value); }); Entry.attachEventListener(nameView, 'blur', nameViewBlur); nameView.value = this.name; return nameView; } setDisabled = () => { if (this.nameView_) { this.nameView_.disabled = true; } if (this.rotateInput_) { this.rotateInput_.disabled = true; } if (this.directionInput_) { this.directionInput_.disabled = true; } if (this.coordinateView_) { this.coordinateView_.sizeInput_.disabled = true; this.coordinateView_.xInput_.disabled = true; this.coordinateView_.yInput_.disabled = true; } }; setEnabled = () => { if (this.nameView_) { this.nameView_.disabled = false; } if (this.rotateInput_) { this.rotateInput_.disabled = false; } if (this.directionInput_) { this.directionInput_.disabled = false; } if (this.coordinateView_) { this.coordinateView_.sizeInput_.disabled = false; this.coordinateView_.xInput_.disabled = false; this.coordinateView_.yInput_.disabled = false; } }; createWrapperView() { const wrapperView = Entry.createElement('div').addClass('entryObjectWrapperWorkspace'); const nameView = this.createNameView(); wrapperView.appendChild(nameView); this.nameView_ = nameView; return wrapperView; } createThumbnailView(objectId) { const thumbnail = Entry.createElement('div').addClass('entryObjectThumbnailWorkspace'); DomUtils.addEventListenerMultiple(thumbnail, 'mousedown touchstart', (e) => { Entry.do('containerSelectObject', objectId); }); thumbnail.addEventListener('touchmove', (e) => { e.preventDefault(); }); return thumbnail; } createObjectInfoView() { const objectInfoView = Entry.createElement('ul').addClass('objectInfoView'); const objectInfoVisible = Entry.createElement('li').addClass('objectInfo_visible'); if (!this.entity.getVisible()) { objectInfoVisible.addClass('objectInfo_unvisible'); } const objectInfoLock = Entry.createElement('li').addClass('objectInfo_unlock'); if (this.getLock()) { objectInfoLock.addClass('objectInfo_lock'); } if (Entry.objectEditable) { objectInfoVisible.bindOnClick(() => { if (Entry.engine.isState('run')) { return; } const entity = this.entity; const visible = entity.setVisible(!entity.getVisible()); if (visible) { objectInfoVisible.removeClass('objectInfo_unvisible'); } else { objectInfoVisible.addClass('objectInfo_unvisible'); } }); objectInfoLock.bindOnClick(() => { if (Entry.engine.isState('run')) { return; } if (this.setLock(!this.getLock())) { objectInfoLock.addClass('objectInfo_lock'); } else { objectInfoLock.removeClass('objectInfo_lock'); } this.updateInputViews(this.getLock()); }); } objectInfoView.appendChild(objectInfoVisible); objectInfoView.appendChild(objectInfoLock); return objectInfoView; } createObjectView(objectId, exceptionsForMouseDown) { const objectView = Entry.createElement('li', objectId).addClass( 'entryContainerListElementWorkspace' ); $(objectView).on('dragstart', (e) => { e.originalEvent.dataTransfer.setData('text', objectId); }); const fragment = document.createDocumentFragment(); fragment.appendChild(objectView); // generate context menu Entry.Utils.disableContextmenu(objectView); objectView.addEventListener('click', (e) => { const isFirstClick = !_.includes(this.view_.classList, 'selectedObject'); if (isFirstClick && Entry.isMobile()) { e.preventDefault(); document.activeElement.blur(); } if ( Entry.container.getObject(objectId) && !_.includes(exceptionsForMouseDown, e.target) ) { Entry.do('selectObject', objectId); } }); const longPressEvent = (e) => { const doc = $(document); const touchEvent = Entry.Utils.convertMouseEvent(e); const mouseDownCoordinate = { x: touchEvent.clientX, y: touchEvent.clientY }; let longPressTimer = null; longPressTimer = setTimeout(() => { if (longPressTimer) { longPressTimer = null; this._rightClick(e); } }, 1000); doc.bind('mousemove.object touchmove.object', (e) => { const touchEvent = Entry.Utils.convertMouseEvent(e); const diff = Math.sqrt( Math.pow(touchEvent.pageX - mouseDownCoordinate.x, 2) + Math.pow(touchEvent.pageY - mouseDownCoordinate.y, 2) ); if (diff > 5 && longPressTimer) { clearTimeout(longPressTimer); longPressTimer = null; } }); doc.bind('mouseup.object touchend.object', (e) => { e.stopPropagation(); doc.unbind('.object'); if (longPressTimer) { clearTimeout(longPressTimer); longPressTimer = null; } }); }; objectView.addEventListener('mousedown', (e) => { if (Entry.Utils.isRightButton(e)) { e.stopPropagation(); this._rightClick(e); } if (Entry.isMobile()) { e.stopPropagation(); longPressEvent(e); } }); objectView.addEventListener('touchstart', (e) => { e.eventFromEntryObject = true; Entry.documentMousedown.notify(e); longPressEvent(e); }); return objectView; } _getRotateView(type = 'free') { if (type === 'free') { return this.rotateModeAView_; } else if (type === 'none') { return this.rotateModeCView_; } else { return this.rotateModeBView_; } } getIndex() { return Entry.container.getObjectIndex(this.id); } _whenRotateEditable(func, obj) { return Entry.Utils.when(() => !(Entry.engine.isState('run') || obj.getLock()), func); } }; ================================================ FILE: src/class/painter.js ================================================ import Extension from '../extensions/extension'; // 1px * 1px png iamge const NULL_IMAGE = // eslint-disable-next-line max-len 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAAtJREFUGFdjYAACAAAFAAGq1chRAAAAAElFTkSuQmCC'; let EntryPaint; Entry.Painter = class Painter { constructor(view) { this.view = view; this.cache = []; this.file = { id: Entry.generateHash(), name: '새그림', modified: false, mode: 'new', // new or edit }; this.dropper = Extension.getExtension('Dropper'); this.isShow = false; this.clipboard = null; this._keyboardEvents = []; Entry.addEventListener('pictureImport', this.addPicture.bind(this)); Entry.addEventListener('run', this.detachKeyboardEvents.bind(this)); Entry.addEventListener('stop', this.attachKeyboardEvents.bind(this)); this.importEntryPaint(); } async importEntryPaint() { EntryPaint = window.EntryPaint.default; if (this.requestShow) { this.initialize(); } } get graphicsMode() { return this.entryPaint.graphicsMode; } initialize() { if (this.entryPaint || !EntryPaint) { this.requestShow = true; return; } this.isShow = true; this.entryPaint = EntryPaint.create({ parent: this.view, mode: 'entry' }); this.entryPaint.setDropper && this.entryPaint.setDropper(this.dropper); this.isImport = true; this.entryPaint.on('SNAPSHOT_SAVED', (e) => { if (!this.isImport && Entry.stage.selectedObject) { Entry.do('editPicture', e, this.entryPaint); this.file.modified = true; } this.isImport = false; }); this.entryPaint.on('NEW_PICTURE', this.newPicture.bind(this)); this.entryPaint.on('IMPORT_IMAGE', () => { Entry.dispatchEvent('openPictureImport'); }); this.entryPaint.on('SAVE_PICTURE', () => { this.fileSave(false); }); this.entryPaint.on('SAVE_NEW_PICTURE', () => { this.file.mode = 'new'; this.fileSave(false); }); this.entryPaint.on('FULL_SCREEN_ON', () => { this.toggleFullscreen(true); }); this.entryPaint.on('FULL_SCREEN_OFF', () => { this.toggleFullscreen(false); }); Entry.addEventListener('pictureSelected', this.changePicture.bind(this)); } show() { if (!this.isShow) { this.initialize(); } this.realign && Entry.windowResized.detach(this.realign); this.realign = Entry.windowResized.attach(this.view, this.entryPaint.realign); } hide() { this.alertSaveModifiedPicture(); this.entryPaint && Entry.windowResized.detach(this.realign); } newPicture() { const newPicture = { dimension: { height: 1, width: 1, }, fileurl: `${Entry.mediaFilePath}_1x1.png`, thumbUrl: `${Entry.mediaFilePath}_1x1.png`, name: Lang.Painter.new_picture, imageType: 'png', }; newPicture.id = Entry.generateHash(); if (this.file && this.file.objectId) { newPicture.objectId = this.file.objectId; } Entry.playground.addPicture(newPicture, true); } changePicture(picture = {}, removed) { if (this.file && this.file.id === picture.id) { if (!this.file.isUpdate) { Entry.stage.updateObject(); this.file.isUpdate = true; } return; } else if (!this.file.modified) { this.afterModified(picture); } else { if (this.isConfirm) { return; } this.isConfirm = true; let wasRun = false; if (Entry.engine.state === 'run') { Entry.engine.toggleStop(); wasRun = true; } if (removed) { this.updatePicture(picture); } else { this.alertSaveModifiedPicture(picture, wasRun); } } Entry.stage.updateObject(); this.file.isUpdate = true; } updatePicture(picture = {}, wasRun = true, result = true) { this.isConfirm = false; result ? this.fileSave(true) : (this.file.modified = false); wasRun ? Entry.playground.injectPicture() : this.afterModified(picture); Entry.stage.updateObject(); } alertSaveModifiedPicture(picture, wasRun) { if (!this.file.modified) { return; } Entry.modal.confirm(Lang.Menus.save_modified_shape).then((result) => { this.updatePicture(picture, wasRun, result); }); } afterModified(picture) { const file = this.file; file.modified = false; this.isImport = true; if (picture.id) { file.id = picture.id || Entry.generateHash(); file.name = picture.name; file.mode = 'edit'; file.objectId = picture.objectId; this.addPicture(picture, true); } else { file.id = Entry.generateHash(); this.entryPaint.reset(); } Entry.stateManager.removeAllPictureCommand(); } getImageSrc(picture) { const { fileurl } = picture || {}; if (fileurl) { return fileurl; } const { imageType = 'png', filename } = picture || {}; return `${Entry.defaultPath}/uploads/${filename.substring(0, 2)}/${filename.substring( 2, 4 )}/image/${filename}.${imageType === 'svg' ? 'svg' : 'png'}`; } addPicture(picture = {}, isChangeShape) { picture.imageType = picture.imageType || 'png'; const { imageType } = picture; const imageSrc = this.getImageSrc(picture); isChangeShape && (this.isImport = true); switch (imageType) { case 'png': this.entryPaint.addBitmap(imageSrc, { graphicsMode: this.isImport ? this.graphicsMode.BITMAP : '', }); break; case 'svg': this.entryPaint.addSVG(imageSrc, { graphicsMode: this.isImport ? this.graphicsMode.VECTOR : '', }); break; default: this.entryPaint.addBitmap(imageSrc, { graphicsMode: this.isImport ? this.graphicsMode.BITMAP : '', }); } } _getImageType() { if (this.entryPaint.mode === this.graphicsMode.VECTOR) { return 'svg'; } else { return 'png'; } } fileSave(taskParam) { if (!Entry.stage.selectedObject) { return; } const dataURL = this.entryPaint.getDataURL() || NULL_IMAGE; if (this.entryPaint.mode === this.graphicsMode.VECTOR) { this.file.svg = this.entryPaint.exportSVG(); } else { delete this.file.svg; } this.file.ext = this._getImageType(); const file = JSON.parse(JSON.stringify(this.file)); Entry.dispatchEvent('saveCanvasImage', { file, image: dataURL, task: taskParam, }); this.file.isUpdate = false; this.file.modified = false; } attachKeyboardEvents() { this.detachKeyboardEvents(); const events = this._keyboardEvents; let evt = Entry.keyPressed; evt && events.push(evt.attach(this, this._keyboardPressControl)); evt = Entry.keyUpped; evt && events.push(evt.attach(this, this._keyboardUpControl)); } detachKeyboardEvents() { const events = this._keyboardEvents; if (!events || !events.length) { return; } while (events.length) { const evt = events.pop(); evt.destroy && evt.destroy(); } } _keyboardUpControl(e) {} _keyboardPressControl(e) {} toggleFullscreen(isFullscreen) { const { pictureView_ } = Entry.playground; const $view = $(this.view); if ((isFullscreen !== true && $view.hasClass('fullscreen')) || isFullscreen === false) { pictureView_.appendChild(this.view); $view.removeClass('fullscreen'); if (this.fullscreenButton) { this.fullscreenButton.setAttribute('title', Lang.Painter.fullscreen); this.fullscreenButton.setAttribute('alt', Lang.Painter.fullscreen); } } else { document.body.appendChild(this.view); $view.addClass('fullscreen'); if (this.fullscreenButton) { this.fullscreenButton.setAttribute('title', Lang.Painter.exit_fullscreen); this.fullscreenButton.setAttribute('alt', Lang.Painter.exit_fullscreen); } } this.entryPaint && this.entryPaint.realign(); } clear() { this.toggleFullscreen(false); } undo() { this.entryPaint.undo(); } redo() { this.entryPaint.redo(); } }; ================================================ FILE: src/class/pdf.ts ================================================ /** * 사용처: Entry#lecture 관련 로직 한군데 */ class EntryPDF { private _view: HTMLDivElement; constructor(filename: string) { this.generateView(filename); } private generateView(file: string) { const pdfView = Entry.createElement('div', 'entryPdfWorkspace'); // @ts-ignore 아무리봐도 순수 HTMLDivElement 에는 이 함수가 없음. 그러나 모르는 무언가가 있을 수 있으므로 그냥 둠 pdfView.addClass('entryRemove'); let url = '/pdfjs/web/viewer.html'; if (file && file !== '') { url += `?file=${file}`; } const pdfViewIframe = Entry.createElement('iframe', 'entryPdfIframeWorkspace'); pdfViewIframe.setAttribute('id', 'pdfViewIframe'); pdfViewIframe.setAttribute('frameborder', '0'); pdfViewIframe.setAttribute('src', url); pdfView.appendChild(pdfViewIframe); this._view = pdfView; } getView() { return this._view; } resize() { const container = document.getElementById('entryContainerWorkspaceId'); const viewFrame = document.getElementById('pdfViewIframe') as HTMLIFrameElement; const width = container.offsetWidth; viewFrame.width = `${width}px`; viewFrame.height = `${(width * 9) / 16}px`; } } export default EntryPDF; Entry.Pdf = EntryPDF; ================================================ FILE: src/class/pixi/atlas/AtlasCanvasViewer.ts ================================================ /** * BaseTexture 의 canvas 에 drawing이 잘 되는지 확인하기 위한 debug 클라스. */ const style = (viewerHeight: number) => ``; const dom = `
`; export class AtlasCanvasViewer { private $style: any; private $container: any; private attached: boolean; constructor(viewerHeight: number = 200) { this.$style = $(style(viewerHeight)); this.$container = $(dom); } private attachToBody() { if (this.attached) { return; } this.attached = true; setTimeout(() => { this.$container.click(() => false); $('head').append(this.$style); $('body').append(this.$container); }, 500); } add(c: HTMLCanvasElement) { const isCanvas = c instanceof HTMLCanvasElement; if (!isCanvas) { return; } this.attachToBody(); const cc = $(c); this.$container.append(cc); cc.addClass('atlas-canvas'); } removeCanvas(c: HTMLCanvasElement) { if (!c) { return; } $(c).remove(); } empty() { this.$container.empty(); } toggleVisible() { this.$container.toggle(); } } ================================================ FILE: src/class/pixi/atlas/EntryTextureOption.ts ================================================ import PIXIHelper from '../helper/PIXIHelper'; import { Rectangle, SCALE_MODES, MIPMAP_MODES } from 'pixi.js'; import { MaxRectsPacker } from '../../maxrect-packer/maxrects_packer'; import { clog } from '../utils/logs'; interface ITexOption {} interface IAtlasOption extends ITexOption { extrudeSize: number; atlasSize: number; newPacker: () => MaxRectsPacker; } export class EntryTextureOption { private _USE_ATLAS: boolean = false; get USE_ATLAS(): boolean { return this._USE_ATLAS; } private readonly GPU_TEX_MAX_SIZE: number; /** 텍스쳐를 최대 몇으로 할지의 값을 Canvas.width , height 기준으로 몇배로 할 지에 대한 값. */ private readonly _texStageRatio: number; readonly scaleMode = SCALE_MODES.LINEAR; readonly mipmap: MIPMAP_MODES = MIPMAP_MODES.OFF; readonly atlasOption: IAtlasOption; /** 텍스쳐 1개의 최대 크기. 이 크기보다 크면 리사이즈 함. */ readonly texMaxRect: Rectangle; constructor(stageWidth: number, stageHeight: number) { this._USE_ATLAS = this._isSpriteSheetEnabled(); this.GPU_TEX_MAX_SIZE = this.computeMaxTextureSize(4096); this._texStageRatio = 1; this.texMaxRect = this.getTexRect( stageWidth, stageHeight, this._texStageRatio, this.GPU_TEX_MAX_SIZE ); this.atlasOption = { extrudeSize: 2, atlasSize: this.GPU_TEX_MAX_SIZE, newPacker: this.newPacker.bind(this), }; } private newPacker(): MaxRectsPacker { //https://www.npmjs.com/package/maxrects-packer const PADDING = 6; //텍스쳐 사이의 간격. const BORDER = 2; //베이스 텍스쳐 테두리 간격 const MAX = this.atlasOption.atlasSize; const OPTION = { smart: false, pot: true, square: false, }; return new MaxRectsPacker(MAX, MAX, BORDER, PADDING, OPTION); } private getTexRect(w: number, h: number, ratio: number, max: number): Rectangle { return new Rectangle(0, 0, Math.min(Math.round(w * ratio), max), Math.min(Math.round(h * ratio), max), ); } private computeMaxTextureSize(LIMIT: number): number { const canvas: HTMLCanvasElement = PIXIHelper.getOffScreenCanvas(true); // @ts-ignore const ctx: WebGLRenderingContext = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); let size = ctx ? ctx.getParameter(ctx.MAX_TEXTURE_SIZE) : 2048; size = Math.min(size, LIMIT); clog(`Max texture size : ${size}`); return size; } private _isSpriteSheetEnabled(): boolean { const spriteSheetString = 'ss=1'; const url = window.location.href; const query = url.split('?')[1]; if (!query) return false; const arr = query.split('&'); for (let i = 0; i < arr.length; i++) { if (arr[i] == spriteSheetString) return true; } return false; } } ================================================ FILE: src/class/pixi/atlas/ISceneTextures.ts ================================================ import { Texture } from 'pixi.js'; import { AtlasImageLoadingInfo } from './loader/AtlasImageLoadingInfo'; import { IRawPicture } from './model/IRawPicture'; export interface ISceneTextures { addPicInfo(info: IRawPicture): void; activate(): void; deactivate(): void; getTexture(path: string): Texture; putImage(info: AtlasImageLoadingInfo, forceUpdateBaseTexture?: boolean): void; _internal_imageRemoved(): void; destroy(): void; } ================================================ FILE: src/class/pixi/atlas/PIXIAtlasHelper.ts ================================================ import { IRawPicture } from './model/IRawPicture'; import { PrimitiveSet } from './structure/PrimitiveSet'; import { ImageRect } from '../../maxrect-packer/geom/ImageRect'; import { autoFit } from '../utils/AutoFit'; interface ISimpleRect { x: number; y: number; width: number; height: number; } class _PIXIAtlasHelper { /** * rawData.fileurl || rawData.filename * @param rawData */ getRawPath(rawData: IRawPicture): string { return rawData.fileurl || rawData.filename; } /** * EntryObject를 전부 조회하여 지정된 장면에서 사용하는 picture의 경로 set 객체를 리턴. * @param sceneID */ getScenePathSet(sceneID: string): PrimitiveSet { const arrObj: any[] = Entry.container.getAllObjects(); const pathSet = new PrimitiveSet(); const LEN = arrObj.length; let LEN2; let pics: IRawPicture[]; let obj: any; for (let i = 0; i < LEN; i++) { obj = arrObj[i]; if (sceneID != obj.scene.id) { continue; } pics = obj.pictures; if (!pics || !(LEN2 = pics.length)) { continue; } for (let j = 0; j < LEN2; j++) { pathSet.put(this.getRawPath(pics[j])); } } return pathSet; } /** * 이미지별 텍스쳐 사이즈 리턴 (정수) * @param pic, texMaxRect */ getNewImageRect(pic: IRawPicture, texMaxRect: ISimpleRect): ImageRect { const w = pic.dimension.width | 0; const h = pic.dimension.height | 0; const r = new ImageRect(0, 0, w, h); if (w > texMaxRect.width || h > texMaxRect.height) { autoFit.fit(texMaxRect, r, autoFit.ScaleMode.INSIDE, autoFit.AlignMode.TL); r.width = Math.ceil(r.width); r.height = Math.ceil(r.height); r.scaleFactor = w / r.width; r.scaleFactorX = w / r.width; r.scaleFactorY = h / r.height; } return r; } } export const PIXIAtlasHelper: _PIXIAtlasHelper = new _PIXIAtlasHelper(); ================================================ FILE: src/class/pixi/atlas/PIXIAtlasManager.ts ================================================ import { Sprite } from 'pixi.js'; import { SceneBins } from './SceneBins'; import { AtlasCanvasViewer } from './AtlasCanvasViewer'; import { AtlasImageLoader, ImageLoaderHandler } from './loader/AtlasImageLoader'; import { AtlasImageLoadingInfo } from './loader/AtlasImageLoadingInfo'; import { IRawPicture } from './model/IRawPicture'; import { PIXIAtlasHelper } from './PIXIAtlasHelper'; import { EntryTextureOption } from './EntryTextureOption'; import { ISceneTextures } from './ISceneTextures'; import { SceneTextures } from './SceneTextures'; import { clog } from '../utils/logs'; import { IGEResManager } from '../../../graphicEngine/IGEResManager'; import each from 'lodash/each'; type SceneBinsMap = { [key: string]: ISceneTextures }; export class PIXIAtlasManager implements IGEResManager { private _sceneID_sceneBin_map: SceneBinsMap = {}; private _activatedScene: ISceneTextures; private _imageLoader: AtlasImageLoader; private _viewer: AtlasCanvasViewer; private _option: EntryTextureOption; /** * @private * @constructor */ public INIT() { if (this._imageLoader) { throw new Error('do not call twice'); } this._option = new EntryTextureOption(640, 360); this._viewer = new AtlasCanvasViewer(); this._imageLoader = new AtlasImageLoader(this._onImageLoaded.bind(this)); Entry.addEventListener('saveCanvasImage', () => { this.imageRemoved('canvas image saved'); }); } private _onImageLoaded(info: AtlasImageLoadingInfo) { this._activatedScene && this._activatedScene.putImage(info); } activateScene(sceneID: string) { if (this._activatedScene) { this._activatedScene.deactivate(); } this._activatedScene = this._getSceneBin(sceneID); this._activatedScene.activate(); } reqResource( spriteNullable: Sprite, sceneID: string, pic: IRawPicture, callback: ImageLoaderHandler ): void { const bin: ISceneTextures = this._getSceneBin(sceneID); bin.addPicInfo(pic); const tex = bin.getTexture(PIXIAtlasHelper.getRawPath(pic)); if (spriteNullable) { spriteNullable.texture = tex; } } private _getSceneBin(sceneID: string, createIfNotExist: boolean = true): ISceneTextures { let s: ISceneTextures = this._sceneID_sceneBin_map[sceneID]; if (!s && createIfNotExist) { if (this._option.USE_ATLAS) { s = new SceneBins(sceneID, this._option, this._imageLoader, this._viewer); } else { s = new SceneTextures(sceneID, this._option, this._imageLoader); } this._sceneID_sceneBin_map[sceneID] = s; } return s; } removeScene(sceneID: string): void { const s: ISceneTextures = this._getSceneBin(sceneID, false); if (!s) { return; } if (this._activatedScene == s) { this._activatedScene = null; } s.destroy(); delete this._sceneID_sceneBin_map[sceneID]; this.imageRemoved(`scend(${sceneID}) removed.`); } imageRemoved(reason: string): void { clog(`AtlasManager::imageRemoved - ${reason}`); this._activatedScene && this._activatedScene._internal_imageRemoved(); this._imageLoader.requestSync(); } clearProject(): void { clog('clearProject'); this._imageLoader.empty(); each(this._sceneID_sceneBin_map, (bin: ISceneTextures) => { bin.destroy(); }); this._sceneID_sceneBin_map = {}; this._activatedScene = null; } } ================================================ FILE: src/class/pixi/atlas/PIXIScaleAdaptor.ts ================================================ /** * 텍스쳐가 너무 커서 리사이즈 된 경우에 그만큼 보정하기 위한 클래스. * 예를 들어 원본크기가 2048, 리사이즈를 1024로 했으면 scaleFactor = 2; * entity에서 scale = 5 로 설정하면 * Sprite.scale = entiry.scale(5) * scaleFactor(2) = 10 이 된다. */ import { DisplayObject, Sprite, Point, ObservablePoint } from 'pixi.js'; import { IDestroyer } from '../../../util/destroyer/Destroyer'; import { AtlasTexture } from '../atlas/texture/AtlasTexture'; type AdaptorConstructor = new () => ScaleFactorNormalAdaptor; export namespace PIXIScaleAdaptor { export function factory(target: DisplayObject): ScaleFactorNormalAdaptor { const clazz: AdaptorConstructor = target instanceof Sprite ? ScaleFactorSpriteAdaptor : ScaleFactorNormalAdaptor; const adaptor: ScaleFactorNormalAdaptor = new clazz(); adaptor._internal_init(target); return adaptor; } } class ScaleFactorNormalAdaptor implements IDestroyer { public scale: ScaleFactorPoint; public pivot: ScaleFactorPoint; protected _target: DisplayObject; _internal_init(target: DisplayObject) { this._target = target; this.scale = new ScaleFactorPoint(target.scale, 'scale'); this.pivot = new ScaleFactorPoint(target.pivot, 'pivot'); } updateScaleFactor() { //do nothing } destroy() { this.pivot.destroy(); this.scale.destroy(); this._target = null; this.pivot = null; this.scale = null; } } class ScaleFactorSpriteAdaptor extends ScaleFactorNormalAdaptor { updateScaleFactor() { const sp = this._target as Sprite; const tex = sp.texture as AtlasTexture; const sfx = tex.textureScaleFactorX; const sfy = tex.textureScaleFactorY; if (!sfx || !sfy) { return; } this.scale.internal_setScaleFactor(sfx, sfy); this.pivot.internal_setScaleFactor(1 / sfx, 1 / sfy); } } class ScaleFactorPoint { private _scaleX: number = 1; private _scaleY: number = 1; private _x: number = 0; private _y: number = 0; // eslint-disable-next-line no-useless-constructor constructor(protected _point: Point | ObservablePoint, protected name: string) {} internal_setScaleFactor(x: number, y: number) { this._scaleX = x; this._scaleY = y; this.set(this._x, this._y); } setX(value: number): void { this._x = value; this._point.x = value * this._scaleX; } setY(value: number): void { this._y = value; this._point.y = value * this._scaleY; } set(x: number, y: number): void { this._x = x; this._y = y || (y != 0 ? x : 0); this._point.set(this._x * this._scaleX, this._y * this._scaleY); } destroy(): void { this._point = null; } } ================================================ FILE: src/class/pixi/atlas/SceneBins.ts ================================================ /** * 하나의 Scene에서 사용하는 이미지들을 TextureAtlas 로 만들어줌. */ import { IRawPicture } from './model/IRawPicture'; import PIXIHelper from '../helper/PIXIHelper'; import { AtlasCanvasViewer } from './AtlasCanvasViewer'; import { AtlasImageLoadingInfo } from './loader/AtlasImageLoadingInfo'; import { PrimitiveSet } from './structure/PrimitiveSet'; import { MaxRectsPacker } from '../../maxrect-packer/maxrects_packer'; import { MaxRectsBin } from '../../maxrect-packer/maxrects_bin'; import { AtlasTexture } from './texture/AtlasTexture'; import { AtlasBaseTexture } from './texture/AtlasBaseTexture'; import { PrimitiveMap } from './structure/PrimitiveMap'; import { AtlasImageLoader } from './loader/AtlasImageLoader'; import { PIXIAtlasHelper } from './PIXIAtlasHelper'; import { TimeoutTimer } from '../utils/TimeoutTimer'; import { ImageRect } from '../../maxrect-packer/geom/ImageRect'; import { EntryTextureOption } from './EntryTextureOption'; import { ISceneTextures } from './ISceneTextures'; import each from 'lodash/each'; const TIMEOUT_INTERVAL = 250; /** * packing 이 되기전에 texture 객체를 생성하기 위한 BaseTexture */ let EMPTY_BASE_TEX: AtlasBaseTexture; export class SceneBins implements ISceneTextures { private static initEmptyTex(maxSize: number) { if (EMPTY_BASE_TEX) { return; } const TEX = new AtlasBaseTexture(); EMPTY_BASE_TEX = TEX; TEX.setRealSize(maxSize, maxSize); TEX.setSize(maxSize, maxSize); const tex: any = TEX; const emptyEmit = function() {}; tex.destroy = emptyEmit; tex.on = emptyEmit; tex.once = emptyEmit; tex.emit = emptyEmit; } //private _pathSet:PrimitiveSet = new PrimitiveSet();//패킹 전/후 pathf르 모두 저장. private _packedRects: ImageRect[] = []; private _notPackedRects: ImageRect[] = []; private _arrBaseTexture: AtlasBaseTexture[] = []; private _packer: MaxRectsPacker; private _path_tex_map: PrimitiveMap = new PrimitiveMap(); private _activated: boolean; private _imageRemoved: boolean; private _timer: TimeoutTimer = new TimeoutTimer(); constructor( public sceneID: string, private _option: EntryTextureOption, private _loader: AtlasImageLoader, private _viewer: AtlasCanvasViewer ) { SceneBins.initEmptyTex(_option.atlasOption.atlasSize); this._packer = _option.atlasOption.newPacker(); } addPicInfo(pic: IRawPicture): void { const path = PIXIAtlasHelper.getRawPath(pic); if (this._path_tex_map.hasValue(path)) { return; } const rect: ImageRect = PIXIAtlasHelper.getNewImageRect(pic, this._option.texMaxRect); this._loader.load(pic, rect); const tex: AtlasTexture = this._newTexture(path, rect); rect.data = { path, tex }; this._notPackedRects.push(rect); if (!this._activated) { return; } if (this._timer.isRunning) { return; } console.log('pack scheduled'); this._timer.timeout(TIMEOUT_INTERVAL, () => { if (this._imageRemoved) { console.log('삭제된 이미지가 있어서 invalidate'); this._invalidate(); } else { console.log('just packing'); this._pack(); } }); } private _newTexture(path: string, rect: ImageRect): AtlasTexture { const tex = new AtlasTexture(EMPTY_BASE_TEX, rect); this._path_tex_map.add(path, tex); return tex; } /** 패킹 하지 않은 Rect를 packing 한다. */ private _pack() { if (!this._notPackedRects.length) { return; } const len = this._notPackedRects.length; let time = new Date().getTime(); this._packer.addArray(this._notPackedRects); const willUpdateBaseTextures: AtlasBaseTexture[] = []; this._notPackedRects.forEach((r: ImageRect) => { const base: AtlasBaseTexture = this._getBaseTexture(r.binIndex); r.data.tex.updateBaseAndUVs(base); const imgInfo = this._loader.getImageInfo(r.data.path); if (!imgInfo.isReady) { return; } this.putImage(imgInfo, false); if (willUpdateBaseTextures.indexOf(base) == -1) { willUpdateBaseTextures.push(base); } }); willUpdateBaseTextures.forEach((base: AtlasBaseTexture) => { base.update(); }); this._destroyBaseTextureAfter(this._packer.bins.length); this._packedRects = this._packedRects.concat(this._notPackedRects); this._notPackedRects = []; time = new Date().getTime() - time; console.log(`pack ${len} items. time:${time}`); } activate(): void { this._activated = true; this._invalidate(); const BASE_TEX_MAX_SIZE = this._option.atlasOption.atlasSize; each(this._packer.bins, (bin: MaxRectsBin, index: number) => { const base: AtlasBaseTexture = this._arrBaseTexture[index]; base.activate(BASE_TEX_MAX_SIZE); base.update(); }); const EXTRUDE_SIZE = this._option.atlasOption.extrudeSize; this._path_tex_map.each((t: AtlasTexture, path: string) => { const info = this._loader.getImageInfo(path); if (!info || !info.isReady) { return; } t.drawImageAtBaseTexture(info, EXTRUDE_SIZE); }); } private _getBaseTexture(index: number): AtlasBaseTexture { let base: AtlasBaseTexture = this._arrBaseTexture[index]; if (base) { return base; } const OP = this._option; base = new AtlasBaseTexture(this._viewer, OP.scaleMode); base.setCanvas(PIXIHelper.getOffScreenCanvas()); // base.imageType = 'png'; deprecated v5 base.setRealSize(OP.atlasOption.atlasSize, OP.atlasOption.atlasSize); base.setSize(OP.atlasOption.atlasSize, OP.atlasOption.atlasSize); base.mipmap = OP.mipmap; this._arrBaseTexture[index] = base; return base; } deactivate() { this._timer.reset(); this._activated = false; each(this._arrBaseTexture, (b: AtlasBaseTexture) => { b.deactivate(); }); } getTexture(path: string): AtlasTexture { return this._path_tex_map.getValue(path); } /** * Scene이 활성화 되어 있을때 이미지가 로드 되면 이 함수를 통해 로드된 이미지 정보가 주입됨. * @param info * @param forceUpdateBaseTexture */ putImage(info: AtlasImageLoadingInfo, forceUpdateBaseTexture: boolean = true) { if (!info) { return; } const t: AtlasTexture = this.getTexture(info.path); if (!t) { return; } //이 Scene에서 사용안함 if (t.isEmptyTexture) { return; } // console.log("put imgageData"); const atlasOption = this._option.atlasOption; const base: AtlasBaseTexture = t.getBaseTexture(); if (!base.activated) { base.activate(atlasOption.atlasSize); } t.drawImageAtBaseTexture(info, atlasOption.extrudeSize); if (forceUpdateBaseTexture) { base.update(); } Entry.requestUpdate = true; } /** * 모든 텍스쳐 패킹을 다시 한다. * @private */ private _invalidate(): void { if (!this._activated) { return; } this._imageRemoved = false; const usedPathSet: PrimitiveSet = PIXIAtlasHelper.getScenePathSet(this.sceneID); this._notPackedRects.length = 0; this._packedRects.length = 0; const unusedPath: string[] = []; //사용안하는 path를 검색, 패킹을 다시 할 것이기 때문에 사용하는 텍스쳐의 rect 정보를 저장. this._path_tex_map.each((tex: AtlasTexture, path: string) => { if (usedPathSet && usedPathSet.hasValue(path)) { this._notPackedRects.push(this._path_tex_map.getValue(path).imageRectForPacking); } else { unusedPath.push(path); } }); console.log('unusedPath', unusedPath); //사용안하는 texture를 제거 unusedPath.forEach((path: string) => { this._path_tex_map.remove(path).destroy(false); }); this._packer.empty(); this._cleanCanvas(); this._pack(); } private _cleanCanvas() { const LEN = this._arrBaseTexture.length; for (let i = 0; i < LEN; i++) { this._arrBaseTexture[i].cleanCanvas(); } } _internal_imageRemoved(): void { this._imageRemoved = true; } private _destroyBaseTextureAfter(startIndex: number) { const LEN = this._arrBaseTexture.length; for (let i = startIndex; i < LEN; i++) { this._arrBaseTexture[i].destroy(); } this._arrBaseTexture.length = startIndex; } destroy() { this._timer.reset(); this._path_tex_map.each((tex: AtlasTexture, path: string) => { tex.destroy(false); }); this._path_tex_map.destroy(); this._destroyBaseTextureAfter(0); this._timer = null; this._arrBaseTexture = null; this._path_tex_map = null; this._packer = null; this._viewer = null; this._packedRects = null; this._notPackedRects = null; } } ================================================ FILE: src/class/pixi/atlas/SceneTextures.ts ================================================ import { ISceneTextures } from './ISceneTextures'; import { AtlasImageLoadingInfo } from './loader/AtlasImageLoadingInfo'; import { PrimitiveMap } from './structure/PrimitiveMap'; import { ImageRect } from '../../maxrect-packer/geom/ImageRect'; import { AtlasImageLoader } from './loader/AtlasImageLoader'; import { EntryTextureOption } from './EntryTextureOption'; import { EntryTexture } from './texture/EntryTexture'; import { EntryBaseTexture } from './texture/EntryBaseTexture'; import { IRawPicture } from './model/IRawPicture'; import { PIXIAtlasHelper } from './PIXIAtlasHelper'; import { clog } from '../utils/logs'; import { PrimitiveSet } from './structure/PrimitiveSet'; import { TimeoutTimer } from '../utils/TimeoutTimer'; export class SceneTextures implements ISceneTextures { private _path_tex_map: PrimitiveMap = new PrimitiveMap(); private _activated: boolean; private _gcTimer: TimeoutTimer = new TimeoutTimer(); constructor( public sceneID: string, private _option: EntryTextureOption, private _loader: AtlasImageLoader ) {} _internal_imageRemoved(): void { if (this._gcTimer.isRunning) { return; } this._gcTimer.timeout(500, () => { this._gcTexture(); }); } _gcTexture(): void { const usedPathSet: PrimitiveSet = PIXIAtlasHelper.getScenePathSet(this.sceneID); let deleteCnt = 0; this._path_tex_map.each((tex: EntryTexture, path: string) => { if (usedPathSet.hasValue(path)) { return; } tex.destroy(true); this._path_tex_map.remove(path); deleteCnt++; }); if (deleteCnt) { clog(`[SceneTextures] ${deleteCnt} textures deleted`); } } activate(): void { this._activated = true; this._path_tex_map.each((tex: EntryTexture, path: string) => { const info = this._loader.getImageInfo(path); if (!info || !info.isReady) { return; } this.putImage(info, false); }); } addPicInfo(pic: IRawPicture): void { const path = PIXIAtlasHelper.getRawPath(pic); const map = this._path_tex_map; if (map.hasValue(path)) { return; } const info = this._loader.getImageInfo(path); const rect: ImageRect = PIXIAtlasHelper.getNewImageRect(pic, this._option.texMaxRect); if (!info) { this._loader.load(pic, rect); } const tex = this._newTexture(path, rect); map.add(path, tex); if (info && info.isReady) { this.putImage(info, false); } } private _newTexture(path: string, rect: ImageRect): EntryTexture { const baseTex: EntryBaseTexture = new EntryBaseTexture(); baseTex.width = rect.width; baseTex.height = rect.height; baseTex.mipmap = this._option.mipmap; baseTex.scaleMode = this._option.scaleMode; const tex = new EntryTexture(baseTex, rect); this._path_tex_map.add(path, tex); return tex; } deactivate(): void { this._activated = false; this._path_tex_map.each((tex: EntryTexture, path: string) => { tex.getBaseTexture().dispose(); }); } getTexture(path: string): EntryTexture { return this._path_tex_map.getValue(path); } putImage(info: AtlasImageLoadingInfo, forceUpdateBaseTexture: boolean): void { const tex: EntryTexture = this._path_tex_map.getValue(info.path); if (!tex) { return; } const baseTex = tex.getBaseTexture(); const source = info.source(); // protected 값에대한 직접접근입니다. 타입체크 하지않습니다. // @ts-ignore if (tex._frame) { // @ts-ignore const textureFrame = tex._frame; if (textureFrame.height != info.srcHeight) { textureFrame.height = info.srcHeight; } if (textureFrame.width != info.srcWidth) { textureFrame.width = info.srcWidth; } } baseTex.updateSource(source); Entry.requestUpdate = true; } destroy(): void { clog('destroy', this.sceneID); this._gcTimer.reset(); this._gcTimer = null; this._path_tex_map.each((tex: EntryTexture, path: string) => { tex.destroy(true); }); this._path_tex_map.destroy(); this._path_tex_map = null; } } ================================================ FILE: src/class/pixi/atlas/loader/AtlasImageLoader.ts ================================================ import { AtlasImageLoadingInfo } from './AtlasImageLoadingInfo'; import { IRawPicture } from '../model/IRawPicture'; import { PrimitiveSet } from '../structure/PrimitiveSet'; import { TimeoutTimer } from '../../utils/TimeoutTimer'; import { PIXIAtlasHelper } from '../PIXIAtlasHelper'; import { ImageRect } from '../../../maxrect-packer/geom/ImageRect'; import { clog } from '../../utils/logs'; // @ts-ignore import each from 'lodash/each'; const TIME_OUT_DELAY: number = 1000; type LoadingInfoMap = { [key: string]: AtlasImageLoadingInfo }; export type ImageLoaderHandler = (info: AtlasImageLoadingInfo) => void; declare let Entry: any; export class AtlasImageLoader { private _path_info_map: LoadingInfoMap = {}; private _timer: TimeoutTimer = new TimeoutTimer(); private _syncRequested: boolean; constructor(private _onLoadCallback: ImageLoaderHandler) {} /** * model 의 이미지를 로드 후, rect.scaleFactor가 1이 아닐경우 rect 만큼 리사이즈한 canvas 를 소스로 설정하긔 * @param model * @param imgRect * @param subCallback */ load(model: IRawPicture, imgRect: ImageRect) { const path = PIXIAtlasHelper.getRawPath(model); let info: AtlasImageLoadingInfo = this._path_info_map[path]; if (info) { return; } info = new AtlasImageLoadingInfo(model, imgRect, this._onLoadCallback); this._path_info_map[path] = info; info.load(); } getImageInfo(rawPath: string): AtlasImageLoadingInfo { return this._path_info_map[rawPath]; } /** * 엔트리오브젝트에서 사용중인 이미지 리스트와 싱크를 맞춰 사용하지 않는 이미지 정보를 삭제함. */ private _syncWithEntryObjects() { this._syncRequested = false; const arrObj: any[] = Entry.container.getAllObjects(); const allPathSet: PrimitiveSet = new PrimitiveSet(); const LEN = arrObj.length; let LEN2; let pics: IRawPicture[]; let pic: IRawPicture; for (let i = 0; i < LEN; i++) { pics = arrObj[i].pictures; if (!pics || !(LEN2 = pics.length)) { continue; } for (let j = 0; j < LEN2; j++) { pic = pics[j]; allPathSet.put(pic.filename || pic.fileurl); } } let deleteCnt = 0; each(this._path_info_map, (info: AtlasImageLoadingInfo, path: string) => { if (allPathSet.hasValue(path)) { return; } info.destroy(); deleteCnt++; delete this._path_info_map[path]; }); if (deleteCnt > 0) { clog(`${deleteCnt} image item(s) deleted`); } } /** * 로드/케시된 모든 정보를 지움. */ empty() { this._timer.reset(); this._syncRequested = false; each(this._path_info_map, (info: AtlasImageLoadingInfo, path: string) => { info.destroy(); }); this._path_info_map = {}; } requestSync() { if (this._syncRequested) { return; } this._syncRequested = true; this._timer.timeout(TIME_OUT_DELAY, () => { this._syncWithEntryObjects(); }); } } ================================================ FILE: src/class/pixi/atlas/loader/AtlasImageLoadingInfo.ts ================================================ import { IRawPicture } from '../model/IRawPicture'; import { PIXIAtlasHelper } from '../PIXIAtlasHelper'; import { ImageRect } from '../../../maxrect-packer/geom/ImageRect'; import PIXIHelper from '../../helper/PIXIHelper'; import { cwarn } from '../../utils/logs'; import { ImageLoaderHandler } from './AtlasImageLoader'; declare let Entry: any; enum LoadingState { NONE = 1, LOADING = 2, COMPLETE = 3, DESTROYED = 4, } export class AtlasImageLoadingInfo { loadState: LoadingState = LoadingState.NONE; private _img: HTMLImageElement; private _canvas: HTMLCanvasElement; /** 계산된 이미지 경로. */ private _realPath: string; /** picture json 에 정의된 경로. fileurl or filename */ private _rawPath: string; private _triedCnt: number = 0; private _picName: string; // 로드된 이미지 혹은 resize된 이미지의 사이즈. dimension 의 값과 다른 경우가 있어서 추가함. public srcWidth: number; public srcHeight: number; private _subCallback: ImageLoaderHandler[] = []; /** * model 의 이미지를 로드 후, imgRect.scaleFactor가 1이 아닐경우 imgRect 만큼 리사이즈한 canvas 를 소스로 설정하긔 * @param model * @param _imgRect * @param _onLoadCallback */ constructor( model: IRawPicture, private _imgRect: ImageRect, private _onLoadCallback: ImageLoaderHandler ) { this._realPath = this._getImageSrc(model); this._rawPath = PIXIAtlasHelper.getRawPath(model); this._picName = model.name; } source(): HTMLImageElement | HTMLCanvasElement { return this._img || this._canvas; } /** * 이미지가 로드 되면 호출 할 콜백들. 이미지가 로드 된 후 add된 값들은 무시 됨. * @param fn */ addCallback(fn: ImageLoaderHandler): void { if (!fn || this.isReady) { return; } this._subCallback.push(fn); } load() { if (this.loadState != LoadingState.NONE) { return; } this.loadState = LoadingState.LOADING; const img: HTMLImageElement = new Image(); this._img = img; img.crossOrigin = 'Anonymous'; img.onload = () => { Entry.Loader.removeQueue(); if (this.loadState == LoadingState.DESTROYED) { return; } this.loadState = LoadingState.COMPLETE; this._canvas = this._resizeIfNotValidSize(); if (this._canvas) { this._destroyImage(); } this._onLoadCallback(this); this._onLoadCallback = null; this._subCallback.forEach((fn) => { fn(this); }); this._subCallback = null; }; img.onerror = (err) => { Entry.Loader.removeQueue(); if (this.loadState == LoadingState.DESTROYED) { return; } if (!this._triedCnt) { if (Entry.type !== 'invisible') { console.log('err=', this._picName, 'load failed'); } this._triedCnt = 1; this._loadPath(this._realPath); } else if (this._triedCnt < 3) { this._triedCnt++; this._loadPath(`${Entry.mediaFilePath}_1x1.png`); } else { //prevent infinite call img.onerror = null; } }; this._loadPath(this._realPath); } private _loadPath(path: string) { if (this.loadState == LoadingState.DESTROYED) { return; } Entry.Loader.addQueue(); this._img.src = path; } get isReady() { return this.loadState == LoadingState.COMPLETE; } /** pictureModel.fileurl or pictureModel.filename **/ get path(): string { return this._rawPath; } private _getImageSrc(picture: IRawPicture) { if (picture.fileurl) { return picture.fileurl; } const name = picture.filename; return `${Entry.defaultPath}/uploads/${name.substring(0, 2)}/${name.substring( 2, 4 )}/image/${name}.png`; } destroy() { this.loadState = LoadingState.DESTROYED; this._destroyImage(); if (this._canvas) { this._canvas = null; } this._subCallback = null; this._rawPath = this._realPath = null; } private _destroyImage() { if (!this._img) { return; } this._img.onload = this._img.onerror = null; this._img = null; } private _resizeIfNotValidSize() { const img: HTMLImageElement = this._img; const sw = img.naturalWidth || img.width; const sh = img.naturalHeight || img.height; this.srcWidth = sw; this.srcHeight = sh; const r = this._imgRect; const isScale1 = r.scaleFactorX == 1 && r.scaleFactorY == 1; const isSameSizeWithData = r.dataWidth == sw && r.dataHeight == sh; if (isScale1 && isSameSizeWithData) { return null; } // if(!isScale1) { // let sfx = r.scaleFactorX.toFixed(3); // let sfy = r.scaleFactorY.toFixed(3); // clog(`tex-rezie (${sw},${sh})->(${r.width},${r.height}). factor:(${sfx},${sfy})`); // } if (!isSameSizeWithData) { cwarn( `Image size not match. data(w=${r.dataWidth},h=${r.dataHeight}), real(w=${sw},h=${sh})` ); } const canvas = PIXIHelper.getOffScreenCanvas(); this.srcWidth = canvas.width = r.width; this.srcHeight = canvas.height = r.height; const ctx: CanvasRenderingContext2D = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; ctx.drawImage(img, 0, 0, r.width, r.height); return canvas; } } ================================================ FILE: src/class/pixi/atlas/model/IRawObject.ts ================================================ import { IRawPicture } from './IRawPicture'; export interface IRawObject { id: string, name: string, script: string, objectType: string, rotateMethod: string, scene: string, sprite:{ pictures:IRawPicture[], sounds:any[] }, text: string, lock: boolean, entity: any } ================================================ FILE: src/class/pixi/atlas/model/IRawPicture.ts ================================================ export interface IRawPicture { id:string; dimension: { width:number, height:number }; fileurl:string; filename:string; name:string; } ================================================ FILE: src/class/pixi/atlas/structure/PrimitiveMap.ts ================================================ // @ts-ignore import each from 'lodash/each'; export class PrimitiveMap { private _map: { [key: string]: T } = {}; add(key: string | number, value: T) { this._map[key] = value; } getValue(key: string | number): T { return this._map[key]; } hasValue(key: string | number): boolean { return Boolean(this._map[key]); } remove(key: string | number): T { const v: T = this._map[key]; delete this._map[key]; return v; } destroy(): void { this._map = null; } each(f: (value: T, key: string | number) => void): void { each(this._map, f); } } ================================================ FILE: src/class/pixi/atlas/structure/PrimitiveSet.ts ================================================ // @ts-ignore import each from 'lodash/each'; export class PrimitiveSet { private _map: any = {}; hasValue(value: string | number): boolean { return this._map[value]; } put(value: string | number) { this._map[value] = true; } remove(value: string | number) { delete this._map[value]; } each(callback: (value: string | number) => void) { each(this._map, (v: boolean, key: string) => { callback(key); }); } } ================================================ FILE: src/class/pixi/atlas/texture/AtlasBaseTexture.ts ================================================ import { BaseTexture, resources } from 'pixi.js'; import { AtlasCanvasViewer } from '../AtlasCanvasViewer'; export class AtlasBaseTexture extends BaseTexture { private _canvas: HTMLCanvasElement; private _ctx: CanvasRenderingContext2D; private _activated: boolean; constructor(private _viewer?: AtlasCanvasViewer, scaleMode?: number) { super(null, { scaleMode }); } get activated(): boolean { return this._activated; } setCanvas(canvas: HTMLCanvasElement) { const resource = new resources.CanvasResource(canvas); this.setResource(resource); this._canvas = canvas; this._ctx = canvas.getContext('2d'); } getCanvas(): HTMLCanvasElement { return this._canvas; } cleanCanvas(): void { this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height); } activate(MAX_SIZE: number) { this._activated = true; this._canvas.width = MAX_SIZE; this._canvas.height = MAX_SIZE; // this.hasLoaded = true; deprecated v5 this._viewer.add(this._canvas); } deactivate() { this._activated = false; this._canvas.width = 1; this._canvas.height = 1; this.dispose(); } destroy() { super.destroy(); this._canvas = null; this._ctx = null; } dispose() { super.dispose(); if (this._viewer) { this._viewer.removeCanvas(this._canvas); } } getCtx() { return this._ctx; } } ================================================ FILE: src/class/pixi/atlas/texture/AtlasTexture.ts ================================================ /* 생성자에서 empty base texture 를 받은 후, sprite 를 통해 즉시 stage에서 사용 할 수 있도록 함. */ import { AtlasBaseTexture } from './AtlasBaseTexture'; import { ImageRect } from '../../../maxrect-packer/geom/ImageRect'; import { AtlasImageLoadingInfo } from '../loader/AtlasImageLoadingInfo'; import { EntryTextureBase } from './EntryTextureBase'; export class AtlasTexture extends EntryTextureBase { /** binpacking의 rect 참조를 위한 변수. 다용 용도로 사용하지 말긔. */ public imageRectForPacking: ImageRect; private _isEmptyTexture: boolean; public textureScaleFactorX: number; public textureScaleFactorY: number; constructor(baseTexture: AtlasBaseTexture, imageRect: ImageRect) { super(baseTexture, imageRect); this._isEmptyTexture = true; this.imageRectForPacking = imageRect; } get isEmptyTexture(): boolean { return this._isEmptyTexture; } getBaseTexture(): AtlasBaseTexture { return this.baseTexture as AtlasBaseTexture; } /** * @param info * @param extrude - must uint value. Reduce flickering in some cases where sprites have to be put next to each other in the final program. * example: https://www.codeandweb.com/texturepacker/documentation/texture-settings */ drawImageAtBaseTexture(info: AtlasImageLoadingInfo, extrude: number): void { if (this._isEmptyTexture) { return; } const img = info.source(); const ctx: CanvasRenderingContext2D = this.getBaseTexture().getCtx(); const r = this.frame; const w = r.width; const h = r.height; const rx = r.x; const ry = r.y; const sw = info.srcWidth; const sh = info.srcHeight; /* //for debug background ctx.fillStyle = PIXIHelper.randomRGBAString(0.3); ctx.fillRect(rx, ry, w, h); //*/ ctx.drawImage(img, 0, 0, sw, sh, rx, ry, w, h); if (extrude) { ctx.save(); ctx.imageSmoothingEnabled = false; //top ctx.drawImage(img, 0, 0, sw, 1, rx, ry - extrude, w, extrude); //down ctx.drawImage(img, 0, sh - 1, sw, 1, rx, ry + h, w, extrude); //left ctx.drawImage(img, 0, 0, 1, sh, rx - extrude, ry, extrude, h); //right ctx.drawImage(img, sw - 1, 0, 1, sh, rx + w, ry, extrude, h); ctx.restore(); } } /** * 진짜로 사용할 BaseTexture를 할당 받고, uv를 업데이트 함. * @param base */ updateBaseAndUVs(base: AtlasBaseTexture): void { this._isEmptyTexture = false; this.baseTexture = base; if ( this.frame.x != this.imageRectForPacking.x || this.frame.y != this.imageRectForPacking.y ) { this.frame.x = this.imageRectForPacking.x; this.frame.y = this.imageRectForPacking.y; this._updateUvs(); } } } ================================================ FILE: src/class/pixi/atlas/texture/EntryBaseTexture.ts ================================================ import { BaseTexture, resources } from 'pixi.js'; export class EntryBaseTexture extends BaseTexture { private _hasSource: boolean; updateSource(src: HTMLImageElement | HTMLCanvasElement) { if (!this.resource) { const resource = resources.autoDetectResource(src); this.setResource(resource); this.update(); } } } ================================================ FILE: src/class/pixi/atlas/texture/EntryTexture.ts ================================================ import { ImageRect } from '../../../maxrect-packer/geom/ImageRect'; import { EntryBaseTexture } from './EntryBaseTexture'; import { EntryTextureBase } from './EntryTextureBase'; export class EntryTexture extends EntryTextureBase { constructor(baseTexture: EntryBaseTexture, imageRect: ImageRect) { super(baseTexture, imageRect); } getBaseTexture(): EntryBaseTexture { return this.baseTexture as EntryBaseTexture; } } ================================================ FILE: src/class/pixi/atlas/texture/EntryTextureBase.ts ================================================ import { ImageRect } from '../../../maxrect-packer/geom/ImageRect'; import { Texture, RenderTexture, Rectangle, BaseTexture } from 'pixi.js'; export class EntryTextureBase extends Texture { public textureScaleFactorX: number; public textureScaleFactorY: number; constructor(baseTexture: BaseTexture, imageRect: ImageRect) { const frame = new Rectangle(0, 0, imageRect.width, imageRect.height); super(baseTexture, frame); this.textureScaleFactorX = imageRect.scaleFactorX; this.textureScaleFactorY = imageRect.scaleFactorY; } assignTextureScaleFactor(target: RenderTexture) { if (target) { const tex: any = target; //textureScaleFactor 변수 네이밍을 여기저기서 쓰지 않으려고 메서드를 만듬. tex.textureScaleFactorX = this.textureScaleFactorX; tex.textureScaleFactorY = this.textureScaleFactorY; } } } ================================================ FILE: src/class/pixi/etc/PIXI-ndgmr.Collision.js ================================================ /* The MIT License Copyright (c) 2012 Olaf Horstmann, indiegamr.com 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. */ /** * [original] * A Pixel Perfect Collision Detection for EaselJS Bitmap-Objects * @author olsn, indiegamr.com * * [edit 2018.09.01] * A Pixel Perfect Collision Detection for entryjs PIXI.Sprite-Object * **/ import * as PIXI from 'pixi.js'; const ndgmr = {}; //--------- Class CollisionCanvas ------- class CollisionCanvas { constructor() { /** @readonly **/ this._canvas = document.createElement('canvas'); this._ctx = this._canvas.getContext('2d'); this._ctx.save(); this._prepended = false; } /** * for debug * @param color css style color */ __prepend(color) { if (this._prepended) { return; } this._prepended = true; $('body').prepend(this._canvas); $(this._canvas).css('border', `1px solid ${color}`); } render(obj, intersectRect) { const tex = obj.internal_getOriginalTex(); if (!tex) { return; } const fr = tex.frame; if (!fr || fr.width === 0 || fr.height === 0) { return; } if (!tex.baseTexture) { return; } const { source } = tex.baseTexture.resource || {}; if (!source) { return; } const IR = intersectRect; const canvas = this._canvas; const ctx = this._ctx; canvas.width = IR.width; canvas.height = IR.height; obj.toLocal(IR, null, _LP); const { a, b, c, d } = obj.worldTransform; ctx.setTransform(a, b, c, d, 0, 0); ctx.translate(-_LP.x, -_LP.y); ctx.drawImage(source, fr.x, fr.y, fr.width, fr.height, 0, 0, fr.width, fr.height); return ctx.getImageData(0, 0, IR.width, IR.height).data; } } //--------- end of Class CollisionCanvas ------- const threshold = 1; /** @type PIXI.Rectangle; **/ let _RECT1; let _RECT2; /** @type PIXI.Point. for global to local point **/ let _LP; //localPoint /** @type CollisionCanvas **/ let canvas1; let canvas2; /** @private use only debug. **/ ndgmr.___debugIntersectionRect = null; ndgmr.initTempObject = function() { _RECT1 = new PIXI.Rectangle(); _RECT2 = new PIXI.Rectangle(); _LP = new PIXI.Point(); canvas1 = new CollisionCanvas(); canvas2 = new CollisionCanvas(); }; function isContainer(obj) { const isSprite = obj instanceof PIXI.Sprite; if (isSprite) { return false; } return obj instanceof PIXI.Container; } ndgmr.checkPixelCollision = function(bitmap1, bitmap2, alphaThreshold, getRect) { if (ndgmr.DEBUG || ndgmr.DEBUG_COLLISION) { canvas2.__prepend('blue'); canvas1.__prepend('red'); } bitmap1.getBounds(false, _RECT1); bitmap2.getBounds(false, _RECT2); if (!_collisionDistancePrecheck(_RECT1, _RECT2)) { return false; } const intersection = _checkRectCollisionForPIXIRect(_RECT1, _RECT2); ndgmr.___debugIntersectionRect = intersection; if (!intersection) { return false; } //글상자와 벽 충돌 체크 if (isContainer(bitmap1) || isContainer(bitmap2)) { return intersection; } const iw = intersection.width; const ih = intersection.height; if (iw === 0 || ih === 0) { return false; } //chrome float point number bug if (iw / threshold < 1 || ih / threshold < 1) { return false; } alphaThreshold = Math.min(0.99999, alphaThreshold || 0); let imgData1; let imgData2; if ( !(imgData1 = canvas1.render(bitmap1, intersection)) || !(imgData2 = canvas2.render(bitmap2, intersection)) ) { return false; } const pixelIntersection = _compareAlphaValues( imgData1, imgData2, iw / threshold, ih / threshold, alphaThreshold, getRect ); if (!pixelIntersection) { return false; } pixelIntersection.x += intersection.x; pixelIntersection.x2 += intersection.x; pixelIntersection.y += intersection.y; pixelIntersection.y2 += intersection.y; return pixelIntersection; }; /** * precheck if objects are even close enough * @param {PIXI.Rectangle} ir1 * @param {PIXI.Rectangle} ir2 * @return {boolean} * @private */ function _collisionDistancePrecheck(ir1, ir2) { return ( Math.abs(ir2.x - ir1.x) < (ir1.x < ir2.x ? ir1.width : ir2.width) && Math.abs(ir2.y - ir1.y) < (ir1.y < ir2.y ? ir1.height : ir2.height) ); } /** * TODO createjs 코드 인데.. 사용하느곳이 있는지 확인. * createjs legacy interface. not use internally. * @param bitmap1 * @param bitmap2 * @return {null| Rect} */ ndgmr.checkRectCollision = function(bitmap1, bitmap2) { let b1; let b2; if (bitmap1 instanceof createjs.Container || bitmap2 instanceof createjs.Container) { b1 = bitmap1.getTransformedBounds(); b2 = bitmap2.getTransformedBounds(); } else { b1 = getBounds(bitmap1); b2 = getBounds(bitmap2); } return _checkRectCollisionForPIXIRect(b1, b2); }; function _checkRectCollisionForPIXIRect(b1, b2) { // 2018.12.14 박봉배 - 불필요한 연산이라 비활성화함. 상단에서 threshold 의 기본값을 1로 고정 // if (Math.min(b1.width, b1.height, b2.width, b2.height) < 2) // threshold = 1; // else // threshold = 1; return ndgmr.calculateIntersection(b1, b2); } ndgmr.calculateIntersection = function(rect1, rect2) { // first we have to calculate the // center of each rectangle and half of // width and height let dx; let dy; const r1 = {}; const r2 = {}; r1.cx = rect1.x + (r1.hw = rect1.width / 2); r1.cy = rect1.y + (r1.hh = rect1.height / 2); r2.cx = rect2.x + (r2.hw = rect2.width / 2); r2.cy = rect2.y + (r2.hh = rect2.height / 2); dx = Math.abs(r1.cx - r2.cx) - (r1.hw + r2.hw); dy = Math.abs(r1.cy - r2.cy) - (r1.hh + r2.hh); if (dx < 0 && dy < 0) { dx = Math.min(Math.min(rect1.width, rect2.width), -dx); dy = Math.min(Math.min(rect1.height, rect2.height), -dy); return { x: Math.max(rect1.x, rect2.x), y: Math.max(rect1.y, rect2.y), width: dx, height: dy, rect1, rect2, }; } else { return null; } }; const _compareAlphaValues = function( imageData1, imageData2, width, height, alphaThreshold, getRect ) { let x; let y; let offset = 3; const pixelRect = { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity }; const _alphaThreshold = Math.round(alphaThreshold * 255) | 0; const _width = width | 0; const _height = height | 0; const _imgData1 = imageData1; const _imgData2 = imageData2; const LEN1 = _imgData1.length; const LEN2 = _imgData2.length; // parsing through the pixels checking for an alpha match // TODO: intelligent parsing, not just from 0 to end! for (y = 0; y < _height; ++y) { for (x = 0; x < _width; ++x) { if ( LEN1 > offset + 1 && LEN2 > offset + 1 && _imgData1[offset] > _alphaThreshold && _imgData2[offset] > _alphaThreshold ) { if (getRect) { if (x < pixelRect.x) { pixelRect.x = x; } if (x > pixelRect.x2) { pixelRect.x2 = x; } if (y < pixelRect.y) { pixelRect.y = y; } if (y > pixelRect.y2) { pixelRect.y2 = y; } } else { return { x, y, width: 1, height: 1 }; } } offset += 4; } } if (pixelRect.x != Infinity) { pixelRect.width = pixelRect.x2 - pixelRect.x + 1; pixelRect.height = pixelRect.y2 - pixelRect.y + 1; return pixelRect; } return null; }; export const PIXICollision = ndgmr; ================================================ FILE: src/class/pixi/etc/PIXIBrushAdaptor.ts ================================================ import { DisplayObject } from 'pixi.js'; import { PIXIGraphics } from '../helper/PIXIHelper'; interface IRBG { r: number; g: number; b: number; } /** * createjs.Graphics 스타일의 lagacy 메서드 호출을 pixi.Graphics 로 변경해주는 adaptor 클라스. */ export class PIXIBrushAdaptor { //아래 값들은 다른 클래스에서 값을 할당해줌. public rgb: IRBG; public thickness: number; public opacity: number; /** [박봉배] 추측 - drawing 중인지 아닌지를 저장하는 값으로 생각 됨. */ public stop: boolean; /** [박봉배] 추측 - 이 브러시가 따라다녀야 할 대상 */ public entity: DisplayObject; //아래 값들은 내부에서만 사용함. private _alpha: number = 1; private _thickness: number; private _color: number; private _shape: PIXIGraphics; private position: any = { x: 0, y: 0 }; endStroke() { //#10141 때문에 closePath 사용안함. // if(!this._shape || this._shape.destroyied) return; // this._shape.closePath(); } /** * createjs 스타일. 문자열 파싱을 하기 때문에 느림. 블럭 몇몇곳에서 이 스타일을 사용하기 떄문에 남겨둠. * @param color - "#FF0000", "rgba(255,0,0,0.5)" */ beginStroke(color: string) { this._parseRGBCssStyleColor(color); this._setStyle(); } /** * pixi 엔진에 최적화된 함수. beginStroke() 보다 빠름. * @param color * @param alpha */ beginStrokeFast(color: number, alpha: number): void { this._color = color; this._alpha = alpha; this._setStyle(); } endFill() { // #10141 때문에 closePath 사용안함. if (!this._shape || this._shape.destroyed) { return; } this._shape.closePath(); } beginFill(color: string) { this._parseRGBCssStyleColor(color); this._setStyle(); } beginFillFast(color: number, alpha: number) { this._color = color; this._alpha = alpha; this._setStyle(); } setStrokeStyle(thickness: number) { this._thickness = thickness; this._setStyle(); } moveTo(x: number, y: number) { if (!this._shape || this._shape.destroyed) { return; } this._shape.moveTo(Number(x), Number(y)); this.position = { x: Number(x), y: Number(y) }; } lineTo(x: number, y: number) { if (!this._shape || this._shape.destroyed) { return; } //this._setStyle(); // pixi webgl 오류 때문에 이것을 함. this._shape.moveTo(this.position.x, this.position.y); this._shape.lineTo(Number(x), Number(y)); // 박봉배: #9374 x,y 좌표가 문자로 넘어와서 생긴 이슈 this.position = { x: Number(x), y: Number(y) }; this._shape.geometry.invalidate(); } /** @param shape - drawing 을 할 대상을 지정 */ internalSetShape(shape: PIXIGraphics) { this._shape = shape; this._setStyle(); } _setStyle() { if (!this._shape || this._shape.destroyed) { return; } this._shape.lineStyle(this._thickness, this._color, this._alpha); } _parseRGBCssStyleColor(colorOld: string) { const color = colorOld.replace('/s/', ''); if (color[0] == '#') { this._color = parseInt(color.replace('#', ''), 16); return; } let result; //rgb 보다 rgba 문자열을 더 많이 사용하는것 같아 이 조건문을 위로 올림 if ((result = /^rgba\((\d+),(\d+),(\d+),(\d+(\.?\d*))\)$/i.exec(color))) { this._color = this._RGBToNumber(result); this._alpha = Number(result[4]); return; } if ((result = /^rgb\((\d+),(\d+),(\d+)\)$/i.exec(color))) { this._color = this._RGBToNumber(result); } } _RGBToNumber(regexResult: any[]) { const [x, r, g, b] = regexResult; return (r << 16) + (g << 8) + Number(b); } // Matched the method name to createjs for fulfilling the purpose of wrapper class (#11626) clear() { const { x = 0, y = 0 } = this.entity || {}; this._shape.clear(); // Disconnect the previously continued path this._shape.moveTo(x, -y); } } ================================================ FILE: src/class/pixi/etc/PIXICanvasInput.js ================================================ /*! * CanvasInput v1.1.5 * http://goldfirestudios.com/blog/108/CanvasInput-HTML5-Canvas-Text-Input * * (c) 2013-2014, James Simpson of GoldFire Studios * goldfirestudios.com * * MIT License */ import * as PIXI from 'pixi.js'; (function() { // create a buffer that stores all inputs so that tabbing // between them is made possible. const inputs = []; // initialize the Canvas Input // eslint-disable-next-line no-multi-assign const CanvasInput = (window.PIXICanvasInput = function(o) { const self = this; o = o ? o : {}; // setup the defaults self._canvas = o.canvas || null; self._isHidden = true; self._ctx = self._canvas ? self._canvas.getContext('2d') : null; self._x = o.x || 0; self._y = o.y || 0; self._extraX = o.extraX || 0; self._extraY = o.extraY || 0; self._fontSize = o.fontSize || 14; self._fontFamily = o.fontFamily || 'Arial'; self._fontColor = o.fontColor || '#000'; self._placeHolderColor = o.placeHolderColor || '#bfbebd'; self._fontWeight = o.fontWeight || 'normal'; self._fontStyle = o.fontStyle || 'normal'; self._readonly = o.readonly || false; self._maxlength = o.maxlength || null; self._width = o.width || 150; self._height = o.height || self._fontSize; self._padding = o.padding >= 0 ? o.padding : 5; self._borderWidth = o.borderWidth >= 0 ? o.borderWidth : 1; self._borderColor = o.borderColor || '#959595'; self._borderRadius = o.borderRadius >= 0 ? o.borderRadius : 3; self._backgroundImage = o.backgroundImage || ''; self._boxShadow = o.boxShadow || '1px 1px 0px rgba(255, 255, 255, 1)'; self._innerShadow = o.innerShadow || '0px 0px 4px rgba(0, 0, 0, 0.4)'; self._selectionColor = o.selectionColor || 'rgba(179, 212, 253, 0.8)'; self._placeHolder = o.placeHolder || ''; self._value = `${o.value || self._placeHolder}`; self._onsubmit = o.onsubmit || function() {}; self._onkeydown = o.onkeydown || function() {}; self._onkeyup = o.onkeyup || function() {}; self._onfocus = o.onfocus || function() {}; self._onblur = o.onblur || function() {}; self._cursor = false; self._cursorPos = 0; self._hasFocus = false; self._selection = [0, 0]; self._wasOver = false; self._topPosition = o.topPosition; // parse box shadow self.boxShadow(self._boxShadow, true); // calculate the full width and height with padding, borders and shadows self._calcWH(); // setup the off-DOM canvas self._renderCanvas = document.createElement('canvas'); self._renderCanvas.setAttribute('width', self.outerW); self._renderCanvas.setAttribute('height', self.outerH); self._renderCtx = self._renderCanvas.getContext('2d'); const texture = PIXI.Texture.from(self._renderCanvas); self._pixiView = new PIXI.Sprite(texture); self._pixiView.interactive = false; // setup another off-DOM canvas for inner-shadows self._shadowCanvas = document.createElement('canvas'); self._shadowCanvas.setAttribute('width', self._width + self._padding * 2); self._shadowCanvas.setAttribute('height', self._height + self._padding * 2); self._shadowCtx = self._shadowCanvas.getContext('2d'); // setup the background color if (typeof o.backgroundGradient !== 'undefined') { self._backgroundColor = self._renderCtx.createLinearGradient(0, 0, 0, self.outerH); self._backgroundColor.addColorStop(0, o.backgroundGradient[0]); self._backgroundColor.addColorStop(1, o.backgroundGradient[1]); } else { self._backgroundColor = o.backgroundColor || '#fff'; } // setup main canvas events if (self._canvas) { self._canvas.addEventListener( 'mousemove', (e) => { e = e || window.event; self.mousemove(e, self); }, false ); self._canvas.addEventListener( 'mousedown', (e) => { e = e || window.event; self.mousedown(e, self); }, false ); self._canvas.addEventListener( 'touchstart', (e) => { e = e || window.event; self.mousedown(e, self); }, false ); self._canvas.addEventListener( 'mouseup', (e) => { e = e || window.event; self.mouseup(e, self); }, false ); } // setup a global mouseup to blur the input outside of the canvas window.addEventListener( 'mouseup', () => { //e = e || window.event; //if (self._hasFocus && !self._mouseDown) { //self.blur(); //} }, true ); // create the hidden input element self._hiddenInput = document.createElement('input'); self._hiddenInput.className = 'entryCanvasHiddenInput'; self._hiddenInput.type = 'text'; self._hiddenInput.style.position = 'absolute'; self._hiddenInput.style.opacity = 0; self._hiddenInput.style.pointerEvents = 'none'; self._hiddenInput.style.left = '-500px'; self._hiddenInput.style.top = '0px'; self._hiddenInput.style.width = `${self._width}px`; self._hiddenInput.style.height = `${self._height}px`; self._hiddenInput.style.zIndex = -999; if (self._maxlength) { self._hiddenInput.maxLength = self._maxlength; } document.body.appendChild(self._hiddenInput); self._hiddenInput.value = self._value; // setup the keydown listener self._hiddenInput.addEventListener('keydown', (e) => { e = e || window.event; if (self._hasFocus) { self.keydown(e, self); } }); // setup the keyup listener self._hiddenInput.addEventListener('keyup', (e) => { e = e || window.event; // update the canvas input state information from the hidden input self._value = self._hiddenInput.value; self._cursorPos = self._hiddenInput.selectionStart; self.render(); if (self._hasFocus) { self._onkeyup(e, self); } }); // add this to the buffer inputs.push(self); self._inputsIndex = inputs.length - 1; // draw the text box self.render(); }); // setup the prototype CanvasInput.prototype = { getPixiView() { return this._pixiView; }, /** * Get/set the main canvas. * @param {Object} data Canvas reference. * @return {Mixed} CanvasInput or current canvas. */ canvas(data) { const self = this; if (typeof data !== 'undefined') { throw new Error('Deprecated: CanvasInput.canvas'); self._canvas = data; self._ctx = self._canvas.getContext('2d'); return self.render(); } else { return self._canvas; } }, /** * Get/set the x-position. * @param {Number} data The pixel position along the x-coordinate. * @return {Mixed} CanvasInput or current x-value. */ x(data) { const self = this; if (typeof data !== 'undefined') { self._x = data; return self.render(); } else { return self._x; } }, /** * Get/set the y-position. * @param {Number} data The pixel position along the y-coordinate. * @return {Mixed} CanvasInput or current y-value. */ y(data) { const self = this; if (typeof data !== 'undefined') { self._y = data; return self.render(); } else { return self._y; } }, /** * Get/set the extra x-position (generally used when no canvas is specified). * @param {Number} data The pixel position along the x-coordinate. * @return {Mixed} CanvasInput or current x-value. */ extraX(data) { const self = this; if (typeof data !== 'undefined') { self._extraX = data; return self.render(); } else { return self._extraX; } }, /** * Get/set the extra y-position (generally used when no canvas is specified). * @param {Number} data The pixel position along the y-coordinate. * @return {Mixed} CanvasInput or current y-value. */ extraY(data) { const self = this; if (typeof data !== 'undefined') { self._extraY = data; return self.render(); } else { return self._extraY; } }, /** * Get/set the font size. * @param {Number} data Font size. * @return {Mixed} CanvasInput or current font size. */ fontSize(data) { const self = this; if (typeof data !== 'undefined') { self._fontSize = data; return self.render(); } else { return self._fontSize; } }, /** * Get/set the font family. * @param {String} data Font family. * @return {Mixed} CanvasInput or current font family. */ fontFamily(data) { const self = this; if (typeof data !== 'undefined') { self._fontFamily = data; return self.render(); } else { return self._fontFamily; } }, /** * Get/set the font color. * @param {String} data Font color. * @return {Mixed} CanvasInput or current font color. */ fontColor(data) { const self = this; if (typeof data !== 'undefined') { self._fontColor = data; return self.render(); } else { return self._fontColor; } }, /** * Get/set the place holder font color. * @param {String} data Font color. * @return {Mixed} CanvasInput or current place holder font color. */ placeHolderColor(data) { const self = this; if (typeof data !== 'undefined') { self._placeHolderColor = data; return self.render(); } else { return self._placeHolderColor; } }, /** * Get/set the font weight. * @param {String} data Font weight. * @return {Mixed} CanvasInput or current font weight. */ fontWeight(data) { const self = this; if (typeof data !== 'undefined') { self._fontWeight = data; return self.render(); } else { return self._fontWeight; } }, /** * Get/set the font style. * @param {String} data Font style. * @return {Mixed} CanvasInput or current font style. */ fontStyle(data) { const self = this; if (typeof data !== 'undefined') { self._fontStyle = data; return self.render(); } else { return self._fontStyle; } }, /** * Get/set the width of the text box. * @param {Number} data Width in pixels. * @return {Mixed} CanvasInput or current width. */ width(data) { const self = this; if (typeof data !== 'undefined') { self._width = data; self._calcWH(); self._updateCanvasWH(); return self.render(); } else { return self._width; } }, /** * Get/set the height of the text box. * @param {Number} data Height in pixels. * @return {Mixed} CanvasInput or current height. */ height(data) { const self = this; if (typeof data !== 'undefined') { self._height = data; self._calcWH(); self._updateCanvasWH(); return self.render(); } else { return self._height; } }, /** * Get/set the padding of the text box. * @param {Number} data Padding in pixels. * @return {Mixed} CanvasInput or current padding. */ padding(data) { const self = this; if (typeof data !== 'undefined') { self._padding = data; self._calcWH(); self._updateCanvasWH(); return self.render(); } else { return self._padding; } }, /** * Get/set the border width. * @param {Number} data Border width. * @return {Mixed} CanvasInput or current border width. */ borderWidth(data) { const self = this; if (typeof data !== 'undefined') { self._borderWidth = data; self._calcWH(); self._updateCanvasWH(); return self.render(); } else { return self._borderWidth; } }, /** * Get/set the border color. * @param {String} data Border color. * @return {Mixed} CanvasInput or current border color. */ borderColor(data) { const self = this; if (typeof data !== 'undefined') { self._borderColor = data; return self.render(); } else { return self._borderColor; } }, /** * Get/set the border radius. * @param {Number} data Border radius. * @return {Mixed} CanvasInput or current border radius. */ borderRadius(data) { const self = this; if (typeof data !== 'undefined') { self._borderRadius = data; return self.render(); } else { return self._borderRadius; } }, /** * Get/set the background color. * @param {Number} data Background color. * @return {Mixed} CanvasInput or current background color. */ backgroundColor(data) { const self = this; if (typeof data !== 'undefined') { self._backgroundColor = data; return self.render(); } else { return self._backgroundColor; } }, /** * Get/set the background gradient. * @param {Number} data Background gradient. * @return {Mixed} CanvasInput or current background gradient. */ backgroundGradient(data) { const self = this; if (typeof data !== 'undefined') { self._backgroundColor = self._renderCtx.createLinearGradient(0, 0, 0, self.outerH); self._backgroundColor.addColorStop(0, data[0]); self._backgroundColor.addColorStop(1, data[1]); return self.render(); } else { return self._backgroundColor; } }, /** * Get/set the box shadow. * @param {String} data Box shadow in CSS format (1px 1px 1px rgba(0, 0, 0.5)). * @param {Boolean} doReturn (optional) True to prevent a premature render. * @return {Mixed} CanvasInput or current box shadow. */ boxShadow(data, doReturn) { const self = this; if (typeof data !== 'undefined') { // parse box shadow const boxShadow = data.split('px '); self._boxShadow = { x: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[0], 10), y: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[1], 10), blur: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[2], 10), color: self._boxShadow === 'none' ? '' : boxShadow[3], }; // take into account the shadow and its direction if (self._boxShadow.x < 0) { self.shadowL = Math.abs(self._boxShadow.x) + self._boxShadow.blur; self.shadowR = self._boxShadow.blur + self._boxShadow.x; } else { self.shadowL = Math.abs(self._boxShadow.blur - self._boxShadow.x); self.shadowR = self._boxShadow.blur + self._boxShadow.x; } if (self._boxShadow.y < 0) { self.shadowT = Math.abs(self._boxShadow.y) + self._boxShadow.blur; self.shadowB = self._boxShadow.blur + self._boxShadow.y; } else { self.shadowT = Math.abs(self._boxShadow.blur - self._boxShadow.y); self.shadowB = self._boxShadow.blur + self._boxShadow.y; } self.shadowW = self.shadowL + self.shadowR; self.shadowH = self.shadowT + self.shadowB; self._calcWH(); if (!doReturn) { self._updateCanvasWH(); return self.render(); } } else { return self._boxShadow; } }, /** * Get/set the inner shadow. * @param {String} data In the format of a CSS box shadow (1px 1px 1px rgba(0, 0, 0.5)). * @return {Mixed} CanvasInput or current inner shadow. */ innerShadow(data) { const self = this; if (typeof data !== 'undefined') { self._innerShadow = data; return self.render(); } else { return self._innerShadow; } }, /** * Get/set the text selection color. * @param {String} data Color. * @return {Mixed} CanvasInput or current selection color. */ selectionColor(data) { const self = this; if (typeof data !== 'undefined') { self._selectionColor = data; return self.render(); } else { return self._selectionColor; } }, /** * Get/set the place holder text. * @param {String} data Place holder text. * @return {Mixed} CanvasInput or current place holder text. */ placeHolder(data) { const self = this; if (typeof data !== 'undefined') { self._placeHolder = data; return self.render(); } else { return self._placeHolder; } }, /** * Get/set the current text box value. * @param {String} data Text value. * @return {Mixed} CanvasInput or current text value. */ value(data) { const self = this; if (typeof data !== 'undefined') { self._value = `${data}`; self._hiddenInput.value = `${data}`; // update the cursor position self._cursorPos = self._clipText().length; self.render(); return self; } else { return self._value === self._placeHolder ? '' : self._value; } }, /** * Set or fire the onsubmit event. * @param {Function} fn Custom callback. */ onsubmit(fn) { const self = this; if (typeof fn !== 'undefined') { self._onsubmit = fn; return self; } else { self._onsubmit(); } }, /** * Set or fire the onkeydown event. * @param {Function} fn Custom callback. */ onkeydown(fn) { const self = this; if (typeof fn !== 'undefined') { self._onkeydown = fn; return self; } else { self._onkeydown(); } }, /** * Set or fire the onkeyup event. * @param {Function} fn Custom callback. */ onkeyup(fn) { const self = this; if (typeof fn !== 'undefined') { self._onkeyup = fn; return self; } else { self._onkeyup(); } }, /** * Place focus on the CanvasInput box, placing the cursor * either at the end of the text or where the user clicked. * @param {Number} pos (optional) The position to place the cursor. * @return {CanvasInput} */ focus(pos) { const self = this; let input; // if this is readonly, don't allow it to get focus if (self._readonly) { return; } // only fire the focus event when going from unfocussed if (!self._hasFocus) { self._onfocus(self); // remove focus from all other inputs for (let i = 0; i < inputs.length; i++) { if (inputs[i]._hasFocus) { inputs[i].blur(); } } } // remove selection if (!self._selectionUpdated) { self._selection = [0, 0]; } else { delete self._selectionUpdated; } // update the cursor position self._cursorPos = typeof pos === 'number' ? pos : self._clipText().length; // clear the place holder if (self._placeHolder === self._value) { self._value = ''; self._hiddenInput.value = ''; } self._hasFocus = true; self._cursor = true; // setup cursor interval if (self._cursorInterval) { clearInterval(self._cursorInterval); } requestAnimationFrame(() => { self._cursorInterval = setInterval(() => { self._cursor = !self._cursor; self.render(); }, 500); }); // check if this is Chrome for Android (there is a bug with returning incorrect character key codes) const nav = navigator.userAgent.toLowerCase(); const isChromeMobile = nav.indexOf('chrome') >= 0 && nav.indexOf('mobile') >= 0 && nav.indexOf('android') >= 0; // add support for mobile const isMobile = typeof window.orientation !== 'undefined'; var hasHiddenFocus = false; if ( isMobile && !isChromeMobile && document && document.createElement && (input = document.createElement('input')) ) { input.type = 'text'; input.style.opacity = 0; input.style.position = 'absolute'; input.style.left = `${self._x + self._extraX + (self._canvas ? self._canvas.offsetLeft : 0)}px`; input.style.top = `${self._y + self._extraY + (self._canvas ? self._canvas.offsetTop : 0)}px`; input.style.width = self._width; input.style.height = 0; const form = document.createElement('form'); form.appendChild(input); document.body.appendChild(form); input.focus(); input.addEventListener( 'blur', () => { if (!hasHiddenFocus) { self.blur(self); } }, false ); input.addEventListener( 'focus', () => { self.focus(); }, false ); } else if (isMobile) { self.value(prompt(self._placeHolder) || ''); } // move the real focus to the hidden input const hasSelection = self._selection[0] > 0 || self._selection[1] > 0; hasHiddenFocus = true; self._hiddenInput.focus(); hasHiddenFocus = false; self._hiddenInput.selectionStart = hasSelection ? self._selection[0] : self._cursorPos; self._hiddenInput.selectionEnd = hasSelection ? self._selection[1] : self._cursorPos; return self.render(); }, /** * Removes focus from the CanvasInput box. * @param {Object} _this Reference to this. * @return {CanvasInput} */ blur(_this) { const self = _this || this; self._onblur(self); if (self._cursorInterval) { clearInterval(self._cursorInterval); } self._hasFocus = false; self._cursor = false; self._selection = [0, 0]; self._hiddenInput.blur(); // fill the place holder if (self._value === '') { self._value = self._placeHolder; } if (self._isHidden) { return; } return self.render(); }, /** * Fired with the keydown event to draw the typed characters. * @param {Event} e The keydown event. * @param {CanvasInput} self * @return {CanvasInput} */ keydown(e, self) { const keyCode = e.which; const isShift = e.shiftKey; const key = null; let startText; let endText; // make sure the correct text field is being updated if (!self._hasFocus) { return; } // fire custom user event self._onkeydown(e, self); // add support for Ctrl/Cmd+A selection if (keyCode === 65 && (e.ctrlKey || e.metaKey)) { self._selection = [0, self._value.length]; self._hiddenInput.selectionStart = 0; self._hiddenInput.selectionEnd = self._value.length; e.preventDefault(); return self.render(); } // block keys that shouldn't be processed if (keyCode === 17 || e.metaKey || e.ctrlKey) { return self; } if (keyCode === 13) { // enter key e.preventDefault(); self._onsubmit(e, self); //Entry.dispatchEvent('canvasInputComplete'); } else if (keyCode === 9) { // tab key e.preventDefault(); if (inputs.length > 1) { const next = inputs[self._inputsIndex + 1] ? self._inputsIndex + 1 : 0; self.blur(); setTimeout(() => { inputs[next].focus(); }, 5); } } // update the canvas input state information from the hidden input self._value = self._hiddenInput.value; self._cursorPos = self._hiddenInput.selectionStart; self._selection = [0, 0]; if (!self._isHidden) { return self.render(); } }, /** * Fired with the click event on the canvas, and puts focus on/off * based on where the user clicks. * @param {Event} e The click event. * @param {CanvasInput} self * @return {CanvasInput} */ click(e, self) { //var mouse = self._mousePos(e), //x = mouse.x, //y = mouse.y; if (this._isFirstClick) { delete this._isFirstClick; return; } const roundRect = Entry.stage.canvas.canvas.getBoundingClientRect(); const x = ((e.x - roundRect.left) / roundRect.width - 0.5) * 480; const y = ((e.y - roundRect.top) / roundRect.height - 0.5) * -270; if (self._endSelection) { delete self._endSelection; delete self._selectionUpdated; return; } if ((self._canvas && self._overInput(x, y)) || !self._canvas) { if (self._isHidden) { return; } if (self._mouseDown) { self._mouseDown = false; self.click(e, self); return self.focus(self._clickPos(x, y)); } } else { return self.blur(); } }, /** * Fired with the mousemove event to update the default cursor. * @param {Event} e The mousemove event. * @param {CanvasInput} self * @return {CanvasInput} */ mousemove(e, self) { const mouse = self._mousePos(e); const x = mouse.x; const y = mouse.y; const isOver = self._overInput(x, y); if (isOver && self._canvas) { self._canvas.style.cursor = 'text'; self._wasOver = true; } else if (self._wasOver && self._canvas) { self._canvas.style.cursor = 'default'; self._wasOver = false; } if (self._hasFocus && self._selectionStart >= 0) { const curPos = self._clickPos(x, y); const start = Math.min(self._selectionStart, curPos); const end = Math.max(self._selectionStart, curPos); if (!isOver) { self._selectionUpdated = true; self._endSelection = true; delete self._selectionStart; self.render(); return; } if (self._selection[0] !== start || self._selection[1] !== end) { self._selection = [start, end]; self.render(); } } }, /** * Fired with the mousedown event to start a selection drag. * @param {Event} e The mousedown event. * @param {CanvasInput} self */ mousedown(e, self) { e = Entry.Utils.convertMouseEvent(e); const roundRect = Entry.stage.getBoundRect(); const offsetX = e.offsetX || e.clientX - roundRect.left; const offsetY = e.offsetY || e.clientY - roundRect.top; const x = (offsetX / roundRect.width - 0.5) * 480; const y = (offsetY / roundRect.height - 0.5) * -270; const isOver = self._overInput(x, y); // setup the 'click' event self._mouseDown = isOver; const inputField = Entry.stage.inputField; if (isOver && !inputField._isHidden) { self._hasFocus = true; setTimeout(() => { inputField.focus(); }, 1); } else if (!isOver && inputField) { self._hasFocus = false; inputField.blur(); } // start the selection drag if inside the input if (self._hasFocus && isOver) { self._selectionStart = self._clickPos(x, y); } }, /** * Fired with the mouseup event to end a selection drag. * @param {Event} e The mouseup event. * @param {CanvasInput} self */ mouseup(e, self) { //var mouse = self._mousePos(e), //x = mouse.x, //y = mouse.y; //// update selection if a drag has happened //var isSelection = self._clickPos(x, y) !== self._selectionStart; //if (self._hasFocus && self._selectionStart >= 0 && self._overInput(x, y) && isSelection) { //self._selectionUpdated = true; //delete self._selectionStart; //self.render(); //} else { //delete self._selectionStart; //} //self.click(e, self); // if (self._isHidden) // return; // self.render(); // self.click(e,self); // var roundRect = Entry.stage.canvas.canvas.getBoundingClientRect(); // var x = ((e.clientX - roundRect.left) / roundRect.width - 0.5) * 480; // var y = ((e.clientY - roundRect.top) / roundRect.height - 0.5) * -270; }, /** * Helper method to get the off-DOM canvas. * @return {Object} Reference to the canvas. */ renderCanvas() { return this._renderCanvas; }, show() { const self = this; self._isHidden = false; self._isFirstClick = true; self.value(''); self.focus(); }, hide() { const self = this; self._isHidden = true; self.blur(); }, setPosition(x, y) { const self = this; self._isHidden = false; self._isFirstClick = true; self._x = x || 0; self._y = y || 0; self.value(''); self.focus(); }, /** * Clears and redraws the CanvasInput on an off-DOM canvas, * and if a main canvas is provided, draws it all onto that. * @return {CanvasInput} */ render() { const self = this; const ctx = self._renderCtx; const w = self.outerW; const h = self.outerH; const br = self._borderRadius; const bw = self._borderWidth; const sw = self.shadowW; const sh = self.shadowH; // clear the canvas ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // setup the box shadow ctx.shadowOffsetX = self._boxShadow.x; ctx.shadowOffsetY = self._boxShadow.y; ctx.shadowBlur = self._boxShadow.blur; ctx.shadowColor = self._boxShadow.color; // draw the border if (self._borderWidth > 0) { ctx.fillStyle = self._borderColor; // self._roundedRect(ctx, self.shadowL, self.shadowT, w - sw, h - sh, br); self._roundedRect(ctx, self.shadowL, self.shadowT, w - sw, h - sh, br); ctx.fill(); ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; ctx.shadowBlur = 0; } // draw the text box background self._drawTextBox(() => { // make sure all shadows are reset ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; ctx.shadowBlur = 0; // clip the text so that it fits within the box let text = self._clipText(); // draw the selection const paddingBorder = self._padding + self._borderWidth + self.shadowT; if (self._selection[1] > 0) { const selectOffset = self._textWidth(text.substring(0, self._selection[0])); const selectWidth = self._textWidth( text.substring(self._selection[0], self._selection[1]) ); ctx.fillStyle = self._selectionColor; ctx.fillRect( paddingBorder + selectOffset, paddingBorder, selectWidth, self._height ); } // draw the cursor if (self._cursor) { const cursorOffset = self._textWidth(text.substring(0, self._cursorPos)); ctx.fillStyle = self._fontColor; ctx.fillRect(paddingBorder + cursorOffset, paddingBorder, 1, self._height); } // draw the text const textX = self._padding + self._borderWidth + self.shadowL; const textY = Math.round(paddingBorder + self._height / 2); // only remove the placeholder text if they have typed something text = text === '' && self._placeHolder ? self._placeHolder : text; ctx.fillStyle = self._value !== '' && self._value !== self._placeHolder ? self._fontColor : self._placeHolderColor; ctx.font = `${self._fontStyle} ${self._fontWeight} ${self._fontSize}px ${self._fontFamily}`; ctx.textAlign = 'left'; ctx.textBaseline = 'middle'; ctx.fillText(text, textX, textY); // parse inner shadow const innerShadow = self._innerShadow.split('px '); const isOffsetX = self._innerShadow === 'none' ? 0 : parseInt(innerShadow[0], 10); const isOffsetY = self._innerShadow === 'none' ? 0 : parseInt(innerShadow[1], 10); const isBlur = self._innerShadow === 'none' ? 0 : parseInt(innerShadow[2], 10); const isColor = self._innerShadow === 'none' ? '' : innerShadow[3]; // draw the inner-shadow (damn you canvas, this should be easier than this...) if (isBlur > 0) { const shadowCtx = self._shadowCtx; const scw = shadowCtx.canvas.width; const sch = shadowCtx.canvas.height; shadowCtx.clearRect(0, 0, scw, sch); shadowCtx.shadowBlur = isBlur; shadowCtx.shadowColor = isColor; // top shadow shadowCtx.shadowOffsetX = 0; shadowCtx.shadowOffsetY = isOffsetY; shadowCtx.fillRect(-1 * w, -100, 3 * w, 100); // right shadow shadowCtx.shadowOffsetX = isOffsetX; shadowCtx.shadowOffsetY = 0; shadowCtx.fillRect(scw, -1 * h, 100, 3 * h); // bottom shadow shadowCtx.shadowOffsetX = 0; shadowCtx.shadowOffsetY = isOffsetY; shadowCtx.fillRect(-1 * w, sch, 3 * w, 100); // left shadow shadowCtx.shadowOffsetX = isOffsetX; shadowCtx.shadowOffsetY = 0; shadowCtx.fillRect(-100, -1 * h, 100, 3 * h); // create a clipping mask on the main canvas self._roundedRect( ctx, bw + self.shadowL, bw + self.shadowT, w - bw * 2 - sw, h - bw * 2 - sh, br ); ctx.clip(); // draw the inner-shadow from the off-DOM canvas ctx.drawImage( self._shadowCanvas, 0, 0, scw, sch, bw + self.shadowL, bw + self.shadowT, scw, sch ); } // draw to the visible canvas // if (self._ctx) { // // self._ctx.clearRect(self._x, self._y, ctx.canvas.width, ctx.canvas.height); // self._ctx.drawImage(self._renderCanvas, self._x, self._y); // } self._pixiView.texture.update(); Entry.requestUpdate = true; return self; }); }, /** * Draw the text box area with either an image or background color. * @param {Function} fn Callback. */ _drawTextBox(fn) { const self = this; const ctx = self._renderCtx; const w = self.outerW; const h = self.outerH; const br = self._borderRadius; const bw = self._borderWidth; const sw = self.shadowW; const sh = self.shadowH; // only draw the background shape if no image is being used if (self._backgroundImage === '') { ctx.fillStyle = self._backgroundColor; self._roundedRect( ctx, bw + self.shadowL, bw + self.shadowT, w - bw * 2 - sw, h - bw * 2 - sh, br ); ctx.fill(); fn(); } else { const img = new Image(); img.src = self._backgroundImage; img.onload = function() { ctx.drawImage( img, 0, 0, img.width, img.height, bw + self.shadowL, bw + self.shadowT, w, h ); fn(); }; } }, /** * Deletes selected text in selection range and repositions cursor. * @return {Boolean} true if text removed. */ _clearSelection() { const self = this; if (self._selection[1] > 0) { // clear the selected contents const start = self._selection[0]; const end = self._selection[1]; self._value = self._value.substr(0, start) + self._value.substr(end); self._cursorPos = start; self._cursorPos = self._cursorPos < 0 ? 0 : self._cursorPos; self._selection = [0, 0]; return true; } return false; }, /** * Clip the text string to only return what fits in the visible text box. * @param {String} value The text to clip. * @return {String} The clipped text. */ _clipText(value) { const self = this; value = typeof value === 'undefined' ? self._value : value; const textWidth = self._textWidth(value); const fillPer = textWidth / (self._width - self._padding); const text = fillPer > 1 ? value.substr(-1 * Math.floor(value.length / fillPer)) : value; return `${text}`; }, /** * Gets the pixel with of passed text. * @param {String} text The text to measure. * @return {Number} The measured width. */ _textWidth(text) { const self = this; const ctx = self._renderCtx; ctx.font = `${self._fontStyle} ${self._fontWeight} ${self._fontSize}px ${self._fontFamily}`; ctx.textAlign = 'left'; return ctx.measureText(text).width; }, /** * Recalculate the outer with and height of the text box. */ _calcWH() { const self = this; // calculate the full width and height with padding, borders and shadows self.outerW = self._width + self._padding * 2 + self._borderWidth * 2 + self.shadowW; self.outerH = self._height + self._padding * 2 + self._borderWidth * 2 + self.shadowH; }, /** * Update the width and height of the off-DOM canvas when attributes are changed. */ _updateCanvasWH() { const self = this; const oldW = self._renderCanvas.width; const oldH = self._renderCanvas.height; // update off-DOM canvas self._renderCanvas.setAttribute('width', self.outerW); self._renderCanvas.setAttribute('height', self.outerH); self._shadowCanvas.setAttribute('width', self._width + self._padding * 2); self._shadowCanvas.setAttribute('height', self._height + self._padding * 2); // clear the main canvas //do nothing. entryjs will control main canvas. // if (self._ctx) { // self._ctx.clearRect(self._x, self._y, oldW, oldH); // } }, /** * Creates the path for a rectangle with rounded corners. * Must call ctx.fill() after calling this to draw the rectangle. * @param {Object} ctx Canvas context. * @param {Number} x x-coordinate to draw from. * @param {Number} y y-coordinate to draw from. * @param {Number} w Width of rectangle. * @param {Number} h Height of rectangle. * @param {Number} r Border radius. */ _roundedRect(ctx, x, y, w, h, r) { if (w < 2 * r) { r = w / 2; } if (h < 2 * r) { r = h / 2; } ctx.beginPath(); ctx.moveTo(x + r, y); ctx.lineTo(x + w - r, y); ctx.quadraticCurveTo(x + w, y, x + w, y + r); ctx.lineTo(x + w, y + h - r); ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h); ctx.lineTo(x + r, y + h); ctx.quadraticCurveTo(x, y + h, x, y + h - r); ctx.lineTo(x, y + r); ctx.quadraticCurveTo(x, y, x + r, y); ctx.closePath(); }, /** * Checks if a coordinate point is over the input box. * @param {Number} x x-coordinate position. * @param {Number} y y-coordinate position. * @return {Boolean} True if it is over the input box. */ _overInput(x, y) { return x >= -226 && x <= 183 && y >= -110 && y <= -73; }, /** * Use the mouse's x & y coordinates to determine * the position clicked in the text. * @param {Number} x X-coordinate. * @param {Number} y Y-coordinate. * @return {Number} Cursor position. */ _clickPos(x, y) { const self = this; let value = self._value; // don't count placeholder text in this if (self._value === self._placeHolder) { value = ''; } // determine where the click was made along the string const text = self._clipText(value); let totalW = 0; let pos = text.length; if (x - (self._x + self._extraX) < self._textWidth(text)) { // loop through each character to identify the position for (let i = 0; i < text.length; i++) { totalW += self._textWidth(text[i]); if (totalW >= x - (self._x + self._extraX)) { pos = i; break; } } } return pos; }, /** * Calculate the mouse position based on the event callback and the elements on the page. * @param {Event} e * @return {Object} x & y values */ _mousePos(e) { let elm = e.target; const style = document.defaultView.getComputedStyle(elm, undefined); const paddingLeft = parseInt(style.paddingLeft, 10) || 0; const paddingTop = parseInt(style.paddingLeft, 10) || 0; const borderLeft = parseInt(style.borderLeftWidth, 10) || 0; const borderTop = parseInt(style.borderLeftWidth, 10) || 0; const htmlTop = document.body.parentNode.offsetTop || 0; const htmlLeft = document.body.parentNode.offsetLeft || 0; let offsetX = 0; let offsetY = 0; let x; let y; // calculate the total offset if (typeof elm.offsetParent !== 'undefined') { do { offsetX += elm.offsetLeft; offsetY += elm.offsetTop; } while ((elm = elm.offsetParent)); } // take into account borders and padding offsetX += paddingLeft + borderLeft + htmlLeft; offsetY += paddingTop + borderTop + htmlTop; return { x: e.pageX - offsetX, y: e.pageY - offsetY, }; }, hasFocus() { return this._hasFocus; }, }; })(); ================================================ FILE: src/class/pixi/etc/PIXIPaintAdaptor.ts ================================================ import { DisplayObject } from 'pixi.js'; import { PIXIGraphics } from '../helper/PIXIHelper'; interface IRBG { r: number; g: number; b: number; } /** * createjs.Graphics 스타일의 lagacy 메서드 호출을 pixi.Graphics 로 변경해주는 adaptor 클라스. */ export class PIXIPaintAdaptor { //아래 값들은 다른 클래스에서 값을 할당해줌. public rgb: IRBG; public thickness: number; public opacity: number; /** [박봉배] 추측 - drawing 중인지 아닌지를 저장하는 값으로 생각 됨. */ public stop: boolean; /** [박봉배] 추측 - 이 브러시가 따라다녀야 할 대상 */ public entity: DisplayObject; //아래 값들은 내부에서만 사용함. private _alpha: number = 1; private _thickness: number; private _color: number; private _shape: PIXIGraphics; private currentPath: PIXI.Polygon; endFill() { // #10141 때문에 closePath 사용안함. if (!this._shape || this._shape.destroyed) { return; } this.currentPath = null; this._shape.closePath(); } beginFill(color: string) { this._parseRGBCssStyleColor(color); this._shape.beginFill(this._color, this._alpha); } beginFillFast(color: number, alpha: number) { this._color = color; this._alpha = alpha; this._shape.beginFill(color, alpha); } moveTo(x: number, y: number) { if (!this._shape || this._shape.destroyed) { return; } this._shape.moveTo(Number(x), Number(y)); this.currentPath = this._shape.currentPath; } lineTo(x: number, y: number) { if (!this._shape || this._shape.destroyed) { return; } if (!this.currentPath) { this._shape.moveTo(0, 0); this.currentPath = this._shape.currentPath; } const points = this.currentPath.points; const fromX = points[points.length - 2]; const fromY = points[points.length - 1]; if (fromX !== x || fromY !== y) { points.push(Number(x), Number(y)); } this._shape.currentPath = this.currentPath; this._shape.lineTo(Number(x), Number(y)); // 박봉배: #9374 x,y 좌표가 문자로 넘어와서 생긴 이슈 this._shape.geometry.invalidate(); } /** @param shape - drawing 을 할 대상을 지정 */ internalSetShape(shape: PIXIGraphics) { this._shape = shape; this._setStyle(); } _setStyle() { if (!this._shape || this._shape.destroyed) { return; } this._shape.lineStyle(this._thickness, this._color, this._alpha); } _parseRGBCssStyleColor(colorOld: string) { const color = colorOld.replace('/s/', ''); if (color[0] == '#') { this._color = parseInt(color.replace('#', ''), 16); return; } let result; //rgb 보다 rgba 문자열을 더 많이 사용하는것 같아 이 조건문을 위로 올림 if ((result = /^rgba\((\d+),(\d+),(\d+),(\d+(\.?\d*))\)$/i.exec(color))) { this._color = this._RGBToNumber(result); this._alpha = Number(result[4]); return; } if ((result = /^rgb\((\d+),(\d+),(\d+)\)$/i.exec(color))) { this._color = this._RGBToNumber(result); } } _RGBToNumber(regexResult: any[]) { const [x, r, g, b] = regexResult; return (r << 16) + (g << 8) + Number(b); } // Matched the method name to createjs for fulfilling the purpose of wrapper class (#11626) clear() { const { x = 0, y = 0 } = this.entity || {}; this._shape.clear(); // Disconnect the previously continued path this._shape.moveTo(x, -y); } } ================================================ FILE: src/class/pixi/etc/PIXITempStore.ts ================================================ /** * 임시로 사용할 변수의 포인터 저장용. */ import { Point, Rectangle, Matrix } from 'pixi.js'; export class PIXITempStore { static point1: Point; static point2: Point; static rect1: Rectangle; static rect2: Rectangle; static matrix1: Matrix; static matrix2: Matrix; static init() { this.point1 = new Point(); this.point2 = new Point(); this.rect1 = new Rectangle(); this.rect2 = new Rectangle(); this.matrix1 = new Matrix(); this.matrix2 = new Matrix(); } } ================================================ FILE: src/class/pixi/handle/PIXIHandle.js ================================================ /** * Resize handle on PIXI.js */ 'use strict'; import { Container, Graphics } from 'pixi.js'; import { PIXIHandleEdge } from './PIXIHandleEdge'; import { PIXIDragHelper } from '../helper/PIXIDragHelper'; import { PIXIGlobal } from '../init/PIXIGlobal'; export class PIXIHandle { constructor(canvas) { this.canvas = canvas; this._baseAsset = PIXIGlobal.baseAsset; this.color = '#c1c7cd'; //this.color = "#6BD5FF"; this.arrowColor = '#E79040'; this.centerColor = '#93440F'; this.rotateKnobColor = '#6B6B6B'; this.x = 0; this.y = 0; this.rotation = 0; this.direction = 0; this.width = 100; this.height = 100; this.flipX = false; this.flipY = false; this.visible = false; this.draggable = true; this.centerEditable = true; this.rotationEditable = true; this.directionEditable = true; this.resizeEnable = true; this.onChangeFunction = null; this.callerObject = null; this.createHandle(); this.render(); this.selectedObject = null; } setChangeListener(object, func) { this.onChangeFunction = func; this.callerObject = object; return this; } /** * for undo and redo */ setEditStartListener(object, func) { this.onEditStartFunction = func; this.editStartCallerObject = object; return this; } setEditEndListener(object, func) { this.onEditEndFunction = func; this.editEndCallerObject = object; return this; } toggleCenter(isEnable) { this.centerEditable = isEnable; this.centerPoint.visible = isEnable; } toggleRotation(isEnable) { this.rotationEditable = isEnable; this.rotateKnob.visible = isEnable; } toggleDirection(isEnable) { this.directionEditable = isEnable; this.directionArrow.visible = isEnable; } toggleResize(isEnable) { this.resizeEditable = isEnable; for (let i = 0; i < 8; i++) { this.knobs[i].visible = isEnable; } } toggleFont(isEnable) { this.fontEditable = isEnable; this.fontKnob.visible = isEnable; } setX(xPos) { this.x = xPos; this.container.x = xPos; this.background.x = xPos; } setY(yPos) { this.y = yPos; this.container.y = yPos; this.background.y = yPos; } setWidth(width) { this.width = width; this.background.width = width; } setHeight(height) { this.height = height; this.background.height = height; } setRegX(regX) { this.regX = regX; this.centerPoint.x = regX; } setRegY(regY) { this.regY = regY; this.centerPoint.y = regY; } setRotation(rotation) { rotation = (rotation + 360) % 360; this.rotation = rotation; const rad = (rotation * Math.PI) / 180; this.container.rotation = rad; this.background.rotation = rad; this.updateKnobCursor(); } setDirection(direction) { direction = (direction + 360) % 360; this.direction = direction; this.directionArrow.rotation = (direction * Math.PI) / 180; } setVisible(visible) { this.visible = visible; this.container.visible = visible; this.background.visible = visible; } setFont(fontSize) { this.font = fontSize; this.fontKnob.y = fontSize - this.height / 2; } createHandle() { const handle = this; const BASE_ASSET = this._baseAsset; const container = new Container(); //border const border = new Graphics(); container.addChild(border); this.border = border; //edge const edge = new PIXIHandleEdge(BASE_ASSET); edge.interactive = true; edge.cursor = 'move'; edge.on(PIXIDragHelper.DOWN, function(e) { PIXIDragHelper.handleDrag(edge); const offset = handle.getEventCoordinate(e); offset.x -= handle.x; offset.y -= handle.y; this.offset = offset; handle.dispatchEditStartEvent(); }); edge.on(PIXIDragHelper.MOVE, function(e) { if (handle.getDraggable()) { const pos = handle.getEventCoordinate(e); pos.x -= this.offset.x; pos.y -= this.offset.y; handle.setX(pos.x); handle.setY(pos.y); handle.dispatchOnChangeEvent(); } }); edge.on(PIXIDragHelper.UP, (e) => { handle.dispatchEditEndEvent(); }); container.addChild(edge); this.edge = edge; //rotate knob const rotateKnob = BASE_ASSET.newSprite('handle/rotateKnob'); rotateKnob.anchor.set(0.5, 1); rotateKnob.interactive = true; rotateKnob.cursor = 'crosshair'; rotateKnob.on(PIXIDragHelper.DOWN, (e) => { PIXIDragHelper.handleDrag(rotateKnob); handle.dispatchEditStartEvent(); }); rotateKnob.on(PIXIDragHelper.MOVE, (e) => { const pos = handle.getEventCoordinate(e); pos.x -= handle.x; pos.y -= handle.y; const rotation = (-Math.atan2(pos.x, pos.y) / Math.PI) * 180 - 180; handle.setRotation(rotation); handle.dispatchOnChangeEvent(); }); rotateKnob.on(PIXIDragHelper.UP, (e) => { handle.dispatchEditEndEvent(); }); container.addChild(rotateKnob); container.setChildIndex(rotateKnob, 1); this.rotateKnob = rotateKnob; const directionArrow = BASE_ASSET.newSprite('handle/arrow'); directionArrow.interactive = true; directionArrow.pivot.set(9, 42); directionArrow.on(PIXIDragHelper.DOWN, (e) => { PIXIDragHelper.handleDrag(directionArrow); handle.dispatchEditStartEvent(); }); directionArrow.on(PIXIDragHelper.MOVE, (e) => { const pos = handle.getLocalCoordinate(handle.getEventCoordinate(e)); const rotation = (-Math.atan2(pos.x, pos.y) / Math.PI) * 180 - 180; handle.setDirection(rotation); handle.dispatchOnChangeEvent(); }); directionArrow.on(PIXIDragHelper.UP, (e) => { handle.dispatchEditEndEvent(); }); container.addChild(directionArrow); container.setChildIndex(directionArrow, 0); this.directionArrow = directionArrow; const centerPoint = BASE_ASSET.newSprite('handle/centerPoint'); centerPoint.interactive = true; centerPoint.anchor.set(0.5, 0.5); centerPoint.on(PIXIDragHelper.DOWN, (e) => { PIXIDragHelper.handleDrag(centerPoint); handle.dispatchEditStartEvent(); }); centerPoint.on(PIXIDragHelper.MOVE, (e) => { let pos = handle.getEventCoordinate(e); pos = handle.getLocalCoordinate(pos); handle.setRegX(pos.x); handle.setRegY(pos.y); handle.dispatchOnChangeEvent(); }); centerPoint.on(PIXIDragHelper.UP, (e) => { handle.dispatchEditEndEvent(); }); container.addChild(centerPoint); this.centerPoint = centerPoint; //resize knobs this.knobs = []; for (let i = 0; i < 8; i++) { const knob = BASE_ASSET.newSprite('handle/knob'); knob.pivot.set(4, 4); knob.interactive = true; knob.knobIndex = i; knob.on(PIXIDragHelper.DOWN, function(e) { const targetKnob = e.currentTarget; PIXIDragHelper.handleDrag(targetKnob); const otherKnobIndex = this.knobIndex + 4 > 7 ? this.knobIndex + 4 - 8 : this.knobIndex + 4; const otherKnob = handle.knobs[otherKnobIndex]; const otherKnobPos = handle.getGlobalCoordinate(otherKnob); this.otherKnobPos = otherKnobPos; handle.dispatchEditStartEvent(); }); knob.on(PIXIDragHelper.MOVE, function(e) { const pos = handle.getEventCoordinate(e); if (handle.checkCenterPointState(handle.regX, handle.regY)) { handle.setRegX(0); handle.setRegY(0); handle.dispatchOnChangeEvent(); } handle.adjust(this.knobIndex, this.otherKnobPos, pos); }); knob.on(PIXIDragHelper.UP, (e) => { handle.dispatchEditEndEvent(); }); container.addChild(knob); this.knobs.push(knob); } const background = BASE_ASSET.newSprite('handle/bg'); background.interactive = true; background.anchor.set(0.5, 0.5); background.on(PIXIDragHelper.DOWN, function(e) { PIXIDragHelper.handleDrag(background); const offset = handle.getEventCoordinate(e); offset.x -= handle.x; offset.y -= handle.y; this.offset = offset; handle.dispatchEditStartEvent(); }); background.on(PIXIDragHelper.MOVE, function(e) { if (handle.getDraggable()) { const pos = handle.getEventCoordinate(e); pos.x -= this.offset.x; pos.y -= this.offset.y; handle.setX(pos.x); handle.setY(pos.y); handle.dispatchOnChangeEvent(); } }); background.on(PIXIDragHelper.UP, (e) => { handle.dispatchEditEndEvent(); }); this.canvas.addChildAt(background, 0); this.background = background; this.container = container; this.canvas.addChild(this.container); } checkCenterPointState(x, y) { const standard = 718; const res = Math.sqrt(x * x + y * y); if (res > standard && Entry.engine.isState('stop')) { Entry.toast.warning( Lang.Workspace.toast_error_title_object_center, Lang.Workspace.toast_error_contents_object_center ); return true; } return false; } render() { this.renderBorder(); this.renderEdge(); this.renderRotateKnob(); this.renderKnobs(); } renderEdge() { this.edge.renderEdge(this.width, this.height); } renderRotateKnob() { this.rotateKnob.y = -this.height / 2; } /** * @deprecated 2018.09.19 박준배. * graphics 에서 texture 로 변경하면서 border와 edge 를 합쳐버림. * 그래서 보더가 필요 없음. * 함수가 public naming 이라서 삭제를 못하겠음. */ renderBorder() {} renderKnobs() { const width = this.width / 2; const height = this.height / 2; this.knobs.forEach((knob, i) => { knob.x = Math.round(Math.sin((i / 4) * Math.PI)) * width; knob.y = Math.round(Math.cos((i / 4) * Math.PI)) * height; }); } getEventCoordinate(e) { const g = e.data.global; return { x: g.x * 0.75 - 240, y: g.y * 0.75 - 135, }; } getGlobalCoordinate(childObject) { const rotation = -this.container.rotation; const cos = Math.cos(rotation); const sin = Math.sin(rotation); return { x: this.x + childObject.x * cos + childObject.y * sin, y: this.y + childObject.y * cos - childObject.x * sin, }; } getLocalCoordinate(pos) { const rotation = this.container.rotation; const cos = Math.cos(rotation); const sin = Math.sin(rotation); pos.x -= this.x; pos.y -= this.y; return { x: pos.x * cos + pos.y * sin, y: pos.y * cos - pos.x * sin, }; } adjust(knobIndex, otherKnobPos, pos) { const newPoint = this.calcPos({ x: this.x, y: this.y }, otherKnobPos, pos); const newCenter = { x: (otherKnobPos.x + newPoint.x) / 2, y: (otherKnobPos.y + newPoint.y) / 2, }; const newLength = Math.sqrt( Math.pow(newPoint.x - otherKnobPos.x, 2) + Math.pow(newPoint.y - otherKnobPos.y, 2) ); if (knobIndex % 4 == 0) { var ratio = newLength / this.height; this.height = newLength; this.setRegY(this.regY * ratio); } else if (knobIndex % 4 == 2) { var ratio = newLength / this.width; this.width = newLength; this.setRegX(this.regX * ratio); } else { const oldLength = 2 * Math.sqrt( Math.pow(this.x - otherKnobPos.x, 2) + Math.pow(this.y - otherKnobPos.y, 2) ); const newWidth = (this.width * newLength) / oldLength; var ratio = newWidth / this.width; this.setWidth(newWidth); this.setRegX(this.regX * ratio); const newHeight = (this.height * newLength) / oldLength; ratio = newHeight / this.height; this.setHeight((this.height * newLength) / oldLength); this.setRegY(this.regY * ratio); } this.setX(newCenter.x); this.setY(newCenter.y); this.render(); this.dispatchOnChangeEvent(); } updateKnobCursor() { const rotation = this.rotation; const cursorList = ['ns-resize', 'nwse-resize', 'ew-resize', 'nesw-resize']; const iter = Math.round(rotation / 45); for (var i = 0; i < iter; i++) { cursorList.unshift(cursorList.pop()); } for (var i = 0; i < 8; i++) { this.knobs[i].cursor = cursorList[i % 4]; } } calcPos(pos1, pos2, targetPos) { if (pos1.x == pos2.x) { return { x: pos1.x, y: targetPos.y, }; } else if (pos1.y == pos2.y) { return { x: targetPos.x, y: pos1.y, }; } else { const a = pos1.y - pos2.y; const b = pos2.x - pos1.x; const c = pos1.x * pos2.y - pos2.x * pos1.y; const k = -(a * targetPos.x + b * targetPos.y + c) / (a * a + b * b); return { x: targetPos.x + a * k, y: targetPos.y + b * k, }; } } dispatchOnChangeEvent() { if (this.onChangeFunction) { this.onChangeFunction.call(this.callerObject, this); } } dispatchEditStartEvent() { if (this.onEditStartFunction) { this.onEditStartFunction.call(this.editStartCallerObject, this); } } dispatchEditEndEvent() { if (this.onEditEndFunction) { this.onEditEndFunction.call(this.editEndCallerObject, this); } } setDraggable(bool) { this.draggable = bool; } getDraggable() { return this.draggable; } destroy() { this.onChangeFunction = null; this.callerObject = null; this.onEditStartFunction = null; this.editStartCallerObject = null; this.onEditEndFunction = null; this.editEndCallerObject = null; } } ================================================ FILE: src/class/pixi/handle/PIXIHandleEdge.js ================================================ import { Container } from 'pixi.js'; export class PIXIHandleEdge extends Container { constructor(baseAsset) { super(); const spriteFactory = () => { const sp = baseAsset.newSprite('handle/border'); sp.pivot.set(0, 4); this.addChild(sp); return sp; }; this._left = spriteFactory(); this._right = spriteFactory(); this._top = spriteFactory(); this._bottom = spriteFactory(); } renderEdge(w, h) { const hw = w / 2; const hh = h / 2; this._top.width = w; this._top.position.set(-hw, -hh); this._bottom.width = w; this._bottom.position.set(-hw, hh); this._left.width = h; this._left.rotation = Math.PI / 2; this._left.position.set(-hw, -hh); this._right.width = h; this._right.rotation = Math.PI / 2; this._right.position.set(hw, -hh); } } ================================================ FILE: src/class/pixi/helper/PIXIDragHelper.js ================================================ /** * pixi 에는 createjs 의 pressmove 가 없어서 그것을 대신해주는 헬퍼 클라스. */ export class PIXIDragHelper { /** * @param {PIXI.DisplayObject} target */ static handleDrag(target) { const C = PIXIDragHelper; const CE = this._convertEvent; function _onMove(e) { target.emit(C.MOVE, CE(e)); } function _onUp(e) { target.emit(C.UP, CE(e)); target.off('pointermove', _onMove); } function _onDown(e) { target.emit(C.DOWN, CE(e)); target.on('pointermove', _onMove); } target.on('pointerdown', _onDown); target.on('pointerup', _onUp); target.on('pointerupoutside', _onUp); target.on('pointercancel', _onUp); } static _convertEvent(e) { const g = e.data.global; return { target: e.target, currentTarget: e.currentTarget, stageX: g.x, stageY: g.y, rawX: g.x, rawY: g.y, }; } } PIXIDragHelper.DOWN = '__pointerdown'; PIXIDragHelper.MOVE = '__pointermove'; PIXIDragHelper.UP = '__pointerup'; PIXIDragHelper.OVER = 'pointerover'; ================================================ FILE: src/class/pixi/helper/PIXIHelper.ts ================================================ import { Sprite, Container, Texture, Graphics } from 'pixi.js'; import { PIXISprite } from '../plugins/PIXISprite'; import { PIXITempStore } from '../etc/PIXITempStore'; import { PIXIText } from '../text/PIXIText'; export class PIXIGraphics extends Graphics { destroyed: boolean = false; destroy(options?: any) { this.destroyed = true; super.destroy(options); } } export default class PIXIHelper { static sprite(debugName?: string, texture?: Texture): Sprite { return new PIXISprite(texture); } static container(debugName?: string): Container { return new Container(); } static text(str: string, font: string, color: string, textBaseline: string, textAlign: string) { // console.log(str, font); const reg = /((\d+)(pt|sp|px))?\s*(.+)/gi; const result: any[] = reg.exec(font) || []; const fontName = result[4] || "NanumGothic, 'Nanum Gothic'"; const size = result[1] || '10pt'; const nColor = parseInt(color.replace('#', '0x')) || 0; // var t = new PIXI.Text(str, { const t = new PIXIText(str, { fontFamily: fontName, fontSize: size, fill: nColor, // textBaseline: textBaseline || 'alphabetic', textBaseline: 'middle', align: textAlign || 'left', miterLimit: 2.5, //createjs default value, padding: 5, //바운드를 삐져나오는 경우를 대비한 패딩 }); return t; } static getOffScreenCanvas(forceHTMLCanvas: boolean = false): HTMLCanvasElement { forceHTMLCanvas = true; const WIN: any = window; if (!forceHTMLCanvas && 'OffscreenCanvas' in WIN) { return new WIN.OffscreenCanvas(1, 1); } else { return document.createElement('canvas'); } } /** * #ff00ff --> 0xff00ff * @param strColor */ static colorToUint(strColor: any) { return strColor ? Number(strColor.replace('#', '0x')) : undefined; } static todo(msg: string) {} static newPIXIGraphics() { return new PIXIGraphics(false); } static randomRGBAString(alpha: number = 0.3): string { const rr = this._rand255; return `rgba(${rr()},${rr()},${rr()},${alpha})`; } private static _rand255(): number { return Math.floor(Math.random() * 255); } /** * createjs.DisplayObject#getTransformBound() * @param {PIXI.DisplayObject} target */ static getTransformBound(target: any) { const bounds = target.getLocalBounds(PIXITempStore.rect1); let x = bounds.x; let y = bounds.y; const width = bounds.width; const height = bounds.height; const mtx = PIXITempStore.matrix1; target.localTransform.copyTo(mtx); if (x || y) { const mat2 = PIXITempStore.matrix2.identity().translate(-x, -y); mtx.append(mat2); } const x_a = width * mtx.a; const x_b = width * mtx.b; const y_c = height * mtx.c; const y_d = height * mtx.d; const tx = mtx.tx; const ty = mtx.ty; let minX = tx; let maxX = tx; let minY = ty; let maxY = ty; if ((x = x_a + tx) < minX) { minX = x; } else if (x > maxX) { maxX = x; } if ((x = x_a + y_c + tx) < minX) { minX = x; } else if (x > maxX) { maxX = x; } if ((x = y_c + tx) < minX) { minX = x; } else if (x > maxX) { maxX = x; } if ((y = x_b + ty) < minY) { minY = y; } else if (y > maxY) { maxY = y; } if ((y = x_b + y_d + ty) < minY) { minY = y; } else if (y > maxY) { maxY = y; } if ((y = y_d + ty) < minY) { minY = y; } else if (y > maxY) { maxY = y; } bounds.x = minX; bounds.y = minY; bounds.width = maxX - minX; bounds.height = maxY - minY; return bounds; } } ================================================ FILE: src/class/pixi/init/PIXIBaseAsset.ts ================================================ /** * 기본 텍스쳐 로드 되기 전에 객체를 생성 할 수 있도록 json은 함께 번들링함. */ import { Sprite, BaseTexture, Spritesheet, Texture } from 'pixi.js'; class PIXIBaseAssetSprite extends Sprite { constructor(t?: any) { super(t); } } // var atlasJson = require("./../../../entry_texture/base_asset.json"); let atlasJson: any; export class PIXIBaseAsset { private _sheet: Spritesheet; constructor() { const path = `${Entry.mediaFilePath}base_asset.png`; const base = BaseTexture.from(path); base.once('loaded', () => { Entry.requestUpdate = true; }); this._sheet = new Spritesheet(base, atlasJson); //서브텍스쳐의 개수는 반드시 1000개보다 작아야 한다. 그렇지 않으면 parse 가 async 로 작동함. //1000 이라는 숫자는 PIXI.Spritesheet.BATCH_SIZE getter 에 정의됨. this._sheet.parse(() => {}); } newSprite(key: string): Sprite { // return new PIXI.Sprite(this._sheet.textures[key]); return new PIXIBaseAssetSprite(this._sheet.textures[key]); } getTexture(key: string): Texture { return this._sheet.textures[key]; } } ================================================ FILE: src/class/pixi/init/PIXIFontLoadHandler.ts ================================================ /** * useWebGL 일때 font 로드가 끝나면 생성된 모든 text 오브젝트를 다시 draw 하도록 함. */ import { TextMetrics } from 'pixi.js'; const LOADED = 'fontLoaded'; export class PIXIFontLoadHandler { private _items: any[] = []; private _fontLoaded: boolean; constructor() { this._handleFontLoaded = this._handleFontLoaded.bind(this); this._listen(); } private _listen() { if ((window as any).fontLoaded) { this._fontLoaded = true; } else { Entry.addEventListener(LOADED, this._handleFontLoaded); } } private _handleFontLoaded() { this._fontLoaded = true; Entry.removeEventListener(LOADED, this._handleFontLoaded); TextMetrics.clearMetrics(null); this._items.forEach((text: any) => { //updateText() 는 private 함수이지만, override 했으므로, 호출하겠음. text.updateText(false); }); Entry.requestUpdate = true; this._items = null; } /** @param {PIXIText} text */ manage(text: any) { if (this._fontLoaded) { return; } this._items.push(text); } /** @param {PIXIText} text */ unmanage(text: any) { if (this._fontLoaded) { return; } const arr = this._items; const index = arr.indexOf(text); if (index == -1) { return; } arr.splice(index, 1); } } ================================================ FILE: src/class/pixi/init/PIXIGlobal.ts ================================================ import { Application, utils as PIXIUtils } from 'pixi.js'; import { PIXIBaseAsset } from './PIXIBaseAsset'; import { PIXICollision as ndgmr } from '../etc/PIXI-ndgmr.Collision'; import '../etc/PIXICanvasInput'; import { PIXIAtlasManager } from '../atlas/PIXIAtlasManager'; import { PIXIPixelPerfectInteractionPlugIn } from '../plugins/PIXIPixelPerfectInteractionPlugIn'; import { PIXITempStore } from '../etc/PIXITempStore'; import { PIXITextMetricsPlugIn } from '../plugins/PIXITextMetricsPlugIn'; import { PIXIShortPropPlugin } from '../plugins/PIXIShortPropPlugin'; import { PIXIGraphicOverride } from '../plugins/PIXIGraphicOverride'; import { PIXIFontLoadHandler } from './PIXIFontLoadHandler'; import { pixiGetChildAt } from '../plugins/pixiGetChildAt'; class _PIXIGlobal { private _init: boolean; /** @readonly */ baseAsset: PIXIBaseAsset; atlasManager: PIXIAtlasManager; fontLoadChecker: PIXIFontLoadHandler; initOnce() { if (this._init) { return; } this._init = true; this._isWebGLSupported(); this.fontLoadChecker = new PIXIFontLoadHandler(); //this.baseAsset = new PIXIBaseAsset(); ndgmr.initTempObject(); (window as any).ndgmr = ndgmr; PIXITempStore.init(); this.atlasManager = new PIXIAtlasManager(); PIXIShortPropPlugin(); pixiGetChildAt(); PIXIPixelPerfectInteractionPlugIn(); PIXITextMetricsPlugIn(); PIXIGraphicOverride(); } getNewApp(canvas: HTMLCanvasElement): Application { PIXIUtils.skipHello(); const app = new Application({ view: canvas, width: canvas.width, height: canvas.height, autoStart: false, antialias: true, transparent: true, }); (app.stage as any).canvas = canvas; return app; } private _isWebGLSupported() { if (PIXIUtils.isWebGLSupported()) { return; } throw new Error('webgl not supported'); } } export const PIXIGlobal: _PIXIGlobal = new _PIXIGlobal(); ================================================ FILE: src/class/pixi/mesh/PIXIH3Plane.js ================================================ import { Container } from 'pixi.js'; export class PIXIH3Plane extends Container { /** * assignTexture() 호출 이후, width, tint 를 호출해야 함. * @param {PIXIBaseAsset} baseAsset */ constructor(baseAsset) { super(); this._baseAsset = baseAsset; this._tint = 0xffffff; this._prevTexturePrefix = ''; } assignTexture(texturePrefix) { if (this._prevTexturePrefix === texturePrefix) { return; } this._prevTexturePrefix = texturePrefix; this._tint = 0xffffff; this._releaseSprite(this._sp0); this._releaseSprite(this._sp1); this._releaseSprite(this._sp2); const ba = this._baseAsset; this._sp0 = this._appendSprite(ba, texturePrefix, 0); this._sp1 = this._appendSprite(ba, texturePrefix, 1); this._sp2 = this._appendSprite(ba, texturePrefix, 2); this._sideWidth = this._sp0.width + this._sp2.width; } /** * * @param {PIXIBaseAsset} baseAsset * @param {string} texturePrefix * @param {number} index */ _appendSprite(baseAsset, texturePrefix, index) { const sp = baseAsset.newSprite(texturePrefix + index); this.addChild(sp); return sp; } _releaseSprite(sp) { if (!sp) { return; } sp.destroy(); } set width(value) { const cw = value - this._sideWidth; if (cw > 0) { this._sp1.x = this._sp0.width; this._sp1.width = cw; this._sp2.x = value - this._sp2.width; } else { this._sp0.scale.x = this._sp2.scale.x = value / this._sideWidth; this._sp2.x = this._sp0.width; this._sp1.scale.x = 0; } } /** * @param {number} value */ set tint(value) { this._tint = value; this._sp0.tint = this._sp1.tint = this._sp2.tint = value; } get tint() { return this._tint; } } ================================================ FILE: src/class/pixi/plugins/PIXIGraphicOverride.js ================================================ import { Graphics } from 'pixi.js'; /** * PIXI.Graphics을 createjs.Shape와 비슷한 인터페이스로 구현하기 위한 함수 * */ class GraphicsAdaptor { constructor(gra) { /** * @private * @type {PIXI.Graphics} */ this._gra = gra; this._lineStyleChanged = false; this._lineStyle = { alpha: 1, color: 0, thickness: 0, }; this._fillStyle = { alpha: 1, color: 0, }; } moveTo(x, y) { this._gra.moveTo(x, y); return this; } beginFill(color) { const style = this._fillStyle; this._parseRGBCssStyleColor(color, style); this._gra.beginFill(style.color, style.alpha); return this; } beginStroke(color) { this._parseRGBCssStyleColor(color, this._lineStyle); this._lineStyleChanged = true; this._setStrokeStyle(); return this; } drawRoundRect(x, y, w, h, r) { this._gra.drawRoundedRect(x, y, w, h, r); return this; } drawCircle(x, y, r) { this._gra.drawCircle(x, y, r); return this; } lineTo(x, y) { this._gra.lineTo(x, y); return this; } clear() { this._gra.clear(); return this; } setStrokeStyle(thickness, caps = 0, joints = 0, miterLimit = 10) { this._lineStyleChanged = true; this._lineStyle.thickness = thickness; this._setStrokeStyle(); return this; } drawRect(x, y, w, h) { this._gra.drawRect(x, y, w, h); return this; } closePath() { this._gra.closePath(); return this; } endStroke() { //todo [박준배] endStroke에 해당하는 pixi 메서드를 찾아서 넣어주긔. return this; } _setStrokeStyle() { if (!this._lineStyleChanged) { return; } this._lineStyleChanged = false; const s = this._lineStyle; this._gra.lineStyle(s.thickness, s.color, s.alpha); } /** * @param color {string} * @param result * @private */ _parseRGBCssStyleColor(color, result) { if (!color) { return; } color = color.replace('/s/', ''); if (color[0] === '#') { result.color = parseInt(color.substr(1), 16); return; } let regexResult; regexResult = /^rgba\((\d+),(\d+),(\d+),(\d+(\.?\d*))\)$/i.exec(color); if (regexResult) { result.color = this._RGBToNumber(regexResult); result.alpha = Number(regexResult[4]); return; } regexResult = /^rgb\((\d+),(\d+),(\d+)\)$/i.exec(color); if (regexResult) { result.color = this._RGBToNumber(regexResult); } } _RGBToNumber(regexResult) { const [x, r, g, b] = regexResult; return (r << 16) + (g << 8) + Number(b); } quadraticCurveTo(cpX, cpY, toX, toY) { this._gra.quadraticCurveTo(cpX, cpY, toX, toY); return this; } drawEllipse(x, y, width, height) { this._gra.drawEllipse(x, y, width, height); return this; } } // createjs tiny api const GP = GraphicsAdaptor.prototype; GP.mt = GP.moveTo; GP.f = GP.beginFill; GP.s = GP.beginStroke; GP.rr = GP.drawRoundRect; GP.dc = GP.drawCircle; GP.lt = GP.lineTo; GP.ss = GP.setStrokeStyle; GP.rect = GP.r = GP.dr = GP.drawRect; GP.cp = GP.closePath; GP.es = GP.endStroke; GP.qt = GP.quadraticCurveTo; GP.de = GP.drawEllipse; export function PIXIGraphicOverride() { const p = Graphics.prototype; Object.defineProperties(p, { graphics: { get() { if (!this.___adaptor___) { this.___adaptor___ = new GraphicsAdaptor(this); } return this.___adaptor___; }, }, }); } ================================================ FILE: src/class/pixi/plugins/PIXIPixelPerfectInteractionPlugIn.js ================================================ import { Sprite, Point } from 'pixi.js'; const tempPoint = new Point(); const hitTestCanvas = document.createElement('canvas'); hitTestCanvas.width = 1; hitTestCanvas.height = 1; const hitTestConText = hitTestCanvas.getContext('2d'); export function PIXIPixelPerfectInteractionPlugIn() { const p = Sprite.prototype; /** * if true use pixel-perfect hit test * @type {boolean} */ p.pixelPerfect = false; /** @type {number} not ratio. 16 bit value. * [박봉배] - createjs 에서 testAlpha > 1 이면 히트로 처리. */ p.pixelPerfectAlpha = 1; /** * PIXISprite.ts 에서 override 함. 메서드명 바꾸지 말긔. * @return {PIXI.BaseTexture | (HTMLImageElement | HTMLCanvasElement | HTMLVideoElement)} */ p.internal_getOriginalTex = function() { return this.texture; }; p.containsPoint = function(point) { //overwrite PIXI.Sprite.containsPoint const tex = this.internal_getOriginalTex(); // if (!tex.baseTexture) { // return false; // } // if (!tex.baseTexture.source) { // return false; // } this.worldTransform.applyInverse(point, tempPoint); const width = tex.orig.width; const height = tex.orig.height; const x1 = -width * this.anchor.x; let y1 = 0; if (tempPoint.x >= x1 && tempPoint.x < x1 + width) { y1 = -height * this.anchor.y; if (tempPoint.y >= y1 && tempPoint.y < y1 + height) { if (this.pixelPerfect) { return this._pixelHasAlpha(tempPoint.x, tempPoint.y, tex); } return true; } } return false; }; // end p.containsPoint p._pixelHasAlpha = function(x, y, tex) { //add method into PIXI.Sprite let left = x; let top = y; const { frame } = tex; const anchor = this.anchor; if (anchor.x !== 0) { left -= -frame.width * anchor.x; } if (anchor.y !== 0) { top -= -frame.height * anchor.y; } left += frame.x; top += frame.y; const { resource } = tex.baseTexture; const { source } = resource || {}; if (!source) { return false; } const ctx = hitTestConText; ctx.clearRect(0, 0, 1, 1); ctx.drawImage(source, left, top, 1, 1, 0, 0, 1, 1); const rgba = ctx.getImageData(0, 0, 1, 1); return rgba.data[3] > this.pixelPerfectAlpha; }; //end p._checkPixel } ================================================ FILE: src/class/pixi/plugins/PIXIShortPropPlugin.js ================================================ import { DisplayObject, Container } from 'pixi.js'; export function PIXIShortPropPlugin() { Object.defineProperties(DisplayObject.prototype, { scaleX: { get() { return this.scale.x; }, set(v) { this.scale.x = v; }, }, scaleY: { get() { return this.scale.y; }, set(v) { this.scale.y = v; }, }, regX: { get() { return this.pivot.x; }, set(v) { this.pivot.x = v; }, }, regY: { get() { return this.pivot.y; }, set(v) { this.pivot.y = v; }, }, mouseEnabled: { get() { return this.interactive; }, set(v) { this.interactive = v; }, }, }); Object.defineProperties(Container.prototype, { mouseChildren: { get() { return this.interactiveChildren; }, set(v) { this.interactiveChildren = v; }, }, }); } ================================================ FILE: src/class/pixi/plugins/PIXISprite.ts ================================================ /** * PIXI.DisplayObject.cacheAsBitmap 이 원하는대로 작동을 안함. * var sp = new PIXI.Sprite(texture); * sp.scale.set(2) * sp.cacheAsBitmap = true; 이렇게 하면 케시된 텍스쳐가 localTransform에 영향을 받아서 스케일이 2배가 되어버림. 원본과 동일해야 하는데... * * 그래서 setFilterAndCache() 로 비슷하게 구현. */ import { Texture, Sprite, RenderTexture, Matrix, Renderer } from 'pixi.js'; import { EntryTextureBase } from '../atlas/texture/EntryTextureBase'; class FilterData { private _orgTex: EntryTextureBase | RenderTexture; private _renderTex: RenderTexture; filters: any[]; invalidate: boolean; setOrgTex(orgTex: EntryTextureBase) { this._orgTex = orgTex; } isSameRenderTex(tex: any): boolean { return tex == this._renderTex; } get orgTex(): EntryTextureBase | RenderTexture { return this._orgTex; } getRenderTexture(width: number, height: number): RenderTexture { if (!this._renderTex) { this._renderTex = RenderTexture.create({ width, height }); return this._renderTex; } const tex = this._renderTex; if (tex.width != width || tex.height != height) { this.destroyRenderTexture(); return this.getRenderTexture(width, height); } return this._renderTex; } destroyRenderTexture() { if (!this._renderTex) { return; } this._renderTex.destroy(true); this._renderTex = null; } destroy() { this.destroyRenderTexture(); this._orgTex = null; this.filters = null; } } const EMPTY_SP = new Sprite(); const MAT: any = new Matrix(); export class PIXISprite extends Sprite { private _filterData: FilterData; // public _filterData:FilterData; //PIXIPixelPerfectInteractionPlugIn 에서 호출함. internal_getOriginalTex() { return (this._filterData && this._filterData.orgTex) || this.texture; } setFilterAndCache(filters: any[] | null) { if (!filters || !filters.length) { if (this._filterData) { this.texture = this._filterData.orgTex; this._filterData.destroy(); this._filterData = null; } } else { if (!this._filterData) { this._filterData = new FilterData(); this._filterData.setOrgTex(this.texture as EntryTextureBase); } else if (!this._filterData.isSameRenderTex(this.texture)) { this._filterData.setOrgTex(this.texture as EntryTextureBase); } this._filterData.filters = filters; this._filterData.invalidate = true; } } /** * filter + cache 가 이미 설정되고, 다른 텍스쳐로 할당 되었을때 filter를 다시 설정하기 위한 메서드 * set texture 를 override 하지 못해서... */ refreshFilter() { if (!this._filterData) { return; } if (!this._filterData.filters) { return; } this.setFilterAndCache(this._filterData.filters); } destroy(options?: any) { super.destroy(options); if (this._filterData) { this._filterData.destroy(); this._filterData = null; } } render(renderer: Renderer): void { if (this._filterData && this._filterData.invalidate) { this._filterData.invalidate = false; this._initFilterCache(renderer); } super.render(renderer); } private _initFilterCache(renderer: Renderer) { const fd: FilterData = this._filterData; const tex: Texture = fd.orgTex; const w = tex.orig.width; const h = tex.orig.height; const renderTex: RenderTexture = fd.getRenderTexture(w, h); if (!renderTex) { return; } if (fd.orgTex instanceof EntryTextureBase) { // filter 된 sprite 를 도장찍기 하면 sprite.texture 의 type 는 RenderTexture 가 된다. fd.orgTex.assignTextureScaleFactor(renderTex); } const sp = EMPTY_SP; sp.filters = this._filterData.filters; sp.texture = tex; const cachedRenderTarget = renderer.renderTexture.current; renderer.batch.flush(); renderer.render(sp, renderTex, true, MAT, false); renderer.renderTexture.bind(cachedRenderTarget); this.texture = renderTex; sp.texture = null; } } ================================================ FILE: src/class/pixi/plugins/PIXITextMetricsPlugIn.js ================================================ import { TextMetrics } from 'pixi.js'; export function PIXITextMetricsPlugIn() { const WordWrap = TextMetrics.wordWrap; TextMetrics.__breakAllWordWrap = __breakAllWordWrap; TextMetrics.wordWrap = function(text, style, canvas = TextMetrics._canvas) { return style.wordBreakAll ? TextMetrics.__breakAllWordWrap(text, style, canvas) : WordWrap(text, style, canvas); }; /** * * @param text * @param {PIXI.TextStyle | PIXITextStyle} style * @param canvas * @return {string} * @private */ function __breakAllWordWrap(text, style, canvas) { const context = canvas.getContext('2d'); let width = 0; let line = ''; let lines = ''; const cache = {}; const { letterSpacing, whiteSpace } = style; // How to handle whitespaces const collapseSpaces = TextMetrics.collapseSpaces(whiteSpace); const collapseNewlines = TextMetrics.collapseNewlines(whiteSpace); // whether or not spaces may be added to the beginning of lines let canPrependSpaces = !collapseSpaces; // There is letterSpacing after every char except the last one // t_h_i_s_' '_i_s_' '_a_n_' '_e_x_a_m_p_l_e_' '_! // so for convenience the above needs to be compared to width + 1 extra letterSpace // t_h_i_s_' '_i_s_' '_a_n_' '_e_x_a_m_p_l_e_' '_!_ // ________________________________________________ // And then the final space is simply no appended to each line const wordWrapWidth = style.wordWrapWidth + letterSpacing; // break text into words, spaces and newline chars const tokens = TextMetrics.tokenize(text); for (let i = 0; i < tokens.length; i++) { // get the word, space or newlineChar let token = tokens[i]; // if word is a new line if (TextMetrics.isNewline(token)) { // keep the new line if (!collapseNewlines) { lines += TextMetrics.addLine(line); canPrependSpaces = !collapseSpaces; line = ''; width = 0; continue; } // if we should collapse new lines // we simply convert it into a space token = ' '; } // if we should collapse repeated whitespaces if (collapseSpaces) { // check both this and the last tokens for spaces const currIsBreakingSpace = TextMetrics.isBreakingSpace(token); const lastIsBreakingSpace = TextMetrics.isBreakingSpace(line[line.length - 1]); if (currIsBreakingSpace && lastIsBreakingSpace) { continue; } } // get word width from cache if possible const tokenWidth = TextMetrics.getFromCache(token, letterSpacing, cache, context); // word is longer than desired bounds if (width + tokenWidth > wordWrapWidth) { const characters = token.split(''); for (let j = 0; j < characters.length; j++) { const char = characters[j]; const characterWidth = TextMetrics.getFromCache( char, letterSpacing, cache, context ); if (width + characterWidth > wordWrapWidth) { //newLine lines += TextMetrics.addLine(line); canPrependSpaces = false; line = ''; width = 0; } line += char; width += characterWidth; } } // word could fit else { // word won't fit because of existing words // start a new line if (tokenWidth + width > wordWrapWidth) { // if its a space we don't want it canPrependSpaces = false; // add a new line lines += TextMetrics.addLine(line); // start a new line line = ''; width = 0; } // don't add spaces to the beginning of lines if (line.length > 0 || !TextMetrics.isBreakingSpace(token) || canPrependSpaces) { // add the word to the current line line += token; // update width counter width += tokenWidth; } } } lines += TextMetrics.addLine(line, false); return lines; } //createjs와 동일한 글씨 크기 측정을 위해 /** * * @param {PIXI.TextStyle} style * @param text * @return {number} * @private */ function _getMeasuredWidth(font, text) { const ctx = TextMetrics._context; ctx.save(); ctx.font = font; const w = ctx.measureText(text).width; ctx.restore(); return w; } //createjs와 동일한 글씨 크기 측정을 위해 TextMetrics.measureText = function(text, style, wordWrap, canvas = TextMetrics._canvas) { wordWrap = wordWrap === undefined || wordWrap === null ? style.wordWrap : wordWrap; const font = style.toFontString(); // const fontProperties = TextMetrics.measureFont(font); //skip for performance const fontProperties = null; const context = canvas.getContext('2d'); context.font = font; const outputText = wordWrap ? TextMetrics.wordWrap(text, style, canvas) : text; const lines = outputText.split(/(?:\r\n|\r|\n)/); const lineWidths = new Array(lines.length); let maxLineWidth = 0; for (let i = 0; i < lines.length; i++) { const lineWidth = context.measureText(lines[i]).width + (lines[i].length - 1) * style.letterSpacing; lineWidths[i] = lineWidth; maxLineWidth = Math.max(maxLineWidth, lineWidth); } const width = maxLineWidth + style.strokeThickness; const lineHeight = style.lineHeight || _getMeasuredWidth(font, 'M') * 1.2; const height = lineHeight * lines.length; return new TextMetrics( text, style, width, height, lines, lineWidths, lineHeight + style.leading, maxLineWidth, fontProperties ); }; } ================================================ FILE: src/class/pixi/plugins/pixiGetChildAt.js ================================================ /** * PIXI.Container.getChildAt 은 잘못된 index를 넣으면 throw 함. createjs 는 안함. * 동일한 스펙을 맞추기 위해 새로 정의함. */ import { Container } from 'pixi.js'; export function pixiGetChildAt() { const p = Container.prototype; p.getChildAt = function(index) { return this.children[index]; }; p.getChildIndex = function(child) { return this.children.indexOf(child); }; p.___addChildAt = p.addChildAt; p.addChildAt = function(child, index) { try { return this.___addChildAt(child, index); } catch (e) { return child; } }; } ================================================ FILE: src/class/pixi/text/PIXIText.js ================================================ /** * createjs 의 rendeeing 방식을 따라 하기 위해 fontProperty를 사용안함. * 뷰의 스케일 조정을 하더라도 깔끔하게 보이기 위해 fontScale 를 추가하여 텍스쳐의 크기를 조절함. */ import { TextMetrics, Text } from 'pixi.js'; import PIXITextStyle from './PIXITextStyle'; import { PIXIGlobal } from '../init/PIXIGlobal'; let $textCanvasContainer; export class PIXIText extends Text { constructor(text, style) { const canvas = document.createElement('canvas'); if (!$textCanvasContainer) { $textCanvasContainer = $('#textCanvasContainer'); } $textCanvasContainer.append(canvas); super(text, style, canvas); this.setFontScaleX(1); this.setFontScaleY(1); PIXIGlobal.fontLoadChecker.manage(this); } set style(style) { // eslint-disable-line require-jsdoc style = style || {}; if (style instanceof PIXITextStyle) { this._style = style; } else { this._style = new PIXITextStyle(style); } this.localStyleID = -1; this.dirty = true; } get style() { return super.style; } setFontScaleX(value) { value = value * PIXIText.STAGE_SCALE; this._fontScaleX = value; this.scale.x = 1 / value; this.dirty = true; } setFontScaleY(value) { value = value * PIXIText.STAGE_SCALE; this._fontScaleY = value; this.scale.y = 1 / value; this.dirty = true; } getMeasuredWidth() { this.updateText(true); return this._measuredWidth; } getMeasuredHeight() { this.updateText(true); return this._measuredHeight; } getMeasuredLineHeight() { this.updateText(true); return this._measuredLineHeight; } /** @deprecated */ get measuredWidth() { this.updateText(true); console.warn('[deprecated] - PIXIText.measuredWidth'); return this._measuredWidth; } /** @deprecated */ get measuredHeight() { this.updateText(true); console.warn('[deprecated] - PIXIText.measuredHeight'); return this._measuredHeight; } /** @deprecated */ get measuredLineHeight() { this.updateText(true); console.warn('[deprecated] - PIXIText.measuredLineHeight'); return this._measuredLineHeight; } /** * Renders text and updates it when needed. * * @private * @param {boolean} respectDirty - Whether to abort updating the text if the Text isn't dirty and the function is called. */ updateText(respectDirty) { const style = this._style; // check if style has changed.. if (this.localStyleID !== style.styleID) { this.dirty = true; this.localStyleID = style.styleID; } if (!this.dirty && respectDirty) { return; } this._font = this._style.toFontString(); const context = this.context; const measured = TextMetrics.measureText( this._text, this._style, this._style.wordWrap, this.canvas ); const width = (this._measuredWidth = measured.width); const height = (this._measuredHeight = measured.height); const lines = measured.lines; const lineHeight = (this._measuredLineHeight = measured.lineHeight); const lineWidths = measured.lineWidths; const maxLineWidth = measured.maxLineWidth; const fontProperties = measured.fontProperties; const UN = undefined; const FSX = this._fontScaleX === UN ? 1 : this._fontScaleX; const FSY = this._fontScaleY === UN ? 1 : this._fontScaleY; this.canvas.width = Math.ceil( (Math.max(1, width) + style.padding * 2) * this.resolution * FSX ); this.canvas.height = Math.ceil( (Math.max(1, height) + style.padding * 2) * this.resolution * FSY ); context.scale(this.resolution * FSX, this.resolution * FSY); context.clearRect(0, 0, this.canvas.width, this.canvas.height); //---------- DEBUG CODE ------------ // context.fillStyle = "rgba(255, 0, 0, 0.3)"; // context.fillRect(0, 0, this.canvas.width, this.canvas.height); //---------- DEBUG CODE ------------ context.font = this._font; context.strokeStyle = style.stroke; context.lineWidth = style.strokeThickness; context.textBaseline = style.textBaseline; context.lineJoin = style.lineJoin; context.miterLimit = style.miterLimit; let linePositionX; let linePositionY; if (style.dropShadow) { context.fillStyle = style.dropShadowColor; context.globalAlpha = style.dropShadowAlpha; context.shadowBlur = style.dropShadowBlur; if (style.dropShadowBlur > 0) { context.shadowColor = style.dropShadowColor; } const xShadowOffset = Math.cos(style.dropShadowAngle) * style.dropShadowDistance; const yShadowOffset = Math.sin(style.dropShadowAngle) * style.dropShadowDistance; for (let i = 0; i < lines.length; i++) { linePositionX = style.strokeThickness / 2; linePositionY = style.strokeThickness / 2 + i * lineHeight + fontProperties.ascent; if (style.align === 'right') { linePositionX += maxLineWidth - lineWidths[i]; } else if (style.align === 'center') { linePositionX += (maxLineWidth - lineWidths[i]) / 2; } if (style.fill) { this.drawLetterSpacing( lines[i], linePositionX + xShadowOffset + style.padding, linePositionY + yShadowOffset + style.padding ); if (style.stroke && style.strokeThickness) { context.strokeStyle = style.dropShadowColor; this.drawLetterSpacing( lines[i], linePositionX + xShadowOffset + style.padding, linePositionY + yShadowOffset + style.padding, true ); context.strokeStyle = style.stroke; } } } } // reset the shadow blur and alpha that was set by the drop shadow, for the regular text context.shadowBlur = 0; context.globalAlpha = 1; // set canvas text styles context.fillStyle = this._generateFillStyle(style, lines); const WORD_WRAP = style.wordWrap; const H_LH = lineHeight * 0.5; // half line-height const MAX_HEIGHT = style.maxHeight < 0 ? 0xffff : style.maxHeight - H_LH; const PAD = style.padding; // draw lines line by line for (let i = 0; i < lines.length; i++) { linePositionX = style.strokeThickness / 2; linePositionY = style.strokeThickness / 2 + i * lineHeight + H_LH; if (WORD_WRAP && linePositionY > MAX_HEIGHT) { break; } if (style.align === 'right') { linePositionX += maxLineWidth - lineWidths[i]; } else if (style.align === 'center') { linePositionX += (maxLineWidth - lineWidths[i]) / 2; } if (style.stroke && style.strokeThickness) { this.drawLetterSpacing( lines[i], linePositionX + style.padding, linePositionY + style.padding, true ); } if (style.fill) { this.drawLetterSpacing( lines[i], linePositionX + style.padding, linePositionY + style.padding ); } //취소선 추가 if (style.cancelLine) { this._drawLineAt( context, linePositionX + PAD, linePositionY + PAD, lineWidths[i], 0 ); } //밑줄 if (style.underLine) { this._drawLineAt( context, linePositionX + PAD, linePositionY + PAD, lineWidths[i], lineHeight * 0.4 ); } } this.updateTexture(); } updateTexture() { const canvas = this.canvas; // 박봉배- entryjs 에서 trim 기능 사용안함. 그리고 trimCanvas 의 참조를 pixi 라이브러리로부터 못갖고 오겠음. /* if (this._style.trim) { const trimmed = trimCanvas(canvas); if (trimmed.data) { canvas.width = trimmed.width; canvas.height = trimmed.height; this.context.putImageData(trimmed.data, 0, 0); } } */ const texture = this._texture; const style = this._style; const padding = style.trim ? 0 : style.padding; const baseTexture = texture.baseTexture; const UN = undefined; const FSX = this._fontScaleX === UN ? 1 : this._fontScaleX; const FSY = this._fontScaleY === UN ? 1 : this._fontScaleY; baseTexture.hasLoaded = true; baseTexture.resolution = this.resolution; baseTexture.setRealSize(canvas.width, canvas.height); baseTexture.setSize(canvas.width, canvas.height, this.resolution); texture.trim.width = texture._frame.width = canvas.width / this.resolution; texture.trim.height = texture._frame.height = canvas.height / this.resolution; texture.trim.x = -padding * FSX; texture.trim.y = -padding * FSY; texture.orig.width = texture._frame.width - padding * 2 * FSX; texture.orig.height = texture._frame.height - padding * 2 * FSY; // call sprite onTextureUpdate to update scale if _width or _height were set this._onTextureUpdate(); baseTexture.emit('update', baseTexture); this.dirty = false; } /** * 취소선 or 밑줄을 draw 하기 위한 함수. * @private * @param {CanvasRenderingContext2D} ctx * @param x * @param y * @param width * @param offsetY */ _drawLineAt(ctx, x, y, width, offsetY) { ctx.fillRect(x, y + offsetY, width, 1); } destroy() { $(this.canvas).remove(); PIXIGlobal.fontLoadChecker.unmanage(this); super.destroy({ children: false, baseTexture: true, texture: true }); } } // PIXIText.STAGE_SCALE = 1.51; PIXIText.STAGE_SCALE = 1.53; // PIXIText.STAGE_SCALE = 1.41; // console.log(`PIXIText.STAGE_SCALE1(${PIXIText.STAGE_SCALE})`); ================================================ FILE: src/class/pixi/text/PIXITextStyle.ts ================================================ /** * 취소선, 밑줄 추가 하기 위해 만튼 스타일. */ import { TextStyle } from 'pixi.js'; export default class PIXITextStyle extends TextStyle { /** 취소선 */ private _cancelLine: boolean = false; private _underLine: boolean = false; /** 멀티 라인일때 ( wordWrap = true ) 글씨가 보여지는 최대 높이. 음수일때는 글씨를 모두 보여줌. */ private _maxHeight: number = -1; private styleID: number = 0; /** * * @return {boolean} */ get cancelLine() { return this._cancelLine; } set cancelLine(value) { if (this._cancelLine !== value) { this._cancelLine = value; this.styleID++; } } /** css wordBreak 의 break-all 속성을 구현하기 위함. entryjs 는 break-all 이 기본이기 때문에 return true 로 해버림. */ get wordBreakAll(): boolean { return true; } /** * * @return {boolean} */ get underLine() { return this._underLine; } set underLine(value) { if (this._underLine !== value) { this._underLine = value; this.styleID++; } } get maxHeight() { return this._maxHeight; } set maxHeight(value) { if (this._maxHeight !== value) { this._maxHeight = value; this.styleID++; } } } ================================================ FILE: src/class/pixi/utils/AutoFit.ts ================================================ export interface IRect { x: number; y: number; width: number; height: number; } export namespace autoFit { export enum ScaleMode { NONE, WIDTH, HEIGHT, INSIDE, OUTSIDE, } export enum AlignMode { TL, TC, CC, BC, BL, NONE, } export function fit( targetArea: IRect, rSource: IRect, scaleMode: ScaleMode, alignMode: AlignMode = AlignMode.CC ): IRect { switch (scaleMode) { case ScaleMode.NONE: align(targetArea, rSource, alignMode); break; case ScaleMode.INSIDE: align(targetArea, proportional_inside(targetArea, rSource), alignMode); break; case ScaleMode.OUTSIDE: align(targetArea, proportional_outside(targetArea, rSource), alignMode); break; case ScaleMode.WIDTH: align(targetArea, width_only(targetArea, rSource), alignMode); break; case ScaleMode.HEIGHT: align(targetArea, height_only(targetArea, rSource), alignMode); break; } return rSource; } function width_only(targetArea: IRect, rSource: IRect): IRect { const s: number = targetArea.width / rSource.width; rSource.width *= s; rSource.height *= s; return rSource; } function height_only(targetArea: IRect, rSource: IRect): IRect { const s: number = targetArea.height / rSource.height; rSource.width *= s; rSource.height *= s; return rSource; } function proportional_inside(targetArea: IRect, rSource: IRect): IRect { const sx: number = targetArea.width / rSource.width; const sy: number = targetArea.height / rSource.height; const s: number = Math.min(sx, sy); rSource.width *= s; rSource.height *= s; return rSource; } function proportional_outside(targetArea: IRect, rSource: IRect): IRect { const sx: number = targetArea.width / rSource.width; const sy: number = targetArea.height / rSource.height; const s: number = Math.max(sx, sy); rSource.width = rSource.width * s; rSource.height = rSource.height * s; return rSource; } function align(targetArea: IRect, rSource: IRect, strAlign: AlignMode): IRect { switch (strAlign) { case AlignMode.TC: setCenter(targetArea, rSource, true, false); rSource.x = targetArea.x; break; case AlignMode.CC: setCenter(targetArea, rSource); break; case AlignMode.TL: rSource.x = targetArea.x; rSource.y = targetArea.y; break; case AlignMode.BC: setCenter(targetArea, rSource, true, false); rSource.y = targetArea.y + targetArea.height - rSource.height; break; case AlignMode.BL: rSource.x = targetArea.x; rSource.y = targetArea.y + targetArea.height - rSource.height; break; case AlignMode.NONE: //아무것도 안함. break; } return rSource; } export function setCenter( targetArea: IRect, rSource: IRect, axisX: Boolean = true, axisY: Boolean = true ): void { const r: IRect = targetArea; if (axisX) { rSource.x = r.x + r.width / 2 - rSource.width / 2; } if (axisY) { rSource.y = r.y + r.height / 2 - rSource.height / 2; } } } ================================================ FILE: src/class/pixi/utils/TimeoutTimer.ts ================================================ export class TimeoutTimer { private _id: number; timeout(timeMS: number, handler: () => void) { this.reset(); this._id = window.setTimeout(() => { handler(); this._id = 0; }, timeMS); } get isRunning(): boolean { return Boolean(this._id); } reset(): void { if (!this._id) { return; } clearTimeout(this._id); this._id = 0; } } ================================================ FILE: src/class/pixi/utils/logs.ts ================================================ type Ilog = (...arg:any[])=>void; let emptyLog:Ilog = (...arg:any[])=>{}; const USE_NATIVE_LOG:boolean = false; let nlog:Ilog = console.log.bind(console); export let clog:Ilog = USE_NATIVE_LOG ? nlog : emptyLog; let nwarn:Ilog = console.warn.bind(console); export let cwarn:Ilog = USE_NATIVE_LOG ? nwarn : emptyLog; ================================================ FILE: src/class/playground.js ================================================ /** * Playground is block construct area. * @fileoverview This manage playground. */ 'use strict'; import { Backpack, ColorPicker, Dropdown, Sortable } from '@entrylabs/tool'; import Toast from '../playground/toast'; import EntryEvent from '@entrylabs/event'; import { Destroyer } from '../util/destroyer/Destroyer'; import DataTable from './DataTable'; import SoundEditor from './sound'; import _get from 'lodash/get'; const Entry = require('../entry'); /** * Class for a playground. * This manage all view related with block. * @constructor */ Entry.Playground = class Playground { constructor() { this._destroyer = this._destroyer || new Destroyer(); this._destroyer.destroy(); this.isTextBGMode_ = false; this.dataTable = DataTable; /** * playground's current view type * View types are 'default', 'code', 'picture', 'text', sound' * @type {string} */ this.viewMode_ = 'default'; Entry.addEventListener('textEdited', () => { this.injectText(); }); Entry.addEventListener('commentVisibleChanged', this.toggleCommentButtonVisible.bind(this)); Entry.addEventListener('workspaceChangeMode', this.updateSelectedObjectTitle.bind(this)); Entry.windowResized.attach(this, this.clearClientRectMemo.bind(this)); } setMode(mode) { this.mainWorkspace.setMode(mode); } /** * Control bar view generator. * @param {!Element} playgroundView playgroundView from Entry. * @param {?string} option for choose type of view. */ generateView(playgroundView, option = 'workspace') { /** @type {!Element} */ this.view_ = playgroundView; this.view_.addClass('entryPlayground'); if (option === 'workspace' || option === 'playground') { this.view_.addClass('entryPlaygroundWorkspace'); const tabView = Entry.createElement('div', 'entryCategoryTab') .addClass('entryPlaygroundTabWorkspace') .appendTo(this.view_); this.generateTabView(tabView); this.tabView_ = tabView; const tabButtonView = Entry.createElement('div', 'entryButtonTab') .addClass('entryPlaygroundButtonTabWorkspace') .appendTo(this.view_); this.tabButtonView_ = tabButtonView; this.createButtonTabView(tabButtonView); const curtainView = Entry.createElement('div', 'entryCurtain') .addClass('entryPlaygroundCurtainWorkspace entryRemove') .appendTo(this.view_); curtainView.textContent = Lang.Workspace.cannot_edit_click_to_stop; curtainView.addEventListener('click', () => { Entry.engine.toggleStop(); }); this.curtainView_ = curtainView; const pictureView = Entry.createElement('div', 'entryPicture') .addClass('entryPlaygroundPictureWorkspace entryRemove') .appendTo(this.view_); this.generatePictureView(pictureView); this.pictureView_ = pictureView; const pictureCurtainView = Entry.createElement('div', 'entryPictureCurtain') .addClass('entryPlaygroundPictureCurtainWorkspace entryRemove') .appendTo(pictureView); this.pictureCurtainView_ = pictureCurtainView; const pictureCurtainText = Entry.createElement('span', 'entryPictureCurtainText') .addClass('entryPlaygroundPictureCurtainWorkspaceText') .appendTo(pictureCurtainView); pictureCurtainText.textContent = Lang.Workspace.add_object_before_edit; const textView = Entry.createElement('div', 'entryText') .addClass('entryPlaygroundTextWorkspace entryRemove') .appendTo(this.view_); this.generateTextView(textView); this.textView_ = textView; const soundView = Entry.createElement('div', 'entrySound') .addClass('entryPlaygroundSoundWorkspace entryRemove') .appendTo(this.view_); this.generateSoundView(soundView); this.soundView_ = soundView; const defaultView = Entry.createElement('div', 'entryDefault') .addClass('entryPlaygroundDefaultWorkspace') .appendTo(this.view_); this.generateDefaultView(defaultView); this.defaultView_ = defaultView; //Code view must be append at last. const codeView = Entry.createElement('div', 'entryCode') .addClass('entryPlaygroundCodeWorkspace entryRemove') .appendTo(this.view_); this.generateCodeView(codeView); this.codeView_ = codeView; const backPackView = Entry.createElement('div', 'entryBackPackView') .addClass('entryPlaygroundBackPackView') .appendTo(this.view_); this.backPackView = backPackView; this.createBackPackView(backPackView); const resizeHandle = Entry.createElement('div') .addClass('entryPlaygroundResizeWorkspace', 'entryRemove') .bindOnClick(() => { this.mainWorkspace.blockMenu.toggleBlockMenu(); }) .appendTo(codeView); this.resizeHandle_ = resizeHandle; /** @type {!Element} */ this.codeView_ = codeView; Entry.addEventListener('run', () => { Entry.playground.curtainView_.removeClass('entryRemove'); }); Entry.addEventListener('stop', () => { Entry.playground.curtainView_.addClass('entryRemove'); }); this.applyTabOption(); } } /** * Generate default view. * default view is shown when object is not selected. * @param {!Element} defaultView * @return {Element} */ generateDefaultView(defaultView) { return defaultView; } /** * generate tab menus * @param {!Element} tabView * @return {Element} */ generateTabView(tabView) { const that = this; const tabList = Entry.createElement('ul').addClass('entryTabListWorkspace'); this.tabList_ = tabList; tabView.appendChild(tabList); this.tabViewElements = {}; const codeTab = Entry.createElement('li', 'entryCodeTab') .addClass('entryTabListItemWorkspace entryTabSelected') .bindOnClick(() => { Entry.do('playgroundChangeViewMode', 'code', that.selectedViewMode); }) .appendTo(tabList); codeTab.textContent = Lang.Workspace.tab_code; this.tabViewElements.code = codeTab; this._codeTab = codeTab; const pictureTab = Entry.createElement('li', 'entryPictureTab') .addClass('entryTabListItemWorkspace') .bindOnClick(() => { Entry.do('playgroundChangeViewMode', 'picture', that.selectedViewMode); }) .appendTo(tabList); pictureTab.textContent = Lang.Workspace.tab_picture; this.tabViewElements.picture = pictureTab; this.pictureTab = pictureTab; const textboxTab = Entry.createElement('li', 'entryTextboxTab') .addClass('entryTabListItemWorkspace entryRemove') .appendTo(tabList) .bindOnClick(() => { Entry.do('playgroundChangeViewMode', 'text', that.selectedViewMode); }); textboxTab.textContent = Lang.Workspace.tab_text; this.tabViewElements.text = textboxTab; this.textboxTab = textboxTab; const soundTab = Entry.createElement('li', 'entrySoundTab') .addClass('entryTabListItemWorkspace') .appendTo(tabList) .bindOnClick(() => { Entry.do('playgroundChangeViewMode', 'sound', that.selectedViewMode); }); soundTab.textContent = Lang.Workspace.tab_sound; this.tabViewElements.sound = soundTab; this.soundTab = soundTab; const variableTab = Entry.createElement('li', 'entryVariableTab') .addClass('entryTabListItemWorkspace entryVariableTabWorkspace') .appendTo(tabList) .bindOnClick(() => { Entry.do('playgroundChangeViewMode', 'variable', that.selectedViewMode); }); variableTab.textContent = Lang.Workspace.tab_attribute; this.tabViewElements.variable = variableTab; this.variableTab = variableTab; } createButtonTabView(tabButtonView) { const { options = {} } = Entry; const { commentDisable, backpackDisable } = options; if (!commentDisable) { const commentToggleButton = Entry.createElement('div') .addClass('entryPlaygroundCommentButtonWorkspace showComment enabled') .appendTo(tabButtonView); commentToggleButton.setAttribute('alt', Lang.Blocks.show_all_comment); commentToggleButton.setAttribute('title', Lang.Blocks.show_all_comment); this.commentToggleButton_ = commentToggleButton; commentToggleButton.bindOnClick(() => { this.toggleCommentButton(); }); const addCommentButton = Entry.createElement('div') .addClass('entryPlaygroundCommentButtonWorkspace addComment enabled') .appendTo(tabButtonView); addCommentButton.setAttribute('alt', Lang.Blocks.add_comment); addCommentButton.setAttribute('title', Lang.Blocks.add_comment); this.addCommentButton_ = addCommentButton; addCommentButton.bindOnClick(() => { this.addComment(); }); } // TODO: 백팩(나의보관함) 숨김처리 if (!backpackDisable) { const backPackButton = Entry.createElement('div') .addClass('entryPlaygroundBackPackButtonWorkspace') .appendTo(tabButtonView); backPackButton.setAttribute('alt', Lang.Workspace.my_storage); backPackButton.setAttribute('title', Lang.Workspace.my_storage); this.backPackButton_ = backPackButton; backPackButton.bindOnClick(() => { Entry.dispatchEvent('openBackPack'); }); } } createBackPackView(backPackView) { this.backPack = new Backpack({ isShow: false, data: { items: [], onClose: () => { Entry.dispatchEvent('closeBackPack'); }, onRemoveItem: (id) => { Entry.dispatchEvent('removeBackPackItem', id); }, onChangeTitle: (id, title) => { Entry.dispatchEvent('changeBackPackTitle', id, title); }, onCustomDragEnter: ({ type, value, onDragEnter }) => { if (Entry.GlobalSvg.isShow && Entry.GlobalSvg.canAddStorageBlock) { const { _view = {} } = Entry.GlobalSvg; onDragEnter({ type: 'block', value: _view, }); } else if (Entry.container.isObjectDragging) { onDragEnter({ type: 'object', value: Entry.container.dragObjectKey, }); } }, onDropItem: ({ type, value }) => { if (type === 'object') { const object = Entry.container.getObject(value); object.addStorage(); } else if (type === 'block') { if (value.addStorage) { value.addStorage(); } } }, }, container: this.backPackView, }); this.blockBackPackArea = Entry.Dom('div') .addClass('blockBackPackDrop') .appendTo(backPackView); this.objectBackPackArea = Entry.Dom('div') .addClass('objectBackPackDrop') .appendTo(backPackView); const icon = Entry.Dom('div', { class: 'blockBackPackIcon', }); const desc = Entry.Dom('div', { class: 'blockBackPackDesc', text: Lang.Workspace.playground_block_drop, }); const desc2 = Entry.Dom('div', { class: 'objectBackPackDesc', text: Lang.Workspace.container_object_drop, }); this.blockBackPackArea.append(icon); this.blockBackPackArea.append(desc); this.objectBackPackArea.append(icon.clone()); this.objectBackPackArea.append(desc2); const { view: blockView } = this.board || {}; if (blockView) { const dom = blockView[0]; const eventDom = new EntryEvent(dom); this.blockBackPackEvent = eventDom; const areaDom = new EntryEvent(this.blockBackPackArea[0]); this.blockBackPackAreaEvent = areaDom; areaDom.on('dropitem', (e) => { const data = this.backPack.getData('data'); Entry.dispatchEvent('addBackPackToEntry', 'block', data); this.blockBackPackArea.css({ display: 'none', }); }); eventDom.on('enteritem', () => { const isDragging = this.backPack.getData('isDragging'); const type = this.backPack.getData('dragType'); if (isDragging && type === 'block') { const { width, height, top, left } = blockView[0].getBoundingClientRect(); this.blockBackPackArea.css({ width: width - 134, height, top, left, display: 'flex', }); } }); areaDom.on('leaveitem', (e) => { this.blockBackPackArea.css({ display: 'none', }); }); } const { modes = {} } = Entry.propertyPanel || {}; const { object = {} } = modes; const { contentDom: objectView } = object; if (objectView) { const dom = objectView[0]; const eventDom = new EntryEvent(dom); this.objectBackPackEvent = eventDom; const areaDom = new EntryEvent(this.objectBackPackArea[0]); this.objectBackPackAreaEvent = areaDom; areaDom.on('dropitem', (e) => { const data = this.backPack.getData('data'); Entry.dispatchEvent('addBackPackToEntry', 'object', data); this.objectBackPackArea.css({ display: 'none', }); }); eventDom.on('enteritem', () => { const isDragging = this.backPack.getData('isDragging'); const type = this.backPack.getData('dragType'); if (isDragging && type === 'object') { const { width, height, top, left } = objectView[0].getBoundingClientRect(); this.objectBackPackArea.css({ width, height, top, left, display: 'flex', }); } }); areaDom.on('leaveitem', (e) => { this.objectBackPackArea.css({ display: 'none', }); }); } const globalEvent = new EntryEvent(document); globalEvent.data = {}; this.globalEvent = globalEvent; this.backPack.on('onChangeDragging', (isDragging) => { if (isDragging) { globalEvent.off().on( 'touchmove.itemdrag mousemove.itemdrag', (e) => { const isDragging = this.backPack.getData('isDragging'); if (isDragging) { const point = Entry.Utils.getPosition(e); const { data } = globalEvent; const { dom: objectDom } = this.objectBackPackEvent; const { dom: blockDom } = this.blockBackPackEvent; const objectRect = this.getBoundingClientRectMemo(objectDom); const blockRect = this.getBoundingClientRectMemo(blockDom, { width: -134, right: -134, }); if ( !data.isObjectMouseEnter && Entry.Utils.isPointInRect(point, objectRect) ) { data.isObjectMouseEnter = true; this.objectBackPackEvent.trigger('enteritem'); } else if ( data.isObjectMouseEnter && !Entry.Utils.isPointInRect(point, objectRect) ) { data.isObjectMouseEnter = false; this.objectBackPackAreaEvent.trigger('leaveitem'); } if (Entry.getMainWS().mode === Entry.Workspace.MODE_BOARD) { if ( !data.isBlockMouseEnter && Entry.Utils.isPointInRect(point, blockRect) ) { data.isBlockMouseEnter = true; this.blockBackPackEvent.trigger('enteritem'); } else if ( data.isBlockMouseEnter && !Entry.Utils.isPointInRect(point, blockRect) ) { data.isBlockMouseEnter = false; this.blockBackPackAreaEvent.trigger('leaveitem'); } } } else { this.objectBackPackAreaEvent.trigger('leaveitem'); this.blockBackPackAreaEvent.trigger('leaveitem'); } }, { passive: false } ); } else { globalEvent.off(); } }); this.backPack.data = { draggableOption: { lockAxis: 'y', distance: 30, onDropItem: (e) => { const { data } = globalEvent; if (data.isObjectMouseEnter) { data.isObjectMouseEnter = false; this.objectBackPackAreaEvent.trigger('dropitem'); } else if (data.isBlockMouseEnter) { data.isBlockMouseEnter = false; this.blockBackPackAreaEvent.trigger('dropitem'); } }, }, }; } setBackpackPointEvent(canPointEvent) { this.backPack.data = { canPointEvent, }; } getBoundingClientRectMemo = _.memoize((target, offset = {}) => { const rect = target.getBoundingClientRect(); const result = { top: rect.top, bottom: rect.bottom, left: rect.left, right: rect.right, }; Object.keys(offset).forEach((key) => { result[key] += offset[key]; }); return result; }); clearClientRectMemo() { this.getBoundingClientRectMemo.cache = new _.memoize.Cache(); } showBackPack(args) { this.backPack.setData({ ...args }); this.backPack.show(); this.backPackView.removeClass('entryRemove'); } hideBackPack() { this.backPack.hide(); this.backPackView.addClass('entryRemove'); } toggleCommentButton() { if (this.board.isVisibleComment) { this.toast.show(Lang.Blocks.hide_all_comment); Entry.do('hideAllComment', this.board); } else { this.toast.show(Lang.Blocks.show_all_comment); Entry.do('showAllComment', this.board); } this.toggleCommentButtonVisible(); } addComment() { if (!Entry.options.commentDisable && this.board) { const { svg, scale } = this.board; const boardCenterX = svg.clientWidth / 2 / scale; const boardCenterY = svg.clientHeight / 2 / scale; Entry.do( 'createComment', { id: Entry.Utils.generateId(), x: Math.max(boardCenterX - 80, 0), y: Math.max(boardCenterY - 80, 0), }, this.board ); } } toggleCommentButtonVisible() { const button = this.commentToggleButton_; const addButton = this.addCommentButton_; if (this.board.isVisibleComment) { addButton.addClass('enabled'); button.addClass('enabled'); button.setAttribute('alt', Lang.Blocks.show_all_comment); button.setAttribute('title', Lang.Blocks.show_all_comment); } else { addButton.removeClass('enabled'); button.removeClass('enabled'); button.setAttribute('alt', Lang.Blocks.hide_all_comment); button.setAttribute('title', Lang.Blocks.hide_all_comment); } } /** * Inject and generate code view * @param {!Element} codeView * @return {Element} */ generateCodeView(codeView) { const variableView = this.createVariableView(); codeView.appendChild(variableView); this.variableView_ = variableView; codeView = Entry.Dom(codeView); const boardView = Entry.Dom('div', { parent: codeView, id: 'entryWorkspaceBoard', class: 'entryWorkspaceBoard', }); this.boardView_ = boardView; const blockMenuView = Entry.Dom('div', { parent: codeView, id: 'entryWorkspaceBlockMenu', class: 'entryWorkspaceBlockMenu', }); const initOpts = { blockMenu: { dom: blockMenuView, align: 'LEFT', categoryData: EntryStatic.getAllBlocks(), scroll: true, }, board: { dom: boardView, }, readOnly: Entry.readOnly, }; if (Entry.textCodingEnable) { initOpts.vimBoard = { dom: boardView }; } this.mainWorkspace = new Entry.Workspace(initOpts); this.blockMenu = this.mainWorkspace.blockMenu; this.board = this.mainWorkspace.board; this.toast = new Toast(this.board); this.blockMenu.banClass('checker'); Entry.Func?.initBlock(this.blockMenu); Entry.expansion?.banAllExpansionBlock(); Entry.aiUtilize?.banAllAIUtilizeBlock(); DataTable?.banAllBlock(); Entry.aiLearning?.banBlocks(); this.vimBoard = this.mainWorkspace.vimBoard; this._destroyer.add(this.mainWorkspace); this._destroyer.add(this.toast); if (Entry.hw) { Entry.hw.refreshHardwareBlockMenu(); } if (Entry.hwLite) { Entry.hwLite.refreshHardwareLiteBlockMenu(); } if (Entry.options.expansionDisable) { Entry.playground.blockMenu.banCategory('expansion'); } if (Entry.options.aiUtilizeDisable) { Entry.playground.blockMenu.banCategory('ai_utilize'); } } /** * Generate picture view. * @param {!Element} pictureView * @return {Element} */ generatePictureView(PictureView) { if (Entry.type === 'workspace') { const pictureAdd = Entry.createElement('div', 'entryAddPicture') .addClass('entryPlaygroundAddPicture') .appendTo(PictureView); const innerPictureAdd = Entry.createElement('div', 'entryAddPictureInner') .addClass('entryPlaygroundAddPictureInner') .bindOnClick(() => { if (!Entry.container || Entry.container.isSceneObjectsExist()) { Entry.do('playgroundClickAddPicture'); } else { Entry.toast.alert( Lang.Workspace.add_object_alert, Lang.Workspace.add_object_alert_msg ); } }) .appendTo(pictureAdd); innerPictureAdd.textContent = Lang.Workspace.picture_add; this._pictureAddButton = innerPictureAdd; const innerDrawNewPicture = Entry.createElement('div', 'entryNewPictureInner') .addClass('entryPlaygroundNewPictureInner') .bindOnClick(() => { this.painter.newPicture(); }) .appendTo(pictureAdd); innerDrawNewPicture.textContent = Lang.Workspace.draw_new; this._drawNewPictureButton = innerDrawNewPicture; this.pictureListView_ = Entry.createElement('ul', 'entryPictureList') .addClass('entryPlaygroundPictureList') .appendTo(PictureView); const painterDom = Entry.createElement('div', 'entryPainter') .addClass('entryPlaygroundPainter') .appendTo(PictureView); switch (Entry.paintMode) { case 'entry-paint': this.painter = new Entry.Painter(painterDom); break; case 'literallycanvas': this.painter = new Entry.LiterallycanvasPainter(painterDom); break; } } } initSortablePictureWidget() { if (this.pictureSortableListWidget) { return; } this.pictureSortableListWidget = new Sortable({ data: { height: '100%', sortableTarget: ['entryPlaygroundPictureThumbnail'], lockAxis: 'y', items: this._getSortablePictureList(), }, container: this.pictureListView_, }).on('change', ([newIndex, oldIndex]) => { Entry.playground.movePicture(newIndex, oldIndex); }); } updatePictureView() { if (this.pictureSortableListWidget) { this.pictureSortableListWidget.setData({ items: [] }); this.pictureSortableListWidget.setData({ items: this._getSortablePictureList(), }); } this.reloadPlayground(); } _getSortablePictureList() { if (!this.object || !this.object.pictures) { return []; } const id = this.object.id; return this.object.pictures.map((value) => ({ key: `${id}-${value.id}`, item: value.view, })); } /** * Generate text view. * @param {!Element} textView * @return {Element} */ generateTextView(textView) { const that = this; const wrap = Entry.createElement('div').addClass('write_box').appendTo(textView); const writeSet = Entry.createElement('div').addClass('write_set'); const inputArea = Entry.createElement('div').addClass('input_box'); wrap.appendChild(writeSet); wrap.appendChild(inputArea); //write set 글 속성 탭 const fontSelect = Entry.createElement('div').addClass('pop_selectbox'); const fontLink = Entry.createElement('a', 'entryTextBoxAttrFontName').addClass( 'select_link imico_pop_select_arr_down' ); fontLink.bindOnClick(() => { const options = EntryStatic.fonts .filter((font) => font.visible) .map((font) => [font.name, font, font.style]); fontLink.addClass('imico_pop_select_arr_up'); fontLink.removeClass('imico_pop_select_arr_down'); this.openDropDown( options, fontLink, (value) => { let font = value[1]; let textValue = textEditInput.value; if (that.object.entity.getLineBreak()) { textValue = textEditArea.value; } const { options = {} } = Entry; const { textOptions = {} } = options; const { hanjaEnable } = textOptions; if (!hanjaEnable) { if (/[\u4E00-\u9FFF]/.exec(textValue) != null) { font = options[0][1]; Entry.modal.alert(Lang.Menus.not_supported_text); } } fontLink.innerText = font.name; this.textEditArea.style.fontFamily = font.family; this.textEditInput.style.fontFamily = font.family; $('#entryTextBoxAttrFontName').data('font', font); this.object.entity.setFontType(font.family); }, () => { fontLink.removeClass('imico_pop_select_arr_up'); fontLink.addClass('imico_pop_select_arr_down'); } ); }); fontSelect.appendChild(fontLink); writeSet.appendChild(fontSelect); //스타일 박스 const alignBox = Entry.createElement('div').addClass('font_style_box'); writeSet.appendChild(alignBox); const alignLeft = Entry.createElement('a') .addClass('style_link imbtn_pop_font_align_left') .bindOnClick(() => { Entry.playground.setFontAlign(Entry.TEXT_ALIGN_LEFT); }); alignLeft.setAttribute('title', Lang.Workspace.align_left); alignBox.appendChild(alignLeft); this.alignLeftBtn = alignLeft; const alignMiddle = Entry.createElement('a') .addClass('style_link imbtn_pop_font_align_middle') .bindOnClick(() => { Entry.playground.setFontAlign(Entry.TEXT_ALIGN_CENTER); }); alignMiddle.setAttribute('title', Lang.Workspace.align_center); alignBox.appendChild(alignMiddle); this.alignCenterBtn = alignMiddle; const alignRight = Entry.createElement('a') .addClass('style_link imbtn_pop_font_align_right') .bindOnClick(() => { Entry.playground.setFontAlign(Entry.TEXT_ALIGN_RIGHT); }); alignRight.setAttribute('title', Lang.Workspace.align_right); alignBox.appendChild(alignRight); this.alignRightBtn = alignRight; const styleBox = Entry.createElement('div').addClass('font_style_box'); writeSet.appendChild(styleBox); const bold = Entry.createElement('a') .addClass('style_link imbtn_pop_font_bold') .bindOnClick((e) => { $(e.currentTarget).toggleClass('on'); Entry.playground.object.entity.toggleFontBold(); $(this.textEditArea).toggleClass('bold'); $(this.textEditInput).toggleClass('bold'); }); bold.setAttribute('title', Lang.Workspace.bold); styleBox.appendChild(bold); const underLine = Entry.createElement('a') .addClass('style_link imbtn_pop_font_underline') .bindOnClick((e) => { const underLineState = !Entry.playground.object.entity.getUnderLine() || false; $(e.currentTarget).toggleClass('on'); Entry.playground.object.entity.setUnderLine(underLineState); const effect = `${underLineState ? 'underline' : ''} ${ Entry.playground.object.entity.getStrike() ? 'line-through' : '' }`.trim(); this.textEditArea.style.textDecoration = effect; this.textEditInput.style.textDecoration = effect; }); underLine.setAttribute('title', Lang.Workspace.font_underline); styleBox.appendChild(underLine); const italic = Entry.createElement('a') .addClass('style_link imbtn_pop_font_italic') .bindOnClick((e) => { $(e.currentTarget).toggleClass('on'); Entry.playground.object.entity.toggleFontItalic(); $(this.textEditArea).toggleClass('italic'); $(this.textEditInput).toggleClass('italic'); }); italic.setAttribute('title', Lang.Workspace.font_tilt); styleBox.appendChild(italic); const through = Entry.createElement('a') .addClass('style_link imbtn_pop_font_through') .bindOnClick((e) => { $(e.currentTarget).toggleClass('on'); const strikeState = !Entry.playground.object.entity.getStrike() || false; Entry.playground.object.entity.setStrike(strikeState); const effect = `${strikeState ? 'line-through' : ''} ${ Entry.playground.object.entity.getUnderLine() ? 'underline' : '' }`.trim(); this.textEditArea.style.textDecoration = effect; this.textEditInput.style.textDecoration = effect; }); through.setAttribute('title', Lang.Workspace.font_cancel); styleBox.appendChild(through); const color = Entry.createElement('a').addClass('imbtn_pop_font_color'); color.appendChild(Entry.createElement('em')); color.bindOnClick(() => this.openColourPicker( color, this.object.entity.getColour(), false, this.setTextColour.bind(this) ) ); color.setAttribute('title', Lang.Workspace.font_color); styleBox.appendChild(color); const backgroundColor = Entry.createElement('a').addClass('imbtn_pop_font_backgroundcolor'); backgroundColor.setAttribute('title', Lang.Workspace.font_fill); backgroundColor.appendChild(Entry.createElement('em')); backgroundColor.bindOnClick(() => this.openColourPicker( backgroundColor, this.object.entity.getBGColour(), true, this.setBackgroundColour.bind(this) ) ); styleBox.appendChild(backgroundColor); const writeTypeBox = Entry.createElement('div').addClass('write_type_box'); const singleLine = Entry.createElement('a'); singleLine.innerText = Lang.Buttons.single_line; singleLine.bindOnClick(() => Entry.playground.toggleLineBreak(false)); const multiLine = Entry.createElement('a'); multiLine.innerText = Lang.Buttons.multi_line; multiLine.bindOnClick(() => Entry.playground.toggleLineBreak(true)); writeTypeBox.appendChild(singleLine); writeTypeBox.appendChild(multiLine); inputArea.appendChild(writeTypeBox); //글자 크기 조절 슬라이드. const fontSizeWrapper = Entry.createElement('div').addClass( 'entryPlaygroundFontSizeWrapper multi' ); inputArea.appendChild(fontSizeWrapper); this.fontSizeWrapper = fontSizeWrapper; const fontSizeLabel = Entry.createElement('div').addClass('entryPlaygroundFontSizeLabel'); fontSizeLabel.textContent = Lang.General.font_size; fontSizeWrapper.appendChild(fontSizeLabel); const fontSizeSlider = Entry.createElement('div').addClass('entryPlaygroundFontSizeSlider'); fontSizeWrapper.appendChild(fontSizeSlider); const fontSizeIndiciator = Entry.createElement('div').addClass( 'entryPlaygroundFontSizeIndicator' ); fontSizeSlider.appendChild(fontSizeIndiciator); this.fontSizeIndiciator = fontSizeIndiciator; const fontSizeKnob = Entry.createElement('div').addClass('entryPlaygroundFontSizeKnob'); fontSizeSlider.appendChild(fontSizeKnob); this.fontSizeKnob = fontSizeKnob; $(fontSizeKnob).bind('mousedown.fontKnob touchstart.fontKnob', () => { const resizeOffset = $(fontSizeSlider).offset().left; const doc = $(document); doc.bind('mousemove.fontKnob touchmove.fontKnob', onMouseMove); doc.bind('mouseup.fontKnob touchend.fontKnob', onMouseUp); function onMouseMove(e) { let x = e.pageX; if (!x) { x = e.originalEvent.touches[0].pageX; } let left = x - resizeOffset; left = Math.max(left, 5); left = Math.min(left, 136); fontSizeKnob.style.left = `${left}px`; left /= 1.36; fontSizeIndiciator.style.width = `${left}%`; Entry.playground.object.entity.setFontSize(left); } function onMouseUp() { $(document).unbind('.fontKnob'); } }); const inputInner = Entry.createElement('div').addClass('input_inner'); inputArea.appendChild(inputInner); const textEditInput = Entry.createElement('input').addClass( 'entryPlayground_textBox single' ); textEditInput.type = 'text'; textEditInput.placeholder = Lang.Workspace.textbox_input; const textChangeApply = function () { const object = Entry.playground.object; const entity = object.entity; const selected = $('#entryTextBoxAttrFontName').data('font'); const defaultFont = EntryStatic.fonts[0]; const { options = {} } = Entry; const { textOptions = {} } = options; const { hanjaEnable } = textOptions; if ( !hanjaEnable && (selected.family === 'Nanum Pen Script' || selected.family === 'Jeju Hallasan') ) { if (/[\u4E00-\u9FFF]/.exec(this.value) != null) { $('#entryTextBoxAttrFontName').text(defaultFont.name); entity.setFontType(defaultFont.family); Entry.modal.alert(Lang.Menus.not_supported_text); } } object.setText(this.value); entity.setText(this.value); }; textEditInput.onkeyup = textChangeApply; textEditInput.onchange = textChangeApply; textEditInput.addEventListener('focusin', () => { textEditInput.prevText = textEditInput.value; }); textEditInput.onblur = function () { if (textEditInput.value !== textEditInput.prevText) { Entry.do('editText', textEditInput.value, textEditInput.prevText); } // Entry.dispatchEvent('textEdited'); }; this.textEditInput = textEditInput; inputInner.appendChild(textEditInput); const textEditArea = Entry.createElement('textarea'); textEditArea.placeholder = Lang.Workspace.textbox_input; textEditArea.addClass('entryPlayground_textArea multi'); textEditArea.style.display = 'none'; textEditArea.onkeyup = textChangeApply; textEditArea.onchange = textChangeApply; textEditArea.addEventListener('focusin', () => { textEditArea.prevText = textEditArea.value; }); textEditArea.onblur = function () { if (textEditArea.value !== textEditArea.prevText) { Entry.do('editText', textEditArea.value, textEditArea.prevText); } }; this.textEditArea = textEditArea; inputInner.appendChild(textEditArea); const singleDesc = Entry.createElement('ul').addClass('list single'); singleDesc.appendChild(Entry.createElement('li').text(Lang.Menus.linebreak_off_desc_1)); singleDesc.appendChild(Entry.createElement('li').text(Lang.Menus.linebreak_off_desc_2)); singleDesc.appendChild(Entry.createElement('li').text(Lang.Menus.linebreak_off_desc_3)); const multiDesc = Entry.createElement('ul').addClass('list multi'); multiDesc.appendChild(Entry.createElement('li').text(Lang.Menus.linebreak_on_desc_1)); multiDesc.appendChild(Entry.createElement('li').text(Lang.Menus.linebreak_on_desc_2)); multiDesc.appendChild(Entry.createElement('li').text(Lang.Menus.linebreak_on_desc_3)); inputArea.appendChild(singleDesc); inputArea.appendChild(multiDesc); } /** * 소리 편집 기능 신규 개발시 해당 로직 삭제 * @private */ _createSoundEditView() { const soundEditView = Entry.createElement('div', 'entrySoundEdit').addClass( 'entryPlaygroundSoundEdit' ); return soundEditView; } /** * Generate sound view. * default view is shown when object is not selected. * @return {Element} * @param soundView */ generateSoundView(soundView) { if (Entry.type === 'workspace') { const soundAdd = Entry.createElement('div', 'entryAddSound'); soundAdd.addClass('entryPlaygroundAddSound'); const innerSoundAdd = Entry.createElement('div', 'entryAddSoundInner').addClass( 'entryPlaygroundAddSoundInner' ); innerSoundAdd.bindOnClick(() => { if (!Entry.container || Entry.container.isSceneObjectsExist()) { Entry.do('playgroundClickAddSound'); } else { Entry.toast.alert( Lang.Workspace.add_object_alert, Lang.Workspace.add_object_alert_msg ); } }); innerSoundAdd.textContent = Lang.Workspace.sound_add; soundAdd.appendChild(innerSoundAdd); soundView.appendChild(soundAdd); const soundList = Entry.createElement('ul', 'entrySoundList').addClass( 'entryPlaygroundSoundList' ); soundView.appendChild(soundList); this.soundListView_ = soundList; this._soundAddButton = innerSoundAdd; const soundEditView = this._createSoundEditView(); soundView.appendChild(soundEditView); this.soundEditor = new SoundEditor(soundEditView); } } initSortableSoundWidget() { if (this.soundSortableListWidget) { return; } this.soundSortableListWidget = new Sortable({ data: { height: '100%', sortableTarget: ['entryPlaygroundSoundThumbnail'], lockAxis: 'y', items: this._getSortableSoundList(), }, container: this.soundListView_, }).on('change', ([newIndex, oldIndex]) => { Entry.playground.moveSound(newIndex, oldIndex); }); } updateSoundsView() { if (this.soundSortableListWidget) { this.soundSortableListWidget.setData({ items: this._getSortableSoundList(), }); } this.reloadPlayground(); } _getSortableSoundList() { if (!this.object || !this.object.sounds) { return []; } const id = this.object.id; return this.object.sounds.map((value) => ({ key: `${id}-${value.id}`, item: value.view, })); } /** * Inject object * @param {?Entry.EntryObject} object */ injectObject(object) { /** @type {Entry.Entryobject} */ if (!object) { this.object = null; //[박봉배-2018.11.12] - 아래 위치에 있으면 죽은 object의 메서드를 호출함. 그래서 위로 올림. this.changeViewMode('code'); return; } if (object === this.object) { return; } this.object = object; const objectType = object.objectType; this.setMenu(objectType); this.injectCode(); const { text: textTab, picture: pictureTab } = this.tabViewElements; if (objectType === 'sprite' && Entry.pictureEditable) { if (textTab) { textTab.addClass('entryRemove'); } if (pictureTab) { pictureTab.removeClass('entryRemove'); } } else if (objectType === 'textBox') { if (pictureTab) { pictureTab.addClass('entryRemove'); } if (textTab) { textTab.removeClass('entryRemove'); } } this.updateObjectTitle(object); const viewMode = this.viewMode_; if (viewMode === 'default') { this.changeViewMode('code'); } else if (viewMode === 'variable') { this.changeViewMode('variable'); } else if ((viewMode === 'picture' || viewMode === 'text') && objectType === 'textBox') { this.changeViewMode('text'); } else if ((viewMode === 'text' || viewMode === 'picture') && objectType === 'sprite') { this.changeViewMode('picture'); } else if (viewMode === 'sound') { this.changeViewMode('sound'); } _.result(this.blockMenu, 'clearRendered'); this.reloadPlayground(); } /** * Inject object * @param {?Entry.EntryObject} object */ injectEmptyObject() { this.object = null; } /** * Inject code */ injectCode() { const workspace = Entry.getMainWS(); if (!workspace) { return; } const object = this.object; const vimBoard = workspace.vimBoard; if (vimBoard && Entry.textCodingEnable && !vimBoard._parser._onError) { vimBoard._changedObject = object; vimBoard._currentScene = object.scene; } const board = workspace.getBoard(); const engine = Entry.engine; workspace.changeBoardCode( object.script, engine && engine.isState('run') ? undefined : board.adjustThreadsPosition.bind(board) ); } /** * Inject picture */ injectPicture(isSelect = true) { const view = this.pictureListView_; if (!view) { return; } if (!this.object) { this.painter.lc && this.painter.lc.pointerDown(); delete Entry.stage.selectedObject; Entry.dispatchEvent('pictureSelected'); } else { (this.object.pictures || []).forEach((picture, i) => { !picture.view && Entry.playground.generatePictureElement(picture); const element = picture.view; element.orderHolder.textContent = i + 1; }); isSelect && this.selectPicture(this.object.selectedPicture); } this.updatePictureView(); } /** * Add picture * @param {picture model} picture */ addPicture(picture, isNew, isSelect = true) { const tempPicture = _.clone(picture); if (isNew === true) { delete tempPicture.id; } delete tempPicture.view; picture = Entry.Utils.copy(tempPicture); if (!picture.id) { picture.id = Entry.generateHash(); } picture.name = Entry.getOrderedName(picture.name, this.object.pictures); this.generatePictureElement(picture); Entry.do('objectAddPicture', picture.objectId || this.object.id, picture, isSelect); } /** * set picture * @param {picture} */ setPicture(picture) { const element = Entry.container.getPictureElement(picture.id, picture.objectId); const $element = $(element); if (element) { picture.view = element; element.picture = picture; const thumbnailView = $element.find(`#t_${picture.id}`)[0]; if (picture.thumbUrl || picture.fileurl) { thumbnailView.style.backgroundImage = `url("${picture.thumbUrl || picture.fileurl}")`; } else { // deprecated const fileName = picture.filename; thumbnailView.style.backgroundImage = `url("${ Entry.defaultPath }/uploads/${fileName.substring(0, 2)}/${fileName.substring( 2, 4 )}/thumb/${fileName}.png")`; } const sizeView = $element.find(`#s_${picture.id}`)[0]; sizeView.textContent = `${picture.dimension.width} X ${picture.dimension.height}`; } Entry.container.setPicture(picture); // Entry.playground.object.setPicture(picture); } /** * Download a picture * @param {!String} pictureId */ downloadPicture(pictureId) { const picture = Entry.playground.object.getPicture(pictureId); const { imageType = 'png' } = picture; Entry.dispatchEvent('downloadPicture', picture); } /** * Clone picture * @param {!String} pictureId */ clonePicture(pictureId) { const sourcePicture = Entry.playground.object.getPicture(pictureId); this.addPicture(sourcePicture, true); } /** * Select picture * @param {picture} */ selectPicture(picture, removed) { const pictures = this.object.pictures; for (let i = 0, len = pictures.length; i < len; i++) { const target = pictures[i]; const view = target.view; if (target.id === picture.id) { view.addClass('entryPictureSelected'); } else { view.removeClass('entryPictureSelected'); } } let objectId_; if (picture && picture.id) { objectId_ = Entry.container.selectPicture(picture.id, picture.objectId); } if (this.object.id === objectId_) { if (!picture.objectId) { picture.objectId = this.object.id; } Entry.dispatchEvent('pictureSelected', picture, removed); } this.updateObjectTitle(this.object); } /** * Move picture in this.object.pictures * this method is for sortable * @param {!number} start * @param {!number} end */ movePicture(start, end) { this.object.pictures.splice(end, 0, this.object.pictures.splice(start, 1)[0]); this.injectPicture(); } /** * Inject text */ injectText() { const object = this.object; if (!object) { return; } const entity = object.entity; const text = entity.getText(); this.textEditInput.value = text; this.textEditArea.value = text; const font = EntryStatic.fonts .filter((font) => font.visible) .find((font) => font.family === entity.getFontName()); if (font) { $('#entryText #entryTextBoxAttrFontName').text(font.name); $('#entryText #entryTextBoxAttrFontName').data('font', font); this.textEditInput.style.fontFamily = font.family; this.textEditArea.style.fontFamily = font.family; } else { $('#entryText #entryTextBoxAttrFontName').text(''); $('#entryText #entryTextBoxAttrFontName').data('font', EntryStatic.fonts[0]); } if (entity.colour) { this.setTextColour(entity.colour, true); } if (entity.bgColor) { this.setBackgroundColour(entity.bgColor, true); } this.setTextBold(entity.fontBold); this.setTextItalic(entity.fontItalic); this.setTextDecoration(entity); this.toggleLineBreak(entity.getLineBreak()); if (entity.getLineBreak()) { const LANG = Lang.Menus; $('.entryPlaygroundLinebreakDescription > p').html(LANG.linebreak_on_desc_1); const pDoms = $('.entryPlaygroundLinebreakDescription > ul > li'); pDoms.eq(0).text(LANG.linebreak_on_desc_2); pDoms.eq(1).text(LANG.linebreak_on_desc_3); this._setFontFontUI(); } this.setFontAlign(entity.getTextAlign()); Entry.stage.updateForce(); } _setFontFontUI() { const fontSize = this.object.entity.getFontSize(); this.fontSizeIndiciator.style.width = `${fontSize}%`; this.fontSizeKnob.style.left = `${fontSize * 1.36}px`; } /** * Inject sound */ injectSound(isSelect = true) { const view = this.soundListView_; if (!view) { return; } if (!this.object) { delete Entry.stage.selectedObject; } else { (this.object.sounds || []).forEach((sound, i) => { const soundLengthView = _get(sound, 'view.soundLengthView'); if (soundLengthView) { soundLengthView.textContent = `${sound.duration} ${Lang.General.second}`; } else { Entry.playground.generateSoundElement(sound); } const element = sound.view; element.orderHolder.textContent = i + 1; }); if (isSelect) { if (this.object.selectedSound) { this.selectSound(this.object.selectedSound); } else { this.unselectSound(); } } } this.updateSoundsView(); } /** * Move sound in this.object.sounds * this method is for sortable * @param {!number} start * @param {!number} end */ moveSound(start, end) { if (this.object.sounds) { this.object.sounds.splice(end, 0, this.object.sounds.splice(start, 1)[0]); this.injectSound(); } } addHardwareLiteModule(module) { Entry.hwLite.addHardwareLiteModule(module); } removeHardwareLiteModule() { Entry.hwLite.removeHardwareLiteModule(); } addExpansionBlocks(items) { Entry.expansion.addExpansionBlocks(items.map(({ name }) => name)); } removeExpansionBlocks(items) { Entry.expansion.banExpansionBlocks(items.map(({ name }) => name)); } addAIUtilizeBlocks(items) { Entry.aiUtilize.addAIUtilizeBlocks(items.map(({ name }) => name)); } removeAIUtilizeBlocks(items) { Entry.aiUtilize.banAIUtilizeBlocks(items.map(({ name }) => name)); } setAiLearningBlock(data) { Entry.aiLearning.removeLearningBlocks(); Entry.aiLearning.load({ ...data }); } /** * Add sound * @param {sound model} sound * @param {boolean} NotForView if this is true, add element into object also. */ addSound(sound, NotForView, isNew, isSelect = true) { const tempSound = _.clone(sound); delete tempSound.view; if (isNew === true) { delete tempSound.id; } sound = Entry.Utils.copy(tempSound); if (!sound.id) { sound.id = Entry.generateHash(); } sound.name = Entry.getOrderedName(sound.name, this.object.sounds); this.generateSoundElement(sound); Entry.do('objectAddSound', sound.objectId || this.object.id, sound, isSelect); } downloadSound(soundId) { const sound = Entry.playground.object.getSound(soundId); Entry.dispatchEvent('downloadSound', sound); } /** * select view mode * @param {string} viewType */ changeViewMode(viewType) { if (!this.tabViewElements) { return; } for (const i in this.tabViewElements) { this.tabViewElements[i].removeClass('entryTabSelected'); } if (viewType !== 'default') { this.tabViewElements[viewType].addClass('entryTabSelected'); } if (viewType === 'variable') { Entry.playground.toggleOnVariableView(); this.tabViewElements.code.removeClass('entryTabSelected'); this.tabViewElements[viewType].addClass('entryTabSelected'); this.resizeHandle_.removeClass('unfolding'); this.resizeHandle_.addClass('entryRemove'); this.boardView_.addClass('wideView'); Entry.windowResized.notify(); return; } else { this.resizeHandle_.removeClass('entryRemove'); this.boardView_.removeClass('wideView'); Entry.windowResized.notify(); } const views = this.view_.children; for (let i = 0; i < views.length; i++) { const view = views[i]; if (view.id.toUpperCase().indexOf(viewType.toUpperCase()) > -1) { view.removeClass('entryRemove'); } else { view.addClass('entryRemove'); } } if (Entry.pictureEditable) { if (viewType === 'picture') { this.painter.show(); this.initSortablePictureWidget(); if (!this.pictureView_.object || this.pictureView_.object != this.object) { this.pictureView_.object = this.object; this.injectPicture(); } else if ( this.object && this.pictureListView_ && !this.pictureListView_.hasChildNodes() ) { const pictures = this.object.pictures; if (pictures && pictures.length) { this.injectPicture(); } } } else { this.painter.hide(); } } if (Entry.soundEditable) { if (viewType === 'sound') { this.initSortableSoundWidget(); if (!this.soundView_.object || this.soundView_.object != this.object) { this.soundView_.object = this.object; this.injectSound(); } else if ( this.object && this.soundListView_ && !this.soundListView_.hasChildNodes() ) { const sounds = this.object.sounds; if (sounds && sounds.length) { this.injectSound(); } } } else { this.soundEditor.hide(); } } if ( (viewType === 'text' && this.object.objectType === 'textBox') || this.textView_.object != this.object ) { this.textView_.object = this.object; this.injectText(); } if (viewType === 'code') { this.resizeHandle_ && this.resizeHandle_.removeClass('entryRemove'); this.tabButtonView_ && this.tabButtonView_.addClass('entryCode'); this.blockMenu.reDraw(); } else { this.tabButtonView_ && this.tabButtonView_.removeClass('entryCode'); } if (Entry.engine.isState('run')) { this.curtainView_.removeClass('entryRemove'); } this.viewMode_ = viewType; this.selectedViewMode = viewType; this.toggleOffVariableView(); } /** * render variable view * @return {!Element} */ createVariableView() { const view = Entry.createElement('div'); if (!Entry.type || Entry.type === 'workspace') { view.addClass('entryVariablePanelWorkspace'); } else if (Entry.type === 'phone') { view.addClass('entryVariablePanelPhone'); } this.variableViewWrapper_ = view; Entry.variableContainer.createDom(view); return view; } /** * toggle on variable view */ toggleOnVariableView() { Entry.playground.changeViewMode('code'); this.hideBlockMenu(); this.variableView_.removeClass('entryRemove'); this.resizeHandle_.removeClass('entryRemove'); this.viewMode_ = 'variable'; this.selectedViewMode = 'variable'; } toggleOffVariableView() { this.showBlockMenu(); this.variableView_.addClass('entryRemove'); } /** * Generate category menu with object type. * @param {!string} objectType */ setMenu(objectType) { if (this.currentObjectType == objectType) { return; } const blockMenu = this.blockMenu; blockMenu.unbanClass(this.currentObjectType, true); blockMenu.banClass(objectType, true); blockMenu.setMenu(true); this.currentObjectType = objectType; } hideTabs() { ['picture', 'text', 'sound', 'variable'].forEach(this.hideTab.bind(this)); } hideTab(item) { if (this.tabViewElements[item]) { this.tabViewElements[item].addClass('hideTab'); this.tabViewElements[item].removeClass('showTab'); } } showTabs() { ['picture', 'text', 'sound', 'variable'].forEach(this.showTab.bind(this)); } showTab(item) { if (this.tabViewElements[item]) { this.tabViewElements[item].addClass('showTab'); this.tabViewElements[item].removeClass('hideTab'); } } /** * Reload playground */ reloadPlayground() { const engine = Entry.engine; if (engine && engine.isState('run')) { return; } _.result(this.mainWorkspace, 'dReDraw'); } /** * flush playground when object is not exist */ flushPlayground() { this.object = null; if (Entry.playground && Entry.playground.view_) { this.injectPicture(); this.injectSound(); const mainWS = Entry.getMainWS(); if (mainWS) { const board = mainWS.getBoard(); board.clear(); board.changeCode(null); } } } refreshPlayground() { if (Entry.playground && Entry.playground.view_) { if (this.getViewMode() === 'picture') { this.injectPicture(); } if (this.getViewMode() === 'sound') { this.injectSound(); } } } clear() { this.flushPlayground(); if (this.painter) { this.painter.clear(); } } nameViewBlur() { if (!Entry.playground.nameViewFocus) { return; } if (this.nameView.value.trim() === '') { Entry.modal.alert(Lang.Workspace.enter_the_name).then(() => { this.nameView.focus(); }); return true; } let nameViewArray = $('.entryPlaygroundPictureName'); if (nameViewArray.length !== Entry.playground.object.pictures.length) { nameViewArray = nameViewArray.slice(0, -1); // pop last element (드래그 시 발생하는 임시 엘리먼트임) } for (let i = 0; i < nameViewArray.length; i++) { if ( nameViewArray.eq(i).val() == this.nameView.value && nameViewArray[i] != this.nameView ) { Entry.modal.alert(Lang.Workspace.name_already_exists).then(() => { this.nameView.focus(); }); return true; } } const newValue = this.nameView.value; this.nameView.picture.name = newValue; const playground = Entry.playground; if (playground) { if (playground.object) { const pic = playground.object.getPicture(this.nameView.picture.id); if (pic) { pic.name = newValue; } } const painter = playground.painter; if (painter && painter.file) { painter.file.name = newValue; } playground.reloadPlayground(); } Entry.dispatchEvent('pictureNameChanged', this.nameView.picture); Entry.playground.nameViewFocus = false; } isDuplicatedTableName(name, selectedIndex = -1) { let nameViewArray = $('.entryPlaygroundTableName'); if (nameViewArray.length !== Entry.playground.dataTable.tables.length) { nameViewArray = nameViewArray.slice(0, -1); } for (let i = 0; i < nameViewArray.length; i++) { if (nameViewArray.eq(i).val() == name && i != selectedIndex) { return true; } } return false; } generatePictureElement(picture) { const element = Entry.createElement('li', picture.id) .addClass('entryPlaygroundPictureElement') .bindOnClick(function () { Entry.playground.selectPicture(this.picture); }); picture.view = element; element.picture = picture; Entry.Utils.disableContextmenu(picture.view); Entry.ContextMenu.onContextmenu(picture.view, (coordinate) => { const options = [ { text: Lang.Workspace.context_rename, callback() { nameView.focus(); }, }, { text: Lang.Workspace.context_duplicate, callback() { Entry.playground.clonePicture(picture.id); }, }, { text: Lang.Workspace.context_remove, callback() { Entry.playground._removePicture(picture, element); }, }, { text: Lang.Workspace.context_download_image, callback() { Entry.playground.downloadPicture(picture.id); }, }, ]; Entry.ContextMenu.show(options, 'workspace-contextmenu', coordinate); }); element.orderHolder = Entry.createElement('div') .addClass('entryPlaygroundPictureOrder') .appendTo(element); const thumbnailView = Entry.createElement('div', `t_${picture.id}`).addClass( 'entryPlaygroundPictureThumbnail' ); let mouseDownCoordinate; const moveThreshold = 5; thumbnailView.addEventListener('touchstart', (e) => { const event = Entry.Utils.convertMouseEvent(e); mouseDownCoordinate = { y: event.clientY }; }); thumbnailView.addEventListener('touchmove', (e) => { e.preventDefault(); const event = Entry.Utils.convertMouseEvent(e); if (Math.abs(event.clientY - mouseDownCoordinate.y) > moveThreshold) { Entry.ContextMenu.hide(); } }); if (picture.thumbUrl || picture.fileurl) { thumbnailView.style.backgroundImage = `url("${picture.thumbUrl || picture.fileurl}")`; } else { // deptecated const fileName = picture.filename; thumbnailView.style.backgroundImage = `url("${ Entry.defaultPath }/uploads/${fileName.substring(0, 2)}/${fileName.substring( 2, 4 )}/thumb/${fileName}.png")`; } element.appendChild(thumbnailView); const nameView = Entry.createElement('input') .addClass('entryPlaygroundPictureName') .addClass('entryEllipsis'); nameView.picture = picture; nameView.value = picture.name; Entry.attachEventListener(nameView, 'blur', this.nameViewBlur.bind(this)); Entry.attachEventListener(nameView, 'focus', (e) => { this.nameView = e.target; this.nameViewFocus = true; }); nameView.onkeypress = Entry.Utils.blurWhenEnter; element.appendChild(nameView); Entry.createElement('div', `s_${picture.id}`) .addClass('entryPlaygroundPictureSize') .appendTo(element).textContent = `${picture.dimension.width} X ${picture.dimension.height}`; const removeButton = Entry.createElement('div').addClass('entryPlayground_del'); const { Buttons = {} } = Lang || {}; const { delete: delText = '삭제' } = Buttons; removeButton.appendTo(element).innerText = delText; removeButton.bindOnClick((e) => { try { e.stopPropagation(); this._removePicture(picture, element); } catch (e) { Entry.toast.alert( Lang.Workspace.shape_remove_fail, Lang.Workspace.shape_remove_fail_msg ); } }); } _removePicture(picture, element) { if (Entry.playground.object.pictures.length > 1) { Entry.do('objectRemovePicture', picture.objectId, picture); Entry.removeElement(element); Entry.toast.success( Lang.Workspace.shape_remove_ok, `${picture.name} ${Lang.Workspace.shape_remove_ok_msg}` ); } else { Entry.toast.alert( Lang.Workspace.shape_remove_fail, Lang.Workspace.shape_remove_fail_msg ); } } generateSoundElement(sound) { const element = Entry.createElement('sound', sound.id).addClass( 'entryPlaygroundSoundElement' ); sound.view = element; element.sound = sound; Entry.Utils.disableContextmenu(sound.view); Entry.ContextMenu.onContextmenu(sound.view, (coordinate) => { const options = [ { text: Lang.Workspace.context_rename, callback() { nameView.focus(); }, }, { text: Lang.Workspace.context_duplicate, callback() { const newSound = Entry.playground.object.getSound(sound.id); Entry.playground.addSound(newSound, true, true); }, }, { text: Lang.Workspace.context_remove, callback() { const result = Entry.do( 'objectRemoveSound', Entry.playground.object.id, sound ); if (result) { Entry.removeElement(element); Entry.dispatchEvent('removeSound', sound); Entry.toast.success( Lang.Workspace.sound_remove_ok, `${sound.name} ${Lang.Workspace.sound_remove_ok_msg}` ); } else { Entry.toast.alert(Lang.Workspace.sound_remove_fail, ''); } Entry.removeElement(element); }, }, { text: Lang.Workspace.context_download_sound, callback() { Entry.playground.downloadSound(sound.id); }, }, ]; Entry.ContextMenu.show(options, 'workspace-contextmenu', coordinate); }); element.orderHolder = Entry.createElement('div') .addClass('entryPlaygroundSoundOrder') .appendTo(element); const thumbnailView = Entry.createElement('div') .addClass('entryPlaygroundSoundThumbnail entryPlaygroundSoundPlay') .appendTo(element); let isPlaying = false; let soundInstance; element.bindOnClick(() => { if (!this.object.sounds || !this.object.sounds.length) { return; } const isExist = this.object.sounds.some((os) => os.id === sound.id); if (isExist) { this.selectSound(sound); } }); let mouseDownCoordinate; const moveThreshold = 5; thumbnailView.addEventListener('touchstart', (e) => { const event = Entry.Utils.convertMouseEvent(e); mouseDownCoordinate = { y: event.clientY }; }); thumbnailView.addEventListener('touchmove', (e) => { e.preventDefault(); const event = Entry.Utils.convertMouseEvent(e); if (Math.abs(event.clientY - mouseDownCoordinate.y) > moveThreshold) { Entry.ContextMenu.hide(); } }); thumbnailView.bindOnClick(() => { this.selectSound(sound); if (isPlaying) { isPlaying = false; thumbnailView.removeClass('entryPlaygroundSoundStop'); thumbnailView.addClass('entryPlaygroundSoundPlay'); soundInstance.dispatchEvent('complete'); soundInstance.stop(); return; } else { isPlaying = true; thumbnailView.removeClass('entryPlaygroundSoundPlay'); thumbnailView.addClass('entryPlaygroundSoundStop'); soundInstance = Entry.Utils.playSound(sound.id); Entry.Utils.addSoundInstances(soundInstance); } soundInstance.addEventListener('complete', () => { thumbnailView.removeClass('entryPlaygroundSoundStop'); thumbnailView.addClass('entryPlaygroundSoundPlay'); isPlaying = false; }); }); const nameView = Entry.createElement('input') .addClass('entryPlaygroundSoundName') .appendTo(element); nameView.sound = sound; nameView.value = sound.name; Entry.attachEventListener(nameView, 'blur', nameViewBlur); function nameViewBlur() { if (this.value.trim() === '') { return Entry.modal.alert(Lang.Workspace.enter_the_name).then(() => { nameView.focus(); }); } let nameViewArray = $('.entryPlaygroundSoundName'); if (nameViewArray.length !== Entry.playground.object.sounds.length) { nameViewArray = nameViewArray.slice(0, -1); // pop last element (드래그 시 발생하는 임시 엘리먼트임) } for (let i = 0; i < nameViewArray.length; i++) { if (nameViewArray.eq(i).val() == nameView.value && nameViewArray[i] != this) { return Entry.modal.alert(Lang.Workspace.name_already_exists).then(() => { nameView.focus(); }); } } const newValue = this.value; this.sound.name = newValue; Entry.playground.reloadPlayground(); } nameView.onkeypress = Entry.Utils.blurWhenEnter; const soundLengthView = Entry.createElement('div') .addClass('entryPlaygroundSoundLength') .appendTo(element); soundLengthView.textContent = `${sound.duration} ${Lang.General.second}`; element.soundLengthView = soundLengthView; const removeButton = Entry.createElement('div').addClass('entryPlayground_del'); const { Buttons = {} } = Lang || {}; const { delete: delText = '삭제' } = Buttons; removeButton.appendTo(element).innerText = delText; removeButton.bindOnClick(() => { try { Entry.Utils.forceStopSounds(); const result = Entry.do('objectRemoveSound', Entry.playground.object.id, sound); if (result) { Entry.dispatchEvent('removeSound', sound); Entry.toast.success( Lang.Workspace.sound_remove_ok, `${sound.name} ${Lang.Workspace.sound_remove_ok_msg}` ); } else { Entry.toast.alert(Lang.Workspace.sound_remove_fail, ''); } Entry.removeElement(element); } catch (e) { Entry.toast.alert(Lang.Workspace.sound_remove_fail, ''); } }); } openDropDown = (options, target, callback, closeCallback) => { const containers = $('.entry-widget-dropdown'); if (containers.length > 0) { closeCallback(); return containers.remove(); } const container = Entry.Dom('div', { class: 'entry-widget-dropdown', parent: $('body'), })[0]; const dropdownWidget = new Dropdown({ data: { items: options, positionDom: target, outsideExcludeDom: [target], onOutsideClick: () => { if (dropdownWidget) { closeCallback(); dropdownWidget.hide(); dropdownWidget.remove(); } if (container) { container.remove(); } }, }, container, }).on('select', (item) => { callback(item); closeCallback(); dropdownWidget.hide(); }); return dropdownWidget; }; openColourPicker = (target, color, canTransparent, callback) => { const containers = $('.entry-color-picker'); if (containers.length > 0) { $(target).removeClass('on'); return containers.remove(); } const container = Entry.Dom('div', { class: 'entry-color-picker', parent: $('body'), })[0]; $(target).addClass('on'); const colorPicker = new ColorPicker({ data: { color, positionDom: target, canTransparent, outsideExcludeDom: [target], onOutsideClick: (color) => { if (colorPicker) { $(target).removeClass('on'); colorPicker.hide(); colorPicker.remove(); } if (container) { container.remove(); } }, }, container, }).on('change', (color) => { if (color) { callback(color, true); } }); return colorPicker; }; selectSound(sound) { this.object.sounds.forEach((item) => { if (item.id !== sound.id) { item.view.removeClass('entrySoundSelected'); } else { item.view.addClass('entrySoundSelected'); } }); let objectId_; if (sound && sound.id) { objectId_ = Entry.container.selectSound(sound.id, sound.objectId); } if (this.object.id === objectId_) { if (!sound.objectId) { sound.objectId = this.object.id; } Entry.dispatchEvent('soundSelected', sound, this.object); } } unselectSound() { Entry.dispatchEvent('soundUnselected'); } setTextColour(colour) { $('.imbtn_pop_font_color em').css('background-color', colour); this.object.entity.setColour(colour); this.textEditArea.style.color = colour; this.textEditInput.style.color = colour; } setTextBold(bold) { $('.style_link.imbtn_pop_font_bold').toggleClass('on', bold); $(this.textEditInput).removeClass('bold'); $(this.textEditArea).removeClass('bold'); if (bold) { $(this.textEditInput).addClass('bold'); $(this.textEditArea).addClass('bold'); } } setTextItalic(fontItalic) { $('.style_link.imbtn_pop_font_italic').toggleClass('on', fontItalic); $(this.textEditInput).removeClass('italic'); $(this.textEditArea).removeClass('italic'); if (fontItalic) { $(this.textEditInput).addClass('italic'); $(this.textEditArea).addClass('italic'); } } setTextDecoration(entity) { $('.style_link.imbtn_pop_font_underline').toggleClass('on', entity.getUnderLine()); $('.style_link.imbtn_pop_font_through').toggleClass('on', entity.getStrike()); const effect = `${entity.getStrike() ? 'line-through' : ''} ${ entity.getUnderLine() ? 'underline' : '' }`.trim(); this.textEditArea.style.textDecoration = effect; this.textEditInput.style.textDecoration = effect; } setBackgroundColour(colour) { $('.imbtn_pop_font_backgroundcolor em').css('background-color', colour); $('.imbtn_pop_font_backgroundcolor').toggleClass( 'clear', colour === 'transparent' || colour === '#ffffff' ); this.object.entity.setBGColour(colour); this.textEditArea.style.backgroundColor = colour; this.textEditInput.style.backgroundColor = colour; } isTextBGMode() { return this.isTextBGMode_; } checkVariables() { if (Entry.forEBS) { return; } const blockMenu = this.blockMenu; const { lists_, variables_ } = Entry.variableContainer; if (lists_.length) { blockMenu.unbanClass('listNotExist'); } else { blockMenu.banClass('listNotExist'); } if (variables_.length) { blockMenu.unbanClass('variableNotExist'); } else { blockMenu.banClass('variableNotExist'); } } getViewMode() { return this.viewMode_; } banExpansionBlock() { const blockMenu = _.result(this.mainWorkspace, 'blockMenu'); if (!blockMenu) { return; } Object.values(Entry.EXPANSION_BLOCK_LIST).forEach((block) => { blockMenu.banClass(block.name, true); blockMenu.banClass(`${block.name}_legacy`, true); }); } banAIUtilizeBlock() { const blockMenu = _.result(this.mainWorkspace, 'blockMenu'); if (!blockMenu) { return; } Object.values(Entry.ALL_AI_UTILIZE_BLOCK_LIST).forEach((block) => { blockMenu.banClass(block.name, true); blockMenu.banClass(`${block.name}_legacy`, true); }); } banHardwareLiteBlock() { const blockMenu = _.result(this.mainWorkspace, 'blockMenu'); if (!blockMenu) { return; } Object.values(Entry.HARDWARE_LITE_LIST).forEach((block) => { blockMenu.banClass(block.name, true); blockMenu.banClass(`${block.name}_legacy`, true); blockMenu.banClass(`${block.name.toLowerCase()}`, true); }); } toggleLineBreak(isLineBreak) { const { objectType, entity } = this.object || {}; if (objectType !== 'textBox') { return; } $('.write_type_box a').removeClass('on'); if (isLineBreak) { entity.setLineBreak(true); $('.input_inner').height('228px'); $('.write_type_box a').eq(1).addClass('on'); $('.input_box .single').hide(); $('.input_box .multi').show(); this._setFontFontUI(); } else { entity.setLineBreak(false); $('.input_inner').height('40px'); $('.write_type_box a').eq(0).addClass('on'); $('.input_box .multi').hide(); $('.input_box .single').show(); } } setFontAlign(fontAlign) { if (this.object.objectType !== 'textBox') { return; } this.alignLeftBtn.removeClass('on'); this.alignCenterBtn.removeClass('on'); this.alignRightBtn.removeClass('on'); switch (fontAlign) { case Entry.TEXT_ALIGN_LEFT: this.alignLeftBtn.addClass('on'); break; case Entry.TEXT_ALIGN_CENTER: this.alignCenterBtn.addClass('on'); break; case Entry.TEXT_ALIGN_RIGHT: this.alignRightBtn.addClass('on'); break; } this.object.entity.setTextAlign(fontAlign); } showPictureCurtain() { this.pictureCurtainView_ && this.pictureCurtainView_.removeClass('entryRemove'); } hidePictureCurtain() { this.pictureCurtainView_ && this.pictureCurtainView_.addClass('entryRemove'); } hideBlockMenu() { this.mainWorkspace.getBlockMenu().hide(); } showBlockMenu() { this.mainWorkspace.getBlockMenu().show(); } getDom(query) { if (query.length) { switch (query.shift()) { case 'tabViewElements': return this.tabViewElements[query.shift()]; case 'blockMenu': return this.blockMenu.getDom(query); case 'board': case 'overlayBoard': return this.mainWorkspace.getCurrentBoard().getDom(query); case 'pictureAddButton': return this._pictureAddButton; case 'soundAddButton': return this._soundAddButton; } } else { } } applyTabOption() { this.textboxTab.addClass('entryRemove'); this.pictureTab.addClass('entryRemove'); this.soundTab.addClass('entryRemove'); this.variableTab.addClass('entryRemove'); if (Entry.pictureEditable) { this.pictureTab.removeClass('entryRemove'); this.textboxTab.removeClass('entryRemove'); } if (Entry.soundEditable) { this.soundTab.removeClass('entryRemove'); } if (Entry.hasVariableManager) { this.variableTab.removeClass('entryRemove'); } } updateObjectTitle(object) { if (this.board) { this.board.updateObjectTitle(object); } } updateSelectedObjectTitle() { if ( this.board && Entry.container.selectedObject && this.board.workspace.getMode() === Entry.Workspace.MODE_BOARD ) { this.board.updateObjectTitle(Entry.container.selectedObject); Entry.Utils.doCodeChange(); } } setSound(sound) { const objectSound = Entry.container.setSound(sound); if (objectSound?.view) { objectSound.view.sound = objectSound; } const soundLengthView = _get(objectSound, 'view.soundLengthView'); if (soundLengthView) { soundLengthView.textContent = `${objectSound.duration} ${Lang.General.second}`; } return objectSound; } destroy() { this.commentToggleButton_ && this.commentToggleButton_.unBindOnClick(); this.addCommentButton_ && this.addCommentButton_.unBindOnClick(); this.backPackButton_ && this.backPackButton_.unBindOnClick(); this.blockBackPackEvent && this.blockBackPackEvent.off(); this.blockBackPackAreaEvent && this.blockBackPackAreaEvent.off(); this.objectBackPackEvent && this.objectBackPackEvent.off(); this.objectBackPackAreaEvent && this.objectBackPackAreaEvent.off(); this.globalEvent && this.globalEvent.destroy(); this.soundEditor && this.soundEditor.destory(); this._destroyer.destroy(); } }; ================================================ FILE: src/class/popup.js ================================================ /** * @fileoverview Popup object for generate popup. */ 'use strict'; /** * Constructor of popup * @constructor */ Entry.Popup = class Popup { constructor(className) { Entry.assert(!window.popup, 'Popup exist'); this.body_ = Entry.createElement('div'); this.body_.addClass('entryPopup'); if (className) { this.body_.addClass(className); } this.body_.bindOnClick(function (e) { if (e.target == this) { this.popup.remove(); } }); this.body_.popup = this; Entry.modalContainer.appendChild(this.body_); this.window_ = Entry.createElement('div'); this.window_.addClass('entryPopupWindow'); if (Entry.targetChecker && !Entry.targetChecker.statusViewDisabled) { this.window_.addClass('targetCheckerPopup'); } // if (Entry.device === 'tablet') this.window_.addClass('tablet'); this.window_.bindOnClick(() => {}); Entry.addEventListener('windowResized', this.resize); window.popup = this; this.resize(); this.body_.appendChild(this.window_); } /** * Remove this popup */ remove() { Entry.dispatchEvent('onPopupClose'); while (this.window_.hasChildNodes()) { if (Entry.type == 'workspace') { Entry.engineContainer.insertBefore( Entry.engine.buttonWrapper, Entry.engineContainer.firstChild ); Entry.engineContainer.insertBefore( this.window_.firstChild, Entry.engineContainer.firstChild ); } else if (Entry.type == 'minimize') { const child = this.window_.firstChild; if (child === Entry.stage.canvas.canvas) { const wrapper = Entry.view_.querySelector('#entryCanvasWrapper'); wrapper.insertBefore(child, wrapper.firstChild); } else if (child === Entry.engine.runButton[0]) { Entry.view_ .querySelector('.entryRunButtonBigMinimizeCurtain') .appendChild(child); } else if (child === Entry.engine.view_) { Entry.view_.appendChild(child); } } else { Entry.engineContainer.insertBefore( this.window_.lastChild, Entry.engineContainer.firstChild ); } } $('body').css('overflow', 'auto'); Entry.removeElement(this.body_); window.popup = null; Entry.removeEventListener('windowResized', this.resize); Entry.view_.removeClass('fullscreen'); Entry.engine.popup = null; Entry.windowResized.notify(); if ( Entry.type === 'workspace' && Entry.targetChecker && !Entry.targetChecker.statusViewDisabled ) { Entry.targetChecker.getStatusView().remove(); } } /** * Resize this view size when window size modified * @param {event} e */ resize(e) { const popup = window.popup; const popupWindow = popup.window_; const bottomOffset = Entry.targetChecker && !Entry.targetChecker.statusViewDisabled ? 91 + 48 : 48; let maxWidth = 0; let maxHeight = 0; if (window.parent) { try { maxWidth = window.parent.innerWidth * 0.9; maxHeight = window.parent.innerHeight * 0.9 - bottomOffset; } catch (e) { maxWidth = window.innerWidth * 0.9; maxHeight = window.innerHeight * 0.9 - bottomOffset; } } else { maxWidth = window.innerWidth * 0.9; maxHeight = window.innerHeight * 0.9 - bottomOffset; } if (maxWidth * 9 <= maxHeight * 16) { maxHeight = (maxWidth / 16) * 9; maxHeight += bottomOffset; popupWindow.style.width = `${String(maxWidth)}px`; popupWindow.style.height = `${String(maxHeight)}px`; } else { maxWidth = (maxHeight * 16) / 9; maxHeight += bottomOffset; popupWindow.style.width = `${String(maxWidth)}px`; popupWindow.style.height = `${String(maxHeight)}px`; } Entry.stage && Entry.stage.updateBoundRect(); } removeMouseDispose(e) { this.body_.unBindOnClick(); } }; ================================================ FILE: src/class/popup_helper.ts ================================================ require('../util/utils'); export default class PopupHelper { private popupList: any = {}; private nextPopupList: string[] = []; private nowContent: any = undefined; private body_: any; private window_: any; private popupWrapper_: any; constructor(reset: boolean) { if (reset) { $('.entryPopup.popupHelper').remove(); window.popupHelper = null; } Entry.assert(!window.popupHelper, 'Popup exist'); const ignoreCloseType = ['confirm', 'spinner']; const spanArea = [ 'entryPopupHelperTopSpan', 'entryPopupHelperBottomSpan', 'entryPopupHelperLeftSpan', 'entryPopupHelperRightSpan', ]; this.body_ = Entry.Dom('div', { classes: ['entryPopup', 'hiddenPopup', 'popupHelper'], }); const popupClickEvent = (e: JQuery.ClickEvent) => { if (this.nowContent && ignoreCloseType.indexOf(this.nowContent.prop('type')) > -1) { return; } const $target = $(e.target); spanArea.forEach((className) => { if ($target.hasClass(className)) { this.hide(); } }); if (e.target == this) { this.hide(); } }; this.body_.bindOnClick(popupClickEvent); window.popupHelper = this; this.body_.prop('popup', this); Entry.Dom('div', { class: 'entryPopupHelperTopSpan', parent: this.body_, }); const middle = Entry.Dom('div', { class: 'entryPopupHelperMiddleSpan', parent: this.body_, }); Entry.Dom('div', { class: 'entryPopupHelperBottomSpan', parent: this.body_, }); Entry.Dom('div', { class: 'entryPopupHelperLeftSpan', parent: middle, }); this.window_ = Entry.Dom('div', { class: 'entryPopupHelperWindow', parent: middle, }); Entry.Dom('div', { class: 'entryPopupHelperRightSpan', parent: middle, }); $('body').append(this.body_); } clearPopup() { const maxCnt = this.popupWrapper_.children.length - 1; for (let i = maxCnt; i > 2; i--) { this.popupWrapper_.removeChild(this.popupWrapper_.children[i]); } } addPopup(key: string, popupObject: any) { const content_ = Entry.Dom('div'); const titleButton_ = Entry.Dom('div', { class: 'entryPopupHelperCloseButton', }); titleButton_.bindOnClick(() => { if (popupObject.closeEvent) { popupObject.closeEvent(this); } this.hide(); }); const popupWrapper_ = Entry.Dom('div', { class: 'entryPopupHelperWrapper', }); popupWrapper_.append(titleButton_); if (popupObject.title) { const title_ = Entry.Dom('div', { class: 'entryPopupHelperTitle', }); popupWrapper_.append(title_); title_.text(popupObject.title); } content_.addClass(key); content_.append(popupWrapper_); // @ts-ignore content_.popupWrapper_ = popupWrapper_; content_.prop('type', popupObject.type); if (typeof popupObject.setPopupLayout === 'function') { popupObject.setPopupLayout(content_); } // @ts-ignore content_._obj = popupObject; this.popupList[key] = content_; } hasPopup(key: string) { return !!this.popupList[key]; } remove(key: string) { if (key) { this.window_.find(`> .${key}`).remove(); } else if (this.window_.children().length > 0) { this.window_.children().remove(); } // 지워지면 안되는 요소인데 지워지고 있었음. 이유는? 잠시동안만 유지. // this.window_.remove(); delete this.popupList[key]; if (this.nowContent && this.nowContent.hasClass(key)) { this.nowContent = undefined; this.body_.addClass('hiddenPopup'); if (this.nextPopupList.length > 0) { this.show(this.nextPopupList.shift()); } } } // 왜있는 함수인지 알수없음 레거시임. 문제없는 경우 삭제해도 됨 resize(e: any) {} show(key: string, isNext?: boolean) { const that = this; function showContent(key: string) { that.window_.append(that.popupList[key]); that.nowContent = that.popupList[key]; that.body_.removeClass('hiddenPopup'); } if (!isNext) { this.window_.children().detach(); showContent(key); } else { if (this.window_.children().length > 0) { this.nextPopupList.push(key); } else { this.window_.children().detach(); showContent(key); } } if (this.nowContent && this.nowContent._obj && this.nowContent._obj.onShow) { this.nowContent._obj.onShow(); } } hide() { const popup = this.nowContent && this.nowContent._obj; if (popup && 'closeEvent' in popup) { popup.closeEvent(this); } this.nowContent = undefined; this.body_.addClass('hiddenPopup'); this.window_.children().detach(); if (this.nextPopupList.length > 0) { this.show(this.nextPopupList.shift()); } } addClass(className?: string) { className && this.body_.addClass(className); } } // Entry Legacy 에서 사용 중 Entry.popupHelper = PopupHelper; ================================================ FILE: src/class/popup_list.js ================================================ 'use strict'; Entry.PopupList = class PopupList { constructor(dom) { this.view = dom; } getView() { return this.view; } resize() {} }; ================================================ FILE: src/class/project.js ================================================ 'use strict'; import get from 'lodash/get'; import isMatch from 'lodash/isMatch'; import pick from 'lodash/pick'; function scriptCheck(script) { if (script.length !== 1 || script[0].length !== 2) { return false; } const whenRun = get(script, '0.0.type'); const repeat = get(script, '0.1.type'); const statements = get(script, '0.1.statements'); const move = get(script, '0.1.statements.0.0.type'); if ( whenRun !== 'when_run_button_click' || repeat !== 'repeat_basic' || statements.length !== 1 || statements[0].length !== 1 || move !== 'move_direction' ) { return false; } return true; } Entry.isDefaultProject = function (project) { try { if (Entry.stateManager.undoStack_.length) { return false; } const script = JSON.parse(get(project, 'objects.0.script')); const { scenes, variables, objects, tables } = project; if ( scenes.length !== 1 || variables.length !== 2 || objects.length !== 1 || tables.length !== 0 || !scriptCheck(script) ) { return false; } const pickData = pick(project, [ 'scenes.0.id', 'variables.0.id', 'variables.0.value', 'variables.0.variableType', 'variables.0.x', 'variables.0.y', 'variables.1.id', 'variables.1.value', 'variables.1.variableType', 'variables.1.x', 'variables.1.y', 'objects.0.id', 'objects.0.scene', 'objects.0.sprite.sounds.0.id', 'objects.0.sprite.sounds.length', 'objects.0.sprite.pictures.0.id', 'objects.0.sprite.pictures.1.id', 'objects.0.sprite.pictures.length', 'expansionBlocks', 'aiUtilizeBlocks', 'speed', ]); return isMatch(Entry.getStartProject(), pickData); } catch (e) { return false; } }; Entry.getStartProject = function (mediaFilePath) { return { category: Lang.Menus.other, scenes: [ { name: `${Lang.Blocks.SCENE} 1`, id: '7dwq', }, ], variables: [ { name: Lang.Workspace.Variable_Timer, id: 'brih', visible: false, value: '0', variableType: 'timer', x: 134, y: -70, array: [], object: null, isCloud: false, }, { name: Lang.Blocks.VARIABLE_get_canvas_input_value, id: '1vu8', visible: false, value: '0', variableType: 'answer', x: 150, y: -100, array: [], object: null, isCloud: false, }, ], objects: [ { id: '7y0y', name: Lang.Blocks.entry_bot_name, label: { ko: '엔트리봇', en: 'Entrybot', }, script: [ [ { type: 'when_run_button_click', x: 40, y: 50, }, { type: 'repeat_basic', statements: [[{ type: 'move_direction' }]], }, ], ], selectedPictureId: 'vx80', objectType: 'sprite', rotateMethod: 'free', scene: '7dwq', sprite: { sounds: [ { duration: 1.3, ext: '.mp3', id: '8el5', fileurl: `${mediaFilePath}media/bark.mp3`, name: Lang.Blocks.doggi_bark, label: { ko: '강아지 짖는소리', en: "Doggi's Bark", }, }, ], pictures: [ { id: 'vx80', fileurl: `${mediaFilePath}media/entrybot1.svg`, thumbUrl: `${mediaFilePath}media/entrybot1.svg`, name: `${Lang.Blocks.walking_entryBot}1`, imageType: 'svg', dimension: { width: 144, height: 246, }, }, { id: '4t48', fileurl: `${mediaFilePath}media/entrybot2.svg`, thumbUrl: `${mediaFilePath}media/entrybot2.svg`, name: `${Lang.Blocks.walking_entryBot}2`, imageType: 'svg', dimension: { width: 144, height: 246, }, }, ], }, entity: { x: 0, y: 0, regX: 72, regY: 123, scaleX: 0.5128205128205128, scaleY: 0.5128205128205128, rotation: 0, direction: 90, width: 144, height: 246, visible: true, }, lock: false, active: true, }, ], expansionBlocks: [], aiUtilizeBlocks: [], speed: 60, }; }; ================================================ FILE: src/class/property_panel.ts ================================================ import { EntryDom } from '../../types/index'; class PropertyPanel { public modes: any = {}; public selected: string = undefined; private _view: EntryDom; private _tabView: EntryDom; private _contentView: EntryDom; private _cover: EntryDom & { _isVisible?: boolean }; generateView(parentDom: HTMLElement) { const container = $(parentDom); this._view = Entry.Dom('div', { class: 'propertyPanel', parent: container, }); this._tabView = Entry.Dom('div', { class: 'propertyTab', parent: this._view, }); this._contentView = Entry.Dom('div', { class: 'propertyContent', parent: this._view, }); this._cover = Entry.Dom('div', { classes: ['propertyPanelCover', 'entryRemove'], parent: this._view, }); const splitter = Entry.Dom('div', { class: 'entryObjectSelectedImgWorkspace', parent: container, }); this._initializeSplitter(splitter); } addMode(mode: string, contentObj: any) { if (this.modes[mode]) { this.removeMode(mode); } let contentDom = contentObj.getView(); // will be removed after apply new Dom class contentDom = Entry.Dom(contentDom, { parent: this._contentView, }); const tabDom = Entry.Dom(`
${Lang.Menus[mode]}
`, { classes: ['propertyTabElement', `propertyTab${mode}`], parent: this._tabView, }); tabDom.bind('click', () => { this.select(mode); }); if (mode === 'console') { contentObj.codeMirror.refresh(); } this._removeDom(mode); this.modes[mode] = { obj: contentObj, tabDom, contentDom, }; if (mode === 'hw') { $('.propertyTabhw').bind('dblclick', () => { Entry.dispatchEvent('hwModeChange'); }); } } removeMode(mode: string) { this._removeDom(mode); const keys = Object.keys(this.modes); if (keys && keys.length > 0) { this.select(keys[0]); } } resize(canvasSize: number) { const selected = this.selected; if (!selected) { return; } const canvasHeight = (canvasSize * 9) / 16; this._view.css({ width: `${canvasSize}px`, top: `${canvasHeight + 35 + 40 + 48 - 22}px`, }); if (canvasSize >= 430) { this._view.removeClass('collapsed'); } else { this._view.addClass('collapsed'); } Entry.dispatchEvent('windowResized'); const obj = this.modes[selected].obj; if (selected === 'hw') { if (this.modes.hw.obj.listPorts) { obj.resizeList(); } else { obj.resize && obj.resize(); } } else { obj.resize && obj.resize(); } } select(modeName: string) { for (const key in this.modes) { const mode = this.modes[key]; mode.tabDom.removeClass('selected'); mode.contentDom.addClass('entryRemove'); $(mode.contentDom).detach(); mode.obj.visible = false; } const selected = this.modes[modeName]; $(this._contentView).append(selected.contentDom); selected.tabDom.addClass('selected'); selected.contentDom.removeClass('entryRemove'); if (selected.obj.resize) { selected.obj.resize(); } selected.obj.visible = true; this.selected = modeName; } private _initializeSplitter(splitter: EntryDom) { splitter.bind('mousedown touchstart', (e) => { e.preventDefault(); if (Entry.disposeEvent) { Entry.disposeEvent.notify(); } const container = Entry.container; splitter.addClass('enabled'); this._cover.removeClass('entryRemove'); this._cover._isVisible = true; container.splitterEnable = true; const beforeVisible = this._cover.width() >= Entry.CANVAS_DEFAULT_WIDTH - 24; let isMoved = false; if (Entry.documentMousemove) { container.resizeEvent = Entry.documentMousemove.attach(this, (e: any) => { if (container.splitterEnable) { isMoved = true; Entry.resizeElement({ canvasWidth: e.clientX || e.x, }); } }); } $(document).bind('mouseup.container:splitter touchend.container:splitter', () => { const container = Entry.container; const listener = container.resizeEvent; if (listener) { container.splitterEnable = false; listener.destroy(); splitter.removeClass('enabled'); delete container.resizeEvent; } if (this._cover._isVisible) { this._cover._isVisible = false; this._cover.addClass('entryRemove'); } if ( !isMoved && !beforeVisible && this._cover.width() < Entry.CANVAS_DEFAULT_WIDTH - 24 ) { Entry.resizeElement({ canvasWidth: Entry.CANVAS_MIN_WIDTH }); } $(document).unbind('.container:splitter'); }); }); } private _removeDom(mode: string) { if (this.modes[mode]) { this.modes[mode].tabDom.remove(); this.modes[mode].contentDom.remove(); if (mode === 'hw') { $(this.modes).removeClass('.propertyTabhw'); $('.propertyTabhw').unbind('dblclick'); } } } } export default PropertyPanel; Entry.PropertyPanel = PropertyPanel; ================================================ FILE: src/class/reporter.js ================================================ 'use strict'; /** * @fileoverview Show dialog on canvas */ Entry.Reporter = class Reporter { constructor(isRealTime) { this.userId = null; this.projectId = null; this.isRealTime = isRealTime; this.activities = []; } start(projectId, userId, startTime) { //this.io = io(window.location.href.split("/")[2]); if (this.isRealTime) { if (window.location.href.indexOf('localhost') > -1) { this.io = io('localhost:7000'); } else { this.io = io('play04.play-entry.com:7000'); } this.io.emit('activity', { message: 'start', userId, projectId, time: startTime, }); } this.userId = userId; this.projectId = projectId; } report(state) { if (this.isRealTime && !this.io) { return; } const params = []; for (const i in state.params) { const param = state.params[i]; if (typeof param !== 'object') { params.push(param); } else if (param.id) { params.push(param.id); } } const activity = { message: state.message, userId: this.userId, projectId: this.projectId, time: state.time, params, }; if (this.isRealTime) { this.io.emit('activity', activity); } else { this.activities.push(activity); } } }; ================================================ FILE: src/class/scene.js ================================================ /** * @fileoverview Scene controller for entry. */ 'use strict'; import { Sortable } from '@entrylabs/tool'; /** * Class for a scene controller. * This have view for scenes. * @constructor */ const STATIC_SCENES_COUNT = 30; Entry.Scene = class { constructor() { this.scenes_ = []; this.selectedScene = null; this.maxCount = this.getMaxSceneCount() || 30; $(window).on('resize', this.resize.bind(this)); this.disposeEvent = Entry.disposeEvent.attach(this, (e) => { const elem = document.activeElement; if (e && elem && elem !== e.target && $(elem).hasClass('entrySceneFieldWorkspace')) { elem.blur(); } }); } /** * Control bar view generator. * @param {!Element} sceneView sceneView from Entry. * @param {?string} option for choose type of view. */ generateView(sceneView, option) { this.view_ = sceneView; this.view_.addClass('entryScene'); if (!option || option === 'workspace' || option === 'playground') { this.view_.addClass('entrySceneWorkspace'); $(this.view_).on('mousedown touchstart', (e) => { const offset = $(this.view_).offset(); const $window = $(window); const slope = -40 / 55; const selectedScene = this.selectedScene; const selectedLeft = $(selectedScene.view) .find('.entrySceneRemoveButtonCoverWorkspace') .offset().left; const x = e.pageX - offset.left + $window.scrollLeft() - selectedLeft; const y = 40 - (e.pageY - offset.top + $window.scrollTop()); if (x < selectedLeft || x > selectedLeft + 55) { return; } }); const listView = this.createListView(); this.view_.appendChild(listView); this.listView_ = listView; if (Entry.sceneEditable) { const addButton = this.createAddButton(); this.view_.appendChild(addButton); this.addButton_ = addButton; const scenePrevButton = this.scenePrevButton(); const sceneNextButton = this.sceneNextButton(); this.view_.appendChild(scenePrevButton); this.view_.appendChild(sceneNextButton); this.scenePrevButton = scenePrevButton; this.sceneNextButton = sceneNextButton; this.prevButton_ = scenePrevButton; this.nextButton_ = sceneNextButton; this.sceneListWidth = Entry.scene.listView_.offsetWidth; this.updateView(); } } } createAddButton() { const addButton = Entry.createElement('span').addClass( 'entrySceneElementWorkspace entrySceneAddButtonWorkspace' ); addButton.bindOnClick((e) => { if (Entry.engine.isState('run')) { return; } Entry.do('sceneAdd', Entry.generateHash()); }); return addButton; } /** * prev scene button */ scenePrevButton() { const prevButton = Entry.createElement('span').addClass( 'entrySceneElementWorkspace entryScenePrevButtonWorkspace' ); const prevBtn = document.createElement('span').addClass('prevBtn'); prevButton.bindOnClick((e) => { this.selectScene(Entry.scene.getPrevScene()); }); prevButton.appendChild(prevBtn); return prevButton; } /** * next scene, add scene button */ sceneNextButton() { const nextButton = Entry.createElement('span').addClass( 'entrySceneElementWorkspace entrySceneNextButtonWorkspace' ); const nextBtn = document.createElement('span').addClass('nextBtn'); nextBtn.bindOnClick((e) => { this.selectScene(Entry.scene.getNextScene()); }); const addButton = document.createElement('span').addClass('addButton'); addButton.bindOnClick((e) => { if (Entry.engine.isState('run')) { return; } this.sceneListwidth = Entry.scene.listView_.offsetWidth; Entry.do('sceneAdd', Entry.generateHash()); }); this.nextAddButton_ = addButton; nextButton.appendChild(nextBtn); nextButton.appendChild(addButton); return nextButton; } createListView() { const listView = Entry.createElement('div'); listView.addClass('entrySceneListWorkspace'); const observer = new ResizeObserver(() => { this.updateView(); }); observer.observe(listView); this.sceneSortableListWidget = new Sortable({ data: { height: '100%', sortableTarget: ['entrySceneRemoveButtonWorkspace', 'entrySceneInputCover'], lockAxis: 'x', axis: 'x', items: this._getSortableSceneList(), }, container: listView, }); if (Entry.sceneEditable) { this.sceneSortableListWidget.on('change', ([newIndex, oldIndex]) => { Entry.scene.moveScene(newIndex, oldIndex); }); } return listView; } updateSceneView() { const items = this._getSortableSceneList(); if (this.sceneSortableListWidget) { setTimeout(() => this.sceneSortableListWidget.setData({ items }), 0); } } _getSortableSceneList() { if (!this.scenes_ || this.scenes_.length === 0) { return []; } return this.scenes_.map((value) => ({ key: value.id, item: value.view, })); } /** * generate li element for scene * @param {!scene model} scene */ generateElement(scene) { const viewTemplate = this.createViewTemplate(scene); Entry.Utils.disableContextmenu(viewTemplate); const nameField = this.createNameField(scene); viewTemplate.nameField = nameField; const sceneLeft = this.createSceneLeft(); viewTemplate.appendChild(sceneLeft); const divide = this.createSceneDivider(); viewTemplate.appendChild(divide); scene.inputWrapper = divide; divide.appendChild(nameField); const removeButtonCover = this.createRemoveButtonCover(); viewTemplate.appendChild(removeButtonCover); if (Entry.sceneEditable) { scene.removeButton = this.createRemoveButton(scene, removeButtonCover); Entry.ContextMenu.onContextmenu(viewTemplate, (coordinate) => { const options = [ { text: Lang.Workspace.duplicate_scene, enable: Entry.engine.isState('stop') && !this.isMax(), callback() { Entry.scene.cloneScene(scene); }, }, ]; Entry.ContextMenu.show(options, 'workspace-contextmenu', coordinate); }); } scene.view = viewTemplate; return viewTemplate; } createRemoveButton(scene, removeButtonCover) { return Entry.createElement('button') .addClass('entrySceneRemoveButtonWorkspace') .bindOnClick((e) => { if (Entry.engine.isState('run')) { return; } const isDeletable = Entry.scene.getScenes().length > 1; if (!isDeletable) { Entry.toast.alert( Lang.Msgs.runtime_error, Lang.Workspace.Scene_delete_error, false ); return; } Entry.do('sceneRemove', scene.id); }) .appendTo(removeButtonCover); } createRemoveButtonCover() { const removeButtonCover = Entry.createElement('span'); removeButtonCover.addClass('entrySceneRemoveButtonCoverWorkspace'); return removeButtonCover; } createSceneDivider() { const divide = Entry.createElement('span'); divide.addClass('entrySceneInputCover'); if (!Entry.sceneEditable) { divide.addClass('entryDisabledScene'); } return divide; } createSceneLeft() { const sceneLeft = Entry.createElement('span'); sceneLeft.addClass('entrySceneLeftWorkspace'); return sceneLeft; } createNameField(scene) { const nameField = Entry.createElement('input'); nameField.addClass('entrySceneFieldWorkspace'); nameField.value = scene.name; nameField.addEventListener('keyup', ({ keyCode: code }) => { if (Entry.isArrowOrBackspace(code)) { return; } const applyValue = (value) => { value !== scene.name && Entry.do('sceneRename', scene.id, value); nameField.blur(); }; let value = nameField.value; if (code === 13) { applyValue(value); } else if (value.length > 10) { value = value.substring(0, 10); applyValue(value); } }); nameField.addEventListener('blur', (e) => { if (nameField.value !== scene.name) { Entry.do('sceneRename', scene.id, nameField.value); } const { playground = {} } = Entry; const { mainWorkspace } = playground; if (mainWorkspace) { mainWorkspace.reDraw(); } }); if (!Entry.sceneEditable) { nameField.disabled = 'disabled'; } return nameField; } createViewTemplate(scene) { const viewTemplate = Entry.createElement('div', scene.id); viewTemplate.addClass('entrySceneElementWorkspace entrySceneButtonWorkspace minValue'); $(viewTemplate).on('mousedown touchstart', (e) => { if (Entry.engine.isState('run')) { return; } if (Entry.scene.selectedScene !== scene) { Entry.do('sceneSelect', scene.id); if (e.type === 'touchstart') { e.preventDefault(); } } }); return viewTemplate; } updateView() { if (!Entry.type || Entry.type === 'workspace') { const addBtnWidth = 72; const sceneListWidth = this.sceneListWidth + addBtnWidth + 170; const browserWidth = Entry.view_.offsetWidth; const maxSceneCount = Entry.scene.scenes_.length || STATIC_SCENES_COUNT; if (this.addButton_) { if (maxSceneCount >= STATIC_SCENES_COUNT) { this.addButton_.addClass('entryRemove'); this.nextAddButton_.addClass('entryRemove'); } else { this.addButton_.removeClass('entryRemove'); this.prevButton_.removeClass('entryRemove'); this.nextButton_.removeClass('entryRemove'); if (sceneListWidth > browserWidth) { this.addButton_.addClass('entryRemove'); this.nextAddButton_.removeClass('entryRemove'); } else { this.nextButton_.addClass('entryRemove'); this.prevButton_.addClass('entryRemove'); } } } } this.updateSceneView(); this.resize(); } /** * add scenes * @param {Array} scenes */ addScenes(scenes) { this.scenes_ = scenes; if (!scenes || scenes.length === 0) { this.scenes_ = []; this.scenes_.push(this.createScene()); } else { for (let i = 0, len = scenes.length; i < len; i++) { this.generateElement(scenes[i]); } } this.selectScene(this.getScenes()[0]); } /** * add scenes to this.scenes_ * @param {scene model} scene */ addScene(scene, index) { if (scene === undefined || typeof scene === 'string') { scene = this.createScene(scene); } if (!scene.view) { this.generateElement(scene); } if (!index && typeof index != 'number') { this.getScenes().push(scene); } else { this.getScenes().splice(index, 0, scene); } Entry.stage.objectContainers.push(Entry.stage.createObjectContainer(scene)); this.selectScene(scene); if (Entry.creationChangedEvent) { Entry.creationChangedEvent.notify(); } const { playground = {} } = Entry || {}; const { mainWorkspace } = playground; if (mainWorkspace) { mainWorkspace.reDraw(); } return scene; } /** * remove scene from this.scenes_ * @param {!scene model} scene */ removeScene(scene) { if (this.getScenes().length <= 1) { Entry.toast.alert(Lang.Msgs.runtime_error, Lang.Workspace.Scene_delete_error, false); return; } Entry.Utils.forceStopSounds(); scene = this.getSceneById(typeof scene === 'string' ? scene : scene.id); this.getScenes().splice(this.getScenes().indexOf(scene), 1); Entry.container .getSceneObjects(scene) .forEach((object) => Entry.container.removeObject(object, true)); Entry.stage.removeObjectContainer(scene); $(scene.view).remove(); this.selectScene(); if (Entry.codeChangedEvent) { Entry.codeChangedEvent.notify(); } } selectScene(scene) { const targetScene = scene || this.getScenes()[0]; const container = Entry.container; container.resetSceneDuringRun(); if (this.selectedScene && this.selectedScene.id === targetScene.id) { return; } if ( Entry.playground.getViewMode() === 'picture' && Entry.playground.nameViewFocus && Entry.playground.nameViewBlur() ) { return; } const prevSelected = this.selectedScene; if (prevSelected) { const prevSelectedView = prevSelected.view; prevSelectedView.removeClass('selectedScene'); const elem = document.activeElement; elem === prevSelectedView.nameField && elem.blur(); } this.selectedScene = targetScene; targetScene.view.addClass('selectedScene'); const stage = Entry.stage; const playground = Entry.playground; container.setCurrentObjects(); stage.selectObjectContainer(targetScene); const targetObject = container.getCurrentObjects()[0]; if (Entry.engine.isState('run')) { Entry.Utils.forceStopSounds(); } if (targetObject && Entry.type !== 'minimize') { container.selectObject(targetObject.id); playground.refreshPlayground(); } else { if (Entry.isTextMode) { const workspace = Entry.getMainWS(); const vimBoard = workspace && workspace.vimBoard; if (vimBoard) { const sObject = vimBoard._currentObject; const sScene = vimBoard._currentScene; const parser = vimBoard._parser; try { if (targetScene.id != sScene.id) { workspace._syncTextCode(); } } catch (e) {} if (parser._onError) { container.selectObject(sObject.id, true); return; } } vimBoard && vimBoard.clearText(); } stage.selectObject(null); playground.flushPlayground(); Entry.variableContainer.selected = null; Entry.variableContainer.updateList(); } !container.listView_ && stage.sortZorder(); container.updateListView(); if (Entry.type && Entry.type !== 'minimize' && Entry.scene.listView_) { this.sceneListWidth = Entry.scene.listView_.offsetWidth; } this.updateView(); Entry.requestUpdate = true; } /** * convert this scenes data to JSON. * @return {JSON} */ toJSON() { return this.getScenes().map((scene) => _.pick(scene, ['id', 'name'])); } /** * Move scene in this.scenes_ * this method is for sortable * @param {!number} start * @param {!number} end */ moveScene(start, end) { this.getScenes().splice(end, 0, this.getScenes().splice(start, 1)[0]); Entry.container.updateObjectsOrder(); Entry.stage.sortZorder(); this.updateSceneView(); //style properties are not removed sometimes $('.entrySceneElementWorkspace').removeAttr('style'); } /** * get scene by scene id * @param {!String} sceneId * @return {scene modal} */ getSceneById(id) { return _.find(this.getScenes(), { id }) || false; } /** * @return {Array} */ getScenes() { return this.scenes_; } /** * remember selectedScene before start * in order to reset when stopped */ takeStartSceneSnapshot() { this.sceneBeforeRun = this.selectedScene; } /** * select selectedScene before start * before run start */ loadStartSceneSnapshot() { this.selectScene(this.sceneBeforeRun); this.sceneBeforeRun = null; } /** * create scene * @return {scene modal} scene */ createScene(sceneId) { const regex = /[0-9]/; let name = Entry.getOrderedName(`${Lang.Blocks.SCENE} `, this.scenes_, 'name'); if (!regex.test(name)) { name += '1'; } const scene = { name, id: sceneId || Entry.generateHash(), }; this.generateElement(scene); return scene; } /** * clone scene by context menu * @param {!scene model} scene */ cloneScene(scene) { if (this.isMax()) { Entry.toast.alert(Lang.Msgs.runtime_error, Lang.Workspace.Scene_add_error, false); return; } const clonedScene = { name: (Lang.Workspace.cloned_scene + scene.name).substring(0, 10), id: Entry.generateHash(), }; this.generateElement(clonedScene); this.addScene(clonedScene); const container = Entry.container; const objects = container.getSceneObjects(scene); try { const oldIds = []; const newIds = []; this.isSceneCloning = true; for (let i = objects.length - 1; i >= 0; i--) { const obj = objects[i]; const ret = container.addCloneObject(obj, clonedScene.id, true); oldIds.push(obj.id); newIds.push(ret.id); } container.adjustClonedValues(oldIds, newIds); const WS = Entry.getMainWS(); WS && WS.board && WS.board.reDraw(); this.isSceneCloning = false; container.setCurrentObjects(); container.updateObjectsOrder(); container.updateListView(); container.selectObject(newIds[newIds.length - 1]); Entry.variableContainer.updateViews(); } catch (e) { console.log('error', e); } } /** * resize html element by window size * @param {!scene model} scene */ resize() { const scenes = this.getScenes(); const selectedScene = this.selectedScene; const addButton = this.addButton_; const firstScene = scenes[0]; if (scenes.length === 0 || !firstScene) { return; } const startPos = $(firstScene.view).offset().left; const marginLeft = parseFloat($(selectedScene.view).css('margin-left')); let totalWidth = Math.floor($(this.view_).width() - startPos - 5); const LEFT_MARGIN = -40; let normWidth = startPos + 15; let diff = 0; let isSelectedView = false; let selectedViewWidth = 0; for (var i in scenes) { var scene = scenes[i]; let view = scene.view; view.addClass('minValue'); isSelectedView = view === this.selectedScene.view; view = $(view); const width = parseFloat(Entry.computeInputWidth(scene.name)); const adjusted = (width * 10) / 9; if (scene === this.selectedScene) { diff = adjusted - width; } // $(scene.inputWrapper).width(adjusted + 'px'); const viewWidth = view.width(); if (isSelectedView) { selectedViewWidth = viewWidth; } normWidth += viewWidth + LEFT_MARGIN; } if (normWidth > totalWidth) { align(); } function align() { const dummyWidth = 30.5; const len = scenes.length - 1; totalWidth = totalWidth - Math.round(selectedViewWidth || $(selectedScene.view).width()) - dummyWidth * len - diff; const fieldWidth = Math.floor(totalWidth / len); for (i in scenes) { scene = scenes[i]; if (selectedScene.id != scene.id) { scene.view.removeClass('minValue'); // $(scene.inputWrapper).width(fieldWidth); } else { scene.view.addClass('minValue'); } } } } getPrevScene() { const scenes = this.getScenes(); return scenes[scenes.indexOf(this.selectedScene) - 1]; } getNextScene() { const scenes = this.getScenes(); return scenes[scenes.indexOf(this.selectedScene) + 1]; } getMaxSceneCount() { return STATIC_SCENES_COUNT; } isMax() { return Entry.scene.scenes_.length >= STATIC_SCENES_COUNT; } clear() { this.scenes_.forEach((s) => Entry.stage.removeObjectContainer(s)); this.scenes_ = []; this.selectedScene = null; this.updateView(); } getDom(query) { let scene; if (query.length > 1) { scene = this.getSceneById(query[1]); } switch (query[0]) { case 'addButton': return this.addButton_; case 'removeButton': return scene.removeButton; case 'nameField': return scene.view.nameField; case 'view': return scene.view; default: return; } } destroy() { // 우선 interface 만 정의함. } }; ================================================ FILE: src/class/sound.ts ================================================ import { renderSoundEditor, loadSoundByUrl, loadSound, clearSound, clearHistory, registExportFunction, unregistExportFunction, undo, redo, isModified, getAudioBuffer, destroy, } from '@entrylabs/sound-editor'; import toWav from 'audiobuffer-to-wav'; interface ISound { duration: number; ext: string; id: string; filename: string; fileurl: string; name: string; path: string; objectId?: string; } interface IObject { id: string; } interface ILastSound { sound: ISound; object: IObject; } class SoundEditor { sound?: ISound; object?: IObject; lastChangeSoundInfo?: ILastSound; constructor(soundView: HTMLDivElement) { this.initialize(soundView); } initialize(soundView: HTMLDivElement) { renderSoundEditor(soundView); Entry.addEventListener('soundSelected', this.changeSound.bind(this)); Entry.addEventListener('soundUnselected', this.clearSound.bind(this)); Entry.addEventListener('saveCompleteSound', this.saveAfterEvent.bind(this)); registExportFunction(this.saveSound.bind(this)); } getEntryAudioBuffer(id: string) { if (!Entry.soundQueue) { return; } return Entry.soundQueue.getResult(id); } async updateSound(sound: ISound, object: IObject) { try { if (Entry.playground.object.id !== object.id) { return; } this.sound = sound; this.object = object; const audioBuffer = this.getEntryAudioBuffer(sound.id); if (!audioBuffer) { Entry.dispatchEvent('startLoading', Lang.Msgs.sound_loading); await loadSoundByUrl(sound.path); } else { loadSound(audioBuffer); } } catch (e) { console.error(e); } finally { Entry.dispatchEvent('endLoading'); } } /** * 이 메서드는 소리와 오브젝트를 매개변수로 받아, * 소리가 없거나 소리의 경로가 없는 경우를 제외하고 현재 소리를 업데이트합니다. * 만약 변경 사항이 있다면, 사용자에게 저장할지 확인한 후, * 오디오 버퍼를 얻고 소리를 저장합니다. * 변경 사항이 없다면, 소리와 오브젝트를 업데이트합니다. * 메서드 실행 중에 오류가 발생하면, 오류를 콘솔에 기록합니다. * * @param {ISound} sound - 업데이트할 소리 * @param {IObject} object - 오브젝트 */ changeSound(sound: ISound, object: IObject) { try { if (!sound || !sound.path || (this.sound && this.sound.id === sound.id)) { return; } if (isModified()) { this.alertSaveModifiedSound(sound, object); } else { this.updateSound(sound, object); } } catch (e) { console.error(e); } } async clearSound() { await this.alertSaveModifiedSound(this.sound, this.object); this.sound = null; this.object = null; clearSound(); } audioBufferToArrayBuffer(audioBuffer: AudioBuffer) { const numberOfChannels = audioBuffer.numberOfChannels; const length = audioBuffer.length * numberOfChannels * 2; // 16-bit PCM const buffer = new ArrayBuffer(length); const view = new DataView(buffer); for (let channel = 0; channel < numberOfChannels; channel++) { const channelData = audioBuffer.getChannelData(channel); let offset = channel * 2; for (let i = 0; i < channelData.length; i++) { const sample = Math.max(-1, Math.min(1, channelData[i])); // Clamp to -1 to 1 // eslint-disable-next-line max-len view.setInt16(offset, sample < 0 ? sample * 0x8000 : sample * 0x7fff, true); // 16-bit PCM offset += numberOfChannels * 2; } } return buffer; } writeUTFBytes(view: DataView, offset: number, string: string) { for (let i = 0; i < string.length; i++) { view.setUint8(offset + i, string.charCodeAt(i)); } } saveSound(audioBuffer: AudioBuffer, isSelect: boolean = true) { if (!audioBuffer) { return; } Entry.dispatchEvent( 'saveSoundBuffer', toWav(audioBuffer), { ...this.sound, objectId: this.object.id, }, isSelect, () => { clearHistory(); } ); } saveAfterEvent(soundInfo: ISound) { let sound: ISound; let object: IObject; if (this.lastChangeSoundInfo) { sound = this.lastChangeSoundInfo.sound; object = this.lastChangeSoundInfo.object; } else if (soundInfo) { sound = soundInfo; object = { id: soundInfo.objectId, }; } if (sound && object) { this.updateSound(sound, object); } this.lastChangeSoundInfo = null; } alertSaveModifiedSound(sound: ISound, object: IObject) { return new Promise((res) => { if (!isModified || !isModified()) { res(); return; } Entry.modal.confirm(Lang.Menus.save_modified_shape).then(async (result: boolean) => { if (result) { this.lastChangeSoundInfo = { sound, object }; this.saveSound(await getAudioBuffer(), false); } else { clearHistory(); this.updateSound(sound, object); } res(); }); }); } hide() { this.alertSaveModifiedSound(this.sound, this.object); } destory() { unregistExportFunction(); destroy(); } } export default SoundEditor; ================================================ FILE: src/class/source/DataTableSource.js ================================================ import { dmetTable } from '../../extensions/dmet'; import CloudVariable from '../../extensions/CloudVariable'; import _throttle from 'lodash/throttle'; import _cloneDeep from 'lodash/cloneDeep'; const getColumns = (table, indexes, wrapper = (x) => x) => indexes.map((index) => table.map((field) => wrapper(field[index]))); function corr(d1, d2) { const { min, pow, sqrt } = Math; const add = (a, b) => Number(a) + Number(b); const n = min(d1.length, d2.length); if (n === 0) { return 0; } [d1, d2] = [d1.slice(0, n), d2.slice(0, n)]; const [sum1, sum2] = [d1, d2].map((l) => l.reduce(add)); const [pow1, pow2] = [d1, d2].map((l) => l.reduce((a, b) => a + pow(b, 2), 0)); const mulSum = d1.map((n, i) => n * d2[i]).reduce(add); const dense = sqrt((pow1 - pow(sum1, 2) / n) * (pow2 - pow(sum2, 2) / n)); if (dense === 0) { return 0; } return ((mulSum - (sum1 * sum2) / n) / dense).toFixed(2); } class DataTableSource { #id; #name; #data; #object; #isCloud = false; #cloudDate = null; #chart = []; #cloudVariable = CloudVariable.getInstance(); #source; #copiedChart; summary; provider; description; fieldInfos; modals = []; updated = new Date(); tab = 'summary'; constructor(source = {}) { const { name, id = Entry.generateHash(), object = null, chart, data, tab = 'summary', fields = [], summary, updatedAt, provider, description, fieldInfos, } = source; this.#name = name; this.#id = id; this.#object = object; this.#source = source; this.#data = new dmetTable(source); this.#chart = chart || []; this.summary = summary; this.provider = provider; this.description = description; this.fieldInfos = fieldInfos; this.tab = tab; this.updated = updatedAt ? new Date(updatedAt) : new Date(); // 정지시 data 초기화. Entry.addEventListener('stop', () => { this.modals = []; this.#data.from({ ...source, data: this.#data.origin, fields: this.#data.originFields, }); this.#copiedChart = undefined; }); const apply = (force = false) => { if (this.modals.length > 0 && (force || this.modals.some((modal) => modal.isShow))) { this.modals.forEach((modal) => modal.setData({ source: { chart: this.copiedChart, fields: this.fields, origin: this.rows, tab: this.tab, summary: this.summary, }, }) ); } }; this.forceApply = () => apply(true); this.applyChart = _throttle(apply, 1000); } get rows() { return this.array.map(({ value }) => value); } get id() { return this.#id; } get name() { return this.#name; } set name(name) { this.#name = name; } get fields() { return this.#data.fields; } get array() { const { array } = this.#data; return array; } get chart() { return this.#chart; } get table() { return [this.fields, ...this.rows]; } get origin() { return this.#data.origin; } get copiedChart() { if (!this.#copiedChart) { this.#copiedChart = _cloneDeep(this.#chart); } return this.#copiedChart; } get dataTable() { return { id: this.id, name: this.name, chart: this.#chart, table: this.table, }; } setArray({ chart, data, fields, name }) { this.#chart = chart; this.#name = name; this.#source = { ...this.#source, fields, data, name }; this.#data.from(this.#source); } getValue(index) { return this.#data.getValue(index); } isExist(index) { const isExist = this.getValue(index); return !!(isExist === null || isExist === 0 || isExist); } appendRow(data) { return new Promise(async (resolve, reject) => { try { const appendOp = this.#data.getOperation({ type: 'appendRow', data }); this.#data.exec(appendOp); resolve(); this.applyChart(); } catch (e) { reject(e); } }); } appendCol(data) { return new Promise(async (resolve, reject) => { try { const appendOp = this.#data.getOperation({ type: 'appendCol', data }); this.#data.exec(appendOp); resolve(); this.applyChart(); } catch (e) { reject(e); } }); } insertRow(index, data) { return new Promise(async (resolve, reject) => { try { const insertOp = this.#data.getOperation({ type: 'insertRow', index, data }); this.#data.exec(insertOp); resolve(); this.applyChart(); } catch (e) { reject(e); } }); } insertCol(index, data) { return new Promise(async (resolve, reject) => { try { const insertOp = this.#data.getOperation({ type: 'insertCol', index, data }); this.#data.exec(insertOp); this.#copiedChart = this.copiedChart.map((chart) => { if (chart.xIndex >= index) { chart.xIndex++; } if (chart.yIndex >= index) { chart.yIndex++; } for (let i = 0; i < chart.categoryIndexes.length; i++) { if (chart.categoryIndexes[i] >= index) { chart.categoryIndexes[i]++; } } return chart; }); resolve(); this.applyChart(); } catch (e) { reject(e); } }); } deleteCol(index) { return new Promise(async (resolve, reject) => { try { const deleteOp = this.#data.getOperation({ type: 'deleteCol', index }); this.#data.exec(deleteOp); this.#copiedChart = this.copiedChart.map((chart) => { if (chart.xIndex == index) { chart.xIndex = -1; chart.yIndex = -1; chart.categoryIndexes = []; } else if (chart.xIndex > index) { chart.xIndex--; } if (chart.yIndex == index) { chart.yIndex = -1; chart.categoryIndexes = []; } else if (chart.yIndex > index) { chart.yIndex--; } for (let i = 0; i < chart.categoryIndexes.length; i++) { if (chart.categoryIndexes[i] == index) { chart.categoryIndexes.splice(i, 1); i--; } else if (chart.categoryIndexes[i] > index) { chart.categoryIndexes[i]--; } } return chart; }); resolve(); this.applyChart(); } catch (e) { reject(e); } }); } deleteRow(index) { return new Promise(async (resolve, reject) => { try { const deleteOp = this.#data.getOperation({ type: 'deleteRow', index }); this.#data.exec(deleteOp); resolve(); this.applyChart(); } catch (e) { reject(e); } }); } replaceValue(index, data) { return new Promise(async (resolve, reject) => { try { const replaceOp = this.#data.getOperation({ type: 'replace', index, data }); this.#data.exec(replaceOp); resolve(); this.applyChart(); } catch (e) { reject(e); } }); } toJSON() { return { _id: this.#data._id, id: this.#id, project: Entry.projectId, fields: this.fields, name: this.#name, object: this.#object, data: this.array, origin: this.#data.origin, chart: this.#chart, isCloud: this.#isCloud, cloudDate: this.#cloudDate, summary: this.summary, updated: this.updated, }; } getCoefficient(colX, colY) { return corr(...getColumns(this.rows, [colY, colX])); } clone() { return { name: this.#name, fields: [...this.fields], data: _cloneDeep(this.#data.origin), chart: [...this.#chart], }; } } export default DataTableSource; ================================================ FILE: src/class/stage.js ================================================ /** * Stage is object to handle canvas * @fileoverview This manage canvas * */ 'use strict'; import Extension from '../extensions/extension'; import { GEHelper } from '../graphicEngine/GEHelper'; import { GEHandle } from '../graphicEngine/GEHandle'; import { PIXIAtlasManager } from './pixi/atlas/PIXIAtlasManager'; /** * class for a canvas * @constructor */ Entry.Stage = class Stage { constructor() { /** @type {Dictionary} */ this.variables = {}; this.objectContainers = []; this.selectedObjectContainer = null; /** @type {null|Entry.EntryObject} */ this.selectedObject = null; this.isObjectClick = false; this._entitySelectable = true; /** @type {PIXI.Application | CreateJsApplication} */ this._app = null; this.background = GEHelper.newGraphic(); this.background.graphics.beginFill('#ffffff').drawRect(-480, -240, 960, 480); this.variableContainer = GEHelper.newContainer('variableContainer'); this.dialogContainer = GEHelper.newContainer('dialogContainer'); } /** * initialize stage with canvas * @param {!Element} canvas for stage */ initStage(canvas) { this._app = GEHelper.newApp(canvas); this.canvas = this._app.stage; this.canvas.x = 960 / 1.5 / 2; this.canvas.y = 540 / 1.5 / 2; this.canvas.scaleX = this.canvas.scaleY = 2 / 1.5; this.canvas.addChild(this.background); this.canvas.addChild(this.variableContainer); this.canvas.addChild(this.dialogContainer); this.inputField = null; this.initCoordinator(); this.initHandle(); this.mouseCoordinate = { x: 0, y: 0 }; const _addEventListener = Entry.addEventListener.bind(Entry); if (Entry.isPhone()) { canvas.ontouchstart = (e) => { Entry.dispatchEvent('canvasClick', e); Entry.stage.isClick = true; }; canvas.ontouchend = (e) => { Entry.stage.isClick = false; Entry.dispatchEvent('canvasClickCanceled', e); }; } else { const downFunc = (e) => { Entry.dispatchEvent('canvasClick', e); if (e.which == 2) { console.log('mouse wheel click disabled'); return; } Entry.stage.isClick = true; }; canvas.onmousedown = downFunc; canvas.ontouchstart = downFunc; const upFunc = (e) => { Entry.stage.isClick = false; Entry.dispatchEvent('canvasClickCanceled', e); }; canvas.onmouseup = upFunc; canvas.ontouchend = upFunc; $(document).click(({ target: { id } }) => { this.focused = id === 'entryCanvas'; }); } _addEventListener('canvasClick', () => (Entry.stage.isObjectClick = false)); _addEventListener('loadComplete', this.sortZorder.bind(this)); Entry.windowResized.attach(this, this.updateBoundRect.bind(this)); const razyScroll = _.debounce(() => { Entry.windowResized.notify(); }, 200); $(window).scroll(() => { window.requestAnimationFrame(razyScroll); }); const moveFunc = (e) => { e.preventDefault(); const { offsetY, offsetX, clientX, clientY } = Entry.Utils.convertMouseEvent(e); const roundRect = Entry.stage.getBoundRect(); const x = offsetX || (clientX && clientX - roundRect.left) || 0; const y = offsetY || (clientY && clientY - roundRect.top) || 0; this.mouseCoordinate = { x: Entry.Utils.toFixed((x / roundRect.width - 0.5) * 480), y: Entry.Utils.toFixed((y / roundRect.height - 0.5) * -270), }; Entry.dispatchEvent('stageMouseMove'); }; canvas.onmousemove = moveFunc; canvas.ontouchmove = moveFunc; canvas.onmouseout = () => Entry.dispatchEvent('stageMouseOut'); const updateObjectFunc = () => { if (Entry.engine.isState('stop')) { Entry.stage.updateObject(); } }; _addEventListener('updateObject', updateObjectFunc); _addEventListener('run', () => Entry.removeEventListener('updateObject', updateObjectFunc)); _addEventListener('stop', () => _addEventListener('updateObject', updateObjectFunc)); _addEventListener('canvasInputComplete', () => { try { const inputValue = this.inputField.value(); this.hideInputField(); if (inputValue) { ((c) => { c.setInputValue(inputValue); c.inputValue.complete = true; })(Entry.container); } } catch (exception) {} }); this.initWall(); this.initVideoContainer(); this.render(); this.dropper = Extension.getExtension('Dropper'); } render = function stageRender() { if (Entry.stage.timer) { clearTimeout(Entry.stage.timer); } let time = _.now(); Entry.stage.update(); time = _.now() - time; Entry.stage.timer = setTimeout(stageRender, 16 - (time % 16) + 16 * Math.floor(time / 16)); }; /** * redraw canvas */ update() { if (Entry.type === 'invisible') { return; } if (!Entry.requestUpdate) { Entry.requestUpdate = false; return; } this.updateForce(); if (Entry.engine.isState('stop') && this.objectUpdated) { this.objectUpdated = false; } const inputField = this.inputField; if (inputField && !inputField._isHidden) { inputField.render(); } if (Entry.requestUpdateTwice) { Entry.requestUpdateTwice = false; } else { Entry.requestUpdate = false; } } updateForce() { this._app && this._app.render(); } /** * add object entity on canvas * @param {Entry.EntryObject} object */ loadObject({ entity: { object }, scene }) { this.getObjectContainerByScene(scene).addChild(object); Entry.requestUpdate = true; } /** * add entity directly on canvas * This is use for cloned entity * @param {Entry.EntityObject} entity */ loadEntity({ parent, object }, index) { const objContainer = Entry.stage.getObjectContainerByScene(parent.scene); if (index > -1) { objContainer.addChildAt(object, index); } else { objContainer.addChild(object); } Entry.requestUpdate = true; } /** * Remove entity directly on canvas * @param {Entry.EntityObject} entity */ unloadEntity({ parent, object }) { Entry.stage.getObjectContainerByScene(parent.scene).removeChild(object); Entry.requestUpdate = true; } /** * add variable view on canvas * @param {Entry.Variable} object */ loadVariable({ view_, id }) { this.variables[id] = view_; this.variableContainer.addChild(view_); Entry.requestUpdate = true; } /** * remove variable view on canvas * @param {Entry.Variable} object */ removeVariable({ view_ }) { this.variableContainer.removeChild(view_); Entry.requestUpdate = true; } /** * add dialog on canvas * @param {Entry.Dialog} dialog */ loadDialog({ object }) { this.dialogContainer.addChild(object); } /** * Remove entity directly on canvas * @param {Entry.Dialog} dialog */ unloadDialog({ object }) { this.dialogContainer.removeChild(object); } setEntityIndex({ object }, index) { if (index === -1) { return; } const selectedObjectContainer = Entry.stage.selectedObjectContainer; const currentIndex = selectedObjectContainer.getChildIndex(object); if (currentIndex === -1 || currentIndex === index) { return; } selectedObjectContainer.setChildIndex(object, index); Entry.requestUpdate = true; } /** * sort Z index of objects */ sortZorder() { const objects = Entry.container.getCurrentObjects().slice(); const length = objects.length; const container = this.selectedObjectContainer; let index = 0; for (let i = length - 1; i >= 0; i--) { const { entity: { object }, } = objects[i]; container.setChildIndex(object, index++); } if (container) { container.children.length = length; } Entry.requestUpdate = true; } /** * sort Z index of objects while running */ sortZorderRun() { Entry.requestUpdate = true; } /** * Initialize coordinate on canvas. It is toggle by Engine. */ initCoordinator() { const tex = GEHelper.newSpriteWithCallback( `${Entry.mediaFilePath}workspace_coordinate.png` ); this.coordinator = Object.assign(tex, { scaleX: 0.5, scaleY: 0.5, x: -240, y: -135, visible: false, }); if (!GEHelper.isWebGL) { this.coordinator.tickEnabled = false; } this.canvas.addChild(this.coordinator); } /** * Toggle coordinator */ toggleCoordinator() { this.coordinator.visible = !this.coordinator.visible; Entry.requestUpdate = true; } /** * Select handle object * @param {?Entry.EntryObject} object */ selectObject(object) { //todo if (!object) { this.selectedObject = null; } else { this.selectedObject = object; } this.updateObject(); } /** * Initialize handle. Handle is use for transform object on canvas. */ initHandle() { this.handle = new GEHandle(this.canvas) .setChangeListener(this, this.updateHandle) .setEditStartListener(this, this.startEdit) .setEditEndListener(this, this.endEdit); } /** * Update handle object to modified object * object -> handle */ updateObject() { if (Entry.type === 'invisible' || Entry.type === 'playground') { return; } Entry.requestUpdate = true; this.handle.setDraggable(true); if (this.editEntity) { return; } const object = this.selectedObject; if (object) { if (object.objectType == 'textBox') { this.handle.toggleCenter(false); } else { this.handle.toggleCenter(true); } const rotateMethod = object.getRotateMethod(); if (rotateMethod == 'free') { this.handle.toggleRotation(true); this.handle.toggleDirection(true); } else if (rotateMethod == 'vertical') { this.handle.toggleRotation(false); this.handle.toggleDirection(true); } else { this.handle.toggleRotation(false); this.handle.toggleDirection(true); } if (object.getLock()) { this.handle.toggleRotation(false); this.handle.toggleDirection(false); this.handle.toggleResize(false); this.handle.toggleCenter(false); this.handle.setDraggable(false); } else { this.handle.toggleResize(true); } this.handle.setVisible(Entry.objectEditable); const entity = object.entity; this.handle.setWidth(entity.getScaleX() * entity.getWidth()); this.handle.setHeight(entity.getScaleY() * entity.getHeight()); let regX; let regY; if (entity.type == 'textBox') { // maybe 0. if (entity.getLineBreak()) { regX = entity.regX * entity.scaleX; regY = -entity.regY * entity.scaleY; } else { const fontAlign = entity.getTextAlign(); regY = -entity.regY * entity.scaleY; switch (fontAlign) { case Entry.TEXT_ALIGN_LEFT: regX = (-entity.getWidth() / 2) * entity.scaleX; break; case Entry.TEXT_ALIGN_CENTER: regX = entity.regX * entity.scaleX; break; case Entry.TEXT_ALIGN_RIGHT: regX = (entity.getWidth() / 2) * entity.scaleX; break; } } } else { regX = (entity.regX - entity.width / 2) * entity.scaleX; regY = (entity.height / 2 - entity.regY) * entity.scaleY; } const rotation = (entity.getRotation() / 180) * Math.PI; this.handle.setX(entity.getX() - regX * Math.cos(rotation) - regY * Math.sin(rotation)); this.handle.setY( -entity.getY() - regX * Math.sin(rotation) + regY * Math.cos(rotation) ); this.handle.setRegX((entity.regX - entity.width / 2) * entity.scaleX); this.handle.setRegY((entity.regY - entity.height / 2) * entity.scaleY); this.handle.setRotation(entity.getRotation()); this.handle.setDirection(entity.getDirection()); this.objectUpdated = true; this.handle.setVisible(Entry.objectEditable && object.entity.getVisible()); if (object.entity.getVisible()) { this.handle.render(); } } else { this.handle.setVisible(false); } //this.toggleHandleEditable(!object.getLock()); } // handle -> object updateHandle() { this.editEntity = true; const handle = this.handle; const entity = this.selectedObject.entity; if (entity.lineBreak) { entity.setHeight(handle.height / entity.getScaleY()); entity.setWidth(handle.width / entity.getScaleX()); } else { if (entity.width !== 0) { let scaleX = Math.abs(handle.width / entity.width); if (entity.flip) { scaleX *= -1; } entity.setScaleX(scaleX); } if (entity.height !== 0) { entity.setScaleY(handle.height / entity.height); } } const direction = (handle.rotation / 180) * Math.PI; if (entity.type == 'textBox') { entity.syncFont(); var newRegX = handle.regX / entity.scaleX; var newRegY = handle.regY / entity.scaleY; if (entity.getLineBreak()) { entity.setX(handle.x); entity.setY(-handle.y); } else { switch (entity.getTextAlign()) { case Entry.TEXT_ALIGN_LEFT: entity.setX(handle.x - (handle.width / 2) * Math.cos(direction)); entity.setY(-handle.y + (handle.width / 2) * Math.sin(direction)); break; case Entry.TEXT_ALIGN_CENTER: entity.setX(handle.x); entity.setY(-handle.y); break; case Entry.TEXT_ALIGN_RIGHT: entity.setX(handle.x + (handle.width / 2) * Math.cos(direction)); entity.setY(-handle.y - (handle.width / 2) * Math.sin(direction)); break; } } } else { var newRegX = entity.width / 2 + handle.regX / entity.scaleX; entity.setX( handle.x + handle.regX * Math.cos(direction) - handle.regY * Math.sin(direction) ); entity.setRegX(newRegX); var newRegY = entity.height / 2 + handle.regY / entity.scaleY; entity.setY( -handle.y - handle.regX * Math.sin(direction) - handle.regY * Math.cos(direction) ); entity.setRegY(newRegY); } entity.setDirection(handle.direction); entity.setRotation(handle.rotation); this.editEntity = false; } startEdit() { const { entity } = this.selectedObject || {}; _.result(entity, 'initCommand'); } endEdit() { const { entity } = this.selectedObject || {}; _.result(entity, 'checkCommand'); } initWall() { const wall = GEHelper.newContainer('wall'); wall.mouseEnabled = false; const tex = GEHelper.newWallTexture(`${Entry.mediaFilePath}media/bound.png`); const newSide = (x, y, sx, sy) => { const sp = GEHelper.newWallSprite(tex); sp.x = x; sp.y = y; sx ? (sp.scaleX = sx) : 0; sy ? (sp.scaleY = sy) : 0; wall.addChild(sp); return sp; }; wall.up = newSide(-240, -135 - 30, 480 / 30, 0); wall.down = newSide(-240, 135, 480 / 30, 0); wall.right = newSide(240, -135, 0, 270 / 30); wall.left = newSide(-240 - 30, -135, 0, 270 / 30); this.canvas.addChild(wall); this.wall = wall; } initVideoContainer() { this.videoContainer = GEHelper.getNewContainer(); this.canvas.addChildAt(this.videoContainer, 2); this.overlayContainer = GEHelper.getNewContainer(); this.canvas.addChildAt(this.overlayContainer, 3); } getCanvasElement(id) { let canvas = document.getElementById(id); if (!canvas) { canvas = window.top.document.getElementById(id); } return canvas; } /** * show inputfield from the canvas */ showInputField() { const THIS = this; const isWebGL = GEHelper.isWebGL; GEHelper.disableTickByEngine(); if (!this.inputField) { this.inputField = _createInputField(); this.inputSubmitButton = _createSubmitButton(); } this.inputField.value(''); if (isWebGL) { this.canvas.addChild(this.inputField.getPixiView()); } this.inputField.show(); this.canvas.addChild(this.inputSubmitButton); Entry.requestUpdateTwice = true; function _createInputField() { const posX = 15; const posY = 275; const isWebGL = GEHelper.isWebGL; const classRef = isWebGL ? window.PIXICanvasInput : CanvasInput; const inputField = new classRef({ canvas: THIS.getCanvasElement('entryCanvas'), fontSize: 20, fontFamily: EntryStatic.fontFamily || "NanumGothic, 'Nanum Gothic'", fontColor: '#2c313d', width: 520, height: 24, padding: 13, borderWidth: 2, borderColor: '#e2e2e2', borderRadius: 10, boxShadow: 'none', innerShadow: 'none', x: posX, y: posY, readonly: false, topPosition: true, onsubmit() { Entry.dispatchEvent('canvasInputComplete'); }, }); if (isWebGL) { const canvas = THIS.canvas; const globalScale = canvas.scale.x; const textView = inputField.getPixiView(); textView.scale.set(1 / globalScale); textView.position.set( posX / globalScale - canvas.x / globalScale, posY / globalScale - canvas.y / globalScale ); } return inputField; } //_createInputField function _createSubmitButton() { const { confirm_button } = EntryStatic.images || {}; const path = confirm_button || `${Entry.mediaFilePath}stage/submit.png`; const inputSubmitButton = GEHelper.newSpriteWithCallback(path, () => { Entry.requestUpdate = true; }); inputSubmitButton.mouseEnabled = true; inputSubmitButton.x = 190; inputSubmitButton.y = 71.5; inputSubmitButton.scaleX = 0.84; inputSubmitButton.scaleY = 0.84; inputSubmitButton.cursor = 'pointer'; const eventType = isWebGL ? 'pointerdown' : 'mousedown'; inputSubmitButton.on(eventType, () => { if (!THIS.inputField._readonly) { Entry.dispatchEvent('canvasInputComplete'); } }); return inputSubmitButton; } //_createSubmitButton } /** * remove inputfield from the canvas */ hideInputField() { if (!this.inputField) { return; } GEHelper.tickByEngine(); if (GEHelper.isWebGL) { this.canvas.removeChild(this.inputField.getPixiView()); } this.inputField.value(''); this.inputField.hide(); this.canvas.removeChild(this.inputSubmitButton); Entry.requestUpdate = true; } /** * init object containers */ initObjectContainers() { const scenes = Entry.scene.scenes_; if (!_.isEmpty(scenes)) { for (let i = 0; i < scenes.length; i++) { this.objectContainers[i] = this.createObjectContainer(scenes[i]); } this.selectedObjectContainer = this.objectContainers[0]; } else { const obj = this.createObjectContainer(Entry.scene.selectedScene); this.objectContainers.push(obj); this.selectedObjectContainer = obj; } if (Entry.type !== 'invisible' && Entry.type !== 'playground') { this.canvas.addChild(this.selectedObjectContainer); } this.selectObjectContainer(Entry.scene.selectedScene); } /** * select object container by scene * @param {Entry.Scene} scene */ selectObjectContainer(scene) { const containers = this.objectContainers; const canvas = this.canvas; if (_.isEmpty(canvas) || _.isEmpty(containers)) { return; } GEHelper.resManager.activateScene(scene && scene.id); const newContainer = this.getObjectContainerByScene(scene); containers.forEach(canvas.removeChild.bind(canvas)); this.selectedObjectContainer = newContainer; canvas.addChildAt(newContainer, 4); } /** * init object containers */ createObjectContainer(scene) { return Object.assign(GEHelper.newContainer('[Stage] SceneContainer'), { scene }); } /** * remove object container * @param {scene model} scene */ removeObjectContainer(scene) { const containers = this.objectContainers; const objContainer = this.getObjectContainerByScene(scene); const canvas = this.canvas; if (canvas) { canvas.removeChild(objContainer); } GEHelper.resManager.removeScene(scene.id); containers.splice(containers.indexOf(objContainer), 1); } /** * get object container * @param {scene model} scene */ getObjectContainerByScene({ id }) { return _.find(this.objectContainers, ({ scene } = {}) => scene.id === id); } moveSprite({ shiftKey, keyCode }) { const selectedObject = this.selectedObject; if (!selectedObject || !Entry.stage.focused || selectedObject.getLock()) { return; } const distance = shiftKey ? 1 : 5; const entity = selectedObject.entity; switch (keyCode) { case 38: //up entity.setY(entity.getY() + distance); break; case 40: //down entity.setY(entity.getY() - distance); break; case 37: //left entity.setX(entity.getX() - distance); break; case 39: //right entity.setX(entity.getX() + distance); break; } this.updateObject(); } getBoundRect(e) { if (!this._boundRect) { return this.updateBoundRect(); } return this._boundRect; } updateBoundRect(e) { return (this._boundRect = this.canvas.canvas.getBoundingClientRect()); } getDom(query) { const key = query.shift(); if (key === 'canvas') { return this.canvas.canvas; } } setEntitySelectable(value) { this._entitySelectable = value; } isEntitySelectable() { return Entry.engine.isState('stop') && this._entitySelectable && !this.dropper.isShow; } destroy() { let destroyOption; if (GEHelper.isWebGL) { destroyOption = { children: true, texture: false, baseTexture: false }; this.objectContainers.forEach((c) => c.destroy(destroyOption)); //this.handle.destroy(); // 추상화 아직 안됨. PIXIAtlasManager?.clearProject?.(); } else { //do nothing } if (this._app) { this._app.destroy(destroyOption); this._app = null; } this.handle = null; this.objectContainers = null; } }; ================================================ FILE: src/class/stamp_entity.js ================================================ /** * @fileoverview stamp entity object is class for entry stamp entity canvas view. */ 'use strict'; import { GEHelper } from '../graphicEngine/GEHelper'; /** * Construct stamp entity class * @param {!Entry.EntryObject} object * @param {!Entry.EntityObject} entity * @constructor */ Entry.StampEntity = class StampEntity extends Entry.EntityObject { constructor(object, entity) { /** @type {!string} */ super(object); this.parent = object; this.type = object.objectType; this.isClone = true; this.isStamp = true; this.width = entity.getWidth(); this.height = entity.getHeight(); if (this.type == 'sprite') { this.object = GEHelper.cloneStamp(entity); if (entity.effect) { this.effect = _.clone(entity.effect); this.applyFilter(); } } else if (this.type == 'textBox') { } this.object.entity = entity; } }; ================================================ FILE: src/class/time_wait.js ================================================ 'use strict'; Entry.TimeWaitManager = { add(id, cb, ms) { if (!Entry.timerInstances) { Entry.timerInstances = []; } const instance = new Entry.TimeWait(id, cb, ms); Entry.timerInstances.push(instance); }, remove(id) { if (!Entry.timerInstances || Entry.timerInstances.length == 0) { return; } Entry.timerInstances = Entry.timerInstances.filter((instance) => { if (instance.id === id) { return false; } else { return true; } }); }, }; Entry.TimeWait = class TimeWait { constructor(id, cb, ms) { this.id = id; this.cb = cb; this.ms = ms; this.startTime = performance.now(); this.timer = setTimeout(this.callback.bind(this), ms); } callback() { if (this.cb) { this.cb(); this.destroy(); } } pause() { if (this.timer) { this.ms = this.ms - (performance.now() - this.startTime); clearTimeout(this.timer); } } resume() { this.timer = setTimeout(this.callback.bind(this), this.ms); this.startTime = performance.now(); } destroy() { delete this.timer; delete this.cb; delete this.ms; delete this.startTime; Entry.TimeWaitManager.remove(this.id); } }; ================================================ FILE: src/class/toast.js ================================================ /** * @fileoverview Toast object for notification */ 'use strict'; /** * Constructor of toast * @constructor */ Entry.Toast = class Toast { constructor() { this.toasts_ = []; /** @type {Element} */ const exist = document.getElementById('entryToastContainer'); if (exist) { Entry.modalContainer.removeChild(exist); } this.body_ = Entry.createElement('div', 'entryToastContainer'); this.body_.addClass('entryToastContainer'); Entry.modalContainer.appendChild(this.body_); } warning(title, message, isNotAutoDispose) { const toast = Entry.createElement('div', 'entryToast'); toast.addClass('entryToast'); toast.addClass('entryToastWarning'); toast.bindOnClick(() => { Entry.toast.body_.removeChild(toast); }); const toastTitle = Entry.createElement('div', 'entryToast'); toastTitle.addClass('entryToastTitle'); toastTitle.textContent = title; toast.appendChild(toastTitle); const toastMessage = Entry.createElement('p', 'entryToast'); toastMessage.addClass('entryToastMessage'); toastMessage.textContent = message; toast.appendChild(toastMessage); this.toasts_.push(toast); this.body_.appendChild(toast); const f = () => { toast.style.opacity = 1; var timer = setInterval(() => { if (toast.style.opacity < 0.05) { clearInterval(timer); toast.style.display = 'none'; Entry.removeElement(toast); } toast.style.opacity *= 0.9; }, 20); }; if (!isNotAutoDispose) { window.setTimeout(f, 1000); } } success(title, message, isNotAutoDispose) { const toast = Entry.createElement('div', 'entryToast'); toast.addClass('entryToast'); toast.addClass('entryToastSuccess'); toast.bindOnClick(() => { Entry.toast.body_.removeChild(toast); }); const toastTitle = Entry.createElement('div', 'entryToast'); toastTitle.addClass('entryToastTitle'); toastTitle.textContent = title; toast.appendChild(toastTitle); const toastMessage = Entry.createElement('p', 'entryToast'); toastMessage.addClass('entryToastMessage'); toastMessage.textContent = message; toast.appendChild(toastMessage); this.toasts_.push(toast); this.body_.appendChild(toast); const f = () => { toast.style.opacity = 1; var timer = setInterval(() => { if (toast.style.opacity < 0.05) { clearInterval(timer); toast.style.display = 'none'; Entry.removeElement(toast); } toast.style.opacity *= 0.9; }, 20); }; if (!isNotAutoDispose) { window.setTimeout(f, 1000); } } alert(title, message, isNotAutoDispose) { const toast = Entry.createElement('div', 'entryToast'); let timer; toast.addClass('entryToast'); toast.addClass('entryToastAlert'); toast.bindOnClick(() => { Entry.toast.body_.removeChild(toast); if (timer) { clearInterval(timer); } }); const toastTitle = Entry.createElement('div', 'entryToast'); toastTitle.addClass('entryToastTitle'); toastTitle.textContent = title; toast.appendChild(toastTitle); const toastMessage = Entry.createElement('p', 'entryToast'); toastMessage.addClass('entryToastMessage'); if (Array.isArray(message)) { toastMessage.textContent = message.reduce( (total, current) => `${total}\n${current}`, '' ); } else { toastMessage.textContent = message; } toast.appendChild(toastMessage); this.toasts_.push(toast); this.body_.appendChild(toast); const f = () => { toast.style.opacity = 1; timer = setInterval(() => { if (toast.style.opacity < 0.05) { clearInterval(timer); toast.style.display = 'none'; //check element already removed from parent if (toast.parentElement) { Entry.toast.body_.removeChild(toast); } } toast.style.opacity *= 0.9; }, 20); }; if (!isNotAutoDispose) { window.setTimeout(f, 5000); } return toast; } isOpen(target) { const activated = this.toasts_.filter((toast) => toast.style.display !== 'none'); if (target) { return activated.includes(target); } return activated.length > 0; } }; ================================================ FILE: src/class/variable/answerVariable.js ================================================ import Variable from './variable'; class AnswerVariable extends Variable { constructor(variable) { Entry.assert(variable.variableType === 'answer', 'Invalid variable type given'); super(variable); } updateView() { if (!this.view_) { return; } if (this.isVisible()) { this._adjustSingleViewPosition(); this.textView_.text = this.getName(); if (this.isNumber()) { const v = Number(this.getValue()); if (parseInt(this.getValue(), 10) == this.getValue()) { this.valueView_.text = v; } else { this.valueView_.text = Number(v) .toFixed(1) .replace('.00', ''); } } else { this.valueView_.text = this.getValue(); } if (this._nameWidth === null) { this._nameWidth = this.textView_.getMeasuredWidth(); } this._adjustSingleValueViewPosition(); if (this._valueWidth === null) { this._valueWidth = this.valueView_.getMeasuredWidth(); } this._adjustSingleViewBox('#F57DF1'); Entry.requestUpdate = true; } } } export default AnswerVariable; ================================================ FILE: src/class/variable/index.js ================================================ import SttVariable from './sttVariable'; import AnswerVariable from './answerVariable'; import ListVariable from './listVariable'; import SlideVariable from './slideVariable'; import TimerVariable from './timerVariable'; import Variable from './variable'; Entry.Variable = Variable; Entry.Variable.create = (variableMetadata) => { const { variableType } = variableMetadata; switch (variableType) { case 'stt': return new SttVariable(variableMetadata); case 'answer': return new AnswerVariable(variableMetadata); case 'list': return new ListVariable(variableMetadata); case 'slide': return new SlideVariable(variableMetadata); case 'timer': return new TimerVariable(variableMetadata); case 'variable': default: return new Variable(variableMetadata); } }; ================================================ FILE: src/class/variable/listVariable.js ================================================ import Variable from './variable'; import { GEHelper } from '../../graphicEngine/GEHelper'; import { GEDragHelper } from '../../graphicEngine/GEDragHelper'; class ListVariable extends Variable { get LIST_MAX_LENGTH() { return 5000; } _trimToMaxLength() { if (this.array_ && this.array_.length > this.LIST_MAX_LENGTH) { this.array_ = this.array_.slice(-this.LIST_MAX_LENGTH); this._showListFullWarning(); } } _showListFullWarning() { Entry.toast?.alert( Lang?.Workspace?.list_cant_add_item || 'Warning', Lang?.Workspace?.list_max_length_exceeded || `You can add up to ${this.LIST_MAX_LENGTH} items to a list.` ); } constructor(variable) { Entry.assert(variable.variableType === 'list', 'Invalid variable type given'); super(variable); let array = variable.array ? variable.array : []; if (array.length > this.LIST_MAX_LENGTH) { array = array.slice(-this.LIST_MAX_LENGTH); setTimeout(() => { Entry.modal?.alert( Lang?.Workspace?.list_truncated_on_load || `The list exceeded ${this.LIST_MAX_LENGTH} items.`, Lang?.Workspace?.list_truncated_on_load_title || 'Notice' ); }, 100); } this.array_ = array; if (!variable.isClone) { this.width_ = variable.width ? variable.width : 100; this.height_ = variable.height ? variable.height : 120; this.scrollPosition = 0; } } generateView(variableIndex) { this.view_ = GEHelper.newContainer(); this.rect_ = GEHelper.newGraphic(); this.view_.addChild(this.rect_); this.view_.variable = this; this.view_.visible = this.visible_; this.view_.mouseEnabled = true; this.view_.mouseChildren = true; GEDragHelper.handleDrag(this.view_); this.titleView_ = GEHelper.textHelper.newText( '', this.FONT, '#000000', 'alphabetic', 'center' ); //todo [박봉배] textview_.width 를 $width 로 변경. this.titleView_.$width = this.width_ - 2 * this.BORDER; if (GEHelper.isWebGL) { this.titleView_.x = (this.width_ - this.titleView_.width) / 2; this.titleView_.y = this.BORDER - 1; } else { this.titleView_.x = this.width_ / 2; this.titleView_.y = this.BORDER + 11; } this.view_.addChild(this.titleView_); const { stage_list_resize_handle } = EntryStatic.images || {}; this.resizeHandle_ = GEHelper.newSpriteWithCallback( stage_list_resize_handle || `${Entry.mediaFilePath}stage_list_resize_handle.png`, () => { Entry.requestUpdate = true; } ); this.resizeHandle_.mouseEnabled = true; this.resizeHandle_.scaleX = 0.7; this.resizeHandle_.scaleY = 0.7; this.view_.addChild(this.resizeHandle_); this.resizeHandle_.list = this; GEDragHelper.handleDrag(this.resizeHandle_); this.resizeHandle_.on(GEDragHelper.types.OVER, function () { this.cursor = 'nwse-resize'; }); this.resizeHandle_.on(GEDragHelper.types.DOWN, function (evt) { // if(Entry.type != 'workspace') return; this.list.isResizing = true; this.offset = { x: evt.stageX * 0.75 - this.list.getWidth(), y: evt.stageY * 0.75 - this.list.getHeight(), }; this.parent.cursor = 'nwse-resize'; }); this.resizeHandle_.on(GEDragHelper.types.MOVE, function (evt) { // if(Entry.type != 'workspace') return; this.list.setWidth(evt.stageX * 0.75 - this.offset.x); this.list.setHeight(evt.stageY * 0.75 - this.offset.y); this.list.updateView(); }); this.view_.on(GEDragHelper.types.OVER, function () { this.cursor = 'move'; }); this.view_.on(GEDragHelper.types.DOWN, function (evt) { if (Entry.type !== 'workspace' || this.variable.isResizing) { return; } this.offset = { x: this.x - (evt.stageX * 0.75 - 240), y: this.y - (evt.stageY * 0.75 - 135), }; this.cursor = 'move'; }); this.view_.on(GEDragHelper.types.UP, function () { this.cursor = 'initial'; this.variable.isResizing = false; }); this.view_.on(GEDragHelper.types.MOVE, function (evt) { if (Entry.type !== 'workspace' || this.variable.isResizing) { return; } this.variable.setX(evt.stageX * 0.75 - 240 + this.offset.x); this.variable.setY(evt.stageY * 0.75 - 135 + this.offset.y); this.variable.updateView(); }); //todo [박봉배] 아래줄 삭제 하는게 맞겠죠? 리스트 아이템인데, 생성을 아래쪽에서 함. //this.elementView = this._createListElementView(); this.scrollButton_ = GEHelper.newGraphic(); this.scrollButton_.mouseEnabled = true; this.scrollButton_.cursor = 'pointer'; GEDragHelper.handleDrag(this.scrollButton_); this.scrollButton_.graphics.f('#aaaaaa').rr(0, 0, 7, 30, 3.5); this.view_.addChild(this.scrollButton_); this.scrollButton_.y = 25; this.scrollButton_.list = this; this.scrollButton_.on(GEDragHelper.types.DOWN, function (evt) { // if(Entry.type != 'workspace') return; this.list.isResizing = true; this.offsetY = evt.stageY - this.y / 0.75; }); this.scrollButton_.on(GEDragHelper.types.MOVE, function (evt) { // if(Entry.type != 'workspace') return; const stageY = evt.stageY; let yPos = (stageY - this.offsetY) * 0.75; const min = 25; const max = this.list.getHeight() - 30; if (yPos < min) { yPos = min; } if (yPos > max) { yPos = max; } this.y = yPos; this.list.updateView(); }); if (this.getX() && this.getY()) { this.setX(this.getX()); this.setY(this.getY()); } else { const listLength = Entry.variableContainer.lists_.length; this.setX(-Math.floor((listLength % 24) / 6) * 110 + 120); this.setY(variableIndex * 24 + 20 - 135 - Math.floor(listLength / 6) * 145); } this.setVisible(this.isVisible()); Entry.stage.loadVariable(this); } getArray() { if (!this.isRealTime_) { return this.array_; } else { const { array } = this.cloudVariable.get({ variableType: this.type, id: this.id_, }) || {}; return array || this.array_; } } setArray(array) { if (!this.isRealTime_) { this.array_ = array; this.updateView(); Entry.requestUpdateTwice = true; } else { return new Promise(async (resolve, reject) => { try { const target = { variableType: this.type, id: this.id_, }; await this.cloudVariable.setArray(target, array); this.updateView(); resolve(); } catch (e) { reject(e); } }); } } appendValue(value) { if (!this.isRealTime_) { if (!this.array_) { this.array_ = []; } this.array_.push({ data: value, }); this._trimToMaxLength(); this.updateView(); } else { return new Promise(async (resolve, reject) => { try { const target = { variableType: this.type, id: this.id_, }; await this.cloudVariable.append(target, value); const list = this.cloudVariable.get(target); if (list) { this.array_ = list.array; } else { this.array_.push({ data: value, }); } this.updateView(); resolve(); } catch (e) { reject(e); } }); } } deleteValue(index) { if (!this.isRealTime_) { this.array_.splice(index - 1, 1); this.updateView(); } else { return new Promise(async (resolve, reject) => { try { const target = { variableType: this.type, id: this.id_, }; await this.cloudVariable.delete(target, index - 1); const list = this.cloudVariable.get(target); if (list) { this.array_ = list.array; } else { this.array_.splice(index - 1, 1); } this.updateView(); resolve(); } catch (e) { reject(e); } }); } } insertValue(index, data) { if (!this.isRealTime_) { this.array_.splice(index - 1, 0, { data }); this._trimToMaxLength(); this.updateView(); } else { return new Promise(async (resolve, reject) => { try { const target = { variableType: this.type, id: this.id_, }; await this.cloudVariable.insert(target, index - 1, data); const list = this.cloudVariable.get(target); if (list) { this.array_ = list.array; } else { this.array_.splice(index - 1, 0, { data }); } this.updateView(); resolve(); } catch (e) { reject(e); } }); } } replaceValue(index, data) { if (!this.isRealTime_) { this.array_[index - 1].data = data; this.updateView(); } else { return new Promise(async (resolve, reject) => { try { const target = { variableType: this.type, id: this.id_, }; await this.cloudVariable.replace(target, index - 1, data); const list = this.cloudVariable.get(target); if (list) { this.array_ = list.array; } else { this.array_[index - 1].data = data; } this.updateView(); resolve(); } catch (e) { reject(e); } }); } } updateView() { if (!this.view_) { return; } if (this.isVisible()) { this._adjustSingleViewPosition(); this.resizeHandle_.x = this.width_ - 10; this.resizeHandle_.y = this.height_ + 16 - 10; const arr = this.getArray(); let name = this.getName(); if (this.object_) { const obj = Entry.container.getObject(this.object_); if (obj) { name = `${obj.name}:${name}`; } } this.titleView_.text = name; if (this.titleView_.getMeasuredWidth() > this.width_) { name = `${name}..`; while (this.titleView_.getMeasuredWidth() > this.width_) { name = `${name.substr(0, name.length - 3)}..`; this.titleView_.text = name; } } if (GEHelper.isWebGL) { this.titleView_.x = (this.width_ - this.titleView_.width) / 2 + 3; } else { this.titleView_.x = this.width_ / 2 + 3; } const colorSet = EntryStatic.colorSet.canvas || {}; this.rect_.graphics .clear() .f('#ffffff') .ss(1, 2, 0) .s(colorSet.border || '#aac5d5') .rr(0, 0, this.width_ + 7, this.height_ + 22, this.RECT_RADIUS); let listChild; while ((listChild = this.view_.children[4])) { this.view_.removeChild(listChild); listChild.destroy && listChild.destroy(); } const maxView = Math.floor((this.getHeight() - 15) / 20); const isOverFlow = maxView < arr.length; const totalWidth = this.getWidth(); let wrapperWidth = totalWidth - 2 * this.BORDER - (isOverFlow ? 30 : 20); if (isOverFlow) { if (this.scrollButton_.y > this.getHeight() - 30) { this.scrollButton_.y = this.getHeight() - 30; } //todo [박봉배] _createListElementView 로 코드 이동 // this.elementView.valueWrapper.graphics // .clear() // .f('#1bafea') // .rr(20, -2, wrapperWidth, 17, 2); this.scrollButton_.x = totalWidth - 6; this.scrollPosition = Math.floor( ((this.scrollButton_.y - 25) / (this.getHeight() - 25 - 30)) * (arr.length - maxView) ); } else { //todo [박봉배] _createListElementView 로 코드 이동 // this.elementView.valueWrapper.graphics // .clear() // .f('#1bafea') // .rr(20, -2, wrapperWidth, 17, 2); this.scrollPosition = 0; } this.scrollButton_.visible = isOverFlow; const _cache = {}; //because of min Width of list //maxLen can not be under 3 //so start from 3 let maxLen = 3; wrapperWidth -= 6; for ( let i = this.scrollPosition; i < this.scrollPosition + maxView && i < arr.length; i++ ) { this.elementView = this._createListElementView(wrapperWidth + 14); if ( Entry.getMainWS() && Entry.getMainWS().getMode() === Entry.Workspace.MODE_VIMBOARD ) { this.elementView.indexView.text = i; } else { this.elementView.indexView.text = i + 1; } const text = String(arr?.[i]?.data ?? 'undefined'); const valueView = this.elementView.valueView; const cachedText = _cache[text.substr(0, 150)]; if (cachedText) { valueView.text = cachedText; } else { let execText = text.substr(0, maxLen); let charIndex = maxLen; valueView.text = text; if (valueView.getMeasuredWidth() > wrapperWidth) { valueView.text = execText; while ( valueView.getMeasuredWidth() < wrapperWidth && text[charIndex] !== undefined ) { execText += text[charIndex++]; valueView.text = execText; } let subCnt = 1; while (valueView.getMeasuredWidth() > wrapperWidth) { execText = `${execText.substr(0, execText.length - subCnt)}..`; valueView.text = execText; subCnt = 3; } } else { execText = text; } _cache[text.substr(0, 150)] = execText; maxLen = Math.max(execText.length, maxLen); } this.elementView.y = (i - this.scrollPosition) * 20 + 23; this.view_.addChild(this.elementView); } } Entry.requestUpdate = true; } _createListElementView(wrapperWidth) { const elementView = GEHelper.newContainer(); const indexView = GEHelper.textHelper.newText('', this.FONT, '#000000', 'middle'); const colorSet = EntryStatic.colorSet.canvas || {}; if (GEHelper.isWebGL) { indexView.y = this.GL_LIST_POS.INDEX_Y; } else { indexView.y = 12; } elementView.addChild(indexView); elementView.indexView = indexView; const valueWrapper = GEHelper.newGraphic(); elementView.addChild(valueWrapper); elementView.valueWrapper = valueWrapper; elementView.valueWrapper.graphics .clear() .f(colorSet.list || '#4f80ff') .rr(18, 4, wrapperWidth, 17, 2); const valueView = GEHelper.textHelper.newText('', this.VALUE_FONT, '#ffffff', 'middle'); valueView.x = 24; if (GEHelper.isWebGL) { valueView.y = this.GL_LIST_POS.VALUE_Y; } else { valueView.y = 12; } elementView.addChild(valueView); elementView.valueView = valueView; elementView.x = this.BORDER; return elementView; } syncModel_(variableModel) { if (!this.isCloud_ && !this.isRealTime_) { this.array_ = variableModel.array; } this.setWidth(variableModel.width); this.setHeight(variableModel.height); super.syncModel_(variableModel); } toJSON() { const json = super.toJSON(); json.width = this.getWidth(); json.height = this.getHeight(); json.array = JSON.parse(JSON.stringify(this.getArray())); return json; } } export default ListVariable; ================================================ FILE: src/class/variable/slideVariable.js ================================================ import Variable from './variable'; import { GEHelper } from '../../graphicEngine/GEHelper'; import { GEDragHelper } from '../../graphicEngine/GEDragHelper'; class SlideVariable extends Variable { constructor(variable) { Entry.assert(variable.variableType === 'slide', 'Invalid variable type given'); super(variable); this.setMinValue(variable.minValue); this.setMaxValue(variable.maxValue); } generateView(variableIndex) { const slide = this; this.view_ = GEHelper.newContainer(); this.rect_ = GEHelper.newGraphic(); this.view_.addChild(this.rect_); this.view_.variable = this; this.view_.visible = this.visible_; this.view_.mouseEnabled = true; this.view_.mouseChildren = true; GEDragHelper.handleDrag(this.view_); this.wrapper_ = GEHelper.newGraphic(); this.view_.addChild(this.wrapper_); this.textView_ = GEHelper.textHelper.newText('name', this.FONT, '#000000', 'alphabetic'); this.textView_.x = 4; if (GEHelper.isWebGL) { this.textView_.y = this.GL_VAR_POS.LABEL_Y; } else { this.textView_.y = 1; } this.view_.addChild(this.textView_); this.valueView_ = GEHelper.textHelper.newText( 'value', this.VALUE_FONT, '#ffffff', 'alphabetic' ); this.view_.on(GEDragHelper.types.DOWN, function(evt) { if (Entry.type !== 'workspace') { return; } this.offset = { x: this.x - (evt.stageX * 0.75 - 240), y: this.y - (evt.stageY * 0.75 - 135), }; }); this.view_.on(GEDragHelper.types.MOVE, function(evt) { if (Entry.type !== 'workspace' || slide.isAdjusting) { return; } this.variable.setX(evt.stageX * 0.75 - 240 + this.offset.x); this.variable.setY(evt.stageY * 0.75 - 135 + this.offset.y); this.variable.updateView(); }); this.view_.addChild(this.valueView_); let width = this.textView_.getMeasuredWidth() + this.valueView_.getMeasuredWidth() + 26; width = Math.max(width, 90); this.maxWidth = width - 20; this.slideBar_ = GEHelper.newGraphic(); this.slideBar_.graphics .beginFill('#d8d8d8') .s('#d8d8d8') .ss(1) .rr(10, 10, this.maxWidth, 15, 4); this.slideBar_.mouseEnabled = true; GEDragHelper.handleDrag(this.slideBar_); this.slideBar_.on(GEDragHelper.types.DOWN, (evt) => { if (!Entry.engine.isState('run')) { return; } const value = evt.stageX * 0.75 - (this.getX() + 240 + 5) + 5; slide.setSlideCommandX(value); }); this.view_.addChild(this.slideBar_); const position = this.getSlidePosition(this.maxWidth); const { stage_variable_slider } = EntryStatic.images || {}; this.valueSetter_ = GEHelper.newSpriteWithCallback( stage_variable_slider || `${Entry.mediaFilePath}stage_variable_slider.png`, () => { Entry.requestUpdate = true; } ); this.valueSetter_.cursor = 'pointer'; this.valueSetter_.scaleX = 0.8; this.valueSetter_.scaleY = 0.8; this.valueSetter_.mouseEnabled = true; this.valueSetter_.y = 9; this.valueSetter_.regX = 0.5; GEDragHelper.handleDrag(this.valueSetter_); this.valueSetter_.on(GEDragHelper.types.DOWN, function(evt) { if (!Entry.engine.isState('run')) { return; } slide.isAdjusting = true; this.offsetX = evt.stageX * 0.75 - this.x; }); this.valueSetter_.on(GEDragHelper.types.MOVE, function(evt) { if (!Entry.engine.isState('run')) { return; } const value = (evt.stageX * 0.75) - this.offsetX + 5; //박봉배 - value 값의 min/max 는 다른곳에서 체크 하므로, 이곳에서는 로직 삭제 하겠음. slide.setSlideCommandX(value); }); this.valueSetter_.on(GEDragHelper.types.UP, () => { slide.isAdjusting = false; }); this.view_.addChild(this.valueSetter_); const variableLength = Entry.variableContainer.variables_.length; if (this.getX() && this.getY()) { this.setX(this.getX()); this.setY(this.getY()); } else { this.setX(10 - 240 + Math.floor(variableLength / 11) * 80); this.setY(variableIndex * 24 + 20 - 135 - Math.floor(variableLength / 11) * 264); } this.setVisible(this.isVisible()); Entry.stage.loadVariable(this); } updateView() { if (!this.view_) { return; } if (this.isVisible()) { this._adjustSingleViewPosition(); const oldContent = this.textView_.text; let newContent; if (this.object_) { const obj = Entry.container.getObject(this.object_); if (obj) { newContent = `${obj.name}:${this.getName()}`; } else { newContent = this.getName(); } } else { newContent = this.getName(); } if (oldContent !== newContent) { this.textView_.text = newContent; this._nameWidth = null; } if (this._nameWidth === null) { this._nameWidth = this.textView_.getMeasuredWidth(); } this._adjustSingleValueViewPosition(); let value = String(this.getValue()); if (this.isFloatPoint()) { const reg = /\.(.*)/; //check the value is float const ret = reg.exec(value); if (!ret) { value += '.00'; } else { while (reg.exec(value)[1].length < 2) { value += '0'; } } } this.valueView_.text = value; if (this._valueWidth === null) { this._valueWidth = this.valueView_.getMeasuredWidth(); } let width = this._nameWidth + this._valueWidth + 35; const colorSet = EntryStatic.colorSet.canvas || {}; width = Math.max(width, 90); this.rect_.graphics .clear() .f('#ffffff') .ss(1, 2, 0) .s(colorSet.border || '#aac5d5') .rr(0, -14, width, 42, 4); this.wrapper_.graphics .clear() .f(colorSet.slideVariable || '#4f80ff') .ss(1, 2, 0) .s(colorSet.slideVariable || '#4f80ff') .rr(this._nameWidth + 14, -10, this._valueWidth + 15, 16, this.RECT_RADIUS); width = this._nameWidth + this._valueWidth + 26; width = Math.max(width, 90); this.maxWidth = width - 16; this.slideBar_.graphics .clear() .beginFill('#d8d8d8') .s('#d8d8d8') .ss(1) .rr(6, 16, this.maxWidth + 4, 5, 2); this.valueSetter_.x = this.getSlidePosition(this.maxWidth); // this.valueSetter_.graphics // .clear() // .beginFill('#1bafea') // .s('#A0A1A1') // .ss(1) // .dc(position, 10 + 0.5, 3); } Entry.requestUpdate = true; } getValue() { const value = super.getValue(); if (this.isNumber()) { return Number(value); } else { return value; } } setValue(value) { const numValue = Number(value); if (numValue < this.minValue_) { this.value_ = this.minValue_; } else if (numValue > this.maxValue_) { this.value_ = this.maxValue_; } else { this.value_ = numValue; } super.setValue(this.value_); } setSlideCommandX(value) { if (!this.valueSetter_.command) { this.valueSetter_.command = {}; } let commandX = typeof value === 'undefined' ? 10 : value; commandX = Math.max(commandX, 10); commandX = Math.min(this.maxWidth + 10, commandX); this.valueSetter_.command.x = commandX; this.updateSlideValueByView(); } updateSlideValueByView() { const maxWidth = this.maxWidth; const position = Math.max(this.valueSetter_.command.x - 10, 0); let ratio = position / maxWidth; if (ratio < 0) { ratio = 0; } if (ratio > 1) { ratio = 1; } const minValue = parseFloat(this.minValue_); const maxValue = parseFloat(this.maxValue_); let value = (minValue + Number(Math.abs(maxValue - minValue) * ratio)).toFixed(2); value = parseFloat(value); if (value < minValue) { value = this.minValue_; } else if (value > maxValue) { value = this.maxValue_; } if (!this.isFloatPoint()) { value = Math.round(value); } this.setValue(value); } getSlidePosition(width) { const minValue = this.minValue_; const maxValue = this.maxValue_; const value = this.value_; const ratio = Math.abs(value - minValue) / Math.abs(maxValue - minValue); return width * ratio + 6; } toJSON() { const json = super.toJSON(); json.minValue = this.minValue_; json.maxValue = this.maxValue_; return json; } } export default SlideVariable; ================================================ FILE: src/class/variable/sttVariable.js ================================================ import Variable from './variable'; import { GEHelper } from '../../graphicEngine/GEHelper'; class SttVariable extends Variable { constructor(variable) { Entry.assert(variable.variableType === 'stt', 'Invalid variable type given'); super(variable); } updateView() { if (!this.view_) { return; } if (this.isVisible()) { this._adjustSingleViewPosition(); this.textView_.text = this.getName(); if (this.isNumber()) { const v = Number(this.getValue()); if (parseInt(this.getValue(), 10) == this.getValue()) { this.valueView_.text = v; } else { this.valueView_.text = Number(v) .toFixed(1) .replace('.00', ''); } } else { this.valueView_.text = this.getValue(); } if (this._nameWidth === null) { this._nameWidth = this.textView_.getMeasuredWidth(); } this._adjustSingleValueViewPosition(); if (this._valueWidth === null) { this._valueWidth = this.valueView_.getMeasuredWidth(); } this._adjustSingleViewBox('#8222ff'); } Entry.requestUpdate = true; } _adjustSingleValueViewPosition() { this.valueView_.x = 12; if (GEHelper.isWebGL) { this.valueView_.y = this.GL_VAR_POS.VALUE_Y + 22; } else { this.valueView_.y = 1.5 + 22; } } _adjustSingleViewBox(boxFillAndStrokeColor) { const rectWidth = Math.max(this._valueWidth + 22, this._nameWidth + 10); const colorSet = EntryStatic.colorSet.canvas || {}; this.rect_.graphics .clear() .f('#ffffff') .ss(1, 2, 0) .s(colorSet.border || '#aac5d5') .rr(0, -14, rectWidth, 45, 4); this.wrapper_.graphics .clear() .f(boxFillAndStrokeColor) .ss(1, 2, 0) .s(boxFillAndStrokeColor) .rr(4, 10, this._valueWidth + 15, 16, this.RECT_RADIUS); } // @summary 음성 인식(STT) 블록의 종류를 반환합니다. // @return {string[]} 음성 인식(STT) 블록의 종류 getSttTypes() { if (!this.sttTypes) { this.sttTypes = Object.entries(Entry.AI_UTILIZE_BLOCK.audio.getBlocks()) .filter(([, block]) => block.class === 'stt') .map(([key]) => key); } return this.sttTypes; } checkVisible(removeBlock, notIncludeSelf) { if (!this.isVisible() || Entry.engine.isState('run')) { return; } const objects = Entry.container.getAllObjects(); const sttTypes = this.getSttTypes(); for (let i = 0, len = objects.length; i < len; i++) { const code = objects[i].script; for (let j = 0; j < sttTypes.length; j++) { const blocks = code.getBlockList(false, sttTypes[j]); if (notIncludeSelf) { const index = blocks.indexOf(removeBlock); if (index > -1) { blocks.splice(index, 1); } } if (blocks.length > 0) { return; } } } this.setVisible(false); } reset() { this.setName(Lang.template.voice_title_text); this.setValue('-'); } } export default SttVariable; ================================================ FILE: src/class/variable/timerVariable.js ================================================ import Variable from './variable'; class TimerVariable extends Variable { constructor(variable) { Entry.assert(variable.variableType === 'timer', 'Invalid variable type given'); super(variable); } updateView() { if (!this.view_) { return; } if (this.isVisible()) { this._adjustSingleViewPosition(); this.textView_.text = this.getName(); if (this._nameWidth === null) { this._nameWidth = this.textView_.getMeasuredWidth(); } this._adjustSingleValueViewPosition(); if (this.isNumber()) { this.valueView_.text = Number(this.getValue()) .toFixed(1) .replace('.00', ''); } else { this.valueView_.text = this.getValue(); } if (this._valueWidth === null) { this._valueWidth = this.valueView_.getMeasuredWidth(); } this._adjustSingleViewBox('#f4af18'); } Entry.requestUpdate = true; } } export default TimerVariable; ================================================ FILE: src/class/variable/variable.js ================================================ 'use strict'; import { GEHelper } from '../../graphicEngine/GEHelper'; import { GEDragHelper } from '../../graphicEngine/GEDragHelper'; import CloudVariable from '../../extensions/CloudVariable'; import _throttle from 'lodash/throttle'; import BinPacking from '../../util/binPacking'; const VariableBP = new BinPacking(460, 250); const bpReplace = _throttle(VariableBP.replace.bind(VariableBP)); /** * 기본 변수블록 객체 * @param {Object} variable variableMetadata */ class Variable { get RECT_RADIUS() { return 7; } get GL_VAR_POS() { return { VALUE_Y: -8.5, LABEL_Y: -9.5, }; } get GL_LIST_POS() { return { INDEX_Y: 5, VALUE_Y: 6, }; } constructor(variable) { Entry.assert(typeof variable.name === 'string', 'Variable name must be given'); /** @type {string} */ this.name_ = variable.name; /** @type {string} */ this.id_ = variable.id ? variable.id : Entry.generateHash(); this.type = variable.variableType || 'variable'; /** @type {entry object.id} */ this.object_ = variable.object || null; /** @type {boolean} */ this.isCloud_ = variable.isCloud || false; this.isRealTime_ = variable.isRealTime || false; this.cloudDate = variable.cloudDate || false; this.cloudVariable = CloudVariable.getInstance(); this._nameWidth = null; this._valueWidth = null; /** @type {number||string} */ const parsedValue = Entry.parseNumber(variable.value); if (typeof parsedValue === 'number') { this.value_ = parsedValue; } else if (!variable.value) { this.value_ = 0; } else { this.value_ = variable.value; } if (!variable.isClone) { /** @type {boolean} */ this.visible_ = variable.visible || typeof variable.visible === 'boolean' ? variable.visible : true; /** @type {number} */ this.x_ = variable.x ? variable.x : null; /** @type {number} */ this.y_ = variable.y ? variable.y : null; const fontFamily = EntryStatic.fontFamily || "NanumGothic, 'Nanum Gothic'"; this.BORDER = 6; this.FONT = `10pt ${fontFamily}`; this.VALUE_FONT = `9pt ${fontFamily}`; } Entry.addEventListener('workspaceChangeMode', this.updateView.bind(this)); } /** * Generate variable view on canvas * @param {number} variableIndex index of this variable for render position */ generateView(variableIndex) { const type = this.type; if (type === 'variable' || type === 'timer' || type === 'answer' || type === 'stt') { this.view_ = GEHelper.newContainer(); this.rect_ = GEHelper.newGraphic(); this.view_.addChild(this.rect_); this.view_.variable = this; this.view_.visible = this.visible_; this.view_.mouseEnabled = true; GEDragHelper.handleDrag(this.view_); // Stage 의 변수박스를 만든다. this.wrapper_ = GEHelper.newGraphic(); this.view_.addChild(this.wrapper_); this.textView_ = GEHelper.textHelper.newText( 'asdf', this.FONT, '#000000', 'alphabetic' ); this.textView_.x = 4; if (GEHelper.isWebGL) { this.textView_.y = this.GL_VAR_POS.LABEL_Y; } else { this.textView_.y = 2.5; } this.view_.addChild(this.textView_); this.valueView_ = GEHelper.textHelper.newText( 'asdf', this.VALUE_FONT, '#ffffff', 'alphabetic' ); const variableLength = Entry.variableContainer.variables_.length; const { x, y } = VariableBP.add( this.id_, this.x_, this.y_, this.getRealWidth(), this.getRealHeight() ); if (this.getX() && this.getY()) { this.setX(this.getX()); this.setY(this.getY()); } else { //TODO // console.log(10 - 240 + Math.floor((variableLength % 66) / 11) * 80, x); // console.log( // variableIndex * 28 + 20 - 135 - Math.floor(variableLength / 11) * 264, // y // ); this.setX(x - 230); this.setY(y - 105); // this.setX(10 - 240 + Math.floor((variableLength % 66) / 11) * 80); // this.setY(variableIndex * 28 + 20 - 135 - Math.floor(variableLength / 11) * 264); } this.view_.addChild(this.valueView_); if (Entry.type === 'workspace') { this.view_.cursor = 'move'; } this.view_.on(GEDragHelper.types.DOWN, function(evt) { if (Entry.type !== 'workspace') { return; } this.offset = { x: this.x - (evt.stageX * 0.75 - 240), y: this.y - (evt.stageY * 0.75 - 135), }; }); this.view_.on(GEDragHelper.types.MOVE, function(evt) { if (Entry.type !== 'workspace') { return; } this.variable.setX(evt.stageX * 0.75 - 240 + this.offset.x); this.variable.setY(evt.stageY * 0.75 - 135 + this.offset.y); this.variable.updateView(); }); } this.setVisible(this.isVisible()); Entry.stage.loadVariable(this); } /** * this.view_ 를 수정 후, 엔트리에 새로 그리기 요청을 한다. * generateView 혹은 updateView 가 이상하게 그려진다면, 혹시 variableType 이 잘못되었는지 확인. */ updateView() { if (!this.view_) { return; } if (this.isVisible()) { this._adjustSingleViewPosition(); const oldContent = this.textView_.text; let newContent; if (this.object_) { const obj = Entry.container.getObject(this.object_); if (obj) { newContent = `${obj.name}:${this.getName()}`; } else { newContent = this.getName(); } } else { newContent = this.getName(); } if (oldContent !== newContent) { this.textView_.text = newContent; this._nameWidth = null; } if (this.isNumber()) { if (this.value_[0] !== 0 && Entry.isInteger(this.value_)) { this.valueView_.text = `${this.getValue()}`; } else { this.valueView_.text = Number(this.getValue()) .toFixed(2) .replace('.00', ''); } } else { this.valueView_.text = this.getValue(); } if (this._nameWidth === null) { this._nameWidth = this.textView_.getMeasuredWidth(); } this._adjustSingleValueViewPosition(); // INFO: Number체크는 slide 일때만 하도록 처리 기본 문자로 처리함(#4876) if (this._valueWidth === null) { this._valueWidth = this.valueView_.getMeasuredWidth(); } const colorSet = EntryStatic.colorSet.canvas || {}; this._adjustSingleViewBox(colorSet.variable || '#4f80ff'); } bpReplace(this.id_, this.x_, this.y_, this.getRealWidth(), this.getRealHeight()); Entry.requestUpdate = true; } /** * stage 내 변수 / 타이머 / 대답 뷰의 크기와 위치를 조정한다. * wrapper 의 이미지는 동일하다. * rr(RectRadius) 의 인자는 각각 x, y, width, height, radius * @param {string} boxFillAndStrokeColor * @protected */ _adjustSingleViewBox(boxFillAndStrokeColor) { // TODO slider updateView 만 rect_.graphics 를 따로 씀. rr 인자 constants 로 묶을 것. const colorSet = EntryStatic.colorSet.canvas || {}; this.rect_.graphics .clear() .f('#ffffff') .ss(1, 2, 0) .s(colorSet.border || '#aac5d5') .rr(0, -14, this._nameWidth + this._valueWidth + 35, 24, 4); this.wrapper_.graphics .clear() .f(boxFillAndStrokeColor) .ss(1, 2, 0) .s(boxFillAndStrokeColor) .rr(this._nameWidth + 14, -10, this._valueWidth + 15, 16, this.RECT_RADIUS); } _adjustSingleViewPosition() { this.view_.x = this.getX(); this.view_.y = this.getY(); } _adjustSingleValueViewPosition() { this.valueView_.x = this._nameWidth + 21; if (GEHelper.isWebGL) { this.valueView_.y = this.GL_VAR_POS.VALUE_Y; } else { this.valueView_.y = 1.5; } } /** * Variable name getter * @return {string} */ getName() { return this.name_; } /** * Variable name setter * @param {!string} variableName */ setName(variableName) { Entry.assert(typeof variableName === 'string', 'Variable name must be string'); this.name_ = variableName; this._nameWidth = null; this.updateView(); Entry.requestUpdateTwice = true; } /** * Variable id getter * @return {string} */ getId() { return this.id_; } setId(id) { this.id_ = id; } /** * Variable value getter * @return {number} */ getValue() { if (!this.isRealTime_) { return this.value_; } else { const { value } = this.cloudVariable.get({ variableType: this.type, id: this.id_, }) || {}; return value || this.value_; } } /** * Verify value is number * @return {boolean} */ isNumber() { return Entry.Utils.isNumber(this.value_); } /** * Variable value setter * @param {!string} variableValue */ setValue(value) { if (!this.isRealTime_) { this.value_ = value; this._valueWidth = null; this.updateView(); Entry.requestUpdateTwice = true; } else { return new Promise(async (resolve, reject) => { try { await this.cloudVariable.set( { variableType: this.type, id: this.id_, }, value ); this.value_ = value; this._valueWidth = null; this.updateView(); Entry.requestUpdateTwice = true; resolve(); } catch (e) { reject(e); } }); } } /** * Variable visible state getter * @return {boolean} */ isVisible() { return this.visible_; } /** * Variable visible state setter * @param {!boolean} visibleState */ setVisible(visibleState) { Entry.assert(typeof visibleState === 'boolean', 'Variable visible state must be boolean'); if (this.visible_ === visibleState) { return; } this.view_.visible = visibleState; this.visible_ = visibleState; this.updateView(); } /** * X coordinate setter * @param {number} x */ setX(x) { /** @type {number} */ this.x_ = x; this.updateView(); } /** * X coordinate getter * @return {number} */ getX() { return this.x_; } /** * Y coordinate setter * @param {number} y */ setY(y) { /** @type {number} */ this.y_ = y; this.updateView(); } /** * Y coordinate getter * @return {number} */ getY() { return this.y_; } /** * width setter * @param {number} width */ setWidth(width) { /** @type {number} */ this.width_ = width < 100 ? 100 : width; this.updateView(); } /** * width getter * @return {number} */ getWidth() { return this.width_; } getRealWidth() { return Math.ceil( this.textView_.getMeasuredWidth(this.name_) + this.textView_.getMeasuredWidth(this.getValue()) + 40 ); } /** * height setter * @param {number} height */ setHeight(height) { /** @type {number} */ this.height_ = height < 100 ? 100 : height; this.updateView(); } /** * height getter * @return {number} */ getHeight() { return this.height_; } getRealHeight() { return Math.ceil(this.textView_.getMeasuredHeight() + 12); } /** * save current state data to 'snapshot_' */ takeSnapshot() { this.snapshot_ = this.toJSON(); } /** * load snapshot to current variable */ loadSnapshot() { this.snapshot_ && this.syncModel_(this.snapshot_); delete this.snapshot_; } /** * sync this model with parameter * @param {!entity model}variableModel * @protected */ syncModel_(variableModel) { if (!this.isCloud_ && !this.isRealTime_) { this.setValue(variableModel.value); } this.setName(variableModel.name); this.setX(variableModel.x); this.setY(variableModel.y); this.setVisible(variableModel.visible); this.isCloud_ = variableModel.isCloud; this.isRealTime_ = variableModel.isRealTime; this.cloudDate = variableModel.cloudDate; } /** * convert this variable's data to JSON. * @return {JSON} */ toJSON() { const json = {}; json.name = this.name_; json.id = this.id_; json.visible = this.visible_; json.value = this.value_; json.variableType = this.type; json.isCloud = this.isCloud_; json.isRealTime = this.isRealTime_; json.cloudDate = this.cloudDate; json.object = this.object_; json.x = this.x_; json.y = this.y_; return json; } /** * Remove self */ remove() { //this.parent.dialog = null; VariableBP.remove(this.id_); Entry.stage.removeVariable(this); } /** * clone self */ clone() { return Entry.Variable.create(Object.assign(this.toJSON(), { isClone: true })); } getType() { return this.type; } getMinValue() { return this.minValue_; } setMinValue(value) { this._valueWidth = null; const minValue = value || 0; this.minValue_ = minValue; if (this.value_ < minValue) { this.setValue(minValue); } this.isMinFloat = Entry.isFloat(this.minValue_); this.updateView(); } getMaxValue() { return this.maxValue_; } setMaxValue(value) { this._valueWidth = null; const maxValue = value || 100; this.maxValue_ = maxValue; if (this.value_ > maxValue) { this.value_ = maxValue; } this.isMaxFloat = Entry.isFloat(this.maxValue_); this.updateView(); } isFloatPoint() { return this.isMaxFloat || this.isMinFloat; } getCloudDate() { return this.cloudDate; } setCloudDate(cloudDate) { this.cloudDate = cloudDate; } getArray() { return this.array_; } setArray(array) { this.array_ = array; this.updateView(); Entry.requestUpdateTwice = true; } } // Entry.Variable = Variable; // add export export default Variable; ================================================ FILE: src/class/variable_container.js ================================================ /** * @fileoverview Variable container for variable object */ 'use strict'; import SimpleBar from 'simplebar'; import xssFilters from 'xss-filters'; import CloudVariable from '../extensions/CloudVariable'; import _get from 'lodash/get'; import _isFunction from 'lodash/isFunction'; import _find from 'lodash/find'; import _includes from 'lodash/includes'; import _some from 'lodash/some'; import _memoize from 'lodash/memoize'; /** * Block variable constructor * @param {variable model} variable * @constructor */ Entry.VariableContainer = class VariableContainer { constructor() { this.cloudVariable = CloudVariable.getInstance(); this.variables_ = []; this.messages_ = []; this.lists_ = []; this.functions_ = {}; this.viewMode_ = 'all'; this.selected = null; this.variableAddPanel = { isOpen: false, info: { object: null, isCloud: false, isRealTime: false, }, }; this.listAddPanel = { isOpen: false, info: { object: null, isCloud: false, isRealTime: false, }, }; this.messageAddPanel = { isOpen: false, info: { object: null, isCloud: false, }, }; this.selectedVariable = null; this._variableRefs = []; this._messageRefs = []; this._functionRefs = []; this._filterTabs = {}; this.listView_ = null; Entry.addEventListener('workspaceChangeMode', this.updateList.bind(this)); Entry.addEventListener( 'changeFuncVariableListSize', this.updateFuncVariableList.bind(this) ); } #removeChildrenClass({ children }, className) { for (const index in children) { const dom = children[index]; if (dom.removeClass) { dom.removeClass(className); } } } createDom(view) { const createElement = Entry.createElement; const that = this; this.filterElements = {}; this.view_ = view; const selectView = createElement('table') .addClass('entryVariableSelectorWorkspace') .appendTo(this.view_); $(selectView).on('click tab', 'td', function () { if (this.disabled) { return; } Entry.do( 'variableContainerSelectFilter', this.getAttribute('data-type'), that.viewMode_ ); }); let selectTrView = createElement('tr').appendTo(selectView); const allButton = this.createSelectButton('all') .addClass('selected', 'allButton') .appendTo(selectTrView); this.filterElements.all = allButton; allButton.setAttribute('rowspan', '2'); this.filterElements.variable = this.createSelectButton( 'variable', Entry.variableEnable ).appendTo(selectTrView); this.filterElements.message = this.createSelectButton( 'message', Entry.messageEnable ).appendTo(selectTrView); selectTrView = createElement('tr').appendTo(selectView); this.filterElements.list = this.createSelectButton('list', Entry.listEnable).appendTo( selectTrView ); this.filterElements.func = this.createSelectButton('func', Entry.functionEnable).appendTo( selectTrView ); const listViewContainer = createElement('div').addClass('entryVariableListWorkspace'); this.view_.appendChild(listViewContainer); const listView = createElement('div') .addClass('entryVariableAdd_box') .appendTo(listViewContainer); $(listView).on('mouseenter', '.entryVariableListElementWorkspace', function () { this.addClass('active'); }); $(listView).on('mouseleave', '.entryVariableListElementWorkspace', function () { this.removeClass('active'); }); this.listView_ = listView; this.generateAddButtons(); this.generateVariableAddView(); this.generateListAddView(); this.generateMessageAddView(); return view; } generateAddButtons() { const createElement = Entry.createElement; const variableAddButton = createElement('button').addClass('entryVariableAddWorkspace'); variableAddButton.textContent = Lang.Workspace.variable_add; this.variableAddButton_ = variableAddButton; const messageAddButton = createElement('button').addClass('entryVariableAddWorkspace'); messageAddButton.textContent = Lang.Workspace.message_add; this.messageAddButton_ = messageAddButton; const listAddButton = createElement('button').addClass('entryVariableAddWorkspace'); listAddButton.textContent = Lang.Workspace.list_create; this.listAddButton_ = listAddButton; const functionAddButton = createElement('button') .addClass('entryVariableAddWorkspace') .addClass('funcAddButton'); functionAddButton.textContent = Lang.Workspace.function_add; this.functionAddButton_ = functionAddButton; } /** * @param {String} type * @param {?Boolean} isEnable */ createSelectButton(type, isEnable = true) { const view = Entry.createElement('td').addClass('entryVariableSelectButtonWorkspace', type); const textView = Entry.createElement('div'); const text = Entry.createElement('span').addClass('text').appendTo(textView); view.setAttribute('data-type', type); view.appendChild(textView); text.innerText = Lang.Workspace[type]; if (isEnable === false) { view.addClass('disabled'); view.disabled = true; } this._filterTabs[type] = view; return view; } /** * @param {String} type */ selectFilter(type) { _.each(this.view_.getElementsByTagName('td'), (elem) => { if (elem.hasClass(type)) { elem.addClass('selected'); } else { elem.removeClass('selected'); } }); this.viewMode_ = type; this.select(); this.updateList(); } updateVariableAddView(type = 'variable') { const { info: { isCloud, object, isRealTime }, view, } = this._getAddPanel(type); const { cloudCheck, globalCheck, localCheck, cloudWrapper } = view; this.#removeChildrenClass(cloudCheck, 'on'); const [normal, cloud, realtime] = cloudCheck.children; if (isCloud) { cloud.addClass('on'); } else if (isRealTime) { realtime.addClass('on'); } else { normal.addClass('on'); } if (object) { globalCheck.removeClass('on'); localCheck.addClass('on'); cloudWrapper.addClass('entryVariableAddSpaceUnCheckedWorkspace'); } else { globalCheck.addClass('on'); localCheck.removeClass('on'); cloudWrapper.removeClass('entryVariableAddSpaceUnCheckedWorkspace'); } } /** * @param {object|Entry.Variable} object */ select(object) { object = this.selected == object ? null : object; if (this.selected) { this.selected.listElement.removeClass('unfold'); this.selected.listElement.addClass('fold'); this.selected.listElement.removeClass('selected'); if (this.selected.callerListElement) { $(this.selected.callerListElement).remove(); delete this.selected.callerListElement; } this.selected = null; } if (!object) { return; } object.listElement.addClass('selected'); this.selected = object; this.selected.listElement.removeClass('fold'); this.selected.listElement.addClass('unfold'); if (object instanceof Entry.Variable) { if (object.type === 'variable') { this.generateVariableSettingView(object); this.updateVariableSettingView(object); } else if (object.type === 'list') { this.generateListSettingView(object); this.updateListSettingView(object); } if (object.object_) { Entry.container.selectObject(object.object_, true); } } else if (object instanceof Entry.Func) { this.generateFuncSettingView(object); this.updateFuncSettingView(object); } else { this.renderMessageReference(object); } } getMessage(id) { return _.find(this.messages_, { id }); } /** * @param {object} message */ renderMessageReference(message) { const messageId = message.id; const hasInFunction = this.hasParamBlockInFunction(messageId); const callers = this._messageRefs.filter(({ block: { params } }) => _includes(params, messageId) ); message.usedView && $(message.usedView).remove(); const usedWrapper = Entry.createElement('div').addClass('use_block'); const boxSubject = Entry.createElement('span').addClass('box_sjt').appendTo(usedWrapper); if (callers.length) { boxSubject.textContent = Entry.Utils.stringFormat( Lang.Workspace.use_block_objects1, callers.length ); const listView = Entry.createElement('ul').addClass('obj_list').appendTo(usedWrapper); const fragment = document.createDocumentFragment(); callers.forEach((caller) => { const element = Entry.createElement('li'); const object = caller.object; if (!object.entity) { return; } !caller.object.thumbnailView_ && caller.object.generateView(); const thumb = element.appendChild(caller.object.thumbnailView_.cloneNode()); thumb.addClass('thmb'); element.appendChild(thumb); Entry.createElement('span').addClass('text').appendTo(element).textContent = `${caller.object.name} : ${Lang.Blocks[`START_${caller.block.type}`]}`; element.bindOnClick((e) => { e.stopPropagation(); if (Entry.playground.object !== caller.object) { Entry.container.selectObject(); Entry.container.selectObject(caller.object.id, true); } const block = caller.block; const board = _.result(block.view, 'getBoard'); if (board) { board.setSelectedBlock(block.view); } Entry.playground.toggleOnVariableView(); Entry.playground.changeViewMode('variable'); }); fragment.appendChild(element); }); listView.appendChild(fragment); } else { const caution = Entry.createElement('div') .addClass('caution_dsc') .appendTo(usedWrapper); caution.textContent = Lang.Workspace.no_use; boxSubject.textContent = Entry.Utils.stringFormat( Lang.Workspace.use_block_objects2, callers.length ); } if (hasInFunction) { const usedInFunction = Entry.createElement('div') .addClass('used_function_dsc') .appendTo(usedWrapper); usedInFunction.textContent = Lang.Workspace.use_block_function; } message.usedView = usedWrapper; message.listElement.appendChild(usedWrapper); } /** * @param {object} variable */ renderVariableReference(variable) { const variableId = variable.id_; const hasInFunction = this.hasParamBlockInFunction(variableId); const callers = this._variableRefs.filter(({ block: { params } }) => _includes(params, variableId) ); const usedWrapper = Entry.createElement('div').addClass('use_obj'); const usedSubject = Entry.createElement('span').addClass('box_sjt').appendTo(usedWrapper); const listView = Entry.createElement('ul').addClass('obj_list').appendTo(usedWrapper); if (callers.length) { usedSubject.textContent = Entry.Utils.stringFormat( Lang.Workspace.use_block_objects1, callers.length ); const fragment = document.createDocumentFragment(); callers.forEach((caller) => { const element = Entry.createElement('li'); const object = caller.object; if (!object.entity) { return; } !caller.object.thumbnailView_ && caller.object.generateView(); const thumb = caller.object.thumbnailView_.cloneNode(); thumb.addClass('thmb'); element.appendChild(thumb); Entry.createElement('span').addClass('text').appendTo(element).textContent = `${caller.object.name} : ${Lang.Blocks[`VARIABLE_${caller.block.type}`]}`; element.variable = variable; element.bindOnClick((e) => { e.stopPropagation(); if (Entry.playground.object != caller.object) { Entry.container.selectObject(); Entry.container.selectObject(caller.object.id, true); } const block = caller.block; const board = _.result(block.view, 'getBoard'); if (board) { board.setSelectedBlock(block.view); } Entry.playground.toggleOnVariableView(); Entry.playground.changeViewMode('variable'); }); fragment.appendChild(element); }); listView.appendChild(fragment); } else { usedSubject.textContent = Entry.Utils.stringFormat( Lang.Workspace.use_block_objects2, callers.length ); Entry.createElement('div').addClass('caution_dsc').appendTo(listView).textContent = Lang.Workspace.no_use; } if (hasInFunction) { const usedInFunction = Entry.createElement('div') .addClass('used_function_dsc') .appendTo(listView); usedInFunction.textContent = Lang.Workspace.use_block_function; } this.variableSettingView && this.variableSettingView.appendChild(usedWrapper); this.listSettingView && this.listSettingView.appendChild(usedWrapper); } generateFuncSettingView(func) { const createElement = Entry.createElement; const element = createElement('div') .addClass('attr_inner_box') .bindOnClick((e) => e.stopPropagation()); if (this.funcSettingView) { $(this.funcSettingView).remove(); delete this.funcSettingView; } this.funcSettingView = element; const funcAttr = createElement('div').addClass('func_attr').appendTo(element); if (this._isPythonMode()) { funcAttr.addClass('hidden'); } const boxSubject = createElement('span').addClass('box_sjt').appendTo(funcAttr); boxSubject.textContent = Lang.Workspace.func_property; this.generateFuncDefaultView(funcAttr, func); this.generateFuncLocalVariableView(funcAttr, func); this.generateFuncValuesView(funcAttr, func); this.renderFunctionReference(func); this.funcSettingView.func = funcAttr; func.listElement.appendChild(this.funcSettingView); } isUsedFunction(func) { if ([...this._functionRefs].some((item) => item.block.data.type === `func_${func.id}`)) { return true; } else if ( Object.keys(this.functions_).some((key) => { const item = this.functions_[key]?.content.findByType(`func_${func.id}`); return Boolean(item); }) ) { return true; } return false; } generateFuncDefaultView(element, func) { const createElement = Entry.createElement; // 슬라이드 입력창 const checkInputBox = createElement('div').addClass('check_inpt').appendTo(element); const resultCheckBox = createElement('div').addClass('chk_box').appendTo(checkInputBox); element.resultCheck = createElement('span') .addClass('entryFuncAddResultCheckWorkspace') .bindOnClick(() => { if (this.isUsedFunction(func)) { return Entry.modal.alert(Lang.Msgs.cannot_delete_function); } Entry.do('funcChangeType', func); }) .appendTo(resultCheckBox); const resultCheckText = createElement('span') .addClass('chk_text') .bindOnClick(() => { if (this.isUsedFunction(func)) { return Entry.modal.alert(Lang.Msgs.cannot_delete_function); } Entry.do('funcChangeType', func); }) .appendTo(resultCheckBox); resultCheckText.textContent = Lang.Workspace.check_result_value; } generateFuncLocalVariableView(element, func) { const createElement = Entry.createElement; const checkInputBox = createElement('div').addClass('check_inpt').appendTo(element); const localVarCheckBox = createElement('div').addClass('chk_box').appendTo(checkInputBox); element.localVarCheck = createElement('span') .addClass('entryFuncAddLocalVarCheckWorkspace') .bindOnClick(() => { const isUseBlock = func.content.hasBlockType([ 'set_func_variable', 'get_func_variable', ]); if (isUseBlock) { Entry.modal .confirm(Lang.Msgs.local_variable_deletion_warning) .then((result) => { if (result) { func.content .getBlockList(false, ['set_func_variable', 'get_func_variable']) .map( Entry.Utils.runAsyncCurry(async (block) => { Entry.do('destroyBlock', block).isPass(true); }) ); Entry.do('toggleFuncUseLocalVariables', func); } }); } else { Entry.do('toggleFuncUseLocalVariables', func); } }) .appendTo(localVarCheckBox); const localVarCheckText = createElement('span') .addClass('chk_text') .bindOnClick(() => { element.localVarCheck.click(); }) .appendTo(localVarCheckBox); localVarCheckText.textContent = Lang.Workspace.check_local_variable; const countInputBox = createElement('div').addClass('cnt_inpt').appendTo(checkInputBox); const buttonMinus = createElement('a') .addClass('btn_cnt') .bindOnClick((e) => { const disabled = e?.target?.hasAttribute('disabled'); if (disabled) { return; } Entry.do('funcLocalVarChangeLength', func, 'minus'); Entry.dispatchEvent('changeFuncVariableListSize'); }) .appendTo(countInputBox); this.funcSettingView.minus = buttonMinus; const limitValue = 10; const maxlength = 2; const countInput = createElement('input').appendTo(countInputBox); countInput.setAttribute('autocomplete', 'off'); countInput.setAttribute('type', 'text'); countInput.setAttribute('maxlength', maxlength); countInput.value = func.localVariables?.length || 0; countInput.onblur = (e) => { const disabled = e?.target?.hasAttribute('disabled'); if (disabled) { return; } let value = _get(e, 'target.value', 0); if (value >= limitValue) { value = limitValue; } Entry.do('funcLocalVarChangeLength', func, value); Entry.dispatchEvent('changeFuncVariableListSize'); }; countInput.onkeypress = Entry.Utils.blurWhenEnter; const buttonPlus = createElement('a') .addClass('btn_cnt') .addClass('plus') .bindOnClick((e) => { const disabled = e?.target?.hasAttribute('disabled'); if (disabled) { return; } const variableLength = func.localVariables.length; if (variableLength < limitValue) { Entry.do('funcLocalVarChangeLength', func, 'plus'); Entry.dispatchEvent('changeFuncVariableListSize'); } }) .appendTo(countInputBox); this.funcSettingView.plus = buttonPlus; this.funcSettingView.lengthInput = countInput; } generateFuncValuesView(element, func) { const localVariables = func.getLocalVariables() || []; if (localVariables?.length === 0) { return; } const createElement = Entry.createElement; const countGroup = createElement('div').addClass('cnt_group').appendTo(element); const countLabel = createElement('div').addClass('cnt_label').appendTo(countGroup); countLabel.textContent = Lang.Workspace.local_variable; const scrollBox = createElement('div') .addClass('scroll_box simplebar-content-wrapper') .appendTo(countGroup); const el = new SimpleBar(scrollBox, { autoHide: false }); const parent = /* html */ `
    {1}
`; this.funcSettingView.countGroup = countGroup; this.funcSettingView.scrollBox = scrollBox; this.funcSettingView.simpleBar = el; const listValues = el.getContentElement(); this.funcSettingView.listValues = listValues; const infinityScroll = new Entry.VirtualScroll(listValues, { dataWrapper: parent, itemHeight: 24, groupSize: 10, }); this.funcSettingView.infinityScroll = infinityScroll; const $listValues = $(listValues); $listValues.empty(); $listValues.off(); const data = localVariables?.map((data, i) => { const value = String(data.name).replace(/\$/g, '$'); return this.createListValueElement(i, value, 1); }); infinityScroll.assignData(data); infinityScroll.show(); $listValues.on( 'change', 'input', _.debounce((e) => { const { target } = e; const index = target.getAttribute('data-index'); func.changeNameLocalVariable(target.value, index); }) ); $listValues.on('focus', 'input', Entry.Utils.setFocused); $listValues.on('keypress', 'input', Entry.Utils.blurWhenEnter); $listValues.on('click', 'a', function () { const index = this.getAttribute('data-index'); Entry.do('removeFuncLocalVariableByIndex', func, index); Entry.dispatchEvent('changeFuncVariableListSize'); }); } updateFuncScrollBar(func) { const view = this.funcSettingView; if (!view) { return; } if (!view.infinityScroll) { this.generateFuncValuesView(this.funcSettingView.func, func); requestAnimationFrame(() => { this.updateFuncScrollBar(func); }); return; } const localVariables = func.getLocalVariables() || []; const { infinityScroll, countGroup, lengthInput, simpleBar, scrollBox } = view; lengthInput.value = func.localVariables?.length || 0; if (localVariables?.length === 0) { countGroup?.addClass('entryRemove'); return; } countGroup?.removeClass('entryRemove'); const data = localVariables?.map((data, i) => { const value = String(data.name).replace(/\$/g, '$'); return this.createListValueElement(i, value, 1); }); infinityScroll.assignData(data); infinityScroll.show(); if (localVariables?.length > 4) { scrollBox.addClass('on'); } else { scrollBox.removeClass('on'); } simpleBar.recalculate(); } updateFuncSettingView(func) { const view = this.funcSettingView; if (!view) { return; } if (func.type === 'value') { view.func.resultCheck.addClass('on'); } else { view.func.resultCheck.removeClass('on'); } if (func.useLocalVariables) { view.func.localVarCheck.addClass('on'); this.funcSettingView.minus.removeAttribute('disabled'); this.funcSettingView.plus.removeAttribute('disabled'); this.funcSettingView.lengthInput.removeAttribute('disabled'); this.funcSettingView?.countGroup?.removeAttribute('disabled'); } else { view.func.localVarCheck.removeClass('on'); this.funcSettingView.minus.setAttribute('disabled', ''); this.funcSettingView.plus.setAttribute('disabled', ''); this.funcSettingView.lengthInput.setAttribute('disabled', ''); this.funcSettingView?.countGroup?.setAttribute('disabled', ''); } this.updateFuncScrollBar(func); } /** * @param {object} variable */ renderFunctionReference(func) { const createElement = Entry.createElement; const funcId = func.id; const hasInFunction = this.hasFuncBlockInFunction(funcId); const callers = [...this._functionRefs].filter( (item) => item.block.data.type === `func_${funcId}` ); func.usedView && $(func.usedView).remove(); const wrapper = createElement('div').addClass('use_block'); const boxSubject = createElement('span').addClass('box_sjt').appendTo(wrapper); if (callers.length) { boxSubject.textContent = Entry.Utils.stringFormat( Lang.Workspace.use_block_objects1, callers.length ); const listView = createElement('ul').addClass('obj_list').appendTo(wrapper); const fragment = document.createDocumentFragment(); callers.forEach((caller) => { const element = createElement('li'); const object = caller.object; if (!object.entity) { return; } !caller.object.thumbnailView_ && caller.object.generateView(); const thumb = element.appendChild(caller.object.thumbnailView_.cloneNode()); thumb.addClass('thmb'); element.appendChild(thumb); const nameElement = createElement('span').addClass('text'); nameElement.textContent = caller.object.name; element.appendChild(nameElement); element.bindOnClick(() => { if (Entry.playground.object != caller.object) { Entry.container.selectObject(); Entry.container.selectObject(caller.object.id, true); } Entry.playground.toggleOnVariableView(); const block = caller.block; const blockView = block.view; blockView && blockView.getBoard().setSelectedBlock(block.view); Entry.playground.changeViewMode('variable'); }); fragment.appendChild(element); }); listView.appendChild(fragment); } else { const caution = createElement('div').addClass('caution_dsc').appendTo(wrapper); caution.textContent = Lang.Workspace.no_use; boxSubject.textContent = Lang.Workspace.use_block_objects2; } if (hasInFunction) { const usedInFunction = createElement('div') .addClass('used_function_dsc') .appendTo(wrapper); usedInFunction.textContent = Lang.Workspace.use_block_function; } func.usedView = wrapper; this.funcSettingView && this.funcSettingView.appendChild(wrapper); } /** * update list view */ updateList() { const listView = this.listView_; if (!listView) { return; } const isPythonMode = this._isPythonMode(); if (isPythonMode) { listView.addClass('entryVariableContainerTextMode'); } else { listView.removeClass('entryVariableContainerTextMode'); } this.clearListElement(); switch (this.viewMode_) { case 'all': this.updateAllTab(); break; case 'message': this.updateMessageTab(); break; case 'variable': this.updateVariableTab(); break; case 'list': this.updateListTab(); break; case 'func': this.updateFuncTab(); break; } this.updateSelected(); } updateFuncVariableList() { [ ...(Entry.block?.set_func_variable?.events?.updateFuncVariableList || []), ...(Entry.block?.get_func_variable?.events?.updateFuncVariableList || []), ].forEach((fn) => { if (_isFunction(fn)) { fn(); } }); } makeChildVariableViews(arr, viewFunc, parent = this.listView_) { return _.each(arr, (data) => { !data.listElement && viewFunc(data); if (this._isPythonMode()) { $(data.listElement) .find('input') .each(function () { $(this).attr('disabled', 'disabled'); }); } else { $(data.listElement) .find('input') .each(function () { $(this).removeAttr('disabled'); }); } parent.appendChild(data.listElement); }); } clearListElement() { const clearList = [this.listView_]; for (const elem of clearList) { while (elem && elem.firstChild) { elem.removeChild(elem.lastChild); } } const arrItems = [this.messages_, this.variables_, this.lists_, this.functions_]; arrItems.forEach((items) => { Object.values(items).forEach((item) => { if (item.listElement) { item.listElement.removeClass('unfold').removeClass('selected').addClass('fold'); } }); }); if (this.listSettingView) { $(this.listSettingView).remove(); delete this.listSettingView; } if (this.variableSettingView) { $(this.variableSettingView).remove(); delete this.variableSettingView; } if (this.funcSettingView) { $(this.funcSettingView).remove(); delete this.funcSettingView; } } updateAllTab() { const createElement = Entry.createElement; const listView = this.listView_; const listWrapper = createElement('div').addClass( 'entryVariableSplitterWorkspace unfold all' ); const listBox = createElement('div').addClass('attr_box unfold').appendTo(listWrapper); const list = createElement('div').addClass('list').appendTo(listBox); this.makeChildVariableViews(this.messages_, this.createMessageView.bind(this), list); this.makeChildVariableViews(this.variables_, this.createVariableView.bind(this), list); this.makeChildVariableViews(this.lists_, this.createListView.bind(this), list); this.makeChildVariableViews(this.functions_, this.createFunctionView.bind(this), list); listView.appendChild(listWrapper); } updateMessageTab() { const createElement = Entry.createElement; const listView = this.listView_; if (Entry.isTextMode) { this.messageAddButton_.unBindOnClick().addClass('disabled'); } else { this.messageAddButton_ .unBindOnClick() .bindOnClick(() => Entry.do('variableContainerClickMessageAddButton')) .removeClass('disabled'); } listView.appendChild(this.messageAddButton_); listView.appendChild(this.messageAddPanel.view); const messageList = createElement('div').addClass( 'entryVariableSplitterWorkspace message unfold' ); const messageListBox = createElement('div').addClass('attr_box').appendTo(messageList); const list = createElement('div').addClass('list').appendTo(messageListBox); this.makeChildVariableViews(this.messages_, this.createMessageView.bind(this), list); listView.appendChild(messageList); } updateVariableTab() { const createElement = Entry.createElement; const listView = this.listView_; const info = this.variableAddPanel.info; if (info.object && !Entry.playground.object) { info.object = null; } if (Entry.isTextMode) { this.variableAddButton_.unBindOnClick().addClass('disabled'); } else { this.variableAddButton_ .unBindOnClick() .bindOnClick(() => Entry.do('variableContainerClickVariableAddButton')) .removeClass('disabled'); } listView.appendChild(this.variableAddButton_); listView.appendChild(this.variableAddPanel.view); //global list container const globalList = createElement('div').addClass( 'entryVariableSplitterWorkspace variable global' ); let isGlobalFolded = false; const globalListTitle = Entry.createElement('a') .addClass('attr_link') .bindOnClick(() => { isGlobalFolded = !isGlobalFolded; this.foldTab(globalList, isGlobalFolded, gLength); }) .appendTo(globalList); const globalListBox = createElement('div').addClass('attr_box').appendTo(globalList); //local list container const localList = createElement('div').addClass( 'entryVariableSplitterWorkspace variable local' ); let isLocalFolded = false; const localListTitle = Entry.createElement('a') .addClass('attr_link') .bindOnClick(() => { isLocalFolded = !isLocalFolded; this.foldTab(localList, isLocalFolded, lLength); }) .appendTo(localList); const localListBox = createElement('div').addClass('attr_box').appendTo(localList); const { globalV, localV } = _.groupBy(this.variables_, ({ object_ }) => object_ ? 'localV' : 'globalV' ); const gLength = (globalV || []).length; const lLength = (localV || []).length; globalListTitle.textContent = `${Lang.Workspace.Variable_used_at_all_objects} (${gLength})`; // eslint-disable-next-line max-len localListTitle.textContent = `${Lang.Workspace.Variable_used_at_special_object} (${lLength})`; this.foldTab(globalList, isGlobalFolded, gLength); this.foldTab(localList, isLocalFolded, lLength); listView.appendChild(globalList); this.makeChildVariableViews(globalV, this.createVariableView.bind(this), globalListBox); listView.appendChild(localList); this.makeChildVariableViews(localV, this.createVariableView.bind(this), localListBox); this.updateVariableAddView('variable'); } foldTab(tab, isFold, count = 0) { if (!count) { return; } if (isFold) { tab.removeClass('unfold'); tab.addClass('fold'); } else { tab.addClass('unfold'); tab.removeClass('fold'); } } updateListTab() { const createElement = Entry.createElement; const listView = this.listView_; const info = this.listAddPanel.info; if (info.object && !Entry.playground.object) { info.object = null; } if (Entry.isTextMode) { this.listAddButton_.unBindOnClick().addClass('disabled'); } else { this.listAddButton_ .unBindOnClick() .bindOnClick(() => Entry.do('variableContainerClickListAddButton')) .removeClass('disabled'); } listView.appendChild(this.listAddButton_); listView.appendChild(this.listAddPanel.view); //global list container const globalList = createElement('div').addClass( 'entryVariableSplitterWorkspace list global' ); let isGlobalFolded = false; const globalListTitle = Entry.createElement('a') .addClass('attr_link') .bindOnClick(() => { isGlobalFolded = !isGlobalFolded; this.foldTab(globalList, isGlobalFolded, gLength); }) .appendTo(globalList); const globalListBox = createElement('div').addClass('attr_box').appendTo(globalList); //local list container const localList = createElement('div').addClass( 'entryVariableSplitterWorkspace list local' ); let isLocalFolded = false; const localListTitle = Entry.createElement('a') .addClass('attr_link') .bindOnClick(() => { isLocalFolded = !isLocalFolded; this.foldTab(localList, isLocalFolded, lLength); }) .appendTo(localList); const localListBox = createElement('div').addClass('attr_box').appendTo(localList); const { localV, globalV } = _.groupBy(this.lists_, ({ object_ }) => object_ ? 'localV' : 'globalV' ); const gLength = (globalV || []).length; const lLength = (localV || []).length; globalListTitle.textContent = `${Lang.Workspace.List_used_all_objects} (${gLength})`; localListTitle.textContent = `${Lang.Workspace.list_used_specific_objects} (${lLength})`; this.foldTab(globalList, isGlobalFolded, gLength); this.foldTab(localList, isLocalFolded, lLength); listView.appendChild(globalList); this.makeChildVariableViews(globalV, this.createListView.bind(this), globalListBox); listView.appendChild(localList); this.makeChildVariableViews(localV, this.createListView.bind(this), localListBox); this.updateVariableAddView('variable'); } updateFuncTab() { const createElement = Entry.createElement; const listView = this.listView_; if (Entry.isTextMode) { this.functionAddButton_.unBindOnClick().addClass('disabled'); } else { this.functionAddButton_ .unBindOnClick() .bindOnClick(() => Entry.do('funcEditStart', Entry.generateHash())) .removeClass('disabled'); } listView.appendChild(this.functionAddButton_); const funcList = createElement('div').addClass( 'entryVariableSplitterWorkspace func unfold' ); const funcListBox = createElement('div').addClass('attr_box').appendTo(funcList); this.makeChildVariableViews( this.functions_, this.createFunctionView.bind(this), funcListBox ); listView.appendChild(funcList); } /** * @param {!Array.} objectModels */ setMessages(messages = []) { this.messages_ = messages.map((message) => { if (!message.id) { message.id = Entry.generateHash(); } return message; }); Entry.playground.reloadPlayground(); } /** * @param {!Array.} objectModels */ appendMessages(messages) { for (const i in messages) { const message = messages[i]; if (!message.id) { message.id = Entry.generateHash(); } else if (this.messages_.some((item) => item.id === message.id)) { continue; } let name = message.name; name = this.checkAllVariableName(name, 'messages_', 'name') ? Entry.getOrderedName(name, this.messages_, 'name') : name; message.name = name; this.messages_.push(message); } Entry.playground.reloadPlayground(); } /** * @param {!Array.} variables */ setVariables(variables = [], options) { variables.forEach((variable) => { variable = Entry.Variable.create(variable); switch (variable.getType()) { case 'variable': case 'slide': variable.generateView(this.variables_.length); this.variables_.push(variable); break; case 'list': variable.generateView(this.lists_.length); this.lists_.push(variable); break; case 'timer': this.generateTimer(variable); break; case 'answer': this.generateAnswer(variable); break; } }); if (_.isEmpty(Entry.engine.projectTimer)) { this.generateTimer(); } if (_.isEmpty(Entry.container.inputValue)) { this.generateAnswer(); } if (_.isEmpty(Entry.container.sttValue)) { this.generateStt(); if (options?.aiUtilizeBlocks?.includes('audio')) { Entry.container.sttValue.setVisible(true); } } Entry.playground.reloadPlayground(); } generateVariable(variable, data, key) { const name = variable.name_; variable.name_ = this.checkAllVariableName(name, key) ? Entry.getOrderedName(name, data, 'name_') : name; variable.generateView(data.length); } /** * @param {!Array.} variables */ appendVariables(variables) { for (const i in variables) { const variable = Entry.Variable.create(variables[i]); if (!variable.id_) { variable.id_ = Entry.generateHash(); } const type = variable.getType(); if (type === 'variable' || type === 'slide') { if (this.variables_.some((item) => item.id_ === variable.id_)) { continue; } this.generateVariable(variable, this.variables_, 'variables_'); this.variables_.push(variable); } else if (type === 'list') { if (this.lists_.some((item) => item.id_ === variable.id_)) { continue; } this.generateVariable(variable, this.lists_, 'lists_'); this.lists_.push(variable); } } if (Entry.isEmpty(Entry.engine.projectTimer)) { Entry.variableContainer.generateTimer(); } if (Entry.isEmpty(Entry.container.inputValue)) { Entry.variableContainer.generateAnswer(); } if (Entry.isEmpty(Entry.container.sttValue)) { Entry.variableContainer.generateStt(); } Entry.playground.reloadPlayground(); } /** * @param {!Array.} variables */ setFunctions(functions = []) { functions.forEach((func) => { func = new Entry.Func(func); func.generateBlock(); this.functions_[func.id] = func; }); } /** * @param {!Array.} variables */ appendFunctions(functions = []) { for (const i in functions) { const func = functions[i]; if (!func.id) { func.id = Entry.generateHash(); } else if (`${func.id}` in this.functions_) { continue; } const parseFunc = new Entry.Func(func); this.changeFunctionName(parseFunc); parseFunc.generateBlock(); this.functions_[parseFunc.id] = parseFunc; } } changeFunctionName(func) { const params = func.content.getEventMap('funcDef')[0].params[0].data.params; const funcParamInfo = this.getFunctionParamInfo(params); const funcParamName = this.getFunctionParamName(funcParamInfo); const funcKeys = Object.keys(this.functions_); const funcsParamNames = funcKeys.map((key) => { const func = this.functions_[key]; const params = func.content.getEventMap('funcDef')[0].params[0].data.params; const info = this.getFunctionParamInfo(params); return { name: this.getFunctionParamName(info), }; }); const isDuplecate = funcsParamNames.some(({ name }) => funcParamName === name); if (isDuplecate) { const orderedNumber = Entry.getOrderedNameNumber( funcParamName, funcsParamNames, 'name' ); for (let i = funcParamInfo.length - 1; ; i--) { const info = funcParamInfo[i]; if (info.type === 'string') { info.parent[0] += orderedNumber; break; } } Entry.Func.generateWsBlock(func); } } getFunctionParamName(info) { return info.reduce((acc, { name }) => (acc += name), ''); } getFunctionParamInfo(parentParams) { const info = []; parentParams.forEach((param, index) => { if (typeof param === 'string') { info[index] = { name: param, type: 'string', parent: parentParams, }; } else if (param instanceof Entry.Block) { const { data = {} } = param; const { params = [], type } = data; if (type.indexOf('stringParam') === 0 || type.indexOf('booleanParam') === 0) { const name = type.slice(0, -5); info[index] = { name, type: name, parent: parentParams, }; } else { const childParamInfo = this.getFunctionParamInfo(params); childParamInfo.forEach((childInfo, childIndex) => { info[childIndex + index] = childInfo; }); } } }); return info; } /** * get func * @return {Entry.Func} */ getFunction(funcId) { return this.functions_[funcId]; } /** * get variable on canvas * @return {Entry.Variable} */ getVariable(id_, entity = {}) { const criteria = { id_ }; let variable = _.find(this.variables_, criteria); if (entity.isClone && variable.object_) { variable = _.find(entity.variables, criteria); } return variable; } /** * get variable on canvas * @return {Entry.List} */ getList(listId, { isClone, lists } = {}) { const criteria = { id_: listId }; let list = _.find(this.lists_, criteria); if (isClone && list.object_) { list = _.find(lists, criteria); } return list; } /** * Create function */ createFunction(data) { if (Entry.Func.isEdit) { Entry.modal.alert( Lang.Msgs.warning_function_aleady_being_edited, Lang.Workspace.function_create ); return; } Entry.Func.edit(new Entry.Func(data)); Entry.Func.save(); this.select(Entry.Func.targetFunc); } removeBlocksInFunctionByType(blockType) { Object.values(this.functions_).forEach((func) => { Entry.do('funcEditStart', func.id).isPass(true); func.content.getBlockList(false, blockType).forEach((b, index) => { Entry.do('destroyBlock', b).isPass(true); }); Entry.do('funcEditEnd', 'save').isPass(true); }); } removeBlocksInFunctionByType2(blockType) { Object.values(this.functions_).forEach((func) => { func.content.getBlockList(false, blockType).forEach((block, index) => { block.destroy(); }); }); } async removeBlocksInFunctionByTypeAsync(blockType) { await Promise.all( Object.values(this.functions_).map(async (func) => { await Promise.all( func.content.getBlockList(false, blockType).map( Entry.Utils.runAsyncCurry((block) => { block.destroy(); }) ) ); }) ); } isUsedBlockTypeInFunction(blockType) { return Object.values(this.functions_).some( (func) => func.content.getBlockList(false, blockType).length ); } /** * Remove variable * @param {Entry.Variable} variable */ removeFunction({ id: functionId }) { const functions = this.functions_; functions[functionId].destroy(); delete functions[functionId]; const functionType = `func_${functionId}`; Entry.container.removeFuncBlocks(functionType); for (const id in functions) { functions[id].content.removeBlocksByType(functionType); } this.updateList(); } removeNotPythonSupportedFunction() { const functions = this.functions_; Object.values(functions).forEach((func) => { const isNotPythonSupport = func.useLocalVariables || func.type === 'value'; if (isNotPythonSupport) { const functionId = func.id; func.destroy(); delete functions[functionId]; const functionType = `func_${functionId}`; Entry.container.removeFuncBlocks(functionType); for (const id in functions) { functions[id].content.removeBlocksByType(functionType); } } }); this.updateList(); } checkListPosition(list, mouse) { const pos = { start_w: list.x_, area_w: list.x_ + list.width_, start_h: -list.y_, area_h: -list.y_ + -list.height_, }; if (mouse.x > pos.start_w && mouse.x < pos.area_w) { if (mouse.y < pos.start_h && mouse.y > pos.area_h) { return true; } } return false; } getListById(mouseevt) { const lists = this.lists_; const returnList = []; if (lists.length > 0) { for (let i = 0; i < lists.length; i++) { if (this.checkListPosition(lists[i], mouseevt)) { returnList.push(lists[i]); } } return returnList; } return false; } _getVariableByName(arr, variableName, isSelf, currentObjectId) { const object = _.result(Entry.playground, 'object'); if (!currentObjectId && object) { currentObjectId = object.id; } for (let i = 0; i < arr.length; i++) { const v = arr[i]; if (isSelf === true) { if (!v.object_ || v.object_ !== currentObjectId) { continue; } } else if (isSelf === false) { if (v.object_) { continue; } } if (v.getName() === variableName) { return v; } } } getVariableByName(variableName, isSelf, currentObjectId) { return this._getVariableByName(this.variables_, variableName, isSelf, currentObjectId); } getListByName(name, isSelf, currentObjectId) { return this._getVariableByName(this.lists_, name, isSelf, currentObjectId); } /** * Save variable * @param {Entry.Func} func */ saveFunction(func) { this.hasBlockInFunction.cache.clear(); this.hasParamBlockInFunction.cache.clear(); this.hasFuncBlockInFunction.cache.clear(); /* add to function list when not exist */ const ws = Entry.getMainWS(); if (ws && ws.overlayModefrom == Entry.Workspace.MODE_VIMBOARD) { if (func && func.description) { const funcName = func.description.substring(1, func.description.length - 1); const alertMsg = Entry.TextCodingUtil.validateNameIncludeSpace( funcName, 'function' ); if (alertMsg) { Entry.modal.alert(alertMsg); Entry.Func.cancelEdit(); return; } } } if (!this.functions_[func.id]) { this.functions_[func.id] = func; this.createFunctionView(func); } if (func.listElement) { func.listElement.nameField.textContent = func.description; } this.updateList(); } /** * @param {Entry.Func} func */ createFunctionView(func) { const createElement = Entry.createElement; const view = Entry.createElement('div').addClass('list default_func'); const that = this; const editBoxWrapper = createElement('div') .addClass('inpt_box') .bindOnClick((e) => { e.stopPropagation(); if (!Entry.isTextMode) { if (Entry.Func.isEdit) { Entry.Func._backupContent = null; Entry.Func.save(); } Entry.do('funcEditStart', func.id); } return this.select(func); }) .appendTo(view); const editBoxInputWrapper = createElement('div').addClass('inpt').appendTo(editBoxWrapper); const editBoxInput = createElement('span').addClass('input').appendTo(editBoxInputWrapper); editBoxInput.textContent = func.description; editBoxInput.setAttribute('autocomplete', 'off'); const ArrowDownButton = createElement('div').addClass('arrowDown').appendTo(editBoxWrapper); const delButton = createElement('a') .addClass('del') .bindOnClick((e) => { e.stopPropagation(); Entry.modal.confirm(Lang.Workspace.will_you_delete_function).then((result) => { if (result === true) { this.destroyFunction(func); this.selected = null; } }); }) .appendTo(editBoxWrapper); delButton.href = '#'; view.nameField = editBoxInput; func.listElement = view; } async destroyFunction(func) { if (Entry.Func.targetFunc) { Entry.do('funcEditEnd', 'cancel'); } const currentObjectId = Entry.playground.object.id; Entry.do('selectObject', currentObjectId); const functionType = `func_${func.id}`; await Entry.Utils.removeBlockByTypeAsync(functionType); Entry.do('funcRemove', func).isPass(true); Entry.do('selectObject', currentObjectId).isPass(true); } /** * Add variable * @param {Entry.Variable} variable * @return {boolean} return true when success */ checkAllVariableName(name, variable, key = 'name_') { return this[variable].some(({ [key]: name_ }) => name_ === name); } _addVariableOrList(type, data) { if (!type) { return; } const panel = this._getAddPanel(type); const name = panel.view.name.value.trim(); if (Entry.isTextMode) { const alertMsg = Entry.TextCodingUtil.validateNameIncludeSpace(name, type); if (alertMsg) { Entry.modal.alert(alertMsg); this.resetVariableAddPanel(type); return; } } const target = `${type}s_`; data = data || this._makeVariableData(type); this.resetVariableAddPanel(type); if (!(data instanceof Entry.Variable)) { data = Entry.Variable.create(data); } if (type === 'variable') { this.createVariableView(data); } else { this.createListView(data); } data.generateView(this[target].length); this[target].unshift(data); const playground = Entry.playground; if (playground) { const { blockMenu } = playground; if (blockMenu) { blockMenu.deleteRendered('variable'); } playground.reloadPlayground(); } this.select(data); this.updateList(); } addVariable(variable) { this._addVariableOrList.call(this, 'variable', variable); } /** * Remove variable * @param {Entry.Variable} variable */ removeVariable(variable) { if (!(variable instanceof Entry.Variable)) { variable = this.getVariable(variable.id); } if (this.selected == variable) { this.select(null); } variable.remove(); const variables = this.variables_; variables.splice(variables.indexOf(variable), 1); Entry.playground.reloadPlayground(); this.updateList(); } /** * @param {Entry.Variable} variable * @param {String} name */ changeVariableName(variable, name) { if (variable.name_ == name) { return; } if (Entry.isTextMode) { const alertMsg = Entry.TextCodingUtil.validateNameIncludeSpace(name, 'variable'); if (alertMsg) { Entry.modal.alert(alertMsg); variable.listElement.nameField.value = variable.name_; return; } } if (Entry.isExist(name, 'name_', this.variables_)) { return this.changeVariableNameDuplicated(variable, 'variable', name); } else if (name.length > 10) { variable.listElement.nameField.value = variable.name_; return Entry.toast.alert( Lang.Workspace.variable_rename_failed, Lang.Workspace.variable_too_long ); } variable.setName(name); variable.listElement.nameField.value = name; Entry.playground.reloadPlayground(); Entry.toast.success(Lang.Workspace.variable_rename, Lang.Workspace.variable_rename_ok); } /** * @param {Entry.Variable} list * @param {String} name */ changeListName(list, name) { if (list.name_ == name) { return; } if (Entry.isTextMode) { const alertMsg = Entry.TextCodingUtil.validateNameIncludeSpace(name, 'list'); if (alertMsg) { Entry.modal.alert(alertMsg); list.listElement.nameField.value = list.name_; return; } } if (Entry.isExist(name, 'name_', this.lists_)) { return this.changeVariableNameDuplicated(list, 'list', name); } else if (name.length > 10) { Entry.toast.alert(Lang.Workspace.list_rename_failed, Lang.Workspace.list_too_long); } else { //name successfully changed list.name_ = name; list.updateView(); Entry.playground.reloadPlayground(); Entry.toast.success(Lang.Workspace.list_rename, Lang.Workspace.list_rename_ok); } list.listElement.nameField.value = list.name_; } /** * @param {Entry.Variable} variable or list * @param {string} type [variable, list] * @param {string} name */ changeVariableNameDuplicated(variable, type, name) { const variables = this[`${type}s_`].filter(({ id_ }) => id_ !== variable.id_); const newName = Entry.getOrderedName( this._truncName(name, type, this._maxNameLength), variables, 'name_' ); variable.setName(newName); variable.listElement.nameField.value = newName; Entry.playground.reloadPlayground(); Entry.toast.warning(Lang.Workspace[`${type}_rename`], Lang.Workspace[`${type}_dup`]); } /** * Remove list * @param {Entry.Variable} list */ removeList(list) { if (!(list instanceof Entry.Variable)) { list = this.getList(list.id); } if (this.selected == list) { this.select(null); } list.remove(); const lists = this.lists_; lists.splice(lists.indexOf(list), 1); Entry.playground.reloadPlayground(); this.updateList(); } /** * @param {Entry.Variable} variable */ createVariableView(variable) { const that = this; const createElement = Entry.createElement; const variableWrapper = createElement('div').addClass('list fold'); if (!variable.object_) { if (variable.isCloud_) { variableWrapper.addClass('cloud_variable'); } else if (variable.isRealTime_) { variableWrapper.addClass('real_time_variable'); } else { variableWrapper.addClass('default_val'); } } else { variableWrapper.addClass('local_val'); } const editBoxWrapper = createElement('div') .addClass('inpt_box') .bindOnClick((e) => { e.stopPropagation(); if (that.variableSettingView) { $(that.variableSettingView).remove(); delete that.variableSettingView; } if (that.selected === variable) { if (!that._isPythonMode()) { editBoxInput.blur(); } that.select(variable); that.updateSelectedVariable(null, 'variable'); } else { Entry.do('setVariableEditable', variable.id_); } }) .appendTo(variableWrapper); const watchButton = createElement('a') .addClass('watch') .bindOnClick((e) => { e.stopPropagation(); Entry.do('variableSetVisibility', variable.id_, !variable.isVisible()); if (variable.isVisible()) { watchButton.addClass('on'); } else { watchButton.removeClass('on'); } }) .appendTo(editBoxWrapper); if (variable.isVisible()) { watchButton.addClass('on'); } else { watchButton.removeClass('on'); } watchButton.href = '#'; const editBoxInputWrapper = createElement('div').addClass('inpt').appendTo(editBoxWrapper); const editBoxInput = createElement('input') .addClass('editBoxInput') .bindOnClick((e) => { e.stopPropagation(); }) .appendTo(editBoxInputWrapper); editBoxInput.setAttribute('autocomplete', 'off'); editBoxInput.setAttribute('type', 'text'); editBoxInput.setAttribute('name', 'inpt_name'); editBoxInput.value = variable.name_; editBoxInput.onblur = function () { const value = this.value.trim(); if (!value) { Entry.toast.alert(Lang.Msgs.warn, Lang.Msgs.variable_can_not_space); this.value = variable.getName(); return this.focus(); } const targetVariable = that.getVariable(variable.getId()); targetVariable && Entry.do('variableSetName', targetVariable.getId(), value); }; editBoxInput.onkeydown = Entry.Utils.blurWhenEnter; const ArrowDownButton = createElement('div').addClass('arrowDown').appendTo(editBoxWrapper); const delButton = createElement('a') .addClass('del') .bindOnClick((e) => { e.stopPropagation(); Entry.do('variableContainerRemoveVariable', variable); }) .appendTo(editBoxWrapper); delButton.href = '#'; variableWrapper.nameField = editBoxInput; variable.listElement = variableWrapper; } /** * Add event for block * @param {message model} message * @return {boolean} return true when success */ addMessage(message = {}) { const messages = this.messages_; if (!message.name) { message.name = `${Lang.Workspace.message} ${messages.length + 1}`; } if (!message.id) { message.id = Entry.generateHash(); } this.createMessageView(message); messages.unshift(message); const { playground } = Entry; if (playground) { const { blockMenu } = playground; if (blockMenu) { blockMenu.deleteRendered('start'); } playground.reloadPlayground(); } this.updateList(); const nameField = message.listElement.nameField; //flag for first time blur command //focus first and value not changed //command will be skipped nameField.isFirst = true; } /** * Add event * @param {message model} message */ removeMessage({ id }) { const message = this.getMessage(id); if (this.selected == message) { this.select(null); } const messages_ = this.messages_; messages_.splice(messages_.indexOf(message), 1); this.updateList(); Entry.playground.reloadPlayground(); } /** * @param {object} message * @param {String} name */ changeMessageName({ id }, name) { const message = this.getMessage(id); if (message.name == name) { return; } const messages = this.messages_; const exist = Entry.isExist(name, 'name', messages); const { listElement: { nameField }, } = message; const { playground, toast } = Entry; if (exist) { return failFunc( message.name, Lang.Workspace.message_rename_failed, Lang.Workspace.message_dup ); } else if (name.length > EntryStatic.messageMaxLength) { return failFunc( message.name, Lang.Workspace.message_rename_failed, Lang.Workspace.message_too_long_to_change ); } message.name = name; nameField.value = message.name; if (playground) { playground.blockMenu.deleteRendered('start'); playground.reloadPlayground(); } toast.success(Lang.Workspace.message_rename, Lang.Workspace.message_rename_ok); function failFunc(value, title, message) { nameField.value = value; return toast.alert(title, message); } } activateMessageEditView(message) { $(message.listElement) .find('.entryVariableListElementNameWorkspace') .removeAttr('disabled') .focus(); } /** * @param {object} message */ createMessageView(message) { const createElement = Entry.createElement; const view = Entry.createElement('div').addClass('list default_message'); const editBoxWrapper = createElement('div') .addClass('inpt_box') .bindOnClick((e) => { e.stopPropagation(); return this.select(message); }) .appendTo(view); const editBoxInputWrapper = createElement('div').addClass('inpt').appendTo(editBoxWrapper); const editBoxInput = createElement('input') .addClass('editBoxInput') .bindOnClick((e) => { e.stopPropagation(); }) .appendTo(editBoxInputWrapper); editBoxInput.setAttribute('autocomplete', 'off'); editBoxInput.setAttribute('type', 'text'); editBoxInput.value = message.name; editBoxInput.onfocus = Entry.Utils.setFocused; editBoxInput.onblur = Entry.Utils.setBlurredTimer(function () { const value = this.value; if (!value.trim()) { Entry.toast.alert(Lang.Msgs.warn, Lang.Msgs.sign_can_not_space); this.value = message.name; return this.focus(); } //check message exist currently message = Entry.variableContainer.getMessage(message.id); if (message && !(this.isFirst && value === message.name)) { Entry.do('messageSetName', message.id, value); } delete this.isFirst; }, 200); editBoxInput.onkeydown = Entry.Utils.blurWhenEnter; const ArrowDownButton = createElement('div').addClass('arrowDown').appendTo(editBoxWrapper); const delButton = createElement('a') .addClass('del') .bindOnClick((e) => { e.stopPropagation(); Entry.do('variableContainerRemoveMessage', message); }) .appendTo(editBoxWrapper); delButton.href = '#'; view.nameField = editBoxInput; message.listElement = view; } /** * Add list for block * @param {list model} list * @return {boolean} return true when success */ addList(list) { this._addVariableOrList.call(this, 'list', list); } /** * @param {Entry.Variable} list */ createListView(list) { const that = this; const createElement = Entry.createElement; const listWrapper = createElement('div').addClass('list fold').appendTo(this.globalListBox); if (!list.object_) { if (list.isCloud_) { listWrapper.addClass('cloud_list'); } else if (list.isRealTime_) { listWrapper.addClass('real_time_list'); } else { listWrapper.addClass('default_list'); } } else { listWrapper.addClass('local_list'); } const editBoxWrapper = createElement('div') .addClass('inpt_box') .bindOnClick((e) => { e.stopPropagation(); if (that.listSettingView) { $(that.listSettingView).remove(); delete that.listSettingView; } if (that.selected === list) { editBoxInput.blur(); that.select(list); that.updateSelectedVariable(null, 'list'); } else { Entry.do('setListEditable', list.id_); } }) .appendTo(listWrapper); const watchButton = createElement('a') .addClass('watch') .bindOnClick((e) => { e.stopPropagation(); Entry.do('listSetVisibility', list.id_, !list.isVisible()); if (list.isVisible()) { watchButton.addClass('on'); } else { watchButton.removeClass('on'); } }) .appendTo(editBoxWrapper); if (list.isVisible()) { watchButton.addClass('on'); } else { watchButton.removeClass('on'); } watchButton.href = '#'; const editBoxInputWrapper = createElement('div').addClass('inpt').appendTo(editBoxWrapper); const editBoxInput = createElement('input') .addClass('editBoxInput') .bindOnClick((e) => { e.stopPropagation(); }) .appendTo(editBoxInputWrapper); editBoxInput.setAttribute('autocomplete', 'off'); editBoxInput.setAttribute('type', 'text'); editBoxInput.setAttribute('name', 'inpt_name'); editBoxInput.value = list.name_; editBoxInput.onblur = function () { const value = this.value.trim(); if (!value) { Entry.toast.alert(Lang.Msgs.warn, Lang.Msgs.list_can_not_space); this.value = list.getName(); return this.focus(); } const targetList = that.getList(list.getId()); targetList && Entry.do('listSetName', targetList.getId(), value); }; editBoxInput.onkeydown = Entry.Utils.blurWhenEnter; const ArrowDownButton = createElement('div').addClass('arrowDown').appendTo(editBoxWrapper); const delButton = createElement('a') .addClass('del') .bindOnClick((e) => { e.stopPropagation(); Entry.do('variableContainerRemoveList', list); }) .appendTo(editBoxWrapper); delButton.href = '#'; listWrapper.nameField = editBoxInput; list.listElement = listWrapper; } /** * Apply map function to variables. But this not replace object with returned one. * So giving map function don't have to return object. * And this support another arguments. * @param {!function} mapFunction * @param {} param */ mapVariable(mapFunction, param) { this.variables_.forEach(_.partial(mapFunction, _, param)); } /** * @param {!function} mapFunction * @param {} param */ mapList(mapFunction, param) { this.lists_.forEach(_.partial(mapFunction, _, param)); } mapFunc(mapFunction, param) { Object.values(this.functions_).forEach(_.partial(mapFunction, _, param)); } /** * convert this variable's data to JSON. * @return {JSON} */ getVariableJSON() { return [ ...this.variables_, ...this.lists_, _.result(Entry.engine, 'projectTimer'), _.result(Entry.container, 'inputValue'), ] .filter(_.identity) .map((v) => (v.toJSON ? v.toJSON() : v)); } /** * convert this message's data to JSON. * @return {JSON} */ getMessageJSON() { return this.messages_.map(_.partial(_.pick, _, 'id', 'name')); } /** * convert this function's data to JSON. * @return {JSON} */ getFunctionJSON() { return _.reduce( this.functions_, (acc, { id, content, type = 'normal', useLocalVariables, localVariables }) => [ ...acc, { id, type, localVariables, useLocalVariables, content: content.stringify(), }, ], [] ); } resetVariableAddPanel(type = 'variable') { const panel = this._getAddPanel(type); if (!panel.view) { return; } const info = panel.info; info.isCloud = false; info.isRealTime = false; info.object = null; panel.view.name.value = ''; panel.isOpen = false; this.updateVariableAddView(type); } generateVariableAddView() { const createElement = Entry.createElement; const _whenEnter = Entry.Utils.whenEnter; const _setFocused = Entry.Utils.setFocused; const _setBlurredTimer = Entry.Utils.setBlurredTimer; const that = this; // 변수 만들기 폼 const variableAddSpace = createElement('div').addClass( 'entryVariableAddSpaceWorkspace off' ); this.variableAddPanel.view = variableAddSpace; this.variableAddPanel.isOpen = false; const variableAddSpaceDataWrapper = createElement('div') .addClass('entryVariableAddSpaceDataWrapperWorkspace') .appendTo(variableAddSpace); // 입력 폼 const addSpaceNameWrapper = createElement('div') .addClass('entryVariableAddSpaceNameWrapperWorkspace') .appendTo(variableAddSpaceDataWrapper); const addSpaceInputLabel = createElement('label') .addClass('entryVariableAddSpaceInputLabelWorkspace') .appendTo(addSpaceNameWrapper); addSpaceInputLabel.setAttribute('for', 'entryVariableAddSpaceInputWorkspace'); addSpaceInputLabel.innerText = Lang.Workspace.Variable_placeholder_name; const addSpaceInput = createElement('input') .addClass('entryVariableAddSpaceInputWorkspace') .appendTo(addSpaceNameWrapper); addSpaceInput.setAttribute('autocomplete', 'off'); addSpaceInput.setAttribute('type', 'text'); addSpaceInput.id = 'entryVariableAddSpaceInputWorkspace'; addSpaceInput.setAttribute('placeholder', Lang.Workspace.Variable_placeholder_content); addSpaceInput.variableContainer = this; addSpaceInput.onkeypress = _whenEnter(function () { if (this.enterKeyDisabled) { this.blur(); } else { that._addVariable(); } }); addSpaceInput.onfocus = _setFocused; const doBlur = _setBlurredTimer(function () { this.isBlurred = false; Entry.do('variableAddSetName', this.value); this.blurCallback && this.blurCallback(); }); addSpaceInput.onblur = () => { this.isBlurred = true; doBlur.apply(this); }; this.variableAddPanel.view.name = addSpaceInput; const addSpaceSelectWrapper = createElement('div') .addClass('entryVariableAddSpaceSelectWrapperWorkspace') .appendTo(variableAddSpaceDataWrapper); const addSpaceGlobalButton = createElement('a') .addClass('button entryVariableAddSpaceGlobalButtonrWorkspace on') .bindOnClick(() => { addSpaceLocalButton.removeClass('on'); addSpaceGlobalButton.addClass('on'); variableTypeWrapper.addClass('on'); return Entry.do('variableAddSetScope', 'global'); }) .appendTo(addSpaceSelectWrapper); addSpaceGlobalButton.textContent = Lang.Workspace.use_all_objects; this.variableAddPanel.view.globalCheck = addSpaceGlobalButton; const addSpaceLocalButton = createElement('a') .addClass('button entryVariableAddSpaceLocalButtonrWorkspace') .bindOnClick(() => { addSpaceGlobalButton.removeClass('on'); addSpaceLocalButton.addClass('on'); variableTypeWrapper.removeClass('on'); return Entry.do('variableAddSetScope', 'local'); }) .appendTo(addSpaceSelectWrapper); addSpaceLocalButton.textContent = Lang.Workspace.Variable_use_this_object; this.variableAddPanel.view.localCheck = addSpaceLocalButton; const variableTypeWrapper = createElement('div') .addClass('entryVariableTypeBoxWrapper on') .appendTo(variableAddSpaceDataWrapper); ['normal', 'cloud', 'real_time'].forEach((type) => { const wrapper = createElement('div') .addClass(`entryVariableTypeWrapper`) .appendTo(variableTypeWrapper) .bindOnClick((e) => { e.stopImmediatePropagation(); const { object, isCloud, isRealTime } = this.variableAddPanel.info; !object && Entry.do('variableAddSetCloud', type); this.#removeChildrenClass(variableTypeWrapper, 'on'); wrapper.addClass('on'); }); if (type === 'normal') { wrapper.addClass('on'); } createElement('span') .addClass(`entryVariable${type}RadioButton radioButton`) .appendTo(wrapper); createElement('span') .addClass(`entryVariable${type}Text`, 'entryVariableAddSpaceCheckWorkspace') .appendTo(wrapper).textContent = Lang.Workspace[`variable_create_${type}`]; }); variableAddSpace.cloudWrapper = variableTypeWrapper; this.variableAddPanel.view.cloudCheck = variableTypeWrapper; // 확인 취소 버튼 const addSpaceButtonWrapper = createElement('div') .addClass('entryVariableAddSpaceButtonWrapperWorkspace') .appendTo(variableAddSpace); const addSpaceCancelButton = createElement('a') .addClass('entryVariableAddSpaceCancelWorkspace') .addClass('entryVariableAddSpaceButtonWorkspace') .bindOnClick(() => { this.variableAddPanel.view.addClass('off'); this.resetVariableAddPanel('variable'); }) .appendTo(addSpaceButtonWrapper); addSpaceCancelButton.href = '#'; addSpaceCancelButton.textContent = Lang.Buttons.cancel; const addSpaceConfirmButton = createElement('a') .addClass('entryVariableAddSpaceConfirmWorkspace') .addClass('entryVariableAddSpaceButtonWorkspace') .bindOnClick(() => { that._addVariable(); }) .appendTo(addSpaceButtonWrapper); addSpaceConfirmButton.textContent = Lang.Buttons.add_variable; this.variableAddConfirmButton = addSpaceConfirmButton; } _addVariable() { const variableInput = Entry.getDom(['variableContainer', 'variableAddInput']); this.variableAddPanel.view.addClass('off'); const blurCallback = () => { delete variableInput.blurCallback; Entry.do( 'variableContainerAddVariable', Entry.Variable.create(this._makeVariableData('variable')) ); const [variable] = this.variables_; this.updateSelectedVariable(variable); const { nameField } = variable.listElement; nameField.removeAttribute('disabled'); }; if (variableInput.isBlurred) { variableInput.blurCallback = blurCallback; } else { blurCallback(); } this.resetVariableAddPanel('variable'); } _addList() { const listInput = Entry.getDom(['variableContainer', 'listAddInput']); this.listAddPanel.view.addClass('off'); const blurCallback = () => { Entry.do( 'variableContainerAddList', Entry.Variable.create(this._makeVariableData('list')) ); const [list] = this.lists_; this.updateSelectedVariable(list); const { nameField } = list.listElement; nameField.removeAttribute('disabled'); }; if (listInput.isBlurred) { listInput.blurCallback = blurCallback; } else { blurCallback(); } this.resetVariableAddPanel('list'); } generateListAddView() { const createElement = Entry.createElement; const _setFocused = Entry.Utils.setFocused; const _setBlurredTimer = Entry.Utils.setBlurredTimer; const that = this; // 리스트 만들기 폼 const listAddSpace = createElement('div').addClass('entryVariableAddSpaceWorkspace off'); this.listAddPanel.view = listAddSpace; this.listAddPanel.isOpen = false; const variableAddSpaceDataWrapper = createElement('div') .addClass('entryVariableAddSpaceDataWrapperWorkspace') .appendTo(listAddSpace); // 리스트 만들기 const addSpaceNameWrapper = createElement('div') .addClass('entryVariableAddSpaceNameWrapperWorkspace') .appendTo(variableAddSpaceDataWrapper); const addSpaceInputLabel = createElement('label') .addClass('entryVariableAddSpaceInputLabelWorkspace') .appendTo(addSpaceNameWrapper); addSpaceInputLabel.innerText = Lang.Workspace.list_name; addSpaceInputLabel.setAttribute('for', 'entryVariableAddSpaceInputWorkspace'); const addSpaceInput = createElement('input') .addClass('entryVariableAddSpaceInputWorkspace') .appendTo(addSpaceNameWrapper); addSpaceInput.setAttribute('autocomplete', 'off'); addSpaceInput.setAttribute('type', 'text'); addSpaceInput.id = 'entryVariableAddSpaceInputWorkspace'; addSpaceInput.setAttribute('placeholder', Lang.Workspace.list_create_placeholder); addSpaceInput.onkeypress = Entry.Utils.whenEnter(function () { if (this.enterKeyDisabled) { this.blur(); } else { that._addList(); } }); addSpaceInput.onfocus = _setFocused; const doBlur = _setBlurredTimer(function () { this.isBlurred = false; Entry.do('listAddSetName', this.value); this.blurCallback && this.blurCallback(); }); addSpaceInput.onblur = () => { this.isBlurred = true; doBlur.apply(this); }; this.listAddPanel.view.name = addSpaceInput; const addSpaceSelectWrapper = createElement('div') .addClass('entryVariableAddSpaceSelectWrapperWorkspace') .appendTo(variableAddSpaceDataWrapper); const addSpaceGlobalButton = createElement('a') .addClass('button entryVariableAddSpaceGlobalButtonrWorkspace on') .bindOnClick(() => { addSpaceLocalButton.removeClass('on'); addSpaceGlobalButton.addClass('on'); variableTypeWrapper.addClass('on'); return Entry.do('listAddSetScope', 'global'); }) .appendTo(addSpaceSelectWrapper); addSpaceGlobalButton.textContent = Lang.Workspace.use_all_objects; this.listAddPanel.view.globalCheck = addSpaceGlobalButton; const addSpaceLocalButton = createElement('a') .addClass('button entryVariableAddSpaceLocalButtonrWorkspace') .bindOnClick(() => { addSpaceGlobalButton.removeClass('on'); addSpaceLocalButton.addClass('on'); variableTypeWrapper.removeClass('on'); return Entry.do('listAddSetScope', 'local'); }) .appendTo(addSpaceSelectWrapper); addSpaceLocalButton.textContent = Lang.Workspace.Variable_use_this_object; this.listAddPanel.view.localCheck = addSpaceLocalButton; const variableTypeWrapper = createElement('div') .addClass('entryVariableTypeBoxWrapper on') .appendTo(variableAddSpaceDataWrapper); ['normal', 'cloud', 'real_time'].forEach((type) => { const wrapper = createElement('div') .addClass(`entryVariableTypeWrapper`) .appendTo(variableTypeWrapper) .bindOnClick((e) => { e.stopImmediatePropagation(); const { object } = this.listAddPanel.info; !object && Entry.do('listAddSetCloud', type); this.#removeChildrenClass(variableTypeWrapper, 'on'); wrapper.addClass('on'); }); if (type === 'normal') { wrapper.addClass('on'); } createElement('span') .addClass(`entryVariable${type}RadioButton radioButton`) .appendTo(wrapper); createElement('span') .addClass(`entryVariable${type}Text`, 'entryVariableAddSpaceCheckWorkspace') .appendTo(wrapper).textContent = Lang.Workspace[`list_create_${type}`]; }); listAddSpace.cloudWrapper = variableTypeWrapper; this.listAddPanel.view.cloudCheck = variableTypeWrapper; // 확인 취소 버튼 const addSpaceButtonWrapper = createElement('div') .addClass('entryVariableAddSpaceButtonWrapperWorkspace') .appendTo(listAddSpace); const addSpaceCancelButton = createElement('a') .addClass('entryVariableAddSpaceCancelWorkspace') .addClass('entryVariableAddSpaceButtonWorkspace') .bindOnClick(() => { this.listAddPanel.view.addClass('off'); this.resetVariableAddPanel('list'); }) .appendTo(addSpaceButtonWrapper); addSpaceCancelButton.href = '#'; addSpaceCancelButton.textContent = Lang.Buttons.cancel; const addSpaceConfirmButton = createElement('a') .addClass('entryVariableAddSpaceConfirmWorkspace') .addClass('entryVariableAddSpaceButtonWorkspace') .bindOnClick(() => { that._addList(); }) .appendTo(addSpaceButtonWrapper); addSpaceConfirmButton.href = '#'; addSpaceConfirmButton.textContent = Lang.Buttons.add_list; this.listAddConfirmButton = addSpaceConfirmButton; } generateMessageAddView() { const createElement = Entry.createElement; const that = this; // 신호 만들기 폼 const msgAddSpace = createElement('div').addClass('message_inpt off'); this.messageAddPanel.view = msgAddSpace; this.messageAddPanel.isOpen = false; const msdAddSpaceWrapper = createElement('div') .addClass('msdAddSpaceWrapper') .appendTo(msgAddSpace); const boxSubject = Entry.createElement('span') .addClass('box_sjt') .appendTo(msdAddSpaceWrapper); boxSubject.textContent = Lang.Workspace.Message_placeholder_name; const msgNameInput = createElement('input').appendTo(msdAddSpaceWrapper); msgNameInput.setAttribute('autocomplete', 'off'); msgNameInput.setAttribute('type', 'text'); msgNameInput.setAttribute('placeholder', Lang.Workspace.message_create_placeholder); msgNameInput.onkeydown = Entry.Utils.whenEnter(function () { if (this.enterKeyDisabled) { this.blur(); } else { const value = msgNameInput.value; if (value.length > EntryStatic.messageMaxLength) { return Entry.toast.alert( Lang.Workspace.message_add_fail, Lang.Workspace.message_too_long ); } that.messageAddPanel.isOpen = false; msgAddSpace.addClass('off'); msgNameInput.value = ''; Entry.do('variableContainerAddMessage', { id: Entry.generateHash(), name: Entry.getOrderedName( value || Lang.Workspace.message, that.messages_, 'name' ), }); } }); this.messageAddPanel.view.name = msgNameInput; const buttonWrapper = createElement('div') .addClass('entryVariableAddSpaceButtonWrapperWorkspace') .appendTo(msgAddSpace); const msgCancel = createElement('a') .addClass('entryVariableAddSpaceCancelWorkspace') .addClass('entryVariableAddSpaceButtonWorkspace') .bindOnClick(() => { msgAddSpace.addClass('off'); msgNameInput.value = ''; this.messageAddPanel.isOpen = false; }) .appendTo(buttonWrapper); msgCancel.href = '#'; msgCancel.textContent = Lang.Buttons.cancel; const msgConfirm = createElement('a') .addClass('entryVariableAddSpaceConfirmWorkspace') .addClass('entryVariableAddSpaceButtonWorkspace') .bindOnClick(() => { const value = msgNameInput.value; if (value.length > EntryStatic.messageMaxLength) { return Entry.toast.alert( Lang.Workspace.message_add_fail, Lang.Workspace.message_too_long ); } this.messageAddPanel.isOpen = false; msgAddSpace.addClass('off'); msgNameInput.value = ''; Entry.do('variableContainerAddMessage', { id: Entry.generateHash(), name: Entry.getOrderedName( value || Lang.Workspace.message, this.messages_, 'name' ), }); }) .appendTo(buttonWrapper); msgConfirm.href = '#'; msgConfirm.textContent = Lang.Buttons.add_message; msgAddSpace.nameField = msgNameInput; } /** * 자료형 블록메뉴에서 변수, 리스트 추가 버튼 클릭시 발생하는 함수 * 패널을 속성탭으로 옮기고 해당 타입의 컨테이너를 오픈한다. * @param type {'variable'|'list'|'message'} */ openVariableAddPanel(type = 'variable') { Entry.playground.toggleOnVariableView(); Entry.playground.changeViewMode('variable'); switch (type) { case 'variable': this.selectFilter(type); this.updateVariableAddView(type); this.clickVariableAddButton(true); break; case 'list': this.selectFilter(type); this.updateVariableAddView(type); this.clickListAddButton(true); break; case 'message': this.selectFilter(type); this.clickMessageAddButton(true); break; } } addCloneLocalVariables(param) { const that = this; //variables this.variables_ .reduce((acc, variable) => { const cloned = clone(variable, param, 'variables_'); cloned && acc.push(cloned); return acc; }, []) .forEach(this.addVariable.bind(this)); //lists this.lists_ .reduce((acc, list) => { const cloned = clone(list, param, 'lists_'); cloned && acc.push(cloned); return acc; }, []) .forEach(this.addList.bind(this)); function clone(variable, param, nameSpace) { //not a local variable const _object = variable.object_; if (!_object || _object !== param.objectId) { return; } const cloned = variable.toJSON(); cloned.originId = cloned.id; cloned.id = Entry.generateHash(); cloned.object = param.newObjectId; cloned.name = that.checkAllVariableName(cloned.name, nameSpace) ? Entry.getOrderedName(cloned.name, that[nameSpace], 'name_') : cloned.name; delete cloned.x; delete cloned.y; const json = param.json; json.script = json.script.replace(new RegExp(cloned.originId, 'g'), cloned.id); return cloned; } } generateTimer(timer) { const x = 240 - (Lang.Workspace.Variable_Timer.length * 12 + 70); timer = timer || Entry.Variable.create({ id: Entry.generateHash(), name: Lang.Workspace.Variable_Timer, value: 0, variableType: 'timer', visible: false, x, y: -70, }); timer.generateView(); timer.tick = null; Entry.engine.projectTimer = timer; Entry.addEventListener('stop', () => { Entry.engine.stopProjectTimer(); }); } //generate Answer generateAnswer(answer) { answer = answer || Entry.Variable.create({ id: Entry.generateHash(), name: Lang.Blocks.VARIABLE_get_canvas_input_value, value: 0, variableType: 'answer', visible: false, x: 150, y: -100, }); answer.generateView(); Entry.container.inputValue = answer; Entry.container.inputValue.setName(Lang.Blocks.VARIABLE_get_canvas_input_value); } generateStt(answer) { answer = answer || Entry.Variable.create({ id: Entry.generateHash(), name: Lang.template.voice_title_text, value: '-', variableType: 'stt', visible: false, }); answer.generateView(); Entry.container.sttValue = answer; } generateVariableSettingView(variable) { const that = this; const createElement = Entry.createElement; const _setFocused = Entry.Utils.setFocused; const _setBlurredTimer = Entry.Utils.setBlurredTimer; // 변수 속성 설정 const element = createElement('div') .addClass('attr_inner_box') .bindOnClick((e) => e.stopPropagation()); if (this.variableSettingView) { $(this.variableSettingView).remove(); delete this.variableSettingView; } this.variableSettingView = element; const varAttr = createElement('div').addClass('val_attr').appendTo(element); const boxSubject = createElement('span').addClass('box_sjt').appendTo(varAttr); boxSubject.textContent = Lang.Workspace.Variable_property; const valTypeText = Entry.createElement('span').addClass('val_type_txt').appendTo(varAttr); if (variable.isRealTime_) { valTypeText.textContent = Lang.Menus.realtime; } else if (variable.isCloud_) { valTypeText.textContent = Lang.Menus.cloud; } // 기본 값 입력 창 const attrInputBox = createElement('div').addClass('attr_inpt').appendTo(varAttr); if (this._isPythonMode()) { attrInputBox.addClass('hidden'); } const attrInputLabel = createElement('label').appendTo(attrInputBox); attrInputLabel.setAttribute('for', 'attr_cnt'); attrInputLabel.textContent = Lang.Workspace.variable_default_value; const attrInputWrapper = createElement('span') .appendTo(attrInputBox) .addClass('val_inptbox'); const attrInput = createElement('input').appendTo(attrInputWrapper); attrInput.setAttribute('autocomplete', 'off'); attrInput.setAttribute('type', 'text'); attrInput.value = 0; attrInput.onkeypress = Entry.Utils.blurWhenEnter; attrInput.onfocus = _setFocused; attrInput.onblur = _setBlurredTimer(function () { const v = that.selected; if (!v) { console.error('error: not selected'); return; } Entry.do('variableSetDefaultValue', v.id_, this.value); }); element.initValueInput = attrInput; // 슬라이드 입력창 const slideInputBox = createElement('div').addClass('slide_inpt').appendTo(varAttr); const slideCheckBox = createElement('div').addClass('chk_box').appendTo(slideInputBox); element.slideCheck = createElement('span') .addClass('entryVariableAddSpaceCheckWorkspace') .bindOnClick(() => { const v = that.selected; Entry.do( 'variableSetSlidable', v.id_, v.getType() === 'variable' ? 'slide' : 'variable' ); }) .appendTo(slideCheckBox); const slideCheckText = createElement('span').addClass('chk_text').appendTo(slideCheckBox); slideCheckText.textContent = Lang.Workspace.slide; // 최소 최대 영역 const slideCountBox = createElement('div').addClass('cnt_box').appendTo(slideInputBox); const minValueInput = createElement('input').appendTo(slideCountBox); minValueInput.textContent = Lang.Workspace.min_value; minValueInput.setAttribute('autocomplete', 'off'); minValueInput.setAttribute('type', 'text'); const v = that.selected; const vType = _.result(v, 'type'); if (vType === 'slide') { minValueInput.value = v.minValue_; } else { minValueInput.value = 0; } minValueInput.onkeypress = Entry.Utils.blurWhenEnter; minValueInput.onfocus = _setFocused; minValueInput.onblur = _setBlurredTimer(function () { const v = that.selected; let value = this.value; value = Entry.Utils.isNumber(value) ? value : v.getMinValue(); Entry.do('variableSetMinValue', v.id_, value); }); element.minValueInput = minValueInput; createElement('span').addClass('dash').appendTo(slideCountBox).textContent = '~'; const maxValueInput = createElement('input').appendTo(slideCountBox); maxValueInput.textContent = Lang.Workspace.max_value; maxValueInput.setAttribute('type', 'text'); maxValueInput.setAttribute('autocomplete', 'off'); if (vType === 'slide') { maxValueInput.value = v.maxValue_; } else { maxValueInput.value = 100; } maxValueInput.onkeypress = Entry.Utils.blurWhenEnter; maxValueInput.onfocus = _setFocused; maxValueInput.onblur = _setBlurredTimer(function () { const v = that.selected; let value = this.value; value = Entry.Utils.isNumber(value) ? value : v.getMaxValue(); Entry.do('variableSetMaxValue', v.id_, value); }); element.maxValueInput = maxValueInput; this.renderVariableReference(variable); } /** * @param {object|Entry.Variable} object */ updateVariableSettingView(v) { const view = this.variableSettingView; if (!view) { return; } const { initValueInput: initValue, slideCheck: slide, minValueInput: minValue, maxValueInput: maxValue, } = view; slide.removeClass('on'); if (v.getType() === 'slide') { slide.addClass('on'); minValue.removeAttribute('disabled'); maxValue.removeAttribute('disabled'); minValue.value = v.getMinValue(); maxValue.value = v.getMaxValue(); } else { minValue.setAttribute('disabled', 'disabled'); maxValue.setAttribute('disabled', 'disabled'); } initValue.value = v.getValue(); v.listElement.appendChild(view); } /** * 속성 > 리스트 편집창 표기 */ generateListSettingView(list) { const createElement = Entry.createElement; // 리스트 속성 설정 const element = createElement('div') .addClass('attr_inner_box') .bindOnClick((e) => e.stopPropagation()); if (this.listSettingView) { $(this.listSettingView).remove(); delete this.listSettingView; } this.listSettingView = element; const listAttr = createElement('div').addClass('list_attr').appendTo(element); if (this._isPythonMode()) { listAttr.addClass('hidden'); } const boxSubject = createElement('span').addClass('box_sjt').appendTo(listAttr); boxSubject.textContent = Lang.Workspace.list_property; const valTypeText = Entry.createElement('span').addClass('val_type_txt').appendTo(listAttr); if (list.isRealTime_) { valTypeText.textContent = Lang.Menus.realtime; } else if (list.isCloud_) { valTypeText.textContent = Lang.Menus.cloud; } this.generateListImportExportView(listAttr); this.generateListCountView(listAttr); this.generateListValuesView(listAttr); this.renderVariableReference(list); } generateListImportExportView(element) { const that = this; const createElement = Entry.createElement; const buttonBox = createElement('div').addClass('btn_box').appendTo(element); const buttonExport = createElement('a') .addClass('btn_list') .bindOnClick((e) => { e.stopPropagation(); const { name_ } = that.selected; const array_ = that.selected.getArray(); if (array_.length === 0) { Entry.modal.alert(Lang.Menus.nothing_to_export); } else { Entry.dispatchEvent('openExportListModal', array_, name_); } }) .appendTo(buttonBox); buttonExport.textContent = Lang.Workspace.list_export; const buttonImport = createElement('a') .addClass('btn_list') .bindOnClick((e) => { e.stopPropagation(); Entry.dispatchEvent('openImportListModal'); }) .appendTo(buttonBox); buttonImport.textContent = Lang.Workspace.list_import; } generateListCountView(element) { const that = this; const createElement = Entry.createElement; const listCount = createElement('div').addClass('list_cnt').appendTo(element); const countSubject = createElement('span').addClass('cnt_sjt').appendTo(listCount); countSubject.textContent = Lang.Workspace.number_of_list; const countInputBox = createElement('div').addClass('cnt_inpt').appendTo(listCount); const buttonMinus = createElement('a') .addClass('btn_cnt') .bindOnClick(() => { const { selected: { id_ }, } = that; Entry.do('listChangeLength', id_, 'minus'); }) .appendTo(countInputBox); buttonMinus.href = '#'; buttonMinus.setAttribute('tabindex', '-1'); this.listSettingView.minus = buttonMinus; //List limit setting. [default value:5000, length: 4] let limitValue = 5000; let maxlength = 4; const countInput = createElement('input').appendTo(countInputBox); countInput.setAttribute('autocomplete', 'off'); countInput.setAttribute('type', 'text'); countInput.setAttribute('maxlength', maxlength); countInput.onblur = function () { const v = that.selected; let value = this.value; const array_ = v.getArray(); value = Entry.Utils.isNumber(value) ? value : array_.length; if (value >= limitValue) { value = limitValue; Entry.toast?.alert( Lang?.Workspace?.list_cant_add_item || 'Warning', Lang?.Workspace?.list_max_length_exceeded || 'You can add up to 5,000 items to a list.' ); } Entry.do('listChangeLength', v.id_, Number(value)); }; countInput.onkeypress = Entry.Utils.blurWhenEnter; this.listSettingView.lengthInput = countInput; const array_ = that.selected.getArray(); if (array_ && array_.length > 0) { const currentLeng = array_.length.toString().length; // 리스트 카운트가 5000 일떄만 설정 maxlength = currentLeng > maxlength ? currentLeng : maxlength; limitValue = array_.length > limitValue ? array_.length : limitValue; } const buttonPlus = createElement('a') .addClass('btn_cnt plus') .bindOnClick(() => { const { selected: { id_ }, } = that; const array_ = Entry.variableContainer.selected.getArray(); const selectedLength = array_.length; if (selectedLength >= limitValue) { Entry.toast?.alert( Lang?.Workspace?.list_cant_add_item || 'Warning', Lang?.Workspace?.list_max_length_exceeded || 'You can add up to 5,000 items to a list.' ); Entry.do('listChangeLength', id_, ''); } else { Entry.do('listChangeLength', id_, 'plus'); } }) .appendTo(countInputBox); buttonPlus.href = '#'; buttonPlus.setAttribute('tabindex', '-1'); this.listSettingView.plus = buttonPlus; } generateListValuesView(element) { const createElement = Entry.createElement; const countGroup = createElement('div').addClass('cnt_group').appendTo(element); const countLabel = createElement('div').addClass('cnt_label').appendTo(countGroup); countLabel.textContent = Lang.Workspace.list_default_value; const scrollBox = createElement('div').addClass('scroll_box').appendTo(countGroup); const el = new SimpleBar(scrollBox, { autoHide: false }); const parent = /* html */ `
    {1}
`; this.listSettingView.countGroup = countGroup; this.listSettingView.scrollBox = scrollBox; this.listSettingView.simpleBar = el; this.listSettingView.listValues = el.getContentElement(); this.listSettingView.infinityScroll = new Entry.VirtualScroll( this.listSettingView.listValues, { dataWrapper: parent, itemHeight: 35, groupSize: 10, } ); } createListValueElement(index, value, startIndex = 0) { return `
  • ${+index + startIndex}
  • `.trim(); } updateListSettingView(list) { const view = this.listSettingView; const that = this; if (!view) { return; } list = list || this.selected; const { infinityScroll, countGroup, listValues, lengthInput, simpleBar, scrollBox } = view; const arr = list.getArray() || []; lengthInput.value = arr.length; if (arr.length > 4) { scrollBox.addClass('on'); } else { scrollBox.removeClass('on'); } list.listElement.appendChild(view); //remove element and event bindings const $listValues = $(listValues); $listValues.empty(); $listValues.off(); const startIndex = Entry.getMainWS().mode === Entry.Workspace.MODE_VIMBOARD ? 0 : 1; if (arr?.length === 0) { countGroup?.addClass('entryRemove'); return; } countGroup?.removeClass('entryRemove'); if (arr.length) { const data = arr.map((data, i) => { const item = data?.data || ''; const value = String(item).replace(/\$/g, '$'); return this.createListValueElement(i, value, startIndex); }); infinityScroll.assignData(data); infinityScroll.show(); $listValues.on( 'keyup', 'input', _.debounce((e) => { const { target } = e; const index = target.getAttribute('data-index'); data[index] = this.createListValueElement(index, target.value, startIndex); list.getArray()[index] = { data: target.value }; list.updateView(); }) ); $listValues.on('focus', 'input', Entry.Utils.setFocused); $listValues.on('keypress', 'input', Entry.Utils.blurWhenEnter); $listValues.on('click', 'a', function () { const index = this.getAttribute('data-index'); arr.splice(index, 1); that.updateListSettingView(); }); } simpleBar.recalculate(); list.updateView(); } setListLength(list, value) { value = Number(value); const arr = this.selected.getArray(); const times = value - arr.length; if (times && Entry.Utils.isNumber(value)) { if (times > 0) { _.times(times, () => this.selected.appendValue(0)); } else { arr.length = value; } } this.updateListSettingView(); } updateViews() { [...this.variables_, ...this.lists_].forEach((v) => v.updateView()); } updateSelectedVariable(object, type = 'variable') { const objectType = _.result(object, 'type'); if (this.selected) { this.selected.listElement.removeClass('unfold'); this.selected.listElement.addClass('fold'); } if (!object) { if (type === 'variable') { this.selected = null; } else { this.selected = null; } } else if (objectType === 'variable' || objectType === 'slide') { this.selected = object; this.selected.listElement.removeClass('fold'); this.selected.listElement.addClass('unfold'); if (!this.variableSettingView) { this.generateVariableSettingView(object); } this.updateVariableSettingView(object); } else if (objectType === 'list') { this.selected = object; this.selected.listElement.removeClass('fold'); this.selected.listElement.addClass('unfold'); if (!this.listSettingView) { this.generateListSettingView(object); } this.updateListSettingView(object); } } removeLocalVariables(objectId) { if (!objectId) { return; } [...this.variables_].forEach((v) => { if (v.object_ == objectId) { this.removeVariable(v); } }); } addRef(type, blockData) { const wsMode = _.result(Entry.getMainWS(), 'getMode'); if (!this.view_ || wsMode !== Entry.Workspace.MODE_BOARD) { return; } const datum = { object: blockData.getCode().object, block: blockData, }; this[type].push(datum); Entry.playground.viewMode_ !== 'default' && this.updateList(); return datum; } removeRef(type, block) { if (!Entry.playground.mainWorkspace) { return; } const wsMode = Entry.getMainWS().getMode(); if (wsMode !== Entry.Workspace.MODE_BOARD) { return; } const arr = this[type]; for (let i = 0; i < arr.length; i++) { if (arr[i].block == block) { arr.splice(i, 1); break; } } Entry.playground.viewMode_ !== 'default' && this.updateList(); } updateSelected() { if (this.selected) { const selected = this.selected; this.selected = null; this.select(selected); } } getObjectVariables(blockList, keys) { const findFuncKeys = keys || {}; let functions = []; const jsonData = this.getVariableJSONByBlockList(blockList); let variables = jsonData.variables; let messages = jsonData.messages; blockList.forEach((block) => { const type = block.type; if (type && type.indexOf('func_') === 0) { const id = type.substr(5); if (!findFuncKeys[id]) { const func = this.functions_[id]; findFuncKeys[id] = true; functions.push({ id, content: JSON.stringify(func.content.toJSON()), type: func.type, localVariables: func.localVariables, useLocalVariables: func.useLocalVariables, }); const contentBlockList = func.content.getBlockList(); const jsonData = this.getObjectVariables(contentBlockList, findFuncKeys); functions = _.unionBy(functions, jsonData.functions, 'id'); variables = _.unionBy(variables, jsonData.variables, 'id'); messages = _.unionBy(messages, jsonData.messages, 'id'); } } }); return { functions, variables, messages, }; } getVariableJSONByBlockList(blockList) { const variables = []; const messages = []; const variableSet = [...this.variables_, ...this.lists_, ...this.messages_].reduce( (acc, data) => { acc[data.id_ || data.id] = data; return acc; }, {} ); blockList.forEach((block) => { const data = block.data || {}; const type = data.type; if (!type) { return; } const isMessage = _includes(EntryStatic.messageBlockList, type); const isVariable = _includes(EntryStatic.variableBlockList, type); if (isMessage || isVariable) { block.data.params.forEach((param) => { if (typeof param === 'string' && !!variableSet[param]) { const item = variableSet[param]; if (isVariable) { variables.push(item.toJSON()); } else { messages.push({ id: item.id, name: item.name, }); } variableSet[param] = undefined; } }); } }); return { variables, messages, }; } _getBlockMenu() { return _.result(Entry.getMainWS(), 'getBlockMenu'); } _truncName(name, type, maxLen) { maxLen = maxLen || this._maxNameLength; if (name.length <= maxLen) { return name; } Entry.toast.warning( Lang.Workspace[`${type}_name_auto_edited_title`], Lang.Workspace[`${type}_too_long`] ); return name.substring(0, maxLen); } _maxNameLength = 10; clear() { this.select(null); const _removeFunc = _.partial(_.result, _, 'remove'); const { engine = {}, container = {}, playground } = Entry; [...this.variables_, ...this.lists_].forEach(_removeFunc); _removeFunc(engine.projectTimer); _removeFunc(container.inputValue); _.each(this.functions_, this.removeFunction.bind(this)); this.viewMode_ = 'all'; this.variables_ = []; this.lists_ = []; this.messages_ = []; this.functions_ = {}; this._variableRefs = []; this._messageRefs = []; this._functionRefs = []; Entry.Func.reset(); playground.reloadPlayground(); this.updateList(); } _isPythonMode() { return _.result(Entry.getMainWS(), 'isVimMode'); } getDom(query) { if (_.isEmpty(query)) { return; } query = [...query]; switch (query.shift()) { case 'filter': return this.filterElements[query.shift()]; case 'functionAddButton': return this.functionAddButton_; case 'variableAddButton': return this.variableAddButton_; case 'listAddButton': return this.listAddButton_; case 'variableAddConfirmButton': return this.variableAddConfirmButton; case 'listAddConfirmButton': return this.listAddConfirmButton; case 'variableAddInput': return this.variableAddPanel.view.name; case 'listAddInput': return this.listAddPanel.view.name; case 'messageAddButton': return this.messageAddButton_; case 'variableSetVisibility': return this.variableSettingView.visibleCheck; case 'listSetVisibility': return this.listSettingView.visibleCheck; case 'variableSetDefaultValue': return this.variableSettingView.initValueInput; case 'slideCheck': return this.variableSettingView.slideCheck; case 'variableMinValue': return this.variableSettingView.minValueInput; case 'variableMaxValue': return this.variableSettingView.maxValueInput; case 'messageList': return this.getMessage(query.shift()).listElement.nameField; case 'variableScope': { const { globalCheck, localCheck } = this._getAddPanel('variable').view; return query.shift() === 'global' ? globalCheck : localCheck; } case 'listScope': { const { globalCheck, localCheck } = this._getAddPanel('list').view; return query.shift() === 'global' ? globalCheck : localCheck; } case 'variableCloud': return this._getAddPanel('variable').view.cloudCheck; case 'listCloud': return this._getAddPanel('list').view.cloudCheck; case 'listChangeLength': return this.listSettingView[query.shift()]; case 'listDefaultValue': return $('.entryListSettingEachInputWorkspace')[query.shift()]; case 'messageEditButton': return $(this.getMessage(query.shift()).listElement).find('.editButton')[0]; case 'variableEditButton': return $(this.getVariable(query.shift()).listElement).find( '.entryVariableListElementEditWorkspace' )[0]; case 'listEditButton': return $(this.getList(query.shift()).listElement).find( '.entryVariableListElementEditWorkspace' )[0]; case 'variableName': return this.getVariable(query.shift()).listElement.nameField; } } _clickAddButton(type, forceOpen, doNotFocus) { const panel = this._getAddPanel(type); const panelView = panel.view; const panelViewName = panelView.name; if (panel.isOpen && !forceOpen) { panelView.addClass('off'); panel.isOpen = false; } else { panelViewName.value = ''; panelView.removeClass('off'); !doNotFocus && Entry.Utils.focusIfNotActive(panelViewName); panel.isOpen = true; } } clickVariableAddButton(...args) { this._clickAddButton.call(this, 'variable', ...args); this.variableAddPanel.view.cloudCheck.addClass('on'); } clickListAddButton(...args) { this._clickAddButton.call(this, 'list', ...args); this.listAddPanel.view.cloudCheck.addClass('on'); } clickMessageAddButton(...args) { this._clickAddButton.call(this, 'message', ...args); } _makeVariableData(type = 'variable') { const { view, info: { isCloud, object, isRealTime }, } = this._getAddPanel(type); let name = view.name.value.trim(); if (_.isEmpty(name)) { name = Lang.Workspace[type]; } name = this._truncName(name, type, this._maxNameLength); const target = `${type}s_`; if (this.checkAllVariableName(name, target)) { name = Entry.getOrderedName(name, this[target], 'name_'); Entry.toast.warning(Lang.Workspace[`${type}_rename`], Lang.Workspace[`${type}_dup`]); } return { name, isCloud, isRealTime, object, variableType: type, }; } applyOption() { const { variable, message, list, func } = this._filterTabs; process(variable, Entry.variableEnable); process(message, Entry.messageEnable); process(list, Entry.listEnable); process(func, Entry.functionEnable); function process(view, value) { if (value) { view.removeClass('disable'); } else { view.addClass('disable'); } view.disabled = !value; } } setVariableSlidable(v, type, value) { //no type changed //just return if (v.getType() === type) { return; } const variables = this.variables_; const variableJSON = v.toJSON(); variableJSON.variableType = type; const newVariable = Entry.Variable.create(variableJSON); variables.splice(variables.indexOf(v), 0, newVariable); if (value !== undefined) { variableJSON.value = value; } if (type === 'slide') { if (newVariable.getValue() < 0) { newVariable.setValue(0); } else if (newVariable.getValue() > 100) { newVariable.setValue(100); } } this.createVariableView(newVariable); this.removeVariable(v); this.updateSelectedVariable(newVariable); newVariable.generateView(); } _getAddPanel(type = 'variable') { return this[`${type}AddPanel`]; } getFunctionByBlockId(blockId) { return _find(this.functions_, (func) => func.getBlockById(blockId)); } hasBlockInFunction = _memoize((blockId) => _some(this.functions_, (func) => Boolean(func.getBlockById(blockId))) ); hasParamBlockInFunction = _memoize((paramId) => _some(this.functions_, (func) => Boolean(func.getBlockByParamId(paramId))) ); hasFuncBlockInFunction = _memoize((funcId) => _some(this.functions_, (func) => Boolean(func.getFuncBlockByFuncId(`func_${funcId}`))) ); }; ================================================ FILE: src/command/command.js ================================================ 'use strict'; Entry.Command = {}; (function(c) { c[Entry.STATIC.COMMAND_TYPES.do] = { recordable: Entry.STATIC.RECORDABLE.SKIP, log(objectId) { return []; }, skipUndoStack: true, }; c[Entry.STATIC.COMMAND_TYPES.undo] = { recordable: Entry.STATIC.RECORDABLE.SKIP, log(objectId) { return []; }, skipUndoStack: true, }; c[Entry.STATIC.COMMAND_TYPES.redo] = { recordable: Entry.STATIC.RECORDABLE.SKIP, log(objectId) { return []; }, skipUndoStack: true, }; })(Entry.Command); ================================================ FILE: src/command/command_util.js ================================================ 'use strict'; const COMMAND_TYPES = Entry.STATIC.COMMAND_TYPES; const obj = { createTooltip(title, content, target, callback, option = {}) { return new Entry.Tooltip( [ { title, content, target, }, ], Object.assign( { restrict: true, dimmed: true, callBack: callback, }, option ) ); }, returnEmptyArr() { return []; }, getExpectedData(name, defaultValue) { const expected = (Entry.expectedAction || []).concat(); if (!name || _.isEmpty(expected)) { return defaultValue; } expected.shift(); const ret = _.find(expected, ([key]) => key === name); if (ret) { return ret[1]; } return defaultValue; }, }; Entry.Command[COMMAND_TYPES.dismissModal] = { do() { Entry.dispatchEvent('dismissModal'); }, state: obj.returnEmptyArr, log: obj.returnEmptyArr, undo: 'dismissModal', recordable: Entry.STATIC.RECORDABLE.SKIP, validate: false, dom: [], }; module.exports = obj; ================================================ FILE: src/command/commander.js ================================================ class EntryCommander { constructor() { Entry.do = this.do.bind(this); Entry.undo = this.undo.bind(this); this.editor = {}; this.reporters = []; Entry.Command.editor = this.editor; this.doEvent = new Entry.Event(this); this.logEvent = new Entry.Event(this); this.doCommandAll = Entry.doCommandAll; this._storage = null; } do(commandType, ...args) { const { stateManager, Command: EntryCommand, STATIC: { COMMAND_TYPES, getCommandName }, } = Entry; if (typeof commandType === 'string') { commandType = COMMAND_TYPES[commandType]; } //intentionally delay reporting this.report(COMMAND_TYPES.do); this.report(commandType, args); const command = EntryCommand[commandType]; console.log('commandType', commandType, getCommandName(commandType)); let state; if (stateManager && !this._checkIsSkip(commandType)) { state = stateManager.addCommand( ...[commandType, this, this.do, command.undo].concat( command.state.apply(this, args) ) ); } else if (this.checkIsChange(commandType)) { if (Entry.creationChangedEvent) { Entry.creationChangedEvent.notify(); } } const value = command.do.apply(this, args); this.doEvent.notify(commandType, args); const id = state ? state.id : null; return { value, isPass: function (isPass, skipCount) { this.isPassById(id, isPass, skipCount); }.bind(this), }; } undo(commandType, ...args) { this.report(Entry.STATIC.COMMAND_TYPES.undo); const command = Entry.Command[commandType]; let state; if (Entry.stateManager && command.skipUndoStack !== true) { state = Entry.stateManager.addCommand.apply( Entry.stateManager, [commandType, this, this.do, command.undo].concat(command.state.apply(this, args)) ); } return { value: command.do.apply(this, args), isPass: function (isPass) { this.isPassById(state.id, isPass); }.bind(this), }; } redo(commandType, ...args) { this.report(Entry.STATIC.COMMAND_TYPES.redo); const command = Entry.Command[commandType]; if (Entry.stateManager && command.skipUndoStack !== true) { Entry.stateManager.addCommand.apply( Entry.stateManager, [commandType, this, this.undo, commandType].concat(command.state.apply(null, args)) ); } command.undo.apply(this, args); } setCurrentEditor(key, object) { this.editor[key] = object; } isPass(isPass = true) { if (!Entry.stateManager) { return; } const lastCommand = Entry.stateManager.getLastCommand(); if (lastCommand) { lastCommand.isPass = isPass; } } isPassById(id, isPass = true, skipCount = 0) { if (!id || !Entry.stateManager) { return; } const lastCommand = Entry.stateManager.getLastCommandById(id); if (lastCommand) { lastCommand.isPass = isPass; if (skipCount) { lastCommand.skipCount = !!skipCount; } } } addReporter(reporter) { reporter.logEventListener = this.logEvent.attach(reporter, reporter.add); } removeReporter(reporter) { if (reporter.logEventListener) { this.logEvent.detatch(reporter.logEventListener); } delete reporter.logEventListener; } report(commandType, argumentsArray) { let data; if (commandType && Entry.Command[commandType] && Entry.Command[commandType].log) { data = Entry.Command[commandType].log.apply(this, argumentsArray); } else { data = argumentsArray; } data.unshift(commandType); this.logEvent.notify(data); } applyOption() { this.doCommandAll = Entry.doCommandAll; } _checkIsSkip(commandType) { const { skipUndoStack } = Entry.Command[commandType]; return ( skipUndoStack === true || (!Entry.doCommandAll && _.includes(Entry.STATIC.COMMAND_TYPES_NOT_ALWAYS, commandType)) ); } checkIsChange(commandType) { return _.includes(Entry.STATIC.COMMAND_TYPES_CHANGE_CHECK, commandType); } } Entry.Commander = EntryCommander; ================================================ FILE: src/command/commands/block.js ================================================ /* * */ 'use strict'; import isFunction from 'lodash/isFunction'; (function (c) { const COMMAND_TYPES = Entry.STATIC.COMMAND_TYPES; let obj; c[COMMAND_TYPES.addThread] = { do(blocks, index) { return this.editor.board.code.createThread(blocks, index); }, state(blocks, index) { if (index === undefined || index === null) { index = this.editor.board.code.getThreadCount(); } return [index]; }, log(blocks, index) { if (blocks instanceof Entry.Thread) { blocks = blocks.toJSON(); } return [ ['blocks', blocks], ['index', index], ]; }, undo: 'destroyThread', recordable: Entry.STATIC.RECORDABLE.SUPPORT, validate: false, dom: ['playground', 'blockMenu', '&0'], }; obj = _.clone(c[COMMAND_TYPES.addThread]); obj.showMe = function (restrictor) { if (restrictor.isTooltipFaded()) { return; } restrictor.fadeOutTooltip(); const svgGroup = Entry.getDom(restrictor.processDomQuery(this.dom)); const nextCmd = restrictor.requestNextData().content; const cmdType = nextCmd[0]; let targetDomQuery; if (cmdType === COMMAND_TYPES.moveBlockFromBlockMenu) { targetDomQuery = ['playground', 'board', 'coord', '&1', '&2']; } else { targetDomQuery = ['playground', 'board', '&1', 'magnet', 'next', 0]; } const targetDom = Entry.getDom(restrictor.processDomQuery(targetDomQuery, nextCmd)); const { left, top } = targetDom.getBoundingClientRect(); Entry.Utils.glideBlock(svgGroup, left, top, () => { restrictor.fadeInTooltip(); }); }; obj.followCmd = true; obj.restrict = function (data, domQuery, callback, restrictor) { const nextCmd = restrictor.requestNextData().content; if (nextCmd[0] === Entry.STATIC.COMMAND_TYPES.insertBlockFromBlockMenu) { Entry.Command.editor.board.scrollToPointer(nextCmd[2][1]); } const isDone = false; const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { dimmed: true, restrict: true, callBack: callback, } ); return tooltip; }; c[COMMAND_TYPES.addThreadFromBlockMenu] = obj; c[COMMAND_TYPES.destroyThread] = { do(thread) { // thread can be index if (!(thread instanceof Entry.Thread)) { thread = this.editor.board.code.getThread(thread); } if (thread) { const block = thread.getFirstBlock(); block.destroy(true, true); } }, state(thread) { if (!(thread instanceof Entry.Thread)) { thread = this.editor.board.code.getThread(thread); } const index = this.editor.board.code.getThreadIndex(thread); const json = thread ? thread.toJSON() : {}; return [json, index]; }, log(threadIndex) { if (threadIndex instanceof Entry.Thread) { threadIndex = this.editor.board.code.getThreadIndex(threadIndex); } return [['index', threadIndex]]; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, restrict(data, domQuery, callback) { callback(); }, validate: false, undo: 'addThread', }; c[COMMAND_TYPES.destroyBlock] = { do(block) { block = this.editor.board.findBlock(block); block.doDestroy(); }, state(block) { let isThread = false; block = this.editor.board.findBlock(block); const pointer = block.targetPointer(); const blockJSON = block.toJSON(); if (pointer.length === 3) { // 첫번째 블록 삭제 if (block.thread.getCount() === 1) { // 단일 블록 쓰레드 삭제 isThread = true; } else { pointer.push(-1); } // targetPointer 결과값 보정 } if (block.getBlockType() === 'output') { blockJSON.params[1] = undefined; } return [blockJSON, pointer, isThread]; }, log(block) { block = this.editor.board.findBlock(block); return [['block', block.pointer ? block.pointer() : block]]; }, undo: 'recoverBlock', }; c[COMMAND_TYPES.recoverBlock] = { do(blockModel, pointer, isThread) { if (isThread) { return this.editor.board.code.createThread([blockModel], pointer[2]); } else { const block = this.editor.board.code.createThread([blockModel]).getFirstBlock(); this.editor.board.insert(block, pointer); } }, state(block) { if (typeof block !== 'string') { block = block.id; } return [block]; }, log(block, pointer) { block = this.editor.board.findBlock(block.id); return [ ['block', block], ['pointer', pointer], ]; }, undo: 'destroyBlock', }; c[COMMAND_TYPES.insertBlock] = { do(block, targetBlock, count) { block = this.editor.board.findBlock(block); let blockArgument; if (block instanceof Entry.FieldBlock) { blockArgument = block.value; } else { blockArgument = block; } this.editor.board.insert(blockArgument, targetBlock, count); const { params = [] } = block._schema || {}; const shouldRerender = params.find( ({ type, menuName }) => type === 'DropdownDynamic' && isFunction(menuName) ); if (shouldRerender) { block.view.reDraw(); } }, state(block, targetBlock, count) { block = this.editor.board.findBlock(block); const data = [block, block.targetPointer()]; if (typeof block !== 'string' && block.getBlockType() === 'basic') { data.push(block.thread.getCount(block)); } else if (typeof block !== 'string' && block.getBlockType() === 'output') { data.push(count || block.getOutputBlockCount() + 1); } return data; }, log(block, targetBlock, count) { block = this.editor.board.findBlock(block); if (!(targetBlock instanceof Array)) { targetBlock = targetBlock.pointer(); } const result = [ ['block', block ? block.pointer() : ''], ['targetPointer', targetBlock], ]; if (count) { result.push(['count', count ? count : null]); } return result; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: 'insertBlock', restrict(data, domQuery, callback, restrictor) { const board = Entry.Command.editor.board; const block = board.code.getByPointer(data.content[1][1]); let blockView; board.scrollToPointer(data.content[1][1]); if (restrictor.toolTipRender) { restrictor.toolTipRender.titleIndex = 0; restrictor.toolTipRender.contentIndex = 0; } const isDefault = data.tooltip.isDefault; let isDone = false; const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { dimmed: true, restrict: true, callBack(isFromInit) { if (isDone || !isFromInit) { return; } isDone = true; callback(); const ret = board.scrollToPointer(data.content[2][1]); if (block) { blockView = block.view; } if (blockView) { blockView = blockView.getSvgRoot().blockView; if (blockView && ret) { blockView.moveBy(-ret[0], -ret[1]); } } restrictor.toolTipRender.titleIndex = 1; if (restrictor.toolTipRender) { if (!isDefault) { restrictor.toolTipRender.contentIndex = 1; } else { const target = Entry.Command.editor.board.code.getTargetByPointer( data.content[2][1] ); if (target && target.isParamBlockType()) { restrictor.toolTipRender.contentIndex = 2; } else { restrictor.toolTipRender.contentIndex = 1; } } } const processedDomQuery = restrictor.processDomQuery([ 'playground', 'board', '&1', 'magnet', ]); tooltip.init( [ { title: data.tooltip.title, content: data.tooltip.content, target: processedDomQuery, }, ], { indicator: true, callBack() {}, } ); }, } ); return tooltip; }, showMe(restrictor) { if (restrictor.isTooltipFaded()) { return; } restrictor.fadeOutTooltip(); const svgGroup = Entry.getDom(restrictor.processDomQuery(this.dom)); const targetDom = Entry.getDom( restrictor.processDomQuery(['playground', 'board', '&1', 'magnet', 'next', 0]) ); const targetRect = targetDom.getBoundingClientRect(); Entry.Utils.glideBlock(svgGroup, targetRect.left, targetRect.top, () => { restrictor.fadeInTooltip(); }); }, dom: ['playground', 'board', '&0'], }; obj = _.clone(c[COMMAND_TYPES.insertBlock]); obj.followCmd = true; c[COMMAND_TYPES.insertBlockFollowSeparate] = obj; obj = _.clone(c[COMMAND_TYPES.insertBlock]); obj.restrict = function (data, domQuery, callback, restrictor) { if (restrictor.toolTipRender) { if (restrictor.toolTipRender) { const target = Entry.Command.editor.board.code.getByPointer(data.content[2][1]); if (!target || target.isParamBlockType()) { restrictor.toolTipRender.contentIndex = 1; } else { restrictor.toolTipRender.contentIndex = 0; } } } callback(); return new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { indicator: true, callBack() {}, } ); }; obj.dom = ['playground', 'board', '&1', 'magnet']; c[COMMAND_TYPES.insertBlockFromBlockMenu] = obj; obj = _.clone(c[COMMAND_TYPES.insertBlockFromBlockMenu]); obj.followCmd = true; c[COMMAND_TYPES.insertBlockFromBlockMenuFollowSeparate] = obj; c[COMMAND_TYPES.separateBlock] = { do(block, dragMode, y) { block = this.editor.board.findBlock(block); let blockView; let blockArgument; if (block instanceof Entry.FieldBlock) { blockView = block.value.view; blockArgument = block.value; } else { blockView = block.view; } if (typeof y === 'number') { blockView.moveTo(dragMode, y); dragMode = undefined; } dragMode = dragMode === undefined ? Entry.DRAG_MODE_DRAG : dragMode; if (blockView) { blockView._toGlobalCoordinate(dragMode); } block.doSeparate(blockArgument); const { params = [] } = block._schema || {}; const shouldRerender = params.find( ({ type, menuName }) => type === 'DropdownDynamic' && isFunction(menuName) ); if (shouldRerender) { block.view.reDraw(); } }, state(block) { block = this.editor.board.findBlock(block); let blockArgument; if (block instanceof Entry.FieldBlock) { blockArgument = block.value; } else { blockArgument = block; } const data = [blockArgument]; const pointer = block.targetPointer(); data.push(pointer); if (block.getBlockType() === 'basic') { data.push(block.thread.getCount(block)); } return data; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, log(block) { block = this.editor.board.findBlock(block); const blockPointer = block.pointer(); if (block.view) { block = block.view; } return [ ['block', blockPointer], ['x', block.x], ['y', block.y], ]; }, restrict(data, domQuery, callback, restrictor) { Entry.Command.editor.board.scrollToPointer(data.content[1][1]); let isDone = false; if (restrictor.toolTipRender) { restrictor.toolTipRender.titleIndex = 0; restrictor.toolTipRender.contentIndex = 0; } const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { dimmed: true, restrict: true, callBack(isFromInit) { if (isDone || !isFromInit) { return; } if (restrictor.toolTipRender) { restrictor.toolTipRender.titleIndex = 1; restrictor.toolTipRender.contentIndex = 1; } callback(); isDone = true; tooltip.init( [ { title: data.tooltip.title, content: data.tooltip.content, target: restrictor.processDomQuery([ 'playground', 'board', 'coord', '&1', '&2', ]), }, ], { indicator: true, callBack() { callback(); }, } ); }, } ); return tooltip; }, undo: 'insertBlock', dom: ['playground', 'board', '&0'], }; obj = _.clone(c[COMMAND_TYPES.separateBlock]); obj.restrict = function (data, domQuery, callback, restrictor) { Entry.Command.editor.board.scrollToPointer(data.content[1][1]); let isDone = false; if (restrictor.toolTipRender) { restrictor.toolTipRender.titleIndex = 0; restrictor.toolTipRender.contentIndex = 0; } const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { dimmed: true, restrict: true, callBack(isFromInit) { if (isDone || !isFromInit) { return; } callback(); if (restrictor.toolTipRender) { restrictor.toolTipRender.titleIndex = 1; restrictor.toolTipRender.contentIndex = 1; } isDone = true; tooltip.init( [ { title: data.tooltip.title, content: data.tooltip.content, target: ['playground', 'board', 'trashcan'], }, ], { indicator: true, callBack() { callback(); }, } ); }, } ); return tooltip; }; obj.showMe = function (restrictor) { if (restrictor.isTooltipFaded()) { return; } restrictor.fadeOutTooltip(); const svgGroup = Entry.getDom(restrictor.processDomQuery(this.dom)); const targetDom = Entry.getDom(['playground', 'board', 'trashcan']); const targetRect = targetDom.getBoundingClientRect(); Entry.Utils.glideBlock(svgGroup, targetRect.left, targetRect.top, () => { restrictor.fadeInTooltip(); }); }; obj.followCmd = true; c[COMMAND_TYPES.separateBlockForDestroy] = obj; c[COMMAND_TYPES.moveBlock] = { do(block, x, y) { if (x !== undefined) { // do from undo stack block = this.editor.board.findBlock(block); block.moveTo(x, y); } else { block._updatePos(); } }, state(block) { block = this.editor.board.findBlock(block); return [block, block.x, block.y]; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, restrict(data, domQuery, callback, restrictor) { let isDone = false; const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { dimmed: true, restrict: true, callBack(isFromInit) { if (isDone || !isFromInit) { return; } isDone = true; callback(); tooltip.init( [ { title: data.tooltip.title, content: data.tooltip.content, target: restrictor.processDomQuery([ 'playground', 'board', 'coord', '&1', '&2', ]), }, ], { indicator: true, callBack() {}, } ); }, } ); return tooltip; }, validate: false, log(block, x, y) { block = this.editor.board.findBlock(block); if (!block || !block.view) { console.error('moveBlock: target not exist ', block); return []; } return [ ['block', block.pointer()], ['x', block.view.x], ['y', block.view.y], ]; }, undo: 'moveBlock', dom: ['playground', 'board', '&0'], }; obj = _.clone(c[COMMAND_TYPES.moveBlock]); obj.followCmd = true; obj.restrict = function (data, domQuery, callback, restrictor) { Entry.Command.editor.board.scrollToPointer(data.content[1][1]); let isDone = false; if (restrictor.toolTipRender) { restrictor.toolTipRender.titleIndex = 0; restrictor.toolTipRender.contentIndex = 0; } const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { dimmed: true, restrict: true, callBack(isFromInit) { if (isDone || !isFromInit) { return; } isDone = true; callback(); if (restrictor.toolTipRender) { restrictor.toolTipRender.titleIndex = 1; restrictor.toolTipRender.contentIndex = 1; } tooltip.init( [ { title: data.tooltip.title, content: data.tooltip.content, target: ['playground', 'board', 'trashcan'], }, ], { indicator: true, callBack() { callback(); }, } ); }, } ); return tooltip; }; c[COMMAND_TYPES.moveBlockForDestroy] = obj; obj = _.clone(c[COMMAND_TYPES.moveBlock]); obj.restrict = function (data, domQuery, callback) { callback(); return new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { callBack() {}, } ); }; obj.dom = ['playground', 'board', 'coord', '&1', '&2']; c[COMMAND_TYPES.moveBlockFromBlockMenu] = obj; cloneCommand(COMMAND_TYPES.cloneBlock, COMMAND_TYPES.addThread, [ ['undo', 'uncloneBlock'], ['dom', undefined], ]); cloneCommand(COMMAND_TYPES.uncloneBlock, COMMAND_TYPES.destroyThread, [['undo', 'cloneBlock']]); c[COMMAND_TYPES.scrollBoard] = { do(dx, dy, isPass) { if (!isPass) { this.editor.board.scroller._scroll(dx, dy); } delete this.editor.board.scroller._diffs; }, state(dx, dy) { return [-dx, -dy]; }, log(dx, dy) { return [ ['dx', dx], ['dy', dy], ]; }, recordable: Entry.STATIC.RECORDABLE.SKIP, undo: 'scrollBoard', }; c[COMMAND_TYPES.setFieldValue] = { do(pointer, value, code) { let field; if (code) { field = code.getByPointer(pointer); } else { field = this.editor.board.findBlock(pointer); } field.setValue(value, true); Entry.disposeEvent.notify(true); field._blockView.disableMouseEvent = false; }, state(pointer, value, code) { let field; if (code) { field = code.getByPointer(pointer); } else { field = this.editor.board.findBlock(pointer); } return [pointer, field._startValue || field.getValue()]; }, log(pointer, value) { return [ ['pointer', pointer], ['value', value], ]; }, restrict(data, domQuery, callback, restrictor) { let isDone = false; const isDefault = data.tooltip.isDefault; Entry.Command.editor.board.scrollToPointer(data.content[1][1]); const field = Entry.Command.editor.board.findBlock(data.content[1][1]); const blockView = field._blockView; blockView.disableMouseEvent = true; const fieldType = field.getFieldRawType(); if (restrictor.toolTipRender) { if (!isDefault) { restrictor.toolTipRender.contentIndex = 0; } else { switch (fieldType) { case 'textInput': restrictor.toolTipRender.contentIndex = 0; break; case 'dropdown': case 'dropdownDynamic': restrictor.toolTipRender.contentIndex = 1; break; case 'keyboard': restrictor.toolTipRender.contentIndex = 2; break; } } } const nextValue = data.content[2][1]; if (field instanceof Entry.FieldTextInput) { field.fixNextValue(nextValue); } const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, direction: 'left', target: domQuery, }, ], { dimmed: true, restrict: true, callBack(isFromInit) { if (isDone || !isFromInit) { return; } isDone = true; callback(); callback(); restrictor.toolTipRender.replaceContent( /&value&/gi, field.getTextValueByValue(nextValue) ); if (restrictor.toolTipRender) { const { renderData = {} } = restrictor.toolTipRender; renderData.isPrev = false; if (!isDefault) { restrictor.toolTipRender.titleIndex = 1; restrictor.toolTipRender.contentIndex = 1; } else { switch (fieldType) { case 'textInput': restrictor.toolTipRender.contentIndex = 3; break; case 'dropdown': case 'dropdownDynamic': restrictor.toolTipRender.contentIndex = 4; break; case 'keyboard': restrictor.toolTipRender.contentIndex = 5; break; } } } tooltip.init( [ { title: data.tooltip.title, content: data.tooltip.content, target: restrictor.processDomQuery([ 'playground', 'board', '&0', 'option', ]), }, ], { dimmed: true, restrict: true, callBack() { blockView.disableMouseEvent = false; }, } ); }, } ); return tooltip; }, disableMouseUpDispose: true, recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['playground', 'board', '&0'], undo: 'setFieldValue', }; c[COMMAND_TYPES.selectBlockMenu] = { do(selector, doNotFold, doNotAlign) { const blockMenu = Entry.getMainWS().blockMenu; blockMenu.selectMenu(selector, doNotFold, doNotAlign); blockMenu.align(); }, state(selector, doNotFold, doNotAlign) { const blockMenu = Entry.getMainWS().blockMenu; return [blockMenu.lastSelector, doNotFold, doNotAlign]; }, log(selector, doNotFold, doNotAlign) { return [['selector', selector]]; }, skipUndoStack: true, recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['playground', 'blockMenu', 'category', '&0'], undo: 'selectBlockMenu', }; c[COMMAND_TYPES.destroyThreads] = { do() { const threads = this.editor.board.code .getThreads() .filter((t) => t.getFirstBlock().isDeletable()) .forEach((t) => { t.destroy(); }); }, state() { const threads = this.editor.board.code .getThreads() .filter((t) => t.getFirstBlock().isDeletable()) .map((t) => t.toJSON()); return [threads]; }, log() { return []; }, undo: 'addThreads', }; c[COMMAND_TYPES.addThreads] = { do(threads) { const code = this.editor.board.code; threads.forEach((t) => { code.createThread(t); }); }, state() { return []; }, log() { return []; }, undo: 'destroyThreads', }; c[COMMAND_TYPES.destroyBlockBelow] = { do(block) { block = this.editor.board.findBlock(block); block.doDestroyBelow(true); if (block.isParamBlockType()) { block.thread?.updateValueBlock?.(); } }, state(block) { block = this.editor.board.findBlock(block); const thread = block.thread; let data; if (thread instanceof Entry.Thread) { data = thread.toJSON(false, block); } else { data = [block.toJSON()]; } return [data, block.targetPointer()]; }, log(block) { return []; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: 'recoverBlockBelow', }; c[COMMAND_TYPES.recoverBlockBelow] = { do(thread, targetPointer) { const board = this.editor.board; var thread = board.code.createThread(thread); board.insert(thread.getFirstBlock(), targetPointer); }, state(thread, targetPointer) { return [thread[0]]; }, log(thread, targetPointer) { return []; }, undo: 'destroyBlockBelow', }; cloneCommand(COMMAND_TYPES.separateBlockByCommand, COMMAND_TYPES.separateBlock); function cloneCommand(newType, oldType, props) { c[newType] = _.clone(c[oldType]); if (props && props instanceof Array) { props.forEach((prop) => { c[newType][prop[0]] = prop[1]; }); } return c[newType]; } })(Entry.Command); ================================================ FILE: src/command/commands/comment.js ================================================ 'use strict'; (function(c) { const COMMAND_TYPES = Entry.STATIC.COMMAND_TYPES; c[COMMAND_TYPES.createComment] = { do(data, board, block) { const comment = new Entry.Comment(data, board, block); if (block) { block.connectComment(comment); } else { board.code.createThread([comment], 0); } board.set({ isVisibleComment: true }); }, state(data) { return [data]; }, log() { return []; }, undo: 'removeComment', }; c[COMMAND_TYPES.removeComment] = { do(target) { const comment = this.editor.board.findBlock(target); comment.destroy(); }, state(target) { const comment = this.editor.board.findBlock(target); return [comment.toJSON(), comment.board, comment.block]; }, log() { return []; }, undo: 'createComment', }; c[COMMAND_TYPES.showAllComment] = { do(board) { board.set({ isVisibleComment: true }); }, state(board) { return [board]; }, log() { return []; }, undo: 'hideAllComment', }; c[COMMAND_TYPES.hideAllComment] = { do(board) { board.set({ isVisibleComment: false }); }, state(board) { return [board]; }, log() { return []; }, undo: 'showAllComment', }; c[COMMAND_TYPES.moveComment] = { do(target, x, y) { const comment = this.editor.board.findBlock(target); if (x) { comment.moveTo(x, y); } else { comment.updatePos(); } }, state(target) { const comment = this.editor.board.findBlock(target); return [comment, comment.x, comment.y]; }, log() { return []; }, undo: 'moveComment', }; c[COMMAND_TYPES.toggleComment] = { do(comment) { comment.set({ isOpened: !comment.isOpened, }); }, state(comment) { return [comment]; }, log() { return []; }, undo: 'toggleComment', }; c[COMMAND_TYPES.cloneComment] = { do(data, board) { const comment = new Entry.Comment(data, board); board.code.createThread([comment], 0); board.set({ isVisibleComment: true }); }, state(comment) { return [comment]; }, log() { return []; }, undo: 'uncloneComment', }; c[COMMAND_TYPES.uncloneComment] = { do(target) { const comment = this.editor.board.findBlock(target); comment.destroy(); }, state(target) { const comment = this.editor.board.findBlock(target); return [target, comment.board]; }, log() { return []; }, undo: 'cloneComment', }; c[COMMAND_TYPES.separateComment] = { do(target) { const comment = this.editor.board.findBlock(target); comment.separateFromBlock(); }, state(target) { const comment = this.editor.board.findBlock(target); return [comment.toJSON(), comment.block]; }, log() { return []; }, undo: 'connectComment', }; c[COMMAND_TYPES.connectComment] = { do(target, block) { const comment = this.editor.board.findBlock(target); comment.connectToBlock(block); }, state(target) { const comment = this.editor.board.findBlock(target); return [comment.toJSON()]; }, log() { return []; }, undo: 'separateComment', }; c[COMMAND_TYPES.writeComment] = { do(target, value) { const comment = this.editor.board.findBlock(target); comment.writeComment(value); }, state(target) { const comment = this.editor.board.findBlock(target); const json = comment.toJSON(); return [json, json.value]; }, log() { return []; }, undo: 'writeComment', }; })(Entry.Command); ================================================ FILE: src/command/commands/container.js ================================================ 'use strict'; const { createTooltip, returnEmptyArr, getExpectedData } = require('../command_util'); (function(c) { const COMMAND_TYPES = Entry.STATIC.COMMAND_TYPES; c[COMMAND_TYPES.containerSelectObject] = { do(objectId) { Entry.container.selectObject(objectId); }, state(objectId) { return [Entry.playground.object.id, objectId]; }, log(objectId) { return [ ['objectId', objectId], ['objectIndex', Entry.container.getObjectIndex(objectId)], ]; }, restrict(data, domQuery, callback) { Entry.container.scrollToObject(data.content[1][1]); return new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { dimmed: true, restrict: true, callBack() { callback(); }, } ); }, undo: 'containerSelectObject', recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['container', 'objectIndex', '&1'], }; c[COMMAND_TYPES.removeObject] = { do(objectId) { Entry.Utils.forceStopSounds(); const { name } = Entry.container.getObject(objectId); Entry.container.removeObject(objectId); Entry.Utils.doCodeChange(); Entry.toast.success( Lang.Workspace.remove_object, `${name} ${Lang.Workspace.remove_object_msg}` ); }, state(objectId) { const object = Entry.container.getObject(objectId); return [object.toJSON(), object.getIndex()]; }, log(objectId) { return [['objectId', objectId]]; }, undo: 'addObject', recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['container', 'objectId', '&0', 'removeButton'], }; c[COMMAND_TYPES.addObject] = { do(objectModel, index) { objectModel.id = getExpectedData('objectModel', {}).id || objectModel.id; Entry.container.addObjectFunc(objectModel, index); Entry.dispatchEvent('dismissModal'); Entry.Utils.doCodeChange(); }, state(objectModel, index) { objectModel.id = getExpectedData('objectModel', {}).id || objectModel.id; return [objectModel.id, index]; }, log(objectModel, index) { const { sprite, options = {} } = objectModel; const { font } = options; //$$hashKey can't saved for db const _omitFunc = _.partial(_.omit, _, '$$hashKey'); objectModel.sprite = _omitFunc(sprite); if (_.isObject(font)) { objectModel.options.font = _omitFunc(font); } return [ ['objectModel', objectModel], ['objectIndex', index], ['spriteId', sprite._id], ]; }, dom: ['.btn_confirm_modal'], restrict(data, domQuery, callback) { Entry.dispatchEvent('dismissModal'); const { tooltip: { title, content }, } = data; const tooltip = createTooltip(title, content, '.btn_confirm_modal', callback, { render: false, }); const event = Entry.getMainWS().widgetUpdateEvent; if (!data.skip) { Entry.dispatchEvent( 'openSpriteManager', getExpectedData('spriteId'), event.notify.bind(event) ); } return tooltip; }, undo: 'removeObject', validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, }; c[COMMAND_TYPES.addObjectButtonClick] = { do() { Entry.dispatchEvent('dismissModal'); Entry.dispatchEvent('openSpriteManager'); }, state: returnEmptyArr, log: returnEmptyArr, undo: 'dismissModal', recordable: Entry.STATIC.RECORDABLE.SUPPORT, validate: false, dom: ['engine', 'objectAddButton'], }; })(Entry.Command); ================================================ FILE: src/command/commands/dataTable.js ================================================ /* * */ 'use strict'; import DataTable from '../../class/DataTable'; (function(c) { const { COMMAND_TYPES, RECORDABLE } = Entry.STATIC; c[COMMAND_TYPES.dataTableAddSource] = { do(table) { Entry.playground.selectTable(table); }, state(table) { return [table]; }, log(table) { return [['table', table]]; }, recordable: RECORDABLE.SUPPORT, validate: false, undo: 'dataTableRemoveSource', dom: ['playground', 'tableAddButton'], }; c[COMMAND_TYPES.dataTableRemoveSource] = { do(table = {}) { const index = DataTable.getIndex(table); if (index < 0) { console.warn('not found table', table); return; } DataTable.tables.splice(index, 1); const isWorkspace = Entry.type === 'workspace'; if (isWorkspace) { Entry.playground.reloadPlayground(); Entry.playground.refreshPlayground(); !DataTable.tables.length && DataTable.banAllBlock(); } }, state(table) { return [table]; }, log(table) { return [['table', table]]; }, recordable: RECORDABLE.SUPPORT, validate: false, undo: 'dataTableAddSource', dom: ['playground', 'tableAddButton'], }; })(Entry.Command); ================================================ FILE: src/command/commands/engine.js ================================================ /* * */ 'use strict'; (function(c) { var COMMAND_TYPES = Entry.STATIC.COMMAND_TYPES; c[COMMAND_TYPES.toggleRun] = { do: function(callerName) { Entry.engine.toggleRun(); }, state: function() { return []; }, log: function(callerName) { return [['callerName', callerName]]; }, restrict: function(data, domQuery, callback, restrictor) { var engine = Entry.engine; if (!engine.isState('stop')) engine.toggleStop(); var isDone = false; return new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { dimmed: true, restrict: true, callBack: function(isFromInit) {}, } ); }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: 'toggleStop', dom: ['engine', '&0'], }; c[COMMAND_TYPES.toggleStop] = { do: function(callerName) { Entry.engine.toggleStop(); }, state: function() { return []; }, log: function(callerName) { return [['callerName', callerName]]; }, restrict: function(data, domQuery, callback, restrictor) { var engine = Entry.engine; if (Entry.engine.popup) Entry.engine.closeFullScreen(); if (!engine.isState('run')) engine.toggleRun(false); return new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { dimmed: true, restrict: true, callBack: function(isFromInit) { callback(); }, } ); }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: 'toggleRun', dom: ['engine', '&0'], }; })(Entry.Command); ================================================ FILE: src/command/commands/function.js ================================================ /* * */ 'use strict'; const { createTooltip, returnEmptyArr, getExpectedData } = require('../command_util'); (function(c) { const COMMAND_TYPES = Entry.STATIC.COMMAND_TYPES; c[COMMAND_TYPES.funcCreateStart] = { do(funcId) { Entry.getMainWS().setMode(Entry.Workspace.MODE_BOARD, 'cancelEdit'); funcId = getExpectedData('funcId') || funcId; Entry.playground.changeViewMode('code'); const blockMenu = Entry.variableContainer._getBlockMenu(); if (blockMenu.lastSelector !== 'func') { blockMenu.selectMenu('func'); } Entry.variableContainer.createFunction({ id: funcId }); }, state(funcId) { return [getExpectedData('funcId', funcId), 'remove']; }, log(funcId) { return [['funcId', getExpectedData('funcId') || funcId]]; }, restrict(data, domQuery, callback) { Entry.playground.changeViewMode('variable'); Entry.variableContainer.selectFilter('func'); const { tooltip: { title, content }, } = data; return createTooltip(title, content, domQuery, callback); }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['variableContainer', 'functionAddButton'], undo: 'funcEditCancel', }; c[COMMAND_TYPES.funcEditStart] = { do(id, json, type) { const func = Entry.variableContainer.getFunction(id); if (func) { Entry.Func.edit(id); } else { Entry.variableContainer.createFunction({ id, type }); } if (json) { Entry.Func.targetFunc.content.load(json); } }, state(id, json, type = 'cancel', isExist) { if (type === 'save' && id && !isExist) { Entry.variableContainer.removeFunction({ id }); } return [type]; }, log(funcId) { return [['funcId', funcId]]; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['variableContainer', 'functionAddButton'], undo: 'funcEditEnd', }; c[COMMAND_TYPES.funcEditEnd] = { do(type) { Entry.Func.isEdit = false; if (type === 'save') { Entry.getMainWS().setMode(Entry.Workspace.MODE_BOARD, 'save'); } else { Entry.getMainWS().setMode(Entry.Workspace.MODE_BOARD, 'cancelEdit'); } }, state(type) { const json = Entry.Func.targetFunc.content.toJSON(); const func = Entry.variableContainer.getFunction(Entry.Func.targetFunc.id); return [Entry.Func.targetFunc.id, json, type, !!func]; }, log(type) { return [['funcId', Entry.Func.targetFunc.id]]; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['variableContainer', 'functionAddButton'], undo: 'funcEditStart', }; c[COMMAND_TYPES.funcRemove] = { do({ id }) { Entry.variableContainer.removeFunction({ id }); }, state({ id }) { const func = Entry.variableContainer.getFunction(id); return [func]; }, log(func) { return [['funcId', func.id]]; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['variableContainer', 'functionAddButton'], undo: 'funcCreate', }; c[COMMAND_TYPES.funcCreate] = { do(func) { Entry.variableContainer.saveFunction(func); Entry.Func.registerFunction(func); Entry.Func.updateMenu(); }, state({ id }) { return [{ id }]; }, log(func) { return [['funcId', func.id]]; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['variableContainer', 'functionAddButton'], undo: 'funcRemove', }; c[COMMAND_TYPES.funcChangeType] = { do(func) { let type = 'value'; if (func.type === 'value') { type = 'normal'; } Entry.Func.changeType(func, type); }, state(func) { return [func]; }, log(func) { return [['funcId', func.id]]; }, validate: false, dom: ['variableContainer', 'functionAddButton'], undo: 'funcChangeType', }; c[COMMAND_TYPES.funcLocalVarChangeLength] = { do(func, value) { if (value === 'minus') { func.removeLastLocalVariable(); } else if (value === 'plus') { const value = func.defaultLocalVariable(); func.appendLocalVariable(value); } else { let length = func.localVariables?.length || 0; if (Entry.Utils.isNumber(value) && value >= 0) { length = value; } func.setLocalVariableLength(length); } }, state(func, value) { let prevValue; if (value === 'minus') { prevValue = 'plus'; } else if (value === 'plus') { prevValue = 'minus'; } else { prevValue = func.localVariables?.length || 0; } return [func, prevValue]; }, log(func, value) { return [ ['funcId', func.id], ['value', value], ]; }, validate: false, dom: ['variableContainer', 'funcLocalVarChangeLength', '&2'], undo: 'funcLocalVarChangeLength', }; c[COMMAND_TYPES.toggleFuncUseLocalVariables] = { do(func) { func.toggleFunctionUseLocalVariables(); }, state(func) { return [func]; }, log(func, value) { return [ ['funcId', func.id], ['value', value], ]; }, validate: false, dom: ['variableContainer', 'toggleFuncUseLocalVariables', '&2'], undo: 'toggleFuncUseLocalVariables', }; c[COMMAND_TYPES.insertFuncLocalVariable] = { do(func, value, index) { func.insertFuncLocalVariable(value, index); }, state(func, _value, index) { return [func, index]; }, log(func, value, index) { return [ ['funcId', func.id], ['value', value], ['index', index], ]; }, validate: false, dom: ['variableContainer', 'insertFuncLocalVariable', '&2'], undo: 'removeFuncLocalVariableByIndex', }; c[COMMAND_TYPES.removeFuncLocalVariableByIndex] = { do(func, index) { func.removeLocalVariable(index); }, state(func, index) { const value = func.localVariables[index]; return [func, value, index]; }, log(func, index) { return [ ['funcId', func.id], ['index', index], ]; }, validate: false, dom: ['variableContainer', 'removeFuncLocalVariableByIndex', '&2'], undo: 'insertFuncLocalVariable', }; })(Entry.Command); ================================================ FILE: src/command/commands/object.js ================================================ /* * */ 'use strict'; const { returnEmptyArr, createTooltip } = require('../command_util'); import VideoUtils from '@entrylabs/legacy-video'; import WebUsbFlasher from '../../class/hardware/webUsbFlasher'; (function (c) { const COMMAND_TYPES = Entry.STATIC.COMMAND_TYPES; c[COMMAND_TYPES.selectObject] = { do(objectId) { return Entry.container.selectObject(objectId); }, state(objectId) { const playground = Entry.playground; if (playground && playground.object) { return [playground.object.id]; } }, log(objectId) { return [objectId]; }, undo: 'selectObject', }; c[COMMAND_TYPES.objectEditButtonClick] = { do(objectId) { Entry.container.getObject(objectId).toggleEditObject(); }, state(objectId) { return []; }, log(objectId) { return [ ['objectId', objectId], ['objectIndex', Entry.container.getObjectIndex(objectId)], ]; }, skipUndoStack: true, recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['container', 'objectIndex', '&1', 'editButton'], undo: 'selectObject', }; c[COMMAND_TYPES.objectAddPicture] = { do(objectId, picture, isSelect = true) { const hashId = c[COMMAND_TYPES.objectAddPicture].hashId; if (hashId) { picture.id = hashId; delete c[COMMAND_TYPES.objectAddPicture].hashId; } Entry.container.getObject(objectId).addPicture(picture); Entry.playground.injectPicture(isSelect); isSelect && Entry.playground.selectPicture(picture); Entry.dispatchEvent('dismissModal'); }, state(objectId, picture) { return [objectId, picture]; }, log(objectId, picture) { const o = {}; o._id = picture._id; o.id = picture.id; o.dimension = picture.dimension; o.filename = picture.filename; o.fileurl = picture.fileurl; o.thumbUrl = picture.thumbUrl; o.name = picture.name; o.scale = picture.scale; return [ ['objectId', objectId], ['picture', o], ]; }, dom: ['.btn_confirm_modal'], restrict(data, domQuery, callback) { this.hashId = data.content[2][1].id; const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: '.btn_confirm_modal', }, ], { restrict: true, dimmed: true, render: false, callBack: callback, } ); const event = Entry.getMainWS().widgetUpdateEvent; if (!data.skip) { Entry.dispatchEvent( 'openPictureManager', data.content[2][1]._id, event.notify.bind(event) ); } return tooltip; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, validate: false, undo: 'objectRemovePicture', }; c[COMMAND_TYPES.objectRemovePicture] = { do(objectId, picture) { Entry.container.getObject(objectId).removePicture(picture.id); }, state(objectId, picture) { return [objectId, picture]; }, log(objectId, picture) { return [ ['objectId', objectId], ['pictureId', picture._id], ]; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, validate: false, undo: 'objectAddPicture', }; c[COMMAND_TYPES.objectAddSound] = { do(objectId, sound, isSelect = true) { const hashId = c[COMMAND_TYPES.objectAddSound].hashId; if (hashId) { sound.id = hashId; delete c[COMMAND_TYPES.objectAddSound].hashId; } const object = Entry.container.getObject(objectId); if (!object.selectedSound) { object.selectedSound = sound; } object.addSound(sound); Entry.playground.injectSound(isSelect); isSelect && Entry.playground.selectSound(sound); Entry.dispatchEvent('dismissModal'); }, state(objectId, sound) { return [objectId, sound]; }, log(objectId, sound) { const o = {}; o._id = sound._id; o.duration = sound.duration; o.ext = sound.ext; o.id = sound.id; o.filename = sound.filename; o.fileurl = sound.fileurl; o.name = sound.name; return [ ['objectId', objectId], ['sound', o], ]; }, dom: ['.btn_confirm_modal'], restrict(data, domQuery, callback) { this.hashId = data.content[2][1].id; const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: '.btn_confirm_modal', }, ], { callBack: callback, dimmed: true, restrict: true, render: false, } ); const event = Entry.getMainWS().widgetUpdateEvent; if (!data.skip) { Entry.dispatchEvent( 'openSoundManager', data.content[2][1]._id, event.notify.bind(event) ); } return tooltip; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, validate: false, undo: 'objectRemoveSound', }; c[COMMAND_TYPES.objectRemoveSound] = { do(objectId, sound) { return Entry.container.getObject(objectId).removeSound(sound.id); }, state(objectId, sound) { return [objectId, sound]; }, log(objectId, sound) { return [ ['objectId', objectId], ['soundId', sound._id], ]; }, dom: ['.btn_confirm_modal'], recordable: Entry.STATIC.RECORDABLE.SUPPORT, validate: false, undo: 'objectAddSound', }; c[COMMAND_TYPES.objectAddExpansionBlocks] = { do(blockNames) { blockNames.forEach((blockName) => { if ( typeof Entry.EXPANSION_BLOCK !== 'undefined' && typeof Entry.EXPANSION_BLOCK[blockName] !== 'undefined' ) { Entry.EXPANSION_BLOCK[blockName].init(); if (typeof Entry.expansionBlocks == 'undefined') { Entry.expansionBlocks = []; } Entry.expansionBlocks = _.union(Entry.expansionBlocks, [blockName]); } Entry.playground.blockMenu.unbanClass(blockName); }); // Entry.dispatchEvent('dismissModal'); }, state(blockNames) { return [blockNames]; }, log(blockNames) { return [['blockName', blockNames]]; }, dom: ['.btn_confirm_modal'], recordable: Entry.STATIC.RECORDABLE.SKIP, validate: false, undo: 'objectRemoveExpansionBlocks', }; c[COMMAND_TYPES.objectRemoveExpansionBlocks] = { do(blockNames) { // 사용된 블록 전체에서 검색가능해질때 사용가능. blockNames.forEach((blockName) => { Entry.playground.blockMenu.banClass(blockName); }); Entry.expansionBlocks = _.pullAll(Entry.expansionBlocks, blockNames); }, state(blockNames) { return [blockNames]; }, log(blockNames) { return [['blockName', blockNames]]; }, dom: ['.btn_confirm_modal'], recordable: Entry.STATIC.RECORDABLE.SKIP, validate: false, undo: 'objectAddExpansionBlocks', }; c[COMMAND_TYPES.objectAddAIUtilizeBlocks] = { do(blockNames) { blockNames.forEach((blockName) => { if ( typeof Entry.AI_UTILIZE_BLOCK !== 'undefined' && typeof Entry.AI_UTILIZE_BLOCK[blockName] !== 'undefined' ) { Entry.AI_UTILIZE_BLOCK[blockName].init(); if (typeof Entry.aiUtilizeBlocks == 'undefined') { Entry.aiUtilizeBlocks = []; } Entry.aiUtilizeBlocks = _.union(Entry.aiUtilizeBlocks, [blockName]); } Entry.playground.blockMenu.unbanClass(blockName); }); // Entry.dispatchEvent('dismissModal'); }, state(blockName) { return [blockName]; }, log(blockName) { return [['blockName', blockName]]; }, dom: ['.btn_confirm_modal'], recordable: Entry.STATIC.RECORDABLE.SKIP, validate: false, undo: 'objectRemoveAIUtilizeBlocks', }; c[COMMAND_TYPES.objectRemoveAIUtilizeBlocks] = { do(blockNames) { // 사용된 블록 전체에서 검색가능해질때 사용가능. // Entry.expansionBlocks = _.pull(Entry.expansionBlocks, blockName); // 사용된 블록 전체에서 검색가능해질때 사용가능. blockNames.forEach((blockName) => { if (blockName === 'video') { VideoUtils.destroy(); } Entry.playground.blockMenu.banClass(blockName); }); Entry.aiUtilizeBlocks = _.pullAll(Entry.aiUtilizeBlocks, blockNames); }, state(blockName) { return [blockName]; }, log(blockName) { return [['blockName', blockName]]; }, dom: ['.btn_confirm_modal'], recordable: Entry.STATIC.RECORDABLE.SKIP, validate: false, undo: 'objectAddAIUtilizeBlocks', }; c[COMMAND_TYPES.objectAddHardwareLiteBlocks] = { do(module) { Entry.hwLite.getConnectFailedMenu(); if (typeof Entry.hardwareLiteBlocks == 'undefined') { Entry.hardwareLiteBlocks = []; } Entry.hardwareLiteBlocks = _.union(Entry.hardwareLiteBlocks, [module.id]); Entry.hwLite.setExternalModule(module); }, state(module) { return [module]; }, log(module) { return [['module', module]]; }, dom: ['.btn_confirm_modal'], recordable: Entry.STATIC.RECORDABLE.SKIP, validate: false, undo: 'objectRemoveHardwareLiteBlocks', }; c[COMMAND_TYPES.objectRemoveHardwareLiteBlocks] = { do(module) { Entry.hardwareLiteBlocks = []; Entry.hwLite.disconnect(); Entry.hwLite.removeWebConnector(); Entry.hwLite.removeFlasher(); }, state(module) { return [module]; }, log(module) { return [['module', module]]; }, dom: ['.btn_confirm_modal'], recordable: Entry.STATIC.RECORDABLE.SKIP, validate: false, undo: 'objectAddHardwareLiteBlocks', }; c[COMMAND_TYPES.objectNameEdit] = { do(objectId, newName) { const object = Entry.container.getObject(objectId); object.setName(newName); object.setInputBlurred('nameInput'); Entry.playground.updateObjectTitle(object); Entry.playground.reloadPlayground(); }, state(objectId, newName) { const object = Entry.container.getObject(objectId); return [objectId, object.getName()]; }, log(objectId, newName) { const object = Entry.container.getObject(objectId); return [ ['objectId', objectId], ['newName', newName], ]; }, dom: ['container', 'objectId', '&0', 'nameInput'], restrict: _inputRestrictor, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: 'objectNameEdit', }; c[COMMAND_TYPES.objectReorder] = { do(newIndex, oldIndex) { Entry.container.moveElement(newIndex, oldIndex); }, state(newIndex, oldIndex) { return [oldIndex, newIndex]; }, log(newIndex, oldIndex) { return [ ['newIndex', newIndex], ['oldIndex', oldIndex], ]; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: 'objectReorder', }; c[COMMAND_TYPES.objectUpdatePosX] = { do(objectId, newX = 0) { const object = Entry.container.getObject(objectId); object.entity.setX(Number(newX)); object.updateCoordinateView(); object.setInputBlurred('xInput'); Entry.stage.updateObject(); }, state(objectId, newX) { const { entity } = Entry.container.getObject(objectId); return [objectId, entity.getX()]; }, log(objectId, newX) { const { entity } = Entry.container.getObject(objectId); return [ ['objectId', objectId], ['newX', newX], ]; }, dom: ['container', 'objectId', '&0', 'xInput'], recordable: Entry.STATIC.RECORDABLE.SUPPORT, restrict: _inputRestrictor, undo: 'objectUpdatePosX', }; c[COMMAND_TYPES.objectUpdatePosY] = { do(objectId, newY = 0) { const object = Entry.container.getObject(objectId); object.entity.setY(Number(newY)); object.updateCoordinateView(); object.setInputBlurred('yInput'); Entry.stage.updateObject(); }, state(objectId, newY) { const { entity } = Entry.container.getObject(objectId); return [objectId, entity.getY()]; }, log(objectId, newY) { const { entity } = Entry.container.getObject(objectId); return [ ['objectId', objectId], ['newY', newY], ]; }, dom: ['container', 'objectId', '&0', 'yInput'], recordable: Entry.STATIC.RECORDABLE.SUPPORT, restrict: _inputRestrictor, undo: 'objectUpdatePosY', }; c[COMMAND_TYPES.objectUpdateSize] = { do(objectId, newSize = 0) { const object = Entry.container.getObject(objectId); object.entity.setSize(Number(newSize)); object.updateCoordinateView(); object.setInputBlurred('sizeInput'); Entry.stage.updateObject(); }, state(objectId, newSize) { const { entity } = Entry.container.getObject(objectId); return [objectId, entity.getSize()]; }, log(objectId, newSize) { const { entity } = Entry.container.getObject(objectId); return [ ['objectId', objectId], ['newSize', newSize], ]; }, dom: ['container', 'objectId', '&0', 'sizeInput'], restrict: _inputRestrictor, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: 'objectUpdateSize', }; c[COMMAND_TYPES.objectUpdateRotationValue] = { do(objectId, newValue = 0) { const object = Entry.container.getObject(objectId); object.entity.setRotation(Number(newValue)); object.updateCoordinateView(); object.setInputBlurred('rotationInput'); Entry.stage.updateObject(); }, state(objectId, newValue) { const { entity } = Entry.container.getObject(objectId); return [objectId, entity.getRotation()]; }, log(objectId, newValue) { const { entity } = Entry.container.getObject(objectId); return [ ['objectId', objectId], ['newRotationValue', newValue], ]; }, dom: ['container', 'objectId', '&0', 'rotationInput'], restrict: _inputRestrictor, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: 'objectUpdateRotationValue', }; c[COMMAND_TYPES.objectUpdateDirectionValue] = { do(objectId, newValue = 0) { const object = Entry.container.getObject(objectId); object.entity.setDirection(Number(newValue)); object.updateCoordinateView(); object.setInputBlurred('directionInput'); Entry.stage.updateObject(); }, state(objectId, newValue) { const { entity } = Entry.container.getObject(objectId); return [objectId, entity.getDirection()]; }, log(objectId, newValue) { const { entity } = Entry.container.getObject(objectId); return [ ['objectId', objectId], ['newDirectionValue', newValue], ]; }, dom: ['container', 'objectId', '&0', 'directionInput'], recordable: Entry.STATIC.RECORDABLE.SUPPORT, restrict: _inputRestrictor, undo: 'objectUpdateDirectionValue', }; c[COMMAND_TYPES.objectUpdateRotateMethod] = { do(objectId, newMethod, rotation) { const object = Entry.container.getObject(objectId); object.initRotateValue(newMethod); object.setRotateMethod(newMethod); if (rotation !== undefined) { object.entity.setRotation(rotation); } Entry.stage.updateObject(); }, state(objectId, newMethod) { const { entity, rotateMethod } = Entry.container.getObject(objectId); return [objectId, rotateMethod, entity.getRotation()]; }, log(objectId, newValue) { const { entity } = Entry.container.getObject(objectId); return [ ['objectId', objectId], ['newDirectionValue', newValue], ]; }, dom: ['container', 'objectId', '&0', 'rotationMethod', '&1'], recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: 'objectUpdateRotateMethod', }; c[COMMAND_TYPES.entitySetModel] = { do(objectId, newModel, oldModel) { const { entity } = Entry.container.getObject(objectId); entity.setModel(newModel); }, state(objectId, newModel, oldModel) { return [objectId, oldModel, newModel]; }, log(objectId, newModel, oldModel) { return [ ['objectId', objectId], ['newModel', newModel], ['oldModel', oldModel], ]; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: 'entitySetModel', }; function _inputRestrictor({ tooltip, content }, domQuery, callback) { const { title: tooltipTitle, content: tooltipContent } = tooltip; _activateEdit(content[1][1], domQuery, callback); return createTooltip(tooltipTitle, tooltipContent, domQuery, callback); } function _activateEdit(objectId, domQuery, callback) { const object = Entry.container.getObject(objectId); if (!object.isEditing) { object.editObjectValues(true); } if (!_.isEmpty(domQuery)) { domQuery = Entry.getDom(domQuery); if (domQuery && !Entry.Utils.isDomActive(domQuery)) { domQuery.focus(); callback(); } } } })(Entry.Command); ================================================ FILE: src/command/commands/painter.js ================================================ /* * */ 'use strict'; (function(c) { const COMMAND_TYPES = Entry.STATIC.COMMAND_TYPES; c[COMMAND_TYPES.editPicture] = { do() { Entry.playground.painter.redo(); }, state() {}, log(objectId) { return [objectId]; }, recordable: Entry.STATIC.RECORDABLE.SKIP, undo: 'uneditPicture', }; c[COMMAND_TYPES.uneditPicture] = { type: Entry.STATIC.COMMAND_TYPES.uneditPicture, do() { Entry.playground.painter.undo(); }, state() {}, log(objectId) { return [objectId]; }, recordable: Entry.STATIC.RECORDABLE.SKIP, undo: 'editPicture', }; c[COMMAND_TYPES.processPicture] = { do() { Entry.playground.painter.redo(); }, state() {}, log(objectId) { return [objectId]; }, recordable: Entry.STATIC.RECORDABLE.SKIP, undo: 'unprocessPicture', isPass: true, }; c[COMMAND_TYPES.unprocessPicture] = { do() { Entry.playground.painter.undo(); }, state() {}, log(objectId) { return [objectId]; }, recordable: Entry.STATIC.RECORDABLE.SKIP, undo: 'processPicture', isPass: true, }; })(Entry.Command); ================================================ FILE: src/command/commands/playground.js ================================================ /* * */ 'use strict'; (function(c) { const COMMAND_TYPES = Entry.STATIC.COMMAND_TYPES; c[COMMAND_TYPES.playgroundChangeViewMode] = { do(newType, oldType) { Entry.variableContainer.selected = null; Entry.variableContainer.updateList(); Entry.playground.changeViewMode(newType); if (Entry.disposeEvent) { Entry.disposeEvent.notify(); } Entry.Utils.forceStopSounds(); }, state(newType, oldType) { return [oldType, newType]; }, log(newType, oldType) { oldType = oldType || 'code'; return [ ['newType', newType], ['oldType', oldType], ]; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: 'playgroundChangeViewMode', dom: ['playground', 'tabViewElements', '&0'], }; c[COMMAND_TYPES.playgroundClickAddPicture] = { do() { Entry.dispatchEvent('openPictureManager'); }, state() { return []; }, log() { return []; }, validate: false, //skipUndoStack: true, recordable: Entry.STATIC.RECORDABLE.SUPPORT, restrict(data, domQuery, callback, restrictor) { Entry.dispatchEvent('dismissModal'); const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { restrict: true, dimmed: true, callBack: callback, } ); return tooltip; }, undo: 'playgroundClickAddPictureCancel', dom: ['playground', 'pictureAddButton'], }; c[COMMAND_TYPES.playgroundClickAddPictureCancel] = { do() { Entry.dispatchEvent('dismissModal'); }, state() { return []; }, log() { return []; }, validate: false, //skipUndoStack: true, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: '', dom: ['playground', 'pictureAddButton'], }; c[COMMAND_TYPES.playgroundClickAddSound] = { do() { Entry.dispatchEvent('openSoundManager'); }, state() { return []; }, log() { return []; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, restrict(data, domQuery, callback, restrictor) { Entry.dispatchEvent('dismissModal'); const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { restrict: true, dimmed: true, callBack: callback, } ); return tooltip; }, undo: 'playgroundClickAddSoundCancel', dom: ['playground', 'soundAddButton'], }; c[COMMAND_TYPES.playgroundClickAddSoundCancel] = { do() { Entry.dispatchEvent('dismissModal'); }, state() { return []; }, log() { return []; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: '', dom: ['playground', 'soundAddButton'], }; c[COMMAND_TYPES.playgroundClickAddTable] = { do() { Entry.dispatchEvent('openTableManager'); }, state() { return []; }, log() { return []; }, validate: false, undo: 'playgroundClickAddTableCancel', dom: ['playground', 'tableAddButton'], }; c[COMMAND_TYPES.playgroundClickAddTableCancel] = { do() { Entry.dispatchEvent('dismissModal'); }, state() { return []; }, log() { return []; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: '', dom: ['playground', 'tableAddButton'], }; c[COMMAND_TYPES.playgroundClickAddExpansionBlock] = { do() { Entry.dispatchEvent('openExpansionBlockManager'); }, state() { return []; }, log() { return []; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, restrict(data, domQuery, callback, restrictor) { Entry.dispatchEvent('dismissModal'); const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { restrict: true, dimmed: true, callBack: callback, } ); return tooltip; }, undo: 'playgroundClickAddExpansionBlockCancel', dom: ['playground', 'soundAddButton'], }; c[COMMAND_TYPES.playgroundClickAddExpansionBlockCancel] = { do() { Entry.dispatchEvent('dismissModal'); }, state() { return []; }, log() { return []; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: '', dom: ['playground', 'soundAddButton'], }; c[COMMAND_TYPES.playgroundClickAddAIUtilizeBlock] = { do: function() { Entry.dispatchEvent('openAIUtilizeBlockManager'); }, state: function() { return []; }, log: function() { return []; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, restrict: function(data, domQuery, callback, restrictor) { Entry.dispatchEvent('dismissModal'); var tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { restrict: true, dimmed: true, callBack: callback, } ); return tooltip; }, undo: 'playgroundClickAddAIUtilizeBlockCancel', dom: ['playground', 'soundAddButton'], }; c[COMMAND_TYPES.playgroundClickAddAIUtilizeBlockCancel] = { do: function() { Entry.dispatchEvent('dismissModal'); }, state: function() { return []; }, log: function() { return []; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: '', dom: ['playground', 'soundAddButton'], }; c[COMMAND_TYPES.playgroundClickAddHardwareLiteBlock] = { do() { Entry.dispatchEvent('openHardwareLiteBlockManager'); }, state() { return []; }, log() { return []; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, restrict(data, domQuery, callback, restrictor) { Entry.dispatchEvent('dismissModal'); const tooltip = new Entry.Tooltip( [ { title: data.tooltip.title, content: data.tooltip.content, target: domQuery, }, ], { restrict: true, dimmed: true, callBack: callback, } ); return tooltip; }, undo: 'playgroundClickAddHardwareLiteBlockCancel', dom: ['playground', 'soundAddButton'], }; c[COMMAND_TYPES.playgroundClickAddHardwareLiteBlockCancel] = { do: function() { Entry.dispatchEvent('dismissModal'); }, state: function() { return []; }, log: function() { return []; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: '', dom: ['playground', 'soundAddButton'], }; })(Entry.Command); ================================================ FILE: src/command/commands/scene.js ================================================ /* * */ 'use strict'; const { createTooltip } = require('../command_util'); (function(c) { const COMMAND_TYPES = Entry.STATIC.COMMAND_TYPES; c[COMMAND_TYPES.sceneAdd] = { /** * @param {!object|string} sceneId can be sceneId or scene object * @param {?number} sceneIndex * @param {?Array} objects will be add to new scene, for undo function */ do(sceneId, sceneIndex, objects) { if (Entry.expectedAction) { sceneId = Entry.expectedAction[1][1]; } Entry.scene.addScene(sceneId, sceneIndex); if (objects) { Entry.container.setObjects(objects); } }, state(sceneId, sceneIndex) { if (!sceneIndex) { sceneIndex = Entry.scene.getScenes().length; } if (Entry.expectedAction) { sceneId = Entry.expectedAction[1][1]; } if (typeof sceneId !== 'string') { sceneId = sceneId.id; } return [sceneId]; }, log(sceneId) { if (Entry.expectedAction) { sceneId = Entry.expectedAction[1][1]; } return [['sceneId', sceneId]]; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['scene', 'addButton'], undo: 'sceneRemove', }; c[COMMAND_TYPES.sceneRemove] = { do(sceneId) { Entry.scene.removeScene(sceneId); }, state(sceneId) { const scene = Entry.scene.getSceneById(sceneId); const sceneJSON = { id: scene.id, name: scene.name, }; const sceneIndex = Entry.scene.getScenes().indexOf(scene); const objects = Entry.container.getSceneObjects(scene).map((o) => o.toJSON()); return [sceneJSON, sceneIndex, objects]; }, log(sceneId) { return [['sceneId', sceneId]]; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['scene', 'removeButton', '&0'], undo: 'sceneAdd', }; c[COMMAND_TYPES.sceneRename] = { do(sceneId, newName) { const scene = Entry.scene.getSceneById(sceneId); scene.name = newName; scene.view.nameField.value = newName; setTimeout(() => { Entry.scene.resize(); }, 0); }, state(sceneId) { const scene = Entry.scene.getSceneById(sceneId); return [sceneId, scene.name]; }, log(sceneId, newName) { return [['sceneId', sceneId], ['newName', newName]]; }, restrict(data, domQuery, callback) { const { content: contentData, tooltip: { title, content }, } = data; callback(); const scene = Entry.scene.getSceneById(contentData[1][1]); scene.view.nameField.focus(); return createTooltip(title, content, domQuery, callback); }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['scene', 'nameField', '&0'], undo: 'sceneRename', }; c[COMMAND_TYPES.sceneSelect] = { do(sceneId) { const scene = Entry.scene.getSceneById(sceneId); Entry.scene.selectScene(scene); }, state(sceneId) { return [Entry.scene.selectedScene.id]; }, log(sceneId) { return [['sceneId', sceneId]]; }, recordable: Entry.STATIC.RECORDABLE.SUPPORT, dom: ['scene', 'view', '&0'], undo: 'sceneSelect', }; })(Entry.Command); ================================================ FILE: src/command/commands/textbox.js ================================================ /* * */ 'use strict'; (function(c) { var COMMAND_TYPES = Entry.STATIC.COMMAND_TYPES; c[COMMAND_TYPES.editText] = { do: function(text, prevText) { Entry.playground.object.setText(text); Entry.playground.object.entity.setText(text); Entry.dispatchEvent('textEdited'); }, state: function(text, prevText) { return [prevText, text]; }, log: function() { return []; }, validate: false, recordable: Entry.STATIC.RECORDABLE.SUPPORT, undo: 'editText', }; })(Entry.Command); ================================================ FILE: src/command/commands/variableContainer.js ================================================ /* * */ 'use strict'; const { createTooltip, returnEmptyArr, getExpectedData } = require('../command_util'); (function(c) { const { COMMAND_TYPES, RECORDABLE } = Entry.STATIC; const { variableContainerSelectFilter, variableContainerClickVariableAddButton, variableContainerAddVariable, variableAddSetName, variableContainerRemoveVariable, variableContainerAddMessage, variableContainerRemoveMessage, messageSetName, variableAddSetScope, variableAddSetCloud, variableSetVisibility, variableSetDefaultValue, variableSetSlidable, variableSetMinValue, variableSetMaxValue, variableContainerClickListAddButton, variableContainerAddList, variableContainerRemoveList, listAddSetName, listAddSetScope, listAddSetCloud, listSetVisibility, listChangeLength, listSetDefaultValue, setMessageEditable, setVariableEditable, setListEditable, variableSetName, listSetName, variableContainerClickMessageAddButton, } = COMMAND_TYPES; c[variableContainerSelectFilter] = { do(newType) { getVC().selectFilter(newType); }, state(newType, oldType) { return [oldType, newType]; }, log(newType, oldType = 'all') { return [ ['newType', newType], ['oldType', oldType], ]; }, recordable: RECORDABLE.SUPPORT, undo: 'variableContainerSelectFilter', dom: ['variableContainer', 'filter', '&0'], }; c[variableContainerClickVariableAddButton] = { do() { getVC().clickVariableAddButton(); }, state: returnEmptyArr, log: returnEmptyArr, recordable: RECORDABLE.SUPPORT, get undo() { try { getVC()._getAddPanel().view.name.value = ''; } catch (e) {} return 'variableContainerClickVariableAddButton'; }, dom: ['variableContainer', 'variableAddButton'], }; c[variableContainerClickMessageAddButton] = { do() { getVC().clickMessageAddButton(); }, state: returnEmptyArr, log: returnEmptyArr, recordable: RECORDABLE.SUPPORT, get undo() { try { getVC()._getAddPanel().view.name.value = ''; } catch (e) {} return 'variableContainerClickMessageAddButton'; }, dom: ['variableContainer', 'variableAddButton'], }; c[variableContainerAddVariable] = { do(variable) { const id = _.result(getExpectedData('variable'), 'id'); if (id) { variable.id_ = id; } getVC().addVariable(variable); }, state(variable) { variable = _toJSON(variable); variable.id = _.result(getExpectedData('variable'), 'id') || variable.id; return [variable]; }, log(variable) { return [['variable', _toJSON(variable)]]; }, recordable: RECORDABLE.SUPPORT, validate: false, undo: 'variableContainerRemoveVariable', restrict(data, domQuery, callback) { getVC().clickVariableAddButton(true, true); $('.entryVariableAddSpaceInputWorkspace').val( _.result(getExpectedData('variable'), 'name') || '' ); const { title, content } = data.tooltip; callback(); return createTooltip(title, content, domQuery, callback); }, dom: ['variableContainer', 'variableAddConfirmButton'], }; c[variableAddSetName] = { do(value) { let { dom } = c[variableAddSetName]; dom = Entry.getDom(dom); dom._focused = false; dom.value = getExpectedData('value', value); }, state() { return ['']; }, log(value) { return [['value', getExpectedData('value', value)]]; }, restrict(data, domQuery, callback) { getVC().clickVariableAddButton(true); const dom = Entry.getDom(this.dom); Entry.Utils.focusIfNotActive(dom); dom.enterKeyDisabled = true; const { title, content } = data.tooltip; return createTooltip(title, content, domQuery, callback, { noDispose: true, }); }, validate: false, recordable: RECORDABLE.SUPPORT, undo: 'variableAddSetName', dom: ['variableContainer', 'variableAddInput'], }; c[variableContainerRemoveVariable] = { do(variable) { getVC().removeVariable(variable); }, state(variable) { return [_toJSON(variable)]; }, log(variable) { return [['variable', _toJSON(variable)]]; }, recordable: RECORDABLE.SUPPORT, validate: false, undo: 'variableContainerAddVariable', dom: ['variableContainer', 'variableAddConfirmButton'], }; c[variableContainerAddMessage] = { do(message) { message.id = _.result(getExpectedData('message'), 'id') || message.id; getVC().addMessage(message); }, state(message) { message.id = _.result(getExpectedData('message'), 'id') || message.id; return [message]; }, log({ name, id }) { return [['message', { name, id }]]; }, validate: false, recordable: RECORDABLE.SUPPORT, undo: 'variableContainerRemoveMessage', dom: ['variableContainer', 'messageAddButton'], }; c[variableContainerRemoveMessage] = { do({ id }) { const VC = getVC(); VC.removeMessage(VC.getMessage(id)); }, state({ id, name }) { return [{ id, name }]; }, log({ id, name }) { return [['message', { name, id }]]; }, validate: false, recordable: RECORDABLE.SUPPORT, undo: 'variableContainerAddMessage', dom: ['variableContainer', 'messageAddButton'], }; c[messageSetName] = { do(id, newName) { const VC = getVC(); const message = VC.getMessage(id); const nameField = message.listElement.nameField; nameField._focused = false; VC.changeMessageName(message, newName); }, state(id) { const { name } = getVC().getMessage(id); return [id, name]; }, log(id, newName) { return [ ['id', id], ['newName', newName], ]; }, restrict(data, domQuery, callback) { const { tooltip: { title, content }, } = data; callback(); const VC = getVC(); const message = VC.getMessage(domQuery[2]); delete message.listElement.nameField.isFirst; VC.activateMessageEditView(message); return createTooltip(title, content, domQuery, callback); }, recordable: RECORDABLE.SUPPORT, undo: 'messageSetName', dom: ['variableContainer', 'messageList', '&0'], }; c[variableAddSetScope] = { do(type = 'global', isCloud = false) { const VC = getVC(); const info = VC.variableAddPanel.info; if (type === 'global') { info.object = null; info.isCloud = isCloud; } else if (type === 'local') { const { object } = Entry.playground; if (!object) { return; } info.object = object.id; info.isCloud = false; } VC.updateVariableAddView('variable'); }, state() { const { variableAddPanel: { object, isCloud }, } = getVC(); return [object ? 'local' : 'global', isCloud]; }, log(type) { return [['type', type]]; }, recordable: RECORDABLE.SUPPORT, undo: 'variableAddSetScope', dom: ['variableContainer', 'variableScope', '&0'], }; c[variableAddSetCloud] = { do(type) { const VC = getVC(); let isCloud; let isRealTime; if (type === 'cloud') { isCloud = true; } else if (type === 'real_time') { isRealTime = true; } VC.variableAddPanel.info.isCloud = isCloud; VC.variableAddPanel.info.isRealTime = isRealTime; VC.updateVariableAddView('variable'); }, state() { const { variableAddPanel: { info: { isCloud, isRealTime }, }, } = getVC(); return [isCloud, isRealTime]; }, log(type) { return [['type', type]]; }, recordable: RECORDABLE.SUPPORT, undo: 'variableAddSetCloud', dom: ['variableContainer', 'variableCloud'], }; c[variableSetVisibility] = { do(id, value) { const VC = getVC(); const variable = VC.getVariable(id); variable.setVisible(value); VC.updateVariableSettingView(variable); }, state(id) { const VC = getVC(); const variable = VC.getVariable(id); return [id, variable.isVisible()]; }, log(id, value) { return [ ['id', id], ['value', value], ]; }, recordable: RECORDABLE.SUPPORT, undo: 'variableSetVisibility', dom: ['variableContainer', 'variableSetVisibility'], }; c[variableSetDefaultValue] = { do(id, value) { const VC = getVC(); const variable = VC.getVariable(id); Entry.getDom(['variableContainer', 'variableSetDefaultValue'])._focused = false; variable.setValue(value); VC.updateVariableSettingView(variable); }, state(id) { const VC = getVC(); const variable = VC.getVariable(id); return [id, variable.getValue()]; }, log(id, value) { return [ ['id', id], ['value', value], ]; }, restrict({ tooltip }, domQuery, callback) { const { title: tooltipTitle, content: tooltipContent } = tooltip; return createTooltip(tooltipTitle, tooltipContent, domQuery, callback, { noDispose: true, }); }, recordable: RECORDABLE.SUPPORT, undo: 'variableSetDefaultValue', dom: ['variableContainer', 'variableSetDefaultValue'], }; c[variableSetSlidable] = { do(id, type, cValue) { const VC = getVC(); const variable = VC.getVariable(id); VC.setVariableSlidable(variable, type, cValue); }, state(id) { const VC = getVC(); const variable = VC.getVariable(id); return [id, variable.getType(), variable.getValue()]; }, log(id, value) { return [ ['id', id], ['value', value], ]; }, recordable: RECORDABLE.SUPPORT, undo: 'variableSetSlidable', dom: ['variableContainer', 'slideCheck'], }; c[variableSetMinValue] = { do(id, value) { const VC = getVC(); const variable = VC.getVariable(id); variable.setMinValue(value); VC.updateVariableSettingView(variable); }, state(id) { const VC = getVC(); const variable = VC.getVariable(id); return [id, variable.getMinValue()]; }, log(id) { const VC = getVC(); const variable = VC.getVariable(id); return [ ['id', id], ['value', variable.getMinValue()], ]; }, recordable: RECORDABLE.SUPPORT, undo: 'variableSetMinValue', dom: ['variableContainer', 'variableMinValue'], }; c[variableSetMaxValue] = { do(id, value) { const VC = getVC(); const variable = VC.getVariable(id); variable.setMaxValue(value); VC.updateVariableSettingView(variable); }, state(id) { const VC = getVC(); const variable = VC.getVariable(id); return [id, variable.getMaxValue()]; }, log(id) { const VC = getVC(); const variable = VC.getVariable(id); return [ ['id', id], ['value', variable.getMaxValue()], ]; }, recordable: RECORDABLE.SUPPORT, undo: 'variableSetMaxValue', dom: ['variableContainer', 'variableMaxValue'], }; c[variableContainerClickListAddButton] = { do() { getVC().clickListAddButton(); }, state: returnEmptyArr, log: returnEmptyArr, recordable: RECORDABLE.SUPPORT, get undo() { try { getVC()._getAddPanel('list').view.name.value = ''; } catch (e) {} return 'variableContainerClickListAddButton'; }, dom: ['variableContainer', 'listAddButton'], }; c[variableContainerAddList] = { do(list) { const id = _.result(getExpectedData('list'), 'id'); if (id) { if (list.setId) { list.setId(id); } else { list.id = id; } } getVC().addList(list); }, state(list) { list = _toJSON(list); list.id = _.result(getExpectedData('list'), 'id') || list.id; return [list]; }, log(list) { list = _toJSON(list); list.id = _.result(getExpectedData('list'), 'id') || list.id; return [['list', list]]; }, recordable: RECORDABLE.SUPPORT, validate: false, undo: 'variableContainerRemoveList', restrict(data, domQuery, callback) { getVC().clickListAddButton(true, true); Entry.getDom(['variableContainer', 'listAddInput']).value = _.result(getExpectedData('list'), 'name') || ''; const { title, content } = data.tooltip; callback(); return createTooltip(title, content, domQuery, callback); }, dom: ['variableContainer', 'listAddConfirmButton'], }; c[variableContainerRemoveList] = { do(list) { getVC().removeList(list); }, state(list) { return [_toJSON(list)]; }, log(list) { return [['list', _toJSON(list)]]; }, recordable: RECORDABLE.SUPPORT, validate: false, undo: 'variableContainerAddList', dom: ['variableContainer', 'listAddConfirmButton'], }; c[listAddSetName] = { do(value) { let { dom } = c[listAddSetName]; dom = Entry.getDom(dom); dom._focused = false; dom.value = getExpectedData('value', value); }, state() { return ['']; }, log(value) { return [['value', getExpectedData('value', value)]]; }, restrict(data, domQuery, callback) { getVC().clickListAddButton(true); const dom = Entry.getDom(this.dom); Entry.Utils.focusIfNotActive(dom); dom.enterKeyDisabled = true; const { title, content } = data.tooltip; return createTooltip(title, content, domQuery, callback, { noDispose: true, }); }, validate: false, recordable: RECORDABLE.SUPPORT, undo: 'listAddSetName', dom: ['variableContainer', 'listAddInput'], }; c[listAddSetScope] = { do(type = 'global', isCloud = false) { const VC = getVC(); const info = VC.listAddPanel.info; if (type === 'global') { info.object = null; info.isCloud = isCloud; } else if (type === 'local') { const { object } = Entry.playground; if (!object) { return; } info.object = object.id; info.isCloud = false; } VC.updateVariableAddView('list'); }, state() { const { listAddPanel: { object, isCloud }, } = getVC(); return [object ? 'local' : 'global', isCloud]; }, log(type) { return [['type', type]]; }, recordable: RECORDABLE.SUPPORT, undo: 'listAddSetScope', dom: ['variableContainer', 'listScope', '&0'], }; c[listAddSetCloud] = { do(type) { const VC = getVC(); let isCloud; let isRealTime; if (type === 'cloud') { isCloud = true; } else if (type === 'real_time') { isRealTime = true; } VC.listAddPanel.info.isCloud = isCloud; VC.listAddPanel.info.isRealTime = isRealTime; VC.updateVariableAddView('list'); }, state() { const { listAddPanel: { info: { isCloud, isRealTime }, }, } = getVC(); return [isCloud, isRealTime]; }, log(type) { return [['type', type]]; }, recordable: RECORDABLE.SUPPORT, undo: 'listAddSetCloud', dom: ['variableContainer', 'listCloud'], }; c[listSetVisibility] = { do(id, value) { const VC = getVC(); const list = VC.getList(id); list.setVisible(value); VC.updateListSettingView(list); }, state(id) { return [ id, getVC() .getList(id) .isVisible(), ]; }, log(id, value) { return [ ['id', id], ['value', value], ]; }, restrict: _listActiveRestrictor, recordable: RECORDABLE.SUPPORT, undo: 'listSetVisibility', dom: ['variableContainer', 'listSetVisibility'], }; c[listChangeLength] = { async do(id, value) { const VC = getVC(); const list = VC.getList(id); const length = list.getArray().length; let result; if (value === 'minus') { result = Math.max(0, length - 1); await list.deleteValue(result); } else if (value === 'plus') { result = length + 1; await list.appendValue(0); } else if (Entry.Utils.isNumber(value) && value >= 0) { result = value; } else { result = length; } VC.setListLength(list, result); }, state(id) { return [id, getVC().getList(id).array_.length]; }, log(id, value) { return [ ['id', id], ['value', value], ['dom', Entry.Utils.isNumber(value) ? 'lengthInput' : value], ]; }, recordable: RECORDABLE.SUPPORT, undo: 'listChangeLength', restrict({ tooltip, content }, domQuery, callback) { _updateSelected(content); const { title: tooltipTitle, content: tooltipContent } = tooltip; return createTooltip(tooltipTitle, tooltipContent, domQuery, callback, { noDispose: true, }); }, dom: ['variableContainer', 'listChangeLength', '&2'], }; c[listSetDefaultValue] = { do(id, idx = 0, data = '0') { const VC = getVC(); const list = VC.getList(id); list.getArray()[idx] = { data }; VC.updateListSettingView(); //list.updateView(); }, state(id, idx) { const { array_ } = getVC().getList(id); return [id, idx, array_[idx].data]; }, log(id, idx, data) { return [ ['id', id], ['idx', idx], ['data', data], ]; }, recordable: RECORDABLE.SUPPORT, undo: 'listSetDefaultValue', restrict(data, domQuery, callback) { _updateSelected(data.content); Entry.Utils.focusIfNotActive(Entry.getDom(domQuery)); const { title, content } = data.tooltip; return createTooltip(title, content, domQuery, callback, { noDispose: true, }); }, dom: ['variableContainer', 'listDefaultValue', '&1'], }; c[setMessageEditable] = { do(id) { const VC = getVC(); const message = VC.getMessage(id); VC.activateMessageEditView(message); message.listElement.removeClass('activeForce'); }, state(id) { return [id]; }, log(id) { return [['id', id]]; }, recordable: RECORDABLE.SUPPORT, undo: 'setMessageEditable', restrict(data, domQuery, callback) { Entry.Utils.blur(); getVC() .getMessage(data.content[1][1]) .listElement.addClass('activeForce'); const { title, content } = data.tooltip; return createTooltip(title, content, domQuery, callback); }, dom: ['variableContainer', 'messageEditButton', '&0'], }; c[setVariableEditable] = { do(id, value = true) { const VC = getVC(); const variable = VC.getVariable(id); const { nameField } = variable.listElement; if (value) { VC.updateSelectedVariable(variable); } else { nameField.blur(); VC.updateSelectedVariable(null, 'variable'); } }, state(id) { return [id]; }, log(id) { return [['id', id]]; }, recordable: RECORDABLE.SUPPORT, undo: 'setVariableEditable', restrict(data, domQuery, callback) { Entry.Utils.blur(); const VC = getVC(); VC.updateSelectedVariable(null, 'variable'); VC.getVariable(data.content[1][1]).listElement.addClass('activeForce'); const { title, content } = data.tooltip; return createTooltip(title, content, domQuery, callback); }, dom: ['variableContainer', 'variableEditButton', '&0'], }; c[setListEditable] = { do(id) { const VC = getVC(); const variable = VC.getList(id); // const { nameField } = variable.listElement; // nameField.removeAttribute('disabled'); VC.updateSelectedVariable(variable); // nameField.focus(); }, state(id) { return [id]; }, log(id) { return [['id', id]]; }, recordable: RECORDABLE.SUPPORT, undo: 'setListEditable', restrict(data, domQuery, callback) { Entry.Utils.blur(); getVC() .getList(data.content[1][1]) .listElement.addClass('activeForce'); const { title, content } = data.tooltip; return createTooltip(title, content, domQuery, callback); }, dom: ['variableContainer', 'listEditButton', '&0'], }; c[variableSetName] = { do(id, value) { const VC = getVC(); VC.changeVariableName(VC.getVariable(id), value); }, state(id) { return [ id, getVC() .getVariable(id) .getName(), ]; }, log(id, value) { return [ ['id', id], ['value', value], ]; }, restrict({ tooltip, content }, domQuery, callback) { _updateSelected(content); Entry.Utils.focusIfNotActive(domQuery); const { title: tooltipTitle, content: tooltipContent } = tooltip; return createTooltip(tooltipTitle, tooltipContent, domQuery, callback, { noDispose: true, }); }, recordable: RECORDABLE.SUPPORT, undo: 'variableSetName', dom: ['variableContainer', 'variableName', '&0'], }; c[listSetName] = { do(id, value) { const VC = getVC(); VC.changeListName(VC.getList(id), value); }, state(id) { return [ id, getVC() .getList(id) .getName(), ]; }, log(id, value) { return [ ['id', id], ['value', value], ]; }, restrict({ tooltip, content }, domQuery, callback) { _updateSelected(content); Entry.Utils.focusIfNotActive(domQuery); const { title: tooltipTitle, content: tooltipContent } = tooltip; return createTooltip(tooltipTitle, tooltipContent, domQuery, callback, { noDispose: true, }); }, recordable: RECORDABLE.SUPPORT, undo: 'listSetName', dom: ['variableContainer', 'listName', '&0'], }; //utilities //if data has toJSON method //return data.toJSON() //else just return data as is function _toJSON(data) { return _.result(data, 'toJSON') || data; } function getVC() { return Entry.variableContainer; } function _updateSelected(content) { const VC = getVC(); const vId = content[1][1]; const v = VC.getVariable(vId) || VC.getList(vId); if (v) { VC.updateSelectedVariable(v); } } function _listActiveRestrictor({ tooltip, content }, domQuery, callback) { _updateSelected(content); const { title: tooltipTitle, content: tooltipContent } = tooltip; return createTooltip(tooltipTitle, tooltipContent, domQuery, callback); } })(Entry.Command); ================================================ FILE: src/core/collection.js ================================================ 'use strict'; /* * Entry Collection object constructor. */ Entry.Collection = class Collection { constructor(data) { this.length = 0; /* * object for hashing data with id * @private */ this._hashMap = {}; /* * observers */ this._observers = []; this.set(data); } /* setters */ set(data) { while (this.length) { Array.prototype.pop.call(this); } const hashMap = this._hashMap; for (const key in hashMap) { delete hashMap[key]; } if (data !== undefined) { for (let i = 0, len = data.length; i < len; i++) { const datum = data[i]; hashMap[datum.id] = datum; Array.prototype.push.call(this, datum); } } } push(elem) { this._hashMap[elem.id] = elem; Array.prototype.push.call(this, elem); } unshift() { const args = Array.prototype.slice.call(arguments, 0); const hashMap = this._hashMap; for (let i = args.length - 1; i >= 0; i--) { const datum = args[i]; Array.prototype.unshift.call(this, datum); hashMap[datum.id] = datum; } } insert(datum, index) { Array.prototype.splice.call(this, index, 0, datum); this._hashMap[datum.id] = datum; } has(id) { return !!this._hashMap[id]; } get(id) { return this._hashMap[id]; } at(index) { return this[index]; } getAll() { const len = this.length; const ret = []; for (let i = 0; i < len; i++) { ret.push(this[i]); } return ret; } indexOf(obj) { return Array.prototype.indexOf.call(this, obj); } find(cond) { const ret = []; let flag; for (let i = 0, len = this.length; i < len; i++) { flag = true; const datum = this[i]; for (const key in cond) { if (cond[key] != datum[key]) { flag = false; break; } } if (flag) { ret.push(datum); } } return ret; } pop() { const datum = Array.prototype.pop.call(this); delete this._hashMap[datum.id]; return datum; } shift() { const datum = Array.prototype.shift.call(this); delete this._hashMap[datum.id]; return datum; } slice(index, amount) { const data = Array.prototype.slice.call(this, index, amount); const hashMap = this._hashMap; for (const i in data) { delete hashMap[data[i].id]; } return data; } remove = function(datum) { const index = this.indexOf(datum); if (index > -1) { delete this._hashMap[datum.id]; this.splice(index, 1); } }; splice(index, amount) { const args = Array.prototype.slice.call(arguments, 2); const hashMap = this._hashMap; amount = amount === undefined ? this.length - index : amount; const splicedData = Array.prototype.splice.call(this, index, amount); for (let i = 0, len = splicedData.length; i < len; i++) { delete hashMap[splicedData[i].id]; } for (let i = 0, len = args.length; i < len; i++) { const datum = args[i]; Array.prototype.splice.call(this, index++, 0, datum); this._hashMap[datum.id] = datum; } return splicedData; } clear() { while (this.length) { Array.prototype.pop.call(this); } this._hashMap = {}; } map(fn, param) { const array = []; for (let i = 0, len = this.length; i < len; i++) { array.push(fn(this[i], param)); } return array; } moveFromTo(from, to) { const max = this.length - 1; if (from < 0 || to < 0 || from > max || to > max) { return; } Array.prototype.splice.call(this, to, 0, Array.prototype.splice.call(this, from, 1)[0]); } sort() {} /* import & export */ fromJSON() {} toJSON() { const json = []; for (let i = 0, len = this.length; i < len; i++) { json.push(this[i].toJSON()); } return json; } /* observe methods */ observe() {} unobserve() {} notify() {} /* end function */ destroy() {} }; ================================================ FILE: src/core/db.js ================================================ 'use strict'; Entry.db = class DB { constructor() { this.data = {}; this.typeMap = {}; } add(datum) { this.data[datum.id] = datum; const type = datum.type; if (this.typeMap[type] === undefined) { this.typeMap[type] = {}; } this.typeMap[type][datum.id] = datum; } has(id) { return this.data.hasOwnProperty(id); } remove(id) { if (!this.has(id)) { return; } const datum = this.data[id]; delete this.typeMap[datum.type][id]; delete this.data[id]; } get(id) { return this.data[id]; } find() {} clear() { this.data = {}; this.typeMap = {}; } }; ================================================ FILE: src/core/dom.ts ================================================ import { EntryDom, EntryDomConstructor } from '../../types/index'; type HandleableClickEvent = JQuery.ClickEvent & { handled: boolean }; const createEntryDom: EntryDomConstructor = function(tag, options) { const tagRegex = /<(\w+)>/; let dom: EntryDom; if (tag instanceof HTMLElement) { dom = $(tag); } else if (tag instanceof jQuery) { dom = tag as JQuery; } else if (typeof tag === 'string' && tagRegex.test(tag)) { dom = $(tag); } else { dom = $(`<${tag}>`); } //NOTE options 가 없으면 bindOnClick 이라는 함수가 없다. 의도한건지 모르겠음. if (options === undefined) { return dom; } options.id && dom.attr('id', options.id); options.class && dom.addClass(options.class); options.classes && options.classes.forEach(dom.addClass.bind(dom)); options.text && dom.text(options.text); options.src && dom.attr('src', options.src); options.href && dom.attr('href', options.href); options.parent && options.parent.append(dom); dom.bindOnClick = function() { let child: any; let func: Function; const handler = function(e: HandleableClickEvent) { e.stopImmediatePropagation(); if (e.handled) { return; } e.handled = true; func.call(this, e); }; if (arguments.length > 1) { func = arguments[1] instanceof Function ? arguments[1] : function() {}; child = typeof arguments[0] === 'string' ? arguments[0] : ''; } else { func = arguments[0] instanceof Function ? arguments[0] : function() {}; } if (child) { $(this).on('click tab', child, handler); } else { $(this).on('click tab', handler); } return this; }; return dom; }; export default createEntryDom; Entry.Dom = createEntryDom; ================================================ FILE: src/core/event.js ================================================ 'use strict'; Entry.Event = class Event { constructor(sender) { this._sender = sender; this._listeners = []; } attach(obj, fn) { const that = this; const listener = { obj, fn, destroy() { that.detach(this); }, }; this._listeners.push(listener); return listener; } detach(listener) { const listeners = this._listeners || []; const index = listeners.indexOf(listener); if (index > -1) { return listeners.splice(index, 1); } } clear() { const listeners = this._listeners; while (listeners.length) { listeners.pop().destroy(); } } notify() { const args = arguments; this._listeners.slice().forEach(function(listener) { try { listener.fn.apply(listener.obj, args); } catch (e) { console.warn(e, listener, listener.fn); } }); } hasListeners() { return !!this._listeners.length; } }; ================================================ FILE: src/core/model.js ================================================ // 'use strict'; /* * Entry Model object generator. * @param {object} obj */ Entry.Model = function(obj, isSeal) { const model = Entry.Model; model.generateSchema(obj); model.generateSetter(obj); model.generateObserve(obj); if (isSeal === undefined || isSeal) { Object.seal(obj); } return obj; }; (function(m) { m.generateSchema = function(obj) { let schema = obj.schema; if (schema === undefined) { return; } try { schema = JSON.parse(JSON.stringify(schema)); } catch (e) { console.log(schema); console.error(e); } obj.data = {}; for (const key in schema) { (function(localKey) { obj.data[localKey] = schema[localKey]; Object.defineProperty(obj, localKey, { get() { return obj.data[localKey]; }, }); })(key); } obj._toJSON = this._toJSON; }; m.generateSetter = function(obj) { obj.set = this.set; }; m.set = function(data, isSilent) { const oldValue = {}; const keys = Object.keys(data); for (const key in this.data) { if (data[key] !== undefined) { if (data[key] === this.data[key]) { keys.splice(keys.indexOf(key), 1); } else { oldValue[key] = this.data[key]; if (data[key] instanceof Array) { this.data[key] = data[key].concat(); } else { this.data[key] = data[key]; } } } } if (!isSilent) { this.notify(keys, oldValue); } }; m.generateObserve = function(obj) { obj.observers = []; obj.observe = this.observe; obj.unobserve = this.unobserve; obj.notify = this.notify; }; /* * @param {object} object that observe this model * @param {string} eventFunc will be call when notify * @param {?object} attrs includes which property to watch. Should be array or null. * @param {boolean} isNotify */ m.observe = function(object, funcName, attrs, isNotify) { const observer = new Entry.Observer(this.observers, object, funcName, attrs); if (isNotify !== false) { object[funcName]([]); } return observer; }; m.unobserve = function(observer) { observer.destroy(); }; /* * @param {object|string} key * @param {} oldValue */ m.notify = function(keys, oldValue) { if (typeof keys === 'string') { keys = [keys]; } const that = this; const observers = that.observers; if (!observers.length) { return; } observers.forEach((observeData) => { let attrs = keys; if (observeData.attrs !== undefined) { attrs = _.intersection(observeData.attrs, keys); } if (!attrs.length) { return; } observeData.object[observeData.funcName]( attrs.forEach((key) => ({ name: key, object: that, oldValue: oldValue[key], })) ); }); }; m._toJSON = function() { const json = {}; for (const key in this.data) { json[key] = this.data[key]; } return json; }; })(Entry.Model); ================================================ FILE: src/core/modelClass.ts ================================================ import intersection from 'lodash/intersection'; export default abstract class ModelClass { public data: Partial; public observers: any[] = []; // new Entry.Observer protected schema: T; protected constructor(schema: T, isSeal?: boolean) { this.schema = schema; this.generateSchema(); if (isSeal === undefined || isSeal) { Object.seal(this); } } private generateSchema() { let schema = this.schema; if (schema === undefined) { return; } try { schema = JSON.parse(JSON.stringify(schema)); } catch (e) { console.log(schema); console.error(e); } this.data = {}; Object.keys(schema).forEach((key) => { // @ts-ignore this.data[key] = schema[key]; Object.defineProperty(this, key, { get() { return this.data[key]; }, }); }); } public set(data: Partial, isSilent?: boolean) { const oldValue: { [key: string]: any } = {}; const keys = Object.keys(data); for (const key in this.data) { if (data[key] !== undefined) { if (data[key] === this.data[key]) { keys.splice(keys.indexOf(key), 1); } else { oldValue[key] = this.data[key]; // @ts-ignore if (data[key] instanceof Array) { this.data[key] = data[key].concat(); } else { this.data[key] = data[key]; } } } } !isSilent && this.notify(keys, oldValue); } public observe(object: any, funcName: string, attrs: any, isNotify?: boolean) { // @ts-ignore const observer = new Entry.Observer(this.observers, object, funcName, attrs); if (isNotify !== false) { object[funcName]([]); } return observer; } public unobserve(observer: any) { observer.destroy(); } public notify(key: string | string[], oldValue: any) { const keys = typeof key === 'string' ? [key] : key; const observers = this.observers; if (!observers.length) { return; } observers.forEach((observeData) => { let attrs = keys; if (observeData.attrs !== undefined) { attrs = intersection(observeData.attrs, keys); } if (!attrs.length) { return; } observeData.object[observeData.funcName]( attrs.forEach((key) => ({ name: key, object: this, oldValue: oldValue[key], })) ); }); } protected _toJSON() { const json: { [key: string]: any } = {}; for (const key in this.data) { json[key] = this.data[key]; } return json; } } ================================================ FILE: src/core/observer.js ================================================ 'use strict'; /* * Entry Observer object Constructor * @param {object} obj */ Entry.Observer = class Observer { constructor(parent, object, funcName, attrs) { this.parent = parent; this.object = object; this.funcName = funcName; this.attrs = attrs; parent.push(this); } destroy = function() { const parent = this.parent; const index = parent.indexOf(this); if (index > -1) { parent.splice(index, 1); } return this; }; }; ================================================ FILE: src/core/promiseManager.js ================================================ module.exports = class PromiseManager { // default timeout value get timeout() { return 30000; } setPromiseTimer(resolve, reject, option) { const { timeout = this.timeout, defaultValue } = option; return setTimeout(() => { if (Entry.engine.state === 'run') { if (defaultValue !== undefined) { resolve(defaultValue); } else { reject('timeout'); } } }, timeout); } /** * 입력한 time 만큼 일시정지한다. * pause 상태인 경우 로직을 수행하지 않고 멈춘다. * 시간은 그대로 흐르기 때문에 timeout 후 재시작하면 다음블록이 바로 실행된다. * * @param time 일시정지할 ms */ sleep(time) { return new Promise((resolve) => { setTimeout(async() => { await waitWhilePause(); resolve(); }, time); }); function waitWhilePause() { return new Promise((resolve) => { if (Entry.engine.state !== 'pause') { resolve(); } const polling = setInterval(() => { if (Entry.engine.state !== 'pause') { window.clearInterval(polling); resolve(); } }, 1000 / Entry.FPS); }); } } /** * sample code * Entry.addEventListener('callApi', ({url}, resolve, reject) => { * $.ajax(url).then((...args) => { * console.log(args); * resolve('asd'); * }).fail(() => { * reject() * }); * }); */ async EventPromise(key, data, option) { return this.Promise((resolve, reject) => { const { defaultValue } = option; const t = this.setPromiseTimer(resolve, reject, option); Entry.dispatchEvent( key, data, (value) => { clearTimeout(t); resolve(value); }, (value) => { clearTimeout(t); if (defaultValue !== undefined) { resolve(defaultValue); } else { reject(value); } } ); }); } Promise(f) { return new Promise((resolve, reject) => { const callback = (data) => { if (Entry.engine.state !== 'run') { reject(new Entry.Utils.AsyncError('Engine 정지')); } else { resolve(data); } }; f(callback, reject); }); } }; ================================================ FILE: src/core/singleInstance.js ================================================ function singleInstance(MyClass) { function getInstance(...props) { if (!MyClass.instance) { MyClass.instance = new MyClass(...props); } return MyClass.instance; } return { getInstance, }; } export default singleInstance; ================================================ FILE: src/core/svg.js ================================================ /** * @fileoverview View element constructor * @author Kyumin Sim * @version 0.2 */ 'use strict'; /** * Function for construct html dom element. * @function * @param {string} tag or html to construct dom element. * @param {?object} options include id, classes, parent etc. */ Entry.SVG = function(id, svgDom) { const element = svgDom ? svgDom : document.getElementById(id); return Entry.SVG.createElement(element); }; Entry.SVG.NS = 'http://www.w3.org/2000/svg'; Entry.SVG.NS_XLINK = 'http://www.w3.org/1999/xlink'; Entry.SVG.createElement = function(tag, options) { let el; if (typeof tag === 'string') { el = document.createElementNS(Entry.SVG.NS, tag); } else { el = tag; } if (options) { if (options.href) { el.setAttributeNS(Entry.SVG.NS_XLINK, 'href', options.href); delete options.href; } for (const key in options) { el.setAttribute(key, options[key]); } } //add util functions el.elem = Entry.SVG.createElement; el.prepend = Entry.SVG.prepend; el.attr = Entry.SVG.attr; el.addClass = Entry.SVG.addClass; el.removeClass = Entry.SVG.removeClass; el.hasClass = Entry.SVG.hasClass; el.remove = Entry.SVG.remove; el.removeAttr = Entry.SVG.removeAttr; if (tag === 'text') { el.setAttributeNS( 'http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve' ); } if (this instanceof SVGElement) { this.appendChild(el); } return el; }; Entry.SVG.prepend = function(tag) { let el; if (typeof tag === 'string') { el = document.createElementNS(Entry.SVG.NS, tag); } else { el = tag; } //add util functions el.elem = Entry.SVG.createElement; el.prepend = Entry.SVG.prepend; el.attr = Entry.SVG.attr; el.addClass = Entry.SVG.addClass; el.removeClass = Entry.SVG.removeClass; el.hasClass = Entry.SVG.hasClass; el.remove = Entry.SVG.remove; el.removeAttr = Entry.SVG.removeAttr; if (this instanceof SVGElement) { if (this.childNodes.length) { this.insertBefore(el, this.childNodes[0]); } else { this.appendChild(el); } } return el; }; Entry.SVG.attr = function(options, property) { if (typeof options === 'string') { const o = {}; o[options] = property; options = o; } if (options) { if (options.href) { this.setAttributeNS(Entry.SVG.NS_XLINK, 'href', options.href); delete options.href; } for (const key in options) { this.setAttribute(key, options[key]); } } return this; }; Entry.SVG.addClass = function(...classes) { const className = classes.reduce((acc, className) => { if (!this.hasClass(className)) { acc += ` ${ className}`; } return acc; }, this.getAttribute('class')); this.setAttribute('class', className.replace(/\s+/g, ' ')); return this; }; Entry.SVG.removeClass = function(...classes) { const className = classes.reduce((acc, className) => { if (this.hasClass(className)) { acc = acc.replace( new RegExp(`(\\s|^)${ className }(\\s|$)`), ' ' ); } return acc; }, this.getAttribute('class')); if (className) { this.setAttribute('class', className.replace(/\s+/g, ' ')); } return this; }; Entry.SVG.hasClass = function(className) { const attr = this.getAttribute('class'); if (!attr) { return false; } else { return attr.match(new RegExp(`(\\s|^)${ className }(\\s|$)`)); } }; Entry.SVG.remove = function() { if (this.parentNode) { this.parentNode.removeChild(this); } }; Entry.SVG.removeAttr = function(attrName) { this.removeAttribute(attrName); }; ================================================ FILE: src/css/codemirror_theme.less ================================================ /* BASICS */ .CodeMirror { /* Set height, width, borders, and global font properties here */ font-family: 'Nanum Gothic Coding' !important; height: 100%; color: black; } .CodeMirror *{ font-family: 'Nanum Gothic Coding' !important; } /* PADDING */ .CodeMirror-sizer { padding-top: 7px; } .CodeMirror-lines { padding: 5px 0; /* Vertical padding around content */ } .CodeMirror pre { padding: 0 5px; /* Horizontal padding of content */ } .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { background-color: white; /* The little square between H and V scrollbars */ } /* GUTTER */ .CodeMirror-gutters { border-right: 1px solid #ddd; background-color: #f7f7f7; white-space: nowrap; } .CodeMirror-linenumbers {} .CodeMirror-linenumber { padding: 0 5px 0 5px; min-width: 20px; text-align: right; color: #A0A0A0; white-space: nowrap; border-right: 1px solid #ddd; } .CodeMirror-guttermarker { color: black; } .CodeMirror-guttermarker-subtle { color: #999; } /* CURSOR */ .CodeMirror-cursor { border-left: 1px solid black; border-right: none; width: 0; } /* Shown when moving in bi-directional text */ .CodeMirror div.CodeMirror-secondarycursor { border-left: 1px solid silver; } .cm-fat-cursor .CodeMirror-cursor { width: auto; border: 0; background: #7e7; } .cm-fat-cursor div.CodeMirror-cursors { z-index: 1; } .cm-animate-fat-cursor { width: auto; border: 0; -webkit-animation: blink 1.06s steps(1) infinite; -moz-animation: blink 1.06s steps(1) infinite; animation: blink 1.06s steps(1) infinite; background-color: #7e7; } @-moz-keyframes blink { 0% {} 50% { background-color: transparent; } 100% {} } @-webkit-keyframes blink { 0% {} 50% { background-color: transparent; } 100% {} } @keyframes blink { 0% {} 50% { background-color: transparent; } 100% {} } /* Can style cursor different in overwrite (non-insert) mode */ .CodeMirror-overwrite .CodeMirror-cursor {} .cm-tab { display: inline-block; text-decoration: inherit; } .CodeMirror-ruler { border-left: 1px solid #ccc; position: absolute; } /* DEFAULT THEME */ .cm-s-default .cm-header {color: blue;} .cm-s-default .cm-quote {color: #090;} .cm-negative {color: #d44;} .cm-positive {color: #292;} .cm-header, .cm-strong {font-weight: bold;} .cm-em {font-style: italic;} .cm-link {text-decoration: underline;} .cm-strikethrough {text-decoration: line-through;} /* .cm-s-default .cm-keyword {color: #2BBFED ;} .cm-s-default .cm-atom {color: #FF9E00;} .cm-s-default .cm-number {color: #E22C0B;} .cm-s-default .cm-def {color: #4F39DB;} .cm-s-default .cm-variable, .cm-s-default .cm-punctuation, .cm-s-default .cm-property, .cm-s-default .cm-operator {color: #E22C0B;} .cm-s-default .cm-variable-2 {color: #0FC764;} .cm-s-default .cm-variable-3 {color: #085;} .cm-s-default .cm-comment {color: #a50;} .cm-s-default .cm-string {color: #4F39DB;} .cm-s-default .cm-string-2 {color: #f50;} .cm-s-default .cm-meta {color: #555;} .cm-s-default .cm-qualifier {color: #555;} .cm-s-default .cm-builtin {color: #30a;} .cm-s-default .cm-bracket {color: #997;} .cm-s-default .cm-tag {color: #170;} .cm-s-default .cm-attribute {color: #00c;} .cm-s-default .cm-hr {color: #999;} .cm-s-default .cm-link {color: #00c;} .cm-s-default .cm-error {color: #f00;} .cm-invalidchar {color: #f00;} */ /*Entry Textcoding Font*/ .cm-s-default .cm-keyword {color: #2BBFED ;} /* applied */ .cm-s-default .cm-atom {color: #FF9E00;} .cm-s-default .cm-number {color: #0FC764;} /* applied */ .cm-s-default .cm-def {color: #4F39DB;} /* applied */ .cm-s-default .cm-variable {color:#E22C0B;} /* applied */ .cm-s-default .cm-punctuation, .cm-s-default .cm-property {color:#E22C0B;} /* applied */ .cm-s-default .cm-operator {color: #000000;} /* applied */ .cm-s-default .cm-variable-2 {color: #E22C0B;} /* applied */ .cm-s-default .cm-variable-3 {color: #085;} .cm-s-default .cm-comment {color: #FF9E00;} /* applied */ .cm-s-default .cm-string {color: #2A7DEF;} /* applied */ .cm-s-default .cm-string-2 {color: #f50;} .cm-s-default .cm-meta {color: #555;} .cm-s-default .cm-qualifier {color: #555;} .cm-s-default .cm-builtin {color: #C93AD8;} /* applied */ .cm-s-default .cm-bracket {color: #997;} .cm-s-default .cm-tag {color: #170;} .cm-s-default .cm-attribute {color: #00c;} .cm-s-default .cm-hr {color: #999;} .cm-s-default .cm-link {color: #00c;} .cm-s-default .cm-error {color: #E22C0B;} .cm-invalidchar {color: #f00;} .CodeMirror-composing { border-bottom: 2px solid; } /* Default styles for common addons */ div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } .CodeMirror-activeline-background {background: #E7F1FD;} /* STOP */ /* The rest of this file contains styles related to the mechanics of the editor. You probably shouldn't touch them. */ .CodeMirror { position: relative; overflow: hidden; background: white; } .CodeMirror-scroll { overflow: scroll !important; /* Things will break if this is overridden */ /* 30px is the magic margin used to hide the element's real scrollbars */ /* See overflow: hidden in .CodeMirror */ margin-bottom: -30px; margin-right: -30px; padding-bottom: 30px; height: 100%; outline: none; /* Prevent dragging from highlighting the element */ position: relative; } .CodeMirror-sizer { position: relative; border-right: 30px solid transparent; } /* The fake, visible scrollbars. Used to force redraw during scrolling before actuall scrolling happens, thus preventing shaking and flickering artifacts. */ .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { position: absolute; z-index: 6; display: none; } .CodeMirror-vscrollbar { right: 0; top: 0; overflow-x: hidden; overflow-y: scroll; } .CodeMirror-hscrollbar { bottom: 0; left: 0; overflow-y: hidden; overflow-x: scroll; } .CodeMirror-scrollbar-filler { right: 0; bottom: 0; } .CodeMirror-gutter-filler { left: 0; bottom: 0; } .CodeMirror-gutters { position: absolute; left: 0; top: 0; z-index: 3; height: 100% !important; } .CodeMirror-gutter { white-space: normal; height: 100%; display: inline-block; margin-bottom: -30px; margin-right: -1px; /* Hack to make IE7 behave */ *zoom:1; *display:inline; } .CodeMirror-gutter-wrapper { position: absolute; z-index: 4; background: none !important; border: none !important; } .CodeMirror-gutter-background { position: absolute; top: 0; bottom: 0; z-index: 4; } .CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; background-color: #f7f7f7; padding-right: 6px; } .CodeMirror-gutter-wrapper { -webkit-user-select: none; -moz-user-select: none; user-select: none; } .CodeMirror-lines { cursor: text; min-height: 1px; /* prevents collapsing before first draw */ } .CodeMirror pre { /* Reset some styles that the rest of the page might have set */ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; border-width: 0; background: transparent; font-family: inherit; font-size: inherit; margin: 0; white-space: pre; word-wrap: normal; line-height: inherit; color: inherit; z-index: 2; position: relative; overflow: visible; -webkit-tap-highlight-color: transparent; } .CodeMirror-wrap pre { word-wrap: break-word; white-space: pre-wrap; word-break: normal; } .CodeMirror-linebackground { position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: 0; } .CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; } .CodeMirror-widget {} .CodeMirror-code { outline: none; } /* Force content-box sizing for the elements where we expect it */ .CodeMirror-scroll, .CodeMirror-sizer, .CodeMirror-gutter, .CodeMirror-gutters, .CodeMirror-linenumber { -moz-box-sizing: content-box; box-sizing: content-box; } .CodeMirror-measure { position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden; } .CodeMirror-cursor { position: absolute; } .CodeMirror-measure pre { position: static; } div.CodeMirror-cursors { visibility: hidden; position: relative; z-index: 3; } div.CodeMirror-dragcursors { visibility: visible; } .CodeMirror-focused div.CodeMirror-cursors { visibility: visible; } .CodeMirror-selected { background: #d9d9d9; } .CodeMirror-focused .CodeMirror-selected { background: #E4F9ED; } .CodeMirror-crosshair { cursor: crosshair; } .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } .cm-searching { background: #ffa; background: rgba(255, 255, 0, .4); } /* IE7 hack to prevent it from returning funny offsetTops on the spans */ .CodeMirror span { *vertical-align: text-bottom; } /* Used to force a border model for a node */ .cm-force-border { padding-right: .1px; } @media print { /* Hide the cursor when printing */ .CodeMirror div.CodeMirror-cursors { visibility: hidden; } } /* See issue #2901 */ .cm-tab-wrap-hack:after { content: ''; } /* Help users use markselection to safely style text background */ span.CodeMirror-selectedtext { background: none; } ================================================ FILE: src/css/common.less ================================================ @url: '../../img/'; @image_url: '../../images/'; @image_url2: '../images/'; html, body { touch-action: none; // position: fixed; overflow: hidden; } * { box-sizing: border-box; } img, fieldset, button { border: 0; } .blind { overflow: hidden; position: absolute; top: 0; left: 0; margin: -1px; padding: 0; width: 1px; height: 1px; border: 0; clip: rect(0, 0, 0, 0); } #__next { position: absolute; height: 100%; width: 100%; } html, body, .wrapper, .entry { height: 100%; margin: 0; padding: 0; } .wrapper, .entry { position: relative; min-width: 1024px; } .engineContainer { position: relative; display: flex; flex-direction: column; float: left; width: 294px; height: 100%; padding: 46px 16px 8px 8px; } .backgroundImage(@imageName) { background-image: url('@{image_url2}@{imageName}'); } .dragNone { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .entryHidden { visibility: hidden; } .entryRemove { display: none !important; } .entryHide { visibility: hidden; } .entryRemoveCategory { display: none !important; } .entryRemoveElement { display: none !important; } .entryNoDeco { text-decoration: none !important; } .entryBtn { border: none; margin: 0; background-color: transparent; } .entryDimmed { opacity: 0.5; background-color: #767676; } .table-modal { position: fixed; left: 0; top: 0; bottom: 0; right: 0; z-index: 1000; } #entryInputForComputeWidth { visibility: hidden; position: fixed; left: -9999px; top: -9999px; } input[type='number']::-webkit-inner-spin-button, input[type='number']::-webkit-outer-spin-button { -webkit-appearance: none; } input[type='number'] { -moz-appearance: textfield; } ================================================ FILE: src/css/components/block.less ================================================ .block.selected > g > .blockPath, .block.selected > g > .blockBackgroundPath { // stroke-width: 3px; // stroke: #798EB1; -webkit-filter: none; filter: none; &:not([fill^='url(#blockHoverPattern']) { -webkit-filter: url(#entryBlockSelectFilter_board); filter: url(#entryBlockSelectFilter_board); } } .block.outputHighlight > g > .blockPath { stroke-width: 2px; stroke: white; } .block.basicButtonView { cursor: pointer; } .block.basicButtonView > g > path { fill: #ffffff; stroke: #4f80ff; stroke-width: 1; } .block.basicButtonDisabledView { cursor: auto; } .block.basicButtonDisabledView > g > path { fill: #f9f9f9; stroke: #e2e2e2; stroke-width: 1; } .block.clickableText { cursor: pointer; } .block.basicText { cursor: default; } .block.basicText:hover > g > path { fill: none; } .block.basicTextLight { cursor: default; } .block.basicTextLight > g > text > tspan { font-weight: lighter; } .block { cursor: url('/media/handopen.cur'), auto; -ms-touch-action: none; } .block.dragging { cursor: url('/media/handclosed.cur'), auto; } .block.selected > path { stroke-width: 3px; stroke: #798eb1; } .block.activated > g > path { stroke-width: 3px; stroke: red; } @keyframes activationDash { to { stroke-dashoffset: 0; } } @-webkit-keyframes activationDash { to { stroke-dashoffset: 0; } } .block g text, .block g image { pointer-events: none; } svg .svgBlockGroup text { white-space: pre; } .entry-field-color { cursor: pointer; } .entry-input-field { cursor: text; } .entry-input-field:hover rect { stroke-width: 1.5px; stroke: white; } .entry-widget-input-field { position: fixed; font-family: EntryFont, NanumGothic, 'Nanum Gothic'; font-weight: bold; border: none; border-radius: 5px; outline: none; line-height: normal; z-index: 254; color: #000000; } .entry-widget-input-field::-ms-clear, .entry-widget-input-field::-ms-reveal { display: none; } .entry-widget-textarea { position: absolute; background-color: #ffda85; resize: none; line-height: 1.6em; outline: none; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; overflow: hidden; } .invisible { visibility: hidden; } .entryWorkspaceBoard.invisibleComment { .svgCommentGroup{ visibility: hidden; } } .entry-field-angle { cursor: default; } .entry-field-angle-circle { stroke: #dbdbdb; stroke-width: 1; fill: #fbfbfb; fill-opacity: 0.8; } .entry-angle-divider { stroke: #bababa; stroke-width: 1; } .entry-angle-indicator { stroke: #333333; stroke-width: 1; stroke-linecap: round; } .entry-angle-fill-area { fill: #5096f5; fill-opacity: 0.3; } .entryWorkspaceFilters { position: absolute; left: -100px; top: -100px; } .entry-widget-keyboard-input { position: fixed; } .entry-comment-resize-arrow { cursor: nwse-resize; } .entry-comment-toggle-arrow { cursor: pointer; } .blockHoverPattern { .pattern1 { opacity: 0; .animation-duration(0.7s); .animation-direction(alternate); .animation-name(blockPatternAnimation); .animation-iteration-count(infinite); } .pattern2 { opacity: 0; .animation-delay(0.33s); .animation-duration(0.7s); .animation-direction(alternate); .animation-name(blockPatternAnimation); .animation-iteration-count(infinite); } .pattern3 { opacity: 0; .animation-delay(0.67s); .animation-duration(0.7s); .animation-direction(alternate); .animation-name(blockPatternAnimation); .animation-iteration-count(infinite); } .pattern4 { opacity: 0; .animation-delay(1s); .animation-duration(0.7s); .animation-direction(alternate); .animation-name(blockPatternAnimation); .animation-iteration-count(infinite); } } //hover block background pattern animation @keyframes blockPatternAnimation { from { opacity: 0; } to { opacity: 0.2; } } @-webkit-keyframes blockPatternAnimation { from { opacity: 0; } to { opacity: 0.2; } } g.entry-field-dropdown { cursor: default; } .guideGroup { opacity: 0.3; } ================================================ FILE: src/css/components/block_menu.less ================================================ .entryWorkspaceBlockMenu { background-color: #fff; position: absolute; top: 0; bottom: 0; z-index: 2; } .entryWorkspaceBlockMenu.entryRemove.init { opacity: 0 !important; display: block !important; z-index: -9999; } .entryCategoryListWorkspace { .scrollIndicator { position: absolute; width: 58px; height: 16px; opacity: 0.8; .backgroundImage("block_menu/scroll_indicator_arrow.svg"); background-repeat: no-repeat; background-position: center; background-color: #aac5d5; z-index: 6; display: none; cursor: pointer; &.prepend { top: 0; } &.append { bottom: 0; -webkit-transform: rotate(180deg); transform: rotate(180deg); } .active { display: block; } } position: relative; min-width: 58px; overflow: hidden; height: 100%; display: inline-block; background-color: #ecf8ff; list-style-type: none; border-radius: 0 0 0 6px; margin: 0; padding: 0; -ms-overflow-style: none; // IE 10+ overflow: -moz-scrollbars-none; // Firefox .entryCategoryList { height: 100%; overflow: hidden; overflow-y: scroll; font-weight: bold; &::-webkit-scrollbar { display: none; // Safari and Chrome } .visiblePoint { margin: 0; } #entryCategoryarduino { margin-bottom: 1px; } } } .entryCategoryListWorkspace:before { position: absolute; left: 0; right: 0; top: 0; bottom: 0; border: 1px solid #d6e9f4; border-radius: 0 0 0 6px; content: ''; } .entryCategoryListWorkspace li { position: relative; background-color: #ecf8ff; z-index: 5; } .entryCategoryListWorkspace li:first-child { margin-top: 0; } .entrySelectedCategory { position: relative; z-index: 5; } .blockMenuContainer { display: inline-block; vertical-align: top; width: 254px; height: 100%; background-color: #ecf8ff; border:1px solid #d6e9f4; border-left: none; .blockMenuWrapper { overflow: hidden; width: 100%; height: 100%; -webkit-transition: width ease 0.2s; transition: width ease 0.2s; } .blockMenuTrashcan { position: absolute; width: 100%; top: 0; left: 0; opacity: 0.95; background: #f7f2d1; border: 2px dashed #ffc803; &:before { display: block; content: ' '; width: 62px; height: 94px; margin-top: 74px; margin-left: calc(50% - 32px); .backgroundImage("trashcan.svg"); } &.open:before { display: block; content: ' '; width: 64px; height: 102px; margin-top: 66px; margin-left: calc(50% - 31px); .backgroundImage("trashcan_open.svg"); } span { position: absolute; top: 180px; width: 100%; font-family: NanumGothicBold, NanumGothic, 'Nanum Gothic'; font-size: 14px; color: #555; text-align: center; } } .block.selected > g > .blockPath, .block.selected > g > .blockBackgroundPath { // stroke-width: 3px; // stroke: #798EB1; -webkit-filter: none; filter: none; &:not([fill^='url(#blockHoverPattern']) { -webkit-filter: url(#entryBlockSelectFilter_blockMenu); filter: url(#entryBlockSelectFilter_blockMenu); } } } .blockMenu { height: 100%; min-width: 700px; } .entryCategoryListPhone { padding: 0; margin: 0; list-style-type: none; } .entryCategoryElementWorkspace { padding: 34px 0 4px; min-width: 58px; text-align: center; background-color: #ecf8ff; font-size: 12px; color: #595959; border: 1px solid #d6e9f4; border-bottom: transparent; cursor: pointer; font-family: EntryFont, NanumGothic, 'Nanum Gothic' !important; line-height: 14px; background-size: 32px auto; background-position: 50% 4px; position:relative; } .entryCategoryBetaTag{ .backgroundImage("beta_tag.svg"); position:absolute; bottom:18px; right:3px; width:26px; height:14px; } .entryCategoryElementPhone { height: 50px; clear: both; width: 56px; padding-top: 30px; text-align: center; background-color: #E2E9F0; font-size: 13px; color: #474747; float: left; border-bottom: 1px solid #B7C4CC; background-position: 5px 2px; cursor: pointer; } .entryCategoryElementEndWorkspace { clear: both; width: 3px; margin-left: 56px; background-color: #515B7C; height: 4000px; } .entryCategoryWorkspace { width: 74px; height: 100%; display: block; } .entryBlockMenuWorkspace { background-color: #e5e5e5; position: absolute; left: 64px; top: 45px; width: 186px; bottom: 0px; z-index: 100; } #entryCategorystart { background-repeat: no-repeat; } .entryUnSelectedCategory#entryCategorystart { .backgroundImage("start.svg"); } .entrySelectedCategory#entryCategorystart { .backgroundImage("start_on.svg"); background-color: #00b400; border-color: #00b400; color: #fff; } #entryCategoryflow { .backgroundImage("flow.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryflow { .backgroundImage("flow_on.svg"); background-color: #17a6d1; border-color: #17a6d1; color: #fff; } #entryCategorymoving { .backgroundImage("moving.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategorymoving { .backgroundImage("moving_on.svg"); background-color: #ad3efb; border-color: #ad3efb; color: #fff; } #entryCategorylooks { /*border-right: 4px solid #EC4466;*/ .backgroundImage("looks.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategorylooks { .backgroundImage("looks_on.svg"); background-color: #ff3a61; border-color: #ff3a61; color: #fff; } #entryCategorybrush { .backgroundImage("brush.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategorybrush { .backgroundImage("brush_on.svg"); background-color: #fc7e01; border-color: #fc7e01; color: #fff; } #entryCategorytext { .backgroundImage("text.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategorytext { .backgroundImage("text_on.svg"); background-color: #e43500; border-color: #e43500; color: #fff; } #entryCategorysound { .backgroundImage("sound.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategorysound { .backgroundImage("sound_on.svg"); background-color: #67b100; border-color: #67b100; color: #fff; } #entryCategoryjudgement { .backgroundImage("judgement.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryjudgement { .backgroundImage("judgement_on.svg"); background-color: #4562f5; border-color: #4562f5; color: #fff; } #entryCategorycalc { .backgroundImage("calc.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategorycalc { .backgroundImage("calc_on.svg"); background-color: #f4af18; border-color: #f4af18; color: #fff; } #entryCategoryvariable { .backgroundImage("variable.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryvariable { .backgroundImage("variable_on.svg"); background-color: #dd47d8; border-color: #dd47d8; color: #fff; } #entryCategoryfunc { .backgroundImage("func.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryfunc { .backgroundImage("func_on.svg"); background-color: #de5c04; border-color: #de5c04; color: #fff; } #entryCategoryanalysis { .backgroundImage("analysis.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryanalysis { .backgroundImage("analysis_on.svg"); background-color: #17a6d1; border-color: #17a6d1; color: #fff; } #entryCategoryai { .backgroundImage("ai.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryai { .backgroundImage("ai_on.svg"); background-color: #8222ff; border-color: #8222ff; color: #fff; } #entryCategoryexpansion { .backgroundImage("expansion.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryexpansion { .backgroundImage("expansion_on.svg"); background-color: #ef6d6d; border-color: #ef6d6d; color: #fff; } #entryCategoryai_utilize { .backgroundImage("ai_utilize.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryai_utilize { .backgroundImage("ai_utilize_on.svg"); background-color: #8222ff; border-color: #670bdd; color: #fff; } #entryCategoryscene { .backgroundImage("scene.png"); background-repeat: no-repeat; border-right: none; } .entrySelectedCategory#entryCategoryscene { border-left: none; border-right: none; } #entryCategoryarduino { .backgroundImage("hardware.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryarduino { .backgroundImage("hardware_on.svg"); background-color: #00b6b1; border-color: #00b6b1; color: #fff; } #entryCategoryhw_sensor { .backgroundImage("sensor.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryhw_sensor { .backgroundImage("sensor_on.svg"); background-color: #00cfca; border-color: #00cfca; color: #fff; } #entryCategoryhw_led { .backgroundImage("diode.svg"); background-repeat: no-repeat; font-size: 10px; } .entrySelectedCategory#entryCategoryhw_led { .backgroundImage("diode_on.svg"); background-color: #00cfca; border-color: #00cfca; color: #fff; } #entryCategoryhw_motor { .backgroundImage("dcmotor.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryhw_motor { .backgroundImage("dcmotor_on.svg"); background-color: #00cfca; border-color: #00cfca; color: #fff; } #entryCategoryhw_melody { .backgroundImage("melody.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryhw_melody { .backgroundImage("melody_on.svg"); background-color: #00cfca; border-color: #00cfca; color: #fff; } #entryCategoryhw_robot { .backgroundImage("robot.svg"); background-repeat: no-repeat; } .entrySelectedCategory#entryCategoryhw_robot { .backgroundImage("robot_on.svg"); background-color: #00cfca; border-color: #00cfca; color: #fff; } .entryBlocklyWorkspace { position: absolute; left: 250px; top: 8px; bottom: 0px; right: 0px; overflow: hidden; border: solid 1px #C4C4B9; border-top-left-radius: 10px; .backgroundImage("entry_bg.svg"); } .entryBlocklyWorkspace.folding { z-index: 300; border-left: solid 1px #C4C4B9; .animation-duration(0.7s); .animation-name(foldBlockly); .animation-fill-mode(forwards); } @keyframes foldBlockly { from {} to {left: 64px;} } @-webkit-keyframes foldBlockly { from {} to {left: 64px;} } .entryBlocklyWorkspace.foldOut { z-index:300; .animation-duration(0.7s); .animation-name(foldOutBlockly); .animation-fill-mode(forwards); } @keyframes foldOutBlockly { from {left: 64px;} to {} } @-webkit-keyframes foldOutBlockly { from {left: 64px;} to {} } .entryBlocklyPhone { position: absolute; top: 0px; left: 56px; right: 0px; bottom: 0px; overflow: hidden; border: solid 1px #C4C4B9; border-left: 0; .backgroundImage("entry_bg_1.png"); } ================================================ FILE: src/css/components/board.less ================================================ .entryBoard { cursor: move; position: absolute; -ms-touch-action: none; } .entryOverlayBoard { background: rgba(138, 163, 178, 0.7); } .boardScrollbar { opacity: 1; cursor: move; -ms-touch-action: none; .scrollbar { transition: opacity 0.5s; cursor: pointer; } } .boardScrollbar:hover { opacity: 0.6; } .entryBoardWrapper { position: absolute; top: 0; left: 0; right: 0; height: 100%; } .entryVimBoard { z-index: 0; position: absolute; top: 0; left: 0; height: 100%; width: 100%; } .entryFunctionButton { font-family: ng !important; font-size: 13 !important; text-anchor: middle; fill: #ffffff; cursor: pointer !important; } .entryFunctionButtonText { font-family: ng !important; font-size: 13 !important; text-anchor: middle; fill: #4f80ff; cursor: pointer !important; } .entryFunctionButtonBorder { font-family: ng !important; font-size: 13 !important; text-anchor: middle; fill: #ffffff; cursor: pointer !important; stroke: #4f80ff; stroke-width: 1; } .entryWorkspaceBoard { position: absolute; left: 313px; top: 0; bottom: 0; right: 0px; border: 1px solid #d6e9f4; border-width: 1px 0; overflow: hidden; .backgroundImage('entry_bg.svg'); &.wideView { left: 254px; } } .entryWorkspaceBoard.folding { z-index: 251; // border-left: solid 1px #c4c4b9; .animation-duration(0.7s); .animation-name(foldBoard); .animation-fill-mode(forwards); } @keyframes foldBoard { from { } to { left: 59px; } } @-ms-keyframes foldBoard { from { } to { left: 61px; } } @-moz-keyframes foldBoard { from { } to { left: 61px; } } @-webkit-keyframes foldBoard { from { } to { left: 61px; } } .entryWorkspaceBoard.foldOut { z-index: 300; .animation-duration(0.7s); .animation-name(foldOutBoard); .animation-fill-mode(forwards); } @keyframes foldOutBoard { from { left: 64px; } to { } } @-o-keyframes foldOutBoard { from { left: 61px; } to { } } @-ms-keyframes foldOutBoard { from { left: 61px; } to { } } @-moz-keyframes foldOutBoard { from { left: 61px; } to { } } @-webkit-keyframes foldOutBoard { from { left: 61px; } to { } } #invisibleBoard { visibility: hidden; position: fixed; left: -1000px; top: -1000px; } ================================================ FILE: src/css/components/console.less ================================================ #entryConsole { height: 100%; } #entryConsole > .CodeMirror { height: 100%; background: #424b50; } #entryConsole .CodeMirror-cursor { border-left: 1px solid white; } #entryConsole span { color: white; } #entryConsole .speak span { color: #fff2a4; } #entryConsole .ask span { color: #bdd1ff; } ================================================ FILE: src/css/components/container.less ================================================ .sortable { .sortableItem { transform: translate3d(0, 0, 0); } } .entryContainerWorkspace { height: 100%; background-color: #fff; .simplebar-scrollbar { right: 4px; width: 8px; &::before { opacity: 1 !important; background-color: #aac5d5; border-radius: 2.5px; } } } .entryContainerPhone { width: 100%; background-color: #fff; } .entryAddObjectWorkspace { display: block; height: 48px; background-color: #e7e7e7; color: #757575; text-align: center; font-size: 11pt; line-height: 44px; margin: 10px; border: 2px dashed #979797; cursor: pointer; } .entryContainerListWorkspaceWrapper { position: absolute; bottom: 0; padding: 0; margin: 0; // overflow: auto; width: 100%; top: 0; background-color: #fff; } .entryContainerExtensions { position: relative; margin: 0px; padding: 0px; width: 100%; background-color: #363c46; list-style-type: none; } .entryContainerListWorkspace { position: relative; margin: 0px; padding: 0px; width: 100%; height: 100%; list-style-type: none; .Draggable { height: 100%; } } .entryContainerListPhone { position: relative; margin: 0px; padding: 0px; width: 100%; background-color: #363c46; list-style-type: none; border-top: 1pt solid #ebeff1; } .entryContainerListWorkspace::-webkit-scrollbar { display: none; } .entryContainerListElementWorkspace { background-color: #f7fcff; display: block; padding: 0; margin: 0; position: relative; overflow: hidden; min-height: 60px; .box-sizing(border-box); border: 1px solid #d6e9f4; border-width: 1px 0; } .entryContainerListElementWorkspace.fold { background-color: #f7fcff; } .entryContainerListElementWorkspace.selectedObject { background-color: #d6e9f4; } .collapsed .selectedObject { height: 149px; } .entryContainerListElementWorkspace:first-child, .entryContainerListElementWorkspace.selectedObject + .entryContainerListElementWorkspace { border-top: 0; } .propertyTabhelper { .backgroundImage('property/helper_off.png'); } .propertyTabhelper.selected { .backgroundImage('property/helper_on.png'); .practical_course_mode & { .backgroundImage('property/helper_on_practical_course.png'); } } .propertyTabhint { .backgroundImage('property/hint_off_property.png'); } .propertyTabhint.selected { .backgroundImage('property/hint_on.png'); } .propertyTabContainer { .backgroundImage('property/container_off.png'); } .propertyTabContainer.selected { .backgroundImage('property/container_on.png'); } .entryContainerTabViewWorkspace { width: 100%; height: 45px; border-bottom: 2px solid #1bafea; } .entryContainerTabItemWorkspace { vertical-align: top; height: 100%; width: 25%; text-align: center; display: inline-block; background-color: rgb(229, 229, 229); color: rgb(158, 159, 159); font-size: 13px; cursor: pointer; padding-top: 13px; } .entryContainerTabItemWorkspace:nth-child(2) { border-left: 2px solid white; border-right: 2px solid white; } .entryContainerTabItemWorkspace:nth-child(3) { border-right: 2px solid white; } .entryContainerTabItemWorkspace.selected { background-color: #1bafea; color: white; } .entryContainerMovieWorkspace { /* position: absolute; width: 100%; top: 45px; bottom: 0px; z-index: 1000; */ position: absolute; background-color: #363c46; top: 0px; width: 100%; overflow: scroll; } .entryContainerMovieWorkspace::-webkit-scrollbar { display: none; } .entryContainerDoneWorkspace { position: absolute; width: 100%; top: 0px; background-color: #363c46; overflow: hidden; text-align: center; } .entryContainerHelperWorkspace { position: absolute; width: 100%; top: 45px; bottom: 0; background-color: #fff; z-index: 1000; background: gray; } .tablet { .entryContainerListElementWorkspace.selectedObject { height: 128px; } .collapsed .selectedObject { height: 159px; } } ================================================ FILE: src/css/components/context_menu.less ================================================ #entry-contextmenu { position: fixed; display: inline-block; list-style: none; padding: 4px 0; outline: none; font-size: 13px; z-index: 25000; span { width: 100%; height: 100%; display: inline-block; } .menuAble { cursor: pointer; padding: 3px 20px; } .menuAble:hover { color: white; background-color: #57e; } .menuDisable { color: #ccc; padding: 3px 20px; } .divider { padding: 0; height: 1px; background-color: #ccc; } } #entry-contextmenu.workspace-contextmenu { font-size: 14px; min-width: 160px; .menuAble { padding: 3px 20px; } .menuAble:hover { color: white; background-color: #57e; } .menuDisable { color: #ccc; padding: 3px 20px; } } ================================================ FILE: src/css/components/curtain.less ================================================ .entryCurtainElem { position: fixed; background-color: #3b3b3b; opacity: 0.7; z-index: 5001; &.top { width: 100%; top: 0; left: 0; right: 0; } &.right { right: 0; bottom: 0; } &.bottom { left: 0; bottom: 0; } &.left { left: 0; } .transition(opacity 0.4s ease-in-out); } .hideTooltip>.entryCurtainElem { opacity: 0; } .entryCurtainCloseBtn { width: 22px; height: 22px; position: fixed; z-index: 10001; right: 22px; top: 22px; .backgroundImage("curtain_close.png"); background-repeat: no-repeat; background-color: transparent; border: none; } ================================================ FILE: src/css/components/engine.less ================================================ .entryEngineWorkspace { height: 35px; width: 480px; background-color: white; border-top: 1pt solid #ebeff1; } .entryEngineWorkspace_w { position: relative; overflow: hidden; width: 270px; background-color: white; border: 1px solid #d6e9f4; border-radius: 6px; } .entryEngineWorkspace_w:after { display: block; clear: both; content: ''; } .entryPopupWindow > .entryEngineWorkspace { position: absolute; top: auto !important; width: 100% !important; bottom: 0px; } .entryPopupWindow > .entryEngineWorkspace_w { position: absolute; width: 100% !important; top: 0px !important; } .entryPopupWindow > .entryEngineWorkspace_w > .entryRunButtonWorkspace_w { display: none; top: 37%; left: 46%; } .entryPopupWindow > .entryEngineWorkspace_w > .entryRunButtonWorkspace_w2 { display: block; width: 111px; height: 111px; background-image: url('@{image_url}play_btn.png'); background-position: 40px center; background-color: rgba(0, 0, 0, 0.5); border-radius: 55px; background-repeat: no-repeat; right: 5px; /*bottom: 5px;*/ bottom: -10px; left: 44%; top: 35%; } .entryPopupWindow > .entryEngineWorkspace_w > .entryStopButtonWorkspace_w2 { display: block; background-image: url('@{image_url}stop_btn.png'); background-repeat: no-repeat; left: 20px; color: transparent; bottom: -10px; width: 90px; background-position: left; color: @bora; } .entryPopupWindow > .entryEngineWorkspace_w > .entryStopButtonWorkspace_w { display: none; } .entryPopupWindow > .entryEngineWorkspace_w > .entryCoordinateButtonWorkspace_w { position: absolute; right: 53px; bottom: 12px; margin: 0; background-image: url('@{image_url}grid.png') !important; background-size: 16px auto; } .entryPopupWindow > .entryEngineWorkspace_w > .entryCoordinateButtonWorkspace_w.toggleOn { position: absolute; right: 53px; bottom: 12px; margin: 0; background-image: url('@{image_url}layers_icon_grid_nor_1.png') !important; background-size: 16px auto; } .entryPopupWindow > .entryEngineWorkspace_w > .entryMaximizeButtonWorkspace_w { position: absolute; right: 6px; bottom: 12px; background-image: url('@{image_url}zoom_out_btn.png'); background-repeat: no-repeat; background-size: 16px auto; } .entryPopupWindow > .entryEngineWorkspace_w > .entryEngineButtonWrapper { display: block; height: 48px; border-top: 1px solid #d6e9f4; box-sizing: border-box; margin-top: 0; } .entryPopupWindow > .entryEngineWorkspace_w > .entryEngineButtonWrapper .entryRunButtonWorkspace_w, .entryPopupWindow > .entryEngineWorkspace_w > .entryEngineButtonWrapper .entryStopButtonWorkspace_w, .entryPopupWindow > .entryEngineWorkspace_w > .entryEngineButtonWrapper .entryPauseButtonWorkspace_full, .entryPopupWindow > .entryEngineWorkspace_w > .entryEngineButtonWrapper .entryRestartButtonWorkspace_full { display: inline-block; overflow: hidden; flex: none; width: auto; height: auto; border: 0; margin-left: 24px; border-radius: 0; background: none; font-size: 14px; font-weight: 600; color: #4f80ff; line-height: 48px; } .entryPopupWindow > .entryEngineWorkspace_w > .entryEngineButtonWrapper .entryRunButtonWorkspace_w:before, .entryPopupWindow > .entryEngineWorkspace_w > .entryEngineButtonWrapper .entryRestartButtonWorkspace_full:before { display: inline-block; width: 14px; height: 18px; margin: 0 8px 0 0; vertical-align: middle; background-image: url('@{image_url}layers_icon_button_play_norx2.png'); background-repeat: no-repeat; background-size: 14px auto; content: ''; } .entryPopupWindow > .entryEngineWorkspace_w > .entryEngineButtonWrapper .entryStopButtonWorkspace_w:before { display: inline-block; width: 16px; height: 16px; margin: 0 8px 0 0; vertical-align: middle; background-image: url('@{image_url}layers_icon_button_stop_norx2.png'); background-repeat: no-repeat; background-size: 16px auto; content: ''; } .entryPopupWindow > .entryEngineWorkspace_w > .entryEngineButtonWrapper .entryPauseButtonWorkspace_full:before { display: inline-block; width: 16px; height: 16px; margin-right: 8px; vertical-align: middle; background-image: url('@{image_url}layers_icon_button_pause_norx2.png'); background-repeat: no-repeat; background-size: 16px auto; content: ''; } .entryPopupWindow > .entryEngineWorkspace_w > .entryEngineButtonWrapper > .entryAddButtonWorkspace_w { display: none; } .entryEngineBlueWorkspace { background-color: #61abdb; } .entryEngineButtonWorkspace { border: none; outline: none; width: 25px; height: 35px; background-color: transparent; background-repeat: no-repeat; background-position: center; } .entryEngineButtonWorkspace_w { border: none; outline: none; width: 25px; height: 24px; background-color: transparent; background-repeat: no-repeat; background-position: center; } .entryRunButtonPhone { width: 100%; height: 100%; border: none; background-color: transparent; font-size: 12pt; border-bottom: 2px solid #89c0d5; .backgroundImage('layers_icon_button_play_nor.png'); background-position: 10px 50%; background-repeat: no-repeat; } .entryStopButtonPhone { width: 100%; height: 100%; border: none; background-color: transparent; font-size: 12pt; border-bottom: 2px solid #89c0d5; .backgroundImage('layers_icon_button_stop_nor.png'); background-position: 10px 50%; background-repeat: no-repeat; } .entryRunButtonPhone.small { } .entryEnginePhone { width: 100%; } .entryEngineHeaderPhone { border-bottom: 1px solid #ccc; width: 100%; background-color: #fff; height: 34px; } .entryEngineFooterPhone { border-top: 1px solid #ccc; width: 100%; background-color: #fff; height: 38px; } .entryMouseViewWorkspace { position: relative; font-size: 9pt; margin: 0 auto; width: 40%; color: #61abdb; line-height: 35px; text-align: center; } .entryMouseViewWorkspace_w { height: 32px; font-size: 12px; font-weight: bold; margin: 0 auto; padding: 10px 0 8px; color: #4f80ff; text-align: center; letter-spacing: -0.4px; line-height: 14px; > input { font-size: 10px; line-height: 11px; border: none; font-weight: bold; color: #555; text-align: center; letter-spacing: -0.4px; user-select: none; } } .entryEngineBlueWorkspace > .entryMouseViewWorkspace { color: white; } .entryMaximizeButtonWorkspace { float: left; margin-left: 5px; .backgroundImage('fullscreen_edit.png'); } .entryMaximizeButtonPhone { width: 20px; height: 100%; border: none; float: right; margin-right: 9px; background-repeat: no-repeat; background-position: center; background-color: transparent; .backgroundImage('layers_icon_fullmode01_nor.png'); } .entryMaximizeButtonWorkspace_w { float: right; margin: 4px 6px 0 5px; .backgroundImage('layers_icon_fullmode01_nor_1.png'); background-repeat: no-repeat; background-size: 16px auto; } .entryEngineBlueWorkspace > .entryMaximizeButtonWorkspace { .backgroundImage('fullscreen_play.png'); } #entrySpeedPanelWorkspace { width: 100%; height: 0px; background-color: #0e0; } .entrySpeedButtonWorkspace { float: left; background-size: contain; width: 18px; height: 16px; margin-top: 8px; margin-left: 10px; .backgroundImage('speed_edit.png'); background-size: 18px auto; } .entrySpeedButtonWorkspace.on { .backgroundImage('speed_edit_on.png'); } .entryPopupWindow > div > .entrySpeedButtonWorkspace { display: none; } .entryPopupWindow .entryMouseViewWorkspace_w { position: absolute; bottom: 0; left: 50%; width: 40%; height: 48px; margin: 0 auto; padding: 0; margin-left: -20%; font-size: 14px; font-weight: 600; color: #4f80ff; text-align: center; line-height: 48px; } #entrySpeedProgressWorkspace { overflow: hidden; width: 100%; height: 30px; margin-top: 4px; border-radius: 4px; table-layout: fixed; box-sizing: border-box; border-spacing: 0; } #entrySpeedProgressWorkspace > tr > td { height: 30px; width: 20%; cursor: pointer; } #entrySpeedProgressWorkspace .on { background-size: 20px auto; background-position: 50% 50%; background-repeat: no-repeat; .backgroundImage('ic_graph_chk.png'); } #progressCell0 { background-color: #cad8ff; } #progressCell1 { background-color: #a7bfff; } #progressCell2 { background-color: #95b3ff; } #progressCell3 { background-color: #7299ff; } #progressCell4 { background-color: #4f80ff; } #entrySpeedLabelWorkspace { position: absolute; left: 10px; top: 12px; font-size: 10px; font-weight: 600; color: #000; letter-spacing: -0.4px; line-height: 11px; } #entrySpeedHandleWorkspace { position: absolute !important; cursor: pointer; width: 18px; height: 16px; top: 21px; z-index: 100; .backgroundImage('speed_handle.png'); } .entrySpeedBox { position: absolute; box-sizing: border-box; height: 39px; margin: 0px 0 -1px; padding: 0 10px 0 60px; border: 1px solid #e2e2e2; border-width: 1px 0; background-color: #f9f9f9; clear: both; z-index: 10; } .entryCoordinateButtonWorkspace { float: right; .backgroundImage('coordinates_edit.png'); } .entryCoordinateButtonWorkspace_w { float: right; margin-top: 4px; .backgroundImage('layers_icon_grid_nor.png'); background-size: 16px auto; } .entryCoordinateButtonWorkspace.toggleOn { .backgroundImage('coordinates_edit_on.png'); } .entryCoordinateButtonWorkspace_w.toggleOn { .backgroundImage('layers_icon_grid_nor_1.png'); } .entryEngineBlueWorkspace > .entryCoordinateButtonWorkspace { .backgroundImage('coordinates_play.png'); } .entryEngineButtonWrapper { display: flex; margin: 0 -1px -1px; margin-top: 12px; } .entryRunButtonWorkspace { float: right; width: 80px; background-position: 7px 50%; padding-right: 10px; text-align: right; font-size: 9pt; color: #61abdb; .backgroundImage('playbutton_edit.png'); } .entryAddButtonWorkspace_w, .entryPauseButtonWorkspace_w, .entryRestartButtonWorkspace_w { flex: none; width: 50%; height: 36px; border: 1px solid #4f80ff; border-radius: 4px; background-color: #fff; font-size: 12px; font-weight: 600; color: #4f80ff; letter-spacing: -0.43px; line-height: 34px; text-align: center; &:before { .backgroundImage('layers_icon_button_plus_nor.png'); display: inline-block; width: 12px; height: 12px; margin: 11px 2px 0 0; background-size: 12px auto; vertical-align: top; content: ''; } } .entryRestartButtonWorkspace_w { background-color: #4f80ff; color: #fff; } .entryPauseButtonWorkspace_w:before { .backgroundImage('layers_icon_button_pause_nor.png'); } .entryRestartButtonWorkspace_w:before { .backgroundImage('layers_icon_button_play_nor_1.png'); margin-right: 4px; } .entryRunButtonWorkspace_w { flex: 1 1 auto; position: relative; height: 36px; padding: 0; margin-left: 4px; border: 1px solid #4f80ff; border-radius: 4px; background-color: #4f80ff; background-size: 10px auto; font-size: 12px; font-weight: 600; color: #fff; text-align: center; line-height: 34px; &:before { .backgroundImage('layers_icon_button_play_nor_1.png'); display: inline-block; width: 11px; height: 12px; background-size: 11px auto; margin: 11px 4px 0 0; vertical-align: top; content: ''; } } .collapsed > .entryRunButtonWorkspace_w { color: transparent; background-position: 50% 43%; } .entryRunButtonWorkspace_w2 { display: none; } .entryEngineBlueWorkspace > .entryRunButtonWorkspace { .backgroundImage('playbutton_play.png'); color: white; } .entryStopButtonWorkspace { float: right; width: 80px; background-position: 7px 50%; border-top: 1px solid #ccc; padding-right: 10px; text-align: right; font-size: 9pt; color: #61abdb; .backgroundImage('stopbutton_pause.png'); } .entryStopButtonWorkspace_w { flex: 1 1 auto; position: relative; height: 36px; padding: 0; margin-left: 4px; border: 1px solid #4f80ff; border-radius: 4px; background-color: #fff; background-size: 10px auto; font-size: 12px; font-weight: 600; color: #4f80ff; text-align: center; line-height: 34px; &:before { .backgroundImage('layers_icon_button_stop_nor_2.png'); background-size: 12px auto; display: inline-block; width: 12px; height: 12px; margin: 10px 4px 0 0; vertical-align: top; content: ''; } } .entryStopButtonWorkspace_w2 { display: none; } .entryEngineBigButtonMinimize_popup { border: none; display: none; margin: 0; padding: 0; position: absolute; left: 50%; width: 111px; height: 111px; margin-left: -55.5px; top: 50%; margin-top: -55.5px; background-repeat: no-repeat; background-position: 40px center; background-color: rgba(0, 0, 0, 0.5); border-radius: 55px; } .entryEngineBigButtonMinimize_popup:hover { opacity: 0.8; } .entryEngineBigButtonMinimize_popup:focus { outline: none; } .entryEngineBigButtonMinimize_popup.entryEngineBigButtonMinimize_popup_run { .backgroundImage('play_btn.png'); } .entryPopupWindow .entryEngineBigButtonMinimize_popup { display: block; } .entryPopupWindow .entryPauseButtonWorkspace_w { flex: 2; order: 2; display: none; } .entryPopupWindow .entryRestartButtonWorkspace_w { display: none; } .entryPauseButtonWorkspace_full { display: none; } .entryRestartButtonWorkspace_full { display: none; } .nav_right_wrapper { right: 0; } .navbar-default { background-color: #89c1e4; border-color: #89c1e4; /*background-color: #4accaa; border-color: #4accaa;*/ } #project_name.normal { background-color: #89c1e4; /*background-color: #4accaa;*/ } .btn-group > .btn { background-color: transparent; border-color: transparent; /*background-color: #4accaa; border-color: #4accaa;*/ } .art_project_name { background-color: white !important; } .art_project_name:hover { border: 1px solid #b4b4b4 !important; } .tablet { .entrySpeedButtonWorkspace { width: 27px; height: 19px; margin-top: 2px; .backgroundImage('speed_edit_big.png'); } .entrySpeedButtonWorkspace.on { .backgroundImage('speed_edit_big.png'); } .entryCoordinateButtonWorkspace_w { .backgroundImage('layers_icon_grid_nor_big.png'); } .entryMaximizeButtonWorkspace_w { .backgroundImage('layers_icon_fullmode01_nor_1_big.png'); } } .entryPopupWindow.tablet { .entryEngineWorkspace_w > .entryCoordinateButtonWorkspace_w { bottom: 5px; background-image: url('@{image_url}grid_big.png') !important; } .entryEngineWorkspace_w > .entryMaximizeButtonWorkspace_w { right: 0; bottom: 5px; background-image: url('@{image_url}zoom_out_btn_big.png'); } } .practical_course_mode { .entryRunButtonWorkspace_w { border-color: @basePurple; &:before { .backgroundImage('layers_icon_button_play_nor_1.png'); } } .entryAddButtonWorkspace_w { border-color: @basePurple; &:before { .backgroundImage('layers_icon_button_plus_nor_practical_course_mode.png'); } } .entryPauseButtonWorkspace_w { border-color: @basePurple; &:before { .backgroundImage('layers_icon_button_pause_nor_practical_course_mode.png'); } } .entryStopButtonWorkspace_w { border-color: @basePurple; &:before { .backgroundImage('layers_icon_button_stop_nor_2_practical_course_mode.png'); } } } //audioShade .audioShadeCirclebox { position: absolute; margin: 0; padding: 0; background: rgba(255, 255, 255, 0.5); text-align: center; z-index: 10; display: flex; flex-direction: column; -moz-flex-direction: column; width: 100%; height: calc(100%-32px); } .audioShadeCircle { margin: auto; margin-bottom: 6%; padding: 0; position: relative; display: inline-block; height: 34%; width: auto; aspect-ratio: 1 / 1; border-radius: 50%; background-color: #32d27d; vertical-align: top; } .audioShadeInner { margin: 0; padding: 0; position: absolute; left: 0; right: 0; top: 0; bottom: 0; width: 60%; height: 60%; margin: auto; background-color: #32d27d; border-radius: 50%; transform: scale(0.5); transform-origin: center center; animation: ani 3s linear infinite; content: ''; } .audioShadeInner:nth-of-type(2) { animation-delay: 1s; } .audioShadeInner:nth-of-type(3) { animation-delay: 2s; } .audioShadeInner:nth-of-type(4) { animation-delay: 3s; } .audioShadeImg { margin: 0; padding: 0; position: absolute; left: 23%; top: 23%; width: 54%; height: 54%; z-index: 10; } .audioShadeText { width: 100%; height: 20%; font-family: NanumGothic, 'Nanum Gothic'; font-size: 1.1em; font-weight: bold; font-stretch: normal; font-style: normal; line-height: normal; letter-spacing: normal; text-align: center; } .audioProgress { width: 64%; height: 64%; position: absolute; left: 18%; top: 18%; } @keyframes ani { 0% { transform: scale(0.5); opacity: 0; } 50% { opacity: 0.1; } 70% { opacity: 0.09; } 100% { transform: scale(3); opacity: 0; } } ================================================ FILE: src/css/components/extensions.less ================================================ .targetChecker { height: 50px; background-color: white; border-bottom: 0.5px solid #5096f5; cursor: pointer; padding: 5px; } .targetChecker.success { background-color: #5cb85c; } .targetChecker.fail { background-color: #d9534f; } ================================================ FILE: src/css/components/function.less ================================================ .entryFunctionEdit { position: absolute; width: 100%; height: 100%; background-color: rgba(180,180,180, 0.4) !important; z-index: 50; } .entryFunctionEdit { position: absolute; width: 100%; height: 100%; background-color: rgba(180,180,180, 0.4) !important; z-index: 50; } #entryFunctionBtnWrapper { position: absolute; z-index: 100; bottom: 90px; margin: 0 auto; left: 50%; } .entryFunctionBtn { position: relative; display: inline-block; cursor: pointer; border: solid 3px #888; color: #666; width: 55px; height: 55px; border-radius: 27.5px; text-align: center; line-height: 48px; left: -50%; } .entryFunctionBtn:hover { border: solid 3px #555; color: #222; } #entryFunctionCancel { } #entryFunctionSave { margin-right: 20px; } ================================================ FILE: src/css/components/global_svg.less ================================================ .globalSvgSurface { pointer-events: none; position: fixed; width: 100%; height: 100%; z-index: 10000; top: 0; left: 0; } #globalSvg { position: fixed; overflow: visible; z-index: 10000; opacity: 0.8; will-change: transform; max-width: 100%; max-height: 100%; } ================================================ FILE: src/css/components/helper.less ================================================ /* helper */ .entryBlockHelperIntro .renderViewContainer { display: none; } #entryBlockHelperBlockWorkspace > .renderViewContainer { width: 100%; .renderView { margin-right: 9px; } } #entryBlockHelperBlockWorkspace > .renderViewContainer > svg { overflow: visible; } /* helper */ @keyframes blockHelperUp { 0% { top: 100%; } 100% { top: 0%; } } @-o-keyframes blockHelperUp { 0% { top: 100%; } 100% { top: 0%; } } @-ms-keyframes blockHelperUp { 0% { top: 100%; } 100% { top: 0%; } } @-moz-keyframes blockHelperUp { 0% { top: 100%; } 100% { top: 0%; } } @-webkit-keyframes blockHelperUp { 0% { top: 100%; } 100% { top: 0%; } } @keyframes blockHelperDown { 0% { top: 0%; } 100% { top: 100%; } } @-o-keyframes blockHelperDown { 0% { top: 0%; } 100% { top: 100%; } } @-ms-keyframes blockHelperDown { 0% { top: 0%; } 100% { top: 100%; } } @-moz-keyframes blockHelperDown { 0% { top: 0%; } 100% { top: 100%; } } @-webkit-keyframes blockHelperDown { 0% { top: 0%; } 100% { top: 100%; } } #entryBlockHelperWorkspaceWrapper { background-color: #ecf8ff; height: 100%; } #entryBlockHelperWorkspace { position: absolute; bottom: 0; width: 100%; height: 100%; background-color: inherit; .animation-name(blockHelperUp); .animation-duration(0.6s); } #entryBlockHelperWorkspace.lecture { .animation-duration(0s); } #entryBlockHelperWorkspace.dispose { display: none; .animation-name(blockHelperDown); } #entryBlockHelperHeaderWorkspace { position: absolute; width: 100%; height: 40px; background-color: #1bafea; font-size: 16px; line-height: 38px; padding-left: 28px; color: #fff; } #entryBlockHelperDisposeWorkspace { float: right; .backgroundImage('block_helper_dispose.png'); background-repeat: no-repeat; background-position: center; padding: 15px; margin-top: 4px; margin-right: 5px; } #entryBlockHelperContentWorkspace { position: absolute; width: 100%; top: 40px; bottom: 0px; overflow-y: auto; overflow-x: hidden; white-space: pre-line; } .entryBlockHelperIntro { .backgroundImage('block_help_icon_2.png'); background-size: 104px; background-repeat: no-repeat; background-position: center top; margin-top: 64px; padding-top: 100px; text-align: center; color: #707070; font-size: 12px; } #entryBlockHelpBtn { position: absolute; .backgroundImage('block_help.png'); background-repeat: no-repeat; background-position: center; padding: 15px; margin-top: 3px; margin-left: 6px; z-index: 100; } #entryBlockHelperBlockWorkspace { width: 100%; bottom: 0px; overflow: hidden; top: 16px; text-align: center; } #entryBlockHelperBlockWorkspace > svg { position: relative; } #entryBlockHelperDescriptionWorkspace { line-height: 20px; width: 100%; font-size: 14px; font-stretch: normal; font-style: normal; line-height: 18px; letter-spacing: -0.33px; padding: 0 20px; color: #555555; text-align: left; margin-top: 24px; } .blockHelperLink { width: 100%; font-size: 14px; font-stretch: normal; font-style: normal; line-height: 18px; letter-spacing: -.33px; padding: 0 20px; color: #555; text-align: left; margin-top: 24px; } .linkTextElem { font-size: 13px; font-weight: bold; color: #4F80FF; } .textModeElem { display: none; } #entryBlockHelperContentWorkspace.textMode { padding: 18px; top: 0; .textModeElem { display: block; } .entryBlockHelperTitle { font-family: EntryFont, NanumGothic, 'Nanum Gothic'; font-size: 18px; font-weight: bold; color: #3b3b3b; } .entryBlockHelperTitle:not(:first-child) { margin-top: 20px; } .renderViewContainer { text-align: left; margin-top: 9px; } #entryBlockHelperBlockWorkspace { height: auto; } #entryBlockHelperBlockWorkspace > div > svg { position: relative; left: auto; } #entryBlockHelperDescriptionWorkspace { text-align: left; padding: 0; } .entryBlockHelperContent { font-family: EntryFont, NanumGothic, 'Nanum Gothic'; font-size: 14px; color: #3b3b3b; margin-top: 8px; } .entryBlockHelperElementsContainer { .elementLeft { display: inline-block; vertical-align: top; } .elementRight { display: inline-block; margin-left: 15px; max-width: 80%; } } .entryBlockHelperElementsContainer:not(:first-child) { margin-top: 12px; } #entryBlockHelperCodeMirrorContainer { margin-top: 8px; } } ================================================ FILE: src/css/components/hw_monitor.less ================================================ .hwMonitor { background-color: #363c46; position: absolute; } .hwComponent text { font-size: 12px; } ================================================ FILE: src/css/components/object.less ================================================ .objectInfoView { list-style: none; padding: 0; height: 60px; width: 18px; position: relative; margin-left: 8px; float: left; } .objectInfo_visible { display: inline-block; position: absolute; top: 8px; left: 0; height: 18px; width: 18px; background-size: 18px auto; cursor: pointer; .box-sizing(border-box); .backgroundImage('layers_icon_visible.png'); } .objectInfo_unvisible { .backgroundImage('layers_icon_unvisible.png'); } .objectInfo_unlock { display: inline-block; position: absolute; top: 34px; left: 0; height: 18px; width: 18px; background-size: 18px auto; .backgroundImage('layers_icon_unlock.png'); cursor: pointer; .box-sizing(border-box); } .objectInfo_lock { .backgroundImage('layers_icon_lock.png'); } .entryDisabled { .objectInfo_visible { .backgroundImage('layers_icon_visible_disabled.png'); cursor: default; } .objectInfo_unlock { .backgroundImage('layers_icon_lock_disabled.png'); cursor: default; } .entryObjectDeleteWorkspace { .backgroundImage('layers_icon_close_nor_new_disabled.png'); background-size: 24px auto; cursor: default; } input { color: #cbcbcb; } &.selectedObject { .entryObjectWrapperWorkspace .entryObjectNameWorkspace { color: #cbcbcb; } } } .entryObjectThumbnailWorkspace { overflow: hidden; cursor: move; position: absolute; top: 8px; left: 34px; width: 36px; height: 40px; border: 1px solid #e2e2e2; border-radius: 4px; background-color: #fff; background-size: 70%; background-repeat: no-repeat; background-position: center; user-select: none; -webkit-touch-callout: none; &.entryObjectTextBox { .backgroundImage('text_icon.svg'); background-size: cover; } } .entryObjectWrapperWorkspace { overflow: hidden; position: relative; margin: 16px 64px 0 76px; } .entryObjectNameWorkspace { overflow: hidden; box-sizing: border-box; width: 100%; padding: 7px 4px 6px; border: 1px solid transparent; border-radius: 4px; background-color: transparent; font-size: 12px; font-weight: 600; color: #2c313d; white-space: nowrap; text-overflow: ellipsis; line-height: 12px; } .selectedObject { .entryObjectNameWorkspace:focus { border-color: #4f80ff; } .entryObjectNameWorkspace { border-color: #aac5d5; background-color: #f7fcff; } } .editButtonToggle { display: block; } .editButtonToggle_ { display: none; } .selectedNotEditionObject { background-color: transparent; } .selectedNotEditionObject:hover { background-color: transparent; } .selectedNotEditionObject:focus { background-color: transparent !important; } /*sj*/ .selectedObject > .entryObjectWrapperWorkspace > .entryObjectNameWorkspace { color: #2c313d; font-family: EntryFont, NanumGothic, 'Nanum Gothic' !important; } .entryObjectNameWorkspace:disabled { background-color: #fff; } .entryContainerListElementWorkspace.entryDisabled > .entryObjectWrapperWorkspace::before { display: block; content: " "; width: 100%; height: 100%; position: absolute; } .entryObjectDeleteWorkspace { overflow: hidden; position: absolute; right: 3px; top: 17px; width: 24px; height: 24px; cursor: pointer; background-size: 10px auto; background-position: 50% 50%; background-repeat: no-repeat; .backgroundImage('layers_icon_close_nor_new.png'); } .entryObjectDeletePhone { float: left; position: absolute; width: 16px; height: 16px; right: 57px; top: 25px; cursor: pointer; .backgroundImage('layers_icon_close_nor.png'); } .entryObjectEditPhone { float: left; position: absolute; width: 24px; background-repeat: no-repeat; height: 21px; right: 17px; background-color: transparent; border: none; top: 21px; cursor: pointer; .backgroundImage('glyphicons_150_edit.png'); } .entryObjectSelectedImgWorkspace { position: absolute; width: 16px; right: 0; top: 45px; bottom: 0; cursor: col-resize; .backgroundImage('entry_scroll.png'); background-repeat: no-repeat; background-size: 6px auto; background-position: 50% 50%; z-index: 250; &.enabled { .backgroundImage('entry_scroll_enable.png') } } .selectedObject .entryObjectSelectedImgWorkspace { float: left; position: absolute; width: 14px; height: 26px; right: 0; top: 20px; cursor: col-resize; .backgroundImage('entry_scroll.png'); } .entryObjectCoordinateWorkspace { display: block; font-size: 12px; font-weight: 600; color: #2c313d; letter-spacing: -0.4px; width: auto; } .entryObjectCoordinateWorkspaceWrapper, .entryObjectCoordinateSizeWrapper { display: inline-block; position: relative; margin-left: 6px; vertical-align: top; &:first-of-type { margin-left: 0; } } .entryObjectCoordinateSizeWrapper { margin-left: 12px; } .entryObjectCoordinateSpanWorkspace { position: absolute; right: 6px; top: 7px; font-size: 10px; font-weight: 600; color: #979797; &.degree { top: 6px; width: 4px; height: 4px; border: solid 1px #979797; border-radius: 50%; } } .selectedObject > .entryObjectWrapperWorkspace > .entryObjectCoordinateWorkspace { color: black; } .entryObjectInformationWorkspace { position: absolute; right: 32px; top: 18px; width: 24px; height: 24px; background-size: 10px auto; background-repeat: no-repeat; background-position: center; cursor: pointer; .backgroundImage('layers_arrow_down_nor.png'); } .selectedObject .entryObjectInformationWorkspace { .backgroundImage('layers_arrow_up_nor.png'); } .fold .entryObjectInformationWorkspace { .backgroundImage('layers_arrow_down_nor.png'); } .informationToggle > .entryObjectWrapperWorkspace > .entryObjectInformationWorkspace { .backgroundImage('layers_arrow_down_nor_1.png'); } .entryObjectButtonWorkspace { display: none; float: right; position: relative; width: 40px; height: 40px; background-color: #bcc3c9; border-radius: 50%; margin: 10px 10px 10px 5px; background-position: center; background-repeat: no-repeat; background-position: 50% 35%; color: white; font-size: 7.5pt; padding: 23px 0 0 0; text-align: center; outline: none; border: none; } .informationToggle > .entryObjectButtonWorkspace { display: none; } .entryObjectSoundWorkspace { .backgroundImage('icon_sound.png'); background-color: #6a9a1f; } .entryObjectSoundWorkspace:hover { background-color: #83af3d; } .entryObjectPictureWorkspace { .backgroundImage('icon_picture.png'); background-color: #f26724; } .entryObjectPictureWorkspace:hover { background-color: #f3783c; } .entryObjectCodeWorkspace { .backgroundImage('icon_code.png'); background-color: #00ace9; } .entryObjectCodeWorkspace:hover { background-color: #5fc8ee; } .entryObjectTextWorkspace { .backgroundImage('text_icon_white.png'); background-color: #f3bb1d; background-position: 50% 20%; background-size: 75%; } .entryObjectRotationWrapperWorkspace { position: relative; display: none; margin: 10px 10px 0; padding-top: 9px; border-top: 1px solid #aac5d5; clear: both; } .collapsed .entryObjectRotationWrapperWorkspace { height: 90px; } .selectedObject .entryObjectRotationWrapperWorkspace { display: block; } .fold .entryObjectRotationWrapperWorkspace { display: none; } .informationToggle > .entryObjectRotationWrapperWorkspace { display: inline-block; } .rotationMethodWrapper { display: inline-block; position: relative; margin-left: 12px; padding-bottom: 32px; vertical-align: top; } .collapsed .rotationMethodWrapper { float: left; position: absolute; bottom: 9px; } .entryObjectRotateMethodLabelWorkspace { position: absolute; left: 0; right: 0; bottom: 13px; font-size: 10px; font-weight: 600; color: #2c313d; line-height: 12px; text-align: center; vertical-align: top; } .entryObjectRotateLabelWrapperWorkspace { position: relative; margin-top: 8px; font-size: 12px; font-weight: 600; color: #2c313d; } .entryObjectRotateWorkspaceWrapper, .entryObjectDirectionWorkspaceWrapper { position: relative; display: inline-block; margin-left: 6px; padding-bottom: 32px; vertical-align: top; &:first-of-type, &.entryRemove + .entryObjectDirectionWorkspaceWrapper { margin-left: 0; } } .entryObjectRotateInputWorkspace, .entryObjectDirectionInputWorkspace { width: 60px; height: 24px; box-sizing: border-box; padding: 0 13px 0 8px; background-color: #fff; border: 1px solid #aac5d5; border-radius: 4px; font-size: 10px; font-weight: 600; color: #2c313d; letter-spacing: -0.4px; text-align: left; } .entryObjectRotateInputWorkspace:focus, .entryObjectRotateInputWorkspace:active, .entryObjectDirectionInputWorkspace:focus, .entryObjectDirectionInputWorkspace:active { border-color: #4f80ff; } .entryObjectDirectionSpanWorkspace, .entryObjectRotateSpanWorkspace { position: absolute; left: 0; right: 0; bottom: 13px; font-size: 10px; font-weight: 600; color: #2c313d; text-align: center; line-height: 12px; } .entryObjectRotateInputWorkspace + .entryObjectDirectionSpanWorkspace { margin-left: 10px; } .entryObjectRotateInputWorkspace.entryRemove + .entryObjectDirectionSpanWorkspace { margin-left: 0; } .entryObjectRotateModeWorkspace { cursor: pointer; display: inline-block; width: 24px; height: 24px; vertical-align: top; background-size: 24px auto; } .entryObjectRotateModeAWorkspace { .backgroundImage('layers_icon_rotate01_nor.png'); } .entryObjectRotateModeAWorkspace.selected { .backgroundImage('layers_icon_rotate01_sel.png'); } .entryObjectRotateModeBWorkspace { margin-left: 6px; .backgroundImage('layers_icon_rotate02_nor.png'); } .entryObjectRotateModeBWorkspace.selected { .backgroundImage('layers_icon_rotate02_sel.png'); } .entryObjectRotateModeCWorkspace { margin-left: 6px; .backgroundImage('layers_icon_rotate03_nor.png'); } .entryObjectRotateModeCWorkspace.selected { .backgroundImage('layers_icon_rotate03_sel.png'); } .entryObjectCoordinateSizeWorkspace { display: inline-block; position: relative; margin-right: 6px; font-size: 10px; font-weight: 600; vertical-align: top; line-height: 24px; } .entryObjectCoordinateInputWorkspace { width: 60px; height: 24px; padding: 0 13px 0 8px; background-color: #fff; border: 1px solid #aac5d5; border-radius: 4px; font-size: 10px; font-weight: 600; color: #2c313d; letter-spacing: -0.4px; text-align: left; box-sizing: border-box; } .entryObjectCoordinateInputWorkspace:focus, .entryObjectCoordinateInputWorkspace:active { border-color: #4f80ff; } .entryObjectCoordinateInputWorkspace_size { float: none; position: relative; } ================================================ FILE: src/css/components/painter.less ================================================ .entryPlaygroundPainter { position: absolute; left: 253px; top: 0; bottom: 0; right: 0; border-left: none; background-color: #f9f9f9; &.fullscreen { min-height: 547px; top: 42px; left: 0; z-index: 251; } .ControlPanel { button { vertical-align: top; } } } ================================================ FILE: src/css/components/pdf.less ================================================ #entryPdfWorkspace:extend(#entryBlockHelperWorkspace) { iframe { width: 100%; height: 100%; } } ================================================ FILE: src/css/components/playground.less ================================================ .entryPlayground_text_buttons { display: inline-block; list-style-type: none; margin: 0; padding: 0; } .entryPlayground_text_buttons > li { float: left; width: 32px; height: 32px; margin-left: 2px; cursor: pointer; } .entryPlaygroundTextAlignLeft { .backgroundImage('text_align_left_off.png'); } .entryPlaygroundTextAlignLeft.toggle { .backgroundImage('text_align_left_on.png'); } .entryPlaygroundTextAlignCenter { .backgroundImage('text_align_center_off.png'); } .entryPlaygroundTextAlignCenter.toggle { .backgroundImage('text_align_center_on.png'); } .entryPlaygroundTextAlignRight { .backgroundImage('text_align_right_off.png'); } .entryPlaygroundTextAlignRight.toggle { .backgroundImage('text_align_right_on.png'); } .entryPlayground_fgColorDiv { position: absolute; width: 15px; height: 4px; margin-top: -10px; margin-left: 8px; } .entryPlayground_bgColorDiv { position: absolute; width: 15px; height: 4px; margin-top: -10px; margin-left: 8px; } .entryPlayground_textBox { margin-top: 5px; height: 33px; width: 400px; } .entryPlayground_textArea { margin-top: 5px; height: 120px; width: 400px; resize: none; } .entryPlaygroundFontSizeWrapper { position: absolute; padding-left: 13px; padding-top: 10px; display: inline-block; width: 244px; height: 40px; border-radius: 4px; background-color: #ffffff; right: 0px; top: 0px; } .entryPlaygroundFontSizeLabel { display: inline-block; width: 65px; height: 15px; font-size: 14px; font-weight: bold; font-style: normal; font-stretch: normal; line-height: normal; letter-spacing: -0.3px; color: #2c313d; } #entryTextColourTable { margin-top: 12px; cursor: pointer; border-collapse: collapse; } .entryTd { width: 22px; height: 22px; } .entryTdTransparent { width: 20px; height: 20px; background-color: white; background-image: -webkit-linear-gradient( 135deg, transparent 11.5px, rgb(255, 0, 0) 13px, rgba(255, 255, 255, 0.5) 14.5px ); border: 1px solid; } .entryPlaygroundSoundLength { margin-top: 6px; font-size: 10px; line-height: 11px; } .entryPlaygroundDefaultWorkspace { height: 100%; background-color: white; color: white; } @introHeight: 66px; .entryPlaygroundIntro.active { position: relative; overflow: hidden; height: @introHeight; top: 50px; z-index: 1; } .entryPlaygroundWorkspace { position: relative; overflow: hidden; height: 100%; background-color: #fff; } .entryPlaygroundIntro.active + .entryPlaygroundWorkspace { height: calc(100% - @introHeight); } .entryPlaygroundPhone { width: 100%; height: 500px; background-color: #f5f5f5; } .entryPlaygroundResizeWorkspace { position: absolute; top: 50%; height: 62px; width: 36px; left: 311px; margin-top: -20px; cursor: pointer; border-left: none; z-index: 1; .backgroundImage('entry_scroll_02.svg'); background-size: 36px auto; &.highIndex { z-index: 300; } &.folding { z-index: 253; .animation-duration(0.7s); .animation-name(foldBlockly); .animation-fill-mode(forwards); .backgroundImage('entry_scroll_03.svg'); } &.unfolding { .animation-duration(0.7s); .animation-name(unfoldBlockly); .animation-fill-mode(forwards); .backgroundImage('entry_scroll_02.svg'); } } @keyframes unfoldBlockly { from {left: 58px;} to {left: 311px;} } @keyframes foldBlockly { from {} to {left: 58px;} } .entryPlaygroundTabWorkspace { position: absolute; left: 0; top: 46px; background-color: #fff; } .entryPlaygroundTabWorkspace.entryRemove { display: block !important; } .entryPlaygroundTabPhone { width: 100%; height: 43px; position: relative; background-color: #f1f1f1; } .entryPlaygroundBackPackView { height: calc(100% - 47px); display: block; right: 0; top: 38px; z-index: 299; position: absolute; .widget { height: 100%; } .blockBackPackDrop, .objectBackPackDrop { position: fixed; display: none; top: 0; left: 0; z-index: 400; background-color: rgba(248, 241, 204, 0.9); border: 2px dashed #ffc800; justify-content: center; align-items: center; flex-direction: column; .blockBackPackIcon { pointer-events: none; width: 32px; height: 32px; margin-bottom: 11px; .backgroundImage('img_backpack_plus.svg'); } .objectBackPackDesc, .blockBackPackDesc { pointer-events: none; font-family: EntryFont, NanumGothic, 'Nanum Gothic'; font-size: 12px; font-weight: bold; letter-spacing: -0.1px; white-space: pre; text-align: center; color: #2c313d; } } } .entryPlaygroundButtonTabWorkspace { position: absolute; right: 0; top: 43px; height: auto; background-color: #fff; .entryPlaygroundCommentButtonWorkspace { float: left; background-repeat: no-repeat; background-size: 32px auto; background-position: 50% 50%; cursor: pointer; width: 32px; height: 32px; &.enabled { background-size: 32px auto; width: 32px; height: 32px; border: 0; background-color: inherit; } &.showComment { margin-right: 4px; .backgroundImage('btn-toggle-comment-off.svg'); &.enabled { .backgroundImage('btn-toggle-comment-select.svg'); } } &.addComment { margin-right: 8px; .backgroundImage('btn-add-comment-off.svg'); &.enabled { .backgroundImage('btn-add-comment-select.svg'); } } } .entryPlaygroundBackPackButtonWorkspace { &::before { content: ''; display: inline-block; width: 1px; height: 16px; background: #bfd8e6; margin: 8px 0 0 -9px; } float: left; .backgroundImage('back_pack_button.svg'); background-repeat: no-repeat; background-size: 32px auto; background-position: 50% 50%; cursor: pointer; width: 32px; height: 32px; margin: 0 9px; } &.entryRemove.entryCode { display: block !important; } } .entryTabListWorkspace { overflow: hidden; list-style: none; padding: 0; margin: 0; } .entryTabListItemWorkspace { float: left; min-width: 58px; margin-left: 2px; padding: 0; cursor: pointer; background-color: #d7e8f4; border-top-right-radius: 6px; border-top-left-radius: 6px; font-size: 12px; font-weight: 600; color: #8ba4b3; text-align: center; letter-spacing: -0.4px; line-height: 32px; } .entryTabListItemWorkspace:first-child { margin-left: 0; } .entryTabSelected { color: #fff; background-color: @baseblue; font-size: 14px; } .entryTabListItemWorkspace:hover { } #entrySoundTab { .animation-delay(0.1s); } #entryPictureTab.hideTab, #entryTextTab.hideTab { .animation-delay(0.2s); } #entrySoundTab.hideTab { .animation-delay(0.1s); } #entryVariableTab.showTab { .animation-delay(0.2s); } .hideTab { .animation-duration(0.7s); .animation-name(hideTab); .animation-fill-mode(forwards); } @keyframes hideTab { from { } to { margin-top: 44px; opacity: 0; } } @-webkit-keyframes hideTab { from { } to { margin-top: 44px; opacity: 0; } } .showTab { opacity: 0; .animation-duration(0.7s); .animation-name(showTab); .animation-fill-mode(forwards); } @keyframes showTab { from { margin-top: 44px; opacity: 0; } to { opacity: 1; } } @-webkit-keyframes showTab { from { margin-top: 44px; opacity: 0; } to { opacity: 1; } } .entryPlaygroundCurtainWorkspace { position: absolute; background-color: black; color: white; padding-top: 270px; text-align: center; font-size: 40px; top: 38px; left: 0; right: 0; bottom: 8px; opacity: 0.5; z-index: 500; cursor: pointer; white-space: pre-line; } .entryPlaygroundCurtainPhone { position: absolute; background-color: rgba(0, 0, 0, 0.8); color: white; padding-top: 100px; text-align: center; font-size: 17px; height: 110%; width: 100%; opacity: 0.5; z-index: 5000; cursor: pointer; } .entryPlaygroundPictureCurtainWorkspace { position: absolute; background-color: black; top: 0; left: 0; right: 0; bottom: 0; opacity: 0.6; z-index: 255; border-radius: 0 0 0 6px; } .entryPlaygroundPictureCurtainWorkspace .entryPlaygroundPictureCurtainWorkspaceText { text-align: center; height: 100%; color: white; font-family: NanumGothic, 'Nanum Gothic'; font-size: 24px; font-weight: bold; line-height: 1.33; letter-spacing: -0.6px; display: flex; justify-content: center; /* align horizontal */ align-items: center; /* align vertical */ white-space: pre-line; } .entryPlaygroundTableCurtainWorkspace { position: absolute; background-color: black; top: 0; left: 0; right: 0; bottom: 0; opacity: 0.6; z-index: 255; border-radius: 0 0 0 6px; } .entryPlaygroundTableCurtainWorkspace .entryPlaygroundTableCurtainWorkspaceText { text-align: center; height: 100%; color: white; font-family: NanumGothic, 'Nanum Gothic'; font-size: 24px; font-weight: bold; line-height: 1.33; letter-spacing: -0.6px; display: flex; justify-content: center; /* align horizontal */ align-items: center; /* align vertical */ } .entryPlaygroundCodeWorkspace { overflow: unset; position: absolute; left: 0; right: 0; top: 80px; bottom: 8px; background-color: #fff; border-radius: 0 0 0 6px; } .entryPlaygroundCodeWorkspace.entryRemove { display: block !important; visibility: hidden; } .entryPlaygroundCodePhone { position: relative; height: 100%; background-color: #f5f5f5; } .entryPlaygroundCodePhone.entryRemove { display: block !important; visibility: hidden; } .entryPlaygroundPicturePhone { margin-left: 0; height: 100%; background-color: #ececec; } .entryPlaygroundPictureWorkspace { position: absolute; left: 0; right: 0; bottom: 8px; background-color: #f9f9f9; top: 80px; margin-left: 0; border-radius: 0 0 0 6px; } .entryPlaygroundAddPicture { width: 254px; padding: 8px 0 7px; background-color: #ecf8ff; border: 1px solid #d6e9f4; } .entryPlaygroundAddPicturePhone { position: relative; padding: 0; margin: 0; height: 50px; cursor: pointer; border-bottom: 1pt solid #ebeff1; } .entryPlaygroundAddPictureInner { display: inline-block; width: 116px; height: 40px; margin-left: 7px; background-color: #fff; border: 1px solid #4f80ff; border-radius: 4px; color: #4f80ff; text-align: center; font-size: 12px; font-weight: 600; line-height: 38px; cursor: pointer; } .entryPlaygroundNewPictureInner { display: inline-block; width: 116px; height: 40px; margin-left: 6px; background-color: #fff; border: 1px solid #e2e2e2; border-radius: 4px; color: #555; text-align: center; font-size: 12px; font-weight: 600; line-height: 38px; cursor: pointer; } .entryPlaygroundAddPictureInnerPhone { display: block; height: 50px; background-color: #cdcfc9; color: #656565; text-align: center; font-size: 10.5pt; line-height: 36px; border: 2px dashed #737373; width: 240px; padding: 8px 10px 12px 10px; } .entryPlaygroundPictureList { position: absolute; padding: 0px; margin: 0px; width: 254px; top: 56px; bottom: 0px; overflow-y: hidden; list-style: none; background-color: #ecf8ff; border: 1px solid #d6e9f4; border-radius: 0 0 0 6px; } .entryPlaygroundPictureListPhone { position: absolute; padding: 0px; margin: 0px; width: 254px; top: 56px; bottom: 0px; overflow: auto; list-style: none; background-color: #ecf8ff; border: 1px solid #d6e9f4; } .entryPlaygroundPictureElement { display: block; position: relative; background-color: #ecf8ff; border-bottom: 1px solid #d6e9f4; padding: 0 56px 0 64px; height: 61px; color: #2c313d; cursor: pointer; } .entryPlaygroundPictureElement::-moz-selection { cursor: move; background-color: #fff; } .entryPlaygroundPictureElement::selection { cursor: move; background-color: #fff; } .entryPlaygroundPictureOrder, .entryPlaygroundSoundOrder { overflow: hidden; position: absolute; left: 19px; top: 11px; width: 14px; height: 14px; background-color: #4f80ff; border-radius: 50%; font-size: 10px; color: #fff; text-align: center; line-height: 16px; z-index: 10; } .entryPictureSelected { background-color: #fff; } .entryPlaygroundPictureThumbnail { position: absolute; height: 44px; width: 40px; top: 8px; left: 16px; border: 1px solid #e2e2e2; background-color: #fff; border-radius: 4px; background-size: contain; background-repeat: no-repeat; background-position: 50% 50%; user-select: none; -webkit-touch-callout: none; } .entryPlaygroundPictureName { width: 100%; height: 24px; margin-top: 10px; padding: 0 4px; background-color: #fff; outline: 0; font-size: 12px; text-overflow: ellipsis; color: #2c313d; font-weight: 600; cursor: text; border: 1px solid #e2e2e2; border-radius: 4px; box-sizing: border-box; } .entryPlaygroundPictureName:focus, .entryPlaygroundPictureName:active { border-color: #4f80ff; } .entryPlaygroundPictureSize { margin-top: 6px; font-size: 10px; line-height: 11px; } .entryPlayground_del { position: absolute; right: 26px; top: 18px; width: 24px; height: 24px; border: 1px solid #e2e2e2; border-radius: 4px; background-color: #fff; background-size: 10px; font-size: 0; cursor: pointer; background-size: 10px auto; background-position: 50% 50%; background-repeat: no-repeat; .backgroundImage('layers_icon_close_nor_new.png'); } .pop_selectbox { position: relative; .select_link { display: block; position: relative; width: 142px; height: 38px; padding: 0 12px; border: 1px solid #e2e2e2; background-color: #fff; border-radius: 4px; font-weight: 600; color: #555; letter-spacing: -0.3px; line-height: 40px; cursor: pointer; } .select_link:after { position: absolute; right: 16px; top: 50%; width: 8px; height: 6px; margin-top: -3px; vertical-align: top; content: ''; } & + .pop_selectbox { margin-top: 40px; } & + .on { z-index: 10; } & + .pop_inpt_text { margin-top: 40px; } &.error .select_link { border-color: #f00; } } .pop_selectbox * { box-sizing: content-box; } .pop_selectbox .tooltip_box { display: none; } .pop_selectbox.on .tooltip_box { display: block; z-index: 10; top: 52px; } .entryPlaygroundTextWorkspace { position: absolute; top: 80px; left: 0; right: 0; bottom: 8px; background-color: #ecf8ff; border-radius: 0 0 0 6px; } // 글상자 .entryPlaygroundTextWorkspace .write_box { height: 568px; } .entryPlaygroundTextWorkspace .write_box .write_set { position: relative; padding: 8px 18px; background-color: #f9f9f9; border: 1px solid #e2e2e2; z-index: 10; } .entryPlaygroundTextWorkspace .write_box .write_set:after { display: block; clear: both; content: ''; } .entryPlaygroundTextWorkspace .write_box .write_set .pop_selectbox { float: left; width: 168px; } .entryPlaygroundTextWorkspace .write_box .write_set .pop_selectbox .tooltip_inner { max-height: 282px; overflow: visible; overflow-y: auto; } .entryPlaygroundTextWorkspace .write_box .write_set .font_style_box { position: relative; float: left; padding-left: 24px; font-size: 0; } .entryPlaygroundTextWorkspace .write_box .write_set .font_style_box .style_link { display: inline-block; overflow: hidden; width: 40px; height: 40px; margin-left: 10px; border: 1px solid #e2e2e2; background-color: #fff; border-radius: 4px; cursor: pointer; } .entryPlaygroundTextWorkspace .write_box .write_set .font_style_box .style_link.on { border: 1px solid #4f80ff; } .entryPlaygroundTextWorkspace .write_box .input_box .write_type_box { display: inline-block; border-radius: 4px; width: 207px; height: 40px; font-size: 0; } .entryPlaygroundTextWorkspace .write_box .input_box .write_type_box a { display: inline-block; position: relative; width: 102px; height: 38px; border: 1px solid #e2e2e2; border-radius: 4px 0 0 4px; font-size: 14px; font-weight: 600; color: #979797; background-color: #fff; text-align: center; letter-spacing: -0.3px; line-height: 36px; cursor: pointer; } .entryPlaygroundTextWorkspace .write_box .input_box .write_type_box a + a { margin-left: -1px; border-radius: 0 4px 4px 0; } .entryPlaygroundTextWorkspace .write_box .input_box .write_type_box .on { color: #4f80ff; border-color: #4f80ff; z-index: 10; } .entryPlaygroundTextWorkspace .write_box .input_box { margin: 24px 38px 0; max-width: 654px; position: relative; } .entryPlaygroundTextWorkspace .write_box .input_box .list { padding: 4px 0px; list-style: none; } .entryPlaygroundTextWorkspace .write_box .input_box .list li { color: #555; margin-top: 4px; line-height: 18px; } .entryPlaygroundTextWorkspace .write_box .input_box .list li:before { display: inline-block; width: 3px; height: 3px; border-radius: 50%; background-color: #555; margin: 6px 8px 0 0; vertical-align: top; content: ''; } .entryPlaygroundTextWorkspace .write_box .input_inner { position: relative; overflow: hidden; height: 40px; max-width: 654px; background-color: #fff; border: 1px solid #e2e2e2; border-radius: 4px; margin-top: 24px; } .entryPlaygroundTextWorkspace .write_box .input_inner .bold { font-weight: bold; } .entryPlaygroundTextWorkspace .write_box .input_inner .italic { font-style: italic; } .entryPlaygroundTextWorkspace .write_box .input_inner input[type='text'] { display: none; width: 100%; height: 100%; margin: 0; padding-left: 15px; border: 0; line-height: 40px; outline: 0; font-size: 14px; letter-spacing: -0.3px; } .entryPlaygroundTextWorkspace .write_box .input_inner textarea { width: 100%; height: 100%; margin: 0; padding: 12px; font-size: 14px; border: 0; line-height: 18px; outline: 0; letter-spacing: -0.3px; } .entryPlaygroundTextWorkspace .write_box .input_inner label { position: absolute; left: 16px; right: 16px; top: 13px; color: #979797; letter-spacing: -0.3px; } .imbtn_pop_font_bold { .backgroundImage('btn_pop_font_bold.png'); background-size: 38px auto; &.on { .backgroundImage('btn_pop_font_bold_on.png'); } } .imbtn_pop_font_underline { .backgroundImage('btn_pop_font_underline.png'); background-size: 38px auto; &.on { .backgroundImage('btn_pop_font_underline_on.png'); } } .imbtn_pop_font_italic { .backgroundImage('btn_pop_font_italic.png'); background-size: 38px auto; &.on { .backgroundImage('btn_pop_font_italic_on.png'); } } .imbtn_pop_font_through { .backgroundImage('btn_pop_font_through.png'); background-size: 38px auto; &.on { .backgroundImage('btn_pop_font_through_on.png'); } } .imbtn_pop_font_color { display: inline-block; position: relative; overflow: hidden; width: 66px; height: 40px; margin-left: 10px; .backgroundImage('btn_pop_font_color.png'); background-size: 66px auto; cursor: pointer; em { position: absolute; left: 5px; right: 5px; top: 5px; bottom: 5px; background-color: #f9f9f9; z-index: -1; } &.on { .backgroundImage('btn_pop_font_color_on.png'); } } .imbtn_pop_font_paint, .imbtn_pop_font_backgroundcolor { display: inline-block; position: relative; overflow: hidden; width: 66px; height: 40px; margin-left: 10px; .backgroundImage('btn_pop_font_paint.png'); background-size: 66px auto; cursor: pointer; em { position: absolute; left: 5px; right: 5px; top: 5px; bottom: 5px; z-index: -1; } &.on { .backgroundImage('btn_pop_font_paint_on.png'); &.clear { .backgroundImage('btn_pop_font_paint_clear_on.png'); em { display: none; } } } &.clear { .backgroundImage('btn_pop_font_paint_clear.png'); em { display: none; } } &.clear_on { .backgroundImage('btn_pop_font_paint_clear_on.png'); em { display: none; } } } .imbtn_pop_font_align_left { .backgroundImage('btn_pop_font_align_left.png'); background-size: 38px auto; &.on { .backgroundImage('btn_pop_font_align_left_on.png'); } } .imbtn_pop_font_align_middle { .backgroundImage('btn_pop_font_align_middle.png'); background-size: 38px auto; &.on { .backgroundImage('btn_pop_font_align_middle_on.png'); } } .imbtn_pop_font_align_right { .backgroundImage('btn_pop_font_align_right.png'); background-size: 38px auto; &.on { .backgroundImage('btn_pop_font_align_right_on.png'); } } .imico_pop_select_arr_down:after { .backgroundImage('ico_pop_select_arr_down.png'); background-size: 8px auto; } .imico_pop_select_arr_up:after { .backgroundImage('ico_pop_select_arr_up.png'); background-size: 8px auto; } #entryFontColorToggle { .backgroundImage('text_in_off.png'); } #entryFontColorToggle.selected { .backgroundImage('text_in_on.png'); } #entryFontBGToggle { margin-left: 6px; .backgroundImage('text_out_off.png'); } #entryFontBGToggle.selected { .backgroundImage('text_out_on.png'); } .entryPlaygroundSoundWorkspace { overflow: hidden; position: absolute; left: 0; right: 0; bottom: 8px; background-color: #f9f9f9; border-radius: 0 0 0 6px; top: 80px; margin-left: 0; } .entryPlaygroundSoundEdit { position: absolute; left: 253px; top: 0; bottom: 0; right: 0; overflow: hidden; border-left: 1px solid #e2e2e2; background-color: #f2f2f2; .entryPlaygroundSoundEditWrapper { text-align: center; } .entryPlaygroundSoundEditImage { .backgroundImage('sound_edit.gif'); width: 160px; height: 160px; -o-object-fit: contain; object-fit: contain; margin: 0 auto 24px; background-size: 160px auto; } .entryPlaygroundSoundEditText { margin: 0 auto; font-size: 14px; font-weight: bold; font-style: normal; font-stretch: normal; line-height: normal; letter-spacing: -0.3px; text-align: center; color: #555555; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; white-space: pre-line; } } .entryPlaygroundAddSound { width: 254px; padding: 8px 0; background-color: #ecf8ff; border: 1px solid #d6e9f4; } .entryPlaygroundAddSoundPhone { position: relative; height: 50px; cursor: pointer; border-bottom: 1pt solid #ebeff1; } .entryPlaygroundAddSoundInner { display: block; overflow: hidden; width: calc(100% - 24px); height: 40px; margin: 0 auto; background-color: #fff; border: 1px solid #4f80ff; border-radius: 4px; color: #4f80ff; text-align: center; letter-spacing: -0.32px; font-size: 14px; font-weight: 600; line-height: 38px; cursor: pointer; } .entryPlaygroundAddSoundInnerPhone { display: block; height: 40px; background-color: #cdcfc9; color: #656565; text-align: center; font-size: 10.5pt; line-height: 36px; margin: 10px; border: 2px dashed #737373; width: 220px; } .entryPlaygroundSoundList { position: absolute; padding: 0; margin: 0; width: 254px; top: 57px; bottom: 0; overflow-y: hidden; list-style: none; background-color: #ecf8ff; border: 1px solid #d6e9f4; } .entryPlaygroundSoundListPhone { position: absolute; padding: 0px; margin: 0px; width: 254px; top: 57px; bottom: 0px; overflow: hidden; overflow-y: auto; list-style: none; background-color: #ecf8ff; border: 1px solid #d6e9f4; border-radius: 0 0 0 6px; } .entryPlaygroundSoundElement { display: block; position: relative; background-color: #ecf8ff; border-bottom: 1px solid #d6e9f4; padding: 0 56px 0 64px; height: 61px; color: #2c313d; cursor: pointer; &.entrySoundSelected { background-color: #fff; } } .entryPlaygroundSoundThumbnail { position: absolute; height: 44px; width: 40px; top: 8px; left: 16px; border: 1px solid #e2e2e2; background-color: #fff; border-radius: 4px; background-size: 28px auto; background-repeat: no-repeat; background-position: 50% 50%; user-select: none; -webkit-touch-callout: none; &.entryPlaygroundSoundPlay { .backgroundImage('workspace_sound_play.svg'); } &.entryPlaygroundSoundStop { .backgroundImage('workspace_sound_stop.svg'); } } .entryPlaygroundSoundName { width: 100%; height: 24px; box-sizing: border-box; margin-top: 10px; padding: 0 4px; background-color: #fff; outline: 0; font-size: 12px; text-overflow: ellipsis; color: #2c313d; font-weight: 600; cursor: text; border: 1px solid #e2e2e2; border-radius: 4px; } .entryPlaygroundSoundName:focus, .entryPlaygroundSoundName:active { border-color: #4f80ff; } .entryPlayground_text_buttons { display: inline-block; list-style-type: none; margin: 0; padding: 0; } .entryPlayground_text_buttons > li { float: left; width: 32px; height: 32px; margin-left: 2px; cursor: pointer; } .entryPlaygroundTextAlignLeft { .backgroundImage('text_align_left_off.png'); } .entryPlaygroundTextAlignLeft.toggle { .backgroundImage('text_align_left_on.png'); } .entryPlaygroundTextAlignCenter { .backgroundImage('text_align_center_off.png'); } .entryPlaygroundTextAlignCenter.toggle { .backgroundImage('text_align_center_on.png'); } .entryPlaygroundTextAlignRight { .backgroundImage('text_align_right_off.png'); } .entryPlaygroundTextAlignRight.toggle { .backgroundImage('text_align_right_on.png'); } .entryPlayground_fgColorDiv { position: absolute; width: 15px; height: 4px; margin-top: -10px; margin-left: 8px; } .entryPlayground_bgColorDiv { position: absolute; width: 15px; height: 4px; margin-top: -10px; margin-left: 8px; } .entryPlaygroundFontSizeSlider { display: inline-block; margin-left: 12px; width: 136px; height: 8px; border-radius: 3px; box-shadow: inset 1px 1px 1px 0 rgba(0, 0, 0, 0.03); background-color: #d8d8d8; } .entryPlaygroundFontSizeIndicator { height: 100%; width: 45%; border-radius: 3px; background-color: #643cd9; } .entryPlaygroundFontSizeKnob { width: 19px; height: 30px; -o-object-fit: contain; object-fit: contain; position: relative; margin-top: -19px; margin-left: -12px; .backgroundImage('text_size_knob.png'); background-repeat: no-repeat; background-position: center; cursor: pointer; } .entryPlaygroundTextColoursWrapper { width: 260px; height: 226px; z-index: 10; cursor: pointer; padding: 20px 5px; position: absolute; .backgroundImage('text_color_bg.png'); background-repeat: no-repeat; background-size: 260px 226px; } .entryPlaygroundTextBackgroundsWrapper { width: 260px; height: 226px; z-index: 10; cursor: pointer; padding: 20px 5px; position: absolute; .backgroundImage('text_color_bg_1.png'); background-repeat: no-repeat; background-size: 260px 226px; } .entryPlaygroundLinebreakWrapper { position: fixed; top: 351px; } .entryPlaygroundLinebreakButtons { display: inline; font-size: 0; img { cursor: pointer; } } .entryPlaygroundLinebreakHorizontal { display: block; border-top: 1px solid #808080; margin: 0 0 12px 0; padding: 0; width: 260px; } .entryPlaygroundLinebreakDescription { margin-top: 12px; p { color: #8888; font-size: 11px; margin-bottom: 5px; } ul { padding-left: 20px; li { color: #b4b4b5; font-size: 11px; } } } .tablet { .entryPlaygroundResizeWorkspace { .backgroundImage('entry_scroll_02.svg'); width: 36px; height: 62px; border-top: none; } } .entrySceneListWorkspace { .rcs-inner-container { > div > div > div { display: table; table-layout: fixed; .sortableItem { display: table-cell; vertical-align: top; width: 76px; } } } } .sortable { height: 100%; .rcs-custom-scrollbar { width: 8px; right: 4px; opacity: 0.8; } .rcs-inner-handle { background-color: #aac5d5 !important; border-radius: 2.5px !important; opacity: 0.8; } } .entryPlaygroundTableWorkspace { overflow: hidden; position: absolute; left: 0; right: 0; bottom: 8px; background-color: #f9f9f9; border-radius: 0 0 0 6px; top: 80px; margin-left: 0; } .entryPlaygroundTableEdit { position: absolute; left: 253px; top: 0; bottom: 0; right: 0; overflow: hidden; border-left: 1px solid #e2e2e2; background-color: #f2f2f2; display: flex; justify-content: center; align-items: center; .entryPlaygroundTableEditWrapper { text-align: center; } .entryPlaygroundTableEditImage { .backgroundImage('sound_edit.gif'); width: 160px; height: 160px; -o-object-fit: contain; object-fit: contain; margin: 0 auto 24px; background-size: 160px auto; } .entryPlaygroundTableEditText { margin: 0 auto; font-size: 14px; font-weight: bold; font-style: normal; font-stretch: normal; line-height: normal; letter-spacing: -0.3px; text-align: center; color: #555555; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } } .entryPlaygroundAddTable { width: 254px; padding: 8px 0; background-color: #ecf8ff; border: 1px solid #d6e9f4; } .entryPlaygroundAddTablePhone { position: relative; height: 50px; cursor: pointer; border-bottom: 1pt solid #ebeff1; } .entryPlaygroundAddTableInner { display: block; width: 146px; height: 40px; margin: 0 auto; background-color: #fff; border: 1px solid #4f80ff; border-radius: 4px; color: #4f80ff; text-align: center; font-size: 14px; font-weight: 600; line-height: 38px; cursor: pointer; } .entryPlaygroundAddTableInnerPhone { display: block; height: 40px; background-color: #cdcfc9; color: #656565; text-align: center; font-size: 10.5pt; line-height: 36px; margin: 10px; border: 2px dashed #737373; width: 220px; } .entryPlaygroundTableList { position: absolute; padding: 0; margin: 0; width: 254px; top: 57px; bottom: 0; overflow-y: hidden; list-style: none; background-color: #ecf8ff; border: 1px solid #d6e9f4; } .entryPlaygroundTableListPhone { position: absolute; padding: 0px; margin: 0px; width: 254px; top: 57px; bottom: 0px; overflow: hidden; overflow-y: auto; list-style: none; background-color: #ecf8ff; border: 1px solid #d6e9f4; border-radius: 0 0 0 6px; } .entryPlaygroundTableList { position: absolute; padding: 0px; margin: 0px; width: 254px; top: 56px; bottom: 0px; overflow-y: hidden; list-style: none; background-color: #ecf8ff; border: 1px solid #d6e9f4; border-radius: 0 0 0 6px; } .entryPlaygroundTableElement { display: block; position: relative; background-color: #ecf8ff; border-bottom: 1px solid #d6e9f4; padding: 0 56px 0 36px; height: 48px; color: #2c313d; cursor: pointer; &.entryTableSelected { background-color: #fff; } .entryPlaygroundTableThumbnail { position: absolute; height: 22px; width: 22px; top: 13px; left: 8px; .backgroundImage('workspace_table_icon.svg'); background-repeat: no-repeat; background-position: 50% 50%; } .entryPlaygroundTableName { width: 100%; height: 24px; box-sizing: border-box; margin-top: 12px; padding: 0 4px; background-color: #fff; outline: 0; font-size: 12px; text-overflow: ellipsis; color: #2c313d; font-weight: 600; cursor: text; border: 1px solid #e2e2e2; border-radius: 4px; } .entryPlaygroundTableName:focus, .entryPlaygroundTableName:active { border-color: #4f80ff; } .entryPlaygroundTableRemove { position: absolute; right: 26px; top: 12px; width: 24px; height: 24px; border: 1px solid #e2e2e2; border-radius: 4px; background-color: #fff; background-size: 10px; font-size: 0; cursor: pointer; background-size: 10px auto; background-position: 50% 50%; background-repeat: no-repeat; .backgroundImage('layers_icon_close_nor_new.png'); } } ================================================ FILE: src/css/components/popup.less ================================================ .entryPopup { overflow: hidden; position: fixed; margin: 0; padding: 0; top: 0; left: 0; height: 100%; width: 100%; z-index: 7000; background-color: rgba(0, 0, 0, 0.6); } .entryPopup.popupHelper { position: fixed; display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; -webkit-box-direction: normal; -moz-box-direction: normal; -webkit-box-orient: vertical; -moz-box-orient: vertical; -webkit-flex-direction: column; -ms-flex-direction: column; flex-direction: column; } .entryPopupWindow { width: 80%; height: 80%; overflow: hidden; position: absolute; left: 0; right: 0; top: 0; bottom: 0; border-radius: 6px; border: 1px solid #d6e9f4; margin: auto; max-width: 100%; max-height: 100%; /*overflow: hidden;*/ z-index: 8000; background-color: @white; } .entryPopup.hiddenPopup { display: none; } .entryPopupHelperTopSpan, .entryPopupHelperBottomSpan { -webkit-box-flex: 1; -moz-box-flex: 1; -ms-flex: 1; flex: 1; } .entryPopupHelperMiddleSpan { display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; -webkit-box-direction: normal; -moz-box-direction: normal; -webkit-box-orient: horizontal; -moz-box-orient: horizontal; -webkit-flex-direction: row; -ms-flex-direction: row; flex-direction: row; .entryPopupHelperLeftSpan, .entryPopupHelperRightSpan { -webkit-box-flex: 1; -moz-box-flex: 1; -ms-flex: 1; flex: 1; } } .entryPopup.buttonsHidden .entryEngineButtonWorkspace_w { display: none; } .entryPopup.learning_popup { z-index: 7001; .ai_learning { overflow: hidden; .learningInputPopup { border: none; height: 248px; width: 294px; background-color: #fff; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; } .learningInputPopup.text { height: 165px; } .learningInputPopup.image { height: 245px; } .learningInputPopup.speech { height: 250px; } } } ================================================ FILE: src/css/components/property_panel.less ================================================ .propertyPanel { // z-index: 10; position: relative; flex: 1; margin-top: 16px; left: 0px; right: 16px; bottom: 0px; height: 1px; } .propertyTab { overflow: hidden; width: 25px; height: 100%; } .propertyTabElement { height: 38px; margin-top: 4px; cursor: pointer; font-size: 0; background-size: 25px auto; } .propertyTabElement:first-child { margin-top: 0; } .collapsed .propertyTabElement { background-position: 50% 9px; height: 36px; font-size: 0; } .propertyTabobject { .backgroundImage('property/container_off.png'); } .propertyTabobject.selected { .backgroundImage('property/container_on.png'); .practical_course_mode & { .backgroundImage('property/container_on_practical_course.png'); } } .propertyTabhw { .backgroundImage('property/hw_off.png'); } .propertyTabhw.selected { .backgroundImage('property/hw_on.png'); .practical_course_mode & { .backgroundImage('property/hw_on_practical_course.png'); } } .propertyTabtvCast { .backgroundImage('property/vedio_off.png'); } .propertyTabtvCast.selected { .backgroundImage('property/vedio_on.png'); } .propertyTabyoutube { .backgroundImage('property/vedio_off.png'); } .propertyTabyoutube.selected { .backgroundImage('property/vedio_on.png'); } .propertyTabgoal { .backgroundImage('property/doneproject.png'); } .propertyTabgoal.selected { .backgroundImage('property/doneproject_on.png'); } .propertyTabpdf { .backgroundImage('property/pdf_off.png'); } .propertyTabpdf.selected { .backgroundImage('property/pdf_on.png'); } .propertyTabconsole { .backgroundImage('property/console_off.png'); } .propertyTabhint { .backgroundImage('property/hint_off_property.png'); } .propertyTabhint.selected { .backgroundImage('property/hint_on.png'); } .propertyTabconsole.selected { .backgroundImage('property/console_on.png'); .practical_course_mode & { .backgroundImage('property/console_on_practical_course.png'); } } .propertyContent { overflow: hidden; position: absolute; top: 0; bottom: 0; left: 25px; right: 0; background-color: #fff; border: 1px solid #d6e9f4; border-radius: 0 6px 6px 6px; } .propertyContent:after { display: block; clear: both; content: ''; } .propertyPanelCover { position: absolute; top: 0; bottom: 0; left: 0; right: 0; } .collapsed .propertyContent { left: 30px; } ================================================ FILE: src/css/components/scene.less ================================================ body { & > .sortableItem { z-index: 250; } } .entryTopFloatingView { display: flex; position: absolute; width: 100%; flex-flow: row nowrap; .entrySceneWorkspace { flex: 1; height: 38px; padding-top: 1px; background-color: @baseblue; overflow: hidden; z-index: 10; .practical_course_mode & { background-color: @basePurple; } } .entryBlockCountView { background-color: @baseblue; z-index: 10; display: flex; flex-direction: row-reverse; align-items: center; .practical_course_mode & { background-color: @basePurple; } .blockCountView { height: 24px; line-height: 24px; border-radius: 14px; margin-right: 12px; padding: 0 8px; background-color: @baseBluePoint; font-size: 12px; color: #ffffff; .practical_course_mode & { background-color: @basePurplePoint; } } } } .entrySceneListWorkspace { overflow: hidden; float: left; margin: 0; padding: 0 0 0 26px; max-width: calc(100% - 72px); .rcs-custom-scroll .rcs-outer-container { overflow: visible; .rcs-inner-container { overflow: visible; } } .sortableItem { z-index: 15; } } .entrySceneElementWorkspace { overflow: hidden; margin: 5px 2px 0 0; color: white; cursor: move; z-index: 10; } .entrySceneElementWorkspace.selectedScene { position: relative; margin-top: 0; z-index: 888; } .entrySceneAddButtonWorkspace { float: left; position: relative; margin: 3px 0px 0px -2px; width: 44px; height: 34px; cursor: pointer; .backgroundImage('btn_scene_add.png'); background-size: 44px 34px; } .entryScenePrevButtonWorkspace { position: absolute; width: 25px; height: 39px; left: 0px; z-index: 299; margin: 0px; .prevBtn { position: absolute; width: 25px; height: 37px; content: ''; .backgroundImage('btn_scene_left.png'); background-position: 50%; background-repeat: no-repeat; background-color: transparent; cursor: pointer; z-index: 299; } } .entrySceneNextButtonWorkspace { position: relative; display: inline-block; background-color: #4f80ff; width: 72px; height: 37px; right: 0px; opacity: 0.8; z-index: 299; margin: 0px; .nextBtn { position: absolute; width: 28px; height: 37px; content: ''; .backgroundImage('btn_scene_right.png'); background-position: 50%; background-repeat: no-repeat; background-color: transparent; cursor: pointer; z-index: 299; } .addButton { float: left; position: relative; right: 0px; margin: 3px 0px 0px 28px; width: 44px; height: 34px; cursor: pointer; .backgroundImage('btn_scene_add.png'); background-size: 44px 34px; } } .selectedScene { .entrySceneInputCover { min-width: 97px; } } .entrySceneInputCover { display: block; overflow: hidden; height: 32px; padding: 4px 10px 0; border-bottom: 2px solid transparent; background-color: #99c4ff; border-radius: 10px 10px 0 0; } .entrySceneInputCover.entryDisabledScene::before { display: block; content: ' '; width: 100%; height: 100%; position: absolute; top: 0; left: 0; } .entrySceneFieldWorkspace { cursor: text !important; display: inline-block; overflow: hidden; margin: 0px; height: 24px; width: 100%; border: 1px solid transparent; border-radius: 4px; outline: 0; background-color: transparent; font-size: 12px; font-weight: 600; color: #fff; line-height: 24px; } .selectedScene .entrySceneInputCover { height: 37px; padding: 7px 30px 0 10px; background-color: #fff; border-radius: 8px 8px 0 0; border-bottom-color: #ffb500; } .selectedScene .entrySceneFieldWorkspace { background-color: #fff; font-size: 14px; color: #ffb500; } .selectedScene .entrySceneFieldWorkspace:focus { font-size: 12px; border: 1px solid #e2e2e2; color: #2c313d; } .entrySceneRemoveButtonWorkspace { position: absolute; right: 0; top: 3px; width: 30px; height: 30px; padding: 0; border: 0; display: none; .backgroundImage('scene_delete_unselect.png'); background-size: 10px auto; background-repeat: no-repeat; background-position: center; background-color: transparent; } .minValue .entrySceneRemoveButtonWorkspace { display: none; } .selectedScene .entrySceneRemoveButtonWorkspace { display: block; top: 3px; background-color: transparent; .backgroundImage('scene_delete.png'); } // .entrySceneRemoveButtonWorkspace:hover { // .backgroundImage("scene_delete_hover.png"); // } .entrySceneDummyView { width: 55px; height: 40px; background-color: orange; display: inline-block; opacity: 0.3; position: absolute; left: 0; top: 0; z-index: 889; left: 100px; } .tablet { .entrySceneRemoveButtonWorkspace { width: 14px; height: 14px; right: 48px; .backgroundImage('scene_delete_unselect_big.png'); } .selectedScene .entrySceneRemoveButtonWorkspace { .backgroundImage('scene_delete_big.png'); } .entrySceneRemoveButtonWorkspace:hover { .backgroundImage('scene_delete_hover_big.png'); } } ================================================ FILE: src/css/components/stage.less ================================================ .entryCanvasWrapper { position: absolute; } .entryCanvasWorkspace { position: relative; top: 0px; left: 0; width: 268px; background-color: white; border-top: 1px solid #d6e9f4; vertical-align: top; } .entryCanvasPhone { width: 100%; background-color: white; display: block; } .entryPopupWindow > .entryCanvasWorkspace { width: 100% !important; position: relative; border-bottom: 1px solid #d6e9f4; border-top: 0px; } .entryPopupWindow > .entryEngine_w { width: 100% !important; height: 100% !important; border: 0; } .entryPopupWindow > div > .entryCanvasWorkspace { width: 100% !important; top: 0 !important; vertical-align: top; } ================================================ FILE: src/css/components/state_manager.less ================================================ .entryStateManagerWorkspace { float: right; height: 40px; margin-right: 10px; } .entryStateManagerButtonWorkspace { border:0; margin: 3px; padding-left: 26px; height: 32px; border-radius: 4px; background-color: #BDC4C9; color: #E2EBFA; font-size: 10pt; background-repeat: no-repeat; background-position: 7px 8px; border-bottom: 2pt solid #A0ACB2; border-right: 2pt solid #A0ACB2; } .entryStateManagerButtonWorkspace.active:hover { background-color: #7CC2EE; } .entryStateManagerButtonWorkspace.active { background-color: #6AAFDA; border-bottom: 2pt solid #639FBD; border-right: 2pt solid #639FBD; } .entryUndoButtonWorkspace { background-image: url("/img/assets/undo.png"); } .entryRedoButtonWorkspace { background-image: url("/img/assets/redo.png"); } ================================================ FILE: src/css/components/table.less ================================================ .entryPlaygroundTable { position: absolute; left: 254px; top: 0; bottom: 0; right: 0; border-left: none; background-color: #f9f9f9; } ================================================ FILE: src/css/components/target_checker.less ================================================ .entryTargetStatus { font-family: EntryFont, NanumGothic, 'Nanum Gothic'; height: 54px; width: 100%; position: absolute; bottom: 0; } .entryTargetStatus .innerWrapper { width: auto; position: absolute; background-color: #f4f4f4; border-radius: 3px; height: 54px; } .entryPopupWindow .entryTargetStatus { height: 91px; } .iframeWithTargetStatus .innerWrapper { width: 100%; } .entryPopupWindow .innerWrapper { left: 16px; right: 16px; } .iframeWithTargetStatus #entryCanvasWrapper { bottom: 89px; } .iframeWithTargetStatus .entryEngine { bottom: 54px; } .entryTargetStatus .statusIndicator { display: inline-block; width: 43px; height: 41px; text-align: center; line-height: 41px; font-size: 14px; color: #fff; .backgroundImage('status_dialog.png'); margin-left: 14px; margin-top: 6px; } .entryTargetStatus .statusMessage { font-size: 14px; color: #3b3b3b; left: 71px; top: 0; bottom: 0; right: 10px; display: table; position: absolute; width: 100%; height: 54px; } .statusMessage p { display: table-cell; vertical-align: middle; padding-right: 81px; } .targetCheckerPopup .entryEngine_w { height: auto !important; bottom: 91px; } .blueWS { .entryTargetStatus .statusIndicator { .backgroundImage('status_dialog_blue.png'); } } .purpleWS { .entryTargetStatus .statusIndicator { .backgroundImage('status_dialog_purple.png'); } } ================================================ FILE: src/css/components/textcoding_helper.less ================================================ .propertyTabconsole { } #textCodingExampleView { position: absolute; width: 100%; top: 150px; } ================================================ FILE: src/css/components/toast.less ================================================ .entryToastContainer { position: fixed; right: 0px; bottom: 15px; margin: 0px; padding: 2px; width: 300px; max-height: 100%; overflow: auto; z-index: 9000; } .entryToast { padding: 7px 16px; margin-top: 8px; width: 100%; background-color: #eee; box-shadow: #999 0 0 8px; border: 2px solid; .border-radius(4px); .transition(opacity 0.25s ease-in-out); text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); cursor: pointer; opacity: 1; } .entryToastSuccess { border-color: #d6e9c6; background-color: #e5f3df; color: #468847; } .entryToastWarning { border-color: #7e7190; background-color: #fff9ab; color: #e07000; } .entryToastAlert { color: #b94a48; background-color: #f2dede; border-color: #eed3d7; } .entryToastTitle { font-size: 12pt; font-weight: bold; } .entryToastMessage { font-size: 9pt; margin-top: 4px; margin-bottom: 2px; white-space: pre-line; } .entryMobileToastWrapper { position: absolute; margin-top: 24px; width: 100%; text-align: center; pointer-events: none; z-index: 1; .entryMobileToast { &::before { content: ''; display: inline-block; .backgroundImage('toast_left.svg'); width: 17px; height: 38px; margin-right: -4px; } &::after { content: ''; display: inline-block; .backgroundImage('toast_right.svg'); width: 20px; height: 38px; margin-left: -4px; } display: inline-block; // width: 90px; height: 38px; font-size: 14px; vertical-align: top; font-weight: bold; font-style: normal; font-stretch: normal; line-height: normal; letter-spacing: -0.5px; text-align: center; color: #4f80ff; .content { display: inline-block; height: 38px; padding: 9px 8px; vertical-align: top; .backgroundImage('toast_bg.svg'); } } } ================================================ FILE: src/css/components/tooltip.less ================================================ @keyframes fIn { 0% { opacity: 0; } 100% { opacity: 0.5; } } .entryTooltipBG { position: absolute; width: 100%; height: 100%; z-index: 9990; top: 0; left: 0; cursor: pointer; animation-name: fIn; animation-duration: 0.3s; animation-timing-function: ease-out; } @keyframes stretch { 0% { opacity: 0; transform: translate(0, -10px); } 100% { opacity: 1; transform: translate(0, 0); } } .entryTooltipWrapper { position: absolute; z-index: 9999; animation-name: stretch; animation-duration: 0.5s; animation-timing-function: ease-out; .transition(opacity 0.4s ease-in-out); } .hideTooltip > .entryTooltipWrapper { opacity: 0; } @balloon-arrow-width: 25px; @balloon-arrow-height: 11px; .mixin-svg-arrow(@width, @height, @degrees) { @svg-arrow: ~''; @-svg-code: escape(~'@{svg-arrow}'); background: url('data:image/svg+xml;charset=utf-8,@{-svg-code}') no-repeat; background-size: 100% auto; height: @height; width: @width; } .svg-arrow(@color, @position) { & when (@position = down) { @width: @balloon-arrow-width; @height: @balloon-arrow-height; @degrees: 180 12.5 5.5; .mixin-svg-arrow(@width, @height, @degrees); } & when (@position = up) { @width: @balloon-arrow-width; @height: @balloon-arrow-height; @degrees: 0; .mixin-svg-arrow(@width, @height, @degrees); } & when (@position = right) { @width: @balloon-arrow-height; @height: @balloon-arrow-width; @degrees: 90 5.5 5.5; .mixin-svg-arrow(@width, @height, @degrees); } & when (@position = left) { @width: @balloon-arrow-height; @height: @balloon-arrow-width; @degrees: -90 12.5 12.5; .mixin-svg-arrow(@width, @height, @degrees); } } .entryTooltip { position: absolute; white-space: nowrap; padding: 25px; background-color: #ffffff; border-radius: 8px; text-align: center; font-size: 14px; font-family: EntryFont, NanumGothic, 'Nanum Gothic'; color: #3b3b3b; box-shadow: 2px 2px 10px 0 rgba(0, 0, 0, 0.19); &:before { position: absolute; content: ''; } } .entryTooltip.up { .transform(translate(-50%, -100%)); margin-top: -11px; &:before { .svg-arrow('#FFF', up); top: 100%; left: 50%; margin-left: -@balloon-arrow-width * 0.5; } } .entryTooltip.down { margin-top: 11px; .transform(translate(-50%, 0)); &:before { .svg-arrow('#FFF', down); top: -@balloon-arrow-height; left: 50%; margin-left: -@balloon-arrow-width * 0.5; } } .entryTooltip.left { margin-left: -11px; .transform(translate(-100%, -50%)); &:before { .svg-arrow('#FFF', left); left: 100%; margin-left: -1px; top: 50%; margin-top: -@balloon-arrow-width * 0.5; } } .entryTooltip.right { margin-left: 11px; .transform(translate(0, -50%)); &:before { .svg-arrow('#FFF', right); top: 50%; left: -@balloon-arrow-height; margin-top: -@balloon-arrow-width * 0.5; } } @keyframes IndicatorPop { 0% { opacity: 1; transform: scale(0); } 75% { opacity: 0; transform: scale(1); } 100% { opacity: 0; transform: scale(1); } } .entryTooltipIndicator { position: absolute; padding-top: 25px; } .entryTooltipIndicator > div { width: 50px; height: 50px; background-color: #ffffff; margin: -100% -50%; border-radius: 100%; position: relative; z-index: 9999; animation-name: IndicatorPop; animation-duration: 1.3s; animation-iteration-count: infinite; animation-timing-function: ease-out; transform: scale(0); } .entryTooltipIndicator > div:nth-child(2) { animation-delay: 0.3s; } .entryTooltipIndicator > div:nth-child(3) { animation-delay: 0.6s; } //special .entryTooltip.left.edge_up { .transform(translate(-100%, -25px)); &:before { top: 25px; } } .entryTooltip.left.edge_down { .transform(translate(-100%, -100%)); margin-top: 25px; &:before { top: 100%; margin-top: -37.5px; } } .entryTooltip.right.edge_up { .transform(translate(0, -25px)); &:before { top: 25px; } } .entryTooltip.right.edge_down { .transform(translate(0, -100%)); margin-top: 25px; &:before { top: 100%; margin-top: -37.5px; } } .entryTooltip.up.edge_left { .transform(translate(-25px, -100%)); &:before { left: 25px; } } .entryTooltip.up.edge_right { .transform(translate(-100%, -100%)); margin-left: 25px; &:before { left: 100%; margin-left: -37.5px; } } .entryTooltip.down.edge_left { .transform(translate(-25px, 0)); &:before { left: 25px; } } .entryTooltip.down.edge_right { left: 0; margin-left: 25px; .transform(translate(-100%, 0)); &:before { left: 100%; margin-left: -37.5px; } } ================================================ FILE: src/css/components/variable_container.less ================================================ .entryVariablePanelWorkspace { position: absolute; overflow: hidden; overflow-y: auto; width: 254px; top: 0; bottom: 0px; padding: 16px 16px 0 8px; background-color: #ecf8ff; // border: 1px solid #d6e9f4; box-shadow: 0 0 0 1px #d6e9f4 inset; border-radius: 0 0 0 6px; } .entryVariablePanelPhone { width: 250px; top: 47px; bottom: 0px; padding: 6px 4px 0px 4px; } .entryVariableSelectorWorkspace { width: 100%; border-collapse: collapse; border-spacing: 0; border: 0; padding: 0; margin: 0; table-layout: fixed; } .entryVariableSelectorWorkspace tr:first-child td:first-child { width: 56px; } .entryVariableSelectButtonWorkspace { font-family: EntryFont, NanumGothic, 'Nanum Gothic' !important; width: 88px; padding: 0; margin: 0; cursor: pointer; vertical-align: top; div { &:before { position: absolute; left: 15px; top: 9px; width: 20px; height: 20px; background-size: 20px auto; vertical-align: top; content: ''; } position: relative; height: 40px; padding-left: 8px; font-size: 12px; font-weight: 600; color: #728997; background-color: #fff; letter-spacing: -0.4px; line-height: 40px; } &.selected div { color: #4f80ff; z-index: 10; } &.allButton div { height: 80px; padding: 0; border-radius: 4px 0 0 4px; text-align: center; line-height: 80px; &:after { right: -1px; border-radius: 4px 0 0 4px; } } .text { display: block; overflow: hidden; margin: 0 8px 0 28px; text-overflow: ellipsis; white-space: nowrap; } } .entryVariableSelectButtonWorkspace.message div { border-radius: 0 6px 0 0; } .entryVariableSelectButtonWorkspace.func div { border-radius: 0 0 6px 0; } .entryVariableSelectButtonWorkspace.disable div { cursor: default; } .entryVariableSelectButtonWorkspace div:after { position: absolute; left: 0; right: 0; top: 0; bottom: 0; border: 1px solid #d6e9f4; content: ''; } .entryVariableSelectButtonWorkspace.selected div:after { border-color: #4f80ff; } .entryVariableSelectButtonWorkspace.allButton div .text { margin: 0; } .entryVariableSelectButtonWorkspace.variable div:after { right: -1px; } .entryVariableSelectButtonWorkspace.message div:after { border-radius: 0 6px 0 0; } .entryVariableSelectButtonWorkspace.list div:after { right: -1px; top: -1px; } .entryVariableSelectButtonWorkspace.func div:after { top: -1px; border-radius: 0 0 6px 0; } .entryVariableSelectButtonWorkspace.allButton div:before { display: none; } .entryVariableSelectButtonWorkspace.variable div:before { .backgroundImage('ic_attr_variable.svg'); } .entryVariableSelectButtonWorkspace.message div:before { .backgroundImage('ic_attr_message.svg'); } .entryVariableSelectButtonWorkspace.list div:before { margin-right: 6px; .backgroundImage('ic_attr_list.svg'); } .entryVariableSelectButtonWorkspace.func div:before { .backgroundImage('ic_attr_func.svg'); } .entryVariableSelectButtonWorkspace.variable.selected div:before { .backgroundImage('ic_attr_variable_on.svg'); } .entryVariableSelectButtonWorkspace.message.selected div:before { .backgroundImage('ic_attr_message_on.svg'); } .entryVariableSelectButtonWorkspace.list.selected div:before { margin-right: 6px; .backgroundImage('ic_attr_list_on.svg'); } .entryVariableSelectButtonWorkspace.func.selected div:before { .backgroundImage('ic_attr_func_on.svg'); } .entryVariableListElementWorkspace { background-repeat: no-repeat; background-position: 14px 10px; background-color: #efefef; border: solid 1px #a8a8a8; margin-bottom: -1px; min-height: 50px; } .entryVariableListWorkspace { overflow: auto; position: absolute; top: 112px; bottom: 0; left: 0; right: 0; padding: 0; margin: 0; border-top: 1px solid #d5d6e9f4; } .entryVariableAdd_box .entryVariableAddWorkspace { display: block; overflow: hidden; width: 146px; height: 40px; margin: 0 auto 16px; margin-top: 16px; border: 1px solid #4f80ff; border-radius: 4px; background-color: #fff; font-size: 14px; font-weight: 600; color: #4f80ff; text-align: center; text-decoration: none; line-height: 42px; -webkit-box-sizing: border-box; box-sizing: border-box; } .entryVariableAdd_box .entryVariableAddWorkspace.disabled { border: 1px solid #e2e2e2; background-color: #f9f9f9; color: #cbcbcb; cursor: default; } .entryVariableAdd_box.entryVariableContainerTextMode .entryVariableAddSpaceWorkspace { display: none; } .entryVariableAdd_box .message_inpt.off { display: none; } .entryVariableAdd_box .message_inpt input[type='text']::placeholder { color: #979797; } .entryVariableAdd_box .message_inpt .entryVariableAddSpaceButtonWrapperWorkspace { border: 0; margin: 0; } .entryVariableAdd_box .entryVariableAddSpaceWorkspace.off { display: none; } .entryVariableAddSpaceNameWrapperWorkspace .entryVariableAddSpaceInputLabelWorkspace { position: relative; left: -10px; margin-bottom: 8px; display: inline-block; font-size: 11px; font-weight: 600; color: #2c313d; line-height: 11px; vertical-align: top; } .entryVariableAddSpaceNameWrapperWorkspace .entryVariableAddSpaceInputLabelWorkspace:before { content: ''; display: inline-block; overflow: hidden; border-radius: 50%; margin: 3px 7px 0 0; vertical-align: top; width: 3px; height: 3px; background-color: #728997; } .entryVariableAddSpaceNameWrapperWorkspace .entryVariableAddSpaceInputWorkspace { overflow: hidden; width: 100%; padding: 6px 8px 5px; border: 1px solid #aac5d5; border-radius: 4px; outline: 0; background-color: #fff; font-size: 10px; font-weight: 600; color: #2c313d; letter-spacing: -0.4px; line-height: 11px; -webkit-box-sizing: border-box; box-sizing: border-box; } .entryVariableAddSpaceNameWrapperWorkspace .entryVariableAddSpaceInputWorkspace::-webkit-input-placeholder { color: #979797; } .entryVariableAddSpaceNameWrapperWorkspace .entryVariableAddSpaceInputWorkspace:-ms-input-placeholder { color: #979797; } .entryVariableAddSpaceNameWrapperWorkspace .entryVariableAddSpaceInputWorkspace::-ms-input-placeholder { color: #979797; } .entryVariableAddSpaceNameWrapperWorkspace .entryVariableAddSpaceInputWorkspace::placeholder { color: #979797; } .entryVariableAddSpaceGlobalWrapperWorkspace { position: relative; margin: 16px 0 0 14px; padding: 0 0 0 26px; font-size: 12px; font-weight: 600; color: #2c313d; cursor: pointer; line-height: 14px; } .entryVariableAddSpaceGlobalWrapperWorkspace + .entryVariableAddSpaceGlobalWrapperWorkspace { margin-top: 22px; } .entryVariableAddSpaceGlobalWrapperWorkspace .Workspace_text { display: inline-block; padding: 4px 0 2px; } .entryVariableAddSpaceGlobalWrapperWorkspace .entryVariableAddSpaceCheckWorkspace { position: absolute; left: 0; top: 0; width: 20px; height: 20px; background-size: 20px auto; .backgroundImage('btn_radio.png'); } .entryVariableAddSpaceGlobalWrapperWorkspace.on .entryVariableAddSpaceCheckWorkspace { .backgroundImage('btn_radio_on.png'); } .entryVariableAddSpaceGlobalWrapperWorkspace .entryVariableAddSpaceCloudWrapperWorkspace { display: none; position: relative; margin: 14px 0 -6px; padding: 11px 0 11px 32px; border: 1px solid #aac5d5; border-width: 1px 0; font-size: 12px; color: #2c313d; cursor: pointer; letter-spacing: -0.5px; } .entryVariableAddSpaceGlobalWrapperWorkspace .entryVariableAddSpaceCloudWrapperWorkspace .entryVariableAddSpaceCloudSpanWorkspace { display: inline-block; line-height: 1.33; letter-spacing: -0.48px; white-space: pre; } .entryVariableAddSpaceGlobalWrapperWorkspace .entryVariableAddSpaceCloudWrapperWorkspace .entryCloudTypeWrapper .entryVariableAddSpaceCheckWorkspace { position: absolute; left: -28px; width: 20px; height: 20px; background-size: 20px auto; .backgroundImage('btn_radio.png'); } .entryVariableAddSpaceGlobalWrapperWorkspace .entryVariableAddSpaceCloudWrapperWorkspace .entryCloudTypeWrapper.on .entryVariableAddSpaceCheckWorkspace { .backgroundImage('btn_radio_on.png'); } .entryVariableAddSpaceGlobalWrapperWorkspace.on .entryVariableAddSpaceCloudWrapperWorkspace { display: block; } .entryVariableAddSpaceCloudWrapperWorkspace { .entryCloudTypeWrapper { position: relative; margin-bottom: 12px; &:last-child { margin-bottom: 0px; } } } .entryVariableSplitterWorkspace { border: 1px solid #d6e9f4; border-width: 1px 0; } .entryVariableSplitterWorkspace + .entryVariableSplitterWorkspace { border-top: 0; } .entryVariableSplitterWorkspace .list + .list { border-top: 1px solid #d6e9f4; } .entryVariableSplitterWorkspace.all .list + .list { border-top: 1px solid #d6e9f4; } .entryVariableSplitterWorkspace.all { border-top: none; } .entryVariableSplitterWorkspace.all .list .inpt_box { background-color: #ecf8ff; } .entryVariableSplitterWorkspace.all .list.unfold .inpt_box { background-color: #fff; } .entryVariableSplitterWorkspace .list .inpt .editBoxInput { border: 1px solid #aac5d5; background-color: #f9f9f9; color: #cbcbcb; } .entryVariableSplitterWorkspace .list .inpt input[type='text'] { width: 100%; height: 24px; padding: 6px 8px 5px; border: 1px solid #aac5d5; border-radius: 4px; outline: 0; background-color: #fff; font-size: 12px; font-weight: 600; color: #2c313d; letter-spacing: -0.2px; line-height: 11px; -webkit-box-sizing: border-box; box-sizing: border-box; } .entryVariableSplitterWorkspace .list .inpt span { width: 100%; padding: 6px 8px 5px; font-size: 12px; font-weight: 600; color: #2c313d; letter-spacing: -0.2px; line-height: 11px; -webkit-box-sizing: border-box; box-sizing: border-box; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; display: block; } .entryVariableSplitterWorkspace .list .attr_inner_box { display: none; border-top: 1px solid #aac5d5; padding: 12px 26px 10px 26px; background-color: #bfd8e6; } .entryVariableSplitterWorkspace .list .attr_inner_box .box_sjt { display: block; font-size: 12px; font-weight: 600; color: #2c313d; letter-spacing: -0.4px; vertical-align: top; line-height: 12px; margin-bottom: 9px; } .entryVariableSplitterWorkspace .list .attr_inner_box .box_sjt:before { display: inline-block; width: 4px; height: 4px; border-radius: 50%; margin: 3px 8px 0 0; background-color: #4f80ff; vertical-align: top; content: ''; } .entryVariableSplitterWorkspace .list .attr_inner_box .val_attr .attr_inpt.hidden { display: none; } .entryVariableSplitterWorkspace .list .attr_inner_box .val_attr .slide_inpt .chk_box { position: relative; font-size: 0; cursor: pointer; margin-bottom: 3px; } .entryVariableSplitterWorkspace .list .attr_inner_box .val_attr .slide_inpt .cnt_box { overflow: hidden; font-size: 0; margin-left: 24px; } .entryVariableSplitterWorkspace .list .attr_inner_box .val_attr .slide_inpt .cnt_box .dash { padding: 0 2px; font-size: 10px; font-weight: 600; color: #2c313d; letter-spacing: -0.4px; line-height: 24px; } .entryVariableSplitterWorkspace .list .attr_inner_box .val_attr .slide_inpt .cnt_box input[type='text']:disabled { border: 1px solid #e2e2e2; background-color: #f9f9f9; color: #cbcbcb; } .entryVariableSplitterWorkspace .list .attr_inner_box .use_obj .obj_list .text { display: block; overflow: hidden; text-overflow: ellipsis; height: 33px; font-size: 12px; font-weight: 600; color: #2c313d; letter-spacing: -0.4px; word-break: break-all; white-space: nowrap; line-height: 34px; } .entryVariableSplitterWorkspace .list .attr_inner_box .use_obj .obj_list .text.red { color: #ff4b4b; padding-left: 10px; } .entryVariableSplitterWorkspace .list .attr_inner_box .list_attr.hidden { display: none; } .entryVariableSplitterWorkspace .list .attr_inner_box .list_attr .scroll_box { max-height: 160px; } .entryVariableSplitterWorkspace .list .attr_inner_box .list_attr .scroll_box.on { padding-right: 20px; } .scroll_box:not(.on) .simplebar-vertical { display: none; } .entryVariableSplitterWorkspace .list .attr_inner_box .list_attr .scroll_box .simplebar-scrollbar { opacity: 0.8; } .entryVariableSplitterWorkspace .list .attr_inner_box .list_attr .cnt_list { margin: 0; padding: 0; list-style: none; } .entryVariableSplitterWorkspace .list .attr_inner_box .list_attr .cnt_list li { position: relative; margin: 8px 0 0 0; padding: 0 34px 0 28px; } .entryVariableSplitterWorkspace .list .attr_inner_box .list_attr .cnt_list li:first-child { margin-top: 0; } .entryVariableSplitterWorkspace .list .attr_inner_box .list_attr .cnt_list .del { right: 0; top: 0; } .entryVariableSplitterWorkspace .list .attr_inner_box .list_attr .cnt_list input[type='text'] { width: 100%; padding: 6px 8px 5px; border: 1px solid #e2e2e2; border-radius: 4px; outline: 0; background-color: #fff; font-size: 12px; font-weight: 600; color: #2c313d; letter-spacing: -0.2px; line-height: 11px; -webkit-box-sizing: border-box; box-sizing: border-box; } .obj_list { overflow: hidden; margin: 0; padding: 0; list-style: none; } .entryVariableSplitterWorkspace .list .use_block { display: none; padding: 4px 26px 4px 32px; background-color: #d6e9f4; } .entryVariableSplitterWorkspace .list .use_block .obj_list li { position: relative; -webkit-box-sizing: content-box; box-sizing: content-box; list-style: none; height: 33px; margin: 0; padding: 4px 4px 4px 42px; border-top: 1px solid #aac5d5; } .entryVariableSplitterWorkspace .list .use_block .obj_list li:first-child { border-top: 0; } .entryVariableSplitterWorkspace .list .use_block .obj_list .thmb { overflow: hidden; position: absolute; top: 4px; left: 4px; height: 33px; width: 30px; border: 1px solid #e2e2e2; border-radius: 4px; background-color: #fff; background-size: auto 80%; background-repeat: no-repeat; background-position: center; } .entryVariableSplitterWorkspace .list .use_block .obj_list .text { display: block; overflow: hidden; text-overflow: ellipsis; height: 33px; font-size: 12px; font-weight: 600; color: #2c313d; letter-spacing: -0.4px; word-break: break-all; white-space: nowrap; line-height: 34px; } .entryVariableSplitterWorkspace .list .watch.on { .backgroundImage('layers_icon_visible24.svg'); } .entryVariableSplitterWorkspace .list.default_val .inpt_box:before { .backgroundImage('ic_attr_variable_on.svg'); } .entryVariableSplitterWorkspace .list.cloud_val .inpt_box:before { .backgroundImage('ic_attr_variable_cloud_on.png'); } .entryVariableSplitterWorkspace .list.cloud_val .inpt_box:before { .backgroundImage('ic_attr_variable_real_time_on.png'); } .entryVariableSplitterWorkspace .list.local_val .inpt_box:before { .backgroundImage('ic_attr_variable_local.svg'); } .entryVariableSplitterWorkspace .list.default_list .inpt_box:before { .backgroundImage('ic_attr_list.svg'); } .entryVariableSplitterWorkspace .list.cloud_variable .inpt_box:before { .backgroundImage('ic_attr_variable_cloud.svg'); } .entryVariableSplitterWorkspace .list.cloud_list .inpt_box:before { .backgroundImage('ic_attr_list_cloud.svg'); } .entryVariableSplitterWorkspace .list.real_time_variable .inpt_box:before { .backgroundImage('ic_attr_variable_real_time.svg'); } .entryVariableSplitterWorkspace .list.real_time_list .inpt_box:before { .backgroundImage('ic_attr_list_real_time.svg'); } .entryVariableSplitterWorkspace .list.local_list .inpt_box:before { .backgroundImage('ic_attr_list_local.svg'); } .entryVariableSplitterWorkspace .list.default_message .inpt_box:before { left: 10px; .backgroundImage('ic_attr_message_on.svg'); } .entryVariableSplitterWorkspace.fold .attr_link { cursor: pointer; } .entryVariableSplitterWorkspace.unfold .attr_link { background-color: #fff; cursor: pointer; } .entryVariableSplitterWorkspace .attr_box { display: none; } .entryVariableSplitterWorkspace.unfold .attr_box { display: block; } .entryVariableSplitterWorkspace .list.unfold .attr_inner_box { display: block; } .entryVariableSplitterWorkspace .list.unfold .use_block { display: block; } .entryVariableSplitterWorkspace .list.unfold .caution_dsc { display: block; } .entryVariableSplitterWorkspace .list.unfold .inpt:after { .backgroundImage('layers_arrow_up_nor.png'); } .entryVariableSplitterWorkspace .list.default_func .inpt_box, .entryVariableSplitterWorkspace .list.default_message .inpt_box { padding: 13px 80px 13px 36px; background-color: #ecf8ff; } .entryVariableSplitterWorkspace .list.default_func .inpt:after, .entryVariableSplitterWorkspace .list.default_message .inpt:after { display: none; } .entryVariableSplitterWorkspace .list.default_message.unfold .inpt_box { background-color: #fff; -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.1); } .entryVariableAdd_box .message_inpt input[type='text']:focus, .entryVariableAdd_box .message_inpt input[type='text']:active { border-color: #4f80ff; } .entryVariableAddSpaceNameWrapperWorkspace .entryVariableAddSpaceInputWorkspace:focus, .entryVariableAddSpaceNameWrapperWorkspace .entryVariableAddSpaceInputWorkspace:active { border-color: #4f80ff; } .entryVariableSplitterWorkspace .list .inpt input[type='text']:focus, .entryVariableSplitterWorkspace .list .inpt input[type='text']:active { border-color: #4f80ff; } .entryVariableSplitterWorkspace .list .attr_inner_box .val_attr .attr_inpt input[type='text']:focus, .entryVariableSplitterWorkspace .list .attr_inner_box .val_attr .attr_inpt input[type='text']:active { border-color: #4f80ff; } .entryVariableSplitterWorkspace .list .attr_inner_box .list_attr .cnt_list input[type='text']:focus, .entryVariableSplitterWorkspace .list .attr_inner_box .list_attr .cnt_list input[type='text']:active { border-color: #4f80ff; } .simplebar-scrollbar { right: 4px; width: 8px; &::before { opacity: 1 !important; background-color: #aac5d5; border-radius: 2.5px; } } // .entryVariableSplitterWorkspace .attr_box .list.default_message .inpt_box:before // .entryVariableSplitterWorkspace .attr_box .list>.list .inpt_box:before // .entryVariableSplitterWorkspace .list.default_message .inpt_box .entryVariableAdd_box { .entryVariableAddWorkspace { display: block; overflow: hidden; width: calc(100% - 24px); height: 40px; border: 1px solid #4f80ff; border-radius: 4px; background-color: #fff; font-weight: 600; color: #4f80ff; text-align: center; text-decoration: none; -webkit-box-sizing: border-box; box-sizing: border-box; margin: 12px; font-size: 12px; letter-spacing: -0.28px; line-height: 40px; } } .entryVariableSplitterWorkspace { background-color: #fff; border: 1px solid #d6e9f4; &.message, &.func { border-top: none; } .attr_box { border-top: 1px solid #d6e9f4; .default_message { &.unfold { border-color: #aac5d5; outline: 1px solid #aac5d5; } } } &.list.global.fold, &.variable.global.fold { border-bottom: 1px solid #aac5d5; } &.entryVariableSplitterWorkspace.unfold { .attr_box { border-top: 1px solid #d6e9f4; .list .list { &:first-child { margin-top: 0; } } .default_func, .default_message, .cloud_list, .real_time_list, .default_list, .local_list, .cloud_variable, .real_time_variable, .local_val, .default_val { &.unfold { border-color: #aac5d5; outline: 1px solid #aac5d5; border-top: none; margin-top: 1px; } .inpt_box { &::before { left: 8px; } .watch { margin-left: 2px; margin-right: 8px; } } } } } &.unfold { .attr_link { &::after { width: 24px; height: 24px; border-radius: 0; .backgroundImage('folder_open.svg'); background-color: inherit; background-size: auto; } } } .attr_link { position: relative; display: block; height: 38px; padding: 0 14px 0 12px; font-size: 10px; letter-spacing: -0.4px; font-weight: 600; color: #2c313d; text-decoration: none; word-break: break-all; cursor: default; line-height: 38px; margin-bottom: 1px; &::after { display: inline-block; position: absolute; top: 7px; right: 14px; overflow: hidden; background-color: #4f80ff; content: ''; width: 24px; height: 24px; border-radius: 0; .backgroundImage('folder_close.svg'); background-color: inherit; background-size: auto; } } .attr_box { .list { // > .list { &.fold { input { margin-left: 4px; pointer-events: none; border: none; background: transparent; padding: 0; } } &.unfold { .used_function_dsc, .caution_dsc { background-color: #d6e9f4; font-size: 10px; font-weight: 600; letter-spacing: -0.4px; color: #4d616e; padding-top: 3px; } .inpt_box { &::after { .backgroundImage('layers_arrow_up_nor.svg'); } background-color: #d6e9f4; .arrowDown { .backgroundImage('layers_arrow_up_nor.svg'); } } .attr_inner_box { position: relative; background-color: #d6e9f4; .val_type_txt { position: absolute; top: 15px; right: 20px; font-size: 9px; font-weight: 600; letter-spacing: -0.36px; color: #4d616e; } } } .inpt_box { display: flex; padding: 13px 0; position: relative; -webkit-box-sizing: content-box; box-sizing: content-box; background-color: #f7fcff; align-items: center; &::before { margin-left: 10px; width: 24px; height: 24px; background-size: 24px auto; content: ''; } .watch { margin-left: 4px; width: 18px; height: 18px; font-size: 0; .backgroundImage('layers_icon_unvisible24.svg'); background-size: 18px auto; &.on { .backgroundImage('layers_icon_visible24.svg'); } } .inpt { position: relative; overflow: hidden; height: 24px; flex: 1; margin-right: 20px; input[type='text'], span { font-size: 10px; line-height: 10px; } } .arrowDown { width: 10px; height: 8px; margin-right: 20px; background-size: auto; .backgroundImage('layers_arrow_down_nor.svg'); } .del { margin-right: 20px; width: 20px; height: 20px; background-position: 50%; background-size: auto; .backgroundImage('layers_icon_close_nor_new.svg'); background-color: transparent; background-repeat: no-repeat; cursor: pointer; } } .attr_inner_box { padding: 0; .box_sjt { &::before { width: 3px; height: 3px; background-color: #728997; } position: relative; left: -10px; margin-bottom: 12px; font-size: 11px; font-weight: 600; letter-spacing: -0.44px; } .list_attr { .btn_box { display: flex; .btn_list { flex: 1; display: inline-block; height: 28px; border-radius: 4px; border: 1px solid #aac5d5; background-color: #fff; font-size: 9px; letter-spacing: -0.36px; font-weight: 600; color: #2c313d; text-align: center; line-height: 26px; cursor: pointer; margin-bottom: 12px; & + .btn_list { margin-left: 4px; } } } .list_cnt { .cnt_sjt { font-size: 10px; font-weight: 600; letter-spacing: -0.4px; color: #4d616e; margin-bottom: 6px; } .cnt_inpt { overflow: hidden; position: relative; -webkit-box-sizing: content-box; box-sizing: content-box; width: 78px; height: 24px; border-radius: 4px; border: solid 1px #aac5d5; margin-bottom: 12px; .btn_cnt { display: inline-block; overflow: hidden; width: 24px; height: 24px; background-color: #ecf8ff; border-radius: 4px 0 0 4px; font-size: 24px; color: #2c313d; text-decoration: none; text-align: center; line-height: 24px; &::before { content: ' '; display: inline-block; position: relative; top: -3px; width: 8px; height: 8px; .backgroundImage('btn_minus.svg'); background-position-y: center; background-repeat: no-repeat; } &.plus { &::before { .backgroundImage('btn_plus.svg'); } border-radius: 0 4px 4px 0; } &[disabled] { opacity: 0.5; cursor: not-allowed; } } input[type='text'] { width: 30px; height: 24px; background-color: #fff; outline: 0; font-size: 10px; letter-spacing: -0.4px; color: #2c313d; font-weight: 600; line-height: 14px; text-align: center; vertical-align: top; border: 0; &[disabled] { opacity: 0.5; cursor: not-allowed; } } } } .cnt_group { .cnt_label { font-size: 10px; font-weight: 600; letter-spacing: -0.4px; color: #4d616e; margin-bottom: 5px; } .cnt_list { margin: 0; padding: 0; list-style: none; li { position: relative; margin-top: 4px; padding: 0 32px 0 0; &:first-child { margin-top: 0; } } .cnt { position: absolute; left: 10px; font-size: 10px; font-weight: 600; letter-spacing: -0.4px; color: #979797; line-height: 24px; } .del { right: 0; top: 0; } input[type='text'] { width: 100%; height: 24px; padding-left: 26px; border: 1px solid #aac5d5; border-radius: 4px; outline: 0; background-color: #fff; font-size: 10px; font-weight: 600; letter-spacing: -0.4px; color: #2c313d; line-height: 24px; -webkit-box-sizing: border-box; box-sizing: border-box; } } } } .val_attr, .list_attr { padding: 15px 20px 15px 20px; .attr_inpt { display: block; margin-bottom: 12px; label { display: block; font-size: 10px; font-weight: 600; letter-spacing: -0.4px; color: #4d616e; line-height: 10px; margin-bottom: 5px; } .val_inptbox { display: block; input { width: 100%; padding: 7px 8px 6px; border: 1px solid #aac5d5; border-radius: 4px; background-color: #fff; font-size: 10px; font-weight: bold; font-stretch: normal; font-style: normal; line-height: normal; letter-spacing: -0.4px; color: #2c313d; } } } .slide_inpt { .entryVariableAddSpaceCheckWorkspace { &.on { .backgroundImage('btn_checkbox_on.svg'); } display: inline-block; width: 18px; height: 18px; background-size: 18px auto; .backgroundImage('btn_checkbox.svg'); vertical-align: top; margin-right: 8px; } .chk_text { display: inline-block; font-weight: 600; letter-spacing: -0.4px; vertical-align: top; font-size: 10px; line-height: 18px; letter-spacing: -0.4px; color: #4d616e; } .cnt_box { input { width: 56px; padding: 7px 8px 6px; border: 1px solid #aac5d5; border-radius: 4px; background-color: #fff; font-size: 10px; font-weight: bold; letter-spacing: -0.4px; color: #2c313d; } } } } .use_obj { padding: 15px 14px 12px 20px; .box_sjt { margin-bottom: 8px; } .obj_list { li { position: relative; height: 24px; margin-bottom: 6px; .thmb { position: static; display: inline-block; overflow: hidden; height: 24px; width: 22px; border: 1px solid #aac5d5; border-radius: 4px; background-color: #fff; background-size: auto 80%; background-repeat: no-repeat; background-position: center; margin-right: 8px; vertical-align: top; } .text { display: inline-block; overflow: hidden; text-overflow: ellipsis; color: #4d616e; white-space: nowrap; line-height: 24px; font-size: 10px; font-weight: 600; letter-spacing: -0.4px; } } } } .func_attr { padding: 15px 14px 15px 20px; border-bottom: 1px solid #aac5d5; .box_sjt { &::before { width: 3px; height: 3px; background-color: #728997; } position: relative; left: -10px; margin-bottom: 8px; } .check_inpt { margin: 3px 0 3px; .entryFuncAddLocalVarCheckWorkspace, .entryFuncAddResultCheckWorkspace { display: inline-block; width: 18px; height: 18px; background-size: 18px; vertical-align: top; .backgroundImage('btn_checkbox.svg'); } .entryFuncAddLocalVarCheckWorkspace.on, .entryFuncAddResultCheckWorkspace.on { .backgroundImage('btn_checkbox_on.svg'); } .chk_text { display: inline-block; margin-left: 10px; font-size: 10px; font-weight: bold; letter-spacing: -0.4px; color: #4d616e; line-height: 18px; font-weight: 600; vertical-align: top; } .cnt_inpt { margin: 3px 0 0 28px; overflow: hidden; position: relative; -webkit-box-sizing: content-box; box-sizing: content-box; width: 78px; height: 24px; border-radius: 4px; border: solid 1px #aac5d5; .btn_cnt { display: inline-block; overflow: hidden; width: 24px; height: 24px; background-color: #ecf8ff; border-radius: 4px 0 0 4px; font-size: 24px; color: #2c313d; text-decoration: none; text-align: center; line-height: 24px; &::before { content: ' '; display: inline-block; position: relative; top: -3px; width: 8px; height: 8px; .backgroundImage('btn_minus.svg'); background-position-y: center; background-repeat: no-repeat; } &.plus { &::before { .backgroundImage('btn_plus.svg'); } border-radius: 0 4px 4px 0; } &[disabled] { opacity: 0.5; cursor: not-allowed; } } input[type='text'] { width: 30px; height: 24px; background-color: #fff; outline: 0; font-size: 10px; letter-spacing: -0.4px; color: #2c313d; font-weight: 600; line-height: 14px; text-align: center; vertical-align: top; border: 0; &[disabled] { opacity: 0.5; cursor: not-allowed; } } } } .cnt_group { margin-top: 10px; margin-left: 28px; .cnt_label { font-size: 10px; font-weight: 600; letter-spacing: -0.4px; color: #4d616e; margin-bottom: 5px; } &[disabled] { display: none; } .scroll_box { max-height: 135px; } .scroll_box.on { padding-right: 20px; } .cnt_list { margin: 0; padding: 0; list-style: none; li { position: relative; margin-top: 4px; padding: 0 32px 0 0; &:first-child { margin-top: 0; } } .cnt { position: absolute; left: 10px; font-size: 10px; font-weight: 600; letter-spacing: -0.4px; color: #979797; line-height: 24px; } .del { right: 0; top: 0; } input[type='text'] { width: 100%; height: 24px; padding-left: 20px; border: 1px solid #aac5d5; border-radius: 4px; outline: 0; background-color: #fff; font-size: 10px; font-weight: 600; letter-spacing: -0.4px; color: #2c313d; line-height: 24px; -webkit-box-sizing: border-box; box-sizing: border-box; } } } } .use_obj { padding: 15px 14px 15px 20px; border-top: solid 1px #aac5d5; } } .use_block { padding: 15px 14px 11px 20px; .box_sjt { &::before { content: ''; display: inline-block; border-radius: 50%; margin: 3px 8px 0 0; vertical-align: top; width: 3px; height: 3px; background-color: #728997; } position: relative; left: -10px; margin-bottom: 5px; display: block; font-size: 12px; font-weight: 600; color: #2c313d; letter-spacing: -0.4px; line-height: 12px; } .obj_list { li { padding: 3px 4px 3px 42px; border: none; height: 24px; .thmb { border: solid 1px #aac5d5; width: 22px; height: 24px; } .text { height: 24px; font-size: 10px; line-height: 24px; color: #4d616e; } } } } &.default_message { &.unfold { .inpt_box { -webkit-box-shadow: 0 1px 1px 0 #aac5d5; box-shadow: 0 1px 1px 0 #aac5d5; } } .inpt_box { &::before { left: 10px; .backgroundImage('ic_attr_message.svg'); } } } &.default_val { .inpt_box { &::before { left: 10px; .backgroundImage('ic_attr_variable.svg'); } } } &.real_time_list, &.cloud_list, &.default_list { .cnt_group { .del { position: absolute; width: 22px; height: 22px; right: 6px; top: 0px; display: inline-block; background-position: 50%; .backgroundImage('layers_icon_close_nor_new.svg'); background-color: transparent; background-repeat: no-repeat; background-position: 50%; border: none; cursor: pointer; } } .inpt_box { &::before { left: 10px; } } } &.default_list { .inpt_box { &::before { .backgroundImage('ic_attr_list.svg'); } } } &.default_func { .del { .backgroundImage('layers_icon_close_nor_new.svg'); background-color: transparent; background-repeat: no-repeat; background-position: 50%; border: none; cursor: pointer; } .cnt_group { .del { position: absolute; width: 22px; height: 22px; right: 6px; top: 0px; display: inline-block; } } &.unfold { .caution_dsc { background-color: #d6e9f4; } .inpt_box { &::after { .backgroundImage('layers_arrow_up_nor.svg'); } background-color: #d6e9f4; } .attr_inner_box { background-color: #d6e9f4; } } .inpt_box { &::before { left: 10px; .backgroundImage('ic_attr_func.svg'); } &::after { width: 10px; height: 8px; .backgroundImage('layers_arrow_down_nor.svg'); background-size: auto; background-repeat: no-repeat; } background-color: #f7fcff; .inpt { input[type='text'], span { font-size: 10px; line-height: 10px; } } } .attr_inner_box { padding: 0; .func_attr { padding: 15px 14px 15px 20px; border-bottom: 1px solid #aac5d5; .box_sjt { &::before { width: 3px; height: 3px; background-color: #728997; } position: relative; left: -10px; margin-bottom: 8px; } .check_inpt { margin: 3px 0 3px; .entryFuncAddLocalVarCheckWorkspace, .entryFuncAddResultCheckWorkspace { display: inline-block; width: 18px; height: 18px; background-size: 18px; vertical-align: top; .backgroundImage('btn_checkbox.svg'); } .entryFuncAddLocalVarCheckWorkspace.on, .entryFuncAddResultCheckWorkspace.on { .backgroundImage('btn_checkbox_on.svg'); } .chk_text { display: inline-block; margin-left: 10px; font-size: 10px; font-weight: bold; letter-spacing: -0.4px; color: #4d616e; line-height: 18px; font-weight: 600; vertical-align: top; } .cnt_inpt { margin: 3px 0 0 28px; overflow: hidden; position: relative; -webkit-box-sizing: content-box; box-sizing: content-box; width: 78px; height: 24px; border-radius: 4px; border: solid 1px #aac5d5; .btn_cnt { display: inline-block; overflow: hidden; width: 24px; height: 24px; background-color: #ecf8ff; border-radius: 4px 0 0 4px; font-size: 24px; color: #2c313d; text-decoration: none; text-align: center; line-height: 24px; &::before { content: ' '; display: inline-block; position: relative; top: -3px; width: 8px; height: 8px; .backgroundImage('btn_minus.svg'); background-position-y: center; background-repeat: no-repeat; } &.plus { &::before { .backgroundImage('btn_plus.svg'); } border-radius: 0 4px 4px 0; } &[disabled] { opacity: 0.5; cursor: not-allowed; } } input[type='text'] { width: 30px; height: 24px; background-color: #fff; outline: 0; font-size: 10px; letter-spacing: -0.4px; color: #2c313d; font-weight: 600; line-height: 14px; text-align: center; vertical-align: top; border: 0; &[disabled] { opacity: 0.5; cursor: not-allowed; } } } } .cnt_group { margin-top: 10px; margin-left: 28px; .cnt_label { font-size: 10px; font-weight: 600; letter-spacing: -0.4px; color: #4d616e; margin-bottom: 5px; } &[disabled] { display: none; } .scroll_box { max-height: 135px; } .scroll_box.on { padding-right: 20px; } .cnt_list { margin: 0; padding: 0; list-style: none; li { position: relative; margin-top: 4px; padding: 0 32px 0 0; &:first-child { margin-top: 0; } } .cnt { position: absolute; left: 10px; font-size: 10px; font-weight: 600; letter-spacing: -0.4px; color: #979797; line-height: 24px; } .del { right: 0; top: 0; } input[type='text'] { width: 100%; height: 24px; padding-left: 20px; border: 1px solid #aac5d5; border-radius: 4px; outline: 0; background-color: #fff; font-size: 10px; font-weight: 600; letter-spacing: -0.4px; color: #2c313d; line-height: 24px; -webkit-box-sizing: border-box; box-sizing: border-box; } } } } } .use_block { padding: 15px 14px 11px 20px; .box_sjt { &::before { content: ''; display: inline-block; border-radius: 50%; margin: 3px 8px 0 0; vertical-align: top; width: 3px; height: 3px; background-color: #728997; } position: relative; left: -10px; margin-bottom: 5px; display: block; font-size: 12px; font-weight: 600; color: #2c313d; letter-spacing: -0.4px; line-height: 12px; } .obj_list { li { padding: 3px 4px 3px 42px; border: none; height: 24px; .thmb { border: solid 1px #aac5d5; width: 22px; height: 24px; } .text { height: 24px; font-size: 10px; line-height: 24px; color: #4d616e; } } } } } } } } .entryVariableAdd_box { .entryVariableSplitterWorkspace { .attr_box { .list.unfold { outline: 1px solid #aac5d5; border-color: #aac5d5; } } } .entryVariableAddSpaceWorkspace { border: solid 1px #aac5d5; background-color: #d6e9f4; .entryVariableAddSpaceDataWrapperWorkspace { padding: 18px 20px 0px 20px; } .entryVariableAddSpaceNameWrapperWorkspace { margin-bottom: 6px; } .entryVariableAddSpaceSelectWrapperWorkspace { height: 28px; border: solid 1px #aac5d5; border-radius: 4px; background-color: #fff; white-space: nowrap; margin-bottom: 10px; .button { &.on { color: #4f80ff; border-color: #4f80ff; background-color: #ffffff; } &:nth-child(even) { border-radius: 0 4px 4px 0; margin-left: 2px; } display: inline-block; height: 28px; width: 50%; margin-top: -1px; margin-left: -1px; color: #728997; font-size: 9px; font-weight: 600; text-align: center; line-height: 26px; letter-spacing: -0.36px; vertical-align: top; border: solid 1px transparent; border-radius: 4px 0 0 4px; cursor: pointer; } } .entryVariableTypeBoxWrapper { &.on { display: block; } display: none; margin-bottom: 10px; .entryVariableTypeWrapper { &.on { .radioButton { .backgroundImage('btn_radio_on.svg'); } } color: #4d616e; font-size: 10px; font-weight: 600; line-height: 18px; letter-spacing: -0.4px; vertical-align: top; .radioButton { display: inline-block; width: 18px; height: 18px; vertical-align: top; margin-right: 10px; margin-bottom: 6px; .backgroundImage('btn_radio.svg'); cursor: pointer; } .entryVariableAddSpaceCheckWorkspace { cursor: pointer; } } } .entryVariableAddSpaceButtonWrapperWorkspace { display: flex; overflow: hidden; margin-top: 10px; border-top: 1px solid #aac5d5; font-size: 0; text-align: center; padding: 15px 18px 18px 8px; .entryVariableAddSpaceButtonWorkspace { display: inline-block; flex: 1; height: 32px; color: #2c313d; font-size: 9px; font-weight: 600; letter-spacing: -0.36px; border: 1px solid #aac5d5; border-radius: 4px; background-color: #fff; text-align: center; text-decoration: none; line-height: 30px; margin: 0 2px; cursor: pointer; } .entryVariableAddSpaceConfirmWorkspace { color: #fff; background-color: #4f80ff; border-color: #4f80ff; } } } .message_inpt { border: solid 1px #aac5d5; background-color: #d6e9f4; .msdAddSpaceWrapper { padding: 18px 20px 0 20px; border-top: 1px solid #d6e9f4; margin-bottom: 16px; .box_sjt { &::before { content: ''; display: inline-block; border-radius: 50%; margin: 3px 8px 0 0; vertical-align: top; width: 3px; height: 3px; background-color: #728997; } position: relative; left: -10px; margin-bottom: 8px; display: block; font-size: 11px; font-weight: 600; color: #2c313d; letter-spacing: -0.44px; line-height: 11px; } input { width: 100%; padding: 7px 8px 6px; border: 1px solid #aac5d5; border-radius: 4px; background-color: #fff; color: #2c313d; font-size: 10px; font-weight: 600; letter-spacing: -0.4px; } } .entryVariableAddSpaceButtonWrapperWorkspace { display: flex; overflow: hidden; margin-top: 10px; border-top: 1px solid #aac5d5; font-size: 0; text-align: center; padding: 15px 20px 18px 20px; .entryVariableAddSpaceButtonWorkspace { &.entryVariableAddSpaceConfirmWorkspace { color: #fff; background-color: #4f80ff; border-color: #4f80ff; } display: inline-block; flex: 1; height: 28px; color: #2c313d; font-size: 9px; font-weight: 600; letter-spacing: -0.36px; border: 1px solid #aac5d5; border-radius: 4px; background-color: #fff; text-align: center; text-decoration: none; line-height: 26px; margin: 0 2px; cursor: pointer; } } } } ================================================ FILE: src/css/components/zoomController.less ================================================ @keyframes fadeToast { 0% { opacity: 0; visibility: hidden; transform: translate3d(0, 7px, 0); } 35% { opacity: 1; visibility: visible; transform: none; } 70% { opacity: 1; visibility: visible; transform: none; } 100% { opacity: 0; visibility: hidden; transform: translate3d(0, 7px, 0); } } .fadeToast { animation-duration: 3s; animation-fill-mode: both; animation-name: fadeToast; } .hideToast { visibility: hidden; opacity: 0; } .toastText { font-family: EntryFont, NanumGothic, 'Nanum Gothic'; font-size: 14px; font-weight: bold; font-style: normal; font-stretch: normal; line-height: normal; letter-spacing: -0.5px; text-align: center; } ================================================ FILE: src/css/entry.less ================================================ @import 'prefix.less'; @import 'static.less'; @import 'common.less'; @import 'minimize.less'; @import 'codemirror_theme.less'; @import './components/block.less'; @import './components/block_menu.less'; @import './components/board.less'; @import './components/container.less'; @import './components/context_menu.less'; @import './components/engine.less'; @import './components/function.less'; @import './components/global_svg.less'; @import './components/helper.less'; @import './components/hw_monitor.less'; @import './components/object.less'; @import "./components/painter.less"; @import './components/playground.less'; @import './components/popup.less'; @import './components/property_panel.less'; @import './components/scene.less'; @import './components/stage.less'; @import './components/state_manager.less'; @import './components/table.less'; @import './components/toast.less'; @import './components/variable_container.less'; @import './components/pdf.less'; @import './components/extensions.less'; @import './components/curtain.less'; @import './components/console.less'; @import './components/target_checker.less'; @import './components/textcoding_helper.less'; @import './components/tooltip.less'; @import './components/zoomController.less'; ================================================ FILE: src/css/minimize.less ================================================ .entryMinimizeWrapper { display: flex; justify-content: center; align-items: flex-start; width: 100%; height: 100vh; overflow: hidden; .entry.minimize { display: flex; flex-direction: column; justify-content: center; background: #fff; height: 0; padding-top: 56.25%; #entryCanvas { position: absolute; } .entryEngineMinimize { margin-top: 48px; } } } @media (min-aspect-ratio: 16/9) { .entry.minimize { min-width: calc((100vh - 48px) * 16 / 9); padding-top: calc(100vh - 48px); } } @media (max-aspect-ratio: 16/9) { .entry.minimize { min-width: unset; max-height: 100vw * 9 / 16; width: 100vw; padding-top: calc(100vh + 48px); } } .entryMinimizeWrapper, .entryPopup { .entry.minimize, .entryPopupWindow { #entryCanvasWrapper { background-color: #000; overflow: hidden; width: 100%; } .canvasButton { display: none; box-sizing: border-box; } .entryCanvasWorkspace { width: 100%; } &:empty + .canvasButton { display: none; } & + .canvasButton { display: block; } &.fsView { .entryMaximizeButtonMinimize { .backgroundImage('minimize/reduce.svg'); } } &.fullscreen { .entryRunButtonBigMinimizeCurtain { background-color: unset; } } &:fullscreen { display: block; #entryCanvasWrapper { display: flex; justify-content: center; align-items: center; height: calc(100% - 48px); #entryCanvas { width: 100vw; height: calc(9 / 16 * 100vw); max-height: calc(100vh - 48px); max-width: calc(16 / 9 * (100vh - 48px)); } } .entryRunButtonBigMinimizeCurtain { z-index: 1; } .entryEngineMinimize { position: absolute; bottom: 0; right: 0; left: 0; } } .canvasButton { display: none; } &:empty, .minimize:empty { z-index: 1; background: #ffffff; &::after { position: relative; content: ''; display: block; width: 100%; height: calc(100vh - 2px); background-image: linear-gradient( 90deg, rgba(255, 255, 255, 0) 0, rgba(255, 255, 255, 0.8) 50%, rgba(255, 255, 255, 0) 100% ), linear-gradient(#f2f2f2 calc(100% - 48px), transparent 0), linear-gradient(#f2f2f2 48px, transparent 0), linear-gradient(#f2f2f2 48px, transparent 0), linear-gradient(#f2f2f2 48px, transparent 0), linear-gradient(#f2f2f2 48px, transparent 0); background-size: 200px 100%, 100% 100%, 140px 20px, 99px 20px, 17px 20px, 17px 20px; background-position: -150% bottom, 0px 0px, center bottom 14px, right 92px bottom 14px, right 57px bottom 14px, right 18px bottom 14px; background-repeat: no-repeat; animation: loading 2s infinite; } } .entryRemove { display: none; } .entryRunButtonBigMinimize { .backgroundImage('minimize/play_big.svg'); position: absolute; top: calc(50% - 55px); left: calc(50% - 56px); width: 111px; height: 111px; border: none; background-repeat: no-repeat; background-position: 50% center; cursor: pointer; z-index: 1; background-color: unset; &:hover { opacity: 1; } } .entryRunButtonBigMinimizeCurtain { position: absolute; top: 0%; width: 100%; height: 100%; border: none; background-color: rgba(0, 0, 0, 0.5); cursor: pointer; z-index: 1; } .entryEngineMinimize { height: 48px; box-sizing: border-box; position: relative; background-color: #ffffff; border-top: solid 1px #f2f2f2; padding-left: 30px; .entryEngineButtonMinimize { border: none; background-color: white; position: relative; margin-top: 16px; margin-right: 24px; float: left; outline: none; color: rgb(44, 49, 61); } .entryCoordinateButtonMinimize { .backgroundImage('minimize/grid.svg'); width: 16px; height: 16px; border: 0px; background-color: white; float: right; background-position: 0 0; background-repeat: no-repeat; background-size: 16px; } .entryMaximizeButtonMinimize { .backgroundImage('minimize/fullscreen.svg'); width: 16px; height: 16px; border: 0px; background-color: white; float: right; margin-right: 18px; background-position: 0 0; background-repeat: no-repeat; background-size: 15px; } .entryStopButtonMinimize { padding-left: 28px; background-image: none; &:before { .backgroundImage('minimize/stop.svg'); position: absolute; left: 0px; width: 14px; height: 14px; background-position: 0 0; background-repeat: no-repeat; background-size: 14px auto; content: ''; } } .entryPauseButtonMinimize { padding-left: 30px; &:before { .backgroundImage('minimize/pause.svg'); position: absolute; left: 0px; width: 14px; height: 14px; background-position: 0 0; background-repeat: no-repeat; background-size: 14px auto; content: ''; } } &.paused { .entryPauseButtonMinimize:before { .backgroundImage('minimize/restart.svg'); background-size: 14px 14px; } } } .entryMouseViewMinimize { color: #f2f2f2; font-size: 9pt; margin: 0 auto; width: 40%; line-height: 52px; text-align: center; } .audioShadeCirclebox { position: absolute; margin: 0; padding: 0; background: rgba(255, 255, 255, 0.5); text-align: center; z-index: 10; display: flex; flex-direction: column; -moz-flex-direction: column; width: 100%; height: calc(100% - 32px); } .audioShadeCircle { margin: auto; margin-bottom: 6%; padding: 0; position: relative; display: inline-block; height: 34%; width: auto; aspect-ratio: 1 / 1; border-radius: 50%; background-color: #32d27d; vertical-align: top; } .audioShadeInner { margin: 0; padding: 0; position: absolute; left: 0; right: 0; top: 0; bottom: 0; width: 60%; height: 60%; margin: auto; background-color: #32d27d; border-radius: 50%; transform: scale(0.5); transform-origin: center center; animation: ani 3s linear infinite; content: ''; } .audioShadeInner:nth-of-type(2) { animation-delay: 1s; } .audioShadeInner:nth-of-type(3) { animation-delay: 2s; } .audioShadeInner:nth-of-type(4) { animation-delay: 3s; } .audioShadeImg { margin: 0; padding: 0; position: absolute; left: 23%; top: 23%; width: 54%; height: 54%; z-index: 10; } .audioShadeText { width: 100%; height: 20%; font-family: NanumGothic, 'Nanum Gothic'; font-size: 1.1em; font-weight: bold; font-stretch: normal; font-style: normal; line-height: normal; letter-spacing: normal; text-align: center; } .audioProgress { width: 64%; height: 64%; position: absolute; left: 18%; top: 18%; } } } .entryPopup { .entryPopupWindow { .entryRunButtonBigMinimize { position: absolute; top: 0%; left: 0%; width: 100%; height: calc(100% - 48px); border: none; background-repeat: no-repeat; background-position: 50% center; background-color: rgba(0, 0, 0, 0.5); } } } @keyframes ani { 0% { transform: scale(0.5); opacity: 0; } 50% { opacity: 0.1; } 70% { opacity: 0.09; } 100% { transform: scale(3); opacity: 0; } } @keyframes loading { to { background-position: 200% bottom, 0px 0px, center bottom 14px, right 92px bottom 14px, right 57px bottom 14px, right 18px bottom 14px; } } ================================================ FILE: src/css/prefix.less ================================================ //--------------------------------------------------- // LESS Prefixer //--------------------------------------------------- // // All of the CSS3 fun, none of the prefixes! // // As a rule, you can use the CSS properties you // would expect just by adding a '.': // // box-shadow => .box-shadow(@args) // // Also, when shorthand is available, arguments are // not parameterized. Learn CSS, not LESS Prefixer. // // ------------------------------------------------- // TABLE OF CONTENTS // (*) denotes a syntax-sugar helper // ------------------------------------------------- // // .animation(@args) // .animation-delay(@delay) // .animation-direction(@direction) // .animation-duration(@duration) // .animation-fill-mode(@mode) // .animation-iteration-count(@count) // .animation-name(@name) // .animation-play-state(@state) // .animation-timing-function(@function) // .background-size(@args) // .border-radius(@args) // .box-shadow(@args) // .inner-shadow(@args) * // .box-sizing(@args) // .border-box() * // .content-box() * // .columns(@args) // .column-count(@count) // .column-gap(@gap) // .column-rule(@args) // .column-width(@width) // .gradient(@default,@start,@stop) * // .linear-gradient-top(@default,@color1,@stop1,@color2,@stop2,[@color3,@stop3,@color4,@stop4])* // .linear-gradient-left(@default,@color1,@stop1,@color2,@stop2,[@color3,@stop3,@color4,@stop4])* // .opacity(@factor) // .transform(@args) // .transform-origin(@args) // .transform-style(@style) // .rotate(@deg) // .scale(@factor) // .translate(@x,@y) // .translate3d(@x,@y,@z) // .translateHardware(@x,@y) * // .text-shadow(@args) // .transition(@args) // .transition-delay(@delay) // .transition-duration(@duration) // .transition-property(@property) // .transition-timing-function(@function) // Flexbox: // .flex-block() // .flex-inline() // .flex-flow(@direction: row, @wrap: nowrap) // .flex-direction(@direction: row) // .flex-wrap(@wrap: nowrap) // .justify-content(@justification) // .align-items(@mode) // .align-content(@alignment) // .flex(@args: none) // .flex-grow(@grow: 1) // .flex-shrink(@shrink: 1) // .flex-basis(@basis: auto) // .order(@num: 0) // .align-self(@align: auto) // // Credit to LESS Elements for the motivation and // to CSS3Please.com for implementation. // // Copyright (c) 2012 Joel Sutherland // MIT Licensed: // http://www.opensource.org/licenses/mit-license.php // //--------------------------------------------------- // Animation .animation(@args) { -webkit-animation: @args; -moz-animation: @args; -ms-animation: @args; -o-animation: @args; animation: @args; } .animation-delay(@delay) { -webkit-animation-delay: @delay; -moz-animation-delay: @delay; -ms-animation-delay: @delay; -o-animation-delay: @delay; animation-delay: @delay; } .animation-direction(@direction) { -webkit-animation-direction: @direction; -moz-animation-direction: @direction; -ms-animation-direction: @direction; -o-animation-direction: @direction; } .animation-duration(@duration) { -webkit-animation-duration: @duration; -moz-animation-duration: @duration; -ms-animation-duration: @duration; -o-animation-duration: @duration; } .animation-fill-mode(@mode) { -webkit-animation-fill-mode: @mode; -moz-animation-fill-mode: @mode; -ms-animation-fill-mode: @mode; -o-animation-fill-mode: @mode; animation-fill-mode: @mode; } .animation-iteration-count(@count) { -webkit-animation-iteration-count: @count; -moz-animation-iteration-count: @count; -ms-animation-iteration-count: @count; -o-animation-iteration-count: @count; animation-iteration-count: @count; } .animation-name(@name) { -webkit-animation-name: @name; -moz-animation-name: @name; -ms-animation-name: @name; -o-animation-name: @name; animation-name: @name; } .animation-play-state(@state) { -webkit-animation-play-state: @state; -moz-animation-play-state: @state; -ms-animation-play-state: @state; -o-animation-play-state: @state; animation-play-state: @state; } .animation-timing-function(@function) { -webkit-animation-timing-function: @function; -moz-animation-timing-function: @function; -ms-animation-timing-function: @function; -o-animation-timing-function: @function; animation-timing-function: @function; } // Background Size .background-size(@args) { -webkit-background-size: @args; background-size: @args; } // Border Radius .border-radius(@args) { -webkit-border-radius: @args; border-radius: @args; background-clip: padding-box; } // Box Shadows .box-shadow(@args) { -webkit-box-shadow: @args; box-shadow: @args; } .inner-shadow(@args) { .box-shadow(inset @args); } // Box Sizing .box-sizing(@args) { -webkit-box-sizing: @args; -moz-box-sizing: @args; box-sizing: @args; } .border-box() { .box-sizing(border-box); } .content-box() { .box-sizing(content-box); } // Columns .columns(@args) { -webkit-columns: @args; -moz-columns: @args; columns: @args; } .column-count(@count) { -webkit-column-count: @count; -moz-column-count: @count; column-count: @count; } .column-gap(@gap) { -webkit-column-gap: @gap; -moz-column-gap: @gap; column-gap: @gap; } .column-width(@width) { -webkit-column-width: @width; -moz-column-width: @width; column-width: @width; } .column-rule(@args) { -webkit-column-rule: @args; -moz-column-rule: @args; column-rule: @args; } // Gradients .gradient(@default: #F5F5F5, @start: #EEE, @stop: #FFF) { .linear-gradient-top(@default,@start,0%,@stop,100%); } .linear-gradient-top(@default,@color1,@stop1,@color2,@stop2) { background-color: @default; background-image: -webkit-gradient( linear, left top, left bottom, color-stop(@stop1, @color1), color-stop(@stop2 @color2) ); background-image: -webkit-linear-gradient(top, @color1 @stop1, @color2 @stop2); background-image: -moz-linear-gradient(top, @color1 @stop1, @color2 @stop2); background-image: -ms-linear-gradient(top, @color1 @stop1, @color2 @stop2); background-image: -o-linear-gradient(top, @color1 @stop1, @color2 @stop2); background-image: linear-gradient(top, @color1 @stop1, @color2 @stop2); } .linear-gradient-top(@default,@color1,@stop1,@color2,@stop2,@color3,@stop3) { background-color: @default; background-image: -webkit-gradient( linear, left top, left bottom, color-stop(@stop1, @color1), color-stop(@stop2 @color2), color-stop(@stop3 @color3) ); background-image: -webkit-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3); background-image: -moz-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3); background-image: -ms-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3); background-image: -o-linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3); background-image: linear-gradient(top, @color1 @stop1, @color2 @stop2, @color3 @stop3); } .linear-gradient-top(@default,@color1,@stop1,@color2,@stop2,@color3,@stop3,@color4,@stop4) { background-color: @default; background-image: -webkit-gradient( linear, left top, left bottom, color-stop(@stop1, @color1), color-stop(@stop2 @color2), color-stop(@stop3 @color3), color-stop(@stop4 @color4) ); background-image: -webkit-linear-gradient( top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4 ); background-image: -moz-linear-gradient( top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4 ); background-image: -ms-linear-gradient( top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4 ); background-image: -o-linear-gradient( top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4 ); background-image: linear-gradient( top, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4 ); } .linear-gradient-left(@default,@color1,@stop1,@color2,@stop2) { background-color: @default; background-image: -webkit-gradient( linear, left top, left top, color-stop(@stop1, @color1), color-stop(@stop2 @color2) ); background-image: -webkit-linear-gradient(left, @color1 @stop1, @color2 @stop2); background-image: -moz-linear-gradient(left, @color1 @stop1, @color2 @stop2); background-image: -ms-linear-gradient(left, @color1 @stop1, @color2 @stop2); background-image: -o-linear-gradient(left, @color1 @stop1, @color2 @stop2); background-image: linear-gradient(left, @color1 @stop1, @color2 @stop2); } .linear-gradient-left(@default,@color1,@stop1,@color2,@stop2,@color3,@stop3) { background-color: @default; background-image: -webkit-gradient( linear, left top, left top, color-stop(@stop1, @color1), color-stop(@stop2 @color2), color-stop(@stop3 @color3) ); background-image: -webkit-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3); background-image: -moz-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3); background-image: -ms-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3); background-image: -o-linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3); background-image: linear-gradient(left, @color1 @stop1, @color2 @stop2, @color3 @stop3); } .linear-gradient-left(@default,@color1,@stop1,@color2,@stop2,@color3,@stop3,@color4,@stop4) { background-color: @default; background-image: -webkit-gradient( linear, left top, left top, color-stop(@stop1, @color1), color-stop(@stop2 @color2), color-stop(@stop3 @color3), color-stop(@stop4 @color4) ); background-image: -webkit-linear-gradient( left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4 ); background-image: -moz-linear-gradient( left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4 ); background-image: -ms-linear-gradient( left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4 ); background-image: -o-linear-gradient( left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4 ); background-image: linear-gradient( left, @color1 @stop1, @color2 @stop2, @color3 @stop3, @color4 @stop4 ); } // Opacity .opacity(@factor) { @iefactor: @factor*100; -ms-filter: 'progid:DXImageTransform.Microsoft.Alpha(Opacity=@{iefactor})'; filter: ~'alpha(opacity=(@{iefactor}))'; opacity: @factor; } // Text Shadow .text-shadow(@args) { text-shadow: @args; } // Transforms .transform(@args) { -webkit-transform: @args; -moz-transform: @args; -ms-transform: @args; -o-transform: @args; transform: @args; } .transform-origin(@args) { -webkit-transform-origin: @args; -moz-transform-origin: @args; -ms-transform-origin: @args; -o-transform-origin: @args; transform-origin: @args; } .transform-style(@style) { -webkit-transform-style: @style; -moz-transform-style: @style; -ms-transform-style: @style; -o-transform-style: @style; transform-style: @style; } .rotate(@deg:45deg) { .transform(rotate(@deg)); } .scale(@factor:0.5) { .transform(scale(@factor)); } .translate(@x,@y) { .transform(translate(@x,@y)); } .translate3d(@x,@y,@z) { .transform(translate3d(@x,@y,@z)); } .translateHardware(@x,@y) { .translate(@x,@y); -webkit-transform: translate3d(@x, @y, 0); -moz-transform: translate3d(@x, @y, 0); -o-transform: translate3d(@x, @y, 0); -ms-transform: translate3d(@x, @y, 0); transform: translate3d(@x, @y, 0); } // Transitions .transition(@args:200ms) { -webkit-transition: @args; -moz-transition: @args; -o-transition: @args; -ms-transition: @args; transition: @args; } .transition-delay(@delay:0) { -webkit-transition-delay: @delay; -moz-transition-delay: @delay; -o-transition-delay: @delay; -ms-transition-delay: @delay; transition-delay: @delay; } .transition-duration(@duration:200ms) { -webkit-transition-duration: @duration; -moz-transition-duration: @duration; -o-transition-duration: @duration; -ms-transition-duration: @duration; transition-duration: @duration; } .transition-property(@property:all) { -webkit-transition-property: @property; -moz-transition-property: @property; -o-transition-property: @property; -ms-transition-property: @property; transition-property: @property; } .transition-timing-function(@function:ease) { -webkit-transition-timing-function: @function; -moz-transition-timing-function: @function; -o-transition-timing-function: @function; -ms-transition-timing-function: @function; transition-timing-function: @function; } // Flexbox .flex-block() { display: -ms-flexbox; display: -webkit-flex; display: flex; } .flex-inline() { display: -ms-inline-flexbox; display: -webkit-inline-flex; display: inline-flex; } .flex-flow(@direction: row, @wrap: nowrap) { -moz-flex-flow: @direction @wrap; -ms-flex-direction: @direction; -ms-flex-wrap: @wrap; -webkit-flex-flow: @direction @wrap; flex-flow: @direction @wrap; } .align-content(@alignment) { -moz-align-content: @alignment; -ms-align-content: @alignment; -webkit-align-content: @alignment; align-content: @alignment; } .flex-direction(@direction: row) { -webkit-flex-direction: @direction; -moz-flex-direction: @direction; -ms-flex-direction: @direction; flex-direction: @direction; } .flex-wrap(@wrap: nowrap) { -webkit-flex-wrap: @wrap; -moz-flex-wrap: @wrap; -ms-flex-wrap: @wrap; flex-wrap: @wrap; } .justify-content(@justification) { -webkit-box-pack: @justification; -moz-box-pack: @justification; -ms-flex-pack: @justification; -webkit-justify-content: @justification; justify-content: @justification; } .align-items(@mode) { -webkit-box-align: @mode; -moz-box-align: @mode; -ms-flex-align: @mode; -webkit-align-items: @mode; align-items: @mode; } .flex(@args: none) { -webkit-flex: @args; -moz-flex: @args; -ms-flex: @args; -webkit-flex: @args; flex: @args; } .order(@num: 0) { -webkit-box-ordinal-group: @order; -moz-box-ordinal-group: @order; -ms-box-ordinal-group: @order; -ms-flex-order: @order; -webkit-order: @order; -moz-order: @order; -ms-order: @order; order: @order; } .flex-grow(@grow: 1) { -webkit-flex-grow: @grow; -moz-flex-grow: @grow; -ms-flex-grow: @grow; -webkit-flex-grow: @grow; flex-grow: @grow; } .flex-shrink(@shrink: 1) { -webkit-flex-shrink: @shrink; -moz-flex-shrink: @shrink; -ms-flex-shrink: @shrink; -webkit-flex-shrink: @shrink; flex-shrink: @shrink; } .flex-basis(@basis: auto) { -webkit-flex-basis: @basis; -moz-flex-basis: @basis; -ms-flex-basis: @basis; -webkit-flex-basis: @basis; flex-basis: @basis; } .align-self(@align: auto) { -webkit-align-self: @align; -moz-align-self: @align; -ms-align-self: @align; -webkit-align-self: @align; align-self: @align; } ================================================ FILE: src/css/static.less ================================================ //main bora color @bora: #4b37a0; @parang: #103366; //main haneul color @haneul: #1bafea; //main pink background color @pink: #ffafb6; //common background color @beige: #f9f8f7; //border color @more: #cec5bc; //font colors @yeonbora: #6c5af2; @norang: #ffcf5f; @dahong: #fa5536; @lightGray: #e5e5e5; @grayFont: #9e9e9f; @lightHaneul: #42caf4; @lightBora: #6c5af2; @blueHaneul: #5096f5; //popup colors @titleBack: #2a7def; @stepBack: #f4810f; @exampleBack: #50a0ff; @stepBorder: #e8740c; @viewText: #004051; @viewUnder: #ffae0b; @viewShadow: #ffed08; @viewEmphasis: #f43900; @objectText: #494949; @indicatorOff: #828282; @indicatorOn: #2f50f4; @white: #ffffff; // 개편 color @baseblue: #4f80ff; @baseBluePoint: #3064ec; @basePurple: #8274ff; @basePurplePoint: #5e4dee; ================================================ FILE: src/entry.js ================================================ __webpack_public_path__ = global.PUBLIC_PATH_FOR_ENTRYJS || 'dist/'; import showConsoleBanner from './util/functions/showConsoleBanner'; import 'simplebar/dist/simplebar.css'; const Entry = {}; Entry.EXPANSION_BLOCK = {}; Entry.EXPANSION_BLOCK_LIST = {}; Entry.AI_UTILIZE_BLOCK = {}; Entry.AI_UTILIZE_BLOCK_LIST = {}; Entry.AI_UTILIZE_BLOCK_LIST_DEPRECATED = {}; Entry.ALL_AI_UTILIZE_BLOCK_LIST = {}; module.exports = Entry; global.Entry = Entry; require('./core/collection'); require('./core/db'); require('./core/dom'); require('./core/event'); require('./core/model'); require('./core/observer'); require('./core/svg'); require('core-js/stable/object/values'); require('./graphicEngine/FakePIXI'); require('./css/entry.less'); require('./class/time_wait'); require('./class/container'); require('./class/dialog'); require('./class/doneProject'); require('./class/engine'); require('./class/entity'); require('./class/function'); require('./class/helper'); require('./class/intro'); require('./class/object'); require('./class/painter'); require('./class/LiterallycanvasPainter'); require('./class/pdf'); require('./class/playground'); require('./class/popup'); require('./class/popup_helper'); require('./class/popup_list'); require('./class/hw'); require('./class/hw_lite'); require('./class/entryModuleLoader'); require('./class/project'); require('./class/property_panel'); require('./class/reporter'); require('./class/scene'); require('./class/blockCountViewer'); require('./class/stage'); require('./class/stamp_entity'); require('./class/toast'); require('./class/variable'); require('./class/variable_container'); require('./command/command'); require('./command/commander'); require('./extensions/extension'); require('./extensions/target_checker'); require('./log/activity'); require('./log/activityReporter'); require('./log/recorder'); require('./log/state'); require('./log/state_manager'); require('./model/block_model'); require('./model/block_render_model'); require('./model/box_model'); require('./model/drag_instance'); require('./model/thread_model'); require('./parser-no/block'); require('./parser-no/js'); require('./parser-no/parser'); require('./playground/block'); require('./playground/block_entry'); require('./playground/block_menu'); require('./playground/block_menu_scroll'); require('./playground/block_view'); require('./playground/comment'); require('./playground/board'); require('./playground/code'); require('./playground/code_view'); require('./playground/connection_ripple'); require('./playground/executors'); require('./playground/scope'); require('./playground/globalSvg'); require('./playground/mutator'); require('./playground/renderView'); require('./playground/scroll'); require('./playground/skeleton'); require('./playground/skinner'); require('./playground/thread'); require('./playground/thread_view'); require('./playground/trashcan'); require('./playground/zoom_controller'); require('./playground/vim'); require('./playground/workspace'); require('./textcoding/parser'); require('./util/block_driver'); require('./util/contextmenu'); require('./util/curtain'); require('./util/fuzzy'); require('./util/init'); require('./util/loader'); require('./util/restrictor'); require('./util/static'); require('./util/tooltip'); require('./util/tvCast'); require('./util/virtualScroll'); require('./util/htmlElementPatcher'); require('./util/eventHandler'); require('./util/utils'); require('./util/youtube'); require('./util/modal'); require('./command/commands/block'); require('./command/commands/comment'); require('./command/commands/container'); require('./command/commands/dataTable'); require('./command/commands/engine'); require('./command/commands/function'); require('./command/commands/object'); require('./command/commands/painter'); require('./command/commands/playground'); require('./command/commands/textbox'); require('./command/commands/variableContainer'); require('./command/commands/scene'); require('./playground/extension/extension'); require('./playground/extension/guide'); require('./playground/extension/side_tag'); require('./playground/field/field'); require('./playground/field/angle'); require('./playground/field/block'); require('./playground/field/color'); require('./playground/field/led'); require('./playground/field/led2'); require('./playground/field/musicScale'); require('./playground/field/dropdown'); require('./playground/field/dropdownDynamic'); require('./playground/field/dropdownExtra'); require('./playground/field/image'); require('./playground/field/indicator'); require('./playground/field/keyboardInput'); require('./playground/field/lineBreak'); require('./playground/field/output'); require('./playground/field/statement'); require('./playground/field/text'); require('./playground/field/textDynamic'); require('./playground/field/textInput'); require('./textcoding/ast/jsAstGenerator'); require('./textcoding/ast/pyAstGenerator'); require('./textcoding/data_processing/map'); require('./textcoding/data_processing/queue'); require('./textcoding/error/textCodingError'); require('./textcoding/hint/python'); require('./textcoding/static/codeMap'); require('./textcoding/static/keyboardCode'); require('./textcoding/util/console'); require('./textcoding/util/textCodingUtil'); window.Entry = Entry; showConsoleBanner(); ================================================ FILE: src/extensions/CloudVariable.js ================================================ import io from 'socket.io-client'; import { dmet, dmetList, dmetTable, dmetVariable } from './dmet'; import singleInstance from '../core/singleInstance'; class CloudVariableExtension { #cvSocket = null; #data = null; #defaultData = null; get data() { return this.#data; } setServerInfo(cvServer) { this.cvServer = cvServer; } disable(target) { if (!this.#cvSocket) { return; } this.#cvSocket.emit('changeMode', 'offline', target); } enable(target) { if (!this.#cvSocket) { return; } this.#cvSocket.emit('changeMode', 'online', target); } async connect(cvServer) { if (this.#cvSocket || !this.cvServer) { return; } const { url, query, type } = this.cvServer; const socket = io(url, { path: '/cv', query: { type, q: query, }, transports: ['websocket'], reconnectionAttempts: 2, timeout: 5000, }); socket.on('action', this.#execDmet.bind(this)); socket.on('create', this.#createVariable.bind(this)); socket.on('reset', (variables) => { try { this.#data = new dmet(variables); } catch (e) { console.warn(e); } }); this.#cvSocket = socket; return new Promise((resolve) => { socket.on('connect_error', () => { console.log('connect_error'); if (!this.#data) { try { this.#data = new dmet(this.#defaultData); } catch (e) { console.warn(e); } resolve(); } }); socket.on('check', (id) => { socket.emit('imAlive', id); }); socket.on('welcome', ({ variables = [], isOffline }) => { try { this.#data = new dmet(variables); variables.forEach(this.#applyValue); } catch (e) { console.warn(e); } if (isOffline) { socket.close(); } resolve(); }); socket.on('disconnect', (reason) => { console.log('disconnect', reason); if (!this.#data) { this.#data = new dmet(this.#defaultData); } resolve(); }); socket.on('changeMode', (mode, target) => { const isOffline = mode === 'offline'; if (isOffline) { socket.close(); } resolve(); }); }); } setDefaultData(defaultData) { this.#defaultData = defaultData; defaultData.forEach(this.#applyValue); } createDmet(object) { this.#data.create(object); } async create(data) { if (!this.#cvSocket) { await this.connect(); } const { id_, type, name } = data; if (type === 'variable') { await this.#createVariable(name, id_); } else if (type === 'list') { await this.#createList(name, id_); } else if (type === 'table') { await this.#createTable(name, id_); } // Entry.dispatchEvent('saveVariable'); } #createVariable(name, id) { if (!this.#cvSocket) { return; } const variable = new dmetVariable( { name, }, id ); return new Promise((resolve) => { this.#cvSocket.emit('create', variable, (isCreate, variable) => { if (isCreate) { this.createDmet(variable); } resolve(); }); }); } #createList(name, id) { if (!this.#cvSocket) { return; } const list = new dmetList( { name, }, id ); return new Promise((resolve) => { this.#cvSocket.emit('create', list, (isCreate, list) => { if (isCreate) { this.createDmet(list); } resolve(); }); }); } #createTable(name, id) { if (!this.#cvSocket) { return; } const table = new dmetTable( { name, }, id ); return new Promise((resolve) => { this.#cvSocket.emit('create', table, (isCreate, table) => { if (isCreate) { this.createDmet(table); } resolve(); }); }); } #run(operation) { return new Promise((resolve) => { if (this.#cvSocket.connected) { this.#cvSocket.emit('action', operation, (isUpdate, operation) => { if (isUpdate) { this.#data.exec(operation); resolve(operation); } else { resolve(); } }); } else { this.#data.exec(operation); resolve(operation); } }).then((operation) => { if (operation) { this.#applyValue(operation); } }); } #execDmet(operation) { this.#data.exec(operation); this.#applyValue(operation); } #applyValue(operation) { const { id, value, data, variableType } = operation; if (variableType === 'variable' || variableType === 'slide') { const variable = Entry.variableContainer.getVariable(id); if (variable) { variable.value_ = value; variable._valueWidth = null; variable.updateView(); } } else if (variableType === 'list') { const list = Entry.variableContainer.getList(id); if (!list) { return; } if (this && this.get) { const { array } = this.get(operation); list.array_ = array; } else if (operation.array) { list.array_ = operation.array; } else if (operation.list) { list.array_ = operation.list.map((key) => ({ data: operation.value[key] })); } list.updateView(); } } set(target, value) { if (!this.#cvSocket) { return; } const variable = this.#data && this.#data.get(target); if (!variable) { return; } const operation = variable.getOperation({ type: 'set', value, }); return this.#run(operation); } get(target) { return this.#data && this.#data.get(target); } // 워크스페이스에서만 동작하는 함수이기 때문에 run 생략 setArray(target, array) { const dmetList = this.#data && this.#data.get(target); if (!dmetList) { console.error('no target ', target); } dmetList.from(array.map(({ data }) => data)); } append(target, data) { if (!this.#cvSocket) { return; } const variable = this?.#data?.get(target); if (!variable) { return; } const operation = variable.getOperation({ type: 'append', data, }); return this.#run(operation); } insert(target, index, data) { if (!this.#cvSocket) { return; } const variable = this.#data.get(target); if (!variable) { return; } const operation = variable.getOperation({ type: 'insert', index, data, }); return this.#run(operation); } delete(target, index) { if (!this.#cvSocket) { return; } const variable = this.#data.get(target); if (!variable) { return; } const operation = variable.getOperation({ type: 'delete', index, }); return this.#run(operation); } replace(target, index, data) { if (!this.#cvSocket) { return; } const variable = this.#data.get(target); if (!variable) { return; } const operation = variable.getOperation({ type: 'replace', index, data, }); return this.#run(operation); } } export default singleInstance(CloudVariableExtension); ================================================ FILE: src/extensions/dmet.js ================================================ import isPlainObject from 'lodash/isPlainObject'; import _mapValues from 'lodash/mapValues'; import _get from 'lodash/get'; import _cloneDeep from 'lodash/cloneDeep'; import CommonUtils, { toNumber } from '../util/common'; class dmetTable { constructor(array = [], id) { this.#id = id; this.from(array); } _id = undefined; __isUpdate = false; #id = ''; #key = CommonUtils.generateId(); #object = {}; #array = []; #origin = []; #fields = []; #originFields = []; #info = {}; #maxRow = 3000; #maxCol = 100; #variableType = 'table'; #keyDelimter = '_'; get fields() { return this.#fields; } get originFields() { return this.#originFields; } get value() { return this.#object; } get array() { return this.#array; } get isDmet() { return true; } get variableType() { return this.#variableType; } get origin() { return this.#origin; } setLabel(index, name) { this.#fields[index] = name; } #fillArray(array, length) { const start = array.length; array.length = length; array.fill(0, start, length); } from(data) { const { list = [], data: array = [], value, _id, id = this.#id, fields = [], ...info } = data; this.#object = {}; this.#array = []; this.#origin = []; if (Array.isArray(array)) { array.forEach((row = []) => { if (Array.isArray(row)) { const key = CommonUtils.generateId(); const value = row.map(toNumber); this.#fillArray(value, fields.length); this.#array.push({ key, value }); this.#object[key] = value; this.#origin.push(_cloneDeep(row)); } else if (typeof row === 'object' && row.key) { const newRow = { key: row.key, value: row.value.map(toNumber), }; this.#array.push(newRow); this.#object[row.key] = newRow.value; this.#origin.push(_cloneDeep(row.value)); } }); } this._id = _id; this.#id = id; this.#fields = fields; this.#originFields = [...fields]; this.#info = info; } toJSON() { return { _id: this._id || undefined, id: this.#id, key: this.#key, data: this.#array, origin: this.#origin, fields: this.#fields, isDmet: true, variableType: this.variableType, }; } getRow(key) { if (Array.isArray(key)) { const [row, col = 0] = key; const result = this.#array[row - 1] || {}; return { ...result, x: row - 1, y: col - 1 }; } else if (typeof key === 'number') { const result = this.#array[key - 1] || {}; return { ...result, x: key - 1 }; } else if (typeof key === 'string') { const [rowKey, col = 0] = key.split(this.#keyDelimter); return { key: rowKey, value: this.#object[rowKey], x: this.getIndex(rowKey), y: col - 1, }; } throw { message: `not found tableData ${key} id: ${this.#id}` }; } getValue(key) { if (typeof key === 'number') { return this.#array[key - 1].value; } else if (Array.isArray(key)) { const [rowKey, ...keys] = key; let { value: row } = this.#array[rowKey - 1] || {}; if (rowKey === 0) { row = this.#fields; } if (keys.length && row) { return _get(row, `[${keys.map((x) => x - 1).join('][')}]`); } else { return row; } } else if (typeof key === 'string') { const [rowKey, ...keys] = key.split(this.#keyDelimter); if (keys.length) { return _get(this.#object[rowKey], `[${keys.map((x) => x - 1).join('][')}]`); } return this.#object[rowKey]; } throw { message: `not found tableData ${key} id: ${this.#id}` }; } getIndex(key) { if (Array.isArray(key)) { return key; } else if (typeof key === 'string') { const [rowKey, ...keys] = key.split(this.#keyDelimter); const rowIndex = this.#array.findIndex((x) => x.key === rowKey); if (rowIndex >= 0) { return [rowIndex, ...keys]; } } return []; } #skipOperation = ['appendRow', 'appendCol', 'insertRow', 'insertCol']; getOperation({ type, key, index, data, newKey } = {}) { if (this.#skipOperation.indexOf(type) === -1 && typeof index === 'number') { const data = this.getRow(index); key = data.key; } let attach = {}; switch (type) { case 'appendRow': case 'appendCol': case 'insertRow': case 'insertCol': attach = { index, data, }; break; case 'deleteCol': case 'deleteRow': attach = { index }; break; case 'replace': attach = { data, index, newKey, }; break; } return { _id: this._id || undefined, id: this.#id, variableType: this.variableType, key, type, ...attach, }; } exec(operation) { const { type } = operation; this.__isUpdate = true; switch (type) { case 'appendCol': return this.#appendCol(operation); case 'appendRow': return this.#appendRow(operation); case 'insertRow': return this.#insertRow(operation); case 'insertCol': return this.#insertCol(operation); case 'deleteCol': return this.#deleteCol(operation); case 'deleteRow': return this.#deleteRow(operation); case 'replace': return this.#replace(operation); } } #getDefaultData(isRow = true) { if (isRow) { return new Array(this.fields.length).fill(0); } return new Array(this.#array.length).fill(0); } #getNewColName() { return Entry.getOrderedName( Lang.DataAnalytics.new_attribute, this.fields.map((name) => ({ name })), 'name' ); } #appendCol({ index, data = this.#getDefaultData(false) } = {}) { this.fields.push(this.#getNewColName()); this.#array.forEach(({ value }, idx) => { value.push(0); }); return this.getOperation({ type: 'appendCol', index, data }); } #insertCol({ index, data = this.#getDefaultData(false) } = {}) { if (index < 1 || index > this.fields.length + 1) { throw { message: `error: insertCol ${index}` }; } this.fields.splice(index - 1, 0, this.#getNewColName()); this.#array.forEach(({ value }, idx) => { value.splice(index - 1, 0, 0); }); return this.getOperation({ type: 'insertCol', index, data }); } #deleteCol({ index }) { if (!index) { throw { message: `error: deleteCol : ${index}` }; } this.fields.splice(index - 1, 1); this.#array.forEach(({ value }, idx) => { value.splice(index - 1, 1); }); return this.getOperation({ type: 'deleteCol', index }); } #appendRow({ key = CommonUtils.generateId(), data = this.#getDefaultData() } = {}) { const index = this.#array.length + 1; if (Array.isArray(data)) { this.#object[key] = data; this.#array.splice(index, 0, { key, value: data }); } else { console.warn('appendRow : ', key, data); } return this.getOperation({ type: 'appendRow', key, index, data }); } #insertRow({ key = CommonUtils.generateId(), index, data = this.#getDefaultData() } = {}) { const value = toNumber(data); if (Array.isArray(data) || index > this.#array.length + 1 || index < 0) { if (index === 0) { const fields = [...data]; data = [...this.#fields]; this.#fields = fields; index = 1; } this.#object[key] = Array.isArray(data) ? data : [value]; this.#array.splice(index - 1, 0, { key, value: this.#object[key] }); } else { console.warn('insert row : ', key, data, index); } return this.getOperation({ type: 'insertRow', key, index, data: value }); } #deleteRow({ key, index }) { if (index === 0) { index = 1; const { value: row } = this.getRow(index); this.#fields = [...row]; } if (!key) { key = index; } const { value: row, key: objKey, x, y } = this.getRow(key); if (!row || (y > -1 && !row[y])) { throw { message: 'not found data' }; } if (y > -1) { delete row[y]; } else { delete this.#object[objKey]; this.#array.splice(x, 1); } return this.getOperation({ type: 'deleteRow', key }); } #replace({ key, index, data, newKey = CommonUtils.generateId() }) { const value = toNumber(data); if (!key) { key = index; } const { value: row, key: objKey, x, y } = this.getRow(key); if (x === -1) { this.#fields[y] = value; } else { if (!row) { throw { message: `not found row ${y}` }; } row[y] = value; } return this.getOperation({ type: 'replace', key, index, data: value, newKey }); } } class dmetList { constructor(array = [], id) { this.#id = id; this.from(array); } _id = undefined; __isUpdate = false; #id = ''; #key = CommonUtils.generateId(); #object = {}; #array = []; #info = {}; #variableType = 'list'; get value() { return this.#array; } get array() { return this.#array; } get isDmet() { return true; } get id() { return this.#id; } get key() { return this.#key; } get variableType() { return this.#variableType; } set #data(array) { this.#array = array.map((data) => { const key = CommonUtils.generateId(); const item = { key, data, }; this.#object[key] = item; return item; }); } from(data) { if (Array.isArray(data)) { this.#data = data; } else if (data.isDmet || isPlainObject(data)) { const { list = [], array = [], value, _id, id = this.#id, ...info } = data; if (data.array && Array.isArray(array)) { this.#array = array; this.#array.map((value) => { const { key, _key } = value; this.#object[key || _key] = value; }); } else if (Array.isArray(list) && isPlainObject(value)) { this.#array = list.map((key) => { const data = { key, data: value[key], }; this.#object[key] = data; return data; }); } else { this.#array = []; this.#object = {}; } this._id = _id; this.#id = id; this.#info = info; } else if ('toJSON' in data) { const plainObject = data.toJSON(); const { array = [], _id, id = this.#id, ...info } = plainObject; this.#array = array; this._id = _id; this.#id = id; this.#info = info; this.#array.map((value) => { const { key, _key } = value; this.#object[key || _key] = value; }); } else { throw 'data is wrong.'; } } get(key) { if (typeof key === 'number') { return this.#array[key]; } else if (typeof key === 'string') { return this.#object[key]; } } getIndex(key) { if (typeof key === 'number') { return key; } else if (typeof key === 'string') { const oldData = this.#object[key]; return this.#array.indexOf(oldData); } else { return 0; } } #skipOperation = ['append', 'insert']; getOperation({ type, key, index, data, newKey } = {}) { if (this.#skipOperation.indexOf(type) === -1 && typeof index === 'number') { const data = this.get(index); key = data.key; } let attach = {}; switch (type) { case 'append': attach = { data, }; break; case 'insert': attach = { index, data, }; break; case 'delete': attach = { index }; break; case 'replace': attach = { data, newKey, }; break; } return { _id: this._id || undefined, id: this.#id, variableType: this.variableType, key, type, ...attach, }; } exec(operation) { const { type } = operation; this.__isUpdate = true; switch (type) { case 'append': return this.#append(operation); case 'insert': return this.#insert(operation); case 'delete': return this.#delete(operation); case 'replace': return this.#replace(operation); } } toJSON() { return { _id: this._id || undefined, id: this.#id, key: this.#key, array: this.#array, isDmet: true, variableType: this.variableType, }; } #append({ key, data } = {}) { if (!key) { key = CommonUtils.generateId(); } const newData = { key, data, }; this.#object[key] = newData; this.#array.push(newData); return this.getOperation({ type: 'append', key, index: -1, data }); } #insert({ key, index, data } = {}) { if (!key) { key = CommonUtils.generateId(); } const newData = { key, data, }; this.#object[key] = newData; this.#array.splice(index, 0, newData); return this.getOperation({ type: 'insert', key, index, data }); } #delete({ key, index }) { try { if (!key) { key = index; } const oldData = this.get(key); if (!oldData) { throw { message: 'not found data' }; } const oldIndex = this.getIndex(key); delete this.#object[oldData.key]; this.#array.splice(oldIndex, 1); return this.getOperation({ type: 'delete', key }); } catch (e) {} } #replace({ key, data, newKey = CommonUtils.generateId() }) { try { const item = this.get(key); if (!item) { throw { message: 'not found data' }; } delete this.#object[item.key]; item.key = newKey; item.data = data; this.#object[newKey] = item; return this.getOperation({ type: 'replace', key, data, newKey }); } catch (e) {} } } class dmetVariable { constructor(variable = '', id) { this.#id = id; this.from(variable); } _id = undefined; #id = ''; #key = CommonUtils.generateId(); #info = {}; #value = ''; #variableType = 'variable'; get value() { return this.#value; } get id() { return this.#id; } get key() { return this.#key; } get variableType() { return this.#variableType; } toJSON() { return { ...this.#info, _id: this._id || undefined, id: this.#id, key: this.#key, value: this.value, isDmet: true, variableType: this.variableType, }; } from(data) { if (typeof data === 'string') { this.#value = data; } else if (data.isDmet || isPlainObject(data)) { const { value = '', _id, id = this.#id, ...info } = data; this.#value = value; this._id = _id; this.#id = id; this.#info = info; } else if ('toJSON' in data) { const plainObject = data.toJSON(); const { value = '', _id, id = this.#id, ...info } = plainObject; this.#value = value; this._id = _id; this.#id = id; this.#info = info; } else { throw 'data is wrong.'; } } get() { return this.#value; } #set(operation) { const { value } = operation; this.#value = value; return operation; } getOperation({ type, value } = {}) { switch (type) { case 'set': return { _id: this._id, id: this.#id, variableType: this.variableType, type, value, }; } } exec(operation) { const { type } = operation; switch (type) { case 'set': return this.#set(operation); } } } class dmetSlideVariable extends dmetVariable { constructor(variable, id) { variable.variableType = 'slide'; super(variable, id); } } class dmet { constructor(variables, options) { this.from(variables, options); } #original = { list: {}, variable: {} }; #id = CommonUtils.generateId(); #list = {}; #variable = {}; #table = {}; get list() { return this.#list; } get variable() { return this.#variable; } get table() { return this.#table; } get id() { return this.#id; } get isDmet() { return true; } get original() { return this.#original; } #objectToJSON(object) { for (const key in object) { object[key] = object[key].toJSON(); } return object; } toJSON() { return { id: this.#id, list: this.list, table: this.table, variable: this.variable, isDmet: true, }; } from(variables = []) { if (Array.isArray(variables)) { variables.forEach((variable) => { const { variableType } = variable; if (variableType === 'variable') { const result = new dmetVariable(variable); this.#variable[result.id] = result; } else if (variableType === 'slide') { const result = new dmetSlideVariable(variable); this.#variable[result.id] = result; } else if (variableType === 'list') { const result = new dmetList(variable); this.#list[result.id] = result; } else if (variableType === 'table') { const result = new dmetTable(variable); this.#table[result.id] = result; } }); } else if (isPlainObject(variables) && variables.isDmet) { this.#list = _mapValues(variables.list, (list) => new dmetList(list)); this.#variable = _mapValues( variables.variable, (variable) => new dmetVariable(variable) ); this.#table = _mapValues(variables.table, (list) => new dmetTable(list)); this.#id = variables.id; } } get({ variableType, id }) { switch (variableType) { case 'variable': return this.#variable[id]; case 'slide': return this.#variable[id]; case 'list': return this.#list[id]; case 'table': return this.#table[id]; case 'default': return undefined; } } create(object) { const { id, variableType } = object; if (!id) { throw 'not found ID'; } if (variableType === 'variable') { this.#variable[id] = new dmetVariable(object); } else if (variableType === 'slide') { this.#variable[id] = new dmetSlideVariable(object); } else if (variableType === 'list') { this.#list[id] = new dmetList(object); } else if (variableType === 'table') { this.#table[id] = new dmetTable(object); } } #subscriber = new Map(); subscribe(key, callback) { this.#subscriber.set(key, callback); } unsubscribe(key) { this.#subscriber.delete(key, callback); } notify(...args) { for (const observer of this.#subscriber.values()) { observer(...args); } } exec(operation) { try { const { id, variableType } = operation; if (variableType === 'variable') { return this.#variable[id].exec(operation); } else if (variableType === 'slide') { return this.#variable[id].exec(operation); } else if (variableType === 'list') { return this.#list[id].exec(operation); } else if (variableType === 'table') { return this.#table[id].exec(operation); } } finally { this.notify(); } } } export { dmetList, dmetVariable, dmet, dmetTable }; ================================================ FILE: src/extensions/dropper.js ================================================ import singleInstance from '../core/singleInstance'; import { Dropper } from '@entrylabs/tool'; class DropperExtension { #view = null; #dropper = null; constructor() { return this.#createView(); } #createView() { this.#view = Entry.Dom('div', { class: 'entryDropper', parent: $('.entryExtension'), }); this.#dropper = new Dropper({ isShow: false, container: this.#view[0], }); return this.#dropper; } } export default singleInstance(DropperExtension); ================================================ FILE: src/extensions/extension.js ================================================ import Dropper from './dropper'; export default class Extension { #view = null; constructor() { this.renderView(); } renderView() { if (!this.#view) { this.#view = Entry.Dom('div', { class: 'entryExtension', parent: $('body'), }); } } static getExtension(key) { switch (key) { case 'Dropper': return Dropper.getInstance(); } } } ================================================ FILE: src/extensions/target_checker.js ================================================ /** * @fileoverview TargetChecker for courseware. */ 'use strict'; require("../util/utils") require("../extensions/extension") /** * @constructor */ Entry.TargetChecker = function(code, isForEdit, type) { this.isForEdit = isForEdit; this.goals = []; this.publicGoals = []; this.unachievedGoals = []; this.listener = {}; this.remainPublicGoal = 0; this.lastMessage = ""; if (this.isForEdit) { this.watchingBlocks = []; Entry.playground.mainWorkspace.blockMenu.unbanClass("checker"); Entry.addEventListener("run", this.reRegisterAll.bind(this)); } this.type = type || "mission"; this.isFail = false; this.isSuccess = false; this.entity = this; this.parent = this; Entry.achieveEvent = new Entry.Event(); Entry.addEventListener("stop", this.reset.bind(this)); Entry.registerAchievement = this.registerAchievement.bind(this); this.script = new Entry.Code(code ? code : [], this); Entry.targetChecker = this; }; (function(p) { p.renderView = function() { this._view = Entry.Dom('li', { class: "targetChecker" }); this._view.bindOnClick(function(e) { Entry.playground.injectObject(this); }.bind(this)); this.updateView(); if (!this.isForEdit) this._view.addClass("entryRemove"); return this._view; }; p.generateStatusView = function(isForIframe) { if(this.statusViewDisabled) { return ; } this._statusView = Entry.Dom('div', { class: "entryTargetStatus" }); var innerWrapper = Entry.Dom('div', { class: "innerWrapper", parent: this._statusView }); this._statusViewIndicator = Entry.Dom('div', { class: "statusIndicator", parent: innerWrapper }); var statusViewContentWrapper = Entry.Dom('div', { class: "statusMessage", parent: innerWrapper }); this._statusViewContent = Entry.Dom('p', { parent: statusViewContentWrapper }); if (isForIframe) { $(Entry.view_).addClass("iframeWithTargetStatus") Entry.view_.appendChild(this._statusView[0]); } this.updateView(); this.showDefaultMessage(); }; p.updateView = function() { if (this._view) { this.renderViewMessage(); if (this.isSuccess) this._view.addClass("success"); else this._view.removeClass("success"); if (this.isFail) this._view.addClass("fail"); else this._view.removeClass("fail"); } if (this._statusView) { this.renderIndicatorMessage(); } }; p.getStatusView = function() { if (!this._statusView) this.generateStatusView(); return this._statusView; } p.showStatusMessage = function(message) { this.lastMessage = message; this.lastIndicatorMessage = null; this.renderIndicatorMessage(); if (this._statusViewContent && !this.isFail) this._statusViewContent.text(message); this.renderViewMessage(); }; p.achieveCheck = function(isSuccess, id) { if (this.isFail || !Entry.engine.achieveEnabled) return; if (isSuccess) this.achieveGoal(id); else this.fail(id); }; p.achieveGoal = function(id) { if (this.isSuccess || this.isFail || this.unachievedGoals.indexOf(id) < 0) return; this.unachievedGoals.splice(this.unachievedGoals.indexOf(id), 1); if (this.publicGoals.indexOf(id) > -1) this.remainPublicGoal--; if (this.remainPublicGoal === 0) { this.isSuccess = true; this.showSuccessMessage(); Entry.achieveEvent.notify("success", id); } this.updateView() }; p.fail = function(id) { if (this.isSuccess || this.isFail) return; this.showStatusMessage(id); this.isFail = true; Entry.achieveEvent.notify("fail", id); this.updateView(); }; p.reset = function() { this.unachievedGoals = this.goals.concat(); this.remainPublicGoal = this.publicGoals.length; this.isFail = false; this.isSuccess = false; this.updateView(); this.showDefaultMessage(); }; p.showDefaultMessage = function() { switch(this.type) { case "mission": this.showStatusMessage("작품을 실행 해봅시다."); break; case "mission_intro": this.showStatusMessage("작품을 실행하며 미션을 파악해 봅시다."); this.renderIndicatorMessage("미션"); break; case "guide_intro": this.showStatusMessage("작품을 실행하며 무엇을 만들지 알아 봅시다."); this.renderIndicatorMessage("안내"); break; } }; p.showSuccessMessage = function() { switch(this.type) { case "mission": break; case "mission_intro": this.showStatusMessage("이제 작품을 만들며 미션을 해결해 봅시다."); this.renderIndicatorMessage("미션"); break; case "guide_intro": this.showStatusMessage("이제 학습을 시작해 봅시다."); this.renderIndicatorMessage("안내"); break; } }; p.checkGoal = function(goalName) { return this.goals.indexOf(goalName) > -1 && this.unachievedGoals.indexOf(goalName) < 0; }; p.registerAchievement = function(originBlock) { const block = $.extend(true, {}, originBlock); block.params = originBlock.params.map(p => p instanceof Entry.Block ? p.data.params[0] : p); if (this.isForEdit) this.watchingBlocks.push(block); if (block.params[1] && this.goals.indexOf(block.params[0] + "") < 0) { this.goals.push(block.params[0] + ""); if (block.params[2]) this.publicGoals.push(block.params[0] + ""); this.remainPublicGoal = this.publicGoals.length; } this.reset(); }; p.reRegisterAll = function() { const blocks = this.script.getBlockList(false, 'check_lecture_goal').map(originBlock => { const block = $.extend(true, {}, originBlock); block.params = originBlock.params.map(p => p instanceof Entry.Block ? p.data.params[0] : p); return block; }); this.watchingBlocks = blocks; this.goals = _.uniq( blocks.filter(function(b) {return b.params[1] === 1}) .map(function(b) {return b.params[0] + ""}) ); this.publicGoals = _.uniq( blocks.filter(function(b) {return b.params[1] === 1 && b.params[2] === 1}) .map(function(b) {return b.params[0] + ""}) ); this.remainPublicGoal = this.publicGoals.length; }; p.clearExecutor = function() { this.script.clearExecutors(); }; p.clearListener = function () { Object.values(this.listener).forEach((listener) => { listener.destroy(); }); this.listener = {}; } p.destroy = function() { this.reset(); Entry.achieveEvent.clear(); this.script.destroy(); $(this._view).remove(); }; p.renderViewMessage = function() { var len = this.goals.length; var publicLen = this.publicGoals.length; if (this._view) this._view.html("목표 : " + (len - this.unachievedGoals.length) + " / " + len + " , 공식 목표 : " + (publicLen - this.remainPublicGoal) + " / " + publicLen + "
    " + this.lastMessage); }; p.renderIndicatorMessage = function(message) { if (!this._statusViewIndicator) return; if (message) this.lastIndicatorMessage = message; var publicLen = this.publicGoals.length; this._statusViewIndicator.text( this.lastIndicatorMessage || Math.min(publicLen - this.remainPublicGoal + 1, publicLen) + "/" + publicLen ) } })(Entry.TargetChecker.prototype); ================================================ FILE: src/graphicEngine/EaselResManager.ts ================================================ import { IGEResManager } from './IGEResManager'; import { IRawPicture } from '../class/pixi/atlas/model/IRawPicture'; import { AtlasImageLoader, ImageLoaderHandler } from '../class/pixi/atlas/loader/AtlasImageLoader'; import { AtlasImageLoadingInfo } from '../class/pixi/atlas/loader/AtlasImageLoadingInfo'; import { PIXIAtlasHelper } from '../class/pixi/atlas/PIXIAtlasHelper'; export class EaselResManager implements IGEResManager { private _imgLoader:AtlasImageLoader; private _MAX_TEX_RECT = {x:0, y:0, width:99999, height:99999 }; INIT():void { this._imgLoader = new AtlasImageLoader(this._onImageLoad.bind(this)); } private _onImageLoad(info:AtlasImageLoadingInfo):void { //do nothing } imageRemoved(reason:string):void { this._imgLoader.requestSync(); } activateScene(sceneID:string):void { //do nothing } reqResource(spriteNullable:PIXI.Sprite | any, sceneID:string, pic:IRawPicture, callback:ImageLoaderHandler|null):void { const loader = this._imgLoader; let path = PIXIAtlasHelper.getRawPath(pic); let info = loader.getImageInfo(path); if(!info) { let rect = PIXIAtlasHelper.getNewImageRect(pic, this._MAX_TEX_RECT); loader.load(pic, rect); info = loader.getImageInfo(path); } if(spriteNullable) { spriteNullable.image = info.source(); } if(!info.isReady) { info.addCallback(callback); } else { callback && callback(info); } } clearProject():void { this._imgLoader.empty(); } removeScene(sceneID:string):void { this._imgLoader.requestSync(); } } ================================================ FILE: src/graphicEngine/FakePIXI.js ================================================ (function() { if(window.PIXI) { return; } const emptyFn = ()=>{}; let names = ["Rectangle", "Texture", "Sprite", "RenderTexture", "Matrix", "Graphics", "Container", "TextStyle", "TextMetrics", "Text", "BaseTexture", "Point"]; let pixi = {}; names.forEach((v)=>{ pixi[v] = emptyFn; }); window.PIXI = pixi; /* //PIXI를 통해 참조하는 속성을 찾아내기 위한 함수 var arr = []; window.pixinames = arr; window.PIXI = new Proxy({}, { get: (target, prop) => { if(arr.indexOf(prop) < 0 ) { arr.push(prop); } return emptyFn; } }); */ })(); ================================================ FILE: src/graphicEngine/GEDragHelper.ts ================================================ interface IEventType { UP: string; MOVE: string; DOWN: string; OVER: string; } function getPIXIEvent(): IEventType { return { UP: '__pointerdown', DOWN: '__pointermove', MOVE: '__pointerup', OVER: 'pointerover', }; } function getCreatejsEvent(): IEventType { return { UP: 'pressup', DOWN: 'mousedown', MOVE: 'pressmove', OVER: 'mouseover', }; } class _GEDragHelper { types: IEventType; private _isWebGL: boolean; public handleDrag: (target: any) => void; INIT(isWebGL: boolean) { this._isWebGL = isWebGL; this.types = isWebGL ? getPIXIEvent() : getCreatejsEvent(); if (isWebGL) { this.types = getPIXIEvent(); this.handleDrag = this._handleDragPIXI; } else { this.types = getCreatejsEvent(); this.handleDrag = this._handleCreateJs; } } /** * @since 190705 extracold1209 * common / move event 는 down / up 사이에 있도록 정리 * as-is / 모든 이벤트 등록, down 외 up, outside, cancel 은 up * to-be / * 최초 이벤트는 down 만 등록 * down 이벤트 발생시 * - move, outside, up 이벤트 등록 * - 그러나 outside 는 최초 down 한 포인트로 이벤트 발생 * * TODO 기존 방식이 move 중 스테이지를 벗어난 경우 cancel 을 위한 onUpEvent 라면 * 다른 방법(스테이지안에 포인터가 있는것인지 체크)으로 확인해야 할 것같음. * 현재 블록코딩시 webGL 을 사용하지 않고, minimize 에서는 move event 없으므로 개선보류 */ private _handleDragPIXI(target: any) { const C = this.types; const CE = this._convertPIXIEventToCreateJsStyle; function _onMove(e: any) { target.emit(C.MOVE, CE(e)); } function _onUp(e: any) { target.emit(C.UP, CE(e)); target.removeAllListeners('pointermove'); target.removeAllListeners('pointerup'); target.removeAllListeners('pointerupoutside'); } function _onDown(e: any) { target.emit(C.DOWN, CE(e)); target.on('pointermove', _onMove); target.on('pointerupoutside', () => { _onUp(e); }); target.on('pointerup', _onUp); } target.on('pointerdown', _onDown); } private _convertPIXIEventToCreateJsStyle(e: any) { let g = e.data.global; return { target: e.target, currentTarget: e.currentTarget, stageX: g.x, stageY: g.y, rawX: g.x, rawY: g.y, }; } private _handleCreateJs(target: any) { //do nothing; } } export let GEDragHelper = new _GEDragHelper(); ================================================ FILE: src/graphicEngine/GEHandle.js ================================================ /** * Resize handle on Easel.js */ 'use strict'; import { GEDragHelper } from './GEDragHelper'; import { GEHelper } from './GEHelper'; export const GEHandle = function(canvas) { if (typeof createjs != 'object') { throw 'createjs is not founded'; } const colorSet = EntryStatic.colorSet.canvas || {}; this.canvas = canvas; this.borderColor = colorSet.handleBorder || '#e2e2e2'; this.knobColor = colorSet.handleKnob || '#4f80ff'; this.arrowColor = colorSet.handleArrow || '#ffb500'; this.centerColor = colorSet.handleCenter || '#4f80ff'; this.rotateKnobColor = colorSet.handleRotateKnob || '#ffb500'; this.x = 0; this.y = 0; this.rotation = 0; this.direction = 0; this.width = 100; this.height = 100; this.flipX = false; this.flipY = false; this.visible = false; this.draggable = true; this.centerEditable = true; this.rotationEditable = true; this.directionEditable = true; this.resizeEnable = true; this.onChangeFunction = null; this.callerObject = null; this.createHandle(); this.render(); this.selectedObject = null; }; (function(p) { p.setChangeListener = function(object, func) { this.onChangeFunction = func; this.callerObject = object; return this; }; /** * for undo and redo */ p.setEditStartListener = function(object, func) { this.onEditStartFunction = func; this.editStartCallerObject = object; return this; }; p.setEditEndListener = function(object, func) { this.onEditEndFunction = func; this.editEndCallerObject = object; return this; }; p.toggleCenter = function(isEnable) { this.centerEditable = isEnable; this.centerPoint.visible = isEnable; }; p.toggleRotation = function(isEnable) { this.rotationEditable = isEnable; this.rotateKnob.visible = isEnable; }; p.toggleDirection = function(isEnable) { this.directionEditable = isEnable; this.directionArrow.visible = isEnable; }; p.toggleResize = function(isEnable) { this.resizeEditable = isEnable; for (let i = 0; i < 8; i++) { this.knobs[i].visible = isEnable; } }; p.toggleFont = function(isEnable) { this.fontEditable = isEnable; this.fontKnob.visible = isEnable; }; p.setX = function(xPos) { this.x = xPos; this.container.x = xPos; this.background.x = xPos; }; p.setY = function(yPos) { this.y = yPos; this.container.y = yPos; this.background.y = yPos; }; p.setWidth = function(width) { this.width = width; this.background.scaleX = width / 100; }; p.setHeight = function(height) { this.height = height; this.background.scaleY = height / 100; }; p.setRegX = function(regX) { this.regX = regX; this.centerPoint.x = regX; }; p.setRegY = function(regY) { this.regY = regY; this.centerPoint.y = regY; }; p.setRotation = function(rotation) { rotation = (rotation + 360) % 360; this.rotation = rotation; rotation *= GEHelper.rotateWrite; this.container.rotation = rotation; this.background.rotation = rotation; this.updateKnobCursor(); }; p.setDirection = function(direction) { direction = (direction + 360) % 360; this.direction = direction; this.directionArrow.rotation = direction * GEHelper.rotateWrite; }; p.setVisible = function(visible) { this.visible = visible; this.container.visible = visible; this.background.visible = visible; }; p.setFont = function(fontSize) { this.font = fontSize; this.fontKnob.y = fontSize - this.height / 2; }; p.createHandle = function() { const handle = this; const container = GEHelper.newContainer(); container.mouseEnabled = true; container.mouseChildren = true; //border const border = GEHelper.newGraphic(); container.addChild(border); this.border = border; //edge const edge = GEHelper.newGraphic(); edge.cursor = 'move'; edge.mouseEnabled = true; GEDragHelper.handleDrag(edge); edge.on(GEDragHelper.types.DOWN, function(e) { const offset = handle.getEventCoordinate(e); offset.x -= handle.x; offset.y -= handle.y; this.offset = offset; handle.dispatchEditStartEvent(); }); edge.on(GEDragHelper.types.MOVE, function(e) { if (handle.getDraggable()) { const pos = handle.getEventCoordinate(e); pos.x -= this.offset.x; pos.y -= this.offset.y; handle.setX(pos.x); handle.setY(pos.y); handle.dispatchOnChangeEvent(); } }); edge.on(GEDragHelper.types.UP, (e) => { handle.dispatchEditEndEvent(); }); container.addChild(edge); container.setChildIndex(edge, 1); this.edge = edge; //rotate knob const rotateKnob = GEHelper.newSpriteWithCallback(`${Entry.mediaFilePath}stage/rotate.png`); rotateKnob.scaleX = 0.4; rotateKnob.scaleY = 0.4; rotateKnob.regX = 25; rotateKnob.regY = 125; rotateKnob.mouseEnabled = true; GEDragHelper.handleDrag(rotateKnob); rotateKnob.cursor = 'crosshair'; rotateKnob.on(GEDragHelper.types.DOWN, (e) => { handle.dispatchEditStartEvent(); }); rotateKnob.on(GEDragHelper.types.MOVE, (e) => { const pos = handle.getEventCoordinate(e); pos.x -= handle.x; pos.y -= handle.y; const rotation = (-Math.atan2(pos.x, pos.y) / Math.PI) * 180 - 180; handle.setRotation(rotation); handle.dispatchOnChangeEvent(); }); rotateKnob.on(GEDragHelper.types.UP, (e) => { handle.dispatchEditEndEvent(); }); container.addChild(rotateKnob); container.setChildIndex(rotateKnob, 1); this.rotateKnob = rotateKnob; const directionArrow = GEHelper.newGraphic(); directionArrow.mouseEnabled = true; GEDragHelper.handleDrag(directionArrow); if (GEHelper.isWebGL) { const arrowLength = 7; // 이 값이 작아질수록 길어집니다 directionArrow.graphics .f(this.arrowColor) .mt(0, -40 + arrowLength) .lt(9, -30 + arrowLength) .lt(-9, -30 + arrowLength) .closePath() .dr(-2, -32 + arrowLength, 4, 25); } else { const arrowLength = 7; directionArrow.graphics .ss(4, 1, 1) .s(this.arrowColor) .f(this.arrowColor) .dc(0, 0, this.DHANDLE_RADIUS) .mt(0, 0) .lt(0, -40 + arrowLength) .lt(7, -32 + arrowLength) .lt(-7, -32 + arrowLength) .lt(0, -40 + arrowLength) .es(); } directionArrow.on(GEDragHelper.types.DOWN, (e) => { handle.dispatchEditStartEvent(); }); directionArrow.on(GEDragHelper.types.MOVE, (e) => { const pos = handle.getLocalCoordinate(handle.getEventCoordinate(e)); const rotation = (-Math.atan2(pos.x, pos.y) / Math.PI) * 180 - 180; handle.setDirection(rotation); handle.dispatchOnChangeEvent(); }); directionArrow.on(GEDragHelper.types.UP, (e) => { handle.dispatchEditEndEvent(); }); container.addChild(directionArrow); this.directionArrow = directionArrow; // center const centerPoint = GEHelper.newGraphic(); centerPoint.mouseEnabled = true; GEDragHelper.handleDrag(centerPoint); centerPoint.scaleX = 1.52; centerPoint.scaleY = 1.52; centerPoint.graphics .ss(3.5, 2, 0) .s('#FFFFFF') .beginFill(this.centerColor) .dc(0, 0, 5.5); centerPoint.on(GEDragHelper.types.DOWN, (e) => { handle.dispatchEditStartEvent(); }); centerPoint.on(GEDragHelper.types.MOVE, (e) => { let pos = handle.getEventCoordinate(e); pos = handle.getLocalCoordinate(pos); handle.setRegX(pos.x); handle.setRegY(pos.y); handle.dispatchOnChangeEvent(); }); centerPoint.on(GEDragHelper.types.UP, (e) => { handle.dispatchEditEndEvent(); }); container.addChild(centerPoint); this.centerPoint = centerPoint; //resize knobs this.knobs = []; for (let i = 0; i < 8; i++) { const knob = GEHelper.newGraphic(); knob.mouseEnabled = true; GEDragHelper.handleDrag(knob); knob.scaleX = 1.52; knob.scaleY = 1.52; knob.graphics .ss(0.2, 0, 0) .s('#d8d8d8') .beginFill('#ffffff') .rr(-6, -6, 12, 12, 1) .beginFill(this.knobColor) .rr(-3.4, -3.4, 7, 7, 1); knob.knobIndex = i; //knob.cursor = "move"; knob.on(GEDragHelper.types.DOWN, function(e) { const otherKnobIndex = this.knobIndex + 4 > 7 ? this.knobIndex + 4 - 8 : this.knobIndex + 4; const otherKnob = handle.knobs[otherKnobIndex]; const otherKnobPos = handle.getGlobalCoordinate(otherKnob); this.otherKnobPos = otherKnobPos; handle.dispatchEditStartEvent(); }); knob.on(GEDragHelper.types.MOVE, function(e) { const pos = handle.getEventCoordinate(e); if (handle.checkCenterPointState(handle.regX, handle.regY)) { handle.setRegX(0); handle.setRegY(0); handle.dispatchOnChangeEvent(); } handle.adjust(this.knobIndex, this.otherKnobPos, pos); }); knob.on(GEDragHelper.types.UP, (e) => { handle.dispatchEditEndEvent(); }); container.addChild(knob); container.setChildIndex(knob, 3); this.knobs.push(knob); } const background = GEHelper.newGraphic(); background.mouseEnabled = true; GEDragHelper.handleDrag(background); background.graphics .ss(1, 2, 0) .s('rgba(254,254,254,0.01)') .beginFill('rgba(254,254,254,1)') .dr(-50, -50, 100, 100); background.on(GEDragHelper.types.DOWN, function(e) { const offset = handle.getEventCoordinate(e); offset.x -= handle.x; offset.y -= handle.y; this.offset = offset; handle.dispatchEditStartEvent(); }); background.on(GEDragHelper.types.MOVE, function(e) { if (handle.getDraggable()) { const pos = handle.getEventCoordinate(e); pos.x -= this.offset.x; pos.y -= this.offset.y; handle.setX(pos.x); handle.setY(pos.y); handle.dispatchOnChangeEvent(); } }); background.on(GEDragHelper.types.UP, (e) => { handle.dispatchEditEndEvent(); }); this.canvas.addChildAt(background, 0); this.background = background; this.container = container; this.canvas.addChild(this.container); }; p.checkCenterPointState = function(x, y) { const standard = 718; const res = Math.sqrt(x * x + y * y); if (res > standard && Entry.engine.isState('stop')) { Entry.toast.warning( Lang.Workspace.toast_error_title_object_center, Lang.Workspace.toast_error_contents_object_center ); return true; } return false; }; p.render = function() { this.renderBorder(); this.renderEdge(); this.renderRotateKnob(); this.renderKnobs(); }; p.renderEdge = function() { const width = this.width; const height = this.height; const t = 10; //thickness const sx = -(width + t) / 2; //startX const sy = -(height + t) / 2; //startY this.edge.graphics .clear() .f('rgba(254,254,254,0.01)') .dr(sx, sy, width + t, t) .dr(sx, sy + height, width + t, t) .dr(sx, sy + t, t, height - t) .dr(sx + width, sy + t, t, height - t); }; p.renderRotateKnob = function() { this.rotateKnob.y = -this.height / 2; }; p.renderBorder = function() { const width = this.width; const height = this.height; this.border.graphics .clear() .ss(0.5, 2, 0) .s(this.borderColor) .mt(-width / 2, -height / 2) .lt(0, -height / 2) .lt(0, -height / 2) .lt(+width / 2, -height / 2) .lt(+width / 2, +height / 2) .lt(-width / 2, +height / 2) .cp(); }; p.renderKnobs = function() { const width = this.width / 2; const height = this.height / 2; this.knobs.forEach((knob, i) => { knob.x = Math.round(Math.sin((i / 4) * Math.PI)) * width; knob.y = Math.round(Math.cos((i / 4) * Math.PI)) * height; }); }; p.getEventCoordinate = function(e) { return { x: e.stageX * 0.75 - 240, y: e.stageY * 0.75 - 135, }; }; p.getGlobalCoordinate = function(childObject) { const container = this.container; const rotation = -(((this.container.rotation * Math.PI) / 180) * GEHelper.rotateRead); return { x: this.x + childObject.x * Math.cos(rotation) + childObject.y * Math.sin(rotation), y: this.y + childObject.y * Math.cos(rotation) - childObject.x * Math.sin(rotation), }; }; p.getLocalCoordinate = function(pos) { const container = this.container; const rotation = ((this.container.rotation * Math.PI) / 180) * GEHelper.rotateRead; pos.x -= this.x; pos.y -= this.y; return { x: pos.x * Math.cos(rotation) + pos.y * Math.sin(rotation), y: pos.y * Math.cos(rotation) - pos.x * Math.sin(rotation), }; }; p.adjust = function(knobIndex, otherKnobPos, pos) { const newPoint = this.calcPos({ x: this.x, y: this.y }, otherKnobPos, pos); const newCenter = { x: (otherKnobPos.x + newPoint.x) / 2, y: (otherKnobPos.y + newPoint.y) / 2, }; const newLength = Math.sqrt( Math.pow(newPoint.x - otherKnobPos.x, 2) + Math.pow(newPoint.y - otherKnobPos.y, 2) ); if (knobIndex % 4 == 0) { const ratio = newLength / this.height; this.height = newLength; this.setRegY(this.regY * ratio); } else if (knobIndex % 4 == 2) { const ratio = newLength / this.width; this.width = newLength; this.setRegX(this.regX * ratio); } else { const oldLength = 2 * Math.sqrt( Math.pow(this.x - otherKnobPos.x, 2) + Math.pow(this.y - otherKnobPos.y, 2) ); const newWidth = (this.width * newLength) / oldLength; let ratio = newWidth / this.width; this.setWidth(newWidth); this.setRegX(this.regX * ratio); const newHeight = (this.height * newLength) / oldLength; ratio = newHeight / this.height; this.setHeight((this.height * newLength) / oldLength); this.setRegY(this.regY * ratio); } this.setX(newCenter.x); this.setY(newCenter.y); this.render(); this.dispatchOnChangeEvent(); }; p.updateKnobCursor = function() { const rotation = this.rotation * GEHelper.rotateRead; const cursorList = ['ns-resize', 'nwse-resize', 'ew-resize', 'nesw-resize']; const iter = Math.round(rotation / 45); for (let i = 0; i < iter; i++) { cursorList.unshift(cursorList.pop()); } for (let i = 0; i < 8; i++) { this.knobs[i].cursor = cursorList[i % 4]; } }; p.calcPos = function(pos1, pos2, targetPos) { if (pos1.x == pos2.x) { return { x: pos1.x, y: targetPos.y, }; } else if (pos1.y == pos2.y) { return { x: targetPos.x, y: pos1.y, }; } else { const a = pos1.y - pos2.y; const b = pos2.x - pos1.x; const c = pos1.x * pos2.y - pos2.x * pos1.y; const k = -(a * targetPos.x + b * targetPos.y + c) / (a * a + b * b); return { x: targetPos.x + a * k, y: targetPos.y + b * k, }; } }; p.dispatchOnChangeEvent = function() { if (this.onChangeFunction) { this.onChangeFunction.call(this.callerObject, this); } }; p.dispatchEditStartEvent = function() { if (this.onEditStartFunction) { this.onEditStartFunction.call(this.editStartCallerObject, this); } }; p.dispatchEditEndEvent = function() { if (this.onEditEndFunction) { this.onEditEndFunction.call(this.editEndCallerObject, this); } }; p.setDraggable = function(bool) { this.draggable = bool; }; p.getDraggable = function() { return this.draggable; }; })(GEHandle.prototype); ================================================ FILE: src/graphicEngine/GEHelper.ts ================================================ import * as PIXI from 'pixi.js'; import PIXIHelper from '../class/pixi/helper/PIXIHelper'; import { PIXIGlobal } from '../class/pixi/init/PIXIGlobal'; import { GEDragHelper } from './GEDragHelper'; import { IGEResManager } from './IGEResManager'; import { EaselResManager } from './EaselResManager'; import { PIXIBrushAdaptor } from '../class/pixi/etc/PIXIBrushAdaptor'; import { PIXIPaintAdaptor } from '../class/pixi/etc/PIXIPaintAdaptor'; import { PIXIScaleAdaptor } from '../class/pixi/atlas/PIXIScaleAdaptor'; const INITIAL_VIDEO_PARAMS = { WIDTH: 480, HEIGHT: 270, X: -240, Y: -135, SCALE_X: 0.75, SCALE_Y: 0.75, ALPHA: 0.5, }; const isFirefox = typeof InstallTrigger !== 'undefined'; declare let createjs: any; interface IGraphicsEngineApplication { render(): void; stage: PIXI.Container | any; destroy(destroyOption: any): void; } interface ITicker { reset(): void; setFPS(n: number): void; } class CreateJsApplication implements IGraphicsEngineApplication { stage: any; constructor(canvas: HTMLCanvasElement) { const stage = new createjs.Stage(canvas.id); createjs.Touch.enable(stage); stage.enableMouseOver(10); stage.mouseMoveOutside = true; this.stage = stage; } render(): void { this.stage.update(); } destroy(destroyOption: any) { this.stage = null; } } export class GEHelperBase { protected _isWebGL: boolean = false; INIT(isWebGL: boolean) { this._isWebGL = isWebGL; } } const emptyFn = (...arg: any[]) => {}; class _GEHelper extends GEHelperBase { get isWebGL(): boolean { return this._isWebGL; } public resManager: IGEResManager; public textHelper: _TextHelper; public colorFilter: _ColorFilterHelper; public brushHelper: _BrushHelper; /** pixi 객체로부터 rotate를 읽을 때 사용할 값 */ public rotateRead: number = 1; /** pixi 객체에 rotate를 할당 할 때 사용할 값 */ public rotateWrite: number = 1; public Ticker: ITicker; private _isInitialized: boolean; /** pixi Graphics로 비디오 감지 표현하기 위한 PIXI.Graphics */ public poseIndicatorGraphic: PIXI.Graphics | createjs.Graphics; public faceIndicatorGraphic: PIXI.Graphics | createjs.Graphics; public objectIndicatorGraphic: PIXI.Graphics | createjs.Graphics; /** * issues/9422#issuecomment-2678582 * 최종 좌표 결정 단계에서 약간의 오차를 주어 이 현상을 막음. */ public rndPosition: () => number; /** * 비디오 블록용 컨테이너, index = 2 , 기존의 오브젝트 컨테이너 = index3; */ private videoContainer: PIXI.Container | createjs.Container; private overlayContainer: PIXI.Container | createjs.Container; INIT(isWebGL: boolean) { super.INIT(isWebGL); if (this._isInitialized) { return; } this._isInitialized = true; GEDragHelper.INIT(isWebGL); (this.colorFilter = new _ColorFilterHelper()).INIT(isWebGL); (this.textHelper = new _TextHelper()).INIT(isWebGL); (this.brushHelper = new _BrushHelper()).INIT(isWebGL); if (this._isWebGL) { // this.rndPosition = ()=>{ return Math.random() * 0.8 - 0.4; }; this.rndPosition = () => 0; this.rotateRead = 180 / Math.PI; this.rotateWrite = Math.PI / 180; PIXIGlobal.initOnce(); this.resManager = PIXIGlobal.atlasManager; this.Ticker = { reset: emptyFn, setFPS: emptyFn, }; } else { this.rndPosition = () => 0; this.resManager = new EaselResManager(); this.Ticker = { reset: createjs.Ticker.reset, setFPS: createjs.Ticker.setFPS, }; } this.resManager.INIT(); } newApp(canvas: HTMLCanvasElement): IGraphicsEngineApplication { let app: IGraphicsEngineApplication; if (this._isWebGL) { app = PIXIGlobal.getNewApp(canvas); } else { app = new CreateJsApplication(canvas); } return app; } cloneStamp(entity: any): any { if (this._isWebGL) { const orgObj = entity.object; const orgTex = orgObj.internal_getOriginalTex && orgObj.internal_getOriginalTex(); const object = PIXIHelper.sprite('StampEntity', orgTex || orgObj.texture); object.visible = orgObj.visible; object.interactive = false; object.interactiveChildren = false; object.setTransform( orgObj.x, orgObj.y, orgObj.scale.x, orgObj.scale.y, orgObj.rotation, orgObj.skew.x, orgObj.skew.y, orgObj.pivot.x, orgObj.pivot.y ); return object; } else { const object = entity.object.clone(); object.mouseEnabled = false; object.tickEnabled = false; object.filters = null; return object; } } hitTestMouse(object: any): boolean { if (this._isWebGL) { const pixiApp: PIXI.Application = Entry.stage._app; const im = pixiApp.renderer.plugins.interaction; const hitObject = im.hitTest(im.mouse.global, object); return !!hitObject; } else { if (object.alpha < 0.001) { return false; } const stage = Entry.stage.canvas; const pt = object.globalToLocal(stage.mouseX, stage.mouseY); return object.hitTest(pt.x, pt.y); } } tickByEngine() { if (this._isWebGL) { Entry.stage._app.ticker.start(); } else { createjs.Ticker.addEventListener('tick', Entry.stage.canvas); } } // for createJS ONLY issue, #12012 disableTickByEngine() { if (this._isWebGL) { return; } else { createjs.Ticker.removeEventListener('tick', Entry.stage.canvas); } } getNewContainer(): any { if (this._isWebGL) { return new PIXI.Container(); } else { return new createjs.Container(); } } // this function returns corresponding VideoElement, getVideoElement(video: HTMLVideoElement): any { console.log('getVideoElement'); let videoElement: any = null; const { WIDTH, X, Y, SCALE_X, SCALE_Y, ALPHA } = INITIAL_VIDEO_PARAMS; let HEIGHT = INITIAL_VIDEO_PARAMS.HEIGHT; if (this._isWebGL) { const videoTexture = PIXI.Texture.from(video); videoElement = new PIXI.Sprite(videoTexture); if (isFirefox) { HEIGHT *= 1.33; } } else { videoElement = new createjs.Bitmap(video); } videoElement.width = WIDTH; videoElement.height = HEIGHT; videoElement.x = X; videoElement.y = Y; videoElement.alpha = ALPHA; if (this._isWebGL) { videoElement.scale.x = SCALE_X; videoElement.scale.y = SCALE_Y; } else { videoElement.scaleX = SCALE_X; videoElement.scaleY = SCALE_Y; videoElement.on('tick', () => { if (videoElement.cacheCanvas) { videoElement.updateCache(); } }); } return videoElement; } getOverlayElement(canvas: HTMLCanvasElement): any { let overlayElement: any = null; const { WIDTH, X, Y, SCALE_X, SCALE_Y, ALPHA } = INITIAL_VIDEO_PARAMS; let HEIGHT = INITIAL_VIDEO_PARAMS.HEIGHT; if (this._isWebGL) { const videoTexture = PIXI.Texture.from(canvas); overlayElement = new PIXI.Sprite(videoTexture); if (isFirefox) { HEIGHT *= 1.33; } } else { overlayElement = new createjs.Bitmap(canvas); } overlayElement.width = WIDTH; overlayElement.height = HEIGHT; overlayElement.x = X; overlayElement.y = Y; overlayElement.alpha = ALPHA; if (this._isWebGL) { overlayElement.scale.x = SCALE_X; overlayElement.scale.y = SCALE_Y; } else { overlayElement.scaleX = SCALE_X; overlayElement.scaleY = SCALE_Y; overlayElement.on('tick', () => { if (overlayElement.cacheCanvas) { overlayElement.updateCache(); } }); } return overlayElement; } createNewIndicatorGraphic() { const graphic = this.newGraphic(); graphic.width = 640; graphic.height = 360; graphic.x = INITIAL_VIDEO_PARAMS.X; graphic.y = INITIAL_VIDEO_PARAMS.Y; return graphic; } drawVideoElement(videoElement: PIXI.Sprite | createjs.Bitmap): any { if (!this.videoContainer) { this.videoContainer = Entry.stage.canvas.getChildAt(2); } this.videoContainer.addChild(videoElement); this.tickByEngine(); } drawOverlayElement(overlayElement: PIXI.Sprite | createjs.Bitmap): any { if (!this.overlayContainer) { this.overlayContainer = Entry.stage.canvas.getChildAt(3); } const isAlready = this.overlayContainer.children.some( (child: PIXI.Sprite | createjs.Bitmap) => { child === overlayElement; } ); if (!isAlready) { this.overlayContainer.addChild(overlayElement); } this.tickByEngine(); } drawDetectedGraphic() { if (!this.poseIndicatorGraphic) { this.poseIndicatorGraphic = this.createNewIndicatorGraphic(); Entry.stage.canvas.addChildAt(this.poseIndicatorGraphic, 4); } if (!this.faceIndicatorGraphic) { this.faceIndicatorGraphic = this.createNewIndicatorGraphic(); Entry.stage.canvas.addChildAt(this.faceIndicatorGraphic, 4); } if (!this.objectIndicatorGraphic) { this.objectIndicatorGraphic = this.createNewIndicatorGraphic(); Entry.stage.canvas.addChildAt(this.objectIndicatorGraphic, 4); } this.tickByEngine(); } turnOffWebcam(canvasVideo: PIXI.Sprite | createjs.Bitmap) { if (!canvasVideo) { return; } const targetContainer = Entry.stage.canvas.getChildAt(2); targetContainer.removeChild(canvasVideo); } turnOffOverlay(overlayElement: PIXI.Sprite | createjs.Bitmap) { if (!overlayElement) { return; } const targetContainer = Entry.stage.canvas.getChildAt(3); targetContainer.removeChild(overlayElement); } destroyWebcam() { this.videoContainer = null; } destroyOverlay() { this.overlayContainer = null; } destroy() { this.videoContainer = null; this.overlayContainer = null; this.faceIndicatorGraphic = null; this.poseIndicatorGraphic = null; this.objectIndicatorGraphic = null; } hFlipVideoElement( canvasVideo: PIXI.Sprite | createjs.Bitmap | PIXI.Sprite[] | createjs.Bitmap[] ): any { if (Array.isArray(canvasVideo)) { canvasVideo.forEach((video: PIXI.Sprite | createjs.Bitmap) => { if (!video) { return; } const { x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY } = video; video.setTransform(-x, y, -scaleX, scaleY, rotation, skewX, skewY, regX, regY); }); } else { const { x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY } = canvasVideo; canvasVideo.setTransform(-x, y, -scaleX, scaleY, rotation, skewX, skewY, regX, regY); } } vFlipVideoElement( canvasVideo: PIXI.Sprite | createjs.Bitmap | PIXI.Sprite[] | createjs.Bitmap[] ): any { if (Array.isArray(canvasVideo)) { canvasVideo.forEach((video: PIXI.Sprite | createjs.Bitmap) => { if (!video) { return; } const { x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY } = video; video.setTransform(x, -y, scaleX, -scaleY, rotation, skewX, skewY, regX, regY); }); } else { const { x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY } = canvasVideo; canvasVideo.setTransform(x, -y, scaleX, -scaleY, rotation, skewX, skewY, regX, regY); } } setVideoAlpha(canvasVideo: PIXI.Sprite | createjs.Bitmap, value: number): any { canvasVideo.alpha = (100 - value) / 100; } removeAllChildInHandler(handler: PIXI.Graphics | createjs.Graphics) { while (handler.children.length > 0) { const child = handler.getChildAt(0); handler.removeChild(child); } } resetHandlers() { if ( !this.faceIndicatorGraphic || !this.poseIndicatorGraphic || !this.objectIndicatorGraphic ) { return; } if (this.isWebGL) { this.faceIndicatorGraphic.clear(); this.poseIndicatorGraphic.clear(); this.objectIndicatorGraphic.clear(); this.removeAllChildInHandler(this.objectIndicatorGraphic); this.removeAllChildInHandler(this.poseIndicatorGraphic); this.removeAllChildInHandler(this.faceIndicatorGraphic); } else { this.faceIndicatorGraphic.graphics.clear(); this.poseIndicatorGraphic.graphics.clear(); this.objectIndicatorGraphic.graphics.clear(); } } async drawHumanPoints(poses: Array, flipStatus: any) { const R = 5; let handler = this.poseIndicatorGraphic; if (this._isWebGL) { while (handler.children.length > 0) { const child = handler.getChildAt(0); handler.removeChild(child); } } else { handler = this.poseIndicatorGraphic.graphics; } handler.clear(); poses.map((pose: any, index: Number) => { const { x, y } = pose.keypoints[3].position; if (this._isWebGL) { const text = PIXIHelper.text( `${Lang.Blocks.video_human}-${index + 1}`, '20px Nanum Gothic', '', 'middle', 'center' ); text.x = x - 20; text.y = y - 20; handler.addChild(text); } else { handler.append({ exec: (ctx: any) => { ctx.font = '20px Nanum Gothic'; ctx.color = 'blue'; ctx.fillText(`${Lang.Blocks.video_human}-${index + 1}`, x - 20, y - 20); }, }); } pose.keypoints.map((item: any) => { const { x, y } = item.position; const recalculatedY = flipStatus.vertical ? INITIAL_VIDEO_PARAMS.HEIGHT - y : y; handler.beginFill(0x0000ff); handler.drawCircle(x, recalculatedY, R); handler.endFill(); }); }); } async drawHumanSkeletons(adjacents: Array, flipStatus: any) { const coordList: any = []; let handler = this.poseIndicatorGraphic; adjacents.forEach((adjacentList: any) => { adjacentList.forEach((pair: any) => { const start = pair[0].position; const end = pair[1].position; if (flipStatus.vertical) { start.y = INITIAL_VIDEO_PARAMS.HEIGHT - start.y; end.y = INITIAL_VIDEO_PARAMS.HEIGHT - end.y; } coordList.push({ start, end }); }); }); if (this._isWebGL) { handler.lineStyle(5, 0x0000ff); } else { handler = handler.graphics; handler.setStrokeStyle(8, 'round').beginStroke('blue'); } coordList.forEach((coord: any) => { const { start, end } = coord; handler.moveTo(start.x, start.y).lineTo(end.x, end.y); }); } async drawFaceEdges(faces: any, flipStatus: any) { let handler = this.faceIndicatorGraphic; if (this._isWebGL) { handler.clear(); while (handler.children.length > 0) { const child = handler.getChildAt(0); handler.removeChild(child); } handler.lineStyle(2, 0xff0000); } else { handler = handler.graphics; handler.clear(); handler.setStrokeStyle(2, 'round').beginStroke('red'); } faces.forEach((face: { landmarks: { _positions: any[] } }, index: Number) => { const positions = face.landmarks._positions; positions.forEach((item, i) => { if ( i === 0 || i === 17 || i === 27 || i === 31 || i === 36 || i === 42 || i === 48 ) { return; } const prev = face.landmarks._positions[i - 1]; this.drawEdge(prev, item, handler, flipStatus); }); // compensation for missing edges this.drawEdge(positions[42], positions[47], handler, flipStatus); this.drawEdge(positions[41], positions[36], handler, flipStatus); this.drawEdge(positions[60], positions[67], handler, flipStatus); this.drawEdge(positions[0], positions[17], handler, flipStatus); this.drawEdge(positions[16], positions[26], handler, flipStatus); this.drawEdge(positions[27], positions[31], handler, flipStatus); this.drawEdge(positions[27], positions[35], handler, flipStatus); this.drawEdge(positions[30], positions[31], handler, flipStatus); this.drawEdge(positions[30], positions[35], handler, flipStatus); const refPoint = positions[57]; let x = refPoint._x; let y = refPoint._y; const { WIDTH, HEIGHT } = INITIAL_VIDEO_PARAMS; if (flipStatus.horizontal) { x = WIDTH - x; } if (flipStatus.vertical) { y = HEIGHT - y; } if (this._isWebGL) { const text = PIXIHelper.text( `${Lang.Blocks.video_face}-${index + 1}`, '20px Nanum Gothic', '', 'middle', 'center' ); text.x = x; text.y = y - 10; handler.addChild(text); } else { handler.append({ exec: (ctx: any) => { ctx.font = '20px Nanum Gothic'; ctx.color = '#0000ff'; ctx.fillText(`${Lang.Blocks.video_face}-${index + 1}`, x, y - 10); }, }); } }); } drawEdge( pos1: { _x: number; _y: number }, pos2: { _x: number; _y: number }, handler: PIXI.Graphics | createjs.Graphics, flipStatus: any ) { const { WIDTH, HEIGHT } = INITIAL_VIDEO_PARAMS; let { _x, _y } = pos2; let prevX = pos1._x; let prevY = pos1._y; if (flipStatus.horizontal) { _x = WIDTH - _x; prevX = WIDTH - prevX; } if (flipStatus.vertical) { _y = HEIGHT - _y; prevY = HEIGHT - prevY; } handler.moveTo(prevX, prevY).lineTo(_x, _y); } async drawObjectBox(objects: Array, flipStatus: any) { const objectsList: any = []; objects.forEach((object: any) => { const bbox = object.bbox; const name = object.class ? `${Lang.Blocks.video_object}-${Lang.video_object_params[object.class]}` : ''; let x = bbox[0]; let y = bbox[1]; const width = bbox[2]; const height = bbox[3]; if (flipStatus.horizontal) { x = INITIAL_VIDEO_PARAMS.WIDTH - x - width; } if (flipStatus.vertical) { y = INITIAL_VIDEO_PARAMS.HEIGHT - y - height; } const textpoint = { x: x + 20, y: y + 20 }; objectsList.push({ textpoint, name, x, y, width, height }); }); let handler = this.objectIndicatorGraphic; if (this._isWebGL) { handler.clear(); while (handler.children.length > 0) { const child = handler.getChildAt(0); handler.removeChild(child); } handler.lineStyle(5, 0xff0000); objectsList.forEach((target: any, index: Number) => { const { textpoint, name, x, y, width, height } = target; if (name) { const text = PIXIHelper.text( `${name}-${index + 1}`, '20px Nanum Gothic', '', 'middle', 'center' ); text.x = textpoint.x; text.y = textpoint.y; handler.addChild(text); } handler.drawRect(x, y, width, height); }); } else { handler = handler.graphics; handler.clear(); objectsList.forEach((target: any, index: Number) => { const { textpoint, name, x, y, width, height } = target; if (name) { handler.append({ exec: (ctx: any) => { ctx.font = '20px Nanum Gothic'; ctx.fillText(`${name}-${index + 1}`, textpoint.x - 5, textpoint.y + 5); }, }); } handler .setStrokeStyle(8, 'round') .beginStroke('red') .drawRect(x, y, width, height); }); } } getTransformedBounds(sprite: PIXI.Sprite | any): PIXI.Rectangle | any { if (this._isWebGL) { return sprite.getBounds(false); } else { return sprite.getTransformedBounds(); } } calcParentBound(obj: any): any { if (this._isWebGL) { return PIXIHelper.getTransformBound(obj); } else { return obj.getTransformedBounds(); } } newContainer(debugName?: string): PIXI.Container | any { if (this._isWebGL) { return PIXIHelper.container(debugName); } else { return new createjs.Container(); } } /** * stage wall 생성만을 위한 함수 * @param path */ newWallTexture(path: string): PIXI.Texture | HTMLImageElement { if (this._isWebGL) { return PIXI.Texture.from(path); } else { const img: HTMLImageElement = new Image(); img.src = path; return img; } } /** * stage wall 생성만을 위한 함수 * @param tex */ newWallSprite(tex: any) { if (this._isWebGL) { return new PIXI.Sprite(tex); } else { return new createjs.Bitmap(tex); } } newEmptySprite() { if (this._isWebGL) { return PIXIHelper.sprite(); } else { return new createjs.Bitmap(); } } newSpriteWithCallback(url: string, callback?: () => void) { const img = new Image(); if (callback) { const handle = () => { img.removeEventListener('load', handle); callback(); }; img.addEventListener('load', handle); } img.src = url; if (this._isWebGL) { const texture = PIXI.Texture.from(img); return PIXI.Sprite.from(texture); } else { return new createjs.Bitmap(img); } } newGraphic() { if (this._isWebGL) { return new PIXI.Graphics(); } else { return new createjs.Shape(); } } newAScaleAdaptor(target: any): any { if (this._isWebGL) { return PIXIScaleAdaptor.factory(target); } //createjs 는 사용하는 코드측에서 분기 처리. return null; } } export const GEHelper = new _GEHelper(); class _ColorFilterHelper extends GEHelperBase { hue(value: number) { if (this._isWebGL) { const cmHue = new PIXI.filters.ColorMatrixFilter(); // @ts-ignore return cmHue.hue(value); } else { const cmHue = new createjs.ColorMatrix(); cmHue.adjustColor(0, 0, 0, value); const hueFilter = new createjs.ColorMatrixFilter(cmHue); return hueFilter; } } brightness(value: number) { if (this._isWebGL) { value /= 255; } // pixi 필터에 brightness 가 있지만, createjs 와 matrix 값이 달라 결과가 다르게 보임. 그래서 동일하게 구현함. const matrix = [ 1, 0, 0, 0, value, 0, 1, 0, 0, value, 0, 0, 1, 0, value, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, ]; return this.newColorMatrixFilter(matrix); } /** * @param matrixValue */ newColorMatrixFilter(matrixValue: number[]) { if (this._isWebGL) { matrixValue.length = 20; // pixi matrix 는 5 * 4 const m = new PIXI.filters.ColorMatrixFilter(); m._loadMatrix(matrixValue, false); return m; } else { //createjs matrix 는 5*5 const cm = new createjs.ColorMatrix(); cm.copy(matrixValue); return new createjs.ColorMatrixFilter(cm); } } /** * * @param entity - EntityObject * @param cache */ setCache(entity: any, cache: boolean) { if (this._isWebGL) { //do nothing } else { cache ? entity.cache() : entity.object.uncache(); } } } class _TextHelper extends GEHelperBase { setColor(target: PIXI.Text | any, color: string) { if (this._isWebGL) { target.style.fill = color; } else { target.color = color; } } /** * @param str * @param font size & fontface - 10pt NanumGothic * @param color css style color - #ffffff * @param textBaseline * @param textAlign * @ */ newText( str: string, font: string, color: string, textBaseline?: string, textAlign?: string ): PIXI.Text | any { if (this._isWebGL) { return PIXIHelper.text(str, font, color, textBaseline, textAlign); } else { const text = new createjs.Text(str, font, color); textBaseline ? (text.textBaseline = textBaseline) : 0; textAlign ? (text.textAlign = textAlign) : 0; return text; } } } class _BrushHelper extends GEHelperBase { newBrush() { if (this._isWebGL) { return new PIXIBrushAdaptor(); } else { return new createjs.Graphics(); } } newPaint() { if (this._isWebGL) { return new PIXIPaintAdaptor(); } else { return new createjs.Graphics(); } } newShape(brush: PIXIBrushAdaptor | any) { if (this._isWebGL) { const shape = PIXIHelper.newPIXIGraphics(); brush.internalSetShape(shape); return shape; } else { const shape = new createjs.Shape(brush); return shape; } } } ================================================ FILE: src/graphicEngine/IGEResManager.ts ================================================ import { IRawPicture } from '../class/pixi/atlas/model/IRawPicture'; import { ImageLoaderHandler } from '../class/pixi/atlas/loader/AtlasImageLoader'; export interface IGEResManager { INIT():void; activateScene(sceneID:string):void; removeScene(sceneID:string):void; imageRemoved(reason:string):void; clearProject():void /** * textrue( or createjs.Bitmap ) 를 요청하고, spriteNullable 에 할당. * @param spriteNullable * @param sceneID * @param pic * @param callback */ reqResource(spriteNullable:PIXI.Sprite|any, sceneID:string, pic:IRawPicture, callback:ImageLoaderHandler):void; } ================================================ FILE: src/log/activity.js ================================================ 'use strict'; Entry.Activity = function(name, data) { this.name = name; this.timestamp = new Date(); var arr = []; if (data !== undefined) { for (var i = 0, len = data.length; i < len; i++) { var datum = data[i]; arr.push({ key: datum[0], value: datum[1], }); } } this.data = arr; }; ================================================ FILE: src/log/activityReporter.js ================================================ 'use strict'; Entry.ActivityReporter = function() { this._activities = []; }; (function(p) { p.add = function(data) { if (!data || data.length === 0) return; var activity; if (data instanceof Entry.Activity) activity = data; else { var type = data.shift(); activity = new Entry.Activity(type, data); } this._activities.push(activity); }; p.clear = function() { this._activities = []; }; p.get = function() { return this._activities; }; p.report = function() {}; })(Entry.ActivityReporter.prototype); ================================================ FILE: src/log/recorder.js ================================================ 'use strict'; Entry.Recorder = function() { this._recordData = []; Entry.commander.addReporter(this); }; (function(p) { p.add = function(data) { var commandType = data[0]; if (!commandType) return; var command = Entry.Command[commandType]; switch (command.recordable) { case Entry.STATIC.RECORDABLE.SUPPORT: this._recordData.push(data); Entry.toast.warning('Record', Lang.Command[commandType + '']); return; case Entry.STATIC.RECORDABLE.SKIP: return; case Entry.STATIC.RECORDABLE.ABANDON: Entry.toast.alert('지원하지 않음'); return; } }; p.getData = function() { return this._recordData; }; })(Entry.Recorder.prototype); ================================================ FILE: src/log/state.js ================================================ /** * @fileoverview State class for undo and redo. */ 'use strict'; /** * @constructor */ Entry.State = function(type, caller, func, param) { /** * function's caller. * @type {!object} */ this.caller = caller; /** * function to recover state. * @type {!function} */ this.func = func; /** * parameters for function. * @type {Array} */ if (arguments.length > 3) this.params = Array.prototype.slice.call(arguments).slice(3); /** * message for interface. * @type {?String} * */ this.message = type; /** * born time * @type {Number} * */ this.time = Entry.getUpTime(); this.isPass = Entry.Command[type] ? Entry.Command[type].isPass : false; this.id = Entry.generateHash(); }; /** * generate message for interface. */ Entry.State.prototype.generateMessage = function() { }; ================================================ FILE: src/log/state_manager.js ================================================ class EntryStateManager { constructor() { this.undoStack_ = []; this.redoStack_ = []; /** prevent add command when undo and redo */ this.isRestore = false; this._isRedoing = false; this.isIgnore = false; Entry.addEventListener('cancelLastCommand', (e) => { this.cancelLastCommand(); }); Entry.addEventListener('saveWorkspace', (e) => { this.addStamp(); }); Entry.addEventListener('undo', (e) => { this.undo(); }); Entry.addEventListener('redo', (e) => { this.redo(); }); } generateView(stateManagerView, option) { console.warn('this method is nothing to do. please consider remove logic'); } addCommand(type, caller, func, params) { if (this.isIgnoring()) { return; } const state = new Entry.State(); Entry.State.prototype.constructor.apply(state, Array.prototype.slice.call(arguments)); if (this.isRestoring()) { this.redoStack_.push(state); } else { this.undoStack_.push(state); if (!this._isRedoing) { this.redoStack_ = []; } } if (Entry.reporter) { Entry.reporter.report(state); } if (Entry.creationChangedEvent) { Entry.creationChangedEvent.notify(); } return state; } cancelLastCommand() { if (!this.canUndo()) { return; } this.undoStack_.pop(); if (Entry.creationChangedEvent) { Entry.creationChangedEvent.notify(); } } getLastCommand() { return this.undoStack_[this.undoStack_.length - 1]; } getLastCommandById(id) { const undoStack = this.undoStack_; const len = undoStack.length - 1; for (let i = len; i >= 0; i--) { const state = undoStack[i]; if (state.id === id) { return state; } } } getLastRedoCommand() { return this.redoStack_[this.redoStack_.length - 1]; } removeAllPictureCommand() { this.undoStack_ = this.undoStack_.filter( (stack) => !(stack.message >= 400 && stack.message < 500) ); this.redoStack_ = this.redoStack_.filter( (stack) => !(stack.message >= 400 && stack.message < 500) ); } undo(count) { if (!this.canUndo() || this.isRestoring()) { return; } this.addActivity('undo'); this.startRestore(); let isFirst = true; while (this.undoStack_.length) { const state = this.undoStack_.pop(); state.func.apply(state.caller, state.params); const command = this.getLastRedoCommand(); if (isFirst) { command.isPass = false; isFirst = !isFirst; } else { command.isPass = true; } if (count) { count--; } if (!count && state.isPass !== true) { break; } } this.endRestore(); if (Entry.disposeEvent) { Entry.disposeEvent.notify(); } if (Entry.creationChangedEvent) { Entry.creationChangedEvent.notify(); } } redo() { if (!this.canRedo() || this.isRestoring()) { return; } this._isRedoing = true; this.addActivity('undo'); this.addActivity('redo'); let isFirst = true; while (this.redoStack_.length) { const state = this.redoStack_.pop(); const ret = state.func.apply(state.caller, state.params); if (isFirst) { ret.isPass(false); isFirst = !isFirst; } else { ret.isPass(true); } if (state.isPass !== true) { break; } } this._isRedoing = false; if (Entry.creationChangedEvent) { Entry.creationChangedEvent.notify(); } } updateView() { return; if (this.undoButton && this.redoButton) { if (this.canUndo()) { this.undoButton.addClass('active'); } else { this.undoButton.removeClass('active'); } if (this.canRedo()) { this.redoButton.addClass('active'); } else { this.redoButton.removeClass('active'); } } } startRestore() { this.isRestore = true; } endRestore() { this.isRestore = false; } isRestoring() { return this.isRestore; } startIgnore() { this.isIgnore = true; } endIgnore() { this.isIgnore = false; } isIgnoring() { return this.isIgnore; } canUndo() { return this.undoStack_.length > 0 && Entry.engine.isState('stop'); } canRedo() { return this.redoStack_.length > 0 && Entry.engine.isState('stop'); } /** * mark state which one saved */ addStamp() { this.stamp = Entry.generateHash(); if (this.undoStack_.length) { this.undoStack_[this.undoStack_.length - 1].stamp = this.stamp; } } /** * @return {!boolean} return true when project is up-to-date */ isSaved() { return ( this.undoStack_.length === 0 || (this.undoStack_[this.undoStack_.length - 1].stamp == this.stamp && typeof this.stamp == 'string') ); } /** * @param {String} activityType */ addActivity(activityType) { if (Entry.reporter) { Entry.reporter.report(new Entry.State(activityType)); } } getUndoStack() { return this.undoStack_.slice(0); } changeLastCommandType(type) { const cmd = this.getLastCommand(); if (cmd) { cmd.message = type; } return cmd; } clear() { while (this.undoStack_.length) { this.undoStack_.pop(); } while (this.redoStack_.length) { this.redoStack_.pop(); } if (Entry.creationChangedEvent) { Entry.creationChangedEvent.notify(); } } } Entry.StateManager = EntryStateManager; ================================================ FILE: src/model/block_model.js ================================================ 'use strict'; Entry.BlockModel = class BlockModel { constructor(context) { Entry.Model(this); this.schema = { id: null, x: 0, y: 0, type: null, params: {}, statements: {}, prev: null, next: null, view: null, }; } }; ================================================ FILE: src/model/block_render_model.js ================================================ 'use strict'; Entry.BlockRenderModel = class BlockRenderModel { constructor() { this.schema = { id: 0, type: Entry.STATIC.BLOCK_RENDER_MODEL, x: 0, y: 0, width: 0, height: 0, magneting: false, }; Entry.Model(this); } }; ================================================ FILE: src/model/box_model.js ================================================ 'use strict'; Entry.BoxModel = class BoxModel { constructor() { this.schema = { id: 0, type: Entry.STATIC.BOX_MODEL, x: 0, y: 0, width: 0, height: 0, }; Entry.Model(this); } }; ================================================ FILE: src/model/drag_instance.js ================================================ 'use strict'; Entry.DragInstance = class DragInstance { constructor(model) { this.schema = { type: Entry.STATIC.DRAG_INSTANCE, startX: 0, startY: 0, offsetX: 0, offsetY: 0, absX: 0, absY: 0, prev: null, height: 0, mode: 0, isNew: false, }; Entry.Model(this); this.set(model); } }; ================================================ FILE: src/model/thread_model.js ================================================ 'use strict'; Entry.ThreadModel = class ThreadModel { constructor() { this.schema = { id: 0, type: Entry.STATIC.THREAD_MODEL, x: 0, y: 0, width: 0, minWidth: 0, height: 0, }; Entry.Model(this); } }; ================================================ FILE: src/parser-no/block.js ================================================ /* * */ 'use strict'; Entry.BlockParser = function(syntax) { this.syntax = syntax; this._iterVariableCount = 0; this._iterVariableChunk = ['i', 'j', 'k']; }; (function(p) { p.Code = function(code) { if (code instanceof Entry.Thread) return this.Thread(code); if (code instanceof Entry.Block) return this.Block(code); var textCode = '', threads = code.getThreads(); for (var i = 0; i < threads.length; i++) { var thread = threads[i]; textCode += this.Thread(thread); } return textCode; }; p.Thread = function(thread) { if (thread instanceof Entry.Block) return this.Block(thread); var code = '', blocks = thread.getBlocks(); for (var i = 0; i < blocks.length; i++) { var block = blocks[i]; code += this.Block(block); } return code; }; p.Block = function(block) { var syntax = block._schema.syntax; if (!syntax) return ''; var syntaxType = syntax[0]; return this[syntaxType](block); }; p.Program = function(block) { return ''; }; p.Scope = function(block) { var syntax = block._schema.syntax.concat(); return syntax.splice(1, syntax.length - 1).join('.') + '();\n'; }; p.BasicFunction = function(block) { var statementCode = this.Thread(block.statements[0]); var code = 'function promise() {\n' + this.indent(statementCode) + '}\n'; return code; }; p.BasicIteration = function(block) { var iterateNumber = block.params[0]; var iterVariable = this.publishIterateVariable(); var statementCode = this.Thread(block.statements[0]); this.unpublishIterateVariable(); var code = 'for (var ' + iterVariable + ' = 0; ' + iterVariable + ' < ' + iterateNumber + '; ' + iterVariable + '++){\n' + this.indent(statementCode) + '}\n'; return code; }; p.BasicIf = function(block) { var statementCode = this.Thread(block.statements[0]); var syntax = block._schema.syntax.concat(); var code = 'if (' + syntax[1] + ') {\n' + this.indent(statementCode) + '}\n'; return code; }; p.BasicWhile = function(block) { var statementCode = this.Thread(block.statements[0]); var syntax = block._schema.syntax.concat(); var code = 'while (' + syntax[1] + ') {\n' + this.indent(statementCode) + '}\n'; return code; }; p.indent = function(textCode) { var result = ' '; var indentedCode = textCode.split('\n'); indentedCode.pop(); result += indentedCode.join('\n ') + '\n'; return result; }; // iterate variable p.publishIterateVariable = function() { var iterVariable = ''; var iterVariableCount = this._iterVariableCount; do { var chunk = this._iterVariableChunk[iterVariableCount % 3]; iterVariable = chunk + iterVariable; iterVariableCount = parseInt(iterVariableCount / 3) - 1; if (iterVariableCount === 0) iterVariable = this._iterVariableChunk[0] + iterVariable; } while (iterVariableCount > 0); this._iterVariableCount++; return iterVariable; }; p.unpublishIterateVariable = function() { if (this._iterVariableCount) this._iterVariableCount--; }; })(Entry.BlockParser.prototype); ================================================ FILE: src/parser-no/js.js ================================================ /* * */ 'use strict'; Entry.JSParser = function(syntax) { this.syntax = syntax; this.scopeChain = []; this.scope = null; }; (function(p) { p.Program = function(node) { var code = []; var block = []; var body = node.body; //block statement block.push({ type: this.syntax.Program, }); var separatedBlocks = this.initScope(node); block = block.concat(this.BlockStatement(node)); this.unloadScope(); code.push(block); code = code.concat(separatedBlocks); return code; }; p.Identifier = function(node, scope) { if (scope) return scope[node.name]; else return this.scope[node.name]; }; // Statement p.ExpressionStatement = function(node) { var expression = node.expression; return this[expression.type](expression); }; p.ForStatement = function(node) { var init = node.init, test = node.test, update = node.update, body = node.body; var contents = ''; var blockType = this.syntax.ForStatement; if (!blockType) { body = this[body.type](body); var startVal = init.declarations[0].init.value; var test = test; var op = test.operator; var endVal = test.right.value; var updateOp = update.operator; var res = 0; if (!(updateOp == '++')) { var temp = startVal; var startVal = endVal; var endVal = temp; } switch (op) { case '<': res = endVal - startVal; break; case '<=': res = endVal + 1 - startVal; break; case '>': res = startVal - endVal; break; case '>=': res = startVal + 1 - endVal; break; } return this.BasicIteration(node, res, body); } else { throw { message: '지원하지 않는 표현식 입니다.', node: node, }; } }; p.BlockStatement = function(node) { var blocks = []; var body = node.body; for (var i = 0; i < body.length; i++) { var childNode = body[i]; var block = this[childNode.type](childNode); if (!block) { continue; } else if (block.type === undefined) { throw { message: '해당하는 블록이 없습니다.', node: childNode, }; } else if (block) blocks.push(block); } return blocks; }; p.EmptyStatement = function(node) { throw { message: 'empty는 지원하지 않는 표현식 입니다.', node: node, }; }; p.DebuggerStatement = function(node) { throw { message: 'debugger는 지원하지 않는 표현식 입니다.', node: node, }; }; p.WithStatement = function(node) { var object = node.object, body = node.body; throw { message: 'with는 지원하지 않는 표현식 입니다.', node: node, }; }; //control flow p.ReturnStaement = function(node) { var args = node.arguments; throw { message: 'return은 지원하지 않는 표현식 입니다.', node: node, }; }; p.LabeledStatement = function(node) { var label = node.label, body = node.body; throw { message: 'label은 지원하지 않는 표현식 입니다.', node: node, }; }; p.BreakStatement = function(node) { var label = node.label; throw { message: 'break는 지원하지 않는 표현식 입니다.', node: node, }; }; p.ContinueStatement = function(node) { var label = node.label; throw { message: 'continue는 지원하지 않는 표현식 입니다.', node: node, }; }; p.IfStatement = function(node) { var test = node.test, consequent = node.consequent, alternate = node.alternate; var blockType = this.syntax.IfStatement; if (!blockType) { return this.BasicIf(node); } else { throw { message: 'if는 지원하지 않는 표현식 입니다.', node: node, }; } }; p.SwitchStatement = function(node) { var discriminant = node.discriminant, cases = node.cases; throw { message: 'switch는 지원하지 않는 표현식 입니다.', node: node, }; }; p.SwitchCase = function(node) { var test = node.test, consequent = node.consequent; throw { message: 'switch ~ case는 지원하지 않는 표현식 입니다.', node: node, }; }; //throwstatement p.ThrowStatement = function(node) { var args = node.arguments; throw { message: 'throw는 지원하지 않는 표현식 입니다.', node: node, }; }; p.TryStatement = function(node) { var block = node.block, handler = node.handler, finalizer = node.finalizer; throw { message: 'try는 지원하지 않는 표현식 입니다.', node: node, }; }; p.CatchClause = function(node) { var param = node.param, body = node.body; throw { message: 'catch는 지원하지 않는 표현식 입니다.', node: node, }; }; p.WhileStatement = function(node) { var test = node.test, body = node.body; var blockType = this.syntax.WhileStatement; body = this[body.type](body); if (!blockType) { return this.BasicWhile(node, body); } else { throw { message: 'while은 지원하지 않는 표현식 입니다.', node: node, }; } }; p.DoWhileStatement = function(node) { var body = node.body, test = node.test; throw { message: 'do ~ while은 지원하지 않는 표현식 입니다.', node: node, }; }; p.ForInStatement = function(node) { var left = node.left, right = node.right, body = node.body; throw { message: 'for ~ in은 지원하지 않는 표현식 입니다.', node: node, }; }; //Declaration p.FunctionDeclaration = function(node) { var id = node.id; var blockType = this.syntax.FunctionDeclaration; if (!blockType) { return null; } else { throw { message: 'function은 지원하지 않는 표현식 입니다.', node: node, }; } }; p.VariableDeclaration = function(node) { var declaration = node.declarations, kind = node.kind; throw { message: 'var은 지원하지 않는 표현식 입니다.', node: node, }; }; // Expression p.ThisExpression = function(node) { return this.scope.this; }; p.ArrayExpression = function(node) { var elements = node.elements; throw { message: 'array는 지원하지 않는 표현식 입니다.', node: node, }; }; p.ObjectExpression = function(node) { var property = node.property; throw { message: 'object는 지원하지 않는 표현식 입니다.', node: node, }; }; p.Property = function(node) { var key = node.key, value = node.value, kind = node.kind; throw { message: 'init, get, set은 지원하지 않는 표현식 입니다.', node: node, }; }; p.FunctionExpression = function(node) { throw { message: 'function은 지원하지 않는 표현식 입니다.', node: node, }; }; // unary expression p.UnaryExpression = function(node) { var operator = node.operator, prefix = node.prefix, args = node.argument; throw { message: operator + '은(는) 지원하지 않는 명령어 입니다.', node: node, }; }; p.UnaryOperator = function() { return ['-', '+', '!', '~', 'typeof', 'void', 'delete']; }; p.updateOperator = function() { return ['++', '--']; }; //Binary expression p.BinaryOperator = function() { return [ '==', '!=', '===', '!==', '<', '<=', '>', '>=', '<<', '>>', '>>>', '+', '-', '*', '/', '%', ',', '^', '&', 'in', 'instanceof', ]; }; p.AssignmentExpression = function(node) { var operator = node.operator, left = node.left, right = node.right; throw { message: operator + '은(는) 지원하지 않는 명령어 입니다.', node: node, }; }; p.AssignmentOperator = function() { return [ '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=', ',=', '^=', '&=', ]; }; p.LogicalExpression = function(node) { var operator = node.operator, left = node.left, right = node.right; throw { message: operator + '은(는) 지원하지 않는 명령어 입니다.', node: node, }; }; p.LogicalOperator = function() { return ['||', '&&']; }; p.MemberExpression = function(node) { var object = node.object, property = node.property, computed = node.computed; console.log(object.type); object = this[object.type](object); console.log(object); property = this[property.type](property, object); if ( !( Object(object) === object && Object.getPrototypeOf(object) === Object.prototype ) ) { throw { message: object + '은(는) 잘못된 멤버 변수입니다.', node: node, }; } var blockType = property; if (!blockType) { throw { message: property + '이(가) 존재하지 않습니다.', node: node, }; } return blockType; }; p.ConditionalExpression = function(node) { var test = node.test, alternate = node.alternate, consequent = node.consequent; throw { message: '지원하지 않는 표현식 입니다.', node: node, }; }; p.UpdateExpression = function(node) { var operator = node.operator, args = node.argument, prefix = node.prefix; throw { message: operator + '은(는) 지원하지 않는 명렁어 입니다.', node: node, }; }; p.CallExpression = function(node) { var callee = node.callee, args = node.arguments; var blockType = this[callee.type](callee); return { type: blockType, }; }; p.NewExpression = function(node) { throw { message: 'new는 지원하지 않는 표현식 입니다.', node: node, }; }; p.SequenceExpression = function(node) { var expressions = node.expressions; throw { message: '지원하지 않는 표현식 입니다.', node: node, }; }; // scope method p.initScope = function(node) { if (this.scope === null) { var scoper = function() {}; scoper.prototype = this.syntax.Scope; this.scope = new scoper(); } else { var scoper = function() {}; scoper.prototype = this.scope; this.scope = new scoper(); } this.scopeChain.push(this.scope); return this.scanDefinition(node); }; p.unloadScope = function() { this.scopeChain.pop(); if (this.scopeChain.length) this.scope = this.scopeChain[this.scopeChain.length - 1]; else this.scope = null; }; p.scanDefinition = function(node) { var body = node.body; var separatedBlocks = []; for (var i = 0; i < body.length; i++) { var childNode = body[i]; if (childNode.type === 'FunctionDeclaration') { this.scope[childNode.id.name] = this.scope.promise; if (this.syntax.BasicFunction) { var childBody = childNode.body; separatedBlocks.push([ { type: this.syntax.BasicFunction, statements: [this[childBody.type](childBody)], }, ]); } } } return separatedBlocks; }; p.BasicFunction = function(node, body) { return null; }; // custom node parser p.BasicIteration = function(node, iterCount, body) { var blockType = this.syntax.BasicIteration; if (!blockType) throw { message: '지원하지 않는 표현식 입니다.', node: node, }; return { params: [iterCount], type: blockType, statements: [body], }; }; p.BasicWhile = function(node, body) { var raw = node.test.raw; if (this.syntax.BasicWhile[raw]) { return { type: this.syntax.BasicWhile[raw], statements: [body], }; } else { throw { message: '지원하지 않는 표현식 입니다.', node: node.test, }; } }; p.BasicIf = function(node) { var consequent = node.consequent; consequent = this[consequent.type](consequent); try { var test = ''; var operator = node.test.operator === '===' ? '==' : node.test.operator; if ( node.test.left.type === 'Identifier' && node.test.right.type === 'Literal' ) { test = node.test.left.name + ' ' + operator + ' ' + node.test.right.raw; } else if ( node.test.left.type === 'Literal' && node.test.right.type === 'Identifier' ) { test = node.test.right.name + ' ' + operator + ' ' + node.test.left.raw; } else { throw new Error(); } if (this.syntax.BasicIf[test]) { if ( !Array.isArray(consequent) && typeof consequent === 'object' ) consequent = [consequent]; return { type: this.syntax.BasicIf[test], statements: [consequent], }; } else { throw new Error(); } } catch (e) { throw { message: '지원하지 않는 표현식 입니다.', node: node.test, }; } }; })(Entry.JSParser.prototype); ================================================ FILE: src/parser-no/parser.js ================================================ /* * */ 'use strict'; Entry.Parser = function(mode, syntax, cm) { this._mode = mode; // maze ai workspace this.syntax = {}; this.codeMirror = cm; this._lang = syntax || 'js'; this.availableCode = []; if (mode === 'maze') { this._stageId = Number(Ntry.configManager.getConfig('stageId')); if (typeof NtryData == 'object') { var configCode = NtryData.config[this._stageId].availableCode; var playerCode = NtryData.player[this._stageId].code; this.setAvailableCode(configCode, playerCode); } } this.mappingSyntax(mode); switch (this._lang) { case 'js': this._parser = new Entry.JSParser(this.syntax); var syntax = this.syntax; var assistScope = {}; for (var key in syntax.Scope) { assistScope[key + '();\n'] = syntax.Scope[key]; } if ('BasicIf' in syntax) { assistScope['front'] = 'BasicIf'; } CodeMirror.commands.javascriptComplete = function(cm) { CodeMirror.showHint(cm, null, { globalScope: assistScope }); }; cm.on('keyup', function(cm, event) { if ( !cm.state.completionActive && (event.keyCode >= 65 && event.keyCode <= 95) ) { CodeMirror.showHint(cm, null, { completeSingle: false, globalScope: assistScope, }); } }); break; case 'block': this._parser = new Entry.BlockParser(this.syntax); break; } }; (function(p) { p.parse = function(code) { var result = null; switch (this._lang) { case 'js': try { var astTree = acorn.parse(code); result = this._parser.Program(astTree); } catch (error) { if (this.codeMirror) { var annotation; if (error instanceof SyntaxError) { annotation = { from: { line: error.loc.line - 1, ch: error.loc.column - 2, }, to: { line: error.loc.line - 1, ch: error.loc.column + 1, }, }; error.message = '문법 오류입니다.'; } else { annotation = this.getLineNumber( error.node.start, error.node.end ); annotation.message = error.message; annotation.severity = 'error'; this.codeMirror.markText( annotation.from, annotation.to, { className: 'CodeMirror-lint-mark-error', __annotation: annotation, clearOnEnter: true, } ); } Entry.toast.alert('Error', error.message); } result = []; } break; case 'block': var textCode = this._parser.Code(code); var textArr = textCode.match(/(.*{.*[\S|\s]+?}|.+)/g); if (Array.isArray(textArr)) { result = textArr.reduce(function(prev, current, index) { var temp = ''; if (index === 1) { prev = prev + '\n'; } if (current.indexOf('function') > -1) { temp = current + prev; } else { temp = prev + current; } return temp + '\n'; }); } else { result = ''; } break; } return result; }; p.getLineNumber = function(start, end) { var value = this.codeMirror.getValue(); var lines = { from: {}, to: {}, }; var startline = value.substring(0, start).split(/\n/gi); lines.from.line = startline.length - 1; lines.from.ch = startline[startline.length - 1].length; var endline = value.substring(0, end).split(/\n/gi); lines.to.line = endline.length - 1; lines.to.ch = endline[endline.length - 1].length; return lines; }; p.mappingSyntax = function(mode) { var types = Object.keys(Entry.block); for (var i = 0; i < types.length; i++) { var type = types[i]; var block = Entry.block[type]; if (block.mode === mode && this.availableCode.indexOf(type) > -1) { var syntaxArray = block.syntax; if (!syntaxArray) continue; var syntax = this.syntax; for (var j = 0; j < syntaxArray.length; j++) { var key = syntaxArray[j]; if ( j === syntaxArray.length - 2 && typeof syntaxArray[j + 1] === 'function' ) { syntax[key] = syntaxArray[j + 1]; break; } if (!syntax[key]) { syntax[key] = {}; } if (j === syntaxArray.length - 1) { syntax[key] = type; } else { syntax = syntax[key]; } } } } }; p.setAvailableCode = function(configCode, playerCode) { var availableList = []; configCode.forEach(function(items, i) { items.forEach(function(item, i) { availableList.push(item.type); }); }); if (playerCode instanceof Entry.Code) { var blocks = playerCode.getBlockList(); blocks.forEach(function(item) { if ( item.type !== NtryData.START && availableList.indexOf(item.type) === -1 ) availableList.push(item.type); }); } else { playerCode.forEach(function(items, i) { items.forEach(function(item, i) { if ( item.type !== NtryData.START && availableList.indexOf(item.type) === -1 ) { availableList.push(item.type); } }); }); } this.availableCode = this.availableCode.concat(availableList); }; })(Entry.Parser.prototype); ================================================ FILE: src/playground/block.js ================================================ 'use strict'; Entry.Block = class Block { schema = { id: null, x: 0, y: 0, type: null, params: [], statements: [], view: null, thread: null, movable: null, deletable: Entry.Block.DELETABLE_TRUE, emphasized: false, readOnly: null, copyable: true, assemble: true, events: {}, extensions: [], }; constructor(block, thread) { const that = this; Entry.Model(this, false); this._schema = null; this.defaultType = block.defaultType; if (block._backupParams) { this._backupParams = block._backupParams; } this.setThread(thread); this.load(block); const category = block.category; if (category) { this.category = category; const entryBlock = Entry.block[this.type]; if (entryBlock) { entryBlock.isFor = [`category_${category}`]; } } const code = this.getCode(); if (block.display !== undefined) { this.display = block.display; } code.registerBlock(this); if (code.object) { (this.events.dataAdd || []).forEach((fn) => { if (_.isFunction(fn)) { fn(that); } }); } const board = code.board; if ( Entry.getMainWS() && Entry.isTextMode && (!board || (board && board.constructor !== Entry.BlockMenu)) ) { (this.events.viewAdd || []).forEach((fn) => { if (_.isFunction(fn)) { fn.apply(that, [that]); } }); } if (block.comment) { this._comment = block.comment; } } get comment() { return this._comment; } load(block) { if (!block.id) { block.id = Entry.Utils.generateId(); } this.set(block); this.loadSchema(); } changeSchema(diff, changeData) { let params = []; if (changeData) { if (changeData.isRestore) { params = this._backupParams || []; delete this._backupParams; } else { switch (changeData.type) { case 'noChange': params = this.params; break; case 'cut': { const pos = changeData.pos; this.params.splice(pos); params = this.params; break; } case 'insert': { const startPos = changeData.startPos; const endPos = changeData.endPos; const schemaParams = Entry.block[this.type].params; params = new Array(schemaParams.length); for (let i = 0; i < startPos; i++) { params[i] = this.params[i]; } const adjust = endPos - startPos + 1; for (let i = endPos + 1; i < schemaParams.length; i++) { params[i] = this.params[i - adjust]; } break; } } } } params.forEach((p) => { if (p instanceof Entry.Block) { p.destroyView(); } }); this.set({ params }); this.loadSchema(); this.view && this.view.changeType(); } getSchema() { // for lazy loading if (!this._schema) { this.loadSchema(); } return this._schema; } loadSchema() { const that = this; this._schema = Entry.block[this.type]; if (!this._schema) { return; } const { changeEvent, paramsBackupEvent, destroyParamsBackupEvent } = this._schema; if (!this._schemaChangeEvent && changeEvent) { this._schemaChangeEvent = changeEvent.attach(this, this.changeSchema); } if (!this._paramsBackupEvent && paramsBackupEvent) { this._paramsBackupEvent = paramsBackupEvent.attach(this, this.paramsBackup); } if (!this._destroyParamsBackupEvent && destroyParamsBackupEvent) { this._destroyParamsBackupEvent = destroyParamsBackupEvent.attach( this, this.destroyParamsBackup ); } const events = this._schema.events; if (events) { for (const key in events) { if (!this.events[key]) { this.events[key] = []; } const funcs = events[key]; for (let i = 0; i < funcs.length; i++) { const func = funcs[i]; if (!func) { continue; } if (this.events[key].indexOf(func) < 0) { this.events[key].push(func); } } } } if (this._schema.event) { this.thread.registerEvent(this, this._schema.event); } const thisParams = this.params; const params = this._schema.params; for (let i = 0; params && i < params.length; i++) { let value = thisParams[i] === undefined || thisParams[i] === null ? params[i].value : thisParams[i]; const paramInjected = thisParams[i] || i < thisParams.length; if (value && (params[i].type === 'Output' || params[i].type === 'Block')) { if (typeof value !== 'object') { value = { type: 'number', params: [value], }; } value = new Entry.Block(value, this.thread); } if (paramInjected) { thisParams.splice(i, 1, value); } else { thisParams.push(value); } } const statements = this._schema.statements || []; for (let i = 0; i < statements.length; i++) { if (!(this.statements[i] instanceof Entry.Thread)) { this.statements.splice( i, 1, new Entry.Thread(this.statements[i], that.getCode(), this) ); } } return true; } changeType(type) { const _destroyFunc = _.partial(_.result, _, 'destroy'); _destroyFunc(this._schemaChangeEvent); _destroyFunc(this._backupEvent); _destroyFunc(this._destroyBackupEvent); this.set({ type }); this.loadSchema(); if (this.view) { this.view.changeType(type); } } setThread(thread) { this.set({ thread }); } getThread() { return this.thread; } getStatements() { return this.statements[0]; } insertAfter(blocks) { this.thread.insertByBlock(this, blocks); } _updatePos() { if (!this.view) { return; } this.set({ x: this.view.x, y: this.view.y, }); } moveTo(x, y) { if (this.view) { this.view.moveTo(x, y); } this._updatePos(); this.getCode().changeEvent.notify(); } createView(board, mode) { board = board || this.getCode().view.board; if (!this.view) { this.set({ view: new Entry.BlockView(this, board, mode), }); this._updatePos(); } if (this.comment) { const comment = this.comment; if (comment instanceof Entry.Comment) { if (!comment.svgGroup) { comment.createComment(board, comment.toJSON()); } } else { this.connectComment(new Entry.Comment(comment, board, this)); } } } destroyView() { _.result(this.view, 'destroy'); this.comment && this.comment.destroyView(); } clone(thread) { return new Entry.Block(this.toJSON(true), thread); } toJSON(isNew, excludeData = [], option = {}) { const jsonBlackList = ['view', 'thread', 'events']; const json = this._toJSON(); const view = this.view; if (isNew) { jsonBlackList.push('id'); } json.params = json.params.map((p, i) => { if (p instanceof Entry.Block) { return p.toJSON(isNew, excludeData, option); } else if ( option.captureDynamic && view.getParam(i) instanceof Entry.FieldDropdownDynamic ) { return view.getParam(i).getTextValue(); } else { return p; } }); const params = [isNew, undefined, excludeData, option]; json.statements = json.statements.map((s) => { return s.toJSON(...params); }); if (this._backupParams) { json._backupParams = this._backupParams.map(function (p) { if (p instanceof Entry.Block) { return p.toJSON(); } else { return p; } }); } if (this._comment) { let comment = this._comment; if (this._comment instanceof Entry.Comment) { comment = this._comment.toJSON(); delete comment.id; } json.comment = comment; } return Object.assign( _.omit(json, [...jsonBlackList, ...excludeData]), _.pick(this, ['x', 'y', 'movable', 'deletable', 'emphasized', 'readOnly']) ); } destroy(animate, next, isNotForce) { if (isNotForce && !this.isDeletable()) { return; } this.comment && this.comment.destroy && this.comment.destroy(); const blockType = this.getBlockType(); if (blockType === 'output' && !next) { const prevOutput = this.getPrevOutputBlock(); const nextOutput = this.getOutputBlock(); if (prevOutput) { this.separate(1); if (nextOutput) { nextOutput.separate(); nextOutput.doInsert(prevOutput.view._contents[1]); } } else if (nextOutput) { _.result(nextOutput.view, '_toGlobalCoordinate'); nextOutput.doInsert(this.getThread()); } } const that = this; const params = this.params || []; for (let i = 0; i < params.length; i++) { const param = params[i]; if (param instanceof Entry.Block) { param.doNotSplice = !(param.thread instanceof Entry.FieldOutput); param.destroy(animate); } } const statements = this.statements || []; for (let i = 0; i < statements.length; i++) { statements[i].destroy(animate); } const code = this.getCode(); code.unregisterBlock(this); const thread = this.getThread(); if (this._schema && this._schema.event) { thread.unregisterEvent(this, this._schema.event); } if (blockType === 'basic') { const prevBlock = this.getPrevBlock(); const nextBlock = this.getNextBlock(); if (nextBlock) { if (next) { nextBlock.destroy(animate, next); } else { const nextBlockView = nextBlock.view; if (!prevBlock) { if (thread.view) { const parent = thread.view.getParent(); const pConstructor = parent.constructor; if (pConstructor === Entry.FieldStatement) { nextBlockView && nextBlockView.bindPrev(parent); parent.insertTopBlock(nextBlock); } else if (pConstructor === Entry.FieldStatement) { nextBlock.replace(parent._valueBlock); } else { nextBlockView && nextBlockView._toGlobalCoordinate(); } } } else { nextBlockView && nextBlockView.bindPrev(prevBlock, true); } } } } const notSpliced = this.doNotSplice; if (!this.doNotSplice && thread.spliceBlock) { thread.spliceBlock(this); } else { delete this.doNotSplice; } this.view && this.view.destroy(animate); const _destroyFunc = _.partial(_.result, _, 'destroy'); _destroyFunc(this._schemaChangeEvent); _destroyFunc(this._paramsBackupEvent); _destroyFunc(this._destroyParamsBackupEvent); let events = []; if (code.object) { events = events.concat(this.events.dataDestroy || []); } const board = this.getCode().board; if ( Entry.getMainWS() && Entry.isTextMode && (!board || (board && board.constructor !== Entry.BlockMenu)) ) { events = events.concat(this.events.viewDestroy || []); } events.forEach((fn) => { if (_.isFunction(fn)) { fn.apply(that, [that, notSpliced]); } }); } getView() { return this.view; } setMovable(movable) { if (this.movable == movable) { return; } this.set({ movable }); } setCopyable(copyable) { if (this.copyable == copyable) { return; } this.set({ copyable }); } isMovable() { return this.movable; } isCopyable() { return this.copyable; } setDeletable(deletable) { if (this.deletable == deletable) { return; } this.set({ deletable }); } isDeletable() { const deletable = this.deletable; return deletable === Entry.Block.DELETABLE_TRUE || deletable === true; } isReadOnly() { return this.readOnly; } isCommentable() { const exclusion = ['basic_string_field', 'basic_boolean_field', 'basic_param']; const skeleton = this._schema && this._schema.skeleton; return !exclusion.includes(skeleton); } hasComment() { return '_comment' in this; } getCode() { return this.thread.getCode(); } // command func doAdd() { this.getCode().changeEvent.notify(); } doMove() { this._updatePos(); this.getCode().changeEvent.notify(); } doInsert(targetBlock) { if (this.getBlockType() === 'basic') { this.insert(targetBlock); } else { this.replace(targetBlock); } } doDestroy(animate) { this.destroy(animate); if (this.thread && this.thread.updateValueBlock) { this.thread.updateValueBlock(); } this.getCode().changeEvent.notify(); return this; } doDestroyBelow(animate) { this.destroy(animate, true); this.getCode().changeEvent.notify(); return this; } copy() { const thread = this.getThread(); const cloned = []; if (thread instanceof Entry.Thread) { const index = thread.getBlocks().indexOf(this); const json = thread.toJSON(true, index); for (let i = 0; i < json.length; i++) { cloned.push(json[i]); } } else { cloned.push(this.toJSON(true)); } const { x, y } = this.view.getAbsoluteCoordinate(); const block = cloned[0]; block.x = x + 15; block.y = y + 15; block.id = Entry.Utils.generateId(); return cloned; } copyToClipboard() { Entry.clipboard = this.copy(); } separate(count, index) { this.thread.separate(this, count, index); this._updatePos(); this.getCode().changeEvent.notify(); } doSeparate = this.separate; insert(targetBlock) { const blocks = this.thread.cut(this); if (targetBlock instanceof Entry.Thread) { targetBlock.insertByBlock(null, blocks); } else { targetBlock.insertAfter(blocks); } this._updatePos(); this.getCode().changeEvent.notify(); } replace(targetBlock) { if (!targetBlock) { console.error('replace error: target not exist'); return; } this.thread.cut(this); targetBlock.getThread().replace(this); this.getCode().changeEvent.notify(); } getPrevBlock() { return this.thread.getPrevBlock(this); } getNextBlock() { return this.thread.getNextBlock(this) || null; } getFirstBlock() { return this.thread.getFirstBlock(); } getLastBlock() { return this.thread.getLastBlock(); } getPrevOutputBlock() { const thread = this.thread; if (thread instanceof Entry.FieldOutput) { return thread._block; } return null; } getOutputBlock() { const params = this._schema.params; for (let i = 0; params && i < params.length; i++) { const paramDef = params[i]; if (paramDef.type === 'Output') { return this.params[i]; } } return null; } getTerminateOutputBlock() { let block = this; while (true) { const outputBlock = block.getOutputBlock(); if (!outputBlock) { return block; } block = outputBlock; } } getOutputBlockCount(count = 0) { const outputBlock = this.getOutputBlock(); if (outputBlock) { return outputBlock.getOutputBlockCount(count + 1); } else { return count; } } getBlockType() { if (!this.view) { return null; } const skeleton = Entry.skeleton[this._schema.skeleton]; if (!skeleton.magnets) { return null; } const magnet = skeleton.magnets(this.view); if (magnet.next || magnet.previous) { return 'basic'; } else if (magnet.boolean || magnet.string) { return 'field'; } else if (magnet.output || magnet.param) { return 'output'; } else { return null; } } indexOfStatements(statement) { return this.statements.indexOf(statement); } pointer(pointer = []) { return this.thread.pointer(pointer, this); } targetPointer() { const pointer = this.thread.pointer([], this); if (pointer.length === 4 && pointer[3] === 0) { pointer.pop(); } else if (pointer[pointer.length - 2] > -1) { if (pointer[pointer.length - 1] === 0) { pointer.pop(); } else { pointer[pointer.length - 1] = pointer[pointer.length - 1] - 1; } } return pointer; } getDataByPointer(pointer) { pointer = pointer.concat(); const data = this.params[pointer.shift()]; if (pointer.length) { if (data.getDataByPointer) { return data.getDataByPointer(pointer); } else { return null; } } else { return data; } } getBlockList(excludePrimitive, type) { const blocks = []; const currentType = type || this.type; if (!this._schema && !this.loadSchema()) { return blocks; } if (excludePrimitive && this._schema.isPrimitive) { return blocks; } currentType === this.type && blocks.push(this); return [...this.params, ...this.statements].reduce((blocks, value) => { const constructor = value && value.constructor; if (constructor !== Entry.Block && constructor !== Entry.Thread) { return blocks; } return blocks.concat(value.getBlockList(excludePrimitive, type)); }, blocks); } stringify(excludeData) { return JSON.stringify(this.toJSON(false, excludeData)); } isInOrigin() { return this.x === 0 && this.y === 0; } isSameParamWith(target) { if (target.type.substr(0, 8) === 'wildcard' || this.type.substr(0, 8) === 'wildcard') { return true; } const targetType = target.type; const thisType = this.type; if ( (targetType === 'number' && thisType === 'positive_number') || (targetType === 'number' && thisType === 'negative_number') || (targetType === 'angle' && thisType === 'text') || (targetType === 'text' && thisType === 'angle') ) { } else if (targetType !== thisType) { return false; } for (let i = 0; i < this.params.length; i++) { const param = this.params[i]; if (param instanceof Entry.Block) { if (!param.isSameParamWith(target.params[i])) { return false; } } else { let l = this.params[i]; let r = target.params[i]; //entry-js로 변경되며서 null로 오던 것이 undefined로 와서 맞춰 줌. if (l === undefined) l = null; l = typeof l === 'number' ? `${l}` : l; r = typeof r === 'number' ? `${r}` : r; if (l === 'positive') { return r > 0; } else if (l === 'negative') { return r < 0; } else if (l !== r) { return false; } } } return true; } paramsBackup() { //do not backup params for blockMenu block if (_.result(this.view, 'isInBlockMenu')) { return; } this._backupParams = this.params.slice(); } destroyParamsBackup() { this._backupParams = null; } getDom(query = []) { if (_.isEmpty(query)) { return this.view.svgGroup; } query = [...query]; const key = query.shift(); if (key === 'magnet') { return this.view.getMagnet(query); } } getParam(index) { return this.params[index]; } isParamBlockType() { return /^(basic_string_field|basic_boolean_field)$/.test(this._schema.skeleton); } getFuncId() { const ret = /func_(.*)/.exec(this.type); if (!ret) { return; } return ret[1]; } getRootBlock() { let block = this; while (block) { const thread = block.getThread(); const parent = thread.parent; if (!parent) { //field block block = thread._block; } else if (parent instanceof Entry.Code) { //thread block = thread.getFirstBlock(); break; } else if (parent instanceof Entry.Block) { //statement block = thread.parent; } else if (parent instanceof Entry.FieldBlock) { break; } else { block = undefined; } } return block; } connectComment(comment) { this._comment = comment; } disconnectComment() { delete this._comment; } getCommentValue() { return this._comment && this._comment.value; } }; Entry.Block.MAGNET_RANGE = 10; Entry.Block.MAGNET_OFFSET = 0.4; Entry.Block.DELETABLE_TRUE = 1; Entry.Block.DELETABLE_FALSE = 2; Entry.Block.DELETABLE_FALSE_LIGHTEN = 3; ================================================ FILE: src/playground/block_entry.js ================================================ 'use strict'; import DataTable from '../class/DataTable'; const { getStateOptions, getCityOptions, locationData } = require('../util/location'); if (typeof global.Entry !== 'object') { global.Entry = {}; } if (typeof exports === 'object') { /* IGNORE_WEBPACK:START */ const Lang = require('../../extern/lang/ko.js').Lang; global.Lang = Lang; /* IGNORE_WEBPACK:END */ if (typeof EntryStatic !== 'object') { global.EntryStatic = {}; } } if (!Entry.block) { Entry.block = {}; } function getConverters() { const c = {}; c.keyboardCode = function (key, value) { let code; if (key) { code = key.toUpperCase(); } const map = { 32: 'space', 13: 'enter', 38: 'up', 37: 'left', 39: 'right', 40: 'down', }; code = map[value] || code || value; if (!Entry.Utils.isNumber(code)) { return code; } else { return '"()"'.replace('"()"', code); } }; c.returnStringKey = function (key, value) { if ((!value && typeof value !== 'number') || value === 'null') { return 'None'; } key = String(key); if (value === 'mouse') { key = 'mouse'; } const name = Entry.TextCodingUtil.dropdownDynamicIdToNameConvertor(value, this.menuName); if (name) { key = name; } if (this.codeMap) { var codeMap = eval(this.codeMap); } const codeMapKey = value; if (codeMap) { const codeMapValue = codeMap[codeMapKey]; if (codeMapValue) { key = codeMapValue; } } key = key.replace(/\"/gi, ''); return '"()"'.replace('()', key); }; c.returnRawStringKey = function (key, value) { if ((!value && typeof value !== 'number') || value === 'null') { return 'None'; } key = String(key); if (value === 'mouse') { key = value; } const name = Entry.TextCodingUtil.dropdownDynamicIdToNameConvertor(value, this.menuName); if (name) { key = name; } key = key.replace(/\"/gi, ''); return '"()"'.replace('"()"', key); }; c.returnStringValue = function (key, value) { if ((!value && typeof value !== 'number') || value === 'null') { return 'None'; } if (this.codeMap) { var codeMap = eval(this.codeMap); } const codeMapKey = value; if (codeMap) { const codeMapValue = codeMap[codeMapKey]; if (codeMapValue) { value = codeMapValue; } } return '"()"'.replace('()', value); }; c.returnOperator = function (key, value) { const map = { EQUAL: '==', GREATER: '>', LESS: '<', GREATER_OR_EQUAL: '>=', LESS_OR_EQUAL: '<=', PLUS: '+', MINUS: '-', MULTI: '*', DIVIDE: '/', NOT_EQUAL: '!=', '!=': 'NOT_EQUAL', '==': 'EQUAL', '>': 'GREATER', '<': 'LESS', '>=': 'GREATER_OR_EQUAL', '<=': 'LESS_OR_EQUAL', '+': 'PLUS', '-': 'MINUS', '*': 'MULTI', '/': 'DIVIDE', AND: 'and', OR: 'or', QUOTIENT: '//', MOD: '%', }; return map[value]; }; c.returnRawNumberValueByKey = function (key, value) { //return String(key).replace(/\D/, ''); return key; }; c.returnStringOrNumberByValue = function (key, value) { if (!Entry.Utils.isNumber(value)) { value = value.replace(/\"/gi, ''); return '"()"'.replace('()', value); } else { return value; } }; c.returnObjectOrStringValue = function (key, value) { if (Entry.container && Entry.container.getObject(value)) { const objectName = Entry.container.getObject(value).name; return '"()"'.replace('()', objectName); } else { if (this.codeMap) { var codeMap = eval(this.codeMap); } const codeMapKey = value; if (codeMap) { const codeMapValue = codeMap[codeMapKey]; if (codeMapValue) { value = codeMapValue; } } value = value.replace(/\"/gi, ''); return '"()"'.replace('()', value); } }; c.returnStringValueUpperCase = function (key, value) { if (this.codeMap) { var codeMap = eval(this.codeMap); } const codeMapKey = value; if (codeMap) { const codeMapValue = codeMap[codeMapKey]; if (codeMapValue) { value = codeMapValue; } } return '"()"'.replace('()', value).toUpperCase(); }; c.returnValueUpperCase = function (key, value) { if (this.codeMap) { var codeMap = eval(this.codeMap); } const codeMapKey = value; if (codeMap) { const codeMapValue = codeMap[codeMapKey]; if (codeMapValue) { value = codeMapValue; } } return value.toUpperCase(); }; c.returnStringValueLowerCase = function (key, value) { if (this.codeMap) { var codeMap = eval(this.codeMap); } const codeMapKey = value; if (codeMap) { const codeMapValue = codeMap[codeMapKey]; if (codeMapValue) { value = codeMapValue; } } return '"()"'.replace('()', value).toLowerCase(); }; c.returnValuePartialUpperCase = function (key, value) { if (this.codeMap) { var codeMap = eval(this.codeMap); } const codeMapKey = value; if (codeMap) { const codeMapValue = codeMap[codeMapKey]; if (codeMapValue) { value = codeMapValue; } } const dot = value.indexOf('.') + 1; if (dot > 1) { return ( value.charAt(0).toUpperCase() + value.substring(1, dot) + value.substring(dot).toUpperCase() ); } else { return value.toUpperCase(); } }; return c; } const blocks = require('./blocks'); function getBlocks() { return { aiUtilizeModelTrainButton: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, isNotFor: ['functionInit'], params: [ { type: 'Text', text: Lang.template.load_ai_utilize_train_block, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], def: { type: 'aiUtilizeModelTrainButton', }, events: { mousedown: [ function () { Entry.aiLearning.openManager(); }, ], }, }, aiUtilizeBlockAddButton: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, isNotFor: ['functionInit'], params: [ { type: 'Text', text: Lang.template.load_ai_utilize_block, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], def: { type: 'aiUtilizeBlockAddButton', }, events: { mousedown: [ function () { Entry.do('playgroundClickAddAIUtilizeBlock'); }, ], }, }, expansionBlockAddButton: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, isNotFor: ['functionInit'], params: [ { type: 'Text', text: Lang.template.load_expansion_block, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], def: { type: 'expansionBlockAddButton', }, events: { mousedown: [ function () { Entry.do('playgroundClickAddExpansionBlock'); }, ], }, }, arduino_lite_connect: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', isNotFor: ['arduinoLiteSupported'], class: 'arduino_default_not_installed', params: [ { type: 'Text', text: Lang.Blocks.arduino_lite_connect, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], events: { mousedown: [ function () { Entry.do('playgroundClickAddHardwareLiteBlock'); }, ], }, }, arduino_lite_guide: { skeleton: 'clickable_text', skeletonOptions: { box: { offsetX: 3, }, }, color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', isNotFor: ['arduinoLiteGuide'], class: 'arduino_default', params: [ { type: 'Text', text: Lang.Blocks.arduino_lite_guide, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], events: { mousedown: [ function () { window.open( 'https://docs.playentry.org/user/block_hardware.html#POINT-%EC%95%84%EB%91%90%EC%9D%B4%EB%85%B8-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0' ); }, ], }, }, arduino_lite_reconnect: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', isNotFor: ['arduinoLiteConnectFailed'], class: 'arduino_default', params: [ { type: 'Text', text: Lang.Blocks.arduino_lite_reconnect, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], events: { mousedown: [ function () { Entry.hwLite.connect(); }, ], }, }, arduino_lite_download_firmware: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', isNotFor: ['arduinoLiteConnectFailed'], class: 'arduino_default', params: [ { type: 'Text', text: Lang.Blocks.arduino_lite_download_firmware, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], events: { mousedown: [], }, }, arduino_lite_disconnect: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', isNotFor: ['arduinoLiteConnectFailed', 'arduinoLiteConnected'], class: 'arduino_default', params: [ { type: 'Text', text: Lang.Blocks.arduino_lite_disconnect, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], events: { mousedown: [ function () { Entry.hwLite.removeHardwareLiteModule(); }, ], }, }, hardware_device_name_title: { skeleton: 'basic_text_light', color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', params: [ { type: 'Text', text: Lang.Blocks.hardware_device_name_title, color: EntryStatic.colorSet.common.TEXT, align: 'center', fontWeight: '100', }, ], class: 'hardware_device_info', isNotFor: [ 'arduinoConnect', 'arduinoConnected', 'arduinoLiteConnectFailed', 'arduinoLiteConnected', ], events: {}, }, hardware_device_name_title_robot: { parent: 'hardware_device_name_title', params: [ { type: 'Text', text: Lang.Blocks.hardware_device_name_title_robot, color: EntryStatic.colorSet.common.TEXT, align: 'center', fontWeight: '100', }, ], isNotFor: [ 'arduinoConnect', 'arduinoConnected', 'arduinoLiteConnectFailed', 'arduinoLiteConnected', ], }, hardware_device_name_title_sensor: { parent: 'hardware_device_name_title_robot', }, hardware_device_name_title_motor: { parent: 'hardware_device_name_title_robot', }, hardware_device_name_title_led: { parent: 'hardware_device_name_title_robot', }, hardware_device_name_title_melody: { parent: 'hardware_device_name_title_robot', }, hardware_device_name_content: { skeleton: 'basic_text', skeletonOptions: { box: { offsetY: 10, }, }, color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', params: [ { type: 'Text', text: Lang.Blocks.hardware_device_name_content, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], class: 'hardware_device_info', isNotFor: [ 'arduinoConnect', 'arduinoConnected', 'arduinoLiteConnectFailed', 'arduinoLiteConnected', ], events: {}, }, hardware_device_name_content_sensor: { parent: 'hardware_device_name_content', }, hardware_device_name_content_motor: { parent: 'hardware_device_name_content', }, hardware_device_name_content_led: { parent: 'hardware_device_name_content', }, hardware_device_name_content_melody: { parent: 'hardware_device_name_content', }, hardware_connected_noti: { skeleton: 'basic_text', skeletonOptions: { box: { offsetY: 10, }, }, color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', params: [ { type: 'Text', text: Lang.Blocks.hardware_connected_noti, color: EntryStatic.colorSet.common.ALERT, align: 'center', }, ], class: 'hardware_device_alert', isNotFor: ['arduinoConnect'], events: {}, }, arduino_lite_connected_noti: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', params: [ { type: 'Text', text: Lang.Blocks.arduino_lite_connected_noti, color: EntryStatic.colorSet.common.GRAY, align: 'center', }, ], def: { type: 'arduino_lite_connected_noti', }, class: 'hardware_device_info', isNotFor: ['arduinoLiteConnectFailed', 'arduinoLiteConnected'], events: {}, }, arduino_lite_alert: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', params: [ { type: 'Text', text: Lang.Blocks.arduino_lite_alert, color: EntryStatic.colorSet.common.ALERT, align: 'center', }, ], def: { type: 'arduino_lite_alert', }, class: 'arduino_lite_alert', isNotFor: ['arduinoLiteConnectFailed'], events: {}, }, arduino_noti: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', params: [ { type: 'Text', text: Lang.Blocks.arduino_noti_text, color: EntryStatic.colorSet.common.GRAY, align: 'center', }, ], def: { type: 'arduino_noti', }, class: 'arduino_default_noti', isNotFor: ['arduinoDisconnected'], events: {}, }, arduino_connected: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, isNotFor: ['arduinoConnected'], params: [ { type: 'Text', text: Lang.Blocks.ARDUINO_connected, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], events: {}, }, arduino_reconnect: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, isNotFor: ['arduinoDisconnected'], params: [ { type: 'Text', text: Lang.Blocks.ARDUINO_reconnect, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], class: 'arduino_default_installed', events: { mousedown: [ function () { Entry.hw.retryConnect(); }, ], }, }, robot_connect_helper: { skeleton: 'clickable_text', skeletonOptions: { box: { offsetY: -10, }, }, template: '%1%2', isNotFor: ['arduinoDisconnected'], color: EntryStatic.colorSet.common.TRANSPARENT, class: 'arduino_guide', params: [ { type: 'Indicator', img: 'question_in_round.svg', size: 9, position: { x: -45, y: 0, }, }, { type: 'Text', text: Lang.Blocks.ROBOT_connect_helper, color: EntryStatic.colorSet.common.BUTTON, align: 'center', fontSize: 13, }, ], events: { mousedown: [ function () { window.open('https://docs.playentry.org/user/block_hardware.html'); }, ], }, }, robot_noti: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', params: [ { type: 'Text', text: Lang.Blocks.robot_noti_text, color: EntryStatic.colorSet.common.GRAY, align: 'center', }, ], def: { type: 'robot_noti', }, class: 'arduino_default_noti', isNotFor: ['arduinoDisconnected'], events: {}, }, robot_reconnect: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, isNotFor: ['arduinoDisconnected'], template: '%1', params: [ { type: 'Text', text: Lang.Blocks.ROBOT_reconnect, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], events: { mousedown: [ function () { Entry.hw.retryConnect(); }, ], }, }, hardware_connect_helper: { skeleton: 'clickable_text', skeletonOptions: { box: { offsetY: -10, }, }, template: '%1%2', isNotFor: ['arduinoDisconnected'], color: EntryStatic.colorSet.common.TRANSPARENT, class: 'arduino_guide', params: [ { type: 'Indicator', img: 'question_in_round.svg', size: 9, position: { x: -55, y: 0, }, }, { type: 'Text', text: Lang.Blocks.hardware_connect_helper, color: EntryStatic.colorSet.common.BUTTON, align: 'center', fontSize: 13, }, ], events: { mousedown: [ function () { window.open('https://docs.playentry.org/user/block_hardware.html'); }, ], }, }, hardware_noti_installed: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', params: [ { type: 'Text', text: Lang.Blocks.hardware_noti_installed, color: EntryStatic.colorSet.common.TEXT, align: 'center', fontSize: 14, }, ], class: 'arduino_default_installed', isNotFor: ['arduinoDisconnected'], events: {}, }, arduino_open: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, isNotFor: ['arduinoDisconnected'], template: '%1', params: [ { type: 'Text', text: Lang.Blocks.ARDUINO_open_connector, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], class: 'arduino_default_installed', events: { mousedown: [ function () { Entry.hw.openHardwareProgram(); }, ], }, }, hardware_program_download: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, isNotFor: ['arduinoDisconnected'], template: '%1', params: [ { type: 'Text', text: Lang.Blocks.hardware_program_download, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], class: 'arduino_default_installed', events: { mousedown: [ function () { Entry.hw.downloadConnector(); }, ], }, }, hardware_noti_not_installed: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, template: '%1', params: [ { type: 'Text', text: Lang.Blocks.hardware_noti_not_installed, color: EntryStatic.colorSet.common.TEXT, align: 'center', fontSize: 14, }, ], class: 'arduino_default_not_installed', isNotFor: ['arduinoDisconnected'], events: {}, }, arduino_cloud_pc_open: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, isNotFor: ['arduinoConnect', 'arduinoConnected'], template: '%1', params: [ { type: 'Text', text: Lang.Blocks.ARDUINO_cloud_pc_connector, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], class: 'arduino_default', events: { mousedown: [ function () { Entry.hw.openHardwareProgram(); }, ], }, }, //endregion hardware 하드웨어 기본 //region basic 기본블록 change_opacity: { color: EntryStatic.colorSet.block.default.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/brush_03.png', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, ], type: 'change_opacity', }, paramsKeyMap: { VALUE: 0, }, class: 'brush_opacity', isNotFor: ['textBox'], func(sprite, script) { let opacity = script.getNumberValue('VALUE', script); if (!sprite.brush || !sprite.shapes.length) { Entry.setBasicBrush(sprite); sprite.brush.stop = true; } opacity = Entry.adjustValueWithMaxMin(sprite.brush.opacity + opacity, 0, 100); if (sprite.brush) { sprite.brush.opacity = opacity; sprite.brush.endStroke(); const rgb = sprite.brush.rgb; sprite.brush.beginStroke( `rgba(${rgb.r},${rgb.g},${rgb.b},${sprite.brush.opacity / 100})` ); sprite.brush.moveTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: [''] }, }, set_opacity: { color: EntryStatic.colorSet.block.default.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/brush_03.png', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['50'], }, null, ], type: 'set_opacity', }, paramsKeyMap: { VALUE: 0, }, class: 'brush_opacity', isNotFor: ['textBox'], func(sprite, script) { const opacity = script.getNumberValue('VALUE', script); if (!sprite.brush || !sprite.shapes.length) { Entry.setBasicBrush(sprite); sprite.brush.stop = true; } if (sprite.brush) { sprite.brush.opacity = Entry.adjustValueWithMaxMin(opacity, 0, 100); sprite.brush.endStroke(); const rgb = sprite.brush.rgb; sprite.brush.beginStroke( `rgba(${rgb.r},${rgb.g},${rgb.b},${sprite.brush.opacity / 100})` ); sprite.brush.moveTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: [''] }, }, number: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextInput', value: 10, }, ], events: {}, def: { params: [], }, paramsKeyMap: { NUM: 0, }, func(sprite, script) { return script.getField('NUM', script); }, isPrimitive: true, syntax: { js: ['Scope', '%1'], py: [ { syntax: '%1', keyOption: 'number', textParams: [ { type: 'TextInput', converter: Entry.block.converters.returnStringOrNumberByValue, }, ], }, ], }, }, angle: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextInput', value: 90, }, ], events: {}, def: { params: [null], type: 'angle', }, paramsKeyMap: { ANGLE: 0, }, func(sprite, script) { return script.getNumberField('ANGLE'); }, isPrimitive: true, syntax: { js: [], py: [ { syntax: '%1', keyOption: 'angle', textParams: [ { type: 'Angle', converter: Entry.block.converters.returnRawNumberValueByKey, }, ], }, ], }, }, color: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Color', }, ], events: {}, def: { params: [null], type: 'color', }, paramsKeyMap: { VALUE: 0, }, func(sprite, script) { return script.getField('VALUE'); }, syntax: { js: [], py: [ { syntax: '%1', keyOption: 'color', textParams: [ { type: 'Color', converter: Entry.block.converters.returnStringValueUpperCase, codeMap: 'Entry.CodeMap.Entry.set_color[0]', }, ], }, ], }, }, text_color: { template: Lang.template.color, color: EntryStatic.colorSet.block.default.TEXT, outerLine: EntryStatic.colorSet.block.darken.TEXT, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Color', }, ], events: {}, def: { params: [null], type: 'text_color', }, paramsKeyMap: { VALUE: 0, }, func(sprite, script) { return script.getField('VALUE'); }, syntax: { js: [], py: [ { syntax: '%1', keyOption: 'text_color', textParams: [ { type: 'Color', converter: Entry.block.converters.returnStringValueUpperCase, codeMap: 'Entry.CodeMap.Entry.set_text_color[0]', }, ], }, ], }, }, get_x_coordinate: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_get_x_coordinate, color: '#3D3D3D', }, ], events: {}, def: { params: [null], type: 'get_x_coordinate', }, class: 'calc', isNotFor: [], func(sprite, script) { return sprite.getX(); }, syntax: { js: [], py: [''] }, }, get_y_coordinate: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_get_y_coordinate, color: '#3D3D3D', }, ], events: {}, def: { params: [null], type: 'get_y_coordinate', }, class: 'calc', isNotFor: [], func(sprite, script) { return sprite.getY(); }, syntax: { js: [], py: [''] }, }, get_angle: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_get_angle, color: '#3D3D3D', }, ], events: {}, def: { params: [null], }, func(sprite, script) { return parseFloat(sprite.getRotation().toFixed(1)); }, syntax: { js: [], py: [''] }, }, get_rotation_direction: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.CALC_rotation_value, 'ROTATION'], [Lang.Blocks.CALC_direction_value, 'DIRECTION'], ], value: 'ROTATION', fontSize: 11, }, ], events: {}, def: { params: [null], type: 'get_rotation_direction', }, paramsKeyMap: { OPERATOR: 0, }, class: 'calc', isNotFor: [], func(sprite, script) { const o = script.getField('OPERATOR', script); if (o.toUpperCase() == 'DIRECTION') { return parseFloat(sprite.getDirection().toFixed(1)); } else { return parseFloat(sprite.getRotation().toFixed(1)); } }, syntax: { js: [], py: [''] }, }, calc_plus: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Text', text: '+', color: '#3D3D3D', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [null], }, paramsKeyMap: { LEFTHAND: 0, RIGHTHAND: 2, }, func(sprite, script) { const leftValue = script.getNumberValue('LEFTHAND', script); const rightValue = script.getNumberValue('RIGHTHAND', script); return leftValue + rightValue; }, syntax: { js: [], py: [''] }, }, calc_minus: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Text', text: '-', color: '#3D3D3D', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [null], }, paramsKeyMap: { LEFTHAND: 0, RIGHTHAND: 2, }, func(sprite, script) { const leftValue = script.getNumberValue('LEFTHAND', script); const rightValue = script.getNumberValue('RIGHTHAND', script); return leftValue - rightValue; }, syntax: { js: [], py: [''] }, }, calc_times: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Text', text: 'x', color: '#3D3D3D', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [null], }, paramsKeyMap: { LEFTHAND: 0, RIGHTHAND: 2, }, func(sprite, script) { const leftValue = script.getNumberValue('LEFTHAND', script); const rightValue = script.getNumberValue('RIGHTHAND', script); return leftValue * rightValue; }, syntax: { js: [], py: [''] }, }, calc_divide: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Text', text: '/', color: '#3D3D3D', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [null], }, paramsKeyMap: { LEFTHAND: 0, RIGHTHAND: 2, }, func(sprite, script) { const leftValue = script.getNumberValue('LEFTHAND', script); const rightValue = script.getNumberValue('RIGHTHAND', script); return leftValue / rightValue; }, syntax: { js: [], py: [''] }, }, calc_mod: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Text', text: '/', color: '#3D3D3D', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_calc_mod_3, color: '#3D3D3D', }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, { type: 'number', params: ['10'], }, null, ], type: 'calc_mod', }, paramsKeyMap: { LEFTHAND: 0, RIGHTHAND: 2, }, class: 'calc', isNotFor: [], func(sprite, script) { const leftValue = script.getNumberValue('LEFTHAND', script); const rightValue = script.getNumberValue('RIGHTHAND', script); return leftValue % rightValue; }, syntax: { js: [], py: ['Entry.get_remainder(%1, %3)'] }, }, calc_share: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Text', text: '/', color: '#3D3D3D', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: '의 몫', color: '#3D3D3D', }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, { type: 'number', params: ['10'], }, null, ], type: 'calc_share', }, paramsKeyMap: { LEFTHAND: 0, RIGHTHAND: 2, }, class: 'calc', isNotFor: [], func(sprite, script) { const leftValue = script.getNumberValue('LEFTHAND', script); const rightValue = script.getNumberValue('RIGHTHAND', script); return Math.floor(leftValue / rightValue); }, syntax: { js: [], py: [''] }, }, reset_project_timer: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic', statements: [], params: [ { type: 'Text', text: '초시계 초기화', color: '#3D3D3D', }, ], events: { viewAdd: [ function () { if (Entry.engine) { Entry.engine.showProjectTimer(); } }, ], viewDestroy: [ function (block, notIncludeSelf) { if (Entry.engine) { Entry.engine.hideProjectTimer(block, notIncludeSelf); } }, ], }, def: { params: [null], type: 'reset_project_timer', }, class: 'calc_timer', isNotFor: [], func(sprite, script) { Entry.engine.updateProjectTimer(0); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, set_visible_project_timer: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_timer_visible_1, color: '#000', }, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_timer_visible_show, 'SHOW'], [Lang.Blocks.CALC_timer_visible_hide, 'HIDE'], ], value: 'SHOW', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.CALC, }, { type: 'Text', text: Lang.Blocks.CALC_timer_visible_2, color: '#000', }, { type: 'Indicator', img: 'block_icon/calc_01.png', size: 12, }, ], events: { viewAdd: [ function () { if (Entry.engine) { Entry.engine.showProjectTimer(); } }, ], viewDestroy: [ function (block, notIncludeSelf) { if (Entry.engine) { Entry.engine.hideProjectTimer(block, notIncludeSelf); } }, ], }, def: { params: [null, 'HIDE', null, null], type: 'set_visible_project_timer', }, pyHelpDef: { params: [null, 'A&value', null, null], type: 'set_visible_project_timer', }, paramsKeyMap: { ACTION: 1, }, class: 'calc_timer', isNotFor: [], func(sprite, script) { const action = script.getField('ACTION'); const timer = Entry.engine.projectTimer; if (action === 'SHOW') { timer.setVisible(true); } else { timer.setVisible(false); } return script.callReturn(); }, syntax: { js: [], py: [ { template: '%1 %2 %3', syntax: 'Entry.timer_view(%2)', textParams: [ { type: 'Text', text: 'Entry.timer_view(', color: '#000', }, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_timer_visible_show, 'SHOW'], [Lang.Blocks.CALC_timer_visible_hide, 'HIDE'], ], value: 'SHOW', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.CALC, converter: Entry.block.converters.returnStringValueLowerCase, codeMap: 'Entry.CodeMap.Entry.set_visible_project_timer[1]', }, { type: 'Text', text: ')', color: '#000', }, ], }, ], }, }, timer_variable: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: '초시계 값', color: '#3D3D3D', }, { type: 'Text', text: ' ', color: '#3D3D3D', }, ], events: {}, def: { params: [null, null], }, func(sprite, script) { return Entry.container.inputValue.getValue(); }, syntax: { js: [], py: [''] }, }, stop_run: { color: EntryStatic.colorSet.block.default.FLOW, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/flow_03.png', size: 12, }, ], events: {}, def: { params: [null], }, func(sprite, script) { return Entry.engine.toggleStop(); }, syntax: { js: [], py: [''] }, }, //endregion basic 기본블록 //region basic 기본 change_to_nth_shape: { color: EntryStatic.colorSet.block.default.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'pictures', fontSize: 11, }, { type: 'Indicator', img: 'block_icon/looks_03.png', size: 12, }, ], events: {}, def: { params: [null, null], type: 'change_to_nth_shape', }, paramsKeyMap: { VALUE: 0, }, class: 'shape', isNotFor: [], func(sprite, script) { const imageId = script.getField('VALUE', script); const picture = sprite.parent.getPicture(imageId); sprite.setImage(picture); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, set_effect_volume: { color: EntryStatic.colorSet.block.default.LOOKS, skeleton: 'basic', statements: [], deprecated: true, params: [ { type: 'Dropdown', options: [ [Lang.Blocks.color, 'color'], [Lang.Blocks.brightness, 'brightness'], [Lang.Blocks.opacity, 'opacity'], ], value: 'color', fontSize: 11, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/looks_03.png', size: 12, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['10'], }, null, ], type: 'set_effect_volume', }, paramsKeyMap: { EFFECT: 0, VALUE: 1, }, class: 'effect', isNotFor: ['textBox'], func(sprite, script) { const effect = script.getField('EFFECT', script); const effectValue = script.getNumberValue('VALUE', script); let effectName = ''; if (effect === 'color') { sprite.effect.hue = effectValue + sprite.effect.hue; effectName = 'hue'; } else if (effect === 'lens') { } else if (effect === 'swriling') { } else if (effect === 'pixel') { } else if (effect === 'mosaic') { } else if (effect === 'brightness') { sprite.effect.brightness = effectValue + sprite.effect.brightness; effectName = 'brightness'; } else if (effect === 'blur') { } else if (effect === 'opacity') { sprite.effect.alpha = sprite.effect.alpha + effectValue / 100; effectName = 'alpha'; } sprite.applyFilter(true, [effectName]); return script.callReturn(); }, syntax: { js: [], py: ['Entry.set_effect_volume(%1, %2)'] }, }, set_effect: { color: EntryStatic.colorSet.block.default.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.color, 'color'], [Lang.Blocks.brightness, 'brightness'], [Lang.Blocks.opacity, 'opacity'], ], value: 'color', fontSize: 11, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/looks_03.png', size: 12, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['100'], }, null, ], type: 'set_effect', }, paramsKeyMap: { EFFECT: 0, VALUE: 1, }, class: 'effect', isNotFor: ['textBox'], func(sprite, script) { const effect = script.getField('EFFECT', script); const effectValue = script.getNumberValue('VALUE', script); let effectName = ''; if (effect == 'color') { sprite.effect.hue = effectValue; effectName = 'hue'; } else if (effect == 'lens') { } else if (effect == 'swriling') { } else if (effect == 'pixel') { } else if (effect == 'mosaic') { } else if (effect == 'brightness') { sprite.effect.brightness = effectValue; effectName = 'brightness'; } else if (effect == 'blur') { } else if (effect == 'opacity') { sprite.effect.alpha = effectValue / 100; effectName = 'alpha'; } sprite.applyFilter(true, [effectName]); return script.callReturn(); }, syntax: { js: [], py: ['Entry.set_effect(%1, %2)'] }, }, change_scale_percent: { color: EntryStatic.colorSet.block.default.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/looks_03.png', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, ], type: 'change_scale_percent', }, paramsKeyMap: { VALUE: 0, }, class: 'scale', isNotFor: [], func(sprite, script) { const scaleValue = (script.getNumberValue('VALUE', script) + 100) / 100; sprite.setScaleX(sprite.getScaleX() * scaleValue); sprite.setScaleY(sprite.getScaleY() * scaleValue); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, set_scale_percent: { color: EntryStatic.colorSet.block.default.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/looks_03.png', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['100'], }, null, ], type: 'set_scale_percent', }, paramsKeyMap: { VALUE: 0, }, class: 'scale', isNotFor: [], func(sprite, script) { const scaleValue = script.getNumberValue('VALUE', script) / 100; const snapshot = sprite.snapshot_; sprite.setScaleX(scaleValue * snapshot.scaleX); sprite.setScaleY(scaleValue * snapshot.scaleY); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, set_object_order: { color: EntryStatic.colorSet.block.default.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'objectSequence', fontSize: 11, }, { type: 'Indicator', img: 'block_icon/looks_03.png', size: 12, }, ], events: {}, def: { params: [null, null], type: 'set_object_order', }, paramsKeyMap: { VALUE: 0, }, class: 'z-index', isNotFor: [], func(sprite, script) { const targetIndex = script.getField('VALUE', script); const currentIndex = Entry.container.getCurrentObjects().indexOf(sprite.parent); if (currentIndex > -1) { return script.callReturn(); } else { throw new Error('object is not available'); } }, syntax: { js: [], py: [''] }, }, get_pictures: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'pictures', // defaultValue: 'null', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.LOOKS, arrowColor: EntryStatic.colorSet.arrow.default.LOOKS, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { VALUE: 0, }, func(sprite, script) { return script.getStringField('VALUE'); }, syntax: { js: [], py: [ { syntax: '%1', keyOption: 'get_pictures', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'pictures', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.LOOKS, converter: Entry.block.converters.returnStringKey, }, ], }, ], }, }, get_table_fields: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, template: '%1 ', skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName() { const value = this.getTargetValue('dataTables', true); if (!value) { return [[Lang.Blocks.no_target, 'null']]; } const { fields = [] } = DataTable.getSource(value) || {}; return fields.map((label, index) => [label, index + 1]); }, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options.length) { return options[0][1]; } return null; }, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { VALUE: 0, }, func(sprite, script) { return script.getStringField('VALUE'); }, syntax: { js: [], py: [ { syntax: '%1', keyOption: 'get_table_fields', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'fields', fontSize: 11, arrowColor: EntryStatic.colorSet.common.WHITE, converter: Entry.block.converters.returnStringKey, }, ], }, ], }, }, get_korea_area_code: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, template: '%1 %2 ', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Dropdown', options: getStateOptions(), value: 'Seoul', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, dropdownSync: 'weather', }, { type: 'DropdownDynamic', value: null, menuName() { const value = this.getTargetValue('weather'); if (!value) { return [[Lang.Blocks.no_target, 'null']]; } return getCityOptions(value); }, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options.length) { return options[0][1]; } return null; }, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { STATE: 0, SUB_LOC: 1, }, func(sprite, script) { return Entry.EXPANSION_BLOCK.weather.getCityCode({ parent: script.getField('STATE'), sub: script.getField('SUB_LOC'), }); }, syntax: { js: [], py: [ { type: 'Dropdown', options: getStateOptions(), value: 'Seoul', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, dropdownSync: 'weather', converter: Entry.block.converters.returnStringValue, }, { type: 'DropdownDynamic', value: null, menuName() { const value = this.getTargetValue('weather'); if (!value) { return [[Lang.Blocks.no_target, 'null']]; } return getCityOptions(value); }, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options.length) { return options[0][1]; } return null; }, converter: Entry.block.converters.returnStringValue, }, ], }, }, set_effect_amount: { color: EntryStatic.colorSet.block.default.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.color, 'color'], [Lang.Blocks.brightness, 'brightness'], [Lang.Blocks.transparency, 'transparency'], ], value: 'color', fontSize: 11, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/looks_03.png', size: 12, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['10'], }, null, ], type: 'set_effect_amount', }, paramsKeyMap: { EFFECT: 0, VALUE: 1, }, class: 'effect', isNotFor: ['textBox'], func(sprite, script) { const effect = script.getField('EFFECT', script); const effectValue = script.getNumberValue('VALUE', script); let effectName = ''; if (effect === 'color') { sprite.effect.hue = effectValue + sprite.effect.hue; effectName = 'hue'; } else if (effect === 'brightness') { sprite.effect.brightness = effectValue + sprite.effect.brightness; effectName = 'brightness'; } else if (effect === 'transparency') { sprite.effect.alpha = sprite.effect.alpha - effectValue / 100; effectName = 'alpha'; } sprite.applyFilter(true, [effectName]); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, set_entity_effect: { color: EntryStatic.colorSet.block.default.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.color, 'color'], [Lang.Blocks.brightness, 'brightness'], [Lang.Blocks.transparency, 'transparency'], ], value: 'color', fontSize: 11, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/looks_03.png', size: 12, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['100'], }, null, ], type: 'set_entity_effect', }, paramsKeyMap: { EFFECT: 0, VALUE: 1, }, class: 'effect', isNotFor: ['textBox'], func(sprite, script) { const effect = script.getField('EFFECT', script); const effectValue = script.getNumberValue('VALUE', script); let effectName = ''; if (effect == 'color') { sprite.effect.hue = effectValue; effectName = 'hue'; } else if (effect == 'brightness') { sprite.effect.brightness = effectValue; effectName = 'brightness'; } else if (effect == 'transparency') { sprite.effect.alpha = 1 - effectValue / 100; effectName = 'alpha'; } sprite.applyFilter(true, [effectName]); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, rotate_by_angle: { color: EntryStatic.colorSet.block.lighten.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/moving_03.png', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['90'], }, null, ], type: 'rotate_by_angle', }, paramsKeyMap: { VALUE: 0, }, class: 'rotate', isNotFor: [], func(sprite, script) { const value = script.getNumberValue('VALUE', script); sprite.setRotation(sprite.getRotation() + value); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, rotate_by_angle_dropdown: { color: EntryStatic.colorSet.block.lighten.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['45', '45'], ['90', '90'], ['135', '135'], ['180', '180'], ], value: '45', fontSize: 11, }, { type: 'Indicator', img: 'block_icon/moving_03.png', size: 12, }, ], events: {}, def: { params: ['45', null], type: 'rotate_by_angle_dropdown', }, paramsKeyMap: { VALUE: 0, }, class: 'ebs', isNotFor: [], func(sprite, script) { const value = script.getField('VALUE', script); sprite.setRotation(sprite.getRotation() + Number(value)); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, see_angle: { color: EntryStatic.colorSet.block.lighten.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/moving_03.png', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['90'], }, null, ], type: 'see_angle', }, paramsKeyMap: { VALUE: 0, }, class: 'rotate', isNotFor: [], func(sprite, script) { const value = script.getNumberValue('VALUE', script); sprite.setDirection(value); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, see_direction: { color: EntryStatic.colorSet.block.lighten.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'sprites', fontSize: 11, }, { type: 'Indicator', img: 'block_icon/moving_03.png', size: 12, }, ], events: {}, def: { params: [null, null], }, paramsKeyMap: { VALUE: 0, }, func(sprite, script) { const targetId = script.getField('VALUE', script); const targetEntity = Entry.container.getEntity(targetId); const deltaX = targetEntity.getX() - sprite.getX(); const deltaY = targetEntity.getY() - sprite.getY(); if (deltaX >= 0) { sprite.setRotation((Math.atan(deltaY / deltaX) / Math.PI) * 180 + 90); } else { sprite.setRotation((Math.atan(deltaY / deltaX) / Math.PI) * 180 + 270); } return script.callReturn(); }, syntax: { js: [], py: [''] }, }, rotate_by_angle_time: { color: EntryStatic.colorSet.block.lighten.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'angle', params: ['90'], }, { type: 'Indicator', img: 'block_icon/moving_03.png', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['2'], }, null, null, ], type: 'rotate_by_angle_time', }, paramsKeyMap: { VALUE: 1, }, class: 'rotate', isNotFor: [], func(sprite, script) { if (!script.isStart) { let timeValue; timeValue = script.getNumberValue('VALUE', script); const angleValue = script.getNumberField('VALUE', script); script.isStart = true; script.frameCount = Math.floor(timeValue * Entry.FPS); script.dAngle = angleValue / script.frameCount; } if (script.frameCount != 0) { sprite.setRotation(sprite.getRotation() + script.dAngle); script.frameCount--; return script; } else { delete script.isStart; delete script.frameCount; return script.callReturn(); } }, syntax: { js: [], py: [''] }, }, flip_arrow_horizontal: { color: EntryStatic.colorSet.block.lighten.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/moving_03.png', size: 12, }, ], events: {}, def: { params: [null], }, func(sprite, script) { sprite.setDirection(sprite.getDirection() + 180); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, flip_arrow_vertical: { color: EntryStatic.colorSet.block.lighten.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/moving_03.png', size: 12, }, ], events: {}, def: { params: [null], }, func(sprite, script) { sprite.setDirection(sprite.getDirection() + 180); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, see_angle_direction: { color: EntryStatic.colorSet.block.lighten.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/moving_03.png', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['90'], }, null, ], type: 'see_angle_direction', }, paramsKeyMap: { VALUE: 0, }, class: 'rotate', isNotFor: [], func(sprite, script) { const value = script.getNumberValue('VALUE', script); const nativeDirection = sprite.getDirection() + sprite.getRotation(); sprite.setRotation(sprite.getRotation() + value - nativeDirection); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, rotate_direction: { color: EntryStatic.colorSet.block.lighten.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/moving_03.png', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['90'], }, null, ], type: 'rotate_direction', }, paramsKeyMap: { VALUE: 0, }, class: 'rotate', isNotFor: [], func(sprite, script) { const value = script.getNumberValue('VALUE', script); sprite.setDirection(value + sprite.getDirection()); return script.callReturn(); }, syntax: { js: [], py: [''] }, }, //endregion basic 기본 //region basic 기본 sound_something: { color: EntryStatic.colorSet.block.default.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'sounds', fontSize: 11, }, { type: 'Indicator', img: 'block_icon/sound_03.png', size: 12, }, ], events: {}, def: { params: [null, null], type: 'sound_something', }, paramsKeyMap: { VALUE: 0, }, class: 'sound', isNotFor: [], func(sprite, script) { const soundId = script.getField('VALUE', script); const sounds = sprite.parent.sounds; const isExist = Entry.isExist(soundId, 'id', sounds); if (isExist) { Entry.Utils.playSound(soundId); } return script.callReturn(); }, syntax: { js: [], py: [''] }, }, sound_something_second: { color: EntryStatic.colorSet.block.default.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'sounds', fontSize: 11, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/sound_03.png', size: 12, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['1'], }, null, ], type: 'sound_something_second', }, paramsKeyMap: { VALUE: 0, SECOND: 1, }, class: 'sound', isNotFor: [], func(sprite, script) { const soundId = script.getField('VALUE', script); const timeValue = script.getNumberValue('SECOND', script); const sounds = sprite.parent.sounds; const isExist = Entry.isExist(soundId, 'id', sounds); if (isExist) { const instance = Entry.Utils.playSound(soundId); Entry.Utils.addSoundInstances(instance); setTimeout(() => { instance.stop(); }, timeValue * 1000); } return script.callReturn(); }, syntax: { js: [], py: [''] }, }, sound_something_wait: { color: EntryStatic.colorSet.block.default.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'sounds', fontSize: 11, }, { type: 'Indicator', img: 'block_icon/sound_03.png', size: 12, }, ], events: {}, def: { params: [null, null], type: 'sound_something_wait', }, paramsKeyMap: { VALUE: 0, }, class: 'sound', isNotFor: [], func(sprite, script) { if (!script.isPlay) { script.isPlay = true; script.playState = 1; const soundId = script.getField('VALUE', script); const sound = sprite.parent.getSound(soundId); const sounds = sprite.parent.sounds; const isExist = Entry.isExist(soundId, 'id', sounds); if (isExist) { const duration = Math.floor( (sound.duration * 1000) / Entry.playbackRateValue ); const instance = Entry.Utils.playSound(soundId); Entry.Utils.addSoundInstances(instance); setTimeout(() => { script.playState = 0; }, duration); } return script; } else if (script.playState === 1) { return script; } else { delete script.playState; delete script.isPlay; return script.callReturn(); } }, syntax: { js: [], py: [''] }, }, sound_something_second_wait: { color: EntryStatic.colorSet.block.default.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'sounds', fontSize: 11, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/sound_03.png', size: 12, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['1'], }, null, ], type: 'sound_something_second_wait', }, paramsKeyMap: { VALUE: 0, SECOND: 1, }, class: 'sound', isNotFor: [], func(sprite, script) { if (!script.isPlay) { script.isPlay = true; script.playState = 1; const soundId = script.getField('VALUE', script); const sounds = sprite.parent.sounds; const isExist = Entry.isExist(soundId, 'id', sounds); if (isExist) { const instance = Entry.Utils.playSound(soundId); const timeValue = script.getNumberValue('SECOND', script); Entry.Utils.addSoundInstances(instance); setTimeout(() => { instance.stop(); script.playState = 0; }, timeValue * 1000); instance.addEventListener('complete', (e) => {}); } return script; } else if (script.playState == 1) { return script; } else { delete script.isPlay; delete script.playState; return script.callReturn(); } }, syntax: { js: [], py: [''] }, }, get_sounds: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'sounds', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.SOUND, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, ], events: {}, def: { params: [null], type: 'get_sounds', }, paramsKeyMap: { VALUE: 0, }, func(sprite, script) { return script.getStringField('VALUE'); }, syntax: { js: [], py: [ { syntax: '%1', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'sounds', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.SOUND, converter: Entry.block.converters.returnStringKey, }, ], keyOption: 'get_sounds', }, ], }, }, boolean_comparison: { color: EntryStatic.colorSet.block.default.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Dropdown', options: [ ['=', 'EQUAL'], ['<', 'SMALLER'], ['>', 'BIGGER'], ], value: 'EQUAL', fontSize: 11, }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [null], type: 'boolean_comparison', }, paramsKeyMap: { LEFTHAND: 0, OPERATOR: 1, RIGHTHAND: 2, }, func(sprite, script) { const operator = script.getField('OPERATOR', script); const leftValue = script.getNumberValue('LEFTHAND', script); const rightValue = script.getNumberValue('RIGHTHAND', script); if (operator === 'EQUAL') { return leftValue === rightValue; } else if (operator === 'BIGGER') { return leftValue > rightValue; } else { return leftValue < rightValue; } }, syntax: { js: [], py: [''] }, }, boolean_equal: { color: EntryStatic.colorSet.block.default.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Text', text: '=', color: '#3D3D3D', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, { type: 'number', params: ['10'], }, ], type: 'boolean_equal', }, paramsKeyMap: { LEFTHAND: 0, RIGHTHAND: 2, }, class: 'boolean_compare', isNotFor: [], func(sprite, script) { const leftValue = script.getStringValue('LEFTHAND', script); const rightValue = script.getStringValue('RIGHTHAND', script); return leftValue == rightValue; }, syntax: { js: [], py: [''] }, }, boolean_bigger: { color: EntryStatic.colorSet.block.default.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Text', text: '>', color: '#3D3D3D', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, { type: 'number', params: ['10'], }, ], type: 'boolean_bigger', }, paramsKeyMap: { LEFTHAND: 0, RIGHTHAND: 2, }, class: 'boolean_compare', isNotFor: [], func(sprite, script) { const leftValue = script.getNumberValue('LEFTHAND', script); const rightValue = script.getNumberValue('RIGHTHAND', script); return leftValue > rightValue; }, syntax: { js: [], py: [''] }, }, boolean_smaller: { color: EntryStatic.colorSet.block.default.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Text', text: '<', color: '#3D3D3D', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, { type: 'number', params: ['10'], }, ], type: 'boolean_smaller', }, paramsKeyMap: { LEFTHAND: 0, RIGHTHAND: 2, }, class: 'boolean_compare', isNotFor: [], func(sprite, script) { const leftValue = script.getNumberValue('LEFTHAND', script); const rightValue = script.getNumberValue('RIGHTHAND', script); return leftValue < rightValue; }, syntax: { js: [], py: [''] }, }, boolean_and: { color: EntryStatic.colorSet.block.default.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Block', accept: 'boolean', }, { type: 'Text', text: Lang.Blocks.JUDGEMENT_boolean_and, color: '#3D3D3D', }, { type: 'Block', accept: 'boolean', }, ], events: {}, def: { params: [ { type: 'True', }, null, { type: 'True', }, ], type: 'boolean_and', }, pyHelpDef: { params: [ { type: 'boolean_shell', params: ['A'], }, null, { type: 'boolean_shell', params: ['B'], }, ], type: 'boolean_and', }, paramsKeyMap: { LEFTHAND: 0, RIGHTHAND: 2, }, class: 'boolean', isNotFor: [], func(sprite, script) { const leftValue = script.getBooleanValue('LEFTHAND', script); const rightValue = script.getBooleanValue('RIGHTHAND', script); return leftValue && rightValue; }, syntax: { js: [], py: [ { syntax: '(%1 and %3)', template: '%1 and %3', blockType: 'param', dic: '&&', }, ], }, }, boolean_or: { color: EntryStatic.colorSet.block.default.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Block', accept: 'boolean', }, { type: 'Text', text: Lang.Blocks.JUDGEMENT_boolean_or, color: '#3D3D3D', }, { type: 'Block', accept: 'boolean', }, ], events: {}, def: { params: [{ type: 'True' }, null, { type: 'False' }], type: 'boolean_or', }, pyHelpDef: { params: [ { type: 'boolean_shell', params: ['A'], }, null, { type: 'boolean_shell', params: ['B'], }, ], type: 'boolean_or', }, paramsKeyMap: { LEFTHAND: 0, RIGHTHAND: 2, }, class: 'boolean', isNotFor: [], func(sprite, script) { const leftValue = script.getBooleanValue('LEFTHAND', script); const rightValue = script.getBooleanValue('RIGHTHAND', script); return leftValue || rightValue; }, syntax: { js: [], py: [ { syntax: '(%1 or %3)', template: '%1 or %3', blockType: 'param', dic: '||', }, ], }, }, true_or_false: { color: EntryStatic.colorSet.block.default.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.JUDGEMENT_true, 'true'], [Lang.Blocks.JUDGEMENT_false, 'false'], ], value: 'true', fontSize: 11, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { VALUE: 0, }, func(sprite, script) { const value = script.children[0].textContent; return value === 'true'; }, syntax: { js: [], py: [''] }, }, True: { color: EntryStatic.colorSet.block.default.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.JUDGEMENT_true, color: EntryStatic.colorSet.common.WHITE, }, ], events: {}, def: { params: [null], type: 'True', }, func(sprite, script) { return true; }, isPrimitive: true, syntax: { js: ['Scope', 'true'], py: ['True'] }, }, False: { color: EntryStatic.colorSet.block.default.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.JUDGEMENT_false, color: EntryStatic.colorSet.common.WHITE, }, ], events: {}, def: { params: [null], type: 'False', }, func(sprite, script) { return false; }, isPrimitive: true, syntax: { js: [], py: ['False'] }, }, press_some_key: { color: EntryStatic.colorSet.block.default.START, skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_keyboard.png', size: 17, position: { x: 0, y: -2, }, }, { type: 'Dropdown', options: [ ['q', 81], ['w', 87], ['e', 69], ['r', 82], ['a', 65], ['s', 83], ['d', 68], ['위쪽 화살표', 38], ['아래쪽 화살표', 40], ['왼쪽 화살표', 37], ['오른쪽 화살표', 39], ['엔터', 13], ['스페이스', 32], ], value: 81, fontSize: 11, }, { type: 'Indicator', img: 'block_icon/start_03.png', size: 12, }, ], events: {}, def: { params: [null, null, null], }, paramsKeyMap: { VALUE: 1, }, func(sprite, script) { return script.callReturn(); }, syntax: { js: [], py: [''] }, }, text: { color: EntryStatic.colorSet.block.lighten.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextInput', value: 10, }, ], events: {}, def: { params: [], type: 'text', }, paramsKeyMap: { NAME: 0, }, func(sprite, script) { return script.getField('NAME', script); }, isPrimitive: true, syntax: { js: ['Scope', '%1'], py: [ { syntax: '%1', keyOption: 'text', textParams: [ { type: 'TextInput', converter: Entry.block.converters.returnStringOrNumberByValue, }, ], }, ], }, }, options_for_list: { color: EntryStatic.colorSet.block.default.VARIABLE, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Dropdown', options: [ ['첫번째', 'FIRST'], ['마지막', 'LAST'], ['무작위', 'RANDOM'], ], value: 'FIRST', fontSize: 11, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { OPERATOR: 0, }, func(sprite, script) { return script.getField('OPERATOR', script); }, syntax: { js: [], py: [''] }, }, //endregion basic 기본 //region basic 기본 run: { skeleton: 'basic', color: EntryStatic.colorSet.block.default.START, contents: ['this is', 'basic block'], }, mutant: { skeleton: 'basic', event: 'start', color: EntryStatic.colorSet.block.default.START, params: [], changeEvent: { _listeners: [], }, }, jr_start: { skeleton: 'pebble_event', event: 'start', color: EntryStatic.colorSet.block.default.START, params: [ { type: 'Indicator', img: '../../../img/assets/ntry/bitmap/jr/block_play_image.png', highlightColor: EntryStatic.colorSet.block.default.START, position: { x: 0, y: 0, }, size: 22, }, ], func() { const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); for (const key in entities) { this._unit = entities[key]; } Ntry.unitComp = Ntry.entityManager.getComponent(this._unit.id, Ntry.STATIC.UNIT); }, }, jr_repeat: { skeleton: 'pebble_loop', color: '#127CDB', params: [ { type: 'Text', text: '', }, { type: 'Dropdown', options: [ [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, 10], ], value: 3, fontSize: 14, roundValue: 3, }, ], statements: [{ accept: 'pebble_basic' }], func() { if (this.repeatCount === undefined) { this.repeatCount = this.block.params[1]; return Entry.STATIC.BREAK; } else if (this.repeatCount > 0) { this.repeatCount--; const statement = this.block.statements[0]; if (statement.getBlocks().length === 0) { return; } this.executor.stepInto(statement); return Entry.STATIC.BREAK; } else { delete this.repeatCount; } }, }, jr_item: { skeleton: 'pebble_basic', color: '#F46C6C', params: [ { type: 'Indicator', img: '../../../img/assets/ntry/bitmap/jr/block_item_image.png', highlightColor: EntryStatic.colorSet.common.WHITE, position: { x: 83, y: 0, }, size: 22, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { Ntry.dispatchEvent('getItem'); self.isAction = false; }; Ntry.dispatchEvent('unitAction', Ntry.STATIC.GET_ITEM, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, cparty_jr_item: { skeleton: 'pebble_basic', color: '#8ABC1D', params: [ { type: 'Indicator', img: '../../../img/assets/ntry/bitmap/cpartyjr/pen.png', highlightColor: EntryStatic.colorSet.common.WHITE, position: { x: 83, y: 0, }, size: 22, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { Ntry.dispatchEvent('getItem'); self.isAction = false; }; Ntry.dispatchEvent('unitAction', Ntry.STATIC.GET_ITEM, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, jr_north: { skeleton: 'pebble_basic', color: EntryStatic.colorSet.block.lighten.MOVING, params: [ { type: 'Indicator', img: '../../../img/assets/ntry/bitmap/jr/block_up_image.png', position: { x: 83, y: 0, }, size: 22, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const STATIC = Ntry.STATIC; const self = this; const callBack = function () { window.setTimeout(() => { Ntry.dispatchEvent('unitAction', Ntry.STATIC.WALK, () => { self.isAction = false; }); }, 3); }; let actionType; switch (Ntry.unitComp.direction) { case Ntry.STATIC.EAST: actionType = STATIC.TURN_LEFT; break; case Ntry.STATIC.SOUTH: actionType = STATIC.HALF_ROTATION; break; case Ntry.STATIC.WEST: actionType = STATIC.TURN_RIGHT; break; default: callBack(); break; } if (actionType) { Ntry.dispatchEvent('unitAction', actionType, callBack); } return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, jr_east: { skeleton: 'pebble_basic', color: EntryStatic.colorSet.block.lighten.MOVING, params: [ { type: 'Indicator', img: '../../../img/assets/ntry/bitmap/jr/block_right_image.png', position: { x: 83, y: 0, }, size: 22, }, ], func() { const STATIC = Ntry.STATIC; if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { window.setTimeout(() => { Ntry.dispatchEvent('unitAction', STATIC.WALK, () => { self.isAction = false; }); }, 3); }; // turn direction let actionType; switch (Ntry.unitComp.direction) { case STATIC.SOUTH: actionType = STATIC.TURN_LEFT; break; case STATIC.WEST: actionType = STATIC.HALF_ROTATION; break; case STATIC.NORTH: actionType = STATIC.TURN_RIGHT; break; default: callBack(); break; } if (actionType) { Ntry.dispatchEvent('unitAction', actionType, callBack); } return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, jr_south: { skeleton: 'pebble_basic', color: EntryStatic.colorSet.block.lighten.MOVING, params: [ { type: 'Indicator', img: '../../../img/assets/ntry/bitmap/jr/block_down_image.png', position: { x: 83, y: 0, }, size: 22, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const STATIC = Ntry.STATIC; const self = this; const callBack = function () { window.setTimeout(() => { Ntry.dispatchEvent('unitAction', Ntry.STATIC.WALK, () => { self.isAction = false; }); }, 3); }; // turn direction let actionType; switch (Ntry.unitComp.direction) { case STATIC.EAST: actionType = STATIC.TURN_RIGHT; break; case STATIC.NORTH: actionType = STATIC.HALF_ROTATION; break; case STATIC.WEST: actionType = STATIC.TURN_LEFT; break; default: callBack(); break; } if (actionType) { Ntry.dispatchEvent('unitAction', actionType, callBack); } return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, jr_west: { skeleton: 'pebble_basic', color: EntryStatic.colorSet.block.lighten.MOVING, params: [ { type: 'Indicator', img: '../../../img/assets/ntry/bitmap/jr/block_left_image.png', position: { x: 83, y: 0, }, size: 22, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const STATIC = Ntry.STATIC; const self = this; const callBack = function () { window.setTimeout(() => { Ntry.dispatchEvent('unitAction', STATIC.WALK, () => { self.isAction = false; }); }, 3); }; // turn direction let actionType; switch (Ntry.unitComp.direction) { case STATIC.SOUTH: actionType = STATIC.TURN_RIGHT; break; case STATIC.EAST: actionType = STATIC.HALF_ROTATION; break; case STATIC.NORTH: actionType = STATIC.TURN_LEFT; break; default: callBack(); break; } if (actionType) { Ntry.dispatchEvent('unitAction', actionType, callBack); } return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, jr_start_basic: { skeleton: 'basic_event', event: 'start', color: EntryStatic.colorSet.block.default.START, params: [ { type: 'Indicator', boxMultiplier: 2, img: '../../../img/assets/block_icon/start_icon_play.png', highlightColor: EntryStatic.colorSet.block.default.START, size: 17, position: { x: 0, y: -2, }, }, { text: '시작하기를 클릭했을때', type: 'Text', }, ], func() { const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); for (const key in entities) { this._unit = entities[key]; } Ntry.unitComp = Ntry.entityManager.getComponent(this._unit.id, Ntry.STATIC.UNIT); }, }, jr_go_straight: { skeleton: 'basic', color: EntryStatic.colorSet.block.lighten.MOVING, params: [ { type: 'Image', img: '../../../img/assets/ntry/bitmap/jr/cparty_go_straight.png', size: 24, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; // turn direction Ntry.dispatchEvent('unitAction', Ntry.STATIC.WALK, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, syntax: ['Scope', 'move'], }, jr_turn_left: { skeleton: 'basic', color: EntryStatic.colorSet.block.lighten.MOVING, params: [ { type: 'Image', img: '../../../img/assets/ntry/bitmap/jr/cparty_rotate_l.png', size: 24, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; // turn direction Ntry.dispatchEvent('unitAction', Ntry.STATIC.TURN_LEFT, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, syntax: ['Scope', 'left'], }, jr_turn_right: { skeleton: 'basic', color: EntryStatic.colorSet.block.lighten.MOVING, params: [ { type: 'Image', img: '../../../img/assets/ntry/bitmap/jr/cparty_rotate_r.png', size: 24, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; // turn direction Ntry.dispatchEvent('unitAction', Ntry.STATIC.TURN_RIGHT, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, syntax: ['Scope', 'right'], }, jr_go_slow: { skeleton: 'basic', color: '#f46c6c', params: [ { type: 'Image', img: '../../../img/assets/ntry/bitmap/jr/cparty_go_slow.png', size: 24, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; // turn direction Ntry.dispatchEvent('unitAction', Ntry.STATIC.GO_SLOW, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, syntax: ['Scope', 'move_slowly'], }, jr_repeat_until_dest: { skeleton: 'basic_loop', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicWhile', 'true'], params: [ { type: 'Image', img: '../../../img/assets/ntry/bitmap/jr/jr_goal_image.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { const statement = this.block.statements[0]; if (statement.getBlocks().length === 0) { return; } this.executor.stepInto(statement); return Entry.STATIC.BREAK; }, }, jr_if_construction: { skeleton: 'basic_loop', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', "front == 'wall'"], params: [ { type: 'Image', img: '../../../img/assets/ntry/bitmap/jr/jr_construction_image.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { if (this.isContinue) { return; } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_REPAIR, } ); this.isContinue = true; const statement = this.block.statements[0]; if (fitEntities.length === 0) { return; } else if (statement.getBlocks().length === 0) { return; } else { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } }, }, jr_if_speed: { skeleton: 'basic_loop', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', "front == 'hump'"], params: [ { type: 'Image', img: '../../../img/assets/ntry/bitmap/jr/jr_speed_image.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { if (this.isContinue) { return; } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_SLOW, } ); this.isContinue = true; const statement = this.block.statements[0]; if (fitEntities.length === 0) { return; } else if (statement.getBlocks().length === 0) { return; } else { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } }, }, maze_step_start: { skeleton: 'basic_event', mode: 'maze', event: 'start', color: EntryStatic.colorSet.block.default.START, syntax: ['Program'], params: [ { type: 'Indicator', boxMultiplier: 2, img: '../../../img/assets/block_icon/start_icon_play.png', highlightColor: EntryStatic.colorSet.block.default.START, size: 17, position: { x: 0, y: -2, }, }, ], func() { const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); for (const key in entities) { this._unit = entities[key]; } Ntry.unitComp = Ntry.entityManager.getComponent(this._unit.id, Ntry.STATIC.UNIT); Ntry.unit = this._unit; }, }, maze_step_jump: { skeleton: 'basic', mode: 'maze', color: '#FF6E4B', params: [ { type: 'Image', img: '/img/assets/week/blocks/jump.png', size: 24, }, ], syntax: ['Scope', 'jump'], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; Ntry.dispatchEvent('unitAction', Ntry.STATIC.JUMP, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_step_jump2: { parent: 'maze_step_jump', func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let unitId; $.each(entities, (id, entity) => { unitId = id; }); const unitComp = Ntry.entityManager.getComponent(unitId, Ntry.STATIC.UNIT); const unitGrid = $.extend( {}, Ntry.entityManager.getComponent(unitId, Ntry.STATIC.GRID) ); const checkGrid = { x: unitGrid.x, y: unitGrid.y, }; const isCollisionPossible = Ntry.checkCollisionTile( unitGrid, unitComp.direction, [Ntry.STATIC.OBSTACLE_IRON], 2 ); if (isCollisionPossible) { Ntry.dispatchEvent('unitAction', Ntry.STATIC.FAIL_JUMP, callBack); Ntry.dispatchEvent('complete', false, Ntry.STATIC.CONTACT_IRON); return; } Ntry.dispatchEvent('unitAction', Ntry.STATIC.JUMP, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_step_jump_pinkbean: { parent: 'maze_step_jump', func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; const unit = Ntry.getUnit(); const components = unit.components || {}; const unitComp = components[Ntry.STATIC.UNIT] || {}; const unitGrid = $.extend({}, components[Ntry.STATIC.GRID]); const checkGrid = { x: unitGrid.x, y: unitGrid.y, }; const isCollisionPossible = Ntry.checkCollisionTile( unitGrid, unitComp.direction, [Ntry.STATIC.OBSTACLE_MUSHROOM], 1 ); if (isCollisionPossible) { Ntry.dispatchEvent('unitAction', Ntry.STATIC.FAIL_JUMP, callBack); Ntry.dispatchEvent('complete', false, Ntry.STATIC.HIT_UNIT_BY_MUSHROOM); return; } Ntry.dispatchEvent('unitAction', Ntry.STATIC.JUMP, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_step_for: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIteration'], params: [ { type: 'Dropdown', key: 'REPEAT', options: [ [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, 10], ], value: 1, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { if (this.repeatCount === undefined) { this.repeatCount = this.block.params[0]; return Entry.STATIC.BREAK; } else if (this.repeatCount > 0) { this.repeatCount--; const statement = this.block.statements[0]; if (statement.getBlocks().length === 0) { return; } this.executor.stepInto(statement); return Entry.STATIC.BREAK; } else { delete this.repeatCount; } }, }, test: { skeleton: 'basic_boolean_field', mode: 'maze', color: '#127CDB', params: [ { type: 'Angle', value: '90', }, { type: 'Dropdown', options: [ [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, 10], ], value: 1, }, ], }, maze_repeat_until_1: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicWhile', 'true'], params: [ { type: 'Image', img: '/img/assets/ntry/block_inner/repeat_goal_1.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { const statement = this.block.statements[0]; if (statement.getBlocks().length === 0) { return; } this.executor.stepInto(statement); return Entry.STATIC.BREAK; }, }, maze_repeat_until_2: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicWhile', 'true'], params: [ { type: 'Image', img: '/img/assets/ntry/block_inner/repeat_goal_1.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { const statement = this.block.statements[0]; if (statement.getBlocks().length === 0) { return; } this.executor.stepInto(statement); return Entry.STATIC.BREAK; }, }, maze_step_if_1: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', "front == 'wall'"], params: [ { type: 'Image', img: '/img/assets/ntry/block_inner/if_target_1.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { if (this.isContinue) { return; } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const existEntities = Ntry.entityManager.find({ type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }); const statement = this.block.statements[0]; if (existEntities.length === 0) { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.WALL, } ); this.isContinue = true; if (fitEntities.length === 0) { return; } else if (statement.getBlocks().length === 0) { return; } else { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } }, }, maze_step_if_2: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', "front == 'bee'"], params: [ { type: 'Image', img: '../../../img/assets/ntry/bitmap/maze2/obstacle_01.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { if (this.isContinue) { return; } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_BEE, } ); this.isContinue = true; const statement = this.block.statements[0]; if (fitEntities.length === 0) { return; } else if (statement.getBlocks().length === 0) { return; } else { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } }, }, maze_call_function: { skeleton: 'basic', mode: 'maze', color: '#B57242', syntax: ['Scope', 'promise'], params: [ { type: 'Image', img: '/img/assets/week/blocks/function.png', size: 24, }, ], func() { if (!this.funcExecutor) { const codes = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.CODE); for (const key in codes) { const code = codes[key].components[Ntry.STATIC.CODE].code; this.funcExecutor = new Entry.Executor(code.getEventMap('define')[0]); } } this.funcExecutor.execute(); if (this.funcExecutor.scope.block === null) { return; } else { return Entry.STATIC.BREAK; } }, }, maze_define_function: { skeleton: 'basic_define', mode: 'maze', color: '#B57242', event: 'define', syntax: ['BasicFunction'], params: [ { type: 'Image', img: '/img/assets/week/blocks/function.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func(executor) { if (this.executed) { return; } const statement = this.block.statements[0]; if (statement.getBlocks().length === 0) { return; } this.executor.stepInto(statement); this.executed = true; return Entry.STATIC.BREAK; }, }, maze_step_if_3: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', 'front == banana'], params: [ { type: 'Image', img: '/img/assets/ntry/block_inner/if_target_3.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { if (this.isContinue) { return; } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_BANANA, } ); this.isContinue = true; const statement = this.block.statements[0]; if (fitEntities.length === 0) { return; } else if (statement.getBlocks().length === 0) { return; } else { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } }, }, maze_step_if_4: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', 'front == wall'], params: [ { type: 'Image', img: '/img/assets/ntry/block_inner/if_target_2.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { if (this.isContinue) { return; } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.WALL, } ); this.isContinue = true; const statement = this.block.statements[0]; if (fitEntities.length === 0) { return; } else if (statement.getBlocks().length === 0) { return; } else { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } }, }, maze_step_move_step: { skeleton: 'basic', mode: 'maze', color: EntryStatic.colorSet.block.lighten.MOVING, syntax: ['Scope', 'move'], params: [ { type: 'Image', img: '/img/assets/week/blocks/moveStep.png', size: 24, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; // turn direction Ntry.dispatchEvent('unitAction', Ntry.STATIC.WALK, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_step_rotate_left: { skeleton: 'basic', mode: 'maze', color: EntryStatic.colorSet.block.lighten.MOVING, syntax: ['Scope', 'left'], params: [ { type: 'Image', img: '/img/assets/week/blocks/turnL.png', size: 24, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; // turn direction Ntry.dispatchEvent('unitAction', Ntry.STATIC.TURN_LEFT, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_step_rotate_right: { skeleton: 'basic', mode: 'maze', color: EntryStatic.colorSet.block.lighten.MOVING, syntax: ['Scope', 'right'], params: [ { type: 'Image', img: '/img/assets/week/blocks/turnR.png', size: 24, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; // turn direction Ntry.dispatchEvent('unitAction', Ntry.STATIC.TURN_RIGHT, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_step_forward: { skeleton: 'basic', mode: 'maze', color: EntryStatic.colorSet.block.lighten.MOVING, syntax: ['Scope', 'move'], params: [ { type: 'Image', img: '/img/assets/week/blocks/moveStep.png', size: 24, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; // turn direction Ntry.dispatchEvent('unitAction', Ntry.STATIC.WALK, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_turn_right: { skeleton: 'basic', mode: 'maze', color: EntryStatic.colorSet.block.lighten.MOVING, syntax: ['Scope', 'turn_right'], params: [ { type: 'Indicator', img: '../../../img/assets/week/blocks/right_ic.png', size: 12, }, ], func() { if (this.isDead) { return Entry.STATIC.BREAK; } else if (this.executor.register.isTurned) { Ntry.dispatchEvent('startEnemyWalk', false, () => {}); this.isDead = true; return Entry.STATIC.BREAK; } else { Ntry.unit.components[Ntry.STATIC.UNIT].direction = Ntry.STATIC.EAST; this.executor.register.isTurned = true; } }, }, maze_turn_left: { skeleton: 'basic', mode: 'maze', color: EntryStatic.colorSet.block.lighten.MOVING, syntax: ['Scope', 'turn_left'], params: [ { type: 'Indicator', img: '../../../img/assets/week/blocks/left_ic.png', size: 12, }, ], func() { if (this.isDead) { return Entry.STATIC.BREAK; } else if (this.executor.register.isTurned) { Ntry.dispatchEvent('startEnemyWalk', false, () => {}); this.isDead = true; return Entry.STATIC.BREAK; } else { Ntry.unit.components[Ntry.STATIC.UNIT].direction = Ntry.STATIC.WEST; this.executor.register.isTurned = true; } }, }, maze_step_if_left_monster: { skeleton: 'basic_double_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', 'left == monster'], params: [ { type: 'Indicator', img: '../../../img/assets/week/blocks/if.png', size: 12, }, { type: 'LineBreak', }, ], statements: [ { accept: 'basic', }, { accept: 'basic', }, ], statementsKeyMap: { STACK_IF: 0, STACK_ELSE: 1, }, func(sprite, script) { if (this.isContinue) { return; } const unitComp = Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x - 1, y: gridComp.y }; const fitEntities = Ntry.entityManager .find({ type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }) .filter((e) => e.components[Ntry.STATIC.ENEMY]); this.isContinue = true; if (fitEntities.length === 0) { return script.getStatement('STACK_ELSE', script); } else { return script.getStatement('STACK_IF', script); } }, }, maze_step_if_right_monster: { skeleton: 'basic_double_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', 'right == monster'], params: [ { type: 'Indicator', img: '../../../img/assets/week/blocks/if.png', size: 12, }, { type: 'LineBreak', }, ], statements: [ { accept: 'basic', }, { accept: 'basic', }, ], statementsKeyMap: { STACK_IF: 0, STACK_ELSE: 1, }, func(sprite, script) { if (this.isContinue) { return; } const unitComp = Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x + 1, y: gridComp.y }; const fitEntities = Ntry.entityManager .find({ type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }) .filter((e) => e.components[Ntry.STATIC.ENEMY]); this.isContinue = true; if (fitEntities.length === 0) { return script.getStatement('STACK_ELSE', script); } else { return script.getStatement('STACK_IF', script); } }, }, maze_step_if_yeti: { skeleton: 'basic_double_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', 'front == yeti'], params: [ { type: 'Image', img: '/img/assets/week/blocks/yeti.png', size: 24, }, { type: 'Indicator', img: '../../../img/assets/week/blocks/if.png', size: 12, }, { type: 'LineBreak', }, ], statements: [ { accept: 'basic', }, { accept: 'basic', }, ], statementsKeyMap: { STACK_IF: 0, STACK_ELSE: 1, }, func(sprite, script) { if (this.isContinue) { return; } const unitComp = Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_YETI, } ); this.isContinue = true; if (fitEntities.length === 0) { return script.getStatement('STACK_ELSE', script); } else { return script.getStatement('STACK_IF', script); } }, }, maze_repeat_until_beat_monster: { parent: 'repeat_inf', params: [ { type: 'Indicator', img: '../../../img/assets/week/blocks/for.png', size: 12, }, ], }, maze_ladder_climb: { skeleton: 'basic', mode: 'maze', color: '#71C11B', emphasizedColor: '#9BDB40', syntax: ['Scope', 'climb'], params: [ { type: 'Image', img: '/img/assets/week/blocks/ladder.png', size: 24, }, ], func(sprite, script) { if (!script.isContinue) { script.isContinue = true; script.isAction = true; const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let unitId; $.each(entities, (id, entity) => { unitId = id; }); const unitComp = Ntry.entityManager.getComponent(unitId, Ntry.STATIC.UNIT); const unitGrid = $.extend( {}, Ntry.entityManager.getComponent(unitId, Ntry.STATIC.GRID) ); script.direction = unitComp.direction; const callBack = function () { unitComp.direction = script.direction; script.isAction = false; }; let isCollisionPossible = false; if (unitGrid.y > 3) { unitComp.direction = Ntry.STATIC.NORTH; isCollisionPossible = Ntry.checkCollisionTile( unitGrid, unitComp.direction, [Ntry.STATIC.LADDER], 2 ); } else { unitComp.direction = Ntry.STATIC.SOUTH; const tile = Ntry.getTileByGrid(unitGrid); if (tile.tileType === Ntry.STATIC.LADDER) { isCollisionPossible = true; } } if (isCollisionPossible) { Ntry.dispatchEvent('unitAction', Ntry.STATIC.CLIMB, callBack); } else { Ntry.dispatchEvent('unitAction', Ntry.STATIC.NOT_FOUND_LADDER, callBack); } return Entry.STATIC.BREAK; } else if (script.isAction) { return Entry.STATIC.BREAK; } else { delete script.isAction; delete script.isContinue; } }, }, maze_attack_lupin: { skeleton: 'basic', mode: 'maze', color: '#ef6d6a', emphasizedColor: '#f29999', syntax: ['Scope', 'yoyo'], params: [ { type: 'Image', img: '/img/assets/week/blocks/lupin.png', size: 24, }, { type: 'Image', img: '/img/assets/week/blocks/pinkbean_ic.png', size: 24, }, ], func(sprite, script) { if (!script.isContinue) { const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let unitId; $.each(entities, (id, entity) => { unitId = id; }); const unitComp = Ntry.entityManager.getComponent(unitId, Ntry.STATIC.UNIT); script.isContinue = true; script.isAction = true; let isFoundMushroom = false; const grid = $.extend( {}, Ntry.entityManager.getComponent(unitId, Ntry.STATIC.GRID) ); for (let i = 0; i < 2; i++) { Ntry.addVectorByDirection(grid, unitComp.direction, 1); const findTile = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_MUSHROOM, } ); if (findTile && findTile.length) { isFoundMushroom = true; } } if (isFoundMushroom) { Ntry.dispatchEvent('unitAction', Ntry.STATIC.WRONG_ATTACK_OBSTACLE, () => { script.isAction = false; }); return Entry.STATIC.BREAK; } const unitGrid = $.extend( {}, Ntry.entityManager.getComponent(unitId, Ntry.STATIC.GRID) ); const isCollisionPossible = Ntry.checkCollisionTile( unitGrid, unitComp.direction, [Ntry.STATIC.OBSTACLE_LUPIN], 2 ); if (!isCollisionPossible) { Ntry.dispatchEvent( 'unitAction', Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT, () => { script.isAction = false; } ); return Entry.STATIC.BREAK; } const callBack = function () { Ntry.dispatchEvent('playSound', 'dieLupin'); Ntry.dispatchEvent('destroyObstacle', 2, (state) => { script.isAction = false; }); }; Ntry.dispatchEvent('unitAction', Ntry.STATIC.ATTACK_LUPIN, callBack); return Entry.STATIC.BREAK; } else if (script.isAction) { return Entry.STATIC.BREAK; } else { delete script.isAction; delete script.isContinue; } }, }, maze_attack_both_side: { skeleton: 'basic', mode: 'maze', color: '#ef6d6a', emphasizedColor: '#f29999', syntax: ['Scope', 'both_side'], params: [ { type: 'Image', img: '/img/assets/week/blocks/pinkbean_ic.png', size: 24, }, ], func(sprite, script) { if (!script.isContinue) { Ntry.dispatchEvent('stopEnemyWalk'); this.executor.register.isTurned = false; script.isContinue = true; script.isAction = true; const grid = $.extend( { type: Ntry.STATIC.GRID }, Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.GRID) ); const backGrid = $.extend( { type: Ntry.STATIC.GRID }, Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.GRID) ); Ntry.addVectorByDirection(grid, Ntry.unitComp.direction, 1); Ntry.addVectorByDirection(backGrid, Ntry.unitComp.direction, -1); const frontExist = !!Ntry.entityManager .find(grid) .filter((e) => e.components[Ntry.STATIC.ENEMY]).length; const backExist = !!Ntry.entityManager .find(backGrid) .filter((e) => e.components[Ntry.STATIC.ENEMY]).length; if (!frontExist || !backExist) { Ntry.dispatchEvent('unitAction', Ntry.STATIC.BOTH_SIDE_FAIL, () => { script.isAction = false; }); return Entry.STATIC.BREAK; } Ntry.dispatchEvent('destroyObstacle', 1, (state) => {}); Ntry.dispatchEvent('destroyObstacle', -1, (state) => {}); const callBack = function () { Ntry.dispatchEvent('startEnemyWalk', true, () => { script.isAction = false; }); }; Ntry.dispatchEvent('unitAction', Ntry.STATIC.BOTH_SIDE, callBack); return Entry.STATIC.BREAK; } else if (script.isAction) { return Entry.STATIC.BREAK; } else { delete script.isAction; delete script.isContinue; } }, }, maze_attack_pepe: { skeleton: 'basic', mode: 'maze', color: '#ef6d6a', emphasizedColor: '#f29999', params: [ { type: 'Image', img: '/img/assets/week/blocks/pepe.png', size: 24, }, { type: 'Image', img: '/img/assets/week/blocks/pinkbean_ic.png', size: 24, }, ], func(sprite, script) { if (!script.isContinue) { Ntry.dispatchEvent('stopEnemyWalk'); this.executor.register.isTurned = false; script.isContinue = true; script.isAction = true; const grid = $.extend( { type: Ntry.STATIC.GRID }, Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.GRID) ); const backGrid = $.extend( { type: Ntry.STATIC.GRID }, Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.GRID) ); Ntry.addVectorByDirection(grid, Ntry.unitComp.direction, 1); const findTile = Ntry.entityManager.find(grid, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_PEPE, }); Ntry.addVectorByDirection(backGrid, Ntry.unitComp.direction, -1); const findBackTile = Ntry.entityManager .find(backGrid) .filter((e) => e.components[Ntry.STATIC.ENEMY]); const frontEnemyExist = !!Ntry.entityManager .find(grid) .filter((e) => e.components[Ntry.STATIC.ENEMY]).length; const frontEnemyValid = !!findTile.length; const backEnemyExist = !!findBackTile.length; if (frontEnemyValid && !backEnemyExist) { // success var callBack = function () { Ntry.dispatchEvent('destroyObstacle', 1, (state) => {}); Ntry.dispatchEvent('startEnemyWalk', true, () => { script.isAction = false; }); }; Ntry.dispatchEvent('unitAction', Ntry.STATIC.PEPE, callBack); } else if (frontEnemyValid && backEnemyExist) { // attack and dead var callBack = function () { Ntry.dispatchEvent('destroyObstacle', 1, (state) => {}); Ntry.dispatchEvent('startEnemyWalk', false, () => {}); }; Ntry.dispatchEvent('unitAction', Ntry.STATIC.PEPE, callBack); } else if (backEnemyExist) { // dead if (frontEnemyExist) { Ntry.dispatchEvent('unitAction', Ntry.STATIC.PEPE_FAIL, () => { script.isAction = false; }); } else { Ntry.dispatchEvent('startEnemyWalk', false, () => {}); } } else { // music time Ntry.dispatchEvent('unitAction', Ntry.STATIC.PEPE_FAIL, () => { script.isAction = false; }); } return Entry.STATIC.BREAK; } else if (script.isAction) { return Entry.STATIC.BREAK; } else { delete script.isAction; delete script.isContinue; } }, }, maze_attack_yeti: { skeleton: 'basic', mode: 'maze', color: '#ef6d6a', emphasizedColor: '#f29999', params: [ { type: 'Image', img: '/img/assets/week/blocks/yeti.png', size: 24, }, { type: 'Image', img: '/img/assets/week/blocks/pinkbean_ic.png', size: 24, }, ], func(sprite, script) { if (!script.isContinue) { Ntry.dispatchEvent('stopEnemyWalk'); this.executor.register.isTurned = false; script.isContinue = true; script.isAction = true; const grid = $.extend( { type: Ntry.STATIC.GRID }, Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.GRID) ); const backGrid = $.extend( { type: Ntry.STATIC.GRID }, Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.GRID) ); Ntry.addVectorByDirection(grid, Ntry.unitComp.direction, 1); const findTile = Ntry.entityManager.find(grid, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_YETI, }); Ntry.addVectorByDirection(backGrid, Ntry.unitComp.direction, -1); const findBackTile = Ntry.entityManager .find(backGrid) .filter((e) => e.components[Ntry.STATIC.ENEMY]); const frontEnemyExist = !!Ntry.entityManager .find(grid) .filter((e) => e.components[Ntry.STATIC.ENEMY]).length; const frontEnemyValid = !!findTile.length; const backEnemyExist = !!findBackTile.length; if (frontEnemyValid && !backEnemyExist) { // success var callBack = function () { Ntry.dispatchEvent('destroyObstacle', 1, (state) => {}); Ntry.dispatchEvent('startEnemyWalk', true, () => { script.isAction = false; }); }; Ntry.dispatchEvent('unitAction', Ntry.STATIC.PEPE, callBack); } else if (frontEnemyValid && backEnemyExist) { // attack and dead var callBack = function () { Ntry.dispatchEvent('destroyObstacle', 1, (state) => {}); Ntry.dispatchEvent('startEnemyWalk', false, () => {}); }; Ntry.dispatchEvent('unitAction', Ntry.STATIC.PEPE, callBack); } else if (backEnemyExist) { // dead if (frontEnemyExist) { Ntry.dispatchEvent('unitAction', Ntry.STATIC.YETI_FAIL, () => { script.isAction = false; }); } else { Ntry.dispatchEvent('startEnemyWalk', false, () => {}); } } else { // music time Ntry.dispatchEvent('unitAction', Ntry.STATIC.YETI_FAIL, () => { script.isAction = false; }); } return Entry.STATIC.BREAK; } else if (script.isAction) { return Entry.STATIC.BREAK; } else { delete script.isAction; delete script.isContinue; } }, }, maze_attack_mushroom: { skeleton: 'basic', mode: 'maze', color: '#ef6d6a', emphasizedColor: '#f29999', syntax: ['Scope', 'both_side'], params: [ { type: 'Image', img: '/img/assets/week/blocks/mushroom.png', size: 24, }, { type: 'Image', img: '/img/assets/week/blocks/pinkbean_ic.png', size: 24, }, ], func(sprite, script) { if (!script.isContinue) { const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let unitId; $.each(entities, (id, entity) => { unitId = id; }); const unitComp = Ntry.entityManager.getComponent(unitId, Ntry.STATIC.UNIT); const unitGrid = $.extend( {}, Ntry.entityManager.getComponent(unitId, Ntry.STATIC.GRID) ); const isCollisionPossible = Ntry.checkCollisionTile( unitGrid, unitComp.direction, [Ntry.STATIC.OBSTACLE_MUSHROOM], 1 ); script.isContinue = true; script.isAction = true; if (!isCollisionPossible) { Ntry.dispatchEvent( 'unitAction', Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT, () => { script.isAction = false; } ); return Entry.STATIC.BREAK; } const callBack = function () { Ntry.dispatchEvent('destroyObstacle', 1, (state) => { script.isAction = false; }); }; Ntry.dispatchEvent('unitAction', Ntry.STATIC.ATTACK_MUSHROOM, callBack); return Entry.STATIC.BREAK; } else if (script.isAction) { return Entry.STATIC.BREAK; } else { delete script.isAction; delete script.isContinue; } }, }, maze_attack_peti: { skeleton: 'basic', mode: 'maze', color: '#ef6d6a', emphasizedColor: '#f29999', syntax: ['Scope', 'both_side'], params: [ { type: 'Image', img: '/img/assets/week/blocks/bigYeti.png', size: 24, }, { type: 'Image', img: '/img/assets/week/blocks/pinkbean_ic.png', size: 24, }, ], func(sprite, script) { if (!script.isContinue) { Ntry.dispatchEvent('stopEnemyWalk'); this.executor.register.isTurned = false; script.isContinue = true; script.isAction = true; const grid = $.extend( { type: Ntry.STATIC.GRID }, Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.GRID) ); const backGrid = $.extend( { type: Ntry.STATIC.GRID }, Ntry.entityManager.getComponent(Ntry.unit.id, Ntry.STATIC.GRID) ); Ntry.addVectorByDirection(grid, Ntry.unitComp.direction, 1); const findTile = Ntry.entityManager.find(grid, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_PETI, }); Ntry.addVectorByDirection(backGrid, Ntry.unitComp.direction, -1); const findBackTile = Ntry.entityManager .find(backGrid) .filter((e) => e.components[Ntry.STATIC.ENEMY]); const frontEnemyExist = !!Ntry.entityManager .find(grid) .filter((e) => e.components[Ntry.STATIC.ENEMY]).length; const frontEnemyValid = !!findTile.length; const backEnemyExist = !!findBackTile.length; if (frontEnemyValid && !backEnemyExist) { // success Ntry.dispatchEvent('destroyObstacle', 1, (state) => {}); var callBack = function () { Ntry.dispatchEvent('startEnemyWalk', true, () => { script.isAction = false; }); }; Ntry.dispatchEvent('unitAction', Ntry.STATIC.PETI, callBack); } else if (frontEnemyValid && backEnemyExist) { // attack and dead Ntry.dispatchEvent('destroyObstacle', 1, (state) => {}); var callBack = function () { Ntry.dispatchEvent('startEnemyWalk', false, () => {}); }; Ntry.dispatchEvent('unitAction', Ntry.STATIC.PETI, callBack); } else if (backEnemyExist) { // dead if (frontEnemyExist) { Ntry.dispatchEvent('unitAction', Ntry.STATIC.PETI_FAIL, () => { script.isAction = false; }); } else { Ntry.dispatchEvent('startEnemyWalk', false, () => {}); } } else { // music time Ntry.dispatchEvent('unitAction', Ntry.STATIC.PETI_FAIL, () => { script.isAction = false; }); } return Entry.STATIC.BREAK; } else if (script.isAction) { return Entry.STATIC.BREAK; } else { delete script.isAction; delete script.isContinue; } }, }, maze_eat_item: { skeleton: 'basic', mode: 'maze', color: '#b2521d', emphasizedColor: '#9BDB40', syntax: ['Scope', 'item'], params: [ { type: 'Image', img: '/img/assets/week/blocks/eat.png', size: 24, }, ], func(sprite, script) { if (!script.isContinue) { script.isContinue = true; script.isAction = true; const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let unitId; $.each(entities, (id, entity) => { unitId = id; }); const callBack = function () { script.isAction = false; }; const unitComp = Ntry.entityManager.getComponent(unitId, Ntry.STATIC.UNIT); const unitGrid = $.extend( {}, Ntry.entityManager.getComponent(unitId, Ntry.STATIC.GRID) ); const meatEntity = Ntry.checkTileByGrid(unitGrid, Ntry.STATIC.MEAT); if (!meatEntity || meatEntity.components[Ntry.STATIC.ITEM].isEaten) { Ntry.dispatchEvent('unitAction', Ntry.STATIC.NOT_FOUND_MEAT, callBack); return Entry.STATIC.BREAK; } Ntry.dispatchEvent('unlockItem'); Ntry.dispatchEvent('unitAction', Ntry.STATIC.EAT, callBack); return Entry.STATIC.BREAK; } else if (script.isAction) { return Entry.STATIC.BREAK; } else { delete script.isAction; delete script.isContinue; } }, }, maze_rotate_left: { skeleton: 'basic', mode: 'maze', color: EntryStatic.colorSet.block.lighten.MOVING, syntax: ['Scope', 'left'], params: [ { type: 'Image', img: '/img/assets/week/blocks/turnL.png', size: 24, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; // turn direction Ntry.dispatchEvent('unitAction', Ntry.STATIC.TURN_LEFT, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_rotate_right: { skeleton: 'basic', mode: 'maze', color: EntryStatic.colorSet.block.lighten.MOVING, syntax: ['Scope', 'right'], params: [ { type: 'Image', img: '/img/assets/week/blocks/turnR.png', size: 24, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const self = this; const callBack = function () { self.isAction = false; }; // turn direction Ntry.dispatchEvent('unitAction', Ntry.STATIC.TURN_RIGHT, callBack); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_moon_kick: { skeleton: 'basic', mode: 'maze', color: '#2EB0E8', syntax: ['Scope', 'right'], params: [ { type: 'Image', img: '/img/assets/maze/sprite/moon_icon.png', size: 24, }, ], func() { if (!this.isContinue) { const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let unitId; $.each(entities, (id, entity) => { unitId = id; }); const unitComp = Ntry.entityManager.getComponent(unitId, Ntry.STATIC.UNIT); const unitGrid = $.extend( {}, Ntry.entityManager.getComponent(unitId, Ntry.STATIC.GRID) ); const isCollisionPossible = Ntry.checkCollisionTile( unitGrid, unitComp.direction, [Ntry.STATIC.OBSTACLE_BRICK], 1 ); if (!isCollisionPossible) { Ntry.dispatchEvent('playSound', Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT); Ntry.dispatchEvent('complete', false, Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT); return; } this.isContinue = true; this.isAction = true; const self = this; const callback = function () { Ntry.dispatchEvent('destroyObstacle', 1, (state) => { switch (state) { case Ntry.STATIC.OBSTACLE_DESTROY_SUCCESS: self.isAction = false; break; } }); }; // turn direction Ntry.dispatchEvent('unitAction', Ntry.STATIC.ATTACK, callback); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_cony_flower_throw: { skeleton: 'basic', mode: 'maze', color: '#D8617D', syntax: ['Scope', 'right'], params: [ { type: 'Image', img: '/img/assets/maze/sprite/cony_icon.png', size: 24, }, ], func() { const self = this; if (!this.isContinue) { this.isContinue = true; this.isAction = true; const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let unitId; let components; $.each(entities, (id, entity) => { unitId = id; components = entity.components; }); const unitComp = Ntry.entityManager.getComponent(unitId, Ntry.STATIC.UNIT); const unitGrid = $.extend( {}, Ntry.entityManager.getComponent(unitId, Ntry.STATIC.GRID) ); const isCollisionPossible = Ntry.checkCollisionTile( unitGrid, unitComp.direction, [Ntry.STATIC.OBSTACLE_SPIDER] ); let particleZIndex = 550; if (unitComp.direction === Ntry.STATIC.NORTH) { particleZIndex = 450; } if (!isCollisionPossible) { Ntry.dispatchEvent('playSound', Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT); Ntry.dispatchEvent('complete', false, Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT); return; } const particle = Ntry.entityManager.addEntity(); Ntry.dispatchEvent('unitAction', Ntry.STATIC.ATTACK, () => { $.each(components, (type, component) => { if (+type === Ntry.STATIC.SPRITE) { const cloneComponent = $.extend({}, component); cloneComponent.zIndex = particleZIndex; Ntry.entityManager.addComponent(particle.id, cloneComponent); } else if (+type != Ntry.STATIC.UNIT) { Ntry.entityManager.addComponent(particle.id, component); } else { Ntry.entityManager.addComponent(particle.id, { type: Ntry.STATIC.PARTICLE, direction: component.direction, collisionList: [Ntry.STATIC.OBSTACLE_SPIDER], }); } }); Ntry.dispatchEvent('particleAction', { entityId: particle.id, actionType: Ntry.STATIC.FLOWER_ATTACK, callback() { Ntry.entityManager.removeEntity(particle.id); self.isAction = false; }, }); }); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_cony_flower_throw2: { skeleton: 'basic', mode: 'maze', color: '#D8617D', template: Lang.template.maze_cony_flower_throw, syntax: ['Scope', 'right'], params: [ { type: 'Image', img: '/img/assets/maze/sprite/cony_icon.png', size: 24, }, ], func() { const self = this; if (!this.isContinue) { const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let unitId; let components; $.each(entities, (id, entity) => { unitId = id; components = entity.components; }); const unitComp = Ntry.entityManager.getComponent(unitId, Ntry.STATIC.UNIT); const unitGrid = $.extend( {}, Ntry.entityManager.getComponent(unitId, Ntry.STATIC.GRID) ); const isCollisionPossible = Ntry.checkCollisionTile( unitGrid, unitComp.direction, [Ntry.STATIC.OBSTACLE_ENERMY5, Ntry.STATIC.OBSTACLE_ENERMY4], 2 ); let particleZIndex = 550; if (unitComp.direction === Ntry.STATIC.NORTH) { particleZIndex = 450; } if (!isCollisionPossible) { Ntry.dispatchEvent('playSound', Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT); Ntry.dispatchEvent('complete', false, Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT); return; } this.isContinue = true; this.isAction = true; const particle = Ntry.entityManager.addEntity(); Ntry.dispatchEvent('unitAction', Ntry.STATIC.ATTACK, () => { $.each(components, (type, component) => { if (+type === Ntry.STATIC.SPRITE) { const cloneComponent = $.extend({}, component); cloneComponent.zIndex = particleZIndex; Ntry.entityManager.addComponent(particle.id, cloneComponent); } else if (+type != Ntry.STATIC.UNIT) { Ntry.entityManager.addComponent(particle.id, component); } else { Ntry.entityManager.addComponent(particle.id, { type: Ntry.STATIC.PARTICLE, direction: component.direction, collisionList: [ Ntry.STATIC.OBSTACLE_ENERMY5, Ntry.STATIC.OBSTACLE_ENERMY4, ], penetrationList: [Ntry.STATIC.WALL], }); } }); Ntry.dispatchEvent('particleAction', { entityId: particle.id, actionType: Ntry.STATIC.HEART_ATTACK, callback() { Ntry.entityManager.removeEntity(particle.id); self.isAction = false; }, }); }); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_james_heart: { skeleton: 'basic', mode: 'maze', color: '#D39D18', syntax: ['Scope', 'right'], params: [ { type: 'Image', img: '/img/assets/maze/sprite/james_icon.png', size: 24, }, ], func() { const self = this; if (!this.isContinue) { const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let unitId; let components; $.each(entities, (id, entity) => { unitId = id; components = entity.components; }); const unitComp = Ntry.entityManager.getComponent(unitId, Ntry.STATIC.UNIT); const unitGrid = $.extend( {}, Ntry.entityManager.getComponent(unitId, Ntry.STATIC.GRID) ); const isCollisionPossible = Ntry.checkCollisionTile( unitGrid, unitComp.direction, [ Ntry.STATIC.OBSTACLE_ENERMY1, Ntry.STATIC.OBSTACLE_ENERMY2, Ntry.STATIC.OBSTACLE_ENERMY3, Ntry.STATIC.OBSTACLE_ENERMY5, ] ); let particleZIndex = 550; if (unitComp.direction === Ntry.STATIC.NORTH) { particleZIndex = 450; } if (!isCollisionPossible) { Ntry.dispatchEvent('playSound', Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT); Ntry.dispatchEvent('complete', false, Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT); return; } this.isContinue = true; this.isAction = true; const particle = Ntry.entityManager.addEntity(); Ntry.dispatchEvent('unitAction', Ntry.STATIC.ATTACK, () => { $.each(components, (type, component) => { if (+type === Ntry.STATIC.SPRITE) { const cloneComponent = $.extend({}, component); cloneComponent.zIndex = particleZIndex; Ntry.entityManager.addComponent(particle.id, cloneComponent); } else if (+type != Ntry.STATIC.UNIT) { Ntry.entityManager.addComponent(particle.id, component); } else { Ntry.entityManager.addComponent(particle.id, { type: Ntry.STATIC.PARTICLE, direction: component.direction, collisionList: [ Ntry.STATIC.OBSTACLE_ENERMY1, Ntry.STATIC.OBSTACLE_ENERMY2, Ntry.STATIC.OBSTACLE_ENERMY3, Ntry.STATIC.OBSTACLE_ENERMY5, ], }); } }); Ntry.dispatchEvent('particleAction', { entityId: particle.id, actionType: Ntry.STATIC.HEART_ATTACK, callback() { Ntry.entityManager.removeEntity(particle.id); self.isAction = false; }, }); }); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_james_heart2: { skeleton: 'basic', mode: 'maze', color: '#D39D18', template: Lang.template.maze_james_heart, syntax: ['Scope', 'right'], params: [ { type: 'Image', img: '/img/assets/maze/sprite/james_icon.png', size: 24, }, ], func() { const self = this; if (!this.isContinue) { const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let unitId; let components; $.each(entities, (id, entity) => { unitId = id; components = entity.components; }); const unitComp = Ntry.entityManager.getComponent(unitId, Ntry.STATIC.UNIT); const unitGrid = $.extend( {}, Ntry.entityManager.getComponent(unitId, Ntry.STATIC.GRID) ); const isCollisionPossible = Ntry.checkCollisionTile( unitGrid, unitComp.direction, [Ntry.STATIC.OBSTACLE_ENERMY3, Ntry.STATIC.OBSTACLE_ENERMY4], 2 ); let particleZIndex = 550; if (unitComp.direction === Ntry.STATIC.NORTH) { particleZIndex = 450; } if (!isCollisionPossible) { Ntry.dispatchEvent('playSound', Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT); Ntry.dispatchEvent('complete', false, Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT); return; } this.isContinue = true; this.isAction = true; const particle = Ntry.entityManager.addEntity(); Ntry.dispatchEvent('unitAction', Ntry.STATIC.ATTACK, () => { $.each(components, (type, component) => { if (+type === Ntry.STATIC.SPRITE) { const cloneComponent = $.extend({}, component); cloneComponent.zIndex = particleZIndex; Ntry.entityManager.addComponent(particle.id, cloneComponent); } else if (+type != Ntry.STATIC.UNIT) { Ntry.entityManager.addComponent(particle.id, component); } else { Ntry.entityManager.addComponent(particle.id, { type: Ntry.STATIC.PARTICLE, direction: component.direction, collisionList: [ Ntry.STATIC.OBSTACLE_ENERMY3, Ntry.STATIC.OBSTACLE_ENERMY4, Ntry.STATIC.OBSTACLE_ENERMY_AREA, ], penetrationList: [Ntry.STATIC.OBSTACLE_ENERMY_AREA], }); } }); Ntry.dispatchEvent('particleAction', { entityId: particle.id, actionType: Ntry.STATIC.HEART_ATTACK, callback() { Ntry.entityManager.removeEntity(particle.id); self.isAction = false; }, }); }); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_iron_switch: { skeleton: 'basic', mode: 'maze', color: '#748d69', syntax: ['Scope', 'right'], params: [ { type: 'Image', img: '/img/assets/maze/sprite/iron_icon.png', size: 24, }, ], func() { if (!this.isContinue) { this.isContinue = true; this.isAction = true; const eventCount = 0; const self = this; const gridSize = Ntry.configManager.getConfig('gridSize'); const tileSize = Ntry.configManager.getConfig('tileSize').width; const entities = Ntry.entityManager.getEntitiesByComponent( Ntry.STATIC.OBSTACLE ); for (const id in entities) { const obstacleComp = Ntry.entityManager.getComponent( id, Ntry.STATIC.OBSTACLE ); if (obstacleComp.tileType === Ntry.STATIC.OBSTACLE_IRON) { const obstacleGrid = Ntry.entityManager.getComponent( id, Ntry.STATIC.GRID ); const grid = { x: obstacleGrid.x, y: obstacleGrid.y === 1 ? 3 : 1, }; obstacleGrid.y = obstacleGrid.y === 1 ? 3 : 1; let deltaY = tileSize * 2; if (obstacleGrid.y === 1) { deltaY = -deltaY; } const deltaPos = { x: 0, y: deltaY * 0.5, }; const deltaPos2 = { x: 0, y: deltaY, }; const targetPos = { minY: 0, maxY: gridSize.height * tileSize, }; if (deltaY > 0) { targetPos.maxY = obstacleGrid.y * tileSize + tileSize / 2; } else { targetPos.minY = obstacleGrid.y * tileSize + tileSize / 2; } (function (_id, _deltaPos, _deltaPos2, _targetPos, obstacleGrid) { const comp = Ntry.entityManager.getComponent( _id, Ntry.STATIC.ANIMATE ); if (comp) { if (eventCount === 0) { self.isAction = false; } Ntry.entityManager.addComponent(_id, { type: Ntry.STATIC.ANIMATE, animateType: Ntry.STATIC.TRANSITION, duration: 20, option: { deltaPos: _deltaPos2, targetPos: _targetPos, }, afterAnimate() { const unitGrid = Ntry.getUtilGrid(); if ( obstacleGrid.x == unitGrid.x && obstacleGrid.y == unitGrid.y ) { Ntry.dispatchEvent( 'unitAction', Ntry.STATIC.CONTACT_IRON2 ); } }, }); } else { Ntry.entityManager.addComponent(_id, { type: Ntry.STATIC.ANIMATE, animateType: Ntry.STATIC.TRANSITION, duration: 10, option: { deltaPos: _deltaPos, }, afterAnimate() { if (eventCount === 0) { self.isAction = false; } Ntry.entityManager.addComponent(_id, { type: Ntry.STATIC.ANIMATE, animateType: Ntry.STATIC.TRANSITION, duration: 10, option: { deltaPos: _deltaPos, targetPos: _targetPos, }, afterAnimate() { const unitGrid = Ntry.getUtilGrid(); if ( obstacleGrid.x == unitGrid.x && obstacleGrid.y == unitGrid.y ) { Ntry.dispatchEvent( 'unitAction', Ntry.STATIC.CONTACT_IRON2 ); } }, }); }, }); } })(id, deltaPos, deltaPos2, targetPos, obstacleGrid); } } return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_brown_punch: { skeleton: 'basic', mode: 'maze', color: '#6C483A', syntax: ['Scope', 'right'], params: [ { type: 'Image', img: '/img/assets/maze/sprite/brown_icon.png', size: 24, }, ], func() { if (!this.isContinue) { const self = this; const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let unitId; $.each(entities, (id) => { unitId = id; }); const unitComp = Ntry.entityManager.getComponent(unitId, Ntry.STATIC.UNIT); const unitGrid = $.extend( {}, Ntry.entityManager.getComponent(unitId, Ntry.STATIC.GRID) ); const isCollisionPossible = Ntry.checkCollisionTile( unitGrid, unitComp.direction, [Ntry.STATIC.OBSTACLE_ICE], 1 ); if (!isCollisionPossible) { Ntry.dispatchEvent('playSound', Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT); Ntry.dispatchEvent('complete', false, Ntry.STATIC.NOT_FOUND_DESTORY_OBJECT); return; } this.isContinue = true; this.isAction = true; const callback = function () { Ntry.dispatchEvent('destroyObstacle', 1, (state) => { switch (state) { case Ntry.STATIC.OBSTACLE_DESTROY_SUCCESS: self.isAction = false; break; } }); }; // turn direction Ntry.dispatchEvent('unitAction', Ntry.STATIC.ATTACK, callback); return Entry.STATIC.BREAK; } else if (this.isAction) { return Entry.STATIC.BREAK; } else { delete this.isAction; delete this.isContinue; } }, }, maze_repeat_until_3: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicWhile', 'true'], params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/tile_goal_01.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { let isGoal = false; const statement = this.block.statements[0]; if (statement.getBlocks().length === 0) { return; } var entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); var entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); if (unitComp.isStartedUnit) { const unitGrid = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); var entities = Ntry.entityManager.getEntitiesByGrid(unitGrid.x, unitGrid.y); for (const idx in entities) { var entity = entities[idx]; const tile = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.TILE); const item = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.ITEM); if ( tile && item && tile.tileType === Ntry.STATIC.GOAL && Ntry.STATIC.GOAL_ITEM_LIST.indexOf(item.itemType) > -1 ) { isGoal = true; break; } } } if (!isGoal) { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } }, }, maze_repeat_until_4: { parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/tile_goal_02.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_repeat_until_5: { parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/tile_goal_03.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_repeat_until_6: { parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/blcok-1.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_repeat_until_7: { parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/blcok-4.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_repeat_until_8: { template: Lang.template.maze_repeat_until_7, parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/blcok-5.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_repeat_until_9: { template: Lang.template.maze_repeat_until_7, parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/blcok-6.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_repeat_until_10: { template: Lang.template.maze_repeat_until_7, parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/blcok-7.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_repeat_until_11: { template: Lang.template.maze_repeat_until_7, parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/blcok-9.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_repeat_until_12: { template: Lang.template.maze_repeat_until_7, parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/blcok-10.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_repeat_until_13: { template: Lang.template.maze_repeat_until_7, parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/blcok-11.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_repeat_until_14: { template: Lang.template.maze_repeat_until_7, parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/blcok-12.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_repeat_until_15: { template: Lang.template.maze_repeat_until_7, parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/maze/bitmap/ws/tile_goal_04.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_repeat_until_goal: { parent: 'maze_repeat_until_3', params: [ { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], }, maze_radar_check: { skeleton: 'basic_boolean_field', mode: 'maze', color: EntryStatic.colorSet.block.default.JUDGE, params: [ { type: 'Dropdown', options: [ [Lang.Menus.maze_distance1, '1'], [Lang.Menus.maze_distance2, '2'], ], value: '1', fontSize: 11, }, { type: 'Dropdown', options: [ [Lang.Menus.maze_object_trap, 'TRAP'], [Lang.Menus.maze_object_monster, 'MONSTER'], [Lang.Menus.maze_object_obstacle1, 'OBSTACLE'], ], value: 'TRAP', fontSize: 11, }, ], paramsKeyMap: { DISTANCE: 0, TYPE: 1, }, func(sprite, script) { const distance = script.getNumberField('DISTANCE', script); const type = script.getField('TYPE', script); const entityId = Ntry.getRadarEntityIdByDistance(distance); let tileType; if (entityId) { const tileComp = Ntry.entityManager.getComponent(entityId, Ntry.STATIC.TILE); switch (tileComp.tileType) { case Ntry.STATIC.OBSTACLE_HOLE: tileType = 'TRAP'; break; case Ntry.STATIC.OBSTACLE_ENERMY1: case Ntry.STATIC.OBSTACLE_ENERMY2: case Ntry.STATIC.OBSTACLE_ENERMY3: case Ntry.STATIC.OBSTACLE_ENERMY4: case Ntry.STATIC.OBSTACLE_ENERMY5: tileType = 'MONSTER'; break; case Ntry.STATIC.OBSTACLE_IRON: tileType = 'OBSTACLE'; break; } } else { tileType = 'TRAP'; } if (type === tileType) { return true; } else { return false; } }, }, // TODO: 해당 부분 수정 필요 maze_step_if_5: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', 'front == bee'], params: [ { type: 'Image', img: '../../../img/assets/ntry/bitmap/maze2/obstacle_01.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { if (this.isContinue) { return; } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_BEE, } ); this.isContinue = true; const statement = this.block.statements[0]; if (fitEntities.length === 0) { return; } else if (statement.getBlocks().length === 0) { return; } else { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } }, }, // TODO: 해당 부분 수정 필요 maze_step_if_6: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', 'front == bee'], params: [ { type: 'Image', img: '../../../img/assets/maze/bitmap/stage4/road_4_01.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { if (this.isContinue) { return; } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.ROAD, } ); this.isContinue = true; const statement = this.block.statements[0]; if (fitEntities.length > 0) { return; } else if (statement.getBlocks().length === 0) { return; } else { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } }, }, // TODO: 해당 부분 수정 필요 maze_step_if_7: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', 'front == ice'], params: [ { type: 'Image', img: '../../../img/assets/maze/bitmap/stage4/obj_ice_01.png', size: 18, }, { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { if (this.isContinue) { return; } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_ICE, } ); this.isContinue = true; const statement = this.block.statements[0]; if (fitEntities.length === 0) { return; } else if (statement.getBlocks().length === 0) { return; } else { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } }, }, maze_step_if_8: { parent: '_if', class: '', syntax: { js: [], py: [] }, }, maze_step_if_mushroom: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', 'front == mushroom'], params: [ { type: 'Image', img: '/img/assets/week/blocks/mushroom.png', size: 24, }, { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { if (this.isContinue) { return; } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_MUSHROOM, } ); this.isContinue = true; const statement = this.block.statements[0]; if (fitEntities.length === 0) { return; } else if (statement.getBlocks().length === 0) { return; } else { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } }, }, maze_step_if_lupin: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', 'front == lupin'], params: [ { type: 'Image', img: '/img/assets/week/blocks/lupin.png', size: 24, }, { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, ], statements: [ { accept: 'basic', }, ], func() { if (this.isContinue) { return; } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 2); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_LUPIN, } ); this.isContinue = true; const statement = this.block.statements[0]; if (fitEntities.length === 0) { return; } else if (statement.getBlocks().length === 0) { return; } else { this.executor.stepInto(statement); return Entry.STATIC.BREAK; } }, }, maze_step_if_else_road: { skeleton: 'basic_double_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, params: [ { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, { type: 'LineBreak', }, ], statements: [ { accept: 'basic', }, { accept: 'basic', }, ], statementsKeyMap: { STACK_IF: 0, STACK_ELSE: 1, }, func(sprite, script) { if (script.isCondition) { delete script.isCondition; return script.callReturn(); } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.ROAD, } ); script.isCondition = true; if (fitEntities.length) { return script.getStatement('STACK_IF', script); } else { return script.getStatement('STACK_ELSE', script); } }, }, maze_step_if_else_mushroom: { skeleton: 'basic_double_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, params: [ { type: 'Image', img: '/img/assets/week/blocks/mushroom.png', size: 24, }, { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, { type: 'LineBreak', }, ], statements: [ { accept: 'basic', }, { accept: 'basic', }, ], statementsKeyMap: { STACK_IF: 0, STACK_ELSE: 1, }, func(sprite, script) { if (script.isCondition) { delete script.isCondition; return script.callReturn(); } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_MUSHROOM, } ); script.isCondition = true; if (fitEntities.length) { return script.getStatement('STACK_IF', script); } else { return script.getStatement('STACK_ELSE', script); } }, }, maze_step_if_else_lupin: { skeleton: 'basic_double_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, params: [ { type: 'Image', img: '/img/assets/week/blocks/lupin.png', size: 24, }, { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, { type: 'LineBreak', }, ], statements: [ { accept: 'basic', }, { accept: 'basic', }, ], statementsKeyMap: { STACK_IF: 0, STACK_ELSE: 1, }, func(sprite, script) { if (script.isCondition) { delete script.isCondition; return script.callReturn(); } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; Ntry.addVectorByDirection(grid, unitComp.direction, 2); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.OBSTACLE_LUPIN, } ); script.isCondition = true; if (fitEntities.length) { return script.getStatement('STACK_IF', script); } else { return script.getStatement('STACK_ELSE', script); } }, }, maze_step_if_else_ladder: { skeleton: 'basic_double_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, params: [ { type: 'Image', img: '/img/assets/week/blocks/ic_ladder.png', size: 24, }, { type: 'Image', img: '/img/assets/week/blocks/if.png', size: 24, }, { type: 'LineBreak', }, ], statements: [ { accept: 'basic', }, { accept: 'basic', }, ], statementsKeyMap: { STACK_IF: 0, STACK_ELSE: 1, }, func(sprite, script) { if (script.isCondition) { delete script.isCondition; return script.callReturn(); } const entities = Ntry.entityManager.getEntitiesByComponent(Ntry.STATIC.UNIT); let entity; for (const key in entities) { entity = entities[key]; } const unitComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.UNIT); const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); const grid = { x: gridComp.x, y: gridComp.y }; if (grid.y > 3) { grid.y = 2; } Ntry.addVectorByDirection(grid, unitComp.direction, 1); const fitEntities = Ntry.entityManager.find( { type: Ntry.STATIC.GRID, x: grid.x, y: grid.y, }, { type: Ntry.STATIC.TILE, tileType: Ntry.STATIC.LADDER, } ); script.isCondition = true; if (fitEntities.length) { return script.getStatement('STACK_IF', script); } else { return script.getStatement('STACK_ELSE', script); } }, }, maze_step_if_else: { parent: 'if_else', class: '', syntax: { js: [], py: [] }, }, test_wrapper: { skeleton: 'basic', mode: 'maze', color: EntryStatic.colorSet.block.default.START, params: [ { type: 'Block', accept: 'basic_boolean_field', value: [ { type: 'test', params: [30, 50], }, ], }, { type: 'Dropdown', options: [ [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, 10], ], value: 1, }, ], }, basic_button: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, params: [ { type: 'Text', text: 'basic button', color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], }, //endregion basic 기본 //region basic 기본 ebs_if: { parent: '_if', def: { type: '_if', params: [ { type: 'reach_something', params: [null, 'wall'], }, ], }, syntax: { js: [], py: [] }, }, ebs_if2: { parent: '_if', def: { type: '_if', params: [ { type: 'reach_something', params: [null, 'cwz5'], }, ], }, syntax: { js: [], py: [] }, }, ai_move_right: { skeleton: 'basic', mode: 'maze', color: EntryStatic.colorSet.block.lighten.MOVING, syntax: ['Scope', 'move'], params: [ { type: 'Image', img: '/img/assets/week/blocks/moveStep.png', size: 24, }, ], func(entity, script) { if (!script.isStart) { script.isStart = true; script.isAction = true; Ntry.dispatchEvent('gridChange', () => { script.isAction = false; }); const spaceShipComp = Ntry.entityManager.getComponent( entity.id, Ntry.STATIC.SPACE_SHIP ); spaceShipComp.direction = Ntry.STATIC.EAST; const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); Ntry.entityManager.addComponent(entity.id, { type: Ntry.STATIC.ANIMATE, animateType: Ntry.STATIC.ROTATE_TO, animateValue: 0, }); gridComp.x++; return Entry.STATIC.BREAK; } else if (script.isAction) { return Entry.STATIC.BREAK; } else { delete script.isAction; delete script.isStart; } }, }, ai_move_up: { skeleton: 'basic', mode: 'maze', color: EntryStatic.colorSet.block.lighten.MOVING, syntax: ['Scope', 'up'], params: [ { type: 'Image', img: '/img/assets/week/blocks/ai_move_up.png', size: 24, }, ], func(entity, script) { if (!script.isStart) { script.isStart = true; script.isAction = true; Ntry.dispatchEvent('gridChange', () => { script.isAction = false; }); const spaceShipComp = Ntry.entityManager.getComponent( entity.id, Ntry.STATIC.SPACE_SHIP ); spaceShipComp.direction = Ntry.STATIC.NORTH; const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); Ntry.entityManager.addComponent(entity.id, { type: Ntry.STATIC.ANIMATE, animateType: Ntry.STATIC.ROTATE_TO, animateValue: -45, }); gridComp.x++; gridComp.y--; return script; } else if (script.isAction) { return script; } else { delete script.isAction; delete script.isStart; return script.callReturn(); } }, }, ai_move_down: { skeleton: 'basic', mode: 'maze', color: EntryStatic.colorSet.block.lighten.MOVING, syntax: ['Scope', 'down'], params: [ { type: 'Image', img: '/img/assets/week/blocks/ai_move_down.png', size: 24, }, ], func(entity, script) { if (!script.isStart) { script.isStart = true; script.isAction = true; Ntry.dispatchEvent('gridChange', () => { script.isAction = false; }); const spaceShipComp = Ntry.entityManager.getComponent( entity.id, Ntry.STATIC.SPACE_SHIP ); spaceShipComp.direction = Ntry.STATIC.SOUTH; const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); Ntry.entityManager.addComponent(entity.id, { type: Ntry.STATIC.ANIMATE, animateType: Ntry.STATIC.ROTATE_TO, animateValue: 45, }); gridComp.x++; gridComp.y++; return script; } else if (script.isAction) { return script; } else { delete script.isAction; delete script.isStart; return script.callReturn(); } }, }, ai_repeat_until_reach: { skeleton: 'basic_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicWhile', 'true'], statements: [ { accept: 'basic', }, ], params: [ { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, ], func() { const statement = this.block.statements[0]; if (statement.getBlocks().length === 0) { return; } return this.executor.stepInto(statement); }, }, ai_if_else_1: { skeleton: 'basic_double_loop', mode: 'maze', color: EntryStatic.colorSet.block.default.FLOW, syntax: ['BasicIf', "front == 'stone'"], statements: [ { accept: 'basic', }, { accept: 'basic', }, ], params: [ { type: 'Image', img: '/img/assets/ntry/bitmap/ai/obstacle_1.png', size: 24, }, { type: 'Image', img: '/img/assets/week/blocks/for.png', size: 24, }, { type: 'LineBreak', }, ], func(entity, script) { if (script.isLooped) { delete script.isLooped; return script.callReturn(); } const radar = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.RADAR); const statements = this.block.statements; let index = 1; script.isLooped = true; if (radar.center.type == Ntry.STATIC.AI_METEO && radar.center.distance == 1) { index = 0; } this.executor.stepInto(statements[index]); return Entry.STATIC.BREAK; }, }, ai_boolean_distance: { skeleton: 'basic_boolean_field', mode: 'maze', color: '#2fc9f0', fontColor: EntryStatic.colorSet.common.WHITE, syntax: ['Scope', 'radar_%1 %2 %3#'], params: [ { type: 'Dropdown', options: [ [Lang.Menus.ai_above, 'UP'], [Lang.Menus.ai_front, 'RIGHT'], [Lang.Menus.ai_under, 'DOWN'], ], value: 'RIGHT', fontSize: 11, }, { type: 'Dropdown', options: [ ['>', 'BIGGER'], ['>=', 'BIGGER_EQUAL'], ['=', 'EQUAL'], ['<', 'SMALLER'], ['<=', 'SMALLER_EQUAL'], ], value: 'BIGGER', fontSize: 11, }, { type: 'Block', accept: 'string', }, ], func(entity) { const radar = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.RADAR); const params = this.block.params; const direction = params[0]; const operator = params[1]; const value = this.getParam(2); let radarValue; switch (direction) { case 'UP': radarValue = radar.left; break; case 'RIGHT': radarValue = radar.center; break; case 'DOWN': radarValue = radar.right; break; } if (radarValue.type == Ntry.STATIC.AI_GOAL) { radarValue = Number.MAX_VALUE; } else { radarValue = radarValue.distance; } switch (operator) { case 'BIGGER': return radarValue > value; case 'BIGGER_EQUAL': return radarValue >= value; case 'EQUAL': return radarValue == value; case 'SMALLER': return radarValue < value; case 'SMALLER_EQUAL': return radarValue <= value; } }, }, ai_distance_value: { skeleton: 'basic_string_field', mode: 'maze', color: EntryStatic.colorSet.block.lighten.CALC, syntax: ['Scope', 'radar_%1#'], params: [ { type: 'Dropdown', options: [ [Lang.Menus.ai_above, 'UP'], [Lang.Menus.ai_front, 'RIGHT'], [Lang.Menus.ai_under, 'DOWN'], ], value: 'RIGHT', fontSize: 11, }, ], func(entity, script) { const radar = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.RADAR); let radarValue = {}; switch (this.block.params[0]) { case 'UP': radarValue = radar.left; break; case 'RIGHT': radarValue = radar.center; break; case 'DOWN': radarValue = radar.right; break; } return radarValue.type == Ntry.STATIC.AI_GOAL ? Number.MAX_VALUE : radarValue.distance; }, }, ai_boolean_object: { skeleton: 'basic_boolean_field', fontColor: EntryStatic.colorSet.common.WHITE, mode: 'maze', color: '#2fc9f0', syntax: ['Scope', 'object_%1 == %2#'], params: [ { type: 'Dropdown', options: [ [Lang.Menus.ai_above, 'UP'], [Lang.Menus.ai_front, 'RIGHT'], [Lang.Menus.ai_under, 'DOWN'], ], value: 'RIGHT', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [ [Lang.Menus.asteroids, 'OBSTACLE'], [Lang.Menus.wall, 'WALL'], [Lang.Menus.item, 'ITEM'], ], value: 'OBSTACLE', fontSize: 11, }, ], func(entity) { const radar = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.RADAR); const params = this.block.params; let radarValue; switch (params[0]) { case 'UP': radarValue = radar.left.type; break; case 'RIGHT': radarValue = radar.center.type; break; case 'DOWN': radarValue = radar.right.type; break; } switch (params[1]) { case 'OBSTACLE': return radarValue == Ntry.STATIC.AI_METEO; case 'WALL': return radarValue == Ntry.STATIC.AI_WALL; case 'ITEM': return radarValue == Ntry.STATIC.AI_ITEM; } }, }, ai_use_item: { skeleton: 'basic', mode: 'maze', color: '#EACF11', syntax: ['Scope', 'use_item'], params: [ { type: 'Image', img: '/img/assets/week/blocks/item.png', size: 24, }, ], func(entity, script) { if (!script.isStart) { Ntry.dispatchEvent('triggerWeapon'); script.isStart = true; script.isAction = true; Ntry.dispatchEvent('gridChange', () => { script.isAction = false; }); const spaceShipComp = Ntry.entityManager.getComponent( entity.id, Ntry.STATIC.SPACE_SHIP ); spaceShipComp.direction = Ntry.STATIC.EAST; const gridComp = Ntry.entityManager.getComponent(entity.id, Ntry.STATIC.GRID); Ntry.entityManager.addComponent(entity.id, { type: Ntry.STATIC.ANIMATE, animateType: Ntry.STATIC.ROTATE_TO, animateValue: 0, }); gridComp.x++; return script; } else if (script.isAction) { return script; } else { delete script.isAction; delete script.isStart; return script.callReturn(); } }, }, ai_boolean_and: { color: '#2fc9f0', skeleton: 'basic_boolean_field', fontColor: EntryStatic.colorSet.common.WHITE, statements: [], syntax: ['Scope', '%1 && %3#'], params: [ { type: 'Block', accept: 'boolean', }, { type: 'Text', text: Lang.Blocks.JUDGEMENT_boolean_and, color: EntryStatic.colorSet.common.WHITE, }, { type: 'Block', accept: 'boolean', }, ], events: {}, func() { return this.getParam(0) && this.getParam(2); }, }, ai_True: { color: '#2fc9f0', skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.JUDGEMENT_true, color: '#3D3D3D', }, ], events: {}, def: { params: [null], type: 'True', }, func() { return true; }, isPrimitive: true, }, ai_if_else: { color: EntryStatic.colorSet.block.default.FLOW, skeleton: 'basic_double_loop', statements: [ { accept: 'basic', }, { accept: 'basic', }, ], params: [ { type: 'Block', accept: 'boolean', }, { type: 'Indicator', img: 'block_icon/if.png', size: 12, }, { type: 'LineBreak', }, ], func(sprite, script) { if (script.isCondition) { delete script.isCondition; return script.callReturn(); } const value = this.getParam(0); script.isCondition = true; const statement = this.block.statements[value ? 0 : 1]; //no blocks end execute if (statement.getBlocks().length === 0) { return this.executor.end(); } else { return this.executor.stepInto(statement); } }, syntax: ['BasicIf', 'true'], }, //endregion basic 기본 //region basic 기본 hidden: { color: EntryStatic.colorSet.block.default.HIDDEN, outerLine: EntryStatic.colorSet.block.darken.HIDDEN, skeleton: 'basic', template: ' %1 %2', statements: [], params: [ { type: 'TextInput', value: '?', clearBG: true, color: 'white', fontSize: 12, }, { type: 'Indicator', color: '#6B6B6B', size: 12, }, ], events: {}, def: { params: [null], type: 'hidden', }, paramsKeyMap: { VALUE: 0, }, class: 'etc', isNotFor: [], func() {}, }, hidden_event: { color: EntryStatic.colorSet.block.default.HIDDEN, outerLine: EntryStatic.colorSet.block.darken.HIDDEN, skeleton: 'basic_event', template: ' %1 ', statements: [], params: [ { type: 'TextInput', value: '?', clearBG: true, color: 'white', fontSize: 12, }, { type: 'Indicator', color: '#6B6B6B', size: 12, }, ], events: {}, def: { params: [null], type: 'hidden_event', }, paramsKeyMap: { VALUE: 0, }, class: 'etc', isNotFor: [], func() {}, }, hidden_loop: { color: EntryStatic.colorSet.block.default.HIDDEN, outerLine: EntryStatic.colorSet.block.darken.HIDDEN, skeleton: 'basic_loop', statements: [ { accept: 'basic', }, ], params: [ { type: 'Image', img: '/img/assets/maze/icon/group.png', size: { width: 47, height: 20, }, }, { type: 'Indicator', color: '#6B6B6B', size: 12, }, ], events: {}, def: { params: [null], type: 'hidden_if', }, class: 'etc', isNotFor: [], func() {}, }, hidden_loop2: { color: EntryStatic.colorSet.block.default.HIDDEN, outerLine: EntryStatic.colorSet.block.darken.HIDDEN, skeleton: 'basic_loop', template: ' %1 ', statements: [ { accept: 'basic', }, ], params: [ { type: 'TextInput', value: '?', clearBG: true, color: 'white', fontSize: 12, }, { type: 'Indicator', color: '#6B6B6B', size: 12, }, ], events: {}, def: { params: [null], type: 'hidden_loop2', }, paramsKeyMap: { VALUE: 0, }, class: 'etc', isNotFor: [], func() {}, }, hidden_if_else: { color: EntryStatic.colorSet.block.default.HIDDEN, outerLine: EntryStatic.colorSet.block.darken.HIDDEN, skeleton: 'basic_double_loop', template: ' %1 %2%3', statements: [ { accept: 'basic', }, { accept: 'basic', }, ], params: [ { type: 'TextInput', value: '?', clearBG: true, color: 'white', fontSize: 12, }, { type: 'Indicator', color: '#6B6B6B', size: 12, }, { type: 'LineBreak', }, ], events: {}, def: { params: [null], type: 'hidden_if', }, class: 'etc', isNotFor: [], func() {}, }, hidden_if_else2: { color: EntryStatic.colorSet.block.default.HIDDEN, outerLine: EntryStatic.colorSet.block.darken.HIDDEN, skeleton: 'basic_double_loop', template: ' %1 %2%3 %4 ', statements: [ { accept: 'basic', }, { accept: 'basic', }, ], params: [ { type: 'TextInput', value: '?', clearBG: true, color: 'white', fontSize: 12, }, { type: 'Indicator', color: '#6B6B6B', size: 12, }, { type: 'LineBreak', }, { type: 'TextInput', value: '?', clearBG: true, color: 'white', fontSize: 12, }, ], events: {}, def: { params: [null], type: 'hidden_if_else2', }, class: 'etc', isNotFor: [], func() {}, }, hidden_string: { color: EntryStatic.colorSet.block.default.HIDDEN, outerLine: EntryStatic.colorSet.block.darken.HIDDEN, skeleton: 'basic_string_field', template: ' %1 ', fontColor: EntryStatic.colorSet.common.WHITE, statements: [], params: [ { type: 'TextInput', value: '?', clearBG: true, color: 'white', fontSize: 12, }, ], events: {}, def: { params: [], type: 'hidden_string', }, paramsKeyMap: { VALUE: 0, }, class: 'etc', isNotFor: [], func() {}, }, hidden_boolean: { color: EntryStatic.colorSet.block.default.HIDDEN, outerLine: EntryStatic.colorSet.block.darken.HIDDEN, skeleton: 'basic_boolean_field', template: ' %1 ', fontColor: EntryStatic.colorSet.common.WHITE, statements: [], params: [ { type: 'TextInput', value: '?', clearBG: true, color: 'white', fontSize: 12, }, ], events: {}, def: { params: [], type: 'hidden_boolean', }, paramsKeyMap: {}, class: 'etc', isNotFor: [], func() {}, }, //endregion basic 기본 //region basic 기본 boolean_shell: { color: EntryStatic.colorSet.block.default.JUDGE, skeleton: 'basic_boolean_field', template: '%1', isPrimitive: true, params: [ { type: 'Text', text: 'A', color: '#3D3D3D', }, ], func() {}, }, //endregion basic 기본 }; } function inheritBlockSchema() { for (const type in Entry.block) { const block = Entry.block[type]; if (!block.isNotFor) { block.isNotFor = []; } if (block.parent) { const F = function () {}; F.prototype = Entry.block[block.parent]; const schema = new F(); schema.syntax = undefined; for (const key in block) { schema[key] = block[key]; } Entry.block[type] = schema; } } } function assignBlocks() { Entry.block.converters = getConverters(); Entry.block.changeBlockText = function (key, text) { const block = this[key]; if (block) { block.params[0].text = text; } }; Entry.block.changeBlockEvent = function (key, event, callback) { const block = this[key]; if (block) { block.events[event] = [callback]; } }; Entry.block = Object.assign(Entry.block, getBlocks(), blocks.getBlocks()); } function applySetLanguage(hasSetLanguageObj) { if ('setLanguage' in hasSetLanguageObj) { const hwLang = hasSetLanguageObj.setLanguage(); const data = hwLang[Lang.type] || hwLang[Lang.fallbackType]; for (const key in data) { Object.assign(Lang[key], data[key]); } } } Entry.reloadBlock = function () { Object.values(Entry.HARDWARE_LIST).forEach(applySetLanguage); Object.values(Entry.HARDWARE_LITE_LIST).forEach(applySetLanguage); assignBlocks(); inheritBlockSchema(); }; Entry.reloadBlock(); Entry.destroyBlock = function () { blocks.destroyBlockList.forEach((fn) => { fn(); }); }; if (typeof exports === 'object') { exports.block = Entry.block; exports.assignBlocks = assignBlocks; } ================================================ FILE: src/playground/block_entry_mini.js ================================================ const miniBlock = { practical_course_dummy: { color: '#7C7C7C', skeleton: 'basic', statements: [], isNotFor: ['arduinoDisconnected'], template: '%1', params: [ { type: 'Indicator', color: '#6B6B6B', size: 12, }, ], events: {}, def: { params: [null], type: 'practical_course_dummy', }, paramsKeyMap: { VALUE: 0, }, func(sprite, script) {}, }, // roborobo_mini /* Dream 블럭 추가*/ }; module.exports.practicalCourseBlock = miniBlock; // module.exports.setLanguage = () => ({ // ko: { // Helper: { // robotis_set_led: 'LED 모듈이 연결된 [포트]를 선택해 지정한 색의 LED를 켜거나 끕니다.', // robotis_touch_value: '접촉센서가 연결된 [포트]의 값입니다.', // robotis_touch_value_boolean: // '접촉센서가 연결된 [포트]를 선택해 [접촉되면/접촉 안되면]을 지정합니다.', // robotis_irs_value: '적외선 센서가 연결된 [포트]의 값입니다.', // robotis_irs_value_boolean: // '적외선 센서가 연결된 [포트]의 값을 [입력]한 숫자와 비교합니다.', // robotis_light_value: '빛감지 센서가 연결된 [포트]의 값입니다.', // robotis_light_value_boolean: // '빛감지 센서가 연결된 [포트]의값을 [입력]한 숫자와 비교합니다.', // robotis_userbutton_value: '사용자 버튼의 값입니다.', // robotis_userbutton_value_boolean: '사용자 버튼이 [접촉되면/접촉 안되면]을 지정합니다.', // robotis_detectedsound_value: '소리 센서가 입력받은 실시간 소리 값입니다.', // robotis_detectedsound_value_boolean: // '소리 센서의 실시간 소리 값과 [입력]한 숫자를 비교합니다.', // robotis_detectedsound_value_init: '소리 센서의 최종 소리 값을 초기화합니다.', // robotis_detectingsound_value: '소리 센서가 입력받은 최종 소리 값입니다.', // robotis_detectingsound_value_boolean: // '소리 센서의 최종 소리 값과 [입력]한 숫자를 비교합니다.', // robotis_color_value: '컬러 센서가 연결된 [포트]의 값입니다.', // robotis_color_value_boolean: // '컬러 센서가 연결된 [포트]의 값을 [선택]한 숫자와 비교합니다.', // robotis_humidity_value: '습도 센서가 연결된 [포트]의 값입니다.', // robotis_humidity_value_boolean: // '습도 센서가 연결된 [포트]의 값을 [입력]한 숫자와 비교합니다.', // robotis_temperature_value: '온도 센서가 연결된 [포트]의 값입니다.', // robotis_temperature_value_boolean: // '온도 센서가 연결된 [포트]의 값을 [입력]한 숫자와 비교합니다.', // robotis_move_for_secs: // '연결된 모터의 [방향/속도]를 선택하고 [입력]한 시간만큼 회전시킵니다.\n입력한시간이 끝나면 모터는 정지합니다.', // robotis_aux_move_for: '연결된 모터의 [방향/속도]를 선택해 회전시킵니다.', // robotis_aux_stop_for: '모터를 선택해 정지시킵니다', // robotis_set_servo_wheel: '서보모터의 [포트/방향/속도]를 선택해 회전시킵니다', // robotis_set_servo_joint: '서보모터의 [포트/위치값/속도]를 입력해 동작시킵니다.', // robotis_melody_note_for: '멜로디의 [음계/옥타브/길이]를 선택해 연주합니다.', // }, // }, // en: { // Helper: { // robotis_aux_move_for: '', // }, // }, // jp: { // Helper: { // robotis_aux_move_for: '', // }, // }, // vn: { // Helper: { // robotis_aux_move_for: '', // }, // }, // }); ================================================ FILE: src/playground/block_menu.ts ================================================ import Visible from '@egjs/visible'; import compact from 'lodash/compact'; import debounce from 'lodash/debounce'; import each from 'lodash/each'; import isEmpty from 'lodash/isEmpty'; import identity from 'lodash/identity'; import remove from 'lodash/remove'; import includes from 'lodash/includes'; import head from 'lodash/head'; import find from 'lodash/find'; import ModelClass from '../core/modelClass'; import Hammer from 'hammerjs'; import { EntryDom } from '../../types/index'; const VARIABLE = 'variable'; const HW = 'arduino'; const practicalCourseCategoryList = ['hw_motor', 'hw_melody', 'hw_sensor', 'hw_led', 'hw_robot']; const splitterHPadding = EntryStatic.splitterHPadding || 20; const BETA_LIST = []; type BlockMenuAlignType = 'LEFT' | 'CENTER'; type CategoryData = { category: string; blocks: string[]; visible?: boolean; }; type Schema = { code: any; dragBlock: any; closeBlock: any; selectedBlockView: any; }; class BlockMenu extends ModelClass { public visible = true; public hwCodeOutdated = false; public code: any; public view: EntryDom; public changeEvent: any; // Entry.Event public categoryDoneEvent: any; // Entry.Event public codeListener: any; // Entry.Event private readonly _svgId = `blockMenu${Date.now()}`; private readonly suffix = 'blockMenu'; private readonly _dSelectMenu: any; private readonly _scroll: boolean; private readonly _scroller: any; // Entry.BlockMenuScroller private readonly _bannedClass: string[]; private readonly _splitters: any[]; // view elements private svg: any; // Entry.SVG private svgDom: EntryDom; private pattern: any; private svgGroup: any; private svgThreadGroup: any; private svgBlockGroup: any; private svgCommentGroup: any; private _boardBlockView: any; // in block private _categoryCol: EntryDom; private _offset: JQuery.Coordinates; private categoryWrapper: EntryDom; private blockMenuContainer: EntryDom; private blockMenuWrapper: EntryDom; private blockMenuWrapperForTrashcan: EntryDom; private objectAlert: any; private _dynamicThreads: any[]; private _selectDynamic: boolean; private _setDynamicTimer: any; private _align: BlockMenuAlignType; private _categories: any[]; private _categoryData: CategoryData[]; private _categoryElems: { [categoryName: string]: EntryDom }; private _selectedCategoryView?: EntryDom; private _renderedCategories: { [key: string]: boolean }; private _threadsMap: { [key: string]: any }; // any => thread private _svgWidth: number; private _generateCodesTimer: NodeJS.Timeout; private categoryIndicatorVisible: any; // egjs.visible private widthBackup: number; private lastSelector: string; private firstSelector: string; private workspace: any; private dragInstance: any; // Entry.dragInstance // schema private selectedBlockView: any; private dragBlock: any; _setDynamic = debounce((blocks = []) => { if (!this._isOn()) { return; } let data; this._dynamicThreads = blocks .map((block: any) => { if (typeof block === 'string') { return block; } else if (block.constructor === Array) { const keyName = block[0]; if (!this.getThreadByBlockKey(keyName)) { data = block[1]; data.category = 'extra'; this._createThread([data], undefined, keyName); } return keyName; } }) .filter(identity); this._selectDynamic = true; this.selectMenu(undefined, true); }, 150); reDraw = debounce(() => { if (!this._isOn()) { return; } let selector = this.lastSelector; if (this._selectDynamic) { selector = undefined; } this.selectMenu(selector, true); this._getSortedBlocks() .shift() .forEach(({ view }) => view.reDraw()); }, 100); constructor( dom: EntryDom, align: BlockMenuAlignType, categoryData: CategoryData[], scroll: boolean ) { super( { code: null, dragBlock: null, closeBlock: null, selectedBlockView: null, }, false ); const { hardwareEnable } = Entry; this._dSelectMenu = debounce(this.selectMenu, 0); this._align = align || 'CENTER'; this._svgWidth = 254; this._scroll = scroll !== undefined ? scroll : false; this._bannedClass = []; this._categories = []; this._dynamicThreads = []; this._setDynamicTimer = null; this._renderedCategories = {}; this._threadsMap = {}; const $dom = typeof dom === 'string' ? $(`#${dom}`) : $(dom); if ($dom.prop('tagName') !== 'DIV') { throw new Error('Dom is not div element'); } this.view = $dom; this._clearCategory(); // hardwareEnable 인 경우, 하드웨어 카테고리와 실과형 로봇카테고리 전부를 제외한다. this._categoryData = remove( categoryData, ({ category }) => hardwareEnable || [...practicalCourseCategoryList, HW].indexOf(category) <= -1 ); this._generateView(this._categoryData); this._splitters = []; this.svg = Entry.SVG(this._svgId); Entry.Utils.addFilters(this.svg, this.suffix); const { pattern } = Entry.Utils.addBlockPattern(this.svg, this.suffix); this.pattern = pattern; this.svgGroup = this.svg.elem('g'); this.svgThreadGroup = this.svgGroup.elem('g'); this.svgThreadGroup.board = this; this.svgBlockGroup = this.svgGroup.elem('g'); this.svgBlockGroup.board = this; this.svgCommentGroup = this.svgGroup.elem('g'); this.svgCommentGroup.board = this; this.changeEvent = new Entry.Event(this); this.categoryDoneEvent = new Entry.Event(this); this.observe(this, '_handleDragBlock', ['dragBlock']); this.changeCode(new Entry.Code([])); this._categoryData && this._generateCategoryCodes(); if (this._scroll) { this._scroller = new Entry.BlockMenuScroller(this); this._addControl($dom.find('.blockMenuContainer')); } if (this.code && Entry.keyPressed) { Entry.keyPressed.attach(this, this._captureKeyEvent); } if (Entry.windowResized) { Entry.windowResized.attach(this, debounce(this.updateOffset, 200)); } Entry.addEventListener( 'setBlockMenuDynamic', function () { this._setDynamicTimer = this._setDynamic.apply(this, arguments); }.bind(this) ); Entry.addEventListener('cancelBlockMenuDynamic', this._cancelDynamic.bind(this)); Entry.addEventListener('fontLoaded', this.reDraw.bind(this)); this.initBlockDoubleClickEvent(); } initBlockDoubleClickEvent() { const hammer = new Hammer(this.code.board.svgBlockGroup); hammer.on('doubletap', (e: { target: HTMLElement }) => { const blockId = e.target.getAttribute('blockId'); if (!blockId) { return; } const targetBlock = this.code.findById(blockId); if ( targetBlock.type.startsWith('func_') || ['basic_text', 'clickable_text', 'basic_button'].includes( targetBlock?._schema?.skeleton ) ) { return; } const { width, height } = targetBlock.view; const { scale, svg } = this.workspace.board; const { left, top, right, bottom } = svg.getBoundingClientRect(); const boardCenterX = (Math.min(window.innerWidth, right) - left) / 2; const boardCenterY = (Math.min(window.innerHeight, bottom) - top) / 2; const block = targetBlock.toJSON(true); block.x = boardCenterX - (width * scale) / 2; block.y = boardCenterY - (height * scale) / 2; Entry.do('addThread', [block]); }); } foldBlockMenu() { const playground = Entry.playground; if (!playground || playground.resizing) { return; } if (this._scroller) { this._scroller.setOpacity(0); } const widthBackup = this.widthBackup; if (widthBackup) { $(this.blockMenuWrapper).css('width', widthBackup); } delete this.widthBackup; } changeCode(code: any) { if (code instanceof Array) { code = new Entry.Code(code); } if (!(code instanceof Entry.Code)) { return console.error('You must inject code instance'); } // this.codeListener?.destory(); this.codeListener?.destroy?.(); this.set({ code }); this.codeListener = this.code.changeEvent.attach(this, () => { this.changeEvent.notify(); }); code.createView(this); this.align(); } bindCodeView(codeView: any) { this.svgBlockGroup.remove(); this.svgThreadGroup.remove(); this.svgBlockGroup = codeView.svgBlockGroup; this.svgThreadGroup = codeView.svgThreadGroup; this.svgGroup.appendChild(this.svgThreadGroup); this.svgGroup.appendChild(this.svgBlockGroup); if (this._scroller) { this.svgGroup.appendChild(this._scroller.svgGroup); } } align() { const code = this.code; if (!(this._isOn() && code)) { return; } this._clearSplitters(); const vPadding = 15; let marginFromTop = 10; const hPadding = this._align === 'LEFT' ? 10 : this.svgDom.width() / 2; let pastClass: string; const blocks = this._getSortedBlocks(); const [visibles = [], inVisibles = []] = blocks; inVisibles.forEach(({ view: blockView } = {}) => { if (!blockView) { return; } blockView.set({ display: false }); blockView.detach(); }); const lastSelector = this.lastSelector; const shouldReDraw = !this._renderedCategories[lastSelector]; visibles.forEach(({ view: blockView, type } = {}, index) => { if (!blockView) { return; } blockView.attach(); blockView.set({ display: true }); if (shouldReDraw || (Entry?.Func?.isEdit && blockView?.block?.data?.params?.length)) { blockView.reDraw(); } if (Entry.block[type]) { const className = Entry.block[type].class; if (pastClass && pastClass !== className) { this._createSplitter(marginFromTop); marginFromTop += vPadding; } pastClass = className; } let left = hPadding - blockView.offsetX; if (this._align === 'CENTER') { left -= blockView.width / 2; } marginFromTop -= blockView.offsetY; blockView.moveTo(left, marginFromTop, false); if (index > 0) { marginFromTop += blockView.marginBottom || 0; } marginFromTop += blockView.height + vPadding; }); this.updateSplitters(); if (this.workspace) { const mode = this.workspace.getMode(); switch (mode) { case Entry.Workspace.MODE_BOARD: case Entry.Workspace.MODE_OVERLAYBOARD: this.renderBlock(blocks); break; case Entry.Workspace.MODE_VIMBOARD: this.renderText(blocks); break; default: this.renderBlock(blocks); } } if (lastSelector !== 'func') { this._renderedCategories[lastSelector] = true; } this.changeEvent.notify(); } cloneToGlobal(e: any) { const blockView = this.dragBlock; if (this._boardBlockView || blockView === null) { if (this.widthBackup) { this.foldBlockMenu(); } return; } const GS = Entry.GlobalSvg; const workspace = this.workspace; const workspaceMode = workspace.getMode(); const { MODE_BOARD, MODE_OVERLAYBOARD } = Entry.Workspace; const svgWidth = this._svgWidth; const board = workspace.selectedBoard; const { x = 0, y = 0 } = blockView.mouseDownCoordinate || {}; const dx = e.pageX - x; const dy = e.pageY - y; if (board && (workspaceMode === MODE_BOARD || workspaceMode === MODE_OVERLAYBOARD)) { if (!board.code) { if (Entry.toast && !(this.objectAlert && Entry.toast.isOpen(this.objectAlert))) { this.objectAlert = Entry.toast.alert( Lang.Workspace.add_object_alert, Lang.Workspace.add_object_alert_msg ); } if (this.selectedBlockView) { this.selectedBlockView.removeSelected(); this.set({ selectedBlockView: null, dragBlock: null, }); } return; } const block = blockView.block; const currentThread = block.getThread(); if (block && currentThread) { const distance = this.offset().top - board.offset().top - $(window).scrollTop(); const datum = currentThread.toJSON(true); const firstBlock: any = head(datum); firstBlock.x = firstBlock.x - svgWidth + (dx || 0); firstBlock.y = firstBlock.y + distance + (dy || 0); const newBlock = Entry.do('addThreadFromBlockMenu', datum).value.getFirstBlock(); const newBlockView = newBlock?.view; // if some error occured // blockView is not exist if (!newBlockView) { newBlock?.destory(); return; } this._boardBlockView = newBlockView; newBlockView.onMouseDown.call(newBlockView, e); if (newBlockView.dragInstance) { newBlockView.dragInstance.set({ isNew: true, }); } GS.setView(newBlockView, workspaceMode); } else { } } else { if (GS.setView(blockView, workspaceMode)) { GS.adjust(dx, dy); GS.addControl(e); } } } terminateDrag() { const boardBlockView = this._boardBlockView; if (!boardBlockView) { return; } this._boardBlockView = null; //board block should be removed below the amount of range const { left, width } = Entry.GlobalSvg; return left < boardBlockView.getBoard().offset().left - width / 2; } getCode() { return this.code; } setSelectedBlock(blockView?: any) { this.selectedBlockView?.removeSelected(); if (blockView instanceof Entry.BlockView) { blockView.addSelected(); } else { blockView = null; } this.set({ selectedBlockView: blockView }); } hide() { this.view.addClass('entryRemove'); } show() { this.view.removeClass('entryRemove'); } renderText(blocks?: any[]) { if (!this._isOn()) { return; } blocks = blocks || this._getSortedBlocks(); const targetMode = Entry.BlockView.RENDER_MODE_TEXT; blocks[0].forEach((block: any) => { if (targetMode === block.view.renderMode) { return; } const thread = block.getThread(); const view = thread.view; if (view) { view.renderText(); } else { thread.createView(this, Entry.BlockView.RENDER_MODE_TEXT); } }); return blocks; } renderBlock(blocks?: any[]) { if (!this._isOn()) { return; } blocks = blocks || this._getSortedBlocks(); const targetMode = Entry.BlockView.RENDER_MODE_BLOCK; blocks[0].forEach((block: any) => { if (targetMode === block.view.renderMode) { return; } const thread = block.getThread(); const view = thread.view; if (view) { view.renderBlock(); } else { thread.createView(this, Entry.BlockView.RENDER_MODE_BLOCK); } }); return blocks; } _createSplitter(topPos: number) { const { common = {} } = EntryStatic.colorSet || {}; this._splitters.push( this.svgBlockGroup.elem('line', { x1: splitterHPadding, y1: topPos, x2: this._svgWidth - splitterHPadding, y2: topPos, stroke: common.SPLITTER || '#AAC5D5', }) ); } updateSplitters(y = 0) { const xDest = this._svgWidth - splitterHPadding; let yDest; this._splitters.forEach((line) => { yDest = parseFloat(line.getAttribute('y1')) + y; line.attr({ x2: xDest, y1: yDest, y2: yDest, }); }); } setMenu(doNotAlign?: boolean) { if (!this.hasCategory()) { return; } const sorted: [any[], any[]] = [[], []]; this._categoryData.forEach(({ category, blocks: threads }) => { if (category === 'func') { const funcThreads = this.code .getThreadsByCategory('func') .map((thread: any) => thread.getFirstBlock().type); threads = funcThreads.length ? funcThreads : threads; } const inVisible = threads.reduce( (count, type) => (this.checkBanClass(Entry.block[type]) ? count - 1 : count), threads.length ) === 0; const elem = this._categoryElems[category]; if (inVisible) { sorted[1].push(elem); } else { sorted[0].push(elem); } }); requestAnimationFrame(() => { //visible sorted[0].forEach((elem) => elem.removeClass('entryRemove')); //invisible sorted[1].forEach((elem) => elem.addClass('entryRemove')); this.selectMenu(0, true, doNotAlign); }); } toggleBlockMenu() { const board = this.workspace.board; const boardView = board.view; if (!boardView.hasClass('folding')) { boardView.addClass('folding'); Entry.playground.resizeHandle_.addClass('highIndex'); Entry.playground.resizeHandle_.addClass('folding'); Entry.playground.resizeHandle_.removeClass('unfolding'); Entry.playground.hideTabs(); this.visible = false; } else { if (!this.visible) { boardView.addClass('foldOut'); Entry.playground.showTabs(); } boardView.removeClass('folding'); Entry.playground.resizeHandle_.addClass('highIndex'); Entry.playground.resizeHandle_.addClass('unfolding'); Entry.playground.resizeHandle_.removeClass('folding'); this.visible = true; } Entry.bindAnimationCallbackOnce(boardView, () => { board.scroller.resizeScrollBar.call(board.scroller); boardView.removeClass('foldOut'); Entry.playground.resizeHandle_.removeClass('highIndex'); Entry.windowResized.notify(); }); this.align(); } selectMenu(selector: number | string, doNotFold: boolean, doNotAlign?: boolean) { if (Entry.disposeEvent) { Entry.disposeEvent.notify(); } if (!this._isOn() || !this._categoryData) { return; } const oldView = this._selectedCategoryView; const name = this._convertSelector(selector); if (selector !== undefined && !name) { this.align(); return; } if (name) { this.lastSelector = name; } switch (name) { case VARIABLE: Entry.playground.checkVariables(); break; case HW: this._generateHwCode(); this.align(); break; } const elem = this._categoryElems[name]; let animate = false; const board = this.workspace.board; const boardView = board.view; const handle = Entry.playground.resizeHandle_; const className = 'entrySelectedCategory'; const className2 = 'entryUnSelectedCategory'; if (oldView) { oldView.removeClass(className); oldView.addClass(className2); } if (elem === oldView && !(doNotFold || !this.hasCategory())) { elem.removeClass(className); elem.addClass(className2); } this._selectedCategoryView = elem; if (elem) { elem.removeClass(className2); elem.addClass(className); } doNotAlign !== true && this.align(); } banCategory(categoryName: string) { const categoryElem = this._categoryElems[categoryName]; if (!categoryElem) { return; } categoryElem.addClass('entryRemoveCategory'); if (this.lastSelector === categoryName) { this._dSelectMenu(this.firstSelector, true); } } unbanCategory(category: string) { const blockList = this._getCategoryBlocks(category); if (!blockList) { return; } const count = blockList.reduce( (count, block) => (this.checkBanClass(Entry.block[block]) ? count - 1 : count), blockList.length ); const categoryElem = this._categoryElems[category]; if (categoryElem && count > 0) { categoryElem.removeClass('entryRemoveCategory'); categoryElem.removeClass('entryRemove'); } } banClass(className: string, doNotAlign?: boolean) { const banned = this._bannedClass; if (!includes(banned, className)) { banned.push(className); doNotAlign !== true && this.align(); } } unbanClass(className: string, doNotAlign?: boolean) { const banned = this._bannedClass; const index = banned.indexOf(className); if (index > -1) { banned.splice(index, 1); doNotAlign !== true && this.align(); } } checkBanClass({ isNotFor = [] } = {}) { if (isEmpty(isNotFor)) { return false; } const banned = this._bannedClass; const filteredIsNotFor = isNotFor.filter(identity); for (let i = 0; i < filteredIsNotFor.length; i++) { if (!includes(banned, filteredIsNotFor[i])) { return false; } } return true; } checkCategory(blockInfo: any) { if (!this.hasCategory() || !blockInfo) { return; } if (!this.lastSelector || this._selectDynamic) { return true; } return !includes(blockInfo.isFor || [], `category_${this.lastSelector}`); } /** * 특정 카테고리에 특정 블록명을 추가한다. * 카테고리가 존재하지 않거나 블록명이 이미 등록된 경우 스킵한다. * Entry.block 목록에 실제 데이터가 있는지, blockMenu 의 그리기 갱신이 필요한지는 상관하지 않는다. * @param categoryName {string} * @param blockName {string} */ addCategoryData(categoryName: string, blockName: string) { const selectedCategory = this._categoryData.find( (element) => element.category === categoryName ); if (selectedCategory?.blocks.indexOf(blockName) === -1) { selectedCategory.blocks.push(blockName); } if (!this.getThreadByBlockKey(blockName)) { const threadDatum = this._buildCategoryCodes([blockName], categoryName); this._createThread(threadDatum[0]); } } destroy() { this.categoryIndicatorVisible.off(); this._categoryCol.off(); $(document).off('.blockMenuScroll'); } removeControl(eventType: string) { this.svgDom.off(eventType); } onMouseMove(e: JQuery.MouseMoveEvent) { e?.stopPropagation(); if (Entry.isMobile()) { this._scroller.setOpacity(0.8); } const { pageY } = Entry.Utils.convertMouseEvent(e); const dragInstance = this.dragInstance; this._scroller.scroll(-pageY + dragInstance.offsetY); dragInstance.set({ offsetY: pageY }); } onMouseUp(e: JQuery.MouseUpEvent) { if (Entry.isMobile()) { this._scroller.setOpacity(0); } if (e.which == 2) { console.log('mouse wheel click disabled'); return; } if (e.button != 1) { $(document).unbind('.blockMenu'); delete this.dragInstance; } } onMouseDown(e: JQuery.TouchMoveEvent) { if (e.preventDefault) { e.preventDefault(); } if (e.which == 2) { console.log('mouse wheel click disabled'); return; } if (e.button === 0 || e.originalEvent?.touches) { const mouseEvent = Entry.Utils.convertMouseEvent(e); if (Entry.documentMousedown) { Entry.documentMousedown.notify(mouseEvent); } const doc = $(document); doc.bind('mousemove.blockMenu touchmove.blockMenu', this.onMouseMove.bind(this)); doc.bind('mouseup.blockMenu touchend.blockMenu', this.onMouseUp.bind(this)); this.dragInstance = new Entry.DragInstance({ startY: mouseEvent.pageY, offsetY: mouseEvent.pageY, }); } } dominate({ view: { svgGroup } }: any) { this.svgBlockGroup.appendChild(svgGroup); } _handleDragBlock() { this._boardBlockView = null; if (this._scroller) { this._scroller.setOpacity(0); } } _handleBoardDragBlock() { this._toggleTrashcan(!!this.workspace?.board?.dragBlock); } _toggleTrashcan(visible: boolean) { this.blockMenuWrapperForTrashcan?.toggleClass('entryRemove', !visible); } enablePattern() { this.pattern.removeAttribute('style'); } disablePattern() { this.pattern.attr({ style: 'display: none' }); } /** * lms, entry-web 에서 사용 중 */ setCategoryData(data: CategoryData[]) { this._clearCategory(); this._categoryData = data; this._generateCategoryView(data); this._generateCategoryCodes(); this.setMenu(); Entry.resizeElement(); } /** * lms 에서 사용 중 */ setNoCategoryData(data: any) { this._clearCategory(); Entry.resizeElement(); this.changeCode(data); this.categoryDoneEvent.notify(); } makeScrollIndicator() { ['append', 'prepend'].forEach((action) => { const point = Entry.Dom('li', { class: `visiblePoint ${action}`, }); const indicator = Entry.Dom('a', { class: `scrollIndicator ${action}`, }); indicator.bindOnClick(() => { point[0].scrollIntoView({ behavior: 'smooth', block: 'nearest', }); }); point.attr('data-action', action); indicator.attr('data-action', action); //@ts-ignore this._categoryCol[action](point); //@ts-ignore this._categoryCol[action](indicator); }); this.categoryIndicatorVisible = new Visible('.entryCategoryListWorkspace', { targetClass: 'visiblePoint', expandSize: 0, }); this.categoryIndicatorVisible.on('change', (e: any) => { e.visible.forEach((dom: any) => { const { dataset } = dom; const { action } = dataset; $(`.scrollIndicator.${action}`).css('display', 'none'); }); e.invisible.forEach((dom: any) => { const { dataset } = dom; const { action } = dataset; $(`.scrollIndicator.${action}`).css('display', 'block'); }); }); this._categoryCol.on( 'scroll', debounce(() => { this.categoryIndicatorVisible.check(); }, 100) ); setTimeout(() => { this.categoryIndicatorVisible.check(); }, 0); if (Entry.windowResized) { Entry.windowResized.attach(this, () => { this.categoryIndicatorVisible.check(); }); } $(document).on('visibilitychange.blockMenuScroll', (e) => { if (document.visibilityState === 'visible') { requestAnimationFrame(() => { this.categoryIndicatorVisible.check(); }); } }); } updateOffset() { this._offset = this.svgDom.offset(); } offset() { const { top = 0, left = 0 } = this._offset || {}; if (top === 0 && left === 0) { this.updateOffset(); } return this._offset; } _generateHwCode(shouldHide?: boolean) { const targetHwCategory = [HW]; const targetPracticalCategories = practicalCourseCategoryList.filter( (category) => category != 'hw_robot' ); EntryStatic.isPracticalCourse && targetHwCategory.push(...targetPracticalCategories); targetHwCategory.map((hwCategory) => { const threads = this.code.getThreadsByCategory(hwCategory); if (!(this._categoryData && this.shouldGenerateHwCode(threads))) { return; } threads.forEach((t: any) => { this._deleteThreadsMap(t); t.destroy(); }); const blocks = this._getCategoryBlocks(hwCategory); if (isEmpty(blocks)) { return; } this._buildCategoryCodes( blocks.filter((b) => !this.checkBanClass(Entry.block[b])), hwCategory ).forEach((t: any) => { if (shouldHide) { t[0].x = -99999; } this._createThread(t); delete t[0].x; }); }); this.hwCodeOutdated = false; Entry.dispatchEvent('hwCodeGenerated'); } /** * Ntry systems/entryPlayground.js#loadConfig 에서 사용됨 * 그 외에는 쓸모없음 * @deprecated */ setAlign(align: BlockMenuAlignType) { this._align = align || 'CENTER'; } _cancelDynamic(fromElement: boolean, cb?: () => void) { if (this._setDynamicTimer) { clearTimeout(this._setDynamicTimer); this._setDynamicTimer = null; } this._selectDynamic = false; this._dynamicThreads = []; if (fromElement !== true) { this.selectMenu(this.lastSelector, true); } cb && cb(); } deleteRendered(name: string) { delete this._renderedCategories[name]; } clearRendered() { this._renderedCategories = {}; } hasCategory() { return !!this._categoryData; } getDom(query: any) { if (isEmpty(query)) { return; } if (query[0] === 'category') { return this._categoryElems[query[1]]; } else { const { type, params = [] } = query[0][0]; this.align(); this.scrollToType(type, params); return this.getSvgDomByType(type, params); } } getSvgDomByType(blockType: string, params: any[]) { const thread = find(this.code.getThreads(), (thread) => { if (!thread) { return; } const { type, params: threadParams } = thread.getFirstBlock(); let option = true; if ( blockType === 'calc_basic' || blockType === 'boolean_basic_operator' || blockType === 'boolean_and_or' ) { option = type === blockType && threadParams[1] === params[1]; } return type === blockType && option; }); if (!thread) { return; } return thread.getFirstBlock().view.svgGroup; } scrollToType(type: string, params: any[]) { if (!type) { return; } const block: any = head(this.code.getBlockList(false, type)); if (!block) { return; } this.hasCategory() && this.selectMenu(block.category, true); if (isOverFlow(this.getSvgDomByType(type, params).getBoundingClientRect())) { this._scroller.scrollByPx(block.view.y - 20); } function isOverFlow({ bottom }: { bottom: number }) { return bottom > $(window).height() - 10; } } shouldGenerateHwCode(threads: any) { return this.hwCodeOutdated || threads.length === 0; } getThreadByBlockKey(key: string) { return this._threadsMap[key]; } private _buildCategoryCodes(blocks: any, category: string) { return blocks.reduce((threads: any, type: string) => { const block = Entry.block[type]; if (!block || !block.def) { return [...threads, [{ type, category }]]; } else { return (block.defs || [block.def]).reduce( (threads: any, d: any) => [...threads, [Object.assign(d, { category })]], threads ); } }, []); } enableTrashcan() { this.blockMenuWrapperForTrashcan = Entry.Dom('div', { class: 'blockMenuWrapper blockMenuTrashcan entryRemove', parent: this.blockMenuContainer, }) .on('pointerenter', () => this.blockMenuWrapperForTrashcan.addClass('open')) .on('pointerleave', () => this.blockMenuWrapperForTrashcan.removeClass('open')); Entry.Dom('span') .text(Lang.Workspace.drag_to_remove) .appendTo(this.blockMenuWrapperForTrashcan); this.workspace?.board?.observe(this, '_handleBoardDragBlock', ['dragBlock']); } changeTypeThreadByBlockKey(key: string) { this.getThreadByBlockKey(key)?.getFirstBlock().changeType(); } private _generateView(categoryData: CategoryData[]) { categoryData && this._generateCategoryView(categoryData); this.blockMenuContainer = Entry.Dom('div', { class: 'blockMenuContainer', parent: this.view, }).css({ position: 'relative', }); Entry.Utils.disableContextmenu(this.blockMenuContainer); this.blockMenuWrapper = Entry.Dom('div', { class: 'blockMenuWrapper', parent: this.blockMenuContainer, }); this.svgDom = Entry.Dom( $( // eslint-disable-next-line max-len `` ), { parent: this.blockMenuWrapper } ); this.svgDom.mouseenter(() => { this._scroller?.setOpacity(0.8); const selectedBlockView = this.workspace.selectedBlockView; if ( !Entry.playground || Entry.playground.resizing || selectedBlockView?.dragMode === Entry.DRAG_MODE_DRAG || Entry.GlobalSvg.isShow ) { return; } const bBox = this.svgGroup.getBBox(); const adjust = this.hasCategory() ? 64 : 0; const expandWidth = bBox.width + bBox.x + adjust + 2; const menuWidth = 319; if (expandWidth > menuWidth) { this.widthBackup = menuWidth - adjust - 2; $(this.blockMenuWrapper).css('width', expandWidth - adjust); } }); this.svgDom.mouseleave(() => { this.foldBlockMenu(); }); Entry.Utils.bindBlockViewHoverEvent(this, this.svgDom); $(window).scroll(this.updateOffset.bind(this)); } private _clearSplitters() { while (this._splitters.length) { this._splitters.pop().remove(); } } private _convertSelector(selector: number | string) { if (!Entry.Utils.isNumber(selector)) { return selector; } let selectorNumber = Number(selector); const categories = this._categories; const elems = this._categoryElems; for (let i = 0; i < categories.length; i++) { const key = categories[i]; const visible = !elems[key].hasClass('entryRemove'); if (visible) { if (selectorNumber-- === 0) { return key; } } } } private _generateCategoryCodes(elems?: any[]) { let elemKeys: string[]; if (!elems) { this.view.addClass('init'); elemKeys = Object.keys(this._categoryElems); } else { elemKeys = elems; } if (isEmpty(elemKeys)) { return; } const key = elemKeys.shift(); if (key !== HW) { this._generateCategoryCode(key); } else { this._generateHwCode(true); } if (elemKeys.length) { this._generateCodesTimer = setTimeout(() => this._generateCategoryCodes(elemKeys), 0); } else { this._generateCodesTimer = null; this.view.removeClass('init'); this.align(); this.categoryDoneEvent.notify(); } } private _generateCategoryCode(category: string) { if (!this._categoryData) { return; } const code = this.code; const blocks = this._getCategoryBlocks(category); if (!blocks) { return; } this._categories.push(category); let index: number; if (category === 'func') { const threads = this.code.getThreadsByCategory('func'); if (threads.length) { index = this.code.getThreadIndex(threads[0]); } } this._buildCategoryCodes(blocks, category).forEach((t: any) => { if (!t || !t[0]) { return; } t[0].x = -99999; this._createThread(t, index); if (index !== undefined) { index++; } delete t[0].x; }); code.changeEvent.notify(); } private _addControl(dom: EntryDom) { dom.on('wheel', this._mouseWheel.bind(this)); if (this._scroller) { $(this.svg).bind('mousedown touchstart', this.onMouseDown.bind(this)); } } // WheelEvent? private _mouseWheel(e: any) { const originalEvent = e.originalEvent; originalEvent.preventDefault(); const disposeEvent = Entry.disposeEvent; if (disposeEvent) { disposeEvent.notify(originalEvent); } this._scroller.scroll(-originalEvent.wheelDeltaY || originalEvent.deltaY / 3); } private _captureKeyEvent(e: KeyboardEvent) { const keyCode = Entry.Utils.inputToKeycode(e); if (!keyCode) { return; } if (e.ctrlKey && Entry.type === 'workspace' && keyCode > 48 && keyCode < 58) { e.preventDefault(); setTimeout(() => { this._cancelDynamic(true); this._dSelectMenu(keyCode, true); }, 200); } } private _clearCategory() { if (this._generateCodesTimer) { clearTimeout(this._generateCodesTimer); this._generateCodesTimer = null; } this._selectedCategoryView = null; this._categories = []; this._threadsMap = {}; each(this._categoryElems, (elem) => elem.remove()); this._categoryElems = {}; const code = this.code; if (code?.constructor == Entry.Code) { code.clear(); } this._categoryCol?.remove(); this._categoryData = null; } /** * 카테고리의 목록 뷰를 그린다. * @param data {{category: string, blocks: object[]}[]} EntryStatic.getAllBlocks * @private */ private _generateCategoryView(data: CategoryData[]) { if (!data) { return; } this._categoryCol?.remove(); // 카테고리가 이미 만들어져있는 상태에서 데이터만 새로 추가된 경우, // categoryWrapper 는 살리고 내부 컬럼 엘리먼트만 치환한다. if (!this.categoryWrapper) { this.categoryWrapper = Entry.Dom('div', { class: 'entryCategoryListWorkspace', }); } else { this.categoryWrapper.textContent = ''; } this._categoryCol = Entry.Dom('ul', { class: 'entryCategoryList', parent: this.categoryWrapper, }); this.view.prepend(this.categoryWrapper); const fragment = document.createDocumentFragment(); /* visible = static_mini 의 실과형 하드웨어에서만 사용됩니다. (EntryStatic 에 책임) */ data.forEach(({ category, visible }) => fragment.appendChild(this._generateCategoryElement(category, visible)[0]) ); this.firstSelector = head(data).category; this._categoryCol[0].appendChild(fragment); this.makeScrollIndicator(); } private _generateCategoryElement(name: string, visible: boolean) { this._categoryElems[name] = Entry.Dom('li', { id: `entryCategory${name}`, classes: [ 'entryCategoryElementWorkspace', 'entryRemove', visible === false ? 'entryRemoveCategory' : '', ], }) .bindOnClick(() => { this._cancelDynamic(true, () => { this.selectMenu(name, undefined, true); this.align(); }); }) .text(Lang.Blocks[name.toUpperCase()]); if (BETA_LIST.includes(name)) { this._categoryElems[name][0].appendChild( Entry.Dom('div', { id: `entryCategory${name}BetaTag`, classes: ['entryCategoryBetaTag'], })[0] ); } return this._categoryElems[name]; } private _isNotVisible(blockInfo: any) { return this.checkCategory(blockInfo) || this.checkBanClass(blockInfo); } private _getSortedBlocks(): [any[], any[]] { let visibles: any[] = []; let inVisibles: any[]; let block; const allBlocks: any[] = compact( this.code.getThreads().map((thread: any) => thread.getFirstBlock()) ); if (this._selectDynamic) { const threadsMap = this._threadsMap; visibles = this._dynamicThreads.reduce((visibles, type) => { block = threadsMap[type].getFirstBlock(); if (block) { visibles.push(block); } return visibles; }, []); inVisibles = allBlocks; } else { inVisibles = []; allBlocks.forEach((block) => { if (!this._isNotVisible(Entry.block[block.type])) { visibles.push(block); } else { inVisibles.push(block); } }); } return [visibles, inVisibles]; } private _isOn() { return this.view.css('display') !== 'none'; } private _registerThreadsMap(type: string, thread: any) { if (!(type && thread?.getFirstBlock())) { return; } this._threadsMap[type] = thread; } private _deleteThreadsMap(thread: any) { const block = thread?.getFirstBlock(); if (!block) { return; } delete this._threadsMap[block.type]; } private _createThread(data: any, index?: number, keyName?: string) { if (typeof keyName !== 'string') { keyName = undefined; } keyName = keyName || data[0].type; const thread = this.code.createThread(data, index); this._registerThreadsMap(keyName, thread); return thread; } private _getCategoryBlocks(category: string): string[] | undefined { const selectedCategory = find(this._categoryData, { category }); return selectedCategory?.blocks; } } export default BlockMenu; Entry.BlockMenu = BlockMenu; ================================================ FILE: src/playground/block_menu_scroll.js ================================================ import debounce from 'lodash/debounce'; class BlockMenuScroller { get SCROLL_WIDTH() { return 8; } get RADIUS() { return 2.5; } constructor(board) { this.board = board; this.board.changeEvent.attach(this, this.#reset); this.svgGroup = null; this.hX = 0; this.vWidth = 0; this.vY = 0; this.vRatio = 0; this._visible = true; this._opacity = -1; this.createScrollBar(); this.setOpacity(0); $(this.vScrollbar).bind('mousedown', this.#onMouseDown.bind(this)); this._domHeight = 0; this._dResizeScrollBar = debounce(this.resizeScrollBar, 50); if (Entry.windowResized) { Entry.windowResized.attach(this, this._dResizeScrollBar); } } createScrollBar() { const r = this.RADIUS; const width = this.SCROLL_WIDTH; const { common = {} } = EntryStatic.colorSet || {}; this.svgGroup = this.board.svgGroup.elem('g', { class: 'boardScrollbar', }); this.vScrollbar = this.svgGroup.elem('rect', { width, rx: r, ry: r, fill: common.SCROLL_BAR || '#aac5d5', class: 'scrollbar', }); } resizeScrollBar() { this.#updateRatio(); const dom = this.board.blockMenuContainer; const newHeight = dom.height(); if (newHeight !== this._domHeight) { this._domHeight = newHeight; return this.board.align(); } if (!this._visible || this.vRatio === 0) { return; } if (this.vRatio === 0) { return; } const width = this.SCROLL_WIDTH; this.vScrollbar.attr({ width, height: dom.height() / this.vRatio, x: dom.width() - 13, }); } updateScrollBar(dy) { this.vY += dy; this.vScrollbar.attr({ y: this.vY }); } scroll(dy) { if (!this.isVisible()) { return; } const dest = this.#adjustValue(dy); dy = dest - this.vY; if (dy === 0) { return; } this.board.code.moveBy(0, -dy * this.vRatio); this.updateScrollBar(dy); } scrollByPx(px) { if (!this.vRatio) { this.#updateRatio(); } this.scroll(px / this.vRatio); } setVisible(visible) { if (visible === this.isVisible()) { return; } this._visible = visible; this.svgGroup.attr({ display: visible === true ? 'block' : 'none', }); } getOpacity() { return this._opacity; } setOpacity(value) { if (this._opacity == value) { return; } this.vScrollbar.attr({ opacity: value, }); this._opacity = value; } isVisible() { return this._visible; } #updateRatio() { const board = this.board; const bRect = board.svgBlockGroup.getBBox(); const realHeight = board.blockMenuContainer.height(); const vRatio = (bRect.height + 20) / realHeight; this.vRatio = vRatio; if (vRatio <= 1) { this.setVisible(false); } else { this.setVisible(true); } } #reset() { this.vY = 0; this.vScrollbar.attr({ y: this.vY, }); this._dResizeScrollBar(); } //adjust value by dy for min/max value #adjustValue(dy) { const domHeight = this.board.svgDom.height(); const limitBottom = domHeight - domHeight / this.vRatio; let newY = this.vY + dy; newY = Math.max(0, newY); newY = Math.min(limitBottom, newY); return newY; } #onMouseDown(e) { const onMouseMove = (e) => { if (e.stopPropagation) { e.stopPropagation(); } if (e.preventDefault) { e.preventDefault(); } if (e.which == 2) { console.log('mouse wheel click disabled'); return; } let mouseEvent; if (e.originalEvent && e.originalEvent.touches) { mouseEvent = e.originalEvent.touches[0]; } else { mouseEvent = e; } const dragInstance = this.dragInstance; this.scroll(mouseEvent.pageY - dragInstance.offsetY); dragInstance.set({ offsetY: mouseEvent.pageY, }); }; const onMouseUp = () => { $(document).unbind('.scroll'); delete this.dragInstance; }; if (e.stopPropagation) { e.stopPropagation(); } if (e.preventDefault) { e.preventDefault(); } if (e.button === 0 || (e.originalEvent && e.originalEvent.touches)) { if (Entry.documentMousedown) { Entry.documentMousedown.notify(e); } let mouseEvent; if (e.originalEvent && e.originalEvent.touches) { mouseEvent = e.originalEvent.touches[0]; } else { mouseEvent = e; } const doc = $(document); doc.bind('mousemove.scroll', onMouseMove); doc.bind('mouseup.scroll', onMouseUp); this.dragInstance = new Entry.DragInstance({ startY: mouseEvent.pageY, offsetY: mouseEvent.pageY, }); } e.stopPropagation(); } } Entry.BlockMenuScroller = BlockMenuScroller; (function(p) {})(Entry.BlockMenuScroller.prototype); ================================================ FILE: src/playground/block_view.js ================================================ import debounce from 'lodash/debounce'; import _get from 'lodash/get'; import Hammer from 'hammerjs'; Entry.BlockView = class BlockView { schema = { id: 0, type: Entry.STATIC.BLOCK_RENDER_MODEL, x: 0, y: 0, offsetX: 0, offsetY: 0, width: 0, height: 0, contentWidth: 0, contentHeight: 0, topFieldHeight: 0, marginBottom: 0, magneting: false, visible: true, animating: false, shadow: true, display: true, }; constructor(block, board, mode) { const that = this; Entry.Model(this, false); this.block = block; this._lazyUpdatePos = debounce(block._updatePos.bind(block), 200); this.mouseUpEvent = new Entry.Event(this); this.disableMouseEvent = false; this.dAlignContent = this.alignContent; this._board = board; this._observers = []; this.set(block); const hash = Entry.generateHash(); this.svgGroup = board.svgBlockGroup.elem('g'); this.svgGroup.attr('id', hash); this.svgGroup.blockView = this; if (block.isCommentable() && board.svgCommentGroup) { this.svgCommentGroup = board.svgCommentGroup.elem('g'); this.svgCommentGroup.attr('id', `${hash}C`); this.svgCommentGroup.blockView = this; } this._schema = Entry.skinContainer.getSkin(block); if (this._schema === undefined) { this.block.destroy(false, false); return; } if (mode === undefined) { const workspace = this.getBoard().workspace; if (workspace && workspace.getBlockViewRenderMode) { this.renderMode = workspace.getBlockViewRenderMode(); } else { this.renderMode = Entry.BlockView.RENDER_MODE_BLOCK; } } else { this.renderMode = Entry.BlockView.RENDER_MODE_BLOCK; } if (this._schema.deletable) { this.block.setDeletable(this._schema.deletable); } if (this._schema.copyable) { this.block.setCopyable(this._schema.copyable); } if (this._schema.display === false || block.display === false) { this.set({ display: false }); } this._skeleton = Entry.skeleton[this._schema.skeleton]; const skeleton = this._skeleton; this._contents = []; this._statements = []; this._extensions = []; this.magnet = {}; this._paramMap = {}; if (skeleton.magnets && skeleton.magnets(this).next) { this.svgGroup.nextMagnet = this.block; this._nextGroup = this.svgGroup.elem('g'); this._nextCommentGroup = this.svgCommentGroup && this.svgCommentGroup.elem('g'); this._observers.push(this.observe(this, '_updateMagnet', ['contentHeight'])); } this.isInBlockMenu = this.getBoard() instanceof Entry.BlockMenu; this.mouseHandler = function(e) { (_.result(that.block.events, 'mousedown') || []).forEach((fn) => { if (Entry.documentMousedown) { Entry.documentMousedown.notify(e); } return fn(that); }); that.onMouseDown(...arguments); }; this._startRender(block, mode); // observe const thisBlock = this.block; this._observers.push(thisBlock.observe(this, '_setMovable', ['movable'])); this._observers.push(thisBlock.observe(this, '_setReadOnly', ['movable'])); this._observers.push(thisBlock.observe(this, '_setCopyable', ['copyable'])); this._observers.push(thisBlock.observe(this, '_updateColor', ['deletable'], false)); this._observers.push(this.observe(this, '_updateBG', ['magneting'], false)); this._observers.push(this.observe(this, '_updateOpacity', ['visible'], false)); this._observers.push(this.observe(this, '_updateDisplay', ['display'])); this._observers.push(this.observe(this, '_updateMagnet', ['offsetY'])); this._observers.push(board.code.observe(this, '_setBoard', ['board'], false)); this.dragMode = Entry.DRAG_MODE_NONE; Entry.Utils.disableContextmenu(this.svgGroup.node); const events = block.events.viewAdd || []; if (Entry.type === 'workspace' && this._board instanceof Entry.Board) { events.forEach((fn) => { if (_.isFunction(fn)) { fn(block); } }); } this.onMouseMove = this.onMouseMove.bind(this); this.onMouseUp = this.onMouseUp.bind(this); } _startRender(block, mode) { const skeleton = this._skeleton; const attr = { class: 'block' }; if (this.display === false) { attr.display = 'none'; } const svgGroup = this.svgGroup; svgGroup.attr(attr); (skeleton.classes || []).forEach((c) => svgGroup.addClass(c)); const path = skeleton.path(this); this.pathGroup = svgGroup.prepend('g'); this._updateMagnet(); this._path = this.pathGroup.elem('path'); let fillColor = this._schema.color; const { deletable, emphasized } = this.block; if (deletable === Entry.Block.DELETABLE_FALSE_LIGHTEN || emphasized) { fillColor = this._schema.emphasizedColor || Entry.Utils.getEmphasizeColor(fillColor); } this._fillColor = fillColor; const pathStyle = { d: path, fill: fillColor, class: 'blockPath', blockId: this.id, }; const blockSchema = this._schema; const { outerLine } = blockSchema; pathStyle.stroke = outerLine || skeleton.outerLine; pathStyle['stroke-linejoin'] = 'round'; pathStyle['stroke-linecap'] = 'round'; if (skeleton.stroke) { pathStyle['stroke-width'] = '1'; } this._path.attr(pathStyle); this.moveTo(this.x, this.y, false); this._startContentRender(mode); this._startExtension(mode); if (this._board.disableMouseEvent !== true) { this._addControl(); } const guide = this.guideSvgGroup; guide && svgGroup.insertBefore(guide, svgGroup.firstChild); this.bindPrev(); } _startContentRender(mode) { mode = _.isUndefined(mode) ? this.renderMode : mode; const _removeFunc = _.partial(_.result, _, 'remove'); _removeFunc(this.contentSvgGroup); _removeFunc(this.statementSvgGroup); if (this.statementCommentGroup) { _removeFunc(this.statementCommentGroup); } this.contentSvgGroup = this.svgGroup.elem('g'); this._contents = []; const schema = this._schema; const statements = schema.statements; if (!_.isEmpty(statements)) { this.statementSvgGroup = this.svgGroup.elem('g'); this.statementCommentGroup = this.svgCommentGroup && this.svgCommentGroup.elem('g'); } const reg = /(%\d+)/im; const parsingReg = /%(\d+)/im; let parsingRet; let template = this._getTemplate(mode) || ''; const params = this._getSchemaParams(mode); if (mode === Entry.BlockView.RENDER_MODE_TEXT) { if ( /(if)+(.|\n)+(else)+/gim.test(template) && !reg.test(template) && this.isInBlockMenu ) { template = template.replace('else', `%${params.length} else`); } } const _renderMode = mode || this.renderMode; template && template.split(reg).forEach((param, i) => { if (param[0] === ' ') { param = param.substring(1); } if (param[param.length - 1] === ' ') { param = param.substring(0, param.length - 1); } if (!param?.length) { return; } parsingRet = parsingReg.exec(param); if (parsingRet) { const paramIndex = parsingRet[1] - 1; param = params[paramIndex]; // params[paramIndex]= null||undefined 일 수 있는 경우에 대한 방어 코드 if (!param) { return; } const field = new Entry[`Field${param.type}`]( param, this, paramIndex, _renderMode, i ); this._contents.push(field); this._paramMap[paramIndex] = field; } else { this._contents.push( new Entry.FieldText({ text: param, color: schema.fontColor }, this) ); } }); (schema.statements || []).forEach((s, i) => { this._statements.push(new Entry.FieldStatement(s, this, i)); }); this.alignContent(false); } _startExtension(mode) { this._extensions = this.block.extensions.map( (e) => new Entry[`Ext${e.type}`](e, this, mode) ); } _updateSchema = this._startContentRender; changeType(type) { this._schema = Entry.block[type || this.type]; this._skeleton = Entry.skeleton[this._schema.skeleton]; this._updateSchema(); } alignContent(animate) { this.resetBackgroundPath(); if (animate !== true) { animate = false; } const cursor = { x: 0, y: 0, height: 0 }; let statementIndex = 0; let width = 0; let secondLineHeight = 0; for (let i = 0; i < this._contents.length; i++) { const c = this._contents[i]; if (c instanceof Entry.FieldLineBreak) { this._alignStatement(animate, statementIndex); c.align(statementIndex); statementIndex++; cursor.y = c.box.y; cursor.x = 8; } else { c.align(cursor.x, cursor.y, animate); // space between content if ( i !== this._contents.length - 1 && !(c instanceof Entry.FieldText && c._text.length === 0) ) { cursor.x += Entry.BlockView.PARAM_SPACE; } } const box = c.box; if (statementIndex !== 0) { secondLineHeight = Math.max(Math.round(box.height) * 1000000, secondLineHeight); } else { cursor.height = Math.max(box.height, cursor.height); } cursor.x += box.width; width = Math.max(width, cursor.x); if (this.contentWidth !== width || this.contentHeight !== cursor.height) { this.set({ contentWidth: width, contentHeight: cursor.height, }); } } if (secondLineHeight) { this.set({ contentHeight: cursor.height + secondLineHeight, }); } if (this._statements.length != statementIndex) { this._alignStatement(animate, statementIndex); } const contentPos = this.getContentPos(); this.contentSvgGroup.attr('transform', `translate(${contentPos.x},${contentPos.y})`); this.contentPos = contentPos; this._render(); const comment = this.block.comment; if (comment instanceof Entry.Comment) { comment.updateParentPos(); } this._updateMagnet(); const ws = this.getBoard().workspace; if (ws && (this.isFieldEditing() || ws.widgetUpdateEveryTime)) { ws.widgetUpdateEvent.notify(); } } isFieldEditing() { const contents = this._contents; for (let i = 0; i < contents.length; i++) { const content = contents[i] || {}; if (content.isEditing && content.isEditing()) { return true; } } return false; } _alignStatement(animate, index) { const positions = this._skeleton.statementPos ? this._skeleton.statementPos(this) : []; const statement = this._statements[index]; if (!statement) { return; } const pos = positions[index]; if (pos) { statement.align(pos.x, pos.y, animate); } } _render() { this._renderPath(); this.set(this._skeleton.box(this)); } _renderPath() { const newPath = this._skeleton.path(this); //no change occured if (this._path.getAttribute('d') === newPath) { return; } if (false && Entry.ANIMATION_DURATION !== 0) { const that = this; setTimeout(() => { that._path.animate({ d: newPath }, Entry.ANIMATION_DURATION, mina.easeinout); }, 0); } else { this._path.attr({ d: newPath }); this.animating === true && this.set({ animating: false }); } } _setPosition() { const board = this.getBoard(); const { scale = 1 } = board || {}; if (!(this.x || this.y)) { this.svgGroup.removeAttr('transform'); this.svgCommentGroup && this.svgCommentGroup.removeAttr('transform'); } else { const transform = `translate(${this.x / scale},${this.y / scale})`; this.svgGroup.attr('transform', transform); this.svgCommentGroup && this.svgCommentGroup.attr('transform', transform); } } moveTo(x, y, animate, doNotUpdatePos) { const thisX = this.x; const thisY = this.y; if (!this.display) { x = -99999; y = -99999; } if (thisX !== x || thisY !== y) { this.set({ x, y }); } doNotUpdatePos !== true && this._lazyUpdatePos(); if (this.visible && this.display) { this._setPosition(animate); } } moveBy(x, y, animate, doNotUpdatePos) { return this.moveTo(this.x + x, this.y + y, animate, doNotUpdatePos); } _addControl() { this._mouseEnable = true; const dblclick = _.result(this.block.events, 'dblclick'); if (dblclick) { const hammer = new Hammer(this.pathGroup); hammer.on('doubletap', () => { if (this._board.readOnly) { return; } dblclick.forEach((fn) => { if (fn) { fn(this); } }); }); $(this.pathGroup).dblclick(() => { if (this._board.readOnly) { return; } dblclick.forEach((fn) => { if (fn) { fn(this); } }); }); } $(this.svgGroup).bind( 'mousedown.blockViewMousedown touchstart.blockViewMousedown', this.mouseHandler ); } removeControl() { this._mouseEnable = false; $(this.svgGroup).unbind('.blockViewMousedown'); } setSelectedBlock(board) { const { workspace } = board; const { selectedBlockView } = workspace; const wsBoard = selectedBlockView ? selectedBlockView.getBoard() : board; if (board !== wsBoard) { wsBoard.setSelectedBlock(null); } else { board.setSelectedBlock(this); } } onMouseDown(e) { if (!this.isInBlockMenu && e.stopPropagation) { e.stopPropagation(); } if (e.preventDefault) { e.preventDefault(); } if (e.which == 2) { console.log('mouse wheel click disabled'); return; } if (e.button == 1) { return; } if (Entry.disposeEvent) { Entry.disposeEvent.notify(); } this.longPressTimer = null; const board = this.getBoard(); if (board.workingEvent) { return; } if (this.readOnly || board.viewOnly) { return; } board.workingEvent = true; this.setSelectedBlock(board); //left mousedown if ( (e.button === 0 || (e.originalEvent && e.originalEvent.touches) || e.touches) && !this._board.readOnly ) { const eventType = e.type; let mouseEvent; if (e.originalEvent && e.originalEvent.touches) { mouseEvent = e.originalEvent.touches[0]; } else if (e.touches) { mouseEvent = e.touches[0]; } else { mouseEvent = e; } this.mouseDownCoordinate = { x: mouseEvent.pageX, y: mouseEvent.pageY, }; const $doc = $(document); if (!this.disableMouseEvent) { $doc.bind('mousemove.block', this.onMouseMove); document.addEventListener('touchmove', this.onMouseMove, { passive: false }); } $doc.bind('mouseup.block', this.onMouseUp); document.addEventListener('touchend', this.onMouseUp); this.dragInstance = new Entry.DragInstance({ startX: mouseEvent.pageX, startY: mouseEvent.pageY, offsetX: mouseEvent.pageX, offsetY: mouseEvent.pageY, height: 0, mode: true, }); board.set({ dragBlock: this }); this.addDragging(); this.dragMode = Entry.DRAG_MODE_MOUSEDOWN; if (eventType === 'touchstart' || Entry.isMobile()) { this.longPressTimer = setTimeout(() => { if (this.longPressTimer) { this.longPressTimer = null; this.onMouseUp(e); this._rightClick(e, 'longPress'); } }, 700); } } else if (Entry.Utils.isRightButton(e)) { this._rightClick(e); } if (board.workspace.getMode() === Entry.Workspace.MODE_VIMBOARD && e) { document .getElementsByClassName('CodeMirror')[0] .dispatchEvent(Entry.Utils.createMouseEvent('dragStart', e)); } } getVerticalMove(mouseEvent, dragInstance) { const dx = Math.abs(mouseEvent.pageX - dragInstance.offsetX); const dy = Math.abs(mouseEvent.pageY - dragInstance.offsetY); return dy / dx > 1.75; } onMouseMove(e) { e.stopPropagation(); e.preventDefault(); const board = this.getBoard(); const workspaceMode = board.workspace.getMode(); let mouseEvent; if (workspaceMode === Entry.Workspace.MODE_VIMBOARD) { this.vimBoardEvent(e, 'dragOver'); } if (e.originalEvent && e.originalEvent.touches) { mouseEvent = e.originalEvent.touches[0]; } else if (e.touches) { mouseEvent = e.touches[0]; } else { mouseEvent = e; } const mouseDownCoordinate = this.mouseDownCoordinate; const diff = Math.sqrt( Math.pow(mouseEvent.pageX - mouseDownCoordinate.x, 2) + Math.pow(mouseEvent.pageY - mouseDownCoordinate.y, 2) ); if (this.dragMode == Entry.DRAG_MODE_DRAG || diff > Entry.BlockView.DRAG_RADIUS) { const blockView = this; if ( (blockView.isInBlockMenu && this.longPressTimer && this.getVerticalMove(mouseEvent, blockView.dragInstance)) || this.isVerticalMove ) { this.isVerticalMove = true; return; } else { $(document).unbind('.blockMenu'); } if (this.longPressTimer) { clearTimeout(this.longPressTimer); this.longPressTimer = null; } if (!this.movable) { return; } if (!this.isInBlockMenu) { let isFirst = false; if (this.dragMode != Entry.DRAG_MODE_DRAG) { this._toGlobalCoordinate(undefined, true); this.dragMode = Entry.DRAG_MODE_DRAG; this.block.getThread().changeEvent.notify(); Entry.GlobalSvg.setView(this, workspaceMode); isFirst = true; this.fromBlockMenu = this.dragInstance && this.dragInstance.isNew; } if (this.animating) { this.set({ animating: false }); } if (this.dragInstance.height === 0) { const height = -1 + this.height; this.dragInstance.set({ height }); } const dragInstance = this.dragInstance; this.moveBy( mouseEvent.pageX - dragInstance.offsetX, mouseEvent.pageY - dragInstance.offsetY, false, true ); Entry.GlobalSvg.position(); dragInstance.set({ offsetX: mouseEvent.pageX, offsetY: mouseEvent.pageY, }); if (!this.originPos) { this.originPos = { x: this.x, y: this.y, }; } if (isFirst) { board.generateCodeMagnetMap(); } this._updateCloseBlock(); } else { board.cloneToGlobal(e); // this.terminateEvent(); } } } terminateEvent() { const $doc = $(document); document.removeEventListener('touchmove', this.onMouseMove, { passive: false }); document.removeEventListener('touchend', this.onMouseUp); $doc.unbind('.block', this.onMouseUp); $doc.unbind('.block', this.onMouseMove); } onMouseUp(e) { if (e.which == 2) { console.log('mouse wheel click disabled'); return; } if (e.button == 1) { return; } if (this.longPressTimer) { clearTimeout(this.longPressTimer); this.longPressTimer = null; } this.terminateEvent(); this.terminateDrag(e); const board = this.getBoard(); if (board) { board.set({ dragBlock: null }); delete board.workingEvent; } this._setHoverBlockView({ that: this }); Entry.GlobalSvg.remove(); this.mouseUpEvent.notify(); delete this.isVerticalMove; delete this.mouseDownCoordinate; delete this.dragInstance; delete this.magnetsOfThread; } vimBoardEvent(event, type, block) { if (!event) { return; } const dragEvent = Entry.Utils.createMouseEvent(type, event); if (block) { dragEvent.block = block; } $('.entryVimBoard>.CodeMirror')[0].dispatchEvent(dragEvent); } terminateDrag(e) { const gs = Entry.GlobalSvg; const board = this.getBoard(); const dragMode = this.dragMode; const block = this.block; const workspaceMode = board.workspace.getMode(); this.removeDragging(); this.set({ visible: true }); this.dragMode = Entry.DRAG_MODE_NONE; const gsRet = gs.terminateDrag(this); if (workspaceMode === Entry.Workspace.MODE_VIMBOARD) { if (board instanceof Entry.BlockMenu) { board.terminateDrag(); gsRet === gs.DONE && this.vimBoardEvent(e, 'dragEnd', block); } else { board.clear(); } } else { const fromBlockMenu = this.dragInstance && this.dragInstance.isNew; if (dragMode === Entry.DRAG_MODE_DRAG) { let ripple = false; const prevBlock = this.block.getPrevBlock(this.block); let suffix = this._board.workspace.trashcan.isOver ? 'ForDestroy' : ''; switch (gsRet) { case gs.DONE: { let closeBlock = board.magnetedBlockView; if (closeBlock instanceof Entry.BlockView) { closeBlock = closeBlock.block; } if (prevBlock && !closeBlock) { Entry.do(`separateBlock${suffix}`, block); } else if (!prevBlock && !closeBlock && !fromBlockMenu) { if (!block.getThread().view.isGlobal()) { Entry.do(`separateBlock${suffix}`, block); } else { Entry.do(`moveBlock${suffix}`, block); this.dominate(); } } else { suffix = fromBlockMenu ? 'FromBlockMenu' : ''; if (closeBlock) { if (closeBlock.view.magneting === 'next') { this.dragMode = dragMode; const targetPointer = closeBlock.pointer(); targetPointer[3] = -1; Entry.do(`insertBlock${suffix}`, block, targetPointer).isPass( fromBlockMenu ); Entry.ConnectionRipple.setView(closeBlock.view).dispose(); this.dragMode = Entry.DRAG_MODE_NONE; } else { if (closeBlock.getThread) { const thread = closeBlock.getThread(); const closeBlockType = closeBlock.type; if ( closeBlockType && thread instanceof Entry.FieldBlock && !Entry.block[closeBlockType].isPrimitive ) { suffix += 'FollowSeparate'; } } Entry.do(`insertBlock${suffix}`, block, closeBlock).isPass( fromBlockMenu ); ripple = true; } Entry.Utils.playSound('entryMagneting'); } else { Entry.do(`moveBlock${suffix}`, block).isPass(fromBlockMenu); this.dominate(); } } break; } case gs.RETURN: { const block = this.block; if (fromBlockMenu) { Entry.do('destroyBlockBelow', this.block).isPass(true); } else { if (prevBlock) { this.set({ animating: false }); Entry.Utils.playSound('entryMagneting'); this.bindPrev(prevBlock); block.insert(prevBlock); } else { const parent = block.getThread().view.getParent(); if (!(parent instanceof Entry.Board)) { Entry.Utils.playSound('entryMagneting'); Entry.do('insertBlock', block, parent); } else { const originPos = this.originPos; this.moveTo(originPos.x, originPos.y, false); this.dominate(); } } } break; } case gs.REMOVE: Entry.Utils.playSound('entryDelete'); Entry.do('destroyBlockBelow', this.block).isPass(fromBlockMenu); break; } board.setMagnetedBlock(null); if (ripple) { Entry.ConnectionRipple.setView(block.view).dispose(); } } else if ( gsRet === gs.REMOVE && fromBlockMenu && dragMode === Entry.DRAG_MODE_MOUSEDOWN ) { Entry.do('destroyBlockBelow', this.block).isPass(true); } } this.destroyShadow(); delete this.originPos; } _getMagnetsInThread() { const magnet = { ...this.magnet }; const lastBlock = this.block.thread?.getLastBlock?.(); const next = lastBlock?.view?.magnet?.next; if (next) { magnet.next = next; } else { delete magnet.next; } return magnet; } _updateCloseBlock() { if (!this._skeleton.magnets) { return; } const board = this.getBoard(); const { scale = 1 } = board || {}; const x = this.x / scale; const y = this.y / scale; if (!this.magnetsOfThread) { this.magnetsOfThread = this._getMagnetsInThread(); } for (const type in this.magnetsOfThread) { const view = _.result( board.getNearestMagnet(x, type === 'next' ? y + this.getBelowHeight() : y, type), 'view' ); if (view) { return board.setMagnetedBlock(view, type); } } board.setMagnetedBlock(null); } dominate() { this.block.getThread().view.dominate(); const board = this.getBoard(); board.scroller.resizeScrollBar.call(board.scroller); } getSvgRoot() { const svgBlockGroup = this.getBoard().svgBlockGroup; let node = this.svgGroup; while (node.parentNode !== svgBlockGroup) { node = node.parentNode; } return node; } getBoard() { return this._board; } getComment() { return this.block.comment; } _setBoard() { this._board = this._board.code.board; } destroy(animate) { this.block.set({ view: null }); $(this.svgGroup).unbind('.blockViewMousedown'); this._destroyObservers(); const svgGroup = this.svgGroup; const _destroyFunc = _.partial(_.result, _, 'destroy'); if (animate) { $(svgGroup).fadeOut(100, () => svgGroup.remove()); } else { svgGroup.remove(); } this.svgCommentGroup && this.svgCommentGroup.remove(); (this._contents || []).forEach(_destroyFunc); (this._statements || []).forEach(_destroyFunc); const block = this.block; if (Entry.type === 'workspace' && !this.isInBlockMenu) { (block.events.viewDestroy || []).forEach((fn) => { if (_.isFunction(fn)) { const notIncludeSelf = !!block?.thread?.acceptType; fn(block, notIncludeSelf); } }); } } getShadow() { if (!this._shadow) { this._shadow = Entry.SVG.createElement(this.svgGroup.cloneNode(true), { opacity: 0.5 }); this.getBoard().svgGroup.appendChild(this._shadow); } return this._shadow; } destroyShadow() { _.result(this._shadow, 'remove'); delete this._shadow; } _updateMagnet() { if (!this._skeleton.magnets) { return; } const magnet = this._skeleton.magnets(this); if (magnet.next) { this._nextGroup && this._nextGroup.attr('transform', `translate(${magnet.next.x},${magnet.next.y})`); this._nextCommentGroup && this._nextCommentGroup.attr( 'transform', `translate(${magnet.next.x},${magnet.next.y})` ); } this.magnet = magnet; this.block.getThread().changeEvent.notify(); } _updateBG() { const dragBlock = this._board.dragBlock; if (!dragBlock || !dragBlock.dragInstance) { return; } const blockView = this; const svgGroup = blockView.svgGroup; if (!(this.magnet.next || this.magnet.previous)) { // field block if (this.magneting) { svgGroup.attr({ filter: `url(#entryBlockHighlightFilter_${this.getBoard().suffix})`, }); svgGroup.addClass('outputHighlight'); } else { svgGroup.removeClass('outputHighlight'); svgGroup.removeAttr('filter'); } return; } const magneting = blockView.magneting; if (magneting) { const shadow = dragBlock.getShadow(); const pos = this.getAbsoluteCoordinate(); let magnet; let transform; if (magneting === 'previous') { magnet = this.magnet.next; transform = `translate(${pos.scaleX + magnet.x},${pos.scaleY + magnet.y})`; } else if (magneting === 'next') { magnet = this.magnet.previous; const dragHeight = dragBlock.getBelowHeight(); const nextX = _get(dragBlock, 'magnet.next.x'); transform = `translate(${pos.scaleX + magnet.x - nextX},${pos.scaleY + magnet.y - dragHeight })`; } const $shadow = $(shadow); $shadow.attr({ transform, }); $shadow.removeAttr('display'); this._clonedShadow = shadow; if (blockView.background) { blockView.background.remove(); blockView.nextBackground.remove(); delete blockView.background; delete blockView.nextBackground; } if (magneting === 'previous' && dragBlock.block.thread instanceof Entry.Thread) { const height = dragBlock.getBelowHeight() + this.offsetY; blockView.originalHeight = blockView.offsetY; blockView.set({ offsetY: height, }); } } else { if (this._clonedShadow) { this._clonedShadow.attr({ display: 'none', }); delete this._clonedShadow; } const height = blockView.originalHeight; if (height !== undefined) { if (blockView.background) { blockView.background.remove(); blockView.nextBackground.remove(); delete blockView.background; delete blockView.nextBackground; } blockView.set({ offsetY: height, }); delete blockView.originalHeight; } } _.result(blockView.block.thread.changeEvent, 'notify'); } addDragging() { this.svgGroup.addClass('dragging'); Entry.playground.setBackpackPointEvent(true); } removeDragging() { this.svgGroup.removeClass('dragging'); Entry.playground.setBackpackPointEvent(false); } addSelected() { document?.activeElement?.blur(); $(this.pathGroup).insertAfter(this._nextGroup); this.svgGroup.removeClass('activated'); this.svgGroup.addClass('selected'); } removeSelected() { $(this.pathGroup).insertBefore(this._nextGroup); this.svgGroup.removeClass('selected'); } addActivated() { $(this.pathGroup).insertAfter(this._nextGroup); this.svgGroup.removeClass('selected'); this.svgGroup.addClass('activated'); } removeActivated() { $(this.pathGroup).insertBefore(this._nextGroup); this.svgGroup.removeClass('activated'); } getSkeleton() { return this._skeleton; } getContentPos() { return this._skeleton.contentPos(this); } renderText() { this.renderMode = Entry.BlockView.RENDER_MODE_TEXT; this._startContentRender(Entry.BlockView.RENDER_MODE_TEXT); } renderBlock() { this.renderMode = Entry.BlockView.RENDER_MODE_BLOCK; this._startContentRender(Entry.BlockView.RENDER_MODE_BLOCK); } renderByMode(mode, isReDraw) { if (this.isRenderMode(mode) && !isReDraw) { return; } this.renderMode = mode; this._startContentRender(mode); } _updateOpacity() { if (this.visible === false) { this.svgGroup.attr({ opacity: 0 }); this.svgCommentGroup && this.svgCommentGroup.attr({ opacity: 0 }); } else { this.svgGroup.removeAttr('opacity'); this.svgCommentGroup && this.svgCommentGroup.removeAttr('opacity'); this._setPosition(); } } _setMovable() { if (this.block.isMovable() !== null) { this.movable = this.block.isMovable(); } else if (this._skeleton.movable !== undefined) { this.movable = this._skeleton.movable; } else { this.movable = true; } } _setReadOnly() { if (this.block.isReadOnly() !== null) { this.readOnly = this.block.isReadOnly(); } else if (this._skeleton.readOnly !== undefined) { this.readOnly = this._skeleton.readOnly; } else { this.readOnly = false; } } _setCopyable() { if (this.block.isCopyable() !== null) { this.copyable = this.block.isCopyable(); } else if (this._skeleton.copyable !== undefined) { this.copyable = this._skeleton.copyable; } else { this.copyable = true; } } bumpAway(distance = 15, delay) { const that = this; if (delay) { const oldX = this.x; const oldY = this.y; window.setTimeout(() => { //only when position not changed if (oldX === that.x && oldY === that.y) { that.moveBy(distance, distance, false); } }, delay); } else { that.moveBy(distance, distance, false); } } _toLocalCoordinate(view) { this.disableMouseEvent = false; this.moveTo(0, 0, false); const { _nextGroup: parentSvgGroup, _nextCommentGroup: parentCommentGroup } = view; parentSvgGroup && parentSvgGroup.appendChild && parentSvgGroup.appendChild(this.svgGroup); parentCommentGroup && parentCommentGroup.appendChild && parentCommentGroup.appendChild(this.svgCommentGroup); } _toGlobalCoordinate(dragMode, doNotUpdatePos) { this.disableMouseEvent = false; const { x, y } = this.getAbsoluteCoordinate(dragMode); this.moveTo(x, y, false, doNotUpdatePos); this.getBoard().svgBlockGroup.appendChild(this.svgGroup); this.svgCommentGroup && this.getBoard().svgCommentGroup.appendChild(this.svgCommentGroup); } bindPrev(prevBlock, isDestroy) { if (prevBlock) { this._toLocalCoordinate(prevBlock.view); const nextBlock = prevBlock.getNextBlock(); if (nextBlock) { if (nextBlock && nextBlock !== this.block) { const endBlock = this.block.getLastBlock(); if (isDestroy) { nextBlock.view._toLocalCoordinate(prevBlock.view); } else if (endBlock.view.magnet.next) { nextBlock.view._toLocalCoordinate(endBlock.view); } else { nextBlock.view._toGlobalCoordinate(); nextBlock.separate(); nextBlock.view.bumpAway(null, 100); } } } } else { prevBlock = this.block.getPrevBlock(); if (prevBlock) { const prevBlockView = prevBlock.view; this._toLocalCoordinate(prevBlockView); const nextBlock = this.block.getNextBlock(); if (nextBlock && nextBlock.view) { nextBlock.view._toLocalCoordinate(this); } } } } getAbsoluteCoordinate(dragMode) { const board = this.getBoard(); const { scale = 1 } = board || {}; dragMode = dragMode !== undefined ? dragMode : this.dragMode; if (dragMode === Entry.DRAG_MODE_DRAG) { return { x: this.x, y: this.y, scaleX: this.x / scale, scaleY: this.y / scale, }; } const pos = this.block.getThread().view.requestAbsoluteCoordinate(this); pos.x += this.x; pos.y += this.y; pos.scaleX = pos.x / scale; pos.scaleY = pos.y / scale; return pos; } getBelowHeight() { return this.block.getThread().view.requestPartHeight(this); } _updateDisplay() { if (this.display) { $(this.svgGroup).removeAttr('display'); this._setPosition(); } else { this.svgGroup.attr({ display: 'none', }); } } _updateColor() { let fillColor = this._schema.color; const { deletable, emphasized } = this.block; if (deletable === Entry.Block.DELETABLE_FALSE_LIGHTEN || emphasized) { const emphasizedColor = this._schema.emphasizedColor; if (!emphasizedColor) { fillColor = Entry.Utils.getEmphasizeColor(fillColor); } else { fillColor = emphasizedColor; } } this._fillColor = fillColor; this._path.attr({ fill: fillColor }); this._updateContents(); } _updateContents(isReDraw) { const params = [undefined, undefined, this.renderMode, isReDraw]; this._contents.forEach((c) => c.renderStart(...params)); this.alignContent(false); } _destroyObservers() { const observers = this._observers; while (observers.length) { observers.pop().destroy(); } } reDraw() { if (!(this.visible && this.display)) { return; } this._updateContents(true); //해당 블럭이 가진 파라미터가 다른 블럭인 경우 재귀로 동작. indicator(undefined), string 은 제외 (this.block.data.params || []).forEach((param) => { if (_get(param, 'data.view')) { param.data.view.reDraw(); } }); (this.block.statements || []).forEach(({ view }) => view.reDraw()); (this._extensions || []).forEach((ext) => _.result(ext, 'updatePos')); } getParam(index) { return this._paramMap[index]; } getDataUrl(notClone, notPng) { return new Promise((resolve, reject) => { const svgGroup = notClone ? this.svgGroup : this.svgGroup.cloneNode(true); const svgCommentGroup = notClone ? this.svgCommentGroup : this.svgCommentGroup && this.svgCommentGroup.cloneNode(true); if (!notClone) { svgGroup.removeAttribute('opacity'); svgGroup.setAttribute('class', 'block selected'); } const box = this._skeleton.box(this); const scale = this.getBoard()?.scale || 1; let fontWeight = this.isWindow7() ? 0.9 : 0.95; if (this.type.indexOf('func_') > -1) { fontWeight *= 0.99; } svgGroup.setAttribute( 'transform', 'scale(%SCALE) translate(0,0)'.replace('%SCALE', scale) ); this.svgCommentGroup && svgCommentGroup.setAttribute( 'transform', 'scale(%SCALE) translate(0,0)'.replace('%SCALE', scale) ); const defs = this.getBoard().svgDom.find('defs'); const images = svgGroup.getElementsByTagName('image'); const texts = svgGroup.getElementsByTagName('text'); const fontFamily = EntryStatic.getDefaultFontFamily(); const boldTypes = ['≥', '≤']; const notResizeTypes = ['≥', '≤', '-', '>', '<', '=', '+', '-', 'x', '/']; _.toArray(texts).forEach((text) => { text.setAttribute('font-family', fontFamily); const size = parseInt(text.getAttribute('font-size'), 10); const content = $(text).text(); if (_.includes(boldTypes, content)) { text.setAttribute('font-weight', '500'); } if (_.includes(notResizeTypes, content)) { text.setAttribute('font-size', `${size}px`); } text.setAttribute('alignment-baseline', 'auto'); }); if (images.length) { Array.from(images).forEach((image) => { const href = image.getAttribute('href'); image.setAttribute('href', `${location.protocol}//${location.host}${href}`); }); } this.processSvg(svgGroup, scale, defs, notPng) .then((data) => { resolve(data); }) .catch((err) => { reject(err); }); }); } async downloadAsImage(i) { const image = await this.getDataUrl(); Entry.dispatchEvent('saveBlockImages', { images: [image], }); } _rightClick(e, eventSource) { const disposeEvent = Entry.disposeEvent; if (disposeEvent) { disposeEvent.notify(e); } const block = this.block; const board = this.getBoard(); delete board.workingEvent; //if long pressed block is function_general block //edit function if (this.isInBlockMenu && eventSource === 'longPress' && block.getFuncId()) { return this._schema.events.dblclick[0](this); } const { clientX: x, clientY: y } = Entry.Utils.convertMouseEvent(e); return Entry.ContextMenu.show(_getOptions(this), null, { x, y }); //helper functon get get context options function _getOptions(blockView) { const isBoardReadOnly = blockView._board.readOnly; const { block, isInBlockMenu, copyable } = blockView; const { options: EntryOptions = {} } = Entry; const { Blocks: { AI_analyze_option, Duplication_option, CONTEXT_COPY_option, cut_blocks, Delete_Blocks, }, Menus: { save_as_image }, } = Lang; const aiAnalyze = { text: AI_analyze_option, enable: copyable && !isBoardReadOnly, callback() { // NOTICE : Entry.do는 필요할지 고려 > 뒤로가기 적용이 필요한지 const blocksData = { ...block.copy() }; Entry.dispatchEvent('analyzeBlock', { data: JSON.stringify(blocksData), }); }, }; const copyAndPaste = { text: Duplication_option, enable: copyable && !isBoardReadOnly, callback() { Entry.do('cloneBlock', block.copy()); }, }; const copy = { text: CONTEXT_COPY_option, enable: copyable && !isBoardReadOnly, callback() { block.copyToClipboard(); }, }; const cut = { text: cut_blocks, enable: copyable && block.isDeletable() && !isBoardReadOnly, callback() { block.copyToClipboard(); Entry.do('destroyBlockBelow', block); blockView.getBoard().setSelectedBlock(null); }, }; const remove = { text: Delete_Blocks, enable: block.isDeletable() && !isBoardReadOnly, callback() { Entry.do('destroyBlock', block); }, }; const addStorage = !EntryOptions.backpackDisable && { text: Lang.Blocks.add_my_storage, enable: copyable && !isBoardReadOnly && !!window.user, callback() { Entry.dispatchEvent('addStorage', { type: 'block', data: block, }); }, }; const download = { text: save_as_image, callback() { blockView.downloadAsImage(); }, }; const hasComment = !!block._comment; const comment = !EntryOptions.commentDisable && { text: hasComment ? Lang.Blocks.delete_comment : Lang.Blocks.add_comment, enable: block.isCommentable(), callback() { hasComment ? Entry.do('removeComment', block._comment) : Entry.do('createComment', { id: Entry.Utils.generateId() }, board, block); }, }; let options = []; if (_isDownloadable()) { options.push(download); } if (!isInBlockMenu) { options = [ Entry.aiAssistantEnable && aiAnalyze, copyAndPaste, copy, cut, remove, addStorage, ...options, comment, ].filter((x) => x); } return options; function _isDownloadable() { return ( Entry.blockSaveImageEnable && Entry.Utils.isChrome() && Entry.type === 'workspace' && !Entry.isMobile() ); } } } addStorage() { if (this.block.view) { Entry.dispatchEvent('addStorage', { type: 'block', data: this.block, }); } } clone() { return this.svgGroup.cloneNode(true); } setBackgroundPath() { const board = this.getBoard(); if (board.dragBlock) { return; } this.resetBackgroundPath(); const originPath = this._path; const clonedPath = originPath.cloneNode(true); clonedPath.setAttribute('class', 'blockBackgroundPath'); clonedPath.setAttribute('fill', this._fillColor); this._backgroundPath = clonedPath; this.pathGroup.insertBefore(clonedPath, originPath); board.enablePattern(); originPath.attr({ fill: `url(#blockHoverPattern_${board.suffix})`, }); } resetBackgroundPath() { const board = this.getBoard(); if (!this._backgroundPath || !board || !board.disablePattern) { return; } board.disablePattern(); _.result($(this._backgroundPath), 'remove'); this._backgroundPath = null; this._path.attr({ fill: this._fillColor }); } _getTemplate(renderMode) { let template; if (renderMode === Entry.BlockView.RENDER_MODE_TEXT) { const board = this.getBoard(); let syntax; const workspace = board.workspace; if (workspace && workspace.vimBoard) { syntax = workspace.vimBoard.getBlockSyntax(this); } else { if (board.getBlockSyntax) { syntax = board.getBlockSyntax(this, renderMode); } } if (syntax) { if (typeof syntax === 'string') { template = syntax; } else { template = syntax.template; } } } return template || this._schema.template || Lang.template[this.block.type]; } _getSchemaParams(mode) { let params = this._schema.params; if (mode === Entry.BlockView.RENDER_MODE_TEXT) { const workspace = this.getBoard().workspace; if (workspace && workspace.vimBoard) { const syntax = workspace.vimBoard.getBlockSyntax(this); if (syntax && syntax.textParams) { params = syntax.textParams; } } } return params; } detach() { this.svgGroup.remove(); } attach(target) { (target || this._board.svgBlockGroup).appendChild(this.svgGroup); } getMagnet(query) { const selector = query.shift() || 'next'; let halfWidth = query.shift(); if (halfWidth === undefined) { halfWidth = 20; } return { getBoundingClientRect: function() { const coord = this.getAbsoluteCoordinate(); const boardOffset = this._board.relativeOffset; const magnet = this.magnet[selector]; return { top: coord.y + boardOffset.top + magnet.y - halfWidth, left: coord.x + boardOffset.left + magnet.x - halfWidth, width: 2 * halfWidth, height: 2 * halfWidth, }; }.bind(this), }; } isRenderMode(mode) { return this.renderMode === mode; } _setHoverBlockView(data) { if (!data) { return; } const { that, blockView } = data; const target = _.result(that.getBoard(), 'workspace'); if (!target) { return; } target.setHoverBlockView(blockView); } setHoverBlockView = this._setHoverBlockView; getFields() { if (!this._schema) { return []; } const THREAD = Entry.Thread; const FIELD_BLOCK = Entry.FieldBlock; const FIELD_OUTPUT = Entry.FieldOutput; return (this._statements || []).reduce( (fields, statement) => { statement = statement && statement._thread; if (!(statement instanceof THREAD)) { return fields; } return fields.concat(statement.view.getFields()); }, (this._contents || []).reduce((fields, c) => { if (!c) { return fields; } fields.push(c); if (c instanceof FIELD_BLOCK || c instanceof FIELD_OUTPUT) { //some output block doesn't have value block const valueBlock = c.getValueBlock && c.getValueBlock(); if (!valueBlock) { return fields; } fields = fields.concat(valueBlock.view.getFields()); } return fields; }, []) ); } processSvg(svgGroup, scale = 1, defs) { return new Promise((resolve, reject) => { let svgData = '(svgGroup)(defs)'; const bBox = this.svgGroup.getBoundingClientRect(); const boxWidth = bBox.width; const boxHeight = bBox.height; const offset = 2 * scale; svgData = svgData .replace('(svgGroup)', new XMLSerializer().serializeToString(svgGroup)) .replace('%W', Math.ceil(boxWidth) + offset) .replace('%H', Math.ceil(boxHeight) + offset) .replace('(defs)', new XMLSerializer().serializeToString(defs[0])) .replace(/>\s+/g, '>') .replace(/\s+ { if (Entry.BlockView.pngMap[src] !== undefined) { return resolve(Entry.BlockView.pngMap[src]); } if (notPng) { return resolve(`${location.origin}${src}`); } width *= multiplier; height *= multiplier; //float point cropped width = Math.ceil(width); height = Math.ceil(height); const img = document.createElement('img'); img.crossOrigin = 'Anonymous'; const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); img.onload = function() { try { ctx.drawImage(img, 0, 0, width, height); const data = canvas.toDataURL('image/png'); if (/\.png$/.test(src)) { Entry.BlockView.pngMap[src] = data; } return resolve(data); } catch (e) { return reject('error occured'); } }; img.onerror = function() { return reject('error occured'); }; img.src = src; }); } isWindow7() { const platform = window.platform; if (platform && platform.name.toLowerCase() === 'windows' && platform.version[0] === '7') { return true; } return false; } }; Entry.BlockView.PARAM_SPACE = 7; Entry.BlockView.DRAG_RADIUS = 5; Entry.BlockView.pngMap = {}; Entry.BlockView.RENDER_MODE_BLOCK = 1; Entry.BlockView.RENDER_MODE_TEXT = 2; ================================================ FILE: src/playground/blocks/block_ai_learning.js ================================================ import _floor from 'lodash/floor'; const DropDownDynamicGenerator = { labels: () => { if (Entry?.aiLearning?.labels?.length) { return Entry.aiLearning.labels.map((name, index) => [name, index]); } else { return [[Lang.Blocks.no_target, 'null']]; } }, tableAttrFields: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields } = table || {}; const attr = select?.[0] || []; return attr.map((fieldIndex, idx) => [fields[fieldIndex], idx]); } else { return [[Lang.Blocks.no_target, 'null']]; } }, valueMap: () => { const valueMap = Object.values( Entry.aiLearning.getTrainResult()?.valueMap || Entry.aiLearning?.result?.valueMap || {} ) || []; if (valueMap?.length) { return valueMap.map((name) => [name, name]); } else { return [[Lang.Blocks.no_target, 'null']]; } }, }; const createParamBlock = ({ name, length, createFunc, skeleton = 'basic_string_field', params = [], type, }) => { const result = {}; new Array(length).fill(0).forEach((_, idx) => { const index = idx + 1; const blockName = `${name}_${index}`; const EmptyArray = new Array(index * 2).fill(0); const lastAttr = { key: 1, value: 1, }; const paramsKeyMap = EmptyArray.reduce((acc, cur, idx, array) => { if (idx % 2 !== 0) { return acc; } const index = idx / 2 + 1; acc[`ATTR${index}`] = idx + 1; lastAttr.key = index; lastAttr.value = idx + 1; return acc; }, {}); if (params.length) { params.forEach((p, i) => { paramsKeyMap[`ATTR${lastAttr.key + i + 1}`] = lastAttr.value + 1; }); } result[blockName] = { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton, statements: [], params: [ ...EmptyArray.map((_, i) => { if (i % 2 !== 0) { return { type: 'Block', accept: 'string', defaultType: 'number', }; } return { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return ( fields[select?.[0]?.[i / 2]] || Lang.AiLearning.model_attr_str ); } return Lang.AiLearning.model_attr_str; }, }; }), ...params, ], events: {}, def: { type: blockName, }, pyHelpDef: { params: [], type: blockName, }, paramsKeyMap, class: 'ai_learning', isNotFor: Array.isArray(type) ? type.map(element => `${element}_attr_${index}`) : [`${type}_attr_${index}`], func: createFunc(paramsKeyMap), syntax: { js: [], py: [], }, }; }); return result; }; module.exports = { DropDownDynamicGenerator, createParamBlock, getBlocks() { return { ...predictBlocks, ...booleanPredictBlocks, learning_title_image: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.learning_title_image_str, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'learning_title_image', }, class: 'ai_learning', isNotFor: ['ai_learning_image'], events: {}, wikiClass: 'ai_image', }, learning_title_speech: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.learning_title_speech_str, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'learning_title_speech', }, class: 'ai_learning', isNotFor: ['ai_learning_speech'], events: {}, wikiClass: 'ai_speech', }, learning_title_text: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.learning_title_text_str, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'learning_title_text', }, class: 'ai_learning', isNotFor: ['ai_learning_text'], events: {}, wikiClass: 'ai_text', }, insert_data_for_test: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'insert_data_for_test', }, pyHelpDef: { params: [], type: 'insert_data_for_test', }, paramsKeyMap: {}, class: 'ai_learning', isNotFor: ['ai_learning_classification'], func(sprite, script) { if (!script.isStart) { script.isStart = true; Entry.aiLearning.openInputPopup(); return script; } if (!Entry.aiLearning.isLoading) { delete script.isStart; return script.callReturn(); } return script; }, syntax: { js: [], py: [], }, }, video_capture_for_image_test: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.video_start, 'start'], [Lang.Blocks.video_end, 'stop'], ], value: 'on', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: ['start', null], type: 'video_capture_for_image_test', }, pyHelpDef: { params: [], type: 'video_capture_for_image_test', }, paramsKeyMap: { MODE: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_image'], async func(sprite, script) { const mode = script.getField('MODE'); if (mode === 'start') { Entry.aiLearning.startPredict(); } else { Entry.aiLearning.stopPredict(); } return script.callReturn(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_image', }, insert_text_block_for_test: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'text', params: [Lang.Blocks.entry], }, null, ], type: 'insert_text_block_for_test', }, pyHelpDef: { params: [], type: 'insert_text_block_for_test', }, paramsKeyMap: { TEXT: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_text'], async func(sprite, script) { const text = script.getStringValue('TEXT', script); await Entry.aiLearning.predict(text); return script.callReturn(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_text', }, test_result: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [], events: {}, def: { params: [null], type: 'test_result', }, pyHelpDef: { params: [], type: 'test_result', }, paramsKeyMap: {}, class: 'ai_learning', isNotFor: ['ai_learning_classification'], func(sprite, script) { return Entry.aiLearning.getPredictResult().className; }, syntax: { js: [], py: [], }, }, accuracy_of_result: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.labels, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, ], events: {}, def: { params: [0], type: 'accuracy_of_result', }, pyHelpDef: { params: [], type: 'accuracy_of_result', }, paramsKeyMap: { GROUP: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_classification'], func(sprite, script) { const group = script.getNumberValue('GROUP', script); return Entry.aiLearning.getPredictResult(group).probability; }, syntax: { js: [], py: [], }, }, is_group: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.labels, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, ], events: {}, def: { params: [0], type: 'is_group', }, class: 'ai_learning', isNotFor: ['ai_learning_classification'], paramsKeyMap: { GROUP: 0, }, func(sprite, script) { const group = script.getNumberValue('GROUP', script); const { labels } = Entry.aiLearning; const result = Entry.aiLearning.getPredictResult().className; return result === labels[group]; }, syntax: { js: [], py: [], }, }, retrain_model: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'retrain_model', }, pyHelpDef: { params: [], type: 'retrain_model', }, paramsKeyMap: { TEXT: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_train'], async func(sprite, script) { Entry.aiLearning.train(); return script.callReturn(); }, syntax: { js: [], py: [], }, }, model_is_trained: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_boolean_field', statements: [], params: [], events: {}, def: { type: 'model_is_trained', }, class: 'ai_learning', isNotFor: ['ai_learning_train'], func(sprite, script) { return Entry.aiLearning.isTrained(); }, syntax: { js: [], py: [], }, }, set_train_visible: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.AiLearning.show, 'show'], [Lang.AiLearning.hide, 'hide'], ], value: 'show', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: ['show', null], type: 'set_train_visible', }, pyHelpDef: { params: [], type: 'set_train_visible', }, paramsKeyMap: { VISIBLE: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_train'], async func(sprite, script) { const visible = script.getField('VISIBLE'); Entry.aiLearning.setVisible(visible === 'show'); return script.callReturn(); }, syntax: { js: [], py: [], }, }, set_train_chart: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.AiLearning.open, 'open'], [Lang.AiLearning.close, 'close'], ], value: 'open', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: ['open', null], type: 'set_train_chart', }, pyHelpDef: { params: [], type: 'set_train_chart', }, paramsKeyMap: { VISIBLE: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_train_chart'], async func(sprite, script) { const visible = script.getField('VISIBLE'); Entry.aiLearning.setChartVisible(visible === 'open'); return script.callReturn(); }, syntax: { js: [], py: [], }, }, get_result_info: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.AiLearning.accuracy, 'accuracy'], [Lang.AiLearning.f1, 'f1'], [Lang.AiLearning.precision, 'precision'], [Lang.AiLearning.recall, 'recall'], ], value: 'accuracy', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, ], events: {}, def: { type: 'get_result_info', }, pyHelpDef: { params: [], type: 'get_result_info', }, paramsKeyMap: { TYPE: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_svm', 'ai_learning_logistic_regression', 'ai_learning_decisiontree'], async func(sprite, script) { const type = script.getField('TYPE', script); const result = Entry.aiLearning?.getTrainResult(); return result?.[type]; }, syntax: { js: [], py: [], }, }, }; }, }; const predictBlocks = createParamBlock({ type: ['svm', 'logistic_regression', 'decisiontree'], name: 'get_predict', length: 6, createFunc: (paramsKeyMap) => async (sprite, script) => { const params = Object.keys(paramsKeyMap).map((key) => script.getNumberValue(key, script)); await Entry.aiLearning.predict(params); const result = Entry.aiLearning.getPredictResult(); return result.sort((a, b) => b.probability - a.probability)[0].className; }, }); const booleanPredictBlocks = createParamBlock({ type: ['svm', 'logistic_regression', 'decisiontree'], name: 'is_result', skeleton: 'basic_boolean_field', length: 6, createFunc: (paramsKeyMap) => async (sprite, script) => { const keys = Object.keys(paramsKeyMap); const predictKey = keys.pop(); const params = keys.map((key) => script.getNumberValue(key, script)); const predict = script.getStringField(predictKey, script); await Entry.aiLearning.predict(params); const predictResult = Entry.aiLearning.getPredictResult(); const result = predictResult.sort((a, b) => b.probability - a.probability)[0]; return result && !!result.probability && result.className === predict; }, params: [ { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, ], }); ================================================ FILE: src/playground/blocks/block_ai_learning_cluster.js ================================================ import { DropDownDynamicGenerator } from './block_ai_learning'; module.exports = { getBlocks() { return { learning_title_cluster: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.learning_title_cluster_str, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'learning_title_cluster', }, class: 'ai_learning', isNotFor: ['ai_learning_cluster'], events: {}, }, set_cluster_option_k: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: [0, null], type: 'set_cluster_option_k', }, pyHelpDef: { params: [], type: 'set_cluster_option_k', }, paramsKeyMap: { VALUE: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_cluster'], async func(sprite, script) { const value = script.getStringValue('VALUE', script); Entry.aiLearning.setTrainOption('k', parseInt(value, 10)); return script.callReturn(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_cluster', }, set_cluster_option_centroids: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.AiLearning.cluster_option_centroids_kmpp, 'kmpp'], [Lang.AiLearning.cluster_option_centroids_random, 'random'], ], value: 'kmpp', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: [null, null], type: 'set_cluster_option_centroids', }, pyHelpDef: { params: [], type: 'set_cluster_option_centroids', }, paramsKeyMap: { CENTRIOD_TYPE: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_cluster'], async func(sprite, script) { const value = script.getField('CENTRIOD_TYPE'); Entry.aiLearning.setTrainOption('initialCentroids', value); return script.callReturn(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_cluster', }, get_cluster_centriod_count: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [], events: {}, def: { params: [], type: 'get_cluster_centriod_count', }, pyHelpDef: { params: [], type: 'get_cluster_centriod_count', }, paramsKeyMap: {}, class: 'ai_learning', isNotFor: ['ai_learning_cluster'], func(sprite, script) { const { k = 0 } = Entry.aiLearning.getTrainOption() || {}; return k; }, syntax: { js: [], py: [], }, wikiClass: 'ai_cluster', }, get_cluster_centriod_value: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.tableAttrFields, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, ], events: {}, def: { params: [1, 0], type: 'get_cluster_centriod_value', }, pyHelpDef: { params: [], type: 'get_cluster_centriod_value', }, paramsKeyMap: { K: 0, ATTR: 1, }, class: 'ai_learning', isNotFor: ['ai_learning_cluster'], func(sprite, script) { const k = script.getNumberValue('K'); const attr = script.getField('ATTR'); const { centroids } = Entry.aiLearning.getTrainResult(); return centroids?.[k - 1]?.[attr] || NaN; }, syntax: { js: [], py: [], }, wikiClass: 'ai_cluster', }, get_cluster_centriod_index_1: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], def: { type: 'get_cluster_centriod_index_1', }, events: {}, pyHelpDef: { params: [], type: 'get_cluster_centriod_index_1', }, paramsKeyMap: { ATTR1: 1, }, class: 'ai_learning', isNotFor: ['cluster_attr_1'], async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); await Entry.aiLearning.predict([x]); return Entry.aiLearning.getPredictResult(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_cluster', }, get_cluster_centriod_index_2: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], def: { type: 'get_cluster_centriod_index_2', }, events: {}, pyHelpDef: { params: [], type: 'get_cluster_centriod_index_2', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, }, class: 'ai_learning', isNotFor: ['cluster_attr_2'], async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); const y = script.getNumberValue('ATTR2', script); await Entry.aiLearning.predict([x, y]); return Entry.aiLearning.getPredictResult(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_cluster', }, get_cluster_centriod_index_3: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], def: { type: 'get_cluster_centriod_index_3', }, events: {}, pyHelpDef: { params: [], type: 'get_cluster_centriod_index_3', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, }, class: 'ai_learning', isNotFor: ['cluster_attr_3'], async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); const y = script.getNumberValue('ATTR2', script); const z = script.getNumberValue('ATTR3', script); await Entry.aiLearning.predict([x, y, z]); return Entry.aiLearning.getPredictResult(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_cluster', }, get_cluster_centriod_index_4: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], def: { type: 'get_cluster_centriod_index_4', }, events: {}, pyHelpDef: { params: [], type: 'get_cluster_centriod_index_4', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, }, class: 'ai_learning', isNotFor: ['cluster_attr_4'], async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); await Entry.aiLearning.predict([a, b, c, d]); return Entry.aiLearning.getPredictResult(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_cluster', }, get_cluster_centriod_index_5: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[4]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], def: { type: 'get_cluster_centriod_index_5', }, events: {}, pyHelpDef: { params: [], type: 'get_cluster_centriod_index_5', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, ATTR5: 9, }, class: 'ai_learning', isNotFor: ['cluster_attr_5'], async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); const e = script.getNumberValue('ATTR5', script); await Entry.aiLearning.predict([a, b, c, d, e]); return Entry.aiLearning.getPredictResult(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_cluster', }, get_cluster_centriod_index_6: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[4]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[5]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], def: { type: 'get_cluster_centriod_index_6', }, events: {}, pyHelpDef: { params: [], type: 'get_cluster_centriod_index_6', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, ATTR5: 9, ATTR6: 11, }, class: 'ai_learning', isNotFor: ['cluster_attr_6'], async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); const e = script.getNumberValue('ATTR5', script); const f = script.getNumberValue('ATTR6', script); await Entry.aiLearning.predict([a, b, c, d, e, f]); return Entry.aiLearning.getPredictResult(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_cluster', }, }; }, }; ================================================ FILE: src/playground/blocks/block_ai_learning_decisiontree.js ================================================ import { createParamBlock, DropDownDynamicGenerator } from './block_ai_learning'; module.exports = { getBlocks() { return { learning_title_decisiontree: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.learning_title_decisiontree_str, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'learning_title_decisiontree', }, class: 'ai_learning', isNotFor: ['ai_learning_decisiontree'], events: {}, }, set_decisiontree_option: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.AiLearning.train_param_minNumSamples, 'minNumSamples'], [Lang.AiLearning.train_param_maxDepth, 'maxDepth'], ], value: 'minNumSamples', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { type: 'set_decisiontree_option', }, pyHelpDef: { params: [], type: 'set_decisiontree_option', }, paramsKeyMap: { OPTION: 0, VALUE: 1, }, class: 'ai_learning', isNotFor: ['ai_learning_decisiontree'], func(sprite, script) { const option = script.getField('OPTION', script); const value = script.getNumberValue('VALUE', script); Entry.aiLearning.setTrainOption(option, parseFloat(value)); return script.callReturn(); }, syntax: { js: [], py: [], }, }, set_decisiontree_tree: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.AiLearning.open, 'open'], [Lang.AiLearning.close, 'close'], ], value: 'open', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: ['open', null], type: 'set_decisiontree_tree', }, pyHelpDef: { params: [], type: 'set_decisiontree_tree', }, paramsKeyMap: { VISIBLE: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_decisiontree'], async func(sprite, script) { const visible = script.getField('VISIBLE'); Entry.aiLearning.setChartVisible(visible === 'open'); return script.callReturn(); }, syntax: { js: [], py: [], }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_ai_learning_knn.js ================================================ import { DropDownDynamicGenerator } from './block_ai_learning'; module.exports = { getBlocks() { return { learning_title_number: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.learning_title_number_str, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'learning_title_number', }, class: 'ai_learning', isNotFor: ['ai_learning_number'], events: {}, }, set_number_learning_option_k: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: [10, null], type: 'set_number_learning_option_k', }, pyHelpDef: { params: [], type: 'set_number_learning_option_k', }, paramsKeyMap: { VALUE: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_number'], async func(sprite, script) { const value = script.getNumberValue('VALUE', script); Entry.aiLearning.setTrainOption('neighbors', parseInt(value)); return script.callReturn(); }, syntax: { js: [], py: [], }, }, get_number_learning_predict_1: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { type: 'get_number_learning_predict_1', }, pyHelpDef: { params: [], type: 'get_number_learning_predict_1', }, paramsKeyMap: { ATTR1: 1, }, class: 'ai_learning', isNotFor: ['number_learning_attr_1'], async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); await Entry.aiLearning.predict([x]); const [{ className }] = Entry.aiLearning.getPredictResult(); return className; }, syntax: { js: [], py: [], }, }, get_number_learning_predict_2: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { type: 'get_number_learning_predict_2', }, pyHelpDef: { params: [], type: 'get_number_learning_predict_2', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, }, class: 'ai_learning', isNotFor: ['number_learning_attr_2'], async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); const y = script.getNumberValue('ATTR2', script); await Entry.aiLearning.predict([x, y]); const [{ className }] = Entry.aiLearning.getPredictResult(); return className; }, syntax: { js: [], py: [], }, }, get_number_learning_predict_3: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { type: 'get_number_learning_predict_3', }, pyHelpDef: { params: [], type: 'get_number_learning_predict_3', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, }, class: 'ai_learning', isNotFor: ['number_learning_attr_3'], async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); const y = script.getNumberValue('ATTR2', script); const z = script.getNumberValue('ATTR3', script); await Entry.aiLearning.predict([x, y, z]); const [{ className }] = Entry.aiLearning.getPredictResult(); return className; }, syntax: { js: [], py: [], }, }, get_number_learning_predict_4: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { type: 'get_number_learning_predict_4', }, pyHelpDef: { params: [], type: 'get_number_learning_predict_4', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, }, class: 'ai_learning', isNotFor: ['number_learning_attr_4'], async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); await Entry.aiLearning.predict([a, b, c, d]); const [{ className }] = Entry.aiLearning.getPredictResult(); return className; }, syntax: { js: [], py: [], }, }, get_number_learning_predict_5: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[4]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { type: 'get_number_learning_predict_5', }, pyHelpDef: { params: [], type: 'get_number_learning_predict_5', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, ATTR5: 9, }, class: 'ai_learning', isNotFor: ['number_learning_attr_5'], async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); const e = script.getNumberValue('ATTR5', script); await Entry.aiLearning.predict([a, b, c, d, e]); const [{ className }] = Entry.aiLearning.getPredictResult(); return className; }, syntax: { js: [], py: [], }, }, get_number_learning_predict_6: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[4]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[5]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { type: 'get_number_learning_predict_6', }, pyHelpDef: { params: [], type: 'get_number_learning_predict_6', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, ATTR5: 9, ATTR6: 11, }, class: 'ai_learning', isNotFor: ['number_learning_attr_6'], async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); const e = script.getNumberValue('ATTR5', script); const f = script.getNumberValue('ATTR6', script); await Entry.aiLearning.predict([a, b, c, d, e, f]); const [{ className }] = Entry.aiLearning.getPredictResult(); return className; }, syntax: { js: [], py: [], }, }, get_number_learning_predict_param_1: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, { type: 'Dropdown', options: [ // [Lang.AiLearning.probability, 'probability'], [Lang.AiLearning.neighbor_count, 'count'], ], value: 'count', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, ], events: {}, def: { type: 'get_number_learning_predict_param_1', }, pyHelpDef: { params: [], type: 'get_number_learning_predict_param_1', }, paramsKeyMap: { ATTR1: 1, CLASS: 2, OPTION: 3, }, class: 'ai_learning', isNotFor: ['number_learning_attr_1'], async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); const clazz = script.getField('CLASS', script); const option = script.getField('OPTION', script); await Entry.aiLearning.predict([x]); const result = Entry.aiLearning.getPredictResult(); const classData = result.find(({ className }) => className === clazz) || {}; return classData[option] || 0; }, syntax: { js: [], py: [], }, }, get_number_learning_predict_param_2: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, { type: 'Dropdown', options: [ // [Lang.AiLearning.probability, 'probability'], [Lang.AiLearning.neighbor_count, 'count'], ], value: 'count', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, ], events: {}, def: { type: 'get_number_learning_predict_param_2', }, pyHelpDef: { params: [], type: 'get_number_learning_predict_param_2', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, CLASS: 4, OPTION: 5, }, class: 'ai_learning', isNotFor: ['number_learning_attr_2'], async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); const y = script.getNumberValue('ATTR2', script); const clazz = script.getField('CLASS', script); const option = script.getField('OPTION', script); await Entry.aiLearning.predict([x, y]); const result = Entry.aiLearning.getPredictResult(); const classData = result.find(({ className }) => className === clazz) || {}; return classData[option] || 0; }, syntax: { js: [], py: [], }, }, get_number_learning_predict_param_3: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, { type: 'Dropdown', options: [ // [Lang.AiLearning.probability, 'probability'], [Lang.AiLearning.neighbor_count, 'count'], ], value: 'count', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, ], events: {}, def: { type: 'get_number_learning_predict_param_3', }, pyHelpDef: { params: [], type: 'get_number_learning_predict_param_3', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, CLASS: 6, OPTION: 7, }, class: 'ai_learning', isNotFor: ['number_learning_attr_3'], async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); const y = script.getNumberValue('ATTR2', script); const z = script.getNumberValue('ATTR3', script); const clazz = script.getField('CLASS', script); const option = script.getField('OPTION', script); await Entry.aiLearning.predict([x, y, z]); const result = Entry.aiLearning.getPredictResult(); const classData = result.find(({ className }) => className === clazz) || {}; return classData[option] || 0; }, syntax: { js: [], py: [], }, }, get_number_learning_predict_param_4: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, { type: 'Dropdown', options: [ // [Lang.AiLearning.probability, 'probability'], [Lang.AiLearning.neighbor_count, 'count'], ], value: 'count', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, ], events: {}, def: { type: 'get_number_learning_predict_param_4', }, pyHelpDef: { params: [], type: 'get_number_learning_predict_param_4', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, CLASS: 8, OPTION: 9, }, class: 'ai_learning', isNotFor: ['number_learning_attr_4'], async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); const clazz = script.getField('CLASS', script); const option = script.getField('OPTION', script); await Entry.aiLearning.predict([a, b, c, d]); const result = Entry.aiLearning.getPredictResult(); const classData = result.find(({ className }) => className === clazz) || {}; return classData[option] || 0; }, syntax: { js: [], py: [], }, }, get_number_learning_predict_param_5: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[4]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, { type: 'Dropdown', options: [ // [Lang.AiLearning.probability, 'probability'], [Lang.AiLearning.neighbor_count, 'count'], ], value: 'count', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, ], events: {}, def: { type: 'get_number_learning_predict_param_5', }, pyHelpDef: { params: [], type: 'get_number_learning_predict_param_5', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, ATTR5: 9, CLASS: 10, OPTION: 11, }, class: 'ai_learning', isNotFor: ['number_learning_attr_5'], async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); const e = script.getNumberValue('ATTR5', script); const clazz = script.getField('CLASS', script); const option = script.getField('OPTION', script); await Entry.aiLearning.predict([a, b, c, d, e]); const result = Entry.aiLearning.getPredictResult(); const classData = result.find(({ className }) => className === clazz) || {}; return classData[option] || 0; }, syntax: { js: [], py: [], }, }, get_number_learning_predict_param_6: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[4]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[5]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, { type: 'Dropdown', options: [ // [Lang.AiLearning.probability, 'probability'], [Lang.AiLearning.neighbor_count, 'count'], ], value: 'count', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, ], events: {}, def: { type: 'get_number_learning_predict_param_6', }, pyHelpDef: { params: [], type: 'get_number_learning_predict_param_6', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, ATTR5: 9, ATTR6: 11, CLASS: 12, OPTION: 13, }, class: 'ai_learning', isNotFor: ['number_learning_attr_6'], async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); const e = script.getNumberValue('ATTR5', script); const f = script.getNumberValue('ATTR6', script); const clazz = script.getField('CLASS', script); const option = script.getField('OPTION', script); await Entry.aiLearning.predict([a, b, c, d, e, f]); const result = Entry.aiLearning.getPredictResult(); const classData = result.find(({ className }) => className === clazz) || {}; return classData[option] || 0; }, syntax: { js: [], py: [], }, }, is_number_learning_group_1: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, ], events: {}, def: { params: [0], type: 'is_number_learning_group_1', }, pyHelpDef: { params: [], type: 'is_number_learning_group_1', }, class: 'ai_learning', isNotFor: ['number_learning_attr_1'], paramsKeyMap: { ATTR1: 1, CLASS: 2, }, async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); const clazz = script.getField('CLASS', script); await Entry.aiLearning.predict([x]); const [{ className }] = Entry.aiLearning.getPredictResult(); return className === clazz; }, syntax: { js: [], py: [], }, }, is_number_learning_group_2: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, ], events: {}, def: { params: [0], type: 'is_number_learning_group_2', }, pyHelpDef: { params: [], type: 'is_number_learning_group_2', }, class: 'ai_learning', isNotFor: ['number_learning_attr_2'], paramsKeyMap: { ATTR1: 1, ATTR2: 3, CLASS: 4, }, async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); const y = script.getNumberValue('ATTR2', script); const clazz = script.getField('CLASS', script); await Entry.aiLearning.predict([x, y]); const [{ className }] = Entry.aiLearning.getPredictResult(); return className === clazz; }, syntax: { js: [], py: [], }, }, is_number_learning_group_3: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, ], events: {}, def: { params: [0], type: 'is_number_learning_group_3', }, pyHelpDef: { params: [], type: 'is_number_learning_group_3', }, class: 'ai_learning', isNotFor: ['number_learning_attr_3'], paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, CLASS: 6, }, async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); const y = script.getNumberValue('ATTR2', script); const z = script.getNumberValue('ATTR3', script); const clazz = script.getField('CLASS', script); await Entry.aiLearning.predict([x, y, z]); const [{ className }] = Entry.aiLearning.getPredictResult(); return className === clazz; }, syntax: { js: [], py: [], }, }, is_number_learning_group_4: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, ], events: {}, def: { params: [0], type: 'is_number_learning_group_4', }, pyHelpDef: { params: [], type: 'is_number_learning_group_4', }, class: 'ai_learning', isNotFor: ['number_learning_attr_4'], paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, CLASS: 8, }, async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); const clazz = script.getField('CLASS', script); await Entry.aiLearning.predict([a, b, c, d]); const [{ className }] = Entry.aiLearning.getPredictResult(); return className === clazz; }, syntax: { js: [], py: [], }, }, is_number_learning_group_5: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[4]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, ], events: {}, def: { params: [0], type: 'is_number_learning_group_5', }, pyHelpDef: { params: [], type: 'is_number_learning_group_5', }, class: 'ai_learning', isNotFor: ['number_learning_attr_5'], paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, ATTR5: 9, CLASS: 10, }, async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); const e = script.getNumberValue('ATTR5', script); const clazz = script.getField('CLASS', script); await Entry.aiLearning.predict([a, b, c, d, e]); const [{ className }] = Entry.aiLearning.getPredictResult(); return className === clazz; }, syntax: { js: [], py: [], }, }, is_number_learning_group_6: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[4]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[5]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, ], events: {}, def: { params: [0], type: 'is_number_learning_group_6', }, pyHelpDef: { params: [], type: 'is_number_learning_group_6', }, class: 'ai_learning', isNotFor: ['number_learning_attr_6'], paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, ATTR5: 9, ATTR6: 11, CLASS: 12, }, async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); const e = script.getNumberValue('ATTR5', script); const f = script.getNumberValue('ATTR6', script); const clazz = script.getField('CLASS', script); await Entry.aiLearning.predict([a, b, c, d, e, f]); const [{ className }] = Entry.aiLearning.getPredictResult(); return className === clazz; }, syntax: { js: [], py: [], }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_ai_learning_logistic_regression.js ================================================ import { createParamBlock, DropDownDynamicGenerator } from './block_ai_learning'; module.exports = { getBlocks() { const probabilityBlocks = createParamBlock({ type: 'logistic_regression', name: 'get_logistic_regression_probability', length: 6, createFunc: (paramsKeyMap) => async (sprite, script) => { const keys = Object.keys(paramsKeyMap); const predictKey = keys.pop(); const params = keys.map((key) => script.getNumberValue(key, script)); const predict = script.getStringField(predictKey, script); await Entry.aiLearning.predict(params); const predictResult = Entry.aiLearning.getPredictResult(); const result = predictResult.find((x) => x.className === predict); return result?.probability || 0; }, params: [ { type: 'DropdownDynamic', value: null, menuName: DropDownDynamicGenerator.valueMap, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return value || 0; }, }, ], }); return { ...probabilityBlocks, learning_title_logistic_regression: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.learning_title_logistic_regression_str, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'learning_title_logistic_regression', }, class: 'ai_learning', isNotFor: ['ai_learning_logistic_regression'], events: {}, }, set_logistic_regression_option: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.AiLearning.train_param_learningRate, 'learningRate'], [Lang.AiLearning.train_param_epochs, 'epochs'], [Lang.AiLearning.train_param_validationRate, 'validationRate'], ], value: 'learningRate', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { type: 'set_logistic_regression_option', }, pyHelpDef: { params: [], type: 'set_logistic_regression_option', }, paramsKeyMap: { OPTION: 0, VALUE: 1, }, class: 'ai_learning', isNotFor: ['ai_learning_logistic_regression'], func(sprite, script) { const option = script.getField('OPTION', script); const value = script.getNumberValue('VALUE', script); Entry.aiLearning.setTrainOption(option, parseFloat(value)); return script.callReturn(); }, syntax: { js: [], py: [], }, }, set_logistic_regression_optimizer: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.AiLearning.train_param_optimizer_adam, 'adam'], [Lang.AiLearning.train_param_optimizer_sgd, 'sgd'], ], value: 'adam', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { type: 'set_logistic_regression_optimizer', }, pyHelpDef: { params: [], type: 'set_logistic_regression_optimizer', }, paramsKeyMap: { OPTIMIZER: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_logistic_regression'], func(sprite, script) { const optimizer = script.getField('OPTIMIZER', script); Entry.aiLearning.setTrainOption('optimizer', optimizer); return script.callReturn(); }, syntax: { js: [], py: [], }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_ai_learning_regression.js ================================================ module.exports = { getBlocks() { return { learning_title_regression: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.learning_title_regression_str, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'learning_title_regression', }, class: 'ai_learning', isNotFor: ['ai_learning_regression'], events: {}, }, set_regression_option: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.AiLearning.train_param_learningRate, 'learningRate'], [Lang.AiLearning.train_param_epochs, 'epochs'], [Lang.AiLearning.train_param_validationRate, 'validationRate'], ], value: 'learningRate', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { type: 'set_regression_option', }, pyHelpDef: { params: [], type: 'set_regression_option', }, paramsKeyMap: { OPTION: 0, VALUE: 1, }, class: 'ai_learning', isNotFor: ['ai_learning_regression'], func(sprite, script) { const option = script.getField('OPTION', script); const value = script.getNumberValue('VALUE', script); Entry.aiLearning.setTrainOption(option, parseFloat(value)); return script.callReturn(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_regression', }, get_regression_predict_1: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { type: 'get_regression_predict_1', }, pyHelpDef: { params: [], type: 'get_regression_predict_1', }, paramsKeyMap: { ATTR1: 1, }, class: 'ai_learning', isNotFor: ['regression_attr_1'], async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); await Entry.aiLearning.predict(x); return Entry.aiLearning.getPredictResult(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_regression', }, get_regression_predict_2: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { type: 'get_regression_predict_2', }, pyHelpDef: { params: [], type: 'get_regression_predict_2', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, }, class: 'ai_learning', isNotFor: ['regression_attr_2'], async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); const y = script.getNumberValue('ATTR2', script); await Entry.aiLearning.predict([x, y]); return Entry.aiLearning.getPredictResult(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_regression', }, get_regression_predict_3: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { type: 'get_regression_predict_3', }, pyHelpDef: { params: [], type: 'get_regression_predict_3', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, }, class: 'ai_learning', isNotFor: ['regression_attr_3'], async func(sprite, script) { const x = script.getNumberValue('ATTR1', script); const y = script.getNumberValue('ATTR2', script); const z = script.getNumberValue('ATTR3', script); await Entry.aiLearning.predict([x, y, z]); return Entry.aiLearning.getPredictResult(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_regression', }, get_regression_predict_4: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { type: 'get_regression_predict_4', }, pyHelpDef: { params: [], type: 'get_regression_predict_4', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, }, class: 'ai_learning', isNotFor: ['regression_attr_4'], async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); await Entry.aiLearning.predict([a, b, c, d]); return Entry.aiLearning.getPredictResult(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_regression', }, get_regression_predict_5: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[4]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { type: 'get_regression_predict_5', }, pyHelpDef: { params: [], type: 'get_regression_predict_5', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, ATTR5: 9, }, class: 'ai_learning', isNotFor: ['regression_attr_5'], async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); const e = script.getNumberValue('ATTR5', script); await Entry.aiLearning.predict([a, b, c, d, e]); return Entry.aiLearning.getPredictResult(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_regression', }, get_regression_predict_6: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [ { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[0]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[1]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[2]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[3]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[4]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'TextDynamic', setValue: () => { const table = Entry.aiLearning?.getTableData?.(); if (table) { const { select = [], fields = [], } = Entry.aiLearning?.getTableData?.(); return fields[select?.[0]?.[5]] || Lang.AiLearning.model_attr_str; } return Lang.AiLearning.model_attr_str; }, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { type: 'get_regression_predict_6', }, pyHelpDef: { params: [], type: 'get_regression_predict_6', }, paramsKeyMap: { ATTR1: 1, ATTR2: 3, ATTR3: 5, ATTR4: 7, ATTR5: 9, ATTR6: 11, }, class: 'ai_learning', isNotFor: ['regression_attr_6'], async func(sprite, script) { const a = script.getNumberValue('ATTR1', script); const b = script.getNumberValue('ATTR2', script); const c = script.getNumberValue('ATTR3', script); const d = script.getNumberValue('ATTR4', script); const e = script.getNumberValue('ATTR5', script); const f = script.getNumberValue('ATTR6', script); await Entry.aiLearning.predict([a, b, c, d, e, f]); return Entry.aiLearning.getPredictResult(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_regression', }, get_regression_accuracy: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic_string_field', statements: [], params: [], events: {}, def: { type: 'get_regression_accuracy', }, pyHelpDef: { params: [], type: 'get_regression_accuracy', }, paramsKeyMap: {}, class: 'ai_learning', isNotFor: ['ai_learning_regression'], async func(sprite, script) { return Entry.aiLearning?.getTrainResult()?.rsquared; }, syntax: { js: [], py: [], }, wikiClass: 'ai_regression', }, }; }, }; ================================================ FILE: src/playground/blocks/block_ai_learning_svm.js ================================================ import { createParamBlock, DropDownDynamicGenerator } from './block_ai_learning'; import { OPTION_DEFAULT_VALUE, KERNEL_STRING_TYPE } from '.././../class/learning/Svm'; module.exports = { getBlocks() { const params = { getKernelOption() { const param = { type: 'DropdownDynamic', value: null, menuName() { const value = this.getTargetValue('kernel'); if (value === KERNEL_STRING_TYPE.POLYNOMIAL) { return [[Lang.AiLearning.train_param_degree, 'degree']] } else if (value === KERNEL_STRING_TYPE.RBF) { return [[Lang.AiLearning.train_param_gamma, 'gamma']] } else { return; } }, needDeepCopy: true, bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options.length) { return options[0][1]; } return null; } } return param; } } return { learning_title_svm: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.learning_title_svm_str, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'learning_title_svm', }, class: 'ai_learning', isNotFor: ['ai_learning_svm'], events: {}, }, set_svm_option: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.AiLearning.train_param_C, 'C'], ], value: 'C', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Block', accept: 'string', defaultType: 'number', value: OPTION_DEFAULT_VALUE.C }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, } ], def: { type: 'set_svm_option', }, paramsKeyMap: { OPTION: 0, VALUE: 1, }, class: 'ai_learning', isNotFor: ['ai_learning_svm'], func(sprite, script) { const option = script.getStringField('OPTION', script); const value = script.getNumberValue('VALUE', script); Entry.aiLearning.setTrainOption(option, parseFloat(value)); return script.callReturn(); }, events: {}, pyHelpDef: { params: [], type: 'set_svm_option', }, syntax: { js: [], py: [], }, }, set_kernel_linear: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'set_kernel_linear', }, pyHelpDef: { params: [], type: 'set_kernel_linear', }, paramsKeyMap: { TEXT: 0, }, class: 'ai_learning', isNotFor: ['ai_learning_svm'], async func(sprite, script) { const defaultValue = { degree: 3, gamma: 1 }; Entry.aiLearning.setTrainOption('kernel', 'linear'); Entry.aiLearning.setTrainOption('degree', defaultValue.degree); Entry.aiLearning.setTrainOption('gamma', defaultValue.gamma); return script.callReturn(); }, syntax: { js: [], py: [], }, }, set_kernel_option: { color: EntryStatic.colorSet.block.default.AI_LEARNING, outerLine: EntryStatic.colorSet.block.darken.AI_LEARNING, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.AiLearning.train_param_kernel_polynomial, KERNEL_STRING_TYPE.POLYNOMIAL], [Lang.AiLearning.train_param_kernel_rbf, KERNEL_STRING_TYPE.RBF], ], value: 'polynomial', bgColor: EntryStatic.colorSet.block.darken.AI_LEARNING, arrowColor: EntryStatic.colorSet.common.WHITE, dropdownSync: 'kernel', }, params.getKernelOption(), { type: 'Block', accept: 'string', defaultType: 'number', value: OPTION_DEFAULT_VALUE.degree }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, } ], def: { type: 'set_kernel_option', }, paramsKeyMap: { KERNEL: 0, OPTION: 1, VALUE: 2, }, class: 'ai_learning', isNotFor: ['ai_learning_svm'], func(sprite, script) { // 초기화 Entry.aiLearning.setTrainOption('gamma', OPTION_DEFAULT_VALUE.gamma); Entry.aiLearning.setTrainOption('degree', OPTION_DEFAULT_VALUE.degree); const kernel = script.getStringField('KERNEL', script); const option = script.getStringField('OPTION', script); const value = script.getNumberValue('VALUE', script); Entry.aiLearning.setTrainOption('kernel', kernel); Entry.aiLearning.setTrainOption(option, parseFloat(value)); return script.callReturn(); }, events: {}, pyHelpDef: { params: [], type: 'set_kernel_option', }, syntax: { js: [], py: [], }, } }; } }; ================================================ FILE: src/playground/blocks/block_ai_utilize_audio.js ================================================ import AudioUtils from '../../util/audioUtils'; import _clamp from 'lodash/clamp'; Entry.AI_UTILIZE_BLOCK.audio = { name: 'audio', imageName: 'audio.svg', category: 'audio', sponsorText: 'Powered by {image}', sponsorImage: 'naverClova.png', sponsorOnImage: 'naverClovaOn.png', title: { ko: '음성 인식', en: 'Speech recognition', jp: 'オーディオ検出', }, titleKey: 'template.voice_title_text', description: Lang.Msgs.ai_utilize_audio_description, descriptionKey: 'Msgs.ai_utilize_audio_description', isInitialized: false, async init() { await AudioUtils.initialize(); Entry.AI_UTILIZE_BLOCK.audio.isInitialized = true; }, }; Entry.AI_UTILIZE_BLOCK.audio.getBlocks = function() { return { audio_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.audio_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'audio_title', }, class: 'audio', isNotFor: ['audio'], events: {}, }, check_microphone: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [], events: {}, def: { type: 'check_microphone', }, paramsKeyMap: { VALUE: 0, }, class: 'audio', isNotFor: ['audio'], async func(sprite, script) { try { if (!AudioUtils.isInitialized) { await AudioUtils.initialize(); } return AudioUtils.audioInputList.length > 0; } catch (err) { return false; } }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_stt', }, get_microphone_volume: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [], events: {}, def: { type: 'get_microphone_volume', }, paramsKeyMap: { VALUE: 0, }, class: 'audio', isNotFor: ['audio'], async func(sprite, script) { if (!AudioUtils.isInitialized) { await AudioUtils.initialize(); } return AudioUtils.currentVolume; }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_stt', }, speech_to_text_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.voice_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'speech_to_text_title', }, class: 'stt', isNotFor: ['audio'], events: {}, }, speech_to_text_convert: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.korean_s, 'Kor'], [Lang.Blocks.english_s, 'Eng'], [Lang.Blocks.japan_s, 'Jpn'], ], value: 'Kor', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: { viewAdd: [ function() { if (Entry.container.sttValue) { Entry.container.sttValue.setVisible(true); } }, ], viewDestroy: [ function(block, notIncludeSelf) { if (Entry.container.sttValue) { Entry.container.sttValue.checkVisible(block, notIncludeSelf); } }, ], }, def: { params: [null], type: 'speech_to_text_convert', }, paramsKeyMap: { LANG: 0, }, class: 'stt', isNotFor: ['audio'], async func(sprite, script) { if (!AudioUtils.isInitialized) { await AudioUtils.initialize(); } if (AudioUtils.isRecording) { return; } try { const language = script.getField('LANG', script); if (language === 'Kor') { Entry.container.sttValue.setName( `${Lang.template.voice_title_text}:${Lang.Blocks.korean_s}` ); } else if (language === 'Eng') { Entry.container.sttValue.setName( `${Lang.template.voice_title_text}:${Lang.Blocks.english_s}` ); } else if (language === 'Jpn') { Entry.container.sttValue.setName( `${Lang.template.voice_title_text}:${Lang.Blocks.japan_s}` ); } AudioUtils.isRecording = true; Entry.container.enableSttValue(); const result = await AudioUtils.startRecord(60 * 1000, language); Entry.dispatchEvent('audioRecordingDone'); Entry.container.setSttValue(result || '-'); } catch (e) { Entry.container.setSttValue('-'); throw e; } }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_stt', }, timed_speech_to_text_convert: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', value: '10', }, { type: 'Dropdown', options: [ [Lang.Blocks.korean_s, 'Kor'], [Lang.Blocks.english_s, 'Eng'], [Lang.Blocks.japan_s, 'Jpn'], ], value: 'Kor', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: { viewAdd: [ function() { if (Entry.container.sttValue) { Entry.container.sttValue.setVisible(true); } }, ], viewDestroy: [ function(block, notIncludeSelf) { if (Entry.container.sttValue) { Entry.container.sttValue.checkVisible(block, notIncludeSelf); } }, ], }, def: { params: [null], type: 'timed_speech_to_text_convert', }, paramsKeyMap: { TIME: 0, LANG: 1, }, class: 'stt', isNotFor: ['audio'], async func(sprite, script) { if (!AudioUtils.isInitialized) { await AudioUtils.initialize(); } if (AudioUtils.isRecording) { return; } try { const time = _clamp(script.getNumberValue('TIME'), 1, 60); const language = script.getField('LANG', script); if (language === 'Kor') { Entry.container.sttValue.setName( `${Lang.template.voice_title_text}:${Lang.Blocks.korean_s}` ); } else if (language === 'Eng') { Entry.container.sttValue.setName( `${Lang.template.voice_title_text}:${Lang.Blocks.english_s}` ); } else if (language === 'Jpn') { Entry.container.sttValue.setName( `${Lang.template.voice_title_text}:${Lang.Blocks.japan_s}` ); } AudioUtils.isRecording = true; Entry.container.enableSttValue(); const result = await AudioUtils.startTimedRecord(time * 1000, language); Entry.dispatchEvent('audioRecordingDone'); Entry.container.setSttValue(result || '-'); } catch (e) { Entry.container.setSttValue('-'); throw e; } }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_stt', }, set_visible_speech_to_text: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.CALC_timer_visible_show, 'SHOW'], [Lang.Blocks.CALC_timer_visible_hide, 'HIDE'], ], value: 'SHOW', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: { viewAdd: [ function() { if (Entry.container.sttValue) { Entry.container.sttValue.setVisible(true); } }, ], viewDestroy: [ function(block, notIncludeSelf) { if (Entry.container.sttValue) { Entry.container.sttValue.checkVisible(block, notIncludeSelf); } }, ], }, def: { type: 'set_visible_speech_to_text', }, paramsKeyMap: { ACTION: 0, }, class: 'stt', isNotFor: ['audio'], func(sprite, script) { const action = script.getField('ACTION'); const sttValue = Entry.container.sttValue; if (!sttValue) { return script.callReturn(); } else if (action === 'SHOW') { sttValue.setVisible(true); } else { sttValue.setVisible(false); } return script.callReturn(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_stt', }, speech_to_text_get_value: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [], events: { viewAdd: [ function() { if (Entry.container.sttValue) { Entry.container.sttValue.setVisible(true); } }, ], viewDestroy: [ function(block, notIncludeSelf) { if (Entry.container.sttValue) { Entry.container.sttValue.checkVisible(block, notIncludeSelf); } }, ], }, def: { type: 'speech_to_text_get_value', }, paramsKeyMap: { VALUE: 0, }, class: 'stt', isNotFor: ['audio'], func(sprite, script) { return Entry.container.getSttValue(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_stt', }, }; }; ================================================ FILE: src/playground/blocks/block_ai_utilize_face_landmarker.js ================================================ import MediaPipeUtils from '../../util/mediaPipeUtils'; const mediaPipeUtils = MediaPipeUtils.getInstance(); Entry.AI_UTILIZE_BLOCK.faceLandmarker = { name: 'faceLandmarker', imageName: 'faceLandmarker.svg', category: 'video', title: { ko: '얼굴 인식', en: 'Face Detection', }, titleKey: 'Workspace.face_landmarker_title_text', description: Lang.Msgs.ai_utilize_face_landmarker_description, descriptionKey: 'Msgs.ai_utilize_face_landmarker_description', isInitialized: false, async init() { await mediaPipeUtils.initialize(); Entry.AI_UTILIZE_BLOCK.faceLandmarker.isInitialized = true; }, destroy() { mediaPipeUtils.destroy(); Entry.AI_UTILIZE_BLOCK.faceLandmarker.isInitialized = false; }, }; Entry.AI_UTILIZE_BLOCK.faceLandmarker.getBlocks = function() { const params = { getEventIndicator() { return { type: 'Indicator', img: 'block_icon/start_icon_face.svg', size: 14, position: { x: 0, y: -2, }, }; }, getCommonIndicator() { return { type: 'Indicator', img: 'block_icon/ai_face_icon.svg', size: 11, }; }, getFaceNumber() { return { type: 'Dropdown', options: [ ['1', 0], ['2', 1], ['3', 2], ['4', 3], ], value: 0, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getGender() { return { type: 'Dropdown', options: [ [Lang.video_gender.female, 'female'], [Lang.video_gender.male, 'male'], ], value: 'female', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getFaceCategory() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_gender, 'gender'], [Lang.Blocks.video_age, 'age'], [Lang.Blocks.video_emotion, 'emotion'], ], value: 'gender', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getOperators() { return { type: 'Dropdown', options: [ ['=', 'EQUAL'], ['!=', 'NOT_EQUAL'], ['>', 'GREATER'], ['<', 'LESS'], ['≥', 'GREATER_OR_EQUAL'], ['≤', 'LESS_OR_EQUAL'], ], value: 'EQUAL', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getEmotions() { return { type: 'Dropdown', options: [ [Lang.video_emotion_params.angry, 'angry'], [Lang.video_emotion_params.disgust, 'disgust'], [Lang.video_emotion_params.fear, 'fear'], [Lang.video_emotion_params.happy, 'happy'], [Lang.video_emotion_params.neutral, 'neutral'], [Lang.video_emotion_params.sad, 'sad'], [Lang.video_emotion_params.surprise, 'surprise'], ], value: 'angry', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getFacePoint() { return { type: 'Dropdown', options: [ [Lang.video_body_coord_params.left_eye, 374], [Lang.video_body_coord_params.right_eye, 145], [Lang.video_body_coord_params.nose, 4], [Lang.video_body_coord_params.left_mouth, 291], [Lang.video_body_coord_params.right_mouth, 61], [Lang.video_body_coord_params.upper_lip, 0], [Lang.video_body_coord_params.lower_lip, 17], ], value: 374, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, dropdownSync: 'handPoint', }; }, getAxis() { return { type: 'Dropdown', options: [ ['x', 'x'], ['y', 'y'], ], value: 'x', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getStartStop() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_start, 'start'], [Lang.Blocks.video_end, 'stop'], ], value: 'start', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getShowHide() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_show_video, 'show'], [Lang.Blocks.video_hide_video, 'hide'], ], value: 'show', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, }; return { face_landmarker_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.Blocks.face_landmarker_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'face_landmarker_title', }, class: 'face', isNotFor: ['faceLandmarker'], events: {}, }, when_face_landmarker: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_event', statements: [], params: [params.getEventIndicator()], events: {}, def: { params: [null], type: 'when_face_landmarker', }, paramsKeyMap: { VALUE: 0, }, event: 'when_face_landmarker', class: 'face', isNotFor: ['faceLandmarker'], func(sprite, script) { return script.callReturn(); }, wikiClass: 'ai_utilize_face', }, face_landmarker: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getStartStop(), params.getCommonIndicator()], events: {}, def: { type: 'face_landmarker', }, paramsKeyMap: { VALUE: 0, }, class: 'face', isNotFor: ['faceLandmarker'], async func(sprite, script) { const value = script.getField('VALUE'); if (!mediaPipeUtils.isInitialized) { await mediaPipeUtils.initialize(); } if (value === 'start') { await mediaPipeUtils.startFaceLandmarker(value); } else { await mediaPipeUtils.stopFaceLandmarker(value); } return script.callReturn(); }, wikiClass: 'ai_utilize_face', }, draw_detected_face: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getShowHide(), params.getCommonIndicator()], events: {}, def: { type: 'draw_detected_face', }, paramsKeyMap: { VALUE: 0, }, class: 'face', isNotFor: ['faceLandmarker'], async func(sprite, script) { const value = script.getField('VALUE'); if (!mediaPipeUtils.isInitialized) { await mediaPipeUtils.initialize(); } if (value === 'show') { mediaPipeUtils.changeDrawDetectedFaceLandmarker(true); } else { mediaPipeUtils.changeDrawDetectedFaceLandmarker(false); } return script.callReturn(); }, wikiClass: 'ai_utilize_face', }, check_detected_face: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [], events: {}, def: { type: 'check_detected_face', }, paramsKeyMap: { VALUE: 0, }, class: 'face', isNotFor: ['faceLandmarker'], func(sprite, script) { return mediaPipeUtils.isPrevFaceLandmarker; }, wikiClass: 'ai_utilize_face', }, count_detected_face: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [], events: {}, def: { type: 'count_detected_face', }, paramsKeyMap: { VALUE: 0, }, class: 'face', isNotFor: ['faceLandmarker'], func(sprite, script) { return mediaPipeUtils.countDetectedFace || 0; }, wikiClass: 'ai_utilize_face', }, locate_to_face: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getFaceNumber(), params.getFacePoint(), params.getCommonIndicator()], events: {}, def: { type: 'locate_to_face', }, paramsKeyMap: { FACE: 0, FACE_POINT: 1, }, class: 'face', isNotFor: ['faceLandmarker'], func(sprite, script) { const face = script.getField('FACE'); const point = script.getField('FACE_POINT'); const axis = mediaPipeUtils.getFacePointAxis(face, point); if (axis) { sprite.setX(axis.x); sprite.setY(axis.y); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(axis.x, axis.y * -1); } } return script.callReturn(); }, wikiClass: 'ai_utilize_face', }, locate_time_to_face: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, params.getFaceNumber(), params.getFacePoint(), params.getCommonIndicator(), ], events: {}, def: { params: [ { type: 'number', params: ['2'], }, null, null, ], type: 'locate_time_to_face', }, paramsKeyMap: { TIME: 0, FACE: 1, FACE_POINT: 2, }, class: 'face', isNotFor: ['faceLandmarker'], func(sprite, script) { if (!script.isStart) { const time = script.getNumberValue('TIME', script); const frameCount = Math.floor(time * Entry.FPS); const face = script.getField('FACE', script); const point = script.getField('FACE_POINT', script); if (frameCount != 0) { const axis = mediaPipeUtils.getFacePointAxis(face, point); if (axis) { script.isStart = true; script.frameCount = frameCount; script.dX = (axis.x - sprite.getX()) / script.frameCount; script.dY = (axis.y - sprite.getY()) / script.frameCount; } } else { const axis = mediaPipeUtils.getFacePointAxis(face, point); if (axis) { sprite.setX(axis.x); sprite.setY(axis.y); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(axis.x, axis.y * -1); } } return script.callReturn(); } } if (script.frameCount != 0) { sprite.setX(sprite.getX() + script.dX); sprite.setY(sprite.getY() + script.dY); script.frameCount--; if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } return script; } else { delete script.isStart; delete script.frameCount; return script.callReturn(); } }, wikiClass: 'ai_utilize_face', }, check_detected_gender: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [ { ...params.getFaceNumber(), fontSize: 10 }, { ...params.getGender(), fontSize: 10 }, ], events: {}, def: { params: [null, null], type: 'check_detected_gender', }, paramsKeyMap: { FACE: 0, GENDER: 1, }, class: 'face', isNotFor: ['faceLandmarker'], func(sprite, script) { const face = script.getField('FACE', script); const gender = script.getField('GENDER', script); const result = mediaPipeUtils.getFaceGender(face); return result === gender; }, wikiClass: 'ai_utilize_face', }, check_compare_age: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [ { ...params.getFaceNumber(), fontSize: 10 }, { ...params.getOperators(), fontSize: 10 }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ null, null, { type: 'number', params: ['10'], }, ], type: 'check_compare_age', }, paramsKeyMap: { FACE: 0, OPERATOR: 1, AGE: 2, }, class: 'face', isNotFor: ['faceLandmarker'], func(sprite, script) { const face = script.getField('FACE', script); const operator = script.getField('OPERATOR', script); const age = script.getNumberValue('AGE', script); const result = mediaPipeUtils.getFaceAge(face); switch (operator) { case 'EQUAL': return result === age; case 'NOT_EQUAL': return result != age; case 'GREATER': return result > age; case 'LESS': return result < age; case 'GREATER_OR_EQUAL': return result >= age; case 'LESS_OR_EQUAL': return result <= age; } }, wikiClass: 'ai_utilize_face', }, check_detected_emotion: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [ { ...params.getFaceNumber(), fontSize: 10 }, { ...params.getEmotions(), fontSize: 10 }, ], events: {}, def: { params: [null, null], type: 'check_detected_emotion', }, paramsKeyMap: { FACE: 0, EMOTION: 1, }, class: 'face', isNotFor: ['faceLandmarker'], func(sprite, script) { const face = script.getField('FACE', script); const emotion = script.getField('EMOTION', script); const result = mediaPipeUtils.getFaceEmotion(face); return result === emotion; }, wikiClass: 'ai_utilize_face', }, axis_detected_face: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [ { ...params.getFaceNumber(), fontSize: 10 }, { ...params.getFacePoint(), fontSize: 10 }, { ...params.getAxis(), fontSize: 10 }, ], events: {}, def: { params: [null, null, null], type: 'axis_detected_face', }, paramsKeyMap: { FACE: 0, FACE_POINT: 1, AXIS: 2, }, class: 'face', isNotFor: ['faceLandmarker'], func(sprite, script) { const face = script.getField('FACE', script); const point = script.getField('FACE_POINT', script); const axisName = script.getField('AXIS', script); const axis = mediaPipeUtils.getFacePointAxis(face, point); if (axis) { return axis[axisName] || 0; } return 0; }, wikiClass: 'ai_utilize_face', }, get_detected_face_value: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [ { ...params.getFaceNumber(), fontSize: 10 }, { ...params.getFaceCategory(), fontSize: 10 }, ], events: {}, def: { params: [null, null], type: 'get_detected_face_value', }, paramsKeyMap: { FACE: 0, CATEGORY: 1, }, class: 'face', isNotFor: ['faceLandmarker'], func(sprite, script) { const face = script.getField('FACE', script); const category = script.getField('CATEGORY', script); if (!mediaPipeUtils.isPrevFaceLandmarker) { if (['gender', 'emotion'].includes(category)) { return 'null'; } else { return 0; } } switch (category) { case 'gender': return ( Lang.video_gender[mediaPipeUtils.getFaceGender(face)] || Lang.Blocks.unknown ); case 'age': return mediaPipeUtils.getFaceAge(face) || 0; case 'emotion': return ( Lang.video_emotion_params[mediaPipeUtils.getFaceEmotion(face)] || Lang.Blocks.unknown ); } }, wikiClass: 'ai_utilize_face', }, }; }; ================================================ FILE: src/playground/blocks/block_ai_utilize_gesture_recognition.js ================================================ import MediaPipeUtils from '../../util/mediaPipeUtils'; const mediaPipeUtils = MediaPipeUtils.getInstance(); Entry.AI_UTILIZE_BLOCK.gestureRecognition = { name: 'gestureRecognition', imageName: 'gestureRecognition.svg', category: 'video', title: { ko: '손 인식', en: 'Gesture Recognition', }, titleKey: 'Workspace.gesture_recognition_title_text', description: Lang.Msgs.ai_utilize_gesture_recognition_description, descriptionKey: 'Msgs.ai_utilize_gesture_recognition_description', isInitialized: false, async init() { await mediaPipeUtils.initialize(); Entry.AI_UTILIZE_BLOCK.gestureRecognition.isInitialized = true; }, destroy() { mediaPipeUtils.destroy(); Entry.AI_UTILIZE_BLOCK.gestureRecognition.isInitialized = false; }, }; Entry.AI_UTILIZE_BLOCK.gestureRecognition.getBlocks = function() { const params = { getEventIndicator() { return { type: 'Indicator', img: 'block_icon/start_icon_hand.svg', size: 14, position: { x: 0, y: -2, }, }; }, getCommonIndicator() { return { type: 'Indicator', img: 'block_icon/ai_hand_icon.svg', size: 11, }; }, getHandNumber() { return { type: 'Dropdown', options: [ ['1', 0], ['2', 1], ], value: 0, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getHand() { return { type: 'Dropdown', options: [ [Lang.Blocks.right_hand, 'Left'], [Lang.Blocks.left_hand, 'Right'], ], value: 'Left', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getGesture() { return { type: 'Dropdown', options: [ [Lang.gesture_list.closed_fist, 'Closed_Fist'], [Lang.gesture_list.open_palm, 'Open_Palm'], [Lang.gesture_list.pointing_up, 'Pointing_Up'], [Lang.gesture_list.thumb_down, 'Thumb_Down'], [Lang.gesture_list.thumb_up, 'Thumb_Up'], [Lang.gesture_list.victory, 'Victory'], [Lang.gesture_list.iloveyou, 'ILoveYou'], ], value: 'Closed_Fist', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getHandPoint() { return { type: 'Dropdown', options: [ [Lang.Blocks.thumb, 1], [Lang.Blocks.index_finger, 5], [Lang.Blocks.middle_finger, 9], [Lang.Blocks.ring_finger, 13], [Lang.Blocks.little_finger, 17], [Lang.Blocks.wrist, 0], ], value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, dropdownSync: 'handPoint', }; }, getHandDetailPoint() { return { type: 'DropdownDynamic', menuName() { const handPoint = this.getTargetValue('handPoint'); const value = this.getValue(); if (handPoint === 1) { if (![2, 3].includes(value)) { this.setValue(3); } return [ [Lang.Blocks.tip, 3], [Lang.Blocks.dip, 2], ]; } else if (handPoint !== 0) { if (![1, 2, 3].includes(value)) { this.setValue(3); } return [ [Lang.Blocks.tip, 3], [Lang.Blocks.dip, 2], [Lang.Blocks.pip, 1], ]; } else { this.setValue(0); return [[Lang.Blocks.none, 0]]; } }, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getAxis() { return { type: 'Dropdown', options: [ ['x', 'x'], ['y', 'y'], ], value: 'x', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getStartStop() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_start, 'start'], [Lang.Blocks.video_end, 'stop'], ], value: 'start', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getShowHide() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_show_video, 'show'], [Lang.Blocks.video_hide_video, 'hide'], ], value: 'show', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, }; return { hand_detection_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.Blocks.hand_detection_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'hand_detection_title', }, class: 'hand', isNotFor: ['gestureRecognition'], events: {}, }, when_hand_detection: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_event', statements: [], params: [params.getEventIndicator()], events: {}, def: { params: [null], type: 'when_hand_detection', }, paramsKeyMap: { VALUE: 0, }, event: 'when_hand_detection', class: 'hand', isNotFor: ['gestureRecognition'], func(sprite, script) { return script.callReturn(); }, wikiClass: 'ai_utilize_gesture', }, hand_detection: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getStartStop(), params.getCommonIndicator()], events: {}, def: { type: 'hand_detection', }, paramsKeyMap: { VALUE: 0, }, class: 'hand', isNotFor: ['gestureRecognition'], async func(sprite, script) { const value = script.getField('VALUE'); if (!mediaPipeUtils.isInitialized) { await mediaPipeUtils.initialize(); } if (value === 'start') { await mediaPipeUtils.startHandGestureRecognition(value); } else { await mediaPipeUtils.stopHandGestureRecognition(value); } return script.callReturn(); }, wikiClass: 'ai_utilize_gesture', }, draw_detected_hand: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getShowHide(), params.getCommonIndicator()], events: {}, def: { type: 'draw_detected_hand', }, paramsKeyMap: { VALUE: 0, }, class: 'hand', isNotFor: ['gestureRecognition'], async func(sprite, script) { const value = script.getField('VALUE'); if (!mediaPipeUtils.isInitialized) { await mediaPipeUtils.initialize(); } if (value === 'show') { mediaPipeUtils.changeDrawDetectedHand(true); } else { mediaPipeUtils.changeDrawDetectedHand(false); } return script.callReturn(); }, wikiClass: 'ai_utilize_gesture', }, check_detected_hand: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [], events: {}, def: { type: 'check_detected_hand', }, paramsKeyMap: { VALUE: 0, }, class: 'hand', isNotFor: ['gestureRecognition'], func(sprite, script) { return mediaPipeUtils.isPrevHandDetected; }, wikiClass: 'ai_utilize_gesture', }, count_detected_hand: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [], events: {}, def: { type: 'count_detected_hand', }, paramsKeyMap: { VALUE: 0, }, class: 'hand', isNotFor: ['gestureRecognition'], func(sprite, script) { return mediaPipeUtils.countDetectedHand; }, wikiClass: 'ai_utilize_gesture', }, locate_to_hand: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ params.getHandNumber(), params.getHandPoint(), params.getHandDetailPoint(), params.getCommonIndicator(), ], events: {}, def: { type: 'locate_to_hand', }, paramsKeyMap: { HAND: 0, HAND_POINT: 1, HAND_DETAIL_POINT: 2, }, class: 'hand', isNotFor: ['gestureRecognition'], func(sprite, script) { const hand = script.getField('HAND'); const point = script.getField('HAND_POINT'); const detail = script.getField('HAND_DETAIL_POINT'); const handPoint = point + detail; const axis = mediaPipeUtils.getHandPointAxis(hand, handPoint); if (axis) { sprite.setX(axis.x); sprite.setY(axis.y); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(axis.x, axis.y * -1); } } return script.callReturn(); }, wikiClass: 'ai_utilize_gesture', }, locate_time_to_hand: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, params.getHandNumber(), params.getHandPoint(), params.getHandDetailPoint(), params.getCommonIndicator(), ], events: {}, def: { params: [ { type: 'number', params: ['2'], }, null, null, null, ], type: 'locate_time_to_hand', }, paramsKeyMap: { TIME: 0, HAND: 1, HAND_POINT: 2, HAND_DETAIL_POINT: 3, }, class: 'hand', isNotFor: ['gestureRecognition'], func(sprite, script) { if (!script.isStart) { const time = script.getNumberValue('TIME', script); const frameCount = Math.floor(time * Entry.FPS); const hand = script.getField('HAND', script); const point = script.getField('HAND_POINT', script); const detail = script.getField('HAND_DETAIL_POINT', script); const handPoint = point + detail; if (frameCount != 0) { const axis = mediaPipeUtils.getHandPointAxis(hand, handPoint); if (axis) { script.isStart = true; script.frameCount = frameCount; script.dX = (axis.x - sprite.getX()) / script.frameCount; script.dY = (axis.y - sprite.getY()) / script.frameCount; } } else { const axis = mediaPipeUtils.getHandPointAxis(hand, handPoint); if (axis) { sprite.setX(axis.x); sprite.setY(axis.y); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(axis.x, axis.y * -1); } } return script.callReturn(); } } if (script.frameCount != 0) { sprite.setX(sprite.getX() + script.dX); sprite.setY(sprite.getY() + script.dY); script.frameCount--; if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } return script; } else { delete script.isStart; delete script.frameCount; return script.callReturn(); } }, wikiClass: 'ai_utilize_gesture', }, axis_detected_hand: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [ { ...params.getHandNumber(), fontSize: 10 }, { ...params.getHandPoint(), fontSize: 10 }, { ...params.getHandDetailPoint(), fontSize: 10 }, { ...params.getAxis(), fontSize: 10 }, ], events: {}, def: { params: [null, null, null, null], type: 'axis_detected_hand', }, paramsKeyMap: { HAND: 0, HAND_POINT: 1, HAND_DETAIL_POINT: 2, AXIS: 3, }, class: 'hand', isNotFor: ['gestureRecognition'], func(sprite, script) { const hand = script.getField('HAND', script); const point = script.getField('HAND_POINT', script); const detail = script.getField('HAND_DETAIL_POINT', script); const axisName = script.getField('AXIS', script); const handPoint = point + detail; const axis = mediaPipeUtils.getHandPointAxis(hand, handPoint); if (axis) { return axis[axisName] || 0; } return 0; }, wikiClass: 'ai_utilize_gesture', }, is_which_hand: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [ { ...params.getHandNumber(), fontSize: 10 }, { ...params.getHand(), fontSize: 10 }, ], events: {}, def: { params: [null, null], type: 'is_which_hand' }, paramsKeyMap: { HAND_NUM: 0, HAND: 1, }, class: 'hand', isNotFor: ['gestureRecognition'], func(sprite, script) { const handNum = script.getField('HAND_NUM', script); const hand = script.getField('HAND', script); const handedness = mediaPipeUtils.getHandedness(handNum); if (!handedness) { return false; } return handedness.categoryName === hand; }, wikiClass: 'ai_utilize_gesture', }, get_which_hand: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [{ ...params.getHandNumber(), fontSize: 10 }], events: {}, def: { params: [null, null], type: 'get_which_hand' }, paramsKeyMap: { HAND_NUM: 0, }, class: 'hand', isNotFor: ['gestureRecognition'], func(sprite, script) { const handNum = script.getField('HAND_NUM', script); const handedness = mediaPipeUtils.getHandedness(handNum); if (!handedness) { return 'null'; } else if (handedness.categoryName === 'Left') { return Lang.Blocks.right_hand; } else { return Lang.Blocks.left_hand; } }, wikiClass: 'ai_utilize_gesture', }, is_which_gesture: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [ { ...params.getHandNumber(), fontSize: 10 }, { ...params.getGesture(), fontSize: 10 }, ], events: {}, def: { params: [null, null], type: 'is_which_gesture' }, paramsKeyMap: { HAND_NUM: 0, GESTURE: 1, }, class: 'hand', isNotFor: ['gestureRecognition'], func(sprite, script) { const handNum = script.getField('HAND_NUM', script); const gestureName = script.getField('GESTURE', script); const gesture = mediaPipeUtils.getGesture(handNum); if (!gesture) { return false; } return gesture.categoryName === gestureName; }, wikiClass: 'ai_utilize_gesture', }, get_which_gesture: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [{ ...params.getHandNumber(), fontSize: 10 }], events: {}, def: { params: [null, null], type: 'get_which_gesture' }, paramsKeyMap: { HAND_NUM: 0, }, class: 'hand', isNotFor: ['gestureRecognition'], func(sprite, script) { const handNum = script.getField('HAND_NUM', script); const gesture = mediaPipeUtils.getGesture(handNum); if (!gesture) { return 'null'; } return Lang.gesture_list[gesture.categoryName.toLowerCase()] || Lang.Blocks.unknown; }, wikiClass: 'ai_utilize_gesture', }, }; }; ================================================ FILE: src/playground/blocks/block_ai_utilize_media_pipe.js ================================================ import MediaPipeUtils, { flipState } from '../../util/mediaPipeUtils'; import _clamp from 'lodash/clamp'; const mediaPipeUtils = MediaPipeUtils.getInstance(); Entry.MediaPipeUtils = mediaPipeUtils; const flipStateTransitions = { hflip: [flipState.HORIZONTAL, flipState.NORMAL, flipState.BOTH, flipState.VERTICAL], vflip: [flipState.VERTICAL, flipState.BOTH, flipState.NORMAL, flipState.HORIZONTAL], }; module.exports = { getBlocks() { const params = { getCommonIndicator() { return { type: 'Indicator', img: 'block_icon/ai_video_icon.svg', size: 11, }; }, getCameraOrder() { return { type: 'DropdownDynamic', menuName: 'connectedCameras', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getVideoFlipOptions() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_left_right, 'hflip'], [Lang.Blocks.video_top_bottom, 'vflip'], ], value: 'hflip', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getOnOff() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_show_video, 'on'], [Lang.Blocks.video_hide_video, 'off'], ], value: 'on', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, }; return { media_pipe_title: { template: '%1', skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.Blocks.media_pipe_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'media_pipe_title', }, class: 'media_pipe', isNotFor: [ 'gestureRecognition', 'poseLandmarker', 'faceLandmarker', 'objectDetector', ], events: {}, }, media_pipe_video_screen: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getOnOff(), params.getCommonIndicator()], events: {}, def: { type: 'media_pipe_video_screen', }, paramsKeyMap: { VALUE: 0, }, class: 'media_pipe', isNotFor: [ 'gestureRecognition', 'poseLandmarker', 'faceLandmarker', 'objectDetector', ], async func(sprite, script) { const value = script.getField('VALUE'); if (!mediaPipeUtils.isInitialized) { await mediaPipeUtils.initialize(); } mediaPipeUtils.cameraOnOff(value); return script.callReturn(); }, wikiClass: 'ai_utilize_video', }, media_pipe_switch_camera: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getCameraOrder(), params.getCommonIndicator()], events: {}, def: { type: 'media_pipe_switch_camera', }, paramsKeyMap: { VALUE: 0, }, class: 'media_pipe', isNotFor: [ 'gestureRecognition', 'poseLandmarker', 'faceLandmarker', 'objectDetector', ], async func(sprite, script) { const value = script.getField('VALUE'); return await mediaPipeUtils.changeSource(value); }, wikiClass: 'ai_utilize_video', }, check_connected_camera: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [], events: {}, def: { type: 'check_connected_camera', }, paramsKeyMap: { VALUE: 0, }, class: 'media_pipe', isNotFor: [ 'gestureRecognition', 'poseLandmarker', 'faceLandmarker', 'objectDetector', ], async func(sprite, script) { return mediaPipeUtils.videoInputList.length; }, wikiClass: 'ai_utilize_video', }, media_pipe_flip_camera: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getVideoFlipOptions(), params.getCommonIndicator()], events: {}, def: { type: 'media_pipe_flip_camera', }, paramsKeyMap: { TARGET: 0, }, class: 'media_pipe', isNotFor: [ 'gestureRecognition', 'poseLandmarker', 'faceLandmarker', 'objectDetector', ], async func(sprite, script) { const target = script.getField('TARGET'); if (!mediaPipeUtils.isInitialized) { await mediaPipeUtils.initialize(); } const flipState = flipStateTransitions[target][mediaPipeUtils.flipState]; mediaPipeUtils.setFlipState(flipState); return script.callReturn(); }, wikiClass: 'ai_utilize_video', }, media_pipe_set_opacity_camera: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', value: '0', }, params.getCommonIndicator(), ], events: {}, def: { type: 'media_pipe_set_opacity_camera', }, paramsKeyMap: { VALUE: 0, }, class: 'media_pipe', isNotFor: [ 'gestureRecognition', 'poseLandmarker', 'faceLandmarker', 'objectDetector', ], async func(sprite, script) { const value = _clamp(script.getNumberValue('VALUE'), 0, 100); if (!mediaPipeUtils.isInitialized) { await mediaPipeUtils.initialize(); } mediaPipeUtils.setOpacityCamera(value); return script.callReturn(); }, wikiClass: 'ai_utilize_video', }, media_pipe_motion_value: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.video_motion_onself, 'self'], [Lang.Blocks.video_motion_onscreen, 'screen'], ], value: 'self', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Dropdown', options: [ [Lang.Blocks.video_motion_scale, 'total'], [Lang.Blocks.video_motion_direction_horizontal, 'x'], [Lang.Blocks.video_motion_direction_vertical, 'y'], ], value: 'total', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }, ], events: {}, def: { type: 'media_pipe_motion_value', }, paramsKeyMap: { TARGET: 0, TYPE: 1, }, class: 'media_pipe', isNotFor: [ 'gestureRecognition', 'poseLandmarker', 'faceLandmarker', 'objectDetector', ], async func(sprite, script) { const target = script.getField('TARGET'); const type = script.getField('TYPE'); if (!mediaPipeUtils.isInitialized) { await mediaPipeUtils.initialize(); } let detected = mediaPipeUtils.totalMotions; if (target === 'self') { detected = await mediaPipeUtils.motionDetect(sprite); if (!detected) { return 0; } } if (type === 'total') { return _clamp(detected.total / 10, 0, 100000).toString(); } try { let rawX = detected.direction.x; if (!mediaPipeUtils.isFlipState('horizontal')) { rawX *= -1; } let rawY = detected.direction.y; if (mediaPipeUtils.isFlipState('vertical')) { rawY *= -1; } const absX = Math.abs(rawX); const absY = Math.abs(rawY); if (absX < 20 && absY < 20) { return 0; } if (type === 'x') { return rawX.toFixed(1).toString(); } else if (type === 'y') { return rawY.toFixed(1).toString(); } return 0; } catch (err) { console.log(detected, err); } }, wikiClass: 'ai_utilize_video', }, }; }, }; ================================================ FILE: src/playground/blocks/block_ai_utilize_object_detector.js ================================================ import MediaPipeUtils from '../../util/mediaPipeUtils'; import _get from 'lodash/get'; const mediaPipeUtils = MediaPipeUtils.getInstance(); Entry.AI_UTILIZE_BLOCK.objectDetector = { name: 'objectDetector', imageName: 'objectDetector.svg', category: 'video', title: { ko: '사물 인식', en: 'Object Detection', }, titleKey: 'Workspace.object_detector_title_text', description: Lang.Msgs.ai_utilize_object_detector_description, descriptionKey: 'Msgs.ai_utilize_object_detector_description', isInitialized: false, async init() { await mediaPipeUtils.initialize(); Entry.AI_UTILIZE_BLOCK.objectDetector.isInitialized = true; }, destroy() { mediaPipeUtils.destroy(); Entry.AI_UTILIZE_BLOCK.objectDetector.isInitialized = false; }, }; Entry.AI_UTILIZE_BLOCK.objectDetector.getBlocks = function() { const params = { getEventIndicator() { return { type: 'Indicator', img: 'block_icon/start_icon_object.svg', size: 14, position: { x: 0, y: -2, }, }; }, getCommonIndicator() { return { type: 'Indicator', img: 'block_icon/ai_object_icon.svg', size: 11, }; }, getObjectNumber() { return { type: 'Dropdown', options: [ ['1', 0], ['2', 1], ['3', 2], ['4', 3], ], value: 0, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getStartStop() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_start, 'start'], [Lang.Blocks.video_end, 'stop'], ], value: 'start', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getShowHide() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_show_video, 'show'], [Lang.Blocks.video_hide_video, 'hide'], ], value: 'show', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getObjectList() { return { type: 'DropdownExtra', options: [ [Lang.video_object_params.person, 'person'], [Lang.video_object_params.bicycle, 'bicycle'], [Lang.video_object_params.car, 'car'], [Lang.video_object_params.motorcycle, 'motorcycle'], [Lang.video_object_params.airplane, 'airplane'], [Lang.video_object_params.bus, 'bus'], [Lang.video_object_params.train, 'train'], [Lang.video_object_params.truck, 'truck'], [Lang.video_object_params.boat, 'boat'], [Lang.video_object_params['traffic light'], 'traffic light'], [Lang.video_object_params['fire hydrant'], 'fire hydrant'], [Lang.video_object_params['stop sign'], 'stop sign'], [Lang.video_object_params['parking meter'], 'parking meter'], [Lang.video_object_params.bench, 'bench'], [Lang.video_object_params.bird, 'bird'], [Lang.video_object_params.cat, 'cat'], [Lang.video_object_params.dog, 'dog'], [Lang.video_object_params.horse, 'horse'], [Lang.video_object_params.sheep, 'sheep'], [Lang.video_object_params.cow, 'cow'], [Lang.video_object_params.elephant, 'elephant'], [Lang.video_object_params.bear, 'bear'], [Lang.video_object_params.zebra, 'zebra'], [Lang.video_object_params.giraffe, 'giraffe'], [Lang.video_object_params.backpack, 'backpack'], [Lang.video_object_params.umbrella, 'umbrella'], [Lang.video_object_params.handbag, 'handbag'], [Lang.video_object_params.tie, 'tie'], [Lang.video_object_params.suitcase, 'suitcase'], [Lang.video_object_params.frisbee, 'frisbee'], [Lang.video_object_params.skis, 'skis'], [Lang.video_object_params.snowboard, 'snowboard'], [Lang.video_object_params['sports ball'], 'sports ball'], [Lang.video_object_params.kite, 'kite'], [Lang.video_object_params['baseball bat'], 'baseball bat'], [Lang.video_object_params['baseball glove'], 'baseball glove'], [Lang.video_object_params.skateboard, 'skateboard'], [Lang.video_object_params.surfboard, 'surfboard'], [Lang.video_object_params['tennis racket'], 'tennis racket'], [Lang.video_object_params.bottle, 'bottle'], [Lang.video_object_params['wine glass'], 'wine glass'], [Lang.video_object_params.cup, 'cup'], [Lang.video_object_params.fork, 'fork'], [Lang.video_object_params.knife, 'knife'], [Lang.video_object_params.spoon, 'spoon'], [Lang.video_object_params.bowl, 'bowl'], [Lang.video_object_params.banana, 'banana'], [Lang.video_object_params.apple, 'apple'], [Lang.video_object_params.sandwich, 'sandwich'], [Lang.video_object_params.orange, 'orange'], [Lang.video_object_params.broccoli, 'broccoli'], [Lang.video_object_params.carrot, 'carrot'], [Lang.video_object_params['hot dog'], 'hot dog'], [Lang.video_object_params.pizza, 'pizza'], [Lang.video_object_params.donut, 'donut'], [Lang.video_object_params.cake, 'cake'], [Lang.video_object_params.chair, 'chair'], [Lang.video_object_params.couch, 'couch'], [Lang.video_object_params['potted plant'], 'potted plant'], [Lang.video_object_params.bed, 'bed'], [Lang.video_object_params['dining table'], 'dining table'], [Lang.video_object_params.toilet, 'toilet'], [Lang.video_object_params.tv, 'tv'], [Lang.video_object_params.laptop, 'laptop'], [Lang.video_object_params.mouse, 'mouse'], [Lang.video_object_params.remote, 'remote'], [Lang.video_object_params.keyboard, 'keyboard'], [Lang.video_object_params['cell phone'], 'cell phone'], [Lang.video_object_params.microwave, 'microwave'], [Lang.video_object_params.oven, 'oven'], [Lang.video_object_params.toaster, 'toaster'], [Lang.video_object_params.sink, 'sink'], [Lang.video_object_params.refrigerator, 'refrigerator'], [Lang.video_object_params.book, 'book'], [Lang.video_object_params.clock, 'clock'], [Lang.video_object_params.vase, 'vase'], [Lang.video_object_params.scissors, 'scissors'], [Lang.video_object_params['teddy bear'], 'teddy bear'], [Lang.video_object_params['hair drier'], 'hair drier'], [Lang.video_object_params.toothbrush, 'toothbrush'], ], value: 'bicycle', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, }; return { object_detector_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.Blocks.object_detector_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'object_detector_title', }, class: 'object', isNotFor: ['objectDetector'], events: {}, }, when_object_detector: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_event', statements: [], params: [params.getEventIndicator()], events: {}, def: { params: [null], type: 'when_object_detector', }, paramsKeyMap: { VALUE: 0, }, event: 'when_object_detector', class: 'object', isNotFor: ['objectDetector'], func(sprite, script) { return script.callReturn(); }, wikiClass: 'ai_utilize_object', }, object_detector: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getStartStop(), params.getCommonIndicator()], events: {}, def: { type: 'object_detector', }, paramsKeyMap: { VALUE: 0, }, class: 'object', isNotFor: ['objectDetector'], async func(sprite, script) { const value = script.getField('VALUE'); if (!mediaPipeUtils.isInitialized) { await mediaPipeUtils.initialize(); } if (value === 'start') { await mediaPipeUtils.startObjectDetector(value); } else { await mediaPipeUtils.stopObjectDetector(value); } return script.callReturn(); }, wikiClass: 'ai_utilize_object', }, draw_detected_object: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getShowHide(), params.getCommonIndicator()], events: {}, def: { type: 'draw_detected_object', }, paramsKeyMap: { VALUE: 0, }, class: 'object', isNotFor: ['objectDetector'], async func(sprite, script) { const value = script.getField('VALUE'); if (!mediaPipeUtils.isInitialized) { await mediaPipeUtils.initialize(); } if (value === 'show') { mediaPipeUtils.changeDrawDetectedObjectDetector(true); } else { mediaPipeUtils.changeDrawDetectedObjectDetector(false); } return script.callReturn(); }, wikiClass: 'ai_utilize_object', }, check_detected_object: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [], events: {}, def: { type: 'check_detected_object', }, paramsKeyMap: {}, class: 'object', isNotFor: ['objectDetector'], func(sprite, script) { return mediaPipeUtils.isPrevObjectDetector; }, wikiClass: 'ai_utilize_object', }, count_detected_object: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [], events: {}, def: { type: 'count_detected_object', }, paramsKeyMap: {}, class: 'object', isNotFor: ['objectDetector'], func(sprite, script) { return mediaPipeUtils.countDetectedObject || 0; }, wikiClass: 'ai_utilize_object', }, is_detected_among_objects: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [{ ...params.getObjectList(), fontSize: 10 }], events: {}, def: { type: 'is_detected_among_objects', }, paramsKeyMap: { TARGET: 0, }, class: 'object', isNotFor: ['objectDetector'], func(sprite, script) { const target = script.getField('TARGET'); const objectDetectorResult = mediaPipeUtils.prevObjectDetectorResult; const detections = _get(objectDetectorResult, 'detections'); if (detections) { const isFound = detections.some((detect) => detect.categories.some((category) => category.categoryName === target) ); return isFound; } return false; }, wikiClass: 'ai_utilize_object', }, }; }; ================================================ FILE: src/playground/blocks/block_ai_utilize_pose_landmarker.js ================================================ import MediaPipeUtils from '../../util/mediaPipeUtils'; const mediaPipeUtils = MediaPipeUtils.getInstance(); Entry.AI_UTILIZE_BLOCK.poseLandmarker = { name: 'poseLandmarker', imageName: 'poseLandmarker.svg', category: 'video', title: { ko: '사람 인식', en: 'Human Detection', }, titleKey: 'Workspace.pose_landmarker_title_text', description: Lang.Msgs.ai_utilize_pose_landmarker_description, descriptionKey: 'Msgs.ai_utilize_pose_landmarker_description', isInitialized: false, async init() { await mediaPipeUtils.initialize(); Entry.AI_UTILIZE_BLOCK.poseLandmarker.isInitialized = true; }, destroy() { mediaPipeUtils.destroy(); Entry.AI_UTILIZE_BLOCK.poseLandmarker.isInitialized = false; }, }; Entry.AI_UTILIZE_BLOCK.poseLandmarker.getBlocks = function() { const params = { getEventIndicator() { return { type: 'Indicator', img: 'block_icon/start_icon_pose.svg', size: 14, position: { x: 0, y: -2, }, }; }, getCommonIndicator() { return { type: 'Indicator', img: 'block_icon/ai_pose_icon.svg', size: 11, }; }, getPoseNumber() { return { type: 'Dropdown', options: [ ['1', 0], ['2', 1], ['3', 2], ['4', 3], ], value: 0, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getPosePoint() { return { type: 'Dropdown', options: [ [Lang.pose_list.nose, 0], [Lang.pose_list.left_eye_inner, 1], [Lang.pose_list.left_eye, 2], [Lang.pose_list.left_eye_outer, 3], [Lang.pose_list.right_eye_inner, 4], [Lang.pose_list.right_eye, 5], [Lang.pose_list.right_eye_outer, 6], [Lang.pose_list.left_ear, 7], [Lang.pose_list.right_ear, 8], [Lang.pose_list.mouth_left, 9], [Lang.pose_list.mouth_right, 10], [Lang.pose_list.left_shoulder, 11], [Lang.pose_list.right_shoulder, 12], [Lang.pose_list.left_elbow, 13], [Lang.pose_list.right_elbow, 14], [Lang.pose_list.left_wrist, 15], [Lang.pose_list.right_wrist, 16], [Lang.pose_list.left_pinky, 17], [Lang.pose_list.right_pinky, 18], [Lang.pose_list.left_index, 19], [Lang.pose_list.right_index, 20], [Lang.pose_list.left_thumb, 21], [Lang.pose_list.right_thumb, 22], [Lang.pose_list.left_hip, 23], [Lang.pose_list.right_hip, 24], [Lang.pose_list.left_knee, 25], [Lang.pose_list.right_knee, 26], [Lang.pose_list.left_ankle, 27], [Lang.pose_list.right_ankle, 28], [Lang.pose_list.left_heel, 29], [Lang.pose_list.right_heel, 30], [Lang.pose_list.left_foot_index, 31], [Lang.pose_list.right_foot_index, 32], ], value: 0, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, dropdownSync: 'posePoint', }; }, getAxis() { return { type: 'Dropdown', options: [ ['x', 'x'], ['y', 'y'], ], value: 'x', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getStartStop() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_start, 'start'], [Lang.Blocks.video_end, 'stop'], ], value: 'start', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getShowHide() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_show_video, 'show'], [Lang.Blocks.video_hide_video, 'hide'], ], value: 'show', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, }; return { pose_landmarker_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.Blocks.pose_landmarker_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'pose_landmarker_title', }, class: 'pose', isNotFor: ['poseLandmarker'], events: {}, }, when_pose_landmarker: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_event', statements: [], params: [params.getEventIndicator()], events: {}, def: { params: [null], type: 'when_pose_landmarker', }, paramsKeyMap: { VALUE: 0, }, event: 'when_pose_landmarker', class: 'pose', isNotFor: ['poseLandmarker'], func(sprite, script) { return script.callReturn(); }, wikiClass: 'ai_utilize_pose', }, pose_landmarker: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getStartStop(), params.getCommonIndicator()], events: {}, def: { type: 'pose_landmarker', }, paramsKeyMap: { VALUE: 0, }, class: 'pose', isNotFor: ['poseLandmarker'], async func(sprite, script) { const value = script.getField('VALUE'); if (!mediaPipeUtils.isInitialized) { await mediaPipeUtils.initialize(); } if (value === 'start') { await mediaPipeUtils.startPoseLandmarker(value); } else { await mediaPipeUtils.stopPoseLandmarker(value); } return script.callReturn(); }, wikiClass: 'ai_utilize_pose', }, draw_detected_pose: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getShowHide(), params.getCommonIndicator()], events: {}, def: { type: 'draw_detected_pose', }, paramsKeyMap: { VALUE: 0, }, class: 'pose', isNotFor: ['poseLandmarker'], async func(sprite, script) { const value = script.getField('VALUE'); if (!mediaPipeUtils.isInitialized) { await mediaPipeUtils.initialize(); } if (value === 'show') { mediaPipeUtils.changeDrawDetectedPoseLandmarker(true); } else { mediaPipeUtils.changeDrawDetectedPoseLandmarker(false); } return script.callReturn(); }, wikiClass: 'ai_utilize_pose', }, check_detected_pose: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [], events: {}, def: { type: 'check_detected_pose', }, paramsKeyMap: { VALUE: 0, }, class: 'pose', isNotFor: ['poseLandmarker'], func(sprite, script) { return mediaPipeUtils.isPrevPoseLandmarker; }, wikiClass: 'ai_utilize_pose', }, count_detected_pose: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [], events: {}, def: { type: 'count_detected_pose', }, paramsKeyMap: { VALUE: 0, }, class: 'pose', isNotFor: ['poseLandmarker'], func(sprite, script) { return mediaPipeUtils.countDetectedPose || 0; }, wikiClass: 'ai_utilize_pose', }, locate_to_pose: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getPoseNumber(), params.getPosePoint(), params.getCommonIndicator()], events: {}, def: { type: 'locate_to_pose', }, paramsKeyMap: { POSE: 0, POSE_POINT: 1, }, class: 'pose', isNotFor: ['poseLandmarker'], func(sprite, script) { const pose = script.getField('POSE'); const point = script.getField('POSE_POINT'); const axis = mediaPipeUtils.getPosePointAxis(pose, point); if (axis) { sprite.setX(axis.x); sprite.setY(axis.y); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(axis.x, axis.y * -1); } } return script.callReturn(); }, wikiClass: 'ai_utilize_pose', }, locate_time_to_pose: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, params.getPoseNumber(), params.getPosePoint(), params.getCommonIndicator(), ], events: {}, def: { params: [ { type: 'number', params: ['2'], }, null, null, ], type: 'locate_time_to_pose', }, paramsKeyMap: { TIME: 0, POSE: 1, POSE_POINT: 2, }, class: 'pose', isNotFor: ['poseLandmarker'], func(sprite, script) { if (!script.isStart) { const time = script.getNumberValue('TIME', script); const frameCount = Math.floor(time * Entry.FPS); const pose = script.getField('POSE', script); const point = script.getField('POSE_POINT', script); if (frameCount != 0) { const axis = mediaPipeUtils.getPosePointAxis(pose, point); if (axis) { script.isStart = true; script.frameCount = frameCount; script.dX = (axis.x - sprite.getX()) / script.frameCount; script.dY = (axis.y - sprite.getY()) / script.frameCount; } } else { const axis = mediaPipeUtils.getPosePointAxis(pose, point); if (axis) { sprite.setX(axis.x); sprite.setY(axis.y); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(axis.x, axis.y * -1); } } return script.callReturn(); } } if (script.frameCount != 0) { sprite.setX(sprite.getX() + script.dX); sprite.setY(sprite.getY() + script.dY); script.frameCount--; if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } return script; } else { delete script.isStart; delete script.frameCount; return script.callReturn(); } }, wikiClass: 'ai_utilize_pose', }, axis_detected_pose: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [ { ...params.getPoseNumber(), fontSize: 10 }, { ...params.getPosePoint(), fontSize: 10 }, { ...params.getAxis(), fontSize: 10 }, ], events: {}, def: { params: [null, null, null], type: 'axis_detected_pose', }, paramsKeyMap: { POSE: 0, POSE_POINT: 1, AXIS: 2, }, class: 'pose', isNotFor: ['poseLandmarker'], func(sprite, script) { const pose = script.getField('POSE', script); const point = script.getField('POSE_POINT', script); const axisName = script.getField('AXIS', script); const axis = mediaPipeUtils.getPosePointAxis(pose, point); if (axis) { return axis[axisName] || 0; } return 0; }, wikiClass: 'ai_utilize_pose', }, }; }; ================================================ FILE: src/playground/blocks/block_ai_utilize_translate.js ================================================ 'use strict'; const PromiseManager = require('../../core/promiseManager'); const { callApi } = require('../../util/common'); /** * 비공식으로 엔트리에서 사용되고 있는 언어코드 (vn, ja)의 경우 공식 언어코드로 치환한다. * @param {string}originalLanguage */ function replaceLanguageCode(originalLanguage) { switch (originalLanguage) { case 'jp': return 'ja'; case 'vn': return 'vi'; default: return originalLanguage; } } function getInitialCodeMap() { return { auto: { lang: Lang.Blocks.auto, sub: [ 'en', 'ja', 'zh-CN', 'zh-TW', 'es', 'fr', 'de', 'ru', 'pt', 'th', 'vi', 'id', 'hi', 'ko', ], }, ko: { lang: Lang.Blocks.korean, sub: ['en', 'ja', 'zh-CN', 'zh-TW', 'es', 'fr', 'de', 'ru', 'pt', 'th', 'vi', 'id'], }, en: { lang: Lang.Blocks.english, sub: [ 'ko', 'ja', 'zh-CN', 'zh-TW', 'es', 'fr', 'de', 'ru', 'pt', 'th', 'vi', 'id', 'hi', ], }, ja: { lang: Lang.Blocks.japan, sub: [ 'ko', 'en', 'zh-CN', 'zh-TW', 'es', 'fr', 'de', 'ru', 'pt', 'th', 'vi', 'id', 'hi', ], }, 'zh-CN': { lang: Lang.Blocks.chinese_simplified, sub: ['ko', 'en', 'ja', 'zh-TW', 'es', 'fr', 'de', 'ru', 'pt', 'th', 'vi', 'id', 'hi'], }, 'zh-TW': { lang: Lang.Blocks.chinese_traditional, sub: ['ko', 'en', 'ja', 'zh-CN', 'es', 'fr', 'de', 'ru', 'pt', 'th', 'vi', 'id', 'hi'], }, es: { lang: Lang.Blocks.spanish, sub: ['ko', 'en', 'ja', 'zh-CN', 'zh-TW', 'fr', 'de', 'ru', 'th', 'vi', 'id'], }, fr: { lang: Lang.Blocks.french, sub: ['ko', 'en', 'ja', 'zh-CN', 'zh-TW', 'es', 'de', 'ru', 'th', 'vi', 'id'], }, de: { lang: Lang.Blocks.german, sub: [ 'ko', 'en', 'ja', 'zh-CN', 'zh-TW', 'es', 'fr', 'ru', 'pt', 'th', 'vi', 'id', 'hi', ], }, ru: { lang: Lang.Blocks.russian, sub: [ 'ko', 'en', 'ja', 'zh-CN', 'zh-TW', 'es', 'fr', 'de', 'pt', 'th', 'vi', 'id', 'hi', ], }, pt: { lang: Lang.Blocks.portuguese, sub: ['ko', 'en', 'ja', 'zh-CN', 'zh-TW', 'de', 'ru', 'hi'], }, th: { lang: Lang.Blocks.thai, sub: ['ko', 'en', 'ja', 'zh-CN', 'zh-TW', 'es', 'fr', 'de', 'ru', 'vi'], }, vi: { lang: Lang.Blocks.vietnamese, sub: ['ko', 'en', 'ja', 'zh-CN', 'zh-TW', 'es', 'fr', 'de', 'ru', 'th', 'id'], }, id: { lang: Lang.Blocks.indonesian, sub: ['ko', 'en', 'zh-CN', 'zh-TW', 'es', 'fr', 'de', 'ru', 'th', 'vi'], }, hi: { lang: Lang.Blocks.hindi, sub: ['ko', 'en', 'ja', 'zh-CN', 'zh-TW', 'de', 'ru', 'pt'], }, }; } Entry.AI_UTILIZE_BLOCK.translate = { name: 'translate', imageName: 'papago.svg', category: 'general', sponsorText: 'Powered by {image}', sponsorImage: 'naver.png', sponsorOnImage: 'naverOn.png', title: { ko: '번역', en: 'translate', jp: '翻訳', }, titleKey: 'template.translate_title_text', description: Lang.Msgs.expansion_translate_description, descriptionKey: 'Msgs.expansion_translate_description', isInitialized: false, init() { if (this.isInitialized) { return; } Entry.AI_UTILIZE_BLOCK.translate.delayKey = Entry.projectId; Entry.AI_UTILIZE_BLOCK.translate.isInitialized = true; }, api: '/api/expansionBlock/papago/', sponsor: 'papagoNaver', sponsorLink: 'https://www.ncloud.com/product/aiService/papagoNmt', typeMap: { dictionary: 'nsmt', artificial_intelligence: 'n2mt', }, apiType: 'n2mt', }; Entry.AI_UTILIZE_BLOCK.translate.getBlocks = function () { const params = { getType(isPython) { const param = { type: 'Dropdown', options: [ [Lang.Blocks.dictionary, 'dictionary'], [Lang.Blocks.artificial_intelligence, 'artificial_intelligence'], ], value: 'dictionary', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getSourceLang(isPython) { const value = replaceLanguageCode(Lang.type); const options = [ [Lang.Blocks.korean, 'ko'], [Lang.Blocks.english, 'en'], [Lang.Blocks.japan, 'ja'], [Lang.Blocks.chinese_simplified, 'zh-CN'], [Lang.Blocks.chinese_traditional, 'zh-TW'], [Lang.Blocks.spanish, 'es'], [Lang.Blocks.french, 'fr'], [Lang.Blocks.german, 'de'], [Lang.Blocks.russian, 'ru'], [Lang.Blocks.portuguese, 'pt'], [Lang.Blocks.thai, 'th'], [Lang.Blocks.vietnamese, 'vi'], [Lang.Blocks.indonesian, 'id'], [Lang.Blocks.hindi, 'hi'], ]; const index = _.findIndex(options, (x) => x[1] === value); if (index > 0) { const temp = options[index]; options[index] = options[0]; options[0] = temp; } const param = { type: 'Dropdown', options, value, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, dropdownSync: 'translate', }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getTargetLang(isPython = false) { const param = { type: 'DropdownDynamic', value: null, menuName() { const value = this.getTargetValue('translate'); if (!value) { return [[Lang.Blocks.no_target, 'null']]; } const langCodeMap = getInitialCodeMap(); const convertedLangCode = replaceLanguageCode(value); return langCodeMap[convertedLangCode].sub.map((code) => [ langCodeMap[code].lang, code, ]); }, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options.length) { return options[0][1]; } return null; }, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, }; const getProjectId = function () { if (Entry.projectId) { Entry.AI_UTILIZE_BLOCK.translate.delayKey = Entry.projectId; } if (Entry.AI_UTILIZE_BLOCK.translate.delayKey) { return Entry.AI_UTILIZE_BLOCK.translate.delayKey; } Entry.AI_UTILIZE_BLOCK.translate.delayKey = _.uniqueId(Entry.generateHash()); return Entry.AI_UTILIZE_BLOCK.translate.delayKey; }; const translate = (params, type, defaultValue) => { params.projectId = getProjectId(); const key = `translate-${type}${JSON.stringify(params)}`; return new PromiseManager() .Promise(async (resolve) => { callApi( key, { url: `${Entry.AI_UTILIZE_BLOCK.translate.api}translate/${type}`, params, }, window.isOffline ? await window.getPapagoHeaderInfo() : {} ) .then((result) => { if (result.data) { return resolve(result.data.translatedText); } return resolve(defaultValue); }) .catch(() => resolve(defaultValue)); }) .catch(() => defaultValue); }; const checkLang = (query, defaultValue) => { const langCodeMap = getInitialCodeMap(); return new PromiseManager() .Promise((resolve) => { callApi( `translate-detect-${query}`, { url: `${Entry.AI_UTILIZE_BLOCK.translate.api}dect/langs`, params: { query, projectId: getProjectId() }, }, window.isOffline ? window.getPapagoHeaderInfo() : {} ) .then((result) => { if ( result.data && result.data.langCode && langCodeMap[result.data.langCode] ) { return resolve(langCodeMap[result.data.langCode].lang); } return resolve(defaultValue); }) .catch(() => resolve(defaultValue)); }) .catch(() => defaultValue); }; const checkText = function (text) { const result = { result: false, message: Lang.Blocks.unknown_sentence, }; if (!text) { result.message = Lang.Blocks.no_sentence; return result; } if (text.length > 3000) { result.message = Lang.Blocks.sentence_over_3000_charactor; return result; } return { result: true, message: text, }; }; return { translate_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.translate_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'translate_title', }, class: 'translate', isNotFor: ['translate'], events: {}, }, get_translated_string: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [ params.getSourceLang(), { type: 'Block', accept: 'string', }, params.getTargetLang(), ], events: {}, def: { params: [ params.getSourceLang().value, { type: 'text', params: [Lang.Blocks.entry], }, null, ], type: 'get_translated_string', }, pyHelpDef: { params: ['A&value', 'B&value', 'C&value'], type: 'get_translated_string', }, paramsKeyMap: { SOURCE: 0, TEXT: 1, TARGET: 2, }, class: 'translate', isNotFor: ['translate'], func(sprite, script) { const textObj = checkText(script.getStringValue('TEXT', script)); if (!textObj.result) { return textObj.message; } const type = Entry.AI_UTILIZE_BLOCK.translate.apiType; const params = { text: textObj.message, target: script.getField('TARGET', script), source: script.getField('SOURCE', script), }; if (params.target == params.source) { return params.text; } return translate(params, type, Lang.Blocks.unknown_sentence); }, syntax: { js: [], py: [ { syntax: 'Translate.do(%1, %2, %3)', blockType: 'param', textParams: [ params.getSourceLang(true), { type: 'Block', accept: 'string', }, params.getTargetLang(true), ], }, ], }, wikiClass: 'ai_utilize_translate', }, check_language: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'text', params: [Lang.Blocks.entry], }, ], type: 'check_language', }, pyHelpDef: { params: ['A&value'], type: 'check_language', }, paramsKeyMap: { TEXT: 0, LANG: 1, }, class: 'translate', isNotFor: ['translate'], func(sprite, script) { const text = script.getStringValue('TEXT', script); const textObj = checkText(text); if (!textObj.result) { return textObj.message; } return checkLang(textObj.message, Lang.Blocks.unknown_sentence); }, syntax: { js: [], py: [ { syntax: 'Translate.getLang(%1)', params: [null], blockType: 'param', textParams: [ { type: 'Block', accept: 'string', }, ], }, ], }, wikiClass: 'ai_utilize_translate', }, }; }; ================================================ FILE: src/playground/blocks/block_ai_utilize_tts.js ================================================ 'use strict'; const { toQueryString } = require('../../util/common'); const _trim = require('lodash/trim'); Entry.AI_UTILIZE_BLOCK.tts = { name: 'tts', imageName: 'tts.svg', category: 'general', sponsorText: 'Powered by {image}', sponsorImage: 'naverClova.png', sponsorOnImage: 'naverClovaOn.png', title: { ko: '읽어주기', en: 'read', jp: 'を読み上げる', }, titleKey: 'template.tts_title_text', description: Lang.Msgs.ai_utilize_tts_description, descriptionKey: 'Msgs.ai_utilize_tts_description', isInitialized: true, init() {}, api: '/api/expansionBlock/tts/read', sponsor: 'clovaNaver', sponsorLink: 'https://www.ncloud.com/product/aiService/css', loadQueue: [], }; Entry.AI_UTILIZE_BLOCK.tts.getBlocks = function() { const params = { getSpeaker(isPython = false) { const param = { type: 'Dropdown', options: [ [Lang.Blocks.tts_female, 'kyuri'], [Lang.Blocks.tts_male, 'jinho'], [Lang.Blocks.tts_kind, 'hana'], [Lang.Blocks.tts_sweet, 'dinna'], [Lang.Blocks.tts_echo, 'brown'], [Lang.Blocks.tts_mischievous, 'minions'], [Lang.Blocks.tts_dainty, 'sally'], [Lang.Blocks.tts_sabina, 'nsabina'], [Lang.Blocks.tts_mammon, 'nmammon'], [Lang.Blocks.tts_kitty, 'nmeow'], [Lang.Blocks.tts_doggy, 'nwoof'], ], value: 'kyuri', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getSpeed(isPython = false) { const param = { type: 'Dropdown', options: [ [Lang.Blocks.tts_veryslow, '5'], [Lang.Blocks.tts_slow, '3'], [Lang.Blocks.tts_normal, '0'], [Lang.Blocks.tts_fast, '-3'], [Lang.Blocks.tts_veryfast, '-5'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getPitch(isPython = false) { const param = { type: 'Dropdown', options: [ [Lang.Blocks.tts_verylow, '5'], [Lang.Blocks.tts_low, '3'], [Lang.Blocks.tts_normal, '0'], [Lang.Blocks.tts_high, '-3'], [Lang.Blocks.tts_veryhigh, '-5'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, }; const hashCode = (s) => s.split('').reduce(function(a, b) { a = (a << 5) - a + b.charCodeAt(0); return a & a; }, 0); const checkText = function(text) { const result = { result: false, message: Lang.Blocks.unknown_sentence, }; if (!text) { result.message = Lang.Blocks.no_sentence; return result; } if (text.length > 2500) { result.message = Lang.Blocks.sentence_over_2500_charactor; return result; } return { result: true, message: _trim(text), hash: hashCode(text + new Date().getTime()), }; }; /** * wodnjs6512: 로드를 새로 할때는 queue를 다시 만든다고 하네요 * 기존 코드에서 하나의 로더로 로드를 2개를 콜하면 하나는 정상 로드가 되지 않는 이슈가 있다고 합니다 * 한번에 로드가 가능하도록 매번 로더를 따로 만들어서 사용하도록 수정 * https://github.com/CreateJS/PreloadJS/issues/232#issuecomment-338739115 * */ const read = function(args) { return new Promise((resolve) => { const { message, hash, prop } = args; const tts = Entry.AI_UTILIZE_BLOCK.tts; const id = `tts-${hash}-${JSON.stringify(prop)}`; const type = createjs.LoadQueue.SOUND; const soundQueue = new createjs.LoadQueue(true); soundQueue.installPlugin(createjs.Sound); soundQueue.maintainScriptOrder = true; const src = `${Entry.baseUrl}${Entry.AI_UTILIZE_BLOCK.tts.api}.mp3?${toQueryString({ text: message, ...prop, })}`; const loadHandler = ({ currentTarget }) => { const items = currentTarget.getItems().map(({ item }) => item); tts.loadQueue = tts.loadQueue.filter((id) => { const filtered = items.find((item) => item.id === id); if (filtered) { const instance = Entry.Utils.playSound(id, filtered.prop); instance.soundType = 'tts'; Entry.Utils.addSoundInstances(instance); const duration = instance.duration > 0 ? instance.duration : filtered.duration * 300; setTimeout(() => { resolve(); }, duration); } return true; }); }; // 읽어주기 오류 발생 시, 다음 블록 실행 const errorHandler = async () => { soundQueue.removeEventListener('complete', loadHandler); soundQueue.removeEventListener('error', errorHandler); soundQueue.destroy(); resolve(); }; soundQueue.on('complete', loadHandler); soundQueue.on('error', errorHandler); soundQueue.loadFile({ id, src, type, prop, duration: message.length }); tts.loadQueue.push(id); }); }; return { tts_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.tts_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'tts_title', }, class: 'tts', isNotFor: ['tts'], events: {}, }, read_text: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'text', params: [Lang.Blocks.entry], }, null, ], type: 'read_text', }, pyHelpDef: { params: ['A&value'], type: 'read_text', }, paramsKeyMap: { TEXT: 0, }, class: 'tts', isNotFor: ['tts'], func(sprite, script) { const { result, message, hash } = checkText(script.getStringValue('TEXT', script)); if (result) { const prop = sprite.getVoiceProp(); read({ message, hash, prop, }); } return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'TTS.read(%1)', blockType: 'param', textParams: [ { type: 'Block', accept: 'string', }, ], }, ], }, wikiClass: 'ai_utilize_tts', }, read_text_wait_with_block: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'text', params: [Lang.Blocks.entry], }, null, ], type: 'read_text_wait_with_block', }, pyHelpDef: { params: ['A&value'], type: 'read_text_wait_with_block', }, paramsKeyMap: { TEXT: 0, }, class: 'tts', isNotFor: ['tts'], async func(sprite, script) { const { result, message, hash } = checkText(script.getStringValue('TEXT', script)); const prop = sprite.getVoiceProp(); if (result) { await read({ message, hash, prop, }); return script.callReturn(); } }, syntax: { js: [], py: [ { passTest: true, syntax: 'TTS.read_and_wait(%1)', }, ], }, wikiClass: 'ai_utilize_tts', }, set_tts_property: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ params.getSpeaker(), params.getSpeed(), params.getPitch(), { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }, ], events: {}, def: { params: [ params.getSpeaker().value, params.getSpeed().value, params.getPitch().value, null, ], type: 'set_tts_property', }, pyHelpDef: { params: ['A&value', 'B&value', 'C&value'], type: 'set_tts_property', }, paramsKeyMap: { SPEAKER: 0, SPEED: 1, PITCH: 2, }, class: 'tts', isNotFor: ['tts'], func(sprite, script) { const speaker = script.getField('SPEAKER', script); const speed = script.getField('SPEED', script); const pitch = script.getField('PITCH', script); const volume = 1; sprite.setVoiceProp({ speaker, speed, pitch, volume }); return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'TTS.set(%1, %2, %3)', blockType: 'param', textParams: [ params.getSpeaker(true), params.getSpeed(true), params.getPitch(true), ], }, ], }, wikiClass: 'ai_utilize_tts', }, }; }; ================================================ FILE: src/playground/blocks/block_ai_utilize_video.js ================================================ import VideoUtils from '@entrylabs/legacy-video'; import clamp from 'lodash/clamp'; import { GEHelper } from '../../graphicEngine/GEHelper'; Entry.VideoUtils = VideoUtils; Entry.AI_UTILIZE_BLOCK.video = { name: 'video', imageName: 'video.svg', category: 'video', title: { ko: '비디오 감지', en: 'Video Detection', jp: 'ビデオ検出', }, titleKey: 'template.video_title_text', description: Lang.Msgs.ai_utilize_video_description, descriptionKey: 'Msgs.ai_utilize_video_description', isInitialized: false, async init() { await VideoUtils.initialize(GEHelper); Entry.AI_UTILIZE_BLOCK.video.isInitialized = true; }, destroy() { VideoUtils.destroy(); Entry.AI_UTILIZE_BLOCK.video.isInitialized = false; }, }; Entry.AI_UTILIZE_BLOCK.video.getBlocks = function() { const params = { getCommonIndicator() { return { type: 'Indicator', img: 'block_icon/ai_utilize_icon.svg', size: 11, }; }, getCameraOrder() { return { type: 'DropdownDynamic', menuName: 'connectedCameras', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getNumbers() { return { type: 'Dropdown', options: [ ['1', 0], ['2', 1], ['3', 2], ['4', 3], ], value: 0, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getOnOff() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_show_video, 'on'], [Lang.Blocks.video_hide_video, 'off'], ], value: 'on', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getVideoFlipOptions() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_left_right, 'hflip'], [Lang.Blocks.video_top_bottom, 'vflip'], ], value: 'hflip', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getAiModelOptions() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_human, 'pose'], [Lang.Blocks.video_face, 'face'], [Lang.Blocks.video_object, 'object'], ], value: 'pose', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getSwitchOptions() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_start, 'on'], [Lang.Blocks.video_end, 'off'], ], value: 'on', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getFaceInfoOptions() { return { type: 'Dropdown', options: [ [Lang.Blocks.video_gender, 'gender'], [Lang.Blocks.video_age, 'age'], [Lang.Blocks.video_emotion, 'emotion'], ], value: 'gender', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getFaceCoords() { return { type: 'Dropdown', options: [ [Lang.video_body_coord_params.left_eye, 45], [Lang.video_body_coord_params.right_eye, 36], [Lang.video_body_coord_params.nose, 30], [Lang.video_body_coord_params.left_mouth, 54], [Lang.video_body_coord_params.right_mouth, 48], [Lang.video_body_coord_params.upper_lip, 62], [Lang.video_body_coord_params.lower_lip, 66], ], value: 45, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getBodyCoords() { return { type: 'Dropdown', options: [ [Lang.video_body_coord_params.face, 0], [Lang.video_body_coord_params.neck, 21], [Lang.video_body_coord_params.left_eye, 1], [Lang.video_body_coord_params.right_eye, 2], [Lang.video_body_coord_params.left_ear, 3], [Lang.video_body_coord_params.right_ear, 4], [Lang.video_body_coord_params.left_shoulder, 5], [Lang.video_body_coord_params.right_shoulder, 6], [Lang.video_body_coord_params.left_elbow, 7], [Lang.video_body_coord_params.right_elbow, 8], [Lang.video_body_coord_params.left_wrist, 9], [Lang.video_body_coord_params.right_wrist, 10], [Lang.video_body_coord_params.left_hip, 11], [Lang.video_body_coord_params.right_hip, 12], [Lang.video_body_coord_params.left_knee, 13], [Lang.video_body_coord_params.right_knee, 14], [Lang.video_body_coord_params.left_ankle, 15], [Lang.video_body_coord_params.right_ankle, 16], ], value: 0, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getCoordXYOptions() { return { type: 'Dropdown', options: [ ['x', 'x'], ['y', 'y'], ], value: 'x', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, getObjectList() { return { type: 'DropdownExtra', options: [ [Lang.video_object_params.person, 'person'], [Lang.video_object_params.bicycle, 'bicycle'], [Lang.video_object_params.car, 'car'], [Lang.video_object_params.motorcycle, 'motorcycle'], [Lang.video_object_params.airplane, 'airplane'], [Lang.video_object_params.bus, 'bus'], [Lang.video_object_params.train, 'train'], [Lang.video_object_params.truck, 'truck'], [Lang.video_object_params.boat, 'boat'], [Lang.video_object_params['traffic light'], 'traffic light'], [Lang.video_object_params['fire hydrant'], 'fire hydrant'], [Lang.video_object_params['stop sign'], 'stop sign'], [Lang.video_object_params['parking meter'], 'parking meter'], [Lang.video_object_params.bench, 'bench'], [Lang.video_object_params.bird, 'bird'], [Lang.video_object_params.cat, 'cat'], [Lang.video_object_params.dog, 'dog'], [Lang.video_object_params.horse, 'horse'], [Lang.video_object_params.sheep, 'sheep'], [Lang.video_object_params.cow, 'cow'], [Lang.video_object_params.elephant, 'elephant'], [Lang.video_object_params.bear, 'bear'], [Lang.video_object_params.zebra, 'zebra'], [Lang.video_object_params.giraffe, 'giraffe'], [Lang.video_object_params.backpack, 'backpack'], [Lang.video_object_params.umbrella, 'umbrella'], [Lang.video_object_params.handbag, 'handbag'], [Lang.video_object_params.tie, 'tie'], [Lang.video_object_params.suitcase, 'suitcase'], [Lang.video_object_params.frisbee, 'frisbee'], [Lang.video_object_params.skis, 'skis'], [Lang.video_object_params.snowboard, 'snowboard'], [Lang.video_object_params['sports ball'], 'sports ball'], [Lang.video_object_params.kite, 'kite'], [Lang.video_object_params['baseball bat'], 'baseball bat'], [Lang.video_object_params['baseball glove'], 'baseball glove'], [Lang.video_object_params.skateboard, 'skateboard'], [Lang.video_object_params.surfboard, 'surfboard'], [Lang.video_object_params['tennis racket'], 'tennis racket'], [Lang.video_object_params.bottle, 'bottle'], [Lang.video_object_params['wine glass'], 'wine glass'], [Lang.video_object_params.cup, 'cup'], [Lang.video_object_params.fork, 'fork'], [Lang.video_object_params.knife, 'knife'], [Lang.video_object_params.spoon, 'spoon'], [Lang.video_object_params.bowl, 'bowl'], [Lang.video_object_params.banana, 'banana'], [Lang.video_object_params.apple, 'apple'], [Lang.video_object_params.sandwich, 'sandwich'], [Lang.video_object_params.orange, 'orange'], [Lang.video_object_params.broccoli, 'broccoli'], [Lang.video_object_params.carrot, 'carrot'], [Lang.video_object_params['hot dog'], 'hot dog'], [Lang.video_object_params.pizza, 'pizza'], [Lang.video_object_params.donut, 'donut'], [Lang.video_object_params.cake, 'cake'], [Lang.video_object_params.chair, 'chair'], [Lang.video_object_params.couch, 'couch'], [Lang.video_object_params['potted plant'], 'potted plant'], [Lang.video_object_params.bed, 'bed'], [Lang.video_object_params['dining table'], 'dining table'], [Lang.video_object_params.toilet, 'toilet'], [Lang.video_object_params.tv, 'tv'], [Lang.video_object_params.laptop, 'laptop'], [Lang.video_object_params.mouse, 'mouse'], [Lang.video_object_params.remote, 'remote'], [Lang.video_object_params.keyboard, 'keyboard'], [Lang.video_object_params['cell phone'], 'cell phone'], [Lang.video_object_params.microwave, 'microwave'], [Lang.video_object_params.oven, 'oven'], [Lang.video_object_params.toaster, 'toaster'], [Lang.video_object_params.sink, 'sink'], [Lang.video_object_params.refrigerator, 'refrigerator'], [Lang.video_object_params.book, 'book'], [Lang.video_object_params.clock, 'clock'], [Lang.video_object_params.vase, 'vase'], [Lang.video_object_params.scissors, 'scissors'], [Lang.video_object_params['teddy bear'], 'teddy bear'], [Lang.video_object_params['hair drier'], 'hair drier'], [Lang.video_object_params.toothbrush, 'toothbrush'], ], value: 'bicycle', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }; }, }; return { video_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.video_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'video_title', }, class: 'video', isNotFor: ['video'], events: {}, }, video_change_cam: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getCameraOrder(), params.getCommonIndicator()], events: {}, def: { type: 'video_change_cam', }, paramsKeyMap: { VALUE: 0, }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const VALUE = script.getField('VALUE'); return await VideoUtils.changeSource(VALUE); }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, video_check_webcam: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [], events: {}, def: { type: 'video_check_webcam', }, paramsKeyMap: { VALUE: 0, }, class: 'video', isNotFor: ['video'], func(sprite, script) { return VideoUtils.videoInputList.length > 0; }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, video_draw_webcam: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getOnOff(), params.getCommonIndicator()], events: {}, def: { type: 'video_draw_webcam', }, paramsKeyMap: { VALUE: 0, }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const value = script.getField('VALUE'); if (!VideoUtils.isInitialized) { await VideoUtils.initialize(GEHelper); } VideoUtils.cameraSwitch(value); return script.callReturn(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, video_set_camera_opacity_option: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', value: '0', }, params.getCommonIndicator(), ], events: {}, def: { type: 'video_set_camera_opacity_option', }, paramsKeyMap: { VALUE: 0, }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const value = clamp(script.getNumberValue('VALUE'), 0, 100); try { if (!VideoUtils.isInitialized) { await VideoUtils.initialize(GEHelper); } VideoUtils.setOptions('transparency', value); return script.callReturn(); } catch (err) { console.log(err); throw err; } }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, video_flip_camera: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getVideoFlipOptions(), params.getCommonIndicator()], events: {}, def: { type: 'video_flip_camera', }, paramsKeyMap: { TARGET: 0, }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const target = script.getField('TARGET'); if (!VideoUtils.isInitialized) { await VideoUtils.initialize(GEHelper); } VideoUtils.setOptions(target); return script.callReturn(); }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, video_toggle_model: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [ params.getAiModelOptions(), params.getSwitchOptions(), params.getCommonIndicator(), ], events: {}, def: { type: 'video_toggle_model', }, paramsKeyMap: { TARGET: 0, MODE: 1, }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const target = script.getField('TARGET'); const mode = script.getField('MODE'); if (!VideoUtils.isInitialized) { await VideoUtils.initialize(GEHelper); } VideoUtils.manageModel(target, mode); }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, video_toggle_ind: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic', statements: [], params: [params.getAiModelOptions(), params.getOnOff(), params.getCommonIndicator()], events: {}, def: { type: 'video_toggle_ind', }, paramsKeyMap: { CRITERIA: 0, OPTION: 1, }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const criteria = script.getField('CRITERIA'); const option = script.getField('OPTION'); if (!VideoUtils.isInitialized) { await VideoUtils.initialize(GEHelper); } if (option === 'on') { VideoUtils.showIndicator(criteria); } else { VideoUtils.removeIndicator(criteria); } }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, video_number_detect: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [params.getAiModelOptions()], events: {}, def: { type: 'video_number_detect', }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const target = script.getField('TARGET'); if (!VideoUtils.isInitialized) { await VideoUtils.initialize(GEHelper); } switch (target) { case 'face': return VideoUtils.faces.length || 0; case 'pose': return (VideoUtils.poses && VideoUtils.poses.predictions.length) || 0; case 'object': return VideoUtils.objects.length || 0; } }, paramsKeyMap: { TARGET: 0, }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, video_object_detected: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [params.getObjectList()], events: {}, def: { type: 'video_object_detected', }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const target = script.getField('TARGET'); if (!VideoUtils.isInitialized) { await VideoUtils.initialize(GEHelper); } let result = false; VideoUtils.objects.forEach((detected) => { if (detected.class === target) { result = true; } }); return result; }, paramsKeyMap: { TARGET: 0, }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, // 원래는 video_is_model_detected 로 나가야 하나, 해당 부분에 있어서 기존 하위 호환성때문에... 이름을 못바꿈... video_is_model_loaded: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_boolean_field', statements: [], params: [params.getAiModelOptions()], events: {}, def: { type: 'video_is_model_loaded', }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const target = script.getField('TARGET'); if (!VideoUtils.isInitialized) { await VideoUtils.initialize(GEHelper); return false; } switch (target) { case 'face': return VideoUtils.faces.length > 0; case 'pose': return VideoUtils.poses && VideoUtils.poses.predictions.length > 0; case 'object': return VideoUtils.objects.length > 0; } }, paramsKeyMap: { TARGET: 0, }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, video_detected_face_info: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [params.getNumbers(), params.getFaceInfoOptions()], events: {}, def: { type: 'video_detected_face_info', }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const index = script.getField('INDEX'); const info = script.getField('INFO'); const faces = VideoUtils.faces; if (!VideoUtils.isInitialized) { await VideoUtils.initialize(GEHelper); } if (faces.length <= index) { return 0; } const target = VideoUtils.faces[index]; if (!target) { return 0; } switch (info) { case 'gender': return Lang.video_gender[target.gender]; case 'age': return target.age.toFixed(0).toString(); case 'emotion': let emotion = ''; let maxVal = 0; for (const status in target.expressions) { const emotionVal = target.expressions[status]; if (emotionVal > maxVal) { maxVal = emotionVal; emotion = status; } } return Lang.video_emotion_params[emotion]; } }, paramsKeyMap: { INDEX: 0, INFO: 1, }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, video_motion_value: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.video_motion_onself, 'self'], [Lang.Blocks.video_motion_onscreen, 'screen'], ], value: 'self', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Dropdown', options: [ [Lang.Blocks.video_motion_scale, 'total'], [Lang.Blocks.video_motion_direction_horizontal, 'x'], [Lang.Blocks.video_motion_direction_vertical, 'y'], ], value: 'total', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.AI_UTILIZE, arrowColor: EntryStatic.colorSet.common.WHITE, }, ], events: {}, def: { type: 'video_motion_value', }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const target = script.getField('TARGET'); const type = script.getField('TYPE'); let detected = VideoUtils.totalMotions; if (!VideoUtils.isInitialized) { await VideoUtils.initialize(GEHelper); } if (target === 'self') { detected = VideoUtils.motionDetect(sprite); } if (type === 'total') { return clamp(detected.total / 10, 0, 100000).toString(); } try { let rawX = detected.direction.x; if (!VideoUtils.flipStatus.horizontal) { rawX *= -1; } let rawY = detected.direction.y; if (VideoUtils.flipStatus.vertical) { rawY *= -1; } const absX = Math.abs(rawX); const absY = Math.abs(rawY); if (absX < 20 && absY < 20) { return 0; } if (type === 'x') { return rawX.toFixed(1).toString(); } else if (type === 'y') { return rawY.toFixed(1).toString(); } return 0; } catch (err) { console.log(detected); } }, paramsKeyMap: { TARGET: 0, TYPE: 1, }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, video_face_part_coord: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [params.getNumbers(), params.getFaceCoords(), params.getCoordXYOptions()], events: {}, def: { type: 'video_face_part_coord', }, paramsKeyMap: { INDEX: 0, PART: 1, COORD: 2, }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const index = script.getField('INDEX'); const part = script.getField('PART'); const coord = script.getField('COORD'); if (!VideoUtils.isInitialized) { await VideoUtils.initialize(GEHelper); } if (!VideoUtils.faces) { return 0; } try { const faces = VideoUtils.faces; if (faces.length <= index) { return 0; } // offset since value shown starts from 1; const rawValue = faces[index].landmarks._positions[part][`_${coord}`]; if (!rawValue) { return 0; } let returningValue = 0; if (coord === 'x') { returningValue = rawValue - VideoUtils.CANVAS_WIDTH / 2; if (VideoUtils.flipStatus.horizontal) { returningValue *= -1; } } else { returningValue = VideoUtils.CANVAS_HEIGHT / 2 - rawValue; if (VideoUtils.flipStatus.vertical) { returningValue *= -1; } } return returningValue.toFixed(1); } catch (err) { return 0; } }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, video_body_part_coord: { color: EntryStatic.colorSet.block.default.AI_UTILIZE, outerLine: EntryStatic.colorSet.block.darken.AI_UTILIZE, skeleton: 'basic_string_field', statements: [], params: [params.getNumbers(), params.getBodyCoords(), params.getCoordXYOptions()], events: {}, def: { type: 'video_body_part_coord', }, paramsKeyMap: { INDEX: 0, PART: 1, COORD: 2, }, class: 'video', isNotFor: ['video'], async func(sprite, script) { const index = script.getField('INDEX'); const part = script.getField('PART'); const coord = script.getField('COORD'); if (!VideoUtils.isInitialized) { await VideoUtils.initialize(GEHelper); } if (!VideoUtils.poses || !VideoUtils.poses.predictions) { return 0; } try { const poses = VideoUtils.poses.predictions; if (poses.length < index) { return 0; } // offset since value shown starts from 1; const rawValue = poses[index].keypoints[part].position[coord]; if (!rawValue) { return 0; } let returningValue = 0; if (coord === 'x') { returningValue = rawValue - VideoUtils.CANVAS_WIDTH / 2; } else { returningValue = VideoUtils.CANVAS_HEIGHT / 2 - rawValue; if (VideoUtils.flipStatus.vertical) { returningValue *= -1; } } return returningValue.toFixed(1); } catch (err) { return 0; } }, syntax: { js: [], py: [], }, wikiClass: 'ai_utilize_video', }, }; }; ================================================ FILE: src/playground/blocks/block_analysis.js ================================================ // import _chain from 'lodash/chain'; import _isNumber from 'lodash/isNumber'; import DataTable from '../../class/DataTable'; import { toNumber } from '../../util/common'; module.exports = { getBlocks() { const getSubMenus = (value) => { const { fields = [] } = DataTable.getSource(value) || {}; return fields.map((label, index) => [label, index + 1]); }; const getColumnNumber = (str) => { if (/\d/.test(str)) { return -1; } return ( // _chain(str) // did not work.. _.chain(str) .toUpper() .reduce((prev, curr) => prev * 26 + curr.charCodeAt() - 64, 0) .value() ); }; return { analizyDataAddButton: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, params: [ { type: 'Text', text: Lang.Workspace.open_analizy_data_import, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], def: { type: 'analizyDataAddButton', }, events: { mousedown: [ function () { Entry.playground.dataTable.show(); }, ], }, syntax: { js: [], py: [''] }, }, append_row_to_table: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Dropdown', options: [ [Lang.Blocks.table_row, 'ROW'], [Lang.Blocks.table_col, 'COL'], ], value: 'ROW', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/block_analysis.svg', size: 11, }, ], events: {}, def: { params: [null, null, null], type: 'append_row_to_table', }, pyHelpDef: { params: [ { type: 'text', params: ['A&value'], }, { type: 'text', params: ['B&value'], }, ], type: 'append_row_to_table', }, paramsKeyMap: { MATRIX: 0, PROPERTY: 1, }, class: 'analysis', isNotFor: ['analysis'], async func(sprite, script) { const tableId = script.getField('MATRIX', script); const property = script.getStringValue('PROPERTY', script); const table = DataTable.getSource(tableId, sprite); if (property === 'ROW') { await table.appendRow(); } else { await table.appendCol(); } return script.callReturn(); }, syntax: { js: [], py: [], }, }, insert_row_to_table: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Dropdown', options: [ [Lang.Blocks.table_row, 'ROW'], [Lang.Blocks.table_col, 'COL'], ], value: 'ROW', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/block_analysis.svg', size: 11, }, ], events: {}, def: { params: [ null, { type: 'text', params: ['2'], }, null, null, ], type: 'insert_row_to_table', }, pyHelpDef: { params: [ { type: 'text', params: ['B&value'], }, { type: 'text', params: ['A&value'], }, { type: 'text', params: ['C&value'], }, null, ], type: 'insert_row_to_table', }, paramsKeyMap: { MATRIX: 0, NUMBER: 1, PROPERTY: 2, }, class: 'analysis', isNotFor: ['analysis'], async func(sprite, script) { const tableId = script.getField('MATRIX', script); const number = script.getNumberValue('NUMBER', script); const property = script.getStringValue('PROPERTY', script); const table = DataTable.getSource(tableId, sprite); if (property === 'ROW') { await table.insertRow(number - 1); } else { await table.insertCol(number); } return script.callReturn(); }, syntax: { js: [], py: [], }, }, delete_row_from_table: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Dropdown', options: [ [Lang.Blocks.table_row, 'ROW'], [Lang.Blocks.table_col, 'COL'], ], value: 'ROW', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/block_analysis.svg', size: 11, }, ], events: {}, def: { params: [ null, { type: 'text', params: ['2'], }, null, null, ], type: 'delete_row_from_table', }, pyHelpDef: { params: [ { type: 'text', params: ['B&value'], }, { type: 'text', params: ['A&value'], }, { type: 'text', params: ['C&value'], }, null, ], type: 'delete_row_from_table', }, paramsKeyMap: { MATRIX: 0, NUMBER: 1, PROPERTY: 2, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const number = script.getNumberValue('NUMBER', script); const property = script.getStringValue('PROPERTY', script); const table = DataTable.getSource(tableId, sprite); if (property === 'ROW') { table.deleteRow(number - 1); } else { table.deleteCol(number); } return script.callReturn(); }, syntax: { js: [], py: [], }, }, set_value_from_table: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/block_analysis.svg', size: 11, }, ], events: {}, def: { params: [ null, { type: 'text', params: ['2'], }, { type: 'get_table_fields', }, { type: 'text', params: ['10'], }, null, ], type: 'set_value_from_table', }, pyHelpDef: { params: [ { type: 'text', params: ['D&value'], }, { type: 'text', params: ['C&value'], }, { type: 'text', params: ['B&value'], }, { type: 'text', params: ['A&value'], }, null, ], type: 'set_value_from_table', }, paramsKeyMap: { MATRIX: 0, NUMBER: 1, FIELD: 2, VALUE: 3, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const row = script.getNumberValue('NUMBER', script) - 1; const col = DataTable.getColumnIndex(script.getValue('FIELD', script)); const value = script.getValue('VALUE', script); const table = DataTable.getSource(tableId, sprite); if (table.isExist([row, col])) { table.replaceValue([row, col], value); } return script.callReturn(); }, syntax: { js: [], py: [], }, }, // 테이블 $1의 현재 상태를 저장하기 save_current_table: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/block_analysis.svg', size: 11, }, ], events: {}, def: { params: [null, null], type: 'save_current_table', }, pyHelpDef: { params: [ { type: 'text', params: ['D&value'], }, null, ], type: 'save_current_table', }, paramsKeyMap: { MATRIX: 0, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const table = DataTable.getSource(tableId); DataTable.saveTable({ selected: table.dataTable }); return script.callReturn(); }, syntax: { js: [], py: [], }, }, // 테이블 %1 %2 개수 get_table_count: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Dropdown', options: [ [Lang.Blocks.table_row, 'ROW'], [Lang.Blocks.table_col, 'COL'], ], value: 'ROW', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, ], events: {}, pyHelpDef: { params: [ { type: 'text', params: ['D&value'], }, null, ], type: 'get_table_count', }, def: { params: [null, null], type: 'get_table_count', }, paramsKeyMap: { MATRIX: 0, PROPERTY: 1, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const property = script.getStringValue('PROPERTY', script); const table = DataTable.getSource(tableId, sprite); if (property === 'ROW') { const { array } = table; return array.length + 1; } else if (property === 'COL') { const labels = table.fields; return labels.length; } return 0; }, syntax: { js: [], py: [], }, }, // 테이블 %1 행 %2 속성 %3 의 값 get_value_from_table: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ null, { type: 'text', params: ['2'], }, { type: 'get_table_fields', }, ], type: 'get_value_from_table', }, paramsKeyMap: { MATRIX: 0, ROW: 1, COL: 2, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const row = script.getNumberValue('ROW', script) - 1; const col = DataTable.getColumnIndex(script.getValue('COL', script)); const table = DataTable.getSource(tableId, sprite); if (table.isExist([row, col])) { return table.getValue([row, col]); } return null; }, syntax: { js: [], py: [], }, }, get_value_from_last_row: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ null, { type: 'get_table_fields', }, ], type: 'get_value_from_last_row', }, paramsKeyMap: { MATRIX: 0, COL: 1, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const col = DataTable.getColumnIndex(script.getValue('COL', script)); const table = DataTable.getSource(tableId, sprite); const row = table && table.array.length; if (table.isExist([row, col])) { return table.getValue([row, col]); } return null; }, syntax: { js: [], py: [], }, }, // 테이블 %1 속성 %1의 합 calc_values_from_table: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Dropdown', options: [ [Lang.Blocks.table_sum, 'SUM'], [Lang.Blocks.table_max, 'MAX'], [Lang.Blocks.table_min, 'MIN'], [Lang.Blocks.table_avg, 'AVG'], [Lang.Blocks.table_stdev, 'STDEV'], [Lang.Blocks.table_median, 'MEDIAN'], ], value: 'SUM', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, ], events: {}, def: { params: [ null, { type: 'get_table_fields', }, null, ], type: 'calc_values_from_table', }, paramsKeyMap: { MATRIX: 0, COL: 1, CALC: 2, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const calc = script.getField('CALC', script); const col = DataTable.getColumnIndex(script.getValue('COL', script)); const table = DataTable.getSource(tableId, sprite); const array = table.array.map(({ value = [] }) => { const parsed = toNumber(value[col - 1]); return _isNumber(parsed) ? parsed : 0; }); const total = array.length; const sum = (x, y) => x + y; const square = (x) => x * x; if (!total) { return 0; } switch (calc) { case 'SUM': return array.reduce(sum); case 'MAX': return array.reduce((x, y) => Math.max(x, y)); case 'MIN': return array.reduce((x, y) => Math.min(x, y)); case 'AVG': return array.reduce(sum) / total; case 'STDEV': { const avg = array.reduce(sum) / total; const deviations = array.map((x) => x - avg); return Math.sqrt(deviations.map(square).reduce(sum) / (total - 1)); } case 'MEDIAN': { const sorted = array.sort((a, b) => a - b); const n = Math.floor(array.length / 2); return (sorted[n] + sorted[array.length - 1 - n]) / 2; } default: return 0; } }, syntax: { js: [], py: [], }, }, // 테이블 %1 창 열기 open_table: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/block_analysis.svg', size: 11, }, ], events: {}, def: { params: [null, null, null], type: 'open_table', }, pyHelpDef: { params: [ { type: 'text', params: ['A&value', 'B&value'], }, null, ], type: 'open_table', }, paramsKeyMap: { MATRIX: 0, CHART_INDEX: 1, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); DataTable.showTable(tableId); return script.callReturn(); }, syntax: { js: [], py: [], }, }, // 테이블 %1 창을 %2 초 동안 열기 open_table_wait: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/block_analysis.svg', size: 11, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['4'], }, null, ], type: 'open_table_wait', }, pyHelpDef: { params: [ { type: 'text', params: ['A&value', 'B&value'], }, { type: 'number', params: ['B&value'], }, null, ], type: 'open_table_wait', }, paramsKeyMap: { MATRIX: 0, SECOND: 1, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const timeValue = script.getNumberValue('SECOND', script); DataTable.showTable(tableId); Entry.engine.setTimeout(() => { DataTable.closeModal(); }, timeValue * 1000); return script.callReturn(); }, syntax: { js: [], py: [], }, }, // 테이블 %1 의 %2 차트 창 열기 open_table_chart: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'DropdownDynamic', value: null, menuName() { const value = this.getTargetValue('dataTables'); const source = DataTable.getSource(value); const { chart: charts = [] } = source || {}; return charts.map(({ title }, index) => [title, index]); }, needDeepCopy: true, fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, defaultValue: (value, options) => { if (options.length) { return options[0][1]; } return null; }, }, { type: 'Indicator', img: 'block_icon/block_analysis.svg', size: 11, }, ], events: {}, def: { params: [null, null, null], type: 'open_table_chart', }, pyHelpDef: { params: [ { type: 'text', params: ['A&value', 'B&value'], }, null, ], type: 'open_table_chart', }, paramsKeyMap: { MATRIX: 0, CHART_INDEX: 1, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const chartIndex = script.getField('CHART_INDEX', script); DataTable.showChart(tableId, chartIndex); return script.callReturn(); }, syntax: { js: [], py: [], }, }, close_table_chart: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/block_analysis.svg', size: 11, }, ], events: {}, def: { params: [null, null], type: 'close_table_chart', }, pyHelpDef: { params: [null], type: 'close_table_chart', }, paramsKeyMap: {}, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { DataTable.closeModal(); return script.callReturn(); }, syntax: { js: [], py: [], }, }, get_coefficient: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ null, { type: 'get_table_fields', }, { type: 'get_table_fields', }, ], type: 'get_coefficient', }, pyHelpDef: { params: [ { type: 'text', params: ['A&value'], }, { type: 'text', params: ['B&value'], }, { type: 'text', params: ['C&value'], }, null, ], type: 'get_coefficient', }, paramsKeyMap: { MATRIX: 0, FIELD1: 1, FIELD2: 2, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const x = DataTable.getColumnIndex(script.getValue('FIELD1', script)); const y = DataTable.getColumnIndex(script.getValue('FIELD2', script)); const table = DataTable.getSource(tableId, sprite); return table.getCoefficient(x - 1, y - 1); }, syntax: { js: [], py: [], }, }, set_value_from_cell: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/block_analysis.svg', size: 11, }, ], events: {}, def: { params: [ null, { type: 'text', params: ['A2'], }, { type: 'text', params: ['10'], }, null, ], type: 'set_value_from_cell', }, paramsKeyMap: { MATRIX: 0, CELL: 1, VALUE: 2, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const cell = script.getValue('CELL', script) || ''; const value = script.getValue('VALUE', script); const table = DataTable.getSource(tableId, sprite); const { col, row } = Entry.Utils.cellToRowCol(cell.toUpperCase()); if (table.isExist([row, col])) { table.replaceValue([row, col], value); } return script.callReturn(); }, syntax: { js: [], py: [], }, }, get_value_from_cell: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ null, { type: 'text', params: ['A2'], }, ], type: 'get_value_from_cell', }, paramsKeyMap: { MATRIX: 0, CELL: 1, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const cell = script.getValue('CELL', script) || ''; const { col, row } = Entry.Utils.cellToRowCol(cell.toUpperCase()); const table = DataTable.getSource(tableId, sprite); if (table.isExist([row, col])) { return table.getValue([row, col]); } return null; }, syntax: { js: [], py: [], }, }, get_value_v_lookup: { color: EntryStatic.colorSet.block.default.ANALYSIS, outerLine: EntryStatic.colorSet.block.darken.ANALYSIS, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'tables', dropdownSync: 'dataTables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.ANALYSIS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ null, { type: 'get_table_fields', }, { type: 'text', params: ['10'], }, { type: 'get_table_fields', }, ], type: 'get_value_v_lookup', }, paramsKeyMap: { MATRIX: 0, FIELD: 1, VALUE: 2, RETURN: 3, }, class: 'analysis', isNotFor: ['analysis'], func(sprite, script) { const tableId = script.getField('MATRIX', script); const col = DataTable.getColumnIndex(script.getValue('FIELD', script)); const returnCol = DataTable.getColumnIndex(script.getValue('RETURN', script)); const value = script.getValue('VALUE', script); const table = DataTable.getSource(tableId, sprite); let foundIndex; for (let i = 0; i < table?.table?.length || 0; i++) { if (table.getValue([i, col]) == value) { foundIndex = i; break; } } if (table.isExist([foundIndex, returnCol])) { return table.getValue([foundIndex, returnCol]); } return null; }, syntax: { js: [], py: [], }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_brush.js ================================================ module.exports = { getBlocks() { return { brush_stamp: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'brush_stamp', }, class: 'stamp', isNotFor: ['textBox'], func(sprite, script) { sprite.addStamp(); return script.callReturn(); }, syntax: { js: [], py: ['Entry.stamp()'] }, }, start_drawing: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'start_drawing', }, class: 'brush_control', isNotFor: ['textBox'], func(sprite, script) { if (sprite.brush) { sprite.brush.stop = false; } else { Entry.setBasicBrush(sprite); } sprite.brush.moveTo(sprite.getX(), sprite.getY() * -1); return script.callReturn(); }, syntax: { js: [], py: ['Entry.start_drawing()'] }, }, stop_drawing: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'stop_drawing', }, class: 'brush_control', isNotFor: ['textBox'], func(sprite, script) { if (sprite.brush) { sprite.brush.stop = true; } return script.callReturn(); }, syntax: { js: [], py: ['Entry.stop_drawing()'] }, }, start_fill: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'start_fill', }, class: 'fill_control', isNotFor: ['textBox'], func(sprite, script) { if (sprite.paint) { sprite.paint.stop = false; const rgb = sprite.paint.rgb; sprite.paint.beginFill( `rgba(${rgb.r},${rgb.g},${rgb.b},${1 - sprite.paint.opacity / 100})` ); } else { Entry.setBasicPaint(sprite); } sprite.paint.moveTo(sprite.getX(), sprite.getY() * -1); return script.callReturn(); }, }, stop_fill: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'stop_fill', }, class: 'fill_control', isNotFor: ['textBox'], func(sprite, script) { if (sprite.paint) { sprite.paint.endFill(); sprite.paint.stop = true; } return script.callReturn(); }, }, set_color: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'color', }, null, ], type: 'set_color', }, pyHelpDef: { params: ['A&value'], type: 'set_color', }, paramsKeyMap: { VALUE: 0, }, class: 'brush_control', isNotFor: ['textBox'], func(sprite, script) { const colour = script.getStringValue('VALUE', script); if (!sprite.brush || !sprite.shapes.length) { Entry.setBasicBrush(sprite); sprite.brush.stop = true; } if (sprite.brush) { const rgb = Entry.hex2rgb(colour); sprite.brush.rgb = rgb; sprite.brush.endStroke(); sprite.brush.beginStroke( `rgba(${rgb.r},${rgb.g},${rgb.b},${1 - sprite.brush.opacity / 100})` ); sprite.brush.moveTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.set_brush_color_to(%1)', textParams: [ { type: 'Color', converter: Entry.block.converters.returnStringValueUpperCase, codeMap: 'Entry.CodeMap.Entry.set_color[0]', }, ], }, ], }, }, set_random_color: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'set_random_color', }, class: 'brush_color', isNotFor: ['textBox'], func(sprite, script) { if (!sprite.brush || !sprite.shapes.length) { Entry.setBasicBrush(sprite); sprite.brush.stop = true; } if (sprite.brush) { const rgb = Entry.generateRgb(); sprite.brush.rgb = rgb; sprite.brush.endStroke(); sprite.brush.beginStroke( `rgba(${rgb.r},${rgb.g},${rgb.b},${1 - sprite.brush.opacity / 100})` ); sprite.brush.moveTo(sprite.getX(), sprite.getY() * -1); } if (!sprite.paint || !sprite.paintShapes.length) { Entry.setBasicPaint(sprite); sprite.paint.stop = true; } if (sprite.paint) { const rgb = Entry.generateRgb(); sprite.paint.rgb = rgb; sprite.paint.endFill(); sprite.paint.beginFill( `rgba(${rgb.r},${rgb.g},${rgb.b},${1 - sprite.paint.opacity / 100})` ); sprite.paint.moveTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.set_brush_color_to_random()'] }, }, set_fill_color: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'color', }, null, ], type: 'set_fill_color', }, paramsKeyMap: { VALUE: 0, }, class: 'fill_control', isNotFor: ['textBox'], func(sprite, script) { const colour = script.getStringValue('VALUE', script); if (!sprite.paint || !sprite.paintShapes.length) { Entry.setBasicPaint(sprite); sprite.paint.stop = true; } if (sprite.paint) { const rgb = Entry.hex2rgb(colour); sprite.paint.rgb = rgb; sprite.paint.endFill(); sprite.paint.beginFill( `rgba(${rgb.r},${rgb.g},${rgb.b},${1 - sprite.paint.opacity / 100})` ); sprite.paint.moveTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, }, change_thickness: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['1'], }, null, ], type: 'change_thickness', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'change_thickness', }, paramsKeyMap: { VALUE: 0, }, class: 'brush_control', isNotFor: ['textBox'], func(sprite, script) { const thickness = script.getNumberValue('VALUE', script); if (!sprite.brush || !sprite.shapes.length) { Entry.setBasicBrush(sprite); sprite.brush.stop = true; } if (sprite.brush) { sprite.brush.thickness += thickness; if (sprite.brush.thickness < 1) { sprite.brush.thickness = 1; } sprite.brush.setStrokeStyle(sprite.brush.thickness); sprite.brush.moveTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.add_brush_size(%1)'] }, }, set_thickness: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['1'], }, null, ], type: 'set_thickness', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'set_thickness', }, paramsKeyMap: { VALUE: 0, }, class: 'brush_control', isNotFor: ['textBox'], func(sprite, script) { const thickness = script.getNumberValue('VALUE', script); if (!sprite.brush || !sprite.shapes.length) { Entry.setBasicBrush(sprite); sprite.brush.stop = true; } if (sprite.brush) { sprite.brush.thickness = thickness; sprite.brush.setStrokeStyle(sprite.brush.thickness); sprite.brush.moveTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.set_brush_size(%1)'] }, }, change_brush_transparency: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, ], type: 'change_brush_transparency', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'change_brush_transparency', }, paramsKeyMap: { VALUE: 0, }, class: 'brush_color', isNotFor: ['textBox'], func(sprite, script) { const opacity = script.getNumberValue('VALUE', script); if (!sprite.brush || !sprite.shapes.length) { Entry.setBasicBrush(sprite); sprite.brush.stop = true; } if (!sprite.paint || !sprite.paintShapes.length) { Entry.setBasicPaint(sprite); sprite.paint.stop = true; } if (sprite.brush) { const newOpacity = Entry.adjustValueWithMaxMin( sprite.brush.opacity + opacity, 0, 100 ); sprite.brush.opacity = newOpacity; sprite.brush.endStroke(); const rgb = sprite.brush.rgb; sprite.brush.beginStroke( `rgba(${rgb.r},${rgb.g},${rgb.b},${1 - sprite.brush.opacity / 100})` ); sprite.brush.moveTo(sprite.getX(), sprite.getY() * -1); } if (sprite.paint) { const newOpacity = Entry.adjustValueWithMaxMin( sprite.paint.opacity + opacity, 0, 100 ); sprite.paint.opacity = newOpacity; sprite.paint.endFill(); const rgb = sprite.paint.rgb; sprite.paint.beginFill( `rgba(${rgb.r},${rgb.g},${rgb.b},${1 - sprite.paint.opacity / 100})` ); sprite.paint.moveTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.add_brush_transparency(%1)'] }, }, set_brush_tranparency: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['50'], }, null, ], type: 'set_brush_tranparency', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'set_brush_tranparency', }, paramsKeyMap: { VALUE: 0, }, class: 'brush_color', isNotFor: ['textBox'], func(sprite, script) { const opacityValue = script.getNumberValue('VALUE', script); if (!sprite.brush || !sprite.shapes.length) { Entry.setBasicBrush(sprite); sprite.brush.stop = true; } const opacity = Entry.adjustValueWithMaxMin(opacityValue, 0, 100); if (sprite.brush) { sprite.brush.opacity = opacity; sprite.brush.endStroke(); const rgb = sprite.brush.rgb; sprite.brush.beginStroke( `rgba(${rgb.r},${rgb.g},${rgb.b},${1 - sprite.brush.opacity / 100})` ); sprite.brush.moveTo(sprite.getX(), sprite.getY() * -1); } if (!sprite.paint || !sprite.paintShapes.length) { Entry.setBasicPaint(sprite); sprite.paint.stop = true; } if (sprite.paint) { sprite.paint.opacity = opacity; sprite.paint.endFill(); const rgb = sprite.paint.rgb; sprite.paint.beginFill( `rgba(${rgb.r},${rgb.g},${rgb.b},${1 - sprite.paint.opacity / 100})` ); sprite.paint.moveTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.set_brush_transparency(%1)'] }, }, brush_erase_all: { color: EntryStatic.colorSet.block.default.BRUSH, outerLine: EntryStatic.colorSet.block.darken.BRUSH, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/brush_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'brush_erase_all', }, class: 'brush_clear', isNotFor: ['textBox'], func(sprite, script) { sprite.eraseBrush && sprite.eraseBrush(); sprite.erasePaint && sprite.erasePaint(); sprite.removeStamps(); return script.callReturn(); }, syntax: { js: [], py: ['Entry.clear_drawing()'] }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_calc.js ================================================ import _get from 'lodash/get'; const calcOperationOptions = EntryStatic.isPracticalCourse ? [ [Lang.Blocks.CALC_calc_operation_unnatural, 'unnatural'], [Lang.Blocks.CALC_calc_operation_floor, 'floor'], [Lang.Blocks.CALC_calc_operation_ceil, 'ceil'], [Lang.Blocks.CALC_calc_operation_round, 'round'], ] : [ [Lang.Blocks.CALC_calc_operation_square, 'square'], [Lang.Blocks.CALC_calc_operation_root, 'root'], [Lang.Blocks.CALC_calc_operation_sin, 'sin'], [Lang.Blocks.CALC_calc_operation_cos, 'cos'], [Lang.Blocks.CALC_calc_operation_tan, 'tan'], [Lang.Blocks.CALC_calc_operation_asin, 'asin_radian'], [Lang.Blocks.CALC_calc_operation_acos, 'acos_radian'], [Lang.Blocks.CALC_calc_operation_atan, 'atan_radian'], [Lang.Blocks.CALC_calc_operation_log, 'log'], [Lang.Blocks.CALC_calc_operation_ln, 'ln'], [Lang.Blocks.CALC_calc_operation_unnatural, 'unnatural'], [Lang.Blocks.CALC_calc_operation_floor, 'floor'], [Lang.Blocks.CALC_calc_operation_ceil, 'ceil'], [Lang.Blocks.CALC_calc_operation_round, 'round'], [Lang.Blocks.CALC_calc_operation_factorial, 'factorial'], [Lang.Blocks.CALC_calc_operation_abs, 'abs'], ]; module.exports = { getBlocks() { return { calc_basic: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Dropdown', options: [ ['+', 'PLUS'], ['-', 'MINUS'], ['x', 'MULTI'], ['/', 'DIVIDE'], ], value: 'PLUS', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.CALC, noArrow: true, }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, 'PLUS', { type: 'number', params: ['10'], }, ], type: 'calc_basic', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, 'PLUS', { type: 'number', params: ['B&value'], }, ], type: 'calc_basic', }, defs: [ { params: [ { type: 'number', params: ['10'], }, 'PLUS', { type: 'number', params: ['10'], }, ], type: 'calc_basic', }, { params: [ { type: 'number', params: ['10'], }, 'MINUS', { type: 'number', params: ['10'], }, ], type: 'calc_basic', }, { params: [ { type: 'number', params: ['10'], }, 'MULTI', { type: 'number', params: ['10'], }, ], type: 'calc_basic', }, { params: [ { type: 'number', params: ['10'], }, 'DIVIDE', { type: 'number', params: ['10'], }, ], type: 'calc_basic', }, ], paramsKeyMap: { LEFTHAND: 0, OPERATOR: 1, RIGHTHAND: 2, }, class: 'calc', isNotFor: [], func(sprite, script) { const operator = script.getField('OPERATOR', script); let leftValue = script.getNumberValue('LEFTHAND', script); let rightValue = script.getNumberValue('RIGHTHAND', script); if (operator === 'PLUS') { const leftStringValue = script.getValue('LEFTHAND', script); const rightStringValue = script.getValue('RIGHTHAND', script); if (!Entry.Utils.isNumber(leftStringValue)) { leftValue = leftStringValue; } if (!Entry.Utils.isNumber(rightStringValue)) { rightValue = rightStringValue; } if (typeof leftValue === 'number' && typeof rightValue === 'number') { return new BigNumber(leftValue).plus(rightValue).toNumber(); } else { return leftValue + rightValue; } } // below statements assume both arguments are number leftValue = new BigNumber(leftValue); rightValue = new BigNumber(rightValue); if (operator === 'MINUS') { return leftValue.minus(rightValue).toNumber(); } else if (operator === 'MULTI') { return leftValue.times(rightValue).toNumber(); } else { return leftValue.dividedBy(rightValue).toNumber(); } }, syntax: { js: [], py: [ { syntax: '(%1 %2 %3)', template: '%1 %2 %3', keyOption: 'calc_basic', blockType: 'param', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Dropdown', options: [ ['+', 'PLUS'], ['-', 'MINUS'], ['x', 'MULTI'], ['/', 'DIVIDE'], ], value: 'PLUS', fontSize: 11, noArrow: true, converter: Entry.block.converters.returnOperator, paramType: 'operator', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, calc_rand: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_calc_rand_1, color: '#FFF', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Text', text: Lang.Blocks.CALC_calc_rand_2, color: '#FFF', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Text', text: Lang.Blocks.CALC_calc_rand_3, color: '#FFF', }, ], events: {}, def: { params: [ null, { type: 'number', params: ['0'], }, null, { type: 'number', params: ['10'], }, null, ], type: 'calc_rand', }, pyHelpDef: { params: [ null, { type: 'number', params: ['A&value'], }, null, { type: 'number', params: ['B&value'], }, null, ], type: 'calc_rand', }, paramsKeyMap: { LEFTHAND: 1, RIGHTHAND: 3, }, class: 'calc', isNotFor: [], func(sprite, script) { const leftValue = script.getStringValue('LEFTHAND', script); const rightValue = script.getStringValue('RIGHTHAND', script); const left = Math.min(leftValue, rightValue); const right = Math.max(leftValue, rightValue); const isLeftFloat = Entry.isFloat(leftValue); const isRightFloat = Entry.isFloat(rightValue); if (isRightFloat || isLeftFloat) { return (Math.random() * (right - left) + left).toFixed(2); } else { return Math.floor(Math.random() * (right - left + 1) + left); } }, syntax: { js: [], py: [ { syntax: 'random.randint(%2, %4)', blockType: 'param', textParams: [ null, { type: 'Block', accept: 'string', paramType: 'integer', }, null, { type: 'Block', accept: 'string', paramType: 'integer', }, null, ], }, { syntax: 'random.uniform(%2, %4)', blockType: 'param', textParams: [ null, { type: 'Block', accept: 'string', paramType: 'float', }, null, { type: 'Block', accept: 'string', paramType: 'float', }, null, ], }, ], }, }, coordinate_mouse: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_coordinate_mouse_1, color: '#FFF', }, { type: 'Dropdown', options: [ ['x', 'x'], ['y', 'y'], ], value: 'x', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.CALC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.CALC_coordinate_mouse_2, color: '#FFF', }, ], events: {}, def: { params: [null, null, null], type: 'coordinate_mouse', }, pyHelpDef: { params: [null, 'A&value', null], type: 'coordinate_mouse', }, paramsKeyMap: { VALUE: 1, }, class: 'calc', isNotFor: [], func(sprite, script) { const targetCoordinate = script.getField('VALUE', script); if (targetCoordinate === 'x') { return Number(Entry.stage.mouseCoordinate.x); } else { return Number(Entry.stage.mouseCoordinate.y); } }, syntax: { js: [], py: [ { syntax: 'Entry.value_of_mouse_pointer(%2)', blockType: 'param', textParams: [ { type: 'Text', text: Lang.Blocks.CALC_coordinate_mouse_1, color: '#FFF', }, { type: 'Dropdown', options: [ ['x', 'x'], ['y', 'y'], ], value: 'x', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.CALC, converter: Entry.block.converters.returnStringKey, codeMap: 'Entry.CodeMap.Entry.coordinate_mouse[1]', }, { type: 'Text', text: Lang.Blocks.CALC_coordinate_mouse_2, color: '#FFF', }, ], }, ], }, }, coordinate_object: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_coordinate_object_1, color: '#FFF', }, { type: 'DropdownDynamic', value: null, menuName: 'spritesWithSelf', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.CALC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.CALC_coordinate_object_2, color: '#FFF', }, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_coordinate_x_value, 'x'], [Lang.Blocks.CALC_coordinate_y_value, 'y'], [Lang.Blocks.CALC_coordinate_rotation_value, 'rotation'], [Lang.Blocks.CALC_coordinate_direction_value, 'direction'], [Lang.Blocks.CALC_coordinate_size_value, 'size'], [Lang.Blocks.CALC_picture_index, 'picture_index'], [Lang.Blocks.CALC_picture_name, 'picture_name'], ], value: 'x', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.CALC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, ], events: {}, def: { params: [null, null, null, null], type: 'coordinate_object', }, pyHelpDef: { params: [null, 'A&value', null, 'B&value'], type: 'coordinate_object', }, paramsKeyMap: { VALUE: 1, COORDINATE: 3, }, class: 'calc', isNotFor: [], func(sprite, script) { const targetId = script.getField('VALUE', script); let targetEntity; if (targetId === 'self') { targetEntity = sprite; } else { targetEntity = Entry.container.getEntity(targetId); } const targetCoordinate = script.getField('COORDINATE', script); switch (targetCoordinate) { case 'x': return targetEntity.getX(); case 'y': return targetEntity.getY(); case 'rotation': return targetEntity.getRotation(); case 'direction': return targetEntity.getDirection(); case 'picture_index': { const object = targetEntity.parent; const pictures = object.pictures; return pictures.indexOf(targetEntity.picture) + 1; } case 'size': return Number(targetEntity.getSize().toFixed(1)); case 'picture_name': { const object = targetEntity.parent; const pictures = object.pictures; const picture = pictures[pictures.indexOf(targetEntity.picture)]; return picture.name; } } }, syntax: { js: [], py: [ { syntax: 'Entry.value_of_object(%2, %4)', blockType: 'param', textParams: [ undefined, { type: 'DropdownDynamic', value: null, menuName: 'spritesWithSelf', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.CALC, converter: Entry.block.converters.returnObjectOrStringValue, codeMap: 'Entry.CodeMap.Entry.coordinate_object[1]', }, undefined, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_coordinate_x_value, 'x'], [Lang.Blocks.CALC_coordinate_y_value, 'y'], [Lang.Blocks.CALC_coordinate_rotation_value, 'rotation'], [Lang.Blocks.CALC_coordinate_direction_value, 'direction'], [Lang.Blocks.CALC_coordinate_size_value, 'size'], [Lang.Blocks.CALC_picture_index, 'picture_index'], [Lang.Blocks.CALC_picture_name, 'picture_name'], ], value: 'x', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.CALC, converter: Entry.block.converters.returnStringValue, codeMap: 'Entry.CodeMap.Entry.coordinate_object[3]', }, ], }, ], }, }, quotient_and_mod: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_quotient_and_mod_1, color: '#FFF', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Text', text: Lang.Blocks.CALC_quotient_and_mod_2, color: '#FFF', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Text', text: Lang.Blocks.CALC_quotient_and_mod_3, color: '#FFF', }, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_quotient_and_mod_sub_1, 'QUOTIENT'], [Lang.Blocks.CALC_quotient_and_mod_sub_2, 'MOD'], ], value: 'QUOTIENT', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.CALC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, ], events: {}, def: { params: [ null, { type: 'text', params: ['10'], }, null, { type: 'text', params: ['10'], }, null, null, ], type: 'quotient_and_mod', }, pyHelpDef: { params: [ null, { type: 'text', params: ['A&value'], }, null, { type: 'text', params: ['B&value'], }, null, null, ], type: 'quotient_and_mod', }, paramsKeyMap: { LEFTHAND: 1, RIGHTHAND: 3, OPERATOR: 5, }, class: 'calc', isNotFor: [], func(sprite, script) { const left = script.getNumberValue('LEFTHAND', script); const right = script.getNumberValue('RIGHTHAND', script); const operator = script.getField('OPERATOR', script); if (operator === 'QUOTIENT') { return Math.floor(left / right); } else { return left - right * Math.floor(left / right); } }, syntax: { js: [], py: [ { syntax: '(%2 %6 %4)', template: '%2 %6 %4', blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, { type: 'Block', accept: 'string', }, undefined, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_quotient_and_mod_sub_1, 'QUOTIENT'], [Lang.Blocks.CALC_quotient_and_mod_sub_2, 'MOD'], ], value: 'QUOTIENT', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.CALC, converter: Entry.block.converters.returnOperator, }, ], }, ], }, }, calc_operation: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_calc_operation_of_1, color: '#FFF', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Text', text: Lang.Blocks.CALC_calc_operation_of_2, color: '#FFF', }, { type: 'Dropdown', options: calcOperationOptions, value: EntryStatic.isPracticalCourse ? 'unnatural' : 'square', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.CALC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['10'], }, null, null, ], type: 'calc_operation', }, pyHelpDef: { params: [ null, { type: 'number', params: ['A&value'], }, null, null, ], type: 'calc_operation', }, paramsKeyMap: { LEFTHAND: 1, VALUE: 3, }, class: 'calc', isNotFor: [], func(sprite, script) { const value = script.getNumberValue('LEFTHAND', script); let operator = script.getField('VALUE', script); const xRangeCheckList = ['asin_radian', 'acos_radian']; if (xRangeCheckList.indexOf(operator) > -1 && (value > 1 || value < -1)) { throw new Error('x range exceeded'); } if (!calcOperationOptions.some((option) => option[1] === operator)) { operator = 'round'; } if (operator.indexOf('_')) { operator = operator.split('_')[0]; } let returnVal = 0; switch (operator) { case 'square': returnVal = value * value; break; case 'factorial': returnVal = Entry.factorial(value); break; case 'root': returnVal = Math.sqrt(value); break; case 'log': returnVal = Math.log(value) / Math.LN10; break; case 'ln': returnVal = Math.log(value); break; case 'asin': case 'acos': case 'atan': returnVal = Entry.toDegrees(Math[operator](value)); break; case 'sin': case 'cos': case 'tan': returnVal = Entry.preciseTrig(value, operator); break; case 'unnatural': { returnVal = new BigNumber(value).minus(Math.floor(value)); returnVal = returnVal.toNumber(); if (value < 0 && returnVal !== 0) { returnVal = 1 - returnVal; } break; } default: returnVal = Math[operator](value); } return returnVal; }, syntax: { js: [], py: [ { syntax: '(%2 ** 2)', template: '%2 ** 2', params: [null, null, null, 'square'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { // for square syntax: 'math.pow(%2)', params: [null, null, null, 'square'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.sqrt(%2)', params: [null, null, null, 'root'], blockType: 'param', textParams: [ undefined, { type: 'Block', isListIndex: true, accept: 'string', }, undefined, null, ], }, { syntax: 'math.sin(%2)', params: [null, null, null, 'sin'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.cos(%2)', params: [null, null, null, 'cos'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.tan(%2)', params: [null, null, null, 'tan'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.asin(%2)', params: [null, null, null, 'asin_radian'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.acos(%2)', params: [null, null, null, 'acos_radian'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.atan(%2)', params: [null, null, null, 'atan_radian'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.log10(%2)', params: [null, null, null, 'log'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.log(%2)', params: [null, null, null, 'ln'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: '%2 - math.floor(%2)', params: [null, null, null, 'unnatural'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.floor(%2)', params: [null, null, null, 'floor'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.ceil(%2)', params: [null, null, null, 'ceil'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.round(%2)', params: [null, null, null, 'round'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.factorial(%2)', params: [null, null, null, 'factorial'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, { syntax: 'math.fabs(%2)', params: [null, null, null, 'abs'], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, null, ], }, ], }, }, get_project_timer_value: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_get_timer_value, color: '#FFF', }, ], events: { viewAdd: [ function () { if (Entry.engine) { Entry.engine.showProjectTimer(); } }, ], viewDestroy: [ function (block, notIncludeSelf) { if (Entry.engine) { Entry.engine.hideProjectTimer(block, notIncludeSelf); } }, ], }, def: { params: [null, null], type: 'get_project_timer_value', }, class: 'calc_timer', isNotFor: [], func() { return Entry.engine.projectTimer.getValue(); }, syntax: { js: [], py: [ { syntax: 'Entry.value_of_timer()', blockType: 'param', }, ], }, }, choose_project_timer_action: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_choose_project_timer_action_1, color: '#FFF', }, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_choose_project_timer_action_sub_1, 'START'], [Lang.Blocks.CALC_choose_project_timer_action_sub_2, 'STOP'], [Lang.Blocks.CALC_choose_project_timer_action_sub_3, 'RESET'], ], value: 'START', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.CALC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.CALC_choose_project_timer_action_2, color: '#FFF', }, { type: 'Indicator', img: 'block_icon/calc_icon.svg', size: 11, }, ], events: { viewAdd: [ function () { if (Entry.engine) { Entry.engine.showProjectTimer(); } }, ], dataDestroy: [ function (block) { if (Entry.engine) { Entry.engine.hideProjectTimer(block); } }, ], }, def: { params: [null, 'START', null, null], type: 'choose_project_timer_action', }, pyHelpDef: { params: [null, 'A&value', null, null], type: 'choose_project_timer_action', }, paramsKeyMap: { ACTION: 1, }, class: 'calc_timer', isNotFor: [], func(sprite, script) { const engine = Entry.engine; const timer = engine.projectTimer; const isPaused = timer.isPaused; const isInit = timer.isInit; const currentTime = new Date().getTime(); switch (script.getField('ACTION')) { case 'START': if (!isInit) { engine.startProjectTimer(); } else if (isInit && isPaused) { if (timer.pauseStart) { timer.pausedTime += currentTime - timer.pauseStart; } delete timer.pauseStart; timer.isPaused = false; } break; case 'STOP': if (isInit && !isPaused) { timer.isPaused = true; timer.pauseStart = currentTime; } break; case 'RESET': engine.resetTimer(); break; } return script.callReturn(); }, syntax: { js: [], py: [ { template: '%1 %2 %3', syntax: 'Entry.timer(%2)', textParams: [ { type: 'Text', text: 'Entry.timer(', color: EntryStatic.colorSet.common.WHITE, }, { type: 'Dropdown', options: [ [ Lang.Blocks.CALC_choose_project_timer_action_sub_1, 'START', ], [ Lang.Blocks.CALC_choose_project_timer_action_sub_2, 'STOP', ], [ Lang.Blocks.CALC_choose_project_timer_action_sub_3, 'RESET', ], ], value: 'START', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.CALC, converter: Entry.block.converters.returnStringValueLowerCase, codeMap: 'Entry.CodeMap.Entry.choose_project_timer_action[1]', }, { type: 'Text', text: ')', color: EntryStatic.colorSet.common.WHITE, }, ], }, ], }, }, set_visible_project_timer: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_timer_visible_1, color: '#FFF', }, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_timer_visible_show, 'SHOW'], [Lang.Blocks.CALC_timer_visible_hide, 'HIDE'], ], value: 'SHOW', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.CALC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.CALC_choose_project_timer_action_2, color: '#FFF', }, { type: 'Indicator', img: 'block_icon/calc_icon.svg', size: 11, }, ], events: { viewAdd: [ function () { if (Entry.engine) { Entry.engine.showProjectTimer(); } }, ], viewDestroy: [ function (block, notIncludeSelf) { if (Entry.engine) { Entry.engine.hideProjectTimer(block, notIncludeSelf); } }, ], }, def: { params: [null, 'HIDE', null, null], type: 'set_visible_project_timer', }, pyHelpDef: { params: [null, 'A&value', null, null], type: 'set_visible_project_timer', }, paramsKeyMap: { ACTION: 1, }, class: 'calc_timer', isNotFor: [], func(sprite, script) { const action = script.getField('ACTION'); const timer = Entry.engine.projectTimer; if (action === 'SHOW') { timer.setVisible(true); } else { timer.setVisible(false); } return script.callReturn(); }, syntax: { js: [], py: [ { template: '%1 %2 %3', syntax: 'Entry.timer_view(%2)', textParams: [ { type: 'Text', text: 'Entry.timer_view(', color: EntryStatic.colorSet.common.WHITE, }, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_timer_visible_show, 'SHOW'], [Lang.Blocks.CALC_timer_visible_hide, 'HIDE'], ], value: 'SHOW', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.CALC, converter: Entry.block.converters.returnStringValueLowerCase, codeMap: 'Entry.CodeMap.Entry.set_visible_project_timer[1]', }, { type: 'Text', text: ')', color: EntryStatic.colorSet.common.WHITE, }, ], }, ], }, }, get_date: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_get_date_1, color: '#FFF', }, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_get_date_year, 'YEAR'], [Lang.Blocks.CALC_get_date_month, 'MONTH'], [Lang.Blocks.CALC_get_date_day, 'DAY'], [Lang.Blocks.CALC_get_date_day_of_week, 'DAY_OF_WEEK'], [Lang.Blocks.CALC_get_date_hour, 'HOUR'], [Lang.Blocks.CALC_get_date_minute, 'MINUTE'], [Lang.Blocks.CALC_get_date_second, 'SECOND'], ], value: 'YEAR', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.CALC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.CALC_get_date_2, color: '#FFF', }, ], events: {}, def: { params: [null, 'YEAR', null], type: 'get_date', }, pyHelpDef: { params: [null, 'A&value', null], type: 'get_date', }, paramsKeyMap: { VALUE: 1, }, class: 'calc_date', isNotFor: [], func(sprite, script) { const operator = script.getField('VALUE', script); const dateTime = new Date(); if (operator === 'YEAR') { return dateTime.getFullYear(); } else if (operator === 'MONTH') { return dateTime.getMonth() + 1; } else if (operator === 'DAY') { return dateTime.getDate(); } else if (operator === 'HOUR') { return dateTime.getHours(); } else if (operator === 'MINUTE') { return dateTime.getMinutes(); } else if (operator === 'DAY_OF_WEEK') { return dateTime.getDay(); } else { return dateTime.getSeconds(); } }, syntax: { js: [], py: [ { syntax: 'Entry.value_of_current_time(%2)', blockType: 'param', textParams: [ undefined, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_get_date_year, 'YEAR'], [Lang.Blocks.CALC_get_date_month, 'MONTH'], [Lang.Blocks.CALC_get_date_day, 'DAY'], [Lang.Blocks.CALC_get_date_hour, 'HOUR'], [Lang.Blocks.CALC_get_date_minute, 'MINUTE'], [Lang.Blocks.CALC_get_date_second, 'SECOND'], [Lang.Blocks.CALC_get_date_day_of_week, 'DAY_OF_WEEK'], ], value: 'YEAR', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.CALC, converter: Entry.block.converters.returnStringValueLowerCase, codeMap: 'Entry.CodeMap.Entry.get_date[1]', }, ], }, ], }, }, distance_something: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_distance_something_1, color: '#FFF', }, { type: 'DropdownDynamic', value: null, menuName: 'spritesWithMouse', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.CALC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.CALC_distance_something_2, color: '#FFF', }, ], events: {}, def: { params: [null, null, null], type: 'distance_something', }, pyHelpDef: { params: [null, 'A&value', null], type: 'distance_something', }, paramsKeyMap: { VALUE: 1, }, class: 'calc_distance', isNotFor: [], func(sprite, script) { const targetId = script.getField('VALUE', script); if (targetId === 'mouse') { const mousePos = Entry.stage.mouseCoordinate; return Math.sqrt( Math.pow(sprite.getX() - mousePos.x, 2) + Math.pow(sprite.getY() - mousePos.y, 2) ); } else { const targetEntity = Entry.container.getEntity(targetId); return Math.sqrt( Math.pow(sprite.getX() - targetEntity.getX(), 2) + Math.pow(sprite.getY() - targetEntity.getY(), 2) ); } }, syntax: { js: [], py: [ { syntax: 'Entry.value_of_distance_to(%2)', blockType: 'param', textParams: [ undefined, { type: 'DropdownDynamic', value: null, menuName: 'spritesWithMouse', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.CALC, converter: Entry.block.converters.returnStringKey, codeMap: 'Entry.CodeMap.Entry.distance_something[1]', }, ], }, ], }, }, get_user_name: { color: EntryStatic.colorSet.block.default.CALC, fontColor: '#FFF', outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [], events: {}, def: { params: [], type: 'get_user_name', }, class: 'calc_user', isNotFor: [], func() { return window.user ? window.user.username : ' '; }, syntax: { js: [], py: [ { syntax: 'Entry.value_of_username()', blockType: 'param', }, ], }, }, get_nickname: { color: EntryStatic.colorSet.block.default.CALC, fontColor: '#FFF', outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [], events: {}, def: { params: [], type: 'get_nickname', }, class: 'calc_user', isNotFor: [], func() { return window.user ? window.user.nickname : ' '; }, syntax: { js: [], py: [ { syntax: 'Entry.value_of_nickname()', blockType: 'param', }, ], }, }, length_of_string: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_length_of_string_1, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_length_of_string_2, color: '#FFF', }, ], events: {}, def: { params: [ null, { type: 'text', params: [Lang.Blocks.entry], }, null, ], type: 'length_of_string', }, pyHelpDef: { params: [ null, { type: 'text', params: ['A&value'], }, null, ], type: 'length_of_string', }, paramsKeyMap: { STRING: 1, }, class: 'calc_string', isNotFor: [], func(sprite, script) { return script.getStringValue('STRING', script).length; }, syntax: { js: [], py: [ { syntax: 'len(%2)', blockType: 'param', keyOption: 'length_of_string', }, ], }, }, reverse_of_string: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_reverse_of_string_1, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_reverse_of_string_2, color: '#FFF', }, ], events: {}, def: { params: [ null, { type: 'text', params: [Lang.Blocks.entry], }, null, ], type: 'reverse_of_string', }, paramsKeyMap: { STRING: 1, }, class: 'calc_string', isNotFor: ['python_disable'], func(sprite, script) { const originStr = script.getStringValue('STRING', script); const reversedStr = originStr.split('').reverse().join(''); return reversedStr; }, syntax: { js: [], py: [], }, }, combine_something: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.VARIABLE_combine_something_1, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.VARIABLE_combine_something_2, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.VARIABLE_combine_something_3, color: '#FFF', }, ], events: {}, def: { params: [ null, { type: 'text', params: [Lang.Blocks.block_hi], }, null, { type: 'text', params: [Lang.Blocks.entry], }, null, ], type: 'combine_something', }, pyHelpDef: { params: [ null, { type: 'text', params: ['A&value'], }, null, { type: 'text', params: ['B&value'], }, null, ], type: 'combine_something', }, paramsKeyMap: { VALUE1: 1, VALUE2: 3, }, class: 'calc_string', isNotFor: [], func(sprite, script) { const leftValue = script.getStringValue('VALUE1', script); const rightValue = script.getStringValue('VALUE2', script); return `${leftValue}${rightValue}`; }, syntax: { js: [], py: [ { syntax: '(%2 + %4)', template: '%2 + %4', blockType: 'param', }, ], }, }, char_at: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_char_at_1, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_char_at_2, color: '#FFF', }, { type: 'Block', isListIndex: true, accept: 'string', defaultType: 'number', }, { type: 'Text', text: Lang.Blocks.CALC_char_at_3, color: '#FFF', }, ], events: {}, def: { params: [ null, { type: 'text', params: [Lang.Blocks.hi_entry], }, null, { type: 'number', params: ['1'], }, null, ], type: 'char_at', }, pyHelpDef: { params: [ null, { type: 'text', params: ['A&value'], }, null, { type: 'number', params: ['B&value'], }, null, ], type: 'char_at', }, paramsKeyMap: { LEFTHAND: 1, RIGHTHAND: 3, }, class: 'calc_string', isNotFor: [], func(sprite, script) { const str = script.getStringValue('LEFTHAND', script); const index = script.getNumberValue('RIGHTHAND', script) - 1; if (index < 0 || index > str.length - 1) { throw new Error(); } else { return str[index]; } }, syntax: { js: [], py: [ { syntax: '%2[%4]', blockType: 'param', textParams: [ { type: 'Text', text: Lang.Blocks.CALC_char_at_1, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_char_at_2, color: '#FFF', }, { type: 'Block', accept: 'string', paramType: 'index', }, { type: 'Text', text: Lang.Blocks.CALC_char_at_3, color: '#FFF', }, ], keyOption: 'char_at', }, ], }, }, substring: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_substring_1, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_substring_2, color: '#FFF', }, { type: 'Block', isListIndex: true, accept: 'string', defaultType: 'number', }, { type: 'Text', text: Lang.Blocks.CALC_substring_3, color: '#FFF', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Text', text: Lang.Blocks.CALC_substring_4, color: '#FFF', }, ], events: {}, def: { params: [ null, { type: 'text', params: [Lang.Blocks.hi_entry], }, null, { type: 'number', params: ['2'], }, null, { type: 'number', params: ['5'], }, null, ], type: 'substring', }, pyHelpDef: { params: [ null, { type: 'text', params: ['A&value'], }, null, { type: 'number', params: ['B&value'], }, null, { type: 'number', params: ['C&value'], }, null, ], type: 'substring', }, paramsKeyMap: { STRING: 1, START: 3, END: 5, }, class: 'calc_string', isNotFor: [], func(sprite, script) { const str = script.getStringValue('STRING', script); const start = script.getNumberValue('START', script) - 1; const end = script.getNumberValue('END', script) - 1; const strLen = str.length - 1; if (start < 0 || end < 0 || start > strLen || end > strLen) { throw new Error(); } else { return str.substring(Math.min(start, end), Math.max(start, end) + 1); } }, syntax: { js: [], py: [ { syntax: '%2[%4:%6]', blockType: 'param', textParams: [ null, { type: 'Block', accept: 'string', }, null, { type: 'Block', accept: 'string', paramType: 'index', }, null, { type: 'Block', accept: 'string', }, null, ], }, ], }, }, count_match_string: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_count_match_string_1, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_count_match_string_2, color: '#FFF', }, ], events: {}, def: { params: [ { type: 'text', params: [Lang.Blocks.hi_entry_en], }, null, { type: 'text', params: ['e'], }, null, ], type: 'count_match_string', }, paramsKeyMap: { STRING: 0, TARGET: 2, }, class: 'calc_string', isNotFor: ['python_disable'], func(sprite, script) { const originStr = script.getStringValue('STRING', script); const targetStr = script.getStringValue('TARGET', script); return originStr.split(targetStr).length - 1; }, syntax: { js: [], py: [], }, }, index_of_string: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_index_of_string_1, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_index_of_string_2, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_index_of_string_3, color: '#FFF', }, ], events: {}, def: { params: [ null, { type: 'text', params: [Lang.Blocks.hi_entry], }, null, { type: 'text', params: [Lang.Blocks.entry], }, null, ], type: 'index_of_string', }, pyHelpDef: { params: [ null, { type: 'text', params: ['A&value'], }, null, { type: 'text', params: ['B&value'], }, null, ], type: 'index_of_string', }, paramsKeyMap: { LEFTHAND: 1, RIGHTHAND: 3, }, class: 'calc_string', isNotFor: [], func(sprite, script) { const str = script.getStringValue('LEFTHAND', script); const target = script.getStringValue('RIGHTHAND', script); const index = str.indexOf(target); return index + 1; }, syntax: { js: [], py: [ { syntax: '%2.find(%4)', blockType: 'param', }, ], }, }, replace_string: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_replace_string_1, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_replace_string_2, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_replace_string_3, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_replace_string_4, color: '#FFF', }, ], events: {}, def: { params: [ null, { type: 'text', params: [Lang.Blocks.hi_entry], }, null, { type: 'text', params: [Lang.Blocks.hello], }, null, { type: 'text', params: [Lang.Blocks.nice], }, null, ], type: 'replace_string', }, pyHelpDef: { params: [ null, { type: 'text', params: ['A&value'], }, null, { type: 'text', params: ['B&value'], }, null, { type: 'text', params: ['C&value'], }, null, ], type: 'replace_string', }, paramsKeyMap: { STRING: 1, OLD_WORD: 3, NEW_WORD: 5, }, class: 'calc_string', isNotFor: [], func(sprite, script) { const oldWord = script.getStringValue('OLD_WORD', script); const newWord = script.getStringValue('NEW_WORD', script); const originalString = script.getStringValue('STRING', script); return originalString.split(oldWord).join(newWord); }, syntax: { js: [], py: [ { syntax: '%2.replace(%4, %6)', blockType: 'param', }, ], }, }, change_string_case: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_change_string_case_1, color: '#FFF', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.CALC_change_string_case_2, color: '#FFF', }, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_change_string_case_sub_1, 'toUpperCase'], [Lang.Blocks.CALC_change_string_case_sub_2, 'toLowerCase'], ], value: 'toUpperCase', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.CALC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.CALC_change_string_case_3, color: '#FFF', }, ], events: {}, def: { params: [ null, { type: 'text', params: ['Hello Entry!'], }, null, null, null, ], type: 'change_string_case', }, pyHelpDef: { params: [ null, { type: 'text', params: ['A&value'], }, null, null, null, ], type: 'change_string_case', }, paramsKeyMap: { STRING: 1, CASE: 3, }, class: 'calc_string', isNotFor: [], func(sprite, script) { const str = script.getStringValue('STRING', script); const caseType = script.getField('CASE', script); if (caseType === 'toUpperCase') { return str.toUpperCase(); } else if (caseType === 'toLowerCase') { return str.toLowerCase(); } return str; }, syntax: { js: [], py: [ { syntax: '%2.upper()', params: [null, null, null, 'toUpperCase', null], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_change_string_case_sub_1, 'toUpperCase'], [Lang.Blocks.CALC_change_string_case_sub_2, 'toLowerCase'], ], value: 'toUpperCase', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.CALC, converter: Entry.block.converters.returnStringValue, }, ], }, { syntax: '%2.lower()', params: [null, null, null, 'toLowerCase', null], blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'string', }, undefined, { type: 'Dropdown', options: [ [Lang.Blocks.CALC_change_string_case_sub_1, 'toUpperCase'], [Lang.Blocks.CALC_change_string_case_sub_2, 'toLowerCase'], ], value: 'toUpperCase', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.CALC, converter: Entry.block.converters.returnStringValue, }, ], }, ], }, }, get_block_count: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'blockCount', fontSize: 10, textColor: '#fff', bgColor: EntryStatic.colorSet.block.darken.CALC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, ], events: {}, def: { params: [null], type: 'get_block_count', }, pyHelpDef: { params: ['A&value'], type: 'get_block_count', }, paramsKeyMap: { OBJECT: 0, }, class: 'block', isNotFor: [], async func(sprite, script) { const objectKey = script.getField('OBJECT', script); if (!objectKey) { return 0; } let object; if (objectKey.indexOf('scene-') === 0) { const blocks = await Entry.Utils.getObjectsBlocksBySceneId( objectKey.substr(6) ); return _get(blocks, 'length', 0); } else if (objectKey === 'all') { object = undefined; } else if (objectKey === 'self') { object = sprite.parent; } else if (objectKey.indexOf('object-') === 0) { object = Entry.container.getObject(objectKey.substr(7)); } else { return 0; } const blocks = await Entry.Utils.getObjectsBlocksForEventThread(object); const count = _get(blocks, 'length', 0); return count; }, syntax: { js: [], py: [ { syntax: 'Entry.get_block_count(%1)', blockType: 'param', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'blockCount', fontSize: 11, textColor: '#fff', arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, converter: Entry.block.converters.returnStringValue, codeMap: 'Entry.CodeMap.Entry.get_block_count[0]', }, ], }, ], }, }, change_rgb_to_hex: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ { type: 'number', params: ['255'], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, ], type: 'change_rgb_to_hex', }, paramsKeyMap: { RED: 0, GREEN: 1, BLUE: 2, }, class: 'color', isNotFor: [], func(sprite, script) { const red = script.getNumberValue('RED', script); const greeb = script.getNumberValue('GREEN', script); const blue = script.getNumberValue('BLUE', script); return Entry.rgb2hex(red, greeb, blue); }, }, change_hex_to_rgb: { color: EntryStatic.colorSet.block.default.CALC, outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Dropdown', options: [ ['R', 'r'], ['G', 'g'], ['B', 'b'], ], value: 'RED', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.CALC, }, ], events: {}, def: { params: [ { type: 'text', params: ['#ff0000'], }, 'r', ], type: 'change_hex_to_rgb', }, paramsKeyMap: { HEX: 0, COLOR: 1, }, class: 'color', isNotFor: [], func(sprite, script) { const color = script.getField('COLOR', script); const value = script.getValue('HEX', script); return Entry.hex2rgb(value)[color]; }, }, get_boolean_value: { color: EntryStatic.colorSet.block.default.CALC, fontColor: '#FFF', outerLine: EntryStatic.colorSet.block.darken.CALC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'boolean', }, ], events: {}, def: { params: [{ type: 'True' }], type: 'get_boolean_value', }, class: 'calc_boolean', isNotFor: [], paramsKeyMap: { BOOLEAN: 0, }, func(sprite, script) { const bool = script.getValue('BOOLEAN', script); if (Boolean(bool)) { return 'TRUE'; } return 'FALSE'; }, syntax: { js: [], py: [ { syntax: 'Entry.value_of_username()', blockType: 'param', }, ], }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_expansion_behaviorconduct_disaster.js ================================================ 'use strict'; const PromiseManager = require('../../core/promiseManager'); const { callApi } = require('../../util/common'); function getInitialCategoryMap() { return { '01001': { lang: Lang.Blocks.behaviorConduct01001, sub: ['01001001', '01001002', '01001003'], }, '01002': { lang: Lang.Blocks.behaviorConduct01002, sub: ['01002002', '01002003', '01002004'], }, '01003': { lang: Lang.Blocks.behaviorConduct01003, sub: ['01003002', '01003003', '01003004'], }, '01004': { lang: Lang.Blocks.behaviorConduct01004, sub: ['01004001', '01004002'], }, '01005': { lang: Lang.Blocks.behaviorConduct01005, sub: ['01005002', '01005003', '01005004'], }, '01006': { lang: Lang.Blocks.behaviorConduct01006, sub: ['01006001', '01006002'], }, '01007': { lang: Lang.Blocks.behaviorConduct01007, sub: ['01007001'], }, '01008': { lang: Lang.Blocks.behaviorConduct01008, sub: ['01008001', '01008002', '01008003'], }, '01009': { lang: Lang.Blocks.behaviorConduct01009, sub: ['01009001', '01009002'], }, '01010': { lang: Lang.Blocks.behaviorConduct01010, sub: ['01010001'], }, '01011': { lang: Lang.Blocks.behaviorConduct01011, sub: ['01011009', '01011010', '01011012'], }, '01013': { lang: Lang.Blocks.behaviorConduct01013, sub: ['01013002', '01013003'], }, '01014': { lang: Lang.Blocks.behaviorConduct01014, sub: ['01014001'], }, }; } Entry.EXPANSION_BLOCK.behaviorConductDisaster = { name: 'behaviorConductDisaster', imageName: 'disaster.png', title: { ko: '자연재난', en: 'Disaster', jp: '自然災害', }, titleKey: 'template.behaviorConductDisaster_title_text', description: Lang.Msgs.expansion_behaviorConductDisaster_description, descriptionKey: 'Msgs.expansion_behaviorConductDisaster_description', isInitialized: false, disabled: true, init() { if (this.isInitialized) { return; } Entry.EXPANSION_BLOCK.behaviorConductDisaster.isInitialized = true; }, api: '/api/expansionBlock/behaviorConduct', apiType: '01', }; Entry.EXPANSION_BLOCK.behaviorConductDisaster.getBlocks = function () { const categoryMap = getInitialCategoryMap(); const getCategory = function () { return Object.keys(categoryMap).map((category) => [categoryMap[category].lang, category]); }; const defaultCategory = Object.keys(categoryMap)[0]; const params = { getCategory(isPython) { const param = { type: 'Dropdown', options: getCategory(), value: defaultCategory, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, dropdownSync: 'disaster', }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getSubCategory(isPython = false) { const param = { type: 'DropdownDynamic', value: null, menuName() { const value = this.getTargetValue('disaster'); if (!value) { return [[Lang.Blocks.no_target, 'null']]; } return categoryMap[value].sub.map((category) => [ Lang.Blocks[`behaviorConduct${category}`], category, ]); }, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options.length) { return options[0][1]; } return null; }, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, }; const getBehavior = (params, defaultValue, index = null) => { const key = `behaviorConduct-${params.category}/${params.subCategory}`; return new PromiseManager() .Promise((resolve) => { callApi(key, { url: `${Entry.EXPANSION_BLOCK.behaviorConductDisaster.api}/${params.category}/${params.subCategory}`, }) .then((result) => { if (result) { const items = result.data.response.body.items.item.filter( (i) => i.hasOwnProperty('actRmks') && i.safetyCate3 == params.subCategory2 ); if (index) { return resolve(items[index - 1].actRmks); } return resolve(items.length); } return resolve(defaultValue); }) .catch(() => resolve(defaultValue)); }) .catch(() => defaultValue); }; return { behaviorConductDisaster_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.behaviorConductDisaster_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'behaviorConductDisaster_title', }, class: 'behaviorConductDisaster', isNotFor: ['behaviorConductDisaster'], events: {}, }, count_disaster_behavior: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [params.getCategory(), params.getSubCategory()], events: {}, def: { params: [params.getCategory().value, null], type: 'count_disaster_behavior', }, pyHelpDef: { params: ['A&value', 'B&value'], type: 'count_disaster_behavior', }, paramsKeyMap: { CATEGORY: 0, SUB_CATEGORY: 1, }, class: 'behaviorConductDisaster', isNotFor: ['behaviorConductDisaster'], func(sprite, script) { const params = { category: Entry.EXPANSION_BLOCK.behaviorConductDisaster.apiType, subCategory: script.getField('CATEGORY', script), subCategory2: script.getField('SUB_CATEGORY', script), }; return getBehavior(params, 0); }, syntax: { js: [], py: [], }, wikiClass: 'emergencyActionGuidelines', }, get_disaster_behavior: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ params.getCategory(), params.getSubCategory(), { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [params.getCategory().value, null, 1], type: 'get_disaster_behavior', }, pyHelpDef: { params: ['A&value', 'B&value', 'C&value'], type: 'get_disaster_behavior', }, paramsKeyMap: { CATEGORY: 0, SUB_CATEGORY: 1, NUMBER: 2, }, class: 'behaviorConductDisaster', isNotFor: ['behaviorConductDisaster'], func(sprite, script) { const number = script.getStringValue('NUMBER', script); const defaultValue = Lang.Blocks.deprecated; const params = { category: Entry.EXPANSION_BLOCK.behaviorConductDisaster.apiType, subCategory: script.getField('CATEGORY', script), subCategory2: script.getField('SUB_CATEGORY', script), }; return getBehavior(params, defaultValue, number); }, syntax: { js: [], py: [], }, wikiClass: 'emergencyActionGuidelines', }, }; }; ================================================ FILE: src/playground/blocks/block_expansion_behaviorconduct_lifesafety.js ================================================ 'use strict'; const PromiseManager = require('../../core/promiseManager'); const { callApi } = require('../../util/common'); function getInitialCategoryMap() { return { '03002': { lang: Lang.Blocks.behaviorConduct03002, sub: ['03002002', '03002003', '03002004', '03002005', '03002006'], }, '03003': { lang: Lang.Blocks.behaviorConduct03003, sub: ['03003001', '03003002', '03003003'], }, '03004': { lang: Lang.Blocks.behaviorConduct03004, sub: ['03004001'], }, '03016': { lang: Lang.Blocks.behaviorConduct03016, sub: ['03016001'], }, '03005': { lang: Lang.Blocks.behaviorConduct03005, sub: ['03005001'], }, '03006': { lang: Lang.Blocks.behaviorConduct03006, sub: ['03006004', '03006005', '03006002', '03006003'], }, '03008': { lang: Lang.Blocks.behaviorConduct03008, sub: ['03008001'], }, '03009': { lang: Lang.Blocks.behaviorConduct03009, sub: ['03009001'], }, '03010': { lang: Lang.Blocks.behaviorConduct03010, sub: ['03010001'], }, '03011': { lang: Lang.Blocks.behaviorConduct03011, sub: ['03011001'], }, '03012': { lang: Lang.Blocks.behaviorConduct03012, sub: ['03012001'], }, '03013': { lang: Lang.Blocks.behaviorConduct03013, sub: ['03013002', '03013005'], }, '03014': { lang: Lang.Blocks.behaviorConduct03014, sub: ['03014001', '03014003', '03014004'], }, '03015': { lang: Lang.Blocks.behaviorConduct03015, sub: ['03015007', '03015003'], }, }; } Entry.EXPANSION_BLOCK.behaviorConductLifeSafety = { name: 'behaviorConductLifeSafety', imageName: 'firstaid.png', title: { ko: '생활안전', en: 'LifeSafety', jp: '生活安全', }, titleKey: 'template.behaviorConductLifeSafety_title_text', description: Lang.Msgs.expansion_behaviorConductLifeSafety_description, descriptionKey: 'Msgs.expansion_behaviorConductLifeSafety_description', isInitialized: false, disabled: true, init() { if (this.isInitialized) { return; } Entry.EXPANSION_BLOCK.behaviorConductLifeSafety.isInitialized = true; }, api: '/api/expansionBlock/behaviorConduct', apiType: '03', }; Entry.EXPANSION_BLOCK.behaviorConductLifeSafety.getBlocks = function () { const categoryMap = getInitialCategoryMap(); const getCategory = function () { return Object.keys(categoryMap).map((category) => [categoryMap[category].lang, category]); }; const defaultCategory = Object.keys(categoryMap)[0]; const params = { getCategory(isPython) { const param = { type: 'Dropdown', options: getCategory(), value: defaultCategory, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, dropdownSync: 'lifesafety', }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getSubCategory(isPython = false) { const param = { type: 'DropdownDynamic', value: null, menuName() { const value = this.getTargetValue('lifesafety'); if (!value) { return [[Lang.Blocks.no_target, 'null']]; } return categoryMap[value].sub.map((category) => [ Lang.Blocks[`behaviorConduct${category}`], category, ]); }, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options.length) { return options[0][1]; } return null; }, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, }; const getBehavior = (params, defaultValue, index = null) => { const key = `behaviorConduct-${params.category}/${params.subCategory}`; return new PromiseManager() .Promise((resolve) => { callApi(key, { url: `${Entry.EXPANSION_BLOCK.behaviorConductLifeSafety.api}/${params.category}/${params.subCategory}`, }) .then((result) => { if (result) { const items = result.data.response.body.items.item.filter( (i) => i.hasOwnProperty('actRmks') && i.safetyCate3 == params.subCategory2 ); if (index) { return resolve(items[index - 1].actRmks); } return resolve(items.length); } return resolve(defaultValue); }) .catch(() => resolve(defaultValue)); }) .catch(() => defaultValue); }; return { behaviorConductLifeSafety_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.behaviorConductLifeSafety_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'behaviorConductLifeSafety_title', }, class: 'behaviorConductLifeSafety', isNotFor: ['behaviorConductLifeSafety'], events: {}, }, count_lifeSafety_behavior: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [params.getCategory(), params.getSubCategory()], events: {}, def: { params: [params.getCategory().value, null], type: 'count_lifeSafety_behavior', }, pyHelpDef: { params: ['A&value', 'B&value'], type: 'count_lifeSafety_behavior', }, paramsKeyMap: { CATEGORY: 0, SUB_CATEGORY: 1, }, class: 'behaviorConductLifeSafety', isNotFor: ['behaviorConductLifeSafety'], func(sprite, script) { const params = { category: Entry.EXPANSION_BLOCK.behaviorConductLifeSafety.apiType, subCategory: script.getField('CATEGORY', script), subCategory2: script.getField('SUB_CATEGORY', script), }; return getBehavior(params, 0); }, syntax: { js: [], py: [], }, wikiClass: 'emergencyActionGuidelines', }, get_lifeSafety_behavior: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ params.getCategory(), params.getSubCategory(), { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [params.getCategory().value, null, 1], type: 'get_lifeSafety_behavior', }, pyHelpDef: { params: ['A&value', 'B&value', 'C&value'], type: 'get_lifeSafety_behavior', }, paramsKeyMap: { CATEGORY: 0, SUB_CATEGORY: 1, NUMBER: 2, }, class: 'behaviorConductLifeSafety', isNotFor: ['behaviorConductLifeSafety'], func(sprite, script) { const number = script.getStringValue('NUMBER', script); const defaultValue = Lang.Blocks.deprecated; const params = { category: Entry.EXPANSION_BLOCK.behaviorConductLifeSafety.apiType, subCategory: script.getField('CATEGORY', script), subCategory2: script.getField('SUB_CATEGORY', script), }; return getBehavior(params, defaultValue, number); }, syntax: { js: [], py: [], }, wikiClass: 'emergencyActionGuidelines', }, }; }; ================================================ FILE: src/playground/blocks/block_expansion_disasterAlert.js ================================================ 'use strict'; const PromiseManager = require('../../core/promiseManager'); const { callApi } = require('../../util/common'); Entry.EXPANSION_BLOCK.disasterAlert = { name: 'disasterAlert', imageName: 'disasterAlert.png', title: { ko: '재난문자', en: 'Disaster alert', }, titleKey: 'template.disaster_alert_title_text', description: Lang.Msgs.expansion_disasterAlert_description, descriptionKey: 'Msgs.expansion_disasterAlert_description', isInitialized: false, init() { if (this.isInitialized) { return; } Entry.EXPANSION_BLOCK.disasterAlert.isInitialized = true; }, api: '/api/expansionBlock/disasterAlert', apiType: '01', }; const EMERGENCY_CATEGORY_MAP = { info: Lang.Blocks.disasterAlertTypeInfo, exigency: Lang.Blocks.disasterAlertTypeExigency, urgency: Lang.Blocks.disasterAlertTypeUrgency, }; const getDisasterAlert = (params, defaultValue) => { const now = new Date(); const hour = now.getHours(); const day = now.getDay(); const key = `disasterAlert-${day}-${hour}`; const promiseManager = new PromiseManager(); const job = promiseManager // eslint-disable-next-line new-cap .Promise((resolve) => { callApi(key, { url: `${Entry.EXPANSION_BLOCK.disasterAlert.api}`, }) .then((result) => { if (result) { let items = result?.data?.body || []; const category = EMERGENCY_CATEGORY_MAP?.[params?.category]; if (category) { items = items.filter((item) => item.EMRG_STEP_NM === category); } switch (params.command) { case 'count': return resolve(items?.length || defaultValue || 0); case 'get': const result = items?.[params?.index - 1]?.[params.option]; if (!result) { return resolve(defaultValue); } if (params?.option === 'REG_YMD') { return resolve(new Date(result).toLocaleString()); } return resolve(result); case 'exist': return resolve(items?.length > 0); default: return resolve(defaultValue); } } return resolve(defaultValue); }) .catch(() => resolve(defaultValue)); }) .catch(() => defaultValue); return job; }; Entry.EXPANSION_BLOCK.disasterAlert.getBlocks = function () { // 전체, 안전안내, 긴급재난, 위급재난 const DisasterAlertCategory = { type: 'Dropdown', options: [ [Lang.Blocks.disasterAlertTypeAll, 'all'], [Lang.Blocks.disasterAlertTypeInfo, 'info'], [Lang.Blocks.disasterAlertTypeExigency, 'exigency'], [Lang.Blocks.disasterAlertTypeUrgency, 'urgency'], ], value: 'all', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, }; // 내용, 수신지역, 긴급단계, 재해구분, 생성일시 const DisasterAlertOptions = { type: 'Dropdown', options: [ [Lang.Blocks.disasterAlertContents, 'MSG_CN'], [Lang.Blocks.disasterAlertRegeion, 'RCPTN_RGN_NM'], [Lang.Blocks.disasterAlertStep, 'EMRG_STEP_NM'], [Lang.Blocks.disasterAlertDisaster, 'DST_SE_NM'], [Lang.Blocks.disasterAlertRegisterDate, 'REG_YMD'], ], value: 'MSG_CN', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, }; return { disaster_alert_title: { template: '%1', skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.disaster_alert_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'disaster_alert_title', }, class: 'disasterAlert', isNotFor: ['disasterAlert'], events: {}, }, count_disaster_alert: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [DisasterAlertCategory], events: {}, def: { params: [DisasterAlertCategory.value], type: 'count_disaster_alert', }, pyHelpDef: { params: ['A&value'], type: 'count_disaster_alert', }, paramsKeyMap: { CATEGORY: 0, }, class: 'disasterAlert', isNotFor: ['disasterAlert'], func(sprite, script) { const category = script.getField('CATEGORY', script); return getDisasterAlert( { command: 'count', category, }, 0 ); }, syntax: { js: [], py: [], }, wikiClass: 'disasterAlert', }, get_disaster_alert: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ DisasterAlertCategory, { type: 'Block', accept: 'string', defaultType: 'number', }, DisasterAlertOptions, ], events: {}, def: { params: [DisasterAlertCategory.value, 1, DisasterAlertOptions.value], type: 'get_disaster_alert', }, pyHelpDef: { params: ['A&value', 'B&value', 'C&value'], type: 'get_disaster_alert', }, paramsKeyMap: { CATEGORY: 0, NUMBER: 1, OPTION: 2, }, class: 'disasterAlert', isNotFor: ['disasterAlert'], func(sprite, script) { const number = script.getStringValue('NUMBER', script); const category = script.getField('CATEGORY', script); const option = script.getField('OPTION', script); return getDisasterAlert({ command: 'get', category, index: number, option, }); }, syntax: { js: [], py: [], }, wikiClass: 'disasterAlert', }, check_disaster_alert: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_boolean_field', statements: [], params: [DisasterAlertCategory], events: {}, def: { params: [DisasterAlertCategory.value], type: 'check_disaster_alert', }, pyHelpDef: { params: ['B&value', null], type: 'check_disaster_alert', }, paramsKeyMap: { CATEGORY: 0, }, class: 'disasterAlert', isNotFor: ['disasterAlert'], async func(sprite, script) { const category = script.getField('CATEGORY', script); return getDisasterAlert({ command: 'exist', category, }); }, syntax: { js: [], py: [], }, wikiClass: 'disasterAlert', }, }; }; ================================================ FILE: src/playground/blocks/block_expansion_emergencyActionGuidelines.js ================================================ 'use strict'; const PromiseManager = require('../../core/promiseManager'); const { callApi } = require('../../util/common'); function getInitialCategoryMap() { return { '01': { '01001': { lang: Lang.Blocks.emergencyActionGuidelines01001, sub: ['01001001', '01001002', '01001003'], }, '01002': { lang: Lang.Blocks.emergencyActionGuidelines01002, sub: ['01002001', '01002002', '01002003', '01002004'], }, '01003': { lang: Lang.Blocks.emergencyActionGuidelines01003, sub: ['01003001', '01003002', '01003003', '01003004'], }, '01004': { lang: Lang.Blocks.emergencyActionGuidelines01004, sub: ['01004001', '01004002', '01004003'], }, '01005': { lang: Lang.Blocks.emergencyActionGuidelines01005, sub: ['01005001', '01005002', '01005003', '01005004'], }, '01006': { lang: Lang.Blocks.emergencyActionGuidelines01006, sub: ['01006001', '01006002'], }, '01007': { lang: Lang.Blocks.emergencyActionGuidelines01007, sub: ['01007001'], }, '01008': { lang: Lang.Blocks.emergencyActionGuidelines01008, sub: ['01008001', '01008002', '01008003', '01008004'], }, '01009': { lang: Lang.Blocks.emergencyActionGuidelines01009, sub: ['01009001', '01009002', '01009003'], }, '01010': { lang: Lang.Blocks.emergencyActionGuidelines01010, sub: ['01010001', '01010002'], }, '01011': { lang: Lang.Blocks.emergencyActionGuidelines01011, sub: ['01011007', '01011008', '01011009', '01011010', '01011012'], }, '01012': { lang: Lang.Blocks.emergencyActionGuidelines01012, sub: ['01012005', '01012006'], }, '01013': { lang: Lang.Blocks.emergencyActionGuidelines01013, sub: ['01013001', '01013002', '01013003', '01013004', '01013005'], }, '01014': { lang: Lang.Blocks.emergencyActionGuidelines01014, sub: ['01014001', '01014002', '01014003', '01014004'], }, '01015': { lang: Lang.Blocks.emergencyActionGuidelines01015, sub: ['01015001', '01015002', '01015003'], }, }, '02': { '02001': { lang: Lang.Blocks.emergencyActionGuidelines02001, sub: ['02001001', '02001002', '02001003'], }, '02002': { lang: Lang.Blocks.emergencyActionGuidelines02002, sub: ['02002001', '02002002'], }, '02003': { lang: Lang.Blocks.emergencyActionGuidelines02003, sub: ['02003001', '02003002', '02003003'], }, '02004': { lang: Lang.Blocks.emergencyActionGuidelines02004, sub: ['02004001', '02004002'], }, '02005': { lang: Lang.Blocks.emergencyActionGuidelines02005, sub: ['02005001', '02005002', '02005003', '02005004', '02005005'], }, '02006': { lang: Lang.Blocks.emergencyActionGuidelines02006, sub: ['02006001', '02006002', '02006003'], }, '02007': { lang: Lang.Blocks.emergencyActionGuidelines02007, sub: ['02007001', '02007002', '02007003'], }, '02008': { lang: Lang.Blocks.emergencyActionGuidelines02008, sub: ['02008001', '02008002'], }, '02009': { lang: Lang.Blocks.emergencyActionGuidelines02009, sub: ['02009001', '02009002', '02009003'], }, '02010': { lang: Lang.Blocks.emergencyActionGuidelines02010, sub: ['02010001', '02010002', '02010003', '02010004'], }, '02011': { lang: Lang.Blocks.emergencyActionGuidelines02011, sub: [ '02011001', '02011002', '02011003', '02011004', '02011005', '02011006', '02011007', '02011008', '02011009', '02011010', '02011011', '02011012', '02011013', '02011014', '02011015', ], }, '02012': { lang: Lang.Blocks.emergencyActionGuidelines02012, sub: [ '02012001', '02012002', '02012003', '02012004', '02012005', '02012006', '02012007', ], }, '02013': { lang: Lang.Blocks.emergencyActionGuidelines02013, sub: [ '02013001', '02013002', '02013003', '02013004', '02013005', '02013007', '02013008', '02013009', '02013010', ], }, '02014': { lang: Lang.Blocks.emergencyActionGuidelines02014, sub: ['02014001', '02014002', '02014003'], }, '02015': { lang: Lang.Blocks.emergencyActionGuidelines02015, sub: ['02015001', '02015004'], }, '02016': { lang: Lang.Blocks.emergencyActionGuidelines02016, sub: ['02016001'], }, '02017': { lang: Lang.Blocks.emergencyActionGuidelines02017, sub: ['02017001'], }, '02018': { lang: Lang.Blocks.emergencyActionGuidelines02018, sub: ['02018001', '02018002', '02018003'], }, '02019': { lang: Lang.Blocks.emergencyActionGuidelines02019, sub: [ '02019001', '02019002', '02019003', '02019004', '02019005', '02019006', '02019007', '02019008', '02019009', '02019010', '02019011', '02019012', '02019013', '02019014', '02019015', '02019016', ], }, '02020': { lang: Lang.Blocks.emergencyActionGuidelines02020, sub: ['02020001', '02020002'], }, '02021': { lang: Lang.Blocks.emergencyActionGuidelines02021, sub: [ '02021001', '02021002', '02021003', '02021004', '02021005', '02021006', '02021007', '02021008', '02021009', '02021010', '02021011', ], }, '02022': { lang: Lang.Blocks.emergencyActionGuidelines02022, sub: [ '02022007', '02022008', '02022009', '02022010', '02022011', '02022012', '02022013', '02022014', '02022015', '02022016', '02022017', ], }, '02023': { lang: Lang.Blocks.emergencyActionGuidelines02023, sub: ['02023001'], }, }, '03': { '03002': { lang: Lang.Blocks.emergencyActionGuidelines03002, sub: [ '03002001', '03002002', '03002003', '03002004', '03002005', '03002006', '03002007', ], }, '03003': { lang: Lang.Blocks.emergencyActionGuidelines03003, sub: ['03003001', '03003002', '03003003'], }, '03004': { lang: Lang.Blocks.emergencyActionGuidelines03004, sub: ['03004001', '03004002', '03004003', '03004004'], }, '03005': { lang: Lang.Blocks.emergencyActionGuidelines03005, sub: ['03005001', '03005002'], }, '03006': { lang: Lang.Blocks.emergencyActionGuidelines03006, sub: ['03006001', '03006002', '03006003'], }, '03007': { lang: Lang.Blocks.emergencyActionGuidelines03007, sub: [ '03007001', '03007002', '03007003', '03007004', '03007005', '03007006', '03007007', ], }, '03008': { lang: Lang.Blocks.emergencyActionGuidelines03008, sub: ['03008001'], }, '03009': { lang: Lang.Blocks.emergencyActionGuidelines03009, sub: ['03009001'], }, '03010': { lang: Lang.Blocks.emergencyActionGuidelines03010, sub: ['03010001'], }, '03011': { lang: Lang.Blocks.emergencyActionGuidelines03011, sub: ['03011001'], }, '03012': { lang: Lang.Blocks.emergencyActionGuidelines03012, sub: ['03012001'], }, '03013': { lang: Lang.Blocks.emergencyActionGuidelines03013, sub: ['03013001', '03013002', '03013003', '03013004', '03013005'], }, '03014': { lang: Lang.Blocks.emergencyActionGuidelines03014, sub: ['03014001', '03014002', '03014003', '03014004', '03014005', '03014006'], }, '03015': { lang: Lang.Blocks.emergencyActionGuidelines03015, sub: [ '03015001', '03015002', '03015003', '03015004', '03015005', '03015006', '03015007', ], }, '03016': { lang: Lang.Blocks.emergencyActionGuidelines03016, sub: ['03016001', '03016002'], }, }, }; } const defaultCategory = { '01': '01001', '02': '02001', '03': '03002', }; Entry.EXPANSION_BLOCK.emergencyActionGuidelines = { name: 'emergencyActionGuidelines', imageName: 'guideline.png', title: { ko: '국민행동요령', en: 'Emergency action guidelines', }, titleKey: 'template.emergencyActionGuidelines_title_text', description: Lang.Msgs.expansion_emergencyActionGuidelines_description, descriptionKey: 'Msgs.expansion_emergencyActionGuidelines_description', isInitialized: false, init() { if (this.isInitialized) { return; } Entry.EXPANSION_BLOCK.emergencyActionGuidelines.isInitialized = true; }, api: '/api/expansionBlock/emergencyActionGuidelines', apiType: '01', }; const getGuideline = (params, defaultValue, index = null) => { const key = `emergencyActionGuidelines-${params.category}-${params.subCategory}`; const promiseManager = new PromiseManager(); const job = promiseManager // eslint-disable-next-line new-cap .Promise((resolve) => { callApi(key, { // eslint-disable-next-line max-len url: `${Entry.EXPANSION_BLOCK.emergencyActionGuidelines.api}/${params.category}/${params.subCategory}`, }) .then((result) => { if (result) { const items = result.data.body.filter( (i) => i.hasOwnProperty('actRmks') && i.safety_cate3 == params.subCategory2 ); if (index) { return resolve(items[index - 1].actRmks); } return resolve(items.length); } return resolve(defaultValue); }) .catch(() => resolve(defaultValue)); }) .catch(() => defaultValue); return job; }; Entry.EXPANSION_BLOCK.emergencyActionGuidelines.getBlocks = function () { const categoryMap = getInitialCategoryMap(); const categoryDisasterMap = getInitialCategoryMap(); const getCategories = function (cate1) { return Object.keys(categoryMap[cate1]).map((cate2) => [ categoryMap[cate1][cate2].lang, cate2, ]); }; const getCategory = (cate1 = '01', isPython) => { const param = { type: 'Dropdown', options: getCategories(cate1), value: defaultCategory[cate1], fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, dropdownSync: 'emergencyAction', }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }; const getSubCategory = (cate1 = '01', isPython = false) => { const param = { type: 'DropdownDynamic', value: null, menuName() { const value = this.getTargetValue('emergencyAction'); if (!value) { return [[Lang.Blocks.no_target, 'null']]; } return categoryMap[cate1][value].sub.map((category) => [ Lang.Blocks[`emergencyActionGuidelines${category}`], category, ]); }, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options.length) { return options[0][1]; } return null; }, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }; return { emergencyActionGuidelines_title: { template: '%1', skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.emergencyActionGuidelines_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'emergencyActionGuidelines_title', }, class: 'emergencyActionGuidelines', isNotFor: ['emergencyActionGuidelines'], events: {}, }, count_disaster_guideline: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [getCategory('01'), getSubCategory('01')], events: {}, def: { params: [getCategory('01').value, null], type: 'count_disaster_guideline', }, pyHelpDef: { params: ['A&value', 'B&value'], type: 'count_disaster_guideline', }, paramsKeyMap: { CATEGORY: 0, SUB_CATEGORY: 1, }, class: 'emergencyActionGuidelines', isNotFor: ['emergencyActionGuidelines'], func(sprite, script) { const params = { category: '01', subCategory: script.getField('CATEGORY', script), subCategory2: script.getField('SUB_CATEGORY', script), }; return getGuideline(params, 0); }, syntax: { js: [], py: [], }, wikiClass: 'emergencyActionGuidelines', }, get_disaster_guideline: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ getCategory('01'), getSubCategory('01'), { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [getCategory('01').value, null, 1], type: 'get_disaster_guideline', }, pyHelpDef: { params: ['A&value', 'B&value', 'C&value'], type: 'get_disaster_guideline', }, paramsKeyMap: { CATEGORY: 0, SUB_CATEGORY: 1, NUMBER: 2, }, class: 'emergencyActionGuidelines', isNotFor: ['emergencyActionGuidelines'], func(sprite, script) { const number = script.getStringValue('NUMBER', script); const defaultValue = Lang.Blocks.no_data; const params = { category: '01', subCategory: script.getField('CATEGORY', script), subCategory2: script.getField('SUB_CATEGORY', script), }; return getGuideline(params, defaultValue, number); }, syntax: { js: [], py: [], }, wikiClass: 'emergencyActionGuidelines', }, count_social_disaster_guideline: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [getCategory('02'), getSubCategory('02')], events: {}, def: { params: [getCategory('02').value, null], type: 'count_social_disaster_guideline', }, pyHelpDef: { params: ['A&value', 'B&value'], type: 'count_social_disaster_guideline', }, paramsKeyMap: { CATEGORY: 0, SUB_CATEGORY: 1, }, class: 'emergencyActionGuidelines', isNotFor: ['emergencyActionGuidelines'], func(sprite, script) { const params = { category: '02', subCategory: script.getField('CATEGORY', script), subCategory2: script.getField('SUB_CATEGORY', script), }; return getGuideline(params, 0); }, syntax: { js: [], py: [], }, wikiClass: 'emergencyActionGuidelines', }, get_social_disaster_guideline: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ getCategory('02'), getSubCategory('02'), { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [getCategory('02').value, null, 1], type: 'get_social_disaster_guideline', }, pyHelpDef: { params: ['A&value', 'B&value', 'C&value'], type: 'get_social_disaster_guideline', }, paramsKeyMap: { CATEGORY: 0, SUB_CATEGORY: 1, NUMBER: 2, }, class: 'emergencyActionGuidelines', isNotFor: ['emergencyActionGuidelines'], func(sprite, script) { const number = script.getStringValue('NUMBER', script); const defaultValue = Lang.Blocks.no_data; const params = { category: '02', subCategory: script.getField('CATEGORY', script), subCategory2: script.getField('SUB_CATEGORY', script), }; return getGuideline(params, defaultValue, number); }, syntax: { js: [], py: [], }, wikiClass: 'emergencyActionGuidelines', }, count_safety_accident_guideline: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [getCategory('03'), getSubCategory('03')], events: {}, def: { params: [getCategory('03').value, null], type: 'count_safety_accident_guideline', }, pyHelpDef: { params: ['A&value', 'B&value'], type: 'count_safety_accident_guideline', }, paramsKeyMap: { CATEGORY: 0, SUB_CATEGORY: 1, }, class: 'emergencyActionGuidelines', isNotFor: ['emergencyActionGuidelines'], func(sprite, script) { const params = { category: '03', subCategory: script.getField('CATEGORY', script), subCategory2: script.getField('SUB_CATEGORY', script), }; return getGuideline(params, 0); }, syntax: { js: [], py: [], }, wikiClass: 'emergencyActionGuidelines', }, get_safety_accident_guideline: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ getCategory('03'), getSubCategory('03'), { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [getCategory('03').value, null, 1], type: 'get_safety_accident_guideline', }, pyHelpDef: { params: ['A&value', 'B&value', 'C&value'], type: 'get_safety_accident_guideline', }, paramsKeyMap: { CATEGORY: 0, SUB_CATEGORY: 1, NUMBER: 2, }, class: 'emergencyActionGuidelines', isNotFor: ['emergencyActionGuidelines'], func(sprite, script) { const number = script.getStringValue('NUMBER', script); const defaultValue = Lang.Blocks.no_data; const params = { category: '03', subCategory: script.getField('CATEGORY', script), subCategory2: script.getField('SUB_CATEGORY', script), }; return getGuideline(params, defaultValue, number); }, syntax: { js: [], py: [], }, wikiClass: 'emergencyActionGuidelines', }, }; }; ================================================ FILE: src/playground/blocks/block_expansion_festival.js ================================================ 'use strict'; const PromiseManager = require('../../core/promiseManager'); const { callApi } = require('../../util/common'); function getLocationMap() { return { Seoul: { code: 1, sub: [ '강남구', '강동구', '강북구', '강서구', '관악구', '광진구', '구로구', '금천구', '노원구', '도봉구', '동대문구', '동작구', '마포구', '서대문구', '서초구', '성동구', '성북구', '송파구', '양천구', '영등포구', '용산구', '은평구', '종로구', '중구', '중랑구', ], }, Incheon: { code: 2, sub: [ '강화군', '계양구', '남구', '남동구', '동구', '부평구', '서구', '연수구', '옹진군', '중구', ], }, Daejeon: { code: 3, sub: ['대덕구', '동구', '서구', '유성구', '중구'], }, Daegu: { code: 4, sub: ['남구', '달서구', '달성군', '동구', '북구', '서구', '수성구', '중구'], }, Gwangju: { code: 5, sub: ['광산구', '남구', '동구', '북구', '서구'], }, Busan: { code: 6, sub: [ '강서구', '금정구', '기장군', '남구', '동구', '동래구', '부산진구', '북구', '사상구', '사하구', '서구', '수영구', '연제구', '영도구', '중구', '해운대구', ], }, Ulsan: { code: 7, sub: ['중구', '남구', '동구', '북구', '울주군'], }, Sejong: { code: 8, sub: ['세종특별자치시'], }, 'Gyeonggi-do': { code: 31, sub: [ '가평군', '고양시', '과천시', '광명시', '광주시', '구리시', '군포시', '김포시', '남양주시', '동두천시', '부천시', '성남시', '수원시', '시흥시', '안산시', '안성시', '안양시', '양주시', '양평군', '여주시', '연천군', '오산시', '용인시', '의왕시', '의정부시', '이천시', '파주시', '평택시', '포천시', '하남시', '화성시', ], }, Gangwon: { code: 32, sub: [ '강릉시', '고성군', '동해시', '삼척시', '속초시', '양구군', '양양군', '영월군', '원주시', '인제군', '정선군', '철원군', '춘천시', '태백시', '평창군', '홍천군', '화천군', '횡성군', ], }, 'Chungcheongbuk-do': { code: 33, sub: [ '괴산군', '단양군', '보은군', '영동군', '옥천군', '음성군', '제천시', '진천군', '청원군', '청주시', '충주시', '증평군', ], }, 'Chungcheongnam-do': { code: 34, sub: [ '공주시', '금산군', '논산시', '당진시', '보령시', '부여군', '서산시', '서천군', '아산시', '예산군', '천안시', '청양군', '태안군', '홍성군', '계룡시', ], }, 'Gyeongsangbuk-do': { code: 35, sub: [ '경산시', '경주시', '고령군', '구미시', '군위군', '김천시', '문경시', '봉화군', '상주시', '성주군', '안동시', '영덕군', '영양군', '영주시', '영천시', '예천군', '울릉군', '울진군', '의성군', '청도군', '청송군', '칠곡군', '포항시', ], }, 'Gyeongsangnam-do': { code: 36, sub: [ '거제시', '거창군', '고성군', '김해시', '남해군', '마산시', '밀양시', '사천시', '산청군', '양산시', '의령군', '진주시', '진해시', '창녕군', '창원시', '통영시', '하동군', '함안군', '함양군', '합천군', ], }, 'Jeollabuk-do': { code: 37, sub: [ '고창군', '군산시', '김제시', '남원시', '무주군', '부안군', '순창군', '완주군', '익산시', '임실군', '장수군', '전주시', '정읍시', '진안군', ], }, 'Jeollanam-do': { code: 38, sub: [ '강진군', '고흥군', '곡성군', '광양시', '구례군', '나주시', '담양군', '목포시', '무안군', '보성군', '순천시', '신안군', '여수시', '영광군', '영암군', '완도군', '장성군', '장흥군', '진도군', '함평군', '해남군', '화순군', ], }, Jeju: { code: 39, sub: ['남제주군', '북제주군', '서귀포시', '제주시'], }, }; } Entry.EXPANSION_BLOCK.festival = { name: 'festival', imageName: 'festival.png', title: { ko: '행사', en: 'festival', jp: 'イベント', }, titleKey: 'template.festival_title_text', description: Lang.Msgs.expansion_festival_description, descriptionKey: 'Msgs.expansion_festival_description', isInitialized: false, init() { if (this.isInitialized) { return; } Entry.EXPANSION_BLOCK.festival.isInitialized = true; }, api: '/api/expansionBlock/ko/festival', locationMap: getLocationMap(), infoTypeMap: { title: 'title', address: 'addr1', start_date: 'eventstartdate', end_date: 'eventenddate', coordinatex: 'mapx', coordinatey: 'mapy', area: 'sigungucode', homepage: 'homepage', overview: 'overview', }, strip(html) { return Entry.Utils.extractTextFromHTML(html); }, monthMap: { January: 1, 'Febuary ': 2, March: 3, April: 4, May: 5, June: 6, July: 7, August: 8, September: 9, October: 10, November: 11, December: 12, }, }; Entry.EXPANSION_BLOCK.festival.getBlocks = function () { const params = { getLocation(isPython) { const param = { type: 'Dropdown', options: [ [Lang.Blocks.location_seoul, 'Seoul'], [Lang.Blocks.location_gangwon, 'Gangwon'], [Lang.Blocks.location_gyeonggi, 'Gyeonggi-do'], [Lang.Blocks.location_gyeongsangnam, 'Gyeongsangnam-do'], [Lang.Blocks.location_gyeongsangbuk, 'Gyeongsangbuk-do'], [Lang.Blocks.location_gwangju, 'Gwangju'], [Lang.Blocks.location_daegu, 'Daegu'], [Lang.Blocks.location_daejeon, 'Daejeon'], [Lang.Blocks.location_busan, 'Busan'], [Lang.Blocks.location_sejong, 'Sejong'], [Lang.Blocks.location_ulsan, 'Ulsan'], [Lang.Blocks.location_incheon, 'Incheon'], [Lang.Blocks.location_jeollanam, 'Jeollanam-do'], [Lang.Blocks.location_jeollabuk, 'Jeollabuk-do'], [Lang.Blocks.location_jeju, 'Jeju'], [Lang.Blocks.location_chungcheongnam, 'Chungcheongnam-do'], [Lang.Blocks.location_chungcheongbuk, 'Chungcheongbuk-do'], ], value: 'Seoul', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getMonth(isPython) { const param = { type: 'Dropdown', options: [ [Lang.Menus.jan, 'January'], [Lang.Menus.feb, 'Febuary '], [Lang.Menus.mar, 'March'], [Lang.Menus.apr, 'April'], [Lang.Menus.may, 'May'], [Lang.Menus.jun, 'June'], [Lang.Menus.jul, 'July'], [Lang.Menus.aug, 'August'], [Lang.Menus.sep, 'September'], [Lang.Menus.oct, 'October'], [Lang.Menus.nov, 'November'], [Lang.Menus.dec, 'December'], ], value: 'January', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getInfoType(isPython) { const param = { type: 'Dropdown', options: [ [Lang.Blocks.EXPANSION_FESTIVAL_title, 'title'], [Lang.Blocks.EXPANSION_FESTIVAL_area, 'area'], [Lang.Blocks.EXPANSION_FESTIVAL_start_date, 'start_date'], [Lang.Blocks.EXPANSION_FESTIVAL_end_date, 'end_date'], [Lang.Blocks.EXPANSION_FESTIVAL_address, 'address'], //[Lang.Blocks.EXPANSION_FESTIVAL_coordinate, 'coordinate'], [Lang.Blocks.EXPANSION_FESTIVAL_overview, 'overview'], [Lang.Blocks.EXPANSION_FESTIVAL_homepage, 'homepage'], ], value: 'title', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, }; const getDetailInfo = (contentid, defaultValue, infoType) => { const key = `festival.api.detail_${contentid}`; return new PromiseManager().Promise((resolve) => { callApi(key, { url: `${Entry.EXPANSION_BLOCK.festival.api}/${contentid}` }) .then((response) => { let item = response.data.response.body.items.item; if (Array.isArray(item)) { item = item[0]; } if (item && item[infoType]) { return resolve(Entry.EXPANSION_BLOCK.festival.strip(item[infoType])); } return resolve(defaultValue); }) .catch(() => resolve(defaultValue)); }); }; const getFestivalCount = (params, defaultValue) => { const key = `festival.api-${JSON.stringify(params)}`; return new PromiseManager().Promise((resolve) => { callApi(key, { url: Entry.EXPANSION_BLOCK.festival.api, params }) .then((result) => { if (result && result.hasOwnProperty('data')) { return resolve(result?.data?.response?.body?.totalCount); } resolve(defaultValue); }) .catch(() => resolve(defaultValue)); }); }; const getFestivals = (number, params, defaultValue) => { if (number < 1) { return defaultValue; } const num = number % 10 || 10; params.page = Math.floor((number - 1) / 10 + 1); const key = `festival.api-${JSON.stringify(params)}`; return new PromiseManager().Promise((resolve) => { callApi(key, { url: Entry.EXPANSION_BLOCK.festival.api, params }) .then((result) => { const items = result?.data?.response?.body?.items?.item; let item = null; if (items.constructor == Array) { item = items[num - 1]; } else { item = items; } return resolve(item); }) .catch(() => resolve(defaultValue)); }); }; return { festival_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.festival_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'festival_title', }, class: 'festival', isNotFor: ['festival'], events: {}, }, count_festival: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [params.getLocation(), params.getMonth()], events: {}, def: { params: [params.getLocation().value, params.getMonth().value], type: 'count_festival', }, pyHelpDef: { params: ['A&value', 'B&value'], type: 'count_festival', }, paramsKeyMap: { LOCATION: 0, MONTH: 1, }, class: 'festival', isNotFor: ['festival'], func(sprite, script) { const defaultValue = 0; const params = { area: Entry.EXPANSION_BLOCK.festival.locationMap[ script.getField('LOCATION', script) ].code, month: Entry.EXPANSION_BLOCK.festival.monthMap[ script.getField('MONTH', script) ], list: 'N', }; return getFestivalCount(params, defaultValue); }, syntax: { js: [], py: [ { syntax: 'Event.get_len(%1, %2)', blockType: 'param', textParams: [params.getLocation(true), params.getMonth(true)], }, ], }, wikiClass: 'festival', }, get_festival_info: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ params.getLocation(), params.getMonth(), { type: 'Block', accept: 'string', defaultType: 'number', }, params.getInfoType(), ], events: {}, def: { params: [ params.getLocation().value, params.getMonth().value, 1, params.getInfoType().value, ], type: 'get_festival_info', }, pyHelpDef: { params: ['A&value', 'B&value', 'C&value', 'D&value'], type: 'get_festival_info', }, paramsKeyMap: { LOCATION: 0, MONTH: 1, NUMBER: 2, TYPE: 3, }, class: 'festival', isNotFor: ['festival'], func(sprite, script) { const number = script.getStringValue('NUMBER', script); const type = script.getField('TYPE', script); const infoType = Entry.EXPANSION_BLOCK.festival.infoTypeMap[type]; const location = Entry.EXPANSION_BLOCK.festival.locationMap[script.getField('LOCATION', script)]; const defaultValue = Lang.Blocks.no_data; const params = { area: location.code, month: Entry.EXPANSION_BLOCK.festival.monthMap[ script.getField('MONTH', script) ], }; return getFestivals(number, params, {}).then((festival) => { switch (type) { case 'area': return location.sub[festival[infoType] - 1] || defaultValue; case 'homepage': case 'overview': return getDetailInfo(festival.contentid, defaultValue, infoType); default: return festival[infoType] || defaultValue; } }); }, syntax: { js: [], py: [ { syntax: 'Event.get_info(%1, %2, %3, %4)', blockType: 'param', textParams: [ params.getLocation(true), params.getMonth(true), { type: 'Block', accept: 'string', }, params.getInfoType(true), ], }, ], }, wikiClass: 'festival', }, }; }; ================================================ FILE: src/playground/blocks/block_expansion_weather.js ================================================ 'use strict'; const { getStateOptions, getCityOptions, locationData } = require('../../util/location'); const { callApi } = require('../../util/common'); function resolveData(weatherData, type, dateStr) { const defaultData = Entry.EXPANSION_BLOCK.weather.defaultData; try { let key = Entry.EXPANSION_BLOCK.weather.getDate(dateStr); if (type === 'now') { key = Object.keys(weatherData)[0]; } else if (type === 'hour') { key = dateStr; } return weatherData[key] || defaultData; } catch (e) { return defaultData; } } Entry.EXPANSION_BLOCK.weather = { isInitialized: false, api: '/api/expansionBlock/weather/', date: new Date(), apiFail: {}, name: 'weather', imageName: 'weather.png', title: { ko: '날씨', en: 'weather', jp: '拡張ブロックを追加する', }, titleKey: 'template.weather_title_text', description: Lang.Msgs.expansion_weather_description, descriptionKey: 'Msgs.expansion_weather_description', init() { if (this.isInitialized) { return; } Entry.EXPANSION_BLOCK.weather.date = new Date(); const localDate = new Date(); const localDateYear = localDate.getFullYear(); const localDateMonth = String(localDate.getMonth() + 1).padStart(2, '0'); const localDateDay = String(localDate.getDate()).padStart(2, '0'); // eslint-disable-next-line max-len Entry.EXPANSION_BLOCK.weather.localDate = `${localDateYear}${localDateMonth}${localDateDay}`; Entry.EXPANSION_BLOCK.weather.getData('week', 'Seoul', 'today'); Entry.EXPANSION_BLOCK.weather.getData('hour', 'Seoul', '00'); Entry.EXPANSION_BLOCK.weather.getData('now', 'Seoul'); Entry.EXPANSION_BLOCK.weather.isInitialized = true; }, getCityCode(location) { let cityCode = null; if (typeof location === 'string') { cityCode = this.locationMap[location].code; } else { if (location.sub == locationData.initialData[1]) { cityCode = this.locationMap[location.parent].code; } else { cityCode = this.locationMap[location.parent].sub[location.sub]; } } return cityCode; }, async getData(type, location, dateStr) { let cityCode = null; if (typeof location === 'string') { cityCode = this.locationMap[location].code; } else { if (location.sub == locationData.initialData[1]) { cityCode = this.locationMap[location.parent].code; } else { cityCode = this.locationMap[location.parent].sub[location.sub]; } } const url = this.api + type; try { const response = await callApi(url, { url }); Entry.EXPANSION_BLOCK.weather.apiFail[type] = false; return resolveData(response.data[cityCode], type, dateStr); } catch (e) { Entry.EXPANSION_BLOCK.weather.apiFail[type] = { error: e }; return Entry.EXPANSION_BLOCK.weather.defaultData; } }, async getDataWithCityCode(type, cityCode, dateStr) { const url = this.api + type; try { const response = await callApi(url, { url }); Entry.EXPANSION_BLOCK.weather.apiFail[type] = false; return resolveData(response.data[cityCode], type, dateStr); } catch (e) { Entry.EXPANSION_BLOCK.weather.apiFail[type] = { error: e }; return Entry.EXPANSION_BLOCK.weather.defaultData; } }, checkWeather(sky_code, weather) { if (Entry.EXPANSION_BLOCK.weather.apiFail.week) { return true; } const skyCodeMap = { 1: 'sunny', //"맑음", 2: 'partly_cloudy', //"구름조금", 3: 'cloudy', //"흐림", 4: 'rainy', //"비", 5: 'snowy', //"눈", 6: 'sleet', //"눈비", 7: 'rainy', //"소나기", 8: 'snowy', //"소낙눈", 9: 'cloudy', //"안개", 10: 'rainy', //"뇌우", 11: 'cloudy', //"차차 흐려짐", 12: 'rainy', //"흐려져 뇌우", 13: 'rainy', //"흐려져 비", 14: 'snowy', //"흐려져 눈", 15: 'sleet', //"흐려져 눈비", 16: 'cloudy', //"흐린 후 갬", 17: 'rainy', //"뇌우 후 갬", 18: 'rainy', //"비 후 갬", 19: 'snowy', //"눈 후 갬", 20: 'sleet', //"눈비 후 갬", 21: 'mostly_cloudy', //"구름많음", 22: 'cloudy', }; if (skyCodeMap[sky_code]) { return skyCodeMap[sky_code] === weather; } else { return 'sunny' === weather; } }, checkFineDust(pm10, finedust) { if (Entry.EXPANSION_BLOCK.weather.apiFail.now) { return true; } const fineDustMap = { good: { min: 0, max: 30 }, normal: { min: 31, max: 80 }, bad: { min: 81, max: 150 }, very_bad: { min: 150, max: 9999 }, }; for (const key in fineDustMap) { if (fineDustMap[key].min <= pm10 && pm10 <= fineDustMap[key].max) { return key === finedust; } } return 'very_bad' === finedust; }, getDate(key) { Entry.EXPANSION_BLOCK.weather.date = Entry.EXPANSION_BLOCK.weather.date || new Date(); const date = new Date(Entry.EXPANSION_BLOCK.weather.date); switch (key) { case 'yesterday': date.setDate(date.getDate() - 1); break; case 'today': break; case 'tomorrow': date.setDate(date.getDate() + 1); break; case 'After_2_days': date.setDate(date.getDate() + 2); break; case 'After_3_days': date.setDate(date.getDate() + 3); break; case 'After_4_days': date.setDate(date.getDate() + 4); break; case 'After_5_days': date.setDate(date.getDate() + 5); break; case 'After_6_days': date.setDate(date.getDate() + 6); break; default: break; } const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}${month}${day}`; }, locationMap: { Seoul: { code: '1100000000', sub: { jongno_gu: '1111000000', jung_gu: '1114000000', yongsan_gu: '1117000000', seongdong_gu: '1120000000', gwangjin_gu: '1121500000', dongdaemun_gu: '1123000000', jungnang_gu: '1126000000', seongbuk_gu: '1129000000', gangbuk_gu: '1130500000', dobong_gu: '1132000000', nowon_gu: '1135000000', eunpyeong_gu: '1138000000', seodaemun_gu: '1141000000', mapo_gu: '1144000000', yangcheon_gu: '1147000000', gangseo_gu: '1150000000', guro_gu: '1153000000', geumcheon_gu: '1154500000', yeongdeungpo_gu: '1156000000', dongjak_gu: '1159000000', gwanak_gu: '1162000000', seocho_gu: '1165000000', gangnam_gu: '1168000000', songpa_gu: '1171000000', gangdong_gu: '1174000000', }, }, Busan: { code: '2600000000', sub: { jung_gu: '2611000000', seo_gu: '2614000000', dong_gu: '2617000000', yeongdo_gu: '2620000000', busanjin_gu: '2623000000', dongnae_gu: '2626000000', nam_gu: '2629000000', buk_gu: '2632000000', haeundae_gu: '2635000000', saha_gu: '2638000000', geumjeong_gu: '2641000000', gangseo_gu: '2644000000', yeonje: '2647000000', suyeong_gu: '2650000000', sasang_gu: '2653000000', gijang: '2671000000', }, }, Daegu: { code: '2700000000', sub: { jung_gu: '2711000000', dong_gu: '2714000000', seo_gu: '2717000000', nam_gu: '2720000000', buk_gu: '2723000000', suseong_gu: '2726000000', dalseo_gu: '2729000000', dalseong: '2771000000', gunwi: '2772000000', }, }, Incheon: { code: '2800000000', sub: { jung_gu: '2811000000', dong_gu: '2814000000', nam_gu: '2817000000', yeonsu_gu: '2818500000', namdong_gu: '2820000000', bupyeong_gu: '2823700000', gyeyang_gu: '2824500000', seo_gu: '2826000000', ganghwa: '2871000000', ongjin_gun: '2872000000', }, }, Gwangju: { code: '2900000000', sub: { dong_gu: '2911000000', seo_gu: '2914000000', nam_gu: '2915500000', buk_gu: '2917000000', gwangsan_gu: '2920000000', }, }, Daejeon: { code: '3000000000', sub: { dong_gu: '3011000000', jung_gu: '3014000000', western: '3017000000', yuseong_gu: '3020000000', daedeok_gu: '3023000000', }, }, Ulsan: { code: '3100000000', sub: { jung_gu: '3111000000', nam_gu: '3114000000', dong_gu: '3117000000', buk_gu: '3120000000', ulju: '3171000000', }, }, Sejong: { code: '3600000000', sub: {}, }, 'Gyeonggi-do': { code: '4100000000', sub: { suwon_si: '4111000000', seongnam: '4113000000', uijeongbu: '4115000000', anyang_si: '4117000000', bucheon_si: '4119000000', gwangmyeong_si: '4121000000', pyeongtaek_si: '4122000000', dongducheon_si: '4125000000', ansan_si: '4127000000', goyang_si: '4128000000', gwacheon_si: '4129000000', guri: '4131000000', namyangju_si: '4136000000', osan: '4137000000', siheung: '4139000000', gunpo_si: '4141000000', uiwang_si: '4143000000', hanam: '4145000000', yongin_si: '4146000000', paju: '4148000000', icheon: '4150000000', anseong_si: '4155000000', gimpo: '4157000000', hwaseong_si: '4159000000', gwangju: '4161000000', yangju_si: '4163000000', pocheon: '4165000000', yeoju: '4167000000', yeoncheon_gun: '4180000000', gapyeong_gun: '4182000000', yangpyeong: '4183000000', }, }, Gangwon: { code: '5100000000', sub: { chuncheon: '5111000000', wonju: '5113000000', gangneung_si: '5115000000', donghae: '5117000000', taebaek_si: '5119000000', 'sokcho city': '5121000000', samcheok_si: '5123000000', hongcheon: '5172000000', hoengseong_gun: '5173000000', yeongwol_gun: '5175000000', pyeongchang: '5176000000', jeongseon: '5177000000', cheolwon: '5178000000', hwacheon: '5179000000', yanggu: '5180000000', inje: '5181000000', goseong: '5182000000', yangyang: '5183000000', }, }, 'Chungcheongbuk-do': { code: '4300000000', sub: { cheongju: '4311000000', chungju: '4313000000', jecheon: '4315000000', boeun: '4372000000', okcheon: '4373000000', yeongdong: '4374000000', jeungpyeong: '4374500000', jincheon: '4375000000', goesan: '4376000000', eumseong: '4377000000', danyang: '4380000000', }, }, 'Chungcheongnam-do': { code: '4400000000', sub: { cheonan: '4413000000', gongju: '4415000000', boryeong: '4418000000', asan: '4420000000', seosan: '4421000000', nonsan: '4423000000', gyeryong: '4425000000', dangjin: '4427000000', geumsan: '4471000000', buyeo: '4476000000', seocheon: '4477000000', cheongyang: '4479000000', hongseong: '4480000000', yesan: '4481000000', taean: '4482500000', }, }, 'Jeollabuk-do': { code: '4500000000', sub: { jeonju: '4511000000', gunsan_si: '4513000000', iksan: '4514000000', jeongeup: '4518000000', namwon: '4519000000', gimje_si: '4521000000', wanju: '4571000000', jinan: '4572000000', muju: '4573000000', jangsu: '4574000000', imsil: '4575000000', sunchang: '4577000000', gochang: '4579000000', buan: '4580000000', }, }, // 'Jeollabuk-do': { // code: '5200000000', // sub: { // jeonju: '5211000000', // gunsan_si: '5213000000', // iksan: '5214000000', // jeongeup: '5218000000', // namwon: '5219000000', // gimje_si: '5221000000', // wanju: '5271000000', // jinan: '5272000000', // muju: '5273000000', // jangsu: '5274000000', // imsil: '5275000000', // sunchang: '5277000000', // gochang: '5279000000', // buan: '5280000000', // }, // }, 'Jeollanam-do': { code: '4600000000', sub: { mokpo: '4611000000', yosu: '4613000000', suncheon_si: '4615000000', naju: '4617000000', gwangyang_si: '4623000000', damyang: '4671000000', gokseong: '4672000000', gurye: '4673000000', goheung: '4677000000', boseong: '4678000000', hwasun: '4679000000', jangheung: '4680000000', gangjin: '4681000000', haenam: '4682000000', yeongam: '4683000000', muan: '4684000000', hampyeong: '4686000000', yeonggwang: '4687000000', jangseong: '4688000000', wando: '4689000000', jindo: '4690000000', sinan: '4691000000', }, }, 'Gyeongsangbuk-do': { code: '4700000000', sub: { pohang_si: '4711000000', gyeongju_si: '4713000000', gimcheon_si: '4715000000', andong_si: '4717000000', gumi_si: '4719000000', yeongju_si: '4721000000', yeongcheon_si: '4723000000', sangju_si: '4725000000', mungyeong_si: '4728000000', gyeongsan_si: '4729000000', uiseong: '4773000000', cheongsong: '4775000000', goryong: '4776000000', yeongdeok: '4777000000', cheongdo: '4782000000', golyeong: '4783000000', seongju: '4784000000', chilgok: '4785000000', yecheon: '4790000000', bonghwa: '4792000000', uljin: '4793000000', ulleung: '4794000000', }, }, 'Gyeongsangnam-do': { code: '4800000000', sub: { changwon_si: '4811000000', jinju: '4817000000', tongyeong_si: '4822000000', sacheon_si: '4824000000', gimhae_si: '4825000000', miryang_si: '4827000000', geoje_si: '4831000000', yangsan_si: '4833000000', uiryeong: '4872000000', haman: '4873000000', changnyeong: '4874000000', goseong: '4882000000', namhae: '4884000000', hadong: '4885000000', sancheong: '4886000000', hamyang: '4887000000', geochang: '4888000000', hapcheon: '4889000000', }, }, Jeju: { code: '5000000000', sub: { jeju_si: '5011000000', seogwipo: '5013000000', }, }, }, propertyMap: { //날짜별 the_lowest_temperature: 'min_temp', the_highest_temperature: 'max_temp', humidity: 'humidity', precipitation: 'rain', precipitation_probability: 'rain_p', wind_speed: 'windspd', //현재 temperature: 'temp', concentration_of_fine_dust: 'pm10', }, // 시간만 강수량 파라미터가 달라서 따로 맵을 만듬. propertyHourMap: { //날짜별 the_lowest_temperature: 'min_temp', the_highest_temperature: 'max_temp', humidity: 'humidity', precipitation: 'rainAmt', precipitation_probability: 'rain', wind_speed: 'windspd', //현재 temperature: 'temp', concentration_of_fine_dust: 'pm10', }, defaultData: { //week //aplYmd: 20180905, max_temp: 0, min_temp: 0, sky: '구름조금', sky_code: '2', winddir: 'W', windspd: 0, rain: 0, rain_p: 0, humidity: 0, locationCode: '1100000000', updated: '2018-09-05T03:27:42.804Z', //hour //aplYmdt: "2018090500", rainAmt: 0, temp: 0, //now pm10: 0, pm10_s: '좋음', }, }; Entry.EXPANSION_BLOCK.weather.getBlocks = function () { const params = { getDate(isPython = false) { const param = { type: 'Dropdown', options: [ [Lang.Blocks.date_yesterday, 'yesterday'], [Lang.Blocks.date_today, 'today'], [Lang.Blocks.date_tomorrow, 'tomorrow'], [Lang.Blocks.date_after_2_days, 'After_2_days'], [Lang.Blocks.date_after_3_days, 'After_3_days'], [Lang.Blocks.date_after_4_days, 'After_4_days'], [Lang.Blocks.date_after_5_days, 'After_5_days'], [Lang.Blocks.date_after_6_days, 'After_6_days'], ], value: 'today', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getLocation(isPython = false) { const param = { type: 'Dropdown', options: getStateOptions(), value: 'Seoul', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, dropdownSync: 'weather', }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getSubLocation(isPython = false) { const param = { type: 'DropdownDynamic', value: null, menuName() { const value = this.getTargetValue('weather'); if (!value) { return [[Lang.Blocks.no_target, 'null']]; } return getCityOptions(value); }, needDeepCopy: true, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, defaultValue: (value, options) => { if (options.length) { return options[0][1]; } return null; }, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getSky(isPython = false) { const param = { type: 'Dropdown', options: [ [Lang.Blocks.EXPANSION_WEATHER_sunny, 'sunny'], [Lang.Blocks.EXPANSION_WEATHER_partly_cloudy, 'partly_cloudy'], [Lang.Blocks.EXPANSION_WEATHER_mostly_cloudy, 'mostly_cloudy'], [Lang.Blocks.EXPANSION_WEATHER_cloudy, 'cloudy'], [Lang.Blocks.EXPANSION_WEATHER_rainy, 'rainy'], [Lang.Blocks.EXPANSION_WEATHER_sleet, 'sleet'], [Lang.Blocks.EXPANSION_WEATHER_snowy, 'snowy'], ], value: 'sunny', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getFineDust(isPython = false) { const param = { type: 'Dropdown', options: [ [Lang.Blocks.EXPANSION_WEATHER_finedust_good, 'good'], [Lang.Blocks.EXPANSION_WEATHER_finedust_normal, 'normal'], [Lang.Blocks.EXPANSION_WEATHER_finedust_bad, 'bad'], [Lang.Blocks.EXPANSION_WEATHER_finedust_very_bad, 'very_bad'], ], value: 'good', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getWeatherElements(isPython = false) { const param = { type: 'Dropdown', options: [ [Lang.Blocks.EXPANSION_WEATHER_lowest_temperature, 'the_lowest_temperature'], [Lang.Blocks.EXPANSION_WEATHER_highest_temperature, 'the_highest_temperature'], [Lang.Blocks.EXPANSION_WEATHER_humidity, 'humidity'], [Lang.Blocks.EXPANSION_WEATHER_precipitation, 'precipitation'], [ Lang.Blocks.EXPANSION_WEATHER_precipitation_probability, 'precipitation_probability', ], [Lang.Blocks.EXPANSION_WEATHER_wind_speed, 'wind_speed'], ], value: 'the_lowest_temperature', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getNowWeatherElement(isPython = false) { const param = { type: 'Dropdown', options: [ [Lang.Blocks.EXPANSION_WEATHER_temperature, 'temperature'], [Lang.Blocks.EXPANSION_WEATHER_finedust, 'concentration_of_fine_dust'], ], value: 'temperature', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getTimeWeatherElement(isPython = false) { const param = { type: 'Dropdown', options: [ [Lang.Blocks.EXPANSION_WEATHER_temperature, 'temperature'], [Lang.Blocks.EXPANSION_WEATHER_precipitation, 'precipitation'], [Lang.Blocks.EXPANSION_WEATHER_wind_speed, 'wind_speed'], [Lang.Blocks.EXPANSION_WEATHER_humidity, 'humidity'], [ Lang.Blocks.EXPANSION_WEATHER_precipitation_probability, 'precipitation_probability', ], ], value: 'temperature', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringValue; } return param; }, getTime(isPython = false) { const param = { type: 'Dropdown', options: [ ['00', '00'], ['03', '03'], ['06', '06'], ['09', '09'], ['12', '12'], ['15', '15'], ['18', '18'], ['21', '21'], ], value: '00', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.EXPANSION, arrowColor: EntryStatic.colorSet.common.WHITE, }; if (isPython) { param.converter = Entry.block.converters.returnStringOrNumberByValue; } return param; }, }; function pad2(n) { return n < 10 ? `0${n}` : n; } return { weather_title: { skeleton: 'basic_text', color: EntryStatic.colorSet.common.TRANSPARENT, params: [ { type: 'Text', text: Lang.template.weather_title_text, color: EntryStatic.colorSet.common.TEXT, align: 'center', }, ], def: { type: 'weather_title', }, class: 'weather', isNotFor: ['weather'], events: {}, }, check_city_weather: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_boolean_field', statements: [], params: [ params.getDate(), params.getLocation(), params.getSubLocation(), params.getSky(), ], events: {}, def: { params: [ params.getDate().value, params.getLocation().value, params.getSubLocation().value, params.getSky().value, ], type: 'check_city_weather', }, pyHelpDef: { params: ['B&value', 'C&value', 'D&value', null], type: 'check_city_weather', }, paramsKeyMap: { DATE: 0, LOCATION: 1, SUBLOCATION: 2, WEATHER: 3, }, class: 'weather_legacy', isNotFor: ['weather_legacy'], async func(sprite, script) { const location = { parent: script.getField('LOCATION', script), sub: script.getField('SUBLOCATION', script), }; const apiResult = await Entry.EXPANSION_BLOCK.weather.getData( 'week', location, script.getField('DATE', script) ); return Entry.EXPANSION_BLOCK.weather.checkWeather( apiResult.sky_code, script.getField('WEATHER', script) ); }, syntax: { js: [], py: [ { syntax: 'Weather.is_condition_sunny(%1, %2, %3)', params: [null, null, null, 'sunny'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getSky(true), ], }, { syntax: 'Weather.is_condition_partly_cloudy(%1, %2, %3)', params: [null, null, null, 'partly_cloudy'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getSky(true), ], }, { syntax: 'Weather.is_condition_mostly_cloudy(%1, %2, %3)', params: [null, null, null, 'mostly_cloudy'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getSky(true), ], }, { syntax: 'Weather.is_condition_cloudy(%1, %2, %3)', params: [null, null, null, 'cloudy'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getSky(true), ], }, { syntax: 'Weather.is_condition_rainy(%1, %2, %3)', params: [null, null, null, 'rainy'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getSky(true), ], }, { syntax: 'Weather.is_condition_sleet(%1, %2, %3)', params: [null, null, null, 'sleet'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getSky(true), ], }, { syntax: 'Weather.is_condition_snowy(%1, %2, %3)', params: [null, null, null, 'snowy'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getSky(true), ], }, ], }, wikiClass: 'weather', }, check_city_finedust: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_boolean_field', statements: [], params: [params.getLocation(), params.getSubLocation(), params.getFineDust()], events: {}, def: { params: [params.getLocation().value, null, params.getFineDust().value], type: 'check_city_finedust', }, pyHelpDef: { params: ['B&value', 'C&value', null], type: 'check_city_finedust', }, paramsKeyMap: { LOCATION: 0, SUBLOCATION: 1, FINEDUST: 2, }, class: 'weather_legacy', isNotFor: ['weather_legacy'], async func(sprite, script) { const location = { parent: script.getField('LOCATION', script), sub: script.getField('SUBLOCATION', script), }; const apiResult = await Entry.EXPANSION_BLOCK.weather.getData( 'now', location, null ); return Entry.EXPANSION_BLOCK.weather.checkFineDust( apiResult.pm10, script.getField('FINEDUST', script) ); }, syntax: { js: [], py: [ { syntax: 'Weather.is_current_finedust_grade_good(%1, %2)', params: [null, null, 'good'], blockType: 'param', textParams: [ params.getLocation(true), params.getSubLocation(true), params.getFineDust(true), ], }, { syntax: 'Weather.is_current_finedust_grade_normal(%1, %2)', params: [null, null, 'normal'], blockType: 'param', textParams: [ params.getLocation(true), params.getSubLocation(true), params.getFineDust(true), ], }, { syntax: 'Weather.is_current_finedust_grade_bad(%1, %2)', params: [null, null, 'bad'], blockType: 'param', textParams: [ params.getLocation(true), params.getSubLocation(true), params.getFineDust(true), ], }, { syntax: 'Weather.is_current_finedust_grade_very_bad(%1, %2)', params: [, null, null, 'very_bad'], blockType: 'param', textParams: [ params.getLocation(true), params.getSubLocation(true), params.getFineDust(true), ], }, ], }, wikiClass: 'weather', }, get_city_weather_data: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ params.getDate(), params.getLocation(), params.getSubLocation(), params.getWeatherElements(), ], events: {}, def: { params: [ params.getDate().value, params.getLocation().value, null, params.getWeatherElements().value, ], type: 'get_city_weather_data', }, pyHelpDef: { params: ['B&value', 'C&value', 'D&value', null], type: 'get_city_weather_data', }, paramsKeyMap: { DATE: 0, LOCATION: 1, SUBLOCATION: 2, TYPE: 3, }, class: 'weather_legacy', isNotFor: ['weather_legacy'], async func(sprite, script) { const location = { parent: script.getField('LOCATION', script), sub: script.getField('SUBLOCATION', script), }; const apiResult = await Entry.EXPANSION_BLOCK.weather.getData( 'week', location, script.getField('DATE', script) ); const type = Entry.EXPANSION_BLOCK.weather.propertyMap[script.getField('TYPE', script)]; return apiResult[type]; }, syntax: { js: [], py: [ { syntax: 'Weather.get_lowest_temperature(%1, %2, %3)', params: [null, null, null, 'the_lowest_temperature'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getWeatherElements(true), ], }, { syntax: 'Weather.get_highest_temperature(%1, %2, %3)', params: [null, null, null, 'the_highest_temperature'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getWeatherElements(true), ], }, { syntax: 'Weather.get_humidity(%1, %2, %3)', params: [null, null, null, 'humidity'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getWeatherElements(true), ], }, { syntax: 'Weather.get_precipitation(%1, %2, %3)', params: [null, null, null, 'precipitation'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getWeatherElements(true), ], }, { syntax: 'Weather.get_precipitation_probability(%1, %2, %3)', params: [null, null, null, 'precipitation_probability'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getWeatherElements(true), ], }, { syntax: 'Weather.get_wind_speed(%1, %2, %3)', params: [null, null, null, 'wind_speed'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSubLocation(true), params.getWeatherElements(true), ], }, ], }, wikiClass: 'weather', }, get_current_city_weather_data: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [params.getLocation(), params.getSubLocation(), params.getNowWeatherElement()], events: {}, def: { params: [params.getLocation().value, null, params.getNowWeatherElement().value], type: 'get_current_city_weather_data', }, pyHelpDef: { params: ['B&value', 'C&value', null], type: 'get_current_city_weather_data', }, paramsKeyMap: { LOCATION: 0, SUBLOCATION: 1, TYPE: 2, }, class: 'weather_legacy', isNotFor: ['weather_legacy'], func(sprite, script) { const location = { parent: script.getField('LOCATION', script), sub: script.getField('SUBLOCATION', script), }; const type = Entry.EXPANSION_BLOCK.weather.propertyMap[script.getField('TYPE', script)]; return new Promise((resolve) => { Entry.EXPANSION_BLOCK.weather .getData('now', location, null) .then((data) => resolve(data[type])); }); }, syntax: { js: [], py: [ { syntax: 'Weather.get_current_finedust(%1, %2)', params: [null, null, 'concentration_of_fine_dust'], blockType: 'param', textParams: [ params.getLocation(true), params.getSubLocation(true), params.getNowWeatherElement(true), ], }, { syntax: 'Weather.get_current_temperature(%1, %2)', params: [null, null, 'temperature'], blockType: 'param', textParams: [ params.getLocation(true), params.getSubLocation(true), params.getNowWeatherElement(true), ], }, ], }, wikiClass: 'weather', }, get_today_city_temperature: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [params.getLocation(), params.getSubLocation(), params.getTime()], events: {}, def: { params: [params.getLocation().value, null, params.getTime().value], type: 'get_today_city_temperature', }, pyHelpDef: { params: ['A&value', 'B&value', 'C&value'], type: 'get_today_city_temperature', }, paramsKeyMap: { LOCATION: 0, SUBLOCATION: 1, TIME: 2, }, class: 'weather_legacy', isNotFor: ['weather_legacy'], async func(sprite, script) { const location = { parent: script.getField('LOCATION', script), sub: script.getField('SUBLOCATION', script), }; const date = Entry.EXPANSION_BLOCK.weather.localDate; let time = script.getField('TIME', script); // db에 저장하지 않으면서 00시가 없어져서 03시부터 가능.. if (time == '00') { time = '03'; } const apiResult = await Entry.EXPANSION_BLOCK.weather.getData( 'hour', location, date + pad2(time - (time % 3)) ); return apiResult.temp; }, syntax: { js: [], py: [ { syntax: 'Weather.get_today_temperature(%1, %2, %3)', blockType: 'param', textParams: [ params.getLocation(true), params.getSubLocation(true), params.getTime(true), ], }, ], }, wikiClass: 'weather', }, //시군구 추가로 인한 legacy code 기존 블럭유지를 위해 필요. check_weather: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_boolean_field', statements: [], params: [params.getDate(), params.getLocation(), params.getSky()], events: {}, def: { params: [params.getDate().value, params.getLocation().value, params.getSky().value], type: 'check_weather', }, pyHelpDef: { params: ['B&value', 'C&value', null], type: 'check_weather', }, paramsKeyMap: { DATE: 0, LOCATION: 1, WEATHER: 2, }, class: 'weather_legacy', isNotFor: ['weather_legacy'], async func(sprite, script) { const apiResult = await Entry.EXPANSION_BLOCK.weather.getData( 'week', script.getField('LOCATION', script), script.getField('DATE', script) ); return Entry.EXPANSION_BLOCK.weather.checkWeather( apiResult.sky_code, script.getField('WEATHER', script) ); }, syntax: { js: [], py: [ { syntax: 'Legacy.Weather.is_condition_sunny(%1, %2)', params: [null, null, 'sunny'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSky(true), ], }, { syntax: 'Legacy.Weather.is_condition_partly_cloudy(%1, %2)', params: [null, null, 'partly_cloudy'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSky(true), ], }, { syntax: 'Legacy.Weather.is_condition_mostly_cloudy(%1, %2)', params: [null, null, 'mostly_cloudy'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSky(true), ], }, { syntax: 'Legacy.Weather.is_condition_cloudy(%1, %2)', params: [null, null, 'cloudy'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSky(true), ], }, { syntax: 'Legacy.Weather.is_condition_rainy(%1, %2)', params: [null, null, 'rainy'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSky(true), ], }, { syntax: 'Legacy.Weather.is_condition_sleet(%1, %2)', params: [null, null, 'sleet'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSky(true), ], }, { syntax: 'Legacy.Weather.is_condition_snowy(%1, %2)', params: [null, null, 'snowy'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getSky(true), ], }, ], }, wikiClass: 'weather', }, check_finedust: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_boolean_field', statements: [], params: [params.getLocation(), params.getFineDust()], events: {}, def: { params: [params.getLocation().value, params.getFineDust().value], type: 'check_finedust', }, pyHelpDef: { params: ['B&value', null], type: 'check_finedust', }, paramsKeyMap: { LOCATION: 0, FINEDUST: 1, }, class: 'weather_legacy', isNotFor: ['weather_legacy'], async func(sprite, script) { const apiResult = await Entry.EXPANSION_BLOCK.weather.getData( 'now', script.getField('LOCATION', script), null ); return Entry.EXPANSION_BLOCK.weather.checkFineDust( apiResult.pm10, script.getField('FINEDUST', script) ); }, syntax: { js: [], py: [ { syntax: 'Legacy.Weather.is_current_finedust_grade_good(%1)', params: [null, 'good'], blockType: 'param', textParams: [params.getLocation(true), params.getFineDust(true)], }, { syntax: 'Legacy.Weather.is_current_finedust_grade_normal(%1)', params: [null, 'normal'], blockType: 'param', textParams: [params.getLocation(true), params.getFineDust(true)], }, { syntax: 'Legacy.Weather.is_current_finedust_grade_bad(%1)', params: [null, 'bad'], blockType: 'param', textParams: [params.getLocation(true), params.getFineDust(true)], }, { syntax: 'Legacy.Weather.is_current_finedust_grade_very_bad(%1)', params: [, null, 'very_bad'], blockType: 'param', textParams: [params.getLocation(true), params.getFineDust(true)], }, ], }, wikiClass: 'weather', }, get_weather_data: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [params.getDate(), params.getLocation(), params.getWeatherElements()], events: {}, def: { params: [ params.getDate().value, params.getLocation().value, params.getWeatherElements().value, ], type: 'get_weather_data', }, pyHelpDef: { params: ['B&value', 'C&value', null], type: 'get_weather_data', }, paramsKeyMap: { DATE: 0, LOCATION: 1, TYPE: 2, }, class: 'weather_legacy', isNotFor: ['weather_legacy'], async func(sprite, script) { const apiResult = await Entry.EXPANSION_BLOCK.weather.getData( 'week', script.getField('LOCATION', script), script.getField('DATE', script) ); const type = Entry.EXPANSION_BLOCK.weather.propertyMap[script.getField('TYPE', script)]; return apiResult[type]; }, syntax: { js: [], py: [ { syntax: 'Legacy.Weather.get_lowest_temperature(%1, %2)', params: [null, null, 'the_lowest_temperature'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getWeatherElements(true), ], }, { syntax: 'Legacy.Weather.get_highest_temperature(%1, %2)', params: [null, null, 'the_highest_temperature'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getWeatherElements(true), ], }, { syntax: 'Legacy.Weather.get_humidity(%1, %2)', params: [null, null, 'humidity'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getWeatherElements(true), ], }, { syntax: 'Legacy.Weather.get_precipitation(%1, %2)', params: [null, null, 'precipitation'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getWeatherElements(true), ], }, { syntax: 'Legacy.Weather.get_precipitation_probability(%1, %2)', params: [null, null, 'precipitation_probability'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getWeatherElements(true), ], }, { syntax: 'Legacy.Weather.get_wind_speed(%1, %2)', params: [null, null, 'wind_speed'], blockType: 'param', textParams: [ params.getDate(true), params.getLocation(true), params.getWeatherElements(true), ], }, ], }, wikiClass: 'weather', }, get_current_weather_data: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [params.getLocation(), params.getNowWeatherElement()], events: {}, def: { params: [params.getLocation().value, params.getNowWeatherElement().value], type: 'get_current_weather_data', }, pyHelpDef: { params: ['B&value', null], type: 'get_current_weather_data', }, paramsKeyMap: { LOCATION: 0, TYPE: 1, }, class: 'weather_legacy', isNotFor: ['weather_legacy'], async func(sprite, script) { const apiResult = await Entry.EXPANSION_BLOCK.weather.getData( 'now', script.getField('LOCATION', script), null ); const type = Entry.EXPANSION_BLOCK.weather.propertyMap[script.getField('TYPE', script)]; return apiResult[type]; }, syntax: { js: [], py: [ { syntax: 'Legacy.Weather.get_current_finedust(%1)', params: [null, 'concentration_of_fine_dust'], blockType: 'param', textParams: [params.getLocation(true), params.getNowWeatherElement(true)], }, { syntax: 'Legacy.Weather.get_current_temperature(%1)', params: [null, 'temperature'], blockType: 'param', textParams: [params.getLocation(true), params.getNowWeatherElement(true)], }, ], }, wikiClass: 'weather', }, get_today_temperature: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [params.getLocation(), params.getTime()], events: {}, def: { params: [params.getLocation().value, params.getTime().value], type: 'get_today_temperature', }, pyHelpDef: { params: ['A&value', 'B&value'], type: 'get_today_temperature', }, paramsKeyMap: { LOCATION: 0, TIME: 1, }, class: 'weather_legacy', isNotFor: ['weather_legacy'], async func(sprite, script) { const date = Entry.EXPANSION_BLOCK.weather.localDate; let time = script.getField('TIME', script); // db에 저장하지 않으면서 00시가 없어져서 03시부터 가능.. if (time == '00') { time = '03'; } const apiResult = await Entry.EXPANSION_BLOCK.weather.getData( 'hour', script.getField('LOCATION', script), date + pad2(time - (time % 3)) ); return apiResult.temp; }, syntax: { js: [], py: [ { syntax: 'Legacy.Weather.get_today_temperature(%1, %2)', blockType: 'param', textParams: [params.getLocation(true), params.getTime(true)], }, ], }, wikiClass: 'weather', }, get_cur_weather: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ { type: 'get_korea_area_code', }, ], type: 'get_cur_weather', }, pyHelpDef: { params: ['A&value'], type: 'get_cur_weather', }, paramsKeyMap: { LOCATION: 0, }, class: 'weather', isNotFor: ['weather'], async func(sprite, script) { const location = script.getValue('LOCATION', script); const apiResult = await Entry.EXPANSION_BLOCK.weather.getDataWithCityCode( 'now', location, null ); return apiResult.sky; }, syntax: { js: [], py: [], }, wikiClass: 'weather', }, get_cur_wind: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ { type: 'get_korea_area_code', }, ], type: 'get_cur_wind', }, pyHelpDef: { params: ['A&value'], type: 'get_cur_wind', }, paramsKeyMap: { LOCATION: 0, }, class: 'weather', isNotFor: ['weather'], async func(sprite, script) { const location = script.getValue('LOCATION', script); const apiResult = await Entry.EXPANSION_BLOCK.weather.getDataWithCityCode( 'now', location, null ); return apiResult.winddir; }, syntax: { js: [], py: [], }, wikiClass: 'weather', }, get_cur_weather_data: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, params.getNowWeatherElement(), ], events: {}, def: { params: [ { type: 'get_korea_area_code', }, params.getNowWeatherElement().value, ], type: 'get_cur_weather_data', }, pyHelpDef: { params: ['A&value', 'B&value'], type: 'get_cur_weather_data', }, paramsKeyMap: { LOCATION: 0, TYPE: 1, }, class: 'weather', isNotFor: ['weather'], async func(sprite, script) { const location = script.getValue('LOCATION', script); const type = Entry.EXPANSION_BLOCK.weather.propertyMap[script.getField('TYPE', script)]; const apiResult = await Entry.EXPANSION_BLOCK.weather.getDataWithCityCode( 'now', location, null ); return apiResult[type]; }, syntax: { js: [], py: [], }, wikiClass: 'weather', }, check_cur_weather: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, params.getSky(), ], events: {}, def: { params: [ { type: 'get_korea_area_code', }, params.getSky().value, ], type: 'check_cur_weather', }, pyHelpDef: { params: ['B&value', 'C&value', 'D&value', null], type: 'check_cur_weather', }, paramsKeyMap: { LOCATION: 0, WEATHER: 1, }, class: 'weather', isNotFor: ['weather'], async func(sprite, script) { const location = script.getValue('LOCATION', script); const apiResult = await Entry.EXPANSION_BLOCK.weather.getDataWithCityCode( 'now', location, null ); return Entry.EXPANSION_BLOCK.weather.checkWeather( apiResult.sky_code, script.getField('WEATHER', script) ); }, syntax: { js: [], py: [], }, wikiClass: 'weather', }, check_cur_finddust: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, params.getFineDust(), ], events: {}, def: { params: [ { type: 'get_korea_area_code', }, params.getFineDust().value, ], type: 'check_cur_finddust', }, pyHelpDef: { params: ['B&value', 'C&value', null], type: 'check_cur_finddust', }, paramsKeyMap: { LOCATION: 0, FINEDUST: 1, }, class: 'weather', isNotFor: ['weather'], async func(sprite, script) { const location = script.getValue('LOCATION', script); const apiResult = await Entry.EXPANSION_BLOCK.weather.getDataWithCityCode( 'now', location, null ); return Entry.EXPANSION_BLOCK.weather.checkFineDust( apiResult.pm10, script.getField('FINEDUST', script) ); }, syntax: { js: [], py: [], }, wikiClass: 'weather', }, get_day_weather: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ params.getDate(), { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ params.getDate().value, { type: 'get_korea_area_code', }, ], type: 'get_day_weather', }, pyHelpDef: { params: ['B&value', 'C&value', null], type: 'get_day_weather', }, paramsKeyMap: { DATE: 0, LOCATION: 1, }, class: 'weather_day', isNotFor: ['weather'], async func(sprite, script) { const location = script.getValue('LOCATION', script); const apiResult = await Entry.EXPANSION_BLOCK.weather.getDataWithCityCode( 'week', location, script.getField('DATE', script) ); return apiResult.sky; }, syntax: { js: [], py: [], }, wikiClass: 'weather', }, get_day_weather_data: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ params.getDate(), { type: 'Block', accept: 'string', defaultType: 'number', }, params.getWeatherElements(), ], events: {}, def: { params: [ params.getDate().value, { type: 'get_korea_area_code', }, params.getWeatherElements().value, ], type: 'get_day_weather_data', }, pyHelpDef: { params: ['B&value', 'C&value', null], type: 'get_day_weather_data', }, paramsKeyMap: { DATE: 0, LOCATION: 1, TYPE: 2, }, class: 'weather_day', isNotFor: ['weather'], async func(sprite, script) { const location = script.getValue('LOCATION', script); const type = Entry.EXPANSION_BLOCK.weather.propertyMap[script.getField('TYPE', script)]; const apiResult = await Entry.EXPANSION_BLOCK.weather.getDataWithCityCode( 'week', location, script.getField('DATE', script) ); return apiResult[type]; }, syntax: { js: [], py: [], }, wikiClass: 'weather', }, check_day_weather: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_boolean_field', statements: [], params: [ params.getDate(), { type: 'Block', accept: 'string', defaultType: 'number', }, params.getSky(), ], events: {}, def: { params: [ params.getDate().value, { type: 'get_korea_area_code', }, params.getSky().value, ], type: 'check_day_weather', }, pyHelpDef: { params: ['B&value', 'C&value', null], type: 'check_day_weather', }, paramsKeyMap: { DATE: 0, LOCATION: 1, WEATHER: 2, }, class: 'weather_day', isNotFor: ['weather'], async func(sprite, script) { const location = script.getValue('LOCATION', script); const apiResult = await Entry.EXPANSION_BLOCK.weather.getDataWithCityCode( 'week', location, script.getField('DATE', script) ); return Entry.EXPANSION_BLOCK.weather.checkWeather( apiResult.sky_code, script.getField('WEATHER', script) ); }, syntax: { js: [], py: [], }, wikiClass: 'weather', }, get_time_weather: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, params.getTime(), ], events: {}, def: { params: [ { type: 'get_korea_area_code', }, params.getTime().value, ], type: 'get_time_weather', }, pyHelpDef: { params: ['A&value', 'B&value', 'C&value'], type: 'get_time_weather', }, paramsKeyMap: { LOCATION: 0, TIME: 1, }, class: 'weather_time', isNotFor: ['weather'], async func(sprite, script) { const location = script.getValue('LOCATION', script); const date = Entry.EXPANSION_BLOCK.weather.localDate; let time = script.getField('TIME', script); // db에 저장하지 않으면서 00시가 없어져서 03시부터 가능.. if (time == '00') { time = '03'; } const apiResult = await Entry.EXPANSION_BLOCK.weather.getDataWithCityCode( 'hour', location, date + pad2(time - (time % 3)) ); return apiResult.sky; }, syntax: { js: [], py: [], }, wikiClass: 'weather', }, get_time_weather_data: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, params.getTime(), params.getTimeWeatherElement(), ], events: {}, def: { params: [ { type: 'get_korea_area_code', }, params.getTime().value, params.getTimeWeatherElement().value, ], type: 'get_time_weather_data', }, pyHelpDef: { params: ['A&value', 'B&value', 'C&value'], type: 'get_time_weather_data', }, paramsKeyMap: { LOCATION: 0, TIME: 1, TYPE: 2, }, class: 'weather_time', isNotFor: ['weather'], async func(sprite, script) { const location = script.getValue('LOCATION', script); const type = Entry.EXPANSION_BLOCK.weather.propertyHourMap[script.getField('TYPE', script)]; const date = Entry.EXPANSION_BLOCK.weather.localDate; let time = script.getField('TIME', script); // db에 저장하지 않으면서 00시가 없어져서 03시부터 가능.. if (time == '00') { time = '03'; } const apiResult = await Entry.EXPANSION_BLOCK.weather.getDataWithCityCode( 'hour', location, date + pad2(time - (time % 3)) ); return apiResult[type]; }, syntax: { js: [], py: [], }, wikiClass: 'weather', }, check_time_weather: { color: EntryStatic.colorSet.block.default.EXPANSION, outerLine: EntryStatic.colorSet.block.darken.EXPANSION, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, params.getTime(), params.getSky(), ], events: {}, def: { params: [ { type: 'get_korea_area_code', }, params.getTime().value, params.getSky().value, ], type: 'check_time_weather', }, pyHelpDef: { params: ['B&value', 'C&value', null], type: 'check_time_weather', }, paramsKeyMap: { LOCATION: 0, TIME: 1, WEATHER: 2, }, class: 'weather_time', isNotFor: ['weather'], async func(sprite, script) { const location = script.getValue('LOCATION', script); const date = Entry.EXPANSION_BLOCK.weather.localDate; let time = script.getField('TIME', script); // db에 저장하지 않으면서 00시가 없어져서 03시부터 가능.. if (time == '00') { time = '03'; } const apiResult = await Entry.EXPANSION_BLOCK.weather.getDataWithCityCode( 'hour', location, date + pad2(time - (time % 3)) ); return Entry.EXPANSION_BLOCK.weather.checkWeather( apiResult.sky_code, script.getField('WEATHER', script) ); }, syntax: { js: [], py: [], }, wikiClass: 'weather', }, }; }; ================================================ FILE: src/playground/blocks/block_flow.js ================================================ module.exports = { getBlocks() { return { wait_second: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['2'], }, null, ], type: 'wait_second', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'wait_second', }, paramsKeyMap: { SECOND: 0, }, class: 'delay', isNotFor: [], func(sprite, script) { if (!script.isStart) { script.isStart = true; script.timeFlag = 1; let timeValue = script.getNumberValue('SECOND', script); const fps = Entry.FPS || 60; timeValue = (60 / fps) * timeValue * 1000; const blockId = script.block.id; Entry.TimeWaitManager.add( blockId, () => { script.timeFlag = 0; }, timeValue ); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Entry.wait_for_sec(%1)', }, ], }, }, repeat_basic: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic_loop', statements: [ { accept: 'basic', }, ], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, ], type: 'repeat_basic', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'repeat_basic', }, paramsKeyMap: { VALUE: 0, }, statementsKeyMap: { DO: 0, }, class: 'repeat', isNotFor: [], func(sprite, script) { if (!script.isLooped) { const iterNumber = script.getNumberValue('VALUE', script); script.isLooped = true; if (iterNumber < 0) { throw new Error(Lang.Blocks.FLOW_repeat_basic_errorMsg); } script.iterCount = Math.floor(iterNumber); } if (script.iterCount !== 0 && !(script.iterCount < 0)) { script.iterCount--; return script.getStatement('DO', script); } else { delete script.isLooped; delete script.iterCount; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'for i in range(%1):\n$1', template: 'for i in range(%1):', idChar: ['i', 'j', 'k'], }, ], }, }, repeat_inf: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic_loop', statements: [ { accept: 'basic', }, ], params: [ { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, { type: 'Block', accept: 'Boolean', }, ], events: {}, def: { params: [null], type: 'repeat_inf', }, pyHelpDef: { params: [ null, { type: 'boolean_shell', params: ['A'], }, ], type: 'repeat_inf', }, statementsKeyMap: { DO: 0, }, class: 'repeat', isNotFor: [], func(sprite, script) { script.isLooped = true; return script.getStatement('DO'); }, syntax: { js: [], py: [ { syntax: 'while True:\n$1', template: 'while %2\n:', textParams: [ undefined, { type: 'Block', accept: 'boolean', }, ], }, ], }, }, repeat_while_true: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic_loop', statements: [ { accept: 'basic', }, ], params: [ { type: 'Block', accept: 'boolean', }, { type: 'Dropdown', options: [ [Lang.Blocks.FLOW_repeat_while_true_until, 'until'], [Lang.Blocks.FLOW_repeat_while_true_while, 'while'], ], value: 'until', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.FLOW, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'True', }, null, null, ], type: 'repeat_while_true', }, pyHelpDef: { params: [ { type: 'boolean_shell', params: ['A'], }, null, null, ], type: 'repeat_while_true', }, paramsKeyMap: { BOOL: 0, OPTION: 1, }, statementsKeyMap: { DO: 0, }, class: 'repeat', isNotFor: [], func(sprite, script) { let value = script.getBooleanValue('BOOL', script); if (script.getField('OPTION', script) === 'until') { value = !value; } script.isLooped = value; return value ? script.getStatement('DO', script) : script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'while %1 %2:\n$1', template: 'while not %1:', }, ], }, }, stop_repeat: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'stop_repeat', }, class: 'repeat', isNotFor: [], func(sprite, script) { return this.executor.breakLoop(); }, syntax: { js: [], py: ['break'] }, }, continue_repeat: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'continue_repeat', }, class: 'repeat', isNotFor: [], func(sprite, script) { return this.executor.continueLoop(); }, syntax: { js: [], py: ['continue'] }, }, _if: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic_loop', statements: [ { accept: 'basic', }, ], params: [ { type: 'Block', accept: 'boolean', }, { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'True', }, null, ], type: '_if', }, pyHelpDef: { params: [ { type: 'boolean_shell', params: ['A'], }, null, ], type: '_if', }, paramsKeyMap: { BOOL: 0, }, statementsKeyMap: { STACK: 0, }, class: 'condition', isNotFor: [], func(sprite, script) { if (script.isCondition) { delete script.isCondition; return script.callReturn(); } const value = script.getBooleanValue('BOOL', script); if (value) { script.isCondition = true; return script.getStatement('STACK', script); } else { return script.callReturn(); } }, syntax: { js: [], py: [{ syntax: 'if %1:\n$1', template: 'if %1:' }], }, }, if_else: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic_double_loop', statements: [ { accept: 'basic', }, { accept: 'basic', }, ], params: [ { type: 'Block', accept: 'boolean', }, { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, { type: 'LineBreak', }, ], events: {}, def: { params: [ { type: 'True', }, null, ], type: 'if_else', }, pyHelpDef: { params: [ { type: 'boolean_shell', params: ['A'], }, null, ], type: 'if_else', }, paramsKeyMap: { BOOL: 0, }, statementsKeyMap: { STACK_IF: 0, STACK_ELSE: 1, }, class: 'condition', isNotFor: [], func(sprite, script) { if (script.isCondition) { delete script.isCondition; return script.callReturn(); } const value = script.getBooleanValue('BOOL', script); script.isCondition = true; if (value) { return script.getStatement('STACK_IF', script); } else { return script.getStatement('STACK_ELSE', script); } }, syntax: { js: [], py: [ { syntax: 'if %1:\n$1\nelse:\n$2', template: 'if %1: %3 else:', textParams: [ { type: 'Block', accept: 'boolean', }, undefined, { type: 'LineBreak', }, ], }, ], }, }, wait_until_true: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'boolean', }, { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'True', }, null, ], type: 'wait_until_true', }, pyHelpDef: { params: [ { type: 'boolean_shell', params: ['A'], }, null, ], type: 'wait_until_true', }, paramsKeyMap: { BOOL: 0, }, class: 'wait', isNotFor: [], func(sprite, script) { const value = script.getBooleanValue('BOOL', script); if (value) { return script.callReturn(); } else { return script; } }, syntax: { js: [], py: ['Entry.wait_until(%1)'] }, }, stop_object: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.FLOW_stop_object_all, 'all'], [Lang.Blocks.FLOW_stop_object_this_object, 'thisOnly'], [Lang.Blocks.FLOW_stop_object_this_thread, 'thisThread'], [Lang.Blocks.FLOW_stop_object_other_thread, 'otherThread'], [Lang.Blocks.FLOW_stop_object_other_objects, 'other_objects'], ], value: 'all', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.FLOW, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, ], events: {}, def: { params: [null, null], type: 'stop_object', }, pyHelpDef: { params: ['A&value', null], type: 'stop_object', }, paramsKeyMap: { TARGET: 0, }, class: 'terminate', isNotFor: [], func(sprite, script) { const object = sprite.parent; switch (script.getField('TARGET', script)) { case 'all': Entry.container.mapObject(function(obj) { if (!obj.objectType) { return; } obj.script.clearExecutors(); }); return this.die(); case 'thisOnly': object.script.clearExecutorsByEntity(sprite); return this.die(); case 'thisObject': object.script.clearExecutors(); return this.die(); case 'thisThread': return this.die(); case 'otherThread': { const executor = this.executor; const code = object.script; const executors = code.executors; const spriteId = sprite.id; for (let i = 0; i < executors.length; i++) { const currentExecutor = executors[i]; if ( currentExecutor !== executor && currentExecutor.entity.id === spriteId ) { code.removeExecutor(currentExecutor); --i; } } return script.callReturn(); } case 'other_objects': Entry.container.mapObject(function(obj) { if (!obj.objectType || obj === object) { return; } obj.script.clearExecutors(); }); return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Entry.stop_code(%1)', textParams: [ { type: 'Dropdown', options: [ [Lang.Blocks.FLOW_stop_object_all, 'all'], [Lang.Blocks.FLOW_stop_object_this_object, 'thisOnly'], [Lang.Blocks.FLOW_stop_object_this_thread, 'thisThread'], [Lang.Blocks.FLOW_stop_object_other_thread, 'otherThread'], [ Lang.Blocks.FLOW_stop_object_other_objects, 'other_objects', ], ], value: 'all', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.FLOW, converter: Entry.block.converters.returnStringValue, codeMap: 'Entry.CodeMap.Entry.stop_object[0]', }, ], }, ], }, }, restart_project: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic_without_next', statements: [], params: [ { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'restart_project', }, class: 'terminate', isNotFor: [], func(sprite, script) { Entry.engine.toggleStop().then(() => { Entry.engine.toggleRun(); }); }, syntax: { js: [], py: ['Entry.start_again()'] }, }, when_clone_start: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_clone.svg', size: 14, position: { x: 0, y: -2, }, }, ], events: {}, def: { params: [null], type: 'when_clone_start', }, class: 'clone', isNotFor: [], func(sprite, script) { return script.callReturn(); }, event: 'when_clone_start', syntax: { js: [], py: [ { syntax: 'def when_make_clone():', blockType: 'event', }, ], }, }, create_clone: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'clone', fontSize: 10, textColor: '#fff', bgColor: EntryStatic.colorSet.block.darken.FLOW, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, ], events: {}, def: { params: [null, null], type: 'create_clone', }, pyHelpDef: { params: ['A&value', null], type: 'create_clone', }, paramsKeyMap: { VALUE: 0, }, class: 'clone', isNotFor: [], func(sprite, script) { const targetSpriteId = script.getField('VALUE', script); const returnBlock = script.callReturn(); if (targetSpriteId === 'self') { sprite.parent.addCloneEntity(sprite.parent, sprite, null); } else { const object = Entry.container.getObject(targetSpriteId); object.addCloneEntity(sprite.parent, null, null); } return returnBlock; }, syntax: { js: [], py: [ { syntax: 'Entry.make_clone_of(%1)', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'clone', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.FLOW, converter: Entry.block.converters.returnStringKey, codeMap: 'Entry.CodeMap.Entry.create_clone[0]', }, ], }, ], }, }, delete_clone: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic_without_next', statements: [], params: [ { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'delete_clone', }, class: 'clone', isNotFor: [], func(sprite, script) { if (!sprite.isClone) { return script.callReturn(); } sprite.removeClone(); return this.die(); }, syntax: { js: [], py: ['Entry.remove_this_clone()'] }, }, remove_all_clones: { color: EntryStatic.colorSet.block.default.FLOW, outerLine: EntryStatic.colorSet.block.darken.FLOW, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/flow_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'remove_all_clones', }, class: 'clone', isNotFor: [], func(sprite, script) { let clonedEntities = sprite.parent.getClonedEntities(); clonedEntities.map(function(entity) { entity.removeClone(); }); clonedEntities = null; return script.callReturn(); }, syntax: { js: [], py: ['Entry.remove_all_clone()'] }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_func.js ================================================ import _cloneDeep from 'lodash/cloneDeep'; module.exports = { getBlocks() { return { functionAddButton: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, isNotFor: ['functionInit'], params: [ { type: 'Text', text: Lang.Workspace.function_create, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], def: { type: 'functionAddButton', }, events: { mousedown: [ function () { Entry.do('funcEditStart', Entry.generateHash()); }, ], }, }, function_name: { template: '%1', skeleton: 'basic_text', skeletonOptions: { contentPos: { x: 5, }, }, color: EntryStatic.colorSet.common.TRANSPARENT, fontColor: EntryStatic.colorSet.common.TEXT, params: [ { type: 'Text', text: '', color: EntryStatic.colorSet.common.TEXT, align: 'left', }, ], class: 'properties', isNotFor: ['functionEdit'], events: {}, }, showFunctionPropsButton: { template: '%1', skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, class: 'properties', isNotFor: ['functionEdit'], params: [ { type: 'Text', text: Lang.Workspace.function_attribute, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], def: { type: 'showFunctionPropsButton', }, events: { mousedown: [ function () { Entry.do( 'playgroundChangeViewMode', 'variable', Entry.playground.selectedViewMode ); Entry.variableContainer.selectFilter('func'); Entry.variableContainer.select(Entry.Func.targetFunc); }, ], }, wikiClass: 'function', }, set_func_variable: { template: Lang.template.set_variable, color: EntryStatic.colorSet.block.default.FUNC, outerLine: EntryStatic.colorSet.block.darken.FUNC, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName(block) { const func = Entry.variableContainer.getFunctionByBlockId(block.id) || Entry.Func.targetFunc || {}; const localVariables = func.localVariables || []; if (localVariables.length) { return localVariables.map((localVariable) => { const { id, name } = localVariable; if (!id) { localVariable.id = `${func.id}_${Entry.generateHash()}`; } return [name, localVariable.id]; }); } else { return [[Lang.Blocks.no_target, 'null']]; } }, fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.FUNC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, defaultValue: (_value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return null; }, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/func_icon.svg', size: 11, }, ], events: { updateFuncVariableList: [ function () { const func = Entry.Func.targetFunc || {}; func?.content ?.getBlockList(false, 'set_func_variable') ?.forEach((block) => { block?.view?.getParam(0)?.updateValue(true); }); }, ], }, def: { params: [ null, { type: 'text', params: ['10'], }, null, ], type: 'set_func_variable', }, paramsKeyMap: { VARIABLE: 0, VALUE: 1, }, class: 'local_variable', isNotFor: ['useLocalVariables'], func(sprite, script) { const variableId = script.getField('VARIABLE', script); const value = script.getValue('VALUE', script); const [funcId, idx] = variableId.split('_'); const func = Entry.variableContainer.getFunction(funcId, idx); func.setValue(value, variableId, script.executor.localVariables); return script.callReturn(); }, syntax: { js: [], py: [ { syntax: '%1 = %2', passTest: true, blockType: 'variable', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'variables', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnRawStringKey, }, { type: 'Block', accept: 'string', }, ], }, ], }, wikiClass: 'function', }, get_func_variable: { template: '%1 %2', color: EntryStatic.colorSet.block.default.FUNC, outerLine: EntryStatic.colorSet.block.darken.FUNC, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName(block) { const func = Entry.variableContainer.getFunctionByBlockId(block.id) || Entry.Func.targetFunc || {}; const localVariables = func.localVariables || []; if (localVariables.length) { return localVariables.map((localVariable) => { const { id, name } = localVariable; if (!id) { localVariable.id = `${func.id}_${Entry.generateHash()}`; } return [name, localVariable.id]; }); } else { return [[Lang.Blocks.no_target, 'null']]; } }, fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.FUNC, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, defaultValue: (_value, options) => { if (options[0] && options[0][1]) { return options[0][1]; } return null; }, }, { type: 'Text', text: Lang.Blocks.VARIABLE_get_variable_1, color: 'white', }, ], events: { updateFuncVariableList: [ function () { const func = Entry.Func.targetFunc || {}; func?.content ?.getBlockList(false, 'get_func_variable') ?.forEach((block) => { block?.view?.getParam(0)?.updateValue(true); }); }, ], }, def: { params: [null], type: 'get_func_variable', }, paramsKeyMap: { VARIABLE: 0, }, class: 'local_variable', isNotFor: ['useLocalVariables'], func(sprite, script) { const variableId = script.getField('VARIABLE', script); const [funcId] = variableId.split('_'); const func = Entry.variableContainer.getFunction(funcId); return func.getValue(variableId, script.executor.localVariables); }, syntax: { js: [], py: [], }, wikiClass: 'function', }, function_create_value: { skeleton: 'basic_create_value', statements: [ { accept: 'basic', }, ], color: EntryStatic.colorSet.block.default.FUNC, outerLine: EntryStatic.colorSet.block.darken.FUNC, event: 'funcDef', params: [ { type: 'Block', accept: 'param', value: { type: 'function_field_label', params: [Lang.Blocks.FUNC], copyable: false, }, }, { type: 'Indicator', img: 'block_icon/func_icon.svg', size: 11, }, { type: 'LineBreak', }, { type: 'Block', accept: 'string', }, ], paramsKeyMap: { FIELD: 0, VALUE: 3, }, statementsKeyMap: { DO: 0, }, func(sprite, script) { if (!script.isFunc) { script.isFunc = true; script.executor.result = script; return script.getStatement('DO', script); } else { delete script.isFunc; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: '%1', keyOption: 'function_create_value', }, ], }, wikiClass: 'function', }, function_general: { skeleton: 'basic', color: EntryStatic.colorSet.block.default.FUNC, outerLine: EntryStatic.colorSet.block.darken.FUNC, class: 'function_executor', params: [ { type: 'Indicator', img: 'block_icon/func_icon.svg', size: 11, }, ], events: { dataAdd: [ function (block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_functionRefs', block); } }, ], dataDestroy: [ function (block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_functionRefs', block); } }, ], dblclick: [ function (blockView) { const mode = blockView.getBoard().workspace.getMode(); if (mode !== Entry.Workspace.MODE_BOARD) { return; } if (Entry.type !== 'workspace') { return; } const block = blockView.block; const id = block.getFuncId(); Entry.do('funcEditStart', id); }, ], }, func(entity, script) { if (!this.initiated) { this.initiated = true; Entry.callStackLength++; const func = Entry.variableContainer.getFunction(this.block.getFuncId()); this.funcCode = func.content; this.funcExecutor = this.funcCode.raiseEvent('funcDef', entity)[0]; this.funcExecutor.register.params = this.values; this.funcExecutor.register.paramMap = func.paramMap; this.funcExecutor.parentExecutor = this.executor; this.funcExecutor.parentScope = script; this.funcExecutor.isFuncExecutor = true; this.funcExecutor.localVariables = _cloneDeep(func.localVariables); } const { promises } = this.funcExecutor.execute(); if (!this.funcExecutor.isEnd()) { if (promises.length) { return Entry.Code.funcAsyncExecute( this.funcCode, this.funcExecutor, promises ); } else { this.funcCode.removeExecutor(this.funcExecutor); return Entry.STATIC.BREAK; } } else { this.funcCode.removeExecutor(this.funcExecutor); } Entry.callStackLength--; }, syntax: { js: [], py: [''] }, wikiClass: 'function', }, function_value: { skeleton: 'basic_string_field', color: EntryStatic.colorSet.block.default.FUNC, outerLine: EntryStatic.colorSet.block.darken.FUNC, class: 'function_executor', params: [], events: { dataAdd: [ function (block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_functionRefs', block); } }, ], dataDestroy: [ function (block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_functionRefs', block); } }, ], dblclick: [ function (blockView) { const mode = blockView.getBoard().workspace.getMode(); if (mode !== Entry.Workspace.MODE_BOARD) { return; } if (Entry.type !== 'workspace') { return; } const block = blockView.block; const id = block.getFuncId(); Entry.do('funcEditStart', id); }, ], }, func(entity, script) { if (!this.initiated) { this.initiated = true; Entry.callStackLength++; const func = Entry.variableContainer.getFunction(this.block.getFuncId()); this.funcCode = func.content; this.funcExecutor = this.funcCode.raiseEvent('funcDef', entity)[0]; this.funcExecutor.register.params = this.values; this.funcExecutor.register.paramMap = func.paramMap; this.funcExecutor.parentExecutor = this.executor; this.funcExecutor.parentScope = script; this.funcExecutor.isFuncExecutor = true; this.funcExecutor.localVariables = _cloneDeep(func.localVariables); } this.funcExecutor.result = this.funcExecutor.scope; const firstBlock = this.funcExecutor?.scope?.block?.statements[0]?.getFirstBlock(); if (firstBlock) { this.funcExecutor.scope = new Entry.Scope(firstBlock, this.funcExecutor); } const { promises } = this.funcExecutor.execute(); if (!this.funcExecutor.isEnd()) { if (promises.length) { return Entry.Code.funcValueAsyncExecute( this.funcCode, this.funcExecutor, promises ); } else { return Entry.Code.funcRestExecute(this.funcCode, this.funcExecutor); } } else { this.funcCode.removeExecutor(this.funcExecutor); } Entry.callStackLength--; const scope = this.funcExecutor.result; scope.values = scope.getParams(); return scope.getValue('VALUE', scope); }, syntax: { js: [], py: [''] }, wikiClass: 'function', }, function_field_label: { skeleton: 'basic_param', isNotFor: ['functionEdit'], color: '#f9c535', params: [ { type: 'TextInput', value: Lang.Blocks.FUNCTION_explanation_1, }, { type: 'Output', accept: 'param', }, ], paramsKeyMap: { NAME: 0, NEXT: 1, }, def: { params: [Lang.Blocks.FUNCTION_explanation_1], type: 'function_field_label', }, //"syntax": {"js": [], "py": ["%1function_field_label#"]} syntax: { js: [], py: ['name'] }, wikiClass: 'function', }, function_field_string: { skeleton: 'basic_param', isNotFor: ['functionEdit'], color: EntryStatic.colorSet.block.lighten.CALC, params: [ { type: 'Block', accept: 'string', restore: true, }, { type: 'Output', accept: 'param', }, ], paramsKeyMap: { PARAM: 0, NEXT: 1, }, def: { params: [ { type: 'text', params: [Lang.template.function_param_string], }, ], type: 'function_field_string', }, syntax: { js: [], py: ['value'] }, wikiClass: 'function', }, function_field_boolean: { skeleton: 'basic_param', isNotFor: ['functionEdit'], color: EntryStatic.colorSet.block.default.JUDGE, params: [ { type: 'Block', accept: 'boolean', restore: true, }, { type: 'Output', accept: 'param', }, ], paramsKeyMap: { PARAM: 0, NEXT: 1, }, def: { params: [ { type: 'True', params: [Lang.template.function_param_boolean], }, ], type: 'function_field_boolean', }, syntax: { js: [], py: ['boolean'] }, wikiClass: 'function', }, function_param_string: { skeleton: 'basic_string_field', color: EntryStatic.colorSet.block.lighten.CALC, fontColor: '#000', template: '%1 %2', events: { viewAdd: [ function () { if (Entry.Func.isEdit) { Entry.Func.refreshMenuCode(); } }, ], }, func() { return this.executor.register.params[ this.executor.register.paramMap[this.block.type] ]; }, syntax: { js: [], py: [''] }, wikiClass: 'function', }, function_param_boolean: { skeleton: 'basic_boolean_field', color: EntryStatic.colorSet.block.default.JUDGE, template: '%1 %2', events: { viewAdd: [ function () { if (Entry.Func.isEdit) { Entry.Func.refreshMenuCode(); } }, ], }, func() { return this.executor.register.params[ this.executor.register.paramMap[this.block.type] ]; }, syntax: { js: [], py: [''] }, wikiClass: 'function', }, function_create: { skeleton: 'basic_create', statements: [ { accept: 'basic', }, ], color: EntryStatic.colorSet.block.default.FUNC, outerLine: EntryStatic.colorSet.block.darken.FUNC, event: 'funcDef', params: [ { type: 'Block', accept: 'param', value: { type: 'function_field_label', params: [Lang.Blocks.FUNC], copyable: false, }, }, { type: 'Indicator', img: 'block_icon/func_icon.svg', size: 11, }, ], paramsKeyMap: { FIELD: 0, }, statementsKeyMap: { DO: 0, }, func(sprite, script) { if (!script.isFunc) { script.isFunc = true; script.executor.result = script; return script.getStatement('DO', script); } else { delete script.isFunc; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: '%1', keyOption: 'function_create', }, ], }, wikiClass: 'function', }, }; }, }; ================================================ FILE: src/playground/blocks/block_judgement.js ================================================ import { GEHelper } from '../../graphicEngine/GEHelper'; import { keyInputList } from './inputs/keyboard'; module.exports = { getBlocks() { return { is_clicked: { color: EntryStatic.colorSet.block.default.JUDGE, outerLine: EntryStatic.colorSet.block.darken.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.JUDGEMENT_is_clicked, color: '#FFF', }, ], events: {}, def: { params: [null], type: 'is_clicked', }, class: 'boolean_input', isNotFor: [], func(sprite, script) { return Entry.stage.isClick; }, syntax: { js: [], py: [ { syntax: 'Entry.is_mouse_clicked()', blockType: 'param', }, ], }, }, is_object_clicked: { color: EntryStatic.colorSet.block.default.JUDGE, outerLine: EntryStatic.colorSet.block.darken.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.JUDGEMENT_is_object_clicked, color: '#FFF', }, ], events: {}, def: { params: [null], type: 'is_object_clicked', }, class: 'boolean_input', isNotFor: ['python_disable'], func(sprite, script) { const objId = sprite.id; if (Entry.stage.clickedObjectId == objId) { return true; } return false; }, syntax: { js: [], py: [] }, }, is_press_some_key: { color: EntryStatic.colorSet.block.default.JUDGE, outerLine: EntryStatic.colorSet.block.darken.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Keyboard', options: keyInputList, value: 'next', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.JUDGE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.JUDGEMENT_is_press_some_key_2, color: '#FFF', }, ], events: {}, def: { params: ['81', null], type: 'is_press_some_key', }, pyHelpDef: { params: ['A&value', null], type: 'is_press_some_key', }, paramsKeyMap: { VALUE: 0, }, class: 'boolean_input', isNotFor: [], func(sprite, script) { const keycode = Number(script.getField('VALUE', script)); return Entry.pressedKeys.indexOf(keycode) >= 0; }, syntax: { js: [], py: [ { syntax: 'Entry.is_key_pressed(%1)', blockType: 'param', textParams: [ { type: 'Dropdown', value: 'next', options: keyInputList, converter: Entry.block.converters.keyboardCode, }, ], }, ], }, }, reach_something: { color: EntryStatic.colorSet.block.default.JUDGE, outerLine: EntryStatic.colorSet.block.darken.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.JUDGEMENT_reach_something_1, color: '#FFF', }, { type: 'DropdownDynamic', value: null, menuName: 'collision', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.JUDGE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.JUDGEMENT_reach_something_2, color: '#FFF', }, ], events: {}, def: { params: [null, null, null], type: 'reach_something', }, pyHelpDef: { params: [null, 'A&value', null], type: 'reach_something', }, paramsKeyMap: { VALUE: 1, }, class: 'boolean_collision', isNotFor: [], func(sprite, script) { if (sprite.getVisible && !sprite.getVisible()) { return false; } const targetSpriteId = script.getField('VALUE', script); const reg = /wall/; const ath = 0.2; const object = sprite.object; const isWall = reg.test(targetSpriteId); const collision = ndgmr.checkPixelCollision; if (isWall) { const wall = Entry.stage.wall; switch (targetSpriteId) { case 'wall': return !!( collision(object, wall.up, ath, false) || collision(object, wall.down, ath, false) || collision(object, wall.left, ath, false) || collision(object, wall.right, ath, false) ); case 'wall_up': return !!collision(object, wall.up, ath, false); case 'wall_down': return !!collision(object, wall.down, ath, false); case 'wall_right': return !!collision(object, wall.right, ath, false); case 'wall_left': return !!collision(object, wall.left, ath, false); } } else if (targetSpriteId === 'mouse') { return GEHelper.hitTestMouse(object); } else { const targetSprite = Entry.container.getEntity(targetSpriteId); if (targetSprite.type === 'textBox' || sprite.type === 'textBox') { const targetBound = GEHelper.getTransformedBounds(targetSprite.object); const bound = GEHelper.getTransformedBounds(object); if (Entry.checkCollisionRect(bound, targetBound)) { return true; } const clonedEntities = targetSprite.parent.clonedEntities; for (let i = 0, len = clonedEntities.length; i < len; i++) { const entity = clonedEntities[i]; if (entity.isStamp || !entity.getVisible()) { continue; } if ( Entry.checkCollisionRect( bound, GEHelper.getTransformedBounds(entity.object) ) ) { return true; } } } else { if ( targetSprite.getVisible() && collision(object, targetSprite.object, ath, false) ) { return true; } const clonedEntities = targetSprite.parent.clonedEntities; for (let i = 0, len = clonedEntities.length; i < len; i++) { const entity = clonedEntities[i]; if (entity.isStamp || !entity.getVisible()) { continue; } if (collision(object, entity.object, ath, false)) { return true; } } } } return false; }, syntax: { js: [], py: [ { syntax: 'Entry.is_touched(%2)', blockType: 'param', textParams: [ undefined, { type: 'DropdownDynamic', value: null, menuName: 'collision', fontSize: 11, converter: Entry.block.converters.returnObjectOrStringValue, codeMap: 'Entry.CodeMap.Entry.reach_something[1]', }, ], }, ], }, }, is_type: { color: EntryStatic.colorSet.block.default.JUDGE, outerLine: EntryStatic.colorSet.block.darken.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.JUDGEMENT_is_type_1, color: '#FFF', }, { type: 'Dropdown', options: [ [Lang.Blocks.is_type_number, 'number'], [Lang.Blocks.is_type_en, 'en'], [Lang.Blocks.is_type_ko, 'ko'], ], value: 'number', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.JUDGE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.JUDGEMENT_is_type_2, color: '#FFF', }, ], events: {}, def: { params: ['10', null, 'number', null], type: 'is_type', }, paramsKeyMap: { VALUE: 0, TYPE: 2, }, class: 'boolean_type', isNotFor: ['python_disable'], func(sprite, script) { const value = script.getStringValue('VALUE', script); const type = script.getField('TYPE', script); if (type === 'number') { return Entry.Utils.isNumber(value); } else if (type === 'en') { const pattern = /^[a-zA-Z]+$/; return pattern.test(value); } else if (type === 'ko') { const pattern = /^[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]+$/; return pattern.test(value); } return false; }, syntax: { js: [], py: [], }, }, boolean_basic_operator: { color: EntryStatic.colorSet.block.default.JUDGE, outerLine: EntryStatic.colorSet.block.darken.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Dropdown', options: [ ['=', 'EQUAL'], ['!=', 'NOT_EQUAL'], ['>', 'GREATER'], ['<', 'LESS'], ['≥', 'GREATER_OR_EQUAL'], ['≤', 'LESS_OR_EQUAL'], ], value: 'EQUAL', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.JUDGE, noArrow: true, }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'text', params: ['10'], }, 'EQUAL', { type: 'text', params: ['10'], }, ], type: 'boolean_basic_operator', }, pyHelpDef: { params: [ { type: 'text', params: ['A&value'], }, 'EQUAL', { type: 'text', params: ['B&value'], }, ], type: 'boolean_basic_operator', }, defs: [ { params: [ { type: 'text', params: ['10'], }, 'EQUAL', { type: 'text', params: ['10'], }, ], type: 'boolean_basic_operator', }, { params: [ { type: 'text', params: ['10'], }, 'NOT_EQUAL', { type: 'text', params: ['10'], }, ], type: 'boolean_basic_operator', }, { params: [ { type: 'text', params: ['10'], }, 'GREATER', { type: 'text', params: ['10'], }, ], type: 'boolean_basic_operator', }, { params: [ { type: 'text', params: ['10'], }, 'LESS', { type: 'text', params: ['10'], }, ], type: 'boolean_basic_operator', }, { params: [ { type: 'text', params: ['10'], }, 'GREATER_OR_EQUAL', { type: 'text', params: ['10'], }, ], type: 'boolean_basic_operator', }, { params: [ { type: 'text', params: ['10'], }, 'LESS_OR_EQUAL', { type: 'text', params: ['10'], }, ], type: 'boolean_basic_operator', }, ], paramsKeyMap: { LEFTHAND: 0, OPERATOR: 1, RIGHTHAND: 2, }, class: 'boolean_compare', isNotFor: [], func(sprite, script) { const operator = script.getField('OPERATOR', script); let [leftValue, rightValue] = script.getValues( ['LEFTHAND', 'RIGHTHAND'], script ); if (typeof leftValue === 'string' && leftValue.length) { const leftNumber = Number(leftValue); if (!isNaN(leftNumber)) { leftValue = leftNumber; } } if (typeof rightValue === 'string' && rightValue.length) { const rightNumber = Number(rightValue); if (!isNaN(rightNumber)) { rightValue = rightNumber; } } switch (operator) { case 'EQUAL': return leftValue === rightValue; case 'NOT_EQUAL': return leftValue != rightValue; case 'GREATER': return leftValue > rightValue; case 'LESS': return leftValue < rightValue; case 'GREATER_OR_EQUAL': return leftValue >= rightValue; case 'LESS_OR_EQUAL': return leftValue <= rightValue; } }, syntax: { js: [], py: [ { syntax: '(%1 %2 %3)', template: '%1 %2 %3', keyOption: 'boolean_basic_operator', blockType: 'param', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Dropdown', options: [ ['=', 'EQUAL'], ['!=', 'NOT_EQUAL'], ['>', 'GREATER'], ['<', 'LESS'], ['≥', 'GREATER_OR_EQUAL'], ['≤', 'LESS_OR_EQUAL'], ], value: 'EQUAL', fontSize: 11, noArrow: true, converter: Entry.block.converters.returnOperator, }, { type: 'Block', accept: 'string', }, ], }, ], }, }, boolean_and_or: { color: EntryStatic.colorSet.block.default.JUDGE, outerLine: EntryStatic.colorSet.block.darken.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Block', accept: 'boolean', }, { type: 'Dropdown', options: [ [Lang.Blocks.JUDGEMENT_boolean_and, 'AND'], [Lang.Blocks.JUDGEMENT_boolean_or, 'OR'], ], value: 'AND', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.JUDGE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'boolean', }, ], events: {}, def: { params: [{ type: 'True' }, 'AND', { type: 'True' }], type: 'boolean_and_or', }, defs: [ { params: [{ type: 'True' }, 'AND', { type: 'True' }], type: 'boolean_and_or', }, { params: [{ type: 'True' }, 'OR', { type: 'False' }], type: 'boolean_and_or', }, ], pyHelpDef: { params: [ { type: 'boolean_shell', params: ['A'], }, 'AND', { type: 'boolean_shell', params: ['B'], }, ], type: 'boolean_and_or', }, paramsKeyMap: { LEFTHAND: 0, OPERATOR: 1, RIGHTHAND: 2, }, func(sprite, script) { const operator = script.getField('OPERATOR', script); let [leftValue, rightValue] = script.getValues( ['LEFTHAND', 'RIGHTHAND'], script ); leftValue = Boolean(leftValue); rightValue = Boolean(rightValue); if (operator === 'AND') { return leftValue && rightValue; } else { return leftValue || rightValue; } }, syntax: { js: [], py: [ { syntax: '(%1 %2 %3)', template: '%1 %2 %3', blockType: 'param', textParams: [ { type: 'Block', accept: 'boolean', }, { type: 'Dropdown', options: [ [Lang.Blocks.JUDGEMENT_boolean_and, 'AND'], [Lang.Blocks.JUDGEMENT_boolean_or, 'OR'], ], converter: Entry.block.converters.returnOperator, value: 'AND', fontSize: 11, }, { type: 'Block', accept: 'boolean', }, ], }, ], }, }, boolean_not: { color: EntryStatic.colorSet.block.default.JUDGE, outerLine: EntryStatic.colorSet.block.darken.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.JUDGEMENT_boolean_not_1, color: '#FFF', }, { type: 'Block', accept: 'boolean', }, { type: 'Text', text: Lang.Blocks.JUDGEMENT_boolean_not_2, color: '#FFF', }, ], events: {}, def: { params: [null, { type: 'True' }, null], type: 'boolean_not', }, pyHelpDef: { params: [null, { type: 'boolean_shell' }, null], type: 'boolean_not', }, paramsKeyMap: { VALUE: 1, }, class: 'boolean', isNotFor: [], func(sprite, script) { return !script.getBooleanValue('VALUE', script); }, syntax: { js: [], py: [ { syntax: 'not (%2)', template: 'not %2', blockType: 'param', textParams: [ undefined, { type: 'Block', accept: 'Boolean', }, ], }, ], }, }, is_boost_mode: { color: EntryStatic.colorSet.block.default.JUDGE, outerLine: EntryStatic.colorSet.block.darken.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.JUDGEMENT_is_boost_mode, color: '#FFF', }, ], events: {}, def: { params: [null], type: 'is_boost_mode', }, class: 'boolean_input', isNotFor: [], func() { return !!Entry.options.useWebGL; }, syntax: { js: [], py: [ { syntax: 'Entry.is_boost_mode()', blockType: 'param', }, ], }, }, is_current_device_type: { color: EntryStatic.colorSet.block.default.JUDGE, outerLine: EntryStatic.colorSet.block.darken.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.desktop, 'desktop'], [Lang.Blocks.tablet, 'tablet'], [Lang.Blocks.smartphone, 'mobile'], ], value: 'desktop', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.JUDGE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, ], events: {}, def: { params: [null], type: 'is_current_device_type', }, pyHelpDef: { params: ['A&value'], type: 'is_current_device_type', }, class: 'boolean_device', isNotFor: [], paramsKeyMap: { DEVICE: 0, }, func(sprite, script) { const device = script.getField('DEVICE', script); const deviceType = Entry.Utils.getDeviceType(); if (device !== 'desktop') { return deviceType === device; } else if (deviceType !== 'mobile' && deviceType !== 'tablet') { return true; } return false; }, syntax: { js: [], py: [ { syntax: 'Entry.is_current_device_type(%1)', blockType: 'param', textParams: [ { type: 'Dropdown', options: [ [Lang.Blocks.desktop, 'desktop'], [Lang.Blocks.tablet, 'tablet'], [Lang.Blocks.smartphone, 'mobile'], ], value: 'desktop', fontSize: 11, converter: Entry.block.converters.returnStringValue, }, ], }, ], }, }, is_touch_supported: { color: EntryStatic.colorSet.block.default.JUDGE, outerLine: EntryStatic.colorSet.block.darken.JUDGE, skeleton: 'basic_boolean_field', statements: [], params: [], events: {}, def: { params: [null], type: 'is_touch_supported', }, class: 'boolean_device', isNotFor: [], func() { return ( 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0 ); }, syntax: { js: [], py: [ { syntax: 'Entry.is_touch_supported()', blockType: 'param', }, ], }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_looks.js ================================================ module.exports = { getBlocks() { return { show: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'show', }, class: 'visibility', isNotFor: [], func(sprite, script) { sprite.setVisible(true); return script.callReturn(); }, syntax: { js: [], py: ['Entry.show()'] }, }, hide: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'hide', }, class: 'visibility', isNotFor: [], func(sprite, script) { sprite.setVisible(false); return script.callReturn(); }, syntax: { js: [], py: ['Entry.hide()'] }, }, dialog_time: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Dropdown', options: [ [Lang.Blocks.speak, 'speak'], [Lang.Blocks.think, 'think'], // [Lang.Blocks.yell, 'yell'], ], value: 'speak', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.LOOKS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'text', params: [Lang.Blocks.block_hi], }, { type: 'number', params: ['4'], }, null, null, ], type: 'dialog_time', }, pyHelpDef: { params: [ { type: 'text', params: ['A&value'], }, { type: 'number', params: ['B&value'], }, { type: 'text', params: ['C&value'], }, null, ], type: 'dialog_time', }, paramsKeyMap: { VALUE: 0, SECOND: 1, OPTION: 2, }, class: 'say', isNotFor: [], func(sprite, script) { if (!script.isStart) { let [timeValue, message] = script.getValues(['SECOND', 'VALUE'], script); timeValue = Number(timeValue); const mode = script.getField('OPTION', script); script.isStart = true; script.timeFlag = 1; if (message === '') { message = ' '; } else if (typeof message === 'boolean') { message = message ? 'True' : 'False'; } else { message = `${message}`; } message = Entry.convertToRoundedDecimals(message, 3); new Entry.Dialog(sprite, message, mode); sprite.syncDialogVisible(sprite.getVisible()); let timeoutId = 0; const stopDialog = () => { script.timeFlag = 0; if (timeoutId) { clearTimeout(timeoutId); timeoutId = 0; } }; sprite.stopDialog = stopDialog; timeoutId = Entry.engine.setTimeout(stopDialog, timeValue * 1000); } if (script.timeFlag == 0) { delete script.timeFlag; delete script.isStart; if (sprite.dialog) { sprite.dialog.remove(); sprite.stopDialog = undefined; } return script.callReturn(); } return script; }, syntax: { js: [], py: [ { syntax: 'Entry.print_for_sec(%1, %2)', params: [null, null, 'speak'], textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Dropdown', options: [ [Lang.Blocks.speak, 'speak'], [Lang.Blocks.think, 'think'], // [Lang.Blocks.yell, 'yell'], ], value: 'speak', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.LOOKS, converter: Entry.block.converters.returnStringValue, }, ], }, ], }, }, dialog: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Dropdown', options: [ [Lang.Blocks.speak, 'speak'], [Lang.Blocks.think, 'think'], // [Lang.Blocks.yell, 'yell'], ], value: 'speak', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.LOOKS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'text', params: [Lang.Blocks.block_hi], }, null, null, ], type: 'dialog', }, pyHelpDef: { params: [ { type: 'text', params: ['A&value'], }, { type: 'text', params: ['B&value'], }, null, ], type: 'dialog', }, paramsKeyMap: { VALUE: 0, OPTION: 1, }, class: 'say', isNotFor: [], func(sprite, script) { let message = script.getValue('VALUE', script); if (message === '') { message = ' '; } else if (typeof message === 'boolean') { message = message ? 'True' : 'False'; } else { message = `${message}`; } const mode = script.getField('OPTION', script); message = Entry.convertToRoundedDecimals(message, 3); new Entry.Dialog(sprite, message, mode); sprite.syncDialogVisible(sprite.getVisible()); return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.print(%1)', params: [null, 'speak'], }, ], }, }, remove_dialog: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'remove_dialog', }, class: 'say', isNotFor: [], func(sprite, script) { if (sprite.stopDialog) { sprite.stopDialog(); } if (sprite.dialog) { sprite.dialog.remove(); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.clear_print()'] }, }, change_to_some_shape: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'get_pictures', id: 'z4jm', }, null, ], type: 'change_to_some_shape', }, pyHelpDef: { params: [ { type: 'get_pictures', params: ['A&value'], }, null, ], type: 'change_to_some_shape', }, paramsKeyMap: { VALUE: 0, }, class: 'shape', isNotFor: ['textBox'], func(sprite, script) { const imageId = script.getStringValue('VALUE'); const picture = sprite.parent.getPicture(imageId); sprite.setImage(picture); return script.callReturn(); }, syntax: { js: [], py: [ { passTest: true, syntax: 'Entry.change_shape(%1)', }, ], }, }, change_to_next_shape: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.LOOKS_change_shape_next, 'next'], [Lang.Blocks.LOOKS_change_shape_prev, 'prev'], ], value: 'next', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.LOOKS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [null, null], type: 'change_to_next_shape', }, pyHelpDef: { params: ['A&value', null], type: 'change_to_next_shape', }, paramsKeyMap: { DRIECTION: 0, }, class: 'shape', isNotFor: ['textBox'], func(sprite, script) { let picture; if (script.getStringField('DRIECTION') !== 'prev') { picture = sprite.parent.getNextPicture(sprite.picture.id); } else { picture = sprite.parent.getPrevPicture(sprite.picture.id); } sprite.setImage(picture); return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.change_shape_to(%1)', textParams: [ { type: 'Dropdown', options: [ [Lang.Blocks.LOOKS_change_shape_next, 'next'], [Lang.Blocks.LOOKS_change_shape_prev, 'prev'], ], value: 'next', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.LOOKS, converter: Entry.block.converters.returnStringValue, codeMap: 'Entry.CodeMap.Entry.change_to_next_shape[0]', }, ], }, ], }, }, add_effect_amount: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.color, 'color'], [Lang.Blocks.brightness, 'brightness'], [Lang.Blocks.transparency, 'transparency'], ], value: 'color', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.LOOKS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['10'], }, null, ], type: 'add_effect_amount', }, pyHelpDef: { params: [ 'A&value', { type: 'number', params: ['B&value'], }, null, ], type: 'add_effect_amount', }, paramsKeyMap: { EFFECT: 0, VALUE: 1, }, class: 'effect', isNotFor: ['textBox'], func(sprite, script) { const effect = script.getField('EFFECT', script); const effectValue = script.getNumberValue('VALUE', script); let effectName = ''; if (effect === 'color') { sprite.effect.hsv = effectValue + sprite.effect.hsv; effectName = 'hsv'; } else if (effect === 'brightness') { sprite.effect.brightness = effectValue + sprite.effect.brightness; effectName = 'brightness'; } else if (effect === 'transparency') { sprite.effect.alpha = sprite.effect.alpha - effectValue / 100; effectName = 'alpha'; } sprite.applyFilter(true, [effectName]); return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.add_effect(%1, %2)', textParams: [ { type: 'Dropdown', options: [ [Lang.Blocks.color, 'color'], [Lang.Blocks.brightness, 'brightness'], [Lang.Blocks.transparency, 'transparency'], ], value: 'color', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.LOOKS, converter: Entry.block.converters.returnStringValue, codeMap: 'Entry.CodeMap.Entry.add_effect_amount[0]', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, change_effect_amount: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.color, 'color'], [Lang.Blocks.brightness, 'brightness'], [Lang.Blocks.transparency, 'transparency'], ], value: 'color', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.LOOKS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['100'], }, null, ], type: 'change_effect_amount', }, pyHelpDef: { params: [ 'A&value', { type: 'number', params: ['B&value'], }, null, ], type: 'change_effect_amount', }, paramsKeyMap: { EFFECT: 0, VALUE: 1, }, class: 'effect', isNotFor: ['textBox'], func(sprite, script) { const effect = script.getField('EFFECT', script); const effectValue = script.getNumberValue('VALUE', script); let effectName = ''; if (effect === 'color') { sprite.effect.hsv = effectValue; effectName = 'hsv'; } else if (effect === 'brightness') { sprite.effect.brightness = effectValue; effectName = 'brightness'; } else if (effect === 'transparency') { sprite.effect.alpha = 1 - effectValue / 100; effectName = 'alpha'; } sprite.applyFilter(true, [effectName]); return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.set_effect(%1, %2)', textParams: [ { type: 'Dropdown', options: [ [Lang.Blocks.color, 'color'], [Lang.Blocks.brightness, 'brightness'], [Lang.Blocks.transparency, 'transparency'], ], value: 'color', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.LOOKS, converter: Entry.block.converters.returnStringValue, codeMap: 'Entry.CodeMap.Entry.change_effect_amount[0]', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, erase_all_effects: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'erase_all_effects', }, class: 'effect', isNotFor: ['textBox'], func(sprite, script) { sprite.resetFilter(); return script.callReturn(); }, syntax: { js: [], py: ['Entry.clear_effect()'] }, }, change_scale_size: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, ], type: 'change_scale_size', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'change_scale_size', }, paramsKeyMap: { VALUE: 0, }, class: 'scale', isNotFor: [], func(sprite, script) { const sizeValue = script.getNumberValue('VALUE', script); sprite.setSize(sprite.getSize() + sizeValue); // sprite.setWidth(sprite.getWidth() * 2); // sprite.setScaleX(sprite.getScaleX() * 2); return script.callReturn(); }, syntax: { js: [], py: ['Entry.add_size(%1)'] }, }, set_scale_size: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['100'], }, null, ], type: 'set_scale_size', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'set_scale_size', }, paramsKeyMap: { VALUE: 0, }, class: 'scale', isNotFor: [], func(sprite, script) { const sizeValue = script.getNumberValue('VALUE', script); sprite.setSize(sizeValue); return script.callReturn(); }, syntax: { js: [], py: ['Entry.set_size(%1)'] }, }, stretch_scale_size: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.width, 'WIDTH'], [Lang.Blocks.height, 'HEIGHT'], ], value: 'WIDTH', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.LOOKS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['10'], }, null, ], type: 'stretch_scale_size', }, paramsKeyMap: { DIMENSION: 0, VALUE: 1, }, class: 'scale', isNotFor: [], func(sprite, script) { const dimension = script.getValue('DIMENSION', script); const sizeValue = script.getNumberValue('VALUE', script); if (dimension === 'WIDTH') { sprite.setXSize(sprite.getSize() + sizeValue); } else { sprite.setYSize(sprite.getSize() + sizeValue); } return script.callReturn(); }, }, reset_scale_size: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'reset_scale_size', }, paramsKeyMap: {}, class: 'scale', isNotFor: [], func(sprite, script) { sprite.resetSize(); return script.callReturn(); }, }, flip_x: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'flip_x', }, class: 'flip', isNotFor: [], func(sprite, script) { sprite.setScaleY(-1 * sprite.getScaleY()); return script.callReturn(); }, syntax: { js: [], py: ['Entry.flip_horizontal()'] }, }, flip_y: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'flip_y', }, class: 'flip', isNotFor: [], func(sprite, script) { sprite.setScaleX(-1 * sprite.getScaleX()); return script.callReturn(); }, syntax: { js: [], py: ['Entry.flip_vertical()'] }, }, change_object_index: { color: EntryStatic.colorSet.block.default.LOOKS, outerLine: EntryStatic.colorSet.block.darken.LOOKS, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.LOOKS_change_object_index_sub_1, 'FRONT'], [Lang.Blocks.LOOKS_change_object_index_sub_2, 'FORWARD'], [Lang.Blocks.LOOKS_change_object_index_sub_3, 'BACKWARD'], [Lang.Blocks.LOOKS_change_object_index_sub_4, 'BACK'], ], value: 'FRONT', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.LOOKS, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/looks_icon.svg', size: 11, }, ], events: {}, def: { params: [null, null], type: 'change_object_index', }, pyHelpDef: { params: ['A&value', null], type: 'change_object_index', }, paramsKeyMap: { LOCATION: 0, }, class: 'z-index', isNotFor: [], func(sprite, script) { const location = script.getField('LOCATION', script); const selectedObjectContainer = Entry.stage.selectedObjectContainer; const currentIndex = selectedObjectContainer.getChildIndex(sprite.object); const max = selectedObjectContainer.children.length - 1; let targetIndex = currentIndex; switch (location) { case 'FRONT': targetIndex = max; break; case 'FORWARD': { if (currentIndex === max) { break; } const frontEntity = selectedObjectContainer.getChildAt( currentIndex + 1 ).entity; const offsetCount = 1 + (sprite.shapes.length ? 1 : 0) + (sprite.paintShapes.length ? 1 : 0); targetIndex += offsetCount + frontEntity.stamps.length; break; } case 'BACKWARD': { const offsetCount = 1 + (sprite.shapes.length ? 1 : 0) + (sprite.paintShapes.length ? 1 : 0); const backIndex = targetIndex - offsetCount + sprite.stamps.length; let backEntity = selectedObjectContainer.getChildAt(backIndex); if (!backEntity) { targetIndex = 0; break; } backEntity = backEntity.entity; targetIndex -= offsetCount + backEntity.stamps.length; break; } case 'BACK': targetIndex = 0; break; } Entry.stage.setEntityIndex(sprite, targetIndex); return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.send_layer_to(%1)', textParams: [ { type: 'Dropdown', options: [ [Lang.Blocks.LOOKS_change_object_index_sub_1, 'FRONT'], [Lang.Blocks.LOOKS_change_object_index_sub_2, 'FORWARD'], [Lang.Blocks.LOOKS_change_object_index_sub_3, 'BACKWARD'], [Lang.Blocks.LOOKS_change_object_index_sub_4, 'BACK'], ], value: 'FRONT', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.LOOKS, converter: Entry.block.converters.returnStringValueLowerCase, codeMap: 'Entry.CodeMap.Entry.change_object_index[0]', }, ], }, ], }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_moving.js ================================================ module.exports = { getBlocks() { function moveInToBound(object, wall) { if (wall.up.y > object.y) { object.y = wall.up.y; } if (wall.down.y < object.y) { object.y = wall.down.y; } if (wall.right.x < object.x) { object.x = wall.right.x; } if (wall.left.x > object.x) { object.x = wall.left.x; } } return { move_direction: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, ], type: 'move_direction', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'move_direction', }, paramsKeyMap: { VALUE: 0, }, class: 'walk', isNotFor: [], func(sprite, script) { const value = script.getNumberValue('VALUE', script); sprite.setX( sprite.getX() + value * Math.cos( ((sprite.getRotation() + sprite.getDirection() - 90) / 180) * Math.PI ) ); sprite.setY( sprite.getY() - value * Math.sin( ((sprite.getRotation() + sprite.getDirection() - 90) / 180) * Math.PI ) ); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } if (sprite.paint && !sprite.paint.stop) { sprite.paint.lineTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.move_to_direction(%1)'] }, }, bounce_wall: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'bounce_wall', }, class: 'walk', isNotFor: [], func(sprite, script) { const threshold = 0; const method = sprite.parent.getRotateMethod(); let angle; if (method === 'free') { angle = (sprite.getRotation() + sprite.getDirection()).mod(360); } else { angle = sprite.getDirection(); } let skip = Entry.Utils.COLLISION.NONE; if ((angle < 90 && angle >= 0) || (angle < 360 && angle >= 270)) { skip = sprite.collision == Entry.Utils.COLLISION.UP; let up = ndgmr.checkPixelCollision( Entry.stage.wall.up, sprite.object, threshold, false ); if (!up && skip) { sprite.collision = Entry.Utils.COLLISION.NONE; } if (up && skip) { up = false; } if (up) { if (method === 'free') { sprite.setRotation( -sprite.getRotation() - sprite.getDirection() * 2 + 180 ); } else { sprite.setDirection(-sprite.getDirection() + 180); } sprite.collision = Entry.Utils.COLLISION.UP; } else { skip = sprite.collision == Entry.Utils.COLLISION.DOWN; let down = ndgmr.checkPixelCollision( Entry.stage.wall.down, sprite.object, threshold, false ); if (!down && skip) { sprite.collision = Entry.Utils.COLLISION.NONE; } if (down && skip) { down = false; } if (down) { if (method === 'free') { sprite.setRotation( -sprite.getRotation() - sprite.getDirection() * 2 + 180 ); } else { sprite.setDirection(-sprite.getDirection() + 180); } sprite.collision = Entry.Utils.COLLISION.DOWN; } } } else if (angle < 270 && angle >= 90) { skip = sprite.collision == Entry.Utils.COLLISION.DOWN; let down = ndgmr.checkPixelCollision( Entry.stage.wall.down, sprite.object, threshold, false ); if (!down && skip) { sprite.collision = Entry.Utils.COLLISION.NONE; } if (down && skip) { down = false; } if (down) { if (method === 'free') { sprite.setRotation( -sprite.getRotation() - sprite.getDirection() * 2 + 180 ); } else { sprite.setDirection(-sprite.getDirection() + 180); } sprite.collision = Entry.Utils.COLLISION.DOWN; //sprite.setY(-135 + bound.height/2 + 1); } else { skip = sprite.collision == Entry.Utils.COLLISION.UP; let up = ndgmr.checkPixelCollision( Entry.stage.wall.up, sprite.object, threshold, false ); if (!up && skip) { sprite.collision = Entry.Utils.COLLISION.NONE; } if (up && skip) { up = false; } if (up) { if (method === 'free') { sprite.setRotation( -sprite.getRotation() - sprite.getDirection() * 2 + 180 ); } else { sprite.setDirection(-sprite.getDirection() + 180); } sprite.collision = Entry.Utils.COLLISION.UP; //sprite.setY(135 - bound.height/2 - 1); } } } if (angle < 360 && angle >= 180) { skip = sprite.collision == Entry.Utils.COLLISION.LEFT; let left = ndgmr.checkPixelCollision( Entry.stage.wall.left, sprite.object, threshold, false ); if (!left && skip) { sprite.collision = Entry.Utils.COLLISION.NONE; } if (left && skip) { left = false; } if (left) { if (method === 'free') { sprite.setRotation( -sprite.getRotation() - sprite.getDirection() * 2 ); } else { sprite.setDirection(-sprite.getDirection() + 360); } sprite.collision = Entry.Utils.COLLISION.LEFT; } else { skip = sprite.collision == Entry.Utils.COLLISION.RIGHT; let right = ndgmr.checkPixelCollision( Entry.stage.wall.right, sprite.object, threshold, false ); if (!right && skip) { sprite.collision = Entry.Utils.COLLISION.NONE; } if (right && skip) { right = false; } if (right) { if (method === 'free') { sprite.setRotation( -sprite.getRotation() - sprite.getDirection() * 2 ); } else { sprite.setDirection(-sprite.getDirection() + 360); } sprite.collision = Entry.Utils.COLLISION.RIGHT; } } } else if (angle < 180 && angle >= 0) { skip = sprite.collision == Entry.Utils.COLLISION.RIGHT; let right = ndgmr.checkPixelCollision( Entry.stage.wall.right, sprite.object, threshold, false ); if (!right && skip) { sprite.collision = Entry.Utils.COLLISION.NONE; } if (right && skip) { right = false; } if (right) { if (method === 'free') { sprite.setRotation( -sprite.getRotation() - sprite.getDirection() * 2 ); } else { sprite.setDirection(-sprite.getDirection() + 360); } sprite.collision = Entry.Utils.COLLISION.RIGHT; } else { skip = sprite.collision == Entry.Utils.COLLISION.LEFT; let left = ndgmr.checkPixelCollision( Entry.stage.wall.left, sprite.object, threshold, false ); if (!left && skip) { sprite.collision = Entry.Utils.COLLISION.NONE; } if (left && skip) { left = false; } if (left) { if (method === 'free') { sprite.setRotation( -sprite.getRotation() - sprite.getDirection() * 2 ); } else { sprite.setDirection(-sprite.getDirection() + 360); } sprite.collision = Entry.Utils.COLLISION.LEFT; } } } return script.callReturn(); }, syntax: { js: [], py: ['Entry.bounce_on_edge()'] }, }, move_x: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, ], type: 'move_x', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'move_x', }, paramsKeyMap: { VALUE: 0, }, class: 'move_relative', isNotFor: [], func(sprite, script) { const value = script.getNumberValue('VALUE', script); sprite.setX(sprite.getX() + value); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } if (sprite.paint && !sprite.paint.stop) { sprite.paint.lineTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.add_x(%1)'] }, }, move_y: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, ], type: 'move_y', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'move_y', }, paramsKeyMap: { VALUE: 0, }, class: 'move_relative', isNotFor: [], func(sprite, script) { const value = script.getNumberValue('VALUE', script); sprite.setY(sprite.getY() + value); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } if (sprite.paint && !sprite.paint.stop) { sprite.paint.lineTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.add_y(%1)'] }, }, move_xy_time: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['2'], }, { type: 'number', params: ['10'], }, { type: 'number', params: ['10'], }, null, ], type: 'move_xy_time', }, pyHelpDef: { params: [ { type: 'number', params: ['C&value'], }, { type: 'number', params: ['A&value'], }, { type: 'number', params: ['B&value'], }, null, ], type: 'move_xy_time', }, paramsKeyMap: { VALUE1: 0, VALUE2: 1, VALUE3: 2, }, class: 'move_relative', isNotFor: [], func(sprite, script) { if (!script.isStart) { let [timeValue, xValue, yValue] = script.getValues( ['VALUE1', 'VALUE2', 'VALUE3'], script ); timeValue = Number(timeValue); xValue = Number(xValue); yValue = Number(yValue); script.isStart = true; script.frameCount = Math.max(Math.floor(timeValue * Entry.FPS), 1); script.dX = xValue / script.frameCount; script.dY = yValue / script.frameCount; if (script.frameCount == 1) { action(); } } if (script.frameCount != 0) { action(); return script; } else { delete script.isStart; delete script.frameCount; return script.callReturn(); } function action() { sprite.setX(sprite.getX() + script.dX); sprite.setY(sprite.getY() + script.dY); script.frameCount--; if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } if (sprite.paint && !sprite.paint.stop) { sprite.paint.lineTo(sprite.getX(), sprite.getY() * -1); } } }, syntax: { js: [], py: ['Entry.add_xy_for_sec(%2, %3, %1)'] }, }, locate_x: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, ], type: 'locate_x', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'locate_x', }, paramsKeyMap: { VALUE: 0, }, class: 'move_absolute', isNotFor: [], func(sprite, script) { const value = script.getNumberValue('VALUE', script); sprite.setX(value); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } if (sprite.paint && !sprite.paint.stop) { sprite.paint.lineTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.set_x(%1)'] }, }, locate_y: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, ], type: 'locate_y', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'locate_y', }, paramsKeyMap: { VALUE: 0, }, class: 'move_absolute', isNotFor: [], func(sprite, script) { const value = script.getNumberValue('VALUE', script); sprite.setY(value); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } if (sprite.paint && !sprite.paint.stop) { sprite.paint.lineTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.set_y(%1)'] }, }, locate_xy: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, null, ], type: 'locate_xy', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, { type: 'number', params: ['B&value'], }, ], type: 'locate_xy', }, paramsKeyMap: { VALUE1: 0, VALUE2: 1, }, class: 'move_absolute', isNotFor: [], func(sprite, script) { let [value1, value2] = script.getValues(['VALUE1', 'VALUE2'], script); value1 = Number(value1); value2 = Number(value2); sprite.setX(value1); sprite.setY(value2); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } if (sprite.paint && !sprite.paint.stop) { sprite.paint.lineTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.set_xy(%1, %2)'] }, }, locate_xy_time: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['2'], }, { type: 'number', params: ['10'], }, { type: 'number', params: ['10'], }, null, ], type: 'locate_xy_time', }, pyHelpDef: { params: [ { type: 'number', params: ['C&value'], }, { type: 'number', params: ['A&value'], }, { type: 'number', params: ['B&value'], }, null, ], type: 'locate_xy_time', }, paramsKeyMap: { VALUE1: 0, VALUE2: 1, VALUE3: 2, }, class: 'move_absolute', isNotFor: [], func(sprite, script) { if (!script.isStart) { let [timeValue, xValue, yValue] = script.getValues( ['VALUE1', 'VALUE2', 'VALUE3'], script ); timeValue = Number(timeValue); xValue = Number(xValue); yValue = Number(yValue); script.x = xValue; script.y = yValue; script.isStart = true; script.frameCount = Math.max(Math.floor(timeValue * Entry.FPS), 1); if (script.frameCount == 1) { action(); } } if (script.frameCount != 0) { action(); return script; } else { delete script.isStart; delete script.frameCount; return script.callReturn(); } function action() { let dX = script.x - sprite.getX(); let dY = script.y - sprite.getY(); dX /= script.frameCount; dY /= script.frameCount; sprite.setX(sprite.getX() + dX); sprite.setY(sprite.getY() + dY); script.frameCount--; if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } if (sprite.paint && !sprite.paint.stop) { sprite.paint.lineTo(sprite.getX(), sprite.getY() * -1); } } }, syntax: { js: [], py: ['Entry.set_xy_for_sec(%2, %3, %1)'] }, }, locate: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'spritesWithMouse', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.MOVING, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [null, null], type: 'locate', }, pyHelpDef: { params: ['A&value', null], type: 'locate', }, paramsKeyMap: { VALUE: 0, }, class: 'move_absolute', isNotFor: [], func(sprite, script) { const targetId = script.getField('VALUE', script); let x; let y; if (targetId === 'mouse') { x = Entry.stage.mouseCoordinate.x; y = Entry.stage.mouseCoordinate.y; } else { const targetEntity = Entry.container.getEntity(targetId); x = targetEntity.getX(); y = targetEntity.getY(); } sprite.setX(Number(x)); sprite.setY(Number(y)); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(x, y * -1); } if (sprite.paint && !sprite.paint.stop) { sprite.paint.lineTo(x, y * -1); } return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.move_to(%1)', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'spritesWithMouse', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.MOVING, converter: Entry.block.converters.returnStringKey, codeMap: 'Entry.CodeMap.Entry.locate[0]', }, ], }, ], }, }, locate_object_time: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: 'spritesWithMouse', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.MOVING, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['2'], }, null, null, ], type: 'locate_object_time', }, pyHelpDef: { params: [ { type: 'number', params: ['B&value'], }, 'A&value', ], type: 'locate_object_time', }, paramsKeyMap: { VALUE: 0, TARGET: 1, }, class: 'move_absolute', isNotFor: [], func(sprite, script) { if (!script.isStart) { let xValue; let yValue; const targetId = script.getField('TARGET', script); const timeValue = script.getNumberValue('VALUE', script); const frameCount = Math.floor(timeValue * Entry.FPS); const mouseCoordi = Entry.stage.mouseCoordinate; if (frameCount != 0) { if (targetId === 'mouse') { xValue = mouseCoordi.x - sprite.getX(); yValue = mouseCoordi.y - sprite.getY(); } else { const targetEntity = Entry.container.getEntity(targetId); xValue = targetEntity.getX() - sprite.getX(); yValue = targetEntity.getY() - sprite.getY(); } script.isStart = true; script.frameCount = frameCount; script.dX = xValue / script.frameCount; script.dY = yValue / script.frameCount; } else { //frame count is zero so execute immediately if (targetId === 'mouse') { xValue = Number(mouseCoordi.x); yValue = Number(mouseCoordi.y); } else { const targetEntity = Entry.container.getEntity(targetId); xValue = targetEntity.getX(); yValue = targetEntity.getY(); } sprite.setX(xValue); sprite.setY(yValue); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } if (sprite.paint && !sprite.paint.stop) { sprite.paint.lineTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); } } if (script.frameCount != 0) { sprite.setX(sprite.getX() + script.dX); sprite.setY(sprite.getY() + script.dY); script.frameCount--; if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } if (sprite.paint && !sprite.paint.stop) { sprite.paint.lineTo(sprite.getX(), sprite.getY() * -1); } return script; } else { delete script.isStart; delete script.frameCount; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Entry.move_to_for_sec(%2, %1)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'DropdownDynamic', value: null, menuName: 'spritesWithMouse', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.MOVING, converter: Entry.block.converters.returnStringKey, codeMap: 'Entry.CodeMap.Entry.locate_object_time[1]', }, ], }, ], }, }, rotate_relative: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'angle', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'angle', params: ['90'], }, null, ], type: 'rotate_relative', }, pyHelpDef: { params: [ { type: 'angle', params: ['A&value'], }, ], type: 'rotate_relative', }, paramsKeyMap: { VALUE: 0, }, class: 'rotate', isNotFor: [], func(entity, script) { const value = script.getNumberValue('VALUE', script); entity.setRotation(value + entity.getRotation()); return script.callReturn(); }, syntax: { js: [], py: ['Entry.add_rotation(%1)'] }, }, direction_relative: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', defaultType: 'angle', accept: 'string', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'angle', params: ['90'], }, null, ], type: 'direction_relative', }, pyHelpDef: { params: [ { type: 'angle', params: ['A&value'], }, null, ], type: 'direction_relative', }, paramsKeyMap: { VALUE: 0, }, class: 'rotate', isNotFor: [], func(entity, script) { const value = script.getNumberValue('VALUE', script); entity.setDirection(value + entity.getDirection()); return script.callReturn(); }, syntax: { js: [], py: ['Entry.add_direction(%1)'] }, }, rotate_by_time: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'angle', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['2'], }, { type: 'angle', params: ['90'], }, null, ], type: 'rotate_by_time', }, pyHelpDef: { params: [ { type: 'number', params: ['B&value'], }, { type: 'angle', params: ['A&value'], }, null, ], type: 'rotate_by_time', }, paramsKeyMap: { VALUE: 0, ANGLE: 1, }, class: 'rotate', isNotFor: [], func(sprite, script) { if (!script.isStart) { let [timeValue, angleValue] = script.getValues(['VALUE', 'ANGLE'], script); timeValue = Number(timeValue); angleValue = Number(angleValue); script.isStart = true; script.frameCount = Math.max(Math.floor(timeValue * Entry.FPS), 1); script.dAngle = angleValue / script.frameCount; if (script.frameCount == 1) { action(); } } if (script.frameCount != 0) { action(); return script; } else { delete script.isStart; delete script.frameCount; return script.callReturn(); } function action() { sprite.setRotation(sprite.getRotation() + script.dAngle); script.frameCount--; } }, syntax: { js: [], py: ['Entry.add_rotation_for_sec(%2, %1)'] }, }, direction_relative_duration: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'angle', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'text', params: ['2'], }, { type: 'angle', params: ['90'], }, null, ], type: 'direction_relative_duration', }, pyHelpDef: { params: [ { type: 'text', params: ['B&value'], }, { type: 'angle', params: ['A&value'], }, null, ], type: 'direction_relative_duration', }, paramsKeyMap: { DURATION: 0, AMOUNT: 1, }, class: 'rotate', isNotFor: [], func(sprite, script) { if (!script.isStart) { let [timeValue, directionValue] = script.getValues( ['DURATION', 'AMOUNT'], script ); timeValue = Number(timeValue); directionValue = Number(directionValue); script.isStart = true; script.frameCount = Math.max(Math.floor(timeValue * Entry.FPS), 1); script.dDirection = directionValue / script.frameCount; if (script.frameCount == 1) { action(); } } if (script.frameCount != 0) { action(); return script; } else { delete script.isStart; delete script.frameCount; delete script.dDirection; return script.callReturn(); } function action() { sprite.setDirection(sprite.getDirection() + script.dDirection); script.frameCount--; } }, syntax: { js: [], py: ['Entry.add_direction_for_sec(%2, %1)'] }, }, rotate_absolute: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', defaultType: 'angle', accept: 'string', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'angle', params: ['90'], }, null, ], type: 'rotate_absolute', }, pyHelpDef: { params: [ { type: 'angle', params: ['A&value'], }, null, ], type: 'rotate_absolute', }, paramsKeyMap: { VALUE: 0, }, class: 'rotate_absolute', isNotFor: [], func(entity, script) { const value = script.getNumberValue('VALUE', script); entity.setRotation(value); return script.callReturn(); }, syntax: { js: [], py: ['Entry.set_rotation(%1)'] }, }, direction_absolute: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', defaultType: 'angle', accept: 'string', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'angle', params: ['90'], }, null, ], type: 'direction_absolute', }, pyHelpDef: { params: [ { type: 'angle', params: ['A&value'], }, null, ], type: 'direction_absolute', }, paramsKeyMap: { VALUE: 0, }, class: 'rotate_absolute', isNotFor: [], func(entity, script) { const value = script.getNumberValue('VALUE', script); entity.setDirection(value); return script.callReturn(); }, syntax: { js: [], py: ['Entry.set_direction(%1)'] }, }, see_angle_object: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'spritesWithMouse', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.MOVING, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [null, null], type: 'see_angle_object', }, pyHelpDef: { params: ['A&value', null], type: 'see_angle_object', }, paramsKeyMap: { VALUE: 0, }, class: 'rotate_absolute', isNotFor: [], func(sprite, script) { const targetId = script.getField('VALUE', script); const spriteX = sprite.getX(); const spriteY = sprite.getY(); let deltaX; let deltaY; let value; if (sprite.parent.id == targetId) { return script.callReturn(); } if (targetId === 'mouse') { const mX = Entry.stage.mouseCoordinate.x; const mY = Entry.stage.mouseCoordinate.y; deltaX = mX - spriteX; deltaY = mY - spriteY; } else { const targetEntity = Entry.container.getEntity(targetId); deltaX = targetEntity.getX() - spriteX; deltaY = targetEntity.getY() - spriteY; } if (deltaX === 0 && deltaY === 0) { value = sprite.getDirection() + sprite.getRotation(); } else if (deltaX >= 0) { value = (-Math.atan(deltaY / deltaX) / Math.PI) * 180 + 90; } else { value = (-Math.atan(deltaY / deltaX) / Math.PI) * 180 + 270; } if (this.entity.parent.getRotateMethod() === 'free') { const nativeDirection = sprite.getDirection() + sprite.getRotation(); sprite.setRotation(sprite.getRotation() + value - nativeDirection); } else { sprite.setDirection(value); } return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.look_at(%1)', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'spritesWithMouse', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.MOVING, converter: Entry.block.converters.returnStringKey, codeMap: 'Entry.CodeMap.Entry.see_angle_object[0]', }, ], }, ], }, }, move_to_angle: { color: EntryStatic.colorSet.block.default.MOVING, outerLine: EntryStatic.colorSet.block.darken.MOVING, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'angle', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/moving_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'angle', params: ['90'], }, { type: 'number', params: ['10'], }, null, ], type: 'move_to_angle', }, pyHelpDef: { params: [ { type: 'angle', params: ['B&value'], }, { type: 'number', params: ['A&value'], }, null, ], type: 'move_to_angle', }, paramsKeyMap: { ANGLE: 0, VALUE: 1, }, class: 'move_rotate', isNotFor: [], func(sprite, script) { let [value, angle] = script.getValues(['VALUE', 'ANGLE'], script); value = Number(value); angle = Number(angle); sprite.setX(sprite.getX() + value * Math.cos(((angle - 90) / 180) * Math.PI)); sprite.setY(sprite.getY() - value * Math.sin(((angle - 90) / 180) * Math.PI)); if (sprite.brush && !sprite.brush.stop) { sprite.brush.lineTo(sprite.getX(), sprite.getY() * -1); } if (sprite.paint && !sprite.paint.stop) { sprite.paint.lineTo(sprite.getX(), sprite.getY() * -1); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.move_to_degree(%2, %1)'] }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_sound.js ================================================ import _clamp from 'lodash/clamp'; Entry.playbackRateValue = 1; module.exports = { getBlocks() { return { sound_something_with_block: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'get_sounds', }, null, ], type: 'sound_something_with_block', }, pyHelpDef: { params: [ { type: 'get_sounds', params: ['A&value'], }, null, ], type: 'sound_something_with_block', }, paramsKeyMap: { VALUE: 0, }, class: 'sound_play', isNotFor: [], func(sprite, script) { const soundId = script.getStringValue('VALUE', script); const sound = sprite.parent.getSound(soundId); if (sound) { const instance = Entry.Utils.playSound(sound.id); Entry.Utils.addSoundInstances(instance, sprite); } return script.callReturn(); }, syntax: { js: [], py: [ { passTest: true, syntax: 'Entry.play_sound(%1)', }, ], }, }, sound_something_second_with_block: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'get_sounds', id: '95dw', }, { type: 'number', params: ['1'], }, null, ], type: 'sound_something_second_with_block', }, pyHelpDef: { params: [ { type: 'get_sounds', params: ['A&value'], }, { type: 'number', params: ['B&value'], }, null, ], type: 'sound_something_second_with_block', }, paramsKeyMap: { VALUE: 0, SECOND: 1, }, class: 'sound_play', isNotFor: [], func(sprite, script) { let [soundId, timeValue] = script.getValues(['VALUE', 'SECOND'], script); soundId = String(soundId); timeValue = Number(timeValue); const sound = sprite.parent.getSound(soundId); if (sound) { const instance = Entry.Utils.playSound(sound.id, { startTime: 0, duration: timeValue * 1000, }); Entry.Utils.addSoundInstances(instance, sprite); } return script.callReturn(); }, syntax: { js: [], py: [ { passTest: true, syntax: 'Entry.play_sound_for_sec(%1, %2)', }, ], }, }, sound_from_to: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'get_sounds', }, { type: 'text', params: ['1'], }, { type: 'text', params: ['10'], }, null, ], type: 'sound_from_to', }, pyHelpDef: { params: [ { type: 'get_sounds', params: ['A&value'], }, { type: 'text', params: ['B&value'], }, { type: 'text', params: ['C&value'], }, null, ], type: 'sound_from_to', }, paramsKeyMap: { VALUE: 0, START: 1, END: 2, }, class: 'sound_play', isNotFor: [], func(sprite, script) { const soundId = script.getStringValue('VALUE', script); const sound = sprite.parent.getSound(soundId); if (sound) { let [start, end] = script.getValues(['START', 'END'], script); start = Number(start) * 1000; end = Number(end) * 1000; const instance = Entry.Utils.playSound(sound.id, { startTime: Math.min(start, end), duration: Math.max(start, end) - Math.min(start, end), }); Entry.Utils.addSoundInstances(instance, sprite); } return script.callReturn(); }, syntax: { js: [], py: [ { passTest: true, syntax: 'Entry.play_sound_from_to(%1, %2, %3)', }, ], }, }, sound_something_wait_with_block: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'get_sounds', }, null, ], type: 'sound_something_wait_with_block', }, pyHelpDef: { params: [ { type: 'get_sounds', params: ['A&value'], }, null, ], type: 'sound_something_wait_with_block', }, paramsKeyMap: { VALUE: 0, }, class: 'sound_wait', isNotFor: [], func(sprite, script) { if (!script.isPlay) { script.isPlay = true; const soundId = script.getStringValue('VALUE', script); const sound = sprite.parent.getSound(soundId); if (sound) { script.playState = 1; const instance = Entry.Utils.playSound(sound.id); Entry.Utils.addSoundInstances(instance, sprite); const duration = Math.floor( (sound.duration * 1000) / Entry.playbackRateValue ); Entry.engine.setTimeout(() => { script.playState = 0; }, duration); } return script; } else if (script.playState == 1) { return script; } else { delete script.playState; delete script.isPlay; return script.callReturn(); } }, syntax: { js: [], py: [ { passTest: true, syntax: 'Entry.play_sound_and_wait(%1)', }, ], }, }, sound_something_second_wait_with_block: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'get_sounds', }, { type: 'number', params: ['1'], }, null, ], type: 'sound_something_second_wait_with_block', }, pyHelpDef: { params: [ { type: 'get_sounds', params: ['A&value'], }, { type: 'number', params: ['B&value'], }, null, ], type: 'sound_something_second_wait_with_block', }, paramsKeyMap: { VALUE: 0, SECOND: 1, }, class: 'sound_wait', isNotFor: [], func(sprite, script) { if (!script.isPlay) { script.isPlay = true; const soundId = script.getStringValue('VALUE', script); const sound = sprite.parent.getSound(soundId); if (sound) { script.playState = 1; const instance = Entry.Utils.playSound(sound.id); Entry.Utils.addSoundInstances(instance, sprite); const timeValue = script.getNumberValue('SECOND', script); Entry.engine.setTimeout(() => { instance.stop(); script.playState = 0; }, timeValue * 1000); instance.addEventListener('complete', (e) => {}); } return script; } else if (script.playState == 1) { return script; } else { delete script.isPlay; delete script.playState; return script.callReturn(); } }, syntax: { js: [], py: [ { passTest: true, syntax: 'Entry.play_sound_for_sec_and_wait(%1, %2)', }, ], }, }, sound_from_to_and_wait: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'get_sounds', }, { type: 'text', params: ['1'], }, { type: 'text', params: ['10'], }, null, ], type: 'sound_from_to_and_wait', }, pyHelpDef: { params: [ { type: 'get_sounds', params: ['A&value'], }, { type: 'text', params: ['B&value'], }, { type: 'text', params: ['C&value'], }, null, ], type: 'sound_from_to_and_wait', }, paramsKeyMap: { VALUE: 0, START: 1, END: 2, }, class: 'sound_wait', isNotFor: [], func(sprite, script) { if (!script.isPlay) { script.isPlay = true; const soundId = script.getStringValue('VALUE', script); const sound = sprite.parent.getSound(soundId); if (sound) { script.playState = 1; let [start, end] = script.getValues(['START', 'END'], script); start = Number(start) * 1000; end = Number(end) * 1000; const startValue = Math.min(start, end); const endValue = Math.max(start, end); const duration = endValue - startValue; const instance = Entry.Utils.playSound(sound.id, { startTime: startValue, duration, }); Entry.Utils.addSoundInstances(instance, sprite); Entry.engine.setTimeout(() => { script.playState = 0; }, duration); } return script; } else if (script.playState == 1) { return script; } else { delete script.isPlay; delete script.playState; return script.callReturn(); } }, syntax: { js: [], py: ['Entry.play_sound_from_to_and_wait(%1, %2, %3)'], }, }, sound_volume_change: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, ], type: 'sound_volume_change', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'sound_volume_change', }, paramsKeyMap: { VALUE: 0, }, class: 'sound_volume', isNotFor: [], func(sprite, script) { let value = script.getNumberValue('VALUE', script) / 100; value = value + Entry.Utils.getVolume(); if (value > 1) { value = 1; } if (value < 0) { value = 0; } Entry.Utils.setVolume(value); return script.callReturn(); }, syntax: { js: [], py: ['Entry.add_sound_volume(%1)'] }, }, sound_volume_set: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['10'], }, null, ], type: 'sound_volume_set', }, pyHelpDef: { params: [ { type: 'number', params: ['A&value'], }, null, ], type: 'sound_volume_set', }, paramsKeyMap: { VALUE: 0, }, class: 'sound_volume', isNotFor: [], func(sprite, script) { let value = script.getNumberValue('VALUE', script) / 100; if (value > 1) { value = 1; } if (value < 0) { value = 0; } Entry.Utils.setVolume(value); return script.callReturn(); }, syntax: { js: [], py: ['Entry.set_sound_volume(%1)'] }, }, get_sound_speed: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic_string_field', statements: [], params: [], events: {}, def: { params: [null], type: 'get_sound_speed', }, paramsKeyMap: { VALUE: 0, }, class: 'sound_speed', isNotFor: [], func() { return Entry.playbackRateValue; }, syntax: { js: [], py: ['Entry.stop_sound()'] }, }, sound_speed_change: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['0.1'], }, null, ], type: 'sound_speed_change', }, paramsKeyMap: { VALUE: 0, }, class: 'sound_speed', isNotFor: [], func(sprite, script) { const value = script.getNumberValue('VALUE'); if (!Entry.Utils.isNumber(value)) { return; } Entry.playbackRateValue = _clamp(value + Entry.playbackRateValue, 0.5, 2); const instances = Entry.soundInstances.getAllValues(); instances.forEach((instance) => { if (instance.sourceNode?.playbackRate) { instance.sourceNode.playbackRate.value = Entry.playbackRateValue; } }); return script.callReturn(); }, syntax: { js: [], py: ['Entry.stop_sound()'] }, }, sound_speed_set: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'number', params: ['1'], }, null, ], type: 'sound_speed_set', }, paramsKeyMap: { VALUE: 0, }, class: 'sound_speed', isNotFor: [], func(sprite, script) { let value = _clamp(script.getNumberValue('VALUE'), 0.5, 2); if (!Entry.Utils.isNumber(value)) { value = 1; } Entry.playbackRateValue = value; const instances = Entry.soundInstances.getAllValues(); instances.forEach((instance) => { if (instance.sourceNode?.playbackRate) { instance.sourceNode.playbackRate.value = Entry.playbackRateValue; } }); return script.callReturn(); }, syntax: { js: [], py: ['Entry.stop_sound()'] }, }, sound_silent_all: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.FLOW_stop_object_all, 'all'], [Lang.Blocks.FLOW_stop_object_this_object, 'thisOnly'], [Lang.Blocks.FLOW_stop_object_other_objects, 'other_objects'], ], value: 'all', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.SOUND, arrowColor: EntryStatic.colorSet.common.WHITE, }, { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'sound_silent_all', }, paramsKeyMap: { TARGET: 0, }, class: 'sound_stop', isNotFor: [], func(sprite, script) { switch (script.getField('TARGET', script)) { case 'all': Entry.Utils.forceStopSounds(); return script.callReturn(); case 'thisOnly': { const instances = [...Entry.soundInstances.getAll(sprite)]; instances.forEach((instance) => { instance?.dispatchEvent?.('complete'); instance.stop(); }); return script.callReturn(); } case 'other_objects': { const instances = [...Entry.soundInstances.getAllExcept(sprite)]; instances.forEach((instance) => { instance?.dispatchEvent?.('complete'); instance.stop(); }); return script.callReturn(); } } return script.callReturn(); }, syntax: { js: [], py: ['Entry.stop_sound()'] }, }, play_bgm: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [ { type: 'get_sounds', }, null, ], type: 'play_bgm', }, paramsKeyMap: { VALUE: 0, }, class: 'bgm', isNotFor: [], func(sprite, script) { const soundId = script.getStringValue('VALUE', script); const sound = sprite.parent.getSound(soundId); if (sound) { Entry.Utils.forceStopBGM(); const instance = Entry.Utils.playBGM(sound.id); Entry.Utils.addBGMInstances(instance); } return script.callReturn(); }, syntax: { js: [], py: ['Entry.stop_sound()'] }, }, stop_bgm: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/sound_icon.svg', size: 11, }, ], events: {}, def: { params: [null], type: 'stop_bgm', }, paramsKeyMap: { TARGET: 0, }, class: 'bgm', isNotFor: [], func(sprite, script) { Entry.Utils.forceStopBGM(); return script.callReturn(); }, syntax: { js: [], py: ['Entry.stop_sound()'] }, }, get_sound_volume: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_get_sound_volume, color: '#FFF', }, ], events: {}, def: { params: [null], type: 'get_sound_volume', }, class: 'sound_volume', isNotFor: [], func() { return Entry.Utils.getVolume() * 100; }, syntax: { js: [], py: [ { syntax: 'Entry.value_of_sound_volume()', blockType: 'param', }, ], }, }, get_sound_duration: { color: EntryStatic.colorSet.block.default.SOUND, outerLine: EntryStatic.colorSet.block.darken.SOUND, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.CALC_get_sound_duration_1, color: '#FFF', }, { type: 'DropdownDynamic', value: null, menuName: 'sounds', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.SOUND, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.CALC_get_sound_duration_2, color: '#FFF', }, ], events: {}, def: { params: [null, null, null], type: 'get_sound_duration', }, pyHelpDef: { params: [null, 'A&value', null], type: 'get_sound_duration', }, paramsKeyMap: { VALUE: 1, }, class: 'sound_duration', isNotFor: [], func(sprite, script) { const soundId = script.getField('VALUE', script); const soundsArr = sprite.parent.sounds; for (let i = 0; i < soundsArr.length; i++) { if (soundsArr[i].id === soundId) { return soundsArr[i].duration; } } }, syntax: { js: [], py: [ { syntax: 'Entry.value_of_sound_length_of(%2)', blockType: 'param', textParams: [ undefined, { type: 'DropdownDynamic', value: null, menuName: 'sounds', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.SOUND, converter: Entry.block.converters.returnStringKey, }, ], }, ], }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_start.js ================================================ import { keyInputList } from './inputs/keyboard'; module.exports = { getBlocks() { return { messageAddButton: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, params: [ { type: 'Text', text: Lang.Workspace.message_create, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], def: { type: 'messageAddButton', }, events: { mousedown: [ function() { Entry.variableContainer.openVariableAddPanel('message'); }, ], }, syntax: { js: [], py: [''] }, }, when_run_button_click: { color: EntryStatic.colorSet.block.default.START, outerLine: EntryStatic.colorSet.block.darken.START, skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_play.svg', size: 14, position: { x: 0, y: -2, }, }, ], events: {}, def: { params: [null], type: 'when_run_button_click', }, class: 'event', isNotFor: [], func(sprite, script) { return script.callReturn(); }, event: 'start', syntax: { js: [], py: [ { syntax: 'def when_start():', blockType: 'event', }, ], }, }, when_some_key_pressed: { color: EntryStatic.colorSet.block.default.START, outerLine: EntryStatic.colorSet.block.darken.START, skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_keyboard.svg', size: 14, position: { x: 0, y: -2, }, }, { type: 'Keyboard', options: keyInputList, value: 'q', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.START, arrowColor: EntryStatic.colorSet.arrow.default.START, }, ], events: {}, def: { params: [null, '81'], type: 'when_some_key_pressed', }, pyHelpDef: { params: [null, 'A&value'], type: 'when_some_key_pressed', }, paramsKeyMap: { VALUE: 1, }, class: 'event', isNotFor: [], func(sprite, script) { return script.callReturn(); }, event: 'keyPress', syntax: { js: [], py: [ { syntax: 'def when_press_key(%2):', passTest: true, blockType: 'event', textParams: [ undefined, { type: 'Dropdown', value: 'q', options: keyInputList, arrowColor: EntryStatic.colorSet.arrow.default.START, converter: Entry.block.converters.keyboardCode, }, ], }, ], }, }, mouse_clicked: { color: EntryStatic.colorSet.block.default.START, outerLine: EntryStatic.colorSet.block.darken.START, skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_mouse.svg', size: 14, position: { x: 0, y: -2, }, }, ], events: {}, def: { params: [null], type: 'mouse_clicked', }, class: 'event', isNotFor: [], func(sprite, script) { return script.callReturn(); }, event: 'mouse_clicked', syntax: { js: [], py: [ { syntax: 'def when_click_mouse_on():', blockType: 'event', }, ], }, }, mouse_click_cancled: { color: EntryStatic.colorSet.block.default.START, outerLine: EntryStatic.colorSet.block.darken.START, skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_mouse.svg', size: 14, position: { x: 0, y: -2, }, }, ], events: {}, def: { params: [null], type: 'mouse_click_cancled', }, class: 'event', isNotFor: [], func(sprite, script) { return script.callReturn(); }, event: 'mouse_click_cancled', syntax: { js: [], py: [ { syntax: 'def when_click_mouse_off():', blockType: 'event', }, ], }, }, when_object_click: { color: EntryStatic.colorSet.block.default.START, outerLine: EntryStatic.colorSet.block.darken.START, skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_mouse.svg', size: 14, position: { x: 0, y: -2, }, }, ], events: {}, def: { params: [null], type: 'when_object_click', }, class: 'event', isNotFor: [], func(sprite, script) { return script.callReturn(); }, event: 'when_object_click', syntax: { js: [], py: [ { syntax: 'def when_click_object_on():', blockType: 'event', }, ], }, }, when_object_click_canceled: { color: EntryStatic.colorSet.block.default.START, outerLine: EntryStatic.colorSet.block.darken.START, skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_mouse.svg', size: 14, position: { x: 0, y: -2, }, }, ], events: {}, def: { params: [null], type: 'when_object_click_canceled', }, class: 'event', isNotFor: [], func(sprite, script) { return script.callReturn(); }, event: 'when_object_click_canceled', syntax: { js: [], py: [ { syntax: 'def when_click_object_off():', blockType: 'event', }, ], }, }, when_message_cast: { color: EntryStatic.colorSet.block.default.START, outerLine: EntryStatic.colorSet.block.darken.START, skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_signal.svg', size: 14, position: { x: 0, y: -2, }, }, { type: 'DropdownDynamic', value: null, menuName: 'messages', fontSize: 10, textColor: '#FFFFFF', bgColor: EntryStatic.colorSet.block.darken.START, arrowColor: EntryStatic.colorSet.arrow.default.START, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_messageRefs', block); } }, ], viewDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_messageRefs', block); } }, ], }, def: { params: [null, null], type: 'when_message_cast', }, pyHelpDef: { params: [null, 'A&value'], type: 'when_message_cast', }, paramsKeyMap: { VALUE: 1, }, class: 'message', isNotFor: ['message'], func(sprite, script) { return script.callReturn(); }, event: 'when_message_cast', //"syntax": {"js": [], "py": ["def entry_event_signal():\n\tif signal == %2:"]} syntax: { js: [], py: [ { syntax: 'def when_get_signal(%2):', blockType: 'event', passTest: true, textParams: [ undefined, { type: 'DropdownDynamic', value: null, menuName: 'messages', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.START, converter: Entry.block.converters.returnStringKey, }, ], }, ], }, }, message_cast: { color: EntryStatic.colorSet.block.default.START, outerLine: EntryStatic.colorSet.block.darken.START, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'messages', fontSize: 10, textColor: '#fff', bgColor: EntryStatic.colorSet.block.darken.START, arrowColor: EntryStatic.colorSet.arrow.default.START, }, { type: 'Indicator', img: 'block_icon/start_icon.svg', size: 11, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_messageRefs', block); } }, ], viewDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_messageRefs', block); } }, ], }, def: { params: [null, null], type: 'message_cast', }, pyHelpDef: { params: ['A&value', null], type: 'message_cast', }, paramsKeyMap: { VALUE: 0, }, class: 'message', isNotFor: ['message'], func(sprite, script) { const value = script.getField('VALUE', script); const arr = Entry.variableContainer.messages_; const isExist = Entry.isExist(value, 'id', arr); if (value == 'null' || !isExist) { throw new Error('value can not be null or undefined'); } setTimeout(() => { Entry.engine.raiseMessage(value); }); }, syntax: { js: [], py: [ { syntax: 'Entry.send_signal(%1)', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'messages', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.START, converter: Entry.block.converters.returnStringKey, paramType: 'signal', }, undefined, ], }, ], }, }, message_cast_wait: { color: EntryStatic.colorSet.block.default.START, outerLine: EntryStatic.colorSet.block.darken.START, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'messages', fontSize: 10, textColor: '#fff', bgColor: EntryStatic.colorSet.block.darken.START, arrowColor: EntryStatic.colorSet.arrow.default.START, }, { type: 'Indicator', img: 'block_icon/start_icon.svg', size: 11, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_messageRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_messageRefs', block); } }, ], }, def: { params: [null, null], type: 'message_cast_wait', }, pyHelpDef: { params: ['A&value', null], type: 'message_cast_wait', }, paramsKeyMap: { VALUE: 0, }, class: 'message', isNotFor: ['message'], func(sprite, script) { if (script.runningScript) { const runningScript = script.runningScript; const length = runningScript.length; for (let i = 0; i < length; i++) { const executor = runningScript.shift(); if (executor && !executor.isEnd()) { runningScript.push(executor); } } if (runningScript.length) { return script; } else { return script.callReturn(); } } else { const value = script.getField('VALUE', script); const arr = Entry.variableContainer.messages_; const isExist = Entry.isExist(value, 'id', arr); if (value == 'null' || !isExist) { throw new Error('value can not be null or undefined'); } const data = Entry.engine.raiseMessage(value); let runningScript = []; while (data.length) { const executor = data.shift(); if (executor) { runningScript = runningScript.concat(executor); } } script.runningScript = runningScript; return script; } }, syntax: { js: [], py: [ { syntax: 'Entry.send_signal_wait(%1)', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'messages', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.START, converter: Entry.block.converters.returnStringKey, }, ], }, ], }, }, when_scene_start: { color: EntryStatic.colorSet.block.default.START, outerLine: EntryStatic.colorSet.block.darken.START, skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_scene.svg', size: 14, position: { x: 0, y: -2, }, }, ], events: {}, def: { params: [null], type: 'when_scene_start', }, class: 'scene', isNotFor: ['scene'], func(sprite, script) { return script.callReturn(); }, event: 'when_scene_start', syntax: { js: [], py: [ { syntax: 'def when_start_scene():', blockType: 'event', }, ], }, }, start_scene: { color: EntryStatic.colorSet.block.default.START, outerLine: EntryStatic.colorSet.block.darken.START, skeleton: 'basic_without_next', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'scenes', fontSize: 10, textColor: '#fff', bgColor: EntryStatic.colorSet.block.darken.START, arrowColor: EntryStatic.colorSet.arrow.default.START, }, { type: 'Indicator', img: 'block_icon/start_icon.svg', size: 11, }, ], events: {}, def: { params: [null, null], type: 'start_scene', }, pyHelpDef: { params: ['A&value', null], type: 'start_scene', }, paramsKeyMap: { VALUE: 0, }, class: 'scene', isNotFor: ['scene'], func(sprite, script) { const value = script.getField('VALUE', script); const scene = Entry.scene.getSceneById(value); if (scene) { Entry.scene.selectScene(scene); Entry.engine.fireEvent('when_scene_start'); } return null; }, syntax: { js: [], py: [ { syntax: 'Entry.start_scene(%1)', blockType: 'last', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'scenes', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.START, converter: Entry.block.converters.returnStringKey, }, ], }, ], }, }, start_neighbor_scene: { color: EntryStatic.colorSet.block.default.START, outerLine: EntryStatic.colorSet.block.darken.START, skeleton: 'basic_without_next', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.SCENE_start_scene_next, 'next'], [Lang.Blocks.SCENE_start_scene_pre, 'prev'], ], value: 'next', fontSize: 10, textColor: '#fff', bgColor: EntryStatic.colorSet.block.darken.START, arrowColor: EntryStatic.colorSet.arrow.default.START, }, { type: 'Indicator', img: 'block_icon/start_icon.svg', size: 11, }, ], events: {}, def: { params: [null, null], type: 'start_neighbor_scene', }, pyHelpDef: { params: ['A&value', null], type: 'start_neighbor_scene', }, paramsKeyMap: { OPERATOR: 0, }, class: 'scene', isNotFor: ['scene'], func(sprite, script) { const currentScene = Entry.scene.selectedScene; const scenes = Entry.scene.getScenes(); const index = scenes.indexOf(currentScene); const o = script.getField('OPERATOR', script); if (o == 'next') { if (index + 1 < scenes.length) { const nextScene = Entry.scene.getSceneById(scenes[index + 1].id); if (nextScene) { Entry.scene.selectScene(nextScene); Entry.engine.fireEvent('when_scene_start'); } } } else { if (index > 0) { const nextScene = Entry.scene.getSceneById(scenes[index - 1].id); if (nextScene) { Entry.scene.selectScene(nextScene); Entry.engine.fireEvent('when_scene_start'); } } } return null; }, syntax: { js: [], py: [ { syntax: 'Entry.start_scene_of(%1)', blockType: 'last', textParams: [ { type: 'Dropdown', options: [ [Lang.Blocks.SCENE_start_scene_next, 'next'], [Lang.Blocks.SCENE_start_scene_pre, 'prev'], ], value: 'next', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.START, converter: Entry.block.converters.returnStringValue, codeMap: 'Entry.CodeMap.Entry.start_neighbor_scene[0]', }, ], }, ], }, }, check_object_property: { color: '#7C7C7C', skeleton: 'basic', template: '%1 가 %2 %3 %4 %5 %6', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'sprites', fontSize: 11, }, { type: 'Dropdown', options: [ ['언젠가', 0], ['지금', 1], ], value: '0', fontSize: 11, }, { type: 'Dropdown', options: [ ['x', 'x'], ['y', 'y'], ['크기', 'size'], ['방향', 'rotation'], ['이동 방향', 'direction'], ['텍스트', 'text'], ], value: 'x', fontSize: 11, }, { type: 'Dropdown', options: [ ['=', 'EQUAL'], ['>', 'GREATER'], ['<', 'LESS'], ['≥', 'GREATER_OR_EQUAL'], ['≤', 'LESS_OR_EQUAL'], ], value: 'EQUAL', fontSize: 11, noArrow: true, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', color: '#6B6B6B', size: 12, }, ], events: {}, def: { params: [null], type: 'check_object_property', }, paramsKeyMap: { VALUE: 0, }, class: 'checker', isNotFor: ['checker'], func(sprite, script) { const obj = Entry.container.getObject(this.block.params[0]); const flow = this.block.params[1]; let propertyKey = this.block.params[2]; const rightValue = this.getParam(4); propertyKey = propertyKey[0].toUpperCase() + propertyKey.substr(1); const leftValue = obj.entity[`get${propertyKey}`].call(obj.entity); let returnVal; switch (this.block.params[3]) { case 'EQUAL': returnVal = leftValue == rightValue; break; case 'GREATER': returnVal = Number(leftValue) > Number(rightValue); break; case 'LESS': returnVal = Number(leftValue) < Number(rightValue); break; case 'GREATER_OR_EQUAL': returnVal = Number(leftValue) >= Number(rightValue); break; case 'LESS_OR_EQUAL': returnVal = Number(leftValue) <= Number(rightValue); break; } if (returnVal) { return; } else if (flow == 0) { return Entry.STATIC.BREAK; } else { this.die(); } }, }, check_block_execution: { color: '#7C7C7C', skeleton: 'basic_loop', template: '%1 에서 아래 블록이 %2 %3 번 실행되었는가 %4', statements: [ { accept: 'basic', }, ], params: [ { type: 'DropdownDynamic', value: null, menuName: 'allSprites', fontSize: 11, }, { type: 'Dropdown', options: [ ['비슷하게', 0], ['똑같이', 1], ], value: '16', fontSize: 11, }, { type: 'TextInput', value: 1, }, { type: 'Indicator', color: '#6B6B6B', size: 12, }, ], events: {}, def: { params: [null, 0, '1'], type: 'check_block_execution', }, paramsKeyMap: { VALUE: 0, }, class: 'checker', isNotFor: ['checker'], func(sprite, script) { const { block = {} } = this; const { data = {} } = block; const { id = '' } = data; if (this.entity.listener[id]) { if (this.remainCheck === 0) { this.entity.listener[id].destroy(); delete this.entity.listener[id]; return; } else { return Entry.STATIC.BREAK; } } const code = Entry.container.getObject(this.block.params[0]).script; const accuracy = this.block.params[1]; const statements = this.block.statements[0].getBlocks(); let lastBlock = null; this.remainCheck = Number(this.block.params[2]); let index = 0; this.entity.listener[id] = code.watchEvent.attach(this, (blocks) => { //dangerous blocks = blocks.concat(); let block; let isFirst = true; while (blocks.length && index < statements.length) { block = blocks.shift(); if (isFirst && block === lastBlock) { continue; } if (accuracy === 0 && statements[index].type === block.type) { index++; } else if (accuracy === 1 && statements[index].isSameParamWith(block)) { index++; } else { index = 0; } isFirst = false; } lastBlock = block; if (index === statements.length) { this.remainCheck = this.remainCheck - 1; index = 0; } }); return Entry.STATIC.BREAK; }, }, switch_scope: { color: '#7C7C7C', skeleton: 'basic', template: '%1 오브젝트 기준으로 실행하기 %2', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'sprites', fontSize: 11, }, { type: 'Indicator', color: '#6B6B6B', size: 12, }, ], events: {}, def: { params: [null], type: 'switch_scope', }, paramsKeyMap: { VALUE: 0, }, class: 'checker', isNotFor: ['checker'], func(sprite, script) { const obj = Entry.container.getObject(this.block.params[0]); this.executor.entity = obj.entity; }, }, is_answer_submited: { color: '#7C7C7C', skeleton: 'basic', template: '대답을 입력 받을때 까지 기다리기 %1', statements: [], params: [ { type: 'Indicator', color: '#6B6B6B', size: 12, }, ], events: {}, def: { params: [null], type: 'is_answer_submited', }, paramsKeyMap: { VALUE: 0, }, class: 'checker', isNotFor: ['checker'], func(sprite, script) { if (this.isSubmitted) { Entry.removeEventListener('answerSubmitted', checkFunc); return; } else if (this.isSubmitted === false) { return Entry.STATIC.BREAK; } const checkFunc = function() { that.isSubmitted = true; }; this.isSubmitted = false; const that = this; Entry.addEventListener('answerSubmitted', checkFunc); return Entry.STATIC.BREAK; }, }, check_lecture_goal: { color: '#7C7C7C', skeleton: 'basic', template: '목표 %1 %2 ( %3 ) %4', statements: [], params: [ { type: 'TextInput', value: 0, }, { type: 'Dropdown', options: [ ['달성', 1], ['실패', 0], ], fontSize: 11, }, { type: 'Dropdown', options: [ ['공식', 1], ['비공식', 0], ], value: 1, fontSize: 11, }, { type: 'Indicator', color: '#6B6B6B', size: 12, }, ], events: { dataAdd: [ function(block) { Entry.registerAchievement(block); }, ], }, def: { params: [0, 1, 1], type: 'check_lecture_goal', }, paramsKeyMap: { VALUE: 0, }, class: 'checker', isNotFor: ['checker'], func(sprite, script) { Entry.targetChecker.achieveCheck( this.block.params[1], `${this.block.params[0]}` ); }, }, check_variable_by_name: { color: '#7C7C7C', skeleton: 'basic_string_field', template: '%1 이름의 변수', statements: [], params: [ { type: 'TextInput', value: '?', }, ], events: {}, def: { params: ['변수'], type: 'check_variable_by_name', }, paramsKeyMap: { VALUE: 0, }, class: 'checker', isNotFor: ['checker'], func(sprite, script) { const variableName = `${this.block.params[0]}`; const variable = Entry.variableContainer.getVariableByName(variableName); if (variable) { return variable.getValue(); } else { return; } }, }, show_prompt: { color: '#7C7C7C', skeleton: 'basic', template: '%1 안내하기 %2', statements: [], params: [ { type: 'TextInput', value: '', }, { type: 'Indicator', color: '#6B6B6B', size: 12, }, ], events: {}, def: { params: [' '], type: 'show_prompt', }, paramsKeyMap: { VALUE: 0, }, class: 'checker', isNotFor: ['checker'], func(sprite, script) { if (Entry.targetChecker) { Entry.targetChecker.showStatusMessage(this.block.params[0]); } }, }, check_goal_success: { color: '#7C7C7C', skeleton: 'basic_boolean_field', template: '목표 %1 이 성공?', statements: [], params: [ { type: 'TextInput', value: '', }, ], events: {}, def: { params: ['0'], type: 'check_goal_success', }, paramsKeyMap: { VALUE: 0, }, class: 'checker', isNotFor: ['checker'], func(sprite, script) { const goalName = `${this.block.params[0]}`; return Entry.targetChecker.checkGoal(goalName); }, }, positive_number: { color: '#7C7C7C', skeleton: 'basic_string_field', template: '양수', fontColor: '#fff', statements: [], params: ['positive'], events: {}, def: { params: ['positive'], type: 'positive_number', }, paramsKeyMap: { VALUE: 0, }, class: 'checker', isNotFor: ['checker'], func(sprite, script) { return 'positive'; }, }, negative_number: { color: '#7C7C7C', skeleton: 'basic_string_field', template: '음수', fontColor: '#fff', statements: [], params: ['negative'], events: {}, def: { params: ['negative'], type: 'negative_number', }, paramsKeyMap: { VALUE: 0, }, class: 'checker', isNotFor: ['checker'], func(sprite, script) { return 'negative'; }, }, wildcard_string: { color: '#7C7C7C', skeleton: 'basic_string_field', template: ' * ', fontColor: '#fff', statements: [], params: [], events: {}, def: { params: [], type: 'wildcard_string', }, paramsKeyMap: { VALUE: 0, }, class: 'checker', isNotFor: ['checker'], func(sprite, script) {}, }, wildcard_boolean: { color: '#7C7C7C', skeleton: 'basic_boolean_field', template: ' * ', fontColor: '#fff', statements: [], params: [], events: {}, def: { params: [], type: 'wildcard_boolean', }, paramsKeyMap: {}, class: 'checker', isNotFor: ['checker'], func(sprite, script) {}, }, register_score: { color: '#7C7C7C', skeleton: 'basic', template: '%1를 %2로 정하기 %3', statements: [], params: [ { type: 'TextInput', value: 'score', }, { type: 'TextInput', value: '1', }, { type: 'Indicator', color: '#6B6B6B', size: 12, }, ], events: {}, def: { params: ['score', 1], type: 'register_score', }, class: 'checker', isNotFor: ['checker'], func(sprite, script) { const obj = {}; obj[this.block.params[0]] = this.block.params[1]; if (typeof entrylms !== 'undefined') { entrylms.emit('registerScore', obj); } return script.callReturn(); }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_text.js ================================================ const { type } = Lang || {}; const filename = type === 'ko' ? 'text_icon_ko.svg' : 'text_icon.svg'; module.exports = { getBlocks() { return { text_read: { color: EntryStatic.colorSet.block.default.TEXT, outerLine: EntryStatic.colorSet.block.darken.TEXT, fontColor: EntryStatic.colorSet.common.WHITE, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'textBoxWithSelf', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.TEXT, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, ], events: {}, def: { params: [null, null], type: 'text_read', }, pyHelpDef: { params: ['A&value', null], type: 'text_read', }, paramsKeyMap: { VALUE: 0, }, class: 'text', isNotFor: ['sprite'], func(sprite, script) { const targetId = script.getField('VALUE', script); let targetEntity; if (targetId === 'self') { if (sprite.type !== 'textBox') { throw new Error('textBox가 아닙니다.'); } targetEntity = sprite; } else { targetEntity = Entry.container.getEntity(targetId); } let value = targetEntity.getText() || ''; value = value.replace(/\n/gim, ' '); return value; }, syntax: { js: [], py: [ { syntax: 'Entry.contents_of_textbox(%1)', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'textBoxWithSelf', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.TEXT, converter: Entry.block.converters.returnStringKey, codeMap: 'Entry.CodeMap.Entry.text_read[0]', }, ], }, ], }, }, text_write: { color: EntryStatic.colorSet.block.default.TEXT, outerLine: EntryStatic.colorSet.block.darken.TEXT, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: `block_icon/${filename}`, size: 11, }, ], events: {}, def: { params: [ { type: 'text', params: [Lang.Blocks.entry], }, null, ], type: 'text_write', }, pyHelpDef: { params: [ { type: 'text', params: ['A&value'], }, null, ], type: 'text_write', }, paramsKeyMap: { VALUE: 0, }, class: 'text', isNotFor: ['sprite'], func(sprite, script) { const text = script.getStringValue('VALUE', script); sprite.setText(text); return script.callReturn(); }, syntax: { js: [], py: ['Entry.write_text(%1)'] }, }, text_append: { color: EntryStatic.colorSet.block.default.TEXT, outerLine: EntryStatic.colorSet.block.darken.TEXT, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: `block_icon/${filename}`, size: 11, }, ], events: {}, def: { params: [ { type: 'text', params: [Lang.Blocks.entry], }, null, ], type: 'text_append', }, pyHelpDef: { params: [ { type: 'text', params: ['A&value'], }, null, ], type: 'text_append', }, paramsKeyMap: { VALUE: 0, }, class: 'text', isNotFor: ['sprite'], func(sprite, script) { const text = script.getStringValue('VALUE', script); sprite.setText(`${sprite.getText()}${text}`); return script.callReturn(); }, syntax: { js: [], py: ['Entry.append_text(%1)'] }, }, text_prepend: { color: EntryStatic.colorSet.block.default.TEXT, outerLine: EntryStatic.colorSet.block.darken.TEXT, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: `block_icon/${filename}`, size: 11, }, ], events: {}, def: { params: [ { type: 'text', params: [Lang.Blocks.entry], }, null, ], type: 'text_prepend', }, pyHelpDef: { params: [ { type: 'text', params: ['A&value'], }, null, ], type: 'text_prepend', }, paramsKeyMap: { VALUE: 0, }, class: 'text', isNotFor: ['sprite'], func(sprite, script) { const text = script.getStringValue('VALUE', script); sprite.setText(`${text}${sprite.getText()}`); return script.callReturn(); }, syntax: { js: [], py: ['Entry.prepend_text(%1)'] }, }, text_change_effect: { color: EntryStatic.colorSet.block.default.TEXT, outerLine: EntryStatic.colorSet.block.darken.TEXT, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ // display, actual value [Lang.Workspace.font_textblock_strikethrough, 'strike'], [Lang.Workspace.font_textblock_underline, 'underLine'], [Lang.Workspace.font_textblock_italic, 'fontItalic'], [Lang.Workspace.font_textblock_bold, 'fontBold'], ], value: 'strike', fontSize: 10, textColor: '#fff', bgColor: EntryStatic.colorSet.block.darken.TEXT, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Dropdown', options: [ [Lang.General.apply, 'on'], [Lang.General.clear, 'off'], ], value: 'on', fontSize: 10, textColor: '#fff', bgColor: EntryStatic.colorSet.block.darken.TEXT, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: `block_icon/${filename}`, size: 11, }, ], events: {}, def: { params: [null], type: 'text_change_effect', }, paramsKeyMap: { EFFECT: 0, MODE: 1, }, class: 'text', isNotFor: ['sprite'], func(sprite, script) { const effect = script.getField('EFFECT'); const mode = script.getField('MODE'); sprite.setTextEffect(effect, mode); return script.callReturn(); }, syntax: { js: [], py: ['Entry.changeTextEffect("%1", "%2")'] }, }, text_change_font: { color: EntryStatic.colorSet.block.default.TEXT, outerLine: EntryStatic.colorSet.block.darken.TEXT, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'fonts', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.TEXT, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: `block_icon/${filename}`, size: 11, }, ], events: {}, def: { params: [null], type: 'text_change_font', }, paramsKeyMap: { FONT: 0, }, class: 'text', isNotFor: ['sprite'], func(sprite, script) { const font = script.getField('FONT'); sprite.setFontWithLog(`${sprite.getFontSize()} ${font}`, false); return script.callReturn(); }, syntax: { js: [], py: ['Entry.text_change_font("%1")'] }, }, text_change_font_color: { color: EntryStatic.colorSet.block.default.TEXT, outerLine: EntryStatic.colorSet.block.darken.TEXT, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: `block_icon/${filename}`, size: 11, }, ], events: {}, def: { params: [ { type: 'text_color', }, null, ], type: 'text_change_font_color', }, paramsKeyMap: { VALUE: 0, }, class: 'text', isNotFor: ['sprite'], func(sprite, script) { let color = script.getStringValue('VALUE', script); if (color.indexOf('#') !== 0) { color = `#${color}`; } sprite.setColorWithLog(color); return script.callReturn(); }, syntax: { js: [], py: ['Entry.text_change_font_color("%1")'] }, }, text_change_bg_color: { color: EntryStatic.colorSet.block.default.TEXT, outerLine: EntryStatic.colorSet.block.darken.TEXT, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: `block_icon/${filename}`, size: 11, }, ], events: {}, def: { params: [ { type: 'text_color', }, null, ], type: 'text_change_bg_color', }, paramsKeyMap: { VALUE: 0, }, class: 'text', isNotFor: ['sprite'], func(sprite, script) { let color = script.getStringValue('VALUE', script); if (color.indexOf('#') !== 0) { color = `#${color}`; } sprite.setBGColourWithLog(color); return script.callReturn(); }, syntax: { js: [], py: ['Entry.text_change_bg_color("%1")'] }, }, text_flush: { color: EntryStatic.colorSet.block.default.TEXT, outerLine: EntryStatic.colorSet.block.darken.TEXT, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: `block_icon/${filename}`, size: 11, }, ], events: {}, def: { params: [null], type: 'text_flush', }, class: 'text', isNotFor: ['sprite'], func(sprite, script) { sprite.setText(''); return script.callReturn(); }, syntax: { js: [], py: ['Entry.clear_text()'] }, }, }; }, }; ================================================ FILE: src/playground/blocks/block_variable.js ================================================ module.exports = { getBlocks() { return { variableAddButton: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, params: [ { type: 'Text', text: Lang.Workspace.variable_create, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], def: { type: 'variableAddButton', }, events: { mousedown: [ function() { Entry.variableContainer.openVariableAddPanel('variable'); }, ], }, syntax: { js: [], py: [''] }, }, listAddButton: { skeleton: 'basic_button', color: EntryStatic.colorSet.common.BUTTON_BACKGROUND, params: [ { type: 'Text', text: Lang.Workspace.create_list_block, color: EntryStatic.colorSet.common.BUTTON, align: 'center', }, ], def: { type: 'listAddButton', }, events: { mousedown: [ function() { Entry.variableContainer.openVariableAddPanel('list'); }, ], }, }, ask_and_wait: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/variable_icon.svg', size: 11, }, ], events: { viewAdd: [ function() { if (Entry.container) { Entry.container.showProjectAnswer(); } }, ], viewDestroy: [ function(block, notIncludeSelf) { if (Entry.container) { Entry.container.hideProjectAnswer(block, notIncludeSelf); } }, ], }, def: { params: [ { type: 'text', params: [Lang.Blocks.block_hi], }, null, ], type: 'ask_and_wait', }, pyHelpDef: { params: [ { type: 'text', params: ['A&value'], }, null, ], type: 'ask_and_wait', }, paramsKeyMap: { VALUE: 0, }, class: 'ask', isNotFor: [], func(sprite, script) { const inputModel = Entry.container.inputValue; const inputView = Entry.stage.inputField; const message = script.getValue('VALUE', script); if (_.isUndefined(message) || message === '') { throw new Error('message can not be empty'); } if (inputModel.sprite == sprite && inputView && !inputView._isHidden) { return script; } else if (inputModel.sprite != sprite && script.isInit) { if (sprite.dialog) { sprite.dialog.remove(); } delete script.isInit; return script.callReturn(); } else if ( inputModel.complete && inputModel.sprite == sprite && inputView._isHidden && script.isInit ) { if (sprite.dialog) { sprite.dialog.remove(); } delete inputModel.complete; delete script.isInit; return script.callReturn(); } else { Entry.stage.showInputField(); new Entry.Dialog(sprite, Entry.convertToRoundedDecimals(message, 3), 'ask'); inputModel.script = script; inputModel.sprite = sprite; inputModel.complete = false; script.isInit = true; return script; } }, syntax: { js: [], py: ['Entry.input(%1)'] }, }, get_canvas_input_value: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.VARIABLE_get_canvas_input_value, color: '#fff', }, ], events: { viewAdd: [ function() { if (Entry.container) { Entry.container.showProjectAnswer(); } }, ], viewDestroy: [ function(block, notIncludeSelf) { if (Entry.container) { Entry.container.hideProjectAnswer(block, notIncludeSelf); } }, ], }, def: { params: [null], type: 'get_canvas_input_value', }, class: 'ask', isNotFor: [], func(sprite, script) { return Entry.container.getInputValue(); }, syntax: { js: [], py: [ { template: '%1', syntax: 'Entry.answer()', blockType: 'param', textParams: [ { type: 'Text', text: 'Entry.answer()', color: '#fff', }, ], }, ], }, }, set_visible_answer: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ [Lang.Blocks.CALC_timer_visible_show, 'SHOW'], [Lang.Blocks.CALC_timer_visible_hide, 'HIDE'], ], value: 'SHOW', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/variable_icon.svg', size: 11, }, ], events: { viewAdd: [ function() { if (Entry.container) { Entry.container.showProjectAnswer(); } }, ], viewDestroy: [ function(block, notIncludeSelf) { if (Entry.container) { Entry.container.hideProjectAnswer(block, notIncludeSelf); } }, ], }, def: { params: ['HIDE', null], type: 'set_visible_answer', }, pyHelpDef: { params: ['A&value', null], type: 'set_visible_answer', }, paramsKeyMap: { BOOL: 0, }, class: 'ask', isNotFor: [], func(sprite, script) { const bool = script.getField('BOOL', script); if (bool === 'HIDE') { Entry.container.inputValue.setVisible(false); } else { Entry.container.inputValue.setVisible(true); } return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.answer_view(%1)', textParams: [ { type: 'Dropdown', options: [ [Lang.Blocks.CALC_timer_visible_show, 'SHOW'], [Lang.Blocks.CALC_timer_visible_hide, 'HIDE'], ], value: 'SHOW', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnStringValueLowerCase, codeMap: 'Entry.CodeMap.Entry.set_visible_answer[0]', }, ], }, ], }, }, get_variable: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic_string_field', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'variables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.VARIABLE_get_variable_1, color: 'white', }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [null], type: 'get_variable', }, pyHelpDef: { params: ['A&value'], type: 'get_variable', }, paramsKeyMap: { VARIABLE: 0, }, class: 'variable', isNotFor: ['variableNotExist'], func(sprite, script) { const variableId = script.getField('VARIABLE', script); const variable = Entry.variableContainer.getVariable(variableId, sprite); return variable.getValue(); }, syntax: { js: [], py: [ { syntax: '%1', passTest: true, keyOption: 'get_variable', blockType: 'param', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'variables', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnRawStringKey, }, ], }, ], }, }, change_variable: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'variables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/variable_icon.svg', size: 11, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [ null, { type: 'text', params: ['10'], }, null, ], type: 'change_variable', }, pyHelpDef: { params: [ 'A&value', { type: 'text', params: ['B&value'], }, null, ], type: 'change_variable', }, paramsKeyMap: { VARIABLE: 0, VALUE: 1, }, class: 'variable', isNotFor: ['variableNotExist'], func(sprite, script) { const variableId = script.getField('VARIABLE', script); let value = script.getValue('VALUE', script); let fixed = 0; if (value == false && typeof value === 'boolean') { throw new Error('Type is not correct'); } const variable = Entry.variableContainer.getVariable(variableId, sprite); const { isRealTime_ } = variable; let variableValue = variable.getValue(); let sumValue; if (Entry.Utils.isNumber(value) && variable.isNumber()) { value = Entry.parseNumber(value); variableValue = Entry.parseNumber(variableValue); fixed = Entry.getMaxFloatPoint([value, variable.getValue()]); sumValue = new BigNumber(value) .plus(variableValue) .toNumber() .toFixed(fixed); } else { sumValue = `${variableValue}${value}`; } if (!isRealTime_) { variable.setValue(sumValue); return script.callReturn(); } else { return new Promise(async (resolve, reject) => { try { await variable.setValue(sumValue); resolve(); } catch (e) { reject(e); } }); } }, syntax: { js: [], py: [ { syntax: '%1 += %2', passTest: true, textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'variables', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnRawStringKey, }, { type: 'Block', accept: 'string', }, ], }, { syntax: '%1 = %1 + %2', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'variables', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnRawStringKey, }, { type: 'Block', accept: 'string', }, ], }, ], }, }, set_variable: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'variables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/variable_icon.svg', size: 11, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [ null, { type: 'text', params: ['10'], }, null, ], type: 'set_variable', }, pyHelpDef: { params: [ 'A&value', { type: 'text', params: ['B&value'], }, null, ], type: 'set_variable', }, paramsKeyMap: { VARIABLE: 0, VALUE: 1, }, class: 'variable', isNotFor: ['variableNotExist'], func(sprite, script) { const variableId = script.getField('VARIABLE', script); const value = script.getValue('VALUE', script); const variable = Entry.variableContainer.getVariable(variableId, sprite); const { isRealTime_ } = variable; if (!isRealTime_) { variable.setValue(value); return script.callReturn(); } else { return new Promise(async (resolve, reject) => { try { await variable.setValue(value); resolve(); } catch (e) { reject(e); } }); } }, syntax: { js: [], py: [ { syntax: '%1 = %2', passTest: true, blockType: 'variable', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'variables', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnRawStringKey, }, { type: 'Block', accept: 'string', }, ], }, ], }, }, show_variable: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'variables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/variable_icon.svg', size: 11, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [null, null], type: 'show_variable', }, pyHelpDef: { params: ['A&value', null], type: 'show_variable', }, paramsKeyMap: { VARIABLE: 0, }, class: 'variable_visibility', isNotFor: ['variableNotExist'], func(sprite, script) { const variableId = script.getField('VARIABLE', script); const variable = Entry.variableContainer.getVariable(variableId, sprite); variable.setVisible(true); variable.updateView(); return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.show_variable(%1)', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'variables', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnStringKey, }, ], }, ], }, }, hide_variable: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'variables', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/variable_icon.svg', size: 11, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [null, null], type: 'hide_variable', }, pyHelpDef: { params: ['A&value', null], type: 'hide_variable', }, paramsKeyMap: { VARIABLE: 0, }, class: 'variable_visibility', isNotFor: ['variableNotExist'], func(sprite, script) { const variableId = script.getField('VARIABLE', script); const variable = Entry.variableContainer.getVariable(variableId, sprite); variable.setVisible(false); return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.hide_variable(%1)', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'variables', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnStringKey, }, ], }, ], }, }, value_of_index_from_list: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.VARIABLE_value_of_index_from_list_1, color: 'white', }, { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.VARIABLE_value_of_index_from_list_2, color: 'white', }, { type: 'Block', isListIndex: true, accept: 'string', defaultType: 'number', }, { type: 'Text', text: Lang.Blocks.VARIABLE_value_of_index_from_list_3, color: 'white', }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [ null, null, null, { type: 'number', params: ['1'], }, ], type: 'value_of_index_from_list', }, pyHelpDef: { params: [ null, 'A&value', null, { type: 'number', params: ['B&value'], }, ], type: 'value_of_index_from_list', }, paramsKeyMap: { LIST: 1, INDEX: 3, }, class: 'list_element', isNotFor: ['listNotExist'], func(sprite, script) { const listId = script.getField('LIST', script); let index = script.getValue('INDEX', script); const list = Entry.variableContainer.getList(listId, sprite); index = Entry.getListRealIndex(index, list); const array = list.getArray(); if (!array || !Entry.Utils.isNumber(index) || index > array.length) { throw new Error('can not insert value to array'); } return array[index - 1].data; }, syntax: { js: [], py: [ { syntax: '%2[%4]', passTest: true, blockType: 'param', textParams: [ undefined, { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnRawStringKey, }, undefined, { type: 'Block', accept: 'string', paramType: 'index', }, ], }, ], }, }, add_value_to_list: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/variable_icon.svg', size: 11, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [ { type: 'text', params: ['10'], }, null, null, ], type: 'add_value_to_list', }, pyHelpDef: { params: [ { type: 'text', params: ['B&value'], }, 'A&value', null, ], type: 'add_value_to_list', }, paramsKeyMap: { VALUE: 0, LIST: 1, }, class: 'list', isNotFor: ['listNotExist'], func(sprite, script) { const listId = script.getField('LIST', script); const value = script.getValue('VALUE', script); const list = Entry.variableContainer.getList(listId, sprite); if (!list.isCloud_) { list.appendValue(value); return script.callReturn(); } else { return new Promise(async (resolve, reject) => { try { await list.appendValue(value); resolve(); } catch (e) { reject(e); } }); } }, syntax: { js: [], py: [ { passTest: true, syntax: '%2.append(%1)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnRawStringKey, }, ], }, ], }, }, remove_value_from_list: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic', statements: [], params: [ { type: 'Block', isListIndex: true, accept: 'string', defaultType: 'number', }, { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/variable_icon.svg', size: 11, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [ { type: 'number', params: ['1'], }, null, null, ], type: 'remove_value_from_list', }, pyHelpDef: { params: [ { type: 'number', params: ['B&value'], }, 'A&value', null, ], type: 'remove_value_from_list', }, paramsKeyMap: { VALUE: 0, LIST: 1, }, class: 'list', isNotFor: ['listNotExist'], func(sprite, script) { const listId = script.getField('LIST', script); const value = script.getValue('VALUE', script); const list = Entry.variableContainer.getList(listId, sprite); const array = list.getArray(); if (!array || !Entry.Utils.isNumber(value) || value > array.length) { throw new Error('can not remove value from array'); } const { isRealTime_ } = list; if (!isRealTime_) { list.deleteValue(+value); return script.callReturn(); } else { return new Promise(async (resolve, reject) => { try { await list.deleteValue(+value); resolve(); } catch (e) { reject(e); } }); } }, syntax: { js: [], py: [ { syntax: '%2.pop(%1)', passTest: true, textParams: [ { type: 'Block', accept: 'string', paramType: 'index', }, { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnRawStringKey, }, ], }, ], }, }, insert_value_to_list: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', isListIndex: true, accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/variable_icon.svg', size: 11, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [ { type: 'text', params: ['10'], }, null, { type: 'text', params: ['1'], }, null, ], type: 'insert_value_to_list', }, pyHelpDef: { params: [ { type: 'text', params: ['C&value'], }, 'A&value', { type: 'text', params: ['B&value'], }, null, ], type: 'insert_value_to_list', }, paramsKeyMap: { DATA: 0, LIST: 1, INDEX: 2, }, class: 'list', isNotFor: ['listNotExist'], func(sprite, script) { const listId = script.getField('LIST', script); const [data, index] = script.getValues(['DATA', 'INDEX'], script); const list = Entry.variableContainer.getList(listId, sprite); const array = list.getArray(); if ( !array || !Entry.Utils.isNumber(index) || index == 0 || index > array.length + 1 ) { throw new Error('can not insert value to array'); } const { isRealTime_ } = list; if (!isRealTime_) { list.insertValue(index, data); return script.callReturn(); } else { return new Promise(async (resolve, reject) => { try { await list.insertValue(index, data); resolve(); } catch (e) { reject(e); } }); } }, syntax: { js: [], py: [ { syntax: '%2.insert(%3, %1)', passTest: true, textParams: [ { type: 'Block', accept: 'string', }, { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnRawStringKey, }, { type: 'Block', accept: 'string', paramType: 'index', }, ], }, ], }, }, change_value_list_index: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Block', isListIndex: true, accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/variable_icon.svg', size: 11, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [ null, { type: 'text', params: ['1'], }, { type: 'text', params: ['10'], }, null, ], type: 'change_value_list_index', }, pyHelpDef: { params: [ 'A&value', { type: 'text', params: ['B&value'], }, { type: 'text', params: ['C&value'], }, null, ], type: 'change_value_list_index', }, paramsKeyMap: { LIST: 0, INDEX: 1, DATA: 2, }, class: 'list', isNotFor: ['listNotExist'], func(sprite, script) { const listId = script.getField('LIST', script); const [data, index] = script.getValues(['DATA', 'INDEX'], script); const list = Entry.variableContainer.getList(listId, sprite); const array = list.getArray(); if (!array || !Entry.Utils.isNumber(index) || index > array.length) { throw new Error('can not insert value to array'); } const { isRealTime_ } = list; if (!isRealTime_) { list.replaceValue(index, data); return script.callReturn(); } else { return new Promise(async (resolve, reject) => { try { await list.replaceValue(index, data); resolve(); } catch (e) { reject(e); } }); } }, syntax: { js: [], py: [ { syntax: '%1[%2] = %3', passTest: true, textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnRawStringKey, }, { type: 'Block', accept: 'string', paramType: 'index', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, length_of_list: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.VARIABLE_length_of_list_1, color: 'white', }, { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.VARIABLE_length_of_list_2, color: 'white', }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [null, null, null], type: 'length_of_list', }, pyHelpDef: { params: [null, 'A&value', null], type: 'length_of_list', }, paramsKeyMap: { LIST: 1, }, class: 'list', isNotFor: ['listNotExist'], func(sprite, script) { const listId = script.getField('LIST', script); const list = Entry.variableContainer.getList(listId, sprite); return list.getArray().length; }, syntax: { js: [], py: [ { syntax: 'len(%2)', blockType: 'param', passTest: true, textParams: [ undefined, { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnRawStringKey, }, ], }, ], }, }, is_included_in_list: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, fontColor: '#fff', skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Text', text: Lang.Blocks.VARIABLE_is_included_in_list_1, color: 'white', }, { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Text', text: Lang.Blocks.VARIABLE_is_included_in_list_2, color: 'white', }, { type: 'Block', accept: 'string', }, { type: 'Text', text: Lang.Blocks.VARIABLE_is_included_in_list_3, color: 'white', }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [ null, null, null, { type: 'text', params: ['10'], }, null, ], type: 'is_included_in_list', }, pyHelpDef: { params: [ null, 'B&value', null, { type: 'text', params: ['A&value'], }, null, ], type: 'is_included_in_list', }, paramsKeyMap: { LIST: 1, DATA: 3, }, class: 'list', isNotFor: ['listNotExist'], func(sprite, script) { const listId = script.getField('LIST', script); const data = script.getStringValue('DATA', script); const list = Entry.variableContainer.getList(listId, sprite); if (!list) { return false; } const arr = list.getArray(); for (let i = 0, len = arr.length; i < len; i++) { if (arr[i].data.toString() == data.toString()) { return true; } } return false; }, syntax: { js: [], py: [ { syntax: '%4 in %2', blockType: 'param', passTest: true, textParams: [ undefined, { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnRawStringKey, }, undefined, { type: 'Block', accept: 'string', }, ], }, ], }, }, show_list: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/variable_icon.svg', size: 11, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [null, null], type: 'show_list', }, pyHelpDef: { params: ['A&value', null], type: 'show_list', }, paramsKeyMap: { LIST: 0, }, class: 'list_visibility', isNotFor: ['listNotExist'], func(sprite, script) { const listId = script.getField('LIST', script); const list = Entry.variableContainer.getList(listId); list.setVisible(true); return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.show_list(%1)', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnStringKey, }, ], }, ], }, }, hide_list: { color: EntryStatic.colorSet.block.default.VARIABLE, outerLine: EntryStatic.colorSet.block.darken.VARIABLE, skeleton: 'basic', statements: [], params: [ { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 10, bgColor: EntryStatic.colorSet.block.darken.VARIABLE, arrowColor: EntryStatic.colorSet.arrow.default.DEFAULT, }, { type: 'Indicator', img: 'block_icon/variable_icon.svg', size: 11, }, ], events: { dataAdd: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.addRef('_variableRefs', block); } }, ], dataDestroy: [ function(block) { const vc = Entry.variableContainer; if (vc) { vc.removeRef('_variableRefs', block); } }, ], }, def: { params: [null, null], type: 'hide_list', }, pyHelpDef: { params: ['A&value', null], type: 'hide_list', }, paramsKeyMap: { LIST: 0, }, class: 'list_visibility', isNotFor: ['listNotExist'], func(sprite, script) { const listId = script.getField('LIST', script); const list = Entry.variableContainer.getList(listId); list.setVisible(false); return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Entry.hide_list(%1)', textParams: [ { type: 'DropdownDynamic', value: null, menuName: 'lists', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.VARIABLE, converter: Entry.block.converters.returnStringKey, }, ], }, ], }, }, }; }, }; ================================================ FILE: src/playground/blocks/hardware/block_0uboard.js ================================================ 'use strict'; Entry.pyocoding = { id: ['52.1'], name: '0uboard', url: 'https://www.pyocoding.co.kr', imageName: '0uboard.png', title: { ko: '0U보드', en: '0UBOARD', }, setZero: function() { if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue = { GET: {}, SET: {}, }; } else { const keySet = Object.keys(Entry.hw.sendQueue.SET); keySet.forEach((key) => { Entry.hw.sendQueue.SET[key].data = 0; Entry.hw.sendQueue.SET[key].time = new Date().getTime(); }); } Entry.hw.update(); }, sensorTypes: { ALIVE: 0, DIGITAL: 1, ANALOG: 2, PWM: 3, SERVO_PIN: 4, TONE: 5, PULSEIN: 6, ULTRASONIC: 7, TIMER: 8, OLED: 241, COM: 242, NEOPIXELCOLOR: 243, DOTMATRIX: 245, }, duration: { TIME_1ms: 1, TIME_5ms: 5, TIME_10ms: 10, TIME_20ms: 20, TIME_50ms: 50, TIME_100ms: 100, TIME_200ms: 200, TIME_500ms: 500, TIME_600ms: 600, }, highList: ['high', '1', 'on'], lowList: ['low', '0', 'off'], toneMap: { '1': [33, 65, 131, 262, 523, 1046, 2093, 4186], '2': [35, 69, 139, 277, 554, 1109, 2217, 4435], '3': [37, 73, 147, 294, 587, 1175, 2349, 4699], '4': [39, 78, 156, 311, 622, 1245, 2849, 4978], '5': [41, 82, 165, 330, 659, 1319, 2637, 5274], '6': [44, 87, 175, 349, 698, 1397, 2794, 5588], '7': [46, 92, 185, 370, 740, 1480, 2960, 5920], '8': [49, 98, 196, 392, 784, 1568, 3136, 6272], '9': [52, 104, 208, 415, 831, 1661, 3322, 6645], '10': [55, 110, 220, 440, 880, 1760, 3520, 7040], '11': [58, 117, 233, 466, 932, 1865, 3729, 7459], '12': [62, 123, 247, 494, 988, 1976, 3951, 7902], }, BlockState: {}, }; Entry.pyocoding.setLanguage = function() { return { ko: { Blocks: { GreenColor: '초록색', BlueColor: '파랑색', YellowColor: '노랑색', RedColor: '빨강색', GreenButton: '초록 버튼', BlueButton: '파랑 버튼', YellowButton: '노랑 버튼', RedButton: '빨강 버튼', }, template: { pyocoding_serial_set: '시리얼 통신으로 설정하고 %1 속도로 전송하기', pyocoding_ble_set: '블루투스 통신으로 설정하고 %1 속도로 전송하기', pyocoding_get_analog_value: '아날로그 %1 센서값', pyocoding_toggle_pin: '디지털 %1 번핀 %2', pyocoding_port_number: '%1', pyocoding_ultrasonic_get_value:'초음파 송신 %1 핀 수신 %2 핀', pyocoding_get_digital_button: '%1 누름', pyocoding_get_digital: '디지털 %1번 센서값', pyocoding_toggle_led: 'LED %1 을 %2', pyocoding_get_port_number1: '%1', pyocoding_get_port_number: '%1', pyocoding_get_ultrasonic_port_number: '%1', pyocoding_set_servo: '서보모터 %1번 핀을 %2 도로 정하기', pyocoding_oled_set: 'OLED %1 번째 줄의 %2 표시하기', pyocoding_pw_get_port_number: '%1', pyocoding_neopixel_set: '디지털 %1 번 핀에 연결된 %2 번째 네오픽셀 %3 개 사용하기', pyocoding_neopixel_led: '네오픽셀 %1 번에 %2 번째 LED R: %3 , G: %4 , B: %5 색을 밝기 %6 으로 켜기', pyocoding_neopixel_all_led: '네오픽셀 %1 번에 LED R: %2 , G: %3 , B: %4 색을 밝기 %5 으로 켜기', pyocoding_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', pyocoding_set_tone: '디지털 %1 번 핀을 %2 음으로 %3 옥타브로 %4 만큼 연주하기 %5', pyocoding_change_4095to255_value: '%1 값 %2을 %3로 변환하기', pyocoding_change_analog_to_temperature_tc_value: '아날로그 온도 변환 %1', pyocoding_get_touch_value : '터치 %1 센서값', pyocoding_dotmatrix : '도트매트릭스 %1 번 배열에 %2 을 그리기', }, }, en: { Blocks: { GreenColor: 'Green Color', BlueColor: 'Blue Color', YellowColor: 'Yellow Color', RedColor: 'Red Color', GreenButton: 'Green Button', BlueButton: 'Blue Button', YellowButton: 'Yellow Button', RedButton: 'Red Button', }, template: { pyocoding_serial_set: 'Set Serial COMM %1 boardrates', pyocoding_ble_set: 'Set Bluetooth COMM %1 boardrates', pyocoding_get_analog_value: 'Analog %1 Value', pyocoding_toggle_pin: 'Digital %1 PIN %2', pyocoding_port_number: '%1', pyocoding_ultrasonic_get_value:'Ultrasonic Trigger %1 PIN echo %2 PIN Value', pyocoding_get_digital_button: '%1 Push', pyocoding_get_digital: 'Digital %1 PIN Value', pyocoding_toggle_led: '%1 LED %2', pyocoding_get_port_number1: '%1', pyocoding_get_port_number: '%1', pyocoding_get_ultrasonic_port_number: '%1', pyocoding_set_servo: 'Servo %1 PIN %2 degree set', pyocoding_oled_set: 'OLE %1 line %2 Display', pyocoding_pw_get_port_number: '%1', pyocoding_neopixel_set: '디지털 %1 번핀에 연결된 %2 개의 네오픽셀 LED 사용하기', pyocoding_neopixel_led: '디지털 %1 번핀에 연결된 %2 번째 네오픽셀 LED R: %3 , G: %4 , B: %5 색으로 켜기', pyocoding_neopixel_all_led: '디지털 %1 번 핀에 연결된 %2 번째 네오픽셀 LED R: %3 , G: %4 , B: %5 색으로 켜기', pyocoding_digital_pwm: 'Digital %1 Pin %2 %3', pyocoding_set_tone: 'Play tone pin %1 on note %2 octave %3 beat %4 %5', pyocoding_change_4095to255_value: 'Analog 4095to255 %1', pyocoding_change_analog_to_temperature_tc_value: 'Analog to Tc %1', pyocoding_get_touch_value : 'touch %1 value', pyocoding_dotmatrix : '도트매트릭스 %1 번 배열에 %2 을 그리기', }, }, }; }; Entry.pyocoding.blockMenuBlocks = [ //'pyocoding_serial_set', //'pyocoding_ble_set', 'pyocoding_get_analog_value', 'pyocoding_ultrasonic_get_value', 'pyocoding_get_digital_button', 'pyocoding_get_digital', 'pyocoding_toggle_pin', 'pyocoding_toggle_led', 'pyocoding_digital_pwm', 'pyocoding_set_tone', 'pyocoding_set_servo', 'pyocoding_oled_set', 'pyocoding_neopixel_set', 'pyocoding_neopixel_led', 'pyocoding_neopixel_all_led', 'pyocoding_change_4095to255_value', 'pyocoding_change_analog_to_temperature_tc_value', 'pyocoding_get_touch_value', 'pyocoding_dotmatrix', ]; Entry.pyocoding.getBlocks = function() { return { pyocoding_serial_set: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params : [ { type: 'Dropdown', options: [ ['1','1'], ['2','2'], ['3','3'], ['4','4'], ['5','5'], ['6','6'], ['7','7'], ['8','8'], ['9','9'], ['10','10'], ], value:'10', fontSize:11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], type: 'pyocoding_serial_set', }, isNotFor: [ '0uboard' ], syntax: undefined, paramsKeyMap: { NOTE: 0, }, class: 'COM', func: function (sprite, script) { var data = script.getField('NOTE'); if(!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } Entry.hw.sendQueue['SET'][0] = { type: 242, data: data, time: new Date().getTime() }; return script.callReturn(); }, }, pyocoding_ble_set: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { "type": "Dropdown", "options": [ ["1","1"], ["2","2"], ["3","3"], ], "value":"3", "fontSize":11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { "params": [ null, ], "type": "pyocoding_ble_set" }, isNotFor: [ '0uboard' ], paramsKeyMap: { "VALUE1": 0, }, class: "COM", func: function (sprite, script) { var data = script.getField("VALUE1"); if(!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } Entry.hw.sendQueue['SET'][1] = { type: 242, data: data, time: new Date().getTime() }; return script.callReturn(); }, }, pyocoding_get_analog_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], events: {}, params: [ { "type": "Dropdown", "options": [ [ "A0", "0" ], [ "A1", "1" ], [ "A2", "2" ], [ "A3", "3" ], [ "A4", "4" ], //[ "A5", "5" ], ], "value": "0", "fontSize": 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], def: { params: [ null ], "type": "pyocoding_get_analog_value" }, isNotFor: [ '0uboard' ], class: "SENSOR", paramsKeyMap: { "PORT": 0, }, func: function (sprite, script) { var port = script.getValue("PORT", script); var ANALOG = Entry.hw.portData.ANALOG; //console.log(port,ANALOG) if (port[0] === "A") port = port.substring(1) return ANALOG ? ANALOG[port] || 0 : 0; }, }, pyocoding_change_4095to255_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], events: {}, params: [ { "type": "Block", "accept": "string" }, { "type": "Block", "accept": "string" }, { "type": "Block", "accept": "string" }, ], def: { params: [ { "type": "text", "params": [ "0" ] }, { "type": "text", "params": [ "4095" ] }, { "type": "text", "params": [ "255" ] }, ], "type": "pyocoding_change_4095to255_value" }, isNotFor: [ '0uboard' ], class: "ext", paramsKeyMap: { "VALUE": 0, "VALUE2": 1, "VALUE3": 2, }, func: function (sprite, script) { var value = script.getNumberValue("VALUE"); var value2 = script.getNumberValue("VALUE2"); var value3 = script.getNumberValue("VALUE3"); console.log(value,value2,value3); var dividedValue = Math.floor(value / (value2 / value3)); return dividedValue; }, }, pyocoding_change_analog_to_temperature_tc_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], events: {}, params: [ { "type": "Block", "accept": "string" }, ], def: { params: [ { "type": "text", "params": [ "0" ] }, null ], "type": "pyocoding_change_analog_to_temperature_tc_value" }, isNotFor: [ '0uboard' ], class: "ext", paramsKeyMap: { "VALUE": 0, }, func: function (sprite, script) { var R1 = 10000; var logR2, R2, T, Tc, Tf; var c1 = 1.106836861e-03, c2 = 2.384641754e-04, c3 = 0.6507394466e-07; var Vo = script.getNumberValue("VALUE"); R2 = R1 * ((4095.0 / Vo) - 1.0); logR2 = Math.log(R2); T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2)); Tc = T - 273.15; //섭씨 //Tf = (Tc * 9.0)/ 5.0 + 32.0; //화씨 // Print the result to the console //console.log("vo:",Vo,"Tc:",Tc); // You can return the value in Fahrenheit as well return Tc; }, }, pyocoding_get_port_number: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: "basic_string_field", statements: [], params: [ { "type": "Dropdown", "options": [ [ "2", "2" ], [ "3", "3" ], [ "4", "4" ], [ "5", "5" ], [ "6", "6" ], [ "7", "7" ], //[ "8", "8" ], //[ "9", "9" ], ], "value": "2", "fontSize": 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, } ], events: {}, def: { "params": [ null ] }, paramsKeyMap: { "PORT": 0 }, func: function (sprite, script) { return script.getStringField("PORT"); }, }, pyocoding_get_ultrasonic_port_number: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: "basic_string_field", statements: [], params: [ { "type": "Dropdown", "options": [ [ "6", "6" ], [ "7", "7" ], //[ "8", "8" ], //[ "9", "9" ], ], "value": "2", "fontSize": 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, } ], events: {}, def: { "params": [ null ] }, paramsKeyMap: { "PORT": 0 }, func: function (sprite, script) { return script.getStringField("PORT"); }, }, pyocoding_port_number: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: "basic_string_field", statements: [], params: [ { "type": "Dropdown", "options": [ [ Lang.Blocks.RedButton, "6" ], [ Lang.Blocks.BlueButton, "7" ], [ Lang.Blocks.GreenButton, "8" ], [ Lang.Blocks.YellowButton, "9" ], ], value: "6", fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, } ], events: {}, def: { "params": [ null ] }, paramsKeyMap: { "PORT": 0 }, func: function (sprite, script) { return script.getStringField("PORT"); }, }, pyocoding_toggle_pin: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { "type": "Block", "accept": "string" }, { "type": "Block", "accept": "string" } ], events: {}, def: { "params": [ { "type": "pyocoding_get_port_number" }, { "type": "arduino_get_digital_toggle", "params": [ "on" ], }, null ], "type": "pyocoding_toggle_pin" }, paramsKeyMap: { "PORT": 0, "VALUE": 1, }, isNotFor: [ '0uboard' ], class: "run", func: function (sprite, script) { var port = script.getNumberValue("PORT"); var value = script.getValue("VALUE"); if(typeof value === 'string') { value = value.toLowerCase(); } if(Entry.ArduinoExt.highList.indexOf(value) > -1) { value = 255; } else if(Entry.ArduinoExt.lowList.indexOf(value) > -1) { value = 0; } else { throw new Error(); } if(!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } Entry.hw.sendQueue['SET'][port] = { type: Entry.pyocoding.sensorTypes.DIGITAL, data: value, time: new Date().getTime() }; return script.callReturn(); }, }, pyocoding_ultrasonic_get_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: "basic_string_field", params: [ { "type": "Block", "accept": "string" }, { "type": "Block", "accept": "string" } ], def: { params: [{ type: 'pyocoding_get_ultrasonic_port_number', params: [ '6' ], }, { type: 'pyocoding_get_ultrasonic_port_number', params: [ '7' ], }], type: "pyocoding_ultrasonic_get_value" }, paramsKeyMap: { "PORT1": 0, "PORT2": 1, }, func: function (sprite, script) { var port1 = script.getNumberValue("PORT1", script); var port2 = script.getNumberValue("PORT2", script); if(!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } delete Entry.hw.sendQueue['SET'][port1]; delete Entry.hw.sendQueue['SET'][port2]; if(!Entry.hw.sendQueue['GET']) { Entry.hw.sendQueue['GET'] = {}; } Entry.hw.sendQueue['GET'][Entry.pyocoding.sensorTypes.ULTRASONIC] = { port: [port1, port2], time: new Date().getTime() }; return Entry.hw.portData.ULTRASONIC || 0; }, isNotFor: [ '0uboard' ], class: "SENSOR", }, pyocoding_get_digital_button: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: "basic_boolean_field", params: [{ "type": "Block", "accept": "string" }], def: { "params": [ { "type": "pyocoding_port_number", "params": [6] } ], "type": "pyocoding_get_digital_button" }, paramsKeyMap: { "PORT": 0 }, class: "digital", isNotFor: [ '0uboard' ], func: function (sprite, script) { var port = script.getNumberValue("PORT", script); var DIGITAL = Entry.hw.portData.DIGITAL; if(!Entry.hw.sendQueue['GET']) { Entry.hw.sendQueue['GET'] = {}; } Entry.hw.sendQueue['GET'][Entry.pyocoding.sensorTypes.DIGITAL] = { port: port, time: new Date().getTime() }; return (DIGITAL) ? DIGITAL[port] || 0 : 0; }, }, pyocoding_get_digital: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: "basic_boolean_field", params: [{ "type": "Block", "accept": "string" }], def: { "params": [ { "type": "pyocoding_get_port_number" } ], "type": "pyocoding_get_digital" }, paramsKeyMap: { "PORT": 0 }, isNotFor: [ '0uboard' ], class: "digital", func: function (sprite, script) { var port = script.getNumberValue("PORT", script); var DIGITAL = Entry.hw.portData.DIGITAL; if(!Entry.hw.sendQueue['GET']) { Entry.hw.sendQueue['GET'] = {}; } Entry.hw.sendQueue['GET'][Entry.pyocoding.sensorTypes.DIGITAL] = { port: port, time: new Date().getTime() }; return (DIGITAL) ? DIGITAL[port] || 0 : 0; }, }, pyocoding_get_port_number1: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: "basic_string_field", statements: [], params: [ { "type": "Dropdown", "options": [ [ Lang.Blocks.RedColor, "2" ], [ Lang.Blocks.BlueColor, "3" ], [ Lang.Blocks.GreenColor, "4" ], [ Lang.Blocks.YellowColor, "5" ], ], "value": "2", "fontSize": 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, } ], "events": {}, "def": { "params": [ null ] }, "paramsKeyMap": { "PORT": 0 }, "func": function (sprite, script) { return script.getStringField("PORT"); }, "class": "ArduinoExt" }, pyocoding_toggle_led: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', params: [ { "type": "Block", "accept": "string" }, { "type": "Block", "accept": "string" } ], def: { "params": [ { "type": "pyocoding_get_port_number1" }, { "type": "arduino_get_digital_toggle", "params": [ "on" ], }, ], "type": "pyocoding_toggle_led" }, "paramsKeyMap": { "PORT": 0, "VALUE": 1 }, "isNotFor": [ '0uboard' ], "class": "run", "func": function (sprite, script) { var port = script.getNumberValue("PORT"); var value = script.getValue("VALUE"); if(typeof value === 'string') { value = value.toLowerCase(); } if(Entry.ArduinoExt.highList.indexOf(value) > -1) { value = 255; } else if(Entry.ArduinoExt.lowList.indexOf(value) > -1) { value = 0; } else { throw new Error(); } if(!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } Entry.hw.sendQueue['SET'][port] = { type: Entry.pyocoding.sensorTypes.DIGITAL, data: value, time: new Date().getTime() }; return script.callReturn(); }, }, pyocoding_pw_get_port_number: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: "basic_string_field", statements: [], params: [ { "type": "Dropdown", "options": [ [ "5", "5" ] ], "value": "5", "fontSize": 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, } ], events: {}, def: { "params": [ null ] }, paramsKeyMap: { "PORT": 0 }, func: function (sprite, script) { return script.getStringField("PORT"); }, }, pyocoding_digital_pwm: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ], value: '2', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, { type: 'text', params: ['255'], }, null, ], type: 'pyocoding_digital_pwm', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'pwm', isNotFor: ['0uboard'], func: function(sprite, script) { //var port = script.getNumberValue("PORT"); var port = script.getField('PORT'); var value = script.getNumberValue('VALUE'); value = Math.round(value); value = Math.max(value, 0); value = Math.min(value, 255); if (!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } Entry.hw.sendQueue['SET'][port] = { type: Entry.DaduBlock.sensorTypes.PWM, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: ['Arduino.analogWrite(%1, %2)'] }, }, pyocoding_set_tone: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['10', '10'], ], value: '10', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [ ['무음', '0'], ['도', '1'], ['도#(레♭)', '2'], ['레', '3'], ['레#(미♭)', '4'], ['미', '5'], ['파', '6'], ['파#(솔♭)', '7'], ['솔', '8'], ['솔#(라♭)', '9'], ['라', '10'], ['라#(시♭)', '11'], ['시', '12'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [ ['1', '0'], ['2', '1'], ['3', '2'], ['4', '3'], ['5', '4'], ['6', '5'], ], value: '3', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, null, null, { type: 'text', params: ['1'], }, null, ], type: 'pyocoding_set_tone', }, paramsKeyMap: { PORT: 0, NOTE: 1, OCTAVE: 2, DURATION: 3, }, class: 'pwm', isNotFor: ['0uboard'], func: function(sprite, script) { var sq = Entry.hw.sendQueue; //var port = script.getNumberValue("PORT", script); var port = script.getField('PORT', script); if (!script.isStart) { var note = script.getNumberField('NOTE', script); var duration = script.getNumberValue('DURATION', script); if (duration < 0) { duration = 0; } if (note === 0 || duration === 0) { sq['SET'][port] = { type: Entry.DaduBlock.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; return script.callReturn(); } var octave = script.getNumberField('OCTAVE', script); var value = Entry.DaduBlock.toneMap[note][octave]; duration = duration * 1000; script.isStart = true; script.timeFlag = 1; if (!sq['SET']) { sq['SET'] = {}; } sq['SET'][port] = { type: Entry.DaduBlock.sensorTypes.TONE, data: { value: value, duration: duration, }, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, duration + 32); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; sq['SET'][port] = { type: Entry.DaduBlock.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; Entry.engine.isContinue = false; return script.callReturn(); } }, }, pyocoding_set_servo: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: "basic", statements: [], params: [ { "type": "Block", "accept": "string" }, { "type": "Block", "accept": "string" }, ], events: {}, def: { params: [ { type: "pyocoding_pw_get_port_number" }, { "type": "text", "params": [ "0" ] }, null ], type: "pyocoding_set_servo" }, paramsKeyMap: { "PORT": 0, "VALUE": 1 }, class: "ext", isNotFor: [ '0uboard' ], func: function (sprite, script) { var port = script.getNumberValue("PORT"); var value = script.getNumberValue("VALUE"); value = Math.round(value); value = Math.max(value, 0); value = Math.min(value, 180); if(!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } Entry.hw.sendQueue['SET'][port] = { type: 4, data: value, time: new Date().getTime() }; return script.callReturn(); }, "syntax": {} }, pyocoding_oled_set: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: "basic", statements: [], params: [ { "type": "Dropdown", "options": [ ["1","1"], ["2","2"], ["3","3"] ], "value":"1", "fontSize":11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { "type": "Block", "accept": "string" } ], events: {}, def: { "params": [ null, { "type":"text", "params": [ "1" ], }, ], "type": "pyocoding_oled_set" }, isNotFor: [ '0uboard' ], paramsKeyMap: { "VALUE1": 0, "VALUE2": 1 }, class: "ext", func: function (sprite, script) { var line = script.getField("VALUE1"); var text = script.getValue("VALUE2"); if(!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } Entry.hw.sendQueue['SET'][line] = { type: 241, data: text, time: new Date().getTime() }; return script.callReturn(); }, "syntax": {} }, pyocoding_neopixel_set: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { "type": "Dropdown", "options": [ ["1","1"], ["2","2"], ], "value":"1", "fontSize":11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_get_port_number', params: ['9'], }, null, { type: 'number', params: ['12'], }, null, ], type: 'pyocoding_neopixel_set', }, paramsKeyMap: { PORT: 0, INDEX: 1, VALUE: 2, }, class: 'neopixel', isNotFor: ['0uboard'], func(sprite, script) { var port = script.getNumberValue("PORT"); var mode = 1; var index = script.getNumberValue("INDEX"); var value = script.getNumberValue("VALUE"); if (!script.isStart) { if(!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } var duration = Entry.Orange.duration.TIME_10ms; script.isStart = true; script.timeFlag = 1; Entry.hw.sendQueue['SET'][port] = { type: Entry.pyocoding.sensorTypes.NEOPIXELCOLOR, data: { value : value, mode: mode, index: index, }, time: new Date().getTime() }; setTimeout(function() { script.timeFlag = 0; }, duration ); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { }, }, pyocoding_neopixel_led: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { "type": "Dropdown", "options": [ ["1","1"], ["2","2"], ], "value":"1", "fontSize":11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['1'], }, { type: 'number', params: ['255'], }, { type: 'number', params: ['255'], }, { type: 'number', params: ['255'], }, { type: 'number', params: ['100'], }, null, ], type: 'pyocoding_neopixel_led', }, paramsKeyMap: { INDEX : 0, POS: 1, RED: 2, GREEN: 3, BLUE: 4, BRIG: 5, }, class: 'neopixel', isNotFor: ['0uboard'], func(sprite, script) { var port = script.getNumberValue("INDEX"); var pos = script.getNumberValue("POS"); var red = script.getNumberValue("RED"); var green = script.getNumberValue("GREEN"); var blue = script.getNumberValue("BLUE"); var brig = script.getNumberValue("BRIG"); var mode = 2; if (!script.isStart) { if(!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } var duration = Entry.Orange.duration.TIME_10ms; script.isStart = true; script.timeFlag = 1; Entry.hw.sendQueue['SET'][port] = { type: Entry.pyocoding.sensorTypes.NEOPIXELCOLOR, data: { index : port, pos : pos, mode: mode, red: red, green: green, blue: blue, brig: brig, }, time: new Date().getTime() }; setTimeout(function() { script.timeFlag = 0; }, duration ); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { }, }, pyocoding_neopixel_all_led: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { "type": "Dropdown", "options": [ ["1","1"], ["2","2"], ], "value":"1", "fontSize":11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['255'], }, { type: 'number', params: ['255'], }, { type: 'number', params: ['255'], }, { type: 'number', params: ['100'], }, null, ], type: 'pyocoding_neopixel_all_led', }, paramsKeyMap: { INDEX : 0, RED: 1, GREEN: 2, BLUE: 3, BRIG: 4, }, class: 'neopixel', isNotFor: ['0uboard'], func(sprite, script) { var port = script.getNumberValue("INDEX"); var red = script.getNumberValue("RED"); var green = script.getNumberValue("GREEN"); var blue = script.getNumberValue("BLUE"); var brig = script.getNumberValue("BRIG"); var mode = 3; if (!script.isStart) { if(!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } var duration = Entry.Orange.duration.TIME_10ms; script.isStart = true; script.timeFlag = 1; Entry.hw.sendQueue['SET'][port] = { type: Entry.pyocoding.sensorTypes.NEOPIXELCOLOR, data: { index : port, mode: mode, red: red, green: green, blue: blue, brig: brig, }, time: new Date().getTime() }; setTimeout(function() { script.timeFlag = 0; }, duration ); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { }, }, pyocoding_dotmatrix: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { "type": "Dropdown", "options": [ ["0","0"], ["1","1"], ["2","2"], ["3","3"], ["4","4"], ["5","5"], ["6","6"], ["7","7"], ], "value":"0", "fontSize":11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['00001111'], }, { type: 'number', params: ['255'], }, { type: 'number', params: ['255'], }, { type: 'number', params: ['100'], }, null, ], type: 'pyocoding_dotmatrix', }, paramsKeyMap: { INDEX : 0, RED: 1, GREEN: 2, BLUE: 3, BRIG: 4, }, class: 'neopixel', isNotFor: ['0uboard'], func(sprite, script) { var port = script.getNumberValue("INDEX"); var red = script.getNumberValue("RED"); var green = script.getNumberValue("GREEN"); var blue = script.getNumberValue("BLUE"); var brig = script.getNumberValue("BRIG"); var mode = 3; let str = parseInt(String(red), 2); red = str; if(red > 255) red=255; console.log(red); if (!script.isStart) { if(!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } var duration = Entry.Orange.duration.TIME_10ms; script.isStart = true; script.timeFlag = 1; Entry.hw.sendQueue['SET'][port] = { type: Entry.pyocoding.sensorTypes.DOTMATRIX, data: { index : port, mode: mode, red: red, green: green, blue: blue, brig: brig, }, time: new Date().getTime() }; setTimeout(function() { script.timeFlag = 0; }, duration ); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { }, }, } //return }; //function module.exports = Entry.pyocoding; ================================================ FILE: src/playground/blocks/hardware/block_CloverSEntry1.js ================================================  'use strict'; Entry.CloverSEntry1 = { id: '38.1', name: 'CloverSEntry1', url: 'http://www.edu-rabbit.com', imageName: 'CloverSEntry1.png', title: { ko: '에듀래빗_클로버', en: 'Edurabbit_Clover', }, setZero: function() { if (!Entry.hw.sendQueue.SET && !Entry.hw.sendQueue.SET_CLOVER && !Entry.hw.sendQueue.GET) { Entry.hw.sendQueue = { GET: {}, SET: {}, GET_CLOVER: {}, SET_CLOVER: {}, }; } else { var self = this; if(Entry.hw.sendQueue.SET) { var keySet = Object.keys(Entry.hw.sendQueue.SET); var keyInt = null; keySet.forEach(function(key) { keyInt = parseInt(key); switch(keyInt) { case self.pinMaps.Digital_Port0 : case self.pinMaps.Digital_Port1 : Entry.hw.sendQueue.SET[key].data = 1; break; case self.pinMaps.Digital_Port2 : case self.pinMaps.Digital_Port3 : case self.pinMaps.Digital_Port4 : case self.pinMaps.Digital_Port5 : case self.pinMaps.Digital_Port6 : Entry.hw.sendQueue.SET[key].data = 0; break; default : Entry.hw.sendQueue.SET[key].data = 0xFF; break; } Entry.hw.sendQueue.SET[key].time = new Date().getTime(); }); } if(Entry.hw.sendQueue.GET) { var keySet = Object.keys(Entry.hw.sendQueue.GET); var keyInt = null; keySet.forEach(function(key) { keyInt = parseInt(key); switch(keyInt) { case self.sensorTypes.ULTRASONIC : Entry.hw.sendQueue.GET[key].port = [self.pinMaps.Ultrasonic_TRIG, self.pinMaps.Ultrasonic_ECHO]; Entry.hw.sendQueue.GET[key].data = 1; break; } Entry.hw.sendQueue.GET[key].time = new Date().getTime(); }); } if(Entry.hw.sendQueue.SET_CLOVER) { var keySet = Object.keys(Entry.hw.sendQueue.SET_CLOVER); var keyInt = null; keySet.forEach(function(key) { keyInt = parseInt(key); if(key == 0) { Entry.hw.sendQueue.SET_CLOVER[key].data = 0; } else if (key <= 80) { Entry.hw.sendQueue.SET_CLOVER[key].data = 1; } else if (key <= 100) { Entry.hw.sendQueue.SET_CLOVER[key].data = 0; } else if(key == 101) { Entry.hw.sendQueue.SET_CLOVER[key].data = 0; } Entry.hw.sendQueue.SET_CLOVER[key].time = new Date().getTime(); }); } if(Entry.hw.sendQueue.GET_CLOVER) { var keySet = Object.keys(Entry.hw.sendQueue.GET_CLOVER); var keyInt = null; keySet.forEach(function(key) { keyInt = parseInt(key); Entry.hw.sendQueue.GET_CLOVER[key].time = new Date().getTime(); }); } } Entry.hw.update(); }, monitorTemplate: { imgPath: 'hw/CloverSEntry1.png', width: 420, height: 420, listPorts: { M_SW1: { name: '스위치1', type: 'input', pos: { x: 0, y: 0 }}, M_SW2: { name: '스위치2', type: 'input', pos: { x: 0, y: 0 }}, M_ANALOG1: { name: '아날로그1', type: 'input', pos: { x: 0, y: 0 }}, M_ANALOG2: { name: '아날로그2', type: 'input', pos: { x: 0, y: 0 }}, M_ULTRASONIC: { name: '초음파센서', type: 'input', pos: { x: 0, y: 0 }}, M_CDS: { name: '조도센서', type: 'input', pos: { x: 0, y: 0 }}, M_TEMP: { name: '온도센서', type: 'input', pos: { x: 0, y: 0 }}, M_C_SW1: { name: '클로버 스위치1', type: 'input', pos: { x: 0, y: 0 }}, M_C_SW2: { name: '클로버 스위치2', type: 'input', pos: { x: 0, y: 0 }}, M_C_SW3: { name: '클로버 스위치3', type: 'input', pos: { x: 0, y: 0 }}, M_C_SW4: { name: '클로버 스위치4', type: 'input', pos: { x: 0, y: 0 }}, M_C_SW5: { name: '클로버 스위치5', type: 'input', pos: { x: 0, y: 0 }}, M_C_SW6: { name: '클로버 스위치6', type: 'input', pos: { x: 0, y: 0 }}, M_C_SW7: { name: '클로버 스위치7', type: 'input', pos: { x: 0, y: 0 }}, M_C_SW8: { name: '클로버 스위치8', type: 'input', pos: { x: 0, y: 0 }}, }, ports : { }, mode: 'both', }, actionType : { GET : 1, SET : 2, RESET : 3, }, sensorTypes : { ALIVE : 0, DIGITAL : 1, ANALOG : 2, PWM : 3, SERVO : 4, TONE : 5, PULSEIN : 6, ULTRASONIC : 7, TIMER : 8, MOTOR_L : 9, MOTOR_R : 10, CLOVER_FND : 11, CLOVER_SW : 12, CLOVER_LED : 13, CLOVER_RGB : 14, CLOVER_TEMP : 15, }, pinMaps : { SW1 : 2, SW2 : 7, LED_G : 17, LED_B : 16, BUZZ : 4, CDS : 7, Digital_Port0 : 17, Digital_Port1 : 16, Digital_Port2 : 3, Digital_Port3 : 5, Digital_Port4 : 6, Digital_Port5 : 9, Digital_Port6 : 10, Digital_Port7 : 11, Digital_Port8 : 12, Digital_Port9 : 13, Analog_Port0 : 14, Analog_Port1 : 15, DIR_L : 5, EN_L : 6, DIR_R : 9, EN_R : 10, Ultrasonic_TRIG : 13, Ultrasonic_ECHO : 12, }, CloverMaps : { FND : 0, MODULE0 : 39, MODULE1 : 38, MODULE2 : 37, MODULE3 : 36, MODULE4 : 35, MODULE5 : 34, MODULE6 : 33, MODULE7 : 32, }, toneTable: { '0': 0, C: 1, CS: 2, D: 3, DS: 4, E: 5, F: 6, FS: 7, G: 8, GS: 9, A: 10, AS: 11, B: 12, }, toneMap: { '1': [33, 65, 131, 262, 523, 1046, 2093, 4186], '2': [35, 69, 139, 277, 554, 1109, 2217, 4435], '3': [37, 73, 147, 294, 587, 1175, 2349, 4699], '4': [39, 78, 156, 311, 622, 1245, 2849, 4978], '5': [41, 82, 165, 330, 659, 1319, 2637, 5274], '6': [44, 87, 175, 349, 698, 1397, 2794, 5588], '7': [46, 92, 185, 370, 740, 1480, 2960, 5920], '8': [49, 98, 196, 392, 784, 1568, 3136, 6272], '9': [52, 104, 208, 415, 831, 1661, 3322, 6645], '10': [55, 110, 220, 440, 880, 1760, 3520, 7040], '11': [58, 117, 233, 466, 932, 1865, 3729, 7459], '12': [62, 123, 247, 494, 988, 1976, 3951, 7902], }, directionTable: { Forward: 0, Backward: 1, }, highList: ['high', '1', 'on'], lowList: ['low', '0', 'off'], BlockState: {}, }; Entry.CloverSEntry1.blockMenuBlocks = [ 'CloverSEntry1_set_digital', 'CloverSEntry1_set_digital1', 'CloverSEntry1_set_tone', 'CloverSEntry1_set_servo', 'CloverSEntry1_set_motor', 'CloverSEntry1_set_rgb', 'CloverSEntry1_set_fnd', 'CloverSEntry1_clover_set_led', 'CloverSEntry1_get_digital', 'CloverSEntry1_get_digital_servo', 'CloverSEntry1_get_analog_value', 'CloverSEntry1_get_analog_value_map', 'CloverSEntry1_get_ultrasonic_value', 'CloverSEntry1_get_cds_value', 'CloverSEntry1_get_temp_value', 'CloverSEntry1_clover_get_sw', ]; Entry.CloverSEntry1.setLanguage = () => { return { ko: { template: { CloverSEntry1_set_digital : '%1 을 %2 %3', CloverSEntry1_set_digital1 : '%1 을 %2 %3', CloverSEntry1_set_tone : '부저를 %1 %2 음으로 %3초 연주하기 %4', CloverSEntry1_set_servo : '%1 번 서보모터를 %2 의 각도로 정하기 %3', CloverSEntry1_set_motor : '%1 모터를 %2 으로 %3 회전 속도로 정하기 %4', CloverSEntry1_set_fnd : '클로버 숫자표시기(FND)에 %1 출력하기 %2', CloverSEntry1_clover_set_led : '클로버 LED %1 을 %2 %3', CloverSEntry1_get_digital : '스위치 %1 번 값', CloverSEntry1_get_digital_servo : '디지털 %1 번 값', CloverSEntry1_get_analog_value : '아날로그 %1 번 센서값', CloverSEntry1_get_analog_value_map : '아날로그 %1 번 값의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', CloverSEntry1_get_ultrasonic_value : '초음파센서 센서값', CloverSEntry1_get_cds_value : '조도센서 센서값', CloverSEntry1_get_temp_value : '온도센서 센서값', CloverSEntry1_clover_get_sw : '클로버 버튼 %1 번 값', CloverSEntry1_set_rgb : '컬러LED를 빨강%1 초록%2 파랑%3 밝기%4로 켜기 %5', } }, } }; Entry.CloverSEntry1.getBlocks = function() { return { CloverSEntry1_set_digital: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options : [ ["녹색", this.pinMaps.Digital_Port0], ["파랑색", this.pinMaps.Digital_Port1], ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options : [ ["켠다",0], ["끈다",1] ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ this.pinMaps.Digital_Port0, 0, null, ], type: 'CloverSEntry1_set_digital', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'setBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var self = Entry.CloverSEntry1; var sq = Entry.hw.sendQueue; var port = script.getField('PORT', script); var value = script.getField('VALUE', script); if (!sq['SET']) { sq['SET'] = {}; } sq['SET'][port] = { type: self.sensorTypes.DIGITAL, data: value, time: new Date().getTime(), }; }, }, CloverSEntry1_set_digital1: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options : [ ["디지털3", this.pinMaps.Digital_Port2], ["디지털5", this.pinMaps.Digital_Port3], ["디지털6", this.pinMaps.Digital_Port4], ["디지털9", this.pinMaps.Digital_Port5], ["디지털10", this.pinMaps.Digital_Port6], ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options : [ ["HIGH",1], ["LOW",0] ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ this.pinMaps.Digital_Port2, 0, null, ], type: 'CloverSEntry1_set_digital1', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'setBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var self = Entry.CloverSEntry1; var sq = Entry.hw.sendQueue; var port = script.getField('PORT', script); var value = script.getField('VALUE', script); if (!sq['SET']) { sq['SET'] = {}; } sq['SET'][port] = { type: self.sensorTypes.DIGITAL, data: value, time: new Date().getTime(), }; }, }, CloverSEntry1_tone_list: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.silent, '0'], [Lang.Blocks.do_name, 'C'], [Lang.Blocks.do_sharp_name, 'CS'], [Lang.Blocks.re_name, 'D'], [Lang.Blocks.re_sharp_name, 'DS'], [Lang.Blocks.mi_name, 'E'], [Lang.Blocks.fa_name, 'F'], [Lang.Blocks.fa_sharp_name, 'FS'], [Lang.Blocks.sol_name, 'G'], [Lang.Blocks.sol_sharp_name, 'GS'], [Lang.Blocks.la_name, 'A'], [Lang.Blocks.la_sharp_name, 'AS'], [Lang.Blocks.si_name, 'B'], ], value: 'C', fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { NOTE: 0, }, func: function(sprite, script) { return script.getField('NOTE'); }, syntax: { js: [], py: [] }, }, CloverSEntry1_tone_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'CloverSEntry1_tone_list', }, ], type: 'CloverSEntry1_tone_value', }, paramsKeyMap: { NOTE: 0, }, func: function(sprite, script) { return script.getNumberValue('NOTE'); }, syntax: { js: [], py: [] }, }, CloverSEntry1_octave_list: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ], value: '3', fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { OCTAVE: 0, }, func: function(sprite, script) { return script.getField('OCTAVE'); }, syntax: { js: [], py: [] }, }, CloverSEntry1_set_tone: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'CloverSEntry1_tone_list', }, { type: 'CloverSEntry1_octave_list', }, { type: 'text', params: ['1'], }, null, ], type: 'CloverSEntry1_set_tone', }, paramsKeyMap: { NOTE: 0, OCTAVE: 1, DURATION: 2, }, class: 'setBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var self = Entry.CloverSEntry1; var sq = Entry.hw.sendQueue; var port = self.pinMaps.BUZZ; if (!script.isStart) { var note = script.getValue('NOTE', script); if (!Entry.Utils.isNumber(note)) note = Entry.CloverSEntry1.toneTable[note]; if (note < 0) { note = 0; } else if (note > 12) { note = 12; } var duration = script.getNumberValue('DURATION', script); if (duration < 0) { duration = 0; } if (!sq['SET']) { sq['SET'] = {}; } if (duration === 0) { sq['SET'][port] = { type: Entry.CloverSEntry1.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; return script.callReturn(); } var octave = script.getNumberValue('OCTAVE', script) - 1; if (octave < 0) { octave = 0; } else if (octave > 5) { octave = 5; } var value = 0; if (note != 0) { value = Entry.CloverSEntry1.toneMap[note][octave]; } duration = duration * 1000; script.isStart = true; script.timeFlag = 1; sq['SET'][port] = { type: Entry.CloverSEntry1.sensorTypes.TONE, data: { value: value, duration: duration, }, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, duration + 32); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; sq['SET'][port] = { type: Entry.CloverSEntry1.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; Entry.engine.isContinue = false; return script.callReturn(); } return null; }, syntax: { js: [], py: [] }, }, CloverSEntry1_set_servo: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options : [ ['1', this.pinMaps.Digital_Port2], ['2', this.pinMaps.Digital_Port3], ['3', this.pinMaps.Digital_Port4], ['4', this.pinMaps.Digital_Port5], ['5', this.pinMaps.Digital_Port6], ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ this.pinMaps.Digital_Port2, 90, null, ], type: 'CloverSEntry1_set_servo', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'setBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var self = Entry.CloverSEntry1; var sq = Entry.hw.sendQueue; var port = script.getField('PORT', script); var value = script.getNumberValue('VALUE', script); if(value < 0) value = 0; else if (value > 180) value = 180; if (!sq['SET']) { sq['SET'] = {}; } sq['SET'][port] = { type: self.sensorTypes.SERVO, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [] }, }, CloverSEntry1_set_motor: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options : [ ['왼쪽', 0], ['오른쪽', 1], ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options : [ ['앞', 0], ['뒤', 1], ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ 0, 0, { type: 'number', params: ['200'], }, null, ], type: 'CloverSEntry1_set_motor', }, paramsKeyMap: { MOTOR_ANGLE: 0, MOTOR_DIRECTION: 1, MOTOR_SPEED: 2, }, class: 'setBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var angle = script.getField('MOTOR_ANGLE', script); var direction = script.getField('MOTOR_DIRECTION', script); var speed = script.getNumberValue('MOTOR_SPEED', script) - 1; if (speed < 0) { speed = 0; } else if (speed > 254) { speed = 254; } if (!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } if(angle == 0) { Entry.hw.sendQueue['SET'][0] = { type: Entry.CloverSEntry1.sensorTypes.MOTOR_L, data: { direction: direction, speed: speed, }, time: new Date().getTime(), }; } else { Entry.hw.sendQueue['SET'][1] = { type: Entry.CloverSEntry1.sensorTypes.MOTOR_R, data: { direction: direction, speed: speed, }, time: new Date().getTime(), }; } setTimeout(function() { script.timeFlag = 0; }, 10); return script.callReturn(); }, syntax: { js: [], py: [] }, }, CloverSEntry1_set_fnd: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ 0, null, ], type: 'CloverSEntry1_set_fnd', }, paramsKeyMap: { VALUE: 0, }, class: 'setBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var self = Entry.CloverSEntry1; var sq = Entry.hw.sendQueue; var port = 0; var value = script.getNumberValue('VALUE', script); if (!sq['SET_CLOVER']) { sq['SET_CLOVER'] = {}; } sq['SET_CLOVER'][port] = { type: self.sensorTypes.CLOVER_FND, data: value, time: new Date().getTime(), }; }, }, CloverSEntry1_set_rgb: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ 100, 100, 100, 10, null, ], type: 'CloverSEntry1_set_rgb', }, paramsKeyMap: { COLOR_R: 0, COLOR_G: 1, COLOR_B: 2, COLOR_W: 3, }, class: 'setBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var self = Entry.CloverSEntry1; var color_r = script.getNumberValue('COLOR_R', script); var color_g = script.getNumberValue('COLOR_G', script); var color_b = script.getNumberValue('COLOR_B', script); var color_w = script.getNumberValue('COLOR_W', script); var sq = Entry.hw.sendQueue; var port = 101; var value; if(isNaN(color_r)) { color_r = 0; } if(isNaN(color_g)) { color_g = 0; } if(isNaN(color_b)) { color_b = 0; } if(isNaN(color_w)) { color_w = 0; } if(color_r < 0) { color_r = 0; }; if(color_r > 255) { color_r = 255; } if(color_g < 0) { color_g = 0; }; if(color_g > 255) { color_g = 255; } if(color_b < 0) { color_b = 0; }; if(color_b > 255) { color_b = 255; } if(color_w < 0) { color_w = 0; }; if(color_w > 255) { color_w = 255; } value = 0; value = (color_r << 24) | (color_g << 16) | (color_b << 8) | (color_w << 0); if (!sq['SET_CLOVER']) { sq['SET_CLOVER'] = {}; } sq['SET_CLOVER'][port] = { type: self.sensorTypes.CLOVER_RGB, data: value, time: new Date().getTime(), }; }, }, CloverSEntry1_get_digital: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_boolean_field', params: [ { type: 'Dropdown', options : [ ['1', this.pinMaps.SW1], ['2', this.pinMaps.SW2], ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [ this.pinMaps.SW1, ], type: 'CloverSEntry1_get_digital', }, paramsKeyMap: { PORT: 0, }, class: 'getBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var port = script.getField('PORT', script); var DIGITAL = Entry.hw.portData.DIGITAL; if (!Entry.hw.sendQueue['GET']) { Entry.hw.sendQueue['GET'] = {}; } Entry.hw.sendQueue['GET'][Entry.CloverSEntry1.sensorTypes.DIGITAL] = { port: port, time: new Date().getTime(), }; if( DIGITAL[port] == 0) { return true; } else { return false;} }, syntax: { js: [], py: [] }, }, CloverSEntry1_get_digital_servo: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_boolean_field', params: [ { type: 'Dropdown', options : [ ["3", 3], ["5", 5], ["6", 6], ["9", 9], ["10", 10], ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [ 3, ], type: 'CloverSEntry1_get_digital_servo', }, paramsKeyMap: { PORT: 0, }, class: 'getBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var port = script.getField('PORT', script); var DIGITAL = Entry.hw.portData.DIGITAL; if (!Entry.hw.sendQueue['GET']) { Entry.hw.sendQueue['GET'] = {}; } Entry.hw.sendQueue['GET'][Entry.CloverSEntry1.sensorTypes.DIGITAL] = { port: port, time: new Date().getTime(), }; if( DIGITAL[port] != 0) { return true; } else { return false;} }, syntax: { js: [], py: [] }, }, CloverSEntry1_get_analog_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Dropdown', options : [ ["1", 0], ["2", 1], ], value : 0, fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [ null ], type: 'CloverSEntry1_get_analog_value', }, paramsKeyMap: { PORT: 0, }, class: 'getBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var port = script.getField('PORT', script); var ANALOG = Entry.hw.portData.ANALOG; return ANALOG[port]; }, syntax: { js: [], py: [] }, }, CloverSEntry1_get_analog_value_map: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Dropdown', options : [ ["1", 0], ["2", 1], ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'number', }, { type: 'Block', accept: 'number', }, { type: 'Block', accept: 'number', }, { type: 'Block', accept: 'number', }, ], events: {}, def: { params: [ 0, { type: 'number', params: ['0'], }, { type: 'number', params: ['1023'], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['100'], }, ], type: 'CloverSEntry1_get_analog_value_map', }, paramsKeyMap: { PORT: 0, VALUE2: 1, VALUE3: 2, VALUE4: 3, VALUE5: 4, }, class: 'getBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var port = script.getField('PORT', script); var ANALOG = Entry.hw.portData.ANALOG; var value2 = script.getNumberValue('VALUE2', script); var value3 = script.getNumberValue('VALUE3', script); var value4 = script.getNumberValue('VALUE4', script); var value5 = script.getNumberValue('VALUE5', script); var org_value; var org_percent; var org_range; var dest_range; var dest_value; var swap = 0; if(value2 > value3) { swap = value2; value2 = value3; value3 = swap; } if (value4 > value5) { swap = value4; value4 = value5; value5 = swap; } org_value = ANALOG[port] - value2; org_range = value3 - value2; dest_range = value5 - value4; if(org_range <= 0) { return 0; } if(dest_range <= 0) { return 0; } if(org_value <= 0) {return 0; } org_percent = (org_value / org_range) * 100; dest_value = value4 + (dest_range * (org_percent / 100)); if(dest_value < value4) { dest_value = value4; } if(dest_value > value5) { dest_value = value5; } return dest_value; }, syntax: { js: [], py: [] }, }, CloverSEntry1_get_ultrasonic_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ ], events: {}, def: { params: [ ], type: 'CloverSEntry1_get_ultrasonic_value', }, paramsKeyMap: { }, class: 'getBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var port1 = Entry.CloverSEntry1.pinMaps.Ultrasonic_TRIG; var port2 = Entry.CloverSEntry1.pinMaps.Ultrasonic_ECHO; if (!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } delete Entry.hw.sendQueue['SET'][port1]; delete Entry.hw.sendQueue['SET'][port2]; if (!Entry.hw.sendQueue['GET']) { Entry.hw.sendQueue['GET'] = {}; } Entry.hw.sendQueue['GET'][Entry.CloverSEntry1.sensorTypes.ULTRASONIC] = { port: [port1, port2], data : 0, time: new Date().getTime(), }; return Entry.hw.portData.ULTRASONIC; }, syntax: { js: [], py: [] }, }, CloverSEntry1_get_cds_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ ], events: {}, def: { params: [ ], type: 'CloverSEntry1_get_cds_value', }, paramsKeyMap: { }, class: 'getBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var self = Entry.CloverSEntry1; var port = self.pinMaps.CDS; var ANALOG = Entry.hw.portData.ANALOG; return ANALOG[port]; }, syntax: { js: [], py: [] }, }, CloverSEntry1_get_temp_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ ], events: {}, def: { params: [ ], type: 'CloverSEntry1_get_temp_value', }, paramsKeyMap: { }, class: 'getBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var self = Entry.CloverSEntry1; var port = self.pinMaps.CDS; var temp = Entry.hw.portData.TEMP; return temp; }, syntax: { js: [], py: [] }, }, CloverSEntry1_clover_set_led: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options : [ ["1", 1], ["2", 2], ["3", 3], ["4", 4], ["5", 5], ["6", 6], ["7", 7], ["8", 8], ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options : [ ["켠다",0], ["끈다",1] ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ 1, 0, null, ], type: 'CloverSEntry1_clover_set_led', }, paramsKeyMap: { NUM : 0, VALUE: 1, }, class: 'setBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var self = Entry.CloverSEntry1; var sq = Entry.hw.sendQueue; var port; var id = self.CloverMaps.MODULE1; var num = script.getField('NUM', script); var value = script.getField('VALUE', script); switch (id) { case self.CloverMaps.MODULE0 : port = (0*10) + num; break; case self.CloverMaps.MODULE1 : port = (1*10) + num; break; case self.CloverMaps.MODULE2 : port = (2*10) + num; break; case self.CloverMaps.MODULE3 : port = (3*10) + num; break; case self.CloverMaps.MODULE4 : port = (4*10) + num; break; case self.CloverMaps.MODULE5 : port = (5*10) + num; break; case self.CloverMaps.MODULE6 : port = (6*10) + num; break; case self.CloverMaps.MODULE7 : port = (7*10) + num; break; } if (!sq['SET_CLOVER']) { sq['SET_CLOVER'] = {}; } sq['SET_CLOVER'][port] = { type: self.sensorTypes.CLOVER_LED, data: value, num : num - 1, time: new Date().getTime(), }; }, }, CloverSEntry1_clover_get_sw: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_boolean_field', params: [ { type: 'Dropdown', options : [ ["1", 1], ["2", 2], ["3", 3], ["4", 4], ["5", 5], ["6", 6], ["7", 7], ["8", 8], ], fontSize: 12, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [ 1, ], type: 'CloverSEntry1_clover_get_sw', }, paramsKeyMap: { PORT: 0, }, class: 'getBlock', isNotFor: ['CloverSEntry1'], func: function(sprite, script) { var self = Entry.CloverSEntry1; var port = self.CloverMaps.MODULE0; var num = script.getField('PORT', script) - 1; var id = self.CloverMaps.MODULE0 - port + 1; var CLOVER = Entry.hw.portData.CLOVER; var value; if (!Entry.hw.sendQueue['GET_CLOVER']) { Entry.hw.sendQueue['GET_CLOVER'] = {}; } Entry.hw.sendQueue['GET_CLOVER'][Entry.CloverSEntry1.sensorTypes.CLOVER_SW] = { port: port, data: 0, time: new Date().getTime(), }; value = (CLOVER[id] & (0x01 << num)) >> num; if(value == 1) { return true; } else { return false; } }, syntax: { js: [], py: [] }, }, }; }; module.exports = Entry.CloverSEntry1; ================================================ FILE: src/playground/blocks/hardware/block_ITPLE_board.js ================================================ 'use strict'; Entry.ITPLE = { // 이전 버튼 상태 저장 prevButtonState: { 'A0': 1, 'A1': 1, '7': 1, '8': 1, }, afterReceive(pd) { if (!Entry.engine.isState('run')) { return; } // 버튼 상태 확인 const portConfigs = [ { key: 'A0', type: 'ANALOG', index: 0 }, { key: 'A1', type: 'ANALOG', index: 1 }, { key: '7', type: 'DIGITAL', index: 7 }, { key: '8', type: 'DIGITAL', index: 8 }, ]; let buttonPressed = false; for (const config of portConfigs) { const currentValue = Entry.hw.portData[config.type]?.[config.index] ?? 1; const prevValue = Entry.ITPLE.prevButtonState[config.key]; // 버튼이 눌린 순간 감지 (1 → 0) if (prevValue !== 0 && currentValue === 0) { buttonPressed = true; } Entry.ITPLE.prevButtonState[config.key] = currentValue; } // 버튼이 눌린 순간에만 이벤트 발생 if (buttonPressed) { Entry.engine.fireEvent('ITPLE_press_button'); } }, id: '5E.1', name: 'ITPLE', url: 'http://www.itpleinfo.com/', imageName: 'ITPLE.png', title: { ko: '잇플보드', en: 'ITPLE board', }, setZero() { if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue = { GET: {}, SET: {}, }; } // 기존 큐 초기화 const keySet = Object.keys(Entry.hw.sendQueue.SET); keySet.forEach((key) => { const portNum = parseInt(key); // 네오픽셀 관련 포트(100-103, 200-205)와 물리 포트 9는 별도 처리 // 206(BLINK), 207(BLINK_STOP)은 명시적으로 삭제 if (portNum === 206 || portNum === 207) { delete Entry.hw.sendQueue.SET[key]; } else if (portNum !== 9 && !(portNum >= 100 && portNum <= 103) && !(portNum >= 200 && portNum <= 205)) { Entry.hw.sendQueue.SET[key].data = 0; Entry.hw.sendQueue.SET[key].time = new Date().getTime(); } }); // 깜박이기 중지 명령 전송 (전체) - INIT보다 먼저 실행 const stopTime = new Date().getTime(); Entry.hw.sendQueue.SET[206] = { type: 15, // NEOPIXEL_BLINK_STOP data: { side: 2 }, // 전체 time: stopTime, }; console.log('[ITPLE] setZero - BLINK_STOP sent at', stopTime); Entry.hw.update(); // 즉시 전송 // NEOPIXEL_INIT 명령 전송 (네오픽셀 끄기) // 깜박이기 중지 후 약간의 시간차를 두고 INIT 실행 setTimeout(() => { const initTime = new Date().getTime(); Entry.hw.sendQueue.SET[200] = { type: 9, // NEOPIXEL_INIT data: 0, time: initTime, }; console.log('[ITPLE] setZero - NEOPIXEL_INIT sent at', initTime); Entry.hw.update(); }, 20); }, sensorTypes: { ALIVE: 0, DIGITAL: 1, ANALOG: 2, PWM: 3, SERVO_PIN: 4, TONE: 5, PULSEIN: 6, ULTRASONIC: 7, TIMER: 8, NEOPIXEL_INIT: 9, NEOPIXEL_COLOR: 10, NEOPIXEL_BRIGHTNESS: 11, NEOPIXEL_SHIFT: 12, NEOPIXEL_ROTATE: 13, NEOPIXEL_BLINK: 14, NEOPIXEL_BLINK_STOP: 15, }, toneTable: { 0: 0, C: 1, CS: 2, D: 3, DS: 4, E: 5, F: 6, FS: 7, G: 8, GS: 9, A: 10, AS: 11, B: 12, }, toneMap: { 1: [33, 65, 131, 262, 523, 1046, 2093, 4186], 2: [35, 69, 139, 277, 554, 1109, 2217, 4435], 3: [37, 73, 147, 294, 587, 1175, 2349, 4699], 4: [39, 78, 156, 311, 622, 1245, 2849, 4978], 5: [41, 82, 165, 330, 659, 1319, 2637, 5274], 6: [44, 87, 175, 349, 698, 1397, 2794, 5588], 7: [46, 92, 185, 370, 740, 1480, 2960, 5920], 8: [49, 98, 196, 392, 784, 1568, 3136, 6272], 9: [52, 104, 208, 415, 831, 1661, 3322, 6645], 10: [55, 110, 220, 440, 880, 1760, 3520, 7040], 11: [58, 117, 233, 466, 932, 1865, 3729, 7459], 12: [62, 123, 247, 494, 988, 1976, 3951, 7902], }, duration: { TIME_1ms: 1, TIME_5ms: 5, TIME_10ms: 10, TIME_20ms: 20, TIME_50ms: 50, TIME_100ms: 100, TIME_200ms: 200, TIME_500ms: 500, TIME_600ms: 600, }, highList: ['high', '1', 'on'], lowList: ['low', '0', 'off'], BlockState: {}, EdgeFlag: { 'A0': false, 'A1': false, '7': false, '8': false, }, timeSeq: 0, }; Entry.ITPLE.setLanguage = function () { return { ko: { template: { ITPLE_push_button: '%1 %2 버튼을 눌렀을 때', ITPLE_get_button_value: '%1 버튼 값', ITPLE_get_sensor_value: '%1 센서 값', ITPLE_get_ultrasonic_value: '초음파 센서 값', ITPLE_is_key_pressed: '%1 키가 눌러져 있는가?', ITPLE_value_sensor: '%1 센서 값이 %2보다 %3', ITPLE_turn_led: '%1 LED %2 %3', ITPLE_set_tone: '버저를 %1 %2 음으로 %3 초 연주하기 %4', ITPLE_set_motor_direction: '%1 모터 %2 방향으로 정하기 %3', ITPLE_set_motor_speed: '%1 모터 %2 빠르기로 정하기 %3', ITPLE_set_servo: '서보모터를 %2 도로 정하기 %3', ITPLE_set_neopixel_init: '네오픽셀 모두 끄기 %1', ITPLE_set_neopixel: '%1 번째 네오픽셀 LED를 %2 색으로 켜기 %3', ITPLE_set_neopixel_all: '네오픽셀 전체의 색상을 %1 (으)로 켜기 %2', ITPLE_set_neopixel_range: '%1 번부터 %2 번까지 네오픽셀을 %3 색상으로 켜기 %4', ITPLE_set_neopixel_rotate: '네오픽셀 %1 방향으로 %2 칸 이동 %3', ITPLE_set_neopixel_brightness: '네오픽셀 최대 밝기를 %1 (으)로 정하기 %2', ITPLE_set_neopixel_blink: '%1 네오픽셀 %2 색으로 깜박이기 (간격: %3초) %4', ITPLE_stop_neopixel_blink: '%1 네오픽셀 깜박이기 중지 %2', ITPLE_color_picker_value: '색상 선택 %1', ITPLE_rgb_to_color_value: 'R: %1 G: %2 B: %3 색상값', }, }, en: { template: { ITPLE_push_button: '%1 When %2 button is pressed', ITPLE_get_button_value: '%1 button value', ITPLE_get_sensor_value: '%1 sensor value', ITPLE_get_ultrasonic_value: 'Ultrasonic sensor value', ITPLE_is_key_pressed: '%1 key pressed', ITPLE_value_sensor: 'Is %1 sensor value %3 than %2', ITPLE_turn_led: '%1 LED %2 %3', ITPLE_set_tone: 'Play tone on note %1 octave %2 beat %3 %4', ITPLE_set_motor_direction: '%1 motor %2 direction %3', ITPLE_set_motor_speed: '%1 motor %2 speed %3', ITPLE_set_servo: 'Set servo motor to %2 degree %3', ITPLE_set_neopixel_init: 'Turn off all NeoPixels %1', ITPLE_set_neopixel: 'Set NeoPixel %1 to %2 color %3', ITPLE_set_neopixel_all: 'Set all NeoPixels to %1 color %2', ITPLE_set_neopixel_range: 'Fill NeoPixels from %1 to %2 with %3 color %4', ITPLE_set_neopixel_rotate: 'Shift NeoPixels %1 by %2 steps %3', ITPLE_set_neopixel_brightness: 'Set NeoPixel max brightness to %1 %2', ITPLE_set_neopixel_blink: 'Blink %1 NeoPixels %2 color (interval: %3s) %4', ITPLE_stop_neopixel_blink: 'Stop %1 NeoPixel blinking %2', ITPLE_color_picker_value: 'Pick color %1', ITPLE_rgb_to_color_value: 'Color from R:%1 G:%2 B:%3', }, }, }; }; Entry.ITPLE.blockMenuBlocks = [ 'ITPLE_push_button', 'ITPLE_get_button_value', 'ITPLE_get_sensor_value', 'ITPLE_get_ultrasonic_value', 'ITPLE_color_picker_value', 'ITPLE_rgb_to_color_value', 'ITPLE_is_key_pressed', 'ITPLE_value_sensor', 'ITPLE_turn_led', 'ITPLE_set_tone', 'ITPLE_set_motor_direction', 'ITPLE_set_motor_speed', 'ITPLE_set_servo', 'ITPLE_set_neopixel_init', 'ITPLE_set_neopixel', 'ITPLE_set_neopixel_all', 'ITPLE_set_neopixel_range', 'ITPLE_set_neopixel_rotate', 'ITPLE_set_neopixel_brightness', 'ITPLE_set_neopixel_blink', 'ITPLE_stop_neopixel_blink', ]; //region ITPLE 보드 Entry.ITPLE.getBlocks = function () { return { ITPLE_push_button: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_hardware.svg', size: 14, position: { x: 0, y: -2, }, }, { type: 'Dropdown', options: [['위쪽', 'A0'], ['아래쪽', 'A1'], ['왼쪽', '7'], ['오른쪽', '8']], value: 'A0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null, 'A0'], type: 'ITPLE_push_button' }, paramsKeyMap: { PORT: 1 }, class: 'ITPLEStart', isNotFor: ['ITPLE'], event: 'ITPLE_press_button', func(sprite, script) { const portConfigMap = { 'A0': { type: 'ANALOG', index: 0 }, 'A1': { type: 'ANALOG', index: 1 }, '7': { type: 'DIGITAL', index: 7 }, '8': { type: 'DIGITAL', index: 8 }, }; const portKey = script.getField('PORT', script); const config = portConfigMap[portKey]; if (!config) { return this.die(); } const value = Entry.hw.portData[config.type]?.[config.index] ?? 1; // 버튼이 눌렸을 때 (value === 0) 실행 if (value === 0) { return script.callReturn(); } return this.die(); }, syntax: { js: [], py: [ { syntax: 'def when_push_button(%2):', passTest: true, blockType: 'event', textParams: [ undefined, { type: 'Dropdown', options: [['위쪽', 'A0'], ['아래쪽', 'A1'], ['왼쪽', '7'], ['오른쪽', '8']], value: 'A0', arrowColor: EntryStatic.colorSet.arrow.default.START, converter: Entry.block.converters.returnStringValue, }, ], }, ], }, }, ITPLE_get_button_value: { color: EntryStatic.colorSet.block["default"].HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [{ type: 'Dropdown', options: [['위쪽', 'A0'], ['아래쪽', 'A1'], ['왼쪽', '7'], ['오른쪽', '8']], value: 'A0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow["default"].HARDWARE }], events: {}, def: { params: [null], type: 'ITPLE_get_button_value' }, paramsKeyMap: { PORT: 0 }, "class": 'ITPLEGet', isNotFor: ['ITPLE'], func: function func(sprite, script) { const portConfigMap = { 'A0': { type: 'ANALOG', index: 0 }, 'A1': { type: 'ANALOG', index: 1 }, '7': { type: 'DIGITAL', index: 7 }, '8': { type: 'DIGITAL', index: 8 }, }; const portKey = script.getValue('PORT', script); const config = portConfigMap[portKey]; if (!config) return 0; return Entry.hw.portData[config.type]?.[config.index] ?? 0; }, syntax: { js: [], py: [{ syntax: 'Arduino.digitalRead(%1)', blockType: 'param', textParams: [{ type: 'Block', accept: 'string' }] }] } }, ITPLE_get_sensor_value: { color: EntryStatic.colorSet.block["default"].HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [{ type: 'Dropdown', options: [['조도', 'A2'], ['소리', 'A3'], ['왼쪽 라인', 'A6'], ['오른쪽 라인', 'A7']], value: 'A2', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow["default"].HARDWARE }], events: {}, def: { params: [null], type: 'ITPLE_get_sensor_value' }, paramsKeyMap: { PORT: 0 }, "class": 'ITPLEGet', isNotFor: ['ITPLE'], func: function func(sprite, script) { const portConfigMap = { 'A2': { type: 'ANALOG', index: 2 }, 'A3': { type: 'ANALOG', index: 3 }, 'A6': { type: 'ANALOG', index: 6 }, 'A7': { type: 'ANALOG', index: 7 }, }; const portKey = script.getValue('PORT', script); const config = portConfigMap[portKey]; if (!config) return 0; return Entry.hw.portData[config.type]?.[config.index] ?? 0; }, syntax: { js: [], py: [{ syntax: 'Arduino.analogRead(%1)', blockType: 'param', textParams: [{ type: 'Block', accept: 'string' }] }] } }, ITPLE_is_key_pressed: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_boolean_field', params: [{ type: 'Dropdown', options: [ ['위쪽', 'A0'], ['아래쪽', 'A1'], ['왼쪽', '7'], ['오른쪽', '8'], ], value: 'A0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, },], events: {}, def: { params: [null], type: 'ITPLE_is_key_pressed', }, paramsKeyMap: { KEY: 0, }, "class": 'ITPLEGet', isNotFor: ['ITPLE'], func(sprite, script) { // 각 키에 대한 하드웨어 포트 정보를 객체로 관리하여 확장성을 높입니다. const keyToPortMap = { 'A0': { type: 'ANALOG', index: 0 }, 'A1': { type: 'ANALOG', index: 1 }, '7': { type: 'DIGITAL', index: 7 }, '8': { type: 'DIGITAL', index: 8 }, }; const selectedKey = script.getField('KEY'); const portConfig = keyToPortMap[selectedKey]; // 유효하지 않은 키는 즉시 false를 반환합니다. if (!portConfig) { return false; } // 옵셔널 체이닝(?.)과 null 병합 연산자(??)를 사용해 // 하드웨어 데이터 존재 여부를 확인하고 값을 안전하게 가져옵니다. const value = Entry.hw.portData[portConfig.type]?.[portConfig.index] ?? 1; // 버튼이 눌렸을 때의 값(0)과 일치하는지 확인하여 boolean 값을 반환합니다. return value === 0; }, syntax: { js: [], py: [ { syntax: 'Arduino.digitalRead("%1")==0', }, ], }, }, ITPLE_value_sensor: { // 저학년을 위한 센서 블록 생성 color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_boolean_field', params: [ { type: 'Dropdown', options: [ ['조도', '2'], ['소리', '3'], ['왼쪽 라인', '6'], ['오른쪽 라인', '7'], ], value: '2', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'number', }, { type: 'Dropdown', options: [ ['크다', '>'], ['크거나같다', '>='], ['같다', '=='], ['작거나같다', '<='], ['작다', '<'], ], value: '>', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, } ], events: {}, def: { params: [null, { type: 'number', params: ['500'] }, null], type: 'ITPLE_value_sensor', }, paramsKeyMap: { PIN: 0, VALUE: 1, COMPARISON: 2, }, class: 'ITPLEGet', isNotFor: ['ITPLE'], func(sprite, script) { const pin = script.getValue('PIN'); const value = script.getValue('VALUE'); const comparison = script.getValue('COMPARISON'); const analogPortData = Entry.hw.portData.ANALOG; if (analogPortData) { switch (comparison) { case '>': return analogPortData[pin] > value; case '<': return analogPortData[pin] < value; case '==': return analogPortData[pin] === value; } } return false; }, syntax: { js: [], py: [ { syntax: 'Arduino.analogRead(%1) %3 %2', }, ], }, }, ITPLE_get_ultrasonic_value: { color: EntryStatic.colorSet.block["default"].HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [{ type: 'Block', accept: 'string', defaultType: 'number' }, { type: 'Block', accept: 'string', defaultType: 'number' }], events: {}, def: { params: [{ type: 'arduino_get_port_number', params: ['13'] }, { type: 'arduino_get_port_number', params: ['12'] }], type: 'ITPLE_get_ultrasonic_value' }, paramsKeyMap: { PORT1: 0, PORT2: 1 }, "class": 'ITPLEGet', isNotFor: ['ITPLE'], func: function func(sprite, script) { var port1 = script.getNumberValue('PORT1', script); var port2 = script.getNumberValue('PORT2', script); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } delete Entry.hw.sendQueue.SET[port1]; delete Entry.hw.sendQueue.SET[port2]; if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } Entry.hw.sendQueue.GET[Entry.ITPLE.sensorTypes.ULTRASONIC] = { port: [port1, port2], time: new Date().getTime() }; return Entry.hw.portData.ULTRASONIC || 0; }, syntax: { js: [], py: [{ syntax: 'Arduino.ultrasonicRead(%1, %2)', blockType: 'param', textParams: [{ type: 'Block', accept: 'string' }, { type: 'Block', accept: 'string' }] }], } }, ITPLE_color_picker_value: { color: EntryStatic.colorSet.block["default"].HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Color' }, ], events: {}, def: { params: [null], type: 'ITPLE_color_picker_value', }, paramsKeyMap: { COLOR: 0, }, class: 'ITPLE_neopixel', isNotFor: ['ITPLE'], func(sprite, script) { // Color 파라미터는 이미 hex 문자열을 반환 return script.getStringValue('COLOR', script); }, syntax: { js: [], py: [] }, }, ITPLE_rgb_to_color_value: { color: EntryStatic.colorSet.block["default"].HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number' }, { type: 'Block', accept: 'string', defaultType: 'number' }, { type: 'Block', accept: 'string', defaultType: 'number' }, ], events: {}, def: { params: [ { type: 'number', params: ['255'] }, { type: 'number', params: ['0'] }, { type: 'number', params: ['0'] }, ], type: 'ITPLE_rgb_to_color_value', }, paramsKeyMap: { RED: 0, GREEN: 1, BLUE: 2, }, class: 'ITPLE_neopixel', isNotFor: ['ITPLE'], func(sprite, script) { let r = script.getNumberValue('RED', script); let g = script.getNumberValue('GREEN', script); let b = script.getNumberValue('BLUE', script); // clamp r = Math.min(255, Math.max(0, Math.floor(r))); g = Math.min(255, Math.max(0, Math.floor(g))); b = Math.min(255, Math.max(0, Math.floor(b))); const toHex = (v) => v.toString(16).padStart(2, '0').toUpperCase(); return `#${toHex(r)}${toHex(g)}${toHex(b)}`; }, syntax: { js: [], py: [] }, }, ITPLE_turn_led: { // 저학년 학생을 위한, 핀 번호 없는 LED 켜기 블록 color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', params: [ { type: 'Dropdown', options: [ ['빨강', 10], ['파랑', 11], ], value: 10, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [ ['켜기', 'on'], ['끄기', 'off'], ], value: 'on', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, ], type: 'ITPLE_turn_led', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'ITPLE', isNotFor: ['ITPLE'], func(sprite, script) { const port = script.getNumberValue('PORT'); let value = script.getValue('VALUE'); if (typeof value === 'string') { value = value.toLowerCase(); } if (Entry.ITPLE.highList.indexOf(value) > -1) { value = 255; } else if (Entry.ITPLE.lowList.indexOf(value) > -1) { value = 0; } else { throw new Error(); } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[port] = { type: Entry.ITPLE.sensorTypes.DIGITAL, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.digitalWrite(%1, %2)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, ITPLE_tone_list: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.silent, '0'], [Lang.Blocks.do_name, 'C'], [Lang.Blocks.do_sharp_name, 'CS'], [Lang.Blocks.re_name, 'D'], [Lang.Blocks.re_sharp_name, 'DS'], [Lang.Blocks.mi_name, 'E'], [Lang.Blocks.fa_name, 'F'], [Lang.Blocks.fa_sharp_name, 'FS'], [Lang.Blocks.sol_name, 'G'], [Lang.Blocks.sol_sharp_name, 'GS'], [Lang.Blocks.la_name, 'A'], [Lang.Blocks.la_sharp_name, 'AS'], [Lang.Blocks.si_name, 'B'], ], value: 'C', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { NOTE: 0, }, func(sprite, script) { return script.getField('NOTE'); }, syntax: { js: [], py: [ { syntax: '%1', textParams: [ { type: 'Dropdown', options: [ [Lang.Blocks.silent, '0'], [Lang.Blocks.do_name, 'C'], [Lang.Blocks.do_sharp_name, 'CS'], [Lang.Blocks.re_name, 'D'], [Lang.Blocks.re_sharp_name, 'DS'], [Lang.Blocks.mi_name, 'E'], [Lang.Blocks.fa_name, 'F'], [Lang.Blocks.fa_sharp_name, 'FS'], [Lang.Blocks.sol_name, 'G'], [Lang.Blocks.sol_sharp_name, 'GS'], [Lang.Blocks.la_name, 'A'], [Lang.Blocks.la_sharp_name, 'AS'], [Lang.Blocks.si_name, 'B'], ], value: 'C', fontSize: 11, converter: Entry.block.converters.returnStringValueUpperCase, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], keyOption: 'ITPLE_tone_list', }, ], }, }, ITPLE_tone_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'ITPLE_tone_list', }, ], type: 'ITPLE_tone_value', }, paramsKeyMap: { NOTE: 0, }, func(sprite, script) { return script.getNumberValue('NOTE'); }, syntax: { js: [], py: [ { syntax: '%1', keyOption: 'ITPLE_tone_value', }, ], }, }, ITPLE_octave_list: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ], value: '4', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { OCTAVE: 0, }, func(sprite, script) { return script.getField('OCTAVE'); }, syntax: { js: [], py: [ { syntax: '%1', keyOption: 'ITPLE_octave_list', }, ], }, }, ITPLE_set_tone: { // 버저 핀번호 가림 업데이트 color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'ITPLE_tone_list', }, { type: 'ITPLE_octave_list', }, { type: 'text', params: ['1'], }, null, ], type: 'ITPLE_set_tone', }, paramsKeyMap: { NOTE: 0, OCTAVE: 1, DURATION: 2, }, class: 'ITPLE', isNotFor: ['ITPLE'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = 3; if (!script.isStart) { let note = script.getValue('NOTE', script); if (!Entry.Utils.isNumber(note)) { note = Entry.ITPLE.toneTable[note]; } if (note < 0) { note = 0; } else if (note > 12) { note = 12; } let duration = script.getNumberValue('DURATION', script); if (duration < 0) { duration = 0; } if (!sq.SET) { sq.SET = {}; } if (duration === 0) { sq.SET[port] = { type: Entry.ITPLE.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; return script.callReturn(); } let octave = script.getNumberValue('OCTAVE', script) - 1; if (octave < 0) { octave = 0; } else if (octave > 5) { octave = 5; } let value = 0; if (note != 0) { value = Entry.ITPLE.toneMap[note][octave]; } duration = duration * 1000; script.isStart = true; script.timeFlag = 1; sq.SET[port] = { type: Entry.ITPLE.sensorTypes.TONE, data: { value, duration, }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, duration + 32); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; sq.SET[port] = { type: Entry.ITPLE.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Arduino.tone(3, %1, %2, %3)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, ITPLE_octave_list: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ], value: '4', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { OCTAVE: 0, }, func(sprite, script) { return script.getField('OCTAVE'); }, syntax: { js: [], py: [ { syntax: '%1', keyOption: 'ITPLE_octave_list', }, ], }, }, ITPLE_set_motor_direction: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['왼쪽', '2'], ['오른쪽', '4'], ], value: '2', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [ ['앞쪽', '0'], ['뒤쪽', '1'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: ['2', '0', null], type: 'ITPLE_set_motor_direction', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'ITPLE_motor', isNotFor: ['ITPLE'], func(sprite, script) { const port = script.getNumberValue('PORT'); let value = script.getValue('VALUE'); if (typeof value === 'string') { value = value.toLowerCase(); } if (Entry.ITPLE.highList.indexOf(value) > -1) { value = 255; } else if (Entry.ITPLE.lowList.indexOf(value) > -1) { value = 0; } else { throw new Error(); } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[port] = { type: Entry.ITPLE.sensorTypes.DIGITAL, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.digitalWrite(%1, %2)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, ITPLE_set_motor_speed: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['왼쪽', '5'], ['오른쪽', '6'], ], value: '5', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ '5', { type: 'text', params: ['255'], }, null, ], type: 'ITPLE_set_motor_speed', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'ITPLE_motor', isNotFor: ['ITPLE'], func(sprite, script) { const port = script.getNumberValue('PORT'); let value = script.getNumberValue('VALUE'); value = Math.round(value); value = Math.max(value, 0); value = Math.min(value, 255); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[port] = { type: Entry.ITPLE.sensorTypes.PWM, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.analogWrite(%1, %2)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, ITPLE_set_servo: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ '9', { type: 'text', params: ['180'], }, null, ], type: 'ITPLE_set_servo', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'ITPLE_motor', isNotFor: ['ITPLE'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = script.getNumberValue('PORT', script); let value = script.getNumberValue('VALUE', script); value = Math.min(180, value); value = Math.max(0, value); if (!sq.SET) { sq.SET = {}; } sq.SET[port] = { type: Entry.ITPLE.sensorTypes.SERVO_PIN, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [{ syntax: 'Arduino.servomotorWrite(%1, %2)', textParams: [{ type: 'Block', accept: 'string', },{ type: 'Block', accept: 'string', },], },], }, }, ITPLE_set_neopixel_init: { color: EntryStatic.colorSet.block["default"].HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [{ type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12 }], events: {}, def: { params: [null], type: 'ITPLE_set_neopixel_init' }, "class": 'ITPLE_neopixel', isNotFor: ['ITPLE'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = 200; if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } // 시퀀스 번호로 고유한 시간 보장 Entry.ITPLE.timeSeq++; const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; sq.SET[port] = { type: Entry.ITPLE.sensorTypes.NEOPIXEL_INIT, data: uniqueTime % 10000, time: uniqueTime, }; script.isStart = true; script.timeFlag = Date.now(); return script; } // 10ms 대기 if (Date.now() - script.timeFlag < 2) { return script; } delete script.isStart; delete script.timeFlag; return script.callReturn(); }, syntax: { js: [], py: [{ syntax: 'Arduino.neopixelInit(9, 4)' }] } }, ITPLE_set_neopixel: { color: EntryStatic.colorSet.block["default"].HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [{ type: 'Dropdown', options: [['1', '0'], ['2', '1'], ['3', '2'], ['4', '3']], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow["default"].HARDWARE }, { type: 'Block', accept: 'string', defaultType: 'text' }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12 }], events: {}, def: { params: [null, { type: 'ITPLE_color_picker_value', params: ['#FF0000'] }, null], type: 'ITPLE_set_neopixel' }, paramsKeyMap: { NUM: 0, COLOR: 1, }, "class": 'ITPLE_neopixel', isNotFor: ['ITPLE'], func(sprite, script) { const sq = Entry.hw.sendQueue; const num = script.getNumberValue('NUM', script); const port = 100 + num; const color = script.getStringValue('COLOR', script); const rgb = Entry.hex2rgb(color); let r = rgb.r || 0; let g = rgb.g || 0; let b = rgb.b || 0; r = Math.min(255, Math.max(0, r)); g = Math.min(255, Math.max(0, g)); b = Math.min(255, Math.max(0, b)); if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } // 시퀀스 번호로 고유한 시간 보장 Entry.ITPLE.timeSeq++; const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; sq.SET[port] = { type: Entry.ITPLE.sensorTypes.NEOPIXEL_COLOR, data: { num, r, g, b }, time: uniqueTime, }; script.isStart = true; script.timeFlag = Date.now(); return script; } // 10ms 대기 if (Date.now() - script.timeFlag < 2) { return script; } delete script.isStart; delete script.timeFlag; return script.callReturn(); }, syntax: { js: [], py: [{ syntax: 'Arduino.neopixelColor(9, %1, %2)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }] } }, ITPLE_set_neopixel_all: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'text' }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'ITPLE_color_picker_value', params: ['#00FF00'] }, null, ], type: 'ITPLE_set_neopixel_all', }, paramsKeyMap: { COLOR: 0, }, class: 'ITPLE_neopixel', isNotFor: ['ITPLE'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = 202; // 전체 설정용 가상 포트 const color = script.getStringValue('COLOR', script); const rgb = Entry.hex2rgb(color); let r = rgb.r || 0; let g = rgb.g || 0; let b = rgb.b || 0; r = Math.min(255, Math.max(0, r)); g = Math.min(255, Math.max(0, g)); b = Math.min(255, Math.max(0, b)); if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } // 시퀀스 번호로 고유한 시간 보장 Entry.ITPLE.timeSeq++; const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; sq.SET[port] = { type: Entry.ITPLE.sensorTypes.NEOPIXEL_COLOR, data: { num: 255, r, g, b }, // num: 255는 전체를 의미 time: uniqueTime, }; script.isStart = true; script.timeFlag = Date.now(); return script; } // 10ms 대기 if (Date.now() - script.timeFlag < 2) { return script; } delete script.isStart; delete script.timeFlag; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.neopixelColorAll(9, %1)', textParams: [ { type: 'Block', accept: 'string', }, ], }, ] }, }, ITPLE_set_neopixel_range: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['1', '0'], ['2', '1'], ['3', '2'], ['4', '3'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [ ['1', '0'], ['2', '1'], ['3', '2'], ['4', '3'], ], value: '3', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', defaultType: 'text' }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, null, { type: 'ITPLE_color_picker_value', params: ['#0000FF'] }, null, ], type: 'ITPLE_set_neopixel_range', }, paramsKeyMap: { START: 0, END: 1, COLOR: 2, }, class: 'ITPLE_neopixel', isNotFor: ['ITPLE'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = 203; // 범위 설정용 가상 포트 let start = script.getNumberValue('START', script); let end = script.getNumberValue('END', script); const color = script.getStringValue('COLOR', script); const rgb = Entry.hex2rgb(color); let r = rgb.r || 0; let g = rgb.g || 0; let b = rgb.b || 0; // 범위 자동 조절 (0~3) start = Math.min(3, Math.max(0, start)); end = Math.min(3, Math.max(0, end)); // start > end인 경우 swap if (start > end) { const temp = start; start = end; end = temp; } // RGB 값 조절 r = Math.min(255, Math.max(0, r)); g = Math.min(255, Math.max(0, g)); b = Math.min(255, Math.max(0, b)); if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } // 시퀀스 번호로 고유한 시간 보장 Entry.ITPLE.timeSeq++; const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; sq.SET[port] = { type: Entry.ITPLE.sensorTypes.NEOPIXEL_COLOR, data: { num: 254, start, end, r, g, b }, // num: 254는 범위를 의미 time: uniqueTime, }; script.isStart = true; script.timeFlag = Date.now(); return script; } // 10ms 대기 if (Date.now() - script.timeFlag < 2) { return script; } delete script.isStart; delete script.timeFlag; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.neopixelColorRange(9, %1, %2, %3)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ] }, }, ITPLE_set_neopixel_rotate: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['왼쪽', '-1'], ['오른쪽', '1'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['1'], }, null, ], type: 'ITPLE_set_neopixel_rotate', }, paramsKeyMap: { DIRECTION: 0, STEPS: 1, }, class: 'ITPLE_neopixel', isNotFor: ['ITPLE'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = 205; // 회전용 가상 포트 let direction = script.getNumberValue('DIRECTION', script); let steps = script.getNumberValue('STEPS', script); // steps 범위 조절 (0~4) steps = Math.min(4, Math.max(0, Math.floor(steps))); if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } // 시퀀스 번호로 고유한 시간 보장 Entry.ITPLE.timeSeq++; const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; sq.SET[port] = { type: Entry.ITPLE.sensorTypes.NEOPIXEL_ROTATE, data: { direction, steps }, time: uniqueTime, }; script.isStart = true; script.timeFlag = Date.now(); return script; } // 10ms 대기 if (Date.now() - script.timeFlag < 10) { return script; } delete script.isStart; delete script.timeFlag; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.neopixelRotate(9, %1, %2)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ] }, }, ITPLE_set_neopixel_brightness: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['255'], }, null, ], type: 'ITPLE_set_neopixel_brightness', }, paramsKeyMap: { BRIGHTNESS: 0, }, class: 'ITPLE_neopixel', isNotFor: ['ITPLE'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = 201; let brightness = script.getNumberValue('BRIGHTNESS', script); brightness = Math.min(255, Math.max(0, brightness)); if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } // 시퀀스 번호로 고유한 시간 보장 Entry.ITPLE.timeSeq++; const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; sq.SET[port] = { type: Entry.ITPLE.sensorTypes.NEOPIXEL_BRIGHTNESS, data: brightness, time: uniqueTime, }; script.isStart = true; script.timeFlag = Date.now(); return script; } // 10ms 대기 if (Date.now() - script.timeFlag < 2) { return script; } delete script.isStart; delete script.timeFlag; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.neopixelBrightness(9, %1)', textParams: [ { type: 'Block', accept: 'string', }, ], }, ] }, }, ITPLE_set_neopixel_blink: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['왼쪽', '0'], ['오른쪽', '1'], ['전체', '2'], ], value: '2', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', defaultType: 'text' }, { type: 'Block', accept: 'string', defaultType: 'number' }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12 }, ], events: {}, def: { params: [ null, { type: 'ITPLE_color_picker_value', params: ['#FFFFFF'] }, { type: 'number', params: ['0.5'] }, null, ], type: 'ITPLE_set_neopixel_blink', }, paramsKeyMap: { SIDE: 0, COLOR: 1, INTERVAL: 2, }, class: 'ITPLE_neopixel', isNotFor: ['ITPLE'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = 206; // BLINK 가상 포트 const side = script.getNumberValue('SIDE', script); // 2: 전체, 0: 왼쪽, 1: 오른쪽 const count = 0; // 무한 깜박임 const color = script.getStringValue('COLOR', script); let intervalSec = script.getNumberValue('INTERVAL', script); const rgb = Entry.hex2rgb(color); let r = rgb.r || 0; let g = rgb.g || 0; let b = rgb.b || 0; r = Math.min(255, Math.max(0, r)); g = Math.min(255, Math.max(0, g)); b = Math.min(255, Math.max(0, b)); const interval = Math.max(0.1, intervalSec) * 1000; // ms if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } // 시퀀스 번호로 고유한 시간 보장 (다른 네오픽셀 동작과 통일) Entry.ITPLE.timeSeq++; const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; sq.SET[port] = { type: Entry.ITPLE.sensorTypes.NEOPIXEL_BLINK, data: { side, count, r, g, b, interval }, time: uniqueTime, }; script.isStart = true; script.timeFlag = Date.now(); return script; } if (Date.now() - script.timeFlag < 2) { return script; } delete script.isStart; delete script.timeFlag; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.neopixelBlink(%1, %2, %3)', textParams: [ { type: 'Block', accept: 'string' }, { type: 'Block', accept: 'string' }, { type: 'Block', accept: 'string' }, ], }, ] }, }, ITPLE_stop_neopixel_blink: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['왼쪽', '0'], ['오른쪽', '1'], ['전체', '2'], ], value: '2', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12 }, ], events: {}, def: { params: [null, null], type: 'ITPLE_stop_neopixel_blink', }, paramsKeyMap: { SIDE: 0, }, class: 'ITPLE_neopixel', isNotFor: ['ITPLE'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = 206; // BLINK/STOP 통합 가상 포트 if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } const side = script.getNumberValue('SIDE', script); // 시퀀스 번호로 고유한 시간 보장 Entry.ITPLE.timeSeq++; const uniqueTime = new Date().getTime() + Entry.ITPLE.timeSeq; sq.SET[port] = { type: Entry.ITPLE.sensorTypes.NEOPIXEL_BLINK_STOP, data: { side }, time: uniqueTime, }; script.isStart = true; script.timeFlag = Date.now(); return script; } if (Date.now() - script.timeFlag < 2) { return script; } delete script.isStart; delete script.timeFlag; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.neopixelBlinkStop(9, %1)' }, ] }, }, }; }; //endregion ITPLE 아두이노 확장모드 module.exports = Entry.ITPLE; ================================================ FILE: src/playground/blocks/hardware/block_KKMOO.js ================================================ 'use strict'; Entry.kkmoo = { id: '53.1', name: 'kkmoo', url: '', imageName: 'kkmoo.png', title: { ko: 'kkmoo', en: 'kkmoo', }, isReceive: 0, motData: [ { num: 0, angle: 0 }, { num: 1, angle: 0 }, { num: 2, angle: 0 }, { num: 3, angle: 0 }, { num: 4, angle: 0 }, { num: 5, angle: 0 }, { num: 6, angle: 0 }, { num: 7, angle: 0 }, { num: 8, angle: 0 }, { num: 9, angle: 0 }, { num: 10, angle: 0 }, { num: 11, angle: 0 }, { num: 12, angle: 0 }, { num: 13, angle: 0 }, { num: 14, angle: 0 }, { num: 15, angle: 0 }, { num: 16, angle: 0 }, { num: 17, angle: 0 }, ], runningStart: false, isMotionRunning: false, motionFrame: [ { frame: 0, data: null, time: 0 }, { frame: 1, data: null, time: 0 }, { frame: 2, data: null, time: 0 }, { frame: 3, data: null, time: 0 }, { frame: 4, data: null, time: 0 }, { frame: 5, data: null, time: 0 }, { frame: 6, data: null, time: 0 }, { frame: 7, data: null, time: 0 }, { frame: 8, data: null, time: 0 }, { frame: 9, data: null, time: 0 }, { frame: 10, data: null, time: 0 }, { frame: 11, data: null, time: 0 }, { frame: 12, data: null, time: 0 }, { frame: 13, data: null, time: 0 }, { frame: 14, data: null, time: 0 }, { frame: 15, data: null, time: 0 }, { frame: 16, data: null, time: 0 }, { frame: 17, data: null, time: 0 }, { frame: 18, data: null, time: 0 }, { frame: 19, data: null, time: 0 }, ], playcnt: 0, checkTimeout: 0, timeoutCnt: 0, setTimeout: function (time) { this.timeoutCnt = time; this.checkTimeout = new Date(); }, timeOut: function () { if (new Date() - this.checkTimeout > this.timeoutCnt) { return true; } else { return false; } }, setZero: function () { for (var i of this.motData) { i.angle = 0; } for (var i of this.motionFrame) { i.data = null; i.time = 0; } Entry.hw.sendQueue.msg = { prot: 'RT', data: null }; this.playcnt = 0; this.checkTimeout = 0; this.timeoutCnt = 0; }, copyObj: function (obj) { const result = {}; for (let key in obj) { if (typeof obj[key] === 'object') { result[key] = this.copyObj(obj[key]); } else { result[key] = obj[key]; } } return result; }, }; Entry.kkmoo.setLanguage = function () { return { ko: { template: { kkmoo_rotate_motor: '%1번 모터의 각도를 %2도로 회전 %3', //kkmoo_isPlaying: '동작이 실행중인가?', kkmoo_motion_play_basic: '기본 %1번 동작 실행 %2', kkmoo_motion_play_custom: '커스텀 %1번 동작 실행 %2', kkmoo_rotate_motor_time: '%1번 모터의 각도를 %2도로 %3밀리초 동안 회전 %4', kkmoo_set_motor_degree: '%1번 모터의 각도를 %2도로 설정 %3', kkmoo_run_set_value_time: '설정값 %1밀리초 동안 실행%2', kkmoo_set_frame: '설정값을 임시동작 %1 번 프레임으로 지정 %2', kkmoo_set_frame_time: '임시동작의 %1 번 프레임의 시간을 %2 밀리초로 설정 %3', kkmoo_play_temp_motion: '임시동작 실행 %1', kkmoo_save_to_robot: '임시동작을 까무 커스텀동작 %1 번에 %2 으로 저장 %3', }, Menus: { kkmoo: '까무', }, }, en: { template: { kkmoo_rotate_motor: 'Rotate motor %1 to %2 degrees %3', //kkmoo_isPlaying: 'Is motion running?', kkmoo_motion_play_basic: 'Play basic motion number %1 %2', kkmoo_motion_play_custom: 'Play custom motion number %1 %2', kkmoo_rotate_motor_time: 'Rotate motor %1 to %2 degrees for%3 milliseconds %4', kkmoo_set_motor_degree: 'Set motor %1 to %2 degrees %3', kkmoo_run_set_value_time: 'Run setting value for %1 milliseconds %2', kkmoo_set_frame: 'Set the setting value as frame number %1 for temporary-motion %2', kkmoo_set_frame_time: 'Set the time of frame number %1 of temporary-motion to %2 milliseconds %3', kkmoo_play_temp_motion: 'Run temporary-Motion %1', kkmoo_save_to_robot: 'Save the temporary-motion to Kamu-Custom-Motion number %1, name as %2 %3', }, Menus: { kkmoo: 'kkmoo', }, }, }; }; Entry.kkmoo.blockMenuBlocks = [ 'kkmoo_rotate_motor', //'kkmoo_isPlaying', 'kkmoo_motion_play_basic', 'kkmoo_motion_play_custom', 'kkmoo_rotate_motor_time', 'kkmoo_set_motor_degree', 'kkmoo_run_set_value_time', 'kkmoo_set_frame', 'kkmoo_set_frame_time', 'kkmoo_play_temp_motion', 'kkmoo_save_to_robot', ]; Entry.kkmoo.getBlocks = function () { return { // 까무_모터 개별회전 kkmoo_rotate_motor: { template: Lang.template.kkmoo_rotate_motor, color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ['14', '14'], ['15', '15'], ['16', '16'], ['17', '17'], ], fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', converter: Entry.block.converters.returnStringOrNumberByValue, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], paramsKeyMap: { MOTNUM: 0, ANGLE: 1, }, events: {}, def: { params: [ '0', //dropdown의 경우 VALUE값이 초기값 { type: 'number', //최대최소값설정? params: ['0'], }, ], type: 'kkmoo_rotate_motor', }, class: 'Basic', isNotFor: ['kkmoo'], func: function (sprite, script) { const prot = 'EC'; const motnum = script.getField('MOTNUM', script); const angle = script.getValue('ANGLE', script); var msg = null; Entry.hw.update(); if (script.isStart != true) { if (Entry.hw.portData.data == 'true') { return script; } else { script.isStart = true; if (angle >= -90 && angle <= 90) { msg = { MOT: motnum, ANG: angle }; } Entry.hw.sendQueue.msg = { prot: prot, data: msg }; Entry.kkmoo.setTimeout(600); return script; } } else { if (Entry.hw.portData.data == 'true' || Entry.kkmoo.timeOut()) { delete script.isStart; delete Entry.hw.sendQueue.msg; return script.callReturn(); } else { return script; } } //return null; //return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Kkmoo.rotateMotor(%1,%2)', blockType: 'param', textParams: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ['14', '14'], ['15', '15'], ['16', '16'], ['17', '17'], ], fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', }, ], }, ], }, }, kkmoo_motion_play_basic: { template: Lang.template.kkmoo_motion_play_basic, color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', converter: Entry.block.converters.returnStringOrNumberByValue, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], paramsKeyMap: { MOTIONNUM: 0, }, events: {}, def: { params: [ { type: 'number', params: ['0'], }, ], type: 'kkmoo_motion_play_basic', }, class: 'Basic', isNotFor: ['kkmoo'], func: function (sprite, script) { const prot = 'PM'; const motionnum = script.getValue('MOTIONNUM', script); var msg = motionnum; Entry.hw.update(); if (script.isStart != true) { if (Entry.hw.portData.data == 'true') { return script; } else { script.isStart = true; Entry.hw.sendQueue.msg = { prot: prot, data: msg }; Entry.kkmoo.setTimeout(600); return script; } } else { if (Entry.hw.portData.data == 'true' || Entry.kkmoo.timeOut()) { delete script.isStart; delete Entry.hw.sendQueue.msg; return script.callReturn(); } else { console.log('!!'); return script; } } }, syntax: { js: [], py: [ { syntax: 'Kkmoo.playBasicMotion(%1)', blockType: 'param', textParams: [ { type: 'Block', accept: 'string', }, ], }, ], }, }, kkmoo_motion_play_custom: { template: Lang.template.kkmoo_motion_play_custom, color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', converter: Entry.block.converters.returnStringOrNumberByValue, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], paramsKeyMap: { MOTIONNUM: 0, }, events: {}, def: { params: [ { type: 'number', params: ['0'], }, ], type: 'kkmoo_motion_play_custom', }, class: 'Basic', isNotFor: ['kkmoo'], func: function (sprite, script) { const prot = 'CM'; const motionnum = script.getValue('MOTIONNUM', script); var msg = motionnum; Entry.hw.update(); if (script.isStart != true) { if (Entry.hw.portData.data == 'true') { return script; } else { script.isStart = true; Entry.hw.sendQueue.msg = { prot: prot, data: msg }; Entry.kkmoo.setTimeout(600); return script; } } else { if (Entry.hw.portData.data == 'true' || Entry.kkmoo.timeOut()) { delete script.isStart; delete Entry.hw.sendQueue.msg; return script.callReturn(); } else { return script; } } }, syntax: { js: [], py: [ { syntax: 'Kkmoo.playCustomMotion(%1)', blockType: 'param', textParams: [ { type: 'Block', accept: 'string', }, ], }, ], }, }, kkmoo_rotate_motor_time: { template: Lang.template.kkmoo_rotate_motor_time, color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ['14', '14'], ['15', '15'], ['16', '16'], ['17', '17'], ], fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', converter: Entry.block.converters.returnStringOrNumberByValue, }, { type: 'Block', accept: 'string', converter: Entry.block.converters.returnStringOrNumberByValue, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], paramsKeyMap: { MOTNUM: 0, ANGLE: 1, TIME: 2, }, events: {}, def: { params: [ '0', //dropdown의 경우 VALUE값이 초기값 { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, ], type: 'kkmoo_rotate_motor_time', }, class: 'Basic', isNotFor: ['kkmoo'], func: function (sprite, script) { const prot = 'AD'; const motnum = script.getField('MOTNUM', script); const angle = script.getValue('ANGLE', script); const time = script.getValue('TIME', script); var msg = null; Entry.hw.update(); if (script.isStart != true) { if (Entry.hw.portData.data == 'true') { return script; } else { script.isStart = true; if (angle >= -90 && angle <= 90) { msg = { MOT: motnum, ANG: angle, TME: time }; } Entry.hw.sendQueue.msg = { prot: prot, data: msg }; Entry.kkmoo.setTimeout(600); return script; } } else { if ( Entry.hw.portData.data == 'true' || script.getValue('TIME', script) == 0 || Entry.kkmoo.timeOut() ) { delete script.isStart; delete Entry.hw.sendQueue.msg; return script.callReturn(); } else { return script; } } //return null; //return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Kkmoo.rotateMotorforSeconds(%1,%2,%3)', blockType: 'param', textParams: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ['14', '14'], ['15', '15'], ['16', '16'], ['17', '17'], ], fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, //===================================================================동작 만들기============================================= kkmoo_set_motor_degree: { template: Lang.template.kkmoo_set_motor_degree, color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ['14', '14'], ['15', '15'], ['16', '16'], ['17', '17'], ], fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', converter: Entry.block.converters.returnStringOrNumberByValue, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], paramsKeyMap: { MOTNUM: 0, ANGLE: 1, }, events: {}, def: { params: [ '0', //dropdown의 경우 VALUE값이 초기값 { type: 'number', params: ['0'], }, ], type: 'kkmoo_set_motor_degree', }, class: 'Make_Motion', isNotFor: ['kkmoo'], func: function (sprite, script) { const motnum = script.getField('MOTNUM', script); const angle = script.getValue('ANGLE', script); Entry.hw.update(); if (script.isStart != true) { script.isStart = true; if (angle >= -90 && angle <= 90) { Entry.kkmoo.motData[motnum].angle = angle; } else if (angle > 90) { Entry.kkmoo.motData[motnum].angle = 90; } else { Entry.kkmoo.motData[motnum].angle = -90; } return script; } else { delete script.isStart; console.log(Entry.kkmoo.motData); return script.callReturn(); } //return null; //return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Kkmoo.setBuffer(%1,%2)', blockType: 'param', textParams: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ['14', '14'], ['15', '15'], ['16', '16'], ['17', '17'], ], fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', }, ], }, ], }, }, kkmoo_run_set_value_time: { template: Lang.template.kkmoo_run_set_value_time, color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', converter: Entry.block.converters.returnStringOrNumberByValue, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], paramsKeyMap: { TIME: 0, }, events: {}, def: { params: [ { type: 'number', params: ['0'], }, ], type: 'kkmoo_run_set_value_time', }, class: 'Make_Motion', isNotFor: ['kkmoo'], func: function (sprite, script) { const prot = 'MP'; var msg = []; Entry.hw.update(); console.log(Entry.hw.portData.data); if (script.isStart != true) { if (Entry.hw.portData.data == 'true') { return script; } else { script.isStart = true; for (var i of Entry.kkmoo.motData) { var angle = i.angle; var motnum = i.num; msg.push({ MOT: motnum, ANG: angle }); } msg.push(script.getValue('TIME', script)); Entry.hw.sendQueue.msg = { prot: prot, data: msg }; Entry.kkmoo.setTimeout(600); return script; } } else { if ( Entry.hw.portData.data == 'true' || script.getValue('TIME', script) == 0 || Entry.kkmoo.timeOut() ) { delete script.isStart; delete Entry.hw.sendQueue.msg; return script.callReturn(); } else { return script; } } }, syntax: { js: [], py: [ { syntax: 'Kkmoo.runBufferforSeconds(%1)', blockType: 'param', textParams: [ { type: 'Block', accept: 'string', }, ], }, ], }, }, kkmoo_set_frame: { template: Lang.template.kkmoo_set_frame, color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ['14', '14'], ['15', '15'], ['16', '16'], ['17', '17'], ['18', '18'], ['19', '19'], ['20', '20'], ], fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], paramsKeyMap: { FRAME: 0, }, events: {}, def: { params: [ '0', //dropdown의 경우 VALUE값이 초기값 ], type: 'kkmoo_set_frame', }, class: 'Save_Motion', isNotFor: ['kkmoo'], func: function (sprite, script) { const motnum = script.getField('FRAME', script); Entry.hw.update(); if (script.isStart != true) { script.isStart = true; var data = Entry.kkmoo.copyObj(Entry.kkmoo.motData); Entry.kkmoo.motionFrame[motnum].data = data; return script; } else { delete script.isStart; console.log(Entry.kkmoo.motionFrame); return script.callReturn(); } //return null; //return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Kkmoo.setBuffertoFrame(%1)', blockType: 'param', textParams: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ['14', '14'], ['15', '15'], ['16', '16'], ['17', '17'], ], fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], }, ], }, }, kkmoo_set_frame_time: { template: Lang.template.kkmoo_set_frame_time, color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ['14', '14'], ['15', '15'], ['16', '16'], ['17', '17'], ['18', '18'], ['19', '19'], ['20', '20'], ], fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', converter: Entry.block.converters.returnStringOrNumberByValue, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], paramsKeyMap: { FRAME: 0, TIME: 1, }, events: {}, def: { params: [ '0', //dropdown의 경우 VALUE값이 초기값 { type: 'number', params: ['0'], }, ], type: 'kkmoo_set_frame_time', }, class: 'Save_Motion', isNotFor: ['kkmoo'], func: function (sprite, script) { const motnum = script.getField('FRAME', script); const time = script.getValue('TIME', script); Entry.hw.update(); if (script.isStart != true) { script.isStart = true; Entry.kkmoo.motionFrame[motnum].time = time; return script; } else { delete script.isStart; return script.callReturn(); } //return null; //return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Kkmoo.setFrameTime(%1,%2)', blockType: 'param', textParams: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ['14', '14'], ['15', '15'], ['16', '16'], ['17', '17'], ], fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', }, ], }, ], }, }, kkmoo_play_temp_motion: { template: Lang.template.kkmoo_play_temp_motion, color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], paramsKeyMap: {}, events: {}, def: { params: [], type: 'kkmoo_play_temp_motion', }, class: 'Save_Motion', isNotFor: ['kkmoo'], func: function (sprite, script) { const prot = 'PT'; var msg = []; Entry.hw.update(); if (script.isStart != true) { if (Entry.hw.portData.data == 'true') { return script; } else { script.isStart = true; for (var dat of Entry.kkmoo.motionFrame) { //frame,data,time if (dat.data != null && dat.time != 0) { Entry.kkmoo.playcnt++; msg.push(dat); } } Entry.hw.sendQueue.msg = { prot: prot, data: msg }; Entry.kkmoo.setTimeout(600); return script; } } else { if ( Entry.hw.portData.data == 'true' || Entry.kkmoo.playcnt == 0 || Entry.kkmoo.timeOut() ) { delete script.isStart; delete Entry.hw.sendQueue.msg; Entry.kkmoo.playcnt = 0; return script.callReturn(); } else { return script; } } }, syntax: { js: [], py: [ { syntax: 'Kkmoo.runTempMotion()', blockType: 'param', textParams: [], }, ], }, }, kkmoo_save_to_robot: { template: Lang.template.kkmoo_save_to_robot, color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_without_next', statements: [], params: [ { type: 'Block', accept: 'string', converter: Entry.block.converters.returnStringOrNumberByValue, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], paramsKeyMap: { SLOT: 0, NAME: 1, }, events: {}, def: { params: [ { type: 'number', params: ['0'], }, { type: 'text', params: ['이름'], }, ], type: 'kkmoo_save_to_robot', }, class: 'Save_Motion', isNotFor: ['kkmoo'], func: function (sprite, script) { const prot = 'SV'; var msg = []; var my_json = { name: '', frame_length: '', frames: [] }; Entry.hw.update(); if (script.isStart != true) { if (Entry.hw.portData.data == 'true') { return script; } else { script.isStart = true; for (var dat of Entry.kkmoo.motionFrame) { //frame,data,time if (dat.data != null && dat.time != 0) { msg.push(dat); var frame = { index: '', transition_time: '', outputs: [] }; frame.index = Entry.kkmoo.playcnt; frame.transition_time = parseInt(dat.time); Entry.kkmoo.playcnt++; var my_data = [ { device: 'left_shoulder_pitch', value: '' }, { device: 'left_thigh_yaw', value: '' }, { device: 'left_shoulder_roll', value: '' }, { device: 'left_elbow_roll', value: '' }, { device: 'left_thigh_roll', value: '' }, { device: 'left_thigh_pitch', value: '' }, { device: 'left_knee_pitch', value: '' }, { device: 'left_foot_pitch', value: '' }, { device: 'left_foot_roll', value: '' }, { device: 'right_shoulder_pitch', value: '' }, { device: 'right_thigh_yaw', value: '' }, { device: 'right_shoulder_roll', value: '' }, { device: 'right_elbow_roll', value: '' }, { device: 'right_thigh_roll', value: '' }, { device: 'right_thigh_pitch', value: '' }, { device: 'right_knee_pitch', value: '' }, { device: 'right_foot_pitch', value: '' }, { device: 'right_foot_roll', value: '' }, ]; for (var i in dat.data) { my_data[i].value = parseInt(dat.data[i].angle); } frame.outputs = my_data; my_json.frames.push(frame); } } var slot = script.getValue('SLOT', script); var name = script.getValue('NAME', script); var namelength = 0; var result = ''; for (var i of name) { var buf = Buffer.from(i, 'utf-8').toString('hex'); var length = buf.length; if (namelength + length > 40) { break; } else { namelength += length; result += buf; } } result = result.padEnd(40, '20'); var numBytes = result.length / 2; var byteArray = new Uint8Array(numBytes); for (var i = 0; i < numBytes; i++) { byteArray[i] = parseInt(result.substr(i * 2, 2), 16); } const decoder = new TextDecoder('utf-8'); var name_string = decoder.decode(byteArray); my_json.name = name_string; my_json.frame_length = msg.length; const CryptoJS = require('crypto-js'); var hash = CryptoJS.SHA256(JSON.stringify(my_json)) .toString() .substring(0, 10); Entry.hw.sendQueue.msg = { prot: prot, data: msg, slot: slot, name: name_string, hash: hash, }; Entry.kkmoo.setTimeout(600); return script; } } else { if ( Entry.hw.portData.data == 'true' || Entry.kkmoo.playcnt == 0 || Entry.kkmoo.timeOut() ) { delete script.isStart; delete Entry.hw.sendQueue.msg; Entry.kkmoo.playcnt = 0; return script.callReturn(); } else { return script; } } }, syntax: { js: [], py: [ { syntax: 'Kkmoo.SaveMotion(%1,%2)', blockType: 'param', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, }; }; module.exports = Entry.kkmoo; ================================================ FILE: src/playground/blocks/hardware/block_KRC.js ================================================ 'use strict'; const DelayTime = 0; let LmotorSpeed = 0; let RmotorSpeed = 0; Entry.krc = { id: '3A.2', name: 'KRC', url: 'http://www.kairobot.co.kr/', imageName: 'KRC.png', title: { ko: 'KRC_S', en: 'KRC_S', }, setZero: () => { // 하드웨어 초기화 로직 if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue = { GET: {}, SET: {}, }; } else { const keySet = Object.keys(Entry.hw.sendQueue.SET); keySet.forEach((key) => { Entry.hw.sendQueue.SET[parseInt(key, 10)].data = 0; Entry.hw.sendQueue.SET[parseInt(key, 10)].time = new Date().getTime(); }); } Entry.hw.update(); LmotorSpeed = 0; RmotorSpeed = 0; }, Static: { // krc_BLOCK_COLOR: '#00979D', // gray(#848484) // krc_ARROW_COLOR_HW: '#00979D', }, sensorTypes: { ALIVE: 0, DIGITAL: 1, ANALOG: 2, BUZZER: 3, SERVO: 4, TONE: 5, USONIC: 7, MOTOR: 12, USONIC_SET: 33, LCD_SET: 40, }, BlockState: {}, }; Entry.krc.blockMenuBlocks = [ /// 하드웨어 블록 등록 , 여기에 등록된 블록이 순서대로 나열되며 설정한 이름으로 화면에 보임 'KrcBuzzerOnOff', // 스피커 삐 소리 'KrcSetMotorSpeed', // DC모터 속도제어 'KrcMotorStop', // DC모터 정지하기 'KrcSetServo', // 서보모터 제어 'KrcDigitalOnOff', /// 디지털 포트 제어 'KrcGetDgitalValue', //디지탈 입력 'KrcGetAnalogValue', // 아날로그 입력 'KrcGetUsonicValue', //초음파센서 읽기 'KrcSetLcdString', 'KrcSetLcdBacklight', 'KrcSetLcdClear', 'KrcGetAnalogMapping', ]; Entry.krc.setLanguage = function() { // 블록 이름 번역 return { ko: { template: { KrcBuzzerOnOff: '스피커 삐 소리 %1 초 연주하기 %2', KrcSetMotorSpeed: 'DC모터 왼쪽 속도%1 오른쪽 속도%2 으로 정하기 %3', KrcMotorStop: 'DC모터 정지하기 %1', KrcSetServo: '서보모터 %1포트, 각도%2도, 속도%3%로 이동 %4', KrcDigitalOnOff: '디지털 %1 포트 %2 설정하기 %3', KrcGetDgitalValue: '디지털 %1 포트 읽기', KrcGetAnalogValue: '아날로그 %1 포트 읽기', KrcGetUsonicValue: '아날로그형 (US-016)초음파센서 %1포트 읽기', KrcSetLcdString: 'lcd 세로%1줄, 가로%2줄 에 %3 표시하기 %4', KrcSetLcdBacklight: 'lcd 후광(백라이트) %1 하기 %2', KrcSetLcdClear: 'lcd 지우기 %1', KrcGetAnalogMapping: ' %1 값 %2 ~ %3 에서 %4 ~ %5 으로 변환값', }, Blocks: { OnBlock: '켜짐(HIGH, 5V)', OffBlock: '꺼짐(LOW, 0V)', AllOnBlock: '모두 켜짐', AllOffBlock: '모두 꺼짐', BacklightOn: '켜기', BacklightOff: '끄기', }, }, en: { template: { KrcBuzzerOnOff: 'Speakers Beep %1 Playing Second %2', KrcSetMotorSpeed: 'Set DC motor left speed %1 right speed %2 %3', KrcMotorStop: 'Stop DC Motor %1', KrcSetServo: 'Servo motor %1 port angle %2 movement %3', KrcDigitalOnOff: 'Setting up digital %1 port %2 %3', KrcGetDgitalValue: 'Read digital %1 port', KrcGetAnalogValue: 'Analog %1 port read', KrcGetUsonicValue: 'Analog type (US-016)High sound sensor %1 port read', KrcSetLcdString: 'lcd Display %3 on line %1 and line %2 %4', KrcSetLcdBacklight: 'Enter lcd backlight %1 %2', KrcSetLcdClear: 'Clear lcd %1', KrcGetAnalogMapping: '%1 value %2 to %3 ; to %4 to %5 conversion value ', }, Blocks: { OnBlock: 'On(HIGH, 5V)', OffBlock: 'Off(LOW, 0V)', AllOnBlock: 'ALL ON', AllOffBlock: 'ALL OFF', BacklightOn: 'ON', BacklightOff: 'OFF', }, }, }; }; Entry.krc.getBlocks = function() { return { KrcDigitalPortOnOffList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.OnBlock, '1'], [Lang.Blocks.OffBlock, '0'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, KrcBacklightOnoffList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.BacklightOn, '0'], [Lang.Blocks.BacklightOff, '1'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, KrcDigitalPortList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['D1', '9'], ['D2', '10'], ['A1', '1'], ['A2', '2'], ['A3', '3'], ['A4', '4'], ['A5', '5'], ['A6', '6'], ['A7', '7'], ['A8', '8'], ['S1', '11'], ['S2', '12'], ['S3', '13'], ['S4', '14'], ['S5', '15'], ['S6', '6'], ], value: '9', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getStringField('PORT'); }, }, KrcServoPortList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['S1', '1'], ['S2', '2'], ['S3', '3'], ['S4', '4'], ['S5', '5'], ['S6', '6'], ['S7', '7'], ], value: '1', // 기본 표시값 fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getStringField('PORT'); }, }, KrcAllOnOffList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.AllOffBlock, '2'], [Lang.Blocks.AllOnBlock, '3'], ], value: '2', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { VALUE: 0, }, func(sprite, script) { return script.getField('VALUE'); }, }, KrcAnalogPortList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['A1', '0'], ['A2', '1'], ['A3', '2'], ['A4', '3'], ['A5', '4'], ['A6', '5'], ['A7', '6'], ['A8', '7'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, // 1. 삐소리 KrcBuzzerOnOff: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'text', params: ['1'], }, null, ], type: 'KrcBuzzerOnOff', }, paramsKeyMap: { VALUE: 0, }, class: 'krc_LV1', isNotFor: ['KRC'], func: (sprite, script) => { const port = 10; let duration = script.getNumberValue('VALUE'); // 길이 const value2 = 2400; //698; // 음 주파수 if (!script.isStart) { if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } if (duration === 0) { // 음 길이가 0 이면 Entry.hw.sendQueue.SET[parseInt(port, 10)] = { type: Entry.krc.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; return script.callReturn(); } if (duration > 300) { duration = 300; } duration = duration * 1000; script.isStart = true; // 출력 시작 플래그 셋 script.timeFlag = 1; // 시간플래그 셋 Entry.hw.sendQueue.SET[parseInt(port, 10)] = { type: Entry.krc.sensorTypes.TONE, data: { value: value2, duration: duration / 10, }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, duration + 32); return script; } else if (script.timeFlag === 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.hw.sendQueue.SET[parseInt(port, 10)] = { type: Entry.krc.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 3. DC 모터 속도 정하기 KrcSetMotorSpeed: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, null, ], type: 'KrcSetMotorSpeed', }, paramsKeyMap: { LSPEED: 0, RSPEED: 1, }, class: 'krc_LV1', isNotFor: ['KRC'], func(sprite, script) { let rspeed = script.getNumberValue('RSPEED', script); let lspeed = script.getNumberValue('LSPEED', script); const port = 3; lspeed = Math.min(100, lspeed); lspeed = Math.max(-100, lspeed); rspeed = Math.min(100, rspeed); rspeed = Math.max(-100, rspeed); if (!(LmotorSpeed === lspeed) || !(RmotorSpeed === rspeed)) { if (!script.isStart) { if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(port, 10)] = { type: Entry.krc.sensorTypes.MOTOR, data: [lspeed, rspeed], time: new Date().getTime(), }; LmotorSpeed = lspeed; RmotorSpeed = rspeed; script.isStart = true; // 출력 시작 플래그 셋 script.timeFlag = 1; // 시간플래그 셋 setTimeout(() => { script.timeFlag = 0; }, DelayTime); return script; } else if (script.timeFlag === 1) { return script; } else { // 설정 시간이 지나면 출력 리셋 delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } } else { return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 4. DC 모터 정지하기 KrcMotorStop: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [null], type: 'KrcMotorStop', }, paramsKeyMap: { //PORT: 0, }, class: 'krc_LV1', isNotFor: ['KRC'], func: (sprite, script) => { const port = 19; //port += 2; const lspeed = 0; const rspeed = 0; if (!(LmotorSpeed === 0) || !(RmotorSpeed === 0)) { if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(port, 10)] = { type: Entry.krc.sensorTypes.MOTOR, data: [lspeed, rspeed], time: new Date().getTime(), }; } LmotorSpeed = 0; RmotorSpeed = 0; return script.callReturn(); }, syntax: { js: [], py: [] }, }, // 5. 서보 모터 각도 설정하기 KrcSetServo: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'KrcServoPortList', }, { type: 'number', params: ['0'], }, { type: 'number', params: ['100'], }, null, ], type: 'KrcSetServo', }, paramsKeyMap: { PORT: 0, ANGLE: 1, SPEED: 2, }, class: 'krc_LV1', isNotFor: ['KRC'], func: (sprite, script) => { const port = script.getNumberValue('PORT', script); let angle = script.getNumberValue('ANGLE', script); let speed = script.getNumberValue('SPEED', script); // port += 2; // var mode = 1; angle = Math.min(180, angle); angle = Math.max(0, angle); speed = Math.min(100, speed); speed = Math.max(0, speed); speed *= speed * 255; //angle += 1; if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(port, 10)] = { type: Entry.krc.sensorTypes.SERVO, data: [angle, speed], time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [] }, }, // 10. 디지털 출력 KrcDigitalOnOff: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'KrcDigitalPortList', }, { type: 'KrcDigitalPortOnOffList', }, null, ], type: 'KrcDigitalOnOff', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'krc_LV3', // 블록을 묶는 그룹 이름. 이 값이 다르면 사이에 가로줄이 생깁니다 isNotFor: ['KRC'], func: (sprite, script) => { const port = script.getNumberValue('PORT'); const value = script.getNumberValue('VALUE'); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(port, 10)] = { type: Entry.krc.sensorTypes.DIGITAL, /// 출력 디바이스 data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [] }, }, // 11. 디지털입력 KrcGetDgitalValue: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', //basic_boolean_field statements: [], template: Lang.template.KrcGetDgitalValue, params: [ { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'KrcDigitalPortList', }, ], type: 'KrcGetDgitalValue', }, paramsKeyMap: { PORT: 0, }, class: 'krc_LV3', isNotFor: ['KRC'], func: (sprite, script) => { const port = script.getNumberValue('PORT'); if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } Entry.hw.sendQueue.GET[Entry.krc.sensorTypes.DIGITAL] = { port: port, time: new Date().getTime(), }; return Entry.hw.portData.DIGITAL[parseInt(port)]; }, syntax: { js: [], py: [] }, }, // 12. 아날로그 읽기 KrcGetAnalogValue: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', template: Lang.template.KrcGetAnalogValue, statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'KrcAnalogPortList', }, ], type: 'KrcGetAnalogValue', }, paramsKeyMap: { PORT: 0, }, class: 'krc_LV3', isNotFor: ['KRC'], func: (sprite, script) => { const BtnIndex = script.getNumberValue('PORT'); const ANALOG = Entry.hw.portData.ANALOG; return ANALOG[parseInt(BtnIndex)]; }, syntax: { js: [], py: [] }, }, // 15. 초음파 센서 값 KrcGetUsonicValue: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', template: Lang.template.KrcGetUsonicValue, statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'KrcAnalogPortList', }, ], type: 'KrcGetUsonicValue', }, paramsKeyMap: { PORT: 0, }, class: 'krc_LV3', isNotFor: ['KRC'], func: (sprite, script) => { const BtnIndex = script.getNumberValue('PORT'); const ANALOG = Entry.hw.portData.ANALOG; return (ANALOG[parseInt(BtnIndex)] * 4 * 3) / 10; }, syntax: { js: [], py: [] }, }, // 21. LCD글자출력 KrcSetLcdString: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, { type: 'text', params: ['Hello'], }, null, ], type: 'KrcSetLcdString', }, paramsKeyMap: { COLUMN: 0, LINE: 1, STRING: 2, }, class: 'krc_LV5', isNotFor: ['KRC'], func: (sprite, script) => { //var sq = Entry.hw.sendQueue; const line2 = script.getValue('LINE', script); const column2 = script.getValue('COLUMN', script); const string = script.getValue('STRING', script); const text = []; let buf; if (!script.isStart) { if (typeof string === 'string') { for (let i = 0; i < string.length; i++) { buf = Entry.memaker.toByte(string[parseInt(i, 10)]); text[parseInt(i, 10)] = buf; //text[i] = Entry.memaker.toByte(string[i]); //text.i = Entry.memaker.toByte(string.i); } } else { text[0] = string; } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } script.isStart = true; script.timeFlag = 1; //var fps = Entry.FPS || 60; // var timeValue = 60 / fps * 50; Entry.hw.sendQueue.SET[3] = { type: Entry.krc.sensorTypes.LCD_SET, data: { line: line2, column: column2, text0: text[0], text1: text[1], text2: text[2], text3: text[3], text4: text[4], text5: text[5], text6: text[6], text7: text[7], text8: text[8], text9: text[9], }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, DelayTime); return script; } else if (script.timeFlag === 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = true; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // . LCD 백라이트 KrcSetLcdBacklight: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'KrcBacklightOnoffList', }, null, ], type: 'KrcSetLcdBacklight', }, paramsKeyMap: { VALUE: 0, }, class: 'krc_LV5', isNotFor: ['KRC'], func: (sprite, script) => { const value = script.getNumberValue('VALUE'); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[1] = { type: Entry.krc.sensorTypes.LCD_SET, data: [value, 1, 1], time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [] }, }, // 23. LCD 지우기 KrcSetLcdClear: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [null], type: 'KrcSetLcdClear', }, class: 'krc_LV5', isNotFor: ['KRC'], func: (sprite, script) => { //var port = 0; if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[4] = { type: Entry.krc.sensorTypes.LCD_SET, data: [4, 4, 4], time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [] }, }, // 3. 소리/빛/가변저항 - 2) mapping 값 KrcGetAnalogMapping: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', template: Lang.template.KrcGetAnalogMapping, statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['1023'], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['100'], }, ], type: 'KrcGetAnalogMapping', }, paramsKeyMap: { IDATA: 0, VALUE2: 1, VALUE3: 2, VALUE4: 3, VALUE5: 4, }, class: 'krc_ANA', isNotFor: ['KRC'], func: (sprite, script) => { let result = script.getNumberValue('IDATA', script); let value2 = script.getNumberValue('VALUE2', script); let value3 = script.getNumberValue('VALUE3', script); let value4 = script.getNumberValue('VALUE4', script); let value5 = script.getNumberValue('VALUE5', script); let swap; if (value2 > value3) { swap = value2; value2 = value3; value3 = swap; } if (value4 > value5) { swap = value4; value4 = value5; value5 = swap; } result -= value2; result = result * ((value5 - value4) / (value3 - value2)); result += value4; result = Math.min(value5, result); result = Math.max(value4, result); return Math.round(result); }, syntax: { js: [], py: [] }, }, }; }; module.exports = Entry.krc; ================================================ FILE: src/playground/blocks/hardware/block_LineCoding.js ================================================ 'use strict'; let LmotorSpeed = 0; let RmotorSpeed = 0; let LineNum = 20; let WheelNum = 18; let LineInit = 0; let LineSaveFlag = 0; let LineOneFlag = 1; const ServeAngle = [0, 0, 0, 0, 0, 0, 0, 0]; const OutPort = [0, 0, 0, 0, 0, 0, 0, 0]; Entry.LineCoding = { id: '3D.1', name: 'LineCoding', url: 'http://www.ssmake.co.kr/', imageName: 'LineCoding.png', title: { ko: '라인코딩', en: 'LineCoding', }, setZero: () => { // 하드웨어 초기화 로직 /* if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue = { GET: {}, SET: {}, }; } else { const keySet = Object.keys(Entry.hw.sendQueue.SET); keySet.forEach((key) => { Entry.hw.sendQueue.SET[parseInt(key)].data = 0; Entry.hw.sendQueue.SET[parseInt(key)].time = new Date().getTime(); }); } */ Entry.hw.sendQueue = { GET: {}, SET: {}, }; Entry.hw.sendQueue.SET[9] = { type: Entry.LineCoding.sensorTypes.LINE_EASY, data: 0, time: new Date().getTime(), }; Entry.hw.update(); LmotorSpeed = 0; RmotorSpeed = 0; LineNum = 20; LineInit = 0; LineSaveFlag = 0; LineOneFlag = 1; ServeAngle[0] = 0; ServeAngle[1] = 0; ServeAngle[2] = 0; ServeAngle[3] = 0; ServeAngle[4] = 0; ServeAngle[5] = 0; ServeAngle[6] = 0; ServeAngle[7] = 0; OutPort[0] = 0; OutPort[1] = 0; OutPort[2] = 0; OutPort[3] = 0; OutPort[4] = 0; OutPort[5] = 0; OutPort[6] = 0; OutPort[7] = 0; }, Static: { // LineCoding_BLOCK_COLOR: '#00979D', // gray(#848484) // LineCoding_ARROW_COLOR_HW: '#00979D', }, sensorTypes: { ALIVE: 0, DIGITAL: 1, ANALOG: 2, BUZZER: 3, TONE: 34, USONIC: 7, USONIC_SET: 33, LCD_SET: 40, LINE_EASY: 51, LINE_FW_SPEED: 55, LINE_TURN_SPEED: 56, LINE_CROSS_TIME: 57, LINE_EASY_MOTOR: 58, LINE_RESTART: 60, LINE_DELAY: 61, LINE_LINE: 62, LINE_TURN: 63, LINE_MOTOR: 64, LINE_BMOTOR: 65, LINE_BWMOTOR: 66, LINE_WHEEL: 67, LINE_SERVO: 70, LINE_SSERVO: 71, LINE_PORT: 72, LINE_BUZZER: 73, LINE_LED: 74, LINE_LINEDELAY: 75, LINE_SLINE: 76, LINE_LINEFIND: 77, LINE_LINELOST: 78, LINE_CLINE: 79, LINE_CLINE2: 80, LINE_FFMOTOR: 90, LINE_BBMOTOR: 91, LINE_MOTORSTOP: 92, LINE_PLINE: 93, LINE_START: 94, LINE_TIMER: 95, LINE_COLOR: 96, LINE_ABSH: 97, LINE_BLACKFORWARDF: 98, LINE_REMOT: 100, }, toneTable: { '0': 0, C: 1, CS: 2, D: 3, DS: 4, E: 5, F: 6, FS: 7, G: 8, GS: 9, A: 10, AS: 11, B: 12, }, toneMap: { '1': [7644, 3821, 1910, 955, 477], '2': [7214, 3607, 1803, 901, 450], '3': [6810, 3404, 1702, 850, 425], '4': [6247, 3213, 1606, 803, 401], '5': [6066, 3033, 1516, 757, 378], '6': [5726, 2862, 1431, 715, 357], '7': [5404, 2702, 1350, 675, 337], '8': [5101, 2550, 1275, 637, 318], '9': [4815, 2407, 1203, 601, 300], '10': [4544, 2272, 1135, 567, 283], '11': [4289, 2144, 1072, 535, 267], '12': [4049, 2024, 1011, 505, 252], }, BlockState: {}, }; Entry.LineCoding.blockMenuBlocks = [ /// 하드웨어 블록 등록 , 여기에 등록된 블록이 순서대로 나열되며 설정한 이름으로 화면에 보임 'LineCodingStart', 'LineCodingStop', 'LineCodingLineEasy', 'LineCodingEasySet', 'LineCodingEasyTimeSet', 'LineCodingEasyMotor', 'LineCodingRestart', 'LineCodingDelay', 'LineCodingLine', 'LineCodingTurn', 'LineCodingMotor', 'LineCodingBmotor', // 'LineCodingBwMotor', 'LineCodingWheel', // 'LineCodingSServo', // 'LineCodingBmotor', /// 디지털 포트 제어 'LineCodingGetDgitalValue', 'LineCodingGetAnalogValue', 'LineCodingDigitalOnOff', 'LineCodingServo', 'LineCodingMelody', // 'LineCodingSline', // 'LineCodingLineFind', // 'LineCodingLineLost', // 'LineCodingCline', // 'LineCodingCline2', // 'LineCodingPline', // 'LineCodingStart', // 'LineCodingTimer', // 'LineCodingLineColor', // 'LineCodingMotorStop', // DC모터 정지하기 // 서보모터 제어 //디지탈 입력 // 아날로그 입력 // 'LineCodingGetUsonicValue', //초음파센서 읽기 'LineCodingSetLcdString', // 'LineCodingSetLcdBacklight', 'LineCodingSetLcdClear', 'LineCodingGetAnalogMapping', 'LineCodingRemotRx', 'LineCodingLineDelay', 'LineCodingBlackForwardF', 'LineCodingBuzzerOnOff', 'LineCodingLED', 'LineCodingABSH', 'LineCodingFFmotor', 'LineCodingBBmotor', 'LineCodingMotorStop', ]; Entry.LineCoding.setLanguage = function() { // 블록 이름 번역 return { ko: { template: { LineCodingStart: '%1 저장하기 시작 %2', LineCodingStop: '라인트레이서에 저장하기 종료 %1', LineCodingLineEasy: '%1 하기 %2', LineCodingEasySet: '%1 %2 로 정하기 %3', LineCodingEasyTimeSet: '교차로에서 %1mS 더 직진하도록 설정하기 %2', LineCodingEasyMotor: '모터 %1 방향으로 %2mS 이동하기 %3', LineCodingRestart: 'restart(%1); %2', LineCodingDelay: 'delay(%1); %2', LineCodingLine: 'line(%1, %2, %3); %4', LineCodingTurn: '%1(%2, %3); %4', LineCodingMotor: 'motor(%1, %2, %3); %4', LineCodingBmotor: '%1(%2, %3, %4); %5', LineCodingWheel: 'wheel(%1, %2); %3', LineCodingServo: 'sservo(%1, %2, %3); %4', LineCodingDigitalOnOff: '디지털 %1 포트 %2 설정하기 %3', LineCodingMelody: '스피커 %1 옥타브 %2음 %3 초 연주하기 %4', LineCodingMotorStop: 'DC모터 정지하기 %1', LineCodingBlackForwardF: 'blackforwardf(%1,%2,%3,%4,%5); %6', LineCodingGetDgitalValue: '디지털 %1 포트 읽기', LineCodingGetAnalogValue: '아날로그 %1 포트 읽기', LineCodingGetAnalogMapping: ' %1 값 %2 ~ %3 에서 %4 ~ %5 으로 변환값', LineCodingRemotRx: ' 조종기버튼 %1, %2 눌리면 실행하는 코드 %3', LineCodingLineDelay: 'linedelay(%1, %2, %3); %4', LineCodingABSH: 'lineabsh(%1, %2, %3, %4, %5, %6); %7', LineCodingBuzzerOnOff: 'buzzer(%1, %2, %3); %4', LineCodingLED: 'led(%1, %2, %3, %4); %5', LineCodingSetLcdString: 'lcd 세로%1줄, 가로%2줄 에 %3 표시하기 %4', LineCodingSetLcdClear: 'lcd 지우기 %1', LineCodingFFmotor: 'ffmotor(%1, %2); %3', LineCodingBBmotor: 'bbmotor(%1, %2); %3', LineCodingMotorStop: 'motorstop(%1, %2); %3', }, Blocks: { OnBlock: '켜짐(HIGH, 5V)', OffBlock: '꺼짐(LOW, 0V)', AllOnBlock: '모두 켜짐', AllOffBlock: '모두 꺼짐', BacklightOn: '켜기', BacklightOff: '끄기', lineForward: '직진', Left: '좌회전', Right: '우회전', LineBack: '후진', ForwardSpeed: '직진속도', TurnSpeed: '회전속도', ForwardOverTime: '교차로 직진시간', Tracer: '라인트레이서', RemotBit: '조종기(비트수신)', RemotPs2: '조종기(PS2)', }, }, en: { template: { LineCodingStart: 'Start saving to the %1 %2', LineCodingStop: 'End saving to lint racer %1', LineCodingLineEasy: 'Go %1 %2', LineCodingEasySet: 'To set the %1 %2 %3', LineCodingEasyTimeSet: 'Set %1mS to go straight at the intersection %2', LineCodingEasyMotor: 'Moving %2mS in the direction of motor %1 %3', LineCodingRestart: 'restart(%1); %2 %2', LineCodingDelay: 'delay(%1); %2', LineCodingLine: 'line(%1, %2, %3); %4', LineCodingTurn: '%1(%2, %3); %4', LineCodingMotor: 'motor(%1, %2, %3); %4', LineCodingBmotor: '%1(%2, %3, %4); %5', LineCodingWheel: 'wheel(%1, %2); %3', LineCodingServo: 'sservo(%1, %2, %3); %4', LineCodingDigitalOnOff: 'Setting up digital %1 port %2 %3', LineCodingMelody: 'Play speaker %1 octave %2 sound %3 seconds %4', LineCodingMotorStop: 'Stop DC Motor %1', LineCodingBlackForwardF: 'blackforwardf(%1,%2,%3,%4);%5', LineCodingGetDgitalValue: 'Read digital %1 port', LineCodingGetAnalogValue: 'Analog %1 port read', LineCodingGetAnalogMapping: '%1 value %2 to %3 ; to %4 to %5 conversion value ', LineCodingRemotRx: ' Code that runs when controller button %1, %2 is pressed %3', LineCodingLineDelay: 'linedelay(%1, %2, %3); %4', LineCodingABSH: 'lineabsh(%1, %2, %3, %4, %5, %6); %7', LineCodingBuzzerOnOff: 'buzzer(%1, %2, %3); %4', LineCodingLED: 'led(%1, %2, %3, %4); %5', LineCodingSetLcdString: 'lcd Display %3 on line %1 and line %2 %4', LineCodingSetLcdClear: 'Clear lcd %1', LineCodingFFmotor: 'ffmotor(%1, %2); %3', LineCodingBBmotor: 'bbmotor(%1, %2); %3', LineCodingMotorStop: 'motorstop(%1, %2); %3', }, Blocks: { OnBlock: 'On(HIGH, 5V)', OffBlock: 'Off(LOW, 0V)', AllOnBlock: 'ALL ON', AllOffBlock: 'ALL OFF', BacklightOn: 'ON', BacklightOff: 'OFF', lineForward: 'FORWARD', Left: 'LEFT', Right: 'RIGHT', LineBack: 'BACK', ForwardSpeed: 'driving speed', TurnSpeed: 'rotational speed', ForwardOverTime: 'Intersection Driving Time', Tracer: 'Line Tracer', RemotBit: 'Remot(bit)', RemotPs2: 'Remot(PS2)', }, }, }; }; Entry.LineCoding.getBlocks = function() { return { LineCodingDigitalPortOnOffList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.OnBlock, '1'], [Lang.Blocks.OffBlock, '0'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, LineCodingBacklightOnoffList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.BacklightOn, '0'], [Lang.Blocks.BacklightOff, '1'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, LineCodingEasylineList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.lineForward, '3'], [Lang.Blocks.Left, '4'], [Lang.Blocks.Right, '5'], ], value: '3', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, LineCodingEasyMotorList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.lineForward, '3'], [Lang.Blocks.Left, '4'], [Lang.Blocks.Right, '5'], [Lang.Blocks.LineBack, '6'], ], value: '3', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, LineCodingStartList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.Tracer, '1'], [Lang.Blocks.RemotBit, '10'], [Lang.Blocks.RemotPs2, '11'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, LineCodingEasySetList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.ForwardSpeed, '55'], [Lang.Blocks.TurnSpeed, '56'], ], value: '55', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, LineCodingCrossroadList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['T1', '21'], ['L1', '1'], ['R1', '4'], ['LR1', '7'], ['SL1', '11'], ['SR1', '14'], ], value: '21', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, LineCodingRemotKeyList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['NONE', '0'], ['L_UP', '1'], ['L_LEFT', '2'], ['L_RIGHT', '3'], ['L_DN', '4'], ['L1', '5'], ['L2', '6'], ['R_UP', '7'], ['R_LEFT', '8'], ['R_RIGHT', '9'], ['R_DN', '10'], ['R1', '11'], ['R2', '12'], ['START', '13'], ['SELECT', '14'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, LineCodingOctaveList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['3', '0'], ['4', '1'], ['5', '2'], ['6', '3'], ['7', '4'], ], value: '2', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { OCTAVE: 0, }, func(sprite, script) { return script.getField('OCTAVE'); }, }, LineCodingToneList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.silent, '0'], [Lang.Blocks.do_name, 'C'], [Lang.Blocks.do_sharp_name, 'CS'], [Lang.Blocks.re_name, 'D'], [Lang.Blocks.re_sharp_name, 'DS'], [Lang.Blocks.mi_name, 'E'], [Lang.Blocks.fa_name, 'F'], [Lang.Blocks.fa_sharp_name, 'FS'], [Lang.Blocks.sol_name, 'G'], [Lang.Blocks.sol_sharp_name, 'GS'], [Lang.Blocks.la_name, 'A'], [Lang.Blocks.la_sharp_name, 'AS'], [Lang.Blocks.si_name, 'B'], ], value: 'C', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { NOTE: 0, }, func(sprite, script) { return script.getField('NOTE'); }, }, LineCodingTurnList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['lt1', '1'], ['rt8', '8'], ['lt2', '2'], ['rt7', '7'], ['lt3', '3'], ['rt6', '6'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, LineCodingMotorList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['B Motor', '1'], ['BW Motor', '2'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, LineCodingLineSensortList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['S1', '1'], ['S2', '2'], ['S3', '4'], ['S4', '8'], ['S5', '16'], ['S6', '32'], ['S7', '64'], ['S8', '128'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getStringField('PORT'); }, }, LineCodingSensorNumtList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['S1', '0'], ['S2', '1'], ['S3', '2'], ['S4', '3'], ['S5', '4'], ['S6', '5'], ['S7', '6'], ['S8', '7'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getStringField('PORT'); }, }, LineCodingDigitalPortList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['IN1', '1'], ['IN2', '2'], ['IN3', '3'], ['IN4', '4'], ['IN5', '5'], ['IN6', '6'], ['IN7', '7'], ['IN8', '8'], ['FW1', '9'], ['FW2', '10'], ['FW3', '11'], ['FW4', '12'], ['FW5', '13'], ['FW6', '14'], ['FW7', '15'], ['FW8', '16'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getStringField('PORT'); }, }, LineCodingServoPortList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['OUT1', '1'], ['OUT2', '2'], ['OUT3', '3'], ['OUT4', '4'], ['OUT5', '5'], ['OUT6', '6'], ['OUT7', '7'], ['OUT8', '8'], ], value: '1', // 기본 표시값 fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getStringField('PORT'); }, }, LineCodingAllOnOffList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.AllOffBlock, '2'], [Lang.Blocks.AllOnBlock, '3'], ], value: '2', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { VALUE: 0, }, func(sprite, script) { return script.getField('VALUE'); }, }, LineCodingAnalogPortList: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['IN1', '1'], ['IN2', '2'], ['IN3', '3'], ['IN4', '4'], ['IN5', '5'], ['IN6', '6'], ['IN7', '7'], ['IN8', '8'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, // 1. 저장 시작하기 LineCodingStart: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'LineCodingStartList', }, null, ], type: 'LineCodingStart', }, paramsKeyMap: { STAY: 0, }, class: 'LineCoding_EASY', isNotFor: ['LineCoding'], func: (sprite, script) => { ++LineNum; LineSaveFlag = 1; // 1 시작 // delay(100); const value = script.getNumberValue('STAY'); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_EASY, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [] }, }, // 2. 저장 종료 LineCodingStop: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [null], type: 'LineCodingStop', }, paramsKeyMap: { //PORT: 0, }, class: 'LineCoding_EASY', isNotFor: ['LineCoding'], func: (sprite, script) => { ++LineNum; LineSaveFlag = 0; // 2 종료 if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[400] = { type: Entry.LineCoding.sensorTypes.LINE_EASY, data: 2, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [] }, }, // 3. 쉬운주행 LineCodingLineEasy: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'LineCodingEasylineList', }, null, ], type: 'LineCodingLineEasy', }, paramsKeyMap: { VALUE: 0, }, class: 'LineCoding_EASY', isNotFor: ['LineCoding'], func: (sprite, script) => { const value = script.getNumberValue('VALUE'); if (LineOneFlag == 1) { if (LineSaveFlag == 1) { ++LineNum; } LineInit = Entry.hw.portData.DIGITAL[0]; if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_EASY, data: value, time: new Date().getTime(), }; LineOneFlag = 0; } if (Entry.hw.portData.DIGITAL[0] == LineInit && LineSaveFlag == 0) { return script; } else { LineOneFlag = 1; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 4. 쉬운주행 설정 LineCodingEasySet: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'LineCodingEasySetList', }, { type: 'number', params: ['20'], }, null, ], type: 'LineCodingEasySet', }, paramsKeyMap: { PORT: 0, NUM: 1, }, class: 'LineCoding_EASY', isNotFor: ['LineCoding'], func: (sprite, script) => { const port = script.getNumberValue('PORT', script); const num = script.getNumberValue('NUM', script); if (!script.isStart) { if (LineSaveFlag == 1) { ++LineNum; } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } script.isStart = true; script.timeFlag = 1; if (port == 55) { Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_FW_SPEED, data: [num], time: new Date().getTime(), }; } else { Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_TURN_SPEED, data: [num], time: new Date().getTime(), }; } setTimeout(() => { script.timeFlag = 0; }, 0.1); return script; } else if (script.timeFlag === 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 직진시간설정 LineCodingEasyTimeSet: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, null, ], type: 'LineCodingEasyTimeSet', }, paramsKeyMap: { TIME: 0, }, class: 'LineCoding_EASY', isNotFor: ['LineCoding'], func: (sprite, script) => { let time2 = script.getNumberValue('TIME'); if (!script.isStart) { if (LineSaveFlag == 1) { ++LineNum; } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } time2 = Math.min(2500, time2); time2 = Math.max(0, time2); script.isStart = true; script.timeFlag = 1; Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_CROSS_TIME, data: { time: time2, }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, 0.1); return script; } else if (script.timeFlag === 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 5. 쉬운 모터이동 LineCodingEasyMotor: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'LineCodingEasyMotorList', }, { type: 'number', params: ['0'], }, null, ], type: 'LineCodingEasyMotor', }, paramsKeyMap: { DIRECTION: 0, TIME: 1, }, class: 'LineCoding_EASY', isNotFor: ['LineCoding'], func: (sprite, script) => { let direction2 = script.getNumberValue('DIRECTION', script); let time2 = script.getNumberValue('TIME', script); if (LineSaveFlag == 1) { ++LineNum; } if (LineOneFlag == 1) { time2 = Math.min(10000, time2); time2 = Math.max(0, time2); direction2 = Math.min(6, direction2); direction2 = Math.max(3, direction2); LineInit = Entry.hw.portData.DIGITAL[0]; if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_EASY_MOTOR, data: { direction: direction2, time: time2, }, time: new Date().getTime(), }; LineOneFlag = 0; } if (Entry.hw.portData.DIGITAL[0] == LineInit && LineSaveFlag == 0) { return script; } else { LineOneFlag = 1; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 리스타트 LineCodingRestart: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['1'], }, null, ], type: 'LineCodingRestart', }, paramsKeyMap: { NUM: 0, }, class: 'LineCoding_LINE1', isNotFor: ['LineCoding'], func: (sprite, script) => { const num = script.getNumberValue('NUM', script); if (LineSaveFlag == 1) { ++LineNum; } if (LineOneFlag == 1) { LineInit = Entry.hw.portData.DIGITAL[0]; if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_RESTART, data: [num], time: new Date().getTime(), }; LineOneFlag = 0; } if (Entry.hw.portData.DIGITAL[0] == LineInit && LineSaveFlag == 0) { return script; } else { LineOneFlag = 1; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 딜레이 LineCodingDelay: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, null, ], type: 'LineCodingDelay', }, paramsKeyMap: { TIME: 0, }, class: 'LineCoding_LINE1', isNotFor: ['LineCoding'], func: (sprite, script) => { let time2 = script.getNumberValue('TIME', script); if (LineSaveFlag == 1) { ++LineNum; } if (LineOneFlag == 1) { time2 = Math.min(10000, time2); time2 = Math.max(0, time2); LineInit = Entry.hw.portData.DIGITAL[0]; if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_DELAY, data: { time: time2, }, time: new Date().getTime(), }; LineOneFlag = 0; } if (Entry.hw.portData.DIGITAL[0] == LineInit && LineSaveFlag == 0) { return script; } else { LineOneFlag = 1; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 5. line LineCodingLine: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'LineCodingCrossroadList', }, { type: 'number', params: ['20'], }, { type: 'number', params: ['0'], }, null, ], type: 'LineCodingLine', }, paramsKeyMap: { CROSS: 0, SPEED: 1, TIME: 2, }, class: 'LineCoding_LINE1', isNotFor: ['LineCoding'], func: (sprite, script) => { const cross2 = script.getNumberValue('CROSS', script); let speed2 = script.getNumberValue('SPEED', script); let time2 = script.getNumberValue('TIME', script); if (LineSaveFlag == 1) { ++LineNum; } if (LineOneFlag == 1) { LineInit = Entry.hw.portData.DIGITAL[0]; time2 = Math.min(10000, time2); time2 = Math.max(-10000, time2); speed2 = Math.min(20, speed2); speed2 = Math.max(0, speed2); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_LINE, data: { cross: cross2, speed: speed2, time: time2, }, time: new Date().getTime(), }; LineOneFlag = 0; } if (Entry.hw.portData.DIGITAL[0] == LineInit && LineSaveFlag == 0) { return script; } else { LineOneFlag = 1; return script.callReturn(); } //return script.callReturn(); }, syntax: { js: [], py: [] }, }, // turn lt rt LineCodingTurn: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'LineCodingTurnList', }, { type: 'number', params: ['20'], }, { type: 'number', params: ['0'], }, null, ], type: 'LineCodingTurn', }, paramsKeyMap: { CROSS: 0, SPEED: 1, TIME: 2, }, class: 'LineCoding_LINE1', isNotFor: ['LineCoding'], func: (sprite, script) => { let cross2 = script.getNumberValue('CROSS', script); let speed2 = script.getNumberValue('SPEED', script); let time2 = script.getNumberValue('TIME', script); if (LineSaveFlag == 1) { ++LineNum; } if (LineOneFlag == 1) { LineInit = Entry.hw.portData.DIGITAL[0]; cross2 = Math.min(8, cross2); cross2 = Math.max(1, cross2); time2 = Math.min(1000, time2); time2 = Math.max(0, time2); speed2 = Math.min(20, speed2); speed2 = Math.max(0, speed2); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_TURN, data: { cross: cross2, speed: speed2, time: time2, }, time: new Date().getTime(), }; LineOneFlag = 0; } if (Entry.hw.portData.DIGITAL[0] == LineInit && LineSaveFlag == 0) { return script; } else { LineOneFlag = 1; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // motor LineCodingMotor: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['20'], }, { type: 'number', params: ['20'], }, { type: 'number', params: ['0'], }, null, ], type: 'LineCodingMotor', }, paramsKeyMap: { LSPEED: 0, RSPEED: 1, TIME: 2, }, class: 'LineCoding_LINE1', isNotFor: ['LineCoding'], func: (sprite, script) => { let cross2 = script.getNumberValue('LSPEED', script); let speed2 = script.getNumberValue('RSPEED', script); let time2 = script.getNumberValue('TIME', script); if (LineSaveFlag == 1) { ++LineNum; } if (LineOneFlag == 1) { LineInit = Entry.hw.portData.DIGITAL[0]; time2 = Math.min(1000, time2); time2 = Math.max(0, time2); cross2 = Math.min(20, cross2); cross2 = Math.max(-20, cross2); speed2 = Math.min(20, speed2); speed2 = Math.max(-20, speed2); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_MOTOR, data: { cross: cross2, speed: speed2, time: time2, }, time: new Date().getTime(), }; LineOneFlag = 0; } if (Entry.hw.portData.DIGITAL[0] == LineInit && LineSaveFlag == 0) { return script; } else { LineOneFlag = 1; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // bmotor bwmotor LineCodingBmotor: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'LineCodingMotorList', }, { type: 'number', params: ['20'], }, { type: 'number', params: ['20'], }, { type: 'LineCodingLineSensortList', }, null, ], type: 'LineCodingBmotor', }, paramsKeyMap: { MODE: 0, LSPEED: 1, RSPEED: 2, SENSOR: 3, }, class: 'LineCoding_LINE1', isNotFor: ['LineCoding'], func: (sprite, script) => { let mode2 = script.getNumberValue('MODE', script); let lspeed2 = script.getNumberValue('LSPEED', script); let rspeed2 = script.getNumberValue('RSPEED', script); let sensor2 = script.getNumberValue('SENSOR', script); if (LineSaveFlag == 1) { ++LineNum; } if (LineOneFlag == 1) { LineInit = Entry.hw.portData.DIGITAL[0]; mode2 = Math.min(2, mode2); mode2 = Math.max(1, mode2); lspeed2 = Math.min(20, lspeed2); lspeed2 = Math.max(-20, lspeed2); rspeed2 = Math.min(20, rspeed2); rspeed2 = Math.max(-20, rspeed2); sensor2 = Math.min(8, sensor2); sensor2 = Math.max(1, sensor2); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } if (mode2 == 1) { Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_BMOTOR, data: { mode: mode2, lspeed: lspeed2, rspeed: rspeed2, sensor: sensor2, }, time: new Date().getTime(), }; } else { Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_BWMOTOR, data: { mode: mode2, lspeed: lspeed2, rspeed: rspeed2, sensor: sensor2, }, time: new Date().getTime(), }; } LineOneFlag = 0; } if (Entry.hw.portData.DIGITAL[0] == LineInit && LineSaveFlag == 0) { return script; } else { LineOneFlag = 1; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, //DC 모터 속도 정하기 wheel LineCodingWheel: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, null, ], type: 'LineCodingWheel', }, paramsKeyMap: { LSPEED: 0, RSPEED: 1, }, class: 'LineCoding_LINE1', isNotFor: ['LineCoding'], func(sprite, script) { let rspeed2 = script.getNumberValue('RSPEED', script); let lspeed2 = script.getNumberValue('LSPEED', script); lspeed2 = Math.min(20, lspeed2); lspeed2 = Math.max(-20, lspeed2); rspeed2 = Math.min(20, rspeed2); rspeed2 = Math.max(-20, rspeed2); if (!(LmotorSpeed === lspeed2) || !(RmotorSpeed === rspeed2) || LineSaveFlag == 1) { if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } if (LineSaveFlag == 1) { ++LineNum; WheelNum = LineNum; } else { if (WheelNum == 18) { WheelNum = 19; } else { WheelNum = 18; } } Entry.hw.sendQueue.SET[parseInt(WheelNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_WHEEL, data: { lspeed: lspeed2, rspeed: rspeed2, }, time: new Date().getTime(), }; LmotorSpeed = lspeed2; RmotorSpeed = rspeed2; return script.callReturn(); } else { return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 5. 서보 모터 각도 설정하기 LineCodingServo: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'LineCodingServoPortList', }, { type: 'number', params: ['1'], }, { type: 'number', params: ['0'], }, null, ], type: 'LineCodingServo', }, paramsKeyMap: { PORT: 0, ANGLE: 1, SPEED: 2, }, class: 'LineCoding_LINE2', isNotFor: ['LineCoding'], func: (sprite, script) => { const sport2 = script.getNumberValue('PORT', script); let angle2 = script.getNumberValue('ANGLE', script); let speed2 = script.getNumberValue('SPEED', script); if (LineSaveFlag == 1) { ++LineNum; } // port += 2; // var mode = 1; angle2 = Math.min(180, angle2); angle2 = Math.max(0, angle2); speed2 = Math.min(100, speed2); speed2 = Math.max(0, speed2); //speed *= speed * 255; //angle += 1; if (ServeAngle[sport2 - 1] != angle2) { ServeAngle[sport2 - 1] = angle2; if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } if (LineSaveFlag == 1) { Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_SERVO, data: { sport: sport2, angle: angle2, speed: speed2, }, time: new Date().getTime(), }; } else { Entry.hw.sendQueue.SET[parseInt(sport2, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_SERVO, data: { sport: sport2, angle: angle2, speed: speed2, }, time: new Date().getTime(), }; } return script.callReturn(); } else { return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 디지털 출력 LineCodingDigitalOnOff: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'LineCodingServoPortList', }, { type: 'LineCodingDigitalPortOnOffList', }, null, ], type: 'LineCodingDigitalOnOff', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'LineCoding_LINE2', // 블록을 묶는 그룹 이름. 이 값이 다르면 사이에 가로줄이 생깁니다 isNotFor: ['LineCoding'], func: (sprite, script) => { const dport2 = script.getNumberValue('PORT'); const value2 = script.getNumberValue('VALUE'); if (OutPort[dport2 - 1] != value2) { OutPort[dport2 - 1] = value2; if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } if (LineSaveFlag == 1) { ++LineNum; Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { //18 type: Entry.LineCoding.sensorTypes.LINE_PORT, /// 출력 디바이스 data: { dport: dport2, value: value2, }, time: new Date().getTime(), }; } else { Entry.hw.sendQueue.SET[parseInt(dport2, 10)] = { //18 type: Entry.LineCoding.sensorTypes.LINE_PORT, /// 출력 디바이스 data: { dport: dport2, value: value2, }, time: new Date().getTime(), }; } return script.callReturn(); } else { return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 스피커 멜로디 LineCodingMelody: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'LineCodingOctaveList', }, { type: 'LineCodingToneList', }, { type: 'text', params: ['0.25'], }, null, ], type: 'LineCodingMelody', }, paramsKeyMap: { OCTAVE: 0, NOTE: 1, DURATION: 2, }, class: 'LineCoding_LINE2', isNotFor: ['LineCoding'], func: (sprite, script) => { let duration2 = script.getNumberValue('DURATION'); let octave = script.getNumberValue('OCTAVE'); let value2 = 0; if (LineSaveFlag == 1) { ++LineNum; } if (!script.isStart) { let note = script.getValue('NOTE'); if (!Entry.Utils.isNumber(note)) { note = Entry.LineCoding.toneTable[note]; } if (note < 0) { note = 0; } else if (note > 12) { note = 12; } if (duration2 < 0) { duration2 = 0; } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } if (duration2 === 0) { // 음 길이가 0 이면 Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; return script.callReturn(); } if (octave < 0) { octave = 0; } else if (octave > 4) { octave = 4; } if (note != 0) { value2 = Entry.LineCoding.toneMap[note][octave]; } if (duration2 > 30) { duration2 = 30; } duration2 = duration2 * 1000; script.isStart = true; // 출력 시작 플래그 셋 script.timeFlag = 1; // 시간플래그 셋 Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.TONE, data: { value: value2, duration: duration2, }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, duration2 + 32); return script; } else if (script.timeFlag === 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 11. 디지털입력 LineCodingGetDgitalValue: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', //basic_boolean_field statements: [], template: Lang.template.LineCodingGetDgitalValue, params: [ { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'LineCodingDigitalPortList', }, ], type: 'LineCodingGetDgitalValue', }, paramsKeyMap: { PORT: 0, }, class: 'LineCoding_LINE3', isNotFor: ['LineCoding'], func: (sprite, script) => { const port2 = script.getNumberValue('PORT'); //const DIGITAL = Entry.hw.portData.DIGITAL; if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } Entry.hw.sendQueue.GET[Entry.LineCoding.sensorTypes.DIGITAL] = { port: port2, time: new Date().getTime(), }; return Entry.hw.portData.DIGITAL[parseInt(port2, 10)]; }, syntax: { js: [], py: [] }, }, // 12. 아날로그 읽기 LineCodingGetAnalogValue: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', template: Lang.template.LineCodingGetAnalogValue, statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'LineCodingAnalogPortList', }, ], type: 'LineCodingGetAnalogValue', }, paramsKeyMap: { PORT: 0, }, class: 'LineCoding_LINE3', isNotFor: ['LineCoding'], func: (sprite, script) => { const BtnIndex = script.getNumberValue('PORT'); const ANALOG = Entry.hw.portData.ANALOG; return ANALOG[parseInt(BtnIndex, 10)]; }, syntax: { js: [], py: [] }, }, // LCD글자출력 LineCodingSetLcdString: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, { type: 'text', params: ['Hi, LineCoding'], }, null, ], type: 'LineCodingSetLcdString', }, paramsKeyMap: { COLUMN: 0, LINE: 1, STRING: 2, }, class: 'LineCoding_LINE3', isNotFor: ['LineCoding'], func: (sprite, script) => { // var sq = Entry.hw.sendQueue; const line2 = script.getValue('LINE', script); const column2 = script.getValue('COLUMN', script); const string = script.getValue('STRING', script); let text = []; let buf; if (!script.isStart) { if (typeof string === 'string') { for (var i = 0; i < string.length; i++) { buf = Entry.memaker.toByte(string[parseInt(i, 10)]); text[parseInt(i, 10)] = buf; } } else { text[0] = string; } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } script.isStart = true; script.timeFlag = 1; //var fps = Entry.FPS || 60; // var timeValue = 60 / fps * 50; Entry.hw.sendQueue.SET[3] = { type: Entry.LineCoding.sensorTypes.LCD_SET, data: { line: line2, column: column2, text0: text[0], text1: text[1], text2: text[2], text3: text[3], text4: text[4], text5: text[5], text6: text[6], text7: text[7], text8: text[8], text9: text[9], text10: text[10], text11: text[11], text12: text[12], text13: text[13], text14: text[14], text15: text[15], text16: text[16], text17: text[17], text18: text[18], text19: text[19], }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, 0); return script; } else if (script.timeFlag === 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = true; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // LCD 지우기 LineCodingSetLcdClear: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [null], type: 'LineCodingSetLcdClear', }, paramsKeyMap: { }, class: 'LineCoding_LINE3', isNotFor: ['LineCoding'], func: (sprite, script) => { //var port = 0; if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[4] = { type: Entry.LineCoding.sensorTypes.LCD_SET, data: [4, 4, 4,], time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [] }, }, // mapping 값 LineCodingGetAnalogMapping: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', template: Lang.template.LineCodingGetAnalogMapping, statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['1023'], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['100'], }, ], type: 'LineCodingGetAnalogMapping', }, paramsKeyMap: { IDATA: 0, VALUE2: 1, VALUE3: 2, VALUE4: 3, VALUE5: 4, }, class: 'LineCoding_LINE5', isNotFor: ['LineCoding'], func: (sprite, script) => { let result = script.getNumberValue('IDATA', script); let value2 = script.getNumberValue('VALUE2', script); let value3 = script.getNumberValue('VALUE3', script); let value4 = script.getNumberValue('VALUE4', script); let value5 = script.getNumberValue('VALUE5', script); let swap; if (value2 > value3) { swap = value2; value2 = value3; value3 = swap; } if (value4 > value5) { swap = value4; value4 = value5; value5 = swap; } result -= value2; result = result * ((value5 - value4) / (value3 - value2)); result += value4; result = Math.min(value5, result); result = Math.max(value4, result); return Math.round(result); }, syntax: { js: [], py: [] }, }, // 조종기 수신 LineCodingRemotRx: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'LineCodingRemotKeyList', }, { type: 'LineCodingRemotKeyList', }, null, ], type: 'LineCodingRemotRx', }, paramsKeyMap: { KEY1: 0, KEY2: 1, }, class: 'LineCoding_LINE5', // 블록을 묶는 그룹 이름. 이 값이 다르면 사이에 가로줄이 생깁니다 isNotFor: ['LineCoding'], func: (sprite, script) => { const dport2 = script.getNumberValue('KEY1'); const value2 = script.getNumberValue('KEY2'); if (LineSaveFlag == 1) { ++LineNum; } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_REMOT, data: { dport: dport2, value: value2, }, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [] }, }, //. linedelay LineCodingLineDelay: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['100'], }, { type: 'number', params: ['20'], }, { type: 'number', params: ['0'], }, null, ], type: 'LineCodingLineDelay', }, paramsKeyMap: { LINETIME: 0, SPEED: 1, TIME: 2, }, class: 'LineCoding_LINE5', isNotFor: ['LineCoding'], func: (sprite, script) => { let linetime2 = script.getNumberValue('LINETIME', script); let speed2 = script.getNumberValue('SPEED', script); let time2 = script.getNumberValue('TIME', script); if (LineSaveFlag == 1) { ++LineNum; } if (LineOneFlag == 1) { LineInit = Entry.hw.portData.DIGITAL[0]; linetime2 = Math.min(10000, linetime2); linetime2 = Math.max(0, linetime2); time2 = Math.min(2550, time2); time2 = Math.max(0, time2); speed2 = Math.min(20, speed2); speed2 = Math.max(0, speed2); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_LINEDELAY, data: { linetime: linetime2, speed: speed2, time: time2, }, time: new Date().getTime(), }; LineOneFlag = 0; } if (Entry.hw.portData.DIGITAL[0] == LineInit && LineSaveFlag == 0) { return script; } else { LineOneFlag = 1; return script.callReturn(); } //return script.callReturn(); }, syntax: { js: [], py: [] }, }, //absh LineCodingABSH: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['20'], }, { type: 'number', params: ['18'], }, { type: 'number', params: ['12'], }, { type: 'number', params: ['10'], }, { type: 'number', params: ['8'], }, { type: 'number', params: ['3'], }, null, ], type: 'LineCodingABSH', }, paramsKeyMap: { ABSH1: 0, ABSH2: 1, ABSH3: 2, ABSH4: 3, ABSH5: 4, ABSH6: 5, }, class: 'LineCoding_LINE5', isNotFor: ['LineCoding'], func: (sprite, script) => { let absh1 = script.getNumberValue('ABSH1', script); let absh2 = script.getNumberValue('ABSH2', script); let absh3 = script.getNumberValue('ABSH3', script); let absh4 = script.getNumberValue('ABSH4', script); let absh5 = script.getNumberValue('ABSH5', script); let absh6 = script.getNumberValue('ABSH6', script); if (!script.isStart) { if (LineSaveFlag == 1) { ++LineNum; } absh1 = Math.min(20, absh1); absh1 = Math.max(0, absh1); absh2 = Math.min(20, absh2); absh2 = Math.max(0, absh2); absh3 = Math.min(20, absh3); absh3 = Math.max(0, absh3); absh4 = Math.min(20, absh4); absh4 = Math.max(0, absh4); absh5 = Math.min(20, absh5); absh5 = Math.max(0, absh5); absh6 = Math.min(20, absh6); absh6 = Math.max(0, absh6); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } script.isStart = true; script.timeFlag = 1; Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_ABSH, data: { absh1, absh2, absh3, absh4, absh5, absh6, }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, 0.1); return script; } else if (script.timeFlag === 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // 부저명령 LineCodingBuzzerOnOff: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'text', params: ['2'], }, { type: 'text', params: ['300'], }, { type: 'text', params: ['300'], }, null, ], type: 'LineCodingBuzzerOnOff', }, paramsKeyMap: { COUNT: 0, ONTIME: 1, OFFTIME: 2, }, class: 'LineCoding_LINE5', isNotFor: ['LineCoding'], func: (sprite, script) => { let ontime = script.getNumberValue('ONTIME'); let offtime = script.getNumberValue('OFFTIME'); let count = script.getValue('COUNT'); if (LineSaveFlag == 1) { ++LineNum; } if (LineOneFlag == 1) { ontime = Math.min(2550, ontime); ontime = Math.max(0, ontime); offtime = Math.min(2550, offtime); offtime = Math.max(0, offtime); count = Math.min(255, count); count = Math.max(0, count); LineInit = Entry.hw.portData.DIGITAL[0]; if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_BUZZER, data: { linetime: ontime, speed: count, time: offtime, }, time: new Date().getTime(), }; LineOneFlag = 0; } if (Entry.hw.portData.DIGITAL[0] == LineInit && LineSaveFlag == 0) { return script; } else { LineOneFlag = 1; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, // LED명령 LineCodingLED: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'text', params: ['2'], }, { type: 'text', params: ['300'], }, { type: 'text', params: ['300'], }, { type: 'LineCodingServoPortList', }, null, ], type: 'LineCodingLED', }, paramsKeyMap: { COUNT: 0, ONTIME: 1, OFFTIME: 2, PORT: 3, }, class: 'LineCoding_LINE5', isNotFor: ['LineCoding'], func: (sprite, script) => { let ontime2 = script.getNumberValue('ONTIME'); let offtime2 = script.getNumberValue('OFFTIME'); let count2 = script.getValue('COUNT'); let outport2 = script.getValue('PORT'); if (LineSaveFlag == 1) { ++LineNum; } if (LineOneFlag == 1) { ontime2 = Math.min(2550, ontime2); ontime2 = Math.max(0, ontime2); offtime2 = Math.min(2550, offtime2); offtime2 = Math.max(0, offtime2); count2 = Math.min(255, count2); count2 = Math.max(0, count2); outport2 = Math.min(8, outport2); outport2 = Math.max(1, outport2); LineInit = Entry.hw.portData.DIGITAL[0]; if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_LED, data: { ontime: ontime2, offtime: offtime2, count: count2, outport: outport2, }, time: new Date().getTime(), }; LineOneFlag = 0; } if (Entry.hw.portData.DIGITAL[0] == LineInit && LineSaveFlag == 0) { return script; } else { LineOneFlag = 1; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, LineCodingBlackForwardF: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'text', params: ['6'], }, { type: 'text', params: ['-4'], }, { type: 'text', params: ['3'], }, { type: 'LineCodingSensorNumtList', params: ['0'], }, { type: 'LineCodingSensorNumtList', params: ['7'], }, null, ], type: 'LineCodingBlackForwardF', }, paramsKeyMap: { SP: 0, BSP: 1, COUNT: 2, LSEN: 3, RSEN: 4, }, class: 'LineCoding_LINE5', isNotFor: ['LineCoding'], func: (sprite, script) => { let fsp2 = script.getNumberValue('SP'); let bsp2 = script.getNumberValue('BSP'); let count2 = script.getValue('COUNT'); let lsen2 = script.getValue('LSEN'); let rsen2 = script.getValue('RSEN'); if (LineSaveFlag == 1) { ++LineNum; } if (LineOneFlag == 1) { fsp2 = Math.min(20, fsp2); fsp2 = Math.max(0, fsp2); bsp2 = Math.min(20, bsp2); bsp2 = Math.max(-20, bsp2); count2 = Math.min(10, count2); count2 = Math.max(0, count2); lsen2 = Math.min(7, lsen2); lsen2 = Math.max(0, lsen2); rsen2 = Math.min(7, rsen2); rsen2 = Math.max(0, rsen2); LineInit = Entry.hw.portData.DIGITAL[0]; if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_BLACKFORWARDF, data: { fsp: fsp2, bsp: bsp2, count: count2, lsen: lsen2, rsen: rsen2, }, time: new Date().getTime(), }; LineOneFlag = 0; } if (Entry.hw.portData.DIGITAL[0] == LineInit && LineSaveFlag == 0) { return script; } else { LineOneFlag = 1; return script.callReturn(); } }, syntax: { js: [], py: [] }, }, //DC 모터 직진편차보정 ffmotor LineCodingFFmotor: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, null, ], type: 'LineCodingFFmotor', }, paramsKeyMap: { LSPEED: 0, RSPEED: 1, }, class: 'LineCoding_LINE5', isNotFor: ['LineCoding'], func(sprite, script) { let rspeed2 = script.getNumberValue('RSPEED', script); let lspeed2 = script.getNumberValue('LSPEED', script); ++LineNum; lspeed2 = Math.min(255, lspeed2); lspeed2 = Math.max(0, lspeed2); rspeed2 = Math.min(255, rspeed2); rspeed2 = Math.max(0, rspeed2); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_FFMOTOR, data: { lspeed: lspeed2, rspeed: rspeed2, }, time: new Date().getTime(), }; ++LineNum; LmotorSpeed = lspeed2; RmotorSpeed = rspeed2; return script.callReturn(); }, syntax: { js: [], py: [] }, }, //DC 모터 후진편차보정 bbmotor LineCodingBBmotor: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, null, ], type: 'LineCodingBBmotor', }, paramsKeyMap: { LSPEED: 0, RSPEED: 1, }, class: 'LineCoding_LINE5', isNotFor: ['LineCoding'], func(sprite, script) { let rspeed2 = script.getNumberValue('RSPEED', script); let lspeed2 = script.getNumberValue('LSPEED', script); ++LineNum; lspeed2 = Math.min(255, lspeed2); lspeed2 = Math.max(0, lspeed2); rspeed2 = Math.min(255, rspeed2); rspeed2 = Math.max(0, rspeed2); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_BBMOTOR, data: { lspeed: lspeed2, rspeed: rspeed2, }, time: new Date().getTime(), }; ++LineNum; LmotorSpeed = lspeed2; RmotorSpeed = rspeed2; return script.callReturn(); }, syntax: { js: [], py: [] }, }, //DC 모터 정지보정 motorstop LineCodingMotorStop: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['255'], }, { type: 'number', params: ['255'], }, null, ], type: 'LineCodingMotorStop', }, paramsKeyMap: { LSPEED: 0, RSPEED: 1, }, class: 'LineCoding_LINE5', isNotFor: ['LineCoding'], func(sprite, script) { let rspeed2 = script.getNumberValue('RSPEED', script); let lspeed2 = script.getNumberValue('LSPEED', script); lspeed2 = Math.min(255, lspeed2); lspeed2 = Math.max(0, lspeed2); rspeed2 = Math.min(255, rspeed2); rspeed2 = Math.max(0, rspeed2); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } ++LineNum; Entry.hw.sendQueue.SET[parseInt(LineNum, 10)] = { type: Entry.LineCoding.sensorTypes.LINE_MOTORSTOP, data: { lspeed: lspeed2, rspeed: rspeed2, }, time: new Date().getTime(), }; ++LineNum; LmotorSpeed = lspeed2; RmotorSpeed = rspeed2; return script.callReturn(); }, syntax: { js: [], py: [] }, }, }; }; module.exports = Entry.LineCoding; ================================================ FILE: src/playground/blocks/hardware/block_Lline.js ================================================ 'use strict'; Entry.Lline = { id: '6C.1', name: 'Lline', url: 'https://Lline.co.kr/', imageName: 'Lline.png', title: { ko: '엘라인', en: 'Lline', }, setZero() { if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue = { GET: {}, SET: {}, }; } else { const keySet = Object.keys(Entry.hw.sendQueue.SET); keySet.forEach((key) => { Entry.hw.sendQueue.SET[key].data = 0; Entry.hw.sendQueue.SET[key].time = new Date().getTime(); }); } Entry.hw.update(); }, sensorTypes: { ALIVE: 0, DIGITAL: 1, ANALOG: 2, PWM: 3, SERVO_PIN: 4, TONE: 5, PULSEIN: 6, ULTRASONIC: 7, TIMER: 8, METRIX: 9, //점찍는거 // 10은 비어있음 METRIXCLEAR: 11, METRIXROWCOLCLEAR: 12, METRIXDRAW: 13, NEOPIXEL: 14, NEOPIXELCLEAR: 15, NEOPIXELINIT: 16, NEOPIXELRAINBOW: 17, NEOPIXELEACH: 18, LCDINIT: 19, LCD_BACKLIGHT:20, LCD: 21, LCDCLEAR: 22, TEMPCHECK: 23, HUMICHECK: 24, // Stepper Motor 관련 추가 STEPPER_INIT: 25, // steps & pin 설정 STEPPER_SPEED: 26, // 속도 설정 STEPPER_STEP: 27, // 회전 STEPPER_STOP: 28, // 정지 IR: 29, // 적외선센서 COLOR_SENSOR_INIT: 30, COLOR_SENSOR: 31, DC_MOTOR_INIT: 32, DC_MOTOR_CONTROL: 33, DC_MOTOR_INIT2: 40, DC_MOTOR_CONTROL2: 41, HC06_INIT: 34, HC06_SEND: 35, HC06_RECEIVE: 36, HM10_INIT: 37, HM10_SEND: 38, HM10_RECEIVE: 39, }, toneTable: { '0': 0, C: 1, CS: 2, D: 3, DS: 4, E: 5, F: 6, FS: 7, G: 8, GS: 9, A: 10, AS: 11, B: 12, }, toneMap: { '1': [33, 65, 131, 262, 523, 1046, 2093, 4186], '2': [35, 69, 139, 277, 554, 1109, 2217, 4435], '3': [37, 73, 147, 294, 587, 1175, 2349, 4699], '4': [39, 78, 156, 311, 622, 1245, 2849, 4978], '5': [41, 82, 165, 330, 659, 1319, 2637, 5274], '6': [44, 87, 175, 349, 698, 1397, 2794, 5588], '7': [46, 92, 185, 370, 740, 1480, 2960, 5920], '8': [49, 98, 196, 392, 784, 1568, 3136, 6272], '9': [52, 104, 208, 415, 831, 1661, 3322, 6645], '10': [55, 110, 220, 440, 880, 1760, 3520, 7040], '11': [58, 117, 233, 466, 932, 1865, 3729, 7459], '12': [62, 123, 247, 494, 988, 1976, 3951, 7902], }, highList: ['high', '1', 'on'], lowList: ['low', '0', 'off'], BlockState: {}, }; Entry.Lline.setLanguage = function() { return { ko: { template: { arduino_Lline_get_analog_value: '아날로그 %1 번 센서값', arduino_Lline_get_analog_value_map: '%1 의 범위를 %2 ~ %3 에서 %4 ~ %5 로 바꾼값', arduino_Lline_get_ultrasonic_value: '울트라소닉 Trig %1 Echo %2 센서값', arduino_Lline_toggle_led: '디지털 %1 번 핀 %2 %3', arduino_Lline_digital_pwm: '디지털 %1 번 핀을 %2 (으)로 정하기 %3', arduino_Lline_set_tone: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', arduino_Lline_set_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', arduino_Lline_get_digital: '디지털 %1 번 센서값', arduino_Lline_get_temp: '온습도 센서 %1 온도 값 ', arduino_Lline_get_humi: '온습도 센서 %1 습도 값 ', arduino_Lline_set_neopixel_init: '네오픽셀 설정 (%1 핀) led %2 개를 %3 밝기로 설정하기 %4', arduino_Lline_set_neopixel: '네오픽셀 (%1 핀) RGB ( %2, %3, %4) %5', arduino_Lline_set_neopixel_each: '네오픽셀(%1 핀) LED (%2 번 쨰) RGB ( %3, %4, %5) %6', arduino_Lline_set_neopixel_rainbow: '무지개 표현하기 (%1 핀)', arduino_Lline_set_neopixel_clear: '네오픽셀 지우기 (%1 핀) %2', arduino_Lline_set_metrix: '도트매트릭스 그리기 (열 %1 - 행 %2) %3', arduino_Lline_set_metrix_draw: '도트매트릭스 그리기 %1 %2', arduino_Lline_set_metrix_rowcol_clear: '도트매트릭스 지우기 (열 %1 - 행 %2) %3', arduino_Lline_set_metrix_clear: '도트매트릭스 전체 지우기 %1', arduino_Lline_set_lcd_init: 'I2C LCD 초기화 (주소 %1, 열: 16, 행: 2) %2', arduino_Lline_lcd_backlight: 'LCD 백라이트 %1 ', arduino_Lline_lcd_row_col: 'LCD %1 행 %2 열 부터 "%3" 출력 %4', arduino_Lline_lcd_clear: 'LCD 화면 지우기 %1', // 스텝모터 관련 arduino_Lline_stepper_init: '스텝모터 핀 steps/rev: %1 PIN1: %2 PIN2: %3 PIN3: %4 PIN4: %5 설정', arduino_Lline_stepper_speed: '스텝모터 속도 %1 rpm 설정 %2', arduino_Lline_stepper_step: '스텝모터 %1 스텝 회전 %2', arduino_Lline_stepper_stop: '스텝모터 정지 %1', arduino_Lline_get_ir_value: '적외선 센서 %1 센서값', arduino_Lline_init_color_sensor: '컬러 센서 초기화 (S0: %1, S1: %2, S2: %3, S3: %4, OUT: %5, LED: %6)', arduino_Lline_get_color_rgb: '컬러 센서에서 %1 값 읽기', //블루투스 HM10 arduino_Lline_hm10_init: 'HM-10 연결 설정 TX: %1 RX: %2', arduino_Lline_hm10_send: 'HM-10 데이터 보내기 %1', arduino_Lline_hm10_receive: 'HM-10 수신 데이터', arduino_Lline_hc06_init: 'HC-06 연결 설정 TX: %1 RX: %2', arduino_Lline_hc06_send: 'HC-06 데이터 보내기 %1', arduino_Lline_hc06_receive: 'HC-06 수신 데이터', arduino_Lline_DC_motor_init: 'DC 모터A 설정 EN: %1 IN1: %2 IN2: %3', arduino_Lline_DC_motor_control: 'DC 모터A %1 속도 %2', arduino_Lline_DC_motor_init2: 'DC 모터B 설정 EN: %1 IN3: %2 IN4: %3', arduino_Lline_DC_motor_control2: 'DC 모터B %1 속도 %2', }, }, en: { template: { arduino_Lline_get_analog_value: 'Analog %1 Sensor value', arduino_Lline_get_analog_value_map: 'Map Value %1 %2 ~ %3 to %4 ~ %5', arduino_Lline_get_ultrasonic_value: 'Read ultrasonic sensor trig pin %1 echo pin %2', arduino_Lline_toggle_led: 'Digital %1 Pin %2 %3', arduino_Lline_digital_pwm: 'Digital %1 Pin %2 %3', arduino_Lline_set_tone: 'Play tone pin %1 on note %2 octave %3 beat %4 %5', arduino_Lline_set_servo: 'Set servo pin %1 angle as %2 %3', arduino_Lline_get_digital: 'Digital %1 Sensor value', arduino_Lline_get_temp: '온습도 센서 %1 온도 값 ', arduino_Lline_get_humi: '온습도 센서 %1 습도 값 ', arduino_Lline_set_neopixel_init: 'set neopixel pin: %1 led-count: %2 bright: %3 %4', arduino_Lline_set_neopixel: 'neopixel pin: %1 (R:%2 G:%3 B:%4) %5', arduino_Lline_set_neopixel_each: 'neopixel pin: %1 LED %2 RGB ( %3, %4, %5) %6', arduino_Lline_set_neopixel_rainbow: 'neopixel pin: %1 %2 %4', arduino_Lline_set_neopixel_clear: 'clear neopixel pin: %1 %2', arduino_Lline_set_metrix: '8x8 paint dot-merix (row : %1, col: %2) %3', arduino_Lline_set_metrix_draw: '8x8 paint dot-merix %1 %2', arduino_Lline_set_metrix_rowcol_clear: 'Clear dot-metrix (row : %1, col: %2) %3', arduino_Lline_set_metrix_clear: 'Clear all dot-metrix %1', arduino_Lline_set_lcd_init: 'I2C LCD 초기화 (주소 %1, 열: 16, 행: 2) %2', arduino_Lline_lcd_backlight: 'LCD 백라이트 %1 ', arduino_Lline_lcd_row_col: 'LCD %1 행 %2 열 부터 "%3" 출력 %4', arduino_Lline_lcd_clear: 'LCD 화면 지우기 %1', // Stepper motor related arduino_Lline_stepper_init: 'Setup Stepper motor pins (%1, %2, %3, %4) steps/rev: %5 %6', arduino_Lline_stepper_speed: 'Set stepper motor speed to %1 rpm %2', arduino_Lline_stepper_step: 'Rotate stepper motor %1 steps %2', arduino_Lline_stepper_stop: 'Stop stepper motor %1', arduino_Lline_get_ir_value: 'IR Sensor value from %1', arduino_Lline_init_color_sensor: 'Initialize color sensor (S0: %1, S1: %2, S2: %3, S3: %4, OUT: %5, LED: %6)', arduino_Lline_get_color_rgb: 'Read color sensor %1 value', arduino_Lline_hm10_init: 'Setup HM-10 TX: %1 RX: %2', arduino_Lline_hm10_send: 'Send HM-10 data %1', arduino_Lline_hm10_receive: 'HM-10 received data', arduino_Lline_hc06_init: 'Setup HC-06 TX: %1 RX: %2', arduino_Lline_hc06_send: 'Send HC-06 data %1', arduino_Lline_hc06_receive: 'HC-06 received data', arduino_Lline_DC_motor_init: 'Setup DC motorA EN: %1 IN1: %2 IN2: %3', arduino_Lline_DC_motor_control: 'DC motor A %1 speed %2', arduino_Lline_DC_motor_init2: 'Setup DC motorB EN: %1 IN3: %2 IN4: %3', arduino_Lline_DC_motor_control2: 'DC motor B %1 speed %2', }, }, }; }; Entry.Lline.blockMenuBlocks = [ 'arduino_Lline_get_analog_value', 'arduino_Lline_get_analog_value_map', 'arduino_Lline_get_ultrasonic_value', 'arduino_Lline_get_digital', 'arduino_Lline_toggle_led', 'arduino_Lline_digital_pwm', 'arduino_Lline_set_servo', 'arduino_Lline_set_tone', 'arduino_Lline_get_temp', 'arduino_Lline_get_humi', 'arduino_Lline_set_neopixel_init', 'arduino_Lline_set_neopixel', 'arduino_Lline_set_neopixel_each', 'arduino_Lline_set_neopixel_rainbow', 'arduino_Lline_set_neopixel_clear', 'arduino_Lline_set_metrix', 'arduino_Lline_set_metrix_draw', 'arduino_Lline_set_metrix_rowcol_clear', 'arduino_Lline_set_metrix_clear', 'arduino_Lline_set_lcd_init', 'arduino_Lline_lcd_backlight', 'arduino_Lline_lcd_row_col', 'arduino_Lline_lcd_clear', // ✅ 스텝모터 관련 블록 추가 'arduino_Lline_stepper_init', 'arduino_Lline_stepper_speed', 'arduino_Lline_stepper_step', 'arduino_Lline_stepper_stop', 'arduino_Lline_get_ir_value', 'arduino_Lline_init_color_sensor', 'arduino_Lline_get_color_rgb', 'arduino_Lline_hm10_init', 'arduino_Lline_hm10_send', 'arduino_Lline_hm10_receive', 'arduino_Lline_hc06_init', 'arduino_Lline_hc06_send', 'arduino_Lline_hc06_receive', 'arduino_Lline_DC_motor_init', 'arduino_Lline_DC_motor_control', 'arduino_Lline_DC_motor_init2', 'arduino_Lline_DC_motor_control2', ]; //region Lline 아두이노 확장모드 Entry.Lline.getBlocks = function() { return { arduino_Lline_analog_list: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['A0', '0'], ['A1', '1'], ['A2', '2'], ['A3', '3'], ['A4', '4'], ['A5', '5'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, syntax: { js: [], py: [ { syntax: '%1', blockType: 'param', textParams: [ { type: 'Dropdown', options: [ ['A0', '0'], ['A1', '1'], ['A2', '2'], ['A3', '3'], ['A4', '4'], ['A5', '5'], ], value: '0', fontSize: 11, converter: Entry.block.converters.returnStringKey, codeMap: 'Entry.CodeMap.Arduino.arduino_Lline_analog_list[0]', bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], keyOption: 'arduino_Lline_analog_list', }, ], }, }, arduino_Lline_get_analog_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ { type: 'arduino_Lline_analog_list', }, ], type: 'arduino_Lline_get_analog_value', }, paramsKeyMap: { PORT: 0, }, class: 'LlineGet', isNotFor: ['Lline'], func(sprite, script) { let port = script.getValue('PORT', script); const ANALOG = Entry.hw.portData.ANALOG; if (port[0] === 'A') { port = port.substring(1); } return ANALOG ? ANALOG[port] || 0 : 0; }, syntax: { js: [], py: [ { syntax: 'Arduino.analogRead(%1)', blockType: 'param', textParams: [ { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_get_analog_value_map: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ { type: 'arduino_Lline_get_analog_value', params: [ { type: 'arduino_Lline_analog_list', }, ], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['1023'], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['100'], }, ], type: 'arduino_Lline_get_analog_value_map', }, paramsKeyMap: { PORT: 0, VALUE2: 1, VALUE3: 2, VALUE4: 3, VALUE5: 4, }, class: 'LlineGet', isNotFor: ['Lline'], func(sprite, script) { let result = script.getValue('PORT', script); const ANALOG = Entry.hw.portData.ANALOG; let value2 = script.getNumberValue('VALUE2', script); let value3 = script.getNumberValue('VALUE3', script); let value4 = script.getNumberValue('VALUE4', script); let value5 = script.getNumberValue('VALUE5', script); const stringValue4 = script.getValue('VALUE4', script); const stringValue5 = script.getValue('VALUE5', script); let isFloat = false; if ( (Entry.Utils.isNumber(stringValue4) && stringValue4.indexOf('.') > -1) || (Entry.Utils.isNumber(stringValue5) && stringValue5.indexOf('.') > -1) ) { isFloat = true; } if (value2 > value3) { var swap = value2; value2 = value3; value3 = swap; } if (value4 > value5) { var swap = value4; value4 = value5; value5 = swap; } result -= value2; result = result * ((value5 - value4) / (value3 - value2)); result += value4; result = Math.min(value5, result); result = Math.max(value4, result); if (isFloat) { result = Math.round(result * 100) / 100; } else { result = Math.round(result); } return result; }, syntax: { js: [], py: [ { syntax: 'Arduino.map(%1, %2, %3, %4, %5)', blockType: 'param', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_get_ultrasonic_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ { type: 'arduino_get_port_number', params: ['6'], }, { type: 'arduino_get_port_number', params: ['5'], }, ], type: 'arduino_Lline_get_ultrasonic_value', }, paramsKeyMap: { PORT1: 0, PORT2: 1, }, class: 'LlineGet', isNotFor: ['Lline'], func(sprite, script) { const port1 = script.getNumberValue('PORT1', script); const port2 = script.getNumberValue('PORT2', script); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } delete Entry.hw.sendQueue.SET[port1]; delete Entry.hw.sendQueue.SET[port2]; if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } Entry.hw.sendQueue.GET[Entry.Lline.sensorTypes.ULTRASONIC] = { port: [port1, port2], time: new Date().getTime(), }; return Entry.hw.portData.ULTRASONIC || 0; }, syntax: { js: [], py: [ { syntax: 'Arduino.ultrasonicRead(%1, %2)', blockType: 'param', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_get_digital: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_boolean_field', params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ { type: 'arduino_get_port_number', params: [2], }, ], type: 'arduino_Lline_get_digital', }, paramsKeyMap: { PORT: 0, }, class: 'LlineGet', isNotFor: ['Lline'], func(sprite, script) { const { hwModule = {} } = Entry.hw; const { name } = hwModule; if (name === 'Lline' || name === 'ArduinoNano') { const port = script.getNumberValue('PORT', script); const DIGITAL = Entry.hw.portData.DIGITAL; if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } Entry.hw.sendQueue.GET[Entry.Lline.sensorTypes.DIGITAL] = { port, time: new Date().getTime(), }; return DIGITAL ? DIGITAL[port] || 0 : 0; } else { return Entry.block.arduino_get_digital_value.func(sprite, script); } }, syntax: { js: [], py: [ { syntax: 'Arduino.digitalRead(%1)', blockType: 'param', textParams: [ { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_get_digital_toggle: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Dropdown', options: [[Lang.Blocks.ARDUINO_on, 'on'], [Lang.Blocks.ARDUINO_off, 'off']], value: 'on', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { OPERATOR: 0, }, func(sprite, script) { return script.getStringField('OPERATOR'); }, syntax: { js: [], py: [ { syntax: '%1', textParams: [ { type: 'Dropdown', options: [ [Lang.Blocks.ARDUINO_on, 'on'], [Lang.Blocks.ARDUINO_off, 'off'], ], value: 'on', fontSize: 11, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, converter: Entry.block.converters.returnStringValueUpperCase, codeMap: 'Entry.CodeMap.Arduino.arduino_get_digital_toggle[0]', bgColor: EntryStatic.colorSet.block.darken.HARDWARE, }, ], keyOption: 'arduino_get_digital_toggle', }, ], }, }, arduino_Lline_toggle_led: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_get_port_number', params: [3], }, { type: 'arduino_get_digital_toggle', params: ['on'], }, null, ], type: 'arduino_Lline_toggle_led', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const port = script.getNumberValue('PORT'); let value = script.getValue('VALUE'); if (typeof value === 'string') { value = value.toLowerCase(); } if (Entry.Lline.highList.indexOf(value) > -1) { value = 255; } else if (Entry.Lline.lowList.indexOf(value) > -1) { value = 0; } else { throw new Error(); } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[port] = { type: Entry.Lline.sensorTypes.DIGITAL, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.digitalWrite(%1, %2)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_digital_pwm: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_get_pwm_port_number', }, { type: 'text', params: ['255'], }, null, ], type: 'arduino_Lline_digital_pwm', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const port = script.getNumberValue('PORT'); let value = script.getNumberValue('VALUE'); value = Math.round(value); value = Math.max(value, 0); value = Math.min(value, 255); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[port] = { type: Entry.Lline.sensorTypes.PWM, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.analogWrite(%1, %2)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_tone_list: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.silent, '0'], [Lang.Blocks.do_name, 'C'], [Lang.Blocks.do_sharp_name, 'CS'], [Lang.Blocks.re_name, 'D'], [Lang.Blocks.re_sharp_name, 'DS'], [Lang.Blocks.mi_name, 'E'], [Lang.Blocks.fa_name, 'F'], [Lang.Blocks.fa_sharp_name, 'FS'], [Lang.Blocks.sol_name, 'G'], [Lang.Blocks.sol_sharp_name, 'GS'], [Lang.Blocks.la_name, 'A'], [Lang.Blocks.la_sharp_name, 'AS'], [Lang.Blocks.si_name, 'B'], ], value: 'C', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { NOTE: 0, }, func(sprite, script) { return script.getField('NOTE'); }, syntax: { js: [], py: [ { syntax: '%1', textParams: [ { type: 'Dropdown', options: [ [Lang.Blocks.silent, '0'], [Lang.Blocks.do_name, 'C'], [Lang.Blocks.do_sharp_name, 'CS'], [Lang.Blocks.re_name, 'D'], [Lang.Blocks.re_sharp_name, 'DS'], [Lang.Blocks.mi_name, 'E'], [Lang.Blocks.fa_name, 'F'], [Lang.Blocks.fa_sharp_name, 'FS'], [Lang.Blocks.sol_name, 'G'], [Lang.Blocks.sol_sharp_name, 'GS'], [Lang.Blocks.la_name, 'A'], [Lang.Blocks.la_sharp_name, 'AS'], [Lang.Blocks.si_name, 'B'], ], value: 'C', fontSize: 11, converter: Entry.block.converters.returnStringValueUpperCase, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], keyOption: 'arduino_Lline_tone_list', }, ], }, }, arduino_Lline_tone_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'arduino_Lline_tone_list', }, ], type: 'arduino_Lline_tone_value', }, paramsKeyMap: { NOTE: 0, }, func(sprite, script) { return script.getNumberValue('NOTE'); }, syntax: { js: [], py: [ { syntax: '%1', keyOption: 'arduino_Lline_tone_value', }, ], }, }, arduino_Lline_octave_list: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ], value: '4', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { OCTAVE: 0, }, func(sprite, script) { return script.getField('OCTAVE'); }, syntax: { js: [], py: [ { syntax: '%1', keyOption: 'arduino_Lline_octave_list', }, ], }, }, arduino_Lline_set_tone: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_get_port_number', params: [3], }, { type: 'arduino_Lline_tone_list', }, { type: 'arduino_Lline_octave_list', }, { type: 'text', params: ['1'], }, null, ], type: 'arduino_Lline_set_tone', }, paramsKeyMap: { PORT: 0, NOTE: 1, OCTAVE: 2, DURATION: 3, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = script.getNumberValue('PORT', script); if (!script.isStart) { let note = script.getValue('NOTE', script); if (!Entry.Utils.isNumber(note)) { note = Entry.Lline.toneTable[note]; } if (note < 0) { note = 0; } else if (note > 12) { note = 12; } let duration = script.getNumberValue('DURATION', script); if (duration < 0) { duration = 0; } if (!sq.SET) { sq.SET = {}; } if (duration === 0) { sq.SET[port] = { type: Entry.Lline.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; return script.callReturn(); } let octave = script.getNumberValue('OCTAVE', script) - 1; if (octave < 0) { octave = 0; } else if (octave > 5) { octave = 5; } let value = 0; if (note != 0) { value = Entry.Lline.toneMap[note][octave]; } duration = duration * 1000; script.isStart = true; script.timeFlag = 1; sq.SET[port] = { type: Entry.Lline.sensorTypes.TONE, data: { value, duration, }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, duration + 32); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; sq.SET[port] = { type: Entry.Lline.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Arduino.tone(%1, %2, %3, %4)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_set_neopixel_init: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_get_port_number', params: [6], }, { type: 'number', params: ['16'], }, { type: 'number', params: ['10'], }, ], type: 'arduino_Lline_set_neopixel_init', }, paramsKeyMap: { PORT: 0, VALUE1: 1, VALUE2: 2, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = script.getNumberValue('PORT', script); let value1 = script.getNumberValue('VALUE1', script); let value2 = script.getNumberValue('VALUE2', script); if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } script.isStart = true; script.timeFlag = 1; var fps = Entry.FPS || 60; var timeValue = (60 / fps) * 50; sq.SET[port] = { type: Entry.Lline.sensorTypes.NEOPIXELINIT, data:{value1,value2}, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, timeValue); return script; }else if (script.timeFlag == 1) { return script; }else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Arduino.neopixel_init(%1, %2, %3)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_set_neopixel: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_get_port_number', params: [6], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, ], type: 'arduino_Lline_set_neopixel', }, paramsKeyMap: { PORT: 0, R: 1, G: 2, B: 3, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = script.getNumberValue('PORT', script); let R_val = script.getNumberValue('R', script); let G_val = script.getNumberValue('G', script); let B_val = script.getNumberValue('B', script); if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } script.isStart = true; script.timeFlag = 1; var fps = Entry.FPS || 60; var timeValue = (60 / fps) * 50; sq.SET[port] = { type: Entry.Lline.sensorTypes.NEOPIXEL, data:{R_val,G_val,B_val}, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, timeValue); return script; }else if (script.timeFlag == 1) { return script; }else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Arduino.neopixel(%1, %2, %3, %4)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_set_neopixel_each: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_get_port_number', params: [6], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, ], type: 'arduino_Lline_set_neopixel_each', }, paramsKeyMap: { PORT: 0, CNT: 1, R: 2, G: 3, B: 4, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = script.getNumberValue('PORT', script); let CNT_val = script.getNumberValue('CNT', script); let R_val = script.getNumberValue('R', script); let G_val = script.getNumberValue('G', script); let B_val = script.getNumberValue('B', script); if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } script.isStart = true; script.timeFlag = 1; var fps = Entry.FPS || 60; var timeValue = (60 / fps) * 50; sq.SET[port] = { type: Entry.Lline.sensorTypes.NEOPIXELEACH, data:{CNT_val,R_val,G_val,B_val}, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, timeValue); return script; }else if (script.timeFlag == 1) { return script; }else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Arduino.neopixel_each(%1, %2, %3, %4, %5)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_set_neopixel_list: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['무지개', '1'], ['조명효과', '2'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { VALUE: 0, }, func(sprite, script) { return script.getField('VALUE'); }, syntax: { js: [], py: [ { syntax: '%1', blockType: 'param', textParams: [ { type: 'Dropdown', options: [ ['무지개', '1'], ['조명효과', '2'], ], value: '0', fontSize: 11, converter: Entry.block.converters.returnStringKey, codeMap: 'Entry.CodeMap.Arduino.arduino_Lline_set_neopixel_list[0]', bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], keyOption: 'arduino_Lline_set_neopixel_list', }, ], }, }, arduino_Lline_set_neopixel_rainbow: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_get_port_number', params: [6], }, { type: 'number', params: ['0'], }, ], type: 'arduino_Lline_set_neopixel_rainbow', }, paramsKeyMap: { PORT : 0, VALUE: 1, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = script.getNumberValue('PORT', script); let value = script.getNumberValue('VALUE', script); if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } script.isStart = true; script.timeFlag = 1; var fps = Entry.FPS || 60; var timeValue = (60 / fps) * 50; sq.SET[port] = { type: Entry.Lline.sensorTypes.NEOPIXELRAINBOW, data: value, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, timeValue); return script; }else if (script.timeFlag == 1) { return script; }else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Arduino.neopixel_rainbow(%1)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ] }, ], }, }, arduino_Lline_set_neopixel_clear: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_get_port_number', params: [6], }, ], type: 'arduino_Lline_set_neopixel_clear', }, paramsKeyMap: { PORT : 0, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = script.getNumberValue('PORT', script); if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } script.isStart = true; script.timeFlag = 1; var fps = Entry.FPS || 60; var timeValue = (60 / fps) * 50; sq.SET[port] = { type: Entry.Lline.sensorTypes.NEOPIXELCLEAR, data: 0, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, timeValue); return script; }else if (script.timeFlag == 1) { return script; }else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Arduino.neopixeclear(%1)', textParams: [ { type: 'Block', accept: 'string', }, ] } ], }, }, arduino_Lline_set_metrix: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, ], type: 'arduino_Lline_set_metrix', }, paramsKeyMap: { VALUE1: 0, VALUE2: 1, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; let value1 = script.getNumberValue('VALUE1', script) +10; let value2 = script.getNumberValue('VALUE2', script) + 10; if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } script.isStart = true; script.timeFlag = 1; var fps = Entry.FPS || 60; var timeValue = (60 / fps) * 50; sq.SET[12] = { type: Entry.Lline.sensorTypes.METRIX, data:{value1,value2}, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, timeValue); return script; }else if (script.timeFlag == 1) { return script; }else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Arduino.metrix(%1, %2)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_set_metrix_list: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['0', '10'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ], value: '10', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { VALUE: 0, }, func(sprite, script) { return script.getField('VALUE'); }, syntax: { js: [], py: [ { syntax: '%1', blockType: 'param', textParams: [ { type: 'Dropdown', options: [ ['0', '10'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ], value: '0', fontSize: 11, converter: Entry.block.converters.returnStringKey, codeMap: 'Entry.CodeMap.Arduino.arduino_Lline_set_metrix_list[0]', bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], keyOption: 'arduino_Lline_set_metrix_list', }, ], }, }, arduino_Lline_set_metrix_draw: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_Lline_set_metrix_list', } ], type: 'arduino_Lline_set_metrix_draw', }, paramsKeyMap: { VALUE: 0, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; let value = script.getNumberValue('VALUE', script); if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } script.isStart = true; script.timeFlag = 1; var fps = Entry.FPS || 60; var timeValue = (60 / fps) * 50; sq.SET[12] = { type: Entry.Lline.sensorTypes.METRIXDRAW, data: value, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, timeValue); return script; }else if (script.timeFlag == 1) { return script; }else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Arduino.draw(%1)', textParams: [ { type: 'Block', accept: 'string', }, ] }, ], }, }, arduino_Lline_set_metrix_rowcol_clear: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: ['0'], }, { type: 'number', params: ['0'], }, ], type: 'arduino_Lline_set_metrix_rowcol_clear', }, paramsKeyMap: { VALUE1: 0, VALUE2: 1, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; let value1 = script.getNumberValue('VALUE1', script) + 10; let value2 = script.getNumberValue('VALUE2', script) + 10; if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } script.isStart = true; script.timeFlag = 1; var fps = Entry.FPS || 60; var timeValue = (60 / fps) * 50; sq.SET[12] = { type: Entry.Lline.sensorTypes.METRIXROWCOLCLEAR, data:{value1,value2}, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, timeValue); return script; }else if (script.timeFlag == 1) { return script; }else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Arduino.metrix_rowcol_clear(%1, %2)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_set_metrix_clear: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ ], type: 'arduino_Lline_set_metrix_clear', }, paramsKeyMap: { VALUE: 0, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = 12; if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } script.isStart = true; script.timeFlag = 1; var fps = Entry.FPS || 60; var timeValue = (60 / fps) * 50; sq.SET[port] = { type: Entry.Lline.sensorTypes.METRIXCLEAR, data: 0, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, timeValue); return script; }else if (script.timeFlag == 1) { return script; }else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { } ], }, }, arduino_Lline_lcd_list_init: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['0x27', '0'], ['0x3F', '1'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { LINE: 0, }, func: function(sprite, script) { return script.getField('LINE'); }, }, arduino_Lline_lcd_row_list: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ['14', '14'], ['15', '15'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { LINE: 0, }, func: function(sprite, script) { return script.getField('LINE'); }, }, arduino_Lline_lcd_col_list: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { LINE: 0, }, func: function(sprite, script) { return script.getField('LINE'); }, }, arduino_Lline_set_lcd_init: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_Lline_lcd_list_init', params: ['0'], }, ], type: 'arduino_Lline_set_lcd_init', }, paramsKeyMap: { LIST: 0, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; const list = script.getNumberValue('LIST', script); if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } script.isStart = true; script.timeFlag = 1; var fps = Entry.FPS || 60; var timeValue = (60 / fps) * 100; sq.SET[1] = { type: Entry.Lline.sensorTypes.LCDINIT, data: { list: list, }, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, timeValue); return script; }else if (script.timeFlag == 1) { return script; }else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Arduino.lcd_init(%1)', textParams: [ { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_lcd_backlight: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'arduino_get_digital_toggle', // 기존 토글 블럭 }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_get_digital_toggle', params: ['on'], // 기본은 ON }, null, ], type: 'arduino_Lline_lcd_backlight', }, paramsKeyMap: { VALUE: 0, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; const lcdAddress = 0x27; // 고정 주소 또는 39 let value = script.getValue('VALUE'); // 'on' / 'off' 가져옴 if (typeof value === 'string') value = value.toLowerCase(); if (Entry.Lline.highList.indexOf(value) > -1) { value = 1; } else if (Entry.Lline.lowList.indexOf(value) > -1) { value = 0; } else { value = 0; // 기본 OFF 처리 } if (!sq.SET) sq.SET = {}; sq.SET[1] = { type: Entry.Lline.sensorTypes.LCD_BACKLIGHT, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.lcd_backlight(%1)', textParams: [ { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_lcd_row_col: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_Lline_lcd_row_list', params: ['0'], }, { type: 'arduino_Lline_lcd_col_list', params: ['0'], }, { type: 'text', params: ['Lline'], }, ], type: 'arduino_Lline_lcd_row_col', }, paramsKeyMap: { ROW: 0, COL: 1, VALUE: 2, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; let row = script.getNumberValue('ROW', script); let col = script.getNumberValue('COL', script); let value = script.getValue('VALUE', script); value += ''; if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } script.isStart = true; script.timeFlag = 1; var fps = Entry.FPS || 60; var timeValue = (60 / fps) * 100; sq.SET[1] = { type: Entry.Lline.sensorTypes.LCD, data: {row, col, value}, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, timeValue); return script; }else if (script.timeFlag == 1) { return script; }else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { syntax: 'Arduino.lcd(%1,%2,%3)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ] }, ], }, }, arduino_Lline_lcd_clear: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ ], type: 'arduino_Lline_lcd_clear', }, paramsKeyMap: { VALUE: 0, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = 1; if (!script.isStart) { if (!sq.SET) { sq.SET = {}; } script.isStart = true; script.timeFlag = 1; var fps = Entry.FPS || 60; var timeValue = (60 / fps) * 50; sq.SET[port] = { type: Entry.Lline.sensorTypes.LCDCLEAR, data: 0, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, timeValue); return script; }else if (script.timeFlag == 1) { return script; }else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: [ { } ], }, }, arduino_Lline_get_temp: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'arduino_Lline_analog_list', }, ], events: {}, def: { params: [ { type: 'arduino_Lline_analog_list', }, ], type: 'arduino_Lline_get_temp', }, paramsKeyMap: { PORT: 0, }, class: 'LlineGet', isNotFor: ['Lline'], func(sprite, script) { const port = Number(script.getValue('PORT', script)); const tempValue = Entry.hw.portData.TEMPCHECK || 0; if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } Entry.hw.sendQueue.GET[Entry.Lline.sensorTypes.TEMPCHECK] = { port, time: new Date().getTime(), }; return tempValue; }, syntax: { js: [], py: [ { syntax: 'Arduino.temp_read(%1)', textParams: [ { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_get_humi: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'arduino_Lline_analog_list', }, ], events: {}, def: { params: [ { type: 'arduino_Lline_analog_list', }, ], type: 'arduino_Lline_get_humi', }, paramsKeyMap: { PORT: 0, }, class: 'LlineGet', isNotFor: ['Lline'], func(sprite, script) { const port = Number(script.getValue('PORT', script)); // 드롭다운 값 받아오기 const humiValue = Entry.hw.portData.HUMICHECK || 0; if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } Entry.hw.sendQueue.GET[Entry.Lline.sensorTypes.HUMICHECK] = { port, time: new Date().getTime(), }; return humiValue; }, syntax: { js: [], py: [ { syntax: 'Arduino.humi_read(%1)', textParams: [ { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_set_servo: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'arduino_get_port_number', params: ['4'], }, null, ], type: 'arduino_Lline_set_servo', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'Lline', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; const port = script.getNumberValue('PORT', script); let value = script.getNumberValue('VALUE', script); value = Math.min(180, value); value = Math.max(0, value); if (!sq.SET) { sq.SET = {}; } sq.SET[port] = { type: Entry.Lline.sensorTypes.SERVO_PIN, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.servomotorWrite(%1, %2)', textParams: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_stepper_init: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, // steps/rev 입력칸 { type: 'Dropdown', options: [['2','2'], ['3','3'], ['4','4'], ['5','5'], ['6','6'], ['7','7'], ['8','8'], ['9','9'], ['10','10'], ['11','11'], ['12','12'], ['13','13']], value: '8', }, // PIN1 { type: 'Dropdown', options: [['2','2'], ['3','3'], ['4','4'], ['5','5'], ['6','6'], ['7','7'], ['8','8'], ['9','9'], ['10','10'], ['11','11'], ['12','12'], ['13','13']], value: '9', }, // PIN2 { type: 'Dropdown', options: [['2','2'], ['3','3'], ['4','4'], ['5','5'], ['6','6'], ['7','7'], ['8','8'], ['9','9'], ['10','10'], ['11','11'], ['12','12'], ['13','13']], value: '10', }, // PIN3 { type: 'Dropdown', options: [['2','2'], ['3','3'], ['4','4'], ['5','5'], ['6','6'], ['7','7'], ['8','8'], ['9','9'], ['10','10'], ['11','11'], ['12','12'], ['13','13']], value: '11', }, // PIN4 ], def: { params: [ { type: 'text', params: ['200'] }, { type: 'Dropdown', value: '8' }, { type: 'Dropdown', value: '9' }, { type: 'Dropdown', value: '10' }, { type: 'Dropdown', value: '11' }, ], type: 'arduino_Lline_stepper_init', }, paramsKeyMap: { STEPS: 0, PIN1: 1, PIN2: 2, PIN3: 3, PIN4: 4, }, class: 'LlineMotor', isNotFor: ['Lline'], func(sprite, script) { const sq = Entry.hw.sendQueue; const steps = script.getNumberValue('STEPS'); const pin1 = Number(script.getField('PIN1')); const pin2 = Number(script.getField('PIN2')); const pin3 = Number(script.getField('PIN3')); const pin4 = Number(script.getField('PIN4')); if ( isNaN(steps) || steps <= 0 || isNaN(pin1) || isNaN(pin2) || isNaN(pin3) || isNaN(pin4) ) { console.warn('❗ [STEPPER_INIT] 유효하지 않은 값:', { steps, pins: [pin1, pin2, pin3, pin4] }); return script.callReturn(); } if (!sq.SET) sq.SET = {}; sq.SET[1] = { type: Entry.Lline.sensorTypes.STEPPER_INIT, data: { steps, pins: [pin1, pin2, pin3, pin4], }, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { text: '스텝모터 설정 steps/rev: %1 PIN1: %2 PIN2: %3 PIN3: %4 PIN4: %5', textParams: [ { type: 'Block', name: 'STEPS' }, { type: 'Dropdown', name: 'PIN1' }, { type: 'Dropdown', name: 'PIN2' }, { type: 'Dropdown', name: 'PIN3' }, { type: 'Dropdown', name: 'PIN4' }, ], }, }, arduino_Lline_stepper_speed: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', name: 'SPEED', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], def: { params: [ { type: 'text', params: ['60'] }, null, ], type: 'arduino_Lline_stepper_speed', }, paramsKeyMap: { SPEED: 0, }, class: 'LlineMotor', isNotFor: ['Lline'], func(sprite, script) { const speed = script.getNumberValue('SPEED'); if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.STEPPER_SPEED, data: { speed }, time: new Date().getTime(), }; return script.callReturn(); }, }, arduino_Lline_stepper_step: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', name: 'STEP', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], def: { params: [ { type: 'text', params: ['200'] }, null, ], type: 'arduino_Lline_stepper_step', }, paramsKeyMap: { STEP: 0, }, class: 'LlineMotor', isNotFor: ['Lline'], func(sprite, script) { const step = script.getNumberValue('STEP'); if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.STEPPER_STEP, data: { step }, time: new Date().getTime(), }; return script.callReturn(); }, }, arduino_Lline_stepper_stop: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], def: { params: [null], type: 'arduino_Lline_stepper_stop', }, class: 'LlineMotor', isNotFor: ['Lline'], func(sprite, script) { if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.STEPPER_STOP, data: 0, time: new Date().getTime(), }; return script.callReturn(); }, }, arduino_Lline_get_ir_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Dropdown', options: [ ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ], value: '3', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], type: 'arduino_Lline_get_ir_value', }, paramsKeyMap: { PORT: 0, }, class: 'LlineGet', isNotFor: ['Lline'], func(sprite, script) { const port = Number(script.getField('PORT')); const value = Entry.hw.portData.IR || 0; if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } Entry.hw.sendQueue.GET[Entry.Lline.sensorTypes.IR] = { port, time: new Date().getTime(), }; return value; }, syntax: { js: [], py: [ { syntax: 'Arduino.ir_read(%1)', textParams: [ { type: 'Block', accept: 'string', }, ], }, ], }, }, arduino_Lline_init_color_sensor: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8']], value: '6', }, { type: 'Dropdown', options: [['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8']], value: '5', }, { type: 'Dropdown', options: [['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8']], value: '4', }, { type: 'Dropdown', options: [['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8']], value: '3', }, { type: 'Dropdown', options: [['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8']], value: '2', }, { type: 'Dropdown', options: [['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8']], value: '7', }, ], events: {}, def: { params: [ { type: 'Dropdown', value: '6' }, { type: 'Dropdown', value: '5' }, { type: 'Dropdown', value: '4' }, { type: 'Dropdown', value: '3' }, { type: 'Dropdown', value: '2' }, { type: 'Dropdown', value: '7' }, ], type: 'arduino_Lline_init_color_sensor', }, paramsKeyMap: { S0: 0, S1: 1, S2: 2, S3: 3, OUT: 4, LED: 5, }, class: 'LlineGet', isNotFor: ['Lline'], func(sprite, script) { const s0 = Number(script.getField('S0')); const s1 = Number(script.getField('S1')); const s2 = Number(script.getField('S2')); const s3 = Number(script.getField('S3')); const out = Number(script.getField('OUT')); const led = Number(script.getField('LED')); if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.COLOR_SENSOR_INIT, data: { s0, s1, s2, s3, out, led, }, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: [ { syntax: 'Arduino.init_color_sensor(%1, %2, %3, %4, %5, %6)', textParams: [ { type: 'Dropdown', options: [['2','2'],['3','3'],['4','4'],['5','5'],['6','6']], value: '6' }, { type: 'Dropdown', options: [['2','2'],['3','3'],['4','4'],['5','5'],['6','6']], value: '5' }, { type: 'Dropdown', options: [['2','2'],['3','3'],['4','4'],['5','5'],['6','6']], value: '4' }, { type: 'Dropdown', options: [['2','2'],['3','3'],['4','4'],['5','5'],['6','6']], value: '3' }, { type: 'Dropdown', options: [['2','2'],['3','3'],['4','4'],['5','5'],['6','6']], value: '2' }, { type: 'Dropdown', options: [['2','2'],['3','3'],['4','4'],['5','5'],['6','6']], value: '7' }, ], }, ], }, }, arduino_Lline_get_color_rgb: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Dropdown', options: [ ['Red', 'R'], ['Green', 'G'], ['Blue', 'B'], ], value: 'R', }, ], events: {}, def: { params: [null], type: 'arduino_Lline_get_color_rgb', }, paramsKeyMap: { COLOR: 0, }, class: 'LlineGet', isNotFor: ['Lline'], func(sprite, script) { const color = script.getField('COLOR'); const colorObj = Entry.hw.portData.COLOR || {}; // COLOR: {R, G, B} // colorIndex: R=0, G=1, B=2로 매핑 const colorIndexMap = { R: 0, G: 1, B: 2 }; const colorIndex = colorIndexMap[color]; if (!Entry.hw.sendQueue.GET) Entry.hw.sendQueue.GET = {}; Entry.hw.sendQueue.GET[Entry.Lline.sensorTypes.COLOR_SENSOR] = { port: [1], data: colorIndex, time: new Date().getTime(), }; return colorObj[color] || 0; // colorObj['R'], 'G', 'B' }, syntax: { js: [], py: [ { syntax: 'Arduino.color_read(%1)', textParams: [ { type: 'Dropdown', options: [ ['Red', 'R'], ['Green', 'G'], ['Blue', 'B'], ], value: 'R', }, ], }, ], }, }, arduino_Lline_hm10_init: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9']], value: '0', }, // TX 핀 { type: 'Dropdown', options: [['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9']], value: '1', }, // RX 핀 ], def: { params: [ { type: 'Dropdown', value: '0' }, { type: 'Dropdown', value: '1' }, ], type: 'arduino_Lline_hm10_init', }, paramsKeyMap: { TX: 0, RX: 1, }, class: 'LlineComm', isNotFor: ['Lline'], func(sprite, script) { const tx = Number(script.getField('TX')); const rx = Number(script.getField('RX')); if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.HM10_INIT, data: { tx, rx }, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { text: 'HM-10 연결 설정 TX: %1 RX: %2', textParams: [ { type: 'Dropdown', name: 'TX' }, { type: 'Dropdown', name: 'RX' }, ], }, }, arduino_Lline_hm10_send: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string' }, // 보낼 문자열 ], def: { params: [ { type: 'text', params: ['Hello'] }, ], type: 'arduino_Lline_hm10_send', }, paramsKeyMap: { DATA: 0, }, class: 'LlineComm', isNotFor: ['Lline'], func(sprite, script) { const data = script.getStringValue('DATA'); if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.HM10_SEND, data: data, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { text: 'HM-10 데이터 보내기 %1', textParams: [ { type: 'Block', name: 'DATA' }, ], }, }, arduino_Lline_hm10_receive: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [], def: { params: [], type: 'arduino_Lline_hm10_receive', }, class: 'LlineComm', isNotFor: ['Lline'], func(sprite, script) { const value = Entry.hw.portData.HM10_RECEIVE || ''; if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.HM10_RECEIVE, time: new Date().getTime(), }; return value; }, syntax: { text: 'HM-10 수신 데이터', textParams: [], }, }, arduino_Lline_hc06_init: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9']], value: '0', }, // TX 핀 { type: 'Dropdown', options: [['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9']], value: '1', }, // RX 핀 ], def: { params: [ { type: 'Dropdown', value: '0' }, { type: 'Dropdown', value: '1' }, ], type: 'arduino_Lline_hc06_init', }, paramsKeyMap: { TX: 0, RX: 1, }, class: 'LlineComm', isNotFor: ['Lline'], func(sprite, script) { const tx = Number(script.getField('TX')); const rx = Number(script.getField('RX')); if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.HC06_INIT, data: { tx, rx }, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { text: 'HC-06 연결 설정 TX: %1 RX: %2', textParams: [ { type: 'Dropdown', name: 'TX' }, { type: 'Dropdown', name: 'RX' }, ], }, }, arduino_Lline_hc06_send: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string' }, // 보낼 문자열 ], def: { params: [ { type: 'text', params: ['Hello'] }, ], type: 'arduino_Lline_hc06_send', }, paramsKeyMap: { DATA: 0, }, class: 'LlineComm', isNotFor: ['Lline'], func(sprite, script) { const data = script.getStringValue('DATA'); if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.HC06_SEND, data: data, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { text: 'HC-06 데이터 보내기 %1', textParams: [ { type: 'Block', name: 'DATA' }, ], }, }, arduino_Lline_hc06_receive: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [], def: { params: [], type: 'arduino_Lline_hc06_receive', }, class: 'LlineComm', isNotFor: ['Lline'], func(sprite, script) { const value = Entry.hw.portData.HC06_RECEIVE || ''; if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.HC06_RECEIVE, time: new Date().getTime(), }; return value; }, syntax: { text: 'HC-06 수신 데이터', textParams: [], }, }, arduino_Lline_DC_motor_init: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', params: [ { type: 'Dropdown', options: [['2','2'], ['3','3'], ['4','4'], ['5','5'], ['6','6'], ['7','7'], ['8','8'], ['9','9'], ['10','10']], value: '2', }, // ENA { type: 'Dropdown', options: [['2','2'], ['3','3'], ['4','4'], ['5','5'], ['6','6'], ['7','7'], ['8','8'], ['9','9'], ['10','10']], value: '3', }, // A-1A { type: 'Dropdown', options: [['2','2'], ['3','3'], ['4','4'], ['5','5'], ['6','6'], ['7','7'], ['8','8'], ['9','9'], ['10','10']], value: '4', }, // A-1B ], def: { params: [ { type: 'Dropdown', value: '2' }, { type: 'Dropdown', value: '3' }, { type: 'Dropdown', value: '4' }, ], type: 'arduino_Lline_DC_motor_init', }, paramsKeyMap: { ENA: 0, A1A: 1, A1B: 2, }, class: 'LlineMotor', isNotFor: ['Lline'], func(sprite, script) { const ena = Number(script.getField('ENA')); const a1a = Number(script.getField('A1A')); const a1b = Number(script.getField('A1B')); if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.DC_MOTOR_INIT, data: { ena, a1a, a1b}, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { text: 'DC 모터 설정 ENA: %1 IN1: %2 IN2: %3', textParams: [ { type: 'Dropdown', name: 'ENA' }, { type: 'Dropdown', name: 'A1A' }, { type: 'Dropdown', name: 'A1B' }, ], }, }, arduino_Lline_DC_motor_control: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', params: [ { type: 'Dropdown', options: [['정방향', 'FORWARD'], ['역방향', 'BACKWARD'], ['정지', 'STOP']], value: 'FORWARD', }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], def: { params: [ { type: 'Dropdown', value: 'FORWARD' }, { type: 'text', params: ['150'] }, ], type: 'arduino_Lline_DC_motor_control', }, paramsKeyMap: { DIR_A: 0, SPEED_A: 1, }, class: 'LlineMotor', isNotFor: ['Lline'], func(sprite, script) { const dirA = script.getField('DIR_A'); const speedA = script.getNumberValue('SPEED_A'); if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.DC_MOTOR_CONTROL, data: { dirA, speedA}, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { text: 'DC 모터 A %1 속도 %2', textParams: [ { type: 'Dropdown', name: 'DIR_A' }, { type: 'Block', name: 'SPEED_A' }, ], }, }, arduino_Lline_DC_motor_init2: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', params: [ { type: 'Dropdown', options: [['2','2'], ['3','3'], ['4','4'], ['5','5'], ['6','6'], ['7','7'], ['8','8'], ['9','9'], ['10','10']], value: '2', }, // ENA { type: 'Dropdown', options: [['2','2'], ['3','3'], ['4','4'], ['5','5'], ['6','6'], ['7','7'], ['8','8'], ['9','9'], ['10','10']], value: '3', }, // A-1A { type: 'Dropdown', options: [['2','2'], ['3','3'], ['4','4'], ['5','5'], ['6','6'], ['7','7'], ['8','8'], ['9','9'], ['10','10']], value: '4', }, // A-1B ], def: { params: [ { type: 'Dropdown', value: '2' }, { type: 'Dropdown', value: '3' }, { type: 'Dropdown', value: '4' }, ], type: 'arduino_Lline_DC_motor_init2', }, paramsKeyMap: { ENB: 0, B1A: 1, B1B: 2, }, class: 'LlineMotor', isNotFor: ['Lline'], func(sprite, script) { const enb = Number(script.getField('ENB')); const b1a = Number(script.getField('B1A')); const b1b = Number(script.getField('B1B')); if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.DC_MOTOR_INIT2, data: { enb, b1a, b1b}, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { text: 'DC 모터 설정 ENA: %1 IN3: %2 IN4: %3', textParams: [ { type: 'Dropdown', name: 'ENB' }, { type: 'Dropdown', name: 'B1A' }, { type: 'Dropdown', name: 'B1B' }, ], }, }, arduino_Lline_DC_motor_control2: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', params: [ { type: 'Dropdown', options: [['정방향', 'FORWARD'], ['역방향', 'BACKWARD'], ['정지', 'STOP']], value: 'FORWARD', }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], def: { params: [ { type: 'Dropdown', value: 'FORWARD' }, { type: 'text', params: ['150'] }, ], type: 'arduino_Lline_DC_motor_control2', }, paramsKeyMap: { DIR_B: 0, SPEED_B: 1, }, class: 'LlineMotor', isNotFor: ['Lline'], func(sprite, script) { const dirB = script.getField('DIR_B'); const speedB = script.getNumberValue('SPEED_B'); if (!Entry.hw.sendQueue.SET) Entry.hw.sendQueue.SET = {}; Entry.hw.sendQueue.SET[1] = { type: Entry.Lline.sensorTypes.DC_MOTOR_CONTROL2, data: { dirB, speedB}, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { text: 'DC 모터 B %1 속도 %2', textParams: [ { type: 'Dropdown', name: 'DIR_B' }, { type: 'Block', name: 'SPEED_B' }, ], }, }, }; }; //endregion Lline 아두이노 확장모드 module.exports = Entry.Lline; ================================================ FILE: src/playground/blocks/hardware/block_RichShield.js ================================================ 'use strict'; Entry.RichShield = { id: '36.2', name: 'RichShield', url: 'https://gorillacell.kr/', imageName: 'RichShield.png', title: { ko: '아두이노 부자실드', en: 'Arduino RichShield', }, setZero() { if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue = { SET: {}, }; } else { const keySet = Object.keys(Entry.hw.sendQueue.SET); keySet.forEach((key) => { if (Entry.hw.sendQueue.SET[key].type == Entry.RichShield.sensorTypes.DCMOTOR) { Entry.hw.sendQueue.SET[key].data.value1 = 0; Entry.hw.sendQueue.SET[key].time = new Date().getTime(); } else { Entry.hw.sendQueue.SET[key].data = 0; Entry.hw.sendQueue.SET[key].time = new Date().getTime(); } }); } Entry.hw.sendQueue.GET = {}; Entry.hw.update(); }, sensorTypes: { ALIVE: 0, DIGITAL: 1, ANALOG: 2, PWM: 3, SERVO: 4, TONE: 5, PULSEIN: 6, ULTRASONIC: 7, TIMER: 8, READ_BLUETOOTH: 9, WRITE_BLUETOOTH: 10, LCD: 11, DHT: 12, DCMOTOR: 13, OLED: 14, PIR: 15, FND: 16, IRREMOTE : 19, DHT2 : 17, RGBLED: 18, }, toneTable: { '0': 0, C: 1, CS: 2, D: 3, DS: 4, E: 5, F: 6, FS: 7, G: 8, GS: 9, A: 10, AS: 11, B: 12, }, toneMap: { '1': [33, 65, 131, 262, 523, 1046, 2093, 4186], '2': [35, 69, 139, 277, 554, 1109, 2217, 4435], '3': [37, 73, 147, 294, 587, 1175, 2349, 4699], '4': [39, 78, 156, 311, 622, 1245, 2849, 4978], '5': [41, 82, 165, 330, 659, 1319, 2637, 5274], '6': [44, 87, 175, 349, 698, 1397, 2794, 5588], '7': [46, 92, 185, 370, 740, 1480, 2960, 5920], '8': [49, 98, 196, 392, 784, 1568, 3136, 6272], '9': [52, 104, 208, 415, 831, 1661, 3322, 6645], '10': [55, 110, 220, 440, 880, 1760, 3520, 7040], '11': [58, 117, 233, 466, 932, 1865, 3729, 7459], '12': [62, 123, 247, 494, 988, 1976, 3951, 7902], }, highList: ['high', '1', 'on'], lowList: ['low', '0', 'off'], BlockState: {}, }; Entry.RichShield.setLanguage = function() { return { ko: { Blocks: { RichShield_pulldown: '기본', RichShield_pullup: '풀업', chocopi_control_event_pressed: '누를 때', chocopi_control_event_released: '뗄 때', chocopi_joystick_X: '조이스틱 좌우', chocopi_joystick_Y: '조이스틱 상하', chocopi_motion_photogate_event_blocked: '막았을 때', chocopi_motion_photogate_event_unblocked: '열었을 때', chocopi_motion_photogate_time_blocked: '막은 시간', chocopi_motion_photogate_time_unblocked: '연 시간', chocopi_motion_angle_x: '각도X', chocopi_motion_angle_y: '각도Y', chocopi_motion_angle_z: '각도Z', chocopi_port: '포트', chocopi_pot: '볼륨', chocopi_touch_event_touch: '만질 때', chocopi_touch_event_untouch: '뗄 때', RichShield_lcd_first_line: '첫 번째', RichShield_lcd_seconds_line: '두 번째', RichShield_toggle_on: '켜기', RichShield_toggle_off: '끄기', }, template: { RichShield_get_Analog_value: '아날로그 %1 번 핀의 값', RichShield_set_digital_toggle: '디지털 %1 번 핀 %2 %3', RichShield_get_digital: '디지털 %1 번 핀 센서 %2 값', RichShield_get_digital_toggle: '디지털 %1 번 핀 센서 %2 값', RichShield_set_digital_pwm: '디지털 PWM %1 번 핀을 %2 (으)로 정하기 %3', RichShield_get_digital_ultrasonic: '초음파 Trig %1 핀 Echo %2 핀 센서 값', RichShield_set_digital_servo: '디지털 %1 번 핀의 서보모터를 %2 의 각도로 정하기 %3', RichShield_set_digital_buzzer: '디지털 %1 번 핀의 버저를 %2 %3 음으로 %4 초 연주하기 %5', RichShield_rgbled_event: '네오픽셀 ( 8 Cell ) - 디지털 13번 핀', RichShield_rgbled_clr: '네오픽셀 off', RichShield_rgbled_set: '%1번 네오픽셀을 빨강 %2 초록 %3 파랑 %4 로 정하기 %5', RichShield_rgbled_show: '네오픽셀 적용(표시)', RichShield_LCD_event: 'LCD Display(1602-)-I2C', RichShield_LCD_Control_init: 'LCD %1 번 : 주소 %2 로 설정', RichShield_LCD_Control_Display: 'LCD %1 번 : %2 행 %3 열에 %4 출력 %5', RichShield_LCD_Control_Clear: 'LCD %1 번 : 지우기', RichShield_LCD_Control_Scroll: 'LCD %1 번 : 화면스크롤 %2', RichShield_FND_event: 'FND 4digit (TM1637)- CLK:D5, DIO:D4', RichShield_FND_Control_init: 'FND %1 번 : 디지털 CLK %2, DIO %3 번 핀으로 설정', RichShield_FND_Control_diplay_brightness: 'FND %1 번 : 밝기 %2 단계로 설정', RichShield_FND_Control_display_onoff: 'FND %1 번 : 전원 %2', RichShield_FND_Control_diplay_char: 'FND %1 번 : %2 출력하기:나머지0채우기 %3 %4 초 대기', RichShield_DHT_event: '온습도센서(DHT11/22)-디지털 12번 핀', RichShield_DHT_Control_Init_Process: '온습도 %1 번 : 디지털 %2 번 핀 / 버전 %3', RichShield_DHT_Control_Get_Temper: '온습도 %1 번 온도값 읽기', RichShield_DHT2: '온습도 %1 번 : 습도값 읽기', RichShield_OLED_event: 'OLED Display(0.96"16*08)-I2C', RichShield_OLED_init: 'OLED : I2C 주소 0X3C로 설정하고, 초기화', RichShield_OLED_Display_String: 'OLED : %1 행, %2 열 %3 출력', RichShield_IRREMOTE_event: '적외선수신-RECV', RichShield_IRREMOTE_init: '적외선 %1번: 디지털 %2번 핀으로 설정~', RichShield_IRREMOTE_recv: '적외선 %1 번: 자료 읽기', }, }, en: { Blocks: { RichShield_pulldown: 'Pull Down', RichShield_pullup: 'Pull Up', chocopi_control_event_pressed: 'pressed', chocopi_control_event_released: 'released', chocopi_joystick_X: 'joystick X', chocopi_joystick_Y: 'joystick Y', chocopi_motion_photogate_event_blocked: 'blocked', chocopi_motion_photogate_event_unblocked: 'unblocked', chocopi_motion_photogate_time_blocked: 'blocked', chocopi_motion_photogate_time_unblocked: 'unblocked', chocopi_motion_angle_x: 'angle X', chocopi_motion_angle_y: 'angle Y', chocopi_motion_angle_z: 'angle Z', chocopi_port: 'P', chocopi_pot: 'potentiometer', chocopi_touch_event_touch: 'touched', chocopi_touch_event_untouch: 'untouched', RichShield_lcd_first_line: 'first', RichShield_lcd_seconds_line: 'second', RichShield_toggle_on: 'on', RichShield_toggle_off: 'off', }, template: { RichShield_get_Analog_value: 'Get Analog %1 pin value', RichShield_set_digital_toggle: 'Digital %1 pin %2 %3', RichShield_get_digital: 'Digital %1 pin sensor value %2', RichShield_get_digital_toggle: 'Digital %1 pin sensor value %2', RichShield_set_digital_pwm: 'Digital pwm %1 Pin %2 %3', RichShield_get_digital_ultrasonic: 'Read ultrasonic Trig %1 Echo %2 sensor value', RichShield_set_digital_servo: 'Set servo pin %1 angle as %2 %3', RichShield_set_digital_buzzer: 'Play tone pin %1 on note %2 octave %3 beat %4 %5', RichShield_rgbled_event: 'NeoPixel ( 8 Cell ) - Digital 13 pin', RichShield_rgbled_clr: 'NeoPixel off', RichShield_rgbled_set: '#%1 NeoPixel Red %2 Green %3 Blue %4 %5', RichShield_rgbled_show: 'NeoPixel Update', RichShield_LCD_event: 'LCD Display(1602-)-I2C', RichShield_LCD_Control_init: 'LCD %1 : Address set to %2', RichShield_LCD_Control_Display: 'LCD %1 : row %2 column %3 display %4 %5', RichShield_LCD_Control_Clear: 'LCD %1 : Clear Display', RichShield_LCD_Control_Scroll: 'LCD %1 : Display Scroll to %2', RichShield_FND_event: 'FND 4digit (TM1637)- CLK:D5, DIO:D4', RichShield_FND_Control_init: 'FND %1 : Digital CLK %2 , DIO %3 pin setting', RichShield_FND_Control_diplay_brightness: 'FND %1 : Brightness %2 level setting', RichShield_FND_Control_display_onoff: 'FND %1 : Power %2', RichShield_FND_Control_diplay_char: 'FND %1 : %2 display:zero-fill %3 %4 sec waiting', RichShield_DHT_event: 'Humidity/Temperature(DHT11/22)-Digital 12 pin', RichShield_DHT_Control_Init_Process: 'Humidity/Temperature %1 : Digital %2 Pin, Version %3', RichShield_DHT_Control_Get_Temper: 'DHT %1 : read Temperature', RichShield_DHT2: 'DHT %1 : read Humid', RichShield_OLED_event: 'OLED Display(0.96"16*08)-I2C', RichShield_OLED_init: 'OLED : I2C adress 0X3C set, initialize', RichShield_OLED_Display_String: 'OLED : %1 Row, %2 Col %3 Display', RichShield_IRREMOTE_event: 'IR RECV-RECV pin:D2', RichShield_IRREMOTE_init: 'IR %1 : Digital recv pin set to %2', RichShield_IRREMOTE_recv: 'IR %1 : IR recv', }, }, }; }; Entry.RichShield.blockMenuBlocks = [ 'RichShield_get_digital', 'RichShield_get_Analog_value', 'RichShield_get_digital_toggle', 'RichShield_get_digital_ultrasonic', 'RichShield_set_digital_toggle', 'RichShield_set_digital_pwm', 'RichShield_set_digital_servo', 'RichShield_set_digital_buzzer', 'RichShield_rgbled_event', 'RichShield_rgbled_clr', 'RichShield_rgbled_set', 'RichShield_rgbled_show', 'RichShield_LCD_event', 'RichShield_LCD_Control_init', 'RichShield_LCD_Control_Display', 'RichShield_LCD_Control_Clear', 'RichShield_FND_event', 'RichShield_FND_Control_diplay_brightness', 'RichShield_FND_Control_display_onoff', 'RichShield_FND_Control_diplay_char', 'RichShield_DHT_event', 'RichShield_DHT_Control_Get_Temper', 'RichShield_DHT2', 'RichShield_OLED_event', 'RichShield_OLED_Display_String', 'RichShield_IRREMOTE_event', 'RichShield_IRREMOTE_recv', ]; Entry.RichShield.getBlocks = function() { return { RichShield_list_digital_basic: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown1', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ], value: '5', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getStringField('PORT'); }, }, RichShield_list_pullup_setting: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.RichShield_pulldown, '0'], [Lang.Blocks.RichShield_pullup, '255'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { OPERATOR: 0, }, func(sprite, script) { return script.getStringField('OPERATOR'); }, }, RichShield_get_digital_ultrasonic: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', template: Lang.template.RichShield_get_digital_ultrasonic, statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'text', params: ['8'], }, { type: 'text', params: ['7'], }, ], type: 'RichShield_get_digital_ultrasonic', }, paramsKeyMap: { PORT1: 0, PORT2: 1, }, class: 'RichShieldGet', isNotFor: ['RichShield'], func: function(sprite, script) { var port1 = script.getNumberValue('PORT1'); var port2 = script.getNumberValue('PORT2'); if (!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } delete Entry.hw.sendQueue['SET'][port1]; delete Entry.hw.sendQueue['SET'][port2]; if (!Entry.hw.sendQueue['GET']) { Entry.hw.sendQueue['GET'] = {}; } Entry.hw.sendQueue['GET'][Entry.RichShield.sensorTypes.ULTRASONIC] = { port: [port1, port2], time: new Date().getTime(), }; return Entry.hw.portData.ULTRASONIC || 0; }, syntax: { js: [], py: ['RichShield.get_digital_ultrasonic(%1, %2)'], }, }, RichShield_get_digital: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], template: Lang.template.RichShield_get_digital, params: [ { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ { type: 'RichShield_list_digital_switch', }, { type: 'RichShield_list_pullup_setting', }, ], type: 'RichShield_get_digital', }, paramsKeyMap: { PORT: 0, OPERATOR: 1, }, class: 'RichShieldGet', isNotFor: ['RichShield'], func(sprite, script) { const port = script.getNumberValue('PORT'); const opr = script.getNumberValue('OPERATOR'); //"down = 0" or "up = 2" const DIGITAL = Entry.hw.portData.DIGITAL; if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } if (Entry.hw.sendQueue.SET[port]) { return Entry.hw.sendQueue.SET[port].data; } else { Entry.hw.sendQueue.GET[Entry.RichShield.sensorTypes.DIGITAL] = { port, data: opr, time: new Date().getTime(), }; } return DIGITAL ? DIGITAL[port] || 0 : 0; }, syntax: { js: [], py: ['RichShield_get_digital(%1,%2)'] }, }, RichShield_get_digital_toggle: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_boolean_field', statements: [], template: Lang.template.RichShield_get_digital_toggle, params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ { type: 'RichShield_list_digital_switch', }, { type: 'RichShield_list_pullup_setting', }, ], type: 'RichShield_get_digital_toggle', }, paramsKeyMap: { PORT: 0, OPERATOR: 1, }, class: 'RichShieldGet', isNotFor: ['RichShield'], func(sprite, script) { const port = script.getNumberValue('PORT'); const opr = script.getNumberValue('OPERATOR'); const DIGITAL = Entry.hw.portData.DIGITAL; if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } if (Entry.hw.sendQueue.SET[port]) { return Entry.hw.sendQueue.SET[port].data; } else { Entry.hw.sendQueue.GET[Entry.Hasseam.sensorTypes.DIGITAL] = { port, data: opr, time: new Date().getTime(), }; } return DIGITAL ? DIGITAL[port] || 0 : 0; }, syntax: { js: [], py: ['RichShield_get_digital_toggle(%1 %2)'] }, }, RichShield_list_analog_basic: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['A0', '0'], ['A1', '1'], ['A2', '2'], ['A3', '3'], ['A4', '4'], ['A5', '5'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getField('PORT'); }, }, RichShield_get_Analog_value: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', template: Lang.template.RichShield_get_Analog_value, statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', defaultType: 'number', }, ], events: {}, def: { params: [ { type: 'RichShield_list_analog_basic', }, ], type: 'RichShield_get_Analog_value', }, paramsKeyMap: { PORT: 0, }, class: 'RichShieldGet', isNotFor: ['RichShield'], func(sprite, script) { let port = script.getValue('PORT', script); const ANALOG = Entry.hw.portData.ANALOG; if (port[0] === 'A') { port = port.substring(1); } if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } Entry.hw.sendQueue.GET[Entry.RichShield.sensorTypes.ANALOG] = { port, time: new Date().getTime(), }; return ANALOG ? ANALOG[port] || 0 : 0; }, syntax: { js: [], py: ['RichShield.Get_Light_Value(%1, %2)'] }, }, RichShield_list_digital_basic: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ], value: '5', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func(sprite, script) { return script.getStringField('PORT'); }, }, RichShield_list_digital_pwm: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['~3', '3'], ['~5', '5'], ['~6', '6'], ['~9', '9'], ['~10', '10'], ['~11', '11'], ], value: '11', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func: function(sprite, script) { return script.getStringField('PORT'); }, }, RichShield_list_digital_pwm2: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['~9', '9'], ['~10', '10'], ['~11', '11'], ], value: '9', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func: function(sprite, script) { return script.getStringField('PORT'); }, }, RichShield_list_digital_basic: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['0', '0'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ['9', '9'], ['10', '10'], ['11', '11'], ['12', '12'], ['13', '13'], ], value: '10', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func: function(sprite, script) { return script.getStringField('PORT'); }, }, RichShield_list_digital_switch: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['4', '4'], ['5', '5'], ], value: '4', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func: function(sprite, script) { return script.getStringField('PORT'); }, }, RichShield_rgbled_event: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_hardware.svg', size: 14, position: { x: 0, y: -2 }, }, ], def: { params: [], type: 'RichShield_rgbled_event' }, class: 'RichShield_rgbled', isNotFor: ['RichShield'], }, RichShield_rgbled_clr: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, null, ], type: 'RichShield_rgbled_clr', }, paramsKeyMap: { PORT: 0, NO: 1, VALUE0: 2, VALUE1: 3, VALUE2: 4, }, class: 'RichShield_rgbled', isNotFor: ['RichShield'], func: function(sprite, script) { var port = 13; if (!script.isStart) { if (!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } script.isStart = true; script.timeFlag = 1; const fps = Entry.FPS || 60; const timeValue = (60 / fps) ; Entry.hw.sendQueue['SET'][port] = { type: Entry.RichShield.sensorTypes.RGBLED, data: { block_Index: 1, }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, timeValue); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: ['RichShield_rgbled_clr(%1)'] }, }, RichShield_rgbled_set: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'text', params: ['1'], }, { type: 'text', params: ['255'], }, { type: 'text', params: ['0'], }, { type: 'text', params: ['0'], }, null, ], type: 'RichShield_rgbled_set', }, paramsKeyMap: { NO: 0, VALUE0: 1, VALUE1: 2, VALUE2: 3, }, class: 'RichShield_rgbled', isNotFor: ['RichShield'], func: function(sprite, script) { var port = 13; var no = script.getNumberValue('NO'); var value = [3]; var noValue1; let time = new Date().getTime(); if (!script.isStart) { noValue1 = no - 1; value[0] = script.getNumberValue('VALUE0'); value[1] = script.getNumberValue('VALUE1'); value[2] = script.getNumberValue('VALUE2'); for (var i = 0; i < 3; i++) { value[i] = Math.round(value[i]); value[i] = Math.min(value[i], 255); value[i] = Math.max(value[i], 0); } if (!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } script.isStart = true; script.timeFlag = 1; const fps = Entry.FPS || 60; const timeValue = (60 / fps) ; Entry.hw.sendQueue['SET'][port] = { type: Entry.RichShield.sensorTypes.RGBLED, data: { block_Index: 2, noValue: noValue1, redValue: value[0], greenValue: value[1], blueValue: value[2], }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, timeValue*20); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } return script.callReturn(); }, syntax: { js: [], py: ['RichShield_rgbled_set(%1, %2, %3, %4, %5)'] }, }, RichShield_rgbled_show: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, null, ], type: 'RichShield_rgbled_show', }, paramsKeyMap: { }, class: 'RichShield_rgbled', isNotFor: ['RichShield'], func: function(sprite, script) { var port = 13; if (!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } Entry.hw.sendQueue['SET'][port] = { type: Entry.RichShield.sensorTypes.RGBLED, data: { block_Index: 3, }, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: ['RichShield_rgbled_show(%1)'] }, }, RichShield_list_digital_servo: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['6', '6'], ], value: '6', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func: function(sprite, script) { return script.getStringField('PORT'); }, }, RichShield_list_digital_sound: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['3', '3'], ], value: '3', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { PORT: 0, }, func: function(sprite, script) { return script.getStringField('PORT'); }, }, RichShield_list_digital_octave: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ['5', '5'], ['6', '6'], ['7', '7'], ['8', '8'], ], value: '3', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { OCTAVE: 0, }, func: function(sprite, script) { return script.getField('OCTAVE'); }, }, RichShield_list_digital_toggle: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.RichShield_toggle_on, 'on'], [Lang.Blocks.RichShield_toggle_off, 'off'], ], value: 'on', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { OPERATOR: 0, }, func(sprite, script) { return script.getStringField('OPERATOR'); }, }, RichShield_set_digital_toggle: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], template: Lang.template.RichShield_set_digital_toggle, params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'RichShield_list_digital_basic', }, { type: 'RichShield_list_digital_toggle', }, null, ], type: 'RichShield_set_digital_toggle', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'RichShield_set', isNotFor: ['RichShield'], func(sprite, script) { const port = script.getNumberValue('PORT'); let value = script.getValue('VALUE'); if (typeof value === 'string') { value = value.toLowerCase(); } if (Entry.RichShield.highList.indexOf(value) > -1) { value = 255; } else if (Entry.RichShield.lowList.indexOf(value) > -1) { value = 0; } else { throw new Error(); } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } Entry.hw.sendQueue.SET[port] = { type: Entry.RichShield.sensorTypes.DIGITAL, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: ['RichShield.Set_Digital_Toggle(%1, %2)'] }, }, RichShield_set_digital_pwm: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], template: Lang.template.RichShield_set_digital_pwm, params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'RichShield_list_digital_pwm2', }, { type: 'text', params: ['255'], }, null, ], type: 'RichShield_set_digital_pwm', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'RichShield_Set', isNotFor: ['RichShield'], func: function(sprite, script) { var port = script.getNumberValue('PORT'); var value = script.getNumberValue('VALUE'); let time = new Date().getTime(); if (!script.isStart) { value = Math.round(value); value = Math.min(value, 255); value = Math.max(value, 0); if (!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } script.isStart = true; script.timeFlag = 1; const fps = Entry.FPS || 60; const timeValue = (60 / fps) * 50; Entry.hw.sendQueue['SET'][port] = { type: Entry.RichShield.sensorTypes.PWM, data: value, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, timeValue); } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } return script.callReturn(); }, syntax: { js: [], py: ['RichShield.set_digital_pwm(%1, %2)'] }, }, RichShield_set_digital_servo: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], template: Lang.template.RichShield_set_digital_servo, params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'RichShield_list_digital_servo', }, { type: 'text', params: ['90'], }, null, ], type: 'RichShield_set_digital_servo', }, paramsKeyMap: { PORT: 0, VALUE: 1, }, class: 'RichShield_Set', isNotFor: ['RichShield'], func: function(sprite, script) { var port = script.getNumberValue('PORT'); var value = script.getNumberValue('VALUE'); value = Math.min(value, 180); value = Math.max(value, 0); if (!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } Entry.hw.sendQueue['SET'][port] = { type: Entry.RichShield.sensorTypes.SERVO, data: value, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: ['RichShield.set_digital_servo(%1, %2)'] }, }, RichShield_set_digital_buzzer: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], template: Lang.template.RichShield_set_digital_buzzer, params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'RichShield_list_digital_sound', }, { type: 'RichShield_list_digital_tone', }, { type: 'RichShield_list_digital_octave', }, { type: 'text', params: ['1'], }, null, ], type: 'RichShield_set_digital_buzzer', }, paramsKeyMap: { PORT: 0, NOTE: 1, OCTAVE: 2, DURATION: 3, }, class: 'RichShield_Set', isNotFor: ['RichShield'], func: function(sprite, script) { var port = script.getNumberValue('PORT'); var duration = script.getNumberValue('DURATION'); var octave = script.getNumberValue('OCTAVE') - 1; var value = 0; if (!script.isStart) { var note = script.getValue('NOTE'); if (!Entry.Utils.isNumber(note)) { note = Entry.RichShield.toneTable[note]; } if (note < 0) { note = 0; } else if (note > 12) { note = 12; } if (duration < 0) { duration = 0; } if (!Entry.hw.sendQueue['SET']) { Entry.hw.sendQueue['SET'] = {}; } if (duration === 0) { Entry.hw.sendQueue['SET'][port] = { type: Entry.RichShield.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; return script.callReturn(); } if (octave < 0) { octave = 0; } else if (octave > 8) { octave = 8; } if (note != 0) { value = Entry.RichShield.toneMap[note][octave]; } duration = duration * 1000; script.isStart = true; script.timeFlag = 1; Entry.hw.sendQueue['SET'][port] = { type: Entry.RichShield.sensorTypes.TONE, data: { value: value, duration: duration, }, time: new Date().getTime(), }; setTimeout(function() { script.timeFlag = 0; }, duration + 32); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.hw.sendQueue['SET'][port] = { type: Entry.RichShield.sensorTypes.TONE, data: 0, time: new Date().getTime(), }; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: ['RichShield.set_digital_toggle(%1, %2, %3, %4)'], }, }, RichShield_LCD_event: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_hardware.svg', size: 14, position: { x: 0, y: -2 }, }, ], def: { params: [], type: 'RichShield_LCD_event' }, class: 'RichShield_LCD', isNotFor: ['RichShield'], }, RichShield_LCD_Control_init: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['1', 1], ['2', 2], ], value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [ ['0x20', 32], ['0x27', 39], ['0x3f', 63], ], value: 32, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], def: { params: [], type: 'RichShield_LCD_Control_init' }, paramsKeyMap: { lcd_device: 0, address: 1 }, class: 'RichShield_LCD', isNotFor: ['RichShield'], func(sprite, script) { const device = script.getNumberValue('lcd_device', script); const addr_val = script.getNumberValue('address', script); const text = []; // index number patched by Remoted 2020-11-20 if (!script.isStart) { if (typeof addr_val === 'string') { for (let i = 0; i < 16; i++) { text[i] = string.charAt(i); } } else if (typeof addr_val === 'number') { text[0] = 1; text[1] = addr_val / 1; } else { text[0] = addr_val; } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } script.isStart = true; script.timeFlag = 1; const fps = Entry.FPS || 60; const timeValue = (60 / fps) * 50; // LCD_Init type data protocol defined Entry.hw.sendQueue.SET[device] = { type: Entry.RichShield.sensorTypes.LCD, data: { block_index:1, text0: text[0], text1: text[1], }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, timeValue); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: ['RichShield_LCD_init(%1, %2)'] }, }, RichShield_list_digital_lcd: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], template: '%1', params: [ { type: 'Dropdown', options: [ [Lang.Blocks.RichShield_lcd_first_line, '0'], [Lang.Blocks.RichShield_lcd_seconds_line, '1'], ], value: '0', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null], }, paramsKeyMap: { LINE: 0, }, func(sprite, script) { return script.getField('LINE'); }, }, RichShield_LCD_Control_Display: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', template: Lang.template.RichShield_LCD_Control_Display, statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ { type: 'number', params: [1], }, { type: 'number', params: [1], }, { type: 'number', params: [1], }, { type: 'text', params: ['RichShield !!'], }, null, ], type: 'RichShield_LCD_Control_Display', }, paramsKeyMap: { line: 0, Row: 1, Col: 2, STRING: 3, }, class: 'RichShield_LCD', isNotFor: ['RichShield'], func(sprite, script) { const line = script.getNumberValue('line'); // No used this data in RichShield const Row = parseInt(script.getNumberValue('Row')); const Col = parseInt(script.getNumberValue('Col')); const string = script.getValue('STRING'); const text = []; if (!script.isStart) { if (typeof string === 'string') { for (let i = 0; i < 16; i++) { text[i] = string.charCodeAt(i); } } else if (typeof string === 'number') { text[0] = 1; text[1] = string / 1; } else { text[0] = string; } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } script.isStart = true; script.timeFlag = 1; const fps = Entry.FPS || 60; const timeValue = (60 / fps) * 60; console.log( `Row : ${Row} / Col : ${Col} / text : ${text}` ); Entry.hw.sendQueue.SET[line] = { type: Entry.RichShield.sensorTypes.LCD, data: { block_index: 2, displayRow: Row, displayCol: Col, text0: text[0], text1: text[1], text2: text[2], text3: text[3], text4: text[4], text5: text[5], text6: text[6], text7: text[7], text8: text[8], text9: text[9], text10: text[10], text11: text[11], text12: text[12], text13: text[13], text14: text[14], text15: text[15], }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, timeValue); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } return script.callReturn(); }, syntax: { js: [], py: ['RichShield.LCD_Display(%1, %2, %3, %4)'] }, }, RichShield_LCD_Control_Clear: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [['1', 1]], value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], def: { params: [], type: 'RichShield_LCD_Control_Clear' }, paramsKeyMap: { lcd_device: 0 }, class: 'RichShield_LCD', isNotFor: ['RichShield'], func(sprite, script) { const device = script.getNumberValue('lcd_device', script); let time = new Date().getTime(); if (!script.isStart) { if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } script.isStart = true; script.timeFlag = 1; const fps = Entry.FPS || 60; const timeValue = (60 / fps) * 50; // LCD_Init type data protocol defined Entry.hw.sendQueue.SET[device] = { type: Entry.RichShield.sensorTypes.LCD, data: { block_index: 3, }, time: time, }; setTimeout(() => { script.timeFlag = 0; }, timeValue); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } return script.callReturn(); }, syntax: { js: [], py: ['RichShield_LCD_Control_Clear(%1)'] }, }, RichShield_LCD_Control_Scroll: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [['1', 1]], value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [ ['왼쪽', 1], ['오른쪽', 2], ], value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], def: { params: [], type: 'RichShield_LCD_Control_Scroll' }, paramsKeyMap: { lcd_device: 0, direction: 1, }, class: 'RichShield_LCD', isNotFor: ['RichShield'], func(sprite, script) { const device = script.getNumberValue('lcd_device', script); const direction = script.getNumberValue('direction', script); if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } // LCD_Init type data protocol defined Entry.hw.sendQueue.SET[device] = { type: Entry.RichShield.sensorTypes.LCD, data: { block_index: 4, direction, }, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: ['RichShield_LCD_Control_Scroll(%1)'] }, }, RichShield_FND_event: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_hardware.svg', size: 14, position: { x: 0, y: -2 }, }, ], def: { params: [], type: 'RichShield_FND_event' }, class: 'RichShield_FND', isNotFor: ['RichShield'], }, RichShield_FND_Control_init: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [['1', 1]], value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [['5', 5]], value: 5, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [['4', 4]], value: 4, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], def: { params: [], type: 'RichShield_FND_Control_init' }, paramsKeyMap: { fnd_device: 0, CLK: 1, DIO: 2 }, class: 'RichShield_FND', isNotFor: ['RichShield'], func(sprite, script) { const device = script.getNumberValue('fnd_device', script); const clk_val = script.getNumberValue('CLK', script); const dio_val = script.getNumberValue('DIO', script); // index number patched by Remoted 2020-11-20 if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } // FND_Init type data protocol defined Entry.hw.sendQueue.SET[device] = { type: Entry.RichShield.sensorTypes.FND, data: { clk_pin: clk_val, dio_pin: dio_val, }, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: ['RichShield_FND_init(%1, %2)'] }, }, RichShield_FND_Control_diplay_brightness: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [['1', 1]], value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [ ['1', 1], ['2', 2], ['3', 3], ['4', 4], ['5', 5], ['6', 6], ['7', 7], ], value: 3, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], def: { params: [], type: 'RichShield_FND_Control_diplay_brightness' }, paramsKeyMap: { fnd_device: 0, level: 1 }, class: 'RichShield_FND', isNotFor: ['RichShield'], func(sprite, script) { const device = script.getNumberValue('fnd_device', script); const level_val = script.getNumberValue('level', script); if (!script.isStart) { // index number patched by Remoted 2020-11-20 if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } script.isStart = true; script.timeFlag = 1; const fps = Entry.FPS || 60; const timeValue = (60 / fps) * 50; // FND_Init type data protocol defined Entry.hw.sendQueue.SET[device] = { type: Entry.RichShield.sensorTypes.FND, data: { level_val, block_index: 1, }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, timeValue); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: ['RichShield_FND_Control_diplay_brightness(%1, %2)'] }, }, RichShield_FND_Control_display_onoff: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [['1', 1]], value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [ [Lang.Blocks.RichShield_toggle_off, 0], [Lang.Blocks.RichShield_toggle_on, 1], ], value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], def: { params: [], type: 'RichShield_FND_Control_display_onoff' }, paramsKeyMap: { fnd_device: 0, onoff: 1 }, class: 'RichShield_FND', isNotFor: ['RichShield'], func(sprite, script) { const device = script.getNumberValue('fnd_device', script); const onoff = script.getNumberValue('onoff', script); if (!script.isStart) { // index number patched by Remoted 2020-11-20 if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } script.isStart = true; script.timeFlag = 1; const fps = Entry.FPS || 60; const timeValue = (60 / fps) * 50; // FND_Init type data protocol defined Entry.hw.sendQueue.SET[device] = { type: Entry.RichShield.sensorTypes.FND, data: { onoff, block_index: 2, }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, timeValue); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: ['RichShield_FND_Control_display_onoff(%1, %2)'] }, }, RichShield_FND_Control_diplay_char: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [['1', 1]], value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', }, { type: 'Dropdown', options: [ [Lang.Blocks.RichShield_toggle_off, 0], [Lang.Blocks.RichShield_toggle_on, 1], ], value: 0, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ '1', { type: 'number', params: ['1234'], }, '0', { type: 'number', params: ['0.1'], }, ], type: 'RichShield_FND_Control_diplay_char', }, events: {}, paramsKeyMap: { fnd_device: 0, display_value: 1, onoff: 2, delay_ms: 3 }, class: 'RichShield_FND', isNotFor: ['RichShield'], func(sprite, script) { const device = script.getNumberValue('fnd_device', script); const display_str = script.getNumberValue('display_value', script); const onoff = script.getNumberValue('onoff', script); const delay_ms_sec = script.getNumberValue('delay_ms', script); const splited_array = []; let display_str_converted = 0; if (!script.isStart) { if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } display_str_converted = display_str.toString(); script.isStart = true; script.timeFlag = 1; const fps = Entry.FPS || 60; const timeValue = (60 / fps) * 100; for (let i = 0; i < display_str_converted.length; i++) { splited_array.push(parseInt(display_str_converted.charAt(i))); } console.log(`splited_array :${splited_array}`); // FND_Init type data protocol defined Entry.hw.sendQueue.SET[device] = { type: Entry.RichShield.sensorTypes.FND, data: { display_str, onoff, block_index: 3, str_length: display_str_converted.length, data_0: splited_array[0], data_1: splited_array[1], data_2: splited_array[2], data_3: splited_array[3], delay_ms: delay_ms_sec, }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, timeValue); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: ['RichShield_FND_Control_diplay_char(%1, %2, %3, %4)'] }, }, RichShield_DHT_event: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_hardware.svg', size: 14, position: { x: 0, y: -2 }, }, ], def: { params: [], type: 'RichShield_DHT_event' }, class: 'RichShield_DHT', isNotFor: ['RichShield'], }, RichShield_DHT_Control_Init_Process: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [['13', 13]], value: 13, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [['DHT11', 4]], value: 4, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], def: { params: [], type: 'RichShield_DHT_Control_Init_Process' }, class: 'RichShield_DHT', isNotFor: ['RichShield'], paramsKeyMap: { dht_device: 0, pin: 1, ver: 2 }, class: 'RichShield_DHT', isNotFor: ['RichShield'], func(sprite, script) { const device = script.getNumberValue('dht_device', script); const dht_val = script.getNumberValue('pin', script); const ver_val = script.getNumberValue('ver', script); // index number patched by Remoted 2020-11-20 if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } // DHT_Init type data protocol defined Entry.hw.sendQueue.SET[device] = { type: Entry.RichShield.sensorTypes.DHT, data: { dht_pin: dht_val, ver_info: ver_val, dht_block_index: 0, }, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: ['RichShield_DHT_Control_Init_Process(%1, %2, %3)'] }, }, RichShield_DHT_Control_Get_Temper: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], def: { params: [], type: 'RichShield_DHT_Control_Get_Temper' }, paramsKeyMap: { dht_device: 0}, class: 'RichShield_DHT', isNotFor: ['RichShield'], func(sprite, script) { const device = script.getNumberValue('dht_device', script); const port = 12; if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } // DHT Temp-Reader type data protocol defined Entry.hw.sendQueue.GET[Entry.RichShield.sensorTypes.DHT] = { port, //tempMode: tempType, dht_block_index: 0, time: new Date().getTime(), }; console.log((Entry.hw.portData.DHT || 0).toFixed(1)); return (Entry.hw.portData.DHT || 0).toFixed(0); }, syntax: { js: [], py: ['RichShield_DHT_Control_Get_Temper(%1, %2)'] }, }, RichShield_OLED_event: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_hardware.svg', size: 14, position: { x: 0, y: -2 }, }, ], def: { params: [], type: 'RichShield_OLED_event' }, class: 'RichShield_OLED', isNotFor: ['RichShield'], }, RichShield_OLED_init: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_hardware.svg', size: 14, position: { x: 0, y: -2 }, }, ], def: { params: [], type: 'RichShield_OLED_init' }, paramsKeyMap: {}, class: 'RichShield_OLED', isNotFor: ['RichShield'], func(sprite, script) { const device = 1; // OLED Block Added By Remoted 2021-03-16 if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } // DHT Temp-Reader type data protocol defined Entry.hw.sendQueue.SET[device] = { type: Entry.RichShield.sensorTypes.OLED, data: { oled_block_index: 0, }, time: new Date().getTime(), }; }, syntax: { js: [], py: ['RichShield_OLED_init(0x3C)'] }, }, RichShield_OLED_Display_String: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, { type: 'Block', accept: 'string', }, ], events: {}, def: { params: [ { type: 'number', params: [1], }, { type: 'number', params: [1], }, { type: 'text', params: ['RichShield !!'], }, null, ], type: 'RichShield_OLED_Display_String', }, paramsKeyMap: { Row: 0, Col: 1, STRING: 2, }, class: 'RichShield_OLED', isNotFor: ['RichShield'], func(sprite, script) { const device = 1; const Row = parseInt(script.getNumberValue('Row')); const Col = parseInt(script.getNumberValue('Col')); const string = script.getValue('STRING'); const text = []; if (!script.isStart) { if (typeof string === 'string') { for (let i = 0; i < 16; i++) { text[i] = string.charCodeAt(i); } } else if (typeof string === 'number') { text[0] = 1; text[1] = string / 1; } else { text[0] = string; } if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } script.isStart = true; script.timeFlag = 1; const fps = Entry.FPS || 60; const timeValue = (60 / fps) * 50; console.log( `Row : ${Row} / Col : ${Col} / text : ${text}` ); Entry.hw.sendQueue.SET[device] = { type: Entry.RichShield.sensorTypes.OLED, data: { oled_block_index: 1, displayRow: Row, displayCol: Col, text0: text[0], text1: text[1], text2: text[2], text3: text[3], text4: text[4], text5: text[5], text6: text[6], text7: text[7], text8: text[8], text9: text[9], text10: text[10], text11: text[11], text12: text[12], text13: text[13], text14: text[14], text15: text[15], }, time: new Date().getTime(), }; setTimeout(() => { script.timeFlag = 0; }, timeValue); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.timeFlag; delete script.isStart; Entry.engine.isContinue = false; return script.callReturn(); } }, syntax: { js: [], py: ['RichShield_OLED_Display_String(%1, %2, %3)'] }, }, RichShield_IRREMOTE_event: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_event', statements: [], params: [ { type: 'Indicator', img: 'block_icon/start_icon_hardware.svg', size: 14, position: { x: 0, y: -2 }, }, ], def: { params: [], type: 'RichShield_IRREMOTE_event' }, class: 'RichShield_IR', isNotFor: ['RichShield'], }, RichShield_IRREMOTE_init: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Block', value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', value: 2, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], def: { params: [], type: 'RichShield_IRREMOTE_init' }, paramsKeyMap: { ir_device: 0, pin: 1 }, class: 'RichShield_IR', isNotFor: ['RichShield'], func(sprite, script) { const device = script.getNumberValue('ir_device', script); const ir_val = script.getNumberValue('pin', script); let time = new Date().getTime(); // index number patched by Remoted 2020-11-20 if (!Entry.hw.sendQueue.SET) { Entry.hw.sendQueue.SET = {}; } // IR_Init type data protocol defined Entry.hw.sendQueue.SET[device] = { type: Entry.RichShield.sensorTypes.IRREMOTE, data: { ir_pin: ir_val, ir_block_index: 0, }, time: new Date().getTime(), }; return script.callReturn(); }, syntax: { js: [], py: ['RichShield_IRREMOTE_init(%1, %2)'] }, }, RichShield_IRREMOTE_recv: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', value: 2, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], def: { params: [], type: 'RichShield_IRREMOTE_recv' }, paramsKeyMap: { ir_device: 0 }, class: 'RichShield_IR', isNotFor: ['RichShield'], func(sprite, script) { const device = script.getNumberValue('ir_device', script); const port = 12; if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } // DHT Temp-Reader type data protocol defined Entry.hw.sendQueue.GET[Entry.RichShield.sensorTypes.IRREMOTE] = { port, dir:123, //dht_block_index: 2, time: new Date().getTime(), }; console.log((Entry.hw.portData.IRREMOTE || 0).toFixed(1)); return (Entry.hw.portData.IRREMOTE || 0).toFixed(0); }, syntax: { js: [], py: ['RichShield_IRREMOTE_recv(%1, %2)'], }, }, RichShield_DHT2: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_string_field', statements: [], params: [ { type: 'Block', value: 1, fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], def: { params: [], type: 'RichShield_DHT2' }, paramsKeyMap: { ir_device: 0 }, class: 'RichShield_DHT', isNotFor: ['RichShield'], func(sprite, script) { const device = script.getNumberValue('ir_device', script); const port = 12; if (!Entry.hw.sendQueue.GET) { Entry.hw.sendQueue.GET = {}; } // DHT Temp-Reader type data protocol defined Entry.hw.sendQueue.GET[Entry.RichShield.sensorTypes.DHT2] = { port, dir:123, time: new Date().getTime(), }; console.log((Entry.hw.portData.DHT2 || 0).toFixed(1)); return (Entry.hw.portData.DHT2 || 0).toFixed(0); }, syntax: { js: [], py: ['RichShield_DHT2(%1, %2)'] }, }, }; }; module.exports = Entry.RichShield; ================================================ FILE: src/playground/blocks/hardware/block_abilix_Krypton0.js ================================================ 'use strict'; Entry.Krypton0 = { SENSOR_PORT_MAP: { '1': undefined, '2': undefined, '3': undefined, '4': undefined, }, deviceTypes: { NONE: 0x01, BUTTON: 0x02, GRAY_INFRARED: 0x03, LIGHT: 0x07, MICROPHONE: 0x08, LED: 0x09, LMOTOR: 0x0a, RMOTOR: 0x0b, Initializing: 0x7d, WrongPort: 0x7f, Unknown: 0xff, }, timeouts: [], removeTimeout(id) { clearTimeout(id); const timeouts = this.timeouts; const index = timeouts.indexOf(id); if (index >= 0) { timeouts.splice(index, 1); } }, setZero() { Object.keys(this.SENSOR_PORT_MAP).forEach((port) => { Entry.hw.sendQueue[port] = { type: Entry.Krypton0.deviceTypes.NONE, port_values: 0, }; }); Entry.hw.sendQueue.LMOTOR = 0; Entry.hw.sendQueue.RMOTOR = 0; Entry.hw.sendQueue.INTERSND = 'none'; Entry.hw.update(); }, abilix_controller: { MIN_MOTOR_SPEED: -50, MAX_MOTOR_SPEED: 50, check_max_speed(speedvalue) { let adjspeed; if (speedvalue > this.MAX_MOTOR_SPEED) { adjspeed = this.MAX_MOTOR_SPEED; } else if (speedvalue < this.MIN_MOTOR_SPEED) { adjspeed = this.MAX_MOTOR_SPEED; } else { adjspeed = speedvalue; } return adjspeed; }, }, id: '30.1', name: 'ABILIX Krypton 0 for School', url: 'http://abilix.co.kr', imageName: 'abilix_Krypton0.png', title: { ko: '크립톤 0', en: 'Krypton 0 for School', }, }; Entry.Krypton0.setLanguage = function() { return { ko: { template: { Krypton0_turnon_motor: '모터를 %1(으)로 %2 속도로 움직이기 %3', Krypton0_move_to_direction_during_secs: '모터를 %1(으)로 %2 초동안 움직이기 %3', Krypton0_turnoff_motor: '모터를 정지 시키기 %1', Krypton0_change_direction_during_secs: '모터를 %1 방향으로 %2초 동안 움직이기 %3', Krypton0_change_speed: '모터 %1의 속도를 %2로 변경하기 %3', Krypton0_play_sound: '크립톤에서 %1 을 재생하기 %2', Krypton0_get_sensor_data: '포트 %1에서 센서 %2 의 값을 읽기', //Krypton0_get_sensor_value: '센서 %1 의 값을 읽기', Krypton0_button_pressed: '포트 %1의 버튼이 눌려져있는가? %2', Krypton0_turnon_led: '포트 %1의 LED를 %2 %3', }, }, en: { template: { Krypton0_turnon_motor: 'Motors move to %1 as %2 speed %3', Krypton0_move_to_direction_during_secs: 'Motors move to %1 during %2 sec %3', Krypton0_turnoff_motor: 'Stop Motors %1', Krypton0_change_direction_during_secs: 'Motors go to %1 during %2 secs %3', Krypton0_change_speed: 'Motor change from speed of %1 to %2 %3', Krypton0_play_sound: 'Kripton play %1 audio %2', Krypton0_get_sensor_data: 'Port %1 read sensor %2 value', //Krypton0_get_sensor_value: 'Read sensor %1 value', Krypton0_button_pressed: 'Port %1 of Button is pressed? %2', Krypton0_turnon_led: 'Port %1 of LED Turn %2 %3', }, }, }; }; Entry.Krypton0.blockMenuBlocks = [ 'Krypton0_turnon_motor', 'Krypton0_move_to_direction_during_secs', 'Krypton0_turnoff_motor', 'Krypton0_change_direction_during_secs', 'Krypton0_change_speed', 'Krypton0_play_sound', 'Krypton0_get_sensor_data', //'Krypton0_get_sensor_value', 'Krypton0_button_pressed', 'Krypton0_turnon_led', ]; Entry.Krypton0.getBlocks = function() { return { //region Krypton0 //************************************************************************* // Name: Krypton0_turnon_motor // // Description: Turn on Motor. // "Motors move to %1 as %2 speed %3" //*************************************************************************/ Krypton0_turnon_motor: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['앞', 'Forward'], ['뒤', 'Backward'], ], value: '앞', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['3'], }, ], type: 'Krypton0_turnon_motor', }, paramsKeyMap: { DIRECTION: 0, VALUE_SPD: 1, }, class: 'Krypton0_motor_control', isNotFor: ['ABILIX Krypton 0 for School'], func(sprite, script) { const direction = script.getStringField('DIRECTION', script); let speedValue = script.getNumberValue('VALUE_SPD'); if (direction == 'Forward') { speedValue = Entry.Krypton0.abilix_controller.check_max_speed(speedValue); } else { speedValue = Entry.Krypton0.abilix_controller.check_max_speed(speedValue * -1); } Entry.hw.sendQueue.LMOTOR = speedValue; Entry.hw.sendQueue.RMOTOR = speedValue; return script.callReturn(); }, }, //************************************************************************* // Name: Krypton0_move_to_direction_during_secs // // Description: Moter move to Forward / Backword during some sec. // "Motors move to %1 during %2 sec %3" //*************************************************************************/ Krypton0_move_to_direction_during_secs: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['앞', 'Forward'], ['뒤', 'Backward'], ], value: '앞', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', defaultType: 'number', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, { type: 'number', params: ['3'], }, ], type: 'Krypton0_move_to_direction_during_secs', }, paramsKeyMap: { DIRECTION: 0, VALUE_SEC: 1, }, class: 'Krypton0_motor_control', isNotFor: ['ABILIX Krypton 0 for School'], func(sprite, script) { if (!script.isStart) { const direction = script.getStringField('DIRECTION', script); script.isStart = true; script.timeFlag = 1; if (direction == 'Forward') { Entry.hw.sendQueue.LMOTOR = 30; Entry.hw.sendQueue.RMOTOR = 30; } else { Entry.hw.sendQueue.LMOTOR = -30; Entry.hw.sendQueue.RMOTOR = -30; } const timeValue = script.getNumberValue('VALUE_SEC') * 1000; const timer = setTimeout(() => { script.timeFlag = 0; Entry.Krypton0.removeTimeout(timer); }, timeValue); Entry.Krypton0.timeouts.push(timer); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.isStart; delete script.timeFlag; Entry.engine.isContinue = false; Entry.hw.sendQueue.LMOTOR = 0; Entry.hw.sendQueue.RMOTOR = 0; return script.callReturn(); } }, }, //************************************************************************* // Name: Krypton0_turnoff_motor // // Description: Turn off motor. // "Stop Motors %1" //*************************************************************************/ Krypton0_turnoff_motor: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [null], type: 'Krypton0_turnoff_motor', }, class: 'Krypton0_motor_control', isNotFor: ['ABILIX Krypton 0 for School'], func(sprite, script) { Entry.hw.sendQueue.LMOTOR = 0; Entry.hw.sendQueue.RMOTOR = 0; return script.callReturn(); }, }, //************************************************************************* // Name: Krypton0_change_direction_during_secs // // Description: Turn left or right during some sec. // "Motors go to %1 during %2 secs %3" //*************************************************************************/ Krypton0_change_direction_during_secs: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['왼쪽', 'LEFT'], ['오른쪽', 'RIGHT'], ], value: 'LEFT', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, { type: 'text', params: ['1'], }, ], type: 'Krypton0_change_direction_during_secs', }, paramsKeyMap: { DIRECTION: 0, VALUE: 1, }, class: 'Krypton0_motor_control', isNotFor: ['ABILIX Krypton 0 for School'], func(sprite, script) { if (!script.isStart) { script.isStart = true; script.timeFlag = 1; const direction = script.getField('DIRECTION', script); if (direction == 'LEFT') { Entry.hw.sendQueue.LMOTOR = -30; Entry.hw.sendQueue.RMOTOR = 30; } else { Entry.hw.sendQueue.LMOTOR = 30; Entry.hw.sendQueue.RMOTOR = -30; } const timeValue = script.getNumberValue('VALUE') * 1000; const timer = setTimeout(() => { script.timeFlag = 0; Entry.Krypton0.removeTimeout(timer); }, timeValue); Entry.Krypton0.timeouts.push(timer); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.isStart; delete script.timeFlag; Entry.engine.isContinue = false; Entry.hw.sendQueue.LMOTOR = 0; Entry.hw.sendQueue.RMOTOR = 0; return script.callReturn(); } }, }, //************************************************************************* // Name: Krypton0_change_speed // // Description: change motor speed about left, right and both. // "Motor change from speed of %1 to %2 %3" //*************************************************************************/ Krypton0_change_speed: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['A', 'A'], ['B', 'B'], ['양쪽', 'BOTH'], ], value: 'BOTH', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Block', accept: 'string', }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [ null, { type: 'text', params: ['10'], }, ], type: 'Krypton0_change_speed', }, paramsKeyMap: { DIRECTION: 0, VALUE: 1, }, class: 'Krypton0_motor_control', isNotFor: ['ABILIX Krypton 0 for School'], func(sprite, script) { const direction = script.getField('DIRECTION'); const value = script.getNumberValue('VALUE'); if (direction == 'A') { Entry.hw.sendQueue.LMOTOR = value; if (Entry.hw.sendQueue.RMOTOR != undefined) { Entry.hw.sendQueue.RMOTOR = Entry.hw.sendQueue.RMOTOR; } else { Entry.hw.sendQueue.RMOTOR = 0; } } else if (direction == 'B') { Entry.hw.sendQueue.RMOTOR = value; if (Entry.hw.sendQueue.LMOTOR != undefined) { Entry.hw.sendQueue.LMOTOR = Entry.hw.sendQueue.LMOTOR; } else { Entry.hw.sendQueue.LMOTOR = 0; } } else { Entry.hw.sendQueue.LMOTOR = value; Entry.hw.sendQueue.RMOTOR = value; } return script.callReturn(); }, }, //************************************************************************* // Name: Krypton0_play_sound // // Description: play internal sound - hello, by, welcom, cheer. // "Kripton play %1 audio %2" //*************************************************************************/ Krypton0_play_sound: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['hello', 'hello'], ['bye', 'bye'], ['welcome', 'welcome'], ['cheer', 'cheer'], ], value: 'hello', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [null], type: 'Krypton0_play_sound', }, paramsKeyMap: { SOUND_VALUE: 0, }, class: 'Krypton0_motor_control', isNotFor: ['ABILIX Krypton 0 for School'], func(sprite, script) { if (!script.isStart) { script.isStart = true; script.timeFlag = 1; const audiofile = script.getField('SOUND_VALUE', script); Entry.hw.sendQueue.INTERSND = audiofile; const timeValue = 500; const timer = setTimeout(() => { script.timeFlag = 0; Entry.Krypton0.removeTimeout(timer); }, timeValue); Entry.Krypton0.timeouts.push(timer); return script; } else if (script.timeFlag == 1) { return script; } else { delete script.isStart; delete script.timeFlag; Entry.engine.isContinue = false; Entry.hw.sendQueue.INTERSND = 'none'; return script.callReturn(); } }, }, //************************************************************************* // Name: Krypton0_get_sensor_data // // Description: Get sensor values - GRAY_INFRARED, ULTRASONIC, // COLOR, LIGHT, MICROPHONE, LANTERN, BUTTON // "Port %1 read sensor %2 value" //*************************************************************************/ Krypton0_get_sensor_data: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, skeleton: 'basic_string_field', statements: [], params: [ { type: 'Dropdown', options: [ ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [ ['적외선', 'GRAY_INFRARED'], ['빛', 'LIGHT'], ['소리센서', 'MICROPHONE'], ['LED', 'LED'], ['버튼', 'BUTTON'], ], value: 'GRAY_INFRARED', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, ], events: {}, def: { params: [null, null], type: 'Krypton0_get_sensor_data', }, paramsKeyMap: { PORT: 0, DEVICE: 1, }, class: 'Krypton0_sensor', isNotFor: ['ABILIX Krypton 0 for School'], func(sprite, script) { const port = script.getField('PORT'); const dev = script.getField('DEVICE'); let portdata; let devtype; switch (port) { case '1': portdata = Entry.hw.getDigitalPortValue('1'); break; case '2': portdata = Entry.hw.getDigitalPortValue('2'); break; case '3': portdata = Entry.hw.getDigitalPortValue('3'); break; case '4': portdata = Entry.hw.getDigitalPortValue('4'); break; } switch (dev) { case 'GRAY_INFRARED': devtype = Entry.Krypton0.deviceTypes.GRAY_INFRARED; break; case 'LIGHT': devtype = Entry.Krypton0.deviceTypes.LIGHT; break; case 'MICROPHONE': devtype = Entry.Krypton0.deviceTypes.MICROPHONE; break; case 'LED': devtype = Entry.Krypton0.deviceTypes.LED; break; case 'BUTTON': devtype = Entry.Krypton0.deviceTypes.BUTTON; break; default: break; } if (portdata.type == devtype) { return portdata.port_values.toString(); } else { console.log('Krypton0_get_sensor_value : differenct dev type'); return ''; } }, }, //************************************************************************* // Name: Krypton0_button_pressed // // Description: Is Button pressed?. // "Port %1 of Button is pressed? %2" //*************************************************************************/ Krypton0_button_pressed: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic_boolean_field', statements: [], params: [ { type: 'Dropdown', options: [ ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [null], type: 'Krypton0_button_pressed', }, paramsKeyMap: { PORT: 0, }, class: 'Krypton0_sensor', isNotFor: ['ABILIX Krypton 0 for School'], func(sprite, script) { const port = script.getField('PORT'); let portdata = Entry.hw.getDigitalPortValue(port); switch (port) { case '1': portdata = Entry.hw.getDigitalPortValue('1'); break; case '2': portdata = Entry.hw.getDigitalPortValue('2'); break; case '3': portdata = Entry.hw.getDigitalPortValue('3'); break; case '4': portdata = Entry.hw.getDigitalPortValue('4'); break; } if (portdata.type == Entry.Krypton0.deviceTypes.BUTTON) { if (portdata.port_values == 1) { console.log('Krypton0_button_pressed'); return true; } } else { console.log('Krypton0_get_sensor_data : differenct dev type'); } return false; }, }, //************************************************************************* // Name: Krypton0_turnon_led // // Description: Turn on / off LED // "Port %1 of LED Turn %2 %3" //*************************************************************************/ Krypton0_turnon_led: { color: EntryStatic.colorSet.block.default.HARDWARE, outerLine: EntryStatic.colorSet.block.darken.HARDWARE, fontColor: '#fff', skeleton: 'basic', statements: [], params: [ { type: 'Dropdown', options: [ ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ], value: '1', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Dropdown', options: [ ['켠다', 'ON'], ['끈다', 'OFF'], ], value: 'ON', fontSize: 11, bgColor: EntryStatic.colorSet.block.darken.HARDWARE, arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, }, { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12, }, ], events: {}, def: { params: [null, null], type: 'Krypton0_turnon_led', }, paramsKeyMap: { PORT: 0, LED_VALUE: 1, }, class: 'Krypton0_sensor', isNotFor: ['ABILIX Krypton 0 for School'], func(sprite, script) { const port = script.getField('PORT'); const ledvalue = script.getField('LED_VALUE'); let portvalue; if (ledvalue == 'ON') { portvalue = 0; } else { portvalue = 1; } Entry.hw.sendQueue[port] = { type: Entry.Krypton0.deviceTypes.LED, port_values: portvalue, }; return script.callReturn(); }, }, //endregion }; }; module.exports = Entry.Krypton0; ================================================ FILE: src/playground/blocks/hardware/block_aidrone.js ================================================ 'use strict'; Entry.AIDrone = { Cmd: { CMD_LED: 1, CMD_TUNE: 2, CMD_TUNEDUR: 3, CMD_ROLL_LOW: 4, CMD_ROLL_HIGH: 5, CMD_PITCH_LOW: 6, CMD_PITCH_HIGH: 7, CMD_OPTION_LOW: 8, CMD_MOTOR0: 9, CMD_MOTOR1: 10, CMD_MOTOR2: 11, CMD_MOTOR3: 12, CMD_EXTPIN1: 13, CMD_EXTPIN2: 14, CMD_EXTPIN3: 15, CMD_PWM: 16, CMD_SERVOPORT: 17, CMD_SERVODGREE: 18, CMD_OPTION_HIGH: 19, CMD_YAW_LOW: 20, CMD_YAW_HIGH: 21, CMD_THROTTLE_LOW: 22, CMD_THROTTLE_HIGH: 23, CMD_POSVEL_LOW: 24, CMD_POSVEL_HIGH: 25, CMD_YAWVEL_LOW: 26, CMD_YAWVEL_HIGH: 27, CMD_ULTRASONIC: 28, }, Sensor: { SENSOR_JOYSTICK_LLR: 1, SENSOR_JOYSTICK_LTB: 2, SENSOR_JOYSTICK_RLR: 3, SENSOR_JOYSTICK_RTB: 4, SENSOR_BUTTON: 5, SENSOR_DRONECONNECT: 6, SENSOR_DRONEALT: 7, SENSOR_GYRO_X: 8, SENSOR_GYRO_Y: 9, SENSOR_DRONEREADY: 10, SENSOR_EXTPIN1: 11, SENSOR_EXTPIN2: 12, SENSOR_ANALOG4: 13, SENSOR_ANALOG5: 14, SENSOR_JDKITMAX: 15, SENSOR_BATTERY: 15, SENSOR_POSX_L: 16, SENSOR_POSX_H: 17, SENSOR_POSY_L: 18, SENSOR_POSY_H: 19, SENSOR_ULTRASONIC: 20, }, setZero: function() { Entry.hw.sendQueue.CMD = [ 0xf0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; Entry.hw.update(); }, id: '6B.1', name: 'AIDrone', url: 'http://www.aidrone.store', imageName: 'aidrone.png', title: { 'en': 'AIDrone', 'ko': 'AI드론', }, monitorTemplate: { imgPath: 'hw/jdrc.png', width: 600, height: 355, listPorts: { 'A6': { name: '드론연결상태', type: 'input', pos: { x: 0, y: 0, }, }, 'A10': { name: '드론준비상태', type: 'input', pos: { x: 0, y: 0, }, }, 'A15': { name: '배터리(%)', type: 'input', pos: { x: 0, y: 0, }, }, 'A8': { name: '드론좌우기울기', type: 'input', pos: { x: 0, y: 0, }, }, 'A9': { name: '드론앞뒤기울기', type: 'input', pos: { x: 0, y: 0, }, }, 'A7': { name: '드론높이', type: 'input', pos: { x: 0, y: 0, }, }, 'A16': { name: '드론좌우이동', type: 'input', pos: { x: 0, y: 0, }, }, 'A18': { name: '드론앞뒤이동', type: 'input', pos: { x: 0, y: 0, }, }, }, ports: { 'A1': { name: '왼쪽 조이스틱 좌우', type: 'input', pos: { x: 140, y: 140, }, }, 'A2': { name: '왼쪽 조이스틱 상하', type: 'input', pos: { x: 140, y: 140, }, }, 'A3': { name: '오른쪽 조이스틱 좌우', type: 'input', pos: { x: 450, y: 140, }, }, 'A4': { name: '오른쪽 조이스틱 상하', type: 'input', pos: { x: 450, y: 140, }, }, 'A5': { name: '버튼', type: 'input', pos: { x: 430, y: 250, }, }, }, mode: 'both', }, }; Entry.AIDrone.setLanguage = function() { return { ko: { template: { 'aidrone_takeoff': '드론 이륙하기 %1', 'aidrone_landing': '드론 착륙하기 %1', 'aidrone_altitude': '%1cm 높이로 비행%2', 'aidrone_throttle': '프로펠러를 %1 % 세기로 돌리기 %2', 'aidrone_velocity': '%1(으)로 %2속도(cm/s)로 비행%3', 'aidrone_distance': '%1(으)로 %2cm 거리를 %3속도(cm/s)로 비행%4', 'aidrone_degree': '%1으로 %2도를 %3각속도(deg/s)로 회전 %4', 'aidrone_motor': '%1 모터를 %2 세기로 돌리기 %3', 'aidrone_emergency': '드론 즉시멈추기 %1', 'aidrone_connect': '드론 연결상태', 'aidrone_ready': '드론 준비상태', 'aidrone_battery': '배터리(%)', 'aidrone_dronealt': '드론 높이', 'aidrone_gyrox': '드론 좌우 기울기', 'aidrone_gyroy': '드론 앞뒤 기울기', 'aidrone_posx': '드론 좌우 이동', 'aidrone_posy': '드론 앞뒤 이동', 'aidrone_led': '%1 LED %2 %3', 'aidrone_tune': '%1 음을 %2 초동안 소리내기 %3', 'aidrone_joystick': '조이스틱 %1 읽기', 'aidrone_button': '%1번 버튼 값 읽어오기', 'aidrone_dir_front': '앞', 'aidrone_dir_back': '뒤', 'aidrone_dir_right': '오른쪽', 'aidrone_dir_left': '왼쪽', 'aidrone_alt': '드론 높이', 'aidrone_tiltx': '드론좌우기울기', 'aidrone_tilty': '드론앞뒤기울기', 'aidrone_battery': '배터리', 'aidrone_detect_marker': '화면에서 마커 찾기 %1', 'aidrone_get_marker_data': '인식된 마커의 %1 값', 'aidrone_color_track_start': '%1 색상 추적 시작 %2', 'aidrone_color_track_stop': '색상 추적 중지 %1', 'aidrone_color_detected': '색상이 감지됨?', 'aidrone_get_color_x': '감지된 색상 X좌표', 'aidrone_get_color_y': '감지된 색상 Y좌표', 'aidrone_get_color_size': '감지된 색상 크기', 'aidrone_get_color_data': '색상 추적 %1', 'aidrone_face_detect': '얼굴 인식하기 %1', 'aidrone_face_detected': '얼굴이 감지됨?', 'aidrone_get_face_x': '얼굴 X좌표', 'aidrone_get_face_y': '얼굴 Y좌표', 'aidrone_get_face_size': '얼굴 크기', 'aidrone_get_face_data': '얼굴 %1', 'aidrone_get_landmark': '얼굴 랜드마크 %1번 %2 좌표', 'aidrone_marker_detected': '마커가 감지됨?', }, }, en: { template: { 'aidrone_takeoff': '드론 이륙하기 %1', 'aidrone_landing': '드론 착륙하기 %1', 'aidrone_altitude': '%1cm 높이로 비행%2', 'aidrone_throttle': '프로펠러를 %1 % 세기로 돌리기 %2', 'aidrone_velocity': '%1(으)로 %2속도(cm/s)로 비행%3', 'aidrone_distance': '%1(으)로 %2cm 거리를 %3속도(cm/s)로 비행%4', 'aidrone_degree': '%1으로 %2도를 %3각속도(deg/s)로 회전 %4', 'aidrone_motor': '%1 모터를 %2 세기로 돌리기 %3', 'aidrone_emergency': '드론 즉시멈추기 %1', 'aidrone_connect': '드론 연결상태', 'aidrone_ready': '드론 준비상태', 'aidrone_battery': '배터리(%)', 'aidrone_dronealt': '드론 높이', 'aidrone_gyrox': '드론 좌우 기울기', 'aidrone_gyroy': '드론 앞뒤 기울기', 'aidrone_posx': '드론 좌우 이동', 'aidrone_posy': '드론 앞뒤 이동', 'aidrone_led': '%1 LED %2 %3', 'aidrone_tune': '%1 음을 %2 초동안 소리내기 %3', 'aidrone_joystick': '조이스틱 %1 읽기', 'aidrone_button': '%1번 버튼 값 읽어오기', 'aidrone_dir_front': '앞', 'aidrone_dir_back': '뒤', 'aidrone_dir_right': '오른쪽', 'aidrone_dir_left': '왼쪽', 'aidrone_alt': '드론 높이', 'aidrone_tiltx': '드론좌우기울기', 'aidrone_tilty': '드론앞뒤기울기', 'aidrone_battery': '배터리', 'aidrone_detect_marker': '화면에서 마커 찾기 %1', 'aidrone_get_marker_data': '인식된 마커의 %1 값', 'aidrone_color_track_start': '%1 color track start %2', 'aidrone_color_track_stop': 'color track stop %1', 'aidrone_color_detected': 'color detected?', 'aidrone_get_color_x': 'color X', 'aidrone_get_color_y': 'color Y', 'aidrone_get_color_size': 'color size', 'aidrone_get_color_data': 'color track %1', 'aidrone_face_detect': 'detect face %1', 'aidrone_face_detected': 'face detected?', 'aidrone_get_face_x': 'face X', 'aidrone_get_face_y': 'face Y', 'aidrone_get_face_size': 'face size', 'aidrone_get_face_data': 'face %1', 'aidrone_get_landmark': 'landmark %1 %2', 'aidrone_marker_detected': 'marker detected?', }, }, }; }; Entry.AIDrone.blockMenuBlocks = [ 'aidrone_takeoff', 'aidrone_landing', 'aidrone_altitude', 'aidrone_throttle', 'aidrone_velocity', 'aidrone_distance', 'aidrone_degree', 'aidrone_emergency', 'aidrone_connect', 'aidrone_ready', 'aidrone_battery', 'aidrone_dronealt', 'aidrone_gyrox', 'aidrone_gyroy', 'aidrone_posx', 'aidrone_posy', 'aidrone_led', 'aidrone_tune', 'aidrone_motor', 'aidrone_joystick', 'aidrone_button', 'aidrone_detect_marker', 'aidrone_get_marker_data', // tracking.js 기반 비전 블록 ─ 색상 추적 'aidrone_color_track_start', 'aidrone_color_track_stop', 'aidrone_color_detected', 'aidrone_get_color_x', 'aidrone_get_color_y', 'aidrone_get_color_size', 'aidrone_get_color_data', // tracking.js 기반 비전 블록 ─ 얼굴 인식 'aidrone_face_detect', 'aidrone_face_detected', 'aidrone_get_face_x', 'aidrone_get_face_y', 'aidrone_get_face_size', 'aidrone_get_face_data', // tracking.js 기반 비전 블록 ─ 랜드마크 'aidrone_get_landmark', // AR 마커 조건 블록 'aidrone_marker_detected', ]; // --- [여기부터] 1단계 코드: 마커 데이터 저장 변수 --- Entry.AIDrone.visionData = { id: -1, // 마커 ID (없으면 -1) x: 0, // 화면 X좌표 (-240 ~ 240) y: 0, // 화면 Y좌표 (-135 ~ 135) dist: 0, // 거리 (cm 추정치) width: 0 // 마커의 크기(픽셀) }; // --- [여기까지] 1단계 코드 --- // ------------------------------------------------------- // tracking.js 전용 데이터 저장 변수 // ------------------------------------------------------- // 색상 추적 데이터 Entry.AIDrone.colorTrackData = { detected: false, // 감지 여부 x: 0, // 감지된 색상 영역 중심 X (엔트리 좌표계) y: 0, // 감지된 색상 영역 중심 Y (엔트리 좌표계) width: 0, // 영역 가로 크기(pixel) height: 0 // 영역 세로 크기(pixel) }; Entry.AIDrone._colorTrackerTask = null; Entry.AIDrone._colorTrackerRunning = false; Entry.AIDrone._colorTrackerStop = null; Entry.AIDrone._arDetector = null; // AR.Detector 재사용 // ---------------------------------------------------------------- // _getVisionCanvas(): 비전 분석에 사용할 canvas 반환 // // 동작 우선순위: // 1순위: Entry.cam.canvas // → 엔트리 [비디오 화면 보이기] + [MJPEG Camera로 바꾸기] 블록 // 실행 후 생성되는 공식 비디오 캔버스 // (매 프레임 Entry.cam.video → Entry.cam.canvas에 그려짐) // // 2순위: Entry.cam.video → 오프스크린 canvas // → Entry.cam.canvas가 없을 때 video를 직접 그려서 분석 // // 3순위: document의 재생 중인